#! /bin/bash
# ------------------------------------------------------------------------------
# Copyright (c) 2010, 2011, 2012 Vifib SARL and Contributors.
# All Rights Reserved.
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsibility of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# guarantees and support are strongly advised to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 3
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
#
# ------------------------------------------------------------------------------
#
# Simulate the command useradd to add a user on the Cygwin
#   useradd -d path -g init-group -s /bin/false -G group NAME
#
#   -g, --gid GROUP
#     The group name or number of the user's new initial login group. The group must exist.
#
#   -G, --groups GROUP1[,GROUP2,...[,GROUPN]]]
#     A list of supplementary groups which the user is also a member of.
#
#   -s
#     Shell used by user
#
export PATH=/usr/local/bin:/usr/bin:/usr/sbin:/sbin:/bin:$PATH
if ! source /usr/share/csih/cygwin-service-installation-helper.sh ; then
    echo "Error: Download the csih package at first, I need this file:"
    echo "  /usr/share/csih/cygwin-service-installation-helper.sh"
    exit 1
fi

# Check Administrator rights
csih_get_system_and_admins_ids
if [[ ! " $(id -G) " == *\ $csih_ADMINSUID\ * ]] ; then
    echo
    echo "Note that creating a new user requires that the current account has"
    echo "Administrator privileges.  You don't have the rights to run this script. "
    echo "Please login as Administrator, or right-click this script"
    echo "then click Run as administrator."
    echo
    exit 1
fi

# ======================================================================
# Routine: create_unprivileged_user
#   Creates a new (unprivileged) user as specified by $1.
#   Useful for running services that do not require elevated privileges,
#     or running servers like sshd in "privilege separation" mode.
#
#   Exits on catastrophic error
#   Returns 0 on total success
#   Returns 1 on failure
#
# csih_auto_answer=no behavior
#   if already exists
#     use it
#   else
#     do nothing, return 1
# ======================================================================
function create_unprivileged_user()
{
  csih_stacktrace "${@}"
  $_csih_trace
  local unpriv_user="$1"
  local unpriv_user_in_passwd=no
  local unpriv_user_in_sam=no
  local dos_var_empty=
  local ret=0

  _csih_setup

  /usr/bin/grep -q "^${unpriv_user}:" "${SYSCONFDIR}/passwd" && unpriv_user_in_passwd=yes
  csih_call_winsys32 net user "${unpriv_user}" >/dev/null 2>&1 && unpriv_user_in_sam=yes
  if [ "${unpriv_user_in_passwd}" != "yes" ]
  then
    if [ "${unpriv_user_in_sam}" != "yes" ]
    then
        dos_var_empty=$(/usr/bin/cygpath -w ${2-${LOCALSTATEDIR}/empty})
        csih_call_winsys32 net user "${unpriv_user}" /add /fullname:"${unpriv_user} nexedi slapos" \
          "/homedir:${dos_var_empty}" /active:no > /dev/null 2>&1 && unpriv_user_in_sam=yes
        if [ "${unpriv_user_in_sam}" != "yes" ]
        then
          csih_warning "Creation of user '${unpriv_user}' failed!"
        fi
    fi
    if [ "${unpriv_user_in_sam}" = "yes" ]
    then
      # user either already existed in local SAM, or we just created a new local
      # user.  Therefore, mkpasswd -l is appropriate.  However, the user does not
      # (yet) appear in /etc/passwd, so add it.
      /usr/bin/mkpasswd -l -u "${unpriv_user}" | /usr/bin/sed -n -e "/^${unpriv_user}/s/bash\$/false/p" >>\
        ${SYSCONFDIR}/passwd
      # make sure the previous command succeeded
      /usr/bin/grep -q "^${unpriv_user}:" "${SYSCONFDIR}/passwd" && unpriv_user_in_passwd=yes
      if [ "${unpriv_user_in_passwd}" != "yes" ]
      then
        csih_warning "Created new user '${unpriv_user}', but failed to add"
        csih_warning "corresponding entry to /etc/passwd!"
      fi
    fi
  else
    if [ "${unpriv_user_in_sam}" != "yes" ]
    then
      # FIXME: Needs real domain awareness to not print spurious warnings
      csih_warning "${unpriv_user} is in ${SYSCONFDIR}/passwd, but the"
      csih_warning "local machine's SAM does not know about ${unpriv_user}."
      csih_warning "Perhaps ${unpriv_user} is a pre-existing domain account."
      csih_warning "Continuing, but check if this is ok."
    fi
  fi
  # as long as the user is in /etc/passwd, return success
  # if missing from SAM, we've already issued a diagnostic
  # and are assuming the user is a valid domain account.
  [ "x${unpriv_user_in_passwd}" = "xyes" ] && return 0
  return 1
} # === End of create_unprivileged_user() === #

# ======================================================================
# Routine: add_member_to_group
#   Add a member $1 to a group $2, there is a special for slapos:
#   if $2 is not a group name, we'll try grp_$2 as group name
#
#   Exits on catastrophic error
#   Returns 0 on total success
#   Returns 1 on failure
#
#   if already exists
#     use it
#   else
#     do nothing, return 1
# ======================================================================

function add_member_to_group()
{
  local name=$1
  local grpname=$2
  net localgroup $grpname > /dev/null 2>&1 || grpname="grp_$grpname"
  net localgroup $grpname > /dev/null 2>&1 || return 1
  if ! net localgroup $grpname | grep -q -e "^$name$" ; then
      net localgroup $grpname $name /add
  fi
} # === End of add_member_to_group() === #

while getopts "Dd:g:G:p:s:r" opt ; do
    case $opt in
        d)
            USER_HOME=$OPTARG
            ;;
        g)
            USER_INIT_GROUP=$OPTARG
            ;;
        G)
            USER_OTHER_GROUP="$USER_OTHER_GROUP $OPTARG"
            ;;
        p)
            USER_PASSWORD=$OPTARG
            ;;
        s)
            USER_SHELL=$OPTARG
            ;;
        r)
            ;;
        *)
            echo Error while adding user in Cygwin
            exit 1
            ;;
    esac
done

shift $(($OPTIND - 1))
USER_NAME=$1

if [[ -z "${USER_NAME}" ]] ; then
    echo Error: no user name specified.
    exit 1
fi

create_unprivileged_user ${USER_NAME} $USER_HOME ||
(echo "Failed to create user ${USER_NAME}" ; exit 1)

for grpname in ${USER_INIT_GROUP} ${USER_OTHER_GROUP} ; do
    [[ -z "$grpname" ]] && continue
    add_member_to_group ${USER_NAME} $grpname ||
    (echo "Failed to add ${USER_NAME} to group $group" ; exit 1)
done

# net user "${USER_NAME}" /delete ||
# (echo "Failed to delete user ${USER_NAME}" ; exit 1)
# sed -i -e "/^${USER_NAME}/d" /etc/passwd