summaryrefslogtreecommitdiff
path: root/usr/src
diff options
context:
space:
mode:
authorJulian Pullen <Julian.Pullen@Sun.COM>2009-05-08 17:38:01 +0100
committerJulian Pullen <Julian.Pullen@Sun.COM>2009-05-08 17:38:01 +0100
commitb57459abfba36eb3068cfe44c6921168b4c4f774 (patch)
tree5479f0844784d6b0929894abd0b14e3cee9135bd /usr/src
parentc9d66ba7a02565d1320b4a0780e249cfe8c02612 (diff)
downloadillumos-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.sh381
-rw-r--r--usr/src/cmd/ldapcachemgr/cachemgr.c19
-rw-r--r--usr/src/cmd/ldapcachemgr/cachemgr.h5
-rw-r--r--usr/src/cmd/ldapcachemgr/cachemgr_change.c8
-rw-r--r--usr/src/cmd/ldapcachemgr/cachemgr_getldap.c44
-rw-r--r--usr/src/cmd/nscd/nscd_frontend.c33
-rw-r--r--usr/src/cmd/nscd/nscd_frontend.h9
-rw-r--r--usr/src/cmd/nscd/nscd_switch.c62
-rw-r--r--usr/src/lib/libsldap/common/ns_cache_door.h2
-rw-r--r--usr/src/lib/libsldap/common/ns_common.c39
-rw-r--r--usr/src/lib/libsldap/common/ns_config.c75
-rw-r--r--usr/src/lib/libsldap/common/ns_confmgr.c20
-rw-r--r--usr/src/lib/libsldap/common/ns_connect.c167
-rw-r--r--usr/src/lib/libsldap/common/ns_internal.h2
-rw-r--r--usr/src/lib/libsldap/common/ns_reads.c121
-rw-r--r--usr/src/lib/libsldap/common/ns_sldap.h7
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,
- &paramVal, &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(&paramVal);
+ 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,
+ &paramVal, &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(&paramVal);
+ }
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,
- &paramVal, &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,
+ &paramVal, &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(&paramVal);
}
- modparamVal = dvalue((char *)*paramVal);
- (void) __ns_ldap_freeParam(&paramVal);
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,
&paramVal, &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(&paramVal);
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 {