diff options
author | Michen Chang <Michen.Chang@Sun.COM> | 2009-02-13 18:18:56 -0800 |
---|---|---|
committer | Michen Chang <Michen.Chang@Sun.COM> | 2009-02-13 18:18:56 -0800 |
commit | dd1104fbe0f0f41434502f335b9f0b34999f771c (patch) | |
tree | 57c95d64bc40cebf2b145329e1f49e811352d502 /usr/src/lib/libsldap | |
parent | d68ef20e3fe871e73146fc684d29d335521dcd99 (diff) | |
download | illumos-joyent-dd1104fbe0f0f41434502f335b9f0b34999f771c.tar.gz |
PSARC 2008/745 nss_ldap shadowAccount support
6715171 nss_ldap and passwdutil do not support all shadowAccount attributes
6797378 'ldapaddent -d passwd' does not print 'x' for the password field
6783712 libsldap fails to set correct version number for V1 profile
Diffstat (limited to 'usr/src/lib/libsldap')
-rw-r--r-- | usr/src/lib/libsldap/common/mapfile-vers | 34 | ||||
-rw-r--r-- | usr/src/lib/libsldap/common/ns_cache_door.h | 14 | ||||
-rw-r--r-- | usr/src/lib/libsldap/common/ns_config.c | 79 | ||||
-rw-r--r-- | usr/src/lib/libsldap/common/ns_confmgr.c | 56 | ||||
-rw-r--r-- | usr/src/lib/libsldap/common/ns_internal.h | 11 | ||||
-rw-r--r-- | usr/src/lib/libsldap/common/ns_sldap.h | 27 | ||||
-rw-r--r-- | usr/src/lib/libsldap/common/ns_writes.c | 308 |
7 files changed, 473 insertions, 56 deletions
diff --git a/usr/src/lib/libsldap/common/mapfile-vers b/usr/src/lib/libsldap/common/mapfile-vers index f58a9328d4..e043513adf 100644 --- a/usr/src/lib/libsldap/common/mapfile-vers +++ b/usr/src/lib/libsldap/common/mapfile-vers @@ -22,19 +22,6 @@ # Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # - -# -# MAPFILE HEADER START -# -# WARNING: STOP NOW. DO NOT MODIFY THIS FILE. -# Object versioning must comply with the rules detailed in -# -# usr/src/lib/README.mapfiles -# -# You should not be making modifications here until you've read the most current -# copy of that file. If you need help, contact a gatekeeper for guidance. -# -# MAPFILE HEADER END # # There really should be only one SUNWprivate version. @@ -42,22 +29,23 @@ SUNWprivate_1.1 { global: - __ns_ldap_initStandalone; - __ns_ldap_getConnectionInfoFromDUA; - __ns_ldap_getRootDSE; - __ns_ldap_pingOfflineServers; __ns_ldap_cancelStandalone; - __ns_ldap_initAuth; + __ns_ldap_check_all_preq; + __ns_ldap_check_dns_preq; + __ns_ldap_check_gssapi_preq; __ns_ldap_getAcctMgmt; - __s_api_get_canonical_name; __ns_ldap_getAttrStruct; + __ns_ldap_getConnectionInfoFromDUA; + __ns_ldap_getRootDSE; + __ns_ldap_initAuth; + __ns_ldap_initStandalone; + __ns_ldap_is_shadow_update_enabled; + __ns_ldap_pingOfflineServers; __ns_ldap_self_gssapi_config; __ns_ldap_self_gssapi_only_set; - __ns_ldap_check_dns_preq; - __ns_ldap_check_gssapi_preq; - __ns_ldap_check_all_preq; - __s_api_ip2hostname; + __s_api_get_canonical_name; __s_api_hostname2ip; + __s_api_ip2hostname; } SUNWprivate_1.0; SUNWprivate_1.0 { diff --git a/usr/src/lib/libsldap/common/ns_cache_door.h b/usr/src/lib/libsldap/common/ns_cache_door.h index 391394cbe7..52599534af 100644 --- a/usr/src/lib/libsldap/common/ns_cache_door.h +++ b/usr/src/lib/libsldap/common/ns_cache_door.h @@ -19,15 +19,13 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #ifndef _NS_CACHE_DOOR_H #define _NS_CACHE_DOOR_H -#pragma ident "%Z%%M% %I% %E% SMI" - /* * Definitions for client side of doors-based ldap caching */ @@ -96,6 +94,13 @@ typedef struct ldap_config_out { char config_str[sizeof (int)]; /* real size is data_size */ } ldap_config_out_t; +typedef struct ldap_admin_mod_result { + uint32_t ns_err; /* ns_ldap error code */ + uint32_t status; /* error status */ + uint32_t msg_size; /* length of error message */ + char msg[sizeof (int)]; /* real size is msg_size */ +} ldap_admin_mod_result_t; + /* * structure returned by server for all calls */ @@ -116,6 +121,7 @@ typedef struct { ldap_strlist_t strlist; ldap_config_out_t config_str; ldap_get_change_out_t changes; + ldap_admin_mod_result_t admin_result; } ldap_u; } ldap_return_t; @@ -187,6 +193,8 @@ typedef union { #define GETCACHESTAT 24 /* Configuration change or server status change notification */ #define GETSTATUSCHANGE 25 + /* perform admin modify via ldap_cachemgr */ +#define ADMINMODIFY 26 /* * GETLDAPSERVER request flags diff --git a/usr/src/lib/libsldap/common/ns_config.c b/usr/src/lib/libsldap/common/ns_config.c index 2046a46bad..1a7a21bfee 100644 --- a/usr/src/lib/libsldap/common/ns_config.c +++ b/usr/src/lib/libsldap/common/ns_config.c @@ -19,12 +19,10 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ -#pragma ident "%Z%%M% %I% %E% SMI" - /* * libsldap - library side configuration components * Routines to manage the config structure @@ -202,6 +200,12 @@ static ns_enum_map ns_pref_enum[] = { { -1, NULL }, }; +static ns_enum_map ns_shadow_update_enum[] = { + { ENUM2INT(NS_LDAP_ENABLE_SHADOW_UPDATE_FALSE), "FALSE" }, + { ENUM2INT(NS_LDAP_ENABLE_SHADOW_UPDATE_TRUE), "TRUE" }, + { -1, NULL }, +}; + static int ns_def_auth_v1[] = { ENUM2INT(NS_LDAP_EA_NONE), 0 @@ -392,11 +396,31 @@ static ns_default_config defconfig[] = { NULL, /* not defined in the Profile */ { CHARPTR, 0, NULL }, __s_val_binddn, NULL }, + {"NS_LDAP_BINDPASSWD", NS_LDAP_BINDPASSWD_P, CREDCONFIG, CHARPTR, TRUE, NS_LDAP_V2, NULL, /* not defined in the Profile */ { CHARPTR, 0, NULL }, __s_val_bindpw, NULL }, + + {"NS_LDAP_ENABLE_SHADOW_UPDATE", NS_LDAP_ENABLE_SHADOW_UPDATE_P, + CREDCONFIG, INT, TRUE, NS_LDAP_V2, + NULL, /* not defined in the Profile */ + { INT, 0, INT2VOIDPTR(NS_LDAP_ENABLE_SHADOW_UPDATE_FALSE) }, + NULL, ns_shadow_update_enum }, + + {"NS_LDAP_ADMIN_BINDDN", NS_LDAP_ADMIN_BINDDN_P, + CREDCONFIG, CHARPTR, TRUE, NS_LDAP_V2, + NULL, /* not defined in the Profile */ + { CHARPTR, 0, NULL }, + __s_val_binddn, NULL }, + + {"NS_LDAP_ADMIN_BINDPASSWD", NS_LDAP_ADMIN_BINDPASSWD_P, + CREDCONFIG, CHARPTR, TRUE, NS_LDAP_V2, + NULL, /* not defined in the Profile */ + { CHARPTR, 0, NULL }, + __s_val_bindpw, NULL }, + {"NS_LDAP_EXP", NS_LDAP_EXP_P, SERVERCONFIG, TIMET, TRUE, NS_LDAP_V2, NULL, /* initialized by code to time+NS_LDAP_CACHETTL */ @@ -601,6 +625,9 @@ __s_get_enum_value(ns_config_t *ptr, char *value, ParamIndexType i) case NS_LDAP_PREF_ONLY_P: mapp = &ns_pref_enum[0]; break; + case NS_LDAP_ENABLE_SHADOW_UPDATE_P: + mapp = &ns_shadow_update_enum[0]; + break; case NS_LDAP_CREDENTIAL_LEVEL_P: if (ptr->version == NS_LDAP_V1) return (-1); @@ -713,6 +740,21 @@ __s_get_searchref_name(ns_config_t *ptr, SearchRef_t type) return ("Unknown SearchRef_t type specified"); } +char * +__s_get_shadowupdate_name(enableShadowUpdate_t type) +{ + register ns_enum_map *mapp; + + mapp = &ns_shadow_update_enum[0]; + + for (; mapp->name != NULL; mapp++) { + if (type == INT2SHADOWUPDATENUM(mapp->value)) { + return (mapp->name); + } + } + return ("Unknown enableShadowUpdate_t type specified"); +} + static char * __s_get_credlvl_name(ns_config_t *ptr, CredLevel_t type) { @@ -1486,6 +1528,8 @@ verify_value(ns_config_t *cfg, char *name, char *value, char *errstr) case NS_LDAP_CERT_NICKNAME_P: case NS_LDAP_BINDDN_P: case NS_LDAP_BINDPASSWD_P: + case NS_LDAP_ADMIN_BINDDN_P: + case NS_LDAP_ADMIN_BINDPASSWD_P: case NS_LDAP_DOMAIN_P: case NS_LDAP_SEARCH_BASEDN_P: case NS_LDAP_SEARCH_TIME_P: @@ -1648,6 +1692,7 @@ __ns_ldap_setParamValue(ns_config_t *ptr, const ParamIndexType type, case NS_LDAP_PREF_ONLY_P: case NS_LDAP_SEARCH_REF_P: case NS_LDAP_SEARCH_SCOPE_P: + case NS_LDAP_ENABLE_SHADOW_UPDATE_P: i = __s_get_enum_value(ptr, cp, def->index); if (i < 0) { (void) snprintf(errstr, sizeof (errstr), @@ -2615,7 +2660,8 @@ __ns_ldap_setParamValue(ns_config_t *ptr, const ParamIndexType type, * * Init NS_LDAP_EXP_P here when CACHETTL is updated */ - if (type == NS_LDAP_BINDPASSWD_P) { + if (type == NS_LDAP_BINDPASSWD_P || + type == NS_LDAP_ADMIN_BINDPASSWD_P) { cp = conf.ns_pc; cp2 = evalue((char *)cp); conf.ns_pc = cp2; @@ -3219,6 +3265,11 @@ __s_api_strValue(ns_config_t *cfg, char *str, __s_get_scope_name(cfg, (ScopeType_t)ptr->ns_i)); break; + case NS_LDAP_ENABLE_SHADOW_UPDATE_P: + (void) strlcat(buf, + __s_get_shadowupdate_name( + (enableShadowUpdate_t)ptr->ns_i), bufsz); + break; default: (void) snprintf(ibuf, sizeof (ibuf), "%d", ptr->ns_i); @@ -3730,15 +3781,21 @@ static int __s_val_binddn(ParamIndexType i, ns_default_config *def, ns_param_t *param, char *errbuf) { + char *dntype; + if (param && param->ns_ptype == CHARPTR && - i == NS_LDAP_BINDDN_P && + (i == NS_LDAP_BINDDN_P || i == NS_LDAP_ADMIN_BINDDN_P) && ((param->ns_pc == NULL) || ((*(param->ns_pc) != '\0') && (strchr(param->ns_pc, '=') != NULL)))) { return (NS_SUCCESS); } + if (i == NS_LDAP_BINDDN_P) + dntype = "proxy"; + else + dntype = "update"; (void) snprintf(errbuf, MAXERROR, - gettext("NULL or invalid proxy bind DN")); + gettext("NULL or invalid %s bind DN"), dntype); return (NS_PARSE_ERR); } @@ -3751,14 +3808,20 @@ static int __s_val_bindpw(ParamIndexType i, ns_default_config *def, ns_param_t *param, char *errbuf) { + char *pwtype; + if (param && param->ns_ptype == CHARPTR && - i == NS_LDAP_BINDPASSWD_P && + (i == NS_LDAP_BINDPASSWD_P || i == NS_LDAP_ADMIN_BINDPASSWD_P) && ((param->ns_pc == NULL) || (*(param->ns_pc) != '\0'))) { return (NS_SUCCESS); } + if (i == NS_LDAP_BINDPASSWD_P) + pwtype = "proxy"; + else + pwtype = "admin"; (void) snprintf(errbuf, MAXERROR, - gettext("NULL proxy bind password")); + gettext("NULL %s bind password"), pwtype); return (NS_PARSE_ERR); } diff --git a/usr/src/lib/libsldap/common/ns_confmgr.c b/usr/src/lib/libsldap/common/ns_confmgr.c index 1fd58aac6f..a96f186ded 100644 --- a/usr/src/lib/libsldap/common/ns_confmgr.c +++ b/usr/src/lib/libsldap/common/ns_confmgr.c @@ -19,12 +19,10 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ -#pragma ident "%Z%%M% %I% %E% SMI" - /* libsldap - cachemgr side configuration components */ #include <stdio.h> @@ -332,6 +330,15 @@ __s_api_create_config_door_str(char *config, ns_ldap_error_t **errorp) __s_api_destroy_config(configStruct); return (NULL); } + } else if (strcasecmp(attrVal, + _PROFILE1_OBJECTCLASS) == 0) { + if (__ns_ldap_setParamValue(configStruct, + NS_LDAP_FILE_VERSION_P, + NS_LDAP_VERSION_1, + errorp) != NS_LDAP_SUCCESS) { + __s_api_destroy_config(configStruct); + return (NULL); + } } continue; } @@ -490,6 +497,10 @@ __ns_ldap_LoadDoorInfo(LineBuf *configinfo, char *domainname, ns_config_t *new) } (void) memset((char *)configinfo, 0, sizeof (LineBuf)); for (i = 0; i <= NS_LDAP_MAX_PIT_P; i++) { + /* the credential for shadow update is not to be exposed */ + if (i == NS_LDAP_ADMIN_BINDDN_P || + i == NS_LDAP_ADMIN_BINDPASSWD_P) + continue; str = __s_api_strValue(ptr, string, sizeof (string), i, NS_DOOR_FMT); if (str == NULL) @@ -628,10 +639,15 @@ __ns_ldap_DumpLdif(char *filename) if (str == NULL) continue; /* - * don't dump binddn, bind password, or cert path as they - * are not part of version 2 profiles + * don't dump binddn, bind password, admin binddn, admin + * bind password, enableShadowUpdate flag, or cert path + * as they are not part of version 2 profiles */ - if ((i != NS_LDAP_BINDDN_P) && (i != NS_LDAP_BINDPASSWD_P) && + if ((i != NS_LDAP_BINDDN_P) && + (i != NS_LDAP_BINDPASSWD_P) && + (i != NS_LDAP_ADMIN_BINDDN_P) && + (i != NS_LDAP_ADMIN_BINDPASSWD_P) && + (i != NS_LDAP_ENABLE_SHADOW_UPDATE_P) && (i != NS_LDAP_HOST_CERTPATH_P)) (void) fprintf(fp, "%s\n", str); if (str != (char *)&string[0]) { @@ -922,6 +938,7 @@ __ns_ldap_make_config(ns_ldap_result_t *result) } } if (ptr->version != NS_LDAP_V1) { + ParamIndexType i; if (curr_ptr->paramList[NS_LDAP_BINDDN_P].ns_ptype == CHARPTR) { (void) __ns_ldap_setParamValue(ptr, NS_LDAP_BINDDN_P, curr_ptr->paramList[NS_LDAP_BINDDN_P].ns_pc, @@ -934,6 +951,28 @@ __ns_ldap_make_config(ns_ldap_result_t *result) curr_ptr->paramList[NS_LDAP_BINDPASSWD_P].ns_pc, &error); } + i = NS_LDAP_ENABLE_SHADOW_UPDATE_P; + if (curr_ptr->paramList[i].ns_ptype == INT) { + char *val; + val = __s_get_shadowupdate_name( + curr_ptr->paramList[i].ns_i); + (void) __ns_ldap_setParamValue(ptr, i, val, &error); + } + if (curr_ptr->paramList[NS_LDAP_ADMIN_BINDDN_P].ns_ptype == + CHARPTR) { + (void) __ns_ldap_setParamValue(ptr, + NS_LDAP_ADMIN_BINDDN_P, + curr_ptr->paramList[NS_LDAP_ADMIN_BINDDN_P].ns_pc, + &error); + } + if (curr_ptr->paramList[NS_LDAP_ADMIN_BINDPASSWD_P].ns_ptype == + CHARPTR) { + (void) __ns_ldap_setParamValue(ptr, + NS_LDAP_ADMIN_BINDPASSWD_P, + curr_ptr-> + paramList[NS_LDAP_ADMIN_BINDPASSWD_P].ns_pc, + &error); + } if (curr_ptr->paramList[NS_LDAP_HOST_CERTPATH_P].ns_ptype == CHARPTR) { (void) __ns_ldap_setParamValue(ptr, @@ -1065,6 +1104,11 @@ __ns_ldap_print_config(int verbose) if ((i == NS_LDAP_CACHETTL_P) && (ptr->version == NS_LDAP_V1)) continue; + /* the credential for shadow update is not to be exposed */ + if (i == NS_LDAP_ADMIN_BINDDN_P || + i == NS_LDAP_ADMIN_BINDPASSWD_P) + continue; + str = __s_api_strValue(ptr, string, BUFSIZ, i, NS_FILE_FMT); if (str == NULL) continue; diff --git a/usr/src/lib/libsldap/common/ns_internal.h b/usr/src/lib/libsldap/common/ns_internal.h index a7dbf4e6de..9adba43565 100644 --- a/usr/src/lib/libsldap/common/ns_internal.h +++ b/usr/src/lib/libsldap/common/ns_internal.h @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -27,8 +27,6 @@ #ifndef _NS_INTERNAL_H #define _NS_INTERNAL_H -#pragma ident "%Z%%M% %I% %E% SMI" - #ifdef __cplusplus extern "C" { #endif @@ -118,6 +116,11 @@ extern "C" { /* max rdn length in conversion routines used by __ns_ldap_addTypedEntry() */ #define RDNSIZE 256 +/* + * special service used by ldap_cachemgr to indicate a shadow update + * is to be done with the credential of the administrator identity + */ +#define NS_ADMIN_SHADOW_UPDATE "shadow__admin_update" /* Phase 1 profile information */ #define _PROFILE1_OBJECTCLASS "SolarisNamingProfile" @@ -316,6 +319,7 @@ typedef struct ns_enum_map { #define INT2SECENUM(x) ((TlsType_t)(x)) #define INT2PREFONLYENUM(x) ((PrefOnly_t)(x)) #define INT2CREDLEVELENUM(x) ((CredLevel_t)(x)) +#define INT2SHADOWUPDATENUM(x) ((enableShadowUpdate_t)(x)) #define INT2LDAPRETURN(x) ((ns_ldap_return_code)(x)) #define INT2CONFIGRETURN(x) ((ns_ldap_config_return_code)(x)) @@ -736,6 +740,7 @@ char *__s_get_security_name(ns_config_t *ptr, TlsType_t type); char *__s_get_scope_name(ns_config_t *ptr, ScopeType_t type); char *__s_get_pref_name(PrefOnly_t type); char *__s_get_searchref_name(ns_config_t *ptr, SearchRef_t type); +char *__s_get_shadowupdate_name(enableShadowUpdate_t type); char *__s_get_hostcertpath(void); void __s_api_free_sessionPool(); int __s_api_requestServer(const char *request, const char *server, diff --git a/usr/src/lib/libsldap/common/ns_sldap.h b/usr/src/lib/libsldap/common/ns_sldap.h index af288c5cf2..f8bb420019 100644 --- a/usr/src/lib/libsldap/common/ns_sldap.h +++ b/usr/src/lib/libsldap/common/ns_sldap.h @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -84,6 +84,13 @@ typedef enum ScopeType { #define NS_LDAP_NOT_CVT_DN 0x2000 /* + * NS_LDAP_UPDATE_SHADOW is for a privileged caller of the + * __ns_ldap_repAttr() to update the shadow database on the + * LDAP server. + */ +#define NS_LDAP_UPDATE_SHADOW 0x4000 + +/* * Authentication Information */ typedef enum CredLevel { @@ -126,6 +133,11 @@ typedef enum PrefOnly { NS_LDAP_PREF_TRUE = 1 } PrefOnly_t; +typedef enum enableShadowUpdate { + NS_LDAP_ENABLE_SHADOW_UPDATE_FALSE = 0, + NS_LDAP_ENABLE_SHADOW_UPDATE_TRUE = 1 +} enableShadowUpdate_t; + typedef struct UnixCred { char *userID; /* Unix ID number */ char *passwd; /* password */ @@ -199,12 +211,15 @@ typedef enum { NS_LDAP_SERVICE_AUTH_METHOD_P = 25, NS_LDAP_SERVICE_CRED_LEVEL_P = 26, NS_LDAP_HOST_CERTPATH_P = 27, + NS_LDAP_ENABLE_SHADOW_UPDATE_P = 28, + NS_LDAP_ADMIN_BINDDN_P = 29, + NS_LDAP_ADMIN_BINDPASSWD_P = 30, /* * The following entry (max ParamIndexType) is an internal * placeholder. It must be the last (and highest value) * entry in this eNum. Please update accordingly. */ - NS_LDAP_MAX_PIT_P = 28 + NS_LDAP_MAX_PIT_P = 31 } ParamIndexType; @@ -484,6 +499,11 @@ typedef struct ns_ldap_objectclass_map { char *mappedOC; /* mapped objectclass */ } ns_ldap_objectclass_map_t; +/* + * Value of the userPassword attribute representing NO Unix password + */ +#define NS_LDAP_NO_UNIX_PASSWORD "<NO UNIX PASSWORD>" + /* Opaque handle for batch API */ typedef struct ns_ldap_list_batch ns_ldap_list_batch_t; @@ -872,6 +892,9 @@ int __ns_ldap_getParamType( int __ns_ldap_getAcctMgmt( const char *user, AcctUsableResponse_t *acctResp); + +boolean_t __ns_ldap_is_shadow_update_enabled(); + void __ns_ldap_self_gssapi_only_set( int flag); diff --git a/usr/src/lib/libsldap/common/ns_writes.c b/usr/src/lib/libsldap/common/ns_writes.c index 3abbefd829..14727d8a6b 100644 --- a/usr/src/lib/libsldap/common/ns_writes.c +++ b/usr/src/lib/libsldap/common/ns_writes.c @@ -19,12 +19,10 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ -#pragma ident "%Z%%M% %I% %E% SMI" - #include <stdio.h> #include <sys/types.h> #include <stdlib.h> @@ -38,10 +36,13 @@ #include <lber.h> #include <ldap.h> #include <syslog.h> +#include <stddef.h> +#include <sys/mman.h> #include "ns_sldap.h" #include "ns_internal.h" #include "ns_connmgmt.h" +#include "ns_cache_door.h" /* Additional headers for addTypedEntry Conversion routines */ #include <pwd.h> @@ -60,7 +61,8 @@ #include <sys/tsol/tndb.h> #include <tsol/label.h> - +static int send_to_cachemgr(const char *, + ns_ldap_attr_t **, ns_ldap_error_t **); /* * If the rdn is a mapped attr: * return NS_LDAP_SUCCESS and a new_dn. @@ -1038,8 +1040,8 @@ write_state_machine( errmsg = NULL; } - (void) sprintf(errstr, - gettext(ldap_err2string(Errno))); + (void) snprintf(errstr, sizeof (errstr), + "%s", ldap_err2string(Errno)); err = strdup(errstr); if (pwd_status != NS_PASSWD_GOOD) { MKERROR_PWD_MGMT(*errorp, Errno, err, @@ -1157,6 +1159,89 @@ __ns_ldap_delAttr( return (rc); } +/* Retrieve the admin bind password from the configuration, if allowed. */ +static int +get_admin_passwd(ns_cred_t *cred, ns_ldap_error_t **errorp) +{ + void **paramVal = NULL; + int rc, ldaprc; + char *modparamVal = NULL; + + /* + * For GSSAPI/Kerberos, host credential is used, no need to get + * admin bind password + */ + if (cred->auth.saslmech == NS_LDAP_SASL_GSSAPI) + return (NS_LDAP_SUCCESS); + + /* + * Retrieve admin bind password. + * The admin bind password is available + * only in the ldap_cachemgr process as + * they are not exposed outside of that + * process. + */ + paramVal = NULL; + if ((ldaprc = __ns_ldap_getParam(NS_LDAP_ADMIN_BINDPASSWD_P, + ¶mVal, errorp)) != NS_LDAP_SUCCESS) + return (ldaprc); + if (paramVal == NULL || *paramVal == NULL) { + rc = NS_LDAP_CONFIG; + *errorp = __s_api_make_error(NS_CONFIG_NODEFAULT, + gettext("Admin bind password not configured")); + if (*errorp == NULL) + rc = NS_LDAP_MEMORY; + return (rc); + } + modparamVal = dvalue((char *)*paramVal); + (void) memset(*paramVal, 0, strlen((char *)*paramVal)); + (void) __ns_ldap_freeParam(¶mVal); + if (modparamVal == NULL || *((char *)modparamVal) == '\0') { + if (modparamVal != NULL) + free(modparamVal); + rc = NS_LDAP_CONFIG; + *errorp = __s_api_make_error(NS_CONFIG_SYNTAX, + gettext("bind password not valid")); + if (*errorp == NULL) + rc = NS_LDAP_MEMORY; + return (rc); + } + + cred->cred.unix_cred.passwd = modparamVal; + return (NS_LDAP_SUCCESS); +} + +boolean_t +__ns_ldap_is_shadow_update_enabled() { + + int **enable_shadow = NULL; + + if (__ns_ldap_getParam(NS_LDAP_ENABLE_SHADOW_UPDATE_P, + (void ***)&enable_shadow, NULL) != NS_LDAP_SUCCESS) { + return (B_FALSE); + } + if ((enable_shadow != NULL && *enable_shadow != NULL) && + (*enable_shadow[0] == NS_LDAP_ENABLE_SHADOW_UPDATE_TRUE)) { + (void) __ns_ldap_freeParam((void ***)&enable_shadow); + return (B_TRUE); + } + if (enable_shadow != NULL) + (void) __ns_ldap_freeParam((void ***)&enable_shadow); + return (B_FALSE); +} + +/* + * __ns_ldap_repAttr modifies ldap attributes of the 'dn' entry stored + * on the LDAP server. 'service' indicates the type of database entries + * to modify. When the Native LDAP client is configured with 'shadow update + * enabled', Shadowshadow(4) entries can only be modified by privileged users. + * Such users use the NS_LDAP_UPDATE_SHADOW flag to indicate the call is + * for such a shadow(4) update, which would be forwarded to ldap_cachemgr + * for performing the LDAP modify operation. ldap_cachemgr would call + * this function again and use the special service NS_ADMIN_SHADOW_UPDATE + * to identify itself, so that admin credential would be obtained and + * the actual LDAP modify operation be done. + */ /*ARGSUSED*/ int __ns_ldap_repAttr( @@ -1169,6 +1254,8 @@ __ns_ldap_repAttr( { LDAPMod **mods; int rc = 0; + boolean_t priv; + boolean_t shadow_update_enabled = B_FALSE; #ifdef DEBUG (void) fprintf(stderr, "__ns_ldap_repAttr START\n"); @@ -1176,13 +1263,59 @@ __ns_ldap_repAttr( *errorp = NULL; /* Sanity check */ - if ((attr == NULL) || (*attr == NULL) || - (dn == NULL) || (cred == NULL)) + if (attr == NULL || *attr == NULL || dn == NULL) + return (NS_LDAP_INVALID_PARAM); + + /* Privileged shadow modify? */ + if ((flags & NS_LDAP_UPDATE_SHADOW) != 0 && + strcmp(service, "shadow") == 0) { + + /* Shadow update enabled ? If not, error out */ + shadow_update_enabled = __ns_ldap_is_shadow_update_enabled(); + if (!shadow_update_enabled) { + *errorp = __s_api_make_error(NS_CONFIG_NOTALLOW, + gettext("Shadow Update is not enabled")); + return (NS_LDAP_CONFIG); + } + + /* privileged shadow modify requires euid 0 or all zone privs */ + priv = (geteuid() == 0); + if (!priv) { + priv_set_t *ps = priv_allocset(); /* caller */ + priv_set_t *zs; /* zone */ + + (void) getppriv(PRIV_EFFECTIVE, ps); + zs = priv_str_to_set("zone", ",", NULL); + priv = priv_isequalset(ps, zs); + priv_freeset(ps); + priv_freeset(zs); + } + if (!priv) + return (NS_LDAP_OP_FAILED); + + rc = send_to_cachemgr(dn, (ns_ldap_attr_t **)attr, errorp); + return (rc); + } + + if (cred == NULL) return (NS_LDAP_INVALID_PARAM); + + /* + * If service is NS_ADMIN_SHADOW_UPDATE, the caller should be + * ldap_cachemgr. We need to get the admin cred to do work. + * If the caller is not ldap_cachemgr, but use the service + * NS_ADMIN_SHADOW_UPDATE, get_admin_passwd() will fail, + * as the admin cred is not available to the caller. + */ + if (strcmp(service, NS_ADMIN_SHADOW_UPDATE) == 0) { + if ((rc = get_admin_passwd((ns_cred_t *)cred, errorp)) != + NS_LDAP_SUCCESS) + return (rc); + } + mods = __s_api_makeModList(service, attr, LDAP_MOD_REPLACE, flags); - if (mods == NULL) { + if (mods == NULL) return (NS_LDAP_MEMORY); - } rc = write_state_machine(LDAP_REQ_MODIFY, (char *)dn, mods, cred, flags, errorp); @@ -1191,7 +1324,6 @@ __ns_ldap_repAttr( return (rc); } - /*ARGSUSED*/ int __ns_ldap_addEntry( @@ -3793,3 +3925,157 @@ __s_api_append_default_basedn( (void) __ns_ldap_freeParam(¶m); return (NS_LDAP_SUCCESS); } + +/* + * Flatten the input ns_ldap_attr_t list, 'attr', and convert it into an + * ldap_strlist_t structure in buffer 'buf', to be used by ldap_cachemgr. + * The output contains a count, a list of offsets, which show where the + * corresponding copied attribute type and attribute value are located. + * For example, for dn=aaaa, userpassword=bbbb, shadowlastchange=cccc, + * the output is the ldap_strlist_t structure with: ldap_count = 6, + * (buf + ldap_offsets[0]) -> "dn" + * (buf + ldap_offsets[1]) -> "aaaa" + * (buf + ldap_offsets[2]) -> "userPassword" + * (buf + ldap_offsets[3]) -> "bbbb" + * (buf + ldap_offsets[4]) -> "shadowlastchange" + * (buf + ldap_offsets[5]) -> "cccc" + * and all the string data shown above copied into the buffer after + * the offset array. The total length of the data will be the return + * value, or -1 if error. + */ +static int +attr2list(const char *dn, ns_ldap_attr_t **attr, + char *buf, int bufsize) +{ + int c = 0; + char *ap; + int ao; + ldap_strlist_t *al = (ldap_strlist_t *)buf; + ns_ldap_attr_t *a = (ns_ldap_attr_t *)*attr; + ns_ldap_attr_t **aptr = (ns_ldap_attr_t **)attr; + + /* bufsize > strlen(dn) + strlen("dn") + 1 ('\0') */ + if ((strlen(dn) + 2 + 1) >= bufsize) + return (-1); + + /* count number of attributes */ + while (*aptr++) + c++; + al->ldap_count = 2 + c * 2; + ao = sizeof (al->ldap_count) + sizeof (al->ldap_offsets[0]) * + al->ldap_count; + if (ao > bufsize) + return (-1); + al->ldap_offsets[0] = ao; + ap = buf + ao; + ao += 3; + + /* copy entry DN */ + if (ao > bufsize) + return (-1); + (void) strlcpy(ap, "dn", bufsize); + ap += 3; + + al->ldap_offsets[1] = ao; + ao += strlen(dn) + 1; + if (ao > bufsize) + return (-1); + (void) strlcpy(ap, dn, bufsize); + ap = buf + ao; + + aptr = attr; + for (c = 2; c < al->ldap_count; c++, aptr++) { + a = *aptr; + if (a->attrname == NULL || a->attrvalue == NULL || + a->value_count != 1 || a->attrvalue[0] == NULL) + return (-1); + al->ldap_offsets[c] = ao; + ao += strlen(a->attrname) + 1; + if (ao > bufsize) + return (-1); + (void) strlcpy(ap, a->attrname, bufsize); + ap = buf + ao; + + c++; + al->ldap_offsets[c] = ao; + ao += strlen(a->attrvalue[0]) + 1; + (void) strlcpy(ap, a->attrvalue[0], bufsize); + ap = buf + ao; + }; + + return (ao); +} + +/* + * Send a modify request to the ldap_cachemgr daemon + * which will use the admin credential to perform the + * operation. + */ + +static int +send_to_cachemgr( + const char *dn, + ns_ldap_attr_t **attr, + ns_ldap_error_t **errorp) +{ + union { + ldap_data_t s_d; + char s_b[DOORBUFFERSIZE]; + } space; + + ldap_data_t *sptr; + int ndata; + int adata; + int len; + int rc; + char errstr[MAXERROR]; + ldap_admin_mod_result_t *admin_result; + + *errorp = NULL; + (void) memset(space.s_b, 0, DOORBUFFERSIZE); + len = attr2list(dn, attr, (char *)&space.s_d.ldap_call.ldap_u.strlist, + sizeof (space) - offsetof(ldap_return_t, ldap_u)); + if (len <= 0) + return (NS_LDAP_INVALID_PARAM); + + adata = sizeof (ldap_call_t) + len; + ndata = sizeof (space); + space.s_d.ldap_call.ldap_callnumber = ADMINMODIFY; + sptr = &space.s_d; + + switch (__ns_ldap_trydoorcall(&sptr, &ndata, &adata)) { + case NS_CACHE_SUCCESS: + break; + case NS_CACHE_NOTFOUND: + (void) snprintf(errstr, sizeof (errstr), + gettext("Door call ADMINMODIFY to " + "ldap_cachemgr failed - error: %d"), + space.s_d.ldap_ret.ldap_errno); + MKERROR(LOG_WARNING, *errorp, NS_CONFIG_CACHEMGR, + strdup(errstr), NULL); + return (NS_LDAP_OP_FAILED); + break; + default: + return (NS_LDAP_OP_FAILED); + } + + admin_result = &sptr->ldap_ret.ldap_u.admin_result; + if (admin_result->ns_err == NS_LDAP_SUCCESS) + rc = NS_LDAP_SUCCESS; + else { + rc = admin_result->ns_err; + if (admin_result->msg_size == 0) + *errorp = __s_api_make_error(admin_result->status, + NULL); + else + *errorp = __s_api_make_error(admin_result->status, + admin_result->msg); + } + + /* clean up the door call */ + if (sptr != &space.s_d) { + (void) munmap((char *)sptr, ndata); + } + + return (rc); +} |