Home | History | Annotate | Download | only in common
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 /*
     22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
     23  * Use is subject to license terms.
     24  */
     25 
     26 #include <shadow.h>
     27 #include <stdlib.h>
     28 #include "ldap_common.h"
     29 
     30 /* shadow attributes filters */
     31 #define	_S_UID			"uid"
     32 #define	_S_USERPASSWORD		"userpassword"
     33 #define	_S_LASTCHANGE		"shadowlastchange"
     34 #define	_S_MIN			"shadowmin"
     35 #define	_S_MAX			"shadowmax"
     36 #define	_S_WARNING		"shadowwarning"
     37 #define	_S_INACTIVE		"shadowinactive"
     38 #define	_S_EXPIRE		"shadowexpire"
     39 #define	_S_FLAG			"shadowflag"
     40 
     41 #define	_F_GETSPNAM		"(&(objectClass=shadowAccount)(uid=%s))"
     42 #define	_F_GETSPNAM_SSD		"(&(%%s)(uid=%s))"
     43 
     44 static const char *sp_attrs[] = {
     45 	_S_UID,
     46 	_S_USERPASSWORD,
     47 	_S_LASTCHANGE,
     48 	_S_MIN,
     49 	_S_MAX,
     50 	_S_WARNING,
     51 	_S_INACTIVE,
     52 	_S_EXPIRE,
     53 	_S_FLAG,
     54 	(char *)NULL
     55 };
     56 
     57 /*
     58  * _nss_ldap_shadow2str is the data marshaling method for the shadow getXbyY
     59  * (e.g., getspnam(), getspent()) backend processes. This method is called after
     60  * a successful ldap search has been performed. This method will parse the
     61  * ldap search values into the file format.
     62  * e.g.
     63  *
     64  * myname:gaBXNJuz4JDmA:6445::::::
     65  *
     66  */
     67 
     68 static int
     69 _nss_ldap_shadow2str(ldap_backend_ptr be, nss_XbyY_args_t *argp)
     70 {
     71 	int		nss_result;
     72 	int		buflen = 0;
     73 	int		shadow_update_enabled;
     74 	unsigned long	len = 0L;
     75 	char		*tmp, *buffer = NULL;
     76 	char		*pw_passwd = NULL;
     77 	ns_ldap_result_t	*result = be->result;
     78 	char		**uid, **passwd, **last, **smin, **smax;
     79 	char		**warning, **inactive, **expire, **flag;
     80 	char		*last_str, *min_str, *max_str, *warning_str;
     81 	char		*inactive_str, *expire_str, *flag_str;
     82 
     83 	if (result == NULL)
     84 		return (NSS_STR_PARSE_PARSE);
     85 	buflen = argp->buf.buflen;
     86 
     87 	nss_result = NSS_STR_PARSE_SUCCESS;
     88 	(void) memset(argp->buf.buffer, 0, buflen);
     89 
     90 	uid = __ns_ldap_getAttr(result->entry, _S_UID);
     91 	if (uid == NULL || uid[0] == NULL || (strlen(uid[0]) < 1)) {
     92 		nss_result = NSS_STR_PARSE_PARSE;
     93 		goto result_spd2str;
     94 	}
     95 	len += strlen(uid[0]);
     96 
     97 	passwd = __ns_ldap_getAttr(result->entry, _S_USERPASSWORD);
     98 	if (passwd == NULL || passwd[0] == NULL) {
     99 		/*
    100 		 * ACL does not allow userpassword to return or
    101 		 * userpassword is not defined
    102 		 */
    103 		pw_passwd = NOPWDRTR;
    104 	} else if (strcmp(passwd[0], "") == 0) {
    105 		/*
    106 		 * An empty password is not supported
    107 		 */
    108 		nss_result = NSS_STR_PARSE_PARSE;
    109 		goto result_spd2str;
    110 	} else {
    111 		if ((tmp = strstr(passwd[0], "{crypt}")) != NULL ||
    112 		    (tmp = strstr(passwd[0], "{CRYPT}")) != NULL) {
    113 			if (tmp != passwd[0])
    114 				pw_passwd = NOPWDRTR;
    115 			else {
    116 				pw_passwd = tmp + strlen("{crypt}");
    117 				if (strcmp(pw_passwd,
    118 				    NS_LDAP_NO_UNIX_PASSWORD) == 0)
    119 					*pw_passwd = '\0';
    120 			}
    121 		} else {
    122 		/* mark password as not retrievable */
    123 			pw_passwd = NOPWDRTR;
    124 		}
    125 	}
    126 	len += strlen(pw_passwd);
    127 
    128 	/*
    129 	 * If shadow update is not enabled, ignore the following
    130 	 * password aging related attributes:
    131 	 * -- shadowlastchange
    132 	 * -- shadowmin
    133 	 * -- shadowmax
    134 	 * -- shadowwarning
    135 	 * -- shadowinactive
    136 	 * -- shadowexpire
    137 	 * When shadow update is not enabled, the LDAP naming
    138 	 * service does not support the password aging fields
    139 	 * defined in the shadow structure. These fields, sp_lstchg,
    140 	 * sp_min, sp_max, sp_warn, sp_inact, and sp_expire,
    141 	 * will be set to -1 by the front end marshaller.
    142 	 */
    143 
    144 	shadow_update_enabled = __ns_ldap_is_shadow_update_enabled();
    145 	if (shadow_update_enabled) {
    146 		last = __ns_ldap_getAttr(result->entry, _S_LASTCHANGE);
    147 		if (last == NULL || last[0] == NULL)
    148 			last_str = _NO_VALUE;
    149 		else
    150 			last_str = last[0];
    151 		len += strlen(last_str);
    152 
    153 		smin = __ns_ldap_getAttr(result->entry, _S_MIN);
    154 		if (smin == NULL || smin[0] == NULL)
    155 			min_str = _NO_VALUE;
    156 		else
    157 			min_str = smin[0];
    158 		len += strlen(min_str);
    159 
    160 		smax = __ns_ldap_getAttr(result->entry, _S_MAX);
    161 		if (smax == NULL || smax[0] == NULL)
    162 			max_str = _NO_VALUE;
    163 		else
    164 			max_str = smax[0];
    165 		len += strlen(max_str);
    166 
    167 		warning = __ns_ldap_getAttr(result->entry, _S_WARNING);
    168 		if (warning == NULL || warning[0] == NULL)
    169 			warning_str = _NO_VALUE;
    170 		else
    171 			warning_str = warning[0];
    172 		len += strlen(warning_str);
    173 
    174 		inactive = __ns_ldap_getAttr(result->entry, _S_INACTIVE);
    175 		if (inactive == NULL || inactive[0] == NULL)
    176 			inactive_str = _NO_VALUE;
    177 		else
    178 			inactive_str = inactive[0];
    179 		len += strlen(inactive_str);
    180 
    181 		expire = __ns_ldap_getAttr(result->entry, _S_EXPIRE);
    182 		if (expire == NULL || expire[0] == NULL)
    183 			expire_str = _NO_VALUE;
    184 		else
    185 			expire_str = expire[0];
    186 		len += strlen(expire_str);
    187 	}
    188 
    189 	flag = __ns_ldap_getAttr(result->entry, _S_FLAG);
    190 	if (flag == NULL || flag[0] == NULL)
    191 		flag_str = _NO_VALUE;
    192 	else
    193 		flag_str = flag[0];
    194 
    195 	/* 9 = 8 ':' + 1 '\0' */
    196 	len += strlen(flag_str) + 9;
    197 
    198 	if (len > buflen) {
    199 		nss_result = NSS_STR_PARSE_ERANGE;
    200 		goto result_spd2str;
    201 	}
    202 
    203 	if (argp->buf.result != NULL) {
    204 		be->buffer = calloc(1, len);
    205 		if (be->buffer == NULL) {
    206 			nss_result = NSS_STR_PARSE_PARSE;
    207 			goto result_spd2str;
    208 		}
    209 		buffer = be->buffer;
    210 	} else
    211 		buffer = argp->buf.buffer;
    212 
    213 	if (shadow_update_enabled) {
    214 		(void) snprintf(buffer, len, "%s:%s:%s:%s:%s:%s:%s:%s:%s",
    215 		    uid[0], pw_passwd, last_str, min_str, max_str, warning_str,
    216 		    inactive_str, expire_str, flag_str);
    217 	} else {
    218 		(void) snprintf(buffer, len, "%s:%s:::::::%s",
    219 		    uid[0], pw_passwd, flag_str);
    220 	}
    221 
    222 	/* The front end marhsaller doesn't need the trailing null */
    223 	if (argp->buf.result != NULL)
    224 		be->buflen = strlen(be->buffer);
    225 result_spd2str:
    226 
    227 	(void) __ns_ldap_freeResult(&be->result);
    228 	return ((int)nss_result);
    229 }
    230 
    231 /*
    232  * getbynam gets a passwd entry by uid name. This function constructs an ldap
    233  * search filter using the name invocation parameter and the getspnam search
    234  * filter defined. Once the filter is constructed we search for a matching
    235  * entry and marshal the data results into struct shadow for the frontend
    236  * process. The function _nss_ldap_shadow2ent performs the data marshaling.
    237  */
    238 
    239 static nss_status_t
    240 getbynam(ldap_backend_ptr be, void *a)
    241 {
    242 	nss_XbyY_args_t	*argp = (nss_XbyY_args_t *)a;
    243 	char		searchfilter[SEARCHFILTERLEN];
    244 	char		userdata[SEARCHFILTERLEN];
    245 	char		name[SEARCHFILTERLEN + 1];
    246 	int		ret;
    247 
    248 	if (_ldap_filter_name(name, argp->key.name, sizeof (name)) != 0)
    249 		return ((nss_status_t)NSS_NOTFOUND);
    250 
    251 	ret = snprintf(searchfilter, sizeof (searchfilter), _F_GETSPNAM, name);
    252 	if (ret >= sizeof (searchfilter) || ret < 0)
    253 		return ((nss_status_t)NSS_NOTFOUND);
    254 
    255 	ret = snprintf(userdata, sizeof (userdata), _F_GETSPNAM_SSD, name);
    256 	if (ret >= sizeof (userdata) || ret < 0)
    257 		return ((nss_status_t)NSS_NOTFOUND);
    258 
    259 	return (_nss_ldap_lookup(be, argp, _SHADOW, searchfilter, NULL,
    260 	    _merge_SSD_filter, userdata));
    261 }
    262 
    263 static ldap_backend_op_t sp_ops[] = {
    264     _nss_ldap_destr,
    265     _nss_ldap_endent,
    266     _nss_ldap_setent,
    267     _nss_ldap_getent,
    268     getbynam
    269 };
    270 
    271 
    272 /*
    273  * _nss_ldap_passwd_constr is where life begins. This function calls the
    274  * generic ldap constructor function to define and build the abstract
    275  * data types required to support ldap operations.
    276  */
    277 
    278 /*ARGSUSED0*/
    279 nss_backend_t *
    280 _nss_ldap_shadow_constr(const char *dummy1, const char *dummy2,
    281 			const char *dummy3)
    282 {
    283 
    284 	return ((nss_backend_t *)_nss_ldap_constr(sp_ops,
    285 	    sizeof (sp_ops)/sizeof (sp_ops[0]),
    286 	    _SHADOW, sp_attrs, _nss_ldap_shadow2str));
    287 }
    288