1 #! /usr/bin/ksh -p
   2 #
   3 # CDDL HEADER START
   4 #
   5 # The contents of this file are subject to the terms of the
   6 # Common Development and Distribution License (the "License").
   7 # You may not use this file except in compliance with the License.
   8 #
   9 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  10 # or http://www.opensolaris.org/os/licensing.
  11 # See the License for the specific language governing permissions
  12 # and limitations under the License.
  13 #
  14 # When distributing Covered Code, include this CDDL HEADER in each
  15 # file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  16 # If applicable, add the following below this CDDL HEADER, with the
  17 # fields enclosed by brackets "[]" replaced with your own identifying
  18 # information: Portions Copyright [yyyy] [name of copyright owner]
  19 #
  20 # CDDL HEADER END
  21 #
  22 
  23 #
  24 # Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  25 # Use is subject to license terms.
  26 #
  27 # uid_proc.ksh 
  28 #     The file contains global variables and support functions uidmapping tests.
  29 #     It contains three sections to help other scrips set up an initial 
  30 #     scripting environment:
  31 #
  32 #        1) The 1st section sources necessary files
  33 #        2) The 2nd section defines variables 
  34 #        3) The 3rd section defines functions 
  35 #
  36 #     All other ksh scripts under "uidmapping" directory are expected to source
  37 #     this file only.
  38 #
  39 # Note on temporary file management:
  40 #     This file defines a ERRLOG variable, which is used by all scripts
  41 #     under "uidmapping" directory as a temporary file to store error message. 
  42 #     If a process creates that file(surely it will), it SHOULD remove that 
  43 #     file when it exits no matter if it exits normally or it is interrupted.
  44 #
  45 #     However, for simplicity purpose, a function might exits without cleaning
  46 #     up the temporary file it created. An example if set_local_domain() in 
  47 #     this file and setup() in runtests.ksh file. If some commands failed
  48 #     within those functions, they just return without any cleanup. That 
  49 #     won't cause any problem since we have a per-process file clean up 
  50 #     solution described above.
  51 
  52 [[ -n $DEBUG ]] && [[ $DEBUG != 0 ]] && set -x
  53 
  54 #
  55 # source necessary files 
  56 #
  57 
  58 NAME=$(basename $0)
  59 CDIR=$(pwd)
  60 TESTROOT=${TESTROOT:-"$CDIR/../../"}
  61 TESTSH="$TESTROOT/testsh"
  62 
  63 # sourcing framework global environment variables created after go_setup
  64 # and for this purpose only this file should be sourced
  65 CONFIGFILE=/var/tmp/nfsv4/config/config.suite
  66 if [[ ! -f $CONFIGFILE ]]; then
  67         echo "$NAME: CONFIGFILE[$CONFIGFILE] not found;"
  68         echo "\texit UNINITIATED."
  69         exit 6
  70 fi
  71 . $CONFIGFILE
  72 
  73 # source useful functions
  74 if [[ ! -f $TESTSH ]]; then
  75         echo "$NAME: TESTSH[$TESTSH] not found; test UNINITIATED."
  76         exit $UNINITIATED
  77 fi
  78 
  79 . $TESTSH
  80 
  81 # 
  82 # "Global" variables used by all scripts or functions
  83 #
  84 
  85 # test directory
  86 TESTDIR=$ZONE_PATH/uidmapping
  87 
  88 # testfile name. 
  89 TESTFILE=uidmapping.$$.test
  90 
  91 # positions of own and group fields in "ls -l" output
  92 OWN=3
  93 GRP=4
  94 
  95 # temporary output file 
  96 ERRLOG=$TMPDIR/uidmapping.$$.err
  97 
  98 #
  99 # Functions
 100 #
 101 
 102 # variables for backup files, used by set/restore_local_domain() functions
 103 NFSCFG_BACKUP=$TMPDIR/uidmapping.nfscfg.backup
 104 DNSCFG_BACKUP=$TMPDIR/uidmapping.dnscfg.backup
 105 DNS_NOTCONFIGURED=$TMPDIR/uidmapping.dns_notconfigured
 106 NIS_DOMAIN=$TMPDIR/uidmapping.nis_domain
 107 
 108 # restart_mapid_service
 109 #     The function restarts mapid service and verifies it has been 
 110 #     restarted successfully. The function is designed to replace 
 111 #     the usual "svcadm restart" command.
 112 # usage:
 113 #     restart_mapid_service
 114 # return value:
 115 #     0 on success; 1 on error
 116 
 117 function restart_mapid_service
 118 {
 119         [[ -n $DEBUG ]] && [[ $DEBUG != 0 ]] && set -x
 120 
 121         orig_pid=$(pgrep -z $(zonename) nfsmapid)
 122 
 123         svcadm restart svc:/network/nfs/mapid:default
 124         (( $? == 0)) || return 1
 125 
 126         # check daemon pid
 127         wait_now 10 "new_pid=\$(pgrep -z $(zonename) nfsmapid); \
 128             [[ \$new_pid != $orig_pid ]]" || return 1
 129         # check service status
 130         wait_now 10 "st=\$(svcprop -p restarter/state nfs/mapid); \
 131             [[ \$st == 'online' ]]" || return 1
 132 
 133         sleep 2
 134 }
 135 
 136 # set_local_domain
 137 #     The function takes one argument and sets localhost's mapid domain
 138 #     to it. If the argument is not null, it modifies /etc/default/nfs file; 
 139 #     or else, it removes /etc/default/nfs and /etc/resolv.conf files and 
 140 #     unsets nis domain.
 141 #       
 142 #     The original environment changed by this function can be 
 143 #     restored by call of restore_local_domain(). These two functions are 
 144 #     supposed to be used together.
 145 # usage:
 146 #     set_local_domain <new_domain>
 147 # return value:
 148 #     0 on success; 1 on error
 149 
 150 function set_local_domain
 151 {
 152         [[ -n $DEBUG ]] && [[ $DEBUG != 0 ]] && set -x
 153 
 154         # check arguments
 155         if (( $# != 1 )); then 
 156                 echo "Usage: set_local_domain <new_domain>"
 157                 return 1
 158         fi
 159 
 160         typeset new_domain=$1
 161 
 162         # Back up /etc/default/nfs
 163         cp -p /etc/default/nfs $NFSCFG_BACKUP 2>$ERRLOG
 164         ckreturn $? "could not back up /etc/default/nfs" $ERRLOG "ERROR" \
 165             || return 1
 166 
 167         if [[ -n $new_domain ]]; then
 168                 orig_pid=$(pgrep -z $(zonename) nfsmapid)
 169                 # Set mapid domain
 170                 sharectl set -p NFSMAPID_DOMAIN=$new_domain nfs 1>$ERRLOG 2>&1
 171                 ckreturn $? "could not set domain for client" $ERRLOG "ERROR" \
 172                     || return 1
 173                 wait_now 10 "[[ \$(sharectl get -p NFSMAPID_DOMAIN nfs | \
 174                         awk -F= '{print \$2}') == $new_domain ]]"
 175                 ckreturn $? "the nfs domain has not been updated even after \
 176                         10 seconds" "ERROR" || return 1
 177                 # check daemon pid
 178                 wait_now 10 "new_pid=\$(pgrep -z $(zonename) nfsmapid); \
 179                         [[ \$new_pid != $orig_pid ]]" || return 1
 180                 # check service status
 181                 wait_now 10 "st=\$(svcprop -p restarter/state nfs/mapid); \
 182                         [[ \$st == 'online' ]]" || return 1
 183                 sleep 2
 184         else
 185                 # Back up DNS setting
 186                 if [[ -f /etc/resolv.conf ]]; then
 187                         # DNS was configured and thus needs to be backed up.
 188                         cp -p /etc/resolv.conf $DNSCFG_BACKUP 2>$ERRLOG
 189                         ckreturn $? "could not back up /etc/resolv.conf" \
 190                             $ERRLOG "ERROR" || return 1
 191                 else
 192                         # DNS wasn't configured. Mark that with a file
 193                         touch $DNS_NOTCONFIGURED 2>$ERRLOG
 194                         ckreturn $? \
 195                             "could not generate $DNS_NOTCONFIGURED" \
 196                             $ERRLOG "ERROR" || return 1
 197                 fi
 198 
 199                 # Back up NIS domain
 200                 domainname | cat > $NIS_DOMAIN
 201                 ckreturn $? "could not back up nis domain" "ERROR" || return 1
 202 
 203                 # Set mapid domain
 204                 grep -v "NFSMAPID_DOMAIN" /etc/default/nfs \
 205                     > $TMPDIR/uidmapping.$$.tmp 2>$ERRLOG \
 206                     && mv $TMPDIR/uidmapping.$$.tmp /etc/default/nfs 2>$ERRLOG \
 207                     && rm -f /etc/resolv.conf 2>$ERRLOG \
 208                     && domainname "" 2>$ERRLOG \
 209                     && restart_mapid_service 2>$ERRLOG 
 210                 ckreturn $? "could not set mapid domain to null" $ERRLOG \
 211                     "ERROR" || return 1
 212         fi
 213 
 214         # This function may exit on various errors, so it may fail to reach 
 215         # the following line and thus leave temporary error file unremoved.
 216         # However, it doesn't matter. Since this function is always supposed 
 217         # to be used together with restore_local_domain() function, which 
 218         # can help to do that if needed. 
 219         rm -f $ERRLOG
 220 }
 221 
 222 # restore_local_domain
 223 #     the function restores the original environment changed by call of 
 224 #     setup_local_domain().
 225 # usage:
 226 #     restore_local_domain
 227 # return value:
 228 #     0 on success; non-zero on error
 229 
 230 function restore_local_domain
 231 {
 232         [[ -n $DEBUG ]] && [[ $DEBUG != 0 ]] && set -x
 233 
 234         typeset ret=0
 235 
 236         # Restore /etc/default/nfs 
 237         if [[ -f $NFSCFG_BACKUP ]]; then
 238                 # Restore the file
 239                 mv $NFSCFG_BACKUP /etc/default/nfs 2>$ERRLOG
 240                 ckreturn $? "could not restore /etc/default/nfs" $ERRLOG \
 241                     "WARNING" || ret=$((ret + 1))
 242         fi
 243 
 244         # Restore DNS configuration if necessary
 245         if [[ -f $DNS_NOTCONFIGURED ]]; then
 246                 # no dns configuration at all
 247                 rm -f $DNS_NOTCONFIGURED 2>$ERRLOG
 248                 ckreturn $? "could not remove $DNS_NOTCONFIGURED" \
 249                     $ERRLOG "WARNING" || ret=$((ret + 1))
 250         elif [[ -f $DNSCFG_BACKUP ]]; then
 251                 # Restore /etc/resolv.conf 
 252                 mv $DNSCFG_BACKUP /etc/resolv.conf 2>$ERRLOG
 253                 ckreturn $? "could not restore /etc/resolv.conf" \
 254                     $ERRLOG "WARNING" || ret=$((ret + 1))
 255         fi
 256 
 257         # Restore NIS domain if necessary
 258         if [[ -f $NIS_DOMAIN ]]; then
 259                 domainname $(cat $NIS_DOMAIN) 2>$ERRLOG \
 260                     && rm -f $NIS_DOMAIN
 261                 ckreturn $? "could not restore NIS domain" $ERRLOG "WARNING" \
 262                     || ret=$((ret + 1))
 263         fi
 264 
 265         # Restart nfsmapid
 266         restart_mapid_service 1>$ERRLOG 2>&1
 267         ckreturn $? "could not restart nfsmapid" $ERRLOG "WARNING" \
 268             || ret=$((ret + 1))
 269 
 270         rm -f $ERRLOG
 271 
 272         return $ret
 273 }
 274 
 275 # get_free_id 
 276 #       This function returns a uid or gid which is unknown on 
 277 #       both client and server. It does that by first trying an value 
 278 #       large enough and check if it is mappable or not on server and client. 
 279 #       If yes, it increases the value by one and try it again until the max 
 280 #       try number is exceeded.
 281 # Usage: get_free_id "UID"|"GID"
 282 # Return Values:            
 283 #       On success, it returns 0 and outputs uid/gid on stdout;
 284 #       On failure, it returns 1.
 285 
 286 function get_free_id
 287 {
 288         [[ -n $DEBUG ]] && [[ $DEBUG != 0 ]] && set -x
 289 
 290         # check arguments
 291         if (( $# != 1 )); then 
 292                 echo "Usage: get_free_id \"UID\"|\"GID\""
 293                 return 1
 294         fi
 295 
 296         # select different database based on query type
 297         idtype=$1
 298         case $idtype in 
 299                 UID )
 300                         database="passwd"
 301                         ;;
 302                 GID )
 303                         database="group"
 304                         ;;
 305                 * )
 306                         echo "Usage: get_free_id \"UID\"|\"GID\""
 307                         return 1
 308                         ;;
 309         esac
 310         
 311         # 
 312         # The following code looks for an uid or gid unknown on both 
 313         # client and server. It picks up a number large enough(5000000)
 314         # and tries it first. If the number is not free, increases it by one
 315         # and tries again until the maximum retry number(100) is met. 
 316         #
 317 
 318         val=4999999
 319         st_server=0
 320         st_client=0
 321 
 322         while (( st_server != 2 || st_client != 2 ))
 323         do
 324                 val=$((val + 1))
 325                 if (( val >= 5000100 )); then
 326                         # if not in the first 100 ids, assume other problem
 327                         rm -f $ERRLOG
 328                         return 1
 329                 fi
 330 
 331                 # check it on server side
 332                 execute $SERVER root "getent $database $val" 1>/dev/null \
 333                     2> $ERRLOG
 334                 st_server=$?
 335                 [[ $DEBUG != 0 ]] && cat $ERRLOG >&2
 336 
 337                 # check it on client side
 338                 getent $database $val 1>/dev/null 2>$ERRLOG
 339                 st_client=$?
 340                 [[ $DEBUG != 0 ]] && cat $ERRLOG >&2
 341         done
 342 
 343         echo $val
 344 
 345         rm -f $ERRLOG
 346         return 0
 347 }
 348 
 349 # print_state
 350 #       This function prints the configuration of the test system, which can
 351 #       be used to help to debug command failures. It currently does the
 352 #       following and might be enhanced when necessary.
 353 #          - print /var/run/nfs4_domain on client and server
 354 #          - print users in /etc/passwd on client and server
 355 # Usage: print_state
 356 # Return Values:
 357 #       it always returns 0.
 358 
 359 function print_state
 360 {
 361         echo "\n===================== DEBUG INFORMATION ====================="
 362         echo "nfs domain on client: $(cat /var/run/nfs4_domain)"
 363         echo "nfs domain on server: $(execute $SERVER root cat /var/run/nfs4_domain)"
 364         typeset MAPID_FMRI="svc:/network/nfs/mapid:default"
 365         echo "nfs/mapid on client:"
 366         svcs $MAPID_FMRI
 367         echo "nfs/mapid on server:"
 368         execute $SERVER root svcs $MAPID_FMRI
 369         users_on_client=$(cut -d: -f1 /etc/passwd)
 370         echo "users on client: " $users_on_client
 371         users_on_server=$(execute $SERVER root cut -d: -f1 /etc/passwd)
 372         echo "users on server: " $users_on_server
 373         echo "============================ END =============================\n"
 374 }