#!/usr/bin/sh

# Usage: /opt/pd/bin/pddcesetup [force]
#
# pddcesetup configures DCE information for the Distributed Print System.
# pddcesetup must be run on each HP-UX host in your DCE cell that will
# execute the HPDPS in the Extended Environment.  If a host will run the
# HPDPS in the Basic Environment only, not in the Extended Environment, then
# execution of pddcesetup is not needed.
# 
# If the parameter "force" is given, then pddcesetup will give you the option
# to fully recreate security identities and CDS directories.  This option is
# useful if DCE has been only partially configured, or if configuration is
# accidentally removed after creation.  If the "force" parameter is not
# given, then pddcesetup quickly checks to see if it appears the DCE
# information has already been configured, and if so, pddcesetup does not
# attempt to configure any of this information.
# 
# The host on which pddcesetup is executed must already be configured as a
# DCE client or server.  You must also be DCE logged in using an account with
# sufficient administrator privileges to modify DCE security and namespace
# information (normally the cell administrator login).

typeset resp
typeset dcecp_rtns
typeset dcecp_runstr
typeset servpasswd
typeset force_redo
typeset -i errors
typeset -i warns
(( errors = 0 ))
(( warns = 0 ))
servpasswd=""

function early_exit
{
   print
   print \
"pddcesetup is exiting without completing HPDPS DCE configuration."
   exit 1
}


function dcecp_run
{
   dcecp_runstr="$1"
   /opt/dce/bin/dcecp -c "$1"
   dcecp_rtns=$?
}


function dcecp_ckreturn
{
   if [[ ${dcecp_rtns} -ne 0 ]]
   then
      print
      print "ERROR: dcecp returned status ${dcecp_rtns}."
      print "The error occurred on command:"
      print "   ${dcecp_runstr}"
      (( errors = errors + 1 ))
      ask_continue
   fi
}


function dcecp_cmd
{
   dcecp_run "$1"
   dcecp_ckreturn
}


function ask
{
    print "$1 \c"
    read resp
}

function ask_password
{
    confirmed=false
    stty -echo

    while [[ "${confirmed}" = "false" ]]
    do
       print
       ask "Please enter $1:"
       print

       if [[ "$2" = "confirm" ]]
       then
          first_resp="${resp}"
          ask "Please re-enter $1:"
          print

          if [[ "${resp}" = "${first_resp}" ]]
          then
             confirmed=true
          else
             print
             print \
"The two passwords entered do not match.  Please try entering and confirming"
             print \
"the new password again."
          fi

       else
          confirmed=true
       fi
    done

    stty echo
}

function ask_yesorno
{
   while /usr/bin/true
   do
      ask "$1"

      if [[ "$resp" = "y" || "$resp" = "yes" ]]
      then
         return 1

      elif [[ "$resp" = "n" || "$resp" = "no" ]]
      then
         return 0

      else
         print "You must enter y[es] or n[o] to this question."
      fi
   done
}


function ask_continue
{
   print
   ask_yesorno "Do you wish to continue executing pddcesetup (y/n)?"

   if [[ $? -eq 0 ]]
   then
      early_exit
   fi
}


function prompt_servpasswd
{
   if [[ "${servpasswd}" = "" ]]
   then
      print

      if [[ "$1" = "set" ]]
      then
         print \
"Please choose a unique password for the pd_server account. This password is"
         print \
"used by the HPDPS client daemon, spooler, and supervisor to automatically"
         print \
"DCE login to account pd_server."

      else
         print \
"The password for the pd_server account must now be entered so that it may"
         print \
"be stored in the local key table.  This password was previously chosen"
         print \
"for your DCE cell, perhaps in a previous execution of pddcesetup."
         print
         ask_yesorno "Are you prepared to enter this password (y/n)?"

         if [[ $? -eq 0 ]]
         then
            print \
"Execute pddcesetup on this host again when you are ready to enter this"
            print \
"password."
            early_exit
         fi
      fi

      print
      ask_password "the password for account pd_server" "confirm"
      servpasswd="$resp"
   fi
}


function create_group
{
   if [[ "${force_redo}" = "true" ]]
   then
      dcecp_run "group show $1" > /dev/null

      if [[ "${dcecp_rtns}" -eq 0 ]]
      then
         print "Group $1 already exists."
         return
      fi
   fi

   dcecp_cmd "group create $1"
}


function create_principal
{
   if [[ "${force_redo}" = "true" ]]
   then
      dcecp_run "principal show $1" > /dev/null

      if [[ "${dcecp_rtns}" -eq 0 ]]
      then
         print "Principal $1 already exists."
         return
      fi
   fi

   dcecp_cmd "principal create $1"
}


function create_adm_acct
{
   if [[ "${force_redo}" = "true" ]]
   then
      dcecp_run "account show adm_user" > /dev/null

      if [[ "${dcecp_rtns}" -eq 0 ]]
      then
         print "Account adm_user already exists."
         return
      fi
   fi

   print
   print \
"Please choose a unique password for new account adm_user.  This account"
   print \
"will be used by HPDPS administrators."
   ask_password "the password for account adm_user" "confirm"
   adminpasswd="$resp"
   print
   print "Creating account adm_user."
   cmd="account create adm_user -group pd_admin "\
"-organization ${org} -password ${adminpasswd} -mypwd ${passwd}"
   print "${cmd}" | /opt/dce/bin/dcecp
   dcecp_rtns=$?
   dcecp_runstr="account create adm_user -group pd_admin ..."
   dcecp_ckreturn
}


function create_serv_acct
{
   if [[ "${force_redo}" = "true" ]]
   then
      dcecp_run "account show pd_server" > /dev/null

      if [[ "${dcecp_rtns}" -eq 0 ]]
      then
         print "Account pd_server already exists."
         return
      fi
   fi

   prompt_servpasswd set
   print
   print "Creating account pd_server."
   cmd="account create pd_server -group subsys/dce/cds-server "\
"-organization ${org} -password ${servpasswd} -mypwd ${passwd}"
   print "${cmd}" | /opt/dce/bin/dcecp
   dcecp_rtns=$?
   dcecp_runstr="account create pd_server -group subsys/dce/cds-server ..."
   dcecp_ckreturn
}


function setup_sec
{
   print
   print \
"The new groups and accounts about to be created must be members of a DCE"
   print \
"\"organization\".  You may use an existing organization if you have already"
   print \
"defined one."
   print
   ask_yesorno "Do you wish to create a new DCE organization (y/n)?"
   neworg=$?

   if [[ "$neworg" -ne 0 ]]   
   then
      ask "Please enter the name of the new organization:"
      org="$resp"

      print
      print "Creating organization ${org}."
      dcecp_cmd "organization create ${org}"
   else
      ask "Please enter the name of the existing organization:"
      org="$resp"
   fi

   print
   print "Creating groups pd_admin and pd_operator."
   create_group pd_admin
   create_group pd_operator

   print
   print "Creating principals pd_server and adm_user."
   create_principal pd_server
   create_principal adm_user

   print
   print "Adding new principals to groups and organizations."

   dcecp_cmd "group add subsys/dce/cds-server -member pd_server"
   dcecp_cmd "organization add ${org} -member pd_server"
   dcecp_cmd "group add pd_admin -member adm_user"
   dcecp_cmd "organization add ${org} -member adm_user"

   print
   print \
"pddcesetup is ready to create DCE accounts pd_server and adm_user.  To"
   print \
"accomplish this, you must enter the password for the DCE account under"
   print \
"which you are currently logged in (${dce_login}).  If not entered"
   print \
"correctly, an attempt to create the new accounts will generate the error"
   print \
"message \"data integrity error\"."

   ask_password "the password for your current DCE login account" "noconfirm"
   passwd="$resp"

   create_adm_acct
   create_serv_acct
}


function create_directory
{
   if [[ "${force_redo}" = "true" ]]
   then
      dcecp_run "directory show $1" > /dev/null

      if [[ "${dcecp_rtns}" -eq 0 ]]
      then
         print "Directory $1 already exists."
         return
      fi
   fi

   dcecp_cmd "directory create $1"
}


function create_link
{
   if [[ "${force_redo}" = "true" ]]
   then
      dcecp_run "link show $1" > /dev/null

      if [[ "${dcecp_rtns}" -eq 0 ]]
      then
         print "Link $1 -> $2 already exists."
         return
      fi
   fi

   dcecp_cmd "link create $1 -to $2"
}


function create_acl
{
   if [[ "${force_redo}" = "true" ]]
   then
      dcecp_run "acl show $1 -$2" | fgrep -q "$3"

      if [[ "${dcecp_rtns}" -eq 0 && $? -eq 0 ]]
      then
         print "$2 ACL for $3 already exists."
         return
      fi
   fi

   dcecp_cmd "acl modify $1 -$2 -add {$3 $4}"
}


function setup_cds
{
   print
   print \
"Creating HPDPS directories and links in the DCE CDS namespace."

   create_directory "/.:/subsys/pd"
   create_directory "/.:/subsys/pd/client"
   create_directory "/.:/subsys/pd/logical_printers"
   create_directory "/.:/subsys/pd/physical_printers"
   create_directory "/.:/subsys/pd/queue"
   create_directory "/.:/subsys/pd/registry"
   create_directory "/.:/subsys/pd/servers"
   create_directory "/.:/subsys/pd/servers/spooler"
   create_directory "/.:/subsys/pd/servers/spvr"
   create_directory "/.:/subsys/pd/servers/srvr_objs"
   create_directory "/.:/subsys/pd/pd_gway_printers"
   create_directory "/.:/subsys/pd/pd_gway_printers/foreign_ds"
   create_directory "/.:/subsys/pd/pd_gway_printers/foreign_printer"

   create_link "/.:/pdsec" "/.:/subsys/pd/servers/srvr_objs"
   create_link "/.:/pdspl" "/.:/subsys/pd/servers/spooler"
   create_link "/.:/pdsuv" "/.:/subsys/pd/servers/spvr"
   create_link "/.:/pdlp"  "/.:/subsys/pd/logical_printers"
   create_link "/.:/pdpp"  "/.:/subsys/pd/physical_printers"
   create_link "/.:/pdq"   "/.:/subsys/pd/queue"
   create_link "/.:/pdc"   "/.:/subsys/pd/client"

   print
   print \
"Creating initial HPDPS Access Control List entries."

   create_acl /.:/pdsec ic "group pd_admin" "rwd"
   create_acl /.:/pdsec ic "group pd_operator" "rw"
   create_acl /.:/pdsec io "group pd_admin" "rwd"
   create_acl /.:/pdsec io "group pd_operator" "rw"
}


# main execution starts here.

unalias -a
PATH=/usr/bin:/usr/sbin:/opt/dce/bin:/opt/pd/bin

id | grep -q "^uid=0"

if [[ $? -ne 0 ]]
then
   print
   print \
"ERROR: Only the root login may execute pddcesetup."
   early_exit
fi

force_redo=false

if [[ "$1" = "force" ]]
then
   print \
"Because parameter \"force\" is specified, pddcesetup will force creation"
   print \
"of DCE configuration that is at least partially already created."
   force_redo=true
fi

if [[ ! -d /var/opt/pd/tmp ]]
then
   print
   print \
"ERROR: The HPDPS product does not appear to be installed on this host.  If"
   print \
"you believe this message is in error, then you must create directory"
   print \
"/var/opt/pd/tmp before executing pddcesetup."

   (( errors = errors + 1 ))
   early_exit
fi

if [[ ! -r /etc/rc.config.d/pd ]]
then
   print
   print \
"WARNING: Cannot read HPDPS configuration file /etc/rc.config.d/pd .  The"
   print \
"default version installed in /opt/pd/newconfig/etc/rc.config.d/pd should be"
   print \
"copied to /etc/rc.config.d/pd and edited appropriately before executing the"
   print \
"HPDPS.  pddcesetup cannot determine if the HPDPS will be executed in the"
   print \
"Extended Environment, and thus cannot determine if DCE configuration is"
   print \
"required.  pddcesetup will still configure DCE if you answer \"yes\" to the"
   print \
"prompt below."

   (( warns = warns + 1 ))
   ask_continue

else
   . /etc/rc.config.d/pd

   if [[ ${PD_ENV} != "extended" ]]
   then
      print
      print \
"WARNING: The HPDPS is not configured to execute in the Extended Environment"
      print \
"on this host.  pddcesetup configures DCE cell information used by the HPDPS"
      print \
"in the Extended Environment.  If this host will execute the HPDPS in the"
      print \
"Basic Environment only, then it is not necessary to run pddcesetup.  If"
      print \
"this host will execute the HPDPS in the Extended Environment then the"
      print \
"parameter PD_ENV in file /etc/rc.config.d/pd must be modified to the value"
   print \
"\"extended\".  pddcesetup will still configure DCE if you answer \"yes\" to"
   print \
"the prompt below."

      (( warns = warns + 1 ))
      ask_continue
   fi
fi


if [[ ! -x /opt/dce/bin/dcecp ]]
then
   print
   print \
"ERROR: Cannot execute /opt/dce/bin/dcecp.  A version of HP DCE that"
   print \
"       includes the dcecp utility must be installed and configured on this"
   print \
"       host before pddcesetup may be executed."
   early_exit
fi

print
print \
"Checking whether your host is configured in a DCE cell."

dcecp_run "cell show" > /dev/null

if [[ $dcecp_rtns -ne 0 ]]
then
   print
   print \
"WARNING: This host does not appear to be configured in a DCE cell.  Your"
   print \
"host must first be configured in a DCE cell before executing pddcesetup."
   print \
"You can configure DCE using SAM or the dce_config utility.  If your host is"
   print \
"configured in a cell then answer \"yes\" to the prompt below to continue"
   print \
"configuring HPDPS DCE information."

   (( warns = warns + 1 ))
   ask_continue
fi

print
print \
"Verifying your DCE login."

dce_login_problem=false
rm -f /var/opt/pd/tmp/dcesetup.tmp
dcecp_run "echo user:\$_u" > /var/opt/pd/tmp/dcesetup.tmp
grep ^user: /var/opt/pd/tmp/dcesetup.tmp | sed "s/user://g" | read -r dce_login
rm -f /var/opt/pd/tmp/dcesetup.tmp
dcecp_ckreturn

if [[ -x /opt/pd/lbin/pdverdce ]]
then
   /opt/pd/lbin/pdverdce

   if [[ $? -ne 0 ]]
   then
      print
      print \
"WARNING: pddcesetup has detected a problem with your DCE login.  Perhaps"
      print \
"you are not DCE logged in, or perhaps your authorization ticket has"
      print \
"expired.  You may execute /opt/dce/bin/klist to list information on your"
      print \
"DCE credentials.  You should be DCE logged in as the cell administrator,"
      print \
"and your authorization ticket should be current, before executing"
      print \
"pddcesetup.  If so, answer \"yes\" to the following prompt to continue"
      print \
"DCE setup."

      (( warns = warns + 1 ))
      ask_continue

   else
      print "You are DCE logged in as ${dce_login}."
   fi

else
   print
   print \
"WARNING: Could not execute /opt/pd/lbin/pdverdce.  The HPDPS may not be"
   print \
"properly installed on this host.  pddcesetup cannot validate your DCE login."
   print \
"You should be DCE logged in as the cell administrator before executing"
   print \
"pddcesetup.  If so, answer \"yes\" to the following prompt to continue"
   print \
"DCE setup."

   (( warns = warns + 1 ))
   ask_continue
fi

print
print \
"Checking whether HPDPS security identities have already been configured in"
print \
"your cell."

dcecp_run "account catalog" | fgrep -q "pd_server"
fgrep_rtn=$?
dcecp_ckreturn

if [[ ${fgrep_rtn} -eq 0 ]]
then
   do_sec_setup="false"
else
   do_sec_setup="true"
fi   

if [[ "$do_sec_setup" = "true" ]]
then
   print
   print \
"DCE security identities needed for the HPDPS have not yet been configured in"
   print \
"your DCE cell.  The security identities that must be configured are:"
   print
   print \
"     Accounts   adm_user and pd_server"
   print \
"     Principals adm_user and pd_server"
   print \
"     Groups     pd_admin and pd_operator"

   print
   ask_yesorno "Are you ready to configure these identities now (y/n)?"

   if [[ $? -eq 0 ]]
   then
      print \
"Execute pddcesetup again on this host when you are ready to configure these"
      print \
"identities, or after these identities are created by executing pddcesetup"
      print \
"on another host."

      early_exit
   fi

else
   if [[ "${force_redo}" = "true" ]]
   then
      print
      print \
"DCE security identities needed for the HPDPS have already been configured in"
      print \
"your DCE cell.  Since you have asked to force recreation of DCE"
      print \
"configuration, you can recreate these identities now, if needed."
      print
      ask_yesorno "Do you wish to recreate HPDPS security identities (y/n)?"

      if [[ $? -ne 0 ]]
      then
         do_sec_setup=true
      fi

   else
      print
      print \
"DCE security identities needed for the HPDPS have already been configured in"
      print \
"your DCE cell.  If any security identities are missing from your cell's"
      print \
"configuration, you may recreate these identities by executing pddcesetup"
      print \
"again with parameter \"force\"."
   fi
fi


if [[ "$do_sec_setup" = "true" ]]
then
   setup_sec
fi

if [[ ! -x /opt/dce/bin/rgy_edit ]]
then
   print
   print \
"ERROR: Cannot execute /opt/dce/bin/rgy_edit.  pddcesetup cannot configure"
   print \
"local key table entries on this host.  This host cannot run a HPDPS client"
   print \
"daemon, spooler, or supervisor until the necessary local key table entries"
   print \
"are created."
   (( errors = errors + 1 ))

else
   print
   print "Checking for existing pd_server entry in the local key table."

   keylist=$(print "ktlist" | /opt/dce/bin/rgy_edit)
   print "${keylist}" | grep -q "^?"

   if [[ $? -eq 0 ]]
   then
      print
      print "$keylist"
      print
      print \
"ERROR: /opt/dce/bin/rgy_edit has returned an error message above."
      (( errors = errors + 1 ))
      ask_continue
   fi

   print "${keylist}" | fgrep -q pd_server

   if [[ $? -eq 0 ]]
   then
      print \
"Local key table pd_server entry has already been configured."

   else
      print
      prompt_servpasswd alreadyset
      print "Adding entry for pd_server to the local key table."

      out=$(print "ktadd -p pd_server -pw ${servpasswd}" | /opt/dce/bin/rgy_edit)
      print "${out}" | grep -q "^?"

      if [[ $? -eq 0 ]]
      then
         print
         print "$out"
         print
         print \
"ERROR: /opt/dce/bin/rgy_edit has returned an error message above."
         (( errors = errors + 1 ))
         ask_continue
      fi
   fi
fi

do_setup_cds=false
print
print "Checking if CDS directories and ACLs have been created in your cell."

typeset dcecp_rtns
typeset dcecp_runstr

dcecp_run "directory show /.:/subsys/pd" > /var/opt/pd/tmp/dcesetup.tmp
dirlist=$(< /var/opt/pd/tmp/dcesetup.tmp)
rm -f /var/opt/pd/tmp/dcesetup.tmp

if [[ ${dcecp_rtns} -eq 0 ]]
then
   print
   print \
"CDS directory /.:/subsys/pd has already been created in your cell."

   if [[ "${force_redo}" = "true" ]]
   then
      print
      print \
"Since you have requested pddcesetup to recreate DCE configuration, you may"
      print \
"recreate the CDS directory and ACL structures now."
      print
      ask_yesorno "Do you wish to recreate CDS directories/ACLs (y/n)?"

      if [[ $? -ne 0 ]]
      then
         do_setup_cds=true
      fi

   else
      print \
"If any CDS subdirectories needed by the HPDPS are missing from your cell's"
      print \
"configuration, you may recreate them by executing pddcesetup again with"
      print \
"parameter \"force\"."
   fi

else
   if [[ "${dirlist}" = "Error: Requested entry does not exist" ]]
   then
      do_setup_cds=true
   else
      print
      print "${dirlist}"
      dcecp_ckreturn
      print \
"CDS directories may not have been created in your cell."
      ask_yesorno "Do you wish to create CDS directories now (y/n)?"

      if [[ $? -ne 0 ]]
      then
         do_setup_cds=true
      fi
   fi
fi

if [[ ${do_setup_cds} = true ]]
then
   setup_cds
fi

print

if [[ ${errors} -ne 0 ]]
then
   print "pddcesetup: DCE setup is complete with errors."

elif [[ ${warns} -ne 0 ]]
then
   print "pddcesetup: DCE setup is complete with warnings."

else
   print "pddcesetup: DCE setup is complete."
fi

exit 0
