diff options
author | Julian Pullen <Julian.Pullen@Sun.COM> | 2009-05-08 17:38:01 +0100 |
---|---|---|
committer | Julian Pullen <Julian.Pullen@Sun.COM> | 2009-05-08 17:38:01 +0100 |
commit | b57459abfba36eb3068cfe44c6921168b4c4f774 (patch) | |
tree | 5479f0844784d6b0929894abd0b14e3cee9135bd /usr/src | |
parent | c9d66ba7a02565d1320b4a0780e249cfe8c02612 (diff) | |
download | illumos-gate-b57459abfba36eb3068cfe44c6921168b4c4f774.tar.gz |
4904603 disable ldaplist to not show userpassword attribute or just user logged in
Diffstat (limited to 'usr/src')
-rw-r--r-- | usr/src/cmd/ldap/ns_ldap/idsconfig.sh | 381 | ||||
-rw-r--r-- | usr/src/cmd/ldapcachemgr/cachemgr.c | 19 | ||||
-rw-r--r-- | usr/src/cmd/ldapcachemgr/cachemgr.h | 5 | ||||
-rw-r--r-- | usr/src/cmd/ldapcachemgr/cachemgr_change.c | 8 | ||||
-rw-r--r-- | usr/src/cmd/ldapcachemgr/cachemgr_getldap.c | 44 | ||||
-rw-r--r-- | usr/src/cmd/nscd/nscd_frontend.c | 33 | ||||
-rw-r--r-- | usr/src/cmd/nscd/nscd_frontend.h | 9 | ||||
-rw-r--r-- | usr/src/cmd/nscd/nscd_switch.c | 62 | ||||
-rw-r--r-- | usr/src/lib/libsldap/common/ns_cache_door.h | 2 | ||||
-rw-r--r-- | usr/src/lib/libsldap/common/ns_common.c | 39 | ||||
-rw-r--r-- | usr/src/lib/libsldap/common/ns_config.c | 75 | ||||
-rw-r--r-- | usr/src/lib/libsldap/common/ns_confmgr.c | 20 | ||||
-rw-r--r-- | usr/src/lib/libsldap/common/ns_connect.c | 167 | ||||
-rw-r--r-- | usr/src/lib/libsldap/common/ns_internal.h | 2 | ||||
-rw-r--r-- | usr/src/lib/libsldap/common/ns_reads.c | 121 | ||||
-rw-r--r-- | usr/src/lib/libsldap/common/ns_sldap.h | 7 |
16 files changed, 847 insertions, 147 deletions
diff --git a/usr/src/cmd/ldap/ns_ldap/idsconfig.sh b/usr/src/cmd/ldap/ns_ldap/idsconfig.sh index 2247f52157..d435e8f1a7 100644 --- a/usr/src/cmd/ldap/ns_ldap/idsconfig.sh +++ b/usr/src/cmd/ldap/ns_ldap/idsconfig.sh @@ -979,6 +979,9 @@ init() HOST="" # NULL or <hostname> NAWK="/usr/bin/nawk" RM="/usr/bin/rm" + WC="/usr/bin/wc" + CAT="/usr/bin/cat" + SED="/usr/bin/sed" DOM="" # Set to NULL # If DNS domain (resolv.conf) exists use that, otherwise use domainname. @@ -1010,6 +1013,7 @@ init() LDAP_SUFFIX="" LDAP_DOMAIN=$DOM # domainname on Server (default value) GEN_CMD="" + PROXY_ACI_NAME="LDAP_Naming_Services_proxy_password_read" # LDAP COMMANDS LDAPSEARCH="/bin/ldapsearch -r" @@ -2594,11 +2598,12 @@ EOF } # -# allow_admin_write_shadow(): Give Admin write permission for shadow data. +# allow_admin_read_write_shadow(): Give Admin read/write permission +# to shadow data. # -allow_admin_write_shadow() +allow_admin_read_write_shadow() { - [ $DEBUG -eq 1 ] && ${ECHO} "In allow_admin_write_shadow()" + [ $DEBUG -eq 1 ] && ${ECHO} "In allow_admin_read_write_shadow()" # Set ACI Name ADMIN_ACI_NAME="LDAP_Naming_Services_admin_shadow_write" @@ -2606,7 +2611,11 @@ allow_admin_write_shadow() # 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 an ACI with ${ADMIN_ACI_NAME} and "write,compare,read,search" + # and ${LDAP_ADMINDN} already exists, we are done + ${EGREP} ".*${ADMIN_ACI_NAME}.*write,compare,read,search.*${LDAP_ADMINDN}.*" \ + ${TMPDIR}/chk_adminwrite_aci 2>&1 > /dev/null if [ $? -eq 0 ]; then MSG="Admin ACI ${ADMIN_ACI_NAME} already exists for ${LDAP_BASEDN}." if [ $EXISTING_PROFILE -eq 1 ]; then @@ -2618,26 +2627,35 @@ allow_admin_write_shadow() return 0 fi + # If an ACI with ${ADMIN_ACI_NAME} and "(write)" and ${LDAP_ADMINDN} + # already exists, delete it first. + find_and_delete_ACI ".*${ADMIN_ACI_NAME}.*(write).*${LDAP_ADMINDN}.*" \ + ${TMPDIR}/chk_adminwrite_aci ${ADMIN_ACI_NAME} + # 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}";) +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,compare,read,search) + 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!" + ${ECHO} " ERROR: Allow ${LDAP_ADMINDN} read/write access to 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." + MSG="Give ${LDAP_ADMINDN} read/write access to shadow data." if [ $EXISTING_PROFILE -eq 1 ]; then ${ECHO} " ACI SET: $MSG" else @@ -2647,12 +2665,12 @@ EOF } # -# allow_host_write_shadow(): Give host principal write permission +# allow_host_read_write_shadow(): Give host principal read/write permission # for shadow data. # -allow_host_write_shadow() +allow_host_read_write_shadow() { - [ $DEBUG -eq 1 ] && ${ECHO} "In allow_host_write_shadow()" + [ $DEBUG -eq 1 ] && ${ECHO} "In allow_host_read_write_shadow()" # Set ACI Name HOST_ACI_NAME="LDAP_Naming_Services_host_shadow_write" @@ -2676,20 +2694,20 @@ allow_host_write_shadow() 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}";) +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 (write,compare,read,search) authmethod="sasl GSSAPI" and userdn = "ldap:///cn=*+ipHostNumber=*,ou=Hosts,${LDAP_BASEDN}";) EOF -) > ${TMPDIR}/host_write +) > ${TMPDIR}/host_read_write # Add the entry. - ${EVAL} "${LDAPMODIFY} ${LDAP_ARGS} -f ${TMPDIR}/host_write ${VERB}" + ${EVAL} "${LDAPMODIFY} ${LDAP_ARGS} -f ${TMPDIR}/host_read_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." + ${RM} -f ${TMPDIR}/host_read_write + MSG="Give host principal read/write permission for shadow." if [ $EXISTING_PROFILE -eq 1 ]; then ${ECHO} " ACI SET: $MSG" else @@ -2732,8 +2750,9 @@ setup_shadow_update() { 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 + delete_proxy_read_pw + allow_host_read_write_shadow + deny_non_host_shadow_access ${ECHO} "" ${ECHO} " Shadow update has been enabled." else @@ -2750,8 +2769,9 @@ setup_shadow_update() { get_adminDN get_admin_pw add_admin - allow_admin_write_shadow - modify_top_aci + delete_proxy_read_pw + allow_admin_read_write_shadow + deny_non_admin_shadow_access ${ECHO} "" ${ECHO} " Shadow update has been enabled." return @@ -2799,6 +2819,7 @@ prompt_config_info() if [ "$LDAP_ENABLE_SHADOW_UPDATE" = "TRUE" ];then setup_shadow_update + cleanup exit 0 fi @@ -4466,7 +4487,6 @@ EOF STEP=`expr $STEP + 1` } - # # modify_top_aci(): Modify the ACI for the top entry to disable self modify # of user attributes. @@ -4486,38 +4506,11 @@ 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 - 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="" + ${ECHO} " ${STEP}. Top level ACI ${ACI_NAME} already exists for ${LDAP_BASEDN}." + STEP=`expr $STEP + 1` + return 0 fi # Crate LDIF for top level ACI. @@ -4525,7 +4518,7 @@ modify_top_aci() dn: ${LDAP_BASEDN} changetype: modify add: aci -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";) +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";) - EOF ) > ${TMPDIR}/top_aci @@ -4538,7 +4531,7 @@ EOF exit 1 fi - # Display message that schema is updated. + # Display message that ACI is updated. MSG="ACI for ${LDAP_BASEDN} modified to disable self modify." if [ $EXISTING_PROFILE -eq 1 ];then ${ECHO} " ACI SET: $MSG" @@ -4549,6 +4542,187 @@ EOF } # +# find_and_delete_ACI(): Find an ACI in file $2 with a matching pattern $1. +# Delete the ACI and print a message using $3 as the ACI name. $3 is needed +# because it could have a different value than that of $1. +find_and_delete_ACI() +{ + [ $DEBUG -eq 1 ] && ${ECHO} "In find_and_delete_ACI" + + # if an ACI with pattern $1 exists in file $2, delete it from ${LDAP_BASEDN} + ${EGREP} $1 $2 | ${SED} -e 's/aci=//' > ${TMPDIR}/grep_find_delete_aci 2>&1 + if [ -s ${TMPDIR}/grep_find_delete_aci ]; then + aci_to_delete=`${CAT} ${TMPDIR}/grep_find_delete_aci` + + # Create the tmp file to delete the ACI. + ( cat <<EOF +dn: ${LDAP_BASEDN} +changetype: modify +delete: aci +aci: ${aci_to_delete} +EOF + ) > ${TMPDIR}/find_delete_aci + + # Delete the ACI + ${EVAL} "${LDAPMODIFY} ${LDAP_ARGS} -f ${TMPDIR}/find_delete_aci ${VERB}" + if [ $? -ne 0 ]; then + ${ECHO} " ERROR: Remove of $3 ACI failed!" + cleanup + exit 1 + fi + + ${RM} -f ${TMPDIR}/find_delete_aci + # Display message that an ACL is deleted. + MSG="ACI $3 deleted." + if [ $EXISTING_PROFILE -eq 1 ]; then + ${ECHO} " ACI DELETED: $MSG" + else + ${ECHO} " ${STEP}. $MSG" + STEP=`expr $STEP + 1` + fi + fi +} + +# +# Add an ACI to deny non-admin access to shadow data when +# shadow update is enabled. +# +deny_non_admin_shadow_access() +{ + [ $DEBUG -eq 1 ] && ${ECHO} "In deny_non_admin_shadow_access()" + + # Set ACI Names + ACI_TO_ADD="LDAP_Naming_Services_deny_non_admin_shadow_access" + ACI_TO_DEL="LDAP_Naming_Services_deny_non_host_shadow_access" + + # Search for ACI_TO_ADD + eval "${LDAPSEARCH} ${LDAP_ARGS} -b \"${LDAP_BASEDN}\" -s base objectclass=* aci > ${TMPDIR}/chk_aci_non_admin 2>&1" + if [ $? -ne 0 ]; then + ${ECHO} "Error searching aci for ${LDAP_BASEDN}" + cleanup + exit 1 + fi + + # If an ACI with ${ACI_TO_ADD} already exists, we are done. + ${EGREP} ${ACI_TO_ADD} ${TMPDIR}/chk_aci_non_admin 2>&1 > /dev/null + if [ $? -eq 0 ]; then + MSG="ACI ${ACI_TO_ADD} already set 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 + + # The deny_non_admin_shadow_access and deny_non_host_shadow_access ACIs + # should be mutually exclusive, so if the latter exists, delete it. + find_and_delete_ACI ${ACI_TO_DEL} ${TMPDIR}/chk_aci_non_admin ${ACI_TO_DEL} + + # 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") (version 3.0; acl ${ACI_TO_ADD}; + deny (write,read,search,compare) userdn != "ldap:///${LDAP_ADMINDN}";) +EOF +) > ${TMPDIR}/non_admin_aci_write + + # Add the entry. + ${EVAL} "${LDAPMODIFY} ${LDAP_ARGS} -f ${TMPDIR}/non_admin_aci_write ${VERB}" + if [ $? -ne 0 ]; then + ${ECHO} " ERROR: Adding ACI ${ACI_TO_ADD} failed!" + ${CAT} ${TMPDIR}/non_admin_aci_write + cleanup + exit 1 + fi + + ${RM} -f ${TMPDIR}/non_admin_aci_write + # Display message that the non-admin access to shadow data is denied. + MSG="Non-Admin access to shadow data denied." + if [ $EXISTING_PROFILE -eq 1 ]; then + ${ECHO} " ACI SET: $MSG" + else + ${ECHO} " ${STEP}. $MSG" + STEP=`expr $STEP + 1` + fi +} + +# +# Add an ACI to deny non-host access to shadow data when +# shadow update is enabled and auth Method if gssapi. +# +deny_non_host_shadow_access() +{ + [ $DEBUG -eq 1 ] && ${ECHO} "In deny_non_host_shadow_access()" + + # Set ACI Names + ACI_TO_ADD="LDAP_Naming_Services_deny_non_host_shadow_access" + ACI_TO_DEL="LDAP_Naming_Services_deny_non_admin_shadow_access" + + # Search for ACI_TO_ADD + eval "${LDAPSEARCH} ${LDAP_ARGS} -b \"${LDAP_BASEDN}\" -s base objectclass=* aci > ${TMPDIR}/chk_aci_non_host 2>&1" + if [ $? -ne 0 ]; then + ${ECHO} "Error searching aci for ${LDAP_BASEDN}" + cleanup + exit 1 + fi + + # If an ACI with ${ACI_TO_ADD} already exists, we are done. + ${EGREP} ${ACI_TO_ADD} ${TMPDIR}/chk_aci_non_host 2>&1 > /dev/null + if [ $? -eq 0 ]; then + MSG="ACI ${ACI_TO_ADD} already set 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 + + # The deny_non_admin_shadow_access and deny_non_host_shadow_access ACIs + # should be mutually exclusive, so if the former exists, delete it. + find_and_delete_ACI ${ACI_TO_DEL} ${TMPDIR}/chk_aci_non_host ${ACI_TO_DEL} + + # 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") (version 3.0; acl ${ACI_TO_ADD}; + deny (write,read,search,compare) + userdn != "ldap:///cn=*+ipHostNumber=*,ou=Hosts,${LDAP_BASEDN}";) +EOF +) > ${TMPDIR}/non_host_aci_write + + # Add the entry. + ${EVAL} "${LDAPMODIFY} ${LDAP_ARGS} -f ${TMPDIR}/non_host_aci_write ${VERB}" + if [ $? -ne 0 ]; then + ${ECHO} " ERROR: Adding ACI ${ACI_TO_ADD} failed!" + ${CAT} ${TMPDIR}/non_host_aci_write + cleanup + exit 1 + fi + + ${RM} -f ${TMPDIR}/non_host_aci_write + # Display message that the non-host access to shadow data is denied. + MSG="Non-host access to shadow data is denied." + 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. # add_vlv_aci() @@ -4927,9 +5101,6 @@ allow_proxy_read_pw() { [ $DEBUG -eq 1 ] && ${ECHO} "In allow_proxy_read_pw()" - # Set ACI Name - PROXY_ACI_NAME="LDAP_Naming_Services_proxy_password_read" - # Search for ACI_NAME eval "${LDAPSEARCH} ${LDAP_ARGS} -b \"${LDAP_BASEDN}\" -s base objectclass=* aci > ${TMPDIR}/chk_proxyread_aci 2>&1" ${GREP} "${PROXY_ACI_NAME}" ${TMPDIR}/chk_proxyread_aci > /dev/null 2>&1 @@ -4944,7 +5115,9 @@ allow_proxy_read_pw() dn: ${LDAP_BASEDN} changetype: modify add: aci -aci: (target="ldap:///${LDAP_BASEDN}")(targetattr="userPassword")(version 3.0; acl ${PROXY_ACI_NAME}; allow (compare,read,search) userdn = "ldap:///${LDAP_PROXYAGENT}";) +aci: (target="ldap:///${LDAP_BASEDN}")(targetattr="userPassword") + (version 3.0; acl ${PROXY_ACI_NAME}; allow (compare,read,search) + userdn = "ldap:///${LDAP_PROXYAGENT}";) EOF ) > ${TMPDIR}/proxy_read @@ -4961,6 +5134,83 @@ EOF STEP=`expr $STEP + 1` } +# Delete Proxy Agent read permission for password. +delete_proxy_read_pw() +{ + [ $DEBUG -eq 1 ] && ${ECHO} "In delete_proxy_read_pw()" + + # Search for ACI_NAME + eval "${LDAPSEARCH} ${LDAP_ARGS} -b \"${LDAP_BASEDN}\" -s base objectclass=* aci > ${TMPDIR}/chk_proxyread_aci 2>&1" + ${GREP} "${PROXY_ACI_NAME}" ${TMPDIR}/chk_proxyread_aci | \ + ${SED} -e 's/aci=//' > ${TMPDIR}/grep_proxyread_aci 2>&1 + if [ $? -ne 0 ]; then + ${ECHO} "Proxy ACI ${PROXY_ACI_NAME} does not exist for ${LDAP_BASEDN}." + return 0 + fi + + # We need to remove proxy agent's read access to user passwords, + # but We do not know the value of the ${LDAP_PROXYAGENT} here, so + # 1. if only one match found, delete it + # 2. if more than one matches found, ask the user which one to delete + HOWMANY=`${WC} -l ${TMPDIR}/grep_proxyread_aci | ${NAWK} '{print $1}'` + if [ $HOWMANY -eq 0 ]; then + ${ECHO} "Proxy ACI ${PROXY_ACI_NAME} does not exist for ${LDAP_BASEDN}." + return 0 + fi + if [ $HOWMANY -eq 1 ];then + proxy_aci=`${CAT} ${TMPDIR}/grep_proxyread_aci` + else + ${CAT} << EOF + +Proxy agent is not allowed to read user passwords when shadow +update is enabled. There are more than one proxy agents found. +Please select the currently proxy agent being used, so that +idsconfig can remove its read access to user passwords. + +The proxy agents are: + +EOF + # generate the proxy agent list + ${SED} -e "s/.*ldap:\/\/\/.*ldap:\/\/\///" \ + ${TMPDIR}/grep_proxyread_aci | ${SED} -e "s/\";)//" > \ + ${TMPDIR}/proxy_agent_list + + # print the proxy agent list + ${NAWK} '{print NR ": " $0}' ${TMPDIR}/proxy_agent_list + + # ask the user to pick one + _MENU_PROMPT="Select the proxy agent (1-$HOWMANY): " + get_menu_choice "${_MENU_PROMPT}" "0" "$HOWMANY" + _CH=$MN_CH + proxy_aci=`${SED} -n "$_CH p" ${TMPDIR}/grep_proxyread_aci` + fi + + # Create the tmp file to delete the ACI. + ( cat <<EOF +dn: ${LDAP_BASEDN} +changetype: modify +delete: aci +aci: ${proxy_aci} +EOF + ) > ${TMPDIR}/proxy_delete + + # Delete the ACI + ${EVAL} "${LDAPMODIFY} ${LDAP_ARGS} -f ${TMPDIR}/proxy_delete ${VERB}" + if [ $? -ne 0 ]; then + ${ECHO} " ERROR: Remove of ${PROXY_ACI_NAME} ACI failed!" + cat ${TMPDIR}/proxy_delete + cleanup + exit 1 + fi + + # Display message that ACI is updated. + MSG="Removed ${PROXY_ACI_NAME} ACI for proxyagent read permission for password." + ${ECHO} " " + ${ECHO} " ACI REMOVED: $MSG" + ${ECHO} " The ACI removed is $proxy_aci" + ${ECHO} " " +} + # # add_profile(): Add client profile to server. # @@ -5156,21 +5406,30 @@ add_vlv_aci # if Proxy needed, Add Proxy Agent and give read permission for password. if [ $NEED_PROXY -eq 1 ]; then add_proxyagent - allow_proxy_read_pw + if [ "$LDAP_ENABLE_SHADOW_UPDATE" != "TRUE" ]; then + allow_proxy_read_pw + fi fi # If admin needed for shadow update, Add the administrator identity and -# give write permission for shadow. +# give read/write permission for shadow, and deny all others read/write +# access to it. if [ $NEED_ADMIN -eq 1 ]; then add_admin - allow_admin_write_shadow + allow_admin_read_write_shadow + # deny non-admin access to shadow data + deny_non_admin_shadow_access fi -# if use host principal for shadow update, give write permission for shadow. +# If use host principal for shadow update, give read/write permission for +# shadow, and deny all others' read/write access to it. if [ $NEED_HOSTACL -eq 1 ]; then - allow_host_write_shadow + allow_host_read_write_shadow + # deny non-host access to shadow data + deny_non_host_shadow_access fi + # Generate client profile and add it to the server. add_profile diff --git a/usr/src/cmd/ldapcachemgr/cachemgr.c b/usr/src/cmd/ldapcachemgr/cachemgr.c index aa01d7da17..5d57b36dcc 100644 --- a/usr/src/cmd/ldapcachemgr/cachemgr.c +++ b/usr/src/cmd/ldapcachemgr/cachemgr.c @@ -72,7 +72,7 @@ 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); +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 @@ -741,18 +741,29 @@ switcher(void *cookie, char *argp, size_t arg_size, * Get the current LDAP configuration. * Since this is dynamic data and its size can exceed * the size of ldap_return_t, the next step will - * calculate who much space exactly is required. + * calculate how much space exactly is required. */ getldap_lookup(&configInfo, ptr); state = GETSIZE; break; + case GETADMINCRED: + /* + * Get the current Admin Credentials (DN and password). + * Since this is dynamic data and its size can exceed + * the size of ldap_return_t, the next step will + * calculate how much space exactly is required. + */ + getldap_admincred(&configInfo, ptr); + + state = GETSIZE; + break; case GETLDAPSERVER: /* * Get the root DSE for a next server in the list. * Since this is dynamic data and its size can exceed * the size of ldap_return_t, the next step will - * calculate who much space exactly is required. + * calculate how much space exactly is required. */ getldap_getserver(&configInfo, ptr); @@ -1802,7 +1813,7 @@ out: * return - 0 No or error * 1 Yes */ -static int +int is_root_or_all_privs(char *dc_str, ucred_t **ucp) { const priv_set_t *ps; /* door client */ diff --git a/usr/src/cmd/ldapcachemgr/cachemgr.h b/usr/src/cmd/ldapcachemgr/cachemgr.h index 2c907c1439..193601bc4d 100644 --- a/usr/src/cmd/ldapcachemgr/cachemgr.h +++ b/usr/src/cmd/ldapcachemgr/cachemgr.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 _CACHEMGR_H #define _CACHEMGR_H -#pragma ident "%Z%%M% %I% %E% SMI" - #ifdef __cplusplus extern "C" { #endif @@ -103,6 +101,7 @@ extern void getldap_revalidate(void); extern int getldap_uidkeepalive(int keep, int interval); extern int getldap_invalidate(void); extern void getldap_lookup(LineBuf *config_info, ldap_call_t *in); +extern void getldap_admincred(LineBuf *config_info, ldap_call_t *in); extern void getldap_refresh(void); extern int cachemgr_set_dl(admin_t *ptr, int value); extern int cachemgr_set_ttl(ldap_stat_t *cache, char *name, int value); diff --git a/usr/src/cmd/ldapcachemgr/cachemgr_change.c b/usr/src/cmd/ldapcachemgr/cachemgr_change.c index 838bcdb84c..85a15a1054 100644 --- a/usr/src/cmd/ldapcachemgr/cachemgr_change.c +++ b/usr/src/cmd/ldapcachemgr/cachemgr_change.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 <strings.h> #include <stdlib.h> #include <syslog.h> @@ -456,11 +454,11 @@ chg_test_config_change(ns_config_t *new, int *change_status) * Flatten the config data of the newly downloaded config and * current default config and compare both. */ - if ((errp = __ns_ldap_LoadDoorInfo(&new_cfg, NULL, new)) != NULL) { + if ((errp = __ns_ldap_LoadDoorInfo(&new_cfg, NULL, new, 0)) != NULL) { __ns_ldap_freeError(&errp); /* error, assume the config is changed */ changed = 1; - } else if ((errp = __ns_ldap_LoadDoorInfo(&cur_cfg, NULL, NULL)) + } else if ((errp = __ns_ldap_LoadDoorInfo(&cur_cfg, NULL, NULL, 0)) != NULL) { __ns_ldap_freeError(&errp); /* error, assume the config is changed */ diff --git a/usr/src/cmd/ldapcachemgr/cachemgr_getldap.c b/usr/src/cmd/ldapcachemgr/cachemgr_getldap.c index 9297e1c510..7a6f5904b8 100644 --- a/usr/src/cmd/ldapcachemgr/cachemgr_getldap.c +++ b/usr/src/cmd/ldapcachemgr/cachemgr_getldap.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 <assert.h> #include <errno.h> #include <memory.h> @@ -57,6 +55,8 @@ static rwlock_t ldap_lock = DEFAULTRWLOCK; static int sighup_update = FALSE; extern admin_t current_admin; +extern int is_root_or_all_privs(char *dc_str, ucred_t **ucp); + /* variables used for SIGHUP wakeup on sleep */ static mutex_t sighuplock; static cond_t cond; @@ -2665,6 +2665,42 @@ getldap_revalidate() } void +getldap_admincred(LineBuf *config_info, ldap_call_t *in) +{ + ns_ldap_error_t *error; + ldap_config_out_t *cout; + ucred_t *uc = NULL; + + if (current_admin.debug_level >= DBG_ALL) { + logit("getldap_admincred()...\n"); + } + /* check privileges */ + if (is_root_or_all_privs("GETADMINCRED", &uc) == 0) { + logit("admin credential requested by a non-root and no ALL " + "privilege user not allowed"); + config_info->str = NULL; + config_info->len = 0; + } else { + (void) rw_rdlock(&ldap_lock); + if ((error = __ns_ldap_LoadDoorInfo(config_info, + in->ldap_u.domainname, NULL, 1)) != NULL) { + if (error != NULL && error->message != NULL) + logit("Error: ldap_lookup: %s\n", + error->message); + (void) __ns_ldap_freeError(&error); + + config_info->str = NULL; + config_info->len = 0; + } + /* set change cookie */ + cout = (ldap_config_out_t *)config_info->str; + if (cout) + cout->cookie = chg_config_cookie_get(); + (void) rw_unlock(&ldap_lock); + } +} + +void getldap_lookup(LineBuf *config_info, ldap_call_t *in) { ns_ldap_error_t *error; @@ -2675,7 +2711,7 @@ getldap_lookup(LineBuf *config_info, ldap_call_t *in) } (void) rw_rdlock(&ldap_lock); if ((error = __ns_ldap_LoadDoorInfo(config_info, - in->ldap_u.domainname, NULL)) != NULL) { + in->ldap_u.domainname, NULL, 0)) != NULL) { if (error != NULL && error->message != NULL) logit("Error: ldap_lookup: %s\n", error->message); (void) __ns_ldap_freeError(&error); diff --git a/usr/src/cmd/nscd/nscd_frontend.c b/usr/src/cmd/nscd/nscd_frontend.c index 6205e943a5..2b692a1fe5 100644 --- a/usr/src/cmd/nscd/nscd_frontend.c +++ b/usr/src/cmd/nscd/nscd_frontend.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. */ @@ -320,16 +320,20 @@ _nscd_get_client_euid() } /* - * Check to see if the door client's euid is 0 or if it has PRIV_FILE_DAC_READ + * Check to see if the door client's euid is 0 or if it has required_priv * privilege. Return 0 if yes, -1 otherwise. + * Supported values for required_priv are: + * - NSCD_ALL_PRIV: for all zones privileges + * - NSCD_READ_PRIV: for PRIV_FILE_DAC_READ privilege */ int -_nscd_check_client_read_priv() +_nscd_check_client_priv(int required_priv) { int rc = 0; ucred_t *uc = NULL; const priv_set_t *eset; char *me = "_nscd_check_client_read_priv"; + priv_set_t *zs; /* zone */ if (door_ucred(&uc) != 0) { _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR) @@ -343,8 +347,27 @@ _nscd_check_client_read_priv() } eset = ucred_getprivset(uc, PRIV_EFFECTIVE); - if (!priv_ismember(eset, PRIV_FILE_DAC_READ)) - rc = -1; + switch (required_priv) { + case NSCD_ALL_PRIV: + zs = priv_str_to_set("zone", ",", NULL); + if (!priv_isequalset(eset, zs)) { + _NSCD_LOG(NSCD_LOG_FRONT_END, + NSCD_LOG_LEVEL_ERROR) + (me, "missing all zones privileges\n"); + rc = -1; + } + priv_freeset(zs); + break; + case NSCD_READ_PRIV: + if (!priv_ismember(eset, PRIV_FILE_DAC_READ)) + rc = -1; + break; + default: + _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR) + (me, "unknown required_priv: %d\n", required_priv); + rc = -1; + break; + } ucred_free(uc); return (rc); } diff --git a/usr/src/cmd/nscd/nscd_frontend.h b/usr/src/cmd/nscd/nscd_frontend.h index c1d46b0d99..ac016706ac 100644 --- a/usr/src/cmd/nscd/nscd_frontend.h +++ b/usr/src/cmd/nscd/nscd_frontend.h @@ -19,15 +19,13 @@ * CDDL HEADER END */ /* - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #ifndef _NSCD_FRONTEND_H #define _NSCD_FRONTEND_H -#pragma ident "%Z%%M% %I% %E% SMI" - #ifdef __cplusplus extern "C" { #endif @@ -40,6 +38,9 @@ extern "C" { #define NSCD_DOORBUF_MAXLEN 1024 * 512 #define NSCD_PHDR_LEN(hdrp) ((hdrp)->data_off) #define NSCD_DATA_LEN(hdrp) ((hdrp)->data_len) +/* used to check clients required privileges */ +#define NSCD_ALL_PRIV 0 +#define NSCD_READ_PRIV 1 #define NSCD_ALLOC_LOOKUP_BUFFER(bufp, bufsiz, hdrp, space, spsiz) \ if ((hdrp)->pbufsiz <= spsiz) { \ @@ -76,7 +77,7 @@ extern "C" { /* prototypes */ uid_t _nscd_get_client_euid(); -int _nscd_check_client_read_priv(); +int _nscd_check_client_priv(int); int _nscd_setup_server(char *execname, char **argv); int _nscd_setup_child_server(int did); int _nscd_get_clearance(sema_t *sema); diff --git a/usr/src/cmd/nscd/nscd_switch.c b/usr/src/cmd/nscd/nscd_switch.c index ad0b55aa55..dea0ded3dc 100644 --- a/usr/src/cmd/nscd/nscd_switch.c +++ b/usr/src/cmd/nscd/nscd_switch.c @@ -20,7 +20,7 @@ */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -521,6 +521,18 @@ get_gss_func(void **func_p) "libgss.so", "gss_inquire_cred", func_p)); } +static nscd_rc_t +get_sldap_shadow_func(void **func_p) +{ + static void *handle = NULL; + static void *func = NULL; + static mutex_t lock = DEFAULTMUTEX; + + return (get_lib_func(&handle, &func, &lock, + "libsldap.so", "__ns_ldap_is_shadow_update_enabled", + func_p)); +} + /* * get_dns_funcs returns pointers to gethostbyname functions in the * dynamically loaded nss_dns & nss_mdns modules that return host @@ -759,14 +771,46 @@ nss_search(nss_db_root_t *rootp, nss_db_initf_t initf, int search_fnum, _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG) (me, "nsw source = %s\n", NSCD_NSW_SRC_NAME(srci)); - /* if no privilege to look up, skip */ - if (params.privdb == 1 && swret != NULL && - strcmp(NSCD_NSW_SRC_NAME(srci), "files") == 0 && - _nscd_check_client_read_priv() != 0) { - _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG) - (me, "no privilege to look up, skip source\n"); + /* + * If no privilege to look up, skip. + * 'files' requires PRIV_FILE_DAC_READ to read shadow(4) data, + * 'ldap' requires all zones privilege. + */ + if (params.privdb == 1 && swret != NULL) { + boolean_t (*is_shadow_update_enabled)(); + boolean_t check_ldap_priv = B_FALSE; - goto next_src; + if (strcmp(NSCD_NSW_SRC_NAME(srci), "ldap") == 0) { + if (get_sldap_shadow_func( + (void **)&is_shadow_update_enabled) == + NSCD_SUCCESS && + is_shadow_update_enabled()) { + check_ldap_priv = B_TRUE; + + /* + * A peruser nscd doesn't have + * the privileges to lookup a + * private database, such as shadow, + * returns NSS_ALTRETRY to have the + * main nscd do the job. + */ + if (_whoami == NSCD_CHILD) { + res = NSS_ALTRETRY; + goto free_nsw_state; + } + } + } + + if ((strcmp(NSCD_NSW_SRC_NAME(srci), "files") == 0 && + _nscd_check_client_priv(NSCD_READ_PRIV) != 0) || + (check_ldap_priv && + _nscd_check_client_priv(NSCD_ALL_PRIV) != 0)) { + _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, + NSCD_LOG_LEVEL_DEBUG) + (me, "no privilege to look up, skip source\n"); + + goto next_src; + } } /* get state of the (backend) client service */ @@ -1057,7 +1101,7 @@ nss_setent_u(nss_db_root_t *rootp, nss_db_initf_t initf, /* if no privilege to look up, return */ if (params.privdb == 1 && swret != NULL && - _nscd_check_client_read_priv() != 0) { + _nscd_check_client_priv(NSCD_READ_PRIV) != 0) { _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG) (me, "no privilege \n"); diff --git a/usr/src/lib/libsldap/common/ns_cache_door.h b/usr/src/lib/libsldap/common/ns_cache_door.h index 52599534af..8e260c4f53 100644 --- a/usr/src/lib/libsldap/common/ns_cache_door.h +++ b/usr/src/lib/libsldap/common/ns_cache_door.h @@ -195,6 +195,8 @@ typedef union { #define GETSTATUSCHANGE 25 /* perform admin modify via ldap_cachemgr */ #define ADMINMODIFY 26 + /* get admin credentials for shadow lookups */ +#define GETADMINCRED 27 /* * GETLDAPSERVER request flags diff --git a/usr/src/lib/libsldap/common/ns_common.c b/usr/src/lib/libsldap/common/ns_common.c index 3518d1fe41..d800741f91 100644 --- a/usr/src/lib/libsldap/common/ns_common.c +++ b/usr/src/lib/libsldap/common/ns_common.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. */ @@ -252,11 +252,46 @@ __ns_ldap_dupAuth(const ns_cred_t *authp) } /* + * FUNCTION: __ns_ldap_freeUnixCred + * + * Frees all the memory associated with a UnixCred_t structure. + * + * RETURN VALUES: NS_LDAP_INVALID_PARAM, NS_LDAP_SUCCESS + * INPUT: UnixCred + */ +int +__ns_ldap_freeUnixCred(UnixCred_t ** credp) +{ + UnixCred_t *ap; + +#ifdef DEBUG + (void) fprintf(stderr, "__ns_ldap_freeUnixCred START\n"); +#endif + if (credp == NULL || *credp == NULL) + return (NS_LDAP_INVALID_PARAM); + + ap = *credp; + if (ap->userID) { + (void) memset(ap->userID, 0, strlen(ap->userID)); + free(ap->userID); + } + + if (ap->passwd) { + (void) memset(ap->passwd, 0, strlen(ap->passwd)); + free(ap->passwd); + } + + free(ap); + *credp = NULL; + return (NS_LDAP_SUCCESS); +} + +/* * FUNCTION: __ns_ldap_freeCred * * Frees all the memory associated with a ns_cred_t structure. * - * RETURN VALUES: NS_LDAP_INVALID_PARAM, NS_LDAP_SUCCESS, NS_LDAP_CONFIG + * RETURN VALUES: NS_LDAP_INVALID_PARAM, NS_LDAP_SUCCESS * INPUT: ns_cred_t */ int diff --git a/usr/src/lib/libsldap/common/ns_config.c b/usr/src/lib/libsldap/common/ns_config.c index 1a7a21bfee..96f3673428 100644 --- a/usr/src/lib/libsldap/common/ns_config.c +++ b/usr/src/lib/libsldap/common/ns_config.c @@ -3335,8 +3335,10 @@ __s_api_strValue(ns_config_t *cfg, char *str, return (buf); } -static int -__door_getldapconfig(char **buffer, int *buflen, ns_ldap_error_t **error) +/* shared by __door_getldapconfig() and __door_getadmincred() */ +int +__door_getconf(char **buffer, int *buflen, ns_ldap_error_t **error, + int callnumber) { typedef union { ldap_data_t s_d; @@ -3367,7 +3369,7 @@ __door_getldapconfig(char **buffer, int *buflen, ns_ldap_error_t **error) adata = (sizeof (ldap_call_t) + strlen(domainname) +1); ndata = sizeof (space_t); - space->s_d.ldap_call.ldap_callnumber = GETLDAPCONFIGV1; + space->s_d.ldap_call.ldap_callnumber = callnumber; (void) strcpy(space->s_d.ldap_call.ldap_u.domainname, domainname); free(domainname); domainname = NULL; @@ -3410,6 +3412,73 @@ __door_getldapconfig(char **buffer, int *buflen, ns_ldap_error_t **error) return (retCode); } +static int +__door_getldapconfig(char **buffer, int *buflen, ns_ldap_error_t **error) +{ + return (__door_getconf(buffer, buflen, error, GETLDAPCONFIGV1)); +} + +/* + * SetDoorInfoToUnixCred parses ldapcachemgr configuration information + * for Admin credentials. + */ +int +SetDoorInfoToUnixCred(char *buffer, ns_ldap_error_t **errorp, + UnixCred_t **cred) +{ + UnixCred_t *ptr; + char errstr[MAXERROR]; + char *name, *value, valbuf[BUFSIZE]; + char *bufptr = buffer; + char *strptr; + char *rest; + ParamIndexType index = 0; + ldap_config_out_t *cfghdr; + + if (errorp == NULL || cred == NULL || *cred == NULL) + return (NS_LDAP_INVALID_PARAM); + *errorp = NULL; + + ptr = *cred; + + cfghdr = (ldap_config_out_t *)bufptr; + bufptr = (char *)cfghdr->config_str; + + strptr = (char *)strtok_r(bufptr, DOORLINESEP, &rest); + for (; ; ) { + if (strptr == NULL) + break; + (void) strlcpy(valbuf, strptr, sizeof (valbuf)); + __s_api_split_key_value(valbuf, &name, &value); + if (__ns_ldap_getParamType(name, &index) != 0) { + (void) snprintf(errstr, MAXERROR, + gettext("SetDoorInfoToUnixCred: " + "Unknown keyword encountered '%s'."), name); + MKERROR(LOG_ERR, *errorp, NS_CONFIG_SYNTAX, + strdup(errstr), NULL); + return (NS_LDAP_CONFIG); + } + switch (index) { + case NS_LDAP_ADMIN_BINDDN_P: + ptr->userID = (char *)strdup(value); + break; + case NS_LDAP_ADMIN_BINDPASSWD_P: + ptr->passwd = (char *)strdup(value); + break; + default: + (void) snprintf(errstr, MAXERROR, + gettext("SetDoorInfoToUnixCred: " + "Unknown index encountered '%d'."), index); + MKERROR(LOG_ERR, *errorp, NS_CONFIG_SYNTAX, + strdup(errstr), NULL); + return (NS_LDAP_CONFIG); + } + strptr = (char *)strtok_r(NULL, DOORLINESEP, &rest); + } + + return (NS_LDAP_SUCCESS); +} + /* * SetDoorInfo parses ldapcachemgr configuration information * and verifies that the profile is version 1 or version 2 based. diff --git a/usr/src/lib/libsldap/common/ns_confmgr.c b/usr/src/lib/libsldap/common/ns_confmgr.c index a96f186ded..d6c9fcfaac 100644 --- a/usr/src/lib/libsldap/common/ns_confmgr.c +++ b/usr/src/lib/libsldap/common/ns_confmgr.c @@ -463,10 +463,13 @@ _print2buf(LineBuf *line, char *toprint, int addsep) * domainname is transmitted to ldapcachemgr and ldapcachemgr uses * it to select a configuration to transmit back. Otherwise it * is essentially unused in sldap. + * If cred_only is not 0, then only the credentials for shadow + * update are taken care of. */ ns_ldap_error_t * -__ns_ldap_LoadDoorInfo(LineBuf *configinfo, char *domainname, ns_config_t *new) +__ns_ldap_LoadDoorInfo(LineBuf *configinfo, char *domainname, + ns_config_t *new, int cred_only) { ns_config_t *ptr; char errstr[MAXERROR]; @@ -497,10 +500,17 @@ __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; + if (cred_only) { + /* only exposed credential for shadow update */ + if (i != NS_LDAP_ADMIN_BINDDN_P && + i != NS_LDAP_ADMIN_BINDPASSWD_P) + continue; + } else { + /* 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) diff --git a/usr/src/lib/libsldap/common/ns_connect.c b/usr/src/lib/libsldap/common/ns_connect.c index 67cdee702f..5be22acc27 100644 --- a/usr/src/lib/libsldap/common/ns_connect.c +++ b/usr/src/lib/libsldap/common/ns_connect.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 <stdlib.h> #include <stdio.h> #include <errno.h> @@ -68,6 +66,13 @@ extern int ldap_sasl_cram_md5_bind_s(LDAP *, char *, struct berval *, LDAPControl **, LDAPControl **); extern int ldapssl_install_gethostbyaddr(LDAP *ld, const char *skip); +extern int __door_getconf(char **buffer, int *buflen, + ns_ldap_error_t **error, int callnumber); +extern int __ns_ldap_freeUnixCred(UnixCred_t **credp); +extern int SetDoorInfoToUnixCred(char *buffer, + ns_ldap_error_t **errorp, + UnixCred_t **cred); + static int openConnection(LDAP **, const char *, const ns_cred_t *, int, ns_ldap_error_t **, int, int, ns_conn_user_t *); static void @@ -135,6 +140,41 @@ getFirstFromConfig(ns_server_info_t *ret, ns_ldap_error_t **error) return (NS_LDAP_SUCCESS); } +/* very similar to __door_getldapconfig() in ns_config.c */ +static int +__door_getadmincred(char **buffer, int *buflen, ns_ldap_error_t **error) +{ + return (__door_getconf(buffer, buflen, error, GETADMINCRED)); +} + +/* + * This function requests Admin credentials from the cache manager through + * the door functionality + */ + +static int +requestAdminCred(UnixCred_t **cred, ns_ldap_error_t **error) +{ + char *buffer = NULL; + int buflen = 0; + int ret; + + *error = NULL; + ret = __door_getadmincred(&buffer, &buflen, error); + + if (ret != NS_LDAP_SUCCESS) { + if (*error != NULL && (*error)->message != NULL) + syslog(LOG_WARNING, "libsldap: %s", (*error)->message); + return (ret); + } + + /* now convert from door format */ + ret = SetDoorInfoToUnixCred(buffer, error, cred); + free(buffer); + + return (ret); +} + /* * This function requests a server from the cache manager through * the door functionality @@ -1418,6 +1458,8 @@ openConnection(LDAP **ldp, const char *serverAddr, const ns_cred_t *auth, * * aMethod Currently requested authentication method to be tried * + * getAdmin If non 0, get Admin -i.e., not proxyAgent- DN and password + * * OUTPUT: * * authp authentication method to use. @@ -1426,7 +1468,8 @@ static int __s_api_getDefaultAuth( int *cLevel, ns_auth_t *aMethod, - ns_cred_t **authp) + ns_cred_t **authp, + int getAdmin) { void **paramVal = NULL; char *modparamVal = NULL; @@ -1435,6 +1478,7 @@ __s_api_getDefaultAuth( int getCertpath = 0; int rc = 0; ns_ldap_error_t *errorp = NULL; + UnixCred_t *AdminCred = NULL; #ifdef DEBUG (void) fprintf(stderr, "__s_api_getDefaultAuth START\n"); @@ -1472,7 +1516,6 @@ __s_api_getDefaultAuth( getPasswd++; } else if (aMethod->saslmech != NS_LDAP_SASL_GSSAPI) { (void) __ns_ldap_freeCred(authp); - *authp = NULL; return (NS_LDAP_INVALID_PARAM); } break; @@ -1488,7 +1531,6 @@ __s_api_getDefaultAuth( getCertpath++; } else { (void) __ns_ldap_freeCred(authp); - *authp = NULL; return (NS_LDAP_INVALID_PARAM); } break; @@ -1496,51 +1538,99 @@ __s_api_getDefaultAuth( if (getUid) { paramVal = NULL; - if ((rc = __ns_ldap_getParam(NS_LDAP_BINDDN_P, - ¶mVal, &errorp)) != NS_LDAP_SUCCESS) { - (void) __ns_ldap_freeCred(authp); - (void) __ns_ldap_freeError(&errorp); - *authp = NULL; - return (rc); - } + if (getAdmin) { + /* + * Assume AdminCred has been retrieved from + * ldap_cachemgr already. It will not work + * without userID or password. Flags getUid + * and getPasswd should always be set + * together. + */ + AdminCred = calloc(1, sizeof (UnixCred_t)); + if (AdminCred == NULL) { + (void) __ns_ldap_freeCred(authp); + return (NS_LDAP_MEMORY); + } - if (paramVal == NULL || *paramVal == NULL) { - (void) __ns_ldap_freeCred(authp); - *authp = NULL; - return (NS_LDAP_INVALID_PARAM); - } + rc = requestAdminCred(&AdminCred, &errorp); + if (rc != NS_LDAP_SUCCESS) { + (void) __ns_ldap_freeCred(authp); + (void) __ns_ldap_freeUnixCred(&AdminCred); + (void) __ns_ldap_freeError(&errorp); + return (rc); + } - (*authp)->cred.unix_cred.userID = strdup((char *)*paramVal); - (void) __ns_ldap_freeParam(¶mVal); + if (AdminCred->userID == NULL) { + (void) __ns_ldap_freeCred(authp); + (void) __ns_ldap_freeUnixCred(&AdminCred); + return (NS_LDAP_INVALID_PARAM); + } + (*authp)->cred.unix_cred.userID = AdminCred->userID; + AdminCred->userID = NULL; + } else { + rc = __ns_ldap_getParam(NS_LDAP_BINDDN_P, + ¶mVal, &errorp); + if (rc != NS_LDAP_SUCCESS) { + (void) __ns_ldap_freeCred(authp); + (void) __ns_ldap_freeError(&errorp); + return (rc); + } + + if (paramVal == NULL || *paramVal == NULL) { + (void) __ns_ldap_freeCred(authp); + return (NS_LDAP_INVALID_PARAM); + } + + (*authp)->cred.unix_cred.userID = + strdup((char *)*paramVal); + (void) __ns_ldap_freeParam(¶mVal); + } if ((*authp)->cred.unix_cred.userID == NULL) { (void) __ns_ldap_freeCred(authp); - *authp = NULL; + (void) __ns_ldap_freeUnixCred(&AdminCred); return (NS_LDAP_MEMORY); } } if (getPasswd) { paramVal = NULL; - if ((rc = __ns_ldap_getParam(NS_LDAP_BINDPASSWD_P, - ¶mVal, &errorp)) != NS_LDAP_SUCCESS) { - (void) __ns_ldap_freeCred(authp); - (void) __ns_ldap_freeError(&errorp); - *authp = NULL; - return (rc); - } + if (getAdmin) { + /* + * Assume AdminCred has been retrieved from + * ldap_cachemgr already. It will not work + * without the userID anyway because for + * getting admin credential, flags getUid + * and getPasswd should always be set + * together. + */ + if (AdminCred == NULL || AdminCred->passwd == NULL) { + (void) __ns_ldap_freeCred(authp); + (void) __ns_ldap_freeUnixCred(&AdminCred); + return (NS_LDAP_INVALID_PARAM); + } + modparamVal = dvalue(AdminCred->passwd); + } else { + rc = __ns_ldap_getParam(NS_LDAP_BINDPASSWD_P, + ¶mVal, &errorp); + if (rc != NS_LDAP_SUCCESS) { + (void) __ns_ldap_freeCred(authp); + (void) __ns_ldap_freeError(&errorp); + return (rc); + } - if (paramVal == NULL || *paramVal == NULL) { - (void) __ns_ldap_freeCred(authp); - *authp = NULL; - return (NS_LDAP_INVALID_PARAM); + if (paramVal == NULL || *paramVal == NULL) { + (void) __ns_ldap_freeCred(authp); + return (NS_LDAP_INVALID_PARAM); + } + + modparamVal = dvalue((char *)*paramVal); + (void) __ns_ldap_freeParam(¶mVal); } - modparamVal = dvalue((char *)*paramVal); - (void) __ns_ldap_freeParam(¶mVal); if (modparamVal == NULL || (strlen((char *)modparamVal) == 0)) { (void) __ns_ldap_freeCred(authp); + (void) __ns_ldap_freeUnixCred(&AdminCred); if (modparamVal != NULL) free(modparamVal); - *authp = NULL; return (NS_LDAP_INVALID_PARAM); } @@ -1551,6 +1641,7 @@ __s_api_getDefaultAuth( if ((rc = __ns_ldap_getParam(NS_LDAP_HOST_CERTPATH_P, ¶mVal, &errorp)) != NS_LDAP_SUCCESS) { (void) __ns_ldap_freeCred(authp); + (void) __ns_ldap_freeUnixCred(&AdminCred); (void) __ns_ldap_freeError(&errorp); *authp = NULL; return (rc); @@ -1558,6 +1649,7 @@ __s_api_getDefaultAuth( if (paramVal == NULL || *paramVal == NULL) { (void) __ns_ldap_freeCred(authp); + (void) __ns_ldap_freeUnixCred(&AdminCred); *authp = NULL; return (NS_LDAP_INVALID_PARAM); } @@ -1566,10 +1658,12 @@ __s_api_getDefaultAuth( (void) __ns_ldap_freeParam(¶mVal); if ((*authp)->hostcertpath == NULL) { (void) __ns_ldap_freeCred(authp); + (void) __ns_ldap_freeUnixCred(&AdminCred); *authp = NULL; return (NS_LDAP_MEMORY); } } + (void) __ns_ldap_freeUnixCred(&AdminCred); return (NS_LDAP_SUCCESS); } @@ -1759,7 +1853,8 @@ getConnection( /* with default credentials */ authp = NULL; rc = __s_api_getDefaultAuth(*cNext, - *aNext, &authp); + *aNext, &authp, + flags & NS_LDAP_READ_SHADOW); if (rc != NS_LDAP_SUCCESS) { continue; } diff --git a/usr/src/lib/libsldap/common/ns_internal.h b/usr/src/lib/libsldap/common/ns_internal.h index a389ef0e28..3157e141ed 100644 --- a/usr/src/lib/libsldap/common/ns_internal.h +++ b/usr/src/lib/libsldap/common/ns_internal.h @@ -831,7 +831,7 @@ char **__ns_ldap_mapAttributeList(const char *service, void __ns_ldap_setServer(int set); ns_ldap_error_t *__ns_ldap_LoadConfiguration(); ns_ldap_error_t *__ns_ldap_LoadDoorInfo(LineBuf *configinfo, char *domainname, - ns_config_t *new); + ns_config_t *new, int cred_only); ns_ldap_error_t *__ns_ldap_DumpConfiguration(char *filename); ns_ldap_error_t *__ns_ldap_DumpLdif(char *filename); int __ns_ldap_cache_ping(); diff --git a/usr/src/lib/libsldap/common/ns_reads.c b/usr/src/lib/libsldap/common/ns_reads.c index a2d658252d..7b65cd986b 100644 --- a/usr/src/lib/libsldap/common/ns_reads.c +++ b/usr/src/lib/libsldap/common/ns_reads.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> @@ -36,6 +34,7 @@ #include <unistd.h> #include <string.h> #include <strings.h> +#include <priv.h> #include "ns_sldap.h" #include "ns_internal.h" @@ -2824,6 +2823,70 @@ search_state_machine(ns_ldap_cookie_t *cookie, ns_state_t state, int cycle) } /* + * For a lookup of shadow data, if shadow update is enabled, + * check the calling process' privilege to ensure it's + * allowed to perform such operation. + */ +static int +check_shadow(ns_ldap_cookie_t *cookie, const char *service) +{ + char errstr[MAXERROR]; + char *err; + boolean_t priv; + /* caller */ + priv_set_t *ps; + /* zone */ + priv_set_t *zs; + + /* + * If service is "shadow", we may need + * to use privilege credentials. + */ + if ((strcmp(service, "shadow") == 0) && + __ns_ldap_is_shadow_update_enabled()) { + /* + * Since we release admin credentials after + * connection is closed and we do not cache + * them, we allow any root or all zone + * privilege process to read shadow data. + */ + priv = (geteuid() == 0); + if (!priv) { + /* caller */ + ps = priv_allocset(); + + (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) { + (void) sprintf(errstr, + gettext("Permission denied")); + err = strdup(errstr); + if (err == NULL) + return (NS_LDAP_MEMORY); + MKERROR(LOG_INFO, cookie->errorp, NS_LDAP_INTERNAL, err, + NULL); + return (NS_LDAP_INTERNAL); + } + cookie->i_flags |= NS_LDAP_READ_SHADOW; + /* + * We do not want to reuse connection (hence + * keep it open) with admin credentials. + * If NS_LDAP_KEEP_CONN is set, reject the + * request. + */ + if (cookie->i_flags & NS_LDAP_KEEP_CONN) + return (NS_LDAP_INVALID_PARAM); + cookie->i_flags |= NS_LDAP_NEW_CONN; + } + + return (NS_LDAP_SUCCESS); +} + +/* * internal function for __ns_ldap_list */ static int @@ -2855,6 +2918,13 @@ ldap_list( *rResult = NULL; *rcp = NS_LDAP_SUCCESS; + /* + * Sanity check - NS_LDAP_READ_SHADOW is for our + * own internal use. + */ + if (flags & NS_LDAP_READ_SHADOW) + return (NS_LDAP_INVALID_PARAM); + /* Initialize State machine cookie */ cookie = init_search_state_machine(); if (cookie == NULL) { @@ -2947,6 +3017,9 @@ ldap_list( cookie->callback = callback; cookie->use_usercb = 1; } + + /* check_shadow() may add extra value to cookie->i_flags */ + cookie->i_flags = flags; if (service) { cookie->service = strdup(service); if (cookie->service == NULL) { @@ -2955,12 +3028,27 @@ ldap_list( *rcp = NS_LDAP_MEMORY; return (NS_LDAP_MEMORY); } + + /* + * If given, use the credential given by the caller, and + * skip the credential check required for shadow update. + */ + if (auth == NULL) { + rc = check_shadow(cookie, service); + if (rc != NS_LDAP_SUCCESS) { + *errorp = cookie->errorp; + cookie->errorp = NULL; + delete_search_cookie(cookie); + cookie = NULL; + *rcp = rc; + return (rc); + } + } } cookie->i_filter = strdup(filter); cookie->i_attr = attribute; cookie->i_auth = auth; - cookie->i_flags = flags; if (batch != NULL) { cookie->batch = batch; @@ -3450,6 +3538,13 @@ firstEntry( *errorp = NULL; *result = NULL; + /* + * Sanity check - NS_LDAP_READ_SHADOW is for our + * own internal use. + */ + if (flags & NS_LDAP_READ_SHADOW) + return (NS_LDAP_INVALID_PARAM); + /* get the service descriptor - or create a default one */ rc = __s_api_get_SSD_from_SSDtoUse_service(service, &sdlist, errorp); @@ -3545,18 +3640,34 @@ firstEntry( cookie->use_filtercb = 1; } cookie->use_usercb = 0; + /* check_shadow() may add extra value to cookie->i_flags */ + cookie->i_flags = flags; if (service) { cookie->service = strdup(service); if (cookie->service == NULL) { delete_search_cookie(cookie); return (NS_LDAP_MEMORY); } + + /* + * If given, use the credential given by the caller, and + * skip the credential check required for shadow update. + */ + if (auth == NULL) { + rc = check_shadow(cookie, service); + if (rc != NS_LDAP_SUCCESS) { + *errorp = cookie->errorp; + cookie->errorp = NULL; + delete_search_cookie(cookie); + cookie = NULL; + return (rc); + } + } } cookie->i_filter = strdup(filter); cookie->i_attr = attribute; cookie->i_auth = auth; - cookie->i_flags = flags; state = INIT; for (;;) { diff --git a/usr/src/lib/libsldap/common/ns_sldap.h b/usr/src/lib/libsldap/common/ns_sldap.h index f8bb420019..a540e7d2f1 100644 --- a/usr/src/lib/libsldap/common/ns_sldap.h +++ b/usr/src/lib/libsldap/common/ns_sldap.h @@ -91,6 +91,13 @@ typedef enum ScopeType { #define NS_LDAP_UPDATE_SHADOW 0x4000 /* + * NS_LDAP_READ_SHADOW is for a privileged caller of __ns_ldap_list() + * and __ns_ldap_firstEntry() to read the shadow database on the + * LDAP server. + */ +#define NS_LDAP_READ_SHADOW 0x8000 + +/* * Authentication Information */ typedef enum CredLevel { |