#!/bin/ksh # IBM_PROLOG_BEGIN_TAG # This is an automatically generated prolog. # # # # Licensed Materials - Property of IBM # # (C) COPYRIGHT International Business Machines Corp. 2004,2006 # 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 # @(#)80 1.38.1.4 src/avs/fs/mmfs/ts/admin/mmauth.sh, mmfs, avs_rgpfs24, rgpfs24s005a 6/14/06 14:39:42 ############################################################################## # # Usage: # # mmauth genkey {new | commit} # # mmauth add remoteClusterName -k keyfile [-l cipherList] # # mmauth update remoteClusterName [-C newClusterName] # [-k keyfile] [-l cipherList] # # mmauth delete {remoteClusterName | all} # # mmauth show [remoteClusterName | all] # # mmauth grant {remoteClusterName | all} -f {device | all} # [-a {rw | ro | none}] [-r {uid:gid | no}] # # mmauth deny {remoteClusterName | all} -f {device | all} # # where # # remoteClusterName is the fully-qualified name for a remote cluster that # will be allowed to mount file systems owned by this cluster. # # -C newClusterName is the new fully-qualified cluster name for an # already-defined cluster remoteClusterName. # # -k keyfile is the authentication key file generated by the mmauth # command on the remote cluster. # # -l cipherList is the cipher list to be used when establishing a connection # to the remote cluster. # # -f device is the name of the file system for which access is being # granted or denied. # # -a {rw | ro | none} is the type of access being granted. Default is "rw". # Specifying "none" is the same as running mmauth deny. # # -r {uid:gid | no} is a root credentials remapping (root-squash) option. # The UID and GID of all processes with root credentials # from the remote cluster, will be remapped to the specified # values. The default is not to remap the root UID and GID. # Note: The UID and GID must be specified as an unsigned # integers or as symbolic names that can be resolved # by the OS to valid UID and GID. Specifying 'no' # (or "off" or DEFAULT) turns off the remapping. # ############################################################################## # Include global declarations and service routines. . /usr/lpp/mmfs/bin/mmglobfuncs . /usr/lpp/mmfs/bin/mmsdrfsdef . /usr/lpp/mmfs/bin/mmfsfuncs sourceFile="mmauth.sh" [[ -n $DEBUG || -n $DEBUGmmauth ]] && set -x $mmTRACE_ENTER "$*" # Local work files. Names should be of the form: # fn=${tmpDir}fn.${mmcmd}.$$ verifiedKey=${tmpDir}verifiedKey.${mmcmd}.$$ fsFile=${tmpDir}fsFile.${mmcmd}.$$ tmpkey=${sslStageDir}tmpkey.${mmcmd}.$$ LOCAL_FILES=" $verifiedKey $tmpkey $fsFile " # Local variables usageMsg=249 contactNodesCount=0 # Local functions ########################################################################## # # Function: Determine the SHA digest (fingerprint) that corresponds # to the public key file for the specified cluster. # # Input: $1 - cluster name # $2 - sdrfs file to use # # Output: The SHA digest string. # # Returns: 0 - no errors encountered # 1 - unexpected error # ########################################################################## function getFingerprint # { typeset sourceFile="mmauth.sh" [[ -n $DEBUG || -n $DEBUGgetFingerprint ]] && set -x typeset clusterName=$1 typeset sdrfs=$2 typeset sdrfsLine clusterNameField lineTypeField keyLine keyFingerprint [[ ! -f $sdrfs ]] && return 1 $rm -f $tmpPublicKey # Go through the current mmsdrfs file and retrieve the requested information. IFS=":" exec 4<&- exec 4< $sdrfs while read -u4 sdrfsLine do # Parse the line. set -f ; set -- $sdrfsLine ; set +f clusterNameField=$1 lineTypeField=$2 # We are interested only in the AUTHORIZED_KEY lines for the specified cluster. if [[ $clusterNameField = $clusterName && $lineTypeField = $AUTHORIZED_KEY ]] then # The public key information is everything past the first 4 fields. shift 4 keyLine=$* keyLine="${keyLine%%+(:)}" # Examine the lines. If the key was generated by the cs4b version # of mmauth genkey, there will be stanza lines and the fingerprint # will be included. If the fingerprint is missing, or if this is # a key generated by a cs3b version of mmauth genkey, extract the # public key in a temp file. if [[ $keyLine = "clusterName="* || $keyLine = "clusterID="* || $keyLine = "genkeyFormat="* || $keyLine = "genkeyCompatibleFormat="* || $keyLine = "keyGenNumber="* || $keyLine = "publicKey=" || $keyLine = "certificate=" ]] then : # Skip the line. elif [[ $keyLine = "keyDigest="* ]] then # Return the key fingerprint. keyFingerprint="${keyLine#keyDigest=}" break else # Add the line to the key file. IFS="" # Reset IFS to preserve blanks and tabs. print -- "$keyLine" >> $tmpPublicKey checkForErrors "writing to file $tmpPublicKey" $? fi # end of if [[ $keyLine = "clusterName="* ]] fi # end of if [[ $clusterNameField = $clusterName && ... IFS=":" # Change the separator back to ":" for the next iteration. done # end while read -u4 sdrfsLine IFS="$IFS_sv" # Restore the default IFS settings. # If the fingerprint was not imbedded in the key stanza, # determine it with the help of the openssl command. if [[ -z $keyFingerprint && -s $tmpPublicKey ]] then keyFingerprint=$($openssl dgst -sha -hex < $tmpPublicKey) checkForErrors "openssl dgst -sha -hex $tmpPublicKey" $? fi [[ -z $keyFingerprint ]] && keyFingerprint="(undefined)" # Return the result. print -- "$keyFingerprint" return 0 } #------------ end function getFingerprint ----------------- ########################################################################## # # Function: Determine the SHA digest (fingerprint) that corresponds # to the specified public key file for the local cluster. # # Input: $1 - key file to use # # Output: The SHA digest string. # # Returns: 0 - no errors encountered # 1 - unexpected error # ########################################################################## function getLocalFingerprint # { typeset sourceFile="mmauth.sh" [[ -n $DEBUG || -n $DEBUGgetLocalFingerprint ]] && set -x typeset keyFile=$1 typeset keyLine keyFingerprint [[ ! -f $keyFile ]] && return 1 $rm -f $tmpPublicKey # Go through the specified file and retrieve the requested information. exec 4<&- exec 4< $keyFile while read -u4 keyLine do # Examine the lines. If the key was generated by the cs4b version # of mmauth genkey, there will be stanza lines and the fingerprint # will be included. If the fingerprint is missing, or if this is # a key generated by a cs3b version of mmauth genkey, extract the # public key in a temp file. if [[ $keyLine = "clusterName="* || $keyLine = "clusterID="* || $keyLine = "genkeyFormat="* || $keyLine = "genkeyCompatibleFormat="* || $keyLine = "keyGenNumber="* || $keyLine = "publicKey=" || $keyLine = "certificate=" ]] then : # Skip the line. elif [[ $keyLine = "keyDigest="* ]] then # Return the key fingerprint. keyFingerprint="${keyLine#keyDigest=}" break else # Add the line to the key file. print -- "$keyLine" >> $tmpPublicKey checkForErrors "writing to file $tmpPublicKey" $? fi # end of if [[ $keyLine = "clusterName="* ]] done # end while read -u4 keyLine # If the fingerprint was not imbedded in the key stanza, # determine it with the help of the openssl command. if [[ -z $keyFingerprint && -s $tmpPublicKey ]] then keyFingerprint=$($openssl dgst -sha -hex < $tmpPublicKey) checkForErrors "openssl dgst -sha -hex $tmpPublicKey" $? fi [[ -z $keyFingerprint ]] && keyFingerprint="(undefined)" # Return the result. print -- "$keyFingerprint" return 0 } #------------ end function getLocalFingerprint ----------------- ################################################################ # # Function: Retrieve the list of authorized file systems # for a given cluster. # # Input: $1 - cluster name # $2 - sdrfs file to use # # Output: A line for each of the file systems that # the specified cluster is allowed to access. # The following information is returned: # deviceName (maxAccessAllowed, rootSquashInfo) # # Returns: 0 - success # 1 - error encountered # ################################################################ function getFileSystemList # { typeset sourceFile="mmauth.sh" [[ -n $DEBUG || -n $DEBUGgetFileSystemList ]] && set -x $mmTRACE_ENTER "$*" typeset clusterName=$1 typeset sdrfs=$2 typeset fsList rootAllowed rootMappedTo [[ ! -s $sdrfs ]] && \ checkForErrors "getFileSystemList: Missing or empty file $sdrfs" 1 # Initialize dictionary items. rootAllowed=$(printInfoMsg 180) rootMappedTo=$(printInfoMsg 181) # Retrieve the information from the mmsdrfs file. fsList=$($awk -F: ' \ $'$NODESETID_Field' == "'$clusterName'" && \ $'$LINE_TYPE_Field' == "'$AUTHORIZED_FS'" { \ { printf ("%-9s (%s, ", \ $'$DEV_NAME_Field', \ $'$ACCESS_TYPE_Field') } \ if ( $'$ROOTSQUASH_UID_Field' == "") { \ { printf ("%s)", rootAllowMsg) } \ } else { \ { printf ("%s %s:%s)", \ rootMapMsg, \ $'$ROOTSQUASH_UID_Field', \ $'$ROOTSQUASH_GID_Field') } \ } \ # Indent the information on the next line. \ { printf ("\n%-21s", " ") } \ } \ END { print fsList } \ ' rootAllowMsg="$rootAllowed" rootMapMsg="$rootMappedTo" $sdrfs) checkForErrors awk $? # Remove the last (empty) line from the result. [[ -n $fsList ]] && fsList=${fsList%? } print -- "$fsList" return $rc } #------ end of function getFileSystemList ----------------- ################################################################ # # Function: Verify the specified uid:god string. Valid values # are symbolic names that can be traslated to legitimate # for the system UID and GID, or unsigned integers, # or one of the keywords that turn off root squashing. # # Input: $1 - uid:gid | off | no | DEFAULT | DELETE # $2 - sdrfs file to use # # Output: uid and gid converted to unsigned integers. # # Returns: 0 - success # 1 - error encountered # ################################################################ function verifyRootSquashString # { typeset sourceFile="mmauth.sh" [[ -n $DEBUG || -n $DEBUGverifyRootSquashString ]] && set -x $mmTRACE_ENTER "$*" typeset rsquashString=$1 typeset rsquashUid rsquashGid uid gid rc # See if the string is one of the many keywords # indicating no root squashing. if [[ $rsquashString = off || $rsquashString = DEFAULT || $rsquashString = no || $rsquashString = DELETE ]] then print -- "DEFAULT" return 0 fi # Parse the input string. IFS=":" set -f ; set -- $rsquashString ; set +f rsquashUid=$1 rsquashGid=$2 IFS="$IFS_sv" if [[ $rsquashUid = +([0-9]) ]] then uid=$rsquashUid elif [[ -n $rsquashUid ]] then uid=$($perl -e ' $uid = getpwnam "'$rsquashUid'"; if ($uid ne "") { printf "%u", $uid } ') else uid="" fi if [[ $rsquashGid = +([0-9]) ]] then gid=$rsquashGid elif [[ -n $rsquashGid ]] then gid=$($perl -e ' $gid = getgrnam "'$rsquashGid'"; if ($gid ne "") { printf "%u", $gid } ') else gid="" fi if [[ -z $uid ]] then # Invalid user name. printErrorMsg 172 $mmcmd $rsquashUid rc=1 elif [[ -z $gid ]] then # Invalid group name. printErrorMsg 173 $mmcmd $rsquashGid rc=1 else # Everything is OK. print -- "$uid $gid" rc=0 fi return $rc } #------ end of function verifyRootSquashString ----------------- ####################### # Mainline processing ####################### ####################################### # Process the command line arguments. ####################################### [[ $arg1 = '-?' || $arg1 = '-h' || $arg1 = '--help' || $arg1 = '--' ]] && \ syntaxError "help" $usageMsg action=$arg1 [[ -z $action ]] && \ syntaxError "missingArgs" $usageMsg remoteClusterName=$arg2 checkName clusterName 255 "$remoteClusterName" [[ $? -ne 0 ]] && cleanupAndExit # Allow "ls" to be used in place of "show". [[ $action = ls ]] && action=show # Allow "revoke" to be used in place of "deny". [[ $action = revoke ]] && action=deny # arg2 must be specified for all subcommands with the possible # exception of the "show" subcommand. It is either the keyword # "new" or "commit" for the "genkey" subcommand, or is the name # of the remote cluster for the rest of the subcommands. if [[ -z $arg2 ]] then if [[ $action = show ]] then remoteClusterName=all elif [[ $action = add || $action = update || $action = delete || $action = grant || $action = deny || $action = genkey ]] then syntaxError "missingArgs" $usageMsg else syntaxError "keyword" $usageMsg "$action" fi # end if [[ $action = show ]] fi # end if [[ -z $arg2 ]] # Continue with the rest of the parameters. if [[ $action = genkey ]] then # The second argument must be "new" or "commit". genkeyAction=$arg2 [[ $genkeyAction != new && $genkeyAction != commit ]] && \ syntaxError "keyword" $usageMsg "$action" # No other arguments are expected. [[ -n $arg3 ]] && syntaxError "extraArg" $usageMsg $arg3 elif [[ $action = delete || $action = show ]] then # No other arguments are expected. [[ -n $arg3 ]] && syntaxError "extraArg" $usageMsg $arg3 elif [[ $action = add || $action = update ]] then shift 2 # Move past the cluster name in the parameter list. # Process the individual arguments and the values associated with them. while getopts :C:k:l: OPT do case $OPT in C) [[ -n $Cflag ]] && syntaxError "multiple" $noUsageMsg "-$OPT" Cflag="-$OPT"; Carg=$OPTARG; newClusterName=$Carg [[ $action != update ]] && \ syntaxError "invalidOption" $usageMsg "-$OPT" checkName clusterName 255 "$Carg" [[ $? -ne 0 ]] && cleanupAndExit ;; k) [[ -n $kflag ]] && syntaxError "multiple" $noUsageMsg "-$OPT" kflag="-$OPT"; karg=$OPTARG; [[ -z $karg || $karg = DEFAULT ]] && karg=DELETE keyfile=$karg ;; l) [[ -n $lflag ]] && syntaxError "multiple" $noUsageMsg "-$OPT" lflag="-$OPT"; larg=$OPTARG; [[ -z $larg || $larg = DEFAULT ]] && larg=DELETE # Replace any colons in the cipher list string with commas. cipherList=$(print -- "$larg" | $sed 's/:/,/g') ;; +[Ckl]) # Invalid option. syntaxError "invalidOption" $usageMsg $OPT ;; :) # Missing argument. syntaxError "missingValue" $usageMsg $OPTARG ;; *) # Invalid option. syntaxError "invalidOption" $usageMsg $OPTARG ;; esac done shift OPTIND-1 [[ $# != 0 ]] && syntaxError "extraArg" $usageMsg $1 # Ensure required parameters are specified. if [[ $action = add ]] then [[ -z $karg ]] && \ syntaxError "missingArgs" $usageMsg else # $action = update [[ -z $Carg && -z $karg && -z $larg ]] && \ syntaxError "missingArgs" $usageMsg fi elif [[ $action = grant || $action = deny ]] then shift 2 # Move past the cluster name in the parameter list. # Process the individual arguments and the values associated with them. while getopts :a:f:r: OPT do case $OPT in a) [[ -n $aflag ]] && syntaxError "multiple" $noUsageMsg "-$OPT" aflag="-$OPT"; aarg=$OPTARG; [[ $action = deny ]] && \ syntaxError "invalidOption" $usageMsg $OPT [[ $aarg = none ]] && aarg=deny [[ $aarg != rw && $aarg != ro && $aarg != deny ]] && \ syntaxError "invalidOption" $usageMsg "-$OPT $OPTARG" accessType=$aarg ;; f) [[ -n $fflag ]] && syntaxError "multiple" $noUsageMsg "-$OPT" fflag="-$OPT"; farg=$OPTARG; device=$farg ;; r) [[ -n $rflag ]] && syntaxError "multiple" $noUsageMsg "-$OPT" rflag="-$OPT"; rarg=$OPTARG; ;; +[afr]) # Invalid option. syntaxError "invalidOption" $usageMsg $OPT ;; :) # Missing argument. syntaxError "missingValue" $usageMsg $OPTARG ;; *) # Invalid option. syntaxError "invalidOption" $usageMsg $OPTARG ;; esac done shift OPTIND-1 [[ $# != 0 ]] && syntaxError "extraArg" $usageMsg $1 # Ensure required parameters are specified. [[ -z $device ]] && \ syntaxError "missingArgs" $usageMsg [[ -z $accessType ]] && accessType=rw # Verify the device name. deviceName=${device##+(/)dev+(/)} # name stripped of /dev/ prefix fqDeviceName="/dev/$deviceName" # fully-qualified name (with /dev/ prefix) if [[ $deviceName = /* ]] then printErrorMsg 169 $mmcmd $device cleanupAndExit elif [[ $deviceName = */* ]] then printErrorMsg 170 $mmcmd $device cleanupAndExit fi # Verify the root squash string. if [[ -z $rarg ]] then rsquashUid="" rsquashGid="" else rsquashString=$(verifyRootSquashString $rarg) [[ $? -ne 0 ]] && \ syntaxError "invalidOption" $noUsageMsg "-r $rarg" if [[ $rsquashString = DEFAULT ]] then rsquashUid="" rsquashGid="" else # Parse the result from verifyRootSquashString. set -f ; set -- $rsquashString ; set +f rsquashUid=$1 rsquashGid=$2 fi # end of if [[ $rsquashString = DEFAULT ]] fi # end of if [[ -z $rsquashString ]] # If the specified access type is "deny" (or "none"), # convert the action to "deny". [[ $accessType = deny ]] && action=deny else # Invalid action requested. syntaxError "keyword" $usageMsg "$action" fi # end if [[ $action = genkey ]] # Determine the lookup order for resolving host names. [[ $osName != AIX ]] && resolveOrder=$(setHostResolveOrder) ####################################################################### # Set up trap exception handling and call the gpfsInit function. # It will ensure that the local copy of the mmsdrfs and the rest of # the GPFS system files are up-to-date and will obtain the sdr lock. ####################################################################### if [[ $action = show ]] then trap pretrap2 HUP INT QUIT KILL gpfsInitOutput=$(gpfsInit nolock) rc=$? else trap pretrap HUP INT QUIT KILL # If action is genkey, tell gpfsInit (and related functions) # to bypass the checking and rebuilding of the security files. [[ $action = genkey ]] && export MMAUTH_GENKEY_RUNNING=yes gpfsInitOutput=$(gpfsInit $lockId) rc=$? unset MMAUTH_GENKEY_RUNNING fi setGlobalVar $rc $gpfsInitOutput # Find out the default cipher list value to be used. if [[ $action = show ]] then defaultCipherList=$(showCfgValue cipherList) fi ####################################################################### # Perform any remaining parameter checking that requires knowledge of # the sdrfsFormatLevel level (set by gpfsInit above). Ensure the user # is not trying to utilize function that has not been enabled yet. ####################################################################### # Ensure the key file exists and has the correct format. if [[ -n $keyfile && $keyfile != DELETE ]] then verifyPublicKeyFile $keyfile $sdrfsFormatLevel $verifiedKey \ $newClusterName $remoteClusterName [[ $? -ne 0 ]] && cleanupAndExit if [[ $sdrfsFormatLevel -eq 0 ]] then # Ensure that the provided key file was generated by a 2.3 version of mmauth. $grep -q -e "^clusterName=" $verifiedKey >/dev/null 2>&1 rc=$? if [[ $rc -eq 0 ]] then print -u2 "$mmcmd: The specified public key file cannot be handled until you" print -u2 " run \"mmchconfig release=LATEST\" to activate the new function." cleanupAndExit fi fi # end of if [[ $sdrfsFormatLevel -eq 0 ]] fi # end of if [[ -n $keyfile && $keyfile != DELETE ]] # Ensure the version of openssl installed on this node # understands the specified cipher list. if [[ -n $cipherList && $cipherList != DELETE ]] then if [[ $cipherList = "AUTHONLY" ]] then ciphers=$($openssl ciphers "NULL-SHA") elif [[ $cipherList = *"AUTHONLY"* ]] then print -u2 "$mmcmd: AUTHONLY cannot be specified in conjunction with other ciphers." else ciphers=$($openssl ciphers rsa "$cipherList") fi if [[ $cipherList != "AUTHONLY" && $sdrfsFormatLevel -eq 0 ]] then print -u2 "$mmcmd: Support for cipher lists other than AUTHONLY has not been enabled yet." print -u2 " Run \"mmchconfig release=LATEST\" to activate the new function." cleanupAndExit fi if [[ -z "$ciphers" ]] then # The specified cipher list is not supported. printErrorMsg 483 $mmcmd "$value" cleanupAndExit else : # The new cipher list is acceptable. fi # end of if [[ -z "$ciphers" ]] fi # end of if [[ -n $cipherList && $cipherList != DELETE ]] ####################################################################### # # Go through the mmsdrfs file and make the necessary changes. # ####################################################################### $rm -f $newsdrfs $nodefile $allClusterNodes IFS=":" exec 3<&- exec 3< $mmsdrfsFile while read -u3 sdrfsLine do # Parse the line. set -f ; set -A v -- - $sdrfsLine ; set +f IFS="$IFS_sv" # Restore the default IFS settings. printLine=true # Assume the line will be printed. # Change some of the fields depending on the type of line. case ${v[$LINE_TYPE_Field]} in $VERSION_LINE ) # Increment the generation number. newGenNumber=${v[$SDRFS_GENNUM_Field]}+1 v[$SDRFS_GENNUM_Field]=$newGenNumber # Retrieve the current key generation numbers and other information. newKeyGenNumber=${v[$NEW_KEY_Field]} [[ -z $newKeyGenNumber ]] && newKeyGenNumber=0 committedKeyGenNumber=${v[$COMMITTED_KEY_Field]} [[ -z $committedKeyGenNumber ]] && committedKeyGenNumber=0 secLevel=${v[$SECLEVEL_Field]} [[ -z $secLevel ]] && secLevel=0 ourClusterName=${v[$CLUSTER_NAME_Field]} ourClusterId=${v[$CLUSTERID_Field]#gpfs} if [[ $action = genkey ]] then # Automatically "commit" old clusters that already have # established private keys (with cs3b level of mmauth). [[ $committedKeyGenNumber -eq 0 ]] && \ committedKeyGenNumber=$newKeyGenNumber if [[ $genkeyAction = new ]] then # Do not allow a new key to be generated if a previously # generated key has not been committed yet. if [[ $committedKeyGenNumber -lt $newKeyGenNumber ]] then # Run: mmauth genkey commit. printErrorMsg 157 $mmcmd "mmauth genkey commit" cleanupAndExit fi # Increment the generation number for the new key # that we are about to create. (( newKeyGenNumber += 1 )) # If this is the very first genkey request, # or if the new code has not been activated yet, # or if this the first genkey request after # activating the new genkey file format, # automatically commit the key. [[ $newKeyGenNumber -eq 1 || $sdrfsFormatLevel -eq 0 || -z ${v[$KEYFILE_FORMAT_Field]} || ${v[$KEYFILE_FORMAT_Field]} -eq 0 ]] && \ committedKeyGenNumber=$newKeyGenNumber # Put the key numbers in the mmsdrfs file. v[$NEW_KEY_Field]=$newKeyGenNumber v[$COMMITTED_KEY_Field]=$committedKeyGenNumber [[ $sdrfsFormatLevel -ge 1 ]] && \ v[$KEYFILE_FORMAT_Field]=$CURRENT_KEYFILE_FORMAT else # genkeyAction = commit # See if there is anything to commit. if [[ $committedKeyGenNumber -eq $newKeyGenNumber ]] then if [[ $newKeyGenNumber -eq 0 ]] then # There is nothing to commit. # Tell the user to run mmauth genkey new. printErrorMsg 155 $mmcmd "mmauth genkey new" else # The current authentication files are already committed. printErrorMsg 156 $mmcmd fi cleanupAndExit fi # Ensure a cipher list has been established. if [[ $secLevel -eq 0 ]] then # You must establish a cipher list first. Tell the user to run # mmauth update $ourClusterName -l printErrorMsg 158 $mmcmd "mmauth update $ourClusterName -l " cleanupAndExit fi # Things seem to be OK. Commit the key. committedKeyGenNumber=$newKeyGenNumber v[$COMMITTED_KEY_Field]=$committedKeyGenNumber fi # end of if [[ $genkeyAction = new ]] fi # end of if [[ $action = genkey ]] # See whether the target of the operation is the local cluster. [[ $remoteClusterName = "." ]] && \ remoteClusterName=$ourClusterName if [[ $remoteClusterName = $ourClusterName ]] then remoteClusterName=$HOME_CLUSTER clusterFound=yes if [[ $action = add || $action = delete || $action = grant || $action = deny ]] then # Operation not allowed for the local cluster. printErrorMsg 294 $mmcmd cleanupAndExit fi if [[ $action = update ]] then if [[ -n $newClusterName ]] then # Operation not allowed for the local cluster. printErrorMsg 294 $mmcmd cleanupAndExit fi if [[ -n $keyfile ]] then # Run "mmauth genkey" to establish a new key. printErrorMsg 314 $mmcmd cleanupAndExit fi if [[ -n $cipherList ]] then # Ensure the security level field is set correctly. if [[ $cipherList = DELETE ]] then secLevel=0 else if [[ $newKeyGenNumber -eq 0 ]] then # Run "mmauth genkey" first. printErrorMsg 307 $mmcmd cleanupAndExit fi secLevel=1 fi # end of if [[ $cipherList = DELETE ]] v[$SECLEVEL_Field]=$secLevel fi # end of if [[ -n $cipherList ]] fi # end of if [[ $action = update ]] fi # end of if [[ $remoteClusterName = $ourClusterName ]] ;; $NODESET_HDR ) if [[ $action = update && -n $cipherList && $remoteClusterName = $HOME_CLUSTER ]] then # Update the cipher list for the local cluster. currentCipherList=${v[$CIPHER_LIST_Field]} [[ -z $currentCipherList ]] && currentCipherList=DELETE if [[ $cipherList != DELETE ]] then v[$CIPHER_LIST_Field]=$cipherList else v[$CIPHER_LIST_Field]="" fi fi # end of if [[ $action = update && -n $cipherList && ... ;; $MEMBER_NODE ) # Add the reliable node name to the appropriate files. # allClusterNodes contains the names of all nodes in the cluster. print -- "${v[$REL_HOSTNAME_Field]}" >> $allClusterNodes checkForErrors "writing to file $allClusterNodes" $? # nodefile contains the names of all nodes except the # primary and backup servers and the node on which the # command is executed (this node). if [[ ${v[$REL_HOSTNAME_Field]} != $primaryServer && ${v[$REL_HOSTNAME_Field]} != $backupServer && ${v[$REL_HOSTNAME_Field]} != $ourNodeName ]] then print -- "${v[$REL_HOSTNAME_Field]}" >> $nodefile checkForErrors "writing to file $nodefile" $? fi # If this is the line for the node that is executing # this command, set the preferredNode variable. [[ ${v[$NODE_NUMBER_Field]} = $ourNodeNumber ]] && \ preferredNode=${v[$REL_HOSTNAME_Field]} ;; $MMFSCFG ) if [[ $action = update && -n $cipherList && $remoteClusterName = $HOME_CLUSTER ]] then # If changing the cipher list for the local cluster, remove # the line from the mmsdrfs file. The mmfs.cfg information # will be added back before committing the changes. printLine=false # Extract the mmfs.cfg information. # It is everything past the first 4 fields. cfgLine="${v[5]}:${v[6]}:${v[7]}:${v[8]}:${v[9]}:${v[10]}:${v[11]}" cfgLine="$cfgLine:${v[12]}:${v[13]}:${v[14]}:${v[15]}:${v[16]}:${v[17]}" cfgLine="$cfgLine:${v[18]}:${v[19]}:${v[20]}:${v[21]}:${v[22]}" # To preserve tabs, temporarily set IFS to new line only. IFS=" " # Strip trailing colons and write the line to the file. print -- "${cfgLine%%+(:)}" >> $tmpCfg checkForErrors "writing to file $tmpCfg" $? IFS="$IFS_sv" # Restore the default IFS settings. fi # end of if [[ $action = update && -n $cipherList && ... ;; $AUTHORIZED_CLUSTER ) if [[ ${v[$NODESETID_Field]} = $remoteClusterName || $remoteClusterName = all && ($action = show || $action = delete || $action = grant || $action = deny) ]] then clusterFound=yes clusterNameList="$clusterNameList ${v[$NODESETID_Field]} " # Processing depends on the specified action: case $action in add ) # The remote cluster is already defined. printErrorMsg 316 $mmcmd $remoteClusterName cleanupAndExit ;; update ) if [[ -n $cipherList ]] then if [[ $cipherList != DELETE ]] then v[$CIPHER_LIST_Field]=$cipherList else v[$CIPHER_LIST_Field]="" fi fi [[ -n $newClusterName ]] && \ v[$NODESETID_Field]=$newClusterName ;; delete ) printLine=false ;; show ) # Display the cluster name. header=$(printInfoMsg 442) printf "%-20s %s\n" "$header" "${v[$NODESETID_Field]}" # Display the cipher list. header=$(printInfoMsg 443) cipherList="${v[$CIPHER_LIST_Field]}" if [[ -z $cipherList ]] then # If there is no explicit cipher list for this cluster, # we use the cipher list for the local cluster. cipherList=$defaultCipherList [[ -z $cipherList ]] && cipherList="(none specified)" fi # end of if [[ -z $cipherList ]] printf "%-20s %s\n" "$header" "$cipherList" $rm -f $tmpPublicKey $fsFile # Display the SHA digest (public key fingerprint). header=$(printInfoMsg 444) keyFingerprint=$(getFingerprint ${v[$NODESETID_Field]} $mmsdrfsFile) printf "%-20s %s\n" "$header" "$keyFingerprint" # Display the file systems that can be accessed by the cluster. header=$(printInfoMsg 445) fsAuthList=$(getFileSystemList ${v[$NODESETID_Field]} $mmsdrfsFile) checkForErrors getFileSystemList $? [[ -z $fsAuthList ]] && fsAuthList="(none authorized)" printf "%-20s %s\n\n" "$header" "$fsAuthList" ;; grant ) : # noop ;; deny ) : # noop ;; *) checkForErrors "unexpected action $action" 1 ;; esac # end case $action in fi # end if [[ ${v[$NODESETID_Field]} = $remoteClusterName || ... ;; $AUTHORIZED_KEY ) if [[ ${v[$NODESETID_Field]} = $remoteClusterName || $remoteClusterName = all && ($action = show || $action = delete) ]] then # Processing depends on the specified action: case $action in add ) # The remote cluster is already defined. printErrorMsg 316 $mmcmd $remoteClusterName cleanupAndExit ;; update ) [[ -n $keyfile ]] && printLine=false if [[ -n $newClusterName ]] then v[$NODESETID_Field]=$newClusterName [[ ${v[$LINE_NUMBER_Field]} = 1 ]] && \ v[$KEY_Field]="clusterName=$newClusterName" fi ;; delete ) printLine=false ;; show ) : # noop ;; grant ) : # noop ;; deny ) : # noop ;; *) checkForErrors "unexpected action $action" 1 ;; esac # end case $action in fi # end if [[ ${v[$NODESETID_Field]} = $remoteClusterName || ... ;; $SG_HEADR ) if [[ ${v[$DEV_NAME_Field]} = $deviceName || $device = all ]] then if [[ ${v[$NODESETID_Field]} = $HOME_CLUSTER ]] then # We are making changes to this file system. fsFound=yes fsList="$fsList ${v[$DEV_NAME_Field]} " elif [[ $device != all ]] then # Command is not allowed for remote file systems. printErrorMsg 106 $mmcmd $device ${v[$NODESETID_Field]} cleanupAndExit fi fi # end if [[ ${v[$DEV_NAME_Field]} = $deviceName || $device = all ]] ;; $AUTHORIZED_FS ) if [[ (${v[$NODESETID_Field]} = $remoteClusterName || $remoteClusterName = all) && (${v[$DEV_NAME_Field]} = $deviceName || $device = all || $action = delete) ]] then if [[ $action = delete || $action = deny ]] then # Remove from the file the affected AUTHORIZED_FS lines. printLine=false elif [[ $action = grant ]] then # If changing an existing authorization, update the affected fields. if [[ -n $aarg ]] then v[$ACCESS_TYPE_Field]=$accessType fi if [[ -n $rarg ]] then v[$ROOTSQUASH_UID_Field]=$rsquashUid v[$ROOTSQUASH_GID_Field]=$rsquashGid fi # Tell the guy what exactly he is doing. if [[ -z ${v[$ROOTSQUASH_UID_Field]} ]] then printInfoMsg 182 $mmcmd ${v[$NODESETID_Field]} \ ${v[$DEV_NAME_Field]} ${v[$ACCESS_TYPE_Field]} else printInfoMsg 183 $mmcmd ${v[$NODESETID_Field]} \ ${v[$DEV_NAME_Field]} ${v[$ACCESS_TYPE_Field]} \ ${v[$ROOTSQUASH_UID_Field]} ${v[$ROOTSQUASH_GID_Field]} fi # Add the name of the fs to the list of processed file systems. # Note: The trailing blank is important. processedFileSystems="$processedFileSystems ${v[$NODESETID_Field]}:${v[$DEV_NAME_Field]} " else : # should not get here. fi # end of if [[ $action = delete || $action = deny ]] fi # end of if [[ (${v[$NODESETID_Field]} = $remoteClusterName ... if [[ ${v[$NODESETID_Field]} = $remoteClusterName ]] then [[ $action = update && -n $newClusterName ]] && \ v[$NODESETID_Field]=$newClusterName fi ;; * ) # Pass all other lines without a change. ;; esac # end of Change some of the fields # Build and write the line to the new mmsdrfs file. if [[ $printLine = true ]] then print_newLine >> $newsdrfs checkForErrors "writing to file $newsdrfs" $? fi IFS=":" # Change the separator back to ":" for the next iteration. done # end while read -u3 mmsdrfsFile IFS="$IFS_sv" # Restore the default IFS settings. ######################################### # Additional action-specific processing. ######################################### if [[ $action = genkey ]] then if [[ $genkeyAction = new ]] then # Ensure the OpenSSL code is installed. if [[ ! -x $openssl ]] then # openssl command not found. printErrorMsg 159 $mmcmd $openssl cleanupAndExit fi # If the sslrandfile user exit is installed, use it to determine # the value for the -rand paramter for the openssl calls. if [[ -x $sslrandfile ]] then randFile=$($sslrandfile 2>/dev/null) [[ -n $randFile ]] && \ randOpt="-rand $randFile" fi # If the multiple keys support has not been activated yet, # ensure the daemon is not running anywhere. if [[ $sdrfsFormatLevel -eq 0 ]] then printInfoMsg 339 verifyDaemonInactive $allClusterNodes $mmcmd [[ $? -ne 0 ]] && cleanupAndExit daemonInactive=yes fi # Regenerate the openssl.conf file. $sed 's/= gpfsCluster/= '$ourClusterName'/' $opensslConfFile > $certConfigFile checkForErrors "creating $certConfigFile" $? # Generate the new local private key. umask 077 $openssl genrsa $randOpt -out $tmpPrivateKey 512 checkForErrors "openssl genrsa $randOpt -out $tmpPrivateKey 512" $? # If the multiple keys functionality is enabled, generate # the corresponding private key and certificate files. # Otherwise, stage the private key file as is. if [[ $sdrfsFormatLevel -eq 0 ]] then $cp $tmpPrivateKey ${privateKey}$newKeyGenNumber checkForErrors "cp $tmpPrivateKey ${privateKey}$newKeyGenNumber" $? $mv $tmpPrivateKey $tmpkey checkForErrors "mv $tmpPrivateKey $tmpkey" $? fileToStage="${privateKey}$newKeyGenNumber" else # Generate the public key file and find its SHA digest. $openssl rsa -in $tmpPrivateKey -pubout -out $tmpPublicKey checkForErrors "openssl rsa -in $tmpPrivateKey -pubout -out $tmpPublicKey" $? keyFingerprint=$($openssl dgst -sha -hex < $tmpPublicKey 2>/dev/null) # Generate the certificate file. $openssl req $randOpt -new -x509 -days 16427 -key $tmpPrivateKey \ -out $tmpCertificate -config $certConfigFile checkForErrors \ "openssl req $randOpt -new -x509 -days 16427 -key $tmpPrivateKey -out $tmpCertificate -config $certConfigFile" $? # Create the combined file with all relevant key information. # # The combined file consists of several (currently 6) simple stanza # lines followed by several (currently 3) variable length sections. # The order must be preserved. If it becomes necessary in the future # to add additional information, the following rules should be obeyed: # - Any new simple stanza lines should follow the initial 6 lines # but should come before any variable length sections. # - Any new variable length sections should come before the current # three sections: privateKey, publicKey and certificate. # print -- "clusterName=$ourClusterName" > $tmpkey checkForErrors "writing to $tmpkey" $? print -- "clusterID=$ourClusterId" >> $tmpkey checkForErrors "writing to $tmpkey" $? print -- "genkeyFormat=$CURRENT_KEYFILE_FORMAT" >> $tmpkey checkForErrors "writing to $tmpkey" $? print -- "genkeyCompatibleFormat=$COMPATIBLE_KEYFILE_FORMAT" >> $tmpkey checkForErrors "writing to $tmpkey" $? print -- "keyGenNumber=$newKeyGenNumber" >> $tmpkey checkForErrors "writing to $tmpkey" $? print -- "keyDigest=$keyFingerprint" >> $tmpkey checkForErrors "writing to $tmpkey" $? print -- "privateKey=" >> $tmpkey checkForErrors "writing to $tmpkey" $? $cat $tmpPrivateKey >> $tmpkey checkForErrors "cat $tmpPrivateKey >> $tmpkey" $? print -- "publicKey=" >> $tmpkey checkForErrors "writing to $tmpkey" $? $cat $tmpPublicKey >> $tmpkey checkForErrors "cat $tmpPublicKey >> $tmpkey" $? print -- "certificate=" >> $tmpkey checkForErrors "writing to $tmpkey" $? $cat $tmpCertificate >> $tmpkey checkForErrors "cat $tmpCertificate >> $tmpkey" $? # If everyting worked out OK so far, copy the new file in the ssl/stage directory. fileToStage="${genkeyData}$newKeyGenNumber" $cp $tmpkey $fileToStage checkForErrors "cp $tmpkey $fileToStage" $? fi # end of if [[ $sdrfsFormatLevel -eq 0 ]] umask $UMASK_sv # Stage the newly-generated key file on the server nodes. # The files will be activated after the new key generation number # is committed as a result of the regular commit protocol. if [[ $primaryServer != $ourNodeName ]] then $rcp -p $fileToStage ${primaryServer}:$fileToStage checkForErrors "$rcp ${primaryServer}:$fileToStage" $? fi if [[ -n $backupServer && $backupServer != $ourNodeName ]] then $rcp -p $fileToStage ${backupServer}:$fileToStage checkForErrors "$rcp ${backupServer}:$fileToStage" $? fi else : # There is nothing to do for genkeyAction commit at this point. fi # end of if [[ $genkeyAction = new ]] fi # end of if [[ $action = genkey ]] if [[ $action = add ]] then # Generate the needed information for the mmsdrfs file. newLine="$remoteClusterName:$AUTHORIZED_CLUSTER:::$accessGranted::$cipherList:" print -- "$newLine" >> $newsdrfs checkForErrors "writing to file $newsdrfs" $? # Process the -k keyfile option. if [[ -n $keyfile ]] then appendFile $remoteClusterName $verifiedKey $AUTHORIZED_KEY $newsdrfs checkForErrors \ "appendFile $remoteClusterName $verifiedKey $AUTHORIZED_KEY $newsdrfs" $? fi fi # end of if [[ $action = add ]] if [[ $action = update ]] then if [[ -z $clusterFound ]] then # The remote cluster is not authorized to access this cluster. printErrorMsg 259 $mmcmd $remoteClusterName cleanupAndExit fi # Process the -k keyfile option. if [[ -n $keyfile && $keyfile != DELETE ]] then if [[ -n $newClusterName ]] then appendFile $newClusterName $verifiedKey $AUTHORIZED_KEY $newsdrfs checkForErrors \ "appendFile $newClusterName $verifiedKey $AUTHORIZED_KEY $newsdrfs" $? else appendFile $remoteClusterName $verifiedKey $AUTHORIZED_KEY $newsdrfs checkForErrors \ "appendFile $remoteClusterName $verifiedKey $AUTHORIZED_KEY $newsdrfs" $? fi fi # end of if [[ -n $keyfile && $keyfile != DELETE ]] # Process the -l cipherList option for the local cluster. if [[ -n $cipherList && $remoteClusterName = $HOME_CLUSTER ]] then # If changing the cipher list for the local cluster, # make changes to the mmfs.cfg file. $mmfixcfg "cipherList" "$cipherList" < $tmpCfg > $newcfg 2>/dev/null checkForErrors "mmfixcfg cipherList" $? # Put the updated mmfs.cfg information back into the mmsdrfs file. appendCfgFile $HOME_CLUSTER $newcfg $newsdrfs checkForErrors "appendCfgFile" $? # The daemon must be down on all nodes if we are about to switch # from a non-secure to a secure environment or vice-versa. if [[ $currentCipherList != $cipherList && ( $currentCipherList = DELETE || $cipherList = DELETE ) ]] then printInfoMsg 339 verifyDaemonInactive $allClusterNodes $mmcmd [[ $? -ne 0 ]] && cleanupAndExit daemonInactiveVerified=yes fi fi # end of if [[ -n $cipherList && $remoteClusterName = $HOME_CLUSTER ]] fi # end of if [[ $action = update ]] if [[ $action = delete ]] then if [[ -z $clusterFound ]] then if [[ $remoteClusterName = all ]] then # There are no remote cluster authorizations. printErrorMsg 258 $mmcmd else # The remote cluster is not authorized to access this cluster. printErrorMsg 259 $mmcmd $remoteClusterName fi cleanupAndExit fi # end of if [[ -z $clusterFound ]] fi # end of if [[ $action = delete ]] if [[ $action = show ]] then # Add the information for the local cluster at the end of the output. if [[ $remoteClusterName = all || $remoteClusterName = $HOME_CLUSTER ]] then clusterFound=yes # Display the cluster name. header=$(printInfoMsg 442) printf "%-20s %s\n" "$header" "$ourClusterName (this cluster)" # Display the cipher list. header=$(printInfoMsg 443) cipherList=$defaultCipherList [[ -z $cipherList ]] && cipherList="(none specified)" printf "%-20s %s\n" "$header" "$cipherList" # Display the SHA digest for the committed public key. header=$(printInfoMsg 444) keyFingerprint=$(getLocalFingerprint $committedPublicKey) printf "%-20s %s\n" "$header" "$keyFingerprint" # Display the SHA digest for the uncommitted public key. if [[ -s $newPublicKey ]] then header=$(printInfoMsg 427) keyFingerprint=$(getLocalFingerprint $newPublicKey) printf "%-20s %s\n" "$header" "$keyFingerprint" fi # Display the file systems that can be accessed by the cluster. header=$(printInfoMsg 445) fsAuthList="(all rw)" printf "%-20s %s\n\n" "$header" "$fsAuthList" fi # end if [[ $remoteClusterName = all || $remoteClusterName = $HOME_CLUSTER ]] if [[ -z $clusterFound ]] then # The remote cluster is not authorized to access this cluster. printErrorMsg 259 $mmcmd $remoteClusterName cleanupAndExit fi # end of if [[ -z $clusterFound ]] # Nothing more to do. cleanupAndExit 0 fi # end of if [[ $action = show ]] if [[ $action = grant ]] then if [[ -z $clusterFound ]] then if [[ $remoteClusterName = all ]] then # There are no remote cluster definitions. printErrorMsg 262 $mmcmd else # The remote cluster is not defined. printErrorMsg 259 $mmcmd $remoteClusterName fi cleanupAndExit fi # end of if [[ -z $clusterFound ]] if [[ -z $fsFound ]] then if [[ $device = all ]] then # No file systems were found. printErrorMsg 200 $mmcmd else # The requested file system was not found. printErrorMsg 288 $mmcmd $device fi cleanupAndExit fi # end of if [[ -z $fsFound ]] # Generate the appropriate AUTHORIZED_FS lines. print -- "" # put a blank separator line for fsName in $fsList do for remCluster in $clusterNameList do [[ $processedFileSystems = *" $remCluster:$fsName "* ]] && continue newLine=$remCluster:$AUTHORIZED_FS:$fsName::$accessType:$rsquashUid:$rsquashGid: print -- "$newLine" >> $newsdrfs checkForErrors "writing to file $newsdrfs" $? if [[ -z $rsquashUid ]] then printInfoMsg 182 $mmcmd $remCluster $fsName $accessType else printInfoMsg 183 $mmcmd $remCluster $fsName $accessType $rsquashUid $rsquashGid fi print -- "" # put a blank separator line done # end of for remCluster in $clusterNameList done # end of for fsName in $fsList fi # end of if [[ $action = grant ]] if [[ $action = deny ]] then if [[ -z $clusterFound ]] then if [[ $remoteClusterName = all ]] then # There are no remote cluster definitions. printErrorMsg 262 $mmcmd else # The remote cluster is not defined. printErrorMsg 259 $mmcmd $remoteClusterName fi cleanupAndExit fi # end of if [[ -z $clusterFound ]] if [[ -z $fsFound ]] then if [[ $device = all ]] then # No file systems were found. printErrorMsg 200 $mmcmd else # The requested file system was not found. printErrorMsg 288 $mmcmd $device fi cleanupAndExit fi # end of if [[ -z $fsFound ]] # Nothing more to do. The appropriate AUTHORIZED_FS lines have been removed. fi # end of if [[ $action = deny ]] #################################################### # Sort the new mmsdrfs file and commit the changes. #################################################### LC_ALL=C $SORT_MMSDRFS $newsdrfs -o $newsdrfs checkForErrors "sorting $newsdrfs" $? trap "" HUP INT QUIT KILL gpfsObjectInfo=$(commitChanges \ $nsId $nsId $gpfsObjectInfo $newGenNumber $newsdrfs $primaryServer) rc=$? if [[ $rc -ne 0 ]] then # The commit step failed; we cannot replace the file in the sdr. printErrorMsg 381 $mmcmd cleanupAndExit fi ################## # Unlock the sdr. ################## freeLockOnServer $primaryServer $ourNodeNumber >/dev/null sdrLocked=no trap posttrap HUP INT QUIT KILL # Issue "command was successful" message. printErrorMsg 272 $mmcmd ##################################################### # Asynchronously propagate the changes to all nodes. ##################################################### if [[ $action = genkey && $genkeyAction = new ]] then propagateKeyFile async $nodefile \ $newsdrfs $newGenNumber $fileToStage $newKeyGenNumber else propagateSdrfsFile async $nodefile $newsdrfs $newGenNumber fi if [[ $secLevel -gt 0 ]] then # Notify all currently-running nodes to refresh their key files. $mmcommon onactive $preferredNode $allClusterNodes \ $NO_FILE_COPY $NO_MOUNT_CHECK NULL $NO_LINK \ tsdsh $mmremote refreshAuth >$tmpfile 2>&1 fi cleanupAndExit 0