#!/bin/bash
set -euo pipefail

#
# Copyright (c) 2016-2020 Samsung Electronics Co., Ltd. All rights reserved.
#
# This file is licensed under the terms of MIT License or the Apache License
# Version 2.0 of your choice. See the LICENSE.MIT file for MIT license details.
# See the LICENSE file or the notice below for Apache License Version 2.0
# details.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

PATH=/bin:/usr/bin:/sbin:/usr/sbin
POLICY_PATH=/usr/share/security-manager/policy
PRIVILEGE_GROUP_MAPPING=$POLICY_PATH/privilege-group.list
PRIVILEGE_SYSTEMD_LIST=$POLICY_PATH/privilege-managed-by-systemd-for-daemons.list

DB_FILE=`tzplatform-get TZ_SYS_DB | cut -d= -f2`/.security-manager.db
UID_SANDBOXING=$(test "" != "" && echo true || echo false)

cynara_policies_to_set=''
# Usage: add_cynara_policy bucket client user privilege type [metadata]
function add_cynara_policy() {
    cynara_policies_to_set+="$1;$2;$3;$4;$5;${6:-}"$'\n'
}

function apply_cynara_policies() {
    cyad --set-policy --bulk=- <<< "${cynara_policies_to_set}"
    cynara_policies_to_set=''
}

# Create default buckets
while read bucket default_policy
do
    # Reuse the primary bucket for PRIVACY_MANAGER bucket
    [ "$bucket" = "PRIVACY_MANAGER" ] && bucket=""
    cyad --set-bucket="$bucket" --type="$default_policy"
done <<END
PRIVACY_MANAGER DENY
ADMIN NONE
APPDEFINED NONE
MAIN DENY
MANIFESTS_GLOBAL DENY
MANIFESTS_LOCAL DENY
END

# Link buckets together
while read bucket_src bucket_dst
do
    # Reuse the main bucket for PRIVACY_MANAGER bucket
    [ "$bucket_src" = "PRIVACY_MANAGER" ] && bucket_src=""
    add_cynara_policy "${bucket_src}" '*' '*' '*' BUCKET "${bucket_dst}"
done <<END
MAIN MANIFESTS_GLOBAL
PRIVACY_MANAGER MAIN
ADMIN APPDEFINED
END

apply_cynara_policies

# Import user-type policies
policy_files="$(find "$POLICY_PATH" -name "usertype-*.profile")"
while read -r file; do
    bucket="$(echo "${file}" | sed -r 's|.*/usertype-(.*).profile$|USER_TYPE_\1|' | tr '[:lower:]' '[:upper:]')"

    # Re-create the bucket with empty contents
    cyad --erase=$bucket --recursive=n --client='#' --user='#' --privilege='#'  >/dev/null 2>&1 || true
    cyad --set-bucket=$bucket --type=DENY

    # Link the bucket to ADMIN bucket
    add_cynara_policy "${bucket}" '*' '*' '*' BUCKET ADMIN

    file_contents="$(grep -v "^'" "${file}")"
    while read -r app privilege; do
        user="*"        # Match any user id
        policy="0xFFFF" # ALLOW (FIXME: cyad should parse policy names, not numeric values)
        add_cynara_policy "${bucket}" "${app}" "${user}" "${privilege}" "${policy}"
    done <<< "${file_contents}"
done <<< "${policy_files}"

if $UID_SANDBOXING; then
    clients=("user" "privileged")
else
    clients=("User" "System" "System::Privileged")
fi

# Non-application programs get access to all privileges...
for client in "${clients[@]}"; do
    add_cynara_policy MANIFESTS_GLOBAL "${client}" '*' '*' ALLOW
done

# ...except these that have their GIDs managed by systemd
privilege_systemd="$(grep -v "^#" "${PRIVILEGE_SYSTEMD_LIST}")"
while read privilege
do
    for client in "${clients[@]}"; do
        add_cynara_policy MANIFESTS_GLOBAL "${client}" '*' "${privilege}" DENY
    done
done <<< "${privilege_systemd}"

# Root shell get access to all privileges
if ! $UID_SANDBOXING; then
    add_cynara_policy MANIFESTS_GLOBAL 'User::Shell' '0' '*' ALLOW
fi # Already done above in no-smack env

# @(kernel thread) can get access to internet privilege
if ! $UID_SANDBOXING; then
    add_cynara_policy MANIFESTS_GLOBAL '@' '*' 'http://tizen.org/privilege/internet' ALLOW
fi

# Ensure applications can access standard devices
for priv in audio video display; do
    add_cynara_policy MANIFESTS_GLOBAL '*' '*' "http://tizen.org/privilege/internal/device/${priv}" ALLOW
    add_cynara_policy MANIFESTS_LOCAL '*' '*' "http://tizen.org/privilege/internal/device/${priv}" ALLOW
done

apply_cynara_policies

# Load privilege-group mappings
(
echo "BEGIN;"
echo "DELETE FROM privilege_group;"
grep -v '^#' "$PRIVILEGE_GROUP_MAPPING" |
while read privilege group
do
    echo "INSERT INTO privilege_group (privilege_name, group_name) VALUES ('$privilege', '$group');"
done
echo "COMMIT;"
) | sqlite3 "$DB_FILE"
