OpenSolaris_b135/lib/nsswitch/ldap/common/getspent.c

/*
 * 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 2009 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

#include <shadow.h>
#include <stdlib.h>
#include "ldap_common.h"

/* shadow attributes filters */
#define	_S_UID			"uid"
#define	_S_USERPASSWORD		"userpassword"
#define	_S_LASTCHANGE		"shadowlastchange"
#define	_S_MIN			"shadowmin"
#define	_S_MAX			"shadowmax"
#define	_S_WARNING		"shadowwarning"
#define	_S_INACTIVE		"shadowinactive"
#define	_S_EXPIRE		"shadowexpire"
#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_LASTCHANGE,
	_S_MIN,
	_S_MAX,
	_S_WARNING,
	_S_INACTIVE,
	_S_EXPIRE,
	_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;
	int		shadow_update_enabled;
	unsigned long	len = 0L;
	char		*tmp, *buffer = NULL;
	char		*pw_passwd = NULL;
	ns_ldap_result_t	*result = be->result;
	char		**uid, **passwd, **last, **smin, **smax;
	char		**warning, **inactive, **expire, **flag;
	char		*last_str, *min_str, *max_str, *warning_str;
	char		*inactive_str, *expire_str, *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}");
				if (strcmp(pw_passwd,
				    NS_LDAP_NO_UNIX_PASSWORD) == 0)
					*pw_passwd = '\0';
			}
		} else {
		/* mark password as not retrievable */
			pw_passwd = NOPWDRTR;
		}
	}
	len += strlen(pw_passwd);

	/*
	 * If shadow update is not enabled, ignore the following
	 * password aging related attributes:
	 * -- shadowlastchange
	 * -- shadowmin
	 * -- shadowmax
	 * -- shadowwarning
	 * -- shadowinactive
	 * -- shadowexpire
	 * When shadow update is not enabled, the LDAP naming
	 * service does not 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.
	 */

	shadow_update_enabled = __ns_ldap_is_shadow_update_enabled();
	if (shadow_update_enabled) {
		last = __ns_ldap_getAttr(result->entry, _S_LASTCHANGE);
		if (last == NULL || last[0] == NULL)
			last_str = _NO_VALUE;
		else
			last_str = last[0];
		len += strlen(last_str);

		smin = __ns_ldap_getAttr(result->entry, _S_MIN);
		if (smin == NULL || smin[0] == NULL)
			min_str = _NO_VALUE;
		else
			min_str = smin[0];
		len += strlen(min_str);

		smax = __ns_ldap_getAttr(result->entry, _S_MAX);
		if (smax == NULL || smax[0] == NULL)
			max_str = _NO_VALUE;
		else
			max_str = smax[0];
		len += strlen(max_str);

		warning = __ns_ldap_getAttr(result->entry, _S_WARNING);
		if (warning == NULL || warning[0] == NULL)
			warning_str = _NO_VALUE;
		else
			warning_str = warning[0];
		len += strlen(warning_str);

		inactive = __ns_ldap_getAttr(result->entry, _S_INACTIVE);
		if (inactive == NULL || inactive[0] == NULL)
			inactive_str = _NO_VALUE;
		else
			inactive_str = inactive[0];
		len += strlen(inactive_str);

		expire = __ns_ldap_getAttr(result->entry, _S_EXPIRE);
		if (expire == NULL || expire[0] == NULL)
			expire_str = _NO_VALUE;
		else
			expire_str = expire[0];
		len += strlen(expire_str);
	}

	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;

	if (shadow_update_enabled) {
		(void) snprintf(buffer, len, "%s:%s:%s:%s:%s:%s:%s:%s:%s",
		    uid[0], pw_passwd, last_str, min_str, max_str, warning_str,
		    inactive_str, expire_str, flag_str);
	} else {
		(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));
}