Print this page
6817447 libgss and various mechs are hiding both the real minor_status and the error token
6405422 Solaris acceptors fail in AD-KDC environments when using non-"host" services (e.g. "cifs")
6824434 Unable to accept context establishment initiated by Windows 2000 clients
6787343 kclient's site lookups fail in certain network environments
6692646 kclient should output errors to stderr
6525327 kinit failed when arcfour-hmac-md5-exp was used for the principal's key
6745582 SUNWkdcu missing package dependencies after kclientv2 integration

@@ -17,11 +17,11 @@
 # fields enclosed by brackets "[]" replaced with your own identifying
 # information: Portions Copyright [yyyy] [name of copyright owner]
 #
 # CDDL HEADER END
 #
-# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 # This script is used to setup the Kerberos client by
 # supplying information about the Kerberos realm and kdc.
 #

@@ -29,16 +29,15 @@
 # be generated and local host's keytab file setup. The script
 # can also optionally setup the system to do kerberized nfs and
 # bringover a master krb5.conf copy from a specified location.
 
 function cleanup {
-        integer ret=$1
 
-        kdestroy -q 1> $TMP_FILE 2>&1
+        kdestroy -q > $TMP_FILE 2>&1
         rm -r $TMPDIR > /dev/null 2>&1
 
-        exit $ret
+        exit $1
 }
 function exiting {
         
         printf "\n$(gettext "Exiting setup, nothing changed").\n\n"
 

@@ -45,22 +44,22 @@
         cleanup $1
 }
 
 function error_message {
 
-        printf -- "---------------------------------------------------\n"
-        printf "$(gettext "Setup FAILED").\n\n"
+        printf -- "---------------------------------------------------\n" >&2
+        printf "$(gettext "Setup FAILED").\n\n" >&2
 
         cleanup 1
 }
 
 function check_bin {
 
         typeset bin=$1
 
         if [[ ! -x $bin ]]; then
-                printf "$(gettext "Could not access/execute %s").\n" $bin
+                printf "$(gettext "Could not access/execute %s").\n" $bin >&2
                 error_message
         fi
 }
 
 function cannot_create {

@@ -193,11 +192,11 @@
 
         printf "\n$(gettext "Setting up %s").\n\n" $KRB5_CONFIG_FILE
 
         exec 3>$KRB5_CONFIG
         if [[ $? -ne 0 ]]; then
-                printf "\n$(gettext "Can not write to %s, exiting").\n" $KRB5_CONFIG
+                printf "\n$(gettext "Can not write to %s, exiting").\n" $KRB5_CONFIG >&2
                 error_message
         fi
 
         printf "[libdefaults]\n" 1>&3
         if [[ $no_keytab == yes ]]; then

@@ -863,11 +862,11 @@
 function write_ads_krb5conf {
         printf "\n$(gettext "Setting up %s").\n\n" $KRB5_CONFIG_FILE
 
         exec 3>$KRB5_CONFIG
         if [[ $? -ne 0 ]]; then
-                printf "\n$(gettext "Can not write to %s, exiting").\n" $KRB5_CONFIG
+                printf "\n$(gettext "Can not write to %s, exiting").\n" $KRB5_CONFIG >&2
                 error_message
         fi
 
         printf "[libdefaults]\n" 1>&3
         printf "\tdefault_realm = $realm\n" 1>&3

@@ -897,11 +896,11 @@
         ldapsearch -R -T -h $dc $ldap_args \
             -b "" -s base "" schemaNamingContext| \
                 grep ^schemaNamingContext|read j schemaNamingContext
 
         if [[ $? -ne 0 ]]; then
-                printf "$(gettext "Can't find forest").\n"
+                printf "$(gettext "Can't find forest").\n" >&2
                 error_message
         fi
         schemaNamingContext=${schemaNamingContext#CN=Schema,CN=Configuration,}
 
         [[ -z $schemaNamingContext ]] && return 1

@@ -937,13 +936,18 @@
         # Default
         set -A GCs -- $ForestDnsZones 3268
         gc=$ForestDnsZones
 }
 
+#
+# The local variables used to calculate the IP address are of type unsigned
+# integer (-ui), as this is required to restrict the integer to 32b.
+# Starting in ksh88, Solaris has incorrectly assummed that -i represents 64b.
+#
 function ipAddr2num {
         typeset OIFS
-        typeset -i16 num byte
+        typeset -ui16 num
 
         if [[ "$1" != +([0-9]).+([0-9]).+([0-9]).+([0-9]) ]]
         then
                 print 0
                 return 0

@@ -957,24 +961,34 @@
         num=$((${1}<<24 | ${2}<<16 | ${3}<<8 | ${4}))
 
         print -- $num
 }
 
+#
+# The local variables used to calculate the IP address are of type unsigned
+# integer (-ui), as this is required to restrict the integer to 32b.
+# Starting in ksh88, Solaris has incorrectly assummed that -i represents 64b.
+#
 function num2ipAddr {
-        typeset -i16 num
-        typeset -i10 a b c d
+        typeset -ui16 num
+        typeset -ui10 a b c d
 
         num=$1
         a=$((num>>24        ))
         b=$((num>>16 & 16#ff))
         c=$((num>>8  & 16#ff))
         d=$((num     & 16#ff))
         print -- $a.$b.$c.$d
 }
 
+#
+# The local variables used to calculate the IP address are of type unsigned
+# integer (-ui), as this is required to restrict the integer to 32b.
+# Starting in ksh88, Solaris has incorrectly assummed that -i represents 64b.
+#
 function netmask2length {
-        typeset -i16 netmask
+        typeset -ui16 netmask
         typeset -i len
 
         netmask=$1
         len=32
         while [[ $((netmask % 2)) -eq 0 ]]

@@ -983,13 +997,18 @@
                 len=$((len - 1))
         done
         print $len
 }
 
+#
+# The local variables used to calculate the IP address are of type unsigned
+# integer (-ui), as this is required to restrict the integer to 32b.
+# Starting in ksh88, Solaris has incorrectly assummed that -i represents 64b.
+#
 function getSubnets {
-        typeset -i16 addr netmask
-        typeset -i16 classa=16\#ff000000
+        typeset -ui16 addr netmask
+        typeset -ui16 classa=16\#ff000000
 
         ifconfig -a|while read line
         do
                 addr=0
                 netmask=0

@@ -1110,11 +1129,11 @@
                 printf "$(gettext "The client is currently configured in a different domain").\n"
                 printf "$(gettext "Currently in the '%s' domain, trying to join the '%s' domain").\n" $oldDom $newDom
                 query "$(gettext "Do you want the client to join a new domain") ?"
                 printf "\n"
                 if [[ $answer != yes ]]; then
-                        printf "$(gettext "Client will not be joined to the new domain").\n"
+                        printf "$(gettext "Client will not be joined to the new domain").\n" >&2
                         error_message
                 fi
         fi
 }
 

@@ -1127,11 +1146,11 @@
         else
                 getDC
                 if [[ -n $dc ]]; then
                         KDC=$dc
                 else
-                        printf "$(gettext "Could not find domain controller server for '%s'.  Exiting").\n" $realm
+                        printf "$(gettext "Could not find domain controller server for '%s'.  Exiting").\n" $realm >&2
                         error_message
                 fi
         fi
 }
 

@@ -1148,11 +1167,11 @@
         else
                 cprinc=$ADMIN_PRINC
         fi
 
         if ! discover_domain; then
-                printf "$(gettext "Can not find realm") '%s'.\n" $realm
+                printf "$(gettext "Can not find realm") '%s'.\n" $realm >&2
                 error_message
         fi
 
         dom=$domain
         realm=$domain

@@ -1190,11 +1209,11 @@
 
         printf "$(gettext "Attempting to join '%s' to the '%s' domain").\n\n" $upcase_nodename $realm
 
         kinit $cprinc@$realm
         if [[ $? -ne 0 ]]; then
-                printf "$(gettext "Could not authenticate %s.  Exiting").\n" $cprinc@$realm
+                printf "$(gettext "Could not authenticate %s.  Exiting").\n" $cprinc@$realm >&2
                 error_message
         fi
 
         if getForestName
         then

@@ -1216,11 +1235,11 @@
 
                 write_ads_krb5conf
         fi
 
         if [[ ${#GCs} -eq 0 ]]; then
-                printf "$(gettext "Could not find global catalogs.  Exiting").\n"
+                printf "$(gettext "Could not find global catalogs.  Exiting").\n" >&2
                 error_message
         fi
 
         # Check to see if the client is transitioning between domains.
         compareDomains $realm

@@ -1231,11 +1250,11 @@
         level=0
         ldapsearch -R -T -h "$dc" $ldap_args -b "" -s base "" \
          domainControllerFunctionality| grep ^domainControllerFunctionality| \
          read j level
         if [[ $? -ne 0 ]]; then
-                printf "$(gettext "Search for domain functionality failed, exiting").\n"
+                printf "$(gettext "Search for domain functionality failed, exiting").\n" >&2
                 error_message
         fi
         # Longhorn and above can't perform an init auth from service
         # keys if the realm is included in the UPN.  w2k3 and below
         # can't perform an init auth when the realm is excluded.

@@ -1244,11 +1263,11 @@
         if ldapsearch -R -T -h "$dc" $ldap_args -b "$baseDN" \
             -s sub sAMAccountName="$netbios_nodename" dn > /dev/null 2>&1
         then
                 :
         else
-                printf "$(gettext "Search for node failed, exiting").\n"
+                printf "$(gettext "Search for node failed, exiting").\n" >&2
                 error_message
         fi
         ldapsearch -R -T -h "$dc" $ldap_args -b "$baseDN" -s sub \
             sAMAccountName="$netbios_nodename" dn|grep "^dn:"|read j dn
 

@@ -1285,17 +1304,17 @@
                 fi
 
                 if $recreate; then
                         ldapdelete -h "$dc" $ldap_args "$dn" > /dev/null 2>&1
                         if [[ $? -ne 0 ]]; then
-                                printf "$(gettext "Error in deleting object: %s").\n" ${sub_dn#$dn}
+                                printf "$(gettext "Error in deleting object: %s").\n" ${sub_dn#$dn} >&2
                                 error_message
                         fi
                 elif $modify_existing; then
                         : # Nothing to delete
                 else
-                        printf "$(gettext "A machine account already exists").\n"
+                        printf "$(gettext "A machine account already exists").\n" >&2
                         error_message
                 fi
         fi
 
         if $modify_existing; then

@@ -1316,11 +1335,11 @@
 EOF
 
                 printf "$(gettext "A machine account already exists; updating it").\n"
                 ldapadd -h "$dc" $ldap_args -f "$object" > /dev/null 2>&1
                 if [[ $? -ne 0 ]]; then
-                        printf "$(gettext "Failed to create the AD object via LDAP").\n"
+                        printf "$(gettext "Failed to create the AD object via LDAP").\n" >&2
                         error_message
                 fi
         else
                 cat > "$object" <<EOF
 dn: CN=$upcase_nodename,$baseDN

@@ -1335,11 +1354,11 @@
 
                 printf "$(gettext "Creating the machine account in AD via LDAP").\n\n"
 
                 ldapadd -h "$dc" $ldap_args -f "$object" > /dev/null 2>&1
                 if [[ $? -ne 0 ]]; then
-                        printf "$(gettext "Failed to create the AD object via LDAP").\n"
+                        printf "$(gettext "Failed to create the AD object via LDAP").\n" >&2
                         error_message
                 fi
         fi
 
         # Generate a new password for the new account

@@ -1376,11 +1395,11 @@
 
         # Set the new password
         printf "%s" $newpw | $KSETPW ${netbios_nodename}@${realm} > /dev/null 2>&1
         if [[ $? -ne 0 ]]
         then
-                printf "$(gettext "Failed to set account password").\n"
+                printf "$(gettext "Failed to set account password").\n" >&2
                 error_message
         fi
 
         # Lookup the new principal's kvno:
         ldapsearch -R -T -h "$dc" $ldap_args -b "$baseDN" \

@@ -1414,19 +1433,18 @@
                 # Use 1DES ONLY if we don't have arcfour
                 userAccountControl=$((userAccountControl + 2097152))
         fi
         if encrypt -l | $grep -q ^des
         then
-                ((val=val+1+2))
-                enctypes[${#enctypes[@]}]=des-cbc-crc
+                ((val=val+2))
                 enctypes[${#enctypes[@]}]=des-cbc-md5
         fi
 
         if [[ ${#enctypes[@]} -eq 0 ]]
         then
                 printf "$(gettext "No enctypes are supported").\n"
-                printf "$(gettext "Please enable arcfour or 1DES, then re-join; see cryptoadm(1M)").\n"
+                printf "$(gettext "Please enable arcfour or 1DES, then re-join; see cryptoadm(1M)").\n" >&2
                 error_message
         fi
 
         # If domain crontroller is Longhorn or above then set new supported
         # encryption type attributes.

@@ -1460,11 +1478,11 @@
 replace: userAccountControl
 userAccountControl: $userAccountControl
 EOF
         ldapmodify -h "$dc" $ldap_args -f "$object" >/dev/null 2>&1
         if [[ $? -ne 0 ]]; then
-                printf "$(gettext "ldapmodify failed to modify account attribute").\n"
+                printf "$(gettext "ldapmodify failed to modify account attribute").\n" >&2
                 error_message
         fi
 
         # Setup a keytab file
         set -A args --

@@ -1481,48 +1499,70 @@
 changetype: modify
 add: servicePrincipalName
 servicePrincipalName: nfs/${fqdn}
 servicePrincipalName: HTTP/${fqdn}
 servicePrincipalName: root/${fqdn}
+servicePrincipalName: cifs/${fqdn}
 EOF
         ldapmodify -h "$dc" $ldap_args -f "$object" >/dev/null 2>&1
         if [[ $? -ne 0 ]]; then
-                printf "$(gettext "ldapmodify failed to modify account attribute").\n"
+                printf "$(gettext "ldapmodify failed to modify account attribute").\n" >&2
                 error_message
         fi
 
-        printf "%s" $newpw | $KSETPW -n -v $kvno -k "$new_keytab" "${args[@]}" host/${fqdn}@${realm} > /dev/null 2>&1
+        #
+        # In Windows, unlike MIT based implementations we salt the keys with
+        # the UPN, which is based on the host/fqdn@realm elements, not with the
+        # individual SPN strings.
+        #
+        salt=host/${fqdn}@${realm}
+
+        printf "%s" $newpw | $KSETPW -n -s $salt -v $kvno -k "$new_keytab" "${args[@]}" host/${fqdn}@${realm} > /dev/null 2>&1
         if [[ $? -ne 0 ]]
         then
-                printf "$(gettext "Failed to set account password").\n"
+                printf "$(gettext "Failed to set account password").\n" >&2
                 error_message
         fi
 
+        printf "%s" $newpw | $KSETPW -n -s $salt -v $kvno -k "$new_keytab" "${args[@]}" HOST/${fqdn}@${realm} > /dev/null 2>&1
+        if [[ $? -ne 0 ]]
+        then
+                printf "$(gettext "Failed to set account password").\n" >&2
+                error_message
+        fi
+
         # Could be setting ${netbios_nodename}@${realm}, but for now no one
         # is requesting this.
 
-        print "%s" $newpw | $KSETPW -n -v $kvno -k "$new_keytab" "${args[@]}" nfs/${fqdn}@${realm} > /dev/null 2>&1
+        printf "%s" $newpw | $KSETPW -n -s $salt -v $kvno -k "$new_keytab" "${args[@]}" nfs/${fqdn}@${realm} > /dev/null 2>&1
         if [[ $? -ne 0 ]]
         then
-                printf "$(gettext "Failed to set account password").\n"
+                printf "$(gettext "Failed to set account password").\n" >&2
                 error_message
         fi
 
-        print "%s" $newpw | $KSETPW -n -v $kvno -k "$new_keytab" "${args[@]}" HTTP/${fqdn}@${realm} > /dev/null 2>&1
+        printf "%s" $newpw | $KSETPW -n -s $salt -v $kvno -k "$new_keytab" "${args[@]}" HTTP/${fqdn}@${realm} > /dev/null 2>&1
         if [[ $? -ne 0 ]]
         then
-                printf "$(gettext "Failed to set account password").\n"
+                printf "$(gettext "Failed to set account password").\n" >&2
                 error_message
         fi
 
-        print "%s" $newpw | $KSETPW -n -v $kvno -k "$new_keytab" "${args[@]}" root/${fqdn}@${realm} > /dev/null 2>&1
+        printf "%s" $newpw | $KSETPW -n -s $salt -v $kvno -k "$new_keytab" "${args[@]}" root/${fqdn}@${realm} > /dev/null 2>&1
         if [[ $? -ne 0 ]]
         then
-                printf "$(gettext "Failed to set account password").\n"
+                printf "$(gettext "Failed to set account password").\n" >&2
                 error_message
         fi
 
+        printf "%s" $newpw | $KSETPW -n -s $salt -v $kvno -k "$new_keytab" "${args[@]}" cifs/${fqdn}@${realm} > /dev/null 2>&1
+        if [[ $? -ne 0 ]]
+        then
+                printf "$(gettext "Failed to set account password").\n" >&2
+                error_message
+        fi
+
         doKRB5config
 
         addDNSRR $dom
 
         setSMB $dom $dc

@@ -1562,19 +1602,23 @@
 typeset -l hostname KDC
 
 export TMPDIR="/var/run/kclient"
 
 mkdir $TMPDIR > /dev/null 2>&1
+if [[ $? -ne 0 ]]; then
+        printf "\n$(gettext "Can not create directory: %s")\n\n" $TMPDIR >&2
+        exit 1
+fi
 
 TMP_FILE=$(mktemp -q -t kclient-tmpfile.XXXXXX)
 export KRB5_CONFIG=$(mktemp -q -t kclient-krb5conf.XXXXXX)
 export KRB5CCNAME=$(mktemp -q -t kclient-krb5ccache.XXXXXX) 
 new_keytab=$(mktemp -q -t kclient-krb5keytab.XXXXXX) 
 if [[ -z $TMP_FILE || -z $KRB5_CONFIG || -z $KRB5CCNAME || -z $new_keytab ]]
 then
-        printf "\n$(gettext "Can not create temporary file, exiting").\n" >&2
-        error_message
+        printf "\n$(gettext "Can not create temporary files, exiting").\n\n" >&2
+        exit 1
 fi
 
 #
 # If we are interrupted, cleanup after ourselves
 #