1#!/bin/ksh -p 2# 3# Copyright 2004 Sun Microsystems, Inc. All rights reserved. 4# Use is subject to license terms. 5# 6# ident "%Z%%M% %I% %E% SMI" 7# 8# This script is used to setup the Kerberos client by 9# supplying information about the Kerberos realm and kdc. 10# 11# The kerberos configuration file (/etc/krb5/krb5.conf) would 12# be generated and local host's keytab file setup. The script 13# can also optionally setup the system to do kerberized nfs and 14# bringover a master krb5.conf copy from a specified location. 15 16error_message() { 17 kdestroy -q -c $TMP_CCACHE 1>$TMP_FILE 2>&1 18 rm -f $TMP_FILE 19 printf "---------------------------------------------------\n" 20 printf "$(gettext "Setup FAILED").\n\n" 21 exit 1 22} 23 24cannot_create() { 25 typeset filename="$1" 26 typeset stat="$2" 27 if [ $stat -ne 0 ]; then 28 printf "\n$(gettext "Cannot create/edit %s, exiting").\n" $filename 29 error_message 30 fi 31} 32 33modify_nfssec_conf() { 34 if [ -r $NFSSEC_FILE ]; then 35 cat $NFSSEC_FILE > $NFSSEC_FILE.sav 36 cannot_create $NFSSEC_FILE.sav $? 37 fi 38 39 cat $NFSSEC_FILE > $TMP_FILE 40 cannot_create $TMP_FILE $? 41 42 if grep -s "#krb5" $NFSSEC_FILE > /dev/null 2>&1; then 43 sed "s%^#krb5%krb5%" $TMP_FILE >$NFSSEC_FILE 44 cannot_create $NFSSEC_FILE $? 45 fi 46} 47 48call_kadmin() { 49 typeset svc="$1" 50 typeset bool1 bool2 bool3 bool4 51 52 for listentry in $fqdnlist; do 53 54 # Reset conditional vars to 1 55 bool1=1; bool2=1; bool3=1; bool4=1 56 57 service_princ=$(echo "$svc/$listentry") 58 getprincsubcommand="getprinc $service_princ" 59 anksubcommand="addprinc -randkey $service_princ" 60 ktaddsubcommand="ktadd $service_princ" 61 62 kadmin -c $TMP_CCACHE -q "$getprincsubcommand" 1>$TMP_FILE 2>&1 63 64 egrep -s "get_principal: Principal does not exist" $TMP_FILE 65 bool1=$? 66 egrep -s "get_principal: Operation requires ``get" $TMP_FILE 67 bool2=$? 68 69 if [[ $bool1 -eq 0 || $bool2 -eq 0 ]]; then 70 kadmin -c $TMP_CCACHE -q "$anksubcommand" 1>$TMP_FILE 2>&1 71 72 egrep -s "add_principal: Principal or policy already exists while creating \"$service_princ@$REALM\"." $TMP_FILE 73 bool3=$? 74 75 egrep -s "Principal \"$service_princ@$REALM\" created." $TMP_FILE 76 bool4=$? 77 78 if [[ $bool3 -eq 0 || $bool4 -eq 0 ]]; then 79 printf "$(gettext "%s entry ADDED to KDC database").\n" $service_princ 80 else 81 cat $TMP_FILE; 82 printf "\n$(gettext "kadmin: add_principal of %s failed, exiting").\n" $service_princ 83 error_message 84 fi 85 else 86 printf "$(gettext "%s entry already exists in KDC database").\n" $service_princ 87 fi 88 89 klist -k 1>$TMP_FILE 2>&1 90 egrep -s "$service_princ@$REALM" $TMP_FILE 91 if [ $? -eq 0 ]; then 92 printf "$(gettext "%s entry already present in keytab").\n" $service_princ 93 else 94 kadmin -c $TMP_CCACHE -q "$ktaddsubcommand" 1>$TMP_FILE 2>&1 95 egrep -s "added to keytab WRFILE:$KRB5_KEYTAB_FILE." $TMP_FILE 96 if [ $? -ne 0 ]; then 97 cat $TMP_FILE; 98 printf "\n$(gettext "kadmin: ktadd of %s failed, exiting").\n" $service_princ 99 error_message 100 else 101 printf "$(gettext "%s entry ADDED to keytab").\n" $service_princ 102 fi 103 fi 104 105 done 106} 107 108writeup_krb5_conf() { 109 printf "\n$(gettext "Setting up %s").\n" $KRB5_CONFIG_FILE 110 111 if [ -r $KRB5_CONFIG_FILE ]; then 112 cat $KRB5_CONFIG_FILE > $KRB5_CONFIG_FILE.sav 113 cannot_create $KRB5_CONFIG_FILE.sav $? 114 fi 115 116 exec > $KRB5_CONFIG_FILE 117 if [ $? -ne 0 ]; then 118 exec > /dev/tty 119 printf "\n$(gettext "Cannot write to %s, exiting").\n" $KRB5_CONFIG_FILE 120 error_message 121 fi 122 123 printf "[libdefaults]\n" 124 if [ "$dns_lookup" = yes ]; then 125 printf "\t$dnsarg = on\n" 126 if [ "$dnsarg" = dns_lookup_kdc ]; then 127 printf "\tdefault_realm = $REALM\n" 128 printf "\n[domain_realm]\n" 129 printf "\t$KDC = $REALM\n" 130 printf "\t$client_machine = $REALM\n" 131 printf "\t.$fqdn = $REALM\n\n" 132 else 133 if [ "$dnsarg" = dns_lookup_realm ]; then 134 135 printf "\n[realms]\n" 136 printf "\t$REALM = {\n" 137 printf "\t\tkdc = $KDC\n" 138 printf "\t\tadmin_server = $KDC\n" 139 printf "\t}\n\n" 140 else 141 printf "\n\n" 142 fi 143 fi 144 else 145 printf "\tdefault_realm = $REALM\n\n" 146 147 printf "[realms]\n" 148 printf "\t$REALM = {\n" 149 printf "\t\tkdc = $KDC\n" 150 printf "\t\tadmin_server = $KDC\n" 151 printf "\t}\n\n" 152 153 printf "[domain_realm]\n" 154 printf "\t$KDC = $REALM\n" 155 printf "\t$client_machine = $REALM\n" 156 printf "\t.$fqdn = $REALM\n\n" 157 fi 158 159 printf "[logging]\n" 160 printf "\tdefault = FILE:/var/krb5/kdc.log\n" 161 printf "\tkdc = FILE:/var/krb5/kdc.log\n" 162 163 # 164 # return output to TTY 165 # 166 exec > /dev/tty 167} 168 169ask() { 170 question=$1 171 default_answer=$2 172 if [ -z "$default_answer" ]; then 173 printf "$question :\c" 174 else 175 printf "$question [$default_answer]: \c" 176 fi 177 read answer 178 test -z "$answer" && answer="$default_answer" 179} 180 181yesno() { 182 typeset question="$1" 183 answer="" 184 while [ -z "$answer" ]; do 185 ask "$question" y/n 186 case "$answer" in 187 y|yes) answer=yes;; 188 n|no) answer=no;; 189 *) answer="";; 190 esac 191 done 192} 193 194query() { 195 yesno "$*" 196 if [ "$answer" = no ]; then 197 printf "\t$(gettext "No action performed").\n" 198 fi 199} 200 201 202read_profile() { 203 typeset param value 204 typeset file="$1" 205 if [[ ! -d $file && -r $file ]]; then 206 while read param value 207 do 208 case "$param" in 209 REALM) if [ -z "$REALM" ]; then 210 REALM="$value" 211 checkval="REALM"; check_value $REALM 212 fi 213 ;; 214 KDC) if [ -z "$KDC" ]; then 215 KDC="$value" 216 checkval="KDC"; check_value $KDC 217 fi 218 ;; 219 ADMIN) if [ -z "$ADMIN_PRINC" ]; then 220 ADMIN_PRINC="$value" 221 checkval="ADMIN_PRINC" 222 check_value $ADMIN_PRINC 223 fi 224 ;; 225 FILEPATH) if [ -z "$filepath" ]; then 226 filepath="$value" 227 fi 228 ;; 229 NFS) if [ -z "$add_nfs" ]; then 230 if [ "$value" = 1 ]; then 231 add_nfs=yes 232 else 233 add_nfs=no 234 fi 235 fi 236 ;; 237 DNSLOOKUP) if [ -z "$dnsarg" ]; then 238 dnsarg="$value" 239 checkval="DNS_OPTIONS" 240 check_value $dnsarg 241 fi 242 ;; 243 FQDN) if [ -z "$fqdnlist" ]; then 244 fqdnlist="$value" 245 checkval="FQDN" 246 check_value $fqdnlist 247 verify_fqdnlist "$fqdnlist" 248 fi 249 ;; 250 esac 251 done <$file 252 else 253 printf "\n$(gettext "The kclient profile \`%s' is not valid, exiting").\n" $file 254 error_message 255 fi 256} 257 258ping_check() { 259 typeset machine="$1" 260 typeset string="$2" 261 if ping $machine > /dev/null; then 262 : 263 else 264 printf "\n$(gettext "%s %s is unreachable, exiting").\n" $string $machine 265 error_message 266 fi 267 268 # Output timesync warning if not using a profile, i.e. in 269 # interactive mode. 270 if [[ -z "$profile" && "$string" = KDC ]]; then 271 # It's difficult to sync up time with KDC esp. if in a 272 # zone so just print a warning about KDC time sync. 273 printf "\n$(gettext "Note, this system and the KDC's time must be within 5 minutes of each other for Kerberos to function. Both systems should run some form of time synchronization system like Network Time Protocol (NTP)").\n" 274 fi 275} 276 277check_value() { 278 typeset arg="$1" 279 if [ -z "$arg" ]; then 280 printf "\n$(gettext "No input obtained for %s, exiting").\n" $checkval 281 error_message 282 else 283 echo "$arg">$TMP_FILE 284 if egrep -s '[*$^#!]+' $TMP_FILE; then 285 printf "\n$(gettext "Invalid input obtained for %s, exiting").\n" $checkval 286 error_message 287 fi 288 fi 289} 290 291set_dns_value() { 292 typeset arg="$1" 293 if [[ "$arg" = dns_lookup_kdc || "$arg" = dns_lookup_realm || "$arg" = dns_fallback ]]; then 294 dns_lookup=yes 295 else 296 arg=$(echo "$arg"|tr '[A-Z]' '[a-z]') 297 if [ "$arg" = none ]; then 298 dns_lookup=no 299 else 300 printf "\n$(gettext "Invalid DNS lookup option, exiting").\n" 301 error_message 302 fi 303 fi 304} 305 306verify_fqdnlist() { 307 integer count=1 308 309 list=$(echo "$1" | tr -d " " | tr -d "\t") 310 hostname=$(uname -n | tr '[A-Z]' '[a-z]' | cut -d"." -f1) 311 fqdnlist=$client_machine 312 313 eachfqdn=$(echo "$list" | cut -d"," -f$count) 314 if [ -z "$eachfqdn" ]; then 315 printf "\n$(gettext "If the -f option is used, atleast one FQDN should be listed").\n\n" 316 317 usage 318 else 319 while [ ! -z "$eachfqdn" ]; do 320 tmpvar=$(echo "$eachfqdn" | cut -d"." -f1) 321 if [ -z "$tmpvar" ]; then 322 fullhost="$hostname$eachfqdn" 323 else 324 fullhost="$hostname.$eachfqdn" 325 fi 326 327 ping_check $fullhost "System" 328 if [ "$fullhost" = "$client_machine" ]; then 329 : 330 else 331 fqdnlist="$fqdnlist $fullhost" 332 fi 333 334 if [[ "$list" == *,* ]]; then 335 ((count = count + 1)) 336 eachfqdn=$(echo "$list" | cut -d"," -f$count) 337 else 338 break 339 fi 340 done 341 fi 342} 343 344usage() { 345 printf "\n$(gettext "Usage: kclient [ -n ] [ -R realm ] [ -k kdc ] [ -a adminuser ] [ -c filepath ] [ -d dnsarg ] [ -f fqdn_list ] [ -p profile ]")\n\n" 346 printf "$(gettext "Refer kclient(1M) for details, exiting").\n" 347 error_message 348} 349 350########################### 351# Main section # 352########################### 353# 354# Set the Kerberos config file and some default strings/files 355# 356KRB5_CONFIG_FILE="/etc/krb5/krb5.conf" 357KRB5_KEYTAB_FILE="/etc/krb5/krb5.keytab" 358RESOLV_CONF_FILE="/etc/resolv.conf" 359NFSSEC_FILE="/etc/nfssec.conf" 360dns_lookup="no" 361ask_fqdns="no" 362checkval="" 363profile="" 364 365# Set OS release level to Solaris 10, inorder to track the requirement 366# of the root/fqdn service principal for kerberized NFS. 367release_level=10 368 369if [ -x /usr/bin/mktemp ]; then 370 TMP_FILE=$(/usr/bin/mktemp /etc/krb5/krb5tmpfile.XXXXXX) 371 TMP_CCACHE=$(/usr/bin/mktemp /etc/krb5/krb5tmpccache.XXXXXX) 372else 373 TMP_FILE="/etc/krb5/krb5tmpfile.$$" 374 TMP_CCACHE="/etc/krb5/krb5tmpccache.$$" 375fi 376 377if [[ -z "$TMP_FILE" || -z "$TMP_CCACHE" ]]; then 378 printf "\n$(gettext "Temporary file creation failed, exiting").\n" >&2 379 exit 1 380fi 381 382# 383# If we are interrupted, cleanup after ourselves 384# 385trap "/usr/bin/rm -f $TMP_FILE $TMP_CCACHE; exit 1" HUP INT QUIT TERM 386 387if [ -d /usr/bin ]; then 388 if [ -d /usr/sbin ]; then 389 PATH=/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:$PATH 390 export PATH 391 else 392 printf "\n$(gettext "Directory /usr/sbin not found, exiting").\n" >&2 393 exit 1 394 fi 395else 396 printf "\n$(gettext "Directory /usr/bin not found, exiting").\n" >&2 397 exit 1 398fi 399 400printf "\n$(gettext "Starting client setup")\n\n" 401printf "---------------------------------------------------\n" 402 403# 404# Check for uid 0, disallow otherwise 405# 406id 1>$TMP_FILE 2>&1 407if [ $? -eq 0 ]; then 408 if egrep -s "uid=0\(root\)" $TMP_FILE; then 409 # uid is 0, go ahead ... 410 : 411 else 412 printf "\n$(gettext "Root privileges are required to run this script, exiting").\n" 413 error_message 414 fi 415else 416 cat $TMP_FILE; 417 printf "\n$(gettext "uid check failed, exiting").\n" 418 error_message 419fi 420 421# 422# Check for /etc/resolv.conf 423# 424if [ -r $RESOLV_CONF_FILE ]; then 425 while read label text 426 do 427 case "$label" in 428 domain) # Copy the entry into $fqdn 429 if [ -z "$text" ]; then 430 printf "\n$(gettext "DNS domain info malformed in %s, exiting").\n" $RESOLV_CONF_FILE 431 error_message 432 fi 433 fqdn=$(echo "$text"|tr '[A-Z]' '[a-z]') 434 break 435 ;; 436 esac 437 done <$RESOLV_CONF_FILE 438 439 if [ -z "$fqdn" ]; then 440 printf "\n$(gettext "DNS domain info missing in %s, exiting").\n" $RESOLV_CONF_FILE 441 error_message 442 fi 443else 444 # 445 # /etc/resolv.conf not present, exit ... 446 # 447 printf "\n$(gettext "%s does not exist and is required for Kerberos setup")\n" $RESOLV_CONF_FILE 448 printf "$(gettext "Refer resolv.conf(4), exiting").\n" 449 error_message 450fi 451 452client_machine=$(uname -n | tr '[A-Z]' '[a-z]' | cut -d"." -f1).$fqdn 453 454# 455# Process the command-line arguments (if any) 456# 457OPTIND=1 458while getopts np:R:k:a:c:d:f: OPTIONS 459do 460 case $OPTIONS in 461 p) options="$options -p" 462 profile="$OPTARG" 463 read_profile $profile 464 ;; 465 R) options="$options -R" 466 REALM="$OPTARG" 467 checkval="REALM"; check_value $REALM 468 ;; 469 k) options="$options -k" 470 KDC="$OPTARG" 471 checkval="KDC"; check_value $KDC 472 ;; 473 a) options="$options -a" 474 ADMIN_PRINC="$OPTARG" 475 checkval="ADMIN_PRINC"; check_value $ADMIN_PRINC 476 ;; 477 c) options="$options -c" 478 filepath="$OPTARG" 479 ;; 480 d) options="$options -d" 481 dnsarg="$OPTARG" 482 checkval="DNS_OPTIONS"; check_value $dnsarg 483 ;; 484 f) options="$options -f" 485 fqdnlist="$OPTARG" 486 verify_fqdnlist "$fqdnlist" 487 ;; 488 n) options="$options -n" 489 add_nfs=yes 490 ;; 491 \?) usage 492 ;; 493 *) usage 494 ;; 495 esac 496done 497 498#correct argument count after options 499shift `expr $OPTIND - 1` 500 501if [ -z "$options" ]; then 502 : 503else 504 if [ $# -ne 0 ]; then 505 usage 506 fi 507fi 508 509if [ -z "$dnsarg" ]; then 510 query "$(gettext "Do you want to use DNS for kerberos lookups") ?" 511 if [ "$answer" = yes ]; then 512 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" 513 printf "\n$(gettext "Enter required DNS option"): \c" 514 read dnsarg 515 checkval="DNS_OPTIONS"; check_value $dnsarg 516 set_dns_value $dnsarg 517 fi 518else 519 set_dns_value $dnsarg 520fi 521 522if [ -z "$REALM" ]; then 523 printf "$(gettext "Enter the Kerberos realm"): \c" 524 read REALM 525 checkval="REALM"; check_value $REALM 526fi 527if [ -z "$KDC" ]; then 528 printf "$(gettext "Specify the KDC hostname for the above realm"): \c" 529 read KDC 530 checkval="KDC"; check_value $KDC 531fi 532 533REALM=$(echo "$REALM"|tr '[a-z]' '[A-Z]') 534KDC=$(echo "$KDC"|tr '[A-Z]' '[a-z]') 535 536echo "$KDC">$TMP_FILE 537if egrep -s '[^.]\.[^.]+$' $TMP_FILE; then 538 # do nothing, KDC is in fqdn format 539 : 540 echo "$KDC" 541else 542 if egrep -s '\.+' $TMP_FILE; then 543 printf "\n$(gettext "Improper format of KDC hostname, exiting").\n" 544 error_message 545 else 546 # Attach fqdn to KDC, to get the Fully Qualified Domain Name 547 # of the KDC requested 548 KDC=$(echo "$KDC.$fqdn") 549 fi 550fi 551# 552# Ping to see if the kdc is alive ! 553# 554ping_check $KDC "KDC" 555 556 557# 558# Start writing up the krb5.conf file, save the existing one 559# if already present 560# 561writeup_krb5_conf 562 563 564# 565# Done creating krb5.conf, so now we ... 566# 567# 1. kinit with ADMIN_PRINC 568# 569 570if [ -z "$ADMIN_PRINC" ]; then 571 printf "\n$(gettext "Enter the krb5 administrative principal to be used"): \c" 572 read ADMIN_PRINC 573 checkval="ADMIN_PRINC"; check_value $ADMIN_PRINC 574fi 575 576echo "$ADMIN_PRINC">$TMP_FILE 577 578if egrep -s '\/admin' $TMP_FILE; then 579 # Already in "/admin" format, do nothing 580 : 581else 582 if egrep -s '\/' $TMP_FILE; then 583 printf "\n$(gettext "Improper entry for krb5 admin principal, exiting").\n" 584 error_message 585 else 586 ADMIN_PRINC=$(echo "$ADMIN_PRINC/admin") 587 fi 588fi 589 590printf "$(gettext "Obtaining TGT for %s") ...\n" $ADMIN_PRINC 591KDC=$(echo "$KDC"|tr '[A-Z]' '[a-z]') 592kinit -c $TMP_CCACHE -S kadmin/$KDC $ADMIN_PRINC 593klist -c $TMP_CCACHE 1>$TMP_FILE 2>&1 594if egrep -s "Valid starting" $TMP_FILE && egrep -s "kadmin/$KDC@$REALM" $TMP_FILE; then 595 : 596else 597 printf "\n$(gettext "kinit of %s failed, exiting").\n" $ADMIN_PRINC 598 error_message 599fi 600 601# 602# 2. Do we want to create and/or add service principal(s) for fqdn's 603# other than the one listed in resolv.conf(4) ? 604# 605if [ -z "$options" ]; then 606 echo 607 query "$(gettext "Do you have multiple DNS domains spanning the Kerberos realm") $REALM ?" 608 ask_fqdns=$answer 609 if [ "$ask_fqdns" = yes ]; then 610 printf "$(gettext "Enter a comma-seperated list of DNS domain names"): \c" 611 read fqdnlist 612 verify_fqdnlist "$fqdnlist" 613 else 614 fqdnlist=$client_machine 615 fi 616else 617 if [ -z "$fqdnlist" ]; then 618 fqdnlist=$client_machine 619 fi 620fi 621 622# 623# 3. Set up keytab/config files for nfs/host/root entries (if requested) 624# 625echo 626if [ -z "$options" ]; then 627 query "$(gettext "Do you plan on doing Kerberized nfs") ?" 628 add_nfs=$answer 629fi 630 631if [ "$add_nfs" = yes ]; then 632 modify_nfssec_conf 633 echo; call_kadmin nfs 634 # 635 # Check to see if the system is a pre-S10 system which would 636 # require the root/FQDN svc principal for kerberized NFS. 637 # 638 current_release=$(uname -r | cut -d"." -f2) 639 if [ $current_release -lt $release_level ]; then 640 echo; call_kadmin root 641 fi 642fi 643 644# Add the host entry to the keytab 645echo; call_kadmin host 646 647# 648# 4. Copy over krb5.conf master copy from filepath 649# 650if [ -z "$options" ]; then 651 echo 652 query "$(gettext "Do you want to copy over the master krb5.conf file") ?" 653 if [ "$answer" = yes ]; then 654 printf "$(gettext "Enter the pathname of the file to be copied"): \c" 655 read filepath 656 fi 657fi 658 659if [ -z "$filepath" ]; then 660 : 661else 662 if [ -r $filepath ]; then 663 cp $filepath $KRB5_CONFIG_FILE 664 if [ $? -eq 0 ]; then 665 printf "\n$(gettext "Copied %s").\n" $filepath 666 else 667 printf "\n$(gettext "Copy of %s failed, exiting").\n" $filepath 668 error_message 669 fi 670 else 671 printf "\n$(gettext "%s not found, exiting").\n" $filepath 672 error_message 673 fi 674fi 675 676printf "\n---------------------------------------------------\n" 677printf "$(gettext "Setup COMPLETE").\n" 678 679# 680# 5. Cleanup, please ! 681# 682kdestroy -q -c $TMP_CCACHE 1>$TMP_FILE 2>&1 683rm -f $TMP_FILE 684exit 0 685