summaryrefslogtreecommitdiff
path: root/usr/src
diff options
context:
space:
mode:
authorMichen Chang <Michen.Chang@Sun.COM>2009-02-13 18:18:56 -0800
committerMichen Chang <Michen.Chang@Sun.COM>2009-02-13 18:18:56 -0800
commitdd1104fbe0f0f41434502f335b9f0b34999f771c (patch)
tree57c95d64bc40cebf2b145329e1f49e811352d502 /usr/src
parentd68ef20e3fe871e73146fc684d29d335521dcd99 (diff)
downloadillumos-joyent-dd1104fbe0f0f41434502f335b9f0b34999f771c.tar.gz
PSARC 2008/745 nss_ldap shadowAccount support
6715171 nss_ldap and passwdutil do not support all shadowAccount attributes 6797378 'ldapaddent -d passwd' does not print 'x' for the password field 6783712 libsldap fails to set correct version number for V1 profile
Diffstat (limited to 'usr/src')
-rw-r--r--usr/src/cmd/ldap/ns_ldap/idsconfig.sh458
-rw-r--r--usr/src/cmd/ldap/ns_ldap/ldapaddent.c65
-rw-r--r--usr/src/cmd/ldap/ns_ldap/ldapclient.c321
-rw-r--r--usr/src/cmd/ldapcachemgr/cachemgr.c398
-rw-r--r--usr/src/cmd/passwd/passwd.c183
-rw-r--r--usr/src/lib/libsldap/common/mapfile-vers34
-rw-r--r--usr/src/lib/libsldap/common/ns_cache_door.h14
-rw-r--r--usr/src/lib/libsldap/common/ns_config.c79
-rw-r--r--usr/src/lib/libsldap/common/ns_confmgr.c56
-rw-r--r--usr/src/lib/libsldap/common/ns_internal.h11
-rw-r--r--usr/src/lib/libsldap/common/ns_sldap.h27
-rw-r--r--usr/src/lib/libsldap/common/ns_writes.c308
-rw-r--r--usr/src/lib/nsswitch/ldap/common/getspent.c100
-rw-r--r--usr/src/lib/passwdutil/__failed_count.c46
-rw-r--r--usr/src/lib/passwdutil/ldap_attr.c860
-rw-r--r--usr/src/lib/passwdutil/passwdutil.h3
16 files changed, 2567 insertions, 396 deletions
diff --git a/usr/src/cmd/ldap/ns_ldap/idsconfig.sh b/usr/src/cmd/ldap/ns_ldap/idsconfig.sh
index 0aaf673e3a..089f95aa9c 100644
--- a/usr/src/cmd/ldap/ns_ldap/idsconfig.sh
+++ b/usr/src/cmd/ldap/ns_ldap/idsconfig.sh
@@ -1,7 +1,5 @@
#!/bin/sh
#
-# ident "%Z%%M% %I% %E% SMI"
-#
# CDDL HEADER START
#
# The contents of this file are subject to the terms of the
@@ -24,7 +22,7 @@
#
# idsconfig -- script to setup iDS 5.x/6.x for Native LDAP II.
#
-# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
@@ -150,7 +148,8 @@ EOF
16 Search Time Limit : $LDAP_SEARCH_TIME_LIMIT
17 Profile Time to Live : $LDAP_PROFILE_TTL
18 Bind Limit : $LDAP_BIND_LIMIT
- 19 Service Search Descriptors Menu
+ 19 Enable shadow update : $LDAP_ENABLE_SHADOW_UPDATE
+ 20 Service Search Descriptors Menu
EOF
;;
@@ -471,6 +470,43 @@ HELP - No valid suffixes (naming contexts) are available on server
EOF
;;
+ enable_shadow_update_help) cat <<EOF
+
+HELP - Enter 'y' to set up the LDAP server for shadow update.
+ The setup will add an administrator identity/credential
+ and modify the necessary access controls for the client
+ to update shadow(4) data on the LDAP server. If sasl/GSSAPI
+ is in use, the Kerberos host principal will be used as the
+ administrator identity.
+
+ Shadow data is used for password aging and account locking.
+ Please refer to the shadow(4) manual page for details.
+
+EOF
+ ;;
+ add_admin_cred_help) cat <<EOF
+
+HELP - Start the setup to add an administrator identity/credential
+ and to modify access controls for the client to update
+ shadow(4) data on the LDAP server.
+
+ Shadow data is used for password aging and account locking.
+ Please refer to the shadow(4) manual page for details.
+
+EOF
+ ;;
+ use_host_principal_help) cat <<EOF
+
+HELP - A profile with a 'sasl/GSSAPI' authentication method and a 'self'
+ credential level is detected, enter 'y' to modify the necessary
+ access controls for allowing the client to update shadow(4) data
+ on the LDAP server.
+
+ Shadow data is used for password aging and account locking.
+ Please refer to the shadow(4) manual page for details.
+
+EOF
+ ;;
esac
}
@@ -942,6 +978,7 @@ init()
BACKUP=no_ldap # backup suffix
HOST="" # NULL or <hostname>
NAWK="/usr/bin/nawk"
+ RM="/usr/bin/rm"
DOM="" # Set to NULL
# If DNS domain (resolv.conf) exists use that, otherwise use domainname.
@@ -963,8 +1000,13 @@ init()
# idsconfig specific variables.
INPUT_FILE=""
OUTPUT_FILE=""
- NEED_PROXY=0 # 0 = No Proxy, 1 = Create Proxy.
+ LDAP_ENABLE_SHADOW_UPDATE="FALSE"
+ NEED_PROXY=0 # 0 = No Proxy, 1 = Create Proxy.
+ NEED_ADMIN=0 # 0 = No Admin, 1 = Create Admin.
+ NEED_HOSTACL=0 # 0 = No Host ACL, 1 = Create Host ACL.
+ EXISTING_PROFILE=0
LDAP_PROXYAGENT=""
+ LDAP_ADMINDN=""
LDAP_SUFFIX=""
LDAP_DOMAIN=$DOM # domainname on Server (default value)
GEN_CMD=""
@@ -1037,6 +1079,8 @@ init()
export LDAP_BASEDN LDAP_ROOTPWF
export LDAP_DOMAIN LDAP_SUFFIX LDAP_PROXYAGENT LDAP_PROXYAGENT_CRED
export NEED_PROXY
+ export LDAP_ENABLE_SHADOW_UPDATE LDAP_ADMINDN LDAP_ADMIN_CRED
+ export NEED_ADMIN NEED_HOSTACL EXISTING_PROFILE
export LDAP_PROFILE_NAME LDAP_BASEDN LDAP_SERVER_LIST
export LDAP_AUTHMETHOD LDAP_FOLLOWREF LDAP_SEARCH_SCOPE LDAP_SEARCH_TIME_LIMIT
export LDAP_PREF_SRVLIST LDAP_PROFILE_TTL LDAP_CRED_LEVEL LDAP_BIND_LIMIT
@@ -1079,12 +1123,21 @@ disp_full_debug()
[ $DEBUG -eq 1 ] && ${ECHO} " LDAP_SEARCH_TIME_LIMIT = $LDAP_SEARCH_TIME_LIMIT"
[ $DEBUG -eq 1 ] && ${ECHO} " LDAP_PROFILE_TTL = $LDAP_PROFILE_TTL"
[ $DEBUG -eq 1 ] && ${ECHO} " LDAP_BIND_LIMIT = $LDAP_BIND_LIMIT"
+ [ $DEBUG -eq 1 ] && ${ECHO} " LDAP_ENABLE_SHADOW_UPDATE = $LDAP_ENABLE_SHADOW_UPDATE"
# Only display proxy stuff if needed.
+ [ $DEBUG -eq 1 ] && ${ECHO} " NEED_PROXY = $NEED_PROXY"
if [ $NEED_PROXY -eq 1 ]; then
[ $DEBUG -eq 1 ] && ${ECHO} " LDAP_PROXYAGENT = $LDAP_PROXYAGENT"
[ $DEBUG -eq 1 ] && ${ECHO} " LDAP_PROXYAGENT_CRED = $LDAP_PROXYAGENT_CRED"
- [ $DEBUG -eq 1 ] && ${ECHO} " NEED_PROXY = $NEED_PROXY"
+ fi
+
+ # Only display admin credential if needed.
+ [ $DEBUG -eq 1 ] && ${ECHO} " NEED_ADMIN = $NEED_ADMIN"
+ [ $DEBUG -eq 1 ] && ${ECHO} " NEED_HOSTACL = $NEED_HOSTACL"
+ if [ $NEED_ADMIN -eq 1 ]; then
+ [ $DEBUG -eq 1 ] && ${ECHO} " LDAP_ADMINDN = $LDAP_ADMINDN"
+ [ $DEBUG -eq 1 ] && ${ECHO} " LDAP_ADMIN_CRED = $LDAP_ADMIN_CRED"
fi
# Service Search Descriptors are a special case.
@@ -1351,6 +1404,20 @@ get_basedn()
done
}
+#
+# get_want_shadow_update(): Ask user if want to enable shadow update?
+#
+get_want_shadow_update()
+{
+ MSG="Do you want to enable shadow update (y/n/h)?"
+ get_confirm "$MSG" "n" "enable_shadow_update_help"
+ if [ $? -eq 1 ]; then
+ LDAP_ENABLE_SHADOW_UPDATE="TRUE"
+ else
+ LDAP_ENABLE_SHADOW_UPDATE="FALSE"
+ fi
+}
+
get_krb_realm() {
# To upper cases
@@ -1612,8 +1679,11 @@ EOF
#
gssapi_setup() {
+ # assume sasl/GSSAPI is supported by the ldap server and may be used
+ GSSAPI_AUTH_MAY_BE_USED=1
${EVAL} "${LDAPSEARCH} ${LDAP_ARGS} -b \"\" -s base \"objectclass=*\" supportedSASLMechanisms | ${GREP} GSSAPI ${VERB}"
if [ $? -ne 0 ]; then
+ GSSAPI_AUTH_MAY_BE_USED=0
${ECHO} " sasl/GSSAPI is not supported by this LDAP server"
return
fi
@@ -1622,7 +1692,7 @@ gssapi_setup() {
if [ $? -eq 0 ]; then
${ECHO}
${ECHO} "GSSAPI is not set up."
- ${ECHO} "sasl/GSSAPI bind may not workif it's not set up before."
+ ${ECHO} "sasl/GSSAPI bind may not work if it's not set up first."
else
get_krb_realm
add_id_mapping_rules
@@ -1647,6 +1717,7 @@ EOF
}
gssapi_setup_auto() {
+ GSSAPI_AUTH_MAY_BE_USED=0
${EVAL} "${LDAPSEARCH} ${LDAP_ARGS} -b \"\" -s base \"objectclass=*\" supportedSASLMechanisms | ${GREP} GSSAPI ${VERB}"
if [ $? -ne 0 ]; then
${ECHO}
@@ -1661,6 +1732,7 @@ gssapi_setup_auto() {
${ECHO}
return
fi
+ GSSAPI_AUTH_MAY_BE_USED=1
if [ -z "${LDAP_GSSAPI_PROFILE}" ]; then
${ECHO}
${ECHO} "LDAP_GSSAPI_PROFILE is not set. Default is gssapi_${LDAP_KRB_REALM}"
@@ -1694,7 +1766,30 @@ get_profile_name()
# Search to see if profile name already exists.
eval "${LDAPSEARCH} ${LDAP_ARGS} -b \"cn=${ANS},ou=profile,${LDAP_BASEDN}\" -s base \"objectclass=*\" ${VERB}"
if [ $? -eq 0 ]; then
- get_confirm_nodef "Are you sure you want to overwire profile cn=${ANS}?"
+
+ cat << EOF
+
+Profile '${ANS}' already exists, it is possible to enable
+shadow update now. idsconfig will exit after shadow update
+is enabled. You can also continue to overwrite the profile
+or create a new one and be given the chance to enable
+shadow update later.
+
+EOF
+
+ MSG="Just enable shadow update (y/n/h)?"
+ get_confirm "$MSG" "n" "enable_shadow_update_help"
+ if [ $? -eq 1 ]; then
+ [ $DEBUG -eq 1 ] && ${ECHO} "set up shadow update"
+ LDAP_ENABLE_SHADOW_UPDATE=TRUE
+ # display alternate messages
+ EXISTING_PROFILE=1
+ # Set Profile Name.
+ LDAP_PROFILE_NAME=$ANS
+ return 0 # set up credentials for shadow update.
+ fi
+
+ get_confirm_nodef "Are you sure you want to overwrite profile cn=${ANS}?"
if [ $? -eq 1 ]; then
DEL_OLD_PROFILE=1
return 0 # Replace old profile name.
@@ -2423,6 +2518,248 @@ ssd_2_profile()
GEN_CMD="${GEN_CMD} `cat ${GEN_TMPFILE}`"
}
+#
+# get_adminDN(): Get the admin DN.
+#
+get_adminDN()
+{
+ LDAP_ADMINDN="cn=admin,ou=profile,${LDAP_BASEDN}" # default
+ get_ans "Enter DN for the administrator:" "$LDAP_ADMINDN"
+ LDAP_ADMINDN=$ANS
+ [ $DEBUG -eq 1 ] && ${ECHO} "LDAP_ADMINDN = $LDAP_ADMINDN"
+}
+
+#
+# get_admin_pw(): Get the admin passwd.
+#
+get_admin_pw()
+{
+ get_passwd "Enter passwd for the administrator:"
+ LDAP_ADMIN_CRED=$ANS
+ [ $DEBUG -eq 1 ] && ${ECHO} "LDAP_ADMIN_CRED = $LDAP_ADMIN_CRED"
+}
+
+#
+# add_admin(): Add an admin entry for nameservice for updating shadow data.
+#
+add_admin()
+{
+ [ $DEBUG -eq 1 ] && ${ECHO} "In add_admin()"
+
+ # Check if the admin user already exists.
+ eval "${LDAPSEARCH} ${LDAP_ARGS} -b \"${LDAP_ADMINDN}\" -s base \"objectclass=*\" ${VERB}"
+ if [ $? -eq 0 ]; then
+ MSG="Administrator ${LDAP_ADMINDN} already exists."
+ if [ $EXISTING_PROFILE -eq 1 ]; then
+ ${ECHO} " NOT ADDED: $MSG"
+ else
+ ${ECHO} " ${STEP}. $MSG"
+ STEP=`expr $STEP + 1`
+ fi
+ return 0
+ fi
+
+ # Get cn and sn names from LDAP_ADMINDN.
+ cn_tmp=`${ECHO} ${LDAP_ADMINDN} | cut -f1 -d, | cut -f2 -d=`
+
+ # Create the tmp file to add.
+ ( cat <<EOF
+dn: ${LDAP_ADMINDN}
+cn: ${cn_tmp}
+sn: ${cn_tmp}
+objectclass: top
+objectclass: person
+userpassword: ${LDAP_ADMIN_CRED}
+EOF
+) > ${TMPDIR}/admin
+
+ # Add the entry.
+ ${EVAL} "${LDAPMODIFY} -a ${LDAP_ARGS} -f ${TMPDIR}/admin ${VERB}"
+ if [ $? -ne 0 ]; then
+ ${ECHO} " ERROR: Adding administrator identity failed!"
+ cleanup
+ exit 1
+ fi
+
+ ${RM} -f ${TMPDIR}/admin
+
+ # Display message that the administrator identity is added.
+ MSG="Administrator identity ${LDAP_ADMINDN}"
+ if [ $EXISTING_PROFILE -eq 1 ]; then
+ ${ECHO} " ADDED: $MSG."
+ else
+ ${ECHO} " ${STEP}. $MSG added."
+ STEP=`expr $STEP + 1`
+ fi
+}
+
+#
+# allow_admin_write_shadow(): Give Admin write permission for shadow data.
+#
+allow_admin_write_shadow()
+{
+ [ $DEBUG -eq 1 ] && ${ECHO} "In allow_admin_write_shadow()"
+
+ # Set ACI Name
+ ADMIN_ACI_NAME="LDAP_Naming_Services_admin_shadow_write"
+
+ # Search for ACI_NAME
+ eval "${LDAPSEARCH} ${LDAP_ARGS} -b \"${LDAP_BASEDN}\" \
+ -s base objectclass=* aci > ${TMPDIR}/chk_adminwrite_aci 2>&1"
+ ${GREP} "${ADMIN_ACI_NAME}" ${TMPDIR}/chk_adminwrite_aci > /dev/null 2>&1
+ if [ $? -eq 0 ]; then
+ MSG="Admin ACI ${ADMIN_ACI_NAME} already exists for ${LDAP_BASEDN}."
+ if [ $EXISTING_PROFILE -eq 1 ]; then
+ ${ECHO} " NOT SET: $MSG"
+ else
+ ${ECHO} " ${STEP}. $MSG"
+ STEP=`expr $STEP + 1`
+ fi
+ return 0
+ fi
+
+ # Create the tmp file to add.
+ ( cat <<EOF
+dn: ${LDAP_BASEDN}
+changetype: modify
+add: aci
+aci: (target="ldap:///${LDAP_BASEDN}")(targetattr="shadowLastChange||shadowMin||shadowMax||shadowWarning||shadowInactive||shadowExpire||shadowFlag||userPassword||loginShell||homeDirectory||gecos")(version 3.0; acl ${ADMIN_ACI_NAME}; allow (write) userdn = "ldap:///${LDAP_ADMINDN}";)
+EOF
+) > ${TMPDIR}/admin_write
+
+ # Add the entry.
+ ${EVAL} "${LDAPMODIFY} ${LDAP_ARGS} -f ${TMPDIR}/admin_write ${VERB}"
+ if [ $? -ne 0 ]; then
+ ${ECHO} " ERROR: Allow ${LDAP_ADMINDN} to write shadow data failed!"
+ cleanup
+ exit 1
+ fi
+
+ ${RM} -f ${TMPDIR}/admin_write
+ # Display message that the administrator ACL is set.
+ MSG="Give ${LDAP_ADMINDN} write permission for shadow."
+ if [ $EXISTING_PROFILE -eq 1 ]; then
+ ${ECHO} " ACI SET: $MSG"
+ else
+ ${ECHO} " ${STEP}. $MSG"
+ STEP=`expr $STEP + 1`
+ fi
+}
+
+#
+# allow_host_write_shadow(): Give host principal write permission
+# for shadow data.
+#
+allow_host_write_shadow()
+{
+ [ $DEBUG -eq 1 ] && ${ECHO} "In allow_host_write_shadow()"
+
+ # Set ACI Name
+ HOST_ACI_NAME="LDAP_Naming_Services_host_shadow_write"
+
+ # Search for ACI_NAME
+ eval "${LDAPSEARCH} ${LDAP_ARGS} -b \"${LDAP_BASEDN}\" -s base objectclass=* aci > ${TMPDIR}/chk_hostwrite_aci 2>&1"
+ ${GREP} "${HOST_ACI_NAME}" ${TMPDIR}/chk_hostwrite_aci > /dev/null 2>&1
+ if [ $? -eq 0 ]; then
+ MSG="Host ACI ${HOST_ACI_NAME} already exists for ${LDAP_BASEDN}."
+ if [ $EXISTING_PROFILE -eq 1 ]; then
+ ${ECHO} " NOT ADDED: $MSG"
+ else
+ ${ECHO} " ${STEP}. $MSG"
+ STEP=`expr $STEP + 1`
+ fi
+ return 0
+ fi
+
+ # Create the tmp file to add.
+ ( cat <<EOF
+dn: ${LDAP_BASEDN}
+changetype: modify
+add: aci
+aci: (target="ldap:///${LDAP_BASEDN}")(targetattr="shadowLastChange||shadowMin||shadowMax||shadowWarning||shadowInactive||shadowExpire||shadowFlag||userPassword||loginShell||homeDirectory||gecos")(version 3.0; acl ${HOST_ACI_NAME}; allow (read, write) authmethod="sasl GSSAPI" and userdn = "ldap:///cn=*+ipHostNumber=*,ou=Hosts,${LDAP_BASEDN}";)
+EOF
+) > ${TMPDIR}/host_write
+
+ # Add the entry.
+ ${EVAL} "${LDAPMODIFY} ${LDAP_ARGS} -f ${TMPDIR}/host_write ${VERB}"
+ if [ $? -ne 0 ]; then
+ ${ECHO} " ERROR: Allow Host Principal to write shadow data failed!"
+ cleanup
+ exit 1
+ fi
+
+ ${RM} -f ${TMPDIR}/host_write
+ MSG="Give host principal write permission for shadow."
+ if [ $EXISTING_PROFILE -eq 1 ]; then
+ ${ECHO} " ACI SET: $MSG"
+ else
+ ${ECHO} " ${STEP}. $MSG"
+ STEP=`expr $STEP + 1`
+ fi
+}
+
+#
+# Set up shadow update
+#
+setup_shadow_update() {
+ [ $DEBUG -eq 1 ] && ${ECHO} "In setup_shadow_update()"
+
+ # get content of the profile
+ PROFILE_OUT=${TMPDIR}/prof_tmpfile
+ ${EVAL} "${LDAPSEARCH} ${LDAP_ARGS} -b \"cn=${LDAP_PROFILE_NAME},ou=profile,${LDAP_BASEDN}\" -s base \"objectclass=*\" > $PROFILE_OUT 2>&1"
+ ${GREP} -i cn $PROFILE_OUT >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ $DEBUG -eq 1 ] && ${ECHO} "Profile ${LDAP_PROFILE_NAME} does not exist"
+ ${RM} ${PROFILE_OUT}
+ return
+ fi
+
+ # Search to see if authenticationMethod has 'GSSAPI' and
+ # credentialLevel has 'self'. If so, ask to use the
+ # host principal for shadow update
+ if [ $GSSAPI_AUTH_MAY_BE_USED -eq 1 ]; then
+ if ${GREP} authenticationMethod $PROFILE_OUT | ${GREP} GSSAPI >/dev/null 2>&1
+ then
+ if ${GREP} credentialLevel $PROFILE_OUT | ${GREP} self >/dev/null 2>&1
+ then
+ NEED_HOSTACL=1
+ fi
+ fi
+ ${RM} ${PROFILE_OUT}
+ [ $DEBUG -eq 1 ] && ${ECHO} "NEED_HOSTACL = $NEED_HOSTACL"
+
+ if [ $NEED_HOSTACL -eq 1 ]; then
+ MSG="Use host principal for shadow data update (y/n/h)?"
+ get_confirm "$MSG" "y" "use_host_principal_help"
+ if [ $? -eq 1 ]; then
+ allow_host_write_shadow
+ modify_top_aci
+ ${ECHO} ""
+ ${ECHO} " Shadow update has been enabled."
+ else
+ ${ECHO} ""
+ ${ECHO} " Shadow update may not work."
+ fi
+ return
+ fi
+ fi
+
+ MSG="Add the administrator identity (y/n/h)?"
+ get_confirm "$MSG" "y" "add_admin_cred_help"
+ if [ $? -eq 1 ]; then
+ get_adminDN
+ get_admin_pw
+ add_admin
+ allow_admin_write_shadow
+ modify_top_aci
+ ${ECHO} ""
+ ${ECHO} " Shadow update has been enabled."
+ return
+ fi
+
+ ${ECHO} " No administrator identity specified, shadow update may not work."
+}
+
#
# prompt_config_info(): This function prompts the user for the config
@@ -2459,6 +2796,12 @@ prompt_config_info()
gssapi_setup
get_profile_name
+
+ if [ "$LDAP_ENABLE_SHADOW_UPDATE" = "TRUE" ];then
+ setup_shadow_update
+ exit 0
+ fi
+
get_srv_list
get_pref_srv
get_search_scope
@@ -2509,6 +2852,9 @@ prompt_config_info()
get_prof_ttl
get_bind_limit
+ # Ask whether to enable shadow update
+ get_want_shadow_update
+
# Reset the sdd_file and prompt user for SSD. Will use menus
# to build an SSD File.
reset_ssd_file
@@ -2547,7 +2893,6 @@ get_proxy_pw()
LDAP_PROXYAGENT_CRED=$ANS
}
-
#
# display_summary(): Display a summary of values entered and let the
# user modify values at will.
@@ -2565,18 +2910,19 @@ display_summary()
TBL5="get_timelimit get_sizelimit get_want_crypt"
TBL6="get_srv_authMethod_pam get_srv_authMethod_key get_srv_authMethod_cmd"
TBL7="get_srch_time get_prof_ttl get_bind_limit"
- TBL8="prompt_ssd"
- FUNC_TBL="$TBL1 $TBL2 $TBL3 $TBL4 $TBL5 $TBL6 $TBL7 $TBL8"
+ TBL8="get_want_shadow_update"
+ TBL9="prompt_ssd"
+ FUNC_TBL="$TBL1 $TBL2 $TBL3 $TBL4 $TBL5 $TBL6 $TBL7 $TBL8 $TBL9"
# Since menu prompt string is long, set here.
- _MENU_PROMPT="Enter config value to change: (1-19 0=commit changes)"
+ _MENU_PROMPT="Enter config value to change: (1-20 0=commit changes)"
# Infinite loop. Test for 0, and break in loop.
while :
do
# Display menu and get value in range.
display_msg summary_menu
- get_menu_choice "${_MENU_PROMPT}" "0" "19" "0"
+ get_menu_choice "${_MENU_PROMPT}" "0" "20" "0"
_CH=$MN_CH
# Make sure where not exiting.
@@ -2604,6 +2950,23 @@ display_summary()
fi
fi
+ # If shadow update is enabled, set up administrator credential
+ if [ "$LDAP_ENABLE_SHADOW_UPDATE" = "TRUE" ]; then
+ NEED_ADMIN=1
+ if ${ECHO} "$LDAP_CRED_LEVEL" | ${GREP} "self" > /dev/null 2>&1; then
+ if ${ECHO} "$LDAP_AUTHMETHOD" | ${GREP} "GSSAPI" > /dev/null 2>&1; then
+ NEED_HOSTACL=1
+ NEED_ADMIN=0
+ fi
+ fi
+ [ $DEBUG -eq 1 ] && ${ECHO} "NEED_HOSTACL = $NEED_HOSTACL"
+ [ $DEBUG -eq 1 ] && ${ECHO} "NEED_ADMIN = $NEED_ADMIN"
+ if [ $NEED_ADMIN -eq 1 ]; then
+ get_adminDN
+ get_admin_pw
+ fi
+ fi
+
# Display FULL debugging info.
disp_full_debug
@@ -2656,6 +3019,9 @@ NEED_PROXY=$NEED_PROXY
NEED_TIME=$NEED_TIME
NEED_SIZE=$NEED_SIZE
NEED_CRYPT=$NEED_CRYPT
+NEED_ADMIN=$NEED_ADMIN
+NEED_HOSTACL=$NEED_HOSTACL
+EXISTING_PROFILE=$EXISTING_PROFILE
# LDAP PROFILE related defaults
LDAP_PROFILE_NAME="$LDAP_PROFILE_NAME"
@@ -2681,10 +3047,17 @@ LDAP_BIND_LIMIT=$LDAP_BIND_LIMIT
LDAP_PROXYAGENT="$LDAP_PROXYAGENT"
LDAP_PROXYAGENT_CRED=$LDAP_PROXYAGENT_CRED
+# enableShadowUpdate flag and Administrator credential
+LDAP_ENABLE_SHADOW_UPDATE=$LDAP_ENABLE_SHADOW_UPDATE
+LDAP_ADMINDN="$LDAP_ADMINDN"
+LDAP_ADMIN_CRED=$LDAP_ADMIN_CRED
+
# Export all the variables (just in case)
export IDS_HOME IDS_PORT LDAP_ROOTDN LDAP_ROOTPWD LDAP_SERVER_LIST LDAP_BASEDN
export LDAP_DOMAIN LDAP_SUFFIX LDAP_PROXYAGENT LDAP_PROXYAGENT_CRED
export NEED_PROXY
+export LDAP_ENABLE_SHADOW_UPDATE LDAP_ADMINDN LDAP_ADMIN_CRED
+export NEED_ADMIN NEED_HOSTACL EXISTING_PROFILE
export LDAP_PROFILE_NAME LDAP_BASEDN LDAP_SERVER_LIST
export LDAP_AUTHMETHOD LDAP_FOLLOWREF LDAP_SEARCH_SCOPE LDAP_SEARCH_TIME_LIMIT
export LDAP_PREF_SRVLIST LDAP_PROFILE_TTL LDAP_CRED_LEVEL LDAP_BIND_LIMIT
@@ -4113,11 +4486,38 @@ modify_top_aci()
cleanup
exit 1
fi
+
+ # Display "already exists" message if necessary. For shadow update,
+ # check also if the deny self-write to userPassword has been done.
+ # If not, more to do, don't display the message.
+ MSG="Top level ACI ${ACI_NAME} already exists for ${LDAP_BASEDN}."
${GREP} "${ACI_NAME}" ${TMPDIR}/chk_top_aci > /dev/null 2>&1
if [ $? -eq 0 ]; then
- ${ECHO} " ${STEP}. Top level ACI ${ACI_NAME} already exists for ${LDAP_BASEDN}."
- STEP=`expr $STEP + 1`
- return 0
+ if [ "$LDAP_ENABLE_SHADOW_UPDATE" != "TRUE" ];then
+ ${ECHO} " ${STEP}. $MSG"
+ STEP=`expr $STEP + 1`
+ return 0
+ else
+ ${GREP} "${ACI_NAME}" ${TMPDIR}/chk_top_aci | ${GREP} -i \
+ userPassword > /dev/null 2>&1
+ if [ $? -eq 0 ]; then
+ # userPassword is already on the deny list, no more to do
+ if [ $EXISTING_PROFILE -eq 1 ];then
+ ${ECHO} " NOT SET: $MSG"
+ else
+ ${ECHO} " ${STEP}. $MSG"
+ STEP=`expr $STEP + 1`
+ fi
+ return 0
+ fi
+ fi
+ fi
+
+ # if shadow update is enabled, also deny self-write to userPassword
+ if [ "$LDAP_ENABLE_SHADOW_UPDATE" = "TRUE" ];then
+ PWD_SELF_CHANGE="userPassword||"
+ else
+ PWD_SELF_CHANGE=""
fi
# Crate LDIF for top level ACI.
@@ -4125,7 +4525,7 @@ modify_top_aci()
dn: ${LDAP_BASEDN}
changetype: modify
add: aci
-aci: (targetattr = "cn||uid||uidNumber||gidNumber||homeDirectory||shadowLastChange||shadowMin||shadowMax||shadowWarning||shadowInactive||shadowExpire||shadowFlag||memberUid||SolarisAuditAlways||SolarisAuditNever||SolarisAttrKeyValue||SolarisAttrReserved1||SolarisAttrReserved2||SolarisUserQualifier")(version 3.0; acl ${ACI_NAME}; deny (write) userdn = "ldap:///self";)
+aci: (targetattr = "${PWD_SELF_CHANGE}cn||uid||uidNumber||gidNumber||homeDirectory||shadowLastChange||shadowMin||shadowMax||shadowWarning||shadowInactive||shadowExpire||shadowFlag||memberUid||SolarisAuditAlways||SolarisAuditNever||SolarisAttrKeyValue||SolarisAttrReserved1||SolarisAttrReserved2||SolarisUserQualifier")(version 3.0; acl ${ACI_NAME}; deny (write) userdn = "ldap:///self";)
-
EOF
) > ${TMPDIR}/top_aci
@@ -4139,11 +4539,15 @@ EOF
fi
# Display message that schema is updated.
- ${ECHO} " ${STEP}. ACI for ${LDAP_BASEDN} modified to disable self modify."
- STEP=`expr $STEP + 1`
+ MSG="ACI for ${LDAP_BASEDN} modified to disable self modify."
+ if [ $EXISTING_PROFILE -eq 1 ];then
+ ${ECHO} " ACI SET: $MSG"
+ else
+ ${ECHO} " ${STEP}. $MSG"
+ STEP=`expr $STEP + 1`
+ fi
}
-
#
# add_vlv_aci(): Add access control information (aci) for VLV.
#
@@ -4516,7 +4920,6 @@ EOF
STEP=`expr $STEP + 1`
}
-
#
# allow_proxy_read_pw(): Give Proxy Agent read permission for password.
#
@@ -4558,7 +4961,6 @@ EOF
STEP=`expr $STEP + 1`
}
-
#
# add_profile(): Add client profile to server.
#
@@ -4757,6 +5159,18 @@ if [ $NEED_PROXY -eq 1 ]; then
allow_proxy_read_pw
fi
+# If admin needed for shadow update, Add the administrator identity and
+# give write permission for shadow.
+if [ $NEED_ADMIN -eq 1 ]; then
+ add_admin
+ allow_admin_write_shadow
+fi
+
+# if use host principal for shadow update, give write permission for shadow.
+if [ $NEED_HOSTACL -eq 1 ]; then
+ allow_host_write_shadow
+fi
+
# Generate client profile and add it to the server.
add_profile
diff --git a/usr/src/cmd/ldap/ns_ldap/ldapaddent.c b/usr/src/cmd/ldap/ns_ldap/ldapaddent.c
index 99ea7d5f51..ac077dcf01 100644
--- a/usr/src/cmd/ldap/ns_ldap/ldapaddent.c
+++ b/usr/src/cmd/ldap/ns_ldap/ldapaddent.c
@@ -19,7 +19,7 @@
* 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.
*/
@@ -3119,7 +3119,6 @@ static void
dump_passwd(ns_ldap_result_t *res)
{
char **value = NULL;
- char pnam[256];
value = __ns_ldap_getAttr(res->entry, "uid");
if (value == NULL)
@@ -3127,15 +3126,13 @@ dump_passwd(ns_ldap_result_t *res)
else
(void) fprintf(stdout, "%s:", value[0]);
value = __ns_ldap_getAttr(res->entry, "userPassword");
- if (value == NULL)
- (void) fprintf(stdout, "*:");
- else {
- (void) strcpy(pnam, value[0]);
- if (strncasecmp(value[0], "{crypt}", 7) == 0)
- (void) fprintf(stdout, "%s:", (pnam+7));
- else
- (void) fprintf(stdout, "*:");
- }
+
+ /*
+ * Don't print the encrypted password, Use x to
+ * indicate it is in the shadow database.
+ */
+ (void) fprintf(stdout, "x:");
+
value = __ns_ldap_getAttr(res->entry, "uidNumber");
if (value && value[0])
(void) fprintf(stdout, "%s:", value[0]);
@@ -3315,8 +3312,16 @@ genent_shadow(char *line, int (*cback)())
(void) snprintf(pname, sizeof (pname), "{crypt}%s",
ecol[1].ec_value.ec_value_val);
data.sp_pwdp = strdup(pname);
- } else
- data.sp_pwdp = NULL;
+ } else {
+ /*
+ * no password (e.g., deleted by "passwd -d"):
+ * use the special value NS_LDAP_NO_UNIX_PASSWORD
+ * instead.
+ */
+ (void) snprintf(pname, sizeof (pname), "{crypt}%s",
+ NS_LDAP_NO_UNIX_PASSWORD);
+ data.sp_pwdp = strdup(pname);
+ }
if (ecol[2].ec_value.ec_value_val != NULL &&
ecol[2].ec_value.ec_value_val[0] != '\0') {
@@ -3450,9 +3455,12 @@ dump_shadow(ns_ldap_result_t *res)
(void) fprintf(stdout, "*:");
else {
(void) strcpy(pnam, value[0]);
- if (strncasecmp(value[0], "{crypt}", 7) == 0)
- (void) fprintf(stdout, "%s:", (pnam+7));
- else
+ if (strncasecmp(value[0], "{crypt}", 7) == 0) {
+ if (strcmp(pnam + 7, NS_LDAP_NO_UNIX_PASSWORD) == 0)
+ (void) fprintf(stdout, ":");
+ else
+ (void) fprintf(stdout, "%s:", (pnam+7));
+ } else
(void) fprintf(stdout, "*:");
}
value = __ns_ldap_getAttr(res->entry, "shadowLastChange");
@@ -3471,11 +3479,30 @@ dump_shadow(ns_ldap_result_t *res)
else
(void) fprintf(stdout, "%s:", value[0]);
- /* ignore shadowWarning, shadowInactive, shadowExpire, shadowFlag */
- (void) fprintf(stdout, ":::\n");
+ value = __ns_ldap_getAttr(res->entry, "shadowWarning");
+ if (value == NULL)
+ (void) fprintf(stdout, ":");
+ else
+ (void) fprintf(stdout, "%s:", value[0]);
-}
+ value = __ns_ldap_getAttr(res->entry, "shadowInactive");
+ if (value == NULL)
+ (void) fprintf(stdout, ":");
+ else
+ (void) fprintf(stdout, "%s:", value[0]);
+
+ value = __ns_ldap_getAttr(res->entry, "shadowExpire");
+ if (value == NULL)
+ (void) fprintf(stdout, ":");
+ else
+ (void) fprintf(stdout, "%s:", value[0]);
+ value = __ns_ldap_getAttr(res->entry, "shadowFlag");
+ if (value == NULL || value[0] == NULL || strcmp(value[0], "0") == 0)
+ (void) fprintf(stdout, "\n");
+ else
+ (void) fprintf(stdout, "%s\n", value[0]);
+}
static int
genent_bootparams(char *line, int (*cback)())
diff --git a/usr/src/cmd/ldap/ns_ldap/ldapclient.c b/usr/src/cmd/ldap/ns_ldap/ldapclient.c
index a47c757a5a..a1716ff685 100644
--- a/usr/src/cmd/ldap/ns_ldap/ldapclient.c
+++ b/usr/src/cmd/ldap/ns_ldap/ldapclient.c
@@ -19,12 +19,10 @@
* 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.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
/*
* ldapclient command. To make (initiailize) or uninitialize a machines as
* and LDAP client. This command MUST be run as root (or it will simply exit).
@@ -87,6 +85,12 @@
* proxyPassword
* Client password not needed for authentication "none".
* (formerly -w)
+ * adminDN
+ * Administrator DN for updating naming data.
+ * adminPassword
+ * Administrator password
+ * enableShadowUpdate
+ * Allow Administrator to change shadow data in LDAP
* searchTimeLimit
* Timeout value. (formerly -o)
* serviceSearchDescriptor
@@ -274,6 +278,9 @@ typedef struct {
char *profileTTL;
char *proxyDN;
char *proxyPassword;
+ char *enableShadowUpdate;
+ char *adminDN;
+ char *adminPassword;
char *bindDN;
char *bindPasswd;
char *defaultSearchScope;
@@ -294,6 +301,7 @@ extern int __ns_ldap_download(const char *, char *, char *, ns_ldap_error_t **);
static void usage(void);
static int credCheck(clientopts_t *arglist);
+static int adminCredCheck(clientopts_t *arglist);
static int clientSetParam(clientopts_t *optlist, int paramFlag, char *attrVal);
static int parseParam(char *param, char **paramVal);
static void dumpargs(clientopts_t *arglist);
@@ -369,7 +377,7 @@ main(int argc, char **argv)
optind = 1;
while (optind < argc) {
- option = getopt(argc, argv, "vqa:ID:w:j:y:");
+ option = getopt(argc, argv, "vqa:ID:w:j:y:z:");
switch (option) {
case 'v':
@@ -397,6 +405,14 @@ main(int argc, char **argv)
"-a proxyPassword is ignored.\n"));
break;
}
+ if (paramFlag == NS_LDAP_ADMIN_BINDPASSWD_P &&
+ optlist->adminPassword != NULL) {
+ (void) fprintf(stderr,
+ gettext("The -a adminPassword option is "
+ "mutually exclusive of -z. "
+ "-a adminPassword is ignored.\n"));
+ break;
+ }
retcode = clientSetParam(optlist, paramFlag, attrVal);
if (retcode != CLIENT_SUCCESS) {
CLIENT_FPRINTF(
@@ -444,13 +460,24 @@ main(int argc, char **argv)
gettext("The -a proxyPassword option is "
"mutually exclusive of -y. "
"-a proxyPassword is ignored.\n"));
- free(optlist->proxyPassword);
}
optlist->proxyPassword = readPwd(optarg);
if (optlist->proxyPassword == NULL) {
exit(CLIENT_ERR_FAIL);
}
break;
+ case 'z':
+ if (optlist->adminPassword != NULL) {
+ (void) fprintf(stderr,
+ gettext("The -a adminPassword option is "
+ "mutually exclusive of -z. "
+ "-a adminPassword is ignored.\n"));
+ }
+ optlist->adminPassword = readPwd(optarg);
+ if (optlist->adminPassword == NULL) {
+ exit(CLIENT_ERR_FAIL);
+ }
+ break;
case EOF:
if (strcmp(argv[optind], "init") == 0) {
op_init = 1;
@@ -530,6 +557,23 @@ main(int argc, char **argv)
exit(CLIENT_ERR_FAIL);
}
+/*
+ * if init or manual, and if adminDN is specified then enableShadowUpdate
+ * must be set to TRUE.
+ */
+ if ((op_init || op_manual) &&
+ (!optlist->enableShadowUpdate ||
+ strcasecmp(optlist->enableShadowUpdate, "TRUE") != 0) &&
+ (optlist->adminDN || optlist->adminPassword)) {
+ CLIENT_FPUTS(
+ gettext("ldapclient: adminDN and adminPassword must not "
+ "be specified if enableShadowUpdate is not set to TRUE \n"),
+ stderr);
+ usage();
+ clientopts_free(optlist);
+ exit(CLIENT_ERR_FAIL);
+ }
+
/* Only one verb can be specified */
if ((op_init + op_manual + op_mod + op_uninit +
op_list + op_genprofile) != 1) {
@@ -807,6 +851,9 @@ client_manual(clientopts_t *arglist)
LDAP_SET_PARAM(arglist->defaultSearchBase, NS_LDAP_SEARCH_BASEDN_P);
LDAP_SET_PARAM(arglist->credentialLevel, NS_LDAP_CREDENTIAL_LEVEL_P);
LDAP_SET_PARAM(arglist->proxyDN, NS_LDAP_BINDDN_P);
+ LDAP_SET_PARAM(arglist->enableShadowUpdate,
+ NS_LDAP_ENABLE_SHADOW_UPDATE_P);
+ LDAP_SET_PARAM(arglist->adminDN, NS_LDAP_ADMIN_BINDDN_P);
LDAP_SET_PARAM(arglist->searchTimeLimit, NS_LDAP_SEARCH_TIME_P);
LDAP_SET_PARAM(arglist->preferredServerList, NS_LDAP_SERVER_PREF_P);
LDAP_SET_PARAM(arglist->profileName, NS_LDAP_PROFILE_P);
@@ -814,6 +861,7 @@ client_manual(clientopts_t *arglist)
LDAP_SET_PARAM(arglist->defaultSearchScope, NS_LDAP_SEARCH_SCOPE_P);
LDAP_SET_PARAM(arglist->bindTimeLimit, NS_LDAP_BIND_TIME_P);
LDAP_SET_PARAM(arglist->proxyPassword, NS_LDAP_BINDPASSWD_P);
+ LDAP_SET_PARAM(arglist->adminPassword, NS_LDAP_ADMIN_BINDPASSWD_P);
LDAP_SET_PARAM(arglist->defaultServerList, NS_LDAP_SERVERS_P);
LDAP_SET_PARAM(arglist->certificatePath, NS_LDAP_HOST_CERTPATH_P);
@@ -854,6 +902,8 @@ client_manual(clientopts_t *arglist)
}
retcode = credCheck(arglist);
+ if (retcode == CLIENT_SUCCESS)
+ retcode = adminCredCheck(arglist);
if (retcode != CLIENT_SUCCESS) {
CLIENT_FPUTS(
gettext("Error in setting up credentials\n"),
@@ -1091,6 +1141,7 @@ client_mod(clientopts_t *arglist)
LDAP_SET_PARAM(arglist->defaultSearchBase, NS_LDAP_SEARCH_BASEDN_P);
LDAP_SET_PARAM(arglist->credentialLevel, NS_LDAP_CREDENTIAL_LEVEL_P);
LDAP_SET_PARAM(arglist->proxyDN, NS_LDAP_BINDDN_P);
+ LDAP_SET_PARAM(arglist->adminDN, NS_LDAP_ADMIN_BINDDN_P);
LDAP_SET_PARAM(arglist->profileTTL, NS_LDAP_CACHETTL_P);
LDAP_SET_PARAM(arglist->searchTimeLimit, NS_LDAP_SEARCH_TIME_P);
LDAP_SET_PARAM(arglist->preferredServerList, NS_LDAP_SERVER_PREF_P);
@@ -1099,7 +1150,10 @@ client_mod(clientopts_t *arglist)
LDAP_SET_PARAM(arglist->defaultSearchScope, NS_LDAP_SEARCH_SCOPE_P);
LDAP_SET_PARAM(arglist->bindTimeLimit, NS_LDAP_BIND_TIME_P);
LDAP_SET_PARAM(arglist->proxyPassword, NS_LDAP_BINDPASSWD_P);
+ LDAP_SET_PARAM(arglist->adminPassword, NS_LDAP_ADMIN_BINDPASSWD_P);
LDAP_SET_PARAM(arglist->defaultServerList, NS_LDAP_SERVERS_P);
+ LDAP_SET_PARAM(arglist->enableShadowUpdate,
+ NS_LDAP_ENABLE_SHADOW_UPDATE_P);
LDAP_SET_PARAM(arglist->certificatePath, NS_LDAP_HOST_CERTPATH_P);
for (counter = 0;
@@ -1144,6 +1198,8 @@ client_mod(clientopts_t *arglist)
}
retcode = credCheck(arglist);
+ if (retcode == CLIENT_SUCCESS)
+ retcode = adminCredCheck(arglist);
if (retcode != CLIENT_SUCCESS) {
CLIENT_FPUTS(
gettext("Error in setting up credentials\n"),
@@ -1300,6 +1356,10 @@ client_genProfile(clientopts_t *arglist)
/* *** Check for invalid args *** */
LDAP_CHECK_INVALID(arglist->proxyDN, "proxyDN");
LDAP_CHECK_INVALID(arglist->proxyPassword, "proxyPassword");
+ LDAP_CHECK_INVALID(arglist->enableShadowUpdate,
+ "enableShadowUpdate");
+ LDAP_CHECK_INVALID(arglist->adminDN, "adminDN");
+ LDAP_CHECK_INVALID(arglist->adminPassword, "adminPassword");
LDAP_CHECK_INVALID(arglist->certificatePath, "certificatePath");
LDAP_CHECK_INVALID(arglist->domainName, "domainName");
LDAP_CHECK_INVALID(arglist->bindDN, "bind DN");
@@ -1472,7 +1532,7 @@ client_init(clientopts_t *arglist)
cfg.SA_CRED = "proxy";
/*
* We don't want to force users to always specify authentication
- * method when we can infer it. If users wants SSL, he/she would
+ * method when we can infer it. If users want SSL, he/she would
* have to specify appropriate -a though.
*/
auth.type = NS_LDAP_AUTH_SIMPLE;
@@ -1558,6 +1618,43 @@ client_init(clientopts_t *arglist)
}
}
+ if (arglist->enableShadowUpdate != NULL) {
+ LDAP_SET_PARAM(arglist->enableShadowUpdate,
+ NS_LDAP_ENABLE_SHADOW_UPDATE_P);
+ }
+
+ if (arglist->enableShadowUpdate &&
+ strcasecmp(arglist->enableShadowUpdate, "TRUE") == 0 &&
+ arglist->adminDN != NULL && arglist->adminPassword == NULL) {
+ arglist->adminPassword = getpassphrase("admin Bind Password:");
+ if (arglist->adminPassword == NULL) {
+ CLIENT_FPUTS(gettext("Get password failed\n"), stderr);
+
+ if (gStartLdap == START_RESET)
+ (void) start_service(LDAP_FMRI, B_TRUE);
+
+ return (CLIENT_ERR_CREDENTIAL);
+ }
+ }
+ if (arglist->adminDN != NULL && arglist->adminPassword != NULL) {
+ if (__ns_ldap_setParam(NS_LDAP_ADMIN_BINDDN_P,
+ arglist->adminDN, &errorp) != NS_LDAP_SUCCESS) {
+ if (errorp != NULL) {
+ CLIENT_FPRINTF(stderr, "%s\n", errorp->message);
+ (void) __ns_ldap_freeError(&errorp);
+ }
+ return (CLIENT_ERR_CREDENTIAL);
+ }
+ if (__ns_ldap_setParam(NS_LDAP_ADMIN_BINDPASSWD_P,
+ arglist->adminPassword, &errorp) != NS_LDAP_SUCCESS) {
+ if (errorp != NULL) {
+ CLIENT_FPRINTF(stderr, "%s\n", errorp->message);
+ (void) __ns_ldap_freeError(&errorp);
+ }
+ return (CLIENT_ERR_CREDENTIAL);
+ }
+ }
+
if (arglist->authenticationMethod != NULL) {
if (__ns_ldap_getParam(NS_LDAP_AUTH_P,
(void ***)&authMethod, &errorp) != NS_LDAP_SUCCESS) {
@@ -1641,6 +1738,8 @@ client_init(clientopts_t *arglist)
}
retcode = credCheck(arglist);
+ if (retcode == CLIENT_SUCCESS)
+ retcode = adminCredCheck(arglist);
if (retcode != CLIENT_SUCCESS) {
CLIENT_FPUTS(
gettext("Error in setting up credentials\n"), stderr);
@@ -1850,7 +1949,8 @@ usage(void)
CLIENT_FPRINTF(stderr,
gettext("\n %s [-v | -q] [-a authenticationMethod]"
" [-D bindDN]\n\t[-w bindPassword] [-j passswdFile]"
- " [-y proxyPasswordFile] init [<args>]\n"),
+ " [-y proxyPasswordFile]\n\t"
+ "[-z adminPasswordFile] init [<args>]\n"),
cmd);
CLIENT_FPUTS(
@@ -2319,6 +2419,189 @@ credCheck(clientopts_t *arglist)
}
/*
+ * adminCredCheck is called to check if the admin credential is required
+ * for this configuration. This means that if enableShadowUpdate is set
+ * to TRUE then credential info is required (adminDN and adminPassword).
+ * One exception is that if there is a 'self' credentialLevel and
+ * 'sasl/GSSAPI' authenticationMethod (i.e., possibly using Kerberos
+ * host credential) then adminDN and adminPassword are not required.
+ */
+static int
+adminCredCheck(clientopts_t *arglist)
+{
+ int counter;
+ int **enabled = NULL;
+ int **credLevel = NULL;
+ char **adminDN = NULL;
+ char **adminPassword = NULL;
+ ns_auth_t **authMethod = NULL;
+ ns_ldap_error_t *errorp = NULL;
+ int credSelf, authSASLgss;
+ int retcode, rc;
+
+ /* If shadow update not enabled, then no need to check */
+ retcode = __ns_ldap_getParam(NS_LDAP_ENABLE_SHADOW_UPDATE_P,
+ (void ***)&enabled, &errorp);
+ if (retcode != 0) {
+ CLIENT_FPRINTF(stderr,
+ gettext("Error %d while trying to retrieve "
+ "enableShadowUpdate\n"), retcode);
+ rc = CLIENT_ERR_FAIL;
+ goto out;
+ }
+ if (enabled == NULL ||
+ *enabled[0] != NS_LDAP_ENABLE_SHADOW_UPDATE_TRUE) {
+ if (mode_verbose)
+ CLIENT_FPUTS(
+ gettext("Shadow Update is not enabled, "
+ "no adminDN/adminPassword is required.\n"), stderr);
+ rc = CLIENT_SUCCESS;
+ goto out;
+ }
+
+ /* get credentialLevel */
+ retcode = __ns_ldap_getParam(NS_LDAP_CREDENTIAL_LEVEL_P,
+ (void ***)&credLevel, &errorp);
+ if (retcode != 0) {
+ CLIENT_FPRINTF(stderr,
+ gettext("Error %d while trying to retrieve credLevel\n"),
+ retcode);
+ rc = CLIENT_ERR_FAIL;
+ goto out;
+ }
+
+ /* get AuthenticationMethod */
+ retcode = __ns_ldap_getParam(NS_LDAP_AUTH_P,
+ (void ***)&authMethod, &errorp);
+ if (retcode != 0) {
+ CLIENT_FPRINTF(stderr,
+ gettext("Error %d while trying to retrieve authMethod\n"),
+ retcode);
+ rc = CLIENT_ERR_FAIL;
+ goto out;
+ }
+
+ /* get adminDN */
+ retcode = __ns_ldap_getParam(NS_LDAP_ADMIN_BINDDN_P,
+ (void ***)&adminDN, &errorp);
+ if (retcode != 0) {
+ CLIENT_FPRINTF(stderr,
+ gettext("Error %d while trying to retrieve adminDN\n"),
+ retcode);
+ rc = CLIENT_ERR_FAIL;
+ goto out;
+ }
+
+ /* get adminPassword */
+ retcode = __ns_ldap_getParam(NS_LDAP_ADMIN_BINDPASSWD_P,
+ (void ***)&adminPassword, &errorp);
+ if (retcode != 0) {
+ CLIENT_FPRINTF(stderr,
+ gettext("Error %d while trying to retrieve "
+ "adminPassword\n"), retcode);
+ rc = CLIENT_ERR_FAIL;
+ goto out;
+ }
+
+ if (mode_verbose) {
+ CLIENT_FPRINTF(stderr,
+ gettext("admin DN: %s\n"),
+ (adminDN && adminDN[0]) ? adminDN[0] : "NULL");
+ CLIENT_FPRINTF(stderr,
+ gettext("admin password: %s\n"),
+ (adminPassword && adminPassword[0]) ?
+ adminPassword[0] : "NULL");
+ }
+
+ credSelf = 0; /* flag to indicate if we have a credLevel of self */
+ for (counter = 0; credLevel && credLevel[counter] != NULL; counter++) {
+ if (mode_verbose)
+ CLIENT_FPRINTF(stderr,
+ gettext("Credential level: %d\n"),
+ *credLevel[counter]);
+ if (*credLevel[counter] == NS_LDAP_CRED_SELF) {
+ credSelf = 1;
+ break;
+ }
+ }
+
+ authSASLgss = 0; /* flag for authMethod of SASL/gssapi */
+ for (counter = 0;
+ authMethod && authMethod[counter] != NULL;
+ counter++) {
+
+ if (mode_verbose)
+ CLIENT_FPRINTF(stderr,
+ gettext("Authentication sasl mechanism: %d\n"),
+ authMethod[counter]->saslmech);
+ if (authMethod[counter]->saslmech == NS_LDAP_SASL_GSSAPI) {
+ authSASLgss = 1;
+ break;
+ }
+ }
+
+ /* First, if we don't need adminDN/adminPassword then just return ok */
+ if (credSelf && authSASLgss) {
+ if (mode_verbose)
+ CLIENT_FPUTS(
+ gettext("A credential Level of self and an "
+ "authentication method of sasl/GSSAPI is "
+ "configured, no adminDN/adminPassword "
+ "is required.\n"), stderr);
+ rc = CLIENT_SUCCESS;
+ goto out;
+ }
+
+ /* Now let's check if we have the cred stuff we need */
+ if (adminDN == NULL || adminDN[0] == '\0') {
+ CLIENT_FPUTS(
+ gettext("Shadow Update is enabled, but "
+ "no adminDN is configured.\n"), stderr);
+ rc = CLIENT_ERR_CREDENTIAL;
+ goto out;
+ }
+
+ /* If we need adminPassword (prompt) */
+ if (adminPassword == NULL || adminPassword[0] == '\0') {
+ CLIENT_FPUTS(
+ gettext("Shadow Update requires adminPassword\n"),
+ stderr);
+ arglist->adminPassword = getpassphrase("admin Password:");
+ if (arglist->adminPassword == NULL) {
+ CLIENT_FPUTS(gettext("Unable to get admin password\n"),
+ stderr);
+ rc = CLIENT_ERR_CREDENTIAL;
+ goto out;
+ }
+ LDAP_SET_PARAM(arglist->adminPassword,
+ NS_LDAP_ADMIN_BINDPASSWD_P);
+ if (retcode != 0) {
+ CLIENT_FPUTS(
+ gettext("setParam adminPassword failed.\n"),
+ stderr);
+ rc = CLIENT_ERR_CREDENTIAL;
+ goto out;
+ }
+ }
+
+ rc = CLIENT_SUCCESS;
+
+ out:
+ if (enabled != NULL)
+ (void) __ns_ldap_freeParam((void ***)&enabled);
+ if (credLevel != NULL)
+ (void) __ns_ldap_freeParam((void ***)&credLevel);
+ if (authMethod != NULL)
+ (void) __ns_ldap_freeParam((void ***)&authMethod);
+ if (adminDN != NULL)
+ (void) __ns_ldap_freeParam((void ***)&adminDN);
+ if (adminPassword != NULL)
+ (void) __ns_ldap_freeParam((void ***)&adminPassword);
+
+ return (rc);
+}
+
+/*
* try to restore the previous name space on this machine
*/
static int
@@ -3043,6 +3326,8 @@ num_args(clientopts_t *list)
arg_count += list->serviceCredentialLevel->count;
arg_count += list->domainName ? 1 : 0;
arg_count += list->proxyDN ? 1 : 0;
+ arg_count += list->enableShadowUpdate ? 1 : 0;
+ arg_count += list->adminDN ? 1 : 0;
arg_count += list->profileTTL ? 1 : 0;
arg_count += list->objectclassMap->count;
arg_count += list->searchTimeLimit ? 1 : 0;
@@ -3054,6 +3339,7 @@ num_args(clientopts_t *list)
arg_count += list->serviceSearchDescriptor->count;
arg_count += list->bindTimeLimit ? 1 : 0;
arg_count += list->proxyPassword ? 1 : 0;
+ arg_count += list->adminPassword ? 1 : 0;
arg_count += list->defaultServerList ? 1 : 0;
arg_count += list->certificatePath ? 1 : 0;
@@ -3075,6 +3361,8 @@ dumpargs(clientopts_t *list)
list->serviceCredentialLevel);
CLIENT_PRINT("\tdomainName: ", list->domainName);
CLIENT_PRINT("\tproxyDN: ", list->proxyDN);
+ CLIENT_PRINT("\tadminDN: ", list->adminDN);
+ CLIENT_PRINT("\tenableShadowUpdate: ", list->enableShadowUpdate);
CLIENT_PRINT("\tprofileTTL: ", list->profileTTL);
multival_list("\tobjectclassMap: ", list->objectclassMap);
CLIENT_PRINT("\tsearchTimeLimit: ", list->searchTimeLimit);
@@ -3087,6 +3375,7 @@ dumpargs(clientopts_t *list)
list->serviceSearchDescriptor);
CLIENT_PRINT("\tbindTimeLimit: ", list->bindTimeLimit);
CLIENT_PRINT("\tproxyPassword: ", list->proxyPassword);
+ CLIENT_PRINT("\tadminPassword: ", list->adminPassword);
CLIENT_PRINT("\tdefaultServerList: ", list->defaultServerList);
CLIENT_PRINT("\tcertificatePath: ", list->certificatePath);
}
@@ -3119,6 +3408,9 @@ static struct param paramArray[] = {
{"serviceAuthenticationMethod", NS_LDAP_SERVICE_AUTH_METHOD_P},
{"serviceCredentialLevel", NS_LDAP_SERVICE_CRED_LEVEL_P},
{"domainName", LOCAL_DOMAIN_P},
+ {"enableShadowUpdate", NS_LDAP_ENABLE_SHADOW_UPDATE_P},
+ {"adminDN", NS_LDAP_ADMIN_BINDDN_P},
+ {"adminPassword", NS_LDAP_ADMIN_BINDPASSWD_P},
{NULL, 0}
};
@@ -3229,6 +3521,16 @@ clientSetParam(clientopts_t *optlist, int paramFlag, char *attrVal)
optlist->proxyDN = attrVal;
break;
+ case NS_LDAP_ENABLE_SHADOW_UPDATE_P:
+ CLIENT_OPT_CHECK(paramFlag, optlist->enableShadowUpdate);
+ optlist->enableShadowUpdate = attrVal;
+ break;
+
+ case NS_LDAP_ADMIN_BINDDN_P:
+ CLIENT_OPT_CHECK(paramFlag, optlist->adminDN);
+ optlist->adminDN = attrVal;
+ break;
+
case NS_LDAP_CACHETTL_P:
CLIENT_OPT_CHECK(paramFlag, optlist->profileTTL);
optlist->profileTTL = attrVal;
@@ -3319,6 +3621,11 @@ clientSetParam(clientopts_t *optlist, int paramFlag, char *attrVal)
optlist->proxyPassword = attrVal;
break;
+ case NS_LDAP_ADMIN_BINDPASSWD_P:
+ CLIENT_OPT_CHECK(paramFlag, optlist->adminPassword);
+ optlist->adminPassword = attrVal;
+ break;
+
case NS_LDAP_HOST_CERTPATH_P:
CLIENT_OPT_CHECK(paramFlag, optlist->certificatePath);
optlist->certificatePath = attrVal;
diff --git a/usr/src/cmd/ldapcachemgr/cachemgr.c b/usr/src/cmd/ldapcachemgr/cachemgr.c
index 4d854a4d00..aa01d7da17 100644
--- a/usr/src/cmd/ldapcachemgr/cachemgr.c
+++ b/usr/src/cmd/ldapcachemgr/cachemgr.c
@@ -19,12 +19,10 @@
* 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.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
/*
* Simple doors ldap cache daemon
*/
@@ -55,6 +53,8 @@
#include <alloca.h>
#include <ucontext.h>
+#include <stddef.h> /* offsetof */
+#include <priv.h>
#include "getxby_door.h"
#include "cachemgr.h"
@@ -72,6 +72,8 @@ static int setadmin(ldap_call_t *ptr);
static int client_setadmin(admin_t *ptr);
static int client_showstats(admin_t *ptr);
static int is_root(int free_uc, char *dc_str, ucred_t **uc);
+static int is_root_or_all_privs(char *dc_str, ucred_t **ucp);
+static void admin_modify(LineBuf *config_info, ldap_call_t *in);
#ifdef SLP
int use_slp = 0;
@@ -833,6 +835,11 @@ switcher(void *cookie, char *argp, size_t arg_size,
ucred_free(uc);
state = ALLOCATE;
break;
+ case ADMINMODIFY:
+ admin_modify(&configInfo, ptr);
+
+ state = GETSIZE;
+ break;
case GETSTATUSCHANGE:
/*
* Process the request and proceed with the default
@@ -1354,16 +1361,18 @@ is_root(int free_uc, char *dc_str, ucred_t **ucp)
if (current_admin.debug_level >= DBG_CANT_FIND)
logit("%s call failed(cred): caller pid %ld, uid %u, "
- "euid %u\n", dc_str, ucred_getpid(*ucp),
- ucred_getruid(*ucp), ucred_geteuid(*ucp));
+ "euid %u (if uid or euid is %u, it may be "
+ "unavailable)\n", dc_str, ucred_getpid(*ucp),
+ ucred_getruid(*ucp), ucred_geteuid(*ucp), -1);
rc = 0;
} else {
if (current_admin.debug_level >= DBG_ALL)
- logit("ldap_cachemgr received %s call from pid %ld, "
- "uid %u, euid %u\n", dc_str, ucred_getpid(*ucp),
- ucred_getruid(*ucp), ucred_geteuid(*ucp));
+ logit("received %s call from pid %ld, uid %u, euid %u "
+ "(if uid or euid is %u, it may be unavailable)\n",
+ dc_str, ucred_getpid(*ucp), ucred_getruid(*ucp),
+ ucred_geteuid(*ucp), -1);
rc = 1;
}
@@ -1458,3 +1467,376 @@ try_again:
return (match);
}
+
+/*
+ * new_attr(name, value)
+ *
+ * create a new LDAP attribute to be sent to the server
+ */
+static ns_ldap_attr_t *
+new_attr(char *name, char *value)
+{
+ ns_ldap_attr_t *tmp;
+
+ tmp = malloc(sizeof (*tmp));
+ if (tmp != NULL) {
+ tmp->attrname = name;
+ tmp->attrvalue = (char **)calloc(2, sizeof (char *));
+ if (tmp->attrvalue == NULL) {
+ free(tmp);
+ return (NULL);
+ }
+ tmp->attrvalue[0] = value;
+ tmp->value_count = 1;
+ }
+
+ return (tmp);
+}
+
+/*
+ * Convert the flatten ldap attributes in a ns_ldap_attr_t back
+ * to an ns_ldap_attr_t array.
+ *
+ * strlist->ldap_offsets[] contains offsets to strings:
+ * "dn", <dn value>, <attr 1>, <attrval 1>, ... <attr n>, <attrval n>
+ * where n is (strlist->ldap_count/2 -1).
+ * The output ns_ldap_attr_t array has a size of (strlist->ldap_count/2)
+ * the first (strlist->ldap_count/2 -1) contains all the attribute data,
+ * the last one is a NULL pointer. DN will be extracted out and pointed
+ * to by *dn.
+ */
+static ns_ldap_attr_t **
+str2attrs(ldap_strlist_t *strlist, char **dn)
+{
+ int c;
+ int i;
+ int j;
+ ns_ldap_attr_t **ret;
+
+ c = strlist->ldap_count;
+ ret = calloc(c/2, sizeof (ns_ldap_attr_t *));
+ if (ret == NULL)
+ return (NULL);
+ *dn = (char *)strlist + strlist->ldap_offsets[1];
+
+ /*
+ * skip the first 'dn'/<dn value> pair, for all other attr type/value
+ * pairs, get pointers to the attr type (offset [i]) and attr value
+ * (offset [i+1]) and put in ns_ldap_attr_t at ret[j]
+ */
+ for (i = 2, j = 0; i < c; i = i + 2, j++) {
+ ret[j] = new_attr((char *)strlist + strlist->ldap_offsets[i],
+ (char *)strlist + strlist->ldap_offsets[i + 1]);
+ }
+ return (ret);
+}
+
+static int
+get_admin_dn(ns_cred_t *credp, int *status, ns_ldap_error_t **errorp)
+{
+ void **paramVal = NULL;
+ int rc;
+
+ /* get bind DN for shadow update */
+ rc = __ns_ldap_getParam(NS_LDAP_ADMIN_BINDDN_P,
+ &paramVal, errorp);
+ if (rc != NS_LDAP_SUCCESS)
+ return (rc);
+
+ if (paramVal == NULL || *paramVal == NULL) {
+ rc = NS_LDAP_CONFIG;
+ *status = NS_CONFIG_NOTALLOW;
+ if (paramVal != NULL)
+ (void) __ns_ldap_freeParam(&paramVal);
+ return (rc);
+ }
+ credp->cred.unix_cred.userID = strdup((char *)*paramVal);
+ (void) __ns_ldap_freeParam(&paramVal);
+ if (credp->cred.unix_cred.userID == NULL)
+ return (NS_LDAP_MEMORY);
+
+ return (NS_LDAP_SUCCESS);
+}
+
+/*
+ * admin_modify() does a privileged modify within the ldap_cachemgr daemon
+ * process using the admin DN/password configured with parameters
+ * NS_LDAP_ADMIN_BINDDN and NS_LDAP_ADMIN_BINDPASSWD. It will only
+ * be done if NS_LDAP_ENABLE_SHADOW_UPDATE is set to TRUE.
+ *
+ * The input ldap_call_t (*in) contains LDAP shadowAccount attributes to
+ * be modified. The data is a flatten ns_ldap_attr_t arrary stored in
+ * the strlist element of the input ldap_call_t.
+ * The output will be in LineBuf (*config_info), an ldap_admin_mod_result_t
+ * structure that contains error code, error status, and error message.
+ */
+static void
+admin_modify(LineBuf *config_info, ldap_call_t *in)
+{
+ int rc = NS_LDAP_SUCCESS;
+ int authstried = 0;
+ int shadow_enabled = 0;
+ char *dn = NULL;
+ char **certpath = NULL;
+ char **enable_shadow = NULL;
+ ns_auth_t **app;
+ ns_auth_t **authpp = NULL;
+ ns_auth_t *authp = NULL;
+ ns_cred_t *credp = NULL;
+ char buffer[MAXERROR];
+ const int rlen = offsetof(ldap_admin_mod_result_t, msg);
+ int mlen = 0;
+ const int msgmax = MAXERROR - rlen;
+ int status = 0;
+ ucred_t *uc = NULL;
+ ldap_strlist_t *strlist;
+ ns_ldap_attr_t **attrs = NULL;
+ ns_ldap_error_t *error = NULL;
+ ldap_admin_mod_result_t *result;
+
+ (void) memset((char *)config_info, 0, sizeof (LineBuf));
+
+ /* only root or an ALL privs user can do admin modify */
+ if (is_root_or_all_privs("ADMINMODIFY", &uc) == 0) {
+ mlen = snprintf(buffer, msgmax, "%s",
+ gettext("shadow update by a non-root and no ALL privilege "
+ "user not allowed"));
+ rc = NS_LDAP_CONFIG;
+ goto out;
+ }
+
+ /* check to see if shadow update is enabled */
+ rc = __ns_ldap_getParam(NS_LDAP_ENABLE_SHADOW_UPDATE_P,
+ (void ***)&enable_shadow, &error);
+ if (rc != NS_LDAP_SUCCESS)
+ goto out;
+ if (enable_shadow != NULL && *enable_shadow != NULL) {
+ shadow_enabled = (*(int *)enable_shadow[0] ==
+ NS_LDAP_ENABLE_SHADOW_UPDATE_TRUE);
+ }
+ if (enable_shadow != NULL)
+ (void) __ns_ldap_freeParam((void ***)&enable_shadow);
+ if (shadow_enabled == 0) {
+ rc = NS_LDAP_CONFIG;
+ status = NS_CONFIG_NOTALLOW;
+ mlen = snprintf(buffer, msgmax, "%s",
+ gettext("shadow update not enabled"));
+ goto out;
+ }
+
+ /* convert attributes in string buffer into an ldap attribute array */
+ strlist = &in->ldap_u.strlist;
+ attrs = str2attrs(strlist, &dn);
+ if (attrs == NULL || *attrs == NULL || dn == NULL || *dn == '\0') {
+ rc = NS_LDAP_INVALID_PARAM;
+ goto out;
+ }
+
+ if ((credp = (ns_cred_t *)calloc(1, sizeof (ns_cred_t))) == NULL) {
+ rc = NS_LDAP_MEMORY;
+ goto out;
+ }
+
+ /* get host certificate path, if one is configured */
+ rc = __ns_ldap_getParam(NS_LDAP_HOST_CERTPATH_P,
+ (void ***)&certpath, &error);
+ if (rc != NS_LDAP_SUCCESS)
+ goto out;
+ if (certpath != NULL && *certpath != NULL) {
+ credp->hostcertpath = strdup(*certpath);
+ if (credp->hostcertpath == NULL)
+ rc = NS_LDAP_MEMORY;
+ }
+ if (certpath != NULL)
+ (void) __ns_ldap_freeParam((void ***)&certpath);
+ if (rc != NS_LDAP_SUCCESS)
+ goto out;
+
+ /* Load the service specific authentication method */
+ rc = __ns_ldap_getServiceAuthMethods("passwd-cmd", &authpp,
+ &error);
+ if (rc != NS_LDAP_SUCCESS) {
+ if (credp->hostcertpath != NULL)
+ free(credp->hostcertpath);
+ goto out;
+ }
+
+ /*
+ * if authpp is null, there is no serviceAuthenticationMethod
+ * try default authenticationMethod
+ */
+ if (authpp == NULL) {
+ rc = __ns_ldap_getParam(NS_LDAP_AUTH_P, (void ***)&authpp,
+ &error);
+ if (rc != NS_LDAP_SUCCESS)
+ goto out;
+ }
+
+ /*
+ * if authpp is still null, then can not authenticate, syslog
+ * error message and return error
+ */
+ if (authpp == NULL) {
+ rc = NS_LDAP_CONFIG;
+ mlen = snprintf(buffer, msgmax, "%s",
+ gettext("No legal LDAP authentication method configured"));
+ goto out;
+ }
+
+ /*
+ * Walk the array and try all authentication methods in order except
+ * for "none".
+ */
+ for (app = authpp; *app; app++) {
+ authp = *app;
+ if (authp->type == NS_LDAP_AUTH_NONE)
+ continue;
+ authstried++;
+ credp->auth.type = authp->type;
+ credp->auth.tlstype = authp->tlstype;
+ credp->auth.saslmech = authp->saslmech;
+ credp->auth.saslopt = authp->saslopt;
+
+ /*
+ * For GSSAPI, host credential will be used. No admin
+ * DN is needed. For other authentication methods,
+ * we need to set admin.
+ */
+ if (credp->auth.saslmech != NS_LDAP_SASL_GSSAPI) {
+ if ((rc = get_admin_dn(credp, &status,
+ &error)) != NS_LDAP_SUCCESS) {
+ if (error != NULL)
+ goto out;
+ if (status == NS_CONFIG_NOTALLOW) {
+ mlen = snprintf(buffer, msgmax, "%s",
+ gettext("Admin bind DN not "
+ "configured"));
+ goto out;
+ }
+ }
+ }
+
+ rc = __ns_ldap_repAttr(NS_ADMIN_SHADOW_UPDATE, dn,
+ (const ns_ldap_attr_t * const *)attrs,
+ credp, 0, &error);
+ if (rc == NS_LDAP_SUCCESS)
+ goto out;
+
+ /*
+ * Other errors might need to be added to this list, for
+ * the current supported mechanisms this is sufficient.
+ */
+ if (rc == NS_LDAP_INTERNAL &&
+ error->pwd_mgmt.status == NS_PASSWD_GOOD &&
+ (error->status == LDAP_INAPPROPRIATE_AUTH ||
+ error->status == LDAP_INVALID_CREDENTIALS))
+ goto out;
+
+ /*
+ * If there is error related to password policy,
+ * return it to caller.
+ */
+ if (rc == NS_LDAP_INTERNAL &&
+ error->pwd_mgmt.status != NS_PASSWD_GOOD) {
+ rc = NS_LDAP_CONFIG;
+ status = NS_CONFIG_NOTALLOW;
+ (void) __ns_ldap_freeError(&error);
+ mlen = snprintf(buffer, msgmax, "%s",
+ gettext("update failed due to "
+ "password policy on server (%d)"),
+ error->pwd_mgmt.status);
+ goto out;
+ }
+
+ /* we don't really care about the error, just clean it up */
+ if (error)
+ (void) __ns_ldap_freeError(&error);
+ }
+ if (authstried == 0) {
+ rc = NS_LDAP_CONFIG;
+ mlen = snprintf(buffer, msgmax, "%s",
+ gettext("No legal LDAP authentication method configured"));
+ goto out;
+ }
+
+ rc = NS_LDAP_OP_FAILED;
+
+out:
+ if (credp != NULL)
+ (void) __ns_ldap_freeCred(&credp);
+
+ if (authpp != NULL)
+ (void) __ns_ldap_freeParam((void ***)&authpp);
+
+ if (error != NULL) {
+ mlen = snprintf(buffer, msgmax, "%s", error->message);
+ status = error->status;
+ (void) __ns_ldap_freeError(&error);
+ }
+
+ if (attrs != NULL) {
+ int i;
+ for (i = 0; attrs[i]; i++) {
+ free(attrs[i]->attrvalue);
+ free(attrs[i]);
+ }
+ }
+
+ config_info->len = rlen + mlen + 1;
+ config_info->str = malloc(config_info->len);
+ if (config_info->str == NULL) {
+ config_info->len = 0;
+ return;
+ }
+ result = (ldap_admin_mod_result_t *)config_info->str;
+ result->ns_err = rc;
+ result->status = status;
+ if (mlen != 0) {
+ result->msg_size = mlen + 1;
+ (void) strcpy(config_info->str + rlen, buffer);
+ }
+}
+
+/*
+ * Check to see if the door client's euid is 0 or if it has ALL zone privilege.
+ * return - 0 No or error
+ * 1 Yes
+ */
+static int
+is_root_or_all_privs(char *dc_str, ucred_t **ucp)
+{
+ const priv_set_t *ps; /* door client */
+ priv_set_t *zs; /* zone */
+ int rc = 0;
+
+ *ucp = NULL;
+
+ /* no more to do if door client's euid is 0 */
+ if (is_root(0, dc_str, ucp) == 1) {
+ ucred_free(*ucp);
+ return (1);
+ }
+
+ /* error if couldn't get the ucred_t */
+ if (*ucp == NULL)
+ return (0);
+
+ if ((ps = ucred_getprivset(*ucp, PRIV_EFFECTIVE)) != NULL) {
+ zs = priv_str_to_set("zone", ",", NULL);
+ if (priv_isequalset(ps, zs))
+ rc = 1; /* has all zone privs */
+ else {
+ if (current_admin.debug_level >= DBG_CANT_FIND)
+ logit("%s call failed (no all zone privs): "
+ "caller pid %ld, uid %u, euid %u "
+ "(if uid or euid is %u, it may "
+ "be unavailable)\n", dc_str,
+ ucred_getpid(*ucp), ucred_getruid(*ucp),
+ ucred_geteuid(*ucp), -1);
+ }
+ priv_freeset(zs);
+ }
+
+ ucred_free(*ucp);
+ return (rc);
+}
diff --git a/usr/src/cmd/passwd/passwd.c b/usr/src/cmd/passwd/passwd.c
index 7b96606534..f20dd63003 100644
--- a/usr/src/cmd/passwd/passwd.c
+++ b/usr/src/cmd/passwd/passwd.c
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -30,8 +29,6 @@
/* Copyright (c) 1987, 1988 Microsoft Corporation */
/* All Rights Reserved */
-#pragma ident "%Z%%M% %I% %E% SMI"
-
/*
* passwd is a program whose sole purpose is to manage
* the password file, map, or table. It allows system administrator
@@ -207,7 +204,7 @@ static int ckarg(int argc, char **argv, attrlist **attributes);
static int get_namelist(pwu_repository_t, char ***, int *);
static int get_namelist_files(char ***, int *);
-static int get_namelist_nisplus(char ***, int *);
+static int get_namelist_local(char ***, int *);
static int get_attr(char *, pwu_repository_t *, attrlist **);
static void display_attr(char *, attrlist *);
static void free_attr(attrlist *);
@@ -318,7 +315,7 @@ main(int argc, char *argv[])
if (num_user == 0) {
(void) fprintf(stderr, "%s: %s\n", prognamep,
- gettext(MSG_FF));
+ gettext(MSG_FF));
passwd_exit(FATAL);
}
i = 0;
@@ -737,11 +734,13 @@ ckarg(int argc, char **argv, attrlist **attributes)
/*
* Delete the password - only privileged processes
- * can execute this for FILES
+ * can execute this for FILES or LDAP
*/
- if (IS_FILES(repository) == FALSE) {
+ if (IS_FILES(repository) == FALSE &&
+ IS_LDAP(repository) == FALSE) {
(void) fprintf(stderr, gettext(
- "-d only applies to files repository\n"));
+ "-d only applies to files "
+ "or ldap repository\n"));
rusage(); /* exit */
retval = BADSYN;
return (FAIL);
@@ -767,9 +766,11 @@ ckarg(int argc, char **argv, attrlist **attributes)
repository = __REPFILES;
if (IS_FILES(repository) == FALSE &&
+ IS_LDAP(repository) == FALSE &&
IS_NISPLUS(repository) == FALSE) {
(void) fprintf(stderr, gettext(
- "-N only applies to files or nisplus repository\n"));
+ "-N only applies to files, ldap or "
+ "nisplus repository\n"));
rusage(); /* exit */
retval = BADOPT;
return (FAIL);
@@ -777,10 +778,10 @@ ckarg(int argc, char **argv, attrlist **attributes)
/*
* Only privileged processes can execute this
- * for FILES
+ * for FILES or LDAP
*/
- if (IS_FILES(repository) &&
- ((retval = ckuid()) != SUCCESS))
+ if ((IS_FILES(repository) || IS_LDAP(repository)) &&
+ ((retval = ckuid()) != SUCCESS))
return (FAIL);
if (flag & (MUTEXFLAG|NONAGEFLAG)) {
rusage(); /* exit */
@@ -798,9 +799,11 @@ ckarg(int argc, char **argv, attrlist **attributes)
repository = __REPFILES;
if (IS_FILES(repository) == FALSE &&
+ IS_LDAP(repository) == FALSE &&
IS_NISPLUS(repository) == FALSE) {
(void) fprintf(stderr, gettext(
- "-l only applies to files or nisplus repository\n"));
+ "-l only applies to files, ldap or "
+ "nisplus repository\n"));
rusage(); /* exit */
retval = BADOPT;
return (FAIL);
@@ -808,10 +811,10 @@ ckarg(int argc, char **argv, attrlist **attributes)
/*
* Only privileged processes can execute this
- * for FILES
+ * for FILES or LDAP
*/
- if (IS_FILES(repository) &&
- ((retval = ckuid()) != SUCCESS))
+ if ((IS_FILES(repository) || IS_LDAP(repository)) &&
+ ((retval = ckuid()) != SUCCESS))
return (FAIL);
if (flag & (MUTEXFLAG|NONAGEFLAG)) {
rusage(); /* exit */
@@ -829,9 +832,11 @@ ckarg(int argc, char **argv, attrlist **attributes)
repository = __REPFILES;
if (IS_FILES(repository) == FALSE &&
+ IS_LDAP(repository) == FALSE &&
IS_NISPLUS(repository) == FALSE) {
(void) fprintf(stderr, gettext(
- "-u only applies to files or nisplus repository\n"));
+ "-u only applies to files, ldap or "
+ "nisplus repository\n"));
rusage(); /* exit */
retval = BADOPT;
return (FAIL);
@@ -839,10 +844,10 @@ ckarg(int argc, char **argv, attrlist **attributes)
/*
* Only privileged processes can execute this
- * for FILES
+ * for FILES or LDAP
*/
- if (IS_FILES(repository) &&
- ((retval = ckuid()) != SUCCESS))
+ if ((IS_FILES(repository) || IS_LDAP(repository)) &&
+ ((retval = ckuid()) != SUCCESS))
return (FAIL);
if (flag & (MUTEXFLAG|NONAGEFLAG)) {
rusage(); /* exit */
@@ -861,9 +866,11 @@ ckarg(int argc, char **argv, attrlist **attributes)
repository = __REPFILES;
if (IS_FILES(repository) == FALSE &&
+ IS_LDAP(repository) == FALSE &&
IS_NISPLUS(repository) == FALSE) {
(void) fprintf(stderr, gettext(
- "-x only applies to files or nisplus repository\n"));
+ "-x only applies to files, ldap or "
+ "nisplus repository\n"));
rusage(); /* exit */
retval = BADSYN;
return (FAIL);
@@ -871,9 +878,10 @@ ckarg(int argc, char **argv, attrlist **attributes)
/*
* Only privileged process can execute this
- * for FILES
+ * for FILES or LDAP
*/
- if (IS_FILES(repository) && (ckuid() != SUCCESS)) {
+ if ((IS_FILES(repository) || IS_LDAP(repository)) &&
+ (ckuid() != SUCCESS)) {
retval = NOPERM;
return (FAIL);
}
@@ -886,7 +894,7 @@ ckarg(int argc, char **argv, attrlist **attributes)
(maxdate = strtol(optarg, &char_p, 10)) < -1 ||
*char_p != '\0') {
(void) fprintf(stderr, "%s: %s -x\n",
- prognamep, gettext(MSG_NV));
+ prognamep, gettext(MSG_NV));
retval = BADSYN;
return (FAIL);
}
@@ -900,9 +908,11 @@ ckarg(int argc, char **argv, attrlist **attributes)
repository = __REPFILES;
if (IS_FILES(repository) == FALSE &&
+ IS_LDAP(repository) == FALSE &&
IS_NISPLUS(repository) == FALSE) {
(void) fprintf(stderr, gettext(
- "-n only applies to files or nisplus repository\n"));
+ "-n only applies to files, ldap or "
+ "nisplus repository\n"));
rusage(); /* exit */
retval = BADSYN;
return (FAIL);
@@ -910,10 +920,10 @@ ckarg(int argc, char **argv, attrlist **attributes)
/*
* Only privileged process can execute this
- * for FILES
+ * for FILES or LDAP
*/
- if (IS_FILES(repository) &&
- ((retval = ckuid()) != SUCCESS))
+ if ((IS_FILES(repository) || IS_LDAP(repository)) &&
+ ((retval = ckuid()) != SUCCESS))
return (FAIL);
if (flag & (SAFLAG|NFLAG|NONAGEFLAG)) {
retval = BADOPT;
@@ -924,7 +934,7 @@ ckarg(int argc, char **argv, attrlist **attributes)
(strtol(optarg, &char_p, 10)) < 0 ||
*char_p != '\0') {
(void) fprintf(stderr, "%s: %s -n\n",
- prognamep, gettext(MSG_NV));
+ prognamep, gettext(MSG_NV));
retval = BADSYN;
return (FAIL);
}
@@ -938,9 +948,11 @@ ckarg(int argc, char **argv, attrlist **attributes)
repository = __REPFILES;
if (IS_FILES(repository) == FALSE &&
+ IS_LDAP(repository) == FALSE &&
IS_NISPLUS(repository) == FALSE) {
(void) fprintf(stderr, gettext(
- "-w only applies to files or nisplus repository\n"));
+ "-w only applies to files, ldap or "
+ "nisplus repository\n"));
rusage(); /* exit */
retval = BADSYN;
return (FAIL);
@@ -948,9 +960,10 @@ ckarg(int argc, char **argv, attrlist **attributes)
/*
* Only privileged process can execute this
- * for FILES
+ * for FILES or LDAP
*/
- if (IS_FILES(repository) && (ckuid() != SUCCESS)) {
+ if ((IS_FILES(repository) || IS_LDAP(repository)) &&
+ (ckuid() != SUCCESS)) {
retval = NOPERM;
return (FAIL);
}
@@ -963,7 +976,7 @@ ckarg(int argc, char **argv, attrlist **attributes)
(strtol(optarg, &char_p, 10)) < 0 ||
*char_p != '\0') {
(void) fprintf(stderr, "%s: %s -w\n",
- prognamep, gettext(MSG_NV));
+ prognamep, gettext(MSG_NV));
retval = BADSYN;
return (FAIL);
}
@@ -979,9 +992,11 @@ ckarg(int argc, char **argv, attrlist **attributes)
/* display password attributes */
if (IS_FILES(repository) == FALSE &&
+ IS_LDAP(repository) == FALSE &&
IS_NISPLUS(repository) == FALSE) {
(void) fprintf(stderr, gettext(
- "-s only applies to files or nisplus repository\n"));
+ "-s only applies to files, ldap or "
+ "nisplus repository\n"));
rusage(); /* exit */
retval = BADSYN;
return (FAIL);
@@ -989,10 +1004,10 @@ ckarg(int argc, char **argv, attrlist **attributes)
/*
* Only privileged process can execute this
- * for FILES
+ * for FILES or LDAP
*/
- if (IS_FILES(repository) &&
- ((retval = ckuid()) != SUCCESS))
+ if ((IS_FILES(repository) || IS_LDAP(repository)) &&
+ ((retval = ckuid()) != SUCCESS))
return (FAIL);
if (flag && (flag != AFLAG)) {
retval = BADOPT;
@@ -1008,9 +1023,11 @@ ckarg(int argc, char **argv, attrlist **attributes)
repository = __REPFILES;
if (IS_FILES(repository) == FALSE &&
+ IS_LDAP(repository) == FALSE &&
IS_NISPLUS(repository) == FALSE) {
(void) fprintf(stderr, gettext(
- "-a only applies to files or nisplus repository\n"));
+ "-a only applies to files, ldap or "
+ "nisplus repository\n"));
rusage(); /* exit */
retval = BADSYN;
return (FAIL);
@@ -1018,10 +1035,10 @@ ckarg(int argc, char **argv, attrlist **attributes)
/*
* Only privileged process can execute this
- * for FILES
+ * for FILES or LDAP
*/
- if (IS_FILES(repository) &&
- ((retval = ckuid()) != SUCCESS))
+ if ((IS_FILES(repository) || IS_LDAP(repository)) &&
+ ((retval = ckuid()) != SUCCESS))
return (FAIL);
if (flag && (flag != SFLAG)) {
retval = BADOPT;
@@ -1037,9 +1054,11 @@ ckarg(int argc, char **argv, attrlist **attributes)
repository = __REPFILES;
if (IS_FILES(repository) == FALSE &&
+ IS_LDAP(repository) == FALSE &&
IS_NISPLUS(repository) == FALSE) {
(void) fprintf(stderr, gettext(
- "-f only applies to files or nisplus repository\n"));
+ "-f only applies to files, ldap or "
+ "nisplus repository\n"));
rusage(); /* exit */
retval = BADSYN;
return (FAIL);
@@ -1047,10 +1066,10 @@ ckarg(int argc, char **argv, attrlist **attributes)
/*
* Only privileged process can execute this
- * for FILES
+ * for FILES or LDAP
*/
- if (IS_FILES(repository) &&
- ((retval = ckuid()) != SUCCESS))
+ if ((IS_FILES(repository) || IS_LDAP(repository)) &&
+ ((retval = ckuid()) != SUCCESS))
return (FAIL);
if (flag & (SAFLAG|FFLAG|NONAGEFLAG)) {
retval = BADOPT;
@@ -1208,7 +1227,7 @@ ckarg(int argc, char **argv, attrlist **attributes)
*/
if ((maxdate == -1) && (flag & NFLAG)) {
(void) fprintf(stderr, "%s: %s -n\n",
- prognamep, gettext(MSG_NV));
+ prognamep, gettext(MSG_NV));
retval = BADOPT;
return (FAIL);
}
@@ -1400,47 +1419,49 @@ get_namelist_files(char ***namelist_p, int *num_user)
}
/*
- * get_namelist_nisplus
+ * get_namelist_local
*
*/
/*
- * Our private version of the switch frontend for getspent. We want to
- * search just the nisplus sp file, so we want to bypass normal nsswitch.conf
- * based processing. This implementation compatible with version 2 of the
- * name service switch.
+ * Our private version of the switch frontend for getspent. We want
+ * to search just the nisplus or ldap sp file, so we want to bypass
+ * normal nsswitch.conf based processing. This implementation
+ * compatible with version 2 of the name service switch.
*/
#define NSS_NISPLUS_ONLY "nisplus"
+#define NSS_LDAP_ONLY "ldap"
extern int str2spwd(const char *, int, void *, char *, int);
static DEFINE_NSS_DB_ROOT(db_root);
static DEFINE_NSS_GETENT(context);
+static char *local_config;
static void
-_np_nss_initf_shadow(nss_db_params_t *p)
+_lc_nss_initf_shadow(nss_db_params_t *p)
{
p->name = NSS_DBNAM_SHADOW;
p->config_name = NSS_DBNAM_PASSWD; /* Use config for "passwd" */
- p->default_config = NSS_NISPLUS_ONLY; /* Use nisplus only */
+ p->default_config = local_config; /* Use ldap or nisplus only */
p->flags = NSS_USE_DEFAULT_CONFIG;
}
static void
-_np_setspent(void)
+_lc_setspent(void)
{
- nss_setent(&db_root, _np_nss_initf_shadow, &context);
+ nss_setent(&db_root, _lc_nss_initf_shadow, &context);
}
static void
-_np_endspent(void)
+_lc_endspent(void)
{
- nss_endent(&db_root, _np_nss_initf_shadow, &context);
+ nss_endent(&db_root, _lc_nss_initf_shadow, &context);
nss_delete(&db_root);
}
static struct spwd *
-_np_getspent_r(struct spwd *result, char *buffer, int buflen)
+_lc_getspent_r(struct spwd *result, char *buffer, int buflen)
{
nss_XbyY_args_t arg;
char *nam;
@@ -1450,11 +1471,11 @@ _np_getspent_r(struct spwd *result, char *buffer, int buflen)
do {
NSS_XbyY_INIT(&arg, result, buffer, buflen, str2spwd);
/* No key to fill in */
- (void) nss_getent(&db_root, _np_nss_initf_shadow, &context,
+ (void) nss_getent(&db_root, _lc_nss_initf_shadow, &context,
&arg);
} while (arg.returnval != 0 &&
- (nam = ((struct spwd *)arg.returnval)->sp_namp) != 0 &&
- (*nam == '+' || *nam == '-'));
+ (nam = ((struct spwd *)arg.returnval)->sp_namp) != 0 &&
+ (*nam == '+' || *nam == '-'));
return (struct spwd *)NSS_XbyY_FINI(&arg);
}
@@ -1462,17 +1483,17 @@ _np_getspent_r(struct spwd *result, char *buffer, int buflen)
static nss_XbyY_buf_t *buffer;
static struct spwd *
-_np_getspent(void)
+_lc_getspent(void)
{
nss_XbyY_buf_t *b;
b = NSS_XbyY_ALLOC(&buffer, sizeof (struct spwd), NSS_BUFLEN_SHADOW);
- return (b == 0 ? 0 : _np_getspent_r(b->result, b->buffer, b->buflen));
+ return (b == 0 ? 0 : _lc_getspent_r(b->result, b->buffer, b->buflen));
}
int
-get_namelist_nisplus(char ***namelist_p, int *num_user)
+get_namelist_local(char ***namelist_p, int *num_user)
{
int nuser = 0;
int alloced = 100;
@@ -1483,22 +1504,22 @@ get_namelist_nisplus(char ***namelist_p, int *num_user)
if ((nl = calloc(alloced, sizeof (*nl))) == NULL)
return (FMERR);
- (void) _np_setspent();
- while ((p = _np_getspent()) != NULL) {
+ (void) _lc_setspent();
+ while ((p = _lc_getspent()) != NULL) {
if ((nl[nuser] = strdup(p->sp_namp)) == NULL) {
- _np_endspent();
+ _lc_endspent();
return (FMERR);
}
if (++nuser == alloced) {
alloced += 100;
nl = realloc(nl, alloced * (sizeof (*nl)));
if (nl == NULL) {
- _np_endspent();
+ _lc_endspent();
return (FMERR);
}
}
}
- (void) _np_endspent();
+ (void) _lc_endspent();
nl[nuser] = NULL;
*namelist_p = nl;
@@ -1510,9 +1531,13 @@ get_namelist_nisplus(char ***namelist_p, int *num_user)
int
get_namelist(pwu_repository_t repository, char ***namelist, int *num_user)
{
- if (IS_NISPLUS(repository))
- return (get_namelist_nisplus(namelist, num_user));
- else if (IS_FILES(repository))
+ if (IS_LDAP(repository)) {
+ local_config = NSS_LDAP_ONLY;
+ return (get_namelist_local(namelist, num_user));
+ } else if (IS_NISPLUS(repository)) {
+ local_config = NSS_NISPLUS_ONLY;
+ return (get_namelist_local(namelist, num_user));
+ } else if (IS_FILES(repository))
return (get_namelist_files(namelist, num_user));
rusage();
@@ -1607,7 +1632,7 @@ passwd_conv(int num_msg, struct pam_message **msg,
return (PAM_CONV_ERR);
*response = (struct pam_response *)calloc(num_msg,
- sizeof (struct pam_response));
+ sizeof (struct pam_response));
if (*response == NULL)
return (PAM_BUF_ERR);
@@ -1644,7 +1669,7 @@ passwd_conv(int num_msg, struct pam_message **msg,
(void) fputs(m->msg, stdout);
}
r->resp = (char *)calloc(PAM_MAX_RESP_SIZE,
- sizeof (char));
+ sizeof (char));
if (r->resp == NULL) {
/* free responses */
r = *response;
@@ -1793,5 +1818,9 @@ rusage(void)
"[-w warn]\n");
MSG("\t\t[-x max] name\n");
MSG("\tpasswd -r ldap [-egh] [name]\n");
+ MSG("\tpasswd -r ldap -sa\n");
+ MSG("\tpasswd -r ldap -s [name]\n");
+ MSG("\tpasswd -r ldap [-l|-N|-u] [-f] [-n min] [-w warn] "
+ "[-x max] name\n");
#undef MSG
}
diff --git a/usr/src/lib/libsldap/common/mapfile-vers b/usr/src/lib/libsldap/common/mapfile-vers
index f58a9328d4..e043513adf 100644
--- a/usr/src/lib/libsldap/common/mapfile-vers
+++ b/usr/src/lib/libsldap/common/mapfile-vers
@@ -22,19 +22,6 @@
# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
-
-#
-# MAPFILE HEADER START
-#
-# WARNING: STOP NOW. DO NOT MODIFY THIS FILE.
-# Object versioning must comply with the rules detailed in
-#
-# usr/src/lib/README.mapfiles
-#
-# You should not be making modifications here until you've read the most current
-# copy of that file. If you need help, contact a gatekeeper for guidance.
-#
-# MAPFILE HEADER END
#
# There really should be only one SUNWprivate version.
@@ -42,22 +29,23 @@
SUNWprivate_1.1 {
global:
- __ns_ldap_initStandalone;
- __ns_ldap_getConnectionInfoFromDUA;
- __ns_ldap_getRootDSE;
- __ns_ldap_pingOfflineServers;
__ns_ldap_cancelStandalone;
- __ns_ldap_initAuth;
+ __ns_ldap_check_all_preq;
+ __ns_ldap_check_dns_preq;
+ __ns_ldap_check_gssapi_preq;
__ns_ldap_getAcctMgmt;
- __s_api_get_canonical_name;
__ns_ldap_getAttrStruct;
+ __ns_ldap_getConnectionInfoFromDUA;
+ __ns_ldap_getRootDSE;
+ __ns_ldap_initAuth;
+ __ns_ldap_initStandalone;
+ __ns_ldap_is_shadow_update_enabled;
+ __ns_ldap_pingOfflineServers;
__ns_ldap_self_gssapi_config;
__ns_ldap_self_gssapi_only_set;
- __ns_ldap_check_dns_preq;
- __ns_ldap_check_gssapi_preq;
- __ns_ldap_check_all_preq;
- __s_api_ip2hostname;
+ __s_api_get_canonical_name;
__s_api_hostname2ip;
+ __s_api_ip2hostname;
} SUNWprivate_1.0;
SUNWprivate_1.0 {
diff --git a/usr/src/lib/libsldap/common/ns_cache_door.h b/usr/src/lib/libsldap/common/ns_cache_door.h
index 391394cbe7..52599534af 100644
--- a/usr/src/lib/libsldap/common/ns_cache_door.h
+++ b/usr/src/lib/libsldap/common/ns_cache_door.h
@@ -19,15 +19,13 @@
* 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.
*/
#ifndef _NS_CACHE_DOOR_H
#define _NS_CACHE_DOOR_H
-#pragma ident "%Z%%M% %I% %E% SMI"
-
/*
* Definitions for client side of doors-based ldap caching
*/
@@ -96,6 +94,13 @@ typedef struct ldap_config_out {
char config_str[sizeof (int)]; /* real size is data_size */
} ldap_config_out_t;
+typedef struct ldap_admin_mod_result {
+ uint32_t ns_err; /* ns_ldap error code */
+ uint32_t status; /* error status */
+ uint32_t msg_size; /* length of error message */
+ char msg[sizeof (int)]; /* real size is msg_size */
+} ldap_admin_mod_result_t;
+
/*
* structure returned by server for all calls
*/
@@ -116,6 +121,7 @@ typedef struct {
ldap_strlist_t strlist;
ldap_config_out_t config_str;
ldap_get_change_out_t changes;
+ ldap_admin_mod_result_t admin_result;
} ldap_u;
} ldap_return_t;
@@ -187,6 +193,8 @@ typedef union {
#define GETCACHESTAT 24
/* Configuration change or server status change notification */
#define GETSTATUSCHANGE 25
+ /* perform admin modify via ldap_cachemgr */
+#define ADMINMODIFY 26
/*
* GETLDAPSERVER request flags
diff --git a/usr/src/lib/libsldap/common/ns_config.c b/usr/src/lib/libsldap/common/ns_config.c
index 2046a46bad..1a7a21bfee 100644
--- a/usr/src/lib/libsldap/common/ns_config.c
+++ b/usr/src/lib/libsldap/common/ns_config.c
@@ -19,12 +19,10 @@
* 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.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
/*
* libsldap - library side configuration components
* Routines to manage the config structure
@@ -202,6 +200,12 @@ static ns_enum_map ns_pref_enum[] = {
{ -1, NULL },
};
+static ns_enum_map ns_shadow_update_enum[] = {
+ { ENUM2INT(NS_LDAP_ENABLE_SHADOW_UPDATE_FALSE), "FALSE" },
+ { ENUM2INT(NS_LDAP_ENABLE_SHADOW_UPDATE_TRUE), "TRUE" },
+ { -1, NULL },
+};
+
static int ns_def_auth_v1[] = {
ENUM2INT(NS_LDAP_EA_NONE),
0
@@ -392,11 +396,31 @@ static ns_default_config defconfig[] = {
NULL, /* not defined in the Profile */
{ CHARPTR, 0, NULL },
__s_val_binddn, NULL },
+
{"NS_LDAP_BINDPASSWD", NS_LDAP_BINDPASSWD_P,
CREDCONFIG, CHARPTR, TRUE, NS_LDAP_V2,
NULL, /* not defined in the Profile */
{ CHARPTR, 0, NULL },
__s_val_bindpw, NULL },
+
+ {"NS_LDAP_ENABLE_SHADOW_UPDATE", NS_LDAP_ENABLE_SHADOW_UPDATE_P,
+ CREDCONFIG, INT, TRUE, NS_LDAP_V2,
+ NULL, /* not defined in the Profile */
+ { INT, 0, INT2VOIDPTR(NS_LDAP_ENABLE_SHADOW_UPDATE_FALSE) },
+ NULL, ns_shadow_update_enum },
+
+ {"NS_LDAP_ADMIN_BINDDN", NS_LDAP_ADMIN_BINDDN_P,
+ CREDCONFIG, CHARPTR, TRUE, NS_LDAP_V2,
+ NULL, /* not defined in the Profile */
+ { CHARPTR, 0, NULL },
+ __s_val_binddn, NULL },
+
+ {"NS_LDAP_ADMIN_BINDPASSWD", NS_LDAP_ADMIN_BINDPASSWD_P,
+ CREDCONFIG, CHARPTR, TRUE, NS_LDAP_V2,
+ NULL, /* not defined in the Profile */
+ { CHARPTR, 0, NULL },
+ __s_val_bindpw, NULL },
+
{"NS_LDAP_EXP", NS_LDAP_EXP_P,
SERVERCONFIG, TIMET, TRUE, NS_LDAP_V2,
NULL, /* initialized by code to time+NS_LDAP_CACHETTL */
@@ -601,6 +625,9 @@ __s_get_enum_value(ns_config_t *ptr, char *value, ParamIndexType i)
case NS_LDAP_PREF_ONLY_P:
mapp = &ns_pref_enum[0];
break;
+ case NS_LDAP_ENABLE_SHADOW_UPDATE_P:
+ mapp = &ns_shadow_update_enum[0];
+ break;
case NS_LDAP_CREDENTIAL_LEVEL_P:
if (ptr->version == NS_LDAP_V1)
return (-1);
@@ -713,6 +740,21 @@ __s_get_searchref_name(ns_config_t *ptr, SearchRef_t type)
return ("Unknown SearchRef_t type specified");
}
+char *
+__s_get_shadowupdate_name(enableShadowUpdate_t type)
+{
+ register ns_enum_map *mapp;
+
+ mapp = &ns_shadow_update_enum[0];
+
+ for (; mapp->name != NULL; mapp++) {
+ if (type == INT2SHADOWUPDATENUM(mapp->value)) {
+ return (mapp->name);
+ }
+ }
+ return ("Unknown enableShadowUpdate_t type specified");
+}
+
static char *
__s_get_credlvl_name(ns_config_t *ptr, CredLevel_t type)
{
@@ -1486,6 +1528,8 @@ verify_value(ns_config_t *cfg, char *name, char *value, char *errstr)
case NS_LDAP_CERT_NICKNAME_P:
case NS_LDAP_BINDDN_P:
case NS_LDAP_BINDPASSWD_P:
+ case NS_LDAP_ADMIN_BINDDN_P:
+ case NS_LDAP_ADMIN_BINDPASSWD_P:
case NS_LDAP_DOMAIN_P:
case NS_LDAP_SEARCH_BASEDN_P:
case NS_LDAP_SEARCH_TIME_P:
@@ -1648,6 +1692,7 @@ __ns_ldap_setParamValue(ns_config_t *ptr, const ParamIndexType type,
case NS_LDAP_PREF_ONLY_P:
case NS_LDAP_SEARCH_REF_P:
case NS_LDAP_SEARCH_SCOPE_P:
+ case NS_LDAP_ENABLE_SHADOW_UPDATE_P:
i = __s_get_enum_value(ptr, cp, def->index);
if (i < 0) {
(void) snprintf(errstr, sizeof (errstr),
@@ -2615,7 +2660,8 @@ __ns_ldap_setParamValue(ns_config_t *ptr, const ParamIndexType type,
*
* Init NS_LDAP_EXP_P here when CACHETTL is updated
*/
- if (type == NS_LDAP_BINDPASSWD_P) {
+ if (type == NS_LDAP_BINDPASSWD_P ||
+ type == NS_LDAP_ADMIN_BINDPASSWD_P) {
cp = conf.ns_pc;
cp2 = evalue((char *)cp);
conf.ns_pc = cp2;
@@ -3219,6 +3265,11 @@ __s_api_strValue(ns_config_t *cfg, char *str,
__s_get_scope_name(cfg,
(ScopeType_t)ptr->ns_i));
break;
+ case NS_LDAP_ENABLE_SHADOW_UPDATE_P:
+ (void) strlcat(buf,
+ __s_get_shadowupdate_name(
+ (enableShadowUpdate_t)ptr->ns_i), bufsz);
+ break;
default:
(void) snprintf(ibuf, sizeof (ibuf),
"%d", ptr->ns_i);
@@ -3730,15 +3781,21 @@ static int
__s_val_binddn(ParamIndexType i, ns_default_config *def,
ns_param_t *param, char *errbuf)
{
+ char *dntype;
+
if (param && param->ns_ptype == CHARPTR &&
- i == NS_LDAP_BINDDN_P &&
+ (i == NS_LDAP_BINDDN_P || i == NS_LDAP_ADMIN_BINDDN_P) &&
((param->ns_pc == NULL) ||
((*(param->ns_pc) != '\0') &&
(strchr(param->ns_pc, '=') != NULL)))) {
return (NS_SUCCESS);
}
+ if (i == NS_LDAP_BINDDN_P)
+ dntype = "proxy";
+ else
+ dntype = "update";
(void) snprintf(errbuf, MAXERROR,
- gettext("NULL or invalid proxy bind DN"));
+ gettext("NULL or invalid %s bind DN"), dntype);
return (NS_PARSE_ERR);
}
@@ -3751,14 +3808,20 @@ static int
__s_val_bindpw(ParamIndexType i, ns_default_config *def,
ns_param_t *param, char *errbuf)
{
+ char *pwtype;
+
if (param && param->ns_ptype == CHARPTR &&
- i == NS_LDAP_BINDPASSWD_P &&
+ (i == NS_LDAP_BINDPASSWD_P || i == NS_LDAP_ADMIN_BINDPASSWD_P) &&
((param->ns_pc == NULL) ||
(*(param->ns_pc) != '\0'))) {
return (NS_SUCCESS);
}
+ if (i == NS_LDAP_BINDPASSWD_P)
+ pwtype = "proxy";
+ else
+ pwtype = "admin";
(void) snprintf(errbuf, MAXERROR,
- gettext("NULL proxy bind password"));
+ gettext("NULL %s bind password"), pwtype);
return (NS_PARSE_ERR);
}
diff --git a/usr/src/lib/libsldap/common/ns_confmgr.c b/usr/src/lib/libsldap/common/ns_confmgr.c
index 1fd58aac6f..a96f186ded 100644
--- a/usr/src/lib/libsldap/common/ns_confmgr.c
+++ b/usr/src/lib/libsldap/common/ns_confmgr.c
@@ -19,12 +19,10 @@
* 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.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
/* libsldap - cachemgr side configuration components */
#include <stdio.h>
@@ -332,6 +330,15 @@ __s_api_create_config_door_str(char *config, ns_ldap_error_t **errorp)
__s_api_destroy_config(configStruct);
return (NULL);
}
+ } else if (strcasecmp(attrVal,
+ _PROFILE1_OBJECTCLASS) == 0) {
+ if (__ns_ldap_setParamValue(configStruct,
+ NS_LDAP_FILE_VERSION_P,
+ NS_LDAP_VERSION_1,
+ errorp) != NS_LDAP_SUCCESS) {
+ __s_api_destroy_config(configStruct);
+ return (NULL);
+ }
}
continue;
}
@@ -490,6 +497,10 @@ __ns_ldap_LoadDoorInfo(LineBuf *configinfo, char *domainname, ns_config_t *new)
}
(void) memset((char *)configinfo, 0, sizeof (LineBuf));
for (i = 0; i <= NS_LDAP_MAX_PIT_P; i++) {
+ /* the credential for shadow update is not to be exposed */
+ if (i == NS_LDAP_ADMIN_BINDDN_P ||
+ i == NS_LDAP_ADMIN_BINDPASSWD_P)
+ continue;
str = __s_api_strValue(ptr, string, sizeof (string), i,
NS_DOOR_FMT);
if (str == NULL)
@@ -628,10 +639,15 @@ __ns_ldap_DumpLdif(char *filename)
if (str == NULL)
continue;
/*
- * don't dump binddn, bind password, or cert path as they
- * are not part of version 2 profiles
+ * don't dump binddn, bind password, admin binddn, admin
+ * bind password, enableShadowUpdate flag, or cert path
+ * as they are not part of version 2 profiles
*/
- if ((i != NS_LDAP_BINDDN_P) && (i != NS_LDAP_BINDPASSWD_P) &&
+ if ((i != NS_LDAP_BINDDN_P) &&
+ (i != NS_LDAP_BINDPASSWD_P) &&
+ (i != NS_LDAP_ADMIN_BINDDN_P) &&
+ (i != NS_LDAP_ADMIN_BINDPASSWD_P) &&
+ (i != NS_LDAP_ENABLE_SHADOW_UPDATE_P) &&
(i != NS_LDAP_HOST_CERTPATH_P))
(void) fprintf(fp, "%s\n", str);
if (str != (char *)&string[0]) {
@@ -922,6 +938,7 @@ __ns_ldap_make_config(ns_ldap_result_t *result)
}
}
if (ptr->version != NS_LDAP_V1) {
+ ParamIndexType i;
if (curr_ptr->paramList[NS_LDAP_BINDDN_P].ns_ptype == CHARPTR) {
(void) __ns_ldap_setParamValue(ptr, NS_LDAP_BINDDN_P,
curr_ptr->paramList[NS_LDAP_BINDDN_P].ns_pc,
@@ -934,6 +951,28 @@ __ns_ldap_make_config(ns_ldap_result_t *result)
curr_ptr->paramList[NS_LDAP_BINDPASSWD_P].ns_pc,
&error);
}
+ i = NS_LDAP_ENABLE_SHADOW_UPDATE_P;
+ if (curr_ptr->paramList[i].ns_ptype == INT) {
+ char *val;
+ val = __s_get_shadowupdate_name(
+ curr_ptr->paramList[i].ns_i);
+ (void) __ns_ldap_setParamValue(ptr, i, val, &error);
+ }
+ if (curr_ptr->paramList[NS_LDAP_ADMIN_BINDDN_P].ns_ptype ==
+ CHARPTR) {
+ (void) __ns_ldap_setParamValue(ptr,
+ NS_LDAP_ADMIN_BINDDN_P,
+ curr_ptr->paramList[NS_LDAP_ADMIN_BINDDN_P].ns_pc,
+ &error);
+ }
+ if (curr_ptr->paramList[NS_LDAP_ADMIN_BINDPASSWD_P].ns_ptype ==
+ CHARPTR) {
+ (void) __ns_ldap_setParamValue(ptr,
+ NS_LDAP_ADMIN_BINDPASSWD_P,
+ curr_ptr->
+ paramList[NS_LDAP_ADMIN_BINDPASSWD_P].ns_pc,
+ &error);
+ }
if (curr_ptr->paramList[NS_LDAP_HOST_CERTPATH_P].ns_ptype ==
CHARPTR) {
(void) __ns_ldap_setParamValue(ptr,
@@ -1065,6 +1104,11 @@ __ns_ldap_print_config(int verbose)
if ((i == NS_LDAP_CACHETTL_P) && (ptr->version == NS_LDAP_V1))
continue;
+ /* the credential for shadow update is not to be exposed */
+ if (i == NS_LDAP_ADMIN_BINDDN_P ||
+ i == NS_LDAP_ADMIN_BINDPASSWD_P)
+ continue;
+
str = __s_api_strValue(ptr, string, BUFSIZ, i, NS_FILE_FMT);
if (str == NULL)
continue;
diff --git a/usr/src/lib/libsldap/common/ns_internal.h b/usr/src/lib/libsldap/common/ns_internal.h
index a7dbf4e6de..9adba43565 100644
--- a/usr/src/lib/libsldap/common/ns_internal.h
+++ b/usr/src/lib/libsldap/common/ns_internal.h
@@ -19,7 +19,7 @@
* 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.
*/
@@ -27,8 +27,6 @@
#ifndef _NS_INTERNAL_H
#define _NS_INTERNAL_H
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#ifdef __cplusplus
extern "C" {
#endif
@@ -118,6 +116,11 @@ extern "C" {
/* max rdn length in conversion routines used by __ns_ldap_addTypedEntry() */
#define RDNSIZE 256
+/*
+ * special service used by ldap_cachemgr to indicate a shadow update
+ * is to be done with the credential of the administrator identity
+ */
+#define NS_ADMIN_SHADOW_UPDATE "shadow__admin_update"
/* Phase 1 profile information */
#define _PROFILE1_OBJECTCLASS "SolarisNamingProfile"
@@ -316,6 +319,7 @@ typedef struct ns_enum_map {
#define INT2SECENUM(x) ((TlsType_t)(x))
#define INT2PREFONLYENUM(x) ((PrefOnly_t)(x))
#define INT2CREDLEVELENUM(x) ((CredLevel_t)(x))
+#define INT2SHADOWUPDATENUM(x) ((enableShadowUpdate_t)(x))
#define INT2LDAPRETURN(x) ((ns_ldap_return_code)(x))
#define INT2CONFIGRETURN(x) ((ns_ldap_config_return_code)(x))
@@ -736,6 +740,7 @@ char *__s_get_security_name(ns_config_t *ptr, TlsType_t type);
char *__s_get_scope_name(ns_config_t *ptr, ScopeType_t type);
char *__s_get_pref_name(PrefOnly_t type);
char *__s_get_searchref_name(ns_config_t *ptr, SearchRef_t type);
+char *__s_get_shadowupdate_name(enableShadowUpdate_t type);
char *__s_get_hostcertpath(void);
void __s_api_free_sessionPool();
int __s_api_requestServer(const char *request, const char *server,
diff --git a/usr/src/lib/libsldap/common/ns_sldap.h b/usr/src/lib/libsldap/common/ns_sldap.h
index af288c5cf2..f8bb420019 100644
--- a/usr/src/lib/libsldap/common/ns_sldap.h
+++ b/usr/src/lib/libsldap/common/ns_sldap.h
@@ -19,7 +19,7 @@
* 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.
*/
@@ -84,6 +84,13 @@ typedef enum ScopeType {
#define NS_LDAP_NOT_CVT_DN 0x2000
/*
+ * NS_LDAP_UPDATE_SHADOW is for a privileged caller of the
+ * __ns_ldap_repAttr() to update the shadow database on the
+ * LDAP server.
+ */
+#define NS_LDAP_UPDATE_SHADOW 0x4000
+
+/*
* Authentication Information
*/
typedef enum CredLevel {
@@ -126,6 +133,11 @@ typedef enum PrefOnly {
NS_LDAP_PREF_TRUE = 1
} PrefOnly_t;
+typedef enum enableShadowUpdate {
+ NS_LDAP_ENABLE_SHADOW_UPDATE_FALSE = 0,
+ NS_LDAP_ENABLE_SHADOW_UPDATE_TRUE = 1
+} enableShadowUpdate_t;
+
typedef struct UnixCred {
char *userID; /* Unix ID number */
char *passwd; /* password */
@@ -199,12 +211,15 @@ typedef enum {
NS_LDAP_SERVICE_AUTH_METHOD_P = 25,
NS_LDAP_SERVICE_CRED_LEVEL_P = 26,
NS_LDAP_HOST_CERTPATH_P = 27,
+ NS_LDAP_ENABLE_SHADOW_UPDATE_P = 28,
+ NS_LDAP_ADMIN_BINDDN_P = 29,
+ NS_LDAP_ADMIN_BINDPASSWD_P = 30,
/*
* The following entry (max ParamIndexType) is an internal
* placeholder. It must be the last (and highest value)
* entry in this eNum. Please update accordingly.
*/
- NS_LDAP_MAX_PIT_P = 28
+ NS_LDAP_MAX_PIT_P = 31
} ParamIndexType;
@@ -484,6 +499,11 @@ typedef struct ns_ldap_objectclass_map {
char *mappedOC; /* mapped objectclass */
} ns_ldap_objectclass_map_t;
+/*
+ * Value of the userPassword attribute representing NO Unix password
+ */
+#define NS_LDAP_NO_UNIX_PASSWORD "<NO UNIX PASSWORD>"
+
/* Opaque handle for batch API */
typedef struct ns_ldap_list_batch ns_ldap_list_batch_t;
@@ -872,6 +892,9 @@ int __ns_ldap_getParamType(
int __ns_ldap_getAcctMgmt(
const char *user,
AcctUsableResponse_t *acctResp);
+
+boolean_t __ns_ldap_is_shadow_update_enabled();
+
void
__ns_ldap_self_gssapi_only_set(
int flag);
diff --git a/usr/src/lib/libsldap/common/ns_writes.c b/usr/src/lib/libsldap/common/ns_writes.c
index 3abbefd829..14727d8a6b 100644
--- a/usr/src/lib/libsldap/common/ns_writes.c
+++ b/usr/src/lib/libsldap/common/ns_writes.c
@@ -19,12 +19,10 @@
* 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.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <stdio.h>
#include <sys/types.h>
#include <stdlib.h>
@@ -38,10 +36,13 @@
#include <lber.h>
#include <ldap.h>
#include <syslog.h>
+#include <stddef.h>
+#include <sys/mman.h>
#include "ns_sldap.h"
#include "ns_internal.h"
#include "ns_connmgmt.h"
+#include "ns_cache_door.h"
/* Additional headers for addTypedEntry Conversion routines */
#include <pwd.h>
@@ -60,7 +61,8 @@
#include <sys/tsol/tndb.h>
#include <tsol/label.h>
-
+static int send_to_cachemgr(const char *,
+ ns_ldap_attr_t **, ns_ldap_error_t **);
/*
* If the rdn is a mapped attr:
* return NS_LDAP_SUCCESS and a new_dn.
@@ -1038,8 +1040,8 @@ write_state_machine(
errmsg = NULL;
}
- (void) sprintf(errstr,
- gettext(ldap_err2string(Errno)));
+ (void) snprintf(errstr, sizeof (errstr),
+ "%s", ldap_err2string(Errno));
err = strdup(errstr);
if (pwd_status != NS_PASSWD_GOOD) {
MKERROR_PWD_MGMT(*errorp, Errno, err,
@@ -1157,6 +1159,89 @@ __ns_ldap_delAttr(
return (rc);
}
+/* Retrieve the admin bind password from the configuration, if allowed. */
+static int
+get_admin_passwd(ns_cred_t *cred, ns_ldap_error_t **errorp)
+{
+ void **paramVal = NULL;
+ int rc, ldaprc;
+ char *modparamVal = NULL;
+
+ /*
+ * For GSSAPI/Kerberos, host credential is used, no need to get
+ * admin bind password
+ */
+ if (cred->auth.saslmech == NS_LDAP_SASL_GSSAPI)
+ return (NS_LDAP_SUCCESS);
+
+ /*
+ * Retrieve admin bind password.
+ * The admin bind password is available
+ * only in the ldap_cachemgr process as
+ * they are not exposed outside of that
+ * process.
+ */
+ paramVal = NULL;
+ if ((ldaprc = __ns_ldap_getParam(NS_LDAP_ADMIN_BINDPASSWD_P,
+ &paramVal, errorp)) != NS_LDAP_SUCCESS)
+ return (ldaprc);
+ if (paramVal == NULL || *paramVal == NULL) {
+ rc = NS_LDAP_CONFIG;
+ *errorp = __s_api_make_error(NS_CONFIG_NODEFAULT,
+ gettext("Admin bind password not configured"));
+ if (*errorp == NULL)
+ rc = NS_LDAP_MEMORY;
+ return (rc);
+ }
+ modparamVal = dvalue((char *)*paramVal);
+ (void) memset(*paramVal, 0, strlen((char *)*paramVal));
+ (void) __ns_ldap_freeParam(&paramVal);
+ if (modparamVal == NULL || *((char *)modparamVal) == '\0') {
+ if (modparamVal != NULL)
+ free(modparamVal);
+ rc = NS_LDAP_CONFIG;
+ *errorp = __s_api_make_error(NS_CONFIG_SYNTAX,
+ gettext("bind password not valid"));
+ if (*errorp == NULL)
+ rc = NS_LDAP_MEMORY;
+ return (rc);
+ }
+
+ cred->cred.unix_cred.passwd = modparamVal;
+ return (NS_LDAP_SUCCESS);
+}
+
+boolean_t
+__ns_ldap_is_shadow_update_enabled() {
+
+ int **enable_shadow = NULL;
+
+ if (__ns_ldap_getParam(NS_LDAP_ENABLE_SHADOW_UPDATE_P,
+ (void ***)&enable_shadow, NULL) != NS_LDAP_SUCCESS) {
+ return (B_FALSE);
+ }
+ if ((enable_shadow != NULL && *enable_shadow != NULL) &&
+ (*enable_shadow[0] == NS_LDAP_ENABLE_SHADOW_UPDATE_TRUE)) {
+ (void) __ns_ldap_freeParam((void ***)&enable_shadow);
+ return (B_TRUE);
+ }
+ if (enable_shadow != NULL)
+ (void) __ns_ldap_freeParam((void ***)&enable_shadow);
+ return (B_FALSE);
+}
+
+/*
+ * __ns_ldap_repAttr modifies ldap attributes of the 'dn' entry stored
+ * on the LDAP server. 'service' indicates the type of database entries
+ * to modify. When the Native LDAP client is configured with 'shadow update
+ * enabled', Shadowshadow(4) entries can only be modified by privileged users.
+ * Such users use the NS_LDAP_UPDATE_SHADOW flag to indicate the call is
+ * for such a shadow(4) update, which would be forwarded to ldap_cachemgr
+ * for performing the LDAP modify operation. ldap_cachemgr would call
+ * this function again and use the special service NS_ADMIN_SHADOW_UPDATE
+ * to identify itself, so that admin credential would be obtained and
+ * the actual LDAP modify operation be done.
+ */
/*ARGSUSED*/
int
__ns_ldap_repAttr(
@@ -1169,6 +1254,8 @@ __ns_ldap_repAttr(
{
LDAPMod **mods;
int rc = 0;
+ boolean_t priv;
+ boolean_t shadow_update_enabled = B_FALSE;
#ifdef DEBUG
(void) fprintf(stderr, "__ns_ldap_repAttr START\n");
@@ -1176,13 +1263,59 @@ __ns_ldap_repAttr(
*errorp = NULL;
/* Sanity check */
- if ((attr == NULL) || (*attr == NULL) ||
- (dn == NULL) || (cred == NULL))
+ if (attr == NULL || *attr == NULL || dn == NULL)
+ return (NS_LDAP_INVALID_PARAM);
+
+ /* Privileged shadow modify? */
+ if ((flags & NS_LDAP_UPDATE_SHADOW) != 0 &&
+ strcmp(service, "shadow") == 0) {
+
+ /* Shadow update enabled ? If not, error out */
+ shadow_update_enabled = __ns_ldap_is_shadow_update_enabled();
+ if (!shadow_update_enabled) {
+ *errorp = __s_api_make_error(NS_CONFIG_NOTALLOW,
+ gettext("Shadow Update is not enabled"));
+ return (NS_LDAP_CONFIG);
+ }
+
+ /* privileged shadow modify requires euid 0 or all zone privs */
+ priv = (geteuid() == 0);
+ if (!priv) {
+ priv_set_t *ps = priv_allocset(); /* caller */
+ priv_set_t *zs; /* zone */
+
+ (void) getppriv(PRIV_EFFECTIVE, ps);
+ zs = priv_str_to_set("zone", ",", NULL);
+ priv = priv_isequalset(ps, zs);
+ priv_freeset(ps);
+ priv_freeset(zs);
+ }
+ if (!priv)
+ return (NS_LDAP_OP_FAILED);
+
+ rc = send_to_cachemgr(dn, (ns_ldap_attr_t **)attr, errorp);
+ return (rc);
+ }
+
+ if (cred == NULL)
return (NS_LDAP_INVALID_PARAM);
+
+ /*
+ * If service is NS_ADMIN_SHADOW_UPDATE, the caller should be
+ * ldap_cachemgr. We need to get the admin cred to do work.
+ * If the caller is not ldap_cachemgr, but use the service
+ * NS_ADMIN_SHADOW_UPDATE, get_admin_passwd() will fail,
+ * as the admin cred is not available to the caller.
+ */
+ if (strcmp(service, NS_ADMIN_SHADOW_UPDATE) == 0) {
+ if ((rc = get_admin_passwd((ns_cred_t *)cred, errorp)) !=
+ NS_LDAP_SUCCESS)
+ return (rc);
+ }
+
mods = __s_api_makeModList(service, attr, LDAP_MOD_REPLACE, flags);
- if (mods == NULL) {
+ if (mods == NULL)
return (NS_LDAP_MEMORY);
- }
rc = write_state_machine(LDAP_REQ_MODIFY,
(char *)dn, mods, cred, flags, errorp);
@@ -1191,7 +1324,6 @@ __ns_ldap_repAttr(
return (rc);
}
-
/*ARGSUSED*/
int
__ns_ldap_addEntry(
@@ -3793,3 +3925,157 @@ __s_api_append_default_basedn(
(void) __ns_ldap_freeParam(&param);
return (NS_LDAP_SUCCESS);
}
+
+/*
+ * Flatten the input ns_ldap_attr_t list, 'attr', and convert it into an
+ * ldap_strlist_t structure in buffer 'buf', to be used by ldap_cachemgr.
+ * The output contains a count, a list of offsets, which show where the
+ * corresponding copied attribute type and attribute value are located.
+ * For example, for dn=aaaa, userpassword=bbbb, shadowlastchange=cccc,
+ * the output is the ldap_strlist_t structure with: ldap_count = 6,
+ * (buf + ldap_offsets[0]) -> "dn"
+ * (buf + ldap_offsets[1]) -> "aaaa"
+ * (buf + ldap_offsets[2]) -> "userPassword"
+ * (buf + ldap_offsets[3]) -> "bbbb"
+ * (buf + ldap_offsets[4]) -> "shadowlastchange"
+ * (buf + ldap_offsets[5]) -> "cccc"
+ * and all the string data shown above copied into the buffer after
+ * the offset array. The total length of the data will be the return
+ * value, or -1 if error.
+ */
+static int
+attr2list(const char *dn, ns_ldap_attr_t **attr,
+ char *buf, int bufsize)
+{
+ int c = 0;
+ char *ap;
+ int ao;
+ ldap_strlist_t *al = (ldap_strlist_t *)buf;
+ ns_ldap_attr_t *a = (ns_ldap_attr_t *)*attr;
+ ns_ldap_attr_t **aptr = (ns_ldap_attr_t **)attr;
+
+ /* bufsize > strlen(dn) + strlen("dn") + 1 ('\0') */
+ if ((strlen(dn) + 2 + 1) >= bufsize)
+ return (-1);
+
+ /* count number of attributes */
+ while (*aptr++)
+ c++;
+ al->ldap_count = 2 + c * 2;
+ ao = sizeof (al->ldap_count) + sizeof (al->ldap_offsets[0]) *
+ al->ldap_count;
+ if (ao > bufsize)
+ return (-1);
+ al->ldap_offsets[0] = ao;
+ ap = buf + ao;
+ ao += 3;
+
+ /* copy entry DN */
+ if (ao > bufsize)
+ return (-1);
+ (void) strlcpy(ap, "dn", bufsize);
+ ap += 3;
+
+ al->ldap_offsets[1] = ao;
+ ao += strlen(dn) + 1;
+ if (ao > bufsize)
+ return (-1);
+ (void) strlcpy(ap, dn, bufsize);
+ ap = buf + ao;
+
+ aptr = attr;
+ for (c = 2; c < al->ldap_count; c++, aptr++) {
+ a = *aptr;
+ if (a->attrname == NULL || a->attrvalue == NULL ||
+ a->value_count != 1 || a->attrvalue[0] == NULL)
+ return (-1);
+ al->ldap_offsets[c] = ao;
+ ao += strlen(a->attrname) + 1;
+ if (ao > bufsize)
+ return (-1);
+ (void) strlcpy(ap, a->attrname, bufsize);
+ ap = buf + ao;
+
+ c++;
+ al->ldap_offsets[c] = ao;
+ ao += strlen(a->attrvalue[0]) + 1;
+ (void) strlcpy(ap, a->attrvalue[0], bufsize);
+ ap = buf + ao;
+ };
+
+ return (ao);
+}
+
+/*
+ * Send a modify request to the ldap_cachemgr daemon
+ * which will use the admin credential to perform the
+ * operation.
+ */
+
+static int
+send_to_cachemgr(
+ const char *dn,
+ ns_ldap_attr_t **attr,
+ ns_ldap_error_t **errorp)
+{
+ union {
+ ldap_data_t s_d;
+ char s_b[DOORBUFFERSIZE];
+ } space;
+
+ ldap_data_t *sptr;
+ int ndata;
+ int adata;
+ int len;
+ int rc;
+ char errstr[MAXERROR];
+ ldap_admin_mod_result_t *admin_result;
+
+ *errorp = NULL;
+ (void) memset(space.s_b, 0, DOORBUFFERSIZE);
+ len = attr2list(dn, attr, (char *)&space.s_d.ldap_call.ldap_u.strlist,
+ sizeof (space) - offsetof(ldap_return_t, ldap_u));
+ if (len <= 0)
+ return (NS_LDAP_INVALID_PARAM);
+
+ adata = sizeof (ldap_call_t) + len;
+ ndata = sizeof (space);
+ space.s_d.ldap_call.ldap_callnumber = ADMINMODIFY;
+ sptr = &space.s_d;
+
+ switch (__ns_ldap_trydoorcall(&sptr, &ndata, &adata)) {
+ case NS_CACHE_SUCCESS:
+ break;
+ case NS_CACHE_NOTFOUND:
+ (void) snprintf(errstr, sizeof (errstr),
+ gettext("Door call ADMINMODIFY to "
+ "ldap_cachemgr failed - error: %d"),
+ space.s_d.ldap_ret.ldap_errno);
+ MKERROR(LOG_WARNING, *errorp, NS_CONFIG_CACHEMGR,
+ strdup(errstr), NULL);
+ return (NS_LDAP_OP_FAILED);
+ break;
+ default:
+ return (NS_LDAP_OP_FAILED);
+ }
+
+ admin_result = &sptr->ldap_ret.ldap_u.admin_result;
+ if (admin_result->ns_err == NS_LDAP_SUCCESS)
+ rc = NS_LDAP_SUCCESS;
+ else {
+ rc = admin_result->ns_err;
+ if (admin_result->msg_size == 0)
+ *errorp = __s_api_make_error(admin_result->status,
+ NULL);
+ else
+ *errorp = __s_api_make_error(admin_result->status,
+ admin_result->msg);
+ }
+
+ /* clean up the door call */
+ if (sptr != &space.s_d) {
+ (void) munmap((char *)sptr, ndata);
+ }
+
+ return (rc);
+}
diff --git a/usr/src/lib/nsswitch/ldap/common/getspent.c b/usr/src/lib/nsswitch/ldap/common/getspent.c
index a533300a08..bcdba2998c 100644
--- a/usr/src/lib/nsswitch/ldap/common/getspent.c
+++ b/usr/src/lib/nsswitch/ldap/common/getspent.c
@@ -19,11 +19,10 @@
* 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.
*/
-
#include <shadow.h>
#include <stdlib.h>
#include "ldap_common.h"
@@ -31,6 +30,12 @@
/* shadow attributes filters */
#define _S_UID "uid"
#define _S_USERPASSWORD "userpassword"
+#define _S_LASTCHANGE "shadowlastchange"
+#define _S_MIN "shadowmin"
+#define _S_MAX "shadowmax"
+#define _S_WARNING "shadowwarning"
+#define _S_INACTIVE "shadowinactive"
+#define _S_EXPIRE "shadowexpire"
#define _S_FLAG "shadowflag"
#define _F_GETSPNAM "(&(objectClass=shadowAccount)(uid=%s))"
@@ -39,6 +44,12 @@
static const char *sp_attrs[] = {
_S_UID,
_S_USERPASSWORD,
+ _S_LASTCHANGE,
+ _S_MIN,
+ _S_MAX,
+ _S_WARNING,
+ _S_INACTIVE,
+ _S_EXPIRE,
_S_FLAG,
(char *)NULL
};
@@ -59,11 +70,15 @@ _nss_ldap_shadow2str(ldap_backend_ptr be, nss_XbyY_args_t *argp)
{
int nss_result;
int buflen = 0;
+ int shadow_update_enabled;
unsigned long len = 0L;
char *tmp, *buffer = NULL;
char *pw_passwd = NULL;
ns_ldap_result_t *result = be->result;
- char **uid, **passwd, **flag, *flag_str;
+ char **uid, **passwd, **last, **smin, **smax;
+ char **warning, **inactive, **expire, **flag;
+ char *last_str, *min_str, *max_str, *warning_str;
+ char *inactive_str, *expire_str, *flag_str;
if (result == NULL)
return (NSS_STR_PARSE_PARSE);
@@ -94,11 +109,15 @@ _nss_ldap_shadow2str(ldap_backend_ptr be, nss_XbyY_args_t *argp)
goto result_spd2str;
} else {
if ((tmp = strstr(passwd[0], "{crypt}")) != NULL ||
- (tmp = strstr(passwd[0], "{CRYPT}")) != NULL) {
+ (tmp = strstr(passwd[0], "{CRYPT}")) != NULL) {
if (tmp != passwd[0])
pw_passwd = NOPWDRTR;
- else
+ else {
pw_passwd = tmp + strlen("{crypt}");
+ if (strcmp(pw_passwd,
+ NS_LDAP_NO_UNIX_PASSWORD) == 0)
+ *pw_passwd = '\0';
+ }
} else {
/* mark password as not retrievable */
pw_passwd = NOPWDRTR;
@@ -107,19 +126,66 @@ _nss_ldap_shadow2str(ldap_backend_ptr be, nss_XbyY_args_t *argp)
len += strlen(pw_passwd);
/*
- * Ignore the following password aging related attributes:
+ * If shadow update is not enabled, ignore the following
+ * password aging related attributes:
* -- shadowlastchange
* -- shadowmin
* -- shadowmax
* -- shadowwarning
* -- shadowinactive
* -- shadowexpire
- * This is because the LDAP naming service does not
- * really support the password aging fields defined
- * in the shadow structure. These fields, sp_lstchg,
+ * When shadow update is not enabled, the LDAP naming
+ * service does not support the password aging fields
+ * defined in the shadow structure. These fields, sp_lstchg,
* sp_min, sp_max, sp_warn, sp_inact, and sp_expire,
* will be set to -1 by the front end marshaller.
*/
+
+ shadow_update_enabled = __ns_ldap_is_shadow_update_enabled();
+ if (shadow_update_enabled) {
+ last = __ns_ldap_getAttr(result->entry, _S_LASTCHANGE);
+ if (last == NULL || last[0] == NULL)
+ last_str = _NO_VALUE;
+ else
+ last_str = last[0];
+ len += strlen(last_str);
+
+ smin = __ns_ldap_getAttr(result->entry, _S_MIN);
+ if (smin == NULL || smin[0] == NULL)
+ min_str = _NO_VALUE;
+ else
+ min_str = smin[0];
+ len += strlen(min_str);
+
+ smax = __ns_ldap_getAttr(result->entry, _S_MAX);
+ if (smax == NULL || smax[0] == NULL)
+ max_str = _NO_VALUE;
+ else
+ max_str = smax[0];
+ len += strlen(max_str);
+
+ warning = __ns_ldap_getAttr(result->entry, _S_WARNING);
+ if (warning == NULL || warning[0] == NULL)
+ warning_str = _NO_VALUE;
+ else
+ warning_str = warning[0];
+ len += strlen(warning_str);
+
+ inactive = __ns_ldap_getAttr(result->entry, _S_INACTIVE);
+ if (inactive == NULL || inactive[0] == NULL)
+ inactive_str = _NO_VALUE;
+ else
+ inactive_str = inactive[0];
+ len += strlen(inactive_str);
+
+ expire = __ns_ldap_getAttr(result->entry, _S_EXPIRE);
+ if (expire == NULL || expire[0] == NULL)
+ expire_str = _NO_VALUE;
+ else
+ expire_str = expire[0];
+ len += strlen(expire_str);
+ }
+
flag = __ns_ldap_getAttr(result->entry, _S_FLAG);
if (flag == NULL || flag[0] == NULL)
flag_str = _NO_VALUE;
@@ -144,8 +210,14 @@ _nss_ldap_shadow2str(ldap_backend_ptr be, nss_XbyY_args_t *argp)
} else
buffer = argp->buf.buffer;
- (void) snprintf(buffer, len, "%s:%s:::::::%s",
- uid[0], pw_passwd, flag_str);
+ if (shadow_update_enabled) {
+ (void) snprintf(buffer, len, "%s:%s:%s:%s:%s:%s:%s:%s:%s",
+ uid[0], pw_passwd, last_str, min_str, max_str, warning_str,
+ inactive_str, expire_str, flag_str);
+ } else {
+ (void) snprintf(buffer, len, "%s:%s:::::::%s",
+ uid[0], pw_passwd, flag_str);
+ }
/* The front end marhsaller doesn't need the trailing null */
if (argp->buf.result != NULL)
@@ -185,7 +257,7 @@ getbynam(ldap_backend_ptr be, void *a)
return ((nss_status_t)NSS_NOTFOUND);
return (_nss_ldap_lookup(be, argp, _SHADOW, searchfilter, NULL,
- _merge_SSD_filter, userdata));
+ _merge_SSD_filter, userdata));
}
static ldap_backend_op_t sp_ops[] = {
@@ -210,6 +282,6 @@ _nss_ldap_shadow_constr(const char *dummy1, const char *dummy2,
{
return ((nss_backend_t *)_nss_ldap_constr(sp_ops,
- sizeof (sp_ops)/sizeof (sp_ops[0]),
- _SHADOW, sp_attrs, _nss_ldap_shadow2str));
+ sizeof (sp_ops)/sizeof (sp_ops[0]),
+ _SHADOW, sp_attrs, _nss_ldap_shadow2str));
}
diff --git a/usr/src/lib/passwdutil/__failed_count.c b/usr/src/lib/passwdutil/__failed_count.c
index 777408d3b5..a72a2fba26 100644
--- a/usr/src/lib/passwdutil/__failed_count.c
+++ b/usr/src/lib/passwdutil/__failed_count.c
@@ -19,12 +19,10 @@
* 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.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <string.h>
#include <syslog.h>
#include "passwdutil.h"
@@ -35,23 +33,31 @@ __incr_failed_count(char *username, char *repname, int max_failures)
int ret;
void *buf;
attrlist items[1];
- repops_t *ops = rops[REP_FILES];
+ int repnum = name_to_int(repname);
+ repops_t *ops;
- /* account locking only defined for files */
- if (strcmp(repname, "files") != 0)
+ /* account locking only defined for files and ldap */
+ if ((repnum != REP_FILES) &&
+ (repnum != REP_LDAP)) {
return (PWU_SUCCESS);
+ }
- if ((ret = ops->lock()) != PWU_SUCCESS)
+ ops = rops[repnum];
+ if ((ops->lock != NULL) &&
+ (ret = ops->lock()) != PWU_SUCCESS) {
return (ret);
+ }
items[0].type = ATTR_INCR_FAILED_LOGINS;
items[0].next = NULL;
- if ((ret = ops->getpwnam(username, items, NULL, &buf)) != PWU_SUCCESS)
+ if ((ret = ops->getpwnam(username, items, NULL, &buf)) != PWU_SUCCESS) {
goto out;
+ }
/* We increment the failed count by one */
- if ((ret = ops->update(items, NULL, buf)) != PWU_SUCCESS)
+ if ((ret = ops->update(items, NULL, buf)) != PWU_SUCCESS) {
goto out;
+ }
/* Did we just exceed "max_failures" ? */
if (items[0].data.val_i >= max_failures) {
@@ -69,7 +75,9 @@ __incr_failed_count(char *username, char *repname, int max_failures)
ret = PWU_ACCOUNT_LOCKED;
out:
- ops->unlock();
+ if (ops->unlock != NULL) {
+ ops->unlock();
+ }
return (ret);
}
@@ -84,14 +92,20 @@ __rst_failed_count(char *username, char *repname)
int ret;
void *buf;
attrlist items[1];
- repops_t *ops = rops[REP_FILES];
+ int repnum = name_to_int(repname);
+ repops_t *ops;
- /* account locking only defined for files */
- if (strcmp(repname, "files") != 0)
+ /* account locking only defined for files and ldap */
+ if ((repnum != REP_FILES) &&
+ (repnum != REP_LDAP)) {
return (PWU_SUCCESS);
+ }
- if ((ret = ops->lock()) != PWU_SUCCESS)
+ ops = rops[repnum];
+ if ((ops->lock != NULL) &&
+ (ret = ops->lock()) != PWU_SUCCESS) {
return (ret);
+ }
items[0].type = ATTR_RST_FAILED_LOGINS;
items[0].next = NULL;
@@ -101,7 +115,9 @@ __rst_failed_count(char *username, char *repname)
goto out;
ret = ops->putpwnam(username, NULL, NULL, NULL, buf);
out:
- ops->unlock();
+ if (ops->unlock != NULL) {
+ ops->unlock();
+ }
return (ret != PWU_SUCCESS ? ret : items[0].data.val_i);
}
diff --git a/usr/src/lib/passwdutil/ldap_attr.c b/usr/src/lib/passwdutil/ldap_attr.c
index 7cf40be7a1..7a29614bf3 100644
--- a/usr/src/lib/passwdutil/ldap_attr.c
+++ b/usr/src/lib/passwdutil/ldap_attr.c
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
@@ -20,17 +19,17 @@
* CDDL HEADER END
*/
/*
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
+#include <macros.h>
+#include <priv.h>
#include "ns_sldap.h"
@@ -45,6 +44,32 @@
#include "utils.h"
+#define MAX_INT_LEN 11 /* 10+1 %d buflen for words/ints [not longs] */
+
+#define STRDUP_OR_RET(to, from) \
+ if ((to = strdup(from)) == NULL) \
+ return (PWU_NOMEM);
+
+#define STRDUP_OR_ERR(to, from, err) \
+ if (((to) = strdup(from)) == NULL) \
+ (err) = PWU_NOMEM;
+
+#define NUM_TO_STR(to, from) \
+ { \
+ char nb[MAX_INT_LEN]; \
+ if (snprintf(nb, MAX_INT_LEN, "%d", (from)) >= MAX_INT_LEN) \
+ return (PWU_NOMEM); \
+ STRDUP_OR_RET(to, nb); \
+ }
+
+#define NEW_ATTR(p, i, attr, val) \
+ { \
+ p[i] = new_attr(attr, (val)); \
+ if (p[i] == NULL) \
+ return (PWU_NOMEM); \
+ i++; \
+ }
+
int ldap_getattr(char *name, attrlist *item, pwu_repository_t *rep);
int ldap_getpwnam(char *name, attrlist *items, pwu_repository_t *rep,
void **buf);
@@ -73,9 +98,14 @@ struct repops ldap_repops = {
* structure used to keep state between get/update/put calls
*/
typedef struct {
- char *passwd; /* encrypted password */
+ char *passwd; /* encrypted password */
struct passwd *pwd;
- ns_ldap_attr_t **attrs;
+ ns_ldap_attr_t **pattrs; /* passwd attrs */
+ int npattrs; /* max attrs */
+ struct spwd *spwd;
+ ns_ldap_attr_t **sattrs; /* passwd attrs */
+ int nsattrs; /* max attrs */
+ boolean_t shadow_update_enabled; /* shadow update configured */
} ldapbuf_t;
/*
@@ -94,15 +124,70 @@ typedef struct {
#define _PWD_HOMEDIRECTORY "homedirectory"
#define _PWD_LOGINSHELL "loginshell"
+#define _PWD_MAX_ATTR 10 /* 9+NULL */
+
+/* shadow attributes filters */
+#define _S_LASTCHANGE "shadowlastchange"
+#define _S_MIN "shadowmin"
+#define _S_MAX "shadowmax"
+#define _S_WARNING "shadowwarning"
+#define _S_INACTIVE "shadowinactive"
+#define _S_EXPIRE "shadowexpire"
+#define _S_FLAG "shadowflag"
+
+#define _S_MAX_ATTR 8 /* 7+NULL */
+
+/*
+ * Frees up an ldapbuf_t
+ */
+
+static void
+free_ldapbuf(ldapbuf_t *p)
+{
+ int i;
+
+ if (p == NULL)
+ return;
+ if (p->passwd) {
+ (void) memset(p->passwd, 0, strlen(p->passwd));
+ free(p->passwd);
+ }
+ if (p->pwd)
+ free_pwd(p->pwd);
+ if (p->spwd)
+ free_spwd(p->spwd);
+ if (p->pattrs) {
+ for (i = 0; i < p->npattrs; i++) {
+ if (p->pattrs[i] != NULL) {
+ free(p->pattrs[i]->attrvalue[0]);
+ free(p->pattrs[i]);
+ }
+ }
+ free(p->pattrs);
+ }
+ if (p->sattrs) {
+ for (i = 0; i < p->nsattrs; i++) {
+ if (p->sattrs[i] != NULL) {
+ free(p->sattrs[i]->attrvalue[0]);
+ free(p->sattrs[i]);
+ }
+ }
+ free(p->sattrs);
+ }
+}
+
/*
* int ldap_user_to_authenticate(user, rep, auth_user, privileged)
*
- * We can't determine whether the user is "privileged" in the LDAP
- * sense. The operation should be attempted and will succeed if
- * the user had privileges.
- *
- * For our purposes, we say that the user is privileged if he/she
- * is attempting to change another user's password attributes.
+ * If the Shadow Update functionality is enabled, then we check to
+ * see if the caller has 0 as the euid or has all zone privs. If so,
+ * the caller would be able to modify shadow(4) data stored on the
+ * LDAP server. Otherwise, when LDAP Shadow Update is not enabled,
+ * we can't determine whether the user is "privileged" in the LDAP
+ * sense. The operation should be attempted and will succeed if the
+ * user had privileges. For our purposes, we say that the user is
+ * privileged if he/she is attempting to change another user's
+ * password attributes.
*/
int
ldap_user_to_authenticate(char *user, pwu_repository_t *rep,
@@ -121,11 +206,47 @@ ldap_user_to_authenticate(char *user, pwu_repository_t *rep,
uid = getuid();
+ /*
+ * need equivalent of write access to /etc/shadow
+ * the privilege escalation model is euid == 0 || all zone privs
+ */
+ if (__ns_ldap_is_shadow_update_enabled()) {
+ boolean_t priv;
+
+ priv = (geteuid() == 0);
+ if (!priv) {
+ priv_set_t *ps = priv_allocset(); /* caller */
+ priv_set_t *zs; /* zone */
+
+ (void) getppriv(PRIV_EFFECTIVE, ps);
+ zs = priv_str_to_set("zone", ",", NULL);
+ priv = priv_isequalset(ps, zs);
+ priv_freeset(ps);
+ priv_freeset(zs);
+ }
+ /*
+ * priv can change anyone's password,
+ * only root isn't prompted.
+ */
+ *privileged = 0; /* for proper prompting */
+ if (priv) {
+ if (uid == 0) {
+ *privileged = 1;
+ *auth_user = NULL;
+ return (res);
+ } else if (uid == pw->pw_uid) {
+ STRDUP_OR_ERR(*auth_user, user, res);
+ return (res);
+ }
+ }
+
+ return (PWU_DENIED);
+ }
+
if (uid == pw->pw_uid) {
- /* changing out own, not privileged */
+ /* changing our own, not privileged */
*privileged = 0;
- if ((*auth_user = strdup(user)) == NULL)
- res = PWU_NOMEM;
+ STRDUP_OR_RET(*auth_user, user);
} else {
char pwd_buf[1024];
struct passwd pwr;
@@ -141,17 +262,15 @@ ldap_user_to_authenticate(char *user, pwu_repository_t *rep,
priviledged_uid = uid;
}
if (getpwuid_r(priviledged_uid, &pwr, pwd_buf,
- sizeof (pwd_buf)) != NULL) {
- if ((*auth_user = strdup(pwr.pw_name)) == NULL)
- res = PWU_NOMEM;
+ sizeof (pwd_buf)) != NULL) {
+ STRDUP_OR_ERR(*auth_user, pwr.pw_name, res);
} else {
/* hmm. can't find name of current user...??? */
-#define MAX_UID_LEN 11 /* UID's larger than 2^32 won't fit... */
- if ((*auth_user = malloc(MAX_UID_LEN)) == NULL) {
+ if ((*auth_user = malloc(MAX_INT_LEN)) == NULL) {
res = PWU_NOMEM;
} else {
- (void) snprintf(*auth_user, MAX_UID_LEN, "%d",
+ (void) snprintf(*auth_user, MAX_INT_LEN, "%d",
(int)uid);
}
}
@@ -169,70 +288,45 @@ ldap_user_to_authenticate(char *user, pwu_repository_t *rep,
int
ldap_getattr(char *name, attrlist *items, pwu_repository_t *rep)
{
+ attrlist *w;
int res;
+ ldapbuf_t *ldapbuf;
struct passwd *pw = NULL;
struct spwd *spw = NULL;
- attrlist *w;
- int need_shadow = 0; /* Need shadow info from LDAP server */
- int need_normal = 0; /* Need non-shadow info from LDAP server */
+ res = ldap_getpwnam(name, items, rep, (void **)&ldapbuf);
+ if (res != PWU_SUCCESS)
+ return (res);
- /* We need the "shadow" map for the password only */
- for (w = items; w != NULL; w = w->next) {
- if (w->type == ATTR_PASSWD ||
- w->type == ATTR_PASSWD_SERVER_POLICY)
- need_shadow = 1;
- else
- need_normal = 1;
- }
-
- if (need_normal) {
- res = dup_pw(&pw, getpwnam_from(name, rep, REP_LDAP));
- if (res != PWU_SUCCESS)
- goto out;
- }
-
- if (need_shadow) {
- res = dup_spw(&spw, getspnam_from(name, rep, REP_LDAP));
- if (res != PWU_SUCCESS) {
- goto out;
- }
- }
+ pw = ldapbuf->pwd;
+ spw = ldapbuf->spwd;
for (w = items; res == PWU_SUCCESS && w != NULL; w = w->next) {
switch (w->type) {
case ATTR_NAME:
- if ((w->data.val_s = strdup(pw->pw_name)) == NULL)
- res = PWU_NOMEM;
+ STRDUP_OR_ERR(w->data.val_s, pw->pw_name, res);
break;
case ATTR_COMMENT:
- if ((w->data.val_s = strdup(pw->pw_comment)) == NULL)
- res = PWU_NOMEM;
+ STRDUP_OR_ERR(w->data.val_s, pw->pw_comment, res);
break;
case ATTR_GECOS:
- if ((w->data.val_s = strdup(pw->pw_gecos)) == NULL)
- res = PWU_NOMEM;
+ STRDUP_OR_ERR(w->data.val_s, pw->pw_gecos, res);
break;
case ATTR_HOMEDIR:
- if ((w->data.val_s = strdup(pw->pw_dir)) == NULL)
- res = PWU_NOMEM;
+ STRDUP_OR_ERR(w->data.val_s, pw->pw_dir, res);
break;
case ATTR_SHELL:
- if ((w->data.val_s = strdup(pw->pw_shell)) == NULL)
- res = PWU_NOMEM;
+ STRDUP_OR_ERR(w->data.val_s, pw->pw_shell, res);
break;
case ATTR_PASSWD:
case ATTR_PASSWD_SERVER_POLICY:
- if ((w->data.val_s = strdup(spw->sp_pwdp)) == NULL)
- res = PWU_NOMEM;
+ STRDUP_OR_ERR(w->data.val_s, spw->sp_pwdp, res);
break;
case ATTR_AGE:
- if ((w->data.val_s = strdup(pw->pw_age)) == NULL)
- res = PWU_NOMEM;
+ STRDUP_OR_ERR(w->data.val_s, pw->pw_age, res);
break;
case ATTR_REP_NAME:
- if ((w->data.val_s = strdup("ldap")) == NULL)
- res = PWU_NOMEM;
+ STRDUP_OR_ERR(w->data.val_s, "ldap", res);
break;
/* integer values */
@@ -243,24 +337,47 @@ ldap_getattr(char *name, attrlist *items, pwu_repository_t *rep)
w->data.val_i = pw->pw_gid;
break;
case ATTR_LSTCHG:
- w->data.val_i = -1;
+ if (ldapbuf->shadow_update_enabled)
+ w->data.val_i = spw->sp_lstchg;
+ else
+ w->data.val_i = -1;
break;
case ATTR_MIN:
- w->data.val_i = -1;
+ if (ldapbuf->shadow_update_enabled)
+ w->data.val_i = spw->sp_min;
+ else
+ w->data.val_i = -1;
break;
case ATTR_MAX:
- w->data.val_i = -1;
+ if (ldapbuf->shadow_update_enabled)
+ w->data.val_i = spw->sp_max;
+ else
+ w->data.val_i = -1;
break;
case ATTR_WARN:
- w->data.val_i = -1;
+ if (ldapbuf->shadow_update_enabled)
+ w->data.val_i = spw->sp_warn;
+ else
+ w->data.val_i = -1;
break;
case ATTR_INACT:
- w->data.val_i = -1;
+ if (ldapbuf->shadow_update_enabled)
+ w->data.val_i = spw->sp_inact;
+ else
+ w->data.val_i = -1;
break;
case ATTR_EXPIRE:
- w->data.val_i = -1;
+ if (ldapbuf->shadow_update_enabled)
+ w->data.val_i = spw->sp_expire;
+ else
+ w->data.val_i = -1;
break;
case ATTR_FLAG:
+ if (ldapbuf->shadow_update_enabled)
+ w->data.val_i = spw->sp_flag;
+ break;
+ case ATTR_FAILED_LOGINS:
+ w->data.val_i = spw->sp_flag & FAILCOUNT_MASK;
break;
default:
break;
@@ -268,11 +385,8 @@ ldap_getattr(char *name, attrlist *items, pwu_repository_t *rep)
}
out:
- if (pw)
- free_pwd(pw);
- if (spw)
- free_spwd(spw);
-
+ free_ldapbuf(ldapbuf);
+ free(ldapbuf);
return (res);
}
@@ -292,45 +406,54 @@ int
ldap_getpwnam(char *name, attrlist *items, pwu_repository_t *rep,
void **buf)
{
- attrlist *p;
- int nr_items;
- int need_pwd = 0;
ldapbuf_t *ldapbuf;
- int res;
-
- for (nr_items = 0, p = items; p != NULL; p = p->next) {
- nr_items++;
- if (p->type == ATTR_PASSWD ||
- p->type == ATTR_PASSWD_SERVER_POLICY)
- need_pwd = 1;
- }
+ int res = PWU_NOMEM;
+ /*
+ * [sp]attrs is treated as NULL terminated
+ */
ldapbuf = calloc(1, sizeof (ldapbuf_t));
if (ldapbuf == NULL)
return (PWU_NOMEM);
- ldapbuf->attrs = calloc(nr_items, sizeof (ns_ldap_attr_t *));
- if (ldapbuf->attrs == NULL)
- return (PWU_NOMEM);
+ ldapbuf->pattrs = calloc(_PWD_MAX_ATTR, sizeof (ns_ldap_attr_t *));
+ if (ldapbuf->pattrs == NULL)
+ goto out;
+ ldapbuf->npattrs = _PWD_MAX_ATTR;
- if (need_pwd) {
- struct spwd *spw;
+ ldapbuf->sattrs = calloc(_S_MAX_ATTR, sizeof (ns_ldap_attr_t *));
+ if (ldapbuf->sattrs == NULL)
+ goto out;
+ ldapbuf->nsattrs = _S_MAX_ATTR;
- res = dup_pw(&ldapbuf->pwd, getpwnam_from(name, rep, REP_LDAP));
- if (res != PWU_SUCCESS)
- return (res);
+ res = dup_pw(&ldapbuf->pwd, getpwnam_from(name, rep, REP_LDAP));
+ if (res != PWU_SUCCESS)
+ goto out;
- spw = getspnam_from(name, rep, REP_LDAP);
- if (spw) {
- ldapbuf->passwd = strdup(spw->sp_pwdp);
+ res = dup_spw(&ldapbuf->spwd, getspnam_from(name, rep, REP_LDAP));
+ if (res != PWU_SUCCESS)
+ goto out;
+ else {
+ char *spw = ldapbuf->spwd->sp_pwdp;
+ if (spw != NULL && *spw != '\0') {
+ ldapbuf->passwd = strdup(spw);
if (ldapbuf->passwd == NULL)
- return (PWU_NOMEM);
- }
+ goto out;
+ } else
+ ldapbuf->passwd = NULL;
}
- *buf = ldapbuf;
- return (0);
+ /* remember if shadow update is enabled */
+ ldapbuf->shadow_update_enabled = __ns_ldap_is_shadow_update_enabled();
+
+ *buf = (void *)ldapbuf;
+ return (PWU_SUCCESS);
+
+out:
+ free_ldapbuf(ldapbuf);
+ free(ldapbuf);
+ return (res);
}
/*
@@ -359,6 +482,63 @@ new_attr(char *name, char *value)
}
/*
+ * max_present(list)
+ *
+ * returns '1' if a ATTR_MAX with value != -1 is present. (in other words:
+ * if password aging is to be turned on).
+ */
+static int
+max_present(attrlist *list)
+{
+ while (list != NULL)
+ if (list->type == ATTR_MAX && list->data.val_i != -1)
+ return (1);
+ else
+ list = list->next;
+ return (0);
+}
+
+/*
+ * attr_addmod(attrs, idx, item, val)
+ *
+ * Adds or updates attribute 'item' in ldap_attrs list to value
+ * update idx if item is added
+ * return: -1 - PWU_NOMEM/error, 0 - success
+ */
+static int
+attr_addmod(ns_ldap_attr_t **attrs, int *idx, char *item, int value)
+{
+ char numbuf[MAX_INT_LEN], *strp;
+ int i;
+
+ /* stringize the value or abort */
+ if (snprintf(numbuf, MAX_INT_LEN, "%d", value) >= MAX_INT_LEN)
+ return (-1);
+
+ /* check for existence and modify existing */
+ for (i = 0; i < *idx; i++) {
+ if (attrs[i] != NULL &&
+ strcmp(item, attrs[i]->attrname) == 0) {
+ strp = strdup(numbuf);
+ if (strp == NULL)
+ return (-1);
+ free(attrs[i]->attrvalue[0]);
+ attrs[i]->attrvalue[0] = strp;
+ return (0);
+ }
+ }
+ /* else add */
+ strp = strdup(numbuf);
+ if (strp == NULL)
+ return (-1);
+ attrs[*idx] = new_attr(item, strp);
+ if (attrs[*idx] == NULL)
+ return (-1);
+ (*idx)++;
+ return (0);
+}
+
+/*
* ldap_update(items, rep, buf)
*
* create LDAP attributes in 'buf' for each attribute in 'items'.
@@ -368,91 +548,399 @@ int
ldap_update(attrlist *items, pwu_repository_t *rep, void *buf)
{
attrlist *p;
- int idx = 0;
ldapbuf_t *ldapbuf = (ldapbuf_t *)buf;
- ns_ldap_attr_t **attrs = ldapbuf->attrs;
+ struct spwd *spw;
+ ns_ldap_attr_t **pattrs = ldapbuf->pattrs;
+ int pidx = 0;
+ ns_ldap_attr_t **sattrs = ldapbuf->sattrs;
+ int sidx = 0;
char *pwd, *val;
char *salt;
size_t cryptlen;
+ int len;
+ int count;
+ int rc = PWU_SUCCESS;
+ int aging_needed = 0;
+ int aging_set = 0;
+ int disable_aging;
+
+ spw = ldapbuf->spwd;
+
+ /*
+ * if sp_max==0 and shadow update is enabled:
+ * disable passwd aging after updating the password
+ */
+ disable_aging = (spw != NULL && spw->sp_max == 0 &&
+ ldapbuf->shadow_update_enabled);
for (p = items; p != NULL; p = p->next) {
switch (p->type) {
case ATTR_PASSWD:
- salt = crypt_gensalt(ldapbuf->passwd, ldapbuf->pwd);
-
- if (salt == NULL) {
- if (errno == ENOMEM)
+ /*
+ * There is a special case for ldap: if the
+ * password is to be deleted (-d to passwd),
+ * p->data.val_s will be NULL.
+ */
+ if (p->data.val_s == NULL) {
+ if (!ldapbuf->shadow_update_enabled)
+ return (PWU_CHANGE_NOT_ALLOWED);
+ cryptlen =
+ sizeof ("{crypt}" NS_LDAP_NO_UNIX_PASSWORD);
+ val = malloc(cryptlen);
+ if (val == NULL)
return (PWU_NOMEM);
- else {
+ (void) snprintf(val, cryptlen,
+ "{crypt}" NS_LDAP_NO_UNIX_PASSWORD);
+ } else { /* not deleting password */
+ salt = crypt_gensalt(ldapbuf->passwd,
+ ldapbuf->pwd);
+
+ if (salt == NULL) {
+ if (errno == ENOMEM)
+ return (PWU_NOMEM);
+
/* algorithm problem? */
syslog(LOG_AUTH | LOG_ALERT,
"passwdutil: crypt_gensalt "
"%m");
return (PWU_UPDATE_FAILED);
}
+
+ pwd = crypt(p->data.val_s, salt);
+ free(salt);
+ cryptlen = strlen(pwd) + sizeof ("{crypt}");
+ val = malloc(cryptlen);
+ if (val == NULL)
+ return (PWU_NOMEM);
+ (void) snprintf(val, cryptlen,
+ "{crypt}%s", pwd);
+ }
+
+ /*
+ * If not managing passwordAccount,
+ * insert the new password in the
+ * passwd attr array and break.
+ */
+ if (!ldapbuf->shadow_update_enabled) {
+ NEW_ATTR(pattrs, pidx,
+ _PWD_USERPASSWORD, val);
+ break;
}
- pwd = crypt(p->data.val_s, salt);
- free(salt);
- cryptlen = strlen(pwd) + sizeof ("{crypt}");
- val = malloc(cryptlen);
- if (val == NULL)
+ /*
+ * Managing passwordAccount, insert the
+ * new password, along with lastChange and
+ * shadowFlag, in the shadow attr array.
+ */
+ NEW_ATTR(sattrs, sidx, _PWD_USERPASSWORD, val);
+
+ if (attr_addmod(sattrs, &sidx, _S_LASTCHANGE,
+ DAY_NOW_32) < 0)
return (PWU_NOMEM);
- (void) snprintf(val, cryptlen, "{crypt}%s", pwd);
+ spw->sp_lstchg = DAY_NOW_32;
- attrs[idx] = new_attr(_PWD_USERPASSWORD, val);
+ if (attr_addmod(sattrs, &sidx, _S_FLAG,
+ spw->sp_flag & ~FAILCOUNT_MASK) < 0)
+ return (PWU_NOMEM);
+ spw->sp_flag &= ~FAILCOUNT_MASK; /* reset count */
+ aging_needed = 1;
break;
- /*
- * For server policy, don't crypt the password,
- * send the password as is to the server and
- * let the LDAP server do its own password
- * encryption
- */
case ATTR_PASSWD_SERVER_POLICY:
- val = strdup(p->data.val_s);
- if (val == NULL)
- return (PWU_NOMEM);
-
- attrs[idx] = new_attr(_PWD_USERPASSWORD, val);
+ /*
+ * For server policy, don't crypt the password,
+ * send the password as is to the server and
+ * let the LDAP server do its own password
+ * encryption
+ */
+ STRDUP_OR_RET(val, p->data.val_s);
+
+ NEW_ATTR(pattrs, pidx, _PWD_USERPASSWORD, val);
break;
case ATTR_COMMENT:
/* XX correct? */
- attrs[idx] = new_attr(_PWD_DESCRIPTION, p->data.val_s);
+ NEW_ATTR(pattrs, pidx, _PWD_DESCRIPTION, p->data.val_s);
break;
case ATTR_GECOS:
- attrs[idx] = new_attr(_PWD_GECOS, p->data.val_s);
+ if (!ldapbuf->shadow_update_enabled) {
+ NEW_ATTR(pattrs, pidx, _PWD_GECOS,
+ p->data.val_s);
+ } else {
+ NEW_ATTR(sattrs, sidx, _PWD_GECOS,
+ p->data.val_s);
+ }
break;
case ATTR_HOMEDIR:
- attrs[idx] = new_attr(_PWD_HOMEDIRECTORY,
- p->data.val_s);
+ if (!ldapbuf->shadow_update_enabled) {
+ NEW_ATTR(pattrs, pidx, _PWD_HOMEDIRECTORY,
+ p->data.val_s);
+ } else {
+ NEW_ATTR(sattrs, sidx, _PWD_HOMEDIRECTORY,
+ p->data.val_s);
+ }
break;
case ATTR_SHELL:
- attrs[idx] = new_attr(_PWD_LOGINSHELL, p->data.val_s);
+ if (!ldapbuf->shadow_update_enabled) {
+ NEW_ATTR(pattrs, pidx, _PWD_LOGINSHELL,
+ p->data.val_s);
+ } else {
+ NEW_ATTR(sattrs, sidx, _PWD_LOGINSHELL,
+ p->data.val_s);
+ }
break;
- /* Unsupported items are below this line */
+ /* We don't update NAME, UID, GID */
case ATTR_NAME:
case ATTR_UID:
case ATTR_GID:
+ /* Unsupported item */
case ATTR_AGE:
+ break;
+ case ATTR_LOCK_ACCOUNT:
+ if (!ldapbuf->shadow_update_enabled)
+ break; /* not managing passwordAccount */
+ if (spw->sp_pwdp == NULL) {
+ spw->sp_pwdp = LOCKSTRING;
+ } else if (strncmp(spw->sp_pwdp, LOCKSTRING,
+ sizeof (LOCKSTRING)-1) != 0) {
+ len = sizeof (LOCKSTRING)-1 +
+ strlen(spw->sp_pwdp) + 1 +
+ sizeof ("{crypt}");
+ pwd = malloc(len);
+ if (pwd == NULL) {
+ return (PWU_NOMEM);
+ }
+ (void) strlcpy(pwd, "{crypt}", len);
+ (void) strlcat(pwd, LOCKSTRING, len);
+ (void) strlcat(pwd, spw->sp_pwdp, len);
+ free(spw->sp_pwdp);
+ spw->sp_pwdp = pwd;
+ NEW_ATTR(sattrs, sidx, _PWD_USERPASSWORD,
+ spw->sp_pwdp);
+ }
+ if (attr_addmod(sattrs, &sidx, _S_LASTCHANGE,
+ DAY_NOW_32) < 0)
+ return (PWU_NOMEM);
+ spw->sp_lstchg = DAY_NOW_32;
+ break;
+
+ case ATTR_UNLOCK_ACCOUNT:
+ if (!ldapbuf->shadow_update_enabled)
+ break; /* not managing passwordAccount */
+ if (spw->sp_pwdp &&
+ strncmp(spw->sp_pwdp, LOCKSTRING,
+ sizeof (LOCKSTRING)-1) == 0) {
+ len = (sizeof ("{crypt}") -
+ sizeof (LOCKSTRING)) +
+ strlen(spw->sp_pwdp) + 1;
+ pwd = malloc(len);
+ if (pwd == NULL) {
+ return (PWU_NOMEM);
+ }
+ (void) strlcpy(pwd, "{crypt}", len);
+ (void) strlcat(pwd, spw->sp_pwdp +
+ sizeof (LOCKSTRING)-1, len);
+ free(spw->sp_pwdp);
+ spw->sp_pwdp = pwd;
+
+ NEW_ATTR(sattrs, sidx, _PWD_USERPASSWORD,
+ spw->sp_pwdp);
+ if (attr_addmod(sattrs, &sidx, _S_LASTCHANGE,
+ DAY_NOW_32) < 0)
+ return (PWU_NOMEM);
+ spw->sp_lstchg = DAY_NOW_32;
+ }
+ break;
+
+ case ATTR_NOLOGIN_ACCOUNT:
+ if (!ldapbuf->shadow_update_enabled)
+ break; /* not managing passwordAccount */
+ free(spw->sp_pwdp);
+ STRDUP_OR_RET(spw->sp_pwdp, "{crypt}" NOLOGINSTRING);
+ NEW_ATTR(sattrs, sidx, _PWD_USERPASSWORD, spw->sp_pwdp);
+ if (attr_addmod(sattrs, &sidx, _S_LASTCHANGE,
+ DAY_NOW_32) < 0)
+ return (PWU_NOMEM);
+ spw->sp_lstchg = DAY_NOW_32;
+ break;
+
+ case ATTR_EXPIRE_PASSWORD:
+ if (!ldapbuf->shadow_update_enabled)
+ break; /* not managing passwordAccount */
+ NUM_TO_STR(val, 0);
+ NEW_ATTR(sattrs, sidx, _S_LASTCHANGE, val);
+ break;
+
case ATTR_LSTCHG:
+ if (!ldapbuf->shadow_update_enabled)
+ break; /* not managing passwordAccount */
+ NUM_TO_STR(val, p->data.val_i);
+ NEW_ATTR(sattrs, sidx, _S_LASTCHANGE, val);
+ break;
+
case ATTR_MIN:
+ if (!ldapbuf->shadow_update_enabled)
+ break; /* not managing passwordAccount */
+ if (spw->sp_max == -1 && p->data.val_i != -1 &&
+ max_present(p->next) == 0)
+ return (PWU_AGING_DISABLED);
+ NUM_TO_STR(val, p->data.val_i);
+ NEW_ATTR(sattrs, sidx, _S_MIN, val);
+ aging_set = 1;
+ break;
+
case ATTR_MAX:
+ if (!ldapbuf->shadow_update_enabled)
+ break; /* not managing passwordAccount */
+ if (p->data.val_i == -1) {
+ /* Turn off aging. Reset min and warn too */
+ spw->sp_max = spw->sp_min = spw->sp_warn = -1;
+ NUM_TO_STR(val, -1);
+ NEW_ATTR(sattrs, sidx, _S_MIN, val);
+ NUM_TO_STR(val, -1);
+ NEW_ATTR(sattrs, sidx, _S_WARNING, val);
+ } else {
+ /* Turn account aging on */
+ if (spw->sp_min == -1) {
+ /*
+ * minage was not set with command-
+ * line option: set to zero
+ */
+ spw->sp_min = 0;
+ NUM_TO_STR(val, 0);
+ NEW_ATTR(sattrs, sidx, _S_MIN,
+ val);
+ }
+ /*
+ * If aging was turned off, we update lstchg.
+ * We take care not to update lstchg if the
+ * user has no password, otherwise the user
+ * might not be required to provide a password
+ * the next time [s]he logs in.
+ *
+ * Also, if lstchg != -1 (i.e., not set)
+ * we keep the old value.
+ */
+ if (spw->sp_max == -1 &&
+ spw->sp_pwdp != NULL && *spw->sp_pwdp &&
+ spw->sp_lstchg == -1) {
+ if (attr_addmod(sattrs, &sidx,
+ _S_LASTCHANGE,
+ DAY_NOW_32) < 0)
+ return (PWU_NOMEM);
+ spw->sp_lstchg = DAY_NOW_32;
+ }
+ }
+ NUM_TO_STR(val, p->data.val_i);
+ NEW_ATTR(sattrs, sidx, _S_MAX, val);
+ aging_set = 1;
+ break;
+
case ATTR_WARN:
+ if (!ldapbuf->shadow_update_enabled)
+ break; /* not managing passwordAccount */
+ if (spw->sp_max == -1 &&
+ p->data.val_i != -1 && max_present(p->next) == 0)
+ return (PWU_AGING_DISABLED);
+ NUM_TO_STR(val, p->data.val_i);
+ NEW_ATTR(sattrs, sidx, _S_WARNING, val);
+ break;
+
case ATTR_INACT:
+ if (!ldapbuf->shadow_update_enabled)
+ break; /* not managing passwordAccount */
+ NUM_TO_STR(val, p->data.val_i);
+ NEW_ATTR(sattrs, sidx, _S_INACTIVE, val);
+ break;
+
case ATTR_EXPIRE:
+ if (!ldapbuf->shadow_update_enabled)
+ break; /* not managing passwordAccount */
+ NUM_TO_STR(val, p->data.val_i);
+ NEW_ATTR(sattrs, sidx, _S_EXPIRE, val);
+ break;
+
case ATTR_FLAG:
+ if (!ldapbuf->shadow_update_enabled)
+ break; /* not managing passwordAccount */
+ NUM_TO_STR(val, p->data.val_i);
+ NEW_ATTR(sattrs, sidx, _S_FLAG, val);
+ break;
+ case ATTR_INCR_FAILED_LOGINS:
+ if (!ldapbuf->shadow_update_enabled) {
+ rc = PWU_CHANGE_NOT_ALLOWED;
+ break; /* not managing passwordAccount */
+ }
+ count = (spw->sp_flag & FAILCOUNT_MASK) + 1;
+ spw->sp_flag &= ~FAILCOUNT_MASK;
+ spw->sp_flag |= min(FAILCOUNT_MASK, count);
+ p->data.val_i = count;
+ NUM_TO_STR(val, spw->sp_flag);
+ NEW_ATTR(sattrs, sidx, _S_FLAG, val);
+ break;
+ case ATTR_RST_FAILED_LOGINS:
+ if (!ldapbuf->shadow_update_enabled) {
+ rc = PWU_CHANGE_NOT_ALLOWED;
+ break; /* not managing passwordAccount */
+ }
+ p->data.val_i = spw->sp_flag & FAILCOUNT_MASK;
+ spw->sp_flag &= ~FAILCOUNT_MASK;
+ NUM_TO_STR(val, spw->sp_flag);
+ NEW_ATTR(sattrs, sidx, _S_FLAG, val);
break;
default:
break;
}
- if (attrs[idx] == NULL)
- return (PWU_NOMEM);
- idx++;
}
- attrs[idx] = NULL;
+ /*
+ * If the ldap client is configured with shadow update enabled,
+ * then what should the new aging values look like?
+ *
+ * There are a number of different conditions
+ *
+ * a) aging is already configured: don't touch it
+ *
+ * b) disable_aging is set: disable aging
+ *
+ * c) aging is not configured: turn on default aging;
+ *
+ * b) and c) of course only if aging_needed and !aging_set.
+ * (i.e., password changed, and aging values not changed)
+ */
- return (PWU_SUCCESS);
+ if (ldapbuf->shadow_update_enabled && spw != NULL && spw->sp_max <= 0) {
+ /* a) aging not yet configured */
+ if (aging_needed && !aging_set) {
+ if (disable_aging) {
+ /* b) turn off aging */
+ spw->sp_min = spw->sp_max = spw->sp_warn = -1;
+ if (attr_addmod(sattrs, &sidx, _S_MIN, -1) < 0)
+ return (PWU_NOMEM);
+ if (attr_addmod(sattrs, &sidx, _S_MAX, -1) < 0)
+ return (PWU_NOMEM);
+ if (attr_addmod(sattrs, &sidx, _S_WARNING,
+ -1) < 0)
+ return (PWU_NOMEM);
+ } else {
+ /* c) */
+ turn_on_default_aging(spw);
+
+ if (attr_addmod(sattrs, &sidx, _S_MIN,
+ spw->sp_min) < 0)
+ return (PWU_NOMEM);
+ if (attr_addmod(sattrs, &sidx, _S_MAX,
+ spw->sp_max) < 0)
+ return (PWU_NOMEM);
+ if (attr_addmod(sattrs, &sidx,
+ _S_WARNING, spw->sp_warn) < 0)
+ return (PWU_NOMEM);
+ }
+ }
+ }
+
+ pattrs[pidx] = NULL;
+ sattrs[sidx] = NULL;
+
+ return (rc);
}
/*
@@ -492,7 +980,7 @@ ldap_to_pwu_code(int error, int pwd_status)
int
ldap_replaceattr(const char *dn, ns_ldap_attr_t **attrs, const char *binddn,
- const char *pwd, int *pwd_status)
+ const char *pwd, int *pwd_status, int flags)
{
int result = NS_LDAP_OP_FAILED;
int ldaprc;
@@ -507,18 +995,20 @@ ldap_replaceattr(const char *dn, ns_ldap_attr_t **attrs, const char *binddn,
debug("%s: replace_ldapattr()", __FILE__);
if ((credp = (ns_cred_t *)calloc(1, sizeof (ns_cred_t))) == NULL)
- return (PWU_NOMEM);
-
- /* Fill in the user name and password */
- if (dn == NULL || pwd == NULL)
- goto out;
+ return (NS_LDAP_MEMORY); /* map to PWU_NOMEM */
- credp->cred.unix_cred.userID = strdup(binddn);
- credp->cred.unix_cred.passwd = strdup(pwd);
+ /* for admin shadow update, dn and pwd will be set later in libsldap */
+ if ((flags & NS_LDAP_UPDATE_SHADOW) == 0) {
+ /* Fill in the user name and password */
+ if (dn == NULL || pwd == NULL)
+ goto out;
+ credp->cred.unix_cred.userID = strdup(binddn);
+ credp->cred.unix_cred.passwd = strdup(pwd);
+ }
/* get host certificate path, if one is configured */
ldaprc = __ns_ldap_getParam(NS_LDAP_HOST_CERTPATH_P,
- (void ***)&certpath, &errorp);
+ (void ***)&certpath, &errorp);
if (ldaprc != NS_LDAP_SUCCESS)
goto out;
@@ -527,7 +1017,7 @@ ldap_replaceattr(const char *dn, ns_ldap_attr_t **attrs, const char *binddn,
/* Load the service specific authentication method */
ldaprc = __ns_ldap_getServiceAuthMethods("passwd-cmd", &authpp,
- &errorp);
+ &errorp);
if (ldaprc != NS_LDAP_SUCCESS)
goto out;
@@ -538,7 +1028,7 @@ ldap_replaceattr(const char *dn, ns_ldap_attr_t **attrs, const char *binddn,
*/
if (authpp == NULL) {
ldaprc = __ns_ldap_getParam(NS_LDAP_AUTH_P, (void ***)&authpp,
- &errorp);
+ &errorp);
if (ldaprc != NS_LDAP_SUCCESS)
goto out;
}
@@ -570,21 +1060,32 @@ ldap_replaceattr(const char *dn, ns_ldap_attr_t **attrs, const char *binddn,
credp->auth.saslopt = authp->saslopt;
ldaprc = __ns_ldap_repAttr("shadow", dn,
- (const ns_ldap_attr_t * const *)attrs,
- credp, 0, &errorp);
+ (const ns_ldap_attr_t * const *)attrs,
+ credp, flags, &errorp);
if (ldaprc == NS_LDAP_SUCCESS) {
result = NS_LDAP_SUCCESS;
goto out;
}
/*
+ * if change not allowed due to configuration, indicate so
+ * to the caller
+ */
+ if (ldaprc == NS_LDAP_CONFIG &&
+ errorp->status == NS_CONFIG_NOTALLOW) {
+ result = NS_LDAP_CONFIG;
+ *pwd_status = NS_PASSWD_CHANGE_NOT_ALLOWED;
+ goto out;
+ }
+
+ /*
* other errors might need to be added to this list, for
* the current supported mechanisms this is sufficient
*/
if ((ldaprc == NS_LDAP_INTERNAL) &&
- (errorp->pwd_mgmt.status == NS_PASSWD_GOOD) &&
- ((errorp->status == LDAP_INAPPROPRIATE_AUTH) ||
- (errorp->status == LDAP_INVALID_CREDENTIALS))) {
+ (errorp->pwd_mgmt.status == NS_PASSWD_GOOD) &&
+ ((errorp->status == LDAP_INAPPROPRIATE_AUTH) ||
+ (errorp->status == LDAP_INVALID_CREDENTIALS))) {
result = ldaprc;
goto out;
}
@@ -594,7 +1095,7 @@ ldap_replaceattr(const char *dn, ns_ldap_attr_t **attrs, const char *binddn,
* return it to caller
*/
if ((ldaprc == NS_LDAP_INTERNAL) &&
- errorp->pwd_mgmt.status != NS_PASSWD_GOOD) {
+ errorp->pwd_mgmt.status != NS_PASSWD_GOOD) {
*pwd_status = errorp->pwd_mgmt.status;
result = ldaprc;
goto out;
@@ -611,7 +1112,7 @@ ldap_replaceattr(const char *dn, ns_ldap_attr_t **attrs, const char *binddn,
result = NS_LDAP_CONFIG;
goto out;
}
- result = PWU_DENIED;
+ result = NS_LDAP_OP_FAILED; /* map to PWU_DENIED */
out:
if (credp)
@@ -627,7 +1128,6 @@ out:
}
-
/*
* ldap_putpwnam(name, oldpw, dummy, rep, buf)
*
@@ -645,7 +1145,8 @@ ldap_putpwnam(char *name, char *oldpw, char *dummy,
char *binddn; /* dn of user who is performing the change */
ns_ldap_error_t *errorp;
ldapbuf_t *ldapbuf = (ldapbuf_t *)buf;
- ns_ldap_attr_t **attrs = ldapbuf->attrs;
+ ns_ldap_attr_t **pattrs = ldapbuf->pattrs;
+ ns_ldap_attr_t **sattrs = ldapbuf->sattrs;
struct passwd *pw;
int pwd_status;
uid_t uid;
@@ -654,6 +1155,26 @@ ldap_putpwnam(char *name, char *oldpw, char *dummy,
return (PWU_NOT_FOUND);
/*
+ * convert name of user whose attributes we are changing
+ * to a distinguished name
+ */
+ res = __ns_ldap_uid2dn(name, &dn, NULL, &errorp);
+ if (res != NS_LDAP_SUCCESS)
+ goto out;
+
+ /* update shadow via ldap_cachemgr if it is enabled */
+ if (ldapbuf->shadow_update_enabled &&
+ sattrs != NULL && sattrs[0] != NULL) {
+ /*
+ * flag NS_LDAP_UPDATE_SHADOW indicates the shadow update
+ * should be done via ldap_cachemgr
+ */
+ res = ldap_replaceattr(dn, sattrs, NULL, NULL, &pwd_status,
+ NS_LDAP_UPDATE_SHADOW);
+ goto out;
+ }
+
+ /*
* The LDAP server checks whether we are permitted to perform
* the requested change. We need to send the name of the user
* who is executing this piece of code, together with his
@@ -667,14 +1188,6 @@ ldap_putpwnam(char *name, char *oldpw, char *dummy,
*/
/*
- * convert name of user whose attributes we are changing
- * to a distinguished name
- */
- res = __ns_ldap_uid2dn(name, &dn, NULL, &errorp);
- if (res != NS_LDAP_SUCCESS)
- goto out;
-
- /*
* create a dn for the user who is executing this code
*/
uid = getuid();
@@ -696,21 +1209,14 @@ ldap_putpwnam(char *name, char *oldpw, char *dummy,
if (res != NS_LDAP_SUCCESS)
goto out;
- res = ldap_replaceattr(dn, attrs, binddn, oldpw,
- &pwd_status);
+ if (pattrs && pattrs[0] != NULL) {
+ res = ldap_replaceattr(dn, pattrs, binddn, oldpw,
+ &pwd_status, 0);
+ } else
+ res = NS_LDAP_OP_FAILED;
out:
- while (*attrs) {
- free((*attrs)->attrvalue[0]);
- free(*attrs);
- attrs++;
- }
- if (ldapbuf->passwd) {
- (void) memset(ldapbuf->passwd, 0, strlen(ldapbuf->passwd));
- free(ldapbuf->passwd);
- }
- if (ldapbuf->pwd)
- free_pwd(ldapbuf->pwd);
+ free_ldapbuf(ldapbuf);
free(dn);
return (ldap_to_pwu_code(res, pwd_status));
diff --git a/usr/src/lib/passwdutil/passwdutil.h b/usr/src/lib/passwdutil/passwdutil.h
index 65216e81e2..7634fce552 100644
--- a/usr/src/lib/passwdutil/passwdutil.h
+++ b/usr/src/lib/passwdutil/passwdutil.h
@@ -19,7 +19,7 @@
* 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.
*/
@@ -166,6 +166,7 @@ int get_ns(pwu_repository_t *, int);
struct passwd *getpwnam_from(const char *, pwu_repository_t *, int);
struct passwd *getpwuid_from(uid_t, pwu_repository_t *, int);
struct spwd *getspnam_from(const char *, pwu_repository_t *, int);
+int name_to_int(char *);
/*
* __set_authtok_attr.c