#!/bin/ksh # IBM_PROLOG_BEGIN_TAG # This is an automatically generated prolog. # # bos72X src/bos/usr/lib/nim/methods/c_function.sh 1.12 # # Licensed Materials - Property of IBM # # Restricted Materials of IBM # # COPYRIGHT International Business Machines Corp. 2012,2022 # All Rights Reserved # # US Government Users Restricted Rights - Use, duplication or # disclosure restricted by GSA ADP Schedule Contract with IBM Corp. # # IBM_PROLOG_END_TAG # @(#)03 1.12 src/bos/usr/lib/nim/methods/c_function.sh, cmdnim, bos72X, x2022_09A3 2/22/22 12:26:14 # ############################################################################## # # c_function # # When adding new function, edit the following section # USAGE string - Update usage for the new function # parse_attr() - Add the new function to the case statement # ck_attrs() - Add the new function to the case statement # run_operation() - Add the new function to the case statement # - Add the new function definition to the script # ############################################################################### NIMPATH=${0%/*} NIMPATH=${NIMPATH%/*} [[ ${NIMPATH} = ${0} ]] && NIMPATH=/usr/lpp/bos.sysmgt/nim NIM_METHODS="${NIMPATH}/methods" . ${NIM_METHODS}/c_sh_lib typeset COMMAND=`basename $0` typeset operation="" typeset ARGUMENT="" # Search by parse_attr_ass and ck_attrs typeset REQUIRED_ATTRS="" # Search by parse_attr_ass typeset OPTIONAL_ATTRS="client" # Search by ck_attrs typeset EXCLUSIVE_ATTRS="" typeset USAGE="$COMMAND -o operation [-v] [-a = ... ] [ ARGUMENT ]\n\ \n\ Note: The presence of attribute and ARGUMENT depend on the operation being invoked.\n\ \n\ operation: \n\ secure_tftp_access - add \"allow:/tftpboot\" to /etc/tftpaccess.ctl\n\ run_hmcauth - get dpasswd file from management server for the client and call hmcauth\n\ setup_dns_resource - check system for resolv.conf and (if found) define temp resource\n\ setup_file_resource - check system for list of file(s) and (if found) define temp resource\n\ \n\ Syntax:\n\ $COMMAND -o secure_tftp_access\n\ $COMMAND -o run_hmcauth -a client=\n\ $COMMAND -o setup_dns_resource -a client=\n\ $COMMAND -o setup_file_resource -a client=\n\ " #------------------------------------------------------------------------------- # # NAME: parse_attr # # PARAMETERS: None # # DESCRIPTION: Check if the correct argument is being passed for the operation. # The function calls parse_attr_ass to check on the two variables: # REQUIRED_ATTRS # OPTIONAL_ATTRS # New function should define the two variables if the # function requires checking for REQUIRED_ATTRS and OPTIONAL_ATTRS. # # RETURNS: (int) # 0 = success # 1 = failure # # OUTPUT: None # #------------------------------------------------------------------------------- parse_attr() { typeset rc=0 case $operation in "secure_tftp_access") ;; "run_hmcauth") ;; "setup_dns_resource") ;; "setup_file_resource") ;; *) echo "$USAGE" rc=1 ;; esac parse_attr_ass "${OPTARG}" rc=$? return $? } #------------------------------------------------------------------------------- # # NAME: check_attrs # # PARAMETERS: None # # DESCRIPTION: Check if the correct argument is being passed for the operation # The function calls ck_attrs to check on the two variables: # REQUIRED_ATTRS # EXCLUSIVE_ATTRS # New function should define the two variables if the # function requires checking for REQUIRED_ATTRS and EXCLUSIVE_ATTRS. # # RETURNS: (int) # 0 = success # 1 = failure # # OUTPUT: None # #------------------------------------------------------------------------------- check_attrs() { typeset rc=0 [[ -z $operation ]] && echo "$USAGE" && return 1 case $operation in "secure_tftp_access") ;; "run_hmcauth") if [[ -z $client ]]; then # # 0042-021 : the "" attribute is required for this # operation error ${ERR_MISSING_ATTR} "client" fi ;; "setup_dns_resource") if [[ -z $client ]]; then # # 0042-021 : the "" attribute is required for this # operation error ${ERR_MISSING_ATTR} "client" fi ;; "setup_file_resource") if [[ -z $client ]]; then # # 0042-021 : the "" attribute is required for this # operation error ${ERR_MISSING_ATTR} "client" fi ;; *) echo "$USAGE" rc=1 ;; esac # # NOTE: # When adding new function, if ARGUMENT is not needed, # then add the operation to be checked. # if [[ $operation = "secure_tftp_access" ]] && [[ -n $ARGUMENT ]]; then echo "$USAGE" return 1 fi ck_attrs rc=$? return $rc } #------------------------------------------------------------------------------- # # NAME: run_operation # # PARAMETERS: None # # DESCRIPTION: Call the function based on the operation. # New function should be defined in the case statement. # # RETURNS: (int) # 0 = success # 1 = failure # OUTPUT: None # #------------------------------------------------------------------------------- run_operation() { case $operation in "secure_tftp_access") secure_tftp_access return $? ;; "run_hmcauth") run_hmcauth return $? ;; "setup_dns_resource") download_dns_copy return $? ;; "setup_file_resource") download_file_copy return $? ;; *) echo "$USAGE" return 1 ;; esac return 0 } #------------------------------------------------------------------------------- # # NAME: secure_tftp_access # # FUNCTION: # Modifies or creates /etc/tftpaccess.ctl to ensure tftp access # is not granted to more than /tftpboot as a result of SPOT # creation on a machine in the NIM env. # # # EXECUTION ENVIRONMENT: # # NOTES: # -- uncomments #allow:/tftpboot # -- comments out deny:/tftpboot # -- when looking for the above, assumes that whitespace may # have been inserted anywhere in the line (even though this # is illegal). # -- creates file if does not exist # -- changes/sets permissions on /etc/tftpaccess.ctl # # RECOVERY OPERATION: # # DATA STRUCTURES: # parameters: # global: # tftp_enabled_by_nim = tells if NIM uncommented the # tftp entry in /etc/inetd.conf # # RETURNS: (int) # None # # OUTPUT: None # #------------------------------------------------------------------------------- function secure_tftp_access { typeset has_access="" typeset has_nimstr="" typeset ALLOW="" typeset DENY="" # if file already exists... if [[ -s ${TFTPACCESS} ]]; then # is there a "deny" for /tftpboot that needs commenting out? DENY="^[ ]*deny:[ ]*\/tftpboot[ ]*$" ${GREP} -qE "${DENY}" ${TFTPACCESS} if [[ $? -eq 0 ]]; then # comment it out ${SED} "s/${DENY}/#deny:\/tftpboot/g" ${TFTPACCESS} \ > ${TMPDIR}/.tftpaccess.ctl.$$ [[ $? -eq 0 ]] && \ ${MV} ${TMPDIR}/.tftpaccess.ctl.$$ ${TFTPACCESS} fi # is there an "allow" for /tftpboot that needs uncommenting? ALLOW="^[ ]*#[ ]*allow:[ ]*\/tftpboot[ ]*$" ${GREP} -qE "${ALLOW}" ${TFTPACCESS} if [[ $? -eq 0 ]]; then # uncomment the allow ${SED} "s/${ALLOW}/allow:\/tftpboot/g" ${TFTPACCESS} \ > ${TMPDIR}/.tftpaccess.ctl.$$ [[ $? -eq 0 ]] && \ ${MV} ${TMPDIR}/.tftpaccess.ctl.$$ ${TFTPACCESS} has_access=1 else # is there already access to /tftpboot? ${GREP} -E "^allow:\/tftpboot$" ${TFTPACCESS} >/dev/null 2>&1 [[ $? -eq 0 ]] && has_access=1 fi # is there an "# NIM access for network boot" string ${GREP} -qE "# NIM access for network boot" ${TFTPACCESS} if [[ $? -eq 0 ]]; then has_nimstr=1 fi fi # append to file if necessary (or create if not there) # add access for /tftpboot [[ -z "${has_nimstr}" ]] && echo "# NIM access for network boot" >> ${TFTPACCESS} [[ -z "${has_access}" ]] && echo "allow:/tftpboot" >> ${TFTPACCESS} # make sure permissions and owner are correct ${CHMOD} 644 ${TFTPACCESS} ${CHOWN} root.system ${TFTPACCESS} return 0 } #------------------------------------------------------------------------------- # # NAME: run_hmcauth # # FUNCTION: # Get the dpasswd file of the managed system managing the client. # Call dkeyexch with a hidden -S flag to save the temporary decrypted # password file. Using the data from the dpasswd file, calll # hmcauth (or pvcauth) to obtain client access to its managed system. # # EXECUTION ENVIRONMENT: # # NOTES: # # RECOVERY OPERATION: # # DATA STRUCTURES: # parameters: # global: # client = NIM client object # # RETURNS: (int) # None # # OUTPUT: None # #------------------------------------------------------------------------------- function run_hmcauth { typeset rc=1 typeset managed_type="" typeset managed_system="" typeset managed_port="" typeset managed_hostname="" typeset passwd_file="" typeset decrypt_file="" typeset project="" managed_system=`$LSNIM -a mgmt_profile1 $client 2>/dev/null | $AWK '(NR==2) {print $3}'` if [[ -z $managed_system ]]; then # # 0042-021 : the "" attribute is required for this # operation # error ${ERR_MISSING_ATTR} "mgmt_profile" fi managed_type=`$LSNIM -l $managed_system 2>/dev/null | $GREP "type " | $AWK '{print $3}'` managed_hostname=`$LSNIM -a if1 $managed_system 2>/dev/null | $AWK '(NR==2) {print $4}'` passwd_file=`$LSNIM -a passwd_file $managed_system 2>/dev/null | $AWK '(NR==2) {print $3}'` if [[ -e $passwd_file ]]; then # Check the validity of the managed system # (also rebuilds connection defaults for powervc) $NIM -o check $managed_system # Call dkeyexch to decrypt the passwd_file decrypt_file=`/usr/bin/dkeyexch -f $passwd_file -I $managed_type -H $managed_hostname -S 2>/dev/null | $GREP "/var/ibm/sysmgt/dsm/tmp"` else # error file doesn't exist (DNE) error $ERR_ENOENT $passwd_file fi if [[ $managed_type = powervc ]]; then project=`$LSNIM -a project $managed_system 2>/dev/null | $AWK '(NR==2) {print $3}'` fi # determine the management service port # -must call after validity check (above) managed_port=`$LSNIM -a mgmt_port $managed_system 2>/dev/null | $AWK '(NR==2) {print $3}'` if [[ -n $decrypt_file ]]; then # Get the user and password from the decrypted file typeset user=`$CAT $decrypt_file | $AWK '{print $1}'` typeset passwd=`$CAT $decrypt_file | $AWK '{print $2}'` $RM $decrypt_file 2>/dev/null # Call hmcauth/pvcauth via c_rsh against the client if [[ -n $user ]] && [[ -n $passwd ]] && [[ -n $managed_hostname ]]; then connect=`$LSNIM -a connect $client 2>/dev/null | $AWK -F"=" '(NR==2) {print $2}'` [[ $managed_type = powervc ]] && authcmd="/usr/sbin/pvcauth" || authcmd="/usr/sbin/hmcauth" if [[ ${connect} = *secure* ]]; then $C_RSH -e $client "$authcmd ${project:+-o $project} -u $user -p '$passwd' -a $managed_hostname -P $managed_port >/dev/null 2>&1" else $C_RSH $client "$authcmd ${project:+-o $project} -u $user -p '$passwd' -a $managed_hostname -P $managed_port >/dev/null 2>&1" fi rc=$? if [[ $rc -ne 0 ]]; then # # 0042-106 : unable to execute the "" program # error ${ERR_EXEC} $authcmd fi fi fi return $rc } #------------------------------------------------------------------------------- # # NAME: download_dns_copy # # FUNCTION: # Check client for existence of file /etc/resolv.conf # If found, a copy will be downloaded into a default # location. # # EXECUTION ENVIRONMENT: # # NOTES: # # RECOVERY OPERATION: # # DATA STRUCTURES: # parameters: # global: # client = NIM client object # # RETURNS: (int) # None # # OUTPUT: None # #------------------------------------------------------------------------------- function download_dns_copy { typeset -i rc=1 typeset hostname="" typeset resource_path="/export/nim/${client}/tmp$$" typeset filename="${resource_path}/resolv.conf" typeset objname="resolv_tmp$$" # use primary interface for remote service request hostname=`$LSNIM -a if1 $client 2>/dev/null | $AWK '(NR==2) {print $4}'` if [[ -z $hostname ]]; then error ${ERR_MISSING_ATTR} "if1" fi # check for file existence rc=`${C_RSH} $hostname "\"/usr/bin/test -f /etc/resolv.conf && print 0 || print 1\""` if [[ $rc -ne 0 ]]; then # File DNE - exit from function return $rc fi # file exists, download into global (predefined) path $MKDIR -p $resource_path rc=`${C_RSH} $hostname "cat /etc/resolv.conf" > $filename` if [[ $rc -ne 0 ]]; then # Download failed or invalid - remove content $RM -r $resource_path 2>/dev/null return $rc fi # download complete - define resource rc=`create_dns_resource $filename $objname` if [[ $rc -ne 0 ]]; then # Creation failed or invalid - remove content $RM -r $resource_path 2>/dev/null return $rc fi # mark for deletion upon dealloc (disregard errors) $NIM -o change -a sync_required=destroy $objname >/dev/null 2>&1 print "$objname" return $rc } #------------------------------------------------------------------------------- # # NAME: create_dns_resource # # FUNCTION: # Defines a name resolution resource (based on existing client data) # # EXECUTION ENVIRONMENT: # # NOTES: # # RECOVERY OPERATION: # # DATA STRUCTURES: # parameters: # filename = FQ path to resolv.conf file # object = name of resource # global: # client = NIM client object # # RETURNS: (int) # None # # OUTPUT: None # #------------------------------------------------------------------------------- function create_dns_resource { typeset rc=1 typeset filename="$1" typeset object="$2" if [[ -z "$filename" ]] || [[ -z "$object" ]]; then # Cannot create resource return 1 fi # Check if object exists $LSNIM $object >/dev/null 2>&1 if [[ $? -eq 0 ]]; then # Cannot create resource return 1 fi $NIM -o define -t resolv_conf -a server=master -a location=$filename $object >/dev/null 2>&1 return $? } #------------------------------------------------------------------------------- # # NAME: download_file_copy # # FUNCTION: # Check client for existence of file(s) referenced in $NIM_COPY_FILE # If found, a copy will be downloaded into a default location. # # EXECUTION ENVIRONMENT: # # NOTES: # # RECOVERY OPERATION: # # DATA STRUCTURES: # parameters: # global: # client = NIM client object # # RETURNS: (int) # None # # OUTPUT: None # #------------------------------------------------------------------------------- function download_file_copy { typeset -i rc=1 typeset hostname="" typeset content="" typeset filename="" typeset default_file="/tmp/._nim_${client}_tmp$$" typeset resource_path="/export/nim/${client}/tmp$$" typeset objname="file_tmp$$" # use primary interface for remote service request hostname=`$LSNIM -a if1 $client 2>/dev/null | $AWK '(NR==2) {print $4}'` if [[ -z $hostname ]]; then error ${ERR_MISSING_ATTR} "if1" fi # if NIM_COPY_FILE hasn't been set, then define # a file with single entry of /etc/hosts content=`env NIM_COPY_FILE 2>/dev/null` if [[ $? -ne 0 ]] || [[ ! -s "$content" ]]; then # copy default content and set var content=$default_file echo "/etc/hosts" > $content fi while read VAR do [[ -z ${VAR} ]] && continue # check for file existence rc=`${C_RSH} $hostname "\"/usr/bin/test -f ${VAR} && print 0 || print 1\""` [[ $rc -ne 0 ]] && continue # file exists, download into global (predefined) path filename="${resource_path}/${VAR}" $MKDIR -p `$DIRNAME "${filename}"` rc=`${C_RSH} $hostname "cat ${VAR}" > $filename` if [[ $rc -ne 0 ]]; then # Download failed or invalid - remove content $RM -r $resource_path 2>/dev/null return $rc fi # uncertainty on the mode, set a default $CHMOD 644 $filename done < $content # download complete - define resource rc=`create_file_resource $resource_path $objname` if [[ $rc -ne 0 ]]; then # Creation failed or invalid - remove content [[ -s "$default_file" ]] && $RM -r $default_file 2>/dev/null $RM -r $resource_path 2>/dev/null return $rc fi # remove tmp default content file [[ -s "$default_file" ]] && $RM -r $default_file 2>/dev/null # mark for deletion upon dealloc (disregard errors) $NIM -o change -a sync_required=destroy $objname >/dev/null 2>&1 print "$objname" return $rc } #------------------------------------------------------------------------------- # # NAME: create_file_resource # # FUNCTION: # Defines a file copying resource (based on existing client data) # # EXECUTION ENVIRONMENT: # # NOTES: # # RECOVERY OPERATION: # # DATA STRUCTURES: # parameters: # path = FQ path to root directory # object = name of resource # global: # client = NIM client object # # RETURNS: (int) # None # # OUTPUT: None # #------------------------------------------------------------------------------- function create_file_resource { typeset rc=1 typeset path="$1" typeset object="$2" if [[ -z "$path" ]] || [[ -z "$object" ]]; then # Cannot create resource return 1 fi # Check if object exists $LSNIM $object >/dev/null 2>&1 if [[ $? -eq 0 ]]; then # Cannot create resource return 1 fi $NIM -o define -t file_res -a server=master -a location=$path -a dest_dir=/ $object >/dev/null 2>&1 return $? } #------------------------------------------------------------------------------- # # NAME: c_function (main) # # PARAMETERS: -o operation= # [ -a = # -a ... # -a = ] # [ -v ] # [ ARGUMENT ] # # DESCRIPTION: Main for executing the operation. # # RETURNS: (int) # 0 = success # 1 = failure # OUTPUT: None # #------------------------------------------------------------------------------- typeset rc=0 typeset opset=0 while getopts :a:o:v c do case ${c} in a) # validate the attr ass [[ $opset -eq 0 ]] && echo "$COMMAND : please specify the operation with '-o' first.\n" && exit 1 parse_attr "${OPTARG}" [[ $? -ne 0 ]] && exit 1 # include the assignment for use in this environment eval ${variable}=\"${value}\" ;; o) # operation opset=1 operation=${OPTARG#*=} ;; v) # verbose mode (for debugging) set -x for i in $(typeset +f) do typeset -ft $i done ;; \?) # unknown option echo "$USAGE" exit 1 ;; esac done # Get the last argument shift $((OPTIND - 1)) ARGUMENT=$* # check for missing attrs check_attrs rc=$? if [[ $rc -eq 0 ]]; then run_operation rc=$? fi exit $rc