#
# The following is a script to set up local apps support on LTSP through LDM
#

# This hook modifies /etc/passwd, group, shadow and gshadow with user/group
# information gathered from the server.

# This will enable us to easily bypass the need for setting up local user
# authentication, and instead leverage the authentication already set up on
# the server.

ssh_run() {
    ssh -S "$LDM_SOCKET" "$LDM_SERVER" "$@"
}

# Return true if the parameter is a valid user or group name.
# The regex is from `man useradd`, and all of "$1" must match it.
is_valid_name() {
    test $(expr match "$1" '[a-z_][a-z0-9_-]*[$]*') -eq ${#1}
}

# First, set up local uids/gids
mkdir -p /var/cache/ltsp

# On first login, copy /etc/passwd, group, shadow and gshadow to cache.
# On subsequent logins, restore them.
for i in passwd group shadow gshadow; do
    if [ ! -e "/var/cache/ltsp/$i" ]; then
        cp "/etc/$i" "/var/cache/ltsp/$i"
    else
        cp "/var/cache/ltsp/$i" "/etc/$i"
    fi
done

# Get user information from the server
IFS=':' read LDM_USERNAME dummy pw_uid pw_gid pw_gecos LDM_HOME pw_shell <<EOF
$(ssh_run '/usr/bin/getent passwd $(/usr/bin/id -u)')
EOF

# Get the groups that the user belongs to, and create them locally.
# groupadd doesn't permit some of the characters used in LDAP, AD etc,
# so we may have to use a temporary valid group name, and sed afterwards.
primary_group="$pw_gid"
sed_list=""
group_list=""
while IFS=':' read gr_name dummy gr_gid dummy; do
    if is_valid_name "$gr_name"; then
        groupadd_name="$gr_name"
    else
        groupadd_name="ltsp_temporary_group_$gr_gid"
        sed_list="$sed_list
s:$groupadd_name:$gr_name:"
    fi
    if [ "$gr_gid" -le 500 ]; then
        system_group="--system"
    else
        system_group=""
    fi
    groupadd --force $system_group --gid "$gr_gid" "$groupadd_name"
    # Remember the user's primary group name for useradd
    test "$gr_gid" -eq "$pw_gid" && primary_group="$groupadd_name"
    group_list="$group_list,$groupadd_name"
done <<EOF
$(ssh_run '/usr/bin/getent group $(/usr/bin/id -G)')
EOF
group_list=${group_list#,}

# useradd also doesn't permit some of the characters used in LDAP, AD etc
if is_valid_name "$LDM_USERNAME"; then
    useradd_name="$LDM_USERNAME"
else
    useradd_name="ltsp_temporary_user_$pw_uid"
    sed_list="$sed_list
s:$useradd_name:$LDM_USERNAME:"
fi
# Note that we want to do name-mapping and not gid-mapping for -g and -G
useradd -c "$pw_gecos" -d "$LDM_HOME" -g "$primary_group" -G "$group_list" \
    -M -N --non-unique -s "$pw_shell" -u "$pw_uid" "$useradd_name"

# For any non-valid names encountered, use sed directly
echo "$sed_list" | while read -r substitution; do
    test -z "$substitution" && continue
    sed -e "$substitution" -i /etc/passwd /etc/group /etc/shadow /etc/gshadow
done

if boolean_is_true "$LOCAL_APPS" || boolean_is_true "$LTSP_FATCLIENT"; then
    # Now, let's mount the home directory
    # First, make the mountpoint
    mkdir -p "$LDM_HOME"
    chown "$pw_uid":"$pw_gid" "$LDM_HOME"
    if [ -n "$XAUTHORITY_DIR" ]; then
        chown "$pw_uid":"$pw_gid" "$XAUTHORITY_DIR"
    fi

    if [ -z "$SSH_FOLLOW_SYMLINKS" ]; then
        # By default, don't follow symlinks under $HOME for localapps, as
        # that breaks some apps that try to create locks to other filesystems.
        # But do follow symlinks for any extra mounts.
        follow_extra_symlinks="follow_symlinks,"
    elif boolean_is_true "$SSH_FOLLOW_SYMLINKS"; then
        follow_home_symlinks="follow_symlinks,"
        follow_extra_symlinks="follow_symlinks,"
    fi
    # If the user's home directory is not located in the root cow device, assume
    # that it has already been mounted with other means, e.g. with FSTAB_x.
    if [ "$(stat -c %m "$LDM_HOME")" != "/" ]; then
        unset SSHFS_HOME
    else
        export SSHFS_HOME=true
        sshfs -o "${follow_home_symlinks}allow_other,nonempty,ControlPath=$LDM_SOCKET" "$LDM_SERVER:$LDM_HOME" "$LDM_HOME"
    fi

    # Mount other directories
    if [ -n "$LOCAL_APPS_EXTRAMOUNTS" ]; then
        oldifs="${IFS-not set}"
        IFS=","
        for extradir in $LOCAL_APPS_EXTRAMOUNTS; do
            mkdir -p "$extradir"
            sshfs -o "${follow_extra_symlinks}allow_other,nonempty,ControlPath=$LDM_SOCKET" "$LDM_SERVER:$extradir" "$extradir"
        done
        test "$oldifs" = "not set" && unset IFS || IFS="$oldifs"
    fi

    # /etc/cups is usually not shipped by the cups-client package, so attempt
    # to create it (it might fail if bind mounts are used).
    if [ ! -d /etc/cups ]; then
        mkdir /etc/cups || true
    fi

    # if cups is installed in the chroot, use LDM_SERVER for printing,
    # unless the user has enabled remote printer browsing via CUPS.
    if [ -d /etc/cups ]; then
        if [ -n "$CUPS_SERVER" ]; then
            echo "ServerName $CUPS_SERVER" > /etc/cups/client.conf
        elif ! grep -qsi "^Browsing on" /etc/cups/cupsd.conf; then
            echo "ServerName $LDM_SERVER" > /etc/cups/client.conf
        fi
    fi
fi
