diff options
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"), |