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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <pwd.h>
30 #include "ldap_common.h"
31 
32 /* passwd attributes filters */
33 #define	_PWD_CN			"cn"
34 #define	_PWD_UID		"uid"
35 #define	_PWD_USERPASSWORD	"userpassword"
36 #define	_PWD_UIDNUMBER		"uidnumber"
37 #define	_PWD_GIDNUMBER		"gidnumber"
38 #define	_PWD_GECOS		"gecos"
39 #define	_PWD_DESCRIPTION	"description"
40 #define	_PWD_HOMEDIRECTORY	"homedirectory"
41 #define	_PWD_LOGINSHELL		"loginshell"
42 
43 
44 #define	_F_GETPWNAM		"(&(objectClass=posixAccount)(uid=%s))"
45 #define	_F_GETPWNAM_SSD		"(&(%%s)(uid=%s))"
46 #define	_F_GETPWUID		"(&(objectClass=posixAccount)(uidNumber=%ld))"
47 #define	_F_GETPWUID_SSD		"(&(%%s)(uidNumber=%ld))"
48 
49 static const char *pwd_attrs[] = {
50 	_PWD_CN,
51 	_PWD_UID,
52 	_PWD_UIDNUMBER,
53 	_PWD_GIDNUMBER,
54 	_PWD_GECOS,
55 	_PWD_DESCRIPTION,
56 	_PWD_HOMEDIRECTORY,
57 	_PWD_LOGINSHELL,
58 	(char *)NULL
59 };
60 
61 
62 /*
63  * _nss_ldap_passwd2ent is the data marshaling method for the passwd getXbyY
64  * (e.g., getbyuid(), getbyname(), getpwent()) backend processes. This method is
65  * called after a successful ldap search has been performed. This method will
66  * parse the ldap search values into struct passwd = argp->buf.buffer which
67  * the frontend process expects. Three error conditions are expected and
68  * returned to nsswitch.
69  */
70 
71 static int
72 _nss_ldap_passwd2ent(ldap_backend_ptr be, nss_XbyY_args_t *argp)
73 {
74 	int		i = 0;
75 	int		nss_result;
76 	int		buflen = (int)0;
77 	unsigned long	len = 0L;
78 	char		*buffer = (char *)NULL;
79 	char		*ptr2x;
80 	char		*ceiling = (char *)NULL;
81 	char		*nullstring = (char *)NULL;
82 	struct passwd	*pwd = (struct passwd *)NULL;
83 	ns_ldap_result_t	*result = be->result;
84 	ns_ldap_attr_t	*attrptr;
85 	int		have_uid = 0;
86 	int		have_uidn = 0;
87 	int		have_gidn = 0;
88 
89 #ifdef	DEBUG
90 	(void) fprintf(stdout, "\n[getpwnam.c: _nss_ldap_passwd2ent]\n");
91 #endif	/* DEBUG */
92 
93 	buffer = argp->buf.buffer;
94 	buflen = (size_t)argp->buf.buflen;
95 	if (!argp->buf.result) {
96 		nss_result = (int)NSS_STR_PARSE_ERANGE;
97 		goto result_pwd2ent;
98 	}
99 	pwd = (struct passwd *)argp->buf.result;
100 	ceiling = buffer + buflen;
101 	nullstring = (buffer + (buflen - 1));
102 
103 	nss_result = (int)NSS_STR_PARSE_SUCCESS;
104 	(void) memset(buffer, 0, buflen);
105 
106 	/*
107 	 * need to always return password as "x"
108 	 * so put "x" at top of the buffer
109 	 */
110 	ptr2x = buffer;
111 	*buffer++ = 'x';
112 	*buffer++ = '\0';
113 
114 	attrptr = getattr(result, 0);
115 	if (attrptr == NULL) {
116 		nss_result = (int)NSS_STR_PARSE_PARSE;
117 		goto result_pwd2ent;
118 	}
119 
120 	pwd->pw_gecos = nullstring;
121 	pwd->pw_dir = nullstring;
122 	pwd->pw_shell = nullstring;
123 
124 	for (i = 0; i < result->entry->attr_count; i++) {
125 		attrptr = getattr(result, i);
126 		if (attrptr == NULL) {
127 			nss_result = (int)NSS_STR_PARSE_PARSE;
128 			goto result_pwd2ent;
129 		}
130 		if (strcasecmp(attrptr->attrname, _PWD_UID) == 0) {
131 			if ((attrptr->attrvalue[0] == NULL) ||
132 			    (len = strlen(attrptr->attrvalue[0])) < 1) {
133 				nss_result = (int)NSS_STR_PARSE_PARSE;
134 				goto result_pwd2ent;
135 			}
136 			pwd->pw_name = buffer;
137 			buffer += len + 1;
138 			if (buffer >= ceiling) {
139 				nss_result = (int)NSS_STR_PARSE_ERANGE;
140 				goto result_pwd2ent;
141 			}
142 			(void) strcpy(pwd->pw_name, attrptr->attrvalue[0]);
143 			have_uid = 1;
144 			continue;
145 		}
146 		if (strcasecmp(attrptr->attrname, _PWD_UIDNUMBER) == 0) {
147 			if (attrptr->attrvalue[0] == '\0') {
148 				nss_result = (int)NSS_STR_PARSE_PARSE;
149 				goto result_pwd2ent;
150 			}
151 			pwd->pw_uid = strtol(attrptr->attrvalue[0],
152 					    (char **)NULL, 10);
153 			have_uidn = 1;
154 			continue;
155 		}
156 		if (strcasecmp(attrptr->attrname, _PWD_GIDNUMBER) == 0) {
157 			if (attrptr->attrvalue[0] == '\0') {
158 				nss_result = (int)NSS_STR_PARSE_PARSE;
159 				goto result_pwd2ent;
160 			}
161 			pwd->pw_gid = strtol(attrptr->attrvalue[0],
162 					    (char **)NULL, 10);
163 			have_gidn = 1;
164 			continue;
165 		}
166 		if ((strcasecmp(attrptr->attrname, _PWD_GECOS) == 0) &&
167 		    (attrptr->value_count > 0)) {
168 			if ((attrptr->attrvalue[0] == NULL) ||
169 			    (len = strlen(attrptr->attrvalue[0])) < 1) {
170 				pwd->pw_gecos = nullstring;
171 			} else {
172 				pwd->pw_gecos = buffer;
173 				buffer += len + 1;
174 				if (buffer >= ceiling) {
175 					nss_result = (int)NSS_STR_PARSE_ERANGE;
176 					goto result_pwd2ent;
177 				}
178 				(void) strcpy(pwd->pw_gecos,
179 					    attrptr->attrvalue[0]);
180 			}
181 			continue;
182 		}
183 		if ((strcasecmp(attrptr->attrname, _PWD_HOMEDIRECTORY) == 0) &&
184 		    (attrptr->value_count > 0)) {
185 			if ((attrptr->attrvalue[0] == NULL) ||
186 			    (len = strlen(attrptr->attrvalue[0])) < 1) {
187 				pwd->pw_dir = nullstring;
188 			} else {
189 				pwd->pw_dir = buffer;
190 				buffer += len + 1;
191 				if (buffer >= ceiling) {
192 					nss_result = (int)NSS_STR_PARSE_ERANGE;
193 					goto result_pwd2ent;
194 				}
195 				(void) strcpy(pwd->pw_dir,
196 				    attrptr->attrvalue[0]);
197 			}
198 			continue;
199 		}
200 		if ((strcasecmp(attrptr->attrname, _PWD_LOGINSHELL) == 0) &&
201 		    (attrptr->value_count > 0)) {
202 			if ((attrptr->attrvalue[0] == NULL) ||
203 			    (len = strlen(attrptr->attrvalue[0])) < 1) {
204 				pwd->pw_shell = nullstring;
205 			} else {
206 				pwd->pw_shell = buffer;
207 				buffer += len + 1;
208 				if (buffer >= ceiling) {
209 					nss_result = (int)NSS_STR_PARSE_ERANGE;
210 					goto result_pwd2ent;
211 				}
212 				(void) strcpy(pwd->pw_shell,
213 				    attrptr->attrvalue[0]);
214 			}
215 			continue;
216 		}
217 	}
218 
219 	/* error if missing required attributes */
220 	if (have_uid == 0 || have_uidn == 0 || have_gidn == 0) {
221 		nss_result = (int)NSS_STR_PARSE_PARSE;
222 	}
223 
224 	pwd->pw_age = nullstring;
225 	pwd->pw_comment = nullstring;
226 	pwd->pw_passwd = ptr2x;
227 
228 #ifdef	DEBUG
229 	(void) fprintf(stdout, "\n[getpwnam.c: _nss_ldap_passwd2ent]\n");
230 	(void) fprintf(stdout, "       pw_name: [%s]\n", pwd->pw_name);
231 	(void) fprintf(stdout, "        pw_uid: [%ld]\n", pwd->pw_uid);
232 	(void) fprintf(stdout, "        pw_gid: [%ld]\n", pwd->pw_gid);
233 	(void) fprintf(stdout, "      pw_gecos: [%s]\n", pwd->pw_gecos);
234 	(void) fprintf(stdout, "        pw_dir: [%s]\n", pwd->pw_dir);
235 	(void) fprintf(stdout, "      pw_shell: [%s]\n", pwd->pw_shell);
236 #endif	/* DEBUG */
237 
238 result_pwd2ent:
239 
240 	(void) __ns_ldap_freeResult(&be->result);
241 	return ((int)nss_result);
242 }
243 
244 
245 /*
246  * getbyname gets a passwd entry by uid name. This function constructs an ldap
247  * search filter using the name invocation parameter and the getpwnam search
248  * filter defined. Once the filter is constructed, we search for a matching
249  * entry and marshal the data results into struct passwd for the frontend
250  * process. The function _nss_ldap_passwd2ent performs the data marshaling.
251  */
252 
253 static nss_status_t
254 getbyname(ldap_backend_ptr be, void *a)
255 {
256 	nss_XbyY_args_t	*argp = (nss_XbyY_args_t *)a;
257 	char		searchfilter[SEARCHFILTERLEN];
258 	char		userdata[SEARCHFILTERLEN];
259 	char		name[SEARCHFILTERLEN];
260 	int		ret;
261 
262 #ifdef	DEBUG
263 	(void) fprintf(stdout, "\n[getpwnam.c: getbyname]\n");
264 #endif	/* DEBUG */
265 
266 	if (_ldap_filter_name(name, argp->key.name, sizeof (name)) != 0)
267 		return ((nss_status_t)NSS_NOTFOUND);
268 
269 	ret = snprintf(searchfilter, sizeof (searchfilter), _F_GETPWNAM, name);
270 	if (ret >= sizeof (searchfilter) || ret < 0)
271 		return ((nss_status_t)NSS_NOTFOUND);
272 
273 	ret = snprintf(userdata, sizeof (userdata), _F_GETPWNAM_SSD, name);
274 	if (ret >= sizeof (userdata) || ret < 0)
275 		return ((nss_status_t)NSS_NOTFOUND);
276 
277 	return ((nss_status_t)_nss_ldap_lookup(be, argp,
278 		_PASSWD, searchfilter, NULL,
279 		_merge_SSD_filter, userdata));
280 }
281 
282 
283 /*
284  * getbyuid gets a passwd entry by uid number. This function constructs an ldap
285  * search filter using the uid invocation parameter and the getpwuid search
286  * filter defined. Once the filter is constructed, we search for a matching
287  * entry and marshal the data results into struct passwd for the frontend
288  * process. The function _nss_ldap_passwd2ent performs the data marshaling.
289  */
290 
291 static nss_status_t
292 getbyuid(ldap_backend_ptr be, void *a)
293 {
294 	nss_XbyY_args_t	*argp = (nss_XbyY_args_t *)a;
295 	char		searchfilter[SEARCHFILTERLEN];
296 	char		userdata[SEARCHFILTERLEN];
297 	int		ret;
298 
299 #ifdef	DEBUG
300 	(void) fprintf(stdout, "\n[getpwnam.c: getbyuid]\n");
301 #endif	/* DEBUG */
302 
303 	ret = snprintf(searchfilter, sizeof (searchfilter),
304 	    _F_GETPWUID, (long)argp->key.uid);
305 	if (ret >= sizeof (searchfilter) || ret < 0)
306 		return ((nss_status_t)NSS_NOTFOUND);
307 
308 	ret = snprintf(userdata, sizeof (userdata),
309 	    _F_GETPWUID_SSD, (long)argp->key.uid);
310 	if (ret >= sizeof (userdata) || ret < 0)
311 		return ((nss_status_t)NSS_NOTFOUND);
312 
313 	return ((nss_status_t)_nss_ldap_lookup(be, argp,
314 		_PASSWD, searchfilter, NULL,
315 		_merge_SSD_filter, userdata));
316 }
317 
318 static ldap_backend_op_t passwd_ops[] = {
319 	_nss_ldap_destr,
320 	_nss_ldap_endent,
321 	_nss_ldap_setent,
322 	_nss_ldap_getent,
323 	getbyname,
324 	getbyuid
325 };
326 
327 
328 /*
329  * _nss_ldap_passwd_constr is where life begins. This function calls the
330  * generic ldap constructor function to define and build the abstract
331  * data types required to support ldap operations.
332  */
333 
334 /*ARGSUSED0*/
335 nss_backend_t *
336 _nss_ldap_passwd_constr(const char *dummy1, const char *dummy2,
337 			const char *dummy3)
338 {
339 
340 #ifdef	DEBUG
341 	(void) fprintf(stdout, "\n[getpwnam.c: _nss_ldap_passwd_constr]\n");
342 #endif	/* DEBUG */
343 
344 	return ((nss_backend_t *)_nss_ldap_constr(passwd_ops,
345 		    sizeof (passwd_ops)/sizeof (passwd_ops[0]),
346 		    _PASSWD, pwd_attrs, _nss_ldap_passwd2ent));
347 }
348