10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * The contents of this file are subject to the terms of the
52830Sdjl * Common Development and Distribution License (the "License").
62830Sdjl * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate *
80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate * See the License for the specific language governing permissions
110Sstevel@tonic-gate * and limitations under the License.
120Sstevel@tonic-gate *
130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate *
190Sstevel@tonic-gate * CDDL HEADER END
200Sstevel@tonic-gate */
210Sstevel@tonic-gate /*
22*8821SMichen.Chang@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
230Sstevel@tonic-gate * Use is subject to license terms.
240Sstevel@tonic-gate */
250Sstevel@tonic-gate
260Sstevel@tonic-gate #include <shadow.h>
270Sstevel@tonic-gate #include <stdlib.h>
280Sstevel@tonic-gate #include "ldap_common.h"
290Sstevel@tonic-gate
300Sstevel@tonic-gate /* shadow attributes filters */
310Sstevel@tonic-gate #define _S_UID "uid"
320Sstevel@tonic-gate #define _S_USERPASSWORD "userpassword"
33*8821SMichen.Chang@Sun.COM #define _S_LASTCHANGE "shadowlastchange"
34*8821SMichen.Chang@Sun.COM #define _S_MIN "shadowmin"
35*8821SMichen.Chang@Sun.COM #define _S_MAX "shadowmax"
36*8821SMichen.Chang@Sun.COM #define _S_WARNING "shadowwarning"
37*8821SMichen.Chang@Sun.COM #define _S_INACTIVE "shadowinactive"
38*8821SMichen.Chang@Sun.COM #define _S_EXPIRE "shadowexpire"
390Sstevel@tonic-gate #define _S_FLAG "shadowflag"
400Sstevel@tonic-gate
410Sstevel@tonic-gate #define _F_GETSPNAM "(&(objectClass=shadowAccount)(uid=%s))"
420Sstevel@tonic-gate #define _F_GETSPNAM_SSD "(&(%%s)(uid=%s))"
430Sstevel@tonic-gate
440Sstevel@tonic-gate static const char *sp_attrs[] = {
450Sstevel@tonic-gate _S_UID,
460Sstevel@tonic-gate _S_USERPASSWORD,
47*8821SMichen.Chang@Sun.COM _S_LASTCHANGE,
48*8821SMichen.Chang@Sun.COM _S_MIN,
49*8821SMichen.Chang@Sun.COM _S_MAX,
50*8821SMichen.Chang@Sun.COM _S_WARNING,
51*8821SMichen.Chang@Sun.COM _S_INACTIVE,
52*8821SMichen.Chang@Sun.COM _S_EXPIRE,
530Sstevel@tonic-gate _S_FLAG,
540Sstevel@tonic-gate (char *)NULL
550Sstevel@tonic-gate };
560Sstevel@tonic-gate
570Sstevel@tonic-gate /*
582830Sdjl * _nss_ldap_shadow2str is the data marshaling method for the shadow getXbyY
590Sstevel@tonic-gate * (e.g., getspnam(), getspent()) backend processes. This method is called after
600Sstevel@tonic-gate * a successful ldap search has been performed. This method will parse the
612830Sdjl * ldap search values into the file format.
622830Sdjl * e.g.
632830Sdjl *
642830Sdjl * myname:gaBXNJuz4JDmA:6445::::::
652830Sdjl *
660Sstevel@tonic-gate */
670Sstevel@tonic-gate
680Sstevel@tonic-gate static int
_nss_ldap_shadow2str(ldap_backend_ptr be,nss_XbyY_args_t * argp)692830Sdjl _nss_ldap_shadow2str(ldap_backend_ptr be, nss_XbyY_args_t *argp)
700Sstevel@tonic-gate {
710Sstevel@tonic-gate int nss_result;
722830Sdjl int buflen = 0;
73*8821SMichen.Chang@Sun.COM int shadow_update_enabled;
740Sstevel@tonic-gate unsigned long len = 0L;
752830Sdjl char *tmp, *buffer = NULL;
762830Sdjl char *pw_passwd = NULL;
770Sstevel@tonic-gate ns_ldap_result_t *result = be->result;
78*8821SMichen.Chang@Sun.COM char **uid, **passwd, **last, **smin, **smax;
79*8821SMichen.Chang@Sun.COM char **warning, **inactive, **expire, **flag;
80*8821SMichen.Chang@Sun.COM char *last_str, *min_str, *max_str, *warning_str;
81*8821SMichen.Chang@Sun.COM char *inactive_str, *expire_str, *flag_str;
822830Sdjl
832830Sdjl if (result == NULL)
842830Sdjl return (NSS_STR_PARSE_PARSE);
852830Sdjl buflen = argp->buf.buflen;
860Sstevel@tonic-gate
872830Sdjl nss_result = NSS_STR_PARSE_SUCCESS;
882830Sdjl (void) memset(argp->buf.buffer, 0, buflen);
890Sstevel@tonic-gate
902830Sdjl uid = __ns_ldap_getAttr(result->entry, _S_UID);
912830Sdjl if (uid == NULL || uid[0] == NULL || (strlen(uid[0]) < 1)) {
922830Sdjl nss_result = NSS_STR_PARSE_PARSE;
932830Sdjl goto result_spd2str;
940Sstevel@tonic-gate }
952830Sdjl len += strlen(uid[0]);
962830Sdjl
972830Sdjl passwd = __ns_ldap_getAttr(result->entry, _S_USERPASSWORD);
984048Schinlong if (passwd == NULL || passwd[0] == NULL) {
994048Schinlong /*
1004048Schinlong * ACL does not allow userpassword to return or
1014048Schinlong * userpassword is not defined
1024048Schinlong */
1037422SJohn.Sonnenschein@Sun.COM pw_passwd = NOPWDRTR;
1044048Schinlong } else if (strcmp(passwd[0], "") == 0) {
1054048Schinlong /*
1064048Schinlong * An empty password is not supported
1074048Schinlong */
1084048Schinlong nss_result = NSS_STR_PARSE_PARSE;
1094048Schinlong goto result_spd2str;
1102830Sdjl } else {
1112830Sdjl if ((tmp = strstr(passwd[0], "{crypt}")) != NULL ||
112*8821SMichen.Chang@Sun.COM (tmp = strstr(passwd[0], "{CRYPT}")) != NULL) {
1132830Sdjl if (tmp != passwd[0])
1147422SJohn.Sonnenschein@Sun.COM pw_passwd = NOPWDRTR;
115*8821SMichen.Chang@Sun.COM else {
1162830Sdjl pw_passwd = tmp + strlen("{crypt}");
117*8821SMichen.Chang@Sun.COM if (strcmp(pw_passwd,
118*8821SMichen.Chang@Sun.COM NS_LDAP_NO_UNIX_PASSWORD) == 0)
119*8821SMichen.Chang@Sun.COM *pw_passwd = '\0';
120*8821SMichen.Chang@Sun.COM }
1212830Sdjl } else {
1227422SJohn.Sonnenschein@Sun.COM /* mark password as not retrievable */
1237422SJohn.Sonnenschein@Sun.COM pw_passwd = NOPWDRTR;
1242830Sdjl }
1252830Sdjl }
1262830Sdjl len += strlen(pw_passwd);
1270Sstevel@tonic-gate
1282830Sdjl /*
129*8821SMichen.Chang@Sun.COM * If shadow update is not enabled, ignore the following
130*8821SMichen.Chang@Sun.COM * password aging related attributes:
1312830Sdjl * -- shadowlastchange
1322830Sdjl * -- shadowmin
1332830Sdjl * -- shadowmax
1342830Sdjl * -- shadowwarning
1352830Sdjl * -- shadowinactive
1362830Sdjl * -- shadowexpire
137*8821SMichen.Chang@Sun.COM * When shadow update is not enabled, the LDAP naming
138*8821SMichen.Chang@Sun.COM * service does not support the password aging fields
139*8821SMichen.Chang@Sun.COM * defined in the shadow structure. These fields, sp_lstchg,
1402830Sdjl * sp_min, sp_max, sp_warn, sp_inact, and sp_expire,
1412830Sdjl * will be set to -1 by the front end marshaller.
1422830Sdjl */
143*8821SMichen.Chang@Sun.COM
144*8821SMichen.Chang@Sun.COM shadow_update_enabled = __ns_ldap_is_shadow_update_enabled();
145*8821SMichen.Chang@Sun.COM if (shadow_update_enabled) {
146*8821SMichen.Chang@Sun.COM last = __ns_ldap_getAttr(result->entry, _S_LASTCHANGE);
147*8821SMichen.Chang@Sun.COM if (last == NULL || last[0] == NULL)
148*8821SMichen.Chang@Sun.COM last_str = _NO_VALUE;
149*8821SMichen.Chang@Sun.COM else
150*8821SMichen.Chang@Sun.COM last_str = last[0];
151*8821SMichen.Chang@Sun.COM len += strlen(last_str);
152*8821SMichen.Chang@Sun.COM
153*8821SMichen.Chang@Sun.COM smin = __ns_ldap_getAttr(result->entry, _S_MIN);
154*8821SMichen.Chang@Sun.COM if (smin == NULL || smin[0] == NULL)
155*8821SMichen.Chang@Sun.COM min_str = _NO_VALUE;
156*8821SMichen.Chang@Sun.COM else
157*8821SMichen.Chang@Sun.COM min_str = smin[0];
158*8821SMichen.Chang@Sun.COM len += strlen(min_str);
159*8821SMichen.Chang@Sun.COM
160*8821SMichen.Chang@Sun.COM smax = __ns_ldap_getAttr(result->entry, _S_MAX);
161*8821SMichen.Chang@Sun.COM if (smax == NULL || smax[0] == NULL)
162*8821SMichen.Chang@Sun.COM max_str = _NO_VALUE;
163*8821SMichen.Chang@Sun.COM else
164*8821SMichen.Chang@Sun.COM max_str = smax[0];
165*8821SMichen.Chang@Sun.COM len += strlen(max_str);
166*8821SMichen.Chang@Sun.COM
167*8821SMichen.Chang@Sun.COM warning = __ns_ldap_getAttr(result->entry, _S_WARNING);
168*8821SMichen.Chang@Sun.COM if (warning == NULL || warning[0] == NULL)
169*8821SMichen.Chang@Sun.COM warning_str = _NO_VALUE;
170*8821SMichen.Chang@Sun.COM else
171*8821SMichen.Chang@Sun.COM warning_str = warning[0];
172*8821SMichen.Chang@Sun.COM len += strlen(warning_str);
173*8821SMichen.Chang@Sun.COM
174*8821SMichen.Chang@Sun.COM inactive = __ns_ldap_getAttr(result->entry, _S_INACTIVE);
175*8821SMichen.Chang@Sun.COM if (inactive == NULL || inactive[0] == NULL)
176*8821SMichen.Chang@Sun.COM inactive_str = _NO_VALUE;
177*8821SMichen.Chang@Sun.COM else
178*8821SMichen.Chang@Sun.COM inactive_str = inactive[0];
179*8821SMichen.Chang@Sun.COM len += strlen(inactive_str);
180*8821SMichen.Chang@Sun.COM
181*8821SMichen.Chang@Sun.COM expire = __ns_ldap_getAttr(result->entry, _S_EXPIRE);
182*8821SMichen.Chang@Sun.COM if (expire == NULL || expire[0] == NULL)
183*8821SMichen.Chang@Sun.COM expire_str = _NO_VALUE;
184*8821SMichen.Chang@Sun.COM else
185*8821SMichen.Chang@Sun.COM expire_str = expire[0];
186*8821SMichen.Chang@Sun.COM len += strlen(expire_str);
187*8821SMichen.Chang@Sun.COM }
188*8821SMichen.Chang@Sun.COM
1892830Sdjl flag = __ns_ldap_getAttr(result->entry, _S_FLAG);
1902830Sdjl if (flag == NULL || flag[0] == NULL)
1912830Sdjl flag_str = _NO_VALUE;
1922830Sdjl else
1932830Sdjl flag_str = flag[0];
1940Sstevel@tonic-gate
1952830Sdjl /* 9 = 8 ':' + 1 '\0' */
1962830Sdjl len += strlen(flag_str) + 9;
1970Sstevel@tonic-gate
1982830Sdjl if (len > buflen) {
1992830Sdjl nss_result = NSS_STR_PARSE_ERANGE;
2002830Sdjl goto result_spd2str;
2010Sstevel@tonic-gate }
2020Sstevel@tonic-gate
2032830Sdjl if (argp->buf.result != NULL) {
2042830Sdjl be->buffer = calloc(1, len);
2052830Sdjl if (be->buffer == NULL) {
2062830Sdjl nss_result = NSS_STR_PARSE_PARSE;
2072830Sdjl goto result_spd2str;
2080Sstevel@tonic-gate }
2092830Sdjl buffer = be->buffer;
2102830Sdjl } else
2112830Sdjl buffer = argp->buf.buffer;
2120Sstevel@tonic-gate
213*8821SMichen.Chang@Sun.COM if (shadow_update_enabled) {
214*8821SMichen.Chang@Sun.COM (void) snprintf(buffer, len, "%s:%s:%s:%s:%s:%s:%s:%s:%s",
215*8821SMichen.Chang@Sun.COM uid[0], pw_passwd, last_str, min_str, max_str, warning_str,
216*8821SMichen.Chang@Sun.COM inactive_str, expire_str, flag_str);
217*8821SMichen.Chang@Sun.COM } else {
218*8821SMichen.Chang@Sun.COM (void) snprintf(buffer, len, "%s:%s:::::::%s",
219*8821SMichen.Chang@Sun.COM uid[0], pw_passwd, flag_str);
220*8821SMichen.Chang@Sun.COM }
2210Sstevel@tonic-gate
2222830Sdjl /* The front end marhsaller doesn't need the trailing null */
2232830Sdjl if (argp->buf.result != NULL)
2242830Sdjl be->buflen = strlen(be->buffer);
2252830Sdjl result_spd2str:
2260Sstevel@tonic-gate
2270Sstevel@tonic-gate (void) __ns_ldap_freeResult(&be->result);
2280Sstevel@tonic-gate return ((int)nss_result);
2290Sstevel@tonic-gate }
2300Sstevel@tonic-gate
2310Sstevel@tonic-gate /*
2320Sstevel@tonic-gate * getbynam gets a passwd entry by uid name. This function constructs an ldap
2330Sstevel@tonic-gate * search filter using the name invocation parameter and the getspnam search
2340Sstevel@tonic-gate * filter defined. Once the filter is constructed we search for a matching
2350Sstevel@tonic-gate * entry and marshal the data results into struct shadow for the frontend
2360Sstevel@tonic-gate * process. The function _nss_ldap_shadow2ent performs the data marshaling.
2370Sstevel@tonic-gate */
2380Sstevel@tonic-gate
2390Sstevel@tonic-gate static nss_status_t
getbynam(ldap_backend_ptr be,void * a)2400Sstevel@tonic-gate getbynam(ldap_backend_ptr be, void *a)
2410Sstevel@tonic-gate {
2420Sstevel@tonic-gate nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a;
2430Sstevel@tonic-gate char searchfilter[SEARCHFILTERLEN];
2440Sstevel@tonic-gate char userdata[SEARCHFILTERLEN];
2450Sstevel@tonic-gate char name[SEARCHFILTERLEN + 1];
2460Sstevel@tonic-gate int ret;
2470Sstevel@tonic-gate
2480Sstevel@tonic-gate if (_ldap_filter_name(name, argp->key.name, sizeof (name)) != 0)
2490Sstevel@tonic-gate return ((nss_status_t)NSS_NOTFOUND);
2500Sstevel@tonic-gate
2510Sstevel@tonic-gate ret = snprintf(searchfilter, sizeof (searchfilter), _F_GETSPNAM, name);
2520Sstevel@tonic-gate if (ret >= sizeof (searchfilter) || ret < 0)
2530Sstevel@tonic-gate return ((nss_status_t)NSS_NOTFOUND);
2540Sstevel@tonic-gate
2550Sstevel@tonic-gate ret = snprintf(userdata, sizeof (userdata), _F_GETSPNAM_SSD, name);
2560Sstevel@tonic-gate if (ret >= sizeof (userdata) || ret < 0)
2570Sstevel@tonic-gate return ((nss_status_t)NSS_NOTFOUND);
2580Sstevel@tonic-gate
2590Sstevel@tonic-gate return (_nss_ldap_lookup(be, argp, _SHADOW, searchfilter, NULL,
260*8821SMichen.Chang@Sun.COM _merge_SSD_filter, userdata));
2610Sstevel@tonic-gate }
2620Sstevel@tonic-gate
2630Sstevel@tonic-gate static ldap_backend_op_t sp_ops[] = {
2640Sstevel@tonic-gate _nss_ldap_destr,
2650Sstevel@tonic-gate _nss_ldap_endent,
2660Sstevel@tonic-gate _nss_ldap_setent,
2670Sstevel@tonic-gate _nss_ldap_getent,
2680Sstevel@tonic-gate getbynam
2690Sstevel@tonic-gate };
2700Sstevel@tonic-gate
2710Sstevel@tonic-gate
2720Sstevel@tonic-gate /*
2730Sstevel@tonic-gate * _nss_ldap_passwd_constr is where life begins. This function calls the
2740Sstevel@tonic-gate * generic ldap constructor function to define and build the abstract
2750Sstevel@tonic-gate * data types required to support ldap operations.
2760Sstevel@tonic-gate */
2770Sstevel@tonic-gate
2780Sstevel@tonic-gate /*ARGSUSED0*/
2790Sstevel@tonic-gate nss_backend_t *
_nss_ldap_shadow_constr(const char * dummy1,const char * dummy2,const char * dummy3)2800Sstevel@tonic-gate _nss_ldap_shadow_constr(const char *dummy1, const char *dummy2,
2810Sstevel@tonic-gate const char *dummy3)
2820Sstevel@tonic-gate {
2830Sstevel@tonic-gate
2840Sstevel@tonic-gate return ((nss_backend_t *)_nss_ldap_constr(sp_ops,
285*8821SMichen.Chang@Sun.COM sizeof (sp_ops)/sizeof (sp_ops[0]),
286*8821SMichen.Chang@Sun.COM _SHADOW, sp_attrs, _nss_ldap_shadow2str));
2870Sstevel@tonic-gate }
288