xref: /titanic_52/usr/src/lib/nsswitch/ldap/common/ldap_common.c (revision fa9e4066f08beec538e775443c5be79dd423fcab)
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 "ldap_common.h"
30 #include <malloc.h>
31 #include <synch.h>
32 #include <syslog.h>
33 #include <rpcsvc/ypclnt.h>
34 #include <rpcsvc/yp_prot.h>
35 #include <thread.h>
36 #include <ctype.h>
37 #include <stdlib.h>
38 #include <signal.h>
39 #include <sys/stat.h>
40 
41 /* getent attributes filters */
42 #define	_F_GETALIASENT		"(objectClass=rfc822MailGroup)"
43 #define	_F_GETAUTHNAME		"(objectClass=SolarisAuthAttr)"
44 #define	_F_GETAUUSERNAME	"(objectClass=SolarisAuditUser)"
45 #define	_F_GETEXECNAME		"(objectClass=SolarisExecAttr)"
46 #define	_F_GETGRENT		"(objectClass=posixGroup)"
47 #define	_F_GETHOSTENT		"(objectClass=ipHost)"
48 #define	_F_GETNETENT		"(objectClass=ipNetwork)"
49 #define	_F_GETPROFNAME		"(objectClass=SolarisProfAttr)"
50 #define	_F_GETPROTOENT		"(objectClass=ipProtocol)"
51 #define	_F_GETPWENT		"(objectClass=posixAccount)"
52 #define	_F_GETPRINTERENT	"(objectClass=sunPrinter)"
53 #define	_F_GETRPCENT		"(objectClass=oncRpc)"
54 #define	_F_GETSERVENT		"(objectClass=ipService)"
55 #define	_F_GETSPENT		"(objectclass=shadowAccount)"
56 #define	_F_GETUSERNAME		"(objectClass=SolarisUserAttr)"
57 #define	_F_GETPROJENT		"(objectClass=SolarisProject)"
58 #define	_F_GETENT_SSD		"(%s)"
59 
60 static struct gettablefilter {
61 	char *tablename;
62 	char *tablefilter;
63 } gettablefilterent[] = {
64 	{(char *)_PASSWD,	(char *)_F_GETPWENT},
65 	{(char *)_SHADOW,	(char *)_F_GETSPENT},
66 	{(char *)_GROUP,	(char *)_F_GETGRENT},
67 	{(char *)_HOSTS,	(char *)_F_GETHOSTENT},
68 	{(char *)_NETWORKS,	(char *)_F_GETNETENT},
69 	{(char *)_PROTOCOLS,	(char *)_F_GETPROTOENT},
70 	{(char *)_RPC,		(char *)_F_GETRPCENT},
71 	{(char *)_ALIASES,	(char *)_F_GETALIASENT},
72 	{(char *)_SERVICES,	(char *)_F_GETSERVENT},
73 	{(char *)_AUUSER,	(char *)_F_GETAUUSERNAME},
74 	{(char *)_AUTHATTR,	(char *)_F_GETAUTHNAME},
75 	{(char *)_EXECATTR,	(char *)_F_GETEXECNAME},
76 	{(char *)_PROFATTR,	(char *)_F_GETPROFNAME},
77 	{(char *)_USERATTR,	(char *)_F_GETUSERNAME},
78 	{(char *)_PROJECT,	(char *)_F_GETPROJENT},
79 	{(char *)_PRINTERS,	(char *)_F_GETPRINTERENT},
80 	{(char *)NULL,		(char *)NULL}
81 };
82 
83 
84 nss_status_t
85 switch_err(int rc, ns_ldap_error_t *error)
86 {
87 	switch (rc) {
88 	    case NS_LDAP_SUCCESS:
89 		return (NSS_SUCCESS);
90 
91 	    case NS_LDAP_NOTFOUND:
92 		return (NSS_NOTFOUND);
93 
94 	    case NS_LDAP_PARTIAL:
95 		return (NSS_TRYAGAIN);
96 
97 	    case NS_LDAP_INTERNAL:
98 		    if (error && (error->status == LDAP_SERVER_DOWN ||
99 				error->status == LDAP_TIMEOUT))
100 			    return (NSS_TRYAGAIN);
101 		    else
102 			    return (NSS_UNAVAIL);
103 
104 	    default:
105 		return (NSS_UNAVAIL);
106 	}
107 }
108 nss_status_t
109 _nss_ldap_lookup(ldap_backend_ptr be, nss_XbyY_args_t *argp,
110 		char *database, char *searchfilter, char *domain,
111 		int (*init_filter_cb)(const ns_ldap_search_desc_t *desc,
112 		char **realfilter, const void *userdata),
113 		const void *userdata)
114 {
115 	int		callbackstat = 0;
116 	ns_ldap_error_t	*error = NULL;
117 	int		rc;
118 
119 #ifdef	DEBUG
120 	(void) fprintf(stdout, "\n[ldap_common.c: _nss_ldap_lookup]\n");
121 	(void) fprintf(stdout, "\tsearchfilter: %s\n", searchfilter);
122 	(void) fprintf(stdout,
123 		"\tuserdata: %s\n", userdata ? userdata : "NULL");
124 	(void) fprintf(stdout, "\tdatabase: %s\n", database);
125 #endif	/* DEBUG */
126 
127 	(void) __ns_ldap_freeResult(&be->result);
128 
129 	if ((rc = __ns_ldap_list(database, searchfilter, init_filter_cb,
130 		be->attrs, NULL, 0, &be->result, &error, NULL,
131 		userdata)) != NS_LDAP_SUCCESS) {
132 		argp->returnval = 0;
133 		rc = switch_err(rc, error);
134 		(void) __ns_ldap_freeError(&error);
135 		return (rc);
136 	}
137 	/* callback function */
138 	if ((callbackstat =
139 		    be->ldapobj2ent(be, argp)) == NSS_STR_PARSE_SUCCESS) {
140 		argp->returnval = argp->buf.result;
141 		return ((nss_status_t)NSS_SUCCESS);
142 	}
143 	(void) __ns_ldap_freeResult(&be->result);
144 
145 	/* error */
146 	if (callbackstat == NSS_STR_PARSE_PARSE) {
147 		argp->returnval = 0;
148 		return ((nss_status_t)NSS_NOTFOUND);
149 	}
150 	if (callbackstat == NSS_STR_PARSE_ERANGE) {
151 		argp->erange = 1;
152 		return ((nss_status_t)NSS_NOTFOUND);
153 	}
154 	if (callbackstat == NSS_STR_PARSE_NO_ADDR) {
155 		/* No IPV4 address is found */
156 		argp->h_errno = HOST_NOT_FOUND;
157 		return ((nss_status_t)NSS_NOTFOUND);
158 	}
159 	return ((nss_status_t)NSS_UNAVAIL);
160 }
161 
162 
163 /*
164  *  This function is similar to _nss_ldap_lookup except it does not
165  *  do a callback.  It is only used by getnetgrent.c
166  */
167 
168 nss_status_t
169 _nss_ldap_nocb_lookup(ldap_backend_ptr be, nss_XbyY_args_t *argp,
170 		char *database, char *searchfilter, char *domain,
171 		int (*init_filter_cb)(const ns_ldap_search_desc_t *desc,
172 		char **realfilter, const void *userdata),
173 		const void *userdata)
174 {
175 	ns_ldap_error_t	*error = NULL;
176 	int		rc;
177 
178 #ifdef	DEBUG
179 	(void) fprintf(stdout, "\n[ldap_common.c: _nss_ldap_nocb_lookup]\n");
180 	(void) fprintf(stdout, "\tsearchfilter: %s\n", searchfilter);
181 	(void) fprintf(stdout, "\tdatabase: %s\n", database);
182 	(void) fprintf(stdout,
183 		"\tuserdata: %s\n", userdata ? userdata : "NULL");
184 #endif	/* DEBUG */
185 
186 	(void) __ns_ldap_freeResult(&be->result);
187 
188 	if ((rc = __ns_ldap_list(database, searchfilter, init_filter_cb,
189 		be->attrs, NULL, 0, &be->result, &error, NULL,
190 		userdata)) != NS_LDAP_SUCCESS) {
191 		argp->returnval = 0;
192 		rc = switch_err(rc, error);
193 		(void) __ns_ldap_freeError(&error);
194 		return (rc);
195 	}
196 
197 	return ((nss_status_t)NSS_SUCCESS);
198 }
199 
200 
201 /*
202  *
203  */
204 
205 void
206 _clean_ldap_backend(ldap_backend_ptr be)
207 {
208 	ns_ldap_error_t *error;
209 
210 #ifdef	DEBUG
211 	(void) fprintf(stdout, "\n[ldap_common.c: _clean_ldap_backend]\n");
212 #endif	/* DEBUG */
213 
214 	if (be->tablename != NULL)
215 		free(be->tablename);
216 	if (be->result != NULL)
217 		(void) __ns_ldap_freeResult(&be->result);
218 	if (be->enumcookie != NULL)
219 		(void) __ns_ldap_endEntry(&be->enumcookie, &error);
220 	if (be->services_cookie != NULL)
221 		_nss_services_cookie_free((void **)&be->services_cookie);
222 	if (be->toglue != NULL) {
223 		free(be->toglue);
224 		be->toglue = NULL;
225 	}
226 	free(be);
227 }
228 
229 
230 /*
231  * _nss_ldap_destr will free all smalloc'ed variable strings and structures
232  * before exiting this nsswitch shared backend library. This function is
233  * called before returning control back to nsswitch.
234  */
235 
236 /*ARGSUSED1*/
237 nss_status_t
238 _nss_ldap_destr(ldap_backend_ptr be, void *a)
239 {
240 
241 #ifdef DEBUG
242 	(void) fprintf(stdout, "\n[ldap_common.c: _nss_ldap_destr]\n");
243 #endif /* DEBUG */
244 
245 	(void) _clean_ldap_backend(be);
246 
247 	return ((nss_status_t)NSS_SUCCESS);
248 }
249 
250 
251 /*
252  * _nss_ldap_setent called before _nss_ldap_getent. This function is
253  * required by POSIX.
254  */
255 
256 nss_status_t
257 _nss_ldap_setent(ldap_backend_ptr be, void *a)
258 {
259 	struct gettablefilter	*gtf;
260 
261 #ifdef DEBUG
262 	(void) fprintf(stdout, "\n[ldap_common.c: _nss_ldap_setent]\n");
263 #endif /* DEBUG */
264 
265 	if (be->setcalled == 1)
266 		(void) _nss_ldap_endent(be, a);
267 	be->filter = NULL;
268 	for (gtf = gettablefilterent; gtf->tablename != (char *)NULL; gtf++) {
269 		if (strcmp(gtf->tablename, be->tablename))
270 			continue;
271 		be->filter = (char *)gtf->tablefilter;
272 		break;
273 	}
274 
275 	be->setcalled = 1;
276 	be->enumcookie = NULL;
277 	be->result = NULL;
278 	be->services_cookie = NULL;
279 	return ((nss_status_t)NSS_SUCCESS);
280 }
281 
282 
283 /*
284  * _nss_ldap_endent called after _nss_ldap_getent. This function is
285  * required by POSIX.
286  */
287 
288 /*ARGSUSED1*/
289 nss_status_t
290 _nss_ldap_endent(ldap_backend_ptr be, void *a)
291 {
292 	ns_ldap_error_t	*error = NULL;
293 
294 #ifdef DEBUG
295 	(void) fprintf(stdout, "\n[ldap_common.c: _nss_ldap_endent]\n");
296 #endif /* DEBUG */
297 
298 	be->setcalled = 0;
299 	be->filter = NULL;
300 	if (be->enumcookie != NULL) {
301 		(void) __ns_ldap_endEntry(&be->enumcookie, &error);
302 		(void) __ns_ldap_freeError(&error);
303 	}
304 	if (be->result != NULL) {
305 		(void) __ns_ldap_freeResult(&be->result);
306 	}
307 	if (be->services_cookie != NULL) {
308 		_nss_services_cookie_free((void **)&be->services_cookie);
309 	}
310 
311 	return ((nss_status_t)NSS_SUCCESS);
312 }
313 
314 
315 /*
316  *
317  */
318 
319 nss_status_t
320 _nss_ldap_getent(ldap_backend_ptr be, void *a)
321 {
322 	nss_XbyY_args_t	*argp = (nss_XbyY_args_t *)a;
323 	ns_ldap_error_t	*error = NULL;
324 	int		parsestat = 0;
325 	int		retcode = 0;
326 
327 #ifdef	DEBUG
328 	(void) fprintf(stdout, "\n[ldap_common.c: _nss_ldap_getent]\n");
329 #endif	/* DEBUG */
330 
331 	if (be->setcalled == 0)
332 		(void) _nss_ldap_setent(be, a);
333 
334 next_entry:
335 	if (be->enumcookie == NULL) {
336 		retcode = __ns_ldap_firstEntry(be->tablename,
337 		be->filter, _merge_SSD_filter, be->attrs, NULL,
338 		0, &be->enumcookie,
339 		&be->result, &error, _F_GETENT_SSD);
340 	} else {
341 		if (be->services_cookie == NULL) {
342 			retcode = __ns_ldap_nextEntry(be->enumcookie,
343 				&be->result, &error);
344 		}
345 	}
346 	if (retcode != NS_LDAP_SUCCESS) {
347 		retcode = switch_err(retcode, error);
348 		(void) __ns_ldap_freeError(&error);
349 		(void) _nss_ldap_endent(be, a);
350 		return (retcode);
351 	} else {
352 		if ((parsestat = be->ldapobj2ent(be, argp))
353 			== NSS_STR_PARSE_SUCCESS) {
354 			be->result = NULL;
355 			argp->returnval = argp->buf.result;
356 			return ((nss_status_t)NSS_SUCCESS);
357 		}
358 		be->result = NULL;
359 		if (parsestat == NSS_STR_PARSE_PARSE) {
360 			argp->returnval = 0;
361 			(void) _nss_ldap_endent(be, a);
362 			return ((nss_status_t)NSS_NOTFOUND);
363 		}
364 
365 		if (parsestat == NSS_STR_PARSE_ERANGE) {
366 			argp->erange = 1;
367 			(void) _nss_ldap_endent(be, a);
368 			return ((nss_status_t)NSS_NOTFOUND);
369 		}
370 		if (parsestat == NSS_STR_PARSE_NO_ADDR)
371 			/*
372 			 * No IPV4 address is found in the current entry.
373 			 * It indicates that the entry contains IPV6 addresses
374 			 * only. Instead of calling _nss_ldap_endent to
375 			 * terminate, get next entry to continue enumeration.
376 			 * If it returned NSS_NOTFOUND here,
377 			 * gethostent() would return NULL
378 			 * and the enumeration would stop prematurely.
379 			 */
380 			goto next_entry;
381 	}
382 
383 	return ((nss_status_t)NSS_SUCCESS);
384 }
385 
386 
387 /*
388  *
389  */
390 
391 nss_backend_t *
392 _nss_ldap_constr(ldap_backend_op_t ops[], int nops, char *tablename,
393 		const char **attrs, fnf ldapobj2ent)
394 {
395 	ldap_backend_ptr	be;
396 
397 #ifdef	DEBUG
398 	(void) fprintf(stdout, "\n[ldap_common.c: _nss_ldap_constr]\n");
399 #endif	/* DEBUG */
400 
401 	if ((be = (ldap_backend_ptr) malloc(sizeof (*be))) == 0)
402 		return (0);
403 	be->ops = ops;
404 	be->nops = (nss_dbop_t)nops;
405 	be->tablename = (char *)strdup(tablename);
406 	be->attrs = attrs;
407 	be->result = NULL;
408 	be->ldapobj2ent = ldapobj2ent;
409 	be->setcalled = 0;
410 	be->filter = NULL;
411 	be->enumcookie = NULL;
412 	be->netgroup_cookie = NULL;
413 	be->services_cookie = NULL;
414 	be->toglue = NULL;
415 
416 	return ((nss_backend_t *)be);
417 }
418 
419 
420 /*
421  *
422  */
423 int
424 chophostdomain(char *string, char *host, char *domain)
425 {
426 	char	*dot;
427 
428 	if (string == NULL)
429 		return (-1);
430 
431 	if ((dot = strchr(string, '.')) == NULL) {
432 		return (0);
433 	}
434 	*dot = '\0';
435 	strcpy(host, string);
436 	strcpy(domain, ++dot);
437 
438 	return (0);
439 }
440 
441 
442 /*
443  *
444  */
445 int
446 propersubdomain(char *domain, char *subdomain)
447 {
448 	int	domainlen, subdomainlen;
449 
450 	/* sanity check */
451 	if (domain == NULL || subdomain == NULL)
452 		return (-1);
453 
454 	domainlen = strlen(domain);
455 	subdomainlen = strlen(subdomain);
456 
457 	/* is afterdot a substring of domain? */
458 	if ((strncasecmp(domain, subdomain, subdomainlen)) != 0)
459 		return (-1);
460 
461 	if (domainlen == subdomainlen)
462 		return (1);
463 
464 	if (subdomainlen > domainlen)
465 		return (-1);
466 
467 	if (*(domain + subdomainlen) != '.')
468 		return (-1);
469 
470 	return (1);
471 }
472