1 #!/bin/ksh93 -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 # Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  23 # Use is subject to license terms.
  24 #
  25 # This script is used to setup the Kerberos client by
  26 # supplying information about the Kerberos realm and kdc.
  27 #
  28 # The kerberos configuration file (/etc/krb5/krb5.conf) would
  29 # be generated and local host's keytab file setup. The script
  30 # can also optionally setup the system to do kerberized nfs and
  31 # bringover a master krb5.conf copy from a specified location.
  32 
  33 function cleanup {
  34         integer ret=$1
  35 
  36         kdestroy -q 1> $TMP_FILE 2>&1
  37         rm -r $TMPDIR > /dev/null 2>&1
  38 
  39         exit $ret
  40 }
  41 function exiting {
  42         
  43         printf "\n$(gettext "Exiting setup, nothing changed").\n\n"
  44 
  45         cleanup $1
  46 }
  47 
  48 function error_message {
  49 
  50         printf -- "---------------------------------------------------\n"
  51         printf "$(gettext "Setup FAILED").\n\n"
  52 
  53         cleanup 1
  54 }
  55 
  56 function check_bin {
  57 
  58         typeset bin=$1
  59 
  60         if [[ ! -x $bin ]]; then
  61                 printf "$(gettext "Could not access/execute %s").\n" $bin
  62                 error_message
  63         fi
  64 }
  65 
  66 function cannot_create {
  67         typeset filename="$1"
  68         typeset stat="$2"
  69 
  70         if [[ $stat -ne 0 ]]; then
  71                 printf "\n$(gettext "Can not create/edit %s, exiting").\n" $filename >&2
  72                 error_message
  73         fi
  74 }
  75 
  76 function update_pam_conf {
  77         typeset PAM TPAM service
  78 
  79         PAM=/etc/pam.conf
  80 
  81         TPAM=$(mktemp -q -t kclient-pamconf.XXXXXX)
  82         if [[ -z $TPAM ]]; then
  83                 printf "\n$(gettext "Can not create temporary file, exiting").\n" >&2
  84                 error_message
  85         fi
  86 
  87         cp $PAM $TPAM >/dev/null 2>&1
  88 
  89         printf "$(gettext "Configuring %s").\n\n" $PAM
  90 
  91         for service in $SVCs; do
  92                 svc=${service%:*}
  93                 auth_type=${service#*:}
  94                 if egrep -s "^$svc[     ][      ]*auth.*pam_krb5*" $TPAM; then
  95                         printf "$(gettext "The %s service is already configured for pam_krb5, please merge this service in %s").\n\n" $svc $PAM >&2
  96                         continue
  97                 else
  98                         exec 3>>$TPAM
  99                         printf "\n$svc\tauth include\t\tpam_krb5_$auth_type\n" 1>&3
 100                 fi
 101         done
 102 
 103         cp $TPAM $PAM > /dev/null 2>&1
 104 
 105         rm $TPAM > /dev/null 2>&1
 106 }
 107 
 108 function modify_nfssec_conf {
 109         typeset NFSSEC_FILE="/etc/nfssec.conf"
 110 
 111         if [[ -r $NFSSEC_FILE ]]; then
 112                 cat $NFSSEC_FILE > $NFSSEC_FILE.sav
 113                 cannot_create $NFSSEC_FILE.sav $?
 114         fi
 115 
 116         cat $NFSSEC_FILE > $TMP_FILE
 117         cannot_create $TMP_FILE $?
 118 
 119         if grep -s "#krb5" $NFSSEC_FILE > /dev/null 2>&1; then
 120                 sed "s%^#krb5%krb5%" $TMP_FILE >$NFSSEC_FILE
 121                 cannot_create $NFSSEC_FILE $?
 122         fi
 123 }
 124 
 125 function call_kadmin {
 126         typeset svc="$1"
 127         typeset bool1 bool2 bool3 bool4
 128         typeset service_princ getprincsubcommand anksubcommand ktaddsubcommand
 129         typeset ktremsubcommand
 130 
 131         for listentry in $fqdnlist; do
 132 
 133         # Reset conditional vars to 1
 134         bool1=1; bool2=1; bool3=1; bool4=1
 135 
 136         service_princ=$(echo "${svc}/${listentry}")
 137         getprincsubcommand="getprinc $service_princ"
 138         anksubcommand="addprinc -randkey $service_princ"
 139         ktaddsubcommand="ktadd $service_princ"
 140         ktremsubcommand="ktrem $service_princ all"
 141 
 142         kadmin -c $KRB5CCNAME -q "$getprincsubcommand" 1>$TMP_FILE 2>&1
 143 
 144         egrep -s "$(gettext "get_principal: Principal does not exist")" $TMP_FILE
 145         bool1=$?
 146         egrep -s "$(gettext "get_principal: Operation requires ``get")" $TMP_FILE
 147         bool2=$?
 148 
 149         if [[ $bool1 -eq 0 || $bool2 -eq 0 ]]; then
 150                 kadmin -c $KRB5CCNAME -q "$anksubcommand" 1>$TMP_FILE 2>&1
 151 
 152                 egrep -s "$(gettext "add_principal: Principal or policy already exists while creating \"$service_princ@$realm\".")" $TMP_FILE
 153                 bool3=$?
 154 
 155                 egrep -s "$(gettext "Principal \"$service_princ@$realm\" created.")" $TMP_FILE
 156                 bool4=$?
 157 
 158                 if [[ $bool3 -eq 0 || $bool4 -eq 0 ]]; then
 159                         printf "$(gettext "%s entry ADDED to KDC database").\n" $service_princ
 160                 else
 161                         cat $TMP_FILE;
 162                         printf "\n$(gettext "kadmin: add_principal of %s failed, exiting").\n" $service_princ >&2
 163                         error_message
 164                 fi
 165         else
 166                 printf "$(gettext "%s entry already exists in KDC database").\n" $service_princ >&2
 167         fi
 168 
 169         klist -k 1>$TMP_FILE 2>&1
 170         egrep -s "$service_princ@$realm" $TMP_FILE
 171         if [[ $? -eq 0 ]]; then
 172                 printf "$(gettext "%s entry already present in keytab").\n" $service_princ >&2
 173                 # Don't care is this succeeds or not, just need to replace old
 174                 # entries as it is assummed that the client is reinitialized
 175                 kadmin -c $KRB5CCNAME -q "$ktremsubcommand" 1>$TMP_FILE 2>&1
 176         fi
 177 
 178         kadmin -c $KRB5CCNAME -q "$ktaddsubcommand" 1>$TMP_FILE 2>&1
 179         egrep -s "$(gettext "added to keytab WRFILE:$KRB5_KEYTAB_FILE.")" $TMP_FILE
 180         if [[ $? -ne 0 ]]; then
 181                 cat $TMP_FILE;
 182                 printf "\n$(gettext "kadmin: ktadd of %s failed, exiting").\n" $service_princ >&2
 183                 error_message
 184         else
 185                 printf "$(gettext "%s entry ADDED to keytab").\n" $service_princ
 186         fi
 187 
 188         done
 189 }
 190 
 191 function writeup_krb5_conf {
 192         typeset dh
 193 
 194         printf "\n$(gettext "Setting up %s").\n\n" $KRB5_CONFIG_FILE
 195 
 196         exec 3>$KRB5_CONFIG
 197         if [[ $? -ne 0 ]]; then
 198                 printf "\n$(gettext "Can not write to %s, exiting").\n" $KRB5_CONFIG
 199                 error_message
 200         fi
 201 
 202         printf "[libdefaults]\n" 1>&3
 203         if [[ $no_keytab == yes ]]; then
 204                 printf "\tverify_ap_req_nofail = false\n" 1>&3
 205         fi
 206         if [[ $dns_lookup == yes ]]; then
 207             printf "\t$dnsarg = on\n" 1>&3
 208             if [[ $dnsarg == dns_lookup_kdc ]]; then
 209                 printf "\tdefault_realm = $realm\n" 1>&3
 210                 printf "\n[domain_realm]\n" 1>&3
 211                 if [[ -n $fkdc_list ]]; then
 212                         for kdc in $fkdc_list; do
 213                                 printf "\t$kdc = $realm\n" 1>&3
 214                         done
 215                 fi
 216                 printf "\t$FKDC = $realm\n" 1>&3
 217                 printf "\t$client_machine = $realm\n" 1>&3
 218                 if [[ -z $short_fqdn ]]; then
 219                         printf "\t.$domain = $realm\n\n" 1>&3
 220                 else
 221                         printf "\t.$short_fqdn = $realm\n\n" 1>&3
 222                 fi
 223                 if [[ -n $domain_list ]]; then
 224                         for dh in $domain_list; do
 225                                 printf "\t$dh = $realm\n" 1>&3
 226                         done
 227                 fi
 228             else
 229                 if [[ $dnsarg = dns_lookup_realm ]]; then
 230                     printf "\tdefault_realm = $realm\n" 1>&3
 231                     printf "\n[realms]\n" 1>&3
 232                     printf "\t$realm = {\n" 1>&3
 233                     if [[ -n $kdc_list ]]; then
 234                         for kdc in $kdc_list; do
 235                                 printf "\t\tkdc = $kdc\n" 1>&3
 236                         done
 237                     else
 238                         printf "\t\tkdc = $KDC\n" 1>&3
 239                     fi
 240                     printf "\t\tadmin_server = $KDC\n" 1>&3
 241                     if [[ $non_solaris == yes ]]; then
 242                         printf "\n\t\tkpasswd_protocol = SET_CHANGE\n" 1>&3
 243                     fi
 244                     printf "\t}\n\n" 1>&3
 245                 else
 246                     printf "\tdefault_realm = $realm\n\n" 1>&3
 247                 fi
 248             fi
 249         else
 250             printf "\tdefault_realm = $realm\n\n" 1>&3
 251 
 252             printf "[realms]\n" 1>&3
 253             printf "\t$realm = {\n" 1>&3
 254             if [[ -n $kdc_list ]]; then
 255                 for kdc in $kdc_list; do
 256                         printf "\t\tkdc = $kdc\n" 1>&3
 257                 done
 258             else
 259                 printf "\t\tkdc = $KDC\n" 1>&3
 260             fi
 261             printf "\t\tadmin_server = $KDC\n" 1>&3
 262             if [[ $non_solaris == yes ]]; then
 263                 printf "\n\t\tkpasswd_protocol = SET_CHANGE\n" 1>&3
 264             fi
 265             printf "\t}\n\n" 1>&3
 266 
 267             printf "[domain_realm]\n" 1>&3
 268             if [[ -n $fkdc_list ]]; then
 269                 for kdc in $fkdc_list; do
 270                         printf "\t$kdc = $realm\n" 1>&3
 271                 done
 272             fi
 273             printf "\t$FKDC = $realm\n" 1>&3
 274             printf "\t$client_machine = $realm\n" 1>&3
 275             if [[ -z $short_fqdn ]]; then
 276                 printf "\t.$domain = $realm\n\n" 1>&3
 277             else
 278                 printf "\t.$short_fqdn = $realm\n\n" 1>&3
 279             fi
 280             if [[ -n $domain_list ]]; then
 281                 for dh in $domain_list; do
 282                         printf "\t$dh = $realm\n" 1>&3
 283                 done
 284             fi
 285         fi
 286 
 287         printf "[logging]\n" 1>&3
 288         printf "\tdefault = FILE:/var/krb5/kdc.log\n" 1>&3
 289         printf "\tkdc = FILE:/var/krb5/kdc.log\n" 1>&3
 290         printf "\tkdc_rotate = {\n\t\tperiod = 1d\n\t\tversions = 10\n\t}\n\n" 1>&3
 291 
 292         printf "[appdefaults]\n" 1>&3
 293         printf "\tkinit = {\n\t\trenewable = true\n\t\tforwardable = true\n" 1>&3
 294         if [[ $no_keytab == yes ]]; then
 295                 printf "\t\tno_addresses = true\n" 1>&3
 296         fi
 297         printf "\t}\n" 1>&3
 298 }
 299 
 300 function ask {
 301         typeset question=$1
 302         typeset default_answer=$2
 303 
 304         if [[ -z $default_answer ]]; then
 305                 printf "$question :"
 306         else
 307                 printf "$question [$default_answer]: "
 308         fi
 309         read answer
 310         test -z "$answer" && answer="$default_answer"
 311 }
 312 
 313 function yesno {
 314         typeset question="$1"
 315 
 316         answer=
 317         yn=`printf "$(gettext "y/n")"`
 318         y=`printf "$(gettext "y")"`
 319         n=`printf "$(gettext "n")"`
 320         yes=`printf "$(gettext "yes")"`
 321         no=`printf "$(gettext "no")"`
 322 
 323         while [[ -z $answer ]]; do
 324                 ask "$question" $yn
 325                 case $answer in
 326                         $y|$yes)        answer=yes;;
 327                         $n|$no)         answer=no;;
 328                         *)              answer=;;
 329                 esac
 330         done
 331 }
 332 
 333 function query {
 334         yesno "$*"
 335 
 336         if [[ $answer == no ]]; then
 337                 printf "\t$(gettext "No action performed").\n"
 338         fi
 339 }
 340 
 341 
 342 function read_profile {
 343         typeset param value
 344         typeset file="$1"
 345 
 346         if [[ ! -d $file && -r $file ]]; then
 347                 while read param value
 348                 do
 349                         case $param in
 350                         REALM)  if [[ -z $realm ]]; then
 351                                         realm="$value"
 352                                         checkval="REALM"; check_value $realm
 353                                 fi
 354                                 ;;
 355                         KDC)    if [[ -z $KDC ]]; then
 356                                         KDC="$value"
 357                                         checkval="KDC"; check_value $KDC
 358                                 fi
 359                                 ;;
 360                         ADMIN)  if [[ -z $ADMIN_PRINC ]]; then
 361                                         ADMIN_PRINC="$value"
 362                                         checkval="ADMIN_PRINC"
 363                                         check_value $ADMIN_PRINC
 364                                 fi
 365                                 ;;
 366                         FILEPATH)  if [[ -z $filepath ]]; then
 367                                         filepath="$value"
 368                                    fi
 369                                    ;;
 370                         NFS)    if [[ -z $add_nfs ]]; then
 371                                     if [[ $value == 1 ]]; then
 372                                             add_nfs=yes
 373                                     else
 374                                             add_nfs=no
 375                                     fi
 376                                 fi
 377                                 ;;
 378                         NOKEY)    if [[ -z $no_keytab ]]; then
 379                                     if [[ $value == 1 ]]; then
 380                                             no_keytab=yes
 381                                     else
 382                                             no_keytab=no
 383                                     fi
 384                                 fi
 385                                 ;;
 386                         NOSOL)  if [[ -z $non_solaris ]]; then
 387                                     if [[ $value == 1 ]]; then
 388                                             non_solaris=yes
 389                                             no_keytab=yes
 390                                     else
 391                                             non_solaris=no
 392                                     fi
 393                                 fi
 394                                 ;;
 395                         LHN)    if [[ -z $logical_hn ]]; then
 396                                         logical_hn="$value"
 397                                         checkval="LOGICAL_HOSTNAME"
 398                                         check_value $logical_hn
 399                                 fi
 400                                 ;;
 401                         DNSLOOKUP) if [[ -z $dnsarg ]]; then
 402                                         dnsarg="$value"
 403                                         checkval="DNS_OPTIONS"
 404                                         check_value $dnsarg
 405                                    fi
 406                                    ;;
 407                         FQDN) if [[ -z $fqdnlist ]]; then
 408                                         fqdnlist="$value"
 409                                         checkval="FQDN"
 410                                         check_value $fqdnlist
 411                                         verify_fqdnlist "$fqdnlist"
 412                               fi
 413                               ;;
 414                         MSAD) if [[ -z $msad ]]; then
 415                                 if [[ $value == 1 ]]; then
 416                                         msad=yes
 417                                         non_solaris=yes
 418                                 else
 419                                         msad=no
 420                                 fi
 421                               fi
 422                               ;;
 423                         esac
 424                 done <$file
 425         else
 426                 printf "\n$(gettext "The kclient profile \`%s' is not valid, exiting").\n" $file >&2
 427                 error_message
 428         fi
 429 }
 430 
 431 function ping_check {
 432         typeset machine="$1"
 433         typeset string="$2"
 434 
 435         if ping $machine 2 > /dev/null 2>&1; then
 436                 :
 437         else
 438                 printf "\n$(gettext "%s %s is unreachable, exiting").\n" $string $machine >&2
 439                 error_message
 440         fi
 441 
 442         # Output timesync warning if not using a profile, i.e. in
 443         # interactive mode.
 444         if [[ -z $profile && $string == KDC ]]; then
 445                 # It's difficult to sync up time with KDC esp. if in a
 446                 # zone so just print a warning about KDC time sync.
 447                 printf "\n$(gettext "Note, this system and the KDC's time must be within 5 minutes of each other for Kerberos to function").\n" >&2
 448                 printf "$(gettext "Both systems should run some form of time synchronization system like Network Time Protocol (NTP)").\n" >&2
 449 break
 450         fi
 451 }
 452 
 453 function check_value {
 454         typeset arg="$1"
 455 
 456         if [[ -z $arg ]]; then
 457                 printf "\n$(gettext "No input obtained for %s, exiting").\n" $checkval >&2
 458                 error_message
 459         else
 460                 echo "$arg" > $TMP_FILE
 461                 if egrep -s '[*$^#!]+' $TMP_FILE; then
 462                         printf "\n$(gettext "Invalid input obtained for %s, exiting").\n" $checkval >&2
 463                         error_message
 464                 fi
 465         fi
 466 }
 467 
 468 function set_dns_value {
 469         typeset -l arg="$1"
 470 
 471         if [[ $arg == dns_lookup_kdc  ||  $arg == dns_lookup_realm  || $arg == dns_fallback ]]; then
 472                 dns_lookup=yes
 473         else
 474                 if [[ $arg == none ]]; then
 475                         dns_lookup=no
 476                 else
 477                         printf "\n$(gettext "Invalid DNS lookup option, exiting").\n" >&2
 478                         error_message
 479                 fi
 480         fi
 481 }
 482 
 483 function verify_kdcs {
 484         typeset k_list="$1"
 485         typeset -l kdc
 486         typeset list fqhn f_list
 487 
 488         kdc_list=$(echo "$k_list" | sed 's/,/ /g')
 489 
 490         if [[ -z $k_list ]]; then
 491                 printf "\n$(gettext "At least one KDC should be listed").\n\n" >&2
 492                 usage
 493         fi
 494 
 495         for kdc in $k_list; do
 496                 if [[ $kdc != $KDC ]]; then
 497                         list="$list $kdc"
 498                         fkdc=`$KLOOKUP $kdc`
 499                         if ping $fkdc 2 > /dev/null; then
 500                                 :
 501                         else
 502                                 printf "\n$(gettext "%s %s is unreachable, no action performed").\n" "KDC" $fkdc >&2
 503                         fi
 504                         f_list="$f_list $fkdc"
 505                 fi
 506         done
 507 
 508         fkdc_list="$f_list"
 509         kdc_list="$list"
 510 }
 511 
 512 function parse_service {
 513         typeset service_list=$1
 514 
 515         service_list=${service_list//,/ }
 516         for service in $service_list; do
 517                 svc=${service%:}
 518                 auth_type=${service#:}
 519                 [[ -z $svc || -z $auth_type ]] && return
 520                 print -- $svc $auth_type
 521         done
 522 }
 523 
 524 function verify_fqdnlist {
 525         typeset list="$1"
 526         typeset -l hostname
 527         typeset -i count=1
 528         typeset fqdnlist eachfqdn tmpvar fullhost
 529 
 530         list=$(echo "$list" | tr -d " " | tr -d "\t")
 531         hostname=$(uname -n | cut -d"." -f1)
 532         fqdnlist=$client_machine
 533 
 534         eachfqdn=$(echo "$list" | cut -d"," -f$count)
 535         if [[ -z $eachfqdn ]]; then
 536                 printf "\n$(gettext "If the -f option is used, at least one FQDN should be listed").\n\n" >&2
 537                 usage
 538         else
 539                 while [[ ! -z $eachfqdn ]]; do
 540                         tmpvar=$(echo "$eachfqdn" | cut -d"." -f1)
 541                         if [[ -z $tmpvar ]]; then
 542                                 fullhost="$hostname$eachfqdn"
 543                         else
 544                                 fullhost="$hostname.$eachfqdn"
 545                         fi
 546 
 547                         ping_check $fullhost $(gettext "System")
 548                         if [[ $fullhost == $client_machine ]]; then
 549                                 :
 550                         else
 551                                 fqdnlist="$fqdnlist $fullhost"
 552                         fi
 553 
 554                         if [[ $list == *,* ]]; then
 555                                 ((count = count + 1))
 556                                 eachfqdn=$(echo "$list" | cut -d"," -f$count)
 557                         else
 558                                 break
 559                         fi
 560                 done
 561         fi
 562 }
 563 
 564 function setup_keytab {
 565         typeset cname ask_fqdns current_release
 566 
 567         #
 568         # 1. kinit with ADMIN_PRINC
 569         #
 570 
 571         if [[ -z $ADMIN_PRINC ]]; then
 572                 printf "\n$(gettext "Enter the krb5 administrative principal to be used"): "
 573                 read ADMIN_PRINC
 574                 checkval="ADMIN_PRINC"; check_value $ADMIN_PRINC
 575         fi
 576 
 577         echo "$ADMIN_PRINC">$TMP_FILE
 578 
 579         [[ -n $msad ]] && return
 580         if egrep -s '\/admin' $TMP_FILE; then
 581                 # Already in "/admin" format, do nothing
 582                 :
 583         else
 584                 if egrep -s '\/' $TMP_FILE; then
 585                         printf "\n$(gettext "Improper entry for krb5 admin principal, exiting").\n" >&2
 586                         error_message
 587                 else
 588                         ADMIN_PRINC=$(echo "$ADMIN_PRINC/admin")
 589                 fi
 590         fi
 591 
 592         printf "$(gettext "Obtaining TGT for %s") ...\n" $ADMIN_PRINC
 593 
 594         cname=$(canon_resolve $KDC)
 595         if [[ -n $cname ]]; then
 596                 kinit -S kadmin/$cname $ADMIN_PRINC
 597         else
 598                 kinit -S kadmin/$FKDC $ADMIN_PRINC
 599         fi
 600         klist 1>$TMP_FILE 2>&1
 601         if egrep -s "$(gettext "Valid starting")" $TMP_FILE && egrep -s "kadmin/$FKDC@$realm" $TMP_FILE; then
 602                 :
 603         else
 604                 printf "\n$(gettext "kinit of %s failed, exiting").\n" $ADMIN_PRINC >&2
 605                 error_message
 606         fi
 607 
 608         #
 609         # 2. Do we want to create and/or add service principal(s) for fqdn's
 610         #    other than the one listed in resolv.conf(4) ?
 611         #
 612         if [[ -z $options ]]; then
 613                 query "$(gettext "Do you have multiple DNS domains spanning the Kerberos realm") $realm ?"
 614                 ask_fqdns=$answer
 615                 if [[ $ask_fqdns == yes ]]; then
 616                         printf "$(gettext "Enter a comma-separated list of DNS domain names"): "
 617                         read fqdnlist
 618                         verify_fqdnlist "$fqdnlist"
 619                 else
 620                         fqdnlist=$client_machine
 621                 fi
 622         else
 623                 if [[ -z $fqdnlist ]]; then
 624                         fqdnlist=$client_machine
 625                 fi
 626         fi
 627 
 628         if [[ $add_nfs == yes ]]; then
 629                 echo; call_kadmin nfs
 630         fi
 631 
 632         # Add the host entry to the keytab
 633         echo; call_kadmin host
 634 
 635 }
 636 
 637 function setup_lhn {
 638         typeset -l logical_hn
 639 
 640         echo "$logical_hn" > $TMP_FILE
 641         if egrep -s '[^.]\.[^.]+$' $TMP_FILE; then
 642                 # do nothing, logical_hn is in fqdn format
 643                 :
 644         else
 645                 if egrep -s '\.+' $TMP_FILE; then
 646                         printf "\n$(gettext "Improper format of logical hostname, exiting").\n" >&2
 647                         error_message
 648                 else
 649                         # Attach fqdn to logical_hn, to get the Fully Qualified
 650                         # Host Name of the client requested
 651                         logical_hn=$(echo "$logical_hn.$fqdn")
 652                 fi
 653         fi
 654 
 655         client_machine=$logical_hn
 656 
 657         ping_check $client_machine $(gettext "System")
 658 }
 659 
 660 function usage {
 661         printf "\n$(gettext "Usage: kclient [ options ]")\n" >&2
 662         printf "\t$(gettext "where options are any of the following")\n\n" >&2
 663         printf "\t$(gettext "[ -D domain_list ]  configure a client that has mul
 664 tiple mappings of doamin and/or hosts to the default realm")\n" >&2
 665         printf "\t$(gettext "[ -K ]  configure a client that does not have host/service keys")\n" >&2
 666         printf "\t$(gettext "[ -R realm ]  specifies the realm to use")\n" >&2
 667         printf "\t$(gettext "[ -T kdc_vendor ]  specifies which KDC vendor is the server")\n" >&2
 668         printf "\t$(gettext "[ -a adminuser ]  specifies the Kerberos administrator")\n" >&2
 669         printf "\t$(gettext "[ -c filepath ]  specifies the krb5.conf path used to configure this client")\n" >&2
 670         printf "\t$(gettext "[ -d dnsarg ]  specifies which information should be looked up in DNS (dns_lookup_kdc, dns_lookup_realm, and dns_fallback)")\n" >&2
 671         printf "\t$(gettext "[ -f fqdn_list ]  specifies which domains to configure host keys for this client")\n" >&2
 672         printf "\t$(gettext "[ -h logicalhostname ]  configure the logical host name for a client that is in a cluster")\n" >&2
 673         printf "\t$(gettext "[ -k kdc_list ]  specify multiple KDCs, if -m is not used the first KDC in the list is assumed to be the master.  KDC host names are used verbatim.")\n" >&2
 674         printf "\t$(gettext "[ -m master ]  master KDC server host name")\n" >&2
 675         printf "\t$(gettext "[ -n ]  configure client to be an NFS client")\n" >&2
 676         printf "\t$(gettext "[ -p profile ]  specifies which profile file to use to configure this client")\n" >&2
 677         printf "\t$(gettext "[ -s pam_list ]  update the service for Kerberos authentication")\n" >&2
 678         error_message
 679 }
 680 
 681 function discover_domain {
 682         typeset dom DOMs
 683 
 684         if [[ -z $realm ]]; then
 685                 set -A DOMs -- `$KLOOKUP _ldap._tcp.dc._msdcs S`
 686         else
 687                 set -A DOMs -- `$KLOOKUP _ldap._tcp.dc._msdcs.$realm S`
 688         fi
 689 
 690         [[ -z ${DOMs[0]} ]] && return 1
 691 
 692         dom=${DOMs[0]}
 693 
 694         dom=${dom#*.}
 695         dom=${dom% *}
 696 
 697         domain=$dom
 698 
 699         return 0
 700 }
 701 
 702 function check_nss_hosts_or_ipnodes_config {
 703         typeset backend
 704 
 705         for backend in $1
 706         do
 707                 [[ $backend == dns ]] && return 0
 708         done
 709         return 1
 710 }
 711 
 712 function check_nss_conf {
 713         typeset i j hosts_config
 714 
 715         for i in hosts ipnodes
 716         do
 717                 grep "^${i}:" /etc/nsswitch.conf|read j hosts_config
 718                 check_nss_hosts_or_ipnodes_config "$hosts_config" || return 1
 719         done
 720 
 721         return 0
 722 }
 723 
 724 function canon_resolve {
 725         typeset name ip
 726 
 727         name=`$KLOOKUP $1 C`
 728         [[ -z $name ]] && name=`$KLOOKUP $1 A`
 729         [[ -z $name ]] && return
 730 
 731         ip=`$KLOOKUP $name I`
 732         [[ -z $ip ]] && return
 733         for i in $ip
 734         do
 735                 if ping $i 2 > /dev/null 2>&1; then
 736                         break
 737                 else
 738                         i=
 739                 fi
 740         done
 741 
 742         cname=`$KLOOKUP $ip P`
 743         [[ -z $cname ]] && return
 744 
 745         print -- "$cname"
 746 }
 747 
 748 function rev_resolve {
 749         typeset name ip
 750 
 751         ip=`$KLOOKUP $1 I`
 752 
 753         [[ -z $ip ]] && return
 754         name=`$KLOOKUP $ip P`
 755         [[ -z $name ]] && return
 756 
 757         print -- $name
 758 }
 759 
 760 # Convert an AD-style domain DN to a DNS domainname
 761 function dn2dns {
 762         typeset OIFS dname dn comp components
 763 
 764         dn=$1
 765         dname=
 766 
 767         OIFS="$IFS"
 768         IFS=,
 769         set -A components -- $1
 770         IFS="$OIFS"
 771 
 772         for comp in "${components[@]}"
 773         do
 774                 [[ "$comp" == [dD][cC]=* ]] || continue
 775                 dname="$dname.${comp#??=}"
 776         done
 777 
 778         print ${dname#.}
 779 }
 780 
 781 # Form a base DN from a DNS domainname and container
 782 function getBaseDN {
 783         if [[ -n "$2" ]]
 784         then
 785                 baseDN="CN=$1,$(dns2dn $2)"
 786         else
 787                 baseDN="$(dns2dn $2)"
 788         fi
 789 }
 790 
 791 # Convert a DNS domainname to an AD-style DN for that domain
 792 function dns2dn {
 793         typeset OIFS dn labels
 794 
 795         OIFS="$IFS"
 796         IFS=.
 797         set -A labels -- $1
 798         IFS="$OIFS"
 799 
 800         dn=
 801         for label in "${labels[@]}"
 802         do
 803                 dn="${dn},DC=$label"
 804         done
 805 
 806         print -- "${dn#,}"
 807 }
 808 
 809 function getSRVs {
 810         typeset srv port
 811 
 812         $KLOOKUP $1 S | while read srv port
 813         do
 814                 if ping $srv 2 > /dev/null 2>&1; then
 815                         print -- $srv $port
 816                 fi
 817         done
 818 }
 819 
 820 function getKDC {
 821         typeset j
 822 
 823         set -A KPWs -- $(getSRVs _kpasswd._tcp.$dom.)
 824         kpasswd=${KPWs[0]}
 825 
 826         if [[ -n $siteName ]]
 827         then
 828                 set -A KDCs -- $(getSRVs _kerberos._tcp.$siteName._sites.$dom.)
 829                 kdc=${KDCs[0]}
 830                 [[ -n $kdc ]] && return
 831         fi
 832 
 833         # No site name
 834         set -A KDCs -- $(getSRVs _kerberos._tcp.$dom.)
 835         kdc=${KDCs[0]}
 836         [[ -n $kdc ]] && return
 837 
 838         # Default
 839         set -A KDCs -- $DomainDnsZones 88
 840         kdc=$ForestDnsZones
 841 }
 842 
 843 function getDC {
 844         typeset j
 845 
 846         if [[ -n $siteName ]]
 847         then
 848                 set -A DCs -- $(getSRVs _ldap._tcp.$siteName._sites.dc._msdcs.$dom.)
 849                 dc=${DCs[0]}
 850                 [[ -n $dc ]] && return
 851         fi
 852 
 853         # No site name
 854         set -A DCs -- $(getSRVs _ldap._tcp.dc._msdcs.$dom.)
 855         dc=${DCs[0]}
 856         [[ -n $dc ]] && return
 857 
 858         # Default
 859         set -A DCs -- $DomainDnsZones 389
 860         dc=$DomainDnsZones
 861 }
 862 
 863 function write_ads_krb5conf {
 864         printf "\n$(gettext "Setting up %s").\n\n" $KRB5_CONFIG_FILE
 865 
 866         exec 3>$KRB5_CONFIG
 867         if [[ $? -ne 0 ]]; then
 868                 printf "\n$(gettext "Can not write to %s, exiting").\n" $KRB5_CONFIG
 869                 error_message
 870         fi
 871 
 872         printf "[libdefaults]\n" 1>&3
 873         printf "\tdefault_realm = $realm\n" 1>&3
 874         printf "\n[realms]\n" 1>&3
 875         printf "\t$realm = {\n" 1>&3
 876         for i in ${KDCs[@]}
 877         do
 878                 [[ $i == +([0-9]) ]] && continue
 879                 printf "\t\tkdc = $i\n" 1>&3
 880         done
 881         # Defining the same as admin_server.  This would cause auth failures
 882         # if this was different.
 883         printf "\n\t\tkpasswd_server = $KDC\n" 1>&3
 884         printf "\n\t\tadmin_server = $KDC\n" 1>&3
 885         printf "\t\tkpasswd_protocol = SET_CHANGE\n\t}\n" 1>&3
 886         printf "\n[domain_realm]\n" 1>&3
 887         printf "\t.$dom = $realm\n\n" 1>&3
 888         printf "[logging]\n" 1>&3
 889         printf "\tdefault = FILE:/var/krb5/kdc.log\n" 1>&3
 890         printf "\tkdc = FILE:/var/krb5/kdc.log\n" 1>&3
 891         printf "\tkdc_rotate = {\n\t\tperiod = 1d\n\t\tversions = 10\n\t}\n\n" 1>&3
 892         printf "[appdefaults]\n" 1>&3
 893         printf "\tkinit = {\n\t\trenewable = true\n\t\tforwardable = true\n\t}\n" 1>&3
 894 }
 895 
 896 function getForestName {
 897         ldapsearch -R -T -h $dc $ldap_args \
 898             -b "" -s base "" schemaNamingContext| \
 899                 grep ^schemaNamingContext|read j schemaNamingContext
 900 
 901         if [[ $? -ne 0 ]]; then
 902                 printf "$(gettext "Can't find forest").\n"
 903                 error_message
 904         fi
 905         schemaNamingContext=${schemaNamingContext#CN=Schema,CN=Configuration,}
 906 
 907         [[ -z $schemaNamingContext ]] && return 1
 908 
 909         forest=
 910         while [[ -n $schemaNamingContext ]]
 911         do
 912                 schemaNamingContext=${schemaNamingContext#DC=}
 913                 forest=${forest}.${schemaNamingContext%%,*}
 914                 [[ "$schemaNamingContext" = *,* ]] || break
 915                 schemaNamingContext=${schemaNamingContext#*,}
 916         done
 917         forest=${forest#.}
 918 }
 919 
 920 function getGC {
 921         typeset j
 922 
 923         [[ -n $gc ]] && return 0
 924 
 925         if [[ -n $siteName ]]
 926         then
 927                 set -A GCs -- $(getSRVs _ldap._tcp.$siteName._sites.gc._msdcs.$forest.)
 928                 gc=${GCs[0]}
 929                 [[ -n $gc ]] && return
 930         fi
 931 
 932         # No site name
 933         set -A GCs -- $(getSRVs _ldap._tcp.gc._msdcs.$forest.)
 934         gc=${GCs[0]}
 935         [[ -n $gc ]] && return
 936 
 937         # Default
 938         set -A GCs -- $ForestDnsZones 3268
 939         gc=$ForestDnsZones
 940 }
 941 
 942 function ipAddr2num {
 943         typeset OIFS
 944         typeset -i16 num byte
 945 
 946         if [[ "$1" != +([0-9]).+([0-9]).+([0-9]).+([0-9]) ]]
 947         then
 948                 print 0
 949                 return 0
 950         fi
 951 
 952         OIFS="$IFS"
 953         IFS=.
 954         set -- $1
 955         IFS="$OIFS"
 956 
 957         num=$((${1}<<24 | ${2}<<16 | ${3}<<8 | ${4}))
 958 
 959         print -- $num
 960 }
 961 
 962 function num2ipAddr {
 963         typeset -i16 num
 964         typeset -i10 a b c d
 965 
 966         num=$1
 967         a=$((num>>24        ))
 968         b=$((num>>16 & 16#ff))
 969         c=$((num>>8  & 16#ff))
 970         d=$((num     & 16#ff))
 971         print -- $a.$b.$c.$d
 972 }
 973 
 974 function netmask2length {
 975         typeset -i16 netmask
 976         typeset -i len
 977 
 978         netmask=$1
 979         len=32
 980         while [[ $((netmask % 2)) -eq 0 ]]
 981         do
 982                 netmask=$((netmask>>1))
 983                 len=$((len - 1))
 984         done
 985         print $len
 986 }
 987 
 988 function getSubnets {
 989         typeset -i16 addr netmask
 990         typeset -i16 classa=16\#ff000000
 991 
 992         ifconfig -a|while read line
 993         do
 994                 addr=0
 995                 netmask=0
 996                 set -- $line
 997                 [[ $1 == inet ]] || continue
 998                 while [[ $# -gt 0 ]]
 999                 do
1000                         case "$1" in
1001                                 inet) addr=$(ipAddr2num $2); shift;;
1002                                 netmask) eval netmask=16\#$2; shift;;
1003                                 *) :;
1004                         esac
1005                         shift
1006                 done
1007 
1008                 [[ $addr -eq 0 || $netmask -eq 0 ]] && continue
1009                 [[ $((addr & classa)) -eq 16\#7f000000 ]] && continue
1010 
1011                 print $(num2ipAddr $((addr & netmask)))/$(netmask2length $netmask)
1012         done
1013 }
1014 
1015 function getSite {
1016         typeset subnet siteDN j ldapsrv subnet_dom
1017 
1018         eval "[[ -n \"\$siteName\" ]]" && return
1019         for subnet in $(getSubnets)
1020         do
1021                 ldapsearch -R -T -h $dc $ldap_args \
1022                     -p 3268 -b "" -s sub cn=$subnet dn |grep ^dn|read j subnetDN
1023 
1024                 [[ -z $subnetDN ]] && continue
1025                 subnet_dom=$(dn2dns $subnetDN)
1026                 ldapsrv=$(canon_resolve DomainDnsZones.$subnet_dom)
1027                 [[ -z $ldapsrv ]] && continue
1028                 ldapsearch -R -T -h $ldapsrv $ldap_args \
1029                     -b "$subnetDN" -s base "" siteObject \
1030                     |grep ^siteObject|read j siteDN
1031 
1032                 [[ -z $siteDN ]] && continue
1033 
1034                 eval siteName=${siteDN%%,*}
1035                 eval siteName=\${siteName#CN=}
1036                 return
1037         done
1038 }
1039 
1040 function doKRB5config {
1041         [[ -f $KRB5_CONFIG_FILE ]] && \
1042                 cp $KRB5_CONFIG_FILE ${KRB5_CONFIG_FILE}-pre-kclient
1043 
1044         [[ -f $KRB5_KEYTAB_FILE ]] && \
1045                 cp $KRB5_KEYTAB_FILE ${KRB5_KEYTAB_FILE}-pre-kclient
1046 
1047         [[ -s $KRB5_CONFIG ]] && cp $KRB5_CONFIG $KRB5_CONFIG_FILE
1048         [[ -s $KRB5_CONFIG_FILE ]] && chmod 0644 $KRB5_CONFIG_FILE
1049         [[ -s $new_keytab ]] && cp $new_keytab $KRB5_KEYTAB_FILE
1050         [[ -s $KRB5_KEYTAB_FILE ]] && chmod 0600 $KRB5_KEYTAB_FILE
1051 }
1052 
1053 function addDNSRR {
1054         smbFMRI=svc:/network/smb/server:default
1055         ddnsProp=smbd/ddns_enable
1056         enProp=general/enabled
1057 
1058         enabled=`svcprop -p $enProp $smbFMRI`
1059         ddns_enable=`svcprop -p $ddnsProp $smbFMRI`
1060 
1061         if [[ $enabled == true && $ddns_enable != true ]]; then
1062                 printf "$(gettext "Warning: won't create DNS records for client").\n"
1063                 printf "$(gettext "%s property not set to 'true' for the %s FMRI").\n" $ddnsProp $smbFMRI
1064                 return
1065         fi
1066         
1067         # Destroy any existing ccache as GSS_C_NO_CREDENTIAL will pick up any
1068         # residual default credential in the cache.
1069         kdestroy > /dev/null 2>&1
1070 
1071         $KDYNDNS -d $1 > /dev/null 2>&1
1072         if [[ $? -ne 0 ]]; then
1073                 #
1074                 # Non-fatal, we should carry-on as clients may resolve to
1075                 # different servers and the client could already exist there.
1076                 #
1077                 printf "$(gettext "Warning: unable to create DNS records for client").\n"
1078                 printf "$(gettext "This could mean that '%s' is not included as a 'nameserver' in the /etc/resolv.conf file or some other type of error").\n" $dc
1079         fi
1080 }
1081 
1082 function setSMB {
1083         typeset domain=$1
1084         typeset server=$2
1085         smbFMRI=svc:/network/smb/server
1086 
1087         printf "%s" $newpw | $KSMB -d $domain -s $server
1088         if [[ $? -ne 0 ]]; then
1089                 printf "$(gettext "Warning: unable to set %s domain, server and password information").\n" $smbFMRI
1090                 return
1091         fi
1092 
1093         svcadm restart $smbFMRI > /dev/null 2>&1
1094         if [[ $? -ne 0 ]]; then
1095                 printf "$(gettext "Warning: unable to restart %s").\n" $smbFMRI
1096         fi
1097 }
1098 
1099 function compareDomains {
1100         typeset oldDom hspn newDom=$1
1101 
1102         # If the client has been previously configured in a different
1103         # realm/domain then we need to prompt the user to see if they wish to
1104         # switch domains.
1105         klist -k 2>&1 | grep @ | read j hspn
1106         [[ -z $hspn ]] && return
1107 
1108         oldDom=${hspn#*@}
1109         if [[ $oldDom != $newDom ]]; then
1110                 printf "$(gettext "The client is currently configured in a different domain").\n"
1111                 printf "$(gettext "Currently in the '%s' domain, trying to join the '%s' domain").\n" $oldDom $newDom
1112                 query "$(gettext "Do you want the client to join a new domain") ?"
1113                 printf "\n"
1114                 if [[ $answer != yes ]]; then
1115                         printf "$(gettext "Client will not be joined to the new domain").\n"
1116                         error_message
1117                 fi
1118         fi
1119 }
1120 
1121 function getKDCDC {
1122 
1123         getKDC
1124         if [[ -n $kdc ]]; then
1125                 KDC=$kdc
1126                 dc=$kdc
1127         else
1128                 getDC
1129                 if [[ -n $dc ]]; then
1130                         KDC=$dc
1131                 else
1132                         printf "$(gettext "Could not find domain controller server for '%s'.  Exiting").\n" $realm
1133                         error_message
1134                 fi
1135         fi
1136 }
1137 
1138 function join_domain {
1139         typeset -u upcase_nodename
1140         typeset netbios_nodename fqdn
1141         
1142         container=Computers
1143         ldap_args="-o authzid= -o mech=gssapi"
1144         userAccountControlBASE=4096
1145 
1146         if [[ -z $ADMIN_PRINC ]]; then
1147                 cprinc=Administrator
1148         else
1149                 cprinc=$ADMIN_PRINC
1150         fi
1151 
1152         if ! discover_domain; then
1153                 printf "$(gettext "Can not find realm") '%s'.\n" $realm
1154                 error_message
1155         fi
1156 
1157         dom=$domain
1158         realm=$domain
1159         upcase_nodename=$hostname
1160         netbios_nodename="${upcase_nodename}\$"
1161         fqdn=$hostname.$domain
1162         upn=host/${fqdn}
1163 
1164         grep=/usr/xpg4/bin/grep
1165 
1166         object=$(mktemp -q -t kclient-computer-object.XXXXXX)
1167         if [[ -z $object ]]; then
1168                 printf "\n$(gettext "Can not create temporary file, exiting").\n
1169 " >&2
1170                 error_message
1171         fi
1172 
1173         grep=/usr/xpg4/bin/grep
1174 
1175         modify_existing=false
1176         recreate=false
1177 
1178         DomainDnsZones=$(rev_resolve DomainDnsZones.$dom.)
1179         ForestDnsZones=$(rev_resolve ForestDnsZones.$dom.)
1180 
1181         getBaseDN "$container" "$dom"
1182 
1183         if [[ -n $KDC ]]; then
1184                 dc=$KDC
1185         else
1186                 getKDCDC
1187         fi
1188 
1189         write_ads_krb5conf
1190 
1191         printf "$(gettext "Attempting to join '%s' to the '%s' domain").\n\n" $upcase_nodename $realm
1192 
1193         kinit $cprinc@$realm
1194         if [[ $? -ne 0 ]]; then
1195                 printf "$(gettext "Could not authenticate %s.  Exiting").\n" $cprinc@$realm
1196                 error_message
1197         fi
1198 
1199         if getForestName
1200         then
1201                 printf "\n$(gettext "Forest name found: %s")\n\n" $forest
1202         else
1203                 printf "\n$(gettext "Forest name not found, assuming forest is the domain name").\n"
1204         fi
1205 
1206         getGC
1207         getSite
1208 
1209         if [[ -z $siteName ]]
1210         then
1211                 printf "$(gettext "Site name not found.  Local DCs/GCs will not be discovered").\n\n"
1212         else
1213                 printf "$(gettext "Looking for _local_ KDCs, DCs and global catalog servers (SRV RRs)").\n"
1214                 getKDCDC
1215                 getGC
1216 
1217                 write_ads_krb5conf
1218         fi
1219 
1220         if [[ ${#GCs} -eq 0 ]]; then
1221                 printf "$(gettext "Could not find global catalogs.  Exiting").\n"
1222                 error_message
1223         fi
1224 
1225         # Check to see if the client is transitioning between domains.
1226         compareDomains $realm
1227 
1228         # Here we check domainFunctionality to see which release:
1229         # 0, 1, 2: Windows 2000, 2003 Interim, 2003 respecitively
1230         # 3: Windows 2008
1231         level=0
1232         ldapsearch -R -T -h "$dc" $ldap_args -b "" -s base "" \
1233          domainControllerFunctionality| grep ^domainControllerFunctionality| \
1234          read j level
1235         if [[ $? -ne 0 ]]; then
1236                 printf "$(gettext "Search for domain functionality failed, exiting").\n"
1237                 error_message
1238         fi
1239         # Longhorn and above can't perform an init auth from service
1240         # keys if the realm is included in the UPN.  w2k3 and below
1241         # can't perform an init auth when the realm is excluded.
1242         [[ $level -lt 3 ]] && upn=${upn}@${realm}
1243 
1244         if ldapsearch -R -T -h "$dc" $ldap_args -b "$baseDN" \
1245             -s sub sAMAccountName="$netbios_nodename" dn > /dev/null 2>&1
1246         then
1247                 :
1248         else
1249                 printf "$(gettext "Search for node failed, exiting").\n"
1250                 error_message
1251         fi
1252         ldapsearch -R -T -h "$dc" $ldap_args -b "$baseDN" -s sub \
1253             sAMAccountName="$netbios_nodename" dn|grep "^dn:"|read j dn
1254 
1255         if [[ -z $dn ]]; then
1256                 : # modify_existing is already false, which is what we want.
1257         else
1258                 printf "$(gettext "Computer account '%s' already exists in the '%s' domain").\n" $upcase_nodename $realm
1259                 query "$(gettext "Do you wish to recreate this computer account") ?"
1260                 printf "\n"
1261                 if [[ $answer == yes ]]; then
1262                         recreate=true
1263                 else
1264                         modify_existing=true
1265                 fi
1266         fi
1267 
1268         if [[ $modify_existing == false && -n $dn ]]; then
1269                 query "$(gettext "Would you like to delete any sub-object found for this computer account") ?"
1270                 if [[ $answer == yes ]]; then
1271                         printf "$(gettext "Looking to see if the machine account contains other objects")...\n"
1272                         ldapsearch -R -T -h "$dc" $ldap_args -b "$dn" -s sub "" dn | while read j sub_dn
1273                         do
1274                                 [[ $j != dn: || -z $sub_dn || $dn == $sub_dn ]] && continue
1275                                 if $recreate; then
1276                                         printf "$(gettext "Deleting the following object: %s")\n" ${sub_dn#$dn}
1277                                         ldapdelete -h "$dc" $ldap_args "$sub_dn" > /dev/null 2>&1
1278                                         if [[ $? -ne 0 ]]; then
1279                                                 printf "$(gettext "Error in deleting object: %s").\n" ${sub_dn#$dn}
1280                                         fi
1281                                 else
1282                                         printf "$(gettext "The following object will not be deleted"): %s\n" ${sub_dn#$dn}
1283                                 fi
1284                         done
1285                 fi
1286 
1287                 if $recreate; then
1288                         ldapdelete -h "$dc" $ldap_args "$dn" > /dev/null 2>&1
1289                         if [[ $? -ne 0 ]]; then
1290                                 printf "$(gettext "Error in deleting object: %s").\n" ${sub_dn#$dn}
1291                                 error_message
1292                         fi
1293                 elif $modify_existing; then
1294                         : # Nothing to delete
1295                 else
1296                         printf "$(gettext "A machine account already exists").\n"
1297                         error_message
1298                 fi
1299         fi
1300 
1301         if $modify_existing; then
1302                 cat > "$object" <<EOF
1303 dn: CN=$upcase_nodename,$baseDN
1304 changetype: modify
1305 replace: userPrincipalName
1306 userPrincipalName: $upn
1307 -
1308 replace: servicePrincipalName
1309 servicePrincipalName: host/${fqdn}
1310 -
1311 replace: userAccountControl
1312 userAccountControl: $((userAccountControlBASE + 32 + 2))
1313 -
1314 replace: dNSHostname
1315 dNSHostname: ${fqdn}
1316 EOF
1317 
1318                 printf "$(gettext "A machine account already exists; updating it").\n"
1319                 ldapadd -h "$dc" $ldap_args -f "$object" > /dev/null 2>&1
1320                 if [[ $? -ne 0 ]]; then
1321                         printf "$(gettext "Failed to create the AD object via LDAP").\n"
1322                         error_message
1323                 fi
1324         else
1325                 cat > "$object" <<EOF
1326 dn: CN=$upcase_nodename,$baseDN
1327 objectClass: computer
1328 cn: $upcase_nodename
1329 sAMAccountName: ${netbios_nodename}
1330 userPrincipalName: $upn
1331 servicePrincipalName: host/${fqdn}
1332 userAccountControl: $((userAccountControlBASE + 32 + 2))
1333 dNSHostname: ${fqdn}
1334 EOF
1335 
1336                 printf "$(gettext "Creating the machine account in AD via LDAP").\n\n"
1337 
1338                 ldapadd -h "$dc" $ldap_args -f "$object" > /dev/null 2>&1
1339                 if [[ $? -ne 0 ]]; then
1340                         printf "$(gettext "Failed to create the AD object via LDAP").\n"
1341                         error_message
1342                 fi
1343         fi
1344 
1345         # Generate a new password for the new account
1346         MAX_PASS=32
1347         i=0
1348 
1349         while :
1350         do
1351                 while ((MAX_PASS > i))
1352                 do
1353                         # 94 elements in the printable character set starting
1354                         # at decimal 33, contiguous.
1355                         dig=$((RANDOM%94+33))
1356                         c=$(printf "\\`printf %o $dig`\n")
1357                         p=$p$c
1358                         ((i+=1))
1359                 done
1360 
1361                 # Ensure that we have four character classes.
1362                 d=${p%[[:digit:]]*}
1363                 a=${p%[[:lower:]]*}
1364                 A=${p%[[:upper:]]*}
1365                 x=${p%[[:punct:]]*}
1366 
1367                 # Just compare the number of characters from what was previously
1368                 # matched.  If there is a difference then we found a match.
1369                 n=${#p}
1370                 [[ ${#d} -ne $n && ${#a} -ne $n && \
1371                    ${#A} -ne $n && ${#x} -ne $n ]] && break
1372                 i=0
1373                 p=
1374         done
1375         newpw=$p
1376 
1377         # Set the new password
1378         printf "%s" $newpw | $KSETPW ${netbios_nodename}@${realm} > /dev/null 2>&1
1379         if [[ $? -ne 0 ]]
1380         then
1381                 printf "$(gettext "Failed to set account password").\n"
1382                 error_message
1383         fi
1384 
1385         # Lookup the new principal's kvno:
1386         ldapsearch -R -T -h "$dc" $ldap_args -b "$baseDN" \
1387                  -s sub cn=$upcase_nodename msDS-KeyVersionNumber| \
1388                 grep "^msDS-KeyVersionNumber"|read j kvno
1389         [[ -z $kvno ]] && kvno=1
1390 
1391         # Set supported enctypes.  This only works for Longhorn/Vista, so we
1392         # ignore errors here.
1393         userAccountControl=$((userAccountControlBASE + 524288 + 65536))
1394         set -A enctypes --
1395 
1396         # Do we have local support for AES?
1397         encrypt -l|grep ^aes|read j minkeysize maxkeysize
1398         val=
1399         if [[ $maxkeysize -eq 256 ]]; then
1400                 val=16
1401                 enctypes[${#enctypes[@]}]=aes256-cts-hmac-sha1-96
1402         fi
1403         if [[ $minkeysize -eq 128 ]]; then
1404                 ((val=val+8))
1405                 enctypes[${#enctypes[@]}]=aes128-cts-hmac-sha1-96
1406         fi
1407 
1408         # RC4 comes next (whether it's better than 1DES or not -- AD prefers it)
1409         if encrypt -l|$grep -q ^arcfour
1410         then
1411                 ((val=val+4))
1412                 enctypes[${#enctypes[@]}]=arcfour-hmac-md5
1413         else
1414                 # Use 1DES ONLY if we don't have arcfour
1415                 userAccountControl=$((userAccountControl + 2097152))
1416         fi
1417         if encrypt -l | $grep -q ^des
1418         then
1419                 ((val=val+1+2))
1420                 enctypes[${#enctypes[@]}]=des-cbc-crc
1421                 enctypes[${#enctypes[@]}]=des-cbc-md5
1422         fi
1423 
1424         if [[ ${#enctypes[@]} -eq 0 ]]
1425         then
1426                 printf "$(gettext "No enctypes are supported").\n"
1427                 printf "$(gettext "Please enable arcfour or 1DES, then re-join; see cryptoadm(1M)").\n"
1428                 error_message
1429         fi
1430 
1431         # If domain crontroller is Longhorn or above then set new supported
1432         # encryption type attributes.
1433         if [[ $level -gt 2 ]]; then
1434                 cat > "$object" <<EOF
1435 dn: CN=$upcase_nodename,$baseDN
1436 changetype: modify
1437 replace: msDS-SupportedEncryptionTypes
1438 msDS-SupportedEncryptionTypes: $val
1439 EOF
1440                 ldapmodify -h "$dc" $ldap_args -f "$object" >/dev/null 2>&1
1441                 if [[ $? -ne 0 ]]; then
1442                         printf "$(gettext "Warning: Could not set the supported encryption type for computer account").\n"
1443                 fi
1444         fi
1445 
1446         # We should probably check whether arcfour is available, and if not,
1447         # then set the 1DES only flag, but whatever, it's not likely NOT to be
1448         # available on S10/Nevada!
1449 
1450         # Reset userAccountControl
1451         #
1452         #  NORMAL_ACCOUNT (512) | DONT_EXPIRE_PASSWORD (65536) |
1453         #  TRUSTED_FOR_DELEGATION (524288)
1454         #
1455         # and possibly UseDesOnly (2097152) (see above)
1456         #
1457         cat > "$object" <<EOF
1458 dn: CN=$upcase_nodename,$baseDN
1459 changetype: modify
1460 replace: userAccountControl
1461 userAccountControl: $userAccountControl
1462 EOF
1463         ldapmodify -h "$dc" $ldap_args -f "$object" >/dev/null 2>&1
1464         if [[ $? -ne 0 ]]; then
1465                 printf "$(gettext "ldapmodify failed to modify account attribute").\n"
1466                 error_message
1467         fi
1468 
1469         # Setup a keytab file
1470         set -A args --
1471         for enctype in "${enctypes[@]}"
1472         do
1473                 args[${#args[@]}]=-e
1474                 args[${#args[@]}]=$enctype
1475         done
1476 
1477         rm $new_keytab > /dev/null 2>&1
1478 
1479         cat > "$object" <<EOF
1480 dn: CN=$upcase_nodename,$baseDN
1481 changetype: modify
1482 add: servicePrincipalName
1483 servicePrincipalName: nfs/${fqdn}
1484 servicePrincipalName: HTTP/${fqdn}
1485 servicePrincipalName: root/${fqdn}
1486 EOF
1487         ldapmodify -h "$dc" $ldap_args -f "$object" >/dev/null 2>&1
1488         if [[ $? -ne 0 ]]; then
1489                 printf "$(gettext "ldapmodify failed to modify account attribute").\n"
1490                 error_message
1491         fi
1492 
1493         printf "%s" $newpw | $KSETPW -n -v $kvno -k "$new_keytab" "${args[@]}" host/${fqdn}@${realm} > /dev/null 2>&1
1494         if [[ $? -ne 0 ]]
1495         then
1496                 printf "$(gettext "Failed to set account password").\n"
1497                 error_message
1498         fi
1499 
1500         # Could be setting ${netbios_nodename}@${realm}, but for now no one
1501         # is requesting this.
1502 
1503         print "%s" $newpw | $KSETPW -n -v $kvno -k "$new_keytab" "${args[@]}" nfs/${fqdn}@${realm} > /dev/null 2>&1
1504         if [[ $? -ne 0 ]]
1505         then
1506                 printf "$(gettext "Failed to set account password").\n"
1507                 error_message
1508         fi
1509 
1510         print "%s" $newpw | $KSETPW -n -v $kvno -k "$new_keytab" "${args[@]}" HTTP/${fqdn}@${realm} > /dev/null 2>&1
1511         if [[ $? -ne 0 ]]
1512         then
1513                 printf "$(gettext "Failed to set account password").\n"
1514                 error_message
1515         fi
1516 
1517         print "%s" $newpw | $KSETPW -n -v $kvno -k "$new_keytab" "${args[@]}" root/${fqdn}@${realm} > /dev/null 2>&1
1518         if [[ $? -ne 0 ]]
1519         then
1520                 printf "$(gettext "Failed to set account password").\n"
1521                 error_message
1522         fi
1523 
1524         doKRB5config
1525 
1526         addDNSRR $dom
1527 
1528         setSMB $dom $dc
1529 
1530         printf -- "\n---------------------------------------------------\n"
1531         printf "$(gettext "Setup COMPLETE").\n\n"
1532 
1533         kdestroy -q 1>$TMP_FILE 2>&1
1534         rm -f $TMP_FILE
1535         rm -rf $TMPDIR > /dev/null 2>&1
1536 
1537         exit 0
1538 }
1539 
1540 ###########################
1541 #       Main section      #
1542 ###########################
1543 #
1544 # Set the Kerberos config file and some default strings/files
1545 #
1546 KRB5_CONFIG_FILE=/etc/krb5/krb5.conf
1547 KRB5_KEYTAB_FILE=/etc/krb5/krb5.keytab
1548 RESOLV_CONF_FILE=/etc/resolv.conf
1549 
1550 KLOOKUP=/usr/lib/krb5/klookup;  check_bin $KLOOKUP
1551 KSETPW=/usr/lib/krb5/ksetpw;    check_bin $KSETPW
1552 KSMB=/usr/lib/krb5/ksmb;        check_bin $KSMB
1553 KDYNDNS=/usr/lib/krb5/kdyndns;  check_bin $KDYNDNS
1554 
1555 dns_lookup=no
1556 ask_fqdns=no
1557 adddns=no
1558 no_keytab=no
1559 checkval=""
1560 profile=""
1561 typeset -u realm
1562 typeset -l hostname KDC
1563 
1564 export TMPDIR="/var/run/kclient"
1565 
1566 mkdir $TMPDIR > /dev/null 2>&1
1567 
1568 TMP_FILE=$(mktemp -q -t kclient-tmpfile.XXXXXX)
1569 export KRB5_CONFIG=$(mktemp -q -t kclient-krb5conf.XXXXXX)
1570 export KRB5CCNAME=$(mktemp -q -t kclient-krb5ccache.XXXXXX) 
1571 new_keytab=$(mktemp -q -t kclient-krb5keytab.XXXXXX) 
1572 if [[ -z $TMP_FILE || -z $KRB5_CONFIG || -z $KRB5CCNAME || -z $new_keytab ]]
1573 then
1574         printf "\n$(gettext "Can not create temporary file, exiting").\n" >&2
1575         error_message
1576 fi
1577 
1578 #
1579 # If we are interrupted, cleanup after ourselves
1580 #
1581 trap "exiting 1" HUP INT QUIT TERM
1582 
1583 if [[ -d /usr/bin ]]; then
1584         if [[ -d /usr/sbin ]]; then
1585                 PATH=/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:$PATH
1586                 export PATH
1587         else
1588                 printf "\n$(gettext "Directory /usr/sbin not found, exiting").\n" >&2
1589                 exit 1
1590         fi
1591 else
1592         printf "\n$(gettext "Directory /usr/bin not found, exiting").\n" >&2
1593         exit 1
1594 fi
1595 
1596 printf "\n$(gettext "Starting client setup")\n\n"
1597 printf -- "---------------------------------------------------\n"
1598 
1599 #
1600 # Check for uid 0, disallow otherwise
1601 #
1602 id 1>$TMP_FILE 2>&1
1603 if [[ $? -eq 0 ]]; then
1604         if egrep -s "uid=0\(root\)" $TMP_FILE; then
1605                 # uid is 0, go ahead ...
1606                 :
1607         else
1608                 printf "\n$(gettext "Administrative privileges are required to run this script, exiting").\n" >&2
1609                 error_message
1610         fi
1611 else
1612         cat $TMP_FILE;
1613         printf "\n$(gettext "uid check failed, exiting").\n" >&2
1614         error_message
1615 fi
1616 
1617 uname=$(uname -n)
1618 hostname=${uname%%.*}
1619 
1620 #
1621 # Process the command-line arguments (if any)
1622 #
1623 OPTIND=1
1624 while getopts nD:Kp:R:k:a:c:d:f:h:m:s:T: OPTIONS
1625 do
1626         case $OPTIONS in
1627             D) options="$options -D"
1628                domain_list="$OPTARG"
1629                ;;
1630             K) options="$options -K"
1631                no_keytab=yes
1632                ;;
1633             R) options="$options -R"
1634                realm="$OPTARG"
1635                checkval="REALM"; check_value $realm
1636                ;;
1637             T) options="$options -T"
1638                type="$OPTARG"
1639                if [[ $type == ms_ad ]]; then
1640                 msad=yes
1641                 adddns=yes
1642                else
1643                 non_solaris=yes
1644                 no_keytab=yes
1645                fi
1646                ;;
1647             a) options="$options -a"
1648                ADMIN_PRINC="$OPTARG"
1649                checkval="ADMIN_PRINC"; check_value $ADMIN_PRINC
1650                ;;
1651             c) options="$options -c"
1652                filepath="$OPTARG"
1653                ;;
1654             d) options="$options -d"
1655                dnsarg="$OPTARG"
1656                checkval="DNS_OPTIONS"; check_value $dnsarg
1657                ;;
1658             f) options="$options -f"
1659                fqdnlist="$OPTARG"
1660                ;;
1661             h) options="$options -h"
1662                logical_hn="$OPTARG"
1663                checkval="LOGICAL_HOSTNAME"; check_value $logical_hn
1664                ;;
1665             k) options="$options -k"
1666                kdc_list="$OPTARG"
1667                ;;
1668             m) options="$options -m"
1669                KDC="$OPTARG"
1670                checkval="KDC"; check_value $KDC
1671                ;;
1672             n) options="$options -n"
1673                add_nfs=yes
1674                ;;
1675             p) options="$options -p"
1676                profile="$OPTARG"
1677                read_profile $profile
1678                ;;
1679             s) options="$options -s"
1680                svc_list="$OPTARG"
1681                SVCs=${svc_list//,/ }
1682                ;;
1683             \?) usage
1684                ;;
1685             *) usage
1686                ;;
1687         esac
1688 done
1689 
1690 #correct argument count after options
1691 shift `expr $OPTIND - 1`
1692 
1693 if [[ -z $options ]]; then
1694         :
1695 else
1696         if [[ $# -ne 0 ]]; then
1697                 usage
1698         fi
1699 fi
1700 
1701 #
1702 # Check to see if we will be a client of a MIT, Heimdal, Shishi, etc.
1703 #
1704 if [[ -z $options ]]; then
1705         query "$(gettext "Is this a client of a non-Solaris KDC") ?"
1706         non_solaris=$answer
1707         if [[ $non_solaris == yes ]]; then
1708                 printf "$(gettext "Which type of KDC is the server"):\n"
1709                 printf "\t$(gettext "ms_ad: Microsoft Active Directory")\n"
1710                 printf "\t$(gettext "mit: MIT KDC server")\n"
1711                 printf "\t$(gettext "heimdal: Heimdal KDC server")\n"
1712                 printf "\t$(gettext "shishi: Shishi KDC server")\n"
1713                 printf "$(gettext "Enter required KDC type"): "
1714                 read kdctype
1715                 if [[ $kdctype == ms_ad ]]; then
1716                         msad=yes
1717                 elif [[ $kdctype == mit || $kdctype == heimdal || \
1718                     $kdctype == shishi ]]; then
1719                         no_keytab=yes
1720                 else
1721                         printf "\n$(gettext "Invalid KDC type option, valid types are ms_ad, mit, heimdal, or shishi, exiting").\n" >&2
1722                         error_message
1723                 fi
1724         fi
1725 fi
1726 
1727 [[ $msad == yes ]] && join_domain
1728 
1729 #
1730 # Check for /etc/resolv.conf
1731 #
1732 if [[ -r $RESOLV_CONF_FILE ]]; then
1733         client_machine=`$KLOOKUP`
1734 
1735         if [[ $? -ne 0 ]]; then
1736                 if [[ $adddns == no ]]; then
1737                         printf "\n$(gettext "%s does not have a DNS record and is required for Kerberos setup")\n" $hostname >&2
1738                         error_message
1739                 fi
1740 
1741         else
1742                 #
1743                 # If client entry already exists then do not recreate it
1744                 #
1745                 adddns=no
1746 
1747                 hostname=${client_machine%%.*}
1748                 domain=${client_machine#*.}
1749         fi
1750 
1751         short_fqdn=${domain#*.*}
1752         short_fqdn=$(echo $short_fqdn | grep "\.")
1753 else
1754         #
1755         # /etc/resolv.conf not present, exit ...
1756         #
1757         printf "\n$(gettext "%s does not exist and is required for Kerberos setup")\n" $RESOLV_CONF_FILE >&2
1758         printf "$(gettext "Refer to resolv.conf(4), exiting").\n" >&2
1759         error_message
1760 fi
1761 
1762 check_nss_conf || printf "$(gettext "/etc/nsswitch.conf does not make use of DNS for hosts and/or ipnodes").\n"
1763 
1764 [[ -n $fqdnlist ]] && verify_fqdnlist "$fqdnlist"
1765 
1766 if [[ -z $dnsarg && (-z $options || -z $filepath) ]]; then
1767         query "$(gettext "Do you want to use DNS for kerberos lookups") ?"
1768         if [[ $answer == yes ]]; then
1769                 printf "\n$(gettext "Valid DNS lookup options are dns_lookup_kdc, dns_lookup_realm,\nand dns_fallback. Refer krb5.conf(4) for further details").\n"
1770                 printf "\n$(gettext "Enter required DNS option"): "
1771                 read dnsarg
1772                 checkval="DNS_OPTIONS"; check_value $dnsarg
1773                 set_dns_value $dnsarg
1774         fi
1775 else
1776         [[ -z $dnsarg ]] && dnsarg=none
1777         set_dns_value $dnsarg
1778 fi
1779 
1780 if [[ -n $kdc_list ]]; then
1781         if [[ -z $KDC ]]; then
1782                 for kdc in $kdc_list; do
1783                         break
1784                 done
1785                 KDC="$kdc"
1786         fi
1787 fi
1788 
1789 if [[ -z $realm ]]; then
1790         printf "$(gettext "Enter the Kerberos realm"): "
1791         read realm
1792         checkval="REALM"; check_value $realm
1793 fi
1794 if [[ -z $KDC ]]; then
1795         printf "$(gettext "Specify the master KDC hostname for the above realm"): "
1796         read KDC
1797         checkval="KDC"; check_value $KDC
1798 fi
1799 
1800 FKDC=`$KLOOKUP $KDC`
1801 
1802 #
1803 # Ping to see if the kdc is alive !
1804 #
1805 ping_check $FKDC "KDC"
1806 
1807 if [[ -z $kdc_list && (-z $options || -z $filepath) ]]; then
1808         query "$(gettext "Do you have any slave KDC(s)") ?"
1809         if [[ $answer == yes ]]; then
1810                 printf "$(gettext "Enter a comma-separated list of slave KDC host names"): "
1811                 read kdc_list
1812         fi
1813 fi
1814 
1815 [[ -n $kdc_list ]] && verify_kdcs "$kdc_list"
1816 
1817 #
1818 # Check to see if we will have a dynamic presence in the realm
1819 #
1820 if [[ -z $options ]]; then
1821         query "$(gettext "Will this client need service keys") ?"
1822         if [[ $answer == no ]]; then
1823                 no_keytab=yes
1824         fi
1825 fi
1826 
1827 #
1828 # Check to see if we are configuring the client to use a logical host name
1829 # of a cluster environment
1830 #
1831 if [[ -z $options ]]; then
1832         query "$(gettext "Is this client a member of a cluster that uses a logical host name") ?"
1833         if [[ $answer == yes ]]; then
1834                 printf "$(gettext "Specify the logical hostname of the cluster"): "
1835                 read logical_hn
1836                 checkval="LOGICAL_HOSTNAME"; check_value $logical_hn
1837                 setup_lhn
1838         fi
1839 fi
1840 
1841 if [[ -n $domain_list && (-z $options || -z $filepath) ]]; then
1842         query "$(gettext "Do you have multiple domains/hosts to map to realm %s"
1843 ) ?" $realm
1844         if [[ $answer == yes ]]; then
1845                 printf "$(gettext "Enter a comma-separated list of domain/hosts
1846 to map to the default realm"): "
1847                 read domain_list
1848         fi
1849 fi
1850 [[ -n domain_list ]] && domain_list=${domain_list//,/ }
1851 
1852 #
1853 # Start writing up the krb5.conf file, save the existing one
1854 # if already present
1855 #
1856 writeup_krb5_conf
1857 
1858 #
1859 # Is this client going to use krb-nfs?  If so then we need to at least
1860 # uncomment the krb5* sec flavors in nfssec.conf.
1861 #
1862 if [[ -z $options ]]; then
1863         query "$(gettext "Do you plan on doing Kerberized nfs") ?"
1864         add_nfs=$answer
1865 fi
1866 
1867 if [[ $add_nfs == yes ]]; then
1868         modify_nfssec_conf
1869 
1870         #       
1871         # We also want to enable gss as we now live in a SBD world
1872         #
1873         svcadm enable svc:/network/rpc/gss:default
1874         [[ $? -ne 0 ]] && printf "$(gettext "Warning: could not enable gss service").\n"
1875 fi
1876 
1877 if [[ -z $options ]]; then
1878         query "$(gettext "Do you want to update /etc/pam.conf") ?"
1879         if [[ $answer == yes ]]; then
1880                 printf "$(gettext "Enter a list of PAM service names in the following format: service:{first|only|optional}[,..]"): "
1881                 read svc_list
1882                 SVCs=${svc_list//,/ }
1883         fi
1884 fi
1885 [[ -n $svc_list ]] && update_pam_conf
1886 
1887 #
1888 # Copy over krb5.conf master copy from filepath
1889 #
1890 if [[ -z $options || -z $filepath ]]; then
1891         query "$(gettext "Do you want to copy over the master krb5.conf file") ?"
1892         if [[ $answer == yes ]]; then
1893                 printf "$(gettext "Enter the pathname of the file to be copied"): "
1894                 read filepath
1895         fi
1896 fi
1897 
1898 if [[ -n $filepath && -r $filepath ]]; then
1899         cp $filepath $KRB5_CONFIG
1900         if [[ $? -eq 0 ]]; then
1901                 printf "$(gettext "Copied %s to %s").\n" $filepath $KRB5_CONFIG
1902         else
1903                 printf "$(gettext "Copy of %s failed, exiting").\n" $filepath >&2
1904                 error_message
1905         fi
1906 elif [[ -n $filepath ]]; then
1907         printf "\n$(gettext "%s not found, exiting").\n" $filepath >&2
1908         error_message
1909 fi
1910 
1911 doKRB5config
1912 
1913 #
1914 # Populate any service keys needed for the client in the keytab file
1915 #
1916 if [[ $no_keytab != yes ]]; then
1917         setup_keytab
1918 else
1919         printf "\n$(gettext "Note: %s file not created, please refer to verify_ap_req_nofail in krb5.conf(4) for the implications").\n" $KRB5_KEYTAB_FILE
1920         printf "$(gettext "Client will also not be able to host services that use Kerberos").\n"
1921 fi
1922 
1923 printf -- "\n---------------------------------------------------\n"
1924 printf "$(gettext "Setup COMPLETE").\n\n"
1925 
1926 #
1927 # If we have configured the client in a cluster we need to remind the user
1928 # to propagate the keytab and configuration files to the other members.
1929 #
1930 if [[ -n $logical_hn ]]; then
1931         printf "\n$(gettext "Note, you will need to securely transfer the /etc/krb5/krb5.keytab and /etc/krb5/krb5.conf files to all the other members of your cluster").\n"
1932 fi
1933 
1934 #
1935 # Cleanup.
1936 #
1937 kdestroy -q 1>$TMP_FILE 2>&1
1938 rm -f $TMP_FILE
1939 rm -rf $TMPDIR > /dev/null 2>&1
1940 exit 0