/* * 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 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include #include "ldap_common.h" /* shadow attributes filters */ #define _S_UID "uid" #define _S_USERPASSWORD "userpassword" #define _S_FLAG "shadowflag" #define _F_GETSPNAM "(&(objectClass=shadowAccount)(uid=%s))" #define _F_GETSPNAM_SSD "(&(%%s)(uid=%s))" static const char *sp_attrs[] = { _S_UID, _S_USERPASSWORD, _S_FLAG, (char *)NULL }; /* * _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 the file format. * e.g. * * myname:gaBXNJuz4JDmA:6445:::::: * */ static int _nss_ldap_shadow2str(ldap_backend_ptr be, nss_XbyY_args_t *argp) { int nss_result; int buflen = 0; unsigned long len = 0L; char *tmp, *buffer = NULL; char *pw_passwd = NULL; ns_ldap_result_t *result = be->result; char **uid, **passwd, **flag, *flag_str; 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); 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; } len += strlen(uid[0]); passwd = __ns_ldap_getAttr(result->entry, _S_USERPASSWORD); if (passwd == NULL || passwd[0] == NULL) { /* * ACL does not allow userpassword to return or * userpassword is not defined */ pw_passwd = NOPWDRTR; } else if (strcmp(passwd[0], "") == 0) { /* * An empty password is not supported */ nss_result = NSS_STR_PARSE_PARSE; goto result_spd2str; } else { if ((tmp = strstr(passwd[0], "{crypt}")) != NULL || (tmp = strstr(passwd[0], "{CRYPT}")) != NULL) { if (tmp != passwd[0]) pw_passwd = NOPWDRTR; else pw_passwd = tmp + strlen("{crypt}"); } else { /* mark password as not retrievable */ pw_passwd = NOPWDRTR; } } 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; (void) snprintf(buffer, len, "%s:%s:::::::%s", uid[0], pw_passwd, flag_str); /* 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); } /* * getbynam gets a passwd entry by uid name. This function constructs an ldap * search filter using the name invocation parameter and the getspnam search * filter defined. Once the filter is constructed we search for a matching * entry and marshal the data results into struct shadow for the frontend * process. The function _nss_ldap_shadow2ent performs the data marshaling. */ static nss_status_t getbynam(ldap_backend_ptr be, void *a) { nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a; char searchfilter[SEARCHFILTERLEN]; char userdata[SEARCHFILTERLEN]; char name[SEARCHFILTERLEN + 1]; int ret; if (_ldap_filter_name(name, argp->key.name, sizeof (name)) != 0) return ((nss_status_t)NSS_NOTFOUND); ret = snprintf(searchfilter, sizeof (searchfilter), _F_GETSPNAM, name); if (ret >= sizeof (searchfilter) || ret < 0) return ((nss_status_t)NSS_NOTFOUND); ret = snprintf(userdata, sizeof (userdata), _F_GETSPNAM_SSD, name); if (ret >= sizeof (userdata) || ret < 0) return ((nss_status_t)NSS_NOTFOUND); return (_nss_ldap_lookup(be, argp, _SHADOW, searchfilter, NULL, _merge_SSD_filter, userdata)); } static ldap_backend_op_t sp_ops[] = { _nss_ldap_destr, _nss_ldap_endent, _nss_ldap_setent, _nss_ldap_getent, getbynam }; /* * _nss_ldap_passwd_constr is where life begins. This function calls the * generic ldap constructor function to define and build the abstract * data types required to support ldap operations. */ /*ARGSUSED0*/ nss_backend_t * _nss_ldap_shadow_constr(const char *dummy1, const char *dummy2, const char *dummy3) { return ((nss_backend_t *)_nss_ldap_constr(sp_ops, sizeof (sp_ops)/sizeof (sp_ops[0]), _SHADOW, sp_attrs, _nss_ldap_shadow2str)); }