diff options
author | djl <none@none> | 2006-09-29 06:00:17 -0700 |
---|---|---|
committer | djl <none@none> | 2006-09-29 06:00:17 -0700 |
commit | cb5caa98562cf06753163f558cbcfe30b8f4673a (patch) | |
tree | 7a24623821583899295e29553207e69701b471ff /usr/src | |
parent | 350f572a3fa518fc3690d53066c2c54fd03b5a08 (diff) | |
download | illumos-gate-cb5caa98562cf06753163f558cbcfe30b8f4673a.tar.gz |
PSARC 2005/133 Sparks: Name Service Switch 2
4406529 artificial limit of 10 threads per backend
4516075 LDAP connections could be reused more
4696964 LDAP naming services should support Kerberos authentication
4740951 Need host based authentication options in Native LDAP
4952533 Some backends of gethostby* do not set h_errno correctly
4979596 getXbyY calls should have better buffer mechanism
5028908 /usr/bin/logins accesses free memory deep in nss_getent_u().
5046881 nscd: old-data-ok parameter is not useful, should go away
6225323 NSS/nscd Enhancements (Sparks Project)
--HG--
rename : usr/src/cmd/nscd/attrstr.c => deleted_files/usr/src/cmd/nscd/attrstr.c
rename : usr/src/cmd/nscd/hash.c => deleted_files/usr/src/cmd/nscd/hash.c
rename : usr/src/cmd/nscd/nscd_parse.c => deleted_files/usr/src/cmd/nscd/nscd_parse.c
rename : usr/src/cmd/nscd/nscd.h => usr/src/cmd/nscd/cache.h
Diffstat (limited to 'usr/src')
236 files changed, 33883 insertions, 14925 deletions
diff --git a/usr/src/Makefile.lint b/usr/src/Makefile.lint index 6b744020b8..39e8a32294 100644 --- a/usr/src/Makefile.lint +++ b/usr/src/Makefile.lint @@ -194,6 +194,7 @@ COMMON_SUBDIRS = \ cmd/nispasswd \ cmd/nl \ cmd/nohup \ + cmd/nscd \ cmd/pagesize \ cmd/passwd \ cmd/pathchk \ @@ -377,6 +378,7 @@ COMMON_SUBDIRS = \ lib/mpss \ lib/nametoaddr \ lib/ncad_addr \ + lib/nsswitch \ lib/pam_modules \ lib/passwdutil \ lib/pkcs11 \ diff --git a/usr/src/cmd/initpkg/nscd.conf b/usr/src/cmd/initpkg/nscd.conf index 9152f40cb4..a2a06950ce 100644 --- a/usr/src/cmd/initpkg/nscd.conf +++ b/usr/src/cmd/initpkg/nscd.conf @@ -2,9 +2,8 @@ # CDDL HEADER START # # The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. @@ -20,67 +19,120 @@ # CDDL HEADER END # # -# Copyright (c) 1994-2001 by Sun Microsystems, Inc. -# All rights reserved. +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. # #ident "%Z%%M% %I% %E% SMI" # # -# Currently supported cache names: passwd, group, hosts, ipnodes -# exec_attr, prof_attr, user_attr +# Currently supported cache names: +# audit_user, auth_attr, bootparams, ethers +# exec_attr, group, hosts, ipnodes, netmasks +# networks, passwd, printers, prof_attr, project +# protocols, rpc, services, tnrhdb, tnrhtp, user_attr # - # logfile /var/adm/nscd.log # enable-cache hosts no debug-level 0 - positive-time-to-live passwd 600 - negative-time-to-live passwd 5 - suggested-size passwd 211 - keep-hot-count passwd 20 - old-data-ok passwd no - check-files passwd yes + positive-time-to-live audit_user 3600 + negative-time-to-live audit_user 5 + keep-hot-count audit_user 20 + check-files audit_user yes + + positive-time-to-live auth_attr 3600 + negative-time-to-live auth_attr 5 + keep-hot-count auth_attr 20 + check-files auth_attr yes + + positive-time-to-live bootparams 3600 + negative-time-to-live bootparams 5 + keep-hot-count bootparams 20 + check-files bootparams yes + + positive-time-to-live ethers 3600 + negative-time-to-live ethers 5 + keep-hot-count ethers 20 + check-files ethers yes + + positive-time-to-live exec_attr 3600 + negative-time-to-live exec_attr 300 + keep-hot-count exec_attr 20 + check-files exec_attr yes positive-time-to-live group 3600 negative-time-to-live group 5 - suggested-size group 211 keep-hot-count group 20 - old-data-ok group no check-files group yes positive-time-to-live hosts 3600 negative-time-to-live hosts 5 - suggested-size hosts 211 keep-hot-count hosts 20 - old-data-ok hosts no check-files hosts yes positive-time-to-live ipnodes 3600 negative-time-to-live ipnodes 5 - suggested-size ipnodes 211 keep-hot-count ipnodes 20 - old-data-ok ipnodes no check-files ipnodes yes - positive-time-to-live exec_attr 3600 - negative-time-to-live exec_attr 300 - suggested-size exec_attr 211 - keep-hot-count exec_attr 20 - old-data-ok exec_attr no - check-files exec_attr yes + positive-time-to-live netmasks 3600 + negative-time-to-live netmasks 5 + keep-hot-count netmasks 20 + check-files netmasks yes + + positive-time-to-live networks 3600 + negative-time-to-live networks 5 + keep-hot-count networks 20 + check-files networks yes + + positive-time-to-live passwd 600 + negative-time-to-live passwd 5 + keep-hot-count passwd 20 + check-files passwd yes + + positive-time-to-live printers 3600 + negative-time-to-live printers 5 + keep-hot-count printers 20 + check-files printers yes positive-time-to-live prof_attr 3600 negative-time-to-live prof_attr 5 - suggested-size prof_attr 211 keep-hot-count prof_attr 20 - old-data-ok prof_attr no check-files prof_attr yes + positive-time-to-live project 3600 + negative-time-to-live project 5 + keep-hot-count project 20 + check-files project yes + + positive-time-to-live protocols 3600 + negative-time-to-live protocols 5 + keep-hot-count protocols 20 + check-files protocols yes + + positive-time-to-live rpc 3600 + negative-time-to-live rpc 5 + keep-hot-count rpc 20 + check-files rpc yes + + positive-time-to-live services 3600 + negative-time-to-live services 5 + keep-hot-count services 20 + check-files services yes + + positive-time-to-live tnrhdb 3600 + negative-time-to-live tnrhdb 5 + keep-hot-count tnrhdb 20 + check-files tnrhdb yes + + positive-time-to-live tnrhtp 3600 + negative-time-to-live tnrhtp 5 + keep-hot-count tnrhtp 20 + check-files tnrhtp yes + positive-time-to-live user_attr 3600 negative-time-to-live user_attr 5 - suggested-size user_attr 211 keep-hot-count user_attr 20 - old-data-ok user_attr no check-files user_attr yes diff --git a/usr/src/cmd/ldap/Makefile.com b/usr/src/cmd/ldap/Makefile.com index d65d341a22..f6b9609477 100644 --- a/usr/src/cmd/ldap/Makefile.com +++ b/usr/src/cmd/ldap/Makefile.com @@ -95,9 +95,9 @@ lint:= TARGET= lint # C Pre-Processor flags used by C, CC & lint CPPFLAGS += -DSUN -DSVR4 -DSOLARIS_LDAP_CMD \ - -I ../../../lib/libldap5/include/ldap \ - -I ../../../lib/libsldap/common \ - -I ../../../lib/libnsl/include/rpcsvc \ + -I $(SRC)/lib/libldap5/include/ldap \ + -I $(SRC)/lib/libsldap/common \ + -I $(SRC)/lib/libnsl/include/rpcsvc \ -DNO_LIBLCACHE -DLDAP_REFERRALS -DNET_SSL -DLDAPSSLIO \ -DHAVE_SASL_OPTIONS -DSOLARIS_LDAP_CMD LDLIBS += $(COMPLIB) @@ -177,7 +177,7 @@ lintns_ldaplist: lintns_ldapaddent: $(LINT.c) $(LDAPADDENTSRCS:%=../ns_ldap/%) $(LDLIBS) -lsldap -lnsl \ - >> $(LINTOUT) 2>&1 + -lsecdb >> $(LINTOUT) 2>&1 lintns_ldapclient: $(LINT.c) $(LDAPCLIENTSRCS:%=../ns_ldap/%) $(LDLIBS) -lsldap -lscf \ diff --git a/usr/src/cmd/ldap/ns_ldap/idsconfig.sh b/usr/src/cmd/ldap/ns_ldap/idsconfig.sh index 3e81b6d6bb..d1d38b3dca 100644 --- a/usr/src/cmd/ldap/ns_ldap/idsconfig.sh +++ b/usr/src/cmd/ldap/ns_ldap/idsconfig.sh @@ -22,7 +22,7 @@ # CDDL HEADER END # # -# idsconfig -- script to setup iDS 5.x for Native LDAP II. +# idsconfig -- script to setup iDS 5.x/6.x for Native LDAP II. # # Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. @@ -69,6 +69,9 @@ The following are the supported credential levels: 1 anonymous 2 proxy 3 proxy anonymous + 4 self + 5 self proxy + 6 self proxy anonymous EOF ;; auth_method_menu) cat <<EOF @@ -78,6 +81,7 @@ The following are the supported Authentication Methods: 3 sasl/DIGEST-MD5 4 tls:simple 5 tls:sasl/DIGEST-MD5 + 6 sasl/GSSAPI EOF ;; srvauth_method_menu) cat <<EOF @@ -86,6 +90,7 @@ The following are the supported Authentication Methods: 2 sasl/DIGEST-MD5 3 tls:simple 4 tls:sasl/DIGEST-MD5 + 5 sasl/GSSAPI EOF ;; prompt_ssd_menu) cat <<EOF @@ -931,6 +936,7 @@ init() DEBUG=0 # Set Debug OFF BACKUP=no_ldap # backup suffix HOST="" # NULL or <hostname> + NAWK="/usr/bin/nawk" DOM="" # Set to NULL # If DNS domain (resolv.conf) exists use that, otherwise use domainname. @@ -1015,6 +1021,11 @@ init() # Set the SSD file name after setting TMPDIR. SSD_FILE=${TMPDIR}/ssd_list + + # GSSAPI setup + LDAP_KRB_REALM="" + LDAP_GSSAPI_PROFILE="" + SCHEMA_UPDATED=0 export DEBUG VERB ECHO EVAL EGREP GREP STEP TMPDIR export IDS_SERVER IDS_PORT LDAP_ROOTDN LDAP_ROOTPWD LDAP_SERVER_LIST @@ -1027,7 +1038,7 @@ init() export NEED_SRVAUTH_PAM NEED_SRVAUTH_KEY NEED_SRVAUTH_CMD export LDAP_SRV_AUTHMETHOD_PAM LDAP_SRV_AUTHMETHOD_KEY LDAP_SRV_AUTHMETHOD_CMD export LDAP_SERV_SRCH_DES SSD_FILE - export GEN_CMD + export GEN_CMD LDAP_KRB_REALM LDAP_GSSAPI_PROFILE SCHEMA_UPDATED } @@ -1127,8 +1138,8 @@ get_ids_server() while : do # Prompt for server name. - get_ans "Enter the iPlanet Directory Server's (iDS) hostname to setup:" "$IDS_SERVER" - IDS_SERVER=$ANS + get_ans "Enter the JES Directory Server's hostname to setup:" "$IDS_SERVER" + IDS_SERVER="$ANS" # Ping server to see if live. If valid break out of loop. ping $IDS_SERVER > /dev/null 2>&1 @@ -1159,7 +1170,6 @@ get_ids_port() # Enter port number. get_number "Enter the port number for iDS (h=help):" "$IDS_PORT" "port_help" IDS_PORT=$ANS - # Do a simple search to check hostname and port number. # If search returns SUCCESS, break out, host and port must # be valid. @@ -1196,8 +1206,8 @@ chk_ids_version() IDS_VER=`cat ${TMPDIR}/checkDSver` IDS_MAJVER=`${ECHO} ${IDS_VER} | cut -f1 -d.` IDS_MINVER=`${ECHO} ${IDS_VER} | cut -f2 -d.` - if [ "${IDS_MAJVER}" != "5" ]; then - ${ECHO} "ERROR: $PROG only works with iDS version 5.x, not ${IDS_VER}." + if [ "${IDS_MAJVER}" != "5" ] && [ "${IDS_MAJVER}" != "6" ]; then + ${ECHO} "ERROR: $PROG only works with JES DS version 5.x and 6.x, not ${IDS_VER}." exit 1 fi if [ $DEBUG -eq 1 ]; then @@ -1336,7 +1346,326 @@ get_basedn() done } +get_krb_realm() { + + # To upper cases + LDAP_KRB_REALM=`${ECHO} ${LDAP_DOMAIN} | ${NAWK} '{ print toupper($0) }'` + get_ans_req "Enter Kerberos Realm:" "$LDAP_KRB_REALM" + # To upper cases + LDAP_KRB_REALM=`${ECHO} ${ANS} | ${NAWK} '{ print toupper($0) }'` +} + +# $1: DN +# $2: ldif file +add_entry_by_DN() { + + ${EVAL} "${LDAPSEARCH} ${LDAP_ARGS} -b \"${1}\" -s base \"objectclass=*\" ${VERB}" + if [ $? -eq 0 ]; then + ${ECHO} " ${1} already exists" + return 0 + else + ${EVAL} "${LDAPADD} ${LDAP_ARGS} -f ${2} ${VERB}" + if [ $? -eq 0 ]; then + ${ECHO} " ${1} is added" + return 0 + else + ${ECHO} " ERROR: failed to add ${1}" + return 1 + fi + fi + +} +# +# Kerberos princiapl to DN mapping rules +# +# Add rules for host credentails and user credentials +# +add_id_mapping_rules() { + + ${ECHO} " Adding Kerberos principal to DN mapping rules..." + + _C_DN="cn=GSSAPI,cn=identity mapping,cn=config" + ( cat << EOF +dn: cn=GSSAPI,cn=identity mapping,cn=config +objectClass: top +objectClass: nsContainer +cn: GSSAPI +EOF +) > ${TMPDIR}/GSSAPI_container.ldif + + add_entry_by_DN "${_C_DN}" "${TMPDIR}/GSSAPI_container.ldif" + if [ $? -ne 0 ]; + then + ${RM} ${TMPDIR}/GSSAPI_container.ldif + return + fi + + _H_CN="host_auth_${LDAP_KRB_REALM}" + _H_DN="cn=${_H_CN}, ${_C_DN}" + ( cat << EOF +dn: ${_H_DN} +objectClass: top +objectClass: nsContainer +objectClass: dsIdentityMapping +objectClass: dsPatternMatching +cn: ${_H_CN} +dsMatching-pattern: \${Principal} +dsMatching-regexp: host\/(.*).${LDAP_DOMAIN}@${LDAP_KRB_REALM} +dsSearchBaseDN: ou=hosts,${LDAP_BASEDN} +dsSearchFilter: (&(objectClass=ipHost)(cn=\$1)) +dsSearchScope: one + +EOF +) > ${TMPDIR}/${_H_CN}.ldif + + add_entry_by_DN "${_H_DN}" "${TMPDIR}/${_H_CN}.ldif" + + _U_CN="user_auth_${LDAP_KRB_REALM}" + _U_DN="cn=${_U_CN}, ${_C_DN}" + ( cat << EOF +dn: ${_U_DN} +objectClass: top +objectClass: nsContainer +objectClass: dsIdentityMapping +objectClass: dsPatternMatching +cn: ${_U_CN} +dsMatching-pattern: \${Principal} +dsMatching-regexp: (.*)@${LDAP_KRB_REALM} +dsMappedDN: uid=\$1,ou=People,${LDAP_BASEDN} + +EOF +) > ${TMPDIR}/${_U_CN}.ldif + + add_entry_by_DN "${_U_DN}" "${TMPDIR}/${_U_CN}.ldif" + +} + + +# +# Modify ACL to allow root to read all the password and only self can read +# its own password when sasl/GSSAPI bind is used # +modify_userpassword_acl_for_gssapi() { + + _P_DN="ou=People,${LDAP_BASEDN}" + _H_DN="ou=Hosts,${LDAP_BASEDN}" + _P_ACI="self-read-pwd" + + ${EVAL} "${LDAPSEARCH} ${LDAP_ARGS} -b \"${_P_DN}\" -s base \"objectclass=*\" > /dev/null 2>&1" + if [ $? -ne 0 ]; then + ${ECHO} " ${_P_DN} does not exist" + # Not Found. Create a new entry + ( cat << EOF +dn: ${_P_DN} +ou: People +objectClass: top +objectClass: organizationalUnit +EOF +) > ${TMPDIR}/gssapi_people.ldif + + add_entry_by_DN "${_P_DN}" "${TMPDIR}/gssapi_people.ldif" + else + ${ECHO} " ${_P_DN} already exists" + fi + + ${EVAL} "${LDAPSEARCH} ${LDAP_ARGS} -b \"${_P_DN}\" -s base \"objectclass=*\" aci > ${TMPDIR}/chk_gssapi_aci 2>&1" + + if [ $? -eq 0 ]; then + ${EVAL} "${GREP} ${_P_ACI} ${TMPDIR}/chk_gssapi_aci > /dev/null 2>&1" + if [ $? -eq 0 ]; then + ${ECHO} " userpassword ACL ${_P_ACI} already exists." + return + else + ${ECHO} " userpassword ACL ${_P_ACI} not found. Create a new one." + fi + else + ${ECHO} " Error searching aci for ${_P_DN}" + cat ${TMPDIR}/chk_gssapi_aci + cleanup + exit 1 + fi + ( cat << EOF +dn: ${_P_DN} +changetype: modify +add: aci +aci: (targetattr="userPassword")(version 3.0; acl self-read-pwd; allow (read,search) userdn="ldap:///self" and authmethod="sasl GSSAPI";) +- +add: aci +aci: (targetattr="userPassword")(version 3.0; acl host-read-pwd; allow (read,search) userdn="ldap:///cn=*+ipHostNumber=*,ou=Hosts,${LDAP_BASEDN}" and authmethod="sasl GSSAPI";) +EOF +) > ${TMPDIR}/user_gssapi.ldif + LDAP_TYPE_OR_VALUE_EXISTS=20 + ${EVAL} "${LDAPMODIFY} ${LDAP_ARGS} -f ${TMPDIR}/user_gssapi.ldif ${VERB}" + + case $? in + 0) + ${ECHO} " ${_P_DN} uaserpassword ACL is updated." + ;; + 20) + ${ECHO} " ${_P_DN} uaserpassword ACL already exists." + ;; + *) + ${ECHO} " ERROR: update of userpassword ACL for ${_P_DN} failed!" + cleanup + exit 1 + ;; + esac +} +# +# $1: objectclass or attributetyp +# $2: name +search_update_schema() { + + ATTR="${1}es" + + ${EVAL} "${LDAPSEARCH} ${LDAP_ARGS} -b cn=schema -s base \"objectclass=*\" ${ATTR} | ${GREP} -i \"${2}\" ${VERB}" + if [ $? -ne 0 ]; then + ${ECHO} "${1} ${2} does not exist." + update_schema_attr + update_schema_obj + SCHEMA_UPDATED=1 + else + ${ECHO} "${1} ${2} already exists. Schema has been updated" + fi +} + +# +# $1: 1 - interactive, 0 - no +# +create_gssapi_profile() { + + + if [ ${1} -eq 1 ]; then + echo + echo "You can create a sasl/GSSAPI enabled profile with default values now." + get_confirm "Do you want to create a sasl/GSSAPI default profile ?" "n" + + if [ $? -eq 0 ]; then + return + fi + fi + + # Add profile container if it does not exist + eval "${LDAPSEARCH} ${LDAP_ARGS} -b \"ou=profile,${LDAP_BASEDN}\" -s base \"objectclass=*\" > /dev/null 2>&1" + if [ $? -ne 0 ]; then + ( cat << EOF +dn: ou=profile,${LDAP_BASEDN} +ou: profile +objectClass: top +objectClass: organizationalUnit +EOF +) > ${TMPDIR}/profile_people.ldif + + add_entry_by_DN "ou=profile,${LDAP_BASEDN}" "${TMPDIR}/profile_people.ldif" + + fi + + search_update_schema "objectclass" "DUAConfigProfile" + + _P_NAME="gssapi_${LDAP_KRB_REALM}" + if [ ${1} -eq 1 ]; then + _P_TMP=${LDAP_PROFILE_NAME} + LDAP_PROFILE_NAME=${_P_NAME} + get_profile_name + LDAP_GSSAPI_PROFILE=${LDAP_PROFILE_NAME} + LDAP_PROFILE_NAME=${_P_TMP} + fi + + _P_DN="cn=${LDAP_GSSAPI_PROFILE},ou=profile,${LDAP_BASEDN}" + if [ ${DEL_OLD_PROFILE} -eq 1 ]; then + DEL_OLD_PROFILE=0 + ${EVAL} "${LDAPDELETE} ${LDAP_ARGS} ${_P_DN} ${VERB}" + fi + + _SVR=`getent hosts ${IDS_SERVER} | ${NAWK} '{ print $1 }'` + if [ ${IDS_PORT} -ne 389 ]; then + _SVR="${_SVR}:${IDS_PORT}" + fi + + (cat << EOF +dn: ${_P_DN} +objectClass: top +objectClass: DUAConfigProfile +defaultServerList: ${_SVR} +defaultSearchBase: ${LDAP_BASEDN} +authenticationMethod: sasl/GSSAPI +followReferrals: ${LDAP_FOLLOWREF} +defaultSearchScope: ${LDAP_SEARCH_SCOPE} +searchTimeLimit: ${LDAP_SEARCH_TIME_LIMIT} +profileTTL: ${LDAP_PROFILE_TTL} +cn: ${LDAP_GSSAPI_PROFILE} +credentialLevel: self +bindTimeLimit: ${LDAP_BIND_LIMIT} +EOF +) > ${TMPDIR}/gssapi_profile.ldif + + add_entry_by_DN "${_P_DN}" "${TMPDIR}/gssapi_profile.ldif" + +} +# +# Set up GSSAPI if necessary +# +gssapi_setup() { + + ${EVAL} "${LDAPSEARCH} ${LDAP_ARGS} -b \"\" -s base \"objectclass=*\" supportedSASLMechanisms | ${GREP} GSSAPI ${VERB}" + if [ $? -ne 0 ]; then + ${ECHO} " sasl/GSSAPI is not supported by this LDAP server" + return + fi + + get_confirm "GSSAPI is supported. Do you want to set up gssapi:(y/n)" "n" + if [ $? -eq 0 ]; then + ${ECHO} + ${ECHO} "GSSAPI is not set up." + ${ECHO} "sasl/GSSAPI bind may not workif it's not set up before." + else + get_krb_realm + add_id_mapping_rules + modify_userpassword_acl_for_gssapi + create_gssapi_profile 1 + ${ECHO} + ${ECHO} "GSSAPI setup is done." + fi + + cat << EOF + +You can continue to create a profile and +configure the LDAP server. +Or you can stop now. + +EOF + get_confirm "Do you want to stop:(y/n)" "n" + if [ $? -eq 1 ]; then + cleanup + exit + fi + +} +gssapi_setup_auto() { + ${EVAL} "${LDAPSEARCH} ${LDAP_ARGS} -b \"\" -s base \"objectclass=*\" supportedSASLMechanisms | ${GREP} GSSAPI ${VERB}" + if [ $? -ne 0 ]; then + ${ECHO} + ${ECHO} "sasl/GSSAPI is not supported by this LDAP server" + ${ECHO} + return + fi + if [ -z "${LDAP_KRB_REALM}" ]; then + ${ECHO} + ${ECHO} "LDAP_KRB_REALM is not set. Skip gssapi setup." + ${ECHO} "sasl/GSSAPI bind won't work properly." + ${ECHO} + return + fi + if [ -z "${LDAP_GSSAPI_PROFILE}" ]; then + ${ECHO} + ${ECHO} "LDAP_GSSAPI_PROFILE is not set. Default is gssapi_${LDAP_KRB_REALM}" + ${ECHO} + LDAP_GSSAPI_PROFILE="gssapi_${LDAP_KRB_REALM}" + fi + add_id_mapping_rules + modify_userpassword_acl_for_gssapi + create_gssapi_profile 0 +} # get_profile_name(): Enter the profile name. # get_profile_name() @@ -1470,8 +1799,17 @@ get_cred_level() return 2 ;; 3) LDAP_CRED_LEVEL="proxy anonymous" return 3 ;; + 4) LDAP_CRED_LEVEL="self" + SELF_GSSAPI=1 + return 4 ;; + 5) LDAP_CRED_LEVEL="self proxy" + SELF_GSSAPI=1 + return 5 ;; + 6) LDAP_CRED_LEVEL="self proxy anonymous" + SELF_GSSAPI=1 + return 6 ;; h) display_msg cred_lvl_help ;; - *) ${ECHO} "Please enter 1, 2 or 3." ;; + *) ${ECHO} "Please enter 1, 2, 3, 4, 5 or 6." ;; esac done } @@ -1506,10 +1844,12 @@ srvauth_menu_handler() break ;; 4) _AUTHMETHOD="tls:sasl/DIGEST-MD5" break ;; + 5) _AUTHMETHOD="sasl/GSSAPI" + break ;; 0) _AUTHMETHOD="" _FIRST=1 break ;; - *) ${ECHO} "Please enter 1-4 or 0 to reset." ;; + *) ${ECHO} "Please enter 1-5 or 0 to reset." ;; esac done } @@ -1546,11 +1886,13 @@ auth_menu_handler() break ;; 5) _AUTHMETHOD="tls:sasl/DIGEST-MD5" break ;; + 6) _AUTHMETHOD="sasl/GSSAPI" + break ;; 0) _AUTHMETHOD="" _FIRST=1 break ;; h) display_msg auth_help ;; - *) ${ECHO} "Please enter 1-5, 0=reset, or h=help." ;; + *) ${ECHO} "Please enter 1-6, 0=reset, or h=help." ;; esac done } @@ -2109,6 +2451,8 @@ prompt_config_info() get_basedn + gssapi_setup + get_profile_name get_srv_list get_pref_srv @@ -2153,6 +2497,7 @@ prompt_config_info() NEED_SRVAUTH_CMD=$? [ $NEED_SRVAUTH_CMD -eq 1 ] && get_srv_authMethod_cmd fi + # Get Timeouts get_srch_time @@ -2298,6 +2643,8 @@ LDAP_ROOTDN="$LDAP_ROOTDN" LDAP_ROOTPWD=$LDAP_ROOTPWD LDAP_DOMAIN="$LDAP_DOMAIN" LDAP_SUFFIX="$LDAP_SUFFIX" +LDAP_KRB_REALM="$LDAP_KRB_REALM" +LDAP_GSSAPI_PROFILE="$LDAP_GSSAPI_PROFILE" # Internal program variables that need to be set. NEED_PROXY=$NEED_PROXY @@ -2338,7 +2685,7 @@ export LDAP_AUTHMETHOD LDAP_FOLLOWREF LDAP_SEARCH_SCOPE LDAP_SEARCH_TIME_LIMIT export LDAP_PREF_SRVLIST LDAP_PROFILE_TTL LDAP_CRED_LEVEL LDAP_BIND_LIMIT export NEED_SRVAUTH_PAM NEED_SRVAUTH_KEY NEED_SRVAUTH_CMD export LDAP_SRV_AUTHMETHOD_PAM LDAP_SRV_AUTHMETHOD_KEY LDAP_SRV_AUTHMETHOD_CMD -export LDAP_SERV_SRCH_DES SSD_FILE +export LDAP_SERV_SRCH_DES SSD_FILE LDAP_KRB_REALM LDAP_GSSAPI_PROFILE # Service Search Descriptors start here if present: EOF @@ -3103,6 +3450,9 @@ add_eq_indexes() # Set eq indexes to add. _INDEXES="uidNumber ipNetworkNumber gidnumber oncrpcnumber automountKey" + if [ -z "${IDS_DATABASE}" ]; then + get_backend + fi # Set _EXT to use as shortcut. _EXT="cn=index,cn=${IDS_DATABASE},cn=ldbm database,cn=plugins,cn=config" @@ -4312,6 +4662,7 @@ then INTERACTIVE=0 # Turns off prompts that occur later. validate_info # Validate basic info in file. chk_ids_version # Check iDS version for compatibility. + gssapi_setup_auto else # Display BACKUP warning to user. display_msg backup_server @@ -4341,8 +4692,10 @@ if [ "$NEED_CRYPT" = "TRUE" ]; then fi # Update the schema (Attributes, Objectclass Definitions) -update_schema_attr -update_schema_obj +if [ ${SCHEMA_UPDATED} -eq 0 ]; then + update_schema_attr + update_schema_obj +fi # Add suffix together with its root entry (if needed) add_suffix || diff --git a/usr/src/cmd/ldap/ns_ldap/ldapaddent.c b/usr/src/cmd/ldap/ns_ldap/ldapaddent.c index e05d591da1..641092fea7 100644 --- a/usr/src/cmd/ldap/ns_ldap/ldapaddent.c +++ b/usr/src/cmd/ldap/ns_ldap/ldapaddent.c @@ -80,9 +80,6 @@ extern int optind; extern char *optarg; extern char *__nis_quote_key(const char *, char *, int); -/* from ns_internal.h */ -extern int __s_api_prepend_automountmapname_to_dn( - const char *, char **, ns_ldap_error_t **); static char *inputbasedn = NULL; static char *databasetype = NULL; @@ -439,7 +436,13 @@ addentry(void *entry, int mod) if (eres->status == LDAP_ALREADY_EXISTS || eres->status == LDAP_NO_SUCH_OBJECT) rc = eres->status; - else { + else if (eres->status == LDAP_INSUFFICIENT_ACCESS) { + (void) fprintf(stderr, + gettext("The user does not have permission" + " to add/modify entries\n")); + perr(eres); + exit(1); + } else { rc = 1; perr(eres); } @@ -2110,20 +2113,24 @@ dump_aliases(ns_ldap_result_t *res) * /etc/publickey */ +static char *h_errno2str(int h_errno); + static int genent_publickey(char *line, int (*cback)()) { char buf[BUFSIZ+1], tmpbuf[BUFSIZ+1], cname[BUFSIZ+1]; char *t, *p, *tmppubkey, *tmpprivkey; entry_col ecol[3]; - int buflen, uid, retval = 1; + int buflen, uid, retval = 1, errnum = 0; struct passwd *pwd; - char auth_type[BUFSIZ+1]; + char auth_type[BUFSIZ+1], *dot; keylen_t keylen; algtype_t algtype; struct _ns_pubkey data; struct hostent *hp; struct in_addr in; + struct in6_addr in6; + char abuf[INET6_ADDRSTRLEN]; /* * don't clobber our argument @@ -2179,17 +2186,48 @@ genent_publickey(char *line, int (*cback)()) (void) strcpy(cname, pwd->pw_name); data.hostcred = NS_HOSTCRED_FALSE; } else { - if ((hp = gethostbyname(tmpbuf)) == 0) { + if ((hp = getipnodebyname(tmpbuf, AF_INET6, + AI_ALL | AI_V4MAPPED, &errnum)) == NULL) { (void) fprintf(stderr, - gettext("can't map hostname %s to hostaddress, skipping\n"), - tmpbuf); + gettext("can't map hostname %s to hostaddress, " + "errnum %d %s skipping\n"), tmpbuf, errnum, + h_errno2str(errnum)); return (GENENT_OK); } - (void) memcpy((char *)&in.s_addr, hp->h_addr_list[0], - sizeof (in)); + (void) memcpy((char *)&in6.s6_addr, hp->h_addr_list[0], + hp->h_length); + if (IN6_IS_ADDR_V4MAPPED(&in6) || + IN6_IS_ADDR_V4COMPAT(&in6)) { + IN6_V4MAPPED_TO_INADDR(&in6, &in); + if (inet_ntop(AF_INET, (const void *)&in, abuf, + INET6_ADDRSTRLEN) == NULL) { + (void) fprintf(stderr, + gettext("can't convert IPV4 address of" + " hostname %s to string, " + "skipping\n"), tmpbuf); + return (GENENT_OK); + } + } else { + if (inet_ntop(AF_INET6, (const void *)&in6, abuf, + INET6_ADDRSTRLEN) == NULL) { + (void) fprintf(stderr, + gettext("can't convert IPV6 address of" + " hostname %s to string, " + "skipping\n"), tmpbuf); + return (GENENT_OK); + } + } data.hostcred = NS_HOSTCRED_TRUE; + /* + * tmpbuf could be an alias, use hp->h_name instead. + * hp->h_name is in FQDN format, so extract 1st field. + */ + if ((dot = strchr(hp->h_name, '.')) != NULL) + *dot = '\0'; (void) snprintf(cname, sizeof (cname), - "%s+ipHostNumber=%s", tmpbuf, inet_ntoa(in)); + "%s+ipHostNumber=%s", hp->h_name, abuf); + if (dot) + *dot = '.'; } ecol[0].ec_value.ec_value_val = cname; @@ -2233,7 +2271,16 @@ genent_publickey(char *line, int (*cback)()) /* * auth_type (col 1) */ - if (!(__nis_keyalg2authtype(keylen, algtype, auth_type, + if (AUTH_DES_KEY(keylen, algtype)) + /* + * {DES} and {DH192-0} means same thing. + * However, nisplus uses "DES" and ldap uses "DH192-0" + * internally. + * See newkey(1M), __nis_mechalias2authtype() which is + * called by __nis_keyalg2authtype() and getkey_ldap_g() + */ + (void) strlcpy(auth_type, "DH192-0", BUFSIZ+1); + else if (!(__nis_keyalg2authtype(keylen, algtype, auth_type, MECH_MAXATNAME))) { (void) fprintf(stderr, gettext("Could not convert algorithm type to " @@ -2291,7 +2338,6 @@ genent_publickey(char *line, int (*cback)()) free(data.pubkey); free(data.privkey); return (GENENT_OK); - } static void @@ -3816,7 +3862,7 @@ main(int argc, char **argv) int rc; int ldaprc; int authstried = 0; - int supportedauth = 0; + int supportedauth = 0, gssapi = 0; int op = OP_ADD; char *ttype, *authmech = 0, *etcfile = 0; char ps[LDAP_MAXNAMELEN]; /* Temporary password variable */ @@ -3916,6 +3962,15 @@ main(int argc, char **argv) authority.auth.saslopt = NS_LDAP_SASLOPT_NONE; supportedauth = 1; } + if (strcasecmp(authmech, "sasl/GSSAPI") == 0) { + authority.auth.type = NS_LDAP_AUTH_SASL; + authority.auth.tlstype = NS_LDAP_TLS_SASL; + authority.auth.saslmech = NS_LDAP_SASL_GSSAPI; + authority.auth.saslopt = NS_LDAP_SASLOPT_PRIV | + NS_LDAP_SASLOPT_INT; + gssapi = 1; + supportedauth = 1; + } if (strcasecmp(authmech, "tls:simple") == 0) { authority.auth.type = NS_LDAP_AUTH_TLS; authority.auth.tlstype = NS_LDAP_TLS_SIMPLE; @@ -3944,6 +3999,23 @@ main(int argc, char **argv) } } + if (!gssapi && authority.cred.unix_cred.userID == NULL && + op != OP_DUMP) { + /* This is not an optional parameter. Exit */ + (void) fprintf(stderr, + gettext("Distinguished Name to bind to directory" + " must be specified. use option -D.\n")); + exit(1); + } + + if (!gssapi && authority.cred.unix_cred.passwd == NULL && + op != OP_DUMP) { + /* If password is not specified, then prompt user for it. */ + password = getpassphrase("Enter password:"); + (void) strcpy(ps, password); + authority.cred.unix_cred.passwd = strdup(ps); + } + if (authmech == NULL) { ldaprc = __ns_ldap_getParam(NS_LDAP_AUTH_P, (void ***)&authpp, &errorp); @@ -3977,6 +4049,21 @@ main(int argc, char **argv) "-a option")); exit(1); } + if (authority.auth.saslmech == NS_LDAP_SASL_GSSAPI && + authority.cred.unix_cred.passwd != NULL && + authority.cred.unix_cred.userID != NULL) { + /* + * -a is not specified and the auth method sasl/GSSAPI + * is defined in the configuration of the ldap profile. + * Even -D and -w is provided it's not valid usage. + */ + + (void) fprintf(stderr, + gettext("The default authentication is sasl/GSSAPI.\n" + "The bind DN and and password is not allowed." + "\n")); + exit(1); + } } ttype = argv[optind++]; @@ -4223,3 +4310,23 @@ static int get_basedn(char *service, char **basedn) { return (NS_LDAP_SUCCESS); } } +static char * +h_errno2str(int h_errno) { + switch (h_errno) { + case HOST_NOT_FOUND: + return ("HOST_NOT_FOUND"); + break; + case TRY_AGAIN: + return ("TRY_AGAIN"); + break; + case NO_RECOVERY: + return ("NO_RECOVERY"); + break; + case NO_DATA: + return ("NO_DATA"); + break; + default: + break; + } + return ("UNKNOWN_ERROR"); +} diff --git a/usr/src/cmd/ldap/ns_ldap/ldapclient.c b/usr/src/cmd/ldap/ns_ldap/ldapclient.c index 0f3666de6d..6e507d2c1c 100644 --- a/usr/src/cmd/ldap/ns_ldap/ldapclient.c +++ b/usr/src/cmd/ldap/ns_ldap/ldapclient.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -114,17 +113,10 @@ #include <limits.h> #include <locale.h> #include <syslog.h> -#include "../../../lib/libsldap/common/ns_sldap.h" #include <libscf.h> #include <assert.h> -/* - * We need ns_internal.h for the #defines of: - * NSCREDFILE, NSCONFIGFILE - * and the function prototypes of: - * __ns_ldap_setServer(), __ns_ldap_LoadConfiguration(), - * __ns_ldap_DumpConfiguration(), __ns_ldap_DumpLdif() - */ -#include "../../../lib/libsldap/common/ns_internal.h" +#include "ns_sldap.h" +#include "ns_internal.h" #if !defined(TEXT_DOMAIN) #define TEXT_DOMAIN "SUNW_OST_OSCMD" @@ -294,7 +286,7 @@ static void clientopts_free(clientopts_t *list); extern ns_ldap_error_t *__ns_ldap_print_config(int); extern void __ns_ldap_default_config(); -extern int __ns_ldap_download(char *, char *, char *, ns_ldap_error_t **); +extern int __ns_ldap_download(const char *, char *, char *, ns_ldap_error_t **); /* Function prototypes (these could be static) */ static void usage(void); @@ -562,9 +554,9 @@ main(int argc, char **argv) if ((retcode == CLIENT_SUCCESS) || (retcode == CLIENT_ERR_FAIL) || (retcode == CLIENT_ERR_CREDENTIAL)) - exit(retcode); + return (retcode); else - exit(CLIENT_ERR_FAIL); + return (CLIENT_ERR_FAIL); } static int @@ -597,6 +589,7 @@ static int client_uninit(clientopts_t *arglist) { int retcode = CLIENT_SUCCESS; + ns_ldap_self_gssapi_config_t config = NS_LDAP_SELF_GSSAPI_CONFIG_NONE; if (mode_verbose) { CLIENT_FPUTS( @@ -613,7 +606,13 @@ client_uninit(clientopts_t *arglist) return (CLIENT_ERR_FAIL); } + (void) __ns_ldap_self_gssapi_config(&config); + retcode = stop_services(STATE_SAVE); + + if (config != NS_LDAP_SELF_GSSAPI_CONFIG_NONE) + (void) system("/usr/sbin/cryptoadm enable metaslot"); + if (retcode != CLIENT_SUCCESS) { CLIENT_FPUTS( gettext("Errors stopping network services.\n"), stderr); @@ -1451,7 +1450,7 @@ client_init(clientopts_t *arglist) /* Get and set profile params */ retcode = __ns_ldap_download( - arglist->profileName, + (const char *)arglist->profileName, arglist->defaultServerList, nisBaseDN, &errorp); @@ -1852,11 +1851,13 @@ stop_services(int saveState) static int start_services(int flag) { - int sysret, retcode = CLIENT_SUCCESS; + int sysret, retcode = CLIENT_SUCCESS, rc = NS_LDAP_SUCCESS; FILE *domain_fp; char domainname[BUFSIZ]; char cmd_domain_start[BUFSIZ]; int domainlen; + ns_ldap_self_gssapi_config_t config = NS_LDAP_SELF_GSSAPI_CONFIG_NONE; + ns_ldap_error_t *errorp = NULL; if (mode_verbose) { CLIENT_FPUTS(gettext("Starting network services\n"), stderr); @@ -1894,8 +1895,8 @@ start_services(int flag) if (domainname[domainlen-1] == '\n') domainname[domainlen-1] = 0; /* buffer size is checked above */ - (void) sprintf(cmd_domain_start, "%s %s %s", CMD_DOMAIN_START, - domainname, TO_DEV_NULL); + (void) snprintf(cmd_domain_start, BUFSIZ, "%s %s %s", + CMD_DOMAIN_START, domainname, TO_DEV_NULL); } /* @@ -1916,9 +1917,42 @@ start_services(int flag) retcode = CLIENT_ERR_FAIL; } - if (start_service(LDAP_FMRI, B_TRUE) != CLIENT_SUCCESS) + if ((rc = __ns_ldap_self_gssapi_config(&config)) != + NS_LDAP_SUCCESS) { + CLIENT_FPRINTF(stderr, gettext("Error (%d) while " + "checking sasl/GSSAPI configuration\n"), + rc); retcode = CLIENT_ERR_FAIL; + } + + if (config != NS_LDAP_SELF_GSSAPI_CONFIG_NONE) { + rc = __ns_ldap_check_dns_preq( + 1, mode_verbose, mode_quiet, + NSSWITCH_LDAP, config, &errorp); + if (errorp) + (void) __ns_ldap_freeError(&errorp); + + if (rc != NS_LDAP_SUCCESS) + retcode = CLIENT_ERR_FAIL; + } + + if (rc == NS_LDAP_SUCCESS && + start_service(LDAP_FMRI, B_TRUE) != CLIENT_SUCCESS) + retcode = CLIENT_ERR_FAIL; + + if (config != NS_LDAP_SELF_GSSAPI_CONFIG_NONE && + rc == NS_LDAP_SUCCESS && retcode == CLIENT_SUCCESS) { + rc = __ns_ldap_check_gssapi_preq( + 1, mode_verbose, mode_quiet, config, + &errorp); + if (errorp) + (void) __ns_ldap_freeError(&errorp); + + if (rc != NS_LDAP_SUCCESS) + retcode = CLIENT_ERR_FAIL; + + } /* No YP or NIS+ after init */ /* * Or we can be starting services after an uninit or error @@ -1973,6 +2007,17 @@ start_services(int flag) !(is_service(NSCD_FMRI, SCF_STATE_STRING_ONLINE))) (void) start_service(NSCD_FMRI, B_TRUE); +#if 0 + if (flag == START_INIT && config != NS_LDAP_SELF_GSSAPI_CONFIG_NONE && + retcode == CLIENT_SUCCESS && + !(is_service(NSCD_FMRI, SCF_STATE_STRING_ONLINE))) { + CLIENT_FPRINTF(stderr, "start: %s\n", + gettext("self/sasl/GSSAPI is configured" + " but nscd is not online")); + retcode = CLIENT_ERR_FAIL; + } +#endif + if ((enableFlag & SENDMAIL_ON) && !(is_service(SENDMAIL_FMRI, SCF_STATE_STRING_ONLINE))) (void) start_service(SENDMAIL_FMRI, B_TRUE); diff --git a/usr/src/cmd/ldap/ns_ldap/mapping.c b/usr/src/cmd/ldap/ns_ldap/mapping.c index 470ca20628..e5b7d26575 100644 --- a/usr/src/cmd/ldap/ns_ldap/mapping.c +++ b/usr/src/cmd/ldap/ns_ldap/mapping.c @@ -74,6 +74,15 @@ static struct mapping maplist[] = { {NULL, NULL, NULL, NULL} }; +#define PROF_ATTR_FILTER \ + "(&(objectclass=SolarisProfAttr)(!(SolarisKernelSecurityPolicy=*))%s)" +#define TNRHTP_FILTER \ + "(&(objectclass=ipTnetTemplate)(!(objectclass=ipTnetHost))%s)" +#define OC_FILTER "objectclass=%s" +#define OC_FLEN 15 +#define OC_FILTER2 "(&(objectclass=%s)%s)" +#define OC_FLEN2 22 + /* Malloc and print error message in case of failure */ #define MALLOC(ptr, len) \ if ((ptr = (char *)malloc(len)) == NULL) { \ @@ -378,6 +387,7 @@ set_filter(char **key, char *database, char **udata) char *keyfilter; int i, filterlen, udatalen; int rc, v2 = 1; + int dbpf, dbtp; void **paramVal = NULL; ns_ldap_error_t *errorp = NULL; short nomem; @@ -415,32 +425,69 @@ set_filter(char **key, char *database, char **udata) */ for (i = 2; maplist[i].database != NULL; i++) { if (strcasecmp(database, maplist[i].database) == SAME) { + dbpf = 0, dbtp = 0; + if (strcasecmp(database, "prof_attr") == 0) + dbpf = 1; + else if (strcasecmp(database, "tnrhtp") == 0) + dbtp = 1; if ((keyfilter = set_keys(key, maplist[i].def_type)) == NULL) { - filterlen = strlen(maplist[i].objectclass) + 13; + filterlen = strlen(maplist[i].objectclass); udatalen = 3; + if (dbpf) + filterlen += strlen(PROF_ATTR_FILTER) + + 1; + else if (dbtp) + filterlen += strlen(TNRHTP_FILTER) + 1; + else + filterlen += OC_FLEN; + MALLOC_FILTER_UDATA(filter, filterlen, userdata, udatalen, nomem); - if (!nomem) { + if (nomem) + goto done; + if (dbpf) + (void) snprintf(filter, filterlen, + PROF_ATTR_FILTER, ""); + else if (dbtp) + (void) snprintf(filter, filterlen, + TNRHTP_FILTER, ""); + else (void) snprintf(filter, filterlen, - "objectclass=%s", + OC_FILTER, maplist[i].objectclass); - (void) snprintf(userdata, udatalen, - "%%s"); - } + + (void) snprintf(userdata, udatalen, "%%s"); } else { filterlen = strlen(maplist[i].objectclass) + - strlen(keyfilter) + 18; + strlen(keyfilter); + if (dbpf) + filterlen += strlen(PROF_ATTR_FILTER) + + 1; + else if (dbtp) + filterlen += strlen(TNRHTP_FILTER) + 1; + else + filterlen += OC_FLEN2; + udatalen = strlen(keyfilter) + 8; MALLOC_FILTER_UDATA(filter, filterlen, userdata, udatalen, nomem); - if (!nomem) { + if (nomem) + goto done; + if (dbpf) (void) snprintf(filter, filterlen, - "(&(objectclass=%s)%s)", - maplist[i].objectclass, keyfilter); - (void) snprintf(userdata, udatalen, - "(&(%%s)%s)", keyfilter); - } + PROF_ATTR_FILTER, keyfilter); + else if (dbtp) + (void) snprintf(filter, filterlen, + TNRHTP_FILTER, keyfilter); + else + (void) snprintf(filter, filterlen, + OC_FILTER2, + maplist[i].objectclass, + keyfilter); + + (void) snprintf(userdata, udatalen, + "(&(%%s)%s)", keyfilter); } goto done; } diff --git a/usr/src/cmd/ldapcachemgr/Makefile b/usr/src/cmd/ldapcachemgr/Makefile index fa38464f75..6b4e86f223 100644 --- a/usr/src/cmd/ldapcachemgr/Makefile +++ b/usr/src/cmd/ldapcachemgr/Makefile @@ -2,9 +2,8 @@ # CDDL HEADER START # # The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@ # CDDL HEADER END # # -# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # ident "%Z%%M% %I% %E% SMI" @@ -62,7 +61,7 @@ LINTOUT= lint.out # GPROF_FLAG= -xpg # DEBUG_FLAG= -g -LDLIBS += -lsldap -lldap +LDLIBS += -lsldap -lldap -lnsl # install macros and rule # diff --git a/usr/src/cmd/ldapcachemgr/cachemgr.c b/usr/src/cmd/ldapcachemgr/cachemgr.c index d97b8d08c1..2fd9f5bbc0 100644 --- a/usr/src/cmd/ldapcachemgr/cachemgr.c +++ b/usr/src/cmd/ldapcachemgr/cachemgr.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -214,7 +213,7 @@ server_tsd_bind(void *arg) */ (void) thr_setspecific(server_key, value); - door_return(NULL, 0, NULL, 0); + (void) door_return(NULL, 0, NULL, 0); return (value); } @@ -470,7 +469,7 @@ main(int argc, char ** argv) * Establish our own server thread pool */ - door_server_create(server_create); + (void) door_server_create(server_create); if (thr_keycreate(&server_key, server_destroy) != 0) { logit("thr_keycreate() call failed\n"); syslog(LOG_ERR, @@ -595,6 +594,8 @@ main(int argc, char ** argv) while (1) { (void) pause(); } + /* NOTREACHED */ + /*LINTED E_FUNC_HAS_NO_RETURN_STMT*/ } @@ -679,7 +680,7 @@ switcher(void *cookie, char *argp, size_t arg_size, u.data.ldap_ret.ldap_bufferbytesused = sizeof (ldap_return_t); break; } - door_return((char *)&u.data, + (void) door_return((char *)&u.data, u.data.ldap_ret.ldap_bufferbytesused, NULL, 0); } diff --git a/usr/src/cmd/ldapcachemgr/cachemgr_getldap.c b/usr/src/cmd/ldapcachemgr/cachemgr_getldap.c index 2a83c2d215..3541102ab6 100644 --- a/usr/src/cmd/ldapcachemgr/cachemgr_getldap.c +++ b/usr/src/cmd/ldapcachemgr/cachemgr_getldap.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -46,6 +45,9 @@ #include <lber.h> #include <ldap.h> #include <ctype.h> /* tolower */ +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> #include "cachemgr.h" #include "solaris-priv.h" @@ -130,6 +132,7 @@ typedef enum { typedef struct server_info_ext { char *addr; + char *hostname; char *rootDSE_data; char *errormsg; info_rw_t type; @@ -449,6 +452,10 @@ sync_current_with_update_copy(server_info_t *info) free(info->sinfo[0].addr); info->sinfo[0].addr = NULL; + if (info->sinfo[0].hostname) + free(info->sinfo[0].hostname); + info->sinfo[0].hostname = NULL; + if (info->sinfo[0].rootDSE_data) free(info->sinfo[0].rootDSE_data); info->sinfo[0].rootDSE_data = NULL; @@ -475,6 +482,8 @@ sync_current_with_update_copy(server_info_t *info) */ if (info->sinfo[1].addr) info->sinfo[0].addr = strdup(info->sinfo[1].addr); + if (info->sinfo[1].hostname) + info->sinfo[0].hostname = strdup(info->sinfo[1].hostname); if (info->sinfo[1].rootDSE_data) info->sinfo[0].rootDSE_data = strdup(info->sinfo[1].rootDSE_data); @@ -563,7 +572,6 @@ getldap_get_rootDSE(void *arg) sync_current_with_update_copy(serverInfo); thr_exit((void *) -1); } - ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, &ldapVersion); ldap_set_option(ld, @@ -810,6 +818,8 @@ getldap_init_serverInfo(server_info_t **head) INFO_SERVER_UP; info->sinfo[1].prev_server_status = INFO_SERVER_UP; + info->sinfo[0].hostname = NULL; + info->sinfo[1].hostname = NULL; info->sinfo[0].rootDSE_data = NULL; info->sinfo[1].rootDSE_data = NULL; info->sinfo[0].errormsg = NULL; @@ -846,6 +856,10 @@ getldap_destroy_serverInfo(server_info_t *head) free(info->sinfo[0].addr); if (info->sinfo[1].addr) free(info->sinfo[1].addr); + if (info->sinfo[0].hostname) + free(info->sinfo[0].hostname); + if (info->sinfo[1].hostname) + free(info->sinfo[1].hostname); if (info->sinfo[0].rootDSE_data) free(info->sinfo[0].rootDSE_data); if (info->sinfo[1].rootDSE_data) @@ -954,11 +968,123 @@ getldap_set_serverInfo(server_info_t *head, } /* + * Convert an IP to a host name + */ +static int +getldap_ip2hostname(char *ipaddr, char **hostname) { + struct in_addr in; + struct in6_addr in6; + struct hostent *hp = NULL; + char *start = NULL, *end = NULL, delim = '\0'; + char *port = NULL, *addr = NULL; + int error_num = 0, len = 0; + + if (ipaddr == NULL || hostname == NULL) + return (NS_LDAP_INVALID_PARAM); + *hostname = NULL; + if ((addr = strdup(ipaddr)) == NULL) + return (NS_LDAP_MEMORY); + + if (addr[0] == '[') { + /* + * Assume it's [ipv6]:port + * Extract ipv6 IP + */ + start = &addr[1]; + if ((end = strchr(addr, ']')) != NULL) { + *end = '\0'; + delim = ']'; + if (*(end + 1) == ':') + /* extract port */ + port = end + 2; + } else { + return (NS_LDAP_INVALID_PARAM); + } + } else if ((end = strchr(addr, ':')) != NULL) { + /* assume it's ipv4:port */ + *end = '\0'; + delim = ':'; + start = addr; + port = end + 1; + } else + /* No port */ + start = addr; + + + if (inet_pton(AF_INET, start, &in) == 1) { + /* IPv4 */ + hp = getipnodebyaddr((char *)&in, + sizeof (struct in_addr), AF_INET, &error_num); + if (hp && hp->h_name) { + /* hostname + '\0' */ + len = strlen(hp->h_name) + 1; + if (port) + /* ':' + port */ + len += strlen(port) + 1; + if ((*hostname = malloc(len)) == NULL) { + free(addr); + freehostent(hp); + return (NS_LDAP_MEMORY); + } + + if (port) + (void) snprintf(*hostname, len, "%s:%s", + hp->h_name, port); + else + (void) strlcpy(*hostname, hp->h_name, len); + + free(addr); + freehostent(hp); + return (NS_LDAP_SUCCESS); + } else { + return (NS_LDAP_NOTFOUND); + } + } else if (inet_pton(AF_INET6, start, &in6) == 1) { + /* IPv6 */ + hp = getipnodebyaddr((char *)&in6, + sizeof (struct in6_addr), AF_INET6, &error_num); + if (hp && hp->h_name) { + /* hostname + '\0' */ + len = strlen(hp->h_name) + 1; + if (port) + /* ':' + port */ + len += strlen(port) + 1; + if ((*hostname = malloc(len)) == NULL) { + free(addr); + freehostent(hp); + return (NS_LDAP_MEMORY); + } + + if (port) + (void) snprintf(*hostname, len, "%s:%s", + hp->h_name, port); + else + (void) strlcpy(*hostname, hp->h_name, len); + + free(addr); + freehostent(hp); + return (NS_LDAP_SUCCESS); + } else { + return (NS_LDAP_NOTFOUND); + } + } else { + /* + * A hostname + * Return it as is + */ + if (end) + *end = delim; + *hostname = addr; + return (NS_LDAP_SUCCESS); + } +} +/* * getldap_get_serverInfo processes the GETLDAPSERVER door request passed * to this function from getldap_serverInfo_op(). * input: * a buffer containing an empty string (e.g., input[0]='\0';) or a string - * as the "input" in printf(input, "%s%s%s", req, DOORLINESEP, addr); + * as the "input" in printf(input, "%s%s%s%s", req, addrtype, DOORLINESEP, + * addr); * where addr is the address of a server and * req is one of the following: * NS_CACHE_NEW: send a new server address, addr is ignored. @@ -966,6 +1092,10 @@ getldap_set_serverInfo(server_info_t *head, * NS_CACHE_NEXT: send the next one, keep addr on list. * NS_CACHE_WRITE: send a non-replica server, if possible, if not, same * as NS_CACHE_NEXT. + * addrtype: + * NS_CACHE_ADDR_IP: return server address as is, this is default. + * NS_CACHE_ADDR_HOSTNAME: return server addess as FQDN format, only + * self credential case requires such format. * output: * a buffer containing server info in the following format: * serveraddress DOORLINESEP [ attr=value [DOORLINESEP attr=value ]...] @@ -982,7 +1112,9 @@ getldap_get_serverInfo(server_info_t *head, char *input, char *addr = NULL; char *req = NULL; char req_new[] = NS_CACHE_NEW; - int matched = FALSE, len; + char addr_type[] = NS_CACHE_ADDR_IP; + int matched = FALSE, len, rc = 0; + char *ret_addr = NULL; if (current_admin.debug_level >= DBG_ALL) { logit("getldap_get_serverInfo()...\n"); @@ -1010,8 +1142,12 @@ getldap_get_serverInfo(server_info_t *head, char *input, req = req_new; if (input[0] != '\0') { req = input; + /* Save addr type flag */ + addr_type[0] = input[1]; input[strlen(NS_CACHE_NEW)] = '\0'; - addr = input + strlen(DOORLINESEP) + strlen(NS_CACHE_NEW); + /* skip acion type flag, addr type flag and DOORLINESEP */ + addr = input + strlen(DOORLINESEP) + strlen(NS_CACHE_NEW) + + strlen(NS_CACHE_ADDR_IP); } /* * if NS_CACHE_NEW, @@ -1122,7 +1258,34 @@ getldap_get_serverInfo(server_info_t *head, char *input, } if (server) { - len = strlen(server->sinfo[0].addr) + + if (strcmp(addr_type, NS_CACHE_ADDR_HOSTNAME) == 0) { + /* + * In SASL/GSSAPI case, a hostname is required for + * Kerberos's service principal. + * e.g. + * ldap/foo.sun.com@SUN.COM + */ + if (server->sinfo[0].hostname == NULL) { + rc = getldap_ip2hostname(server->sinfo[0].addr, + &server->sinfo[0].hostname); + if (rc != NS_LDAP_SUCCESS) { + (void) mutex_unlock(&info->mutex[0]); + return (rc); + } + if (current_admin.debug_level >= DBG_ALL) { + logit("getldap_get_serverInfo: " + "%s is converted to %s\n", + server->sinfo[0].addr, + server->sinfo[0].hostname); + } + } + ret_addr = server->sinfo[0].hostname; + + } else + ret_addr = server->sinfo[0].addr; + + + len = strlen(ret_addr) + strlen(server->sinfo[0].rootDSE_data) + strlen(DOORLINESEP) + 1; *output = (char *)malloc(len); @@ -1131,7 +1294,7 @@ getldap_get_serverInfo(server_info_t *head, char *input, return (NS_LDAP_MEMORY); } (void) snprintf(*output, len, "%s%s%s", - server->sinfo[0].addr, DOORLINESEP, + ret_addr, DOORLINESEP, server->sinfo[0].rootDSE_data); server->sinfo[0].info_status = INFO_STATUS_OLD; (void) mutex_unlock(&info->mutex[0]); @@ -1927,7 +2090,6 @@ getldap_serverInfo_op(info_op_t op, char *input, char **output) } else (void) getldap_get_serverInfo(serverInfo_old, input, output, &server_removed); - (void) rw_unlock(&info_lock_old); /* @@ -2354,9 +2516,9 @@ update_from_profile() logit("update_from_profile: reset profile TTL to %d" " seconds\n", current_admin.ldap_stat.ldap_ttl); - logit("update_from_profile: expire time %d " + logit("update_from_profile: expire time %ld " "seconds\n", - *ptr->paramList[NS_LDAP_EXP_P].ns_pi); + ptr->paramList[NS_LDAP_EXP_P].ns_tm); } /* set ptr as current_config */ @@ -2370,6 +2532,7 @@ update_from_profile() rc = -1; } (void) rw_unlock(&ldap_lock); + return (rc); } @@ -2416,7 +2579,8 @@ perform_update(void) ns_ldap_error_t *error; struct timeval tp; char buf[20]; - int rc; + int rc, rc1; + ns_ldap_self_gssapi_config_t config; if (current_admin.debug_level >= DBG_ALL) { logit("perform_update()...\n"); @@ -2450,7 +2614,7 @@ perform_update(void) &error) != NS_LDAP_SUCCESS) { logit("Error: __ns_ldap_setParam failed, status: %d " "message: %s\n", error->status, error->message); - __ns_ldap_freeError(&error); + (void) __ns_ldap_freeError(&error); return; } @@ -2478,6 +2642,23 @@ perform_update(void) /* statistics: previous refresh time */ prev_refresh_time = tp.tv_sec; } + rc1 = __ns_ldap_self_gssapi_config(&config); + if (rc1 == NS_LDAP_SUCCESS) { + if (config != NS_LDAP_SELF_GSSAPI_CONFIG_NONE) { + rc1 = __ns_ldap_check_all_preq(0, 0, 0, config, &error); + (void) __ns_ldap_freeError(&error); + if (rc1 != NS_LDAP_SUCCESS) { + logit("Error: Check on self credential " + "prerquesites failed: %d\n", + rc1); + exit(rc1); + } + } + } else { + logit("Error: Failed to get self credential configuration %d\n", + rc1); + exit(rc1); + } (void) rw_rdlock(&ldap_lock); if ((error = __ns_ldap_DumpConfiguration(NSCONFIGREFRESH)) != NULL) { @@ -2498,6 +2679,7 @@ perform_update(void) logit("Error: unlink failed - errno: %d\n", errno); if (rename(NSCREDREFRESH, NSCREDFILE) != 0) logit("Error: unlink failed - errno: %d\n", errno); + (void) rw_unlock(&ldap_lock); } diff --git a/usr/src/cmd/nscd/Makefile b/usr/src/cmd/nscd/Makefile index 4932374ed6..c3f749bc77 100644 --- a/usr/src/cmd/nscd/Makefile +++ b/usr/src/cmd/nscd/Makefile @@ -2,9 +2,8 @@ # CDDL HEADER START # # The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. @@ -20,11 +19,13 @@ # CDDL HEADER END # # -# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # ident "%Z%%M% %I% %E% SMI" # +# Makefile for name service cache daemon +# PROG= nscd NISPROG= nscd_nischeck @@ -39,9 +40,21 @@ $(ROOTMANIFEST) := FILEMODE= 444 $(ROOTMANIFESTDIR)/%: % $(INS.file) -OBJS= server.o getpw.o getgr.o gethost.o getnode.o hash.o \ - nscd_biggest.o nscd_parse.o nscd_wait.o \ - getexec.o getprof.o getuser.o attrstr.o +OBJS= server.o getpw.o getgr.o gethost.o getnode.o \ + getether.o getrpc.o getproto.o getnet.o \ + getbootp.o getauuser.o getauth.o getserv.o \ + getnetmasks.o getprinter.o getproject.o \ + getexec.o getprof.o getuser.o cache.o \ + nscd_biggest.o nscd_wait.o \ + nscd_init.o nscd_access.o nscd_cfgfile.o nscd_config.o \ + nscd_dbimpl.o nscd_getentctx.o nscd_intaddr.o \ + nscd_log.o nscd_nswconfig.o nscd_nswstate.o nscd_nswcfgst.o \ + nscd_seqnum.o nscd_smfmonitor.o \ + nscd_switch.o nscd_nswparse.o nscd_initf.o nscd_selfcred.o \ + nscd_frontend.o nscd_admin.o nscd_door.o \ + gettnrhtp.o gettnrhdb.o + + NISOBJS= nscd_nischeck.o @@ -51,13 +64,18 @@ SRCS= ${OBJS:%.o=%.c} NISSRC= ${NISOBJS:%.o=%.c} -CPPFLAGS += -D_REENTRANT -DSUN_THREADS +CPPFLAGS += -D_REENTRANT -DSUN_THREADS \ + -I../../lib/libc/port/gen -I../../lib/libc/inc \ + -I../../lib/libsldap/common +LINTFLAGS += -erroff=E_GLOBAL_COULD_BE_STATIC2 +LINTFLAGS += -erroff=E_NAME_USED_NOT_DEF2 +LINTFLAGS += -erroff=E_NAME_DEF_NOT_USED2 # TCOV_FLAG= -ql # GPROF_FLAG= -xpg # DEBUG_FLAG= -g -$(PROG) := LDLIBS += -lresolv -lnsl -lsocket -lumem -lscf +$(PROG) := LDLIBS += -lresolv -lnsl -lsocket -lumem -lscf -lavl -lgss $(NISPROG) := LDLIBS += -lnsl # install macros and rule @@ -78,8 +96,6 @@ ${NISPROG}: ${NISOBJS} ${LINK.c} ${OPT} -o $@ ${NISOBJS} ${LDLIBS} ${POST_PROCESS} -lint := LINTFLAGS=-x -b -u - lint: $(LINT.c) ${SRCS} diff --git a/usr/src/cmd/nscd/cache.c b/usr/src/cmd/nscd/cache.c new file mode 100644 index 0000000000..a8f6f43515 --- /dev/null +++ b/usr/src/cmd/nscd/cache.c @@ -0,0 +1,2378 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * Cache routines for nscd + */ +#include <assert.h> +#include <errno.h> +#include <memory.h> +#include <signal.h> +#include <stdlib.h> +#include <stddef.h> +#include <stdio.h> +#include <string.h> +#include <sys/stat.h> +#include <sys/time.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <unistd.h> +#include <ucred.h> +#include <nss_common.h> +#include <locale.h> +#include <ctype.h> +#include <strings.h> +#include <string.h> +#include <umem.h> +#include <fcntl.h> +#include "cache.h" +#include "nscd_door.h" +#include "nscd_log.h" +#include "nscd_config.h" +#include "nscd_frontend.h" +#include "nscd_switch.h" + +#define SUCCESS 0 +#define NOTFOUND -1 +#define SERVERERROR -2 +#define NOSERVER -3 +#define CONTINUE -4 + +static nsc_db_t *nsc_get_db(nsc_ctx_t *, int); +static nscd_rc_t lookup_cache(nsc_lookup_args_t *, nscd_cfg_cache_t *, + nss_XbyY_args_t *, char *, nsc_entry_t **); +static uint_t reap_cache(nsc_ctx_t *, uint_t, uint_t); +static void delete_entry(nsc_db_t *, nsc_ctx_t *, nsc_entry_t *); +static void print_stats(nscd_cfg_stat_cache_t *); +static void print_cfg(nscd_cfg_cache_t *); +static int lookup_int(nsc_lookup_args_t *, int); + +#ifdef NSCD_DEBUG +static void print_entry(nsc_db_t *, time_t, nsc_entry_t *); +static void avl_dump(nsc_db_t *, time_t); +static void hash_dump(nsc_db_t *, time_t); +#endif /* NSCD_DEBUG */ +static nsc_entry_t *hash_find(nsc_db_t *, nsc_entry_t *, uint_t *, nscd_bool_t); + +static void queue_adjust(nsc_db_t *, nsc_entry_t *); +static void queue_remove(nsc_db_t *, nsc_entry_t *); +#ifdef NSCD_DEBUG +static void queue_dump(nsc_db_t *, time_t); +#endif /* NSCD_DEBUG */ + +static int launch_update(nsc_lookup_args_t *); +static void do_update(nsc_lookup_args_t *); +static void getxy_keepalive(nsc_ctx_t *, nsc_db_t *, int, int); + +static void ctx_info(nsc_ctx_t *); +static void ctx_info_nolock(nsc_ctx_t *); +static void ctx_invalidate(nsc_ctx_t *); + +static void nsc_db_str_key_getlogstr(char *, char *, size_t, nss_XbyY_args_t *); +static void nsc_db_int_key_getlogstr(char *, char *, size_t, nss_XbyY_args_t *); +static void nsc_db_any_key_getlogstr(char *, char *, size_t, nss_XbyY_args_t *); + +static int nsc_db_cis_key_compar(const void *, const void *); +static int nsc_db_ces_key_compar(const void *, const void *); +static int nsc_db_int_key_compar(const void *, const void *); + +static uint_t nsc_db_cis_key_gethash(nss_XbyY_key_t *, int); +static uint_t nsc_db_ces_key_gethash(nss_XbyY_key_t *, int); +static uint_t nsc_db_int_key_gethash(nss_XbyY_key_t *, int); + +static umem_cache_t *nsc_entry_cache; + +static nsc_ctx_t *init_cache_ctx(int); +static void reaper(nsc_ctx_t *); +static void revalidate(nsc_ctx_t *); + +static nss_status_t +dup_packed_buffer(void *src, void *dst) { + nsc_lookup_args_t *s = (nsc_lookup_args_t *)src; + nsc_entry_t *d = (nsc_entry_t *)dst; + nss_pheader_t *sphdr = (nss_pheader_t *)s->buffer; + nss_pheader_t *dphdr = (nss_pheader_t *)d->buffer; + int slen, new_pbufsiz = 0; + + if (NSCD_GET_STATUS(sphdr) != NSS_SUCCESS) { + + /* no result, copy header only (status, errno, etc) */ + slen = sphdr->data_off; + } else { + /* + * lookup result returned, data to copy is the packed + * header plus result (add 1 for the terminating NULL + * just in case) + */ + slen = sphdr->data_off + sphdr->data_len + 1; + } + + /* allocate cache packed buffer */ + if (dphdr != NULL && d->bufsize <= slen && d->bufsize != 0) { + /* old buffer too small, free it */ + free(dphdr); + d->buffer = NULL; + d->bufsize = 0; + dphdr = NULL; + } + if (dphdr == NULL) { + /* get new buffer */ + dphdr = calloc(1, slen + 1); + if (dphdr == NULL) + return (NSS_ERROR); + d->buffer = dphdr; + d->bufsize = slen + 1; + new_pbufsiz = slen + 1; + } + + (void) memcpy(dphdr, sphdr, slen); + if (new_pbufsiz != 0) + dphdr->pbufsiz = new_pbufsiz; + + return (NSS_SUCCESS); +} + +char *cache_name[CACHE_CTX_COUNT] = { + NSS_DBNAM_PASSWD, + NSS_DBNAM_GROUP, + NSS_DBNAM_HOSTS, + NSS_DBNAM_IPNODES, + NSS_DBNAM_EXECATTR, + NSS_DBNAM_PROFATTR, + NSS_DBNAM_USERATTR, + NSS_DBNAM_ETHERS, + NSS_DBNAM_RPC, + NSS_DBNAM_PROTOCOLS, + NSS_DBNAM_NETWORKS, + NSS_DBNAM_BOOTPARAMS, + NSS_DBNAM_AUDITUSER, + NSS_DBNAM_AUTHATTR, + NSS_DBNAM_SERVICES, + NSS_DBNAM_NETMASKS, + NSS_DBNAM_PRINTERS, + NSS_DBNAM_PROJECT, + NSS_DBNAM_TSOL_TP, + NSS_DBNAM_TSOL_RH +}; + +typedef void (*cache_init_ctx_t)(nsc_ctx_t *); +static cache_init_ctx_t cache_init_ctx[CACHE_CTX_COUNT] = { + passwd_init_ctx, + group_init_ctx, + host_init_ctx, + ipnode_init_ctx, + exec_init_ctx, + prof_init_ctx, + user_init_ctx, + ether_init_ctx, + rpc_init_ctx, + proto_init_ctx, + net_init_ctx, + bootp_init_ctx, + auuser_init_ctx, + auth_init_ctx, + serv_init_ctx, + netmask_init_ctx, + printer_init_ctx, + project_init_ctx, + tnrhtp_init_ctx, + tnrhdb_init_ctx +}; + +nsc_ctx_t *cache_ctx_p[CACHE_CTX_COUNT] = { 0 }; +static nscd_cfg_stat_cache_t null_stats = { 0 }; +static nscd_cfg_global_cache_t global_cfg; + +/* + * Given database name 'dbname' find cache index + */ +int +get_cache_idx(char *dbname) { + int i; + char *nsc_name; + + for (i = 0; i < CACHE_CTX_COUNT; i++) { + nsc_name = cache_name[i]; + if (strcmp(nsc_name, dbname) == 0) + return (i); + } + return (-1); +} + +/* + * Given database name 'dbname' retrieve cache context, + * if not created yet, allocate and initialize it. + */ +static nscd_rc_t +get_cache_ctx(char *dbname, nsc_ctx_t **ctx) { + int i; + + *ctx = NULL; + + i = get_cache_idx(dbname); + if (i == -1) + return (NSCD_INVALID_ARGUMENT); + if ((*ctx = cache_ctx_p[i]) == NULL) { + *ctx = init_cache_ctx(i); + if (*ctx == NULL) + return (NSCD_NO_MEMORY); + } + + return (NSCD_SUCCESS); +} + +/* + * Generate a log string to identify backend operation in debug logs + */ +static void +nsc_db_str_key_getlogstr(char *name, char *whoami, size_t len, + nss_XbyY_args_t *argp) { + (void) snprintf(whoami, len, "%s [key=%s]", name, argp->key.name); +} + + +static void +nsc_db_int_key_getlogstr(char *name, char *whoami, size_t len, + nss_XbyY_args_t *argp) { + (void) snprintf(whoami, len, "%s [key=%d]", name, argp->key.number); +} + +/*ARGSUSED*/ +static void +nsc_db_any_key_getlogstr(char *name, char *whoami, size_t len, + nss_XbyY_args_t *argp) { + (void) snprintf(whoami, len, "%s", name); +} + + +/* + * Returns cache based on dbop + */ +static nsc_db_t * +nsc_get_db(nsc_ctx_t *ctx, int dbop) { + int i; + + for (i = 0; i < ctx->db_count; i++) { + if (ctx->nsc_db[i] && dbop == ctx->nsc_db[i]->dbop) + return (ctx->nsc_db[i]); + } + return (NULL); +} + + +/* + * integer compare routine for _NSC_DB_INT_KEY + */ +static int +nsc_db_int_key_compar(const void *n1, const void *n2) { + nsc_entry_t *e1, *e2; + + e1 = (nsc_entry_t *)n1; + e2 = (nsc_entry_t *)n2; + return (_NSC_INT_KEY_CMP(e1->key.number, e2->key.number)); +} + + +/* + * case sensitive name compare routine for _NSC_DB_CES_KEY + */ +static int +nsc_db_ces_key_compar(const void *n1, const void *n2) { + nsc_entry_t *e1, *e2; + int res, l1, l2; + + e1 = (nsc_entry_t *)n1; + e2 = (nsc_entry_t *)n2; + l1 = strlen(e1->key.name); + l2 = strlen(e2->key.name); + res = strncmp(e1->key.name, e2->key.name, (l1 > l2)?l1:l2); + return (_NSC_INT_KEY_CMP(res, 0)); +} + + +/* + * case insensitive name compare routine _NSC_DB_CIS_KEY + */ +static int +nsc_db_cis_key_compar(const void *n1, const void *n2) { + nsc_entry_t *e1, *e2; + int res, l1, l2; + + e1 = (nsc_entry_t *)n1; + e2 = (nsc_entry_t *)n2; + l1 = strlen(e1->key.name); + l2 = strlen(e2->key.name); + res = strncasecmp(e1->key.name, e2->key.name, (l1 > l2)?l1:l2); + return (_NSC_INT_KEY_CMP(res, 0)); +} + +/* + * macro used to generate elf hashes for strings + */ +#define _NSC_ELF_STR_GETHASH(func, str, htsize, hval) \ + hval = 0; \ + while (*str) { \ + uint_t g; \ + hval = (hval << 4) + func(*str++); \ + if ((g = (hval & 0xf0000000)) != 0) \ + hval ^= g >> 24; \ + hval &= ~g; \ + } \ + hval %= htsize; + + +/* + * cis hash function + */ +uint_t +cis_gethash(const char *key, int htsize) { + uint_t hval; + if (key == NULL) + return (0); + _NSC_ELF_STR_GETHASH(tolower, key, htsize, hval); + return (hval); +} + + +/* + * ces hash function + */ +uint_t +ces_gethash(const char *key, int htsize) { + uint_t hval; + if (key == NULL) + return (0); + _NSC_ELF_STR_GETHASH(, key, htsize, hval); + return (hval); +} + + +/* + * one-at-a-time hash function + */ +uint_t +db_gethash(const void *key, int len, int htsize) { + uint_t hval, i; + const char *str = key; + + if (str == NULL) + return (0); + + for (hval = 0, i = 0; i < len; i++) { + hval += str[i]; + hval += (hval << 10); + hval ^= (hval >> 6); + } + hval += (hval << 3); + hval ^= (hval >> 11); + hval += (hval << 15); + return (hval % htsize); +} + + +/* + * case insensitive name gethash routine _NSC_DB_CIS_KEY + */ +static uint_t +nsc_db_cis_key_gethash(nss_XbyY_key_t *key, int htsize) { + return (cis_gethash(key->name, htsize)); +} + + +/* + * case sensitive name gethash routine _NSC_DB_CES_KEY + */ +static uint_t +nsc_db_ces_key_gethash(nss_XbyY_key_t *key, int htsize) { + return (ces_gethash(key->name, htsize)); +} + + +/* + * integer gethash routine _NSC_DB_INT_KEY + */ +static uint_t +nsc_db_int_key_gethash(nss_XbyY_key_t *key, int htsize) { + return (db_gethash(&key->number, sizeof (key->number), htsize)); +} + + +/* + * Find entry in the hash table + * if cmp == nscd_true) + * return entry only if the keys match + * else + * return entry in the hash location without checking the keys + * + */ +static nsc_entry_t * +hash_find(nsc_db_t *nscdb, nsc_entry_t *entry, uint_t *hash, + nscd_bool_t cmp) { + + nsc_entry_t *hashentry; + + if (nscdb->gethash) + *hash = nscdb->gethash(&entry->key, nscdb->htsize); + else + return (NULL); + + hashentry = nscdb->htable[*hash]; + if (cmp == nscd_false || hashentry == NULL) + return (hashentry); + if (nscdb->compar) { + if (nscdb->compar(entry, hashentry) == 0) + return (hashentry); + } + return (NULL); +} + + +#define HASH_REMOVE(nscdb, entry, hash, cmp) \ + if (nscdb->htable) { \ + if (entry == hash_find(nscdb, entry, &hash, cmp)) \ + nscdb->htable[hash] = NULL; \ + } + + +#define HASH_INSERT(nscdb, entry, hash, cmp) \ + if (nscdb->htable) { \ + (void) hash_find(nscdb, entry, &hash, cmp); \ + nscdb->htable[hash] = entry; \ + } + + +#ifdef NSCD_DEBUG +static void +print_entry(nsc_db_t *nscdb, time_t now, nsc_entry_t *entry) { + nss_XbyY_args_t args; + char whoami[512]; + + switch (entry->stats.status) { + case ST_NEW_ENTRY: + (void) fprintf(stdout, gettext("\t status: new entry\n")); + return; + case ST_UPDATE_PENDING: + (void) fprintf(stdout, gettext("\t status: update pending\n")); + return; + case ST_LOOKUP_PENDING: + (void) fprintf(stdout, gettext("\t status: lookup pending\n")); + return; + case ST_DISCARD: + (void) fprintf(stdout, gettext("\t status: discarded entry\n")); + return; + default: + if (entry->stats.timestamp < now) + (void) fprintf(stdout, + gettext("\t status: expired (%d seconds ago)\n"), + now - entry->stats.timestamp); + else + (void) fprintf(stdout, + gettext("\t status: valid (expiry in %d seconds)\n"), + entry->stats.timestamp - now); + break; + } + (void) fprintf(stdout, gettext("\t hits: %u\n"), entry->stats.hits); + args.key = entry->key; + (void) nscdb->getlogstr(nscdb->name, whoami, sizeof (whoami), &args); + (void) fprintf(stdout, "\t %s\n", whoami); +} +#endif /* NSCD_DEBUG */ + +static void +print_stats(nscd_cfg_stat_cache_t *statsp) { + + (void) fprintf(stdout, gettext("\n\t STATISTICS:\n")); + (void) fprintf(stdout, gettext("\t positive hits: %lu\n"), + statsp->pos_hits); + (void) fprintf(stdout, gettext("\t negative hits: %lu\n"), + statsp->neg_hits); + (void) fprintf(stdout, gettext("\t positive misses: %lu\n"), + statsp->pos_misses); + (void) fprintf(stdout, gettext("\t negative misses: %lu\n"), + statsp->neg_misses); + (void) fprintf(stdout, gettext("\t total entries: %lu\n"), + statsp->entries); + (void) fprintf(stdout, gettext("\t queries queued: %lu\n"), + statsp->wait_count); + (void) fprintf(stdout, gettext("\t queries dropped: %lu\n"), + statsp->drop_count); + (void) fprintf(stdout, gettext("\t cache invalidations: %lu\n"), + statsp->invalidate_count); + + _NSC_GET_HITRATE(statsp); + (void) fprintf(stdout, gettext("\t cache hit rate: %10.1f\n"), + statsp->hitrate); +} + + +static void +print_cfg(nscd_cfg_cache_t *cfgp) { + (void) fprintf(stdout, gettext("\n\t CONFIG:\n")); + (void) fprintf(stdout, gettext("\t enabled: %s\n"), + yes_no(cfgp->enable)); + (void) fprintf(stdout, gettext("\t per user cache: %s\n"), + yes_no(cfgp->per_user)); + (void) fprintf(stdout, gettext("\t avoid name service: %s\n"), + yes_no(cfgp->avoid_ns)); + (void) fprintf(stdout, gettext("\t check file: %s\n"), + yes_no(cfgp->check_files)); + (void) fprintf(stdout, gettext("\t check file interval: %d\n"), + cfgp->check_interval); + (void) fprintf(stdout, gettext("\t positive ttl: %d\n"), + cfgp->pos_ttl); + (void) fprintf(stdout, gettext("\t negative ttl: %d\n"), + cfgp->neg_ttl); + (void) fprintf(stdout, gettext("\t keep hot count: %d\n"), + cfgp->keephot); + (void) fprintf(stdout, gettext("\t hint size: %d\n"), + cfgp->hint_size); + (void) fprintf(stdout, gettext("\t max entries: %lu%s"), + cfgp->maxentries, + cfgp->maxentries?"\n":" (unlimited)\n"); +} + + +#ifdef NSCD_DEBUG +static void +hash_dump(nsc_db_t *nscdb, time_t now) { + nsc_entry_t *entry; + int i; + + (void) fprintf(stdout, gettext("\n\nHASH TABLE:\n")); + for (i = 0; i < nscdb->htsize; i++) { + if ((entry = nscdb->htable[i]) != NULL) { + (void) fprintf(stdout, "hash[%d]:\n", i); + print_entry(nscdb, now, entry); + } + } +} +#endif /* NSCD_DEBUG */ + + +#ifdef NSCD_DEBUG +static void +avl_dump(nsc_db_t *nscdb, time_t now) { + nsc_entry_t *entry; + int i; + + (void) fprintf(stdout, gettext("\n\nAVL TREE:\n")); + for (entry = avl_first(&nscdb->tree), i = 0; entry != NULL; + entry = avl_walk(&nscdb->tree, entry, AVL_AFTER)) { + (void) fprintf(stdout, "avl node[%d]:\n", i++); + print_entry(nscdb, now, entry); + } +} +#endif /* NSCD_DEBUG */ + + +#ifdef NSCD_DEBUG +static void +queue_dump(nsc_db_t *nscdb, time_t now) { + nsc_entry_t *entry; + int i; + + (void) fprintf(stdout, + gettext("\n\nCACHE [name=%s, nodes=%lu]:\n"), + nscdb->name, avl_numnodes(&nscdb->tree)); + + (void) fprintf(stdout, + gettext("Starting with the most recently accessed:\n")); + + for (entry = nscdb->qtail, i = 0; entry; entry = entry->qnext) { + (void) fprintf(stdout, "entry[%d]:\n", i++); + print_entry(nscdb, now, entry); + } +} +#endif /* NSCD_DEBUG */ + +static void +queue_remove(nsc_db_t *nscdb, nsc_entry_t *entry) { + + if (nscdb->qtail == entry) + nscdb->qtail = entry->qnext; + else + entry->qprev->qnext = entry->qnext; + + if (nscdb->qhead == entry) + nscdb->qhead = entry->qprev; + else + entry->qnext->qprev = entry->qprev; + + if (nscdb->reap_node == entry) + nscdb->reap_node = entry->qnext; + entry->qnext = entry->qprev = NULL; +} + + +static void +queue_adjust(nsc_db_t *nscdb, nsc_entry_t *entry) { + +#ifdef NSCD_DEBUG + assert(nscdb->qtail || entry->qnext == NULL && + entry->qprev == NULL); + + assert(nscdb->qtail && nscdb->qhead || + nscdb->qtail == NULL && nscdb->qhead == NULL); + + assert(entry->qprev || entry->qnext == NULL || + nscdb->qtail == entry); +#endif /* NSCD_DEBUG */ + + /* already in the desired position */ + if (nscdb->qtail == entry) + return; + + /* new queue */ + if (nscdb->qtail == NULL) { + nscdb->qhead = nscdb->qtail = entry; + return; + } + + /* new entry (prev == NULL AND tail != entry) */ + if (entry->qprev == NULL) { + nscdb->qtail->qprev = entry; + entry->qnext = nscdb->qtail; + nscdb->qtail = entry; + return; + } + + /* existing entry */ + if (nscdb->reap_node == entry) + nscdb->reap_node = entry->qnext; + if (nscdb->qhead == entry) + nscdb->qhead = entry->qprev; + else + entry->qnext->qprev = entry->qprev; + entry->qprev->qnext = entry->qnext; + entry->qprev = NULL; + entry->qnext = nscdb->qtail; + nscdb->qtail->qprev = entry; + nscdb->qtail = entry; +} + + +/* + * Init cache + */ +nscd_rc_t +init_cache(int debug_level) { + int cflags; + + cflags = (debug_level > 0)?0:UMC_NODEBUG; + nsc_entry_cache = umem_cache_create("nsc_entry_cache", + sizeof (nsc_entry_t), 0, NULL, NULL, NULL, + NULL, NULL, cflags); + if (nsc_entry_cache == NULL) + return (NSCD_NO_MEMORY); + return (NSCD_SUCCESS); +} + + +/* + * Create cache + */ +nsc_db_t * +make_cache(enum db_type dbtype, int dbop, char *name, + int (*compar) (const void *, const void *), + void (*getlogstr)(char *, char *, size_t, nss_XbyY_args_t *), + uint_t (*gethash)(nss_XbyY_key_t *, int), + enum hash_type httype, int htsize) { + + nsc_db_t *nscdb; + char *me = "make_cache"; + + nscdb = (nsc_db_t *)malloc(sizeof (*nscdb)); + if (nscdb == NULL) { + _NSCD_LOG(NSCD_LOG_CACHE, NSCD_LOG_LEVEL_ERROR) + (me, "%s: memory allocation failure\n", name); + goto out; + } + (void) memset(nscdb, 0, sizeof (*nscdb)); + + nscdb->dbop = dbop; + nscdb->name = name; + nscdb->db_type = dbtype; + + /* Assign compare routine */ + if (compar == NULL) { + if (_NSC_DB_CES_KEY(nscdb)) + nscdb->compar = nsc_db_ces_key_compar; + else if (_NSC_DB_CIS_KEY(nscdb)) + nscdb->compar = nsc_db_cis_key_compar; + else if (_NSC_DB_INT_KEY(nscdb)) + nscdb->compar = nsc_db_int_key_compar; + else + assert(0); + } else { + nscdb->compar = compar; + } + + /* The cache is an AVL tree */ + avl_create(&nscdb->tree, nscdb->compar, sizeof (nsc_entry_t), + offsetof(nsc_entry_t, avl_link)); + + /* Assign log routine */ + if (getlogstr == NULL) { + if (_NSC_DB_STR_KEY(nscdb)) + nscdb->getlogstr = nsc_db_str_key_getlogstr; + else if (_NSC_DB_INT_KEY(nscdb)) + nscdb->getlogstr = nsc_db_int_key_getlogstr; + else + nscdb->getlogstr = nsc_db_any_key_getlogstr; + } else { + nscdb->getlogstr = getlogstr; + } + + /* The AVL tree based cache uses a hash table for quick access */ + if (htsize != 0) { + /* Determine hash table size based on type */ + nscdb->hash_type = httype; + if (htsize < 0) { + switch (httype) { + case nsc_ht_power2: + htsize = _NSC_INIT_HTSIZE_POWER2; + break; + case nsc_ht_prime: + case nsc_ht_default: + default: + htsize = _NSC_INIT_HTSIZE_PRIME; + } + } + nscdb->htsize = htsize; + + /* Create the hash table */ + nscdb->htable = calloc(htsize, sizeof (*(nscdb->htable))); + if (nscdb->htable == NULL) { + _NSCD_LOG(NSCD_LOG_CACHE, NSCD_LOG_LEVEL_ERROR) + (me, "%s: memory allocation failure\n", name); + goto out; + } + + /* Assign gethash routine */ + if (gethash == NULL) { + if (_NSC_DB_CES_KEY(nscdb)) + nscdb->gethash = nsc_db_ces_key_gethash; + else if (_NSC_DB_CIS_KEY(nscdb)) + nscdb->gethash = nsc_db_cis_key_gethash; + else if (_NSC_DB_INT_KEY(nscdb)) + nscdb->gethash = nsc_db_int_key_gethash; + else + assert(0); + } else { + nscdb->gethash = gethash; + } + } + + (void) mutex_init(&nscdb->db_mutex, USYNC_THREAD, NULL); + return (nscdb); + +out: + if (nscdb->htable) + free(nscdb->htable); + if (nscdb) + free(nscdb); + return (NULL); +} + + +/* + * verify + */ +/* ARGSUSED */ +nscd_rc_t +_nscd_cfg_cache_verify( + void *data, + struct nscd_cfg_param_desc *pdesc, + nscd_cfg_id_t *nswdb, + nscd_cfg_flag_t dflag, + nscd_cfg_error_t **errorp, + void **cookie) +{ + + return (NSCD_SUCCESS); +} + +/* + * notify + */ +/* ARGSUSED */ +nscd_rc_t +_nscd_cfg_cache_notify( + void *data, + struct nscd_cfg_param_desc *pdesc, + nscd_cfg_id_t *nswdb, + nscd_cfg_flag_t dflag, + nscd_cfg_error_t **errorp, + void **cookie) +{ + nsc_ctx_t *ctx; + void *dp; + int i; + + /* group data */ + if (_nscd_cfg_flag_is_set(dflag, NSCD_CFG_DFLAG_GROUP)) { + if (_nscd_cfg_flag_is_set(pdesc->pflag, + NSCD_CFG_PFLAG_GLOBAL)) { + /* global config */ + global_cfg = *(nscd_cfg_global_cache_t *)data; + } else if (_nscd_cfg_flag_is_set(dflag, + NSCD_CFG_DFLAG_SET_ALL_DB)) { + /* non-global config for all dbs */ + for (i = 0; i < CACHE_CTX_COUNT; i++) { + ctx = cache_ctx_p[i]; + if (ctx == NULL) + return (NSCD_CTX_NOT_FOUND); + (void) rw_wrlock(&ctx->cfg_rwlp); + ctx->cfg = *(nscd_cfg_cache_t *)data; + ctx->cfg_mtime = time(NULL); + (void) rw_unlock(&ctx->cfg_rwlp); + } + } else { + /* non-global config for a specific db */ + + /* ignore non-caching databases */ + if (get_cache_ctx(nswdb->name, &ctx) != + NSCD_SUCCESS) + return (NSCD_SUCCESS); + (void) rw_wrlock(&ctx->cfg_rwlp); + ctx->cfg = *(nscd_cfg_cache_t *)data; + ctx->cfg_mtime = time(NULL); + (void) rw_unlock(&ctx->cfg_rwlp); + } + return (NSCD_SUCCESS); + } + + /* individual data */ + if (_nscd_cfg_flag_is_set(pdesc->pflag, + NSCD_CFG_PFLAG_GLOBAL)) { + /* global config */ + dp = (char *)&global_cfg + pdesc->p_offset; + (void) memcpy(dp, data, pdesc->p_size); + } else if (_nscd_cfg_flag_is_set(dflag, + NSCD_CFG_DFLAG_SET_ALL_DB)) { + /* non-global config for all dbs */ + for (i = 0; i < CACHE_CTX_COUNT; i++) { + ctx = cache_ctx_p[i]; + if (ctx == NULL) + return (NSCD_CTX_NOT_FOUND); + dp = (char *)&ctx->cfg + pdesc->p_offset; + (void) rw_wrlock(&ctx->cfg_rwlp); + (void) memcpy(dp, data, pdesc->p_size); + ctx->cfg_mtime = time(NULL); + (void) rw_unlock(&ctx->cfg_rwlp); + } + } else { + /* non-global config for a specific db */ + + /* ignore non-caching databases */ + if (get_cache_ctx(nswdb->name, &ctx) != NSCD_SUCCESS) + return (NSCD_SUCCESS); + dp = (char *)&ctx->cfg + pdesc->p_offset; + (void) rw_wrlock(&ctx->cfg_rwlp); + (void) memcpy(dp, data, pdesc->p_size); + ctx->cfg_mtime = time(NULL); + (void) rw_unlock(&ctx->cfg_rwlp); + } + return (NSCD_SUCCESS); +} + + +/* + * get stat + */ +/* ARGSUSED */ +nscd_rc_t +_nscd_cfg_cache_get_stat( + void **stat, + struct nscd_cfg_stat_desc *sdesc, + nscd_cfg_id_t *nswdb, + nscd_cfg_flag_t *dflag, + void (**free_stat)(void *stat), + nscd_cfg_error_t **errorp) +{ + nscd_cfg_stat_cache_t *statsp, stats; + nsc_ctx_t *ctx; + int i; + nscd_rc_t rc; + + statsp = calloc(1, sizeof (*statsp)); + if (statsp == NULL) + return (NSCD_NO_MEMORY); + + if (_nscd_cfg_flag_is_set(sdesc->sflag, NSCD_CFG_SFLAG_GLOBAL)) { + for (i = 0; i < CACHE_CTX_COUNT; i++) { + if (cache_ctx_p[i] == NULL) + stats = null_stats; + else { + (void) mutex_lock(&cache_ctx_p[i]->stats_mutex); + stats = cache_ctx_p[i]->stats; + (void) mutex_unlock( + &cache_ctx_p[i]->stats_mutex); + } + statsp->pos_hits += stats.pos_hits; + statsp->neg_hits += stats.neg_hits; + statsp->pos_misses += stats.pos_misses; + statsp->neg_misses += stats.neg_misses; + statsp->entries += stats.entries; + statsp->drop_count += stats.drop_count; + statsp->wait_count += stats.wait_count; + statsp->invalidate_count += + stats.invalidate_count; + } + } else { + if ((rc = get_cache_ctx(nswdb->name, &ctx)) != NSCD_SUCCESS) { + free(statsp); + return (rc); + } + (void) mutex_lock(&ctx->stats_mutex); + *statsp = ctx->stats; + (void) mutex_unlock(&ctx->stats_mutex); + } + + _NSC_GET_HITRATE(statsp); + *stat = statsp; + return (NSCD_SUCCESS); +} + +/* + * This function should only be called when nscd is + * not a daemon. + */ +void +nsc_info(nsc_ctx_t *ctx, char *dbname, nscd_cfg_cache_t cfg[], + nscd_cfg_stat_cache_t stats[]) +{ + int i; + char *me = "nsc_info"; + nsc_ctx_t *ctx1; + nsc_ctx_t ctx2; + nscd_rc_t rc; + + if (ctx) { + ctx_info(ctx); + return; + } + + if (dbname) { + rc = get_cache_ctx(dbname, &ctx1); + if (rc == NSCD_INVALID_ARGUMENT) { + _NSCD_LOG(NSCD_LOG_CACHE, NSCD_LOG_LEVEL_WARNING) + (me, "%s: no cache context found\n", dbname); + return; + } else if (rc == NSCD_NO_MEMORY) { + _NSCD_LOG(NSCD_LOG_CACHE, NSCD_LOG_LEVEL_WARNING) + (me, "%s: unable to create cache context - no memory\n", + dbname); + return; + } + ctx_info(ctx1); + return; + } + + if (cfg == NULL || stats == NULL) + return; + + for (i = 0; i < CACHE_CTX_COUNT; i++) { + + ctx2.dbname = cache_name[i]; + ctx2.cfg = cfg[i]; + ctx2.stats = stats[i]; + ctx_info_nolock(&ctx2); + } +} + +static void +ctx_info_nolock(nsc_ctx_t *ctx) { + nscd_cfg_cache_t cfg; + nscd_cfg_stat_cache_t stats; + + cfg = ctx->cfg; + (void) fprintf(stdout, gettext("\n\nCACHE: %s\n"), ctx->dbname); + (void) print_cfg(&cfg); + + if (cfg.enable == nscd_false) + return; + + stats = ctx->stats; + (void) print_stats(&stats); +} + +static void +ctx_info(nsc_ctx_t *ctx) { + nscd_cfg_cache_t cfg; + nscd_cfg_stat_cache_t stats; + + (void) rw_rdlock(&ctx->cfg_rwlp); + cfg = ctx->cfg; + (void) rw_unlock(&ctx->cfg_rwlp); + (void) fprintf(stdout, gettext("\n\nCACHE: %s\n"), ctx->dbname); + (void) print_cfg(&cfg); + + if (cfg.enable == nscd_false) + return; + + (void) mutex_lock(&ctx->stats_mutex); + stats = ctx->stats; + (void) mutex_unlock(&ctx->stats_mutex); + (void) print_stats(&stats); +} + +#ifdef NSCD_DEBUG +/* + * This function should only be called when nscd is + * not a daemon. + */ +int +nsc_dump(char *dbname, int dbop) { + nsc_ctx_t *ctx; + nsc_db_t *nscdb; + nscd_bool_t enabled; + time_t now; + char *me = "nsc_dump"; + int i; + + if ((i = get_cache_idx(dbname)) == -1) { + (void) fprintf(stdout, gettext("invalid cache name\n")); + + _NSCD_LOG(NSCD_LOG_CACHE, NSCD_LOG_LEVEL_WARNING) + (me, "%s: invalid cache name\n", dbname); + return (NSCD_CACHE_INVALID_CACHE_NAME); + } + + if ((ctx = cache_ctx_p[i]) == NULL) { + (void) fprintf(stdout, gettext("no cache context\n")); + + _NSCD_LOG(NSCD_LOG_CACHE, NSCD_LOG_LEVEL_WARNING) + (me, "%s: no cache context\n", dbname); + return (NSCD_CACHE_NO_CACHE_CTX); + } + + now = time(NULL); + (void) rw_rdlock(&ctx->cfg_rwlp); + enabled = ctx->cfg.enable; + (void) rw_unlock(&ctx->cfg_rwlp); + + if (enabled == nscd_false) + return (NSCD_CACHE_DISABLED); + + nscdb = nsc_get_db(ctx, dbop); + if (nscdb == NULL) { + _NSCD_LOG(NSCD_LOG_CACHE, NSCD_LOG_LEVEL_WARNING) + (me, "%s:%d: no cache found\n", dbname, dbop); + return (NSCD_CACHE_NO_CACHE_FOUND); + } + + (void) mutex_lock(&nscdb->db_mutex); + (void) queue_dump(nscdb, now); + (void) hash_dump(nscdb, now); + (void) avl_dump(nscdb, now); + (void) mutex_unlock(&nscdb->db_mutex); + return (NSCD_SUCCESS); +} +#endif /* NSCD_DEBUG */ + +/* + * These macros are for exclusive use of nsc_lookup + */ +#define NSC_LOOKUP_RETURN(retcode, loglevel, fmt) \ + (void) mutex_unlock(&nscdb->db_mutex); \ + _NSCD_LOG(NSCD_LOG_CACHE, NSCD_LOG_LEVEL_##loglevel) \ + (me, fmt, whoami); \ + return (retcode); + +#define NSC_LOOKUP_NO_CACHE(str) \ + _NSCD_LOG(NSCD_LOG_CACHE, NSCD_LOG_LEVEL_DEBUG) \ + (me, "%s: name service lookup (bypassing cache\n", \ + str); \ + nss_psearch(largs->buffer, largs->bufsize); \ + status = NSCD_GET_STATUS(largs->buffer); \ + _NSCD_LOG(NSCD_LOG_CACHE, NSCD_LOG_LEVEL_DEBUG) \ + (me, "%s: name service lookup status = %d\n", \ + str, status); \ + if (status == NSS_SUCCESS) { \ + return (SUCCESS); \ + } else if (status == NSS_NOTFOUND) \ + return (NOTFOUND); \ + else \ + return (SERVERERROR); + +/* + * This function starts the revalidation and reaper threads + * for a cache + */ +static void +start_threads(nsc_ctx_t *ctx) { + + int errnum; + char *me = "start_threads"; + + /* + * kick off the revalidate thread (if necessary) + */ + if (ctx->revalidate_on != nscd_true) { + if (thr_create(NULL, NULL, (void *(*)(void *))revalidate, + ctx, 0, NULL) != 0) { + errnum = errno; + _NSCD_LOG(NSCD_LOG_CACHE, NSCD_LOG_LEVEL_ERROR) + (me, "thr_create (revalidate thread for %s): %s\n", + ctx->dbname, strerror(errnum)); + exit(1); + } + ctx->revalidate_on = nscd_true; + } + + /* + * kick off the reaper thread (if necessary) + */ + if (ctx->reaper_on != nscd_true) { + if (thr_create(NULL, NULL, (void *(*)(void *))reaper, + ctx, 0, NULL) != 0) { + errnum = errno; + _NSCD_LOG(NSCD_LOG_CACHE, NSCD_LOG_LEVEL_ERROR) + (me, "thr_create (reaper thread for %s): %s\n", + ctx->dbname, strerror(errnum)); + exit(1); + } + ctx->reaper_on = nscd_true; + } +} + +/* + * Examine the packed buffer, see if the front-end parameters + * indicate that the caller specified nsswitch config should be + * used for the lookup. Return 1 if yes, otherwise 0. + */ +static int +nsw_config_in_phdr(void *buf) +{ + nss_pheader_t *pbuf = (nss_pheader_t *)buf; + nssuint_t off; + nss_dbd_t *pdbd; + char *me = "nsw_config_in_phdr"; + + off = pbuf->dbd_off; + if (off == 0) + return (0); + pdbd = (nss_dbd_t *)((void *)((char *)pbuf + off)); + if (pdbd->o_default_config == 0) + return (0); + + if ((enum nss_dbp_flags)pdbd->flags & NSS_USE_DEFAULT_CONFIG) { + _NSCD_LOG(NSCD_LOG_CACHE, NSCD_LOG_LEVEL_DEBUG) + (me, "use caller specified nsswitch config\n"); + return (1); + } else + return (0); +} + +static nss_status_t +copy_result(void *rbuf, void *cbuf) +{ + nss_pheader_t *rphdr = (nss_pheader_t *)rbuf; + nss_pheader_t *cphdr = (nss_pheader_t *)cbuf; + char *me = "copy_result"; + + /* return NSS_ERROR if not enough room to copy result */ + if (cphdr->data_len + 1 > rphdr->data_len) { + NSCD_SET_STATUS(rphdr, NSS_ERROR, ERANGE); + return (NSS_ERROR); + } else { + char *dst; + + if (cphdr->data_len == 0) + return (NSS_SUCCESS); + + dst = (char *)rphdr + rphdr->data_off; + (void) memcpy(dst, (char *)cphdr + cphdr->data_off, + cphdr->data_len); + rphdr->data_len = cphdr->data_len; + /* some frontend code expects a terminating NULL char */ + *(dst + rphdr->data_len) = '\0'; + + _NSCD_LOG(NSCD_LOG_CACHE, NSCD_LOG_LEVEL_DEBUG) + (me, "cache data (len = %lld): %s\n", + cphdr->data_len, (char *)cphdr + cphdr->data_off); + + return (NSS_SUCCESS); + } +} + +static int +get_dns_ttl(void *pbuf, char *dbname) +{ + nss_pheader_t *phdr = (nss_pheader_t *)pbuf; + int ttl; + char *me = "get_dns_ttl"; + + /* if returned, dns ttl is stored in the extended data area */ + if (phdr->ext_off == 0) + return (-1); + + if (strcmp(dbname, NSS_DBNAM_HOSTS) != 0 && + strcmp(dbname, NSS_DBNAM_IPNODES) != 0) + return (-1); + + ttl = *(nssuint_t *)((void *)((char *)pbuf + phdr->ext_off)); + + _NSCD_LOG(NSCD_LOG_CACHE, NSCD_LOG_LEVEL_DEBUG) + (me, "dns ttl is %d seconds\n", ttl); + + return (ttl); +} + +static int +check_config(nsc_lookup_args_t *largs, nscd_cfg_cache_t *cfgp, + char *whoami, int flag) +{ + nsc_db_t *nscdb; + nsc_ctx_t *ctx; + nss_status_t status; + char *me = "check_config"; + + ctx = largs->ctx; + nscdb = largs->nscdb; + + /* see if the cached config needs update */ + if (nscdb->cfg_mtime != ctx->cfg_mtime) { + (void) rw_rdlock(&ctx->cfg_rwlp); + nscdb->cfg = ctx->cfg; + nscdb->cfg_mtime = ctx->cfg_mtime; + (void) rw_unlock(&ctx->cfg_rwlp); + _NSCD_LOG(NSCD_LOG_CACHE, NSCD_LOG_LEVEL_DEBUG) + (me, "config for context %s, database %s updated\n", + ctx->dbname, nscdb->name); + } + *cfgp = nscdb->cfg; + + if (cfgp->enable == nscd_false) { + _NSCD_LOG(NSCD_LOG_CACHE, NSCD_LOG_LEVEL_DEBUG) + (me, "%s: cache disabled\n", ctx->dbname); + + if (UPDATEBIT & flag) + return (NOTFOUND); + else { + NSC_LOOKUP_NO_CACHE(whoami); + } + } + + /* + * if caller requests lookup using his + * own nsswitch config, bypass cache + */ + if (nsw_config_in_phdr(largs->buffer)) { + NSC_LOOKUP_NO_CACHE(whoami); + } + + /* no need of cache if we are dealing with 0 ttls */ + if (cfgp->pos_ttl <= 0 && cfgp->neg_ttl <= 0) { + if (flag & UPDATEBIT) + return (NOTFOUND); + else if (cfgp->avoid_ns == nscd_true) + return (SERVERERROR); + NSC_LOOKUP_NO_CACHE(whoami); + } + + return (CONTINUE); +} + +/* + * Invalidate cache if database file has been modified. + * See check_files config param for details. + */ +static void +check_db_file(nsc_ctx_t *ctx, nscd_cfg_cache_t cfg, + char *whoami, time_t now) +{ + struct stat buf; + nscd_bool_t file_modified = nscd_false; + char *me = "check_db_file"; + + if (cfg.check_interval != 0 && + (now - ctx->file_chktime) < cfg.check_interval) + return; + + ctx->file_chktime = now; + if (stat(ctx->file_name, &buf) == 0) { + if (ctx->file_mtime == 0) { + (void) mutex_lock(&ctx->file_mutex); + if (ctx->file_mtime == 0) { + ctx->file_mtime = buf.st_mtime; + ctx->file_size = buf.st_size; + ctx->file_ino = buf.st_ino; + } + (void) mutex_unlock(&ctx->file_mutex); + } else if (ctx->file_mtime < buf.st_mtime || + ctx->file_size != buf.st_size || + ctx->file_ino != buf.st_ino) { + (void) mutex_lock(&ctx->file_mutex); + if (ctx->file_mtime < buf.st_mtime || + ctx->file_size != buf.st_size || + ctx->file_ino != buf.st_ino) { + file_modified = nscd_true; + ctx->file_mtime = buf.st_mtime; + ctx->file_size = buf.st_size; + ctx->file_ino = buf.st_ino; + } + (void) mutex_unlock(&ctx->file_mutex); + } + } + + if (file_modified == nscd_true) { + _NSCD_LOG(NSCD_LOG_CACHE, NSCD_LOG_LEVEL_DEBUG) + (me, "%s: file %s has been modified - invalidating cache\n", + whoami, ctx->file_name); + ctx_invalidate(ctx); + } +} + +static int +lookup_int(nsc_lookup_args_t *largs, int flag) { + + nsc_ctx_t *ctx; + nsc_db_t *nscdb; + nscd_cfg_cache_t cfg; + nsc_entry_t *this_entry; + nsc_entry_stat_t *this_stats; + nsc_action_t next_action; + nss_status_t status; + nscd_bool_t delete; + nscd_rc_t rc; + char *dbname; + int dbop, errnum; + int cfg_rc; + nss_XbyY_args_t args; + char whoami[128]; + time_t now = time(NULL); /* current time */ + char *me = "lookup_int"; + + /* extract dbop, dbname, key and cred */ + status = nss_packed_getkey(largs->buffer, largs->bufsize, &dbname, + &dbop, &args); + if (status != NSS_SUCCESS) { + _NSCD_LOG(NSCD_LOG_CACHE, NSCD_LOG_LEVEL_ERROR) + (me, "nss_packed_getkey failure (%d)\n", status); + return (SERVERERROR); + } + + /* get the cache context */ + if (largs->ctx == NULL) { + if (get_cache_ctx(dbname, &largs->ctx) != NSCD_SUCCESS) { + _NSCD_LOG(NSCD_LOG_CACHE, NSCD_LOG_LEVEL_WARNING) + (me, "%s: no cache context found\n", dbname); + + if (UPDATEBIT & flag) + return (NOTFOUND); + else { + NSC_LOOKUP_NO_CACHE(dbname); + } + } + } + ctx = largs->ctx; + + if (largs->nscdb == NULL) { + if ((largs->nscdb = nsc_get_db(ctx, dbop)) == NULL) { + _NSCD_LOG(NSCD_LOG_CACHE, NSCD_LOG_LEVEL_WARNING) + (me, "%s:%d: no cache found\n", + dbname, dbop); + + if (UPDATEBIT & flag) + return (NOTFOUND); + else { + NSC_LOOKUP_NO_CACHE(dbname); + } + } + } + + nscdb = largs->nscdb; + + _NSCD_LOG_IF(NSCD_LOG_CACHE, NSCD_LOG_LEVEL_ALL) { + (void) nscdb->getlogstr(nscdb->name, whoami, + sizeof (whoami), &args); + } + + if (UPDATEBIT & flag) { + _NSCD_LOG(NSCD_LOG_CACHE, NSCD_LOG_LEVEL_DEBUG) + (me, "%s: refresh start\n", whoami); + } else { + _NSCD_LOG(NSCD_LOG_CACHE, NSCD_LOG_LEVEL_DEBUG) + (me, "%s: lookup start\n", whoami); + } + + cfg_rc = check_config(largs, &cfg, whoami, flag); + if (cfg_rc != CONTINUE) + return (cfg_rc); + + /* + * Invalidate cache if file has been modified. + */ + if (cfg.check_files == nscd_true) + check_db_file(ctx, cfg, whoami, now); + + (void) mutex_lock(&nscdb->db_mutex); + + /* Lookup the cache table */ + for (;;) { + delete = nscd_false; + rc = lookup_cache(largs, &cfg, &args, whoami, &this_entry); + if (rc != NSCD_SUCCESS) { + (void) mutex_unlock(&nscdb->db_mutex); + + /* Either no entry and avoid name service */ + if (rc == NSCD_DB_ENTRY_NOT_FOUND || + rc == NSCD_INVALID_ARGUMENT) + return (NOTFOUND); + + /* OR memory error */ + return (SERVERERROR); + } + + /* get the stats from the entry */ + this_stats = &this_entry->stats; + + /* + * What should we do next ? + */ + switch (this_stats->status) { + case ST_NEW_ENTRY: + delete = nscd_true; + next_action = _NSC_NSLOOKUP; + break; + case ST_UPDATE_PENDING: + if (flag & UPDATEBIT) { + (void) mutex_unlock(&nscdb->db_mutex); + return (NOTFOUND); + } else if (this_stats->timestamp < now) + next_action = _NSC_WAIT; + else + next_action = _NSC_USECACHED; + break; + case ST_LOOKUP_PENDING: + if (flag & UPDATEBIT) { + (void) mutex_unlock(&nscdb->db_mutex); + return (NOTFOUND); + } + next_action = _NSC_WAIT; + break; + case ST_DISCARD: + if (cfg.avoid_ns == nscd_true) { + (void) mutex_unlock(&nscdb->db_mutex); + return (NOTFOUND); + } + /* otherwise reuse the entry */ + (void) memset(this_stats, 0, sizeof (*this_stats)); + next_action = _NSC_NSLOOKUP; + break; + default: + if (cfg.avoid_ns == nscd_true) + next_action = _NSC_USECACHED; + else if ((flag & UPDATEBIT) || + (this_stats->timestamp < now)) { + _NSCD_LOG(NSCD_LOG_CACHE, NSCD_LOG_LEVEL_DEBUG) + (me, "%s: cached entry needs to be updated\n", + whoami); + next_action = _NSC_NSLOOKUP; + } else + next_action = _NSC_USECACHED; + break; + } + + if (next_action == _NSC_WAIT) { + _NSCD_LOG(NSCD_LOG_CACHE, NSCD_LOG_LEVEL_DEBUG) + (me, "%s: need to wait\n", whoami); + + /* do we have clearance ? */ + if (_nscd_get_clearance(&ctx->throttle_sema) != 0) { + /* nope. quit */ + (void) mutex_lock(&ctx->stats_mutex); + ctx->stats.drop_count++; + (void) mutex_unlock(&ctx->stats_mutex); + NSC_LOOKUP_RETURN(NOSERVER, WARNING, + "%s: no clearance to wait\n"); + } + /* yes can wait */ + (void) nscd_wait(&ctx->wait, &nscdb->db_mutex, + &this_stats->status); + (void) _nscd_release_clearance(&ctx->throttle_sema); + continue; + } + + break; + } + + + if (!(UPDATEBIT & flag)) + this_stats->hits++; /* update hit count */ + + if (next_action == _NSC_NSLOOKUP) { + + _NSCD_LOG(NSCD_LOG_CACHE, NSCD_LOG_LEVEL_DEBUG) + (me, "%s: name service lookup required\n", whoami); + + if (_nscd_get_clearance(&ctx->throttle_sema) != 0) { + if (delete == nscd_true) + delete_entry(nscdb, ctx, this_entry); + else + this_stats->status = ST_DISCARD; + (void) mutex_lock(&ctx->stats_mutex); + ctx->stats.drop_count++; + (void) mutex_unlock(&ctx->stats_mutex); + NSC_LOOKUP_RETURN(NOSERVER, WARNING, + "%s: no clearance for lookup\n"); + } + + /* block any threads accessing this entry */ + this_stats->status = (flag & UPDATEBIT)? + ST_UPDATE_PENDING:ST_LOOKUP_PENDING; + + /* release lock and do name service lookup */ + (void) mutex_unlock(&nscdb->db_mutex); + nss_psearch(largs->buffer, largs->bufsize); + status = NSCD_GET_STATUS(largs->buffer); + (void) mutex_lock(&nscdb->db_mutex); + this_stats->status = 0; + (void) _nscd_release_clearance(&ctx->throttle_sema); + + /* signal waiting threads */ + (void) nscd_signal(&ctx->wait, &this_stats->status); + + _NSCD_LOG(NSCD_LOG_CACHE, NSCD_LOG_LEVEL_DEBUG) + (me, "%s: name service lookup status = %d\n", + whoami, status); + + if (status == NSS_SUCCESS) { + int ttl; + + /* + * data found in name service + * update cache + */ + status = dup_packed_buffer(largs, this_entry); + if (status != NSS_SUCCESS) { + delete_entry(nscdb, ctx, this_entry); + NSC_LOOKUP_RETURN(SERVERERROR, ERROR, + "%s: failed to update cache\n"); + } + + /* + * store unpacked key in cache + */ + status = nss_packed_getkey(this_entry->buffer, + this_entry->bufsize, + &dbname, &dbop, &args); + if (status != NSS_SUCCESS) { + delete_entry(nscdb, ctx, this_entry); + NSC_LOOKUP_RETURN(SERVERERROR, ERROR, + "%s: failed to extract key\n"); + } + this_entry->key = args.key; /* struct copy */ + + /* update +ve miss count */ + if (!(UPDATEBIT & flag)) { + (void) mutex_lock(&ctx->stats_mutex); + ctx->stats.pos_misses++; + (void) mutex_unlock(&ctx->stats_mutex); + } + + /* update +ve ttl */ + ttl = get_dns_ttl(largs->buffer, dbname); + /* honor the dns ttl less than postive ttl */ + if (ttl < 0 || ttl > cfg.pos_ttl) + ttl = cfg.pos_ttl; + this_stats->timestamp = time(NULL) + ttl; + + /* + * start the revalidation and reaper threads + * if not already started + */ + start_threads(ctx); + + NSC_LOOKUP_RETURN(SUCCESS, DEBUG, + "%s: cache updated with positive entry\n"); + } else if (status == NSS_NOTFOUND) { + /* + * data not found in name service + * update cache + */ + + if (NSCD_GET_ERRNO(largs->buffer) == ERANGE) { + delete_entry(nscdb, ctx, this_entry); + NSC_LOOKUP_RETURN(NOTFOUND, DEBUG, + "%s: ERANGE, cache not updated with negative entry\n"); + } + + status = dup_packed_buffer(largs, this_entry); + if (status != NSS_SUCCESS) { + delete_entry(nscdb, ctx, this_entry); + NSC_LOOKUP_RETURN(SERVERERROR, ERROR, + "%s: failed to update cache\n"); + } + + /* store unpacked key in cache */ + status = nss_packed_getkey(this_entry->buffer, + this_entry->bufsize, + &dbname, &dbop, &args); + if (status != NSS_SUCCESS) { + delete_entry(nscdb, ctx, this_entry); + NSC_LOOKUP_RETURN(SERVERERROR, ERROR, + "%s: failed to extract key\n"); + } + this_entry->key = args.key; /* struct copy */ + + /* update -ve ttl */ + this_stats->timestamp = time(NULL) + cfg.neg_ttl; + + /* update -ve miss count */ + if (!(UPDATEBIT & flag)) { + (void) mutex_lock(&ctx->stats_mutex); + ctx->stats.neg_misses++; + (void) mutex_unlock(&ctx->stats_mutex); + } + + /* + * start the revalidation and reaper threads + * if not already started + */ + start_threads(ctx); + + NSC_LOOKUP_RETURN(NOTFOUND, DEBUG, + "%s: cache updated with negative entry\n"); + } else { + /* + * name service lookup failed + */ + errnum = NSCD_GET_ERRNO(largs->buffer); + if (delete == nscd_true) + delete_entry(nscdb, ctx, this_entry); + else + this_stats->status = ST_DISCARD; + + (void) mutex_unlock(&nscdb->db_mutex); + _NSCD_LOG(NSCD_LOG_CACHE, NSCD_LOG_LEVEL_WARNING) + (me, "%s: name service lookup failed (status=%d, errno=%d)\n", + whoami, status, errnum); + + return (SERVERERROR); + } + } else if (next_action == _NSC_USECACHED) { + /* + * found entry in cache + */ + if (UPDATEBIT & flag) { + NSC_LOOKUP_RETURN(SUCCESS, DEBUG, + "%s: no need to update\n"); + } + + if (NSCD_GET_STATUS((nss_pheader_t *)this_entry->buffer) == + NSS_SUCCESS) { + /* positive hit */ + (void) mutex_lock(&ctx->stats_mutex); + ctx->stats.pos_hits++; + (void) mutex_unlock(&ctx->stats_mutex); + + /* update response buffer */ + if (copy_result(largs->buffer, + this_entry->buffer) != NSS_SUCCESS) { + NSC_LOOKUP_RETURN(SERVERERROR, ERROR, + "%s: response buffer insufficient\n"); + } + + NSC_LOOKUP_RETURN(SUCCESS, DEBUG, + "%s: positive entry in cache\n"); + } else { + /* negative hit */ + (void) mutex_lock(&ctx->stats_mutex); + ctx->stats.neg_hits++; + (void) mutex_unlock(&ctx->stats_mutex); + + NSCD_SET_STATUS((nss_pheader_t *)largs->buffer, + NSCD_GET_STATUS(this_entry->buffer), + NSCD_GET_ERRNO(this_entry->buffer)); + NSCD_SET_HERRNO((nss_pheader_t *)largs->buffer, + NSCD_GET_HERRNO(this_entry->buffer)); + + NSC_LOOKUP_RETURN(NOTFOUND, DEBUG, + "%s: negative entry in cache\n"); + } + } + + NSC_LOOKUP_RETURN(SERVERERROR, ERROR, + "%s: cache backend failure\n"); +} + +/* + * NSCD cache backend lookup function + */ +/*ARGSUSED*/ +void +nsc_lookup(nsc_lookup_args_t *largs, int flag) { + + nss_pheader_t *phdr = (nss_pheader_t *)largs->buffer; + int rc; + + rc = lookup_int(largs, 0); + + if (NSCD_GET_STATUS(phdr) == NSS_TRYLOCAL) + return; + + switch (rc) { + + case SUCCESS: + NSCD_RETURN_STATUS(phdr, NSS_SUCCESS, 0); + break; + + case NOTFOUND: + NSCD_RETURN_STATUS(phdr, NSS_NOTFOUND, -1); + break; + + case SERVERERROR: + /* status and errno already set in the phdr */ + break; + + case NOSERVER: + NSCD_RETURN_STATUS(phdr, NSS_UNAVAIL, -1); + break; + } +} + + +static nsc_ctx_t * +init_cache_ctx(int i) { + nsc_ctx_t *ctx; + + ctx = calloc(1, sizeof (nsc_ctx_t)); + if (ctx == NULL) + return (NULL); + + /* init locks and semaphores */ + (void) mutex_init(&ctx->file_mutex, USYNC_THREAD, NULL); + (void) rwlock_init(&ctx->cfg_rwlp, USYNC_THREAD, NULL); + (void) mutex_init(&ctx->stats_mutex, USYNC_THREAD, NULL); + (void) _nscd_init_cache_sema(&ctx->throttle_sema, cache_name[i]); + cache_init_ctx[i](ctx); + cache_ctx_p[i] = ctx; + + return (ctx); +} + + +static void +revalidate(nsc_ctx_t *ctx) +{ + for (;;) { + int i, slp, interval, count; + + (void) rw_rdlock(&ctx->cfg_rwlp); + slp = ctx->cfg.pos_ttl; + count = ctx->cfg.keephot; + (void) rw_unlock(&ctx->cfg_rwlp); + + if (slp < 60) + slp = 60; + if (count != 0) { + interval = (slp/2)/count; + if (interval == 0) + interval = 1; + (void) sleep(slp*2/3); + for (i = 0; i < ctx->db_count; i++) { + getxy_keepalive(ctx, ctx->nsc_db[i], + count, interval); + } + } else { + (void) sleep(slp); + } + } +} + + +static void +getxy_keepalive(nsc_ctx_t *ctx, nsc_db_t *nscdb, int keep, int interval) +{ + nsc_keephot_t *table; + nsc_entry_t *entry, *ptr; + int i; + nsc_lookup_args_t *largs; + nss_pheader_t *phdr; + int bufsiz; + char *me = "getxy_keepalive"; + + /* we won't be here if keep == 0 so need to check that */ + + _NSCD_LOG(NSCD_LOG_CACHE, NSCD_LOG_LEVEL_DEBUG) + (me, "%s: keep alive\n", nscdb->name); + + if ((table = maken(keep)) == NULL) { + _NSCD_LOG(NSCD_LOG_CACHE, NSCD_LOG_LEVEL_ERROR) + (me, "memory allocation failure\n"); + exit(1); + } + + (void) mutex_lock(&nscdb->db_mutex); + entry = nscdb->qtail; + while (entry != NULL) { + /* leave pending calls alone */ + if (!(entry->stats.status & ST_PENDING)) { + /* do_revalidate */ + (void) insertn(table, entry->stats.hits, + entry); + } + entry = entry->qnext; + } + for (i = 1; i <= keep; i++) { + if (table[i].ptr == NULL) + continue; + ptr = (nsc_entry_t *)table[i].ptr; + phdr = (nss_pheader_t *)ptr->buffer; + if (NSCD_GET_STATUS(phdr) == NSS_SUCCESS) + /* + * for positive cache, in addition to the packed + * header size, allocate twice the size of the + * existing result (in case the result grows + * larger) + */ + bufsiz = phdr->data_off + 2 * phdr->data_len; + else + /* + * for negative cache, allocate 8K buffer to + * hold result in case the next lookup may + * return something (in addition to the + * packed header size) + */ + bufsiz = phdr->data_off + 8096; + table[i].ptr = malloc(bufsiz); + if (table[i].ptr == NULL) { + (void) mutex_unlock(&nscdb->db_mutex); + _NSCD_LOG(NSCD_LOG_CACHE, NSCD_LOG_LEVEL_ERROR) + (me, "memory allocation failure\n"); + exit(1); + } + (void) memcpy(table[i].ptr, ptr->buffer, ptr->bufsize); + ((nss_pheader_t *)table[i].ptr)->pbufsiz = bufsiz; + table[i].num = bufsiz; + } + (void) mutex_unlock(&nscdb->db_mutex); + + /* launch update thread for each keep hot entry */ + for (i = keep; i > 0; i--) { + if (table[i].ptr == NULL) + continue; /* unused slot in table */ + _NSCD_LOG(NSCD_LOG_CACHE, NSCD_LOG_LEVEL_DEBUG) + (me, "%s: launching update\n", nscdb->name); + largs = (nsc_lookup_args_t *)malloc(sizeof (*largs)); + if (largs == NULL) { + _NSCD_LOG(NSCD_LOG_CACHE, NSCD_LOG_LEVEL_ERROR) + (me, "memory allocation failure\n"); + exit(1); + } + largs->buffer = table[i].ptr; + largs->bufsize = table[i].num; + largs->ctx = ctx; + largs->nscdb = nscdb; + if (launch_update(largs) < 0) + exit(1); + (void) sleep(interval); + } + + /* + * The update thread will handle freeing of buffer and largs. + * Free the table here. + */ + free(table); +} + + +static int +launch_update(nsc_lookup_args_t *in) +{ + char *me = "launch_update"; + int errnum; + + errnum = thr_create(NULL, NULL, (void *(*)(void*))do_update, + in, 0|THR_DETACHED, NULL); + if (errnum != 0) { + _NSCD_LOG(NSCD_LOG_CACHE, NSCD_LOG_LEVEL_ERROR) + (me, "%s: thread creation failure (%d)\n", + in->nscdb->name, errnum); + return (-1); + } + return (0); +} + + +static void +do_update(nsc_lookup_args_t *in) { + nss_pheader_t *phdr = (nss_pheader_t *)in->buffer; + + /* update the length of the data buffer */ + phdr->data_len = phdr->pbufsiz - phdr->data_off; + + (void) lookup_int(in, UPDATEBIT); + if (in->buffer) + free(in->buffer); + free(in); +} + + +/* + * Invalidate cache + */ +void +nsc_invalidate(nsc_ctx_t *ctx, char *dbname, nsc_ctx_t **ctxs) { + int i; + char *me = "nsc_invalidate"; + + if (ctx) { + ctx_invalidate(ctx); + return; + } + + if (dbname) { + if ((i = get_cache_idx(dbname)) == -1) { + _NSCD_LOG(NSCD_LOG_CACHE, + NSCD_LOG_LEVEL_WARNING) + (me, "%s: invalid cache name\n", dbname); + return; + } + if ((ctx = cache_ctx_p[i]) == NULL) { + _NSCD_LOG(NSCD_LOG_CACHE, + NSCD_LOG_LEVEL_WARNING) + (me, "%s: no cache context found\n", + dbname); + return; + } + ctx_invalidate(ctx); + return; + } + + if (ctxs == NULL) + ctxs = cache_ctx_p; + + for (i = 0; i < CACHE_CTX_COUNT; i++) { + if (ctxs[i] != NULL) + ctx_invalidate(ctxs[i]); + } +} + + +/* + * Invalidate cache by context + */ +static void +ctx_invalidate(nsc_ctx_t *ctx) { + int i; + nsc_entry_t *entry; + char *me = "ctx_invalidate"; + + _NSCD_LOG(NSCD_LOG_CACHE, NSCD_LOG_LEVEL_DEBUG) + (me, "%s: invalidate cache\n", ctx->dbname); + + for (i = 0; i < ctx->db_count; i++) { + if (ctx->nsc_db[i] == NULL) + continue; + (void) mutex_lock(&ctx->nsc_db[i]->db_mutex); + entry = ctx->nsc_db[i]->qtail; + while (entry != NULL) { + /* leave pending calls alone */ + if (!(entry->stats.status & ST_PENDING)) + entry->stats.status = ST_DISCARD; + entry = entry->qnext; + } + (void) mutex_unlock(&ctx->nsc_db[i]->db_mutex); + } + + (void) mutex_lock(&ctx->stats_mutex); + ctx->stats.invalidate_count++; + (void) mutex_unlock(&ctx->stats_mutex); +} + + +/* + * Free nsc_entry_t + * + * Pre-reqs: + * nscdb->db_mutex lock must be held before calling this function + */ +static void +delete_entry(nsc_db_t *nscdb, nsc_ctx_t *ctx, nsc_entry_t *entry) { + uint_t hash; + + avl_remove(&nscdb->tree, entry); + HASH_REMOVE(nscdb, entry, hash, nscd_false); + queue_remove(nscdb, entry); + if (entry->buffer != NULL) { + free(entry->buffer); + entry->buffer = NULL; + } + umem_cache_free(nsc_entry_cache, entry); + (void) mutex_lock(&ctx->stats_mutex); + ctx->stats.entries--; + (void) mutex_unlock(&ctx->stats_mutex); +} + + +static nscd_rc_t +lookup_cache(nsc_lookup_args_t *largs, nscd_cfg_cache_t *cfgp, + nss_XbyY_args_t *argp, char *whoami, nsc_entry_t **entry) { + + nsc_db_t *nscdb; + nsc_ctx_t *ctx; + uint_t hash; + avl_index_t pos; + ulong_t nentries; + nsc_entry_t find_entry, *node; + char *me = "lookup_cache"; + + ctx = largs->ctx; + nscdb = largs->nscdb; + + /* set the search key */ + find_entry.key = argp->key; /* struct copy (not deep) */ + + /* lookup the hash table ==> O(1) */ + if (nscdb->htable) { + *entry = hash_find(nscdb, &find_entry, &hash, nscd_true); + if (*entry != NULL) { + (void) queue_adjust(nscdb, *entry); + return (NSCD_SUCCESS); + } + } + + /* if not found, lookup the AVL tree ==> O(log n) */ + *entry = (nsc_entry_t *)avl_find(&nscdb->tree, &find_entry, &pos); + if (*entry != NULL) { + (void) queue_adjust(nscdb, *entry); + /* move it to the hash table */ + if (nscdb->htable) { + if (nscdb->htable[hash] == NULL || + (*entry)->stats.hits >= + nscdb->htable[hash]->stats.hits) { + nscdb->htable[hash] = *entry; + } + } + return (NSCD_SUCCESS); + } + + /* entry not found in the cache */ + _NSCD_LOG(NSCD_LOG_CACHE, NSCD_LOG_LEVEL_DEBUG) + (me, "%s: cache miss\n", whoami); + + if (cfgp->avoid_ns == nscd_true) { + _NSCD_LOG(NSCD_LOG_CACHE, + NSCD_LOG_LEVEL_DEBUG) + (me, "%s: avoid name service\n", whoami); + return (NSCD_DB_ENTRY_NOT_FOUND); + } + + /* allocate memory for new entry (stub) */ + *entry = (nsc_entry_t *)umem_cache_alloc(nsc_entry_cache, + UMEM_DEFAULT); + if (*entry == NULL) { + _NSCD_LOG(NSCD_LOG_CACHE, + NSCD_LOG_LEVEL_ERROR) + (me, "%s: memory allocation failure\n", whoami); + return (NSCD_NO_MEMORY); + } + (void) memset(*entry, 0, sizeof (**entry)); + + /* + * Note that the actual data for the key is stored within + * the largs->buffer (input buffer to nsc_lookup). + * find_entry.key only contains pointers to this data. + * + * If largs->buffer will be re-allocated by nss_psearch + * then (*entry)->key will have dangling pointers. + * In such case, the following assignment needs to be + * replaced by code that duplicates the key. + */ + (*entry)->key = find_entry.key; + + /* + * Add the entry to the cache. + */ + avl_insert(&nscdb->tree, *entry, pos); /* O(log n) */ + (void) queue_adjust(nscdb, *entry); /* constant */ + if (nscdb->htable) /* constant */ + nscdb->htable[hash] = *entry; + (*entry)->stats.status = ST_NEW_ENTRY; + + (void) mutex_lock(&ctx->stats_mutex); + nentries = ++(ctx->stats.entries); + (void) mutex_unlock(&ctx->stats_mutex); + + /* Have we exceeded max entries ? */ + if (cfgp->maxentries > 0 && nentries > cfgp->maxentries) { + _NSCD_LOG(NSCD_LOG_CACHE, NSCD_LOG_LEVEL_DEBUG) + (me, "%s: maximum entries exceeded -- " + "deleting least recently used entry\n", + whoami); + + node = nscdb->qhead; + while (node != NULL && node != *entry) { + if (node->stats.status == ST_DISCARD || + !(node->stats.status & ST_PENDING)) { + delete_entry(nscdb, ctx, node); + break; + } + node = node->qprev; + } + + /* + * It's okay if we were not able to find one to delete. + * The reaper (when invoked) will return the cache to a + * safe level. + */ + } + + return (NSCD_SUCCESS); +} + +static void +reaper(nsc_ctx_t *ctx) { + uint_t ttl, extra_sleep, total_sleep, intervals; + uint_t nodes_per_interval, seconds_per_interval; + ulong_t nsc_entries; + char *me = "reaper"; + + for (;;) { + (void) mutex_lock(&ctx->stats_mutex); + nsc_entries = ctx->stats.entries; + (void) mutex_unlock(&ctx->stats_mutex); + + (void) rw_rdlock(&ctx->cfg_rwlp); + ttl = ctx->cfg.pos_ttl; + (void) rw_unlock(&ctx->cfg_rwlp); + + if (nsc_entries == 0) { + _NSCD_LOG(NSCD_LOG_CACHE, NSCD_LOG_LEVEL_DEBUG) + (me, "%s: nothing to reap\n", ctx->dbname); + + /* sleep for atleast 60 seconds */ + if (ttl < 60) + ttl = 60; + _NSCD_LOG(NSCD_LOG_CACHE, NSCD_LOG_LEVEL_DEBUG) + (me, "%s: sleep %d\n", ctx->dbname, ttl); + (void) sleep(ttl); + continue; + } + + if (ttl < 32) ttl = 32; + if (ttl > (1<<28)) ttl = 1<<28; + + /* + * minimum nodes_per_interval = 256 or 1<<8 + * maximum nodes_per_interval = nsc_entries + * minimum seconds_per_interval = 32 or 1<<5 + * maximum_seconds_per_interval = ttl + */ + if (nsc_entries <= ttl) { + intervals = (nsc_entries >> 8) + 1; + seconds_per_interval = ttl / intervals; + nodes_per_interval = 256; + } else { + intervals = (ttl >> 5) + 1; + seconds_per_interval = 32; + nodes_per_interval = nsc_entries / intervals; + if (nodes_per_interval < 256) + nodes_per_interval = 256; + } + + _NSCD_LOG(NSCD_LOG_CACHE, NSCD_LOG_LEVEL_DEBUG) + (me, "%s: total entries = %d, " + "seconds per interval = %d, " + "nodes per interval = %d\n", + ctx->dbname, nsc_entries, seconds_per_interval, + nodes_per_interval); + total_sleep = reap_cache(ctx, nodes_per_interval, + seconds_per_interval); + extra_sleep = 1 + ttl - total_sleep; + if (extra_sleep > 0) + (void) sleep(extra_sleep); + } +} + + +static uint_t +reap_cache(nsc_ctx_t *ctx, uint_t nodes_per_interval, + uint_t seconds_per_interval) { + uint_t nodes_togo, total_sleep; + time_t now; + nsc_entry_t *node, *next_node; + nsc_db_t *nscdb; + uint_t primes[] = {_NSC_HTSIZE_PRIMES}; + ulong_t count, nentries, maxentries; + int i, slot, value, newhtsize; + char *me = "reap_cache"; + + count = 0; + total_sleep = 0; + nodes_togo = nodes_per_interval; + now = time(NULL); + + for (i = 0; i < ctx->db_count; i++) { + nscdb = ctx->nsc_db[i]; + (void) mutex_lock(&nscdb->db_mutex); + nscdb->reap_node = nscdb->qtail; + while (nscdb->reap_node != NULL) { + if (nodes_togo == 0) { + (void) mutex_unlock(&nscdb->db_mutex); + (void) sleep(seconds_per_interval); + total_sleep += seconds_per_interval; + nodes_togo = nodes_per_interval; + now = time(NULL); + (void) mutex_lock(&nscdb->db_mutex); + } + /* delete ST_DISCARD and expired nodes */ + if ((node = nscdb->reap_node) == NULL) + break; + if (node->stats.status == ST_DISCARD || + (!(node->stats.status & ST_PENDING) && + node->stats.timestamp < now)) { + /* + * Delete entry if its discard flag is + * set OR if it has expired. Entries + * with pending updates are not + * deleted. + * nscdb->reap_node will be adjusted + * by delete_entry() + */ + delete_entry(nscdb, ctx, node); + count++; + } else { + nscdb->reap_node = node->qnext; + } + nodes_togo--; + } + + if (nscdb->htsize == 0) { + (void) mutex_unlock(&nscdb->db_mutex); + continue; + } + + /* + * Dynamic adjustment of hash table size. + * + * Hash table size is roughly 1/8th of the + * total entries. However the size is changed + * only when the number of entries double or + * reduced by half + */ + nentries = avl_numnodes(&nscdb->tree); + for (slot = 0, value = _NSC_INIT_HTSIZE_SLOT_VALUE; + slot < _NSC_HTSIZE_NUM_SLOTS && nentries > value; + value = (value << 1) + 1, slot++); + if (nscdb->hash_type == nsc_ht_power2) + newhtsize = _NSC_INIT_HTSIZE_POWER2 << slot; + else + newhtsize = primes[slot]; + + /* Recommended size is same as the current size. Done */ + if (nscdb->htsize == newhtsize) { + (void) mutex_unlock(&nscdb->db_mutex); + continue; + } + + _NSCD_LOG(NSCD_LOG_CACHE, NSCD_LOG_LEVEL_DEBUG) + (me, "%s: resizing hash table from %d to %d\n", + nscdb->name, nscdb->htsize, newhtsize); + + /* + * Dump old hashes because it would be time + * consuming to rehash them. + */ + (void) free(nscdb->htable); + nscdb->htable = calloc(newhtsize, sizeof (*(nscdb->htable))); + if (nscdb->htable == NULL) { + _NSCD_LOG(NSCD_LOG_CACHE, NSCD_LOG_LEVEL_ERROR) + (me, + "%s: memory allocation failure\n", + nscdb->name); + /* -1 to try later */ + nscdb->htsize = -1; + } else { + nscdb->htsize = newhtsize; + } + (void) mutex_unlock(&nscdb->db_mutex); + } + + _NSCD_LOG(NSCD_LOG_CACHE, NSCD_LOG_LEVEL_DEBUG) + (me, "%s: reaped %lu entries\n", ctx->dbname, count); + + /* + * if cache is almost full then reduce it to a safe level by + * evicting LRU entries + */ + + (void) rw_rdlock(&ctx->cfg_rwlp); + maxentries = ctx->cfg.maxentries; + (void) rw_unlock(&ctx->cfg_rwlp); + + /* No limit on number of entries. Done */ + if (maxentries == 0) + goto out; + + (void) mutex_lock(&ctx->stats_mutex); + nentries = ctx->stats.entries; + (void) mutex_unlock(&ctx->stats_mutex); + + /* what is the percentage of cache used ? */ + value = (nentries * 100) / maxentries; + if (value < _NSC_EVICTION_START_LEVEL) + goto out; + + /* + * cache needs to be reduced to a safe level + */ + value -= _NSC_EVICTION_SAFE_LEVEL; + for (i = 0, count = 0; i < ctx->db_count; i++) { + /* + * Reduce each subcache by 'value' percent + */ + nscdb = ctx->nsc_db[i]; + (void) mutex_lock(&nscdb->db_mutex); + nodes_togo = (value * avl_numnodes(&nscdb->tree)) / 100; + + /* Start from LRU entry i.e queue head */ + next_node = nscdb->qhead; + while (nodes_togo > 0 && next_node != NULL) { + node = next_node; + next_node = next_node->qprev; + if (node->stats.status == ST_DISCARD || + !(node->stats.status & ST_PENDING)) { + /* Leave nodes with pending updates alone */ + delete_entry(nscdb, ctx, node); + count++; + nodes_togo--; + } + } + (void) mutex_unlock(&nscdb->db_mutex); + } + + _NSCD_LOG(NSCD_LOG_CACHE, NSCD_LOG_LEVEL_DEBUG) + (me, "%s: evicted %lu LRU entries\n", ctx->dbname, count); + +out: + return (total_sleep); +} diff --git a/usr/src/cmd/nscd/cache.h b/usr/src/cmd/nscd/cache.h new file mode 100644 index 0000000000..088e8e1512 --- /dev/null +++ b/usr/src/cmd/nscd/cache.h @@ -0,0 +1,372 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _NSCD_H +#define _NSCD_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * This is a private header file. Applications should not directly include + * this file. + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#include <sys/avl.h> +#include <thread.h> +#include <synch.h> +#include <nss_dbdefs.h> +#include "getxby_door.h" +#include "nscd_common.h" +#include "nscd_config.h" + +/* + * OR'D in by server to call self for updates + */ +#define UPDATEBIT (1<<30) +#define MASKUPDATEBIT(a) ((~UPDATEBIT)&(a)) + +/* + * debug levels + */ +#define DBG_OFF 0 +#define DBG_CANT_FIND 2 +#define DBG_NETLOOKUPS 4 +#define DBG_ALL 6 + +/* + * Max size name we allow to be passed to avoid + * buffer overflow problems + */ +#define NSCDMAXNAMELEN 255 + +/* + * cached entry status + */ +#define ST_UPDATE_PENDING 0x1 +#define ST_LOOKUP_PENDING 0x2 +#define ST_PENDING (ST_LOOKUP_PENDING | ST_UPDATE_PENDING) +#define ST_NEW_ENTRY 0x4 +#define ST_DISCARD 0x8 + +/* + * Cache eviction start and stop levels + */ +#define _NSC_EVICTION_START_LEVEL 90 +#define _NSC_EVICTION_SAFE_LEVEL 80 + +/* + * other internal constants + */ +#define _NSC_MAX_DB 2 +#define _NSC_PUBLIC_ACCESS -1 +#define _NSC_FILE_CHECK_TIME 0 /* check always for backwards compat */ + +/* + * Macros used for logging purposes + */ +#define yes_no(flag) (flag == nscd_true)?"yes":"no" +#define check_null(str) (str)?str:"<null>" + +/* + * Macros used by compare routines + */ +#define _NSC_INT_KEY_CMP(n1, n2) \ + (n1 > n2)?1:((n1 == n2)?0:-1) + +#define _NSC_GET_HITRATE(sp) \ + sp->hitrate = sp->pos_misses + sp->neg_misses + \ + sp->pos_hits + sp->neg_hits; \ + if (sp->hitrate > 0.0) \ + sp->hitrate = (100.0 * \ + ((double)sp->pos_hits + \ + (double)sp->neg_hits)) / sp->hitrate; + +/* + * nsc_lookup action + */ +typedef enum { + _NSC_NSLOOKUP = 0, + _NSC_WAIT, + _NSC_USECACHED +} nsc_action_t; + +/* + * Structure to handle waiting for pending name service requests + */ +typedef struct waiter { + cond_t w_waitcv; + uint8_t *w_key; + struct waiter *w_next, *w_prev; +} waiter_t; + +/* + * What each entry in the nameserver cache looks like. + */ + +typedef struct nsc_entry_stat { + uint_t hits; /* number of hits */ + uint8_t status; /* activity status */ + time_t timestamp; /* expiry time */ + int refcount; /* reference count */ +} nsc_entry_stat_t; + +typedef struct nsc_entry { + avl_node_t avl_link; /* libavl requirement */ + struct nsc_entry *qnext; /* next on pqueue */ + struct nsc_entry *qprev; /* prev on pqueue */ + nsc_entry_stat_t stats; /* entry's statistics */ + nss_XbyY_key_t key; /* entry's key */ + void *buffer; /* data buffer */ + size_t bufsize; /* data buffer length */ +} nsc_entry_t; + +typedef struct nsc_keephot { + void *ptr; + uint_t num; +} nsc_keephot_t; + +/* + * Macros used by hash table + * + * _NSC_HTSIZE_PRIMES are prime numbers that are used as hash table + * sizes when hash table type is nsc_ht_prime. For hash tables of + * type nsc_ht_power2, the size is automatically calculated. + * Number of primes listed below is _NSC_HTSIZE_NUM_SLOTS + 1. + * Each number (except the first) is a prime closest to a + * power of 2 in increasing order. Ex: 509 is the closest prime to + * 512 (2**9), 1021 is closest to 1024 (2**10), and so on. + * The first prime is chosen as 211 for historical reasons. + */ +#define _NSC_INIT_HTSIZE_PRIME 211 +#define _NSC_INIT_HTSIZE_POWER2 256 +#define _NSC_INIT_HTSIZE_SLOT_VALUE 2896 +#define _NSC_HTSIZE_NUM_SLOTS 10 +#define _NSC_HTSIZE_PRIMES 211, 509, 1021, 2053, 4099, 8191, \ + 16381, 32771, 65537, 131071, 262147 + +#define _NSC_DB_CES_KEY(ptr) \ + ((ptr)->db_type == nsc_key_ces) +#define _NSC_DB_CIS_KEY(ptr) \ + ((ptr)->db_type == nsc_key_cis) +#define _NSC_DB_STR_KEY(ptr) \ + _NSC_DB_CES_KEY(ptr) || _NSC_DB_CIS_KEY(ptr) +#define _NSC_DB_INT_KEY(ptr) \ + ((ptr)->db_type == nsc_key_int) + +/* + * cache backend param group (global) + */ +#define NSCD_CFG_GROUP_INFO_GLOBAL_CACHE {1, 0x0001} +typedef struct nscd_cfg_global_cache { + nscd_cfg_group_info_t gi; /* config requirement */ + nscd_bool_t enable; +} nscd_cfg_global_cache_t; + +#define NSCD_CFG_GLOBAL_CACHE_DEFAULTS \ + { NSCD_CFG_GROUP_INFO_GLOBAL_CACHE, nscd_true } + +/* + * cache backend param group (per database) + */ +#define NSCD_CFG_GROUP_INFO_CACHE {12, 0x0fff} +typedef struct nscd_cfg_cache { + nscd_cfg_group_info_t gi; /* config requirement */ + nscd_bool_t enable; /* if false return NOSERVER */ + nscd_bool_t per_user; /* if true per user access */ + nscd_bool_t avoid_ns; /* if true avoid name service */ + nscd_bool_t check_files; /* if true check file */ + int check_interval; /* check interval */ + int pos_ttl; /* time to live for +ve entries */ + int neg_ttl; /* time to live for -ve entries */ + int keephot; /* keep hot count */ + int hint_size; /* size to return for a GETHINTS */ + ulong_t maxentries; /* maximum entries allowed */ + int suggestedsize; /* obsolete */ + nscd_bool_t old_data_ok; /* obsolete */ +} nscd_cfg_cache_t; + +#define NSCD_CFG_CACHE_DEFAULTS \ + { \ + NSCD_CFG_GROUP_INFO_CACHE, \ + nscd_true, nscd_false, nscd_false, nscd_true, \ + _NSC_FILE_CHECK_TIME, 600, 10, 0, 1 << 11, 0, \ + 0, nscd_false \ + } + +/* + * cache backend stat group (per database) + */ +#define NSCD_CFG_STAT_GROUP_INFO_CACHE {9, 0x01ff} +typedef struct nscd_cfg_stat_cache { + nscd_cfg_group_info_t gi; /* config requirement */ + ulong_t pos_hits; /* hits on +ve entries */ + ulong_t neg_hits; /* hits on -ve entries */ + ulong_t pos_misses; /* misses on +ve entries */ + ulong_t neg_misses; /* misses on -ve entries */ + ulong_t entries; /* count of cache entries */ + ulong_t drop_count; /* cache queries dropped */ + ulong_t wait_count; /* cache queries queued */ + ulong_t invalidate_count; /* count for cache invalidation */ + double hitrate; /* computed from other fields */ +} nscd_cfg_stat_cache_t; + +typedef struct nsc_db { + /* + * Data + */ + avl_tree_t tree; + nsc_entry_t **htable; + nsc_entry_t *qhead; + nsc_entry_t *qtail; + nsc_entry_t *reap_node; + int callnumber; + int dbop; + char *name; + mutex_t db_mutex; + int htsize; + enum hash_type { + nsc_ht_default = 0, + nsc_ht_prime = 1, + nsc_ht_power2 = 2 + } hash_type; + enum db_type { + nsc_key_ces = 0, + nsc_key_cis = 1, + nsc_key_int = 2, + nsc_key_other = 3 + } db_type; + /* + * Methods + */ + uint_t (*gethash)(nss_XbyY_key_t *, int); + int (*compar)(const void *, const void *); + void (*getlogstr)(char *, char *, size_t, nss_XbyY_args_t *); + /* + * Config + */ + nscd_cfg_cache_t cfg; + time_t cfg_mtime; +} nsc_db_t; + + +typedef struct nsc_ctx { + char *dbname; /* cache name */ + nscd_cfg_stat_cache_t stats; /* statistics */ + nscd_cfg_cache_t cfg; /* configs */ + time_t cfg_mtime; /* config last modified time */ + rwlock_t cfg_rwlp; /* config rwlock */ + mutex_t stats_mutex; /* stats mutex */ + mutex_t file_mutex; /* file mutex */ + time_t file_mtime; /* file last modified time */ + time_t file_chktime; /* file last checked time */ + off_t file_size; /* file size at last check */ + ino_t file_ino; /* file inode at last check */ + const char *file_name; /* filename for check_files */ + int db_count; /* number of caches */ + nsc_db_t *nsc_db[_NSC_MAX_DB]; /* caches */ + waiter_t wait; /* lookup wait CV */ + sema_t throttle_sema; /* throttle lookups */ + sema_t revalidate_sema; /* revalidation threads */ + nscd_bool_t revalidate_on; /* reval. thread started */ + nscd_bool_t reaper_on; /* reaper thread started */ +} nsc_ctx_t; + +typedef struct nsc_lookup_args { + nsc_ctx_t *ctx; + nsc_db_t *nscdb; + void *buffer; + size_t bufsize; +} nsc_lookup_args_t; + +#define CACHE_CTX_COUNT 20 + +/* Context initialization */ +extern void passwd_init_ctx(nsc_ctx_t *); +extern void group_init_ctx(nsc_ctx_t *); +extern void host_init_ctx(nsc_ctx_t *); +extern void ipnode_init_ctx(nsc_ctx_t *); +extern void exec_init_ctx(nsc_ctx_t *); +extern void prof_init_ctx(nsc_ctx_t *); +extern void user_init_ctx(nsc_ctx_t *); +extern void ether_init_ctx(nsc_ctx_t *); +extern void rpc_init_ctx(nsc_ctx_t *); +extern void proto_init_ctx(nsc_ctx_t *); +extern void net_init_ctx(nsc_ctx_t *); +extern void bootp_init_ctx(nsc_ctx_t *); +extern void auuser_init_ctx(nsc_ctx_t *); +extern void auth_init_ctx(nsc_ctx_t *); +extern void serv_init_ctx(nsc_ctx_t *); +extern void netmask_init_ctx(nsc_ctx_t *); +extern void printer_init_ctx(nsc_ctx_t *); +extern void project_init_ctx(nsc_ctx_t *); +extern void tnrhtp_init_ctx(nsc_ctx_t *); +extern void tnrhdb_init_ctx(nsc_ctx_t *); + +/* Functions used to throttle threads */ +extern int nscd_wait(waiter_t *, mutex_t *, uint8_t *); +extern int nscd_signal(waiter_t *, uint8_t *); + +/* Cache creation and initialization */ +extern nscd_rc_t init_cache(); +extern nsc_db_t *make_cache(enum db_type, int, char *, + int (*compar) (const void *, const void *), + void (*getlogstr)(char *, char *, size_t, nss_XbyY_args_t *), + uint_t (*gethash)(nss_XbyY_key_t *, int), + enum hash_type, int); + +/* Cache backend lookup */ +extern void nsc_lookup(nsc_lookup_args_t *, int); + +/* Cache backend info */ +extern void nsc_info(nsc_ctx_t *, char *, nscd_cfg_cache_t cfg[], + nscd_cfg_stat_cache_t stats[]); +#ifdef NSCD_DEBUG +extern int nsc_dump(char *, int); +#endif /* NSCD_DEBUG */ + +/* Cache invalidate */ +extern void nsc_invalidate(nsc_ctx_t *, char *, nsc_ctx_t **); + +/* Keep hot functions */ +extern nsc_keephot_t *maken(int); +extern void *insertn(nsc_keephot_t *, uint_t, void *); + +/* hash related routines */ +extern uint_t cis_gethash(const char *, int); +extern uint_t ces_gethash(const char *, int); +extern uint_t db_gethash(const void *, int, int); + +extern void leave(int n); +extern int get_cache_idx(char *); + +#ifdef __cplusplus +} +#endif + +#endif /* _NSCD_H */ diff --git a/usr/src/cmd/nscd/attrstr.c b/usr/src/cmd/nscd/getauth.c index 1d4f162458..2a8ec60082 100644 --- a/usr/src/cmd/nscd/attrstr.c +++ b/usr/src/cmd/nscd/getauth.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,22 +19,28 @@ * CDDL HEADER END */ /* - * Copyright (c) 1999 by Sun Microsystems, Inc. - * All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. */ #pragma ident "%Z%%M% %I% %E% SMI" -#include <strings.h> +/* + * Routines to handle getauth* calls in nscd + */ -int -attr_strlen(char *s) -{ - return (s ? strlen(s) : 0); -} +#include "cache.h" + +#define nam_db ctx->nsc_db[0] +#define NSC_NAME_AUTHATTR_BYNAME "getauthnam" -char * -attr_strcpy(char *dest, char *src) -{ - return (strcpy(dest, src ? src : "")); +void +auth_init_ctx(nsc_ctx_t *ctx) { + ctx->dbname = NSS_DBNAM_AUTHATTR; + ctx->file_name = "/etc/security/auth_attr"; + ctx->db_count = 1; + nam_db = make_cache(nsc_key_ces, + NSS_DBOP_AUTHATTR_BYNAME, + NSC_NAME_AUTHATTR_BYNAME, + NULL, NULL, NULL, nsc_ht_default, -1); } diff --git a/usr/src/cmd/nscd/getauuser.c b/usr/src/cmd/nscd/getauuser.c new file mode 100644 index 0000000000..267bda6238 --- /dev/null +++ b/usr/src/cmd/nscd/getauuser.c @@ -0,0 +1,46 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * Routines to handle getauuser* calls in nscd + */ + +#include "cache.h" + +#define nam_db ctx->nsc_db[0] +#define NSC_NAME_AUDITUSER_BYNAME "getauusernam" + +void +auuser_init_ctx(nsc_ctx_t *ctx) { + ctx->dbname = NSS_DBNAM_AUDITUSER; + ctx->file_name = "/etc/security/audit_user"; + ctx->db_count = 1; + nam_db = make_cache(nsc_key_ces, + NSS_DBOP_AUDITUSER_BYNAME, + NSC_NAME_AUDITUSER_BYNAME, + NULL, NULL, NULL, nsc_ht_default, -1); +} diff --git a/usr/src/cmd/nscd/getbootp.c b/usr/src/cmd/nscd/getbootp.c new file mode 100644 index 0000000000..6ee9b14273 --- /dev/null +++ b/usr/src/cmd/nscd/getbootp.c @@ -0,0 +1,46 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * Routines to handle bootparams* calls in nscd + */ + +#include "cache.h" + +#define nam_db ctx->nsc_db[0] +#define NSC_NAME_BOOTPARAMS_BYNAME "bootparams" + +void +bootp_init_ctx(nsc_ctx_t *ctx) { + ctx->dbname = NSS_DBNAM_BOOTPARAMS; + ctx->file_name = "/etc/bootparams"; + ctx->db_count = 1; + nam_db = make_cache(nsc_key_cis, + NSS_DBOP_BOOTPARAMS_BYNAME, + NSC_NAME_BOOTPARAMS_BYNAME, + NULL, NULL, NULL, nsc_ht_default, -1); +} diff --git a/usr/src/cmd/nscd/getether.c b/usr/src/cmd/nscd/getether.c new file mode 100644 index 0000000000..ec5ff516c9 --- /dev/null +++ b/usr/src/cmd/nscd/getether.c @@ -0,0 +1,97 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * Routines to handle ether_*to* calls in nscd + */ + +#include <stdlib.h> +#include <net/if.h> +#include <netinet/in.h> +#include <netinet/if_ether.h> +#include <string.h> +#include "cache.h" + +#define host_db ctx->nsc_db[0] +#define addr_db ctx->nsc_db[1] + +#define NSC_NAME_ETHERS_HOSTTON "ether_hostton" +#define NSC_NAME_ETHERS_NTOHOST "ether_ntohost" + +static void ether_getlogstr(char *, char *, size_t, nss_XbyY_args_t *); +static int ether_compar(const void *, const void *); +static uint_t ether_gethash(nss_XbyY_key_t *, int); + +void +ether_init_ctx(nsc_ctx_t *ctx) { + ctx->dbname = NSS_DBNAM_ETHERS; + ctx->file_name = "/etc/ethers"; + ctx->db_count = 2; + host_db = make_cache(nsc_key_cis, + NSS_DBOP_ETHERS_HOSTTON, + NSC_NAME_ETHERS_HOSTTON, + NULL, NULL, NULL, nsc_ht_default, -1); + + addr_db = make_cache(nsc_key_other, + NSS_DBOP_ETHERS_NTOHOST, + NSC_NAME_ETHERS_NTOHOST, + ether_compar, + ether_getlogstr, + ether_gethash, nsc_ht_default, -1); +} + +static int +ether_compar(const void *n1, const void *n2) { + nsc_entry_t *e1, *e2; + int res; + + e1 = (nsc_entry_t *)n1; + e2 = (nsc_entry_t *)n2; + if (ether_cmp(e1->key.ether, e2->key.ether) != 0) { + res = memcmp(e1->key.ether, e2->key.ether, + sizeof (struct ether_addr)); + return (_NSC_INT_KEY_CMP(res, 0)); + } + return (0); +} + +static uint_t +ether_gethash(nss_XbyY_key_t *key, int htsize) { + return (db_gethash(key->ether, sizeof (struct ether_addr), + htsize)); +} + +static void +ether_getlogstr(char *name, char *whoami, size_t len, nss_XbyY_args_t *argp) { + struct ether_addr *e; + e = (struct ether_addr *)argp->key.ether; + (void) snprintf(whoami, len, "%s [key=%x:%x:%x:%x:%x:%x]", + name, + e->ether_addr_octet[0], e->ether_addr_octet[1], + e->ether_addr_octet[2], e->ether_addr_octet[3], + e->ether_addr_octet[4], e->ether_addr_octet[5]); +} diff --git a/usr/src/cmd/nscd/getexec.c b/usr/src/cmd/nscd/getexec.c index 8abb15723e..0de0cd44cb 100644 --- a/usr/src/cmd/nscd/getexec.c +++ b/usr/src/cmd/nscd/getexec.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -30,504 +29,101 @@ * Routines to handle getexec* calls in nscd */ -#include <assert.h> -#include <errno.h> -#include <memory.h> -#include <signal.h> -#include <stdio.h> -#include <stdlib.h> #include <string.h> -#include <sys/door.h> -#include <sys/stat.h> -#include <sys/time.h> -#include <sys/types.h> -#include <sys/wait.h> -#include <thread.h> -#include <unistd.h> -#include <ucred.h> -#include <nss_common.h> -#include <nss_dbdefs.h> - #include <exec_attr.h> +#include "cache.h" -#include <getxby_door.h> -#include "server_door.h" -#include "nscd.h" - -extern execstr_t *_getexecprof(char *, char *, char *, int, execstr_t *, - char *, int, int *); - -static hash_t *nam_hash; -static mutex_t db_lock = DEFAULTMUTEX; -static waiter_t db_wait; - -static int getexec_namekeepalive(int keep, int interval); -static int update_exec_bucket(nsc_bucket_t **old, nsc_bucket_t *new, - int callnumber); -static nsc_bucket_t *fixbuffer(nsc_return_t *in, int maxlen); -static void do_findgnams(nsc_bucket_t *ptr, int *table, char *gnam); -static void do_invalidate(nsc_bucket_t **ptr, int callnumber); -static void getexec_invalidate_unlocked(void); +static int execattr_compar(const void *, const void *); +static uint_t execattr_gethash(nss_XbyY_key_t *, int); +static void execattr_getlogstr(char *, char *, size_t, nss_XbyY_args_t *); +#define nam_db ctx->nsc_db[0] +#define id_db ctx->nsc_db[1] +#define nam_id_db ctx->nsc_db[2] +#define NSC_NAME_EXECATTR_BYNAME "execattr_byname" +#define NSC_NAME_EXECATTR_BYID "execattr_byid" +#define NSC_NAME_EXECATTR_BYNAMEID "execattr_bynameid" void -getexec_init(void) -{ - nam_hash = make_hash(current_admin.exec.nsc_suggestedsize); +exec_init_ctx(nsc_ctx_t *ctx) { + ctx->dbname = NSS_DBNAM_EXECATTR; + ctx->file_name = "/etc/security/exec_attr"; + ctx->db_count = 3; + nam_db = make_cache(nsc_key_other, + NSS_DBOP_EXECATTR_BYNAME, + NSC_NAME_EXECATTR_BYNAME, + execattr_compar, + execattr_getlogstr, + execattr_gethash, nsc_ht_default, -1); + id_db = make_cache(nsc_key_other, + NSS_DBOP_EXECATTR_BYID, + NSC_NAME_EXECATTR_BYID, + execattr_compar, + execattr_getlogstr, + execattr_gethash, nsc_ht_default, -1); + nam_id_db = make_cache(nsc_key_other, + NSS_DBOP_EXECATTR_BYNAMEID, + NSC_NAME_EXECATTR_BYNAMEID, + execattr_compar, + execattr_getlogstr, + execattr_gethash, nsc_ht_default, -1); } -static void -do_invalidate(nsc_bucket_t ** ptr, int callnumber) -{ - if (*ptr != NULL && *ptr != (nsc_bucket_t *)-1) { - /* leave pending calls alone */ - update_exec_bucket(ptr, NULL, callnumber); - } -} - -static void -do_findgnams(nsc_bucket_t *ptr, int *table, char *gnam) -{ - - /* - * be careful with ptr - it may be -1 or NULL. - */ - - if (ptr != NULL && ptr != (nsc_bucket_t *)-1) { - char *tmp = (char *)insertn(table, ptr->nsc_hits, - (int)strdup(gnam)); - if (tmp != (char *)-1) - free(tmp); - } -} - -void -getexec_revalidate(void) -{ - for (;;) { - int slp; - int interval; - int count; - - slp = current_admin.exec.nsc_pos_ttl; - - if (slp < 60) { - slp = 60; - } - if ((count = current_admin.exec.nsc_keephot) != 0) { - interval = (slp / 2)/count; - if (interval == 0) interval = 1; - sleep(slp * 2 / 3); - getexec_namekeepalive(count, interval); - } else { - sleep(slp); - } - } -} +#define EXEC_STR_CMP(s1, s2) \ + if ((a = s1) == NULL) \ + a = z; \ + if ((b = s2) == NULL) \ + b = z; \ + res = strcmp(a, b); \ + if (res != 0) \ + return (res > 0 ? 1 : -1); static int -getexec_namekeepalive(int keep, int interval) -{ - int *table; - union { - nsc_data_t ping; - char space[sizeof (nsc_data_t) + NSCDMAXNAMELEN]; - } u; +execattr_compar(const void *n1, const void *n2) { + nsc_entry_t *e1 = (nsc_entry_t *)n1; + nsc_entry_t *e2 = (nsc_entry_t *)n2; + _priv_execattr *ep1 = (_priv_execattr *)e1->key.attrp; + _priv_execattr *ep2 = (_priv_execattr *)e2->key.attrp; + int res; + const char *a, *b, *z = ""; - int i; + /* compare name */ + EXEC_STR_CMP(ep1->name, ep2->name); - if (!keep) - return (0); + /* compare policy */ + EXEC_STR_CMP(ep1->policy, ep2->policy); - table = maken(keep); - mutex_lock(&db_lock); - operate_hash(nam_hash, do_findgnams, (char *)table); - mutex_unlock(&db_lock); + /* compare type */ + EXEC_STR_CMP(ep1->type, ep2->type); - for (i = 1; i <= keep; i++) { - char *tmp; + /* compare id */ + EXEC_STR_CMP(ep1->id, ep2->id); - u.ping.nsc_call.nsc_callnumber = GETEXECID; - if ((tmp = (char *)table[keep + 1 + i]) == (char *)-1) - continue; /* unused slot in table */ - strcpy(u.ping.nsc_call.nsc_u.name, tmp); - launch_update(&u.ping.nsc_call); - sleep(interval); - } - - for (i = 1; i <= keep; i++) { - char *tmp; - if ((tmp = (char *)table[keep + 1 + i]) != (char *)-1) - free(tmp); - } - - free(table); - return (0); + /* compare search flag */ + return (_NSC_INT_KEY_CMP(ep1->search_flag, ep2->search_flag)); } - -/* - * This routine marks all entries as invalid - * - */ - -void -getexec_invalidate(void) -{ - mutex_lock(&db_lock); - getexec_invalidate_unlocked(); - mutex_unlock(&db_lock); +static uint_t +execattr_gethash(nss_XbyY_key_t *key, int htsize) { + _priv_execattr *ep = key->attrp; + char keys[1024]; + int len; + + len = snprintf(keys, sizeof (keys), "%s:%s:%s:%s:%d", + ep->name ? ep->name : "", ep->type ? ep->type : "", + ep->id ? ep->id : "", ep->policy ? ep->policy : "", + ep->search_flag); + return (db_gethash(keys, len, htsize)); } static void -getexec_invalidate_unlocked(void) -{ - operate_hash_addr(nam_hash, do_invalidate, (char *)GETEXECID); - current_admin.exec.nsc_invalidate_count++; -} - -void -getexec_lookup(nsc_return_t *out, int maxsize, nsc_call_t *in, time_t now) -{ - int out_of_date; - nsc_bucket_t *retb; - char **bucket; - char *p_name; - char *p_type; - char *p_id; - char *unique; - char *lasts; - char *sep = ":"; - - static time_t lastmod; - - int bufferspace = maxsize - sizeof (nsc_return_t); - - if (current_admin.exec.nsc_enabled == 0) { - out->nsc_return_code = NOSERVER; - out->nsc_bufferbytesused = sizeof (*out); - return; - } - - mutex_lock(&db_lock); - - if (current_admin.exec.nsc_check_files) { - struct stat buf; - - if (stat(EXECATTR_FILENAME, &buf) < 0) { - /*EMPTY*/; - } else if (lastmod == 0) { - lastmod = buf.st_mtime; - } else if (lastmod < buf.st_mtime) { - getexec_invalidate_unlocked(); - lastmod = buf.st_mtime; - } - } - - if (current_admin.debug_level >= DBG_ALL) { - logit("getexec_lookup: looking for name %s\n", - in->nsc_u.name); - } - - for (;;) { - if (attr_strlen(in->nsc_u.name) > NSCDMAXNAMELEN) { - ucred_t *uc = NULL; - - if (door_ucred(&uc) != 0) { - logit("getexec_lookup: Name too long, " - "but no user credential: %s\n", - strerror(errno)); - } else { - logit("getexec_lookup: Name too long from pid " - "%d uid %d\n", ucred_getpid(uc), - ucred_getruid(uc)); - ucred_free(uc); - } - - out->nsc_errno = NSS_NOTFOUND; - out->nsc_return_code = NOTFOUND; - out->nsc_bufferbytesused = sizeof (*out); - goto getout; - } - bucket = get_hash(nam_hash, in->nsc_u.name); - - if (*bucket == (char *)-1) { /* pending lookup */ - if (get_clearance(in->nsc_callnumber) != 0) { - /* no threads available */ - out->nsc_return_code = NOSERVER; - /* cannot process now */ - out->nsc_bufferbytesused = - sizeof (*out); - current_admin.exec.nsc_throttle_count++; - goto getout; - } - nscd_wait(&db_wait, &db_lock, bucket); - release_clearance(in->nsc_callnumber); - continue; /* go back and relookup hash bucket */ - } - break; - } - - /* - * check for no name_service mode - */ - - if (*bucket == NULL && current_admin.avoid_nameservice) { - out->nsc_return_code = NOTFOUND; - out->nsc_bufferbytesused = sizeof (*out); - } else if ((*bucket == NULL) || /* New entry in name service */ - (in->nsc_callnumber & UPDATEBIT) || /* needs updating */ - (out_of_date = (!current_admin.avoid_nameservice && - (current_admin.exec.nsc_old_data_ok == 0) && - (((nsc_bucket_t *)*bucket)->nsc_timestamp < now)))) { - /* time has expired */ - int saved_errno; - int saved_hits = 0; - execstr_t *p; - - if (get_clearance(in->nsc_callnumber) != 0) { - /* no threads available */ - out->nsc_return_code = NOSERVER; - /* cannot process now */ - out->nsc_bufferbytesused = sizeof (*out); - current_admin.exec.nsc_throttle_count++; - goto getout; - } - - if (*bucket != NULL) { - saved_hits = - ((nsc_bucket_t *)*bucket)->nsc_hits; - } - - /* - * block any threads accessing this bucket if data is - * non-existent out of date - */ - - if (*bucket == NULL || out_of_date) { - update_exec_bucket((nsc_bucket_t **)bucket, - (nsc_bucket_t *)-1, - in->nsc_callnumber); - } else { - /* - * if still not -1 bucket we are doing update... - * mark to prevent - * pileups of threads if the name service is hanging.... - */ - ((nsc_bucket_t *)(*bucket))->nsc_status |= - ST_UPDATE_PENDING; - /* cleared by deletion of old data */ - } - mutex_unlock(&db_lock); - - /* - * Call non-caching version in libnsl. - */ - unique = strdup(in->nsc_u.name); - p_name = strtok_r(unique, sep, &lasts); - p_type = strtok_r(NULL, sep, &lasts); - p_id = strtok_r(NULL, sep, &lasts); - p = _getexecprof(p_name, - p_type, - p_id, - GET_ONE, - &out->nsc_u.exec, - out->nsc_u.buff + sizeof (execstr_t), - bufferspace, - &saved_errno); - - free(unique); - mutex_lock(&db_lock); - - release_clearance(in->nsc_callnumber); - - if (p == NULL) { /* data not found */ - - if (current_admin.debug_level >= DBG_CANT_FIND) { - logit("getexec_lookup: nscd COULDN'T FIND exec_attr name %s\n", - in->nsc_u.name); - } - - if (!(UPDATEBIT & in->nsc_callnumber)) - current_admin.exec.nsc_neg_cache_misses++; - - retb = (nsc_bucket_t *)malloc(sizeof (nsc_bucket_t)); - - retb->nsc_refcount = 1; - retb->nsc_data.nsc_bufferbytesused = - sizeof (nsc_return_t); - retb->nsc_data.nsc_return_code = NOTFOUND; - retb->nsc_data.nsc_errno = saved_errno; - memcpy(out, &retb->nsc_data, - retb->nsc_data.nsc_bufferbytesused); - update_exec_bucket((nsc_bucket_t **)bucket, - retb, in->nsc_callnumber); - goto getout; - } else { - if (current_admin.debug_level >= DBG_ALL) { - logit("getexec_lookup: nscd FOUND exec_attr name %s\n", - in->nsc_u.name); - } - if (!(UPDATEBIT & in->nsc_callnumber)) - current_admin.exec.nsc_pos_cache_misses++; - retb = fixbuffer(out, bufferspace); - update_exec_bucket((nsc_bucket_t **)bucket, - retb, in->nsc_callnumber); - if (saved_hits) - retb->nsc_hits = saved_hits; - } - } else { /* found entry in cache */ - retb = (nsc_bucket_t *)*bucket; - retb->nsc_hits++; - memcpy(out, &(retb->nsc_data), - retb->nsc_data.nsc_bufferbytesused); - if (out->nsc_return_code == SUCCESS) { - if (!(UPDATEBIT & in->nsc_callnumber)) - current_admin.exec.nsc_pos_cache_hits++; - if (current_admin.debug_level >= DBG_ALL) { - logit("getexec_lookup: found name %s in cache\n", - in->nsc_u.name); - } - } else { - if (!(UPDATEBIT & in->nsc_callnumber)) - current_admin.exec.nsc_neg_cache_hits++; - if (current_admin.debug_level >= DBG_ALL) { - logit("getexec_lookup: %s marked as NOT FOUND in cache.\n", - in->nsc_u.name); - } - } - - if ((retb->nsc_timestamp < now) && - !(in->nsc_callnumber & UPDATEBIT) && - !(retb->nsc_status & ST_UPDATE_PENDING)) { - logit("launch update since time = %d\n", retb->nsc_timestamp); - retb->nsc_status |= ST_UPDATE_PENDING; - /* cleared by deletion of old data */ - launch_update(in); - } - } - -getout: - mutex_unlock(&db_lock); -} - -/*ARGSUSED*/ -static int -update_exec_bucket(nsc_bucket_t **old, nsc_bucket_t *new, int callnumber) -{ - if (*old != NULL && *old != (nsc_bucket_t *)-1) { /* old data exists */ - free(*old); - current_admin.exec.nsc_entries--; - } - - /* - * we can do this before reseting *old since we're holding the lock - */ - - else if (*old == (nsc_bucket_t *)-1) { - nscd_signal(&db_wait, (char **)old); - } - - *old = new; - - if ((new != NULL) && (new != (nsc_bucket_t *)-1)) { - /* real data, not just update pending or invalidate */ - new->nsc_hits = 1; - new->nsc_status = 0; - new->nsc_refcount = 1; - current_admin.exec.nsc_entries++; - - if (new->nsc_data.nsc_return_code == SUCCESS) { - new->nsc_timestamp = time(NULL) + - current_admin.exec.nsc_pos_ttl; - } else { - new->nsc_timestamp = time(NULL) + - current_admin.exec.nsc_neg_ttl; - } - } - return (0); -} - -/*ARGSUSED*/ -static nsc_bucket_t * -fixbuffer(nsc_return_t *in, int maxlen) -{ - nsc_bucket_t *retb; - nsc_return_t *out; - char *dest; - int offset; - int strs; - - /* - * find out the size of the data block we're going to need - */ - - strs = attr_strlen(in->nsc_u.exec.name) + - attr_strlen(in->nsc_u.exec.policy) + - attr_strlen(in->nsc_u.exec.type) + - attr_strlen(in->nsc_u.exec.res1) + - attr_strlen(in->nsc_u.exec.res2) + - attr_strlen(in->nsc_u.exec.id) + - attr_strlen(in->nsc_u.exec.attr) + EXECATTR_DB_NCOL; - - /* - * allocate it and copy it in - * code doesn't assume packing order in original buffer - */ - - if ((retb = (nsc_bucket_t *)malloc(sizeof (*retb) + strs)) == NULL) { - return (NULL); - } - - out = &(retb->nsc_data); - out->nsc_bufferbytesused = strs + ((int)&out->nsc_u.exec - (int)out) + - sizeof (execstr_t); - out->nsc_return_code = SUCCESS; - out->nsc_errno = 0; - - dest = retb->nsc_data.nsc_u.buff + sizeof (execstr_t); - offset = (int)dest; - - attr_strcpy(dest, in->nsc_u.exec.name); - strs = 1 + attr_strlen(in->nsc_u.exec.name); - out->nsc_u.exec.name = dest - offset; - dest += strs; - - attr_strcpy(dest, in->nsc_u.exec.policy); - strs = 1 + attr_strlen(in->nsc_u.exec.policy); - out->nsc_u.exec.policy = dest - offset; - dest += strs; - - attr_strcpy(dest, in->nsc_u.exec.type); - strs = 1 + attr_strlen(in->nsc_u.exec.type); - out->nsc_u.exec.type = dest - offset; - dest += strs; - - attr_strcpy(dest, in->nsc_u.exec.res1); - strs = 1 + attr_strlen(in->nsc_u.exec.res1); - out->nsc_u.exec.res1 = dest - offset; - dest += strs; - - attr_strcpy(dest, in->nsc_u.exec.res2); - strs = 1 + attr_strlen(in->nsc_u.exec.res2); - out->nsc_u.exec.res2 = dest - offset; - dest += strs; - - attr_strcpy(dest, in->nsc_u.exec.id); - strs = 1 + attr_strlen(in->nsc_u.exec.id); - out->nsc_u.exec.id = dest - offset; - dest += strs; - - attr_strcpy(dest, in->nsc_u.exec.attr); - out->nsc_u.exec.attr = dest - offset; - - memcpy(in, out, out->nsc_bufferbytesused); - - return (retb); -} - -void -getexec_reaper(void) -{ - nsc_reaper("getexec", nam_hash, ¤t_admin.exec, &db_lock); +execattr_getlogstr(char *name, char *whoami, size_t len, + nss_XbyY_args_t *argp) { + _priv_execattr *ep = argp->key.attrp; + + (void) snprintf(whoami, len, + "%s [name=%s:type=%s:id=%s:policy=%s:flags=%d]", + name, check_null(ep->name), check_null(ep->type), + check_null(ep->id), check_null(ep->policy), + ep->search_flag); } diff --git a/usr/src/cmd/nscd/getgr.c b/usr/src/cmd/nscd/getgr.c index 5bf10680b4..1fc9215248 100644 --- a/usr/src/cmd/nscd/getgr.c +++ b/usr/src/cmd/nscd/getgr.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2003 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -30,587 +29,51 @@ * Routines to handle getgr* calls in nscd */ -#include <assert.h> -#include <errno.h> -#include <memory.h> -#include <signal.h> -#include <stdio.h> #include <stdlib.h> -#include <string.h> -#include <sys/door.h> -#include <sys/stat.h> -#include <sys/time.h> -#include <sys/types.h> -#include <sys/wait.h> -#include <thread.h> -#include <unistd.h> -#include <ucred.h> -#include <nss_common.h> +#include "cache.h" -#include <getxby_door.h> -#include "server_door.h" -#include "nscd.h" +#define nam_db ctx->nsc_db[0] +#define gid_db ctx->nsc_db[1] -static hash_t *uid_hash; -static hash_t *nam_hash; -static mutex_t group_lock = DEFAULTMUTEX; -static waiter_t group_wait; +#define NSC_NAME_GROUP_BYNAME "getgrnam" +#define NSC_NAME_GROUP_BYGID "getgrgid" -static void getgr_gidkeepalive(int keep, int interval); -static void getgr_namekeepalive(int keep, int interval); -static int update_gr_bucket(nsc_bucket_t **old, nsc_bucket_t *new, - int callnumber); -static nsc_bucket_t *fixbuffer(nsc_return_t *in, int maxlen); -static void do_findgids(nsc_bucket_t *ptr, int *table, int gid); -static void do_findgnams(nsc_bucket_t *ptr, int *table, char *gnam); -static void do_invalidate(nsc_bucket_t **ptr, int callnumber); -static void getgr_invalidate_unlocked(void); - - -void -getgr_init(void) -{ - uid_hash = make_ihash(current_admin.group.nsc_suggestedsize); - nam_hash = make_hash(current_admin.group.nsc_suggestedsize); - -} - -static void -do_invalidate(nsc_bucket_t **ptr, int callnumber) -{ - if (*ptr != NULL && *ptr != (nsc_bucket_t *)-1) { - /* leave pending calls alone */ - update_gr_bucket(ptr, NULL, callnumber); - } -} - -static void -do_findgids(nsc_bucket_t *ptr, int *table, int gid) -{ - - /* - * be careful with ptr - it may be -1 or NULL. - */ - if (ptr != NULL && ptr != (nsc_bucket_t *)-1) { - insertn(table, ptr->nsc_hits, gid); - } -} - -static void -do_findgnams(nsc_bucket_t *ptr, int *table, char *gnam) -{ - - /* - * be careful with ptr - it may be -1 or NULL. - */ - - if (ptr != NULL && ptr != (nsc_bucket_t *)-1) { - char *tmp = (char *)insertn(table, ptr->nsc_hits, - (int)strdup(gnam)); - if (tmp != (char *)-1) - free(tmp); - } -} +static void grgid_getlogstr(char *, char *, size_t, nss_XbyY_args_t *); +static int grgid_compar(const void *, const void *); +static uint_t grgid_gethash(nss_XbyY_key_t *, int); void -getgr_revalidate(void) -{ - for (;;) { - int slp; - int interval; - int count; - - slp = current_admin.group.nsc_pos_ttl; - - if (slp < 60) { - slp = 60; - } - - if ((count = current_admin.group.nsc_keephot) != 0) { - interval = (slp / 2)/count; - if (interval == 0) interval = 1; - sleep(slp * 2 / 3); - getgr_gidkeepalive(count, interval); - getgr_namekeepalive(count, interval); - } else { - sleep(slp); - } - } -} - -static void -getgr_gidkeepalive(int keep, int interval) -{ - int *table; - nsc_data_t ping; - int i; - - if (!keep) - return; - - table = maken(keep); - mutex_lock(&group_lock); - operate_hash(uid_hash, do_findgids, (char *)table); - mutex_unlock(&group_lock); - - for (i = 1; i <= keep; i++) { - ping.nsc_call.nsc_callnumber = GETGRGID; - if ((ping.nsc_call.nsc_u.gid = table[keep + 1 + i]) == -1) - continue; /* unused slot in table */ - launch_update(&ping.nsc_call); - sleep(interval); - } - free(table); +group_init_ctx(nsc_ctx_t *ctx) { + ctx->dbname = NSS_DBNAM_GROUP; + ctx->file_name = "/etc/group"; + ctx->db_count = 2; + nam_db = make_cache(nsc_key_ces, + NSS_DBOP_GROUP_BYNAME, + NSC_NAME_GROUP_BYNAME, + NULL, NULL, NULL, nsc_ht_default, -1); + gid_db = make_cache(nsc_key_other, + NSS_DBOP_GROUP_BYGID, + NSC_NAME_GROUP_BYGID, + grgid_compar, + grgid_getlogstr, + grgid_gethash, nsc_ht_default, -1); } static void -getgr_namekeepalive(int keep, int interval) -{ - int *table; - union { - nsc_data_t ping; - char space[sizeof (nsc_data_t) + NSCDMAXNAMELEN]; - } u; - - int i; - - if (!keep) - return; - - table = maken(keep); - mutex_lock(&group_lock); - operate_hash(nam_hash, do_findgnams, (char *)table); - mutex_unlock(&group_lock); - - for (i = 1; i <= keep; i++) { - char *tmp; - u.ping.nsc_call.nsc_callnumber = GETGRNAM; - - if ((tmp = (char *)table[keep + 1 + i]) == (char *)-1) - continue; /* unused slot in table */ - - strcpy(u.ping.nsc_call.nsc_u.name, tmp); - - launch_update(&u.ping.nsc_call); - sleep(interval); - } - - for (i = 1; i <= keep; i++) { - char *tmp; - if ((tmp = (char *)table[keep + 1 + i]) != (char *)-1) - free(tmp); - } - - free(table); -} - - -/* - * This routine marks all entries as invalid - * - */ - -void -getgr_invalidate(void) -{ - mutex_lock(&group_lock); - getgr_invalidate_unlocked(); - mutex_unlock(&group_lock); -} - -static void -getgr_invalidate_unlocked(void) -{ - operate_hash_addr(nam_hash, do_invalidate, (char *)GETGRNAM); - operate_hash_addr(uid_hash, do_invalidate, (char *)GETGRGID); - current_admin.group.nsc_invalidate_count++; -} - -void -getgr_lookup(nsc_return_t *out, int maxsize, nsc_call_t *in, time_t now) -{ - int out_of_date; - nsc_bucket_t *retb; - char **bucket; - - static time_t lastmod; - - int bufferspace = maxsize - sizeof (nsc_return_t); - - if (current_admin.group.nsc_enabled == 0) { - out->nsc_return_code = NOSERVER; - out->nsc_bufferbytesused = sizeof (*out); - return; - } - - mutex_lock(&group_lock); - - if (current_admin.group.nsc_check_files) { - struct stat buf; - - if (stat("/etc/group", &buf) < 0) { - /*EMPTY*/; - } else if (lastmod == 0) { - lastmod = buf.st_mtime; - } else if (lastmod < buf.st_mtime) { - getgr_invalidate_unlocked(); - lastmod = buf.st_mtime; - } - } - - if (current_admin.debug_level >= DBG_ALL) { - if (MASKUPDATEBIT(in->nsc_callnumber) == GETGRGID) { - logit("getgr_lookup: looking for gid %d\n", - in->nsc_u.gid); - } else { - logit("getgr_lookup: looking for name %s\n", - in->nsc_u.name); - } - } - - for (;;) { - if (MASKUPDATEBIT(in->nsc_callnumber) == GETGRGID) { - bucket = get_hash(uid_hash, (char *)in->nsc_u.gid); - } else { - if (strlen(in->nsc_u.name) > NSCDMAXNAMELEN) { - ucred_t *uc = NULL; - - if (door_ucred(&uc) != 0) { - logit("getgr_lookup: Name too long, " - "but no user credential: %s\n", - strerror(errno)); - } else { - logit("getgr_lookup: Name too long " - "from pid %d uid %d\n", - ucred_getpid(uc), - ucred_getruid(uc)); - ucred_free(uc); - } - - out->nsc_errno = NSS_NOTFOUND; - out->nsc_return_code = NOTFOUND; - out->nsc_bufferbytesused = sizeof (*out); - goto getout; - } - bucket = get_hash(nam_hash, in->nsc_u.name); - } - - if (*bucket == (char *)-1) { /* pending lookup */ - if (get_clearance(in->nsc_callnumber) != 0) { - /* - * no threads available - * cannot process now - */ - out->nsc_return_code = NOSERVER; - out->nsc_bufferbytesused = sizeof (*out); - current_admin.group.nsc_throttle_count++; - goto getout; - } - nscd_wait(&group_wait, &group_lock, bucket); - release_clearance(in->nsc_callnumber); - continue; /* go back and relookup hash bucket */ - } - break; - } - - /* - * check for no name_service mode - */ - - if (*bucket == NULL && current_admin.avoid_nameservice) { - out->nsc_return_code = NOTFOUND; - out->nsc_bufferbytesused = sizeof (*out); - } else if ((*bucket == NULL) || /* New entry in name service */ - (in->nsc_callnumber & UPDATEBIT) || /* needs updating */ - (out_of_date = (!current_admin.avoid_nameservice && - (current_admin.group.nsc_old_data_ok == 0) && - (((nsc_bucket_t *)*bucket)->nsc_timestamp < now)))) { - /* time has expired */ - int saved_errno; - int saved_hits = 0; - struct group *p; - - if (get_clearance(in->nsc_callnumber) != 0) { - /* no threads available */ - out->nsc_return_code = NOSERVER; - /* cannot process now */ - out->nsc_bufferbytesused = sizeof (*out); - current_admin.group.nsc_throttle_count++; - goto getout; - } - - if (*bucket != NULL) { - saved_hits = ((nsc_bucket_t *)*bucket)->nsc_hits; - } - - /* - * block any threads accessing this bucket if data is - * non-existent out of date - */ - - if (*bucket == NULL || out_of_date) { - update_gr_bucket((nsc_bucket_t **)bucket, - (nsc_bucket_t *)-1, - in->nsc_callnumber); - } else { - /* - * if still not -1 bucket we are doing update... - * mark to prevent pileups of threads if the name - * service is hanging.... - */ - ((nsc_bucket_t *)(*bucket))->nsc_status |= - ST_UPDATE_PENDING; - /* cleared by deletion of old data */ - } - mutex_unlock(&group_lock); - - if (MASKUPDATEBIT(in->nsc_callnumber) == GETGRGID) { - p = _uncached_getgrgid_r(in->nsc_u.gid, &out->nsc_u.grp, - out->nsc_u.buff + sizeof (struct group), - bufferspace); - saved_errno = errno; - } else { - p = _uncached_getgrnam_r(in->nsc_u.name, - &out->nsc_u.grp, - out->nsc_u.buff + sizeof (struct group), - bufferspace); - saved_errno = errno; - } - - mutex_lock(&group_lock); - - release_clearance(in->nsc_callnumber); - - if (p == NULL) { /* data not found */ - if (current_admin.debug_level >= DBG_CANT_FIND) { - if (MASKUPDATEBIT(in->nsc_callnumber) == - GETGRGID) { - logit("getgr_lookup: nscd COULDN'T FIND gid %d\n", - in->nsc_u.gid); - } else { - logit("getgr_lookup: nscd COULDN'T FIND group name %s\n", - in->nsc_u.name); - } - } - - - if (!(UPDATEBIT & in->nsc_callnumber)) - current_admin.group.nsc_neg_cache_misses++; - - retb = (nsc_bucket_t *)malloc(sizeof (nsc_bucket_t)); - - retb->nsc_refcount = 1; - retb->nsc_data.nsc_bufferbytesused = - sizeof (nsc_return_t); - retb->nsc_data.nsc_return_code = NOTFOUND; - retb->nsc_data.nsc_errno = saved_errno; - memcpy(out, &retb->nsc_data, - retb->nsc_data.nsc_bufferbytesused); - update_gr_bucket((nsc_bucket_t **)bucket, - retb, - in->nsc_callnumber); - goto getout; - } else { - if (current_admin.debug_level >= DBG_ALL) { - if (MASKUPDATEBIT(in->nsc_callnumber) == - GETGRGID) { - logit("getgr_lookup: nscd FOUND gid %d\n", - in->nsc_u.gid); - } else { - logit("getgr_lookup: nscd FOUND group name %s\n", - in->nsc_u.name); - } - } - if (!(UPDATEBIT & in->nsc_callnumber)) - current_admin.group.nsc_pos_cache_misses++; - - retb = fixbuffer(out, bufferspace); - update_gr_bucket((nsc_bucket_t **)bucket, - retb, - in->nsc_callnumber); - if (saved_hits) - retb->nsc_hits = saved_hits; - } - } else { /* found entry in cache */ - retb = (nsc_bucket_t *)*bucket; - - retb->nsc_hits++; - - memcpy(out, &(retb->nsc_data), - retb->nsc_data.nsc_bufferbytesused); - - if (out->nsc_return_code == SUCCESS) { - if (!(UPDATEBIT & in->nsc_callnumber)) - current_admin.group.nsc_pos_cache_hits++; - if (current_admin.debug_level >= DBG_ALL) { - if (MASKUPDATEBIT(in->nsc_callnumber) == - GETGRGID) { - logit("getgr_lookup: found gid %d in cache\n", - in->nsc_u.gid); - } else { - logit("getgr_lookup: found name %s in cache\n", - in->nsc_u.name); - } - } - } else { - if (!(UPDATEBIT & in->nsc_callnumber)) - current_admin.group.nsc_neg_cache_hits++; - if (current_admin.debug_level >= DBG_ALL) { - if (MASKUPDATEBIT(in->nsc_callnumber) == - GETGRGID) { - logit("getgr_lookup: %d marked as NOT FOUND in cache.\n", - in->nsc_u.gid); - } else { - logit("getgr_lookup: %s marked as NOT FOUND in cache.\n", - in->nsc_u.name); - } - } - } - - if ((retb->nsc_timestamp < now) && - !(in->nsc_callnumber & UPDATEBIT) && - !(retb->nsc_status & ST_UPDATE_PENDING)) { - logit("launch update since time = %d\n", retb->nsc_timestamp); - retb->nsc_status |= ST_UPDATE_PENDING; - /* cleared by deletion of old data */ - launch_update(in); - } - } - -getout: - - mutex_unlock(&group_lock); +grgid_getlogstr(char *name, char *whoami, size_t len, nss_XbyY_args_t *argp) { + (void) snprintf(whoami, len, "%s [key=%d]", name, argp->key.gid); } -/*ARGSUSED*/ static int -update_gr_bucket(nsc_bucket_t **old, nsc_bucket_t *new, int callnumber) -{ - if (*old != NULL && *old != (nsc_bucket_t *)-1) { /* old data exists */ - free(*old); - current_admin.group.nsc_entries--; - } - - /* - * we can do this before reseting *old since we're holding the lock - */ - - else if (*old == (nsc_bucket_t *)-1) { - nscd_signal(&group_wait, (char **)old); - } +grgid_compar(const void *n1, const void *n2) { + nsc_entry_t *e1, *e2; - - *old = new; - - if ((new != NULL) && (new != (nsc_bucket_t *)-1)) { - /* real data, not just update pending or invalidate */ - - new->nsc_hits = 1; - new->nsc_status = 0; - new->nsc_refcount = 1; - current_admin.group.nsc_entries++; - - if (new->nsc_data.nsc_return_code == SUCCESS) { - new->nsc_timestamp = time(NULL) + - current_admin.group.nsc_pos_ttl; - } else { - new->nsc_timestamp = time(NULL) + - current_admin.group.nsc_neg_ttl; - } - } - return (0); + e1 = (nsc_entry_t *)n1; + e2 = (nsc_entry_t *)n2; + return (_NSC_INT_KEY_CMP(e1->key.gid, e2->key.gid)); } - -/*ARGSUSED*/ -static nsc_bucket_t * -fixbuffer(nsc_return_t *in, int maxlen) -{ - int group_members; - int i; - nsc_bucket_t *retb; - nsc_return_t *out; - char *dest; - int offset; - int strs; - char **members; - int pwlen; - - /* - * find out the size of the data block we're going to need - */ - - strs = 0; - strs += 1 + strlen(in->nsc_u.grp.gr_name); - pwlen = strlen(in->nsc_u.grp.gr_passwd); - if (pwlen < 4) - pwlen = 4; - strs += 1 + pwlen; - - group_members = 0; - while (in->nsc_u.grp.gr_mem[group_members]) { - strs += 1 + strlen(in->nsc_u.grp.gr_mem[group_members]); - group_members++; - } - - strs += (group_members+1) * sizeof (char *); - - /* - * allocate it and copy it in - * code doesn't assume packing order in original buffer - */ - - if ((retb = (nsc_bucket_t *)malloc(sizeof (*retb) + strs)) == NULL) { - return (NULL); - } - - out = &(retb->nsc_data); - out->nsc_bufferbytesused = strs + ((int)&out->nsc_u.grp - (int)out) + - sizeof (struct group); - out->nsc_return_code = SUCCESS; - out->nsc_errno = 0; - - - out->nsc_u.grp.gr_gid = in->nsc_u.grp.gr_gid; - - dest = retb->nsc_data.nsc_u.buff + sizeof (struct group); - offset = (int)dest; - - members = (char **)dest; - out->nsc_u.grp.gr_mem = (char **)(dest - offset); - dest += (group_members+1) * sizeof (char *); - - - strcpy(dest, in->nsc_u.grp.gr_name); - strs = 1 + strlen(in->nsc_u.grp.gr_name); - out->nsc_u.grp.gr_name = dest - offset; - dest += strs; - - strcpy(dest, in->nsc_u.grp.gr_passwd); - strs = 1 + pwlen; - out->nsc_u.grp.gr_passwd = dest - offset; - dest += strs; - - for (i = 0; i < group_members; i++) { - members[i] = dest - offset; - strcpy(dest, in->nsc_u.grp.gr_mem[i]); - strs = 1 + strlen(in->nsc_u.grp.gr_mem[i]); - dest += strs; - } - members[i] = NULL; /* null terminate list */ - memcpy(in, out, out->nsc_bufferbytesused); - - return (retb); -} - -void -getgr_uid_reaper() -{ - nsc_reaper("gr_uid", uid_hash, ¤t_admin.group, &group_lock); -} - -void -getgr_nam_reaper() -{ - nsc_reaper("gr_nam", nam_hash, ¤t_admin.group, &group_lock); +static uint_t +grgid_gethash(nss_XbyY_key_t *key, int htsize) { + return (key->gid % htsize); } diff --git a/usr/src/cmd/nscd/gethost.c b/usr/src/cmd/nscd/gethost.c index c38b7f0b2b..b0cee1ad7e 100644 --- a/usr/src/cmd/nscd/gethost.c +++ b/usr/src/cmd/nscd/gethost.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2003 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -30,654 +29,73 @@ * Routines to handle gethost* calls in nscd */ -#include <assert.h> -#include <errno.h> -#include <memory.h> -#include <signal.h> -#include <stdlib.h> -#include <stdio.h> #include <string.h> -#include <sys/door.h> -#include <sys/stat.h> -#include <sys/time.h> +#include <stdlib.h> #include <sys/types.h> -#include <sys/wait.h> -#include <thread.h> -#include <unistd.h> -#include <ucred.h> -#include <nss_common.h> - -#include "getxby_door.h" -#include "server_door.h" -#include "nscd.h" - -static hash_t *addr_hash; -static hash_t *hnam_hash; -static mutex_t host_lock = DEFAULTMUTEX; -static waiter_t host_wait; - -static void gethost_addrkeepalive(int keep, int interval); -static void gethost_invalidate_unlocked(void); -static void gethost_namekeepalive(int keep, int interval); -static int addr_to_int(char *addr); -static int int_to_addr(int h); -static void update_host_bucket(nsc_bucket_t **old, nsc_bucket_t *new, - int callnumber); -static nsc_bucket_t *fixbuffer(nsc_return_t *in, int maxlen); -static void do_findhaddrs(nsc_bucket_t *ptr, int *table, int intaddr); -static void do_findhnams(nsc_bucket_t *ptr, int *table, char *name); -static void do_invalidate(nsc_bucket_t **ptr, int callnumber); - -static int -addr_to_int(char *addr) -{ - union { - char data[4]; - int hashval; - } u; - -/* - * following code is byte order dependant, but since all we use this for - * is hashing this works out just fine. - */ - u.data[0] = *addr++; - u.data[1] = *addr++; - u.data[2] = *addr++; - u.data[3] = *addr++; - - return (u.hashval); -} - -static int -int_to_addr(int h) -{ - union { - char data[4]; - int hashval; - } u; - -/* - * following code is byte order dependant, but since all we use this for - * is hashing this works out just fine. - */ - u.hashval = h; - return (* ((int *)u.data)); -} - -void -gethost_init(void) -{ - addr_hash = make_ihash(current_admin.host.nsc_suggestedsize); - hnam_hash = make_hash(current_admin.host.nsc_suggestedsize); -} +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include "cache.h" -static void -do_invalidate(nsc_bucket_t ** ptr, int callnumber) -{ - if (*ptr != NULL && *ptr != (nsc_bucket_t *)-1) { - /* leave pending calls alone */ - update_host_bucket(ptr, NULL, callnumber); - } -} +#define hnam_db ctx->nsc_db[0] +#define addr_db ctx->nsc_db[1] -static void -do_findhnams(nsc_bucket_t *ptr, int *table, char *name) -{ - /* - * be careful with ptr - it may be -1 or NULL. - */ +#define NSC_NAME_HOSTS_BYNAME "gethostbyname" +#define NSC_NAME_HOSTS_BYADDR "gethostbyaddr" - if (ptr != NULL && ptr != (nsc_bucket_t *)-1) { - /* leave pending calls alone */ - char *tmp = (char *)insertn(table, ptr->nsc_hits, - (int)strdup(name)); - if (tmp != (char *)-1) - free(tmp); - } -} - -static void -do_findhaddrs(nsc_bucket_t *ptr, int *table, int intaddr) -{ - if (ptr != NULL && ptr != (nsc_bucket_t *)-1) { - /* leave pending calls alone */ - insertn(table, ptr->nsc_hits, int_to_addr(intaddr)); - } -} +static int hostaddr_compar(const void *, const void *); +static uint_t hostaddr_gethash(nss_XbyY_key_t *, int); +static void hostaddr_getlogstr(char *, char *, size_t, nss_XbyY_args_t *); void -gethost_revalidate(void) -{ - for (;;) { - int slp; - int interval; - int count; - - slp = current_admin.host.nsc_pos_ttl; - - if (slp < 60) - slp = 60; - count = current_admin.host.nsc_keephot; - if (count != 0) { - interval = (slp/2)/count; - if (interval == 0) interval = 1; - sleep(slp*2/3); - gethost_namekeepalive(count, interval); - gethost_addrkeepalive(count, interval); - } else { - sleep(slp); - } - } -} - -static void -gethost_namekeepalive(int keep, int interval) -{ - int *table; - union { - nsc_data_t ping; - char space[sizeof (nsc_data_t) + NSCDMAXNAMELEN]; - } u; - - int i; - - if (!keep) - return; - - table = maken(keep); - mutex_lock(&host_lock); - operate_hash(hnam_hash, do_findhnams, (char *)table); - mutex_unlock(&host_lock); - - for (i = 1; i <= keep; i++) { - char *tmp; - u.ping.nsc_call.nsc_callnumber = GETHOSTBYNAME; - - if ((tmp = (char *)table[keep + 1 + i]) == (char *)-1) - continue; /* unused slot in table */ - if (current_admin.debug_level >= DBG_ALL) - logit("keepalive: reviving host %s\n", tmp); - strcpy(u.ping.nsc_call.nsc_u.name, tmp); - - launch_update(&u.ping.nsc_call); - sleep(interval); - } - - for (i = 1; i <= keep; i++) { - char *tmp; - if ((tmp = (char *)table[keep + 1 + i]) != (char *)-1) - free(tmp); - } - - free(table); -} - -static void -gethost_addrkeepalive(int keep, int interval) -{ - int *table; - union { - nsc_data_t ping; - char space[sizeof (nsc_data_t) + 80]; - } u; - - int i; - - if (!keep) - return; - - table = maken(keep); - mutex_lock(&host_lock); - operate_hash(addr_hash, do_findhaddrs, (char *)table); - mutex_unlock(&host_lock); - - for (i = 1; i <= keep; i++) { - int tmp; - u.ping.nsc_call.nsc_callnumber = GETHOSTBYADDR; - - if ((tmp = table[keep + 1 + i]) == -1) - continue; /* unused slot in table */ - u.ping.nsc_call.nsc_u.addr.a_type = AF_INET; - u.ping.nsc_call.nsc_u.addr.a_length = sizeof (int); - memcpy(u.ping.nsc_call.nsc_u.addr.a_data, &tmp, sizeof (int)); - launch_update(&u.ping.nsc_call); - sleep(interval); - } - - free(table); -} - -/* - * This routine marks all entries as invalid - * - */ -void -gethost_invalidate(void) -{ - mutex_lock(&host_lock); - gethost_invalidate_unlocked(); - mutex_unlock(&host_lock); -} - -static void -gethost_invalidate_unlocked(void) -{ - operate_hash_addr(hnam_hash, do_invalidate, (char *)GETHOSTBYNAME); - operate_hash_addr(addr_hash, do_invalidate, (char *)GETHOSTBYADDR); - current_admin.host.nsc_invalidate_count++; -} - -void -gethost_lookup(nsc_return_t *out, int maxsize, nsc_call_t *in, time_t now) -{ - int out_of_date; - nsc_bucket_t *retb; - char **bucket; - - static time_t lastmod; - - int bufferspace = maxsize - sizeof (nsc_return_t); - - if (current_admin.host.nsc_enabled == 0) { - out->nsc_return_code = NOSERVER; - out->nsc_bufferbytesused = sizeof (*out); - return; - } - - mutex_lock(&host_lock); - - if (current_admin.host.nsc_check_files) { - struct stat buf; +host_init_ctx(nsc_ctx_t *ctx) { + ctx->dbname = NSS_DBNAM_HOSTS; + ctx->db_count = 2; + ctx->file_name = "/etc/inet/hosts"; - if (stat("/etc/hosts", &buf) < 0) { - /*EMPTY*/; - } else if (lastmod == 0) { - lastmod = buf.st_mtime; - } else if (lastmod < buf.st_mtime) { - gethost_invalidate_unlocked(); - lastmod = buf.st_mtime; - } - } - - - if (current_admin.debug_level >= DBG_ALL) { - if (MASKUPDATEBIT(in->nsc_callnumber) == GETHOSTBYADDR) { - logit("gethost_lookup: looking for address %s\n", - inet_ntoa(*((struct in_addr *)in->nsc_u.addr.a_data))); - } else { - logit("gethost_lookup: looking for hostname %s\n", - in->nsc_u.name); - } - } - - for (;;) { - if (MASKUPDATEBIT(in->nsc_callnumber) == GETHOSTBYADDR) { - bucket = get_hash(addr_hash, - (char *)addr_to_int(in->nsc_u.addr.a_data)); - } else { /* bounce excessively long requests */ - if (strlen(in->nsc_u.name) > NSCDMAXNAMELEN) { - ucred_t *uc = NULL; - - if (door_ucred(&uc) != 0) { - logit("gethost_lookup: Name too long, " - "but no user credential: %s\n", - strerror(errno)); - } else { - logit("gethost_lookup: Name too long " - "from pid %d uid %d\n", - ucred_getpid(uc), - ucred_getruid(uc)); - ucred_free(uc); - } - - out->nsc_errno = NSS_NOTFOUND; - out->nsc_return_code = NOTFOUND; - out->nsc_bufferbytesused = sizeof (*out); - goto getout; - } - bucket = get_hash(hnam_hash, in->nsc_u.name); - } - - if (*bucket == (char *)-1) { /* pending lookup */ - if (get_clearance(in->nsc_callnumber) != 0) { - /* no threads available */ - out->nsc_return_code = NOSERVER; - /* cannot process now */ - out->nsc_bufferbytesused = sizeof (*out); - current_admin.host.nsc_throttle_count++; - goto getout; - } - nscd_wait(&host_wait, &host_lock, bucket); - release_clearance(in->nsc_callnumber); - continue; /* go back and relookup hash bucket */ - } - break; - } - - /* - * check for no name_service mode - */ - - if (*bucket == NULL && current_admin.avoid_nameservice) { - out->nsc_return_code = NOTFOUND; - out->nsc_bufferbytesused = sizeof (*out); - } else if ((*bucket == NULL) || /* New entry in name service */ - (in->nsc_callnumber & UPDATEBIT) || /* needs updating */ - (out_of_date = (!current_admin.avoid_nameservice && - (current_admin.host.nsc_old_data_ok == 0) && - (((nsc_bucket_t *)*bucket)->nsc_timestamp < now)))) { - /* time has expired */ - int saved_errno; - int saved_hits = 0; - struct hostent *p; - - if (get_clearance(in->nsc_callnumber) != 0) { - /* no threads available */ - out->nsc_return_code = NOSERVER; - /* cannot process now */ - out->nsc_bufferbytesused = sizeof (*out); - current_admin.host.nsc_throttle_count++; - goto getout; - } - - if (*bucket != NULL) { - saved_hits = ((nsc_bucket_t *)*bucket)->nsc_hits; - } - - /* - * block any threads accessing this bucket if data is - * non-existent or out of date - */ - - if (*bucket == NULL || out_of_date) { - update_host_bucket((nsc_bucket_t **)bucket, - (nsc_bucket_t *)-1, - in->nsc_callnumber); - } else { - /* - * if still not -1 bucket we are doing update... mark - * to prevent pileups of threads if the name service - * is hanging.... - */ - ((nsc_bucket_t *)(*bucket))->nsc_status |= - ST_UPDATE_PENDING; - /* cleared by deletion of old data */ - } - mutex_unlock(&host_lock); - - if (MASKUPDATEBIT(in->nsc_callnumber) == GETHOSTBYADDR) { - p = _uncached_gethostbyaddr_r(in->nsc_u.addr.a_data, - in->nsc_u.addr.a_length, - in->nsc_u.addr.a_type, - &out->nsc_u.hst, - out->nsc_u.buff+sizeof (struct hostent), - bufferspace, - &saved_errno); - } else { - p = _uncached_gethostbyname_r(in->nsc_u.name, - &out->nsc_u.hst, - out->nsc_u.buff+sizeof (struct hostent), - bufferspace, - &saved_errno); - } - - mutex_lock(&host_lock); - - release_clearance(in->nsc_callnumber); - - if (p == NULL) { /* data not found */ - if (current_admin.debug_level >= DBG_CANT_FIND) { - if (MASKUPDATEBIT(in->nsc_callnumber) == - GETHOSTBYADDR) { - logit("gethost_lookup: nscd COULDN'T FIND address %s\n", - inet_ntoa(*((struct in_addr *)in->nsc_u.addr.a_data))); - } else { - logit("gethost_lookup: nscd COULDN'T FIND host name %s\n", - in->nsc_u.name); - } - } + hnam_db = make_cache(nsc_key_cis, + NSS_DBOP_HOSTS_BYNAME, + NSC_NAME_HOSTS_BYNAME, + NULL, NULL, NULL, nsc_ht_default, -1); - if (!(UPDATEBIT & in->nsc_callnumber)) - current_admin.host.nsc_neg_cache_misses++; - - retb = (nsc_bucket_t *)malloc(sizeof (nsc_bucket_t)); - - retb->nsc_refcount = 1; - retb->nsc_data.nsc_return_code = NOTFOUND; - retb->nsc_data.nsc_bufferbytesused = - sizeof (nsc_return_t); - retb->nsc_data.nsc_errno = saved_errno; - memcpy(out, &(retb->nsc_data), - retb->nsc_data.nsc_bufferbytesused); - update_host_bucket((nsc_bucket_t **)bucket, retb, - in->nsc_callnumber); - goto getout; - } else { - if (current_admin.debug_level >= DBG_ALL) { - if (MASKUPDATEBIT(in->nsc_callnumber) == - GETHOSTBYADDR) { - logit("gethost_lookup: nscd FOUND addr %s\n", - inet_ntoa(*((struct in_addr *)in->nsc_u.addr.a_data))); - } else { - logit("gethost_lookup: nscd FOUND host name %s\n", - in->nsc_u.name); - } - } - if (!(UPDATEBIT & in->nsc_callnumber)) - current_admin.host.nsc_pos_cache_misses++; - - retb = fixbuffer(out, bufferspace); - - update_host_bucket((nsc_bucket_t **)bucket, retb, - in->nsc_callnumber); - if (saved_hits) - retb->nsc_hits = saved_hits; - } - } else { /* found entry in cache */ - retb = (nsc_bucket_t *)*bucket; - - retb->nsc_hits++; - - memcpy(out, &(retb->nsc_data), - retb->nsc_data.nsc_bufferbytesused); - - if (out->nsc_return_code == SUCCESS) { - if (!(UPDATEBIT & in->nsc_callnumber)) - current_admin.host.nsc_pos_cache_hits++; - if (current_admin.debug_level >= DBG_ALL) { - if (MASKUPDATEBIT(in->nsc_callnumber) == - GETHOSTBYADDR) { - logit("gethost_lookup: found address %s in cache\n", - inet_ntoa(*((struct in_addr *)in->nsc_u.addr.a_data))); - } else { - logit("gethost_lookup: found host name %s in cache\n", - in->nsc_u.name); - } - } - } else { - if (!(UPDATEBIT & in->nsc_callnumber)) - current_admin.host.nsc_neg_cache_hits++; - if (current_admin.debug_level >= DBG_ALL) { - if (MASKUPDATEBIT(in->nsc_callnumber) == - GETHOSTBYADDR) { - logit("gethost_lookup: %s marked as NOT FOUND in cache.\n", - inet_ntoa(*((struct in_addr *)in->nsc_u.addr.a_data))); - } else { - logit("gethost_lookup: %s marked as NOT FOUND in cache.\n", - in->nsc_u.name); - } - } - } - - if ((retb->nsc_timestamp < now) && - !(in->nsc_callnumber & UPDATEBIT) && - !(retb->nsc_status & ST_UPDATE_PENDING)) { - logit("launch update since time = %d\n", retb->nsc_timestamp); - /* cleared by deletion of old data */ - retb->nsc_status |= ST_UPDATE_PENDING; - launch_update(in); - } - } - -getout: - - mutex_unlock(&host_lock); + addr_db = make_cache(nsc_key_other, + NSS_DBOP_HOSTS_BYADDR, + NSC_NAME_HOSTS_BYADDR, + hostaddr_compar, + hostaddr_getlogstr, + hostaddr_gethash, nsc_ht_default, -1); } -/*ARGSUSED*/ static void -update_host_bucket(nsc_bucket_t **old, nsc_bucket_t *new, int callnumber) -{ - if (*old != NULL && *old != (nsc_bucket_t *)-1) { - /* old data exists */ - free(*old); - current_admin.host.nsc_entries--; - } - - /* - * we can do this before reseting *old since we're holding the lock - */ +hostaddr_getlogstr(char *name, char *whoami, size_t len, + nss_XbyY_args_t *argp) { + char addr[INET6_ADDRSTRLEN]; - else if (*old == (nsc_bucket_t *)-1) { - nscd_signal(&host_wait, (char **)old); - } - - - - *old = new; - - if ((new != NULL) && - (new != (nsc_bucket_t *)-1)) { - /* real data, not just update pending or invalidate */ - - new->nsc_hits = 1; - new->nsc_status = 0; - new->nsc_refcount = 1; - current_admin.host.nsc_entries++; - - if (new->nsc_data.nsc_return_code == SUCCESS) { - new->nsc_timestamp = time(NULL) + - current_admin.host.nsc_pos_ttl; - } else { - new->nsc_timestamp = time(NULL) + - current_admin.host.nsc_neg_ttl; - } + if (inet_ntop(argp->key.hostaddr.type, argp->key.hostaddr.addr, addr, + sizeof (addr)) == NULL) { + (void) snprintf(whoami, len, "%s", name); + } else { + (void) snprintf(whoami, len, "%s [key=%s, addrtype=%d]", + name, addr, argp->key.hostaddr.type); } } - -/*ARGSUSED*/ -static nsc_bucket_t * -fixbuffer(nsc_return_t *in, int maxlen) -{ - nsc_return_t *out; - nsc_bucket_t *retb; - char *dest; - char **aliaseslist; - char **addrlist; - int offset; - int strs; - int i; - int numaliases; - int numaddrs; - - /* - * find out the size of the data block we're going to need - */ - - strs = 1 + strlen(in->nsc_u.hst.h_name); - for (numaliases = 0; in->nsc_u.hst.h_aliases[numaliases]; numaliases++) - strs += 1 + strlen(in->nsc_u.hst.h_aliases[numaliases]); - strs += sizeof (char *) * (numaliases+1); - for (numaddrs = 0; in->nsc_u.hst.h_addr_list[numaddrs]; numaddrs++) - strs += in->nsc_u.hst.h_length; - strs += sizeof (char *) * (numaddrs+1+3); - - /* - * allocate it and copy it in - * code doesn't assume packing order in original buffer - */ - - if ((retb = (nsc_bucket_t *)malloc(sizeof (*retb) + strs)) == NULL) { - return (NULL); - } - - out = &(retb->nsc_data); - out->nsc_bufferbytesused = sizeof (*in) + strs; - out->nsc_return_code = SUCCESS; - out->nsc_errno = 0; - - - dest = retb->nsc_data.nsc_u.buff + sizeof (struct hostent); - - offset = (int)dest; - - /* - * allocat the h_aliases list and the h_addr_list first to align 'em. - */ - aliaseslist = (char **)dest; - - dest += sizeof (char *) * (numaliases+1); - - addrlist = (char **)dest; - - dest += sizeof (char *) * (numaddrs+1); - - strcpy(dest, in->nsc_u.hst.h_name); - strs = 1 + strlen(in->nsc_u.hst.h_name); - out->nsc_u.hst.h_name = dest - offset; - dest += strs; - - - /* - * fill out the h_aliases list - */ - for (i = 0; i < numaliases; i++) { - strcpy(dest, in->nsc_u.hst.h_aliases[i]); - strs = 1 + strlen(in->nsc_u.hst.h_aliases[i]); - aliaseslist[i] = dest - offset; - dest += strs; - } - aliaseslist[i] = 0; /* null term ptr chain */ - - out->nsc_u.hst.h_aliases = (char **)((int)aliaseslist-offset); - - /* - * fill out the h_addr list - */ - - dest = (char *)(((int)dest + 3) & ~3); - - for (i = 0; i < numaddrs; i++) { - memcpy(dest, in->nsc_u.hst.h_addr_list[i], - in->nsc_u.hst.h_length); - strs = in->nsc_u.hst.h_length; - addrlist[i] = dest - offset; - dest += strs; - dest = (char *)(((int)dest + 3) & ~3); - } - - addrlist[i] = 0; /* null term ptr chain */ - - out->nsc_u.hst.h_addr_list = (char **)((int)addrlist-offset); - - out->nsc_u.hst.h_length = in->nsc_u.hst.h_length; - out->nsc_u.hst.h_addrtype = in->nsc_u.hst.h_addrtype; - - memcpy(in, &(retb->nsc_data), retb->nsc_data.nsc_bufferbytesused); - - return (retb); - -} - -void -gethost_nam_reaper() -{ - nsc_reaper("gethost_nam", hnam_hash, ¤t_admin.host, &host_lock); -} - -void -gethost_addr_reaper() -{ - nsc_reaper("gethost_addr", addr_hash, ¤t_admin.host, &host_lock); +static int +hostaddr_compar(const void *n1, const void *n2) { + nsc_entry_t *e1, *e2; + int res, l1, l2; + + e1 = (nsc_entry_t *)n1; + e2 = (nsc_entry_t *)n2; + l1 = e1->key.hostaddr.len; + l2 = e2->key.hostaddr.len; + res = memcmp(e1->key.hostaddr.addr, e2->key.hostaddr.addr, + (l2 > l1)?l1:l2); + return ((res) ? _NSC_INT_KEY_CMP(res, 0) : _NSC_INT_KEY_CMP(l1, l2)); +} + +static uint_t +hostaddr_gethash(nss_XbyY_key_t *key, int htsize) { + return (db_gethash(key->hostaddr.addr, + key->hostaddr.len, htsize)); } diff --git a/usr/src/cmd/nscd/getnet.c b/usr/src/cmd/nscd/getnet.c new file mode 100644 index 0000000000..468e8ffa68 --- /dev/null +++ b/usr/src/cmd/nscd/getnet.c @@ -0,0 +1,120 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * Routines to handle getnet* calls in nscd + */ + +#include <string.h> +#include <stdlib.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include "cache.h" + +#define nam_db ctx->nsc_db[0] +#define addr_db ctx->nsc_db[1] + +#define NSC_NAME_NETWORKS_BYNAME "getnetbyname" +#define NSC_NAME_NETWORKS_BYADDR "getnetbyaddr" + +static int netaddr_compar(const void *, const void *); +static uint_t netaddr_gethash(nss_XbyY_key_t *, int); +static void netaddr_getlogstr(char *, char *, size_t, nss_XbyY_args_t *); + +void +net_init_ctx(nsc_ctx_t *ctx) { + ctx->dbname = NSS_DBNAM_NETWORKS; + ctx->db_count = 2; + ctx->file_name = "/etc/inet/networks"; + + nam_db = make_cache(nsc_key_ces, + NSS_DBOP_NETWORKS_BYNAME, + NSC_NAME_NETWORKS_BYNAME, + NULL, NULL, NULL, nsc_ht_default, -1); + + addr_db = make_cache(nsc_key_other, + NSS_DBOP_NETWORKS_BYADDR, + NSC_NAME_NETWORKS_BYADDR, + netaddr_compar, + netaddr_getlogstr, + netaddr_gethash, nsc_ht_default, -1); +} + +static void +netaddr_getlogstr(char *name, char *whoami, size_t len, nss_XbyY_args_t *argp) { + if (argp->key.netaddr.type == AF_INET) { + uint32_t net; + uchar_t *up; + + net = htonl(argp->key.netaddr.net); + up = (uchar_t *)&net; + + if (up[0]) + (void) snprintf(whoami, len, "%s [key=%d.%d.%d.%d]", + name, + up[0], up[1], up[2], up[3]); + else if (up[1]) + (void) snprintf(whoami, len, "%s [key=%d.%d.%d]", + name, + up[1], up[2], up[3]); + else if (up[2]) + (void) snprintf(whoami, len, "%s [key=%d.%d]", + name, + up[2], up[3]); + else + (void) snprintf(whoami, len, "%s [key=%d]", + name, + up[3]); + } else { + (void) snprintf(whoami, len, "%s [key=%d, %d]", + name, + argp->key.netaddr.net, argp->key.netaddr.type); + } +} + +static int +netaddr_compar(const void *n1, const void *n2) { + nsc_entry_t *e1, *e2; + + e1 = (nsc_entry_t *)n1; + e2 = (nsc_entry_t *)n2; + + if (e1->key.netaddr.type > e2->key.netaddr.type) + return (1); + else if (e1->key.netaddr.type < e2->key.netaddr.type) + return (-1); + + return (_NSC_INT_KEY_CMP(e1->key.netaddr.net, e2->key.netaddr.net)); +} + +static uint_t +netaddr_gethash(nss_XbyY_key_t *key, int htsize) { + return (db_gethash(&key->netaddr.net, + sizeof (key->netaddr.net), htsize)); +} diff --git a/usr/src/cmd/nscd/getnetmasks.c b/usr/src/cmd/nscd/getnetmasks.c new file mode 100644 index 0000000000..81b709e104 --- /dev/null +++ b/usr/src/cmd/nscd/getnetmasks.c @@ -0,0 +1,48 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * Routines to handle getnetmask* calls in nscd + */ + +#include "cache.h" + +#define key_db ctx->nsc_db[0] + +#define NSC_NAME_NETMASKS_BYNET "getnetmaskbykey" + +void +netmask_init_ctx(nsc_ctx_t *ctx) { + ctx->dbname = NSS_DBNAM_NETMASKS; + ctx->db_count = 1; + ctx->file_name = "/etc/inet/netmasks"; + + key_db = make_cache(nsc_key_ces, + NSS_DBOP_NETMASKS_BYNET, + NSC_NAME_NETMASKS_BYNET, + NULL, NULL, NULL, nsc_ht_default, -1); +} diff --git a/usr/src/cmd/nscd/getnode.c b/usr/src/cmd/nscd/getnode.c index a744841197..fdf255672d 100644 --- a/usr/src/cmd/nscd/getnode.c +++ b/usr/src/cmd/nscd/getnode.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2003 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -32,772 +31,120 @@ * related to them in the nscd will remain as getnode*. */ -#include <assert.h> -#include <errno.h> -#include <memory.h> -#include <signal.h> #include <stdlib.h> -#include <stdio.h> #include <string.h> #include <strings.h> -#include <sys/door.h> -#include <sys/stat.h> -#include <sys/time.h> #include <sys/types.h> -#include <sys/wait.h> -#include <thread.h> -#include <unistd.h> -#include <ucred.h> -#include <nss_common.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> #include <inet/ip6.h> +#include "cache.h" -#include "getxby_door.h" -#include "server_door.h" -#include "nscd.h" +static int ipaddr_compar(const void *, const void *); +static uint_t ipaddr_gethash(nss_XbyY_key_t *, int); +static void ipaddr_getlogstr(char *, char *, size_t, nss_XbyY_args_t *); -static hash_t *addr_hash; /* node address hash */ -static hash_t *nnam_hash; /* node name hash */ -static mutex_t node_lock = DEFAULTMUTEX; -static waiter_t node_wait; +static int ipname_compar(const void *, const void *); +static uint_t ipname_gethash(nss_XbyY_key_t *, int); +static void ipname_getlogstr(char *, char *, size_t, nss_XbyY_args_t *); -static void getnode_addrkeepalive(int keep, int interval); -static void getnode_invalidate_unlocked(void); -static void getnode_namekeepalive(int keep, int interval); -static void update_node_bucket(nsc_bucket_t ** old, nsc_bucket_t *new, - int callnumber); -static nsc_bucket_t *fixbuffer(nsc_return_t *in, int maxlen); -static void do_findnaddrs(nsc_bucket_t *ptr, int *table, char *addr); -static void do_findnnams(nsc_bucket_t *ptr, int *table, char *name); -static void do_invalidate(nsc_bucket_t ** ptr, int callnumber); +#define nnam_db ctx->nsc_db[0] +#define addr_db ctx->nsc_db[1] -/* - * Create a combined key - * combined key = - * name + ":" + af_family(in %d format) + ":" + flags(in %d format) - * name = foo, af_family = 26, flags = 3, addrconfig = 1 - * key = "foo:26:3" - * The string is allocated and caller has to free it. - * - * Insert ":" in between to ensure the uniqueness of the key. - * - * af_family: [2 | 26] ([AF_INET | AF_INET6]) - * flags: 0 - strict - * 1 - AI_V4MAPPED - * 3 - (AI_V4MAPPED | AI_ALL) - * 4 - AI_ADDRCONFIG - * 5 - AI_DEFAULT (AI_V4MAPPED | AI_ADDRCONFIG) - * 7 - (AI_V4MAPPED | AI_ALL | AI_ADDRCONFIG) - */ -static char * -get_ipnode_combined_key(nsc_call_t *in) { - int len; - char *key; - char af_str[8]; /* in %d format */ - char flags_str[8]; /* in %d format */ - - snprintf(af_str, 8, "%d", in->nsc_u.ipnode.af_family); - snprintf(flags_str, 8, "%d", in->nsc_u.ipnode.flags); - /* name + ":" + af_str + ":" + flags_str + 1 */ - len = strlen(in->nsc_u.ipnode.name) + strlen(af_str) + - strlen(flags_str) + 3; - - if ((key = (char *)malloc(len)) == NULL) - return (NULL); - - snprintf(key, len, "%s:%s:%s", in->nsc_u.ipnode.name, af_str, - flags_str); - return (key); -} -/* - * Parse key and copy the values to out - */ -static void -copy_ipnode_combined_key(char *key, nsc_call_t *out) { - char *token, *lasts; - - if ((token = strtok_r(key, ":", &lasts)) != NULL) { - /* copy name */ - (void) strncpy(out->nsc_u.ipnode.name, token, - NSCDMAXNAMELEN); - if ((token = strtok_r(NULL, ":", &lasts)) != NULL) { - /* Copy af_family */ - out->nsc_u.ipnode.af_family = atoi(token); - - if ((token = strtok_r(NULL, ":", &lasts)) != NULL) { - /* Copy flags */ - out->nsc_u.ipnode.flags = atoi(token); - } - } - } -} - -static void -safe_inet_ntop(int af, const void *addr, char *cp, size_t size) -{ - if (inet_ntop(af, addr, cp, size) != cp) { - /* - * Called only for logging purposes... - * this should never happen in the nscd... but - * just in case we'll make sure we have a - * plausible error message. - */ - (void) snprintf(cp, size, "<inet_ntop returned %s>", - strerror(errno)); - } -} - -void -getnode_init(void) -{ - addr_hash = make_hash(current_admin.node.nsc_suggestedsize); - nnam_hash = make_hash(current_admin.node.nsc_suggestedsize); -} - -static void -do_invalidate(nsc_bucket_t ** ptr, int callnumber) -{ - if (*ptr != NULL && *ptr != (nsc_bucket_t *)-1) { - /* leave pending calls alone */ - update_node_bucket(ptr, NULL, callnumber); - } -} - -static void -do_findnnams(nsc_bucket_t *ptr, int *table, char *name) -{ - /* - * be careful with ptr - it may be -1 or NULL. - */ - - if (ptr != NULL && ptr != (nsc_bucket_t *)-1) { - /* leave pending calls alone */ - char *tmp = (char *)insertn(table, ptr->nsc_hits, - (int)strdup(name)); - if (tmp != (char *)-1) - free(tmp); - } -} - -static void -do_findnaddrs(nsc_bucket_t *ptr, int *table, char *addr) -{ - - if (ptr != NULL && ptr != (nsc_bucket_t *)-1) { - - /* leave pending calls alone */ - char *tmp = (char *)insertn(table, ptr->nsc_hits, - (int)strdup(addr)); - if (tmp != (char *)-1) - free(tmp); - } -} +#define NSC_NAME_IPNODES_BYNAME "getipnodebyname" +#define NSC_NAME_IPNODES_BYADDR "getipnodebyaddr" void -getnode_revalidate(void) -{ - for (;;) { - int slp; - int interval; - int count; - - slp = current_admin.node.nsc_pos_ttl; - - if (slp < 60) - slp = 60; - - if ((count = current_admin.node.nsc_keephot) != 0) { - interval = (slp/2)/count; - if (interval == 0) interval = 1; - (void) sleep(slp*2/3); - getnode_namekeepalive(count, interval); - getnode_addrkeepalive(count, interval); - } else { - (void) sleep(slp); - } - } -} - -static void -getnode_namekeepalive(int keep, int interval) -{ - int *table; - union { - nsc_data_t ping; - char space[sizeof (nsc_data_t) + NSCDMAXNAMELEN]; - } u; - - int i; - - if (!keep) - return; - - table = maken(keep); - (void) mutex_lock(&node_lock); - operate_hash(nnam_hash, do_findnnams, (char *)table); - (void) mutex_unlock(&node_lock); - - for (i = 1; i <= keep; i++) { - char *tmp; - u.ping.nsc_call.nsc_callnumber = GETIPNODEBYNAME; - - if ((tmp = (char *)table[keep + 1 + i]) == (char *)-1) - continue; /* unused slot in table */ - if (current_admin.debug_level >= DBG_ALL) - logit("keepalive: reviving node %s\n", tmp); - copy_ipnode_combined_key(tmp, &u.ping.nsc_call); - - launch_update(&u.ping.nsc_call); - (void) sleep(interval); - } - - for (i = 1; i <= keep; i++) { - char *tmp; - if ((tmp = (char *)table[keep + 1 + i]) != (char *)-1) - free(tmp); - } - - free(table); +ipnode_init_ctx(nsc_ctx_t *ctx) { + ctx->dbname = NSS_DBNAM_IPNODES; + ctx->file_name = "/etc/inet/ipnodes"; + ctx->db_count = 2; + nnam_db = make_cache(nsc_key_other, + NSS_DBOP_IPNODES_BYNAME, + NSC_NAME_IPNODES_BYNAME, + ipname_compar, + ipname_getlogstr, + ipname_gethash, nsc_ht_default, -1); + + addr_db = make_cache(nsc_key_other, + NSS_DBOP_IPNODES_BYADDR, + NSC_NAME_IPNODES_BYADDR, + ipaddr_compar, + ipaddr_getlogstr, + ipaddr_gethash, nsc_ht_default, -1); +} + +static int +ipaddr_compar(const void *n1, const void *n2) { + nsc_entry_t *e1, *e2; + int res, l1, l2; + + e1 = (nsc_entry_t *)n1; + e2 = (nsc_entry_t *)n2; + + if (e1->key.hostaddr.type > e2->key.hostaddr.type) + return (1); + else if (e1->key.hostaddr.type < e2->key.hostaddr.type) + return (-1); + + l1 = e1->key.hostaddr.len; + l2 = e2->key.hostaddr.len; + res = memcmp(e1->key.hostaddr.addr, e2->key.hostaddr.addr, + (l2 > l1)?l1:l2); + return ((res) ? _NSC_INT_KEY_CMP(res, 0) : _NSC_INT_KEY_CMP(l1, l2)); +} + +static uint_t +ipaddr_gethash(nss_XbyY_key_t *key, int htsize) { + return (db_gethash(key->hostaddr.addr, + key->hostaddr.len, htsize)); } static void -getnode_addrkeepalive(int keep, int interval) -{ - int *table; - union { - nsc_data_t ping; - char space[sizeof (nsc_data_t) + 80]; - } u; - - int i; - - if (!keep) - return; - - table = maken(keep); - (void) mutex_lock(&node_lock); - operate_hash(addr_hash, do_findnaddrs, (char *)table); - (void) mutex_unlock(&node_lock); - - for (i = 1; i <= keep; i++) { - char *tmp; - char addr[IPV6_ADDR_LEN]; - - u.ping.nsc_call.nsc_callnumber = GETIPNODEBYADDR; - - if ((tmp = (char *)table[keep + 1 + i]) == (char *)-1) - continue; /* enused slot in table */ - u.ping.nsc_call.nsc_u.addr.a_type = AF_INET6; - u.ping.nsc_call.nsc_u.addr.a_length = IPV6_ADDR_LEN; - if (inet_pton(AF_INET6, (const char *) tmp, (void *) addr) != - 1) - continue; /* illegal address - skip it */ - else { - (void) memcpy(u.ping.nsc_call.nsc_u.addr.a_data, - addr, IPV6_ADDR_LEN); - if (current_admin.debug_level >= DBG_ALL) - logit("keepalive: reviving address %s\n", tmp); - launch_update(&u.ping.nsc_call); - } - (void) sleep(interval); - } +ipaddr_getlogstr(char *name, char *whoami, size_t len, nss_XbyY_args_t *argp) { + char addr[INET6_ADDRSTRLEN]; - for (i = 1; i <= keep; i++) { - char *tmp; - if ((tmp = (char *)table[keep + 1 + i]) != (char *)-1) - free(tmp); + if (inet_ntop(argp->key.hostaddr.type, argp->key.hostaddr.addr, addr, + sizeof (addr)) == NULL) { + (void) snprintf(whoami, len, "%s", name); + } else { + (void) snprintf(whoami, len, "%s [key=%s addrtype=%d]", + name, + addr, argp->key.hostaddr.type); } - - free(table); } -/* - * This routine marks all entries as invalid - * - */ - -void -getnode_invalidate(void) -{ - (void) mutex_lock(&node_lock); - getnode_invalidate_unlocked(); - (void) mutex_unlock(&node_lock); -} +static int +ipname_compar(const void *n1, const void *n2) { + nsc_entry_t *e1, *e2; + int res, l1, l2; -static void -getnode_invalidate_unlocked(void) -{ - operate_hash_addr(nnam_hash, do_invalidate, (char *)GETIPNODEBYNAME); - operate_hash_addr(addr_hash, do_invalidate, (char *)GETIPNODEBYADDR); - current_admin.node.nsc_invalidate_count++; -} + e1 = (nsc_entry_t *)n1; + e2 = (nsc_entry_t *)n2; -/* - * Mark only the ipnodebyname cache entries as invalid - */ + if (e1->key.ipnode.af_family > e2->key.ipnode.af_family) + return (1); + else if (e1->key.ipnode.af_family < e2->key.ipnode.af_family) + return (-1); -void -getnode_name_invalidate(void) -{ - (void) mutex_lock(&node_lock); - operate_hash_addr(nnam_hash, do_invalidate, (char *)GETIPNODEBYNAME); - current_admin.node.nsc_invalidate_count++; - (void) mutex_unlock(&node_lock); + l1 = strlen(e1->key.ipnode.name); + l2 = strlen(e2->key.ipnode.name); + res = strncasecmp(e1->key.ipnode.name, e2->key.ipnode.name, + (l1 > l2)?l1:l2); + return (_NSC_INT_KEY_CMP(res, 0)); } -void -getnode_lookup(nsc_return_t *out, int maxsize, nsc_call_t *in, time_t now) -{ - int out_of_date; - nsc_bucket_t *retb; - char **bucket, *key; - - static time_t lastmod; - - int bufferspace = maxsize - sizeof (nsc_return_t); - - if (current_admin.node.nsc_enabled == 0) { - out->nsc_return_code = NOSERVER; - out->nsc_bufferbytesused = sizeof (*out); - return; - } - - (void) mutex_lock(&node_lock); - - if (current_admin.node.nsc_check_files) { - struct stat buf; - - if (stat("/etc/inet/ipnodes", &buf) < 0) { - /*EMPTY*/; - } else if (lastmod == 0) { - lastmod = buf.st_mtime; - } else if (lastmod < buf.st_mtime) { - getnode_invalidate_unlocked(); - lastmod = buf.st_mtime; - } - } - - - if (current_admin.debug_level >= DBG_ALL) { - if (MASKUPDATEBIT(in->nsc_callnumber) == GETIPNODEBYADDR) { - char addr[INET6_ADDRSTRLEN]; - safe_inet_ntop(AF_INET6, - (const void *)in->nsc_u.addr.a_data, addr, - sizeof (addr)); - logit("getnode_lookup: looking for address %s\n", addr); - } else { - logit("getnode_lookup: looking for nodename %s:%d:%d\n", - in->nsc_u.ipnode.name, - in->nsc_u.ipnode.af_family, - in->nsc_u.ipnode.flags); - } - } - - for (;;) { - if (MASKUPDATEBIT(in->nsc_callnumber) == GETIPNODEBYADDR) { - char addr[INET6_ADDRSTRLEN]; - if (inet_ntop(AF_INET6, - (const void *)in->nsc_u.addr.a_data, - addr, sizeof (addr)) == NULL) { - out->nsc_errno = NSS_NOTFOUND; - out->nsc_return_code = NOTFOUND; - out->nsc_bufferbytesused = sizeof (*out); - goto getout; - } - bucket = get_hash(addr_hash, addr); - } else { /* bounce excessively long requests */ - if (strlen(in->nsc_u.ipnode.name) > NSCDMAXNAMELEN) { - ucred_t *uc = NULL; - - if (door_ucred(&uc) != 0) { - logit("getnode_lookup: Name too long, " - "but no user credential: %s\n", - strerror(errno)); - } else { - logit("getnode_lookup: Name too long " - "from pid %d uid %d\n", - ucred_getpid(uc), - ucred_getruid(uc)); - ucred_free(uc); - } - - out->nsc_errno = NSS_NOTFOUND; - out->nsc_return_code = NOTFOUND; - out->nsc_bufferbytesused = sizeof (*out); - goto getout; - } - if ((key = get_ipnode_combined_key(in)) == NULL) { - - out->nsc_errno = NSS_NOTFOUND; - out->nsc_return_code = NOTFOUND; - out->nsc_bufferbytesused = sizeof (*out); - goto getout; - } - - bucket = get_hash(nnam_hash, key); - free(key); - } - - if (*bucket == (char *)-1) { /* pending lookup */ - if (get_clearance(in->nsc_callnumber) != 0) { - /* no threads available */ - out->nsc_return_code = NOSERVER; - /* cannot process now */ - out->nsc_bufferbytesused = sizeof (*out); - current_admin.node.nsc_throttle_count++; - goto getout; - } - nscd_wait(&node_wait, &node_lock, bucket); - release_clearance(in->nsc_callnumber); - continue; /* go back and relookup hash bucket */ - } - break; - } - - /* - * check for no name_service mode - */ - - if (*bucket == NULL && current_admin.avoid_nameservice) { - out->nsc_return_code = NOTFOUND; - out->nsc_bufferbytesused = sizeof (*out); - } else if ((*bucket == NULL) || /* New entry in name service */ - (in->nsc_callnumber & UPDATEBIT) || /* needs updating */ - (out_of_date = (!current_admin.avoid_nameservice && - (current_admin.node.nsc_old_data_ok == 0) && - (((nsc_bucket_t *)*bucket)->nsc_timestamp < now)))) { - /* time has expired */ - int saved_errno; - int saved_hits = 0; - struct hostent *p; - - if (get_clearance(in->nsc_callnumber) != 0) { - /* no threads available */ - out->nsc_return_code = NOSERVER; - /* cannot process now */ - out->nsc_bufferbytesused = sizeof (* out); - current_admin.node.nsc_throttle_count++; - goto getout; - } - - if (*bucket != NULL) { - saved_hits = ((nsc_bucket_t *)*bucket)->nsc_hits; - } - - /* - * block any threads accessing this bucket if data is - * non-existent or out of date - */ - - if (*bucket == NULL || out_of_date) { - update_node_bucket((nsc_bucket_t **)bucket, - (nsc_bucket_t *)-1, - in->nsc_callnumber); - } else { - /* - * if still not -1 bucket we are doing update... mark to - * prevent pileups of threads if the name service is hanging... - */ - ((nsc_bucket_t *)(*bucket))->nsc_status |= - ST_UPDATE_PENDING; - /* cleared by deletion of old data */ - } - (void) mutex_unlock(&node_lock); - - if (MASKUPDATEBIT(in->nsc_callnumber) == GETIPNODEBYADDR) { - p = _uncached_getipnodebyaddr(in->nsc_u.addr.a_data, - in->nsc_u.addr.a_length, - in->nsc_u.addr.a_type, - &out->nsc_u.hst, - out->nsc_u.buff+sizeof (struct hostent), - bufferspace, - &saved_errno); - } else { - p = _uncached_getipnodebyname(in->nsc_u.ipnode.name, - &out->nsc_u.hst, - out->nsc_u.buff+sizeof (struct hostent), - bufferspace, - in->nsc_u.ipnode.af_family, - in->nsc_u.ipnode.flags, - &saved_errno); - } - - (void) mutex_lock(&node_lock); - - release_clearance(in->nsc_callnumber); - - if (p == NULL) { /* data not found */ - if (current_admin.debug_level >= DBG_CANT_FIND) { - if (MASKUPDATEBIT(in->nsc_callnumber) == - GETIPNODEBYADDR) { - char addr[INET6_ADDRSTRLEN]; - safe_inet_ntop(AF_INET6, - (const void *)in->nsc_u.addr.a_data, - addr, sizeof (addr)); - logit("getnode_lookup: nscd COULDN'T "\ - "FIND address %s\n", addr); - } else { - logit("getnode_lookup: nscd COULDN'T "\ - "FIND node name %s:%d:%d\n", - in->nsc_u.ipnode.name, - in->nsc_u.ipnode.af_family, - in->nsc_u.ipnode.flags); - } - } - - if (!(UPDATEBIT & in->nsc_callnumber)) - current_admin.node.nsc_neg_cache_misses++; - - retb = (nsc_bucket_t *)malloc(sizeof (nsc_bucket_t)); - retb->nsc_refcount = 1; - retb->nsc_data.nsc_return_code = NOTFOUND; - retb->nsc_data.nsc_bufferbytesused = - sizeof (nsc_return_t); - retb->nsc_data.nsc_errno = saved_errno; - (void) memcpy(out, &(retb->nsc_data), - retb->nsc_data.nsc_bufferbytesused); - update_node_bucket((nsc_bucket_t **)bucket, retb, - in->nsc_callnumber); - goto getout; - } - - else { - if (current_admin.debug_level >= DBG_ALL) { - if (MASKUPDATEBIT(in->nsc_callnumber) == - GETIPNODEBYADDR) { - char addr[INET6_ADDRSTRLEN]; - safe_inet_ntop(AF_INET6, - (const void *)in->nsc_u.addr.a_data, - addr, sizeof (addr)); - logit("getnode_lookup: nscd FOUND "\ - "addr %s\n", addr); - } else { - logit("getnode_lookup: nscd FOUND "\ - "node name %s:%d:%d\n", - in->nsc_u.ipnode.name, - in->nsc_u.ipnode.af_family, - in->nsc_u.ipnode.flags); - } - } - if (!(UPDATEBIT & in->nsc_callnumber)) - current_admin.node.nsc_pos_cache_misses++; - - retb = fixbuffer(out, bufferspace); - - update_node_bucket((nsc_bucket_t **)bucket, retb, - in->nsc_callnumber); - if (saved_hits) - retb->nsc_hits = saved_hits; - } - } else { /* found entry in cache */ - retb = (nsc_bucket_t *)*bucket; - - retb->nsc_hits++; - - (void) memcpy(out, &(retb->nsc_data), - retb->nsc_data.nsc_bufferbytesused); - - if (out->nsc_return_code == SUCCESS) { - if (!(UPDATEBIT & in->nsc_callnumber)) - current_admin.node.nsc_pos_cache_hits++; - if (current_admin.debug_level >= DBG_ALL) { - if (MASKUPDATEBIT(in->nsc_callnumber) == - GETIPNODEBYADDR) { - char addr[INET6_ADDRSTRLEN]; - safe_inet_ntop(AF_INET6, - (const void *)in->nsc_u.addr.a_data, - addr, sizeof (addr)); - logit("getnode_lookup: found address "\ - "%s in cache\n", addr); - } else { - logit("getnode_lookup: found node "\ - "name %s:%d:%d in cache\n", - in->nsc_u.ipnode.name, - in->nsc_u.ipnode.af_family, - in->nsc_u.ipnode.flags); - } - } - } else { - if (!(UPDATEBIT & in->nsc_callnumber)) - current_admin.node.nsc_neg_cache_hits++; - if (current_admin.debug_level >= DBG_ALL) { - if (MASKUPDATEBIT(in->nsc_callnumber) == - GETIPNODEBYADDR) { - char addr[INET6_ADDRSTRLEN]; - safe_inet_ntop(AF_INET6, - (const void *)in->nsc_u.addr.a_data, - addr, sizeof (addr)); - logit("getnode_lookup: %s marked as "\ - "NOT FOUND in cache.\n", addr); - } else { - logit("getnode_lookup: %s:%d:%d marked"\ - " as NOT FOUND in cache.\n", - in->nsc_u.ipnode.name, - in->nsc_u.ipnode.af_family, - in->nsc_u.ipnode.flags); - } - } - } - - if ((retb->nsc_timestamp < now) && - !(in->nsc_callnumber & UPDATEBIT) && - !(retb->nsc_status & ST_UPDATE_PENDING)) { - logit("launch update since time = %d\n", - retb->nsc_timestamp); - retb->nsc_status |= ST_UPDATE_PENDING; - /* cleared by deletion of old data */ - launch_update(in); - } - } - -getout: - - (void) mutex_unlock(&node_lock); +static uint_t +ipname_gethash(nss_XbyY_key_t *key, int htsize) { + return (cis_gethash(key->ipnode.name, htsize)); } - -/*ARGSUSED*/ static void -update_node_bucket(nsc_bucket_t ** old, nsc_bucket_t *new, int callnumber) -{ - if (*old != NULL && *old != (nsc_bucket_t *)-1) { /* old data exists */ - free(*old); - current_admin.node.nsc_entries--; - } - - /* - * we can do this before reseting *old since we're holding the lock - */ - - else if (*old == (nsc_bucket_t *)-1) { - nscd_signal(&node_wait, (char **)old); - } - - *old = new; - - if ((new != NULL) && - (new != (nsc_bucket_t *)-1)) { - /* real data, not just update pending or invalidate */ - - new->nsc_hits = 1; - new->nsc_status = 0; - new->nsc_refcount = 1; - current_admin.node.nsc_entries++; - - if (new->nsc_data.nsc_return_code == SUCCESS) { - new->nsc_timestamp = time(NULL) + - current_admin.node.nsc_pos_ttl; - } else { - new->nsc_timestamp = time(NULL) + - current_admin.node.nsc_neg_ttl; - } - } -} - -/* Allocate a bucket to fit the data(nsc_return_t *in size) */ -/* copy the data into the bucket and return the bucket */ - -/*ARGSUSED*/ -static nsc_bucket_t * -fixbuffer(nsc_return_t *in, int maxlen) -{ - nsc_return_t *out; - nsc_bucket_t *retb; - char *dest; - char ** aliaseslist; - char ** addrlist; - int offset; - int strs; - int i; - int numaliases; - int numaddrs; - - /* find out the size of the data block we're going to need */ - - strs = 1 + strlen(in->nsc_u.hst.h_name); - for (numaliases = 0; in->nsc_u.hst.h_aliases[numaliases]; numaliases++) - strs += 1 + strlen(in->nsc_u.hst.h_aliases[numaliases]); - strs += sizeof (char *) * (numaliases+1); - for (numaddrs = 0; in->nsc_u.hst.h_addr_list[numaddrs]; numaddrs++) - strs += in->nsc_u.hst.h_length; - strs += sizeof (char *) * (numaddrs+1+3); - - /* allocate it and copy it in code doesn't assume packing */ - /* order in original buffer */ - - if ((retb = (nsc_bucket_t *)malloc(sizeof (*retb) + strs)) == NULL) { - return (NULL); - } - - out = &(retb->nsc_data); - out->nsc_bufferbytesused = sizeof (*in) + strs; - out->nsc_return_code = SUCCESS; - out->nsc_errno = 0; - - dest = retb->nsc_data.nsc_u.buff + sizeof (struct hostent); - offset = (int)dest; - - /* allocat the h_aliases list and the h_addr_list first to align 'em. */ - aliaseslist = (char **)dest; - - dest += sizeof (char *) * (numaliases+1); - - addrlist = (char **)dest; - - dest += sizeof (char *) * (numaddrs+1); - - (void) strcpy(dest, in->nsc_u.hst.h_name); - strs = 1 + strlen(in->nsc_u.hst.h_name); - out->nsc_u.hst.h_name = dest - offset; - dest += strs; - - - /* fill out the h_aliases list */ - - for (i = 0; i < numaliases; i++) { - (void) strcpy(dest, in->nsc_u.hst.h_aliases[i]); - strs = 1 + strlen(in->nsc_u.hst.h_aliases[i]); - aliaseslist[i] = dest - offset; - dest += strs; - } - aliaseslist[i] = 0; /* null term ptr chain */ - - out->nsc_u.hst.h_aliases = (char **)((int)aliaseslist-offset); - - /* fill out the h_addr list */ - - dest = (char *)(((int)dest + 3) & ~3); - - for (i = 0; i < numaddrs; i++) { - (void) memcpy(dest, in->nsc_u.hst.h_addr_list[i], - in->nsc_u.hst.h_length); - strs = in->nsc_u.hst.h_length; - addrlist[i] = dest - offset; - dest += strs; - dest = (char *)(((int)dest + 3) & ~3); - } - - addrlist[i] = 0; /* null term ptr chain */ - - out->nsc_u.hst.h_addr_list = (char **)((int)addrlist-offset); - - out->nsc_u.hst.h_length = in->nsc_u.hst.h_length; - out->nsc_u.hst.h_addrtype = in->nsc_u.hst.h_addrtype; - - (void) memcpy(in, &(retb->nsc_data), - retb->nsc_data.nsc_bufferbytesused); - - return (retb); - -} - -void -getnode_nam_reaper() -{ - nsc_reaper("getnode_nam", nnam_hash, ¤t_admin.node, &node_lock); -} - -void -getnode_addr_reaper() -{ - nsc_reaper("getnode_addr", addr_hash, ¤t_admin.node, &node_lock); +ipname_getlogstr(char *name, char *whoami, size_t len, nss_XbyY_args_t *argp) { + (void) snprintf(whoami, len, "%s [key=%s:af=%d:flags=%d]", + name, + argp->key.ipnode.name, + argp->key.ipnode.af_family, + argp->key.ipnode.flags); } diff --git a/usr/src/cmd/nscd/getprinter.c b/usr/src/cmd/nscd/getprinter.c new file mode 100644 index 0000000000..d5d82fc3c5 --- /dev/null +++ b/usr/src/cmd/nscd/getprinter.c @@ -0,0 +1,47 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * Routines to handle getprinter* calls in nscd + */ + +#include "cache.h" + +#define nam_db ctx->nsc_db[0] + +#define NSC_NAME_PRINTERS_BYNAME "getprinterbyname" + +void +printer_init_ctx(nsc_ctx_t *ctx) { + ctx->dbname = NSS_DBNAM_PRINTERS; + ctx->file_name = "/etc/printers.conf"; + ctx->db_count = 1; + nam_db = make_cache(nsc_key_ces, + NSS_DBOP_PRINTERS_BYNAME, + NSC_NAME_PRINTERS_BYNAME, + NULL, NULL, NULL, nsc_ht_default, -1); +} diff --git a/usr/src/cmd/nscd/getprof.c b/usr/src/cmd/nscd/getprof.c index ad171d027c..e7f796a3e1 100644 --- a/usr/src/cmd/nscd/getprof.c +++ b/usr/src/cmd/nscd/getprof.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2003 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -30,479 +29,18 @@ * Routines to handle getprof* calls in nscd */ -#include <assert.h> -#include <errno.h> -#include <memory.h> -#include <signal.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <sys/door.h> -#include <sys/stat.h> -#include <sys/time.h> -#include <sys/types.h> -#include <sys/wait.h> -#include <thread.h> -#include <unistd.h> -#include <ucred.h> -#include <nss_common.h> +#include "cache.h" -#include <prof_attr.h> - -#include <getxby_door.h> -#include "server_door.h" -#include "nscd.h" - -extern profstr_t *_getprofnam(const char *, profstr_t *, char *, int, int *); - -static hash_t *nam_hash; -static mutex_t db_lock = DEFAULTMUTEX; -static waiter_t db_wait; - -static void getprof_namekeepalive(int keep, int interval); -static void update_prof_bucket(nsc_bucket_t **old, nsc_bucket_t *new, - int callnumber); -static nsc_bucket_t *fixbuffer(nsc_return_t *in, int maxlen); -static void do_findgnams(nsc_bucket_t *ptr, int *table, char *gnam); -static void do_invalidate(nsc_bucket_t **ptr, int callnumber); -static void getprof_invalidate_unlocked(void); - -void -getprof_init(void) -{ - nam_hash = make_hash(current_admin.prof.nsc_suggestedsize); -} - -static void -do_invalidate(nsc_bucket_t ** ptr, int callnumber) -{ - if (*ptr != NULL && *ptr != (nsc_bucket_t *)-1) { - /* leave pending calls alone */ - update_prof_bucket(ptr, NULL, callnumber); - } -} - -static void -do_findgnams(nsc_bucket_t *ptr, int *table, char *gnam) -{ - - /* - * be careful with ptr - it may be -1 or NULL. - */ - - if (ptr != NULL && ptr != (nsc_bucket_t *)-1) { - char *tmp = (char *)insertn(table, ptr->nsc_hits, - (int)strdup(gnam)); - if (tmp != (char *)-1) - free(tmp); - } -} - -void -getprof_revalidate(void) -{ - for (;;) { - int slp; - int interval; - int count; - - slp = current_admin.prof.nsc_pos_ttl; - - if (slp < 60) { - slp = 60; - } - - if ((count = current_admin.prof.nsc_keephot) != 0) { - interval = (slp / 2)/count; - if (interval == 0) interval = 1; - sleep(slp * 2 / 3); - getprof_namekeepalive(count, interval); - } else { - sleep(slp); - } - } -} - -static void -getprof_namekeepalive(int keep, int interval) -{ - int *table; - union { - nsc_data_t ping; - char space[sizeof (nsc_data_t) + NSCDMAXNAMELEN]; - } u; - - int i; - - if (!keep) - return; - - table = maken(keep); - mutex_lock(&db_lock); - operate_hash(nam_hash, do_findgnams, (char *)table); - mutex_unlock(&db_lock); - - for (i = 1; i <= keep; i++) { - char *tmp; - u.ping.nsc_call.nsc_callnumber = GETPROFNAM; - - if ((tmp = (char *)table[keep + 1 + i]) == (char *)-1) - continue; /* unused slot in table */ - - strcpy(u.ping.nsc_call.nsc_u.name, tmp); - - launch_update(&u.ping.nsc_call); - sleep(interval); - } - - for (i = 1; i <= keep; i++) { - char *tmp; - if ((tmp = (char *)table[keep + 1 + i]) != (char *)-1) - free(tmp); - } - - free(table); -} - - -/* - * This routine marks all entries as invalid - * - */ - -void -getprof_invalidate(void) -{ - mutex_lock(&db_lock); - getprof_invalidate_unlocked(); - mutex_unlock(&db_lock); -} - -static void -getprof_invalidate_unlocked(void) -{ - operate_hash_addr(nam_hash, do_invalidate, (char *)GETPROFNAM); - current_admin.prof.nsc_invalidate_count++; -} - -void -getprof_lookup(nsc_return_t *out, int maxsize, nsc_call_t *in, time_t now) -{ - int out_of_date; - nsc_bucket_t *retb; - char **bucket; - - static time_t lastmod; - - int bufferspace = maxsize - sizeof (nsc_return_t); - - if (current_admin.prof.nsc_enabled == 0) { - out->nsc_return_code = NOSERVER; - out->nsc_bufferbytesused = sizeof (*out); - return; - } - - mutex_lock(&db_lock); - - if (current_admin.prof.nsc_check_files) { - struct stat buf; - - if (stat(PROFATTR_FILENAME, &buf) < 0) { - /*EMPTY*/; - } else if (lastmod == 0) { - lastmod = buf.st_mtime; - } else if (lastmod < buf.st_mtime) { - getprof_invalidate_unlocked(); - lastmod = buf.st_mtime; - } - } - - if (current_admin.debug_level >= DBG_ALL) { - logit("getprof_lookup: looking for name %s\n", - in->nsc_u.name); - } - - for (;;) { - if (attr_strlen(in->nsc_u.name) > NSCDMAXNAMELEN) { - ucred_t *uc = NULL; - - if (door_ucred(&uc) != 0) { - logit("getprof_lookup: Name too long, " - "but no user credential: %s\n", - strerror(errno)); - } else { - logit("getprof_lookup: Name too long " - "from pid %d uid %d\n", - ucred_getpid(uc), - ucred_getruid(uc)); - ucred_free(uc); - } - - out->nsc_errno = NSS_NOTFOUND; - out->nsc_return_code = NOTFOUND; - out->nsc_bufferbytesused = sizeof (*out); - goto getout; - } - bucket = get_hash(nam_hash, in->nsc_u.name); - - if (*bucket == (char *)-1) { /* pending lookup */ - if (get_clearance(in->nsc_callnumber) != 0) { - /* no threads available */ - out->nsc_return_code = NOSERVER; - /* cannot process now */ - out->nsc_bufferbytesused = - sizeof (*out); - current_admin.prof.nsc_throttle_count++; - goto getout; - } - nscd_wait(&db_wait, &db_lock, bucket); - release_clearance(in->nsc_callnumber); - continue; /* go back and relookup hash bucket */ - } - break; - } - - /* - * check for no name_service mode - */ - - if (*bucket == NULL && current_admin.avoid_nameservice) { - out->nsc_return_code = NOTFOUND; - out->nsc_bufferbytesused = sizeof (*out); - } else if ((*bucket == NULL) || /* New entry in name service */ - (in->nsc_callnumber & UPDATEBIT) || /* needs updating */ - (out_of_date = (!current_admin.avoid_nameservice && - (current_admin.prof.nsc_old_data_ok == 0) && - (((nsc_bucket_t *)*bucket)->nsc_timestamp < now)))) { - /* time has expired */ - int saved_errno; - int saved_hits = 0; - profstr_t *p; - - if (get_clearance(in->nsc_callnumber) != 0) { - /* no threads available */ - out->nsc_return_code = NOSERVER; - /* cannot process now */ - out->nsc_bufferbytesused = sizeof (*out); - current_admin.prof.nsc_throttle_count++; - goto getout; - } - - if (*bucket != NULL) { - saved_hits = - ((nsc_bucket_t *)*bucket)->nsc_hits; - } - - /* - * block any threads accessing this bucket if data is - * non-existent out of date - */ - - if (*bucket == NULL || out_of_date) { - update_prof_bucket((nsc_bucket_t **)bucket, - (nsc_bucket_t *)-1, in->nsc_callnumber); - } else { - /* - * if still not -1 bucket we are doing update... - * mark to prevent - * pileups of threads if the name service is hanging.... - */ - ((nsc_bucket_t *)(*bucket))->nsc_status |= - ST_UPDATE_PENDING; - /* cleared by deletion of old data */ - } - mutex_unlock(&db_lock); - - /* - * Call non-caching version in libnsl. - */ - p = _getprofnam(in->nsc_u.name, &out->nsc_u.prof, - out->nsc_u.buff + sizeof (profstr_t), - bufferspace, &errno); - saved_errno = errno; - - mutex_lock(&db_lock); - - release_clearance(in->nsc_callnumber); - - if (p == NULL) { /* data not found */ - - if (current_admin.debug_level >= DBG_CANT_FIND) { - logit("getprof_lookup: nscd COULDN'T FIND prof_attr name %s\n", - in->nsc_u.name); - } - - if (!(UPDATEBIT & in->nsc_callnumber)) - current_admin.prof.nsc_neg_cache_misses++; - - retb = (nsc_bucket_t *)malloc(sizeof (nsc_bucket_t)); - - retb->nsc_refcount = 1; - retb->nsc_data.nsc_bufferbytesused = - sizeof (nsc_return_t); - retb->nsc_data.nsc_return_code = NOTFOUND; - retb->nsc_data.nsc_errno = saved_errno; - memcpy(out, &retb->nsc_data, - retb->nsc_data.nsc_bufferbytesused); - update_prof_bucket((nsc_bucket_t **)bucket, - retb, in->nsc_callnumber); - goto getout; - } else { - if (current_admin.debug_level >= DBG_ALL) { - logit("getprof_lookup: nscd FOUND prof_attr name %s\n", - in->nsc_u.name); - } - if (!(UPDATEBIT & in->nsc_callnumber)) - current_admin.prof.nsc_pos_cache_misses++; - - retb = fixbuffer(out, bufferspace); - update_prof_bucket((nsc_bucket_t **)bucket, - retb, in->nsc_callnumber); - if (saved_hits) - retb->nsc_hits = saved_hits; - } - } else { /* found entry in cache */ - retb = (nsc_bucket_t *)*bucket; - - retb->nsc_hits++; - - memcpy(out, &(retb->nsc_data), - retb->nsc_data.nsc_bufferbytesused); - - if (out->nsc_return_code == SUCCESS) { - if (!(UPDATEBIT & in->nsc_callnumber)) - current_admin.prof.nsc_pos_cache_hits++; - if (current_admin.debug_level >= DBG_ALL) { - logit("getprof_lookup: found name %s in cache\n", - in->nsc_u.name); - } - } else { - if (!(UPDATEBIT & in->nsc_callnumber)) - current_admin.prof.nsc_neg_cache_hits++; - if (current_admin.debug_level >= DBG_ALL) { - logit("getprof_lookup: %s marked as NOT FOUND in cache.\n", - in->nsc_u.name); - } - } - - if ((retb->nsc_timestamp < now) && - !(in->nsc_callnumber & UPDATEBIT) && - !(retb->nsc_status & ST_UPDATE_PENDING)) { - logit("launch update since time = %d\n", retb->nsc_timestamp); - retb->nsc_status |= ST_UPDATE_PENDING; - /* cleared by deletion of old data */ - launch_update(in); - } - } - -getout: - mutex_unlock(&db_lock); -} - -/*ARGSUSED*/ -static void -update_prof_bucket(nsc_bucket_t **old, nsc_bucket_t *new, int callnumber) -{ - if (*old != NULL && *old != (nsc_bucket_t *)-1) { /* old data exists */ - free(*old); - current_admin.prof.nsc_entries--; - } - - /* - * we can do this before reseting *old since we're holding the lock - */ - - else if (*old == (nsc_bucket_t *)-1) { - nscd_signal(&db_wait, (char **)old); - } - - *old = new; - - if ((new != NULL) && (new != (nsc_bucket_t *)-1)) { - /* real data, not just update pending or invalidate */ - new->nsc_hits = 1; - new->nsc_status = 0; - new->nsc_refcount = 1; - current_admin.prof.nsc_entries++; - - if (new->nsc_data.nsc_return_code == SUCCESS) { - new->nsc_timestamp = time(NULL) + - current_admin.prof.nsc_pos_ttl; - } else { - new->nsc_timestamp = time(NULL) + - current_admin.prof.nsc_neg_ttl; - } - } -} - -/*ARGSUSED*/ -static nsc_bucket_t * -fixbuffer(nsc_return_t *in, int maxlen) -{ - nsc_bucket_t *retb; - nsc_return_t *out; - char *dest; - int offset; - int strs; - - /* - * find out the size of the data block we're going to need - */ - - strs = attr_strlen(in->nsc_u.prof.name) + - attr_strlen(in->nsc_u.prof.res1) + - attr_strlen(in->nsc_u.prof.res2) + - attr_strlen(in->nsc_u.prof.desc) + - attr_strlen(in->nsc_u.prof.attr) + PROFATTR_DB_NCOL; - - /* - * allocate it and copy it in - * code doesn't assume packing order in original buffer - */ - - if ((retb = (nsc_bucket_t *)malloc(sizeof (*retb) + strs)) == NULL) { - return (NULL); - } - - out = &(retb->nsc_data); - out->nsc_bufferbytesused = strs + ((int)&out->nsc_u.prof - (int)out) + - sizeof (profstr_t); - out->nsc_return_code = SUCCESS; - out->nsc_errno = 0; - - dest = retb->nsc_data.nsc_u.buff + sizeof (profstr_t); - offset = (int)dest; - - attr_strcpy(dest, in->nsc_u.prof.name); - strs = 1 + attr_strlen(in->nsc_u.prof.name); - out->nsc_u.prof.name = dest - offset; - dest += strs; - - attr_strcpy(dest, in->nsc_u.prof.res1); - strs = 1 + attr_strlen(in->nsc_u.prof.res1); - out->nsc_u.prof.res1 = dest - offset; - dest += strs; - - attr_strcpy(dest, in->nsc_u.prof.res2); - strs = 1 + attr_strlen(in->nsc_u.prof.res2); - out->nsc_u.prof.res2 = dest - offset; - dest += strs; - - attr_strcpy(dest, in->nsc_u.prof.desc); - strs = 1 + attr_strlen(in->nsc_u.prof.desc); - out->nsc_u.prof.desc = dest - offset; - dest += strs; - - attr_strcpy(dest, in->nsc_u.prof.attr); - out->nsc_u.prof.attr = dest - offset; - - memcpy(in, out, out->nsc_bufferbytesused); - - return (retb); -} +#define nam_db ctx->nsc_db[0] +#define NSC_NAME_PROFATTR_BYNAME "getprofnam" void -getprof_reaper(void) -{ - nsc_reaper("getprof", nam_hash, ¤t_admin.prof, &db_lock); +prof_init_ctx(nsc_ctx_t *ctx) { + ctx->dbname = NSS_DBNAM_PROFATTR; + ctx->file_name = "/etc/security/prof_attr"; + ctx->db_count = 1; + nam_db = make_cache(nsc_key_ces, + NSS_DBOP_PROFATTR_BYNAME, + NSC_NAME_PROFATTR_BYNAME, + NULL, NULL, NULL, nsc_ht_default, -1); } diff --git a/usr/src/cmd/nscd/getproject.c b/usr/src/cmd/nscd/getproject.c new file mode 100644 index 0000000000..76ca1e9063 --- /dev/null +++ b/usr/src/cmd/nscd/getproject.c @@ -0,0 +1,80 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * Routines to handle getproj* calls in nscd + */ + +#include <stdlib.h> +#include "cache.h" + +#define nam_db ctx->nsc_db[0] +#define pid_db ctx->nsc_db[1] + +#define NSC_NAME_PROJECT_BYNAME "getprojbyname" +#define NSC_NAME_PROJECT_BYID "getprojbyid" + +static void projid_getlogstr(char *, char *, size_t, nss_XbyY_args_t *); +static int projid_compar(const void *, const void *); +static uint_t projid_gethash(nss_XbyY_key_t *, int); + +void +project_init_ctx(nsc_ctx_t *ctx) { + ctx->dbname = NSS_DBNAM_PROJECT; + ctx->file_name = "/etc/project"; + ctx->db_count = 2; + nam_db = make_cache(nsc_key_ces, + NSS_DBOP_PROJECT_BYNAME, + NSC_NAME_PROJECT_BYNAME, + NULL, NULL, NULL, nsc_ht_default, -1); + + pid_db = make_cache(nsc_key_other, + NSS_DBOP_PROJECT_BYID, + NSC_NAME_PROJECT_BYID, + projid_compar, + projid_getlogstr, + projid_gethash, nsc_ht_default, -1); +} + +static int +projid_compar(const void *n1, const void *n2) { + nsc_entry_t *e1, *e2; + + e1 = (nsc_entry_t *)n1; + e2 = (nsc_entry_t *)n2; + return (_NSC_INT_KEY_CMP(e1->key.projid, e2->key.projid)); +} + +static uint_t +projid_gethash(nss_XbyY_key_t *key, int htsize) { + return (db_gethash(&key->projid, sizeof (key->projid), htsize)); +} + +static void +projid_getlogstr(char *name, char *whoami, size_t len, nss_XbyY_args_t *argp) { + (void) snprintf(whoami, len, "%s [key=%d]", name, argp->key.projid); +} diff --git a/usr/src/cmd/nscd/getproto.c b/usr/src/cmd/nscd/getproto.c new file mode 100644 index 0000000000..d7605da680 --- /dev/null +++ b/usr/src/cmd/nscd/getproto.c @@ -0,0 +1,54 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * Routines to handle getprotoby* calls in nscd + */ + +#include "cache.h" + +#define nam_db ctx->nsc_db[0] +#define num_db ctx->nsc_db[1] + +#define NSC_NAME_PROTOCOLS_BYNAME "getprotobyname" +#define NSC_NAME_PROTOCOLS_BYNUMBER "getprotobynumber" + +void +proto_init_ctx(nsc_ctx_t *ctx) { + ctx->dbname = NSS_DBNAM_PROTOCOLS; + ctx->file_name = "/etc/inet/protocols"; + ctx->db_count = 2; + nam_db = make_cache(nsc_key_ces, + NSS_DBOP_PROTOCOLS_BYNAME, + NSC_NAME_PROTOCOLS_BYNAME, + NULL, NULL, NULL, nsc_ht_default, -1); + + num_db = make_cache(nsc_key_int, + NSS_DBOP_PROTOCOLS_BYNUMBER, + NSC_NAME_PROTOCOLS_BYNUMBER, + NULL, NULL, NULL, nsc_ht_default, -1); +} diff --git a/usr/src/cmd/nscd/getpw.c b/usr/src/cmd/nscd/getpw.c index cd38871554..645861e733 100644 --- a/usr/src/cmd/nscd/getpw.c +++ b/usr/src/cmd/nscd/getpw.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2003 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -30,644 +29,54 @@ * Routines to handle getpw* calls in nscd */ -#include <assert.h> -#include <errno.h> -#include <memory.h> -#include <signal.h> #include <stdlib.h> -#include <stdio.h> -#include <string.h> -#include <sys/door.h> -#include <sys/stat.h> -#include <sys/time.h> -#include <sys/types.h> -#include <sys/wait.h> -#include <thread.h> -#include <unistd.h> -#include <nss_common.h> -#include <ucred.h> +#include "cache.h" -#include "getxby_door.h" -#include "server_door.h" - -#include "nscd.h" - -static hash_t *uid_hash; -static hash_t *nam_hash; -static mutex_t passwd_lock = DEFAULTMUTEX; -static waiter_t passwd_wait; - -static void getpw_invalidate_unlocked(void); -static void getpw_namekeepalive(int keep, int interval); -static void getpw_uidkeepalive(int keep, int interval); -static void update_pw_bucket(nsc_bucket_t **old, nsc_bucket_t *new, - int callnumber); -static nsc_bucket_t *fixbuffer(nsc_return_t *in, int maxlen); -static void do_findnams(nsc_bucket_t *ptr, int *table, char *name); -static void do_finduids(nsc_bucket_t *ptr, int *table, int uid); -static void do_invalidate(nsc_bucket_t **ptr, int callnumber); - -void -getpw_init(void) -{ - uid_hash = make_ihash(current_admin.passwd.nsc_suggestedsize); - nam_hash = make_hash(current_admin.passwd.nsc_suggestedsize); -} - -static void -do_invalidate(nsc_bucket_t ** ptr, int callnumber) -{ - if (*ptr != NULL && *ptr != (nsc_bucket_t *)-1) { - /* leave pending calls alone */ - update_pw_bucket(ptr, NULL, callnumber); - } -} - -static void -do_finduids(nsc_bucket_t *ptr, int *table, int uid) -{ - - /* - * be careful with ptr - it may be -1 or NULL. - */ - if (ptr != NULL && ptr != (nsc_bucket_t *)-1) { - insertn(table, ptr->nsc_hits, uid); - } -} - -static void -do_findnams(nsc_bucket_t *ptr, int *table, char *name) -{ - - /* - * be careful with ptr - it may be -1 or NULL. - */ - if (ptr != NULL && ptr != (nsc_bucket_t *)-1) { - char *tmp = (char *)insertn(table, ptr->nsc_hits, - (int)strdup(name)); - if (tmp != (char *)-1) - free(tmp); - } -} +#define nam_db ctx->nsc_db[0] +#define uid_db ctx->nsc_db[1] +#define NSC_NAME_PASSWD_BYNAME "getpwnam" +#define NSC_NAME_PASSWD_BYUID "getpwuid" +static void pwuid_getlogstr(char *, char *, size_t, nss_XbyY_args_t *); +static int pwuid_compar(const void *, const void *); +static uint_t pwuid_gethash(nss_XbyY_key_t *, int); void -getpw_revalidate(void) -{ - for (;;) { - int slp; - int interval; - int count; - - slp = current_admin.passwd.nsc_pos_ttl; - - if (slp < 60) { - slp = 60; - } - - if ((count = current_admin.passwd.nsc_keephot) != 0) { - interval = (slp / 2)/count; - if (interval == 0) interval = 1; - sleep(slp * 2 / 3); - getpw_uidkeepalive(count, interval); - getpw_namekeepalive(count, interval); - } else { - sleep(slp); - } - } -} - -static void -getpw_uidkeepalive(int keep, int interval) -{ - int *table; - nsc_data_t ping; - int i; - - if (!keep) - return; - - table = maken(keep); - mutex_lock(&passwd_lock); - operate_hash(uid_hash, do_finduids, (char *)table); - mutex_unlock(&passwd_lock); - - for (i = 1; i <= keep; i++) { - ping.nsc_call.nsc_callnumber = GETPWUID; - if ((ping.nsc_call.nsc_u.uid = table[keep + 1 + i]) == -1) - continue; /* unused slot in table */ - launch_update(&ping.nsc_call); - sleep(interval); - } - free(table); +passwd_init_ctx(nsc_ctx_t *ctx) { + ctx->dbname = NSS_DBNAM_PASSWD; + ctx->file_name = "/etc/passwd"; + ctx->db_count = 2; + ctx->cfg.pos_ttl = 600; + nam_db = make_cache(nsc_key_ces, + NSS_DBOP_PASSWD_BYNAME, + NSC_NAME_PASSWD_BYNAME, + NULL, NULL, + NULL, nsc_ht_default, -1); + + uid_db = make_cache(nsc_key_other, + NSS_DBOP_PASSWD_BYUID, + NSC_NAME_PASSWD_BYUID, + pwuid_compar, + pwuid_getlogstr, + pwuid_gethash, nsc_ht_default, -1); } +static int +pwuid_compar(const void *n1, const void *n2) { + nsc_entry_t *e1, *e2; -static void -getpw_namekeepalive(int keep, int interval) -{ - int *table; - union { - nsc_data_t ping; - char space[sizeof (nsc_data_t) + NSCDMAXNAMELEN]; - } u; - - int i; - - if (!keep) - return; - - table = maken(keep); - mutex_lock(&passwd_lock); - operate_hash(nam_hash, do_findnams, (char *)table); - mutex_unlock(&passwd_lock); - - for (i = 1; i <= keep; i++) { - char *tmp; - u.ping.nsc_call.nsc_callnumber = GETPWNAM; - - if ((tmp = (char *)table[keep + 1 + i]) == (char *)-1) - continue; /* unused slot in table */ - - strcpy(u.ping.nsc_call.nsc_u.name, tmp); - - launch_update(&u.ping.nsc_call); - sleep(interval); - } - - for (i = 1; i <= keep; i++) { - char *tmp; - if ((tmp = (char *)table[keep + 1 + i]) != (char *)-1) - free(tmp); - } - - free(table); + e1 = (nsc_entry_t *)n1; + e2 = (nsc_entry_t *)n2; + return (_NSC_INT_KEY_CMP(e1->key.uid, e2->key.uid)); } - - - -/* - * This routine marks all entries as invalid - * - */ -void -getpw_invalidate(void) -{ - mutex_lock(&passwd_lock); - getpw_invalidate_unlocked(); - mutex_unlock(&passwd_lock); +static uint_t +pwuid_gethash(nss_XbyY_key_t *key, int htsize) { + return (key->uid % htsize); } static void -getpw_invalidate_unlocked(void) -{ - operate_hash_addr(nam_hash, do_invalidate, (char *)GETPWNAM); - operate_hash_addr(uid_hash, do_invalidate, (char *)GETPWUID); - current_admin.passwd.nsc_invalidate_count++; -} - -void -getpw_lookup(nsc_return_t *out, int maxsize, nsc_call_t *in, time_t now) -{ - int out_of_date; - nsc_bucket_t *retb; - char **bucket; - - static time_t lastmod; - - int bufferspace = maxsize - sizeof (nsc_return_t); - - if (current_admin.passwd.nsc_enabled == 0) { - out->nsc_return_code = NOSERVER; - out->nsc_bufferbytesused = sizeof (*out); - return; - } - - mutex_lock(&passwd_lock); - - if (current_admin.passwd.nsc_check_files) { - struct stat buf; - - if (stat("/etc/passwd", &buf) < 0) { - /*EMPTY*/; - } else if (lastmod == 0) { - lastmod = buf.st_mtime; - } else if (lastmod < buf.st_mtime) { - getpw_invalidate_unlocked(); - lastmod = buf.st_mtime; - } - } - - if (current_admin.debug_level >= DBG_ALL) { - if (MASKUPDATEBIT(in->nsc_callnumber) == GETPWUID) { - logit("getpw_lookup: looking for uid %d\n", - in->nsc_u.uid); - } else { - logit("getpw_lookup: looking for name %s\n", - in->nsc_u.name); - } - } - - for (;;) { - if (MASKUPDATEBIT(in->nsc_callnumber) == GETPWUID) { - bucket = get_hash(uid_hash, (char *)in->nsc_u.uid); - } else { /* make reasonableness check here */ - if (strlen(in->nsc_u.name) > NSCDMAXNAMELEN) { - ucred_t *uc = NULL; - - if (door_ucred(&uc) != 0) { - logit("getpw_lookup: Name too long, " - "but no user credential: %s\n", - strerror(errno)); - } else { - - logit("getpw_lookup: Name too long " - "from pid %d uid %d\n", - ucred_getpid(uc), - ucred_getruid(uc)); - ucred_free(uc); - } - - - out->nsc_errno = NSS_NOTFOUND; - out->nsc_return_code = NOTFOUND; - out->nsc_bufferbytesused = sizeof (*out); - goto getout; - } - bucket = get_hash(nam_hash, in->nsc_u.name); - } - - if (*bucket == (char *)-1) { /* pending lookup */ - if (get_clearance(in->nsc_callnumber) != 0) { - /* no threads available */ - out->nsc_return_code = NOSERVER; - /* cannot process now */ - out->nsc_bufferbytesused = sizeof (*out); - current_admin.passwd.nsc_throttle_count++; - goto getout; - } - nscd_wait(&passwd_wait, &passwd_lock, bucket); - release_clearance(in->nsc_callnumber); - continue; /* go back and relookup hash bucket */ - } - break; - } - - /* - * check for no name_service mode - */ - - if (*bucket == NULL && current_admin.avoid_nameservice) { - out->nsc_return_code = NOTFOUND; - out->nsc_bufferbytesused = sizeof (*out); - } else if (*bucket == NULL || - (in->nsc_callnumber & UPDATEBIT) || - (out_of_date = (!current_admin.avoid_nameservice && - (current_admin.passwd.nsc_old_data_ok == 0) && - (((nsc_bucket_t *)*bucket)->nsc_timestamp < now)))) { - /* - * time has expired - */ - int saved_errno; - int saved_hits = 0; - struct passwd *p; - - if (get_clearance(in->nsc_callnumber) != 0) { - /* no threads available */ - out->nsc_return_code = NOSERVER; - /* cannot process now */ - out->nsc_bufferbytesused = sizeof (*out); - current_admin.passwd.nsc_throttle_count++; - goto getout; - } - if (*bucket != NULL) { - saved_hits = ((nsc_bucket_t *)*bucket)->nsc_hits; - } - - /* - * block any threads accessing this bucket if data - * is non-existent or out of date - */ - - if (*bucket == NULL || out_of_date) { - update_pw_bucket((nsc_bucket_t **)bucket, - (nsc_bucket_t *)-1, - in->nsc_callnumber); - } else { - /* - * if still not -1 bucket we are doing - * update... mark to prevent pileups of threads if - * the name service is hanging.. - */ - ((nsc_bucket_t *)(*bucket))->nsc_status |= - ST_UPDATE_PENDING; - /* cleared by deletion of old data */ - } - mutex_unlock(&passwd_lock); - - if (MASKUPDATEBIT(in->nsc_callnumber) == GETPWUID) { - p = _uncached_getpwuid_r(in->nsc_u.uid, &out->nsc_u.pwd, - out->nsc_u.buff+sizeof (struct passwd), - bufferspace); - saved_errno = errno; - } else { - p = _uncached_getpwnam_r(in->nsc_u.name, - &out->nsc_u.pwd, - out->nsc_u.buff+sizeof (struct passwd), - bufferspace); - saved_errno = errno; - } - - mutex_lock(&passwd_lock); - - release_clearance(in->nsc_callnumber); - - if (p == NULL) { /* data not found */ - if (current_admin.debug_level >= DBG_CANT_FIND) { - if (MASKUPDATEBIT(in->nsc_callnumber) == - GETPWUID) { - logit("getpw_lookup: nscd COULDN'T FIND uid %d\n", - in->nsc_u.uid); - } else { - logit("getpw_lookup: nscd COULDN'T FIND passwd name %s\n", - in->nsc_u.name); - } - } - - if (!(UPDATEBIT & in->nsc_callnumber)) - current_admin.passwd.nsc_neg_cache_misses++; - - retb = (nsc_bucket_t *)malloc(sizeof (nsc_bucket_t)); - - retb->nsc_refcount = 1; - retb->nsc_data.nsc_bufferbytesused = - sizeof (nsc_return_t); - retb->nsc_data.nsc_return_code = NOTFOUND; - retb->nsc_data.nsc_errno = saved_errno; - memcpy(out, &retb->nsc_data, - retb->nsc_data.nsc_bufferbytesused); - update_pw_bucket((nsc_bucket_t **)bucket, retb, - in->nsc_callnumber); - goto getout; - } else { - if (current_admin.debug_level >= DBG_ALL) { - if (MASKUPDATEBIT(in->nsc_callnumber) == - GETPWUID) { - logit("getpw_lookup: nscd FOUND uid %d\n", - in->nsc_u.uid); - } else { - logit("getpw_lookup: nscd FOUND passwd name %s\n", - in->nsc_u.name); - } - } - if (!(UPDATEBIT & in->nsc_callnumber)) - current_admin.passwd.nsc_pos_cache_misses++; - - retb = fixbuffer(out, bufferspace); - update_pw_bucket((nsc_bucket_t **)bucket, - retb, in->nsc_callnumber); - if (saved_hits) - retb->nsc_hits = saved_hits; - } - } else { /* found entry in cache */ - retb = (nsc_bucket_t *)*bucket; - - retb->nsc_hits++; - - memcpy(out, &(retb->nsc_data), - retb->nsc_data.nsc_bufferbytesused); - - if (out->nsc_return_code == SUCCESS) { - if (!(UPDATEBIT & in->nsc_callnumber)) - current_admin.passwd.nsc_pos_cache_hits++; - if (current_admin.debug_level >= DBG_ALL) { - if (MASKUPDATEBIT(in->nsc_callnumber) == - GETPWUID) { - logit("getpw_lookup: found uid %d in cache\n", - in->nsc_u.uid); - } else { - logit("getpw_lookup: found name %s in cache\n", - in->nsc_u.name); - } - } - } else { - if (!(UPDATEBIT & in->nsc_callnumber)) - current_admin.passwd.nsc_neg_cache_hits++; - if (current_admin.debug_level >= DBG_ALL) { - if (MASKUPDATEBIT(in->nsc_callnumber) == - GETPWUID) { - logit("getpw_lookup: %d marked as NOT FOUND in cache.\n", - in->nsc_u.uid); - } else { - logit("getpw_lookup: %s marked as NOT FOUND in cache.\n", - in->nsc_u.name); - } - } - } - - if ((retb->nsc_timestamp < now) && - !(in->nsc_callnumber & UPDATEBIT) && - !(retb->nsc_status & ST_UPDATE_PENDING)) { - logit("launch update since time = %d\n", - retb->nsc_timestamp); - retb->nsc_status |= ST_UPDATE_PENDING; - /* cleared by deletion of old data */ - launch_update(in); - } - } - -getout: - - mutex_unlock(&passwd_lock); - - /* - * secure mode check - blank out passwd if call sucessfull - * and caller != effective id - */ - if ((current_admin.passwd.nsc_secure_mode != 0) && - (out->nsc_return_code == SUCCESS) && - !(UPDATEBIT & in->nsc_callnumber)) { - - ucred_t *uc = NULL; - - if (door_ucred(&uc) != 0) { - perror("door_ucred"); - } else { - if (ucred_geteuid(uc) != out->nsc_u.pwd.pw_uid) { - /* - * write *NP* into passwd field if - * not already that way... we fixed - * the buffer code so there's always room. - */ - int len; - - char *foo = out->nsc_u.buff - + sizeof (struct passwd) - + (int)out->nsc_u.pwd.pw_passwd; - - len = strlen(foo); - if (len > 0 && - strcmp(foo, "*NP*") != 0 && - strcmp(foo, "x") != 0) { - if (len < 5) - len = 5; - strncpy(foo, "*NP*", len); - /* - * strncpy will - * blank all - */ - } - } - ucred_free(uc); - } - } -} - -/*ARGSUSED*/ -static void -update_pw_bucket(nsc_bucket_t **old, nsc_bucket_t *new, int callnumber) -{ - if (*old != NULL && *old != (nsc_bucket_t *)-1) { - /* old data exists */ - free(*old); - current_admin.passwd.nsc_entries--; - } - - /* - * we can do this before reseting *old since we're holding the lock - */ - - else if (*old == (nsc_bucket_t *)-1) { - nscd_signal(&passwd_wait, (char **)old); - } - - - - *old = new; - - if ((new != NULL) && - (new != (nsc_bucket_t *)-1)) { - /* real data, not just update pending or invalidate */ - - new->nsc_hits = 1; - new->nsc_status = 0; - new->nsc_refcount = 1; - current_admin.passwd.nsc_entries++; - - if (new->nsc_data.nsc_return_code == SUCCESS) { - new->nsc_timestamp = time(NULL) + - current_admin.passwd.nsc_pos_ttl; - } else { - new->nsc_timestamp = time(NULL) + - current_admin.passwd.nsc_neg_ttl; - } - } -} - - -/*ARGSUSED*/ -static nsc_bucket_t * -fixbuffer(nsc_return_t *in, int maxlen) -{ - nsc_bucket_t *retb; - char *dest; - - nsc_return_t *out; - int offset; - int strs; - int pwlen; - - /* - * find out the size of the data block we're going to need - */ - - strs = 0; - strs += 1 + strlen(in->nsc_u.pwd.pw_name); - pwlen = strlen(in->nsc_u.pwd.pw_passwd); - if (pwlen < 4) - pwlen = 4; - strs += 1 + pwlen; - strs += 1 + strlen(in->nsc_u.pwd.pw_age); - strs += 1 + strlen(in->nsc_u.pwd.pw_comment); - strs += 1 + strlen(in->nsc_u.pwd.pw_gecos); - strs += 1 + strlen(in->nsc_u.pwd.pw_dir); - strs += 1 + strlen(in->nsc_u.pwd.pw_shell); - - - /* - * allocate it and copy it in - * code doesn't assume packing order in original buffer - */ - - if ((retb = (nsc_bucket_t *)malloc(sizeof (*retb) + strs)) == NULL) { - return (NULL); - } - - out = &(retb->nsc_data); - - - - out->nsc_bufferbytesused = sizeof (*in) + strs; - out->nsc_return_code = SUCCESS; - out->nsc_errno = 0; - - out->nsc_u.pwd.pw_uid = in->nsc_u.pwd.pw_uid; - out->nsc_u.pwd.pw_gid = in->nsc_u.pwd.pw_gid; - - dest = retb->nsc_data.nsc_u.buff + sizeof (struct passwd); - - offset = (int)dest; - - strcpy(dest, in->nsc_u.pwd.pw_name); - strs = 1 + strlen(in->nsc_u.pwd.pw_name); - out->nsc_u.pwd.pw_name = dest - offset; - dest += strs; - - strcpy(dest, in->nsc_u.pwd.pw_passwd); - strs = 1 + pwlen; - out->nsc_u.pwd.pw_passwd = dest - offset; - dest += strs; - - strcpy(dest, in->nsc_u.pwd.pw_age); - strs = 1 + strlen(in->nsc_u.pwd.pw_age); - out->nsc_u.pwd.pw_age = dest - offset; - dest += strs; - - strcpy(dest, in->nsc_u.pwd.pw_comment); - strs = 1 + strlen(in->nsc_u.pwd.pw_comment); - out->nsc_u.pwd.pw_comment = dest - offset; - dest += strs; - - strcpy(dest, in->nsc_u.pwd.pw_gecos); - strs = 1 + strlen(in->nsc_u.pwd.pw_gecos); - out->nsc_u.pwd.pw_gecos = dest - offset; - dest += strs; - - strcpy(dest, in->nsc_u.pwd.pw_dir); - strs = 1 + strlen(in->nsc_u.pwd.pw_dir); - out->nsc_u.pwd.pw_dir = dest - offset; - dest += strs; - - strcpy(dest, in->nsc_u.pwd.pw_shell); - out->nsc_u.pwd.pw_shell = dest - offset; - - memcpy(in, out, retb->nsc_data.nsc_bufferbytesused); - - - return (retb); - -} - -void -getpw_uid_reaper() -{ - nsc_reaper("getpw_uid", uid_hash, ¤t_admin.passwd, &passwd_lock); -} - -void -getpw_nam_reaper() -{ - nsc_reaper("getpw_nam", nam_hash, ¤t_admin.passwd, &passwd_lock); +pwuid_getlogstr(char *name, char *whoami, size_t len, nss_XbyY_args_t *argp) { + (void) snprintf(whoami, len, "%s [key=%d]", name, argp->key.uid); } diff --git a/usr/src/cmd/nscd/getrpc.c b/usr/src/cmd/nscd/getrpc.c new file mode 100644 index 0000000000..aa62dee73f --- /dev/null +++ b/usr/src/cmd/nscd/getrpc.c @@ -0,0 +1,54 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * Routines to handle getrpcby* calls in nscd + */ + +#include "cache.h" + +#define nam_db ctx->nsc_db[0] +#define num_db ctx->nsc_db[1] + +#define NSC_NAME_RPC_BYNAME "getrpcbyname" +#define NSC_NAME_RPC_BYNUMBER "getrpcbynumber" + +void +rpc_init_ctx(nsc_ctx_t *ctx) { + ctx->dbname = NSS_DBNAM_RPC; + ctx->file_name = "/etc/rpc"; + ctx->db_count = 2; + nam_db = make_cache(nsc_key_ces, + NSS_DBOP_RPC_BYNAME, + NSC_NAME_RPC_BYNAME, + NULL, NULL, NULL, nsc_ht_default, -1); + + num_db = make_cache(nsc_key_int, + NSS_DBOP_RPC_BYNUMBER, + NSC_NAME_RPC_BYNUMBER, + NULL, NULL, NULL, nsc_ht_default, -1); +} diff --git a/usr/src/cmd/nscd/getserv.c b/usr/src/cmd/nscd/getserv.c new file mode 100644 index 0000000000..700d5c6bfb --- /dev/null +++ b/usr/src/cmd/nscd/getserv.c @@ -0,0 +1,158 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * Routines to handle getserv* calls in nscd + */ + +#include <strings.h> +#include "cache.h" + + +#define name_db ctx->nsc_db[0] +#define port_db ctx->nsc_db[1] + +#define NSC_NAME_SERVICES_BYNAME "getservbyname" +#define NSC_NAME_SERVICES_BYPORT "getservbyport" + +static void servname_getlogstr(char *, char *, size_t, nss_XbyY_args_t *); +static int servname_compar(const void *, const void *); +static uint_t servname_gethash(nss_XbyY_key_t *, int); + +static void servport_getlogstr(char *, char *, size_t, nss_XbyY_args_t *); +static int servport_compar(const void *, const void *); +static uint_t servport_gethash(nss_XbyY_key_t *, int); + +void +serv_init_ctx(nsc_ctx_t *ctx) { + ctx->dbname = NSS_DBNAM_SERVICES; + ctx->file_name = "/etc/services"; + ctx->db_count = 2; + name_db = make_cache(nsc_key_other, + NSS_DBOP_SERVICES_BYNAME, + NSC_NAME_SERVICES_BYNAME, + servname_compar, + servname_getlogstr, + servname_gethash, nsc_ht_default, -1); + + port_db = make_cache(nsc_key_other, + NSS_DBOP_SERVICES_BYPORT, + NSC_NAME_SERVICES_BYPORT, + servport_compar, + servport_getlogstr, + servport_gethash, nsc_ht_default, -1); +} + +static int +servname_compar(const void *n1, const void *n2) { + nsc_entry_t *e1, *e2; + int res, l1, l2; + + e1 = (nsc_entry_t *)n1; + e2 = (nsc_entry_t *)n2; + + /* compare protocol */ + if (e1->key.serv.proto == NULL && e2->key.serv.proto) + return (-1); + if (e1->key.serv.proto && e2->key.serv.proto == NULL) + return (1); + if (e1->key.serv.proto) { + l1 = strlen(e1->key.serv.proto); + l2 = strlen(e2->key.serv.proto); + res = strncmp(e1->key.serv.proto, e2->key.serv.proto, + (l1 > l2)?l1:l2); + if (res > 0) + return (1); + if (res < 0) + return (-1); + } + + /* compare service name */ + l1 = strlen(e1->key.serv.serv.name); + l2 = strlen(e2->key.serv.serv.name); + res = strncmp(e1->key.serv.serv.name, e2->key.serv.serv.name, + (l1 > l2)?l1:l2); + return (_NSC_INT_KEY_CMP(res, 0)); +} + +static uint_t +servname_gethash(nss_XbyY_key_t *key, int htsize) { + return (ces_gethash(key->serv.serv.name, htsize)); +} + +static void +servname_getlogstr(char *name, char *whoami, size_t len, + nss_XbyY_args_t *argp) { + (void) snprintf(whoami, len, "%s [key=%s, %s]", + name, + argp->key.serv.serv.name, + check_null(argp->key.serv.proto)); +} + +static int +servport_compar(const void *n1, const void *n2) { + nsc_entry_t *e1, *e2; + int res, l1, l2; + + e1 = (nsc_entry_t *)n1; + e2 = (nsc_entry_t *)n2; + + /* compare protocol */ + if (e1->key.serv.proto == NULL && e2->key.serv.proto) + return (-1); + if (e1->key.serv.proto && e2->key.serv.proto == NULL) + return (1); + if (e1->key.serv.proto) { + l1 = strlen(e1->key.serv.proto); + l2 = strlen(e2->key.serv.proto); + res = strncmp(e1->key.serv.proto, e2->key.serv.proto, + (l1 > l2)?l1:l2); + if (res > 0) + return (1); + if (res < 0) + return (-1); + } + + /* compare port */ + return (_NSC_INT_KEY_CMP(e1->key.serv.serv.port, + e2->key.serv.serv.port)); +} + +static uint_t +servport_gethash(nss_XbyY_key_t *key, int htsize) { + return (db_gethash(&key->serv.serv.port, + sizeof (key->serv.serv.port), htsize)); +} + +static void +servport_getlogstr(char *name, char *whoami, size_t len, + nss_XbyY_args_t *argp) { + (void) snprintf(whoami, len, "%s [key=%d, %s]", + name, + argp->key.serv.serv.port, + check_null(argp->key.serv.proto)); +} diff --git a/usr/src/cmd/nscd/gettnrhdb.c b/usr/src/cmd/nscd/gettnrhdb.c new file mode 100644 index 0000000000..b42a51b6e8 --- /dev/null +++ b/usr/src/cmd/nscd/gettnrhdb.c @@ -0,0 +1,93 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * Routines to handle tsol_getrhbyaddr calls in nscd + */ + +#include <string.h> +#include <stdlib.h> +#include <sys/types.h> +#include <libtsnet.h> +#include "cache.h" + +#define tsol_rh_db ctx->nsc_db[0] + +#define NSC_NAME_TSOL_RH_BYADDR "tsol_getrhbyaddr" + +static int tsol_rh_compar(const void *, const void *); +static uint_t tsol_rh_gethash(nss_XbyY_key_t *, int); +static void tsol_rh_getlogstr(char *, char *, size_t, nss_XbyY_args_t *); + +void +tnrhdb_init_ctx(nsc_ctx_t *ctx) { + ctx->dbname = NSS_DBNAM_TSOL_RH; + ctx->db_count = 1; + ctx->file_name = TNRHDB_PATH; + + tsol_rh_db = make_cache(nsc_key_other, + NSS_DBOP_TSOL_RH_BYADDR, + NSC_NAME_TSOL_RH_BYADDR, + tsol_rh_compar, + tsol_rh_getlogstr, + tsol_rh_gethash, nsc_ht_default, -1); +} + +static void +tsol_rh_getlogstr(char *name, char *whoami, size_t len, + nss_XbyY_args_t *argp) { + + (void) snprintf(whoami, len, "%s [key=%s, len=%d, addrtype=%d]", + name, argp->key.hostaddr.addr, argp->key.hostaddr.len, + argp->key.hostaddr.type); +} + +static int +tsol_rh_compar(const void *n1, const void *n2) { + nsc_entry_t *e1, *e2; + int res, l1, l2; + + e1 = (nsc_entry_t *)n1; + e2 = (nsc_entry_t *)n2; + + if (e1->key.hostaddr.type > e2->key.hostaddr.type) + return (1); + else if (e1->key.hostaddr.type < e2->key.hostaddr.type) + return (-1); + + l1 = strlen(e1->key.hostaddr.addr); + l2 = strlen(e2->key.hostaddr.addr); + res = strncasecmp(e1->key.hostaddr.addr, e2->key.hostaddr.addr, + (l1 > l2)?l1:l2); + return (_NSC_INT_KEY_CMP(res, 0)); +} + +static uint_t +tsol_rh_gethash(nss_XbyY_key_t *key, int htsize) { + return (db_gethash(key->hostaddr.addr, + strlen(key->hostaddr.addr), htsize)); +} diff --git a/usr/src/cmd/nscd/gettnrhtp.c b/usr/src/cmd/nscd/gettnrhtp.c new file mode 100644 index 0000000000..e03804d848 --- /dev/null +++ b/usr/src/cmd/nscd/gettnrhtp.c @@ -0,0 +1,52 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * Routines to handle tsol_gettpbyname call in nscd + */ + +#include <string.h> +#include <stdlib.h> +#include <sys/types.h> +#include <libtsnet.h> +#include "cache.h" + +#define tsol_tp_db ctx->nsc_db[0] + +#define NSC_NAME_TSOL_TP_BYNAME "tsol_gettpbyname" + +void +tnrhtp_init_ctx(nsc_ctx_t *ctx) { + ctx->dbname = TNRHTP_PATH; + ctx->db_count = 1; + ctx->file_name = TNRHTP_PATH; + + tsol_tp_db = make_cache(nsc_key_cis, + NSS_DBOP_TSOL_TP_BYNAME, + NSC_NAME_TSOL_TP_BYNAME, + NULL, NULL, NULL, nsc_ht_default, -1); +} diff --git a/usr/src/cmd/nscd/getuser.c b/usr/src/cmd/nscd/getuser.c index fe654ef070..bd384a76c5 100644 --- a/usr/src/cmd/nscd/getuser.c +++ b/usr/src/cmd/nscd/getuser.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2003 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -30,481 +29,18 @@ * Routines to handle getuser* calls in nscd */ -#include <assert.h> -#include <errno.h> -#include <memory.h> -#include <signal.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <sys/door.h> -#include <sys/stat.h> -#include <sys/time.h> -#include <sys/types.h> -#include <sys/wait.h> -#include <thread.h> -#include <unistd.h> -#include <ucred.h> -#include <nss_common.h> +#include "cache.h" -#include <user_attr.h> - -#include <getxby_door.h> -#include "server_door.h" -#include "nscd.h" - -extern userstr_t *_getusernam(const char *, userstr_t *, char *, int, int *); - -static hash_t *nam_hash; -static mutex_t db_lock = DEFAULTMUTEX; -static waiter_t db_wait; - -static void getuser_namekeepalive(int keep, int interval); -static void update_user_bucket(nsc_bucket_t **old, nsc_bucket_t *new, - int callnumber); -static nsc_bucket_t *fixbuffer(nsc_return_t *in, int maxlen); -static void do_findgnams(nsc_bucket_t *ptr, int *table, char *gnam); -static void do_invalidate(nsc_bucket_t **ptr, int callnumber); -static void getuser_invalidate_unlocked(void); - -void -getuser_init(void) -{ - nam_hash = make_hash(current_admin.user.nsc_suggestedsize); -} - -static void -do_invalidate(nsc_bucket_t ** ptr, int callnumber) -{ - if (*ptr != NULL && *ptr != (nsc_bucket_t *)-1) { - /* leave pending calls alone */ - update_user_bucket(ptr, NULL, callnumber); - } -} - -static void -do_findgnams(nsc_bucket_t *ptr, int *table, char *gnam) -{ - - /* - * be careful with ptr - it may be -1 or NULL. - */ - - if (ptr != NULL && ptr != (nsc_bucket_t *)-1) { - char *tmp = (char *)insertn(table, ptr->nsc_hits, - (int)strdup(gnam)); - if (tmp != (char *)-1) - free(tmp); - } -} - -void -getuser_revalidate(void) -{ - for (;;) { - int slp; - int interval; - int count; - - slp = current_admin.user.nsc_pos_ttl; - - if (slp < 60) { - slp = 60; - } - - if ((count = current_admin.user.nsc_keephot) != 0) { - interval = (slp / 2)/count; - if (interval == 0) interval = 1; - sleep(slp * 2 / 3); - getuser_namekeepalive(count, interval); - } else { - sleep(slp); - } - } -} - -static void -getuser_namekeepalive(int keep, int interval) -{ - int *table; - union { - nsc_data_t ping; - char space[sizeof (nsc_data_t) + NSCDMAXNAMELEN]; - } u; - - int i; - - if (!keep) - return; - - table = maken(keep); - mutex_lock(&db_lock); - operate_hash(nam_hash, do_findgnams, (char *)table); - mutex_unlock(&db_lock); - - for (i = 1; i <= keep; i++) { - char *tmp; - u.ping.nsc_call.nsc_callnumber = GETUSERNAM; - - if ((tmp = (char *)table[keep + 1 + i]) == (char *)-1) - continue; /* unused slot in table */ - - strcpy(u.ping.nsc_call.nsc_u.name, tmp); - - launch_update(&u.ping.nsc_call); - sleep(interval); - } - - for (i = 1; i <= keep; i++) { - char *tmp; - if ((tmp = (char *)table[keep + 1 + i]) != (char *)-1) - free(tmp); - } - - free(table); -} - - -/* - * This routine marks all entries as invalid - * - */ - -void -getuser_invalidate() -{ - mutex_lock(&db_lock); - getuser_invalidate_unlocked(); - mutex_unlock(&db_lock); -} - -static void -getuser_invalidate_unlocked() -{ - operate_hash_addr(nam_hash, do_invalidate, (char *)GETUSERNAM); - current_admin.user.nsc_invalidate_count++; -} - -void -getuser_lookup(nsc_return_t *out, int maxsize, nsc_call_t *in, time_t now) -{ - int out_of_date; - nsc_bucket_t *retb; - char **bucket; - - static time_t lastmod; - - int bufferspace = maxsize - sizeof (nsc_return_t); - - if (current_admin.user.nsc_enabled == 0) { - out->nsc_return_code = NOSERVER; - out->nsc_bufferbytesused = sizeof (*out); - return; - } - - mutex_lock(&db_lock); - - if (current_admin.user.nsc_check_files) { - struct stat buf; - - if (stat(USERATTR_FILENAME, &buf) < 0) { - /*EMPTY*/; - } else if (lastmod == 0) { - lastmod = buf.st_mtime; - } else if (lastmod < buf.st_mtime) { - getuser_invalidate_unlocked(); - lastmod = buf.st_mtime; - } - } - - if (current_admin.debug_level >= DBG_ALL) { - logit("getuser_lookup: looking for name %s\n", - in->nsc_u.name); - } - - for (;;) { - if (attr_strlen(in->nsc_u.name) > NSCDMAXNAMELEN) { - ucred_t *uc = NULL; - - if (door_ucred(&uc) != 0) { - logit("getuser_lookup: Name too long, " - "but no user credential: %s\n", - strerror(errno)); - } else { - logit("getuser_lookup: Name too long " - "from pid %d uid %d\n", - ucred_getpid(uc), - ucred_getruid(uc)); - ucred_free(uc); - } - - out->nsc_errno = NSS_NOTFOUND; - out->nsc_return_code = NOTFOUND; - out->nsc_bufferbytesused = sizeof (*out); - goto getout; - } - bucket = get_hash(nam_hash, in->nsc_u.name); - - if (*bucket == (char *)-1) { /* pending lookup */ - if (get_clearance(in->nsc_callnumber) != 0) { - /* no threads available */ - out->nsc_return_code = NOSERVER; - /* cannot process now */ - out->nsc_bufferbytesused = - sizeof (*out); - current_admin.user.nsc_throttle_count++; - goto getout; - } - nscd_wait(&db_wait, &db_lock, bucket); - release_clearance(in->nsc_callnumber); - continue; /* go back and relookup hash bucket */ - } - break; - } - - /* - * check for no name_service mode - */ - - if (*bucket == NULL && current_admin.avoid_nameservice) { - out->nsc_return_code = NOTFOUND; - out->nsc_bufferbytesused = sizeof (*out); - } else if ((*bucket == NULL) || /* New entry in name service */ - (in->nsc_callnumber & UPDATEBIT) || /* needs updating */ - (out_of_date = (!current_admin.avoid_nameservice && - (current_admin.user.nsc_old_data_ok == 0) && - (((nsc_bucket_t *)*bucket)->nsc_timestamp < now)))) { - /* time has expired */ - int saved_errno; - int saved_hits = 0; - userstr_t *p; - - if (get_clearance(in->nsc_callnumber) != 0) { - /* no threads available */ - out->nsc_return_code = NOSERVER; - /* cannot process now */ - out->nsc_bufferbytesused = sizeof (*out); - current_admin.user.nsc_throttle_count++; - goto getout; - } - - if (*bucket != NULL) { - saved_hits = - ((nsc_bucket_t *)*bucket)->nsc_hits; - } - - /* - * block any threads accessing this bucket if data is - * non-existent out of date - */ - - if (*bucket == NULL || out_of_date) { - update_user_bucket((nsc_bucket_t **)bucket, - (nsc_bucket_t *)-1, in->nsc_callnumber); - } else { - /* - * if still not -1 bucket we are doing update... - * mark to prevent - * pileups of threads if the name service is hanging.... - */ - ((nsc_bucket_t *)(*bucket))->nsc_status |= - ST_UPDATE_PENDING; - /* cleared by deletion of old data */ - } - mutex_unlock(&db_lock); - - /* - * Call non-caching version in libnsl. - */ - p = _getusernam(in->nsc_u.name, &out->nsc_u.user, - out->nsc_u.buff + sizeof (userstr_t), - bufferspace, &errno); - saved_errno = errno; - - mutex_lock(&db_lock); - - release_clearance(in->nsc_callnumber); - - if (p == NULL) { /* data not found */ - - if (current_admin.debug_level >= DBG_CANT_FIND) { - logit("getuser_lookup: nscd COULDN'T FIND user_attr name %s\n", - in->nsc_u.name); - } - - - if (!(UPDATEBIT & in->nsc_callnumber)) - current_admin.user.nsc_neg_cache_misses++; - - retb = (nsc_bucket_t *)malloc(sizeof (nsc_bucket_t)); - - retb->nsc_refcount = 1; - retb->nsc_data.nsc_bufferbytesused = - sizeof (nsc_return_t); - retb->nsc_data.nsc_return_code = NOTFOUND; - retb->nsc_data.nsc_errno = saved_errno; - memcpy(out, &retb->nsc_data, - retb->nsc_data.nsc_bufferbytesused); - update_user_bucket((nsc_bucket_t **)bucket, - retb, in->nsc_callnumber); - goto getout; - } else { - if (current_admin.debug_level >= DBG_ALL) { - logit("getuser_lookup: nscd FOUND user_attr name %s\n", - in->nsc_u.name); - } - if (!(UPDATEBIT & in->nsc_callnumber)) - current_admin.user.nsc_pos_cache_misses++; - - retb = fixbuffer(out, bufferspace); - update_user_bucket((nsc_bucket_t **)bucket, - retb, in->nsc_callnumber); - if (saved_hits) - retb->nsc_hits = saved_hits; - } - } else { /* found entry in cache */ - retb = (nsc_bucket_t *)*bucket; - - retb->nsc_hits++; - - memcpy(out, &(retb->nsc_data), - retb->nsc_data.nsc_bufferbytesused); - - if (out->nsc_return_code == SUCCESS) { - if (!(UPDATEBIT & in->nsc_callnumber)) - current_admin.user.nsc_pos_cache_hits++; - if (current_admin.debug_level >= DBG_ALL) { - logit("getuser_lookup: found name %s in cache\n", - in->nsc_u.name); - } - } else { - if (!(UPDATEBIT & in->nsc_callnumber)) - current_admin.user.nsc_neg_cache_hits++; - if (current_admin.debug_level >= DBG_ALL) { - logit("getuser_lookup: %s marked as NOT FOUND in cache.\n", - in->nsc_u.name); - } - } - - if ((retb->nsc_timestamp < now) && - !(in->nsc_callnumber & UPDATEBIT) && - !(retb->nsc_status & ST_UPDATE_PENDING)) { - logit("launch update since time = %d\n", retb->nsc_timestamp); - retb->nsc_status |= ST_UPDATE_PENDING; - /* cleared by deletion of old data */ - launch_update(in); - } - } - -getout: - mutex_unlock(&db_lock); -} - -/*ARGSUSED*/ -static void -update_user_bucket(nsc_bucket_t **old, nsc_bucket_t *new, int callnumber) -{ - if (*old != NULL && *old != (nsc_bucket_t *)-1) { /* old data exists */ - free(*old); - current_admin.user.nsc_entries--; - } - - /* - * we can do this before reseting *old since we're holding the lock - */ - - else if (*old == (nsc_bucket_t *)-1) { - nscd_signal(&db_wait, (char **)old); - } - - *old = new; - - if ((new != NULL) && - (new != (nsc_bucket_t *)-1)) { - /* real data, not just update pending or invalidate */ - new->nsc_hits = 1; - new->nsc_status = 0; - new->nsc_refcount = 1; - current_admin.user.nsc_entries++; - - if (new->nsc_data.nsc_return_code == SUCCESS) { - new->nsc_timestamp = time(NULL) + - current_admin.user.nsc_pos_ttl; - } else { - new->nsc_timestamp = time(NULL) + - current_admin.user.nsc_neg_ttl; - } - } -} - -/*ARGSUSED*/ -static nsc_bucket_t * -fixbuffer(nsc_return_t *in, int maxlen) -{ - nsc_bucket_t *retb; - nsc_return_t *out; - char *dest; - int offset; - int strs; - - /* - * find out the size of the data block we're going to need - */ - - strs = attr_strlen(in->nsc_u.user.name) + - attr_strlen(in->nsc_u.user.qualifier) + - attr_strlen(in->nsc_u.user.res1) + - attr_strlen(in->nsc_u.user.res2) + - attr_strlen(in->nsc_u.user.attr) + USERATTR_DB_NCOL; - - /* - * allocate it and copy it in - * code doesn't assume packing order in original buffer - */ - - if ((retb = (nsc_bucket_t *)malloc(sizeof (*retb) + strs)) == NULL) { - return (NULL); - } - - out = &(retb->nsc_data); - out->nsc_bufferbytesused = strs + ((int)&out->nsc_u.user - (int)out) + - sizeof (userstr_t); - out->nsc_return_code = SUCCESS; - out->nsc_errno = 0; - - dest = retb->nsc_data.nsc_u.buff + sizeof (userstr_t); - offset = (int)dest; - - attr_strcpy(dest, in->nsc_u.user.name); - strs = 1 + attr_strlen(in->nsc_u.user.name); - out->nsc_u.user.name = dest - offset; - dest += strs; - - attr_strcpy(dest, in->nsc_u.user.qualifier); - strs = 1 + attr_strlen(in->nsc_u.user.qualifier); - out->nsc_u.user.qualifier = dest - offset; - dest += strs; - - attr_strcpy(dest, in->nsc_u.user.res1); - strs = 1 + attr_strlen(in->nsc_u.user.res1); - out->nsc_u.user.res1 = dest - offset; - dest += strs; - - attr_strcpy(dest, in->nsc_u.user.res2); - strs = 1 + attr_strlen(in->nsc_u.user.res2); - out->nsc_u.user.res2 = dest - offset; - dest += strs; - - attr_strcpy(dest, in->nsc_u.user.attr); - out->nsc_u.user.attr = dest - offset; - - memcpy(in, out, out->nsc_bufferbytesused); - - return (retb); -} +#define nam_db ctx->nsc_db[0] +#define NSC_NAME_USERATTR_BYNAME "getusernam" void -getuser_reaper(void) -{ - nsc_reaper("getuser", nam_hash, ¤t_admin.user, &db_lock); +user_init_ctx(nsc_ctx_t *ctx) { + ctx->dbname = NSS_DBNAM_USERATTR; + ctx->file_name = "/etc/user_attr"; + ctx->db_count = 1; + nam_db = make_cache(nsc_key_ces, + NSS_DBOP_USERATTR_BYNAME, + NSC_NAME_USERATTR_BYNAME, + NULL, NULL, NULL, nsc_ht_default, -1); } diff --git a/usr/src/cmd/nscd/hash.c b/usr/src/cmd/nscd/hash.c deleted file mode 100644 index 91a3018cbb..0000000000 --- a/usr/src/cmd/nscd/hash.c +++ /dev/null @@ -1,346 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. - * - * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE - * or http://www.opensolaris.org/os/licensing. - * See the License for the specific language governing permissions - * and limitations under the License. - * - * When distributing Covered Code, include this CDDL HEADER in each - * file and include the License file at usr/src/OPENSOLARIS.LICENSE. - * If applicable, add the following below this CDDL HEADER, with the - * fields enclosed by brackets "[]" replaced with your own identifying - * information: Portions Copyright [yyyy] [name of copyright owner] - * - * CDDL HEADER END - */ -/* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#pragma ident "%Z%%M% %I% %E% SMI" - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <synch.h> -#include <memory.h> -#include <getxby_door.h> - -static int hash_string(); - -hash_t * -make_hash(size) -int size; -{ - hash_t *ptr; - - ptr = (hash_t *)malloc(sizeof (*ptr)); - ptr->size = size; - ptr->table = (hash_entry_t **) - malloc((unsigned) (sizeof (hash_entry_t *) * size)); - (void) memset((char *)ptr->table, (char)0, - sizeof (hash_entry_t *)*size); - ptr->start = NULL; - ptr->hash_type = String_Key; - return (ptr); -} - -hash_t * -make_ihash(size) -int size; -{ - hash_t *ptr; - - ptr = (hash_t *)malloc(sizeof (*ptr)); - ptr->size = size; - ptr->table = (hash_entry_t **)malloc((unsigned) - (sizeof (hash_entry_t *) * size)); - (void) memset((char *)ptr->table, (char)0, - sizeof (hash_entry_t *)*size); - ptr->start = NULL; - ptr->hash_type = Integer_Key; - return (ptr); -} - - -char ** -get_hash(hash_t *tbl, char *key) -{ - - int bucket; - hash_entry_t *tmp; - hash_entry_t *new; - - if (tbl->hash_type == String_Key) { - tmp = tbl->table[bucket = hash_string(key, tbl->size)]; - } else { - tmp = tbl->table[bucket = abs((int)key) % tbl->size]; - } - - if (tbl->hash_type == String_Key) { - while (tmp != NULL) { - if (strcmp(tmp->key, key) == 0) { - return (&tmp->data); - } - tmp = tmp->next_entry; - } - } else { - while (tmp != NULL) { - if (tmp->key == key) { - return (&tmp->data); - } - tmp = tmp->next_entry; - } - } - - /* - * not found.... - * insert new entry into bucket... - */ - - new = (hash_entry_t *)malloc(sizeof (*new)); - new->key = ((tbl->hash_type == String_Key)?strdup(key):key); - /* - * hook into chain from tbl... - */ - new->right_entry = NULL; - new->left_entry = tbl->start; - tbl->start = new; - if (new->left_entry != NULL) - new->left_entry->right_entry = new; - /* - * hook into bucket chain - */ - new->next_entry = tbl->table[bucket]; - tbl->table[bucket] = new; - new->data = NULL; /* so we know that it is new */ - return (&new->data); -} - -char ** -find_hash(hash_t *tbl, char *key) -{ - hash_entry_t *tmp; - - if (tbl->hash_type == String_Key) { - tmp = tbl->table[hash_string(key, tbl->size)]; - for (; tmp != NULL; tmp = tmp->next_entry) { - if (strcmp(tmp->key, key) == 0) { - return (&tmp->data); - } - } - } else { - tmp = tbl->table[abs((int)key) % tbl->size]; - for (; tmp != NULL; tmp = tmp->next_entry) { - if (tmp->key == key) { - return (&tmp->data); - } - } - } - - return (NULL); -} - -char * -del_hash(hash_t *tbl, hash_entry_t *del_this, hash_entry_t *prev, int bucket) -{ - /* - * del_this points to entry marked for deletion, prev to - * item preceeding in bucket chain or NULL if del_this is first. - * remove from bucket chain first.... - */ - if (tbl->hash_type == String_Key) { - free(del_this->key); - } - if (prev != NULL) { - prev->next_entry = del_this->next_entry; - } else { - tbl->table[bucket] = del_this->next_entry; - } - /* - * now remove from tbl chain.... - */ - if (del_this->right_entry != NULL) { /* not first in chain.... */ - del_this->right_entry->left_entry = del_this->left_entry; - } else { - tbl->start = del_this->left_entry; - } - if (del_this->left_entry != NULL) { /* not last in chain.... */ - del_this->left_entry->right_entry = del_this->right_entry; - } - return (del_this->data); -} - -int -operate_hash(hash_t *tbl, void (*ptr)(), char *usr_arg) -{ - hash_entry_t *tmp = tbl->start; - int c = 0; - - while (tmp) { - (*ptr)(tmp->data, usr_arg, tmp->key); - tmp = tmp->left_entry; - c++; - } - return (c); -} - -int -operate_hash_addr(hash_t *tbl, void (*ptr)(), char *usr_arg) -{ - hash_entry_t *tmp = tbl->start; - int c = 0; - - while (tmp) { - (*ptr)(&(tmp->data), usr_arg, tmp->key); - tmp = tmp->left_entry; - c++; - } - return (c); -} - -void -destroy_hash(hash_t *tbl, int (*ptr)(), char *usr_arg) -{ - hash_entry_t *tmp = tbl->start, *prev; - - while (tmp) { - if (ptr) { - (*ptr)(tmp->data, usr_arg, tmp->key); - } - - if (tbl->hash_type == String_Key) { - free(tmp->key); - } - prev = tmp; - tmp = tmp->left_entry; - free((char *)prev); - } - free((char *)tbl->table); - free(tbl); -} - -static int -hash_string(char *s, int modulo) -{ - unsigned result = 0; - int i = 1; - - while (*s != 0) { - result += (*s++ << i++); - } - - return (result % modulo); -} - -int -reap_hash(hash_t *tbl, nsc_stat_t *admin_ptr, mutex_t *hash_lock, - int howlong) -{ - - hash_entry_t *tmp, *next, *prev; - uint_t count = 0; - uint_t bucket; - uint_t extra_sleep = 1; - uint_t buckets_per_interval, seconds_per_interval, buckets_togo; - uint_t total_buckets; - time_t now; - - /* - * We don't want to spend too much time reaping nor too little. - * We cap the TTL at 2^28 to prevent overflow. This is 8.5 years, - * so we aren't really going to reap anything anyway. - * Also, we want the total time to be one second more than the - * time to expire the entries. - */ - howlong++; - if (howlong < 32) howlong = 32; - if (howlong > (1<<28)) howlong = 1<<28; - - /* Total_buckets can range from 37 to 2^30 */ - total_buckets = admin_ptr->nsc_suggestedsize; - - if (total_buckets >= howlong && total_buckets > (howlong>>2)) { - /* - * In the realm of buckets_per_second. total_buckets might - * be near 2^30, so we divide first - */ - buckets_per_interval = total_buckets/(howlong>>2); - seconds_per_interval = 4; - } else if (total_buckets >= howlong) { - /* Still buckets per second, but it is safe to multiply first */ - buckets_per_interval = (total_buckets<<2)/howlong; - seconds_per_interval = 4; - } else if (total_buckets <= (howlong>>2)) { - /* - * Now in the secs/buck realm. Howlong is at least 4 times - * total_buckets, so we are safe to use this as the interval. - * Figure out the rounding error and sleep it at the end. - */ - seconds_per_interval = howlong/total_buckets; - buckets_per_interval = 1; - extra_sleep = 1 + howlong - - (total_buckets*seconds_per_interval); - } else { - /* - * Still in secs/buck realm, but seconds_per_interval - * is too short. Use 8 as the minimum, then adjust the extra - * at the end. We need 8 because of rounding error. - */ - seconds_per_interval = (howlong/(total_buckets>>3)); - buckets_per_interval = 8; - extra_sleep = 1 + howlong - - ((total_buckets>>3)*seconds_per_interval); - } - - /* - * bucket keeps track of which bucket in the whole table we are on. - * buckets_togo is which bucket in this interval we are on. - */ - - for (bucket = buckets_togo = 0; - bucket < admin_ptr->nsc_suggestedsize; - bucket++) { - if (buckets_togo <= 0) { - sleep(seconds_per_interval); - buckets_togo = buckets_per_interval; - now = time(NULL); - } - mutex_lock(hash_lock); - tmp = tbl->table[bucket]; - prev = NULL; - while (tmp != NULL) { - next = tmp->next_entry; - if (tmp->data == (char *)NULL) { - del_hash(tbl, tmp, prev, bucket); - free(tmp); - count++; - } else if ((tmp->data != (char *)-1) && - ((((nsc_bucket_t *)(tmp->data))->nsc_status & - ST_UPDATE_PENDING) == 0) && - (((nsc_bucket_t *)(tmp->data))->nsc_timestamp - < now)) { - del_hash(tbl, tmp, prev, bucket); - free(tmp->data); - free(tmp); - count++; - admin_ptr->nsc_entries--; - } else { - prev = tmp; - } - tmp = next; - } - mutex_unlock(hash_lock); - buckets_togo--; - - } - sleep(extra_sleep); - return (count); -} diff --git a/usr/src/cmd/nscd/name-service-cache.xml b/usr/src/cmd/nscd/name-service-cache.xml index 14cc588eff..e85f22278c 100644 --- a/usr/src/cmd/nscd/name-service-cache.xml +++ b/usr/src/cmd/nscd/name-service-cache.xml @@ -1,15 +1,14 @@ <?xml version="1.0"?> <!DOCTYPE service_bundle SYSTEM "/usr/share/lib/xml/dtd/service_bundle.dtd.1"> <!-- - Copyright 2005 Sun Microsystems, Inc. All rights reserved. + Copyright 2006 Sun Microsystems, Inc. All rights reserved. Use is subject to license terms. CDDL HEADER START The contents of this file are subject to the terms of the - Common Development and Distribution License, Version 1.0 only - (the "License"). You may not use this file except in compliance - with the License. + Common Development and Distribution License (the "License"). + You may not use this file except in compliance with the License. You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE or http://www.opensolaris.org/os/licensing. @@ -86,6 +85,18 @@ value='solaris.smf.manage.name-service-cache' /> </property_group> + <property_group name='config' type='application' > + <propval + name='enable_per_user_lookup' + type='boolean' + value='true' /> + <propval + name='per_user_nscd_time_to_live' + type='integer' + value='120' /> + </property_group> + + <stability value='Unstable' /> diff --git a/usr/src/cmd/nscd/nscd.h b/usr/src/cmd/nscd/nscd.h deleted file mode 100644 index a7dab9fd90..0000000000 --- a/usr/src/cmd/nscd/nscd.h +++ /dev/null @@ -1,127 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. - * - * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE - * or http://www.opensolaris.org/os/licensing. - * See the License for the specific language governing permissions - * and limitations under the License. - * - * When distributing Covered Code, include this CDDL HEADER in each - * file and include the License file at usr/src/OPENSOLARIS.LICENSE. - * If applicable, add the following below this CDDL HEADER, with the - * fields enclosed by brackets "[]" replaced with your own identifying - * information: Portions Copyright [yyyy] [name of copyright owner] - * - * CDDL HEADER END - */ -/* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#ifndef _NSCD_H -#define _NSCD_H - -#pragma ident "%Z%%M% %I% %E% SMI" - -#ifdef __cplusplus -extern "C" { -#endif - -extern admin_t current_admin; - -extern int attr_strlen(char *); -extern char *attr_strcpy(char *, char *); - -extern nsc_stat_t *getcacheptr(char *s); -extern int nscd_set_lf(admin_t *ptr, char *s); -extern void logit(char *format, ...); -extern int launch_update(nsc_call_t *in); -extern int load_admin_defaults(admin_t *ptr, int will_become_server); -extern void getpw_init(void); -extern void getpw_revalidate(void); -extern void getpw_uid_reaper(void); -extern void getpw_nam_reaper(void); -extern void getpw_invalidate(void); -extern void getpw_lookup(nsc_return_t *out, int maxsize, nsc_call_t *in, - time_t now); -extern void getgr_init(void); -extern void getgr_revalidate(void); -extern void getgr_uid_reaper(void); -extern void getgr_nam_reaper(void); -extern void getgr_invalidate(void); -extern void getgr_lookup(nsc_return_t *out, int maxsize, nsc_call_t *in, - time_t now); -extern void gethost_init(void); -extern void gethost_revalidate(void); -extern void gethost_nam_reaper(void); -extern void gethost_addr_reaper(void); -extern void gethost_invalidate(void); -extern void gethost_lookup(nsc_return_t *out, int maxsize, nsc_call_t *in, - time_t now); -extern void getnode_init(void); -extern void getnode_revalidate(void); -extern void getnode_nam_reaper(void); -extern void getnode_addr_reaper(void); -extern void getnode_invalidate(void); -extern void getnode_name_invalidate(void); -extern void getnode_lookup(nsc_return_t *out, int maxsize, nsc_call_t *in, - time_t now); -extern hash_t *make_hash(int size); -extern hash_t *make_ihash(int size); -extern char **get_hash(hash_t *tbl, char *key); -extern char **find_hash(hash_t *tbl, char *key); -extern char *del_hash(hash_t *tbl, hash_entry_t *del_this, hash_entry_t *prev, - int bucket); -extern int operate_hash(hash_t *tbl, void (*ptr)(), char *usr_arg); -extern int operate_hash_addr(hash_t *tbl, void (*ptr)(), char *usr_arg); -extern void nsc_reaper(char *tbl_name, hash_t *tbl, - nsc_stat_t *admin_ptr, mutex_t *hash_lock); -extern int reap_hash(hash_t *tbl, nsc_stat_t *admin_ptr, - mutex_t *hash_lock, int howlong); -extern void destroy_hash(hash_t *tbl, int (*ptr)(), char *usr_arg); -extern int *maken(int n); -extern int insertn(int *table, int n, int data); -extern int nscd_parse(char *progname, char *filename); -extern int nscd_set_dl(admin_t *ptr, int value); -extern int nscd_set_ec(nsc_stat_t *cache, char *name, int value); -extern int nscd_set_khc(nsc_stat_t *cache, char *name, int value); -extern int nscd_set_odo(nsc_stat_t *cache, char *name, int value); -extern int nscd_set_ss(nsc_stat_t *cache, char *name, int value); -extern int nscd_set_ttl_positive(nsc_stat_t *cache, char *name, int value); -extern int nscd_set_ttl_negative(nsc_stat_t *cache, char *name, int value); -extern int nscd_wait(waiter_t *wchan, mutex_t *lock, char **key); -extern int nscd_signal(waiter_t *wchan, char **key); -extern int get_clearance(int callnumber); -extern int release_clearance(int callnumber); - -extern void getexec_init(void); -extern void getexec_revalidate(void); -extern void getexec_reaper(void); -extern void getexec_invalidate(void); -extern void getexec_lookup(nsc_return_t *out, int maxsize, nsc_call_t *in, - time_t now); -extern void getprof_init(void); -extern void getprof_revalidate(void); -extern void getprof_reaper(void); -extern void getprof_invalidate(void); -extern void getprof_lookup(nsc_return_t *out, int maxsize, nsc_call_t *in, - time_t now); -extern void getuser_init(void); -extern void getuser_revalidate(void); -extern void getuser_reaper(void); -extern void getuser_invalidate(void); -extern void getuser_lookup(nsc_return_t *out, int maxsize, nsc_call_t *in, - time_t now); - -extern void leave(int n); -#ifdef __cplusplus -} -#endif - -#endif /* _NSCD_H */ diff --git a/usr/src/cmd/nscd/nscd_access.c b/usr/src/cmd/nscd/nscd_access.c new file mode 100644 index 0000000000..36f168652b --- /dev/null +++ b/usr/src/cmd/nscd/nscd_access.c @@ -0,0 +1,588 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <assert.h> +#include <stdlib.h> +#include <string.h> +#include "nscd_db.h" +#include "nscd_log.h" + +/* + * Access control structure for a piece of nscd data. This structure + * is always tagged before the nscd data. nscd_alloc, which should + * be used to allocate memory that requires access control or usage + * count control, will initialize this access control structure at the + * start of the memory returned to the caller. + */ +struct nscd_access_s { + void *data; /* addr of real data */ + void (*free_func)(nscd_acc_data_t *data); /* destructor */ + mutex_t mutex; /* protect this structure */ + mutex_t *data_mutex; + rwlock_t *data_rwlock; + cond_t *data_cond; + int nUse; /* usage count */ + int type; + int delete; /* no longer available */ + nscd_seq_num_t seq_num; /* sequence number */ +}; + +/* size should be in multiple of 8 */ +static int sizeof_access = roundup(sizeof (nscd_access_t)); + +#define ABORT_DUE_TO_NO_VALID_NSCD_ACCESS_DATA 0 +#define ASSERT_ACCESS_DATA \ + if (access->data != data) \ + assert(ABORT_DUE_TO_NO_VALID_NSCD_ACCESS_DATA) + +#define SET_ACCESS_PTR \ + access = (nscd_access_t *) \ + ((void *)((char *)data - sizeof_access)) + +static void _nscd_free(nscd_acc_data_t *data); + +/* + * FUNCTION: _nscd_release + * + * Decrements the usage count maintained in the access data + * tagged before 'data'. Delete the nscd data item if the delete + * flag is set and the usage count reaches 0. + */ +void +_nscd_release( + nscd_acc_data_t *data) +{ + nscd_access_t *access; + char *me = "_nscd_release"; + + if (data == NULL) + return; + + SET_ACCESS_PTR; + + _NSCD_LOG(NSCD_LOG_ACCESS_INFO, NSCD_LOG_LEVEL_DEBUG) + (me, "data = %p, access->data = %p, " + "seq = %lld, nUse = %d\n", + data, access->data, access->seq_num, access->nUse); + ASSERT_ACCESS_DATA; + + (void) mutex_lock(&access->mutex); + access->nUse--; + if (access->nUse < 0) { +#define ACCESS_NUSE_LESS_THAN_ZERO 0 + assert(ACCESS_NUSE_LESS_THAN_ZERO); + } + if (access->nUse <= 0 && + access->delete == 1) { + + _NSCD_LOG(NSCD_LOG_ACCESS_INFO, NSCD_LOG_LEVEL_DEBUG) + (me, "deleting data %p\n", access->data); + (access->free_func)(access->data); + + /* + * if we get here, no other thread could be + * holding the access->mutex lock, It is safe + * to free the memory containing the mutex + * structure. No mutex_unlock is necessary. + */ + _nscd_free(data); + } else + (void) mutex_unlock(&access->mutex); +} + + +/* + * FUNCTION: _nscd_destroy + * + * Marks the nscd data item as to-be-deleted and then releases + * (If the usage count happens to be zero, then _nscd_release() + * will destroy the data.) + * + * Note that _nscd_destroy should only be called if the + * caller has created the nscd data with _nscd_alloc + * (with the exception of _nscd_set). That nscd data + * item should be private to the caller. + */ +static void +_nscd_destroy( + nscd_acc_data_t *data) +{ + nscd_access_t *access; + char *me = "_nscd_destroy"; + + if (data == NULL) + return; + + SET_ACCESS_PTR; + + _NSCD_LOG(NSCD_LOG_ACCESS_INFO, NSCD_LOG_LEVEL_DEBUG) + (me, "data = %p, access->data = %p\n", data, access->data); + ASSERT_ACCESS_DATA; + + (void) mutex_lock(&access->mutex); + access->delete = 1; + (void) mutex_unlock(&access->mutex); + + _nscd_release(data); +} + +/* + * FUNCTION: _nscd_get + * + * Increment the usage count by one if 'data' can + * be found in the internal address database. + */ +nscd_acc_data_t * +_nscd_get( + nscd_acc_data_t *data) +{ + nscd_access_t *access; + void *ret = data; + rwlock_t *addr_rwlock; + char *me = "_nscd_get"; + + if (data == NULL) + return (NULL); + + SET_ACCESS_PTR; + + _NSCD_LOG(NSCD_LOG_ACCESS_INFO, NSCD_LOG_LEVEL_DEBUG) + (me, "data = %p, access->data = %p, seq#= %lld, nUse = %d\n", + data, access->data, access->seq_num, access->nUse); + ASSERT_ACCESS_DATA; + + /* + * see if this addr is still valid, + * if so, _nscd_is_int_addr will + * do a read lock on the returned + * multiple readers/single writer lock + * to prevent the access data from being + * deleted while it is being accessed. + */ + if ((addr_rwlock = _nscd_is_int_addr(data, + access->seq_num)) == NULL) { + _NSCD_LOG(NSCD_LOG_ACCESS_INFO, NSCD_LOG_LEVEL_DEBUG) + (me, "internal address %p not found\n", data); + assert(addr_rwlock != NULL); + return (NULL); + } + + (void) mutex_lock(&access->mutex); + if (access->delete == 1) + ret = NULL; + else + access->nUse++; + (void) mutex_unlock(&access->mutex); + + /* + * done with the multiple readers/single writer lock + */ + (void) rw_unlock(addr_rwlock); + + return (ret); +} + +/* + * FUNCTION: _nscd_set + * + * _nscd_set sets the address of a nscd data item + * to 'new' and delete the old nscd data (old). + * The pointer 'new' is returned. + */ +nscd_acc_data_t * +_nscd_set( + nscd_acc_data_t *old, + nscd_acc_data_t *new) +{ + nscd_acc_data_t *old_data, *new_data; + char *me = "_nscd_set"; + + if (new == old) + return (old); + + _NSCD_LOG(NSCD_LOG_ACCESS_INFO, NSCD_LOG_LEVEL_DEBUG) + (me, "new = %p, old = %p\n", new, old); + + old_data = _nscd_get(old); + new_data = _nscd_get(new); + + if (old_data != new_data) { + + _nscd_destroy(old_data); + _nscd_release(new_data); + return (new_data); + } + + /* if old_data == new_data, both must be NULL */ + return (NULL); +} + +/* + * FUNCTION: _nscd_rdlock + * + * Lock (rw_rdlock) a nscd data item for reading. The caller + * needs to call _nscd_rw_unlock() to unlock the data item + * when done using the data. + */ +nscd_acc_data_t * +_nscd_rdlock( + nscd_acc_data_t *data) +{ + nscd_access_t *access; + void *ret; + char *me = "_nscd_rdlock"; + + ret = _nscd_get(data); + + if (ret == NULL) + return (NULL); + + SET_ACCESS_PTR; + + _NSCD_LOG(NSCD_LOG_ACCESS_INFO, NSCD_LOG_LEVEL_DEBUG) + (me, "data = %p, access->data = %p\n", data, access->data); + ASSERT_ACCESS_DATA; + + assert(access->data_rwlock != NULL); + + (void) rw_rdlock(access->data_rwlock); + + return (ret); +} + +/* + * FUNCTION: _nscd_wrlock + * + * Lock (rw_wrlock) a nscd data item for writing. The caller + * needs to call _nscd_rw_unlock() to unlock the data item + * when done using the data. + */ +nscd_acc_data_t * +_nscd_wrlock( + nscd_acc_data_t *data) +{ + nscd_access_t *access; + void *ret; + char *me = "_nscd_wrlock"; + + ret = _nscd_get(data); + + if (ret == NULL) + return (NULL); + + SET_ACCESS_PTR; + + _NSCD_LOG(NSCD_LOG_ACCESS_INFO, NSCD_LOG_LEVEL_DEBUG) + (me, "data = %p, access->data = %p\n", data, access->data); + ASSERT_ACCESS_DATA; + + assert(access->data_rwlock != NULL); + + (void) rw_wrlock(access->data_rwlock); + + return (ret); +} + +/* + * FUNCTION: _nscd_rw_unlock + * + * Unlock (rw_unlock) a locked nscd data item. + */ +void +_nscd_rw_unlock( + nscd_acc_data_t *data) +{ + nscd_access_t *access; + char *me = "_nscd_rw_unlock"; + + if (data == NULL) + return; + + SET_ACCESS_PTR; + + _NSCD_LOG(NSCD_LOG_ACCESS_INFO, NSCD_LOG_LEVEL_DEBUG) + (me, "data = %p, access->data = %p\n", + data, access->data); + ASSERT_ACCESS_DATA; + + assert(access->data_rwlock != NULL); + + (void) rw_unlock(access->data_rwlock); + _nscd_release(data); +} + +/* + * FUNCTION: _nscd_rw_unlock_no_release + * + * Unlock (rw_unlock) a locked nscd data item but without release + * it, i.e., without decrement the usage count to indicate that + * the data item is still being referenced. + */ +void +_nscd_rw_unlock_no_release( + nscd_acc_data_t *data) +{ + nscd_access_t *access; + + if (data == NULL) + return; + + SET_ACCESS_PTR; + ASSERT_ACCESS_DATA; + + assert(access->data_rwlock != NULL); + + (void) rw_unlock(access->data_rwlock); +} + +/* + * FUNCTION: _nscd_mutex_lock + * + * Lock (mutex_lock) a nscd data item. The caller needs + * to call _nscd_mutex_unlock() to unlock the data item + * when done using the data. + */ +nscd_acc_data_t * +_nscd_mutex_lock( + nscd_acc_data_t *data) +{ + nscd_access_t *access; + void *ret; + char *me = "_nscd_mutex_lock"; + + ret = _nscd_get(data); + + if (ret == NULL) + return (NULL); + + SET_ACCESS_PTR; + + _NSCD_LOG(NSCD_LOG_ACCESS_INFO, NSCD_LOG_LEVEL_DEBUG) + (me, "data = %p, access->data = %p\n", data, access->data); + ASSERT_ACCESS_DATA; + + assert(access->data_mutex != NULL); + + (void) mutex_lock(access->data_mutex); + + return (ret); +} + + +/* + * FUNCTION: _nscd_mutex_unlock + * + * Unlock a locked nscd data item (that were locked by _nscd_mutex_lock).. + */ +void +_nscd_mutex_unlock( + nscd_acc_data_t *data) +{ + nscd_access_t *access; + char *me = "_nscd_mutex_unlock"; + + if (data == NULL) + return; + + SET_ACCESS_PTR; + + _NSCD_LOG(NSCD_LOG_ACCESS_INFO, NSCD_LOG_LEVEL_DEBUG) + (me, "data = %p, access->data = %p\n", data, access->data); + ASSERT_ACCESS_DATA; + + assert(access->data_mutex != NULL); + + (void) mutex_unlock(access->data_mutex); + _nscd_release(data); +} + +/* + * FUNCTION: _nscd_cond_wait + * + * Perform a condition wait with the cond_t and mutex_t associated + * with data. + */ +void +_nscd_cond_wait( + nscd_acc_data_t *data, cond_t *cond) +{ + nscd_access_t *access; + char *me = "_nscd_cond_wait"; + + if (data == NULL) + return; + + SET_ACCESS_PTR; + + _NSCD_LOG(NSCD_LOG_ACCESS_INFO, NSCD_LOG_LEVEL_DEBUG) + (me, "data = %p, access->data = %p\n", data, access->data); + ASSERT_ACCESS_DATA; + + assert(access->data_cond != NULL && access->data_mutex != NULL); + + if (cond == NULL) + (void) cond_wait(access->data_cond, access->data_mutex); + else + (void) cond_wait(cond, access->data_mutex); +} + +/* + * FUNCTION: _nscd_cond_signal + * + * Perform a condition signal with the cond_t associated with 'data'. + */ +void +_nscd_cond_signal( + nscd_acc_data_t *data) +{ + nscd_access_t *access; + char *me = "_nscd_cond_signal"; + + if (data == NULL) + return; + + SET_ACCESS_PTR; + + _NSCD_LOG(NSCD_LOG_ACCESS_INFO, NSCD_LOG_LEVEL_DEBUG) + (me, "data = %p, access->data = %p\n", data, access->data); + ASSERT_ACCESS_DATA; + + assert(access->data_cond != NULL); + + (void) cond_signal(access->data_cond); +} + +/* + * FUNCTION: _nscd_alloc + * + * Allocate a piece of nscd memory. 'data_free' + * is the function to invoke to free the data + * stored in this memory, i.e., the desctrctor. + * 'option' indicate whether a mutex or a + * readers/writer (or both, or none) should also + * be allocated. + */ +nscd_acc_data_t * +_nscd_alloc( + int type, + size_t size, + void (*data_free)(nscd_acc_data_t *data), + int option) +{ + nscd_access_t *access; + nscd_acc_data_t *ptr; + nscd_seq_num_t seq_num; + rwlock_t *rwlock = NULL; + mutex_t *mutex = NULL; + cond_t *cond = NULL; + + if ((ptr = (nscd_acc_data_t *)calloc(1, + size + sizeof_access)) == NULL) + return (NULL); + if (option & NSCD_ALLOC_MUTEX) { + if ((mutex = (mutex_t *)calloc(1, sizeof (mutex_t))) == + NULL) { + free(ptr); + return (NULL); + } else + (void) mutex_init(mutex, USYNC_THREAD, NULL); + } + if (option & NSCD_ALLOC_RWLOCK) { + if ((rwlock = (rwlock_t *)calloc(1, sizeof (rwlock_t))) == + NULL) { + free(ptr); + free(mutex); + return (NULL); + } else + (void) rwlock_init(rwlock, USYNC_THREAD, NULL); + } + if (option & NSCD_ALLOC_COND) { + if ((cond = (cond_t *)calloc(1, sizeof (cond_t))) == + NULL) { + free(ptr); + free(mutex); + free(rwlock); + return (NULL); + } else + (void) cond_init(cond, USYNC_THREAD, NULL); + } + + /* get current sequence number */ + seq_num = _nscd_get_seq_num(); + + access = (nscd_access_t *)ptr; + access->data = (char *)ptr + sizeof_access; + access->data_mutex = mutex; + access->data_rwlock = rwlock; + access->data_cond = cond; + access->nUse = 0; + access->delete = 0; + access->type = type; + access->free_func = data_free; + access->seq_num = seq_num; + + /* add the address to the internal address database */ + if (_nscd_add_int_addr(access->data, type, + seq_num) != NSCD_SUCCESS) { + free(ptr); + return (NULL); + } + + return (access->data); +} + +/* + * FUNCTION: _nscd_free + * + * Free a piece of nscd memory. + */ +static void +_nscd_free( + nscd_acc_data_t *data) +{ + nscd_access_t *access; + + if (data == NULL) + return; + + SET_ACCESS_PTR; + ASSERT_ACCESS_DATA; + + /* remove the address from the internal address database */ + _nscd_del_int_addr(access->data, access->seq_num); + + if (access->data_mutex) + free(access->data_mutex); + if (access->data_rwlock) + free(access->data_rwlock); + if (access->data_cond) + free(access->data_cond); + + (void) memset(access, 0, sizeof (*access)); + + free(access); +} diff --git a/usr/src/cmd/nscd/nscd_admin.c b/usr/src/cmd/nscd/nscd_admin.c new file mode 100644 index 0000000000..5574e88744 --- /dev/null +++ b/usr/src/cmd/nscd/nscd_admin.c @@ -0,0 +1,410 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <stdlib.h> +#include <locale.h> +#include <string.h> +#include "cache.h" +#include "nscd_door.h" +#include "nscd_log.h" +#include "nscd_admin.h" + +extern nsc_ctx_t *cache_ctx_p[]; +extern char *cache_name[]; + +static nscd_admin_t admin_c = { 0 }; +static nscd_admin_mod_t admin_mod = { 0 }; +static mutex_t mod_lock = DEFAULTMUTEX; + +/*ARGSUSED*/ +int +_nscd_door_getadmin(void *outbuf) +{ + int i; + int data_size = NSCD_N2N_DOOR_BUF_SIZE(admin_c); + nss_pheader_t *phdr = (nss_pheader_t *)outbuf; + nscd_cfg_cache_t cfg_default = NSCD_CFG_CACHE_DEFAULTS; + + /* + * if size of buffer is not big enough, tell the caller to + * increase it to the size returned + */ + if (phdr->pbufsiz < data_size) + return (sizeof (admin_c)); + + NSCD_SET_STATUS_SUCCESS(phdr); + phdr->data_off = sizeof (nss_pheader_t); + phdr->data_len = sizeof (admin_c); + + for (i = 0; i < CACHE_CTX_COUNT; i++) { + if (cache_ctx_p[i] != NULL) { + (void) rw_rdlock(&cache_ctx_p[i]->cfg_rwlp); + admin_c.cache_cfg[i] = cache_ctx_p[i]->cfg; + (void) rw_unlock(&cache_ctx_p[i]->cfg_rwlp); + + (void) mutex_lock(&cache_ctx_p[i]->stats_mutex); + admin_c.cache_stats[i] = cache_ctx_p[i]->stats; + (void) mutex_unlock(&cache_ctx_p[i]->stats_mutex); + } else { + admin_c.cache_cfg[i] = cfg_default; + (void) memset(&admin_c.cache_stats[i], 0, + sizeof (admin_c.cache_stats[0])); + } + } + (void) memcpy(((char *)outbuf) + phdr->data_off, + &admin_c, sizeof (admin_c)); + + return (0); +} + +void +_nscd_client_showstats() +{ + (void) printf("nscd configuration:\n\n"); + (void) printf("%10d server debug level\n", admin_c.debug_level); + (void) printf("\"%s\" is server log file\n", admin_c.logfile); + + (void) nsc_info(NULL, NULL, admin_c.cache_cfg, admin_c.cache_stats); +} + +/*ARGSUSED*/ +nscd_rc_t +_nscd_server_setadmin(nscd_admin_mod_t *set) +{ + nscd_rc_t rc = NSCD_ADMIN_FAIL_TO_SET; + nscd_cfg_handle_t *h; + int i, j; + char *group = "param-group-cache"; + char *dbname; + nscd_cfg_error_t *err = NULL; + char *me = "_nscd_server_setadmin"; + + if (set == NULL) + set = &admin_mod; + + /* one setadmin at a time */ + (void) mutex_lock(&mod_lock); + + _NSCD_LOG_IF(NSCD_LOG_ADMIN, NSCD_LOG_LEVEL_DEBUG) { + + _nscd_logit(me, "total_size = %d\n", set->total_size); + + _nscd_logit(me, "debug_level_set = %d, debug_level = %d\n", + set->debug_level_set, set->debug_level); + + _nscd_logit(me, "logfile_set = %d, logfile = %s\n", + set->logfile_set, *set->logfile == '\0' ? + "" : set->logfile); + + _nscd_logit(me, "cache_cfg_num = %d\n", + set->cache_cfg_num); + _nscd_logit(me, "cache_flush_num = %d\n", + set->cache_flush_num); + } + + /* + * global admin stuff + */ + + if (set->debug_level_set == nscd_true) { + if (_nscd_set_debug_level(set->debug_level) + != NSCD_SUCCESS) { + + _NSCD_LOG(NSCD_LOG_ADMIN, NSCD_LOG_LEVEL_ERROR) + (me, "unable to set debug level %d\n", + set->debug_level); + + goto err_exit; + } + admin_c.debug_level = set->debug_level; + } + + if (set->logfile_set == nscd_true) { + if (_nscd_set_log_file(set->logfile) != NSCD_SUCCESS) { + + _NSCD_LOG(NSCD_LOG_ADMIN, NSCD_LOG_LEVEL_ERROR) + (me, "unable to set log file %s\n", set->logfile); + + goto err_exit; + } + (void) strlcpy(admin_c.logfile, set->logfile, + NSCD_LOGFILE_LEN); + } + + /* + * For caches to be changed + */ + if (set->cache_cfg_num > CACHE_CTX_COUNT) { + + _NSCD_LOG(NSCD_LOG_ADMIN, NSCD_LOG_LEVEL_ERROR) + (me, "number of caches (%d) to change out of bound %s\n", + set->cache_cfg_num); + + goto err_exit; + } + + for (i = 0; i < set->cache_cfg_num; i++) { + + nscd_cfg_cache_t *new_cfg; + + j = set->cache_cfg_set[i]; + new_cfg = &set->cache_cfg[i]; + dbname = cache_name[j]; + if (cache_ctx_p[j] == NULL) { + _NSCD_LOG(NSCD_LOG_ADMIN, NSCD_LOG_LEVEL_ERROR) + (me, "unable to find cache context for %s\n", + dbname); + } + + rc = _nscd_cfg_get_handle(group, dbname, &h, NULL); + if (rc != NSCD_SUCCESS) { + _NSCD_LOG(NSCD_LOG_ADMIN, NSCD_LOG_LEVEL_ERROR) + (me, "unable to get handle for < %s : %s >\n", + dbname, group); + + goto err_exit; + } + + rc = _nscd_cfg_set(h, new_cfg, &err); + if (rc != NSCD_SUCCESS) { + _NSCD_LOG(NSCD_LOG_ADMIN, NSCD_LOG_LEVEL_ERROR) + (me, "unable to set admin data for < %s : %s >\n", + dbname, group); + + _nscd_cfg_free_handle(h); + + goto err_exit; + } + _nscd_cfg_free_handle(h); + } + + /* + * For caches to be flushed + */ + if (set->cache_flush_num > CACHE_CTX_COUNT) { + + _NSCD_LOG(NSCD_LOG_ADMIN, NSCD_LOG_LEVEL_ERROR) + (me, "number of caches (%d) to flush out of bound %s\n", + set->cache_flush_num); + + goto err_exit; + } + + for (i = 0; i < set->cache_flush_num; i++) { + int j; + + j = set->cache_flush_set[i]; + + if (cache_ctx_p[j] == NULL) { + _NSCD_LOG(NSCD_LOG_ADMIN, NSCD_LOG_LEVEL_ERROR) + (me, "unable to find cache context for %s\n", + dbname); + } + nsc_invalidate(cache_ctx_p[j], NULL, NULL); + } + + rc = NSCD_SUCCESS; + err_exit: + + (void) mutex_unlock(&mod_lock); + return (rc); +} + + +/*ARGSUSED*/ +void +_nscd_door_setadmin(void *buf) +{ + nscd_rc_t rc; + nss_pheader_t *phdr = (nss_pheader_t *)buf; + char *me = "_nscd_door_setadmin"; + + rc = _nscd_server_setadmin(NSCD_N2N_DOOR_DATA(nscd_admin_mod_t, buf)); + if (rc != NSCD_SUCCESS) { + _NSCD_LOG(NSCD_LOG_ADMIN, NSCD_LOG_LEVEL_ERROR) + (me, "SETADMIN call failed\n"); + + NSCD_RETURN_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0, rc); + } else { + NSCD_RETURN_STATUS_SUCCESS(phdr); + } +} + +/* + * for a database 'dbname', add config value 'val' of option 'opt' + * to the global admin_mod structure + */ +int +_nscd_add_admin_mod(char *dbname, char opt, + char *val, char *msg, int msglen) { + int i, j; + nscd_cfg_cache_t *cfg; + nscd_cfg_group_info_t gi = NSCD_CFG_GROUP_INFO_CACHE; + char dbn[64], *cp; + + /* set initial admin_mod size; assume no cache config to set */ + if (admin_mod.total_size == 0) + admin_mod.total_size = sizeof (admin_mod) - + sizeof (admin_mod.cache_cfg); + + /* global admin stuff */ + if (opt == 'l' || opt == 'd') { + if (opt == 'l') { + (void) strlcpy(admin_mod.logfile, + val, NSCD_LOGFILE_LEN); + admin_mod.logfile_set = nscd_true; + } else { + admin_mod.debug_level = atoi(val); + admin_mod.debug_level_set = nscd_true; + } + return (0); + } + + /* options to be processed next requires cache name */ + (void) strlcpy(dbn, dbname, sizeof (dbn)); + if ((cp = strchr(dbn, ',')) != NULL) + *cp = '\0'; + i = get_cache_idx(dbn); + if (i == -1) { + (void) snprintf(msg, msglen, + gettext("invalid cache name \"%s\""), dbn); + return (-1); + } + + /* flush cache ? */ + if (opt == 'i') { + admin_mod.cache_flush_set[admin_mod.cache_flush_num++] = i; + return (0); + } + + /* options to be processed next requires a param value */ + if (val == NULL) { + (void) snprintf(msg, msglen, + gettext("value missing after \"%s\""), dbn); + return (-1); + } + + /* try to use an existing cache_cfg in admin_mod */ + for (j = 0; j < admin_mod.cache_cfg_num; j++) { + if (admin_mod.cache_cfg_set[j] == i) + break; + } + + /* no existing one, set up another one */ + if (j == admin_mod.cache_cfg_num) { + admin_mod.cache_cfg_set[j] = i; + admin_mod.cache_cfg_num++; + admin_mod.total_size += sizeof (admin_mod.cache_cfg[0]); + } + + cfg = &admin_mod.cache_cfg[j]; + cfg->gi.num_param = gi.num_param; + + switch (opt) { + + case 'e': + /* enable cache */ + + _nscd_cfg_bitmap_set_nth(cfg->gi.bitmap, 0); + if (strcmp(val, "yes") == 0) + cfg->enable = nscd_true; + else if (strcmp(val, "no") == 0) + cfg->enable = nscd_false; + else { + (void) snprintf(msg, msglen, + gettext("\"yes\" or \"no\" not specified after \"%s\""), dbn); + return (-1); + } + break; + + case 'c': + /* check files */ + + _nscd_cfg_bitmap_set_nth(cfg->gi.bitmap, 3); + if (strcmp(val, "yes") == 0) + cfg->check_files = nscd_true; + else if (strcmp(val, "no") == 0) + cfg->check_files = nscd_false; + else { + (void) snprintf(msg, msglen, + gettext("\"yes\" or \"no\" not specified after \"%s\""), dbn); + return (-1); + } + break; + + case 'p': + /* positive time to live */ + + _nscd_cfg_bitmap_set_nth(cfg->gi.bitmap, 5); + cfg->pos_ttl = atoi(val); + break; + + case 'n': + /* negative time to live */ + + _nscd_cfg_bitmap_set_nth(cfg->gi.bitmap, 6); + cfg->neg_ttl = atoi(val); + break; + + case 'h': + /* keep hot count */ + + _nscd_cfg_bitmap_set_nth(cfg->gi.bitmap, 7); + cfg->keephot = atoi(val); + break; + } + + return (0); +} + +int +_nscd_client_getadmin(char opt) +{ + int callnum; + nss_pheader_t phdr; + + if (opt == 'G') + callnum = NSCD_GETPUADMIN; + else + callnum = NSCD_GETADMIN; + + (void) _nscd_doorcall_data(callnum, NULL, sizeof (admin_c), + &admin_c, sizeof (admin_c), &phdr); + + if (NSCD_STATUS_IS_NOT_OK(&phdr)) { + return (1); + } + + return (0); +} + +int +_nscd_client_setadmin() +{ + return (_nscd_doorcall_data(NSCD_SETADMIN, &admin_mod, + sizeof (admin_mod), NULL, 0, NULL)); +} diff --git a/usr/src/cmd/nscd/nscd_admin.h b/usr/src/cmd/nscd/nscd_admin.h new file mode 100644 index 0000000000..520290e420 --- /dev/null +++ b/usr/src/cmd/nscd/nscd_admin.h @@ -0,0 +1,81 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _NSCD_ADMIN_H +#define _NSCD_ADMIN_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + +#include "cache.h" +#include "nscd_common.h" +#include "nscd_config.h" + +#define NSCD_LOGFILE_LEN 128 + +/* + * structure used for door call NSCD_GETADMIN and NSCD_GETPUADMIN + */ +typedef struct nscd_admin { + int debug_level; + char logfile[NSCD_LOGFILE_LEN]; + nscd_cfg_cache_t cache_cfg[CACHE_CTX_COUNT]; + nscd_cfg_stat_cache_t cache_stats[CACHE_CTX_COUNT]; +} nscd_admin_t; + +/* + * structure used for door call NSCD_SETADMIN and NSCD_SETPUADMIN + */ +typedef struct nscd_admin_mod { + int total_size; + nscd_bool_t debug_level_set; + nscd_bool_t logfile_set; + uint8_t cache_cfg_set[CACHE_CTX_COUNT]; + uint8_t cache_flush_set[CACHE_CTX_COUNT]; + nscd_bool_t global_cfg_set; + uint8_t cache_cfg_num; + uint8_t cache_flush_num; + int debug_level; + char logfile[NSCD_LOGFILE_LEN]; + nscd_cfg_cache_t cache_cfg[CACHE_CTX_COUNT]; +} nscd_admin_mod_t; + +#ifdef __cplusplus +} +#endif + +int _nscd_client_getadmin(char opt); +int _nscd_client_setadmin(); +void _nscd_client_showstats(); +nscd_rc_t _nscd_server_setadmin(nscd_admin_mod_t *set); +int _nscd_door_getadmin(void *outbuf); +void _nscd_door_setadmin(void *buf); +int _nscd_add_admin_mod(char *dbname, char opt, + char *val, char *msg, int msglen); + +#endif /* _NSCD_ADMIN_H */ diff --git a/usr/src/cmd/nscd/nscd_biggest.c b/usr/src/cmd/nscd/nscd_biggest.c index 7ddfda863e..a0d6c9edff 100644 --- a/usr/src/cmd/nscd/nscd_biggest.c +++ b/usr/src/cmd/nscd/nscd_biggest.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -30,87 +29,54 @@ #include <string.h> #include <stdlib.h> -/* - * routines to find largest n numbers, carrying 4 bytes of data - */ +#include "cache.h" -int * +nsc_keephot_t * maken(int n) { - int * ret; - - n++; + nsc_keephot_t *ret; - ret = (int *) memset(malloc(2 * n *sizeof (int)), - -1, 2 * n * sizeof (int)); - ret[0] = n - 1; + ++n; + ret = (nsc_keephot_t *)calloc(n, sizeof (nsc_keephot_t)); + if (ret == NULL) + return (NULL); + ret[0].num = n - 1; return (ret); } -int -insertn(int * table, int n, int data) +void * +insertn(nsc_keephot_t *table, uint_t n, void *data) { - int size = *table; - int guess, base, last; - int olddata; + void *olddata; + int size, guess, base, last; - if (table[1] > n) + if (n < 1 || table[1].num > n) { return (data); + } - if (table[size] < n) /* biggest so far */ + size = table[0].num; + if (table[size].num < n) /* biggest so far */ guess = size; else { base = 1; last = size; while (last >= base) { guess = (last+base)/2; - if (table[guess] == n) + if (table[guess].num == n) goto doit; - if (table[guess] > n) - last = guess -1; + if (table[guess].num > n) + last = guess - 1; else base = guess + 1; } guess = last; } - doit: - olddata = table[2 + size]; - memmove(table + 1, table+2, sizeof (int) * (guess-1)); - memmove(table + 2 + size, table + 3 + size, sizeof (int) * (guess-1)); - table[guess + size + 1] = data; - table[guess] = n; - return (olddata); -} -/* - * test code - */ -#if 0 -int -main(int argc, char * argv[]) -{ - int * t; - char buffer[100]; - int i, n; - char * tmp; - - t = maken(100); - - for (i = 0; i < 1100; i++) { - n = random(); - sprintf(buffer, "trial %d: %d", i, n); - tmp = (char *)insertn(t, n, (int)strdup(buffer)); - if (tmp != -1) { - printf("freeing %s\n", tmp); - free(tmp); - } - } - - for (i = 1; i <= 100; i++) { - printf("%d: %s\n", i, t[100 + 1 + i]); - free((char *)t[100 + 1 + i]); - } - - free(t); +doit: + olddata = table[1].ptr; + (void) memmove(table + 1, table + 2, + sizeof (nsc_keephot_t) * (guess-1)); + table[guess].ptr = data; + table[guess].num = n; + return (olddata); } -#endif diff --git a/usr/src/cmd/nscd/nscd_cfgdef.h b/usr/src/cmd/nscd/nscd_cfgdef.h new file mode 100644 index 0000000000..09c9584463 --- /dev/null +++ b/usr/src/cmd/nscd/nscd_cfgdef.h @@ -0,0 +1,1413 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _NSCD_CFGDEF_H +#define _NSCD_CFGDEF_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + +#include <stddef.h> +#include <limits.h> +#include <nss_dbdefs.h> +#include "nscd_config.h" +#include "nscd_log.h" +#include "cache.h" + +/* + * structure used for preliminary checking of an integer + * configuration value + */ +typedef struct { + int min; + int max; +} nscd_cfg_int_check_t; + +/* + * structure used for preliminary checking of a bitmap + * configuration value + */ +typedef struct { + nscd_cfg_bitmap_t valid_bits; +} nscd_cfg_bitmap_check_t; + +/* + * structure used for preliminary checking of a string + * configuration value + */ +typedef struct { + nscd_bool_t must_not_null; + int maxlen; +} nscd_cfg_str_check_t; + +/* + * Per nsswitch database config data + */ +typedef struct { + nscd_cfg_frontend_t fe; + nscd_cfg_switch_t sw; + nscd_cfg_cache_t cache; +} nscd_cfg_nsw_db_data_t; + +/* + * Per nsswitch database statistics data + */ +typedef struct { + nscd_cfg_stat_switch_t sw; + nscd_cfg_stat_cache_t cache; +} nscd_cfg_stat_nsw_db_data_t; + +/* + * global statistics data + */ +typedef struct { + nscd_cfg_stat_global_log_t log; + nscd_cfg_stat_global_switch_t sw; + nscd_cfg_stat_cache_t cache; +} nscd_cfg_stat_global_data_t; + +/* + * global config data + */ +typedef struct { + nscd_cfg_global_log_t log; + nscd_cfg_global_frontend_t fe; + nscd_cfg_global_selfcred_t sc; + nscd_cfg_global_switch_t sw; + nscd_cfg_global_cache_t cache; +} nscd_cfg_global_data_t; + +/* + * structure for handling the switch database specific group + * or parameter default + */ +typedef struct nscd_cfg_nsw_spc_default { + char *db; + int group_off; + int param_off; + void *data; /* pointer or link to data */ + int data_len; +} nscd_cfg_nsw_spc_default_t; + +/* + * name service switch source (repository) table + */ +nscd_cfg_id_t _nscd_cfg_nsw_src[] = { + { 0, "files" }, + { 1, "ldap" }, + { 2, "nis" }, + { 3, "nisplus" }, + { 4, "dns" }, + { 5, "compat" }, + { 6, "user" }, + { -1, NULL } +}; + +/* + * name service related smf service table + * (the order of the services should match the order of the source + * listed above, 0: files, 1: ldap, 2: nis, 3: nisplus. dns is + * not needed) + */ +nscd_cfg_id_t _nscd_cfg_smf_services[] = { + { 0, "svc:/system/name-service-cache:default"}, + { 1, "svc:/network/ldap/client:default" }, + { 2, "svc:/network/nis/client:default" }, + { 3, "svc:/network/rpc/nisplus:default" }, + { -1, NULL } +}; + +/* + * name service database table + */ +nscd_cfg_id_t _nscd_cfg_nsw_db[] = { + { 0, NSS_DBNAM_PASSWD }, + { 1, NSS_DBNAM_GROUP }, + { 2, NSS_DBNAM_HOSTS }, + { 3, NSS_DBNAM_IPNODES }, + { 4, NSS_DBNAM_EXECATTR }, + { 5, NSS_DBNAM_PROFATTR }, + { 6, NSS_DBNAM_USERATTR }, + { 7, NSS_DBNAM_NETWORKS }, + { 8, NSS_DBNAM_PROTOCOLS }, + { 9, NSS_DBNAM_RPC }, + { 10, NSS_DBNAM_ETHERS }, + { 11, NSS_DBNAM_NETMASKS }, + { 12, NSS_DBNAM_BOOTPARAMS }, + { 13, NSS_DBNAM_PUBLICKEY }, + { 14, NSS_DBNAM_NETGROUP }, + { 15, NSS_DBNAM_SERVICES }, + { 16, NSS_DBNAM_PRINTERS }, + { 17, NSS_DBNAM_AUTHATTR }, + { 18, NSS_DBNAM_PROJECT }, + { 19, NSS_DBNAM_SHADOW }, + { 20, NSS_DBNAM_AUDITUSER }, + { 21, NSS_DBNAM_TSOL_TP }, + { 22, NSS_DBNAM_TSOL_RH }, + /* pseudo-databases for the compat backend */ + { 23, NSS_DBNAM_PASSWD_COMPAT }, + { 24, NSS_DBNAM_GROUP_COMPAT }, +#define NSS_DBNAM_COMPAT_NUM_DB 5 + /* + * pseudo-databases that use the switch policy that is + * configured for NSS_DBNAM_PASSWD_COMPAT + */ + { 25, NSS_DBNAM_PASSWD }, + { 26, NSS_DBNAM_SHADOW }, + { 27, NSS_DBNAM_AUDITUSER }, + { 28, NSS_DBNAM_USERATTR }, + /* + * pseudo-database that uses the switch policy that is + * configured for NSS_DBNAM_GROUP_COMPAT + */ + { 29, NSS_DBNAM_GROUP }, + { -1, NULL } +}; + +/* + * A special way to indicate all switch databases + */ +static nscd_cfg_id_t _nscd_cfg_nsw_alldb = { + NSCD_CFG_NSW_ALLDB_INDEX, + NSCD_CFG_NSW_ALLDB +}; + +/* + * data for preliminary checking of the log configuration + */ +static nscd_cfg_str_check_t NSCD_CFG_LOGFILE_PCHECK = + {nscd_false, PATH_MAX}; +static nscd_cfg_bitmap_check_t NSCD_CFG_LOGCOMP_PCHECK = + {NSCD_LOG_ALL}; +static nscd_cfg_bitmap_check_t NSCD_CFG_LOGLEVEL_PCHECK = + {NSCD_LOG_LEVEL_ALL}; + +/* data for preliminary checking of the switch configuration */ +static nscd_cfg_str_check_t NSCD_CFG_NSWCFGSTR_PCHECK = + {nscd_true, 128}; + +/* + * macros for defining the static param table + */ +#define NSCD_CFG_PGROUP_DESC(pn, type, pflag, gf, g_in_t, pcheck_p,\ + nfunc_name, vfunc_name) \ + { \ + {-1, pn}, type, (NSCD_CFG_PFLAG_GROUP | pflag), \ + 0, 0, 0,\ + NSCD_SIZEOF(g_in_t, gf), offsetof(g_in_t, gf), -1, \ + pcheck_p, nfunc_name, vfunc_name, NULL, NULL \ + } + +#define NSCD_CFG_PARAM_DESC(pn, type, pflag, pf, p_in_t, \ + gf, g_in_t, pcheck_p, nfunc_name, vfunc_name) \ + { \ + {-1, pn}, type, pflag, \ + NSCD_SIZEOF(p_in_t, pf), offsetof(p_in_t, pf), -1, \ + NSCD_SIZEOF(g_in_t, gf), offsetof(g_in_t, gf), -1, \ + pcheck_p, nfunc_name, vfunc_name, NULL, NULL \ + } + +#define NSCD_CFG_PGROUP_DESC_NULL \ + { \ + {-1, NULL}, -1, NSCD_CFG_PFLAG_GROUP, \ + 0, 0, 0, \ + 0, 0, 0, \ + NULL, NULL, NULL, NULL, NULL \ + } +#define NSCD_CFG_FUNC_NAME_AS_GROUP "(as_group)" + +/* + * the static config parameter description table + */ +static nscd_cfg_param_desc_t _nscd_cfg_param_desc[] = { + + NSCD_CFG_PGROUP_DESC( + "param-group-global-log", + NSCD_CFG_DATA_NONE, + NSCD_CFG_PFLAG_INIT_SEND_WHOLE_GROUP | + NSCD_CFG_PFLAG_GLOBAL, + log, + nscd_cfg_global_data_t, + NULL, + "_nscd_cfg_log_notify", + "_nscd_cfg_log_verify"), + + NSCD_CFG_PARAM_DESC( + "logfile", + NSCD_CFG_DATA_STRING, + NSCD_CFG_PFLAG_GLOBAL | + NSCD_CFG_PFLAG_VLEN_DATA, + logfile, + nscd_cfg_global_log_t, + log, + nscd_cfg_global_data_t, + &NSCD_CFG_LOGFILE_PCHECK, + NSCD_CFG_FUNC_NAME_AS_GROUP, + NSCD_CFG_FUNC_NAME_AS_GROUP), + + NSCD_CFG_PARAM_DESC( + "debug-level", + NSCD_CFG_DATA_BITMAP, + NSCD_CFG_PFLAG_GLOBAL, + debug_level, + nscd_cfg_global_log_t, + log, + nscd_cfg_global_data_t, + &NSCD_CFG_LOGLEVEL_PCHECK, + NSCD_CFG_FUNC_NAME_AS_GROUP, + NSCD_CFG_FUNC_NAME_AS_GROUP), + + NSCD_CFG_PARAM_DESC( + "debug-components", + NSCD_CFG_DATA_BITMAP, + NSCD_CFG_PFLAG_GLOBAL, + debug_comp, + nscd_cfg_global_log_t, + log, + nscd_cfg_global_data_t, + &NSCD_CFG_LOGCOMP_PCHECK, + NSCD_CFG_FUNC_NAME_AS_GROUP, + NSCD_CFG_FUNC_NAME_AS_GROUP), + + NSCD_CFG_PGROUP_DESC( + "param-group-global-frontend", + NSCD_CFG_DATA_NONE, + NSCD_CFG_PFLAG_INIT_SEND_WHOLE_GROUP | + NSCD_CFG_PFLAG_GLOBAL, + fe, + nscd_cfg_global_data_t, + NULL, + "_nscd_cfg_frontend_notify", + "_nscd_cfg_frontend_verify"), + + NSCD_CFG_PARAM_DESC( + "common-worker-threads", + NSCD_CFG_DATA_INTEGER, + NSCD_CFG_PFLAG_SEND_BIT_SELECTED | + NSCD_CFG_PFLAG_GLOBAL, + common_worker_threads, + nscd_cfg_global_frontend_t, + fe, + nscd_cfg_global_data_t, + NULL, + NSCD_CFG_FUNC_NAME_AS_GROUP, + NSCD_CFG_FUNC_NAME_AS_GROUP), + + NSCD_CFG_PARAM_DESC( + "cache-hit-threads", + NSCD_CFG_DATA_INTEGER, + NSCD_CFG_PFLAG_SEND_BIT_SELECTED | + NSCD_CFG_PFLAG_GLOBAL, + cache_hit_threads, + nscd_cfg_global_frontend_t, + fe, + nscd_cfg_global_data_t, + NULL, + NSCD_CFG_FUNC_NAME_AS_GROUP, + NSCD_CFG_FUNC_NAME_AS_GROUP), + + NSCD_CFG_PGROUP_DESC( + "param-group-global-selfcred", + NSCD_CFG_DATA_NONE, + NSCD_CFG_PFLAG_INIT_SEND_WHOLE_GROUP | + NSCD_CFG_PFLAG_GLOBAL, + sc, + nscd_cfg_global_data_t, + NULL, + "_nscd_cfg_selfcred_notify", + "_nscd_cfg_selfcred_verify"), + + NSCD_CFG_PARAM_DESC( + "enable-selfcred", + NSCD_CFG_DATA_BOOLEAN, + NSCD_CFG_PFLAG_GLOBAL, + enable_selfcred, + nscd_cfg_global_selfcred_t, + sc, + nscd_cfg_global_data_t, + NULL, + NSCD_CFG_FUNC_NAME_AS_GROUP, + NSCD_CFG_FUNC_NAME_AS_GROUP), + + NSCD_CFG_PARAM_DESC( + "max-per-user-nscd", + NSCD_CFG_DATA_INTEGER, + NSCD_CFG_PFLAG_GLOBAL, + max_per_user_nscd, + nscd_cfg_global_selfcred_t, + sc, + nscd_cfg_global_data_t, + NULL, + NSCD_CFG_FUNC_NAME_AS_GROUP, + NSCD_CFG_FUNC_NAME_AS_GROUP), + + NSCD_CFG_PARAM_DESC( + "per-user-nscd-ttl", + NSCD_CFG_DATA_INTEGER, + NSCD_CFG_PFLAG_GLOBAL, + per_user_nscd_ttl, + nscd_cfg_global_selfcred_t, + sc, + nscd_cfg_global_data_t, + NULL, + NSCD_CFG_FUNC_NAME_AS_GROUP, + NSCD_CFG_FUNC_NAME_AS_GROUP), + + NSCD_CFG_PGROUP_DESC( + "param-group-global-switch", + NSCD_CFG_DATA_NONE, + NSCD_CFG_PFLAG_INIT_SEND_WHOLE_GROUP | + NSCD_CFG_PFLAG_GLOBAL, + sw, + nscd_cfg_global_data_t, + NULL, + "_nscd_cfg_switch_notify", + "_nscd_cfg_switch_verify"), + + NSCD_CFG_PARAM_DESC( + "global-enable-lookup", + NSCD_CFG_DATA_BOOLEAN, + NSCD_CFG_PFLAG_GLOBAL, + enable_lookup_g, + nscd_cfg_global_switch_t, + sw, + nscd_cfg_global_data_t, + NULL, + NSCD_CFG_FUNC_NAME_AS_GROUP, + NSCD_CFG_FUNC_NAME_AS_GROUP), + + NSCD_CFG_PARAM_DESC( + "global-enable-loopback-checking", + NSCD_CFG_DATA_BOOLEAN, + NSCD_CFG_PFLAG_GLOBAL, + enable_loopback_checking_g, + nscd_cfg_global_switch_t, + sw, + nscd_cfg_global_data_t, + NULL, + NSCD_CFG_FUNC_NAME_AS_GROUP, + NSCD_CFG_FUNC_NAME_AS_GROUP), + + NSCD_CFG_PARAM_DESC( + "global-check-smf-state-interval", + NSCD_CFG_DATA_INTEGER, + NSCD_CFG_PFLAG_GLOBAL, + check_smf_state_interval_g, + nscd_cfg_global_switch_t, + sw, + nscd_cfg_global_data_t, + NULL, + NSCD_CFG_FUNC_NAME_AS_GROUP, + NSCD_CFG_FUNC_NAME_AS_GROUP), + + NSCD_CFG_PGROUP_DESC( + "param-group-global-cache", + NSCD_CFG_DATA_NONE, + NSCD_CFG_PFLAG_INIT_SEND_WHOLE_GROUP | + NSCD_CFG_PFLAG_INIT_SET_ALL_DB | + NSCD_CFG_PFLAG_GLOBAL, + cache, + nscd_cfg_global_data_t, + NULL, + "_nscd_cfg_cache_notify", + "_nscd_cfg_cache_verify"), + + NSCD_CFG_PARAM_DESC( + "global-enable-cache", + NSCD_CFG_DATA_BOOLEAN, + NSCD_CFG_PFLAG_GLOBAL, + enable, + nscd_cfg_global_cache_t, + cache, + nscd_cfg_global_data_t, + NULL, + NSCD_CFG_FUNC_NAME_AS_GROUP, + NSCD_CFG_FUNC_NAME_AS_GROUP), + + /* non-global config param from this point on */ + + NSCD_CFG_PGROUP_DESC( + "param-group-frontend", + NSCD_CFG_DATA_NONE, + NSCD_CFG_PFLAG_INIT_SEND_WHOLE_GROUP, + fe, + nscd_cfg_nsw_db_data_t, + NULL, + "_nscd_cfg_frontend_notify", + "_nscd_cfg_frontend_verify"), + + NSCD_CFG_PARAM_DESC( + "worker-thread-per-nsw-db", + NSCD_CFG_DATA_INTEGER, + NSCD_CFG_PFLAG_NONE, + worker_thread_per_nsw_db, + nscd_cfg_frontend_t, + fe, + nscd_cfg_nsw_db_data_t, + NULL, + NSCD_CFG_FUNC_NAME_AS_GROUP, + NSCD_CFG_FUNC_NAME_AS_GROUP), + + NSCD_CFG_PGROUP_DESC( + "param-group-switch", + NSCD_CFG_DATA_NONE, + NSCD_CFG_PFLAG_INIT_SEND_WHOLE_GROUP | + NSCD_CFG_PFLAG_NONE, + sw, + nscd_cfg_nsw_db_data_t, + NULL, + "_nscd_cfg_switch_notify", + "_nscd_cfg_switch_verify"), + + NSCD_CFG_PARAM_DESC( + "nsw-config-string", + NSCD_CFG_DATA_STRING, + NSCD_CFG_PFLAG_VLEN_DATA | + NSCD_CFG_PFLAG_LINKED, + nsw_config_string, + nscd_cfg_switch_t, + sw, + nscd_cfg_nsw_db_data_t, + &NSCD_CFG_NSWCFGSTR_PCHECK, + NSCD_CFG_FUNC_NAME_AS_GROUP, + NSCD_CFG_FUNC_NAME_AS_GROUP), + + NSCD_CFG_PARAM_DESC( + "nsw-config-database", + NSCD_CFG_DATA_STRING, + NSCD_CFG_PFLAG_VLEN_DATA | + NSCD_CFG_PFLAG_HIDDEN, + nsw_config_db, + nscd_cfg_switch_t, + sw, + nscd_cfg_nsw_db_data_t, + &NSCD_CFG_NSWCFGSTR_PCHECK, + NSCD_CFG_FUNC_NAME_AS_GROUP, + NSCD_CFG_FUNC_NAME_AS_GROUP), + + NSCD_CFG_PARAM_DESC( + "enable-lookup", + NSCD_CFG_DATA_BOOLEAN, + NSCD_CFG_PFLAG_NONE, + enable_lookup, + nscd_cfg_switch_t, + sw, + nscd_cfg_nsw_db_data_t, + NULL, + NSCD_CFG_FUNC_NAME_AS_GROUP, + NSCD_CFG_FUNC_NAME_AS_GROUP), + + NSCD_CFG_PARAM_DESC( + "enable-loopback-checking", + NSCD_CFG_DATA_BOOLEAN, + NSCD_CFG_PFLAG_NONE, + enable_loopback_checking, + nscd_cfg_switch_t, + sw, + nscd_cfg_nsw_db_data_t, + NULL, + NSCD_CFG_FUNC_NAME_AS_GROUP, + NSCD_CFG_FUNC_NAME_AS_GROUP), + + NSCD_CFG_PARAM_DESC( + "max-nsw-state-per-db", + NSCD_CFG_DATA_INTEGER, + NSCD_CFG_PFLAG_NONE, + max_nsw_state_per_db, + nscd_cfg_switch_t, + sw, + nscd_cfg_nsw_db_data_t, + NULL, + NSCD_CFG_FUNC_NAME_AS_GROUP, + NSCD_CFG_FUNC_NAME_AS_GROUP), + + NSCD_CFG_PARAM_DESC( + "max-nsw-state-per-thread", + NSCD_CFG_DATA_INTEGER, + NSCD_CFG_PFLAG_NONE, + max_nsw_state_per_thread, + nscd_cfg_switch_t, + sw, + nscd_cfg_nsw_db_data_t, + NULL, + NSCD_CFG_FUNC_NAME_AS_GROUP, + NSCD_CFG_FUNC_NAME_AS_GROUP), + + NSCD_CFG_PARAM_DESC( + "max-getent-ctx-per-db", + NSCD_CFG_DATA_INTEGER, + NSCD_CFG_PFLAG_NONE, + max_getent_ctx_per_db, + nscd_cfg_switch_t, + sw, + nscd_cfg_nsw_db_data_t, + NULL, + NSCD_CFG_FUNC_NAME_AS_GROUP, + NSCD_CFG_FUNC_NAME_AS_GROUP), + + NSCD_CFG_PGROUP_DESC( + "param-group-cache", + NSCD_CFG_DATA_NONE, + NSCD_CFG_PFLAG_INIT_SEND_WHOLE_GROUP, + cache, + nscd_cfg_nsw_db_data_t, + NULL, + "_nscd_cfg_cache_notify", + "_nscd_cfg_cache_verify"), + + NSCD_CFG_PARAM_DESC( + "enable-cache", + NSCD_CFG_DATA_BOOLEAN, + NSCD_CFG_PFLAG_NONE, + enable, + nscd_cfg_cache_t, + cache, + nscd_cfg_nsw_db_data_t, + NULL, + NSCD_CFG_FUNC_NAME_AS_GROUP, + NSCD_CFG_FUNC_NAME_AS_GROUP), + + NSCD_CFG_PARAM_DESC( + "enable-per-user-cache", + NSCD_CFG_DATA_BOOLEAN, + NSCD_CFG_PFLAG_NONE, + per_user, + nscd_cfg_cache_t, + cache, + nscd_cfg_nsw_db_data_t, + NULL, + NSCD_CFG_FUNC_NAME_AS_GROUP, + NSCD_CFG_FUNC_NAME_AS_GROUP), + + NSCD_CFG_PARAM_DESC( + "avoid-nameservice", + NSCD_CFG_DATA_BOOLEAN, + NSCD_CFG_PFLAG_NONE, + avoid_ns, + nscd_cfg_cache_t, + cache, + nscd_cfg_nsw_db_data_t, + NULL, + NSCD_CFG_FUNC_NAME_AS_GROUP, + NSCD_CFG_FUNC_NAME_AS_GROUP), + + NSCD_CFG_PARAM_DESC( + "check-files", + NSCD_CFG_DATA_BOOLEAN, + NSCD_CFG_PFLAG_NONE, + check_files, + nscd_cfg_cache_t, + cache, + nscd_cfg_nsw_db_data_t, + NULL, + NSCD_CFG_FUNC_NAME_AS_GROUP, + NSCD_CFG_FUNC_NAME_AS_GROUP), + + NSCD_CFG_PARAM_DESC( + "check-file-interval", + NSCD_CFG_DATA_INTEGER, + NSCD_CFG_PFLAG_NONE, + check_interval, + nscd_cfg_cache_t, + cache, + nscd_cfg_nsw_db_data_t, + NULL, + NSCD_CFG_FUNC_NAME_AS_GROUP, + NSCD_CFG_FUNC_NAME_AS_GROUP), + + NSCD_CFG_PARAM_DESC( + "positive-time-to-live", + NSCD_CFG_DATA_INTEGER, + NSCD_CFG_PFLAG_NONE, + pos_ttl, + nscd_cfg_cache_t, + cache, + nscd_cfg_nsw_db_data_t, + NULL, + NSCD_CFG_FUNC_NAME_AS_GROUP, + NSCD_CFG_FUNC_NAME_AS_GROUP), + + NSCD_CFG_PARAM_DESC( + "negative-time-to-live", + NSCD_CFG_DATA_INTEGER, + NSCD_CFG_PFLAG_NONE, + neg_ttl, + nscd_cfg_cache_t, + cache, + nscd_cfg_nsw_db_data_t, + NULL, + NSCD_CFG_FUNC_NAME_AS_GROUP, + NSCD_CFG_FUNC_NAME_AS_GROUP), + + NSCD_CFG_PARAM_DESC( + "keep-hot-count", + NSCD_CFG_DATA_INTEGER, + NSCD_CFG_PFLAG_NONE, + keephot, + nscd_cfg_cache_t, + cache, + nscd_cfg_nsw_db_data_t, + NULL, + NSCD_CFG_FUNC_NAME_AS_GROUP, + NSCD_CFG_FUNC_NAME_AS_GROUP), + + NSCD_CFG_PARAM_DESC( + "hint-size", + NSCD_CFG_DATA_INTEGER, + NSCD_CFG_PFLAG_NONE, + hint_size, + nscd_cfg_cache_t, + cache, + nscd_cfg_nsw_db_data_t, + NULL, + NSCD_CFG_FUNC_NAME_AS_GROUP, + NSCD_CFG_FUNC_NAME_AS_GROUP), + + NSCD_CFG_PARAM_DESC( + "maximum-entries-allowed", + NSCD_CFG_DATA_INTEGER, + NSCD_CFG_PFLAG_NONE, + maxentries, + nscd_cfg_cache_t, + cache, + nscd_cfg_nsw_db_data_t, + NULL, + NSCD_CFG_FUNC_NAME_AS_GROUP, + NSCD_CFG_FUNC_NAME_AS_GROUP), + + NSCD_CFG_PARAM_DESC( + "suggested-size", + NSCD_CFG_DATA_INTEGER, + NSCD_CFG_PFLAG_OBSOLETE, + suggestedsize, + nscd_cfg_cache_t, + cache, + nscd_cfg_nsw_db_data_t, + NULL, + NSCD_CFG_FUNC_NAME_AS_GROUP, + NSCD_CFG_FUNC_NAME_AS_GROUP), + + NSCD_CFG_PARAM_DESC( + "old-data-ok", + NSCD_CFG_DATA_BOOLEAN, + NSCD_CFG_PFLAG_OBSOLETE, + old_data_ok, + nscd_cfg_cache_t, + cache, + nscd_cfg_nsw_db_data_t, + NULL, + NSCD_CFG_FUNC_NAME_AS_GROUP, + NSCD_CFG_FUNC_NAME_AS_GROUP), + + NSCD_CFG_PGROUP_DESC_NULL +}; + +/* + * defaults for the global configuration + */ +static nscd_cfg_global_data_t nscd_cfg_global_default = { + + /* + * nscd_cfg_global_log_t + */ + { + + NSCD_CFG_GROUP_INFO_GLOBAL_LOG, + NULL, + NSCD_LOG_LEVEL_ERROR, /* debug_level */ + NSCD_LOG_CACHE, /* debug_comp */ + + }, + + /* + * nscd_cfg_global_frontend_t + */ + { + + NSCD_CFG_GROUP_INFO_GLOBAL_FRONTEND, + 20, /* common_worker_threads */ + 20, /* cache_hit_threads */ + + }, + + /* + * nscd_cfg_global_selfcred_t + */ + { + + NSCD_CFG_GROUP_INFO_GLOBAL_SELFCRED, + nscd_true, /* enable_selfcred */ + 1000, /* max_per_user_nscd */ + 120, /* per_user_nscd_ttl: 120 seconds */ + + }, + + /* + * nscd_cfg_global_switch_t + */ + { + + NSCD_CFG_GROUP_INFO_GLOBAL_SWITCH, + nscd_true, /* enable_lookup_g */ + nscd_false, /* enable_loopback_checking_g */ + 120, /* check_smf_state_interval_g */ + + }, + + /* + * nscd_cfg_global_cache_t + */ + NSCD_CFG_GLOBAL_CACHE_DEFAULTS +}; + +/* + * defaults for the per switch database configuration + */ +static nscd_cfg_nsw_db_data_t nscd_cfg_nsw_db_data_default = { + + /* + * nscd_cfg_frontend_t + */ + { + + NSCD_CFG_GROUP_INFO_FRONTEND, + 10, /* worker_thread_per_nsw_db */ + + }, + + /* + * nscd_cfg_switch_t + */ + { + + NSCD_CFG_GROUP_INFO_SWITCH, + "nis files", /* nsw_config_string */ + NULL, /* nsw_config_db */ + nscd_true, /* enable_lookup */ + nscd_false, /* enable_loopback_checking */ + 10, /* max_nsw_state_per_db */ + 5, /* max_nsw_state_per_thread */ + 10, /* max_getent_ctx_per_db */ + + }, + + /* + * nscd_cfg_cache_t + */ + NSCD_CFG_CACHE_DEFAULTS +}; + +/* + * macros for defining the database specific defaults + */ +#define NSCD_CFG_DB_DEFAULT_PARAM(db, gf, pf, gt, defaddr, deflen) \ + { \ + db, offsetof(nscd_cfg_nsw_db_data_t, gf), \ + offsetof(gt, pf), defaddr, deflen \ + } + +#define NSCD_CFG_DB_DEFAULT_GROUP(db, gf, defaddr, deflen) \ + { \ + db, offsetof(nscd_cfg_nsw_db_data_t, gf), \ + 0, defaddr, deflen \ + } + +#define NSCD_CFG_DB_DEFAULT_NULL \ + { \ + NULL, 0, 0, NULL, 0 \ + } + +/* + * shadow, user_attr, and audit_user use the same switch policy + * as that of passwd. exec_attr use that of prof_attr. + */ +static char *nscd_cfg_shadow_cfg_db = NSS_DBNAM_PASSWD; +static char *nscd_cfg_userattr_cfg_db = NSS_DBNAM_PASSWD; +static char *nscd_cfg_auuser_cfg_db = NSS_DBNAM_PASSWD; +static char *nscd_cfg_execattr_cfg_db = NSS_DBNAM_PROFATTR; + +/* + * default switch policy for pseudo-databases passwd_compat and + * and group_compa is "nis" + */ +static char *nscd_cfg_def_passwd_compat = NSS_DEFCONF_PASSWD_COMPAT; +static char *nscd_cfg_def_group_compat = NSS_DEFCONF_GROUP_COMPAT; + +static nscd_cfg_nsw_spc_default_t nscd_cfg_passwd_cfg_link = + NSCD_CFG_DB_DEFAULT_PARAM( + NSS_DBNAM_PASSWD, + sw, + nsw_config_string, + nscd_cfg_switch_t, + NULL, + NSCD_SIZEOF(nscd_cfg_switch_t, nsw_config_string)); + +static nscd_cfg_nsw_spc_default_t nscd_cfg_profattr_cfg_link = + NSCD_CFG_DB_DEFAULT_PARAM( + NSS_DBNAM_PROFATTR, + sw, + nsw_config_string, + nscd_cfg_switch_t, + NULL, + NSCD_SIZEOF(nscd_cfg_switch_t, nsw_config_string)); + + +/* + * switch database specific defaults + */ +nscd_cfg_nsw_spc_default_t _nscd_cfg_nsw_spc_default[] = { + + NSCD_CFG_DB_DEFAULT_PARAM( + NSS_DBNAM_SHADOW, + sw, + nsw_config_db, + nscd_cfg_switch_t, + &nscd_cfg_shadow_cfg_db, + sizeof (nscd_cfg_shadow_cfg_db)), + + NSCD_CFG_DB_DEFAULT_PARAM( + NSS_DBNAM_USERATTR, + sw, + nsw_config_db, + nscd_cfg_switch_t, + &nscd_cfg_userattr_cfg_db, + sizeof (nscd_cfg_userattr_cfg_db)), + + NSCD_CFG_DB_DEFAULT_PARAM( + NSS_DBNAM_AUDITUSER, + sw, + nsw_config_db, + nscd_cfg_switch_t, + &nscd_cfg_auuser_cfg_db, + sizeof (nscd_cfg_auuser_cfg_db)), + + NSCD_CFG_DB_DEFAULT_PARAM( + NSS_DBNAM_EXECATTR, + sw, + nsw_config_db, + nscd_cfg_switch_t, + &nscd_cfg_execattr_cfg_db, + sizeof (nscd_cfg_execattr_cfg_db)), + + NSCD_CFG_DB_DEFAULT_PARAM( + NSS_DBNAM_PASSWD_COMPAT, + sw, + nsw_config_string, + nscd_cfg_switch_t, + &nscd_cfg_def_passwd_compat, + sizeof (nscd_cfg_def_passwd_compat)), + + NSCD_CFG_DB_DEFAULT_PARAM( + NSS_DBNAM_GROUP_COMPAT, + sw, + nsw_config_string, + nscd_cfg_switch_t, + &nscd_cfg_def_group_compat, + sizeof (nscd_cfg_def_group_compat)), + + NSCD_CFG_DB_DEFAULT_NULL +}; + +/* + * switch database specific defaults that are linked to + * those of other databases + */ +nscd_cfg_nsw_spc_default_t _nscd_cfg_nsw_link_default[] = { + + NSCD_CFG_DB_DEFAULT_PARAM( + NSS_DBNAM_SHADOW, + sw, + nsw_config_string, + nscd_cfg_switch_t, + &nscd_cfg_passwd_cfg_link, + 0), + + NSCD_CFG_DB_DEFAULT_PARAM( + NSS_DBNAM_USERATTR, + sw, + nsw_config_string, + nscd_cfg_switch_t, + &nscd_cfg_passwd_cfg_link, + 0), + + NSCD_CFG_DB_DEFAULT_PARAM( + NSS_DBNAM_AUDITUSER, + sw, + nsw_config_string, + nscd_cfg_switch_t, + &nscd_cfg_passwd_cfg_link, + 0), + + NSCD_CFG_DB_DEFAULT_PARAM( + NSS_DBNAM_EXECATTR, + sw, + nsw_config_string, + nscd_cfg_switch_t, + &nscd_cfg_profattr_cfg_link, + 0), + + NSCD_CFG_DB_DEFAULT_NULL +}; + +/* + * macros for defining the static stats table + */ +#define NSCD_CFG_SGROUP_DESC(sn, type, sflag, gi, \ + gf, g_in_t, gsfunc_name) \ + { \ + {-1, sn}, type, NSCD_CFG_SFLAG_GROUP | sflag, gi, \ + 0, 0, 0,\ + NSCD_SIZEOF(g_in_t, gf), offsetof(g_in_t, gf), -1, \ + gsfunc_name, NULL \ + } + +#define NSCD_CFG_STAT_DESC(sn, type, sflag, sf, s_in_t, \ + gf, g_in_t, gsfunc_name) \ + { \ + {-1, sn}, type, sflag, NSCD_CFG_GROUP_INFO_NULL, \ + NSCD_SIZEOF(s_in_t, sf), offsetof(s_in_t, sf), -1, \ + NSCD_SIZEOF(g_in_t, gf), offsetof(g_in_t, gf), -1, \ + gsfunc_name, NULL \ + } + +#define NSCD_CFG_SGROUP_DESC_NULL \ + { \ + {-1, NULL}, -1, NSCD_CFG_SFLAG_GROUP, NULL, \ + 0, 0, 0, \ + 0, 0, 0, \ + NULL, NULL \ + } + +/* + * the static statistics description table + */ +static nscd_cfg_stat_desc_t _nscd_cfg_stat_desc[] = { + + NSCD_CFG_SGROUP_DESC( + "stat-group-global-log", + NSCD_CFG_DATA_NONE, + NSCD_CFG_SFLAG_GLOBAL, + NSCD_CFG_STAT_GROUP_INFO_GLOBAL_LOG, + log, + nscd_cfg_stat_global_data_t, + "_nscd_cfg_log_get_stat"), + + NSCD_CFG_STAT_DESC( + "entries-logged", + NSCD_CFG_DATA_INTEGER, + NSCD_CFG_SFLAG_GLOBAL, + entries_logged, + nscd_cfg_stat_global_log_t, + log, + nscd_cfg_stat_global_data_t, + NSCD_CFG_FUNC_NAME_AS_GROUP), + + NSCD_CFG_SGROUP_DESC( + "stat-group-global-switch", + NSCD_CFG_DATA_NONE, + NSCD_CFG_SFLAG_GLOBAL, + NSCD_CFG_STAT_GROUP_INFO_GLOBAL_SWITCH, + sw, + nscd_cfg_stat_global_data_t, + "_nscd_cfg_switch_get_stat"), + + NSCD_CFG_STAT_DESC( + "global-lookup-request-received", + NSCD_CFG_DATA_INTEGER, + NSCD_CFG_SFLAG_GLOBAL, + lookup_request_received_g, + nscd_cfg_stat_global_switch_t, + sw, + nscd_cfg_stat_global_data_t, + NSCD_CFG_FUNC_NAME_AS_GROUP), + + NSCD_CFG_STAT_DESC( + "global-lookup-request-queued", + NSCD_CFG_DATA_INTEGER, + NSCD_CFG_SFLAG_GLOBAL, + lookup_request_queued_g, + nscd_cfg_stat_global_switch_t, + sw, + nscd_cfg_stat_global_data_t, + NSCD_CFG_FUNC_NAME_AS_GROUP), + + NSCD_CFG_STAT_DESC( + "global-lookup-request-in-progress", + NSCD_CFG_DATA_INTEGER, + NSCD_CFG_SFLAG_GLOBAL, + lookup_request_in_progress_g, + nscd_cfg_stat_global_switch_t, + sw, + nscd_cfg_stat_global_data_t, + NSCD_CFG_FUNC_NAME_AS_GROUP), + + NSCD_CFG_STAT_DESC( + "global-lookup-request-succeeded", + NSCD_CFG_DATA_INTEGER, + NSCD_CFG_SFLAG_GLOBAL, + lookup_request_succeeded_g, + nscd_cfg_stat_global_switch_t, + sw, + nscd_cfg_stat_global_data_t, + NSCD_CFG_FUNC_NAME_AS_GROUP), + + NSCD_CFG_STAT_DESC( + "global-lookup-request-failed", + NSCD_CFG_DATA_INTEGER, + NSCD_CFG_SFLAG_GLOBAL, + lookup_request_failed_g, + nscd_cfg_stat_global_switch_t, + sw, + nscd_cfg_stat_global_data_t, + NSCD_CFG_FUNC_NAME_AS_GROUP), + + NSCD_CFG_STAT_DESC( + "global-loopback-nsw-db-skipped", + NSCD_CFG_DATA_INTEGER, + NSCD_CFG_SFLAG_GLOBAL, + loopback_nsw_db_skipped_g, + nscd_cfg_stat_global_switch_t, + sw, + nscd_cfg_stat_global_data_t, + NSCD_CFG_FUNC_NAME_AS_GROUP), + + NSCD_CFG_SGROUP_DESC( + "stat-group-global-cache", + NSCD_CFG_DATA_NONE, + NSCD_CFG_SFLAG_GLOBAL, + NSCD_CFG_STAT_GROUP_INFO_CACHE, + cache, + nscd_cfg_stat_global_data_t, + "_nscd_cfg_cache_get_stat"), + + NSCD_CFG_STAT_DESC( + "global-cache-hits-on-positive", + NSCD_CFG_DATA_INTEGER, + NSCD_CFG_SFLAG_GLOBAL, + pos_hits, + nscd_cfg_stat_cache_t, + cache, + nscd_cfg_stat_global_data_t, + NSCD_CFG_FUNC_NAME_AS_GROUP), + + NSCD_CFG_STAT_DESC( + "global-cache-hits-on-negative", + NSCD_CFG_DATA_INTEGER, + NSCD_CFG_SFLAG_GLOBAL, + neg_hits, + nscd_cfg_stat_cache_t, + cache, + nscd_cfg_stat_global_data_t, + NSCD_CFG_FUNC_NAME_AS_GROUP), + + NSCD_CFG_STAT_DESC( + "global-cache-misses-on-positive", + NSCD_CFG_DATA_INTEGER, + NSCD_CFG_SFLAG_GLOBAL, + pos_misses, + nscd_cfg_stat_cache_t, + cache, + nscd_cfg_stat_global_data_t, + NSCD_CFG_FUNC_NAME_AS_GROUP), + + NSCD_CFG_STAT_DESC( + "global-cache-misses-on-negative", + NSCD_CFG_DATA_INTEGER, + NSCD_CFG_SFLAG_GLOBAL, + neg_misses, + nscd_cfg_stat_cache_t, + cache, + nscd_cfg_stat_global_data_t, + NSCD_CFG_FUNC_NAME_AS_GROUP), + + NSCD_CFG_STAT_DESC( + "global-cache-queries-queued", + NSCD_CFG_DATA_INTEGER, + NSCD_CFG_SFLAG_GLOBAL, + wait_count, + nscd_cfg_stat_cache_t, + cache, + nscd_cfg_stat_global_data_t, + NSCD_CFG_FUNC_NAME_AS_GROUP), + + NSCD_CFG_STAT_DESC( + "global-total-cache-entries", + NSCD_CFG_DATA_INTEGER, + NSCD_CFG_SFLAG_GLOBAL, + entries, + nscd_cfg_stat_cache_t, + cache, + nscd_cfg_stat_global_data_t, + NSCD_CFG_FUNC_NAME_AS_GROUP), + + NSCD_CFG_STAT_DESC( + "global-complete-cache-invalidations", + NSCD_CFG_DATA_INTEGER, + NSCD_CFG_SFLAG_GLOBAL, + invalidate_count, + nscd_cfg_stat_cache_t, + cache, + nscd_cfg_stat_global_data_t, + NSCD_CFG_FUNC_NAME_AS_GROUP), + + NSCD_CFG_STAT_DESC( + "global-cache-queries-dropped", + NSCD_CFG_DATA_INTEGER, + NSCD_CFG_SFLAG_GLOBAL, + drop_count, + nscd_cfg_stat_cache_t, + cache, + nscd_cfg_stat_global_data_t, + NSCD_CFG_FUNC_NAME_AS_GROUP), + + NSCD_CFG_STAT_DESC( + "global-cache-hit-rate", + NSCD_CFG_DATA_PERCENT, + NSCD_CFG_SFLAG_GLOBAL, + hitrate, + nscd_cfg_stat_cache_t, + cache, + nscd_cfg_stat_global_data_t, + NSCD_CFG_FUNC_NAME_AS_GROUP), + + /* non-global stat from this point on */ + + NSCD_CFG_SGROUP_DESC( + "stat-group-switch", + NSCD_CFG_DATA_NONE, + NSCD_CFG_SFLAG_GROUP, + NSCD_CFG_STAT_GROUP_INFO_SWITCH, + cache, + nscd_cfg_stat_nsw_db_data_t, + "_nscd_cfg_switch_get_stat"), + + NSCD_CFG_STAT_DESC( + "lookup-request-received", + NSCD_CFG_DATA_INTEGER, + NSCD_CFG_SFLAG_NONE, + lookup_request_received, + nscd_cfg_stat_switch_t, + sw, + nscd_cfg_stat_nsw_db_data_t, + NSCD_CFG_FUNC_NAME_AS_GROUP), + + NSCD_CFG_STAT_DESC( + "lookup-request-queued", + NSCD_CFG_DATA_INTEGER, + NSCD_CFG_SFLAG_NONE, + lookup_request_queued, + nscd_cfg_stat_switch_t, + sw, + nscd_cfg_stat_nsw_db_data_t, + NSCD_CFG_FUNC_NAME_AS_GROUP), + + NSCD_CFG_STAT_DESC( + "lookup-request-in-progress", + NSCD_CFG_DATA_INTEGER, + NSCD_CFG_SFLAG_NONE, + lookup_request_in_progress, + nscd_cfg_stat_switch_t, + sw, + nscd_cfg_stat_nsw_db_data_t, + NSCD_CFG_FUNC_NAME_AS_GROUP), + + NSCD_CFG_STAT_DESC( + "lookup-request-succeeded", + NSCD_CFG_DATA_INTEGER, + NSCD_CFG_SFLAG_NONE, + lookup_request_succeeded, + nscd_cfg_stat_switch_t, + sw, + nscd_cfg_stat_nsw_db_data_t, + NSCD_CFG_FUNC_NAME_AS_GROUP), + + NSCD_CFG_STAT_DESC( + "lookup-request-failed", + NSCD_CFG_DATA_INTEGER, + NSCD_CFG_SFLAG_NONE, + lookup_request_failed, + nscd_cfg_stat_switch_t, + sw, + nscd_cfg_stat_nsw_db_data_t, + NSCD_CFG_FUNC_NAME_AS_GROUP), + + NSCD_CFG_STAT_DESC( + "loopback-nsw-db-skipped", + NSCD_CFG_DATA_INTEGER, + NSCD_CFG_SFLAG_NONE, + loopback_nsw_db_skipped, + nscd_cfg_stat_switch_t, + sw, + nscd_cfg_stat_nsw_db_data_t, + NSCD_CFG_FUNC_NAME_AS_GROUP), + + NSCD_CFG_SGROUP_DESC( + "stat-group-cache", + NSCD_CFG_DATA_NONE, + NSCD_CFG_SFLAG_GROUP, + NSCD_CFG_STAT_GROUP_INFO_CACHE, + cache, + nscd_cfg_stat_nsw_db_data_t, + "_nscd_cfg_cache_get_stat"), + + NSCD_CFG_STAT_DESC( + "cache-hits-on-positive", + NSCD_CFG_DATA_INTEGER, + NSCD_CFG_SFLAG_NONE, + pos_hits, + nscd_cfg_stat_cache_t, + cache, + nscd_cfg_stat_nsw_db_data_t, + NSCD_CFG_FUNC_NAME_AS_GROUP), + + NSCD_CFG_STAT_DESC( + "cache-hits-on-negative", + NSCD_CFG_DATA_INTEGER, + NSCD_CFG_SFLAG_NONE, + neg_hits, + nscd_cfg_stat_cache_t, + cache, + nscd_cfg_stat_nsw_db_data_t, + NSCD_CFG_FUNC_NAME_AS_GROUP), + + NSCD_CFG_STAT_DESC( + "cache-misses-on-positive", + NSCD_CFG_DATA_INTEGER, + NSCD_CFG_SFLAG_NONE, + pos_misses, + nscd_cfg_stat_cache_t, + cache, + nscd_cfg_stat_nsw_db_data_t, + NSCD_CFG_FUNC_NAME_AS_GROUP), + + NSCD_CFG_STAT_DESC( + "cache-misses-on-negative", + NSCD_CFG_DATA_INTEGER, + NSCD_CFG_SFLAG_NONE, + neg_misses, + nscd_cfg_stat_cache_t, + cache, + nscd_cfg_stat_nsw_db_data_t, + NSCD_CFG_FUNC_NAME_AS_GROUP), + + NSCD_CFG_STAT_DESC( + "cache-queries-queued", + NSCD_CFG_DATA_INTEGER, + NSCD_CFG_SFLAG_NONE, + wait_count, + nscd_cfg_stat_cache_t, + cache, + nscd_cfg_stat_nsw_db_data_t, + NSCD_CFG_FUNC_NAME_AS_GROUP), + + NSCD_CFG_STAT_DESC( + "total-cache-entries", + NSCD_CFG_DATA_INTEGER, + NSCD_CFG_SFLAG_NONE, + entries, + nscd_cfg_stat_cache_t, + cache, + nscd_cfg_stat_nsw_db_data_t, + NSCD_CFG_FUNC_NAME_AS_GROUP), + + NSCD_CFG_STAT_DESC( + "complete-cache-invalidations", + NSCD_CFG_DATA_INTEGER, + NSCD_CFG_SFLAG_NONE, + invalidate_count, + nscd_cfg_stat_cache_t, + cache, + nscd_cfg_stat_nsw_db_data_t, + NSCD_CFG_FUNC_NAME_AS_GROUP), + + NSCD_CFG_STAT_DESC( + "cache-hit-rate", + NSCD_CFG_DATA_PERCENT, + NSCD_CFG_SFLAG_NONE, + hitrate, + nscd_cfg_stat_cache_t, + cache, + nscd_cfg_stat_nsw_db_data_t, + NSCD_CFG_FUNC_NAME_AS_GROUP), + + NSCD_CFG_STAT_DESC( + "cache-queries-dropped", + NSCD_CFG_DATA_PERCENT, + NSCD_CFG_SFLAG_NONE, + drop_count, + nscd_cfg_stat_cache_t, + cache, + nscd_cfg_stat_nsw_db_data_t, + NSCD_CFG_FUNC_NAME_AS_GROUP), + + + NSCD_CFG_SGROUP_DESC_NULL +}; + +/* number of entries in the static tables */ + +int _nscd_cfg_num_nsw_src = + (sizeof (_nscd_cfg_nsw_src) / + sizeof (_nscd_cfg_nsw_src[0]) - 1); + +int _nscd_cfg_num_smf_services = + (sizeof (_nscd_cfg_smf_services) / + sizeof (_nscd_cfg_smf_services[0]) - 1); + +/* number of supported nsw databases (including pseudo ones) */ +int _nscd_cfg_num_nsw_db_all = + (sizeof (_nscd_cfg_nsw_db) / + sizeof (_nscd_cfg_nsw_db[0]) - 1); + +/* number of supported nsw databases (not including pseudo ones) */ +int _nscd_cfg_num_nsw_db = + (sizeof (_nscd_cfg_nsw_db) / + sizeof (_nscd_cfg_nsw_db[0]) - 1) - + NSS_DBNAM_COMPAT_NUM_DB; + +static int _nscd_cfg_num_param = + (sizeof (_nscd_cfg_param_desc) / + sizeof (_nscd_cfg_param_desc[0]) - 1); + +static int _nscd_cfg_num_stat = + (sizeof (_nscd_cfg_stat_desc) / + sizeof (_nscd_cfg_stat_desc[0]) - 1); + +int _nscd_cfg_num_nsw_default = + (sizeof (_nscd_cfg_nsw_spc_default) / + sizeof (_nscd_cfg_nsw_spc_default[0]) - 1); + +int _nscd_cfg_num_link_default = + (sizeof (_nscd_cfg_nsw_link_default) / + sizeof (_nscd_cfg_nsw_link_default[0]) - 1); + +#ifdef __cplusplus +} +#endif + +#endif /* _NSCD_CFGDEF_H */ diff --git a/usr/src/cmd/nscd/nscd_cfgfile.c b/usr/src/cmd/nscd/nscd_cfgfile.c new file mode 100644 index 0000000000..f3075ac792 --- /dev/null +++ b/usr/src/cmd/nscd/nscd_cfgfile.c @@ -0,0 +1,386 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * routine to read configuration file + * + */ +#include "nscd_config.h" +#include "nscd_log.h" +#include <locale.h> +#include <ctype.h> +#include <string.h> +#include <errno.h> + +static int +strbreak(char *field[], int array_size, char *s, char *sep) +{ + int i; + char *lasts, *qp; + int inquote; + + qp = strchr(s, '"'); + for (i = 0; i < array_size && (field[i] = + strtok_r((i?(char *)NULL:s), sep, &lasts)); i++); + + if (qp == NULL) + return (i); + + inquote = 1; + while (++qp < lasts) { + + switch (*qp) { + + case '"': + inquote = (inquote == 0); + break; + + case '\\': + /* escape " */ + if (inquote == 1 && *(qp + 1) == '"') + qp++; + break; + + case '\0': + if (inquote == 1) { + *qp = ' '; + i--; + } + + break; + } + } + + return (i); +} + + +nscd_rc_t +_nscd_cfg_read_file( + char *filename, + nscd_cfg_error_t **errorp) +{ + char *me = "_nscd_cfg_read_file"; + FILE *in; + char buffer[255]; + char *fields [128]; + int linecnt; + int fieldcnt; + nscd_rc_t rc = NSCD_SUCCESS; + nscd_cfg_handle_t *h = NULL; + nscd_cfg_param_desc_t *pdesc; + char *dbname, *str; + void *data_p; + int i; + char msg[NSCD_CFG_MAX_ERR_MSG_LEN]; + + union { + int i; + char data[256]; + } u; + + if ((in = fopen(filename, "r")) == NULL) { + + (void) snprintf(msg, sizeof (msg), + gettext("open of configuration file \"%s\" failed: %s"), + filename, strerror(errno)); + if (errorp != NULL) + *errorp = _nscd_cfg_make_error( + NSCD_CFG_FILE_OPEN_ERROR, msg); + + _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR) + (me, "%s\n", msg); + + return (NSCD_CFG_FILE_OPEN_ERROR); + } + + linecnt = 0; + msg[0] = '\0'; + while (fgets(buffer, sizeof (buffer), in) != NULL) { + + linecnt++; + if ((fieldcnt = strbreak(fields, 128, buffer, " \t\n")) == + 0 || *fields[0] == '#') { + /* skip blank or comment lines */ + continue; + } + + switch (fieldcnt) { + + case 2: + dbname = NULL; + str = fields[1]; + break; + + case 3: + dbname = fields[1]; + str = fields[2]; + break; + + default: + + (void) strlcpy(u.data, fields[0], sizeof (u.data)); + for (i = 1; i < fieldcnt; i++) { + (void) strlcat(u.data, " ", + sizeof (u.data)); + (void) strlcat(u.data, fields[i], + sizeof (u.data)); + } + + (void) snprintf(msg, sizeof (msg), + gettext("Syntax error: line %d of configuration " + "file: %s : \"%s\""), linecnt, filename, u.data); + if (errorp != NULL) + *errorp = _nscd_cfg_make_error( + NSCD_CFG_SYNTAX_ERROR, msg); + + _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR) + (me, "%s\n", msg); + + rc = NSCD_CFG_SYNTAX_ERROR; + break; + } + + if (rc != NSCD_SUCCESS) + break; + + rc = _nscd_cfg_get_handle(fields[0], dbname, &h, errorp); + if (rc != NSCD_SUCCESS) + break; + + pdesc = _nscd_cfg_get_desc(h); + + /* convert string to data */ + rc = _nscd_cfg_str_to_data(pdesc, str, &u.data, + &data_p, errorp); + if (rc != NSCD_SUCCESS) + break; + + /* do preliminary check based on data type */ + rc = _nscd_cfg_prelim_check(pdesc, data_p, errorp); + if (rc != NSCD_SUCCESS) + break; + + rc = _nscd_cfg_set_linked(h, data_p, errorp); + _nscd_cfg_free_handle(h); + h = NULL; + if (rc != NSCD_CFG_READ_ONLY && rc != NSCD_SUCCESS) + break; + else { + _nscd_cfg_free_error(*errorp); + *errorp = NULL; + } + } + /* NSCD_CFG_READ_ONLY is not fatal */ + if (rc == NSCD_CFG_READ_ONLY) + rc = NSCD_SUCCESS; + + if (h != NULL) + _nscd_cfg_free_handle(h); + + (void) fclose(in); + + if (msg[0] == '\0' && rc != NSCD_SUCCESS) { + if (errorp != NULL) + _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR) + (me, "%s\n", NSCD_ERR2MSG(*errorp)); + } + + return (rc); +} + +nscd_rc_t +_nscd_cfg_read_nsswitch_file( + char *filename, + nscd_cfg_error_t **errorp) +{ + char *me = "_nscd_cfg_read_nsswitch_file"; + char *pname = "nsw-config-string"; + FILE *in; + char buffer[255]; + char *cc, *ce, *ce1, *c1, *c2; + char *db, *dbe; + char *nsscfg; + int syntax_err; + int linecnt; + nscd_rc_t rc = NSCD_SUCCESS; + nscd_cfg_handle_t *h = NULL; + nscd_cfg_param_desc_t *pdesc; + void *data_p; + char msg[NSCD_CFG_MAX_ERR_MSG_LEN]; + + union { + int i; + char data[256]; + } u; + + if ((in = fopen(filename, "r")) == NULL) { + + (void) snprintf(msg, sizeof (msg), + gettext("open of configuration file \"%s\" failed: %s"), + filename, strerror(errno)); + if (errorp != NULL) + *errorp = _nscd_cfg_make_error( + NSCD_CFG_FILE_OPEN_ERROR, msg); + + _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR) + (me, "%s\n", msg); + + return (NSCD_CFG_FILE_OPEN_ERROR); + } + + linecnt = 0; + msg[0] = '\0'; + while (fgets(buffer, sizeof (buffer), in) != NULL) { + + linecnt++; + syntax_err = 0; + /* skip blank or comment lines */ + if (buffer[0] == '#' || buffer[0] == '\n') + continue; + /* skip end of line comment */ + if ((ce = strchr(buffer, '\n')) != NULL) + *ce = '\0'; + else + ce = &buffer[255]; + if ((ce1 = strchr(buffer, '#')) != NULL) { + ce = ce1; + *ce = '\0'; + } + if ((cc = strchr(buffer, ':')) == NULL) { + c1 = buffer; + while (isalpha(*c1) && c1 < ce) + c1++; + if (c1 > ce) + syntax_err = 1; + else /* blank line */ + continue; + } else { + /* + * data name goes before ':', + * skip spaces on both ends + */ + c2 = cc - 1; + while (buffer <= c2 && isspace(*c2)) + c2--; + c1 = buffer; + while (c1 <= cc && isspace(*c1)) + c1++; + if (c1 > c2) + syntax_err = 1; + else { + db = c1; + dbe = c2 + 1; + + /* + * nss config goes after ':', + * skip spaces on both ends + */ + c1 = cc + 1; + while (c1 <= ce && isspace(*c1)) + c1++; + c2 = ce - 1; + while (cc <= c2 && isspace(*c2)) + c2--; + if (c1 > c2) + syntax_err = 1; + else { + *dbe = '\0'; + nsscfg = c1; + *(c2 + 1) = '\0'; + } + } + } + + if (syntax_err == 1) { + + (void) snprintf(msg, sizeof (msg), + gettext("Syntax error: line %d of configuration " + "file: %s : \"%s\""), linecnt, filename, buffer); + if (errorp != NULL) + *errorp = _nscd_cfg_make_error( + NSCD_CFG_SYNTAX_ERROR, msg); + + _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR) + (me, "%s\n", msg); + + rc = NSCD_CFG_SYNTAX_ERROR; + return (rc); + } + + rc = _nscd_cfg_get_handle(pname, db, &h, errorp); + if (rc != NSCD_SUCCESS) { + /* ignore unsupported switch database */ + if (rc == NSCD_CFG_UNSUPPORTED_SWITCH_DB) { + _nscd_cfg_free_error(*errorp); + *errorp = NULL; + rc = NSCD_SUCCESS; + continue; + } + break; + } + + pdesc = _nscd_cfg_get_desc(h); + + /* convert string to data */ + rc = _nscd_cfg_str_to_data(pdesc, nsscfg, &u.data, + &data_p, errorp); + if (rc != NSCD_SUCCESS) + break; + + /* do preliminary check based on data type */ + rc = _nscd_cfg_prelim_check(pdesc, data_p, errorp); + if (rc != NSCD_SUCCESS) + break; + + rc = _nscd_cfg_set_linked(h, data_p, errorp); + _nscd_cfg_free_handle(h); + h = NULL; + if (rc != NSCD_CFG_READ_ONLY && rc != NSCD_SUCCESS) + break; + else { + _nscd_cfg_free_error(*errorp); + *errorp = NULL; + } + } + /* NSCD_CFG_READ_ONLY is not fatal */ + if (rc == NSCD_CFG_READ_ONLY) + rc = NSCD_SUCCESS; + + if (h != NULL) + _nscd_cfg_free_handle(h); + + (void) fclose(in); + + if (msg[0] == '\0' && rc != NSCD_SUCCESS) { + if (errorp != NULL) + _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR) + (me, "%s\n", NSCD_ERR2MSG(*errorp)); + } + + return (rc); +} diff --git a/usr/src/cmd/nscd/nscd_common.h b/usr/src/cmd/nscd/nscd_common.h new file mode 100644 index 0000000000..7b2ccffd91 --- /dev/null +++ b/usr/src/cmd/nscd/nscd_common.h @@ -0,0 +1,105 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _NSCD_COMMON_H +#define _NSCD_COMMON_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + +#include <sys/types.h> +#include <synch.h> + +/* + * nscd internal return/error codes + */ +typedef enum { + NSCD_SUCCESS = 0, + NSCD_INITIALIZATION_FAILED, + NSCD_CTX_NOT_FOUND, + NSCD_DB_ENTRY_FOUND, + NSCD_DB_ENTRY_NOT_FOUND, + NSCD_INVALID_ARGUMENT, + NSCD_NO_MEMORY, + NSCD_THREAD_CREATE_ERROR, + NSCD_SMF_ERROR, + NSCD_CFG_UNSUPPORTED_SWITCH_DB, + NSCD_CFG_UNSUPPORTED_SWITCH_SRC, + NSCD_CFG_DLOPEN_ERROR, + NSCD_CFG_DLSYM_ERROR, + NSCD_CFG_SET_PARAM_FAILED, + NSCD_CFG_PARAM_DESC_ERROR, + NSCD_CFG_STAT_DESC_ERROR, + NSCD_CFG_INVALID_HANDLE, + NSCD_CFG_PARSE_ERROR, + NSCD_CFG_FILE_OPEN_ERROR, + NSCD_CFG_FILE_ACCESS_ERROR, + NSCD_CFG_SYNTAX_ERROR, + NSCD_CFG_PRELIM_CHECK_FAILED, + NSCD_CFG_DATA_CONVERSION_FAILED, + NSCD_CFG_WRITE_ERROR, + NSCD_CFG_READ_ONLY, + NSCD_CFG_CHANGE_NOT_ALLOWED, + NSCD_CREATE_NSW_STATE_FAILED, + NSCD_CREATE_GETENT_CTX_FAILED, + NSCD_NSS_BACKEND_NOT_FOUND, + NSCD_DOOR_UCRED_ERROR, + NSCD_SELF_CRED_NOT_CONFIGURED, + NSCD_SELF_CRED_NO_FORKER, + NSCD_SELF_CRED_WRONG_NSCD, + NSCD_SELF_CRED_MAIN_IMPOSTER, + NSCD_SELF_CRED_FORKER_IMPOSTER, + NSCD_SELF_CRED_CHILD_IMPOSTER, + NSCD_SELF_CRED_NO_DOOR, + NSCD_SELF_CRED_NO_CHILD_SLOT, + NSCD_SELF_CRED_INVALID_SLOT_NUMBER, + NSCD_SELF_CRED_INVALID_SLOT_STATE, + NSCD_ADMIN_FAIL_TO_SET, + NSCD_CACHE_INVALID_CACHE_NAME, + NSCD_CACHE_NO_CACHE_CTX, + NSCD_CACHE_DISABLED, + NSCD_CACHE_NO_CACHE_FOUND, + NSCD_CACHE_AVOID_NS + +} nscd_rc_t; + + +/* nscd data type: boolean */ +typedef uint8_t nscd_bool_t; +#define nscd_true 1 +#define nscd_false 0 + +/* common functions */ +nscd_rc_t _nscd_init(char *cfgfile); +nscd_rc_t _nscd_refresh(); + +#ifdef __cplusplus +} +#endif + +#endif /* _NSCD_COMMON_H */ diff --git a/usr/src/cmd/nscd/nscd_config.c b/usr/src/cmd/nscd/nscd_config.c new file mode 100644 index 0000000000..02e3375ab0 --- /dev/null +++ b/usr/src/cmd/nscd/nscd_config.c @@ -0,0 +1,2923 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <stdio.h> +#include <stdlib.h> +#include <locale.h> /* gettext */ +#include <dlfcn.h> +#include <string.h> +#include <sys/varargs.h> +#include <errno.h> +#include "nscd_db.h" +#include "nscd_config.h" +#include "nscd_cfgdef.h" +#include "nscd_log.h" + +typedef struct { + rwlock_t *global; + rwlock_t *alldb; + rwlock_t *nswdb; +} nscd_cfg_lock_t; + +static rwlock_t cfg_paramDB_rwlock = DEFAULTRWLOCK; +static nscd_db_t *cfg_paramDB = NULL; + +static nscd_cfg_global_data_t *nscd_cfg_global_current; +static nscd_cfg_nsw_db_data_t *nscd_cfg_nsw_db_data_current; +static nscd_cfg_nsw_db_data_t *nscd_cfg_nsw_alldb_current; +static rwlock_t *nscd_cfg_global_rwlock; +static rwlock_t *nscd_cfg_nsw_db_data_rwlock; +static rwlock_t *nscd_cfg_nsw_alldb_rwlock; + +extern int _nscd_cfg_num_nsw_src_all; +extern nscd_cfg_id_t *_nscd_cfg_nsw_src_all; + +nscd_cfg_error_t * +_nscd_cfg_make_error( + nscd_rc_t rc, + char *msg) +{ + + nscd_cfg_error_t *ret; + int size, msglen; + + msglen = (msg != NULL ? strlen(msg) + 1 : 0); + + size = sizeof (nscd_cfg_error_t) + msglen; + + ret = calloc(1, size); + if (ret == NULL) + return (NULL); + + ret->rc = rc; + if (msg != NULL) { + ret->msg = (char *)ret + + sizeof (nscd_cfg_error_t); + (void) memcpy(ret->msg, msg, msglen); + } + + return (ret); +} + +static nscd_rc_t +_nscd_cfg_get_list( + nscd_cfg_list_t **list, + nscd_cfg_list_type_t type) +{ + char *me = "_nscd_cfg_get_list"; + int i, num, size; + nscd_cfg_id_t *l; + nscd_cfg_list_t *ret; + nscd_cfg_param_desc_t *pl; + nscd_cfg_stat_desc_t *sl; + void *p; + + if (list == NULL) { + _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR) + (me, "invalid argument: list = %p\n", list); + + return (NSCD_INVALID_ARGUMENT); + } + *list = NULL; + + switch (type) { + case NSCD_CFG_LIST_NSW_DB: + + num = _nscd_cfg_num_nsw_db; + l = &_nscd_cfg_nsw_db[0]; + break; + + case NSCD_CFG_LIST_NSW_SRC: + + num = _nscd_cfg_num_nsw_src_all; + l = _nscd_cfg_nsw_src_all; + break; + + case NSCD_CFG_LIST_PARAM: + + num = _nscd_cfg_num_param; + pl = &_nscd_cfg_param_desc[0]; + break; + + case NSCD_CFG_LIST_STAT: + + num = _nscd_cfg_num_stat; + sl = &_nscd_cfg_stat_desc[0]; + break; + + default: + _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR) + (me, "invalid argument: type (%d)\n", type); + + return (NSCD_INVALID_ARGUMENT); + break; + } + + size = sizeof (nscd_cfg_list_t) + sizeof (nscd_cfg_id_t *) * (num + 1); + + ret = calloc(1, size); + if (ret == NULL) + return (NSCD_NO_MEMORY); + + ret->num = num; + p = (char *)ret + sizeof (nscd_cfg_list_t); + ret->list = (nscd_cfg_id_t **)p; + + if (type == NSCD_CFG_LIST_PARAM) { + for (i = 0; i <= num; i++) + ret->list[i] = (nscd_cfg_id_t *)&pl[i]; + } else if (type == NSCD_CFG_LIST_STAT) { + for (i = 0; i <= num; i++) + ret->list[i] = (nscd_cfg_id_t *)&sl[i]; + } else { + for (i = 0; i <= num; i++) + ret->list[i] = &l[i]; + } + + *list = ret; + + return (NSCD_SUCCESS); +} + +nscd_rc_t +_nscd_cfg_get_param_desc_list( + nscd_cfg_param_desc_list_t **list) +{ + return (_nscd_cfg_get_list((nscd_cfg_list_t **)list, + NSCD_CFG_LIST_PARAM)); +} + +/* find function pointer in the executable via dlopen(0) */ +static nscd_rc_t +_nscd_cfg_init_funcs( + char *name, + void **func_p, + nscd_cfg_error_t **errorp) +{ + char *me = "_nscd_cfg_init_funcs"; + char msg[NSCD_CFG_MAX_ERR_MSG_LEN]; + static void *handle = NULL; + void *sym; + nscd_rc_t rc = NSCD_SUCCESS; + + if (name == NULL && handle != NULL) { + (void) dlclose(handle); + return (rc); + } + if (name == NULL) + return (rc); + + if (handle == NULL) { + handle = dlopen((const char *)0, RTLD_LAZY); + if (handle == NULL) { + + rc = NSCD_CFG_DLOPEN_ERROR; + (void) snprintf(msg, sizeof (msg), + gettext("unable to dlopen the nscd executable: %s"), + dlerror()); + goto error_exit; + } + } + + if (func_p) { + if ((sym = dlsym(handle, name)) == NULL) { + + rc = NSCD_CFG_DLSYM_ERROR; + (void) snprintf(msg, sizeof (msg), +gettext("unable to get the address of a symbol in the nscd executable: %s"), + dlerror()); + goto error_exit; + } else + (void) memcpy(func_p, &sym, sizeof (void *)); + } + + return (rc); + + error_exit: + + _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR) + (me, "%s\n", msg); + if (errorp != NULL) + *errorp = _nscd_cfg_make_error(rc, msg); + + return (rc); +} + + +/* + * FUNCTION: _nscd_cfg_create_paramDB + * + * Create the internal config parameter database + */ +static nscd_db_t * +_nscd_cfg_create_paramDB() +{ + + nscd_db_t *ret; + + (void) rw_wrlock(&cfg_paramDB_rwlock); + + ret = _nscd_alloc_db(NSCD_DB_SIZE_MEDIUM); + + if (ret != NULL) + cfg_paramDB = ret; + + (void) rw_unlock(&cfg_paramDB_rwlock); + + return (ret); +} + +/* + * FUNCTION: _nscd_cfg_add_index_entry + * + * Add a config index entry (a name to index mapping) + * to the internal configuration database. + */ +static nscd_rc_t +_nscd_cfg_add_index_entry( + char *name, + int index, + nscd_cfg_list_type_t type) +{ + int *idx; + int size; + int dbe_type; + nscd_db_entry_t *db_entry; + + if (name == NULL) + return (NSCD_INVALID_ARGUMENT); + + if (type == NSCD_CFG_LIST_NSW_DB) + dbe_type = NSCD_DATA_CFG_NSW_DB_INDEX; + else if (type == NSCD_CFG_LIST_NSW_SRC) + dbe_type = NSCD_DATA_CFG_NSW_SRC_INDEX; + else if (type == NSCD_CFG_LIST_PARAM) + dbe_type = NSCD_DATA_CFG_PARAM_INDEX; + else if (type == NSCD_CFG_LIST_STAT) + dbe_type = NSCD_DATA_CFG_STAT_INDEX; + + size = sizeof (int); + + db_entry = _nscd_alloc_db_entry(dbe_type, (const char *)name, + size, 1, 1); + if (db_entry == NULL) + return (NSCD_NO_MEMORY); + + idx = (int *)*(db_entry->data_array); + *idx = index; + + (void) rw_wrlock(&cfg_paramDB_rwlock); + (void) _nscd_add_db_entry(cfg_paramDB, name, db_entry, + NSCD_ADD_DB_ENTRY_FIRST); + (void) rw_unlock(&cfg_paramDB_rwlock); + + return (NSCD_SUCCESS); +} + +/* + * FUNCTION: _nscd_cfg_get_index + * + * Get the index of a config data item by searching the internal config + * database. Do not free the returned data. + */ +static int +_nscd_cfg_get_index( + char *name, + nscd_cfg_list_type_t type) +{ + int index = -1, dbe_type; + const nscd_db_entry_t *db_entry; + + if (name == NULL) + return (-1); + + if (type == NSCD_CFG_LIST_NSW_DB) + dbe_type = NSCD_DATA_CFG_NSW_DB_INDEX; + else if (type == NSCD_CFG_LIST_NSW_SRC) + dbe_type = NSCD_DATA_CFG_NSW_SRC_INDEX; + else if (type == NSCD_CFG_LIST_PARAM) + dbe_type = NSCD_DATA_CFG_PARAM_INDEX; + else if (type == NSCD_CFG_LIST_STAT) + dbe_type = NSCD_DATA_CFG_STAT_INDEX; + else + return (-1); + + db_entry = _nscd_get_db_entry(cfg_paramDB, dbe_type, + (const char *)name, NSCD_GET_FIRST_DB_ENTRY, 0); + + if (db_entry != NULL) + index = *(int *)*(db_entry->data_array); + + return (index); +} + +static nscd_rc_t +_nscd_cfg_verify_group_info( + nscd_cfg_group_info_t *g_info, + nscd_cfg_param_desc_t *gdesc) +{ + + char *me = "_nscd_cfg_verify_group_info"; + void *vp; + nscd_cfg_group_info_t *gi; + + if (_nscd_cfg_flag_is_set(gdesc->pflag, NSCD_CFG_PFLAG_GLOBAL)) { + vp = (char *)&nscd_cfg_global_default + + gdesc->g_offset; + gi = (nscd_cfg_group_info_t *)vp; + } else { + vp = (char *)&nscd_cfg_nsw_db_data_default + + gdesc->g_offset; + gi = (nscd_cfg_group_info_t *)vp; + + } + + if (g_info->num_param == gi->num_param && + _nscd_cfg_bitmap_is_equal(g_info->bitmap, gi->bitmap)) + return (NSCD_SUCCESS); + + _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR) + (me, "ERROR: group (%s) info mismatched: group info " + "(%d, %#6.4x) not equal to that of default configuration data " + "(%d, %#6.4x)\n", gdesc->id.name, g_info->num_param, + _nscd_cfg_bitmap_value(g_info->bitmap), gi->num_param, + _nscd_cfg_bitmap_value(gi->bitmap)); + + return (NSCD_CFG_PARAM_DESC_ERROR); + +} + + +static nscd_rc_t +_nscd_cfg_init_nsw() +{ + char *me = "_nscd_cfg_init_nsw"; + int i, j, idx, rc, num; + nscd_cfg_id_t *id; + nscd_cfg_list_type_t type[2] = { NSCD_CFG_LIST_NSW_DB, + NSCD_CFG_LIST_NSW_SRC }; + + nscd_cfg_id_t *list[2] = { _nscd_cfg_nsw_db, NULL}; + + list[1] = _nscd_cfg_nsw_src_all; + + for (j = 0; j < 2; j++) { + + if (j == 0) + num = _nscd_cfg_num_nsw_db + 1; + else + num = _nscd_cfg_num_nsw_src_all; + + for (i = 0; i < num; i++) { + + /* + * _nscd_cfg_nsw_alldb is the id for the + * special ALLDB (defaults for all db) + */ + if (j == 0 && i == _nscd_cfg_num_nsw_db) { + id = &_nscd_cfg_nsw_alldb; + idx = NSCD_CFG_NSW_ALLDB_INDEX; + } else { + id = &(list[j])[i]; + id->index = idx = i; + } + + if (id->name == NULL) + continue; + + if ((rc = _nscd_cfg_add_index_entry(id->name, + idx, type[j])) != NSCD_SUCCESS) { + + _NSCD_LOG(NSCD_LOG_CONFIG, + NSCD_LOG_LEVEL_ERROR) + (me, "unable to add index entry for " + "nsswitch entry %s\n", id->name); + + _nscd_free_db(cfg_paramDB); + return (rc); + } + } + } + + return (NSCD_SUCCESS); +} + +/* + * get the address of a function in the nscd executable + * and store it in where 'dest_p' points to + */ +static nscd_rc_t +_nscd_cfg_get_funcp( + char *name, + void *dest_p, + void **gfunc_a, + nscd_cfg_error_t **errorp) +{ + + void *func; + nscd_rc_t rc; + + if (gfunc_a != NULL) { + + if (strcmp(name, NSCD_CFG_FUNC_NAME_AS_GROUP) == 0) + (void) memcpy(dest_p, gfunc_a, sizeof (void *)); + + return (NSCD_SUCCESS); + } + + rc = _nscd_cfg_init_funcs(name, &func, errorp); + if (rc != NSCD_SUCCESS) + return (rc); + (void) memcpy(dest_p, &func, sizeof (func)); + + return (NSCD_SUCCESS); +} + +static nscd_rc_t +_nscd_cfg_init_param() +{ + char *me = "_nscd_cfg_init_param"; + int i, gi, fn = 0; + nscd_cfg_id_t *id; + nscd_cfg_param_desc_t *desc, *gdesc = NULL; + nscd_cfg_group_info_t g_info; + nscd_cfg_list_type_t type = NSCD_CFG_LIST_PARAM; + nscd_rc_t rc; + void *nfunc, *vfunc; + + if (_nscd_cfg_create_paramDB() == NULL) + return (NSCD_NO_MEMORY); + + desc = &_nscd_cfg_param_desc[0]; + + /* + * need to loop to the last (+1) param description + * which is a fake group and which marks the end + * of list. It is used to signal the end of the + * previous group so that the proper data will be + * set for that group + */ + for (i = 0; i < _nscd_cfg_num_param + 1; i++, desc++) { + + id = (nscd_cfg_id_t *)desc; + + if (_nscd_cfg_flag_is_set(desc->pflag, + NSCD_CFG_PFLAG_GROUP)) { + + if (gdesc != NULL) { + g_info.num_param = fn; + gdesc->p_fn = fn; + + if ((rc = _nscd_cfg_verify_group_info( + &g_info, gdesc)) != NSCD_SUCCESS) + return (rc); + } + + gi = i; + fn = 0; + gdesc = desc; + g_info.bitmap = NSCD_CFG_BITMAP_ZERO; + nfunc = NULL; + vfunc = NULL; + + /* + * set the notify/verify functions + */ + if (gdesc->nfunc_name != NULL) { + rc = _nscd_cfg_get_funcp(gdesc->nfunc_name, + &gdesc->notify, NULL, NULL); + if (rc != NULL) + return (rc); + nfunc = (void *)gdesc->notify; + } + if (gdesc->vfunc_name != NULL) { + rc = _nscd_cfg_get_funcp(gdesc->vfunc_name, + &gdesc->verify, NULL, NULL); + if (rc != NULL) + return (rc); + vfunc = (void *)gdesc->verify; + } + } else { + if (i == 0) { + + _NSCD_LOG(NSCD_LOG_CONFIG, + NSCD_LOG_LEVEL_ERROR) + (me, "ERROR: first parameter " + "description is not for a group\n"); + + return (NSCD_CFG_PARAM_DESC_ERROR); + } + + /* + * set bitmap: the rightmost bit represents + * the first member (index = 0) in the group, + * the next bit is for the second member + * (index = 1), and so on + */ + _nscd_cfg_bitmap_set_nth(g_info.bitmap, fn); + + desc->p_fn = fn++; + + /* + * set the notify/verify functions + */ + if (desc->nfunc_name != NULL) { + rc = _nscd_cfg_get_funcp(desc->nfunc_name, + &desc->notify, &nfunc, NULL); + if (rc != NULL) + return (rc); + } + if (desc->vfunc_name != NULL) { + rc = _nscd_cfg_get_funcp(desc->vfunc_name, + &desc->verify, &vfunc, NULL); + if (rc != NULL) + return (rc); + } + } + + /* if end of list reached, we are done */ + if (i == _nscd_cfg_num_param) + break; + + desc->g_index = gi; + + id->index = i; + + if ((rc = _nscd_cfg_add_index_entry(id->name, + i, type)) != NSCD_SUCCESS) { + + _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR) + (me, "unable to add index entry for parameter " + "%s\n", id->name); + + _nscd_free_db(cfg_paramDB); + return (rc); + } else { + _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG) + (me, "index entry for parameter " + "%s added\n", id->name); + } + } + + return (_nscd_cfg_init_nsw()); +} + +static nscd_rc_t +_nscd_cfg_init_stat() +{ + char *me = "_nscd_cfg_init_stat"; + int i, gi, fn = 0; + nscd_cfg_id_t *id; + nscd_cfg_stat_desc_t *desc, *gdesc = NULL; + nscd_cfg_group_info_t g_info; + nscd_cfg_list_type_t type = NSCD_CFG_LIST_STAT; + nscd_rc_t rc; + void *gsfunc; + + desc = &_nscd_cfg_stat_desc[0]; + + /* + * need to loop to the last (+1) stat description + * which is a fake group and which marks the end + * of list. It is used to signal the end of the + * previous group so that the proper data will be + * set for that group + */ + for (i = 0; i < _nscd_cfg_num_stat + 1; i++, desc++) { + + id = (nscd_cfg_id_t *)desc; + + if (_nscd_cfg_flag_is_set(desc->sflag, + NSCD_CFG_SFLAG_GROUP)) { + + if (gdesc != NULL) { + g_info.num_param = fn; + gdesc->s_fn = fn; + + if (g_info.num_param != + gdesc->gi.num_param || + !_nscd_cfg_bitmap_is_equal( + g_info.bitmap, gdesc->gi.bitmap)) { + + _NSCD_LOG(NSCD_LOG_CONFIG, + NSCD_LOG_LEVEL_ERROR) + (me, "ERROR: group (%s) " + "info mismatched: " + "group info (%d, %#6.4x) not " + "equal to the predefined one " + "(%d, %#6.4x)\n", gdesc->id.name, + g_info.num_param, + _nscd_cfg_bitmap_value(g_info.bitmap), + gdesc->gi.num_param, + _nscd_cfg_bitmap_value( + gdesc->gi.bitmap)); + + exit(1); + return (NSCD_CFG_STAT_DESC_ERROR); + } + } + + gi = i; + fn = 0; + gdesc = desc; + g_info.bitmap = NSCD_CFG_BITMAP_ZERO; + gsfunc = NULL; + + /* + * set the get_stat function + */ + if (gdesc->gsfunc_name != NULL) { + rc = _nscd_cfg_get_funcp(gdesc->gsfunc_name, + &gdesc->get_stat, NULL, NULL); + if (rc != NULL) + return (rc); + gsfunc = (void *)gdesc->get_stat; + } + } else { + if (i == 0) { + + _NSCD_LOG(NSCD_LOG_CONFIG, + NSCD_LOG_LEVEL_ERROR) + (me, "ERROR: first stat " + "description is not for a group\n"); + + return (NSCD_CFG_STAT_DESC_ERROR); + } + + /* + * set bitmap: the rightmost bit represents + * the first member (index = 0) in the group, + * the next bit is for the second member + * (index = 1), and so on + */ + _nscd_cfg_bitmap_set_nth(g_info.bitmap, fn); + + desc->s_fn = fn++; + + /* + * set the get_stat function + */ + if (desc->gsfunc_name != NULL) { + rc = _nscd_cfg_get_funcp(desc->gsfunc_name, + &desc->get_stat, &gsfunc, NULL); + if (rc != NULL) + return (rc); + } + } + + /* if end of list reached, we are done */ + if (i == _nscd_cfg_num_stat) + break; + + desc->g_index = gi; + + id->index = i; + + if ((rc = _nscd_cfg_add_index_entry(id->name, + i, type)) != NSCD_SUCCESS) { + + _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR) + (me, "unable to add index entry for stat " + "description %s\n", id->name); + + _nscd_free_db(cfg_paramDB); + return (rc); + } else { + _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG) + (me, "index entry for stat description " + "%s added\n", id->name); + } + } + + return (NSCD_SUCCESS); +} + +static nscd_rc_t +_nscd_cfg_copy_vlen_data( + void *data, + void **new_data_p, + nscd_cfg_param_desc_t *desc, + int *data_len, + nscd_bool_t in) +{ + int len, dlen; + nscd_cfg_vlen_data_t *v = NULL; + + *new_data_p = NULL; + *data_len = 0; + + /* it is OK if there is nothing to copy */ + if (data == NULL) + return (NSCD_SUCCESS); + + /* + * if copy to the config store we need to allocate space + * for the extra vlen header + */ + if (desc->type == NSCD_CFG_DATA_STRING) { + len = dlen = strlen((char *)data) + 1; + if (in == nscd_true) + len += sizeof (nscd_cfg_vlen_data_t); + } else { + /* + * should not be here, since for now + * only string variable length data + * is supported + */ + *new_data_p = NULL; + return (NSCD_CFG_PARAM_DESC_ERROR); + } + + v = calloc(1, len); + if (v == NULL) { + *new_data_p = NULL; + return (NSCD_NO_MEMORY); + } + + /* + * if copy to the config store, set up + * the extra vlen header in which the + * pointer to, and length of, the real + * data are kept. The pointer to the real + * data, not the vlen header, is returned. + */ + if (in == nscd_true) { + v->ptr = (char *)v + sizeof (nscd_cfg_vlen_data_t); + v->len = dlen; + (void) memcpy(v->ptr, data, dlen); + *new_data_p = v->ptr; + } else { + (void) memcpy(v, data, dlen); + *new_data_p = v; + } + *data_len = dlen; + + return (NSCD_SUCCESS); +} + +static void +_nscd_cfg_free_vlen_data_int( + void *data) +{ + nscd_cfg_vlen_data_t *v = NULL; + void *p; + + if (data == NULL) + return; + + p = (char *)data - sizeof (nscd_cfg_vlen_data_t); + v = (nscd_cfg_vlen_data_t *)p; + if (v->ptr == data) + free(v); +} + +static nscd_rc_t +_nscd_cfg_set_vlen_data_int( + void *src, + void *dest, + nscd_bool_t global) +{ + int i, offset, dlen = 0; + void *s, *d, *new; + void *cptr; + nscd_rc_t rc; + nscd_cfg_param_desc_t *desc; + + desc = &_nscd_cfg_param_desc[0]; + for (i = 0; i < _nscd_cfg_num_param; i++, desc++) { + + if (global == nscd_true && + _nscd_cfg_flag_is_not_set(desc->pflag, + NSCD_CFG_PFLAG_GLOBAL)) + continue; + else if (global != nscd_true && + _nscd_cfg_flag_is_set(desc->pflag, + NSCD_CFG_PFLAG_GLOBAL)) + continue; + + if (_nscd_cfg_flag_is_set(desc->pflag, + NSCD_CFG_PFLAG_VLEN_DATA)) { + + offset = desc->g_offset + desc->p_offset; + + s = (char *)src + offset; + cptr = *(char **)s; + + rc = _nscd_cfg_copy_vlen_data(cptr, &new, + desc, &dlen, nscd_true); + if (rc != NSCD_SUCCESS) + return (rc); + + d = (char *)dest + offset; + /* free the old vlen data */ + if (*(char **)d == NULL) + _nscd_cfg_free_vlen_data_int(*(char **)d); + + *(char **)d = new; + } + } + + return (NSCD_SUCCESS); +} + +static void * +_nscd_cfg_locate_vlen_data( + void *cfg_data, + int *len) +{ + void *ptr, *ret; + + ptr = *(char **)cfg_data; + ret = ptr; + if (ret == NULL) { + *len = 0; + return (NULL); + } + ptr = (char *)ptr - sizeof (nscd_cfg_vlen_data_t); + *len = ((nscd_cfg_vlen_data_t *)ptr)->len; + + return (ret); +} + +static void +_nscd_cfg_lock( + nscd_bool_t is_read, + nscd_cfg_lock_t *cfglock) +{ + + int (*lockfunc)(rwlock_t *); + + if (cfglock == NULL) + return; + + if (is_read == nscd_true) + lockfunc = rw_rdlock; + else + lockfunc = rw_wrlock; + + if (cfglock->global != NULL) { + + (lockfunc)(cfglock->global); + return; + } + + if (cfglock->alldb != NULL) + (lockfunc)(cfglock->alldb); + + if (cfglock->nswdb != NULL) + (lockfunc)(cfglock->nswdb); +} + +static void +_nscd_cfg_unlock( + nscd_cfg_lock_t *cfglock) +{ + if (cfglock == NULL) + return; + + if (cfglock->global != NULL) { + + (void) rw_unlock(cfglock->global); + free(cfglock); + return; + } + + if (cfglock->nswdb != NULL) + (void) rw_unlock(cfglock->nswdb); + + if (cfglock->alldb != NULL) + (void) rw_unlock(cfglock->alldb); + + free(cfglock); +} + +/* + * If vlen_data_addr is given, it will be set to the + * address of the pointer pointing to the vlen data. + * 'cfglock' will be set to point to the reader/writer + * lock(s) protecting the (group) configuration data. + */ +static nscd_rc_t +_nscd_cfg_locate_cfg_data( + void **cfg_data, + nscd_bool_t is_read, + nscd_cfg_param_desc_t *desc, + nscd_cfg_id_t *nswdb, + nscd_bool_t get_group, + void **vlen_data_addr, + int *len, + nscd_cfg_lock_t **cfglock) +{ + int offset; + + *cfg_data = NULL; + if (len != NULL) + *len = 0; + if (vlen_data_addr != NULL) + *vlen_data_addr = NULL; + + if (cfglock != NULL) { + *cfglock = calloc(1, sizeof (nscd_cfg_lock_t)); + if (*cfglock == NULL) + return (NSCD_NO_MEMORY); + } + + /* assume if nswdb is NULL, the param is a global one */ + if (nswdb == NULL) { + + offset = desc->g_offset; + if (get_group != nscd_true) + offset += desc->p_offset; + *cfg_data = (char *)nscd_cfg_global_current + offset; + + if (cfglock != NULL) + (*cfglock)->global = nscd_cfg_global_rwlock; + + } else if (nswdb->index == NSCD_CFG_NSW_ALLDB_INDEX) { + + offset = desc->g_offset; + if (get_group != nscd_true) + offset += desc->p_offset; + *cfg_data = (char *)nscd_cfg_nsw_alldb_current + + offset; + + if (cfglock != NULL) + (*cfglock)->alldb = nscd_cfg_nsw_alldb_rwlock; + + } else { + + offset = nswdb->index * + (sizeof (nscd_cfg_nsw_db_data_t)) + desc->g_offset; + if (get_group != nscd_true) + offset += desc->p_offset; + *cfg_data = (char *)nscd_cfg_nsw_db_data_current + + offset; + + if (cfglock != NULL) { + (*cfglock)->nswdb = + &nscd_cfg_nsw_db_data_rwlock[nswdb->index]; + + (*cfglock)->alldb = nscd_cfg_nsw_alldb_rwlock; + } + } + + /* lock the config data */ + if (cfglock != NULL) + _nscd_cfg_lock(is_read, *cfglock); + + if (get_group != nscd_true && + _nscd_cfg_flag_is_not_set(desc->pflag, + NSCD_CFG_PFLAG_GROUP) && + (_nscd_cfg_flag_is_set(desc->pflag, + NSCD_CFG_PFLAG_VLEN_DATA))) { + if (vlen_data_addr != NULL) + *vlen_data_addr = *cfg_data; + *cfg_data = _nscd_cfg_locate_vlen_data(*cfg_data, len); + return (NSCD_SUCCESS); + } + + if (len != NULL) { + if (get_group == nscd_true) + *len = desc->g_size; + else + *len = desc->p_size; + } + + return (NSCD_SUCCESS); +} + +/* + * perform the preliminary (range) check on 'data' based on the + * datatype (desc->datatype) of the config parameter + */ +nscd_rc_t +_nscd_cfg_prelim_check( + nscd_cfg_param_desc_t *desc, + void *data, + nscd_cfg_error_t **errorp) +{ + + char *me = "_nscd_cfg_prelim_check"; + char msg[NSCD_CFG_MAX_ERR_MSG_LEN]; + nscd_cfg_str_check_t *sc; + nscd_cfg_int_check_t *ic; + nscd_cfg_bitmap_check_t *bmc; + nscd_rc_t rc = NSCD_CFG_PRELIM_CHECK_FAILED; + + if ((nscd_cfg_str_check_t *)desc->p_check == NULL) + return (NSCD_SUCCESS); + + switch (desc->type) { + + case NSCD_CFG_DATA_STRING: + + sc = (nscd_cfg_str_check_t *)desc->p_check; + if (sc->must_not_null == nscd_true && data == NULL) { + + if (errorp == NULL) + break; + + (void) snprintf(msg, sizeof (msg), + gettext("data must be specified for %s"), + desc->id.name); + + break; + } + + if (data == NULL) { + rc = NSCD_SUCCESS; + break; + } + + if (sc->maxlen != 0 && + strlen((char *)data) > sc->maxlen) { + + if (errorp == NULL) + break; + + (void) snprintf(msg, sizeof (msg), + gettext("length of data (%s) for %s larger than %d"), + (char *)data, desc->id.name, sc->maxlen); + break; + } + + rc = NSCD_SUCCESS; + + break; + + case NSCD_CFG_DATA_INTEGER: + + ic = (nscd_cfg_int_check_t *)desc->p_check; + if (*(int *)data > ic->max || + *(int *)data < ic->min) { + + if (errorp == NULL) + break; + + (void) snprintf(msg, sizeof (msg), + gettext("data (%d) for %s out of range (%d - %d)"), + *(int *)data, desc->id.name, + ic->min, ic->max); + + break; + } + + rc = NSCD_SUCCESS; + + break; + + case NSCD_CFG_DATA_BITMAP: + + bmc = (nscd_cfg_bitmap_check_t *)desc->p_check; + if (_nscd_cfg_bitmap_value(*(nscd_cfg_bitmap_t *)data) & + ~(bmc->valid_bits)) { + + if (errorp == NULL) + break; + + (void) snprintf(msg, sizeof (msg), + gettext("data (%#6.4x) for %s contain bit not in 0x%x"), + _nscd_cfg_bitmap_value( + *(nscd_cfg_bitmap_t *)data), + desc->id.name, + _nscd_cfg_bitmap_value(bmc->valid_bits)); + break; + } + + rc = NSCD_SUCCESS; + + break; + } + + if (rc != NSCD_SUCCESS && errorp != NULL) { + *errorp = _nscd_cfg_make_error(rc, msg); + + _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG) + (me, "invalid argument: %s\n", (*errorp)->msg); + } + + return (rc); +} + +static nscd_rc_t +_nscd_cfg_notify_i( + nscd_cfg_param_desc_t *desc, + nscd_cfg_id_t *nswdb, + int *skip, + nscd_cfg_error_t **errorp) +{ + + char *me = "_nscd_cfg_notify_i"; + int i, num, skip_bk; + void *cfg_data, *cdata; + void *cookie = NULL; + nscd_rc_t rc; + nscd_cfg_flag_t dflag, dflag1; + nscd_cfg_bitmap_t bitmap_c, bitmap_s, *bitmap_addr; + nscd_cfg_group_info_t *gi; + + if (errorp != NULL) + *errorp = NULL; + + if (skip == NULL) + skip = &skip_bk; + + *skip = 0; + + if (_nscd_cfg_flag_is_not_set(desc->pflag, + NSCD_CFG_PFLAG_GROUP)) { + + _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR) + (me, "ERROR: expect parameter description for group, " + "but receive parameter description is for %s\n", + desc->id.name); + + return (NSCD_CFG_PARAM_DESC_ERROR); + } + + /* + * Set data flag going with data to be sent to the + * verify/notify routines. Allowing the config flag + * be exipandable, set the bits one by one. + */ + dflag = NSCD_CFG_FLAG_ZERO; + dflag = _nscd_cfg_flag_set(dflag, NSCD_CFG_DFLAG_STATIC_DATA); + dflag = _nscd_cfg_flag_set(dflag, NSCD_CFG_DFLAG_INIT); + dflag = _nscd_cfg_flag_set(dflag, NSCD_CFG_DFLAG_GROUP); + if (_nscd_cfg_flag_is_set(desc->pflag, + NSCD_CFG_PFLAG_INIT_SET_ALL_DB)) + dflag = _nscd_cfg_flag_set(dflag, + NSCD_CFG_DFLAG_SET_ALL_DB); + + /* get to the group data in the config store */ + rc = _nscd_cfg_locate_cfg_data(&cfg_data, nscd_true, + desc, nswdb, nscd_true, NULL, NULL, NULL); + if (rc != NSCD_SUCCESS) + goto error; + + /* + * the static bitmap associated with the group + * may be replaced before sending to the components, + * so save the bitmap for later use + */ + gi = _nscd_cfg_get_gi(cfg_data); + bitmap_c = gi->bitmap; + bitmap_addr = &(gi->bitmap); + + /* + * the elements in this group will all be handled + * so the caller can skip them + */ + *skip = desc->p_fn; + + if (_nscd_cfg_flag_is_set(desc->pflag, + NSCD_CFG_PFLAG_INIT_SEND_WHOLE_GROUP)) + /* send the entire group just once */ + num = 1; + + else { /* send individual members one by one */ + + num = desc->p_fn; + + /* + * skip the first desc which is for the group + * and get to the desc for the first member + */ + desc++; + + dflag = _nscd_cfg_flag_unset(dflag, + NSCD_CFG_DFLAG_GROUP); + } + + dflag1 = dflag; + for (i = 0; i < num; i++, desc++) { + + dflag = dflag1; + + if (_nscd_cfg_flag_is_set(desc->pflag, + NSCD_CFG_PFLAG_SEND_BIT_SELECTED)) { + + /* set the bitmap to select just this member */ + bitmap_s = NSCD_CFG_BITMAP_ZERO; + _nscd_cfg_bitmap_set_nth(bitmap_s, i); + /* replace the bitmap in the cfg data */ + _nscd_cfg_bitmap_set(bitmap_addr, bitmap_s); + + /* + * send the whole group but with only one + * member selected + */ + cdata = cfg_data; + + dflag = _nscd_cfg_flag_set(dflag, + NSCD_CFG_DFLAG_GROUP); + dflag = _nscd_cfg_flag_set(dflag, + NSCD_CFG_DFLAG_BIT_SELECTED); + } else { + /* + * send param data or group data: + * param data - non-xero desc->p_offset + * group data - zero desc->p_offset + */ + cdata = (char *)cfg_data + desc->p_offset; + + /* + * if variable length data, need to send pointer + * to the data (not the address of the pointer) + */ + if (_nscd_cfg_flag_is_set(desc->pflag, + NSCD_CFG_PFLAG_VLEN_DATA)) + cdata = *(char **)cdata; + } + + if (desc->verify != NULL) { + dflag = _nscd_cfg_flag_set(dflag, + NSCD_CFG_DFLAG_VERIFY); + rc = desc->verify(cdata, desc, nswdb, + dflag, errorp, &cookie); + if (rc != NSCD_SUCCESS) + goto error; + } + + if (desc->notify != NULL) { + dflag = _nscd_cfg_flag_set(dflag, + NSCD_CFG_DFLAG_NOTIFY); + + rc = desc->notify(cfg_data, desc, nswdb, + dflag, errorp, cookie); + if (rc != NSCD_SUCCESS) + goto error; + } + } + + rc = NSCD_SUCCESS; + + /* restore the bitmap in the cfg data */ + _nscd_cfg_bitmap_set(bitmap_addr, bitmap_c); + + error: + + return (rc); + +} + +static nscd_rc_t +_nscd_cfg_notify_init( + nscd_cfg_error_t **errorp) +{ + int i, j, skip; + nscd_rc_t rc; + nscd_cfg_id_t *nswdb = NULL; + nscd_cfg_param_desc_t *desc; + + if (errorp != NULL) + *errorp = NULL; + + for (i = 0; i < _nscd_cfg_num_param; i++) { + + desc = &_nscd_cfg_param_desc[i]; + + if (_nscd_cfg_flag_is_set(desc->pflag, + NSCD_CFG_PFLAG_GLOBAL)) { /* global cfg data */ + + rc = _nscd_cfg_notify_i(desc, NULL, &skip, errorp); + } else { + + /* + * if use defaults for all nsswitch database, + * send the config data to verify/notify once + */ + if (_nscd_cfg_flag_is_set(desc->pflag, + NSCD_CFG_PFLAG_INIT_SET_ALL_DB)) { + + nswdb = &_nscd_cfg_nsw_alldb; + + rc = _nscd_cfg_notify_i(desc, nswdb, + &skip, errorp); + } else { /* send data once for each nsw db */ + + for (j = 0; j < _nscd_cfg_num_nsw_db; + j++) { + + nswdb = &_nscd_cfg_nsw_db[j]; + + rc = _nscd_cfg_notify_i(desc, + nswdb, &skip, errorp); + } + } + } + + if (rc != NSCD_SUCCESS) + return (rc); + + i += skip; + } + + return (NSCD_SUCCESS); +} + +nscd_rc_t +_nscd_cfg_init( + nscd_cfg_error_t **errorp) +{ + + int i, j, datalen; + int dbi = 0, dbj = 0; + char *dest, *src; + char *dbni = NULL, *dbnj = NULL; + nscd_rc_t rc; + nscd_cfg_nsw_spc_default_t *spc; + + if (errorp != NULL) + *errorp = NULL; + + rc = _nscd_cfg_init_param(); + if (rc != NSCD_SUCCESS) + return (rc); + + rc = _nscd_cfg_init_stat(); + if (rc != NSCD_SUCCESS) + return (rc); + + nscd_cfg_global_current = calloc(1, + sizeof (nscd_cfg_global_data_t)); + if (nscd_cfg_global_current == NULL) + return (NSCD_NO_MEMORY); + + nscd_cfg_nsw_alldb_current = calloc(1, + sizeof (nscd_cfg_nsw_db_data_t)); + if (nscd_cfg_nsw_alldb_current == NULL) + return (NSCD_NO_MEMORY); + + nscd_cfg_nsw_db_data_current = calloc(_nscd_cfg_num_nsw_db, + sizeof (nscd_cfg_nsw_db_data_t)); + if (nscd_cfg_nsw_db_data_current == NULL) + return (NSCD_NO_MEMORY); + + nscd_cfg_global_rwlock = calloc(1, sizeof (rwlock_t)); + if (nscd_cfg_global_rwlock == NULL) + return (NSCD_NO_MEMORY); + (void) rwlock_init(nscd_cfg_global_rwlock, NULL, NULL); + + *nscd_cfg_global_current = nscd_cfg_global_default; + + rc = _nscd_cfg_set_vlen_data_int(&nscd_cfg_global_default, + nscd_cfg_global_current, nscd_true); + if (rc != NSCD_SUCCESS) + return (rc); + + nscd_cfg_nsw_db_data_rwlock = calloc(_nscd_cfg_num_nsw_db, + sizeof (rwlock_t)); + if (nscd_cfg_nsw_db_data_rwlock == NULL) + return (NSCD_NO_MEMORY); + + /* set per switch db config to the default for all db's */ + for (i = 0; i < _nscd_cfg_num_nsw_db; i++) { + + nscd_cfg_nsw_db_data_current[i] = + nscd_cfg_nsw_db_data_default; + + (void) rwlock_init(&nscd_cfg_nsw_db_data_rwlock[i], + NULL, NULL); + } + + /* add db specific defaults */ + for (i = 0; i < _nscd_cfg_num_nsw_default; i++) { + + if (_nscd_cfg_nsw_spc_default[i].data == NULL) + continue; + + if (_nscd_cfg_nsw_spc_default[i].db != dbni) { + for (j = 0; j < _nscd_cfg_num_nsw_db; j++) { + + if (strcmp(_nscd_cfg_nsw_db[j].name, + _nscd_cfg_nsw_spc_default[i].db) != 0) + continue; + + dbi = _nscd_cfg_nsw_db[j].index; + dbni = _nscd_cfg_nsw_db[j].name; + break; + } + } + + dest = (char *)&nscd_cfg_nsw_db_data_current[dbi] + + _nscd_cfg_nsw_spc_default[i].group_off + + _nscd_cfg_nsw_spc_default[i].param_off; + + src = _nscd_cfg_nsw_spc_default[i].data; + datalen = _nscd_cfg_nsw_spc_default[i].data_len; + + (void) memcpy(dest, src, datalen); + } + + /* add db specific defaults via links */ + for (i = 0; i < _nscd_cfg_num_link_default; i++) { + + if (_nscd_cfg_nsw_link_default[i].data == NULL) + continue; + + spc = _nscd_cfg_nsw_link_default[i].data; + + if (_nscd_cfg_nsw_link_default[i].db != dbni) { + for (j = 0; j < _nscd_cfg_num_nsw_db; j++) { + + if (strcmp(_nscd_cfg_nsw_db[j].name, + _nscd_cfg_nsw_link_default[i].db) != 0) + continue; + + dbi = _nscd_cfg_nsw_db[j].index; + dbni = _nscd_cfg_nsw_db[j].name; + break; + } + } + + dest = (char *)&nscd_cfg_nsw_db_data_current[dbi] + + _nscd_cfg_nsw_link_default[i].group_off + + _nscd_cfg_nsw_link_default[i].param_off; + + if (_nscd_cfg_nsw_db[j].name != dbnj) { + for (j = 0; j < _nscd_cfg_num_nsw_db; j++) { + + if (strcmp(spc->db, + _nscd_cfg_nsw_db[j].name) != 0) + continue; + + dbnj = _nscd_cfg_nsw_db[j].name; + dbj = _nscd_cfg_nsw_db[j].index; + break; + } + } + + src = (char *)&nscd_cfg_nsw_db_data_current[dbj] + + spc->group_off + spc->param_off; + datalen = spc->data_len; + + (void) memcpy(dest, src, datalen); + } + + /* fix up variable length fields */ + for (i = 0; i < _nscd_cfg_num_nsw_db; i++) { + + rc = _nscd_cfg_set_vlen_data_int( + &nscd_cfg_nsw_db_data_current[i], + &nscd_cfg_nsw_db_data_current[i], nscd_false); + if (rc != NSCD_SUCCESS) + return (rc); + } + + nscd_cfg_nsw_alldb_rwlock = calloc(1, sizeof (rwlock_t)); + if (nscd_cfg_nsw_alldb_rwlock == NULL) + return (NSCD_NO_MEMORY); + + (void) rwlock_init(nscd_cfg_nsw_alldb_rwlock, NULL, NULL); + + rc = _nscd_cfg_set_vlen_data_int( + &nscd_cfg_nsw_db_data_default, + &nscd_cfg_nsw_alldb_current, nscd_false); + if (rc != NSCD_SUCCESS) + return (rc); + + /* + * notify and send the configuration data to + * the nscd components + */ + rc = _nscd_cfg_notify_init(errorp); + if (rc != NSCD_SUCCESS) + return (rc); + + return (NSCD_SUCCESS); +} + +static nscd_rc_t +_nscd_cfg_get_handle_common( + nscd_cfg_list_type_t type, + char *name, + char *nswdb_name, + nscd_cfg_handle_t **handle, + nscd_cfg_error_t **errorp) +{ + + int i, is_global; + char *desc_str; + nscd_cfg_handle_t *h; + nscd_cfg_param_desc_t *pdesc; + nscd_cfg_stat_desc_t *sdesc; + char *me = "_nscd_cfg_get_handle_common"; + char msg[NSCD_CFG_MAX_ERR_MSG_LEN]; + nscd_rc_t rc = NSCD_INVALID_ARGUMENT; + + if (handle == NULL) { + + (void) snprintf(msg, sizeof (msg), + gettext("address of handle not specified")); + if (errorp) + *errorp = _nscd_cfg_make_error(rc, msg); + + _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG) + (me, "invalid argument: %s\n", msg); + + return (rc); + } + + *handle = NULL; + + if (name == NULL) { + + (void) snprintf(msg, sizeof (msg), + gettext("name not specified")); + if (errorp) + *errorp = _nscd_cfg_make_error(rc, msg); + + _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG) + (me, "invalid argument: %s\n"); + + return (rc); + } + + h = calloc(1, sizeof (nscd_cfg_handle_t)); + if (h == NULL) + return (NSCD_NO_MEMORY); + h->type = type; + + if (type == NSCD_CFG_LIST_PARAM) + desc_str = gettext("configuration parameter"); + else + desc_str = gettext("statistics"); + + /* get param or stat descriptor */ + i = _nscd_cfg_get_index(name, type); + if (i != -1) { + + _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG) + (me, "%s: index of %s is %d\n", desc_str, name, i); + + if (type == NSCD_CFG_LIST_PARAM) { + pdesc = &_nscd_cfg_param_desc[i]; + (void) memcpy(&h->desc, &pdesc, sizeof (pdesc)); + is_global = _nscd_cfg_flag_is_set( + pdesc->pflag, NSCD_CFG_PFLAG_GLOBAL); + + /* hidden params are not exposed */ + if (_nscd_cfg_flag_is_set( + pdesc->pflag, NSCD_CFG_PFLAG_HIDDEN)) + i = -1; + + if (_nscd_cfg_flag_is_set(pdesc->pflag, + NSCD_CFG_PFLAG_OBSOLETE)) { + _NSCD_LOG(NSCD_LOG_CONFIG, + NSCD_LOG_LEVEL_WARNING) + (me, + gettext("%s: %s is obsolete and will be ignored\n"), + desc_str, name); + } + } else { + sdesc = &_nscd_cfg_stat_desc[i]; + (void) memcpy(&h->desc, &sdesc, sizeof (sdesc)); + is_global = _nscd_cfg_flag_is_set( + sdesc->sflag, NSCD_CFG_SFLAG_GLOBAL); + } + } + + if (i == -1) { + + (void) snprintf(msg, sizeof (msg), + gettext("%s: unknown name \"%s\""), desc_str, name); + if (errorp) + *errorp = _nscd_cfg_make_error(rc, msg); + + _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR) + (me, "%s\n", msg); + + free(h); + return (rc); + } + + /* + * if the param/stat is not a global one, we need to + * know which nsswitch database we are dealing with + */ + if (is_global == 0) { + if (nswdb_name == NULL) { + + (void) snprintf(msg, sizeof (msg), + gettext("%s: switch database name not specified"), + desc_str); + if (errorp) + *errorp = _nscd_cfg_make_error(rc, msg); + + _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR) + (me, "%s for non-global param or stat %s\n", + msg, name); + + free(h); + return (rc); + } + } else { + + if (nswdb_name != NULL) { + + (void) snprintf(msg, sizeof (msg), + gettext("%s: switch database specified for global data"), + desc_str); + if (errorp) + *errorp = _nscd_cfg_make_error(rc, msg); + + _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR) + (me, "%s %s\n", msg, name); + + free(h); + return (rc); + } + + *handle = h; + return (NSCD_SUCCESS); + } + + /* get nsw DB id */ + i = _nscd_cfg_get_index(nswdb_name, NSCD_CFG_LIST_NSW_DB); + if (i != -1) { + + if (i == NSCD_CFG_NSW_ALLDB_INDEX) + h->nswdb = &_nscd_cfg_nsw_alldb; + else + h->nswdb = &_nscd_cfg_nsw_db[i]; + + _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG) + (me, "%s: index of %s is %d\n", + desc_str, nswdb_name, i); + } else { + + (void) snprintf(msg, sizeof (msg), + gettext("%s: unknown switch database name \"%s\""), + desc_str, nswdb_name); + if (errorp) + *errorp = _nscd_cfg_make_error(rc, msg); + + _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR) + (me, "%s\n", msg); + + free(h); + return (NSCD_CFG_UNSUPPORTED_SWITCH_DB); + } + + *handle = h; + + return (NSCD_SUCCESS); +} + +nscd_rc_t +_nscd_cfg_get_handle( + char *param_name, + char *nswdb_name, + nscd_cfg_handle_t **handle, + nscd_cfg_error_t **errorp) +{ + + return (_nscd_cfg_get_handle_common(NSCD_CFG_LIST_PARAM, + param_name, nswdb_name, handle, errorp)); +} + +nscd_rc_t +_nscd_cfg_get_stat_handle( + char *stat_name, + char *nswdb_name, + nscd_cfg_handle_t **handle, + nscd_cfg_error_t **errorp) +{ + + return (_nscd_cfg_get_handle_common(NSCD_CFG_LIST_STAT, + stat_name, nswdb_name, handle, errorp)); +} + +void +_nscd_cfg_free_handle( + nscd_cfg_handle_t *handle) +{ + + free(handle); + +} + +static void +_nscd_cfg_free_vlen_data_group( + nscd_cfg_param_desc_t *gdesc, + void *group_data, + nscd_bool_t in) +{ + int num; + void *dest, *ptr; + nscd_cfg_param_desc_t *desc; + + desc = gdesc; + + num = ((nscd_cfg_group_info_t *)group_data)->num_param; + + while (num-- > 0) { + + desc++; + + /* skip fixed length data */ + if (_nscd_cfg_flag_is_not_set(desc->pflag, + NSCD_CFG_PFLAG_VLEN_DATA)) + continue; + + dest = (char *)group_data + desc->p_offset; + ptr = *(char **)dest; + if (ptr == NULL) + continue; + if (in == nscd_true) + _nscd_cfg_free_vlen_data_int(ptr); + else + free(ptr); + } +} + +void +_nscd_cfg_free_param_data( + void *data) +{ + + if (data == NULL) + return; + + free(data); +} + +void +_nscd_cfg_free_group_data( + nscd_cfg_handle_t *handle, + void *data) +{ + + nscd_cfg_param_desc_t *desc; + nscd_cfg_group_info_t *gi; + + if (handle == NULL || data == NULL) + return; + + desc = _nscd_cfg_get_desc(handle); + gi = (nscd_cfg_group_info_t *)data; + if (desc->p_fn != gi->num_param) + return; + + _nscd_cfg_free_vlen_data_group(desc, data, nscd_false); + + free(data); +} + +void +_nscd_cfg_free_error( + nscd_cfg_error_t *error) +{ + + if (error == NULL) + return; + + free(error); +} + +static nscd_rc_t +_nscd_cfg_copy_param_data( + nscd_cfg_param_desc_t *desc, + void *dest, + void *pdata, + nscd_bool_t in, + nscd_bool_t set_addr) +{ + + char *me = "_nscd_cfg_copy_param_data"; + void *tmp; + int dlen; + nscd_rc_t rc = NSCD_SUCCESS; + + if (desc == NULL || dest == NULL) { + _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR) + (me, "input desc == %p, dest == %p\n", desc, dest); + return (NSCD_INVALID_ARGUMENT); + } + + /* fixed length data */ + if (_nscd_cfg_flag_is_not_set(desc->pflag, + NSCD_CFG_PFLAG_VLEN_DATA)) { + (void) memcpy(dest, pdata, desc->p_size); + goto done; + } + + + /* variable length data from this point on */ + + /* make a copy of the variable length data */ + rc = _nscd_cfg_copy_vlen_data(pdata, &tmp, desc, &dlen, in); + if (rc != NSCD_SUCCESS) + goto done; + + if (in == nscd_true) { /* data to internal */ + + /* free the variable length data in the config store */ + if (*(char **)dest != NULL) + _nscd_cfg_free_vlen_data_int(*(char **)dest); + } + + if (set_addr == nscd_true) { + /* + * set the addr of the vlen data + */ + *(char **)dest = tmp; + } else { + /* + * copy the data content (not address) + */ + (void) memcpy(dest, tmp, dlen); + } + + done: + + return (rc); +} + +static nscd_rc_t +_nscd_cfg_copy_group_data_in( + nscd_cfg_param_desc_t *gdesc, + nscd_cfg_group_info_t *gi, + void *group_dest, + void *group_src) +{ + int i, num; + nscd_cfg_param_desc_t *desc; + void *src, *dest; + + i = 0; + num = gi->num_param; + desc = gdesc; + + while (num-- > 0) { + + desc++; + + /* if member not selected by bitmap, skip */ + if (_nscd_cfg_bitmap_is_not_set(gi->bitmap, i++)) + continue; + + src = (char *)group_src + desc->p_offset; + dest = (char *)group_dest + desc->p_offset; + + /* + * if variable length data, free and replace the old + * with the new + */ + if (_nscd_cfg_flag_is_set(desc->pflag, + NSCD_CFG_PFLAG_VLEN_DATA)) { + _nscd_cfg_free_vlen_data_int(*(char **)dest); + *(char **)dest = *(char **)src; + *(char **)src = NULL; + } else { + /* + * fixed length data, just copy it + */ + (void) memcpy(dest, src, desc->p_size); + } + } + + return (NSCD_SUCCESS); +} + +static nscd_rc_t +_nscd_cfg_copy_group_data_out( + nscd_cfg_param_desc_t *gdesc, + void *group_dest, + void *group_src) +{ + + char *me = "_nscd_cfg_copy_group_data_out"; + void *src, *dest; + int dlen; + int num; + nscd_cfg_group_info_t *gi; + nscd_rc_t rc = NSCD_SUCCESS; + nscd_cfg_param_desc_t *desc; + + if (group_dest == NULL) { + _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR) + (me, "input group_dest = NULL\n"); + return (NSCD_INVALID_ARGUMENT); + } + + gi = _nscd_cfg_get_gi(group_src); + num = gi->num_param; + desc = gdesc; + + while (num-- > 0) { + + desc++; + + dest = (char *)group_dest + desc->p_offset; + src = (char *)group_src + desc->p_offset; + + /* + * if variable length data, get the real + * address and length of the data + */ + if (_nscd_cfg_flag_is_set(desc->pflag, + NSCD_CFG_PFLAG_VLEN_DATA)) { + src = _nscd_cfg_locate_vlen_data(src, &dlen); + if (dlen == NULL) + continue; + } + + /* + * The nscd_true asks _nscd_cfg_copy_param_data + * to set addr of the vlen data in 'dest' rather + * than copying the data content + */ + rc = _nscd_cfg_copy_param_data(desc, dest, src, + nscd_false, nscd_true); + if (rc != NSCD_SUCCESS) { + _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR) + (me, "unable to copy param data for %s\n", + desc->id.name); + + _nscd_cfg_free_vlen_data_group(gdesc, + group_dest, nscd_false); + + free(group_dest); + + return (rc); + } + } + + /* + * set group bitmap + */ + (void) memcpy(group_dest, group_src, + sizeof (nscd_cfg_group_info_t)); + + return (rc); +} + + +/* + * group_cfg is needed always; group_src may be NULL if + * param_index not zero and pdata not NULL; group_cfg and + * pdata should not be both non-NULL + */ +static nscd_rc_t +_nscd_cfg_copy_group_data_merge( + nscd_cfg_param_desc_t *gdesc, + void **group_dest, + void *group_src, + void *group_cfg, + int param_index, + void *pdata) +{ + + char *me = "_nscd_cfg_copy_group_data_merge"; + void *src, *dest, *tmp_dest = NULL; + int num, i = 0; + nscd_cfg_group_info_t *gi; + nscd_rc_t rc = NSCD_SUCCESS; + nscd_cfg_param_desc_t *desc; + nscd_cfg_bitmap_t bitmap; + + if (group_dest == NULL) { + _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR) + (me, "input **group_dest == NULL\n"); + return (NSCD_INVALID_ARGUMENT); + } + + if (group_cfg == NULL) { + _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR) + (me, "input **group_cfg == NULL\n"); + return (NSCD_INVALID_ARGUMENT); + } + + if (param_index != NULL && pdata == NULL) { + _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR) + (me, "param_index != NULL but pdata == %p\n", pdata); + return (NSCD_INVALID_ARGUMENT); + } + + tmp_dest = calloc(1, gdesc->g_size); + if (tmp_dest == NULL) + return (NSCD_NO_MEMORY); + + if (group_src != NULL) + gi = _nscd_cfg_get_gi(group_src); + else { + gi = _nscd_cfg_get_gi(group_cfg); + bitmap = NSCD_CFG_BITMAP_ZERO; + } + + num = gi->num_param; + desc = gdesc; + + while (num-- > 0) { + + desc++; + + dest = (char *)tmp_dest + desc->p_offset; + + /* + * if member not selected by bitmap in group_src, + * get the member data in group_cfg + */ + if (_nscd_cfg_bitmap_is_not_set(gi->bitmap, i++) || + group_src == NULL) { + src = (char *)group_cfg + desc->p_offset; + } else + src = (char *)group_src + desc->p_offset; + + if (desc->id.index == param_index) { + + /* use the param data in pdata if provided */ + src = pdata; + _nscd_cfg_bitmap_set_nth(bitmap, i); + } + + /* + * if variable length data, get to the data + * instead of pointer to the data + */ + if (_nscd_cfg_flag_is_set(desc->pflag, + NSCD_CFG_PFLAG_VLEN_DATA)) + src = *(char **)src; + + /* + * nscd_true asks _nscd_cfg_copy_param_data to + * set addr of the vlen data in 'dest' rather + * than copying the data content + */ + rc = _nscd_cfg_copy_param_data(desc, dest, src, + nscd_true, nscd_true); + if (rc != NSCD_SUCCESS) { + _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR) + (me, "unable to copy param data for %s\n", + desc->id.name); + + _nscd_cfg_free_vlen_data_group(gdesc, + tmp_dest, nscd_true); + + free(tmp_dest); + + return (rc); + } + } + + *group_dest = tmp_dest; + + /* + * set bitmap: if input is group data, use the one + * given; if input is param data, use the one computed + * above + */ + if (group_src != NULL) + (void) memcpy(*group_dest, group_src, + sizeof (nscd_cfg_group_info_t)); + else { + gi = _nscd_cfg_get_gi(*group_dest); + _nscd_cfg_bitmap_set(&gi->bitmap, bitmap); + } + + return (rc); +} + +/* ARGSUSED */ +nscd_rc_t +_nscd_cfg_get( + nscd_cfg_handle_t *handle, + void **data, + int *data_len, + nscd_cfg_error_t **errorp) +{ + char *me = "_nscd_cfg_get"; + int dlen; + nscd_rc_t rc = NSCD_SUCCESS; + nscd_cfg_id_t *nswdb; + nscd_cfg_param_desc_t *desc; + void *cfg_data, *ptr = NULL; + nscd_bool_t get_group = nscd_false; + nscd_bool_t out = nscd_false; + nscd_cfg_lock_t *lock = NULL; + + if (data_len != NULL) + *data_len = 0; + + if (data == NULL) { + _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR) + (me, "input data = %p\n", data); + return (NSCD_INVALID_ARGUMENT); + } + + *data = NULL; + + if (handle == NULL) { + _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR) + (me, "handle is NULL\n"); + return (NSCD_INVALID_ARGUMENT); + } + + nswdb = handle->nswdb; + desc = (nscd_cfg_param_desc_t *)handle->desc; + + if (_nscd_cfg_flag_is_set(desc->pflag, NSCD_CFG_PFLAG_GROUP)) + get_group = nscd_true; + + /* + * locate the current value of the param or group + * and lock the config data for reading + */ + rc = _nscd_cfg_locate_cfg_data(&cfg_data, nscd_true, desc, + nswdb, get_group, NULL, &dlen, &lock); + if (rc != NSCD_SUCCESS) { + + _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR) + (me, "unable to locate config data\n"); + return (rc); + + } else if (cfg_data == NULL) /* NULL vlen data */ + goto done; + + ptr = calloc(1, dlen); + if (ptr == NULL) { + rc = NSCD_NO_MEMORY; + goto error_exit; + } + + if (get_group == nscd_true) { + + rc = _nscd_cfg_copy_group_data_out(desc, ptr, cfg_data); + if (rc != NSCD_SUCCESS) { + _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR) + (me, "unable to copy group data %p: " + "error = %d\n", cfg_data, rc); + + goto error_exit; + } + } else { + /* + * nscd_false asks _nscd_cfg_copy_param_data to + * copy the data content rather than just setting + * the addr of the vlen data in 'ptr' + */ + rc = _nscd_cfg_copy_param_data(desc, ptr, cfg_data, + out, nscd_false); + + if (rc != NSCD_SUCCESS) { + _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR) + (me, "unable to copy param data %p: " + "error = %d\n", cfg_data, rc); + + goto error_exit; + } + } + + *data = ptr; + + done: + + if (data_len != NULL) + *data_len = dlen; + + _nscd_cfg_unlock(lock); + + return (NSCD_SUCCESS); + + error_exit: + + _nscd_cfg_unlock(lock); + if (ptr != NULL) + free(ptr); + + return (rc); +} + +/* + * three type of data: + * 1 - single param + * desc is that of the param + * 2 - single param to be sent in a group + * a single bit is set in the bitmap, + * desc is that of the group + * 3 - group data + * one of more bits are set in the bitmap, + * desc is that of the group + */ +static nscd_rc_t +_nscd_cfg_notify_s( + nscd_cfg_param_desc_t *desc, + nscd_cfg_id_t *nswdb, + void *data, + nscd_cfg_error_t **errorp) +{ + int i, num, is_group = 0; + void *cookie = NULL; + void *cdata; + nscd_rc_t rc; + nscd_cfg_flag_t dflag, dflag1; + nscd_cfg_bitmap_t bitmap_s, bitmap_in, *bitmap_addr = NULL; + nscd_cfg_group_info_t *gi; + + if (errorp != NULL) + *errorp = NULL; + + /* + * Set data flag going with data to be sent to the + * verify/notify routines. To allow the config flag + * be exipandable, set the bits one by one. + */ + dflag = NSCD_CFG_FLAG_ZERO; + dflag = _nscd_cfg_flag_set(dflag, NSCD_CFG_DFLAG_STATIC_DATA); + if (_nscd_cfg_flag_is_set(desc->pflag, NSCD_CFG_PFLAG_GROUP)) { + dflag = _nscd_cfg_flag_set(dflag, NSCD_CFG_DFLAG_GROUP); + is_group = 1; + } + if (nswdb != NULL && + strcmp(NSCD_CFG_NSW_ALLDB, nswdb->name) == 0) + dflag = _nscd_cfg_flag_set(dflag, + NSCD_CFG_DFLAG_SET_ALL_DB); + + /* + * the bitmap in the input data may be replaced before + * sending to the components, so save the bitmap for + * later use + */ + if (is_group == 1) { + gi = _nscd_cfg_get_gi(data); + bitmap_in = gi->bitmap; + bitmap_addr = &(gi->bitmap); + + if (_nscd_cfg_flag_is_set(desc->pflag, + NSCD_CFG_PFLAG_INIT_SEND_WHOLE_GROUP)) + /* send the entire group just once */ + num = 1; + + else { /* send individual members one by one */ + + num = desc->p_fn; + + /* + * skip the first desc which is for the group + * and get to the desc for the first member + */ + desc++; + + dflag = _nscd_cfg_flag_unset(dflag, + NSCD_CFG_DFLAG_GROUP); + } + } else { + /* not group data, send the member once */ + num = 1; + } + + dflag1 = dflag; + for (i = 0; i < num; i++, desc++) { + + dflag = dflag1; + + if (is_group == 0) { + cdata = data; + goto verify_data; + } + + if (_nscd_cfg_flag_is_set(desc->pflag, + NSCD_CFG_PFLAG_SEND_BIT_SELECTED)) { + + /* set the bitmap to select just this member */ + bitmap_s = NSCD_CFG_BITMAP_ZERO; + _nscd_cfg_bitmap_set_nth(bitmap_s, i); + /* replace the bitmap in the input data */ + _nscd_cfg_bitmap_set(bitmap_addr, bitmap_s); + + /* + * send the whole group but with only one + * member selected + */ + cdata = data; + + dflag = _nscd_cfg_flag_set(dflag, + NSCD_CFG_DFLAG_GROUP); + dflag = _nscd_cfg_flag_set(dflag, + NSCD_CFG_DFLAG_BIT_SELECTED); + } else { + /* + * send param data or group data: + * param data - non-xero desc->p_offset + * group data - zero desc->p_offset + */ + cdata = (char *)data + desc->p_offset; + + /* + * if variable length data, need to send pointer + * to the data (not the address of the pointer) + */ + if (_nscd_cfg_flag_is_set(desc->pflag, + NSCD_CFG_PFLAG_VLEN_DATA)) + cdata = *(char **)cdata; + } + + verify_data: + + if (desc->verify != NULL) { + dflag = _nscd_cfg_flag_set(dflag, + NSCD_CFG_DFLAG_VERIFY); + rc = desc->verify(cdata, desc, nswdb, + dflag, errorp, &cookie); + if (rc != NSCD_SUCCESS) + goto error_exit; + } + + if (desc->notify != NULL) { + dflag = _nscd_cfg_flag_set(dflag, + NSCD_CFG_DFLAG_NOTIFY); + + rc = desc->notify(data, desc, nswdb, + dflag, errorp, cookie); + if (rc != NSCD_SUCCESS) + goto error_exit; + } + } + + rc = NSCD_SUCCESS; + + error_exit: + + /* restore the bitmap in the input data */ + if (bitmap_addr != NULL) + _nscd_cfg_bitmap_set(bitmap_addr, bitmap_in); + + return (rc); +} + +/* + * Convert string 'str' to data based on the data type in 'desc'. + * 'data' points to the buffer in which the converted data + * is placed. '*data_p' points to the buffer, or in the case + * of a string data type, points to the untoched string (i.e., + * 'str'). + */ +nscd_rc_t +_nscd_cfg_str_to_data( + nscd_cfg_param_desc_t *desc, + char *str, + void *data, + void **data_p, + nscd_cfg_error_t **errorp) +{ + + char *me = "_nscd_cfg_str_to_data"; + char *c; + nscd_cfg_bitmap_t bitmap; + char msg[NSCD_CFG_MAX_ERR_MSG_LEN]; + nscd_rc_t rc = NSCD_CFG_DATA_CONVERSION_FAILED; + + if (desc == NULL || str == NULL || data == NULL) { + _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR) + (me, "ERROR: one of the following is NULL " + "desc = %p, str = %p, data = %p, data_p = %p\n", + desc, str, data, data_p); + + return (NSCD_INVALID_ARGUMENT); + } + *data_p = data; + + /* if description is that of a group, return error */ + if (_nscd_cfg_flag_is_set(desc->pflag, NSCD_CFG_PFLAG_GROUP)) { + + (void) snprintf(msg, sizeof (msg), + gettext("single data specified for group %s"), desc->id.name); + + if (errorp != NULL) + *errorp = _nscd_cfg_make_error(NSCD_INVALID_ARGUMENT, + msg); + + _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR) + (me, "ERROR: %s)\n", msg); + + return (NSCD_INVALID_ARGUMENT); + + } + + if (desc->type == NSCD_CFG_DATA_STRING) { + if (strcmp(str, NSCD_NULL) == 0) + *(char **)data_p = NULL; + else { + /* remove the " char if quoted string */ + if (str[0] == '"') { + c = str + strlen(str) - 1; + if (*c == '"') + *c = '\0'; + *(char **)data_p = str + 1; + } else + *(char **)data_p = str; + + } + return (NSCD_SUCCESS); + } + + if (str == NULL) { + + (void) snprintf(msg, sizeof (msg), + gettext("data must be specified for %s"), desc->id.name); + + if (errorp != NULL) + *errorp = _nscd_cfg_make_error(NSCD_INVALID_ARGUMENT, + msg); + + _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR) + (me, "ERROR: %s\n", msg); + + return (NSCD_INVALID_ARGUMENT); + + } + + switch (desc->type) { + + case NSCD_CFG_DATA_BOOLEAN: + + if (strcasecmp(str, "yes") == 0) + *(nscd_bool_t *)data = nscd_true; + else if (strcasecmp(str, "no") == 0) + *(nscd_bool_t *)data = nscd_false; + else { + + (void) snprintf(msg, sizeof (msg), + gettext("data (%s) must be 'yes' or 'no' for %s"), + str, desc->id.name); + + if (errorp != NULL) + *errorp = _nscd_cfg_make_error(NSCD_INVALID_ARGUMENT, + msg); + + _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR) + (me, "ERROR: %s\n", msg); + + return (NSCD_INVALID_ARGUMENT); + } + + break; + + case NSCD_CFG_DATA_INTEGER: + + errno = 0; + *(int *)data = (int)strtol(str, (char **)NULL, 10); + if (errno != NULL) { + + (void) snprintf(msg, sizeof (msg), + gettext("unable to convert data (%s) for %s"), + str, desc->id.name); + + if (errorp != NULL) + *errorp = _nscd_cfg_make_error(rc, msg); + + _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR) + (me, "ERROR: %s\n", msg); + + return (rc); + } + + break; + + case NSCD_CFG_DATA_BITMAP: + + errno = 0; + bitmap = (nscd_cfg_bitmap_t)strtol(str, (char **)NULL, 10); + if (errno != NULL) { + + (void) snprintf(msg, sizeof (msg), + gettext("unable to convert data (%s) for %s"), + str, desc->id.name); + + if (errorp != NULL) + *errorp = _nscd_cfg_make_error(rc, msg); + + _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR) + (me, "ERROR: %s\n", msg); + + return (rc); + } + + _nscd_cfg_bitmap_set(data, bitmap); + + break; + + } + + return (NSCD_SUCCESS); +} + + +nscd_rc_t +_nscd_cfg_set( + nscd_cfg_handle_t *handle, + void *data, + nscd_cfg_error_t **errorp) +{ + char *me = "_nscd_cfg_set"; + int dlen; + nscd_cfg_id_t *nswdb; + nscd_cfg_param_desc_t *desc, *gdesc; + nscd_cfg_group_info_t *gi; + char *nswdb_name, *param_name; + void *pdata = NULL; + void *cfg_data, *vdata_addr = NULL; + nscd_bool_t get_group = 0; + nscd_bool_t in = nscd_true; + nscd_cfg_lock_t *lock = NULL; + nscd_rc_t rc = NSCD_SUCCESS; + + if (handle == NULL) { + _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR) + (me, "handle is NULL\n"); + return (NSCD_INVALID_ARGUMENT); + } + + nswdb = handle->nswdb; + desc = (nscd_cfg_param_desc_t *)handle->desc; + if (nswdb == NULL) + nswdb_name = "global"; + else + nswdb_name = nswdb->name; + param_name = desc->id.name; + + if (data == NULL && _nscd_cfg_flag_is_not_set(desc->pflag, + NSCD_CFG_PFLAG_VLEN_DATA)) { + _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR) + (me, "data == NULL\n"); + return (NSCD_INVALID_ARGUMENT); + } + + if (_nscd_cfg_flag_is_set(desc->pflag, + NSCD_CFG_PFLAG_UPDATE_SEND_WHOLE_GROUP) || + _nscd_cfg_flag_is_set(desc->pflag, NSCD_CFG_PFLAG_GROUP)) + get_group = nscd_true; + + /* + * locate the current value of the param or group + * and lock the config data for writing + */ + rc = _nscd_cfg_locate_cfg_data(&cfg_data, nscd_false, desc, + nswdb, get_group, &vdata_addr, &dlen, &lock); + if (rc != NSCD_SUCCESS) { + _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR) + (me, "unable to locate config data (rc = %d)\n", rc); + return (rc); + } + + if (_nscd_cfg_flag_is_set(desc->pflag, NSCD_CFG_PFLAG_GROUP) && + ((nscd_cfg_group_info_t *)cfg_data)->num_param != + ((nscd_cfg_group_info_t *)data)->num_param) { + + _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR) + (me, "number of parameters in group <%s : %s> not equal: " + "%d in input data, should be %d\n", + NSCD_STR_OR_GLOBAL(nswdb_name), + NSCD_STR_OR_NULL(param_name), + ((nscd_cfg_group_info_t *)data)->num_param, + ((nscd_cfg_group_info_t *)cfg_data)->num_param); + + rc = NSCD_INVALID_ARGUMENT; + goto error_exit; + } + + /* + * if variable length data, we want the address + * of the pointer pointing to the data + */ + if (vdata_addr != NULL) + cfg_data = vdata_addr; + + /* + * just copy in the specified data, if no need + * to verify the data or notify the associated + * component + */ + if (get_group == nscd_true) { + + gdesc = &_nscd_cfg_param_desc[desc->g_index]; + + rc = _nscd_cfg_copy_group_data_merge( + gdesc, &pdata, data, cfg_data, + desc->id.index, data); + + if (rc != NSCD_SUCCESS) { + _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR) + (me, "unable to copy group data <%s : %s>\n", + NSCD_STR_OR_GLOBAL(nswdb_name), + NSCD_STR_OR_NULL(param_name)); + + goto error_exit; + } + + rc = _nscd_cfg_notify_s(gdesc, nswdb, + pdata, errorp); + + } else + rc = _nscd_cfg_notify_s(desc, nswdb, data, + errorp); + + if (rc != NSCD_SUCCESS) { + + _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR) + (me, "verifying/notifying of new configuration " + "parameter <%s : %s> failed. %s\n", + NSCD_STR_OR_GLOBAL(nswdb_name), + param_name, (*errorp && (*errorp)->msg) ? + (*errorp)->msg : ""); + + goto error_exit; + } + + /* + * Move the new config into the config store + */ + rc = NSCD_CFG_SET_PARAM_FAILED; + if (_nscd_cfg_flag_is_set(desc->pflag, + NSCD_CFG_PFLAG_GROUP)) { + gi = _nscd_cfg_get_gi(pdata); + rc = _nscd_cfg_copy_group_data_in(gdesc, gi, + cfg_data, pdata); + } else { + /* + * nscd_true asks _nscd_cfg_copy_param_data to + * set addr of the vlen data in 'cfg_data' rather + * than copying the data content + */ + if (pdata != NULL) + _nscd_cfg_free_vlen_data_group(gdesc, + pdata, in); + + rc = _nscd_cfg_copy_param_data(desc, + cfg_data, data, in, nscd_true); + } + + if (rc != NSCD_SUCCESS) { + + _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR) + (me, "unable to make new param data <%s : %s> current\n", + NSCD_STR_OR_GLOBAL(nswdb_name), + NSCD_STR_OR_NULL(param_name)); + } + + error_exit: + + _nscd_cfg_unlock(lock); + + return (rc); +} + +nscd_rc_t +_nscd_cfg_set_linked( + nscd_cfg_handle_t *handle, + void *data, + nscd_cfg_error_t **errorp) +{ + char *me = "_nscd_cfg_set_linked"; + nscd_cfg_id_t *nswdb; + nscd_cfg_handle_t *hl; + nscd_cfg_param_desc_t *desc; + char *nswdb_name, *param_name, *dbl; + nscd_rc_t rc = NSCD_SUCCESS; + nscd_cfg_nsw_spc_default_t *spc; + int i; + char msg[NSCD_CFG_MAX_ERR_MSG_LEN]; + + if (handle == NULL) { + _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR) + (me, "handle is NULL\n"); + return (NSCD_INVALID_ARGUMENT); + } + + nswdb = handle->nswdb; + desc = (nscd_cfg_param_desc_t *)handle->desc; + + /* + * no need to do the special linking thing, + * if a global param, or a group, or not a linked param + */ + if (nswdb == NULL || _nscd_cfg_flag_is_set(desc->pflag, + NSCD_CFG_PFLAG_GROUP) || + _nscd_cfg_flag_is_not_set(desc->pflag, + NSCD_CFG_PFLAG_LINKED)) + return (_nscd_cfg_set(handle, data, errorp)); + else + nswdb_name = nswdb->name; + param_name = desc->id.name; + + /* + * if a param is linked to another, it can not be + * changed directly + */ + for (i = 0; i < _nscd_cfg_num_link_default; i++) { + + if (_nscd_cfg_nsw_link_default[i].data == NULL) + continue; + + if (strcmp(_nscd_cfg_nsw_link_default[i].db, + nswdb_name) == 0 && + _nscd_cfg_nsw_link_default[i].group_off == + desc->g_offset && + _nscd_cfg_nsw_link_default[i].param_off == + desc->p_offset) { + + rc = NSCD_CFG_READ_ONLY; + + (void) snprintf(msg, sizeof (msg), +gettext("vaule of \'%s\' not changeable, change that of \'%s\' instead"), + nswdb->name, "passwd"); + + if (errorp != NULL) + *errorp = _nscd_cfg_make_error(rc, msg); + + _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR) + (me, "ERROR: %s\n", msg); + + return (rc); + } + } + + /* + * if a param is linked from another, it should be verify + * and changed first + */ + for (i = 0; i < _nscd_cfg_num_link_default; i++) { + + if (_nscd_cfg_nsw_link_default[i].data == NULL) + continue; + + spc = _nscd_cfg_nsw_link_default[i].data; + + if (strcmp(spc->db, nswdb_name) == 0 && + spc->group_off == desc->g_offset && + spc->param_off == desc->p_offset) { + + rc = _nscd_cfg_set(handle, data, errorp); + if (rc != NSCD_SUCCESS) + return (rc); + break; + } + } + + /* + * then change all those linked to the one that has been changed + */ + for (i = 0; i < _nscd_cfg_num_link_default; i++) { + + if (_nscd_cfg_nsw_link_default[i].data == NULL) + continue; + + spc = _nscd_cfg_nsw_link_default[i].data; + + if (strcmp(spc->db, nswdb_name) == 0 && + spc->group_off == desc->g_offset && + spc->param_off == desc->p_offset && + _nscd_cfg_nsw_link_default[i].group_off == + desc->g_offset && + _nscd_cfg_nsw_link_default[i].param_off == + desc->p_offset) { + + dbl = _nscd_cfg_nsw_link_default[i].db; + + rc = _nscd_cfg_get_handle(param_name, dbl, + &hl, errorp); + rc = _nscd_cfg_set(hl, data, errorp); + _nscd_cfg_free_handle(hl); + if (rc != NSCD_SUCCESS) + return (rc); + } + } + + return (_nscd_cfg_set(handle, data, errorp)); +} + +/* + * Return a list of space-separated database names that + * have at least one of the input sources appeared in the + * configured nsswitch policy string of the databases. + * The return string should be freed by the caller. + * + * For compat sources (compat_group and compat_passwd), + * "group" will be returned, if the policy string for + * compat_group contains one of the input sources. Same + * for compat_passwd and passwd. + */ +char * +_nscd_srcs_in_db_nsw_policy( + int num_src, + char **srcs) +{ + uint8_t i, j, n = 0, nc = 0; + uint8_t compat_grp = 0, compat_pwd = 0; + uint8_t *db; + uint8_t *db_compat; + int dlen = 0; + nscd_cfg_nsw_db_data_t *dbcfg; + nscd_cfg_switch_t *sw; + char *outstr = NULL; + char *dbname; + + db = (uint8_t *)calloc(_nscd_cfg_num_nsw_db, sizeof (uint8_t)); + if (db == NULL) + return (NULL); + + db_compat = (uint8_t *)calloc(_nscd_cfg_num_nsw_db, + sizeof (uint8_t)); + if (db_compat == NULL) { + free(db); + return (NULL); + } + + for (i = 0; i < _nscd_cfg_num_nsw_db; i++) { + + (void) rw_rdlock(&nscd_cfg_nsw_db_data_rwlock[i]); + + dbcfg = &nscd_cfg_nsw_db_data_current[i]; + sw = &dbcfg->sw; + if (sw->nsw_config_string == NULL) + continue; + + dbname = _nscd_cfg_nsw_db[i].name; + for (j = 0; j < num_src; j++) { + if (strstr(sw->nsw_config_string, srcs[j]) != + NULL) { + db[n++] = i; + dlen += strlen(dbname) + 1; + } else if (strcmp(sw->nsw_config_string, + "compat") == 0) { + if (strcmp(dbname, "passwd") == 0) { + compat_pwd = 1; + dlen += 7; + } else if (strcmp(dbname, "group") == 0) { + compat_grp = 1; + dlen += 6; + } else { + db_compat[nc++] = i; + dlen += strlen(dbname) + 1; + + } + } + } + (void) rw_unlock(&nscd_cfg_nsw_db_data_rwlock[i]); + } + + if (dlen != NULL) + outstr = (char *)calloc(1, dlen); + if (outstr == NULL) { + free(db_compat); + free(db); + return (NULL); + } + + for (j = 0; j < n; j++) { + dbname = _nscd_cfg_nsw_db[db[j]].name; + if (strstr(dbname, "group_compat") != NULL) { + if (compat_grp == 1) + dbname = "group"; + else + continue; + } else if (strstr(dbname, "passwd_compat") != NULL) { + if (compat_pwd == 1) + dbname = "passwd"; + else + continue; + } + + (void) strlcat(outstr, dbname, dlen); + (void) strlcat(outstr, ",", dlen); + } + + for (j = 0; j < nc; j++) { + dbname = _nscd_cfg_nsw_db[db_compat[j]].name; + if (compat_pwd == 1) { + (void) strlcat(outstr, dbname, dlen); + (void) strlcat(outstr, " ", dlen); + } + } + + free(db); + free(db_compat); + return (outstr); + +} diff --git a/usr/src/cmd/nscd/nscd_config.h b/usr/src/cmd/nscd/nscd_config.h new file mode 100644 index 0000000000..44b3c9489f --- /dev/null +++ b/usr/src/cmd/nscd/nscd_config.h @@ -0,0 +1,653 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _NSCD_CONFIG_H +#define _NSCD_CONFIG_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + +#include <stdio.h> +#include "nscd_common.h" + +/* + * nscd_cfg_id_t is used to identify a config/stat + * object. 'index' provides a way to quickly locate + * the object in the associated configuration list. + * 'name' can be looked up in the config info database + * to obtain the index. + */ +typedef struct { + int index; + char *name; +} nscd_cfg_id_t; + +/* + * forward declaration of nscd_cfg_param_desc_t + */ +struct nscd_cfg_param_desc; + +/* + * for operations that apply to configuration data + * in all the nsswitch databases + */ +#define NSCD_CFG_NSW_ALLDB "ALLDB" +#define NSCD_CFG_NSW_ALLDB_INDEX 9999 + +/* + * configuration lists includes switch databases (eg. hosts, passwd), + * switch sources (eg. files, ldap), config parameter descriptions + * (defined below), and status/statistic counter descriptions (defined + * below) + */ +typedef struct { + int num; + nscd_cfg_id_t **list; +} nscd_cfg_list_t; + +/* + * type of configuration list + */ +typedef enum { + NSCD_CFG_LIST_NSW_DB = 0, + NSCD_CFG_LIST_NSW_SRC = 1, + NSCD_CFG_LIST_PARAM = 2, + NSCD_CFG_LIST_STAT = 3 +} nscd_cfg_list_type_t; + +/* + * A config handle identifies config or stat data, + * which if is nsswitch database specific, 'nswdb' + * indicates the id of the database; if global, + * 'nswdb' should be null. 'desc' is the config + * param or stat description assocaited with the + * data. + */ +typedef struct { + nscd_cfg_id_t *nswdb; + void *desc; + nscd_cfg_list_type_t type; +} nscd_cfg_handle_t; + +/* + * type of configuration/statistics data + */ +typedef enum { + NSCD_CFG_DATA_NONE = 0, + NSCD_CFG_DATA_INTEGER = 1, + NSCD_CFG_DATA_BOOLEAN = 2, + NSCD_CFG_DATA_STRING = 3, + NSCD_CFG_DATA_BITMAP = 4, + NSCD_CFG_DATA_PERCENT = 5 +} nscd_cfg_data_type_t; +#define NSCD_CFG_NUM_DATA_TYPE 5 + +/* + * data flag is attached to config/stat data passed between + * function to specify the nature/type of action to perform + */ + +#define NSCD_CFG_DFLAG_NONE 0x0000 + +/* + * data should not be freed by receiver; + * otherwise it should be freed + */ +#define NSCD_CFG_DFLAG_STATIC_DATA 0x0001 + +/* + * data is sent/received due to nscd initialization; + * otherwise due to modification of the config data + * requested by users + */ +#define NSCD_CFG_DFLAG_INIT 0x0002 + +/* + * the entire group of data is, or should be, sent; + * otherwise only a single parameter/stat value + */ +#define NSCD_CFG_DFLAG_GROUP 0x0004 + +/* + * the data sent/received is to be verified by the + * 'verify' function defined in the parameter + * description + */ +#define NSCD_CFG_DFLAG_VERIFY 0x0008 + +/* + * the data sent/received is to be processed by the + * 'notify' function defined in the parameter + * description + */ +#define NSCD_CFG_DFLAG_NOTIFY 0x0010 + +/* + * the data sent/received is to be applied to all + * nsswitch databases + */ +#define NSCD_CFG_DFLAG_SET_ALL_DB 0x0020 + +/* + * the entire group of data is sent/received; + * however, only those parameters selected by + * the bitmap in the group info should be + * processed + */ +#define NSCD_CFG_DFLAG_BIT_SELECTED 0x0040 + +/* + * param flag is defined in the parameter description. + * It specifies what operation should be applied to, or + * the nature of, the config parameters. + */ + +#define NSCD_CFG_PFLAG_NONE 0x0000 + +/* + * At init/refresh time, send the parameter value + * with the data of the entire group; otherwise + * send the parameter value only + */ +#define NSCD_CFG_PFLAG_INIT_SEND_WHOLE_GROUP 0x0001 + +/* + * At user requested update time, send the parameter + * value with the data of the entire group; otherwise + * send the parameter value only + */ +#define NSCD_CFG_PFLAG_UPDATE_SEND_WHOLE_GROUP 0x0002 + +/* + * At init/refresh time, send the config data + * once for each nsswitch database + */ +#define NSCD_CFG_PFLAG_INIT_SET_ALL_DB 0x0004 + +/* + * At user requested update time, send the per nsswitch + * database (non-global) data just one time (not once + * for each nsswitch database) + */ +#define NSCD_CFG_PFLAG_UPDATE_SEND_NON_GLOBAL_ONCE 0x0008 + +/* + * send entire group data, but use bitmap to indicate + * the one config parameter being processed. This flag + * can only be sepcified for a group description + */ +#define NSCD_CFG_PFLAG_SEND_BIT_SELECTED 0x0010 + +/* + * data is global, not per nsswitch database + */ +#define NSCD_CFG_PFLAG_GLOBAL 0x0020 + +/* + * data is group data, not individual parameter value + */ +#define NSCD_CFG_PFLAG_GROUP 0x0040 + +/* + * data is of variable length + */ +#define NSCD_CFG_PFLAG_VLEN_DATA 0x0080 + +/* + * data is hidden, for internal use only, get/set not allowed + */ +#define NSCD_CFG_PFLAG_HIDDEN 0x0100 + +/* + * data is linked, using the value of a different database + */ +#define NSCD_CFG_PFLAG_LINKED 0x0200 + +/* + * data is obsolete, ignored with warning, should not be displayed + */ +#define NSCD_CFG_PFLAG_OBSOLETE 0x0400 + +/* + * structure for error reporting + */ +typedef struct { + nscd_rc_t rc; + char *msg; +} nscd_cfg_error_t; + +/* + * typedef for flag, bitmap, and boolean + */ +typedef int nscd_cfg_flag_t; +typedef int nscd_cfg_bitmap_t; + +/* + * struct nscd_cfg_param_desc is used to describe each and + * every one of the nscd config parameters so that they can + * be processed generically by the configuration management + * component. During init or update time, config data needs + * to be pushed to other nscd components (frontend, switch + * engine, cache backend, and so on) for further processing. + * The 'verify' and 'notify' functions are the hooks provided + * by these other components to validate and store the new + * config data. The 'p_check' field, if specified, points + * to a set of data used for preliminary check of a parameter + * value (range, length, null checking etc). + */ +typedef struct nscd_cfg_param_desc { + nscd_cfg_id_t id; + nscd_cfg_data_type_t type; + nscd_cfg_flag_t pflag; + int p_size; + size_t p_offset; + int p_fn; + int g_size; + size_t g_offset; + int g_index; + void *p_check; + char *nfunc_name; + char *vfunc_name; + nscd_rc_t (*notify)(void *data, + struct nscd_cfg_param_desc *pdesc, + nscd_cfg_id_t *nswdb, + nscd_cfg_flag_t dflag, + nscd_cfg_error_t **errorp, + void *cookie); + nscd_rc_t (*verify)(void *data, + struct nscd_cfg_param_desc *pdesc, + nscd_cfg_id_t *nswdb, + nscd_cfg_flag_t dflag, + nscd_cfg_error_t **errorp, + void **cookie); +} nscd_cfg_param_desc_t; + +/* + * the _nscd_cfg_get_param_desc_list function returns + * the list of nscd config param descriptions at + * run time + */ +typedef struct { + int num; + nscd_cfg_param_desc_t **list; +} nscd_cfg_param_desc_list_t; + +/* this describes data of variable length */ +typedef struct { + void *ptr; + int len; +} nscd_cfg_vlen_data_t; + +/* + * The following defines the various global and nsswitch + * database specific data structures for all the groups of + * configuration parameters. Before each one, there lists + * the associated group info which contains the number of + * parameters and the corresponding bitmap. + */ + +typedef struct { + int num_param; + nscd_cfg_bitmap_t bitmap; +} nscd_cfg_group_info_t; +#define NSCD_CFG_GROUP_INFO_NULL {-1, 0x0000} + +/* + * frontend param group (Per nsswitch database) + */ +#define NSCD_CFG_GROUP_INFO_FRONTEND {1, 0x0001} +typedef struct { + nscd_cfg_group_info_t gi; + int worker_thread_per_nsw_db; +} nscd_cfg_frontend_t; + +/* + * switch engine param group (Per nsswitch database) + */ +#define NSCD_CFG_GROUP_INFO_SWITCH {7, 0x07f} +typedef struct { + nscd_cfg_group_info_t gi; + char *nsw_config_string; + char *nsw_config_db; + nscd_bool_t enable_lookup; + nscd_bool_t enable_loopback_checking; + int max_nsw_state_per_db; + int max_nsw_state_per_thread; + int max_getent_ctx_per_db; +} nscd_cfg_switch_t; + +/* + * log/debug param group (global) + */ +#define NSCD_CFG_GROUP_INFO_GLOBAL_LOG {3, 0x0007} +typedef struct { + nscd_cfg_group_info_t gi; + char *logfile; + int debug_level; + int debug_comp; +} nscd_cfg_global_log_t; + +/* + * frontend param group (global) + */ +#define NSCD_CFG_GROUP_INFO_GLOBAL_FRONTEND {2, 0x0003} +typedef struct { + nscd_cfg_group_info_t gi; + int common_worker_threads; + int cache_hit_threads; +} nscd_cfg_global_frontend_t; + +/* + * self credential param group (global) + */ +#define NSCD_CFG_GROUP_INFO_GLOBAL_SELFCRED {3, 0x0007} +typedef struct { + nscd_cfg_group_info_t gi; + nscd_bool_t enable_selfcred; + int max_per_user_nscd; + int per_user_nscd_ttl; +} nscd_cfg_global_selfcred_t; + +/* + * switch engine param group (global) + */ +#define NSCD_CFG_GROUP_INFO_GLOBAL_SWITCH {3, 0x0007} +typedef struct { + nscd_cfg_group_info_t gi; + nscd_bool_t enable_lookup_g; + nscd_bool_t enable_loopback_checking_g; + int check_smf_state_interval_g; +} nscd_cfg_global_switch_t; + +/* + * nscd_cfg_param_desc_t should always have nscd_cfg_id_t + * as its first field. _nscd_cfg_get_desc below provides + * an way to get to the nscd_cfg_param_desc_t from a + * pointer to the static nscd_cfg_id_t returned by the + * various_nscd_cfg_* functions + */ +#define _nscd_cfg_get_desc_i(id) ((nscd_cfg_param_desc_t *)(id)) + +#define _nscd_cfg_get_desc(h) ((h)->desc) + +/* + * The various param group structure should always have + * nscd_cfg_group_info_t as its first field. + * _nscd_cfg_get_gi below provides a generic way to + * get to the nscd_cfg_group_info_t from a void pointer + * to the various param group structure returned by the + * _nscd_cfg_* functions + */ +#define _nscd_cfg_get_gi(voidp) ((nscd_cfg_group_info_t *)(voidp)) + +/* + * It is possible in the future, we will need more bits + * than those in nscd_cfg_flag_t and nscd_cfg_bitmap_t. To + * make it easier to extend, the following macro should be + * used to deal with flags and bitmaps. + * m, m1, m2, ma: mask, n: nth bit (0 based) + * f: flag, v: value + */ +#define NSCD_CFG_BITMAP_ZERO 0 +#define _nscd_cfg_bitmap_is_set(m, n) (((m) >> n) & 1) +#define _nscd_cfg_bitmap_is_not_set(m, n) (!(((m) >> n) & 1)) +#define _nscd_cfg_bitmap_is_equal(m1, m2) ((m1) == (m2)) +#define _nscd_cfg_bitmap_value(m) (m) +#define _nscd_cfg_bitmap_set_nth(m, n) ((m) |= (1 << n)) +#define _nscd_cfg_bitmap_set(ma, m) (*(nscd_cfg_bitmap_t *) \ + (ma) = (m)) +#define _nscd_cfg_bitmap_valid(m1, m2) (((m1) & ~(m2)) == 0) + +#define NSCD_CFG_FLAG_ZERO 0 +#define _nscd_cfg_flag_is_set(f, v) ((f) & (v)) +#define _nscd_cfg_flag_is_not_set(f, v) (!((f) & (v))) +#define _nscd_cfg_flag_value(f) (f) +#define _nscd_cfg_flag_set(f, v) ((f) | (v)) +#define _nscd_cfg_flag_unset(f, v) ((f) & ~(v)) + +/* + * handy macros + */ +#define NSCD_NULL "NULL" +#define NSCD_CFG_MAX_ERR_MSG_LEN 1024 +#define NSCD_STR_OR_NULL(s) ((s) == NULL ? "NULL" : (s)) +#define NSCD_STR_OR_GLOBAL(s) ((s) == NULL ? "GLOBAL" : (s)) +#define NSCD_Y_OR_N(s) (*(nscd_bool_t *)s == nscd_true ? \ + "yes" : "no") + +#define NSCD_ERR2MSG(e) (((e) && (e)->msg) ? (e)->msg : "") + + +/* + * This macro is based on offsetof defined in stddef_iso.h, + * it gives the size of 'm' in structure 's' without needing + * the declaration of a 's' variable (as macro sizeof does) + */ +#define NSCD_SIZEOF(s, m) (sizeof (((s *)0)->m)) + + +/* + * struct nscd_cfg_stat_desc is used to describe each and every + * one of the nscd statistics counters so that they can be + * processed generically by the configuration management + * component. The component does not keep a separate copy of + * all counters, which should be maintained by other nscd + * components. The 'get_stat' functions defined in the + * stat description are supplied by those components and used + * by the config management component to request and print + * counters on behave of the users. The free_stat function + * returned by those components will also be used to free + * the stat data if the NSCD_CFG_DFLAG_STATIC_DATA bit is + * not set in dflag. + */ +typedef struct nscd_cfg_stat_desc { + nscd_cfg_id_t id; + nscd_cfg_data_type_t type; + nscd_cfg_flag_t sflag; + nscd_cfg_group_info_t gi; + int s_size; + size_t s_offset; + int s_fn; + int g_size; + size_t g_offset; + int g_index; + char *gsfunc_name; + nscd_rc_t (*get_stat)(void **stat, + struct nscd_cfg_stat_desc *sdesc, + nscd_cfg_id_t *nswdb, + nscd_cfg_flag_t *dflag, + void (**free_stat) + (void *stat), + nscd_cfg_error_t **errorp); +} nscd_cfg_stat_desc_t; + +/* + * stat flag is defined in the stat description. It + * specifies the nature of the statistics counters. + */ + +#define NSCD_CFG_SFLAG_NONE 0x0000 + +/* + * statistics counter is global, not per nsswitch database + */ +#define NSCD_CFG_SFLAG_GLOBAL 0x0001 + +/* + * description is for counter group, not individual counter + */ +#define NSCD_CFG_SFLAG_GROUP 0x0002 + +/* + * The following defines the various global and nsswitch + * database specific data structures for all the groups of + * statistics counters. Before each one, there lists + * the associated group info which contains the number of + * counters and the corresponding bitmap. + */ + +/* + * switch engine stat group (Per nsswitch database) + */ +#define NSCD_CFG_STAT_GROUP_INFO_SWITCH {6, 0x003f} +typedef struct { + nscd_cfg_group_info_t gi; + int lookup_request_received; + int lookup_request_queued; + int lookup_request_in_progress; + int lookup_request_succeeded; + int lookup_request_failed; + int loopback_nsw_db_skipped; +} nscd_cfg_stat_switch_t; + +/* + * log/debug stat group (global) + */ +#define NSCD_CFG_STAT_GROUP_INFO_GLOBAL_LOG {1, 0x0001} +typedef struct { + nscd_cfg_group_info_t gi; + int entries_logged; +} nscd_cfg_stat_global_log_t; + +/* + * switch engine stat group (global) + */ +#define NSCD_CFG_STAT_GROUP_INFO_GLOBAL_SWITCH {6, 0x003f} +typedef struct { + nscd_cfg_group_info_t gi; + int lookup_request_received_g; + int lookup_request_queued_g; + int lookup_request_in_progress_g; + int lookup_request_succeeded_g; + int lookup_request_failed_g; + int loopback_nsw_db_skipped_g; +} nscd_cfg_stat_global_switch_t; + +/* + * control structure for appending string data to a buffer + */ +typedef struct { + char *buf; + char *next; + int size; + int used; + int left; + int real; +} nscd_cfg_buf_t; + +/* + * internal configuration management related functions + */ +nscd_rc_t _nscd_cfg_init(); + +nscd_rc_t +_nscd_cfg_get_param_desc_list( + nscd_cfg_param_desc_list_t **list); + +nscd_rc_t +_nscd_cfg_get_handle( + char *param_name, + char *nswdb_name, + nscd_cfg_handle_t **handle, + nscd_cfg_error_t **errorp); + +nscd_cfg_error_t * +_nscd_cfg_make_error( + nscd_rc_t rc, + char *msg); + +void +_nscd_cfg_free_handle( + nscd_cfg_handle_t *handle); + +void +_nscd_cfg_free_group_data( + nscd_cfg_handle_t *handle, + void *data); + +void +_nscd_cfg_free_param_data( + void *data); + +void +_nscd_cfg_free_error( + nscd_cfg_error_t *error); + +nscd_rc_t +_nscd_cfg_get( + nscd_cfg_handle_t *handle, + void **data, + int *data_len, + nscd_cfg_error_t **errorp); + +nscd_rc_t +_nscd_cfg_set( + nscd_cfg_handle_t *handle, + void *data, + nscd_cfg_error_t **errorp); + +nscd_rc_t +_nscd_cfg_str_to_data( + nscd_cfg_param_desc_t *desc, + char *str, + void *data, + void **data_p, + nscd_cfg_error_t **errorp); + +nscd_rc_t +_nscd_cfg_prelim_check( + nscd_cfg_param_desc_t *desc, + void *data, + nscd_cfg_error_t **errorp); + +nscd_rc_t +_nscd_cfg_read_file( + char *filename, + nscd_cfg_error_t **errorp); + +nscd_rc_t +_nscd_cfg_set_linked( + nscd_cfg_handle_t *handle, + void *data, + nscd_cfg_error_t **errorp); + +char * +_nscd_srcs_in_db_nsw_policy( + int num_src, + char **srcs); + +nscd_rc_t +_nscd_cfg_read_nsswitch_file( + char *filename, + nscd_cfg_error_t **errorp); + +#ifdef __cplusplus +} +#endif + +#endif /* _NSCD_CONFIG_H */ diff --git a/usr/src/cmd/nscd/nscd_db.h b/usr/src/cmd/nscd/nscd_db.h new file mode 100644 index 0000000000..7186f0d0dd --- /dev/null +++ b/usr/src/cmd/nscd/nscd_db.h @@ -0,0 +1,253 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _NSCD_DB_H +#define _NSCD_DB_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + +#include <nss_dbdefs.h> /* nssuint_t */ +#include "nscd_common.h" + +/* make a pointer 8-byte aligned, or an integer a multiple of 8 */ +#define roundup(x) (((unsigned long)(x)+7) & ~7) + +/* + * type of nscd data + */ +#define NSCD_DATA_UNKNOWN 0 +#define NSCD_DATA_NSW_CONFIG 1 +#define NSCD_DATA_NSW_STATE_BASE 2 +#define NSCD_DATA_GETENT_CTX_BASE 3 +#define NSCD_DATA_BACKEND_INFO 4 +#define NSCD_DATA_BACKEND_INFO_DB 5 +#define NSCD_DATA_CFG_NSW_DB_INDEX 6 +#define NSCD_DATA_CFG_NSW_SRC_INDEX 7 +#define NSCD_DATA_CFG_PARAM_INDEX 8 +#define NSCD_DATA_CFG_STAT_INDEX 9 +#define NSCD_DATA_ADDR 127 +#define NSCD_DATA_CTX_ADDR 128 + +/* + * database operation options + */ +typedef enum { + NSCD_GET_FIRST_DB_ENTRY = 1, + NSCD_GET_NEXT_DB_ENTRY = 2, + NSCD_GET_EXACT_DB_ENTRY = 3, + NSCD_ADD_DB_ENTRY_FIRST = 4, + NSCD_ADD_DB_ENTRY_LAST = 5, + NSCD_ADD_DB_ENTRY_REPLACE = 6, + NSCD_ADD_DB_ENTRY_IF_NONE = 7, + NSCD_DEL_FIRST_DB_ENTRY = 8, + NSCD_DEL_ALL_DB_ENTRY = 9, + NSCD_DEL_EXACT_DB_ENTRY = 10 +} nscd_db_option_t; + +/* + * This structure defines an instance of the + * nscd database entry. + */ +typedef struct nscd_db_entry { + int type; + int id_num; + int num_data; + int num_array; + char *name; + void **data_array; +} nscd_db_entry_t; + +/* + * sequence number attached to nscd data + */ +typedef nssuint_t nscd_seq_num_t; +typedef nssuint_t nscd_cookie_t; + +/* + * The nscd_access_s datatype represents a nscd + * access data structure. It is an opaque structure. + */ +struct nscd_access_s; +typedef struct nscd_access_s nscd_access_t; +struct nscd_acc_data_s; +typedef struct nscd_acc_data_s nscd_acc_data_t; + +/* + * The nscd_db_t datatype represents a nscd + * database. It is also an opaque structure. + */ +struct nscd_db_s; +typedef struct nscd_db_s nscd_db_t; + +/* + * four sizes for a nscd database: + * large, medium, small, tiny + */ +#define NSCD_DB_SIZE_LARGE 1 +#define NSCD_DB_SIZE_MEDIUM 2 +#define NSCD_DB_SIZE_SMALL 3 +#define NSCD_DB_SIZE_TINY 4 + +/* + * options for _nscd_alloc() + */ +#define NSCD_ALLOC_MUTEX 0x0001 +#define NSCD_ALLOC_RWLOCK 0x0002 +#define NSCD_ALLOC_COND 0x0004 + +/* + * prototypes + */ +nscd_seq_num_t +_nscd_get_seq_num(); + +nscd_cookie_t +_nscd_get_cookie(); + +nscd_acc_data_t * +_nscd_get( + nscd_acc_data_t *data); + +nscd_acc_data_t +*_nscd_set( + nscd_acc_data_t *old, + nscd_acc_data_t *new); + +void +_nscd_release( + nscd_acc_data_t *data); + +nscd_acc_data_t +*_nscd_rdlock( + nscd_acc_data_t *data); + +nscd_acc_data_t +*_nscd_wrlock( + nscd_acc_data_t *data); + +void +_nscd_rw_unlock( + nscd_acc_data_t *data); + +void +_nscd_rw_unlock_no_release( + nscd_acc_data_t *data); + +nscd_acc_data_t +*_nscd_mutex_lock( + nscd_acc_data_t *data); + +void +_nscd_mutex_unlock( + nscd_acc_data_t *data); + +void +_nscd_cond_signal( + nscd_acc_data_t *data); + +void +_nscd_cond_wait( + nscd_acc_data_t *data, + cond_t *cond); + +nscd_acc_data_t * +_nscd_alloc( + int type, + size_t size, + void (*data_free)( + nscd_acc_data_t *data), + int option); + +nscd_rc_t +_nscd_add_int_addr( + void *ptr, + int type, + nscd_seq_num_t seq_num); + +rwlock_t * +_nscd_is_int_addr( + void *ptr, + nscd_seq_num_t seq_num); + +void +_nscd_del_int_addr( + void *ptr, + nscd_seq_num_t seq_num); + +nscd_db_t * +_nscd_alloc_db( + int size); + +void +_nscd_free_db( + nscd_db_t *db); + +nscd_db_entry_t * +_nscd_alloc_db_entry( + int type, + const char *name, + int dataSize, + int num_data, + int num_array); + +const nscd_db_entry_t * +_nscd_get_db_entry( + const nscd_db_t *db, + int type, + const char *str, + nscd_db_option_t option, + int id_num); + +nscd_rc_t +_nscd_add_db_entry( + nscd_db_t *db, + const char *str, + nscd_db_entry_t *entry, + nscd_db_option_t option); + +nscd_rc_t +_nscd_delete_db_entry( + nscd_db_t *db, + int type, + const char *str, + nscd_db_option_t option, + int id_num); + + +void * +_nscd_create_int_addrDB(); + +void +_nscd_destroy_int_addrDB(); + +#ifdef __cplusplus +} +#endif + +#endif /* _NSCD_DB_H */ diff --git a/usr/src/cmd/nscd/nscd_dbimpl.c b/usr/src/cmd/nscd/nscd_dbimpl.c new file mode 100644 index 0000000000..822b4b6aba --- /dev/null +++ b/usr/src/cmd/nscd/nscd_dbimpl.c @@ -0,0 +1,617 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include "nscd_db.h" + +/* + * This file implements the database functionality used by the + * switch and configuration components. The implementation is + * based on hash and has table. If the need arises in the future, + * the code in this file can be changed to use other algorithms. + * The following lists the functions implemented: + * + * _nscd_add_db_entry + * _nscd_delete_db_entry + * _nscd_get_db_entry + * _nscd_alloc_db + * _nscd_free_db + * _nscd_walk_db + * _nscd_delete_db_entry_cookie + */ + +/* + * This structure defines an instance of the hash entry + * which implements the nscd database entry. The + * db_entry field should always be the first one in + * the structure. + */ +typedef struct nscd_hash { + nscd_db_entry_t db_entry; + struct nscd_hash *next_p; + struct nscd_hash *prev_p; +} nscd_hash_t; + +/* + * This structure defines a nscd database which + * is implemented as an array of nscd_hash_t. + */ +struct nscd_db_s { + int array_size; /* number of elements in hash_tbl_p */ + nscd_hash_t **hash_tbl_p; +}; + +/* + * This cookie structure is used to iterate through the + * database entries contained in a nscd database. + */ +struct cookie { + int idx; /* the current bucket */ + nscd_hash_t *hash; /* the current hash entry */ + nscd_db_t *db; /* the database */ +}; + +/* + * FUNCTION: calc_hash + * + * Calculate a hash for a string based on the elf_hash + * algorithm, hash is case insensitive. Uses tolower + * instead of _tolower because of I18N. + */ +static unsigned long +calc_hash( + const char *str) +{ + unsigned int hval = 0; + char ch; + + while (*str != NULL) { + unsigned int g; + + ch = (char)*str++; + if (isupper(ch)) + ch = _tolower(ch); + hval = (hval << 4) + ch; + if ((g = (hval & 0xf0000000)) != 0) + hval ^= g >> 24; + hval &= ~g; + } + return ((unsigned long)hval); +} + +/* + * FUNCTION: scan_hash + * + * Scan a hash table for a matching hash entry. Assume 'str' is + * not NULL. If option is NSCD_GET_NEXT_DB_ENTRY and id_num + * is less than zero, then treats the option as NSCD_GET_FIRST_DB_ENTRY. + */ + +static const nscd_hash_t * +scan_hash( + int type, + const char *str, + const nscd_hash_t *idx_p, + nscd_db_option_t option, + int id_num) +{ + int id_matched = 0; + nscd_db_entry_t *db_entry; + + while (idx_p != NULL) { + db_entry = &((nscd_hash_t *)idx_p)->db_entry; + if (db_entry->type == type) { + if (strcasecmp(str, db_entry->name) == 0) { + switch (option) { + case NSCD_GET_FIRST_DB_ENTRY: + return (idx_p); + case NSCD_GET_EXACT_DB_ENTRY: + if (id_num == db_entry->id_num) + return (idx_p); + break; + case NSCD_GET_NEXT_DB_ENTRY: + if (id_num < 0) + return (idx_p); + if (id_matched == 1) + return (idx_p); + if (id_num == db_entry->id_num) + id_matched = 1; + break; + } + } + } + idx_p = idx_p->next_p; + } + return (NULL); +} + +/* + * FUNCTION: _nscd_get_db_entry + * + * Find a nscd database entry from a nscd database. + */ +const nscd_db_entry_t * +_nscd_get_db_entry( + const nscd_db_t *db, + int type, + const char *str, + nscd_db_option_t option, + int id_num) +{ + unsigned long hash; + const nscd_hash_t *idx_p, *hash_p; + + if (db == NULL || str == NULL) + return (NULL); + + hash = calc_hash(str); + idx_p = db->hash_tbl_p[hash % db->array_size]; + + hash_p = scan_hash(type, str, idx_p, option, id_num); + + return (&hash_p->db_entry); +} + +/* + * FUNCTION: _nscd_add_db_entry + * + * Add a nscd database entry to a nscd database. This function + * is not MT safe. The caller should lock the database to + * prevent concurrent updates done by other threads. + */ +nscd_rc_t +_nscd_add_db_entry( + nscd_db_t *db, + const char *str, + nscd_db_entry_t *entry, + nscd_db_option_t option) +{ + int i; + unsigned long hash; + nscd_hash_t *next_p = NULL, *prev_p = NULL; + nscd_hash_t *idx_p, *hash_entry; + nscd_db_entry_t *db_entry; + + /* find the bucket */ + hash = calc_hash(str); + i = hash % db->array_size; + idx_p = db->hash_tbl_p[i]; + + /* can not replace nothing */ + if (idx_p == NULL) + if (option == NSCD_ADD_DB_ENTRY_REPLACE) + return (NSCD_DB_ENTRY_NOT_FOUND); + + while (idx_p != NULL) { + db_entry = &idx_p->db_entry; + switch (option) { + + case NSCD_ADD_DB_ENTRY_FIRST: + next_p = idx_p; + goto add_entry; + + case NSCD_ADD_DB_ENTRY_REPLACE: + if (db_entry->type != entry->type) + goto cont; + if (strcasecmp(db_entry->name, str) != 0) + goto cont; + + if (db_entry->id_num == entry->id_num) { + prev_p = idx_p->prev_p; + next_p = idx_p->next_p; + free(idx_p); + goto add_entry; + } + goto cont; + + case NSCD_ADD_DB_ENTRY_IF_NONE: + if (db_entry->type != entry->type) + break; + if (strcasecmp(db_entry->name, str) != 0) + break; + return (NSCD_DB_ENTRY_FOUND); + } + + if (idx_p->next_p == NULL) { + if (option == NSCD_ADD_DB_ENTRY_LAST || + option == NSCD_ADD_DB_ENTRY_IF_NONE) { + prev_p = idx_p; + goto add_entry; + } + } + + cont: + idx_p = idx_p->next_p; + } + + add_entry: + + /* + * the nscd_entry_t field should be the first field + * in a nscd_hash_t + */ + hash_entry = (nscd_hash_t *)entry; + + /* update the prev link list */ + hash_entry->prev_p = prev_p; + if (prev_p == NULL) + db->hash_tbl_p[i] = hash_entry; + else + prev_p->next_p = hash_entry; + + /* update the next link list */ + hash_entry->next_p = next_p; + if (next_p != NULL) + next_p->prev_p = hash_entry; + + return (NSCD_SUCCESS); +} + +/* + * FUNCTION: _nscd_delete_db_entry + * + * Delete a nscd database entry from a nscd database. This + * function is not MT safe. The caller should lock the + * database to prevent concurrent updates done by other + * threads. + */ +nscd_rc_t +_nscd_delete_db_entry( + nscd_db_t *db, + int type, + const char *str, + nscd_db_option_t option, + int id_num) +{ + int i; + int del_more = 0; + unsigned long hash; + nscd_hash_t *idx_p, *next_p = NULL, *prev_p = NULL; + nscd_db_entry_t *db_entry; + + /* find the bucket */ + hash = calc_hash(str); + i = hash % db->array_size; + idx_p = db->hash_tbl_p[i]; + + /* delete nothing always works */ + if (idx_p == NULL) + return (NSCD_SUCCESS); + + while (idx_p != NULL) { + db_entry = &idx_p->db_entry; + if (db_entry->type != type) + goto cont; + if (strcasecmp(db_entry->name, str) != 0) + goto cont; + + switch (option) { + + case NSCD_DEL_FIRST_DB_ENTRY: + prev_p = idx_p->prev_p; + next_p = idx_p->next_p; + del_more = 0; + break; + + case NSCD_DEL_EXACT_DB_ENTRY: + if (db_entry->id_num == id_num) { + prev_p = idx_p->prev_p; + next_p = idx_p->next_p; + del_more = 0; + } else + goto cont; + break; + + case NSCD_DEL_ALL_DB_ENTRY: + prev_p = idx_p->prev_p; + next_p = idx_p->next_p; + break; + } + + if (prev_p == NULL) + db->hash_tbl_p[i] = next_p; + else + prev_p->next_p = next_p; + + if (next_p != NULL) + next_p->prev_p = prev_p; + + free(idx_p); + + if (del_more == 0) + break; + /* + * only when option == NSCD_DEL_ALL_DB_ENTRY + * will we get here. next_p should be set to + * idx_p->next_p beforehand + */ + idx_p = next_p; + continue; + + cont: + + idx_p = idx_p->next_p; + } + + return (NSCD_SUCCESS); +} + +/* + * FUNCTION: _nscd_alloc_db_entry + * + * Allocate and return the memory for a database entry + * so the caller can insert data and then add it to the + * database. + */ +nscd_db_entry_t * +_nscd_alloc_db_entry( + int type, + const char *name, + int dataSize, + int num_data, + int num_array) +{ + int size; + int array_o, data_o; + nscd_hash_t *hash; + void *p; + + /* first part: hash data structure and name string */ + size = sizeof (*hash) + strlen(name) + 1; + array_o = size = roundup(size); + + /* second part: pointer array to data */ + size += (num_data + num_array) * sizeof (void **); + size = roundup(size); + + /* third part: actual data */ + data_o = size; + size += dataSize; + + /* allocate the memory */ + hash = (nscd_hash_t *)calloc(1, size); + + if (hash == NULL) + return (NULL); + + /* init the entry based on caller's input */ + hash->db_entry.num_data = num_data; + hash->db_entry.num_array = num_array; + hash->db_entry.type = type; + hash->db_entry.name = (char *)hash + sizeof (*hash); + p = (char *)hash + array_o; + hash->db_entry.data_array = (void **)p; + *(hash->db_entry.data_array) = (char *)hash + data_o; + (void) strcpy(hash->db_entry.name, name); + + return (&hash->db_entry); +} + +/* + * FUNCTION: _nscd_delete_db_entry_cookie + * + * Delete a database entry using the information from + * the input 'cookie'. + */ +void +_nscd_delete_db_entry_cookie( + nscd_db_t *db, + void **cookie) +{ + nscd_hash_t *hp; + struct cookie *c; + + /* snaity check */ + if (cookie == NULL || *cookie == NULL || db == NULL) + return; + c = *cookie; + + /* more snaity check */ + if (db != c->db || c->hash == NULL || + c->idx < 0 || c->idx >= db->array_size) + return; + + /* retrieve the hash entry from the cookie */ + hp = c->hash; + + /* + * Update the next/previous link list. + * Need to update c->hash as well, in case + * the cookie is also used in a walk-db + * loop. This is to make sure that the + * next _nscd_walk_db() call will + * find the (updated) next hash entry in line. + */ + if (hp->prev_p == NULL) { + /* + * make sure the current bucket will be + * walked again if _nscd_walk_db is + * called next + */ + c->hash = NULL; + db->hash_tbl_p[c->idx] = hp->next_p; + c->idx--; + + } else { + c->hash = hp->prev_p; + hp->prev_p->next_p = hp->next_p; + } + if (hp->next_p != NULL) + hp->next_p->prev_p = hp->prev_p; + + /* delete the entry */ + free(hp); +} + +/* + * FUNCTION: _nscd_alloc_db + * + * Allocate the space for a nscd database. + * + * The input argument, size, indicates the size of the database. + * NSCD_DB_SIZE_LARGE specifies an bucket array of size 67, + * NSCD_DB_SIZE_MEDIUM specifies an bucket array of size 37, + * NSCD_DB_SIZE_SMALL specifies an bucket array of size 13, + * NSCD_DB_SIZE_TINY specifies an bucket array of size 3. + */ +nscd_db_t * +_nscd_alloc_db( + int size) +{ + int sz; + nscd_db_t *db; + + /* allocate the database */ + db = (nscd_db_t *)calloc(1, sizeof (nscd_db_t)); + if (db == NULL) + return (NULL); + + /* allocate the bucket array */ + if (size == NSCD_DB_SIZE_LARGE) + sz = 67; + else if (size == NSCD_DB_SIZE_MEDIUM) + sz = 37; + else if (size == NSCD_DB_SIZE_SMALL) + sz = 13; + else if (size == NSCD_DB_SIZE_TINY) + sz = 3; + db->hash_tbl_p = (nscd_hash_t **)calloc(sz + 1, + sizeof (nscd_hash_t *)); + if (db->hash_tbl_p == NULL) { + free(db); + return (NULL); + } + + db->array_size = sz; + + return (db); +} + +/* + * FUNCTION: _nscd_free_db + * + * Delete a nscd database. + */ +void +_nscd_free_db( + nscd_db_t *db) +{ + int i; + nscd_hash_t *hp, *next_p; + + /* + * find non-empty buckets and for each one of them, + * delete all the database entries in it's link list + */ + for (i = 0; i < db->array_size; i++) { + + hp = db->hash_tbl_p[i]; + + while (hp != NULL) { + next_p = hp->next_p; + free(hp); + hp = next_p; + } + } + + /* free the bucket array */ + free(db->hash_tbl_p); + + free(db); +} + +/* + * FUNCTION: _nscd_walk_db + * + * Iterate through the database entries contained in + * a nscd database and return one entry at a time. + * The cookie structure is used to indicate the + * location of the returned entry for the next call + * to this function. For the very first call, *cookie + * should be set to NULL. For subsequent calls, the one + * returned by the previous call sould be used. + */ +nscd_db_entry_t * +_nscd_walk_db( + nscd_db_t *db, + void **cookie) +{ + struct cookie *c; + + /* sanity check */ + if (cookie == NULL || db == NULL) + return (NULL); + + if (*cookie != NULL) { + + c = *cookie; + + /* + * More sanity check. _nscd_delete_db_entry_cookie() + * could change c->idx to -1. + */ + if (db != c->db || + c->idx < -1 || c->idx >= db->array_size) + return (NULL); + + /* is there a next entry ? */ + if (c->hash != NULL) + c->hash = c->hash->next_p; + + /* yes, return it */ + if (c->hash != NULL) { + return (&c->hash->db_entry); + } + } else { + c = (struct cookie *)calloc(1, sizeof (*c)); + if (c == NULL) + return (NULL); + c->idx = -1; + c->hash = NULL; + c->db = db; + } + + /* find the first non-empty bucket */ + for (c->idx++; c->idx < db->array_size; c->idx++) { + c->hash = db->hash_tbl_p[c->idx]; + if (c->hash != NULL) + break; + } + + /* no (more) non-empty bucket, we are done */ + if (c->hash == NULL) { + free(c); + *cookie = NULL; + return (NULL); + } + + *cookie = c; + return (&c->hash->db_entry); +} diff --git a/usr/src/cmd/nscd/nscd_door.c b/usr/src/cmd/nscd/nscd_door.c new file mode 100644 index 0000000000..87640baf02 --- /dev/null +++ b/usr/src/cmd/nscd/nscd_door.c @@ -0,0 +1,353 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/param.h> +#include <string.h> +#include <door.h> +#include <sys/mman.h> +#include "nscd_door.h" +#include "nscd_log.h" +#include <getxby_door.h> +#include <sys/types.h> +#include <errno.h> +#include <fcntl.h> + +static void +initdoor(void *buf, int *doorfd) +{ + nss_pheader_t *phdr = (nss_pheader_t *)buf; + door_info_t doori; + char *me = "initdoor"; + + *doorfd = open64(NAME_SERVICE_DOOR, O_RDONLY, 0); + + _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG) + (me, "door is %s (fd is %d)\n", NAME_SERVICE_DOOR, + *doorfd); + + if (*doorfd == -1) + NSCD_RETURN_STATUS(phdr, NSS_ERROR, errno); + + if (door_info(*doorfd, &doori) < 0 || + (doori.di_attributes & DOOR_REVOKED) || + doori.di_data != (uintptr_t)NAME_SERVICE_DOOR_COOKIE) { + + /* + * we should close doorfd because we just opened it + */ + (void) close(*doorfd); + + _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG) + (me, "door %d not valid\n", *doorfd); + + NSCD_RETURN_STATUS(phdr, NSS_ERROR, ECONNREFUSED); + } + + NSCD_RETURN_STATUS_SUCCESS(phdr); +} + +/* general door call functions used by nscd */ + +static nss_status_t +copy_output(void *outdata, int outdlen, + nss_pheader_t *phdr, nss_pheader_t *outphdr) +{ + void *dp; + nss_status_t ret = NSS_SUCCESS; + char *me = "copy_output"; + + if (outdata != NULL && phdr->data_off > 0 && phdr->data_len > 0) { + if (phdr->data_len <= outdlen) { + dp = (char *)phdr + phdr->data_off; + (void) memmove(outdata, dp, phdr->data_len); + } else { + + _NSCD_LOG(NSCD_LOG_FRONT_END, + NSCD_LOG_LEVEL_DEBUG) + (me, "output buffer not large enough " + " should be > %d but is %d\n", + phdr->data_len, outdlen); + + if (outphdr != NULL) { + NSCD_SET_N2N_STATUS(phdr, NSS_NSCD_PRIV, + 0, NSCD_INVALID_ARGUMENT); + NSCD_COPY_STATUS(outphdr, phdr); + } + ret = NSS_NSCD_PRIV; + } + } + + return (ret); +} + + +nss_status_t +_nscd_doorcall(int callnum) +{ + nss_pheader_t phdr; + void *dptr; + size_t ndata; + size_t adata; + int ret; + char *me = "_nscd_doorcall"; + + _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG) + (me, "processing door call %d ...\n", callnum); + + phdr.nsc_callnumber = callnum; + ndata = sizeof (phdr); + adata = sizeof (phdr); + dptr = (void *)&phdr; + ret = _nsc_trydoorcall(&dptr, &ndata, &adata); + + if (ret != NSS_SUCCESS) { + _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG) + (me, "door call (%d) failed (status = %d, error = %s)\n", + callnum, ret, strerror(NSCD_GET_ERRNO(&phdr))); + } + + return (ret); +} + +nss_status_t +_nscd_doorcall_data(int callnum, void *indata, int indlen, + void *outdata, int outdlen, nss_pheader_t *phdr) +{ + void *uptr; + size_t buflen; + void *dptr; + void *datap; + size_t ndata; + size_t adata; + nss_pheader_t *phdr_d; + int ret; + char *me = "_nscd_doorcall_data"; + + _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG) + (me, "processing door call %d ...\n", callnum); + + /* allocate door buffer from the stack */ + NSCD_ALLOC_DOORBUF(callnum, indlen, uptr, buflen); + dptr = uptr; + ndata = buflen; + adata = buflen; + datap = NSCD_N2N_DOOR_DATA(void, dptr); + if (indata != NULL) + (void) memmove(datap, indata, indlen); + + ret = _nsc_trydoorcall(&dptr, &ndata, &adata); + + phdr_d = (nss_pheader_t *)dptr; + if (ret != NSS_SUCCESS) { + _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG) + (me, "door call (%d) failed (status = %d, error = %s)\n", + callnum, ret, strerror(NSCD_GET_ERRNO(phdr_d))); + } else { + if (phdr != NULL) { + NSCD_COPY_STATUS(phdr, phdr_d); + } + ret = copy_output(outdata, outdlen, phdr_d, phdr); + } + + /* if new buffer allocated for this door call, free it */ + if (dptr != uptr) + (void) munmap(dptr, ndata); + + return (ret); +} + +nss_status_t +_nscd_doorcall_fd(int fd, int callnum, void *indata, int indlen, + void *outdata, int outdlen, nss_pheader_t *phdr) +{ + void *uptr; + void *dptr; + void *datap; + size_t ndata; + size_t adata; + size_t buflen; + door_arg_t param; + int ret, errnum; + nss_pheader_t *phdr_d; + char *me = "_nscd_doorcall_fd"; + + _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG) + (me, "processing door call %d (fd = %d)...\n", callnum, fd); + + /* allocate door buffer from the stack */ + NSCD_ALLOC_DOORBUF(callnum, indlen, uptr, buflen); + dptr = uptr; + ndata = buflen; + adata = buflen; + datap = NSCD_N2N_DOOR_DATA(void, dptr); + if (indata != NULL) + (void) memmove(datap, indata, indlen); + + param.rbuf = (char *)dptr; + param.rsize = ndata; + param.data_ptr = (char *)dptr; + param.data_size = adata; + param.desc_ptr = NULL; + param.desc_num = 0; + ret = door_call(fd, ¶m); + if (ret < 0) { + errnum = errno; + /* + * door call did not get through, return errno + * if requested + */ + if (phdr != NULL) { + NSCD_SET_STATUS(phdr, NSS_ERROR, errnum); + } + + _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG) + (me, "door call (%d to %d) did not get through (%s)\n", + callnum, fd, strerror(errnum)); + + return (NSS_ERROR); + } + ndata = param.rsize; + dptr = (void *)param.data_ptr; + + /* + * door call got through, check if operation failed. + * if so, return error info if requested + */ + phdr_d = (nss_pheader_t *)dptr; + ret = NSCD_GET_STATUS(phdr_d); + if (ret != NSS_SUCCESS) { + if (phdr != NULL) { + NSCD_COPY_STATUS(phdr, phdr_d); + } + + _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG) + (me, "door call (%d to %d) failed: p_status = %d, " + "p_errno = %s, nscd status = %d\n", callnum, fd, + ret, strerror(NSCD_GET_ERRNO(phdr_d)), + NSCD_GET_NSCD_STATUS(phdr_d)); + } else + ret = copy_output(outdata, outdlen, phdr_d, phdr); + + /* if new buffer allocated for this door call, free it */ + if (dptr != uptr) + (void) munmap(dptr, param.rsize); + + + return (ret); +} + +static void +send_doorfd(void **dptr, size_t *ndata, size_t *adata, + door_desc_t *pdesc) +{ + nss_pheader_t *phdr = (nss_pheader_t *)*dptr; + door_arg_t param; + int ret; + int doorfd; + int errnum; + char *me = "send_doorfd"; + + initdoor(*dptr, &doorfd); + if (NSCD_STATUS_IS_NOT_OK(phdr)) + return; + + param.rbuf = (char *)*dptr; + param.rsize = *ndata; + param.data_ptr = (char *)*dptr; + param.data_size = *adata; + param.desc_ptr = pdesc; + param.desc_num = 1; + ret = door_call(doorfd, ¶m); + if (ret < 0) { + errnum = errno; + + _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG) + (me, "door call (to fd %d) failed (%s)\n", + doorfd, strerror(errnum)); + (void) close(doorfd); + NSCD_RETURN_STATUS(phdr, NSS_ERROR, errnum); + } + *adata = param.data_size; + *ndata = param.rsize; + *dptr = (void *)param.data_ptr; + + if (*adata == 0 || *dptr == NULL) { + (void) close(doorfd); + + _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG) + (me, "no data\n"); + + NSCD_RETURN_STATUS(phdr, NSS_ERROR, ENOTCONN); + } + + (void) close(doorfd); +} + +nss_status_t +_nscd_doorcall_sendfd(int fd, int callnum, void *indata, int indlen, + nss_pheader_t *phdr) +{ + void *uptr; + void *dptr; + void *datap; + size_t ndata; + size_t adata; + size_t buflen; + nss_pheader_t *phdr_d; + door_desc_t desc; + char *me = "_nscd_doorcall_sendfd"; + + _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG) + (me, "processing door call %d (fd = %d)...\n", callnum, fd); + + /* allocate door buffer from the stack */ + NSCD_ALLOC_DOORBUF(callnum, indlen, uptr, buflen); + dptr = uptr; + ndata = buflen; + adata = buflen; + datap = NSCD_N2N_DOOR_DATA(void, dptr); + if (indata != NULL) + (void) memmove(datap, indata, indlen); + desc.d_attributes = DOOR_DESCRIPTOR; + desc.d_data.d_desc.d_descriptor = fd; + + send_doorfd(&dptr, &ndata, &adata, &desc); + + phdr_d = (nss_pheader_t *)dptr; + if (NSCD_STATUS_IS_NOT_OK(phdr_d)) { + if (phdr != NULL) + *phdr = *phdr_d; + + _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG) + (me, "door call (%d) failed (status = %d, error = %s)\n", + callnum, NSCD_GET_STATUS(phdr_d), + strerror(NSCD_GET_ERRNO(phdr_d))); + } + + return (NSCD_GET_STATUS(phdr_d)); +} diff --git a/usr/src/cmd/nscd/nscd_door.h b/usr/src/cmd/nscd/nscd_door.h new file mode 100644 index 0000000000..382968f5e1 --- /dev/null +++ b/usr/src/cmd/nscd/nscd_door.h @@ -0,0 +1,175 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _NSCD_DOOR_H +#define _NSCD_DOOR_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * Definitions for nscd to nscd door interfaces + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#include <alloca.h> +#include <nss_dbdefs.h> + +/* door for Trusted Extensions */ +#define TSOL_NAME_SERVICE_DOOR "/var/tsol/doors/name_service_door" + +/* nscd v2 nscd -> nscd call numbers */ +#define NSCD_PING (NSCD_CALLCAT_N2N|0x01) +#define NSCD_GETADMIN (NSCD_CALLCAT_N2N|0x02) +#define NSCD_SETADMIN (NSCD_CALLCAT_N2N|0x03) +#define NSCD_GETPUADMIN (NSCD_CALLCAT_N2N|0x04) +#define NSCD_SETPUADMIN (NSCD_CALLCAT_N2N|0x05) +#define NSCD_KILLSERVER (NSCD_CALLCAT_N2N|0x06) + +#define NSCD_IMHERE (NSCD_CALLCAT_N2N|0x10) /* IMHERE+WHOAMI */ +#define NSCD_FORK (NSCD_CALLCAT_N2N|0x20) +#define NSCD_SETUID (NSCD_CALLCAT_N2N|0x30) +#define NSCD_KILL (NSCD_CALLCAT_N2N|0x40) +#define NSCD_PULSE (NSCD_CALLCAT_N2N|0x50) +#define NSCD_REFRESH (NSCD_CALLCAT_N2N|0x60) + +/* nscd v2 nscd identities */ + +#define NSCD_MAIN 0x00000001 +#define NSCD_FORKER 0x00000002 +#define NSCD_CHILD 0x00000004 +#define NSCD_WHOAMI 0x0000000F + +#define NSCD_ALLOC_DOORBUF(cn, dsz, uptr, usz) \ + usz = (sizeof (nss_pheader_t) + (dsz)); \ + uptr = alloca(usz); \ + (void) memset(uptr, 0, usz); \ + ((nss_pheader_t *)uptr)->nsc_callnumber = (cn); \ + ((nss_pheader_t *)uptr)->pbufsiz = usz; \ + ((nss_pheader_t *)uptr)->data_off = sizeof (nss_pheader_t); + +#define NSCD_N2N_DOOR_DATA(type, buf) \ + (type *)((void *)(((char *)(buf)) + sizeof (nss_pheader_t))) + +#define NSCD_N2N_DOOR_BUF_SIZE(struct) \ + sizeof (nss_pheader_t) + sizeof (struct) + +#define NSCD_SET_STATUS(ph, st, errno) \ + { \ + int e = errno; \ + (ph)->p_status = st; \ + if (e != -1) \ + (ph)->p_errno = e; \ + } + +#define NSCD_SET_HERRNO(ph, herrno) \ + (ph)->p_herrno = herrno; + + +#define NSCD_RETURN_STATUS(ph, st, errno) \ + { \ + int e = errno; \ + (ph)->p_status = st; \ + if (e != -1) \ + (ph)->p_errno = e; \ + return; \ + } + +#define NSCD_SET_STATUS_SUCCESS(ph) \ + (ph)->p_status = NSS_SUCCESS; \ + (ph)->p_errno = 0; + +#define NSCD_RETURN_STATUS_SUCCESS(ph) \ + (ph)->p_status = NSS_SUCCESS; \ + (ph)->p_errno = 0; \ + return; + +#define NSCD_SET_N2N_STATUS(ph, st, errno, n2nst) \ + { \ + int e = errno; \ + (ph)->p_status = st; \ + if (e != -1) \ + (ph)->p_errno = e; \ + (ph)->nscdpriv = n2nst; \ + } + +#define NSCD_RETURN_N2N_STATUS(ph, st, errno, n2nst) \ + { \ + int e = errno; \ + (ph)->p_status = st; \ + if (e != -1) \ + (ph)->p_errno = e; \ + (ph)->nscdpriv = n2nst; \ + return; \ + } + +#define NSCD_STATUS_IS_OK(ph) \ + (((ph)->p_status) == NSS_SUCCESS) + +#define NSCD_STATUS_IS_NOT_OK(ph) \ + (((ph)->p_status) != NSS_SUCCESS) + +#define NSCD_GET_STATUS(ph) \ + (((nss_pheader_t *)(ph))->p_status) + +#define NSCD_GET_ERRNO(ph) \ + (((nss_pheader_t *)(ph))->p_errno) + +#define NSCD_GET_HERRNO(ph) \ + (((nss_pheader_t *)(ph))->p_herrno) + +#define NSCD_GET_NSCD_STATUS(ph) \ + (((nss_pheader_t *)(ph))->nscdpriv) + +#define NSCD_CLEAR_STATUS(ph) \ + (ph)->p_status = 0; \ + (ph)->p_errno = 0; \ + (ph)->nscdpriv = 0; + +#define NSCD_COPY_STATUS(ph, ph1) \ + (ph)->p_status = (ph1)->p_status; \ + (ph)->p_errno = (ph1)->p_errno; \ + (ph)->nscdpriv = (ph1)->nscdpriv; + +nss_status_t _nscd_doorcall(int callnum); +nss_status_t _nscd_doorcall_data(int callnum, void *indata, + int indlen, void *outdata, int outdlen, + nss_pheader_t *phdr); + +nss_status_t _nscd_doorcall_fd(int fd, int callnum, void *indata, + int indlen, void *outdata, int outdlen, + nss_pheader_t *phdr); + +nss_status_t _nscd_doorcall_sendfd(int fd, int callnum, + void *indata, int indlen, nss_pheader_t *phdr); + +#ifdef __cplusplus +} +#endif + +#endif /* _NSCD_DOOR_H */ diff --git a/usr/src/cmd/nscd/nscd_frontend.c b/usr/src/cmd/nscd/nscd_frontend.c new file mode 100644 index 0000000000..7f718111e9 --- /dev/null +++ b/usr/src/cmd/nscd/nscd_frontend.c @@ -0,0 +1,1150 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <stdlib.h> +#include <alloca.h> +#include <signal.h> +#include <sys/stat.h> +#include <unistd.h> +#include <pthread.h> +#include <time.h> +#include <errno.h> +#include <door.h> +#include <zone.h> +#include <resolv.h> +#include <sys/socket.h> +#include <net/route.h> +#include <string.h> +#include <net/if.h> +#include <sys/stat.h> +#include <fcntl.h> +#include "nscd_common.h" +#include "nscd_door.h" +#include "nscd_config.h" +#include "nscd_switch.h" +#include "nscd_log.h" +#include "nscd_selfcred.h" +#include "nscd_frontend.h" +#include "nscd_admin.h" + +static void rts_mon(void); +static void keep_open_dns_socket(void); + +extern nsc_ctx_t *cache_ctx_p[]; + +/* + * Current active Configuration data for the frontend component + */ +static nscd_cfg_global_frontend_t frontend_cfg_g; +static nscd_cfg_frontend_t *frontend_cfg; + +static int max_servers = 0; +static int max_servers_set = 0; +static int per_user_is_on = 1; + +static char *main_execname; +static char **main_argv; +extern int _whoami; +extern long activity; +extern mutex_t activity_lock; + +static sema_t common_sema; + +static thread_key_t lookup_state_key; +static mutex_t create_lock = DEFAULTMUTEX; +static int num_servers = 0; +static thread_key_t server_key; + +/* + * Bind a TSD value to a server thread. This enables the destructor to + * be called if/when this thread exits. This would be a programming + * error, but better safe than sorry. + */ +/*ARGSUSED*/ +static void * +server_tsd_bind(void *arg) +{ + static void *value = 0; + + /* disable cancellation to avoid hangs if server threads disappear */ + (void) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); + (void) thr_setspecific(server_key, value); + (void) door_return(NULL, 0, NULL, 0); + + /* make lint happy */ + return (NULL); +} + +/* + * Server threads are created here. + */ +/*ARGSUSED*/ +static void +server_create(door_info_t *dip) +{ + (void) mutex_lock(&create_lock); + if (++num_servers > max_servers) { + num_servers--; + (void) mutex_unlock(&create_lock); + return; + } + (void) mutex_unlock(&create_lock); + (void) thr_create(NULL, 0, server_tsd_bind, NULL, + THR_BOUND|THR_DETACHED, NULL); +} + +/* + * Server thread are destroyed here + */ +/*ARGSUSED*/ +static void +server_destroy(void *arg) +{ + (void) mutex_lock(&create_lock); + num_servers--; + (void) mutex_unlock(&create_lock); +} + +/* + * get clearance + */ +int +_nscd_get_clearance(sema_t *sema) { + if (sema_trywait(&common_sema) == 0) { + (void) thr_setspecific(lookup_state_key, NULL); + return (0); + } + + if (sema_trywait(sema) == 0) { + (void) thr_setspecific(lookup_state_key, (void*)1); + return (0); + } + + return (1); +} + + +/* + * release clearance + */ +int +_nscd_release_clearance(sema_t *sema) { + int which; + + (void) thr_getspecific(lookup_state_key, (void**)&which); + if (which == 0) /* from common pool */ { + (void) sema_post(&common_sema); + return (0); + } + + (void) sema_post(sema); + return (1); +} + +static void +dozip(void) +{ + /* not much here */ +} + +static void +restart_if_cfgfile_changed() +{ + + static mutex_t nsswitch_lock = DEFAULTMUTEX; + static time_t last_nsswitch_check = 0; + static time_t last_nsswitch_modified = 0; + static time_t last_resolv_modified = 0; + time_t now = time(NULL); + char *me = "restart_if_cfgfile_changed"; + + if (now - last_nsswitch_check <= _NSC_FILE_CHECK_TIME) + return; + + (void) mutex_lock(&nsswitch_lock); + + if (now - last_nsswitch_check > _NSC_FILE_CHECK_TIME) { + struct stat nss_buf; + struct stat res_buf; + + last_nsswitch_check = now; + + (void) mutex_unlock(&nsswitch_lock); /* let others continue */ + + /* + * This code keeps us from statting resolv.conf + * if it doesn't exist, yet prevents us from ignoring + * it if it happens to disappear later on for a bit. + */ + + if (last_resolv_modified >= 0) { + if (stat("/etc/resolv.conf", &res_buf) < 0) { + if (last_resolv_modified == 0) + last_resolv_modified = -1; + else + res_buf.st_mtime = last_resolv_modified; + } else if (last_resolv_modified == 0) { + last_resolv_modified = res_buf.st_mtime; + } + } + + if (stat("/etc/nsswitch.conf", &nss_buf) < 0) { + + /*EMPTY*/; + + } else if (last_nsswitch_modified == 0) { + + last_nsswitch_modified = nss_buf.st_mtime; + + } else if ((last_nsswitch_modified < nss_buf.st_mtime) || + ((last_resolv_modified > 0) && + (last_resolv_modified < res_buf.st_mtime))) { + static mutex_t exit_lock = DEFAULTMUTEX; + char *fmri; + + /* + * if in self cred mode, kill the forker and + * child nscds + */ + if (_nscd_is_self_cred_on(0, NULL)) { + _nscd_kill_forker(); + _nscd_kill_all_children(); + } + + /* + * time for restart + */ + _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_INFO) + (me, "nscd restart due to %s or %s change\n", + "/etc/nsswitch.conf", "resolv.conf"); + /* + * try to restart under smf + */ + if ((fmri = getenv("SMF_FMRI")) == NULL) { + /* not running under smf - reexec */ + (void) execv(main_execname, main_argv); + exit(1); /* just in case */ + } + + /* prevent multiple restarts */ + (void) mutex_lock(&exit_lock); + + if (smf_restart_instance(fmri) == 0) + (void) sleep(10); /* wait a bit */ + exit(1); /* give up waiting for resurrection */ + } + + } else + (void) mutex_unlock(&nsswitch_lock); +} + +uid_t +_nscd_get_client_euid() +{ + ucred_t *uc = NULL; + uid_t id; + char *me = "get_client_euid"; + + if (door_ucred(&uc) != 0) { + _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG) + (me, "door_ucred: %s\n", strerror(errno)); + return ((uid_t)-1); + } + + id = ucred_geteuid(uc); + ucred_free(uc); + return (id); +} + +static void +N2N_check_priv( + void *buf, + char *dc_str) +{ + nss_pheader_t *phdr = (nss_pheader_t *)buf; + ucred_t *uc = NULL; + const priv_set_t *eset; + zoneid_t zoneid; + int errnum; + char *me = "N2N_check_priv"; + + if (door_ucred(&uc) != 0) { + errnum = errno; + _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG) + (me, "door_ucred: %s\n", strerror(errno)); + + NSCD_RETURN_STATUS(phdr, NSS_ERROR, errnum); + } + + eset = ucred_getprivset(uc, PRIV_EFFECTIVE); + zoneid = ucred_getzoneid(uc); + + if ((zoneid != GLOBAL_ZONEID && zoneid != getzoneid()) || + eset != NULL ? !priv_ismember(eset, PRIV_SYS_ADMIN) : + ucred_geteuid(uc) != 0) { + + _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ALERT) + (me, "%s call failed(cred): caller pid %d, uid %d, " + "euid %d, zoneid %d\n", dc_str, ucred_getpid(uc), + ucred_getruid(uc), ucred_geteuid(uc), zoneid); + ucred_free(uc); + + NSCD_RETURN_STATUS(phdr, NSS_ERROR, EACCES); + } + + _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG) + (me, "nscd received %s cmd from pid %d, uid %d, " + "euid %d, zoneid %d\n", dc_str, ucred_getpid(uc), + ucred_getruid(uc), ucred_geteuid(uc), zoneid); + + ucred_free(uc); + + NSCD_RETURN_STATUS_SUCCESS(phdr); +} + +static void +APP_check_cred( + void *buf, + pid_t *pidp, + char *dc_str) +{ + nss_pheader_t *phdr = (nss_pheader_t *)buf; + ucred_t *uc = NULL; + uid_t ruid; + uid_t euid; + int errnum; + char *me = "APP_check_cred"; + + if (door_ucred(&uc) != 0) { + errnum = errno; + _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG) + (me, "door_ucred: %s\n", strerror(errno)); + + NSCD_RETURN_STATUS(phdr, NSS_ERROR, errnum); + } + + if (NSS_PACKED_CRED_CHECK(buf, ruid = ucred_getruid(uc), + euid = ucred_geteuid(uc))) { + if (pidp != NULL) + *pidp = ucred_getpid(uc); + ucred_free(uc); + + NSCD_RETURN_STATUS_SUCCESS(phdr); + } + + _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ALERT) + (me, "%s call failed: caller pid %d, ruid %d, " + "euid %d, header ruid %d, header euid %d\n", dc_str, + (pidp != NULL) ? *pidp : -1, ruid, euid, + ((nss_pheader_t *)(buf))->p_ruid, ((nss_pheader_t *)(buf))->p_euid); + + + ucred_free(uc); + + NSCD_RETURN_STATUS(phdr, NSS_ERROR, EACCES); +} + +static void +lookup(char *argp, size_t arg_size) +{ + nsc_lookup_args_t largs; + char space[NSCD_LOOKUP_BUFSIZE]; + nss_pheader_t *phdr = (nss_pheader_t *)(void *)argp; + + NSCD_ALLOC_LOOKUP_BUFFER(argp, arg_size, phdr, space, + sizeof (space)); + + (void) memset(&largs, 0, sizeof (largs)); + largs.buffer = argp; + largs.bufsize = arg_size; + nsc_lookup(&largs, 0); + + /* + * only the PUN needs to keep track of the + * activity count to determine when to + * terminate itself + */ + if (_whoami == NSCD_CHILD) { + (void) mutex_lock(&activity_lock); + ++activity; + (void) mutex_unlock(&activity_lock); + } + + NSCD_SET_RETURN_ARG(phdr, arg_size); + (void) door_return(argp, arg_size, NULL, 0); +} + +static void +getent(char *argp, size_t arg_size) +{ + char space[NSCD_LOOKUP_BUFSIZE]; + nss_pheader_t *phdr = (nss_pheader_t *)(void *)argp; + + NSCD_ALLOC_LOOKUP_BUFFER(argp, arg_size, phdr, + space, sizeof (space)); + + nss_pgetent(argp, arg_size); + + NSCD_SET_RETURN_ARG(phdr, arg_size); + (void) door_return(argp, arg_size, NULL, 0); +} + +static int +is_db_per_user(void *buf, char *dblist) +{ + nss_pheader_t *phdr = (nss_pheader_t *)buf; + nss_dbd_t *pdbd; + char *dbname, *dbn; + int len; + + /* copy db name into a temp buffer */ + pdbd = (nss_dbd_t *)((void *)((char *)buf + phdr->dbd_off)); + dbname = (char *)pdbd + pdbd->o_name; + len = strlen(dbname); + dbn = alloca(len + 2); + (void) memcpy(dbn, dbname, len); + + /* check if <dbname> + ',' can be found in the dblist string */ + dbn[len] = ','; + dbn[len + 1] = '\0'; + if (strstr(dblist, dbn) != NULL) + return (1); + + /* + * check if <dbname> can be found in the last part + * of the dblist string + */ + dbn[len] = '\0'; + if (strstr(dblist, dbn) != NULL) + return (1); + + return (0); +} + +/* + * Check to see if all conditions are met for processing per-user + * requests. Returns 1 if yes, -1 if backend is not configured, + * 0 otherwise. + */ +static int +need_per_user_door(void *buf, int whoami, uid_t uid, char **dblist) +{ + nss_pheader_t *phdr = (nss_pheader_t *)buf; + + NSCD_SET_STATUS_SUCCESS(phdr); + + /* if already a per-user nscd, no need to get per-user door */ + if (whoami == NSCD_CHILD) + return (0); + + /* forker shouldn't be asked */ + if (whoami == NSCD_FORKER) { + NSCD_SET_STATUS(phdr, NSS_ERROR, ENOTSUP); + return (0); + } + + /* if door client is root, no need for a per-user door */ + if (uid == 0) + return (0); + + /* + * if per-user lookup is not configured, no per-user + * door available + */ + if (_nscd_is_self_cred_on(0, dblist) == 0) + return (-1); + + /* + * if per-user lookup is not configured for the db, + * don't bother + */ + if (is_db_per_user(phdr, *dblist) == 0) + return (0); + + return (1); +} + +static void +if_selfcred_return_per_user_door(char *argp, size_t arg_size, + door_desc_t *dp, int whoami) +{ + nss_pheader_t *phdr = (nss_pheader_t *)((void *)argp); + char *dblist; + int door = -1; + int rc = 0; + door_desc_t desc; + char space[1024*4]; + + /* + * check to see if self-cred is configured and + * need to return an alternate PUN door + */ + if (per_user_is_on == 1) { + rc = need_per_user_door(argp, whoami, + _nscd_get_client_euid(), &dblist); + if (rc == -1) + per_user_is_on = 0; + } + if (rc <= 0) { + /* + * self-cred not configured, and no error detected, + * return to continue the door call processing + */ + if (NSCD_STATUS_IS_OK(phdr)) + return; + else + /* + * configured but error detected, + * stop the door call processing + */ + (void) door_return(argp, phdr->data_off, NULL, 0); + } + + /* get the alternate PUN door */ + _nscd_proc_alt_get(argp, &door); + if (NSCD_GET_STATUS(phdr) != NSS_ALTRETRY) { + (void) door_return(argp, phdr->data_off, NULL, 0); + } + + /* return the alternate door descriptor */ + (void) memcpy(space, phdr, NSCD_PHDR_LEN(phdr)); + argp = space; + phdr = (nss_pheader_t *)(void *)space; + dp = &desc; + dp->d_attributes = DOOR_DESCRIPTOR; + dp->d_data.d_desc.d_descriptor = door; + phdr->data_len = strlen(dblist) + 1; + (void) strcpy(((char *)phdr) + NSCD_PHDR_LEN(phdr), dblist); + + arg_size = NSCD_PHDR_LEN(phdr) + NSCD_DATA_LEN(phdr); + (void) door_return(argp, arg_size, dp, 1); +} + +/*ARGSUSED*/ +static void +switcher(void *cookie, char *argp, size_t arg_size, + door_desc_t *dp, uint_t n_desc) +{ + int iam; + pid_t ent_pid = -1; + nss_pheader_t *phdr = (nss_pheader_t *)((void *)argp); + void *uptr; + int buflen, len; + int callnum; + char *me = "switcher"; + + _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG) + (me, "switcher ...\n"); + + if (argp == DOOR_UNREF_DATA) { + (void) printf("Door Slam... exiting\n"); + exit(0); + } + + if (argp == NULL) { /* empty door call */ + (void) door_return(NULL, 0, 0, 0); /* return the favor */ + } + + /* + * need to restart if main nscd and config file(s) changed + */ + if (_whoami == NSCD_MAIN) + restart_if_cfgfile_changed(); + + if ((phdr->nsc_callnumber & NSCDV2CATMASK) == NSCD_CALLCAT_APP) { + switch (phdr->nsc_callnumber) { + case NSCD_SEARCH: + + /* if a fallback to main nscd, skip per-user setup */ + if (phdr->p_status != NSS_ALTRETRY) + if_selfcred_return_per_user_door(argp, arg_size, + dp, _whoami); + lookup(argp, arg_size); + + break; + + case NSCD_SETENT: + + APP_check_cred(argp, &ent_pid, "NSCD_SETENT"); + if (NSCD_STATUS_IS_OK(phdr)) { + if_selfcred_return_per_user_door(argp, arg_size, + dp, _whoami); + nss_psetent(argp, arg_size, ent_pid); + } + break; + + case NSCD_GETENT: + + getent(argp, arg_size); + break; + + case NSCD_ENDENT: + + nss_pendent(argp, arg_size); + break; + + case NSCD_PUT: + + _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR) + (me, "door call NSCD_PUT not supported yet\n"); + + NSCD_SET_STATUS(phdr, NSS_ERROR, ENOTSUP); + break; + + case NSCD_GETHINTS: + + _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR) + (me, "door call NSCD_GETHINTS not supported yet\n"); + + NSCD_SET_STATUS(phdr, NSS_ERROR, ENOTSUP); + break; + + default: + + _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR) + (me, "Unknown name service door call op %x\n", + phdr->nsc_callnumber); + + NSCD_SET_STATUS(phdr, NSS_ERROR, EINVAL); + break; + } + + (void) door_return(argp, arg_size, NULL, 0); + } + + iam = NSCD_MAIN; + callnum = phdr->nsc_callnumber & ~NSCD_WHOAMI; + if (callnum == NSCD_IMHERE || + callnum == NSCD_PULSE || callnum == NSCD_FORK) + iam = phdr->nsc_callnumber & NSCD_WHOAMI; + else + callnum = phdr->nsc_callnumber; + + /* nscd -> nscd v2 calls */ + switch (callnum) { + + case NSCD_PING: + NSCD_SET_STATUS_SUCCESS(phdr); + break; + + case NSCD_IMHERE: + _nscd_proc_iamhere(argp, dp, n_desc, iam); + break; + + case NSCD_PULSE: + N2N_check_priv(argp, "NSCD_PULSE"); + if (NSCD_STATUS_IS_OK(phdr)) + _nscd_proc_pulse(argp, iam); + break; + + case NSCD_FORK: + N2N_check_priv(argp, "NSCD_FORK"); + if (NSCD_STATUS_IS_OK(phdr)) + _nscd_proc_fork(argp, iam); + break; + + case NSCD_KILL: + N2N_check_priv(argp, "NSCD_KILL"); + if (NSCD_STATUS_IS_OK(phdr)) + exit(0); + break; + + case NSCD_REFRESH: + if (_nscd_refresh() != NSCD_SUCCESS) + exit(1); + NSCD_SET_STATUS_SUCCESS(phdr); + break; + + case NSCD_GETPUADMIN: + + if (_nscd_is_self_cred_on(0, NULL)) { + _nscd_peruser_getadmin(argp, sizeof (nscd_admin_t)); + } else { + NSCD_SET_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0, + NSCD_SELF_CRED_NOT_CONFIGURED); + } + break; + + case NSCD_GETADMIN: + + len = _nscd_door_getadmin((void *)argp); + if (len == 0) + break; + + /* size of door buffer not big enough, allocate one */ + NSCD_ALLOC_DOORBUF(NSCD_GETADMIN, len, uptr, buflen); + + /* copy packed header */ + *(nss_pheader_t *)uptr = *(nss_pheader_t *)((void *)argp); + + /* set new buffer size */ + ((nss_pheader_t *)uptr)->pbufsiz = buflen; + + /* try one more time */ + (void) _nscd_door_getadmin((void *)uptr); + (void) door_return(uptr, buflen, NULL, 0); + break; + + case NSCD_SETADMIN: + N2N_check_priv(argp, "NSCD_SETADMIN"); + if (NSCD_STATUS_IS_OK(phdr)) + _nscd_door_setadmin(argp); + break; + + case NSCD_KILLSERVER: + N2N_check_priv(argp, "NSCD_KILLSERVER"); + if (NSCD_STATUS_IS_OK(phdr)) { + /* also kill the forker nscd if one is running */ + _nscd_kill_forker(); + exit(0); + } + break; + + default: + _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR) + (me, "Unknown name service door call op %d\n", + phdr->nsc_callnumber); + + NSCD_SET_STATUS(phdr, NSS_ERROR, EINVAL); + + (void) door_return(argp, arg_size, NULL, 0); + break; + + } + (void) door_return(argp, arg_size, NULL, 0); +} + +int +_nscd_setup_server(char *execname, char **argv) +{ + + int fd; + int errnum; + int bind_failed = 0; + struct stat buf; + sigset_t myset; + struct sigaction action; + char *me = "_nscd_setup_server"; + + main_execname = execname; + main_argv = argv; + + keep_open_dns_socket(); + + /* + * the max number of server threads should be fixed now, so + * set flag to indicate that no in-flight change is allowed + */ + max_servers_set = 1; + + (void) thr_keycreate(&lookup_state_key, NULL); + (void) sema_init(&common_sema, + frontend_cfg_g.common_worker_threads, + USYNC_THREAD, 0); + + /* Establish server thread pool */ + (void) door_server_create(server_create); + if (thr_keycreate(&server_key, server_destroy) != 0) { + errnum = errno; + _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR) + (me, "thr_keycreate (server thread): %s\n", + strerror(errnum)); + return (-1); + } + + /* Create a door */ + if ((fd = door_create(switcher, NAME_SERVICE_DOOR_COOKIE, + DOOR_UNREF | DOOR_NO_CANCEL)) < 0) { + errnum = errno; + _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR) + (me, "door_create: %s\n", strerror(errnum)); + return (-1); + } + + /* if not main nscd, no more setup to do */ + if (_whoami != NSCD_MAIN) + return (fd); + + /* bind to file system */ + if (is_system_labeled()) { + if (stat(TSOL_NAME_SERVICE_DOOR, &buf) < 0) { + int newfd; + if ((newfd = creat(TSOL_NAME_SERVICE_DOOR, 0444)) < 0) { + errnum = errno; + _NSCD_LOG(NSCD_LOG_FRONT_END, + NSCD_LOG_LEVEL_ERROR) + (me, "Cannot create %s: %s\n", + TSOL_NAME_SERVICE_DOOR, + strerror(errnum)); + bind_failed = 1; + } + (void) close(newfd); + } + if (symlink(TSOL_NAME_SERVICE_DOOR, NAME_SERVICE_DOOR) != 0) { + if (errno != EEXIST) { + errnum = errno; + _NSCD_LOG(NSCD_LOG_FRONT_END, + NSCD_LOG_LEVEL_ERROR) + (me, "Cannot symlink %s: %s\n", + NAME_SERVICE_DOOR, + strerror(errnum)); + bind_failed = 1; + } + } + } else if (stat(NAME_SERVICE_DOOR, &buf) < 0) { + int newfd; + if ((newfd = creat(NAME_SERVICE_DOOR, 0444)) < 0) { + errnum = errno; + _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR) + (me, "Cannot create %s: %s\n", NAME_SERVICE_DOOR, + strerror(errnum)); + bind_failed = 1; + } + (void) close(newfd); + } + + if (bind_failed == 1) { + (void) door_revoke(fd); + return (-1); + } + + if (fattach(fd, NAME_SERVICE_DOOR) < 0) { + if ((errno != EBUSY) || + (fdetach(NAME_SERVICE_DOOR) < 0) || + (fattach(fd, NAME_SERVICE_DOOR) < 0)) { + errnum = errno; + _NSCD_LOG(NSCD_LOG_FRONT_END, + NSCD_LOG_LEVEL_ERROR) + (me, "fattach: %s\n", strerror(errnum)); + (void) door_revoke(fd); + return (-1); + } + } + + /* + * kick off routing socket monitor thread + */ + if (thr_create(NULL, NULL, + (void *(*)(void *))rts_mon, 0, 0, NULL) != 0) { + errnum = errno; + _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR) + (me, "thr_create (routing socket monitor): %s\n", + strerror(errnum)); + + (void) door_revoke(fd); + return (-1); + } + + /* + * set up signal handler for SIGHUP + */ + action.sa_handler = dozip; + action.sa_flags = 0; + (void) sigemptyset(&action.sa_mask); + (void) sigemptyset(&myset); + (void) sigaddset(&myset, SIGHUP); + + if (sigaction(SIGHUP, &action, NULL) < 0) { + errnum = errno; + _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR) + (me, "sigaction (SIGHUP): %s\n", strerror(errnum)); + + (void) door_revoke(fd); + return (-1); + } + + return (fd); +} + +int +_nscd_setup_child_server(int did) +{ + + int errnum; + int fd; + nscd_rc_t rc; + char *me = "_nscd_setup_child_server"; + + /* Re-establish our own server thread pool */ + (void) door_server_create(server_create); + if (thr_keycreate(&server_key, server_destroy) != 0) { + errnum = errno; + _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG) + (me, "thr_keycreate failed: %s", strerror(errnum)); + return (-1); + } + + /* + * Create a new door. + * Keep DOOR_REFUSE_DESC (self-cred nscds don't fork) + */ + (void) close(did); + if ((fd = door_create(switcher, + NAME_SERVICE_DOOR_COOKIE, + DOOR_REFUSE_DESC|DOOR_UNREF|DOOR_NO_CANCEL)) < 0) { + errnum = errno; + _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG) + (me, "door_create failed: %s", strerror(errnum)); + return (-1); + } + + /* + * kick off routing socket monitor thread + */ + if (thr_create(NULL, NULL, + (void *(*)(void *))rts_mon, 0, 0, NULL) != 0) { + errnum = errno; + _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR) + (me, "thr_create (routing socket monitor): %s\n", + strerror(errnum)); + (void) door_revoke(fd); + return (-1); + } + + /* + * start monitoring the states of the name service clients + */ + rc = _nscd_init_smf_monitor(); + if (rc != NSCD_SUCCESS) { + _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR) + (me, "unable to start the SMF monitor (rc = %d)\n", rc); + + (void) door_revoke(fd); + return (-1); + } + + return (fd); +} + +nscd_rc_t +_nscd_alloc_frontend_cfg() +{ + frontend_cfg = calloc(NSCD_NUM_DB, sizeof (nscd_cfg_frontend_t)); + if (frontend_cfg == NULL) + return (NSCD_NO_MEMORY); + + return (NSCD_SUCCESS); +} + + +/* ARGSUSED */ +nscd_rc_t +_nscd_cfg_frontend_notify( + void *data, + struct nscd_cfg_param_desc *pdesc, + nscd_cfg_id_t *nswdb, + nscd_cfg_flag_t dflag, + nscd_cfg_error_t **errorp, + void *cookie) +{ + void *dp; + + /* + * At init time, the whole group of config params are received. + * At update time, group or individual parameter value could + * be received. + */ + + if (_nscd_cfg_flag_is_set(dflag, NSCD_CFG_DFLAG_INIT) || + _nscd_cfg_flag_is_set(dflag, NSCD_CFG_DFLAG_GROUP)) { + /* + * group data is received, copy in the + * entire strcture + */ + if (_nscd_cfg_flag_is_set(pdesc->pflag, + NSCD_CFG_PFLAG_GLOBAL)) + frontend_cfg_g = + *(nscd_cfg_global_frontend_t *)data; + else + frontend_cfg[nswdb->index] = + *(nscd_cfg_frontend_t *)data; + + } else { + /* + * individual paramater is received: copy in the + * parameter value. + */ + if (_nscd_cfg_flag_is_set(pdesc->pflag, + NSCD_CFG_PFLAG_GLOBAL)) + dp = (char *)&frontend_cfg_g + pdesc->p_offset; + else + dp = (char *)&frontend_cfg[nswdb->index] + + pdesc->p_offset; + (void) memcpy(dp, data, pdesc->p_size); + } + + return (NSCD_SUCCESS); +} + +/* ARGSUSED */ +nscd_rc_t +_nscd_cfg_frontend_verify( + void *data, + struct nscd_cfg_param_desc *pdesc, + nscd_cfg_id_t *nswdb, + nscd_cfg_flag_t dflag, + nscd_cfg_error_t **errorp, + void **cookie) +{ + + char *me = "_nscd_cfg_frontend_verify"; + + /* + * if max. number of server threads is set and in effect, + * don't allow changing of the frontend configuration + */ + if (max_servers_set) { + _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_INFO) + (me, "changing of the frontend configuration not allowed now"); + + return (NSCD_CFG_CHANGE_NOT_ALLOWED); + } + + return (NSCD_SUCCESS); +} + +/* ARGSUSED */ +nscd_rc_t +_nscd_cfg_frontend_get_stat( + void **stat, + struct nscd_cfg_stat_desc *sdesc, + nscd_cfg_id_t *nswdb, + nscd_cfg_flag_t *dflag, + void (**free_stat)(void *stat), + nscd_cfg_error_t **errorp) +{ + return (NSCD_SUCCESS); +} + +void +_nscd_init_cache_sema(sema_t *sema, char *cache_name) +{ + int i, j; + char *dbn; + + if (max_servers == 0) + max_servers = frontend_cfg_g.common_worker_threads + + frontend_cfg_g.cache_hit_threads; + + for (i = 0; i < NSCD_NUM_DB; i++) { + + dbn = NSCD_NSW_DB_NAME(i); + if (strcasecmp(dbn, cache_name) == 0) { + j = frontend_cfg[i].worker_thread_per_nsw_db; + (void) sema_init(sema, j, USYNC_THREAD, 0); + max_servers += j; + break; + } + } +} + +/* + * Monitor the routing socket. Address lists stored in the ipnodes + * cache are sorted based on destination address selection rules, + * so when things change that could affect that sorting (interfaces + * go up or down, flags change, etc.), we clear that cache so the + * list will be re-ordered the next time the hostname is resolved. + */ +static void +rts_mon(void) +{ + int rt_sock, rdlen, idx; + union { + struct { + struct rt_msghdr rtm; + struct sockaddr_storage addrs[RTA_NUMBITS]; + } r; + struct if_msghdr ifm; + struct ifa_msghdr ifam; + } mbuf; + struct ifa_msghdr *ifam = &mbuf.ifam; + char *me = "rts_mon"; + + rt_sock = socket(PF_ROUTE, SOCK_RAW, 0); + if (rt_sock < 0) { + _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR) + (me, "Failed to open routing socket: %s\n", strerror(errno)); + thr_exit(0); + } + + for (;;) { + rdlen = read(rt_sock, &mbuf, sizeof (mbuf)); + if (rdlen <= 0) { + if (rdlen == 0 || (errno != EINTR && errno != EAGAIN)) { + _NSCD_LOG(NSCD_LOG_FRONT_END, + NSCD_LOG_LEVEL_ERROR) + (me, "routing socket read: %s\n", + strerror(errno)); + thr_exit(0); + } + continue; + } + if (ifam->ifam_version != RTM_VERSION) { + _NSCD_LOG(NSCD_LOG_FRONT_END, + NSCD_LOG_LEVEL_ERROR) + (me, "rx unknown version (%d) on " + "routing socket.\n", + ifam->ifam_version); + continue; + } + switch (ifam->ifam_type) { + case RTM_NEWADDR: + case RTM_DELADDR: + /* if no ipnodes cache, then nothing to do */ + idx = get_cache_idx("ipnodes"); + if (cache_ctx_p[idx] == NULL || + cache_ctx_p[idx]->reaper_on != nscd_true) + break; + nsc_invalidate(cache_ctx_p[idx], NULL, NULL); + break; + case RTM_ADD: + case RTM_DELETE: + case RTM_CHANGE: + case RTM_GET: + case RTM_LOSING: + case RTM_REDIRECT: + case RTM_MISS: + case RTM_LOCK: + case RTM_OLDADD: + case RTM_OLDDEL: + case RTM_RESOLVE: + case RTM_IFINFO: + break; + default: + _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR) + (me, "rx unknown msg type (%d) on routing socket.\n", + ifam->ifam_type); + break; + } + } +} + +static void +keep_open_dns_socket(void) +{ + _res.options |= RES_STAYOPEN; /* just keep this udp socket open */ +} diff --git a/usr/src/cmd/nscd/nscd_frontend.h b/usr/src/cmd/nscd/nscd_frontend.h new file mode 100644 index 0000000000..73c0fa1d68 --- /dev/null +++ b/usr/src/cmd/nscd/nscd_frontend.h @@ -0,0 +1,84 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2006 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 + +#include "cache.h" + +#define NSCD_LOOKUP_BUFSIZE 1024 * 16 +#define NSCD_DOORBUF_MAXLEN 1024 * 512 +#define NSCD_PHDR_LEN(hdrp) ((hdrp)->data_off) +#define NSCD_DATA_LEN(hdrp) ((hdrp)->data_len) + +#define NSCD_ALLOC_LOOKUP_BUFFER(bufp, bufsiz, hdrp, space, spsiz) \ + if ((hdrp)->pbufsiz <= spsiz) { \ + (void) memcpy(space, (hdrp), NSCD_PHDR_LEN((hdrp))); \ + bufp = space; \ + bufsiz = spsiz; \ + hdrp = (nss_pheader_t *)(void *)space; \ + } else { \ + (bufp) = NULL; \ + bufsiz = (hdrp)->pbufsiz; \ + if (bufsiz > spsiz) \ + bufsiz = NSCD_DOORBUF_MAXLEN; \ + (bufp) = alloca(bufsiz); \ + if ((bufp) != NULL) { \ + (void) memcpy((bufp), (hdrp), NSCD_PHDR_LEN(hdrp)); \ + (hdrp) = (nss_pheader_t *)(void *)(bufp); \ + } else { \ + NSCD_SET_STATUS((hdrp), NSS_ERROR, ENOMEM); \ + (void) door_return((char *)(hdrp), \ + NSCD_PHDR_LEN(hdrp), NULL, 0); \ + } \ + } + +#define NSCD_SET_RETURN_ARG(hdrp, arg_size) \ + if (NSCD_STATUS_IS_OK((nss_pheader_t *)(hdrp))) \ + arg_size = NSCD_PHDR_LEN(hdrp) + (NSCD_DATA_LEN(hdrp) > 0 ? \ + NSCD_DATA_LEN(hdrp) + 1 : 0); \ + else \ + arg_size = NSCD_PHDR_LEN(hdrp); + +/* prototypes */ +uid_t _nscd_get_client_euid(); +int _nscd_setup_server(char *execname, char **argv); +int _nscd_setup_child_server(int did); +int _nscd_get_clearance(sema_t *sema); +int _nscd_release_clearance(sema_t *sema); +void _nscd_init_cache_sema(sema_t *sema, char *cache_name); +nscd_rc_t _nscd_alloc_frontend_cfg(); + +#ifdef __cplusplus +} +#endif + +#endif /* _NSCD_FRONTEND_H */ diff --git a/usr/src/cmd/nscd/nscd_getentctx.c b/usr/src/cmd/nscd/nscd_getentctx.c new file mode 100644 index 0000000000..d37b8d1cf3 --- /dev/null +++ b/usr/src/cmd/nscd/nscd_getentctx.c @@ -0,0 +1,661 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <stdlib.h> +#include <assert.h> +#include <string.h> +#include <errno.h> +#include <fcntl.h> +#include "nscd_db.h" +#include "nscd_log.h" +#include "nscd_switch.h" +#include "nscd_door.h" + +extern int _whoami; +static mutex_t getent_monitor_mutex = DEFAULTMUTEX; +static int getent_monitor_started = 0; + +static rwlock_t getent_ctxDB_rwlock = DEFAULTRWLOCK; +static nscd_db_t *getent_ctxDB = NULL; + +/* + * internal structure representing a nscd getent context + */ +typedef struct nscd_getent_ctx { + int to_delete; /* this ctx no longer valid */ + nscd_getent_context_t *ptr; + nscd_cookie_t cookie; +} nscd_getent_ctx_t; + +/* + * nscd_getent_context_t list for each nss database. Protected + * by the readers/writer lock nscd_getent_ctx_lock. + */ +nscd_getent_ctx_base_t **nscd_getent_ctx_base; +static rwlock_t nscd_getent_ctx_base_lock = DEFAULTRWLOCK; + +extern nscd_db_entry_t *_nscd_walk_db(nscd_db_t *db, void **cookie); + +static nscd_rc_t _nscd_init_getent_ctx_monitor(); + +/* + * FUNCTION: _nscd_create_getent_ctxDB + * + * Create the internal getent context database to keep track of the + * getent contexts currently being used. + */ +nscd_db_t * +_nscd_create_getent_ctxDB() +{ + + nscd_db_t *ret; + + (void) rw_wrlock(&getent_ctxDB_rwlock); + + if (getent_ctxDB != NULL) { + (void) rw_unlock(&getent_ctxDB_rwlock); + return (getent_ctxDB); + } + + ret = _nscd_alloc_db(NSCD_DB_SIZE_LARGE); + + if (ret != NULL) + getent_ctxDB = ret; + + (void) rw_unlock(&getent_ctxDB_rwlock); + + return (ret); +} + +/* + * FUNCTION: _nscd_add_getent_ctx + * + * Add a getent context to the internal context database. + */ +static nscd_rc_t +_nscd_add_getent_ctx( + nscd_getent_context_t *ptr, + nscd_cookie_t cookie) +{ + int size; + char buf[2 * sizeof (cookie) + 1]; + nscd_db_entry_t *db_entry; + nscd_getent_ctx_t *gnctx; + + if (ptr == NULL) + return (NSCD_INVALID_ARGUMENT); + + (void) snprintf(buf, sizeof (buf), "%lld", cookie); + + size = sizeof (*gnctx); + + db_entry = _nscd_alloc_db_entry(NSCD_DATA_CTX_ADDR, + (const char *)buf, size, 1, 1); + if (db_entry == NULL) + return (NSCD_NO_MEMORY); + + gnctx = (nscd_getent_ctx_t *)*(db_entry->data_array); + gnctx->ptr = ptr; + gnctx->cookie = cookie; + + (void) rw_wrlock(&getent_ctxDB_rwlock); + (void) _nscd_add_db_entry(getent_ctxDB, buf, db_entry, + NSCD_ADD_DB_ENTRY_FIRST); + (void) rw_unlock(&getent_ctxDB_rwlock); + + return (NSCD_SUCCESS); +} + +/* + * FUNCTION: _nscd_is_getent_ctx + * + * Check to see if a getent context can be found in the internal + * getent context database. + */ +nscd_getent_context_t * +_nscd_is_getent_ctx( + nscd_cookie_t cookie) +{ + char ptrstr[1 + 2 * sizeof (cookie)]; + const nscd_db_entry_t *db_entry; + nscd_getent_context_t *ret = NULL; + + (void) snprintf(ptrstr, sizeof (ptrstr), "%lld", cookie); + + (void) rw_rdlock(&getent_ctxDB_rwlock); + + db_entry = _nscd_get_db_entry(getent_ctxDB, NSCD_DATA_CTX_ADDR, + (const char *)ptrstr, NSCD_GET_FIRST_DB_ENTRY, 0); + + if (db_entry != NULL) { + nscd_getent_ctx_t *gnctx; + + gnctx = (nscd_getent_ctx_t *)*(db_entry->data_array); + + /* + * If the ctx is not to be deleted and + * the cookie numbers match, return the ctx. + * Otherwise return NULL. + */ + if (gnctx->to_delete == 0 && gnctx->cookie == cookie) + ret = gnctx->ptr; + } + + (void) rw_unlock(&getent_ctxDB_rwlock); + + return (ret); +} + +/* + * FUNCTION: _nscd_del_getent_ctx + * + * Delete a getent context from the internal getent context database. + */ +static void +_nscd_del_getent_ctx( + nscd_getent_context_t *ptr, + nscd_cookie_t cookie) +{ + char ptrstr[1 + 2 * sizeof (cookie)]; + nscd_getent_ctx_t *gnctx; + const nscd_db_entry_t *db_entry; + + if (ptr == NULL) + return; + + (void) snprintf(ptrstr, sizeof (ptrstr), "%lld", cookie); + + (void) rw_rdlock(&getent_ctxDB_rwlock); + /* + * first find the db entry and make sure the + * sequence number matched, then delete it from + * the database. + */ + db_entry = _nscd_get_db_entry(getent_ctxDB, + NSCD_DATA_CTX_ADDR, + (const char *)ptrstr, + NSCD_GET_FIRST_DB_ENTRY, 0); + if (db_entry != NULL) { + gnctx = (nscd_getent_ctx_t *)*(db_entry->data_array); + if (gnctx->ptr == ptr && gnctx->cookie == cookie) { + + (void) rw_unlock(&getent_ctxDB_rwlock); + (void) rw_wrlock(&getent_ctxDB_rwlock); + + (void) _nscd_delete_db_entry(getent_ctxDB, + NSCD_DATA_CTX_ADDR, + (const char *)ptrstr, + NSCD_DEL_FIRST_DB_ENTRY, 0); + } + } + (void) rw_unlock(&getent_ctxDB_rwlock); +} + +static void +_nscd_free_getent_ctx( + nscd_getent_context_t *gnctx) +{ + + char *me = "_nscd_free_getent_ctx"; + + _NSCD_LOG(NSCD_LOG_GETENT_CTX, NSCD_LOG_LEVEL_DEBUG) + (me, "getent context %p\n", gnctx); + + _nscd_put_nsw_state(gnctx->nsw_state); + _nscd_del_getent_ctx(gnctx, gnctx->cookie); + free(gnctx); +} + + +static void +_nscd_free_getent_ctx_base( + nscd_acc_data_t *data) +{ + nscd_getent_ctx_base_t *base = (nscd_getent_ctx_base_t *)data; + nscd_getent_context_t *c, *tc; + char *me = "_nscd_free_getent_ctx_base"; + + _NSCD_LOG(NSCD_LOG_GETENT_CTX | NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG) + (me, "getent context base %p\n", base); + + if (base == NULL) + return; + + c = base->first; + while (c != NULL) { + tc = c->next; + _nscd_free_getent_ctx(c); + c = tc; + } +} + +void +_nscd_free_all_getent_ctx_base() +{ + nscd_getent_ctx_base_t *base; + int i; + char *me = "_nscd_free_all_getent_ctx_base"; + + _NSCD_LOG(NSCD_LOG_GETENT_CTX | NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG) + (me, "entering ..\n"); + + (void) rw_wrlock(&nscd_getent_ctx_base_lock); + + for (i = 0; i < NSCD_NUM_DB; i++) { + + base = nscd_getent_ctx_base[i]; + if (base == NULL) + continue; + + nscd_getent_ctx_base[i] = (nscd_getent_ctx_base_t *) + _nscd_set((nscd_acc_data_t *)base, NULL); + } + (void) rw_unlock(&nscd_getent_ctx_base_lock); +} + +static nscd_getent_context_t * +_nscd_create_getent_ctx( + nscd_nsw_params_t *params) +{ + nscd_getent_context_t *gnctx; + nss_db_root_t db_root; + char *me = "_nscd_create_getent_ctx"; + + gnctx = calloc(1, sizeof (nscd_getent_context_t)); + if (gnctx == NULL) + return (NULL); + else { + _NSCD_LOG(NSCD_LOG_GETENT_CTX, NSCD_LOG_LEVEL_DEBUG) + (me, "getent context allocated %p\n", gnctx); + } + + gnctx->dbi = params->dbi; + gnctx->cookie = _nscd_get_cookie(); + + if (_nscd_get_nsw_state(&db_root, params) != NSCD_SUCCESS) { + free(gnctx); + return (NULL); + } + gnctx->nsw_state = (nscd_nsw_state_t *)db_root.s; + /* this is a nsw_state used for getent processing */ + gnctx->nsw_state->getent = 1; + + _NSCD_LOG(NSCD_LOG_GETENT_CTX, NSCD_LOG_LEVEL_DEBUG) + (me, "got nsw_state %p\n", gnctx->nsw_state); + + return (gnctx); +} + + +nscd_rc_t +_nscd_get_getent_ctx( + nss_getent_t *contextpp, + nscd_nsw_params_t *params) +{ + + nscd_getent_context_t *c; + nscd_getent_ctx_base_t *base, *tmp; + nscd_rc_t rc; + char *me = "_nscd_get_getent_ctx"; + + _NSCD_LOG(NSCD_LOG_GETENT_CTX, NSCD_LOG_LEVEL_DEBUG) + (me, "entering ...\n"); + + (void) rw_rdlock(&nscd_getent_ctx_base_lock); + base = nscd_getent_ctx_base[params->dbi]; + (void) rw_unlock(&nscd_getent_ctx_base_lock); + assert(base != NULL); + + /* + * If the context list is not empty, return the first one + * on the list. Otherwise, create and return a new one if + * limit is not reached. if reacehed, wait for the 'one is + * available' signal. + */ + tmp = (nscd_getent_ctx_base_t *)_nscd_mutex_lock( + (nscd_acc_data_t *)base); + assert(base == tmp); + if (base->first == NULL) { + if (base->num_getent_ctx == base->max_getent_ctx) { + base->num_waiter++; + while (base->first == NULL) { + + _NSCD_LOG(NSCD_LOG_GETENT_CTX, + NSCD_LOG_LEVEL_DEBUG) + (me, "waiting for signal\n"); + + _nscd_cond_wait((nscd_acc_data_t *)base, NULL); + + _NSCD_LOG(NSCD_LOG_GETENT_CTX, + NSCD_LOG_LEVEL_DEBUG) + (me, "woke up\n"); + } + base->num_waiter--; + } else { + base->first = _nscd_create_getent_ctx(params); + if (base->first != NULL) { + base->first->base = base; + base->num_getent_ctx++; + } else { + /* not able to create an getent ctx */ + + _NSCD_LOG(NSCD_LOG_GETENT_CTX, + NSCD_LOG_LEVEL_ERROR) + (me, "create getent ctx failed\n"); + + _nscd_mutex_unlock((nscd_acc_data_t *)base); + return (NSCD_CREATE_GETENT_CTX_FAILED); + } + + _NSCD_LOG(NSCD_LOG_GETENT_CTX, NSCD_LOG_LEVEL_DEBUG) + (me, "got a new getent ctx %p\n", base->first); + } + } + + assert(base->first != NULL); + + c = base->first; + base->first = c->next; + c->next = NULL; + c->seq_num = 1; + + _NSCD_LOG(NSCD_LOG_GETENT_CTX, NSCD_LOG_LEVEL_DEBUG) + (me, "got a getent ctx %p\n", c); + + _nscd_mutex_unlock((nscd_acc_data_t *)base); + + _NSCD_LOG(NSCD_LOG_GETENT_CTX, NSCD_LOG_LEVEL_DEBUG) + (me, "adding new ctx %p, cookie = %lld\n", c, c->cookie); + + if ((rc = _nscd_add_getent_ctx(c, c->cookie)) != NSCD_SUCCESS) { + _nscd_put_getent_ctx(c); + return (rc); + } + contextpp->ctx = (struct nss_getent_context *)c; + + /* start monitor and reclaim orphan getent context */ + if (getent_monitor_started == 0) { + (void) mutex_lock(&getent_monitor_mutex); + if (getent_monitor_started == 0) { + getent_monitor_started = 1; + (void) _nscd_init_getent_ctx_monitor(); + } + (void) mutex_unlock(&getent_monitor_mutex); + } + + return (NSCD_SUCCESS); +} + +void +_nscd_put_getent_ctx( + nscd_getent_context_t *gnctx) +{ + + nscd_getent_ctx_base_t *base; + char *me = "_nscd_put_getent_ctx"; + + base = gnctx->base; + gnctx->seq_num = 0; + + /* if context base is gone, so should this context */ + if ((_nscd_mutex_lock((nscd_acc_data_t *)base)) == NULL) { + _nscd_free_getent_ctx(gnctx); + return; + } + + if (base->first != NULL) { + gnctx->next = base->first; + base->first = gnctx; + } else + base->first = gnctx; + + /* put back the db state */ + _NSCD_LOG(NSCD_LOG_GETENT_CTX, NSCD_LOG_LEVEL_DEBUG) + (me, "putting back nsw state %p\n", gnctx->nsw_state); + + /* this nsw_state is no longer used for getent processing */ + if (gnctx->nsw_state != NULL) + gnctx->nsw_state->getent = 0; + _nscd_put_nsw_state(gnctx->nsw_state); + gnctx->nsw_state = NULL; + + _nscd_del_getent_ctx(gnctx, gnctx->cookie); + + _NSCD_LOG(NSCD_LOG_GETENT_CTX, NSCD_LOG_LEVEL_DEBUG) + (me, "ctx (%p seq# = %lld) removed from getent ctx DB\n", + gnctx, gnctx->cookie); + + if (base->num_waiter > 0) { + _NSCD_LOG(NSCD_LOG_GETENT_CTX, NSCD_LOG_LEVEL_DEBUG) + (me, "signaling (waiter = %d)\n", base->num_waiter); + + _nscd_cond_signal((nscd_acc_data_t *)base); + } + + _nscd_mutex_unlock((nscd_acc_data_t *)base); +} + +nscd_rc_t +_nscd_init_getent_ctx_base( + int dbi, + int lock) +{ + nscd_getent_ctx_base_t *base = NULL; + char *me = "_nscd_init_getent_ctx_base"; + + if (lock) + (void) rw_rdlock(&nscd_getent_ctx_base_lock); + + base = (nscd_getent_ctx_base_t *)_nscd_alloc( + NSCD_DATA_GETENT_CTX_BASE, + sizeof (nscd_getent_ctx_base_t), + _nscd_free_getent_ctx_base, + NSCD_ALLOC_MUTEX | NSCD_ALLOC_COND); + + if (base == NULL) { + if (lock) + (void) rw_unlock(&nscd_getent_ctx_base_lock); + return (NSCD_NO_MEMORY); + } + _NSCD_LOG(NSCD_LOG_GETENT_CTX | NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG) + (me, "base %p allocated\n", base); + + /* + * initialize and activate the new getent_ctx base + */ + base->dbi = dbi; + base->max_getent_ctx = NSCD_SW_CFG(dbi).max_getent_ctx_per_db; + nscd_getent_ctx_base[dbi] = + (nscd_getent_ctx_base_t *)_nscd_set( + (nscd_acc_data_t *)nscd_getent_ctx_base[dbi], + (nscd_acc_data_t *)base); + + if (lock) + (void) rw_unlock(&nscd_getent_ctx_base_lock); + + return (NSCD_SUCCESS); +} + +nscd_rc_t +_nscd_init_all_getent_ctx_base() +{ + int i; + nscd_rc_t rc; + char *me = "_nscd_init_all_getent_ctx_base"; + + (void) rw_wrlock(&nscd_getent_ctx_base_lock); + + for (i = 0; i < NSCD_NUM_DB; i++) { + + rc = _nscd_init_getent_ctx_base(i, 0); + + if (rc != NSCD_SUCCESS) { + (void) rw_unlock(&nscd_getent_ctx_base_lock); + return (rc); + } + } + + _NSCD_LOG(NSCD_LOG_GETENT_CTX | NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG) + (me, "all getent context base initialized\n"); + + (void) rw_unlock(&nscd_getent_ctx_base_lock); + + return (NSCD_SUCCESS); +} +nscd_rc_t +_nscd_alloc_getent_ctx_base() +{ + + (void) rw_wrlock(&nscd_getent_ctx_base_lock); + + nscd_getent_ctx_base = calloc(NSCD_NUM_DB, + sizeof (nscd_getent_ctx_base_t *)); + if (nscd_getent_ctx_base == NULL) { + (void) rw_unlock(&nscd_getent_ctx_base_lock); + return (NSCD_NO_MEMORY); + } + + (void) rw_unlock(&nscd_getent_ctx_base_lock); + + return (NSCD_SUCCESS); +} + +static int +process_exited(pid_t pid) +{ + char pname[PATH_MAX]; + int fd; + + (void) snprintf(pname, sizeof (pname), "/proc/%d/psinfo", pid); + if ((fd = open(pname, O_RDONLY)) == -1) + return (1); + else { + (void) close(fd); + return (0); + } +} + +/* + * FUNCTION: reclaim_getent_ctx + */ +/*ARGSUSED*/ +static void * +reclaim_getent_ctx(void *arg) +{ + void *cookie = NULL; + nscd_db_entry_t *ep; + nscd_getent_ctx_t *ctx; + nscd_getent_context_t *gctx, *c; + nscd_getent_context_t *first = NULL, *last = NULL; + char *me = "reclaim_getent_ctx"; + + /*CONSTCOND*/ + while (1) { + + (void) rw_rdlock(&getent_ctxDB_rwlock); + + for (ep = _nscd_walk_db(getent_ctxDB, &cookie); ep != NULL; + ep = _nscd_walk_db(getent_ctxDB, &cookie)) { + + ctx = (nscd_getent_ctx_t *)*(ep->data_array); + + gctx = ctx->ptr; + + /* + * if the client process, which did the setent, + * exited, add the context to the orphan list + */ + if (gctx->pid != -1 && process_exited(gctx->pid)) { + + _NSCD_LOG(NSCD_LOG_GETENT_CTX, + NSCD_LOG_LEVEL_DEBUG) + (me, "process %d exited, " + "getent context = %p, " + "db index = %d, cookie = %lld, " + "sequence # = %lld\n", + gctx->pid, gctx, gctx->dbi, + gctx->cookie, gctx->seq_num); + + if (first != NULL) { + last->next = gctx; + last = gctx; + } else { + first = gctx; + last = gctx; + } + } + } + + (void) rw_unlock(&getent_ctxDB_rwlock); + + + /* + * return all the orphan getent contexts to the pool + */ + for (gctx = first; gctx; ) { + c = gctx->next; + gctx->next = NULL; + _nscd_put_getent_ctx(gctx); + gctx = c; + } + first = last = NULL; + + (void) sleep(60); + } + /*NOTREACHED*/ + /*LINTED E_FUNC_HAS_NO_RETURN_STMT*/ +} + +static nscd_rc_t +_nscd_init_getent_ctx_monitor() { + + int errnum; + char *me = "_nscd_init_getent_ctx_monitor"; + + _NSCD_LOG(NSCD_LOG_GETENT_CTX, NSCD_LOG_LEVEL_DEBUG) + (me, "initializing the getent context monitor\n"); + + /* + * the forker nscd does not process getent requests + * so no need to monitor orphan getent contexts + */ + if (_whoami == NSCD_FORKER) + return (NSCD_SUCCESS); + + /* + * start a thread to reclaim unused getent contexts + */ + if (thr_create(NULL, NULL, reclaim_getent_ctx, + NULL, THR_DETACHED, NULL) != 0) { + errnum = errno; + _NSCD_LOG(NSCD_LOG_GETENT_CTX, NSCD_LOG_LEVEL_ERROR) + (me, "thr_create: %s\n", strerror(errnum)); + return (NSCD_THREAD_CREATE_ERROR); + } + + return (NSCD_SUCCESS); +} diff --git a/usr/src/cmd/nscd/nscd_init.c b/usr/src/cmd/nscd/nscd_init.c new file mode 100644 index 0000000000..991d31a9ff --- /dev/null +++ b/usr/src/cmd/nscd/nscd_init.c @@ -0,0 +1,241 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <locale.h> +#include <unistd.h> +#include <string.h> +#include "nscd_common.h" +#include "nscd_config.h" +#include "nscd_log.h" +#include "nscd_switch.h" +#include "nscd_frontend.h" + +static char *cfgfile_save = NULL; + +nscd_rc_t +_nscd_init( + char *cfgfile) +{ + char *me = "nscd_init"; + nscd_rc_t rc; + nscd_cfg_error_t *err; + + /* + * allocate the space for tables + */ + rc = _nscd_alloc_nsw_config(); + rc = _nscd_alloc_service_state_table(); + rc = _nscd_alloc_nsw_state_base(); + rc = _nscd_alloc_nsw_be_info_db(); + rc = _nscd_alloc_getent_ctx_base(); + if (rc != NSCD_SUCCESS) + return (rc); + + /* + * allocate the space for local configuration + * and statistics + */ + rc = _nscd_alloc_switch_cfg(); + rc = _nscd_alloc_frontend_cfg(); + rc = _nscd_alloc_switch_stats(); + if (rc != NSCD_SUCCESS) + return (rc); + + /* + * Create and init the internal address database to keep + * track of the memory allocated by _nscd_alloc + */ + if (_nscd_create_int_addrDB() == NULL) { + _NSCD_LOG(NSCD_LOG_INT_ADDR, NSCD_LOG_LEVEL_ERROR) + (me, "_nscd_create_int_addrDB failed\n"); + return (NSCD_NO_MEMORY); + } + + /* + * Create and init the internal context database to keep + * track of the getent context currently being used + */ + if (_nscd_create_getent_ctxDB() == NULL) { + _NSCD_LOG(NSCD_LOG_GETENT_CTX, NSCD_LOG_LEVEL_ERROR) + (me, "_nscd_create_getent_ctx_addrDB failed\n"); + return (NSCD_NO_MEMORY); + } + + /* + * Create the backend info database for each possible source + */ + if ((rc = _nscd_init_all_nsw_be_info_db()) != NSCD_SUCCESS) { + _NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_ERROR) + (me, "_nscd_init_all_nsw_be_info_db failed (rc = %d)\n", + rc); + return (rc); + } + + /* + * Create the nscd_nsw_config_t for each possible nss database + */ + if ((rc = _nscd_init_all_nsw_config()) != NSCD_SUCCESS) { + _NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_ERROR) + (me, "_nscd_init_all_nsw_config failed (rc = %d)\n", rc); + return (rc); + } + + /* + * populate the backend info databases + */ + if ((rc = _nscd_populate_nsw_backend_info()) != NSCD_SUCCESS) { + _NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_ERROR) + (me, "_nscd_init_all_nsw_be_info_db failed (rc = %d)\n", rc); + return (rc); + } + + /* + * initialize config/stats management + */ + rc = _nscd_cfg_init(&err); + if (rc != NSCD_SUCCESS) { + if (err != NULL) + _nscd_cfg_free_error(err); + return (rc); + } + + /* + * read in the nsswitch configuration + */ + rc = _nscd_cfg_read_nsswitch_file("/etc/nsswitch.conf", &err); + if (rc != NSCD_SUCCESS) { + (void) printf( + gettext("reading config file %s failed with rc = %d, %s\n"), + "/etc/nsswitch.conf", rc, NSCD_ERR2MSG(err)); + if (err != NULL) + _nscd_cfg_free_error(err); + + _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR) + (me, "unable to read /etc/nsswitch.conf (rc = %d)\n", rc); + return (rc); + } + + /* + * read in the nscd configuration + */ + if (cfgfile == NULL) { + cfgfile = "/etc/nscd.conf"; + if (access(cfgfile, R_OK) != 0) { + _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR) + (me, "unable to read /etc/nscd.conf (rc = %d)\n", rc); + + return (NSCD_CFG_FILE_ACCESS_ERROR); + } + } + rc = _nscd_cfg_read_file(cfgfile, &err); + if (rc != NSCD_SUCCESS) { + (void) printf( + gettext("reading config file %s failed with rc = %d, %s\n"), + cfgfile, rc, NSCD_ERR2MSG(err)); + if (err != NULL) + _nscd_cfg_free_error(err); + + _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR) + (me, "unable to read configuration from %s (rc = %d)\n", + cfgfile, rc); + + return (rc); + } + /* + * remember the name of the config file + * in case refresh is requested later + */ + if (cfgfile != NULL) { + cfgfile_save = strdup(cfgfile); + if (cfgfile == NULL) + return (NSCD_NO_MEMORY); + } + + return (NSCD_SUCCESS); +} + +nscd_rc_t +_nscd_refresh() +{ + char *me = "nscd_refresh"; + char *cfgfile; + nscd_rc_t rc; + nscd_cfg_error_t *err; + char errmsg[1024]; + + /* + * re-read the nsswitch configuration + */ + rc = _nscd_cfg_read_nsswitch_file("/etc/nsswitch.conf", &err); + if (rc != NSCD_SUCCESS) { + (void) snprintf(errmsg, sizeof (errmsg), + "unable to parse the config file %s (rc = %d), %s\n", + "/etc/nsswitch.conf", rc, NSCD_ERR2MSG(err)); + goto error_exit; + } + + /* + * re-read the nscd configuration + */ + if (cfgfile_save == NULL) + cfgfile = "/etc/nscd.conf"; + else + cfgfile = cfgfile_save; + + if (access(cfgfile, R_OK) != 0) { + (void) snprintf(errmsg, sizeof (errmsg), + "unable to read the config file %s (rc = %d), %s\n", + cfgfile, NSCD_CFG_FILE_ACCESS_ERROR, + strerror(errno)); + + goto error_exit; + } + + rc = _nscd_cfg_read_file(cfgfile, &err); + if (rc != NSCD_SUCCESS) { + (void) snprintf(errmsg, sizeof (errmsg), + "unable to parse the config file %s (rc = %d), %s\n", + cfgfile, rc, NSCD_ERR2MSG(err)); + + goto error_exit; + } + + _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ALL) + (me, "nsswitch/nscd configuration refreshed successfully\n"); + + return (NSCD_SUCCESS); + + error_exit: + + if (err != NULL) + _nscd_cfg_free_error(err); + + _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR) + (me, "%s\n", errmsg); + + return (rc); +} diff --git a/usr/src/cmd/nscd/nscd_initf.c b/usr/src/cmd/nscd/nscd_initf.c new file mode 100644 index 0000000000..e225923907 --- /dev/null +++ b/usr/src/cmd/nscd/nscd_initf.c @@ -0,0 +1,250 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <nss_common.h> +#include <nss_dbdefs.h> +#include "nscd_common.h" +#include "nscd_switch.h" + +void +_nss_initf_passwd(nss_db_params_t *p) +{ + p->name = NSS_DBNAM_PASSWD; + p->default_config = NSS_DEFCONF_PASSWD; +} + +void +_nss_initf_hosts(nss_db_params_t *p) +{ + p->name = NSS_DBNAM_HOSTS; + p->default_config = NSS_DEFCONF_HOSTS; +} + +void +_nss_initf_group(nss_db_params_t *p) +{ + p->name = NSS_DBNAM_GROUP; + p->default_config = NSS_DEFCONF_GROUP; +} + +void +_nss_initf_ipnodes(nss_db_params_t *p) +{ + p->name = NSS_DBNAM_IPNODES; + p->default_config = NSS_DEFCONF_IPNODES; +} + +void +_nss_initf_net(nss_db_params_t *p) +{ + p->name = NSS_DBNAM_NETWORKS; + p->default_config = NSS_DEFCONF_NETWORKS; +} + +void +_nss_initf_proto(nss_db_params_t *p) +{ + p->name = NSS_DBNAM_PROTOCOLS; + p->default_config = NSS_DEFCONF_PROTOCOLS; +} + +void +_nss_initf_rpc(p) + nss_db_params_t *p; +{ + p->name = NSS_DBNAM_RPC; + p->default_config = NSS_DEFCONF_RPC; +} + +void +_nss_initf_ethers(nss_db_params_t *p) +{ + p->name = NSS_DBNAM_ETHERS; + p->default_config = NSS_DEFCONF_ETHERS; +} + +void +_nss_initf_netmasks(nss_db_params_t *p) +{ + p->name = NSS_DBNAM_NETMASKS; + p->default_config = NSS_DEFCONF_NETMASKS; +} + +void +_nss_initf_bootparams(nss_db_params_t *p) +{ + p->name = NSS_DBNAM_BOOTPARAMS; + p->default_config = NSS_DEFCONF_BOOTPARAMS; +} + +void +_nss_initf_publickey(nss_db_params_t *p) +{ + p->name = NSS_DBNAM_PUBLICKEY; + p->default_config = NSS_DEFCONF_PUBLICKEY; +} + +void +_nss_initf_netgroup(nss_db_params_t *p) +{ + p->name = NSS_DBNAM_NETGROUP; + p->default_config = NSS_DEFCONF_NETGROUP; +} + +void +_nss_initf_services(nss_db_params_t *p) +{ + p->name = NSS_DBNAM_SERVICES; + p->default_config = NSS_DEFCONF_SERVICES; +} + +void +_nss_initf_printers(nss_db_params_t *p) +{ + p->name = NSS_DBNAM_PRINTERS; + p->default_config = NSS_DEFCONF_PRINTERS; +} + +void +_nss_initf_authattr(nss_db_params_t *p) +{ + p->name = NSS_DBNAM_AUTHATTR; + p->default_config = NSS_DEFCONF_AUTHATTR; +} + +void +_nss_initf_profattr(nss_db_params_t *p) +{ + p->name = NSS_DBNAM_PROFATTR; + p->default_config = NSS_DEFCONF_PROFATTR; +} + +void +_nss_initf_execattr(nss_db_params_t *p) +{ + p->name = NSS_DBNAM_EXECATTR; + p->default_config = NSS_DEFCONF_PROFATTR; + p->config_name = NSS_DBNAM_PROFATTR; /* use config for "prof_attr" */ +} + +void +_nss_initf_userattr(nss_db_params_t *p) +{ + p->name = NSS_DBNAM_USERATTR; + p->config_name = NSS_DBNAM_PASSWD; + p->default_config = NSS_DEFCONF_USERATTR; +} + +void +_nss_initf_project(nss_db_params_t *p) +{ + p->name = NSS_DBNAM_PROJECT; + p->default_config = NSS_DEFCONF_PROJECT; +} + +void +_nss_initf_auuser(nss_db_params_t *p) +{ + p->name = NSS_DBNAM_AUDITUSER; + p->config_name = NSS_DBNAM_PASSWD; + p->default_config = NSS_DEFCONF_AUDITUSER; +} + +void +_nss_initf_shadow(nss_db_params_t *p) +{ + p->name = NSS_DBNAM_SHADOW; + p->config_name = NSS_DBNAM_PASSWD; + p->default_config = NSS_DEFCONF_PASSWD; +} + +void +_nss_initf_passwd_compat(nss_db_params_t *p) +{ + p->name = NSS_DBNAM_PASSWD; + p->config_name = NSS_DBNAM_PASSWD_COMPAT; + p->default_config = NSS_DEFCONF_PASSWD_COMPAT; +} + +void +_nss_initf_group_compat(nss_db_params_t *p) +{ + p->name = NSS_DBNAM_GROUP; + p->config_name = NSS_DBNAM_GROUP_COMPAT; + p->default_config = NSS_DEFCONF_GROUP_COMPAT; +} + +void +_nss_initf_tsol_rh(nss_db_params_t *p) +{ + p->name = NSS_DBNAM_TSOL_RH; + p->default_config = NSS_DEFCONF_TSOL_RH; +} + +void +_nss_initf_tsol_tp(nss_db_params_t *p) +{ + p->name = NSS_DBNAM_TSOL_TP; + p->default_config = NSS_DEFCONF_TSOL_TP; +} + +nss_db_initf_t nscd_nss_db_initf[] = { + _nss_initf_passwd, + _nss_initf_hosts, + _nss_initf_group, + _nss_initf_ipnodes, + _nss_initf_net, + _nss_initf_proto, + _nss_initf_rpc, + _nss_initf_ethers, + _nss_initf_netmasks, + _nss_initf_bootparams, + _nss_initf_publickey, + _nss_initf_netgroup, + _nss_initf_services, + _nss_initf_printers, + _nss_initf_authattr, + _nss_initf_profattr, + _nss_initf_execattr, + _nss_initf_userattr, + _nss_initf_project, + _nss_initf_shadow, + _nss_initf_auuser, + _nss_initf_tsol_rh, + _nss_initf_tsol_tp, + _nss_initf_passwd_compat, + _nss_initf_group_compat, + /* + * no initf() for pseudo-databases: passwd, shadow, + * audit_user, user_attr, and group (when called from + * the compat backend) + */ + NULL, + NULL, + NULL, + NULL, + NULL}; diff --git a/usr/src/cmd/nscd/nscd_intaddr.c b/usr/src/cmd/nscd/nscd_intaddr.c new file mode 100644 index 0000000000..f427d0c98a --- /dev/null +++ b/usr/src/cmd/nscd/nscd_intaddr.c @@ -0,0 +1,248 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2006 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 "nscd_db.h" +#include "nscd_log.h" + +static rwlock_t addrDB_rwlock = DEFAULTRWLOCK; +static nscd_db_t *addrDB = NULL; + +/* + * internal structure representing a nscd internal address + */ +typedef struct nscd_int_addr { + int to_delete; /* no longer valid */ + int type; + void *ptr; + nscd_seq_num_t seq_num; + rwlock_t rwlock; /* used to serialize get and destroy */ +} nscd_int_addr_t; + +/* + * FUNCTION: _nscd_create_int_addrDB + * + * Create the internal address database to keep track of the + * memory allocated by _nscd_alloc. + */ +void * +_nscd_create_int_addrDB() +{ + + nscd_db_t *ret; + char *me = "_nscd_create_int_addrDB"; + + _NSCD_LOG(NSCD_LOG_INT_ADDR | NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG) + (me, "initializing the internal address database\n"); + + (void) rw_wrlock(&addrDB_rwlock); + + if (addrDB != NULL) { + (void) rw_unlock(&addrDB_rwlock); + return (addrDB); + } + + ret = _nscd_alloc_db(NSCD_DB_SIZE_LARGE); + + if (ret != NULL) + addrDB = ret; + + (void) rw_unlock(&addrDB_rwlock); + + return (ret); +} + +/* + * FUNCTION: _nscd_add_int_addr + * + * Add an address of 'type' to the internal address database. + */ +nscd_rc_t +_nscd_add_int_addr( + void *ptr, + int type, + nscd_seq_num_t seq_num) +{ + int size; + char buf[2 * sizeof (ptr) + 1]; + nscd_db_entry_t *db_entry; + nscd_int_addr_t *int_addr; + + if (ptr == NULL) + return (NSCD_INVALID_ARGUMENT); + + (void) snprintf(buf, sizeof (buf), "%p", ptr); + + size = sizeof (*int_addr); + + db_entry = _nscd_alloc_db_entry(NSCD_DATA_ADDR, + (const char *)buf, size, 1, 1); + if (db_entry == NULL) + return (NSCD_NO_MEMORY); + + int_addr = (nscd_int_addr_t *)*(db_entry->data_array); + int_addr->ptr = ptr; + int_addr->type = type; + int_addr->seq_num = seq_num; + (void) rwlock_init(&int_addr->rwlock, USYNC_THREAD, NULL); + + (void) rw_wrlock(&addrDB_rwlock); + (void) _nscd_add_db_entry(addrDB, buf, db_entry, + NSCD_ADD_DB_ENTRY_FIRST); + (void) rw_unlock(&addrDB_rwlock); + + return (NSCD_SUCCESS); +} + +/* + * FUNCTION: _nscd_is_int_addr + * + * Check to see if an address can be found in the internal + * address database, if so, obtain a reader lock on the + * associated rw_lock. The caller needs to unlock it when + * done using the data. + */ +rwlock_t * +_nscd_is_int_addr( + void *ptr, + nscd_seq_num_t seq_num) +{ + char *me = "_nscd_is_int_addr"; + char ptrstr[1 + 2 * sizeof (ptr)]; + rwlock_t *addr_rwlock; + const nscd_db_entry_t *db_entry; + + if (ptr == NULL) + return (NULL); + + (void) snprintf(ptrstr, sizeof (ptrstr), "%p", ptr); + + (void) rw_rdlock(&addrDB_rwlock); + + db_entry = _nscd_get_db_entry(addrDB, NSCD_DATA_ADDR, + (const char *)ptrstr, NSCD_GET_FIRST_DB_ENTRY, 0); + + if (db_entry != NULL) { + nscd_int_addr_t *int_addr; + + int_addr = (nscd_int_addr_t *)*(db_entry->data_array); + addr_rwlock = &int_addr->rwlock; + (void) rw_rdlock(addr_rwlock); + + /* + * If the data is marked as to be deleted + * or the sequence number does not match, + * return NULL. + */ + if (int_addr->to_delete == 1 || + int_addr->seq_num != seq_num) { + (void) rw_unlock(addr_rwlock); + addr_rwlock = NULL; + } + + _NSCD_LOG(NSCD_LOG_INT_ADDR, NSCD_LOG_LEVEL_DEBUG) + (me, "found %p, seq# = %lld\n", ptr, int_addr->seq_num); + } else + addr_rwlock = NULL; + + (void) rw_unlock(&addrDB_rwlock); + + return (addr_rwlock); +} + +/* + * FUNCTION: _nscd_del_int_addr + * + * Delete an address from the internal address database. + */ +void +_nscd_del_int_addr( + void *ptr, + nscd_seq_num_t seq_num) +{ + char *me = "_nscd_del_int_addr"; + char ptrstr[1 + 2 * sizeof (ptr)]; + rwlock_t *addr_rwlock; + nscd_int_addr_t *int_addr; + const nscd_db_entry_t *db_entry; + + if (ptr == NULL) + return; + + _NSCD_LOG(NSCD_LOG_INT_ADDR, NSCD_LOG_LEVEL_DEBUG) + (me, "deleting int addr %p (%d)\n", ptr, seq_num); + (void) snprintf(ptrstr, sizeof (ptrstr), "%p", ptr); + + (void) rw_rdlock(&addrDB_rwlock); + /* + * first find the db entry and make sure that + * no one is currently locking it. i.e., + * no one is waiting to use the same address. + * If it is locked, rw_wrlock() will not return + * until it is unlocked. + */ + db_entry = _nscd_get_db_entry(addrDB, + NSCD_DATA_ADDR, + (const char *)ptrstr, + NSCD_GET_FIRST_DB_ENTRY, 0); + if (db_entry != NULL) { + int_addr = (nscd_int_addr_t *)*(db_entry->data_array); + addr_rwlock = &int_addr->rwlock; + (void) rw_wrlock(addr_rwlock); + } else { + (void) rw_unlock(&addrDB_rwlock); + return; + } + (void) rw_unlock(&addrDB_rwlock); + + /* + * delete the db entry if the sequence numbers match + */ + if (int_addr->seq_num == seq_num) { + (void) rw_wrlock(&addrDB_rwlock); + (void) _nscd_delete_db_entry(addrDB, + NSCD_DATA_ADDR, + (const char *)ptrstr, + NSCD_DEL_FIRST_DB_ENTRY, 0); + (void) rw_unlock(&addrDB_rwlock); + } +} + +/* + * FUNCTION: _nscd_destroy_int_addrDB + * + * Destroy the internal address database. + */ +void +_nscd_destroy_int_addrDB() +{ + (void) rw_wrlock(&addrDB_rwlock); + _nscd_free_db(addrDB); + addrDB = NULL; + (void) rw_unlock(&addrDB_rwlock); +} diff --git a/usr/src/cmd/nscd/nscd_log.c b/usr/src/cmd/nscd/nscd_log.c new file mode 100644 index 0000000000..748fcb2ddb --- /dev/null +++ b/usr/src/cmd/nscd/nscd_log.c @@ -0,0 +1,427 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <stdlib.h> +#include <locale.h> +#include <limits.h> +#include <fcntl.h> +#include <sys/stat.h> +#include <sys/varargs.h> +#include <synch.h> +#include <thread.h> +#include <string.h> +#include <unistd.h> +#include "nscd_log.h" +#include "nscd_config.h" +#include "nscd_switch.h" +#include "cache.h" + +/* + * old nscd debug levels + */ +#define DBG_OFF 0 +#define DBG_CANT_FIND 2 +#define DBG_NETLOOKUPS 4 +#define DBG_ALL 6 + +/* max. chars in a nscd log entry */ +#define LOGBUFLEN 1024 + +/* configuration for the nscd log component */ +int _nscd_log_comp = 0x0; +int _nscd_log_level = 0x0; +static char logfile[PATH_MAX]; + +/* statistics data */ +static nscd_cfg_stat_global_log_t logstats = { + NSCD_CFG_STAT_GROUP_INFO_GLOBAL_LOG, 0 }; + +/* if no log file specified, log entry goes to stderr */ +int _logfd = 2; + +/* close old log file and open a new one */ +static nscd_rc_t +_nscd_set_lf( + char *lf) +{ + int newlogfd; + char *me = "_nscd_set_lf"; + + /* + * don't try and open the log file /dev/null + */ + if (lf == NULL || *lf == 0) { + /* ignore empty log file specs */ + return (NSCD_SUCCESS); + } else if (strcmp(lf, "/dev/null") == 0) { + (void) strlcpy(logfile, lf, PATH_MAX); + if (_logfd >= 0) + (void) close(_logfd); + _logfd = -1; + return (NSCD_SUCCESS); + } else if (strcmp(lf, "stderr") == 0) { + (void) strlcpy(logfile, lf, PATH_MAX); + if (_logfd != -1 && _logfd != 2) + (void) close(_logfd); + _logfd = 2; + return (NSCD_SUCCESS); + } else { + + /* + * In order to open this file securely, we'll try a few tricks + */ + + if ((newlogfd = open(lf, O_EXCL|O_WRONLY|O_CREAT, 0644)) < 0) { + /* + * File already exists... now we need to get cute + * since opening a file in a world-writeable directory + * safely is hard = it could be a hard link or a + * symbolic link to a system file. + */ + struct stat before; + + if (lstat(lf, &before) < 0) { + _nscd_logit(me, "Cannot open new " + "logfile \"%s\": %sn", lf, strerror(errno)); + return (NSCD_CFG_FILE_OPEN_ERROR); + } + + if (S_ISREG(before.st_mode) && /* no symbolic links */ + (before.st_nlink == 1) && /* no hard links */ + (before.st_uid == 0)) { /* owned by root */ + if ((newlogfd = + open(lf, O_APPEND|O_WRONLY, 0644)) < 0) { + _nscd_logit(me, "Cannot open new "\ + "logfile \"%s\": %s\n", lf, + strerror(errno)); + return (NSCD_CFG_FILE_OPEN_ERROR); + } + } else { + _nscd_logit(me, "Cannot use specified " + "logfile \"%s\": "\ + "file is/has links or isn't owned by "\ + "root\n", lf); + return (NSCD_CFG_FILE_OPEN_ERROR); + } + } + + (void) close(_logfd); + (void) strlcpy(logfile, lf, PATH_MAX); + _logfd = newlogfd; + _nscd_logit(me, "Start of new logfile %s\n", lf); + } + return (NSCD_SUCCESS); +} + + +/* log an entry to the configured nscd log file */ +void +_nscd_logit( + char *funcname, + char *format, + ...) +{ + static mutex_t loglock = DEFAULTMUTEX; + struct timeval tv; + char tid_buf[32]; + char pid_buf[32]; + char buffer[LOGBUFLEN]; + int safechars, offset; + va_list ap; + + if (_logfd < 0) + return; + + va_start(ap, format); + + if (gettimeofday(&tv, NULL) != 0 || + ctime_r(&tv.tv_sec, buffer, LOGBUFLEN) == NULL) { + (void) snprintf(buffer, LOGBUFLEN, + "<time conversion failed>\t"); + } else { + (void) sprintf(tid_buf, "--%d", thr_self()); + (void) sprintf(pid_buf, "--%ld", getpid()); + /* + * ctime_r() includes some stuff we don't want; + * adjust length to overwrite " YYYY\n" and + * include tid string length. + */ + offset = strlen(buffer) - 6; + safechars = LOGBUFLEN - (offset - 1); + (void) snprintf(buffer + offset, + safechars, ".%.4ld%s%s\t%s:\n\t\t", + tv.tv_usec/100, tid_buf, pid_buf, + funcname); + } + offset = strlen(buffer); + safechars = LOGBUFLEN - (offset - 1); + /*LINTED: E_SEC_PRINTF_VAR_FMT*/ + if (vsnprintf(buffer + offset, safechars, format, ap) > + safechars) { + (void) strncat(buffer, "...\n", LOGBUFLEN); + } + + (void) mutex_lock(&loglock); + (void) write(_logfd, buffer, strlen(buffer)); + logstats.entries_logged++; + (void) mutex_unlock(&loglock); + + va_end(ap); +} + + +/* ARGSUSED */ +nscd_rc_t +_nscd_cfg_log_notify( + void *data, + struct nscd_cfg_param_desc *pdesc, + nscd_cfg_id_t *nswdb, + nscd_cfg_flag_t dflag, + nscd_cfg_error_t **errorp, + void *cookie) +{ + + nscd_cfg_global_log_t *logcfg; + int off; + + /* + * At init time, the whole group of config params are received. + * At update time, group or individual parameter value could + * be received. + */ + + if (_nscd_cfg_flag_is_set(dflag, NSCD_CFG_DFLAG_GROUP)) { + + logcfg = (nscd_cfg_global_log_t *)data; + + _nscd_log_comp = logcfg->debug_comp; + _nscd_log_level = logcfg->debug_level; + + /* + * logcfg->logfile should have been opened + * by _nscd_cfg_log_verify() + */ + + return (NSCD_SUCCESS); + } + + /* + * individual config parameter + */ + off = offsetof(nscd_cfg_global_log_t, debug_comp); + if (pdesc->p_offset == off) { + _nscd_log_comp = *(nscd_cfg_bitmap_t *)data; + return (NSCD_SUCCESS); + } + + off = offsetof(nscd_cfg_global_log_t, debug_level); + if (pdesc->p_offset == off) + _nscd_log_level = *(nscd_cfg_bitmap_t *)data; + + /* + * logcfg->logfile should have been opened + * by _nscd_cfg_log_verify() + */ + + return (NSCD_SUCCESS); +} + +/* ARGSUSED */ +nscd_rc_t +_nscd_cfg_log_verify( + void *data, + struct nscd_cfg_param_desc *pdesc, + nscd_cfg_id_t *nswdb, + nscd_cfg_flag_t dflag, + nscd_cfg_error_t **errorp, + void **cookie) +{ + nscd_cfg_global_log_t *logcfg; + nscd_cfg_bitmap_t bt; + int off; + + /* + * There is no switch db specific config params + * for the nscd log component. It is a bug if + * the input param description is global. + */ + if (_nscd_cfg_flag_is_not_set(pdesc->pflag, NSCD_CFG_PFLAG_GLOBAL)) + return (NSCD_CFG_PARAM_DESC_ERROR); + + /* + * At init time, the whole group of config params are received. + * At update time, group or individual parameter value could + * be received. + */ + + if (_nscd_cfg_flag_is_set(dflag, NSCD_CFG_DFLAG_GROUP)) { + + logcfg = (nscd_cfg_global_log_t *)data; + + if (_nscd_cfg_bitmap_valid(logcfg->debug_comp, + NSCD_LOG_ALL) == 0) + return (NSCD_CFG_SYNTAX_ERROR); + + if (_nscd_cfg_bitmap_valid(logcfg->debug_level, + NSCD_LOG_LEVEL_ALL) == 0) + return (NSCD_CFG_SYNTAX_ERROR); + + if (logcfg->logfile != NULL) + return (_nscd_set_lf(logcfg->logfile)); + + return (NSCD_SUCCESS); + } + + /* + * individual config parameter + */ + + off = offsetof(nscd_cfg_global_log_t, debug_comp); + if (pdesc->p_offset == off) { + + bt = *(nscd_cfg_bitmap_t *)data; + if (_nscd_cfg_bitmap_valid(bt, NSCD_LOG_ALL) == 0) + return (NSCD_CFG_SYNTAX_ERROR); + + return (NSCD_SUCCESS); + } + + off = offsetof(nscd_cfg_global_log_t, debug_level); + if (pdesc->p_offset == off) { + + bt = *(nscd_cfg_bitmap_t *)data; + if (_nscd_cfg_bitmap_valid(bt, NSCD_LOG_LEVEL_ALL) == 0) + return (NSCD_CFG_SYNTAX_ERROR); + + return (NSCD_SUCCESS); + } + + off = offsetof(nscd_cfg_global_log_t, logfile); + if (pdesc->p_offset == off) { + if (data != NULL) + return (_nscd_set_lf((char *)data)); + else + return (NSCD_SUCCESS); + } + + return (NSCD_CFG_PARAM_DESC_ERROR); +} + +/* ARGSUSED */ +nscd_rc_t +_nscd_cfg_log_get_stat( + void **stat, + struct nscd_cfg_stat_desc *sdesc, + nscd_cfg_id_t *nswdb, + nscd_cfg_flag_t *dflag, + void (**free_stat)(void *stat), + nscd_cfg_error_t **errorp) +{ + + *(nscd_cfg_stat_global_log_t **)stat = &logstats; + + /* indicate the statistics are static, i.e., do not free */ + *dflag = _nscd_cfg_flag_set(*dflag, NSCD_CFG_DFLAG_STATIC_DATA); + + return (NSCD_SUCCESS); +} + +/* + * set the name of the current log file and make it current. + */ +nscd_rc_t +_nscd_set_log_file( + char *name) +{ + nscd_rc_t rc; + nscd_cfg_handle_t *h; + + rc = _nscd_cfg_get_handle("logfile", NULL, &h, NULL); + if (rc != NSCD_SUCCESS) + return (rc); + + rc = _nscd_cfg_set(h, name, NULL); + _nscd_cfg_free_handle(h); + if (rc != NSCD_SUCCESS) + exit(rc); + + return (NSCD_SUCCESS); +} + +/* + * Map old nscd debug level to new one and make it current. + * -- debug component: NSCD_LOG_CACHE + * -- debug level: + * -- DBG_OFF --> NSCD_LOG_LEVEL_NONE + * -- DBG_CANT_FIND --> NSCD_LOG_LEVEL_ERROR + * -- DBG_DBG_NETLOOKUPS --> NSCD_LOG_LEVEL_ERROR + * -- DBG_ALL --> NSCD_LOG_LEVEL_ALL + */ +nscd_rc_t +_nscd_set_debug_level( + int level) +{ + nscd_rc_t rc; + nscd_cfg_handle_t *h; + int l; + int c; + + rc = _nscd_cfg_get_handle("debug-components", NULL, &h, NULL); + if (rc != NSCD_SUCCESS) + return (rc); + c = NSCD_LOG_CACHE; + + if (level < 0) + c = -1 * level / 10000; + rc = _nscd_cfg_set(h, &c, NULL); + _nscd_cfg_free_handle(h); + if (rc != NSCD_SUCCESS) + exit(rc); + + rc = _nscd_cfg_get_handle("debug-level", NULL, &h, NULL); + if (rc != NSCD_SUCCESS) + return (rc); + + if (level == DBG_OFF) + l = NSCD_LOG_LEVEL_NONE; + else if (level >= DBG_CANT_FIND) + l = NSCD_LOG_LEVEL_ERROR; + else if (level >= DBG_NETLOOKUPS) + l = NSCD_LOG_LEVEL_ERROR; + else if (level >= DBG_ALL) + l = NSCD_LOG_LEVEL_ALL; + + if (level < 0) + l = -1 * level % 10000; + + rc = _nscd_cfg_set(h, &l, NULL); + _nscd_cfg_free_handle(h); + if (rc != NSCD_SUCCESS) + exit(rc); + + return (NSCD_SUCCESS); +} diff --git a/usr/src/cmd/nscd/nscd_log.h b/usr/src/cmd/nscd/nscd_log.h new file mode 100644 index 0000000000..784c74cf01 --- /dev/null +++ b/usr/src/cmd/nscd/nscd_log.h @@ -0,0 +1,96 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _NSCD_LOG_H +#define _NSCD_LOG_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + +#include "nscd_common.h" + +/* + * nscd logging options + */ +/* + * components: select more than one by OR'ing + */ +#define NSCD_LOG_NONE 0x0000 +#define NSCD_LOG_ACCESS_INFO 0x0001 +#define NSCD_LOG_INT_ADDR 0x0002 +#define NSCD_LOG_NSW_STATE 0x0004 +#define NSCD_LOG_GETENT_CTX 0x0008 +#define NSCD_LOG_SWITCH_ENGINE 0x0010 +#define NSCD_LOG_CONFIG 0x0020 +#define NSCD_LOG_FRONT_END 0x0040 +#define NSCD_LOG_CACHE 0x0080 +#define NSCD_LOG_SMF_MONITOR 0x0100 +#define NSCD_LOG_ADMIN 0x0200 +#define NSCD_LOG_SELF_CRED 0x0400 +#define NSCD_LOG_ALL 0x07ff + +/* + * debug level: select more than one by OR'ing + */ +#define NSCD_LOG_LEVEL_NONE 0x0000 +#define NSCD_LOG_LEVEL_CANT_FOUND 0x0001 +#define NSCD_LOG_LEVEL_ALERT 0x0002 +#define NSCD_LOG_LEVEL_CRIT 0x0004 +#define NSCD_LOG_LEVEL_ERROR 0x0008 +#define NSCD_LOG_LEVEL_WARNING 0x0010 +#define NSCD_LOG_LEVEL_NOTICE 0x0020 +#define NSCD_LOG_LEVEL_INFO 0x0040 +#define NSCD_LOG_LEVEL_DEBUG 0x0080 +#define NSCD_LOG_LEVEL_ALL 0x00ff + +/* + * _nscd_log_comp and _nscd_log_level defined in nscd_log.c + */ +extern int _nscd_log_comp; +extern int _nscd_log_level; + +#define _NSCD_LOG(comp, lvl) if ((_nscd_log_comp & (comp)) && \ + (_nscd_log_level & (lvl))) \ + _nscd_logit + +#define _NSCD_LOG_IF(comp, lvl) if ((_nscd_log_comp & (comp)) && \ + (_nscd_log_level & (lvl))) + + +/* + * prototypes + */ +void _nscd_logit(char *funcname, char *format, ...); +nscd_rc_t _nscd_set_debug_level(int level); +nscd_rc_t _nscd_set_log_file(char *name); + +#ifdef __cplusplus +} +#endif + +#endif /* _NSCD_LOG_H */ diff --git a/usr/src/cmd/nscd/nscd_nswcfgst.c b/usr/src/cmd/nscd/nscd_nswcfgst.c new file mode 100644 index 0000000000..7659b9706d --- /dev/null +++ b/usr/src/cmd/nscd/nscd_nswcfgst.c @@ -0,0 +1,262 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <stdlib.h> +#include <locale.h> +#include <string.h> +#include "nscd_config.h" +#include "nscd_log.h" +#include "nscd_switch.h" + +/* + * Configuration data for the nscd switch functions. + */ +nscd_cfg_global_switch_t nscd_switch_cfg_g; +nscd_cfg_switch_t *nscd_switch_cfg; + +/* + * statistics of the nscd switch functions. + */ +nscd_cfg_stat_global_switch_t nscd_switch_stats_g; +nscd_cfg_stat_switch_t *nscd_switch_stats; + +/* + * cookie is set up by the verify function for passing to + * the notify function + */ +typedef struct { + struct __nsw_switchconfig_v1 *cfg; + char *cfgstr; +} nsw_cfg_cookie_t; + +nscd_rc_t +_nscd_alloc_switch_cfg() +{ + nscd_switch_cfg = calloc(NSCD_NUM_DB, sizeof (nscd_cfg_switch_t)); + if (nscd_switch_cfg == NULL) + return (NSCD_NO_MEMORY); + + return (NSCD_SUCCESS); +} + +nscd_rc_t +_nscd_alloc_switch_stats() +{ + + nscd_switch_stats = calloc(NSCD_NUM_DB, + sizeof (nscd_cfg_stat_switch_t)); + if (nscd_switch_stats == NULL) + return (NSCD_NO_MEMORY); + + return (NSCD_SUCCESS); +} + +/* ARGSUSED */ +nscd_rc_t +_nscd_cfg_switch_notify( + void *data, + struct nscd_cfg_param_desc *pdesc, + nscd_cfg_id_t *nswdb, + nscd_cfg_flag_t dflag, + nscd_cfg_error_t **errorp, + void *cookie) +{ + + void *dp; + nscd_rc_t rc; + nsw_cfg_cookie_t *ck = (nsw_cfg_cookie_t *)cookie; + + if (_nscd_cfg_flag_is_set(dflag, NSCD_CFG_DFLAG_INIT) || + _nscd_cfg_flag_is_set(dflag, NSCD_CFG_DFLAG_GROUP)) { + /* + * group data is received, copy in the + * entire strcture + */ + if (_nscd_cfg_flag_is_set(pdesc->pflag, + NSCD_CFG_PFLAG_GLOBAL)) { + nscd_switch_cfg_g = *(nscd_cfg_global_switch_t *)data; + } else { + nscd_switch_cfg[nswdb->index] = + *(nscd_cfg_switch_t *)data; + + } + } else { + /* + * individual paramater is received: copy in the + * parameter value except for nsw-config-string. + */ + if (_nscd_cfg_flag_is_set(pdesc->pflag, + NSCD_CFG_PFLAG_GLOBAL)) { + dp = (char *)&nscd_switch_cfg_g + pdesc->p_offset; + (void) memcpy(dp, data, pdesc->p_size); + } else { + dp = (char *)&nscd_switch_cfg[nswdb->index] + + pdesc->p_offset; + if (pdesc->p_offset != + offsetof(nscd_cfg_switch_t, nsw_config_string)) + (void) memcpy(dp, data, pdesc->p_size); + } + } + + /* + * cookie contains data for the switch policy config + */ + if (cookie != NULL) { + rc = _nscd_create_sw_struct(nswdb->index, nswdb->name, + ck->cfgstr, ck->cfg, NULL); + if (rc != NSCD_SUCCESS) { + (void) __nsw_freeconfig_v1(ck->cfg); + free(ck); + return (rc); + } + free(ck); + } + + if (_nscd_cfg_flag_is_not_set(dflag, NSCD_CFG_DFLAG_STATIC_DATA)) + free(data); + + return (NSCD_SUCCESS); +} + +/* ARGSUSED */ +nscd_rc_t +_nscd_cfg_switch_verify( + void *data, + struct nscd_cfg_param_desc *pdesc, + nscd_cfg_id_t *nswdb, + nscd_cfg_flag_t dflag, + nscd_cfg_error_t **errorp, + void **cookie) +{ + char *me = "_nscd_cfg_switch_verify"; + nscd_cfg_switch_t *cfg; + char *nswcfgstr; + int size; + struct __nsw_switchconfig_v1 *switchcfg = NULL; + enum __nsw_parse_err err; + nsw_cfg_cookie_t *ck; + char buf[MAX_NSSWITCH_CONFIG_STRING_SZ]; + char msg[NSCD_CFG_MAX_ERR_MSG_LEN]; + + /* + * global config data has nothing special to verify + */ + if (_nscd_cfg_flag_is_set(pdesc->pflag, NSCD_CFG_PFLAG_GLOBAL)) + return (NSCD_SUCCESS); + + *cookie = NULL; + + /* + * switch policy string is the one to parse and verify + */ + + if (_nscd_cfg_flag_is_set(dflag, NSCD_CFG_DFLAG_INIT) || + _nscd_cfg_flag_is_set(dflag, NSCD_CFG_DFLAG_GROUP)) { + + /* get it from the group data */ + cfg = (nscd_cfg_switch_t *)data; + nswcfgstr = cfg->nsw_config_string; + } else { + /* not group, and not the switch policy string, return */ + if (pdesc->p_offset != offsetof(nscd_cfg_switch_t, + nsw_config_string)) + return (NSCD_SUCCESS); + + /* the data itself is the string */ + nswcfgstr = (char *)data; + } + + /* + * convert the string into struct __nsw_switchconfig_v1 + */ + size = MAX_NSSWITCH_CONFIG_STRING_SZ; + if (strlcpy(buf, nswcfgstr, size) >= size) { + + (void) snprintf(msg, sizeof (msg), + gettext("switch policy string too long (\"%s : %s\" > %d)"), + nswdb->name, nswcfgstr, size); + + _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR) + (me, "%s\n", msg); + + if (*errorp) + *errorp = _nscd_cfg_make_error( + NSCD_CFG_SYNTAX_ERROR, msg); + + return (NSCD_CFG_SYNTAX_ERROR); + } + switchcfg = _nsw_getoneconfig_v1(nswdb->name, buf, &err); + if (switchcfg == NULL) { + + (void) snprintf(msg, sizeof (msg), + gettext("syntax error: switch policy string (%s : %s) rc = %d"), + nswdb->name, nswcfgstr, err); + + _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR) + (me, "%s\n", msg); + + if (*errorp) + *errorp = _nscd_cfg_make_error( + NSCD_CFG_SYNTAX_ERROR, msg); + + return (NSCD_CFG_SYNTAX_ERROR); + } + + /* save the __nsw_switchconfig_v1 for the notify function */ + ck = calloc(1, sizeof (nsw_cfg_cookie_t)); + if (ck == NULL) { + (void) __nsw_freeconfig_v1(switchcfg); + return (NSCD_CFG_SYNTAX_ERROR); + } + ck->cfg = switchcfg; + ck->cfgstr = nswcfgstr; + *cookie = ck; + + return (NSCD_SUCCESS); +} + +/* ARGSUSED */ +nscd_rc_t +_nscd_cfg_switch_get_stat( + void **stat, + struct nscd_cfg_stat_desc *sdesc, + nscd_cfg_id_t *nswdb, + nscd_cfg_flag_t *dflag, + void (**free_stat)(void *stat), + nscd_cfg_error_t **errorp) +{ + + if (_nscd_cfg_flag_is_set(sdesc->sflag, NSCD_CFG_SFLAG_GLOBAL)) { + *stat = &NSCD_SW_STATS_G; + } else + *stat = &NSCD_SW_STATS(nswdb->index); + + /* indicate the statistics are static, i.e., do not free */ + *dflag = _nscd_cfg_flag_set(*dflag, NSCD_CFG_DFLAG_STATIC_DATA); + + return (NSCD_SUCCESS); +} diff --git a/usr/src/cmd/nscd/nscd_nswconfig.c b/usr/src/cmd/nscd/nscd_nswconfig.c new file mode 100644 index 0000000000..f6e669324d --- /dev/null +++ b/usr/src/cmd/nscd/nscd_nswconfig.c @@ -0,0 +1,686 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <stdlib.h> +#include <libscf_priv.h> +#include <string.h> +#include <assert.h> +#include "nscd_switch.h" +#include "nscd_log.h" +#include "nscd_db.h" + +/* + * nscd database for each source. It contains backend + * info (nscd_be_info_t) for each naming database. + * Protected by nscd_src_backend_db_lock. + */ +nscd_db_t ***nscd_src_backend_db; +static rwlock_t nscd_src_backend_db_lock = DEFAULTRWLOCK; + +/* + * nsswitch config monitored by nscd. Protected by + * readers/writer lock nscd_nsw_config_lock + */ +nscd_nsw_config_t ***nscd_nsw_config; +static rwlock_t nscd_nsw_config_lock = DEFAULTRWLOCK; + +/* + * nsswitch source index/name array + * (allow 16 user-defined nsswitch sources/backends) + */ +#define NSCD_NUM_SRC_UDEF 16 +nscd_cfg_id_t *_nscd_cfg_nsw_src_all; +int _nscd_cfg_num_nsw_src_all; + +static void +free_nscd_nsw_config( + nscd_acc_data_t *data) +{ + + nscd_nsw_config_t *nsw_cfg = *(nscd_nsw_config_t **)data; + char *me = "free_nscd_nsw_config"; + + _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG) + (me, "freeing nscd nsw config %p \n", nsw_cfg); + if (nsw_cfg == NULL) + return; + + if (nsw_cfg->db_name != NULL) + free(nsw_cfg->db_name); + if (nsw_cfg->nsw_cfg_str != NULL) + free(nsw_cfg->nsw_cfg_str); + if (nsw_cfg->nsw_config != NULL) + (void) __nsw_freeconfig_v1(nsw_cfg->nsw_config); + if (nsw_cfg->src_idx != NULL) + free(nsw_cfg->src_idx); + + free(nsw_cfg); +} + + +void +_nscd_free_nsw_config( + nscd_nsw_config_t *nswcfg) +{ + free_nscd_nsw_config((nscd_acc_data_t *)&nswcfg); +} + +void +_nscd_free_all_nsw_config() +{ + + nscd_nsw_config_t **nsw_cfg; + int i; + char *me = "_nscd_free_all_nsw_config"; + + _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG) + (me, "freeing all nscd nsw config \n"); + + (void) rw_wrlock(&nscd_nsw_config_lock); + for (i = 0; i < NSCD_NUM_DB; i++) { + + if ((nsw_cfg = nscd_nsw_config[i]) == NULL) + continue; + + nscd_nsw_config[i] = (nscd_nsw_config_t **)_nscd_set( + (nscd_acc_data_t *)nsw_cfg, NULL); + } + (void) rw_unlock(&nscd_nsw_config_lock); +} + + +static void +free_nsw_backend_info_db(nscd_acc_data_t *data) +{ + + nscd_db_t *db = *(nscd_db_t **)data; + char *me = "free_nsw_backend_info_db"; + + _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG) + (me, "freeing nsw backend info db %p\n", db); + + if (db == NULL) + return; + + _nscd_free_db(db); + +} + +void +_nscd_free_all_nsw_backend_info_db() +{ + + nscd_db_t **db; + int i; + char *me = " _nscd_free_all_nsw_backend_info_db"; + + _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG) + (me, "freeing all nsw backend info db\n"); + + (void) rw_wrlock(&nscd_src_backend_db_lock); + for (i = 0; i < NSCD_NUM_SRC; i++) { + + if ((db = nscd_src_backend_db[i]) == NULL) + continue; + + nscd_src_backend_db[i] = (nscd_db_t **)_nscd_set( + (nscd_acc_data_t *)db, NULL); + } + (void) rw_unlock(&nscd_src_backend_db_lock); +} + +/* + * Populate the backend info db for the 'NSCD_NSW_SRC_NAME(srci)' + * source. Create one entry for each source/database pair + * (e.g., ldap:passwd, nis:hosts, etc). + */ +static nscd_rc_t +_nscd_populate_nsw_backend_info_db(int srci) +{ + nscd_be_info_t be_info, *bi; + nss_backend_finder_t *bf; + nscd_nsw_config_t *nsw_cfg; + int i, size; + nscd_db_entry_t *db_entry; + char *src = NSCD_NSW_SRC_NAME(srci); + const char *dbn; + char *me = "_nscd_populate_nsw_backend_info_db"; + + for (i = 0; i < NSCD_NUM_DB; i++) { + + if (nscd_nsw_config[i] == NULL) + continue; + + nsw_cfg = *nscd_nsw_config[i]; + dbn = NSCD_NSW_DB_NAME(i); + _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG) + (me, "adding backend info for <%s : %s>\n", src, dbn); + + (void) memset(&be_info, 0, sizeof (be_info)); + + for (bf = nsw_cfg->fe_params.finders; bf != 0; + bf = bf->next) { + nss_backend_constr_t c; + + c = (*bf->lookup)(bf->lookup_priv, dbn, src, + &be_info.finder_priv); + + if (c != 0) { + be_info.be_constr = c; + be_info.finder = bf; + break; + } + } + if (be_info.be_constr == NULL) { + /* + * Couldn't find the backend anywhere. + * This is fine, some backend just don't + * support certain databases. + */ + _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR) + (me, "unable to find backend info " + "for <%s : %s>\n", src, dbn); + } + + size = sizeof (nscd_be_info_t); + + db_entry = _nscd_alloc_db_entry(NSCD_DATA_BACKEND_INFO, + dbn, size, 1, 1); + + if (db_entry == NULL) { + _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR) + (me, "unable to allocate db entry for " + "<%s : %s>\n", src, dbn); + return (NSCD_NO_MEMORY); + } + + _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG) + (me, "adding be db entry %p for <%s : %s> to db %p: " + "constr = %p\n", db_entry, src, dbn, + *nscd_src_backend_db[srci], be_info.be_constr); + + bi = (nscd_be_info_t *)*(db_entry->data_array); + *bi = be_info; + + (void) _nscd_rdlock((nscd_acc_data_t *) + nscd_src_backend_db[srci]); + (void) _nscd_add_db_entry(*nscd_src_backend_db[srci], + dbn, db_entry, NSCD_ADD_DB_ENTRY_LAST); + (void) _nscd_rw_unlock((nscd_acc_data_t *) + nscd_src_backend_db[srci]); + } + + return (NSCD_SUCCESS); +} + +/* + * create data structures (used by the switch engine) based + * on the input switch policy configuration and database + * name and indexes + */ +nscd_rc_t +_nscd_create_sw_struct( + int dbi, + const char *dbn, + const char *cfgstr, + void *swcfgv1, + nscd_nsw_params_t *params) +{ + char *me = "_nscd_create_sw_struct"; + nscd_rc_t rc = NSCD_SUCCESS; + nscd_nsw_config_t *nsw_cfg = NULL; + nscd_nsw_config_t **nsw_cfg_p = NULL; + struct __nsw_switchconfig_v1 *swcfg = NULL; + struct __nsw_lookup_v1 *lkp; + enum __nsw_parse_err err; + int maxsrc; + int *src_idx_a = NULL; + int j, k; + + /* + * if the nsw config string has been parsed into + * a struct __nsw_switchconfig_v1, use it. If not, + * create the struct. + */ + if (swcfgv1 != NULL) + swcfg = (struct __nsw_switchconfig_v1 *)swcfgv1; + else { + char *cstr; + + cstr = strdup(cfgstr); + if (cstr == NULL) + return (NSCD_NO_MEMORY); + + /* + * parse the nsw config string and create + * a struct __nsw_switchconfig_v1 + */ + swcfg = _nsw_getoneconfig_v1(dbn, cstr, &err); + free(cstr); + if (swcfg == NULL) { + rc = NSCD_CFG_SYNTAX_ERROR; + _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR) + (me, "error: unable to process nsw config string\n"); + goto error_exit; + } + } + + /* allocate the space for a nscd_nsw_config_t */ + nsw_cfg = calloc(1, sizeof (nscd_nsw_config_t)); + if (nsw_cfg == NULL) { + rc = NSCD_NO_MEMORY; + _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR) + (me, "error: unable to allocate an nscd_nsw_config_t\n"); + goto error_exit; + } + + /* need to know how many backends (sources) */ + maxsrc = swcfg->num_lookups; + nsw_cfg->max_src = maxsrc; + + /* + * allocate an array to store the index for each + * backend (source) + */ + src_idx_a = calloc(1, maxsrc * sizeof (int)); + if (src_idx_a == NULL) { + rc = NSCD_NO_MEMORY; + _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR) + (me, "error: unable to allocate an array for source index\n"); + goto error_exit; + } + + /* + * set the index for each backend (source) + */ + lkp = swcfg->lookups; + for (j = 0; j < maxsrc; j++) { + char *usrc; + + for (k = 0; k < NSCD_NUM_SRC && + NSCD_NSW_SRC_NAME(k) != NULL && + strcmp(lkp->service_name, + NSCD_NSW_SRC_NAME(k)) != 0; k++); + + if (k < NSCD_NUM_SRC && NSCD_NSW_SRC_NAME(k) == NULL) { + _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG) + (me, "unknown nsw source name %s\n", + lkp->service_name); + usrc = strdup(lkp->service_name); + if (usrc == NULL) { + rc = NSCD_NO_MEMORY; + _NSCD_LOG(NSCD_LOG_CONFIG, + NSCD_LOG_LEVEL_ERROR) + (me, "unable to strdup() source name\n"); + goto error_exit; + } + NSCD_NSW_SRC_NAME(k) = usrc; + + rc = _nscd_populate_nsw_backend_info_db(k); + if (rc != NSCD_SUCCESS) { + free(usrc); + NSCD_NSW_SRC_NAME(k) = NULL; + goto error_exit; + } + } else if (NSCD_NSW_SRC_NAME(k) == NULL) { + /* + * number of user-defined source exceeded + */ + rc = NSCD_CFG_SYNTAX_ERROR; + _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR) + (me, "error: number of user_defined source exceeded\n"); + + goto error_exit; + } + + _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG) + (me, "setting source index array [%d] = %d (%s)\n", + j, k, lkp->service_name); + + src_idx_a[j] = k; + + lkp = lkp->next; + if (lkp == NULL) break; + + _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG) + (me, "number of nsw sources = %d\n", nsw_cfg->max_src); + _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG) + (me, "next nsw source is %s\n", lkp->service_name); + } + + /* set it up to reference count the switch policy config */ + nsw_cfg_p = (nscd_nsw_config_t **)_nscd_alloc( + NSCD_DATA_NSW_CONFIG, + sizeof (nscd_nsw_config_t **), + free_nscd_nsw_config, + NSCD_ALLOC_RWLOCK); + + if (nsw_cfg_p == NULL) { + rc = NSCD_NO_MEMORY; + _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR) + (me, "unable to allocate a new nsw config DB\n"); + goto error_exit; + } + *nsw_cfg_p = nsw_cfg; + + _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG) + (me, "new nsw config DB %p allocated\n", nsw_cfg_p); + + /* save all the data in the new nscd_nsw_config_t */ + nsw_cfg->db_name = strdup(dbn); + nsw_cfg->nsw_cfg_str = strdup(cfgstr); + if (nsw_cfg->db_name == NULL || nsw_cfg->nsw_cfg_str == NULL) { + rc = NSCD_NO_MEMORY; + goto error_exit; + } + + _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG) + (me, "switch policy \"%s\" for database is \"%s\"\n", + nsw_cfg->db_name, nsw_cfg->nsw_cfg_str); + + nsw_cfg->nsw_config = swcfg; + nsw_cfg->src_idx = src_idx_a; + + /* + * set default frontend params and if necessary call initf() + * to initialize or override + */ + nsw_cfg->fe_params.max_active_per_src = 10; + nsw_cfg->fe_params.max_dormant_per_src = 1; + nsw_cfg->fe_params.finders = nss_default_finders; + if (params != NULL) { + nsw_cfg->fe_params = params->p; + + if (params->p.flags & NSS_USE_DEFAULT_CONFIG) { + params->nswcfg = nsw_cfg_p; + /* + * this nsw_cfg is not meant to last long, no need + * to set up the nsw state and getent bases, just + * exit with NSCD_SUCCESS + */ + nsw_cfg->nobase = 1; + goto error_exit; + } + } else + (void) (nscd_nss_db_initf[dbi])(&nsw_cfg->fe_params); + + /* + * activate the new nscd_nsw_config_t, the old one + * will either be deleted or left on the side (and be + * deleted eventually) + */ + nscd_nsw_config[dbi] = (nscd_nsw_config_t **)_nscd_set( + (nscd_acc_data_t *)nscd_nsw_config[dbi], + (nscd_acc_data_t *)nsw_cfg_p); + + /* + * also create a new nsw state base + */ + if ((rc = _nscd_init_nsw_state_base(dbi, 1)) != NSCD_SUCCESS) { + _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR) + (me, "unable to initialize a nsw state base(%d)\n", dbi); + goto error_exit; + } + + _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG) + (me, "new nsw state base(%d) %p created\n", dbi, + nscd_nsw_state_base[dbi]); + + /* + * also create a new getent context base + */ + if ((rc = _nscd_init_getent_ctx_base(dbi, 1)) != NSCD_SUCCESS) { + _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR) + (me, "unable to initialize a getent context base(%d)\n", dbi); + goto error_exit; + } + + _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG) + (me, "new getent context base(%d) %p created\n", dbi, + nscd_getent_ctx_base[dbi]); + + _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG) + (me, "new nsw config created (database = %s, " + "config = %s)\n", dbn, cfgstr); + + + error_exit: + + if (rc != NSCD_SUCCESS) { + + if (swcfgv1 == NULL && swcfg != NULL) + (void) __nsw_freeconfig_v1(swcfg); + if (src_idx_a != NULL) + free(src_idx_a); + if (nsw_cfg_p) + free(nsw_cfg_p); + if (nsw_cfg != NULL) { + if (nsw_cfg->db_name != NULL) + free(nsw_cfg->db_name); + if (nsw_cfg->nsw_cfg_str != NULL) + free(nsw_cfg->nsw_cfg_str); + free(nsw_cfg); + } + + return (rc); + } else + return (NSCD_SUCCESS); +} + +static nscd_rc_t +create_nsw_config(int dbi) +{ + + nscd_nsw_config_t *nsw_cfg = NULL; + nscd_nsw_config_t **nsw_cfg_p = NULL; + char *me = "create_nsw_config"; + + /* + * if pseudo-databases (initf function not defined), + * don't bother now + */ + if (nscd_nss_db_initf[dbi] == NULL) + return (NSCD_SUCCESS); + + /* allocate the space for a nscd_nsw_config_t */ + nsw_cfg = calloc(1, sizeof (nscd_nsw_config_t)); + if (nsw_cfg == NULL) { + _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR) + (me, "unable to allocate a nsw config structure\n"); + return (NSCD_NO_MEMORY); + } + _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG) + (me, "nsw config structure %pallocated\n", nsw_cfg); + + nsw_cfg_p = (nscd_nsw_config_t **)_nscd_alloc( + NSCD_DATA_NSW_CONFIG, + sizeof (nscd_nsw_config_t **), + free_nscd_nsw_config, + NSCD_ALLOC_RWLOCK); + + if (nsw_cfg_p == NULL) { + _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR) + (me, "unable to allocate a pointer to nsw config structure\n"); + return (NSCD_NO_MEMORY); + } + _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG) + (me, "nsw config pointer = %p\n", nsw_cfg_p); + + nsw_cfg->db_name = strdup(NSCD_NSW_DB_NAME(dbi)); + if (nsw_cfg->db_name == NULL) { + _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR) + (me, "unable to strdup the db name\n"); + return (NSCD_NO_MEMORY); + } + + /* + * set default frontend params and then call initf() + * to initialize or override + */ + nsw_cfg->fe_params.max_active_per_src = 10; + nsw_cfg->fe_params.max_dormant_per_src = 1; + nsw_cfg->fe_params.finders = nss_default_finders; + (void) (nscd_nss_db_initf[dbi])(&nsw_cfg->fe_params); + + /* + * activate the new nscd_nsw_config_t + */ + *nsw_cfg_p = nsw_cfg; + nscd_nsw_config[dbi] = (nscd_nsw_config_t **)_nscd_set( + (nscd_acc_data_t *)nscd_nsw_config[dbi], + (nscd_acc_data_t *)nsw_cfg_p); + + _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG) + (me, "nsw config %p activated\n", nsw_cfg); + + return (NSCD_SUCCESS); +} + +nscd_rc_t +_nscd_init_all_nsw_config(void) +{ + nscd_rc_t rc; + int i; + char *me = "_nscd_init_all_nsw_config"; + + _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG) + (me, "initializing all nsw config\n"); + + for (i = 0; i < NSCD_NUM_DB; i++) { + if ((rc = create_nsw_config(i)) != NSCD_SUCCESS) + return (rc); + } + + return (NSCD_SUCCESS); +} + +static nscd_rc_t +init_nsw_be_info_db(int srci) +{ + nscd_db_t *ret, **db_p; + char *me = "init_nsw_be_info_db"; + + ret = _nscd_alloc_db(NSCD_DB_SIZE_SMALL); + + if (ret == NULL) { + _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR) + (me, "unable to allocate a nsw be info database\n"); + return (NSCD_NO_MEMORY); + } + + /* set up to reference count the backend info db */ + db_p = (nscd_db_t **) + _nscd_alloc(NSCD_DATA_BACKEND_INFO_DB, + sizeof (nscd_db_t **), + free_nsw_backend_info_db, + NSCD_ALLOC_RWLOCK); + + if (db_p == NULL) { + _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR) + (me, "unable to allocate the pointer to the nsw " + "be info database\n"); + return (NSCD_NO_MEMORY); + } + + *db_p = ret; + _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG) + (me, "backend database (db_p = %p, db = %p)\n", db_p, *db_p); + + nscd_src_backend_db[srci] = (nscd_db_t **)_nscd_set( + (nscd_acc_data_t *)nscd_src_backend_db[srci], + (nscd_acc_data_t *)db_p); + + return (NSCD_SUCCESS); +} + +nscd_rc_t +_nscd_init_all_nsw_be_info_db(void) +{ + + int i; + nscd_rc_t rc; + char *me = "_nscd_init_all_nsw_be_info_db"; + + _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG) + (me, "initializing all nsw be info databases\n"); + + for (i = 0; i < NSCD_NUM_SRC; i++) { + if ((rc = init_nsw_be_info_db(i)) != NSCD_SUCCESS) + return (rc); + } + + return (NSCD_SUCCESS); +} + + +nscd_rc_t +_nscd_alloc_nsw_config() +{ + nscd_nsw_config = calloc(NSCD_NUM_DB, sizeof (nscd_nsw_config_t **)); + if (nscd_nsw_config == NULL) + return (NSCD_NO_MEMORY); + + return (NSCD_SUCCESS); +} + +nscd_rc_t +_nscd_alloc_nsw_be_info_db() +{ + int i; + + _nscd_cfg_num_nsw_src_all = _nscd_cfg_num_nsw_src + NSCD_NUM_SRC_UDEF; + nscd_src_backend_db = calloc(NSCD_NUM_SRC, sizeof (nscd_db_t **)); + if (nscd_src_backend_db == NULL) + return (NSCD_NO_MEMORY); + + /* also allocate/init the nsswitch source index/name array */ + _nscd_cfg_nsw_src_all = (nscd_cfg_id_t *)calloc( + _nscd_cfg_num_nsw_src_all + 1, sizeof (nscd_cfg_id_t)); + for (i = 0; i < _nscd_cfg_num_nsw_src_all + 1; i++) + (_nscd_cfg_nsw_src_all + i)->index = -1; + + (void) memcpy(_nscd_cfg_nsw_src_all, _nscd_cfg_nsw_src, + _nscd_cfg_num_nsw_src * sizeof (nscd_cfg_id_t)); + return (NSCD_SUCCESS); +} + +nscd_rc_t +_nscd_populate_nsw_backend_info() +{ + int i; + nscd_rc_t rc; + + for (i = 0; i < NSCD_NUM_SRC; i++) { + if (NSCD_NSW_SRC_NAME(i) == NULL) + continue; + rc = _nscd_populate_nsw_backend_info_db(i); + if (rc != NSCD_SUCCESS) + return (rc); + } + + return (NSCD_SUCCESS); +} diff --git a/usr/src/cmd/nscd/nscd_nswparse.c b/usr/src/cmd/nscd/nscd_nswparse.c new file mode 100644 index 0000000000..ac90788e91 --- /dev/null +++ b/usr/src/cmd/nscd/nscd_nswparse.c @@ -0,0 +1,379 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <stdlib.h> +#include <limits.h> +#include <string.h> +#include <ctype.h> + +#define __NSS_PRIVATE_INTERFACE +#include "nsswitch_priv.h" +#undef __NSS_PRIVATE_INTERFACE + +#define islabel(c) (isalnum(c) || (c) == '_') + +/* + * The _nsw_getoneconfig_v1() in this file parses the switch policy + * configuration for a switch database, e.g., + * + * hosts: nis [NOTFOUND=return] files + * or + * printers: user files nis + */ + +/* + * Local routines + */ +static char *skip(char **, char); +static char *labelskip(char *); +static char *spaceskip(char *); +static void freeconf_v1(struct __nsw_switchconfig_v1 *); +static int alldigits(char *); + +/* + * + * With the "lookup control" feature, the default criteria for NIS, NIS+, + * and any new services (e.g. ldap) will be: + * [SUCCESS=return NOTFOUND=continue UNAVAIL=continue TRYAGAIN=forever] + * + * For backward compat, NIS via NIS server in DNS forwarding mode will be: + * [SUCCESS=return NOTFOUND=continue UNAVAIL=continue TRYAGAIN=continue] + * + * And also for backward compat, the default criteria for DNS will be: + * [SUCCESS=return NOTFOUND=continue UNAVAIL=continue TRYAGAIN=continue] + */ + + + +/* + * The BIND resolver normally will retry several times on server non-response. + * But now with the "lookup control" feature, we don't want the resolver doing + * many retries, rather we want it to return control (reasonably) quickly back + * to the switch engine. However, when TRYAGAIN=N or TRYAGAIN=forever is + * not explicitly set by the admin in the conf file, we want the old "resolver + * retry a few times" rather than no retries at all. + */ +static int dns_tryagain_retry = 3; + +/* + * For backward compat (pre "lookup control"), the dns default behavior is + * soft lookup. + */ +static void +set_dns_default_lkp(struct __nsw_lookup_v1 *lkp) +{ + if (strcasecmp(lkp->service_name, "dns") == 0) { + lkp->actions[__NSW_TRYAGAIN] = + __NSW_TRYAGAIN_NTIMES; + lkp->max_retries = dns_tryagain_retry; + } +} + +static void +freeconf_v1(struct __nsw_switchconfig_v1 *cfp) +{ + if (cfp) { + if (cfp->dbase) + free(cfp->dbase); + if (cfp->lookups) { + struct __nsw_lookup_v1 *nex, *cur; + for (cur = cfp->lookups; cur; cur = nex) { + free(cur->service_name); + nex = cur->next; + free(cur); + } + } + free(cfp); + } +} + +/* give the next non-alpha character */ +static char * +labelskip(char *cur) +{ + char *p = cur; + while (islabel(*p)) + ++p; + return (p); +} + +/* give the next non-space character */ +static char * +spaceskip(char *cur) +{ + char *p = cur; + while (*p == ' ' || *p == '\t') + ++p; + return (p); +} + +/* + * terminate the *cur pointed string by null only if it is + * followed by "key" surrounded by zero or more spaces and + * return value is the same as the original *cur pointer and + * *cur pointer is advanced to the first non {space, key} char + * followed by the key. Otherwise, return NULL and keep + * *cur unchanged. + */ +static char * +skip(char **cur, char key) +{ + char *p, *tmp; + char *q = *cur; + int found, tmpfound; + + tmp = labelskip(*cur); + p = tmp; + found = (*p == key); + if (found) { + *p++ = '\0'; /* overwrite the key */ + p = spaceskip(p); + } else { + while (*p == ' ' || *p == '\t') { + tmpfound = (*++p == key); + if (tmpfound) { + found = tmpfound; + /* null terminate the return token */ + *tmp = '\0'; + p++; /* skip the key */ + } + } + } + if (!found) + return (NULL); /* *cur unchanged */ + *cur = p; + return (q); +} + +/* Return 1 if the string contains all digits, else return 0. */ +static int +alldigits(char *s) +{ + for (; *s; s++) + if (!isdigit(*s)) + return (0); + return (1); +} + +struct __nsw_switchconfig_v1 * +_nsw_getoneconfig_v1(const char *name, char *linep, enum __nsw_parse_err *errp) + /* linep Nota Bene: not const char * */ + /* errp Meanings are abused a bit */ +{ + struct __nsw_switchconfig_v1 *cfp; + struct __nsw_lookup_v1 *lkp, **lkq; + int end_crit; + action_t act; + char *p, *tokenp; + + *errp = __NSW_CONF_PARSE_SUCCESS; + + if ((cfp = calloc(1, sizeof (struct __nsw_switchconfig_v1))) + == NULL) { + *errp = __NSW_CONF_PARSE_SYSERR; + return (NULL); + } + cfp->dbase = strdup(name); + lkq = &cfp->lookups; + + /* linep points to a naming service name */ + for (;;) { + int i; + + /* white space following the last service */ + if (*linep == '\0' || *linep == '\n') { + return (cfp); + } + if ((lkp = calloc(1, sizeof (struct __nsw_lookup_v1))) + == NULL) { + *errp = __NSW_CONF_PARSE_SYSERR; + freeconf_v1(cfp); + return (NULL); + } + + *lkq = lkp; + lkq = &lkp->next; + + for (i = 0; i < __NSW_STD_ERRS_V1; i++) + if (i == __NSW_SUCCESS) + lkp->actions[i] = __NSW_RETURN; + else if (i == __NSW_TRYAGAIN) + lkp->actions[i] = __NSW_TRYAGAIN_FOREVER; + else + lkp->actions[i] = __NSW_CONTINUE; + + /* get criteria for the naming service */ + if (tokenp = skip(&linep, '[')) { /* got criteria */ + + /* premature end, illegal char following [ */ + if (!islabel(*linep)) + goto barf_line; + lkp->service_name = strdup(tokenp); + cfp->num_lookups++; + + set_dns_default_lkp(lkp); + + end_crit = 0; + + /* linep points to a switch_err */ + for (;;) { + int ntimes = 0; /* try again max N times */ + int dns_continue = 0; + + if ((tokenp = skip(&linep, '=')) == NULL) { + goto barf_line; + } + + /* premature end, ill char following = */ + if (!islabel(*linep)) + goto barf_line; + + /* linep points to the string following '=' */ + p = labelskip(linep); + if (*p == ']') + end_crit = 1; + else if (*p != ' ' && *p != '\t') + goto barf_line; + *p++ = '\0'; /* null terminate linep */ + p = spaceskip(p); + if (!end_crit) { + if (*p == ']') { + end_crit = 1; + *p++ = '\0'; + } else if (*p == '\0' || *p == '\n') { + return (cfp); + } else if (!islabel(*p)) + /* p better be the next switch_err */ + goto barf_line; + } + if (strcasecmp(linep, __NSW_STR_RETURN) == 0) + act = __NSW_RETURN; + else if (strcasecmp(linep, + __NSW_STR_CONTINUE) == 0) { + if (strcasecmp(lkp->service_name, + "dns") == 0 && + strcasecmp(tokenp, + __NSW_STR_TRYAGAIN) + == 0) { + /* + * Add one more condition + * so it retries only if it's + * "dns [TRYAGAIN=continue]" + */ + dns_continue = 1; + act = __NSW_TRYAGAIN_NTIMES; + } else + act = __NSW_CONTINUE; + } else if (strcasecmp(linep, + __NSW_STR_FOREVER) == 0) + act = __NSW_TRYAGAIN_FOREVER; + else if (alldigits(linep)) { + act = __NSW_TRYAGAIN_NTIMES; + ntimes = atoi(linep); + if (ntimes < 0 || ntimes > INT_MAX) + ntimes = 0; + } + else + goto barf_line; + + if (__NSW_SUCCESS_ACTION(act) && + strcasecmp(tokenp, + __NSW_STR_SUCCESS) == 0) { + lkp->actions[__NSW_SUCCESS] = act; + } else if (__NSW_NOTFOUND_ACTION(act) && + strcasecmp(tokenp, + __NSW_STR_NOTFOUND) == 0) { + lkp->actions[__NSW_NOTFOUND] = act; + } else if (__NSW_UNAVAIL_ACTION(act) && + strcasecmp(tokenp, + __NSW_STR_UNAVAIL) == 0) { + lkp->actions[__NSW_UNAVAIL] = act; + } else if (__NSW_TRYAGAIN_ACTION(act) && + strcasecmp(tokenp, + __NSW_STR_TRYAGAIN) == 0) { + lkp->actions[__NSW_TRYAGAIN] = act; + if (strcasecmp(lkp->service_name, + "nis") == 0) + lkp->actions[ + __NSW_NISSERVDNS_TRYAGAIN] + = act; + if (act == __NSW_TRYAGAIN_NTIMES) + lkp->max_retries = + dns_continue ? + dns_tryagain_retry : ntimes; + } else { + /*EMPTY*/ + /* + * convert string tokenp to integer + * and put in long_errs + */ + } + if (end_crit) { + linep = spaceskip(p); + if (*linep == '\0' || *linep == '\n') + return (cfp); + break; /* process next naming service */ + } + linep = p; + } /* end of while loop for a name service's criteria */ + } else { + /* + * no criteria for this naming service. + * linep points to name service, but not null + * terminated. + */ + p = labelskip(linep); + if (*p == '\0' || *p == '\n') { + *p = '\0'; + lkp->service_name = strdup(linep); + set_dns_default_lkp(lkp); + cfp->num_lookups++; + return (cfp); + } + if (*p != ' ' && *p != '\t') + goto barf_line; + *p++ = '\0'; + lkp->service_name = strdup(linep); + set_dns_default_lkp(lkp); + cfp->num_lookups++; + linep = spaceskip(p); + } + } /* end of while(1) loop for a name service */ + +barf_line: + freeconf_v1(cfp); + *errp = __NSW_CONF_PARSE_NOPOLICY; + return (NULL); +} + +int +__nsw_freeconfig_v1( + struct __nsw_switchconfig_v1 *conf) +{ + freeconf_v1(conf); + return (0); +} diff --git a/usr/src/cmd/nscd/nscd_nswstate.c b/usr/src/cmd/nscd/nscd_nswstate.c new file mode 100644 index 0000000000..2f571e4e3f --- /dev/null +++ b/usr/src/cmd/nscd/nscd_nswstate.c @@ -0,0 +1,786 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <stdio.h> +#include <stdlib.h> +#include <assert.h> +#include <string.h> +#include "nscd_switch.h" +#include "nscd_log.h" + +/* + * nscd_nsw_state_t list for each nss database. Protected + * by the readers/writer lock nscd_nsw_state_base_lock. + */ +nscd_nsw_state_base_t **nscd_nsw_state_base; +static rwlock_t nscd_nsw_state_base_lock = DEFAULTRWLOCK; + +static void +_nscd_free_nsw_state( + nscd_nsw_state_t *s) +{ + + int i; + char *me = "_nscd_free_nsw_state"; + + _NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG) + (me, "freeing nsw state = %p\n", s); + + if (s == NULL) + return; + + if (s->nsw_cfg_p != NULL) + /* + * an nsw state without base does not reference + * count the nsw config data (ie not using a + * shared one), so the one created for it should + * be freed + */ + if ((*s->nsw_cfg_p)->nobase != 1) + _nscd_release((nscd_acc_data_t *)s->nsw_cfg_p); + else + _nscd_free_nsw_config(*s->nsw_cfg_p); + + if (s->be_db_pp != NULL) { + for (i = 0; i < s->max_src; i++) { + if (s->be_db_pp[i] == NULL) + continue; + _nscd_release((nscd_acc_data_t *)s->be_db_pp[i]); + _NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG) + (me, "release db be ptr %p\n", s->be_db_pp[i]); + } + free(s->be_db_pp); + } + + if (s->be != NULL) { + for (i = 0; i < s->max_src; i++) { + if (s->be[i] == NULL) + continue; + if (s->getent == 1) + (void) NSS_INVOKE_DBOP(s->be[i], + NSS_DBOP_ENDENT, 0); + (void) NSS_INVOKE_DBOP(s->be[i], + NSS_DBOP_DESTRUCTOR, 0); + } + free(s->be); + } + + s->base = NULL; + + _NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG) + (me, "nsw state %p freed \n", s); + + free(s); +} + +static void +_nscd_free_nsw_state_base( + nscd_acc_data_t *data) +{ + nscd_nsw_state_base_t *base = (nscd_nsw_state_base_t *)data; + nscd_nsw_state_t *s, *ts; + int i; + char *me = "_nscd_free_nsw_state_base"; + + _NSCD_LOG(NSCD_LOG_NSW_STATE | NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG) + (me, "freeing db state base %p\n", base); + + if (base == NULL) + return; + + for (i = 0; i < 2; i++) { + if (i == 1) + s = base->nsw_state.first; + else + s = base->nsw_state_thr.first; + + while (s != NULL) { + ts = s->next; + _nscd_free_nsw_state(s); + s = ts; + } + } + + _NSCD_LOG(NSCD_LOG_NSW_STATE | NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG) + (me, "nsw state base %p freed \n", base); +} + +void +_nscd_free_all_nsw_state_base() +{ + nscd_nsw_state_base_t *base; + int i; + char *me = "_nscd_free_all_nsw_state_base"; + + _NSCD_LOG(NSCD_LOG_NSW_STATE | NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG) + (me, "freeing all db state base\n"); + + (void) rw_wrlock(&nscd_nsw_state_base_lock); + for (i = 0; i < NSCD_NUM_DB; i++) { + + base = nscd_nsw_state_base[i]; + _NSCD_LOG(NSCD_LOG_NSW_STATE | NSCD_LOG_CONFIG, + NSCD_LOG_LEVEL_DEBUG) + (me, "freeing db state base (%d) %p \n", i, base); + + if (base == NULL) + continue; + + nscd_nsw_state_base[i] = (nscd_nsw_state_base_t *) + _nscd_set((nscd_acc_data_t *)base, NULL); + } + (void) rw_unlock(&nscd_nsw_state_base_lock); +} + +static nscd_nsw_state_t * +_nscd_create_nsw_state( + nscd_nsw_params_t *params) +{ + nscd_nsw_state_t *s; + nscd_nsw_config_t *nsw_cfg; + nscd_db_t **be_db_p, *be_db; + int i, nobe = 1; + char *me = "_nscd_create_nsw_state"; + + + _NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG) + (me, "creating nsw state...\n"); + + s = calloc(1, sizeof (nscd_nsw_state_t)); + if (s == NULL) { + if ((*s->nsw_cfg_p)->nobase != 1) + _nscd_release((nscd_acc_data_t *)params->nswcfg); + _NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_ERROR) + (me, "not able to allocate a nsw state\n"); + return (NULL); + } else + _NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG) + (me, "nsw state %p allocated\n", s); + + s->dbi = params->dbi; + s->next = NULL; + + nsw_cfg = *params->nswcfg; + + s->nsw_cfg_p = params->nswcfg; + s->config = nsw_cfg->nsw_config; + s->max_src = nsw_cfg->max_src; + s->p = params->p; + + s->be = calloc(s->max_src, sizeof (nss_backend_t **)); + if (s->be == NULL) { + _NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_ERROR) + (me, "not able to allocate s->be\n"); + + _nscd_free_nsw_state(s); + return (NULL); + } else { + _NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG) + (me, "db be array %p allocated\n", s->be); + } + + s->be_db_pp = calloc(s->max_src, sizeof (nscd_db_t ***)); + if (s->be_db_pp == NULL) { + _NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_ERROR) + (me, "not able to allocate s->be_db_pp\n"); + _nscd_free_nsw_state(s); + return (NULL); + } else { + _NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG) + (me, "be_db_pp array %p allocated\n", s->be_db_pp); + } + + /* create the source:database backends */ + for (i = 0; i < s->max_src; i++) { + nss_backend_t *be; + int srci; + char *srcn; + const char *dbn; + struct __nsw_lookup_v1 *lkp; + const nscd_db_entry_t *dbe; + nscd_be_info_t *be_info; + + if (i == 0) + lkp = s->config->lookups; + else + lkp = lkp->next; + if (lkp == NULL) { + _NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_ERROR) + (me, "error: lkp is NULL\n"); + _nscd_free_nsw_state(s); + return (NULL); + } + + srci = nsw_cfg->src_idx[i]; + srcn = lkp->service_name; + _NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG) + (me, "source name = %s, index = %d\n", srcn, srci); + + be_db_p = (nscd_db_t **)_nscd_get( + (nscd_acc_data_t *)nscd_src_backend_db[srci]); + if (be_db_p == NULL) { + _nscd_free_nsw_state(s); + return (NULL); + } + be_db = *be_db_p; + s->be_db_pp[i] = be_db_p; + _NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG) + (me, "be db ptr array %p referenced\n", be_db_p); + + be_info = NULL; + be = NULL; + dbn = params->p.name; + dbe = _nscd_get_db_entry(be_db, NSCD_DATA_BACKEND_INFO, + (const char *)dbn, NSCD_GET_FIRST_DB_ENTRY, 0); + if (dbe != NULL) + be_info = (nscd_be_info_t *)*(dbe->data_array); + + if (be_info == NULL || be_info->be_constr == NULL) { + _NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG) + (me, "no backend info or be_constr is NULL " + "for <%s : %s>\n", NSCD_NSW_SRC_NAME(srci), + dbn); + } else + be = (be_info->be_constr)(dbn, + NSCD_NSW_SRC_NAME(srci), 0); + + if (be == NULL) { + _NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_ERROR) + (me, "not able to init be for <%s : %s>\n", + NSCD_NSW_SRC_NAME(srci), dbn); + + _NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG) + (me, "releasing db be ptr %p\n", be_db_p); + + _nscd_release((nscd_acc_data_t *)be_db_p); + s->be_db_pp[i] = NULL; + + continue; + } + + s->be[i] = be; + nobe = 0; + } + + if (nobe == 1) { + _NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG) + (me, "NO backend found, returning NULL\n"); + + _nscd_free_nsw_state(s); + return (NULL); + } + + return (s); +} + +static nscd_rc_t +_get_nsw_state_int( + nss_db_root_t *rootp, + nscd_nsw_params_t *params, + thread_t *tid) +{ + + nscd_nsw_state_t *ret = NULL; + nscd_nsw_config_t **nswcfg; + nscd_nsw_state_base_t *base; + nscd_state_ctrl_t *ctrl_p; + int thread_only = 0, wait_cond = 0; + char *me = "_get_nsw_state_int"; + int dbi; + nscd_rc_t rc; + + dbi = params->dbi; + + /* + * no nsw state will be reused, if asked to use + * default config. So create the new structures + * used by the switch engine and the new nsw state + */ + if (params->p.flags & NSS_USE_DEFAULT_CONFIG) { + rc = _nscd_create_sw_struct(dbi, (char *)params->p.name, + (char *)params->p.default_config, NULL, params); + if (rc != NSCD_SUCCESS) + return (rc); + + _NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG) + (me, "no base nsw config created for %s (sources: %s)\n", + params->p.name, params->p.default_config); + + ret = _nscd_create_nsw_state(params); + if (ret == NULL) + return (NSCD_CREATE_NSW_STATE_FAILED); + rootp->s = (struct nss_db_state *)ret; + return (NSCD_SUCCESS); + } + + /* + * if getting a nsw state for a request from the compat + * backend, create the new switch structures if this + * is the first time around for a passwd, shadow, group, + * audit_user, or user_attr database + */ + if (params->compati != -1) { + + nscd_nsw_config_t **nswcfg1; + int i = params->compati; + + nswcfg = (nscd_nsw_config_t **)_nscd_get( + (nscd_acc_data_t *)nscd_nsw_config[i]); + + /* + * if nsw data structures not created yet, get the + * config string from the passwd_compat or + * group_compat DB and create the structures + */ + if (nswcfg == NULL) { + nswcfg1 = (nscd_nsw_config_t **)_nscd_get( + (nscd_acc_data_t *)nscd_nsw_config[params->cfgdbi]); + if (nswcfg1 == NULL) { + _NSCD_LOG(NSCD_LOG_NSW_STATE, + NSCD_LOG_LEVEL_ERROR) + (me, "no nsw config for %s\n", + params->p.name); + return (NSCD_CREATE_NSW_STATE_FAILED); + } + + rc = _nscd_create_sw_struct(i, params->p.name, + (*nswcfg1)->nsw_cfg_str, NULL, params); + _nscd_release((nscd_acc_data_t *)nswcfg1); + if (rc != NSCD_SUCCESS) + return (rc); + + _NSCD_LOG(NSCD_LOG_NSW_STATE, + NSCD_LOG_LEVEL_DEBUG) + (me, "nsw config created for %s (%s)\n", + params->p.name, (*nswcfg1)->nsw_cfg_str); + } else + _nscd_release((nscd_acc_data_t *)nswcfg); + } + + (void) rw_rdlock(&nscd_nsw_state_base_lock); + base = nscd_nsw_state_base[dbi]; + (void) rw_unlock(&nscd_nsw_state_base_lock); + if (base == NULL) + assert(base != NULL); + + /* + * If list is not empty, return the first one on list. + * Otherwise, create and return a new db state if the + * limit is not reached. if reacehed, wait for the 'one + * is available' signal. + */ + assert(base == (nscd_nsw_state_base_t *)_nscd_mutex_lock( + (nscd_acc_data_t *)base)); + + if (tid == NULL) { + ctrl_p = &base->nsw_state; + } else { + thread_only = 1; + ctrl_p = &base->nsw_state_thr; + + _NSCD_LOG_IF(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG) { + _nscd_logit(me, "per thread nsw state info: \n"); + _nscd_logit(me, "tid = %d\n", *tid); + _nscd_logit(me, "tid in base = %d\n", base->tid); + _nscd_logit(me, "number of free nsw_state = %d\n", + ctrl_p->free); + _nscd_logit(me, "number of nsw state allocated = %d\n", + ctrl_p->allocated); + _nscd_logit(me, "first nsw state on list = %p\n", + ctrl_p->first); + _nscd_logit(me, "number of waiter = %d\n", + ctrl_p->waiter); + } + } + + if (ctrl_p->first == NULL && ctrl_p->allocated == ctrl_p->max) + wait_cond = 1; + else if (thread_only && base->used_by_thr && base->tid != *tid) + wait_cond = 1; + + if (wait_cond) { + + ctrl_p->waiter++; + + while (wait_cond) { + if (!thread_only) + _NSCD_LOG(NSCD_LOG_NSW_STATE, + NSCD_LOG_LEVEL_DEBUG) + (me, "waiting for nsw state signal\n"); + else + _NSCD_LOG(NSCD_LOG_NSW_STATE, + NSCD_LOG_LEVEL_DEBUG) + (me, "waiting for per thread " + "nsw state signal\n"); + + if (thread_only) { + _nscd_cond_wait((nscd_acc_data_t *)base, + &base->thr_cond); + + if (base->used_by_thr == 0 && + ctrl_p->first != NULL) + wait_cond = 0; + } else { + _nscd_cond_wait((nscd_acc_data_t *)base, NULL); + + if (ctrl_p->first != NULL) + wait_cond = 0; + } + + if (!thread_only) + _NSCD_LOG(NSCD_LOG_NSW_STATE, + NSCD_LOG_LEVEL_DEBUG) + (me, "woke from cond wait ...wait_cond = %d\n", + wait_cond); + else + + _NSCD_LOG(NSCD_LOG_NSW_STATE, + NSCD_LOG_LEVEL_DEBUG) + (me, "woke from cond wait (per thread) " + "...wait_cond = %d\n", wait_cond); + + } + + ctrl_p->waiter--; + } + + if (ctrl_p->first == NULL) { + int geti; + + /* + * for lookup calls from the compat backend + * uses the switch policy for passwd_compat + * or group_compat + */ + if (params->compati != -1) + geti = params->compati; + else + geti = params->dbi; + + params->nswcfg = (nscd_nsw_config_t **)_nscd_get( + (nscd_acc_data_t *)nscd_nsw_config[geti]); + _NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG) + (me, "got a nsw config %p for index %d\n", + params->nswcfg, geti); + + ctrl_p->first = _nscd_create_nsw_state(params); + if (ctrl_p->first != NULL) { + ctrl_p->first->base = base; + + if (tid == NULL) { + _NSCD_LOG(NSCD_LOG_NSW_STATE, + NSCD_LOG_LEVEL_DEBUG) + (me, "got a new nsw_state %p\n", ctrl_p->first); + } else { + _NSCD_LOG(NSCD_LOG_NSW_STATE, + NSCD_LOG_LEVEL_DEBUG) + (me, "got a new per thread nsw_state %p\n", + ctrl_p->first); + } + ctrl_p->allocated++; + ctrl_p->free++; + } else { + _NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_ERROR) + (me, "error: unable to obtain a nsw state\n"); + _nscd_mutex_unlock((nscd_acc_data_t *)base); + return (NSCD_CREATE_NSW_STATE_FAILED); + } + } + + ret = ctrl_p->first; + ctrl_p->first = ret->next; + ret->next = NULL; + ctrl_p->free--; + if (thread_only) { + base->tid = *tid; + base->used_by_thr = 1; + + _NSCD_LOG_IF(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG) { + _nscd_logit(me, "\t\t\tgot a per thread nsw " + "state %p: \n", ret); + _nscd_logit(me, "tid = %d\n", *tid); + _nscd_logit(me, "tid in base = %d\n", base->tid); + _nscd_logit(me, "number of free nsw_state = %d\n", + ctrl_p->free); + _nscd_logit(me, "number od nsw state allocated = %d\n", + ctrl_p->allocated); + _nscd_logit(me, "first nsw state on list = %p\n", + ctrl_p->first); + _nscd_logit(me, "number of waiter = %d\n", + ctrl_p->waiter); + } + } + else + _NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG) + (me, "got old nsw state %p\n", ret); + + _nscd_mutex_unlock((nscd_acc_data_t *)base); + + rootp->s = (struct nss_db_state *)ret; + + return (NSCD_SUCCESS); +} + +nscd_rc_t +_nscd_get_nsw_state( + nss_db_root_t *rootp, + nscd_nsw_params_t *params) +{ + return (_get_nsw_state_int(rootp, params, NULL)); +} + +nscd_rc_t +_nscd_get_nsw_state_thread( + nss_db_root_t *rootp, + nscd_nsw_params_t *params) +{ + thread_t tid = thr_self(); + return (_get_nsw_state_int(rootp, params, &tid)); +} + + +static void +_put_nsw_state_int( + nscd_nsw_state_t *s, + thread_t *tid) +{ + + nscd_nsw_state_base_t *base; + nscd_state_ctrl_t *ctrl_p; + int thread_only = 0; + char *me = "_put_nsw_state_int"; + + _NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG) + (me, "put back a nsw state\n"); + + if (s == NULL) { + _NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG) + (me, "nsw state is NULL, nothing to put back\n"); + return; + } + + /* + * no need to put back if the nsw state is not on any base + * but need to free the resources used + */ + if ((*s->nsw_cfg_p)->nobase == 1) { + _NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG) + (me, "no base nsw state, freeing resources ...\n"); + + _nscd_free_nsw_state(s); + return; + } + + if (tid != NULL) + thread_only = 1; + + base = s->base; + + if (_nscd_mutex_lock((nscd_acc_data_t *)base) == NULL) { + /* base has been freed, free this db state */ + _NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG) + (me, "nsw state base has been freed, freeing %p\n", s); + _nscd_free_nsw_state(s); + return; + } + + if (thread_only) + ctrl_p = &base->nsw_state_thr; + else + ctrl_p = &base->nsw_state; + + _NSCD_LOG_IF(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG) { + _nscd_logit(me, "before returning the nsw state: \n"); + _nscd_logit(me, "tid = %d\n", (tid == NULL) ? -1 : *tid); + _nscd_logit(me, "tid in base = %d\n", base->tid); + _nscd_logit(me, "number of free nsw_state = %d\n", + ctrl_p->free); + _nscd_logit(me, "number od nsw state allocated = %d\n", + ctrl_p->allocated); + _nscd_logit(me, "first nsw state on list = %p\n", + ctrl_p->first); + _nscd_logit(me, "number of waiter = %d\n", + ctrl_p->waiter); + } + + if (ctrl_p->first != NULL) { + s->next = ctrl_p->first; + ctrl_p->first = s; + } else { + ctrl_p->first = s; + s->next = NULL; + } + ctrl_p->free++; + + _NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG) + (me, "signaling waiter thread_only = %d..\n", thread_only); + + if (thread_only && ctrl_p->free == ctrl_p->allocated) { + assert(ctrl_p->first != NULL); + base->used_by_thr = 0; + if (ctrl_p->waiter > 0) { + (void) cond_signal(&base->thr_cond); + } + } + + if (!thread_only && ctrl_p->waiter > 0) { + + _nscd_cond_signal((nscd_acc_data_t *)base); + } + + _NSCD_LOG_IF(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG) { + _nscd_logit(me, "after the nsw state is returned: \n"); + _nscd_logit(me, "tid = %d\n", (tid == NULL) ? -1 : *tid); + _nscd_logit(me, "tid in base = %d\n", base->tid); + _nscd_logit(me, "number of free nsw_state = %d\n", + ctrl_p->free); + _nscd_logit(me, "number od nsw state allocated = %d\n", + ctrl_p->allocated); + _nscd_logit(me, "first nsw state on list = %p\n", + ctrl_p->first); + _nscd_logit(me, "tnumber of waiter = %d\n", + ctrl_p->waiter); + } + + _NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG) + (me, "done putting back nsw state %p, thread_only = %d\n", + s, thread_only); + + _nscd_mutex_unlock((nscd_acc_data_t *)base); + +} + +void +_nscd_put_nsw_state( + nscd_nsw_state_t *s) +{ + _put_nsw_state_int(s, NULL); +} + +void +_nscd_put_nsw_state_thread( + nscd_nsw_state_t *s) +{ + thread_t tid = thr_self(); + _put_nsw_state_int(s, &tid); +} + +nscd_rc_t +_nscd_init_nsw_state_base( + int dbi, + int lock) +{ + nscd_nsw_state_base_t *base = NULL; + char *me = "_nscd_init_nsw_state_base"; + + if (lock) + (void) rw_rdlock(&nscd_nsw_state_base_lock); + + base = (nscd_nsw_state_base_t *)_nscd_alloc( + NSCD_DATA_NSW_STATE_BASE, + sizeof (nscd_nsw_state_base_t), + _nscd_free_nsw_state_base, + NSCD_ALLOC_MUTEX | NSCD_ALLOC_COND); + + if (base == NULL) { + _NSCD_LOG(NSCD_LOG_NSW_STATE | NSCD_LOG_CONFIG, + NSCD_LOG_LEVEL_ERROR) + (me, "not able to allocate a nsw state base\n"); + if (lock) + (void) rw_unlock(&nscd_nsw_state_base_lock); + return (NSCD_NO_MEMORY); + } + _NSCD_LOG(NSCD_LOG_NSW_STATE | NSCD_LOG_CONFIG, + NSCD_LOG_LEVEL_DEBUG) + (me, "nsw state base %p allocated\n", base); + + /* + * initialize and activate the new nss_nsw_state base + */ + base->dbi = dbi; + base->nsw_state.max = NSCD_SW_CFG(dbi).max_nsw_state_per_db; + base->nsw_state_thr.max = NSCD_SW_CFG(dbi).max_nsw_state_per_thread; + + nscd_nsw_state_base[dbi] = (nscd_nsw_state_base_t *)_nscd_set( + (nscd_acc_data_t *)nscd_nsw_state_base[dbi], + (nscd_acc_data_t *)base); + + if (lock) + (void) rw_unlock(&nscd_nsw_state_base_lock); + + return (NSCD_SUCCESS); +} + +nscd_rc_t +_nscd_init_all_nsw_state_base() +{ + int i; + nscd_rc_t rc; + char *me = "_nscd_init_all_nsw_state_base"; + + (void) rw_rdlock(&nscd_nsw_state_base_lock); + + for (i = 0; i < NSCD_NUM_DB; i++) { + + rc = _nscd_init_nsw_state_base(i, 0); + + if (rc != NSCD_SUCCESS) { + _NSCD_LOG(NSCD_LOG_NSW_STATE | NSCD_LOG_CONFIG, + NSCD_LOG_LEVEL_ERROR) + (me, "not able to initialize a nsw db state " + "base (%d)\n", i); + + (void) rw_unlock(&nscd_nsw_state_base_lock); + return (rc); + } + } + _NSCD_LOG(NSCD_LOG_NSW_STATE | NSCD_LOG_CONFIG, + NSCD_LOG_LEVEL_DEBUG) + (me, "all nsw state base initialized\n"); + + (void) rw_unlock(&nscd_nsw_state_base_lock); + + return (NSCD_SUCCESS); +} + +nscd_rc_t +_nscd_alloc_nsw_state_base() +{ + + (void) rw_rdlock(&nscd_nsw_state_base_lock); + + nscd_nsw_state_base = calloc(NSCD_NUM_DB, + sizeof (nscd_nsw_state_base_t *)); + if (nscd_nsw_state_base == NULL) { + (void) rw_unlock(&nscd_nsw_state_base_lock); + return (NSCD_NO_MEMORY); + } + + (void) rw_rdlock(&nscd_nsw_state_base_lock); + + return (NSCD_SUCCESS); +} diff --git a/usr/src/cmd/nscd/nscd_parse.c b/usr/src/cmd/nscd/nscd_parse.c deleted file mode 100644 index 7555bb10b1..0000000000 --- a/usr/src/cmd/nscd/nscd_parse.c +++ /dev/null @@ -1,402 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. - * - * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE - * or http://www.opensolaris.org/os/licensing. - * See the License for the specific language governing permissions - * and limitations under the License. - * - * When distributing Covered Code, include this CDDL HEADER in each - * file and include the License file at usr/src/OPENSOLARIS.LICENSE. - * If applicable, add the following below this CDDL HEADER, with the - * fields enclosed by brackets "[]" replaced with your own identifying - * information: Portions Copyright [yyyy] [name of copyright owner] - * - * CDDL HEADER END - */ -/* - * Copyright 1994-2002 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#pragma ident "%Z%%M% %I% %E% SMI" - -/* - * routine to parse configuration file - * - * returns -1 on error, 0 on sucess. Error messages to log. - */ - -#include <errno.h> -#include <stdlib.h> -#include <string.h> -#include <synch.h> -#include <sys/door.h> -#include <unistd.h> - -#include "getxby_door.h" -#include "server_door.h" -#include "nscd.h" - -static int strbreak(char **, char *, char *); -static int nscd_yesno(char *); -static int nscd_set_integer(int *, char *, char *, int, int, int); -static int nscd_set_short(short *, char *, char *, int, int, int); -static int nscd_setyesno(int *, char *, char *, int); -static int nscd_setyesno_sh(short *, char *, char *, int); -static int nscd_set_cf(nsc_stat_t *, char *, int); - -int -nscd_parse(char *progname, char *filename) -{ - FILE *in; - char buffer[255]; - char *fields [128]; - int errflg; - int linecnt; - int fieldcnt; - - if ((in = fopen(filename, "r")) == NULL) { - logit("%s: open of configuration file %s failed: %s\n", - progname, filename, strerror(errno)); - return (-1); - } - - errflg = 0; - linecnt = 0; - while (fgets(buffer, sizeof (buffer), in) != NULL && !errflg) { - nsc_stat_t *cache; - - linecnt++; - if ((fieldcnt = strbreak(fields, buffer, " \t\n")) == 0) { - /* blank */ - continue; - } - - switch (*fields[0]) { - case '#': /* comment ignore it */ - break; - case 'p': - - if ((strcmp("positive-time-to-live", fields[0]) != 0) || - (fieldcnt != 3) || - !(cache = getcacheptr(fields[1]))) { - errflg++; - break; - } - - if (nscd_set_ttl_positive(cache, fields[1], - atoi(fields[2])) < 0) - errflg++; - - break; - - case 'n': - - if ((strcmp("negative-time-to-live", fields[0]) != 0) || - (fieldcnt != 3) || - !(cache = getcacheptr(fields[1]))) { - errflg++; - break; - } - - if (nscd_set_ttl_negative(cache, fields[1], - atoi(fields[2])) < 0) - errflg++; - - break; - - case 's': - - if ((strcmp("suggested-size", fields[0]) != 0) || - (fieldcnt != 3) || - !(cache = getcacheptr(fields[1]))) { - errflg++; - break; - } - - if (nscd_set_ss(cache, fields[1], atoi(fields[2])) < 0) - errflg++; - - break; - - case 'k': - - if ((strcmp("keep-hot-count", fields[0]) != 0) || - (fieldcnt != 3) || - !(cache = getcacheptr(fields[1]))) { - errflg++; - break; - } - - if (nscd_set_khc(cache, fields[1], atoi(fields[2])) < 0) - errflg++; - - break; - - case 'o': - - if ((strcmp("old-data-ok", fields[0]) != 0) || - (fieldcnt != 3) || - !(cache = getcacheptr(fields[1]))) { - errflg++; - break; - } - - if (nscd_set_odo(cache, fields[1], - nscd_yesno(fields[2])) < 0) { - errflg++; - } - - break; - - case 'e': - if ((strcmp("enable-cache", fields[0]) != 0) || - (fieldcnt != 3) || - !(cache = getcacheptr(fields[1]))) { - errflg++; - break; - } - - if (nscd_set_ec(cache, fields[1], - nscd_yesno(fields[2])) < 0) - errflg++; - break; - - case 'c': - - if ((strcmp("check-files", fields[0]) != 0) || - (fieldcnt != 3) || - !(cache = getcacheptr(fields[1]))) { - errflg++; - break; - } - - if (nscd_set_cf(cache, fields[1], - nscd_yesno(fields[2])) < 0) - errflg++; - break; - - - case 'l': - - if (strcmp("logfile", fields[0])) { - errflg++; - break; - } - - if (nscd_set_lf(¤t_admin, fields[1]) < 0) - errflg++; - - break; - - case 'd': - if (strcmp("debug-level", fields[0])) { - errflg++; - break; - } - - if (nscd_set_dl(¤t_admin, atoi(fields[1])) < 0) - errflg++; - break; - - - - default: - errflg++; - break; - } - - if (errflg) { - logit("Syntax error line %d of configuration file %s\n", - linecnt, filename); - return (-1); - } - - } - - fclose(in); - return (errflg?-1:0); -} - -static int -strbreak(char *field[], char *s, char *sep) -{ - register int i; - char *lasts; - - for (i = 0; field[i] = strtok_r((i?(char *)NULL:s), sep, &lasts); i++) - ; - return (i); -} - -static int -nscd_yesno(char *s) -{ - if (strcmp(s, "yes") == 0) - return (1); - - if (strcmp(s, "no") == 0) - return (0); - return (-1); -} - -static int -nscd_set_integer(int *addr, char *facility, char *cachename, int value, - int min, int max) -{ - if (value < min || value > max) { - logit("attempted to set value of %s for %s to %d, which is not" - "%d <= x <= %d\n", facility, cachename, value, min, max); - return (-1); - } - - if (*addr != value) { - if (current_admin.debug_level) - logit("Setting %s for %s to %d\n", - facility, cachename, value); - *addr = value; - return (1); - } - return (0); -} - -static int -nscd_set_short(short *addr, char *facility, char *cachename, int value, - int min, int max) -{ - if (value < min || value > max) { - logit("attempted to set value of %s for %s to %d, which is not " - "%d <= x <= %d\n", facility, cachename, value, min, max); - return (-1); - } - - if (*addr != value) { - if (current_admin.debug_level) { - logit("Setting %s for %s to %d\n", - facility, cachename, value); - } - *addr = value; - return (1); - } - return (0); -} - -static int -nscd_setyesno(int *addr, char *facility, char *cachename, int value) -{ - int yn; - - switch (yn = value) { - case 1: - case 0: - if (*addr != yn) { - if (current_admin.debug_level) - logit("%s now %s for %s\n", facility, - (yn?"enabled":"disabled"), cachename); - *addr = yn; - return (1); - } - else - return (0); - } - return (-1); -} - -static int -nscd_setyesno_sh(short *addr, char *facility, char *cachename, int value) -{ - int yn; - - switch (yn = value) { - case 1: - case 0: - if (*addr != yn) { - if (current_admin.debug_level) { - logit("%s now %s for %s\n", - facility, (yn?"enabled":"disabled"), - cachename); - } - *addr = yn; - return (1); - } - else - return (0); - } - return (-1); -} - -int -nscd_set_dl(admin_t *ptr, int value) -{ - return (nscd_set_integer(&(ptr->debug_level), "Debug level", "nscd", - value, 0, 10)); -} - -int -nscd_set_ec(nsc_stat_t *cache, char *name, int value) -{ - return (nscd_setyesno(&(cache->nsc_enabled), "Caching", name, value)); -} - -static int -nscd_set_cf(nsc_stat_t *cache, char *name, int value) -{ - return (nscd_setyesno_sh(&(cache->nsc_check_files), "Checking files", - name, value)); -} - -int -nscd_set_khc(nsc_stat_t *cache, char *name, int value) -{ - if (cache->nsc_pos_ttl < 600 && cache->nsc_keephot) { - logit("ttl less than 600 seconds - disabling keep warm for %s " - "cache\n", name); - return (0); - } else { - return (nscd_set_short(&(cache->nsc_keephot), - "Number of entries to keep hot", name, value, 0, 200)); - } -} - -int -nscd_set_odo(nsc_stat_t *cache, char *name, int value) -{ - return (nscd_setyesno_sh(&(cache->nsc_old_data_ok), - "Allowing return of old data", name, value)); -} - -int -nscd_set_ss(nsc_stat_t *cache, char *name, int value) -{ - return (nscd_set_integer(&(cache->nsc_suggestedsize), - "Suggested size", name, value, 37, 1<<30)); -} - -int -nscd_set_ttl_positive(nsc_stat_t *cache, char *name, int value) -{ - int result = nscd_set_integer(&(cache->nsc_pos_ttl), - "Time to live for positive cache entries", - name, value, 0, 1<<30); - if (cache->nsc_pos_ttl < 600 && cache->nsc_keephot) { - cache->nsc_keephot = 0; - logit("Disabling keephot for cache %s since ttl is less than " - "600 seconds\n", name); - } - return (result); -} - -int -nscd_set_ttl_negative(nsc_stat_t *cache, char *name, int value) -{ - int result = nscd_set_integer(&(cache->nsc_neg_ttl), - "Time to live for negative cache entries", - name, value, 0, 1 << 30); - return (result); -} diff --git a/usr/src/cmd/nscd/nscd_selfcred.c b/usr/src/cmd/nscd/nscd_selfcred.c new file mode 100644 index 0000000000..90b39bb88b --- /dev/null +++ b/usr/src/cmd/nscd/nscd_selfcred.c @@ -0,0 +1,1589 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <stdio.h> +#include <stdlib.h> +#include <synch.h> +#include <thread.h> +#include <string.h> +#include <errno.h> +#include <dlfcn.h> +#include <door.h> +#include <libscf.h> +#include <ucred.h> +#include <sys/varargs.h> +#include <signal.h> +#include <unistd.h> +#include <sys/types.h> +#include <dirent.h> +#include <sys/proc.h> +#include <procfs.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <limits.h> +#include <sys/resource.h> +#include <libscf.h> +#include "nscd_door.h" +#include "nscd_config.h" +#include "nscd_log.h" +#include "nscd_frontend.h" +#include "nscd_selfcred.h" +#include "nscd_admin.h" +#include "nscd_common.h" +#include "ns_sldap.h" + +extern int _logfd; +static char *execpath; +static char **execargv; +static char *selfcred_dbs = NULL; + +static void *get_smf_prop(const char *var, char type, void *def_val); + +/* current self-cred configuration data being used */ +static nscd_cfg_global_selfcred_t nscd_selfcred_cfg_g; + +#define _NSCD_PUN_BLOCK 1024 +static uint8_t pu_nscd_enabled; +static int max_pu_nscd = _NSCD_PUN_BLOCK; +static int pu_nscd_ttl; + +static nscd_rc_t setup_ldap_backend(); +static nscd_rc_t init_user_proc_monitor(); + +/* + * clild state + */ +typedef enum { + CHILD_STATE_NONE = 0, + CHILD_STATE_UIDKNOWN, + CHILD_STATE_FORKSENT, + CHILD_STATE_PIDKNOWN +} child_state_t; + + +typedef struct _child { + int child_slot; + int child_door; + pid_t child_pid; + uid_t child_uid; + gid_t child_gid; + child_state_t child_state; + int next_open; + mutex_t *mutex; + cond_t *cond; +} child_t; + +static child_t **child = NULL; +static mutex_t child_lock = DEFAULTMUTEX; +static int open_head; +static int open_tail; +static int used_slot; + +/* nscd door id */ +extern int _doorfd; +static pid_t main_uid = 0; + +/* nscd id: main, forker, or child */ +extern int _whoami; + +/* forker nscd pid */ +static pid_t forker_pid = 0; +static pid_t forker_uid = 0; + +long activity = 0; +mutex_t activity_lock = DEFAULTMUTEX; + +static int forking_door = -1; +static mutex_t forking_lock = DEFAULTMUTEX; + +static void +free_slot(int s) +{ + if (child[s] == NULL) + return; + free(child[s]->mutex); + free(child[s]->cond); + free(child[s]); + child[s] = NULL; +} + +void +_nscd_free_cslots() +{ + + int i; + + (void) mutex_lock(&child_lock); + + for (i = 0; i < max_pu_nscd; i++) + free_slot(i); + + open_head = -1; + open_tail = -1; + used_slot = -1; + + (void) mutex_unlock(&child_lock); + +} + +static int +init_slot(int s) +{ + child_t *ch; + char *me = "init_slot"; + + if (child[s] == NULL) { + child[s] = (child_t *)calloc(1, sizeof (child_t)); + if (child[s] == NULL) + return (-1); + ch = child[s]; + + if ((ch->mutex = (mutex_t *)calloc(1, + sizeof (mutex_t))) == NULL) { + free(ch); + return (-1); + } + (void) mutex_init(ch->mutex, USYNC_THREAD, NULL); + + if ((ch->cond = (cond_t *)calloc(1, + sizeof (cond_t))) == NULL) { + free(ch->mutex); + free(ch); + return (-1); + } + (void) cond_init(ch->cond, USYNC_THREAD, NULL); + + _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) + (me, "slot %d allocated\n", s); + } else + ch = child[s]; + + ch->child_slot = s; + ch->child_door = 0; + ch->child_state = CHILD_STATE_NONE; + ch->child_pid = 0; + ch->child_uid = 0; + ch->child_gid = 0; + ch->next_open = -1; + + _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) + (me, "slot %d initialized\n", s); + + return (0); +} + +static int +_nscd_init_cslots() +{ + (void) mutex_lock(&child_lock); + + child = (child_t **)calloc(max_pu_nscd, sizeof (child_t *)); + if (child == NULL) + return (-1); + + open_head = -1; + open_tail = -1; + used_slot = -1; + + (void) mutex_unlock(&child_lock); + + return (0); +} + +static child_t * +get_cslot( + uid_t uid, + int no_alloc) +{ + int i; + child_t *ch, *ret = NULL; + char *me = "get_cslot"; + + (void) mutex_lock(&child_lock); + + _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) + (me, "looking for uid %d (slot used = %d)\n", uid, used_slot); + + /* first find the slot with a matching uid */ + for (i = 0; i <= used_slot; i++) { + ch = child[i]; + if (ch->child_state >= CHILD_STATE_UIDKNOWN && + ch->child_uid == uid) { + ret = ch; + (void) mutex_unlock(&child_lock); + + _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) + (me, "slot %d found with uid %d\n", + ret->child_slot, ret->child_uid); + + return (ret); + } + } + + /* if no need to allocate a new slot, return NULL */ + if (no_alloc == 1) { + (void) mutex_unlock(&child_lock); + return (ret); + } + + /* no open slot ? get a new one */ + if (open_head == -1) { + /* if no slot available, allocate more */ + if (used_slot >= max_pu_nscd - 1) { + child_t **tmp; + int newmax = max_pu_nscd + _NSCD_PUN_BLOCK; + + tmp = (child_t **)calloc(newmax, sizeof (child_t *)); + if (tmp == NULL) { + (void) mutex_unlock(&child_lock); + return (ret); + } + (void) memcpy(tmp, child, sizeof (child_t) * + max_pu_nscd); + free(child); + child = tmp; + max_pu_nscd = newmax; + } + used_slot++; + if (init_slot(used_slot) == -1) { + used_slot--; + (void) mutex_unlock(&child_lock); + return (ret); + } + ch = child[used_slot]; + } else { + ch = child[open_head]; + open_head = ch->next_open; + /* got last one ? reset tail */ + if (open_head == -1) + open_tail = -1; + ch->next_open = -1; + } + + ch->child_uid = uid; + ch->child_state = CHILD_STATE_UIDKNOWN; + ret = ch; + + (void) mutex_unlock(&child_lock); + + return (ret); +} + +static void +return_cslot_nolock(child_t *ch) +{ + + int slot = ch->child_slot; + + /* have open slot ? add to and reset tail */ + if (open_tail != -1) { + child[open_tail]->next_open = slot; + open_tail = slot; + } else { + /* no open slot ? make one */ + open_head = open_tail = slot; + } + + (void) init_slot(ch->child_slot); +} + +static void +return_cslot(child_t *ch) +{ + + char *me = "return_cslot"; + + _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) + (me, "returning slot %d\n", ch->child_slot); + + /* return if the slot has been returned by another thread */ + if (ch->child_state == CHILD_STATE_NONE) + return; + + (void) mutex_lock(&child_lock); + + /* check one more time */ + if (ch->child_state == CHILD_STATE_NONE) { + (void) mutex_unlock(&child_lock); + return; + } + + return_cslot_nolock(ch); + + (void) mutex_unlock(&child_lock); +} + +static int +selfcred_kill( + int fd) +{ + int ret; + char *me = "selfcred_kill"; + + _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) + (me, "sending kill to door %d\n", fd); + + if (fd != -1) + ret = _nscd_doorcall_fd(fd, NSCD_KILL, NULL, 0, + NULL, 0, NULL); + else + ret = _nscd_doorcall(NSCD_KILL); + + _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) + (me, "kill request sent to door %d (rc = %d)\n", fd, ret); + + return (ret); +} + + +void +_nscd_kill_forker() +{ + (void) mutex_lock(&forking_lock); + if (forking_door != -1) + (void) selfcred_kill(forking_door); + forking_door = -1; + (void) mutex_unlock(&forking_lock); +} + +void +_nscd_kill_all_children() +{ + int i; + int ret; + char *me = "_nscd_kill_all_children"; + + (void) mutex_lock(&child_lock); + for (i = 0; i <= used_slot; i++) { + if (child[i] == NULL) + continue; + + if (child[i]->child_state >= CHILD_STATE_PIDKNOWN) { + _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) + (me, "killing child process %d (doorfd %d)\n", + child[i]->child_pid, child[i]->child_door); + + ret = selfcred_kill(child[i]->child_door); + + if (ret != -1) + (void) kill(child[i]->child_pid, SIGTERM); + } + if (child[i]->child_state != CHILD_STATE_NONE) + (void) return_cslot_nolock(child[i]); + } + (void) mutex_unlock(&child_lock); +} +static int +selfcred_pulse( + int fd) +{ + int ret; + char *me = "selfcred_pulse"; + + _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) + (me, "start monitoring door %d\n", fd); + + ret = _nscd_doorcall_fd(fd, NSCD_PULSE |(_whoami & NSCD_WHOAMI), + NULL, 0, NULL, 0, NULL); + + _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) + (me, "door (%d) monitor exited (rc = %d)\n", fd, ret); + + return (ret); +} + +/*ARGSUSED*/ +static void * +forker_monitor( + void *arg) +{ + pid_t fpid; + char *fmri; + char *me = "forker_monitor"; + + /* wait until forker exits */ + fpid = forker_pid; + (void) selfcred_pulse(forking_door); + + _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) +(me, "forker (pid = %d) exited or crashed, killing all child processes\n", + fpid); + + (void) mutex_lock(&forking_lock); + forking_door = -1; + forker_pid = -1; + (void) mutex_unlock(&forking_lock); + + /* forker exited/crashed, kill all the child processes */ + _nscd_kill_all_children(); + + /* restart forker */ + _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) + (me, "restarting the forker ...\n"); + + switch (fpid = fork1()) { + case (pid_t)-1: + _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) + (me, "unable to fork and start the forker ...\n"); + + /* enter the maintenance mode */ + if ((fmri = getenv("SMF_FMRI")) != NULL) { + _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) + (me, "entering maintenance mode ...\n"); + smf_maintain_instance(fmri, SMF_TEMPORARY); + } + thr_exit((void *)1); + break; + case 0: + _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) + (me, "execv path = %s\n", execpath); + + (void) execv(execpath, execargv); + exit(0); + break; + default: + _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) + (me, "new forker's pid is %d\n", fpid); + forker_pid = fpid; + break; + } + + thr_exit((void *)0); + + /*LINTED E_FUNC_HAS_NO_RETURN_STMT*/ +} + +static void * +child_monitor( + void *arg) +{ + child_t *ch = (child_t *)arg; + pid_t cpid; + char *me = "child_monitor"; + + /* wait until child exits */ + cpid = ch->child_pid; + (void) selfcred_pulse(ch->child_door); + + _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) + (me, "child (pid = %d) exited or crashed ...\n", cpid); + + /* return the slot used by the child */ + return_cslot(ch); + + thr_exit((void *)0); + /*LINTED E_FUNC_HAS_NO_RETURN_STMT*/ +} + + +void +_nscd_proc_iamhere( + void *buf, + door_desc_t *dp, + uint_t n_desc, + int iam) +{ + int cslot; + child_t *ch; + int errnum; + ucred_t *uc = NULL; + uid_t uid; + nscd_imhere_t *ih; + nss_pheader_t *phdr = (nss_pheader_t *)buf; + char *me = "_nscd_proc_iamhere"; + + + _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) + (me, "%d receives iamhere from %d\n", _whoami, iam); + + if (door_ucred(&uc) != 0) { + errnum = errno; + _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) + (me, "door_ucred failed: %s\n", strerror(errnum)); + + NSCD_RETURN_N2N_STATUS(phdr, NSS_NSCD_PRIV, errnum, + NSCD_DOOR_UCRED_ERROR); + } + uid = ucred_geteuid(uc); + + switch (iam) { + + case NSCD_MAIN: + if (_whoami == NSCD_MAIN || uid != main_uid) { + /* + * I'm main, or uid from door is not correct, + * this must be an imposter + */ + _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) + (me, "MAIN IMPOSTER CAUGHT!\n"); + + + NSCD_SET_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0, + NSCD_SELF_CRED_MAIN_IMPOSTER); + } + break; + + case NSCD_FORKER: + if (_whoami == NSCD_FORKER || uid != forker_uid) { + /* + * I'm forker, or uid from door is not correct, + * this must be an imposter + */ + _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) + (me, "FORKER IMPOSTER CAUGHT!\n"); + + + NSCD_SET_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0, + NSCD_SELF_CRED_FORKER_IMPOSTER); + break; + } + + /* only main needs to know the forker */ + if (_whoami != NSCD_MAIN) { + + NSCD_SET_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0, + NSCD_SELF_CRED_WRONG_NSCD); + break; + } + + if (ucred_getpid(uc) != forker_pid) { + _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) + (me, "FORKER IMPOSTER CAUGHT: pid = %d should be %d\n", + ucred_getpid(uc), forker_pid); + + + NSCD_SET_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0, + NSCD_SELF_CRED_FORKER_IMPOSTER); + break; + } + + if (n_desc < 1) { + _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) + (me, "BAD FORKER, NO DOOR!\n"); + + + NSCD_SET_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0, + NSCD_SELF_CRED_NO_DOOR); + break; + } + + if ((dp->d_attributes & DOOR_DESCRIPTOR) && + dp->d_data.d_desc.d_descriptor > 0 && + dp->d_data.d_desc.d_id != 0) { + (void) mutex_lock(&forking_lock); + if (forking_door != -1) + (void) close(forking_door); + forking_door = dp->d_data.d_desc.d_descriptor; + (void) mutex_unlock(&forking_lock); + + _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) + (me, "forking door is %d\n", forking_door); + + NSCD_SET_STATUS_SUCCESS(phdr); + } else { + NSCD_SET_STATUS(phdr, NSS_ALTRETRY, 0); + break; + } + + /* monitor the forker nscd */ + (void) thr_create(NULL, 0, forker_monitor, NULL, + THR_DETACHED, NULL); + + break; + + case NSCD_CHILD: + if (_whoami != NSCD_MAIN) { + /* child nscd can only talk to the main nscd */ + _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) + (me, "CHILD IMPOSTER CAUGHT!\n"); + + NSCD_SET_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0, + NSCD_SELF_CRED_CHILD_IMPOSTER); + break; + } + + /* get the main nscd assigned slot number */ + ih = NSCD_N2N_DOOR_DATA(nscd_imhere_t, buf); + cslot = ih->slot; + (void) mutex_lock(&child_lock); + if (cslot < 0 || cslot >= max_pu_nscd) + ch = NULL; + else + ch = child[cslot]; + (void) mutex_unlock(&child_lock); + + if (ch == NULL) { + /* Bad slot number */ + _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) + (me, "bad slot number %d\n", cslot); + + NSCD_SET_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0, + NSCD_SELF_CRED_INVALID_SLOT_NUMBER); + break; + } + + if (uid != ch->child_uid) { + _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) + (me, "CHILD IMPOSTER CAUGHT: uid = %d should be %d\n", + uid, ch->child_uid); + + NSCD_SET_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0, + NSCD_SELF_CRED_CHILD_IMPOSTER); + break; + } + + if (ch->child_state != CHILD_STATE_UIDKNOWN && + ch->child_state != CHILD_STATE_FORKSENT) { + _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) + (me, "invalid slot/child state (%d) for uid %d\n", + ch->child_state, uid); + + NSCD_SET_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0, + NSCD_SELF_CRED_INVALID_SLOT_STATE); + break; + } + + _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) + (me, "d_descriptor = %d, d_id = %lld\n", + dp->d_data.d_desc.d_descriptor, dp->d_data.d_desc.d_id); + + if ((dp->d_attributes & DOOR_DESCRIPTOR) && + dp->d_data.d_desc.d_descriptor > 0 && + dp->d_data.d_desc.d_id != 0) { + (void) mutex_lock(ch->mutex); + if (ch->child_door != -1) + (void) close(ch->child_door); + ch->child_door = dp->d_data.d_desc.d_descriptor; + ch->child_pid = ucred_getpid(uc); + ch->child_state = CHILD_STATE_PIDKNOWN; + _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) + (me, "child in slot %d has door %d\n", + cslot, ch->child_door); + + /* + * let waiters know that the child is ready to + * serve + */ + (void) cond_broadcast(ch->cond); + (void) mutex_unlock(ch->mutex); + + /* monitor the child nscd */ + (void) thr_create(NULL, 0, child_monitor, + ch, THR_DETACHED, NULL); + NSCD_SET_STATUS_SUCCESS(phdr); + break; + } else { + NSCD_SET_STATUS(phdr, NSS_ALTRETRY, 0); + } + break; + } + + ucred_free(uc); + uc = NULL; +} + +void +_nscd_proc_pulse( + void *buf, + int iam) +{ + long last_active; + int done = 0; + nss_pheader_t *phdr = (nss_pheader_t *)buf; + char *me = "_nscd_proc_pulse"; + + /* only main nscd sends pulse */ + if (iam != NSCD_MAIN) { + _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) + (me, "MAIN IMPOSTER CAUGHT! i am %d not NSCD_MAIN\n", iam); + + NSCD_RETURN_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0, + NSCD_SELF_CRED_MAIN_IMPOSTER); + } + + /* forker doesn't return stats, it just pauses */ + if (_whoami == NSCD_FORKER) { + _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) + (me, "forker ready to pause ...\n"); + + /*CONSTCOND*/ + while (1) + (void) pause(); + + NSCD_RETURN_STATUS_SUCCESS(phdr); + } + + /* remember the current activity sequence number */ + (void) mutex_lock(&activity_lock); + last_active = activity; + (void) mutex_unlock(&activity_lock); + + while (!done) { + + /* allow per_user_nscd_ttl seconds of inactivity */ + (void) sleep(pu_nscd_ttl); + + (void) mutex_lock(&activity_lock); + if (last_active == activity) + done = 1; + else { + last_active = activity; + _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) + (me, "active, sleep again for %d seconds\n", + pu_nscd_ttl); + } + (void) mutex_unlock(&activity_lock); + } + + /* no activity in the specified seconds, exit and disconnect */ + _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) + (me, "no activity in the last %d seconds, exit\n", pu_nscd_ttl); + exit(0); +} + +void +_nscd_proc_fork( + void *buf, + int iam) +{ + int slot; + int ret; + char *fmri; + pid_t cid; + uid_t set2uid; + gid_t set2gid; + nss_pheader_t *phdr = (nss_pheader_t *)buf; + char *me = "_nscd_proc_fork"; + nscd_fork_t *f; + nscd_imhere_t ih; + + _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) + (me, "%d receives fork request from %d\n", _whoami, iam); + + /* only main nscd sends fork requests */ + if (iam != NSCD_MAIN) { + _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) + (me, "MAIN IMPOSTER CAUGHT! i am %d not NSCD_MAIN\n", + iam); + + NSCD_RETURN_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0, + NSCD_SELF_CRED_MAIN_IMPOSTER); + } + + /* only forker handles fork requests */ + if (_whoami != NSCD_FORKER) { + _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) + (me, "MAIN IMPOSTER CAUGHT! I AM NOT FORKER!\n"); + + NSCD_RETURN_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0, + NSCD_SELF_CRED_WRONG_NSCD); + } + + /* fork a child for the slot assigned by the main nscd */ + f = NSCD_N2N_DOOR_DATA(nscd_fork_t, buf); + slot = f->slot; + /* set the uid/gid as assigned by the main nscd */ + set2uid = f->uid; + set2gid = f->gid; + + /* ignore bad slot number */ + if (slot < 0 || slot >= max_pu_nscd) { + _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) + (me, "bas slot number\n"); + + NSCD_RETURN_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0, + NSCD_SELF_CRED_INVALID_SLOT_NUMBER); + } + + _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) + (me, "before fork1() ...\n"); + + if ((cid = fork1()) == 0) { + _whoami = NSCD_CHILD; + + /* close all except the log file */ + if (_logfd > 0) { + int i; + for (i = 0; i < _logfd; i++) + (void) close(i); + closefrom(_logfd + 1); + } else + closefrom(0); + + _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) + (me, "child %d\n", getpid()); + + (void) setgid(set2gid); + (void) setuid(set2uid); + + /* set up the door and server thread pool */ + if ((_doorfd = _nscd_setup_child_server(_doorfd)) == -1) + exit(-1); + + /* tell libsldap to do self cred only */ + (void) setup_ldap_backend(); + + /* notify main that child is active */ + ih.slot = slot; + for (ret = NSS_ALTRETRY; ret == NSS_ALTRETRY; ) + ret = _nscd_doorcall_sendfd(_doorfd, + NSCD_IMHERE | (NSCD_CHILD & NSCD_WHOAMI), + &ih, sizeof (ih), NULL); + + NSCD_RETURN_STATUS_SUCCESS(phdr); + } if (cid == (pid_t)-1) { + _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) + (me, "forker unable to fork ...\n"); + + /* enter the maintenance mode */ + if ((fmri = getenv("SMF_FMRI")) != NULL) { + _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) + (me, "entering maintenance mode ...\n"); + smf_maintain_instance(fmri, SMF_TEMPORARY); + } + exit(0); + } else { + /* + * start the monitor so as to exit as early as + * possible if no other processes are running + * with the same PUN uid (i.e., this PUN is + * not needed any more) + */ + (void) init_user_proc_monitor(); + + _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) + (me, "child forked: parent pid = %d, child pid = %d\n", + getpid(), cid); + + NSCD_SET_STATUS_SUCCESS(phdr); + } + + _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) + (me, "after fork\n"); +} + +static void +selfcred_fork( + void *buf, + int doorfd, + int cslot, + uid_t uid, + gid_t gid) +{ + int ret; + nscd_fork_t f; + nss_pheader_t *phdr = (nss_pheader_t *)buf; + char *me = "selfcred_fork"; + + /* if no door fd, do nothing */ + if (doorfd == -1) { + NSCD_SET_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0, + NSCD_SELF_CRED_NO_DOOR); + } + + _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) + (me, "sending fork request to door %d for slot %d " + "(uid = %d, gid = %d)\n", doorfd, cslot, uid, gid); + + f.slot = cslot; + f.uid = uid; + f.gid = gid; + + ret = _nscd_doorcall_fd(doorfd, NSCD_FORK|(_whoami&NSCD_WHOAMI), + &f, sizeof (f), NULL, 0, phdr); + + _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) + (me, "fork request sent to door %d for slot %d (rc = %d)\n", + doorfd, cslot, ret); + + if (NSCD_STATUS_IS_NOT_OK(phdr)) { + + _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) + (me, "fork request sent to door %d for slot %d failed: " + "status = %d, errno = %s, nscd status = %d\n", doorfd, + cslot, NSCD_GET_STATUS(phdr), strerror(NSCD_GET_ERRNO(phdr)), + NSCD_GET_NSCD_STATUS(phdr)); + + } +} + +void +_nscd_proc_alt_get( + void *buf, + int *door) +{ + int errnum; + uid_t set2uid; + gid_t set2gid; + nss_pheader_t *phdr = (nss_pheader_t *)buf; + char *me = "_nscd_proc_alt_get"; + ucred_t *uc = NULL; + child_t *ch; + + _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) + (me, "getting an alternate door ...\n"); + + /* make sure there is a door to talk to the forker */ + if (forking_door == -1) { + _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_ERROR) + (me, "no door to talk to the forker\n"); + + NSCD_RETURN_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0, + NSCD_SELF_CRED_NO_FORKER); + } + + /* get door client's credential information */ + if (door_ucred(&uc) != 0) { + errnum = errno; + _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) + (me, "door_ucred failed: %s\n", strerror(errnum)); + + NSCD_RETURN_N2N_STATUS(phdr, NSS_NSCD_PRIV, errnum, + NSCD_DOOR_UCRED_ERROR); + } + + /* get door client's effective uid and effective gid */ + set2uid = ucred_geteuid(uc); + set2gid = ucred_getegid(uc); + ucred_free(uc); + uc = NULL; + + _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) + (me, "child uid = %d, gid = %d\n", set2uid, set2gid); + + /* is a slot available ? if not, no one to serve */ + if (child == NULL || (ch = get_cslot(set2uid, 0)) == NULL) { + + _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) + (me, "no child slot available (child array = %p, slot = %d)\n", + child, ch->child_slot); + + NSCD_RETURN_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0, + NSCD_SELF_CRED_NO_CHILD_SLOT); + } + + /* create the per user nscd if necessary */ + if (ch->child_state != CHILD_STATE_PIDKNOWN) { + + nss_pheader_t phdr1; + NSCD_CLEAR_STATUS(&phdr1); + + (void) mutex_lock(ch->mutex); + if (ch->child_state == CHILD_STATE_UIDKNOWN) { + + /* ask forker to fork a new child */ + selfcred_fork(&phdr1, forking_door, ch->child_slot, + set2uid, set2gid); + if (NSCD_STATUS_IS_NOT_OK(&phdr1)) { + (void) mutex_unlock(ch->mutex); + NSCD_COPY_STATUS(phdr, &phdr1); + return; + } + ch->child_state = CHILD_STATE_FORKSENT; + } + + _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) + (me, "waiting for door (slot = %d, uid = %d, gid = %d)\n", + ch->child_slot, set2uid, set2gid); + + /* wait for the per user nscd to become available */ + while (ch->child_state == CHILD_STATE_FORKSENT) { + timestruc_t to; + int err; + int ttl = 5; + + to.tv_sec = ttl; + to.tv_nsec = 0; + _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) + (me, "cond_reltimedwait %d seconds\n", ttl); + err = cond_reltimedwait(ch->cond, ch->mutex, &to); + if (err == ETIME) { + ch->child_state = + CHILD_STATE_UIDKNOWN; + _NSCD_LOG(NSCD_LOG_SELF_CRED, + NSCD_LOG_LEVEL_DEBUG) + (me, "door wait timedout (slot = %d)\n", + ch->child_slot); + break; + } + } + (void) mutex_unlock(ch->mutex); + } + + if (ch->child_state != CHILD_STATE_PIDKNOWN) { + + NSCD_RETURN_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0, + NSCD_SELF_CRED_INVALID_SLOT_STATE); + } + + *door = ch->child_door; + + _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) + (me, "returning door %d for slot %d, uid %d, gid = %d\n", + *door, ch->child_slot, set2uid, set2gid); + + NSCD_RETURN_STATUS(phdr, NSS_ALTRETRY, 0); +} + +static char ** +cpargv( + int argc, + char **inargv) +{ + char **newargv; + int c = 4; + int i = 0, j, k = 0, n = 0; + + newargv = (char **)calloc(c + 1, sizeof (char *)); + if (newargv == NULL) + return (NULL); + + newargv[n] = strdup(inargv[0]); + if (newargv[n++] == NULL) { + free(newargv); + return (NULL); + } + + newargv[n] = strdup("-F"); + if (newargv[n++] == NULL) { + free(newargv[0]); + free(newargv); + return (NULL); + } + + for (i = 1; i < argc; i++) { + if (strcmp(inargv[i], "-f") == 0) + k = 2; + if (k == 0) + continue; + + newargv[n] = strdup(inargv[i]); + if (newargv[n] == NULL) { + for (j = 0; j < n; j++) + free(newargv[j]); + free(newargv); + return (NULL); + } + + k--; + n++; + } + return (newargv); +} + + +void +_nscd_start_forker( + char *path, + int argc, + char **argv) +{ + pid_t cid; + struct rlimit rl; + char *me = "_nscd_start_forker"; + + /* if self cred is not configured, do nothing */ + if (!_nscd_is_self_cred_on(1, NULL)) + return; + + /* save pathname and generate the new argv for the forker */ + execpath = strdup(path); + execargv = cpargv(argc, argv); + if (execpath == NULL || execargv == NULL) + exit(1); + + switch (cid = fork1()) { + case (pid_t)-1: + exit(1); + break; + case 0: + /* start the forker nscd */ + (void) execv(path, execargv); + exit(0); + break; + default: + /* main nscd */ + /* remember process id of the forker */ + forker_pid = cid; + + /* set NOFILE to unlimited */ + rl.rlim_cur = rl.rlim_max = RLIM_INFINITY; + if (setrlimit(RLIMIT_NOFILE, &rl) < 0) { + _NSCD_LOG(NSCD_LOG_SELF_CRED, + NSCD_LOG_LEVEL_ERROR) + (me, "Cannot set open file limit: %s\n", + strerror(errno)); + exit(1); + } + + /* enable child nscd management */ + (void) _nscd_init_cslots(); + break; + } +} + +static nscd_rc_t +get_ldap_funcs( + char *name, + void **func_p) +{ + char *me = "get_ldap_funcs"; + static void *handle = NULL; + void *sym; + + if (name == NULL && handle != NULL) { + (void) dlclose(handle); + return (NSCD_SUCCESS); + } + /* no handle to close, it's OK */ + if (name == NULL) + return (NSCD_SUCCESS); + + if (handle == NULL) { + handle = dlopen("libsldap.so.1", RTLD_LAZY); + if (handle == NULL) { + + _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_ERROR) + (me, "unable to dlopen libsldap.so.1"); + return (NSCD_CFG_DLOPEN_ERROR); + } + } + + if ((sym = dlsym(handle, name)) == NULL) { + + _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_ERROR) + (me, "unable to find symbol %s", name); + return (NSCD_CFG_DLSYM_ERROR); + } else + (void) memcpy(func_p, &sym, sizeof (void *)); + + return (NSCD_SUCCESS); +} + + +int +_nscd_is_self_cred_on(int recheck, char **dblist) +{ + static int checked = 0; + static int is_on = 0; + static int (*ldap_func)(); + char *srcs = "ldap"; /* only ldap support self cred */ + int ldap_on = 0; + + char *ldap_sc_func = "__ns_ldap_self_gssapi_config"; + ns_ldap_self_gssapi_config_t ldap_config; + + if (checked && !recheck) { + if (is_on && dblist != NULL) + *dblist = selfcred_dbs; + return (is_on); + } + + if (selfcred_dbs != NULL) + free(selfcred_dbs); + selfcred_dbs = _nscd_srcs_in_db_nsw_policy(1, &srcs); + + /* + * also check the ldap backend to see if + * the configuration there is good for + * doing self credentialing + */ + if (ldap_func == NULL) + (void) get_ldap_funcs(ldap_sc_func, (void **)&ldap_func); + if (ldap_func != NULL) { + if (ldap_func(&ldap_config) == NS_LDAP_SUCCESS && + ldap_config != NS_LDAP_SELF_GSSAPI_CONFIG_NONE) + ldap_on = 1; + } + + is_on = pu_nscd_enabled == nscd_true && + ldap_on && selfcred_dbs != NULL; + + checked = 1; + + if (is_on && dblist != NULL) + *dblist = selfcred_dbs; + + return (is_on); +} + +static nscd_rc_t +setup_ldap_backend() +{ + nscd_rc_t rc; + static void (*ldap_func)(); + char *ldap_sc_func = "__ns_ldap_self_gssapi_only_set"; + if (ldap_func == NULL) + rc = get_ldap_funcs(ldap_sc_func, (void **)&ldap_func); + if (ldap_func != NULL) { + ldap_func(1); + return (NSCD_SUCCESS); + } + return (rc); +} + +/*ARGSUSED*/ +void +_nscd_peruser_getadmin( + void *buf, + int buf_size) +{ + void *result_mn = NSCD_N2N_DOOR_DATA(void, buf); + int errnum = 0; + int ret; + uid_t uid; + nss_pheader_t *phdr = (nss_pheader_t *)buf; + char *me = "_nscd_peruser_getadmin"; + ucred_t *uc = NULL; + child_t *ch; + + /* get door client's credential information */ + if (door_ucred(&uc) != 0) { + errnum = errno; + _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) + (me, "door_ucred failed: %s\n", strerror(errnum)); + + NSCD_RETURN_N2N_STATUS(phdr, NSS_NSCD_PRIV, errnum, + NSCD_DOOR_UCRED_ERROR); + } + + /* get door client's effective uid */ + uid = ucred_geteuid(uc); + ucred_free(uc); + uc = NULL; + + _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) + (me, "per user get admin ... (uid = %d)\n", uid); + + /* is the per-user nscd running ? if not, no one to serve */ + ch = get_cslot(uid, 1); + if (ch == NULL) { + NSCD_RETURN_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0, + NSCD_SELF_CRED_NO_CHILD_SLOT); + } + + ret = _nscd_doorcall_fd(ch->child_door, NSCD_GETADMIN, + NULL, sizeof (nscd_admin_t), result_mn, + sizeof (nscd_admin_t), phdr); + + if (ret == NSS_SUCCESS) { + phdr->data_len = sizeof (nscd_admin_t); + return; + } +} + +static void +set_selfcred_cfg( + char param, + void *data) +{ + int64_t prop_int; + char *me = "set_selfcred_cfg"; + + if (param == 'a' || param == 'e') { + pu_nscd_enabled = *(uint8_t *)get_smf_prop( + "enable_per_user_lookup", 'b', data); + + _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) + (me, "self cred config: enabled = %d\n", pu_nscd_enabled); + } + + if (param == 'a' || param == 't') { + prop_int = *(int *)data; + pu_nscd_ttl = *(int64_t *)get_smf_prop( + "per_user_nscd_time_to_live", 'i', &prop_int); + + _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) + (me, "self cred config: PUN TTL = %d\n", pu_nscd_ttl); + } +} + +/* ARGSUSED */ +nscd_rc_t +_nscd_cfg_selfcred_notify( + void *data, + struct nscd_cfg_param_desc *pdesc, + nscd_cfg_id_t *nswdb, + nscd_cfg_flag_t dflag, + nscd_cfg_error_t **errorp, + void *cookie) +{ + + nscd_cfg_global_selfcred_t *sc_cfg = &nscd_selfcred_cfg_g; + int off; + + /* + * At init time, the whole group of config params are received. + * At update time, group or individual parameter value could + * be received. + */ + + if (_nscd_cfg_flag_is_set(dflag, NSCD_CFG_DFLAG_GROUP)) { + + *sc_cfg = *(nscd_cfg_global_selfcred_t *)data; + + off = offsetof(nscd_cfg_global_selfcred_t, + enable_selfcred); + set_selfcred_cfg('e', (char *)data + off); + + off = offsetof(nscd_cfg_global_selfcred_t, + max_per_user_nscd); + set_selfcred_cfg('n', (char *)data + off); + + off = offsetof(nscd_cfg_global_selfcred_t, + per_user_nscd_ttl); + set_selfcred_cfg('t', (char *)data + off); + + return (NSCD_SUCCESS); + } + + /* + * individual config parameter + */ + off = offsetof(nscd_cfg_global_selfcred_t, enable_selfcred); + if (pdesc->p_offset == off) { + sc_cfg->enable_selfcred = *(nscd_bool_t *)data; + set_selfcred_cfg('e', data); + return (NSCD_SUCCESS); + } + + off = offsetof(nscd_cfg_global_selfcred_t, max_per_user_nscd); + if (pdesc->p_offset == off) { + sc_cfg->max_per_user_nscd = *(int *)data; + set_selfcred_cfg('n', data); + return (NSCD_SUCCESS); + } + + off = offsetof(nscd_cfg_global_selfcred_t, per_user_nscd_ttl); + if (pdesc->p_offset == off) { + sc_cfg->per_user_nscd_ttl = *(int *)data; + set_selfcred_cfg('t', data); + return (NSCD_SUCCESS); + } + + return (NSCD_SUCCESS); +} + +/* ARGSUSED */ +nscd_rc_t +_nscd_cfg_selfcred_verify( + void *data, + struct nscd_cfg_param_desc *pdesc, + nscd_cfg_id_t *nswdb, + nscd_cfg_flag_t dflag, + nscd_cfg_error_t **errorp, + void **cookie) +{ + + return (NSCD_SUCCESS); +} + +/* ARGSUSED */ +nscd_rc_t +_nscd_cfg_selfcred_get_stat( + void **stat, + struct nscd_cfg_stat_desc *sdesc, + nscd_cfg_id_t *nswdb, + nscd_cfg_flag_t *dflag, + void (**free_stat)(void *stat), + nscd_cfg_error_t **errorp) +{ + return (NSCD_SUCCESS); +} + +static int +check_uid(char *pid_name) +{ + char pname[PATH_MAX]; + static pid_t pid = 0; + static uid_t uid = 0; + static uid_t euid = 0; + int pfd; /* file descriptor for /proc/<pid>/psinfo */ + psinfo_t info; /* process information from /proc */ + + if (uid == 0) { + pid = getpid(); + uid = getuid(); + euid = geteuid(); + } + + (void) snprintf(pname, sizeof (pname), "/proc/%s/psinfo", pid_name); +retry: + if ((pfd = open(pname, O_RDONLY)) == -1) { + /* Process may have exited */ + return (1); + } + + /* + * Get the info structure for the process and close quickly. + */ + if (read(pfd, (char *)&info, sizeof (info)) < 0) { + int saverr = errno; + + (void) close(pfd); + if (saverr == EAGAIN) + goto retry; + if (saverr != ENOENT) + return (1); + } + (void) close(pfd); + + if (info.pr_pid != pid && + info.pr_uid == uid && info.pr_euid == euid) + return (0); + else + return (1); +} + + +/* + * FUNCTION: check_user_process + */ +/*ARGSUSED*/ +static void * +check_user_process(void *arg) +{ + + DIR *dp; + struct dirent *ep; + int found; + char *me = "check_user_process"; + + /*CONSTCOND*/ + while (1) { + (void) sleep(60); + + found = 0; + + /* + * search the /proc directory and look at each process + */ + if ((dp = opendir("/proc")) == NULL) { + _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_ERROR) + (me, "unable to open the /proc directory\n"); + continue; + } + + /* for each active process */ + while (ep = readdir(dp)) { + if (ep->d_name[0] == '.') /* skip . and .. */ + continue; + if (check_uid(ep->d_name) == 0) { + found = 1; + break; + } + } + + /* + * if no process running as the PUN uid found, exit + * to kill this PUN + */ + if (found == 0) { + (void) closedir(dp); + exit(1); + } + (void) closedir(dp); + } + /* NOTREACHED */ + /*LINTED E_FUNC_HAS_NO_RETURN_STMT*/ +} + +static nscd_rc_t +init_user_proc_monitor() { + + int errnum; + char *me = "init_user_proc_monitor"; + + _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) + (me, "initializing the user process monitor\n"); + + /* + * start a thread to make sure there is at least a process + * running as the PUN user. If not, terminate this PUN. + */ + if (thr_create(NULL, NULL, check_user_process, + NULL, THR_DETACHED, NULL) != 0) { + errnum = errno; + _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_ERROR) + (me, "thr_create: %s\n", strerror(errnum)); + return (NSCD_THREAD_CREATE_ERROR); + } + + return (NSCD_SUCCESS); +} + +static void * +get_smf_prop(const char *var, char type, void *def_val) +{ + scf_simple_prop_t *prop; + void *val = def_val; + char *me = "get_smf_prop"; + + prop = scf_simple_prop_get(NULL, NULL, "config", var); + if (prop) { + switch (type) { + case 'b': + val = scf_simple_prop_next_boolean(prop); + break; + + case 'i': + val = scf_simple_prop_next_integer(prop); + break; + + case 'c': + val = scf_simple_prop_next_count(prop); + break; + } + scf_simple_prop_free(prop); + } + + if (prop == NULL || val == NULL) { + char vs[64]; + + switch (type) { + case 'b': + if (*(uint8_t *)def_val) + (void) strcpy(vs, "yes"); + else + (void) strcpy(vs, "no"); + + break; + + case 'i': + case 'c': + (void) sprintf(vs, "%lld", *(int64_t *)def_val); + break; + + } + _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_ALERT) + (me, "no value for config/%s (%s). " + "Using default \"%s\"\n", var, + scf_strerror(scf_error()), vs); + } + + return (val); +} diff --git a/usr/src/cmd/nscd/nscd_selfcred.h b/usr/src/cmd/nscd/nscd_selfcred.h new file mode 100644 index 0000000000..6a42c226e4 --- /dev/null +++ b/usr/src/cmd/nscd/nscd_selfcred.h @@ -0,0 +1,75 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _NSCD_SELFCRED_H +#define _NSCD_SELFCRED_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + +#include <unistd.h> +#include <door.h> +#include "nscd_door.h" + +/* + * structure used for door call NSCD_IMHERE + */ +typedef struct nscd_imhere { + int slot; +} nscd_imhere_t; + +/* + * structure used for door call NSCD_FORK + */ +typedef struct nscd_fork { + int slot; + uid_t uid; + gid_t gid; +} nscd_fork_t; + +/* + * prototypes + */ +int _nscd_is_self_cred_on(int recheck, char **dblist); +void _nscd_set_forker_pid(pid_t pid); +void _nscd_free_cslots(); +void _nscd_kill_forker(); +void _nscd_kill_all_children(); +void _nscd_proc_iamhere(void *buf, door_desc_t *dp, + uint_t n_desc, int iam); +void _nscd_proc_pulse(void *buf, int iam); +void _nscd_proc_fork(void *buf, int iam); +void _nscd_proc_alt_get(void *buf, int *door); +void _nscd_start_forker(char *path, int argc, char **argv); +void _nscd_peruser_getadmin(void *buf, int buf_size); + +#ifdef __cplusplus +} +#endif + +#endif /* _NSCD_SELFCRED_H */ diff --git a/usr/src/cmd/nscd/nscd_seqnum.c b/usr/src/cmd/nscd/nscd_seqnum.c new file mode 100644 index 0000000000..bf1c1d9e39 --- /dev/null +++ b/usr/src/cmd/nscd/nscd_seqnum.c @@ -0,0 +1,59 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include "nscd_db.h" + +static nscd_seq_num_t acc_seq = 1; +static mutex_t seq_mutex = DEFAULTMUTEX; +static nscd_cookie_t cookie = 1234; +static mutex_t cookie_mutex = DEFAULTMUTEX; + +nscd_seq_num_t +_nscd_get_seq_num() +{ + nscd_seq_num_t seq_num; + + (void) mutex_lock(&seq_mutex); + seq_num = acc_seq; + acc_seq += 1; + (void) mutex_unlock(&seq_mutex); + + return (seq_num); +} + +nscd_cookie_t +_nscd_get_cookie() +{ + nscd_cookie_t ret; + + (void) mutex_lock(&cookie_mutex); + ret = cookie; + cookie += 1; + (void) mutex_unlock(&cookie_mutex); + + return (ret); +} diff --git a/usr/src/cmd/nscd/nscd_smfmonitor.c b/usr/src/cmd/nscd/nscd_smfmonitor.c new file mode 100644 index 0000000000..ab6c647083 --- /dev/null +++ b/usr/src/cmd/nscd/nscd_smfmonitor.c @@ -0,0 +1,209 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <stdlib.h> +#include <libscf.h> +#include <string.h> +#include "nscd_switch.h" +#include "nscd_log.h" +#include "nscd_door.h" + +extern int _whoami; + +/* + * Service states monitored by nscd. Protected by + * readers/writer lock nscd_smf_service_state_lock + */ +nscd_smf_state_t *nscd_smf_service_state; +static rwlock_t nscd_smf_service_state_lock = DEFAULTRWLOCK; +/* + * init service state table + */ +nscd_rc_t +_nscd_alloc_service_state_table() +{ + int i; + + nscd_smf_service_state = calloc(NSCD_NUM_SMF_FMRI, + sizeof (nscd_smf_state_t)); + + if (nscd_smf_service_state == NULL) + return (NSCD_NO_MEMORY); + + for (i = 1; i < NSCD_NUM_SMF_FMRI; i++) + NSCD_SMF_SVC_STATE(i) = NSCD_SVC_STATE_UNINITED; + + return (NSCD_SUCCESS); +} + +static int +query_smf_state(int srci) +{ + + int ret = NSCD_SVC_STATE_UNINITED; + char *state = NULL; + char *me = "query_smf_state"; + + state = smf_get_state(NSCD_SMF_SVC_FMRI(srci)); + if (state == NULL) + return (ret); + + _NSCD_LOG(NSCD_LOG_SMF_MONITOR, NSCD_LOG_LEVEL_DEBUG) + (me, "%s -- %s\n", state, NSCD_SMF_SVC_FMRI(srci)); + + (void) rw_wrlock(&nscd_smf_service_state_lock); + + if (nscd_smf_service_state[srci].src_name == NULL) + nscd_smf_service_state[srci].src_name = + NSCD_NSW_SRC_NAME(srci); + + if (strcmp(state, SCF_STATE_STRING_UNINIT) == 0) + NSCD_SMF_SVC_STATE(srci) = SCF_STATE_UNINIT; + else if (strcmp(state, SCF_STATE_STRING_MAINT) == 0) + NSCD_SMF_SVC_STATE(srci) = SCF_STATE_MAINT; + else if (strcmp(state, SCF_STATE_STRING_OFFLINE) == 0) + NSCD_SMF_SVC_STATE(srci) = SCF_STATE_OFFLINE; + else if (strcmp(state, SCF_STATE_STRING_DISABLED) == 0) + NSCD_SMF_SVC_STATE(srci) = SCF_STATE_DISABLED; + else if (strcmp(state, SCF_STATE_STRING_ONLINE) == 0) + NSCD_SMF_SVC_STATE(srci) = SCF_STATE_ONLINE; + else if (strcmp(state, SCF_STATE_STRING_DEGRADED) == 0) + NSCD_SMF_SVC_STATE(srci) = SCF_STATE_DEGRADED; + + ret = NSCD_SMF_SVC_STATE(srci); + (void) rw_unlock(&nscd_smf_service_state_lock); + + free(state); + return (ret); +} + +/* ARGSUSED */ +static void * +set_smf_state(void *arg) +{ + + int i; + int st; + + /* + * the forker nscd needs not monitor the state + * of the client services + */ + if (_whoami == NSCD_FORKER) + thr_exit(0); + + /*CONSTCOND*/ + while (1) { + + /* skip the first service which is nscd */ + for (i = 1; i < NSCD_NUM_SMF_FMRI; i++) { + st = query_smf_state(i); + if (st == NSCD_SVC_STATE_UNINITED) + break; + } + + (void) sleep(NSCD_SW_CFG_G.check_smf_state_interval_g); + } + /* NOTREACHED */ + /*LINTED E_FUNC_HAS_NO_RETURN_STMT*/ +} + +nscd_rc_t +_nscd_init_smf_monitor() { + + int errnum; + char *me = "_nscd_init_smf_monitor"; + + _NSCD_LOG(NSCD_LOG_SMF_MONITOR, NSCD_LOG_LEVEL_DEBUG) + (me, "initializing the smf monitor\n"); + + /* + * start a thread to check the state of the client services + */ + if (thr_create(NULL, NULL, set_smf_state, + NULL, THR_DETACHED, NULL) != 0) { + errnum = errno; + _NSCD_LOG(NSCD_LOG_SMF_MONITOR, NSCD_LOG_LEVEL_ERROR) + (me, "thr_create: %s\n", strerror(errnum)); + return (NSCD_THREAD_CREATE_ERROR); + } + + return (NSCD_SUCCESS); +} + +int +_nscd_get_smf_state(int srci, int dbi, int recheck) +{ + int s; + char *n; + + n = NSCD_NSW_SRC_NAME(srci); + + /* the files, compat, and dns backends are always available */ + if ((*n == 'f' || *n == 'c' || *n == 'd') && + (strcmp(NSCD_NSW_SRC_NAME(srci), "files") == 0 || + strcmp(NSCD_NSW_SRC_NAME(srci), "compat") == 0 || + strcmp(NSCD_NSW_SRC_NAME(srci), "dns") == 0)) { + return (SCF_STATE_ONLINE); + } + + /* + * for the printer database and user backend, treat the + * backend as a unsupported one, as nscd can not access + * the home directory of the user + */ + if (*n == 'u' && strcmp(NSCD_NSW_SRC_NAME(srci), "user") == 0) { + if (strcmp(NSCD_NSW_DB_NAME(dbi), NSS_DBNAM_PRINTERS) == 0) + return (NSCD_SVC_STATE_UNKNOWN_SRC); + else + return (SCF_STATE_ONLINE); + } + + /* + * unknown backend is not supported by nscd, + * tell the switch engine to return NSS_TRYLOCAL + * via rc NSCD_SVC_STATE_UNKNOWN_SRC + */ + if (srci >= _nscd_cfg_num_nsw_src) + return (NSCD_SVC_STATE_UNKNOWN_SRC); + + if (recheck == 1) + return (query_smf_state(srci)); + + (void) rw_rdlock(&nscd_smf_service_state_lock); + s = NSCD_SMF_SVC_STATE(srci); + (void) rw_unlock(&nscd_smf_service_state_lock); + + /* + * if the state has been queried at least once but is + * still not online, query one more time + */ + if (s != NSCD_SVC_STATE_UNINITED && s < SCF_STATE_ONLINE) + s = query_smf_state(srci); + + return (s); +} diff --git a/usr/src/cmd/nscd/nscd_switch.c b/usr/src/cmd/nscd/nscd_switch.c new file mode 100644 index 0000000000..351b6ad03e --- /dev/null +++ b/usr/src/cmd/nscd/nscd_switch.c @@ -0,0 +1,1546 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <stdlib.h> /* getenv() */ +#include <assert.h> +#include <unistd.h> +#include <string.h> +#include <dlfcn.h> +#include <nss_dbdefs.h> +#include <exec_attr.h> +#include <gssapi/gssapi.h> +#include "nscd_door.h" +#include "nscd_switch.h" +#include "nscd_log.h" +#include "nscd_frontend.h" + +#pragma weak nss_search = _nss_search +#define nss_search _nss_search + +extern rwlock_t nscd_smf_service_state_lock; + +/* nscd id: main, forker, or child */ +extern int _whoami; + +static int +retry_test(nss_status_t res, int n, struct __nsw_lookup_v1 *lkp) +{ + if (res != NSS_TRYAGAIN && res != NSS_NISSERVDNS_TRYAGAIN) { + if (res == NSS_SUCCESS) { + __NSW_UNPAUSE_ACTION(lkp->actions[__NSW_TRYAGAIN]); + __NSW_UNPAUSE_ACTION( + lkp->actions[__NSW_NISSERVDNS_TRYAGAIN]); + } + return (0); + } + + if ((res == NSS_TRYAGAIN && + lkp->actions[__NSW_TRYAGAIN] == __NSW_TRYAGAIN_FOREVER) || + (res == NSS_NISSERVDNS_TRYAGAIN && + lkp->actions[__NSW_NISSERVDNS_TRYAGAIN] == __NSW_TRYAGAIN_FOREVER)) + return (1); + + if (res == NSS_TRYAGAIN && + lkp->actions[__NSW_TRYAGAIN] == __NSW_TRYAGAIN_NTIMES) + if (n <= lkp->max_retries) + return (1); + else { + lkp->actions[__NSW_TRYAGAIN] = __NSW_TRYAGAIN_PAUSED; + return (0); + } + + if (res == NSS_NISSERVDNS_TRYAGAIN && + lkp->actions[__NSW_NISSERVDNS_TRYAGAIN] == __NSW_TRYAGAIN_NTIMES) + if (n <= lkp->max_retries) + return (1); + else { + lkp->actions[__NSW_NISSERVDNS_TRYAGAIN] = + __NSW_TRYAGAIN_PAUSED; + return (0); + } + + return (0); +} + +static thread_key_t loopback_key; +static mutex_t loopback_key_lock = DEFAULTMUTEX; +static int loopback_key_created = 0; +typedef struct lb_key { + int srci; + int dbi; + int fnum; + int *lb_flagp; +} lb_key_t; + +static int +set_loopback_key(lb_key_t *key) { + + int rc = 0; + lb_key_t *k; + + if (!loopback_key_created) { + (void) mutex_lock(&loopback_key_lock); + if (!loopback_key_created) { + if ((rc = thr_keycreate(&loopback_key, + NULL)) == 0) + loopback_key_created = 1; + } + (void) mutex_unlock(&loopback_key_lock); + } + if (rc == 0) { + /* set key if not already set */ + if (thr_getspecific(loopback_key, (void **)&k) == 0 && + k == NULL) { + rc = thr_setspecific(loopback_key, key); + } + } + + return (rc); +} + +static lb_key_t * +get_loopback_key(void) { + + char *me = "get_loopback_key"; + int rc = 0; + lb_key_t *k = NULL; + + if (!loopback_key_created) + return (NULL); + + rc = thr_getspecific(loopback_key, (void **)&k); + + _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG) + (me, "get loopback key rc= %d, key = %p\n", rc, k); + + if (rc == 0 && k != NULL) + return (k); + + return (NULL); +} + +static void +clear_loopback_key(lb_key_t *key) { + + char *me = "clear_loopback_key"; + + if (loopback_key_created && key != 0) { + /* + * key->lb_flagp points to the location of the + * flag, check_flag, in the stack where it was + * first set; clearing the flag tells that + * stack the loopback error has been resolved + */ + *key->lb_flagp = 0; + (void) thr_setspecific(loopback_key, NULL); + } + + _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG) + (me, "key %p cleared\n", key); +} + +static thread_key_t initf_key; +static mutex_t initf_key_lock = DEFAULTMUTEX; +static int initf_key_created = 0; + +static int +set_initf_key(void *pbuf) { + + int rc = 0; + + if (!initf_key_created) { + (void) mutex_lock(&initf_key_lock); + if (!initf_key_created) { + if ((rc = thr_keycreate(&initf_key, NULL)) == 0) + initf_key_created = 1; + } + (void) mutex_unlock(&initf_key_lock); + } + if (rc == 0) + rc = thr_setspecific(initf_key, pbuf); + + return (rc); +} + +static void * +get_initf_key(void) { + + char *me = "get_initf_key"; + void *pbuf; + int rc = 0; + + if (!initf_key_created) + return (NULL); + + rc = thr_getspecific(initf_key, (void **)&pbuf); + + _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG) + (me, "got initf pbuf rc= %d, key = %p\n", rc, pbuf); + + if (rc == 0 && pbuf != NULL) + return (pbuf); + + return (NULL); +} + +static void +clear_initf_key(void) { + + char *me = "clear_initf_key"; + + if (initf_key_created) + (void) thr_setspecific(initf_key, NULL); + + _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG) + (me, "initf pbuf cleared\n"); +} + +/* + * Call the input initf function to extract the + * NSS front end parameters and examine them to + * determine if an NSS lookup is to be performed + * on a regular or a pseudo (called from compat + * backend) database. Then set the necessary + * parameters for later data structures creation + * and processing. + */ +static nscd_rc_t +getparams( + int search_fnum, + nss_db_initf_t initf, + nscd_nsw_params_t *params) +{ + + nscd_rc_t rc = NSCD_SUCCESS; + nss_db_params_t *p; + int j; + char *dbn; + const char *n; + + p = ¶ms->p; + (void) memset(p, 0, sizeof (*p)); + (*initf)(p); + params->dbi = -1; + params->cfgdbi = -1; + params->compati = -1; + params->dnsi = -1; + + /* map database name to index */ + n = p->name; + for (j = 0; j < NSCD_NUM_DB; j++) { + dbn = NSCD_NSW_DB_NAME(j); + if (*n != *dbn) + continue; + if (strcmp(n, dbn) == 0) { + params->dbi = j; + if (*n != 'h' && *n != 'i' && *n != 's' && *n != 'a') + break; + if (strcmp(n, NSS_DBNAM_HOSTS) == 0 && + search_fnum == NSS_DBOP_HOSTS_BYNAME) + params->dnsi = 0; + else if (strcmp(n, NSS_DBNAM_IPNODES) == 0 && + search_fnum == NSS_DBOP_IPNODES_BYNAME) + params->dnsi = 1; + else if (strcmp(n, NSS_DBNAM_SHADOW) == 0) + params->privdb = 1; + else if (strcmp(n, NSS_DBNAM_AUDITUSER) == 0) + params->privdb = 1; + break; + } + } + + /* + * use the switch policy for passwd_compat or + * group_compat? + */ + if (p->config_name != NULL) { + + n = p->config_name; + for (j = 0; j < NSCD_NUM_DB; j++) { + dbn = NSCD_NSW_DB_NAME(j); + if (*n == *dbn) { + if (strcmp(n, dbn) == 0) { + params->cfgdbi = j; + break; + } + } + } + } + + /* map the database name to the pseudo database index */ + if (params->cfgdbi != -1) { + if (strstr(p->config_name, "_compat") != NULL) { + n = p->name; + for (j = params->cfgdbi; j < NSCD_NUM_DB; j++) { + dbn = NSCD_NSW_DB_NAME(j); + if (*n == *dbn) { + if (strcmp(n, dbn) == 0) { + params->compati = j; + break; + } + } + } + } + } + + assert(params->dbi != -1); + return (rc); +} + +static void +nscd_initf(nss_db_params_t *p) +{ + nss_pheader_t *pbuf; + nssuint_t off; + nss_dbd_t *pdbd; + char *me = "nscd_initf"; + + pbuf = (nss_pheader_t *)get_initf_key(); + if (pbuf == NULL) { + _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG) + (me, "ERROR: initf key not set\n"); + return; + } + + if (pbuf->dbd_len <= sizeof (nss_dbd_t)) { + _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG) + (me, "invalid db front params data ? dbd_len = %d\n", + pbuf->dbd_len); + return; + } + + off = pbuf->dbd_off; + pdbd = (nss_dbd_t *)((void *)((char *)pbuf + off)); + + p->name = (char *)pdbd + pdbd->o_name; + p->config_name = (char *)pdbd + pdbd->o_config_name; + p->default_config = (char *)pdbd + pdbd->o_default_config; + p->flags = (enum nss_dbp_flags)pdbd->flags; + (void) memcpy(&p->private, &pbuf->nscdpriv, sizeof (p->private)); + + _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG) + (me, "db frontend params: name =%s, config_name = %s, " + "default_config = %s, flags = %x\n", p->name, + (p->config_name && *p->config_name != '\0' ? + p->config_name : "<NOT SPECIFIED>"), + (p->default_config && *p->default_config != '\0' ? + p->default_config : "<NOT SPECIFIED>"), + p->flags); +} + + +static void +trace_result( + int dbi, + int srci, + int op, + nss_status_t res, + nss_XbyY_args_t *arg) +{ + char *res_str; + char *src = "?"; + char *db = "?"; + char *me = "nss_search"; + + switch (res) { + case NSS_SUCCESS: + res_str = "NSS_SUCCESS"; + break; + case NSS_NOTFOUND: + res_str = "NSS_NOTFOUND"; + break; + case NSS_UNAVAIL: + res_str = "NSS_UNAVAIL"; + break; + case NSS_TRYAGAIN: + res_str = "NSS_TRYAGAIN"; + break; + case NSS_NISSERVDNS_TRYAGAIN: + res_str = "NSS_NISSERVDNS_TRYAGAIN"; + break; + default: + res_str = "UNKNOWN STATUS"; + break; + } + + if (dbi != -1) + db = NSCD_NSW_DB_NAME(dbi); + if (srci != -1) + src = NSCD_NSW_SRC_NAME(srci); + + if (res == NSS_SUCCESS) { + _nscd_logit(me, +"%s: database: %s, operation: %d, source: %s returned \"%s\", length = %d\n", + res_str, db, op, src, arg->buf.buffer, arg->returnlen); + + return; + } + + _nscd_logit(me, +"%s: database: %s, operation: %d, source: %s, erange= %d, errno: %s \n", + res_str, db, op, src, arg->erange, strerror(arg->h_errno)); +} + +/* + * Determine if a request should be done locally in the getXbyY caller's + * process. Return none zero if yes, 0 otherwise. + * This function returnis 1 if: + * -- the database is exec_attr and the search_flag is GET_ALL + */ +static int +try_local( + int dbi, + void *arg) +{ + struct nss_XbyY_args *ap = (struct nss_XbyY_args *)arg; + _priv_execattr *ep; + int rc = 0; + char *me = "try_local"; + + if (strcmp(NSCD_NSW_DB_NAME(dbi), NSS_DBNAM_EXECATTR) == 0) { + if ((ep = ap->key.attrp) != NULL && + ep->search_flag == GET_ALL) + rc = 1; + } + + if (rc != 0) { + + _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG) + (me, "TRYLOCAL: exec_attr:GET_ALL\n"); + } + + return (rc); +} + +static nscd_rc_t +get_dns_funcs(int dnsi, void **func_p) +{ + char *me = "get_dns_funcs"; + static void *handle = NULL; + static mutex_t func_lock = DEFAULTMUTEX; + void *sym; + char *func_name[2] = { "_nss_get_dns_hosts_name", + "_nss_get_dns_ipnodes_name" }; + static void *func[2] = {NULL, NULL}; + + if (handle != NULL && dnsi > 0 && func[dnsi] != NULL) { + (void) memcpy(func_p, &func[dnsi], sizeof (void *)); + return (NSCD_SUCCESS); + } + + (void) mutex_lock(&func_lock); + + /* close the handle if requested */ + if (dnsi < 0) { + if (handle != NULL) { + (void) dlclose(handle); + func[0] = NULL; + func[1] = NULL; + } + (void) mutex_unlock(&func_lock); + return (NSCD_SUCCESS); + } + + if (handle != NULL && func[dnsi] != NULL) { + (void) memcpy(func_p, &func[dnsi], sizeof (void *)); + (void) mutex_unlock(&func_lock); + return (NSCD_SUCCESS); + } + + if (handle == NULL) { + handle = dlopen("nss_dns.so.1", RTLD_LAZY); + if (handle == NULL) { + _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, + NSCD_LOG_LEVEL_ERROR) + (me, "unable to dlopen nss_dns.so.1\n"); + (void) mutex_unlock(&func_lock); + return (NSCD_CFG_DLOPEN_ERROR); + } + } + + if ((sym = dlsym(handle, func_name[dnsi])) == NULL) { + + _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_ERROR) + (me, "unable to find symbol %s\n", func_name[dnsi]); + (void) mutex_unlock(&func_lock); + return (NSCD_CFG_DLSYM_ERROR); + } else { + (void) memcpy(func_p, &sym, sizeof (void *)); + (void) memcpy(&func[dnsi], &sym, sizeof (void *)); + } + + (void) mutex_unlock(&func_lock); + return (NSCD_SUCCESS); +} + +static nss_status_t +search_dns_withttl(nscd_sw_return_t *swret, char *srcname, int dnsi) +{ + nss_status_t (*func)(); + nss_status_t res = NSS_UNAVAIL; + nscd_rc_t rc; + + swret->noarg = 0; + if (strcmp(srcname, "dns") != 0) + return (NSS_ERROR); + + rc = get_dns_funcs(dnsi, (void **)&func); + if (rc == NSCD_SUCCESS) + res = (func)(NULL, &swret->pbuf, &swret->pbufsiz); + return (res); +} + +/* + * Returns a flag to indicate if needs to fall back to the + * main nscd when a per-user lookup failed with rc NSS_NOTFOUND. + */ +static int +set_fallback_flag(char *srcname, nss_status_t rc) +{ + char *me = "set_fallback_flag"; + if (strcmp(srcname, "ldap") == 0 && rc == NSS_NOTFOUND) { + + _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG) + (me, "NSS_NOTFOUND (ldap): fallback to main nscd " + "may be needed\n"); + return (1); + } + return (0); +} + +nss_status_t +nss_search(nss_db_root_t *rootp, nss_db_initf_t initf, int search_fnum, + void *search_args) +{ + char *me = "nss_search"; + nss_status_t res = NSS_UNAVAIL; + nscd_nsw_state_t *s = NULL; + int n_src; + unsigned int status_vec = 0; + int dbi, srci = -1; + int check_loopback = 0; + int state_thr = 0; + lb_key_t key, *k = NULL; + nss_db_root_t root_db; + nscd_nsw_params_t params; + nscd_sw_return_t *swret; + + _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG) + (me, "rootp = %p, initf = %p, search_fnum = %d, " + "search_args = %p\n", rootp, initf, + search_fnum, search_args); + + NSCD_SW_STATS_G.lookup_request_received_g++; + NSCD_SW_STATS_G.lookup_request_in_progress_g++; + NSCD_SW_STATS_G.lookup_request_queued_g++; + + /* determine db index, cfg db index, etc */ + (void) getparams(search_fnum, initf, ¶ms); + dbi = params.dbi; + + /* get address of the switch engine return data area */ + if (initf == nscd_initf) { + swret = (nscd_sw_return_t *)params.p.private; + swret->srci = -1; + } else { + swret = NULL; + params.dnsi = -1; + } + + /* + * for request that should be processed by the client, + * send it back with status NSS_TRYLOCAL + */ + if (try_local(dbi, search_args) == 1) { + res = NSS_TRYLOCAL; + goto error_exit; + } + + NSCD_SW_STATS(dbi).lookup_request_received++; + NSCD_SW_STATS(dbi).lookup_request_in_progress++; + NSCD_SW_STATS(dbi).lookup_request_queued++; + + /* if lookup not enabled, return NSS_UNAVAIL */ + if (!(NSCD_SW_CFG_G.enable_lookup_g == nscd_true && + NSCD_SW_CFG(dbi).enable_lookup == nscd_true)) { + + _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG) + (me, "lookup not enabled for %s\n", NSCD_NSW_DB_NAME(dbi)); + + goto error_exit; + } + + /* determine if loopback checking is configured */ + if (NSCD_SW_CFG_G.enable_loopback_checking_g == nscd_true && + NSCD_SW_CFG(dbi).enable_loopback_checking == nscd_true) { + check_loopback = 1; + + _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG) + (me, "loopback checking enabled for %s\n", + NSCD_NSW_DB_NAME(dbi)); + } + + if (check_loopback) { + k = get_loopback_key(); + if (k != NULL) { + if (k->dbi != dbi || k->fnum != search_fnum) { + clear_loopback_key(k); + k = NULL; + } + } + } + + if (s == 0) { + nscd_rc_t rc; + + if (check_loopback) { + rc = _nscd_get_nsw_state_thread(&root_db, ¶ms); + state_thr = 1; + } else + rc = _nscd_get_nsw_state(&root_db, ¶ms); + + NSCD_SW_STATS_G.lookup_request_queued_g--; + NSCD_SW_STATS(dbi).lookup_request_queued--; + + if (rc != NSCD_SUCCESS) + goto error_exit; + + s = (nscd_nsw_state_t *)root_db.s; + } + + _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG) + (me, "database = %s, config = [ %s ]\n", NSCD_NSW_DB_NAME(dbi), + (*s->nsw_cfg_p)->nsw_cfg_str); + + for (n_src = 0; n_src < s->max_src; n_src++) { + nss_backend_t *be; + nss_backend_op_t funcp; + struct __nsw_lookup_v1 *lkp; + int smf_state; + int n_loop = 0; + int max_retry = 10; + + res = NSS_UNAVAIL; + + if (n_src == 0) + lkp = s->config->lookups; + else + lkp = lkp->next; + + /* set the number of max. retries */ + if (lkp->actions[__NSW_TRYAGAIN] == __NSW_TRYAGAIN_NTIMES) + max_retry = lkp->max_retries; + + srci = (*s->nsw_cfg_p)->src_idx[n_src]; + if (swret != NULL) + swret->srci = srci; + + _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_get_client_euid() != 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 */ + smf_state = _nscd_get_smf_state(srci, dbi, 0); + + /* stop if the source is one that should be TRYLOCAL */ + if (smf_state == NSCD_SVC_STATE_UNKNOWN_SRC) { + _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, + NSCD_LOG_LEVEL_DEBUG) + (me, "returning TRYLOCAL ... \n"); + res = NSS_TRYLOCAL; + goto free_nsw_state; + } + + if (check_loopback && k != NULL) { + + if (k->srci == srci && k->dbi == dbi) + if (k->fnum == search_fnum) { + + _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, + NSCD_LOG_LEVEL_DEBUG) + (me, "loopback detected: " + "source = %s, database = %s " + "search fnum = %d\n", + NSCD_NSW_SRC_NAME(srci), + NSCD_NSW_DB_NAME(dbi), search_fnum); + + NSCD_SW_STATS_G.loopback_nsw_db_skipped_g++; + NSCD_SW_STATS(dbi).loopback_nsw_db_skipped++; + continue; + } + } + + be = s->be[n_src]; + if (be != NULL) + funcp = NSS_LOOKUP_DBOP(be, search_fnum); + + if ((params.dnsi >= 0 && be == 0) || (params.dnsi < 0 && + (be == 0 || (smf_state != NSCD_SVC_STATE_UNINITED && + smf_state < SCF_STATE_ONLINE) || funcp == 0))) { + + _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, + NSCD_LOG_LEVEL_DEBUG) + (me, "unable to look up source %s: be = %p, " + "smf state = %d, funcp = %p\n", + NSCD_NSW_SRC_NAME(srci), be, smf_state, funcp); + + goto next_src; + } + + do { + /* + * we can only retry max_retry times, + * otherwise threads may get stuck in this + * do-while loop forever + */ + if (n_loop > max_retry) { + if (swret != NULL) + res = NSS_TRYLOCAL; + goto free_nsw_state; + } + + /* + * set up to prevent loopback + */ + if (check_loopback && k == NULL) { + key.srci = srci; + key.dbi = dbi; + key.fnum = search_fnum; + key.lb_flagp = &check_loopback; + (void) set_loopback_key(&key); + k = &key; + } + + _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, + NSCD_LOG_LEVEL_DEBUG) + (me, "looking up source = %s, loop# = %d \n", + NSCD_NSW_SRC_NAME(srci), n_loop); + + /* + * search the backend, if hosts lookups, + * try to get the hosts data with ttl first + */ + if (params.dnsi >= 0) { + res = search_dns_withttl(swret, + NSCD_NSW_SRC_NAME(srci), + params.dnsi); + /* + * if not able to get ttl, fall back + * to the regular backend call + */ + if (res == NSS_ERROR) + res = (*funcp)(be, search_args); + else { + /* + * status/result are in the + * packed buffer, not + * search_args + */ + swret->noarg = 1; + } + } else + res = (*funcp)(be, search_args); + if (swret != NULL) + swret->errnum = errno; + + /* + * backend is not up, check and update the + * smf state table + */ + if (res == NSS_UNAVAIL) + (void) _nscd_get_smf_state(srci, dbi, 1); + + /* + * may need to fall back to use the main nscd + * if per-user lookup + */ + if (_whoami == NSCD_CHILD && swret != NULL) + swret->fallback = set_fallback_flag( + NSCD_NSW_SRC_NAME(srci), res); + + _NSCD_LOG_IF(NSCD_LOG_SWITCH_ENGINE, + NSCD_LOG_LEVEL_DEBUG) { + + /* + * set up to trace the result/status + * of the dns/ttl lookup + */ + if (swret != NULL && swret->noarg == 1) { + nss_pheader_t *phdr; + struct nss_XbyY_args *arg; + arg = (struct nss_XbyY_args *) + search_args; + phdr = (nss_pheader_t *)swret->pbuf; + arg->buf.buffer = (char *)phdr + + phdr->data_off; + arg->returnlen = phdr->data_len; + if (phdr->p_errno == ERANGE) + arg->erange = 1; + arg->h_errno = phdr->p_herrno; + } + + trace_result(dbi, srci, search_fnum, res, + (nss_XbyY_args_t *)search_args); + } + + n_loop++; + } while (retry_test(res, n_loop, lkp)); + + next_src: + + status_vec |= (1 << res); + + if (__NSW_ACTION_V1(lkp, res) == __NSW_RETURN) { + break; + } + } + + free_nsw_state: + + if (state_thr == 1) + _nscd_put_nsw_state_thread(s); + else + _nscd_put_nsw_state(s); + if (check_loopback && k != NULL) + clear_loopback_key(k); + + if (res != NSS_SUCCESS) + goto error_exit; + + NSCD_SW_STATS_G.lookup_request_succeeded_g++; + NSCD_SW_STATS(dbi).lookup_request_succeeded++; + NSCD_SW_STATS_G.lookup_request_in_progress_g--; + NSCD_SW_STATS(dbi).lookup_request_in_progress--; + + return (NSS_SUCCESS); + + error_exit: + + NSCD_SW_STATS_G.lookup_request_failed_g++; + NSCD_SW_STATS_G.lookup_request_in_progress_g--; + NSCD_SW_STATS(dbi).lookup_request_failed++; + NSCD_SW_STATS(dbi).lookup_request_in_progress--; + + return (res); +} + + +/* ===> get/set/endent */ + +static void nss_setent_u(nss_db_root_t *, + nss_db_initf_t, + nss_getent_t *); +static nss_status_t nss_getent_u(nss_db_root_t *, + nss_db_initf_t, + nss_getent_t *, + void *); +static void nss_endent_u(nss_db_root_t *, + nss_db_initf_t, + nss_getent_t *); + +void +nss_setent(nss_db_root_t *rootp, nss_db_initf_t initf, + nss_getent_t *contextpp) +{ + if (contextpp == 0) + return; + nss_setent_u(rootp, initf, contextpp); +} + +nss_status_t +nss_getent(nss_db_root_t *rootp, nss_db_initf_t initf, nss_getent_t *contextpp, + void *args) +{ + nss_status_t status; + + if (contextpp == 0) { + return (NSS_UNAVAIL); + } + status = nss_getent_u(rootp, initf, contextpp, args); + return (status); +} + +void +nss_endent(nss_db_root_t *rootp, nss_db_initf_t initf, + nss_getent_t *contextpp) +{ + if (contextpp == 0) + return; + nss_endent_u(rootp, initf, contextpp); +} + +/*ARGSUSED*/ +static void +end_iter_u(nss_db_root_t *rootp, struct nss_getent_context *contextp) +{ + nscd_getent_context_t *ctx; + nscd_nsw_state_t *s; + nss_backend_t *be; + int n_src; + + ctx = (nscd_getent_context_t *)contextp; + s = ctx->nsw_state; + n_src = ctx->n_src; + be = ctx->be; + + if (s != 0) { + if (n_src < s->max_src && be != 0) { + (void) NSS_INVOKE_DBOP(be, NSS_DBOP_ENDENT, 0); + ctx->be = 0; /* Should be unnecessary, but hey */ + } + } + ctx->n_src = 0; +} + +static void +nss_setent_u(nss_db_root_t *rootp, nss_db_initf_t initf, + nss_getent_t *contextpp) +{ + char *me = "nss_setent_u"; + nscd_nsw_state_t *s; + nscd_getent_context_t *contextp; + nscd_nsw_params_t params; + nss_db_root_t root; + nss_backend_t *be; + int n_src, i; + nscd_sw_return_t *swret = NULL; + + _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG) + (me, "rootp = %p, initf = %p, contextpp = %p \n", + rootp, initf, contextpp); + + /* get the nsw db index via the initf function */ + (void) getparams(-1, initf, ¶ms); + + /* get address of the switch engine return data area */ + if (initf == nscd_initf) + swret = (nscd_sw_return_t *)params.p.private; + + /* if no privilege to look up, return */ + if (params.privdb == 1 && swret != NULL && + ((nss_pheader_t *)(swret->pbuf))->p_euid != 0) { + + _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG) + (me, "no privilege \n"); + return; + } + + if ((contextp = (nscd_getent_context_t *)contextpp->ctx) == 0) { + if ((_nscd_get_getent_ctx(contextpp, ¶ms)) != + NSCD_SUCCESS) { + return; + } + contextp = (nscd_getent_context_t *)contextpp->ctx; + } + s = contextp->nsw_state; + + if (s == 0) { + if (_nscd_get_nsw_state(&root, ¶ms) != + NSCD_SUCCESS) { + return; + } + s = (nscd_nsw_state_t *)root.s; + contextp->nsw_state = s; + + } else { + s = contextp->nsw_state; + n_src = contextp->n_src; + be = contextp->be; + if (n_src == 0 && be != 0) { + /* + * Optimization: don't do endent, don't change + * backends, just do the setent. Look Ma, no locks + * (nor any context that needs updating). + */ + (void) NSS_INVOKE_DBOP(be, NSS_DBOP_SETENT, 0); + return; + } + if (n_src < s->max_src && be != 0) { + (void) NSS_INVOKE_DBOP(be, NSS_DBOP_ENDENT, 0); + contextp->be = 0; /* Play it safe */ + } + } + for (n_src = 0, be = 0; n_src < s->max_src && + (be = s->be[n_src]) == 0; n_src++) { + ; + } + + contextp->n_src = n_src; + contextp->be = be; + + if (be == 0) { + /* Things are broken enough that we can't do setent/getent */ + nss_endent_u(rootp, initf, contextpp); + return; + } + + /* + * make sure all the backends are supported + */ + for (i = 0; i < s->max_src; i++) { + int st, srci; + + srci = (*s->nsw_cfg_p)->src_idx[i]; + st = _nscd_get_smf_state(srci, params.dbi, 1); + if (st == NSCD_SVC_STATE_UNKNOWN_SRC || + st == NSCD_SVC_STATE_UNINITED) { + nss_endent_u(rootp, initf, contextpp); + + _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, + NSCD_LOG_LEVEL_DEBUG) + (me, "backend (%s) not available (state = %d)\n", + NSCD_NSW_SRC_NAME(srci), st); + + return; + } + } + + (void) NSS_INVOKE_DBOP(be, NSS_DBOP_SETENT, 0); +} + +nss_status_t +nss_getent_u(nss_db_root_t *rootp, nss_db_initf_t initf, + nss_getent_t *contextpp, void *args) +{ + char *me = "nss_getent_u"; + nscd_nsw_state_t *s; + nscd_getent_context_t *contextp; + int n_src; + nss_backend_t *be; + + _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG) + (me, "rootp = %p, initf = %p, contextpp = %p, args = %p\n", + rootp, initf, contextpp, args); + + if ((contextp = (nscd_getent_context_t *)contextpp->ctx) == 0) { + nss_setent_u(rootp, initf, contextpp); + if ((contextp = (nscd_getent_context_t *)contextpp->ctx) == 0) { + /* Give up */ + _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, + NSCD_LOG_LEVEL_ERROR) + (me, "not able to obtain getent context ... give up\n"); + + return (NSS_UNAVAIL); + } + } + + s = contextp->nsw_state; + n_src = contextp->n_src; + be = contextp->be; + + if (s == 0) { + /* + * We've done an end_iter() and haven't done nss_setent() + * or nss_endent() since; we should stick in this state + * until the caller invokes one of those two routines. + */ + return (NSS_SUCCESS); + } + + while (n_src < s->max_src) { + nss_status_t res; + struct __nsw_lookup_v1 *lkp = NULL; + int n; + + /* get the nsw config for the current source */ + lkp = s->config->lookups; + for (n = 0; n < n_src; n++) + lkp = lkp->next; + + if (be == 0) { + /* If it's null it's a bug, but let's play safe */ + res = NSS_UNAVAIL; + } else { + _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, + NSCD_LOG_LEVEL_DEBUG) + (me, "database: %s, backend: %s, nsswitch config: %s\n", + NSCD_NSW_DB_NAME(s->dbi), + lkp->service_name, + (*s->nsw_cfg_p)->nsw_cfg_str); + + res = NSS_INVOKE_DBOP(be, NSS_DBOP_GETENT, args); + } + + if (__NSW_ACTION_V1(lkp, res) == __NSW_RETURN) { + if (res != __NSW_SUCCESS) { + end_iter_u(rootp, + (struct nss_getent_context *)contextp); + } + return (res); + } + (void) NSS_INVOKE_DBOP(be, NSS_DBOP_ENDENT, 0); + do { + n_src++; + } while (n_src < s->max_src && + (be = s->be[n_src]) == 0); + if (be == 0) { + /* + * This is the case where we failed to get the backend + * for the last source. We exhausted all sources. + */ + nss_endent_u(rootp, initf, contextpp); + return (NSS_SUCCESS); + } + contextp->n_src = n_src; + contextp->be = be; + (void) NSS_INVOKE_DBOP(be, NSS_DBOP_SETENT, 0); + } + /* Got to the end of the sources without finding another entry */ + end_iter_u(rootp, (struct nss_getent_context *)contextp); + return (NSS_SUCCESS); + /* success is either a successful entry or end of the sources */ +} + +/*ARGSUSED*/ +void +nss_endent_u(nss_db_root_t *rootp, nss_db_initf_t initf, + nss_getent_t *contextpp) +{ + char *me = "nss_endent_u"; + nscd_getent_context_t *contextp; + + _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG) + (me, "rootp = %p, initf = %p, contextpp = %p \n", + rootp, initf, contextpp); + + if ((contextp = (nscd_getent_context_t *)contextpp->ctx) == 0) { + /* nss_endent() on an unused context is a no-op */ + return; + } + end_iter_u(rootp, (struct nss_getent_context *)contextp); + _nscd_put_getent_ctx(contextp); + contextpp->ctx = NULL; +} + +/* + * _nss_db_state_destr() and nss_delete() do nothing in nscd + * but is needed to make the caller (below nscd) happy + */ +/*ARGSUSED*/ +void +_nss_db_state_destr(struct nss_db_state *s) +{ + /* nsw state in nscd is always reused, so do nothing here */ +} + +/*ARGSUSED*/ +void +nss_delete(nss_db_root_t *rootp) +{ + /* + * the only resource kept tracked by the nss_db_root_t + * is the nsw state which is always reused and no need + * to be freed. So just return. + */ +} + +/* + * Start of nss_psearch/nss_psetent()/nss_pgetent()/nss_pendent() + * buffers switch entry points + */ + +/* + * nss_psearch opens a packed structure header, assembles a local + * nss_XbyY_args_t structure and calls the local copy of nss_search. + * The return data is assembled in "files native format" in the + * return buffer location. Status if packed back up with the buffer + * and the whole wad is returned to the cache or the client. + */ + +void +nss_psearch(void *buffer, size_t length) +{ + /* inputs */ + nss_db_initf_t initf; + int dbop; + int rc; + nss_XbyY_args_t arg; + nss_status_t status; + nscd_sw_return_t swret = { 0 }, *swrp = &swret; + nss_pheader_t *pbuf = (nss_pheader_t *)buffer; + char *me = "nss_psearch"; + + if (buffer == NULL || length == 0) { + NSCD_RETURN_STATUS(pbuf, NSS_ERROR, EFAULT); + } + + status = nss_packed_arg_init(buffer, length, + NULL, &initf, &dbop, &arg); + if (status != NSS_SUCCESS) { + NSCD_RETURN_STATUS(pbuf, status, -1); + } + + /* + * pass the address of the return data area + * for the switch engine to return its own data + */ + (void) memcpy(&pbuf->nscdpriv, &swrp, sizeof (swrp)); + swret.pbuf = buffer; + swret.pbufsiz = length; + + /* + * use the generic nscd_initf for all database lookups + * (the TSD key is the pointer to the packed header) + */ + rc = set_initf_key(pbuf); + if (rc != 0) { + NSCD_RETURN_STATUS(pbuf, NSS_UNAVAIL, EINVAL); + } + initf = nscd_initf; + + /* Perform local search and pack results into return buffer */ + /* nscd's search ignores db_root */ + status = nss_search(NULL, initf, dbop, &arg); + + /* + * If status is NSS_NOTFOUND and ldap also returned + * NSS_NOTFOUND, it is possible that the user does + * not have a credential, so check and see if + * needs to return NSS_ALTRETRY to let the main + * nscd get a chance to process the lookup + */ + if (swret.fallback == 1 && status == NSS_NOTFOUND) { + OM_uint32 stat; + + if (gss_inquire_cred(&stat, GSS_C_NO_CREDENTIAL, + NULL, NULL, NULL, NULL) != GSS_S_COMPLETE) { + + _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, + NSCD_LOG_LEVEL_DEBUG) + (me, "NSS_ALTRETRY: fallback to main nscd needed\n"); + + status = NSS_ALTRETRY; + } + } + + NSCD_SET_STATUS(pbuf, status, -1); + errno = swret.errnum; + + /* + * move result/status from args to packed buffer only if + * arg was being used + */ + if (!swret.noarg) + nss_packed_set_status(buffer, length, status, &arg); + + _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG) + (me, "switch engine result: source is %s, status %d, " + "herrno is %d, errno is %s\n", + (swret.srci != -1) ? NSCD_NSW_SRC_NAME(swret.srci) : "<NOTSET>", + pbuf->p_status, pbuf->p_herrno, strerror(pbuf->p_errno)); + + /* clear the TSD key used by the generic initf */ + clear_initf_key(); + pbuf->nscdpriv = 0; +} + +static void +nscd_map_contextp(void *buffer, nss_getent_t *contextp, + nssuint_t **cookie_p, nssuint_t **seqnum_p, int setent) +{ + nss_pheader_t *pbuf = (nss_pheader_t *)buffer; + nssuint_t off; + nscd_getent_context_t *ctx; + char *me = "nscd_map_contextp"; + + struct cookie_seqnum { + nssuint_t cookie; + nssuint_t seqnum; + } *csp; + + if (buffer == NULL) { + NSCD_RETURN_STATUS(pbuf, NSS_ERROR, EFAULT); + } + + off = pbuf->key_off; + csp = (struct cookie_seqnum *)((void *)((char *)buffer + off)); + if (seqnum_p != NULL) + *seqnum_p = &csp->seqnum; + + /* + * if called by nss_psetent, and the passed in cookie is + * NSCD_NEW_COOKIE, then there is no cookie yet, return + * a pointer pointing to where the cookie will be stored. + * Also because there is no cookie to validate, just + * return success. + * + * On the other hand, if a cookie is passed in, we need + * to validate the cookie before returning. + */ + if (cookie_p != NULL) + *cookie_p = &csp->cookie; + if (setent == 1 && csp->cookie == NSCD_NEW_COOKIE) { + NSCD_RETURN_STATUS_SUCCESS(pbuf); + } + + _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG) + (me, "cookie = %lld, sequence number = %lld\n", + csp->cookie, csp->seqnum); + + ctx = _nscd_is_getent_ctx(csp->cookie); + + if (ctx == NULL) { + _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG) + (me, "invalid cookie (%lld)\n", csp->cookie); + + NSCD_RETURN_STATUS(pbuf, NSS_ERROR, EFAULT); + } + + if (setent == 1) { + /* if called by nss_psetent, reset the seq number */ + ctx->seq_num = 1; + } else if (ctx->seq_num != (nscd_seq_num_t)csp->seqnum) { + _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG) + (me, "invalid sequence number (%lld)\n", csp->seqnum); + + NSCD_RETURN_STATUS(pbuf, NSS_ERROR, EFAULT); + } + + contextp->ctx = (struct nss_getent_context *)ctx; + + NSCD_RETURN_STATUS_SUCCESS(pbuf); +} + +void +nss_psetent(void *buffer, size_t length, pid_t pid) +{ + /* inputs */ + nss_db_initf_t initf; + nss_getent_t context = { 0 }; + nss_getent_t *contextp = &context; + nss_status_t status; + nssuint_t *cookiep; + nssuint_t *seqnump; + nscd_getent_context_t *ctx; + int rc; + nss_pheader_t *pbuf = (nss_pheader_t *)buffer; + nscd_sw_return_t swret = { 0 }, *swrp = &swret; + char *me = "nss_psetent"; + + if (buffer == NULL || length == 0) { + NSCD_RETURN_STATUS(pbuf, NSS_ERROR, EFAULT); + } + + /* + * If this is a per-user nscd, and the user does not have + * the necessary credential, return NSS_TRYLOCAL, so the + * setent/getent can be done locally in the process of the + * setent call + */ + if (_whoami == NSCD_CHILD) { + OM_uint32 stat; + + if (gss_inquire_cred(&stat, GSS_C_NO_CREDENTIAL, + NULL, NULL, NULL, NULL) != GSS_S_COMPLETE) { + + _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, + NSCD_LOG_LEVEL_DEBUG) + (me, "NSS_TRYLOCAL: fallback to caller process\n"); + NSCD_RETURN_STATUS(pbuf, NSS_TRYLOCAL, 0); + } + } + + status = nss_packed_context_init(buffer, length, + NULL, &initf, &contextp, (nss_XbyY_args_t *)NULL); + if (status != NSS_SUCCESS) { + NSCD_RETURN_STATUS(pbuf, status, -1); + } + + /* + * use the generic nscd_initf for all the setent requests + * (the TSD key is the pointer to the packed header) + */ + rc = set_initf_key(pbuf); + if (rc != 0) { + NSCD_RETURN_STATUS(pbuf, NSS_UNAVAIL, EINVAL); + } + initf = nscd_initf; + + /* get address of cookie and seqnum for later updates */ + nscd_map_contextp(buffer, contextp, &cookiep, &seqnump, 1); + if (NSCD_STATUS_IS_NOT_OK(pbuf)) + return; + /* + * pass the packed header buffer pointer to nss_setent + */ + (void) memcpy(&pbuf->nscdpriv, &swrp, sizeof (swrp)); + swret.pbuf = buffer; + + /* Perform local setent and set context */ + nss_setent(NULL, initf, contextp); + + /* insert cookie info into buffer and return */ + ctx = (nscd_getent_context_t *)contextp->ctx; + if (ctx != NULL) { + *cookiep = ctx->cookie; + *seqnump = (nssuint_t)ctx->seq_num; + ctx->pid = pid; + } else { + /* + * not able to allocate a getent context, the + * client should try the enumeration locally + */ + *cookiep = NSCD_LOCAL_COOKIE; + *seqnump = 0; + } + + _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG) + (me, "cookie = %lld, sequence number = %lld\n", + *cookiep, *seqnump); + + if (ctx != NULL) { + _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG) + (me, "cookie = %lld, sequence number = %lld\n", + ctx->cookie, ctx->seq_num); + } + + /* clear the TSD key used by the generic initf */ + clear_initf_key(); + + if (*cookiep == NSCD_LOCAL_COOKIE) { + NSCD_RETURN_STATUS(pbuf, NSS_TRYLOCAL, 0); + } else { + NSCD_RETURN_STATUS(pbuf, NSS_SUCCESS, 0); + } +} + +void +nss_pgetent(void *buffer, size_t length) +{ + /* inputs */ + nss_db_initf_t initf; + nss_getent_t context; + nss_getent_t *contextp = &context; + nss_XbyY_args_t arg; + nss_status_t status; + nssuint_t *cookiep; + nssuint_t *seqnump; + nscd_getent_context_t *ctx; + int rc; + nss_pheader_t *pbuf = (nss_pheader_t *)buffer; + char *me = "nss_pgetent"; + + if (buffer == NULL || length == 0) { + NSCD_RETURN_STATUS(pbuf, NSS_ERROR, EFAULT); + } + + status = nss_packed_context_init(buffer, length, + NULL, &initf, &contextp, &arg); + if (status != NSS_SUCCESS) { + NSCD_RETURN_STATUS(pbuf, status, -1); + } + + /* + * use the generic nscd_initf for all the getent requests + * (the TSD key is the pointer to the packed header) + */ + rc = set_initf_key(pbuf); + if (rc != 0) { + NSCD_RETURN_STATUS(pbuf, NSS_UNAVAIL, EINVAL); + } + initf = nscd_initf; + + + /* verify the cookie passed in */ + nscd_map_contextp(buffer, contextp, &cookiep, &seqnump, 0); + if (NSCD_STATUS_IS_NOT_OK(pbuf)) + return; + + /* Perform local search and pack results into return buffer */ + status = nss_getent(NULL, initf, contextp, &arg); + NSCD_SET_STATUS(pbuf, status, -1); + nss_packed_set_status(buffer, length, status, &arg); + + /* increment sequence number in the buffer and nscd context */ + if (status == NSS_SUCCESS) { + ctx = (nscd_getent_context_t *)contextp->ctx; + ctx->seq_num++; + *seqnump = ctx->seq_num; + *cookiep = ctx->cookie; + + _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG) + (me, "getent OK, new sequence number = %lld, len = %lld," + " data = [ %s ]\n", *seqnump, + pbuf->data_len, (char *)buffer + pbuf->data_off); + } else { + ctx = (nscd_getent_context_t *)contextp->ctx; + _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG) + (me, "getent failed, status = %d, sequence number = %lld\n", + status, *seqnump); + } + + /* clear the TSD key used by the generic initf */ + clear_initf_key(); +} + +void +nss_pendent(void *buffer, size_t length) +{ + nss_getent_t context; + nss_getent_t *contextp = &context; + nssuint_t *seqnump; + nssuint_t *cookiep; + nss_pheader_t *pbuf = (nss_pheader_t *)buffer; + char *me = "nss_pendent"; + + if (buffer == NULL || length == 0) { + NSCD_RETURN_STATUS(pbuf, NSS_ERROR, EFAULT); + } + + /* map the contextp from the cookie information */ + nscd_map_contextp(buffer, contextp, &cookiep, &seqnump, 0); + if (NSCD_STATUS_IS_NOT_OK(pbuf)) + return; + + _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE, NSCD_LOG_LEVEL_DEBUG) + (me, "endent, cookie = %lld, sequence number = %lld\n", + *cookiep, *seqnump); + + /* Perform local endent and reset context */ + nss_endent(NULL, NULL, contextp); + NSCD_RETURN_STATUS(pbuf, NSS_SUCCESS, 0); +} + +/*ARGSUSED*/ +void +nss_pdelete(void *buffer, size_t length) +{ + nss_pheader_t *pbuf = (nss_pheader_t *)buffer; + + /* unnecessary, kept for completeness */ + NSCD_RETURN_STATUS_SUCCESS(pbuf); +} diff --git a/usr/src/cmd/nscd/nscd_switch.h b/usr/src/cmd/nscd/nscd_switch.h new file mode 100644 index 0000000000..0522fb3851 --- /dev/null +++ b/usr/src/cmd/nscd/nscd_switch.h @@ -0,0 +1,399 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _NSCD_SWITCH_H +#define _NSCD_SWITCH_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + +#include <nss_dbdefs.h> +#include <thread.h> +#include <libscf.h> +#define __NSS_PRIVATE_INTERFACE +#include "nsswitch_priv.h" +#undef __NSS_PRIVATE_INTERFACE +#include "nscd_db.h" +#include "nscd_config.h" + +/* + * max. length of e.g. "passwd: files ldap" + */ +#define MAX_NSSWITCH_CONFIG_STRING_SZ 256 + +/* + * max. length of the name of a NSS database + */ +#define MAX_NSSWITCH_CONFIG_DB_NAME_SZ 256 + +/* + * nscd_nsw_config_t is an abstraction of the configuration + * for a NSS database + */ +typedef struct { + char *db_name; + char *nsw_cfg_str; + nss_db_params_t fe_params; + struct __nsw_switchconfig_v1 *nsw_config; + int max_src; + int *src_idx; /* ptr to array of */ + /* src index */ + int nobase; /* not shared */ +} nscd_nsw_config_t; + +/* + * nscd_be_info_t is an abstraction of a NSS backend + */ +typedef struct { + nss_backend_constr_t be_constr; + nss_backend_finder_t *finder; + void *finder_priv; +} nscd_be_info_t; + +/* + * nscd_state_ctrl_t is used to control a nscd_nsw_state pool + */ +typedef struct { + int max; + int allocated; + int free; + int waiter; + struct nscd_nsw_state *first; +} nscd_state_ctrl_t; + +/* + * nscd_nsw_state_base_t represents the nscd_nsw_state pool + * for a NSS database + */ +typedef struct nscd_nsw_state_base { + int dbi; /* which database? */ + nscd_state_ctrl_t nsw_state; + nscd_state_ctrl_t nsw_state_thr; + int used_by_thr; + thread_t tid; + cond_t thr_cond; +} nscd_nsw_state_base_t; + +/* + * nscd_nsw_state_t is an abstraction of all the data needed + * to do lookup of NSS database (e.g. "passwd" or "hosts") + */ +typedef struct nscd_nsw_state { + int dbi; /* which database? */ + int max_src; /* is == config->num_lookups */ + int getent; /* used by getent */ + nss_db_params_t p; + struct __nsw_switchconfig_v1 *config; + nscd_nsw_config_t **nsw_cfg_p; + nscd_nsw_state_base_t *base; + nss_backend_t **be; /* array of backends */ + nscd_db_t ***be_db_pp; + struct nscd_nsw_state *next; +} nscd_nsw_state_t; + +/* + * nscd_getent_ctx_base_t represents the nscd_getent_ctx_base_t pool + * for a NSS database + */ +typedef struct nscd_getent_ctx_base { + int dbi; /* which database? */ + int deattached; /* not associated with */ + /* current config */ + int max_getent_ctx; + int num_getent_ctx; + int num_waiter; + struct nscd_getent_context *first; +} nscd_getent_ctx_base_t; + +/* + * nscd_getent_context_t is an abstraction of all the data needed + * to enumerate a NSS database (e.g. "passwd" or "hosts") + */ +typedef struct nscd_getent_context { + int dbi; + nscd_seq_num_t seq_num; + nscd_cookie_t cookie; + pid_t pid; /* door client's pid */ + int n_src; /* >=max_src: end of sequence */ + nscd_nsw_state_t *nsw_state; + nss_backend_t *be; + nscd_getent_ctx_base_t *base; + struct nscd_getent_context *next; +} nscd_getent_context_t; + +/* + * nscd_smf_state_t is used to keep track of the state of the smf + * service associated with a NSS source (e.g. "passwd" or "hosts") + */ +typedef struct { + char *src_name; + int src_state; +} nscd_smf_state_t; + +/* + * nscd_smf_state_t is used to keep track of the state of the smf + * service associated with a NSS source (e.g. "passwd" or "hosts") + */ +typedef struct { + int dbi; /* database index */ + /* + * index of the database of which the switch policy + * should be used + */ + int cfgdbi; + /* + * index of the pseudo database that the NSS backend + * does search on + */ + int compati; + /* + * ptr to ptr to the siwtch config structure + */ + nscd_nsw_config_t **nswcfg; + /* + * frontend params passed to nss_search or nss_*ent + */ + struct nss_db_params p; + /* + * set to 1 if database is "hosts", else 2 if "ipnodes" + */ + int8_t dnsi; + /* + * set to 1 if require privilege to look up the database + */ + uint8_t privdb; +} nscd_nsw_params_t; + +/* + * additional info returned by the switch engine + */ +typedef struct { + void *pbuf; /* ptr to packed buffer */ + size_t pbufsiz; /* length of the packed buffer */ + int srci; /* last source searched */ + int errnum; /* errno from the backend */ + int noarg; /* if set, backend does not use the arg structure */ + int fallback; /* if set, may need to fall back to main nscd */ +} nscd_sw_return_t; + +/* + * static tables or global data defined in other files + */ +extern int _nscd_cfg_num_nsw_src; +extern int _nscd_cfg_num_nsw_src_all; +extern int _nscd_cfg_num_nsw_db; +extern int _nscd_cfg_num_nsw_db_all; +extern int _nscd_cfg_num_smf_services; +extern nscd_cfg_id_t _nscd_cfg_nsw_src[]; +extern nscd_cfg_id_t *_nscd_cfg_nsw_src_all; +extern nscd_cfg_id_t _nscd_cfg_nsw_db[]; +extern nss_db_initf_t nscd_nss_db_initf[]; +extern nscd_cfg_id_t _nscd_cfg_smf_services[]; +extern nscd_smf_state_t *nscd_smf_service_state; +extern nscd_db_t ***nscd_src_backend_db; +extern nscd_nsw_config_t ***nscd_nsw_config; +extern nscd_nsw_state_base_t **nscd_nsw_state_base; +extern nscd_getent_ctx_base_t **nscd_getent_ctx_base; +extern nscd_cfg_global_switch_t nscd_switch_cfg_g; +extern nscd_cfg_switch_t *nscd_switch_cfg; +extern nscd_cfg_stat_global_switch_t nscd_switch_stats_g; +extern nscd_cfg_stat_switch_t *nscd_switch_stats; + +#define NSCD_NUM_SRC _nscd_cfg_num_nsw_src_all +#define NSCD_NUM_DB _nscd_cfg_num_nsw_db_all +#define NSCD_NUM_SMF_FMRI _nscd_cfg_num_smf_services +#define NSCD_NSW_SRC_NAME(i) (_nscd_cfg_nsw_src_all + i)->name +#define NSCD_NSW_DB_NAME(i) _nscd_cfg_nsw_db[i].name +#define NSCD_SMF_SVC_FMRI(i) _nscd_cfg_smf_services[i].name +#define NSCD_SMF_SVC_INDEX(i) _nscd_cfg_smf_services[i].index +#define NSCD_SMF_SVC_STATE(i) nscd_smf_service_state[i].src_state +#define NSCD_SW_CFG_G nscd_switch_cfg_g +#define NSCD_SW_CFG(i) nscd_switch_cfg[i] +#define NSCD_SW_STATS_G nscd_switch_stats_g +#define NSCD_SW_STATS(i) nscd_switch_stats[i] + +/* + * special service states used by the switch engine + */ +#define NSCD_SVC_STATE_UNINITED -1 +#define NSCD_SVC_STATE_UNKNOWN_SRC -2 + +/* + * prototypes + */ + +void +_nscd_put_nsw_state( + nscd_nsw_state_t *s); + +void +_nscd_put_nsw_state_thread( + nscd_nsw_state_t *s); + +nscd_rc_t +_nscd_get_nsw_state( + nss_db_root_t *rootp, + nscd_nsw_params_t *params); + +nscd_rc_t +_nscd_get_nsw_state_thread( + nss_db_root_t *rootp, + nscd_nsw_params_t *params); + +nscd_rc_t +_nscd_init_all_nsw_state_base(); + +nscd_rc_t +_nscd_init_nsw_state_base( + int dbi, + int lock); + +nscd_rc_t +_nscd_init_all_getent_ctx(); + +nscd_rc_t +_nscd_init_getent_ctx_base( + int dbi, + int lock); + +nscd_db_t +*_nscd_create_getent_ctxaddrDB(); + +nscd_rc_t +_nscd_get_getent_ctx( + nss_getent_t *contextpp, + nscd_nsw_params_t *params); + +void +_nscd_put_getent_ctx( + nscd_getent_context_t *ctx); + +nscd_rc_t +_nscd_init_all_nsw_config(); + +nscd_rc_t +_nscd_init_all_nsw_be_info_db(); + +#ifdef NSCD_NSSWITCH_CONF_FROM_SMF_PROP +nscd_rc_t +_nscd_get_new_nsw_config( + scf_handle_t *hndl, + const char *fmri, + scf_propertygroup_t *pg); +#endif + +nscd_rc_t +_nscd_get_new_service_state( + int index, + scf_handle_t *hndl, + scf_property_t *prop); + +nscd_getent_context_t * +_nscd_is_getent_ctx( + nscd_cookie_t cookie); + +nscd_rc_t +_nscd_create_sw_struct( + int dbi, + const char *dbn, + const char *cfgstr, + void *swcfgv1, + nscd_nsw_params_t *params); + +nscd_rc_t +_nscd_create_new_config( + nscd_nsw_params_t *params); + +void +_nscd_free_nsw_config( + nscd_nsw_config_t *nswcfg); + +nscd_rc_t +_nscd_init_smf_monitor(); + +nscd_rc_t +_nscd_alloc_nsw_config(); + +nscd_rc_t +_nscd_alloc_service_state_table(); + +nscd_rc_t +_nscd_alloc_nsw_state_base(); + +nscd_rc_t +_nscd_alloc_nsw_be_info_db(); + +nscd_rc_t +_nscd_alloc_getent_ctx_base(); + +void +_nscd_free_all_nsw_state_base(); + +void +_nscd_free_all_getent_ctx_base(); + +void +_nscd_free_all_nsw_config(); + +void +_nscd_free_all_nsw_backend_info_db(); + +struct __nsw_switchconfig_v1 * +_nsw_getoneconfig_v1( + const char *name, + char *linep, + enum __nsw_parse_err *errp); +int +__nsw_freeconfig_v1( + struct __nsw_switchconfig_v1 *conf); + +int +_nscd_get_smf_state(int srci, int dbi, int recheck); + +void +nss_psearch(void *buffer, size_t length); +void +nss_psetent(void *buffer, size_t length, pid_t pid); +void +nss_pgetent(void *buffer, size_t length); +void +nss_pendent(void *buffer, size_t length); +void +nss_pdelete(void *buffer, size_t length); + +nscd_rc_t _nscd_alloc_switch_cfg(); +nscd_rc_t _nscd_alloc_switch_stats(); +nscd_db_t *_nscd_create_getent_ctx_addrDB(); +nscd_rc_t _nscd_populate_nsw_backend_info(); +nscd_db_t *_nscd_create_getent_ctxDB(); + +#ifdef __cplusplus +} +#endif + +#endif /* _NSCD_SWITCH_H */ diff --git a/usr/src/cmd/nscd/nscd_wait.c b/usr/src/cmd/nscd/nscd_wait.c index b5af46749e..e091f8764c 100644 --- a/usr/src/cmd/nscd/nscd_wait.c +++ b/usr/src/cmd/nscd/nscd_wait.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -30,123 +29,42 @@ * routines to wait and wake up a client waiting on a list for a * name service request */ -#include <thread.h> -#include <synch.h> -#include "getxby_door.h" +#include "cache.h" int -nscd_wait(waiter_t * wchan, mutex_t * lock, char ** key) +nscd_wait(waiter_t *wchan, mutex_t *lock, uint8_t *key) { waiter_t mywait; - cond_init(&(mywait.w_waitcv), USYNC_THREAD, 0); + (void) cond_init(&(mywait.w_waitcv), USYNC_THREAD, 0); mywait.w_key = key; mywait.w_next = wchan->w_next; mywait.w_prev = wchan; - if(mywait.w_next) + if (mywait.w_next) mywait.w_next->w_prev = &mywait; wchan->w_next = &mywait; - - while( *key == (char *) -1) - cond_wait(&(mywait.w_waitcv), lock); - if(mywait.w_prev) + + while (*key & ST_PENDING) + (void) cond_wait(&(mywait.w_waitcv), lock); + if (mywait.w_prev) mywait.w_prev->w_next = mywait.w_next; - if(mywait.w_next) + if (mywait.w_next) mywait.w_next->w_prev = mywait.w_prev; - return(0); + return (0); } int -nscd_signal(waiter_t * wchan, char ** key) +nscd_signal(waiter_t *wchan, uint8_t *key) { int c = 0; - waiter_t * tmp = wchan->w_next; + waiter_t *tmp = wchan->w_next; - while(tmp) { - if(tmp->w_key == key) { - cond_signal(&(tmp->w_waitcv)); + while (tmp) { + if (tmp->w_key == key) { + (void) cond_signal(&(tmp->w_waitcv)); c++; } tmp = tmp->w_next; } - return(c); + return (c); } - -#ifdef TESTPROG - -static waiter_t w; -static mutex_t l; -static char ** blocks; - -static int num_threads; - -main(int argc, char * argv[]) -{ - int i; - void * go(); - if(argc != 2) { - printf("usage: %s numthreads\n", argv[0]); - exit(1); - } - - num_threads = atoi(argv[1]); - - blocks = (char **) malloc(sizeof(char **) * num_threads); - - memset(blocks, -1, sizeof(char**) * num_threads); - - mutex_lock(&l); - - for(i=0;i<num_threads;i++) - if(thr_create(NULL, NULL, go, (void*)i, THR_NEW_LWP, NULL) != 0) { - printf("thread_create failed\n"); - exit(2); - } - - - - mutex_unlock(&l); - - sleep(5); - - printf("going\n"); - mutex_lock(&l); - - memset(blocks, 0, sizeof(char**) * num_threads); - - for(i=0;i<num_threads;i++) - nscd_signal(&w, blocks+i); - - mutex_unlock(&l); - - while(num_threads--) { - if(thr_join(NULL, NULL, NULL) < 0) { - printf("error in join\n"); - exit(2); - } - } - - printf("all done\n"); - exit(0); -} - -void * go(int index) -{ - printf("thread %d locking\n", index); - - mutex_lock(&l); - - printf("thread %d waiting\n", index); - - nscd_wait(&w,&l, blocks+index); - - printf("thread %d unlocking\n", index); - - mutex_unlock(&l); - - thr_exit(NULL); -} - - -#endif /* TESTPROG */ - diff --git a/usr/src/cmd/nscd/req.flg b/usr/src/cmd/nscd/req.flg new file mode 100644 index 0000000000..e366b376b3 --- /dev/null +++ b/usr/src/cmd/nscd/req.flg @@ -0,0 +1,31 @@ +#!/bin/sh +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +#pragma ident "%Z%%M% %I% %E% SMI" +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# + +echo_file usr/src/lib/libc/port/gen/getxby_door.h +echo_file usr/src/lib/libc/inc/nsswitch_priv.h +echo_file usr/src/lib/libsldap/common/ns_sldap.h diff --git a/usr/src/cmd/nscd/server.c b/usr/src/cmd/nscd/server.c index d4cba76b85..699579fdfe 100644 --- a/usr/src/cmd/nscd/server.c +++ b/usr/src/cmd/nscd/server.c @@ -30,139 +30,44 @@ */ #include <stdio.h> -#include <signal.h> -#include <sys/door.h> -#include <sys/types.h> -#include <time.h> -#include <string.h> -#include <sys/stat.h> -#include <sys/time.h> -#include <sys/wait.h> -#include <sys/zone.h> #include <stdlib.h> +#include <fcntl.h> +#include <string.h> #include <errno.h> -#include <pthread.h> -#include <thread.h> #include <stdarg.h> -#include <fcntl.h> -#include <assert.h> -#include <unistd.h> -#include <memory.h> -#include <sys/socket.h> -#include <net/route.h> -#include <net/if.h> -#include <netinet/in.h> -#include <arpa/nameser.h> -#include <resolv.h> -#include <door.h> -#include "getxby_door.h" -#include "server_door.h" -#include "nscd.h" -/* Includes for filenames of databases */ -#include <shadow.h> -#include <userdefs.h> -#include <netdb.h> -#include <nss_dbdefs.h> -#include <exec_attr.h> -#include <prof_attr.h> -#include <user_attr.h> -#include <ucred.h> -#include <priv.h> -#include <libscf.h> +#include <locale.h> #include <tsol/label.h> #include <zone.h> - -#define TSOL_NAME_SERVICE_DOOR "/var/tsol/doors/name_service_door" +#include "cache.h" +#include "nscd_log.h" +#include "nscd_selfcred.h" +#include "nscd_frontend.h" +#include "nscd_common.h" +#include "nscd_admin.h" +#include "nscd_door.h" +#include "nscd_switch.h" extern int optind; extern int opterr; extern int optopt; extern char *optarg; -static void switcher(void *, char *, size_t, door_desc_t *, uint_t); -static void rts_mon(void); -static void usage(char *); -static int nsc_calllen(nsc_call_t *); -static int client_getadmin(admin_t *); -static void getadmin(nsc_return_t *, int, nsc_call_t *); -static int setadmin(nsc_return_t *, int, nsc_call_t *); -static void client_killserver(void); -static int client_setadmin(admin_t *); -static void client_showstats(admin_t *); -static void detachfromtty(void); - +#define NSCDOPT "S:Kf:c:ge:p:n:i:l:d:s:h:o:GFR" -admin_t current_admin; -static int will_become_server; - -void -nsc_reaper(char *tbl_name, hash_t *tbl, nsc_stat_t *admin_ptr, - mutex_t *hash_lock) -{ - uint_t count; - uint_t interval; +/* assume this is a single nscd or, if multiple, the main nscd */ +int _whoami = NSCD_MAIN; +int _doorfd = -1; +extern int _logfd; +static char *cfgfile = NULL; - while (1) { +extern nsc_ctx_t *cache_ctx_p[]; - if (current_admin.debug_level >= DBG_ALL) { - logit("reaper_%s: %d entries in cache\n", - tbl_name, admin_ptr->nsc_entries); - } - if (admin_ptr->nsc_entries > 0) { - count = reap_hash(tbl, admin_ptr, hash_lock, - admin_ptr->nsc_pos_ttl); - if (current_admin.debug_level >= DBG_ALL) { - logit("reaper_%s: reaped %d entries\n", - tbl_name, count); - } - } else { - /* - * We set a minimum wait of 60 before checking again; - * we don't want to sleep for no time at all. - * We don't clamp it for the reaping itself, that is - * done in reap_hash, and with a different minimum. - */ - interval = admin_ptr->nsc_pos_ttl; - if (interval < 60) interval = 60; - if (current_admin.debug_level >= DBG_ALL) { - logit( - "reaper_%s: Nothing to reap, sleep %d\n", - tbl_name, interval); - } - sleep(interval); - } - } -} - -nsc_stat_t * -getcacheptr(char *s) -{ - static const char *caches[7] = {"passwd", "group", "hosts", "ipnodes", - "exec_attr", "prof_attr", "user_attr" }; - - if (strncmp(caches[0], s, strlen(caches[0])) == 0) - return (¤t_admin.passwd); - - if (strncmp(caches[1], s, strlen(caches[1])) == 0) - return (¤t_admin.group); - - if (strncmp(caches[2], s, strlen(caches[2])) == 0) - return (¤t_admin.host); - - if (strncmp(caches[3], s, strlen(caches[3])) == 0) - return (¤t_admin.node); - - if (strncmp(caches[4], s, strlen(caches[4])) == 0) - return (¤t_admin.exec); - - if (strncmp(caches[5], s, strlen(caches[5])) == 0) - return (¤t_admin.prof); - - if (strncmp(caches[6], s, strlen(caches[6])) == 0) - return (¤t_admin.user); +static void usage(char *); +static void detachfromtty(void); - return (NULL); -} +static int debug_level = 0; +static char logfile[128] = { 0 }; +static int will_become_server; static char * getcacheopt(char *s) @@ -173,37 +78,6 @@ getcacheopt(char *s) } /* - * routine to check if server is already running - */ - -static int -nsc_ping(void) -{ - nsc_data_t data; - nsc_data_t *dptr; - int ndata; - int adata; - - data.nsc_call.nsc_callnumber = NULLCALL; - ndata = sizeof (data); - adata = sizeof (data); - dptr = &data; - return (_nsc_trydoorcall(&dptr, &ndata, &adata)); -} - -static void -dozip(void) -{ - /* not much here */ -} - -static void -keep_open_dns_socket(void) -{ - _res.options |= RES_STAYOPEN; /* just keep this udp socket open */ -} - -/* * declaring this causes the files backend to use hashing * this is of course an utter hack, but provides a nice * quiet back door to enable this feature for only the nscd. @@ -211,242 +85,11 @@ keep_open_dns_socket(void) void __nss_use_files_hash(void) { - } -/* - * - * The allocation of resources for cache lookups is an interesting - * problem, and one that has caused several bugs in the beta release - * of 2.5. In particular, the introduction of a thottle to prevent - * the creation of excessive numbers of LWPs in the case of a failed - * name service has led to a denial of service problem when the - * name service request rate exceeds the name service's ability - * to respond. As a result, I'm implementing the following - * algorithm: - * - * 1) We cap the number of total threads. - * 2) We save CACHE_THREADS of those for cache lookups only. - * 3) We use a common pool of 2/3 of the remain threads that are used first - * 4) We save the remainder and allocate 1/3 of it for table specific lookups - * - * The intent is to prevent the failure of a single name service from - * causing denial of service, and to always have threads available for - * cached lookups. If a request comes in and the answer isn't in the - * cache and we cannot get a thread, we simply return NOSERVER, forcing - * the client to lookup the - * data itself. This will prevent the types of starvation seen - * at UNC due to a single threaded DNS backend, and allows the cache - * to eventually become filled. - * - */ -/* 7 tables: passwd, group, hosts, ipnodes, exec_attr, prof_attr, user_attr */ -#define NSCD_TABLES 7 -#define TABLE_THREADS 10 -#define COMMON_THREADS 20 -#define CACHE_MISS_THREADS (COMMON_THREADS + NSCD_TABLES * TABLE_THREADS) -#define CACHE_HIT_THREADS 20 -#define MAX_SERVER_THREADS (CACHE_HIT_THREADS + CACHE_MISS_THREADS) - -static sema_t common_sema; -static sema_t passwd_sema; -static sema_t hosts_sema; -static sema_t nodes_sema; -static sema_t group_sema; -static sema_t exec_sema; -static sema_t prof_sema; -static sema_t user_sema; -static thread_key_t lookup_state_key; - -static void -initialize_lookup_clearance(void) -{ - thr_keycreate(&lookup_state_key, NULL); - (void) sema_init(&common_sema, COMMON_THREADS, USYNC_THREAD, 0); - (void) sema_init(&passwd_sema, TABLE_THREADS, USYNC_THREAD, 0); - (void) sema_init(&hosts_sema, TABLE_THREADS, USYNC_THREAD, 0); - (void) sema_init(&nodes_sema, TABLE_THREADS, USYNC_THREAD, 0); - (void) sema_init(&group_sema, TABLE_THREADS, USYNC_THREAD, 0); - (void) sema_init(&exec_sema, TABLE_THREADS, USYNC_THREAD, 0); - (void) sema_init(&prof_sema, TABLE_THREADS, USYNC_THREAD, 0); - (void) sema_init(&user_sema, TABLE_THREADS, USYNC_THREAD, 0); -} - -int -get_clearance(int callnumber) -{ - sema_t *table_sema = NULL; - char *tab; - - if (sema_trywait(&common_sema) == 0) { - thr_setspecific(lookup_state_key, NULL); - return (0); - } - - switch (MASKUPDATEBIT(callnumber)) { - - case GETPWUID: - case GETPWNAM: - tab = "passwd"; - table_sema = &passwd_sema; - break; - - case GETGRNAM: - case GETGRGID: - tab = "group"; - table_sema = &group_sema; - break; - - case GETHOSTBYNAME: - case GETHOSTBYADDR: - tab = "hosts"; - table_sema = &hosts_sema; - break; - - case GETIPNODEBYNAME: - case GETIPNODEBYADDR: - tab = "ipnodes"; - table_sema = &nodes_sema; - break; - case GETEXECID: - tab = "exec_attr"; - table_sema = &exec_sema; - break; - - case GETPROFNAM: - tab = "prof_attr"; - table_sema = &prof_sema; - break; - - case GETUSERNAM: - tab = "user_attr"; - table_sema = &user_sema; - break; - - } - - if (sema_trywait(table_sema) == 0) { - thr_setspecific(lookup_state_key, (void*)1); - return (0); - } - - if (current_admin.debug_level >= DBG_CANT_FIND) { - logit("get_clearance: throttling load for %s table\n", tab); - } - return (-1); -} - -int -release_clearance(int callnumber) -{ - int which; - - sema_t *table_sema = NULL; - - thr_getspecific(lookup_state_key, (void**)&which); - - if (which == 0) /* from common pool */ { - (void) sema_post(&common_sema); - return (0); - } - - switch (MASKUPDATEBIT(callnumber)) { - - case GETPWUID: - case GETPWNAM: - table_sema = &passwd_sema; - break; - - case GETGRNAM: - case GETGRGID: - table_sema = &group_sema; - break; - - case GETHOSTBYNAME: - case GETHOSTBYADDR: - table_sema = &hosts_sema; - break; - - case GETIPNODEBYNAME: - case GETIPNODEBYADDR: - table_sema = &nodes_sema; - break; - - case GETEXECID: - table_sema = &exec_sema; - break; - - case GETPROFNAM: - table_sema = &prof_sema; - break; - - case GETUSERNAM: - table_sema = &user_sema; - break; - } - - (void) sema_post(table_sema); - return (0); -} - - -static mutex_t create_lock; -static int nscd_max_servers = MAX_SERVER_THREADS; -static int num_servers = 0; -static thread_key_t server_key; - -/* - * Bind a TSD value to a server thread. This enables the destructor to - * be called if/when this thread exits. This would be a programming error, - * but better safe than sorry. - */ -/*ARGSUSED*/ -static void * -server_tsd_bind(void *arg) -{ - static void *value = 0; - - /* disable cancellation to avoid hangs if server threads disappear */ - pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); - thr_setspecific(server_key, value); - door_return(NULL, 0, NULL, 0); - - /* make lint happy */ - return (NULL); -} - -/* - * Server threads are created here. - */ -/*ARGSUSED*/ -static void -server_create(door_info_t *dip) -{ - (void) mutex_lock(&create_lock); - if (++num_servers > nscd_max_servers) { - num_servers--; - (void) mutex_unlock(&create_lock); - return; - } - (void) mutex_unlock(&create_lock); - thr_create(NULL, 0, server_tsd_bind, NULL, THR_BOUND|THR_DETACHED, - NULL); -} - -/* - * Server thread are destroyed here - */ -/*ARGSUSED*/ -static void -server_destroy(void *arg) -{ - (void) mutex_lock(&create_lock); - num_servers--; - (void) mutex_unlock(&create_lock); -} - -static char **saved_argv; -static char saved_execname[MAXPATHLEN]; +static int saved_argc = 0; +static char **saved_argv = NULL; +static char saved_execname[MAXPATHLEN]; static void save_execname() @@ -457,23 +100,31 @@ save_execname() if (name[0] != '/') { /* started w/ relative path */ (void) getcwd(saved_execname, MAXPATHLEN); - strlcat(saved_execname, "/", MAXPATHLEN); + (void) strlcat(saved_execname, "/", MAXPATHLEN); } - strlcat(saved_execname, name, MAXPATHLEN); + (void) strlcat(saved_execname, name, MAXPATHLEN); } int main(int argc, char ** argv) { - int did; - int opt; - int errflg = 0; - int showstats = 0; - int doset = 0; - int loaded_config_file = 0; - struct stat buf; - sigset_t myset; - struct sigaction action; + int opt; + int errflg = 0; + int showstats = 0; + int doset = 0; + nscd_rc_t rc; + char *me = "main()"; + char *ret_locale; + char *ret_textdomain; + char msg[128]; + + ret_locale = setlocale(LC_ALL, ""); + if (ret_locale == NULL) + (void) fprintf(stderr, gettext("Unable to set locale\n")); + + ret_textdomain = textdomain(TEXT_DOMAIN); + if (ret_textdomain == NULL) + (void) fprintf(stderr, gettext("Unable to set textdomain\n")); /* * The admin model for TX is that labeled zones are managed @@ -482,250 +133,207 @@ main(int argc, char ** argv) */ if (is_system_labeled() && (getzoneid() != GLOBAL_ZONEID)) { (void) fprintf(stderr, - "With Trusted Extensions nscd runs only in " \ - "the global zone.\n"); +gettext("With Trusted Extensions nscd runs only in the global zone.\n")); exit(1); } /* - * Special case non-root user here - he can just print stats + * Special case non-root user here - he can just print stats */ - if (geteuid()) { - if (argc != 2 || strcmp(argv[1], "-g")) { + if (argc != 2 || + (strcmp(argv[1], "-g") && strcmp(argv[1], "-G"))) { (void) fprintf(stderr, - "Must be root to use any option other than "\ - "-g.\n\n"); + gettext("Must be root to use any option other than -g\n\n")); usage(argv[0]); } - if ((nsc_ping() != SUCCESS) || - (client_getadmin(¤t_admin) != 0)) { + if (_nscd_doorcall(NSCD_PING) != NSS_SUCCESS) { (void) fprintf(stderr, - "%s doesn't appear to be running.\n", argv[0]); + gettext("%s doesn't appear to be running.\n"), + argv[0]); exit(1); } - client_showstats(¤t_admin); + if (_nscd_client_getadmin(argv[1][1]) != 0) { + (void) fprintf(stderr, + gettext("unable to get configuration and statistics data\n")); + exit(1); + } + + _nscd_client_showstats(); exit(0); } - - /* - * Determine if there is already a daemon running + * Determine if there is already a daemon (main nscd) running. + * If not, will start it. Forker NSCD will always become a + * daemon. */ + will_become_server = (_nscd_doorcall(NSCD_PING) != NSS_SUCCESS); + if (argc >= 2 && strcmp(argv[1], "-F") == 0) { + will_become_server = 1; + _whoami = NSCD_FORKER; - will_become_server = (nsc_ping() != SUCCESS); - - /* - * process usual options - */ + /* + * allow time for the main nscd to get ready + * to receive the IMHERE door request this + * process will send later + */ + (void) usleep(100000); + } /* - * load normal config file + * first get the config file path. Also detect + * invalid option as soon as possible. */ + while ((opt = getopt(argc, argv, NSCDOPT)) != EOF) { + switch (opt) { - if (will_become_server) { - static const nsc_stat_t defaults = { - 0, /* stats */ - 0, /* stats */ - 0, /* stats */ - 0, /* stats */ - 0, /* stats */ - 0, /* stats */ - 0, /* stats */ - 211, /* suggested size */ - 1, /* enabled */ - 0, /* invalidate cmd */ - 600, /* positive ttl */ - 10, /* netative ttl */ - 20, /* keep hot */ - 0, /* old data not ok */ - 1 }; /* check files */ - - current_admin.passwd = defaults; - current_admin.group = defaults; - current_admin.host = defaults; - current_admin.node = defaults; - current_admin.exec = defaults; - current_admin.prof = defaults; - current_admin.user = defaults; - - current_admin.logfile[0] = '\0'; - - if (access("/etc/nscd.conf", R_OK) == 0) { - if (nscd_parse(argv[0], "/etc/nscd.conf") < 0) { + case 'f': + if ((cfgfile = strdup(optarg)) == NULL) exit(1); + break; + case 'g': + if (will_become_server) { + (void) fprintf(stderr, + gettext("nscd not running, no statistics to show\n\n")); + errflg++; + } + break; + case 'i': + if (will_become_server) { + (void) fprintf(stderr, + gettext("nscd not running, no cache to invalidate\n\n")); + errflg++; } - loaded_config_file++; + break; + + case '?': + errflg++; + break; } + } + if (errflg) + usage(argv[0]); + + /* + * perform more initialization and load configuration + * if to become server + */ + if (will_become_server) { - else { - if (client_getadmin(¤t_admin)) { + /* initialize switch engine and config/stats management */ + if ((rc = _nscd_init(cfgfile)) != NSCD_SUCCESS) { (void) fprintf(stderr, - "Cannot contact nscd properly(?)\n"); + gettext("initialization of switch failed (rc = %d)\n"), rc); exit(1); } - current_admin.logfile[0] = '\0'; + /* + * initialize cache store + */ + if ((rc = init_cache(0)) != NSCD_SUCCESS) { + (void) fprintf(stderr, + gettext("initialization of cache store failed (rc = %d)\n"), rc); + exit(1); + } } - while ((opt = getopt(argc, argv, - "S:Kf:c:ge:p:n:i:l:d:s:h:o:")) != EOF) { - nsc_stat_t *cache; - char *cacheopt; + /* + * process usual options + */ + optind = 1; /* this is a rescan */ + *msg = '\0'; + while ((opt = getopt(argc, argv, NSCDOPT)) != EOF) { switch (opt) { - case 'S': /* undocumented feature */ - doset++; - cache = getcacheptr(optarg); - cacheopt = getcacheopt(optarg); - if (!cache || !cacheopt) { - errflg++; - break; - } - if (strcmp(cacheopt, "yes") == 0) - cache->nsc_secure_mode = 1; - else if (strcmp(cacheopt, "no") == 0) - cache->nsc_secure_mode = 0; - else - errflg++; - break; - case 'K': /* undocumented feature */ - client_killserver(); + (void) _nscd_doorcall(NSCD_KILLSERVER); exit(0); break; - case 'f': - doset++; - loaded_config_file++; - if (nscd_parse(argv[0], optarg) < 0) { - exit(1); - } - break; - + case 'G': case 'g': showstats++; break; case 'p': doset++; - cache = getcacheptr(optarg); - cacheopt = getcacheopt(optarg); - if (!cache || !cacheopt) { + if (_nscd_add_admin_mod(optarg, 'p', + getcacheopt(optarg), + msg, sizeof (msg)) == -1) errflg++; - break; - } - cache->nsc_pos_ttl = atoi(cacheopt); break; case 'n': doset++; - cache = getcacheptr(optarg); - cacheopt = getcacheopt(optarg); - if (!cache || !cacheopt) { + if (_nscd_add_admin_mod(optarg, 'n', + getcacheopt(optarg), + msg, sizeof (msg)) == -1) errflg++; - break; - } - cache->nsc_neg_ttl = atoi(cacheopt); break; case 'c': doset++; - cache = getcacheptr(optarg); - cacheopt = getcacheopt(optarg); - if (!cache || !cacheopt) { + if (_nscd_add_admin_mod(optarg, 'c', + getcacheopt(optarg), + msg, sizeof (msg)) == -1) errflg++; - break; - } - - if (strcmp(cacheopt, "yes") == 0) - cache->nsc_check_files = 1; - else if (strcmp(cacheopt, "no") == 0) - cache->nsc_check_files = 0; - else - errflg++; break; - case 'i': doset++; - cache = getcacheptr(optarg); - if (!cache) { + if (_nscd_add_admin_mod(optarg, 'i', NULL, + msg, sizeof (msg)) == -1) errflg++; - break; - } - cache->nsc_invalidate = 1; break; case 'l': doset++; - (void) strlcpy(current_admin.logfile, optarg, 128); + (void) strlcpy(logfile, optarg, 128); + (void) _nscd_add_admin_mod(NULL, 'l', optarg, + msg, sizeof (msg)); break; case 'd': - doset++; - current_admin.debug_level = atoi(optarg); + debug_level = atoi(optarg); + (void) _nscd_add_admin_mod(NULL, 'd', optarg, + msg, sizeof (msg)); break; - case 's': - doset++; - cache = getcacheptr(optarg); - cacheopt = getcacheopt(optarg); - if (!cache || !cacheopt) { - errflg++; - break; - } + case 'S': + /* silently ignore secure-mode */ + break; - cache->nsc_suggestedsize = atoi(cacheopt); + case 's': + /* silently ignore suggested-size */ + break; + case 'o': + /* silently ignore old-data-ok */ break; case 'h': doset++; - cache = getcacheptr(optarg); - cacheopt = getcacheopt(optarg); - if (!cache || !cacheopt) { + if (_nscd_add_admin_mod(optarg, 'h', + getcacheopt(optarg), + msg, sizeof (msg)) == -1) errflg++; - break; - } - cache->nsc_keephot = atoi(cacheopt); break; - case 'o': + case 'e': doset++; - cache = getcacheptr(optarg); - cacheopt = getcacheopt(optarg); - if (!cache || !cacheopt) { + if (_nscd_add_admin_mod(optarg, 'e', + getcacheopt(optarg), + msg, sizeof (msg)) == -1) errflg++; - break; - } - if (strcmp(cacheopt, "yes") == 0) - cache->nsc_old_data_ok = 1; - else if (strcmp(cacheopt, "no") == 0) - cache->nsc_old_data_ok = 0; - else - errflg++; break; - case 'e': - doset++; - cache = getcacheptr(optarg); - cacheopt = getcacheopt(optarg); - if (!cache || !cacheopt) { - errflg++; - break; - } - if (strcmp(cacheopt, "yes") == 0) - cache->nsc_enabled = 1; - else if (strcmp(cacheopt, "no") == 0) - cache->nsc_enabled = 0; - else - errflg++; + case 'F': + _whoami = NSCD_FORKER; break; default: @@ -735,548 +343,123 @@ main(int argc, char ** argv) } - if (errflg) + if (errflg) { + if (*msg != '\0') + (void) fprintf(stderr, "\n%s: %s\n\n", argv[0], msg); usage(argv[0]); - - if (!will_become_server) { - - if (showstats) { - client_showstats(¤t_admin); - } - - if (doset) { - if (client_setadmin(¤t_admin) < 0) { - (void) fprintf(stderr, - "Error during admin call\n"); - exit(1); - } - } - if (!showstats && !doset) { - (void) fprintf(stderr, - "%s already running.... no admin specified\n", - argv[0]); - } - exit(0); } /* - * daemon from here ou + * if main nscd already running and not forker nscd, + * can only do admin work */ + if (_whoami == NSCD_MAIN) { + if (!will_become_server) { + if (showstats) { + if (_nscd_client_getadmin('g')) { + (void) fprintf(stderr, + gettext("Cannot contact nscd properly(?)\n")); + exit(1); + } + _nscd_client_showstats(); + } - if (!loaded_config_file) { - (void) fprintf(stderr, - "No configuration file specifed and /etc/nscd.conf" \ - "not present\n"); - exit(1); - } - - saved_argv = argv; - save_execname(); - - if (current_admin.debug_level) { - /* we're debugging... */ - if (strlen(current_admin.logfile) == 0) - /* no specified log file */ - (void) strcpy(current_admin.logfile, "stderr"); - else - (void) nscd_set_lf(¤t_admin, - current_admin.logfile); - } else { - if (strlen(current_admin.logfile) == 0) - (void) strcpy(current_admin.logfile, "/dev/null"); - (void) nscd_set_lf(¤t_admin, current_admin.logfile); - detachfromtty(); - } - - /* perform some initialization */ - initialize_lookup_clearance(); - keep_open_dns_socket(); - getpw_init(); - getgr_init(); - gethost_init(); - getnode_init(); - getexec_init(); - getprof_init(); - getuser_init(); - - /* Establish our own server thread pool */ - - door_server_create(server_create); - if (thr_keycreate(&server_key, server_destroy) != 0) { - perror("thr_keycreate"); - exit(-1); - } - - /* Create a door */ - - if ((did = door_create(switcher, NAME_SERVICE_DOOR_COOKIE, - DOOR_UNREF | DOOR_REFUSE_DESC | DOOR_NO_CANCEL)) < 0) { - perror("door_create"); - exit(-1); - } - - /* bind to file system */ - - if (is_system_labeled()) { - if (stat(TSOL_NAME_SERVICE_DOOR, &buf) < 0) { - int newfd; - if ((newfd = creat(TSOL_NAME_SERVICE_DOOR, 0444)) < 0) { - logit("Cannot create %s:%s\n", - TSOL_NAME_SERVICE_DOOR, strerror(errno)); - exit(1); + if (doset) { + if (_nscd_client_setadmin() < 0) { + (void) fprintf(stderr, + gettext("Error during admin call\n")); + exit(1); + } } - (void) close(newfd); - } - if (symlink(TSOL_NAME_SERVICE_DOOR, NAME_SERVICE_DOOR) != 0) { - if (errno != EEXIST) { - logit("Cannot symlink %s:%s\n", - NAME_SERVICE_DOOR, strerror(errno)); - exit(1); + if (!showstats && !doset) { + (void) fprintf(stderr, +gettext("%s already running.... no administration option specified\n"), + argv[0]); } + exit(0); } - } else if (stat(NAME_SERVICE_DOOR, &buf) < 0) { - int newfd; - if ((newfd = creat(NAME_SERVICE_DOOR, 0444)) < 0) { - logit("Cannot create %s:%s\n", NAME_SERVICE_DOOR, - strerror(errno)); - exit(1); - } - (void) close(newfd); - } - - if (fattach(did, NAME_SERVICE_DOOR) < 0) { - if ((errno != EBUSY) || - (fdetach(NAME_SERVICE_DOOR) < 0) || - (fattach(did, NAME_SERVICE_DOOR) < 0)) { - perror("door_attach"); - exit(2); - } - } - - action.sa_handler = dozip; - action.sa_flags = 0; - (void) sigemptyset(&action.sa_mask); - (void) sigemptyset(&myset); - (void) sigaddset(&myset, SIGHUP); - - if (sigaction(SIGHUP, &action, NULL) < 0) { - perror("sigaction"); - exit(1); - } - - if (thr_sigsetmask(SIG_BLOCK, &myset, NULL) < 0) { - perror("thr_sigsetmask"); - exit(1); - } - - - /* - * kick off revalidate threads - */ - - if (thr_create(NULL, NULL, - (void *(*)(void *))getpw_revalidate, 0, 0, NULL) != 0) { - perror("thr_create"); - exit(1); - } - - if (thr_create(NULL, NULL, - (void *(*)(void *))gethost_revalidate, 0, 0, NULL) != 0) { - perror("thr_create"); - exit(1); - } - - if (thr_create(NULL, NULL, - (void *(*)(void*))getnode_revalidate, 0, 0, NULL) != 0) { - perror("thr_create"); - exit(1); - } - - if (thr_create(NULL, NULL, - (void *(*)(void*))getgr_revalidate, 0, 0, NULL) != 0) { - perror("thr_create"); - exit(1); - } - - if (thr_create(NULL, NULL, - (void *(*)(void*))getexec_revalidate, 0, 0, NULL) != 0) { - perror("thr_create"); - exit(1); - } - - if (thr_create(NULL, NULL, - (void *(*)(void*))getprof_revalidate, 0, 0, NULL) != 0) { - perror("thr_create"); - exit(1); - } - - if (thr_create(NULL, NULL, - (void *(*)(void*))getuser_revalidate, 0, 0, NULL) != 0) { - perror("thr_create"); - exit(1); - } - - /* - * kick off reaper threads - */ - - if (thr_create(NULL, NULL, - (void *(*)(void *))getpw_uid_reaper, 0, 0, NULL) != 0) { - perror("thr_create"); - exit(1); - } - - if (thr_create(NULL, NULL, - (void *(*)(void *))getpw_nam_reaper, 0, 0, NULL) != 0) { - perror("thr_create"); - exit(1); - } - - if (thr_create(NULL, NULL, - (void *(*)(void *))getgr_uid_reaper, 0, 0, NULL) != 0) { - perror("thr_create"); - exit(1); - } - - if (thr_create(NULL, NULL, - (void *(*)(void *))getgr_nam_reaper, 0, 0, NULL) != 0) { - perror("thr_create"); - exit(1); - } - - - if (thr_create(NULL, NULL, - (void *(*)(void *))gethost_nam_reaper, 0, 0, NULL) != 0) { - perror("thr_create"); - exit(1); - } - - if (thr_create(NULL, NULL, - (void *(*)(void *))gethost_addr_reaper, 0, 0, NULL) != 0) { - perror("thr_create"); - exit(1); - } - - if (thr_create(NULL, NULL, - (void *(*)(void *))getnode_nam_reaper, 0, 0, NULL) != 0) { - perror("thr_create"); - exit(1); - } - - if (thr_create(NULL, NULL, - (void *(*)(void *))getnode_addr_reaper, 0, 0, NULL) != 0) { - perror("thr_create"); - exit(1); - } - - if (thr_create(NULL, NULL, - (void *(*)(void *))getexec_reaper, 0, 0, NULL) != 0) { - perror("thr_create"); - exit(1); - } - - if (thr_create(NULL, NULL, - (void *(*)(void *))getprof_reaper, 0, 0, NULL) != 0) { - perror("thr_create"); - exit(1); - } - - if (thr_create(NULL, NULL, - (void *(*)(void *))getuser_reaper, 0, 0, NULL) != 0) { - perror("thr_create"); - exit(1); } /* - * kick off routing socket monitor thread + * daemon from here on */ - if (thr_create(NULL, NULL, - (void *(*)(void *))rts_mon, 0, 0, NULL) != 0) { - perror("thr_create"); - exit(1); - } + if (_whoami == NSCD_MAIN) { - if (thr_sigsetmask(SIG_UNBLOCK, &myset, NULL) < 0) { - perror("thr_sigsetmask"); - return (1); - } - - for (;;) { - (void) pause(); - logit("Reloading /etc/nscd.conf\n"); - nscd_parse(argv[0], "/etc/nscd.conf"); - } -} - - -/*ARGSUSED*/ -static void -switcher(void *cookie, char *argp, size_t arg_size, - door_desc_t *dp, uint_t n_desc) -{ - union { - nsc_data_t data; - char space[8192]; - } u; - - time_t now; - - static time_t last_nsswitch_check; - static time_t last_nsswitch_modified; - static time_t last_resolv_modified; - - static mutex_t nsswitch_lock; - - nsc_call_t *ptr = (nsc_call_t *)argp; - - if (argp == DOOR_UNREF_DATA) { - (void) printf("Door Slam... exiting\n"); - exit(0); - } - - if (ptr == NULL) { /* empty door call */ - (void) door_return(NULL, 0, 0, 0); /* return the favor */ - } - - now = time(NULL); - - /* - * just in case check - */ - - (void) mutex_lock(&nsswitch_lock); - - if (now - last_nsswitch_check > 10) { - struct stat nss_buf; - struct stat res_buf; - - last_nsswitch_check = now; - - (void) mutex_unlock(&nsswitch_lock); /* let others continue */ + /* save enough info in case need to restart or fork */ + saved_argc = argc; + saved_argv = argv; + save_execname(); /* - * This code keeps us from statting resolv.conf - * if it doesn't exist, yet prevents us from ignoring - * it if it happens to disappear later on for a bit. + * if a log file is not specified, set it to + * "stderr" or "/dev/null" based on debug level */ + if (_logfd < 0 && *logfile == '\0') { + if (debug_level != 0) + /* we're debugging... */ + (void) strcpy(logfile, "stderr"); + else + (void) strcpy(logfile, "/dev/null"); - if (last_resolv_modified >= 0) { - if (stat("/etc/resolv.conf", &res_buf) < 0) { - if (last_resolv_modified == 0) - last_resolv_modified = -1; - else - res_buf.st_mtime = last_resolv_modified; - } else if (last_resolv_modified == 0) { - last_resolv_modified = res_buf.st_mtime; - } + (void) _nscd_add_admin_mod(NULL, 'l', logfile, + msg, sizeof (msg)); } - if (stat("/etc/nsswitch.conf", &nss_buf) < 0) { - - /*EMPTY*/; - - } else if (last_nsswitch_modified == 0) { + /* activate command options */ + if (_nscd_server_setadmin(NULL) != NSCD_SUCCESS) { + (void) fprintf(stderr, + gettext("unable to set command line options\n")); + exit(1); + } - last_nsswitch_modified = nss_buf.st_mtime; + if (debug_level) { + /* we're debugging, no forking of nscd */ - } else if ((last_nsswitch_modified < nss_buf.st_mtime) || - ((last_resolv_modified > 0) && - (last_resolv_modified < res_buf.st_mtime))) { - static mutex_t exit_lock; - char *fmri; /* - * time for restart + * forker nscd will be started if self credential + * is configured */ - logit("nscd restart due to /etc/nsswitch.conf or "\ - "resolv.conf change\n"); + _nscd_start_forker(saved_execname, saved_argc, + saved_argv); + } else { /* - * try to restart under smf + * daemonize the nscd (forker nscd will also + * be started if self credential is configured) */ - if ((fmri = getenv("SMF_FMRI")) == NULL) { - /* not running under smf - reexec */ - execv(saved_execname, saved_argv); - exit(1); /* just in case */ - } - - mutex_lock(&exit_lock); /* prevent multiple restarts */ - if (smf_restart_instance(fmri) == 0) - sleep(10); /* wait a bit */ - exit(1); /* give up waiting for resurrection */ + detachfromtty(); } - - } else - (void) mutex_unlock(&nsswitch_lock); - - switch (ptr->nsc_callnumber) { - - case NULLCALL: - u.data.nsc_ret.nsc_return_code = SUCCESS; - u.data.nsc_ret.nsc_bufferbytesused = sizeof (nsc_return_t); - break; - - - case GETPWNAM: - *(argp + arg_size - 1) = 0; /* FALLTHROUGH */ - case GETPWUID: - getpw_lookup(&u.data.nsc_ret, sizeof (u), ptr, now); - break; - - case GETGRNAM: - *(argp + arg_size - 1) = 0; /* FALLTHROUGH */ - case GETGRGID: - getgr_lookup(&u.data.nsc_ret, sizeof (u), ptr, now); - break; - - case GETHOSTBYNAME: - *(argp + arg_size - 1) = 0; /* FALLTHROUGH */ - case GETHOSTBYADDR: - gethost_lookup(&u.data.nsc_ret, sizeof (u), ptr, now); - break; - - case GETIPNODEBYNAME: - *(argp + arg_size - 1) = 0; /* FALLTHROUGH */ - case GETIPNODEBYADDR: - getnode_lookup(&u.data.nsc_ret, sizeof (u), ptr, now); - break; - - case GETEXECID: - *(argp + arg_size - 1) = 0; - getexec_lookup(&u.data.nsc_ret, sizeof (u), ptr, now); - break; - - case GETPROFNAM: - *(argp + arg_size - 1) = 0; - getprof_lookup(&u.data.nsc_ret, sizeof (u), ptr, now); - break; - - case GETUSERNAM: - *(argp + arg_size - 1) = 0; - getuser_lookup(&u.data.nsc_ret, sizeof (u), ptr, now); - break; - - case GETADMIN: - getadmin(&u.data.nsc_ret, sizeof (u), ptr); - break; - - case SETADMIN: - case KILLSERVER: { - - ucred_t *uc = NULL; - const priv_set_t *eset; - zoneid_t zoneid; - - if (door_ucred(&uc) != 0) { - perror("door_ucred"); - u.data.nsc_ret.nsc_return_code = NOTFOUND; - break; - } - - eset = ucred_getprivset(uc, PRIV_EFFECTIVE); - zoneid = ucred_getzoneid(uc); - - if ((zoneid != GLOBAL_ZONEID && zoneid != getzoneid()) || - eset != NULL ? !priv_ismember(eset, PRIV_SYS_ADMIN) : - ucred_geteuid(uc) != 0) { - logit("SETADMIN call failed(cred): caller pid %d, " - "uid %d, euid %d, zoneid %d\n", ucred_getpid(uc), - ucred_getruid(uc), ucred_geteuid(uc), zoneid); - u.data.nsc_ret.nsc_return_code = NOTFOUND; - ucred_free(uc); - break; - } - - if (ptr->nsc_callnumber == KILLSERVER) { - logit("Nscd received KILLSERVER cmd from pid %d, " - "uid %d, euid %d, zoneid %d\n", ucred_getpid(uc), - ucred_getruid(uc), ucred_geteuid(uc), zoneid); - exit(0); - } else { - if (setadmin(&u.data.nsc_ret, sizeof (u), ptr) != 0) - logit("SETADMIN call failed\n"); - } - ucred_free(uc); - break; + } else { /* NSCD_FORKER */ + (void) open("/dev/null", O_RDWR, 0); + (void) dup(0); + if (_logfd != 2) + (void) dup(0); } - default: - logit("Unknown name service door call op %d\n", - ptr->nsc_callnumber); - u.data.nsc_ret.nsc_return_code = -1; - u.data.nsc_ret.nsc_bufferbytesused = sizeof (nsc_return_t); - break; - + /* set up door and establish our own server thread pool */ + if ((_doorfd = _nscd_setup_server(saved_execname, saved_argv)) == -1) { + _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR) + (me, "unable to set up door\n"); + exit(1); } - door_return((char *)&u.data, u.data.nsc_ret.nsc_bufferbytesused, - NULL, 0); -} -/* - * Monitor the routing socket. Address lists stored in the ipnodes - * cache are sorted based on destination address selection rules, - * so when things change that could affect that sorting (interfaces - * go up or down, flags change, etc.), we clear that cache so the - * list will be re-ordered the next time the hostname is resolved. - */ -static void -rts_mon(void) -{ - int rt_sock, rdlen; - union { - struct { - struct rt_msghdr rtm; - struct sockaddr_storage addrs[RTA_NUMBITS]; - } r; - struct if_msghdr ifm; - struct ifa_msghdr ifam; - } mbuf; - struct ifa_msghdr *ifam = &mbuf.ifam; - - rt_sock = socket(PF_ROUTE, SOCK_RAW, 0); - if (rt_sock < 0) { - logit("Failed to open routing socket: %s\n", strerror(errno)); - thr_exit(0); + /* inform the main nscd that this forker is ready */ + if (_whoami == NSCD_FORKER) { + int ret; + + for (ret = NSS_ALTRETRY; ret == NSS_ALTRETRY; ) + ret = _nscd_doorcall_sendfd(_doorfd, + NSCD_IMHERE | (NSCD_FORKER & NSCD_WHOAMI), + NULL, 0, NULL); } for (;;) { - rdlen = read(rt_sock, &mbuf, sizeof (mbuf)); - if (rdlen <= 0) { - if (rdlen == 0 || (errno != EINTR && errno != EAGAIN)) { - logit("routing socket read: %s\n", - strerror(errno)); - thr_exit(0); - } - continue; - } - if (ifam->ifam_version != RTM_VERSION) { - logit("rx unknown version (%d) on routing socket.\n", - ifam->ifam_version); - continue; - } - switch (ifam->ifam_type) { - case RTM_NEWADDR: - case RTM_DELADDR: - getnode_name_invalidate(); - break; - case RTM_ADD: - case RTM_DELETE: - case RTM_CHANGE: - case RTM_GET: - case RTM_LOSING: - case RTM_REDIRECT: - case RTM_MISS: - case RTM_LOCK: - case RTM_OLDADD: - case RTM_OLDDEL: - case RTM_RESOLVE: - case RTM_IFINFO: - break; - default: - logit("rx unknown msg type (%d) on routing socket.\n", - ifam->ifam_type); - break; - } + (void) pause(); + (void) _nscd_doorcall(NSCD_REFRESH); } + + /* NOTREACHED */ + /*LINTED E_FUNC_HAS_NO_RETURN_STMT*/ } static void @@ -1289,609 +472,43 @@ usage(char *s) (void) fprintf(stderr, " [-n cachename,negative_time_to_live]\n"); (void) fprintf(stderr, - " [-i cachename] [-s cachename,suggestedsize]\n"); - + " [-i cachename]\n"); (void) fprintf(stderr, - " [-h cachename,keep_hot_count] "\ - "[-o cachename,\"yes\"|\"no\"]\n"); - + " [-h cachename,keep_hot_count]\n"); (void) fprintf(stderr, " [-e cachename,\"yes\"|\"no\"] [-g] " \ "[-c cachename,\"yes\"|\"no\"]\n"); - (void) fprintf(stderr, " [-f configfilename] \n"); - (void) fprintf(stderr, - "\n Supported caches: passwd, group, hosts, ipnodes\n"); - + "\n Supported caches:\n"); (void) fprintf(stderr, - " exec_attr, prof_attr, and user_attr.\n"); - + " audit_user, auth_attr, bootparams, ethers\n"); + (void) fprintf(stderr, + " exec_attr, group, hosts, ipnodes, netmasks\n"); + (void) fprintf(stderr, + " networks, passwd, printers, prof_attr, project\n"); + (void) fprintf(stderr, + " protocols, rpc, services, tnrhtp, tnrhdb\n"); + (void) fprintf(stderr, + " user_attr\n"); exit(1); - -} - - -static int logfd = 2; - -int -nscd_set_lf(admin_t *ptr, char *s) -{ - int newlogfd; - - /* - * we don't really want to try and open the log file - * /dev/null since that will fail w/ our security fixes - */ - - if (*s == 0) { - /* ignore empty log file specs */ - /*EMPTY*/; - } else if (s == NULL || strcmp(s, "/dev/null") == 0) { - (void) strcpy(current_admin.logfile, "/dev/null"); - (void) close(logfd); - logfd = -1; - } else { - /* - * In order to open this file securely, we'll try a few tricks - */ - - if ((newlogfd = open(s, O_EXCL|O_WRONLY|O_CREAT, 0644)) < 0) { - /* - * File already exists... now we need to get cute - * since opening a file in a world-writeable directory - * safely is hard = it could be a hard link or a - * symbolic link to a system file. - */ - struct stat before; - - if (lstat(s, &before) < 0) { - logit("Cannot open new logfile \"%s\": %sn", - s, strerror(errno)); - return (-1); - } - - if (S_ISREG(before.st_mode) && /* no symbolic links */ - (before.st_nlink == 1) && /* no hard links */ - (before.st_uid == 0)) { /* owned by root */ - if ((newlogfd = - open(s, O_APPEND|O_WRONLY, 0644)) < 0) { - logit("Cannot open new "\ - "logfile \"%s\": %s\n", s, - strerror(errno)); - return (-1); - } - } else { - logit("Cannot use specified logfile \"%s\": "\ - "file is/has links or isn't owned by "\ - "root\n", s); - return (-1); - } - } - - (void) strlcpy(ptr->logfile, s, 128); - (void) close(logfd); - logfd = newlogfd; - logit("Start of new logfile %s\n", s); - } - return (0); -} - -void -logit(char *format, ...) -{ - static mutex_t loglock; - struct timeval tv; - -#define LOGBUFLEN 1024 - char buffer[LOGBUFLEN]; - - va_list ap; - va_start(ap, format); - - if (logfd >= 0) { - int safechars, offset; - if (gettimeofday(&tv, NULL) != 0 || - ctime_r(&tv.tv_sec, buffer, LOGBUFLEN) == NULL) { - (void) snprintf(buffer, LOGBUFLEN, - "<time conversion failed>\t"); - } else { - /* - * ctime_r() includes some stuff we don't want; - * adjust length to overwrite " YYYY\n". - */ - offset = strlen(buffer) - 6; - safechars = LOGBUFLEN - (offset - 1); - (void) snprintf(buffer + offset, safechars, ".%.4ld\t", - tv.tv_usec/100); - } - offset = strlen(buffer); - safechars = LOGBUFLEN - (offset - 1); - if (vsnprintf(buffer + offset, safechars, format, ap) > - safechars) { - (void) strncat(buffer, "...\n", LOGBUFLEN); - } - - (void) mutex_lock(&loglock); - (void) write(logfd, buffer, strlen(buffer)); - (void) mutex_unlock(&loglock); - } - - va_end(ap); -#undef LOGBUFLEN } -static void -do_update(nsc_call_t *in) -{ - union { - nsc_data_t data; - char space[8192]; - } u; - - time_t now = time(NULL); - - switch (MASKUPDATEBIT(in->nsc_callnumber)) { - - case GETPWUID: - case GETPWNAM: - getpw_lookup(&u.data.nsc_ret, sizeof (u), in, now); - break; - - case GETGRNAM: - case GETGRGID: - getgr_lookup(&u.data.nsc_ret, sizeof (u), in, now); - break; - - case GETHOSTBYNAME: - case GETHOSTBYADDR: - gethost_lookup(&u.data.nsc_ret, sizeof (u), in, now); - break; - - case GETIPNODEBYNAME: - case GETIPNODEBYADDR: - getnode_lookup(&u.data.nsc_ret, sizeof (u), in, now); - break; - - case GETEXECID: - getexec_lookup(&u.data.nsc_ret, sizeof (u), in, now); - break; - - case GETPROFNAM: - getprof_lookup(&u.data.nsc_ret, sizeof (u), in, now); - break; - - case GETUSERNAM: - getuser_lookup(&u.data.nsc_ret, sizeof (u), in, now); - break; - - default: - assert(0); - break; - } - - free(in); -} - -int -launch_update(nsc_call_t *in) -{ - nsc_call_t *c; - - int l = nsc_calllen(in); - - in->nsc_callnumber |= UPDATEBIT; - - if ((c = malloc(l)) == NULL) { - logit("thread create failed: %s\n", strerror(errno)); - exit(1); - } - (void) memcpy(c, in, l); - - if (current_admin.debug_level >= DBG_ALL) { - logit("launching update\n"); - } - - if (thr_create(NULL, - NULL, - (void *(*)(void*))do_update, - c, - 0|THR_DETACHED, NULL) != 0) { - logit("thread create failed\n"); - exit(1); - } - - return (0); -} - -static int -nsc_calllen(nsc_call_t *in) -{ - switch (MASKUPDATEBIT(in->nsc_callnumber)) { - - case GETPWUID: - case GETGRGID: - case NULLCALL: - return (sizeof (*in)); - - case GETPWNAM: - case GETGRNAM: - case GETHOSTBYNAME: - return (sizeof (*in) + strlen(in->nsc_u.name)); - case GETIPNODEBYNAME: - return (sizeof (*in) + strlen(in->nsc_u.ipnode.name)); - - case GETHOSTBYADDR: - case GETIPNODEBYADDR: - return (sizeof (*in) + in->nsc_u.addr.a_length); - - case GETEXECID: - case GETPROFNAM: - case GETUSERNAM: - - return (sizeof (*in) + strlen(in->nsc_u.name)); - } - - return (0); -} - -static int -client_getadmin(admin_t *ptr) -{ - union { - nsc_data_t data; - char space[8192]; - } u; - - nsc_data_t *dptr; - int ndata; - int adata; - - u.data.nsc_call.nsc_callnumber = GETADMIN; - ndata = sizeof (u); - adata = sizeof (u.data); - dptr = &u.data; - - if (_nsc_trydoorcall(&dptr, &ndata, &adata) != SUCCESS) { - return (-1); - } - - (void) memcpy(ptr, dptr->nsc_ret.nsc_u.buff, sizeof (*ptr)); - return (0); -} - -/*ARGSUSED*/ -static void -getadmin(nsc_return_t *out, int size, nsc_call_t *ptr) -{ - out->nsc_return_code = SUCCESS; - out->nsc_bufferbytesused = sizeof (current_admin); - (void) memcpy(out->nsc_u.buff, ¤t_admin, sizeof (current_admin)); -} - - -static int -nscd_set_rbac(admin_t *new_admin, int invalidate) -{ - int i; - char *dbname = NULL; - nsc_stat_t *cache = NULL; - nsc_stat_t *new = NULL; - void (*invalidate_func)(void); - - - for (i = 1; i <= 3; i++) { - /* - * Three of the RBAC databases are cached. - */ - switch (i) { - case 1: - dbname = NSS_DBNAM_EXECATTR; - cache = ¤t_admin.exec; - new = &new_admin->exec; - invalidate_func = getexec_invalidate; - break; - case 2: - dbname = NSS_DBNAM_PROFATTR; - cache = ¤t_admin.prof; - new = &new_admin->prof; - invalidate_func = getprof_invalidate; - break; - case 3: - dbname = NSS_DBNAM_USERATTR; - cache = ¤t_admin.user; - new = &new_admin->user; - invalidate_func = getuser_invalidate; - break; - default: - break; - } - - if (invalidate) { - if (new->nsc_invalidate) { - logit("Invalidating %s cache\n", dbname); - (*invalidate_func)(); - } - } else { - if (nscd_set_ttl_positive(cache, dbname, - new->nsc_pos_ttl) < 0 || - nscd_set_ttl_negative(cache, dbname, - new->nsc_neg_ttl) < 0 || - nscd_set_khc(cache, dbname, new->nsc_keephot) < 0 || - nscd_set_odo(cache, dbname, - new->nsc_old_data_ok) < 0 || - nscd_set_ec(cache, dbname, new->nsc_enabled) < 0 || - nscd_set_ss(cache, dbname, - new->nsc_suggestedsize) < 0) - return (-1); - } - } - - return (0); -} - -/*ARGSUSED*/ -static int -setadmin(nsc_return_t *out, int size, nsc_call_t *ptr) -{ - admin_t *new; - - out->nsc_return_code = SUCCESS; - out->nsc_bufferbytesused = sizeof (nsc_return_t); - - new = (admin_t *)ptr->nsc_u.name; - - - /* - * global admin stuff - */ - - if ((nscd_set_lf(¤t_admin, new->logfile) < 0) || - nscd_set_dl(¤t_admin, new->debug_level) < 0) { - out->nsc_return_code = NOTFOUND; - return (-1); - } - - /* - * per cache items - */ - - if (new->passwd.nsc_invalidate) { - logit("Invalidating passwd cache\n"); - getpw_invalidate(); - } - - if (new->group.nsc_invalidate) { - logit("Invalidating group cache\n"); - getgr_invalidate(); - } - - if (new->host.nsc_invalidate) { - logit("Invalidating host cache\n"); - gethost_invalidate(); - } - - if (new->node.nsc_invalidate) { - logit("Invalidating ipnodes cache\n"); - getnode_invalidate(); - } - - (void) nscd_set_rbac(new, 1); /* invalidate rbac cache */ - - if (nscd_set_ttl_positive(¤t_admin.passwd, - "passwd", - new->passwd.nsc_pos_ttl) < 0 || - nscd_set_ttl_negative(¤t_admin.passwd, - "passwd", - new->passwd.nsc_neg_ttl) < 0 || - nscd_set_khc(¤t_admin.passwd, - "passwd", - new->passwd.nsc_keephot) < 0 || - nscd_set_odo(¤t_admin.passwd, - "passwd", - new->passwd.nsc_old_data_ok) < 0 || - nscd_set_ec(¤t_admin.passwd, - "passwd", - new->passwd.nsc_enabled) < 0 || - nscd_set_ss(¤t_admin.passwd, - "passwd", - new->passwd.nsc_suggestedsize) < 0 || - - nscd_set_ttl_positive(¤t_admin.group, - "group", - new->group.nsc_pos_ttl) < 0 || - nscd_set_ttl_negative(¤t_admin.group, - "group", - new->group.nsc_neg_ttl) < 0 || - nscd_set_khc(¤t_admin.group, - "group", - new->group.nsc_keephot) < 0 || - nscd_set_odo(¤t_admin.group, - "group", - new->group.nsc_old_data_ok) < 0 || - nscd_set_ec(¤t_admin.group, - "group", - new->group.nsc_enabled) < 0 || - nscd_set_ss(¤t_admin.group, - "group", - new->group.nsc_suggestedsize) < 0 || - - nscd_set_ttl_positive(¤t_admin.node, - "ipnodes", - new->node.nsc_pos_ttl) < 0 || - nscd_set_ttl_negative(¤t_admin.node, - "ipnodes", - new->node.nsc_neg_ttl) < 0 || - nscd_set_khc(¤t_admin.node, - "ipnodes", - new->node.nsc_keephot) < 0 || - nscd_set_odo(¤t_admin.node, - "ipnodes", - new->node.nsc_old_data_ok) < 0 || - nscd_set_ec(¤t_admin.node, - "ipnodes", - new->node.nsc_enabled) < 0 || - nscd_set_ss(¤t_admin.node, - "ipnodes", - new->node.nsc_suggestedsize) < 0 || - - nscd_set_ttl_positive(¤t_admin.host, - "hosts", - new->host.nsc_pos_ttl) < 0 || - nscd_set_ttl_negative(¤t_admin.host, - "hosts", - new->host.nsc_neg_ttl) < 0 || - nscd_set_khc(¤t_admin.host, - "hosts", - new->host.nsc_keephot) < 0 || - nscd_set_odo(¤t_admin.host, - "hosts", - new->host.nsc_old_data_ok) < 0 || - nscd_set_ec(¤t_admin.host, - "hosts", - new->host.nsc_enabled) < 0 || - nscd_set_ss(¤t_admin.host, - "hosts", - new->host.nsc_suggestedsize) < 0 || - nscd_set_rbac(new, 0) < 0) { - out->nsc_return_code = NOTFOUND; - return (-1); - } - out->nsc_return_code = SUCCESS; - return (0); -} - -void -client_killserver(void) -{ - union { - nsc_data_t data; - char space[8192]; - } u; - - nsc_data_t *dptr; - int ndata; - int adata; - - u.data.nsc_call.nsc_callnumber = KILLSERVER; - - ndata = sizeof (u); - adata = sizeof (nsc_call_t); - - dptr = &u.data; - - _nsc_trydoorcall(&dptr, &ndata, &adata); -} - - -static int -client_setadmin(admin_t *ptr) -{ - union { - nsc_data_t data; - char space[8192]; - } u; - - nsc_data_t *dptr; - int ndata; - int adata; - - u.data.nsc_call.nsc_callnumber = SETADMIN; - - (void) memcpy(u.data.nsc_call.nsc_u.name, ptr, sizeof (*ptr)); - - ndata = sizeof (u); - adata = sizeof (*ptr); - - dptr = &u.data; - - if (_nsc_trydoorcall(&dptr, &ndata, &adata) != SUCCESS) { - return (-1); - } - - return (0); -} - -static void -dump_stat(nsc_stat_t *ptr) -{ - double hitrate; - (void) printf("%10s cache is enabled\n", - (ptr->nsc_enabled?"Yes":"No")); - (void) printf("%10d cache hits on positive entries\n", - ptr->nsc_pos_cache_hits); - (void) printf("%10d cache hits on negative entries\n", - ptr->nsc_neg_cache_hits); - (void) printf("%10d cache misses on positive entries\n", - ptr->nsc_pos_cache_misses); - (void) printf("%10d cache misses on negative entries\n", - ptr->nsc_neg_cache_misses); - hitrate = ptr->nsc_pos_cache_misses + ptr->nsc_neg_cache_misses + - ptr->nsc_pos_cache_hits + ptr->nsc_neg_cache_hits; - - if (hitrate > 0.0) - hitrate = (100.0 * ((double)ptr->nsc_pos_cache_hits + - (double)ptr->nsc_neg_cache_hits))/hitrate; - - (void) printf("%10.1f%% cache hit rate\n", hitrate); - (void) printf("%10d queries deferred\n", ptr->nsc_throttle_count); - (void) printf("%10d total entries\n", ptr->nsc_entries); - (void) printf("%10d complete cache invalidations\n", - ptr->nsc_invalidate_count); - (void) printf("%10d suggested size\n", ptr->nsc_suggestedsize); - (void) printf("%10d seconds time to live for positive entries\n", - ptr->nsc_pos_ttl); - (void) printf("%10d seconds time to live for negative entries\n", - ptr->nsc_neg_ttl); - (void) printf("%10d most active entries to be kept valid\n", - ptr->nsc_keephot); - (void) printf("%10s check /etc/{passwd, group, hosts, inet/ipnodes} " - "file for changes\n", - (ptr->nsc_check_files?"Yes":"No")); - - (void) printf("%10s use possibly stale data rather than waiting for " - "refresh\n", - (ptr->nsc_old_data_ok?"Yes":"No")); -} - -static void -client_showstats(admin_t *ptr) -{ - - (void) printf("nscd configuration:\n\n"); - (void) printf("%10d server debug level\n", ptr->debug_level); - (void) printf("\"%s\" is server log file\n", ptr->logfile); - - (void) printf("\npasswd cache:\n\n"); - dump_stat(&(ptr->passwd)); - (void) printf("\ngroup cache:\n\n"); - dump_stat(&(ptr->group)); - (void) printf("\nhosts cache:\n\n"); - dump_stat(&(ptr->host)); - (void) printf("\nipnodes cache:\n\n"); - dump_stat(&(ptr->node)); - (void) printf("\nexec_attr cache:\n\n"); - dump_stat(&(ptr->exec)); - (void) printf("\nprof_attr cache:\n\n"); - dump_stat(&(ptr->prof)); - (void) printf("\nuser_attr cache:\n\n"); - dump_stat(&(ptr->user)); -} - - - /* * detach from tty */ static void detachfromtty(void) { - if (logfd > 0) { + nscd_rc_t rc; + char *me = "detachfromtty"; + + if (_logfd > 0) { int i; - for (i = 0; i < logfd; i++) + for (i = 0; i < _logfd; i++) (void) close(i); - closefrom(logfd+1); + closefrom(_logfd + 1); } else closefrom(0); @@ -1899,9 +516,16 @@ detachfromtty(void) switch (fork1()) { case (pid_t)-1: + + _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR) + (me, "unable to fork: pid = %d, %s\n", + getpid(), strerror(errno)); + exit(1); break; case 0: + /* start the forker nscd if so configured */ + _nscd_start_forker(saved_execname, saved_argc, saved_argv); break; default: exit(0); @@ -1909,5 +533,17 @@ detachfromtty(void) (void) setsid(); (void) open("/dev/null", O_RDWR, 0); (void) dup(0); - (void) dup(0); + if (_logfd != 2) + (void) dup(0); + + /* + * start monitoring the states of the name service clients + */ + rc = _nscd_init_smf_monitor(); + if (rc != NSCD_SUCCESS) { + _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR) + (me, "unable to start the SMF monitor (rc = %d)\n", rc); + + exit(-1); + } } diff --git a/usr/src/cmd/nscd/svc-nscd b/usr/src/cmd/nscd/svc-nscd index a611923be4..08a856ee66 100644 --- a/usr/src/cmd/nscd/svc-nscd +++ b/usr/src/cmd/nscd/svc-nscd @@ -20,6 +20,7 @@ # # CDDL HEADER END # +# # Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # @@ -56,14 +57,7 @@ if (smf_is_system_labeled); then fi if [ -f /etc/nscd.conf -a -f /usr/sbin/nscd ]; then - secure="" - - if egrep -s "^(passwd|passwd_compat):.*nisplus" /etc/nsswitch.conf - then - /usr/lib/nscd_nischeck passwd || secure=" -S passwd,yes" - fi - - /usr/sbin/nscd$secure < /dev/null > /dev/msglog 2>&1 & + /usr/sbin/nscd < /dev/null > /dev/msglog 2>&1 & else echo "No /etc/nscd.conf or no /usr/sbin/nscd" exit $SMF_EXIT_ERR_CONFIG diff --git a/usr/src/cmd/rpcsvc/nis/utils/nisaddent.c b/usr/src/cmd/rpcsvc/nis/utils/nisaddent.c index 4e92c45d05..6c9c95ee1a 100644 --- a/usr/src/cmd/rpcsvc/nis/utils/nisaddent.c +++ b/usr/src/cmd/rpcsvc/nis/utils/nisaddent.c @@ -1396,7 +1396,7 @@ genent_hosts6(line, cback, udata) eobj.EN_data.en_cols.en_cols_val = ecol; eobj.EN_data.en_cols.en_cols_len = 4; - if (cback != NULL) + if (cback == NULL) cback = addentry; /* diff --git a/usr/src/head/nss_common.h b/usr/src/head/nss_common.h index 5582bacd48..d2fa459d39 100644 --- a/usr/src/head/nss_common.h +++ b/usr/src/head/nss_common.h @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,8 +19,8 @@ * CDDL HEADER END */ /* - * Copyright (c) 1992-1999 by Sun Microsystems, Inc. - * All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. */ /* @@ -49,9 +48,9 @@ extern "C" { * * From nsswitch.conf(4): * - * The operating system uses a number of ``databases'' of information + * The operating system uses a number of "databases" of information * about hosts, users (passwd/shadow), groups and so forth. Data for - * these can come from a variety of ``sources'': host-names and + * these can come from a variety of "sources": host-names and * -addresses, for example, may be found in /etc/hosts, NIS, NIS+ or * DNS. One or more sources may be used for each database; the * sources and their lookup order are specified in the @@ -59,16 +58,20 @@ extern "C" { * * The implementation of this consists of: * - * - a ``frontend'' for each database, which provides a programming + * - a "frontend" for each database, which provides a programming * interface for that database [for example, the "passwd" frontend * consists of getpwnam_r(), getpwuid_r(), getpwent_r(), setpwent(), * endpwent(), and the old MT-unsafe routines getpwnam() and getpwuid()] * and is implemented by calls to... * - * - the common core of the switch (``switch engine''); it determines - * which sources to use and invokes... + * - the common core of the switch (called the "switch" or "policy" engine); + * that determines what sources to use and when to invoke them. This + * component works in conjunction with the name service switch (nscd). + * Usually nscd is the policy engine for an application lookup. * - * - A ``backend'' for each useful <database, source> pair. Each backend + * - Old style backend interfaces follow this pointer to function interface: + * + * A "backend" exists for useful <database, source> pairs. Each backend * consists of whatever private data it needs and a set of functions * that the switch engine may invoke on behalf of the frontend * [e.g. the "nis" backend for "passwd" provides routines to lookup @@ -78,13 +81,15 @@ extern "C" { * all its backends. The switch engine knows as little as possible * about these interfaces. * - * (The term ``backend'' is used ambiguously; it may also refer to a + * (The term "backend" is used ambiguously; it may also refer to a * particular instantiation of a backend, or to the set of all backends * for a particular source, e.g. "the nis backend"). * * This header file defines the interface between the switch engine and the * frontends and backends. Interfaces between specific frontends and * backends are defined elsewhere; many are in <nss_dbdefs.h>. + * Most of these definitions are in the form of pointer to function + * indicies used to call specific backend APIs. * * * Switch-engine outline @@ -102,24 +107,29 @@ extern "C" { * * (1) getpwnam_r fills in (getpwnam-specific) argument/result struct, * calls nss_search(), - * (2) nss_search looks up configuration info, gets "passwd: files nis", - * (3) nss_search decides to try first source ("files"), + * (2) nss_search queries the name service cache for an existing + * result via a call to _nsc_search(). if the cache + * (nscd) has a definitive answer skip to step 7 + * (3) nss_search looks up configuration info, gets "passwd: files nis", + * (4) nss_search decides to try first source ("files"), * (a) nss_search locates code for <"passwd", "files"> backend, * (b) nss_search creates instance of backend, * (c) nss_search calls get-by-name routine in backend, + * through a function pointer interface, * (d) backend searches /etc/passwd, doesn't find the name, * returns "not found" status to nss_search, - * (4) nss_search examines status and config info, decides to try + * (5) nss_search examines status and config info, decides to try * next source ("nis"), * (a) nss_search locates code for <"passwd", "nis"> backend, * (b) nss_search creates instance of backend, * (c) nss_search calls get-by-name routine in backend, + * through a function pointer interface, * (d) backend searches passwd.byname, finds the desired entry, * fills in the result part of the getpwnam-specific * struct, returns "success" status to nss_search, - * (5) nss_search examines status and config info, decides to return + * (6) nss_search examines status and config info, decides to return * to caller, - * (6) getpwnam_r extracts result from getpwnam-specific struct, + * (7) getpwnam_r extracts result from getpwnam-specific struct, * returns to caller. * * @@ -167,7 +177,6 @@ extern "C" { * give per-invocation state. */ - /* * Backend instances * ----------------- @@ -191,19 +200,50 @@ extern "C" { * structure (the contents are opaque to the switch engine). * The four well-known functions ignore the (void *) pointer. * - * Backend routines return one of five status codes to the switch engine: + * Backend routines return the following status codes to the switch engine: + * * SUCCESS, UNAVAIL, NOTFOUND, TRYAGAIN (these are the same codes that may - * be specified in the config information; see nsswitch.conf(4)), or + * be specified in the config information; see nsswitch.conf(4)) + * + * The remaining conditions/errors are internally generated and if + * necessary are translated, as to one of the above external errors, + * usually NOTFOUND or UNAVAIL. + * * NSS_NISSERVDNS_TRYAGAIN (should only be used by the NIS backend for * NIS server in DNS forwarding mode to indicate DNS server non-response). + * + * The policy component may return NSS_TRYLOCAL which signifies that nscd + * is not going to process the request, and it should be performed locally. + * + * NSS_ERROR is a catchall for internal error conditions, errno will be set + * to a system <errno.h> error that can help track down the problem if + * it is persistent. This error is the result of some internal error + * condition and should not be seen during or exposed to aan application. + * The error may be from the application side switch component or from the + * nscd side switch component. + * + * NSS_ALTRETRY and NSS_ALTRESET are internal codes used by the application + * side policy component and nscd to direct the policy component to + * communicate to a per-user nscd if/when per-user authentication is enabled. + * + * NSS_NSCD_PRIV is a catchall for internal nscd errors or status + * conditions. This return code is not visible to applications. nscd + * may use this as a status flag and maintain additional error or status + * information elsewhere in other private nscd data. This status value + * is for nscd private/internal use only. */ typedef enum { - NSS_SUCCESS, - NSS_NOTFOUND, - NSS_UNAVAIL, - NSS_TRYAGAIN, - NSS_NISSERVDNS_TRYAGAIN + NSS_SUCCESS = 0, + NSS_NOTFOUND = 1, + NSS_UNAVAIL = 2, + NSS_TRYAGAIN = 3, + NSS_NISSERVDNS_TRYAGAIN = 4, + NSS_TRYLOCAL = 5, + NSS_ERROR = 6, + NSS_ALTRETRY = 7, + NSS_ALTRESET = 8, + NSS_NSCD_PRIV = 9 } nss_status_t; struct nss_backend; @@ -256,11 +296,11 @@ typedef int nss_dbop_t; */ #if defined(__STDC__) -typedef nss_backend_t * (*nss_backend_constr_t)(const char *db_name, +typedef nss_backend_t *(*nss_backend_constr_t)(const char *db_name, const char *src_name, /* Hook for (unimplemented) args in nsswitch.conf */ const char *cfg_args); #else -typedef nss_backend_t * (*nss_backend_constr_t)(); +typedef nss_backend_t *(*nss_backend_constr_t)(); #endif struct nss_backend_finder { @@ -342,6 +382,20 @@ typedef void (*nss_db_initf_t)(); #endif /* + * DBD param offsets in NSS2 nscd header. + * Offsets are relative to beginning of dbd section. + * 32 bit offsets should be sufficient, forever. + * 0 offset == NULL + * flags == nss_dbp_flags + */ +typedef struct nss_dbd { + uint32_t o_name; + uint32_t o_config_name; + uint32_t o_default_config; + uint32_t flags; +} nss_dbd_t; + +/* * These structures are defined inside the implementation of the switch * engine; the interface just holds pointers to them. */ @@ -369,22 +423,81 @@ typedef struct { #define NSS_GETENT_INIT { 0, DEFAULTMUTEX } #define DEFINE_NSS_GETENT(name) nss_getent_t name = NSS_GETENT_INIT +/* + * Policy Engine Configuration + * --------------------------- + * + * When nscd is running it can reconfigure it's internal policy engine + * as well as advise an application's front-end and policy engine on how + * respond optimally to results being returned from nscd. This is done + * through the policy engine configuration interface. + */ + +typedef enum { + NSS_CONFIG_GET, + NSS_CONFIG_PUT, + NSS_CONFIG_ADD, + NSS_CONFIG_DELETE, + NSS_CONFIG_LIST +} nss_config_op_t; + +struct nss_config { + char *name; + nss_config_op_t cop; + mutex_t *lock; + void *buffer; + size_t length; +}; +typedef struct nss_config nss_config_t; + + #if defined(__STDC__) +extern nss_status_t nss_config(nss_config_t **, int); + extern nss_status_t nss_search(nss_db_root_t *, nss_db_initf_t, int search_fnum, void *search_args); extern nss_status_t nss_getent(nss_db_root_t *, nss_db_initf_t, nss_getent_t *, void *getent_args); extern void nss_setent(nss_db_root_t *, nss_db_initf_t, nss_getent_t *); - extern void nss_endent(nss_db_root_t *, nss_db_initf_t, nss_getent_t *); - /* ^^ superfluous but consistent */ extern void nss_delete(nss_db_root_t *); + +extern nss_status_t nss_pack(void *, size_t, nss_db_root_t *, + nss_db_initf_t, int, void *); +extern nss_status_t nss_pack_ent(void *, size_t, nss_db_root_t *, + nss_db_initf_t, nss_getent_t *); +extern nss_status_t nss_unpack(void *, size_t, nss_db_root_t *, + nss_db_initf_t, int, void *); +extern nss_status_t nss_unpack_ent(void *, size_t, nss_db_root_t *, + nss_db_initf_t, nss_getent_t *, void *); + +extern nss_status_t _nsc_search(nss_db_root_t *, nss_db_initf_t, + int search_fnum, void *search_args); +extern nss_status_t _nsc_getent_u(nss_db_root_t *, nss_db_initf_t, + nss_getent_t *, void *getent_args); +extern nss_status_t _nsc_setent_u(nss_db_root_t *, nss_db_initf_t, + nss_getent_t *); +extern nss_status_t _nsc_endent_u(nss_db_root_t *, nss_db_initf_t, + nss_getent_t *); + #else +extern nss_status_t nss_config(); + extern nss_status_t nss_search(); extern nss_status_t nss_getent(); extern void nss_setent(); extern void nss_endent(); extern void nss_delete(); + +extern int nss_pack(); +extern int nss_pack_ent(); +extern int nss_unpack(); +extern int nss_unpack_ent(); + +extern nss_status_t _nsc_search(); +extern nss_status_t _nsc_getent_u(); +extern nss_status_t _nsc_setent_u(); +extern nss_status_t _nsc_endent_u(); #endif #ifdef __cplusplus diff --git a/usr/src/head/nss_dbdefs.h b/usr/src/head/nss_dbdefs.h index dc37584a46..fa4dd6525e 100644 --- a/usr/src/head/nss_dbdefs.h +++ b/usr/src/head/nss_dbdefs.h @@ -40,6 +40,8 @@ #pragma ident "%Z%%M% %I% %E% SMI" +#include <sys/types.h> +#include <unistd.h> #include <errno.h> #include <netdb.h> /* MAXALIASES, MAXADDRS */ #include <limits.h> /* LOGNAME_MAX */ @@ -209,12 +211,17 @@ extern "C" { #define NSS_BUFLEN_USERATTR ((NSS_BUFLEN_ATTRDB) * 8) #define NSS_BUFLEN_TSOL NSS_LINELEN_TSOL - #define NSS_BUFLEN_TSOL_TP NSS_BUFLEN_TSOL #define NSS_BUFLEN_TSOL_RH NSS_BUFLEN_TSOL #define NSS_BUFLEN_TSOL_ZC NSS_BUFLEN_TSOL /* + * Default cache door buffer size (2x largest buffer) + */ + +#define NSS_BUFLEN_DOOR ((NSS_BUFSIZ) * 16) + +/* * Arguments and results, passed between the frontends and backends for * the well-known databases. The getXbyY_r() and getXent_r() routines * use a common format that is further described below; other routines @@ -222,6 +229,26 @@ extern "C" { */ /* + * The nss_str2ent_t routine is the data marshaller for the nsswitch. + * it converts 'native files' format into 'entry' format as part of the + * return processing for a getXbyY interface. + * + * The nss_groupstr_t routine does the real work for any backend + * that can supply a netgroup entry as a string in /etc/group format + */ +#if defined(__STDC__) +typedef int (*nss_str2ent_t)(const char *in, int inlen, + void *ent, char *buf, int buflen); + +struct nss_groupsbymem; /* forward definition */ +typedef nss_status_t (*nss_groupstr_t)(const char *instr, int inlen, + struct nss_groupsbymem *); +#else +typedef int (*nss_str2ent_t)(); +typedef nss_status_t (*nss_groupstr_t)(); +#endif + +/* * The initgroups() function [see initgroups(3c)] needs to find all the * groups to which a given user belongs. To do this it calls * _getgroupsbymember(), which is part of the frontend for the "group" @@ -248,21 +275,8 @@ struct nss_groupsbymem { /* For _getgroupsbymember() */ gid_t *gid_array; int maxgids; int force_slow_way; - /* - * The process_cstr() routine does the real work for any backend - * that can supply a group entry as a string in /etc/group format - */ -#if defined(__STDC__) - int (*str2ent) (const char *instr, - int instr_len, - void *ent, char *buffer, int buflen); - nss_status_t (*process_cstr) (const char *instr, - int instr_len, - struct nss_groupsbymem *); -#else - int (*str2ent)(); - nss_status_t (*process_cstr)(); -#endif + nss_str2ent_t str2ent; + nss_groupstr_t process_cstr; /* in_out: */ int numgids; @@ -305,16 +319,16 @@ struct nss_groupsbymem { /* For _getgroupsbymember() */ */ enum nss_netgr_argn { /* We need (machine, user, domain) triples */ - NSS_NETGR_MACHINE, - NSS_NETGR_USER, - NSS_NETGR_DOMAIN, - NSS_NETGR_N + NSS_NETGR_MACHINE = 0, + NSS_NETGR_USER = 1, + NSS_NETGR_DOMAIN = 2, + NSS_NETGR_N = 3 }; enum nss_netgr_status { /* Status from setnetgrent, multi_innetgr */ - NSS_NETGR_FOUND, - NSS_NETGR_NO, - NSS_NETGR_NOMEM + NSS_NETGR_FOUND = 0, + NSS_NETGR_NO = 1, + NSS_NETGR_NOMEM = 2 }; struct nss_setnetgrent_args { @@ -349,7 +363,6 @@ struct nss_innetgr_args { enum nss_netgr_status status; }; - /* * nss_XbyY_buf_t -- structure containing the generic arguments passwd to * getXXXbyYYY_r() and getXXXent_r() routines. The (void *) value points to @@ -376,7 +389,7 @@ extern void _nss_XbyY_buf_free(); #define NSS_XbyY_ALLOC(bufpp, str_size, buf_size) (\ (*bufpp) == 0 \ ? (*bufpp) = _nss_XbyY_buf_alloc(str_size, buf_size) \ - : (*bufpp)) \ + : (*bufpp)) #define NSS_XbyY_FREE(bufpp) (_nss_XbyY_buf_free(*bufpp), (*bufpp) = 0) @@ -406,7 +419,7 @@ extern void _nss_XbyY_buf_free(); * in parsing and marshalling these into the buffer. */ -union nss_XbyY_key { /* No tag; backend should know what to expect */ +typedef union nss_XbyY_key { /* No tag; backend should know what to expect */ uid_t uid; gid_t gid; projid_t projid; @@ -439,7 +452,16 @@ union nss_XbyY_key { /* No tag; backend should know what to expect */ int flags; } ipnode; void *attrp; /* for the new attr databases */ -}; +} nss_XbyY_key_t; + + +#if defined(__STDC__) +typedef int (*nss_key2str_t)(void *buffer, size_t buflen, + nss_XbyY_key_t *key, size_t *len); +#else +typedef int (*nss_key2str_t)(); +#endif + typedef struct nss_XbyY_args { @@ -451,22 +473,187 @@ typedef struct nss_XbyY_args { * Used only in hosts, protocols, * networks, rpc, and services. */ -#if defined(__STDC__) - int (*str2ent) (const char *instr, - int instr_len, - void *ent, char *buffer, int buflen); -#else - int (*str2ent)(); -#endif + nss_str2ent_t str2ent; union nss_XbyY_key key; /* OUT */ void *returnval; int erange; - int h_errno; /* For gethost*_r() */ - nss_status_t status; /* from the backend last called */ + int h_errno; /* For gethost*_r() */ + nss_status_t status; /* from the backend last called */ +/* NSS2 */ + nss_key2str_t key2str; /* IN */ + size_t returnlen; /* OUT */ + +/* NSCD/DOOR data */ + +/* ... buffer arena follows... */ } nss_XbyY_args_t; + + +/* + * nss/nscd v2 interface, packed buffer format + * + * A key component of the v2 name service switch is the redirection + * of all activity to nscd for actual processing. In the original + * switch most activity took place in each application, and the nscd + * cache component was an add-on optional interface. + * + * The nscd v1 format was a completely private interface that + * implemented specific bufferiing formats on a per getXbyY API basis. + * + * The nss/nscd v2 interface uses a common header and commonalizes + * the buffering format as consistently as possible. The general rule + * of thumb is that backends are required to assemble their results in + * "files based" format [IE the format used on a per result basis as + * returned by the files backend] and then call the standard str2ent + * interface. This is the original intended design as used in the files + * and nis backends. + * + * The benefit of this is that the application side library can assemble + * a request and provide a header and a variable length result buffer via + * a doors API, and then the nscd side switch can assemble a a getXbyY + * request providing the result buffer and a str2ent function that copies + * but does not unpack the result. + * + * This results is returned back via the door, and unpacked using the + * native library side str2ent interface. + * + * Additionally, the common header allows extensibility to add new + * getXbyYs, putXbyYs or other maintenance APIs to/from nscd without + * changing the existing "old style" backend interfaces. + * + * Finally new style getXbyY, putXbyY and backend interfaces can be + * by adding new operation requests to the header, while old style + * backwards compatability. + */ + +/* + * nss/nscd v2 callnumber definitions + */ + +/* + * callnumbers are separated by categories, such as: + * application to nscd requests, nscd to nscd requests, + * smf to nscd requests, etc. + */ + +#define NSCDV2CATMASK (0xFF000000) +#define NSCDV2CALLMASK (0x00FFFFFF) + +/* + * nss/nscd v2 categories + */ + +#define NSCD_CALLCAT_APP ('a'<<24) +#define NSCD_CALLCAT_N2N ('n'<<24) + +/* nscd v2 app-> nscd callnumbers */ + +#define NSCD_SEARCH (NSCD_CALLCAT_APP|0x01) +#define NSCD_SETENT (NSCD_CALLCAT_APP|0x02) +#define NSCD_GETENT (NSCD_CALLCAT_APP|0x03) +#define NSCD_ENDENT (NSCD_CALLCAT_APP|0x04) +#define NSCD_PUT (NSCD_CALLCAT_APP|0x05) +#define NSCD_GETHINTS (NSCD_CALLCAT_APP|0x06) + +/* nscd v2 SETENT cookie markers */ + +#define NSCD_NEW_COOKIE 0 +#define NSCD_LOCAL_COOKIE 1 + +/* nscd v2 header revision */ +/* treated as 0xMMMMmmmm MMMM - Major Rev, mmmm - Minor Rev */ + +#define NSCD_HEADER_REV 0x00020000 + +/* + * ptr/uint data type used to calculate shared nscd buffer struct sizes + * sizes/offsets are arbitrarily limited to 32 bits for 32/64 compatibility + * datatype is 64 bits for possible pointer storage and future use + */ + +typedef uint64_t nssuint_t; + +/* + * nscd v2 buffer layout overview + * + * The key interface to nscd moving forward is the doors interface + * between applications and nscd (NSCD_CALLCAT_APP), and nscd and + * it's children (NSCD_CALLCAT_N2N). + * + * Regardless of the interface used, the buffer layout is consistent. + * The General Layout is: + * [nss_pheader_t][IN key][OUT data results]{extend results} + * + * The header (nss_pheader_t) remains constant. + * Keys and key layouts vary between call numbers/requests + * NSCD_CALLCAT_APP use key layouts mimics/defines in nss_dbdefs.h + * NSCD_CALLCAT_NSN use layouts defined by nscd headers + * Data and data results vary between results + * NSCD_CALLCAT_APP return "file standard format" output buffers + * NSCD_CALLCAT_NSN return data defined by nscd headers + * extended results are optional and vary + * + */ + +/* + * nss_pheader_t -- buffer header structure that contains switch data + * "packed" by the client into a buffer suitable for transport over + * nscd's door, and that can be unpacked into a native form within + * nscd's switch. Capable of packing and unpacking data ans results. + * + * NSCD_HEADER_REV: 0x00020000 16 x uint64 = (128 byte header) + */ + +typedef struct { + uint32_t nsc_callnumber; /* packed buffer request */ + uint32_t nss_dbop; /* old nss dbop */ + uint32_t p_ruid; /* real uid */ + uint32_t p_euid; /* effective uid */ + uint32_t p_version; /* 0xMMMMmmmm Major/minor */ + uint32_t p_status; /* nss_status_t */ + uint32_t p_errno; /* errno */ + uint32_t p_herrno; /* h_errno */ + nssuint_t libpriv; /* reserved (for lib/client) */ + nssuint_t pbufsiz; /* buffer size */ + nssuint_t dbd_off; /* IN: db desc off */ + nssuint_t dbd_len; /* IN: db desc len */ + nssuint_t key_off; /* IN: key off */ + nssuint_t key_len; /* IN: key len */ + nssuint_t data_off; /* OUT: data off */ + nssuint_t data_len; /* OUT: data len */ + nssuint_t ext_off; /* OUT: extended results off */ + nssuint_t ext_len; /* OUT: extended results len */ + nssuint_t nscdpriv; /* reserved (for nscd) */ + nssuint_t reserved1; /* reserved (TBD) */ +} nss_pheader_t; + +/* + * nss_pnetgr_t -- packed offset structure for holding keys used + * by innetgr (__multi_innetgr) key + * Key format is: + * nss_pnetgr_t + * (nssuint_t)[machine_argc] offsets to strings + * (nssuint_t)[user_argc] offsets to strings + * (nssuint_t)[domain_argc] offsets to strings + * (nssuint_t)[groups_argc] offsets to strings + * machine,user,domain,groups strings + */ + +typedef struct { + uint32_t machine_argc; + uint32_t user_argc; + uint32_t domain_argc; + uint32_t groups_argc; + nssuint_t machine_offv; + nssuint_t user_offv; + nssuint_t domain_offv; + nssuint_t groups_offv; +} nss_pnetgr_t; + + /* status returned by the str2ent parsing routines */ #define NSS_STR_PARSE_SUCCESS 0 #define NSS_STR_PARSE_PARSE 1 @@ -478,18 +665,51 @@ typedef struct nss_XbyY_args { (str)->buf.buflen = (len), \ (str)->stayopen = 0, \ (str)->str2ent = (func), \ + (str)->key2str = NULL, \ (str)->returnval = 0, \ + (str)->returnlen = 0, \ + (str)->erange = 0) + +#define NSS_XbyY_INIT_EXT(str, res, bufp, len, func, kfunc) (\ + (str)->buf.result = (res), \ + (str)->buf.buffer = (bufp), \ + (str)->buf.buflen = (len), \ + (str)->stayopen = 0, \ + (str)->str2ent = (func), \ + (str)->key2str = (kfunc), \ + (str)->returnval = 0, \ + (str)->returnlen = 0, \ (str)->erange = 0) #define NSS_XbyY_FINI(str) (\ (str)->returnval == 0 && (str)->erange && (errno = ERANGE), \ (str)->returnval) +#define NSS_PACKED_CRED_CHECK(buf, ruid, euid) (\ + ((nss_pheader_t *)(buf))->p_ruid == (ruid) && \ + ((nss_pheader_t *)(buf))->p_euid == (euid)) + #if defined(__STDC__) -extern char **_nss_netdb_aliases - (const char *, int, char *, int); +extern char **_nss_netdb_aliases(const char *, int, char *, int); +extern nss_status_t nss_default_key2str(void *, size_t, nss_XbyY_args_t *, + const char *, int, size_t *); +extern nss_status_t nss_packed_arg_init(void *, size_t, nss_db_root_t *, + nss_db_initf_t *, int *, + nss_XbyY_args_t *); +extern nss_status_t nss_packed_context_init(void *, size_t, nss_db_root_t *, + nss_db_initf_t *, nss_getent_t **, + nss_XbyY_args_t *); +extern void nss_packed_set_status(void *, size_t, nss_status_t, + nss_XbyY_args_t *); +extern nss_status_t nss_packed_getkey(void *, size_t, char **, int *, + nss_XbyY_args_t *); #else extern char **_nss_netdb_aliases(); +extern int nss_default_key2str(); +extern nss_status_t nss_packed_arg_init(); +extern nss_status_t nss_packed_context_init(); +extern void nss_packed_set_status(); +extern nss_status_t nss_packed_getkey(); #endif /* @@ -497,6 +717,39 @@ extern char **_nss_netdb_aliases(); * destructor/endent/setent/getent are defined in <nss_common.h> */ +/* + * These are part of the "Over the wire" IE app->nscd getXbyY + * op for well known getXbyY's. Cannot use NSS_DBOP_X_Y directly + * because NSS_DBOP_next_iter is NOT an incrementing counter value + * it's a starting offset into an array value. + */ + +#define NSS_DBOP_X(x) ((x)<<16) +#define NSS_DBOP_XY(x, y) ((x)|(y)) + +#define NSS_DBOP_ALIASES NSS_DBOP_X(1) +#define NSS_DBOP_AUTOMOUNT NSS_DBOP_X(2) +#define NSS_DBOP_BOOTPARAMS NSS_DBOP_X(3) +#define NSS_DBOP_ETHERS NSS_DBOP_X(4) +#define NSS_DBOP_GROUP NSS_DBOP_X(5) +#define NSS_DBOP_HOSTS NSS_DBOP_X(6) +#define NSS_DBOP_IPNODES NSS_DBOP_X(7) +#define NSS_DBOP_NETGROUP NSS_DBOP_X(8) +#define NSS_DBOP_NETMASKS NSS_DBOP_X(9) +#define NSS_DBOP_NETWORKS NSS_DBOP_X(10) +#define NSS_DBOP_PASSWD NSS_DBOP_X(11) +#define NSS_DBOP_PRINTERS NSS_DBOP_X(12) +#define NSS_DBOP_PROJECT NSS_DBOP_X(13) +#define NSS_DBOP_PROTOCOLS NSS_DBOP_X(14) +#define NSS_DBOP_PUBLICKEY NSS_DBOP_X(15) +#define NSS_DBOP_RPC NSS_DBOP_X(16) +#define NSS_DBOP_SERVICES NSS_DBOP_X(17) +#define NSS_DBOP_AUDITUSER NSS_DBOP_X(18) +#define NSS_DBOP_AUTHATTR NSS_DBOP_X(19) +#define NSS_DBOP_EXECATTR NSS_DBOP_X(20) +#define NSS_DBOP_PROFATTR NSS_DBOP_X(21) +#define NSS_DBOP_USERATTR NSS_DBOP_X(22) + #define NSS_DBOP_GROUP_BYNAME (NSS_DBOP_next_iter) #define NSS_DBOP_GROUP_BYGID (NSS_DBOP_GROUP_BYNAME + 1) #define NSS_DBOP_GROUP_BYMEMBER (NSS_DBOP_GROUP_BYGID + 1) diff --git a/usr/src/head/nss_netdir.h b/usr/src/head/nss_netdir.h index f84bc07657..6c8988eabf 100644 --- a/usr/src/head/nss_netdir.h +++ b/usr/src/head/nss_netdir.h @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 1993-94, 1999, 2003 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ diff --git a/usr/src/head/nsswitch.h b/usr/src/head/nsswitch.h index ecf4841cf9..f2657f135e 100644 --- a/usr/src/head/nsswitch.h +++ b/usr/src/head/nsswitch.h @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,8 +19,8 @@ * CDDL HEADER END */ /* - * Copyright (c) 1991-2000 by Sun Microsystems, Inc. - * All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. */ /* @@ -31,7 +30,6 @@ * in <nss_common.h> should be used in preference to this. * * This is a Project Private interface. It may change in future releases. - * ==== ^^^^^^^^^^^^^^^ ? */ #ifndef _NSSWITCH_H @@ -43,7 +41,9 @@ extern "C" { #endif +#ifndef __NSW_CONFIG_FILE #define __NSW_CONFIG_FILE "/etc/nsswitch.conf" +#endif #define __NSW_DEFAULT_FILE "/etc/default/nss" #define __NSW_HOSTS_DB "hosts" diff --git a/usr/src/lib/libc/inc/nsswitch_priv.h b/usr/src/lib/libc/inc/nsswitch_priv.h index 70baa39fb3..65e2dd176e 100644 --- a/usr/src/lib/libc/inc/nsswitch_priv.h +++ b/usr/src/lib/libc/inc/nsswitch_priv.h @@ -33,7 +33,6 @@ * and contains new versions of the switch low level interface. * * This is a Project Private interface. It may change in future releases. - * ==== ^^^^^^^^^^^^^^^ ? */ #ifndef _NSSWITCH_PRIV_H diff --git a/usr/src/lib/libc/inc/tsd.h b/usr/src/lib/libc/inc/tsd.h index 004dc82846..58042b983c 100644 --- a/usr/src/lib/libc/inc/tsd.h +++ b/usr/src/lib/libc/inc/tsd.h @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -29,6 +28,10 @@ #pragma ident "%Z%%M% %I% %E% SMI" +#ifdef __cplusplus +extern "C" { +#endif + typedef enum { _T_GETDATE = 0, _T_WCSTOK, @@ -55,6 +58,7 @@ typedef enum { _T_PWBUF, _T_GRBUF, _T_SPBUF, + _T_DOORBUF, _T_NUM_ENTRIES /* this *must* be the last member */ } __tsd_item_t; @@ -63,4 +67,8 @@ typedef enum { */ extern void *tsdalloc(__tsd_item_t, size_t, void (*)(void *)); +#ifdef __cplusplus +} +#endif + #endif /* _LIBC_INC_TSD_H */ diff --git a/usr/src/lib/libc/port/gen/getgrnam_r.c b/usr/src/lib/libc/port/gen/getgrnam_r.c index adaa8ce918..d1574b1985 100644 --- a/usr/src/lib/libc/port/gen/getgrnam_r.c +++ b/usr/src/lib/libc/port/gen/getgrnam_r.c @@ -48,8 +48,7 @@ #include <sys/mman.h> extern int _getgroupsbymember(const char *, gid_t[], int, int); -int str2group(const char *, int, void *, - char *, int); +int str2group(const char *, int, void *, char *, int); static DEFINE_NSS_DB_ROOT(db_root); static DEFINE_NSS_GETENT(context); @@ -66,10 +65,6 @@ _nss_initf_group(nss_db_params_t *p) #include <getxby_door.h> #include <sys/door.h> -static struct group * -process_getgr(struct group *result, char *buffer, int buflen, - nsc_data_t *sptr, int ndata); - struct group * _uncached_getgrnam_r(const char *name, struct group *result, char *buffer, int buflen); @@ -84,52 +79,17 @@ _uncached_getgrgid_r(gid_t gid, struct group *result, char *buffer, int buflen); struct group * _getgrnam_r(const char *name, struct group *result, char *buffer, int buflen) { - /* - * allocate room on the stack for the nscd to return - * group and group member information - */ - union { - nsc_data_t s_d; - char s_b[8192]; - } space; - nsc_data_t *sptr; - int ndata; - int adata; - struct group *resptr = NULL; - - if ((name == (const char *)NULL) || - (strlen(name) >= (sizeof (space) - sizeof (nsc_data_t)))) { - errno = ERANGE; - return (NULL); - } - - ndata = sizeof (space); - adata = strlen(name) + sizeof (nsc_call_t) + 1; - space.s_d.nsc_call.nsc_callnumber = GETGRNAM; - (void) strcpy(space.s_d.nsc_call.nsc_u.name, name); - sptr = &space.s_d; + nss_XbyY_args_t arg; - switch (_nsc_trydoorcall(&sptr, &ndata, &adata)) { - case SUCCESS: /* positive cache hit */ - break; - case NOTFOUND: /* negative cache hit */ + if (name == (const char *)NULL) { + errno = ERANGE; return (NULL); - default: - return ((struct group *)_uncached_getgrnam_r(name, result, - buffer, buflen)); } - - resptr = process_getgr(result, buffer, buflen, sptr, ndata); - - /* - * check to see if doors reallocated memory underneath us - * if they did munmap the memory or suffer a memory leak - */ - - if (sptr != &space.s_d) - munmap((void *)sptr, ndata); - - return (resptr); + NSS_XbyY_INIT(&arg, result, buffer, buflen, str2group); + arg.key.name = name; + (void) nss_search(&db_root, _nss_initf_group, + NSS_DBOP_GROUP_BYNAME, &arg); + return ((struct group *)NSS_XbyY_FINI(&arg)); } /* @@ -139,186 +99,13 @@ _getgrnam_r(const char *name, struct group *result, char *buffer, int buflen) struct group * _getgrgid_r(gid_t gid, struct group *result, char *buffer, int buflen) { - /* - * allocate room on the stack for the nscd to return - * group and group member information - */ - union { - nsc_data_t s_d; - char s_b[8192]; - } space; - nsc_data_t *sptr; - int ndata; - int adata; - struct group *resptr = NULL; - - ndata = sizeof (space); - adata = sizeof (nsc_call_t) + 1; - space.s_d.nsc_call.nsc_callnumber = GETGRGID; - space.s_d.nsc_call.nsc_u.gid = gid; - sptr = &space.s_d; - - switch (_nsc_trydoorcall(&sptr, &ndata, &adata)) { - case SUCCESS: /* positive cache hit */ - break; - case NOTFOUND: /* negative cache hit */ - return (NULL); - default: - return ((struct group *)_uncached_getgrgid_r(gid, result, - buffer, buflen)); - } - - resptr = process_getgr(result, buffer, buflen, sptr, ndata); - - /* - * check to see if doors reallocated memory underneath us - * if they did munmap the memory or suffer a memory leak - */ - - if (sptr != &space.s_d) - munmap((void *)sptr, ndata); - - return (resptr); -} -/* - * This routine should be rewritten - there's no reason it - * cannot be the same code for 32 and 64 bit w/ a bit of care. - */ -/* ARGSUSED4 */ -static struct group * -process_getgr(struct group *result, char *buffer, int buflen, - nsc_data_t *sptr, int ndata) -{ - int i; - char *fixed; -#ifdef _LP64 - char *buffer32; - char **gr_mem32; - uptr32_t index; - struct group group64; -#endif /* _LP64 */ - -/* align buffer on a pointer boundry 4bytes in 32bits and 8 bytes in 64bits */ -#ifdef _LP64 - fixed = (char *)(((uintptr_t)buffer + 7) & ~7); -#else - fixed = (char *)(((uintptr_t)buffer + 3) & ~3); -#endif /* _LP64 */ - - if (buflen <= fixed - buffer) { /* watch out for wrap-around */ - errno = ERANGE; - return (NULL); - } - - buflen -= fixed - buffer; - - buffer = fixed; - -#ifdef _LP64 - /* - * this is just a rationality check; we need to make - * sure that there's enough space for the gr_mem array - * as well... easiest place to do that is when we copy - * them in place. - */ - - if (sptr->nsc_ret.nsc_bufferbytesused + - /* - * ^^^ number of bytes from nscd - */ - (sizeof (char **)) + - /* - * ^^^ we need 8 bytes for gr_mem - */ - (sizeof (char *) - 1) - - /* - * ^^^ plus space for pssibly fixing aligment of gr_mem - */ - sizeof (group32_t) - /* - * ^^^ because we don't put this in the usr buffer - */ - > buflen) { -#else - if (sptr->nsc_ret.nsc_bufferbytesused - sizeof (struct group) - > buflen) { -#endif /* _LP64 */ - errno = ERANGE; - return (NULL); - } - - if (sptr->nsc_ret.nsc_return_code != SUCCESS) - return (NULL); - -/* - * ncsd is a 32bit application, so use 32bit data items if we are in 64bit mode - */ -#ifdef _LP64 - - (void) memcpy(buffer, - (sptr->nsc_ret.nsc_u.buff + sizeof (group32_t)), - (sptr->nsc_ret.nsc_bufferbytesused - sizeof (group32_t))); - - group64.gr_name = (char *)(sptr->nsc_ret.nsc_u.grp.gr_name + - (uintptr_t)buffer); - group64.gr_passwd = (char *)(sptr->nsc_ret.nsc_u.grp.gr_passwd + - (uintptr_t)buffer); - group64.gr_gid = sptr->nsc_ret.nsc_u.grp.gr_gid; - - group64.gr_mem = (char **)((uintptr_t)buffer + - sptr->nsc_ret.nsc_bufferbytesused - sizeof (group32_t)); - group64.gr_mem = (char **)(((uintptr_t)group64.gr_mem + 7) & ~7); - - gr_mem32 = (char **)(uintptr_t)sptr->nsc_ret.nsc_u.grp.gr_mem; - buffer32 = buffer; - - for (i = 0; ; i++) { - index = *((uptr32_t *) - ((uintptr_t)gr_mem32 + (uintptr_t)buffer32)); - - /* - * make sure there's enough space to copy the pointer... - */ - if (&group64.gr_mem[i + 1] > - (char **)((uintptr_t)buffer + buflen)) { - errno = ERANGE; - return (NULL); - } - - if (index == 0) - break; - - group64.gr_mem[i] = (char *)(index + buffer); - buffer32 += sizeof (uptr32_t); - - } - group64.gr_mem[i] = NULL; - - *result = group64; -#else - - (void) memcpy(buffer, - (sptr->nsc_ret.nsc_u.buff + sizeof (struct group)), - (sptr->nsc_ret.nsc_bufferbytesused - sizeof (struct group))); - - sptr->nsc_ret.nsc_u.grp.gr_name += (uintptr_t)buffer; - sptr->nsc_ret.nsc_u.grp.gr_passwd += (uintptr_t)buffer; - - sptr->nsc_ret.nsc_u.grp.gr_mem = - (char **)((uintptr_t)sptr->nsc_ret.nsc_u.grp.gr_mem + - (uintptr_t)buffer); - - i = 0; - while (sptr->nsc_ret.nsc_u.grp.gr_mem[i]) { - sptr->nsc_ret.nsc_u.grp.gr_mem[i] += (uintptr_t)buffer; - i++; - } - - *result = sptr->nsc_ret.nsc_u.grp; - -#endif /* _LP64 */ + nss_XbyY_args_t arg; - return (result); + NSS_XbyY_INIT(&arg, result, buffer, buflen, str2group); + arg.key.gid = gid; + (void) nss_search(&db_root, _nss_initf_group, + NSS_DBOP_GROUP_BYGID, &arg); + return ((struct group *)NSS_XbyY_FINI(&arg)); } struct group * @@ -452,6 +239,12 @@ fgetgrent_r(FILE *f, struct group *result, char *buffer, int buflen) * number of valid gids in gid_array (may be zero) * or * -1 (and errno set appropriately) on errors (none currently defined) + * + * NSS2 Consistency enhancements: + * The "files normal" format between an application and nscd for the + * NSS_DBOP_GROUP_BYMEMBER nss_search operation is defined to be a + * processed array of numgids [up to maxgids] gid_t values. gid_t + * values in the array are unique. */ static nss_status_t process_cstr(const char *, int, struct nss_groupsbymem *); @@ -468,6 +261,10 @@ _getgroupsbymember(const char *username, gid_t gid_array[], arg.gid_array = gid_array; arg.maxgids = maxgids; arg.numgids = numgids; + /* + * In backwards compatibility mode, use the old str2group & + * process_cstr interfaces. Ditto within nscd processing. + */ arg.str2ent = str2group; arg.process_cstr = process_cstr; @@ -505,14 +302,6 @@ _getgroupsbymember(const char *username, gid_t gid_array[], (void) nss_search(&db_root, _nss_initf_group, NSS_DBOP_GROUP_BYMEMBER, &arg); -#ifdef undef - /* - * Only do this if there's existing code somewhere that relies on - * initgroups() doing an endgrent() -- most unlikely. - */ - endgrent(); -#endif /* undef */ - return (arg.numgids); } @@ -560,8 +349,15 @@ str2group(const char *instr, int lenstr, void *ent, char *buffer, int buflen) * We copy the input string into the output buffer and * operate on it in place. */ - (void) memcpy(buffer, instr, lenstr); - buffer[lenstr] = '\0'; + if (instr != buffer) { + /* Overlapping buffer copies are OK */ + (void) memmove(buffer, instr, lenstr); + buffer[lenstr] = '\0'; + } + + /* quick exit do not entry fill if not needed */ + if (ent == (void *)NULL) + return (NSS_STR_PARSE_SUCCESS); next = buffer; diff --git a/usr/src/lib/libc/port/gen/getnetgrent.c b/usr/src/lib/libc/port/gen/getnetgrent.c index cae4720b81..d8d111e818 100644 --- a/usr/src/lib/libc/port/gen/getnetgrent.c +++ b/usr/src/lib/libc/port/gen/getnetgrent.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -74,10 +73,14 @@ _nss_initf_netgroup(p) * - getnetgrent(...) is repeatedly invoked by the user to extract the * contents of the entry found by setnetgrent(). * - endnetgrent() is almost like a real endXXXent routine. - * If we were certain that all the backends could provide netgroup information - * in a common form, we could make the setnetgrent() backend return the entire - * entry to the frontend, then implement getnetgrent() and endnetgrent() - * strictly in the frontend (aka here). But we're not certain, so we won't. + * The behaviour in NSS was: + * If we were certain that all the backends could provide netgroup information + * in a common form, we could make the setnetgrent() backend return the entire + * entry to the frontend, then implement getnetgrent() and endnetgrent() + * strictly in the frontend (aka here). But we're not certain, so we won't. + * In NSS2: + * Since nscd returns the results, and it is nscd that accumulates + * the results, then we can return the entire result on the setnetgrent. * * NOTE: * In the SunOS 4.x (YP) version of this code, innetgr() did not diff --git a/usr/src/lib/libc/port/gen/getpwnam.c b/usr/src/lib/libc/port/gen/getpwnam.c index 1d0aad906a..7a3b8c4b37 100644 --- a/usr/src/lib/libc/port/gen/getpwnam.c +++ b/usr/src/lib/libc/port/gen/getpwnam.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ diff --git a/usr/src/lib/libc/port/gen/getpwnam_r.c b/usr/src/lib/libc/port/gen/getpwnam_r.c index f318f1aec0..75b8fa171d 100644 --- a/usr/src/lib/libc/port/gen/getpwnam_r.c +++ b/usr/src/lib/libc/port/gen/getpwnam_r.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -67,86 +66,6 @@ struct passwd * _uncached_getpwnam_r(const char *name, struct passwd *result, char *buffer, int buflen); -static struct passwd * -process_getpw(struct passwd *result, char *buffer, int buflen, - nsc_data_t *sptr, int ndata); - -/* ARGSUSED4 */ -static struct passwd * -process_getpw(struct passwd *result, char *buffer, int buflen, - nsc_data_t *sptr, int ndata) -{ - - char *fixed; -#ifdef _LP64 - struct passwd pass64; -#endif - -#ifdef _LP64 - fixed = (char *)(((uintptr_t)buffer + 7) & ~7); -#else - fixed = (char *)(((uintptr_t)buffer + 3) & ~3); -#endif - buflen -= fixed - buffer; - buffer = fixed; - - if (sptr->nsc_ret.nsc_return_code != SUCCESS) - return (NULL); - -#ifdef _LP64 - if (sptr->nsc_ret.nsc_bufferbytesused - (int)sizeof (passwd32_t) - > buflen) { -#else - if (sptr->nsc_ret.nsc_bufferbytesused - (int)sizeof (struct passwd) - > buflen) { -#endif - errno = ERANGE; - return (NULL); - } - -#ifdef _LP64 - - (void) memcpy(buffer, - (sptr->nsc_ret.nsc_u.buff + sizeof (passwd32_t)), - (sptr->nsc_ret.nsc_bufferbytesused - sizeof (passwd32_t))); - - pass64.pw_name = (char *)(sptr->nsc_ret.nsc_u.pwd.pw_name + - (uintptr_t)buffer); - pass64.pw_passwd = (char *)(sptr->nsc_ret.nsc_u.pwd.pw_passwd + - (uintptr_t)buffer); - pass64.pw_uid = sptr->nsc_ret.nsc_u.pwd.pw_uid; - pass64.pw_gid = sptr->nsc_ret.nsc_u.pwd.pw_gid; - pass64.pw_age = (char *)(sptr->nsc_ret.nsc_u.pwd.pw_age + - (uintptr_t)buffer); - pass64.pw_comment = (char *)(sptr->nsc_ret.nsc_u.pwd.pw_comment + - (uintptr_t)buffer); - pass64.pw_gecos = (char *)(sptr->nsc_ret.nsc_u.pwd.pw_gecos + - (uintptr_t)buffer); - pass64.pw_dir = (char *)(sptr->nsc_ret.nsc_u.pwd.pw_dir + - (uintptr_t)buffer); - pass64.pw_shell = (char *)(sptr->nsc_ret.nsc_u.pwd.pw_shell + - (uintptr_t)buffer); - - *result = pass64; -#else - sptr->nsc_ret.nsc_u.pwd.pw_name += (uintptr_t)buffer; - sptr->nsc_ret.nsc_u.pwd.pw_passwd += (uintptr_t)buffer; - sptr->nsc_ret.nsc_u.pwd.pw_age += (uintptr_t)buffer; - sptr->nsc_ret.nsc_u.pwd.pw_comment += (uintptr_t)buffer; - sptr->nsc_ret.nsc_u.pwd.pw_gecos += (uintptr_t)buffer; - sptr->nsc_ret.nsc_u.pwd.pw_dir += (uintptr_t)buffer; - sptr->nsc_ret.nsc_u.pwd.pw_shell += (uintptr_t)buffer; - - *result = sptr->nsc_ret.nsc_u.pwd; - - (void) memcpy(buffer, - (sptr->nsc_ret.nsc_u.buff + sizeof (struct passwd)), - (sptr->nsc_ret.nsc_bufferbytesused - sizeof (struct passwd))); -#endif - - return (result); -} - /* * POSIX.1c Draft-6 version of the function getpwnam_r. * It was implemented by Solaris 2.3. @@ -154,48 +73,17 @@ process_getpw(struct passwd *result, char *buffer, int buflen, struct passwd * _getpwnam_r(const char *name, struct passwd *result, char *buffer, int buflen) { - /* - * allocate data on the stack for passwd information - */ - union { - nsc_data_t s_d; - char s_b[1024]; - } space; - nsc_data_t *sptr; - int ndata; - int adata; - struct passwd *resptr = NULL; - - if ((name == (const char *)NULL) || - (strlen(name) >= (sizeof (space) - sizeof (nsc_data_t)))) { + nss_XbyY_args_t arg; + + if (name == (const char *)NULL) { errno = ERANGE; - return ((struct passwd *)NULL); - } - ndata = sizeof (space); - adata = strlen(name) + sizeof (nsc_call_t) + 1; - space.s_d.nsc_call.nsc_callnumber = GETPWNAM; - (void) strcpy(space.s_d.nsc_call.nsc_u.name, name); - sptr = &space.s_d; - - switch (_nsc_trydoorcall(&sptr, &ndata, &adata)) { - case SUCCESS: /* positive cache hit */ - break; - case NOTFOUND: /* negative cache hit */ return (NULL); - default: - return ((struct passwd *)_uncached_getpwnam_r(name, result, - buffer, buflen)); } - resptr = process_getpw(result, buffer, buflen, sptr, ndata); - - /* - * check if doors reallocated the memory underneath us - * if they did munmap it or suffer a memory leak - */ - if (sptr != &space.s_d) - munmap((void *)sptr, ndata); - - return (resptr); + NSS_XbyY_INIT(&arg, result, buffer, buflen, str2passwd); + arg.key.name = name; + (void) nss_search(&db_root, _nss_initf_passwd, NSS_DBOP_PASSWD_BYNAME, + &arg); + return ((struct passwd *)NSS_XbyY_FINI(&arg)); } /* @@ -205,40 +93,13 @@ _getpwnam_r(const char *name, struct passwd *result, char *buffer, int buflen) struct passwd * _getpwuid_r(uid_t uid, struct passwd *result, char *buffer, int buflen) { - union { - nsc_data_t s_d; - char s_b[1024]; - } space; - nsc_data_t *sptr; - int ndata; - int adata; - struct passwd *resptr = NULL; - - ndata = sizeof (space); - adata = sizeof (nsc_call_t) + 1; - space.s_d.nsc_call.nsc_callnumber = GETPWUID; - space.s_d.nsc_call.nsc_u.uid = uid; - sptr = &space.s_d; - - switch (_nsc_trydoorcall(&sptr, &ndata, &adata)) { - case SUCCESS: /* positive cache hit */ - break; - case NOTFOUND: /* negative cache hit */ - return (NULL); - default: - return ((struct passwd *)_uncached_getpwuid_r(uid, result, - buffer, buflen)); - } - resptr = process_getpw(result, buffer, buflen, sptr, ndata); - - /* - * check if doors reallocated the memory underneath us - * if they did munmap it or suffer a memory leak - */ - if (sptr != &space.s_d) - munmap((void *)sptr, ndata); + nss_XbyY_args_t arg; - return (resptr); + NSS_XbyY_INIT(&arg, result, buffer, buflen, str2passwd); + arg.key.uid = uid; + (void) nss_search(&db_root, _nss_initf_passwd, NSS_DBOP_PASSWD_BYUID, + &arg); + return ((struct passwd *)NSS_XbyY_FINI(&arg)); } @@ -397,8 +258,15 @@ str2passwd(const char *instr, int lenstr, void *ent, char *buffer, int buflen) * We copy the input string into the output buffer and * operate on it in place. */ - (void) memcpy(buffer, instr, lenstr); - buffer[lenstr] = '\0'; + if (instr != buffer) { + /* Overlapping buffer copies are OK */ + (void) memmove(buffer, instr, lenstr); + buffer[lenstr] = '\0'; + } + + /* quick exit do not entry fill if not needed */ + if (ent == (void *)NULL) + return (NSS_STR_PARSE_SUCCESS); next = buffer; diff --git a/usr/src/lib/libc/port/gen/getspent_r.c b/usr/src/lib/libc/port/gen/getspent_r.c index 565ede148e..78c42b7b62 100644 --- a/usr/src/lib/libc/port/gen/getspent_r.c +++ b/usr/src/lib/libc/port/gen/getspent_r.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -48,7 +47,7 @@ int str2spwd(const char *, int, void *, static DEFINE_NSS_DB_ROOT(db_root); static DEFINE_NSS_GETENT(context); -static void +void _nss_initf_shadow(nss_db_params_t *p) { p->name = NSS_DBNAM_SHADOW; @@ -204,8 +203,16 @@ str2spwd(const char *instr, int lenstr, void *ent, char *buffer, int buflen) if (lencopy + 1 > buflen) { return (NSS_STR_PARSE_ERANGE); } - (void) memcpy(buffer, instr, lencopy); - buffer[lencopy] = 0; + + if (instr != buffer) { + /* Overlapping buffer copies are OK */ + (void) memmove(buffer, instr, lencopy); + buffer[lencopy] = 0; + } + + /* quick exit do not entry fill if not needed */ + if (ent == (void *)NULL) + return (NSS_STR_PARSE_SUCCESS); black_magic = (*instr == '+' || *instr == '-'); shadow->sp_namp = bufp = buffer; diff --git a/usr/src/lib/libc/port/gen/getxby_door.c b/usr/src/lib/libc/port/gen/getxby_door.c index d4e64868e1..e659ed9dcb 100644 --- a/usr/src/lib/libc/port/gen/getxby_door.c +++ b/usr/src/lib/libc/port/gen/getxby_door.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -21,7 +20,7 @@ */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -30,18 +29,32 @@ #include "synonyms.h" #include <mtlib.h> #include <sys/types.h> +#include <errno.h> #include <pwd.h> #include <nss_dbdefs.h> #include <stdio.h> +#include <string.h> #include <synch.h> #include <sys/param.h> #include <fcntl.h> #include <unistd.h> +#include <stdlib.h> #include <getxby_door.h> #include <sys/door.h> +#include <procfs.h> +#include <door.h> #include "libc.h" +#include "tsd.h" #include "base_conversion.h" +/* nss<->door hints */ +static mutex_t hints_lock = DEFAULTMUTEX; +static size_t door_bsize = 0; +static size_t door_nbsize = 0; +static int proc_is_cache = -1; + +/* library<->nscd door interaction apis */ + /* * * Routine that actually performs the door call. @@ -65,7 +78,7 @@ * and we're a multi-threaded application. Note that we cannot protect * the application if it closes the fd and it is multi-threaded. * - * int _nsc_trydoorcall(void *dptr, int *bufsize, int *actualsize); + * int _nsc_trydoorcall(void *dptr, size_t *bufsize, size_t *actualsize); * * *dptr IN: points to arg buffer OUT: points to results buffer * *bufsize IN: overall size of buffer OUT: overall size of buffer @@ -80,36 +93,166 @@ * */ -static mutex_t _door_lock = DEFAULTMUTEX; +/* + * Max size for list of db names supported by the private nscd + * No implied max here, any size will do, fixed size chosen to + * reduce yet another malloc + */ -int -_nsc_trydoorcall(nsc_data_t **dptr, int *ndata, int *adata) +#define BD_BUFSIZE 1024 +#define BD_SEP ',' + +typedef struct _nsc_door_t { + int doorfd; + mutex_t door_lock; + door_info_t doori; +} nsc_door_t; + +static nsc_door_t nsc_door[2] = { + { -1, DEFAULTMUTEX, { 0 } }, /* front (fattached) door */ + { -1, DEFAULTMUTEX, { 0 } }, /* back (private) door */ +}; + +/* assumed to be locked by using nsc_door[1] mutex */ +static char *nsc_db_buf = NULL; +static char **nsc_db_list = NULL; + +/* + * Check for a valid and matching db in the list. + * assume list is in the locked state. + */ + +static int +_nsc_use_backdoor(char *db) +{ + char **ndb; + + if (db && nsc_db_buf != NULL && nsc_db_list != NULL) { + for (ndb = nsc_db_list; *ndb; ndb++) { + if (strcmp(db, *ndb) == 0) + return (1); + } + } + return (0); +} + +/* + * flush private db lists + */ +static void +_nsc_flush_private_db() +{ + if (nsc_db_buf != NULL) { + libc_free((void *)nsc_db_buf); + nsc_db_buf = NULL; + } + if (nsc_db_list != NULL) { + libc_free((void *)nsc_db_list); + nsc_db_list = NULL; + } +} + +/* + * init/update nsc_db_buf given buff containing list of + * db's to be processed by a private nscd. + * This function assumes it has a well formed string from nscd. + */ + +static int +_nsc_init_private_db(char *dblist) +{ + char *cp, **lp; + int buflen = 0; + int arrlen = 0; + + if (dblist == NULL) + return (0); + + /* reset db list */ + _nsc_flush_private_db(); + + /* rebuild fresh list */ + buflen = strlen(dblist) + 1; + for (cp = dblist; *cp; cp++) + if (*cp == BD_SEP) + arrlen++; + if (cp == dblist) + return (0); + arrlen += 2; + nsc_db_buf = (char *)libc_malloc(buflen); + if (nsc_db_buf == (char *)NULL) + return (0); + nsc_db_list = (char **)libc_malloc(arrlen * sizeof (char *)); + if (nsc_db_list == (char **)NULL) { + libc_free((void *)nsc_db_buf); + nsc_db_buf = NULL; + return (0); + } + (void) memcpy(nsc_db_buf, dblist, buflen); + lp = nsc_db_list; + *lp++ = nsc_db_buf; + for (cp = nsc_db_buf; *cp; ) { + if (*cp == BD_SEP) { + *cp++ = '\0'; + *lp++ = cp; + } else + cp++; + } + *lp = NULL; + return (1); +} + +/* + * _nsc_initdoor_fp attempts to validate the given door and + * confirm that it is still available for use. The options are: + * Front door: + * If it's not open, attempt to open or error + * If it's open attempt to validate. + * If it's not validatable, reset fd and try again. + * Other wise it open and validated, return success + * Per user (back) door: + * This door is passed to the client through th front door + * attempt to validate it. If it can't be validated, it + * must be reset. Then send a NSS_ALTRESET error, so nscd can + * forward another fd if desired. + */ + +static nss_status_t +_nsc_initdoor_fp(nsc_door_t *dp) { - static int doorfd = -1; - static door_info_t real_door; + door_info_t my_door; - door_arg_t param; + + if (dp == NULL) { + errno = ENOTCONN; + return (NSS_ERROR); + } /* - * the first time in we try and open and validate the door. - * the validations are that the door must have been - * created with the name service door cookie and - * that the file attached to the door is owned by root - * and readonly by user, group and other. If any of these - * validations fail we refuse to use the door. + * the first time in we try and open and validate the front door. + * A front door request may return an alternate private back door + * that the client should use instead. + * + * To validate a door the door must have been created with + * the name service door cookie. The front door is file + * attached, owned by root and readonly by user, group and + * other. If any of these validations fail we refuse to use + * the door. A back door is delivered from the front door + * via a door_desc_t, and have the same cooke notification. */ - lmutex_lock(&_door_lock); + lmutex_lock(&dp->door_lock); try_again: - if (doorfd == -1) { + if (dp->doorfd == -1 && dp == &nsc_door[0]) { /* open front door */ int tbc[3]; int i; - if ((doorfd = open64(NAME_SERVICE_DOOR, O_RDONLY, 0)) == -1) { - lmutex_unlock(&_door_lock); - return (NOSERVER); + dp->doorfd = open64(NAME_SERVICE_DOOR, O_RDONLY, 0); + if (dp->doorfd == -1) { + lmutex_unlock(&dp->door_lock); + return (NSS_ERROR); } /* @@ -118,14 +261,14 @@ try_again: */ i = 0; - while (doorfd < 3) { /* we have a reserved fd */ - tbc[i++] = doorfd; - if ((doorfd = dup(doorfd)) < 0) { + while (dp->doorfd < 3) { /* we have a reserved fd */ + tbc[i++] = dp->doorfd; + if ((dp->doorfd = dup(dp->doorfd)) < 0) { while (i--) (void) close(tbc[i]); - doorfd = -1; - lmutex_unlock(&_door_lock); - return (NOSERVER); + dp->doorfd = -1; + lmutex_unlock(&dp->door_lock); + return (NSS_ERROR); } } @@ -135,38 +278,76 @@ try_again: /* * mark this door descriptor as close on exec */ - (void) fcntl(doorfd, F_SETFD, FD_CLOEXEC); - if (__door_info(doorfd, &real_door) == -1 || - (real_door.di_attributes & DOOR_REVOKED) || - real_door.di_data != (uintptr_t)NAME_SERVICE_DOOR_COOKIE) { + (void) fcntl(dp->doorfd, F_SETFD, FD_CLOEXEC); + if (__door_info(dp->doorfd, &dp->doori) < 0 || + (dp->doori.di_attributes & DOOR_REVOKED) || + dp->doori.di_data != (uintptr_t)NAME_SERVICE_DOOR_COOKIE) { /* * we should close doorfd because we just opened it */ - (void) close(doorfd); - doorfd = -1; - lmutex_unlock(&_door_lock); - return (NOSERVER); + (void) close(dp->doorfd); + dp->doorfd = -1; + (void) memset((void *)&dp->doori, + '\0', sizeof (door_info_t)); + lmutex_unlock(&dp->door_lock); + errno = ECONNREFUSED; + return (NSS_ERROR); } } else { - if (__door_info(doorfd, &my_door) == -1 || + if (__door_info(dp->doorfd, &my_door) < 0 || my_door.di_data != (uintptr_t)NAME_SERVICE_DOOR_COOKIE || - my_door.di_uniquifier != real_door.di_uniquifier) { + my_door.di_uniquifier != dp->doori.di_uniquifier) { /* * don't close it - * someone else has clobbered fd */ - doorfd = -1; + dp->doorfd = -1; + (void) memset((void *)&dp->doori, + '\0', sizeof (door_info_t)); + if (dp == &nsc_door[1]) { /* reset back door */ + /* flush invalid db list */ + _nsc_flush_private_db(); + lmutex_unlock(&dp->door_lock); + return (NSS_ALTRESET); + } goto try_again; } if (my_door.di_attributes & DOOR_REVOKED) { - (void) close(doorfd); /* nscd exited .... */ - doorfd = -1; /* try and restart connection */ + (void) close(dp->doorfd); /* nscd exited .... */ + dp->doorfd = -1; /* try and restart connection */ + (void) memset((void *)&dp->doori, + '\0', sizeof (door_info_t)); + if (dp == &nsc_door[1]) { /* back door reset */ + /* flush invalid db list */ + _nsc_flush_private_db(); + lmutex_unlock(&dp->door_lock); + return (NSS_ALTRESET); + } goto try_again; } } - lmutex_unlock(&_door_lock); + lmutex_unlock(&dp->door_lock); + return (NSS_SUCCESS); +} + +/* + * Try the door request once only, to the specified connection. + * return the results or error. + */ + +static nss_status_t +_nsc_try1door(nsc_door_t *dp, void **dptr, size_t *ndata, + size_t *adata, int *pdesc) +{ + door_arg_t param; + int ret; + nss_pheader_t *rp; + + ret = _nsc_initdoor_fp(dp); + if (ret != NSS_SUCCESS) + return (ret); param.rbuf = (char *)*dptr; param.rsize = *ndata; @@ -174,15 +355,346 @@ try_again: param.data_size = *adata; param.desc_ptr = NULL; param.desc_num = 0; - if (__door_call(doorfd, ¶m) == -1) { - return (NOSERVER); + ret = __door_call(dp->doorfd, ¶m); + if (ret < 0) { + return (NSS_ERROR); + } + *adata = param.data_size; + *ndata = param.rsize; + *dptr = (void *)param.data_ptr; + rp = (nss_pheader_t *)((void *)param.rbuf); + if (pdesc != NULL && rp && rp->p_status == NSS_ALTRETRY && + param.desc_ptr != NULL && param.desc_num > 0) { + if ((param.desc_ptr->d_attributes & DOOR_DESCRIPTOR) && + param.desc_ptr->d_data.d_desc.d_descriptor >= 0 && + param.desc_ptr->d_data.d_desc.d_id != 0) { + /* have an alt descriptor */ + *pdesc = param.desc_ptr->d_data.d_desc.d_descriptor; + /* got a NSS_ALTRETRY command */ + return (NSS_ALTRETRY); + } + errno = EINVAL; + return (NSS_ERROR); /* other error? */ } - *adata = (int)param.data_size; - *ndata = (int)param.rsize; - *dptr = (nsc_data_t *)(uintptr_t)param.data_ptr; if (*adata == 0 || *dptr == NULL) { - return (NOSERVER); + errno = ENOTCONN; + return (NSS_ERROR); } - return ((*dptr)->nsc_ret.nsc_return_code); + if (rp->p_status == NSS_ALTRESET || + rp->p_status == NSS_ALTRETRY || + rp->p_status == NSS_TRYLOCAL) + return (rp->p_status); + + return (NSS_SUCCESS); +} + +/* + * Backwards compatible API + */ + +nss_status_t +_nsc_trydoorcall(void **dptr, size_t *ndata, size_t *adata) +{ + return (_nsc_try1door(&nsc_door[0], dptr, ndata, adata, NULL)); +} + +/* + * Send the request to the designated door, based on the supplied db + * Retry on the alternate door fd if possible. + */ + +nss_status_t +_nsc_trydoorcall_ext(void **dptr, size_t *ndata, size_t *adata) +{ + int ret = NSS_ALTRETRY; + nsc_door_t *frontd = &nsc_door[0]; + nsc_door_t *backd = &nsc_door[1]; + int fd; + + nss_pheader_t *ph, ph_save; + char *dbl; + char *db = NULL; + nss_dbd_t *dbd; + int fb2frontd = 0; + int reset_frontd = 0; + + ph = (nss_pheader_t *)*dptr; + dbd = (nss_dbd_t *)((void *)((char *)ph + ph->dbd_off)); + if (dbd->o_name != 0) + db = (char *)dbd + dbd->o_name; + ph_save = *ph; + + while (ret == NSS_ALTRETRY || ret == NSS_ALTRESET) { + /* try private (back) door first if it exists and applies */ + if (db != NULL && backd->doorfd > 0 && fb2frontd == 0 && + _nsc_use_backdoor(db)) { + ret = _nsc_try1door(backd, dptr, ndata, adata, NULL); + if (ret == NSS_ALTRESET) { + /* + * received NSS_ALTRESET command, + * retry on front door + */ + lmutex_lock(&backd->door_lock); + backd->doorfd = -1; + (void) memset((void *)&backd->doori, + '\0', sizeof (door_info_t)); + /* flush now invalid db list */ + _nsc_flush_private_db(); + lmutex_unlock(&backd->door_lock); + continue; + } else if (ret == NSS_ALTRETRY) { + /* + * received NSS_ALTRETRY command, + * fall back and retry on front door + */ + fb2frontd = 1; + *ph = ph_save; + /* + * tell the front door server, this is + * a fallback call + */ + ph->p_status = NSS_ALTRETRY; + continue; + } + + /* return the result or error */ + break; + } + + /* try the front door */ + fd = -1; + ret = _nsc_try1door(frontd, dptr, ndata, adata, &fd); + + if (ret != NSS_ALTRETRY) { + /* + * got a success or failure result. + * but front door should never send NSS_ALTRESET + */ + if (ret == NSS_ALTRESET) + /* reset the front door */ + reset_frontd = 1; + else + /* + * not NSS_ALTRETRY and not NSS_ALTRESET + * return the result or error + */ + break; + } else if (fb2frontd == 1) { + /* + * front door should never send NSS_ALTRETRY + * in a fallback call. Reset the front door. + */ + reset_frontd = 1; + } + + if (reset_frontd == 1) { + lmutex_lock(&frontd->door_lock); + frontd->doorfd = -1; + (void) memset((void *)&frontd->doori, + '\0', sizeof (door_info_t)); + lmutex_unlock(&frontd->door_lock); + /* error out */ + ret = NSS_ERROR; + break; + } + + /* process NSS_ALTRETRY request from front door */ + if (fd < 0) + continue; /* no new door given, try again */ + + /* update and try alternate door */ + lmutex_lock(&backd->door_lock); + if (backd->doorfd >= 0) { + /* unexpected open alt door - clean up, continue */ + _nsc_flush_private_db(); + (void) close(backd->doorfd); + } + + /* set up back door fd */ + backd->doorfd = fd; + + /* set up back door db list */ + ph = (nss_pheader_t *)*dptr; + dbl = ((char *)ph) + ph->data_off; + + if (_nsc_init_private_db(dbl) == 0) { + /* could not init db list, try again */ + (void) close(backd->doorfd); + backd->doorfd = -1; + lmutex_unlock(&backd->door_lock); + continue; + } + if (door_info(backd->doorfd, &backd->doori) < 0 || + (backd->doori.di_attributes & DOOR_REVOKED) || + backd->doori.di_data != + (uintptr_t)NAME_SERVICE_DOOR_COOKIE) { + /* doorfd bad, or must not really be open */ + (void) close(backd->doorfd); + backd->doorfd = -1; + (void) memset((void *)&backd->doori, + '\0', sizeof (door_info_t)); + } + (void) fcntl(backd->doorfd, F_SETFD, FD_CLOEXEC); + lmutex_unlock(&backd->door_lock); + /* NSS_ALTRETRY new back door */ + *ph = ph_save; + } + return (ret); +} + +/* + * Get the current (but growable) buffer size for a NSS2 packet. + * Heuristic algorithm used: + * 1) Make sure it's at least NSS_BUFLEN_DOOR in length (16k default) + * 2) if an incoming user buffer is > larger than the current size + * Make the buffer at least NSS_BUFLEN_DOOR/2+user buffer size + * This should account for any reasonable nss_pheader, keys + * extended area etc. + * 3) keep the prototype/debugging (private)NSS_BUFLEN option + * to change any preconfigured value if needed(?) + */ + +static size_t +_nsc_getdoorbsize(size_t min_size) +{ + if (!door_bsize) { + lmutex_lock(&hints_lock); + if (!door_bsize) { + /* future work - get nscd hint & use hint size */ + door_bsize = ROUND_UP(door_bsize, NSS_BUFSIZ); + if (door_bsize < NSS_BUFLEN_DOOR) { + door_bsize = NSS_BUFLEN_DOOR; + } + } + lmutex_unlock(&hints_lock); + } + if (min_size && door_bsize < (min_size + NSS_BUFLEN_DOOR/2)) { + lmutex_lock(&hints_lock); + if (door_bsize < (min_size + NSS_BUFLEN_DOOR/2)) { + min_size += NSS_BUFLEN_DOOR; + door_bsize = ROUND_UP(min_size, NSS_BUFSIZ); + } + lmutex_unlock(&hints_lock); + } + return (door_bsize); +} + +static void +_nsc_freedbuf(void *arg) +{ + nss_XbyY_buf_t *tsdbuf = arg; + + if (tsdbuf != NULL && tsdbuf->buffer != NULL) { + lfree(tsdbuf->buffer, (size_t)tsdbuf->buflen); + tsdbuf->result = NULL; + tsdbuf->buffer = NULL; + tsdbuf->buflen = 0; + } +} + +/* + * _nsc_getdoorbuf - return the client side per thread door buffer + * Elsewhere, it is assumed that the header is 0'd upon return from here. + */ + +int +_nsc_getdoorbuf(void **doorptr, size_t *bufsize) +{ + nss_XbyY_buf_t *tsdbuf; + char *bp; + size_t dsize; + + if (doorptr == NULL || bufsize == NULL) + return (-1); + + /* Get thread specific pointer to door buffer */ + tsdbuf = tsdalloc(_T_DOORBUF, sizeof (nss_XbyY_buf_t), _nsc_freedbuf); + if (tsdbuf == NULL) + return (-1); + + /* if door buffer does not exist create it */ + if (tsdbuf->buffer == NULL) { + dsize = _nsc_getdoorbsize(*bufsize); + + /* setup a door buffer with a total length of dsize */ + bp = lmalloc(dsize); + if (bp == NULL) + return (-1); + tsdbuf->buffer = bp; + tsdbuf->buflen = dsize; + } else { + /* check old buffer size and resize if needed */ + if (*bufsize) { + dsize = _nsc_getdoorbsize(*bufsize); + if (tsdbuf->buflen < dsize) { + lfree(tsdbuf->buffer, (size_t)tsdbuf->buflen); + bp = lmalloc(dsize); + if (bp == NULL) + return (-1); + tsdbuf->buffer = bp; + tsdbuf->buflen = dsize; + } + } + /* freshly malloc'd door bufs are 0'd */ + /* 0 header for now. Zero entire buf(?) TDB */ + (void) memset((void *)tsdbuf->buffer, 0, + (size_t)sizeof (nss_pheader_t)); + + } + *doorptr = (void *)tsdbuf->buffer; + *bufsize = tsdbuf->buflen; + return (0); +} + +void +_nsc_resizedoorbuf(size_t bsize) +{ + /* signal to update if new door size is desired */ + lmutex_lock(&hints_lock); + if (bsize > door_bsize && door_nbsize < bsize) + door_nbsize = bsize; + lmutex_unlock(&hints_lock); +} + +/* + * Check uid and /proc/PID/psinfo to see if this process is nscd + * If it is set the appropriate flags and allow policy reconfiguration. + */ +int +_nsc_proc_is_cache() +{ + psinfo_t pinfo; + char fname[128]; + int ret; + int fd; + + if (proc_is_cache >= 0) + return (proc_is_cache); + lmutex_lock(&hints_lock); + if (proc_is_cache >= 0) { + lmutex_unlock(&hints_lock); + return (proc_is_cache); + } + proc_is_cache = 0; + /* It can't be nscd if it's not running as root... */ + if (getuid() != 0) { + lmutex_unlock(&hints_lock); + return (0); + } + ret = snprintf(fname, 128, "/proc/%d/psinfo", getpid()); + if (ret > 0 && ret < 128) { + if ((fd = open(fname, O_RDONLY)) > 0) { + ret = read(fd, &pinfo, sizeof (psinfo_t)); + (void) close(fd); + if (ret == sizeof (psinfo_t) && + (strcmp(pinfo.pr_fname, "nscd") == 0)) { + /* process runs as root and is named nscd */ + /* that's good enough for now */ + proc_is_cache = 1; + } + } + } + lmutex_unlock(&hints_lock); + return (proc_is_cache); } diff --git a/usr/src/lib/libc/port/gen/getxby_door.h b/usr/src/lib/libc/port/gen/getxby_door.h index fd4c6db044..54741d08b5 100644 --- a/usr/src/lib/libc/port/gen/getxby_door.h +++ b/usr/src/lib/libc/port/gen/getxby_door.h @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 1994, 1999-2003 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -46,283 +45,31 @@ extern "C" { #include <exec_attr.h> #include <prof_attr.h> #include <user_attr.h> - -#ifdef _LP64 - -/* NB uid_t and gid_t are the same size in 32 & 64 bit mode */ - -typedef unsigned int uptr32_t; /* 32bit pointer type */ - -typedef struct passwd32 { - uptr32_t pw_name; - uptr32_t pw_passwd; - uid_t pw_uid; - gid_t pw_gid; - uptr32_t pw_age; - uptr32_t pw_comment; - uptr32_t pw_gecos; - uptr32_t pw_dir; - uptr32_t pw_shell; -} passwd32_t; - -typedef struct group32 { - uptr32_t gr_name; - uptr32_t gr_passwd; - gid_t gr_gid; - uptr32_t gr_mem; -} group32_t; - -/* NB int is the same size in 32 & 64 bit mode */ - -typedef struct hostent32 { - uptr32_t h_name; /* official name of host */ - uptr32_t h_aliases; /* alias list */ - int h_addrtype; /* host address type */ - int h_length; /* length of address */ - uptr32_t h_addr_list; /* list of addresses from name server */ -#define h_addr h_addr_list[0] /* address, for backward compatiblity */ -} hostent32_t; - -typedef struct execstr32_s { - uptr32_t name; - uptr32_t policy; - uptr32_t type; - uptr32_t res1; - uptr32_t res2; - uptr32_t id; - uptr32_t attr; -} execstr32_t; - -typedef struct profstr32_s { - uptr32_t name; - uptr32_t res1; - uptr32_t res2; - uptr32_t desc; - uptr32_t attr; -} profstr32_t; - -typedef struct userstr32_s { - uptr32_t name; - uptr32_t qualifier; - uptr32_t res1; - uptr32_t res2; - uptr32_t attr; -} userstr32_t; - -#endif /* _LP64 */ - -/* - * statistics & control structure - */ - -typedef struct nsc_stat { - int nsc_pos_cache_hits; /* hits on real entries */ - int nsc_neg_cache_hits; /* hits on hegative entries */ - int nsc_pos_cache_misses; /* miss that results in real entry */ - int nsc_neg_cache_misses; /* miss that results in neg entry */ - int nsc_entries; /* count of cache entries */ - int nsc_throttle_count; /* count of load shedding */ - int nsc_invalidate_count; /* count for cache invalidation */ - int nsc_suggestedsize; /* suggested size */ - int nsc_enabled; /* if 0, always return NOSERVER */ - int nsc_invalidate; /* command to invalidate cache */ - int nsc_pos_ttl; /* time to live for positive entries */ - int nsc_neg_ttl; /* time to live for negative entries */ - short nsc_keephot; /* number of entries to keep hot */ - short nsc_old_data_ok; /* set if expired data is acceptable */ - short nsc_check_files; /* set if file time should be checked */ - short nsc_secure_mode; /* set if pw fields to be blanked for */ - /* those other than owners */ -} nsc_stat_t; - +#include <nss_dbdefs.h> /* - * structure returned by server for all calls + * nscd version 2 doors interfaces + * The known, but private NAME_SERVICE_DOOR, filesystem name remains + * the same, even though the transfer contents is significantly different. */ -typedef struct { - int nsc_bufferbytesused; - int nsc_return_code; - int nsc_errno; - - union { -/* - * If we are 64bit mode explicitly use the 32 versions, otherwise we are in - * 32bit mode and can use the original definitions. No need to worry about - * padding since all the sizes are preserved - */ -#ifdef _LP64 - passwd32_t pwd; - group32_t grp; - hostent32_t hst; - execstr32_t exec; - profstr32_t prof; - userstr32_t user; -#else - struct passwd pwd; - struct group grp; - struct hostent hst; - execstr_t exec; - profstr_t prof; - userstr_t user; +#define NAME_SERVICE_DOOR_V2 2 +#define NAME_SERVICE_DOOR_VERSION 2 +#ifndef NAME_SERVICE_DOOR +#define NAME_SERVICE_DOOR "/var/run/name_service_door" #endif - nsc_stat_t stats; - char buff[4]; - } nsc_u; - -} nsc_return_t; - -/* - * calls look like this - */ - -typedef struct { - int nsc_callnumber; - union { - uid_t uid; - gid_t gid; - char name[sizeof (int)]; /* size is indeterminate */ - struct { - int a_type; - int a_length; - char a_data[sizeof (int)]; - } addr; - struct { - int af_family; - int flags; - char name[sizeof (int)]; /* size is indeterminate */ - } ipnode; - } nsc_u; -} nsc_call_t; -/* - * how the client views the call process - */ - -typedef union { - nsc_call_t nsc_call; - nsc_return_t nsc_ret; - char nsc_buff[sizeof (int)]; -} nsc_data_t; - -/* - * What each entry in the nameserver cache looks like. - */ - -typedef struct { - int nsc_hits; /* number of hits */ - int nsc_status; /* flag bits */ - time_t nsc_timestamp; /* last time entry validated */ - int nsc_refcount; /* reference count */ - nsc_return_t nsc_data; /* data returned to client */ -} nsc_bucket_t; - -typedef struct hash_entry { - struct hash_entry *next_entry; - struct hash_entry *right_entry; - struct hash_entry *left_entry; - char *key; - char *data; -} hash_entry_t; - -typedef struct hash { - int size; - hash_entry_t **table; - hash_entry_t *start; - enum hash_type { - String_Key = 0, Integer_Key = 1 - } hash_type; -} hash_t; - -typedef struct passwd_cache { - hash_entry_t passwd; -} passwd_cache_t; - -typedef struct group_cache { - hash_entry_t group; -} group_cache_t; - -typedef struct host_cache { - hash_entry_t host; -} host_cache_t; - -/* - * structure to handle waiting for pending name service requests - */ - -typedef struct waiter { - cond_t w_waitcv; - char **w_key; - struct waiter *w_next, *w_prev; -} waiter_t; - -/* - * OR'D in by server to call self for updates - */ - -#define UPDATEBIT (1<<30) -#define MASKUPDATEBIT(a) ((~UPDATEBIT)&(a)) - -#define NULLCALL 0 -#define GETPWUID 1 -#define GETPWNAM 2 -#define GETGRNAM 3 -#define GETGRGID 4 -#define GETHOSTBYNAME 5 -#define GETHOSTBYADDR 6 -#define GETIPNODEBYNAME 10 -#define GETIPNODEBYADDR 11 -#define GETEXECID 12 /* for exec_attr */ -#define GETPROFNAM 13 /* for prof_attr */ -#define GETUSERNAM 14 /* for user_attr */ - -/* - * administrative calls - */ - -#define KILLSERVER 7 -#define GETADMIN 8 -#define SETADMIN 9 - - -/* - * debug levels - */ - -#define DBG_OFF 0 -#define DBG_CANT_FIND 2 -#define DBG_NETLOOKUPS 4 -#define DBG_ALL 6 - -/* - * Max size name we allow to be passed to avoid - * buffer overflow problems - */ -#define NSCDMAXNAMELEN 255 - -/* - * flag bits - */ - -#define ST_UPDATE_PENDING 1 - +#define NAME_SERVICE_DOOR_COOKIE ((void*)(0xdeadbeef^NAME_SERVICE_DOOR_VERSION)) /* - * defines for client-server interaction + * internal APIs */ -#define NAME_SERVICE_DOOR_VERSION 1 -#define NAME_SERVICE_DOOR "/var/run/name_service_door" -#define NAME_SERVICE_DOOR_COOKIE ((void*)(0xdeadbeef^NAME_SERVICE_DOOR_VERSION)) -#define UPDATE_DOOR_COOKIE ((void*)(0xdeadcafe) - -#define SUCCESS 0 -#define NOTFOUND -1 -#define CREDERROR -2 -#define SERVERERROR -3 -#define NOSERVER -4 +nss_status_t _nsc_trydoorcall(void **dptr, size_t *bsize, size_t *dsize); +nss_status_t _nsc_trydoorcall_ext(void **dptr, size_t *bsize, size_t *dsize); +int _nsc_getdoorbuf(void **dptr, size_t *bsize); +void _nsc_resizedoorbuf(size_t bsize); +int _nsc_proc_is_cache(); -int -_nsc_trydoorcall(nsc_data_t **dptr, int *ndata, int *adata); struct passwd * _uncached_getpwuid_r(uid_t uid, struct passwd *result, char *buffer, diff --git a/usr/src/lib/libc/port/gen/nss_common.c b/usr/src/lib/libc/port/gen/nss_common.c index ad27e0f807..4e5f12e959 100644 --- a/usr/src/lib/libc/port/gen/nss_common.c +++ b/usr/src/lib/libc/port/gen/nss_common.c @@ -44,15 +44,58 @@ #undef __NSS_PRIVATE_INTERFACE #include <nss_common.h> +#include <nss_dbdefs.h> #include <unistd.h> #include <stdlib.h> #include <stdio.h> #include <string.h> #include <thread.h> +#include <sys/types.h> +#include <sys/mman.h> +#include <errno.h> #include "libc.h" #include "tsd.h" +#include <getxby_door.h> + +/* + * policy component function interposing definitions: + * nscd if so desired can interpose it's own switch functions over + * the internal unlocked counterparts. This will allow nscd to replace + * the switch policy state engine with one that uses it's internal + * components. + * Only nscd can change this through it's use of nss_config. + * The golden rule is: ptr == NULL checking is used in the switch to + * see if a function was interposed. But nscd is responsible for seeing + * that mutex locking to change the values are observed when the data is + * changed. Especially if it happens > once. The switch does not lock + * the pointer with mutexs. + */ + +typedef struct { + void *p; +#if 0 + void (*nss_delete_fp)(nss_db_root_t *rootp); + nss_status_t (*nss_search_fp)(nss_db_root_t *rootp, + nss_db_initf_t initf, int search_fnum, + void *search_args); + void (*nss_setent_u_fp)(nss_db_root_t *, + nss_db_initf_t, nss_getent_t *); + nss_status_t (*nss_getent_u_fp)(nss_db_root_t *, + nss_db_initf_t, nss_getent_t *, void *); + void (*nss_endent_u_fp)(nss_db_root_t *, + nss_db_initf_t, nss_getent_t *); + void (*end_iter_u_fp)(nss_db_root_t *rootp, + struct nss_getent_context *contextp); +#endif +} nss_policyf_t; + +static mutex_t nss_policyf_lock = DEFAULTMUTEX; +static nss_policyf_t nss_policyf_ptrs = + { (void *)NULL }; + /* + * nsswitch db_root state machine definitions: * The golden rule is: if you hold a pointer to an nss_db_state struct and * you don't hold the lock, you'd better have incremented the refcount * while you held the lock; otherwise, it may vanish or change @@ -126,7 +169,11 @@ void _nss_db_state_destr(struct nss_db_state *); /* === the config info hasn't changed (by comparing version numbers) */ -/* NSS_OPTIONS infrastructure BEGIN */ +/* + * NSS_OPTIONS/NIS_OPTIONS environment varibles data definitions: + * This remains for backwards compatibility. But generally nscd will + * decide if/how this gets used. + */ static int checked_env = 0; /* protected by "rootlock" */ /* allowing __nss_debug_file to be set could be a security hole. */ @@ -178,6 +225,397 @@ static struct option nis_options[] = { { 0, 0, 0 }, }; +/* + * switch configuration parameter "database" definitions: + * The switch maintains a simmple read/write parameter database + * that nscd and the switch components can use to communicate + * nscd data to other components for configuration or out of band + * [IE no in the context of a getXbyY or putXbyY operation] data. + * The data passed are pointers to a lock data buffer and a length. + * Use of this is treated as SunwPrivate between nscd and the switch + * unless other wise stated. + */ + +typedef struct nss_cfgparam { + char *name; + mutex_t *lock; + void *buffer; + size_t length; +} nss_cfgparam_t; + +typedef struct nss_cfglist { + char *name; + nss_cfgparam_t *list; + int count; + int max; +} nss_cfglist_t; + +#define NSS_CFG_INCR 16 + +static nss_cfglist_t *nss_cfg = (nss_cfglist_t *)NULL; +static int nss_cfgcount = 0; +static int nss_cfgmax = 0; +static mutex_t nss_cfglock = DEFAULTMUTEX; + +static int nss_cfg_policy_init(); + +/* + * A config parameters are in the form component:parameter + * as in: nss:parameter - switch (internal FE/policy/BE) parameter + * nscd:param - nscd application parameter + * ldap:param - nss_ldap BE parameter + * passwd:param - get/put passwd FE parameter + */ + +#define NSS_CONFIG_BRK ':' + +/* + * The policy components initial parameter list + */ +static nss_config_t nss_policy_params[] = { + { "nss:policyfunc", NSS_CONFIG_ADD, &nss_policyf_lock, + (void *)&nss_policyf_ptrs, (size_t)sizeof (nss_policyf_t) }, + { NULL, NSS_CONFIG_ADD, (mutex_t *)NULL, (void *)NULL, (size_t)0 }, +}; + +/* + * NSS parameter configuration routines + */ + +/* compare config name (component:parameter) to a component name */ +static int +nss_cfgcn_cmp(const char *cfgname, const char *compname) +{ + char *c; + size_t len, len2; + + /* this code assumes valid pointers */ + if ((c = strchr(cfgname, NSS_CONFIG_BRK)) == NULL) + return (-1); + len = (size_t)(c - cfgname); + len2 = strlen(compname); + if (len2 != len) + return (-1); + return (strncmp(cfgname, compname, len)); +} + +/* init configuration arena */ +static int +nss_cfg_init() +{ + int i; + + /* First time caller? */ + if (nss_cfg != NULL) + return (0); + + /* Initialize internal tables */ + lmutex_lock(&nss_cfglock); + if (nss_cfg != NULL) { + lmutex_unlock(&nss_cfglock); + return (0); + } + nss_cfg = (nss_cfglist_t *)libc_malloc(NSS_CFG_INCR * + sizeof (nss_cfglist_t)); + if (nss_cfg == (nss_cfglist_t *)NULL) { + errno = ENOMEM; + lmutex_unlock(&nss_cfglock); + return (-1); + } + nss_cfgmax = NSS_CFG_INCR; + for (i = 0; i < nss_cfgmax; i++) { + nss_cfg[i].list = (nss_cfgparam_t *)libc_malloc(NSS_CFG_INCR * + sizeof (nss_cfgparam_t)); + if (nss_cfg[i].list == (nss_cfgparam_t *)NULL) { + errno = ENOMEM; + lmutex_unlock(&nss_cfglock); + return (-1); + } + nss_cfg[i].max = NSS_CFG_INCR; + } + + /* Initialize Policy Engine values */ + lmutex_unlock(&nss_cfglock); + if (nss_cfg_policy_init() < 0) { + return (-1); + } + return (0); +} + +/* find the name'd component list - create it if non-existent */ +static nss_cfglist_t * +nss_cfgcomp_get(char *name, int add) +{ + nss_cfglist_t *next; + char *c; + int i, len; + size_t nsize; + + /* Make sure system is init'd */ + if (nss_cfg == NULL && nss_cfg_init() < 0) + return ((nss_cfglist_t *)NULL); + + /* and check component:name validity */ + if (name == NULL || (c = strchr(name, NSS_CONFIG_BRK)) == NULL) + return ((nss_cfglist_t *)NULL); + + lmutex_lock(&nss_cfglock); + next = nss_cfg; + for (i = 0; i < nss_cfgcount; i++) { + if (next->name && nss_cfgcn_cmp(name, next->name) == 0) { + lmutex_unlock(&nss_cfglock); + return (next); + } + next++; + } + if (!add) { + lmutex_unlock(&nss_cfglock); + return (NULL); + } + + /* not found, create a fresh one */ + if (nss_cfgcount >= nss_cfgmax) { + /* realloc first */ + nsize = (nss_cfgmax + NSS_CFG_INCR) * sizeof (nss_cfgparam_t); + next = (nss_cfglist_t *)libc_realloc(nss_cfg, nsize); + if (next == NULL) { + errno = ENOMEM; + lmutex_unlock(&nss_cfglock); + return ((nss_cfglist_t *)NULL); + } + (void) memset((void *)(next + nss_cfgcount), '\0', + NSS_CFG_INCR * sizeof (nss_cfglist_t)); + nss_cfgmax += NSS_CFG_INCR; + nss_cfg = next; + } + next = nss_cfg + nss_cfgcount; + len = (size_t)(c - name) + 1; + if ((next->name = libc_malloc(len)) == NULL) { + errno = ENOMEM; + lmutex_unlock(&nss_cfglock); + return ((nss_cfglist_t *)NULL); + } + nss_cfgcount++; + (void) strlcpy(next->name, name, len); + lmutex_unlock(&nss_cfglock); + return (next); +} + +/* find the name'd parameter - create it if non-existent */ +static nss_cfgparam_t * +nss_cfgparam_get(char *name, int add) +{ + nss_cfglist_t *comp; + nss_cfgparam_t *next; + int count, i; + size_t nsize; + + if ((comp = nss_cfgcomp_get(name, add)) == NULL) + return ((nss_cfgparam_t *)NULL); + lmutex_lock(&nss_cfglock); + count = comp->count; + next = comp->list; + for (i = 0; i < count; i++) { + if (next->name && strcmp(name, next->name) == 0) { + lmutex_unlock(&nss_cfglock); + return (next); + } + next++; + } + if (!add) { + lmutex_unlock(&nss_cfglock); + return (NULL); + } + + /* not found, create a fresh one */ + if (count >= comp->max) { + /* realloc first */ + nsize = (comp->max + NSS_CFG_INCR) * sizeof (nss_cfgparam_t); + next = (nss_cfgparam_t *)libc_realloc(comp->list, nsize); + if (next == NULL) { + errno = ENOMEM; + lmutex_unlock(&nss_cfglock); + return ((nss_cfgparam_t *)NULL); + } + comp->max += NSS_CFG_INCR; + comp->list = next; + } + next = comp->list + comp->count; + if ((next->name = libc_strdup(name)) == NULL) { + errno = ENOMEM; + lmutex_unlock(&nss_cfglock); + return ((nss_cfgparam_t *)NULL); + } + comp->count++; + lmutex_unlock(&nss_cfglock); + return (next); +} + +/* find the name'd parameter - delete it if it exists */ +static void +nss_cfg_del(nss_config_t *cfgp) +{ + char *name; + nss_cfglist_t *comp; + nss_cfgparam_t *next, *cur; + int count, i, j; + + /* exit if component name does not already exist */ + if ((name = cfgp->name) == NULL || + (comp = nss_cfgcomp_get(name, 0)) == NULL) + return; + + /* find it */ + lmutex_lock(&nss_cfglock); + count = comp->count; + next = comp->list; + for (i = 0; i < count; i++) { + if (next->name && strcmp(name, next->name) == 0) { + break; /* found it... */ + } + next++; + } + if (i >= count) { + /* not found, already deleted */ + lmutex_unlock(&nss_cfglock); + return; + } + + /* copy down the remaining parameters, and clean up */ + /* don't try to clean up component tables */ + cur = next; + next++; + for (j = i+1; j < count; j++) { + *cur = *next; + cur++; + next++; + } + /* erase the last one */ + if (cur->name) { + libc_free(cur->name); + cur->name = (char *)NULL; + } + cur->lock = (mutex_t *)NULL; + cur->buffer = (void *)NULL; + cur->length = 0; + comp->count--; + lmutex_unlock(&nss_cfglock); +} + +static int +nss_cfg_get(nss_config_t *next) +{ + nss_cfgparam_t *param; + + errno = 0; + if ((param = nss_cfgparam_get(next->name, 0)) == NULL) + return (-1); + next->lock = param->lock; + next->buffer = param->buffer; + next->length = param->length; + return (0); +} + +static int +nss_cfg_put(nss_config_t *next, int add) +{ + nss_cfgparam_t *param; + + errno = 0; + if ((param = nss_cfgparam_get(next->name, add)) == NULL) + return (-1); + param->lock = next->lock; + param->buffer = next->buffer; + param->length = next->length; + return (0); +} + +/* + * Policy engine configurator - set and get interface + * argument is a NULL terminated list of set/get requests + * with input/result buffers and lengths. nss_cname is the + * specifier of a set or get operation and the property being + * managed. The intent is limited functions and expandability. + */ + +nss_status_t +nss_config(nss_config_t **plist, int cnt) +{ + nss_config_t *next; + int i; + + /* interface is only available to nscd */ + if (_nsc_proc_is_cache() <= 0) { + return (NSS_UNAVAIL); + } + if (plist == NULL || cnt <= 0) + return (NSS_SUCCESS); + for (i = 0; i < cnt; i++) { + next = plist[i]; + if (next == NULL) + break; + if (next->name == NULL) { + errno = EFAULT; + return (NSS_ERROR); + } + switch (next->cop) { + case NSS_CONFIG_GET: + /* get current lock/buffer/length fields */ + if (nss_cfg_get(next) < 0) { + return (NSS_ERROR); + } + break; + case NSS_CONFIG_PUT: + /* set new lock/buffer/length fields */ + if (nss_cfg_put(next, 0) < 0) { + return (NSS_ERROR); + } + break; + case NSS_CONFIG_ADD: + /* add parameter & set new lock/buffer/length fields */ + if (nss_cfg_put(next, 1) < 0) { + return (NSS_ERROR); + } + break; + case NSS_CONFIG_DELETE: + /* delete parameter - should always work... */ + nss_cfg_del(next); + break; + case NSS_CONFIG_LIST: + break; + default: + continue; + } + } + return (NSS_SUCCESS); +} + +/* + * This routine is called immediately after nss_cfg_init but prior to + * any commands from nscd being processed. The intent here is to + * initialize the nss:* parameters allowed by the policy component + * so that nscd can then proceed and modify them if so desired. + * + * We know we can only get here if we are nscd so we can skip the + * preliminaries. + */ + +static int +nss_cfg_policy_init() +{ + nss_config_t *next = &nss_policy_params[0]; + + for (; next && next->name != NULL; next++) { + if (nss_cfg_put(next, 1) < 0) + return (-1); + } + return (0); +} + +/* + * NSS_OPTION & NIS_OPTION environment variable functions + */ + static void set_option(struct option *opt, char *name, char *val) @@ -293,9 +731,12 @@ __nis_get_environment() return; __parse_environment(nis_options, p); } -/* NSS_OPTIONS/NIS_OPTIONS infrastructure END */ +/* + * Switch policy component backend state machine functions + */ + static nss_backend_t * nss_get_backend_u(nss_db_root_t **rootpp, struct nss_db_state *s, int n_src) { @@ -512,6 +953,10 @@ _nss_src_state_destr(struct nss_src_state *src, int max_dormant) void _nss_db_state_destr(struct nss_db_state *s) { + + if (s == NULL) + return; + /* === _private_mutex_destroy(&s->orphan_root.lock); */ if (s->p.cleanup != 0) { (*s->p.cleanup)(&s->p); @@ -531,20 +976,6 @@ _nss_db_state_destr(struct nss_db_state *s) libc_free(s); } -void -nss_delete(nss_db_root_t *rootp) -{ - struct nss_db_state *s; - - NSS_ROOTLOCK(rootp, &s); - if (s == 0) { - NSS_UNLOCK(rootp); - } else { - rootp->s = 0; - NSS_UNREF_UNLOCK(rootp, s); - } -} - /* * _nss_status_vec() returns a bit vector of all status codes returned during @@ -675,6 +1106,28 @@ retry_test(nss_status_t res, int n, struct __nsw_lookup_v1 *lkp) return (0); } +/* + * Switch policy component functional interfaces + */ + +void +nss_delete(nss_db_root_t *rootp) +{ + struct nss_db_state *s; + + /* no name service cache daemon divert here */ + /* local nss_delete decrements state reference counts */ + /* and may free up opened switch resources. */ + + NSS_ROOTLOCK(rootp, &s); + if (s == 0) { + NSS_UNLOCK(rootp); + } else { + rootp->s = 0; + NSS_UNREF_UNLOCK(rootp, s); + } +} + nss_status_t nss_search(nss_db_root_t *rootp, nss_db_initf_t initf, int search_fnum, void *search_args) @@ -682,7 +1135,17 @@ nss_search(nss_db_root_t *rootp, nss_db_initf_t initf, int search_fnum, nss_status_t res = NSS_UNAVAIL; struct nss_db_state *s; int n_src; - unsigned int *status_vec_p = _nss_status_vec_p(); + unsigned int *status_vec_p; + + /* name service cache daemon divert */ + res = _nsc_search(rootp, initf, search_fnum, search_args); + if (res != NSS_TRYLOCAL) + return (res); + + /* fall through - process locally */ + errno = 0; /* just in case ... */ + res = NSS_UNAVAIL; + status_vec_p = _nss_status_vec_p(); if (status_vec_p == NULL) { return (NSS_UNAVAIL); @@ -763,7 +1226,7 @@ nss_search(nss_db_root_t *rootp, nss_db_initf_t initf, int search_fnum, /* - * Start of nss_setent()/nss_getent()/nss_endent() + * Start of nss_{setent|getent|endent} */ /* @@ -772,16 +1235,31 @@ nss_search(nss_db_root_t *rootp, nss_db_initf_t initf, int search_fnum, * database; in practice, since Posix and UI have helpfully said that * getent() state is global rather than, say, per-thread or user-supplied, * we have at most one of these per nss_db_state. + * XXX ? Is this statement still true? + * + * NSS2 - a client's context is maintained as a cookie delivered by and + * passed to nscd. The cookie is a 64 bit (nssuint_t) unique opaque value + * created by nscd. + * cookie states: + * NSCD_NEW_COOKIE - cookie value uninitialized + * NSCD_LOCAL_COOKIE - setent is a local setent + * all other - NSCD unique opaque id for this setent + * A client's context is also associated with a seq_num. This is a nscd + * opaque 64 bit (nssuint_t) value passed with a cookie, and used to by nscd + * to validate the sequencing of the context. The client treats this as + * a pass through value. + * + * XXX ?? Use Cookie as cross-check info so that we can detect an + * nss_context that missed an nss_delete() or similar. */ struct nss_getent_context { int n_src; /* >= max_src ==> end of sequence */ nss_backend_t *be; struct nss_db_state *s; - /* - * XXX ?? Should contain enough cross-check info that we can detect an - * nss_context that missed an nss_delete() or similar. - */ + nssuint_t cookie; + nssuint_t seq_num; + nss_db_params_t param; }; static void nss_setent_u(nss_db_root_t *, @@ -834,7 +1312,7 @@ nss_endent(nss_db_root_t *rootp, nss_db_initf_t initf, nss_getent_t *contextpp) /* * Each of the _u versions of the nss interfaces assume that the context - * lock is held. + * lock is held. No need to divert to nscd. Private to local sequencing. */ static void @@ -864,21 +1342,31 @@ static void nss_setent_u(nss_db_root_t *rootp, nss_db_initf_t initf, nss_getent_t *contextpp) { + nss_status_t status; struct nss_db_state *s; struct nss_getent_context *contextp; nss_backend_t *be; int n_src; + /* setup process wide context while locked */ if ((contextp = contextpp->ctx) == 0) { if ((contextp = libc_malloc(sizeof (*contextp))) == 0) { return; } contextpp->ctx = contextp; + contextp->cookie = NSCD_NEW_COOKIE; /* cookie init */ + contextp->seq_num = 0; /* seq_num init */ s = 0; } else { s = contextp->s; } + /* name service cache daemon divert */ + status = _nsc_setent_u(rootp, initf, contextpp); + if (status != NSS_TRYLOCAL) + return; + + /* fall through - process locally */ if (s == 0) { NSS_LOCK_CHECK(rootp, initf, &s); if (s == 0) { @@ -935,6 +1423,7 @@ static nss_status_t nss_getent_u(nss_db_root_t *rootp, nss_db_initf_t initf, nss_getent_t *contextpp, void *args) { + nss_status_t status; struct nss_db_state *s; struct nss_getent_context *contextp; int n_src; @@ -947,6 +1436,12 @@ nss_getent_u(nss_db_root_t *rootp, nss_db_initf_t initf, return (NSS_UNAVAIL); } } + /* name service cache daemon divert */ + status = _nsc_getent_u(rootp, initf, contextpp, args); + if (status != NSS_TRYLOCAL) + return (status); + + /* fall through - process locally */ s = contextp->s; n_src = contextp->n_src; be = contextp->be; @@ -1009,12 +1504,25 @@ static void nss_endent_u(nss_db_root_t *rootp, nss_db_initf_t initf, nss_getent_t *contextpp) { + nss_status_t status; struct nss_getent_context *contextp; if ((contextp = contextpp->ctx) == 0) { /* nss_endent() on an unused context is a no-op */ return; } + + /* notify name service cache daemon */ + status = _nsc_endent_u(rootp, initf, contextpp); + if (status != NSS_TRYLOCAL) { + /* clean up */ + libc_free(contextp); + contextpp->ctx = 0; + return; + } + + /* fall through - process locally */ + /* * Existing code (BSD, SunOS) works in such a way that getXXXent() * following an endXXXent() behaves as though the user had invoked @@ -1033,3 +1541,698 @@ nss_endent_u(nss_db_root_t *rootp, nss_db_initf_t initf, libc_free(contextp); contextpp->ctx = 0; } + +/* + * pack dbd data into header + * Argment pointers assumed valid. + * poff offset position pointer + * IN = starting offset for dbd header + * OUT = starting offset for next section + */ + +static nss_status_t +nss_pack_dbd(void *buffer, size_t bufsize, nss_db_params_t *p, size_t *poff) +{ + nss_pheader_t *pbuf = (nss_pheader_t *)buffer; + nss_dbd_t *pdbd; + size_t off = *poff; + size_t len, blen; + size_t n, nc, dc; + char *bptr; + + pbuf->dbd_off = (nssuint_t)off; + bptr = (char *)buffer + off; + blen = bufsize - off; + len = sizeof (nss_dbd_t); + + n = nc = dc = 0; + if (p->name == NULL) { + errno = ERANGE; /* actually EINVAL */ + return (NSS_ERROR); + } + + /* if default config not specified, the flag should be reset */ + if (p->default_config == NULL) { + p->default_config = "<NULL>"; + p->flags = p->flags & ~NSS_USE_DEFAULT_CONFIG; + } + + n = strlen(p->name) + 1; + dc = strlen(p->default_config) + 1; + if (n < 2 || dc < 2) { /* What no DB? */ + errno = ERANGE; /* actually EINVAL */ + return (NSS_ERROR); + } + if (p->config_name != NULL) { + nc = strlen(p->config_name) + 1; + } + if ((len + n + nc + dc) >= blen) { + errno = ERANGE; /* actually EINVAL */ + return (NSS_ERROR); + } + + pdbd = (nss_dbd_t *)((void *)bptr); + bptr += len; + pdbd->flags = p->flags; + pdbd->o_name = len; + (void) strlcpy(bptr, p->name, n); + len += n; + bptr += n; + if (nc == 0) { + pdbd->o_config_name = 0; + } else { + pdbd->o_config_name = len; + (void) strlcpy(bptr, p->config_name, nc); + bptr += nc; + len += nc; + } + pdbd->o_default_config = len; + (void) strlcpy(bptr, p->default_config, dc); + len += dc; + pbuf->dbd_len = (nssuint_t)len; + off += ROUND_UP(len, sizeof (nssuint_t)); + *poff = off; + return (NSS_SUCCESS); +} + +/* + * Switch packed and _nsc (switch->nscd) interfaces + * Return: NSS_SUCCESS (OK to proceed), NSS_ERROR, NSS_NOTFOUND + */ + +/*ARGSUSED*/ +nss_status_t +nss_pack(void *buffer, size_t bufsize, nss_db_root_t *rootp, + nss_db_initf_t initf, int search_fnum, void *search_args) +{ + nss_pheader_t *pbuf = (nss_pheader_t *)buffer; + nss_XbyY_args_t *in = (nss_XbyY_args_t *)search_args; + nss_db_params_t tparam = { 0 }; + nss_status_t ret = NSS_ERROR; + const char *dbn; + size_t blen, len, off = 0; + char *bptr; + nssuint_t *uptr; + struct nss_groupsbymem *gbm; + + if (pbuf == NULL || in == NULL || initf == (nss_db_initf_t)NULL) { + errno = ERANGE; /* actually EINVAL */ + return (ret); + } + tparam.cleanup = NULL; + (*initf)(&tparam); + if ((dbn = tparam.name) == 0) { + if (tparam.cleanup != 0) + (tparam.cleanup)(&tparam); + errno = ERANGE; /* actually EINVAL */ + return (ret); + } + + /* init buffer header */ + pbuf->pbufsiz = (nssuint_t)bufsize; + pbuf->p_ruid = (uint32_t)getuid(); + pbuf->p_euid = (uint32_t)geteuid(); + pbuf->p_version = NSCD_HEADER_REV; + pbuf->p_status = 0; + pbuf->p_errno = 0; + pbuf->p_herrno = 0; + + /* possible audituser init */ + if (strcmp(dbn, NSS_DBNAM_AUTHATTR) == 0 && in->h_errno != 0) + pbuf->p_herrno = (uint32_t)in->h_errno; + + pbuf->libpriv = 0; + + off = sizeof (nss_pheader_t); + + /* setup getXbyY operation - database and sub function */ + pbuf->nss_dbop = (uint32_t)search_fnum; + ret = nss_pack_dbd(buffer, bufsize, &tparam, &off); + if (ret != NSS_SUCCESS) { + errno = ERANGE; /* actually EINVAL */ + return (ret); + } + ret = NSS_ERROR; + /* setup request key */ + pbuf->key_off = (nssuint_t)off; + bptr = (char *)buffer + off; + blen = bufsize - off; + /* use key2str if provided, else call default getXbyY packer */ + if (strcmp(dbn, NSS_DBNAM_NETGROUP) == 0) { + /* This has to run locally due to backend knowledge */ + if (search_fnum == NSS_DBOP_NETGROUP_SET) { + errno = 0; + return (NSS_TRYLOCAL); + } + /* use default packer for known getXbyY ops */ + ret = nss_default_key2str(bptr, blen, in, dbn, + search_fnum, &len); + } else if (in->key2str == NULL || + (search_fnum == NSS_DBOP_GROUP_BYMEMBER && + strcmp(dbn, NSS_DBNAM_GROUP) == 0)) { + /* use default packer for known getXbyY ops */ + ret = nss_default_key2str(bptr, blen, in, dbn, + search_fnum, &len); + } else { + ret = (*in->key2str)(bptr, blen, &in->key, &len); + } + if (tparam.cleanup != 0) + (tparam.cleanup)(&tparam); + if (ret != NSS_SUCCESS) { + errno = ERANGE; /* actually ENOMEM */ + return (ret); + } + pbuf->key_len = (nssuint_t)len; + off += ROUND_UP(len, sizeof (nssuint_t)); + + pbuf->data_off = (nssuint_t)off; + pbuf->data_len = (nssuint_t)(bufsize - off); + /* + * Prime data return with first result if + * the first result is passed in + * [_getgroupsbymember oddness] + */ + gbm = (struct nss_groupsbymem *)search_args; + if (search_fnum == NSS_DBOP_GROUP_BYMEMBER && + strcmp(dbn, NSS_DBNAM_GROUP) == 0 && gbm->numgids == 1) { + uptr = (nssuint_t *)((void *)((char *)buffer + off)); + *uptr = (nssuint_t)gbm->gid_array[0]; + } + + errno = 0; /* just in case ... */ + return (NSS_SUCCESS); +} + +/* + * Switch packed and _nsc (switch->nscd) {set/get/end}ent interfaces + * Return: NSS_SUCCESS (OK to proceed), NSS_ERROR, NSS_NOTFOUND + */ + +/*ARGSUSED*/ +nss_status_t +nss_pack_ent(void *buffer, size_t bufsize, nss_db_root_t *rootp, + nss_db_initf_t initf, nss_getent_t *contextpp) +{ + nss_pheader_t *pbuf = (nss_pheader_t *)buffer; + struct nss_getent_context *contextp = contextpp->ctx; + nss_status_t ret = NSS_ERROR; + size_t blen, len = 0, off = 0; + char *bptr; + nssuint_t *nptr; + + if (pbuf == NULL || initf == (nss_db_initf_t)NULL) { + errno = ERANGE; /* actually EINVAL */ + return (ret); + } + + /* init buffer header */ + pbuf->pbufsiz = (nssuint_t)bufsize; + pbuf->p_ruid = (uint32_t)getuid(); + pbuf->p_euid = (uint32_t)geteuid(); + pbuf->p_version = NSCD_HEADER_REV; + pbuf->p_status = 0; + pbuf->p_errno = 0; + pbuf->p_herrno = 0; + pbuf->libpriv = 0; + + off = sizeof (nss_pheader_t); + + /* setup getXXXent operation - database and sub function */ + pbuf->nss_dbop = (uint32_t)0; /* iterators have no dbop */ + ret = nss_pack_dbd(buffer, bufsize, &contextp->param, &off); + if (ret != NSS_SUCCESS) { + errno = ERANGE; /* actually EINVAL */ + return (ret); + } + ret = NSS_ERROR; + off += ROUND_UP(len, sizeof (nssuint_t)); + + pbuf->key_off = (nssuint_t)off; + bptr = (char *)buffer + off; + blen = bufsize - off; + len = (size_t)(sizeof (nssuint_t) * 2); + if (len >= blen) { + errno = ERANGE; /* actually EINVAL */ + return (ret); + } + nptr = (nssuint_t *)((void *)bptr); + *nptr++ = contextp->cookie; + *nptr = contextp->seq_num; + pbuf->key_len = (nssuint_t)len; + + off += len; + pbuf->data_off = (nssuint_t)off; + pbuf->data_len = (nssuint_t)(bufsize - off); + return (NSS_SUCCESS); +} + +/* + * Unpack packed arguments buffer + * Return: status, errnos and results from requested operation. + * + * NOTES: When getgroupsbymember is being processed in the NSCD backend, + * or via the backwards compatibility interfaces then the standard + * str2group API is used in conjunction with process_cstr. When, + * processing a returned buffer, in NSS2 the return results are the + * already digested groups array. Therefore, unpack the digested results + * back to the return buffer. + * + * Note: the digested results are nssuint_t quantities. _getgroupsbymember + * digests int quantities. Therefore convert. Assume input is in nssuint_t + * quantities. Store in an int array... Assume gid's are <= 32 bits... + */ + +/*ARGSUSED*/ +nss_status_t +nss_unpack(void *buffer, size_t bufsize, nss_db_root_t *rootp, + nss_db_initf_t initf, int search_fnum, void *search_args) +{ + nss_pheader_t *pbuf = (nss_pheader_t *)buffer; + nss_XbyY_args_t *in = (nss_XbyY_args_t *)search_args; + nss_dbd_t *pdbd; + char *dbn; + nss_status_t status; + char *buf; + int len; + int ret; + int i; + gid_t *gidp; + nssuint_t *uptr; + struct nss_groupsbymem *arg; + + + if (pbuf == NULL || in == NULL) + return (-1); + status = pbuf->p_status; + /* if error - door's switch error */ + /* extended data could contain additional information? */ + if (status != NSS_SUCCESS) { + in->h_errno = (int)pbuf->p_herrno; + if (pbuf->p_errno == ERANGE) + in->erange = 1; + return (status); + } + + if (pbuf->data_off == 0 || pbuf->data_len == 0) + return (NSS_NOTFOUND); + + buf = (char *)buffer + pbuf->data_off; + len = pbuf->data_len; + + /* sidestep odd cases */ + pdbd = (nss_dbd_t *)((void *)((char *)buffer + pbuf->dbd_off)); + dbn = (char *)pdbd + pdbd->o_name; + if (search_fnum == NSS_DBOP_GROUP_BYMEMBER) { + if (strcmp(dbn, NSS_DBNAM_GROUP) == 0) { + arg = (struct nss_groupsbymem *)in; + /* copy returned gid array from returned nscd buffer */ + i = len / sizeof (nssuint_t); + /* not enough buffer */ + if (i > arg->maxgids) { + i = arg->maxgids; + } + arg->numgids = i; + gidp = arg->gid_array; + uptr = (nssuint_t *)((void *)buf); + while (--i >= 0) + *gidp++ = (gid_t)*uptr++; + return (NSS_SUCCESS); + } + } + if (search_fnum == NSS_DBOP_NETGROUP_IN) { + if (strcmp(dbn, NSS_DBNAM_NETGROUP) == 0) { + struct nss_innetgr_args *arg = + (struct nss_innetgr_args *)in; + + if (pbuf->p_status == NSS_SUCCESS) { + arg->status = NSS_NETGR_FOUND; + return (NSS_SUCCESS); + } else { + arg->status = NSS_NETGR_NO; + return (NSS_NOTFOUND); + } + } + } + + /* process the normal cases */ + /* marshall data directly into users buffer */ + ret = (*in->str2ent)(buf, len, in->buf.result, in->buf.buffer, + in->buf.buflen); + if (ret == NSS_STR_PARSE_ERANGE) { + in->returnval = 0; + in->returnlen = 0; + in->erange = 1; + ret = NSS_NOTFOUND; + } else if (ret == NSS_STR_PARSE_SUCCESS) { + in->returnval = in->buf.result; + in->returnlen = len; + ret = NSS_SUCCESS; + } + in->h_errno = (int)pbuf->p_herrno; + return ((nss_status_t)ret); +} + +/* + * Unpack a returned packed {set,get,end}ent arguments buffer + * Return: status, errnos, cookie info and results from requested operation. + */ + +/*ARGSUSED*/ +nss_status_t +nss_unpack_ent(void *buffer, size_t bufsize, nss_db_root_t *rootp, + nss_db_initf_t initf, nss_getent_t *contextpp, void *args) +{ + nss_pheader_t *pbuf = (nss_pheader_t *)buffer; + nss_XbyY_args_t *in = (nss_XbyY_args_t *)args; + struct nss_getent_context *contextp = contextpp->ctx; + nssuint_t *nptr; + nssuint_t cookie; + nss_status_t status; + char *buf; + int len; + int ret; + + if (pbuf == NULL) + return (-1); + status = pbuf->p_status; + /* if error - door's switch error */ + /* extended data could contain additional information? */ + if (status != NSS_SUCCESS) + return (status); + + /* unpack assigned cookie from SET/GET/END request */ + if (pbuf->key_off == 0 || + pbuf->key_len != (sizeof (nssuint_t) * 2)) + return (NSS_NOTFOUND); + + nptr = (nssuint_t *)((void *)((char *)buffer + pbuf->key_off)); + cookie = contextp->cookie; + if (cookie != NSCD_NEW_COOKIE && cookie != *nptr) { + /* Should either be new or a match, else error */ + return (NSS_NOTFOUND); + } + /* save away for the next ent request */ + contextp->cookie = *nptr++; + contextp->seq_num = *nptr; + + /* All done if no marshalling is expected {set,end}ent */ + if (args == NULL) + return (NSS_SUCCESS); + + /* unmarshall the data */ + if (pbuf->data_off == 0 || pbuf->data_len == 0) + return (NSS_NOTFOUND); + buf = (char *)buffer + pbuf->data_off; + + len = pbuf->data_len; + + /* marshall data directly into users buffer */ + ret = (*in->str2ent)(buf, len, in->buf.result, in->buf.buffer, + in->buf.buflen); + if (ret == NSS_STR_PARSE_ERANGE) { + in->returnval = 0; + in->returnlen = 0; + in->erange = 1; + } else if (ret == NSS_STR_PARSE_SUCCESS) { + in->returnval = in->buf.result; + in->returnlen = len; + } + in->h_errno = (int)pbuf->p_herrno; + return ((nss_status_t)ret); +} + +/* + * Start of _nsc_{search|setent_u|getent_u|endent_u} NSCD interposition funcs + */ + +nss_status_t +_nsc_search(nss_db_root_t *rootp, nss_db_initf_t initf, int search_fnum, + void *search_args) +{ + nss_pheader_t *pbuf; + void *doorptr = NULL; + size_t bufsize = 0; + size_t datasize = 0; + nss_status_t status; + + if (_nsc_proc_is_cache() > 0) { + /* internal nscd call - don't use the door */ + return (NSS_TRYLOCAL); + } + + /* standard client calls nscd code */ + if (search_args == NULL) + return (NSS_NOTFOUND); + + /* get the door buffer & configured size */ + bufsize = ((nss_XbyY_args_t *)search_args)->buf.buflen; + if (_nsc_getdoorbuf(&doorptr, &bufsize) != 0) + return (NSS_TRYLOCAL); + if (doorptr == NULL || bufsize == 0) + return (NSS_TRYLOCAL); + + pbuf = (nss_pheader_t *)doorptr; + /* pack argument and request into door buffer */ + pbuf->nsc_callnumber = NSCD_SEARCH; + /* copy relevant door request info into door buffer */ + status = nss_pack((void *)pbuf, bufsize, rootp, + initf, search_fnum, search_args); + + /* Packing error return error results */ + if (status != NSS_SUCCESS) + return (status); + + /* transfer packed switch request to nscd via door */ + /* data_off can be used because it is header+dbd_len+key_len */ + datasize = pbuf->data_off; + status = _nsc_trydoorcall_ext(&doorptr, &bufsize, &datasize); + + /* If unsuccessful fallback to standard nss logic */ + if (status != NSS_SUCCESS) { + /* + * check if doors reallocated the memory underneath us + * if they did munmap it or suffer a memory leak + */ + if (doorptr != (void *)pbuf) { + _nsc_resizedoorbuf(bufsize); + munmap((void *)doorptr, bufsize); + } + return (NSS_TRYLOCAL); + } + + /* unpack and marshall data/errors to user structure */ + /* set any error conditions */ + status = nss_unpack((void *)doorptr, bufsize, rootp, initf, + search_fnum, search_args); + /* + * check if doors reallocated the memory underneath us + * if they did munmap it or suffer a memory leak + */ + if (doorptr != (void *)pbuf) { + _nsc_resizedoorbuf(bufsize); + munmap((void *)doorptr, bufsize); + } + return (status); +} + +/* + * contact nscd for a cookie or to reset an existing cookie + * if nscd fails (NSS_TRYLOCAL) then set cookie to -1 and + * continue diverting to local + */ +nss_status_t +_nsc_setent_u(nss_db_root_t *rootp, nss_db_initf_t initf, + nss_getent_t *contextpp) +{ + nss_status_t status = NSS_TRYLOCAL; + struct nss_getent_context *contextp = contextpp->ctx; + nss_pheader_t *pbuf; + void *doorptr = NULL; + size_t bufsize = 0; + size_t datasize = 0; + + /* return if already in local mode */ + if (contextp->cookie == NSCD_LOCAL_COOKIE) + return (NSS_TRYLOCAL); + + if (_nsc_proc_is_cache() > 0) { + /* internal nscd call - don't try to use the door */ + contextp->cookie = NSCD_LOCAL_COOKIE; + return (NSS_TRYLOCAL); + } + + /* get the door buffer & configured size */ + if (_nsc_getdoorbuf(&doorptr, &bufsize) != 0) { + contextp->cookie = NSCD_LOCAL_COOKIE; + return (NSS_TRYLOCAL); + } + if (doorptr == NULL || bufsize == 0) { + contextp->cookie = NSCD_LOCAL_COOKIE; + return (NSS_TRYLOCAL); + } + + pbuf = (nss_pheader_t *)doorptr; + pbuf->nsc_callnumber = NSCD_SETENT; + + contextp->param.cleanup = NULL; + (*initf)(&contextp->param); + if (contextp->param.name == 0) { + if (contextp->param.cleanup != 0) + (contextp->param.cleanup)(&contextp->param); + errno = ERANGE; /* actually EINVAL */ + return (NSS_ERROR); + } + + /* pack relevant setent request info into door buffer */ + status = nss_pack_ent((void *)pbuf, bufsize, rootp, + initf, contextpp); + if (status != NSS_SUCCESS) + return (status); + + /* transfer packed switch request to nscd via door */ + /* data_off can be used because it is header+dbd_len+key_len */ + datasize = pbuf->data_off; + status = _nsc_trydoorcall_ext(&doorptr, &bufsize, &datasize); + + /* If fallback to standard nss logic (door failure) if possible */ + if (status != NSS_SUCCESS) { + if (contextp->cookie == NSCD_NEW_COOKIE) { + contextp->cookie = NSCD_LOCAL_COOKIE; + return (NSS_TRYLOCAL); + } + return (NSS_UNAVAIL); + } + /* unpack returned cookie stash it away */ + status = nss_unpack_ent((void *)doorptr, bufsize, rootp, + initf, contextpp, NULL); + /* + * check if doors reallocated the memory underneath us + * if they did munmap it or suffer a memory leak + */ + if (doorptr != (void *)pbuf) { + _nsc_resizedoorbuf(bufsize); + munmap((void *)doorptr, bufsize); + } + return (status); +} + +nss_status_t +_nsc_getent_u(nss_db_root_t *rootp, nss_db_initf_t initf, + nss_getent_t *contextpp, void *args) +{ + nss_status_t status = NSS_TRYLOCAL; + struct nss_getent_context *contextp = contextpp->ctx; + nss_pheader_t *pbuf; + void *doorptr = NULL; + size_t bufsize = 0; + size_t datasize = 0; + + /* return if already in local mode */ + if (contextp->cookie == NSCD_LOCAL_COOKIE) + return (NSS_TRYLOCAL); + + /* _nsc_setent_u already checked for nscd local case ... proceed */ + if (args == NULL) + return (NSS_NOTFOUND); + + /* get the door buffer & configured size */ + bufsize = ((nss_XbyY_args_t *)args)->buf.buflen; + if (_nsc_getdoorbuf(&doorptr, &bufsize) != 0) + return (NSS_UNAVAIL); + if (doorptr == NULL || bufsize == 0) + return (NSS_UNAVAIL); + + pbuf = (nss_pheader_t *)doorptr; + pbuf->nsc_callnumber = NSCD_GETENT; + + /* pack relevant setent request info into door buffer */ + status = nss_pack_ent((void *)pbuf, bufsize, rootp, + initf, contextpp); + if (status != NSS_SUCCESS) + return (status); + + /* transfer packed switch request to nscd via door */ + /* data_off can be used because it is header+dbd_len+key_len */ + datasize = pbuf->data_off; + status = _nsc_trydoorcall_ext(&doorptr, &bufsize, &datasize); + + /* If fallback to standard nss logic (door failure) if possible */ + if (status != NSS_SUCCESS) { + if (contextp->cookie == NSCD_NEW_COOKIE) { + contextp->cookie = NSCD_LOCAL_COOKIE; + return (NSS_TRYLOCAL); + } + return (NSS_UNAVAIL); + } + /* check error, unpack and process results */ + status = nss_unpack_ent((void *)doorptr, bufsize, rootp, + initf, contextpp, args); + /* + * check if doors reallocated the memory underneath us + * if they did munmap it or suffer a memory leak + */ + if (doorptr != (void *)pbuf) { + _nsc_resizedoorbuf(bufsize); + munmap((void *)doorptr, bufsize); + } + return (status); +} + +nss_status_t +_nsc_endent_u(nss_db_root_t *rootp, nss_db_initf_t initf, + nss_getent_t *contextpp) +{ + nss_status_t status = NSS_TRYLOCAL; + struct nss_getent_context *contextp = contextpp->ctx; + nss_pheader_t *pbuf; + void *doorptr = NULL; + size_t bufsize = 0; + size_t datasize = 0; + + /* return if already in local mode */ + if (contextp->cookie == NSCD_LOCAL_COOKIE) + return (NSS_TRYLOCAL); + + /* _nsc_setent_u already checked for nscd local case ... proceed */ + + /* get the door buffer & configured size */ + if (_nsc_getdoorbuf(&doorptr, &bufsize) != 0) + return (NSS_UNAVAIL); + if (doorptr == NULL || bufsize == 0) + return (NSS_UNAVAIL); + + /* pack up a NSCD_ENDGET request passing in the cookie */ + pbuf = (nss_pheader_t *)doorptr; + pbuf->nsc_callnumber = NSCD_ENDENT; + + /* pack relevant setent request info into door buffer */ + status = nss_pack_ent((void *)pbuf, bufsize, rootp, + initf, contextpp); + if (status != NSS_SUCCESS) + return (status); + + /* transfer packed switch request to nscd via door */ + /* data_off can be used because it is header+dbd_len+key_len */ + datasize = pbuf->data_off; + (void) _nsc_trydoorcall_ext(&doorptr, &bufsize, &datasize); + + /* error codes & unpacking ret values don't matter. We're done */ + + /* + * check if doors reallocated the memory underneath us + * if they did munmap it or suffer a memory leak + */ + if (doorptr != (void *)pbuf) { + _nsc_resizedoorbuf(bufsize); + munmap((void *)doorptr, bufsize); + } + + /* clean up initf setup */ + if (contextp->param.cleanup != 0) + (contextp->param.cleanup)(&contextp->param); + contextp->param.cleanup = NULL; + + /* clear cookie */ + contextp->cookie = NSCD_NEW_COOKIE; + return (NSS_SUCCESS); +} diff --git a/usr/src/lib/libc/port/gen/nss_dbdefs.c b/usr/src/lib/libc/port/gen/nss_dbdefs.c index 510c0bcbb6..687c3a9711 100644 --- a/usr/src/lib/libc/port/gen/nss_dbdefs.c +++ b/usr/src/lib/libc/port/gen/nss_dbdefs.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,19 +19,34 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #pragma ident "%Z%%M% %I% %E% SMI" #include "synonyms.h" +#include <mtlib.h> #include <ctype.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <nss_dbdefs.h> #include <limits.h> +#include <dlfcn.h> +#include <link.h> +#include <thread.h> +/* headers for key2str/str2key routines */ +#include <sys/ethernet.h> +#include <exec_attr.h> +#include <grp.h> + +/* + * functions in nss_dbdefs.c deal more with the mechanics of + * the data structures like nss_XbyY_args_t and the interaction + * with the packed buffers etc. versus the mechanics of the + * actual policy component operations such as nss_search sequencing. + */ /* * ALIGN? is there an official definition of this? @@ -165,3 +179,1104 @@ _nss_netdb_aliases(const char *instr, int lenstr, char *buffer, int buflen) *aliasp++ = 0; return (alias_start); } + + +/* + * pack well known getXbyY keys to packed buffer prior to the door_call + * to nscd. Some consideration is given to ordering the tests based on + * usage. Note: buf is nssuint_t aligned. + */ + +typedef struct { + const char *name; /* NSS_DBNAM_* */ + const char *defconf; /* NSS_DEFCONF_* */ + const char *initfn; /* init function name */ + const char *strfn; /* str2X function name */ + const char *cstrfn; /* cstr2X function name */ + uint32_t dbop; /* NSS_DBOP_* */ + const char *tostr; /* key2str cvt str */ +} getXbyY_to_dbop_t; + +#define NSS_MK_GETXYDBOP(x, y, f, e) \ + { NSS_DBNAM_##x, NSS_DEFCONF_##x, "_nss_initf_" f, "str2" f, \ + NULL, NSS_DBOP_##x##_##y, (e) } + +#define NSS_MK_GETXYDBOPA(x, a, f, e) \ + { NSS_DBNAM_##x, NSS_DEFCONF_##x, "_nss_initf_" f, "str2" f, \ + NULL, NSS_DBOP_##a, (e) } + +#define NSS_MK_GETXYDBOPB(x, b, a, f, s, e) \ + { NSS_DBNAM_##x, NSS_DEFCONF_##b, "_nss_initf_" f, s, \ + NULL, NSS_DBOP_##a, (e) } + +#define NSS_MK_GETXYDBOPC(x, a, f, s, e) \ + { NSS_DBNAM_##x, NSS_DEFCONF_##x, "_nss_initf_" f, s, \ + NULL, NSS_DBOP_##x##_##a, (e) } + +#define NSS_MK_GETXYDBOPD(x, y, i, f, e) \ + { NSS_DBNAM_##x, NSS_DEFCONF_##x, "_nss_initf_" i, "str2" f, \ + NULL, NSS_DBOP_##x##_##y, (e) } + +#define NSS_MK_GETXYDBOPCSTR(x, a, f, s, e) \ + { NSS_DBNAM_##x, NSS_DEFCONF_##x, "_nss_initf_" f, s, \ + "process_cstr", NSS_DBOP_##x##_##a, (e) } + +/* + * The getXbyY_to_dbop structure is hashed on first call in order to + * reduce the search time for the well known getXbyY operations. + * A binary search was not fast enough. There were on average + * 3-4 tests (strcmps) per getXbyY call. + * + * DBOP_PRIME_HASH must be a prime number (reasonably small) but that + * is sufficient to uniquely map the entries in the following table + * without collision. + * + * The DBOP_PRIME_HASH was selected as the smallest hash value + * for this table without collisions. Changing this table WILL + * necessitate re-testing for possible collisions. + */ + +#define DBOP_PRIME_HASH 223 +#define DBOP_HASH_TAG 0xf0000000 +static int getXbyYdbopHASH[DBOP_PRIME_HASH] = { 0 }; +static mutex_t getXbydbop_hash_lock = DEFAULTMUTEX; +static int getXbyYdbop_hashed = 0; + +static getXbyY_to_dbop_t getXbyY_to_dbop[] = { + /* NSS_MK_GETXYDBOP(ALIASES, ?, ?), */ + NSS_MK_GETXYDBOPD(AUDITUSER, BYNAME, "auuser", "audituser", "n"), + NSS_MK_GETXYDBOP(AUTHATTR, BYNAME, "authattr", "n"), + /* NSS_MK_GETXYDBOP(AUTOMOUNT, ?, ?), */ + NSS_MK_GETXYDBOP(BOOTPARAMS, BYNAME, "bootparams", "n"), + NSS_MK_GETXYDBOPC(ETHERS, HOSTTON, "ethers", "str2ether", "n"), + NSS_MK_GETXYDBOPC(ETHERS, NTOHOST, "ethers", "str2ether", "e"), + NSS_MK_GETXYDBOP(EXECATTR, BYNAME, "execattr", "A"), + NSS_MK_GETXYDBOP(EXECATTR, BYID, "execattr", "A"), + NSS_MK_GETXYDBOP(EXECATTR, BYNAMEID, "execattr", "A"), + NSS_MK_GETXYDBOP(GROUP, BYNAME, "group", "n"), + NSS_MK_GETXYDBOP(GROUP, BYGID, "group", "g"), + NSS_MK_GETXYDBOPCSTR(GROUP, BYMEMBER, "group", "str2group", "I"), + NSS_MK_GETXYDBOPC(HOSTS, BYNAME, "hosts", "str2hostent", "n"), + NSS_MK_GETXYDBOPC(HOSTS, BYADDR, "hosts", "str2hostent", "h"), + NSS_MK_GETXYDBOPC(IPNODES, BYNAME, "ipnodes", "str2hostent", "i"), + NSS_MK_GETXYDBOPC(IPNODES, BYADDR, "ipnodes", "str2hostent", "h"), + NSS_MK_GETXYDBOP(NETGROUP, IN, "netgroup", "t"), + NSS_MK_GETXYDBOP(NETGROUP, SET, "netgroup", "T"), + NSS_MK_GETXYDBOPC(NETMASKS, BYNET, "netmasks", "str2addr", "n"), + NSS_MK_GETXYDBOPC(NETWORKS, BYNAME, "net", "str2netent", "n"), + NSS_MK_GETXYDBOPC(NETWORKS, BYADDR, "net", "str2netent", "a"), + NSS_MK_GETXYDBOP(PASSWD, BYNAME, "passwd", "n"), + NSS_MK_GETXYDBOP(PASSWD, BYUID, "passwd", "u"), + NSS_MK_GETXYDBOP(PRINTERS, BYNAME, "printers", "n"), + NSS_MK_GETXYDBOP(PROFATTR, BYNAME, "profattr", "n"), + NSS_MK_GETXYDBOP(PROJECT, BYNAME, "project", "n"), + NSS_MK_GETXYDBOP(PROJECT, BYID, "project", "p"), + NSS_MK_GETXYDBOPC(PROTOCOLS, BYNAME, "proto", "str2protoent", "n"), + NSS_MK_GETXYDBOPC(PROTOCOLS, BYNUMBER, "proto", "str2protoent", "N"), + NSS_MK_GETXYDBOPA(PUBLICKEY, KEYS_BYNAME, "publickey", "k"), + NSS_MK_GETXYDBOPC(RPC, BYNAME, "rpc", "str2rpcent", "n"), + NSS_MK_GETXYDBOPC(RPC, BYNUMBER, "rpc", "str2rpcent", "N"), + NSS_MK_GETXYDBOPC(SERVICES, BYNAME, "services", "str2servent", "s"), + NSS_MK_GETXYDBOPC(SERVICES, BYPORT, "services", "str2servent", "S"), + NSS_MK_GETXYDBOPB(SHADOW, PASSWD, PASSWD_BYNAME, "shadow", + "str2spwd", "n"), + NSS_MK_GETXYDBOPC(TSOL_RH, BYADDR, "tsol_rh", "str_to_rhstr", "h"), + NSS_MK_GETXYDBOPC(TSOL_TP, BYNAME, "tsol_tp", "str_to_tpstr", "n"), + NSS_MK_GETXYDBOPC(TSOL_ZC, BYNAME, "tsol_zc", "str_to_zcstr", "n"), + NSS_MK_GETXYDBOP(USERATTR, BYNAME, "userattr", "n"), +}; + +static int +nss_dbop_search(const char *name, uint32_t dbop) +{ + getXbyY_to_dbop_t *hptr; + int count = (sizeof (getXbyY_to_dbop) / sizeof (getXbyY_to_dbop_t)); + uint32_t hval, g; + const char *cp; + int i, idx; + + /* Uses a table size is known to have no collisions */ + if (getXbyYdbop_hashed == 0) { + lmutex_lock(&getXbydbop_hash_lock); + if (getXbyYdbop_hashed == 0) { + for (i = 0; i < count; i++) { + cp = getXbyY_to_dbop[i].name; + hval = 0; + while (*cp) { + hval = (hval << 4) + *cp++; + if ((g = (hval & 0xf00000000)) != 0) + hval ^= g >> 24; + hval &= ~g; + } + hval += getXbyY_to_dbop[i].dbop; + hval %= DBOP_PRIME_HASH; + if (getXbyYdbopHASH[hval] != 0) { + /* hash table collision-see above */ + lmutex_unlock(&getXbydbop_hash_lock); + return (-1); + } + getXbyYdbopHASH[hval] = i | DBOP_HASH_TAG; + } + getXbyYdbop_hashed = 1; + } + lmutex_unlock(&getXbydbop_hash_lock); + } + cp = name; + hval = 0; + while (*cp) { + hval = (hval << 4) + *cp++; + if ((g = (hval & 0xf00000000)) != 0) + hval ^= g >> 24; + hval &= ~g; + } + hval += dbop; + hval %= DBOP_PRIME_HASH; + idx = getXbyYdbopHASH[hval]; + if ((idx & DBOP_HASH_TAG) != DBOP_HASH_TAG) + return (-1); + idx &= ~DBOP_HASH_TAG; + if (idx >= count) + return (-1); + hptr = &getXbyY_to_dbop[idx]; + if (hptr->dbop != dbop || strcmp(name, hptr->name) != 0) + return (-1); + return (idx); +} + +/* + * nss_pack_key2str + * Private key to string packing function for getXbyY routines + * This routine performs a printf like parse over the argument + * key, given a string of items to pack and assembles the key in + * the packed structure. This routine is called (currently) by + * nss_default_key2str, but will be used by other external + * APIs in the future. + * + * buffer - Start of the key buffer location [in packed buffer] + * length - Length of key buffer component + * Key offsets are relative to start of key buffer location. + * + * Pack fields Key + * key.name n + * key.number N + * key.uid u + * key.gid g + * key.hostaddr h + * key.ipnode i + * key.projid p + * key.serv(name) s + * key.serv(port) S + * key.ether e + * key.pkey k + * key.netaddr a + * key.attrp A + * groupsbymember I + * innetgr_args t + * setnetgr_args T + */ + +/*ARGSUSED*/ +static nss_status_t +nss_pack_key2str(void *buffer, size_t length, nss_XbyY_args_t *arg, + const char *dbname, int dbop, size_t *rlen, const char *typestr) +{ + int i, j; + size_t len, len2, len3, len4, len5, slop; + nssuint_t *uptr, offv, offc; + struct nss_setnetgrent_args *sng; + struct nss_innetgr_args *ing; + struct nss_groupsbymem *gbm; + char **cv, *dptr; + nss_pnetgr_t *pptr; + _priv_execattr *pe; + + if (buffer == NULL || length == 0 || arg == NULL || + dbname == NULL || rlen == NULL || typestr == NULL) + return (NSS_ERROR); + + while (typestr && *typestr) { + switch (*typestr++) { + case 'n': + if (arg->key.name == NULL) + return (NSS_NOTFOUND); + len = strlen(arg->key.name) + 1; + if (len >= length) + return (NSS_ERROR); + (void) strlcpy(buffer, arg->key.name, len); + *rlen = len; + break; + case 'N': + len = sizeof (nssuint_t); + if (len >= length) + return (NSS_ERROR); + *(nssuint_t *)buffer = (nssuint_t)arg->key.number; + *rlen = len; + break; + case 'u': + len = sizeof (nssuint_t); + if (len >= length) + return (NSS_ERROR); + *(nssuint_t *)buffer = (nssuint_t)arg->key.uid; + *rlen = len; + break; + case 'g': + len = sizeof (nssuint_t); + if (len >= length) + return (NSS_ERROR); + *(nssuint_t *)buffer = (nssuint_t)arg->key.gid; + *rlen = len; + break; + case 'h': + if (arg->key.hostaddr.addr == NULL) + return (-1); + len = arg->key.hostaddr.len; + len = ROUND_UP(len, sizeof (nssuint_t)); + len2 = (sizeof (nssuint_t) * 2) + len; + if (len2 >= length) + return (NSS_ERROR); + *(nssuint_t *)buffer = + (nssuint_t)arg->key.hostaddr.len; + buffer = (void *)((char *)buffer + sizeof (nssuint_t)); + *(nssuint_t *)buffer = + (nssuint_t)arg->key.hostaddr.type; + buffer = (void *)((char *)buffer + sizeof (nssuint_t)); + (void) memcpy(buffer, arg->key.hostaddr.addr, + arg->key.hostaddr.len); + *rlen = len2; + break; + case 'i': + if (arg->key.ipnode.name == NULL) + return (NSS_NOTFOUND); + len = strlen(arg->key.ipnode.name) + 1; + len = ROUND_UP(len, sizeof (nssuint_t)); + len2 = (sizeof (nssuint_t) * 2) + len; + if (len2 >= length) + return (NSS_ERROR); + *(nssuint_t *)buffer = + (nssuint_t)arg->key.ipnode.af_family; + buffer = (void *)((char *)buffer + sizeof (nssuint_t)); + *(nssuint_t *)buffer = + (nssuint_t)arg->key.ipnode.flags; + buffer = (void *)((char *)buffer + sizeof (nssuint_t)); + (void) strlcpy(buffer, arg->key.ipnode.name, len); + *rlen = len2; + break; + case 'p': + len = sizeof (nssuint_t); + if (len >= length) + return (NSS_ERROR); + *(nssuint_t *)buffer = (nssuint_t)arg->key.projid; + *rlen = len; + break; + case 's': + if (arg->key.serv.serv.name == NULL) + return (NSS_NOTFOUND); + len = strlen(arg->key.serv.serv.name) + 1; + len2 = 1; + if (arg->key.serv.proto != NULL) + len2 += strlen(arg->key.serv.proto); + len3 = len + len2; + len3 = ROUND_UP(len3, sizeof (nssuint_t)); + if (len3 >= length) + return (NSS_ERROR); + (void) strlcpy(buffer, arg->key.serv.serv.name, len); + buffer = (void *)((char *)buffer + len); + if (len2 > 1) + (void) strlcpy(buffer, arg->key.serv.proto, + len2); + else + *(char *)buffer = '\0'; + *rlen = len3; + break; + case 'S': + len2 = 0; + if (arg->key.serv.proto != NULL) + len2 = strlen(arg->key.serv.proto) + 1; + len = sizeof (nssuint_t) + len2; + if (len >= length) + return (NSS_ERROR); + uptr = (nssuint_t *)buffer; + *uptr++ = (nssuint_t)arg->key.serv.serv.port; + if (len2) { + (void) strlcpy((char *)uptr, + arg->key.serv.proto, len2); + } + *rlen = len; + break; + case 'e': + if (arg->key.ether == NULL) + return (NSS_NOTFOUND); + len = sizeof (struct ether_addr); + len = ROUND_UP(len, sizeof (nssuint_t)); + if (len >= length) + return (NSS_ERROR); + *(struct ether_addr *)buffer = + *(struct ether_addr *)arg->key.ether; + *rlen = len; + break; + case 'k': + if (arg->key.pkey.name == NULL || + arg->key.pkey.keytype == NULL) + return (NSS_NOTFOUND); + len = strlen(arg->key.pkey.name) + 1; + len2 = strlen(arg->key.pkey.keytype) + 1; + len3 = len + len2; + len3 = ROUND_UP(len3, sizeof (nssuint_t)); + if (len3 >= length) + return (NSS_ERROR); + (void) strlcpy(buffer, arg->key.pkey.name, len); + buffer = (void *)((char *)buffer + len); + (void) strlcpy(buffer, arg->key.pkey.keytype, len2); + *rlen = len3; + break; + case 'a': + uptr = (nssuint_t *)buffer; + len = sizeof (nssuint_t) * 2; + if (len >= length) + return (NSS_ERROR); + *uptr++ = (nssuint_t)arg->key.netaddr.net; + *uptr++ = (nssuint_t)arg->key.netaddr.type; + *rlen = len; + break; + case 'A': + pe = (_priv_execattr *)(arg->key.attrp); + if (pe == NULL) + return (NSS_NOTFOUND); + /* for search flag */ + len = sizeof (nssuint_t); + /* for sizeof (_priv_execattr) static buffer */ + /* Plus lots of slop just in case... */ + slop = sizeof (nssuint_t) * 16; + len += slop; + + len2 = len3 = len4 = len5 = 1; + if (pe->name != NULL) + len2 = strlen(pe->name) + 1; + if (pe->type != NULL) + len3 = strlen(pe->type) + 1; + if (pe->id != NULL) + len4 = strlen(pe->id) + 1; + if (pe->policy != NULL) + len5 = strlen(pe->policy) + 1; + /* head_exec, prev_exec - are client side only... */ + len += len2 + len3 + len4 + len5; + len = ROUND_UP(len, sizeof (nssuint_t)); + if (len >= length) + return (NSS_ERROR); + (void) memset((void *)buffer, 0, slop); + uptr = (nssuint_t *)((void *)((char *)buffer + slop)); + *uptr++ = (nssuint_t)pe->search_flag; + dptr = (char *)uptr; + if (len2 == 1) + *dptr++ = '\0'; + else { + (void) strlcpy(dptr, pe->name, len2); + dptr += len2; + } + if (len3 == 1) + *dptr++ = '\0'; + else { + (void) strlcpy(dptr, pe->type, len3); + dptr += len3; + } + if (len4 == 1) + *dptr++ = '\0'; + else { + (void) strlcpy(dptr, pe->id, len4); + dptr += len4; + } + if (len5 == 1) + *dptr++ = '\0'; + else + (void) strlcpy(dptr, pe->policy, len5); + *rlen = len; + break; + case 'I': + gbm = (struct nss_groupsbymem *)arg; + if (gbm->username == NULL) + return (NSS_NOTFOUND); + len = strlen(gbm->username) + 1; + len2 = sizeof (nssuint_t) * 4; + len2 += ROUND_UP(len, sizeof (nssuint_t)); + if (len2 >= length) + return (NSS_ERROR); + uptr = (nssuint_t *)buffer; + *uptr++ = (nssuint_t)gbm->force_slow_way; + *uptr++ = (nssuint_t)gbm->maxgids; + *uptr++ = (nssuint_t)gbm->numgids; + if (gbm->numgids == 1) { + *uptr++ = (nssuint_t)gbm->gid_array[0]; + } else { + *uptr++ = (nssuint_t)0; + } + (void) strlcpy((void *)uptr, gbm->username, len); + *rlen = len2; + break; + case 't': + pptr = (nss_pnetgr_t *)buffer; + ing = (struct nss_innetgr_args *)arg; + len = sizeof (nss_pnetgr_t); + len2 = ing->arg[NSS_NETGR_MACHINE].argc + + ing->arg[NSS_NETGR_USER].argc + + ing->arg[NSS_NETGR_DOMAIN].argc + + ing->groups.argc; + len2 *= sizeof (nssuint_t); + len3 = 0; + for (j = 0; j < NSS_NETGR_N; j++) { + cv = ing->arg[j].argv; + for (i = ing->arg[j].argc; --i >= 0; ) { + if (*cv) + len3 += strlen(*cv++) + 1; + } + } + cv = ing->groups.argv; + for (i = ing->groups.argc; --i >= 0; ) { + if (*cv) + len3 += strlen(*cv++) + 1; + } + len3 = ROUND_UP(len3, sizeof (nssuint_t)); + /* + * Double argv space. Reason: + * First 1/2 offsets + * Second 1/2 for client side pointer arrays + * resolves malloc/free issues with unpacked argvs + */ + if ((len + (len2 << 1) + len3) >= length) + return (NSS_ERROR); + *rlen = len + (len2 << 1) + len3; + + pptr->machine_argc = ing->arg[NSS_NETGR_MACHINE].argc; + pptr->user_argc = ing->arg[NSS_NETGR_USER].argc; + pptr->domain_argc = ing->arg[NSS_NETGR_DOMAIN].argc; + pptr->groups_argc = ing->groups.argc; + offv = len; + uptr = (nssuint_t *)((void *)((char *)buffer + offv)); + offc = len + (len2 << 1); + dptr = (char *)buffer + offc; + if (pptr->machine_argc == 0) { + pptr->machine_offv = (nssuint_t)0; + } else { + pptr->machine_offv = offv; + cv = ing->arg[NSS_NETGR_MACHINE].argv; + i = pptr->machine_argc; + offv += sizeof (nssuint_t) * i; + for (; --i >= 0; ) { + *uptr++ = offc; + len3 = strlen(*cv) + 1; + (void) strlcpy(dptr, *cv++, len3); + offc += len3; + dptr += len3; + } + } + if (pptr->user_argc == 0) { + pptr->user_offv = (nssuint_t)0; + } else { + pptr->user_offv = offv; + cv = ing->arg[NSS_NETGR_USER].argv; + i = pptr->user_argc; + offv += sizeof (nssuint_t) * i; + for (; --i >= 0; ) { + *uptr++ = offc; + len3 = strlen(*cv) + 1; + (void) strlcpy(dptr, *cv++, len3); + offc += len3; + dptr += len3; + } + } + if (pptr->domain_argc == 0) { + pptr->domain_offv = (nssuint_t)0; + } else { + pptr->domain_offv = offv; + cv = ing->arg[NSS_NETGR_DOMAIN].argv; + i = pptr->domain_argc; + offv += sizeof (nssuint_t) * i; + for (; --i >= 0; ) { + *uptr++ = offc; + len3 = strlen(*cv) + 1; + (void) strlcpy(dptr, *cv++, len3); + offc += len3; + dptr += len3; + } + } + if (pptr->groups_argc == 0) { + pptr->groups_offv = (nssuint_t)0; + } else { + pptr->groups_offv = offv; + cv = ing->groups.argv; + i = pptr->groups_argc; + offv += sizeof (nssuint_t) * i; + for (; --i >= 0; ) { + *uptr++ = offc; + len3 = strlen(*cv) + 1; + (void) strlcpy(dptr, *cv++, len3); + offc += len3; + dptr += len3; + } + } + break; + case 'T': + sng = (struct nss_setnetgrent_args *)arg; + if (sng->netgroup == NULL) + return (NSS_NOTFOUND); + len = strlen(sng->netgroup) + 1; + if (len >= length) + return (NSS_ERROR); + (void) strlcpy(buffer, sng->netgroup, len); + *rlen = len; + break; + default: + return (NSS_ERROR); + } + } + return (NSS_SUCCESS); +} + +nss_status_t +nss_default_key2str(void *buffer, size_t length, nss_XbyY_args_t *arg, + const char *dbname, int dbop, size_t *rlen) +{ + int index; + + if (buffer == NULL || length == 0 || arg == NULL || + dbname == NULL || rlen == NULL) + return (NSS_ERROR); + + /* + * If this is not one of the well known getXbyYs + * (IE _printers special processing etc.) use a + * local (non-nscd) getXbyY lookup. + */ + if ((index = nss_dbop_search(dbname, (uint32_t)dbop)) < 0) + return (NSS_TRYLOCAL); + + return (nss_pack_key2str(buffer, length, arg, dbname, + dbop, rlen, getXbyY_to_dbop[index].tostr)); +} + +/*ARGSUSED*/ +void +nss_packed_set_status(void *buffer, size_t length, nss_status_t status, + nss_XbyY_args_t *arg) +{ + nss_pheader_t *pbuf = (nss_pheader_t *)buffer; + nss_dbd_t *pdbd; + char *dbn; + + /* sidestep odd cases */ + pdbd = (nss_dbd_t *)((void *)((char *)buffer + pbuf->dbd_off)); + dbn = (char *)pdbd + pdbd->o_name; + if (pbuf->nss_dbop == NSS_DBOP_GROUP_BYMEMBER) { + if (strcmp(dbn, NSS_DBNAM_GROUP) == 0) { + struct nss_groupsbymem *in = + (struct nss_groupsbymem *)arg; + + if (in->numgids >= 0) { + pbuf->p_status = NSS_SUCCESS; + pbuf->data_len = in->numgids * + sizeof (nssuint_t); + pbuf->p_herrno = 0; + } else { + pbuf->p_status = status; + pbuf->p_errno = errno; + pbuf->data_len = 0; + pbuf->p_herrno = (uint32_t)arg->h_errno; + } + return; + } + } + if (pbuf->nss_dbop == NSS_DBOP_NETGROUP_IN) { + if (strcmp(dbn, NSS_DBNAM_NETGROUP) == 0) { + struct nss_innetgr_args *in = + (struct nss_innetgr_args *)arg; + + /* tell nss_unpack() operation is successful */ + pbuf->data_len = 1; + + if (in->status == NSS_NETGR_FOUND) { + pbuf->p_status = NSS_SUCCESS; + } else { + pbuf->p_status = NSS_NOTFOUND; + pbuf->p_errno = errno; + } + return; + } + } + + /* process normal cases */ + if ((pbuf->p_status = status) != NSS_SUCCESS) { + if (arg->erange == 1) + pbuf->p_errno = ERANGE; + else + pbuf->p_errno = errno; + } else + pbuf->p_errno = 0; + if (arg != NULL) { + pbuf->p_herrno = (uint32_t)arg->h_errno; + pbuf->data_len = (nssuint_t)arg->returnlen; + } else { + pbuf->p_herrno = 0; + pbuf->data_len = 0; + } +} + +/* + * nss_upack_key2arg + * Private string to key unpacking function for getXbyY routines + * This routine performs a scanf/printf like parse over the packed + * string, to uppack and re-assemble the key in the args structure. + * + * buffer - Start of the key buffer location [in packed buffer] + * length - Length of key buffer component + * Key offsets are relative to start of key buffer location. + * + * Unpack fields Key + * key.name n + * key.number N + * key.uid u + * key.gid g + * key.hostaddr h + * key.ipnode i + * key.projid p + * key.serv(name) s + * key.serv(port) S + * key.ether e + * key.pkey k + * key.netaddr a + * key.attrp A + * groupsbymember I + * innetgr_args t + * setnetgr_args T + * Assumes arguments are all valid + */ + +/*ARGSUSED*/ +static nss_status_t +nss_upack_key2arg(void *buffer, size_t length, char **dbname, + int *dbop, nss_XbyY_args_t *arg, int index) +{ + nss_pheader_t *pbuf = (nss_pheader_t *)buffer; + const char *strtype = NULL; + nssuint_t off, *uptr; + size_t len, slop; + int i, j; + char **cv, *bptr; + struct nss_setnetgrent_args *sng; + struct nss_innetgr_args *ing; + struct nss_groupsbymem *gbm; + nss_pnetgr_t *pptr; + _priv_execattr *pe; + + off = pbuf->key_off; + bptr = (char *)buffer + off; + uptr = (nssuint_t *)((void *)bptr); + strtype = getXbyY_to_dbop[index].tostr; + if (strtype == NULL) + return (NSS_ERROR); + while (*strtype) { + switch (*strtype++) { + case 'n': + arg->key.name = (const char *)bptr; + break; + case 'N': + arg->key.number = (int)(*uptr); + break; + case 'u': + arg->key.uid = (uid_t)(*uptr); + break; + case 'g': + arg->key.gid = (gid_t)(*uptr); + break; + case 'h': + arg->key.hostaddr.len = (int)(*uptr++); + arg->key.hostaddr.type = (int)(*uptr++); + arg->key.hostaddr.addr = (const char *)uptr; + break; + case 'i': + arg->key.ipnode.af_family = (int)(*uptr++); + arg->key.ipnode.flags = (int)(*uptr++); + arg->key.ipnode.name = (const char *)uptr; + break; + case 'p': + arg->key.projid = (projid_t)(*uptr); + break; + case 's': + arg->key.serv.serv.name = (const char *)bptr; + len = strlen(arg->key.serv.serv.name) + 1; + bptr += len; + if (*(const char *)bptr == '\0') + arg->key.serv.proto = NULL; + else + arg->key.serv.proto = (const char *)bptr; + break; + case 'S': + arg->key.serv.serv.port = (int)(*uptr++); + if (pbuf->key_len == sizeof (nssuint_t)) { + arg->key.serv.proto = NULL; + } else { + bptr += sizeof (nssuint_t); + arg->key.serv.proto = (const char *)bptr; + } + break; + case 'e': + arg->key.ether = bptr; + break; + case 'k': + arg->key.pkey.name = (const char *)bptr; + len = strlen(arg->key.pkey.name) + 1; + bptr += len; + arg->key.pkey.keytype = (const char *)bptr; + break; + case 'a': + arg->key.netaddr.net = (uint32_t)(*uptr++); + arg->key.netaddr.type = (int)(*uptr++); + break; + case 'A': + pe = (_priv_execattr *)((void *)bptr); + /* use slop space as priv_execattr structure */ + arg->key.attrp = (void *)pe; + /* skip over slop ... */ + slop = sizeof (nssuint_t) * 16; + uptr = (nssuint_t *)((void *)((char *)bptr + slop)); + pe->search_flag = (int)*uptr++; + bptr = (char *)uptr; + if (*bptr == '\0') { + pe->name = NULL; + bptr++; + } else { + pe->name = (char *)bptr; + bptr += strlen(pe->name) + 1; + } + if (*bptr == '\0') { + pe->type = NULL; + bptr++; + } else { + pe->type = (char *)bptr; + bptr += strlen(pe->type) + 1; + } + if (*bptr == '\0') { + pe->id = NULL; + bptr++; + } else { + pe->id = (char *)bptr; + bptr += strlen(pe->id) + 1; + } + if (*bptr == '\0') { + pe->policy = NULL; + } else { + pe->policy = (char *)bptr; + } + pe->head_exec = NULL; + pe->prev_exec = NULL; + break; + case 'I': + gbm = (struct nss_groupsbymem *)arg; + gbm->gid_array = (gid_t *) + ((void *)((char *)pbuf + pbuf->data_off)); + gbm->force_slow_way = (int)(*uptr++); + gbm->maxgids = (int)(*uptr++); + gbm->numgids = (int)(*uptr++); + if (gbm->numgids == 1) { + /* insert initial group into data area */ + ((nssuint_t *) + ((void *)gbm->gid_array))[0] = *uptr++; + } + gbm->username = (const char *)uptr; + break; + case 't': + pptr = (nss_pnetgr_t *)((void *)bptr); + ing = (struct nss_innetgr_args *)arg; + ing->arg[NSS_NETGR_MACHINE].argc = pptr->machine_argc; + ing->arg[NSS_NETGR_USER].argc = pptr->user_argc; + ing->arg[NSS_NETGR_DOMAIN].argc = pptr->domain_argc; + ing->groups.argc = pptr->groups_argc; + + /* + * Start of argv pointer storage + */ + off = ing->arg[NSS_NETGR_MACHINE].argc + + ing->arg[NSS_NETGR_USER].argc + + ing->arg[NSS_NETGR_DOMAIN].argc + + ing->groups.argc; + off *= sizeof (nssuint_t); + off += sizeof (nss_pnetgr_t); + + cv = (char **)((void *)(bptr + off)); + uptr = (nssuint_t *) + ((void *)(bptr + sizeof (nss_pnetgr_t))); + for (j = 0; j < NSS_NETGR_N; j++) { + ing->arg[j].argv = cv; + for (i = 0; i < ing->arg[j].argc; i++) { + *cv++ = (bptr + *uptr++); + } + } + ing->groups.argv = cv; + for (i = 0; i < ing->groups.argc; i++) { + *cv++ = (bptr + *uptr++); + } + break; + case 'T': + sng = (struct nss_setnetgrent_args *)arg; + sng->netgroup = (const char *)bptr; + sng->iterator = 0; + break; + + default: + return (NSS_ERROR); + } + } + return (NSS_SUCCESS); +} + +static nss_status_t +nss_pinit_funcs(int index, nss_db_initf_t *initf, nss_str2ent_t *s2e) +{ + const char *name; + void *handle; + void *sym; + + if ((handle = dlopen((const char *)0, RTLD_LAZY)) != NULL) { + if (initf) { + name = getXbyY_to_dbop[index].initfn; + if ((sym = dlsym(handle, name)) == 0) { + (void) dlclose(handle); + return (NSS_ERROR); + } else { + *initf = (nss_db_initf_t)sym; + } + } + if (s2e) { + name = getXbyY_to_dbop[index].strfn; + if ((sym = dlsym(handle, name)) == 0) { + (void) dlclose(handle); + return (NSS_ERROR); + } else { + *s2e = (nss_str2ent_t)sym; + } + } + } + return (NSS_SUCCESS); +} + +nss_status_t +nss_packed_getkey(void *buffer, size_t length, char **dbname, + int *dbop, nss_XbyY_args_t *arg) +{ + nss_pheader_t *pbuf = (nss_pheader_t *)buffer; + nss_dbd_t *pdbd; + nssuint_t off; + int index; + + if (buffer == NULL || length == 0 || dbop == NULL || + arg == NULL || dbname == NULL) + return (NSS_ERROR); + + *dbop = pbuf->nss_dbop; + off = pbuf->dbd_off; + pdbd = (nss_dbd_t *)((void *)((char *)buffer + off)); + *dbname = (char *)buffer + off + pdbd->o_name; + if ((index = nss_dbop_search(*dbname, (uint32_t)*dbop)) < 0) + return (NSS_ERROR); + return (nss_upack_key2arg(buffer, length, dbname, dbop, arg, index)); +} + + +/* + * str2packent: Standard format interposed str2X function for normal APIs + * + * Return values: 0 = success, 1 = parse error, 2 = erange ... + * + * The structure pointer is ignored since this is a nscd side packed request. + * The client side routine does all the real parsing; we just check limits and + * store the entry in the buffer we were passed by the caller. + */ + +/*ARGSUSED*/ +static int +str2packent( + const char *instr, + int lenstr, + void *ent, /* really (char *) */ + char *buffer, + int buflen +) +{ + if (buflen <= lenstr) { /* not enough buffer */ + return (NSS_STR_PARSE_ERANGE); + } + (void) memmove(buffer, instr, lenstr); + buffer[lenstr] = '\0'; + + return (NSS_STR_PARSE_SUCCESS); +} + +/* + * getgroupsbymem format interposed cstr2X function + * This are similar to the API in getgrnam_r EXCEPT, this API + * store values in nssuint_t quantities in the buffer, not gid_t + * quantities. The unpacker in nss_common.c knows how to unpack + * into gid_t quantities. + */ + +static nss_status_t +pack_cstr(const char *instr, int instr_len, struct nss_groupsbymem *gbm) +{ + /* + * It's possible to do a much less inefficient version of this by + * selectively duplicating code from str2group(). For now, + * however, we'll take the easy way out and implement this on + * top of str2group(). + */ + + const char *username = gbm->username; + nss_XbyY_buf_t *buf; + struct group *grp; + char **memp; + char *mem; + int parsestat; + + /* TODO FIX THIS - with getdoorbsize type call */ + buf = _nss_XbyY_buf_alloc(sizeof (struct group), NSS_BUFLEN_GROUP); + if (buf == 0) + return (NSS_UNAVAIL); + + grp = (struct group *)buf->result; + + parsestat = (*gbm->str2ent)(instr, instr_len, + grp, buf->buffer, buf->buflen); + + if (parsestat != NSS_STR_PARSE_SUCCESS) { + _nss_XbyY_buf_free(buf); + return (NSS_NOTFOUND); /* === ? */ + } + + if (grp->gr_mem) { + for (memp = grp->gr_mem; (memp) && ((mem = *memp) != 0); + memp++) { + if (strcmp(mem, username) == 0) { + gid_t gid = grp->gr_gid; + nssuint_t *gidp; + int numgids; + int i; + + gidp = (nssuint_t *)((void *)gbm->gid_array); + numgids = gbm->numgids; + + _nss_XbyY_buf_free(buf); + + for (i = 0; i < numgids && + *gidp != (nssuint_t)gid; + i++, gidp++) { + ; + } + if (i >= numgids) { + if (i >= gbm->maxgids) { + /* Filled the array; stop searching */ + return (NSS_SUCCESS); + } + *gidp = (nssuint_t)gid; + gbm->numgids = numgids + 1; + } + return (NSS_NOTFOUND); /* Explained in */ + /* <nss_dbdefs.h> */ + } + } + } + _nss_XbyY_buf_free(buf); + return (NSS_NOTFOUND); +} + +/* + * Initialize db_root, initf, dbop and arg from a packed buffer + */ + +/*ARGSUSED*/ +nss_status_t +nss_packed_arg_init(void *buffer, size_t length, nss_db_root_t *db_root, + nss_db_initf_t *initf, int *dbop, nss_XbyY_args_t *arg) +{ + nss_pheader_t *pbuf = (nss_pheader_t *)buffer; + nss_str2ent_t s2e = str2packent; + nss_str2ent_t real_s2e = NULL; + nss_dbd_t *pdbd; + nssuint_t off; + char *dbname, *bptr; + size_t len; + int index; + + if (buffer == NULL || length == 0 || + dbop == NULL || arg == NULL) + return (NSS_ERROR); + + /* init dbop */ + *dbop = pbuf->nss_dbop; + off = pbuf->dbd_off; + pdbd = (nss_dbd_t *)((void *)((char *)buffer + off)); + dbname = (char *)buffer + off + pdbd->o_name; + if ((index = nss_dbop_search(dbname, (uint32_t)*dbop)) < 0) + return (NSS_ERROR); + + /* db_root is initialized by nscd's based on door info */ + /* do nothing here */ + + /* init key information - (and get dbname dbop etc...) */ + if (nss_upack_key2arg(buffer, length, &dbname, + dbop, arg, index) != NSS_SUCCESS) + return (NSS_ERROR); + + /* possible audituser init */ + if (strcmp(dbname, NSS_DBNAM_AUTHATTR) == 0) + arg->h_errno = (int)pbuf->p_herrno; + + bptr = (char *)buffer + pbuf->data_off; + len = (size_t)pbuf->data_len; + + /* sidestep odd arg cases */ + if (*dbop == NSS_DBOP_GROUP_BYMEMBER && + strcmp(dbname, NSS_DBNAM_GROUP) == 0) { + /* get initf and str2ent functions */ + if (nss_pinit_funcs(index, initf, &real_s2e) != NSS_SUCCESS) + return (NSS_ERROR); + ((struct nss_groupsbymem *)arg)->str2ent = real_s2e; + ((struct nss_groupsbymem *)arg)->process_cstr = pack_cstr; + return (NSS_SUCCESS); + } + if (pbuf->nss_dbop == NSS_DBOP_NETGROUP_IN && + strcmp(dbname, NSS_DBNAM_NETGROUP) == 0) { + return (NSS_SUCCESS); + } + + /* get initf and str2ent functions */ + if (nss_pinit_funcs(index, initf, NULL) != NSS_SUCCESS) + return (NSS_ERROR); + + /* init normal arg cases */ + NSS_XbyY_INIT(arg, NULL, bptr, len, s2e); + arg->h_errno = 0; + + return (NSS_SUCCESS); +} + +/* + * Initialize db_root, initf, dbop, contextp and arg from a packed buffer + */ + +/*ARGSUSED*/ +nss_status_t +nss_packed_context_init(void *buffer, size_t length, nss_db_root_t *db_root, + nss_db_initf_t *initf, nss_getent_t **contextp, + nss_XbyY_args_t *arg) +{ + nss_pheader_t *pbuf = (nss_pheader_t *)buffer; + nss_str2ent_t s2e = str2packent; + char *bptr; + size_t len; + + /* init arg */ + if (arg != NULL) { + bptr = (char *)buffer + pbuf->data_off; + len = (size_t)pbuf->data_len; + NSS_XbyY_INIT(arg, NULL, bptr, len, s2e); + } + + return (NSS_SUCCESS); +} diff --git a/usr/src/lib/libc/port/gen/nss_deffinder.c b/usr/src/lib/libc/port/gen/nss_deffinder.c index dc06ff923b..7620512646 100644 --- a/usr/src/lib/libc/port/gen/nss_deffinder.c +++ b/usr/src/lib/libc/port/gen/nss_deffinder.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -49,8 +48,14 @@ /* === ? move these constants to a public header file ? */ static const int dlopen_version = 1; -static const char dlopen_format[] = "nss_%s.so.%d"; -static const char dlsym_format [] = "_nss_%s_%s_constr"; +#ifndef NSS_DLOPEN_FORMAT +#define NSS_DLOPEN_FORMAT "nss_%s.so.%d" +#endif +#ifndef NSS_DLSYM_FORMAT +#define NSS_DLSYM_FORMAT "_nss_%s_%s_constr" +#endif +static const char dlopen_format[] = NSS_DLOPEN_FORMAT; +static const char dlsym_format [] = NSS_DLSYM_FORMAT; static const size_t format_maxlen = sizeof (dlsym_format) - 4; /*ARGSUSED*/ diff --git a/usr/src/lib/libc/port/mapfile-vers b/usr/src/lib/libc/port/mapfile-vers index 42b24ea43d..6d5cee49e7 100644 --- a/usr/src/lib/libc/port/mapfile-vers +++ b/usr/src/lib/libc/port/mapfile-vers @@ -1727,13 +1727,21 @@ SUNWprivate_1.1 { _nrand48; _nss_db_state_destr; _nss_default_finders; + nss_default_key2str; nss_delete; _nss_delete; nss_endent; _nss_endent; nss_getent; _nss_getent; + _nss_initf_group; _nss_initf_netgroup; + _nss_initf_passwd; + _nss_initf_shadow; + nss_packed_arg_init; + nss_packed_context_init; + nss_packed_getkey; + nss_packed_set_status; nss_search; _nss_search; nss_setent; @@ -2016,6 +2024,8 @@ SUNWprivate_1.1 { _srand48; _ssignal; _statfs; + str2group; + str2passwd; _str2sig; str2spwd; __strcoll_C; diff --git a/usr/src/lib/libnsl/common/llib-lnsl b/usr/src/lib/libnsl/common/llib-lnsl index 87f0091ba8..889d4bf1fa 100644 --- a/usr/src/lib/libnsl/common/llib-lnsl +++ b/usr/src/lib/libnsl/common/llib-lnsl @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -24,7 +23,7 @@ /* PROTOLIB1 */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -1329,3 +1328,6 @@ bool_t xdr_ypdelete_args(XDR *xdrs, ypdelete_args *objp); /* nis_sec_mechs.c */ char *__nis_keyalg2authtype(keylen_t keylen, algtype_t algtype, char *authtype, size_t authtype_len); + +/* usr/src/lib/libnsl/nss/parse.c */ +char *_strtok_escape(char *string, char *sepset, char **lasts); diff --git a/usr/src/lib/libnsl/key/publickey.c b/usr/src/lib/libnsl/key/publickey.c index febc30e423..afea031537 100644 --- a/usr/src/lib/libnsl/key/publickey.c +++ b/usr/src/lib/libnsl/key/publickey.c @@ -124,6 +124,23 @@ static int extract_secret(); static DEFINE_NSS_DB_ROOT(db_root); /* + * str2key + */ +/* ARGSUSED */ +static int +str2key(const char *instr, int lenstr, + void *ent, char *buffer, int buflen) { + if (lenstr + 1 > buflen) + return (NSS_STR_PARSE_ERANGE); + /* + * We copy the input string into the output buffer + */ + (void) memcpy(buffer, instr, lenstr); + buffer[lenstr] = '\0'; + + return (NSS_STR_PARSE_SUCCESS); +} +/* * These functions are the "backends" for the switch for public keys. They * get both the public and private keys from each of the supported name * services (nis, nisplus, files). They are passed the appropriate parameters @@ -704,7 +721,7 @@ getkeys_ldap_g( NSS_XbyY_ALLOC(&buf, 0, NSS_BUFLEN_PUBLICKEY); - NSS_XbyY_INIT(&arg, buf->result, buf->buffer, buf->buflen, NULL); + NSS_XbyY_INIT(&arg, buf->result, buf->buffer, buf->buflen, str2key); arg.key.pkey.name = netname; /* diff --git a/usr/src/lib/libnsl/nss/getauthattr.c b/usr/src/lib/libnsl/nss/getauthattr.c index d734e99ab9..b01c7447e8 100644 --- a/usr/src/lib/libnsl/nss/getauthattr.c +++ b/usr/src/lib/libnsl/nss/getauthattr.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -68,12 +67,12 @@ str2authattr(const char *instr, int lenstr, void *ent, char *buffer, int buflen) char *sep = KV_TOKEN_DELIMIT; authstr_t *auth = (authstr_t *)ent; - if ((instr >= buffer && (buffer + buflen) > instr) || - (buffer >= instr && (instr + lenstr) > buffer)) - return (NSS_STR_PARSE_PARSE); if (lenstr >= buflen) return (NSS_STR_PARSE_ERANGE); - (void) strncpy(buffer, instr, buflen); + + if (instr != buffer) + (void) strncpy(buffer, instr, buflen); + /* * Remove newline that nis (yp_match) puts at the * end of the entry it retrieves from the map. @@ -81,6 +80,10 @@ str2authattr(const char *instr, int lenstr, void *ent, char *buffer, int buflen) if (buffer[lenstr] == '\n') buffer[lenstr] = '\0'; + /* quick exit do not entry fill if not needed */ + if (ent == (void *)NULL) + return (NSS_STR_PARSE_SUCCESS); + auth->name = _strtok_escape(buffer, sep, &last); auth->res1 = _strtok_escape(NULL, sep, &last); auth->res2 = _strtok_escape(NULL, sep, &last); diff --git a/usr/src/lib/libnsl/nss/getauuser.c b/usr/src/lib/libnsl/nss/getauuser.c index 877a108ff8..f42b80cc5c 100644 --- a/usr/src/lib/libnsl/nss/getauuser.c +++ b/usr/src/lib/libnsl/nss/getauuser.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -72,12 +71,12 @@ str2auuser(const char *instr, int lenstr, void *ent, char *buffer, int buflen) char *sep = KV_TOKEN_DELIMIT; au_user_str_t *au_user = (au_user_str_t *)ent; - if ((instr >= buffer && (buffer + buflen) > instr) || - (buffer >= instr && (instr + lenstr) > buffer)) - return (NSS_STR_PARSE_PARSE); if (lenstr >= buflen) return (NSS_STR_PARSE_ERANGE); - (void) strncpy(buffer, instr, buflen); + + if (instr != buffer) + (void) strncpy(buffer, instr, buflen); + /* * Remove newline that nis (yp_match) puts at the * end of the entry it retrieves from the map. @@ -86,6 +85,10 @@ str2auuser(const char *instr, int lenstr, void *ent, char *buffer, int buflen) buffer[lenstr] = '\0'; } + /* quick exit do not entry fill if not needed */ + if (ent == (void *)NULL) + return (NSS_STR_PARSE_SUCCESS); + au_user->au_name = _strtok_escape(buffer, sep, &last); au_user->au_always = _strtok_escape(NULL, sep, &last); au_user->au_never = _strtok_escape(NULL, sep, &last); diff --git a/usr/src/lib/libnsl/nss/getexecattr.c b/usr/src/lib/libnsl/nss/getexecattr.c index 1990cea7ed..023667f092 100644 --- a/usr/src/lib/libnsl/nss/getexecattr.c +++ b/usr/src/lib/libnsl/nss/getexecattr.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -21,7 +20,7 @@ */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -99,15 +98,12 @@ str2execattr(const char *instr, int lenstr, void *ent, char *buffer, int buflen) char *sep = KV_TOKEN_DELIMIT; execstr_t *exec = (execstr_t *)ent; - if (exec == NULL) - return (NSS_STR_PARSE_PARSE); - - if ((instr >= buffer && (buffer + buflen) > instr) || - (buffer >= instr && (instr + lenstr) > buffer)) - return (NSS_STR_PARSE_PARSE); if (lenstr >= buflen) return (NSS_STR_PARSE_ERANGE); - (void) strncpy(buffer, instr, buflen); + + if (instr != buffer) + (void) strncpy(buffer, instr, buflen); + /* * Remove newline that nis (yp_match) puts at the * end of the entry it retrieves from the map. @@ -116,6 +112,10 @@ str2execattr(const char *instr, int lenstr, void *ent, char *buffer, int buflen) buffer[lenstr] = '\0'; } + /* quick exit do not entry fill if not needed */ + if (ent == (void *)NULL) + return (NSS_STR_PARSE_SUCCESS); + exec->name = _strtok_escape(buffer, sep, &last); exec->policy = _strtok_escape(NULL, sep, &last); exec->type = _strtok_escape(NULL, sep, &last); @@ -245,9 +245,12 @@ retry_policy: res = nss_search(&pexec_root, _nsw_initf_execattr, getby_flag, &arg); - _nss_db_state_destr(pexec_root.s); + if (pexec_root.s != NULL) + _nss_db_state_destr( + pexec_root.s); } - _nss_db_state_destr(prof_root.s); + if (prof_root.s != NULL) + _nss_db_state_destr(prof_root.s); (void) mutex_unlock(&_nsw_exec_lock); if ((pres == NSS_SUCCESS) || (conf == NULL)) break; diff --git a/usr/src/lib/libnsl/nss/gethostby_door.c b/usr/src/lib/libnsl/nss/gethostby_door.c index 8b7f66f46f..4c3bdebc38 100644 --- a/usr/src/lib/libnsl/nss/gethostby_door.c +++ b/usr/src/lib/libnsl/nss/gethostby_door.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -19,7 +18,6 @@ * * CDDL HEADER END */ - /* * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. @@ -40,285 +38,20 @@ #ifdef PIC -static struct hostent *process_gethost(struct hostent *, char *, int, int *, - nsc_data_t *); - struct hostent * _door_gethostbyname_r(const char *name, struct hostent *result, char *buffer, int buflen, int *h_errnop) { - - /* - * allocate space on the stack for the nscd to return - * host and host alias information - */ - union { - nsc_data_t s_d; - char s_b[8192]; - } space; - nsc_data_t *sptr; - int ndata; - int adata; - struct hostent *resptr = NULL; - - if ((name == NULL) || - (strlen(name) >= (sizeof (space) - sizeof (nsc_data_t)))) { - errno = ERANGE; - if (h_errnop) - *h_errnop = HOST_NOT_FOUND; - return (NULL); - } - - adata = (sizeof (nsc_call_t) + strlen(name) + 1); - ndata = sizeof (space); - space.s_d.nsc_call.nsc_callnumber = GETHOSTBYNAME; - (void) strcpy(space.s_d.nsc_call.nsc_u.name, name); - sptr = &space.s_d; - - switch (_nsc_trydoorcall(&sptr, &ndata, &adata)) { - case SUCCESS: /* positive cache hit */ - break; - case NOTFOUND: /* negative cache hit */ - if (h_errnop) - *h_errnop = space.s_d.nsc_ret.nsc_errno; - return (NULL); - default: - return ((struct hostent *)_switch_gethostbyname_r(name, + return ((struct hostent *)_switch_gethostbyname_r(name, result, buffer, buflen, h_errnop)); - } - resptr = process_gethost(result, buffer, buflen, h_errnop, sptr); - - /* - * check if doors realloced buffer underneath of us.... - * munmap or suffer a memory leak - */ - - if (sptr != &space.s_d) { - munmap((char *)sptr, ndata); /* return memory */ - } - - return (resptr); } struct hostent * _door_gethostbyaddr_r(const char *addr, int length, int type, struct hostent *result, char *buffer, int buflen, int *h_errnop) { - /* - * allocate space on the stack for the nscd to return - * host and host alias information - */ - union { - nsc_data_t s_d; - char s_b[8192]; - } space; - nsc_data_t *sptr; - int ndata; - int adata; - struct hostent *resptr = NULL; - - if (addr == NULL) { - if (h_errnop) - *h_errnop = HOST_NOT_FOUND; - return (NULL); - } - - ndata = sizeof (space); - adata = length + sizeof (nsc_call_t) + 1; - sptr = &space.s_d; - - space.s_d.nsc_call.nsc_callnumber = GETHOSTBYADDR; - space.s_d.nsc_call.nsc_u.addr.a_type = type; - space.s_d.nsc_call.nsc_u.addr.a_length = length; - (void) memcpy(space.s_d.nsc_call.nsc_u.addr.a_data, addr, length); - - switch (_nsc_trydoorcall(&sptr, &ndata, &adata)) { - case SUCCESS: /* positive cache hit */ - break; - case NOTFOUND: /* negative cache hit */ - if (h_errnop) - *h_errnop = space.s_d.nsc_ret.nsc_errno; - return (NULL); - default: - return ((struct hostent *)_switch_gethostbyaddr_r(addr, + return ((struct hostent *)_switch_gethostbyaddr_r(addr, length, type, result, buffer, buflen, h_errnop)); - } - - resptr = process_gethost(result, buffer, buflen, h_errnop, sptr); - - /* - * check if doors realloced buffer underneath of us.... - * munmap it or suffer a memory leak - */ - - if (sptr != &space.s_d) { - munmap((char *)sptr, ndata); /* return memory */ - } - - return (resptr); - -} - -#if !defined(_LP64) - -static struct hostent * -process_gethost(struct hostent *result, char *buffer, int buflen, - int *h_errnop, nsc_data_t *sptr) -{ - int i; - - char *fixed; - - fixed = (char *)(((int)buffer +3) & ~3); - buflen -= fixed - buffer; - buffer = fixed; - - if (buflen + sizeof (struct hostent) - < sptr->nsc_ret.nsc_bufferbytesused) { - /* - * no enough space allocated by user - */ - errno = ERANGE; - if (h_errnop) - *h_errnop = HOST_NOT_FOUND; - return (NULL); - } - - (void) memcpy(buffer, - sptr->nsc_ret.nsc_u.buff + sizeof (struct hostent), - sptr->nsc_ret.nsc_bufferbytesused - sizeof (struct hostent)); - - sptr->nsc_ret.nsc_u.hst.h_name += (int)buffer; - sptr->nsc_ret.nsc_u.hst.h_aliases = - (char **)((char *)sptr->nsc_ret.nsc_u.hst.h_aliases + (int)buffer); - sptr->nsc_ret.nsc_u.hst.h_addr_list = - (char **)((char *)sptr->nsc_ret.nsc_u.hst.h_addr_list + - (int)buffer); - for (i = 0; sptr->nsc_ret.nsc_u.hst.h_aliases[i]; i++) { - sptr->nsc_ret.nsc_u.hst.h_aliases[i] += (int)buffer; - } - for (i = 0; sptr->nsc_ret.nsc_u.hst.h_addr_list[i]; i++) { - sptr->nsc_ret.nsc_u.hst.h_addr_list[i] += (int)buffer; - } - - *result = sptr->nsc_ret.nsc_u.hst; - - return (result); } -#else /* _LP64 */ - -#define RNDUP(buf, n) (((uintptr_t)buf + n - 1l) & ~(n - 1l)) - -static struct hostent * -process_gethost(struct hostent *result, char *buffer, int buflen, - int *h_errnop, nsc_data_t *sptr) -{ - char *fixed; - char *dest; - char *start; - char **aliaseslist; - char **addrlist; - int *alias; - int *address; - size_t strs; - int numaliases; - int numaddrs; - int i; - - fixed = (char *)RNDUP(buffer, sizeof (char *)); - buflen -= fixed - buffer; - buffer = fixed; - - if (buflen < 0) { - /* no enough space allocated by user */ - errno = ERANGE; - if (h_errnop) - *h_errnop = HOST_NOT_FOUND; - return (NULL); - } - - /* find out whether the user has provided sufficient space */ - - start = sptr->nsc_ret.nsc_u.buff + sizeof (struct hostent32); - strs = 1 + strlen(sptr->nsc_ret.nsc_u.hst.h_name + start); - alias = (int *)(start + sptr->nsc_ret.nsc_u.hst.h_aliases); - for (numaliases = 0; alias[numaliases]; numaliases++) - strs += 1 + strlen(start + alias[numaliases]); - strs = RNDUP(strs, sizeof (int)); - strs += sizeof (char *) * (numaliases + 1); - address = (int *)(start + sptr->nsc_ret.nsc_u.hst.h_addr_list); - for (numaddrs = 0; address[numaddrs]; numaddrs++) - strs += RNDUP(sptr->nsc_ret.nsc_u.hst.h_length, sizeof (int)); - strs += sizeof (char *) * (numaddrs + 1); - - if (buflen < strs) { - - /* no enough space allocated by user */ - - errno = ERANGE; - if (h_errnop) - *h_errnop = HOST_NOT_FOUND; - return (NULL); - } - - - /* - * allocat the h_aliases list and the h_addr_list first to align 'em. - */ - - dest = buffer; - aliaseslist = (char **)dest; - dest += sizeof (char *) * (numaliases + 1); - addrlist = (char **)dest; - dest += sizeof (char *) * (numaddrs + 1); - - /* fill out h_name */ - - start = sptr->nsc_ret.nsc_u.buff + sizeof (struct hostent32); - (void) strcpy(dest, sptr->nsc_ret.nsc_u.hst.h_name + start); - strs = 1 + strlen(sptr->nsc_ret.nsc_u.hst.h_name + start); - result->h_name = dest; - dest += strs; - - /* - * fill out the h_aliases list - */ - for (i = 0; i < numaliases; i++) { - alias = (int *)(start + sptr->nsc_ret.nsc_u.hst.h_aliases); - (void) strcpy(dest, start + alias[i]); - strs = 1 + strlen(start + alias[i]); - aliaseslist[i] = dest; - dest += strs; - } - aliaseslist[i] = 0; /* null term ptr chain */ - - result->h_aliases = aliaseslist; - - /* - * fill out the h_addr list - */ - - dest = (char *)RNDUP(dest, sizeof (int)); - - for (i = 0; i < numaddrs; i++) { - address = (int *)(start + sptr->nsc_ret.nsc_u.hst.h_addr_list); - (void) memcpy(dest, start + address[i], - sptr->nsc_ret.nsc_u.hst.h_length); - strs = sptr->nsc_ret.nsc_u.hst.h_length; - addrlist[i] = dest; - dest += strs; - dest = (char *)RNDUP(dest, sizeof (int)); - } - - addrlist[i] = 0; /* null term ptr chain */ - - result->h_addr_list = addrlist; - - result->h_length = sptr->nsc_ret.nsc_u.hst.h_length; - result->h_addrtype = sptr->nsc_ret.nsc_u.hst.h_addrtype; - - return (result); -} -#endif /* _LP64 */ #endif /* PIC */ diff --git a/usr/src/lib/libnsl/nss/gethostbyname_r.c b/usr/src/lib/libnsl/nss/gethostbyname_r.c index 27435b95fe..7a3c5aaaa0 100644 --- a/usr/src/lib/libnsl/nss/gethostbyname_r.c +++ b/usr/src/lib/libnsl/nss/gethostbyname_r.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -151,7 +150,10 @@ gethostbyaddr_r(const char *addr, int length, int type, struct netconfig *nconf; struct nss_netdirbyaddr_in nssin; union nss_netdirbyaddr_out nssout; - int neterr; + int neterr, dummy; + + if (h_errnop == NULL) + h_errnop = &dummy; if (type != AF_INET) { *h_errnop = HOST_NOT_FOUND; diff --git a/usr/src/lib/libnsl/nss/gethostent.c b/usr/src/lib/libnsl/nss/gethostent.c index 8cbc3b9dec..c02c8c5ebf 100644 --- a/usr/src/lib/libnsl/nss/gethostent.c +++ b/usr/src/lib/libnsl/nss/gethostent.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. diff --git a/usr/src/lib/libnsl/nss/getipnodeby_door.c b/usr/src/lib/libnsl/nss/getipnodeby_door.c index 8c0423196e..17e1f953c1 100644 --- a/usr/src/lib/libnsl/nss/getipnodeby_door.c +++ b/usr/src/lib/libnsl/nss/getipnodeby_door.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -19,7 +18,6 @@ * * CDDL HEADER END */ - /* * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. @@ -41,298 +39,20 @@ #ifdef PIC -static struct hostent *__process_getipnode(struct hostent *, char *, int, int *, - nsc_data_t *); - struct hostent * _door_getipnodebyname_r(const char *name, struct hostent *result, char *buffer, int buflen, int af_family, int flags, int *h_errnop) { - - /* - * allocate space on the stack for the nscd to return - * host and host alias information - */ - union { - nsc_data_t s_d; - char s_b[8192]; - } space; - nsc_data_t *sptr; - int ndata; - int adata; - struct hostent *resptr = NULL; - - if ((name == NULL) || - (strlen(name) >= (sizeof (space) - sizeof (nsc_data_t) - - 2 * sizeof (int)))) { - errno = ERANGE; - if (h_errnop) - *h_errnop = HOST_NOT_FOUND; - return (NULL); - } - - adata = (sizeof (nsc_call_t) + strlen(name) + 1 + 2 * sizeof (int)); - ndata = sizeof (space); - space.s_d.nsc_call.nsc_callnumber = GETIPNODEBYNAME; - space.s_d.nsc_call.nsc_u.ipnode.af_family = af_family; - space.s_d.nsc_call.nsc_u.ipnode.flags = flags; - (void) strcpy(space.s_d.nsc_call.nsc_u.ipnode.name, name); - sptr = &space.s_d; - - switch (_nsc_trydoorcall(&sptr, &ndata, &adata)) { - case SUCCESS: /* positive cache hit */ - break; - case NOTFOUND: /* negative cache hit */ - if (h_errnop) - *h_errnop = space.s_d.nsc_ret.nsc_errno; - return (NULL); - default: - return ((struct hostent *)_switch_getipnodebyname_r(name, + return ((struct hostent *)_switch_getipnodebyname_r(name, result, buffer, buflen, af_family, flags, h_errnop)); - } - resptr = __process_getipnode(result, buffer, buflen, h_errnop, sptr); - - /* - * check if doors realloced buffer underneath of us.... - * munmap or suffer a memory leak - */ - - if (sptr != &space.s_d) { - munmap((char *)sptr, ndata); /* return memory */ - } - - return (resptr); } struct hostent * _door_getipnodebyaddr_r(const char *addr, int length, int type, struct hostent *result, char *buffer, int buflen, int *h_errnop) { - /* - * allocate space on the stack for the nscd to return - * host and host alias information - */ - union { - nsc_data_t s_d; - char s_b[8192]; - } space; - nsc_data_t *sptr; - int ndata; - int adata; - struct hostent *resptr = NULL; - - if (addr == NULL) { - if (h_errnop) - *h_errnop = HOST_NOT_FOUND; - return (NULL); - } - - ndata = sizeof (space); - adata = length + sizeof (nsc_call_t) + 1; - sptr = &space.s_d; - - space.s_d.nsc_call.nsc_callnumber = GETIPNODEBYADDR; - space.s_d.nsc_call.nsc_u.addr.a_type = type; - space.s_d.nsc_call.nsc_u.addr.a_length = length; - (void) memcpy(space.s_d.nsc_call.nsc_u.addr.a_data, addr, length); - - switch (_nsc_trydoorcall(&sptr, &ndata, &adata)) { - case SUCCESS: /* positive cache hit */ - break; - case NOTFOUND: /* negative cache hit */ - if (h_errnop) - *h_errnop = space.s_d.nsc_ret.nsc_errno; - return (NULL); - default: - return ((struct hostent *)_switch_getipnodebyaddr_r(addr, + return ((struct hostent *)_switch_getipnodebyaddr_r(addr, length, type, result, buffer, buflen, h_errnop)); - } - - resptr = __process_getipnode(result, buffer, buflen, h_errnop, sptr); - - /* - * check if doors realloced buffer underneath of us.... - * munmap it or suffer a memory leak - */ - - if (sptr != &space.s_d) { - munmap((char *)sptr, ndata); /* return memory */ - } - - return (resptr); -} - -#if !defined(_LP64) - -static struct hostent * -__process_getipnode(struct hostent *result, char *buffer, int buflen, - int *h_errnop, nsc_data_t *sptr) -{ - int i; - - char *fixed; - - fixed = (char *)ROUND_UP((int)buffer, sizeof (char *)); - buflen -= fixed - buffer; - buffer = fixed; - - if (buflen + sizeof (struct hostent) - < sptr->nsc_ret.nsc_bufferbytesused) { - /* - * no enough space allocated by user - */ - errno = ERANGE; - if (h_errnop) - *h_errnop = HOST_NOT_FOUND; - return (NULL); - } - - (void) memcpy(buffer, - sptr->nsc_ret.nsc_u.buff + sizeof (struct hostent), - sptr->nsc_ret.nsc_bufferbytesused - sizeof (struct hostent)); - - sptr->nsc_ret.nsc_u.hst.h_name += (int)buffer; - sptr->nsc_ret.nsc_u.hst.h_aliases = - (char **)((char *)sptr->nsc_ret.nsc_u.hst.h_aliases + (int)buffer); - sptr->nsc_ret.nsc_u.hst.h_addr_list = - (char **)((char *)sptr->nsc_ret.nsc_u.hst.h_addr_list + - (int)buffer); - for (i = 0; sptr->nsc_ret.nsc_u.hst.h_aliases[i]; i++) { - sptr->nsc_ret.nsc_u.hst.h_aliases[i] += (int)buffer; - } - for (i = 0; sptr->nsc_ret.nsc_u.hst.h_addr_list[i]; i++) { - sptr->nsc_ret.nsc_u.hst.h_addr_list[i] += (int)buffer; - } - - *result = sptr->nsc_ret.nsc_u.hst; - - return (result); -} - -#else /* _LP64 */ - -static struct hostent * -__process_getipnode(struct hostent *result, char *buffer, int buflen, - int *h_errnop, nsc_data_t *sptr) -{ - char *fixed; - char *dest; - char *start; - char **aliaseslist; - char **addrlist; - int *alias; - int *address; - size_t strs; - int numaliases; - int numaddrs; - int i; - - fixed = (char *)ROUND_UP(buffer, sizeof (char *)); - buflen -= fixed - buffer; - buffer = fixed; - if (buflen < 0) { - /* no enough space allocated by user */ - errno = ERANGE; - if (h_errnop) - *h_errnop = HOST_NOT_FOUND; - return (NULL); - } - - /* - * find out whether the user has provided sufficient space - */ - start = sptr->nsc_ret.nsc_u.buff + sizeof (struct hostent32); - /* - * Length of hostname + null - */ - strs = 1 + strlen(sptr->nsc_ret.nsc_u.hst.h_name + start); - /* - * length of all aliases + null - */ - alias = (int *)(start + sptr->nsc_ret.nsc_u.hst.h_aliases); - for (numaliases = 0; alias[numaliases]; numaliases++) - strs += 1 + strlen(start + alias[numaliases]); - /* - * Realign on word boundary - */ - strs = ROUND_UP(strs, sizeof (char *)); - /* - * Count the array of pointers to all aliases + null pointer - */ - strs += sizeof (char *) * (numaliases + 1); - /* - * length of all addresses + null. Also, account for word alignment. - */ - address = (int *)(start + sptr->nsc_ret.nsc_u.hst.h_addr_list); - for (numaddrs = 0; address[numaddrs]; numaddrs++) { - strs += sptr->nsc_ret.nsc_u.hst.h_length; - strs = ROUND_UP(strs, sizeof (char *)); - } - /* - * Count the array of pointers to all addresses + null pointer - */ - strs += sizeof (char *) * (numaddrs + 1); - - if (buflen < strs) { - - /* no enough space allocated by user */ - - errno = ERANGE; - if (h_errnop) - *h_errnop = HOST_NOT_FOUND; - return (NULL); - } - - /* - * allocat the h_aliases list and the h_addr_list first to align 'em. - */ - dest = buffer; - aliaseslist = (char **)dest; - dest += sizeof (char *) * (numaliases + 1); - addrlist = (char **)dest; - dest += sizeof (char *) * (numaddrs + 1); - /* - * fill out h_name - */ - start = sptr->nsc_ret.nsc_u.buff + sizeof (struct hostent32); - (void) strcpy(dest, sptr->nsc_ret.nsc_u.hst.h_name + start); - strs = 1 + strlen(sptr->nsc_ret.nsc_u.hst.h_name + start); - result->h_name = dest; - dest += strs; - /* - * fill out the h_aliases list - */ - alias = (int *)(start + sptr->nsc_ret.nsc_u.hst.h_aliases); - for (i = 0; i < numaliases; i++) { - (void) strcpy(dest, start + alias[i]); - aliaseslist[i] = dest; - dest += 1 + strlen(start + alias[i]); - } - aliaseslist[i] = 0; /* null term ptr chain */ - result->h_aliases = aliaseslist; - - /* - * fill out the h_addr list - */ - dest = (char *)ROUND_UP(dest, sizeof (char *)); - address = (int *)(start + sptr->nsc_ret.nsc_u.hst.h_addr_list); - for (i = 0; i < numaddrs; i++) { - (void) memcpy(dest, start + address[i], - sptr->nsc_ret.nsc_u.hst.h_length); - addrlist[i] = dest; - dest += sptr->nsc_ret.nsc_u.hst.h_length; - dest = (char *)ROUND_UP(dest, sizeof (char *)); - } - - addrlist[i] = 0; /* null term ptr chain */ - - result->h_addr_list = addrlist; - - result->h_length = sptr->nsc_ret.nsc_u.hst.h_length; - result->h_addrtype = sptr->nsc_ret.nsc_u.hst.h_addrtype; - - return (result); } -#endif /* _LP64 */ #endif /* PIC */ diff --git a/usr/src/lib/libnsl/nss/getprofattr.c b/usr/src/lib/libnsl/nss/getprofattr.c index ffda122e05..bf5f7e94fa 100644 --- a/usr/src/lib/libnsl/nss/getprofattr.c +++ b/usr/src/lib/libnsl/nss/getprofattr.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -67,12 +66,11 @@ str2profattr(const char *instr, int lenstr, void *ent, char *buffer, int buflen) char *sep = KV_TOKEN_DELIMIT; profstr_t *prof = (profstr_t *)ent; - if ((instr >= buffer && (buffer + buflen) > instr) || - (buffer >= instr && (instr + lenstr) > buffer)) - return (NSS_STR_PARSE_PARSE); if (lenstr >= buflen) return (NSS_STR_PARSE_ERANGE); - (void) strncpy(buffer, instr, buflen); + if (instr != buffer) + (void) strncpy(buffer, instr, buflen); + /* * Remove newline that nis (yp_match) puts at the * end of the entry it retrieves from the map. @@ -80,6 +78,10 @@ str2profattr(const char *instr, int lenstr, void *ent, char *buffer, int buflen) if (buffer[lenstr] == '\n') buffer[lenstr] = '\0'; + /* quick exit do not entry fill if not needed */ + if (ent == (void *)NULL) + return (NSS_STR_PARSE_SUCCESS); + prof->name = _strtok_escape(buffer, sep, &last); prof->res1 = _strtok_escape(NULL, sep, &last); prof->res2 = _strtok_escape(NULL, sep, &last); diff --git a/usr/src/lib/libnsl/nss/getrpcent_r.c b/usr/src/lib/libnsl/nss/getrpcent_r.c index 206b3896d0..e794ee7538 100644 --- a/usr/src/lib/libnsl/nss/getrpcent_r.c +++ b/usr/src/lib/libnsl/nss/getrpcent_r.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -59,6 +58,10 @@ getrpcbyname_r(const char *name, struct rpcent *result, char *buffer, nss_XbyY_args_t arg; nss_status_t res; + if (name == (const char *)NULL) { + errno = ERANGE; + return (NULL); + } NSS_XbyY_INIT(&arg, result, buffer, buflen, str2rpcent); arg.key.name = name; arg.stayopen = rpc_stayopen; diff --git a/usr/src/lib/libnsl/nss/getuserattr.c b/usr/src/lib/libnsl/nss/getuserattr.c index 30b196c8de..5106155854 100644 --- a/usr/src/lib/libnsl/nss/getuserattr.c +++ b/usr/src/lib/libnsl/nss/getuserattr.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -75,12 +74,12 @@ str2userattr(const char *instr, int lenstr, void *ent, char *buffer, int buflen) char *sep = KV_TOKEN_DELIMIT; userstr_t *user = (userstr_t *)ent; - if ((instr >= buffer && (buffer + buflen) > instr) || - (buffer >= instr && (instr + lenstr) > buffer)) - return (NSS_STR_PARSE_PARSE); if (lenstr >= buflen) return (NSS_STR_PARSE_ERANGE); - (void) strncpy(buffer, instr, buflen); + + if (instr != buffer) + (void) strncpy(buffer, instr, buflen); + /* * Remove newline that nis (yp_match) puts at the * end of the entry it retrieves from the map. @@ -89,6 +88,10 @@ str2userattr(const char *instr, int lenstr, void *ent, char *buffer, int buflen) buffer[lenstr] = '\0'; } + /* quick exit do not entry fill if not needed */ + if (ent == (void *)NULL) + return (NSS_STR_PARSE_SUCCESS); + user->name = _strtok_escape(buffer, sep, &last); user->qualifier = _strtok_escape(NULL, sep, &last); user->res1 = _strtok_escape(NULL, sep, &last); diff --git a/usr/src/lib/libnsl/nss/netdir_inet.c b/usr/src/lib/libnsl/nss/netdir_inet.c index a8fc687daf..411f24c63c 100644 --- a/usr/src/lib/libnsl/nss/netdir_inet.c +++ b/usr/src/lib/libnsl/nss/netdir_inet.c @@ -90,17 +90,10 @@ #define UDPDEV "/dev/udp" #define UDP6DEV "/dev/udp6" -#ifdef PIC -#define DOOR_GETHOSTBYNAME_R _door_gethostbyname_r -#define DOOR_GETHOSTBYADDR_R _door_gethostbyaddr_r -#define DOOR_GETIPNODEBYNAME_R _door_getipnodebyname_r -#define DOOR_GETIPNODEBYADDR_R _door_getipnodebyaddr_r -#else #define DOOR_GETHOSTBYNAME_R _switch_gethostbyname_r #define DOOR_GETHOSTBYADDR_R _switch_gethostbyaddr_r #define DOOR_GETIPNODEBYNAME_R _switch_getipnodebyname_r #define DOOR_GETIPNODEBYADDR_R _switch_getipnodebyaddr_r -#endif /* PIC */ #define DONT_SORT "SORT_ADDRS=NO" #define DONT_SORT2 "SORT_ADDRS=FALSE" diff --git a/usr/src/lib/libsecdb/common/getexecattr.c b/usr/src/lib/libsecdb/common/getexecattr.c index 1f6782b84f..1e1ab20ffd 100644 --- a/usr/src/lib/libsecdb/common/getexecattr.c +++ b/usr/src/lib/libsecdb/common/getexecattr.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -54,7 +53,6 @@ extern char *_strdup_null(char *); static execattr_t *userprof(const char *, const char *, const char *, int); static execattr_t *get_tail(execattr_t *); static execattr_t *execstr2attr(execstr_t *); -static execstr_t *process_getexec(execstr_t *, char *, int, nsc_data_t *); execattr_t * getexecattr() @@ -73,26 +71,16 @@ getexecattr() execattr_t * getexecprof(const char *name, const char *type, const char *id, int search_flag) { - int len_unique; int err = 0; - int ndata = 0; - int adata = 0; char unique[NSS_BUFLEN_EXECATTR]; char buf[NSS_BUFLEN_EXECATTR]; execattr_t *head = (execattr_t *)NULL; execattr_t *prev = (execattr_t *)NULL; execstr_t exec; execstr_t *tmp; - execstr_t *resptr = (execstr_t *)NULL; - nsc_data_t *sptr = (nsc_data_t *)NULL; - union { - nsc_data_t s_d; - char s_b[NSS_BUFLEN_EXECATTR]; - } space; (void) memset(unique, 0, NSS_BUFLEN_EXECATTR); (void) memset(&exec, 0, sizeof (execstr_t)); - (void) memset(&space, 0, sizeof (space)); if ((search_flag != GET_ONE) && (search_flag != GET_ALL)) { return ((execattr_t *)NULL); @@ -120,55 +108,6 @@ getexecprof(const char *name, const char *type, const char *id, int search_flag) return (head); } -#ifdef PIC - /* - * If the search criteria is completely specified - * and we only want a single entry, - * then attempt to look up the entry using the nscd. - * Only commands are cached. - */ - if (name && type && (strcmp(type, KV_COMMAND) == 0) && id && - (search_flag == GET_ONE)) { - if (snprintf(unique, NSS_BUFLEN_EXECATTR, "%s:%s:%s", - name, type, id) >= NSS_BUFLEN_EXECATTR) { - errno = ERANGE; - return ((execattr_t *)NULL); - } - len_unique = strlen(unique); - if ((len_unique >= (sizeof (space) - sizeof (nsc_data_t)))) { - errno = ERANGE; - return ((execattr_t *)NULL); - } - ndata = sizeof (space); - adata = len_unique + sizeof (nsc_call_t) + 1; - space.s_d.nsc_call.nsc_callnumber = GETEXECID; - (void) strcpy(space.s_d.nsc_call.nsc_u.name, unique); - sptr = &space.s_d; - - switch (_nsc_trydoorcall(&sptr, &ndata, &adata)) { - case SUCCESS: /* positive cache hit */ - break; - case NOTFOUND: /* negative cache hit */ - return ((execattr_t *)NULL); - default: - resptr = _getexecprof(name, type, id, search_flag, - &exec, buf, NSS_BUFLEN_EXECATTR, &err); - return (execstr2attr(resptr)); - } - resptr = process_getexec(&exec, buf, NSS_BUFLEN_EXECATTR, - sptr); - - /* - * check if doors reallocated the memory underneath us - * if they did munmap it or suffer a memory leak - */ - if (sptr != &space.s_d) - (void) munmap((void *)sptr, ndata); - - return (execstr2attr(resptr)); - } /* end if (name && type && id && search_flag == GET_ONE) */ -#endif /* PIC */ - tmp = _getexecprof(name, type, id, @@ -427,76 +366,6 @@ execstr2attr(execstr_t *es) return (newexec); } - -static execstr_t * -process_getexec( - execstr_t *result, - char *buffer, - int buflen, - nsc_data_t *sptr) -{ - char *fixed; -#ifdef _LP64 - execstr_t exec64; - - fixed = (char *)(((uintptr_t)buffer + 7) & ~7); -#else - fixed = (char *)(((uintptr_t)buffer + 3) & ~3); -#endif - buflen -= fixed - buffer; - buffer = fixed; - - if (sptr->nsc_ret.nsc_return_code != SUCCESS) - return ((execstr_t *)NULL); - -#ifdef _LP64 - if (sptr->nsc_ret.nsc_bufferbytesused - (int)sizeof (execstr32_t) - > buflen) -#else - if (sptr->nsc_ret.nsc_bufferbytesused - (int)sizeof (execstr_t) - > buflen) -#endif - { - errno = ERANGE; - return ((execstr_t *)NULL); - } - -#ifdef _LP64 - (void) memcpy(buffer, (sptr->nsc_ret.nsc_u.buff + sizeof (execstr32_t)), - (sptr->nsc_ret.nsc_bufferbytesused - sizeof (execstr32_t))); - exec64.name = (char *)(sptr->nsc_ret.nsc_u.exec.name + - (uintptr_t)buffer); - exec64.type = (char *)(sptr->nsc_ret.nsc_u.exec.type + - (uintptr_t)buffer); - exec64.policy = (char *)(sptr->nsc_ret.nsc_u.exec.policy + - (uintptr_t)buffer); - exec64.res1 = (char *)(sptr->nsc_ret.nsc_u.exec.res1 + - (uintptr_t)buffer); - exec64.res2 = (char *)(sptr->nsc_ret.nsc_u.exec.res2 + - (uintptr_t)buffer); - exec64.id = (char *)(sptr->nsc_ret.nsc_u.exec.id + - (uintptr_t)buffer); - exec64.attr = (char *)(sptr->nsc_ret.nsc_u.exec.attr + - (uintptr_t)buffer); - exec64.next = (execstr_t *)NULL; - *result = exec64; -#else - sptr->nsc_ret.nsc_u.exec.name += (uintptr_t)buffer; - sptr->nsc_ret.nsc_u.exec.type += (uintptr_t)buffer; - sptr->nsc_ret.nsc_u.exec.policy += (uintptr_t)buffer; - sptr->nsc_ret.nsc_u.exec.res1 += (uintptr_t)buffer; - sptr->nsc_ret.nsc_u.exec.res2 += (uintptr_t)buffer; - sptr->nsc_ret.nsc_u.exec.id += (uintptr_t)buffer; - sptr->nsc_ret.nsc_u.exec.attr += (uintptr_t)buffer; - sptr->nsc_ret.nsc_u.exec.next = (execstr_t *)NULL; - *result = sptr->nsc_ret.nsc_u.exec; - (void) memcpy(buffer, (sptr->nsc_ret.nsc_u.buff + sizeof (execstr_t)), - (sptr->nsc_ret.nsc_bufferbytesused - sizeof (execstr_t))); -#endif - return (result); -} - - #ifdef DEBUG void print_execattr(execattr_t *exec) diff --git a/usr/src/lib/libsecdb/common/getprofattr.c b/usr/src/lib/libsecdb/common/getprofattr.c index ade2cdfcc8..bb3173672c 100644 --- a/usr/src/lib/libsecdb/common/getprofattr.c +++ b/usr/src/lib/libsecdb/common/getprofattr.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -43,8 +42,6 @@ extern void _setprofattr(void); extern void _endprofattr(void); static profattr_t *profstr2attr(profstr_t *); -static profstr_t *process_getprof(profstr_t *, char *, int, nsc_data_t *); - profattr_t * getprofattr() @@ -63,55 +60,13 @@ profattr_t * getprofnam(const char *name) { int err = 0; - int ndata = 0; - int adata = 0; char buf[NSS_BUFLEN_PROFATTR]; profstr_t prof; - union { - nsc_data_t s_d; - char s_b[1024]; - } space; - nsc_data_t *sptr = (nsc_data_t *)NULL; profstr_t *resptr = (profstr_t *)NULL; (void) memset(&prof, 0, sizeof (profstr_t)); -#ifdef PIC - (void) memset(&space, 0, sizeof (space)); - - if ((name == NULL) || - (strlen(name) >= (sizeof (space) - sizeof (nsc_data_t)))) { - errno = ERANGE; - return ((profattr_t *)NULL); - } - ndata = sizeof (space); - adata = strlen(name) + sizeof (nsc_call_t) + 1; - space.s_d.nsc_call.nsc_callnumber = GETPROFNAM; - (void) strcpy(space.s_d.nsc_call.nsc_u.name, name); - sptr = &space.s_d; - - switch (_nsc_trydoorcall(&sptr, &ndata, &adata)) { - case SUCCESS: /* positive cache hit */ - break; - case NOTFOUND: /* negative cache hit */ - return ((profattr_t *)NULL); - default: - (void) memset(&prof, 0, sizeof (profattr_t)); - resptr = _getprofnam(name, &prof, buf, - NSS_BUFLEN_PROFATTR, &err); - return (profstr2attr(resptr)); - } - resptr = process_getprof(&prof, buf, NSS_BUFLEN_PROFATTR, sptr); - - /* - * check if doors reallocated the memory underneath us - * if they did munmap it or suffer a memory leak - */ - if (sptr != &space.s_d) - (void) munmap((void *)sptr, ndata); -#else /* !PIC */ resptr = _getprofnam(name, &prof, buf, NSS_BUFLEN_PROFATTR, &err); -#endif /* PIC */ return (profstr2attr(resptr)); @@ -166,67 +121,6 @@ profstr2attr(profstr_t *prof) } -static profstr_t * -process_getprof( - profstr_t *result, - char *buffer, - int buflen, - nsc_data_t *sptr) -{ - char *fixed; -#ifdef _LP64 - profstr_t prof64; - - fixed = (char *)(((uintptr_t)buffer + 7) & ~7); -#else - fixed = (char *)(((uintptr_t)buffer + 3) & ~3); -#endif - buflen -= fixed - buffer; - buffer = fixed; - - if (sptr->nsc_ret.nsc_return_code != SUCCESS) - return ((profstr_t *)NULL); - -#ifdef _LP64 - if (sptr->nsc_ret.nsc_bufferbytesused - (int)sizeof (profstr32_t) - > buflen) -#else - if (sptr->nsc_ret.nsc_bufferbytesused - (int)sizeof (profstr_t) - > buflen) -#endif - { - errno = ERANGE; - return ((profstr_t *)NULL); - } - -#ifdef _LP64 - (void) memcpy(buffer, (sptr->nsc_ret.nsc_u.buff + sizeof (profstr32_t)), - (sptr->nsc_ret.nsc_bufferbytesused - sizeof (profstr32_t))); - prof64.name = (char *)(sptr->nsc_ret.nsc_u.prof.name + - (uintptr_t)buffer); - prof64.res1 = (char *)(sptr->nsc_ret.nsc_u.prof.res1 + - (uintptr_t)buffer); - prof64.res2 = (char *)(sptr->nsc_ret.nsc_u.prof.res2 + - (uintptr_t)buffer); - prof64.desc = (char *)(sptr->nsc_ret.nsc_u.prof.desc + - (uintptr_t)buffer); - prof64.attr = (char *)(sptr->nsc_ret.nsc_u.prof.attr + - (uintptr_t)buffer); - *result = prof64; -#else - sptr->nsc_ret.nsc_u.prof.name += (uintptr_t)buffer; - sptr->nsc_ret.nsc_u.prof.res1 += (uintptr_t)buffer; - sptr->nsc_ret.nsc_u.prof.res2 += (uintptr_t)buffer; - sptr->nsc_ret.nsc_u.prof.desc += (uintptr_t)buffer; - sptr->nsc_ret.nsc_u.prof.attr += (uintptr_t)buffer; - *result = sptr->nsc_ret.nsc_u.prof; - (void) memcpy(buffer, (sptr->nsc_ret.nsc_u.buff + sizeof (profstr_t)), - (sptr->nsc_ret.nsc_bufferbytesused - sizeof (profstr_t))); -#endif - return (result); -} - - /* * Given a profile name, gets the list of profiles found from * the whole hierarchy, using the given profile as root diff --git a/usr/src/lib/libsecdb/common/getuserattr.c b/usr/src/lib/libsecdb/common/getuserattr.c index 7c0c8b9ff8..dd0789b5dd 100644 --- a/usr/src/lib/libsecdb/common/getuserattr.c +++ b/usr/src/lib/libsecdb/common/getuserattr.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -46,7 +45,6 @@ extern void _enduserattr(void); static userattr_t *userstr2attr(userstr_t *); -static userstr_t *process_getuser(userstr_t *, char *, int, nsc_data_t *); userattr_t * @@ -80,51 +78,11 @@ userattr_t * getusernam(const char *name) { int err = 0; - int ndata; - int adata; char buf[NSS_BUFLEN_USERATTR]; userstr_t user; - union { - nsc_data_t s_d; - char s_b[1024]; - } space; - nsc_data_t *sptr; userstr_t *resptr = (userstr_t *)NULL; -#ifdef PIC - if ((name == NULL) || - (strlen(name) >= (sizeof (space) - sizeof (nsc_data_t)))) { - errno = ERANGE; - return ((userattr_t *)NULL); - } - ndata = sizeof (space); - adata = strlen(name) + sizeof (nsc_call_t) + 1; - space.s_d.nsc_call.nsc_callnumber = GETUSERNAM; - (void) strcpy(space.s_d.nsc_call.nsc_u.name, name); - sptr = &space.s_d; - - switch (_nsc_trydoorcall(&sptr, &ndata, &adata)) { - case SUCCESS: /* positive cache hit */ - break; - case NOTFOUND: /* negative cache hit */ - return ((userattr_t *)NULL); - default: - (void) memset(&user, 0, sizeof (userattr_t)); - resptr = _getusernam(name, &user, buf, - NSS_BUFLEN_USERATTR, &err); - return (userstr2attr(resptr)); - } - resptr = process_getuser(&user, buf, NSS_BUFLEN_USERATTR, sptr); - - /* - * check if doors reallocated the memory underneath us - * if they did munmap it or suffer a memory leak - */ - if (sptr != &space.s_d) - (void) munmap((void *)sptr, ndata); -#else /* !PIC */ resptr = _getusernam(name, &user, buf, NSS_BUFLEN_USERATTR, &err); -#endif /* PIC */ return (userstr2attr(resptr)); @@ -191,67 +149,6 @@ userstr2attr(userstr_t *user) } -static userstr_t * -process_getuser( - userstr_t *result, - char *buffer, - int buflen, - nsc_data_t *sptr) -{ - char *fixed; -#ifdef _LP64 - userstr_t user64; - - fixed = (char *)(((uintptr_t)buffer + 7) & ~7); -#else - fixed = (char *)(((uintptr_t)buffer + 3) & ~3); -#endif - buflen -= fixed - buffer; - buffer = fixed; - - if (sptr->nsc_ret.nsc_return_code != SUCCESS) - return ((userstr_t *)NULL); - -#ifdef _LP64 - if (sptr->nsc_ret.nsc_bufferbytesused - (int)sizeof (userstr32_t) - > buflen) -#else - if (sptr->nsc_ret.nsc_bufferbytesused - (int)sizeof (userstr_t) - > buflen) -#endif - { - errno = ERANGE; - return ((userstr_t *)NULL); - } - -#ifdef _LP64 - (void) memcpy(buffer, (sptr->nsc_ret.nsc_u.buff + sizeof (userstr32_t)), - (sptr->nsc_ret.nsc_bufferbytesused - sizeof (userstr32_t))); - user64.name = (char *)(sptr->nsc_ret.nsc_u.user.name + - (uintptr_t)buffer); - user64.qualifier = (char *)(sptr->nsc_ret.nsc_u.user.qualifier + - (uintptr_t)buffer); - user64.res1 = (char *)(sptr->nsc_ret.nsc_u.user.res1 + - (uintptr_t)buffer); - user64.res2 = (char *)(sptr->nsc_ret.nsc_u.user.res2 + - (uintptr_t)buffer); - user64.attr = (char *)(sptr->nsc_ret.nsc_u.user.attr + - (uintptr_t)buffer); - *result = user64; -#else - sptr->nsc_ret.nsc_u.user.name += (uintptr_t)buffer; - sptr->nsc_ret.nsc_u.user.qualifier += (uintptr_t)buffer; - sptr->nsc_ret.nsc_u.user.res1 += (uintptr_t)buffer; - sptr->nsc_ret.nsc_u.user.res2 += (uintptr_t)buffer; - sptr->nsc_ret.nsc_u.user.attr += (uintptr_t)buffer; - *result = sptr->nsc_ret.nsc_u.user; - (void) memcpy(buffer, (sptr->nsc_ret.nsc_u.buff + sizeof (userstr_t)), - (sptr->nsc_ret.nsc_bufferbytesused - sizeof (userstr_t))); -#endif - return (result); -} - - #ifdef DEBUG void print_userattr(userattr_t *user) diff --git a/usr/src/lib/libsldap/Makefile.com b/usr/src/lib/libsldap/Makefile.com index ce3a899fec..244c974085 100644 --- a/usr/src/lib/libsldap/Makefile.com +++ b/usr/src/lib/libsldap/Makefile.com @@ -22,8 +22,9 @@ # Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # -# ident "%Z%%M% %I% %E% SMI" +#ident "%Z%%M% %I% %E% SMI" # +# lib/libsldap/Makefile.com LIBRARY= libsldap.a VERS= .1 @@ -32,7 +33,7 @@ SLDAPOBJ= ns_common.o ns_reads.o ns_writes.o \ ns_connect.o ns_config.o ns_error.o \ ns_cache_door.o ns_getalias.o ns_trace.o \ ns_init.o ns_crypt.o ns_confmgr.o \ - ns_mapping.o ns_wrapper.o + ns_mapping.o ns_wrapper.o ns_sasl.o OBJECTS= $(SLDAPOBJ) @@ -41,13 +42,14 @@ include ../../Makefile.lib SRCS = $(SLDAPOBJ:%.o=../common/%.c) LIBS = $(DYNLIB) $(LINTLIB) $(LINTLIB):= SRCS=../common/llib-lsldap -LDLIBS += -lnsl -lldap -lc +LDLIBS += -lnsl -lldap -lscf -lc SRCDIR = ../common CFLAGS += $(CCVERBOSE) -LOCFLAGS += -D_REENTRANT -DSUNW_OPTIONS -DTHREAD_SUNOS5_LWP -CPPFLAGS += -I../common -I$(SRC)/lib/libldap5/include/ldap -I/usr/include/mps $(LOCFLAGS) +LOCFLAGS += -D_REENTRANT -DSUNW_OPTIONS +CPPFLAGS += -I../common -I$(SRC)/lib/libldap5/include/ldap \ + -I/usr/include/mps $(LOCFLAGS) LINTFLAGS += -erroff=E_BAD_PTR_CAST_ALIGN LINTFLAGS64 += -erroff=E_BAD_PTR_CAST_ALIGN diff --git a/usr/src/lib/libsldap/common/llib-lsldap b/usr/src/lib/libsldap/common/llib-lsldap index 6114809d89..466116a856 100644 --- a/usr/src/lib/libsldap/common/llib-lsldap +++ b/usr/src/lib/libsldap/common/llib-lsldap @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -23,7 +22,7 @@ /* PROTOLIB1 */ /* - * Copyright 2003 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #pragma ident "%Z%%M% %I% %E% SMI" @@ -186,3 +185,49 @@ char *__s_api_get_canonical_name( ns_ldap_entry_t *entry, ns_ldap_attr_t *attrptr, int case_ignore); + +void __ns_ldap_setServer( + int set); + +ns_ldap_error_t *__ns_ldap_LoadConfiguration( + void); + +ns_ldap_error_t *__ns_ldap_DumpConfiguration( + char *file); + +ns_ldap_error_t *__ns_ldap_DumpLdif( + char *filename); + +ns_ldap_error_t *__ns_ldap_print_config( + int verbose); + +void __ns_ldap_default_config( + void); + +int __ns_ldap_download( + const char *profile, + char *addr, + char *baseDN, + ns_ldap_error_t **errorp); + +int __ns_ldap_check_dns_preq( + int foreground, + int mode_verbose, + int mode_quiet, + const char *fname, + ns_ldap_self_gssapi_config_t config, + ns_ldap_error_t **errpp); + +int __ns_ldap_check_gssapi_preq( + int foreground, + int mode_verbose, + int mode_quiet, + ns_ldap_self_gssapi_config_t config, + ns_ldap_error_t **errpp); + +int __ns_ldap_check_all_preq( + int foreground, + int mode_verbose, + int mode_quiet, + ns_ldap_self_gssapi_config_t config, + ns_ldap_error_t **errpp); diff --git a/usr/src/lib/libsldap/common/mapfile-vers b/usr/src/lib/libsldap/common/mapfile-vers index 37fd9dd2be..18a1ddd867 100644 --- a/usr/src/lib/libsldap/common/mapfile-vers +++ b/usr/src/lib/libsldap/common/mapfile-vers @@ -32,6 +32,12 @@ SUNWprivate_1.1 { global: __ns_ldap_getAcctMgmt; __s_api_get_canonical_name; + __ns_ldap_getAttrStruct; + __ns_ldap_self_gssapi_config; + __ns_ldap_self_gssapi_only_set; + __ns_ldap_check_dns_preq; + __ns_ldap_check_gssapi_preq; + __ns_ldap_check_all_preq; } SUNWprivate_1.0; SUNWprivate_1.0 { diff --git a/usr/src/lib/libsldap/common/ns_cache_door.h b/usr/src/lib/libsldap/common/ns_cache_door.h index 21d32b5292..d6c9e3a56e 100644 --- a/usr/src/lib/libsldap/common/ns_cache_door.h +++ b/usr/src/lib/libsldap/common/ns_cache_door.h @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 1999-2002 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -164,6 +163,8 @@ typedef union { #define NS_CACHE_NORESP "1" #define NS_CACHE_NEXT "2" #define NS_CACHE_WRITE "3" +#define NS_CACHE_ADDR_HOSTNAME "H" +#define NS_CACHE_ADDR_IP "I" /* * GETCACHE/SETCACHE data flags diff --git a/usr/src/lib/libsldap/common/ns_common.c b/usr/src/lib/libsldap/common/ns_common.c index 2089509afc..1244b22710 100644 --- a/usr/src/lib/libsldap/common/ns_common.c +++ b/usr/src/lib/libsldap/common/ns_common.c @@ -2223,16 +2223,24 @@ __s_api_removeServer(const char *server) (void) memset(ret, 0, sizeof (ns_server_info_t)); (void) memset(space.s_b, 0, DOORBUFFERSIZE); - adata = (sizeof (ldap_call_t) + strlen(ireq) +1); + adata = (sizeof (ldap_call_t) + strlen(ireq) + + strlen(NS_CACHE_ADDR_IP) + 1); adata += strlen(DOORLINESEP) + 1; adata += strlen(server) + 1; ndata = sizeof (space); space.s_d.ldap_call.ldap_callnumber = GETLDAPSERVER; len = sizeof (space) - sizeof (space.s_d.ldap_call.ldap_callnumber); - (void) strlcpy(space.s_d.ldap_call.ldap_u.domainname, ireq, len); - (void) strlcat(space.s_d.ldap_call.ldap_u.domainname, DOORLINESEP, len); - (void) strlcat(space.s_d.ldap_call.ldap_u.domainname, server, len); + if (strlcpy(space.s_d.ldap_call.ldap_u.domainname, ireq, len) >= len) + return (-1); + if (strlcat(space.s_d.ldap_call.ldap_u.domainname, + NS_CACHE_ADDR_IP, len) >= len) + return (-1); + if (strlcat(space.s_d.ldap_call.ldap_u.domainname, DOORLINESEP, len) >= + len) + return (-1); + if (strlcat(space.s_d.ldap_call.ldap_u.domainname, server, len) >= len) + return (-1); sptr = &space.s_d; /* try to remove the server via the door interface */ diff --git a/usr/src/lib/libsldap/common/ns_config.c b/usr/src/lib/libsldap/common/ns_config.c index 1e52104c6c..fb24f7721b 100644 --- a/usr/src/lib/libsldap/common/ns_config.c +++ b/usr/src/lib/libsldap/common/ns_config.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -140,6 +139,7 @@ static ns_enum_map ns_auth_enum_v2[] = { { ENUM2INT(NS_LDAP_EA_SASL_DIGEST_MD5_CONF), "sasl/DIGEST-MD5:auth-conf" }, { ENUM2INT(NS_LDAP_EA_SASL_EXTERNAL), "sasl/EXTERNAL" }, + { ENUM2INT(NS_LDAP_EA_SASL_GSSAPI), "sasl/GSSAPI" }, { ENUM2INT(NS_LDAP_EA_TLS_NONE), "tls:none" }, { ENUM2INT(NS_LDAP_EA_TLS_SIMPLE), "tls:simple" }, { ENUM2INT(NS_LDAP_EA_TLS_SASL_CRAM_MD5), "tls:sasl/CRAM-MD5" }, @@ -1005,7 +1005,7 @@ __s_api_crosscheck(ns_config_t *ptr, char *errstr, int check_dn) int i, len, cnt; const char *begin; char **ppc; - int *pi; + int *pi, self, gssapi; if (ptr == NULL) @@ -1171,7 +1171,38 @@ __s_api_crosscheck(ns_config_t *ptr, char *errstr, int check_dn) } ptr->paramList[NS_LDAP_EXP_P].ns_tm = tm; } - + /* + * If credential level self is defined, there should be + * at least an auth method sasl/GSSAPI and vice versa. + */ + self = 0; + cnt = ptr->paramList[NS_LDAP_CREDENTIAL_LEVEL_P].ns_acnt; + for (i = 0; i < cnt; i++) { + if (ptr->paramList[NS_LDAP_CREDENTIAL_LEVEL_P].ns_pi[i] == + NS_LDAP_CRED_SELF) + self++; + } + gssapi = 0; + cnt = ptr->paramList[NS_LDAP_AUTH_P].ns_acnt; + for (i = 0; i < cnt; i++) { + if (ptr->paramList[NS_LDAP_AUTH_P].ns_pi[i] == + NS_LDAP_EA_SASL_GSSAPI) + gssapi++; + } + if (gssapi == 0 && self > 0) { + (void) snprintf(errstr, MAXERROR, + gettext("Configuration Error: " + "Credential level self requires " + "authentication method sasl/GSSAPI")); + return (NS_PARSE_ERR); + } + if (gssapi > 0 && self == 0) { + (void) snprintf(errstr, MAXERROR, + gettext("Configuration Error: " + "Authentication method sasl/GSSAPI " + "requires credential level self")); + return (NS_PARSE_ERR); + } return (NS_SUCCESS); } @@ -3453,6 +3484,12 @@ __s_api_AuthEnumtoStruct(const EnumAuthType_t i) ap->type = NS_LDAP_AUTH_SASL; ap->saslmech = NS_LDAP_SASL_EXTERNAL; break; + case NS_LDAP_EA_SASL_GSSAPI: + ap->type = NS_LDAP_AUTH_SASL; + ap->saslmech = NS_LDAP_SASL_GSSAPI; + ap->saslopt = NS_LDAP_SASLOPT_INT | + NS_LDAP_SASLOPT_PRIV; + break; case NS_LDAP_EA_TLS_NONE: ap->type = NS_LDAP_AUTH_TLS; ap->tlstype = NS_LDAP_TLS_NONE; diff --git a/usr/src/lib/libsldap/common/ns_connect.c b/usr/src/lib/libsldap/common/ns_connect.c index ccf75a9963..514c802b34 100644 --- a/usr/src/lib/libsldap/common/ns_connect.c +++ b/usr/src/lib/libsldap/common/ns_connect.c @@ -38,6 +38,7 @@ #include <nsswitch.h> #include <nss_dbdefs.h> #include "solaris-priv.h" +#include "solaris-int.h" #include "ns_sldap.h" #include "ns_internal.h" #include "ns_cache_door.h" @@ -54,8 +55,18 @@ extern int ldapssl_install_gethostbyaddr(LDAP *ld, const char *skip); static int openConnection(LDAP **, const char *, const ns_cred_t *, int, ns_ldap_error_t **, int, int); - -static mutex_t sessionPoolLock = DEFAULTMUTEX; +/* + * sessionLock, wait4session, sessionTid + * are variables to synchronize the creation/retrieval of a connection. + * MTperCon is a flag to enable/disable multiple threads sharing the same + * connection. + * sessionPoolLock is a mutex lock for the connection pool. + */ +static mutex_t sessionLock = DEFAULTMUTEX; +static int wait4session = 0; +static thread_t sessionTid = 0; +int MTperConn = 1; +static rwlock_t sessionPoolLock = DEFAULTRWLOCK; static Connection **sessionPool = NULL; static int sessionPoolSize = 0; @@ -65,10 +76,239 @@ static mutex_t nscdLock = DEFAULTMUTEX; static int nscdChecked = 0; static pid_t checkedPid = -1; static int isNscd = 0; +/* + * SSF values are for SASL integrity & privacy. + * JES DS5.2 does not support this feature but DS6 does. + * The values between 0 and 65535 can work with both server versions. + */ +#define MAX_SASL_SSF 65535 +#define MIN_SASL_SSF 0 /* Number of hostnames to allocate memory for */ #define NUMTOMALLOC 32 +/* + * ns_mtckey is for sharing a ldap connection among multiple + * threads; created by ns_ldap_init() in ns_init.c + */ +extern thread_key_t ns_mtckey; + +/* Per thread LDAP error resides in thread-specific data. */ +struct ldap_error { + int le_errno; + char *le_matched; + char *le_errmsg; +}; + +/* destructor */ +void +ns_tsd_cleanup(void *key) { + struct ldap_error *le = (struct ldap_error *)key; + + if (le == NULL) + return; + if (le->le_matched != NULL) { + ldap_memfree(le->le_matched); + } + if (le->le_errmsg != NULL) { + ldap_memfree(le->le_errmsg); + } + free(le); +} + +/* Callback function for allocating a mutex */ +static void * +ns_mutex_alloc(void) +{ + mutex_t *mutexp = NULL; + + if ((mutexp = malloc(sizeof (mutex_t))) != NULL) { + if (mutex_init(mutexp, USYNC_THREAD, NULL) != 0) { + free(mutexp); + mutexp = NULL; + } + } + return (mutexp); +} + +/* Callback function for freeing a mutex */ +static void +ns_mutex_free(void *mutexp) +{ + (void) mutex_destroy((mutex_t *)mutexp); + free(mutexp); +} + +/* + * Function for setting up thread-specific data + * where per thread LDAP error is stored + */ +static int +tsd_setup() +{ + void *tsd; + int rc; + + /* return success if TSD already set */ + rc = thr_getspecific(ns_mtckey, &tsd); + if (rc == 0 && tsd != NULL) + return (0); + + /* allocate and set TSD */ + tsd = (void *) calloc(1, sizeof (struct ldap_error)); + if (tsd == NULL) + return (-1); + rc = thr_setspecific(ns_mtckey, tsd); + if (rc != 0) { /* must be ENOMEM */ + free(tsd); + return (-1); + } + return (0); + + +} + +/* Callback function for setting the per thread LDAP error */ +/*ARGSUSED*/ +static void +set_ld_error(int err, char *matched, char *errmsg, void *dummy) +{ + struct ldap_error *le; + + if (thr_getspecific(ns_mtckey, (void **)&le) != 0) { + syslog(LOG_ERR, "set_ld_error: thr_getspecific failed. errno" + " %d", errno); + return; + } + le->le_errno = err; + if (le->le_matched != NULL) { + ldap_memfree(le->le_matched); + } + le->le_matched = matched; + if (le->le_errmsg != NULL) { + ldap_memfree(le->le_errmsg); + } + le->le_errmsg = errmsg; +} +/* Callback function for getting the per thread LDAP error */ +/*ARGSUSED*/ +static int +get_ld_error(char **matched, char **errmsg, void *dummy) +{ + struct ldap_error *le; + + if (thr_getspecific(ns_mtckey, (void **)&le) != 0) { + syslog(LOG_ERR, "get_ld_error: thr_getspecific failed. errno" + " %d", errno); + return (errno); + } + if (matched != NULL) { + *matched = le->le_matched; + } + if (errmsg != NULL) { + *errmsg = le->le_errmsg; + } + return (le->le_errno); +} + +/* Callback function for setting per thread errno */ +static void +set_errno(int err) +{ + errno = err; +} + +/* Callback function for getting per thread errno */ +static int +get_errno(void) +{ + return (errno); +} + +/* + * set up to allow multiple threads to use the same ldap connection + */ +static int +setup_mt_conn(LDAP *ld) +{ + + struct ldap_thread_fns tfns; + struct ldap_extra_thread_fns extrafns; + int rc; + + /* + * Set the function pointers for dealing with mutexes + * and error information + */ + (void) memset(&tfns, '\0', sizeof (struct ldap_thread_fns)); + tfns.ltf_mutex_alloc = (void *(*)(void)) ns_mutex_alloc; + tfns.ltf_mutex_free = (void (*)(void *)) ns_mutex_free; + tfns.ltf_mutex_lock = (int (*)(void *)) mutex_lock; + tfns.ltf_mutex_unlock = (int (*)(void *)) mutex_unlock; + tfns.ltf_get_errno = get_errno; + tfns.ltf_set_errno = set_errno; + tfns.ltf_get_lderrno = get_ld_error; + tfns.ltf_set_lderrno = set_ld_error; + tfns.ltf_lderrno_arg = NULL; + + /* + * Set up this session to use those function pointers + */ + rc = ldap_set_option(ld, LDAP_OPT_THREAD_FN_PTRS, + (void *) &tfns); + if (rc < 0) { + syslog(LOG_WARNING, "libsldap: ldap_set_option " + "(LDAP_OPT_THREAD_FN_PTRS)"); + return (-1); + } + + /* + * Set the function pointers for working with semaphores + */ + (void) memset(&extrafns, '\0', + sizeof (struct ldap_extra_thread_fns)); + extrafns.ltf_threadid_fn = (void * (*)(void))thr_self; + extrafns.ltf_mutex_trylock = NULL; + extrafns.ltf_sema_alloc = NULL; + extrafns.ltf_sema_free = NULL; + extrafns.ltf_sema_wait = NULL; + extrafns.ltf_sema_post = NULL; + + /* Set up this session to use those function pointers */ + rc = ldap_set_option(ld, LDAP_OPT_EXTRA_THREAD_FN_PTRS, + (void *) &extrafns); + if (rc < 0) { + syslog(LOG_WARNING, "libsldap: ldap_set_option " + "(LDAP_OPT_EXTRA_THREAD_FN_PTRS)"); + return (-1); + } + + return (0); +} + +static void +ns_setup_mt_conn_and_tsd(LDAP *ld) { + thread_t t = thr_self(); + void *tsd; + /* set up to share this connection among threads */ + if (MTperConn == 1) { + if (tsd_setup() == -1) { + syslog(LOG_ERR, "tid= %d: unable " + "to set up TSD\n", t); + } else { + if (setup_mt_conn(ld) == -1) { + /* multiple threads per connection not supported */ + syslog(LOG_ERR, "tid= %d: multiple " + "threads per connection not " + "supported\n", t); + (void) thr_getspecific(ns_mtckey, &tsd); + ns_tsd_cleanup(tsd); + (void) thr_setspecific(ns_mtckey, NULL); + MTperConn = 0; + } + } + } +} /* * Check /proc/PID/psinfo to see if this process is nscd @@ -126,7 +366,7 @@ nscd_proc() static int __s_api_requestServer(const char *request, const char *server, - ns_server_info_t *ret, ns_ldap_error_t **error) + ns_server_info_t *ret, ns_ldap_error_t **error, const char *addrType) { union { ldap_data_t s_d; @@ -142,7 +382,7 @@ __s_api_requestServer(const char *request, const char *server, char **mptr, **mptr1, **cptr, **cptr1; int mcnt, ccnt; char **servers; - int rc; + int rc, len; if (ret == NULL || error == NULL) { return (NS_LDAP_OP_FAILED); @@ -157,18 +397,26 @@ __s_api_requestServer(const char *request, const char *server, else ireq = request; - adata = (sizeof (ldap_call_t) + strlen(ireq) +1); + adata = (sizeof (ldap_call_t) + strlen(ireq) + strlen(addrType) + 1); if (server != NULL) { adata += strlen(DOORLINESEP) + 1; adata += strlen(server) + 1; } ndata = sizeof (space); + len = sizeof (space) - sizeof (space.s_d.ldap_call.ldap_callnumber); space.s_d.ldap_call.ldap_callnumber = GETLDAPSERVER; - (void) strcpy(space.s_d.ldap_call.ldap_u.domainname, ireq); + if (strlcpy(space.s_d.ldap_call.ldap_u.domainname, ireq, len) >= len) + return (NS_LDAP_MEMORY); + if (strlcat(space.s_d.ldap_call.ldap_u.domainname, addrType, len) >= + len) + return (NS_LDAP_MEMORY); if (server != NULL) { - (void) strcat(space.s_d.ldap_call.ldap_u.domainname, - DOORLINESEP); - (void) strcat(space.s_d.ldap_call.ldap_u.domainname, server); + if (strlcat(space.s_d.ldap_call.ldap_u.domainname, + DOORLINESEP, len) >= len) + return (NS_LDAP_MEMORY); + if (strlcat(space.s_d.ldap_call.ldap_u.domainname, server, + len) >= len) + return (NS_LDAP_MEMORY); } sptr = &space.s_d; @@ -327,86 +575,120 @@ __s_api_requestServer(const char *request, const char *server, return (NS_LDAP_SUCCESS); } -#ifdef DEBUG /* * printCred(): prints the credential structure */ static void -printCred(FILE *fp, const ns_cred_t *cred) +printCred(int pri, const ns_cred_t *cred) { - if (fp == NULL) { - (void) fprintf(fp, "printCred: fp is NULL\n"); - return; - } + thread_t t = thr_self(); + if (cred == NULL) { - (void) fprintf(fp, "printCred: cred is NULL\n"); + syslog(LOG_ERR, "tid= %d: printCred: cred is NULL\n", t); return; } - (void) fprintf(fp, "AuthType=%d\n", cred->auth.type); - (void) fprintf(fp, "TlsType=%d\n", cred->auth.tlstype); - (void) fprintf(fp, "SaslMech=%d\n", cred->auth.saslmech); - (void) fprintf(fp, "SaslOpt=%d\n", cred->auth.saslopt); + syslog(pri, "tid= %d: AuthType=%d", t, cred->auth.type); + syslog(pri, "tid= %d: TlsType=%d", t, cred->auth.tlstype); + syslog(pri, "tid= %d: SaslMech=%d", t, cred->auth.saslmech); + syslog(pri, "tid= %d: SaslOpt=%d", t, cred->auth.saslopt); if (cred->hostcertpath) - (void) fprintf(fp, "hostCertPath=%s\n", cred->hostcertpath); + syslog(pri, "tid= %d: hostCertPath=%s\n", + t, cred->hostcertpath); if (cred->cred.unix_cred.userID) - (void) fprintf(fp, "userID=%s\n", cred->cred.unix_cred.userID); + syslog(pri, "tid= %d: userID=%s\n", + t, cred->cred.unix_cred.userID); if (cred->cred.unix_cred.passwd) - (void) fprintf(fp, "passwd=%s\n", cred->cred.unix_cred.passwd); + syslog(pri, "tid= %d: passwd=%s\n", + t, cred->cred.unix_cred.passwd); } /* * printConnection(): prints the connection structure */ static void -printConnection(FILE *fp, Connection *con) +printConnection(int pri, Connection *con) { - if (fp == NULL || con == NULL) + thread_t t = thr_self(); + + if (con == NULL) return; - (void) fprintf(fp, "connectionID=%d\n", con->connectionId); - (void) fprintf(fp, "usedBit=%d\n", con->usedBit); - (void) fprintf(fp, "threadID=%d\n", con->threadID); + syslog(pri, "tid= %d: connectionID=%d\n", t, con->connectionId); + syslog(pri, "tid= %d: shared=%d\n", t, con->shared); + syslog(pri, "tid= %d: usedBit=%d\n", t, con->usedBit); + syslog(pri, "tid= %d: threadID=%d\n", t, con->threadID); if (con->serverAddr) { - (void) fprintf(fp, "serverAddr=%s\n", con->serverAddr); + syslog(pri, "tid= %d: serverAddr=%s\n", + t, con->serverAddr); } - printCred(fp, con->auth); - (void) fprintf(fp, "-----------------------------------------------\n"); - fflush(fp); + printCred(pri, con->auth); } -#endif /* DEBUG */ /* - * addConnection(): inserts a connection in the connection list. - * It will also sets use bit and the thread Id for the thread - * using the connection for the first time. + * addConnection(): set up a connection so that it can be shared + * among multiple threads and then insert the connection in the + * connection list. * Returns: -1 = failure, new Connection ID = success + * + * This function could exit with sessionLock locked. It will be + * be unlocked in __s_api_getConnection() when it exits without getting a + * connection. */ static int addConnection(Connection *con) { - int i; + int i, noMTperC = 0; + thread_t t = thr_self(); + struct ldap_thread_fns tfns; + void *tsd; if (!con) return (-1); -#ifdef DEBUG - (void) fprintf(stderr, "Adding connection thrid=%d\n", con->threadID); -#endif /* DEBUG */ - (void) mutex_lock(&sessionPoolLock); + + syslog(LOG_DEBUG, "tid= %d: Adding connection (serverAddr=%s)", + t, con->serverAddr); + + if (MTperConn == 1) { + /* + * Make sure ld has proper thread functions and tsd + * is set up. + */ + (void) memset(&tfns, 0, sizeof (struct ldap_thread_fns)); + /* + * ldap_init sets ltf_get_lderrno and ltf_set_lderrno to NULLs. + * It's supposed to be overwritten by ns_setup_mt_conn_and_tsd. + */ + if (ldap_get_option(con->ld, LDAP_OPT_THREAD_FN_PTRS, + (void *)&tfns) != 0 || + tfns.ltf_get_lderrno != get_ld_error || + tfns.ltf_set_lderrno != set_ld_error) { + MTperConn = 0; + noMTperC = 1; + } else { + if (thr_getspecific(ns_mtckey, &tsd) != 0 || + tsd == NULL) + noMTperC = 1; + } + + } else { + noMTperC = 1; + } + + (void) rw_wrlock(&sessionPoolLock); if (sessionPool == NULL) { sessionPoolSize = SESSION_CACHE_INC; sessionPool = calloc(sessionPoolSize, sizeof (struct connection **)); if (!sessionPool) { - (void) mutex_unlock(&sessionPoolLock); + (void) rw_unlock(&sessionPoolLock); return (-1); } -#ifdef DEBUG - (void) fprintf(stderr, "Initialized sessionPool\n"); -#endif /* DEBUG */ + + syslog(LOG_DEBUG, "tid= %d: Initialized sessionPool", t); } for (i = 0; (i < sessionPoolSize) && (sessionPool[i] != NULL); ++i) ; @@ -417,26 +699,44 @@ addConnection(Connection *con) (sessionPoolSize + SESSION_CACHE_INC) * sizeof (Connection *)); if (!cl) { - (void) mutex_unlock(&sessionPoolLock); + (void) rw_unlock(&sessionPoolLock); return (-1); } (void) memset(cl + sessionPoolSize, 0, SESSION_CACHE_INC * sizeof (struct connection *)); sessionPool = cl; sessionPoolSize += SESSION_CACHE_INC; -#ifdef DEBUG - (void) fprintf(stderr, "Increased sessionPoolSize to: %d\n", - sessionPoolSize); -#endif /* DEBUG */ + syslog(LOG_DEBUG, "tid: %d: Increased " + "sessionPoolSize to: %d\n", + t, sessionPoolSize); } sessionPool[i] = con; - con->usedBit = B_TRUE; - (void) mutex_unlock(&sessionPoolLock); + if (noMTperC == 0) + con->shared++; + else + con->usedBit = B_TRUE; + + (void) rw_unlock(&sessionPoolLock); + con->connectionId = i + CONID_OFFSET; -#ifdef DEBUG - (void) fprintf(stderr, "Connection added [%d]\n", i); - printConnection(stderr, con); -#endif /* DEBUG */ + + syslog(LOG_DEBUG, "tid= %d: Connection added [%d]\n", + t, i); + printConnection(LOG_DEBUG, con); + + /* + * A connection can be shared now, unlock + * the session mutex and let other + * threads try to use this connection or + * get their own. + */ + if (wait4session != 0 && sessionTid == thr_self()) { + wait4session = 0; + sessionTid = 0; + syslog(LOG_DEBUG, "tid= %d: unlocking sessionLock\n", t); + (void) mutex_unlock(&sessionLock); + } + return (i + CONID_OFFSET); } @@ -453,6 +753,11 @@ findConnectionById(int flags, const ns_cred_t *auth, ConnectionID cID, if ((conp == NULL) || (auth == NULL) || cID < CONID_OFFSET) return (-1); + + /* if a new connection is requested, no need to continue */ + if (flags & NS_LDAP_NEW_CONN) + return (-1); + *conp = NULL; if (sessionPool == NULL) return (-1); @@ -460,9 +765,9 @@ findConnectionById(int flags, const ns_cred_t *auth, ConnectionID cID, if (id < 0 || id >= sessionPoolSize) return (-1); - (void) mutex_lock(&sessionPoolLock); + (void) rw_rdlock(&sessionPoolLock); if (sessionPool[id] == NULL) { - (void) mutex_unlock(&sessionPoolLock); + (void) rw_unlock(&sessionPoolLock); return (-1); } cp = sessionPool[id]; @@ -471,11 +776,12 @@ findConnectionById(int flags, const ns_cred_t *auth, ConnectionID cID, * Make sure the connection has the same type of authentication method */ if ((cp->usedBit) || + (cp->notAvail) || (cp->auth->auth.type != auth->auth.type) || (cp->auth->auth.tlstype != auth->auth.tlstype) || (cp->auth->auth.saslmech != auth->auth.saslmech) || (cp->auth->auth.saslopt != auth->auth.saslopt)) { - (void) mutex_unlock(&sessionPoolLock); + (void) rw_unlock(&sessionPoolLock); return (-1); } if ((((cp->auth->auth.type == NS_LDAP_AUTH_SASL) && @@ -485,18 +791,19 @@ findConnectionById(int flags, const ns_cred_t *auth, ConnectionID cID, ((cp->auth->cred.unix_cred.userID == NULL) || (strcasecmp(cp->auth->cred.unix_cred.userID, auth->cred.unix_cred.userID) != 0))) { - (void) mutex_unlock(&sessionPoolLock); + (void) rw_unlock(&sessionPoolLock); return (-1); } + /* An existing connection is found but it needs to be reset */ if (flags & NS_LDAP_NEW_CONN) { - (void) mutex_unlock(&sessionPoolLock); + (void) rw_unlock(&sessionPoolLock); DropConnection(cID, 0); return (-1); } /* found an available connection */ cp->usedBit = B_TRUE; - (void) mutex_unlock(&sessionPoolLock); + (void) rw_unlock(&sessionPoolLock); cp->threadID = thr_self(); *conp = cp; return (cID); @@ -508,39 +815,111 @@ findConnectionById(int flags, const ns_cred_t *auth, ConnectionID cID, * If serverAddr is NULL, then find a connection to any server * as long as it matches the rest of the parameters. * Returns: -1 = failure, the Connection ID found = success. + * + * This function could exit with sessionLock locked. It will be + * be unlocked in addConnection() when this thread adds the connection + * to the pool or in __s_api_getConnection() when it exits without getting a + * connection. */ +#define TRY_TIMES 10 static int -findConnection(const char *serverAddr, const ns_cred_t *auth, Connection **conp) +findConnection(int flags, const char *serverAddr, + const ns_cred_t *auth, Connection **conp) { Connection *cp; int i; + int rc; + int try; +#ifdef DEBUG + thread_t t = thr_self(); +#endif /* DEBUG */ if (auth == NULL || conp == NULL) return (-1); *conp = NULL; + /* no need to find connection if anonymous */ + if (auth->auth.type == NS_LDAP_AUTH_NONE) + return (-1); + + /* if a new connection is requested, no need to continue */ + if (flags & NS_LDAP_NEW_CONN) + return (-1); + #ifdef DEBUG - (void) fprintf(stderr, "Find connection\n"); - (void) fprintf(stderr, "Looking for ....\n"); + (void) fprintf(stderr, "tid= %d: Find connection\n", t); + (void) fprintf(stderr, "tid= %d: Looking for ....\n", t); if (serverAddr && *serverAddr) - (void) fprintf(stderr, "serverAddr=%s\n", serverAddr); + (void) fprintf(stderr, "tid= %d: serverAddr=%s\n", + t, serverAddr); else - (void) fprintf(stderr, "serverAddr=NULL\n"); + (void) fprintf(stderr, "tid= %d: serverAddr=NULL\n", t); printCred(stderr, auth); fflush(stderr); #endif /* DEBUG */ - if (sessionPool == NULL) + + /* + * If multiple threads per connection not supported, + * no sessionPool means no connection + */ + (void) rw_rdlock(&sessionPoolLock); + if (MTperConn == 0 && sessionPool == NULL) { + (void) rw_unlock(&sessionPoolLock); return (-1); - (void) mutex_lock(&sessionPoolLock); + } + + /* + * If no connection in cache, then serialize the opening + * of connections. Make sure only one is being opened + * at a time. Otherwise, we may end up with more + * connections than we want (if multiple threads get + * here at the same time) + */ + if (sessionPool == NULL) { + (void) rw_unlock(&sessionPoolLock); + (void) mutex_lock(&sessionLock); + if (sessionPool == NULL) { + wait4session = 1; + sessionTid = thr_self(); +#ifdef DEBUG + (void) fprintf(stderr, "tid= %d: get " + "connection ... \n", t); + fflush(stderr); +#endif /* DEBUG */ + /* + * Exit with sessionLock locked. It will be + * be unlocked in addConnection() when this + * thread adds the connection to the pool or + * in __s_api_getConnection() when it exits + * without getting a connection. + */ + return (-1); + } + +#ifdef DEBUG + (void) fprintf(stderr, "tid= %d: session pool not empty\n", t); + fflush(stderr); +#endif /* DEBUG */ + /* + * connection pool is not empty, check to see if + * one can be shared. + */ + (void) mutex_unlock(&sessionLock); + (void) rw_rdlock(&sessionPoolLock); + } + try = 0; + check_again: + for (i = 0; i < sessionPoolSize; ++i) { if (sessionPool[i] == NULL) continue; cp = sessionPool[i]; #ifdef DEBUG - (void) fprintf(stderr, "checking connection [%d] ....\n", i); + (void) fprintf(stderr, "tid= %d: checking connection " + "[%d] ....\n", t, i); printConnection(stderr, cp); #endif /* DEBUG */ - if ((cp->usedBit) || + if ((cp->usedBit) || (cp->notAvail) || (cp->auth->auth.type != auth->auth.type) || (cp->auth->auth.tlstype != auth->auth.tlstype) || (cp->auth->auth.saslmech != auth->auth.saslmech) || @@ -560,18 +939,89 @@ findConnection(const char *serverAddr, const ns_cred_t *auth, Connection **conp) auth->cred.unix_cred.passwd) != 0)))) continue; /* found an available connection */ - cp->usedBit = B_TRUE; - (void) mutex_unlock(&sessionPoolLock); - cp->threadID = thr_self(); + if (MTperConn == 0) + cp->usedBit = B_TRUE; + else { + /* allocate TSD for per thread ldap error */ + rc = tsd_setup(); + + /* if we got TSD, this connection is shared */ + if (rc != -1) + cp->shared++; + else if (cp->shared == 0) { + cp->usedBit = B_TRUE; + cp->threadID = thr_self(); + (void) rw_unlock(&sessionPoolLock); + return (-1); + } + } + (void) rw_unlock(&sessionPoolLock); + *conp = cp; #ifdef DEBUG - (void) fprintf(stderr, "Connection found cID=%d\n", i); + (void) fprintf(stderr, "tid= %d: Connection found " + "cID=%d, shared =%d\n", t, i, cp->shared); fflush(stderr); #endif /* DEBUG */ return (i + CONID_OFFSET); } - (void) mutex_unlock(&sessionPoolLock); - return (-1); + (void) rw_unlock(&sessionPoolLock); + + /* + * If multiple threads per connection not supported, + * we are done, just return -1 to tell the caller to + * proceed with opening a connection + */ + if (MTperConn == 0) + return (-1); + + /* + * No connection can be shared, test to see if + * one is being opened. If trylock returns + * EBUSY then it is, so wait until the opening + * is done and try to see if the new connection + * can be shared. + */ + rc = mutex_trylock(&sessionLock); + if (rc == EBUSY) { + (void) mutex_lock(&sessionLock); + (void) mutex_unlock(&sessionLock); + (void) rw_rdlock(&sessionPoolLock); +#ifdef DEBUG + (void) fprintf(stderr, "tid= %d: check session " + "pool again\n", t); + fflush(stderr); +#endif /* DEBUG */ + if (try < TRY_TIMES) { + try++; + goto check_again; + } else { + syslog(LOG_WARNING, "libsldap: mutex_trylock " + "%d times. Stop.", TRY_TIMES); + return (-1); + } + } else if (rc == 0) { + /* + * No connection can be shared, none being opened, + * exit with sessionLock locked to open one. The + * mutex will be unlocked in addConnection() when + * this thread adds the new connection to the pool + * or in __s_api_getConnection() when it exits + * without getting a connection. + */ + wait4session = 1; + sessionTid = thr_self(); +#ifdef DEBUG + (void) fprintf(stderr, "tid= %d: no connection found, " + "none being opened, get connection ...\n", t); + fflush(stderr); +#endif /* DEBUG */ + return (-1); + } else { + syslog(LOG_WARNING, "libsldap: mutex_trylock unexpected " + "error", rc); + return (-1); + } } /* @@ -607,7 +1057,7 @@ static int makeConnection(Connection **conp, const char *serverAddr, const ns_cred_t *auth, ConnectionID *cID, int timeoutSec, ns_ldap_error_t **errorp, int fail_if_new_pwd_reqd, - int nopasswd_acct_mgmt, char ***badsrvrs) + int nopasswd_acct_mgmt, int flags, char ***badsrvrs) { Connection *con = NULL; ConnectionID id; @@ -618,7 +1068,9 @@ makeConnection(Connection **conp, const char *serverAddr, LDAP *ld = NULL; int passwd_mgmt = 0; int totalbad = 0; /* Number of servers contacted unsuccessfully */ - short memerr = 0; /* Variable for tracking memory allocation errors */ + short memerr = 0; /* Variable for tracking memory allocation */ + char *serverAddrType = NULL; + if (conp == NULL || errorp == NULL || auth == NULL) return (NS_LDAP_INVALID_PARAM); @@ -628,10 +1080,11 @@ makeConnection(Connection **conp, const char *serverAddr, sinfo.controls = NULL; sinfo.saslMechanisms = NULL; - if ((id = findConnection(serverAddr, auth, &con)) != -1) { + if ((id = findConnection(flags, serverAddr, auth, &con)) != -1) { /* connection found in cache */ #ifdef DEBUG - (void) fprintf(stderr, "connection found in cache %d\n", id); + (void) fprintf(stderr, "tid= %d: connection found in " + "cache %d\n", thr_self(), id); fflush(stderr); #endif /* DEBUG */ *cID = id; @@ -639,21 +1092,26 @@ makeConnection(Connection **conp, const char *serverAddr, return (NS_LDAP_SUCCESS); } + if (auth->auth.saslmech == NS_LDAP_SASL_GSSAPI) + serverAddrType = NS_CACHE_ADDR_HOSTNAME; + else + serverAddrType = NS_CACHE_ADDR_IP; + if (serverAddr) { - rc = openConnection(&ld, serverAddr, auth, timeoutSec, errorp, + rc = __s_api_requestServer(NS_CACHE_NEW, serverAddr, + &sinfo, errorp, serverAddrType); + if (rc != NS_LDAP_SUCCESS || sinfo.server == NULL) { + (void) snprintf(errmsg, sizeof (errmsg), + gettext("makeConnection: unable to get " + "server information for %s"), serverAddr); + syslog(LOG_ERR, "libsldap: %s", errmsg); + return (NS_LDAP_OP_FAILED); + } + rc = openConnection(&ld, sinfo.server, auth, timeoutSec, errorp, fail_if_new_pwd_reqd, passwd_mgmt); if (rc == NS_LDAP_SUCCESS || rc == NS_LDAP_SUCCESS_WITH_INFO) { exit_rc = rc; - rc = __s_api_requestServer(NS_CACHE_NEW, serverAddr, - &sinfo, errorp); - if (rc != NS_LDAP_SUCCESS || sinfo.server == NULL) { - (void) snprintf(errmsg, sizeof (errmsg), - gettext("makeConnection: unable to get " - "server information for %s"), serverAddr); - syslog(LOG_ERR, "libsldap: %s", errmsg); - return (NS_LDAP_OP_FAILED); - } goto create_con; } else { return (rc); @@ -666,7 +1124,8 @@ makeConnection(Connection **conp, const char *serverAddr, hReq = NS_CACHE_NEW; else hReq = NS_CACHE_NEXT; - rc = __s_api_requestServer(hReq, host, &sinfo, errorp); + rc = __s_api_requestServer(hReq, host, &sinfo, errorp, + serverAddrType); if ((rc != NS_LDAP_SUCCESS) || (sinfo.server == NULL) || (host && (strcasecmp(host, sinfo.server) == 0))) { /* Log the error */ @@ -851,6 +1310,7 @@ create_con: } con->threadID = thr_self(); + con->ld = ld; if ((id = addConnection(con)) == -1) { freeConnection(con); @@ -866,7 +1326,8 @@ create_con: return (NS_LDAP_MEMORY); } #ifdef DEBUG - (void) fprintf(stderr, "connection added into cache %d\n", id); + (void) fprintf(stderr, "tid= %d: connection added into " + "cache %d\n", thr_self(), id); fflush(stderr); #endif /* DEBUG */ *cID = id; @@ -884,42 +1345,86 @@ _DropConnection(ConnectionID cID, int flag, int fini) { Connection *cp; int id; - int use_mutex = !fini; + int use_lock = !fini; +#ifdef DEBUG + thread_t t = thr_self(); +#endif /* DEBUG */ id = cID - CONID_OFFSET; if (id < 0 || id >= sessionPoolSize) return; #ifdef DEBUG - (void) fprintf(stderr, - "Dropping connection cID=%d flag=0x%x\n", cID, flag); + (void) fprintf(stderr, "tid= %d: " + "Dropping connection cID=%d flag=0x%x, fini = %d\n", + t, cID, flag, fini); fflush(stderr); #endif /* DEBUG */ - if (use_mutex) - (void) mutex_lock(&sessionPoolLock); + if (use_lock) + (void) rw_wrlock(&sessionPoolLock); cp = sessionPool[id]; /* sanity check before removing */ - if (!cp || (!fini && (!cp->usedBit || cp->threadID != thr_self()))) { - if (use_mutex) - (void) mutex_unlock(&sessionPoolLock); + if (!cp || (!fini && !cp->shared && (!cp->usedBit || + cp->threadID != thr_self()))) { +#ifdef DEBUG + if (cp == NULL) + (void) fprintf(stderr, "tid= %d: no " + "need to remove (fini = %d, cp = %p)\n", t, + fini, cp); + else + (void) fprintf(stderr, "tid= %d: no " + "need to remove (fini = %d, cp = %p, shared = %d)\n", + t, fini, cp, cp->shared); + fflush(stderr); +#endif /* DEBUG */ + if (use_lock) + (void) rw_unlock(&sessionPoolLock); return; } if (!fini && - ((flag & NS_LDAP_NEW_CONN) == 0) && - ((flag & NS_LDAP_KEEP_CONN) || nscd_proc())) { + ((flag & NS_LDAP_NEW_CONN) == 0) && !cp->notAvail && + ((flag & NS_LDAP_KEEP_CONN) || + (MTperConn == 0 && nscd_proc()) || + MTperConn)) { +#ifdef DEBUG + (void) fprintf(stderr, "tid= %d: keep alive (fini = %d " + "shared = %d)\n", t, fini, cp->shared); +#endif /* DEBUG */ /* release Connection (keep alive) */ + if (cp->shared) + cp->shared--; cp->usedBit = B_FALSE; cp->threadID = 0; /* unmark the threadID */ - if (use_mutex) - (void) mutex_unlock(&sessionPoolLock); + if (use_lock) + (void) rw_unlock(&sessionPoolLock); } else { /* delete Connection (disconnect) */ - sessionPool[id] = NULL; - if (use_mutex) - (void) mutex_unlock(&sessionPoolLock); - (void) ldap_unbind(cp->ld); - freeConnection(cp); + if (cp->shared > 0) { +#ifdef DEBUG + (void) fprintf(stderr, "tid= %d: Connection no " + "longer available (fini = %d, shared = %d)\n", + t, fini, cp->shared); + fflush(stderr); +#endif /* DEBUG */ + cp->shared--; + cp->notAvail = 1; + } + + if (cp->shared <= 0) { +#ifdef DEBUG + (void) fprintf(stderr, "tid= %d: unbind " + "(fini = %d, shared = %d)\n", + t, fini, cp->shared); + fflush(stderr); +#endif /* DEBUG */ + sessionPool[id] = NULL; + (void) ldap_unbind(cp->ld); + freeConnection(cp); + } + + if (use_lock) + (void) rw_unlock(&sessionPoolLock); } } @@ -1189,16 +1694,17 @@ openConnection(LDAP **ldp, const char *serverAddr, const ns_cred_t *auth, int errnum = 0; LDAPMessage *resultMsg; int msgId; - int useSSL = 0; + int useSSL = 0, port = 0; struct timeval tv; AuthType_t bindType; int timeoutMilliSec = timeoutSec * 1000; struct berval cred; char *sslServerAddr; char *s1; - char *errmsg; + char *errmsg, *end = NULL; LDAPControl **controls; - int pwd_rc; + int pwd_rc, min_ssf = MIN_SASL_SSF, max_ssf = MAX_SASL_SSF; + ns_sasl_cb_param_t sasl_param; *errorp = NULL; *ldp = NULL; @@ -1246,7 +1752,8 @@ openConnection(LDAP **ldp, const char *serverAddr, const ns_cred_t *auth, const char *hostcertpath; char *alloc_hcp = NULL; #ifdef DEBUG - (void) fprintf(stderr, "+++TLS transport\n"); + (void) fprintf(stderr, "tid= %d: +++TLS transport\n", + thr_self()); #endif /* DEBUG */ if (prldap_set_session_option(NULL, NULL, @@ -1324,15 +1831,40 @@ openConnection(LDAP **ldp, const char *serverAddr, const ns_cred_t *auth, } } else { #ifdef DEBUG - (void) fprintf(stderr, "+++Unsecure transport\n"); + (void) fprintf(stderr, "tid= %d: +++Unsecure transport\n", + thr_self()); #endif /* DEBUG */ - /* Warning message IF cannot connect to host(s) */ - if ((ld = ldap_init((char *)serverAddr, LDAP_PORT)) == NULL) { + port = LDAP_PORT; + if (auth->auth.saslmech == NS_LDAP_SASL_GSSAPI && + (end = strchr(serverAddr, ':')) != NULL) { + /* + * The IP is converted to hostname so it's a + * hostname:port up to this point. + * + * libldap passes hostname:port to the sasl layer. + * The ldap service principal is constructed as + * ldap/hostname:port@REALM. Kerberos authentication + * will fail. So it needs to be parsed to construct + * a valid principal ldap/hostname@REALM. + * + * For useSSL case above, it already parses port so + * no need to parse serverAddr + */ + *end = '\0'; + port = atoi(end + 1); + } + + /* Warning message IF cannot connect to host(s) */ + if ((ld = ldap_init((char *)serverAddr, port)) == NULL) { char *p = strerror(errno); MKERROR(LOG_WARNING, *errorp, LDAP_CONNECT_ERROR, strdup(p), NULL); + if (end) + *end = ':'; return (NS_LDAP_INTERNAL); } else { + if (end) + *end = ':'; /* check and avoid gethostname recursion */ if (ldap_in_hosts_switch() > 0 && ! __s_api_isipv4((char *)serverAddr) && @@ -1340,21 +1872,22 @@ openConnection(LDAP **ldp, const char *serverAddr, const ns_cred_t *auth, /* host: ldap - found, attempt to recover */ if (ldap_set_option(ld, LDAP_X_OPT_DNS_SKIPDB, "ldap") != 0) { - (void) snprintf(errstr, sizeof (errstr), - gettext("openConnection: " - "unrecoverable gethostname " - "recursion detected " - "in /etc/nsswitch.conf")); - MKERROR(LOG_WARNING, *errorp, - LDAP_CONNECT_ERROR, - strdup(errstr), NULL); - (void) ldap_unbind(ld); - return (NS_LDAP_INTERNAL); + (void) snprintf(errstr, sizeof (errstr), + gettext("openConnection: " + "unrecoverable gethostname " + "recursion detected " + "in /etc/nsswitch.conf")); + MKERROR(LOG_WARNING, *errorp, + LDAP_CONNECT_ERROR, + strdup(errstr), NULL); + (void) ldap_unbind(ld); + return (NS_LDAP_INTERNAL); } } } } + ns_setup_mt_conn_and_tsd(ld); (void) ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, &ldapVersion); (void) ldap_set_option(ld, LDAP_OPT_DEREF, &derefOption); /* @@ -1377,7 +1910,8 @@ openConnection(LDAP **ldp, const char *serverAddr, const ns_cred_t *auth, switch (bindType) { case NS_LDAP_AUTH_NONE: #ifdef DEBUG - (void) fprintf(stderr, "+++Anonymous bind\n"); + (void) fprintf(stderr, "tid= %d: +++Anonymous bind\n", + thr_self()); #endif /* DEBUG */ break; case NS_LDAP_AUTH_SIMPLE: @@ -1394,7 +1928,8 @@ openConnection(LDAP **ldp, const char *serverAddr, const ns_cred_t *auth, } #ifdef DEBUG - (void) fprintf(stderr, "+++Simple bind\n"); + (void) fprintf(stderr, "tid= %d: +++Simple bind\n", + thr_self()); #endif /* DEBUG */ msgId = ldap_simple_bind(ld, binddn, passwd); @@ -1462,31 +1997,35 @@ openConnection(LDAP **ldp, const char *serverAddr, const ns_cred_t *auth, break; case NS_LDAP_AUTH_SASL: - /* We don't support any sasl options yet */ - if (auth->auth.saslopt != NS_LDAP_SASLOPT_NONE) { + if (auth->auth.saslopt != NS_LDAP_SASLOPT_NONE && + auth->auth.saslmech != NS_LDAP_SASL_GSSAPI) { (void) sprintf(errstr, gettext("openConnection: SASL options are " - "not supported (%d)"), auth->auth.saslopt); + "not supported (%d) for non-GSSAPI sasl bind"), + auth->auth.saslopt); MKERROR(LOG_WARNING, *errorp, LDAP_AUTH_METHOD_NOT_SUPPORTED, strdup(errstr), NULL); (void) ldap_unbind(ld); return (NS_LDAP_INTERNAL); } - binddn = auth->cred.unix_cred.userID; - passwd = auth->cred.unix_cred.passwd; - if (passwd == NULL || *passwd == '\0' || - binddn == NULL || *binddn == '\0') { - (void) sprintf(errstr, + if (auth->auth.saslmech != NS_LDAP_SASL_GSSAPI) { + binddn = auth->cred.unix_cred.userID; + passwd = auth->cred.unix_cred.passwd; + if (passwd == NULL || *passwd == '\0' || + binddn == NULL || *binddn == '\0') { + (void) sprintf(errstr, gettext("openConnection: missing credentials " "for SASL bind")); - MKERROR(LOG_WARNING, *errorp, LDAP_INVALID_CREDENTIALS, - strdup(errstr), NULL); - (void) ldap_unbind(ld); - return (NS_LDAP_INTERNAL); + MKERROR(LOG_WARNING, *errorp, + LDAP_INVALID_CREDENTIALS, + strdup(errstr), NULL); + (void) ldap_unbind(ld); + return (NS_LDAP_INTERNAL); + } + cred.bv_val = passwd; + cred.bv_len = strlen(passwd); } - cred.bv_val = passwd; - cred.bv_len = strlen(passwd); switch (auth->auth.saslmech) { case NS_LDAP_SASL_CRAM_MD5: @@ -1584,6 +2123,47 @@ openConnection(LDAP **ldp, const char *serverAddr, const ns_cred_t *auth, free(digest_md5_name); break; + case NS_LDAP_SASL_GSSAPI: + if (sasl_gssapi_inited == 0) { + rc = __s_api_sasl_gssapi_init(); + if (rc != NS_LDAP_SUCCESS) { + (void) snprintf(errstr, sizeof (errstr), + gettext("openConnection: " + "GSSAPI initialization " + "failed")); + (void) ldap_unbind(ld); + MKERROR(LOG_WARNING, *errorp, rc, + strdup(errstr), NULL); + return (rc); + } + } + (void) memset(&sasl_param, 0, + sizeof (ns_sasl_cb_param_t)); + sasl_param.authid = NULL; + sasl_param.authzid = ""; + (void) ldap_set_option(ld, LDAP_OPT_X_SASL_SSF_MIN, + (void *)&min_ssf); + (void) ldap_set_option(ld, LDAP_OPT_X_SASL_SSF_MAX, + (void *)&max_ssf); + + rc = ldap_sasl_interactive_bind_s( + ld, NULL, "GSSAPI", + NULL, NULL, LDAP_SASL_INTERACTIVE, + __s_api_sasl_bind_callback, + &sasl_param); + + if (rc != LDAP_SUCCESS) { + (void) snprintf(errstr, sizeof (errstr), + gettext("openConnection: " + "GSSAPI bind failed " + "- %d %s"), rc, ldap_err2string(rc)); + (void) ldap_unbind(ld); + MKERROR(LOG_WARNING, *errorp, NS_LDAP_INTERNAL, + strdup(errstr), NULL); + return (NS_LDAP_INTERNAL); + } + + break; default: (void) ldap_unbind(ld); (void) sprintf(errstr, @@ -1648,12 +2228,11 @@ __s_api_getDefaultAuth( return (NS_LDAP_INVALID_PARAM); } - /* - * Do not differentiate between (proxy/self) at this time, but - * reject self credential levels at this time + * credential level "self" can work with auth method sasl/GSSAPI only */ - if (cLevel && *cLevel == NS_LDAP_CRED_SELF) + if (cLevel && *cLevel == NS_LDAP_CRED_SELF && + aMethod->saslmech != NS_LDAP_SASL_GSSAPI) return (NS_LDAP_INVALID_PARAM); *authp = (ns_cred_t *)calloc(1, sizeof (ns_cred_t)); @@ -1674,7 +2253,7 @@ __s_api_getDefaultAuth( (aMethod->saslmech == NS_LDAP_SASL_CRAM_MD5)) { getUid++; getPasswd++; - } else { + } else if (aMethod->saslmech != NS_LDAP_SASL_GSSAPI) { (void) __ns_ldap_freeCred(authp); *authp = NULL; return (NS_LDAP_INVALID_PARAM); @@ -1845,7 +2424,7 @@ __s_api_getConnection( int sec = 1; ns_cred_t *authp = NULL; ns_cred_t anon; - int version = NS_LDAP_V2; + int version = NS_LDAP_V2, self_gssapi_only = 0; void **paramVal = NULL; char **badSrvrs = NULL; /* List of problem hostnames */ @@ -1941,16 +2520,20 @@ __s_api_getConnection( /* using specified auth method */ rc = makeConnection(&con, server, cred, sessionId, timeoutSec, errorp, - fail_if_new_pwd_reqd, nopasswd_acct_mgmt, - &badSrvrs); + fail_if_new_pwd_reqd, + nopasswd_acct_mgmt, flags, &badSrvrs); if (rc == NS_LDAP_SUCCESS || rc == NS_LDAP_SUCCESS_WITH_INFO) { *session = con; break; } } else { + self_gssapi_only = __s_api_self_gssapi_only_get(); /* for every cred level */ for (cNext = cLevel; *cNext != NULL; cNext++) { + if (self_gssapi_only && + **cNext != NS_LDAP_CRED_SELF) + continue; if (**cNext == NS_LDAP_CRED_ANON) { /* * make connection anonymously @@ -1964,7 +2547,8 @@ __s_api_getConnection( rc = makeConnection(&con, server, &anon, sessionId, timeoutSec, errorp, fail_if_new_pwd_reqd, - nopasswd_acct_mgmt, &badSrvrs); + nopasswd_acct_mgmt, flags, + &badSrvrs); if (rc == NS_LDAP_SUCCESS || rc == NS_LDAP_SUCCESS_WITH_INFO) { @@ -1975,6 +2559,22 @@ __s_api_getConnection( } /* for each cred level */ for (aNext = aMethod; *aNext != NULL; aNext++) { + if (self_gssapi_only && + (*aNext)->saslmech != + NS_LDAP_SASL_GSSAPI) + continue; + /* + * self coexists with sasl/GSSAPI only + * and non-self coexists with non-gssapi + * only + */ + if ((**cNext == NS_LDAP_CRED_SELF && + (*aNext)->saslmech != + NS_LDAP_SASL_GSSAPI) || + (**cNext != NS_LDAP_CRED_SELF && + (*aNext)->saslmech == + NS_LDAP_SASL_GSSAPI)) + continue; /* make connection and authenticate */ /* with default credentials */ authp = NULL; @@ -1994,7 +2594,8 @@ __s_api_getConnection( rc = makeConnection(&con, server, authp, sessionId, timeoutSec, errorp, fail_if_new_pwd_reqd, - nopasswd_acct_mgmt, &badSrvrs); + nopasswd_acct_mgmt, flags, + &badSrvrs); (void) __ns_ldap_freeCred(&authp); if (rc == NS_LDAP_SUCCESS || rc == @@ -2015,6 +2616,30 @@ __s_api_getConnection( } done: + /* + * If unable to get a connection, and this is + * the thread opening the shared connection, + * unlock the session mutex and let other + * threads try to get their own connection. + */ + if (wait4session != 0 && sessionTid == thr_self()) { + wait4session = 0; + sessionTid = 0; +#ifdef DEBUG + (void) fprintf(stderr, "tid= %d: __s_api_getConnection: " + "unlocking sessionLock \n", thr_self()); + fflush(stderr); +#endif /* DEBUG */ + (void) mutex_unlock(&sessionLock); + } + if (self_gssapi_only && rc == NS_LDAP_SUCCESS && *session == NULL) { + /* + * self_gssapi_only is true but no self/sasl/gssapi is + * configured + */ + rc = NS_LDAP_CONFIG; + } + (void) __ns_ldap_freeParam((void ***)&aMethod); (void) __ns_ldap_freeParam((void ***)&cLevel); @@ -2038,7 +2663,7 @@ _free_sessionPool() { int id; - (void) mutex_lock(&sessionPoolLock); + (void) rw_wrlock(&sessionPoolLock); if (sessionPool != NULL) { for (id = 0; id < sessionPoolSize; id++) _DropConnection(id + CONID_OFFSET, 0, 1); @@ -2046,5 +2671,5 @@ _free_sessionPool() sessionPool = NULL; sessionPoolSize = 0; } - (void) mutex_unlock(&sessionPoolLock); + (void) rw_unlock(&sessionPoolLock); } diff --git a/usr/src/lib/libsldap/common/ns_init.c b/usr/src/lib/libsldap/common/ns_init.c index e95a99375f..e9b6842210 100644 --- a/usr/src/lib/libsldap/common/ns_init.c +++ b/usr/src/lib/libsldap/common/ns_init.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 1999-2002 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -28,11 +27,25 @@ #include "ns_sldap.h" #include "ns_internal.h" +#include <syslog.h> #pragma init(ns_ldap_init) +thread_key_t ns_mtckey; + static void ns_ldap_init() { get_environment(); /* load environment debugging options */ + + /* + * ns_mtckey is needed to allow the sharing of an + * ldap connection among multiple threads. Used + * mainly in ns_connect.c. + */ + if (thr_keycreate(&ns_mtckey, ns_tsd_cleanup) != 0) { + syslog(LOG_ERR, "libsldap: unable to create the thread " + "key needed for sharing ldap connections"); + MTperConn = 0; + } } diff --git a/usr/src/lib/libsldap/common/ns_internal.h b/usr/src/lib/libsldap/common/ns_internal.h index 07fc60149e..699cb1dfa0 100644 --- a/usr/src/lib/libsldap/common/ns_internal.h +++ b/usr/src/lib/libsldap/common/ns_internal.h @@ -474,7 +474,7 @@ typedef enum EnumAuthType { NS_LDAP_EA_SASL_DIGEST_MD5_INT = 5, NS_LDAP_EA_SASL_DIGEST_MD5_CONF = 6, NS_LDAP_EA_SASL_EXTERNAL = 7, - NS_LDAP_EA_SASL_GSSAPI = 8, /* unsupported */ + NS_LDAP_EA_SASL_GSSAPI = 8, NS_LDAP_EA_SASL_SPNEGO = 9, /* unsupported */ NS_LDAP_EA_TLS_NONE = 10, NS_LDAP_EA_TLS_SIMPLE = 11, @@ -549,9 +549,15 @@ typedef int ConnectionID; */ typedef struct connection { ConnectionID connectionId; - boolean_t usedBit; + boolean_t usedBit; /* true if only used by */ + /* one thread and not shared */ + /* by other threads */ + boolean_t notAvail; /* not sharable, delete */ + /* when shared == 0 */ + int shared; /* number of threads */ + /* using this connection */ char *serverAddr; - ns_cred_t *auth; + ns_cred_t *auth; LDAP *ld; thread_t threadID; /* thread ID using it */ struct ns_ldap_cookie *cookieInfo; @@ -664,6 +670,23 @@ typedef struct ns_server_info { } ns_server_info_t; /* + * sasl callback function parameters + */ +typedef struct ns_sasl_cb_param { + char *mech; + char *authid; + char *authzid; + char *passwd; + char *realm; +} ns_sasl_cb_param_t; + +/* self/sasl/gssapi variable */ +extern int sasl_gssapi_inited; + +/* Multiple threads per connection variable */ +extern int MTperConn; + +/* * INTERNAL GLOBAL DEFINITIONS AND FUNCTION DECLARATIONS */ @@ -748,6 +771,29 @@ ns_ldap_error_t *__ns_ldap_LoadDoorInfo(LineBuf *configinfo, char *domainname); ns_ldap_error_t *__ns_ldap_DumpConfiguration(char *filename); ns_ldap_error_t *__ns_ldap_DumpLdif(char *filename); int __ns_ldap_cache_ping(); +ns_ldap_error_t *__ns_ldap_print_config(int); +void __ns_ldap_default_config(); +int __ns_ldap_download(const char *, char *, char *, + ns_ldap_error_t **); +int +__ns_ldap_check_dns_preq(int foreground, + int mode_verbose, + int mode_quiet, + const char *fname, + ns_ldap_self_gssapi_config_t config, + ns_ldap_error_t **errpp); +int +__ns_ldap_check_gssapi_preq(int foreground, + int mode_verbose, + int mode_quiet, + ns_ldap_self_gssapi_config_t config, + ns_ldap_error_t **errpp); +int +__ns_ldap_check_all_preq(int foreground, + int mode_verbose, + int mode_quiet, + ns_ldap_self_gssapi_config_t config, + ns_ldap_error_t **errpp); /* internal un-exposed APIs */ ns_cred_t *__ns_ldap_dupAuth(const ns_cred_t *authp); @@ -804,6 +850,19 @@ int __s_api_contain_account_usable_control_oid(char **oids); char *__s_api_get_canonical_name(ns_ldap_entry_t *entry, ns_ldap_attr_t *attrptr, int case_ignore); +/* self/sasl/gssapi functions */ +int __s_api_sasl_bind_callback( + LDAP *ld, + unsigned flags, + void *defaults, + void *in); + +int __s_api_self_gssapi_only_get(void); +int __s_api_sasl_gssapi_init(void); + +/* Multiple threads per connection functions */ +void ns_tsd_cleanup(void *); + #ifdef __cplusplus } #endif diff --git a/usr/src/lib/libsldap/common/ns_reads.c b/usr/src/lib/libsldap/common/ns_reads.c index 8db18695c4..3239ab9a55 100644 --- a/usr/src/lib/libsldap/common/ns_reads.c +++ b/usr/src/lib/libsldap/common/ns_reads.c @@ -2220,10 +2220,18 @@ search_state_machine(ns_ldap_cookie_t *cookie, ns_state_t state, int cycle) LDAP_ERROR; } if (cookie->connectionId > -1) { - DropConnection( + /* + * NS_LDAP_NEW_CONN + * indicates that the + * connection should + * be deleted, not + * kept alive + */ + DropConnection( cookie->connectionId, NS_LDAP_NEW_CONN); - cookie->connectionId = -1; + cookie->connectionId = + -1; } } break; @@ -3022,7 +3030,7 @@ __ns_ldap_auth(const ns_cred_t *auth, if (!auth) return (NS_LDAP_INVALID_PARAM); - rc = __s_api_getConnection(NULL, flags, + rc = __s_api_getConnection(NULL, flags | NS_LDAP_NEW_CONN, auth, &connectionId, &conp, errorp, do_not_fail_if_new_pwd_reqd, nopasswd_acct_mgmt); if (rc == NS_LDAP_OP_FAILED && *errorp) @@ -3047,6 +3055,20 @@ __ns_ldap_getAttr(const ns_ldap_entry_t *entry, const char *attrname) return (NULL); } +ns_ldap_attr_t * +__ns_ldap_getAttrStruct(const ns_ldap_entry_t *entry, const char *attrname) +{ + int i; + + if (entry == NULL) + return (NULL); + for (i = 0; i < entry->attr_count; i++) { + if (strcasecmp(entry->attr_pair[i]->attrname, attrname) == NULL) + return (entry->attr_pair[i]); + } + return (NULL); +} + /*ARGSUSED*/ int diff --git a/usr/src/lib/libsldap/common/ns_sasl.c b/usr/src/lib/libsldap/common/ns_sasl.c new file mode 100644 index 0000000000..fc708b735a --- /dev/null +++ b/usr/src/lib/libsldap/common/ns_sasl.c @@ -0,0 +1,580 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <stdio.h> +#include <stdlib.h> +#include <strings.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#include <thread.h> +#include <synch.h> +#include <sasl/sasl.h> +#include <sys/socket.h> +#include <netdb.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <syslog.h> +#include <ctype.h> +#include <libscf.h> +#include <libintl.h> +#include <locale.h> +#include "ns_sldap.h" +#include "ns_internal.h" + +static int self_gssapi_only = 0; +static mutex_t self_gssapi_only_lock = DEFAULTMUTEX; + +#define DNS_FMRI "svc:/network/dns/client:default" +#define MSGSIZE 256 + +#define NSSWITCH_CONF "/etc/nsswitch.conf" + +/* + * Error Handling + */ +#define CLIENT_FPRINTF if (mode_verbose && !mode_quiet) (void) fprintf + +/* + * One time initializtion + */ +int sasl_gssapi_inited = 0; +static mutex_t sasl_gssapi_lock = DEFAULTMUTEX; +int +__s_api_sasl_gssapi_init(void) { + int rc = NS_LDAP_SUCCESS; + (void) mutex_lock(&sasl_gssapi_lock); + if (!sasl_gssapi_inited) { + if (getuid() == 0) { + if (system( + "/usr/sbin/cryptoadm disable metaslot") + == 0) { + syslog(LOG_WARNING, + "libsldap: Metaslot disabled " + "for self credential mode"); + sasl_gssapi_inited = 1; + } else { + syslog(LOG_ERR, + "libsldap: Can't disable " + "Metaslot for self credential " + "mode"); + rc = NS_LDAP_INTERNAL; + } + } + } + (void) mutex_unlock(&sasl_gssapi_lock); + + return (rc); +} + +/* + * nscd calls this function to set self_gssapi_only flag so libsldap performs + * sasl/GSSAPI bind only. Also see comments of __ns_ldap_self_gssapi_config. + * + * Input: flag 0 use any kind of connection + * 1 use self/gssapi connection only + */ +void +__ns_ldap_self_gssapi_only_set(int flag) { + (void) mutex_lock(&self_gssapi_only_lock); + self_gssapi_only = flag; + (void) mutex_unlock(&self_gssapi_only_lock); +} +/* + * Get the flag value of self_gssapi_only + */ +int +__s_api_self_gssapi_only_get(void) { + int flag; + (void) mutex_lock(&self_gssapi_only_lock); + flag = self_gssapi_only; + (void) mutex_unlock(&self_gssapi_only_lock); + return (flag); +} +/* + * nscd calls this function to detect the current native ldap configuration. + * The output are + * NS_LDAP_SELF_GSSAPI_CONFIG_NONE: No credential level self and + * no authentication method sasl/GSSAPI is + * configured. + * NS_LDAP_SELF_GSSAPI_CONFIG_ONLY: Only credential level self and + * authentication method sasl/GSSAPI are + * configured. + * NS_LDAP_SELF_GSSAPI_CONFIG_MIXED: More than one credential level are + * configured, including self. + * More than one authentication method + * are configured, including sasl/GSSAPI. + * + * __s_api_crosscheck makes sure self and sasl/GSSAPI pair up if they do + * get configured. + * + * When nscd detects it's MIXED case, it calls __ns_ldap_self_gssapi_only_set + * to force libsldap to do sasl/GSSAPI bind only for per-user lookup. + * + * Return: NS_LDAP_SUCCESS + * OTHERWISE - FAILURE + * + * Output: config. See comments above. + * + */ +int +__ns_ldap_self_gssapi_config(ns_ldap_self_gssapi_config_t *config) { + int self = 0, other_level = 0, gssapi = 0, other_method = 0; + ns_auth_t **aMethod = NULL, **aNext = NULL; + int **cLevel = NULL, **cNext = NULL, rc; + ns_ldap_error_t *errp = NULL; + + if (config == NULL) + return (NS_LDAP_INVALID_PARAM); + else + *config = NS_LDAP_SELF_GSSAPI_CONFIG_NONE; + + /* Get the credential level list */ + if ((rc = __ns_ldap_getParam(NS_LDAP_CREDENTIAL_LEVEL_P, + (void ***)&cLevel, &errp)) != NS_LDAP_SUCCESS) { + if (errp) + (void) __ns_ldap_freeError(&errp); + if (cLevel) + (void) __ns_ldap_freeParam((void ***)&cLevel); + return (rc); + } + if (errp) + (void) __ns_ldap_freeError(&errp); + /* Get the authentication method list */ + if ((rc = __ns_ldap_getParam(NS_LDAP_AUTH_P, + (void ***)&aMethod, &errp)) != NS_LDAP_SUCCESS) { + if (errp) + (void) __ns_ldap_freeError(&errp); + if (cLevel) + (void) __ns_ldap_freeParam((void ***)&cLevel); + if (aMethod) + (void) __ns_ldap_freeParam((void ***)&aMethod); + return (rc); + } + if (errp) + (void) __ns_ldap_freeError(&errp); + + if (cLevel == NULL || aMethod == NULL) { + if (cLevel) + (void) __ns_ldap_freeParam((void ***)&cLevel); + if (aMethod) + (void) __ns_ldap_freeParam((void ***)&aMethod); + return (NS_LDAP_SUCCESS); + } + + for (cNext = cLevel; *cNext != NULL; cNext++) { + if (**cNext == NS_LDAP_CRED_SELF) + self++; + else + other_level++; + } + for (aNext = aMethod; *aNext != NULL; aNext++) { + if ((*aNext)->saslmech == NS_LDAP_SASL_GSSAPI) + gssapi++; + else + other_method++; + } + + if (self > 0 && gssapi > 0) { + if (other_level == 0 && other_method == 0) + *config = NS_LDAP_SELF_GSSAPI_CONFIG_ONLY; + else + *config = NS_LDAP_SELF_GSSAPI_CONFIG_MIXED; + } + + if (cLevel) + (void) __ns_ldap_freeParam((void ***)&cLevel); + if (aMethod) + (void) __ns_ldap_freeParam((void ***)&aMethod); + return (NS_LDAP_SUCCESS); +} + +int +__s_api_sasl_bind_callback( + /* LINTED E_FUNC_ARG_UNUSED */ + LDAP *ld, + /* LINTED E_FUNC_ARG_UNUSED */ + unsigned flags, + void *defaults, + void *in) +{ + char *ret = NULL; + sasl_interact_t *interact = in; + ns_sasl_cb_param_t *cred = (ns_sasl_cb_param_t *)defaults; + + + while (interact->id != SASL_CB_LIST_END) { + + switch (interact->id) { + + case SASL_CB_GETREALM: + ret = cred->realm; + break; + case SASL_CB_AUTHNAME: + ret = cred->authid; + break; + case SASL_CB_PASS: + ret = cred->passwd; + break; + case SASL_CB_USER: + ret = cred->authzid; + break; + case SASL_CB_NOECHOPROMPT: + case SASL_CB_ECHOPROMPT: + default: + break; + } + + if (ret) { + interact->result = strdup(ret); + if (interact->result == NULL) + return (LDAP_NO_MEMORY); + + interact->len = strlen(ret); + } else { + interact->result = NULL; + interact->len = 0; + } + interact++; + } + + return (LDAP_SUCCESS); +} + +/* + * Find "dbase: service1 [...] services2" in fname and return + * " service1 [...] services2" + * e.g. + * Find "hosts: files dns" and return " files dns" + */ +static char * +__ns_nsw_getconfig(const char *dbase, const char *fname, int *errp) +{ + FILE *fp = NULL; + char *linep, *retp = NULL; + char lineq[BUFSIZ], db_colon[BUFSIZ]; + + if ((fp = fopen(fname, "rF")) == NULL) { + *errp = NS_LDAP_CONFIG; + return (NULL); + } + *errp = NS_LDAP_SUCCESS; + + while (linep = fgets(lineq, BUFSIZ, fp)) { + char *tokenp, *comment; + + /* + * Ignore portion of line following the comment character '#'. + */ + if ((comment = strchr(linep, '#')) != NULL) { + *comment = '\0'; + } + if ((*linep == '\0') || isspace(*linep)) { + continue; + } + (void) snprintf(db_colon, BUFSIZ, "%s:", dbase); + if ((tokenp = strstr(linep, db_colon)) == NULL) { + continue; /* ignore this line */ + } else { + /* skip "dbase:" */ + retp = strdup(tokenp + strlen(db_colon)); + if (retp == NULL) + *errp = NS_LDAP_MEMORY; + } + } + + (void) fclose(fp); + return (retp); +} +/* + * Test the configurations of the "hosts" and "ipnodes" + * dns has to be present and appear before ldap + * e.g. + * "dns" , "dns files" "dns ldap files", "files dns" are allowed. + * + * Kerberos requires dns or it'd fail. + */ +static int +test_dns_nsswitch(int foreground, + const char *fname, + ns_ldap_error_t **errpp) { + int ldap, dns, i, pserr, rc = NS_LDAP_SUCCESS; + char *db[3] = {"hosts", "ipnodes", NULL}; + char buf[MSGSIZE], *conf = NULL, *token = NULL, *last = NULL; + + for (i = 0; db[i] != NULL; i++) { + conf = __ns_nsw_getconfig(db[i], fname, &pserr); + + if (conf == NULL) { + (void) snprintf(buf, MSGSIZE, + gettext("Parsing %s to find \"%s:\" " + "failed. err: %d"), + fname, db[i], pserr); + if (foreground) { + (void) fprintf(stderr, "%s\n", buf); + } else { + MKERROR(LOG_ERR, *errpp, NS_LDAP_CONFIG, + strdup(buf), NS_LDAP_MEMORY); + } + return (pserr); + } + ldap = dns = 0; + token = strtok_r(conf, " ", &last); + while (token != NULL) { + if (strncmp(token, "dns", 3) == 0) { + if (ldap) { + (void) snprintf(buf, MSGSIZE, + gettext("%s: ldap can't appear " + "before dns"), db[i]); + if (foreground) { + (void) fprintf(stderr, + "start: %s\n", + buf); + } else { + MKERROR(LOG_ERR, *errpp, + NS_LDAP_CONFIG, + strdup(buf), + NS_LDAP_MEMORY); + } + free(conf); + return (NS_LDAP_CONFIG); + } else { + dns++; + } + } else if (strncmp(token, "ldap", 4) == 0) { + ldap++; + } + /* next token */ + token = strtok_r(NULL, " ", &last); + } + if (conf) { + free(conf); + conf = NULL; + } + if (!dns) { + (void) snprintf(buf, MSGSIZE, + gettext("%s: dns is not defined in " + "%s"), db[i], fname); + if (foreground) { + (void) fprintf(stderr, "start: %s\n", buf); + } else { + MKERROR(LOG_ERR, *errpp, NS_LDAP_CONFIG, + strdup(buf), NS_LDAP_MEMORY); + } + rc = NS_LDAP_CONFIG; + break; + } + } + return (rc); +} + +static boolean_t +is_service(const char *fmri, const char *state) { + char *st; + boolean_t result = B_FALSE; + + if ((st = smf_get_state(fmri)) != NULL) { + if (strcmp(st, state) == 0) + result = B_TRUE; + free(st); + } + return (result); +} + + +/* + * This function checks dns prerequisites for sasl/GSSAPI bind. + * It's called only if config == NS_LDAP_SELF_GSSAPI_CONFIG_ONLY || + * config == NS_LDAP_SELF_GSSAPI_CONFIG_MIXED. + */ +int +__ns_ldap_check_dns_preq(int foreground, + int mode_verbose, + int mode_quiet, + const char *fname, + ns_ldap_self_gssapi_config_t config, + ns_ldap_error_t **errpp) { + + char buf[MSGSIZE]; + int retcode = NS_LDAP_SUCCESS; + int loglevel; + + if (errpp) + *errpp = NULL; + else + return (NS_LDAP_INVALID_PARAM); + + if (config == NS_LDAP_SELF_GSSAPI_CONFIG_NONE) + /* Shouldn't happen. Check this value just in case */ + return (NS_LDAP_SUCCESS); + + if ((retcode = test_dns_nsswitch(foreground, fname, errpp)) != + NS_LDAP_SUCCESS) + return (retcode); + + if (is_service(DNS_FMRI, SCF_STATE_STRING_ONLINE)) { + if (foreground) { + CLIENT_FPRINTF(stdout, "start: %s\n", + gettext("DNS client is enabled")); + } else { + syslog(LOG_INFO, "%s", + gettext("DNS client is enabled")); + } + return (NS_LDAP_SUCCESS); + } else { + if (config == NS_LDAP_SELF_GSSAPI_CONFIG_ONLY) { + (void) snprintf(buf, MSGSIZE, + gettext("%s: DNS client is not enabled. " + "Run \"svcadm enable %s\". %s."), + "Error", DNS_FMRI, "Abort"); + loglevel = LOG_ERR; + retcode = NS_LDAP_CONFIG; + } else if (config == NS_LDAP_SELF_GSSAPI_CONFIG_MIXED) { + (void) snprintf(buf, MSGSIZE, + gettext("%s: DNS client is not enabled. " + "Run \"svcadm enable %s\". %s." + "Fall back to other cred level/bind. "), + "Warning", DNS_FMRI, "Continue"); + loglevel = LOG_INFO; + retcode = NS_LDAP_SUCCESS; + } + + if (foreground) { + (void) fprintf(stderr, "start: %s\n", buf); + } else { + MKERROR(loglevel, *errpp, retcode, strdup(buf), + NS_LDAP_MEMORY); + } + return (retcode); + } +} + +/* + * Check if sasl/GSSAPI works + */ +int +__ns_ldap_check_gssapi_preq(int foreground, + int mode_verbose, + int mode_quiet, + ns_ldap_self_gssapi_config_t config, + ns_ldap_error_t **errpp) { + + int rc; + char *attr[2] = {"dn", NULL}, buf[MSGSIZE]; + ns_cred_t cred; + ns_ldap_result_t *result = NULL; + int loglevel; + + if (errpp) + *errpp = NULL; + else + return (NS_LDAP_INVALID_PARAM); + + if (config == NS_LDAP_SELF_GSSAPI_CONFIG_NONE) + /* Don't need to check */ + return (NS_LDAP_SUCCESS); + + (void) memset(&cred, 0, sizeof (ns_cred_t)); + + cred.auth.type = NS_LDAP_AUTH_SASL; + cred.auth.tlstype = NS_LDAP_TLS_NONE; + cred.auth.saslmech = NS_LDAP_SASL_GSSAPI; + + rc = __ns_ldap_list(NULL, (const char *)"objectclass=*", + NULL, (const char **)attr, &cred, + NS_LDAP_SCOPE_BASE, &result, errpp, NULL, NULL); + if (result) + (void) __ns_ldap_freeResult(&result); + + if (rc == NS_LDAP_SUCCESS) { + if (foreground) { + CLIENT_FPRINTF(stdout, "start: %s\n", + gettext("sasl/GSSAPI bind works")); + } else { + syslog(LOG_INFO, "%s", + gettext("sasl/GSSAPI bind works")); + } + return (NS_LDAP_SUCCESS); + } else { + if (config == NS_LDAP_SELF_GSSAPI_CONFIG_ONLY) { + (void) snprintf(buf, MSGSIZE, + gettext("%s: sasl/GSSAPI bind is not " + "working. %s."), + "Error", "Abort"); + loglevel = LOG_ERR; + } else if (config == NS_LDAP_SELF_GSSAPI_CONFIG_MIXED) { + (void) snprintf(buf, MSGSIZE, + gettext("%s: sasl/GSSAPI bind is not " + "working. Fall back to other cred " + "level/bind. %s."), + "Warning", "Continue"); + loglevel = LOG_INFO; + /* reset return code */ + rc = NS_LDAP_SUCCESS; + } + + if (foreground) { + (void) fprintf(stderr, "start: %s\n", buf); + } else { + MKERROR(loglevel, *errpp, rc, strdup(buf), + NS_LDAP_MEMORY); + } + return (rc); + } +} +/* + * This is called by ldap_cachemgr to check dns and gssapi prequisites. + */ +int +__ns_ldap_check_all_preq(int foreground, + int mode_verbose, + int mode_quiet, + ns_ldap_self_gssapi_config_t config, + ns_ldap_error_t **errpp) { + + int rc; + + if (errpp) + *errpp = NULL; + else + return (NS_LDAP_INVALID_PARAM); + + if (config == NS_LDAP_SELF_GSSAPI_CONFIG_NONE) + /* Don't need to check */ + return (NS_LDAP_SUCCESS); + + if ((rc = __ns_ldap_check_dns_preq(foreground, + mode_verbose, mode_quiet, NSSWITCH_CONF, + config, errpp)) != NS_LDAP_SUCCESS) + return (rc); + if ((rc = __ns_ldap_check_gssapi_preq(foreground, + mode_verbose, mode_quiet, config, errpp)) != + NS_LDAP_SUCCESS) + return (rc); + + return (NS_LDAP_SUCCESS); +} diff --git a/usr/src/lib/libsldap/common/ns_sldap.h b/usr/src/lib/libsldap/common/ns_sldap.h index 0138c1e3d5..59d7ae516a 100644 --- a/usr/src/lib/libsldap/common/ns_sldap.h +++ b/usr/src/lib/libsldap/common/ns_sldap.h @@ -91,7 +91,7 @@ typedef enum ScopeType { typedef enum CredLevel { NS_LDAP_CRED_ANON = 0, NS_LDAP_CRED_PROXY = 1, - NS_LDAP_CRED_SELF = 2 /* currently not supported */ + NS_LDAP_CRED_SELF = 2 } CredLevel_t; typedef enum AuthType { @@ -113,14 +113,14 @@ typedef enum SaslMech { NS_LDAP_SASL_CRAM_MD5 = 1, NS_LDAP_SASL_DIGEST_MD5 = 2, NS_LDAP_SASL_EXTERNAL = 3, /* currently not supported */ - NS_LDAP_SASL_GSSAPI = 4, /* currently not supported */ + NS_LDAP_SASL_GSSAPI = 4, NS_LDAP_SASL_SPNEGO = 5 /* currently not supported */ } SaslMech_t; typedef enum SaslOpt { NS_LDAP_SASLOPT_NONE = 0, - NS_LDAP_SASLOPT_INT = 1, /* currently not supported */ - NS_LDAP_SASLOPT_PRIV = 2 /* currently not supported */ + NS_LDAP_SASLOPT_INT = 1, + NS_LDAP_SASLOPT_PRIV = 2 } SaslOpt_t; typedef enum PrefOnly { @@ -211,6 +211,17 @@ typedef enum { } ParamIndexType; /* + * NONE - No self / SASL/GSSAPI configured + * ONLY - Only self / SASL/GSSAPI configured + * MIXED - self / SASL/GSSAPI is mixed with other types of configuration + */ +typedef enum { + NS_LDAP_SELF_GSSAPI_CONFIG_NONE = 0, + NS_LDAP_SELF_GSSAPI_CONFIG_ONLY = 1, + NS_LDAP_SELF_GSSAPI_CONFIG_MIXED = 2 +} ns_ldap_self_gssapi_config_t; + +/* * __ns_ldap_*() return codes */ typedef enum { @@ -614,6 +625,10 @@ char **__ns_ldap_getAttr( const ns_ldap_entry_t *entry, const char *attrname); +ns_ldap_attr_t *__ns_ldap_getAttrStruct( + const ns_ldap_entry_t *entry, + const char *attrname); + int __ns_ldap_getServiceAuthMethods( const char *service, ns_auth_t ***auth, @@ -666,6 +681,12 @@ int __ns_ldap_getParamType( int __ns_ldap_getAcctMgmt( const char *user, AcctUsableResponse_t *acctResp); +void +__ns_ldap_self_gssapi_only_set( + int flag); +int +__ns_ldap_self_gssapi_config( + ns_ldap_self_gssapi_config_t *config); #ifdef __cplusplus } #endif diff --git a/usr/src/lib/libsldap/common/ns_writes.c b/usr/src/lib/libsldap/common/ns_writes.c index dadec06207..474db98161 100644 --- a/usr/src/lib/libsldap/common/ns_writes.c +++ b/usr/src/lib/libsldap/common/ns_writes.c @@ -691,7 +691,7 @@ write_state_machine( switch (state) { case W_EXIT: if (connectionId > -1) - DropConnection(connectionId, 0); + DropConnection(connectionId, NS_LDAP_NEW_CONN); if (ref_list) __s_api_deleteRefInfo(ref_list); if (target_dn && target_dn_allocated) @@ -723,7 +723,7 @@ write_state_machine( break; case GET_CONNECTION: rc = __s_api_getConnection(NULL, - flags, + flags | NS_LDAP_NEW_CONN, cred, &connectionId, &conp, @@ -912,7 +912,7 @@ write_state_machine( if (*errorp) (void) __ns_ldap_freeError(errorp); if (connectionId > -1) - DropConnection(connectionId, 0); + DropConnection(connectionId, NS_LDAP_NEW_CONN); rc = __s_api_getConnection(current_ref->refHost, 0, cred, diff --git a/usr/src/lib/libsldap/req.flg b/usr/src/lib/libsldap/req.flg index 6ced3afe87..25da177a24 100644 --- a/usr/src/lib/libsldap/req.flg +++ b/usr/src/lib/libsldap/req.flg @@ -28,3 +28,4 @@ echo_file usr/src/lib/libldap5/include/ldap/solaris-priv.h echo_file usr/src/lib/libldap5/include/ldap/ldappr.h +echo_file usr/src/lib/libldap5/include/ldap/solaris-int.h diff --git a/usr/src/lib/libsocket/common/mapfile-vers b/usr/src/lib/libsocket/common/mapfile-vers index 81c0972716..c4fdda3f62 100644 --- a/usr/src/lib/libsocket/common/mapfile-vers +++ b/usr/src/lib/libsocket/common/mapfile-vers @@ -140,6 +140,15 @@ SUNWprivate_1.3 { global: _link_aton; _link_ntoa; + _nss_initf_ethers; + _nss_initf_net; + _nss_initf_netmasks; + _nss_initf_proto; + _nss_initf_services; + str2ether; + str2addr; + str2netent; + str2protoent; } SUNWprivate_1.2; SUNWprivate_1.2 { diff --git a/usr/src/lib/libsocket/inet/ether_addr.c b/usr/src/lib/libsocket/inet/ether_addr.c index 3fbdb3bbb0..44f8979691 100644 --- a/usr/src/lib/libsocket/inet/ether_addr.c +++ b/usr/src/lib/libsocket/inet/ether_addr.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -61,11 +60,11 @@ #include <netinet/if_ether.h> #include <nss_dbdefs.h> -static int str2ether(const char *, int, void *, char *, int); +int str2ether(const char *, int, void *, char *, int); static DEFINE_NSS_DB_ROOT(db_root); -static void +void _nss_initf_ethers(nss_db_params_t *p) { p->name = NSS_DBNAM_ETHERS; @@ -181,7 +180,7 @@ ether_line( #define lisalnum(x) (isdigit(x) || \ ((x) >= 'a' && (x) <= 'z') || ((x) >= 'A' && (x) <= 'Z')) /* ARGSUSED */ -static int +int str2ether(const char *instr, int lenstr, void *ent, char *buffer, int buflen) { uchar_t *ether = (uchar_t *)ent; diff --git a/usr/src/lib/libsocket/inet/getnetent_r.c b/usr/src/lib/libsocket/inet/getnetent_r.c index 1484809b15..0b9ae98556 100644 --- a/usr/src/lib/libsocket/inet/getnetent_r.c +++ b/usr/src/lib/libsocket/inet/getnetent_r.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 1986-2002 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -37,7 +36,7 @@ #include <nss_dbdefs.h> -static int str2netent(const char *, int, void *, char *, int); +int str2netent(const char *, int, void *, char *, int); static int net_stayopen; /* @@ -48,7 +47,7 @@ static int net_stayopen; static DEFINE_NSS_DB_ROOT(db_root); static DEFINE_NSS_GETENT(context); -static void +void _nss_initf_net(nss_db_params_t *p) { p->name = NSS_DBNAM_NETWORKS; @@ -62,6 +61,10 @@ getnetbyname_r(const char *name, struct netent *result, nss_XbyY_args_t arg; nss_status_t res; + if (name == (const char *)NULL) { + errno = ERANGE; + return (NULL); + } NSS_XbyY_INIT(&arg, result, buffer, buflen, str2netent); arg.key.name = name; arg.stayopen = net_stayopen; @@ -127,7 +130,7 @@ getnetent_r(struct netent *result, char *buffer, int buflen) * wherein the field pointers would be set to areas in the buffer if * need be. instring and buffer should be separate areas. */ -static int +int str2netent(const char *instr, int lenstr, void *ent /* really (struct netnet *) */, char *buffer, int buflen) { diff --git a/usr/src/lib/libsocket/inet/getprotoent_r.c b/usr/src/lib/libsocket/inet/getprotoent_r.c index e1cb1c7f0b..4f89a047bf 100644 --- a/usr/src/lib/libsocket/inet/getprotoent_r.c +++ b/usr/src/lib/libsocket/inet/getprotoent_r.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,8 @@ * CDDL HEADER END */ /* - * Copyright (c) 1986-1992 by Sun Microsystems Inc. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. */ #pragma ident "%Z%%M% %I% %E% SMI" @@ -31,7 +31,7 @@ #include <string.h> #include <nss_dbdefs.h> -static int str2protoent(const char *, int, void *, +int str2protoent(const char *, int, void *, char *, int); static int proto_stayopen; @@ -43,7 +43,7 @@ static int proto_stayopen; static DEFINE_NSS_DB_ROOT(db_root); static DEFINE_NSS_GETENT(context); -static void +void _nss_initf_proto(nss_db_params_t *p) { p->name = NSS_DBNAM_PROTOCOLS; @@ -57,6 +57,10 @@ getprotobyname_r(const char *name, struct protoent *result, nss_XbyY_args_t arg; nss_status_t res; + if (name == (const char *)NULL) { + errno = ERANGE; + return (NULL); + } NSS_XbyY_INIT(&arg, result, buffer, buflen, str2protoent); arg.key.name = name; arg.stayopen = proto_stayopen; @@ -121,7 +125,7 @@ getprotoent_r(struct protoent *result, char *buffer, int buflen) * need be. instring and buffer should be separate areas. Let's not * fight over crumbs. */ -static int +int str2protoent(const char *instr, int lenstr, void *ent /* it is really (struct protoent *) */, char *buffer, int buflen) diff --git a/usr/src/lib/libsocket/inet/getservent_r.c b/usr/src/lib/libsocket/inet/getservent_r.c index 6eb9ff49a2..aeccf9f499 100644 --- a/usr/src/lib/libsocket/inet/getservent_r.c +++ b/usr/src/lib/libsocket/inet/getservent_r.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,8 @@ * CDDL HEADER END */ /* - * Copyright (c) 1986-1994 by Sun Microsystems Inc. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. * * lib/libsocket/inet/getservent_r.c * @@ -52,7 +52,7 @@ static int services_stayopen; static DEFINE_NSS_DB_ROOT(db_root); static DEFINE_NSS_GETENT(context); -static void +void _nss_initf_services(nss_db_params_t *p) { p->name = NSS_DBNAM_SERVICES; diff --git a/usr/src/lib/libsocket/inet/netmasks.c b/usr/src/lib/libsocket/inet/netmasks.c index e944e00e84..f9e5ef4049 100644 --- a/usr/src/lib/libsocket/inet/netmasks.c +++ b/usr/src/lib/libsocket/inet/netmasks.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -44,11 +43,11 @@ #include <arpa/inet.h> #include <nss_dbdefs.h> -static int str2addr(const char *, int, void *, char *, int); +int str2addr(const char *, int, void *, char *, int); static DEFINE_NSS_DB_ROOT(db_root); -static void +void _nss_initf_netmasks(nss_db_params_t *p) { p->name = NSS_DBNAM_NETMASKS; @@ -59,24 +58,27 @@ _nss_initf_netmasks(nss_db_params_t *p) * Print a network number such as 129.144 as well as an IP address. * Assumes network byte order for both IP addresses and network numbers * (Network numbers are normally passed around in host byte order). + * to be MT safe, use a passed in buffer like otherget*_r APIs. */ static char * -inet_nettoa(struct in_addr in) +inet_nettoa(struct in_addr in, char *result, int len) { uint32_t addr = in.s_addr; uchar_t *up = (uchar_t *)&addr; - static char result[256]; + + if (result == NULL) + return (NULL); /* Omit leading zeros */ if (up[0]) { - (void) sprintf(result, "%d.%d.%d.%d", + (void) snprintf(result, len, "%d.%d.%d.%d", up[0], up[1], up[2], up[3]); } else if (up[1]) { - (void) sprintf(result, "%d.%d.%d", up[1], up[2], up[3]); + (void) snprintf(result, len, "%d.%d.%d", up[1], up[2], up[3]); } else if (up[2]) { - (void) sprintf(result, "%d.%d", up[2], up[3]); + (void) snprintf(result, len, "%d.%d", up[2], up[3]); } else { - (void) sprintf(result, "%d", up[3]); + (void) snprintf(result, len, "%d", up[3]); } return (result); } @@ -102,8 +104,10 @@ getnetmaskbykey(const struct in_addr addr, struct in_addr *mask) * the network address in the 'name' field as a filter to speed * up the lookup. */ + if (inet_nettoa(addr, tmp, NSS_LINELEN_NETMASKS) == NULL) + return (NSS_NOTFOUND); + NSS_XbyY_INIT(&arg, mask, NULL, 0, str2addr); - (void) strcpy(tmp, inet_nettoa(addr)); arg.key.name = tmp; res = nss_search(&db_root, _nss_initf_netmasks, NSS_DBOP_NETMASKS_BYNET, &arg); diff --git a/usr/src/lib/nsswitch/compat/common/compat_common.c b/usr/src/lib/nsswitch/compat/common/compat_common.c index fe21797abf..330a4b7707 100644 --- a/usr/src/lib/nsswitch/compat/common/compat_common.c +++ b/usr/src/lib/nsswitch/compat/common/compat_common.c @@ -36,6 +36,11 @@ #include <ctype.h> #include <bsm/libbsm.h> #include <user_attr.h> +#include <pwd.h> +#include <shadow.h> +#include <grp.h> +#include <unistd.h> /* for GF_PATH */ +#include <dlfcn.h> #include "compat_common.h" /* @@ -44,6 +49,62 @@ extern int yp_get_default_domain(char **domain); +/* from libc */ +extern int str2passwd(const char *instr, int lenstr, void *ent, + char *buffer, int buflen); +extern int str2spwd(const char *instr, int lenstr, void *ent, + char *buffer, int buflen); +extern int str2group(const char *instr, int lenstr, void *ent, + char *buffer, int buflen); + +/* from libnsl */ +extern char *_strtok_escape(char *, char *, char **); + +/* + * str2auuser_s and str2userattr_s are very simple version + * of the str2auuser() and str2userattr() that can be found in + * libnsl. They only copy the user name into the userstr_t + * or au_user_str_t structure (so check on user name can be + * performed). + */ +static int +str2auuser_s( + const char *instr, + int lenstr, + void *ent, + char *buffer, + int buflen) +{ + char *last = NULL; + char *sep = KV_TOKEN_DELIMIT; + au_user_str_t *au_user = (au_user_str_t *)ent; + + if (lenstr >= buflen) + return (NSS_STR_PARSE_ERANGE); + (void) strncpy(buffer, instr, buflen); + au_user->au_name = _strtok_escape(buffer, sep, &last); + return (0); +} + +static int +str2userattr_s( + const char *instr, + int lenstr, + void *ent, + char *buffer, + int buflen) +{ + char *last = NULL; + char *sep = KV_TOKEN_DELIMIT; + userstr_t *user = (userstr_t *)ent; + + if (lenstr >= buflen) + return (NSS_STR_PARSE_ERANGE); + (void) strncpy(buffer, instr, buflen); + user->name = _strtok_escape(buffer, sep, &last); + return (0); +} + /* * Routines to manage list of "-" users for get{pw, sp, gr}ent(). Current * implementation is completely moronic; we use a linked list. But then @@ -58,7 +119,6 @@ struct setofstrings { * object rather than two. */ }; -typedef struct setofstrings *strset_t; static void strset_free(ssp) @@ -88,7 +148,7 @@ strset_add(ssp, nam) free(new); return (B_FALSE); } - strcpy(new->name, nam); + (void) strcpy(new->name, nam); new->next = *ssp; *ssp = new; return (B_TRUE); @@ -109,41 +169,6 @@ strset_in(ssp, nam) return (B_FALSE); } - -struct compat_backend { - compat_backend_op_t *ops; - int n_ops; - const char *filename; - FILE *f; - int minbuf; - char *buf; - int linelen; /* <== Explain use, lifetime */ - - nss_db_initf_t db_initf; - nss_db_root_t *db_rootp; /* Shared between instances */ - nss_getent_t db_context; /* Per-instance enumeration */ - - compat_get_name getnamef; - compat_merge_func mergef; - - /* We wouldn't need all this hokey state stuff if we */ - /* used another thread to implement a coroutine... */ - enum { - GETENT_FILE, - GETENT_NETGROUP, - GETENT_ATTRDB, - GETENT_ALL, - GETENT_DONE - } state; - strset_t minuses; - - int permit_netgroups; - const char *yp_domain; - nss_backend_t *getnetgrent_backend; - char *netgr_buffer; -}; - - /* * Lookup and enumeration routines for +@group and -@group. * @@ -171,15 +196,6 @@ netgr_in(compat_backend_ptr_t be, const char *group, const char *user) return (innetgr(group, 0, user, be->yp_domain)); } -static boolean_t -netgr_all_in(compat_backend_ptr_t be, const char *group) -{ - /* - * 4.x does this; ours not to reason why... - */ - return (netgr_in(be, group, "*")); -} - static void netgr_set(be, netgroup) compat_backend_ptr_t be; @@ -202,7 +218,7 @@ netgr_set(be, netgroup) args.netgroup = netgroup; args.iterator = 0; - nss_search(&netgr_db_root, _nss_initf_netgroup, + (void) nss_search(&netgr_db_root, _nss_initf_netgroup, NSS_DBOP_NETGROUP_SET, &args); be->getnetgrent_backend = args.iterator; } @@ -270,7 +286,7 @@ do_merge(be, args, instr, linelen) int overrides; const char *p; const char *end = instr + linelen; - nss_status_t res; + nss_status_t res = NSS_NOTFOUND; /* * Potential optimization: only perform the field-splitting nonsense @@ -292,7 +308,7 @@ do_merge(be, args, instr, linelen) overrides = -1; /* Indicates "you lose" */ break; } - memcpy(s, p, len); + (void) memcpy(s, p, len); s[len] = '\0'; fields[i] = s; overrides++; @@ -306,16 +322,29 @@ do_merge(be, args, instr, linelen) } } if (overrides == 1) { - /* No real overrides, return (*args) intact */ - res = NSS_SUCCESS; - } else if (overrides > 1) { + /* + * return result here if /etc file format is requested + */ + if (be->return_string_data != 1) { + /* No real overrides, return (*args) intact */ + res = NSS_SUCCESS; + } else { + free(fields[0]); + fields[0] = NULL; + } + } + + if (overrides > 1 || be->return_string_data == 1) { /* * The zero'th field is always nonempty (+/-...), but at least * one other field was also nonempty, i.e. wants to override */ switch ((*be->mergef)(be, args, (const char **)fields)) { case NSS_STR_PARSE_SUCCESS: - args->returnval = args->buf.result; + if (be->return_string_data != 1) + args->returnval = args->buf.result; + else + args->returnval = args->buf.buffer; args->erange = 0; res = NSS_SUCCESS; break; @@ -331,7 +360,7 @@ do_merge(be, args, instr, linelen) res = NSS_NOTFOUND; break; } - } else { + } else if (res != NSS_SUCCESS) { args->returnval = 0; args->erange = 0; res = NSS_UNAVAIL; /* ==> Right? */ @@ -383,7 +412,7 @@ _nss_compat_endent(be, dummy) void *dummy; { if (be->f != 0) { - fclose(be->f); + (void) fclose(be->f); be->f = 0; } if (be->buf != 0) { @@ -412,7 +441,7 @@ _nss_compat_destr(be, dummy) { if (be != 0) { if (be->f != 0) { - _nss_compat_endent(be, 0); + (void) _nss_compat_endent(be, 0); } nss_delete(be->db_rootp); nss_delete(&netgr_db_root); @@ -459,6 +488,7 @@ read_line(f, buffer, buflen) ; } } + /*NOTREACHED*/ } static int @@ -493,6 +523,10 @@ _attrdb_compat_XY_all(be, argp, netdb, check, op_num) int (*func)(); const char *filter = argp->key.name; nss_status_t res; + union { + au_user_str_t au; + userstr_t user; + } workarea; #ifdef DEBUG (void) fprintf(stdout, "\n[compat_common.c: _attrdb_compat_XY_all]\n"); @@ -502,11 +536,33 @@ _attrdb_compat_XY_all(be, argp, netdb, check, op_num) (be->buf = malloc(be->minbuf)) == 0) { return (NSS_UNAVAIL); } - if ((res = _nss_compat_setent(be, 0)) != NSS_SUCCESS) { - return (res); - } + if (check != NULL) + if ((res = _nss_compat_setent(be, 0)) != NSS_SUCCESS) + return (res); + res = NSS_NOTFOUND; + /* + * assume a NULL buf.result pointer is an indication + * that the lookup result should be returned in /etc + * file format + */ + if (argp->buf.result == NULL) { + be->return_string_data = 1; + + /* + * the code executed later needs the result struct + * as working area + */ + argp->buf.result = &workarea; + + if (strcmp(be->filename, USERATTR_FILENAME) == 0) + func = str2userattr_s; + else + func = str2auuser_s; + } else + func = argp->str2ent; + /*CONSTCOND*/ while (1) { int linelen; @@ -560,16 +616,36 @@ _attrdb_compat_XY_all(be, argp, netdb, check, op_num) } } argp->returnval = 0; - func = argp->str2ent; parsestat = (*func)(instr, linelen, argp->buf.result, argp->buf.buffer, argp->buf.buflen); if (parsestat == NSS_STR_PARSE_SUCCESS) { - argp->returnval = argp->buf.result; + argp->returnval = argp->buf.result; if (check == 0 || (*check)(argp)) { + int len; + + if (be->return_string_data != 1) { + res = NSS_SUCCESS; + break; + } + + /* copy string data to result buffer */ + argp->buf.result = NULL; + argp->returnval = argp->buf.buffer; + if ((len = strlcpy(argp->buf.buffer, instr, + argp->buf.buflen)) >= + argp->buf.buflen) { + argp->returnval = NULL; + res = NSS_NOTFOUND; + argp->erange = 1; + break; + } + + argp->returnlen = len; res = NSS_SUCCESS; break; } } else if (parsestat == NSS_STR_PARSE_ERANGE) { + res = NSS_NOTFOUND; argp->erange = 1; break; } @@ -583,6 +659,14 @@ _attrdb_compat_XY_all(be, argp, netdb, check, op_num) } if (res != NSS_SUCCESS) { + /* + * tell the nss_search() and nss_getent() below + * if the result should be returned in the /etc + * file format + */ + if (be->return_string_data == 1) + argp->buf.result = NULL; + if ((op_num == NSS_DBOP_USERATTR_BYNAME) || (op_num == NSS_DBOP_AUDITUSER_BYNAME)) { res = nss_search(be->db_rootp, @@ -611,6 +695,13 @@ _nss_compat_XY_all(be, args, check, op_num) { nss_status_t res; int parsestat; + union { + struct passwd pwd; + struct spwd shdw; + struct group grp; + } workarea; + int (*str2ent_save)(); + if (be->buf == 0 && (be->buf = malloc(be->minbuf)) == 0) { @@ -623,6 +714,30 @@ _nss_compat_XY_all(be, args, check, op_num) res = NSS_NOTFOUND; + /* + * assume a NULL buf.result pointer is an indication + * that the lookup result should be returned in /etc + * file format + */ + if (args->buf.result == NULL) { + + be->return_string_data = 1; + + /* + * the code executed later needs the result struct + * as working area + */ + args->buf.result = &workarea; + + str2ent_save = args->str2ent; + if (strcmp(be->filename, PASSWD) == 0) + args->str2ent = str2passwd; + else if (strcmp(be->filename, SHADOW) == 0) + args->str2ent = str2spwd; + else + args->str2ent = str2group; + } + /*CONSTCOND*/ while (1) { int linelen; @@ -648,13 +763,37 @@ _nss_compat_XY_all(be, args, check, op_num) if (parsestat == NSS_STR_PARSE_SUCCESS) { args->returnval = args->buf.result; if ((*check)(args) != 0) { - res = NSS_SUCCESS; - break; - } + int len; + if (be->return_string_data != 1) { + res = NSS_SUCCESS; + break; + } + + /* + * copy string data to + * result buffer + */ + args->buf.result = NULL; + args->str2ent = str2ent_save; + if ((len = strlcpy(args->buf.buffer, + instr, args->buf.buflen)) >= + args->buf.buflen) + parsestat = + NSS_STR_PARSE_ERANGE; + else { + args->returnval = + args->buf.buffer; + args->returnlen = len; + res = NSS_SUCCESS; + break; + } + } else + continue; + } /* ===> Check the Dani logic here... */ - } else if (parsestat == NSS_STR_PARSE_ERANGE) { + if (parsestat == NSS_STR_PARSE_ERANGE) { args->erange = 1; res = NSS_NOTFOUND; break; @@ -665,6 +804,7 @@ _nss_compat_XY_all(be, args, check, op_num) /* ==> ?? */ continue; } + /* * Process "+", "+name", "+@netgroup", "-name" or "-@netgroup" * @@ -701,15 +841,15 @@ _nss_compat_XY_all(be, args, check, op_num) continue; if (instr[0] == '+') { /* need to search for "+" entry */ - nss_search(be->db_rootp, be->db_initf, - op_num, args); + (void) nss_search(be->db_rootp, + be->db_initf, op_num, args); if (args->returnval == 0) continue; } } else { /* search then compare */ - nss_search(be->db_rootp, be->db_initf, op_num, - args); + (void) nss_search(be->db_rootp, + be->db_initf, op_num, args); if (args->returnval == 0) continue; if (!be->permit_netgroups || @@ -727,7 +867,8 @@ _nss_compat_XY_all(be, args, check, op_num) if (instr[0] == '-') continue; /* need to search for "+" entry */ - nss_search(be->db_rootp, be->db_initf, op_num, args); + (void) nss_search(be->db_rootp, be->db_initf, + op_num, args); if (args->returnval == 0) continue; } else { @@ -746,15 +887,15 @@ _nss_compat_XY_all(be, args, check, op_num) continue; if (instr[0] == '+') { /* need to search for "+" entry */ - nss_search(be->db_rootp, be->db_initf, - op_num, args); + (void) nss_search(be->db_rootp, + be->db_initf, op_num, args); if (args->returnval == 0) continue; } } else { /* search then compare */ - nss_search(be->db_rootp, be->db_initf, op_num, - args); + (void) nss_search(be->db_rootp, + be->db_initf, op_num, args); if (args->returnval == 0) continue; if (strcmp(instr + 1, (*be->getnamef)(args)) @@ -783,6 +924,10 @@ _nss_compat_XY_all(be, args, check, op_num) (void) _nss_compat_endent(be, 0); } + if (be->return_string_data == 1) { + args->str2ent = str2ent_save; + } + return (res); } @@ -794,6 +939,12 @@ _nss_compat_getent(be, a) nss_XbyY_args_t *args = (nss_XbyY_args_t *)a; nss_status_t res; char *colon = 0; /* <=== need comment re lifetime */ + union { + struct passwd pwd; + struct spwd shdw; + struct group grp; + } workarea; + if (be->f == 0) { if ((res = _nss_compat_setent(be, 0)) != NSS_SUCCESS) { @@ -806,6 +957,21 @@ _nss_compat_getent(be, a) return (NSS_UNAVAIL); /* really panic, malloc failed */ } + /* + * assume a NULL buf.result pointer is an indication + * that the lookup result should be returned in /etc + * file format + */ + if (args->buf.result == NULL) { + be->return_string_data = 1; + + /* + * the code executed later needs the result struct + * as working area + */ + args->buf.result = &workarea; + } + /*CONSTCOND*/ while (1) { char *instr = be->buf; @@ -829,6 +995,7 @@ _nss_compat_getent(be, a) return (NSS_NOTFOUND); case GETENT_ATTRDB: + args->key.name = NULL; res = _attrdb_compat_XY_all(be, args, 1, (compat_XY_check_func)NULL, 0); return (res); @@ -845,11 +1012,12 @@ _nss_compat_getent(be, a) } if (instr[0] == '-') { if (instr[1] != '@') { - strset_add(&be->minuses, instr + 1); + (void) strset_add(&be->minuses, + instr + 1); } else if (be->permit_netgroups) { netgr_set(be, instr + 2); while (netgr_next_u(be, &name)) { - strset_add(&be->minuses, + (void) strset_add(&be->minuses, name); } netgr_end(be); @@ -869,8 +1037,30 @@ _nss_compat_getent(be, a) args->buf.buffer, args->buf.buflen); if (parsestat == NSS_STR_PARSE_SUCCESS) { - args->returnval = args->buf.result; - return (NSS_SUCCESS); + int len; + + if (be->return_string_data != 1) { + args->returnval = + args->buf.result; + return (NSS_SUCCESS); + } + + /* + * copy string data to + * result buffer + */ + args->buf.result = NULL; + args->returnval = + args->buf.buffer; + if ((len = strlcpy(args->buf.buffer, + instr, args->buf.buflen)) >= + args->buf.buflen) + parsestat = + NSS_STR_PARSE_ERANGE; + else { + args->returnlen = len; + return (NSS_SUCCESS); + } } /* ==> ?? Treat ERANGE differently ?? */ if (parsestat == NSS_STR_PARSE_ERANGE) { @@ -903,7 +1093,7 @@ _nss_compat_getent(be, a) case GETENT_ALL: linelen = be->linelen; args->returnval = 0; - nss_getent(be->db_rootp, be->db_initf, + (void) nss_getent(be->db_rootp, be->db_initf, &be->db_context, args); if (args->returnval == 0) { /* ==> ?? Treat ERANGE differently ?? */ @@ -947,7 +1137,7 @@ _nss_compat_getent(be, a) savename = args->key.name; args->key.name = name; args->returnval = 0; - nss_search(be->db_rootp, be->db_initf, + (void) nss_search(be->db_rootp, be->db_initf, NSS_DBOP_next_iter, args); args->key.name = savename; /* In case anyone cares */ } @@ -966,6 +1156,7 @@ _nss_compat_getent(be, a) } return (do_merge(be, args, instr, linelen)); } + /*NOTREACHED*/ } /* We don't use this directly; we just copy the bits when we want to */ @@ -1016,6 +1207,7 @@ _nss_compat_constr(ops, n_ops, filename, min_bufsize, rootp, initf, netgroups, be->yp_domain = 0; be->getnetgrent_backend = 0; be->netgr_buffer = 0; + be->return_string_data = 0; return ((nss_backend_t *)be); } diff --git a/usr/src/lib/nsswitch/compat/common/compat_common.h b/usr/src/lib/nsswitch/compat/common/compat_common.h index cfd4f37e5c..08b30a3c82 100644 --- a/usr/src/lib/nsswitch/compat/common/compat_common.h +++ b/usr/src/lib/nsswitch/compat/common/compat_common.h @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,8 +19,10 @@ * CDDL HEADER END */ /* - * Copyright (c) 1992, by Sun Microsystems, Inc. - * + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ +/* * Common code and structures used by name-service-switch "compat" backends. */ @@ -58,6 +59,42 @@ typedef int (*compat_merge_func)(compat_backend_ptr_t, nss_XbyY_args_t *, const char **fields); +typedef struct setofstrings *strset_t; + +struct compat_backend { + compat_backend_op_t *ops; + int n_ops; + const char *filename; + FILE *f; + int minbuf; + char *buf; + int linelen; /* <== Explain use, lifetime */ + + nss_db_initf_t db_initf; + nss_db_root_t *db_rootp; /* Shared between instances */ + nss_getent_t db_context; /* Per-instance enumeration */ + + compat_get_name getnamef; + compat_merge_func mergef; + + /* We wouldn't need all this hokey state stuff if we */ + /* used another thread to implement a coroutine... */ + enum { + GETENT_FILE, + GETENT_NETGROUP, + GETENT_ATTRDB, + GETENT_ALL, + GETENT_DONE + } state; + strset_t minuses; + + int permit_netgroups; + const char *yp_domain; + nss_backend_t *getnetgrent_backend; + char *netgr_buffer; + int return_string_data; +}; + #if defined(__STDC__) extern nss_backend_t *_nss_compat_constr(compat_backend_op_t *ops, int n_ops, diff --git a/usr/src/lib/nsswitch/compat/common/getauuser.c b/usr/src/lib/nsswitch/compat/common/getauuser.c index 8bf983c7dc..55b700bbb4 100644 --- a/usr/src/lib/nsswitch/compat/common/getauuser.c +++ b/usr/src/lib/nsswitch/compat/common/getauuser.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,8 +19,8 @@ * CDDL HEADER END */ /* - * Copyright (c) 1999-2000 by Sun Microsystems, Inc. - * All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. */ #pragma ident "%Z%%M% %I% %E% SMI" @@ -34,7 +33,7 @@ static DEFINE_NSS_DB_ROOT(db_root); -void +static void _nss_initf_auuser_compat(nss_db_params_t *p) { p->name = NSS_DBNAM_AUDITUSER; @@ -91,6 +90,7 @@ static compat_backend_op_t auuser_ops[] = { getbynam }; +/*ARGSUSED*/ nss_backend_t * _nss_compat_audit_user_constr(const char *dummy1, const char *dummy2, diff --git a/usr/src/lib/nsswitch/compat/common/getgrent.c b/usr/src/lib/nsswitch/compat/common/getgrent.c index b34c594de2..0457392e59 100644 --- a/usr/src/lib/nsswitch/compat/common/getgrent.c +++ b/usr/src/lib/nsswitch/compat/common/getgrent.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -22,7 +21,7 @@ /* * getgrent.c * - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * * lib/nsswitch/compat/getgrent.c -- name-service-switch backend for getgrnam() @@ -192,6 +191,7 @@ merge_grents(be, argp, fields) char *buf; char *s; int parsestat; + int dlen; /* * We're allowed to override the passwd (has anyone ever actually used @@ -201,7 +201,8 @@ merge_grents(be, argp, fields) * * Efficiency is heartlessly abandoned in the quest for simplicity. */ - if (fields[1] == 0 && fields[3] == 0) { + if (fields[1] == 0 && fields[3] == 0 && + be->return_string_data != 1) { /* No legal overrides, leave *argp unscathed */ return (NSS_STR_PARSE_SUCCESS); } @@ -216,7 +217,7 @@ merge_grents(be, argp, fields) g->gr_gid); s += strlen(s); if (fields[3] != 0) { - strcpy(s, fields[3]); + (void) strcpy(s, fields[3]); s += strlen(s); } else { char **memp; @@ -235,10 +236,31 @@ merge_grents(be, argp, fields) } } } - parsestat = (*argp->str2ent)(buf, s - buf, + + dlen = s - buf; + + /* + * if asked, return the data in /etc file format + */ + if (be->return_string_data == 1) { + /* reset the result ptr to the original value */ + argp->buf.result = NULL; + + if (dlen > argp->buf.buflen) { + parsestat = NSS_STR_PARSE_ERANGE; + } else { + (void) strncpy(argp->buf.buffer, buf, dlen); + argp->returnval = argp->buf.buffer; + argp->returnlen = dlen; + parsestat = NSS_SUCCESS; + } + } else { + parsestat = (*argp->str2ent)(buf, dlen, argp->buf.result, argp->buf.buffer, argp->buf.buflen); + } + free(buf); return (parsestat); } diff --git a/usr/src/lib/nsswitch/compat/common/getpwent.c b/usr/src/lib/nsswitch/compat/common/getpwent.c index e31462443f..1219dab7fa 100644 --- a/usr/src/lib/nsswitch/compat/common/getpwent.c +++ b/usr/src/lib/nsswitch/compat/common/getpwent.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,10 +19,10 @@ * CDDL HEADER END */ /* - * getpwent.c + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. * - * Copyright (c) 1988-1992 Sun Microsystems Inc - * All Rights Reserved. + * getpwent.c * * lib/nsswitch/compat/getpwent.c -- name-service-switch backend for getpwnam() * et al that does 4.x compatibility. It looks in /etc/passwd; if it finds @@ -60,7 +59,7 @@ static DEFINE_NSS_DB_ROOT(db_root); -void +static void _nss_initf_passwd_compat(p) nss_db_params_t *p; { @@ -92,7 +91,7 @@ getbyname(be, a) compat_backend_ptr_t be; void *a; { - nss_XbyY_args_t *argp = (nss_XbyY_args_t *) a; + nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a; return (_nss_compat_XY_all(be, argp, check_pwname, NSS_DBOP_PASSWD_BYNAME)); @@ -112,7 +111,7 @@ getbyuid(be, a) compat_backend_ptr_t be; void *a; { - nss_XbyY_args_t *argp = (nss_XbyY_args_t *) a; + nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a; return (_nss_compat_XY_all(be, argp, check_pwuid, NSS_DBOP_PASSWD_BYUID)); @@ -129,6 +128,8 @@ merge_pwents(be, argp, fields) char *buf = malloc(NSS_LINELEN_PASSWD); char *s; int parsestat; + int len; + int buflen; if (buf == 0) { return (NSS_STR_PARSE_PARSE); @@ -142,30 +143,60 @@ merge_pwents(be, argp, fields) * That's what the SunOS 4.x code did; who are we to question it... */ s = buf; - sprintf(s, "%s:", pw->pw_name); - s += strlen(s); - if (fields[1] != 0) { - strcpy(s, fields[1]); - } else { - strcpy(s, pw->pw_passwd); - if (pw->pw_age != 0) { - s += strlen(s); + buflen = argp->buf.buflen; + + if (fields[1] != 0) + len = snprintf(s, buflen, "%s:%s", + pw->pw_name, fields[1]); + else { /* ====> Does this do the right thing? */ - sprintf(s, ",%s", pw->pw_age); - } + if (pw->pw_age != 0 && *pw->pw_age != '\0') + len = snprintf(s, buflen, "%s:%s,%s", + pw->pw_name, pw->pw_passwd, pw->pw_age); + else + len = snprintf(s, buflen, "%s:%s", + pw->pw_name, pw->pw_passwd); } - s += strlen(s); - sprintf(s, ":%d:%d:%s:%s:%s", + + if (len > buflen) + return (NSS_STR_PARSE_ERANGE); + + s += len; + buflen -= len; + len = snprintf(s, buflen, ":%ld:%ld:%s:%s:%s", pw->pw_uid, pw->pw_gid, fields[4] != 0 ? fields[4] : pw->pw_gecos, fields[5] != 0 ? fields[5] : pw->pw_dir, fields[6] != 0 ? fields[6] : pw->pw_shell); - s += strlen(s); - parsestat = (*argp->str2ent)(buf, s - buf, + + if (len > buflen) + return (NSS_STR_PARSE_ERANGE); + + s += len; + len = s - buf; + + /* + * if asked, return the data in /etc file format + */ + if (be->return_string_data == 1) { + /* reset the result ptr to the original value */ + argp->buf.result = NULL; + + if (len > argp->buf.buflen) { + parsestat = NSS_STR_PARSE_ERANGE; + } else { + (void) strncpy(argp->buf.buffer, buf, len); + argp->returnval = argp->buf.buffer; + argp->returnlen = len; + parsestat = NSS_SUCCESS; + } + } else { + parsestat = (*argp->str2ent)(buf, len, argp->buf.result, argp->buf.buffer, argp->buf.buflen); + } free(buf); return (parsestat); } diff --git a/usr/src/lib/nsswitch/compat/common/getspent.c b/usr/src/lib/nsswitch/compat/common/getspent.c index c5671dcdef..96aba4f6e1 100644 --- a/usr/src/lib/nsswitch/compat/common/getspent.c +++ b/usr/src/lib/nsswitch/compat/common/getspent.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,11 +19,12 @@ * CDDL HEADER END */ /* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ +/* * getspent.c * - * Copyright (c) 1988-1992 Sun Microsystems Inc - * All Rights Reserved. - * * lib/nsswitch/compat/getspent.c -- name-service-switch backend for getspnam() * It looks in /etc/shadow; if it finds shadow entries there that begin * with "+" or "-", it consults other services. By default it uses NIS (YP), @@ -55,7 +55,7 @@ static DEFINE_NSS_DB_ROOT(db_root); -void +static void _nss_initf_shadow_compat(p) nss_db_params_t *p; { @@ -87,7 +87,7 @@ getbyname(be, a) compat_backend_ptr_t be; void *a; { - nss_XbyY_args_t *argp = (nss_XbyY_args_t *) a; + nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a; return (_nss_compat_XY_all(be, argp, check_spnamp, NSS_DBOP_SHADOW_BYNAME)); @@ -116,10 +116,12 @@ merge_spents(be, argp, fields) return (NSS_STR_PARSE_ERANGE); } if (sp->sp_namp != argp->buf.buffer) { - memmove(argp->buf.buffer, sp->sp_namp, namelen); + (void) memmove(argp->buf.buffer, + sp->sp_namp, namelen); sp->sp_namp = argp->buf.buffer; } - memcpy(argp->buf.buffer + namelen, fields[1], passlen); + (void) memcpy(argp->buf.buffer + namelen, + fields[1], passlen); } #define override(field, longp) \ @@ -142,7 +144,39 @@ merge_spents(be, argp, fields) override(fields[6], &sp->sp_inact); override(fields[7], &sp->sp_expire); override(fields[8], &sp->sp_flag); - return (NSS_STR_PARSE_SUCCESS); + + /* + * if asked, return the data in /etc file format + */ + if (be->return_string_data == 1) { + int n; + char b[16]; + + /* reset the result ptr to the original value */ + argp->buf.result = NULL; + +#define printnum(num) sprintf(b, "%d", num)) ? b : "" + + n = snprintf(argp->buf.buffer, argp->buf.buflen, + "%s:%s:%s:%s:%s:%s:%s:%s:%s", sp->sp_namp, + (sp->sp_pwdp ? sp->sp_pwdp : ""), + (sp->sp_lstchg >= 0 && printnum(sp->sp_lstchg), + (sp->sp_min >= 0 && printnum(sp->sp_min), + (sp->sp_max >= 0 && printnum(sp->sp_max), + (sp->sp_warn > 0 && printnum(sp->sp_warn), + (sp->sp_inact > 0 && printnum(sp->sp_inact), + (sp->sp_expire > 0 && printnum(sp->sp_expire), + (sp->sp_flag != 0 && printnum(sp->sp_flag)); + + if (n > argp->buf.buflen) + return (NSS_STR_PARSE_ERANGE); + else { + argp->returnlen = n - 1; + return (NSS_SUCCESS); + } + + } else + return (NSS_STR_PARSE_SUCCESS); } static compat_backend_op_t shadow_ops[] = { diff --git a/usr/src/lib/nsswitch/compat/common/getuserattr.c b/usr/src/lib/nsswitch/compat/common/getuserattr.c index 00572fa644..653101eca1 100644 --- a/usr/src/lib/nsswitch/compat/common/getuserattr.c +++ b/usr/src/lib/nsswitch/compat/common/getuserattr.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,8 +19,8 @@ * CDDL HEADER END */ /* - * Copyright (c) 1999-2000 by Sun Microsystems, Inc. - * All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. */ #pragma ident "%Z%%M% %I% %E% SMI" @@ -34,7 +33,7 @@ static DEFINE_NSS_DB_ROOT(db_root); -void +static void _nss_initf_userattr_compat(nss_db_params_t *p) { p->name = NSS_DBNAM_USERATTR; @@ -91,6 +90,7 @@ static compat_backend_op_t userattr_ops[] = { getbynam }; +/*ARGSUSED*/ nss_backend_t * _nss_compat_user_attr_constr(const char *dummy1, const char *dummy2, diff --git a/usr/src/lib/nsswitch/dns/Makefile.com b/usr/src/lib/nsswitch/dns/Makefile.com index f4aa3f433c..23c89c32f8 100644 --- a/usr/src/lib/nsswitch/dns/Makefile.com +++ b/usr/src/lib/nsswitch/dns/Makefile.com @@ -2,9 +2,8 @@ # CDDL HEADER START # # The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@ # CDDL HEADER END # # -# Copyright 2003 Sun Microsystems, Inc. All rights reserved. +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # ident "%Z%%M% %I% %E% SMI" @@ -45,5 +44,7 @@ include ../../../Makefile.rootfs # if no libresolv was provided by the application. CPPFLAGS += -DNSS_DNS_LIBRESOLV=\"libresolv.so.2\" +LINTFLAGS += -erroff=E_GLOBAL_COULD_BE_STATIC2 + LDLIBS += -lnsl DYNLIB1 = nss_dns.so$(VERS) diff --git a/usr/src/lib/nsswitch/dns/common/dns_common.c b/usr/src/lib/nsswitch/dns/common/dns_common.c index da766c4d12..0ed02f1d23 100644 --- a/usr/src/lib/nsswitch/dns/common/dns_common.c +++ b/usr/src/lib/nsswitch/dns/common/dns_common.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,16 +19,27 @@ * CDDL HEADER END */ /* - * dns_common.c - * - * Copyright (c) 1993,1998 by Sun Microsystems, Inc. - * All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. */ -#pragma ident "%Z%%M% %I% %E% SMI" +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * dns_common.c + */ #include "dns_common.h" +#pragma weak dn_expand +#pragma weak res_ninit +#pragma weak res_nsearch +#pragma weak res_nclose +#pragma weak ns_get16 +#pragma weak ns_get32 +#pragma weak __ns_get16 +#pragma weak __ns_get32 + #define DNS_ALIASES 0 #define DNS_ADDRLIST 1 #define DNS_MAPDLIST 2 @@ -58,7 +68,8 @@ dns_netdb_aliases(from_list, to_list, aliaspp, type, count, af_type) if (*aliaspp <= (char *)&to_list[cnt+1]) return (NSS_STR_PARSE_ERANGE); if (type == DNS_MAPDLIST) { - struct in6_addr *addr6p = (struct in6_addr *) *aliaspp; + /* LINTED: E_BAD_PTR_CAST_ALIGN */ + struct in6_addr *addr6p = (struct in6_addr *)*aliaspp; (void) memset(addr6p, '\0', sizeof (struct in6_addr)); (void) memcpy(&addr6p->s6_addr[12], fstr, @@ -96,7 +107,7 @@ ent2result(he, argp, af_type) struct in6_addr *addrp6; limit = argp->buf.buffer + buflen; - host = (struct hostent *) argp->buf.result; + host = (struct hostent *)argp->buf.result; buffer = argp->buf.buffer; /* h_addrtype and h_length */ @@ -114,7 +125,7 @@ ent2result(he, argp, af_type) /* h_addr_list */ if (af_type == AF_INET) { - addrp = (struct in_addr *) ROUND_DOWN(limit, sizeof (*addrp)); + addrp = (struct in_addr *)ROUND_DOWN(limit, sizeof (*addrp)); host->h_addr_list = (char **) ROUND_UP(buffer, sizeof (char **)); ret = dns_netdb_aliases(he->h_addr_list, host->h_addr_list, @@ -152,16 +163,368 @@ ent2result(he, argp, af_type) return (ret); } +/* + * Convert the hostent structure into string in the following + * format: + * + * IP-address official-host-name nicknames ... + * + * If more than one IP-addresses matches the official-host-name, + * the above line will be followed by: + * IP-address-1 official-host-name + * IP-address-2 official-host-name + * ... + * + * This is so that the str2hostent function in libnsl + * can convert the string back to the original hostent + * data. + */ +int +ent2str( + struct hostent *hp, + nss_XbyY_args_t *ap, + int af_type) +{ + char **p; + char obuf[INET6_ADDRSTRLEN]; + void *addr; + struct in_addr in4; + int af; + int n; + const char *res; + char **q; + int l = ap->buf.buflen; + char *s = ap->buf.buffer; + + /* + * for "hosts" lookup, we only want address type of + * AF_INET. For "ipnodes", we can have both AF_INET + * and AF_INET6. + */ + if (af_type == AF_INET && hp->h_addrtype != AF_INET) + return (NSS_STR_PARSE_PARSE); + + for (p = hp->h_addr_list; *p != 0; p++) { + + if (p != hp->h_addr_list) { + *s = '\n'; + s++; + l--; + } + + if (hp->h_addrtype == AF_INET6) { + /* LINTED: E_BAD_PTR_CAST_ALIGN */ + if (IN6_IS_ADDR_V4MAPPED((struct in6_addr *)*p)) { + /* LINTED: E_BAD_PTR_CAST_ALIGN */ + IN6_V4MAPPED_TO_INADDR((struct in6_addr *)*p, + &in4); + af = AF_INET; + addr = &in4; + } else { + af = AF_INET6; + addr = *p; + } + } else { + af = AF_INET; + addr = *p; + } + res = inet_ntop(af, addr, obuf, sizeof (obuf)); + if (res == NULL) + return (NSS_STR_PARSE_PARSE); + + if ((n = snprintf(s, l, "%s %s", res, hp->h_name)) >= l) + return (NSS_STR_PARSE_ERANGE); + l -= n; + s += n; + if (p == hp->h_addr_list) { + for (q = hp->h_aliases; q && *q; q++) { + if ((n = snprintf(s, l, " %s", *q)) >= l) + return (NSS_STR_PARSE_ERANGE); + l -= n; + s += n; + } + } + } + + ap->returnlen = s - ap->buf.buffer; + return (NSS_STR_PARSE_SUCCESS); +} nss_backend_t * _nss_dns_constr(dns_backend_op_t ops[], int n_ops) { dns_backend_ptr_t be; - if ((be = (dns_backend_ptr_t) malloc(sizeof (*be))) == 0) + if ((be = (dns_backend_ptr_t)malloc(sizeof (*be))) == 0) return (0); be->ops = ops; be->n_ops = n_ops; - return ((nss_backend_t *) be); + return ((nss_backend_t *)be); +} + + +/* + * nss_dns_gethost_withttl(void *buffer, size_t bufsize, int ipnode) + * nss2 get hosts/ipnodes with ttl backend DNS search engine. + * + * This API is given a pointer to a packed buffer, and the buffer size + * It's job is to perform the appropriate res_nsearch, extract the + * results and build a unmarshalled hosts/ipnodes result buffer. + * Additionally in the extended results a nssuint_t ttl is placed. + * This ttl is the lessor of the ttl's extracted from the result. + * + * ***Currently the first version of this API only performs simple + * single res_nsearch lookups for with T_A or T_AAAA results. + * Other searches are deferred to the generic API w/t ttls. + * + * This function is not a generic res_* operation. It only performs + * a single T_A or T_AAAA lookups*** + * + * RETURNS: NSS_SUCCESS or NSS_ERROR + * If an NSS_ERROR result is returned, nscd is expected + * to resubmit the gethosts request using the old style + * nsswitch lookup format. + */ + +struct tsd_priv { + struct __res_state *statp; /* dns state block */ + union msg { + uchar_t buf[NS_MAXMSG]; /* max legal DNS answer size */ + HEADER h; + } resbuf; + char aliases[NS_MAXMSG]; /* set of aliases */ +}; + +static void ghttlcleanup(void *ptr) +{ + struct tsd_priv *priv = (struct tsd_priv *)ptr; + + if (priv) { + if (priv->statp != NULL) { + res_nclose(priv->statp); + free((void *)priv->statp); + } + free(ptr); + } +} + +nss_status_t +_nss_dns_gethost_withttl(void *buffer, size_t bufsize, int ipnode) +{ + /* nss buffer variables */ + nss_pheader_t *pbuf = (nss_pheader_t *)buffer; + nss_XbyY_args_t arg; + char *dbname; + int dbop; + nss_status_t sret; + size_t bsize, blen; + char *bptr; + /* resolver query variables */ + static mutex_t keylock; + static thread_key_t key; + static int once_per_keyname = 0; + struct tsd_priv *tsd = NULL; + const char *name; + int qtype; + /* answer parsing variables */ + HEADER *hp; + uchar_t *cp; /* current location in message */ + uchar_t *bom; /* start of message */ + uchar_t *eom; /* end of message */ + uchar_t *eor; /* end of record */ + int ancount, qdcount; + int type, class; + nssuint_t nttl, ttl, *pttl; /* The purpose of this API */ + int n, ret; + const char *np; + /* temporary buffers */ + char nbuf[INET6_ADDRSTRLEN]; /* address parser */ + char host[MAXHOSTNAMELEN]; /* result host name */ + char ans[MAXHOSTNAMELEN]; /* record name */ + char aname[MAXHOSTNAMELEN]; /* alias result (C_NAME) */ + /* misc variables */ + int af; + char *ap, *apc; + int hlen, alen, iplen, len; + + if (!once_per_keyname) { + (void) mutex_lock(&keylock); + if (!once_per_keyname) { + (void) thr_keycreate(&key, ghttlcleanup); + once_per_keyname++; + } + (void) mutex_unlock(&keylock); + } + (void) thr_getspecific(key, (void **)&tsd); + if (tsd == NULL) { + tsd = (struct tsd_priv *)calloc(1, sizeof (struct tsd_priv)); + (void) thr_setspecific(key, (void *)tsd); + (void) thr_getspecific(key, (void **)&tsd); + tsd->statp = (struct __res_state *) + calloc(1, sizeof (struct __res_state)); + if (tsd->statp == NULL) + return (NSS_ERROR); + if (res_ninit(tsd->statp) == -1) { + free(tsd->statp); + return (NSS_ERROR); + } + } + ap = apc = (char *)tsd->aliases; + alen = 0; + ttl = (nssuint_t)0xFFFFFFF; /* start w/max, find smaller */ + + /* save space for ttl otherwise, why bother... */ + bsize = pbuf->data_len - sizeof (nssuint_t); + bptr = (char *)buffer + pbuf->data_off; + blen = 0; + sret = nss_packed_getkey(buffer, bufsize, &dbname, &dbop, &arg); + if (sret != NSS_SUCCESS) { + return (NSS_ERROR); + } + + if (ipnode) { + /* initially only handle the simple cases */ + if (arg.key.ipnode.flags != 0) + return (NSS_ERROR); + name = arg.key.ipnode.name; + if (arg.key.ipnode.af_family == AF_INET6) + qtype = T_AAAA; + else + qtype = T_A; + } else { + name = arg.key.name; + qtype = T_A; + } + ret = res_nsearch(tsd->statp, name, C_IN, qtype, + tsd->resbuf.buf, NS_MAXMSG); + if (ret == -1) { + if (tsd->statp->res_h_errno == HOST_NOT_FOUND) { + pbuf->p_herrno = HOST_NOT_FOUND; + pbuf->p_status = NSS_NOTFOUND; + pbuf->data_len = 0; + return (NSS_NOTFOUND); + } + /* else lookup error - handle in general code */ + return (NSS_ERROR); + } + + cp = tsd->resbuf.buf; + hp = (HEADER *)&tsd->resbuf.h; + bom = cp; + eom = cp + ret; + + ancount = ntohs(hp->ancount); + qdcount = ntohs(hp->qdcount); + cp += HFIXEDSZ; + if (qdcount != 1) + return (NSS_ERROR); + n = dn_expand(bom, eom, cp, host, MAXHOSTNAMELEN); + if (n < 0) { + return (NSS_ERROR); + } else + hlen = strlen(host); + cp += n + QFIXEDSZ; + if (cp > eom) + return (NSS_ERROR); + while (ancount-- > 0 && cp < eom && blen < bsize) { + n = dn_expand(bom, eom, cp, ans, MAXHOSTNAMELEN); + if (n > 0) { + if (strncasecmp(host, ans, hlen) != 0) + return (NSS_ERROR); /* spoof? */ + } + cp += n; + /* bounds check */ + type = ns_get16(cp); /* type */ + cp += INT16SZ; + class = ns_get16(cp); /* class */ + cp += INT16SZ; + nttl = (nssuint_t)ns_get32(cp); /* ttl in sec */ + if (nttl < ttl) + ttl = nttl; + cp += INT32SZ; + n = ns_get16(cp); /* len */ + cp += INT16SZ; + if (class != C_IN) { + cp += n; + continue; + } + eor = cp + n; + if (type == T_CNAME) { + /* add an alias to the alias list */ + n = dn_expand(bom, eor, cp, aname, MAXHOSTNAMELEN); + if (n > 0) { + len = strlen(aname); + if (len > 0) { + /* + * Just error out if there is an + * attempted buffer overflow exploit + * generic code will do a syslog + */ + if (alen + len + 2 > NS_MAXMSG) + return (NSS_ERROR); + *apc++ = ' '; + alen++; + (void) strlcpy(apc, aname, len + 1); + alen += len; + apc += len; + } + } + cp += n; + continue; + } + if (type != qtype) { + cp += n; + continue; + } + /* check data size */ + if ((type == T_A && n != INADDRSZ) || + (type == T_AAAA && n != IN6ADDRSZ)) { + cp += n; + continue; + } + af = (type == T_A ? AF_INET : AF_INET6); + np = inet_ntop(af, (void *)cp, nbuf, INET6_ADDRSTRLEN); + if (np == NULL) + return (NSS_ERROR); + cp += n; + /* append IP host aliases to results */ + iplen = strlen(np); + /* ip <SP> hostname [<SP>][aliases] */ + len = iplen + 2 + hlen + alen; + if (alen > 0) + len++; + if (blen + len > bsize) + return (NSS_ERROR); + (void) strlcpy(bptr, np, bsize - blen); + blen += iplen; + bptr += iplen; + *bptr++ = ' '; + blen++; + (void) strlcpy(bptr, host, bsize - blen); + blen += hlen; + bptr += hlen; + if (alen > 0) { + *bptr++ = ' '; + blen++; + (void) strlcpy(bptr, ap, bsize - blen); + blen += alen; + bptr += alen; + } + *bptr++ = '\n'; + blen++; + } + /* Presumably the buffer is now filled. */ + len = ROUND_UP(blen, sizeof (nssuint_t)); + /* still room? */ + if (len + sizeof (nssuint_t) > pbuf->data_len) { + /* sigh, no, what happened? */ + return (NSS_ERROR); + } + pbuf->ext_off = pbuf->data_off + len; + pbuf->ext_len = sizeof (nssuint_t); + pbuf->data_len = blen; + pttl = (nssuint_t *)((void *)((char *)pbuf + pbuf->ext_off)); + *pttl = ttl; + return (NSS_SUCCESS); } diff --git a/usr/src/lib/nsswitch/dns/common/dns_common.h b/usr/src/lib/nsswitch/dns/common/dns_common.h index 7861cbb683..f60a37e436 100644 --- a/usr/src/lib/nsswitch/dns/common/dns_common.h +++ b/usr/src/lib/nsswitch/dns/common/dns_common.h @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,9 +19,10 @@ * CDDL HEADER END */ /* - * Copyright (c) 1993, 1998-1999 by Sun Microsystems, Inc. - * All rights reserved. - * + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ +/* * Common code and structures used by name-service-switch "dns" backends. */ @@ -39,10 +39,12 @@ #include <netdb.h> #include <strings.h> #include <thread.h> +#include <arpa/inet.h> #include <arpa/nameser.h> #include <resolv.h> #include <syslog.h> #include <nsswitch.h> +#include <nss_common.h> #include <nss_dbdefs.h> #include <stdlib.h> #include <signal.h> @@ -74,13 +76,17 @@ extern mutex_t one_lane; extern int _thr_sigsetmask(int, const sigset_t *, sigset_t *); extern int _mutex_lock(mutex_t *); extern int _mutex_unlock(mutex_t *); -extern const char *inet_ntop(int, const void *, char *, size_t); extern int ent2result(struct hostent *, nss_XbyY_args_t *, int); +extern int ent2str(struct hostent *, nss_XbyY_args_t *, int); nss_backend_t *_nss_dns_constr(dns_backend_op_t *, int); extern nss_status_t _herrno2nss(int); +nss_status_t _nss_dns_gethost_withttl(void *buf, size_t bufsize, int ipnode); +nss_status_t _nss_get_dns_hosts_name(dns_backend_ptr_t *, void **, size_t *); +nss_status_t _nss_get_dns_ipnodes_name(dns_backend_ptr_t *, void **, size_t *); + #ifdef __cplusplus } #endif diff --git a/usr/src/lib/nsswitch/dns/common/dns_mt.c b/usr/src/lib/nsswitch/dns/common/dns_mt.c index 7e236c40eb..bf6ac565c4 100644 --- a/usr/src/lib/nsswitch/dns/common/dns_mt.c +++ b/usr/src/lib/nsswitch/dns/common/dns_mt.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,8 +19,8 @@ * CDDL HEADER END */ /* - * Copyright (c) 1993, 1998-2001 by Sun Microsystems, Inc. - * All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. */ #pragma ident "%Z%%M% %I% %E% SMI" @@ -109,11 +108,10 @@ mutex_t one_lane = DEFAULTMUTEX; void _nss_dns_init(void) { - struct hostent *(*f_hostent_ptr)(); void *reslib, (*f_void_ptr)(); /* If no libresolv library, then load one */ - if ((f_hostent_ptr = res_gethostbyname) == 0) { + if (res_gethostbyname == 0) { if ((reslib = dlopen(NSS_DNS_LIBRESOLV, RTLD_LAZY|RTLD_GLOBAL)) != 0) { /* Turn off /etc/hosts fall back in libresolv */ diff --git a/usr/src/lib/nsswitch/dns/common/gethostent.c b/usr/src/lib/nsswitch/dns/common/gethostent.c index 38c8a44a3a..af365f4f2a 100644 --- a/usr/src/lib/nsswitch/dns/common/gethostent.c +++ b/usr/src/lib/nsswitch/dns/common/gethostent.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,8 +19,8 @@ * CDDL HEADER END */ /* - * Copyright (c) 1993, 1998-2000 by Sun Microsystems, Inc. - * All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. */ #pragma ident "%Z%%M% %I% %E% SMI" @@ -144,10 +143,22 @@ getbyname(be, a) he = _gethostbyname(&argp->h_errno, argp->key.name); if (he != NULL) { - ret = ent2result(he, a, AF_INET); - if (ret == NSS_STR_PARSE_SUCCESS) { - argp->returnval = argp->buf.result; + if (argp->buf.result == NULL) { + /* + * if asked to return data in string, + * convert the hostent structure into + * string data + */ + ret = ent2str(he, a, AF_INET); + if (ret == NSS_STR_PARSE_SUCCESS) + argp->returnval = argp->buf.buffer; } else { + ret = ent2result(he, a, AF_INET); + if (ret == NSS_STR_PARSE_SUCCESS) + argp->returnval = argp->buf.result; + } + + if (ret != NSS_STR_PARSE_SUCCESS) { argp->h_errno = HOST_NOT_FOUND; if (ret == NSS_STR_PARSE_ERANGE) { argp->erange = 1; @@ -176,6 +187,7 @@ getbyaddr(be, a) * Exposing a DNS backend specific interface so that it doesn't conflict * with other getbyaddr() routines from other switch backends. */ +/*ARGSUSED*/ nss_status_t __nss_dns_getbyaddr(be, a) dns_backend_ptr_t be; @@ -195,11 +207,12 @@ __nss_dns_getbyaddr(be, a) switch_resolver_setup(&mt_disabled, &oldmask, &old_retry); + /* LINTED: E_BAD_PTR_CAST_ALIGN */ if (IN6_IS_ADDR_V4MAPPED((struct in6_addr *)argp->key.hostaddr.addr)) { addrp = &unmapv4; addrlen = sizeof (unmapv4); af = AF_INET; - memcpy(addrp, &argp->key.hostaddr.addr[12], addrlen); + (void) memcpy(addrp, &argp->key.hostaddr.addr[12], addrlen); } else { addrp = (void *)argp->key.hostaddr.addr; addrlen = argp->key.hostaddr.len; @@ -217,7 +230,18 @@ __nss_dns_getbyaddr(be, a) if (n < MAXHOSTNAMELEN-1 && hbuf[n-1] != '.') { (void) strcat(hbuf, "."); } - ret = ent2result(he, a, argp->key.hostaddr.type); + + /* + * if asked to return data in string, + * convert the hostent structure into + * string data + */ + if (argp->buf.result == NULL) + ret = ent2str(he, a, argp->key.hostaddr.type); + else + ret = ent2result(he, a, + argp->key.hostaddr.type); + save_h_errno = argp->h_errno; } if (ret == NSS_STR_PARSE_SUCCESS) { @@ -242,7 +266,12 @@ __nss_dns_getbyaddr(be, a) if (memcmp(*ans, addrp, addrlen) == 0) { argp->h_errno = save_h_errno; - argp->returnval = argp->buf.result; + if (argp->buf.result == NULL) + argp->returnval = + argp->buf.buffer; + else + argp->returnval = + argp->buf.result; break; } } else { @@ -259,12 +288,16 @@ __nss_dns_getbyaddr(be, a) * this go. And return the name from byaddr. */ argp->h_errno = save_h_errno; - argp->returnval = argp->buf.result; + if (argp->buf.result == NULL) + argp->returnval = argp->buf.buffer; + else + argp->returnval = argp->buf.result; } /* we've been spoofed, make sure to log it. */ if (argp->h_errno == HOST_NOT_FOUND) { if (argp->key.hostaddr.type == AF_INET) syslog(LOG_NOTICE, "gethostbyaddr: %s != %s", + /* LINTED: E_BAD_PTR_CAST_ALIGN */ hbuf, inet_ntoa(*(struct in_addr *)argp->key.hostaddr.addr)); else syslog(LOG_NOTICE, "gethostbyaddr: %s != %s", @@ -414,3 +447,22 @@ _nss_dns_hosts_constr(dummy1, dummy2, dummy3) return (_nss_dns_constr(host_ops, sizeof (host_ops) / sizeof (host_ops[0]))); } + +/* + * optional NSS2 packed backend gethostsbyname with ttl + * entry point. + * + * Returns: + * NSS_SUCCESS - successful + * NSS_NOTFOUND - successful but nothing found + * NSS_ERROR - fallback to NSS backend lookup mode + * If successful, buffer will be filled with valid data + * + */ + +/*ARGSUSED*/ +nss_status_t +_nss_get_dns_hosts_name(dns_backend_ptr_t *be, void **bufp, size_t *sizep) +{ + return (_nss_dns_gethost_withttl(*bufp, *sizep, 0)); +} diff --git a/usr/src/lib/nsswitch/dns/common/gethostent6.c b/usr/src/lib/nsswitch/dns/common/gethostent6.c index e92ce6a356..b2d71d6b24 100644 --- a/usr/src/lib/nsswitch/dns/common/gethostent6.c +++ b/usr/src/lib/nsswitch/dns/common/gethostent6.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,9 +19,10 @@ * CDDL HEADER END */ /* - * Copyright 1993-2000, 2003 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. - * + */ +/* * gethostent6.c */ @@ -115,7 +115,7 @@ cloneName(struct hostent *h, int *outerr) { return (0); } - memcpy(name, h->h_name, len+1); + (void) memcpy(name, h->h_name, len+1); *errp = 0; return (name); @@ -130,7 +130,7 @@ cloneName(struct hostent *h, int *outerr) { * Note: The pointers to the addresses in the moreAddrs[] array are copied, * but not the IP addresses themselves. */ -struct in6_addr ** +static struct in6_addr ** cloneAddrList(struct hostent *h, struct in6_addr **moreAddrs, int *outerr) { struct in6_addr **addrArray, *addrList; @@ -176,10 +176,12 @@ cloneAddrList(struct hostent *h, struct in6_addr **moreAddrs, int *outerr) { for (i = 0; i < addrCount; i++) { addrArray[i] = addrList; if (domap) { + /* LINTED: E_BAD_PTR_CAST_ALIGN */ IN6_INADDR_TO_V4MAPPED( (struct in_addr *)h->h_addr_list[i], addrArray[i]); } else { - memcpy(addrArray[i], h->h_addr_list[i], addrlen); + (void) memcpy(addrArray[i], h->h_addr_list[i], + addrlen); } addrList = PTROFF(addrList, addrlen); } @@ -211,7 +213,7 @@ static char ** cloneAliasList(struct hostent *h, char **mergeAliases, int *outerr) { char **aliasArray, *aliasList; - int i, j, k, aliasCount, mergeAliasCount = 0, realMac = 0; + int i, j, aliasCount, mergeAliasCount = 0, realMac = 0; int stringSize = 0; int error, *errp; @@ -259,7 +261,7 @@ cloneAliasList(struct hostent *h, char **mergeAliases, int *outerr) { for (i = 0; i < aliasCount; i++) { int len = strlen(h->h_aliases[i]); aliasArray[i] = aliasList; - memcpy(aliasArray[i], h->h_aliases[i], len+1); + (void) memcpy(aliasArray[i], h->h_aliases[i], len+1); aliasList = PTROFF(aliasList, RNDUP(len+1)); } @@ -275,7 +277,7 @@ cloneAliasList(struct hostent *h, char **mergeAliases, int *outerr) { return (aliasArray); } - +/*ARGSUSED*/ static nss_status_t getbyname(be, a) dns_backend_ptr_t be; @@ -407,11 +409,23 @@ getbyname(be, a) argp->h_errno = v6_h_errno; } - if (he != 0) { - ret = ent2result(he, a, AF_INET6); - if (ret == NSS_STR_PARSE_SUCCESS) { - argp->returnval = argp->buf.result; + if (he != NULL) { + /* + * if asked to return data in string, + * convert the hostent structure into + * string data + */ + if (argp->buf.result == NULL) { + ret = ent2str(he, a, AF_INET6); + if (ret == NSS_STR_PARSE_SUCCESS) + argp->returnval = argp->buf.buffer; } else { + ret = ent2result(he, a, AF_INET6); + if (ret == NSS_STR_PARSE_SUCCESS) + argp->returnval = argp->buf.result; + } + + if (ret != NSS_STR_PARSE_SUCCESS) { argp->h_errno = HOST_NOT_FOUND; if (ret == NSS_STR_PARSE_ERANGE) { argp->erange = 1; @@ -532,3 +546,22 @@ _nss_dns_ipnodes_constr(dummy1, dummy2, dummy3) return (_nss_dns_constr(ipnodes_ops, sizeof (ipnodes_ops) / sizeof (ipnodes_ops[0]))); } + +/* + * optional NSS2 packed backend gethostsbyipnode with ttl + * entry point. + * + * Returns: + * NSS_SUCCESS - successful + * NSS_NOTFOUND - successful but nothing found + * NSS_ERROR - fallback to NSS backend lookup mode + * If successful, buffer will be filled with valid data + * + */ + +/*ARGSUSED*/ +nss_status_t +_nss_get_dns_ipnodes_name(dns_backend_ptr_t *be, void **bufp, size_t *sizep) +{ + return (_nss_dns_gethost_withttl(*bufp, *sizep, 1)); +} diff --git a/usr/src/lib/nsswitch/dns/common/mapfile-vers b/usr/src/lib/nsswitch/dns/common/mapfile-vers index 6e44ffe568..9aa3d5ff1a 100644 --- a/usr/src/lib/nsswitch/dns/common/mapfile-vers +++ b/usr/src/lib/nsswitch/dns/common/mapfile-vers @@ -1,15 +1,14 @@ # #ident "%Z%%M% %I% %E% SMI" # -# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # CDDL HEADER START # # The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. @@ -41,6 +40,8 @@ SUNWprivate_1.1 { global: _nss_dns_hosts_constr; _nss_dns_ipnodes_constr; + _nss_get_dns_hosts_name; + _nss_get_dns_ipnodes_name; local: *; }; diff --git a/usr/src/lib/nsswitch/files/Makefile.com b/usr/src/lib/nsswitch/files/Makefile.com index f6105144d7..0f5ff82629 100644 --- a/usr/src/lib/nsswitch/files/Makefile.com +++ b/usr/src/lib/nsswitch/files/Makefile.com @@ -61,8 +61,10 @@ include ../../Makefile.com include ../../../Makefile.rootfs CPPFLAGS += -I../../../common/inc +LINTFLAGS += -erroff=E_GLOBAL_COULD_BE_STATIC2 +LINTFLAGS64 += -erroff=E_GLOBAL_COULD_BE_STATIC2 -LDLIBS += -lnsl +LDLIBS += -lsocket -lnsl DYNLIB1 = nss_files.so$(VERS) all: $(DYNLIB1) fnamecheck diff --git a/usr/src/lib/nsswitch/files/common/bootparams_getbyname.c b/usr/src/lib/nsswitch/files/common/bootparams_getbyname.c index ef51910acb..e1e88b1ced 100644 --- a/usr/src/lib/nsswitch/files/common/bootparams_getbyname.c +++ b/usr/src/lib/nsswitch/files/common/bootparams_getbyname.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,11 +19,11 @@ * CDDL HEADER END */ /* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + * * files/bootparams_getbyname.c -- "files" backend for * nsswitch "bootparams" database. - * - * Copyright (c) 1988-1995 Sun Microsystems Inc - * All Rights Reserved. */ #pragma ident "%Z%%M% %I% %E% SMI" @@ -44,7 +43,7 @@ getbyname(be, a) files_backend_ptr_t be; void *a; { - nss_XbyY_args_t *argp = (nss_XbyY_args_t *) a; + nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a; nss_status_t res; /* bootparams_getbyname() has not set/endent; rewind on each call */ @@ -108,14 +107,14 @@ _nss_files_XY_bootparams(be, args, filter) * _nss_files_read_line does process the '\' that are used * in /etc/bootparams for continuation and gives one long * buffer. - * + * * linelen counts the characters up to but excluding the '\n' */ if ((linelen = _nss_files_read_line(be->f, instr, be->minbuf)) < 0) { /* End of file */ args->returnval = 0; - args->erange = 0; + args->returnlen = 0; break; } @@ -158,6 +157,7 @@ _nss_files_XY_bootparams(be, args, filter) (void) memcpy(args->buf.buffer, p, linelen); args->buf.buffer[linelen] = '\0'; args->returnval = args->buf.result; + args->returnlen = linelen; res = NSS_SUCCESS; break; } diff --git a/usr/src/lib/nsswitch/files/common/ether_addr.c b/usr/src/lib/nsswitch/files/common/ether_addr.c index 4731e0c354..b8900cf043 100644 --- a/usr/src/lib/nsswitch/files/common/ether_addr.c +++ b/usr/src/lib/nsswitch/files/common/ether_addr.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,9 +19,9 @@ * CDDL HEADER END */ /* - * files/ether_addr.c -- "files" backend for nsswitch "ethers" database + * files/ether_addr.c -- "files" backend for nsswitch "ethers" database * - * Copyright 1988-1995,2002 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -44,14 +43,38 @@ #include <nss_dbdefs.h> #include "files_common.h" #include <strings.h> +#include <ctype.h> #define _PATH_ETHERS "/etc/ethers" +#define DIGIT(x) \ + (isdigit(x) ? (x) - '0' : islower(x) ? (x) + 10 - 'a' : (x) + 10 - 'A') static int -check_host(args) - nss_XbyY_args_t *args; +check_host(nss_XbyY_args_t *argp, const char *line, int linelen) { - return (strcmp(args->buf.buffer, args->key.name) == 0); + const char *limit, *linep, *keyp; + linep = line; + limit = line + linelen; + + /* skip leading spaces */ + while (linep < limit && isspace(*linep)) + linep++; + /* skip mac address */ + while (linep < limit && !isspace(*linep)) + linep++; + /* skip the delimiting spaces */ + while (linep < limit && isspace(*linep)) + linep++; + if (linep == limit) + return (0); + + /* compare the host name */ + keyp = argp->key.name; + while (*keyp != '\0' && linep < limit && *keyp == *linep) { + keyp++; + linep++; + } + return (*keyp == '\0' && linep == limit); } static nss_status_t @@ -63,21 +86,57 @@ getbyhost(be, a) char hostname[MAXHOSTNAMELEN]; nss_status_t res; - argp->buf.buffer = hostname; - argp->buf.buflen = MAXHOSTNAMELEN; + /* + * use the buffer passed in if result is to be returned + * in /etc file format + */ + if (argp->buf.result != NULL) { + argp->buf.buffer = hostname; + argp->buf.buflen = MAXHOSTNAMELEN; + } res = _nss_files_XY_all(be, argp, 0, argp->key.name, check_host); - argp->buf.buffer = NULL; - argp->buf.buflen = 0; + if (argp->buf.result != NULL) { + argp->buf.buffer = NULL; + argp->buf.buflen = 0; + } + return (res); } static int -check_ether(args) - nss_XbyY_args_t *args; +check_ether(nss_XbyY_args_t *argp, const char *line, int linelen) { - return (ether_cmp(args->buf.result, args->key.ether) == 0); + + const char *limit, *linep; + uchar_t ether[6]; + ptrdiff_t i; + int n; + + linep = line; + limit = line + linelen; + + /* skip leading spaces */ + while (linep < limit && isspace(*linep)) + linep++; + + for (i = 0; i < 6; i++) { + n = 0; + while (linep < limit && isxdigit(*linep)) { + n = 16 * n + DIGIT(*linep); + linep++; + } + if (*linep != ':' && i < 5) { + return (0); + } else if (*linep == ':' && i == 5) { + return (0); + } else { + linep++; + ether[i] = (uchar_t)n; + } + } + return (ether_cmp((void *)ether, (void *)argp->key.ether) == 0); } static nss_status_t diff --git a/usr/src/lib/nsswitch/files/common/files_common.c b/usr/src/lib/nsswitch/files/common/files_common.c index bdf03a3ca9..0f89f25d0b 100644 --- a/usr/src/lib/nsswitch/files/common/files_common.c +++ b/usr/src/lib/nsswitch/files/common/files_common.c @@ -41,6 +41,7 @@ #include <poll.h> #include <unistd.h> #include <sys/stat.h> +#include <sys/mman.h> /*ARGSUSED*/ nss_status_t @@ -69,7 +70,7 @@ _nss_files_endent(be, dummy) void *dummy; { if (be->f != 0) { - fclose(be->f); + (void) fclose(be->f); be->f = 0; } if (be->buf != 0) { @@ -186,7 +187,7 @@ _nss_files_do_all(be, args, filter, func) } while (res == NSS_NOTFOUND); - _nss_files_endent(be, 0); + (void) _nss_files_endent(be, 0); return (res); } @@ -208,6 +209,8 @@ _nss_files_XY_all(be, args, netdb, filter, check) int parsestat; int (*func)(); + if (filter != NULL && *filter == '\0') + return (NSS_NOTFOUND); if (be->buf == 0 && (be->buf = malloc(be->minbuf)) == 0) { return (NSS_UNAVAIL); /* really panic, malloc failed */ @@ -230,7 +233,7 @@ _nss_files_XY_all(be, args, netdb, filter, check) be->minbuf)) < 0) { /* End of file */ args->returnval = 0; - args->erange = 0; + args->returnlen = 0; break; } if (filter != 0 && strstr(instr, filter) == 0) { @@ -277,17 +280,21 @@ _nss_files_XY_all(be, args, netdb, filter, check) } args->returnval = 0; + args->returnlen = 0; + + if (check != NULL && (*check)(args, instr, linelen) == 0) + continue; func = args->str2ent; parsestat = (*func)(instr, linelen, args->buf.result, args->buf.buffer, args->buf.buflen); if (parsestat == NSS_STR_PARSE_SUCCESS) { - args->returnval = args->buf.result; - if (check == 0 || (*check)(args)) { - res = NSS_SUCCESS; - break; - } + args->returnval = (args->buf.result != NULL)? + args->buf.result : args->buf.buffer; + args->returnlen = linelen; + res = NSS_SUCCESS; + break; } else if (parsestat == NSS_STR_PARSE_ERANGE) { args->erange = 1; break; @@ -339,15 +346,22 @@ _nss_files_hash_destroy(files_hash_t *fhp) extern void __nss_use_files_hash(void); #endif /* pic */ +/*ARGSUSED*/ nss_status_t _nss_files_XY_hash(files_backend_ptr_t be, nss_XbyY_args_t *args, int netdb, files_hash_t *fhp, int hashop, files_XY_check_func check) { + /* LINTED E_FUNC_VAR_UNUSED */ int fd, retries, ht; + /* LINTED E_FUNC_VAR_UNUSED */ uint_t hash, line, f; + /* LINTED E_FUNC_VAR_UNUSED */ files_hashent_t *hp, *htab; + /* LINTED E_FUNC_VAR_UNUSED */ char *cp, *first, *last; + /* LINTED E_FUNC_VAR_UNUSED */ nss_XbyY_args_t xargs; + /* LINTED E_FUNC_VAR_UNUSED */ struct stat64 st; #ifndef PIC @@ -375,26 +389,30 @@ retry: st.st_mtim.tv_nsec == fhp->fh_mtime.tv_nsec && fhp->fh_table != NULL) { htab = &fhp->fh_table[hashop * fhp->fh_size]; - hash = fhp->fh_hash_func[hashop](args, 1); + hash = fhp->fh_hash_func[hashop](args, 1, NULL, 0); for (hp = htab[hash % fhp->fh_size].h_first; hp != NULL; hp = hp->h_next) { if (hp->h_hash != hash) continue; line = hp - htab; + if ((*check)(args, fhp->fh_line[line].l_start, + fhp->fh_line[line].l_len) == 0) + continue; if ((*args->str2ent)(fhp->fh_line[line].l_start, fhp->fh_line[line].l_len, args->buf.result, args->buf.buffer, args->buf.buflen) == NSS_STR_PARSE_SUCCESS) { - args->returnval = args->buf.result; - if ((*check)(args)) { - mutex_unlock(&fhp->fh_lock); - return (NSS_SUCCESS); - } + args->returnval = (args->buf.result)? + args->buf.result:args->buf.buffer; + args->returnlen = fhp->fh_line[line].l_len; + mutex_unlock(&fhp->fh_lock); + return (NSS_SUCCESS); } else { args->erange = 1; } } args->returnval = 0; + args->returnlen = 0; mutex_unlock(&fhp->fh_lock); return (NSS_NOTFOUND); } @@ -461,14 +479,6 @@ retry: if (fhp->fh_line == NULL || fhp->fh_table == NULL) goto unavail; - xargs = *args; - xargs.buf.result = malloc(fhp->fh_resultsize + fhp->fh_bufsize); - if (xargs.buf.result == NULL) - goto unavail; - xargs.buf.buffer = (char *)xargs.buf.result + fhp->fh_resultsize; - xargs.buf.buflen = fhp->fh_bufsize; - xargs.returnval = xargs.buf.result; - line = 0; cp = fhp->fh_file_start; while (cp < fhp->fh_file_end) { @@ -494,18 +504,14 @@ retry: --last; *++last = '\0'; } - if ((*xargs.str2ent)(first, last - first, - xargs.buf.result, xargs.buf.buffer, xargs.buf.buflen) != - NSS_STR_PARSE_SUCCESS) - continue; for (ht = 0; ht < fhp->fh_nhtab; ht++) { hp = &fhp->fh_table[ht * fhp->fh_size + line]; - hp->h_hash = fhp->fh_hash_func[ht](&xargs, 0); + hp->h_hash = fhp->fh_hash_func[ht](&xargs, 0, first, + last - first); } fhp->fh_line[line].l_start = first; fhp->fh_line[line++].l_len = last - first; } - free(xargs.buf.result); /* * Populate the hash tables in reverse order so that the hash chains @@ -561,13 +567,13 @@ _nss_files_destr(be, dummy) { if (be != 0) { if (be->f != 0) { - _nss_files_endent(be, 0); + (void) _nss_files_endent(be, 0); } if (be->hashinfo != NULL) { - mutex_lock(&be->hashinfo->fh_lock); + (void) mutex_lock(&be->hashinfo->fh_lock); if (--be->hashinfo->fh_refcnt == 0) _nss_files_hash_destroy(be->hashinfo); - mutex_unlock(&be->hashinfo->fh_lock); + (void) mutex_unlock(&be->hashinfo->fh_lock); } free(be); } @@ -596,10 +602,80 @@ _nss_files_constr(ops, n_ops, filename, min_bufsize, fhp) be->hashinfo = fhp; if (fhp != NULL) { - mutex_lock(&fhp->fh_lock); + (void) mutex_lock(&fhp->fh_lock); fhp->fh_refcnt++; - mutex_unlock(&fhp->fh_lock); + (void) mutex_unlock(&fhp->fh_lock); } return ((nss_backend_t *)be); } + +int +_nss_files_check_name_colon(nss_XbyY_args_t *argp, const char *line, + int linelen) +{ + const char *linep, *limit; + const char *keyp = argp->key.name; + + linep = line; + limit = line + linelen; + while (*keyp && linep < limit && *keyp == *linep) { + keyp++; + linep++; + } + return (linep < limit && *keyp == '\0' && *linep == ':'); +} + +/* + * This routine is used to parse lines of the form: + * name number aliases + * It returns 1 if the key in argp matches any one of the + * names in the line, otherwise 0 + * Used by rpc, networks, protocols + */ +int +_nss_files_check_name_aliases(nss_XbyY_args_t *argp, const char *line, + int linelen) +{ + const char *limit, *linep, *keyp; + + linep = line; + limit = line + linelen; + keyp = argp->key.name; + + /* compare name */ + while (*keyp && linep < limit && !isspace(*linep) && *keyp == *linep) { + keyp++; + linep++; + } + if (*keyp == '\0' && linep < limit && isspace(*linep)) + return (1); + /* skip remainder of the name, if any */ + while (linep < limit && !isspace(*linep)) + linep++; + /* skip the delimiting spaces */ + while (linep < limit && isspace(*linep)) + linep++; + /* compare with the aliases */ + while (linep < limit) { + /* + * 1st pass: skip number + * Other passes: skip remainder of the alias name, if any + */ + while (linep < limit && !isspace(*linep)) + linep++; + /* skip the delimiting spaces */ + while (linep < limit && isspace(*linep)) + linep++; + /* compare with the alias name */ + keyp = argp->key.name; + while (*keyp && linep < limit && !isspace(*linep) && + *keyp == *linep) { + keyp++; + linep++; + } + if (*keyp == '\0' && (linep == limit || isspace(*linep))) + return (1); + } + return (0); +} diff --git a/usr/src/lib/nsswitch/files/common/files_common.h b/usr/src/lib/nsswitch/files/common/files_common.h index 87980f8310..9f7457a033 100644 --- a/usr/src/lib/nsswitch/files/common/files_common.h +++ b/usr/src/lib/nsswitch/files/common/files_common.h @@ -45,12 +45,12 @@ extern "C" { typedef struct files_backend *files_backend_ptr_t; typedef nss_status_t (*files_backend_op_t)(files_backend_ptr_t, void *); -typedef u_int (*files_hash_func)(nss_XbyY_args_t *, int); +typedef uint_t (*files_hash_func)(nss_XbyY_args_t *, int, const char *, int); typedef struct files_hashent { struct files_hashent *h_first; struct files_hashent *h_next; - u_int h_hash; + uint_t h_hash; } files_hashent_t; typedef struct { @@ -92,7 +92,8 @@ struct files_backend { * generic work for nss_XbyY_args_t backends (calls cstr2ent etc). */ typedef nss_status_t (*files_do_all_func_t)(const char *, int, void *args); -typedef int (*files_XY_check_func)(nss_XbyY_args_t *); +typedef int (*files_XY_check_func)(nss_XbyY_args_t *, + const char *, int); #if defined(__STDC__) extern nss_backend_t *_nss_files_constr(files_backend_op_t *ops, @@ -133,6 +134,9 @@ extern nss_status_t _nss_files_XY_all(); extern nss_status_t _nss_files_XY_hash(); #endif +int _nss_files_check_name_aliases(nss_XbyY_args_t *, const char *, int); +int _nss_files_check_name_colon(nss_XbyY_args_t *, const char *, int); + #ifdef __cplusplus } #endif diff --git a/usr/src/lib/nsswitch/files/common/getauthattr.c b/usr/src/lib/nsswitch/files/common/getauthattr.c index df236111ec..bf02ce214c 100644 --- a/usr/src/lib/nsswitch/files/common/getauthattr.c +++ b/usr/src/lib/nsswitch/files/common/getauthattr.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,8 +19,8 @@ * CDDL HEADER END */ /* - * Copyright (c) 1999-2001 by Sun Microsystems, Inc. - * All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. */ #pragma ident "%Z%%M% %I% %E% SMI" @@ -35,24 +34,14 @@ * files/getauthattr.c -- * "files" backend for nsswitch "auth_attr" database */ -static int -check_name(nss_XbyY_args_t *args) -{ - authstr_t *auth = (authstr_t *)args->returnval; - const char *name = args->key.name; - - if (strcmp(auth->name, name) == 0) { - return (1); - } - return (0); -} static nss_status_t getbyname(files_backend_ptr_t be, void *a) { nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a; - return (_nss_files_XY_all(be, argp, 1, argp->key.name, check_name)); + return (_nss_files_XY_all(be, argp, 1, argp->key.name, + _nss_files_check_name_colon)); } static files_backend_op_t authattr_ops[] = { @@ -63,6 +52,7 @@ static files_backend_op_t authattr_ops[] = { getbyname }; +/*ARGSUSED*/ nss_backend_t * _nss_files_auth_attr_constr(const char *dummy1, const char *dummy2, diff --git a/usr/src/lib/nsswitch/files/common/getauuser.c b/usr/src/lib/nsswitch/files/common/getauuser.c index b47525e416..08a79e271f 100644 --- a/usr/src/lib/nsswitch/files/common/getauuser.c +++ b/usr/src/lib/nsswitch/files/common/getauuser.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,8 +19,8 @@ * CDDL HEADER END */ /* - * Copyright (c) 1999-2001 by Sun Microsystems, Inc. - * All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. */ #pragma ident "%Z%%M% %I% %E% SMI" @@ -35,24 +34,14 @@ * files/getauuser.c -- * "files" backend for nsswitch "audit_user" database */ -static int -check_name(nss_XbyY_args_t *args) -{ - au_user_str_t *au_user = (au_user_str_t *)args->returnval; - const char *name = args->key.name; - - if (strcmp(au_user->au_name, name) == 0) { - return (1); - } - return (0); -} static nss_status_t getbyname(files_backend_ptr_t be, void *a) { nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a; - return (_nss_files_XY_all(be, argp, 1, argp->key.name, check_name)); + return (_nss_files_XY_all(be, argp, 1, argp->key.name, + _nss_files_check_name_colon)); } static files_backend_op_t auuser_ops[] = { @@ -63,6 +52,7 @@ static files_backend_op_t auuser_ops[] = { getbyname }; +/*ARGSUSED*/ nss_backend_t * _nss_files_audit_user_constr(const char *dummy1, const char *dummy2, const char *dummy3) diff --git a/usr/src/lib/nsswitch/files/common/getexecattr.c b/usr/src/lib/nsswitch/files/common/getexecattr.c index 502c0112b9..ac9e50ad3a 100644 --- a/usr/src/lib/nsswitch/files/common/getexecattr.c +++ b/usr/src/lib/nsswitch/files/common/getexecattr.c @@ -52,29 +52,47 @@ extern int _readbufline(char *, int, char *, int, int *); extern char *_exec_wild_id(char *, const char *); extern void _exec_cleanup(nss_status_t, nss_XbyY_args_t *); -typedef int (*_exec_XY_check_func) (nss_XbyY_args_t *); - /* * check_match: returns 1 if matching entry found, else returns 0. */ static int -check_match(nss_XbyY_args_t *argp) +check_match(nss_XbyY_args_t *argp, const char *line, int linelen) { + const char *limit, *linep, *keyp; _priv_execattr *_priv_exec = (_priv_execattr *)(argp->key.attrp); - const char *name = _priv_exec->name; - const char *type = _priv_exec->type; - const char *id = _priv_exec->id; - const char *policy = _priv_exec->policy; - execstr_t *exec = (execstr_t *)argp->returnval; - - if ((policy && exec->policy && (strcmp(policy, exec->policy) != 0)) || - (name && exec->name && (strcmp(name, exec->name) != 0)) || - (type && exec->type && (strcmp(type, exec->type) != 0)) || - (id && exec->id && (strcmp(id, exec->id) != 0))) { - return (0); + const char *exec_field[6]; + int i; + + exec_field[0] = _priv_exec->name; /* name */ + exec_field[1] = _priv_exec->policy; /* policy */ + exec_field[2] = _priv_exec->type; /* type */ + exec_field[3] = NULL; /* res1 */ + exec_field[4] = NULL; /* res2 */ + exec_field[5] = _priv_exec->id; /* id */ + /* No need to check attr field */ + + linep = line; + limit = line + linelen; + + for (i = 0; i < 6; i++) { + keyp = exec_field[i]; + if (keyp) { + /* compare field */ + while (*keyp && linep < limit && + *linep != ':' && *keyp == *linep) { + keyp++; + linep++; + } + if (*keyp || linep == limit || *linep != ':') + return (0); + } else { + /* skip field */ + while (linep < limit && *linep != ':') + linep++; + } + linep++; } - return (1); } @@ -90,7 +108,6 @@ _exec_files_XY_all(files_backend_ptr_t be, int f_size = 0; time_t f_time = 0; static time_t read_time = 0; - char *key = NULL; char *first; char *last; static char *f_buf = NULL; @@ -169,16 +186,15 @@ _exec_files_XY_all(files_backend_ptr_t be, } res = NSS_NOTFOUND; + /*CONSTCOND*/ while (1) { int linelen = 0; - int check_stat = 0; char *instr = be->buf; linelen = _readbufline(f_buf, f_size, instr, be->minbuf, &lastlen); if (linelen < 0) { /* End of file */ - argp->erange = 0; break; } @@ -235,26 +251,25 @@ _exec_files_XY_all(files_backend_ptr_t be, if (first != instr) instr = first; - /* - * Parse the entry. - */ + /* Check the entry */ argp->returnval = NULL; + argp->returnlen = 0; + if (check_match(argp, instr, linelen) == 0) + continue; + + /* Marshall the data */ parse_stat = (*argp->str2ent)(instr, linelen, argp->buf.result, argp->buf.buffer, argp->buf.buflen); if (parse_stat == NSS_STR_PARSE_SUCCESS) { - argp->returnval = argp->buf.result; - if (check_match(argp)) { - res = NSS_SUCCESS; - if (_priv_exec->search_flag == GET_ONE) { - break; - } else if (_doexeclist(argp) == 0) { - res = NSS_UNAVAIL; - break; - } - } else { - argp->returnval = NULL; - memset(argp->buf.buffer, NULL, - argp->buf.buflen); + argp->returnval = (argp->buf.result != NULL)? + argp->buf.result : argp->buf.buffer; + argp->returnlen = linelen; + res = NSS_SUCCESS; + if (_priv_exec->search_flag == GET_ONE) { + break; + } else if (_doexeclist(argp) == 0) { + res = NSS_UNAVAIL; + break; } } else if (parse_stat == NSS_STR_PARSE_ERANGE) { argp->erange = 1; @@ -276,13 +291,13 @@ _exec_files_XY_all(files_backend_ptr_t be, static nss_status_t get_wild(files_backend_ptr_t be, nss_XbyY_args_t *argp, int getby_flag) { - char *orig_id = NULL; + const char *orig_id = NULL; char *old_id = NULL; char *wild_id = NULL; nss_status_t res = NSS_NOTFOUND; _priv_execattr *_priv_exec = (_priv_execattr *)(argp->key.attrp); - orig_id = strdup(_priv_exec->id); + orig_id = _priv_exec->id; old_id = strdup(_priv_exec->id); wild_id = old_id; while ((wild_id = _exec_wild_id(wild_id, _priv_exec->type)) != NULL) { @@ -318,6 +333,7 @@ getbyid(files_backend_ptr_t be, void *a) { nss_status_t res; nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a; + /*LINTED*/ _priv_execattr *_priv_exec = (_priv_execattr *)(argp->key.attrp); res = _exec_files_XY_all(be, argp, NSS_DBOP_EXECATTR_BYID); @@ -336,6 +352,7 @@ getbynameid(files_backend_ptr_t be, void *a) { nss_status_t res; nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a; + /*LINTED*/ _priv_execattr *_priv_exec = (_priv_execattr *)(argp->key.attrp); res = _exec_files_XY_all(be, argp, NSS_DBOP_EXECATTR_BYNAMEID); @@ -359,6 +376,7 @@ static files_backend_op_t execattr_ops[] = { getbynameid }; +/*ARGSUSED*/ nss_backend_t * _nss_files_exec_attr_constr(const char *dummy1, const char *dummy2, diff --git a/usr/src/lib/nsswitch/files/common/getgrent.c b/usr/src/lib/nsswitch/files/common/getgrent.c index 82bc1989df..6f45136f16 100644 --- a/usr/src/lib/nsswitch/files/common/getgrent.c +++ b/usr/src/lib/nsswitch/files/common/getgrent.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,37 +19,71 @@ * CDDL HEADER END */ /* - * Copyright (c) 1988-1995 Sun Microsystems Inc - * All Rights Reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. * - * files/getgrent.c -- "files" backend for nsswitch "group" database + * files/getgrent.c -- "files" backend for nsswitch "group" database */ #pragma ident "%Z%%M% %I% %E% SMI" #include <grp.h> #include <unistd.h> /* for GF_PATH */ +#include <stdlib.h> /* for GF_PATH */ #include "files_common.h" #include <strings.h> -static u_int -hash_grname(nss_XbyY_args_t *argp, int keyhash) +static uint_t +hash_grname(nss_XbyY_args_t *argp, int keyhash, const char *line, + int linelen) { - struct group *g = argp->returnval; - const char *name = keyhash ? argp->key.name : g->gr_name; - u_int hash = 0; - - while (*name != 0) - hash = hash * 15 + *name++; - + const char *name; + int namelen, i; + uint_t hash = 0; + + if (keyhash) { + name = argp->key.name; + namelen = strlen(name); + } else { + name = line; + namelen = 0; + while (linelen-- && *line++ != ':') + namelen++; + } + + for (i = 0; i < namelen; i++) + hash = hash * 15 + name[i]; return (hash); } -static u_int -hash_grgid(nss_XbyY_args_t *argp, int keyhash) +static uint_t +hash_grgid(nss_XbyY_args_t *argp, int keyhash, const char *line, + int linelen) { - struct group *g = argp->returnval; - return (keyhash ? (u_int)argp->key.gid : (u_int)g->gr_gid); + uint_t id; + const char *linep, *limit, *end; + + linep = line; + limit = line + linelen; + + if (keyhash) + return ((uint_t)argp->key.gid); + + /* skip groupname */ + while (linep < limit && *linep++ != ':'); + /* skip password */ + while (linep < limit && *linep++ != ':'); + if (linep == limit) + return (GID_NOBODY); + + /* gid */ + end = linep; + id = (uint_t)strtol(linep, (char **)&end, 10); + /* empty gid */ + if (linep == end) + return (GID_NOBODY); + + return (id); } static files_hash_func hash_gr[2] = { hash_grname, hash_grgid }; @@ -64,15 +97,22 @@ static files_hash_t hashinfo = { }; static int -check_grname(argp) - nss_XbyY_args_t *argp; +check_grname(nss_XbyY_args_t *argp, const char *line, int linelen) { - struct group *g = (struct group *)argp->returnval; + const char *linep, *limit; + const char *keyp = argp->key.name; + + linep = line; + limit = line + linelen; - /* +/- entries only valid in compat source */ - if (g->gr_name != 0 && (g->gr_name[0] == '+' || g->gr_name[0] == '-')) + /* +/- entries valid for compat source only */ + if (linelen == 0 || *line == '+' || *line == '-') return (0); - return (strcmp(g->gr_name, argp->key.name) == 0); + while (*keyp && linep < limit && *keyp == *linep) { + keyp++; + linep++; + } + return (linep < limit && *keyp == '\0' && *linep == ':'); } static nss_status_t @@ -84,15 +124,34 @@ getbyname(be, a) } static int -check_grgid(argp) - nss_XbyY_args_t *argp; +check_grgid(nss_XbyY_args_t *argp, const char *line, int linelen) { - struct group *g = (struct group *)argp->returnval; + const char *linep, *limit, *end; + gid_t gr_gid; + + linep = line; + limit = line + linelen; + + /* +/- entries valid for compat source only */ + if (linelen == 0 || *line == '+' || *line == '-') + return (0); - /* +/- entries only valid in compat source */ - if (g->gr_name != 0 && (g->gr_name[0] == '+' || g->gr_name[0] == '-')) + /* skip username */ + while (linep < limit && *linep++ != ':'); + /* skip password */ + while (linep < limit && *linep++ != ':'); + if (linep == limit) return (0); - return (g->gr_gid == argp->key.gid); + + /* uid */ + end = linep; + gr_gid = (gid_t)strtol(linep, (char **)&end, 10); + + /* empty gid is not valid */ + if (linep == end) + return (0); + + return (gr_gid == argp->key.gid); } static nss_status_t @@ -108,7 +167,7 @@ getbymember(be, a) files_backend_ptr_t be; void *a; { - struct nss_groupsbymem *argp = (struct nss_groupsbymem *) a; + struct nss_groupsbymem *argp = (struct nss_groupsbymem *)a; return (_nss_files_do_all(be, argp, argp->username, (files_do_all_func_t)argp->process_cstr)); diff --git a/usr/src/lib/nsswitch/files/common/gethostent.c b/usr/src/lib/nsswitch/files/common/gethostent.c index 24dd4550c1..7012cbc856 100644 --- a/usr/src/lib/nsswitch/files/common/gethostent.c +++ b/usr/src/lib/nsswitch/files/common/gethostent.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * * files/gethostent.c -- "files" backend for nsswitch "hosts" database @@ -38,33 +37,84 @@ #include <sys/socket.h> #include <netinet/in.h> #include <arpa/nameser.h> +#include <arpa/inet.h> #include <ctype.h> -static int check_name(); +static int check_name(nss_XbyY_args_t *, const char *, int, + int, const char **, int *, void *, int *); static char *do_aliases(); -static char *strcasestr(); +static char *strcasestr(const char *as1, const char *as2); nss_status_t __nss_files_XY_hostbyname(); int __nss_files_2herrno(); +static int __nss_files_get_addr(int, const char *, int, + void *, int, int *); static int -check_name(host, args) - struct hostent *host; - nss_XbyY_args_t *args; +check_name(nss_XbyY_args_t *argp, const char *line, int linelen, + int type, const char **namep, int *namelen, + void *addrp, int *addrsize) { - const char *name = args->key.name; - char **aliasp; - - if (!host->h_name) - return (0); - if (strcasecmp(host->h_name, name) == 0) { - return (1); + const char *limit, *linep, *keyp, *addrstart; + int v6flag = 0, addrlen; + + linep = line; + limit = line + linelen; + + /* Address */ + addrstart = linep; + while (linep < limit && !isspace(*linep)) { + if (*linep == ':') + v6flag++; + linep++; } - for (aliasp = host->h_aliases; *aliasp != 0; aliasp++) { - if (strcasecmp(*aliasp, name) == 0) { + addrlen = linep - addrstart; + + /* skip the delimiting spaces */ + while (linep < limit && isspace(*linep)) + linep++; + + /* Canonical name */ + keyp = argp->key.name; + *namep = linep; + while (*keyp && linep < limit && !isspace(*linep) && + tolower(*keyp) == tolower(*linep)) { + keyp++; + linep++; + } + if (*keyp == '\0' && (linep == limit || isspace(*linep))) { + if (__nss_files_get_addr(type, addrstart, addrlen, + addrp, v6flag, addrsize)) { + *namelen = linep - *namep; return (1); } } + while (linep < limit && !isspace(*linep)) + linep++; + *namelen = linep - *namep; + + /* Aliases */ + while (linep < limit) { + /* skip the delimiting spaces */ + while (linep < limit && isspace(*linep)) + linep++; + + /* compare name (case insensitive) */ + keyp = argp->key.name; + while (*keyp && linep < limit && !isspace(*linep) && + tolower(*keyp) == tolower(*linep)) { + keyp++; + linep++; + } + if (*keyp == '\0' && (linep == limit || isspace(*linep))) + return (__nss_files_get_addr(type, addrstart, addrlen, + addrp, v6flag, addrsize)); + + /* skip remainder of alias, if any */ + while (linep < limit && !isspace(*linep)) + linep++; + } return (0); + } static nss_status_t @@ -81,22 +131,87 @@ getbyname(be, a) return (res); } +static int +__nss_files_get_addr(int af, const char *addrstart, int addrlen, + void *addrp, int v6flag, int *h_length) +{ + struct in_addr addr_ipv4; + struct in6_addr *addrpv6; + in_addr_t *addrpv4; + char addrbuf[INET6_ADDRSTRLEN + 1]; + + if (addrlen >= sizeof (addrbuf)) + return (0); + (void) memcpy(addrbuf, addrstart, addrlen); + addrbuf[addrlen] = '\0'; + + if (af == AF_INET) { + addrpv4 = (in_addr_t *)addrp; + if ((*addrpv4 = inet_addr(addrbuf)) == 0xffffffffU) + return (0); + *h_length = sizeof (in_addr_t); + } else if (af == AF_INET6) { + addrpv6 = (struct in6_addr *)addrp; + if (v6flag) { + if (inet_pton(af, addrbuf, addrpv6) != 1) + return (0); + } else { + if ((addr_ipv4.s_addr = inet_addr(addrbuf)) == + 0xffffffffU) + return (0); + IN6_INADDR_TO_V4MAPPED(&addr_ipv4, addrpv6); + } + *h_length = sizeof (struct in6_addr); + } else { + return (0); + } + return (1); +} + int -__nss_files_check_addr(argp) - nss_XbyY_args_t *argp; +__nss_files_check_addr(int af, nss_XbyY_args_t *argp, const char *line, + int linelen) { - struct hostent *host = (struct hostent *)argp->returnval; + const char *limit, *linep, *addrstart; + int v6flag = 0, addrlen, h_length; + in_addr_t addr_ipv4; + struct in6_addr addr_ipv6; + char *h_addrp; + + /* Compare the address type */ + if (argp->key.hostaddr.type != af) + return (0); - /* - * We know that /etc/hosts can only store one address per host, so... - */ - return (host->h_length == argp->key.hostaddr.len && - host->h_addrtype == argp->key.hostaddr.type && - memcmp(host->h_addr_list[0], argp->key.hostaddr.addr, + /* Retrieve the address */ + if (af == AF_INET) + h_addrp = (char *)&addr_ipv4; + else + h_addrp = (char *)&addr_ipv6; + linep = line; + limit = line + linelen; + addrstart = linep; + while (linep < limit && !isspace(*linep)) { + if (*linep == ':') + v6flag++; + linep++; + } + addrlen = linep - addrstart; + if (__nss_files_get_addr(af, addrstart, addrlen, h_addrp, + v6flag, &h_length) == 0) + return (0); + + /* Compare the address */ + return (h_length == argp->key.hostaddr.len && + memcmp(h_addrp, argp->key.hostaddr.addr, argp->key.hostaddr.len) == 0); } +static int +check_addr(nss_XbyY_args_t *argp, const char *line, int linelen) +{ + return (__nss_files_check_addr(AF_INET, argp, line, linelen)); +} static nss_status_t getbyaddr(be, a) @@ -106,7 +221,7 @@ getbyaddr(be, a) nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a; nss_status_t res; - res = _nss_files_XY_all(be, argp, 1, 0, __nss_files_check_addr); + res = _nss_files_XY_all(be, argp, 1, 0, check_addr); if (res != NSS_SUCCESS) argp->h_errno = __nss_files_2herrno(res); return (res); @@ -146,20 +261,21 @@ __nss_files_XY_hostbyname(be, args, filter, type) const char *filter; /* hint for name string */ int type; { - nss_status_t res; - int parsestat; - char *first; - char *last; - int i, nhosts = 0; - struct hostent he, *hp, *thp; - in_addr_t taddr[MAXADDRS]; - struct in6_addr taddr6[MAXADDRS]; - char *abuf = 0; /* alias buffer */ - char *abuf_start = 0, *abuf_end; - int (*func)(); - - if (be->buf == 0 && - (be->buf = malloc(be->minbuf)) == 0) { + nss_status_t res; + char *abuf = NULL, *abuf_start = NULL, *abuf_end; + char *first, *last, *buffer; + int parsestat, i, nhosts = 0, buflen; + const char *namep; + char *h_name; + int h_namelen, namelen; + struct hostent *hp; + in_addr_t *taddr = NULL; + struct in6_addr *taddr6 = NULL; + size_t ntaddr; + void *addrp; + char *alias_end = NULL; + + if (be->buf == 0 && (be->buf = malloc(be->minbuf)) == 0) { return (NSS_UNAVAIL); } @@ -168,10 +284,25 @@ __nss_files_XY_hostbyname(be, args, filter, type) return (res); } + ntaddr = MAXADDRS; + if (type == AF_INET) { + taddr = (in_addr_t *)calloc(ntaddr, sizeof (*taddr)); + if (taddr == NULL) + return (NSS_UNAVAIL); + } else { + taddr6 = (struct in6_addr *)calloc(ntaddr, sizeof (*taddr6)); + if (taddr6 == NULL) + return (NSS_UNAVAIL); + } + res = NSS_NOTFOUND; - args->erange = 0; args->returnval = (char *)0; - hp = thp = (struct hostent *)args->buf.result; + args->returnlen = 0; + hp = (struct hostent *)args->buf.result; + buffer = args->buf.buffer; + buflen = args->buf.buflen; + h_namelen = 0; + h_name = NULL; for (;;) { char *instr = be->buf; @@ -207,83 +338,189 @@ __nss_files_XY_hostbyname(be, args, filter, type) if (first != instr) instr = first; - if (nhosts && strcasestr(instr, hp->h_name) == 0) { - break; - } - /* - * If we've already matched once and have a possible match - * on this line, copy the aliases where they're safe from - * being overwritten when we look at the next entry. They're - * saved as a string of blank separated names for the alias - * parser. On errors, we return failure whether or not we - * have already obtained a valid address. - */ - if (nhosts == 1 && !abuf) { - abuf = malloc(args->buf.buflen); - if (abuf == NULL) { - res = NSS_UNAVAIL; - break; - } - abuf_start = &abuf[0]; - abuf_end = abuf_start + args->buf.buflen; - if (abuf + strlen(hp->h_name) + 1 > abuf_end) { - free(abuf_start); - abuf = NULL; - args->erange = 1; - res = NSS_NOTFOUND; - break; - } - (void) strcpy(abuf, hp->h_name); - abuf += strlen(hp->h_name); - *abuf++ = ' '; - abuf = do_aliases(hp, abuf, abuf_start, abuf_end); - if (abuf == NULL) { - args->erange = 1; - res = NSS_NOTFOUND; - break; - } - } - func = args->str2ent; - parsestat = (*func)(instr, linelen, thp, - args->buf.buffer, args->buf.buflen); - - if (parsestat != NSS_STR_PARSE_SUCCESS) { - if (parsestat == NSS_STR_PARSE_ERANGE) - args->erange = 1; + /* Bail out if the canonical name does not match */ + if (nhosts && strcasestr(instr, h_name) == 0) { continue; } /* * Still need to check, strcasestr() above is just a hint. */ + addrp = (type == AF_INET)? + (void *)&taddr[nhosts]: + (void *)&taddr6[nhosts]; + + if (check_name(args, instr, linelen, + type, &namep, &namelen, + addrp, &i)) { - if (type == thp->h_addrtype) - if (check_name(thp, args)) { - if (type == AF_INET) - taddr[nhosts++] = - (*(in_addr_t *)thp->h_addr_list[0]); - else { - memcpy(&taddr6[nhosts++], thp->h_addr_list[0], - sizeof (struct in6_addr)); + /* + * If we've already matched once and have a possible + * match on this line, copy the aliases where they're + * safe from being overwritten when we look at the + * next entry. They're saved as a string of blank + * separated names for the alias parser. On errors, + * we return failure whether or not we have already + * obtained a valid address. + */ + if (nhosts == 1 && hp) { + if (h_namelen + 1 > args->buf.buflen) { + args->erange = 1; + res = NSS_NOTFOUND; + break; + } + abuf = (char *)malloc(args->buf.buflen); + if (abuf == NULL) { + res = NSS_UNAVAIL; + break; + } + abuf_start = abuf; + abuf_end = abuf_start + args->buf.buflen; + (void) memcpy(abuf, h_name, h_namelen); + abuf += h_namelen; + *abuf = '\0'; + abuf = do_aliases(hp, abuf, abuf_end); + if (abuf == NULL) { + args->erange = 1; + res = NSS_NOTFOUND; + break; + } } + if (hp != NULL) { + /* inside the application */ + parsestat = (*args->str2ent)(instr, linelen, + hp, buffer, buflen); + if (parsestat != NSS_STR_PARSE_SUCCESS) { + if (parsestat == NSS_STR_PARSE_ERANGE) + args->erange = 1; + (void) memset(buffer, 0, buflen); + continue; + } + } else { + /* inside nscd */ + int alen, cplen, erange = 0; + char *ap; + + /* Add alias to the first line if any */ + if (nhosts > 0) { + + /* get to the start of alias */ + ap = (char *)namep + namelen; + /* see if there's any alias */ + if (ap == instr + linelen) + alen = 0; + else + alen = linelen - (ap - instr); + if (alen + 1 >= buflen) + erange = 1; + if (erange == 0 && alen != 0) { + /* make room for the alias */ + if (alias_end != NULL) + (void) memmove(alias_end + + alen, alias_end, buffer - + alias_end); + /* copy in the alias */ + (void) memmove(alias_end, + ap, alen); + buffer += alen; + buflen -= alen; + alias_end += alen; + } + + /* Add delimiter to the buffer */ + *buffer++ = '\n'; + buflen--; + args->returnlen++; + } + + /* copy just the addr if not first one */ + if (alias_end == NULL) + cplen = linelen; + else + cplen = namep - instr; + + if (cplen >= buflen || erange == 1) { + args->erange = 1; + if (nhosts > 0) { + *(--buffer) = '\0'; + buflen++; + args->returnlen--; + } + continue; + } + + (void) memcpy(buffer, instr, cplen); + /* Adjust buffer */ + buffer += cplen; + *buffer = '\0'; + buflen -= cplen; + if (alias_end == NULL) + alias_end = buffer; + } + + args->returnlen += linelen; - if (nhosts == 1) { + /* + * If this is the first one, save the canonical + * name for future matches and continue. + */ + if (++nhosts == 1) { + h_name = malloc(namelen + 1); + if (h_name == NULL) { + res = NSS_UNAVAIL; + break; + } res = NSS_SUCCESS; - args->returnval = args->buf.result; - thp = &he; /* switch to tmp hostent */ + (void) memcpy(h_name, namep, namelen); + h_name[namelen] = '\0'; + h_namelen = namelen; + if (hp) + args->returnval = hp; + else + args->returnval = args->buf.buffer; continue; } - if (nhosts >= MAXADDRS) - break; - abuf = do_aliases(thp, abuf, abuf_start, abuf_end); - if (abuf == NULL) { - args->erange = 1; - res = NSS_NOTFOUND; - break; + + + /* Extend the array */ + if (nhosts >= ntaddr) { + ntaddr *= 2; + if (type == AF_INET) { + addrp = realloc(taddr, + sizeof (*taddr) * ntaddr); + if (addrp == NULL) { + res = NSS_UNAVAIL; + break; + } + taddr = (in_addr_t *)addrp; + } else { + addrp = realloc(taddr6, + sizeof (*taddr6) * ntaddr); + if (addrp == NULL) { + res = NSS_UNAVAIL; + break; + } + taddr6 = (struct in6_addr *)addrp; + } + } + + /* + * For non-nscd, save aliases in a temporary buffer + * Don't have to do this for nscd as 'buffer' already + * contains the required data in the appropriate + * format + */ + if (hp) { + abuf = do_aliases(hp, abuf, abuf_end); + if (abuf == NULL) { + args->erange = 1; + res = NSS_NOTFOUND; + break; + } } - } else if (abuf && - strcasecmp(hp->h_name, thp->h_name) == 0) { + } else if (namep && h_namelen == namelen && + strncasecmp(h_name, namep, namelen) == 0) { /* * This line didn't have the requested name but * is part of the same multihomed host (i.e. it @@ -296,7 +533,10 @@ __nss_files_XY_hostbyname(be, args, filter, type) } } - if (abuf) { + if (abuf && res == NSS_SUCCESS) { + + /* abuf != NULL implies hp and abuf_start != NULL */ + struct in_addr *addrp; struct in6_addr *addrp6; @@ -318,8 +558,8 @@ __nss_files_XY_hostbyname(be, args, filter, type) ((nhosts + 1) * sizeof (char *) + (nhosts * sizeof (*addrp6))), sizeof (char *))); for (i = 0, --addrp6; i < nhosts; i++, --addrp6) { - memcpy(addrp6, &taddr6[i], - sizeof (struct in6_addr)); + (void) memcpy(addrp6, &taddr6[i], + sizeof (struct in6_addr)); hp->h_addr_list[i] = (char *)addrp6; } } @@ -330,12 +570,11 @@ __nss_files_XY_hostbyname(be, args, filter, type) (char *)hp->h_addr_list - args->buf.buffer); if (hp->h_aliases == 0) { args->erange = 1; - res = NSS_STR_PARSE_ERANGE; + res = NSS_NOTFOUND; } else { hp->h_name = hp->h_aliases[0]; hp->h_aliases++; } - free(abuf_start); } /* @@ -345,6 +584,15 @@ __nss_files_XY_hostbyname(be, args, filter, type) if (!args->stayopen) (void) _nss_files_endent(be, 0); + if (taddr) + free(taddr); + if (taddr6) + free(taddr6); + if (h_name) + free(h_name); + if (abuf_start) + free(abuf_start); + return (res); } @@ -352,13 +600,11 @@ __nss_files_XY_hostbyname(be, args, filter, type) * A case-insensitive version of strstr(). */ static char * -strcasestr(as1, as2) - char *as1; - char *as2; +strcasestr(const char *as1, const char *as2) { int c2; - register char *tptr; - register char *s1, *s2; + register const char *tptr; + register const char *s1, *s2; s1 = as1; s2 = as2; @@ -383,25 +629,22 @@ strcasestr(as1, as2) static char * -do_aliases(hp, abuf, start, end) - struct hostent *hp; - char *abuf; - char *start; - char *end; +do_aliases(struct hostent *hp, char *abuf, char *end) { - char **cp; + char **cp; + size_t len; - for (cp = hp->h_aliases; cp && *cp && **cp; cp++) { - size_t len; + if ((cp = hp->h_aliases) == NULL) + return (abuf); + for (; *cp; cp++) { len = strlen(*cp); if (abuf+len+1 >= end) { - free(start); - return ((char *)0); + return (NULL); } - (void) strcpy(abuf, *cp); - abuf += len; *abuf++ = ' '; + (void) memcpy(abuf, *cp, len); + abuf += len; } *abuf = '\0'; diff --git a/usr/src/lib/nsswitch/files/common/gethostent6.c b/usr/src/lib/nsswitch/files/common/gethostent6.c index 22d8703848..a47f1b5f45 100644 --- a/usr/src/lib/nsswitch/files/common/gethostent6.c +++ b/usr/src/lib/nsswitch/files/common/gethostent6.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,10 +19,10 @@ * CDDL HEADER END */ /* - * Copyright 1988-1995, 2003 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * - * files/gethostent6.c -- "files" backend for nsswitch "hosts" database + * files/gethostent6.c -- "files" backend for nsswitch "hosts" database */ #pragma ident "%Z%%M% %I% %E% SMI" @@ -42,8 +41,7 @@ extern nss_status_t __nss_files_XY_hostbyname(); extern int __nss_files_2herrno(); -extern int __nss_files_check_addr(nss_XbyY_args_t *); - +extern int __nss_files_check_addr(int, nss_XbyY_args_t *, const char *, int); static nss_status_t getbyname(be, a) @@ -60,7 +58,11 @@ getbyname(be, a) return (res); } - +static int +check_addr(nss_XbyY_args_t *argp, const char *line, int linelen) +{ + return (__nss_files_check_addr(AF_INET6, argp, line, linelen)); +} static nss_status_t getbyaddr(be, a) @@ -71,13 +73,12 @@ getbyaddr(be, a) nss_status_t res; - res = _nss_files_XY_all(be, argp, 1, 0, __nss_files_check_addr); + res = _nss_files_XY_all(be, argp, 1, 0, check_addr); if (res != NSS_SUCCESS) argp->h_errno = __nss_files_2herrno(res); return (res); } - static files_backend_op_t ipnodes_ops[] = { _nss_files_destr, _nss_files_endent, diff --git a/usr/src/lib/nsswitch/files/common/getnetent.c b/usr/src/lib/nsswitch/files/common/getnetent.c index 992f19326c..d47b78d324 100644 --- a/usr/src/lib/nsswitch/files/common/getnetent.c +++ b/usr/src/lib/nsswitch/files/common/getnetent.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,55 +19,70 @@ * CDDL HEADER END */ /* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. * - * Copyright (c) 1988-1995 Sun Microsystems Inc - * All Rights Reserved. - * - * files/getnetent.c -- "files" backend for nsswitch "networks" database + * files/getnetent.c -- "files" backend for nsswitch "networks" database */ #pragma ident "%Z%%M% %I% %E% SMI" +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> #include <netdb.h> #include "files_common.h" #include <strings.h> - -static int -check_name(args) - nss_XbyY_args_t *args; -{ - struct netent *net = (struct netent *)args->returnval; - const char *name = args->key.name; - char **aliasp; - - if (strcmp(net->n_name, name) == 0) - return (1); - for (aliasp = net->n_aliases; *aliasp != 0; aliasp++) { - if (strcmp(*aliasp, name) == 0) - return (1); - } - return (0); -} +#include <ctype.h> static nss_status_t getbyname(be, a) files_backend_ptr_t be; void *a; { - nss_XbyY_args_t *argp = (nss_XbyY_args_t *) a; + nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a; - return (_nss_files_XY_all(be, argp, 1, argp->key.name, check_name)); + return (_nss_files_XY_all(be, argp, 1, argp->key.name, + _nss_files_check_name_aliases)); } static int -check_addr(args) - nss_XbyY_args_t *args; +check_addr(nss_XbyY_args_t *argp, const char *line, int linelen) { - struct netent *net = (struct netent *)args->returnval; - return ((net->n_addrtype == args->key.netaddr.type) && - (net->n_net == args->key.netaddr.net)); + const char *limit, *linep, *addrstart; + int addrlen; + char addrbuf[NSS_LINELEN_NETWORKS]; + in_addr_t linenet; + + linep = line; + limit = line + linelen; + + /* skip network name */ + while (linep < limit && !isspace(*linep)) + linep++; + /* skip the delimiting spaces */ + while (linep < limit && isspace(*linep)) + linep++; + if (linep == limit) + return (0); + + addrstart = linep; + while (linep < limit && !isspace(*linep)) + linep++; + addrlen = linep - addrstart; + if (addrlen < sizeof (addrbuf)) { + (void) memcpy(addrbuf, addrstart, addrlen); + addrbuf[addrlen] = '\0'; + if ((linenet = inet_network(addrbuf)) == + (in_addr_t)0xffffffffU) + return (0); + return (AF_INET == argp->key.netaddr.type && + linenet == argp->key.netaddr.net); + } + return (0); } static nss_status_t @@ -76,7 +90,7 @@ getbyaddr(be, a) files_backend_ptr_t be; void *a; { - nss_XbyY_args_t *argp = (nss_XbyY_args_t *) a; + nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a; return (_nss_files_XY_all(be, argp, 1, 0, check_addr)); } diff --git a/usr/src/lib/nsswitch/files/common/getprinter.c b/usr/src/lib/nsswitch/files/common/getprinter.c index c41771f8d2..8f5fab855b 100644 --- a/usr/src/lib/nsswitch/files/common/getprinter.c +++ b/usr/src/lib/nsswitch/files/common/getprinter.c @@ -36,140 +36,63 @@ static const char *printers = "/etc/printers.conf"; #include <stdlib.h> #include <strings.h> -static nss_status_t _nss_files_XY_printers(files_backend_ptr_t, - nss_XbyY_args_t *, const char *); - - -static nss_status_t -getent(be, a) - files_backend_ptr_t be; - void *a; +static int +check_name(nss_XbyY_args_t *argp, const char *line, int linelen) { - nss_XbyY_args_t *args = (nss_XbyY_args_t *)a; - return (_nss_files_XY_all(be, args, 0, 0, 0)); + const char *limit, *linep; + const char *keyp = argp->key.name; + int klen = strlen(keyp); + + linep = line; + limit = line + linelen; + + /* + * find the name in the namelist a|b|c...: + */ + while (linep+klen < limit && *linep != '|' && *linep != ':') { + if ((strncmp(linep, keyp, klen) == 0) && + ((*(linep + klen) == '|') || (*(linep + klen) == ':'))) { + return (1); + } else { + while (linep < limit && *linep != '|' && *linep != ':') + linep++; + if (linep >= limit || *linep == ':') + return (0); + if (*linep == '|') + linep++; + } + } + return (0); } - static nss_status_t getbyname(be, a) files_backend_ptr_t be; void *a; { nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a; - nss_status_t res; - /* printers_getbyname() has not set/endent; rewind on each call */ - if ((res = _nss_files_setent(be, 0)) != NSS_SUCCESS) { - return (res); - } - return (_nss_files_XY_printers(be, argp, argp->key.name)); + return (_nss_files_XY_all(be, argp, 1, argp->key.name, + check_name)); } static files_backend_op_t printers_ops[] = { _nss_files_destr, _nss_files_endent, _nss_files_setent, - getent, + _nss_files_getent_rigid, getbyname }; +/*ARGSUSED*/ nss_backend_t * _nss_files_printers_constr(dummy1, dummy2, dummy3) const char *dummy1, *dummy2, *dummy3; { return (_nss_files_constr(printers_ops, - sizeof (printers_ops) / sizeof (printers_ops[0]), - printers, - NSS_LINELEN_PRINTERS, - NULL)); -} - -/* - * printers has the hostname as part of the data in the file, but the other - * backends don't include it in the data passed to the backend. For this - * reason, we process everything here and don't bother calling the backend. - */ -static nss_status_t -_nss_files_XY_printers(be, args, filter) - files_backend_ptr_t be; - nss_XbyY_args_t *args; - const char *filter; - /* - * filter not useful here since the key - * we are looking for is the first "word" - * on the line and we can be fast enough. - */ -{ - nss_status_t res; - int parsestat; - int namelen; - - if (be->buf == 0 && - (be->buf = (char *)malloc(be->minbuf)) == 0) { - (void) _nss_files_endent(be, 0); - return (NSS_UNAVAIL); /* really panic, malloc failed */ - } - - res = NSS_NOTFOUND; - namelen = strlen(args->key.name); - - while (1) { - char *instr = be->buf; - char *p, *limit; - int linelen; - int found = 0; - - /* - * _nss_files_read_line does process the '\' that are used - * in /etc/printers.conf for continuation and gives one long - * buffer. - * - * linelen counts the characters up to but excluding the '\n' - */ - if ((linelen = _nss_files_read_line(be->f, instr, - be->minbuf)) < 0) { - /* End of file */ - args->returnval = 0; - args->erange = 0; - break; - } - p = instr; - - if (*p == '#') /* comment */ - continue; - - /* - * find the name in the namelist a|b|c...: - */ - if ((limit = strchr(instr, ':')) == NULL) /* bad line */ - continue; - while ((p < limit) && (found == 0)) { - if ((strncmp(p, args->key.name, namelen) == 0) && - ((*(p+namelen) == '|') || (*(p+namelen) == ':'))) - found++; - else { - if ((p = strchr(p, '|')) == NULL) - p = limit; - else /* skip the '|' */ - p++; - } - } - if (found == 0) - continue; - - p = instr; - - if (args->buf.buflen <= linelen) { /* not enough buffer */ - args->erange = 1; - break; - } - (void) memcpy(args->buf.buffer, p, linelen); - args->buf.buffer[linelen] = '\0'; - args->returnval = args->buf.result; - res = NSS_SUCCESS; - break; - } - (void) _nss_files_endent(be, 0); - return (res); + sizeof (printers_ops) / sizeof (printers_ops[0]), + printers, + NSS_LINELEN_PRINTERS, + NULL)); } diff --git a/usr/src/lib/nsswitch/files/common/getprofattr.c b/usr/src/lib/nsswitch/files/common/getprofattr.c index 67c49369b0..83d4369eaa 100644 --- a/usr/src/lib/nsswitch/files/common/getprofattr.c +++ b/usr/src/lib/nsswitch/files/common/getprofattr.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,8 +19,8 @@ * CDDL HEADER END */ /* - * Copyright (c) 1999-2001 by Sun Microsystems, Inc. - * All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. */ #pragma ident "%Z%%M% %I% %E% SMI" @@ -35,24 +34,14 @@ * files/getprofattr.c -- * "files" backend for nsswitch "prof_attr" database */ -static int -check_name(nss_XbyY_args_t *args) -{ - profstr_t *prof = (profstr_t *)args->returnval; - const char *name = args->key.name; - - if (strcmp(prof->name, name) == 0) { - return (1); - } - return (0); -} static nss_status_t getbyname(files_backend_ptr_t be, void *a) { nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a; - return (_nss_files_XY_all(be, argp, 1, argp->key.name, check_name)); + return (_nss_files_XY_all(be, argp, 1, argp->key.name, + _nss_files_check_name_colon)); } static files_backend_op_t profattr_ops[] = { @@ -63,6 +52,7 @@ static files_backend_op_t profattr_ops[] = { getbyname }; +/*ARGSUSED*/ nss_backend_t * _nss_files_prof_attr_constr(const char *dummy1, const char *dummy2, diff --git a/usr/src/lib/nsswitch/files/common/getprojent.c b/usr/src/lib/nsswitch/files/common/getprojent.c index cad512746c..e534760093 100644 --- a/usr/src/lib/nsswitch/files/common/getprojent.c +++ b/usr/src/lib/nsswitch/files/common/getprojent.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,8 +19,8 @@ * CDDL HEADER END */ /* - * Copyright (c) 1999-2000 by Sun Microsystems, Inc. - * All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. */ #pragma ident "%Z%%M% %I% %E% SMI" @@ -29,24 +28,57 @@ #include <sys/types.h> #include <project.h> #include <string.h> +#include <stdlib.h> #include "files_common.h" static uint_t -hash_projname(nss_XbyY_args_t *argp, int keyhash) { - struct project *p = argp->returnval; - const char *name = keyhash ? argp->key.name : p->pj_name; - uint_t hash = 0; - - while (*name != 0) - hash = hash * 15 + *name++; - +hash_projname(nss_XbyY_args_t *argp, int keyhash, const char *line, + int linelen) { + + const char *name; + int namelen, i; + uint_t hash = 0; + + if (keyhash) { + name = argp->key.name; + namelen = strlen(name); + } else { + name = line; + namelen = 0; + while (linelen-- && *line++ != ':') + namelen++; + } + + for (i = 0; i < namelen; i++) + hash = hash * 15 + name[i]; return (hash); } static uint_t -hash_projid(nss_XbyY_args_t *argp, int keyhash) { - struct project *p = argp->returnval; - return (keyhash ? (uint_t)argp->key.projid : (uint_t)p->pj_projid); +hash_projid(nss_XbyY_args_t *argp, int keyhash, const char *line, + int linelen) { + + uint_t id; + const char *linep, *limit, *end; + + linep = line; + limit = line + linelen; + + if (keyhash) + return ((uint_t)argp->key.projid); + + /* skip projname */ + while (linep < limit && *linep++ != ':'); + if (linep == limit) + return (0); + + /* projid */ + end = linep; + id = (uint_t)strtol(linep, (char **)&end, 10); + if (linep == end) + return (0); + + return (id); } static files_hash_func hash_proj[2] = { @@ -63,26 +95,35 @@ static files_hash_t hashinfo = { }; static int -check_projname(nss_XbyY_args_t *argp) { - struct project *p = argp->returnval; +check_projid(nss_XbyY_args_t *argp, const char *line, int linelen) { + projid_t projid; + const char *linep, *limit, *end; + + linep = line; + limit = line + linelen; + + /* skip projname */ + while (linep < limit && *linep++ != ':'); - if (p->pj_name == 0) + /* empty projname not allowed */ + if (linep == limit || linep == line + 1) return (0); - return (strcmp(p->pj_name, argp->key.name) == 0); -} -static int -check_projid(nss_XbyY_args_t *argp) { - struct project *p = argp->returnval; + /* projid */ + end = linep; + projid = (projid_t)strtol(linep, (char **)&end, 10); - if (p->pj_name == 0) + /* empty projid is not valid */ + if (linep == end) return (0); - return (p->pj_projid == argp->key.projid); + + return (projid == argp->key.projid); } static nss_status_t getbyname(files_backend_ptr_t be, void *a) { - return (_nss_files_XY_hash(be, a, 0, &hashinfo, 0, check_projname)); + return (_nss_files_XY_hash(be, a, 0, &hashinfo, 0, + _nss_files_check_name_colon)); } static nss_status_t diff --git a/usr/src/lib/nsswitch/files/common/getprotoent.c b/usr/src/lib/nsswitch/files/common/getprotoent.c index 25659b2e92..2f3578d13b 100644 --- a/usr/src/lib/nsswitch/files/common/getprotoent.c +++ b/usr/src/lib/nsswitch/files/common/getprotoent.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,10 +19,10 @@ * CDDL HEADER END */ /* - * Copyright (c) 1988-1995 Sun Microsystems Inc - * All Rights Reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. * - * files/getprotoent.c -- "files" backend for nsswitch "protocols" database + * files/getprotoent.c -- "files" backend for nsswitch "protocols" database */ #pragma ident "%Z%%M% %I% %E% SMI" @@ -31,41 +30,39 @@ #include <netdb.h> #include "files_common.h" #include <strings.h> - -static int -check_name(args) - nss_XbyY_args_t *args; -{ - struct protoent *proto = (struct protoent *)args->returnval; - const char *name = args->key.name; - char **aliasp; - - if (strcmp(proto->p_name, name) == 0) - return (1); - for (aliasp = proto->p_aliases; *aliasp != 0; aliasp++) { - if (strcmp(*aliasp, name) == 0) - return (1); - } - return (0); -} +#include <ctype.h> +#include <stdlib.h> static nss_status_t getbyname(be, a) files_backend_ptr_t be; void *a; { - nss_XbyY_args_t *argp = (nss_XbyY_args_t *) a; + nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a; - return (_nss_files_XY_all(be, argp, 1, argp->key.name, check_name)); + return (_nss_files_XY_all(be, argp, 1, argp->key.name, + _nss_files_check_name_aliases)); } static int -check_addr(args) - nss_XbyY_args_t *args; +check_addr(nss_XbyY_args_t *argp, const char *line, int linelen) { - struct protoent *proto = (struct protoent *)args->returnval; + int proto; + const char *limit, *linep; + + linep = line; + limit = line + linelen; - return (proto->p_proto == args->key.number); + /* skip name */ + while (linep < limit && !isspace(*linep)) + linep++; + /* skip the delimiting spaces */ + while (linep < limit && isspace(*linep)) + linep++; + if (linep == limit) + return (0); + proto = (int)strtol(linep, NULL, 10); + return (proto == argp->key.number); } static nss_status_t @@ -73,10 +70,10 @@ getbynumber(be, a) files_backend_ptr_t be; void *a; { - nss_XbyY_args_t *argp = (nss_XbyY_args_t *) a; + nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a; char numstr[12]; - sprintf(numstr, "%d", argp->key.number); + (void) snprintf(numstr, 12, "%d", argp->key.number); return (_nss_files_XY_all(be, argp, 1, 0, check_addr)); } diff --git a/usr/src/lib/nsswitch/files/common/getpwnam.c b/usr/src/lib/nsswitch/files/common/getpwnam.c index 303b8323c6..8faa2014eb 100644 --- a/usr/src/lib/nsswitch/files/common/getpwnam.c +++ b/usr/src/lib/nsswitch/files/common/getpwnam.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,10 +19,10 @@ * CDDL HEADER END */ /* - * Copyright (c) 1988-1995 Sun Microsystems Inc - * All Rights Reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. * - * files/getpwnam.c -- "files" backend for nsswitch "passwd" database + * files/getpwnam.c -- "files" backend for nsswitch "passwd" database */ #pragma ident "%Z%%M% %I% %E% SMI" @@ -33,25 +32,60 @@ #include <unistd.h> /* for PF_PATH */ #include "files_common.h" #include <strings.h> +#include <stdlib.h> -static u_int -hash_pwname(nss_XbyY_args_t *argp, int keyhash) +static uint_t +hash_pwname(nss_XbyY_args_t *argp, int keyhash, const char *line, + int linelen) { - struct passwd *p = argp->returnval; - const char *name = keyhash ? argp->key.name : p->pw_name; - u_int hash = 0; - - while (*name != 0) - hash = hash * 15 + *name++; - + const char *name; + int namelen, i; + uint_t hash = 0; + + if (keyhash) { + name = argp->key.name; + namelen = strlen(name); + } else { + name = line; + namelen = 0; + while (linelen-- && *line++ != ':') + namelen++; + } + + for (i = 0; i < namelen; i++) + hash = hash * 15 + name[i]; return (hash); } -static u_int -hash_pwuid(nss_XbyY_args_t *argp, int keyhash) +static uint_t +hash_pwuid(nss_XbyY_args_t *argp, int keyhash, const char *line, + int linelen) { - struct passwd *p = argp->returnval; - return (keyhash ? (u_int)argp->key.uid : (u_int)p->pw_uid); + uint_t id; + const char *linep, *limit, *end; + + linep = line; + limit = line + linelen; + + if (keyhash) + return ((uint_t)argp->key.uid); + + /* skip username */ + while (linep < limit && *linep++ != ':'); + /* skip password */ + while (linep < limit && *linep++ != ':'); + if (linep == limit) + return (UID_NOBODY); + + /* uid */ + end = linep; + id = (uint_t)strtol(linep, (char **)&end, 10); + + /* empty uid */ + if (linep == end) + return (UID_NOBODY); + + return (id); } static files_hash_func hash_pw[2] = { hash_pwname, hash_pwuid }; @@ -65,15 +99,22 @@ static files_hash_t hashinfo = { }; static int -check_pwname(argp) - nss_XbyY_args_t *argp; +check_pwname(nss_XbyY_args_t *argp, const char *line, int linelen) { - struct passwd *p = (struct passwd *)argp->returnval; + const char *linep, *limit; + const char *keyp = argp->key.name; + + linep = line; + limit = line + linelen; /* +/- entries valid for compat source only */ - if (p->pw_name != 0 && (p->pw_name[0] == '+' || p->pw_name[0] == '-')) + if (linelen == 0 || *line == '+' || *line == '-') return (0); - return (strcmp(p->pw_name, argp->key.name) == 0); + while (*keyp && linep < limit && *keyp == *linep) { + keyp++; + linep++; + } + return (linep < limit && *keyp == '\0' && *linep == ':'); } static nss_status_t @@ -85,15 +126,34 @@ getbyname(be, a) } static int -check_pwuid(argp) - nss_XbyY_args_t *argp; +check_pwuid(nss_XbyY_args_t *argp, const char *line, int linelen) { - struct passwd *p = (struct passwd *)argp->returnval; + const char *linep, *limit, *end; + uid_t pw_uid; + + linep = line; + limit = line + linelen; /* +/- entries valid for compat source only */ - if (p->pw_name != 0 && (p->pw_name[0] == '+' || p->pw_name[0] == '-')) + if (linelen == 0 || *line == '+' || *line == '-') + return (0); + + /* skip username */ + while (linep < limit && *linep++ != ':'); + /* skip password */ + while (linep < limit && *linep++ != ':'); + if (linep == limit) return (0); - return (p->pw_uid == argp->key.uid); + + /* uid */ + end = linep; + pw_uid = (uid_t)strtol(linep, (char **)&end, 10); + + /* empty uid is not valid */ + if (linep == end) + return (0); + + return (pw_uid == argp->key.uid); } static nss_status_t diff --git a/usr/src/lib/nsswitch/files/common/getrpcent.c b/usr/src/lib/nsswitch/files/common/getrpcent.c index 789822c63c..3732c368dd 100644 --- a/usr/src/lib/nsswitch/files/common/getrpcent.c +++ b/usr/src/lib/nsswitch/files/common/getrpcent.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,10 +19,10 @@ * CDDL HEADER END */ /* - * Copyright (c) 1988-1995 Sun Microsystems Inc - * All Rights Reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. * - * files/getrpcent.c -- "files" backend for nsswitch "rpc" database + * files/getrpcent.c -- "files" backend for nsswitch "rpc" database */ #pragma ident "%Z%%M% %I% %E% SMI" @@ -31,43 +30,39 @@ #include <rpc/rpcent.h> #include "files_common.h" #include <strings.h> - -static int -check_name(args) - nss_XbyY_args_t *args; -{ - struct rpcent *rpc = (struct rpcent *) args->returnval; - const char *name = args->key.name; - char **aliasp; - - if (strcmp(rpc->r_name, name) == 0) { - return (1); - } - for (aliasp = rpc->r_aliases; *aliasp != 0; aliasp++) { - if (strcmp(*aliasp, name) == 0) { - return (1); - } - } - return (0); -} +#include <ctype.h> +#include <stdlib.h> static nss_status_t getbyname(be, a) files_backend_ptr_t be; void *a; { - nss_XbyY_args_t *argp = (nss_XbyY_args_t *) a; + nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a; - return (_nss_files_XY_all(be, argp, 1, argp->key.name, check_name)); + return (_nss_files_XY_all(be, argp, 1, argp->key.name, + _nss_files_check_name_aliases)); } static int -check_rpcnum(argp) - nss_XbyY_args_t *argp; +check_rpcnum(nss_XbyY_args_t *argp, const char *line, int linelen) { - struct rpcent *rpc = (struct rpcent *) argp->returnval; + int r_number; + const char *limit, *linep; + + linep = line; + limit = line + linelen; - return (rpc->r_number == argp->key.number); + /* skip name */ + while (linep < limit && !isspace(*linep)) + linep++; + /* skip the delimiting spaces */ + while (linep < limit && isspace(*linep)) + linep++; + if (linep == limit) + return (0); + r_number = (int)strtol(linep, NULL, 10); + return (r_number == argp->key.number); } @@ -76,10 +71,10 @@ getbynumber(be, a) files_backend_ptr_t be; void *a; { - nss_XbyY_args_t *argp = (nss_XbyY_args_t *) a; + nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a; char numstr[12]; - sprintf(numstr, "%d", argp->key.number); + (void) snprintf(numstr, 12, "%d", argp->key.number); return (_nss_files_XY_all(be, argp, 1, numstr, check_rpcnum)); } diff --git a/usr/src/lib/nsswitch/files/common/getservent.c b/usr/src/lib/nsswitch/files/common/getservent.c index 855b543d55..32e73ea3f6 100644 --- a/usr/src/lib/nsswitch/files/common/getservent.c +++ b/usr/src/lib/nsswitch/files/common/getservent.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,10 +19,10 @@ * CDDL HEADER END */ /* - * Copyright (c) 1988-1995 Sun Microsystems Inc - * All Rights Reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. * - * files/getservent.c -- "files" backend for nsswitch "services" database + * files/getservent.c -- "files" backend for nsswitch "services" database */ #pragma ident "%Z%%M% %I% %E% SMI" @@ -32,27 +31,85 @@ #include "files_common.h" #include <sys/types.h> #include <netinet/in.h> +#include <inttypes.h> #include <strings.h> +#include <ctype.h> +#include <stdlib.h> static int -check_name(args) - nss_XbyY_args_t *args; +check_name(nss_XbyY_args_t *argp, const char *line, int linelen) { - struct servent *serv = (struct servent *) args->returnval; - const char *name = args->key.serv.serv.name; - const char *proto = args->key.serv.proto; - char **aliasp; + const char *limit, *linep, *keyp; + int name_match = 0; - if (proto != 0 && strcmp(serv->s_proto, proto) != 0) { - return (0); + linep = line; + limit = line + linelen; + keyp = argp->key.serv.serv.name; + + /* compare name */ + while (*keyp && linep < limit && !isspace(*linep) && *keyp == *linep) { + keyp++; + linep++; } - if (strcmp(serv->s_name, name) == 0) { - return (1); + if (*keyp == '\0' && linep < limit && isspace(*linep)) { + if (argp->key.serv.proto == NULL) + return (1); + else + name_match = 1; } - for (aliasp = serv->s_aliases; *aliasp != 0; aliasp++) { - if (strcmp(*aliasp, name) == 0) { + + /* skip remainder of the name, if any */ + while (linep < limit && !isspace(*linep)) + linep++; + /* skip the delimiting spaces */ + while (linep < limit && isspace(*linep)) + linep++; + /* skip port number */ + while (linep < limit && !isspace(*linep) && *linep != '/') + linep++; + if (linep == limit || *linep != '/') + return (0); + + linep++; + if ((keyp = argp->key.serv.proto) == NULL) { + /* skip protocol */ + while (linep < limit && !isspace(*linep)) + linep++; + } else { + /* compare protocol */ + while (*keyp && linep < limit && !isspace(*linep) && + *keyp == *linep) { + keyp++; + linep++; + } + /* no protocol match */ + if (*keyp || (linep < limit && !isspace(*linep))) + return (0); + /* protocol and name match, return */ + if (name_match) return (1); + /* protocol match but name yet to be matched, so continue */ + } + + /* compare with the aliases */ + while (linep < limit) { + /* skip the delimiting spaces */ + while (linep < limit && isspace(*linep)) + linep++; + + /* compare with the alias name */ + keyp = argp->key.serv.serv.name; + while (*keyp && linep < limit && !isspace(*linep) && + *keyp == *linep) { + keyp++; + linep++; } + if (*keyp == '\0' && (linep == limit || isspace(*linep))) + return (1); + + /* skip remainder of the alias name, if any */ + while (linep < limit && !isspace(*linep)) + linep++; } return (0); } @@ -62,21 +119,56 @@ getbyname(be, a) files_backend_ptr_t be; void *a; { - nss_XbyY_args_t *argp = (nss_XbyY_args_t *) a; + nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a; return (_nss_files_XY_all(be, argp, 1, argp->key.serv.serv.name, check_name)); } static int -check_port(args) - nss_XbyY_args_t *args; +check_port(nss_XbyY_args_t *argp, const char *line, int linelen) { - struct servent *serv = (struct servent *) args->returnval; - const char *proto = args->key.serv.proto; + const char *limit, *linep, *keyp, *numstart; + int numlen, s_port; + char numbuf[12], *numend; + + linep = line; + limit = line + linelen; + + /* skip name */ + while (linep < limit && !isspace(*linep)) + linep++; + /* skip the delimiting spaces */ + while (linep < limit && isspace(*linep)) + linep++; + + /* compare port num */ + numstart = linep; + while (linep < limit && !isspace(*linep) && *linep != '/') + linep++; + if (linep == limit || *linep != '/') + return (0); + numlen = linep - numstart; + if (numlen == 0 || numlen >= sizeof (numbuf)) + return (0); + (void) memcpy(numbuf, numstart, numlen); + numbuf[numlen] = '\0'; + s_port = htons((int)strtol(numbuf, &numend, 10)); + if (*numend != '\0') + return (0); + if (s_port == argp->key.serv.serv.port) { + if ((keyp = argp->key.serv.proto) == NULL) + return (1); + } else + return (0); - return (serv->s_port == args->key.serv.serv.port && - (proto == 0 || strcmp(serv->s_proto, proto) == 0)); + /* compare protocol */ + linep++; + while (*keyp && linep < limit && !isspace(*linep) && *keyp == *linep) { + keyp++; + linep++; + } + return (*keyp == '\0' && (linep == limit || isspace(*linep))); } static nss_status_t @@ -84,10 +176,10 @@ getbyport(be, a) files_backend_ptr_t be; void *a; { - nss_XbyY_args_t *argp = (nss_XbyY_args_t *) a; + nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a; char portstr[12]; - sprintf(portstr, "%d", ntohs(argp->key.serv.serv.port)); + (void) snprintf(portstr, 12, "%d", ntohs(argp->key.serv.serv.port)); return (_nss_files_XY_all(be, argp, 1, portstr, check_port)); } diff --git a/usr/src/lib/nsswitch/files/common/getspent.c b/usr/src/lib/nsswitch/files/common/getspent.c index 7287f024d2..af280b6d74 100644 --- a/usr/src/lib/nsswitch/files/common/getspent.c +++ b/usr/src/lib/nsswitch/files/common/getspent.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,10 +19,10 @@ * CDDL HEADER END */ /* - * Copyright (c) 1988-1995 Sun Microsystems Inc - * All Rights Reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. * - * files/getspent.c -- "files" backend for nsswitch "shadow" database + * files/getspent.c -- "files" backend for nsswitch "shadow" database */ #pragma ident "%Z%%M% %I% %E% SMI" @@ -33,15 +32,19 @@ #include <strings.h> static int -check_spnamp(argp) - nss_XbyY_args_t *argp; +check_spnamp(nss_XbyY_args_t *argp, const char *line, int linelen) { - struct spwd *s = (struct spwd *)argp->returnval; + const char *linep = line; + const char *keyp = argp->key.name; - /* +/- entries valid in compat source only */ - if (s->sp_namp != 0 && (s->sp_namp[0] == '+' || s->sp_namp[0] == '-')) + /* +/- entries valid for compat source only */ + if (linelen == 0 || *line == '+' || *line == '-') return (0); - return (strcmp(s->sp_namp, argp->key.name) == 0); + while (*keyp && linelen-- && *keyp == *linep) { + keyp++; + linep++; + } + return (linelen && *keyp == '\0' && *linep == ':'); } static nss_status_t @@ -49,7 +52,7 @@ getbyname(be, a) files_backend_ptr_t be; void *a; { - nss_XbyY_args_t *argp = (nss_XbyY_args_t *) a; + nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a; return (_nss_files_XY_all(be, argp, 0, argp->key.name, check_spnamp)); } diff --git a/usr/src/lib/nsswitch/files/common/getuserattr.c b/usr/src/lib/nsswitch/files/common/getuserattr.c index 82f377c5da..3ada2a420f 100644 --- a/usr/src/lib/nsswitch/files/common/getuserattr.c +++ b/usr/src/lib/nsswitch/files/common/getuserattr.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,8 +19,8 @@ * CDDL HEADER END */ /* - * Copyright (c) 1999-2001 by Sun Microsystems, Inc. - * All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. */ #pragma ident "%Z%%M% %I% %E% SMI" @@ -35,24 +34,14 @@ * files/getuserattr.c -- * "files" backend for nsswitch "user_attr" database */ -static int -check_name(nss_XbyY_args_t *args) -{ - userstr_t *user = (userstr_t *)args->returnval; - const char *name = args->key.name; - - if (strcmp(user->name, name) == 0) { - return (1); - } - return (0); -} static nss_status_t getbyname(files_backend_ptr_t be, void *a) { nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a; - return (_nss_files_XY_all(be, argp, 1, argp->key.name, check_name)); + return (_nss_files_XY_all(be, argp, 1, argp->key.name, + _nss_files_check_name_colon)); } static files_backend_op_t userattr_ops[] = { @@ -63,6 +52,7 @@ static files_backend_op_t userattr_ops[] = { getbyname }; +/*ARGSUSED*/ nss_backend_t * _nss_files_user_attr_constr(const char *dummy1, const char *dummy2, diff --git a/usr/src/lib/nsswitch/files/common/netmasks.c b/usr/src/lib/nsswitch/files/common/netmasks.c index 876fcf66a6..2fe4a2fe1b 100644 --- a/usr/src/lib/nsswitch/files/common/netmasks.c +++ b/usr/src/lib/nsswitch/files/common/netmasks.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,10 +19,10 @@ * CDDL HEADER END */ /* - * files/netmasks.c -- "files" backend for nsswitch "netmasks" database + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. * - * Copyright (c) 1996 Sun Microsystems Inc - * All Rights Reserved. + * files/netmasks.c -- "files" backend for nsswitch "netmasks" database */ #pragma ident "%Z%%M% %I% %E% SMI" @@ -43,20 +42,45 @@ #include <netinet/in.h> #include <arpa/inet.h> #include <nss_dbdefs.h> +#include <ctype.h> /* * Validate 'files' netmasks entry. The comparison objects are in IPv4 * internet address format. */ static int -check_addr(args) - nss_XbyY_args_t *args; +check_addr(nss_XbyY_args_t *argp, const char *line, int linelen) { - struct in_addr tmp; + const char *limit, *linep, *addrstart; + int addrlen; + char addrbuf[NSS_LINELEN_NETMASKS]; + struct in_addr lineaddr, argsaddr; - tmp.s_addr = inet_addr(args->key.name); - return (memcmp(args->buf.buffer, (char *)&tmp, - sizeof (struct in_addr)) == 0); + linep = line; + limit = line + linelen; + + /* skip leading spaces */ + while (linep < limit && isspace(*linep)) + linep++; + + addrstart = linep; + while (linep < limit && !isspace(*linep)) + linep++; + if (linep == limit) + return (0); + addrlen = linep - addrstart; + if (addrlen < sizeof (addrbuf)) { + (void) memcpy(addrbuf, addrstart, addrlen); + addrbuf[addrlen] = '\0'; + if ((lineaddr.s_addr = inet_addr(addrbuf)) == + (in_addr_t)0xffffffffU) + return (0); + if ((argsaddr.s_addr = inet_addr(argp->key.name)) + == (in_addr_t)0xffffffffU) + return (0); + return (lineaddr.s_addr == argsaddr.s_addr); + } + return (0); } static nss_status_t @@ -64,15 +88,46 @@ getbynet(be, a) files_backend_ptr_t be; void *a; { - nss_XbyY_args_t *argp = (nss_XbyY_args_t *) a; + nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a; nss_status_t res; char tmpbuf[NSS_LINELEN_NETMASKS]; - argp->buf.buffer = tmpbuf; - argp->buf.buflen = NSS_LINELEN_NETMASKS; + /* + * use the buffer passed in if result is to be returned + * in /etc file format + */ + if (argp->buf.result != NULL) { + argp->buf.buffer = tmpbuf; + argp->buf.buflen = NSS_LINELEN_NETMASKS; + } res = _nss_files_XY_all(be, argp, 0, argp->key.name, check_addr); - argp->buf.buffer = NULL; - argp->buf.buflen = 0; + if (argp->buf.result != NULL) { + argp->buf.buffer = NULL; + argp->buf.buflen = 0; + } else { + /* the frontend expects the netmask data only */ + if (res == NSS_SUCCESS) { + char *m; + char *s = (char *)argp->returnval; + int l = 0; + + m = s + argp->returnlen - 1; + + /* skip trailing spaces */ + while (s < m && isspace(*m)) + m--; + + for (; s <= m; m--) { + if (isspace(*m)) + break; + l++; + } + m++; + (void) memmove(argp->returnval, m, l); + argp->returnlen = l; + *(s + l) = '\0'; + } + } return (res); } diff --git a/usr/src/lib/nsswitch/files/common/tsol_getrhent.c b/usr/src/lib/nsswitch/files/common/tsol_getrhent.c index f41f606034..180a660189 100644 --- a/usr/src/lib/nsswitch/files/common/tsol_getrhent.c +++ b/usr/src/lib/nsswitch/files/common/tsol_getrhent.c @@ -28,30 +28,102 @@ #include "files_common.h" #include <string.h> #include <libtsnet.h> +#include <netinet/in.h> /* * files/tsol_getrhent.c -- * "files" backend for nsswitch "tnrhdb" database */ static int -check_addr(nss_XbyY_args_t *args) +check_addr(nss_XbyY_args_t *args, const char *line, int linelen) { - tsol_rhstr_t *rhstrp = (tsol_rhstr_t *)args->returnval; + const char *limit, *linep, *keyp; + char prev; + int ipv6; - if ((args->key.hostaddr.type == rhstrp->family) && - (strcmp(args->key.hostaddr.addr, rhstrp->address) == 0)) + linep = line; + limit = line + linelen; + keyp = args->key.hostaddr.addr; + prev = '\0'; + + if (strstr(linep, "\\:") != NULL) + ipv6 = 1; + else + ipv6 = 0; + + /* + * compare addr in + * + * 192.168.120.6:public + * fec0\:\:a00\:20ff\:fea0\:21f7:cipso + * + * ':' is the seperator. + */ + + while (*keyp && linep < limit && *keyp == *linep) { + if ((ipv6 == 0 && *linep == ':') || + (ipv6 == 1 && prev != '\\' && *linep == ':')) + break; + + prev = *linep; + keyp++; + linep++; + } + if (*keyp == '\0' && linep < limit && ((ipv6 == 0 && *linep == ':') || + (ipv6 == 1 && prev != '\\' && *linep == ':'))) return (1); return (0); } +static void +escape_colon(const char *in, char *out) { + int i, j; + for (i = 0, j = 0; in[i] != '\0'; i++) { + if (in[i] == ':') { + out[j++] = '\\'; + out[j++] = in[i]; + } else + out[j++] = in[i]; + } + out[j] = '\0'; +} + static nss_status_t getbyaddr(files_backend_ptr_t be, void *a) { nss_XbyY_args_t *argp = a; + char addr6[INET6_ADDRSTRLEN + 5]; /* 5 '\' for ':' */ + const char *addr = NULL; + nss_status_t rc; + + if (argp->key.hostaddr.addr == NULL || + (argp->key.hostaddr.type != AF_INET && + argp->key.hostaddr.type != AF_INET6)) + return (NSS_NOTFOUND); + if (strchr(argp->key.hostaddr.addr, ':') != NULL) { + /* IPV6 */ + if (argp->key.hostaddr.type == AF_INET) + return (NSS_NOTFOUND); + escape_colon(argp->key.hostaddr.addr, addr6); + /* save the key in original format */ + addr = argp->key.hostaddr.addr; + /* Replace the key with escaped format */ + argp->key.hostaddr.addr = addr6; + } else { + /* IPV4 */ + if (argp->key.hostaddr.type == AF_INET6) + return (NSS_NOTFOUND); + } + + rc = _nss_files_XY_all(be, argp, 1, + argp->key.hostaddr.addr, check_addr); + + /* restore argp->key.hostaddr.addr */ + if (addr) + argp->key.hostaddr.addr = addr; - return (_nss_files_XY_all(be, argp, 1, - argp->key.hostaddr.addr, check_addr)); + return (rc); } static files_backend_op_t tsol_rh_ops[] = { @@ -62,9 +134,10 @@ static files_backend_op_t tsol_rh_ops[] = { getbyaddr }; -/* ARGSUSED */ nss_backend_t * +/* LINTED E_FUNC_ARG_UNUSED */ _nss_files_tnrhdb_constr(const char *dummy1, const char *dummy2, +/* LINTED E_FUNC_ARG_UNUSED */ const char *dummy3) { return (_nss_files_constr(tsol_rh_ops, diff --git a/usr/src/lib/nsswitch/files/common/tsol_gettpent.c b/usr/src/lib/nsswitch/files/common/tsol_gettpent.c index ae5e9ca2be..dd604a5ee9 100644 --- a/usr/src/lib/nsswitch/files/common/tsol_gettpent.c +++ b/usr/src/lib/nsswitch/files/common/tsol_gettpent.c @@ -34,12 +34,20 @@ * "files" backend for nsswitch "tnrhtp" database */ static int -check_name(nss_XbyY_args_t *args) +check_name(nss_XbyY_args_t *args, const char *line, int linelen) { - tsol_tpstr_t *tpstrp = (tsol_tpstr_t *)args->returnval; - const char *name = args->key.name; + const char *limit, *linep, *keyp; - if (strcmp(tpstrp->template, name) == 0) + linep = line; + limit = line + linelen; + keyp = args->key.name; + + /* compare template name, ':' is the seperator */ + while (*keyp && linep < limit && *linep != ':' && *keyp == *linep) { + keyp++; + linep++; + } + if (*keyp == '\0' && linep < limit && *linep == ':') return (1); return (0); @@ -52,6 +60,9 @@ getbyname(be, a) { nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a; + if (argp->key.name == NULL) + return (NSS_NOTFOUND); + return (_nss_files_XY_all(be, argp, 1, argp->key.name, check_name)); } @@ -62,8 +73,8 @@ static files_backend_op_t tsol_tp_ops[] = { _nss_files_getent_netdb, getbyname }; - nss_backend_t * +/* LINTED E_FUNC_ARG_UNUSED */ _nss_files_tnrhtp_constr(dummy1, dummy2, dummy3) const char *dummy1, *dummy2, *dummy3; { diff --git a/usr/src/lib/nsswitch/ldap/Makefile.com b/usr/src/lib/nsswitch/ldap/Makefile.com index 031dd04f46..43779514fc 100644 --- a/usr/src/lib/nsswitch/ldap/Makefile.com +++ b/usr/src/lib/nsswitch/ldap/Makefile.com @@ -62,4 +62,6 @@ include ../../Makefile.com CPPFLAGS += -I../../../libsldap/common LDLIBS += -lsldap -lnsl -lsocket -lldap +LINTFLAGS += -erroff=E_GLOBAL_COULD_BE_STATIC2 +LINTFLAGS64 += -erroff=E_GLOBAL_COULD_BE_STATIC2 DYNLIB1 = nss_ldap.so$(VERS) diff --git a/usr/src/lib/nsswitch/ldap/common/getauthattr.c b/usr/src/lib/nsswitch/ldap/common/getauthattr.c index ea3341bf57..7b7b0c38b2 100644 --- a/usr/src/lib/nsswitch/ldap/common/getauthattr.c +++ b/usr/src/lib/nsswitch/ldap/common/getauthattr.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2003 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -51,170 +50,94 @@ static const char *auth_attrs[] = { _AUTH_ATTRS, (char *)NULL }; - - +/* + * _nss_ldap_auth2str is the data marshaling method for the auth_attr + * system call getauthattr and getauthnam. + * This method is called after a successful search has been performed. + * This method will parse the search results into the file format. + * e.g. + * + * solaris.:::All Solaris Authorizations::help=AllSolAuthsHeader.html + * + */ static int -_nss_ldap_auth2ent(ldap_backend_ptr be, nss_XbyY_args_t *argp) +_nss_ldap_auth2str(ldap_backend_ptr be, nss_XbyY_args_t *argp) { - int i, nss_result; - int buflen = (int)0; + int nss_result; + int buflen = 0; unsigned long len = 0L; - char *nullstring = (char *)NULL; - char *buffer = (char *)NULL; - char *ceiling = (char *)NULL; - authstr_t *auth = (authstr_t *)NULL; - ns_ldap_attr_t *attrptr; + char *buffer = NULL; ns_ldap_result_t *result = be->result; + char **name, **res1, **res2, **sdes, **ldes, **attr; + char *res1_str, *res2_str, *sdes_str, *ldes_str; + char *attr_str; - buffer = argp->buf.buffer; - buflen = (size_t)argp->buf.buflen; - if (!argp->buf.result) { - nss_result = (int)NSS_STR_PARSE_ERANGE; - goto result_auth2ent; - } - auth = (authstr_t *)(argp->buf.result); - ceiling = buffer + buflen; - auth->name = (char *)NULL; - auth->res1 = (char *)NULL; - auth->res2 = (char *)NULL; - auth->short_desc = (char *)NULL; - auth->long_desc = (char *)NULL; - auth->attr = (char *)NULL; - nss_result = (int)NSS_STR_PARSE_SUCCESS; - (void) memset(argp->buf.buffer, 0, buflen); - - attrptr = getattr(result, 0); - if (attrptr == NULL) { - nss_result = (int)NSS_STR_PARSE_PARSE; - goto result_auth2ent; - } + if (result == NULL) + return (NSS_STR_PARSE_PARSE); - for (i = 0; i < result->entry->attr_count; i++) { - attrptr = getattr(result, i); - if (attrptr == NULL) { - nss_result = (int)NSS_STR_PARSE_PARSE; - goto result_auth2ent; - } - if (strcasecmp(attrptr->attrname, _AUTH_NAME) == 0) { - if ((attrptr->attrvalue[0] == NULL) || - (len = strlen(attrptr->attrvalue[0])) < 1) { - nss_result = (int)NSS_STR_PARSE_PARSE; - goto result_auth2ent; - } - auth->name = buffer; - buffer += len + 1; - if (buffer >= ceiling) { - nss_result = (int)NSS_STR_PARSE_ERANGE; - goto result_auth2ent; - } - (void) strcpy(auth->name, attrptr->attrvalue[0]); - continue; - } - if (strcasecmp(attrptr->attrname, _AUTH_RES1) == 0) { - if ((attrptr->attrvalue[0] == NULL) || - (len = strlen(attrptr->attrvalue[0])) < 1) { - auth->res1 = nullstring; - } else { - auth->res1 = buffer; - buffer += len + 1; - if (buffer >= ceiling) { - nss_result = (int)NSS_STR_PARSE_ERANGE; - goto result_auth2ent; - } - (void) strcpy(auth->res1, - attrptr->attrvalue[0]); - } - continue; - } - if (strcasecmp(attrptr->attrname, _AUTH_RES2) == 0) { - if ((attrptr->attrvalue[0] == NULL) || - (len = strlen(attrptr->attrvalue[0])) < 1) { - auth->res2 = nullstring; - } else { - auth->res2 = buffer; - buffer += len + 1; - if (buffer >= ceiling) { - nss_result = (int)NSS_STR_PARSE_ERANGE; - goto result_auth2ent; - } - (void) strcpy(auth->res2, - attrptr->attrvalue[0]); - } - continue; - } - if (strcasecmp(attrptr->attrname, _AUTH_SHORTDES) == 0) { - if ((attrptr->attrvalue[0] == NULL) || - (len = strlen(attrptr->attrvalue[0])) < 1) { - auth->short_desc = nullstring; - } else { - auth->short_desc = buffer; - buffer += len + 1; - if (buffer >= ceiling) { - nss_result = (int)NSS_STR_PARSE_ERANGE; - goto result_auth2ent; - } - (void) strcpy(auth->short_desc, - attrptr->attrvalue[0]); - } - continue; - } - if (strcasecmp(attrptr->attrname, _AUTH_LONGDES) == 0) { - if ((attrptr->attrvalue[0] == NULL) || - (len = strlen(attrptr->attrvalue[0])) < 1) { - auth->long_desc = nullstring; - } else { - auth->long_desc = buffer; - buffer += len + 1; - if (buffer >= ceiling) { - nss_result = (int)NSS_STR_PARSE_ERANGE; - goto result_auth2ent; - } - (void) strcpy(auth->long_desc, - attrptr->attrvalue[0]); - } - continue; - } - if (strcasecmp(attrptr->attrname, _AUTH_ATTRS) == 0) { - if ((attrptr->attrvalue[0] == NULL) || - (len = strlen(attrptr->attrvalue[0])) < 1) { - auth->attr = nullstring; - } else { - auth->attr = buffer; - buffer += len + 1; - if (buffer >= ceiling) { - nss_result = (int)NSS_STR_PARSE_ERANGE; - goto result_auth2ent; - } - (void) strcpy(auth->attr, - attrptr->attrvalue[0]); - } - continue; - } - } + buflen = argp->buf.buflen; + nss_result = NSS_STR_PARSE_SUCCESS; + (void) memset(argp->buf.buffer, 0, buflen); -#ifdef DEBUG - (void) fprintf(stdout, "\n[getauthattr.c: _nss_ldap_auth2ent]\n"); - (void) fprintf(stdout, " auth-name: [%s]\n", auth->name); - if (auth->res1 != (char *)NULL) { - (void) fprintf(stdout, " res1: [%s]\n", auth->res1); - } - if (auth->res2 != (char *)NULL) { - (void) fprintf(stdout, " res2: [%s]\n", auth->res2); - } - if (auth->short_desc != (char *)NULL) { - (void) fprintf(stdout, " short_desc: [%s]\n", - auth->short_desc); + name = __ns_ldap_getAttr(result->entry, _AUTH_NAME); + if (name == NULL || name[0] == NULL || + (strlen(name[0]) < 1)) { + nss_result = NSS_STR_PARSE_PARSE; + goto result_auth2str; } - if (auth->long_desc != (char *)NULL) { - (void) fprintf(stdout, " long_desc: [%s]\n", - auth->long_desc); + res1 = __ns_ldap_getAttr(result->entry, _AUTH_RES1); + if (res1 == NULL || res1[0] == NULL || (strlen(res1[0]) < 1)) + res1_str = _NO_VALUE; + else + res1_str = res1[0]; + + res2 = __ns_ldap_getAttr(result->entry, _AUTH_RES2); + if (res2 == NULL || res2[0] == NULL || (strlen(res2[0]) < 1)) + res2_str = _NO_VALUE; + else + res2_str = res2[0]; + + sdes = __ns_ldap_getAttr(result->entry, _AUTH_SHORTDES); + if (sdes == NULL || sdes[0] == NULL || (strlen(sdes[0]) < 1)) + sdes_str = _NO_VALUE; + else + sdes_str = sdes[0]; + + ldes = __ns_ldap_getAttr(result->entry, _AUTH_LONGDES); + if (ldes == NULL || ldes[0] == NULL || (strlen(ldes[0]) < 1)) + ldes_str = _NO_VALUE; + else + ldes_str = ldes[0]; + + attr = __ns_ldap_getAttr(result->entry, _AUTH_ATTRS); + if (attr == NULL || attr[0] == NULL || (strlen(attr[0]) < 1)) + attr_str = _NO_VALUE; + else + attr_str = attr[0]; + /* 6 = 5 ':' + 1 '\0' */ + len = strlen(name[0]) + strlen(res1_str) + strlen(res2_str) + + strlen(sdes_str) + strlen(ldes_str) + strlen(attr_str) + 6; + if (len > buflen) { + nss_result = NSS_STR_PARSE_ERANGE; + goto result_auth2str; } - if (auth->attr != (char *)NULL) { - (void) fprintf(stdout, " attr: [%s]\n", auth->attr); - } -#endif /* DEBUG */ -result_auth2ent: + if (argp->buf.result != NULL) { + if ((be->buffer = calloc(1, len)) == NULL) { + nss_result = NSS_STR_PARSE_PARSE; + goto result_auth2str; + } + buffer = be->buffer; + } else + buffer = argp->buf.buffer; + (void) snprintf(buffer, len, "%s:%s:%s:%s:%s:%s", + name[0], res1_str, res2_str, sdes_str, + ldes_str, attr_str); + /* The front end marshaller doesn't need the trailing null */ + if (argp->buf.result != NULL) + be->buflen = strlen(be->buffer); + +result_auth2str: (void) __ns_ldap_freeResult(&be->result); return ((int)nss_result); } @@ -229,10 +152,6 @@ getbyname(ldap_backend_ptr be, void *a) char name[SEARCHFILTERLEN]; int ret; -#ifdef DEBUG - (void) fprintf(stdout, "\n[getauthattr.c: getbyname]\n"); -#endif /* DEBUG */ - if (_ldap_filter_name(name, argp->key.name, sizeof (name)) != 0) return ((nss_status_t)NSS_NOTFOUND); @@ -268,11 +187,7 @@ _nss_ldap_auth_attr_constr(const char *dummy1, const char *dummy4, const char *dummy5) { -#ifdef DEBUG - (void) fprintf(stdout, - "\n[getauthattr.c: _nss_ldap_auth_attr_constr]\n"); -#endif return ((nss_backend_t *)_nss_ldap_constr(authattr_ops, sizeof (authattr_ops)/sizeof (authattr_ops[0]), _AUTHATTR, - auth_attrs, _nss_ldap_auth2ent)); + auth_attrs, _nss_ldap_auth2str)); } diff --git a/usr/src/lib/nsswitch/ldap/common/getauuser.c b/usr/src/lib/nsswitch/ldap/common/getauuser.c index 2267b22ba9..7c9d9431c5 100644 --- a/usr/src/lib/nsswitch/ldap/common/getauuser.c +++ b/usr/src/lib/nsswitch/ldap/common/getauuser.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2003 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -45,109 +44,73 @@ static const char *auuser_attrs[] = { _AU_NEVER, (char *)NULL }; - - +/* + * _nss_ldap_au2str is the data marshaling method for the audit_user + * system call getauusernam, getauusernam_r, getauuserent and getauuserent_r. + * This method is called after a successful search has been performed. + * This method will parse the search results into the file format. + * e.g. + * + * root:lo:no + * + */ static int -_nss_ldap_au2ent(ldap_backend_ptr be, nss_XbyY_args_t *argp) +_nss_ldap_au2str(ldap_backend_ptr be, nss_XbyY_args_t *argp) { - int i, nss_result; - int buflen = (int)0; + int nss_result; + int buflen = 0; unsigned long len = 0L; - char *nullstring = (char *)NULL; - char *buffer = (char *)NULL; - char *ceiling = (char *)NULL; - au_user_str_t *au_user = (au_user_str_t *)NULL; - ns_ldap_attr_t *attrptr; + char *buffer = NULL; ns_ldap_result_t *result = be->result; + char **name, **al, **ne, *al_str, *ne_str; - buffer = argp->buf.buffer; - buflen = (size_t)argp->buf.buflen; - if (!argp->buf.result) { - nss_result = (int)NSS_STR_PARSE_ERANGE; - goto result_au2ent; - } - au_user = (au_user_str_t *)(argp->buf.result); - ceiling = buffer + buflen; - au_user->au_name = (char *)NULL; - au_user->au_always = (char *)NULL; - au_user->au_never = (char *)NULL; - nss_result = (int)NSS_STR_PARSE_SUCCESS; - (void) memset(argp->buf.buffer, 0, buflen); + if (result == NULL) + return (NSS_STR_PARSE_PARSE); - attrptr = getattr(result, 0); - if (attrptr == NULL) { - nss_result = (int)NSS_STR_PARSE_PARSE; - goto result_au2ent; - } - for (i = 0; i < result->entry->attr_count; i++) { - attrptr = getattr(result, i); - if (attrptr == NULL) { - nss_result = (int)NSS_STR_PARSE_PARSE; - goto result_au2ent; - } - if (strcasecmp(attrptr->attrname, _AU_NAME) == 0) { - if ((attrptr->attrvalue[0] == NULL) || - (len = strlen(attrptr->attrvalue[0])) < 1) { - nss_result = (int)NSS_STR_PARSE_PARSE; - goto result_au2ent; - } - au_user->au_name = buffer; - buffer += len + 1; - if (buffer >= ceiling) { - nss_result = (int)NSS_STR_PARSE_ERANGE; - goto result_au2ent; - } - (void) strcpy(au_user->au_name, attrptr->attrvalue[0]); - continue; - } - if (strcasecmp(attrptr->attrname, _AU_ALWAYS) == 0) { - if ((attrptr->attrvalue[0] == NULL) || - (len = strlen(attrptr->attrvalue[0])) < 1) { - au_user->au_always = nullstring; - } else { - au_user->au_always = buffer; - buffer += len + 1; - if (buffer >= ceiling) { - nss_result = (int)NSS_STR_PARSE_ERANGE; - goto result_au2ent; - } - (void) strcpy(au_user->au_always, - attrptr->attrvalue[0]); - } - continue; - } - if (strcasecmp(attrptr->attrname, _AU_NEVER) == 0) { - if ((attrptr->attrvalue[0] == NULL) || - (len = strlen(attrptr->attrvalue[0])) < 1) { - au_user->au_never = nullstring; - } else { - au_user->au_never = buffer; - buffer += len + 1; - if (buffer >= ceiling) { - nss_result = (int)NSS_STR_PARSE_ERANGE; - goto result_au2ent; - } - (void) strcpy(au_user->au_never, - attrptr->attrvalue[0]); - } - continue; - } - } + buflen = argp->buf.buflen; + nss_result = NSS_STR_PARSE_SUCCESS; + (void) memset(argp->buf.buffer, 0, buflen); -#ifdef DEBUG - (void) fprintf(stdout, "\n[getauuser.c: _nss_ldap_au2ent]\n"); - (void) fprintf(stdout, " au_name: [%s]\n", au_user->au_name); - if (au_user->au_always != (char *)NULL) { - (void) fprintf(stdout, " au_always: [%s]\n", - au_user->au_always); + name = __ns_ldap_getAttr(result->entry, _AU_NAME); + if (name == NULL || name[0] == NULL || + (strlen(name[0]) < 1)) { + nss_result = NSS_STR_PARSE_PARSE; + goto result_au2str; } - if (au_user->au_never != (char *)NULL) { - (void) fprintf(stdout, " au_never: [%s]\n", - au_user->au_never); + al = __ns_ldap_getAttr(result->entry, _AU_ALWAYS); + if (al == NULL || al[0] == NULL || (strlen(al[0]) < 1)) + al_str = _NO_VALUE; + else + al_str = al[0]; + + ne = __ns_ldap_getAttr(result->entry, _AU_NEVER); + if (ne == NULL || ne[0] == NULL || (strlen(ne[0]) < 1)) + ne_str = _NO_VALUE; + else + ne_str = ne[0]; + + /* 3 = 2 ':' + 1 '\0' */ + len = strlen(name[0]) + strlen(al_str) + strlen(ne_str) + 3; + if (len > buflen) { + nss_result = NSS_STR_PARSE_ERANGE; + goto result_au2str; } -#endif /* DEBUG */ -result_au2ent: + if (argp->buf.result != NULL) { + if ((be->buffer = calloc(1, len)) == NULL) { + nss_result = NSS_STR_PARSE_PARSE; + goto result_au2str; + } + buffer = be->buffer; + } else + buffer = argp->buf.buffer; + (void) snprintf(buffer, len, "%s:%s:%s", + name[0], al_str, ne_str); + /* The front end marshaller doesn't need the trailing null */ + if (argp->buf.result != NULL) + be->buflen = strlen(be->buffer); + +result_au2str: (void) __ns_ldap_freeResult(&be->result); return ((int)nss_result); } @@ -162,10 +125,6 @@ getbyname(ldap_backend_ptr be, void *a) nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a; int ret; -#ifdef DEBUG - (void) fprintf(stdout, "\n[getauuser.c: getbyname]\n"); -#endif /* DEBUG */ - if (_ldap_filter_name(name, argp->key.name, sizeof (name)) != 0) return ((nss_status_t)NSS_NOTFOUND); @@ -203,11 +162,7 @@ _nss_ldap_audit_user_constr(const char *dummy1, const char *dummy4, const char *dummy5) { -#ifdef DEBUG - (void) fprintf(stdout, - "\n[getauuser.c: _nss_ldap_audit_user_constr]\n"); -#endif return ((nss_backend_t *)_nss_ldap_constr(auuser_ops, sizeof (auuser_ops)/sizeof (auuser_ops[0]), _AUUSER, - auuser_attrs, _nss_ldap_au2ent)); + auuser_attrs, _nss_ldap_au2str)); } diff --git a/usr/src/lib/nsswitch/ldap/common/getbootparams.c b/usr/src/lib/nsswitch/ldap/common/getbootparams.c index f1426ba4b6..6a5c05d132 100644 --- a/usr/src/lib/nsswitch/ldap/common/getbootparams.c +++ b/usr/src/lib/nsswitch/ldap/common/getbootparams.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2003 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -41,85 +40,83 @@ static const char *bootparams_attrs[] = { }; /* - * _nss_ldap_bootparams2ent is the data marshaling method for the - * bootparams getXbyY (e.g., getbyname()) backend processes. This - * method is called after a successful ldap search has been performed. - * This method will parse the ldap search values into argp->buf.buffer - * Three error conditions are expected and returned to nsswitch. + * _nss_ldap_bootparams2str is the data marshaling method for the + * bootparams bootparams_getbyname backend processes. + * This method is called after a successful ldap search has been performed. + * This method will parse the ldap search values into the file format. * * A host's bootparameters are returned on one line separated by white - * space. Slapd stores each boot parameter as a separate entry. If more - * than one bootparameter is available, a white space separated buffer + * space. The LDAP server stores each boot parameter as a separate entry. + * If more than one bootparameter is available, a white space separated buffer * must be constructed and returned. + * */ static int -_nss_ldap_bootparams2ent(ldap_backend_ptr be, nss_XbyY_args_t *argp) +_nss_ldap_bootparams2str(ldap_backend_ptr be, nss_XbyY_args_t *argp) { - int i, j, nss_result; - int buflen = (int)0; - int firstime = (int)1; - unsigned long len = 0L; - char *cp = (char *)NULL; - char *buffer = (char *)NULL; + uint_t i; + int buflen = 0, len = 0; + int nss_result, firsttime; + ns_ldap_attr_t *bparams; + char *buffer, **names; ns_ldap_result_t *result = be->result; - ns_ldap_attr_t *attrptr; - - buffer = argp->buf.buffer; - buflen = (size_t)argp->buf.buflen; - nss_result = (int)NSS_STR_PARSE_SUCCESS; - (void) memset(buffer, 0, buflen); - - attrptr = getattr(result, 0); - if (attrptr == NULL) { - nss_result = (int)NSS_STR_PARSE_PARSE; - goto result_bp2ent; + if (result == NULL) + return (NSS_STR_PARSE_PARSE); + buflen = argp->buf.buflen; + if (argp->buf.result != NULL) { + if ((be->buffer = calloc(1, buflen)) == NULL) { + nss_result = NSS_STR_PARSE_PARSE; + goto result_bp2str; + } + buffer = be->buffer; + } else + buffer = argp->buf.buffer; + + nss_result = NSS_STR_PARSE_SUCCESS; + (void) memset(argp->buf.buffer, 0, buflen); + + names = __ns_ldap_getAttr(result->entry, _B_HOSTNAME); + if (names == NULL || names[0] == NULL || + (strlen(names[0]) < 1)) { + nss_result = NSS_STR_PARSE_PARSE; + goto result_bp2str; } - - for (i = 0; i < result->entry->attr_count; i++) { - attrptr = getattr(result, i); - if (attrptr == NULL) { - nss_result = (int)NSS_STR_PARSE_PARSE; - goto result_bp2ent; + bparams = __ns_ldap_getAttrStruct(result->entry, _B_PARAMETER); + if (bparams == NULL || bparams->attrvalue == NULL) { + nss_result = NSS_STR_PARSE_PARSE; + goto result_bp2str; + } + firsttime = 1; + for (i = 0; i < bparams->value_count; i++) { + if (bparams->attrvalue[i] == NULL) { + nss_result = NSS_STR_PARSE_PARSE; + goto result_bp2str; } - if (strcasecmp(attrptr->attrname, _B_PARAMETER) == 0) { - for (j = 0; j < attrptr->value_count; j++) { - if ((attrptr->attrvalue[j] == NULL) || - (len = strlen(attrptr->attrvalue[j])) < 1) { - *buffer = 0; - nss_result = (int)NSS_STR_PARSE_PARSE; - goto result_bp2ent; - } - if (len > buflen) { - nss_result = (int)NSS_STR_PARSE_ERANGE; - goto result_bp2ent; - } - if (firstime) { - (void) strcpy(buffer, - attrptr->attrvalue[j]); - firstime = (int)0; - } else { - if ((cp = strrchr(buffer, '\0')) - != NULL) - *cp = ' '; - (void) strcat(buffer, - attrptr->attrvalue[j]); - } - } + /* + * Skip client host name. The early version of ldapaddent + * adds hostname as a boot param and it should be filtered. + */ + if (strcasecmp(names[0], bparams->attrvalue[i]) != 0) { + if (firsttime) { + firsttime = 0; + len = snprintf(buffer, buflen, "%s", + bparams->attrvalue[i]); + } else + len = snprintf(buffer, buflen, " %s", + bparams->attrvalue[i]); + TEST_AND_ADJUST(len, buffer, buflen, result_bp2str); } } + /* The front end marshaller doesn't need to copy trailing nulls */ + if (argp->buf.result != NULL) + be->buflen = strlen(be->buffer); -#ifdef DEBUG - (void) fprintf(stdout, "\n[bootparams_getbyname.c: " - "_nss_ldap_bootparams2ent]\n"); - (void) fprintf(stdout, " bootparameter: [%s]\n", buffer); -#endif /* DEBUG */ - -result_bp2ent: +result_bp2str: (void) __ns_ldap_freeResult(&be->result); - return ((int)nss_result); + return (nss_result); } /* @@ -156,7 +153,6 @@ getbyname(ldap_backend_ptr be, void *a) _F_GETBOOTPARAMBYNAME_SSD, hostname); if (ret >= sizeof (userdata) || ret < 0) return ((nss_status_t)NSS_NOTFOUND); - return ((nss_status_t)_nss_ldap_lookup(be, argp, _BOOTPARAMS, searchfilter, NULL, _merge_SSD_filter, userdata)); @@ -183,5 +179,5 @@ _nss_ldap_bootparams_constr(const char *dummy1, const char *dummy2, return ((nss_backend_t *)_nss_ldap_constr(bootparams_ops, sizeof (bootparams_ops)/sizeof (bootparams_ops[0]), - _BOOTPARAMS, bootparams_attrs, _nss_ldap_bootparams2ent)); + _BOOTPARAMS, bootparams_attrs, _nss_ldap_bootparams2str)); } diff --git a/usr/src/lib/nsswitch/ldap/common/getether.c b/usr/src/lib/nsswitch/ldap/common/getether.c index 01f337dea8..9ce919853b 100644 --- a/usr/src/lib/nsswitch/ldap/common/getether.c +++ b/usr/src/lib/nsswitch/ldap/common/getether.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2003 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -48,131 +47,58 @@ static const char *ethers_attrs[] = { (char *)NULL }; - /* - * _nss_ldap_ethers2ent is the data marshaling method for the ethers - * getXbyY * (e.g., getbyhost(), getbyether()) backend processes. This - * method is called after a successful ldap search has been performed. - * This method will parse the ldap search values into uchar_t *ether - * = argp->buf.buffer which the frontend process expects. Three error - * conditions are expected and returned to nsswitch. - * - * Place the resulting struct ether_addr from the ldap query into - * argp->buf.result only if argp->buf.result is initialized (not NULL). - * e.g., it happens for the call ether_hostton. + * _nss_ldap_ethers2str is the data marshaling method for the ethers + * ether_hostton/ether_ntohost backend processes. + * This method is called after a successful ldap search has been performed. + * This method will parse the ldap search values into the file format. + * e.g. * - * Place the resulting hostname into argp->buf.buffer only if - * argp->buf.buffer is initialized. I.e. it happens for the call - * ether_ntohost. + * 8:0:20:8e:eb:8a8 borealis * - * argp->buf.buflen does not make sense for ethers. It is always set - * to 0 by the frontend. The caller only passes a hostname pointer in - * case of ether_ntohost, that is assumed to be big enough. For - * ether_hostton, the struct ether_addr passed is a fixed size. + * The front end marshaller str2ether uses argp->buf.result for a different + * purpose so a flag be->db_type is set to work around this oddity. * - * The interface does not let the caller specify how long is the buffer - * pointed by host. We make a safe assumption that the callers will - * always give MAXHOSTNAMELEN. In any case, it is the only finite number - * we can lay our hands on in case of runaway strings, memory corruption etc. */ - +/*ARGSUSED0*/ static int -_nss_ldap_ethers2ent(ldap_backend_ptr be, nss_XbyY_args_t *argp) +_nss_ldap_ethers2str(ldap_backend_ptr be, nss_XbyY_args_t *argp) { - int i, ip; int nss_result; - int buflen = (int)0; - unsigned int t[ETHERADDRL]; - unsigned long len = 0L; - char *host = NULL; - struct ether_addr *ether = NULL; ns_ldap_result_t *result = be->result; - ns_ldap_attr_t *attrptr; - int etherflag = 0, hostflag = 0; + char **host, **macaddress; - if (argp->buf.buffer) { - hostflag = 1; - host = argp->buf.buffer; - } - - buflen = (size_t)argp->buf.buflen; + if (result == NULL) + return (NSS_STR_PARSE_PARSE); + nss_result = NSS_STR_PARSE_SUCCESS; - if (argp->buf.result) { - etherflag = 1; - ether = (struct ether_addr *)argp->buf.result; + host = __ns_ldap_getAttr(result->entry, _E_HOSTNAME); + if (host == NULL || host[0] == NULL || (strlen(host[0]) < 1)) { + nss_result = NSS_STR_PARSE_PARSE; + goto result_ea2str; } - - nss_result = (int)NSS_STR_PARSE_SUCCESS; - (void) memset(argp->buf.buffer, 0, buflen); - - attrptr = getattr(result, 0); - if (attrptr == NULL) { - nss_result = (int)NSS_STR_PARSE_PARSE; - goto result_ea2ent; + macaddress = __ns_ldap_getAttr(result->entry, _E_MACADDRESS); + if (macaddress == NULL || macaddress[0] == NULL || + (strlen(macaddress[0]) < 1)) { + nss_result = NSS_STR_PARSE_PARSE; + goto result_ea2str; } - - for (i = 0; i < result->entry->attr_count; i++) { - attrptr = getattr(result, i); - if (attrptr == NULL) { - nss_result = (int)NSS_STR_PARSE_PARSE; - goto result_ea2ent; - } - if (hostflag) { - if (strcasecmp(attrptr->attrname, _E_HOSTNAME) == 0) { - if ((attrptr->attrvalue[0] == NULL) || - (len = strlen(attrptr->attrvalue[0])) < 1) { - nss_result = (int)NSS_STR_PARSE_PARSE; - goto result_ea2ent; - } - if (len > MAXHOSTNAMELEN) { - nss_result = (int)NSS_STR_PARSE_ERANGE; - goto result_ea2ent; - } - (void) strcpy(host, attrptr->attrvalue[0]); - continue; - } - } - if (etherflag) { - if (strcasecmp(attrptr->attrname, _E_MACADDRESS) == 0) { - if ((attrptr->attrvalue[0] == NULL) || - (len = strlen(attrptr->attrvalue[0])) < 1) { - nss_result = (int)NSS_STR_PARSE_PARSE; - goto result_ea2ent; - } - ip = (int)sscanf(attrptr->attrvalue[0], - "%x:%x:%x:%x:%x:%x", &t[0], &t[1], - &t[2], &t[3], &t[4], &t[5]); - if (ip != ETHERADDRL) { - nss_result = (int)NSS_STR_PARSE_PARSE; - goto result_ea2ent; - } - for (ip = 0; ip < ETHERADDRL; ip++) - ether->ether_addr_octet[ip] = - (uchar_t)t[ip]; - continue; - } - } + be->buflen = strlen(host[0]) + strlen(macaddress[0]) + 1; /* ' ' */ + /* Add a trailing null for easy debug */ + be->buffer = calloc(1, be->buflen + 1); + if (be->buffer == NULL) { + nss_result = NSS_STR_PARSE_PARSE; + goto result_ea2str; } -#ifdef DEBUG - (void) fprintf(stdout, "\n[ether_addr.c: _nss_ldap_ethers2ent]\n"); - if (host != NULL) - (void) fprintf(stdout, " hostname: [%s]\n", host); - if (ether != NULL) - (void) fprintf(stdout, - " ether_addr: [%x:%x:%x:%x:%x:%x]\n", - ether->ether_addr_octet[0], - ether->ether_addr_octet[1], - ether->ether_addr_octet[2], - ether->ether_addr_octet[3], - ether->ether_addr_octet[4], - ether->ether_addr_octet[5]); -#endif /* DEBUG */ - -result_ea2ent: + (void) snprintf(be->buffer, be->buflen + 1, "%s %s", + macaddress[0], host[0]); + be->db_type = NSS_LDAP_DB_ETHERS; + +result_ea2str: (void) __ns_ldap_freeResult(&be->result); - return ((int)nss_result); + return (nss_result); } /* @@ -197,23 +123,28 @@ getbyhost(ldap_backend_ptr be, void *a) char searchfilter[SEARCHFILTERLEN]; char userdata[SEARCHFILTERLEN]; int ret; + nss_status_t rc; if (_ldap_filter_name(hostname, argp->key.name, sizeof (hostname)) != 0) return ((nss_status_t)NSS_NOTFOUND); ret = snprintf(searchfilter, sizeof (searchfilter), _F_GETETHERBYHOST, hostname); + if (ret >= sizeof (searchfilter) || ret < 0) return ((nss_status_t)NSS_NOTFOUND); ret = snprintf(userdata, sizeof (userdata), _F_GETETHERBYHOST_SSD, hostname); + if (ret >= sizeof (userdata) || ret < 0) return ((nss_status_t)NSS_NOTFOUND); - return ((nss_status_t)_nss_ldap_lookup(be, argp, + rc = (nss_status_t)_nss_ldap_lookup(be, argp, _ETHERS, searchfilter, NULL, - _merge_SSD_filter, userdata)); + _merge_SSD_filter, userdata); + + return (rc); } @@ -279,5 +210,5 @@ _nss_ldap_ethers_constr(const char *dummy1, const char *dummy2, return ((nss_backend_t *)_nss_ldap_constr(ethers_ops, sizeof (ethers_ops)/sizeof (ethers_ops[0]), _ETHERS, - ethers_attrs, _nss_ldap_ethers2ent)); + ethers_attrs, _nss_ldap_ethers2str)); } diff --git a/usr/src/lib/nsswitch/ldap/common/getexecattr.c b/usr/src/lib/nsswitch/ldap/common/getexecattr.c index 4dfedc8628..35a60e579d 100644 --- a/usr/src/lib/nsswitch/ldap/common/getexecattr.c +++ b/usr/src/lib/nsswitch/ldap/common/getexecattr.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2003 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -262,29 +261,94 @@ _exec_ldap_exec2ent(ns_ldap_entry_t *entry, nss_XbyY_args_t *argp) /* - * place the results from ldap object structure into argp->buf.result + * place the results from ldap object structure into the file format * returns NSS_STR_PARSE_{SUCCESS, ERANGE, PARSE} */ static int -_nss_ldap_exec2ent(ldap_backend_ptr be, nss_XbyY_args_t *argp) +_nss_ldap_exec2str(ldap_backend_ptr be, nss_XbyY_args_t *argp) { - int status = (int)NSS_STR_PARSE_SUCCESS; - ns_ldap_entry_t *entry; + int status = NSS_STR_PARSE_SUCCESS; ns_ldap_result_t *result = be->result; - - if (!argp->buf.result) { - status = (int)NSS_STR_PARSE_ERANGE; - goto result_exec2ent; + int len; + char *buffer, **name, **policy, **type; + char **res1, **res2, **id, **attr; + char *policy_str, *type_str, *res1_str, *res2_str; + char *id_str, *attr_str; + + if (result == NULL) + return (NSS_STR_PARSE_PARSE); + + (void) memset(argp->buf.buffer, 0, argp->buf.buflen); + + name = __ns_ldap_getAttr(result->entry, _EXEC_NAME); + if (name == NULL || name[0] == NULL || + (strlen(name[0]) < 1)) { + status = NSS_STR_PARSE_PARSE; + goto result_exec2str; } - for (entry = result->entry; entry != NULL; entry = entry->next) { - status = _exec_ldap_exec2ent(entry, argp); - if (status != NSS_STR_PARSE_SUCCESS) { - goto result_exec2ent; - } + policy = __ns_ldap_getAttr(result->entry, _EXEC_POLICY); + + if (policy == NULL || policy[0] == NULL) + policy_str = _NO_VALUE; + else + policy_str = policy[0]; + + type = __ns_ldap_getAttr(result->entry, _EXEC_TYPE); + if (type == NULL || type[0] == NULL) + type_str = _NO_VALUE; + else + type_str = type[0]; + + res1 = __ns_ldap_getAttr(result->entry, _EXEC_RES1); + if (res1 == NULL || res1[0] == NULL) + res1_str = _NO_VALUE; + else + res1_str = res1[0]; + + res2 = __ns_ldap_getAttr(result->entry, _EXEC_RES2); + if (res2 == NULL || res2[0] == NULL) + res2_str = _NO_VALUE; + else + res2_str = res2[0]; + + id = __ns_ldap_getAttr(result->entry, _EXEC_ID); + if (id == NULL || id[0] == NULL) + id_str = _NO_VALUE; + else + id_str = id[0]; + + attr = __ns_ldap_getAttr(result->entry, _EXEC_ATTRS); + if (attr == NULL || attr[0] == NULL) + attr_str = _NO_VALUE; + else + attr_str = attr[0]; + + /* 7 = 6 ':' + 1 '\0' */ + len = strlen(name[0]) + strlen(policy_str) + strlen(type_str) + + strlen(res1_str) + strlen(res2_str) + strlen(id_str) + + strlen(attr_str) + 7; + + if (len > argp->buf.buflen) { + status = NSS_STR_PARSE_ERANGE; + goto result_exec2str; } - -result_exec2ent: + if (argp->buf.result != NULL) { + if ((be->buffer = calloc(1, len)) == NULL) { + status = NSS_STR_PARSE_PARSE; + goto result_exec2str; + } + buffer = be->buffer; + } else + buffer = argp->buf.buffer; + + (void) snprintf(buffer, len, "%s:%s:%s:%s:%s:%s:%s", + name[0], policy_str, type_str, res1_str, + res2_str, id_str, attr_str); + /* The front end marshaller does not need the trailing null */ + if (argp->buf.result != NULL) + be->buflen = strlen(buffer); +result_exec2str: (void) __ns_ldap_freeResult(&be->result); return (status); } @@ -300,10 +364,6 @@ _exec_process_val(ldap_backend_ptr be, nss_XbyY_args_t *argp) ns_ldap_result_t *result = be->result; _priv_execattr *_priv_exec = (_priv_execattr *)(argp->key.attrp); -#ifdef DEBUG - (void) fprintf(stdout, "\n[getexecattr.c: _exec_process_val]\n"); -#endif /* DEBUG */ - argp->returnval = NULL; attrptr = getattr(result, 0); if (attrptr == NULL) { @@ -426,6 +486,54 @@ go_out: } static nss_status_t +exec_attr_process_val(ldap_backend_ptr be, nss_XbyY_args_t *argp) { + + _priv_execattr *_priv_exec = (_priv_execattr *)(argp->key.attrp); + int stat, nss_stat = NSS_SUCCESS; + + if (_priv_exec->search_flag == GET_ONE) { + /* ns_ldap_entry_t -> file format */ + stat = (*be->ldapobj2str)(be, argp); + + if (stat == NSS_STR_PARSE_SUCCESS) { + if (argp->buf.result != NULL) { + /* file format -> execstr_t */ + stat = (*argp->str2ent)(be->buffer, + be->buflen, + argp->buf.result, + argp->buf.buffer, + argp->buf.buflen); + if (stat == NSS_STR_PARSE_SUCCESS) { + argp->returnval = argp->buf.result; + argp->returnlen = 1; /* irrelevant */ + nss_stat = NSS_SUCCESS; + } else { + argp->returnval = NULL; + argp->returnlen = 0; + nss_stat = NSS_NOTFOUND; + } + } else { + /* return file format in argp->buf.buffer */ + argp->returnval = argp->buf.buffer; + argp->returnlen = strlen(argp->buf.buffer); + nss_stat = NSS_SUCCESS; + } + } else { + argp->returnval = NULL; + argp->returnlen = 0; + nss_stat = NSS_NOTFOUND; + } + } else { + /* GET_ALL */ + nss_stat = _exec_process_val(be, argp); + _exec_cleanup(nss_stat, argp); + } + + return (nss_stat); + +} + +static nss_status_t getbynam(ldap_backend_ptr be, void *a) { char searchfilter[SEARCHFILTERLEN]; @@ -438,10 +546,6 @@ getbynam(ldap_backend_ptr be, void *a) const char *policy = _priv_exec->policy; const char *type = _priv_exec->type; -#ifdef DEBUG - (void) fprintf(stdout, "\n[getexecattr.c: getbyname]\n"); -#endif /* DEBUG */ - if (strpbrk(policy, "*()\\") != NULL || type != NULL && strpbrk(type, "*()\\") != NULL || _ldap_filter_name(name, _priv_exec->name, sizeof (name)) != 0) @@ -458,31 +562,22 @@ getbynam(ldap_backend_ptr be, void *a) nss_stat = _nss_ldap_nocb_lookup(be, argp, _EXECATTR, searchfilter, NULL, _merge_SSD_filter, userdata); - if (nss_stat == NSS_SUCCESS) - nss_stat = _exec_process_val(be, argp); - - _exec_cleanup(nss_stat, argp); + if (nss_stat == NSS_SUCCESS) + nss_stat = exec_attr_process_val(be, argp); return (nss_stat); } - static nss_status_t getbyid(ldap_backend_ptr be, void *a) { - nss_status_t nss_stat; + nss_status_t nss_stat = NSS_SUCCESS; nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a; -#ifdef DEBUG - (void) fprintf(stdout, "\n[getexecattr.c: getbyid]\n"); -#endif /* DEBUG */ - nss_stat = get_wild(be, argp, NSS_DBOP_EXECATTR_BYID); - if (nss_stat == NSS_SUCCESS) - nss_stat = _exec_process_val(be, argp); - - _exec_cleanup(nss_stat, argp); + if (nss_stat == NSS_SUCCESS) + nss_stat = exec_attr_process_val(be, argp); return (nss_stat); } @@ -494,16 +589,10 @@ getbynameid(ldap_backend_ptr be, void *a) nss_status_t nss_stat; nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a; -#ifdef DEBUG - (void) fprintf(stdout, "\n[getexecattr.c: getbynameid]\n"); -#endif /* DEBUG */ - nss_stat = get_wild(be, argp, NSS_DBOP_EXECATTR_BYNAMEID); - if (nss_stat == NSS_SUCCESS) - nss_stat = _exec_process_val(be, argp); - - _exec_cleanup(nss_stat, argp); + if (nss_stat == NSS_SUCCESS) + nss_stat = exec_attr_process_val(be, argp); return (nss_stat); } @@ -536,5 +625,5 @@ _nss_ldap_exec_attr_constr(const char *dummy1, #endif return ((nss_backend_t *)_nss_ldap_constr(execattr_ops, sizeof (execattr_ops)/sizeof (execattr_ops[0]), _EXECATTR, - exec_attrs, _nss_ldap_exec2ent)); + exec_attrs, _nss_ldap_exec2str)); } diff --git a/usr/src/lib/nsswitch/ldap/common/getgrent.c b/usr/src/lib/nsswitch/ldap/common/getgrent.c index 1533ad8b3b..3456b6241f 100644 --- a/usr/src/lib/nsswitch/ldap/common/getgrent.c +++ b/usr/src/lib/nsswitch/ldap/common/getgrent.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2003 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -56,195 +55,106 @@ static const char *gr_attrs[] = { /* - * _nss_ldap_group2ent is the data marshaling method for the group getXbyY + * _nss_ldap_group2str is the data marshaling method for the group getXbyY * (e.g., getgrnam(), getgrgid(), getgrent()) backend processes. This method * is called after a successful ldap search has been performed. This method - * will parse the ldap search values into struct group = argp->buf.buffer - * which the frontend process expects. Three error conditions are expected - * and returned to nsswitch. + * will parse the ldap search values into the file format. + * e.g. + * + * adm::4:root,adm,daemon + * */ static int -_nss_ldap_group2ent(ldap_backend_ptr be, nss_XbyY_args_t *argp) +_nss_ldap_group2str(ldap_backend_ptr be, nss_XbyY_args_t *argp) { - int i, j; + int i; int nss_result; - int buflen = (int)0; - int firstime = (int)1; - unsigned long len = 0L; - char **mp = NULL; - char *val = (char *)NULL; - char *buffer = (char *)NULL; - char *ceiling = (char *)NULL; - struct group *grp = (struct group *)NULL; + int buflen = 0, len; + int firstime = 1; + char *buffer = NULL; ns_ldap_result_t *result = be->result; - ns_ldap_attr_t *attrptr; + char **gname, **passwd, **gid, *password; + ns_ldap_attr_t *members; - buffer = argp->buf.buffer; - buflen = (size_t)argp->buf.buflen; - if (!argp->buf.result) { - nss_result = (int)NSS_STR_PARSE_ERANGE; - goto result_grp2ent; - } - grp = (struct group *)argp->buf.result; - ceiling = buffer + buflen; - mp = grp->gr_mem = (char **)NULL; - - /* initialize no group password */ - grp->gr_passwd = (char *)NULL; - nss_result = (int)NSS_STR_PARSE_SUCCESS; - (void) memset(argp->buf.buffer, 0, buflen); - - attrptr = getattr(result, 0); - if (attrptr == NULL) { - nss_result = (int)NSS_STR_PARSE_PARSE; - goto result_grp2ent; - } - for (i = 0; i < result->entry->attr_count; i++) { - attrptr = getattr(result, i); - if (attrptr == NULL) { - nss_result = (int)NSS_STR_PARSE_PARSE; - goto result_grp2ent; - } - if (strcasecmp(attrptr->attrname, _G_NAME) == 0) { - if ((attrptr->attrvalue[0] == NULL) || - (len = strlen(attrptr->attrvalue[0])) < 1) { - nss_result = (int)NSS_STR_PARSE_PARSE; - goto result_grp2ent; - } - grp->gr_name = buffer; - buffer += len + 1; - if (buffer > ceiling) { - nss_result = (int)NSS_STR_PARSE_ERANGE; - goto result_grp2ent; - } - (void) strcpy(grp->gr_name, attrptr->attrvalue[0]); - continue; - } - if (strcasecmp(attrptr->attrname, _G_PASSWD) == 0) { - val = attrptr->attrvalue[0]; - /* - * Preen "{crypt}" if necessary. - * If the password does not include the {crypt} prefix - * then the password may be plain text. And thus - * perhaps crypt(3c) should be used to encrypt it. - * Currently the password is copied verbatim. - */ - if (strncasecmp(val, _CRYPT, - (sizeof (_CRYPT) - 1)) == 0) - val += (sizeof (_CRYPT) - 1); - len = strlen(val); - grp->gr_passwd = buffer; - buffer += len + 1; - if (buffer > ceiling) { - nss_result = (int)NSS_STR_PARSE_ERANGE; - goto result_grp2ent; - } - (void) strcpy(grp->gr_passwd, val); - continue; - } - if (strcasecmp(attrptr->attrname, _G_GID) == 0) { - if (strlen(attrptr->attrvalue[0]) == 0) { - nss_result = (int)NSS_STR_PARSE_PARSE; - goto result_grp2ent; - } - errno = 0; - grp->gr_gid = (gid_t)strtol(attrptr->attrvalue[0], - (char **)NULL, 10); - if (errno != 0) { - nss_result = (int)NSS_STR_PARSE_PARSE; - goto result_grp2ent; - } - continue; - } - if (strcasecmp(attrptr->attrname, _G_MEM) == 0) { - for (j = 0; j < attrptr->value_count; j++) { - if (firstime) { - mp = grp->gr_mem = - (char **)ROUND_UP(buffer, - sizeof (char **)); - buffer = (char *)grp->gr_mem + - sizeof (char *) * - (attrptr->value_count + 1); - buffer = (char *)ROUND_UP(buffer, - sizeof (char **)); - if (buffer > ceiling) { - nss_result = - (int)NSS_STR_PARSE_ERANGE; - goto result_grp2ent; - } - firstime = (int)0; - } - if (attrptr->attrvalue[j] == NULL) { - nss_result = (int)NSS_STR_PARSE_PARSE; - goto result_grp2ent; - } - len = strlen(attrptr->attrvalue[j]); - if (len == 0) - continue; - *mp = buffer; - buffer += len + 1; - if (buffer > ceiling) { - nss_result = (int)NSS_STR_PARSE_ERANGE; - goto result_grp2ent; - } - (void) strcpy(*mp++, attrptr->attrvalue[j]); - continue; - } + if (result == NULL) + return (NSS_STR_PARSE_PARSE); + buflen = argp->buf.buflen; + + if (argp->buf.result != NULL) { + if ((be->buffer = calloc(1, buflen)) == NULL) { + nss_result = NSS_STR_PARSE_PARSE; + goto result_grp2str; } + buffer = be->buffer; + } else + buffer = argp->buf.buffer; + + nss_result = NSS_STR_PARSE_SUCCESS; + (void) memset(buffer, 0, buflen); + + gname = __ns_ldap_getAttr(result->entry, _G_NAME); + if (gname == NULL || gname[0] == NULL || (strlen(gname[0]) < 1)) { + nss_result = NSS_STR_PARSE_PARSE; + goto result_grp2str; } - /* Don't leave password as null */ - if (grp->gr_passwd == (char *)NULL) { + passwd = __ns_ldap_getAttr(result->entry, _G_PASSWD); + if (passwd == NULL || passwd[0] == NULL || (strlen(passwd[0]) == 0)) { + /* group password could be NULL, replace it with "" */ + password = _NO_PASSWD_VAL; + } else { /* - * The password may be missing; rfc2307bis defines - * the 'posixGroup' attributes 'authPassword' and - * 'userPassword' as being optional. Or a directory - * access control may be preventing us from reading - * the password. Currently we don't know which it is. - * If it's an access problem then perhaps the password - * should be set to "*NP*". But for now a simple empty - * string is returned. + * Preen "{crypt}" if necessary. + * If the password does not include the {crypt} prefix + * then the password may be plain text. And thus + * perhaps crypt(3c) should be used to encrypt it. + * Currently the password is copied verbatim. */ - grp->gr_passwd = buffer; - buffer += sizeof (_NO_PASSWD_VAL); - if (buffer > ceiling) { - nss_result = (int)NSS_STR_PARSE_ERANGE; - goto result_grp2ent; - } - (void) strcpy(grp->gr_passwd, _NO_PASSWD_VAL); + if (strncasecmp(passwd[0], _CRYPT, strlen(_CRYPT)) == 0) + password = passwd[0] + strlen(_CRYPT); + else + password = passwd[0]; } - if (mp == NULL) { - mp = grp->gr_mem = (char **)ROUND_UP(buffer, sizeof (char **)); - buffer = (char *)grp->gr_mem + sizeof (char *); - buffer = (char *)ROUND_UP(buffer, sizeof (char **)); - if (buffer > ceiling) { - nss_result = (int)NSS_STR_PARSE_ERANGE; - goto result_grp2ent; - } + gid = __ns_ldap_getAttr(result->entry, _G_GID); + if (gid == NULL || gid[0] == NULL || (strlen(gid[0]) < 1)) { + nss_result = NSS_STR_PARSE_PARSE; + goto result_grp2str; } - *mp = NULL; - -#ifdef DEBUG - (void) fprintf(stdout, "\n[getgrent.c: _nss_ldap_group2ent]\n"); - (void) fprintf(stdout, " gr_name: [%s]\n", grp->gr_name); - if (grp->gr_passwd != (char *)NULL) - (void) fprintf(stdout, " gr_passwd: [%s]\n", - grp->gr_passwd); - (void) fprintf(stdout, " gr_gid: [%ld]\n", grp->gr_gid); - if (mp != NULL) { - for (mp = grp->gr_mem; *mp != NULL; mp++) - (void) fprintf(stdout, " gr_mem: [%s]\n", *mp); + len = snprintf(buffer, buflen, "%s:%s:%s:", + gname[0], password, gid[0]); + TEST_AND_ADJUST(len, buffer, buflen, result_grp2str); + + members = __ns_ldap_getAttrStruct(result->entry, _G_MEM); + if (members == NULL || members->attrvalue == NULL) { + nss_result = NSS_STR_PARSE_PARSE; + goto result_grp2str; } -#endif /* DEBUG */ - -result_grp2ent: + for (i = 0; i < members->value_count; i++) { + if (members->attrvalue[i] == NULL) { + nss_result = NSS_STR_PARSE_PARSE; + goto result_grp2str; + } + if (firstime) { + len = snprintf(buffer, buflen, "%s", + members->attrvalue[i]); + TEST_AND_ADJUST(len, buffer, buflen, result_grp2str); + firstime = 0; + } else { + len = snprintf(buffer, buflen, ",%s", + members->attrvalue[i]); + TEST_AND_ADJUST(len, buffer, buflen, result_grp2str); + } + } + /* The front end marshaller doesn't need the trailing nulls */ + if (argp->buf.result != NULL) + be->buflen = strlen(be->buffer); +result_grp2str: (void) __ns_ldap_freeResult(&be->result); - return ((int)nss_result); + return (nss_result); } - /* * getbynam gets a group entry by name. This function constructs an ldap * search filter using the name invocation parameter and the getgrnam search @@ -262,9 +172,6 @@ getbynam(ldap_backend_ptr be, void *a) char groupname[SEARCHFILTERLEN]; int ret; -#ifdef DEBUG - (void) fprintf(stdout, "\n[getgrent.c: getbyname]\n"); -#endif /* DBEUG */ if (_ldap_filter_name(groupname, argp->key.name, sizeof (groupname)) != 0) return ((nss_status_t)NSS_NOTFOUND); @@ -300,9 +207,6 @@ getbygid(ldap_backend_ptr be, void *a) char userdata[SEARCHFILTERLEN]; int ret; -#ifdef DEBUG - (void) fprintf(stdout, "\n[getgrent.c: getbygid]\n"); -#endif /* DBEUG */ ret = snprintf(searchfilter, sizeof (searchfilter), _F_GETGRGID, (long)argp->key.uid); if (ret >= sizeof (searchfilter) || ret < 0) @@ -354,10 +258,7 @@ getbymember(ldap_backend_ptr be, void *a) gid_t gid; int ret; -#ifdef DEBUG - (void) fprintf(stdout, "\n[getgrent.c: getbymember]\n"); -#endif /* DBEUG */ - + /* LINTED E_EXPR_NULL_EFFECT */ NSS_XbyY_ALLOC(&gb, sizeof (struct group), NSS_BUFLEN_GROUP); NSS_XbyY_INIT(&argb, gb->result, gb->buffer, gb->buflen, 0); @@ -414,7 +315,7 @@ getbymember(ldap_backend_ptr be, void *a) curEntry = curEntry->next; } - __ns_ldap_freeResult((ns_ldap_result_t **)&be->result); + (void) __ns_ldap_freeResult((ns_ldap_result_t **)&be->result); NSS_XbyY_FREE(&gb); if (gcnt == argp->numgids) return ((nss_status_t)NSS_NOTFOUND); @@ -441,5 +342,5 @@ _nss_ldap_group_constr(const char *dummy1, const char *dummy2, return ((nss_backend_t *)_nss_ldap_constr(gr_ops, sizeof (gr_ops)/sizeof (gr_ops[0]), _GROUP, gr_attrs, - _nss_ldap_group2ent)); + _nss_ldap_group2str)); } diff --git a/usr/src/lib/nsswitch/ldap/common/gethostent.c b/usr/src/lib/nsswitch/ldap/common/gethostent.c index 78b84c785e..f327c232c6 100644 --- a/usr/src/lib/nsswitch/ldap/common/gethostent.c +++ b/usr/src/lib/nsswitch/ldap/common/gethostent.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2003 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -52,261 +51,203 @@ static const char *hosts_attrs[] = { (char *)NULL }; - /* - * _nss_ldap_hosts2ent is the data marshaling method for the hosts getXbyY - * system call gethostbyname() and gethostbyaddr. The format of this call - * is a cononical name and alias (alias is cononical name too) and one or - * more IP addresses in support of multihomed hosts. This method is called - * after a successful synchronous search has been performed. This method - * will parse the search results into struct hostent = argp->buf.buffer - * which gets returned to the frontend process. One of three error - * conditions is also returned to nsswitch. + * _nss_ldap_hosts2str is the data marshaling method for the hosts getXbyY + * system call gethostbyname() and gethostbyaddr. + * This method is called after a successful search has been performed. + * This method will parse the search results into the file format. + * e.g. + * + * 9.9.9.9 jurassic jurassic1 jurassic2 + * 10.10.10.10 puppy + * */ - -static int -_nss_ldap_hosts2ent(ldap_backend_ptr be, nss_XbyY_args_t *argp) +int +_nss_ldap_hosts2str_int(int af, ldap_backend_ptr be, nss_XbyY_args_t *argp) { - int i, j; + uint_t i; int nss_result; - int buflen = (int)0; - int firstimename = (int)1; - int firstimedn = (int)1; - int firstimeaddr = (int)1; - unsigned long len = 0L; - char **hn, **ha, **dp; - char *cname = (char *)NULL; - char *buffer = (char *)NULL; - char *ceiling = (char *)NULL; - struct hostent *host = (struct hostent *)NULL; - in_addr_t addr; + int buflen, buflen1, buflen2, len; + int firstimedn = 1, first_entry; + int validaddress = 0, copy_cname; + char *cname = NULL, *h_name = NULL; + char *buffer = NULL; + char *name; ns_ldap_result_t *result = be->result; - ns_ldap_attr_t *attrptr; - in_addr_t inet_addr(const char *cp); - int namecount = 0; - int addrcount = 0; - int aliascount = 0; - int validaddress = 0; - int gluelen = 0; + ns_ldap_attr_t *names; ns_ldap_entry_t *entry; - ns_ldap_attr_t *attr; -#ifdef DEBUG - struct in_addr in; -#endif /* DEBUG */ - - buffer = argp->buf.buffer; - buflen = (size_t)argp->buf.buflen; - if (!argp->buf.result) { - nss_result = (int)NSS_STR_PARSE_ERANGE; - goto result_hosts2ent; + char **ips = NULL, **dns = NULL; + char *first_host = NULL, *other_hosts = NULL; + char *buf1, *buf2; + + if (result == NULL) + return (NSS_STR_PARSE_PARSE); + buflen = buflen1 = buflen2 = argp->buf.buflen; + + if (argp->buf.result != NULL) { + if ((be->buffer = calloc(1, buflen)) == NULL) { + nss_result = NSS_STR_PARSE_PARSE; + goto result_host2str; + } + buffer = be->buffer; + } else + buffer = argp->buf.buffer; + if ((first_host = calloc(1, buflen1)) == NULL) { + nss_result = NSS_STR_PARSE_PARSE; + goto result_host2str; } - - host = (struct hostent *)argp->buf.result; - ceiling = buffer + buflen; - - nss_result = (int)NSS_STR_PARSE_SUCCESS; - (void) memset(argp->buf.buffer, 0, buflen); - - attrptr = getattr(result, 0); - if (attrptr == NULL) { - nss_result = (int)NSS_STR_PARSE_PARSE; - goto result_hosts2ent; + if ((other_hosts = calloc(1, buflen2)) == NULL) { + nss_result = NSS_STR_PARSE_PARSE; + goto result_host2str; } - namecount = 0; - addrcount = 0; - for (entry = result->entry; entry != NULL; entry = entry->next) { - for (i = 0, attr = entry->attr_pair[i]; - i < entry->attr_count; i++) { - attr = entry->attr_pair[i]; - if (strcasecmp(attr->attrname, _H_NAME) == 0) - namecount += attr->value_count; - if (strcasecmp(attr->attrname, _H_ADDR) == 0) - addrcount += attr->value_count; - } - } + nss_result = NSS_STR_PARSE_SUCCESS; + (void) memset(argp->buf.buffer, 0, buflen); + /* + * Multiple lines return will be sepereated by newlines + * Single line return or last line does not have newline + * e.g. + * + * 8.8.8.8 hostname + * + * or the search for hostname h1 returns 3 entries + * + * 9.9.9.9 h1 + * 10.10.10.10 h1 xx + * 20.20.20.20 h1 yyy + * + * str2hostent expects all name/aliases in the first entry + * so the string is organized as + * + * "9.9.9.9 h1 xx yy\n10.10.10.10 \n20.20.20.20 " + * + * Use first_host to hold "9.9.9.9 h1 xx yy" and other_hosts to hold + * "\n10.10.10.10 \n20.20.20.20 " + * + */ + buf1 = first_host; + buf2 = other_hosts; + first_entry = 1; for (entry = result->entry; entry != NULL; entry = entry->next) { - for (i = 0; i < entry->attr_count; i++) { - attrptr = entry->attr_pair[i]; - if (attrptr == NULL) { - nss_result = (int)NSS_STR_PARSE_PARSE; - goto result_hosts2ent; - } - if (strcasecmp(attrptr->attrname, _H_DN) == 0) { - for (j = 0; j < attrptr->value_count; j++) { - if (firstimedn) { - /* get domain name associated with this dn */ - be->toglue = _get_domain_name( - attrptr->attrvalue[j]); - firstimedn = (int)0; - } - } - } - if (strcasecmp(attrptr->attrname, _H_NAME) == 0) { - for (j = 0; j < attrptr->value_count; j++) { - if (firstimename) { - /* canonical name */ - cname = __s_api_get_canonical_name(result->entry, - attrptr, 1); - if (cname == NULL || - (len = strlen(cname)) < 1) { - nss_result = (int)NSS_STR_PARSE_PARSE; - goto result_hosts2ent; - } - if (be->toglue != NULL && - !DOTTEDSUBDOMAIN(cname)) - gluelen = strlen(be->toglue) + 1; - else - gluelen = 0; - host->h_name = buffer; - buffer += len + gluelen + 1; - if (buffer >= ceiling) { - nss_result = (int)NSS_STR_PARSE_ERANGE; - goto result_hosts2ent; - } - (void) strcpy(host->h_name, cname); - if (gluelen > 0) { - (void) strcat(host->h_name, "."); - (void) strcat(host->h_name, be->toglue); - } - /* alias name */ - aliascount = (namecount >= 1 ? (namecount - 1) : 0); - hn = host->h_aliases = (char **)ROUND_UP(buffer, - sizeof (char **)); - buffer = (char *)host->h_aliases + - (sizeof (char *) * (aliascount + 1)); - buffer = (char *)ROUND_UP(buffer, - sizeof (char **)); - if (buffer >= ceiling) { - nss_result = (int)NSS_STR_PARSE_ERANGE; - goto result_hosts2ent; - } - firstimename = (int)0; - } - /* alias list */ - if (aliascount > 0) { - if ((attrptr->attrvalue[j] == NULL) || - (len = strlen(attrptr->attrvalue[j])) < 1) { - nss_result = (int)NSS_STR_PARSE_PARSE; - goto result_hosts2ent; - } - /* skip canonical name */ - if (strcmp(cname, attrptr->attrvalue[j]) == 0) - continue; - /* check for duplicates */ - for (dp = host->h_aliases; *dp != NULL; dp++) { - if (strcmp(*dp, attrptr->attrvalue[j]) == 0) - goto next_alias; - } - if (be->toglue != NULL && - !DOTTEDSUBDOMAIN(attrptr->attrvalue[j])) - gluelen = strlen(be->toglue) + 1; - else - gluelen = 0; - *hn = buffer; - buffer += len + gluelen + 1; - if (buffer >= ceiling) { - nss_result = (int)NSS_STR_PARSE_ERANGE; - goto result_hosts2ent; - } - (void) strcpy(*hn, attrptr->attrvalue[j]); - if (gluelen > 0) { - (void) strcat(*hn, "."); - (void) strcat(*hn, be->toglue); - } - hn++; - } -next_alias: - continue; + if (firstimedn) { + dns = __ns_ldap_getAttr(entry, _H_DN); + if (dns == NULL || dns[0] == NULL || strlen(dns[0]) < 1) { + nss_result = NSS_STR_PARSE_PARSE; + goto result_host2str; } - } + /* get domain name associated with this dn */ + be->toglue = _get_domain_name(dns[0]); + firstimedn = 0; } - } - for (entry = result->entry; entry != NULL; entry = entry->next) { - for (i = 0; i < entry->attr_count; i++) { - attrptr = entry->attr_pair[i]; - if (attrptr == NULL) { - nss_result = (int)NSS_STR_PARSE_PARSE; - goto result_hosts2ent; - } - if (strcasecmp(attrptr->attrname, _H_ADDR) == 0) { - for (j = 0; j < attrptr->value_count; j++) { - if (firstimeaddr) { - /* allocate 1 address per entry */ - ha = host->h_addr_list = - (char **)ROUND_UP(buffer, - sizeof (char **)); - buffer = (char *)host->h_addr_list + - sizeof (char *) * - (addrcount + 1); - buffer = (char *)ROUND_UP(buffer, - sizeof (char **)); - if (buffer >= ceiling) { - nss_result = (int)NSS_STR_PARSE_ERANGE; - goto result_hosts2ent; - } - firstimeaddr = (int)0; - } - /* filter out IPV6 addresses */ - addr = inet_addr(_strip_quotes(attrptr->attrvalue[j])); - if (addr == (in_addr_t)-1) { - goto next_addr; - } - validaddress++; - /* check for duplicates */ - for (dp = host->h_addr_list; *dp != NULL; dp++) { - if (memcmp(*dp, &addr, (size_t)sizeof (in_addr_t)) == 0) - goto next_addr; - } - *ha = buffer; - len = (unsigned long)sizeof (in_addr_t); - buffer += len; - if (buffer >= ceiling) { - nss_result = (int)NSS_STR_PARSE_ERANGE; - goto result_hosts2ent; - } - (void) memcpy(*ha++, (char *)&addr, (size_t)len); -next_addr: - continue; - } - } + /* Get IP */ + ips = __ns_ldap_getAttr(entry, _H_ADDR); + if (ips == NULL || ips[0] == NULL || strlen(ips[0]) < 1) { + nss_result = NSS_STR_PARSE_PARSE; + goto result_host2str; + } + /* Skip IPV6 address in AF_INET mode */ + if (af == AF_INET && + (inet_addr(_strip_quotes(ips[0])) == (in_addr_t)-1)) + continue; + + /* A valid address for either af mode */ + validaddress++; + + if (first_entry) { + len = snprintf(buf1, buflen1, "%s", ips[0]); + TEST_AND_ADJUST(len, buf1, buflen1, result_host2str); + } else { + len = snprintf(buf2, buflen2, "\n%s ", ips[0]); + TEST_AND_ADJUST(len, buf2, buflen2, result_host2str); } - } - if (validaddress == 0) { - nss_result = (int)NSS_STR_PARSE_NO_ADDR; - goto result_hosts2ent; - } + /* Get host names */ + names = __ns_ldap_getAttrStruct(entry, _H_NAME); + if (names == NULL || names->attrvalue == NULL) { + nss_result = NSS_STR_PARSE_PARSE; + goto result_host2str; + } - host->h_addrtype = AF_INET; - host->h_length = sizeof (uint_t); + /* Get canonical name of each entry */ + cname = __s_api_get_canonical_name(entry, + names, 1); + if (cname == NULL || strlen(cname) < 1) { + nss_result = NSS_STR_PARSE_PARSE; + goto result_host2str; + } -#ifdef DEBUG - (void) fprintf(stdout, "\n[gethostent.c: _nss_ldap_hosts2ent]\n"); - (void) fprintf(stdout, " h_name: [%s]\n", host->h_name); - if (host->h_aliases != NULL) { - for (hn = host->h_aliases; *hn != NULL; hn++) - (void) fprintf(stdout, " h_aliases: [%s]\n", *hn); - } - (void) fprintf(stdout, " h_addrtype: [%d]\n", host->h_addrtype); - (void) fprintf(stdout, " h_length: [%d]\n", host->h_length); - for (ha = host->h_addr_list; *ha != NULL; ha++) { - (void) memcpy(&in.s_addr, *ha, sizeof (in.s_addr)); - if (inet_ntoa(in) != NULL) - (void) fprintf(stdout, " h_addr_list: [%s]\n", - inet_ntoa(in)); + /* Filter cname that's identical to h_name */ + if (first_entry) { + h_name = cname; + first_entry = 0; + copy_cname = 1; + } else if (strcasecmp(cname, h_name) != 0) { + copy_cname = 1; + } else + copy_cname = 0; + + if (copy_cname) { + /* Use the canonical name as the host name */ + if (DOTTEDSUBDOMAIN(cname)) + len = snprintf(buf1, buflen1, " %s", cname); else - (void) fprintf(stdout, " h_addr_list: <NULL>\n"); - } -#endif /* DEBUG */ + /* append domain name */ + len = snprintf(buf1, buflen1, " %s.%s", cname, + be->toglue); -result_hosts2ent: + TEST_AND_ADJUST(len, buf1, buflen1, result_host2str); + } + + /* Append aliases */ + for (i = 0; i < names->value_count; i++) { + name = names->attrvalue[i]; + if (name == NULL) { + nss_result = NSS_STR_PARSE_PARSE; + goto result_host2str; + } + /* Skip the canonical name and h_name */ + if (strcasecmp(name, cname) != 0 && + strcasecmp(name, h_name) != 0) { + if (DOTTEDSUBDOMAIN(name)) + len = snprintf(buf1, buflen1, " %s", name); + else + /* append domain name */ + len = snprintf(buf1, buflen1, " %s.%s", + name, be->toglue); + TEST_AND_ADJUST(len, buf1, buflen1, result_host2str); + } + } + } + if (validaddress == 0) { + /* + * For AF_INET mode, it found an IPv6 address and skipped it. + */ + nss_result = NSS_STR_PARSE_NO_ADDR; + goto result_host2str; + } + /* Combine 2 strings */ + len = snprintf(buffer, buflen, "%s%s", first_host, other_hosts); + TEST_AND_ADJUST(len, buffer, buflen, result_host2str); + + /* The front end marshaller doesn't need to copy trailing nulls */ + if (argp->buf.result != NULL) + be->buflen = strlen(be->buffer); + +result_host2str: + if (first_host) + free(first_host); + if (other_hosts) + free(other_hosts); (void) __ns_ldap_freeResult(&be->result); - return ((int)nss_result); + return (nss_result); } +static int +_nss_ldap_hosts2str(ldap_backend_ptr be, nss_XbyY_args_t *argp) { + return (_nss_ldap_hosts2str_int(AF_INET, be, argp)); +} /* * getbyname gets a struct hostent by hostname. This function constructs @@ -484,10 +425,7 @@ _nss_ldap_hosts_constr(const char *dummy1, const char *dummy2, const char *dummy3) { -#ifdef DEBUG - (void) fprintf(stdout, "\n[gethostent.c: _nss_ldap_hosts_constr]\n"); -#endif /* DEBUG */ return ((nss_backend_t *)_nss_ldap_constr(hosts_ops, sizeof (hosts_ops)/sizeof (hosts_ops[0]), _HOSTS, - hosts_attrs, _nss_ldap_hosts2ent)); + hosts_attrs, _nss_ldap_hosts2str)); } diff --git a/usr/src/lib/nsswitch/ldap/common/gethostent6.c b/usr/src/lib/nsswitch/ldap/common/gethostent6.c index 8b0a453d69..1fad135afa 100644 --- a/usr/src/lib/nsswitch/ldap/common/gethostent6.c +++ b/usr/src/lib/nsswitch/ldap/common/gethostent6.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,17 +19,17 @@ * CDDL HEADER END */ /* - * Copyright 2003 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #pragma ident "%Z%%M% %I% %E% SMI" #include <netdb.h> -#include <netinet/in.h> +#include <sys/types.h> #include <sys/socket.h> -#include <inet/ip6.h> -#include <syslog.h> +#include <netinet/in.h> +#include <arpa/inet.h> #include <sys/systeminfo.h> #include "ns_internal.h" #include "ldap_common.h" @@ -57,254 +56,24 @@ static const char *ipnodes_attrs[] = { (char *)NULL }; -extern int inet_pton(int, const char *, void *); -const char *inet_ntop(int af, const void *src, char *dst, size_t size); +extern int +_nss_ldap_hosts2str_int(int af, ldap_backend_ptr be, nss_XbyY_args_t *argp); /* - * _nss_ldap_hosts2ent is the data marshaling method for the ipnodes getXbyY - * system call gethostbyname() and gethostbyaddr. The format of this call - * is a cononical name and alias (alias is cononical name too) and one or - * more IP addresses in support of multihomed hosts. This method is called - * after a successful synchronous search has been performed. This method - * will parse the search results into struct hostent = argp->buf.buffer - * which gets returned to the frontend process. One of three error - * conditions is also returned to nsswitch. + * _nss_ldap_hosts2str is the data marshaling method for the ipnodes getXbyY + * system call gethostbyname() and gethostbyaddr. + * This method is called after a successful search has been performed. + * This method will parse the search results into the file format. + * e.g. + * + * fe80::a00:20ff:fec4:f2b6 ipnodes_1 + * */ - static int -_nss_ldap_hosts2ent(ldap_backend_ptr be, nss_XbyY_args_t *argp) -{ - int i, j; - int nss_result; - int buflen = (int)0; - int firstimename = (int)1; - int firstimedn = (int)1; - int firstimeaddr = (int)1; - unsigned long len = 0L; - char **hn, **ha, **dp; - char *cname = (char *)NULL; - char *buffer = (char *)NULL; - char *ceiling = (char *)NULL; - struct hostent *host = (struct hostent *)NULL; - struct in6_addr addr6; - struct in_addr addr; - char *val; - ns_ldap_result_t *result = be->result; - ns_ldap_attr_t *attrptr; - int namecount = 0; - int addrcount = 0; - int aliascount = 0; - int gluelen = 0; - ns_ldap_entry_t *entry; - ns_ldap_attr_t *attr; - - buffer = argp->buf.buffer; - buflen = (size_t)argp->buf.buflen; - if (!argp->buf.result) { - nss_result = (int)NSS_STR_PARSE_ERANGE; - goto result_hosts2ent; - } - host = (struct hostent *)argp->buf.result; - ceiling = buffer + buflen; - - nss_result = (int)NSS_STR_PARSE_SUCCESS; - (void) memset(argp->buf.buffer, 0, buflen); - - attrptr = getattr(result, 0); - if (attrptr == NULL) { - nss_result = (int)NSS_STR_PARSE_PARSE; - goto result_hosts2ent; - } - - for (entry = result->entry; entry != NULL; entry = entry->next) { - for (i = 0, attr = entry->attr_pair[i]; - i < entry->attr_count; i++) { - attr = entry->attr_pair[i]; - if (strcasecmp(attr->attrname, _H_NAME) == 0) - namecount += attr->value_count; - if (strcasecmp(attr->attrname, _H_ADDR) == 0) - addrcount += attr->value_count; - } - } - - for (entry = result->entry; entry != NULL; entry = entry->next) { - for (i = 0; i < entry->attr_count; i++) { - attrptr = entry->attr_pair[i]; - if (attrptr == NULL) { - nss_result = (int)NSS_STR_PARSE_PARSE; - goto result_hosts2ent; - } - if (strcasecmp(attrptr->attrname, _H_DN) == 0) { - for (j = 0; j < attrptr->value_count; j++) { - if (firstimedn) { - /* get domain name associated with this dn */ - be->toglue = _get_domain_name( - attrptr->attrvalue[j]); - firstimedn = (int)0; - } - } - } - if (strcasecmp(attrptr->attrname, _H_NAME) == 0) { - for (j = 0; j < attrptr->value_count; j++) { - if (firstimename) { - /* canonical name */ - cname = __s_api_get_canonical_name(result->entry, - attrptr, 1); - if (cname == NULL || - (len = strlen(cname)) < 1) { - nss_result = (int)NSS_STR_PARSE_PARSE; - goto result_hosts2ent; - } - if (be->toglue != NULL && - !DOTTEDSUBDOMAIN(cname)) - gluelen = strlen(be->toglue) + 1; - else - gluelen = 0; - host->h_name = buffer; - buffer += len + gluelen + 1; - if (buffer >= ceiling) { - nss_result = (int)NSS_STR_PARSE_ERANGE; - goto result_hosts2ent; - } - (void) strcpy(host->h_name, cname); - if (gluelen > 0) { - (void) strcat(host->h_name, "."); - (void) strcat(host->h_name, be->toglue); - } - /* alias name */ - aliascount = (namecount >= 1 ? (namecount - 1) : 0); - hn = host->h_aliases = - (char **)ROUND_UP(buffer, sizeof (char **)); - buffer = (char *)host->h_aliases + - sizeof (char *) * (aliascount + 1); - buffer = (char *)ROUND_UP(buffer, sizeof (char **)); - if (buffer >= ceiling) { - nss_result = (int)NSS_STR_PARSE_ERANGE; - goto result_hosts2ent; - } - firstimename = (int)0; - } - /* alias list */ - if (aliascount > 0) { - if ((attrptr->attrvalue[j] == NULL) || - (len = strlen(attrptr->attrvalue[j])) < 1) { - nss_result = (int)NSS_STR_PARSE_PARSE; - goto result_hosts2ent; - } - /* skip canonical name */ - if (strcmp(attrptr->attrvalue[j], cname) == 0) - continue; - /* check for duplicates */ - for (dp = host->h_aliases; *dp != NULL; dp++) { - if (strcmp(*dp, attrptr->attrvalue[j]) == 0) - goto next_alias; - } - if (be->toglue != NULL && - !DOTTEDSUBDOMAIN(attrptr->attrvalue[j])) - gluelen = strlen(be->toglue) + 1; - else - gluelen = 0; - *hn = buffer; - buffer += len + gluelen + 1; - if (buffer >= ceiling) { - nss_result = (int)NSS_STR_PARSE_ERANGE; - goto result_hosts2ent; - } - (void) strcpy(*hn, attrptr->attrvalue[j]); - if (gluelen > 0) { - (void) strcat(*hn, "."); - (void) strcat(*hn, be->toglue); - } - hn++; - } -next_alias: - continue; - } - } - } - } - - for (entry = result->entry; entry != NULL; entry = entry->next) { - for (i = 0; i < entry->attr_count; i++) { - attrptr = entry->attr_pair[i]; - if (attrptr == NULL) { - nss_result = (int)NSS_STR_PARSE_PARSE; - goto result_hosts2ent; - } - - if (strcasecmp(attrptr->attrname, _H_ADDR) == 0) { - for (j = 0; j < attrptr->value_count; j++) { - if (firstimeaddr) { - /* allocate 1 address per entry */ - ha = host->h_addr_list = (char **)ROUND_UP(buffer, - sizeof (char **)); - buffer = (char *)host->h_addr_list + - sizeof (char *) * (addrcount + 1); - buffer = (char *)ROUND_UP(buffer, sizeof (char **)); - if (buffer >= ceiling) { - nss_result = (int)NSS_STR_PARSE_ERANGE; - goto result_hosts2ent; - } - firstimeaddr = (int)0; - } - val = (char *)_strip_quotes(attrptr->attrvalue[j]); - if (inet_pton(AF_INET6, val, (void *) &addr6) != 1) { - if (inet_pton(AF_INET, val, (void *) &addr) != 1) { - goto next_addr; - } else { - IN6_INADDR_TO_V4MAPPED(&addr, &addr6); - } - } - - /* check for duplicates */ - for (dp = host->h_addr_list; *dp != NULL; dp++) { - if (memcmp(*dp, &addr6, sizeof (struct in6_addr)) - == 0) - goto next_addr; - } - *ha = buffer; - len = (unsigned long)sizeof (struct in6_addr); - buffer += len; - if (buffer >= ceiling) { - nss_result = (int)NSS_STR_PARSE_ERANGE; - goto result_hosts2ent; - } - (void) memcpy(*ha++, (char *)&addr6, (size_t)len); -next_addr: - continue; - } - } - } - } - - host->h_addrtype = AF_INET6; - host->h_length = IPV6_ADDR_LEN; - -#ifdef DEBUG - (void) fprintf(stdout, "\n[gethostent.c: _nss_ldap_byname2ent]\n"); - (void) fprintf(stdout, " h_name: [%s]\n", host->h_name); - if (host->h_aliases != NULL) { - for (hn = host->h_aliases; *hn != NULL; hn++) - (void) fprintf(stdout, " h_aliases: [%s]\n", *hn); - } - (void) fprintf(stdout, " h_addrtype: [%d]\n", host->h_addrtype); - (void) fprintf(stdout, " h_length: [%d]\n", host->h_length); - - for (hn = host->h_addr_list; *hn != NULL; hn++) { - char addrbuf[INET6_ADDRSTRLEN + 1]; - (void) fprintf(stdout, " haddr_list: [%s]\n", - inet_ntop(AF_INET6, (void *)hn, (void *)addrbuf, - INET6_ADDRSTRLEN)); - } -#endif /* DEBUG */ - -result_hosts2ent: - - (void) __ns_ldap_freeResult(&be->result); - return ((int)nss_result); +_nss_ldap_hosts2str(ldap_backend_ptr be, nss_XbyY_args_t *argp) { + return (_nss_ldap_hosts2str_int(AF_INET6, be, argp)); } - /* * getbyname gets a struct hostent by hostname. This function constructs * an ldap search filter using the name invocation parameter and the @@ -325,10 +94,6 @@ getbyname(ldap_backend_ptr be, void *a) char userdata[SEARCHFILTERLEN]; int rc; -#ifdef DEBUG - (void) fprintf(stdout, "\n[gethostent6.c: getbyname]\n"); -#endif /* DEBUG */ - if (_ldap_filter_name(hostname, argp->key.ipnode.name, sizeof (hostname)) != 0) return ((nss_status_t)NSS_NOTFOUND); @@ -432,9 +197,6 @@ getbyaddr(ldap_backend_ptr be, void *a) char userdata[SEARCHFILTERLEN]; int ret; -#ifdef DEBUG - (void) fprintf(stdout, "\n[gethostent6.c: getbyaddr]\n"); -#endif /* DEBUG */ argp->h_errno = 0; if ((argp->key.hostaddr.type != AF_INET6) || (argp->key.hostaddr.len != sizeof (addr))) @@ -493,10 +255,7 @@ _nss_ldap_ipnodes_constr(const char *dummy1, const char *dummy2, const char *dummy3) { -#ifdef DEBUG - (void) fprintf(stdout, "\n[gethostent6.c: _nss_ldap_host6_constr]\n"); -#endif /* DEBUG */ return ((nss_backend_t *)_nss_ldap_constr(ipnodes_ops, sizeof (ipnodes_ops)/sizeof (ipnodes_ops[0]), _HOSTS6, - ipnodes_attrs, _nss_ldap_hosts2ent)); + ipnodes_attrs, _nss_ldap_hosts2str)); } diff --git a/usr/src/lib/nsswitch/ldap/common/getkeyent.c b/usr/src/lib/nsswitch/ldap/common/getkeyent.c index c1c9dbd381..95f27cddb9 100644 --- a/usr/src/lib/nsswitch/ldap/common/getkeyent.c +++ b/usr/src/lib/nsswitch/ldap/common/getkeyent.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2003 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -49,69 +48,58 @@ static const char *keys_attrs[] = { /* - * _nss_ldap_key2ent is the data marshaling method for the publickey getXbyY + * _nss_ldap_key2str is the data marshaling method for the publickey getXbyY * (e.g., getpublickey() and getsecretkey()) backend processes. This method * is called after a successful ldap search has been performed. This method - * will parse the ldap search values into "public:secret" key string = - * argp->buf.buffer which the frontend process expects. Three error - * conditions are expected and returned to nsswitch. + * will parse the ldap search values into "public:secret" file format. + * + * c3d91f44568fbbefada50d336d9bd67b16e7016f987bb607: + * 7675cd9b8753b5db09dabf12da759c2bd1331c927bb322861fffb54be13f55e9 + * + * (All in one line) + * + * Publickey does not have a front end marshaller so db_type is set + * for special handling. */ static int -_nss_ldap_key2ent(ldap_backend_ptr be, nss_XbyY_args_t *argp) +_nss_ldap_key2str(ldap_backend_ptr be, nss_XbyY_args_t *argp) { int nss_result; char *keytype = (char *)argp->key.pkey.keytype; int keytypelen = strlen(keytype); - char *key_start = NULL; - int key_len; - int buflen = (size_t)argp->buf.buflen; - char *buffer = (char *)argp->buf.buffer; - char *ceiling = (char *)NULL; + int len; + int buflen = argp->buf.buflen; + char *buffer, *pkey, *skey; ns_ldap_result_t *result = be->result; - char **key_array; - -#ifdef DEBUG - (void) fprintf(stdout, "\n[getpublikey.c: _nss_ldap_passwd2ent]\n"); -#endif /* DEBUG */ + char **pkey_array, **skey_array; - if (!argp->buf.result) { - nss_result = (int)NSS_STR_PARSE_ERANGE; - goto result_key2ent; + if (result == NULL || keytype == NULL) { + nss_result = NSS_STR_PARSE_ERANGE; + goto result_key2str; } - ceiling = buffer + buflen; - nss_result = (int)NSS_STR_PARSE_SUCCESS; - (void) memset(buffer, 0, buflen); - + nss_result = NSS_STR_PARSE_SUCCESS; + (void) memset(argp->buf.buffer, 0, buflen); /* get the publickey */ - key_array = __ns_ldap_getAttr(result->entry, _KEY_NISPUBLICKEY); - if (key_array == NULL) { - nss_result = (int)NSS_STR_PARSE_PARSE; - goto result_key2ent; + pkey_array = __ns_ldap_getAttr(result->entry, _KEY_NISPUBLICKEY); + if (pkey_array == NULL) { + nss_result = NSS_STR_PARSE_PARSE; + goto result_key2str; } - while (*key_array) { - if (strncasecmp(*key_array, keytype, keytypelen) == NULL) + while (*pkey_array) { + if (strncasecmp(*pkey_array, keytype, keytypelen) == NULL) break; - key_array++; - } - if (*key_array == NULL) { - nss_result = (int)NSS_STR_PARSE_PARSE; - goto result_key2ent; + pkey_array++; } - - key_start = *(key_array) + keytypelen; - key_len = strlen(key_start) + 1; - if (buffer + key_len + 2 > ceiling) { - nss_result = (int)NSS_STR_PARSE_ERANGE; - goto result_key2ent; + if (*pkey_array == NULL) { + nss_result = NSS_STR_PARSE_PARSE; + goto result_key2str; } - (void) strncpy(buffer, key_start, key_len); - (void) strcat(buffer, ":"); - buffer += strlen(buffer); + pkey = *pkey_array + keytypelen; /* get the secretkey */ - key_array = __ns_ldap_getAttr(result->entry, _KEY_NISSECRETKEY); - if (key_array == NULL) { + skey_array = __ns_ldap_getAttr(result->entry, _KEY_NISSECRETKEY); + if (skey_array == NULL) { /* * if we got this far, it's possible that the secret * key is actually missing or no permission to read it. @@ -120,33 +108,37 @@ _nss_ldap_key2ent(ldap_backend_ptr be, nss_XbyY_args_t *argp) * the only possibility of reaching this here is due to * missing secret key. */ - nss_result = (int)NSS_STR_PARSE_PARSE; - goto result_key2ent; + nss_result = NSS_STR_PARSE_PARSE; + goto result_key2str; } - while (*key_array) { - if (strncasecmp(*key_array, keytype, keytypelen) == NULL) + while (*skey_array) { + if (strncasecmp(*skey_array, keytype, keytypelen) == NULL) break; - key_array++; + skey_array++; } - if (*key_array == NULL) { - nss_result = (int)NSS_STR_PARSE_PARSE; - goto result_key2ent; + if (*skey_array == NULL) { + nss_result = NSS_STR_PARSE_PARSE; + goto result_key2str; } + skey = *skey_array + keytypelen; - key_start = *(key_array) + keytypelen; - key_len = strlen(key_start); - if (buffer + key_len + 1 > ceiling) { - nss_result = (int)NSS_STR_PARSE_ERANGE; - goto result_key2ent; + /* 2 = 1 ':' + 1 '\0' */ + len = strlen(pkey) + strlen(skey) + 2; + if (len > buflen) { + nss_result = NSS_STR_PARSE_ERANGE; + goto result_key2str; } - (void) strcat(buffer, key_start); + /* + * publickey does not have a frontend marshaller. + * copy the result to buf.buffer directly + */ + buffer = argp->buf.buffer; + + (void) snprintf(buffer, len, "%s:%s", pkey, skey); -#ifdef DEBUG - (void) fprintf(stdout, "\n[getkeys.c: _nss_ldap_key2ent]\n"); - (void) fprintf(stdout, "\treturn: %s\n", buffer); -#endif /* DEBUG */ + be->db_type = NSS_LDAP_DB_PUBLICKEY; -result_key2ent: +result_key2str: (void) __ns_ldap_freeResult(&be->result); return ((int)nss_result); @@ -176,10 +168,6 @@ getkeys(ldap_backend_ptr be, void *a) nss_status_t rc; int ret; -#ifdef DEBUG - (void) fprintf(stdout, "\n[getpwnam.c: getbyname]\n"); -#endif /* DEBUG */ - /* * We need to break it down to find if this is a netname for host * or user. We'll pass the domain as is to the LDAP call. @@ -187,6 +175,7 @@ getkeys(ldap_backend_ptr be, void *a) if (_ldap_filter_name(netname, argp->key.pkey.name, sizeof (netname)) != 0) return ((nss_status_t)NSS_NOTFOUND); + domain = strchr(netname, '@'); if (!domain) return ((nss_status_t)NSS_NOTFOUND); @@ -252,11 +241,7 @@ _nss_ldap_publickey_constr(const char *dummy1, const char *dummy2, const char *dummy3) { -#ifdef DEBUG - (void) fprintf(stdout, "\n[getkeys.c: _nss_ldap_keys_constr]\n"); -#endif /* DEBUG */ - return ((nss_backend_t *)_nss_ldap_constr(keys_ops, sizeof (keys_ops)/sizeof (keys_ops[0]), - _PUBLICKEY, keys_attrs, _nss_ldap_key2ent)); + _PUBLICKEY, keys_attrs, _nss_ldap_key2str)); } diff --git a/usr/src/lib/nsswitch/ldap/common/getnetent.c b/usr/src/lib/nsswitch/ldap/common/getnetent.c index a5afb360ce..d042e0fe2b 100644 --- a/usr/src/lib/nsswitch/ldap/common/getnetent.c +++ b/usr/src/lib/nsswitch/ldap/common/getnetent.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2003 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -38,8 +37,10 @@ #define _N_NETWORK "ipnetworknumber" #define _F_GETNETBYNAME "(&(objectClass=ipNetwork)(cn=%s))" #define _F_GETNETBYNAME_SSD "(&(%%s)(cn=%s))" -#define _F_GETNETBYADDR "(&(objectClass=ipNetwork)(ipNetworkNumber=%s))" -#define _F_GETNETBYADDR_SSD "(&(%%s)(ipNetworkNumber=%s))" +#define _F_GETNETBYADDR "(&(objectClass=ipNetwork)(|(ipNetworkNumber=%s)" \ + "(ipNetworkNumber=%s)))" +#define _F_GETNETBYADDR_SSD "(&(%%s)(|(ipNetworkNumber=%s)" \ + "(ipNetworkNumber=%s)))" static const char *networks_attrs[] = { _N_NAME, @@ -48,187 +49,119 @@ static const char *networks_attrs[] = { }; /* - * _nss_ldap_networks2ent is the data marshaling method for the networks + * _nss_ldap_networks2str is the data marshaling method for the networks * getXbyY * (e.g., getbyname(), getbyaddr(), getnetent() backend processes. * This method is called after a successful ldap search has been performed. - * This method will parse the ldap search values into struct netent = - * argp->buf.buffer which the frontend process expects. Three error conditions - * are expected and returned to nsswitch. + * This method will parse the ldap search values into the file format. + * e.g. + * + * SunRay-ce2 10.34.96.0 SunRay + * */ - static int -_nss_ldap_networks2ent(ldap_backend_ptr be, nss_XbyY_args_t *argp) +_nss_ldap_networks2str(ldap_backend_ptr be, nss_XbyY_args_t *argp) { - int i, j; + uint_t i; int nss_result; - int buflen = (int)0; - int firstime = (int)1; - unsigned long len = 0L; - char **mp, *cname = NULL; -#ifdef DEBUG - char addrstr[16]; -#endif /* DEBUG */ - char *buffer = (char *)NULL; - char *ceiling = (char *)NULL; - struct netent *ntk = (struct netent *)NULL; + int buflen = 0, len; + char **network, *cname = NULL; + char *buffer = NULL; ns_ldap_result_t *result = be->result; - ns_ldap_attr_t *attrptr; + ns_ldap_attr_t *names; - buffer = argp->buf.buffer; - buflen = (size_t)argp->buf.buflen; - if (!argp->buf.result) { - nss_result = (int)NSS_STR_PARSE_ERANGE; - goto result_net2ent; - } - ntk = (struct netent *)argp->buf.result; - ceiling = buffer + buflen; + if (result == NULL) + return (NSS_STR_PARSE_PARSE); + buflen = argp->buf.buflen; - nss_result = (int)NSS_STR_PARSE_SUCCESS; + if (argp->buf.result != NULL) { + if ((be->buffer = calloc(1, buflen)) == NULL) { + nss_result = NSS_STR_PARSE_PARSE; + goto result_net2str; + } + buffer = be->buffer; + } else + buffer = argp->buf.buffer; + + nss_result = NSS_STR_PARSE_SUCCESS; (void) memset(argp->buf.buffer, 0, buflen); - attrptr = getattr(result, 0); - if (attrptr == NULL) { - nss_result = (int)NSS_STR_PARSE_PARSE; - goto result_net2ent; + names = __ns_ldap_getAttrStruct(result->entry, _N_NAME); + if (names == NULL || names->attrvalue == NULL) { + nss_result = NSS_STR_PARSE_PARSE; + goto result_net2str; } - - for (i = 0; i < result->entry->attr_count; i++) { - attrptr = getattr(result, i); - if (attrptr == NULL) { - nss_result = (int)NSS_STR_PARSE_PARSE; - goto result_net2ent; - } - if (strcasecmp(attrptr->attrname, _N_NAME) == 0) { - for (j = 0; j < attrptr->value_count; j++) { - if (firstime) { - /* - * The definition of the object class - * "ipNetwork" has a descripency between - * RFC 2307 and 2307bis. - * In 2307, "cn" is a MUST attribute. - * In 2307bis, "cn" is a MAY attribute. - * If "cn" is a MAY attribute, - * it does not appear in RDN and can't - * be derived from RDN as a canonical - * "cn" name. In that case, use 1st - * "cn" value as the official name. - */ - cname = __s_api_get_canonical_name( - result->entry, attrptr, 1); - if (cname == NULL) - /* 2307bis case */ - cname = attrptr->attrvalue[j]; - - if (cname == NULL || - (len = strlen(cname)) < 1) { - nss_result = - NSS_STR_PARSE_PARSE; - goto result_net2ent; - } - ntk->n_name = buffer; - buffer += len + 1; - if (buffer >= ceiling) { - nss_result = - (int)NSS_STR_PARSE_ERANGE; - goto result_net2ent; - } - (void) strcpy(ntk->n_name, cname); - /* alias list */ - mp = ntk->n_aliases = - (char **)ROUND_UP(buffer, - sizeof (char **)); - buffer = (char *)ntk->n_aliases + - sizeof (char *) * - (attrptr->value_count + 1); - buffer = (char *)ROUND_UP(buffer, - sizeof (char **)); - if (buffer >= ceiling) { - nss_result = - (int)NSS_STR_PARSE_ERANGE; - goto result_net2ent; - } - firstime = (int)0; - } - /* alias list */ - if ((attrptr->attrvalue[j] == NULL) || - (len = strlen(attrptr->attrvalue[j])) < 1) { - nss_result = (int)NSS_STR_PARSE_PARSE; - goto result_net2ent; - } - /* skip canonical name(official name) */ - if (strcmp(attrptr->attrvalue[j], cname) == 0) - continue; - *mp = buffer; - buffer += len + 1; - if (buffer >= ceiling) { - nss_result = (int)NSS_STR_PARSE_ERANGE; - goto result_net2ent; - } - (void) strcpy(*mp++, attrptr->attrvalue[j]); - continue; - } + /* Get the canonical name */ + cname = __s_api_get_canonical_name(result->entry, names, 1); + /* + * The definition of the object class "ipNetwork" has a + * discrepency between RFC 2307 and 2307bis. + * In 2307, "cn" is a MUST attribute. In 2307bis, "cn" is a + * MAY attribute. + * If "cn" is a MAY attribute, it does not appear in RDN and can't + * be derived from RDN as a canonical "cn" name. In that case, use 1st + * "cn" value as the official name. + */ + if (cname == NULL) + /* 2307bis case */ + cname = names->attrvalue[0]; + if (cname == NULL || (len = strlen(cname)) < 1) { + nss_result = NSS_STR_PARSE_PARSE; + goto result_net2str; + } + network = __ns_ldap_getAttr(result->entry, _N_NETWORK); + if (network == NULL || network[0] == NULL || + (len = strlen(network[0])) < 1) { + nss_result = NSS_STR_PARSE_PARSE; + goto result_net2str; + } + len = snprintf(buffer, buflen, "%s %s", cname, network[0]); + TEST_AND_ADJUST(len, buffer, buflen, result_net2str); + /* Append aliases */ + for (i = 0; i < names->value_count; i++) { + if (names->attrvalue[i] == NULL) { + nss_result = NSS_STR_PARSE_PARSE; + goto result_net2str; } - if (strcasecmp(attrptr->attrname, _N_NETWORK) == 0) { - if ((attrptr->attrvalue[0] == NULL) || - (len = strlen(attrptr->attrvalue[0])) < 1) { - nss_result = (int)NSS_STR_PARSE_PARSE; - goto result_net2ent; - } - if ((ntk->n_net = (in_addr_t) - inet_network(attrptr->attrvalue[0])) == - (in_addr_t)-1) { - nss_result = (int)NSS_STR_PARSE_PARSE; - goto result_net2ent; - } -#ifdef DEBUG - strlcpy(addrstr, attrptr->attrvalue[0], - sizeof (addrstr)); -#endif /* DEBUG */ - continue; + /* Skip the canonical name */ + if (strcasecmp(names->attrvalue[i], cname) != 0) { + len = snprintf(buffer, buflen, " %s", + names->attrvalue[i]); + TEST_AND_ADJUST(len, buffer, buflen, result_net2str); } } - ntk->n_addrtype = AF_INET; - -#ifdef DEBUG - (void) fprintf(stdout, "\n[getnetent.c: _nss_ldap_networks2ent]\n"); - (void) fprintf(stdout, " n_name: [%s]\n", ntk->n_name); - if (mp != NULL) { - for (mp = ntk->n_aliases; *mp != NULL; mp++) - (void) fprintf(stdout, " n_aliases: [%s]\n", *mp); - } - if (ntk->n_addrtype == AF_INET) - (void) fprintf(stdout, " n_addrtype: [AF_INET]\n"); - else - (void) fprintf(stdout, " n_addrtype: [%d]\n", - ntk->n_addrtype); - (void) fprintf(stdout, " n_net: [%s]\n", addrstr); -#endif /* DEBUG */ -result_net2ent: + /* The front end marshaller doesn't need to copy trailing nulls */ + if (argp->buf.result != NULL) + be->buflen = strlen(be->buffer); + +result_net2str: (void) __ns_ldap_freeResult(&be->result); - return ((int)nss_result); + return (nss_result); } - /* * Takes an unsigned integer in host order, and returns a printable * string for it as a network number. To allow for the possibility of * naming subnets, only trailing dot-zeros are truncated. + * buf2 is untruncated version. */ -static int nettoa(int anet, char *buf, int buflen) +static int nettoa(int anet, char *buf, char *buf2, int buflen) { int addr; char *p; struct in_addr in; - if (buf == 0) + if (buf == NULL || buf2 == NULL) return ((int)1); in = inet_makeaddr(anet, INADDR_ANY); addr = in.s_addr; - if (strlcpy(buf, inet_ntoa(in), buflen) >= buflen) + if (inet_ntop(AF_INET, (const void *)&in, buf2, INET_ADDRSTRLEN) + == NULL) + return ((int)1); + if (strlcpy(buf, buf2, buflen) >= buflen) return ((int)1); if ((IN_CLASSA_HOST & htonl(addr)) == 0) { p = strchr(buf, '.'); @@ -304,21 +237,22 @@ static nss_status_t getbyaddr(ldap_backend_ptr be, void *a) { nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a; - char addrstr[16]; + char addrstr[INET_ADDRSTRLEN], addrstr2[INET_ADDRSTRLEN]; char searchfilter[SEARCHFILTERLEN]; char userdata[SEARCHFILTERLEN]; int ret; - if (nettoa((int)argp->key.netaddr.net, addrstr, 16) != 0) + if (nettoa((int)argp->key.netaddr.net, addrstr, addrstr2, + INET_ADDRSTRLEN) != 0) return ((nss_status_t)NSS_UNAVAIL); ret = snprintf(searchfilter, sizeof (searchfilter), - _F_GETNETBYADDR, addrstr); + _F_GETNETBYADDR, addrstr, addrstr2); if (ret >= sizeof (searchfilter) || ret < 0) return ((nss_status_t)NSS_NOTFOUND); ret = snprintf(userdata, sizeof (userdata), - _F_GETNETBYADDR_SSD, addrstr); + _F_GETNETBYADDR_SSD, addrstr, addrstr2); if (ret >= sizeof (userdata) || ret < 0) return ((nss_status_t)NSS_NOTFOUND); @@ -351,5 +285,5 @@ _nss_ldap_networks_constr(const char *dummy1, const char *dummy2, return ((nss_backend_t *)_nss_ldap_constr(net_ops, sizeof (net_ops)/sizeof (net_ops[0]), _NETWORKS, - networks_attrs, _nss_ldap_networks2ent)); + networks_attrs, _nss_ldap_networks2str)); } diff --git a/usr/src/lib/nsswitch/ldap/common/getnetgrent.c b/usr/src/lib/nsswitch/ldap/common/getnetgrent.c index 01728e3420..d3072440f2 100644 --- a/usr/src/lib/nsswitch/ldap/common/getnetgrent.c +++ b/usr/src/lib/nsswitch/ldap/common/getnetgrent.c @@ -890,7 +890,7 @@ netgr_set(ldap_backend_ptr be, void *a) get_be->tablename = NULL; get_be->attrs = netgrent_attrs; get_be->result = NULL; - get_be->ldapobj2ent = NULL; + get_be->ldapobj2str = NULL; get_be->setcalled = 1; get_be->filter = NULL; get_be->toglue = NULL; diff --git a/usr/src/lib/nsswitch/ldap/common/getnetmasks.c b/usr/src/lib/nsswitch/ldap/common/getnetmasks.c index 69ef802520..2e6f28053e 100644 --- a/usr/src/lib/nsswitch/ldap/common/getnetmasks.c +++ b/usr/src/lib/nsswitch/ldap/common/getnetmasks.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2003 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -47,80 +46,61 @@ static const char *netmasks_attrs[] = { /* - * _nss_ldap_netmasks2ent is the data marshaling method for the netmasks - * getXbyY * (e.g., getbynet()) backend processes. This method is called - * after a successful ldap search has been performed. This method will - * parse the ldap search values into struct in_addr *mask = argp->buf.result - * only if argp->buf.result is initialized (not NULL). Three error - * conditions are expected and returned to nsswitch. + * _nss_ldap_netmasks2str is the data marshaling method for the netmasks + * getXbyY * (e.g., getnetmaskby[net|addr]()) backend processes. + * This method is called after a successful ldap search has been performed. + * This method will parse the ldap search values into the file format. + * + * getnetmaskbykey set argp->buf.buffer to NULL and argp->buf.buflen to 0 + * and argp->buf.result to non-NULL. + * The front end marshaller str2add expects "netmask" only + * + * e.g. + * + * 255.255.255.0 + * + * */ static int -_nss_ldap_netmasks2ent(ldap_backend_ptr be, nss_XbyY_args_t *argp) +_nss_ldap_netmasks2str(ldap_backend_ptr be, nss_XbyY_args_t *argp) { - int i, j; - int nss_result; - unsigned long len = 0L; -#ifdef DEBUG - char maskstr[16]; -#endif /* DEBUG */ - struct in_addr addr; - struct in_addr *mask = (struct in_addr *)NULL; + int nss_result, len; ns_ldap_result_t *result = be->result; - ns_ldap_attr_t *attrptr; + char *buffer, **netmask; - mask = (struct in_addr *)argp->buf.result; - nss_result = (int)NSS_STR_PARSE_SUCCESS; + if (result == NULL) + return (NSS_STR_PARSE_PARSE); - attrptr = getattr(result, 0); - if (attrptr == NULL) { - nss_result = (int)NSS_STR_PARSE_PARSE; - goto result_nmks2ent; - } + nss_result = NSS_STR_PARSE_SUCCESS; - for (i = 0; i < result->entry->attr_count; i++) { - attrptr = getattr(result, i); - if (attrptr == NULL) { - nss_result = (int)NSS_STR_PARSE_PARSE; - goto result_nmks2ent; - } - if (strcasecmp(attrptr->attrname, _N_NETMASK) == 0) { - for (j = 0; j < attrptr->value_count; j++) { - if (mask == NULL) - continue; - if ((attrptr->attrvalue[j] == NULL) || - (len = strlen(attrptr->attrvalue[j])) < 1) { - nss_result = (int)NSS_STR_PARSE_PARSE; - goto result_nmks2ent; - } - /* addr a IPv4 address and 32 bits */ - addr.s_addr = inet_addr(attrptr->attrvalue[j]); - if (addr.s_addr == 0xffffffffUL) { - nss_result = (int)NSS_STR_PARSE_PARSE; - goto result_nmks2ent; - } - mask->s_addr = addr.s_addr; -#ifdef DEBUG - strlcpy(maskstr, attrptr->attrvalue[j], - sizeof (maskstr)); -#endif /* DEBUG */ - continue; - } - } + netmask = __ns_ldap_getAttr(result->entry, _N_NETMASK); + if (netmask == NULL || netmask[0] == NULL || + (strlen(netmask[0]) < 1)) { + nss_result = NSS_STR_PARSE_PARSE; + goto result_nmks2str; } + /* Add a trailing null for debugging purpose */ + len = strlen(netmask[0]) + 1; + if (argp->buf.result != NULL) { + if ((be->buffer = calloc(1, len)) == NULL) { + nss_result = NSS_STR_PARSE_PARSE; + goto result_nmks2str; + } + be->buflen = len - 1; + buffer = be->buffer; + } else + buffer = argp->buf.buffer; -#ifdef DEBUG - (void) fprintf(stdout, "\n[netmasks.c: _nss_ldap_netmasks2ent]\n"); - (void) fprintf(stdout, " netmask: [%s]\n", maskstr); -#endif /* DEBUG */ -result_nmks2ent: + (void) snprintf(buffer, len, "%s", netmask[0]); + +result_nmks2str: (void) __ns_ldap_freeResult(&be->result); return ((int)nss_result); } - /* * getbynet gets a network mask by address. This function constructs an * ldap search filter using the netmask name invocation parameter and the @@ -142,7 +122,6 @@ getbynet(ldap_backend_ptr be, void *a) if (_ldap_filter_name(netnumber, argp->key.name, sizeof (netnumber)) != 0) return ((nss_status_t)NSS_NOTFOUND); - ret = snprintf(searchfilter, sizeof (searchfilter), _F_GETMASKBYNET, netnumber); if (ret >= sizeof (searchfilter) || ret < 0) @@ -179,5 +158,5 @@ _nss_ldap_netmasks_constr(const char *dummy1, const char *dummy2, return ((nss_backend_t *)_nss_ldap_constr(netmasks_ops, sizeof (netmasks_ops)/sizeof (netmasks_ops[0]), _NETMASKS, - netmasks_attrs, _nss_ldap_netmasks2ent)); + netmasks_attrs, _nss_ldap_netmasks2str)); } diff --git a/usr/src/lib/nsswitch/ldap/common/getprinter.c b/usr/src/lib/nsswitch/ldap/common/getprinter.c index f4004be41a..aae2f326cb 100644 --- a/usr/src/lib/nsswitch/ldap/common/getprinter.c +++ b/usr/src/lib/nsswitch/ldap/common/getprinter.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -36,6 +35,9 @@ static void append_attr(char *buf, char *attr); #define _F_GETPRINTERBYNAME \ "(&(objectClass=sunPrinter)(|(printer-name=%s)(printer-aliases=%s)))" +#define PRINTER_PREFIX "printer-" +#define SUNWPR_PREFIX "sunwpr-" + /* * Attributes from the following classes: * printerService @@ -50,85 +52,82 @@ static const char **printer_attrs = NULL; /* - * _nss_ldap_printers2ent is the data marshaling method for the printers + * _nss_ldap_printers2str is the data marshaling method for the printers * getXbyY backend processes. This method is called after a successful * ldap search has been performed. This method will parse the ldap search * values into argp->buf.buffer. Three error conditions are expected and * returned to nsswitch. + * In order to be compatible with old data output, the code is commented out + * with NSS_LDAP_PRINTERS. The NSS_LDAP_PRINTERS section is for future + * refrences if it's decided to fix the output format. */ static int -_nss_ldap_printers2ent(ldap_backend_ptr be, nss_XbyY_args_t *argp) +_nss_ldap_printers2str(ldap_backend_ptr be, nss_XbyY_args_t *argp) { int i, j; int nss_result; - int buflen = (int)0; - unsigned long len = 0L; - char *cp = (char *)NULL; - char *buffer = (char *)NULL; + int buflen = 0, len; + char *buffer = NULL; + char **name, *attrname; ns_ldap_attr_t *attr; ns_ldap_result_t *result = be->result; +#ifdef NSS_LDAP_PRINTERS + int slen, plen; +#endif - buffer = argp->buf.buffer; - buflen = (size_t)argp->buf.buflen; - if (!argp->buf.result) { - nss_result = (int)NSS_STR_PARSE_ERANGE; - goto result_printers2ent; + if (result == NULL) + return (NSS_STR_PARSE_PARSE); + + buflen = argp->buf.buflen; + if (argp->buf.result != NULL) { + be->buffer = calloc(1, buflen); + if (be->buffer == NULL) + return (NSS_STR_PARSE_PARSE); + be->buflen = buflen; + buffer = be->buffer; + } else { + buffer = argp->buf.buffer; + (void) memset(argp->buf.buffer, 0, buflen); } - nss_result = (int)NSS_STR_PARSE_SUCCESS; - (void) memset(argp->buf.buffer, 0, buflen); - - /* Make sure our buffer stays NULL terminated */ - buflen--; + nss_result = NSS_STR_PARSE_SUCCESS; - attr = getattr(result, 0); - if (attr == NULL) { - nss_result = (int)NSS_STR_PARSE_PARSE; - goto result_printers2ent; - } +#ifdef NSS_LDAP_PRINTERS + slen = strlen(SUNWPR_PREFIX); + plen = strlen(PRINTER_PREFIX); +#endif /* - * Pick out the printer name. + * Pick out the printer name and aliases */ - for (i = 0; i < result->entry->attr_count; i++) { - attr = getattr(result, i); - if (attr == NULL) { - nss_result = (int)NSS_STR_PARSE_PARSE; - goto result_printers2ent; - } - if (strcasecmp(attr->attrname, "printer-name") == 0) { - len = strlen(attr->attrvalue[0]); - if (len < 1 || (attr->attrvalue[0] == '\0')) { - *buffer = 0; - nss_result = (int)NSS_STR_PARSE_PARSE; - goto result_printers2ent; - } - if (len > buflen) { - nss_result = (int)NSS_STR_PARSE_ERANGE; - goto result_printers2ent; - } - (void) strcpy(buffer, attr->attrvalue[0]); - } + name = __ns_ldap_getAttr(result->entry, "printer-name"); + if (name == NULL || name[0] == NULL) { + nss_result = NSS_STR_PARSE_PARSE; + goto result_printers2str; } - - /* - * Should never happen since it is mandatory but bail if - * we don't have a printer name. - */ - if (buffer[0] == NULL) { - nss_result = (int)NSS_STR_PARSE_PARSE; - goto result_printers2ent; + len = snprintf(buffer, buflen, "%s", name[0]); + TEST_AND_ADJUST(len, buffer, buflen, result_printers2str); + +#ifdef NSS_LDAP_PRINTERS + attr = __ns_ldap_getAttrStruct(result->entry, "printer-aliases"); + if (attr != NULL && attr->attrvalue != NULL) { + for (i = 0; i < attr->value_count; i++) { + len = snprintf(buffer, buflen, "|%s", + attr->attrvalue[i]); + TEST_AND_ADJUST(len, buffer, buflen, + result_printers2str); + } } - +#endif /* * Add the rest of the attributes */ for (i = 0; i < result->entry->attr_count; i++) { attr = getattr(result, i); if (attr == NULL) { - nss_result = (int)NSS_STR_PARSE_PARSE; - goto result_printers2ent; + nss_result = NSS_STR_PARSE_PARSE; + goto result_printers2str; } /* * The attribute contains key=value @@ -140,51 +139,76 @@ _nss_ldap_printers2ent(ldap_backend_ptr be, nss_XbyY_args_t *argp) (attr->attrvalue[j] == '\0')) { *buffer = 0; nss_result = (int)NSS_STR_PARSE_PARSE; - goto result_printers2ent; - } - len += strlen(buffer) + 1; /* 1 for ':' */ - if (len > buflen) { - nss_result = (int)NSS_STR_PARSE_ERANGE; - goto result_printers2ent; - } - if ((cp = strrchr(buffer, '\0')) != NULL) { - *cp = ':'; - (void) strcat(buffer, - attr->attrvalue[j]); + goto result_printers2str; } + len = snprintf(buffer, buflen, ":%s", + attr->attrvalue[j]); + TEST_AND_ADJUST(len, buffer, buflen, + result_printers2str); } } else { /* - * Skip the printer name + * Skip some attr names */ - if (strcmp(attr->attrname, "printer-name") == 0) { +#ifdef NSS_LDAP_PRINTERS + if (strcasecmp(attr->attrname, "printer-name") == 0 || + strcasecmp(attr->attrname, "dn") == 0 || + strcasecmp(attr->attrname, + "objectclass") == 0 || + strcasecmp(attr->attrname, + "printer-uri") == 0 || + strcasecmp(attr->attrname, + "printer-aliases") == 0) +#else + if (strcasecmp(attr->attrname, "printer-name") == 0) +#endif continue; } /* - * Translate sun-printer-bsdaddr -> bsdaddr + * Translate attr name ->key name */ - if (strcmp(attr->attrname, "sun-printer-bsdaddr") == - 0) { - if (attr->attrname != NULL) { - free(attr->attrname); - } - attr->attrname = strdup("bsdaddr"); - } + if (strcmp(attr->attrname, "sun-printer-bsdaddr") + == 0) + attrname = "bsdaddr"; +#ifdef NSS_LDAP_PRINTERS + else if (strcmp(attr->attrname, "printer-info") + == 0) + attrname = "description"; + else if (strcmp(attr->attrname, "sunwpr-support") + == 0) + attrname = "itopssupported"; + else if (strncmp(attr->attrname, PRINTER_PREFIX, plen) + == 0) + attrname = attr->attrname + plen; + else if (strncmp(attr->attrname, SUNWPR_PREFIX, slen) + == 0) + attrname = attr->attrname + slen; +#endif + else + attrname = attr->attrname; /* - * The attribute name is the key. The attribute + * The attrname is the key. The attribute * data is the value. */ + len = snprintf(buffer, buflen, ":%s=", attrname); + TEST_AND_ADJUST(len, buffer, buflen, + result_printers2str); + for (j = 0; j < attr->value_count; j++) { int k; char *kp; + if (attr->attrvalue[j] == NULL) { + *buffer = 0; + nss_result = NSS_STR_PARSE_PARSE; + goto result_printers2str; + } len = strlen(attr->attrvalue[j]); - if (len < 1 || - (attr->attrvalue[j] == '\0')) { + if (len < 1) { *buffer = 0; - nss_result = (int)NSS_STR_PARSE_PARSE; - goto result_printers2ent; + nss_result = NSS_STR_PARSE_PARSE; + goto result_printers2str; } /* * Add extra for any colons which need to @@ -193,38 +217,33 @@ _nss_ldap_printers2ent(ldap_backend_ptr be, nss_XbyY_args_t *argp) k = 0; for (kp = attr->attrvalue[j]; *kp != NULL; kp++) if (*kp == ':') + /* count ':' in value */ k++; - len += strlen(buffer) + k; + if (j == 0) + /* first time */ + len += k; + else + /* add ',' */ + len += k + 1; - if (j == 0) { - len += strlen(attr->attrname) + 1; - } if (len > buflen) { - nss_result = (int)NSS_STR_PARSE_ERANGE; - goto result_printers2ent; + nss_result = NSS_STR_PARSE_ERANGE; + goto result_printers2str; } - if ((cp = strrchr(buffer, '\0')) != NULL) { - if (j == 0) { - *cp = ':'; - (void) strcat(buffer, - attr->attrname); - (void) strcat(buffer, "="); - } else { - *cp = ','; - } - (void) append_attr(buffer, + if (j > 0) + *buffer++ = ','; + + (void) append_attr(buffer, attr->attrvalue[j]); - } + buffer += strlen(attr->attrvalue[j]) + k; + buflen -= len; } - } } -#ifdef DEBUG - (void) fprintf(stdout, "\n[getprinter.c: _nss_ldap_printers2ent]\n"); - (void) fprintf(stdout, " printers: [%s]\n", buffer); -#endif + if (argp->buf.result != NULL) + be->buflen = strlen(be->buffer); -result_printers2ent: +result_printers2str: (void) __ns_ldap_freeResult(&be->result); return ((int)nss_result); } @@ -241,7 +260,7 @@ append_attr(char *buf, char *attr) (void) strcat(buf, attr); return; } - bp = buf + strlen(buf); + bp = buf; cp = attr; while (*cp != NULL) { if (*cp == ':') { @@ -257,7 +276,7 @@ append_attr(char *buf, char *attr) * parameter and the getprinterbyname search filter defined. Once the * filter is constructed, we search for matching entries and marshal * the data results into argp->buf.buffer for the frontend process. - * The function * _nss_ldap_printers2ent performs the data marshaling. + * The function _nss_ldap_printers2str performs the data marshaling. */ static nss_status_t @@ -297,12 +316,7 @@ _nss_ldap_printers_constr(const char *dummy1, const char *dummy2, const char *dummy3) { -#ifdef DEBUG - (void) fprintf(stdout, - "\n[getprinterent.c: _nss_ldap_printers_constr]\n"); -#endif - return ((nss_backend_t *)_nss_ldap_constr(printers_ops, sizeof (printers_ops)/sizeof (printers_ops[0]), _PRINTERS, - printer_attrs, _nss_ldap_printers2ent)); + printer_attrs, _nss_ldap_printers2str)); } diff --git a/usr/src/lib/nsswitch/ldap/common/getprofattr.c b/usr/src/lib/nsswitch/ldap/common/getprofattr.c index d4c4adf6d4..dc8469ce58 100644 --- a/usr/src/lib/nsswitch/ldap/common/getprofattr.c +++ b/usr/src/lib/nsswitch/ldap/common/getprofattr.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2003 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -37,7 +36,9 @@ #define _PROF_RES2 "SolarisAttrReserved2" #define _PROF_DESC "SolarisAttrLongDesc" #define _PROF_ATTRS "SolarisAttrKeyValue" -#define _PROF_GETPROFNAME "(&(objectClass=SolarisProfAttr)(cn=%s))" +/* Negate an exec_attr attribute to exclude exec_attr entries */ +#define _PROF_GETPROFNAME \ +"(&(objectClass=SolarisProfAttr)(!(SolarisKernelSecurityPolicy=*))(cn=%s))" #define _PROF_GETPROFNAME_SSD "(&(%%s)(cn=%s))" static const char *prof_attrs[] = { @@ -48,150 +49,88 @@ static const char *prof_attrs[] = { _PROF_ATTRS, (char *)NULL }; - - +/* + * _nss_ldap_prof2str is the data marshaling method for the prof_attr + * system call getprofattr, getprofnam and getproflist. + * This method is called after a successful search has been performed. + * This method will parse the search results into the file format. + * e.g. + * + * All:::Execute any command as the user or role:help=RtAll.html + * + */ static int -_nss_ldap_prof2ent(ldap_backend_ptr be, nss_XbyY_args_t *argp) +_nss_ldap_prof2str(ldap_backend_ptr be, nss_XbyY_args_t *argp) { - int i, nss_result; - int buflen = (int)0; + int nss_result; + int buflen = 0; unsigned long len = 0L; - char *nullstring = (char *)NULL; - char *buffer = (char *)NULL; - char *ceiling = (char *)NULL; - profstr_t *prof = (profstr_t *)NULL; - ns_ldap_attr_t *attrptr; + char *buffer = NULL; ns_ldap_result_t *result = be->result; + char **name, **res1, **res2, **des, **attr; + char *res1_str, *res2_str, *des_str, *attr_str; - buffer = argp->buf.buffer; - buflen = (size_t)argp->buf.buflen; - if (!argp->buf.result) { - nss_result = (int)NSS_STR_PARSE_ERANGE; - goto result_prof2ent; - } - prof = (profstr_t *)(argp->buf.result); - ceiling = buffer + buflen; - prof->name = (char *)NULL; - prof->res1 = (char *)NULL; - prof->res2 = (char *)NULL; - prof->desc = (char *)NULL; - prof->attr = (char *)NULL; - nss_result = (int)NSS_STR_PARSE_SUCCESS; - (void) memset(argp->buf.buffer, 0, buflen); + if (result == NULL) + return (NSS_STR_PARSE_PARSE); - attrptr = getattr(result, 0); - if (attrptr == NULL) { - nss_result = (int)NSS_STR_PARSE_PARSE; - goto result_prof2ent; - } - - for (i = 0; i < result->entry->attr_count; i++) { - attrptr = getattr(result, i); - if (attrptr == NULL) { - nss_result = (int)NSS_STR_PARSE_PARSE; - goto result_prof2ent; - } - if (strcasecmp(attrptr->attrname, _PROF_NAME) == 0) { - if ((attrptr->attrvalue[0] == NULL) || - (len = strlen(attrptr->attrvalue[0])) < 1) { - nss_result = (int)NSS_STR_PARSE_PARSE; - goto result_prof2ent; - } - prof->name = buffer; - buffer += len + 1; - if (buffer >= ceiling) { - nss_result = (int)NSS_STR_PARSE_ERANGE; - goto result_prof2ent; - } - (void) strcpy(prof->name, attrptr->attrvalue[0]); - continue; - } - if (strcasecmp(attrptr->attrname, _PROF_RES1) == 0) { - if ((attrptr->attrvalue[0] == NULL) || - (len = strlen(attrptr->attrvalue[0])) < 1) { - prof->res1 = nullstring; - } else { - prof->res1 = buffer; - buffer += len + 1; - if (buffer >= ceiling) { - nss_result = (int)NSS_STR_PARSE_ERANGE; - goto result_prof2ent; - } - (void) strcpy(prof->res1, - attrptr->attrvalue[0]); - } - continue; - } - if (strcasecmp(attrptr->attrname, _PROF_RES2) == 0) { - if ((attrptr->attrvalue[0] == NULL) || - (len = strlen(attrptr->attrvalue[0])) < 1) { - prof->res2 = nullstring; - } else { - prof->res2 = buffer; - buffer += len + 1; - if (buffer >= ceiling) { - nss_result = (int)NSS_STR_PARSE_ERANGE; - goto result_prof2ent; - } - (void) strcpy(prof->res2, - attrptr->attrvalue[0]); - } - continue; - } - if (strcasecmp(attrptr->attrname, _PROF_DESC) == 0) { - if ((attrptr->attrvalue[0] == NULL) || - (len = strlen(attrptr->attrvalue[0])) < 1) { - prof->desc = nullstring; - } else { - prof->desc = buffer; - buffer += len + 1; - if (buffer >= ceiling) { - nss_result = (int)NSS_STR_PARSE_ERANGE; - goto result_prof2ent; - } - (void) strcpy(prof->desc, - attrptr->attrvalue[0]); - } - continue; - } - if (strcasecmp(attrptr->attrname, _PROF_ATTRS) == 0) { - if ((attrptr->attrvalue[0] == NULL) || - (len = strlen(attrptr->attrvalue[0])) < 1) { - prof->attr = nullstring; - } else { - prof->attr = buffer; - buffer += len + 1; - if (buffer >= ceiling) { - nss_result = (int)NSS_STR_PARSE_ERANGE; - goto result_prof2ent; - } - (void) strcpy(prof->attr, - attrptr->attrvalue[0]); - } - continue; - } - } + buflen = argp->buf.buflen; + nss_result = NSS_STR_PARSE_SUCCESS; + (void) memset(argp->buf.buffer, 0, buflen); -#ifdef DEBUG - (void) fprintf(stdout, "\n[getprofattr.c: _nss_ldap_prof2ent]\n"); - (void) fprintf(stdout, " prof-name: [%s]\n", prof->name); - if (prof->res1 != (char *)NULL) { - (void) fprintf(stdout, " res1: [%s]\n", prof->res1); - } - if (prof->res2 != (char *)NULL) { - (void) fprintf(stdout, " res2: [%s]\n", prof->res2); - } - if (prof->desc != (char *)NULL) { - (void) fprintf(stdout, " desc: [%s]\n", prof->desc); + name = __ns_ldap_getAttr(result->entry, _PROF_NAME); + if (name == NULL || name[0] == NULL || + (strlen(name[0]) < 1)) { + nss_result = NSS_STR_PARSE_PARSE; + goto result_prof2str; } - if (prof->attr != (char *)NULL) { - (void) fprintf(stdout, " attr: [%s]\n", prof->attr); + res1 = __ns_ldap_getAttr(result->entry, _PROF_RES1); + if (res1 == NULL || res1[0] == NULL || (strlen(res1[0]) < 1)) + res1_str = _NO_VALUE; + else + res1_str = res1[0]; + + res2 = __ns_ldap_getAttr(result->entry, _PROF_RES2); + if (res2 == NULL || res2[0] == NULL || (strlen(res2[0]) < 1)) + res2_str = _NO_VALUE; + else + res2_str = res2[0]; + + des = __ns_ldap_getAttr(result->entry, _PROF_DESC); + if (des == NULL || des[0] == NULL || (strlen(des[0]) < 1)) + des_str = _NO_VALUE; + else + des_str = des[0]; + + attr = __ns_ldap_getAttr(result->entry, _PROF_ATTRS); + if (attr == NULL || attr[0] == NULL || (strlen(attr[0]) < 1)) + attr_str = _NO_VALUE; + else + attr_str = attr[0]; + /* 5 = 4 ':' + 1 '\0' */ + len = strlen(name[0]) + strlen(res1_str) + strlen(res2_str) + + strlen(des_str) + strlen(attr_str) + 6; + if (len > buflen) { + nss_result = NSS_STR_PARSE_ERANGE; + goto result_prof2str; } -#endif /* DEBUG */ -result_prof2ent: + if (argp->buf.result != NULL) { + if ((be->buffer = calloc(1, len)) == NULL) { + nss_result = NSS_STR_PARSE_PARSE; + goto result_prof2str; + } + buffer = be->buffer; + } else + buffer = argp->buf.buffer; + (void) snprintf(buffer, len, "%s:%s:%s:%s:%s", + name[0], res1_str, res2_str, des_str, attr_str); + /* The front end marshaller doesn't need the trailing null */ + if (argp->buf.result != NULL) + be->buflen = strlen(be->buffer); + +result_prof2str: (void) __ns_ldap_freeResult(&be->result); - return ((int)nss_result); + return (nss_result); } @@ -204,10 +143,6 @@ getbyname(ldap_backend_ptr be, void *a) int ret; nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a; -#ifdef DEBUG - (void) fprintf(stdout, "\n[getprofattr.c: getbyname]\n"); -#endif /* DEBUG */ - if (_ldap_filter_name(name, argp->key.name, sizeof (name)) != 0) return ((nss_status_t)NSS_NOTFOUND); @@ -243,11 +178,7 @@ _nss_ldap_prof_attr_constr(const char *dummy1, const char *dummy4, const char *dummy5) { -#ifdef DEBUG - (void) fprintf(stdout, - "\n[getprofattr.c: _nss_ldap_prof_attr_constr]\n"); -#endif return ((nss_backend_t *)_nss_ldap_constr(profattr_ops, sizeof (profattr_ops)/sizeof (profattr_ops[0]), _PROFATTR, - prof_attrs, _nss_ldap_prof2ent)); + prof_attrs, _nss_ldap_prof2str)); } diff --git a/usr/src/lib/nsswitch/ldap/common/getprojent.c b/usr/src/lib/nsswitch/ldap/common/getprojent.c index fd332209d8..f1ff6db64e 100644 --- a/usr/src/lib/nsswitch/ldap/common/getprojent.c +++ b/usr/src/lib/nsswitch/ldap/common/getprojent.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -50,220 +49,96 @@ static const char *project_attrs[] = { (char *)NULL }; -static char * -gettok(char **nextpp, char sep) -{ - char *p = *nextpp; - char *q = p; - char c; - - if (p == NULL) - return (NULL); - while ((c = *q) != '\0' && c != sep) - q++; - if (c == '\0') - *nextpp = 0; - else { - *q++ = '\0'; - *nextpp = q; - } - return (p); -} - /* - * _nss_ldap_proj2ent is the data marshalling method for the project getXbyY + * _nss_ldap_proj2str is the data marshalling method for the project getXbyY * (getprojbyname, getprojbyid, getprojent) backend processes. This method * is called after a successful ldap search has been performed. This method - * will parse the ldap search values into struct project = argp->buf.buffer - * which the frontend routine expects. Three error conditions are expected - * and returned to nsswitch. + * will parse the ldap search values into the file format. + * e.g. + * + * system:0:System::: + * + * beatles:100:The Beatles:john,paul,george,ringo::task.max-lwps= + * (privileged,100,signal=SIGTERM),(privileged,110,deny) + * + * (All in one line) */ static int -_nss_ldap_proj2ent(ldap_backend_ptr be, nss_XbyY_args_t *argp) +_nss_ldap_proj2str(ldap_backend_ptr be, nss_XbyY_args_t *argp) { - int i, nss_result; + int nss_result, buflen; unsigned long len = 0; - char **uglist; - char *buffer, *ceiling; - char *users, *groups, *p; - struct project *proj; + char *buffer, *comment, *user_str, *group_str, *attr_str; ns_ldap_result_t *result = be->result; - ns_ldap_attr_t *attrptr; + char **name, **id, **descr, **users, **groups, **attr; + + if (result == NULL) + return (NSS_STR_PARSE_PARSE); + buflen = argp->buf.buflen; - buffer = argp->buf.buffer; - if (!argp->buf.result) { - nss_result = NSS_STR_PARSE_ERANGE; - goto result_proj2ent; - } - attrptr = getattr(result, 0); - if (attrptr == NULL) { - nss_result = NSS_STR_PARSE_PARSE; - goto result_proj2ent; - } nss_result = NSS_STR_PARSE_SUCCESS; - proj = argp->buf.result; - proj->pj_users = proj->pj_groups = NULL; - proj->pj_attr = proj->pj_comment = NULL; - ceiling = (char *)ROUND_DOWN(buffer + argp->buf.buflen, - sizeof (char *)); - (void) memset(argp->buf.buffer, 0, argp->buf.buflen); - for (i = 0; i < result->entry->attr_count; i++) { - attrptr = getattr(result, i); - if (attrptr == NULL) { - nss_result = NSS_STR_PARSE_PARSE; - goto result_proj2ent; - } - len = strlen(attrptr->attrvalue[0]); - if (strcasecmp(attrptr->attrname, _PROJ_NAME) == 0) { - if (len == 0) { - nss_result = NSS_STR_PARSE_PARSE; - goto result_proj2ent; - } - proj->pj_name = buffer; - buffer += len + 1; - if (buffer >= ceiling) { - nss_result = NSS_STR_PARSE_ERANGE; - goto result_proj2ent; - } - (void) strcpy(proj->pj_name, attrptr->attrvalue[0]); - continue; - } - if (strcasecmp(attrptr->attrname, _PROJ_PROJID) == 0) { - if (len == 0) { - nss_result = NSS_STR_PARSE_PARSE; - goto result_proj2ent; - } - errno = 0; - proj->pj_projid = - (projid_t)strtol(attrptr->attrvalue[0], - NULL, 10); - if (errno != 0) { - nss_result = NSS_STR_PARSE_PARSE; - goto result_proj2ent; - } - continue; - } - if (strcasecmp(attrptr->attrname, _PROJ_DESCR) == 0) { - proj->pj_comment = buffer; - buffer += len + 1; - if (buffer >= ceiling) { - nss_result = NSS_STR_PARSE_ERANGE; - goto result_proj2ent; - } - (void) strcpy(proj->pj_comment, attrptr->attrvalue[0]); - continue; - } - if (strcasecmp(attrptr->attrname, _PROJ_ATTR) == 0) { - proj->pj_attr = buffer; - buffer += len + 1; - if (buffer >= ceiling) { - nss_result = NSS_STR_PARSE_ERANGE; - goto result_proj2ent; - } - (void) strcpy(proj->pj_attr, attrptr->attrvalue[0]); - continue; - } - if (strcasecmp(attrptr->attrname, _PROJ_USERS) == 0) { - buffer = (char *)ROUND_UP(buffer, sizeof (char *)); - users = buffer; - buffer += len + 1; - if (buffer >= ceiling) { - nss_result = NSS_STR_PARSE_ERANGE; - goto result_proj2ent; - } - (void) strcpy(users, attrptr->attrvalue[0]); - buffer = (char *)ROUND_UP(buffer, sizeof (char *)); - if (buffer >= ceiling) { - nss_result = NSS_STR_PARSE_ERANGE; - goto result_proj2ent; - } - proj->pj_users = uglist = (char **)buffer; - *uglist = NULL; - while (uglist < (char **)ceiling) { - p = gettok(&users, ','); - if (p == NULL || *p == '\0') { - *uglist++ = 0; - break; - } - *uglist++ = p; - } - buffer = (char *)uglist; - if (buffer >= ceiling) - return (NSS_STR_PARSE_ERANGE); - continue; - } - if (strcasecmp(attrptr->attrname, _PROJ_GROUPS) == 0) { - buffer = (char *)ROUND_UP(buffer, sizeof (char *)); - groups = buffer; - buffer += len + 1; - if (buffer >= ceiling) { - nss_result = NSS_STR_PARSE_ERANGE; - goto result_proj2ent; - } - (void) strcpy(groups, attrptr->attrvalue[0]); - buffer = (char *)ROUND_UP(buffer, sizeof (char *)); - if (buffer >= ceiling) { - nss_result = NSS_STR_PARSE_ERANGE; - goto result_proj2ent; - } - proj->pj_groups = uglist = (char **)buffer; - *uglist = NULL; - while (uglist < (char **)ceiling) { - p = gettok(&groups, ','); - if (p == NULL || *p == '\0') { - *uglist++ = 0; - break; - } - *uglist++ = p; - } - buffer = (char *)uglist; - if (buffer >= ceiling) - return (NSS_STR_PARSE_ERANGE); - continue; - } - } - if (proj->pj_comment == NULL) { - buffer = (char *)ROUND_UP(buffer, sizeof (char *)); - if (buffer >= ceiling) { - nss_result = NSS_STR_PARSE_ERANGE; - goto result_proj2ent; - } - proj->pj_comment = buffer; - *buffer = '\0'; - buffer++; + (void) memset(argp->buf.buffer, 0, buflen); + + name = __ns_ldap_getAttr(result->entry, _PROJ_NAME); + if (name == NULL || name[0] == NULL || (strlen(name[0]) < 1)) { + nss_result = NSS_STR_PARSE_PARSE; + goto result_proj2str; } - if (proj->pj_users == NULL) { - buffer = (char *)ROUND_UP(buffer, sizeof (char *)); - if (buffer >= ceiling) { - nss_result = NSS_STR_PARSE_ERANGE; - goto result_proj2ent; - } - proj->pj_users = (char **)buffer; - *buffer = '\0'; - buffer++; + id = __ns_ldap_getAttr(result->entry, _PROJ_PROJID); + if (id == NULL || id[0] == NULL || (strlen(id[0]) < 1)) { + nss_result = NSS_STR_PARSE_PARSE; + goto result_proj2str; } - if (proj->pj_groups == NULL) { - buffer = (char *)ROUND_UP(buffer, sizeof (char *)); - if (buffer >= ceiling) { - nss_result = NSS_STR_PARSE_ERANGE; - goto result_proj2ent; - } - proj->pj_groups = (char **)buffer; - *buffer = '\0'; - buffer++; + descr = __ns_ldap_getAttr(result->entry, _PROJ_DESCR); + if (descr == NULL || descr[0] == NULL || (strlen(descr[0]) < 1)) + comment = _NO_VALUE; + + else + comment = descr[0]; + + users = __ns_ldap_getAttr(result->entry, _PROJ_USERS); + if (users == NULL || users[0] == NULL || (strlen(users[0]) < 1)) + user_str = _NO_VALUE; + + else + user_str = users[0]; + + groups = __ns_ldap_getAttr(result->entry, _PROJ_GROUPS); + if (groups == NULL || groups[0] == NULL || (strlen(groups[0]) < 1)) + group_str = _NO_VALUE; + + else + group_str = groups[0]; + + attr = __ns_ldap_getAttr(result->entry, _PROJ_ATTR); + if (attr == NULL || attr[0] == NULL || (strlen(attr[0]) < 1)) + attr_str = _NO_VALUE; + + else + attr_str = attr[0]; + + /* 6 = 5 ':' + 1 '\0' */ + len = strlen(name[0]) + strlen(id[0]) + strlen(comment) + + strlen(user_str) + strlen(group_str) + strlen(attr_str) + 6; + if (len >= buflen) { + nss_result = NSS_STR_PARSE_ERANGE; + goto result_proj2str; } - if (proj->pj_attr == NULL) { - buffer = (char *)ROUND_UP(buffer, sizeof (char *)); - if (buffer >= ceiling) { - nss_result = NSS_STR_PARSE_ERANGE; - goto result_proj2ent; + if (argp->buf.result != NULL) { + if ((be->buffer = calloc(1, len)) == NULL) { + nss_result = NSS_STR_PARSE_PARSE; + goto result_proj2str; } - proj->pj_attr = buffer; - *buffer = '\0'; - buffer++; - } + buffer = be->buffer; + /* The front end marshaller does not need trailing nulls */ + be->buflen = len - 1; + } else + buffer = argp->buf.buffer; + + (void) snprintf(buffer, len, "%s:%s:%s:%s:%s:%s", name[0], id[0], + comment, user_str, group_str, attr_str); -result_proj2ent: +result_proj2str: (void) __ns_ldap_freeResult(&be->result); return ((int)nss_result); } @@ -327,5 +202,5 @@ _nss_ldap_project_constr(const char *dummy1, const char *dummy2, { return (_nss_ldap_constr(project_ops, sizeof (project_ops) / sizeof (project_ops[0]), - _PROJECT, project_attrs, _nss_ldap_proj2ent)); + _PROJECT, project_attrs, _nss_ldap_proj2str)); } diff --git a/usr/src/lib/nsswitch/ldap/common/getprotoent.c b/usr/src/lib/nsswitch/ldap/common/getprotoent.c index 09522445e4..e9542a7543 100644 --- a/usr/src/lib/nsswitch/ldap/common/getprotoent.c +++ b/usr/src/lib/nsswitch/ldap/common/getprotoent.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2003 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -47,181 +46,164 @@ static const char *protocols_attrs[] = { (char *)NULL }; +typedef struct protocol_alias { + char *protocol; + char *alias; +} protocol_alias_t; + +static const protocol_alias_t ip_aliases[10] = { + { "ip", "IP" }, + { "ipip", "IP-IP" }, + { "ipcomp", "IPComp" }, + { "ipv6", "IPv6" }, + { "ipv6-route", "IPv6-Route" }, + { "ipv6-frag", "IPv6-Frag" }, + { "ipv6-icmp", "IPv6-ICMP" }, + { "ipv6-nonxt", "IPv6-NoNxt" }, + { "ipv6-opts", "IPv6-Opts" }, + { NULL, NULL } +}; /* - * _nss_ldap_protocols2ent is the data marshaling method for the protocols + * When the data is imported by ldapaddent, it does not save the aliase in the + * "cn" that is same as the canonical name but only different in case. + * e.g. + * icmp 1 ICMP + * + * is saved as + * + * dn: cn=icmp, ... + * ... + * cn: icmp + * ... + * + * So it needs to replicate the canonical name as an alias of upper case. + * But some protocol does have different aliases. + * + * e.g. + * dn: cn=ospf, ... + * ... + * cn: ospf + * cn: OSPFIGP + * ... + * + * For many ip* protocols, the aliases are mixed cased. Maybe it's case + * insensitive. But this fucntion tries to restore the aliases to the original + * form as much as possible. If the alias can't be found in the aliases table, + * it assumes the alias is all upper case. + * + */ +static char * +get_alias(char *protocol) { + int i; + char *cp; + + if (strncmp(protocol, "ip", 2) == 0) { + for (i = 0; ip_aliases[i].protocol != NULL; i++) { + if (strcmp(protocol, ip_aliases[i].protocol) == 0) + return (ip_aliases[i].alias); + } + /* + * No aliase in the table. Return an all upper case aliase + */ + for (cp = protocol; *cp; cp++) + *cp = toupper(*cp); + + return (protocol); + } else { + /* Return an all upper case aliase */ + for (cp = protocol; *cp; cp++) + *cp = toupper(*cp); + + return (protocol); + } + +} +/* + * _nss_ldap_protocols2str is the data marshaling method for the protocols * getXbyY * (e.g., getbyname(), getbynumber(), getent()) backend processes. * This method is called after a successful ldap search has been performed. - * This method will parse the ldap search values into *proto = (struct - * protoent *)argp->buf.result which the frontend process expects. Three error - * conditions are expected and returned to nsswitch. + * This method will parse the ldap search values into a file format. + * e.g. + * idrp 45 IDRP + * or + * ospf 89 OSPFIGP */ static int -_nss_ldap_protocols2ent(ldap_backend_ptr be, nss_XbyY_args_t *argp) +_nss_ldap_protocols2str(ldap_backend_ptr be, nss_XbyY_args_t *argp) { - int i, j; + uint_t i; int nss_result; - int buflen = (int)0; - int firstime = (int)1; - unsigned long len = 0L; - char *cp, **mp, *cname = NULL; - char *buffer = (char *)NULL; - char *ceiling = (char *)NULL; - struct protoent *proto = (struct protoent *)NULL; + int buflen = 0, len; + char *cname = NULL; + char *buffer = NULL, **number, *alias; ns_ldap_result_t *result = be->result; - ns_ldap_attr_t *attrptr; + ns_ldap_attr_t *names; - buffer = (char *)argp->buf.buffer; - buflen = (size_t)argp->buf.buflen; - if (!argp->buf.result) { - nss_result = (int)NSS_STR_PARSE_ERANGE; - goto result_pls2ent; - } - proto = (struct protoent *)argp->buf.result; - ceiling = buffer + buflen; + if (result == NULL) + return (NSS_STR_PARSE_PARSE); - nss_result = (int)NSS_STR_PARSE_SUCCESS; + buflen = argp->buf.buflen; + if (argp->buf.result != NULL) { + if ((be->buffer = calloc(1, buflen)) == NULL) { + nss_result = NSS_STR_PARSE_PARSE; + goto result_pls2str; + } + buffer = be->buffer; + } else + buffer = argp->buf.buffer; + + nss_result = NSS_STR_PARSE_SUCCESS; (void) memset(argp->buf.buffer, 0, buflen); - attrptr = getattr(result, 0); - if (attrptr == NULL) { - nss_result = (int)NSS_STR_PARSE_PARSE; - goto result_pls2ent; + names = __ns_ldap_getAttrStruct(result->entry, _P_NAME); + if (names == NULL || names->attrvalue == NULL) { + nss_result = NSS_STR_PARSE_PARSE; + goto result_pls2str; } - for (i = 0; i < result->entry->attr_count; i++) { - attrptr = getattr(result, i); - if (attrptr == NULL) { - nss_result = (int)NSS_STR_PARSE_PARSE; - goto result_pls2ent; - } - if (strcasecmp(attrptr->attrname, _P_NAME) == 0) { - for (j = 0; j < attrptr->value_count; j++) { - if (firstime) { - /* protocol name */ - cname = __s_api_get_canonical_name( - result->entry, attrptr, 1); - if (cname == NULL || - (len = strlen(cname)) < 1) { - nss_result = - NSS_STR_PARSE_PARSE; - goto result_pls2ent; - } - proto->p_name = buffer; - buffer += len + 1; - if (buffer >= ceiling) { - nss_result = - (int)NSS_STR_PARSE_ERANGE; - goto result_pls2ent; - } - (void) strcpy(proto->p_name, cname); - mp = proto->p_aliases = - (char **)ROUND_UP(buffer, - sizeof (char **)); - buffer = (char *)proto->p_aliases + - sizeof (char *) * - (attrptr->value_count + 1); - buffer = (char *)ROUND_UP(buffer, - sizeof (char **)); - if (buffer >= ceiling) { - nss_result = - (int)NSS_STR_PARSE_ERANGE; - goto result_pls2ent; - } - firstime = (int)0; - } - /* alias list */ - if ((attrptr->attrvalue[j] == NULL) || - (len = strlen(attrptr->attrvalue[j])) < 1) { - nss_result = NSS_STR_PARSE_PARSE; - goto result_pls2ent; - } - /* - * When the data is imported by ldapaddent, - * it does not save the aliase in the "cn" - * that is same as the canonical name but only - * differnt in case. - * e.g. - * icmp 1 ICMP - * - * is saved as - * - * dn: cn=icmp, ... - * ... - * cn: icmp - * ... - * So it needs to replicate the canonical name - * as an aliase of upper case. - * - * But in the case of - * ospf 89 OSPFIGP - * it creates a redundant aliase. - * e.g. - * dn: cn=icmp, ... - * ... - * cn: ospf - * cn: OSPFIGP - * ... - * - * getent services ospf - * ==> ospf 89 ospf OSPFIGP - * - * Some condition check is added to handle this - * scenario. Such check also works with - * following scenario. - * dn: cn=icmp, ... - * ... - * cn: icmp - * cn: ICMP - * ... - */ - if (strcmp(proto->p_name, - attrptr->attrvalue[j]) == 0) { - if (attrptr->value_count > 1) - /* Do not replicate */ - continue; - for (cp = attrptr->attrvalue[j]; - *cp; cp++) - *cp = toupper(*cp); - } - *mp = buffer; - buffer += len + 1; - if (buffer >= ceiling) { - nss_result = (int)NSS_STR_PARSE_ERANGE; - goto result_pls2ent; - } - (void) strcpy(*mp++, attrptr->attrvalue[j]); - continue; - } - } - if (strcasecmp(attrptr->attrname, _P_PROTO) == 0) { - if ((attrptr->attrvalue[0] == NULL) || - (len = strlen(attrptr->attrvalue[0])) < 1) { - nss_result = (int)NSS_STR_PARSE_PARSE; - goto result_pls2ent; + /* Get the canonical name */ + cname = __s_api_get_canonical_name(result->entry, names, 1); + if (cname == NULL || (len = strlen(cname)) < 1) { + nss_result = NSS_STR_PARSE_PARSE; + goto result_pls2str; + } + number = __ns_ldap_getAttr(result->entry, _P_PROTO); + if (number == NULL || number[0] == NULL || + (len = strlen(number[0])) < 1) { + nss_result = NSS_STR_PARSE_PARSE; + goto result_pls2str; + } + len = snprintf(buffer, buflen, "%s %s", cname, number[0]); + TEST_AND_ADJUST(len, buffer, buflen, result_pls2str); + /* Append aliases */ + if (names->value_count == 1) { + /* create an aliase from protocol name */ + alias = get_alias(cname); + len = snprintf(buffer, buflen, " %s", alias); + TEST_AND_ADJUST(len, buffer, buflen, result_pls2str); + + } else { + for (i = 0; i < names->value_count; i++) { + if (names->attrvalue[i] == NULL) { + nss_result = NSS_STR_PARSE_PARSE; + goto result_pls2str; } - errno = 0; - proto->p_proto = (int)strtol(attrptr->attrvalue[0], - (char **)NULL, 10); - if (errno != 0) { - nss_result = (int)NSS_STR_PARSE_PARSE; - goto result_pls2ent; + /* Skip the canonical name */ + if (strcasecmp(names->attrvalue[i], cname) != 0) { + len = snprintf(buffer, buflen, " %s", + names->attrvalue[i]); + TEST_AND_ADJUST(len, buffer, buflen, + result_pls2str); } - continue; } } -#ifdef DEBUG - (void) fprintf(stdout, "\n[getprotoent.c: _nss_ldap_protocols2ent]\n"); - (void) fprintf(stdout, " p_name: [%s]\n", proto->p_name); - if (mp != NULL) { - for (mp = proto->p_aliases; *mp != NULL; mp++) - (void) fprintf(stdout, " p_aliases: [%s]\n", *mp); - } - (void) fprintf(stdout, " p_proto: [%d]\n", proto->p_proto); -#endif /* DEBUG */ + /* The front end marshaller doesn't need to copy trailing nulls */ + if (argp->buf.result != NULL) + be->buflen = strlen(be->buffer); -result_pls2ent: +result_pls2str: (void) __ns_ldap_freeResult(&be->result); return ((int)nss_result); @@ -323,5 +305,5 @@ _nss_ldap_protocols_constr(const char *dummy1, const char *dummy2, return ((nss_backend_t *)_nss_ldap_constr(proto_ops, sizeof (proto_ops)/sizeof (proto_ops[0]), _PROTOCOLS, - protocols_attrs, _nss_ldap_protocols2ent)); + protocols_attrs, _nss_ldap_protocols2str)); } diff --git a/usr/src/lib/nsswitch/ldap/common/getpwnam.c b/usr/src/lib/nsswitch/ldap/common/getpwnam.c index 205513812a..a2c9ff40c9 100644 --- a/usr/src/lib/nsswitch/ldap/common/getpwnam.c +++ b/usr/src/lib/nsswitch/ldap/common/getpwnam.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2003 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -58,190 +57,106 @@ static const char *pwd_attrs[] = { (char *)NULL }; - /* - * _nss_ldap_passwd2ent is the data marshaling method for the passwd getXbyY + * _nss_ldap_passwd2str is the data marshaling method for the passwd getXbyY * (e.g., getbyuid(), getbyname(), getpwent()) backend processes. This method is * called after a successful ldap search has been performed. This method will - * parse the ldap search values into struct passwd = argp->buf.buffer which - * the frontend process expects. Three error conditions are expected and - * returned to nsswitch. + * parse the ldap search values into the file format. + * e.g. + * + * nobody:x:60001:60001:Nobody:/: + * */ - static int -_nss_ldap_passwd2ent(ldap_backend_ptr be, nss_XbyY_args_t *argp) +_nss_ldap_passwd2str(ldap_backend_ptr be, nss_XbyY_args_t *argp) { - int i = 0; int nss_result; - int buflen = (int)0; - unsigned long len = 0L; - char *buffer = (char *)NULL; - char *ptr2x; - char *ceiling = (char *)NULL; - char *nullstring = (char *)NULL; - struct passwd *pwd = (struct passwd *)NULL; + int buflen = 0; + unsigned long str_len = 0L; + char *buffer = NULL; ns_ldap_result_t *result = be->result; - ns_ldap_attr_t *attrptr; - int have_uid = 0; - int have_uidn = 0; - int have_gidn = 0; + ns_ldap_entry_t *entry; + char **uid_v, **uidn_v, **gidn_v; + char **gecos_v, **homedir_v, **shell_v; + char *NULL_STR = ""; + + if (result == NULL) + return (NSS_STR_PARSE_PARSE); -#ifdef DEBUG - (void) fprintf(stdout, "\n[getpwnam.c: _nss_ldap_passwd2ent]\n"); -#endif /* DEBUG */ + entry = result->entry; + buflen = argp->buf.buflen; buffer = argp->buf.buffer; - buflen = (size_t)argp->buf.buflen; - if (!argp->buf.result) { - nss_result = (int)NSS_STR_PARSE_ERANGE; - goto result_pwd2ent; - } - pwd = (struct passwd *)argp->buf.result; - ceiling = buffer + buflen; - nullstring = (buffer + (buflen - 1)); - nss_result = (int)NSS_STR_PARSE_SUCCESS; + nss_result = NSS_STR_PARSE_SUCCESS; (void) memset(buffer, 0, buflen); - /* - * need to always return password as "x" - * so put "x" at top of the buffer - */ - ptr2x = buffer; - *buffer++ = 'x'; - *buffer++ = '\0'; - - attrptr = getattr(result, 0); - if (attrptr == NULL) { - nss_result = (int)NSS_STR_PARSE_PARSE; - goto result_pwd2ent; - } - - pwd->pw_gecos = nullstring; - pwd->pw_dir = nullstring; - pwd->pw_shell = nullstring; + /* 8 = 6 ':' + 1 '\0' + 1 'x' */ + buflen -= 8; - for (i = 0; i < result->entry->attr_count; i++) { - attrptr = getattr(result, i); - if (attrptr == NULL) { - nss_result = (int)NSS_STR_PARSE_PARSE; - goto result_pwd2ent; - } - if (strcasecmp(attrptr->attrname, _PWD_UID) == 0) { - if ((attrptr->attrvalue[0] == NULL) || - (len = strlen(attrptr->attrvalue[0])) < 1) { - nss_result = (int)NSS_STR_PARSE_PARSE; - goto result_pwd2ent; - } - pwd->pw_name = buffer; - buffer += len + 1; - if (buffer >= ceiling) { - nss_result = (int)NSS_STR_PARSE_ERANGE; - goto result_pwd2ent; - } - (void) strcpy(pwd->pw_name, attrptr->attrvalue[0]); - have_uid = 1; - continue; - } - if (strcasecmp(attrptr->attrname, _PWD_UIDNUMBER) == 0) { - if (attrptr->attrvalue[0] == '\0') { - nss_result = (int)NSS_STR_PARSE_PARSE; - goto result_pwd2ent; - } - pwd->pw_uid = strtol(attrptr->attrvalue[0], - (char **)NULL, 10); - have_uidn = 1; - continue; - } - if (strcasecmp(attrptr->attrname, _PWD_GIDNUMBER) == 0) { - if (attrptr->attrvalue[0] == '\0') { - nss_result = (int)NSS_STR_PARSE_PARSE; - goto result_pwd2ent; - } - pwd->pw_gid = strtol(attrptr->attrvalue[0], - (char **)NULL, 10); - have_gidn = 1; - continue; - } - if ((strcasecmp(attrptr->attrname, _PWD_GECOS) == 0) && - (attrptr->value_count > 0)) { - if ((attrptr->attrvalue[0] == NULL) || - (len = strlen(attrptr->attrvalue[0])) < 1) { - pwd->pw_gecos = nullstring; - } else { - pwd->pw_gecos = buffer; - buffer += len + 1; - if (buffer >= ceiling) { - nss_result = (int)NSS_STR_PARSE_ERANGE; - goto result_pwd2ent; - } - (void) strcpy(pwd->pw_gecos, - attrptr->attrvalue[0]); - } - continue; - } - if ((strcasecmp(attrptr->attrname, _PWD_HOMEDIRECTORY) == 0) && - (attrptr->value_count > 0)) { - if ((attrptr->attrvalue[0] == NULL) || - (len = strlen(attrptr->attrvalue[0])) < 1) { - pwd->pw_dir = nullstring; - } else { - pwd->pw_dir = buffer; - buffer += len + 1; - if (buffer >= ceiling) { - nss_result = (int)NSS_STR_PARSE_ERANGE; - goto result_pwd2ent; - } - (void) strcpy(pwd->pw_dir, - attrptr->attrvalue[0]); - } - continue; - } - if ((strcasecmp(attrptr->attrname, _PWD_LOGINSHELL) == 0) && - (attrptr->value_count > 0)) { - if ((attrptr->attrvalue[0] == NULL) || - (len = strlen(attrptr->attrvalue[0])) < 1) { - pwd->pw_shell = nullstring; - } else { - pwd->pw_shell = buffer; - buffer += len + 1; - if (buffer >= ceiling) { - nss_result = (int)NSS_STR_PARSE_ERANGE; - goto result_pwd2ent; - } - (void) strcpy(pwd->pw_shell, - attrptr->attrvalue[0]); - } - continue; - } + uid_v = __ns_ldap_getAttr(entry, _PWD_UID); + uidn_v = __ns_ldap_getAttr(entry, _PWD_UIDNUMBER); + gidn_v = __ns_ldap_getAttr(entry, _PWD_GIDNUMBER); + if (uid_v == NULL || uidn_v == NULL || gidn_v == NULL || + uid_v[0] == NULL || uidn_v[0] == NULL || gidn_v[0] == NULL) { + nss_result = NSS_STR_PARSE_PARSE; + goto result_pwd2str; + } + str_len = strlen(uid_v[0]) + strlen(uidn_v[0]) + strlen(gidn_v[0]); + if (str_len > buflen) { + nss_result = NSS_STR_PARSE_ERANGE; + goto result_pwd2str; } - /* error if missing required attributes */ - if (have_uid == 0 || have_uidn == 0 || have_gidn == 0) { - nss_result = (int)NSS_STR_PARSE_PARSE; + gecos_v = __ns_ldap_getAttr(entry, _PWD_GECOS); + if (gecos_v == NULL || gecos_v[0] == NULL || *gecos_v[0] == '\0') + gecos_v = &NULL_STR; + else + str_len += strlen(gecos_v[0]); + + homedir_v = __ns_ldap_getAttr(entry, _PWD_HOMEDIRECTORY); + if (homedir_v == NULL || homedir_v[0] == NULL || *homedir_v[0] == '\0') + homedir_v = &NULL_STR; + else + str_len += strlen(homedir_v[0]); + + shell_v = __ns_ldap_getAttr(entry, _PWD_LOGINSHELL); + if (shell_v == NULL || shell_v[0] == NULL || *shell_v[0] == '\0') + shell_v = &NULL_STR; + else + str_len += strlen(shell_v[0]); + + if (str_len > buflen) { + nss_result = NSS_STR_PARSE_ERANGE; + goto result_pwd2str; } - pwd->pw_age = nullstring; - pwd->pw_comment = nullstring; - pwd->pw_passwd = ptr2x; + if (argp->buf.result != NULL) { + be->buflen = str_len + 8; + be->buffer = malloc(be->buflen); + if (be->buffer == NULL) { + nss_result = (int)NSS_STR_PARSE_ERANGE; + goto result_pwd2str; + } -#ifdef DEBUG - (void) fprintf(stdout, "\n[getpwnam.c: _nss_ldap_passwd2ent]\n"); - (void) fprintf(stdout, " pw_name: [%s]\n", pwd->pw_name); - (void) fprintf(stdout, " pw_uid: [%ld]\n", pwd->pw_uid); - (void) fprintf(stdout, " pw_gid: [%ld]\n", pwd->pw_gid); - (void) fprintf(stdout, " pw_gecos: [%s]\n", pwd->pw_gecos); - (void) fprintf(stdout, " pw_dir: [%s]\n", pwd->pw_dir); - (void) fprintf(stdout, " pw_shell: [%s]\n", pwd->pw_shell); -#endif /* DEBUG */ + (void) snprintf(be->buffer, be->buflen, + "%s:%s:%s:%s:%s:%s:%s", + uid_v[0], "x", uidn_v[0], gidn_v[0], + gecos_v[0], homedir_v[0], shell_v[0]); + } else { + (void) snprintf(argp->buf.buffer, (str_len + 8), + "%s:%s:%s:%s:%s:%s:%s", + uid_v[0], "x", uidn_v[0], gidn_v[0], + gecos_v[0], homedir_v[0], shell_v[0]); -result_pwd2ent: + } + +result_pwd2str: (void) __ns_ldap_freeResult(&be->result); return ((int)nss_result); } - /* * getbyname gets a passwd entry by uid name. This function constructs an ldap * search filter using the name invocation parameter and the getpwnam search @@ -259,10 +174,6 @@ getbyname(ldap_backend_ptr be, void *a) char name[SEARCHFILTERLEN]; int ret; -#ifdef DEBUG - (void) fprintf(stdout, "\n[getpwnam.c: getbyname]\n"); -#endif /* DEBUG */ - if (_ldap_filter_name(name, argp->key.name, sizeof (name)) != 0) return ((nss_status_t)NSS_NOTFOUND); @@ -296,10 +207,6 @@ getbyuid(ldap_backend_ptr be, void *a) char userdata[SEARCHFILTERLEN]; int ret; -#ifdef DEBUG - (void) fprintf(stdout, "\n[getpwnam.c: getbyuid]\n"); -#endif /* DEBUG */ - ret = snprintf(searchfilter, sizeof (searchfilter), _F_GETPWUID, (long)argp->key.uid); if (ret >= sizeof (searchfilter) || ret < 0) @@ -337,11 +244,7 @@ _nss_ldap_passwd_constr(const char *dummy1, const char *dummy2, const char *dummy3) { -#ifdef DEBUG - (void) fprintf(stdout, "\n[getpwnam.c: _nss_ldap_passwd_constr]\n"); -#endif /* DEBUG */ - return ((nss_backend_t *)_nss_ldap_constr(passwd_ops, sizeof (passwd_ops)/sizeof (passwd_ops[0]), - _PASSWD, pwd_attrs, _nss_ldap_passwd2ent)); + _PASSWD, pwd_attrs, _nss_ldap_passwd2str)); } diff --git a/usr/src/lib/nsswitch/ldap/common/getrpcent.c b/usr/src/lib/nsswitch/ldap/common/getrpcent.c index e8e0d51df3..3419d93fb6 100644 --- a/usr/src/lib/nsswitch/ldap/common/getrpcent.c +++ b/usr/src/lib/nsswitch/ldap/common/getrpcent.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2003 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -47,144 +46,86 @@ static const char *rpc_attrs[] = { }; /* - * _nss_ldap_rpc2ent is the data marshaling method for the rpc getXbyY + * _nss_ldap_rpc2str is the data marshaling method for the rpc getXbyY * (e.g., getbyname(), getbynumber(), getrpcent()) backend processes. * This method is called after a successful ldap search has been performed. - * This method will parse the ldap search values into *rpc = (struct - * rpcent *)argp->buf.result which the frontend process expects. Three - * error conditions are expected and returned to nsswitch. + * This method will parse the ldap search values into the file format. + * e.g. + * + * nfs_acl 100227 + * snmp 100122 na.snmp snmp-cmc snmp-synoptics snmp-unisys snmp-utk */ - static int -_nss_ldap_rpc2ent(ldap_backend_ptr be, nss_XbyY_args_t *argp) +_nss_ldap_rpc2str(ldap_backend_ptr be, nss_XbyY_args_t *argp) { - int i, j; + uint_t i; int nss_result; - int buflen = (int)0; - int firstime = (int)1; - unsigned long len = 0L; - char **mp, *cname = NULL; - char *buffer = (char *)NULL; - char *ceiling = (char *)NULL; - struct rpcent *rpc = (struct rpcent *)NULL; + int buflen = 0, len; + char *cname = NULL; + char *buffer = NULL; ns_ldap_result_t *result = be->result; - ns_ldap_attr_t *attrptr; - - buffer = (char *)argp->buf.buffer; - buflen = (size_t)argp->buf.buflen; - if (!argp->buf.result) { - nss_result = (int)NSS_STR_PARSE_ERANGE; - goto result_rpc2ent; - } - rpc = (struct rpcent *)argp->buf.result; - ceiling = buffer + buflen; + ns_ldap_attr_t *names; + char **rpcnumber; - nss_result = (int)NSS_STR_PARSE_SUCCESS; + if (result == NULL) + return (NSS_STR_PARSE_PARSE); + nss_result = NSS_STR_PARSE_SUCCESS; (void) memset(argp->buf.buffer, 0, buflen); - attrptr = getattr(result, 0); - if (attrptr == NULL) { - nss_result = (int)NSS_STR_PARSE_PARSE; - goto result_rpc2ent; - } - for (i = 0; i < result->entry->attr_count; i++) { - attrptr = getattr(result, i); - if (attrptr == NULL) { - nss_result = (int)NSS_STR_PARSE_PARSE; - goto result_rpc2ent; + buflen = argp->buf.buflen; + if (argp->buf.result != NULL) { + if ((be->buffer = calloc(1, buflen)) == NULL) { + nss_result = NSS_STR_PARSE_PARSE; + goto result_rpc2str; } - if (strcasecmp(attrptr->attrname, _R_NAME) == 0) { - for (j = 0; j < attrptr->value_count; j++) { - /* traverse for all multivalued values */ - if (firstime) { - /* rpc name */ - cname = __s_api_get_canonical_name( - result->entry, attrptr, 1); - if (cname == NULL || - (len = strlen(cname)) < 1) { - nss_result = - NSS_STR_PARSE_PARSE; - goto result_rpc2ent; - } - rpc->r_name = buffer; - buffer += len + 1; - if (buffer >= ceiling) { - nss_result = - (int)NSS_STR_PARSE_ERANGE; - goto result_rpc2ent; - } - (void) strcpy(rpc->r_name, cname); - /* alias list */ - mp = rpc->r_aliases = - (char **)ROUND_UP(buffer, - sizeof (char **)); - buffer = (char *)rpc->r_aliases + - sizeof (char *) * - (attrptr->value_count + 1); - buffer = (char *)ROUND_UP(buffer, - sizeof (char **)); - if (buffer >= ceiling) { - nss_result = - (int)NSS_STR_PARSE_ERANGE; - goto result_rpc2ent; - } - firstime = (int)0; - } - /* alias list */ - if ((attrptr->attrvalue[j] == NULL) || - (len = strlen(attrptr->attrvalue[j])) < 1) { - nss_result = (int)NSS_STR_PARSE_PARSE; - goto result_rpc2ent; - } - /* skip canonical name */ - if (strcmp(attrptr->attrvalue[j], cname) == 0) - continue; - *mp = buffer; - buffer += len + 1; - if (buffer >= ceiling) { - nss_result = (int)NSS_STR_PARSE_ERANGE; - goto result_rpc2ent; - } - (void) strcpy(*mp++, attrptr->attrvalue[j]); - continue; - } + buffer = be->buffer; + } else + buffer = argp->buf.buffer; + + + names = __ns_ldap_getAttrStruct(result->entry, _R_NAME); + if (names == NULL || names->attrvalue == NULL) { + nss_result = NSS_STR_PARSE_PARSE; + goto result_rpc2str; + } + /* Get the canonical rpc name */ + cname = __s_api_get_canonical_name(result->entry, names, 1); + if (cname == NULL || (len = strlen(cname)) < 1) { + nss_result = NSS_STR_PARSE_PARSE; + goto result_rpc2str; + } + rpcnumber = __ns_ldap_getAttr(result->entry, _R_NUMBER); + if (rpcnumber == NULL || rpcnumber[0] == NULL || + (len = strlen(rpcnumber[0])) < 1) { + nss_result = NSS_STR_PARSE_PARSE; + goto result_rpc2str; + } + len = snprintf(buffer, buflen, "%s %s", cname, rpcnumber[0]); + TEST_AND_ADJUST(len, buffer, buflen, result_rpc2str); + /* Append aliases */ + for (i = 0; i < names->value_count; i++) { + if (names->attrvalue[i] == NULL) { + nss_result = NSS_STR_PARSE_PARSE; + goto result_rpc2str; } - if (strcasecmp(attrptr->attrname, _R_NUMBER) == 0) { - if ((attrptr->attrvalue[0] == NULL) || - (len = strlen(attrptr->attrvalue[0])) < 1) { - nss_result = (int)NSS_STR_PARSE_PARSE; - goto result_rpc2ent; - } - errno = 0; - rpc->r_number = (int)strtol(attrptr->attrvalue[0], - (char **)NULL, 10); - if (errno != 0) { - nss_result = (int)NSS_STR_PARSE_PARSE; - goto result_rpc2ent; - } - continue; + /* Skip the canonical name */ + if (strcasecmp(names->attrvalue[i], cname) != 0) { + len = snprintf(buffer, buflen, " %s", + names->attrvalue[i]); + TEST_AND_ADJUST(len, buffer, buflen, result_rpc2str); } } - if (mp != NULL) - *mp = NULL; - -#ifdef DEBUG - (void) fprintf(stdout, "\n[getrpcent.c: _nss_ldap_rpc2ent]\n"); - (void) fprintf(stdout, " r_name: [%s]\n", rpc->r_name); - if (mp != NULL) { - for (mp = rpc->r_aliases; *mp != NULL; mp++) - (void) fprintf(stdout, " r_aliases: [%s]\n", *mp); - } - (void) fprintf(stdout, " r_number: [%d]\n", rpc->r_number); -#endif /* DEBUG */ -result_rpc2ent: + /* The front end marshaller doesn't need to copy trailing nulls */ + if (argp->buf.result != NULL) + be->buflen = strlen(be->buffer); + +result_rpc2str: (void) __ns_ldap_freeResult(&be->result); - return ((int)nss_result); + return (nss_result); } - /* * getbyname gets struct rpcent values by rpc name. This function * constructs an ldap search filter using the rpc name invocation @@ -276,5 +217,5 @@ _nss_ldap_rpc_constr(const char *dummy1, const char *dummy2, return ((nss_backend_t *)_nss_ldap_constr(rpc_ops, sizeof (rpc_ops)/sizeof (rpc_ops[0]), - _RPC, rpc_attrs, _nss_ldap_rpc2ent)); + _RPC, rpc_attrs, _nss_ldap_rpc2str)); } diff --git a/usr/src/lib/nsswitch/ldap/common/getservent.c b/usr/src/lib/nsswitch/ldap/common/getservent.c index e266a31b42..9d83298fbc 100644 --- a/usr/src/lib/nsswitch/ldap/common/getservent.c +++ b/usr/src/lib/nsswitch/ldap/common/getservent.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2003 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -91,14 +90,15 @@ _nss_services_cookie_new(ns_ldap_result_t *result, int index, char *cname) { return (cookie); } - /* - * _nss_ldap_services2ent is the data marshaling method for the services + * _nss_ldap_services2str is the data marshaling method for the services * getXbyY * (e.g., getbyname(), getbyport(), getent()) backend processes. * This method is called after a successful ldap search has been performed. - * This method will parse the ldap search values into *serv = (struct - * servent *)argp->buf.result which the frontend process expects. Three error - * conditions are expected and returned to nsswitch. + * This method will parse the ldap search values into the file format. + * e.g. + * + * nfsd 2049/udp nfs + * nfsd 2049/tcp nfs * * In section 5.5 of RFC 2307, it specifies that a "services" LDAP entry * containing multiple ipserviceprotocol values should be able to be mapped @@ -107,30 +107,18 @@ _nss_services_cookie_new(ns_ldap_result_t *result, int index, char *cname) { */ static int -_nss_ldap_services2ent(ldap_backend_ptr be, nss_XbyY_args_t *argp) +_nss_ldap_services2str(ldap_backend_ptr be, nss_XbyY_args_t *argp) { - int i, j, k; + uint_t i, k; int nss_result; - int buflen = (int)0; - int firstime = (int)1; - unsigned long len = 0L; - char **mp, *cname = NULL, *protoval = NULL; - char *buffer = (char *)NULL; - char *ceiling = (char *)NULL; - struct servent *serv = (struct servent *)NULL; + int buflen = 0, len; + char **ipport, *cname = NULL, *protoval = NULL; + char *buffer = NULL; ns_ldap_result_t *result; - ns_ldap_attr_t *attrptr, *protocol = NULL; + ns_ldap_attr_t *names = NULL, *protocol = NULL; _nss_services_cookie_t *cookie = (_nss_services_cookie_t *) be->services_cookie; - buffer = (char *)argp->buf.buffer; - buflen = (size_t)argp->buf.buflen; - serv = (struct servent *)argp->buf.result; - ceiling = buffer + buflen; -#ifdef DEBUG - (void) fprintf(stderr, "[getservent.c: _nss_ldap_services2ent]\n"); -#endif /* DEBUG */ - if (cookie) { /* * getservent_r with multiple protocol values and the entry @@ -146,160 +134,123 @@ _nss_ldap_services2ent(ldap_backend_ptr be, nss_XbyY_args_t *argp) */ result = be->result; } + if (result == NULL) { + nss_result = NSS_STR_PARSE_PARSE; + goto result_srvs2str; + } + + buflen = argp->buf.buflen; + if (argp->buf.result != NULL) { + if ((be->buffer = calloc(1, buflen)) == NULL) { + nss_result = NSS_STR_PARSE_PARSE; + goto result_srvs2str; + } + buffer = be->buffer; + } else + buffer = argp->buf.buffer; + - nss_result = (int)NSS_STR_PARSE_SUCCESS; + nss_result = NSS_STR_PARSE_SUCCESS; (void) memset(argp->buf.buffer, 0, buflen); - attrptr = getattr(result, 0); - if (attrptr == NULL) { - nss_result = (int)NSS_STR_PARSE_PARSE; - goto result_srvs2ent; + /* Get services names */ + names = __ns_ldap_getAttrStruct(result->entry, _S_NAME); + if (names == NULL || names->attrvalue == NULL) { + nss_result = NSS_STR_PARSE_PARSE; + goto result_srvs2str; + } + /* Get canonical services name */ + if (cname == NULL) { + cname = __s_api_get_canonical_name(result->entry, names, 1); + if (cname == NULL || (len = strlen(cname)) < 1) { + nss_result = NSS_STR_PARSE_PARSE; + goto result_srvs2str; + } + } + /* Get port */ + ipport = __ns_ldap_getAttr(result->entry, _S_PORT); + if (ipport == NULL || ipport[0] == NULL || + (len = strlen(cname)) < 1) { + nss_result = NSS_STR_PARSE_PARSE; + goto result_srvs2str; + } + /* Set services name and port and '/' */ + len = snprintf(buffer, buflen, "%s %s/", cname, ipport[0]); + TEST_AND_ADJUST(len, buffer, buflen, result_srvs2str); + + /* Get protocol */ + protocol = __ns_ldap_getAttrStruct(result->entry, _S_PROTOCOL); + if (protocol == NULL || protocol->attrvalue == NULL) { + nss_result = NSS_STR_PARSE_PARSE; + goto result_srvs2str; } - for (i = 0; i < result->entry->attr_count; i++) { - attrptr = getattr(result, i); - if (attrptr == NULL) { - nss_result = (int)NSS_STR_PARSE_PARSE; - goto result_srvs2ent; - } - if (strcasecmp(attrptr->attrname, _S_NAME) == 0) { - for (j = 0; j < attrptr->value_count; j++) { - if (firstime) { - /* service name */ - if (cname == NULL) { - cname = __s_api_get_canonical_name( - result->entry, attrptr, 1); - } - if (cname == NULL || - (len = strlen(cname)) < 1) { - nss_result = - NSS_STR_PARSE_PARSE; - goto result_srvs2ent; - } - serv->s_name = buffer; - buffer += len + 1; - if (buffer >= ceiling) { - nss_result = - (int)NSS_STR_PARSE_ERANGE; - goto result_srvs2ent; - } - (void) strcpy(serv->s_name, cname); - /* alias list */ - mp = serv->s_aliases = - (char **)ROUND_UP(buffer, - sizeof (char **)); - buffer = (char *)serv->s_aliases + - sizeof (char *) * - (attrptr->value_count + 1); - buffer = (char *)ROUND_UP(buffer, - sizeof (char **)); - if (buffer >= ceiling) { - nss_result = - (int)NSS_STR_PARSE_ERANGE; - goto result_srvs2ent; - } - firstime = (int)0; - } - /* alias list */ - if ((attrptr->attrvalue[j] == NULL) || - (len = strlen(attrptr->attrvalue[j])) < 1) { - nss_result = (int)NSS_STR_PARSE_PARSE; - goto result_srvs2ent; - } - /* skip canonical name */ - if (strcmp(cname, attrptr->attrvalue[j]) == 0) - continue; - - *mp = buffer; - buffer += len + 1; - if (buffer >= ceiling) { - nss_result = (int)NSS_STR_PARSE_ERANGE; - goto result_srvs2ent; - } - (void) strcpy(*mp++, attrptr->attrvalue[j]); - continue; - } - } - if (strcasecmp(attrptr->attrname, _S_PORT) == 0) { - if ((attrptr->attrvalue[0] == NULL) || - (len = strlen(attrptr->attrvalue[0])) < 1) { - nss_result = (int)NSS_STR_PARSE_PARSE; - goto result_srvs2ent; + if (cookie) { + /* + * getservent_r + * Get current value then increment index + */ + protoval = protocol->attrvalue[cookie->index++]; + } else if (protocol->value_count > 1 && be->setcalled == 0 && + argp->key.serv.proto) { + /* + * getserverbyname_r and getservbyport_r + * + * If there are more than one value and + * it needs to match protocol too, + * iterate each value to find matching one. + */ + for (k = 0; k < protocol->value_count; k++) { + if (protocol->attrvalue[k] == NULL) { + nss_result = NSS_STR_PARSE_PARSE; + goto result_srvs2str; + } + if (strcmp(protocol->attrvalue[k], + argp->key.serv.proto) == 0) { + protoval = protocol->attrvalue[k]; + break; } - serv->s_port = - htons((ushort_t)atoi(attrptr->attrvalue[0])); - continue; } + } else { + /* + * 1. getserverbyname_r and getservbyport_r + * + * It does not need to match protocol or + * ipserviceprotocol has single value, + * return the first one. + * + * 2. getservent_r with single ipserviceprotocol value + * or multiple values and the entry is + * enumerated 1st time, return the first one. + * + */ + protoval = protocol->attrvalue[0]; + } - if (strcasecmp(attrptr->attrname, _S_PROTOCOL) == 0) { - /* protocol name */ - if (attrptr->attrvalue == NULL) { - nss_result = (int)NSS_STR_PARSE_PARSE; - goto result_srvs2ent; - } - protocol = attrptr; - if (cookie) { - /* - * getservent_r - * Get current value then increment index - */ - protoval = attrptr->attrvalue[cookie->index++]; - } else if (attrptr->value_count > 1 && - argp->key.serv.proto) { - /* - * getserverbyname_r and getservbyport_r - * - * If there are more than one value and - * it needs to match protocol too, - * iterate each value to find matching one. - * getservent_r sets key.serv.proto to NULL, - * so it wouldn't run this part of code. - */ - for (k = 0; k < attrptr->value_count; k++) { - if (attrptr->attrvalue[k] == NULL) { - nss_result = - NSS_STR_PARSE_PARSE; - goto result_srvs2ent; - } - if (strcmp(attrptr->attrvalue[k], - argp->key.serv.proto) == 0) { - protoval = - attrptr->attrvalue[k]; - break; - } - } - } else { - /* - * 1. getserverbyname_r and getservbyport_r - * - * It does not need to match protocol or - * ipserviceprotocol has single value, - * return the first one - * - * 2. getservent_r with single value - * or multiple values and the entry is - * enumerated 1st time, - * return the first one - * - */ - protoval = attrptr->attrvalue[0]; - } + if (protoval == NULL || (len = strlen(protoval)) < 1) { + nss_result = NSS_STR_PARSE_PARSE; + goto result_srvs2str; + } - if (protoval == NULL || (len = strlen(protoval)) < 1) { - nss_result = (int)NSS_STR_PARSE_PARSE; - goto result_srvs2ent; - } - serv->s_proto = buffer; - buffer += len + 1; - if (buffer >= ceiling) { - nss_result = (int)NSS_STR_PARSE_ERANGE; - goto result_srvs2ent; - } - (void) strcpy(serv->s_proto, protoval); - continue; + /* Set protocol */ + len = snprintf(buffer, buflen, "%s", protoval); + TEST_AND_ADJUST(len, buffer, buflen, result_srvs2str); + + /* Append aliases */ + for (i = 0; i < names->value_count; i++) { + if (names->attrvalue[i] == NULL) { + nss_result = NSS_STR_PARSE_PARSE; + goto result_srvs2str; + } + /* Skip the canonical name */ + if (strcmp(cname, names->attrvalue[i]) != 0) { + len = snprintf(buffer, buflen, " %s", + names->attrvalue[i]); + TEST_AND_ADJUST(len, buffer, buflen, result_srvs2str); } } + if (be->enumcookie != NULL && cookie == NULL && protocol->value_count > 1) { /* @@ -314,25 +265,18 @@ _nss_ldap_services2ent(ldap_backend_ptr be, nss_XbyY_args_t *argp) (void *)_nss_services_cookie_new(be->result, 1, cname); if (be->services_cookie == NULL) { nss_result = NSS_STR_PARSE_PARSE; - goto result_srvs2ent; + goto result_srvs2str; } /* reset be->result so it won't get freed later */ be->result = NULL; } -#ifdef DEBUG - (void) fprintf(stdout, "\n[getservent.c: _nss_ldap_services2ent]\n"); - (void) fprintf(stdout, " s_name: [%s]\n", serv->s_name); - if (mp != NULL) { - for (mp = serv->s_aliases; *mp != NULL; mp++) - (void) fprintf(stdout, " s_aliases: [%s]\n", *mp); - } - (void) fprintf(stdout, " s_port: [%d]\n", serv->s_port); - (void) fprintf(stdout, " s_protocol: [%s]\n", serv->s_proto); -#endif /* DEBUG */ + /* The front end marshaller doesn't need to copy trailing nulls */ + if (argp->buf.result != NULL) + be->buflen = strlen(be->buffer); -result_srvs2ent: +result_srvs2str: if (cookie) { /* * getservent_r with multiple ipserviceprotocol values and @@ -356,10 +300,9 @@ result_srvs2ent: */ (void) __ns_ldap_freeResult(&be->result); } - return ((int)nss_result); + return (nss_result); } - /* * getbyname gets struct servent values by service name. This * function constructs an ldap search filter using the service @@ -498,5 +441,5 @@ _nss_ldap_services_constr(const char *dummy1, const char *dummy2, return ((nss_backend_t *)_nss_ldap_constr(serv_ops, sizeof (serv_ops)/sizeof (serv_ops[0]), _SERVICES, - services_attrs, _nss_ldap_services2ent)); + services_attrs, _nss_ldap_services2str)); } diff --git a/usr/src/lib/nsswitch/ldap/common/getspent.c b/usr/src/lib/nsswitch/ldap/common/getspent.c index cf5ea84652..dc93c5d9ca 100644 --- a/usr/src/lib/nsswitch/ldap/common/getspent.c +++ b/usr/src/lib/nsswitch/ldap/common/getspent.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2003 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -31,7 +30,6 @@ #include "ldap_common.h" /* shadow attributes filters */ -#define _S_CN "cn" #define _S_UID "uid" #define _S_USERPASSWORD "userpassword" #define _S_FLAG "shadowflag" @@ -46,185 +44,105 @@ static const char *sp_attrs[] = { (char *)NULL }; - -extern ns_ldap_attr_t *getattr(ns_ldap_result_t *result, int i); - /* - * _nss_ldap_shadow2ent is the data marshaling method for the passwd getXbyY + * _nss_ldap_shadow2str is the data marshaling method for the shadow getXbyY * (e.g., getspnam(), getspent()) backend processes. This method is called after * a successful ldap search has been performed. This method will parse the - * ldap search values into struct spwd = argp->buf.buffer which the frontend - * process expects. Three error conditions are expected and returned to - * nsswitch. + * ldap search values into the file format. + * e.g. + * + * myname:gaBXNJuz4JDmA:6445:::::: + * */ static int -_nss_ldap_shadow2ent(ldap_backend_ptr be, nss_XbyY_args_t *argp) +_nss_ldap_shadow2str(ldap_backend_ptr be, nss_XbyY_args_t *argp) { - int i = 0; int nss_result; - int buflen = (int)0; + int buflen = 0; unsigned long len = 0L; - char *buffer = (char *)NULL; - char *ceiling = (char *)NULL; - char *pw_passwd = (char *)NULL; - char *nullstring = (char *)NULL; + char *tmp, *buffer = NULL; + char *pw_passwd = NULL; char np[] = "*NP*"; ns_ldap_result_t *result = be->result; - ns_ldap_attr_t *attrptr; - long ltmp = (long)0L; - struct spwd *spd = (struct spwd *)NULL; - -#ifdef DEBUG - (void) fprintf(stdout, "\n[getspent.c: _nss_ldap_shadow2ent]\n"); -#endif /* DEBUG */ + char **uid, **passwd, **flag, *flag_str; - buffer = argp->buf.buffer; - buflen = (size_t)argp->buf.buflen; - if (!argp->buf.result) { - nss_result = (int)NSS_STR_PARSE_ERANGE; - goto result_spd2ent; - } - spd = (struct spwd *)argp->buf.result; - ceiling = buffer + buflen; - nullstring = (buffer + (buflen - 1)); - - /* Default values */ - spd->sp_lstchg = -1; spd->sp_min = -1; - spd->sp_max = -1; spd->sp_warn = -1; - spd->sp_inact = -1; spd->sp_expire = -1; - spd->sp_flag = 0; spd->sp_pwdp = NULL; + if (result == NULL) + return (NSS_STR_PARSE_PARSE); + buflen = argp->buf.buflen; - nss_result = (int)NSS_STR_PARSE_SUCCESS; - (void) memset(buffer, 0, buflen); + nss_result = NSS_STR_PARSE_SUCCESS; + (void) memset(argp->buf.buffer, 0, buflen); - attrptr = getattr(result, 0); - if (attrptr == NULL) { - nss_result = (int)NSS_STR_PARSE_PARSE; - goto result_spd2ent; + uid = __ns_ldap_getAttr(result->entry, _S_UID); + if (uid == NULL || uid[0] == NULL || (strlen(uid[0]) < 1)) { + nss_result = NSS_STR_PARSE_PARSE; + goto result_spd2str; } - - for (i = 0; i < result->entry->attr_count; i++) { - attrptr = getattr(result, i); - if (strcasecmp(attrptr->attrname, _S_UID) == 0) { - if ((attrptr->attrvalue[0] == NULL) || - (len = strlen(attrptr->attrvalue[0])) < 1) { - nss_result = (int)NSS_STR_PARSE_PARSE; - goto result_spd2ent; - } - spd->sp_namp = buffer; - buffer += len + 1; - if (buffer >= ceiling) { - nss_result = (int)NSS_STR_PARSE_ERANGE; - goto result_spd2ent; - } - (void) strcpy(spd->sp_namp, attrptr->attrvalue[0]); - continue; - } - if (strcasecmp(attrptr->attrname, _S_USERPASSWORD) == 0) { - if (attrptr->attrvalue[0] == '\0') { - spd->sp_pwdp = nullstring; - nss_result = (int)NSS_STR_PARSE_PARSE; - goto result_spd2ent; - } - pw_passwd = attrptr->attrvalue[0]; - if (pw_passwd) { - char *tmp; - - if ((tmp = strstr(pw_passwd, "{crypt}")) - != NULL) { - if (tmp != pw_passwd) - pw_passwd = np; - else - pw_passwd += 7; - } else if ((tmp = strstr(pw_passwd, "{CRYPT}")) - != NULL) { - if (tmp != pw_passwd) - pw_passwd = np; - else - pw_passwd += 7; - } else { - pw_passwd = np; - } - } - len = (unsigned long)strlen(pw_passwd); - if (len < 1) { - spd->sp_pwdp = nullstring; - } else { - spd->sp_pwdp = buffer; - buffer += len + 1; - if (buffer >= ceiling) { - nss_result = (int)NSS_STR_PARSE_ERANGE; - goto result_spd2ent; - } - } - (void) strcpy(spd->sp_pwdp, pw_passwd); - } - - /* - * Ignore the following password aging related attributes: - * -- shadowlastchange - * -- shadowmin - * -- shadowmax - * -- shadowwarning - * -- shadowinactive - * -- shadowexpire - * This is because the LDAP naming service does not - * really support the password aging fields defined - * in the shadow structure. These fields, sp_lstchg, - * sp_min, sp_max, sp_warn, sp_inact, and sp_expire, - * have been set to -1. - */ - - if (strcasecmp(attrptr->attrname, _S_FLAG) == 0) { - if (attrptr->attrvalue[0] == '\0') { - nss_result = (int)NSS_STR_PARSE_PARSE; - goto result_spd2ent; - } - errno = 0; - ltmp = strtol(attrptr->attrvalue[0], (char **)NULL, 10); - if (errno != 0) { - nss_result = (int)NSS_STR_PARSE_PARSE; - goto result_spd2ent; - } - spd->sp_flag = (int)ltmp; - continue; + len += strlen(uid[0]); + + passwd = __ns_ldap_getAttr(result->entry, _S_USERPASSWORD); + if (passwd == NULL || passwd[0] == NULL || strlen(passwd[0]) < 1) { + pw_passwd = _NO_VALUE; + } else { + if ((tmp = strstr(passwd[0], "{crypt}")) != NULL || + (tmp = strstr(passwd[0], "{CRYPT}")) != NULL) { + if (tmp != passwd[0]) + pw_passwd = np; + else + pw_passwd = tmp + strlen("{crypt}"); + } else { + /* Replace it with *NP* */ + pw_passwd = np; } } - - /* we will not allow for an empty password to be */ - /* returned to the front end as this is not a supported */ - /* configuration. Since we got to this point without */ - /* the password being set, we assume that no password was */ - /* set on the server which is consider a misconfiguration. */ - /* We will proceed and set the password to *NP* as no password */ - /* is not supported */ - - if (spd->sp_pwdp == NULL) { - spd->sp_pwdp = buffer; - buffer += strlen(np) + 1; - if (buffer >= ceiling) { - nss_result = (int)NSS_STR_PARSE_ERANGE; - goto result_spd2ent; - } - strcpy(spd->sp_pwdp, np); + len += strlen(pw_passwd); + + /* + * Ignore the following password aging related attributes: + * -- shadowlastchange + * -- shadowmin + * -- shadowmax + * -- shadowwarning + * -- shadowinactive + * -- shadowexpire + * This is because the LDAP naming service does not + * really support the password aging fields defined + * in the shadow structure. These fields, sp_lstchg, + * sp_min, sp_max, sp_warn, sp_inact, and sp_expire, + * will be set to -1 by the front end marshaller. + */ + flag = __ns_ldap_getAttr(result->entry, _S_FLAG); + if (flag == NULL || flag[0] == NULL) + flag_str = _NO_VALUE; + else + flag_str = flag[0]; + + /* 9 = 8 ':' + 1 '\0' */ + len += strlen(flag_str) + 9; + + if (len > buflen) { + nss_result = NSS_STR_PARSE_ERANGE; + goto result_spd2str; } + if (argp->buf.result != NULL) { + be->buffer = calloc(1, len); + if (be->buffer == NULL) { + nss_result = NSS_STR_PARSE_PARSE; + goto result_spd2str; + } + buffer = be->buffer; + } else + buffer = argp->buf.buffer; -#ifdef DEBUG - (void) fprintf(stdout, "\n[getspent.c: _nss_ldap_shadow2ent]\n"); - (void) fprintf(stdout, " sp_namp: [%s]\n", spd->sp_namp); - (void) fprintf(stdout, " sp_pwdp: [%s]\n", spd->sp_pwdp); - (void) fprintf(stdout, " sp_latchg: [%d]\n", spd->sp_lstchg); - (void) fprintf(stdout, " sp_min: [%d]\n", spd->sp_min); - (void) fprintf(stdout, " sp_max: [%d]\n", spd->sp_max); - (void) fprintf(stdout, " sp_warn: [%d]\n", spd->sp_warn); - (void) fprintf(stdout, " sp_inact: [%d]\n", spd->sp_inact); - (void) fprintf(stdout, " sp_expire: [%d]\n", spd->sp_expire); - (void) fprintf(stdout, " sp_flag: [%d]\n", spd->sp_flag); -#endif /* DEBUG */ + (void) snprintf(buffer, len, "%s:%s:::::::%s", + uid[0], pw_passwd, flag_str); -result_spd2ent: + /* The front end marhsaller doesn't need the trailing null */ + if (argp->buf.result != NULL) + be->buflen = strlen(be->buffer); +result_spd2str: (void) __ns_ldap_freeResult(&be->result); return ((int)nss_result); @@ -245,13 +163,8 @@ getbynam(ldap_backend_ptr be, void *a) char searchfilter[SEARCHFILTERLEN]; char userdata[SEARCHFILTERLEN]; char name[SEARCHFILTERLEN + 1]; - int len; int ret; -#ifdef DEBUG - (void) fprintf(stdout, "\n[getspent.c: getbynam]\n"); -#endif /* DEBUG */ - if (_ldap_filter_name(name, argp->key.name, sizeof (name)) != 0) return ((nss_status_t)NSS_NOTFOUND); @@ -288,11 +201,7 @@ _nss_ldap_shadow_constr(const char *dummy1, const char *dummy2, const char *dummy3) { -#ifdef DEBUG - (void) fprintf(stdout, "\n[getspent.c: _nss_ldap_shadow_constr]\n"); -#endif /* DEBUG */ - return ((nss_backend_t *)_nss_ldap_constr(sp_ops, sizeof (sp_ops)/sizeof (sp_ops[0]), - _SHADOW, sp_attrs, _nss_ldap_shadow2ent)); + _SHADOW, sp_attrs, _nss_ldap_shadow2str)); } diff --git a/usr/src/lib/nsswitch/ldap/common/getuserattr.c b/usr/src/lib/nsswitch/ldap/common/getuserattr.c index d36194d27e..c804a92187 100644 --- a/usr/src/lib/nsswitch/ldap/common/getuserattr.c +++ b/usr/src/lib/nsswitch/ldap/common/getuserattr.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2003 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -50,149 +49,87 @@ static const char *user_attrs[] = { _USER_ATTRS, (char *)NULL }; - - +/* + * _nss_ldap_user2str is the data marshaling method for the user_attr + * system call getuserattr, getusernam and getuseruid. + * This method is called after a successful search has been performed. + * This method will parse the search results into the file format. + * e.g. + * + * adm::::profiles=Log Management + * + */ static int -_nss_ldap_user2ent(ldap_backend_ptr be, nss_XbyY_args_t *argp) +_nss_ldap_user2str(ldap_backend_ptr be, nss_XbyY_args_t *argp) { - int i, nss_result; - int buflen = (int)0; + int nss_result; + int buflen = 0; unsigned long len = 0L; - char *nullstring = (char *)NULL; - char *buffer = (char *)NULL; - char *ceiling = (char *)NULL; - userstr_t *user = (userstr_t *)NULL; - ns_ldap_attr_t *attrptr; + char *buffer = NULL; ns_ldap_result_t *result = be->result; + char **name, **res1, **res2, **qu, **attr; + char *res1_str, *res2_str, *qu_str, *attr_str; - buffer = argp->buf.buffer; - buflen = (size_t)argp->buf.buflen; - if (!argp->buf.result) { - nss_result = (int)NSS_STR_PARSE_ERANGE; - goto result_user2ent; - } - user = (userstr_t *)(argp->buf.result); - ceiling = buffer + buflen; - user->name = (char *)NULL; - user->qualifier = (char *)NULL; - user->res1 = (char *)NULL; - user->res2 = (char *)NULL; - user->attr = (char *)NULL; - nss_result = (int)NSS_STR_PARSE_SUCCESS; + if (result == NULL) + return (NSS_STR_PARSE_PARSE); + + buflen = argp->buf.buflen; + nss_result = NSS_STR_PARSE_SUCCESS; (void) memset(argp->buf.buffer, 0, buflen); - attrptr = getattr(result, 0); - if (attrptr == NULL) { - nss_result = (int)NSS_STR_PARSE_PARSE; - goto result_user2ent; + name = __ns_ldap_getAttr(result->entry, _USER_NAME); + if (name == NULL || name[0] == NULL || + (strlen(name[0]) < 1)) { + nss_result = NSS_STR_PARSE_PARSE; + goto result_user2str; } - for (i = 0; i < result->entry->attr_count; i++) { - attrptr = getattr(result, i); - if (attrptr == NULL) { - nss_result = (int)NSS_STR_PARSE_PARSE; - goto result_user2ent; - } - if (strcasecmp(attrptr->attrname, _USER_NAME) == 0) { - if ((attrptr->attrvalue[0] == NULL) || - (len = strlen(attrptr->attrvalue[0])) < 1) { - nss_result = (int)NSS_STR_PARSE_PARSE; - goto result_user2ent; - } - user->name = buffer; - buffer += len + 1; - if (buffer >= ceiling) { - nss_result = (int)NSS_STR_PARSE_ERANGE; - goto result_user2ent; - } - (void) strcpy(user->name, attrptr->attrvalue[0]); - continue; - } - if (strcasecmp(attrptr->attrname, _USER_QUALIFIER) == 0) { - if ((attrptr->attrvalue[0] == NULL) || - (len = strlen(attrptr->attrvalue[0])) < 1) { - user->qualifier = nullstring; - } else { - user->qualifier = buffer; - buffer += len + 1; - if (buffer >= ceiling) { - nss_result = (int)NSS_STR_PARSE_ERANGE; - goto result_user2ent; - } - (void) strcpy(user->qualifier, - attrptr->attrvalue[0]); - } - continue; - } - if (strcasecmp(attrptr->attrname, _USER_RES1) == 0) { - if ((attrptr->attrvalue[0] == NULL) || - (len = strlen(attrptr->attrvalue[0])) < 1) { - user->res1 = nullstring; - } else { - user->res1 = buffer; - buffer += len + 1; - if (buffer >= ceiling) { - nss_result = (int)NSS_STR_PARSE_ERANGE; - goto result_user2ent; - } - (void) strcpy(user->res1, - attrptr->attrvalue[0]); - } - continue; - } - if (strcasecmp(attrptr->attrname, _USER_RES2) == 0) { - if ((attrptr->attrvalue[0] == NULL) || - (len = strlen(attrptr->attrvalue[0])) < 1) { - user->res2 = nullstring; - } else { - user->res2 = buffer; - buffer += len + 1; - if (buffer >= ceiling) { - nss_result = (int)NSS_STR_PARSE_ERANGE; - goto result_user2ent; - } - (void) strcpy(user->res2, - attrptr->attrvalue[0]); - } - continue; - } - if (strcasecmp(attrptr->attrname, _USER_ATTRS) == 0) { - if ((attrptr->attrvalue[0] == NULL) || - (len = strlen(attrptr->attrvalue[0])) < 1) { - user->attr = nullstring; - } else { - user->attr = buffer; - buffer += len + 1; - if (buffer >= ceiling) { - nss_result = (int)NSS_STR_PARSE_ERANGE; - goto result_user2ent; - } - (void) strcpy(user->attr, - attrptr->attrvalue[0]); - } - continue; - } - } - -#ifdef DEBUG - (void) fprintf(stdout, "\n[getuserattr.c: _nss_ldap_user2ent]\n"); - (void) fprintf(stdout, " user-name: [%s]\n", user->name); - if (user->qualifier != (char *)NULL) { - (void) fprintf(stdout, " qualifier: [%s]\n", - user->qualifier); + qu = __ns_ldap_getAttr(result->entry, _USER_QUALIFIER); + if (qu == NULL || qu[0] == NULL || (strlen(qu[0]) < 1)) + qu_str = _NO_VALUE; + else + qu_str = qu[0]; + + res1 = __ns_ldap_getAttr(result->entry, _USER_RES2); + if (res1 == NULL || res1[0] == NULL || (strlen(res1[0]) < 1)) + res1_str = _NO_VALUE; + else + res1_str = res1[0]; + + res2 = __ns_ldap_getAttr(result->entry, _USER_RES2); + if (res2 == NULL || res2[0] == NULL || (strlen(res2[0]) < 1)) + res2_str = _NO_VALUE; + else + res2_str = res2[0]; + + attr = __ns_ldap_getAttr(result->entry, _USER_ATTRS); + if (attr == NULL || attr[0] == NULL || (strlen(attr[0]) < 1)) + attr_str = _NO_VALUE; + else + attr_str = attr[0]; + /* 5 = 4 ':' + 1 '\0' */ + len = strlen(name[0]) + strlen(res1_str) + strlen(res2_str) + + strlen(qu_str) + strlen(attr_str) + 5; + if (len > buflen) { + nss_result = NSS_STR_PARSE_ERANGE; + goto result_user2str; } - if (user->res1 != (char *)NULL) { - (void) fprintf(stdout, " res1: [%s]\n", user->res1); - } - if (user->res2 != (char *)NULL) { - (void) fprintf(stdout, " res2: [%s]\n", user->res2); - } - if (user->attr != (char *)NULL) { - (void) fprintf(stdout, " attr: [%s]\n", user->attr); - } -#endif /* DEBUG */ -result_user2ent: + if (argp->buf.result != NULL) { + if ((be->buffer = calloc(1, len)) == NULL) { + nss_result = NSS_STR_PARSE_PARSE; + goto result_user2str; + } + buffer = be->buffer; + } else + buffer = argp->buf.buffer; + (void) snprintf(buffer, len, "%s:%s:%s:%s:%s", + name[0], qu_str, res1_str, res2_str, attr_str); + /* The front end marshaller doesn't need the trailing null */ + if (argp->buf.result != NULL) + be->buflen = strlen(be->buffer); + +result_user2str: (void) __ns_ldap_freeResult(&be->result); return ((int)nss_result); } @@ -207,10 +144,6 @@ getbyname(ldap_backend_ptr be, void *a) char name[SEARCHFILTERLEN]; int ret; -#ifdef DEBUG - (void) fprintf(stdout, "\n[getuserattr.c: getbyname]\n"); -#endif /* DEBUG */ - if (_ldap_filter_name(name, argp->key.name, sizeof (name)) != 0) return ((nss_status_t)NSS_NOTFOUND); @@ -246,11 +179,7 @@ _nss_ldap_user_attr_constr(const char *dummy1, const char *dummy4, const char *dummy5) { -#ifdef DEBUG - (void) fprintf(stdout, - "\n[getuserattr.c: _nss_ldap_user_attr_constr]\n"); -#endif return ((nss_backend_t *)_nss_ldap_constr(userattr_ops, sizeof (userattr_ops)/sizeof (userattr_ops[0]), _USERATTR, - user_attrs, _nss_ldap_user2ent)); + user_attrs, _nss_ldap_user2str)); } diff --git a/usr/src/lib/nsswitch/ldap/common/ldap_common.c b/usr/src/lib/nsswitch/ldap/common/ldap_common.c index 9d961d9d1d..a6537c7b41 100644 --- a/usr/src/lib/nsswitch/ldap/common/ldap_common.c +++ b/usr/src/lib/nsswitch/ldap/common/ldap_common.c @@ -45,7 +45,8 @@ #define _F_GETGRENT "(objectClass=posixGroup)" #define _F_GETHOSTENT "(objectClass=ipHost)" #define _F_GETNETENT "(objectClass=ipNetwork)" -#define _F_GETPROFNAME "(objectClass=SolarisProfAttr)" +#define _F_GETPROFNAME \ +"(&(objectClass=SolarisProfAttr)(!(SolarisKernelSecurityPolicy=*)))" #define _F_GETPROTOENT "(objectClass=ipProtocol)" #define _F_GETPWENT "(objectClass=posixAccount)" #define _F_GETPRINTERENT "(objectClass=sunPrinter)" @@ -85,7 +86,7 @@ static struct gettablefilter { }; -nss_status_t +static nss_status_t switch_err(int rc, ns_ldap_error_t *error) { switch (rc) { @@ -109,6 +110,7 @@ switch_err(int rc, ns_ldap_error_t *error) return (NSS_UNAVAIL); } } +/* ARGSUSED */ nss_status_t _nss_ldap_lookup(ldap_backend_ptr be, nss_XbyY_args_t *argp, char *database, char *searchfilter, char *domain, @@ -136,16 +138,79 @@ _nss_ldap_lookup(ldap_backend_ptr be, nss_XbyY_args_t *argp, argp->returnval = 0; rc = switch_err(rc, error); (void) __ns_ldap_freeError(&error); + return (rc); } + (void) __ns_ldap_freeError(&error); /* callback function */ if ((callbackstat = - be->ldapobj2ent(be, argp)) == NSS_STR_PARSE_SUCCESS) { - argp->returnval = argp->buf.result; - return ((nss_status_t)NSS_SUCCESS); + be->ldapobj2str(be, argp)) != NSS_STR_PARSE_SUCCESS) { + goto error_out; } - (void) __ns_ldap_freeResult(&be->result); + /* + * publickey does not have a front end marshaller and expects + * a string to be returned in NSS. + * No need to convert file format -> struct. + * + */ + if (be->db_type == NSS_LDAP_DB_PUBLICKEY) { + argp->returnval = argp->buf.buffer; + argp->returnlen = strlen(argp->buf.buffer); + be->db_type = NSS_LDAP_DB_NONE; + return (NSS_SUCCESS); + } + /* + * Assume the switch engine wants the returned data in the file + * format when argp->buf.result == NULL. + * The front-end marshaller str2ether(ethers) uses + * ent (argp->buf.result) and buffer (argp->buf.buffer) + * for different purpose so ethers has to be treated differently. + */ + if (argp->buf.result != NULL || + be->db_type == NSS_LDAP_DB_ETHERS) { + /* file format -> struct */ + if (argp->str2ent == NULL) { + callbackstat = NSS_STR_PARSE_PARSE; + goto error_out; + } + + callbackstat = (*argp->str2ent)(be->buffer, + be->buflen, + argp->buf.result, + argp->buf.buffer, + argp->buf.buflen); + if (callbackstat == NSS_STR_PARSE_SUCCESS) { + if (be->db_type == NSS_LDAP_DB_ETHERS && + argp->buf.buffer != NULL) { + argp->returnval = argp->buf.buffer; + argp->returnlen = strlen(argp->buf.buffer); + } else { + argp->returnval = argp->buf.result; + argp->returnlen = 1; /* irrelevant */ + } + if (be->buffer != NULL) { + free(be->buffer); + be->buffer = NULL; + be->buflen = 0; + be->db_type = NSS_LDAP_DB_NONE; + } + return ((nss_status_t)NSS_SUCCESS); + } + } else { + /* return file format in argp->buf.buffer */ + argp->returnval = argp->buf.buffer; + argp->returnlen = strlen(argp->buf.buffer); + return ((nss_status_t)NSS_SUCCESS); + } + +error_out: + if (be->buffer != NULL) { + free(be->buffer); + be->buffer = NULL; + be->buflen = 0; + be->db_type = NSS_LDAP_DB_NONE; + } /* error */ if (callbackstat == NSS_STR_PARSE_PARSE) { argp->returnval = 0; @@ -163,12 +228,12 @@ _nss_ldap_lookup(ldap_backend_ptr be, nss_XbyY_args_t *argp, return ((nss_status_t)NSS_UNAVAIL); } - /* * This function is similar to _nss_ldap_lookup except it does not * do a callback. It is only used by getnetgrent.c */ +/* ARGSUSED */ nss_status_t _nss_ldap_nocb_lookup(ldap_backend_ptr be, nss_XbyY_args_t *argp, char *database, char *searchfilter, char *domain, @@ -227,6 +292,10 @@ _clean_ldap_backend(ldap_backend_ptr be) free(be->toglue); be->toglue = NULL; } + if (be->buffer != NULL) { + free(be->buffer); + be->buffer = NULL; + } free(be); } @@ -280,6 +349,7 @@ _nss_ldap_setent(ldap_backend_ptr be, void *a) be->enumcookie = NULL; be->result = NULL; be->services_cookie = NULL; + be->buffer = NULL; return ((nss_status_t)NSS_SUCCESS); } @@ -311,6 +381,10 @@ _nss_ldap_endent(ldap_backend_ptr be, void *a) if (be->services_cookie != NULL) { _nss_services_cookie_free((void **)&be->services_cookie); } + if (be->buffer != NULL) { + free(be->buffer); + be->buffer = NULL; + } return ((nss_status_t)NSS_SUCCESS); } @@ -353,11 +427,47 @@ next_entry: (void) _nss_ldap_endent(be, a); return (retcode); } else { - if ((parsestat = be->ldapobj2ent(be, argp)) + /* ns_ldap_entry_t -> file format */ + if ((parsestat = be->ldapobj2str(be, argp)) == NSS_STR_PARSE_SUCCESS) { - be->result = NULL; - argp->returnval = argp->buf.result; - return ((nss_status_t)NSS_SUCCESS); + if (argp->buf.result != NULL) { + /* file format -> struct */ + if (argp->str2ent == NULL) { + parsestat = NSS_STR_PARSE_PARSE; + goto error_out; + } + parsestat = (*argp->str2ent)(be->buffer, + be->buflen, + argp->buf.result, + argp->buf.buffer, + argp->buf.buflen); + if (parsestat == NSS_STR_PARSE_SUCCESS) { + if (be->buffer != NULL) { + free(be->buffer); + be->buffer = NULL; + be->buflen = 0; + } + be->result = NULL; + argp->returnval = argp->buf.result; + argp->returnlen = 1; /* irrevelant */ + return ((nss_status_t)NSS_SUCCESS); + } + } else { + /* + * nscd is not caching the enumerated + * entries. This code path would be dormant. + * Keep this path for the future references. + */ + argp->returnval = argp->buf.buffer; + argp->returnlen = + strlen(argp->buf.buffer) + 1; + } + } +error_out: + if (be->buffer != NULL) { + free(be->buffer); + be->buffer = NULL; + be->buflen = 0; } be->result = NULL; if (parsestat == NSS_STR_PARSE_PARSE) { @@ -394,7 +504,7 @@ next_entry: nss_backend_t * _nss_ldap_constr(ldap_backend_op_t ops[], int nops, char *tablename, - const char **attrs, fnf ldapobj2ent) + const char **attrs, fnf ldapobj2str) { ldap_backend_ptr be; @@ -402,20 +512,13 @@ _nss_ldap_constr(ldap_backend_op_t ops[], int nops, char *tablename, (void) fprintf(stdout, "\n[ldap_common.c: _nss_ldap_constr]\n"); #endif /* DEBUG */ - if ((be = (ldap_backend_ptr) malloc(sizeof (*be))) == 0) + if ((be = (ldap_backend_ptr) calloc(1, sizeof (*be))) == 0) return (0); be->ops = ops; be->nops = (nss_dbop_t)nops; be->tablename = (char *)strdup(tablename); be->attrs = attrs; - be->result = NULL; - be->ldapobj2ent = ldapobj2ent; - be->setcalled = 0; - be->filter = NULL; - be->enumcookie = NULL; - be->netgroup_cookie = NULL; - be->services_cookie = NULL; - be->toglue = NULL; + be->ldapobj2str = ldapobj2str; return ((nss_backend_t *)be); } @@ -436,8 +539,8 @@ chophostdomain(char *string, char *host, char *domain) return (0); } *dot = '\0'; - strcpy(host, string); - strcpy(domain, ++dot); + (void) strcpy(host, string); + (void) strcpy(domain, ++dot); return (0); } diff --git a/usr/src/lib/nsswitch/ldap/common/ldap_common.h b/usr/src/lib/nsswitch/ldap/common/ldap_common.h index 23d5e2b1ae..deb5ffd642 100644 --- a/usr/src/lib/nsswitch/ldap/common/ldap_common.h +++ b/usr/src/lib/nsswitch/ldap/common/ldap_common.h @@ -76,6 +76,19 @@ extern "C" { ((string != NULL) && (strchr(string, '.') != NULL)) #define SEARCHFILTERLEN 256 +#define _NO_VALUE "" + +#define TEST_AND_ADJUST(len, buffer, buflen, label) \ + /* Use '>=' to ensure there is at least one byte left for '\0' */ \ + if (len >= buflen || len < 0) { \ + nss_result = NSS_STR_PARSE_ERANGE; \ + goto label; \ + } \ + /* Adjust pointer and available buffer length */ \ + buffer += len; \ + buflen -= len; + + /* * Superset the nss_backend_t abstract data type. This ADT has * been extended to include ldap associated data structures. @@ -85,6 +98,12 @@ typedef struct ldap_backend *ldap_backend_ptr; typedef nss_status_t (*ldap_backend_op_t)(ldap_backend_ptr, void *); typedef int (*fnf)(ldap_backend_ptr be, nss_XbyY_args_t *argp); +typedef enum { + NSS_LDAP_DB_NONE = 0, + NSS_LDAP_DB_PUBLICKEY = 1, + NSS_LDAP_DB_ETHERS = 2 +} nss_ldap_db_type_t; + struct ldap_backend { ldap_backend_op_t *ops; nss_dbop_t nops; @@ -94,10 +113,13 @@ struct ldap_backend { int setcalled; const char **attrs; ns_ldap_result_t *result; - fnf ldapobj2ent; + fnf ldapobj2str; void *netgroup_cookie; void *services_cookie; char *toglue; + char *buffer; + int buflen; + nss_ldap_db_type_t db_type; }; extern nss_status_t _nss_ldap_destr(ldap_backend_ptr be, void *a); @@ -105,7 +127,7 @@ extern nss_status_t _nss_ldap_endent(ldap_backend_ptr be, void *a); extern nss_status_t _nss_ldap_setent(ldap_backend_ptr be, void *a); extern nss_status_t _nss_ldap_getent(ldap_backend_ptr be, void *a); nss_backend_t *_nss_ldap_constr(ldap_backend_op_t ops[], int nops, - char *tablename, const char **attrs, fnf ldapobj2ent); + char *tablename, const char **attrs, fnf ldapobj2str); extern nss_status_t _nss_ldap_nocb_lookup(ldap_backend_ptr be, nss_XbyY_args_t *argp, char *database, char *searchfilter, char *domain, @@ -132,7 +154,6 @@ extern int _merge_SSD_filter(const ns_ldap_search_desc_t *desc, char **realfilter, const void *userdata); extern int _ldap_filter_name(char *filter_name, const char *name, int filter_name_size); -extern nss_status_t switch_err(int rc, ns_ldap_error_t *error); extern void _nss_services_cookie_free(void **cookieP); diff --git a/usr/src/lib/nsswitch/ldap/common/tsol_getrhent.c b/usr/src/lib/nsswitch/ldap/common/tsol_getrhent.c index 90a21988a2..77e04f2cfe 100644 --- a/usr/src/lib/nsswitch/ldap/common/tsol_getrhent.c +++ b/usr/src/lib/nsswitch/ldap/common/tsol_getrhent.c @@ -45,82 +45,82 @@ static const char *tnrhdb_attrs[] = { NULL }; +static void +escape_colon(char *in, char *out) { + int i, j; + for (i = 0, j = 0; in[i] != '\0'; i++) { + if (in[i] == ':') { + out[j++] = '\\'; + out[j++] = in[i]; + } else + out[j++] = in[i]; + } + out[j] = '\0'; +} + +/* + * _nss_ldap_tnrhdb2str is the data marshaling method for the tnrhdb + * (tsol_getrhbyaddr()/tsol_getrhent()) backend processes. + * This method is called after a successful ldap search has been performed. + * This method will parse the ldap search values into the file format. + * + * e.g. + * + * 192.168.120.6:public + * fec0\:\:a00\:20ff\:fea0\:21f7:cipso + * + */ static int -_nss_ldap_tnrhdb2ent(ldap_backend_ptr be, nss_XbyY_args_t *argp) +_nss_ldap_tnrhdb2str(ldap_backend_ptr be, nss_XbyY_args_t *argp) { - int i, nss_result; + int nss_result = NSS_STR_PARSE_SUCCESS; int len = 0; - int buflen = 0; char *buffer = NULL; - char *ceiling = NULL; - ns_ldap_attr_t *attrptr; + char **addr, **template, *addr_out; ns_ldap_result_t *result = be->result; - tsol_rhstr_t *rhstrp; + char addr6[INET6_ADDRSTRLEN + 5]; /* 5 '\' for ':' at most */ + + if (result == NULL) + return (NSS_STR_PARSE_PARSE); - buffer = argp->buf.buffer; - buflen = argp->buf.buflen; - if (argp->buf.result == NULL) { - nss_result = NSS_STR_PARSE_ERANGE; - goto result_tnrhdb2ent; + addr = __ns_ldap_getAttr(result->entry, _TNRHDB_ADDR); + if (addr == NULL || addr[0] == NULL || (strlen(addr[0]) < 1)) { + nss_result = NSS_STR_PARSE_PARSE; + goto result_tnrhdb2str; } - rhstrp = (tsol_rhstr_t *)(argp->buf.result); - rhstrp->family = 0; - rhstrp->address = rhstrp->template = NULL; - ceiling = buffer + buflen; - (void) memset(argp->buf.buffer, 0, buflen); - attrptr = getattr(result, 0); - if (attrptr == NULL) { + + /* + * Escape ':' in IPV6. + * The value is stored in LDAP directory without escape charaters. + */ + if (strchr(addr[0], ':') != NULL) { + escape_colon(addr[0], addr6); + addr_out = addr6; + } else + addr_out = addr[0]; + + template = __ns_ldap_getAttr(result->entry, _TNRHDB_TNAME); + if (template == NULL || template[0] == NULL || + (strlen(template[0]) < 1)) { nss_result = NSS_STR_PARSE_PARSE; - goto result_tnrhdb2ent; + goto result_tnrhdb2str; } - for (i = 0; i < result->entry->attr_count; i++) { - attrptr = getattr(result, i); - if (attrptr == NULL) { + /* "addr:template" */ + len = strlen(addr_out) + strlen(template[0]) + 2; + + if (argp->buf.result != NULL) { + if ((be->buffer = calloc(1, len)) == NULL) { nss_result = NSS_STR_PARSE_PARSE; - goto result_tnrhdb2ent; - } - if (strcasecmp(attrptr->attrname, _TNRHDB_ADDR) == 0) { - len = strlen(attrptr->attrvalue[0]); - if (len < 1 || (attrptr->attrvalue[0] == '\0')) { - nss_result = NSS_STR_PARSE_PARSE; - goto result_tnrhdb2ent; - } - rhstrp->address = buffer; - buffer += len + 1; - if (buffer >= ceiling) { - nss_result = (int)NSS_STR_PARSE_ERANGE; - goto result_tnrhdb2ent; - } - (void) strcpy(rhstrp->address, attrptr->attrvalue[0]); - continue; + goto result_tnrhdb2str; } - if (strcasecmp(attrptr->attrname, _TNRHDB_TNAME) == 0) { - len = strlen(attrptr->attrvalue[0]); - if (len < 1 || (attrptr->attrvalue[0] == '\0')) { - nss_result = NSS_STR_PARSE_PARSE; - goto result_tnrhdb2ent; - } - rhstrp->template = buffer; - buffer += len + 1; - if (buffer >= ceiling) { - nss_result = (int)NSS_STR_PARSE_ERANGE; - goto result_tnrhdb2ent; - } - (void) strcpy(rhstrp->template, attrptr->attrvalue[0]); - continue; - } - } - nss_result = NSS_STR_PARSE_SUCCESS; + be->buflen = len - 1; + buffer = be->buffer; + } else + buffer = argp->buf.buffer; -#ifdef DEBUG - (void) printf("\n[tsol_getrhent.c: _nss_ldap_tnrhdb2ent]\n"); - (void) printf(" address: [%s]\n", - rhstrp->address ? rhstrp->address : "NULL"); - (void) printf("template: [%s]\n", - rhstrp->template ? rhstrp->template : "NULL"); -#endif /* DEBUG */ + (void) snprintf(buffer, len, "%s:%s", addr_out, template[0]); -result_tnrhdb2ent: +result_tnrhdb2str: (void) __ns_ldap_freeResult(&be->result); return (nss_result); } @@ -132,23 +132,31 @@ getbyaddr(ldap_backend_ptr be, void *a) char searchfilter[SEARCHFILTERLEN]; char userdata[SEARCHFILTERLEN]; nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a; - struct in_addr addr; - char buf[18]; - extern char *inet_ntoa_r(); -#ifdef DEBUG - (void) fprintf(stdout, "\n[tsol_getrhent.c: getbyaddr]\n"); -#endif /* DEBUG */ - - (void) memcpy(&addr, argp->key.hostaddr.addr, sizeof (addr)); - (void) inet_ntoa_r(addr, buf); + if (argp->key.hostaddr.addr == NULL || + (argp->key.hostaddr.type != AF_INET && + argp->key.hostaddr.type != AF_INET6)) + return (NSS_NOTFOUND); + if (strchr(argp->key.hostaddr.addr, ':') != NULL) { + /* IPV6 */ + if (argp->key.hostaddr.type == AF_INET) + return (NSS_NOTFOUND); + } else { + /* IPV4 */ + if (argp->key.hostaddr.type == AF_INET6) + return (NSS_NOTFOUND); + } + /* + * The IPV6 addresses are saved in the directory without '\'s. + * So don't need to escape colons in IPV6 addresses. + */ if (snprintf(searchfilter, sizeof (searchfilter), _F_GETTNDBBYADDR, - buf) < 0) + argp->key.hostaddr.addr) < 0) return ((nss_status_t)NSS_NOTFOUND); if (snprintf(userdata, sizeof (userdata), _F_GETTNDBBYADDR_SSD, - buf) < 0) + argp->key.hostaddr.addr) < 0) return ((nss_status_t)NSS_NOTFOUND); return (_nss_ldap_lookup(be, argp, _TNRHDB, searchfilter, NULL, @@ -173,11 +181,7 @@ _nss_ldap_tnrhdb_constr(const char *dummy1, const char *dummy4, const char *dummy5) { -#ifdef DEBUG - (void) fprintf(stdout, - "\n[tsol_getrhent.c: _nss_ldap_tnrhdb_constr]\n"); -#endif return ((nss_backend_t *)_nss_ldap_constr(tnrhdb_ops, sizeof (tnrhdb_ops)/sizeof (tnrhdb_ops[0]), _TNRHDB, - tnrhdb_attrs, _nss_ldap_tnrhdb2ent)); + tnrhdb_attrs, _nss_ldap_tnrhdb2str)); } diff --git a/usr/src/lib/nsswitch/ldap/common/tsol_gettpent.c b/usr/src/lib/nsswitch/ldap/common/tsol_gettpent.c index b7f5423f6f..31c84df762 100644 --- a/usr/src/lib/nsswitch/ldap/common/tsol_gettpent.c +++ b/usr/src/lib/nsswitch/ldap/common/tsol_gettpent.c @@ -32,6 +32,7 @@ #define _TNRHTP_NAME "ipTnetTemplateName" #define _TNRHTP_ATTRS "SolarisAttrKeyValue" #define _F_GETTNTPBYNAME "(&(objectClass=ipTnetTemplate)"\ + "(!(objectClass=ipTnetHost))" \ "(ipTnetTemplateName=%s))" #define _F_GETTNTPBYNAME_SSD "(&(%%s)(ipTnetTemplateName=%s))" @@ -41,97 +42,63 @@ static const char *tnrhtp_attrs[] = { NULL }; +/* + * _nss_ldap_tnrhtp2str is the data marshaling method for the tnrhtp + * (tsol_gettpbyaddr()/tsol_gettpent()) backend processes. + * This method is called after a successful ldap search has been performed. + * This method will parse the ldap search values into the file format. + * + * e.g. + * + * admin_low:host_type=unlabeled;def_label=[0x0000000000000000000000000000000000 + * 0000000000000000000000000000000000];min_sl=0x00000000000000000000000000000000 + * 000000000000000000000000000000000000;max_sl=0x7ffffffffffffffffffffffffffffff + * fffffffffffffffffffffffffffffffffffff;doi=0; + */ static int -_nss_ldap_tnrhtp2ent(ldap_backend_ptr be, nss_XbyY_args_t *argp) +_nss_ldap_tnrhtp2str(ldap_backend_ptr be, nss_XbyY_args_t *argp) { - int i, nss_result; + int nss_result = NSS_STR_PARSE_SUCCESS; int len = 0; - int buflen = 0; char *buffer = NULL; - char *ceiling = NULL; - ns_ldap_attr_t *attrptr; + char **attrs, **template; ns_ldap_result_t *result = be->result; - tsol_tpstr_t *tpstrp; - buffer = argp->buf.buffer; - buflen = argp->buf.buflen; - if (argp->buf.result == NULL) { - nss_result = (int)NSS_STR_PARSE_ERANGE; - goto result_tnrhtp2ent; + if (result == NULL) + return (NSS_STR_PARSE_PARSE); + + template = __ns_ldap_getAttr(result->entry, _TNRHTP_NAME); + if (template == NULL || template[0] == NULL || + (strlen(template[0]) < 1)) { + nss_result = NSS_STR_PARSE_PARSE; + goto result_tnrhtp2str; } - tpstrp = (tsol_tpstr_t *)(argp->buf.result); - tpstrp->template = tpstrp->attrs = NULL; - ceiling = buffer + buflen; - (void) memset(argp->buf.buffer, 0, buflen); - attrptr = getattr(result, 0); - if (attrptr == NULL) { + attrs = __ns_ldap_getAttr(result->entry, _TNRHTP_ATTRS); + if (attrs == NULL || attrs[0] == NULL || (strlen(attrs[0]) < 1)) { nss_result = NSS_STR_PARSE_PARSE; - goto result_tnrhtp2ent; + goto result_tnrhtp2str; } - for (i = 0; i < result->entry->attr_count; i++) { - attrptr = getattr(result, i); - if (attrptr == NULL) { - nss_result = (int)NSS_STR_PARSE_PARSE; - goto result_tnrhtp2ent; - } -#ifdef DEBUG - (void) fprintf(stdout, - "\n[tsol_gettpent.c: _nss_ldap_tnrhtp2ent %d]\n", i); - (void) fprintf(stdout, " entry value count %d: %s:%s\n", - attrptr->value_count, - attrptr->attrname ? attrptr->attrname : "NULL", - attrptr->attrvalue[0] ? attrptr->attrvalue[0] : "NULL"); -#endif /* DEBUG */ - if (strcasecmp(attrptr->attrname, _TNRHTP_NAME) == 0) { - len = strlen(attrptr->attrvalue[0]); - if (len < 1 || (attrptr->attrvalue[0] == '\0')) { - nss_result = (int)NSS_STR_PARSE_PARSE; - goto result_tnrhtp2ent; - } - tpstrp->template = buffer; - buffer += len + 1; - if (buffer >= ceiling) { - nss_result = (int)NSS_STR_PARSE_ERANGE; - goto result_tnrhtp2ent; - } - (void) strcpy(tpstrp->template, attrptr->attrvalue[0]); - continue; - } - if (strcasecmp(attrptr->attrname, _TNRHTP_ATTRS) == 0) { - len = strlen(attrptr->attrvalue[0]); - if (len < 1 || (attrptr->attrvalue[0] == '\0')) { - nss_result = (int)NSS_STR_PARSE_PARSE; - goto result_tnrhtp2ent; - } - tpstrp->attrs = buffer; - buffer += len + 1; - if (buffer >= ceiling) { - nss_result = (int)NSS_STR_PARSE_PARSE; - goto result_tnrhtp2ent; - } - (void) strcpy(tpstrp->attrs, attrptr->attrvalue[0]); - continue; + + /* "template:attrs" */ + len = strlen(template[0]) + strlen(attrs[0]) + 2; + + if (argp->buf.result != NULL) { + if ((be->buffer = calloc(1, len)) == NULL) { + nss_result = NSS_STR_PARSE_PARSE; + goto result_tnrhtp2str; } - } - if (tpstrp->attrs == NULL) - nss_result = NSS_STR_PARSE_PARSE; - else - nss_result = NSS_STR_PARSE_SUCCESS; - -#ifdef DEBUG - (void) fprintf(stdout, "\n[tsol_gettpent.c: _nss_ldap_tnrhtp2ent]\n"); - (void) fprintf(stdout, " template: [%s]\n", - tpstrp->template ? tpstrp->template : "NULL"); - (void) fprintf(stdout, " attrs: [%s]\n", - tpstrp->attrs ? tpstrp->attrs : "NULL"); -#endif /* DEBUG */ - -result_tnrhtp2ent: + be->buflen = len - 1; + buffer = be->buffer; + } else + buffer = argp->buf.buffer; + + (void) snprintf(buffer, len, "%s:%s", template[0], attrs[0]); + +result_tnrhtp2str: (void) __ns_ldap_freeResult(&be->result); return (nss_result); } - static nss_status_t getbyname(ldap_backend_ptr be, void *a) { @@ -139,9 +106,8 @@ getbyname(ldap_backend_ptr be, void *a) char userdata[SEARCHFILTERLEN]; nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a; -#ifdef DEBUG - (void) fprintf(stdout, "\n[tsol_gettpent.c: getbyname]\n"); -#endif /* DEBUG */ + if (argp->key.name == NULL) + return (NSS_NOTFOUND); if (snprintf(searchfilter, SEARCHFILTERLEN, _F_GETTNTPBYNAME, argp->key.name) < 0) @@ -164,7 +130,7 @@ static ldap_backend_op_t tnrhtp_ops[] = { getbyname }; - +/* ARGSUSED */ nss_backend_t * _nss_ldap_tnrhtp_constr(const char *dummy1, const char *dummy2, @@ -172,11 +138,7 @@ _nss_ldap_tnrhtp_constr(const char *dummy1, const char *dummy4, const char *dummy5) { -#ifdef DEBUG - (void) fprintf(stdout, - "\n[gettnrhtpattr.c: _nss_ldap_tnrhtp_constr]\n"); -#endif return ((nss_backend_t *)_nss_ldap_constr(tnrhtp_ops, sizeof (tnrhtp_ops)/sizeof (tnrhtp_ops[0]), _TNRHTP, - tnrhtp_attrs, _nss_ldap_tnrhtp2ent)); + tnrhtp_attrs, _nss_ldap_tnrhtp2str)); } diff --git a/usr/src/lib/nsswitch/nis/Makefile.com b/usr/src/lib/nsswitch/nis/Makefile.com index 63bd6a6936..2b0180d0d2 100644 --- a/usr/src/lib/nsswitch/nis/Makefile.com +++ b/usr/src/lib/nsswitch/nis/Makefile.com @@ -2,9 +2,8 @@ # CDDL HEADER START # # The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@ # CDDL HEADER END # # -# Copyright 1993,2001-2003 Sun Microsystems, Inc. All rights reserved. +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # ident "%Z%%M% %I% %E% SMI" @@ -58,5 +57,8 @@ include ../../Makefile.com # install this library in the root filesystem include ../../../Makefile.rootfs +LINTFLAGS += -erroff=E_GLOBAL_COULD_BE_STATIC2 +LINTFLAGS64 += -erroff=E_GLOBAL_COULD_BE_STATIC2 + LDLIBS += -lnsl -lsocket DYNLIB1 = nss_nis.so$(VERS) diff --git a/usr/src/lib/nsswitch/nis/common/ether_addr.c b/usr/src/lib/nsswitch/nis/common/ether_addr.c index 83d65a4bbb..fbd233a7c0 100644 --- a/usr/src/lib/nsswitch/nis/common/ether_addr.c +++ b/usr/src/lib/nsswitch/nis/common/ether_addr.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,10 +19,10 @@ * CDDL HEADER END */ /* - * nis/ether_addr.c -- "nis" backend for nsswitch "ethers" database + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. * - * Copyright (c) 1988-1992 Sun Microsystems Inc - * All Rights Reserved. + * nis/ether_addr.c -- "nis" backend for nsswitch "ethers" database */ #pragma ident "%Z%%M% %I% %E% SMI" @@ -51,7 +50,7 @@ getbyhost(be, a) nis_backend_ptr_t be; void *a; { - nss_XbyY_args_t *argp = (nss_XbyY_args_t *) a; + nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a; return (_nss_nis_lookup(be, argp, 0, "ethers.byname", argp->key.name, 0)); @@ -62,11 +61,11 @@ getbyether(be, a) nis_backend_ptr_t be; void *a; { - nss_XbyY_args_t *argp = (nss_XbyY_args_t *) a; + nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a; char etherstr[18]; - u_char *e = argp->key.ether; + uchar_t *e = argp->key.ether; - sprintf(etherstr, "%x:%x:%x:%x:%x:%x", + (void) snprintf(etherstr, 18, "%x:%x:%x:%x:%x:%x", *e, *(e + 1), *(e + 2), *(e + 3), *(e + 4), *(e + 5)); return (_nss_nis_lookup(be, argp, 0, "ethers.byaddr", etherstr, 0)); } diff --git a/usr/src/lib/nsswitch/nis/common/getauthattr.c b/usr/src/lib/nsswitch/nis/common/getauthattr.c index c4040131f7..a37dcf00cd 100644 --- a/usr/src/lib/nsswitch/nis/common/getauthattr.c +++ b/usr/src/lib/nsswitch/nis/common/getauthattr.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,8 +19,8 @@ * CDDL HEADER END */ /* - * Copyright (c) 1999 by Sun Microsystems, Inc. - * All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. */ #pragma ident "%Z%%M% %I% %E% SMI" @@ -49,6 +48,7 @@ static nis_backend_op_t authattr_ops[] = { getbynam }; +/*ARGSUSED*/ nss_backend_t * _nss_nis_auth_attr_constr(const char *dummy1, const char *dummy2, diff --git a/usr/src/lib/nsswitch/nis/common/getauuser.c b/usr/src/lib/nsswitch/nis/common/getauuser.c index 8abf038c7b..a86ba4112d 100644 --- a/usr/src/lib/nsswitch/nis/common/getauuser.c +++ b/usr/src/lib/nsswitch/nis/common/getauuser.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,8 +19,8 @@ * CDDL HEADER END */ /* - * Copyright (c) 1999 by Sun Microsystems, Inc. - * All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. */ #pragma ident "%Z%%M% %I% %E% SMI" @@ -50,6 +49,7 @@ static nis_backend_op_t auuser_ops[] = { getbynam }; +/*ARGSUSED*/ nss_backend_t * _nss_nis_audit_user_constr(const char *dummy1, const char *dummy2, diff --git a/usr/src/lib/nsswitch/nis/common/getexecattr.c b/usr/src/lib/nsswitch/nis/common/getexecattr.c index bc912602bc..07f8640f0b 100644 --- a/usr/src/lib/nsswitch/nis/common/getexecattr.c +++ b/usr/src/lib/nsswitch/nis/common/getexecattr.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 1999-2002 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -41,7 +40,7 @@ extern void massage_netdb(const char **, int *); extern int _doexeclist(nss_XbyY_args_t *); extern char *_exec_wild_id(char *, const char *); extern void _exec_cleanup(nss_status_t, nss_XbyY_args_t *); - +extern char *_strtok_escape(char *, char *, char **); typedef struct __exec_nis_args { int *yp_status; @@ -88,6 +87,43 @@ check_match(nss_XbyY_args_t *argp, int check_policy) return (1); } +/* + * check_match_strbuf: set up the data needed by check_match() + * and call it to match exec_attr data in strbuf and argp->key.attrp + */ +static int +check_match_strbuf(nss_XbyY_args_t *argp, char *strbuf, int check_policy) +{ + char *last = NULL; + char *sep = KV_TOKEN_DELIMIT; + execstr_t exec; + execstr_t *execp = &exec; + void *sp; + int rc; + + /* + * Remove newline that yp_match puts at the + * end of the entry it retrieves from the map. + */ + if (strbuf[argp->returnlen] == '\n') { + strbuf[argp->returnlen] = '\0'; + } + + execp->name = _strtok_escape(strbuf, sep, &last); + execp->policy = _strtok_escape(NULL, sep, &last); + execp->type = _strtok_escape(NULL, sep, &last); + execp->res1 = _strtok_escape(NULL, sep, &last); + execp->res2 = _strtok_escape(NULL, sep, &last); + execp->id = _strtok_escape(NULL, sep, &last); + + sp = argp->returnval; + argp->returnval = execp; + rc = check_match(argp, check_policy); + argp->returnval = sp; + free(strbuf); + + return (rc); +} static nss_status_t _exec_nis_parse(const char *instr, @@ -98,13 +134,28 @@ _exec_nis_parse(const char *instr, int parse_stat; nss_status_t res; _priv_execattr *_priv_exec = (_priv_execattr *)(argp->key.attrp); + char *strbuf; + int check_matched; + argp->returnval = NULL; + argp->returnlen = 0; parse_stat = (*argp->str2ent)(instr, instr_len, argp->buf.result, argp->buf.buffer, argp->buf.buflen); switch (parse_stat) { case NSS_STR_PARSE_SUCCESS: - argp->returnval = argp->buf.result; - if (check_match(argp, check_policy)) { + argp->returnlen = instr_len; + /* if exec_attr file format requested */ + if (argp->buf.result == NULL) { + argp->returnval = argp->buf.buffer; + if ((strbuf = strdup(instr)) == NULL) + res = NSS_UNAVAIL; + check_matched = check_match_strbuf(argp, + strbuf, check_policy); + } else { + argp->returnval = argp->buf.result; + check_matched = check_match(argp, check_policy); + } + if (check_matched) { res = NSS_SUCCESS; if (_priv_exec->search_flag == GET_ALL) { if (_doexeclist(argp) == 0) { @@ -133,6 +184,7 @@ _exec_nis_parse(const char *instr, * flow of key-value pairs. If it returns a non-zero value, it is not called * again. The functional value of yp_all is then 0. */ +/*ARGSUSED*/ static int _exec_nis_cb(int instatus, char *inkey, @@ -144,7 +196,6 @@ _exec_nis_cb(int instatus, int check_policy = 1; /* always check policy for yp_all */ int stop_cb; const char *filter; - char *key = NULL; nss_status_t res; _exec_nis_args *eargp = (_exec_nis_args *)indata; nss_XbyY_args_t *argp = eargp->argp; @@ -206,7 +257,6 @@ _exec_nis_lookup(nis_backend_ptr_t be, nss_XbyY_args_t *argp, int getby_flag) if (getby_flag == NSS_DBOP_EXECATTR_BYNAMEID) { int check_policy = 0; int vallen; - int parse_stat; char *val; char key[MAX_INPUT]; @@ -330,6 +380,7 @@ getbyid(nis_backend_ptr_t be, void *a) { nss_status_t res; nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a; + /*LINTED*/ _priv_execattr *_priv_exec = (_priv_execattr *)(argp->key.attrp); res = _exec_nis_lookup(be, argp, NSS_DBOP_EXECATTR_BYID); @@ -348,6 +399,7 @@ getbynameid(nis_backend_ptr_t be, void *a) { nss_status_t res; nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a; + /*LINTED*/ _priv_execattr *_priv_exec = (_priv_execattr *)(argp->key.attrp); res = _exec_nis_lookup(be, argp, NSS_DBOP_EXECATTR_BYNAMEID); @@ -371,6 +423,7 @@ static nis_backend_op_t execattr_ops[] = { getbynameid }; +/*ARGSUSED*/ nss_backend_t * _nss_nis_exec_attr_constr(const char *dummy1, const char *dummy2, diff --git a/usr/src/lib/nsswitch/nis/common/getgrent.c b/usr/src/lib/nsswitch/nis/common/getgrent.c index c1f529e70b..f6447a9d4c 100644 --- a/usr/src/lib/nsswitch/nis/common/getgrent.c +++ b/usr/src/lib/nsswitch/nis/common/getgrent.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -59,7 +58,7 @@ getbygid(be, a) nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a; char gidstr[12]; /* More than enough */ - sprintf(gidstr, "%d", argp->key.gid); + (void) snprintf(gidstr, 12, "%d", argp->key.gid); return (_nss_nis_lookup(be, argp, 0, "group.bygid", gidstr, 0)); } @@ -154,7 +153,6 @@ parse_netid(const char *buf, gid_t gid_array[], int maxgids, int *numgids_ptr) { int numgids = *numgids_ptr; char *buf_next; - int buflen = strlen(buf); gid_t gid; long value; @@ -207,7 +205,6 @@ netid_lookup(struct nss_groupsbymem *argp) nss_status_t res; char *val; int vallen; - char *comment; int parse_res; char *lasts; @@ -232,7 +229,7 @@ netid_lookup(struct nss_groupsbymem *argp) return (res); } - strtok_r(val, "#", &lasts); + (void) strtok_r(val, "#", &lasts); parse_res = parse_netid(val, argp->gid_array, argp->maxgids, &argp->numgids); diff --git a/usr/src/lib/nsswitch/nis/common/gethostent.c b/usr/src/lib/nsswitch/nis/common/gethostent.c index 8636e5ef93..dd3f310336 100644 --- a/usr/src/lib/nsswitch/nis/common/gethostent.c +++ b/usr/src/lib/nsswitch/nis/common/gethostent.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,8 +19,8 @@ * CDDL HEADER END */ /* - * Copyright (c) 1988-1992 Sun Microsystems Inc - * All Rights Reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. * * nis/gethostent.c -- "nis" backend for nsswitch "hosts" database */ @@ -43,7 +42,7 @@ getbyname(be, a) nis_backend_ptr_t be; void *a; { - nss_XbyY_args_t *argp = (nss_XbyY_args_t *) a; + nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a; nss_status_t res; const char *s; @@ -82,7 +81,7 @@ getbyaddr(be, a) nis_backend_ptr_t be; void *a; { - nss_XbyY_args_t *argp = (nss_XbyY_args_t *) a; + nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a; struct in_addr addr; char buf[18]; nss_status_t res; @@ -95,7 +94,7 @@ getbyaddr(be, a) argp->key.hostaddr.len != sizeof (addr)) { return (NSS_NOTFOUND); } - memcpy(&addr, argp->key.hostaddr.addr, sizeof (addr)); + (void) memcpy(&addr, argp->key.hostaddr.addr, sizeof (addr)); res = _nss_nis_lookup(be, argp, 1, "hosts.byaddr", inet_ntoa_r(addr, buf), 0); if (res != NSS_SUCCESS) diff --git a/usr/src/lib/nsswitch/nis/common/gethostent6.c b/usr/src/lib/nsswitch/nis/common/gethostent6.c index 4f1da89d04..48fb1f6377 100644 --- a/usr/src/lib/nsswitch/nis/common/gethostent6.c +++ b/usr/src/lib/nsswitch/nis/common/gethostent6.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 1988-1992, 2003 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * * nis/gethostent.c -- "nis" backend for nsswitch "ipnodes" database @@ -94,7 +93,7 @@ getbyaddr(be, a) argp->key.hostaddr.len != sizeof (addr)) { return (NSS_NOTFOUND); } - memcpy(&addr, argp->key.hostaddr.addr, sizeof (addr)); + (void) memcpy(&addr, argp->key.hostaddr.addr, sizeof (addr)); if (IN6_IS_ADDR_V4MAPPED(&addr)) { if (inet_ntop(AF_INET, (void *) &addr.s6_addr[12], (void *)buf, INET_ADDRSTRLEN) == NULL) { diff --git a/usr/src/lib/nsswitch/nis/common/getnetgrent.c b/usr/src/lib/nsswitch/nis/common/getnetgrent.c index 4863f8fdff..92a631421f 100644 --- a/usr/src/lib/nsswitch/nis/common/getnetgrent.c +++ b/usr/src/lib/nsswitch/nis/common/getnetgrent.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -100,7 +99,7 @@ getnetgr_get(be, a) struct nis_getnetgr_be *be; void *a; { - struct nss_getnetgrent_args *args = (struct nss_getnetgrent_args *) a; + struct nss_getnetgrent_args *args = (struct nss_getnetgrent_args *)a; struct grouplist *mem; if ((mem = be->next_member) == 0) { @@ -120,7 +119,7 @@ getnetgr_get(be, a) args->retp[i] = 0; } else if ((len = strlen(str) + 1) <= buflen) { args->retp[i] = buffer; - memcpy(buffer, str, len); + (void) memcpy(buffer, str, len); buffer += len; buflen -= len; } else { @@ -170,7 +169,7 @@ getnetgr_destr(be, dummy) void *dummy; { if (be != 0) { - getnetgr_end(be, (void *)0); + (void) getnetgr_end(be, (void *)0); free(be); } return (NSS_SUCCESS); @@ -248,7 +247,7 @@ static void ngt_init(ngt) struct netgrtab *ngt; { - memset((void *)ngt, 0, sizeof (*ngt)); + (void) memset((void *)ngt, 0, sizeof (*ngt)); ngt->expand_lastp = &ngt->expand_first; } @@ -285,7 +284,7 @@ ngt_insert(ngt, name, namelen) if (cur == 0) { return; /* Out of memory, too bad */ } - memcpy(cur->name, name, namelen); + (void) memcpy(cur->name, name, namelen); cur->name[namelen] = 0; /* Insert in hash table */ @@ -349,7 +348,7 @@ top_down(struct nis_netgr_be *be, const char **groups, int ngroups, int done; nss_status_t result; - if ((ngt = (struct netgrtab *) malloc(sizeof (*ngt))) == 0) { + if ((ngt = (struct netgrtab *)malloc(sizeof (*ngt))) == 0) { return (NSS_UNAVAIL); } ngt_init(ngt); @@ -373,7 +372,9 @@ top_down(struct nis_netgr_be *be, const char **groups, int ngroups, result = _nss_nis_ypmatch(be->domain, "netgroup", group, &val, &vallen, &yperr); if (result != NSS_SUCCESS) { + /*LINTED E_NOP_IF_STMT*/ if (result == NSS_NOTFOUND) { + ; #ifdef DEBUG syslog(LOG_WARNING, "NIS netgroup lookup: %s doesn't exist", @@ -550,11 +551,11 @@ netgr_set(be, a) struct nis_netgr_be *be; void *a; { - struct nss_setnetgrent_args *args = (struct nss_setnetgrent_args *) a; + struct nss_setnetgrent_args *args = (struct nss_setnetgrent_args *)a; struct nis_getnetgr_be *get_be; nss_status_t res; - get_be = (struct nis_getnetgr_be *) malloc(sizeof (*get_be)); + get_be = (struct nis_getnetgr_be *)malloc(sizeof (*get_be)); if (get_be == 0) { return (NSS_UNAVAIL); } @@ -570,7 +571,7 @@ netgr_set(be, a) get_be->netgroup = strdup(args->netgroup); get_be->next_member = get_be->all_members; - args->iterator = (nss_backend_t *) get_be; + args->iterator = (nss_backend_t *)get_be; } else { args->iterator = 0; free(get_be); @@ -815,7 +816,7 @@ netgr_in(be, a) struct nis_netgr_be *be; void *a; { - struct nss_innetgr_args *ia = (struct nss_innetgr_args *) a; + struct nss_innetgr_args *ia = (struct nss_innetgr_args *)a; nss_status_t res; ia->status = NSS_NETGR_NO; @@ -852,7 +853,7 @@ netgr_in(be, a) */ /*ARGSUSED*/ -nss_status_t +static nss_status_t netgr_destr(be, dummy) struct nis_netgr_be *be; void *dummy; @@ -882,12 +883,12 @@ _nss_nis_netgroup_constr(dummy1, dummy2, dummy3) struct nis_netgr_be *be; if ((domain = _nss_nis_domain()) == 0 || - (be = (struct nis_netgr_be *) malloc(sizeof (*be))) == 0) { + (be = (struct nis_netgr_be *)malloc(sizeof (*be))) == 0) { return (0); } be->ops = netgroup_ops; be->n_ops = sizeof (netgroup_ops) / sizeof (netgroup_ops[0]); be->domain = domain; - return ((nss_backend_t *) be); + return ((nss_backend_t *)be); } diff --git a/usr/src/lib/nsswitch/nis/common/getprinter.c b/usr/src/lib/nsswitch/nis/common/getprinter.c index 0ccb484541..2983a00078 100644 --- a/usr/src/lib/nsswitch/nis/common/getprinter.c +++ b/usr/src/lib/nsswitch/nis/common/getprinter.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -37,7 +36,6 @@ getbyname(be, a) void *a; { nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a; - nss_status_t res; return (_nss_nis_lookup(be, argp, 0, "printers.conf.byname", argp->key.name, 0)); @@ -51,6 +49,7 @@ static nis_backend_op_t printers_ops[] = { getbyname }; +/*ARGSUSED*/ nss_backend_t * _nss_nis_printers_constr(dummy1, dummy2, dummy3) const char *dummy1, *dummy2, *dummy3; diff --git a/usr/src/lib/nsswitch/nis/common/getprofattr.c b/usr/src/lib/nsswitch/nis/common/getprofattr.c index 9813f70054..cdf4793e4c 100644 --- a/usr/src/lib/nsswitch/nis/common/getprofattr.c +++ b/usr/src/lib/nsswitch/nis/common/getprofattr.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,8 +19,8 @@ * CDDL HEADER END */ /* - * Copyright (c) 1999 by Sun Microsystems, Inc. - * All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. */ #pragma ident "%Z%%M% %I% %E% SMI" @@ -49,6 +48,7 @@ static nis_backend_op_t profattr_ops[] = { getbynam }; +/*ARGSUSED*/ nss_backend_t * _nss_nis_prof_attr_constr(const char *dummy1, const char *dummy2, diff --git a/usr/src/lib/nsswitch/nis/common/getprojent.c b/usr/src/lib/nsswitch/nis/common/getprojent.c index 10b43d243f..c388f65749 100644 --- a/usr/src/lib/nsswitch/nis/common/getprojent.c +++ b/usr/src/lib/nsswitch/nis/common/getprojent.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,8 +19,8 @@ * CDDL HEADER END */ /* - * Copyright (c) 1999-2000 by Sun Microsystems, Inc. - * All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. */ #pragma ident "%Z%%M% %I% %E% SMI" @@ -42,7 +41,7 @@ static nss_status_t getbyid(nis_backend_ptr_t be, void *a) { char projstr[PROJNAME_MAX]; nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a; - (void) sprintf(projstr, "%d", argp->key.projid); + (void) snprintf(projstr, PROJNAME_MAX, "%ld", argp->key.projid); return (_nss_nis_lookup(be, argp, 0, "project.byprojid", projstr, 0)); } diff --git a/usr/src/lib/nsswitch/nis/common/getpwnam.c b/usr/src/lib/nsswitch/nis/common/getpwnam.c index d623ebcbbd..a23ee8af5c 100644 --- a/usr/src/lib/nsswitch/nis/common/getpwnam.c +++ b/usr/src/lib/nsswitch/nis/common/getpwnam.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,8 +19,8 @@ * CDDL HEADER END */ /* - * Copyright (c) 1988-1992 Sun Microsystems Inc - * All Rights Reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. * * nis/getpwnam.c -- "nis" backend for nsswitch "passwd" database */ @@ -36,7 +35,7 @@ getbyname(be, a) nis_backend_ptr_t be; void *a; { - nss_XbyY_args_t *argp = (nss_XbyY_args_t *) a; + nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a; return (_nss_nis_lookup(be, argp, 0, "passwd.byname", argp->key.name, 0)); @@ -47,10 +46,10 @@ getbyuid(be, a) nis_backend_ptr_t be; void *a; { - nss_XbyY_args_t *argp = (nss_XbyY_args_t *) a; + nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a; char uidstr[12]; /* More than enough */ - sprintf(uidstr, "%d", argp->key.uid); + (void) snprintf(uidstr, 12, "%ld", argp->key.uid); return (_nss_nis_lookup(be, argp, 0, "passwd.byuid", uidstr, 0)); } diff --git a/usr/src/lib/nsswitch/nis/common/getrpcent.c b/usr/src/lib/nsswitch/nis/common/getrpcent.c index 88794e19a6..a2ead8d1e9 100644 --- a/usr/src/lib/nsswitch/nis/common/getrpcent.c +++ b/usr/src/lib/nsswitch/nis/common/getrpcent.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,8 +19,8 @@ * CDDL HEADER END */ /* - * Copyright (c) 1988-1992 Sun Microsystems Inc - * All Rights Reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. * * nis/getrpcent.c -- "nis" backend for nsswitch "rpc" database */ @@ -41,19 +40,29 @@ static int check_name(args) nss_XbyY_args_t *args; { - struct rpcent *rpc = (struct rpcent *) args->returnval; + struct rpcent *rpc = (struct rpcent *)args->returnval; const char *name = args->key.name; char **aliasp; - if (strcmp(rpc->r_name, name) == 0) { - return (1); - } - for (aliasp = rpc->r_aliases; *aliasp != 0; aliasp++) { - if (strcmp(*aliasp, name) == 0) { + if (rpc) { + if (strcmp(rpc->r_name, name) == 0) { return (1); } + for (aliasp = rpc->r_aliases; *aliasp != 0; aliasp++) { + if (strcmp(*aliasp, name) == 0) { + return (1); + } + } + return (0); + } else { + /* + * NSS2: nscd is running. + */ + return (_nss_nis_check_name_aliases(args, + (const char *)args->buf.buffer, + strlen(args->buf.buffer))); + } - return (0); } static mutex_t no_byname_lock = DEFAULTMUTEX; @@ -64,30 +73,31 @@ getbyname(be, a) nis_backend_ptr_t be; void *a; { - nss_XbyY_args_t *argp = (nss_XbyY_args_t *) a; + nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a; int no_map; sigset_t oldmask, newmask; - sigfillset(&newmask); + (void) sigfillset(&newmask); (void) _thr_sigsetmask(SIG_SETMASK, &newmask, &oldmask); (void) _mutex_lock(&no_byname_lock); no_map = no_byname_map; (void) _mutex_unlock(&no_byname_lock); - (void) _thr_sigsetmask(SIG_SETMASK, &oldmask, (sigset_t*)NULL); + (void) _thr_sigsetmask(SIG_SETMASK, &oldmask, (sigset_t *)NULL); if (no_map == 0) { int yp_status; nss_status_t res; res = _nss_nis_lookup(be, argp, 1, "rpc.byname", - argp->key.name, &yp_status); + argp->key.name, &yp_status); if (yp_status == YPERR_MAP) { - sigfillset(&newmask); + (void) sigfillset(&newmask); _thr_sigsetmask(SIG_SETMASK, &newmask, &oldmask); _mutex_lock(&no_byname_lock); no_byname_map = 1; _mutex_unlock(&no_byname_lock); - _thr_sigsetmask(SIG_SETMASK, &oldmask, (sigset_t*)NULL); + _thr_sigsetmask(SIG_SETMASK, &oldmask, + (sigset_t *)NULL); } else /* if (res == NSS_SUCCESS) <==== */ { return (res); } @@ -101,10 +111,10 @@ getbynumber(be, a) nis_backend_ptr_t be; void *a; { - nss_XbyY_args_t *argp = (nss_XbyY_args_t *) a; + nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a; char numstr[12]; - sprintf(numstr, "%d", argp->key.number); + (void) sprintf(numstr, "%d", argp->key.number); return (_nss_nis_lookup(be, argp, 1, "rpc.bynumber", numstr, 0)); } diff --git a/usr/src/lib/nsswitch/nis/common/getservent.c b/usr/src/lib/nsswitch/nis/common/getservent.c index 373ca89391..13b0ea17ea 100644 --- a/usr/src/lib/nsswitch/nis/common/getservent.c +++ b/usr/src/lib/nsswitch/nis/common/getservent.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,8 +19,8 @@ * CDDL HEADER END */ /* - * Copyright (c) 1988-1992 Sun Microsystems Inc - * All Rights Reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. * * nis/getservent.c -- "nis" backend for nsswitch "services" database */ @@ -30,11 +29,13 @@ #include "nis_common.h" #include <stdio.h> +#include <stdlib.h> #include <string.h> #include <signal.h> #include <malloc.h> #include <netdb.h> #include <synch.h> +#include <ctype.h> #include <rpcsvc/ypclnt.h> #include <thread.h> #include <sys/types.h> @@ -44,7 +45,7 @@ static int check_name(args) nss_XbyY_args_t *args; { - struct servent *serv = (struct servent *) args->returnval; + struct servent *serv = (struct servent *)args->returnval; const char *name = args->key.serv.serv.name; const char *proto = args->key.serv.proto; char **aliasp; @@ -63,6 +64,84 @@ check_name(args) return (0); } +static int +check_name2(nss_XbyY_args_t *argp) +{ + const char *limit, *linep, *keyp; + int name_match = 0; + + linep = (const char *)argp->buf.buffer; + limit = linep + strlen(argp->buf.buffer); + keyp = argp->key.serv.serv.name; + + /* compare name */ + while (*keyp && linep < limit && !isspace(*linep) && *keyp == *linep) { + keyp++; + linep++; + } + if (*keyp == '\0' && linep < limit && isspace(*linep)) { + if (argp->key.serv.proto == NULL) + return (1); + else + name_match = 1; + } + + /* skip remainder of the name, if any */ + while (linep < limit && !isspace(*linep)) + linep++; + /* skip the delimiting spaces */ + while (linep < limit && isspace(*linep)) + linep++; + /* skip port number */ + while (linep < limit && !isspace(*linep) && *linep != '/') + linep++; + if (linep == limit || *linep != '/') + return (0); + + linep++; + if ((keyp = argp->key.serv.proto) == NULL) { + /* skip protocol */ + while (linep < limit && !isspace(*linep)) + linep++; + } else { + /* compare protocol */ + while (*keyp && linep < limit && !isspace(*linep) && + *keyp == *linep) { + keyp++; + linep++; + } + /* no protocol match */ + if (*keyp || (linep < limit && !isspace(*linep))) + return (0); + /* protocol and name match, return */ + if (name_match) + return (1); + /* protocol match but name yet to be matched, so continue */ + } + + /* compare with the aliases */ + while (linep < limit) { + /* skip the delimiting spaces */ + while (linep < limit && isspace(*linep)) + linep++; + + /* compare with the alias name */ + keyp = argp->key.serv.serv.name; + while (*keyp && linep < limit && !isspace(*linep) && + *keyp == *linep) { + keyp++; + linep++; + } + if (*keyp == '\0' && (linep == limit || isspace(*linep))) + return (1); + + /* skip remainder of the alias name, if any */ + while (linep < limit && !isspace(*linep)) + linep++; + } + return (0); +} + static mutex_t no_byname_lock = DEFAULTMUTEX; static int no_byname_map = 0; @@ -71,13 +150,13 @@ getbyname(be, a) nis_backend_ptr_t be; void *a; { - nss_XbyY_args_t *argp = (nss_XbyY_args_t *) a; + nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a; const char *name = argp->key.serv.serv.name; const char *proto = argp->key.serv.proto; int no_map; sigset_t oldmask, newmask; - sigfillset(&newmask); + (void) sigfillset(&newmask); (void) _thr_sigsetmask(SIG_SETMASK, &newmask, &oldmask); (void) _mutex_lock(&no_byname_lock); no_map = no_byname_map; @@ -92,37 +171,46 @@ getbyname(be, a) res = _nss_nis_lookup(be, argp, 1, "services.byservicename", name, &yp_status); } else { - char *key = malloc(strlen(name) + strlen(proto) + 3); + int len = strlen(name) + strlen(proto) + 3; + char *key = malloc(len); - if (key == 0) { + if (key == NULL) { return (NSS_UNAVAIL); } - sprintf(key, "%s/%s", name, proto); + (void) snprintf(key, len, "%s/%s", name, proto); res = _nss_nis_lookup(be, argp, 1, "services.byservicename", key, &yp_status); free(key); } if (yp_status == YPERR_MAP) { - sigfillset(&newmask); + (void) sigfillset(&newmask); _thr_sigsetmask(SIG_SETMASK, &newmask, &oldmask); _mutex_lock(&no_byname_lock); no_byname_map = 1; _mutex_unlock(&no_byname_lock); - _thr_sigsetmask(SIG_SETMASK, &oldmask, (sigset_t*)NULL); + _thr_sigsetmask(SIG_SETMASK, &oldmask, + (sigset_t *)NULL); } else /* if (res == NSS_SUCCESS) <==== */ { return (res); } } - return (_nss_nis_XY_all(be, argp, 1, name, check_name)); + /* + * use check_anme to compare service name if nss1 or nss2 and + * request is not from nscd; otherwise use check_name2 + */ + if (argp->buf.result != NULL) + return (_nss_nis_XY_all(be, argp, 1, name, check_name)); + else + return (_nss_nis_XY_all(be, argp, 1, name, check_name2)); } static int check_port(args) nss_XbyY_args_t *args; { - struct servent *serv = (struct servent *) args->returnval; + struct servent *serv = (struct servent *)args->returnval; /* * We only resorted to _nss_nis_XY_all because proto == 0, so just... @@ -130,28 +218,87 @@ check_port(args) return (serv->s_port == args->key.serv.serv.port); } +static int +check_port2(nss_XbyY_args_t *argp) +{ + const char *limit, *linep, *keyp, *numstart; + int numlen, s_port; + char numbuf[12], *numend; + + linep = (const char *)argp->buf.buffer; + limit = linep + strlen(argp->buf.buffer); + + /* skip name */ + while (linep < limit && !isspace(*linep)) + linep++; + /* skip the delimiting spaces */ + while (linep < limit && isspace(*linep)) + linep++; + + /* compare port num */ + numstart = linep; + while (linep < limit && !isspace(*linep) && *linep != '/') + linep++; + if (linep == limit || *linep != '/') + return (0); + numlen = linep - numstart; + if (numlen == 0 || numlen >= sizeof (numbuf)) + return (0); + (void) memcpy(numbuf, numstart, numlen); + numbuf[numlen] = '\0'; + s_port = htons((int)strtol(numbuf, &numend, 10)); + if (*numend != '\0') + return (0); + if (s_port == argp->key.serv.serv.port) { + if ((keyp = argp->key.serv.proto) == NULL) + return (1); + } else + return (0); + + /* compare protocol */ + linep++; + while (*keyp && linep < limit && !isspace(*linep) && *keyp == *linep) { + keyp++; + linep++; + } + return (*keyp == '\0' && (linep == limit || isspace(*linep))); +} + + static nss_status_t getbyport(be, a) nis_backend_ptr_t be; void *a; { - nss_XbyY_args_t *argp = (nss_XbyY_args_t *) a; + nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a; int port = ntohs(argp->key.serv.serv.port); const char *proto = argp->key.serv.proto; char *key; nss_status_t res; + int len; if (proto == 0) { char portstr[12]; - sprintf(portstr, "%d", port); - return (_nss_nis_XY_all(be, argp, 1, portstr, check_port)); + (void) snprintf(portstr, 12, "%d", port); + /* + * use check_port to compare service port if nss1 or + * nss2 and request is not from nscd; otherwise use + * check_port2 + */ + if (argp->buf.result != NULL) + return (_nss_nis_XY_all(be, argp, 1, portstr, + check_port)); + else + return (_nss_nis_XY_all(be, argp, 1, portstr, + check_port2)); } - if ((key = malloc(strlen(proto) + 14)) == 0) { + len = strlen(proto) + 14; + if ((key = malloc(len)) == 0) { return (NSS_UNAVAIL); } - sprintf(key, "%d/%s", port, proto); + (void) snprintf(key, len, "%d/%s", port, proto); res = _nss_nis_lookup(be, argp, 1, "services.byname", key, 0); diff --git a/usr/src/lib/nsswitch/nis/common/getspent.c b/usr/src/lib/nsswitch/nis/common/getspent.c index 060083f0b9..55aff0b42f 100644 --- a/usr/src/lib/nsswitch/nis/common/getspent.c +++ b/usr/src/lib/nsswitch/nis/common/getspent.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -19,9 +18,10 @@ * * CDDL HEADER END */ + /* - * Copyright (c) 1988-1992 Sun Microsystems Inc - * All Rights Reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. * * nis/getspent.c -- "nis" backend for nsswitch "shadow" database */ @@ -54,7 +54,7 @@ nis_str2spent(instr, lenstr, ent, buffer, buflen) int buflen; { struct spwd *spwd = (struct spwd *)ent; - char *p, *q; + char *p, *q, *r; /* * We know that instr != 0 because we're in 'nis', not 'files' @@ -70,19 +70,34 @@ nis_str2spent(instr, lenstr, ent, buffer, buflen) if (q + 1 - instr > buflen) { return (NSS_STR_PARSE_ERANGE); } - memcpy(buffer, instr, q - instr); - buffer[p - instr] = '\0'; - buffer[q - instr] = '\0'; - - spwd->sp_namp = buffer; - spwd->sp_pwdp = buffer + (p + 1 - instr); - spwd->sp_lstchg = -1; - spwd->sp_min = -1; - spwd->sp_max = -1; - spwd->sp_warn = -1; - spwd->sp_inact = -1; - spwd->sp_expire = -1; - spwd->sp_flag = 0; + /* + * "name:password" is copied + */ + (void) memcpy(buffer, instr, q - instr); + if (spwd) { + buffer[p - instr] = '\0'; + buffer[q - instr] = '\0'; + + spwd->sp_namp = buffer; + spwd->sp_pwdp = buffer + (p + 1 - instr); + spwd->sp_lstchg = -1; + spwd->sp_min = -1; + spwd->sp_max = -1; + spwd->sp_warn = -1; + spwd->sp_inact = -1; + spwd->sp_expire = -1; + spwd->sp_flag = 0; + } else { + /* + * NSS2: nscd is running. Return files format. + * + * name:password::::::: + */ + r = buffer + (q - instr); + *r = '\0'; + if (strlcat(buffer, ":::::::", buflen) >= buflen) + return (NSS_STR_PARSE_ERANGE); + } return (NSS_STR_PARSE_SUCCESS); } @@ -93,10 +108,11 @@ getbyname(be, a) nis_backend_ptr_t be; void *a; { - nss_XbyY_args_t *argp = (nss_XbyY_args_t *) a; + nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a; cstr2ent_t save_c2e; nss_status_t res; struct spwd *spwd; + char *p; save_c2e = argp->str2ent; argp->str2ent = nis_str2spent; @@ -110,12 +126,32 @@ getbyname(be, a) * succeed if the caller's uid is 0 because only root user * can use privilege port. */ - if ((res == NSS_SUCCESS) && (spwd->sp_pwdp) && - (*(spwd->sp_pwdp) == '#') && (*(spwd->sp_pwdp + 1) == '#')) { - /* get password from passwd.adjunct.byname */ - res = _nss_nis_lookup_rsvdport(be, argp, 0, + if (res == NSS_SUCCESS) { + if (spwd) { + if ((spwd->sp_pwdp) && (*(spwd->sp_pwdp) == '#') && + (*(spwd->sp_pwdp + 1) == '#')) { + /* get password from passwd.adjunct.byname */ + res = _nss_nis_lookup_rsvdport(be, argp, 0, "passwd.adjunct.byname", argp->key.name, 0); + } + } else { + /* + * getent request from nscd + */ + if ((p = memchr(argp->buf.buffer, ':', + argp->buf.buflen)) == NULL) + return (NSS_STR_PARSE_PARSE); + if (strncmp(p + 1, "##", 2) == 0) + /* get password from passwd.adjunct.byname */ + res = _nss_nis_lookup_rsvdport(be, argp, 0, + "passwd.adjunct.byname", + argp->key.name, 0); + if (res == NSS_SUCCESS) { + argp->returnval = argp->buf.buffer; + argp->returnlen = strlen(argp->buf.buffer); + } + } } argp->str2ent = save_c2e; @@ -131,10 +167,11 @@ getent(be, a) nis_backend_ptr_t be; void *a; { - nss_XbyY_args_t *argp = (nss_XbyY_args_t *) a; + nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a; cstr2ent_t save_c2e; nss_status_t res; struct spwd *spwd; + char *p; save_c2e = argp->str2ent; argp->str2ent = nis_str2spent; @@ -148,13 +185,36 @@ getent(be, a) * succeed if the caller's uid is 0 because only root user * can use privilege port. */ - if ((res == NSS_SUCCESS) && (spwd->sp_pwdp) && - (*(spwd->sp_pwdp) == '#') && (*(spwd->sp_pwdp + 1) == '#')) { - /* get password from passwd.adjunct.byname */ - res = _nss_nis_lookup_rsvdport(be, argp, 0, + if (res == NSS_SUCCESS) { + if (spwd) { + if ((spwd->sp_pwdp) && (*(spwd->sp_pwdp) == '#') && + (*(spwd->sp_pwdp + 1) == '#')) { + /* get password from passwd.adjunct.byname */ + res = _nss_nis_lookup_rsvdport(be, argp, 0, "passwd.adjunct.byname", spwd->sp_namp, 0); + } + } else { + /* + * getent request from nscd + */ + if ((p = memchr(argp->buf.buffer, ':', + argp->buf.buflen)) == NULL) + return (NSS_STR_PARSE_PARSE); + if (strncmp(p + 1, "##", 2) == 0) { + /* need the name for the next search */ + *p = '\0'; + /* get password from passwd.adjunct.byname */ + res = _nss_nis_lookup_rsvdport(be, argp, 0, + "passwd.adjunct.byname", p, 0); + } + if (res == NSS_SUCCESS) { + argp->returnval = argp->buf.buffer; + argp->returnlen = strlen(argp->buf.buffer); + } + } } + argp->str2ent = save_c2e; return (res); } @@ -173,6 +233,7 @@ static nis_backend_op_t shadow_ops[] = { getbyname }; +/*ARGSUSED*/ nss_backend_t * _nss_nis_shadow_constr(dummy1, dummy2, dummy3) const char *dummy1, *dummy2, *dummy3; diff --git a/usr/src/lib/nsswitch/nis/common/getuserattr.c b/usr/src/lib/nsswitch/nis/common/getuserattr.c index c3550c51ba..48e961550b 100644 --- a/usr/src/lib/nsswitch/nis/common/getuserattr.c +++ b/usr/src/lib/nsswitch/nis/common/getuserattr.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,8 +19,8 @@ * CDDL HEADER END */ /* - * Copyright (c) 1999 by Sun Microsystems, Inc. - * All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. */ #pragma ident "%Z%%M% %I% %E% SMI" @@ -49,6 +48,7 @@ static nis_backend_op_t userattr_ops[] = { getbynam }; +/*ARGSUSED*/ nss_backend_t * _nss_nis_user_attr_constr(const char *dummy1, const char *dummy2, diff --git a/usr/src/lib/nsswitch/nis/common/nis_common.c b/usr/src/lib/nsswitch/nis/common/nis_common.c index e7e90db51f..e90d82eb13 100644 --- a/usr/src/lib/nsswitch/nis/common/nis_common.c +++ b/usr/src/lib/nsswitch/nis/common/nis_common.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 1998-2002 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -71,10 +70,12 @@ switch_err(ypstatus, ismatch) { switch (ypstatus) { case 0: + errno = 0; return (NSS_SUCCESS); case YPERR_BADARGS: case YPERR_KEY: + errno = 0; return (NSS_NOTFOUND); /* @@ -161,7 +162,7 @@ _nss_nis_ypmatch(domain, map, key, valp, vallenp, ypstatusp) #if MT_UNSAFE_YP sigset_t oldmask, newmask; - sigfillset(&newmask); + (void) sigfillset(&newmask); _thr_sigsetmask(SIG_SETMASK, &newmask, &oldmask); _mutex_lock(&one_lane); #endif @@ -182,7 +183,8 @@ _nss_nis_ypmatch(domain, map, key, valp, vallenp, ypstatusp) * XXX special version of _nss_nis_ypmatch() for handling C2 (passwd.adjunct) * lookups when we need a reserved port. */ -nss_status_t + +static nss_status_t _nss_nis_ypmatch_rsvdport(domain, map, key, valp, vallenp, ypstatusp) const char *domain; const char *map; @@ -192,12 +194,11 @@ _nss_nis_ypmatch_rsvdport(domain, map, key, valp, vallenp, ypstatusp) int *ypstatusp; { int ypstatus; - extern int yp_match_rsvdport(); #if MT_UNSAFE_YP sigset_t oldmask, newmask; - sigfillset(&newmask); + (void) sigfillset(&newmask); _thr_sigsetmask(SIG_SETMASK, &newmask, &oldmask); _mutex_lock(&one_lane); #endif @@ -240,10 +241,13 @@ _nss_nis_lookup(be, args, netdb, map, key, ypstatusp) massage_netdb((const char **)&val, &vallen); } + args->returnval = NULL; + args->returnlen = 0; parsestat = (*args->str2ent)(val, vallen, args->buf.result, args->buf.buffer, args->buf.buflen); if (parsestat == NSS_STR_PARSE_SUCCESS) { args->returnval = args->buf.result; + args->returnlen = vallen; res = NSS_SUCCESS; } else if (parsestat == NSS_STR_PARSE_ERANGE) { args->erange = 1; @@ -282,10 +286,13 @@ _nss_nis_lookup_rsvdport(be, args, netdb, map, key, ypstatusp) massage_netdb((const char **)&val, &vallen); } + args->returnval = NULL; + args->returnlen = 0; parsestat = (*args->str2ent)(val, vallen, args->buf.result, args->buf.buffer, args->buf.buflen); if (parsestat == NSS_STR_PARSE_SUCCESS) { args->returnval = args->buf.result; + args->returnlen = vallen; res = NSS_SUCCESS; } else if (parsestat == NSS_STR_PARSE_ERANGE) { args->erange = 1; @@ -314,7 +321,7 @@ do_getent(be, args, netdb) #if MT_UNSAFE_YP sigset_t oldmask, newmask; - sigfillset(&newmask); + (void) sigfillset(&newmask); _thr_sigsetmask(SIG_SETMASK, &newmask, &oldmask); _mutex_lock(&one_lane); #endif @@ -345,10 +352,13 @@ do_getent(be, args, netdb) massage_netdb((const char **)&outval, &outvallen); } + args->returnval = NULL; + args->returnlen = 0; parsestat = (*args->str2ent)(outval, outvallen, args->buf.result, args->buf.buffer, args->buf.buflen); if (parsestat == NSS_STR_PARSE_SUCCESS) { args->returnval = args->buf.result; + args->returnlen = outvallen; res = NSS_SUCCESS; } else if (parsestat == NSS_STR_PARSE_ERANGE) { args->erange = 1; @@ -450,7 +460,7 @@ _nss_nis_do_all(be, args, filter, func) #if MT_UNSAFE_YP sigset_t oldmask, newmask; - sigfillset(&newmask); + (void) sigfillset(&newmask); _thr_sigsetmask(SIG_SETMASK, &newmask, &oldmask); _mutex_lock(&one_lane); #endif @@ -494,12 +504,15 @@ XbyY_iterator(instr, instr_len, a) massage_netdb(&instr, &instr_len); } + args->returnval = NULL; + args->returnlen = 0; parsestat = (*args->str2ent)(instr, instr_len, args->buf.result, args->buf.buffer, args->buf.buflen); if (parsestat == NSS_STR_PARSE_SUCCESS) { args->returnval = args->buf.result; if ((*xydata->func)(args)) { res = NSS_SUCCESS; + args->returnlen = instr_len; } else { res = NSS_NOTFOUND; args->returnval = 0; @@ -545,7 +558,7 @@ _nss_nis_destr(be, dummy) { if (be != 0) { /* === Should change to invoke ops[ENDENT] ? */ - _nss_nis_endent(be, 0); + (void) _nss_nis_endent(be, 0); free(be); } return (NSS_SUCCESS); /* In case anyone is dumb enough to check */ @@ -565,7 +578,7 @@ _nss_nis_domain() */ sigset_t oldmask, newmask; - sigfillset(&newmask); + (void) sigfillset(&newmask); (void) _thr_sigsetmask(SIG_SETMASK, &newmask, &oldmask); (void) _mutex_lock(&yp_domain_lock); @@ -609,3 +622,57 @@ _nss_nis_constr(ops, n_ops, enum_map) return ((nss_backend_t *)be); } + +/* + * This routine is used to parse lines of the form: + * name number aliases + * It returns 1 if the key in argp matches any one of the + * names in the line, otherwise 0 + * Used by rpc + */ +int +_nss_nis_check_name_aliases(nss_XbyY_args_t *argp, const char *line, + int linelen) +{ + const char *limit, *linep, *keyp; + + linep = line; + limit = line + linelen; + keyp = argp->key.name; + + /* compare name */ + while (*keyp && linep < limit && !isspace(*linep) && *keyp == *linep) { + keyp++; + linep++; + } + if (*keyp == '\0' && linep < limit && isspace(*linep)) + return (1); + /* skip remainder of the name, if any */ + while (linep < limit && !isspace(*linep)) + linep++; + /* skip the delimiting spaces */ + while (linep < limit && isspace(*linep)) + linep++; + /* compare with the aliases */ + while (linep < limit) { + /* + * 1st pass: skip number + * Other passes: skip remainder of the alias name, if any + */ + while (linep < limit && !isspace(*linep)) + linep++; + /* skip the delimiting spaces */ + while (linep < limit && isspace(*linep)) + linep++; + /* compare with the alias name */ + keyp = argp->key.name; + while (*keyp && linep < limit && !isspace(*linep) && + *keyp == *linep) { + keyp++; + linep++; + } + if (*keyp == '\0' && (linep == limit || isspace(*linep))) + return (1); + } + return (0); +} diff --git a/usr/src/lib/nsswitch/nis/common/nis_common.h b/usr/src/lib/nsswitch/nis/common/nis_common.h index 281f80cb91..ad5407700e 100644 --- a/usr/src/lib/nsswitch/nis/common/nis_common.h +++ b/usr/src/lib/nsswitch/nis/common/nis_common.h @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 1998-2002 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -116,6 +115,9 @@ extern int __nss2herrno(nss_status_t nsstat); extern int _thr_sigsetmask(int how, const sigset_t *set, sigset_t *oset); extern int _mutex_lock(mutex_t *mp); extern int _mutex_unlock(mutex_t *mp); +extern int _nss_nis_check_name_aliases(nss_XbyY_args_t *argp, + const char *line, + int linelen); /* private yp "configurable lookup persistence" interface in libnsl */ extern int __yp_match_cflookup(char *, char *, char *, int, char **, diff --git a/usr/src/lib/nsswitch/nisplus/Makefile.com b/usr/src/lib/nsswitch/nisplus/Makefile.com index b060f52c50..c7481d2fe3 100644 --- a/usr/src/lib/nsswitch/nisplus/Makefile.com +++ b/usr/src/lib/nsswitch/nisplus/Makefile.com @@ -2,9 +2,8 @@ # CDDL HEADER START # # The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@ # CDDL HEADER END # # -# Copyright 1993,2001-2003 Sun Microsystems, Inc. All rights reserved. +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # ident "%Z%%M% %I% %E% SMI" @@ -57,5 +56,8 @@ include ../../Makefile.com # install this library in the root filesystem include ../../../Makefile.rootfs +LINTFLAGS += -erroff=E_GLOBAL_COULD_BE_STATIC2 +LINTFLAGS64 += -erroff=E_GLOBAL_COULD_BE_STATIC2 + LDLIBS += -lnsl -lsocket DYNLIB1 = nss_nisplus.so$(VERS) diff --git a/usr/src/lib/nsswitch/nisplus/common/bootparams_getbyname.c b/usr/src/lib/nsswitch/nisplus/common/bootparams_getbyname.c index f43ffc0fc4..5cb2b8c591 100644 --- a/usr/src/lib/nsswitch/nisplus/common/bootparams_getbyname.c +++ b/usr/src/lib/nsswitch/nisplus/common/bootparams_getbyname.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,17 +19,21 @@ * CDDL HEADER END */ /* - * nisplus/bootparams_getbyname.c -- "nisplus" backend for nsswitch - * "bootparams" database. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +/* + * nisplus/bootparams_getbyname.c * - * Copyright (c) 1988-1992 Sun Microsystems Inc - * All Rights Reserved. + * nisplus backend for nsswitch bootparams database. */ #pragma ident "%Z%%M% %I% %E% SMI" #include <nss_dbdefs.h> #include <strings.h> +#include <stdlib.h> #include "nisplus_common.h" #include "nisplus_tables.h" @@ -39,7 +42,7 @@ getbyname(be, a) nisplus_backend_ptr_t be; void *a; { - nss_XbyY_args_t *argp = (nss_XbyY_args_t *) a; + nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a; return (_nss_nisplus_lookup(be, argp, BOOTPARAM_TAG_KEY, argp->key.name)); @@ -47,22 +50,20 @@ getbyname(be, a) /* * place the results from the nis_object structure into argp->buf.buffer - * (hid argp->buf.buflen) that was supplied by the caller. + * that was supplied by the caller. * Returns NSS_STR_PARSE_{SUCCESS, ERANGE, PARSE} */ /*ARGSUSED*/ static int -nis_object2ent(nobj, obj, argp) - int nobj; - nis_object *obj; - nss_XbyY_args_t *argp; +nis_object2str(nobj, obj, be, argp) + int nobj; + nis_object *obj; + nisplus_backend_ptr_t be; + nss_XbyY_args_t *argp; { - char *buffer, *val; - int buflen = argp->buf.buflen; - struct entry_col *ecol; - int len; - - buffer = argp->buf.buffer; + char *buffer, *val; + int buflen, vallen; + struct entry_col *ecol; /* * If we got more than one nis_object, we just ignore it. @@ -79,18 +80,28 @@ nis_object2ent(nobj, obj, argp) } ecol = obj->EN_data.en_cols.en_cols_val; - /* - * datum - */ - EC_SET(ecol, BOOTPARAM_NDX_DATUM, len, val); - if (len < 2) { - *buffer = 0; - return (NSS_STR_PARSE_SUCCESS); - } - if (len > buflen) - return (NSS_STR_PARSE_ERANGE); - strncpy(buffer, val, len); + /* datum */ + __NISPLUS_GETCOL_OR_EMPTY(ecol, BOOTPARAM_NDX_DATUM, vallen, val); + buflen = vallen + 1; + if (argp->buf.result != NULL) { + if ((be->buffer = calloc(1, buflen)) == NULL) + return (NSS_STR_PARSE_PARSE); + /* include trailing null in length */ + be->buflen = buflen; + buffer = be->buffer; + } else { + if (buflen > argp->buf.buflen) + return (NSS_STR_PARSE_ERANGE); + buflen = argp->buf.buflen; + buffer = argp->buf.buffer; + (void) memset(buffer, 0, buflen); + } + (void) snprintf(buffer, buflen, "%s", val); +#ifdef DEBUG + (void) fprintf(stdout, "bootparams [%s]\n", buffer); + (void) fflush(stdout); +#endif /* DEBUG */ return (NSS_STR_PARSE_SUCCESS); } @@ -106,5 +117,5 @@ _nss_nisplus_bootparams_constr(dummy1, dummy2, dummy3) { return (_nss_nisplus_constr(bootparams_ops, sizeof (bootparams_ops) / sizeof (bootparams_ops[0]), - BOOTPARAM_TBLNAME, nis_object2ent)); + BOOTPARAM_TBLNAME, nis_object2str)); } diff --git a/usr/src/lib/nsswitch/nisplus/common/ether_addr.c b/usr/src/lib/nsswitch/nisplus/common/ether_addr.c index 3d0fbb25e1..346188c4b4 100644 --- a/usr/src/lib/nsswitch/nisplus/common/ether_addr.c +++ b/usr/src/lib/nsswitch/nisplus/common/ether_addr.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,12 +19,16 @@ * CDDL HEADER END */ /* - * nisplus/ether_addr.c -- "nisplus" backend for nsswitch "ethers" database - * - * Copyright 1988-1992,2002 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ +/* + * nisplus/ether_addr.c + * + * nisplus backend for nsswitch "ethers" database + */ + #pragma ident "%Z%%M% %I% %E% SMI" /* @@ -36,6 +39,7 @@ * bytes are always in network order. */ +#include <stdlib.h> #include <sys/types.h> #include <sys/socket.h> #include <net/if.h> @@ -67,43 +71,30 @@ getbyether(be, a) char etherstr[18]; uchar_t *e = argp->key.ether; - (void) sprintf(etherstr, "%x:%x:%x:%x:%x:%x", + (void) snprintf(etherstr, 18, "%x:%x:%x:%x:%x:%x", *e, *(e + 1), *(e + 2), *(e + 3), *(e + 4), *(e + 5)); return (_nss_nisplus_lookup(be, argp, ETHER_TAG_ADDR, etherstr)); } /* - * Place the resulting struct ether_addr from the nis_object structure into - * argp->buf.result only if argp->buf.result is initialized (not NULL). - * I.e. it happens for the call ether_hostton. - * - * Place the resulting hostname into argp->buf.buffer only if - * argp->buf.buffer is initialized. I.e. it happens for the call - * ether_ntohost. + * Convert the ethers nisplus object into files format * * Returns NSS_STR_PARSE_{SUCCESS, ERANGE, PARSE} */ /*ARGSUSED*/ static int -nis_object2ent(nobj, obj, argp) - int nobj; - nis_object *obj; - nss_XbyY_args_t *argp; +nis_object2str(nobj, obj, be, argp) + int nobj; + nis_object *obj; + nisplus_backend_ptr_t be; + nss_XbyY_args_t *argp; { - uchar_t *ether = (uchar_t *)argp->buf.result; - char *host = argp->buf.buffer; - char *val; - struct entry_col *ecol; - int len; + char *addr, *name; + int addrlen, namelen; + struct entry_col *ecol; /* - * argp->buf.buflen does not make sense for ethers. It - * is always set to 0 by the frontend. The caller only - * passes a hostname pointer in case of ether_ntohost, - * that is assumed to be big enough. For ether_hostton, - * the struct ether_addr passed is a fixed size. - * * If we got more than one nis_object, we just ignore it. * Although it should never have happened. * @@ -118,46 +109,29 @@ nis_object2ent(nobj, obj, argp) } ecol = obj->EN_data.en_cols.en_cols_val; - /* - * get ether addr - * - * ether_hostton - */ - if (ether) { - int i; - unsigned int t[6]; - - EC_SET(ecol, ETHER_NDX_ADDR, len, val); - if (len < 2) - return (NSS_STR_PARSE_PARSE); - i = sscanf(val, "%x:%x:%x:%x:%x:%x", - &t[0], &t[1], &t[2], &t[3], &t[4], &t[5]); - if (i != ETHERADDRL) - return (NSS_STR_PARSE_PARSE); - for (i = 0; i < ETHERADDRL; i++) - *(ether + i) = (uchar_t)t[i]; + /* addr */ + __NISPLUS_GETCOL_OR_RETURN(ecol, ETHER_NDX_ADDR, addrlen, addr); + + /* name */ + __NISPLUS_GETCOL_OR_RETURN(ecol, ETHER_NDX_NAME, namelen, name); + + /* skip comment */ /* - * get hostname + * can't use argp->buf.result == NULL test to determine if + * the caller is nscd or not. * - * ether_ntohost + * exclude trailing null from length */ - } else if (host) { - EC_SET(ecol, ETHER_NDX_NAME, len, val); - if (len < 2) - return (NSS_STR_PARSE_PARSE); - /* - * The interface does not let the caller specify how long is - * the buffer pointed by host. We make a safe assumption that - * the callers will always give MAXHOSTNAMELEN. In any case, - * it is the only finite number we can lay our hands on in - * case of runaway strings, memory corruption etc. - */ - if (len > MAXHOSTNAMELEN) - return (NSS_STR_PARSE_ERANGE); - strcpy(host, val); - } + be->buflen = addrlen + namelen + 1; + if ((be->buffer = calloc(1, be->buflen + 1)) == NULL) + return (NSS_STR_PARSE_PARSE); + (void) snprintf(be->buffer, be->buflen + 1, "%s %s", addr, name); +#ifdef DEBUG + (void) fprintf(stdout, "ethers [%s]\n", be->buffer); + (void) fflush(stdout); +#endif /* DEBUG */ return (NSS_STR_PARSE_SUCCESS); } @@ -174,5 +148,5 @@ _nss_nisplus_ethers_constr(dummy1, dummy2, dummy3) { return (_nss_nisplus_constr(ethers_ops, sizeof (ethers_ops) / sizeof (ethers_ops[0]), - ETHER_TBLNAME, nis_object2ent)); + ETHER_TBLNAME, nis_object2str)); } diff --git a/usr/src/lib/nsswitch/nisplus/common/getauthattr.c b/usr/src/lib/nsswitch/nisplus/common/getauthattr.c index 5c9d63545a..cb3d76efd7 100644 --- a/usr/src/lib/nsswitch/nisplus/common/getauthattr.c +++ b/usr/src/lib/nsswitch/nisplus/common/getauthattr.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,8 +19,8 @@ * CDDL HEADER END */ /* - * Copyright (c) 1999 by Sun Microsystems, Inc. - * All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. */ #pragma ident "%Z%%M% %I% %E% SMI" @@ -44,23 +43,20 @@ getbynam(nisplus_backend_ptr_t be, void *a) } /* - * place the results from the nis_object structure into argp->buf.result * Returns NSS_STR_PARSE_{SUCCESS, ERANGE, PARSE} */ +/*ARGSUSED*/ static int -nis_object2authstr(int nobj, nis_object *obj, nss_XbyY_args_t *argp) +nis_object2authstr(int nobj, nis_object *obj, + nisplus_backend_ptr_t be, + nss_XbyY_args_t *argp) { - int len; - int buflen = argp->buf.buflen; - char *buffer, *limit, *val, *endnum, *nullstring; - char *empty = ""; - authstr_t *auth; + char *buffer, *name, *res1, *res2; + char *shortdesc, *longdesc, *attr; + int buflen, namelen, res1len, res2len; + int shortdesclen, longdesclen, attrlen; struct entry_col *ecol; - limit = argp->buf.buffer + buflen; - auth = (authstr_t *)argp->buf.result; - buffer = argp->buf.buffer; - /* * If we got more than one nis_object, we just ignore object(s) * except the first. Although it should never have happened. @@ -76,96 +72,48 @@ nis_object2authstr(int nobj, nis_object *obj, nss_XbyY_args_t *argp) } ecol = obj->EN_data.en_cols.en_cols_val; - /* - * authstr->name: authorization name - */ - EC_SET(ecol, AUTHATTR_NDX_NAME, len, val); - if (len < 1 || (*val == '\0')) { - val = empty; - } - auth->name = buffer; - buffer += len; - if (buffer >= limit) { - return (NSS_STR_PARSE_ERANGE); - } - strcpy(auth->name, val); - nullstring = (buffer - 1); - - /* - * authstr->res1: reserved field 1 - */ - EC_SET(ecol, AUTHATTR_NDX_RES1, len, val); - if (len < 1 || (*val == '\0')) { - val = empty; - } - auth->res1 = buffer; - buffer += len; - if (buffer >= limit) { - return (NSS_STR_PARSE_ERANGE); - } - strcpy(auth->res1, val); - nullstring = (buffer - 1); - - /* - * authstr->res2: reserved field 2 - */ - EC_SET(ecol, AUTHATTR_NDX_RES2, len, val); - if (len < 1 || (*val == '\0')) { - val = empty; - } - auth->res2 = buffer; - buffer += len; - if (buffer >= limit) { - return (NSS_STR_PARSE_ERANGE); - } - strcpy(auth->res2, val); - nullstring = (buffer - 1); - - /* - * authstr->short_desc: short description - */ - EC_SET(ecol, AUTHATTR_NDX_SHORTDESC, len, val); - if (len < 1 || (*val == '\0')) { - val = empty; - } - auth->short_desc = buffer; - buffer += len; - if (buffer >= limit) { - return (NSS_STR_PARSE_ERANGE); - } - strcpy(auth->short_desc, val); - nullstring = (buffer - 1); - - /* - * authstr->long_desc: long description - */ - EC_SET(ecol, AUTHATTR_NDX_LONGDESC, len, val); - if (len < 1 || (*val == '\0')) { - val = empty; + /* authorization name */ + __NISPLUS_GETCOL_OR_RETURN(ecol, AUTHATTR_NDX_NAME, namelen, name); + + /* reserved field 1 */ + __NISPLUS_GETCOL_OR_EMPTY(ecol, AUTHATTR_NDX_RES1, res1len, res1); + + /* reserved field 2 */ + __NISPLUS_GETCOL_OR_EMPTY(ecol, AUTHATTR_NDX_RES2, res2len, res2); + + /* short description */ + __NISPLUS_GETCOL_OR_EMPTY(ecol, AUTHATTR_NDX_SHORTDESC, + shortdesclen, shortdesc); + + /* long description */ + __NISPLUS_GETCOL_OR_EMPTY(ecol, AUTHATTR_NDX_LONGDESC, + longdesclen, longdesc); + + /* key-value pairs of attributes */ + __NISPLUS_GETCOL_OR_EMPTY(ecol, AUTHATTR_NDX_ATTR, + attrlen, attr); + + buflen = namelen + res1len + res2len + shortdesclen + + longdesclen + attrlen + 6; + if (argp->buf.result != NULL) { + if ((be->buffer = calloc(1, buflen)) == NULL) + return (NSS_STR_PARSE_PARSE); + /* exclude trailing null from length */ + be->buflen = buflen - 1; + buffer = be->buffer; + } else { + if (buflen > argp->buf.buflen) + return (NSS_STR_PARSE_ERANGE); + buflen = argp->buf.buflen; + buffer = argp->buf.buffer; + (void) memset(buffer, 0, buflen); } - auth->long_desc = buffer; - buffer += len; - if (buffer >= limit) { - return (NSS_STR_PARSE_ERANGE); - } - strcpy(auth->long_desc, val); - nullstring = (buffer - 1); - - /* - * authstr->attrs: key-value pairs of attributes - */ - EC_SET(ecol, AUTHATTR_NDX_ATTR, len, val); - if (len < 1 || (*val == '\0')) { - val = empty; - } - auth->attr = buffer; - buffer += len; - if (buffer >= limit) { - return (NSS_STR_PARSE_ERANGE); - } - strcpy(auth->attr, val); - nullstring = (buffer - 1); - + (void) snprintf(buffer, buflen, "%s:%s:%s:%s:%s:%s", + name, res1, res2, shortdesc, longdesc, attr); +#ifdef DEBUG + (void) fprintf(stdout, "authattr [%s]\n", buffer); + (void) fflush(stdout); +#endif /* DEBUG */ return (NSS_STR_PARSE_SUCCESS); } @@ -177,6 +125,7 @@ static nisplus_backend_op_t authattr_ops[] = { getbynam }; +/*ARGSUSED*/ nss_backend_t * _nss_nisplus_auth_attr_constr(const char *dummy1, const char *dummy2, diff --git a/usr/src/lib/nsswitch/nisplus/common/getauuser.c b/usr/src/lib/nsswitch/nisplus/common/getauuser.c index b7ab478db4..23429494cf 100644 --- a/usr/src/lib/nsswitch/nisplus/common/getauuser.c +++ b/usr/src/lib/nsswitch/nisplus/common/getauuser.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,8 +19,8 @@ * CDDL HEADER END */ /* - * Copyright (c) 1999-2001 by Sun Microsystems, Inc. - * All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. */ #pragma ident "%Z%%M% %I% %E% SMI" @@ -42,7 +41,6 @@ #include <secdb.h> #include "nisplus_tables.h" - static nss_status_t getbynam(nisplus_backend_ptr_t be, void *a) { @@ -53,22 +51,18 @@ getbynam(nisplus_backend_ptr_t be, void *a) } /* - * place the results from the nis_object structure into argp->buf.result * Returns NSS_STR_PARSE_{SUCCESS, ERANGE, PARSE} */ +/*ARGSUSED*/ static int -nis_object2auuser(int nobj, nis_object *obj, nss_XbyY_args_t *argp) +nis_object2auuser(int nobj, nis_object *obj, + nisplus_backend_ptr_t be, + nss_XbyY_args_t *argp) { - int len; - int buflen = argp->buf.buflen; - char *p, *buffer, *limit, *val, *endnum, *nullstring; - char *empty = ""; - au_user_str_t *au_user; + char *buffer, *name, *always, *never; + int buflen, namelen, alwayslen, neverlen; struct entry_col *ecol; - limit = argp->buf.buffer + buflen; - au_user = (au_user_str_t *)argp->buf.result; - buffer = argp->buf.buffer; /* * If we got more than one nis_object, we just ignore object(s) except * the first. Although it should never have happened. @@ -82,51 +76,38 @@ nis_object2auuser(int nobj, nis_object *obj, nss_XbyY_args_t *argp) } ecol = obj->EN_data.en_cols.en_cols_val; - /* - * au_user->name: user name - */ - EC_SET(ecol, AUDITUSER_NDX_NAME, len, val); - if (len < 1 || (*val == '\0')) { - val = empty; - } - au_user->au_name = buffer; - buffer += len; - if (buffer >= limit) { - return (NSS_STR_PARSE_ERANGE); - } - strcpy(au_user->au_name, val); - nullstring = (buffer - 1); + /* user name */ + __NISPLUS_GETCOL_OR_RETURN(ecol, AUDITUSER_NDX_NAME, + namelen, name); - /* - * au_user->au_always: always audited events - */ - EC_SET(ecol, AUDITUSER_NDX_ALWAYS, len, val); - if (len < 1 || (*val == '\0')) { - val = empty; - } - au_user->au_always = buffer; - buffer += len; - if (buffer >= limit) { - return (NSS_STR_PARSE_ERANGE); - } - strcpy(au_user->au_always, val); - nullstring = (buffer - 1); + /* always audited events */ + __NISPLUS_GETCOL_OR_EMPTY(ecol, AUDITUSER_NDX_ALWAYS, + alwayslen, always); - /* - * au_user->au_never: never audited events - */ - EC_SET(ecol, AUDITUSER_NDX_NEVER, len, val); - if (len < 1 || (*val == '\0')) { - val = empty; - } - au_user->au_never = buffer; - buffer += len; - if (buffer >= limit) { - return (NSS_STR_PARSE_ERANGE); - } - strcpy(au_user->au_never, val); - nullstring = (buffer - 1); + /* never audited events */ + __NISPLUS_GETCOL_OR_EMPTY(ecol, AUDITUSER_NDX_NEVER, + neverlen, never); + buflen = namelen + alwayslen + neverlen + 3; + if (argp->buf.result != NULL) { + if ((be->buffer = calloc(1, buflen)) == NULL) + return (NSS_STR_PARSE_PARSE); + /* exclude trailing null from length */ + be->buflen = buflen - 1; + buffer = be->buffer; + } else { + if (buflen > argp->buf.buflen) + return (NSS_STR_PARSE_ERANGE); + buflen = argp->buf.buflen; + buffer = argp->buf.buffer; + (void) memset(buffer, 0, buflen); + } + (void) snprintf(buffer, buflen, "%s:%s:%s", + name, always, never); +#ifdef DEBUG + (void) fprintf(stdout, "audituser [%s]\n", buffer); + (void) fflush(stdout); +#endif /* DEBUG */ return (NSS_STR_PARSE_SUCCESS); } @@ -138,6 +119,7 @@ static nisplus_backend_op_t auuser_ops[] = { getbynam }; +/*ARGSUSED*/ nss_backend_t * _nss_nisplus_audit_user_constr(const char *dummy1, const char *dummy2, diff --git a/usr/src/lib/nsswitch/nisplus/common/getexecattr.c b/usr/src/lib/nsswitch/nisplus/common/getexecattr.c index a0f3fb65cc..8a60c77e75 100644 --- a/usr/src/lib/nsswitch/nisplus/common/getexecattr.c +++ b/usr/src/lib/nsswitch/nisplus/common/getexecattr.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 1999-2002 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -88,8 +87,7 @@ _print_execstr(execstr_t *exec) static nss_status_t _exec_process_val(_exec_nisplus_args * eargp, nis_object * obj) { - int parse_stat; - nss_status_t res; + int parsestat; nss_XbyY_args_t *argp = eargp->argp; nisplus_backend_t *be = eargp->be; _priv_execattr *_priv_exec = (_priv_execattr *)(argp->key.attrp); @@ -98,30 +96,70 @@ _exec_process_val(_exec_nisplus_args * eargp, nis_object * obj) (void) fprintf(stdout, "\n[getexecattr.c: _exec_process_val]\n"); #endif /* DEBUG */ - parse_stat = (be->obj2ent) (1, obj, argp); /* passing one obj */ - switch (parse_stat) { - case NSS_STR_PARSE_SUCCESS: + /* passing one obj */ + parsestat = (be->obj2str) (1, obj, be, argp); + if (parsestat != NSS_STR_PARSE_SUCCESS) + goto fail; + + /* + * If caller is nscd's switch engine, the data + * will be in argp->buf.buffer. nscd does not + * support GET_ALL at this time so return + * success from here. + */ + if (argp->buf.result == NULL && be->buffer == NULL) { + argp->returnval = argp->buf.buffer; + if (argp->buf.buffer != NULL) + argp->returnlen = strlen(argp->buf.buffer); + return (NSS_SUCCESS); + } + + /* + * If the data is in be->buffer it needs + * to be marshalled. + */ + if (argp->str2ent == NULL) { + parsestat = NSS_STR_PARSE_PARSE; + goto fail; + } + parsestat = (*argp->str2ent)(be->buffer, + be->buflen, + argp->buf.result, + argp->buf.buffer, + argp->buf.buflen); + if (parsestat == NSS_STR_PARSE_SUCCESS) { + if (be->buffer != NULL) { + free(be->buffer); + be->buffer = NULL; + be->buflen = 0; + } argp->returnval = argp->buf.result; - res = NSS_SUCCESS; - if (_priv_exec->search_flag == GET_ALL) { - if (_doexeclist(argp) == 0) { - res = NSS_UNAVAIL; - } + if (argp->buf.result != NULL) + argp->returnlen = 1; + else if (argp->buf.buffer != NULL) { + argp->returnval = argp->buf.buffer; + argp->returnlen = strlen(argp->buf.buffer); } - break; - case NSS_STR_PARSE_ERANGE: - argp->erange = 1; - res = NSS_NOTFOUND; /* We won't find this otherwise, anyway */ - break; - case NSS_STR_PARSE_PARSE: - res = NSS_NOTFOUND; - break; - default: - res = NSS_UNAVAIL; - break; + if (_priv_exec->search_flag == GET_ALL) + if (_doexeclist(argp) == 0) + return (NSS_UNAVAIL); + return (NSS_SUCCESS); } - return (res); +fail: + if (be->buffer != NULL) { + free(be->buffer); + be->buffer = NULL; + be->buflen = 0; + } + if (parsestat == NSS_STR_PARSE_ERANGE) { + argp->erange = 1; + /* We won't find this otherwise, anyway */ + return (NSS_NOTFOUND); + } else if (parsestat == NSS_STR_PARSE_PARSE) { + return (NSS_NOTFOUND); + } + return (NSS_UNAVAIL); } @@ -131,17 +169,16 @@ _exec_process_val(_exec_nisplus_args * eargp, nis_object * obj) * returns 0 if - no matching entry found, * matching entry found and next match needed. */ +/*ARGSUSED*/ static int check_match(nis_name table, nis_object * obj, void *eargs) { - int len; - int status = 0; - char *p, *val; + int len, status = 0; + char *val; struct entry_col *ecol; nss_status_t res; _exec_nisplus_args *eargp = (_exec_nisplus_args *)eargs; nss_XbyY_args_t *argp = eargp->argp; - nisplus_backend_t *be = eargp->be; _priv_execattr *_priv_exec = (_priv_execattr *)(argp->key.attrp); const char *type = _priv_exec->type; const char *policy = _priv_exec->policy; @@ -171,7 +208,7 @@ check_match(nis_name table, nis_object * obj, void *eargs) * check policy; it was not a searchable column in old servers. */ EC_SET(ecol, EXECATTR_NDX_POLICY, len, val); - if ((len == NULL) || (strcmp(val, policy) != 0)) { + if ((len == 0) || (strcmp(val, policy) != 0)) { return (0); } } @@ -181,7 +218,7 @@ check_match(nis_name table, nis_object * obj, void *eargs) * check type */ EC_SET(ecol, EXECATTR_NDX_TYPE, len, val); - if ((len == NULL) || (strcmp(val, type) != 0)) { + if ((len == 0) || (strcmp(val, type) != 0)) { return (0); } } @@ -210,11 +247,9 @@ _exec_nisplus_lookup(nisplus_backend_t *be, nss_XbyY_args_t *argp, int getby_flag) { - int status; char key[MAX_INPUT]; char policy_key[POLICY_LEN]; const char *column1, *key1, *column2, *key2; - nis_object *obj; nis_result *r = NULL; nss_status_t res = NSS_NOTFOUND; _exec_nisplus_args eargs; @@ -347,7 +382,6 @@ getbyid(nisplus_backend_ptr_t be, void *a) { nss_status_t res; nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a; - _priv_execattr *_priv_exec = (_priv_execattr *)(argp->key.attrp); #ifdef DEBUG (void) fprintf(stdout, "\n[getexecattr.c: getbyid]\n"); @@ -369,7 +403,6 @@ getbynameid(nisplus_backend_ptr_t be, void *a) { nss_status_t res; nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a; - _priv_execattr *_priv_exec = (_priv_execattr *)(argp->key.attrp); #ifdef DEBUG (void) fprintf(stdout, "\n[getexecattr.c: getbynameid]\n"); @@ -387,28 +420,20 @@ getbynameid(nisplus_backend_ptr_t be, void *a) /* - * place the results from the nis_object structure into argp->buf.result * Returns NSS_STR_PARSE_{SUCCESS, ERANGE, PARSE} */ +/*ARGSUSED*/ static int -nis_object2execstr(int nobj, nis_object *obj, nss_XbyY_args_t *argp) +nis_object2execstr(int nobj, nis_object *obj, + nisplus_backend_ptr_t be, + nss_XbyY_args_t *argp) { - int len; - int buflen = argp->buf.buflen; - char *limit, *val, *endnum, *nullstring; - char *buffer = NULL; - char *empty = ""; - execstr_t *exec = NULL; + char *buffer, *name, *type, *policy; + char *res1, *res2, *id, *attr; + int buflen, namelen, typelen, policylen; + int res1len, res2len, idlen, attrlen; struct entry_col *ecol; - limit = argp->buf.buffer + buflen; - exec = (execstr_t *)argp->buf.result; - buffer = argp->buf.buffer; - - if ((buffer == NULL) || (exec == NULL)) { - return (NSS_STR_PARSE_PARSE); - } - /* * If we got more than one nis_object, we just ignore object(s) except * the first. Although it should never have happened. @@ -422,113 +447,49 @@ nis_object2execstr(int nobj, nis_object *obj, nss_XbyY_args_t *argp) } ecol = obj->EN_data.en_cols.en_cols_val; - /* - * execstr->name: profile name - */ - EC_SET(ecol, EXECATTR_NDX_NAME, len, val); - if (len < 1 || (*val == '\0')) { - val = empty; - } - exec->name = buffer; - buffer += len; - if (buffer >= limit) { - return (NSS_STR_PARSE_ERANGE); - } - strcpy(exec->name, val); - nullstring = (buffer - 1); - - /* - * execstr->type: exec type - */ - EC_SET(ecol, EXECATTR_NDX_TYPE, len, val); - if (len < 1 || (*val == '\0')) { - val = empty; - } - exec->type = buffer; - buffer += len; - if (buffer >= limit) { - return (NSS_STR_PARSE_ERANGE); - } - strcpy(exec->type, val); - nullstring = (buffer - 1); - - /* - * execstr->policy - */ - EC_SET(ecol, EXECATTR_NDX_POLICY, len, val); - if (len < 1 || (*val == '\0')) { - val = empty; - } - exec->policy = buffer; - buffer += len; - if (buffer >= limit) { - return (NSS_STR_PARSE_ERANGE); - } - strcpy(exec->policy, val); - nullstring = (buffer - 1); - - /* - * execstr->res1: reserved field 1 - */ - EC_SET(ecol, EXECATTR_NDX_RES1, len, val); - if (len < 1 || (*val == '\0')) { - val = empty; - } - exec->res1 = buffer; - buffer += len; - if (buffer >= limit) { - return (NSS_STR_PARSE_ERANGE); - } - strcpy(exec->res1, val); - nullstring = (buffer - 1); - - /* - * execstr->res2: reserved field 2 - */ - EC_SET(ecol, EXECATTR_NDX_RES2, len, val); - if (len < 1 || (*val == '\0')) { - val = empty; - } - exec->res2 = buffer; - buffer += len; - if (buffer >= limit) { - return (NSS_STR_PARSE_ERANGE); - } - strcpy(exec->res2, val); - nullstring = (buffer - 1); - - /* - * execstr->id: unique id - */ - EC_SET(ecol, EXECATTR_NDX_ID, len, val); - if (len < 1 || (*val == '\0')) { - val = empty; - } - exec->id = buffer; - buffer += len; - if (buffer >= limit) { - return (NSS_STR_PARSE_ERANGE); - } - strcpy(exec->id, val); - nullstring = (buffer - 1); - - /* - * execstr->attrs: key-value pairs of attributes - */ - EC_SET(ecol, EXECATTR_NDX_ATTR, len, val); - if (len < 1 || (*val == '\0')) { - val = empty; - } - exec->attr = buffer; - buffer += len; - if (buffer >= limit) { - return (NSS_STR_PARSE_ERANGE); + /* profile name */ + __NISPLUS_GETCOL_OR_RETURN(ecol, EXECATTR_NDX_NAME, namelen, name); + + /* exec type */ + __NISPLUS_GETCOL_OR_EMPTY(ecol, EXECATTR_NDX_TYPE, typelen, type); + + /* policy */ + __NISPLUS_GETCOL_OR_EMPTY(ecol, EXECATTR_NDX_POLICY, + policylen, policy); + + /* reserved field 1 */ + __NISPLUS_GETCOL_OR_EMPTY(ecol, EXECATTR_NDX_RES1, res1len, res1); + + /* reserved field 2 */ + __NISPLUS_GETCOL_OR_EMPTY(ecol, EXECATTR_NDX_RES2, res2len, res2); + + /* unique id */ + __NISPLUS_GETCOL_OR_EMPTY(ecol, EXECATTR_NDX_ID, idlen, id); + + /* key-value pairs of attributes */ + __NISPLUS_GETCOL_OR_EMPTY(ecol, EXECATTR_NDX_ATTR, attrlen, attr); + + buflen = namelen + policylen + typelen + res1len + res2len + + idlen + attrlen + 7; + if (argp->buf.result != NULL) { + if ((be->buffer = calloc(1, buflen)) == NULL) + return (NSS_STR_PARSE_PARSE); + /* exclude trailing null from length */ + be->buflen = buflen - 1; + buffer = be->buffer; + } else { + if (buflen > argp->buf.buflen) + return (NSS_STR_PARSE_ERANGE); + buflen = argp->buf.buflen; + buffer = argp->buf.buffer; + (void) memset(buffer, 0, buflen); } - strcpy(exec->attr, val); - nullstring = (buffer - 1); - - exec->next = (execstr_t *)NULL; - + (void) snprintf(buffer, buflen, "%s:%s:%s:%s:%s:%s:%s", + name, policy, type, res1, res2, id, attr); +#ifdef DEBUG + (void) fprintf(stdout, "execattr [%s]\n", buffer); + (void) fflush(stdout); +#endif /* DEBUG */ return (NSS_STR_PARSE_SUCCESS); } @@ -542,6 +503,7 @@ static nisplus_backend_op_t execattr_ops[] = { getbynameid }; +/*ARGSUSED*/ nss_backend_t * _nss_nisplus_exec_attr_constr(const char *dummy1, const char *dummy2, diff --git a/usr/src/lib/nsswitch/nisplus/common/getgrent.c b/usr/src/lib/nsswitch/nisplus/common/getgrent.c index 1b51eb5d23..5d1a5234ff 100644 --- a/usr/src/lib/nsswitch/nisplus/common/getgrent.c +++ b/usr/src/lib/nsswitch/nisplus/common/getgrent.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -72,7 +71,7 @@ getbygid(be, a) nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a; char gidstr[12]; /* More than enough */ - sprintf(gidstr, "%d", argp->key.gid); + (void) snprintf(gidstr, 12, "%ld", argp->key.gid); return (_nss_nisplus_lookup(be, argp, GR_TAG_GID, gidstr)); } @@ -144,7 +143,8 @@ getbymember(be, a) * dumping all of the group entries and searching from the member * name on our own. */ - sprintf(buf, "[members=%s],%s", argp->username, be->table_name); + (void) snprintf(buf, NIS_MAXNAMELEN, "[members=%s],%s", + argp->username, be->table_name); r = __nis_list_localcb(buf, NIS_LIST_COMMON | ALL_RESULTS | __nis_force_hard_lookups, gr_cback, &grdata); if (r && r->status != NIS_BADATTRIBUTE) { @@ -165,7 +165,7 @@ getbymember(be, a) /* - * place the results from the nis_object structure into argp->buf.result + * convert the nisplus object into files format * Returns NSS_STR_PARSE_{SUCCESS, ERANGE, PARSE} * * This routine does not tolerate non-numeric gr_gid. It @@ -173,21 +173,16 @@ getbymember(be, a) */ /*ARGSUSED*/ static int -nis_object2ent(nobj, obj, argp) - int nobj; - nis_object *obj; - nss_XbyY_args_t *argp; +nis_object2str(nobj, obj, be, argp) + int nobj; + nis_object *obj; + nisplus_backend_ptr_t be; + nss_XbyY_args_t *argp; { - char *buffer, *limit, *val, *endnum, *grstart; - int buflen = argp->buf.buflen; - struct group *gr; - struct entry_col *ecol; - int len; - char **memlist; - - limit = argp->buf.buffer + buflen; - gr = (struct group *)argp->buf.result; - buffer = argp->buf.buffer; + char *buffer, *name, *passwd, *gid, *members; + int buflen, namelen, passwdlen, gidlen, memberslen; + char *endnum; + struct entry_col *ecol; /* * If we got more than one nis_object, we just ignore it. @@ -204,92 +199,44 @@ nis_object2ent(nobj, obj, argp) } ecol = obj->EN_data.en_cols.en_cols_val; - /* - * gr_name: group name - */ - EC_SET(ecol, GR_NDX_NAME, len, val); - if (len < 2) - return (NSS_STR_PARSE_PARSE); - gr->gr_name = buffer; - buffer += len; - if (buffer >= limit) - return (NSS_STR_PARSE_ERANGE); - strcpy(gr->gr_name, val); + /* name: group name */ + __NISPLUS_GETCOL_OR_RETURN(ecol, GR_NDX_NAME, namelen, name); /* - * gr_passwd: group passwd - * - * POLICY: The empty password ("") is gladly accepted. + * passwd: group passwd + * empty password ("") is gladly accepted. */ - EC_SET(ecol, GR_NDX_PASSWD, len, val); - if (len == 0) { - len = 1; - val = ""; - } - gr->gr_passwd = buffer; - buffer += len; - if (buffer >= limit) - return (NSS_STR_PARSE_ERANGE); - strcpy(gr->gr_passwd, val); + __NISPLUS_GETCOL_OR_EMPTY(ecol, GR_NDX_PASSWD, passwdlen, passwd); - /* - * gr_gid: group id - */ - EC_SET(ecol, GR_NDX_GID, len, val); - if (len == 0) { + /* gid: group id */ + __NISPLUS_GETCOL_OR_RETURN(ecol, GR_NDX_GID, gidlen, gid); + (void) strtol(gid, &endnum, 10); + if (*endnum != 0 || gid == endnum) return (NSS_STR_PARSE_PARSE); - } else { - gr->gr_gid = strtol(val, &endnum, 10); - if (*endnum != 0) { - return (NSS_STR_PARSE_PARSE); - } - } - /* - * gr_mem: gid list - * - * We first copy the field that looks like "grp1,grp2,..,grpn\0" - * into the buffer and advance the buffer in order to allocate - * for the gr_mem vector. We work on the group members in place - * in the buffer by replacing the "commas" with \0 and simulataneously - * advance the vector and point to a member. - * - * POLICY: We happily accept a null gid list. NIS+ tables store - * that as a single null character. - */ - EC_SET(ecol, GR_NDX_MEM, len, val); - if (len == 0) { - len = 1; - val = ""; - } - grstart = buffer; - buffer += len; - if (buffer >= limit) - return (NSS_STR_PARSE_ERANGE); - strcpy(grstart, val); - - gr->gr_mem = memlist = (char **)ROUND_UP(buffer, sizeof (char **)); - limit = (char *)ROUND_DOWN(limit, sizeof (char **)); - - while ((char *)memlist < limit) { - char c; - char *p = grstart; - - if (*p != '\0') /* avoid empty string */ - *memlist++ = p; - while ((c = *p) != '\0' && c != ',') { - p++; - } - if (*p == '\0') { /* all done */ - *memlist = 0; - break; - } - *p++ = '\0'; - grstart = p; - } - if ((char *)memlist >= limit) - return (NSS_STR_PARSE_ERANGE); + /* members: gid list */ + __NISPLUS_GETCOL_OR_EMPTY(ecol, GR_NDX_MEM, memberslen, members); + buflen = namelen + passwdlen + gidlen + memberslen + 4; + if (argp->buf.result != NULL) { + if ((be->buffer = calloc(1, buflen)) == NULL) + return (NSS_STR_PARSE_PARSE); + /* exclude the trailing null from length */ + be->buflen = buflen - 1; + buffer = be->buffer; + } else { + if (buflen > argp->buf.buflen) + return (NSS_STR_PARSE_ERANGE); + buflen = argp->buf.buflen; + buffer = argp->buf.buffer; + (void) memset(buffer, 0, buflen); + } + (void) snprintf(buffer, buflen, "%s:%s:%s:%s", + name, passwd, gid, members); +#ifdef DEBUG + (void) fprintf(stdout, "group [%s]\n", buffer); + (void) fflush(stdout); +#endif /* DEBUG */ return (NSS_STR_PARSE_SUCCESS); } @@ -310,7 +257,7 @@ _nss_nisplus_group_constr(dummy1, dummy2, dummy3) { return (_nss_nisplus_constr(gr_ops, sizeof (gr_ops) / sizeof (gr_ops[0]), - GR_TBLNAME, nis_object2ent)); + GR_TBLNAME, nis_object2str)); } #define NEXT 0 @@ -404,7 +351,7 @@ netid_lookup(struct memdata *grdata, nisplus_backend_ptr_t be) return (NSS_NOTFOUND); } - snprintf(buf, NIS_MAXNAMELEN, + (void) snprintf(buf, NIS_MAXNAMELEN, "[auth_name=%d,auth_type=LOCAL],cred.%s", pw.pw_uid, nis_domain_of(be->table_name)); @@ -436,6 +383,7 @@ netid_lookup(struct memdata *grdata, nisplus_backend_ptr_t be) } } +/*ARGSUSED*/ static int netid_cback(nis_name objname, nis_object *obj, struct memdata *g) { diff --git a/usr/src/lib/nsswitch/nisplus/common/gethostent.c b/usr/src/lib/nsswitch/nisplus/common/gethostent.c index 4070316799..ed413ffe0b 100644 --- a/usr/src/lib/nsswitch/nisplus/common/gethostent.c +++ b/usr/src/lib/nsswitch/nisplus/common/gethostent.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,9 +19,11 @@ * CDDL HEADER END */ /* - * Copyright (c) 1988-1992 Sun Microsystems Inc - * All Rights Reserved. - * + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +/* * nisplus/gethostent.c -- NIS+ backend for nsswitch "hosts" database */ @@ -30,6 +31,8 @@ #include <string.h> #include <netdb.h> +#include <sys/types.h> +#include <arpa/inet.h> #include <netinet/in.h> #include <sys/socket.h> #include "nisplus_common.h" @@ -40,7 +43,7 @@ getbyname(be, a) nisplus_backend_ptr_t be; void *a; { - nss_XbyY_args_t *argp = (nss_XbyY_args_t *) a; + nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a; nss_status_t res; /* @@ -59,13 +62,13 @@ getbyaddr(be, a) nisplus_backend_ptr_t be; void *a; { - nss_XbyY_args_t *argp = (nss_XbyY_args_t *) a; + nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a; struct in_addr addr; char addrbuf[18]; nss_status_t res; - memcpy(&addr, argp->key.hostaddr.addr, sizeof (addr)); - inet_ntoa_r(addr, addrbuf); + (void) memcpy(&addr, argp->key.hostaddr.addr, sizeof (addr)); + (void) inet_ntoa_r(addr, addrbuf); res = _nss_nisplus_expand_lookup(be, argp, HOST_TAG_ADDR, addrbuf, HOST_TBLNAME); if (res != NSS_SUCCESS) @@ -75,75 +78,121 @@ getbyaddr(be, a) /* - * place the results from the nis_object structure into argp->buf.result * Returns NSS_STR_PARSE_{SUCCESS, ERANGE, PARSE} */ static int -nis_object2ent(nobj, obj, argp) - int nobj; - nis_object *obj; - nss_XbyY_args_t *argp; +nis_object2str(nobj, obj, be, argp) + int nobj; + nis_object *obj; + nisplus_backend_ptr_t be; + nss_XbyY_args_t *argp; { - char *buffer, *limit; - int buflen = argp->buf.buflen; - struct hostent *host; - struct in_addr *addrp; - int count, ret; - - limit = argp->buf.buffer + buflen; - host = (struct hostent *)argp->buf.result; - buffer = argp->buf.buffer; + return (nis_hosts_object2str(nobj, obj, be, argp, AF_INET)); +} + /* - * <--------------- buffer + buflen --------------------------------------> - * |-----------------|-----------------|----------------|----------------| - * | pointers vector | pointers vector | aliases grow | addresses grow | - * | for addresses | for aliases | | | - * | this way -> | this way -> | <- this way |<- this way | - * |-----------------|-----------------|----------------|----------------| - * | grows in PASS 1 | grows in PASS2 | grows in PASS2 | grows in PASS 1| - * - * - * ASSUME: the name and aliases columns in NIS+ tables ARE - * null terminated. - * - * - * PASS 1: get addresses + * Returns NSS_STR_PARSE_{SUCCESS, ERANGE, PARSE} */ - - addrp = (struct in_addr *) ROUND_DOWN(limit, sizeof (*addrp)); - host->h_addr_list = (char **) ROUND_UP(buffer, sizeof (char **)); - if ((char *)host->h_addr_list >= limit || - (char *)addrp <= (char *)host->h_addr_list) { - return (NSS_STR_PARSE_ERANGE); +int +nis_hosts_object2str(nobj, obj, be, argp, af) + int nobj; + nis_object *obj; + nisplus_backend_ptr_t be; + nss_XbyY_args_t *argp; + int af; +{ + char *buffer; + char *cname, *name, *addr; + int buflen, cnamelen, namelen, addrlen; + int first; + struct in_addr addr4; + struct entry_col *ecol; + + buflen = argp->buf.buflen; + buffer = argp->buf.buffer; + (void) memset(buffer, 0, buflen); + + for (first = 1; nobj > 0; nobj--, obj++) { + if (obj == NULL) + return (NSS_STR_PARSE_PARSE); + if (obj->zo_data.zo_type != NIS_ENTRY_OBJ || + obj->EN_data.en_cols.en_cols_len < HOST_COL) { + /* namespace/table/object is curdled */ + return (NSS_STR_PARSE_PARSE); + } + ecol = obj->EN_data.en_cols.en_cols_val; + + /* cname */ + __NISPLUS_GETCOL_OR_RETURN(ecol, HOST_NDX_CNAME, + cnamelen, cname); + + /* addr */ + __NISPLUS_GETCOL_OR_RETURN(ecol, HOST_NDX_ADDR, + addrlen, addr); + if (af == AF_INET) { + addr4.s_addr = inet_addr(addr); + if (addr4.s_addr == INADDR_NONE) + return (NSS_STR_PARSE_PARSE); + } + + /* name */ + __NISPLUS_GETCOL_OR_EMPTY(ecol, HOST_NDX_NAME, + namelen, name); + + /* + * newline is used to separate multiple + * entries. There is no newline before + * the first entry and after the last + * entry + */ + if (first) { + first = 0; + } else if (buflen > 1) { + *buffer = '\n'; + buffer++; + buflen--; + } else { + return (NSS_STR_PARSE_ERANGE); + } + + if (namelen > 1) { + if ((addrlen + cnamelen + namelen + 3) + > buflen) + return (NSS_STR_PARSE_ERANGE); + (void) snprintf(buffer, buflen, "%s %s %s", + addr, cname, name); + buffer += addrlen + cnamelen + namelen + 2; + buflen -= (addrlen + cnamelen + namelen + 2); + } else { + if ((addrlen + cnamelen + 2) > buflen) + return (NSS_STR_PARSE_ERANGE); + (void) snprintf(buffer, buflen, "%s %s", + addr, cname); + buffer += addrlen + cnamelen + 1; + buflen -= (addrlen + cnamelen + 1); + } } - ret = __netdb_aliases_from_nisobj(obj, nobj, NULL, - host->h_addr_list, (char **)&addrp, 0, &count, AF_INET); - if (ret != NSS_STR_PARSE_SUCCESS) - return (ret); - - /* - * PASS 2: get cname and aliases - */ - - host->h_aliases = host->h_addr_list + count + 1; - host->h_name = NULL; - - /* - * Assume that CNAME is the first column and NAME the second. - */ - ret = __netdb_aliases_from_nisobj(obj, nobj, NULL, host->h_aliases, - (char **)&addrp, &(host->h_name), &count, AF_INET); - if (ret != NSS_STR_PARSE_SUCCESS) - return (ret); - - host->h_addrtype = AF_INET; - host->h_length = sizeof (u_int); - + if (argp->buf.result != NULL) { + /* + * Some front end marshallers may require the + * files formatted data in a distinct buffer + */ + if ((be->buffer = strdup(argp->buf.buffer)) == NULL) + return (NSS_STR_PARSE_PARSE); + be->buflen = strlen(be->buffer); + } +#ifdef DEBUG + (void) fprintf(stdout, "%s [%s]\n", + (af == AF_INET)?"hosts":"ipnodes", + argp->buf.buffer); + (void) fflush(stdout); +#endif /* DEBUG */ return (NSS_STR_PARSE_SUCCESS); } + static nisplus_backend_op_t host_ops[] = { _nss_nisplus_destr, _nss_nisplus_endent, @@ -160,5 +209,5 @@ _nss_nisplus_hosts_constr(dummy1, dummy2, dummy3) { return (_nss_nisplus_constr(host_ops, sizeof (host_ops) / sizeof (host_ops[0]), - HOST_TBLNAME, nis_object2ent)); + HOST_TBLNAME, nis_object2str)); } diff --git a/usr/src/lib/nsswitch/nisplus/common/gethostent6.c b/usr/src/lib/nsswitch/nisplus/common/gethostent6.c index e9633d58a0..55ca8bc5a5 100644 --- a/usr/src/lib/nsswitch/nisplus/common/gethostent6.c +++ b/usr/src/lib/nsswitch/nisplus/common/gethostent6.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,9 +19,11 @@ * CDDL HEADER END */ /* - * Copyright 1988-1992, 2003 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. - * + */ + +/* * nisplus/gethostent6.c -- NIS+ backend for nsswitch "ipnodes" database */ @@ -34,10 +35,9 @@ #include <sys/socket.h> #include "nisplus_common.h" #include "nisplus_tables.h" +#include <arpa/inet.h> #include <inet/ip6.h> -const char *inet_ntop(int af, const void *src, char *dst, size_t size); - static nss_status_t getbyname(be, a) nisplus_backend_ptr_t be; @@ -72,7 +72,7 @@ getbyaddr(be, a) return (NSS_NOTFOUND); } - memcpy(&addr, argp->key.hostaddr.addr, sizeof (addr)); + (void) memcpy(&addr, argp->key.hostaddr.addr, sizeof (addr)); if (IN6_IS_ADDR_V4MAPPED(&addr)) { if (inet_ntop(AF_INET, (void *) &addr.s6_addr[12], (void *)addrbuf, INET_ADDRSTRLEN) == NULL) { @@ -93,76 +93,19 @@ getbyaddr(be, a) /* - * place the results from the nis_object structure into argp->buf.result * Returns NSS_STR_PARSE_{SUCCESS, ERANGE, PARSE} */ static int -nis_object2ent(nobj, obj, argp) - int nobj; - nis_object *obj; - nss_XbyY_args_t *argp; +nis_object2str(nobj, obj, be, argp) + int nobj; + nis_object *obj; + nisplus_backend_ptr_t be; + nss_XbyY_args_t *argp; { - char *buffer, *limit; - int buflen = argp->buf.buflen; - struct hostent *host; - struct in6_addr *addrp; - int count, ret; - - limit = argp->buf.buffer + buflen; - host = (struct hostent *)argp->buf.result; - buffer = argp->buf.buffer; - -/* - * <--------------- buffer + buflen --------------------------------------> - * |-----------------|-----------------|----------------|----------------| - * | pointers vector | pointers vector | aliases grow | addresses grow | - * | for addresses | for aliases | | | - * | this way -> | this way -> | <- this way |<- this way | - * |-----------------|-----------------|----------------|----------------| - * | grows in PASS 1 | grows in PASS2 | grows in PASS2 | grows in PASS 1| - * - * - * ASSUME: the name and aliases columns in NIS+ tables ARE - * null terminated. - * - * - * PASS 1: get addresses - */ - - addrp = (struct in6_addr *)ROUND_DOWN(limit, sizeof (*addrp)); - host->h_addr_list = (char **)ROUND_UP(buffer, sizeof (char **)); - if ((char *)host->h_addr_list >= limit || - (char *)addrp <= (char *)host->h_addr_list) { - return (NSS_STR_PARSE_ERANGE); - } - - ret = __netdb_aliases_from_nisobj(obj, nobj, NULL, - host->h_addr_list, (char **)&addrp, 0, &count, AF_INET6); - if (ret != NSS_STR_PARSE_SUCCESS) - return (ret); - - /* - * PASS 2: get cname and aliases - */ - - host->h_aliases = host->h_addr_list + count + 1; - host->h_name = NULL; - - /* - * Assume that CNAME is the first column and NAME the second. - */ - ret = __netdb_aliases_from_nisobj(obj, nobj, NULL, - host->h_aliases, (char **)&addrp, &(host->h_name), &count, - AF_INET6); - if (ret != NSS_STR_PARSE_SUCCESS) - return (ret); - - host->h_addrtype = AF_INET6; - host->h_length = IPV6_ADDR_LEN; - - return (NSS_STR_PARSE_SUCCESS); + return (nis_hosts_object2str(nobj, obj, be, argp, AF_INET6)); } + static nisplus_backend_op_t ipnodes_ops[] = { _nss_nisplus_destr, _nss_nisplus_endent, @@ -179,5 +122,5 @@ _nss_nisplus_ipnodes_constr(dummy1, dummy2, dummy3) { return (_nss_nisplus_constr(ipnodes_ops, sizeof (ipnodes_ops) / sizeof (ipnodes_ops[0]), - IPNODES_TBLNAME, nis_object2ent)); + IPNODES_TBLNAME, nis_object2str)); } diff --git a/usr/src/lib/nsswitch/nisplus/common/getnetent.c b/usr/src/lib/nsswitch/nisplus/common/getnetent.c index b6efa5f950..3a0a08cb7b 100644 --- a/usr/src/lib/nsswitch/nisplus/common/getnetent.c +++ b/usr/src/lib/nsswitch/nisplus/common/getnetent.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,11 +19,11 @@ * CDDL HEADER END */ /* - * getnetent.c - * - * Copyright (c) 1988-1992 Sun Microsystems Inc - * All Rights Reserved. - * + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +/* * nisplus/getnetent.c -- NIS+ backend for nsswitch "net" database */ @@ -44,7 +43,7 @@ getbyname(be, a) nisplus_backend_ptr_t be; void *a; { - nss_XbyY_args_t *argp = (nss_XbyY_args_t *) a; + nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a; /* * Don't have to do anything for case-insensitivity; the NIS+ table @@ -58,10 +57,10 @@ getbyaddr(be, a) nisplus_backend_ptr_t be; void *a; { - nss_XbyY_args_t *argp = (nss_XbyY_args_t *) a; + nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a; char addrstr[16]; - if (nettoa((int) argp->key.netaddr.net, addrstr, 16) != 0) + if (nettoa((int)argp->key.netaddr.net, addrstr, 16) != 0) return (NSS_UNAVAIL); /* it's really ENOMEM */ return (_nss_nisplus_lookup(be, argp, NET_TAG_ADDR, addrstr)); @@ -69,66 +68,68 @@ getbyaddr(be, a) /* - * place the results from the nis_object structure into argp->buf.result + * Convert nisplus object into files format * Returns NSS_STR_PARSE_{SUCCESS, ERANGE, PARSE} */ static int -nis_object2ent(nobj, obj, argp) - int nobj; - nis_object *obj; - nss_XbyY_args_t *argp; +nis_object2str(nobj, obj, be, argp) + int nobj; + nis_object *obj; + nisplus_backend_ptr_t be; + nss_XbyY_args_t *argp; { - char *buffer, *limit, *val; - int buflen = argp->buf.buflen; - struct netent *net; - int len, ret; - struct entry_col *ecol; - - limit = argp->buf.buffer + buflen; - net = (struct netent *)argp->buf.result; - buffer = argp->buf.buffer; - - /* - * <-----buffer + buflen --------------> - * |-----------------|----------------| - * | pointers vector | aliases grow | - * | for aliases | | - * | this way -> | <- this way | - * |-----------------|----------------| - * - * - * ASSUME: name, aliases and number columns in NIS+ tables ARE - * null terminated. - * - * get cname and aliases - */ - - net->n_aliases = (char **) ROUND_UP(buffer, sizeof (char **)); - if ((char *)net->n_aliases >= limit) { - return (NSS_STR_PARSE_ERANGE); + char *buffer, *linep, *limit; + char *cname, *addr; + int buflen, cnamelen, addrlen; + int stat; + struct entry_col *ecol; + + if (obj->zo_data.zo_type != NIS_ENTRY_OBJ || + obj->EN_data.en_cols.en_cols_len < NET_COL) { + /* namespace/table/object is curdled */ + return (NSS_STR_PARSE_PARSE); } + ecol = obj->EN_data.en_cols.en_cols_val; - net->n_name = NULL; + buflen = argp->buf.buflen; + buffer = argp->buf.buffer; + (void) memset(buffer, 0, buflen); - /* - * Assume that CNAME is the first column and NAME the second. - */ - ret = netdb_aliases_from_nisobj(obj, nobj, NULL, - net->n_aliases, &limit, &(net->n_name), &len); - if (ret != NSS_STR_PARSE_SUCCESS) - return (ret); + /* cname */ + __NISPLUS_GETCOL_OR_RETURN(ecol, NET_NDX_CNAME, + cnamelen, cname); - /* - * get network number from the first object - * - */ - ecol = obj->EN_data.en_cols.en_cols_val; - EC_SET(ecol, NET_NDX_ADDR, len, val); - if (len <= 0 || ((net->n_net = inet_network(val)) == (in_addr_t)-1)) + /* addr */ + __NISPLUS_GETCOL_OR_RETURN(ecol, NET_NDX_ADDR, + addrlen, addr); + if (inet_network(addr) == (in_addr_t)-1) return (NSS_STR_PARSE_PARSE); - net->n_addrtype = AF_INET; - + if (cnamelen + addrlen + 2 > buflen) + return (NSS_STR_PARSE_ERANGE); + (void) snprintf(buffer, buflen, "%s %s", cname, addr); + + linep = buffer + cnamelen + addrlen + 1; + limit = buffer + buflen; + + stat = nis_aliases_object2str(obj, nobj, cname, NULL, linep, limit); + if (stat != NSS_STR_PARSE_SUCCESS) + return (stat); + + if (argp->buf.result != NULL) { + /* + * Some front end marshallers may require the + * files formatted data in a distinct buffer + */ + if ((be->buffer = strdup(buffer)) == NULL) + return (NSS_STR_PARSE_PARSE); + be->buflen = strlen(buffer); + buffer = be->buffer; + } +#ifdef DEBUG + (void) fprintf(stdout, "networks [%s]\n", buffer); + (void) fflush(stdout); +#endif /* DEBUG */ return (NSS_STR_PARSE_SUCCESS); } @@ -148,7 +149,7 @@ _nss_nisplus_networks_constr(dummy1, dummy2, dummy3) { return (_nss_nisplus_constr(net_ops, sizeof (net_ops) / sizeof (net_ops[0]), - NET_TBLNAME, nis_object2ent)); + NET_TBLNAME, nis_object2str)); } /* @@ -159,18 +160,18 @@ _nss_nisplus_networks_constr(dummy1, dummy2, dummy3) static int nettoa(anet, buf, buflen) int anet; - char *buf; + char *buf; int buflen; { - char *p; - struct in_addr in; - int addr; + char *p; + struct in_addr in; + int addr; if (buf == 0) return (1); in = inet_makeaddr(anet, INADDR_ANY); addr = in.s_addr; - (void) strncpy(buf, inet_ntoa(in), buflen); + (void) strlcpy(buf, inet_ntoa(in), buflen); if ((IN_CLASSA_HOST & htonl(addr)) == 0) { p = strchr(buf, '.'); if (p == NULL) diff --git a/usr/src/lib/nsswitch/nisplus/common/getnetgrent.c b/usr/src/lib/nsswitch/nisplus/common/getnetgrent.c index ba4c0ce14f..36ef196801 100644 --- a/usr/src/lib/nsswitch/nisplus/common/getnetgrent.c +++ b/usr/src/lib/nsswitch/nisplus/common/getnetgrent.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -147,7 +146,7 @@ getnetgr_get(be, a) args->retp[i] = 0; } else if ((len = strlen(str) + 1) <= buflen) { args->retp[i] = buffer; - memcpy(buffer, str, len); + (void) memcpy(buffer, str, len); buffer += len; buflen -= len; } else { @@ -196,7 +195,7 @@ getnetgr_destr(be, dummy) void *dummy; { if (be != 0) { - getnetgr_end(be, 0); + (void) getnetgr_end(be, 0); free(be); } return (NSS_SUCCESS); @@ -273,7 +272,7 @@ static void ngt_init(ngt) struct netgrtab *ngt; { - memset((void *)ngt, 0, sizeof (*ngt)); + (void) memset((void *)ngt, 0, sizeof (*ngt)); ngt->expand_lastp = &ngt->expand_first; } @@ -339,7 +338,7 @@ ngt_insert(ngt, name, namelen, breadth_first) if (cur == 0) { return; /* Out of memory, too bad */ } - memcpy(cur->name, name, namelen); + (void) memcpy(cur->name, name, namelen); cur->name[namelen] = 0; /* Insert in hash table */ @@ -497,26 +496,25 @@ top_down(be, groups, ngroups, func, iter_args) int i; /* %%% was NETGR_NDX_NAME */ - sprintf(search_crit, "[%s=%s]%s", + (void) snprintf(search_crit, NIS_MAXNAMELEN, "[%s=%s]%s", NETGR_TAG_NAME, group, be->table_name); result = _nss_nisplus_list(search_crit, 0, &r); if (result != NSS_SUCCESS) { - if (result == NSS_NOTFOUND) { #ifdef DEBUG + if (result == NSS_NOTFOUND) { syslog(LOG_WARNING, "innetgr: no such NIS+ netgroup as %s", group); -#endif /* DEBUG */ } else { -#ifdef DEBUG syslog(LOG_WARNING, "innetgr: nis_list returned [%s]", (r == 0) ? "A null pointer !?" : nis_sperrno(NIS_RES_STATUS(r))); + } #endif /* DEBUG */ + if (result != NSS_NOTFOUND) done = 1; /* Give up, return result */ - } if (r != 0) { nis_freeresult(r); } @@ -750,7 +748,7 @@ every_which_way(be, args) enum { BAD, BAD_NSS_TRYAGAIN, NO, YES } verdict; /* Copy NIS+ search value; ==== Should really do NIS+ quoting */ -#define catquoted(to, from) strcat(to, from) +#define catquoted(to, from) (void) strcat(to, from) /* * ====> @@ -813,7 +811,7 @@ every_which_way(be, args) pusers = nusers ? args->arg[NSS_NETGR_USER].argv : 0; do { if (pusers != 0) { - strcpy(users, ",user="); + (void) strcpy(users, ",user="); if (nusers != 0) { catquoted(users, *pusers); pusers++; @@ -825,7 +823,7 @@ every_which_way(be, args) phosts = nhosts ? args->arg[NSS_NETGR_MACHINE].argv : 0; do { if (phosts != 0) { - strcpy(hosts, ",host="); + (void) strcpy(hosts, ",host="); if (nhosts != 0) { catquoted(hosts, *phosts); phosts++; @@ -833,8 +831,8 @@ every_which_way(be, args) } search_crit[0] = '['; /* Was temporarily a comma */ - strcat(search_crit, "]"); - strcat(search_crit, be->table_name); + (void) strcat(search_crit, "]"); + (void) strcat(search_crit, be->table_name); switch (_nss_nisplus_list(search_crit, 0, &r)) { case NSS_SUCCESS: break; @@ -913,7 +911,8 @@ every_which_way(be, args) #ifdef SEARCH_DOWN_TOO if (top->n_total < bottom->n_total /* and a fudge factor? */) { group = ngt_next(top); - sprintf(search_crit, "[%s=%s]%s", + (void) snprintf(search_crit, NIS_MAXNAMELEN, + "[%s=%s]%s", NETGR_NDX_NAME, group, be->table_name); switch (_nss_nisplus_list(search_crit, 0, &r)) { case NSS_SUCCESS: @@ -962,7 +961,8 @@ every_which_way(be, args) #endif /* SEARCH_DOWN_TOO */ group = ngt_next(bottom); /* %%% was NETGR_NDX_GROUP */ - sprintf(search_crit, "[%s=%s],%s", + (void) snprintf(search_crit, NIS_MAXNAMELEN, + "[%s=%s],%s", NETGR_TAG_GROUP, group, be->table_name); switch (_nss_nisplus_list(search_crit, 0, &r)) { case NSS_SUCCESS: @@ -1067,10 +1067,11 @@ netgr_in(be, a) /*ARGSUSED*/ static int -bogus_object2ent(nobj, obj, argp) - int nobj; - nis_object *obj; - nss_XbyY_args_t *argp; +bogus_object2str(nobj, obj, be, argp) + int nobj; + nis_object *obj; + nisplus_backend_ptr_t be; + nss_XbyY_args_t *argp; { /* * This should never get used in the netgroup backend; @@ -1098,5 +1099,5 @@ _nss_nisplus_netgroup_constr(dummy1, dummy2, dummy3) { return (_nss_nisplus_constr(netgroup_ops, sizeof (netgroup_ops) / sizeof (netgroup_ops[0]), - NETGR_TBLNAME, bogus_object2ent)); + NETGR_TBLNAME, bogus_object2str)); } diff --git a/usr/src/lib/nsswitch/nisplus/common/getprinter.c b/usr/src/lib/nsswitch/nisplus/common/getprinter.c index 86566727c2..26037c0f96 100644 --- a/usr/src/lib/nsswitch/nisplus/common/getprinter.c +++ b/usr/src/lib/nsswitch/nisplus/common/getprinter.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,18 +19,19 @@ * CDDL HEADER END */ /* - * Copyright (c) 1988-1995 Sun Microsystems Inc - * All Rights Reserved. - * - * nisplus/getspent.c: implementations of getspnam(), getspent(), setspent(), - * endspent() for NIS+. We keep the shadow information in a column - * ("shadow") of the same table that stores vanilla passwd information. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +/* + * nisplus/getprinter.c */ #pragma ident "%Z%%M% %I% %E% SMI" #pragma weak _nss_nisplus__printers_constr = _nss_nisplus_printers_constr +#include <stdlib.h> #include <nss_dbdefs.h> #include "nisplus_common.h" #include "nisplus_tables.h" @@ -42,29 +42,26 @@ getbyname(be, a) nisplus_backend_ptr_t be; void *a; { - nss_XbyY_args_t *argp = (nss_XbyY_args_t *) a; + nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a; return (_nss_nisplus_lookup(be, argp, PRINTERS_TAG_KEY, argp->key.name)); } /* - * place the results from the nis_object structure into argp->buf.buffer - * (hid argp->buf.buflen) that was supplied by the caller. * Returns NSS_STR_PARSE_{SUCCESS, ERANGE, PARSE} */ +/*ARGSUSED*/ static int -nis_object2ent(nobj, obj, argp) - int nobj; - nis_object *obj; - nss_XbyY_args_t *argp; +nis_object2str(nobj, obj, be, argp) + int nobj; + nis_object *obj; + nisplus_backend_ptr_t be; + nss_XbyY_args_t *argp; { - char *buffer, *val; - int buflen = argp->buf.buflen; - struct entry_col *ecol; - int len; - - buffer = argp->buf.buffer; + char *buffer, *key, *val; + int buflen, keylen, vallen; + struct entry_col *ecol; /* * If we got more than one nis_object, we just ignore it. @@ -81,30 +78,30 @@ nis_object2ent(nobj, obj, argp) } ecol = obj->EN_data.en_cols.en_cols_val; - /* - * key - */ - EC_SET(ecol, PRINTERS_NDX_KEY, len, val); - if (len < 2) { - *buffer = 0; - return (NSS_STR_PARSE_SUCCESS); - } - if (len > buflen) - return (NSS_STR_PARSE_ERANGE); - strncpy(buffer, val, len); + /* key */ + __NISPLUS_GETCOL_OR_RETURN(ecol, PRINTERS_NDX_KEY, keylen, key); - /* - * datum - */ - EC_SET(ecol, PRINTERS_NDX_DATUM, len, val); - if (len < 2) { - *buffer = 0; - return (NSS_STR_PARSE_SUCCESS); - } - if (len > buflen) - return (NSS_STR_PARSE_ERANGE); - strncat(buffer, val, buflen); + /* datum */ + __NISPLUS_GETCOL_OR_EMPTY(ecol, PRINTERS_NDX_DATUM, vallen, val); + buflen = vallen + keylen + 1; + if (argp->buf.result != NULL) { + if ((be->buffer = calloc(1, buflen)) == NULL) + return (NSS_STR_PARSE_PARSE); + be->buflen = buflen; + buffer = be->buffer; + } else { + if (buflen > argp->buf.buflen) + return (NSS_STR_PARSE_ERANGE); + buflen = argp->buf.buflen; + buffer = argp->buf.buffer; + (void) memset(buffer, 0, buflen); + } + (void) snprintf(buffer, buflen, "%s%s", key, val); +#ifdef DEBUG + (void) fprintf(stdout, "printers [%s]\n", buffer); + (void) fflush(stdout); +#endif /* DEBUG */ return (NSS_STR_PARSE_SUCCESS); } @@ -116,11 +113,12 @@ static nisplus_backend_op_t printers_ops[] = { getbyname }; +/*ARGSUSED*/ nss_backend_t * _nss_nisplus_printers_constr(dummy1, dummy2, dummy3) const char *dummy1, *dummy2, *dummy3; { return (_nss_nisplus_constr(printers_ops, sizeof (printers_ops) / sizeof (printers_ops[0]), - PRINTERS_TBLNAME, nis_object2ent)); + PRINTERS_TBLNAME, nis_object2str)); } diff --git a/usr/src/lib/nsswitch/nisplus/common/getprofattr.c b/usr/src/lib/nsswitch/nisplus/common/getprofattr.c index 7e6dfcb04c..c1a7111f41 100644 --- a/usr/src/lib/nsswitch/nisplus/common/getprofattr.c +++ b/usr/src/lib/nsswitch/nisplus/common/getprofattr.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,8 +19,8 @@ * CDDL HEADER END */ /* - * Copyright (c) 1999-2001 by Sun Microsystems, Inc. - * All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. */ #pragma ident "%Z%%M% %I% %E% SMI" @@ -47,19 +46,18 @@ getbynam(nisplus_backend_ptr_t be, void *a) * place the results from the nis_object structure into argp->buf.result * Returns NSS_STR_PARSE_{SUCCESS, ERANGE, PARSE} */ +/*ARGSUSED*/ static int -nis_object2profstr(int nobj, nis_object *obj, nss_XbyY_args_t *argp) +nis_object2profstr(int nobj, nis_object *obj, + nisplus_backend_ptr_t be, + nss_XbyY_args_t *argp) { - int len; - int buflen = argp->buf.buflen; - char *buffer, *limit, *val, *endnum, *nullstring; - char *empty = ""; - profstr_t *prof; + char *buffer, *name, *res1, *res2, *desc; + char *attr; + int buflen, namelen, res1len, res2len; + int desclen, attrlen; struct entry_col *ecol; - limit = argp->buf.buffer + buflen; - prof = (profstr_t *)argp->buf.result; - buffer = argp->buf.buffer; /* * If we got more than one nis_object, we just ignore object(s) except * the first. Although it should never have happened. @@ -74,81 +72,41 @@ nis_object2profstr(int nobj, nis_object *obj, nss_XbyY_args_t *argp) } ecol = obj->EN_data.en_cols.en_cols_val; - /* - * profstr->name: profile name - */ - EC_SET(ecol, PROFATTR_NDX_NAME, len, val); - if (len < 1 || (*val == '\0')) { - val = empty; - } - prof->name = buffer; - buffer += len; - if (buffer >= limit) { - return (NSS_STR_PARSE_ERANGE); - } - strcpy(prof->name, val); - nullstring = (buffer - 1); - - /* - * profstr->res1: reserved field 1 - */ - EC_SET(ecol, PROFATTR_NDX_RES1, len, val); - if (len < 1 || (*val == '\0')) { - val = empty; - } - prof->res1 = buffer; - buffer += len; - if (buffer >= limit) { - return (NSS_STR_PARSE_ERANGE); - } - strcpy(prof->res1, val); - nullstring = (buffer - 1); - - /* - * profstr->res2: reserved field 2 - */ - EC_SET(ecol, PROFATTR_NDX_RES2, len, val); - if (len < 1 || (*val == '\0')) { - val = empty; + /* name: profile name */ + __NISPLUS_GETCOL_OR_RETURN(ecol, PROFATTR_NDX_NAME, namelen, name); + + /* res1: reserved field 1 */ + __NISPLUS_GETCOL_OR_EMPTY(ecol, PROFATTR_NDX_RES1, res1len, res1); + + /* res2: reserved field 2 */ + __NISPLUS_GETCOL_OR_EMPTY(ecol, PROFATTR_NDX_RES2, res2len, res2); + + /* desc: description */ + __NISPLUS_GETCOL_OR_EMPTY(ecol, PROFATTR_NDX_DESC, desclen, desc); + + /* attrs: key-value pairs of attributes */ + __NISPLUS_GETCOL_OR_EMPTY(ecol, PROFATTR_NDX_ATTR, attrlen, attr); + + buflen = namelen + res1len + res2len + desclen + attrlen + 5; + if (argp->buf.result != NULL) { + if ((be->buffer = calloc(1, buflen)) == NULL) + return (NSS_STR_PARSE_PARSE); + /* exclude trailing null from length */ + be->buflen = buflen - 1; + buffer = be->buffer; + } else { + if (buflen > argp->buf.buflen) + return (NSS_STR_PARSE_ERANGE); + buflen = argp->buf.buflen; + buffer = argp->buf.buffer; + (void) memset(buffer, 0, buflen); } - prof->res2 = buffer; - buffer += len; - if (buffer >= limit) { - return (NSS_STR_PARSE_ERANGE); - } - strcpy(prof->res2, val); - nullstring = (buffer - 1); - - /* - * profstr->desc: description - */ - EC_SET(ecol, PROFATTR_NDX_DESC, len, val); - if (len < 1 || (*val == '\0')) { - val = empty; - } - prof->desc = buffer; - buffer += len; - if (buffer >= limit) { - return (NSS_STR_PARSE_ERANGE); - } - strcpy(prof->desc, val); - nullstring = (buffer - 1); - - /* - * profstr->attrs: key-value pairs of attributes - */ - EC_SET(ecol, PROFATTR_NDX_ATTR, len, val); - if (len < 1 || (*val == '\0')) { - val = empty; - } - prof->attr = buffer; - buffer += len; - if (buffer >= limit) { - return (NSS_STR_PARSE_ERANGE); - } - strcpy(prof->attr, val); - nullstring = (buffer - 1); - + (void) snprintf(buffer, buflen, "%s:%s:%s:%s:%s", + name, res1, res2, desc, attr); +#ifdef DEBUG + (void) fprintf(stdout, "profattr [%s]\n", buffer); + (void) fflush(stdout); +#endif /* DEBUG */ return (NSS_STR_PARSE_SUCCESS); } @@ -160,6 +118,7 @@ static nisplus_backend_op_t profattr_ops[] = { getbynam }; +/*ARGSUSED*/ nss_backend_t * _nss_nisplus_prof_attr_constr(const char *dummy1, const char *dummy2, diff --git a/usr/src/lib/nsswitch/nisplus/common/getprotoent.c b/usr/src/lib/nsswitch/nisplus/common/getprotoent.c index aa40a34fc1..356236d2f2 100644 --- a/usr/src/lib/nsswitch/nisplus/common/getprotoent.c +++ b/usr/src/lib/nsswitch/nisplus/common/getprotoent.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,11 +19,11 @@ * CDDL HEADER END */ /* - * getprotoent.c - * - * Copyright (c) 1988-1992 Sun Microsystems Inc - * All Rights Reserved. - * + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +/* * nisplus/getprotoent.c -- NIS+ backend for nsswitch "proto" database */ @@ -41,7 +40,7 @@ getbyname(be, a) nisplus_backend_ptr_t be; void *a; { - nss_XbyY_args_t *argp = (nss_XbyY_args_t *) a; + nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a; /* * Don't have to do anything for case-insensitivity; the NIS+ table @@ -55,74 +54,78 @@ getbynumber(be, a) nisplus_backend_ptr_t be; void *a; { - nss_XbyY_args_t *argp = (nss_XbyY_args_t *) a; + nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a; char numstr[12]; - sprintf(numstr, "%d", argp->key.number); + (void) snprintf(numstr, 12, "%d", argp->key.number); return (_nss_nisplus_lookup(be, argp, PROTO_TAG_NUMBER, numstr)); } /* - * place the results from the nis_object structure into argp->buf.result + * Convert nisplus object into files format * Returns NSS_STR_PARSE_{SUCCESS, ERANGE, PARSE} */ static int -nis_object2ent(nobj, obj, argp) - int nobj; - nis_object *obj; - nss_XbyY_args_t *argp; +nis_object2str(nobj, obj, be, argp) + int nobj; + nis_object *obj; + nisplus_backend_ptr_t be; + nss_XbyY_args_t *argp; { - char *buffer, *limit, *val; - int buflen = argp->buf.buflen; - struct protoent *proto; - int len, ret; - struct entry_col *ecol; - - limit = argp->buf.buffer + buflen; - proto = (struct protoent *)argp->buf.result; - buffer = argp->buf.buffer; - - /* - * <-----buffer + buflen --------------> - * |-----------------|----------------| - * | pointers vector | aliases grow | - * | for aliases | | - * | this way -> | <- this way | - * |-----------------|----------------| - * - * - * ASSUME: name, aliases and number columns in NIS+ tables ARE - * null terminated. - * - * get cname and aliases - */ - - proto->p_aliases = (char **) ROUND_UP(buffer, sizeof (char **)); - if ((char *)proto->p_aliases >= limit) { - return (NSS_STR_PARSE_ERANGE); + char *buffer, *linep, *limit; + char *cname, *number, *endnum; + int buflen, cnamelen, numberlen; + int stat; + struct entry_col *ecol; + + if (obj->zo_data.zo_type != NIS_ENTRY_OBJ || + obj->EN_data.en_cols.en_cols_len < PROTO_COL) { + /* namespace/table/object is curdled */ + return (NSS_STR_PARSE_PARSE); } + ecol = obj->EN_data.en_cols.en_cols_val; - proto->p_name = NULL; + buflen = argp->buf.buflen; + buffer = argp->buf.buffer; + (void) memset(buffer, 0, buflen); - /* - * Assume that CNAME is the first column and NAME the second. - */ - ret = netdb_aliases_from_nisobj(obj, nobj, NULL, - proto->p_aliases, &limit, &(proto->p_name), &len); - if (ret != NSS_STR_PARSE_SUCCESS) - return (ret); + /* cname */ + __NISPLUS_GETCOL_OR_RETURN(ecol, PROTO_NDX_CNAME, + cnamelen, cname); - /* - * get protocol number from the first object - * - */ - ecol = obj->EN_data.en_cols.en_cols_val; - EC_SET(ecol, PROTO_NDX_NUMBER, len, val); - if (len <= 0) + /* number */ + __NISPLUS_GETCOL_OR_RETURN(ecol, PROTO_NDX_NUMBER, + numberlen, number); + (void) strtol(number, &endnum, 10); + if (*endnum != 0 || endnum == number) return (NSS_STR_PARSE_PARSE); - proto->p_proto = atoi(val); + if (cnamelen + numberlen + 2 > buflen) + return (NSS_STR_PARSE_ERANGE); + (void) snprintf(buffer, buflen, "%s %s", cname, number); + + linep = buffer + cnamelen + numberlen + 1; + limit = buffer + buflen; + + stat = nis_aliases_object2str(obj, nobj, cname, NULL, linep, limit); + if (stat != NSS_STR_PARSE_SUCCESS) + return (stat); + + if (argp->buf.result != NULL) { + /* + * Some front end marshallers may require the + * files formatted data in a distinct buffer + */ + if ((be->buffer = strdup(buffer)) == NULL) + return (NSS_STR_PARSE_PARSE); + be->buflen = strlen(buffer); + buffer = be->buffer; + } +#ifdef DEBUG + (void) fprintf(stdout, "protocols [%s]\n", buffer); + (void) fflush(stdout); +#endif /* DEBUG */ return (NSS_STR_PARSE_SUCCESS); } @@ -142,5 +145,5 @@ _nss_nisplus_protocols_constr(dummy1, dummy2, dummy3) { return (_nss_nisplus_constr(proto_ops, sizeof (proto_ops) / sizeof (proto_ops[0]), - PROTO_TBLNAME, nis_object2ent)); + PROTO_TBLNAME, nis_object2str)); } diff --git a/usr/src/lib/nsswitch/nisplus/common/getpwnam.c b/usr/src/lib/nsswitch/nisplus/common/getpwnam.c index 5336e05a82..19807456e5 100644 --- a/usr/src/lib/nsswitch/nisplus/common/getpwnam.c +++ b/usr/src/lib/nsswitch/nisplus/common/getpwnam.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,12 +19,12 @@ * CDDL HEADER END */ /* - * getpwnam.c - * - * Copyright (c) 1988-1992 Sun Microsystems Inc - * All Rights Reserved. - * - * nisplus/getpwnam.c -- NIS+ backend for nsswitch "passwd" database + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +/* + * nisplus/getpwnam.c -- NIS+ backend for nsswitch "passwd" database */ #pragma ident "%Z%%M% %I% %E% SMI" @@ -42,7 +41,7 @@ getbynam(be, a) nisplus_backend_ptr_t be; void *a; { - nss_XbyY_args_t *argp = (nss_XbyY_args_t *) a; + nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a; return (_nss_nisplus_lookup(be, argp, PW_TAG_NAME, argp->key.name)); } @@ -52,39 +51,32 @@ getbyuid(be, a) nisplus_backend_ptr_t be; void *a; { - nss_XbyY_args_t *argp = (nss_XbyY_args_t *) a; + nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a; char uidstr[12]; /* More than enough */ - sprintf(uidstr, "%d", argp->key.uid); + (void) snprintf(uidstr, 12, "%ld", argp->key.uid); return (_nss_nisplus_lookup(be, argp, PW_TAG_UID, uidstr)); } /* + * convert nisplus object into files format * place the results from the nis_object structure into argp->buf.result * Returns NSS_STR_PARSE_{SUCCESS, ERANGE, PARSE} - * - * This routine does not tolerate non-numeric or empty pw_uid or pw_gid. - * Nor empty name field. - * It will immediately flag a PARSE error and return. Returns a - * pointer-to-a-null in case of empty gecos, home_dir, or shell fields. */ /*ARGSUSED*/ static int -nis_object2ent(nobj, obj, argp) - int nobj; - nis_object *obj; - nss_XbyY_args_t *argp; +nis_object2str(nobj, obj, be, argp) + int nobj; + nis_object *obj; + nisplus_backend_ptr_t be; + nss_XbyY_args_t *argp; { - char *buffer, *limit, *val, *endnum, *nullstring; - int buflen = argp->buf.buflen; - struct passwd *pw; - struct entry_col *ecol; - int len; - - limit = argp->buf.buffer + buflen; - pw = (struct passwd *)argp->buf.result; - buffer = argp->buf.buffer; + char *buffer, *name, *uid, *gid, *gecos; + char *dir, *shell, *endnum; + int buflen, namelen, uidlen, gidlen, gecoslen; + int dirlen, shelllen; + struct entry_col *ecol; /* * If we got more than one nis_object, we just ignore object(s) @@ -101,126 +93,53 @@ nis_object2ent(nobj, obj, argp) } ecol = obj->EN_data.en_cols.en_cols_val; - /* - * pw_name: user name - */ - EC_SET(ecol, PW_NDX_NAME, len, val); - if (len < 2 || (*val == '\0')) - return (NSS_STR_PARSE_PARSE); - pw->pw_name = buffer; - buffer += len; - if (buffer >= limit) - return (NSS_STR_PARSE_ERANGE); - strcpy(pw->pw_name, val); - nullstring = (buffer - 1); + /* name: user name */ + __NISPLUS_GETCOL_OR_RETURN(ecol, PW_NDX_NAME, namelen, name); - /* - * pw_uid: user id - */ - EC_SET(ecol, PW_NDX_UID, len, val); - if (len < 2) { - return (NSS_STR_PARSE_PARSE); - } else { - pw->pw_uid = strtol(val, &endnum, 10); - if (*endnum != 0 || val == endnum) { - return (NSS_STR_PARSE_PARSE); - } - } + /* password field is 'x' */ - /* - * pw_passwd: user passwd. Do not HAVE to get this here - * because the caller would do a getspnam() anyway. - */ - EC_SET(ecol, PW_NDX_PASSWD, len, val); - if (len < 2) { - /* - * don't return NULL pointer, lot of stupid programs - * out there. - */ - pw->pw_passwd = nullstring; - } else { - pw->pw_passwd = buffer; - buffer += len; - if (buffer >= limit) - return (NSS_STR_PARSE_ERANGE); - strcpy(pw->pw_passwd, val); - } + /* uid: user id. Must be numeric */ + __NISPLUS_GETCOL_OR_RETURN(ecol, PW_NDX_UID, uidlen, uid); + (void) strtol(uid, &endnum, 10); + if (*endnum != 0 || uid == endnum) + return (NSS_STR_PARSE_PARSE); - /* - * pw_gid: user's primary group id. - */ - EC_SET(ecol, PW_NDX_GID, len, val); - if (len < 2) { + /* gid: primary group id. Must be numeric */ + __NISPLUS_GETCOL_OR_RETURN(ecol, PW_NDX_GID, gidlen, gid); + (void) strtol(gid, &endnum, 10); + if (*endnum != 0 || gid == endnum) return (NSS_STR_PARSE_PARSE); - } else { - pw->pw_gid = strtol(val, &endnum, 10); - if (*endnum != 0 || val == endnum) { - return (NSS_STR_PARSE_PARSE); - } - } - /* - * pw_gecos: user's real name. - */ - EC_SET(ecol, PW_NDX_GCOS, len, val); - if (len < 2) { - /* - * don't return NULL pointer, lot of stupid programs - * out there. - */ - pw->pw_gecos = nullstring; - } else { - pw->pw_gecos = buffer; - buffer += len; - if (buffer >= limit) - return (NSS_STR_PARSE_ERANGE); - strcpy(pw->pw_gecos, val); - } + /* gecos: user's real name */ + __NISPLUS_GETCOL_OR_EMPTY(ecol, PW_NDX_GCOS, gecoslen, gecos); - /* - * pw_dir: user's home directory - */ - EC_SET(ecol, PW_NDX_HOME, len, val); - if (len < 2) { - /* - * don't return NULL pointer, lot of stupid programs - * out there. - */ - pw->pw_dir = nullstring; - } else { - pw->pw_dir = buffer; - buffer += len; - if (buffer >= limit) - return (NSS_STR_PARSE_ERANGE); - strcpy(pw->pw_dir, val); - } + /* dir: user's home directory */ + __NISPLUS_GETCOL_OR_EMPTY(ecol, PW_NDX_HOME, dirlen, dir); - /* - * pw_shell: user's login shell - */ - EC_SET(ecol, PW_NDX_SHELL, len, val); - if (len < 2) { - /* - * don't return NULL pointer, lot of stupid programs - * out there. - */ - pw->pw_shell = nullstring; + /* shell: user's login shell */ + __NISPLUS_GETCOL_OR_EMPTY(ecol, PW_NDX_SHELL, shelllen, shell); + + buflen = namelen + uidlen + gidlen + gecoslen + + dirlen + shelllen + 8; + if (argp->buf.result != NULL) { + if ((be->buffer = calloc(1, buflen)) == NULL) + return (NSS_STR_PARSE_PARSE); + /* include trailing null in length */ + be->buflen = buflen; + buffer = be->buffer; } else { - pw->pw_shell = buffer; - buffer += len; - if (buffer >= limit) + if (buflen > argp->buf.buflen) return (NSS_STR_PARSE_ERANGE); - strcpy(pw->pw_shell, val); + buflen = argp->buf.buflen; + buffer = argp->buf.buffer; + (void) memset(buffer, 0, buflen); } - - /* - * pw_age and pw_comment shouldn't be used anymore, but various things - * (allegedly in.ftpd) merrily do strlen() on them anyway, so we - * keep the peace by returning a zero-length string instead of a - * null pointer. - */ - pw->pw_age = pw->pw_comment = nullstring; - + (void) snprintf(buffer, buflen, "%s:x:%s:%s:%s:%s:%s", + name, uid, gid, gecos, dir, shell); +#ifdef DEBUG + (void) fprintf(stdout, "passwd [%s]\n", buffer); + (void) fflush(stdout); +#endif /* DEBUG */ return (NSS_STR_PARSE_SUCCESS); } @@ -240,5 +159,5 @@ _nss_nisplus_passwd_constr(dummy1, dummy2, dummy3) { return (_nss_nisplus_constr(pw_ops, sizeof (pw_ops) / sizeof (pw_ops[0]), - PW_TBLNAME, nis_object2ent)); + PW_TBLNAME, nis_object2str)); } diff --git a/usr/src/lib/nsswitch/nisplus/common/getrpcent.c b/usr/src/lib/nsswitch/nisplus/common/getrpcent.c index aea3a5865d..0075a90fd9 100644 --- a/usr/src/lib/nsswitch/nisplus/common/getrpcent.c +++ b/usr/src/lib/nsswitch/nisplus/common/getrpcent.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,11 +19,11 @@ * CDDL HEADER END */ /* - * getrpcent.c - * - * Copyright (c) 1988-1992 Sun Microsystems Inc - * All Rights Reserved. - * + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +/* * nisplus/getrpcent.c -- NIS+ backend for nsswitch "rpc" database */ @@ -42,7 +41,7 @@ getbyname(be, a) nisplus_backend_ptr_t be; void *a; { - nss_XbyY_args_t *argp = (nss_XbyY_args_t *) a; + nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a; /* * Don't have to do anything for case-insensitivity; the NIS+ table @@ -56,74 +55,78 @@ getbynumber(be, a) nisplus_backend_ptr_t be; void *a; { - nss_XbyY_args_t *argp = (nss_XbyY_args_t *) a; + nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a; char numstr[12]; - sprintf(numstr, "%d", argp->key.number); + (void) snprintf(numstr, 12, "%d", argp->key.number); return (_nss_nisplus_lookup(be, argp, RPC_TAG_NUMBER, numstr)); } /* - * place the results from the nis_object structure into argp->buf.result + * Convert nisplus object into files format * Returns NSS_STR_PARSE_{SUCCESS, ERANGE, PARSE} */ static int -nis_object2ent(nobj, obj, argp) - int nobj; - nis_object *obj; - nss_XbyY_args_t *argp; +nis_object2str(nobj, obj, be, argp) + int nobj; + nis_object *obj; + nisplus_backend_ptr_t be; + nss_XbyY_args_t *argp; { - char *buffer, *limit, *val; - int buflen = argp->buf.buflen; - struct rpcent *rpc; - int len, ret; - struct entry_col *ecol; - - limit = argp->buf.buffer + buflen; - rpc = (struct rpcent *)argp->buf.result; - buffer = argp->buf.buffer; - - /* - * <-----buffer + buflen --------------> - * |-----------------|----------------| - * | pointers vector | aliases grow | - * | for aliases | | - * | this way -> | <- this way | - * |-----------------|----------------| - * - * - * ASSUME: name, aliases and number columns in NIS+ tables ARE - * null terminated. - * - * get cname and aliases - */ - - rpc->r_aliases = (char **) ROUND_UP(buffer, (sizeof (char **))); - if ((char *)rpc->r_aliases >= limit) { - return (NSS_STR_PARSE_ERANGE); + char *buffer, *linep, *limit; + char *cname, *number, *endnum; + int buflen, cnamelen, numberlen; + int stat; + struct entry_col *ecol; + + if (obj->zo_data.zo_type != NIS_ENTRY_OBJ || + obj->EN_data.en_cols.en_cols_len < RPC_COL) { + /* namespace/table/object is curdled */ + return (NSS_STR_PARSE_PARSE); } + ecol = obj->EN_data.en_cols.en_cols_val; - rpc->r_name = NULL; + buflen = argp->buf.buflen; + buffer = argp->buf.buffer; + (void) memset(buffer, 0, buflen); - /* - * Assume that CNAME is the first column and NAME the second. - */ - ret = netdb_aliases_from_nisobj(obj, nobj, NULL, - rpc->r_aliases, &limit, &(rpc->r_name), &len); - if (ret != NSS_STR_PARSE_SUCCESS) - return (ret); + /* cname */ + __NISPLUS_GETCOL_OR_RETURN(ecol, RPC_NDX_CNAME, + cnamelen, cname); - /* - * get program number from the first object - * - */ - ecol = obj->EN_data.en_cols.en_cols_val; - EC_SET(ecol, RPC_NDX_NUMBER, len, val); - if (len <= 0) + /* number */ + __NISPLUS_GETCOL_OR_RETURN(ecol, RPC_NDX_NUMBER, + numberlen, number); + (void) strtol(number, &endnum, 10); + if (*endnum != 0 || endnum == number) return (NSS_STR_PARSE_PARSE); - rpc->r_number = atoi(val); + if (cnamelen + numberlen + 2 > buflen) + return (NSS_STR_PARSE_ERANGE); + (void) snprintf(buffer, buflen, "%s %s", cname, number); + + linep = buffer + cnamelen + numberlen + 1; + limit = buffer + buflen; + + stat = nis_aliases_object2str(obj, nobj, cname, NULL, linep, limit); + if (stat != NSS_STR_PARSE_SUCCESS) + return (stat); + + if (argp->buf.result != NULL) { + /* + * Some front end marshallers may require the + * files formatted data in a distinct buffer + */ + if ((be->buffer = strdup(buffer)) == NULL) + return (NSS_STR_PARSE_PARSE); + be->buflen = strlen(buffer); + buffer = be->buffer; + } +#ifdef DEBUG + (void) fprintf(stdout, "rpc [%s]\n", buffer); + (void) fflush(stdout); +#endif /* DEBUG */ return (NSS_STR_PARSE_SUCCESS); } @@ -143,5 +146,5 @@ _nss_nisplus_rpc_constr(dummy1, dummy2, dummy3) { return (_nss_nisplus_constr(rpc_ops, sizeof (rpc_ops) / sizeof (rpc_ops[0]), - RPC_TBLNAME, nis_object2ent)); + RPC_TBLNAME, nis_object2str)); } diff --git a/usr/src/lib/nsswitch/nisplus/common/getservent.c b/usr/src/lib/nsswitch/nisplus/common/getservent.c index fc932dfdb6..b3138f8c1a 100644 --- a/usr/src/lib/nsswitch/nisplus/common/getservent.c +++ b/usr/src/lib/nsswitch/nisplus/common/getservent.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,11 +19,11 @@ * CDDL HEADER END */ /* - * getservent.c - * - * Copyright (c) 1988-1992 Sun Microsystems Inc - * All Rights Reserved. - * + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +/* * nisplus/getservent.c -- NIS+ backend for nsswitch "serv" database */ @@ -41,13 +40,13 @@ getbyname(be, a) nisplus_backend_ptr_t be; void *a; { - nss_XbyY_args_t *argp = (nss_XbyY_args_t *) a; + nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a; /* * Don't have to do anything for case-insensitivity; the NIS+ table * has the right flags enabled in the 'cname' and 'name' columns. * - * Make sure that nis_object2ent would cull out only those entries + * Make sure that nis_object2str would cull out only those entries * with the given protocol if it is non-NULL, or the first one it * finds in the nis_object if user supplied proto is NULL. */ @@ -60,124 +59,109 @@ getbyport(be, a) nisplus_backend_ptr_t be; void *a; { - nss_XbyY_args_t *argp = (nss_XbyY_args_t *) a; + nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a; char portstr[12]; /* - * Make sure that nis_object2ent would cull out only those entries + * Make sure that nis_object2str would cull out only those entries * with the given protocol if it is non-NULL, or the first one it * finds in the nis_object if user supplied proto is NULL. */ - sprintf(portstr, "%d", ntohs((u_short)argp->key.serv.serv.port)); + (void) snprintf(portstr, 12, "%d", + ntohs((ushort_t)argp->key.serv.serv.port)); return (_nss_nisplus_lookup(be, argp, SERV_TAG_PORT, portstr)); } /* - * place the results from the nis_object structure into argp->buf.result + * Convert nisplus object into files format * Returns NSS_STR_PARSE_{SUCCESS, ERANGE, PARSE} */ static int -nis_object2ent(nobj, obj, argp) - int nobj; - nis_object *obj; - nss_XbyY_args_t *argp; +nis_object2str(nobj, obj, be, argp) + int nobj; + nis_object *obj; + nisplus_backend_ptr_t be; + nss_XbyY_args_t *argp; { - char *buffer, *limit, *val; - int buflen = argp->buf.buflen; - struct servent *serv; - int len, ret; - struct entry_col *ecol; - const char *proto = argp->key.serv.proto; - int i; - - limit = argp->buf.buffer + buflen; - serv = (struct servent *)argp->buf.result; - buffer = argp->buf.buffer; + char *buffer, *linep, *limit; + char *cname, *port, *proto, *endnum; + int buflen, cnamelen, portlen, protolen; + const char *protokey; + int protokeylen, stat; + struct entry_col *ecol; - /* - * If the caller does not care about a specific protocol - * (udp or tcp usually), pick the one from the first nis_object - * and parse all the entries associated with only this protocol. - * NULL proto is also specified by getservent() functions. We - * end up doing extraneous work in the case. - */ - if (proto == NULL) { + protokey = argp->key.serv.proto; + protokeylen = (protokey) ? strlen(protokey) : 0; + for (; nobj > 0; obj++, nobj--) { if (obj->zo_data.zo_type != NIS_ENTRY_OBJ || obj->EN_data.en_cols.en_cols_len < SERV_COL) { + /* namespace/table/object is curdled */ return (NSS_STR_PARSE_PARSE); } ecol = obj->EN_data.en_cols.en_cols_val; - EC_SET(ecol, SERV_NDX_PROTO, len, proto); - if (len < 2) - return (NSS_STR_PARSE_PARSE); - } else { - len = strlen(proto) + 1; - } - /* - * Return (a copy of) proto in serv->s_proto - */ - if (buffer + len > limit) { - return (NSS_STR_PARSE_ERANGE); + + /* protocol */ + __NISPLUS_GETCOL_OR_RETURN(ecol, SERV_NDX_PROTO, + protolen, proto); + if (protokey != NULL) { + if (protolen != protokeylen || + strncasecmp(proto, protokey, protolen) != 0) + continue; + } + + /* + * If the caller does not care about a specific protocol + * (udp or tcp usually), pick the one from the first nis_object + * and parse all the entries associated with only this protocol. + * NULL proto is also specified by getservent() functions. We + * end up doing extraneous work in the case. + */ + break; } - memcpy(buffer, proto, len); - serv->s_proto = buffer; - buffer += len; - buflen -= len; - /* - * <-----buffer + buflen --------------> - * |-----------------|----------------| - * | pointers vector | aliases grow | - * | for aliases | | - * | this way -> | <- this way | - * |-----------------|----------------| - * - * - * ASSUME: name, aliases, proto and port columns in NIS+ tables ARE - * null terminated. - * - * get cname and aliases - */ + if (nobj <= 0) + return (NSS_STR_PARSE_PARSE); + + buflen = argp->buf.buflen; + buffer = argp->buf.buffer; + (void) memset(buffer, 0, buflen); + + /* cname */ + __NISPLUS_GETCOL_OR_RETURN(ecol, SERV_NDX_CNAME, cnamelen, cname); - serv->s_aliases = (char **) ROUND_UP(buffer, sizeof (char **)); - if ((char *)serv->s_aliases >= limit) { + /* port */ + __NISPLUS_GETCOL_OR_RETURN(ecol, SERV_NDX_PORT, portlen, port); + (void) strtol(port, &endnum, 10); + if (*endnum != 0 || endnum == port) + return (NSS_STR_PARSE_PARSE); + + if (cnamelen + portlen + protolen + 3 > buflen) return (NSS_STR_PARSE_ERANGE); - } + (void) snprintf(buffer, buflen, "%s %s/%s", cname, port, proto); - serv->s_name = NULL; + linep = buffer + cnamelen + portlen + protolen + 2; + limit = buffer + buflen; - /* - * Assume that CNAME is the first column and NAME the second. - */ - ret = netdb_aliases_from_nisobj(obj, nobj, proto, - serv->s_aliases, &limit, &(serv->s_name), &len); - if (ret != NSS_STR_PARSE_SUCCESS) - return (ret); + stat = nis_aliases_object2str(obj, nobj, cname, proto, linep, limit); + if (stat != NSS_STR_PARSE_SUCCESS) + return (stat); - /* - * Read port from the first object having the desired protocol. - * There is guaranteed to be at least one such object, or - * netdb_aliases_from_nisobj() wouldn't have returned SUCCESS. - */ - for (i = 0; i < nobj; i++) { - ecol = obj[i].EN_data.en_cols.en_cols_val; - EC_SET(ecol, SERV_NDX_PROTO, len, val); - if (len < 2) + if (argp->buf.result != NULL) { + /* + * Some front end marshallers may require the + * files formatted data in a distinct buffer + */ + if ((be->buffer = strdup(buffer)) == NULL) return (NSS_STR_PARSE_PARSE); - if (strcmp(proto, val) == 0) - break; + be->buflen = strlen(buffer); + buffer = be->buffer; } - if (i == nobj) { /* none found... can't happen, but what the heck */ - return (NSS_STR_PARSE_PARSE); - } - EC_SET(ecol, SERV_NDX_PORT, len, val); - if (len < 2) { - return (NSS_STR_PARSE_PARSE); - } - serv->s_port = htons((u_short)atoi(val)); - +#ifdef DEBUG + (void) fprintf(stdout, "services [%s]\n", buffer); + (void) fflush(stdout); +#endif /* DEBUG */ return (NSS_STR_PARSE_SUCCESS); } @@ -197,5 +181,5 @@ _nss_nisplus_services_constr(dummy1, dummy2, dummy3) { return (_nss_nisplus_constr(serv_ops, sizeof (serv_ops) / sizeof (serv_ops[0]), - SERV_TBLNAME, nis_object2ent)); + SERV_TBLNAME, nis_object2str)); } diff --git a/usr/src/lib/nsswitch/nisplus/common/getspent.c b/usr/src/lib/nsswitch/nisplus/common/getspent.c index 028a37ad98..dd246e3b76 100644 --- a/usr/src/lib/nsswitch/nisplus/common/getspent.c +++ b/usr/src/lib/nsswitch/nisplus/common/getspent.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,9 +19,11 @@ * CDDL HEADER END */ /* - * Copyright (c) 1988-1995 Sun Microsystems Inc - * All Rights Reserved. - * + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +/* * nisplus/getspent.c: implementations of getspnam(), getspent(), setspent(), * endspent() for NIS+. We keep the shadow information in a column * ("shadow") of the same table that stores vanilla passwd information. @@ -62,8 +63,8 @@ getbynam(be, a) nisplus_backend_ptr_t be; void *a; { - nss_XbyY_args_t *argp = (nss_XbyY_args_t *) a; - struct spwd *sp = (struct spwd *) argp->buf.result; + nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a; + struct spwd *sp = (struct spwd *)argp->buf.result; int buflen = argp->buf.buflen; nss_status_t status; const char *username; @@ -76,12 +77,17 @@ getbynam(be, a) _mutex_lock(&one_lane); /* - * There is a dirty little private protocol with the nis_object2ent() + * There is a dirty little private protocol with the nis_object2str() * routine below: it gives us back a uid in the argp->key.uid * field. Since "key" is a union, and we're using key.name, * we save/restore it in case anyone cares. + * + * NSS2: be->flag is used to indicate *NP* case since we + * may not have the shadow passwd available at this point + * if called by nscd's switch. */ username = argp->key.name; + be->flag = 0; status = _nss_nisplus_lookup(be, argp, PW_TAG_NAME, username); @@ -95,13 +101,13 @@ getbynam(be, a) /* fix for bugid 4301477 DELETED if (_thr_main() != -1) goto out; */ - if (!(status == NSS_SUCCESS && argp->returnval != 0 && - sp->sp_pwdp != 0 && strcmp(sp->sp_pwdp, "*NP*") == 0)) + if (status != NSS_SUCCESS || argp->returnval == 0 || be->flag == 0) goto out; /* Get our current euid and that of the entry */ orig_uid = geteuid(); entry_uid = argp->key.uid; + be->flag = 0; /* * If the entry uid differs from our own euid, set our euid to @@ -116,10 +122,10 @@ getbynam(be, a) * results. */ if (key_secretkey_is_set_g(0, 0) && - ((save_buf = (char *) malloc(buflen)) != 0)) { + ((save_buf = (char *)malloc(buflen)) != 0)) { /* Save the old results in case the new lookup fails */ - memcpy(save_buf, argp->buf.buffer, buflen); + (void) memcpy(save_buf, argp->buf.buffer, buflen); save_sp = *sp; /* Do the lookup (this time as the user). */ @@ -128,7 +134,8 @@ getbynam(be, a) /* If it failed, restore the old results */ if (status != NSS_SUCCESS) { - memcpy(argp->buf.buffer, save_buf, buflen); + (void) memcpy(argp->buf.buffer, save_buf, + buflen); *sp = save_sp; status = NSS_SUCCESS; } @@ -137,7 +144,7 @@ getbynam(be, a) } /* Set uid back */ - seteuid(orig_uid); + (void) seteuid(orig_uid); } out: @@ -154,24 +161,17 @@ out: */ /*ARGSUSED*/ static int -nis_object2ent(nobj, obj, argp) - int nobj; - nis_object *obj; - nss_XbyY_args_t *argp; +nis_object2str(nobj, obj, be, argp) + int nobj; + nis_object *obj; + nisplus_backend_ptr_t be; + nss_XbyY_args_t *argp; { - struct spwd *sp = (struct spwd *) argp->buf.result; - char *buffer = argp->buf.buffer; - int buflen = argp->buf.buflen; - char *limit = buffer + buflen; - - struct entry_col *ecol; - char *val; - int len; - - char *endnum; - uid_t uid; - char *p; - long x; + char *buffer, *name, *passwd, *shadow; + int buflen, namelen, passwdlen, shadowlen; + char *endnum, *uidstr; + int uidlen; + struct entry_col *ecol; /* * If we got more than one nis_object, we just ignore it. @@ -188,47 +188,16 @@ nis_object2ent(nobj, obj, argp) } ecol = obj->EN_data.en_cols.en_cols_val; - /* - * sp_namp: user name - */ - EC_SET(ecol, PW_NDX_NAME, len, val); - if (len < 2) - return (NSS_STR_PARSE_PARSE); - sp->sp_namp = buffer; - buffer += len; - if (buffer >= limit) - return (NSS_STR_PARSE_ERANGE); - strcpy(sp->sp_namp, val); + /* name: user name */ + __NISPLUS_GETCOL_OR_RETURN(ecol, PW_NDX_NAME, namelen, name); - /* - * sp_pwdp: password - */ - EC_SET(ecol, PW_NDX_PASSWD, len, val); - if (len < 2) { - /* - * don't return NULL pointer, lot of stupid programs - * out there. - */ - *buffer = '\0'; - sp->sp_pwdp = buffer++; - if (buffer >= limit) - return (NSS_STR_PARSE_ERANGE); - } else { - sp->sp_pwdp = buffer; - buffer += len; - if (buffer >= limit) - return (NSS_STR_PARSE_ERANGE); - strcpy(sp->sp_pwdp, val); - } + /* passwd */ + __NISPLUS_GETCOL_OR_EMPTY(ecol, PW_NDX_PASSWD, passwdlen, passwd); - /* - * get uid - */ - EC_SET(ecol, PW_NDX_UID, len, val); - if (len < 2) - return (NSS_STR_PARSE_PARSE); - uid = strtol(val, &endnum, 10); - if (*endnum != 0) + /* uid */ + __NISPLUS_GETCOL_OR_RETURN(ecol, PW_NDX_UID, uidlen, uidstr); + (void) strtol(uidstr, &endnum, 10); + if (*endnum != 0 || endnum == uidstr) return (NSS_STR_PARSE_PARSE); /* * See discussion of private protocol in getbynam() above. @@ -236,18 +205,8 @@ nis_object2ent(nobj, obj, argp) * _nss_nisplus_getent(), but that's OK -- when we're doing * enumerations we don't care what's in the argp->key union. */ - argp->key.uid = uid; - - /* - * Default values - */ - sp->sp_lstchg = -1; - sp->sp_min = -1; - sp->sp_max = -1; - sp->sp_warn = -1; - sp->sp_inact = -1; - sp->sp_expire = -1; - sp->sp_flag = 0; + if (strncmp(passwd, "*NP*", passwdlen) == 0) + be->flag = 1; /* * shadow information @@ -256,67 +215,28 @@ nis_object2ent(nobj, obj, argp) * with less than the desired number of ":" separated longs. * XXX - should we be more strict ? */ - EC_SET(ecol, PW_NDX_SHADOW, len, val); - - if (len < 2) - return (NSS_STR_PARSE_SUCCESS); - - /* - * Parse val for the aging fields (quickly, they might die) - */ - - limit = val + len; - p = val; - - x = strtol(p, &endnum, 10); - if (*endnum != ':' || endnum >= limit) - return (NSS_STR_PARSE_SUCCESS); - if (endnum != p) - sp->sp_lstchg = (int) x; - p = endnum + 1; - - x = strtol(p, &endnum, 10); - if (*endnum != ':' || endnum >= limit) - return (NSS_STR_PARSE_SUCCESS); - if (endnum != p) - sp->sp_min = (int) x; - p = endnum + 1; - - x = strtol(p, &endnum, 10); - if (*endnum != ':' || endnum >= limit) - return (NSS_STR_PARSE_SUCCESS); - if (endnum != p) - sp->sp_max = (int) x; - p = endnum + 1; - - x = strtol(p, &endnum, 10); - if (*endnum != ':' || endnum >= limit) - return (NSS_STR_PARSE_SUCCESS); - if (endnum != p) - sp->sp_warn = (int) x; - p = endnum + 1; - - x = strtol(p, &endnum, 10); - if (*endnum != ':' || endnum >= limit) - return (NSS_STR_PARSE_SUCCESS); - if (endnum != p) { - sp->sp_inact = (int) x; + __NISPLUS_GETCOL_OR_EMPTY(ecol, PW_NDX_SHADOW, shadowlen, shadow); + + buflen = namelen + passwdlen + shadowlen + 3; + if (argp->buf.result != NULL) { + if ((be->buffer = calloc(1, buflen)) == NULL) + return (NSS_STR_PARSE_PARSE); + /* exclude trailing null from length */ + be->buflen = buflen - 1; + buffer = be->buffer; + } else { + if (buflen > argp->buf.buflen) + return (NSS_STR_PARSE_ERANGE); + buflen = argp->buf.buflen; + buffer = argp->buf.buffer; + (void) memset(buffer, 0, buflen); } - p = endnum + 1; - - x = strtol(p, &endnum, 10); - if (*endnum != ':' || endnum >= limit) - return (NSS_STR_PARSE_SUCCESS); - if (endnum != p) - sp->sp_expire = (int) x; - p = endnum + 1; - - x = strtol(p, &endnum, 10); - if (*endnum != '\0' && *endnum != ':') - return (NSS_STR_PARSE_SUCCESS); - if (endnum != p) - sp->sp_flag = (int) x; - + (void) snprintf(buffer, buflen, "%s:%s:%s", + name, passwd, shadow); +#ifdef DEBUG + (void) fprintf(stdout, "shadow [%s]\n", buffer); + (void) fflush(stdout); +#endif /* DEBUG */ return (NSS_STR_PARSE_SUCCESS); } @@ -335,5 +255,5 @@ _nss_nisplus_shadow_constr(dummy1, dummy2, dummy3) { return (_nss_nisplus_constr(sp_ops, sizeof (sp_ops) / sizeof (sp_ops[0]), - PW_TBLNAME, nis_object2ent)); + PW_TBLNAME, nis_object2str)); } diff --git a/usr/src/lib/nsswitch/nisplus/common/getuserattr.c b/usr/src/lib/nsswitch/nisplus/common/getuserattr.c index 70b8a05e76..c6337373c7 100644 --- a/usr/src/lib/nsswitch/nisplus/common/getuserattr.c +++ b/usr/src/lib/nsswitch/nisplus/common/getuserattr.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,8 +19,8 @@ * CDDL HEADER END */ /* - * Copyright (c) 1999 by Sun Microsystems, Inc. - * All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. */ #pragma ident "%Z%%M% %I% %E% SMI" @@ -45,23 +44,20 @@ getbynam(nisplus_backend_ptr_t be, void *a) /* - * place the results from the nis_object structure into argp->buf.result * Returns NSS_STR_PARSE_{SUCCESS, ERANGE, PARSE} */ +/*ARGSUSED*/ static int -nis_object2userstr(int nobj, nis_object *obj, nss_XbyY_args_t *argp) +nis_object2userstr(int nobj, nis_object *obj, + nisplus_backend_ptr_t be, + nss_XbyY_args_t *argp) { - int len; - int buflen = argp->buf.buflen; - char *buffer, *limit, *val, *endnum, *nullstring; - char *empty = ""; - userstr_t *user; + char *buffer, *name, *qual, *res1, *res2; + char *attr; + int buflen, namelen, quallen, res1len; + int res2len, attrlen; struct entry_col *ecol; - limit = argp->buf.buffer + buflen; - user = (userstr_t *)argp->buf.result; - buffer = argp->buf.buffer; - /* * If we got more than one nis_object, we just ignore object(s) * except the first. Although it should never have happened. @@ -77,81 +73,42 @@ nis_object2userstr(int nobj, nis_object *obj, nss_XbyY_args_t *argp) } ecol = obj->EN_data.en_cols.en_cols_val; - /* - * userstr->name: user name - */ - EC_SET(ecol, USERATTR_NDX_NAME, len, val); - if (len < 1 || (*val == '\0')) { - val = empty; - } - user->name = buffer; - buffer += len; - if (buffer >= limit) { - return (NSS_STR_PARSE_ERANGE); - } - strcpy(user->name, val); - nullstring = (buffer - 1); - - /* - * userstr->qualifier: reserved for future use - */ - EC_SET(ecol, USERATTR_NDX_QUALIFIER, len, val); - if (len < 1 || (*val == '\0')) { - val = empty; - } - user->qualifier = buffer; - buffer += len; - if (buffer >= limit) { - return (NSS_STR_PARSE_ERANGE); - } - strcpy(user->qualifier, val); - nullstring = (buffer - 1); - - /* - * userstr->res1: reserved field 1 - */ - EC_SET(ecol, USERATTR_NDX_RES1, len, val); - if (len < 1 || (*val == '\0')) { - val = empty; + /* user name */ + __NISPLUS_GETCOL_OR_RETURN(ecol, USERATTR_NDX_NAME, namelen, name); + + /* qualifier: reserved for future use */ + __NISPLUS_GETCOL_OR_EMPTY(ecol, USERATTR_NDX_QUALIFIER, + quallen, qual); + + /* res1: reserved field 1 */ + __NISPLUS_GETCOL_OR_EMPTY(ecol, USERATTR_NDX_RES1, res1len, res1); + + /* userstr->res2: reserved field 2 */ + __NISPLUS_GETCOL_OR_EMPTY(ecol, USERATTR_NDX_RES2, res2len, res2); + + /* attrs: key-value pairs of attributes */ + __NISPLUS_GETCOL_OR_EMPTY(ecol, USERATTR_NDX_ATTR, attrlen, attr); + + buflen = namelen + quallen + res1len + res2len + attrlen + 5; + if (argp->buf.result != NULL) { + if ((be->buffer = calloc(1, buflen)) == NULL) + return (NSS_STR_PARSE_PARSE); + /* exclude trailing null from length */ + be->buflen = buflen - 1; + buffer = be->buffer; + } else { + if (buflen > argp->buf.buflen) + return (NSS_STR_PARSE_ERANGE); + buflen = argp->buf.buflen; + buffer = argp->buf.buffer; + (void) memset(buffer, 0, buflen); } - user->res1 = buffer; - buffer += len; - if (buffer >= limit) { - return (NSS_STR_PARSE_ERANGE); - } - strcpy(user->res1, val); - nullstring = (buffer - 1); - - /* - * userstr->res2: reserved field 2 - */ - EC_SET(ecol, USERATTR_NDX_RES2, len, val); - if (len < 1 || (*val == '\0')) { - val = empty; - } - user->res2 = buffer; - buffer += len; - if (buffer >= limit) { - return (NSS_STR_PARSE_ERANGE); - } - strcpy(user->res2, val); - nullstring = (buffer - 1); - - /* - * userstr->attrs: key-value pairs of attributes - */ - EC_SET(ecol, USERATTR_NDX_ATTR, len, val); - if (len < 1 || (*val == '\0')) { - val = empty; - } - user->attr = buffer; - buffer += len; - if (buffer >= limit) { - return (NSS_STR_PARSE_ERANGE); - } - strcpy(user->attr, val); - nullstring = (buffer - 1); - + (void) snprintf(buffer, buflen, "%s:%s:%s:%s:%s", + name, qual, res1, res2, attr); +#ifdef DEBUG + (void) fprintf(stdout, "userattr [%s]\n", buffer); + (void) fflush(stdout); +#endif /* DEBUG */ return (NSS_STR_PARSE_SUCCESS); } @@ -163,6 +120,7 @@ static nisplus_backend_op_t userattr_ops[] = { getbynam }; +/*ARGSUSED*/ nss_backend_t * _nss_nisplus_user_attr_constr(const char *dummy1, const char *dummy2, diff --git a/usr/src/lib/nsswitch/nisplus/common/netmasks.c b/usr/src/lib/nsswitch/nisplus/common/netmasks.c index 8e6ae5000c..308033514e 100644 --- a/usr/src/lib/nsswitch/nisplus/common/netmasks.c +++ b/usr/src/lib/nsswitch/nisplus/common/netmasks.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,10 +19,12 @@ * CDDL HEADER END */ /* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +/* * nisplus/netmasks.c -- "nisplus" backend for nsswitch "netmasks" database - * - * Copyright (c) 1996 Sun Microsystems Inc - * All Rights Reserved. */ #pragma ident "%Z%%M% %I% %E% SMI" @@ -35,6 +36,8 @@ * dotted internet notation. */ +#include <stdlib.h> +#include <strings.h> #include <sys/types.h> #include <sys/socket.h> #include <net/if.h> @@ -49,29 +52,27 @@ getbynet(be, a) nisplus_backend_ptr_t be; void *a; { - nss_XbyY_args_t *argp = (nss_XbyY_args_t *) a; + nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a; return (_nss_nisplus_lookup(be, argp, NETMASK_TAG_ADDR, argp->key.name)); } /* - * Place the resulting struct inaddr from the nis_object structure into - * argp->buf.result only if argp->buf.result is initialized (not NULL). - * + * Convert nisplus object to files format * Returns NSS_STR_PARSE_{SUCCESS, ERANGE, PARSE} */ /*ARGSUSED*/ static int -nis_object2ent(nobj, obj, argp) - int nobj; - nis_object *obj; - nss_XbyY_args_t *argp; +nis_object2str(nobj, obj, be, argp) + int nobj; + nis_object *obj; + nisplus_backend_ptr_t be; + nss_XbyY_args_t *argp; { - struct in_addr *mask = (struct in_addr *)argp->buf.result; - char *val; - struct in_addr addr; - struct entry_col *ecol; - int len; + char *mask; + int masklen; + struct in_addr addr; + struct entry_col *ecol; /* * If we got more than one nis_object, we just ignore it. @@ -89,17 +90,22 @@ nis_object2ent(nobj, obj, argp) ecol = obj->EN_data.en_cols.en_cols_val; /* getnetmaskbynet */ - if (mask) { - EC_SET(ecol, NETMASK_NDX_MASK, len, val); - if (len < 2) - return (NSS_STR_PARSE_PARSE); - /* addr is an IPv4 address, therefore will always be 32bits */ - addr.s_addr = inet_addr(val); - if (addr.s_addr == 0xffffffffL) - return (NSS_STR_PARSE_PARSE); - mask->s_addr = addr.s_addr; - } + __NISPLUS_GETCOL_OR_RETURN(ecol, NETMASK_NDX_MASK, masklen, mask); + /* addr is an IPv4 address, therefore will always be 32bits */ + addr.s_addr = inet_addr(mask); + if (addr.s_addr == INADDR_NONE) + return (NSS_STR_PARSE_PARSE); + + /* exclude trailing null from length */ + be->buflen = masklen; + if ((be->buffer = calloc(1, be->buflen + 1)) == NULL) + return (NSS_STR_PARSE_PARSE); + (void) strlcpy(be->buffer, mask, be->buflen + 1); +#ifdef DEBUG + (void) fprintf(stdout, "netmasks [%s]\n", be->buffer); + (void) fflush(stdout); +#endif /* DEBUG */ return (NSS_STR_PARSE_SUCCESS); } @@ -115,5 +121,5 @@ _nss_nisplus_netmasks_constr(dummy1, dummy2, dummy3) { return (_nss_nisplus_constr(netmasks_ops, sizeof (netmasks_ops) / sizeof (netmasks_ops[0]), NETMASK_TBLNAME, - nis_object2ent)); + nis_object2str)); } diff --git a/usr/src/lib/nsswitch/nisplus/common/nisplus_common.c b/usr/src/lib/nsswitch/nisplus/common/nisplus_common.c index 51ad628f68..eec3fa9ada 100644 --- a/usr/src/lib/nsswitch/nisplus/common/nisplus_common.c +++ b/usr/src/lib/nsswitch/nisplus/common/nisplus_common.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,8 +19,8 @@ * CDDL HEADER END */ /* - * Copyright (c) 1991-1999 by Sun Microsystems, Inc. - * All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. */ /* @@ -35,6 +34,7 @@ #include "nisplus_common.h" #include "nisplus_tables.h" #include <string.h> +#include <strings.h> #include <stdlib.h> #include <arpa/inet.h> #include <rpcsvc/nislib.h> @@ -43,7 +43,7 @@ #define ORGDIR2 ".org_dir." #define ORGDIRLEN 7 -extern u_int __nis_force_hard_lookups; +extern uint_t __nis_force_hard_lookups; extern int inet_pton(int, const char *, void *); static nss_status_t @@ -58,11 +58,13 @@ switch_err(nis_res) case NIS_SUCCESS: case NIS_S_SUCCESS: case NIS_CBRESULTS: + errno = 0; return (NSS_SUCCESS); case NIS_NOTFOUND: case NIS_PARTIAL: case NIS_NOSUCHNAME: + errno = 0; return (NSS_NOTFOUND); case NIS_NAMEUNREACHABLE: @@ -82,18 +84,21 @@ _nss_nisplus_list(name, extra_flags, res_p) nis_result **res_p; { *res_p = nis_list((char *)name, NIS_LIST_COMMON | extra_flags | - __nis_force_hard_lookups, 0, 0); + __nis_force_hard_lookups, 0, 0); return (switch_err(*res_p)); } -nss_status_t +static nss_status_t process_val(args, be, result) - nss_XbyY_args_t *args; + nss_XbyY_args_t *args; nisplus_backend_t *be; - nis_result *result; + nis_result *result; { nss_status_t res; - int parsestat; + int parsestat; + + args->returnval = NULL; + args->returnlen = 0; if ((res = switch_err(result)) != NSS_SUCCESS) { return (res); @@ -101,21 +106,71 @@ process_val(args, be, result) if (NIS_RES_OBJECT(result) == 0) { return (NSS_NOTFOUND); } - parsestat = (be->obj2ent)(NIS_RES_NUMOBJ(result), - NIS_RES_OBJECT(result), args); + parsestat = (be->obj2str)(NIS_RES_NUMOBJ(result), + NIS_RES_OBJECT(result), be, args); + if (parsestat != NSS_STR_PARSE_SUCCESS) + goto fail; + + /* + * If called by nscd's switch engine, the data + * is available in args->buf.buffer and there is + * no need to marshall it. + * + * Note for some dbs like ethers, the obj2str() + * routine will always put the NFF data in + * be->buffer because we cannot determine if + * we are inside nscd or inside the application. + */ + if (args->buf.result == NULL && be->buffer == NULL) { + args->returnval = args->buf.buffer; + if (args->buf.buffer != NULL) + args->returnlen = strlen(args->buf.buffer); + return (NSS_SUCCESS); + } + + /* + * If the data is in be->buffer it needs + * to be marshalled. + */ + if (args->str2ent == NULL) { + parsestat = NSS_STR_PARSE_PARSE; + goto fail; + } + parsestat = (*args->str2ent)(be->buffer, + be->buflen, + args->buf.result, + args->buf.buffer, + args->buf.buflen); if (parsestat == NSS_STR_PARSE_SUCCESS) { + if (be->buffer != NULL) { + free(be->buffer); + be->buffer = NULL; + be->buflen = 0; + } args->returnval = args->buf.result; - res = NSS_SUCCESS; - } else if (parsestat == NSS_STR_PARSE_ERANGE) { - args->returnval = 0; + if (args->buf.result != NULL) + args->returnlen = 1; + else if (args->buf.buffer != NULL) { + args->returnval = args->buf.buffer; + args->returnlen = strlen(args->buf.buffer); + } + return (NSS_SUCCESS); + } + +fail: + if (be->buffer != NULL) { + free(be->buffer); + be->buffer = NULL; + be->buflen = 0; + } + if (parsestat == NSS_STR_PARSE_ERANGE) { args->erange = 1; /* We won't find this otherwise, anyway */ - res = NSS_NOTFOUND; + return (NSS_NOTFOUND); } else if (parsestat == NSS_STR_PARSE_PARSE) { - args->returnval = 0; - res = NSS_NOTFOUND; + return (NSS_NOTFOUND); } - return (res); + return (NSS_UNAVAIL); } nss_status_t @@ -141,7 +196,7 @@ _nss_nisplus_lookup(be, argp, column_name, keyname) /* * Assumes that "keyname" is a null-terminated string. */ - sprintf(namebuf, "[%s=%s]%s", column_name, keyname, + (void) snprintf(namebuf, BUFSIZ, "[%s=%s]%s", column_name, keyname, be->table_name); r = nis_list(namebuf, NIS_LIST_COMMON | USE_DGRAM | __nis_force_hard_lookups, 0, 0); @@ -194,23 +249,23 @@ _nss_nisplus_expand_lookup(be, argp, column_name, keyname, table) (directory[0] == '.' && directory[1] == '\0')) { return (0); } - sprintf(namebuf, "[%s=", column_name); + (void) snprintf(namebuf, sizeof (namebuf), "[%s=", column_name); if (strcmp(column_name, HOST_TAG_NAME) == 0) { p = strchr(keyname, '.'); if (p == 0) { - strcat(namebuf, keyname); + (void) strlcat(namebuf, keyname, sizeof (namebuf)); } else { - strncat(namebuf, keyname, p - keyname); + (void) strncat(namebuf, keyname, p - keyname); } } else { - strcat(namebuf, keyname); + (void) strlcat(namebuf, keyname, sizeof (namebuf)); p = 0; } - strcat(namebuf, "]"); - strcat(namebuf, table); - strcat(namebuf, ORGDIR1); + (void) strlcat(namebuf, "]", sizeof (namebuf)); + (void) strlcat(namebuf, table, sizeof (namebuf)); + (void) strlcat(namebuf, ORGDIR1, sizeof (namebuf)); if (p != 0) { - strcat(namebuf, p); + (void) strlcat(namebuf, p, sizeof (namebuf)); } r = nis_list(namebuf, EXPAND_NAME | USE_DGRAM | NIS_LIST_COMMON | __nis_force_hard_lookups, 0, 0); @@ -222,45 +277,36 @@ _nss_nisplus_expand_lookup(be, argp, column_name, keyname, table) } nss_backend_t * -_nss_nisplus_constr(ops, n_ops, tblname, obj2ent) +_nss_nisplus_constr(ops, n_ops, tblname, obj2str) nisplus_backend_op_t ops[]; int n_ops; - const char *tblname; /* (Unqualified) name of */ - /* NIS+ table */ - nisplus_obj2ent_func obj2ent; + const char *tblname; /* (Unqualified) name of NIS+ table */ + nisplus_obj2str_func obj2str; { const char *directory = nis_local_directory(); nisplus_backend_t *be; #ifdef DEBUG -fprintf(stderr, "Constructor called\n"); + (void) fprintf(stdout, "Constructor called\n"); #endif /* DEBUG */ if (directory == 0 || (directory[0] == '.' && directory[1] == '\0') || - (be = (nisplus_backend_t *)malloc(sizeof (*be))) == 0) { - return (0); + (be = (nisplus_backend_t *)calloc(1, sizeof (*be))) == 0) { + return (0); } - be->ops = ops; - be->n_ops = n_ops; - - be->directory = directory; - if ((be->table_name = (char *)malloc - (strlen(tblname) + ORGDIRLEN + strlen(directory) + 3)) == 0) + be->ops = ops; + be->n_ops = n_ops; + be->directory = directory; + if ((be->table_name = (char *)malloc + (strlen(tblname) + ORGDIRLEN + strlen(directory) + 3)) == 0) { + free(be); return (0); - strcpy(be->table_name, tblname); - strcat(be->table_name, ORGDIR2); - strcat(be->table_name, directory); - - be->obj2ent = obj2ent; - be->cursor.no.n_bytes = 0; - be->cursor.no.n_len = 0; - be->cursor.max_len = 0; - - /* this indicates that the path_list stuff is not initialized */ - be->path_list = 0; - be->table_path = 0; - be->path_index = 0; + } + (void) strcpy(be->table_name, tblname); + (void) strcat(be->table_name, ORGDIR2); + (void) strcat(be->table_name, directory); + be->obj2str = obj2str; be->path_count = -1; return ((nss_backend_t *)be); @@ -274,10 +320,13 @@ _nss_nisplus_destr(be, dummy) { if (be != 0) { /* === Should change to invoke ops[ENDENT] ? */ - _nss_nisplus_endent(be, 0); + (void) _nss_nisplus_endent(be, 0); if (be->table_name != 0) { free(be->table_name); } + if (be->buffer != NULL) { + free(be->buffer); + } free(be); } return (NSS_SUCCESS); /* In case anyone is dumb enough to check */ @@ -310,7 +359,8 @@ nis_cursor_set_next(be, from) be->cursor.no.n_bytes = (char *)malloc(be->cursor.max_len); } - memcpy(be->cursor.no.n_bytes, from->n_bytes, from->n_len); + (void) memcpy(be->cursor.no.n_bytes, from->n_bytes, + from->n_len); } be->cursor.no.n_len = from->n_len; } @@ -367,6 +417,9 @@ _nss_nisplus_setent(be, dummy) nis_result *res; nis_object *tobj; + be->buffer = NULL; + be->buflen = 0; + be->flag = 0; if (be->path_list == 0) { res = nis_lookup(be->table_name, NIS_LIST_COMMON | __nis_force_hard_lookups); @@ -393,9 +446,9 @@ _nss_nisplus_setent(be, dummy) nis_freeresult(res); return (NSS_UNAVAIL); } - strcpy(table_name, tobj->zo_name); - strcat(table_name, "."); - strcat(table_name, tobj->zo_domain); + (void) strcpy(table_name, tobj->zo_name); + (void) strcat(table_name, "."); + (void) strcat(table_name, tobj->zo_domain); /* save table path */ table_path = res->objects.objects_val[0].TA_data.ta_path; @@ -423,7 +476,7 @@ _nss_nisplus_setent(be, dummy) be->path_list[0] = table_name; be->path_count = __nis_parse_path(be->table_path, - &be->path_list[1], n - 1); + &be->path_list[1], (int)(n - 1)); be->path_count++; /* for entry at index 0 */ } be->path_index = 0; @@ -452,232 +505,73 @@ _nss_nisplus_endent(be, dummy) free(be->path_list[0]); free(be->path_list); } + if (be->buffer != NULL) { + free(be->buffer); + be->buffer = NULL; + be->buflen = 0; + } + be->flag = 0; be->table_path = 0; be->path_list = 0; be->path_index = 0; be->path_count = -1; - be->cursor.no.n_len = 0; - be->cursor.max_len = 0; + be->cursor.no.n_len = 0; + be->cursor.max_len = 0; return (NSS_SUCCESS); } - -/* - * returns NSS_STR_PARSE_PARSE if no aliases found. - * - * Overly loaded interface. Trying to do to many things using one common - * code. Main purpose is to extract cname and aliases from NIS+ entry object(s) - * for netdb databases: hosts, networks, protocols, rpc and services. - * - * hosts have always been special. We have special case code to deal with - * multiple addresses. cnamep is overloaded to indicate this special case, - * when NULL, otherwise it is set to point to the cname field in the caller's - * structure to be populated. - * - * services are weird since they sometimes use 1-1/2 keys, e.g. name and proto - * or port and proto. The NIS+ services table also has an extra column. The - * special argument, proto, when non-NULL, serves the purpose of indicating - * that we are parsing a services entry, and have specified the protocol which - * must be used for screening. It is also non-NULL, and set to the proto field - * of the first NIS+ entry by nis_obj2ent(), in case of enumeration on - * services, and getservbyname/port calls where caller used a null proto, - * which implies the caller can accept "any" protocol with the matching - * name/port. The proto argument is NULL for all non-services searches. - */ int -netdb_aliases_from_nisobj(obj, nobj, proto, alias_list, aliaspp, cnamep, count) - /* IN */ - nis_object *obj; - int nobj; - const char *proto; - /* IN-OUT */ - char **alias_list; /* beginning of the buffer and alias vector */ - char **aliaspp; /* end of the buffer + 1 */ - char **cnamep; - /* OUT */ - int *count; /* number of distinct aliases/address found */ -{ - return (__netdb_aliases_from_nisobj(obj, nobj, proto, alias_list, - aliaspp, cnamep, count, 0)); -} +nis_aliases_object2str(nis_object *obj, int nobj, + const char *cname, const char *protokey, + char *linep, char *limit) { + char *p, *name, *proto; + int cnamelen, namelen, protolen, protokeylen; + struct entry_col *ecol; -int -__netdb_aliases_from_nisobj(obj, nobj, proto, alias_list, aliaspp, cnamep, - count, af_type) - /* IN */ - nis_object *obj; - int nobj; - const char *proto; - int af_type; /* address family for host mapping only */ - /* IN-OUT */ - char **alias_list; /* beginning of the buffer and alias vector */ - char **aliaspp; /* end of the buffer + 1 */ - char **cnamep; - /* OUT */ - int *count; /* number of distinct aliases/address found */ -{ - int isaddr = (cnamep == 0); + cnamelen = strlen(cname); + protokeylen = (protokey) ? strlen(protokey) : 0; - *count = 0; - if ((char *)alias_list >= *aliaspp) { - /* - * Input condition not met. We must get a contiguous - * area (alias_list, *aliaspp - 1). - */ - return (NSS_STR_PARSE_PARSE); - } - for (/* */; nobj > 0; obj++, nobj--) { - /* - * in every iteration, pull the - * address/alias/cname, copy it, set and update - * the pointers vector if it is not a duplicate. - */ - struct entry_col *ecol; - char *val; - int len; + /* + * process remaining entries + */ + for (; nobj > 0; --nobj, obj++) { + /* object should be non-null */ + if (obj == NULL) + return (NSS_STR_PARSE_PARSE); if (obj->zo_data.zo_type != NIS_ENTRY_OBJ || - (obj->EN_data.en_cols.en_cols_len < NETDB_COL)) { + obj->EN_data.en_cols.en_cols_len < NETDB_COL) { /* namespace/table/object is curdled */ return (NSS_STR_PARSE_PARSE); } ecol = obj->EN_data.en_cols.en_cols_val; - /* - * ASSUMPTION: cname and name field in NIS+ tables are - * null terminated and the len includes the null char. - */ - if (isaddr) { - EC_SET(ecol, HOST_NDX_ADDR, len, val); - } else { + if (protokey != NULL) { + /* skip if protocols doesn't match for services */ + __NISPLUS_GETCOL_OR_RETURN(ecol, SERV_NDX_PROTO, + protolen, proto); + if (protolen != protokeylen || + strncasecmp(proto, protokey, protolen) != 0) + continue; + } - if (proto) { - /* - * indicates we screen for a desired proto - * in the case of getservbyname/port() - * with a non-null proto arg - */ - EC_SET(ecol, SERV_NDX_PROTO, len, val); - if (len < 2) - return (NSS_STR_PARSE_PARSE); - if (strcmp(proto, val) != 0) - continue; /* ignore this entry */ - } + __NISPLUS_GETCOL_OR_CONTINUE(ecol, NETDB_NDX_NAME, + namelen, name); - if (*cnamep == 0) { - /* canonical name, hasn't been set so far */ - EC_SET(ecol, NETDB_NDX_CNAME, len, val); - if (len < 2) - return (NSS_STR_PARSE_PARSE); - *aliaspp -= len; - if (*aliaspp <= - (char *)&(alias_list[*count + 1])) { - /* - * Has to be room for the pointer to - * the name we're about to add, as - * well as the final NULL ptr. - */ - return (NSS_STR_PARSE_ERANGE); - } - memcpy(*aliaspp, val, len); - *cnamep = *aliaspp; - } - EC_SET(ecol, NETDB_NDX_NAME, len, val); - } - if (len > 0) { - int i; - struct in6_addr addr6; - struct in_addr addr; - - if (isaddr) { /* special case for host addresses */ - - if (af_type == AF_INET) { - if (inet_pton(AF_INET, val, - (void *) &addr) != 1) - continue; /* skip entry */ - } else { - /* - * We now allow IPv4 and IPv6 addrs in the - * ipnodes table. If found, convert it to a - * v4 mapped IPv6 address. - */ - if (inet_pton(AF_INET6, val, - (void *) &addr6) != 1) { - if (inet_pton(AF_INET, val, - (void *) &addr) != 1) { - continue; - /* skip entry */ - } else { - IN6_INADDR_TO_V4MAPPED( - &addr, - &addr6); - } - } - } - - /* Check for duplicate address */ - for (i = 0; i < *count; i++) { - if (af_type == AF_INET) { - if (memcmp(alias_list[i], &addr, - sizeof (struct in_addr)) - == 0) { - goto next_obj; - } - } else { - if (memcmp(alias_list[i], - &addr6, - sizeof (struct in6_addr)) - == 0) { - goto next_obj; - } - } - } - /* - * Hope nobody treats an h_addr_list[i] as a - * null terminated string. We are not storing - * that here. - */ - if (af_type == AF_INET) - *aliaspp -= sizeof (struct in_addr); - else - *aliaspp -= sizeof (struct in6_addr); - } else { - /* Check for duplicate alias */ - for (i = 0; i < *count; i++) { - if (strcmp(alias_list[i], val) == 0) { - goto next_obj; - } - } - *aliaspp -= len; - } - alias_list[i] = *aliaspp; - if (*aliaspp <= (char *)&(alias_list[i + 1])) { - /* - * Has to be room for the pointer to - * the address we're about to add, as - * well as the final NULL ptr. - */ + /* + * add the "name" to the list if it doesn't + * match the "cname" + */ + if (cnamelen != namelen || + strncmp(name, cname, namelen) != 0) { + p = linep + 1 + namelen; + if (p >= limit) return (NSS_STR_PARSE_ERANGE); - } - if (isaddr) { - if (af_type == AF_INET) - memcpy(alias_list[i], (char *)&addr, - sizeof (struct in_addr)); - else - memcpy(alias_list[i], (char *)&addr6, - sizeof (struct in6_addr)); - } else { - memcpy(*aliaspp, val, len); - } - ++(*count); + (void) snprintf(linep, (size_t)(limit - linep), + " %s", name); + linep = p; } - next_obj: - ; } - alias_list[*count] = NULL; - if (*count == 0) - return (NSS_STR_PARSE_PARSE); - else - return (NSS_STR_PARSE_SUCCESS); + return (NSS_STR_PARSE_SUCCESS); } diff --git a/usr/src/lib/nsswitch/nisplus/common/nisplus_common.h b/usr/src/lib/nsswitch/nisplus/common/nisplus_common.h index 6e8bfac6ff..5c6ae11c8c 100644 --- a/usr/src/lib/nsswitch/nisplus/common/nisplus_common.h +++ b/usr/src/lib/nsswitch/nisplus/common/nisplus_common.h @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -38,97 +37,101 @@ /* * We want these flags turned on in all nis_list() requests that we perform; - * other flags (USE_DGRAM, EXPAND_NAME) are only wanted for some requests. + * other flags (USE_DGRAM, EXPAND_NAME) are only wanted for some requests. */ #define NIS_LIST_COMMON (FOLLOW_LINKS | FOLLOW_PATH) typedef struct nisplus_backend *nisplus_backend_ptr_t; typedef nss_status_t (*nisplus_backend_op_t)(nisplus_backend_ptr_t, void *); -typedef int (*nisplus_obj2ent_func)(int nobjs, - nis_object *obj, - nss_XbyY_args_t *arg); +typedef int (*nisplus_obj2str_func)(int nobjs, nis_object *obj, + nisplus_backend_ptr_t be, + nss_XbyY_args_t *arg); struct nisplus_backend { nisplus_backend_op_t *ops; nss_dbop_t n_ops; - const char *directory; /* fully qualified directory */ - /* name */ - char *table_name; + const char *directory; /* fully qualified directory */ + /* * table_name is fully qualified (includes org_dir and * directory name) and cached here using one time malloc. */ - nisplus_obj2ent_func obj2ent; + char *table_name; + + nisplus_obj2str_func obj2str; struct { - struct netobj no; - u_int max_len; - } cursor; + struct netobj no; + uint_t max_len; + } cursor; - /* + /* * Fields for handling table paths during enumeration. * The path_list field is allocated dynamically because * it is kind of big and most applications don't do * enumeration. */ - char *table_path; - int path_index; - int path_count; - nis_name *path_list; + char *table_path; + int path_index; + int path_count; + nis_name *path_list; + + /* + * Internal fields to support NSS2 format + */ + char *buffer; + int buflen; + uint8_t flag; }; typedef struct nisplus_backend nisplus_backend_t; #if defined(__STDC__) -extern nss_backend_t *_nss_nisplus_constr (nisplus_backend_op_t *ops, - int n_ops, - const char *rdn, - nisplus_obj2ent_func func); -extern nss_status_t _nss_nisplus_destr (nisplus_backend_ptr_t, +extern nss_backend_t *_nss_nisplus_constr(nisplus_backend_op_t *ops, + int n_ops, + const char *rdn, + nisplus_obj2str_func func); +extern nss_status_t _nss_nisplus_destr(nisplus_backend_ptr_t, void *dummy); -extern nss_status_t _nss_nisplus_setent (nisplus_backend_ptr_t, +extern nss_status_t _nss_nisplus_setent(nisplus_backend_ptr_t, void *dummy); -extern nss_status_t _nss_nisplus_endent (nisplus_backend_ptr_t, +extern nss_status_t _nss_nisplus_endent(nisplus_backend_ptr_t, void *dummy); -extern nss_status_t _nss_nisplus_getent (nisplus_backend_ptr_t, - void *arg); -extern nss_status_t _nss_nisplus_lookup (nisplus_backend_ptr_t, +extern nss_status_t _nss_nisplus_getent(nisplus_backend_ptr_t, + void *arg); +extern nss_status_t _nss_nisplus_lookup(nisplus_backend_ptr_t, nss_XbyY_args_t *arg, - const char *key, - const char *val); -extern nss_status_t _nss_nisplus_expand_lookup (nisplus_backend_ptr_t, + const char *key, + const char *val); +extern nss_status_t _nss_nisplus_expand_lookup(nisplus_backend_ptr_t, nss_XbyY_args_t *arg, - const char *key, - const char *val, - const char *table); -extern int netdb_aliases_from_nisobj(nis_object *obj, - int nobj, - const char *proto, - char **alias_list, - char **aliaspp, - char **cnamep, - int *count); -extern int __netdb_aliases_from_nisobj(nis_object *obj, + const char *key, + const char *val, + const char *table); +extern int nis_aliases_object2str(nis_object *obj, int nobj, + const char *cname, const char *proto, - char **alias_list, - char **aliaspp, - char **cnamep, - int *count, - int af_type); + char *linep, + char *limit); +extern int nis_hosts_object2str(int nobj, + nis_object *obj, + nisplus_backend_ptr_t be, + nss_XbyY_args_t *argp, + int af); #else /* __STDC__ */ extern nss_backend_t *_nss_nisplus_constr(); -extern nss_status_t _nss_nisplus_destr (); +extern nss_status_t _nss_nisplus_destr(); extern nss_status_t _nss_nisplus_setent(); extern nss_status_t _nss_nisplus_endent(); extern nss_status_t _nss_nisplus_getent(); -extern nss_status_t _nss_nisplus_lookup (); +extern nss_status_t _nss_nisplus_lookup(); extern nss_status_t _nss_nisplus__expand_lookup(); extern int build_aliases_from_nisobj(); #endif /* __STDC__ */ /* Lower-level interface */ -extern nss_status_t _nss_nisplus_list(const char *name, - int extra_flags, - nis_result **r); +extern nss_status_t _nss_nisplus_list(const char *name, + int extra_flags, + nis_result **r); extern int __nis_parse_path(); extern int _thr_main(void); extern int __nss2herrno(); diff --git a/usr/src/lib/nsswitch/nisplus/common/nisplus_tables.h b/usr/src/lib/nsswitch/nisplus/common/nisplus_tables.h index 7f3823e985..a9f53fd00c 100644 --- a/usr/src/lib/nsswitch/nisplus/common/nisplus_tables.h +++ b/usr/src/lib/nsswitch/nisplus/common/nisplus_tables.h @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,10 +19,12 @@ * CDDL HEADER END */ /* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +/* * nisplus_tables.h - * - * Copyright (c) 1988-2000 by Sun Microsystems, Inc. - * All rights reserved. */ #ifndef _NISPLUS_TABLES_H @@ -302,6 +303,30 @@ extern "C" { #define EC_SET(ecp, ndx, l, v) \ ((l) = EC_LEN(ecp, ndx), (v) = EC_VAL(ecp, ndx)) +#define __NISPLUS_GETCOL_OR_EMPTY(ecp, ndx, l, v) \ + EC_SET(ecp, ndx, l, v);\ + if (l < 2) {\ + (v) = "";\ + (l) = 1;\ + } else {\ + l--;\ + } + +#define __NISPLUS_GETCOL_OR_RETURN(ecp, ndx, l, v) \ + EC_SET(ecp, ndx, l, v);\ + if (l < 2) {\ + return (NSS_STR_PARSE_PARSE);\ + } else {\ + l--;\ + } + +#define __NISPLUS_GETCOL_OR_CONTINUE(ecp, ndx, l, v) \ + EC_SET(ecp, ndx, l, v);\ + if (l < 2) {\ + continue;\ + } else {\ + l--;\ + } #ifdef __cplusplus } #endif diff --git a/usr/src/lib/nsswitch/user/Makefile.com b/usr/src/lib/nsswitch/user/Makefile.com index c51cc34604..df1c209dfc 100644 --- a/usr/src/lib/nsswitch/user/Makefile.com +++ b/usr/src/lib/nsswitch/user/Makefile.com @@ -39,6 +39,8 @@ include ../../Makefile.com include ../../../Makefile.rootfs CPPFLAGS += -I../../../common/inc +LINTFLAGS += -erroff=E_GLOBAL_COULD_BE_STATIC2 -erroff=E_FUNC_SET_NOT_USED +LINTFLAGS64 += -erroff=E_GLOBAL_COULD_BE_STATIC2 -erroff=E_FUNC_SET_NOT_USED DYNLIB1 = nss_user.so$(VERS) diff --git a/usr/src/lib/nsswitch/user/common/getprinter.c b/usr/src/lib/nsswitch/user/common/getprinter.c index 25bc1ac49d..7e62b69724 100644 --- a/usr/src/lib/nsswitch/user/common/getprinter.c +++ b/usr/src/lib/nsswitch/user/common/getprinter.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * * "user" backend for nsswitch "printers" database. This module implements @@ -95,6 +94,7 @@ _nss_user_printers_convert(char *entry, nss_XbyY_args_t *args) * backends don't include it in the data passed to the backend. For this * reason, we process everything here and don't bother calling the backend. */ +/*ARGSUSED*/ static nss_status_t _nss_user_XY_printers(be, args, filter) user_backend_ptr_t be; @@ -107,7 +107,6 @@ _nss_user_XY_printers(be, args, filter) */ { nss_status_t res; - int parsestat; int namelen; if (be->buf == 0 && @@ -119,12 +118,12 @@ _nss_user_XY_printers(be, args, filter) res = NSS_NOTFOUND; namelen = strlen(args->key.name); + /*CONSTCOND*/ while (1) { char *instr = be->buf; char *p, *limit; int linelen; int found = 0; - char *key, *value; /* * _nss_user_read_line does process the '\' that are used @@ -194,6 +193,7 @@ getent(be, a) res = NSS_NOTFOUND; + /*CONSTCOND*/ while (1) { char *instr = be->buf; int linelen; @@ -240,6 +240,7 @@ static user_backend_op_t printers_ops[] = { getbyname }; +/*ARGSUSED*/ nss_backend_t * _nss_user_printers_constr(dummy1, dummy2, dummy3) const char *dummy1, *dummy2, *dummy3; @@ -248,7 +249,7 @@ _nss_user_printers_constr(dummy1, dummy2, dummy3) if ((home = getenv("HOME")) == NULL) home = ""; - snprintf(path, sizeof (path), "%s/.printers", home); + (void) snprintf(path, sizeof (path), "%s/.printers", home); return (_nss_user_constr(printers_ops, sizeof (printers_ops) / sizeof (printers_ops[0]), diff --git a/usr/src/lib/nsswitch/user/common/user_common.c b/usr/src/lib/nsswitch/user/common/user_common.c index 1a52140be3..76a7aa9872 100644 --- a/usr/src/lib/nsswitch/user/common/user_common.c +++ b/usr/src/lib/nsswitch/user/common/user_common.c @@ -43,6 +43,7 @@ #include <sys/stat.h> #include <string.h> +/*ARGSUSED*/ nss_status_t _nss_user_setent(be, dummy) user_backend_ptr_t be; @@ -62,13 +63,14 @@ _nss_user_setent(be, dummy) return (NSS_SUCCESS); } +/*ARGSUSED*/ nss_status_t _nss_user_endent(be, dummy) user_backend_ptr_t be; void *dummy; { if (be->f != 0) { - fclose(be->f); + (void) fclose(be->f); be->f = 0; } if (be->buf != 0) { @@ -98,6 +100,7 @@ _nss_user_read_line(f, buffer, buflen) int linelen; /* 1st unused slot in buffer */ int c; + /*CONSTCOND*/ while (1) { linelen = 0; while (linelen < buflen - 1) { /* "- 1" saves room for \n\0 */ @@ -168,6 +171,7 @@ _nss_user_XY_all(be, args, netdb, filter, check) res = NSS_NOTFOUND; + /*CONSTCOND*/ while (1) { char *instr = be->buf; int linelen; @@ -250,6 +254,7 @@ _nss_user_XY_all(be, args, netdb, filter, check) } +/*ARGSUSED*/ nss_status_t _nss_user_destr(be, dummy) user_backend_ptr_t be; @@ -257,7 +262,7 @@ _nss_user_destr(be, dummy) { if (be != 0) { if (be->f != 0) { - _nss_user_endent(be, 0); + (void) _nss_user_endent(be, 0); } free((char *)be->filename); free(be); diff --git a/usr/src/lib/print/libprint/common/nss_printer.c b/usr/src/lib/print/libprint/common/nss_printer.c index f84fbb3b64..252e4e6297 100644 --- a/usr/src/lib/print/libprint/common/nss_printer.c +++ b/usr/src/lib/print/libprint/common/nss_printer.c @@ -64,7 +64,7 @@ _nss_initf_printers(p) /* regular behaviour */ p->name = NSS_DBNAM_PRINTERS; /* "printers" */ p->default_config = NSS_DEFCONF_PRINTERS; - initialized = 1; + /* keep reinitializing as needed was: initialized = 1; */ } syslog(LOG_DEBUG, "database: %s, services: %s", (p->name ? p->name : "NULL"), |