2N/A/*
2N/A * CDDL HEADER START
2N/A *
2N/A * The contents of this file are subject to the terms of the
2N/A * Common Development and Distribution License (the "License").
2N/A * You may not use this file except in compliance with the License.
2N/A *
2N/A * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
2N/A * or http://www.opensolaris.org/os/licensing.
2N/A * See the License for the specific language governing permissions
2N/A * and limitations under the License.
2N/A *
2N/A * When distributing Covered Code, include this CDDL HEADER in each
2N/A * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
2N/A * If applicable, add the following below this CDDL HEADER, with the
2N/A * fields enclosed by brackets "[]" replaced with your own identifying
2N/A * information: Portions Copyright [yyyy] [name of copyright owner]
2N/A *
2N/A * CDDL HEADER END
2N/A */
2N/A/*
2N/A * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
2N/A * Use is subject to license terms.
2N/A */
2N/A
2N/A#include <shadow.h>
2N/A#include <stdlib.h>
2N/A#include "ldap_common.h"
2N/A
2N/A/* shadow attributes filters */
2N/A#define _S_UID "uid"
2N/A#define _S_USERPASSWORD "userpassword"
2N/A#define _S_LASTCHANGE "shadowlastchange"
2N/A#define _S_MIN "shadowmin"
2N/A#define _S_MAX "shadowmax"
2N/A#define _S_WARNING "shadowwarning"
2N/A#define _S_INACTIVE "shadowinactive"
2N/A#define _S_EXPIRE "shadowexpire"
2N/A#define _S_FLAG "shadowflag"
2N/A
2N/A#define _F_GETSPNAM "(&(objectClass=shadowAccount)(uid=%s))"
2N/A#define _F_GETSPNAM_SSD "(&(%%s)(uid=%s))"
2N/A
2N/Astatic const char *sp_attrs[] = {
2N/A _S_UID,
2N/A _S_USERPASSWORD,
2N/A _S_LASTCHANGE,
2N/A _S_MIN,
2N/A _S_MAX,
2N/A _S_WARNING,
2N/A _S_INACTIVE,
2N/A _S_EXPIRE,
2N/A _S_FLAG,
2N/A (char *)NULL
2N/A};
2N/A
2N/A/*
2N/A * _nss_ldap_shadow2str is the data marshaling method for the shadow getXbyY
2N/A * (e.g., getspnam(), getspent()) backend processes. This method is called after
2N/A * a successful ldap search has been performed. This method will parse the
2N/A * ldap search values into the file format.
2N/A * e.g.
2N/A *
2N/A * myname:gaBXNJuz4JDmA:6445::::::
2N/A *
2N/A */
2N/A
2N/Astatic int
2N/A_nss_ldap_shadow2str(ldap_backend_ptr be, nss_XbyY_args_t *argp)
2N/A{
2N/A int nss_result;
2N/A int buflen = 0;
2N/A int shadow_update_enabled;
2N/A unsigned long len = 0L;
2N/A char *tmp, *buffer = NULL;
2N/A char *pw_passwd = NULL;
2N/A ns_ldap_result_t *result = be->result;
2N/A char **uid, **passwd, **last, **smin, **smax;
2N/A char **warning, **inactive, **expire, **flag;
2N/A char *last_str, *min_str, *max_str, *warning_str;
2N/A char *inactive_str, *expire_str, *flag_str;
2N/A
2N/A if (result == NULL)
2N/A return (NSS_STR_PARSE_PARSE);
2N/A buflen = argp->buf.buflen;
2N/A
2N/A nss_result = NSS_STR_PARSE_SUCCESS;
2N/A (void) memset(argp->buf.buffer, 0, buflen);
2N/A
2N/A uid = __ns_ldap_getAttr(result->entry, _S_UID);
2N/A if (uid == NULL || uid[0] == NULL || (strlen(uid[0]) < 1)) {
2N/A nss_result = NSS_STR_PARSE_PARSE;
2N/A goto result_spd2str;
2N/A }
2N/A len += strlen(uid[0]);
2N/A
2N/A passwd = __ns_ldap_getAttr(result->entry, _S_USERPASSWORD);
2N/A if (passwd == NULL || passwd[0] == NULL) {
2N/A /*
2N/A * ACL does not allow userpassword to return or
2N/A * userpassword is not defined
2N/A */
2N/A pw_passwd = NOPWDRTR;
2N/A } else if (strcmp(passwd[0], "") == 0) {
2N/A /*
2N/A * An empty password is not supported
2N/A */
2N/A nss_result = NSS_STR_PARSE_PARSE;
2N/A goto result_spd2str;
2N/A } else {
2N/A if ((tmp = strstr(passwd[0], "{crypt}")) != NULL ||
2N/A (tmp = strstr(passwd[0], "{CRYPT}")) != NULL) {
2N/A if (tmp != passwd[0])
2N/A pw_passwd = NOPWDRTR;
2N/A else {
2N/A pw_passwd = tmp + strlen("{crypt}");
2N/A if (strcmp(pw_passwd,
2N/A NS_LDAP_NO_UNIX_PASSWORD) == 0)
2N/A *pw_passwd = '\0';
2N/A }
2N/A } else {
2N/A /* mark password as not retrievable */
2N/A pw_passwd = NOPWDRTR;
2N/A }
2N/A }
2N/A len += strlen(pw_passwd);
2N/A
2N/A /*
2N/A * If shadow update is not enabled, ignore the following
2N/A * password aging related attributes:
2N/A * -- shadowlastchange
2N/A * -- shadowmin
2N/A * -- shadowmax
2N/A * -- shadowwarning
2N/A * -- shadowinactive
2N/A * -- shadowexpire
2N/A * When shadow update is not enabled, the LDAP naming
2N/A * service does not support the password aging fields
2N/A * defined in the shadow structure. These fields, sp_lstchg,
2N/A * sp_min, sp_max, sp_warn, sp_inact, and sp_expire,
2N/A * will be set to -1 by the front end marshaller.
2N/A */
2N/A
2N/A shadow_update_enabled = __ns_ldap_is_shadow_update_enabled();
2N/A if (shadow_update_enabled) {
2N/A last = __ns_ldap_getAttr(result->entry, _S_LASTCHANGE);
2N/A if (last == NULL || last[0] == NULL)
2N/A last_str = _NO_VALUE;
2N/A else
2N/A last_str = last[0];
2N/A len += strlen(last_str);
2N/A
2N/A smin = __ns_ldap_getAttr(result->entry, _S_MIN);
2N/A if (smin == NULL || smin[0] == NULL)
2N/A min_str = _NO_VALUE;
2N/A else
2N/A min_str = smin[0];
2N/A len += strlen(min_str);
2N/A
2N/A smax = __ns_ldap_getAttr(result->entry, _S_MAX);
2N/A if (smax == NULL || smax[0] == NULL)
2N/A max_str = _NO_VALUE;
2N/A else
2N/A max_str = smax[0];
2N/A len += strlen(max_str);
2N/A
2N/A warning = __ns_ldap_getAttr(result->entry, _S_WARNING);
2N/A if (warning == NULL || warning[0] == NULL)
2N/A warning_str = _NO_VALUE;
2N/A else
2N/A warning_str = warning[0];
2N/A len += strlen(warning_str);
2N/A
2N/A inactive = __ns_ldap_getAttr(result->entry, _S_INACTIVE);
2N/A if (inactive == NULL || inactive[0] == NULL)
2N/A inactive_str = _NO_VALUE;
2N/A else
2N/A inactive_str = inactive[0];
2N/A len += strlen(inactive_str);
2N/A
2N/A expire = __ns_ldap_getAttr(result->entry, _S_EXPIRE);
2N/A if (expire == NULL || expire[0] == NULL)
2N/A expire_str = _NO_VALUE;
2N/A else
2N/A expire_str = expire[0];
2N/A len += strlen(expire_str);
2N/A }
2N/A
2N/A flag = __ns_ldap_getAttr(result->entry, _S_FLAG);
2N/A if (flag == NULL || flag[0] == NULL)
2N/A flag_str = _NO_VALUE;
2N/A else
2N/A flag_str = flag[0];
2N/A
2N/A /* 9 = 8 ':' + 1 '\0' */
2N/A len += strlen(flag_str) + 9;
2N/A
2N/A if (len > buflen) {
2N/A nss_result = NSS_STR_PARSE_ERANGE;
2N/A goto result_spd2str;
2N/A }
2N/A
2N/A if (argp->buf.result != NULL) {
2N/A be->buffer = calloc(1, len);
2N/A if (be->buffer == NULL) {
2N/A nss_result = NSS_STR_PARSE_PARSE;
2N/A goto result_spd2str;
2N/A }
2N/A buffer = be->buffer;
2N/A } else
2N/A buffer = argp->buf.buffer;
2N/A
2N/A if (shadow_update_enabled) {
2N/A (void) snprintf(buffer, len, "%s:%s:%s:%s:%s:%s:%s:%s:%s",
2N/A uid[0], pw_passwd, last_str, min_str, max_str, warning_str,
2N/A inactive_str, expire_str, flag_str);
2N/A } else {
2N/A (void) snprintf(buffer, len, "%s:%s:::::::%s",
2N/A uid[0], pw_passwd, flag_str);
2N/A }
2N/A
2N/A /* The front end marhsaller doesn't need the trailing null */
2N/A if (argp->buf.result != NULL)
2N/A be->buflen = strlen(be->buffer);
2N/Aresult_spd2str:
2N/A
2N/A (void) __ns_ldap_freeResult(&be->result);
2N/A return ((int)nss_result);
2N/A}
2N/A
2N/A/*
2N/A * getbynam gets a passwd entry by uid name. This function constructs an ldap
2N/A * search filter using the name invocation parameter and the getspnam search
2N/A * filter defined. Once the filter is constructed we search for a matching
2N/A * entry and marshal the data results into struct shadow for the frontend
2N/A * process. The function _nss_ldap_shadow2ent performs the data marshaling.
2N/A */
2N/A
2N/Astatic nss_status_t
2N/Agetbynam(ldap_backend_ptr be, void *a)
2N/A{
2N/A nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a;
2N/A char searchfilter[SEARCHFILTERLEN];
2N/A char userdata[SEARCHFILTERLEN];
2N/A char name[SEARCHFILTERLEN + 1];
2N/A int ret;
2N/A
2N/A if (_ldap_filter_name(name, argp->key.name, sizeof (name)) != 0)
2N/A return ((nss_status_t)NSS_NOTFOUND);
2N/A
2N/A ret = snprintf(searchfilter, sizeof (searchfilter), _F_GETSPNAM, name);
2N/A if (ret >= sizeof (searchfilter) || ret < 0)
2N/A return ((nss_status_t)NSS_NOTFOUND);
2N/A
2N/A ret = snprintf(userdata, sizeof (userdata), _F_GETSPNAM_SSD, name);
2N/A if (ret >= sizeof (userdata) || ret < 0)
2N/A return ((nss_status_t)NSS_NOTFOUND);
2N/A
2N/A return (_nss_ldap_lookup(be, argp, _SHADOW, searchfilter, NULL,
2N/A _merge_SSD_filter, userdata));
2N/A}
2N/A
2N/Astatic ldap_backend_op_t sp_ops[] = {
2N/A _nss_ldap_destr,
2N/A _nss_ldap_endent,
2N/A _nss_ldap_setent,
2N/A _nss_ldap_getent,
2N/A getbynam
2N/A};
2N/A
2N/A
2N/A/*
2N/A * _nss_ldap_passwd_constr is where life begins. This function calls the
2N/A * generic ldap constructor function to define and build the abstract
2N/A * data types required to support ldap operations.
2N/A */
2N/A
2N/A/*ARGSUSED0*/
2N/Anss_backend_t *
2N/A_nss_ldap_shadow_constr(const char *dummy1, const char *dummy2,
2N/A const char *dummy3)
2N/A{
2N/A
2N/A return ((nss_backend_t *)_nss_ldap_constr(sp_ops,
2N/A sizeof (sp_ops)/sizeof (sp_ops[0]),
2N/A _SHADOW, sp_attrs, _nss_ldap_shadow2str));
2N/A}