Merge remote-tracking branch 'origin/master'
[unleashed/lotheac.git] / usr / src / lib / nsswitch / ldap / common / ldap_common.c
blobfd6708495e59626ea05d3e391a265d8d75a0e509
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
22 * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
25 #include "ldap_common.h"
26 #include <malloc.h>
27 #include <synch.h>
28 #include <syslog.h>
29 #include <rpcsvc/ypclnt.h>
30 #include <rpcsvc/yp_prot.h>
31 #include <thread.h>
32 #include <ctype.h>
33 #include <stdlib.h>
34 #include <signal.h>
35 #include <sys/stat.h>
37 /* getent attributes filters */
38 #define _F_GETALIASENT "(objectClass=rfc822MailGroup)"
39 #define _F_GETAUTHNAME "(objectClass=SolarisAuthAttr)"
40 #define _F_GETEXECNAME "(objectClass=SolarisExecAttr)"
41 #define _F_GETGRENT "(objectClass=posixGroup)"
42 #define _F_GETHOSTENT "(objectClass=ipHost)"
43 #define _F_GETNETENT "(objectClass=ipNetwork)"
44 #define _F_GETPROFNAME \
45 "(&(objectClass=SolarisProfAttr)(!(SolarisKernelSecurityPolicy=*)))"
46 #define _F_GETPROTOENT "(objectClass=ipProtocol)"
47 #define _F_GETPWENT "(objectClass=posixAccount)"
48 #define _F_GETPRINTERENT "(objectClass=sunPrinter)"
49 #define _F_GETRPCENT "(objectClass=oncRpc)"
50 #define _F_GETSERVENT "(objectClass=ipService)"
51 #define _F_GETSPENT "(objectclass=shadowAccount)"
52 #define _F_GETUSERNAME "(objectClass=SolarisUserAttr)"
53 #define _F_GETPROJENT "(objectClass=SolarisProject)"
54 #define _F_GETENT_SSD "(%s)"
56 /* getent sort attributes */
57 #define _A_UID "uid"
58 #define _A_GIDNUMBER "gidnumber"
59 #define _A_CN "cn"
60 #define _A_IPNETWORKNUM "ipnetworknumber"
61 #define _A_PROJECTNAM "SolarisProjectName"
63 static struct gettablefilter {
64 char *tablename;
65 char *tablefilter;
66 char *sortattr;
67 } gettablefilterent[] = {
68 {(char *)_PASSWD, (char *)_F_GETPWENT, (char *)_A_UID},
69 {(char *)_SHADOW, (char *)_F_GETSPENT, (char *)_A_UID},
70 {(char *)_GROUP, (char *)_F_GETGRENT, (char *)_A_GIDNUMBER},
71 {(char *)_HOSTS, (char *)_F_GETHOSTENT, (char *)_A_CN},
72 {(char *)_NETWORKS, (char *)_F_GETNETENT,
73 (char *)_A_IPNETWORKNUM},
74 {(char *)_PROTOCOLS, (char *)_F_GETPROTOENT, (char *)_A_CN},
75 {(char *)_RPC, (char *)_F_GETRPCENT, (char *)_A_CN},
76 {(char *)_ALIASES, (char *)_F_GETALIASENT, (char *)_A_CN},
77 {(char *)_SERVICES, (char *)_F_GETSERVENT, (char *)_A_CN},
78 {(char *)_AUTHATTR, (char *)_F_GETAUTHNAME, (char *)_A_CN},
79 {(char *)_EXECATTR, (char *)_F_GETEXECNAME, (char *)_A_CN},
80 {(char *)_PROFATTR, (char *)_F_GETPROFNAME, (char *)_A_CN},
81 {(char *)_USERATTR, (char *)_F_GETUSERNAME, (char *)_A_UID},
82 {(char *)_PROJECT, (char *)_F_GETPROJENT, (char *)_A_PROJECTNAM},
83 {(char *)_PRINTERS, (char *)_F_GETPRINTERENT, (char *)_A_CN},
84 {NULL, NULL, NULL}
88 nss_status_t
89 switch_err(int rc, ns_ldap_error_t *error)
91 switch (rc) {
92 case NS_LDAP_SUCCESS:
93 return (NSS_SUCCESS);
95 case NS_LDAP_NOTFOUND:
96 return (NSS_NOTFOUND);
98 case NS_LDAP_PARTIAL:
99 return (NSS_TRYAGAIN);
101 case NS_LDAP_INTERNAL:
102 if (error && (error->status == LDAP_SERVER_DOWN ||
103 error->status == LDAP_TIMEOUT))
104 return (NSS_TRYAGAIN);
105 else
106 return (NSS_UNAVAIL);
108 default:
109 return (NSS_UNAVAIL);
112 /* ARGSUSED */
113 nss_status_t
114 _nss_ldap_lookup(ldap_backend_ptr be, nss_XbyY_args_t *argp,
115 char *database, char *searchfilter, char *domain,
116 int (*init_filter_cb)(const ns_ldap_search_desc_t *desc,
117 char **realfilter, const void *userdata),
118 const void *userdata)
120 int callbackstat = 0;
121 ns_ldap_error_t *error = NULL;
122 int rc;
124 #ifdef DEBUG
125 (void) fprintf(stdout, "\n[ldap_common.c: _nss_ldap_lookup]\n");
126 (void) fprintf(stdout, "\tsearchfilter: %s\n", searchfilter);
127 (void) fprintf(stdout,
128 "\tuserdata: %s\n", userdata ? userdata : "NULL");
129 (void) fprintf(stdout, "\tdatabase: %s\n", database);
130 #endif /* DEBUG */
132 (void) __ns_ldap_freeResult(&be->result);
134 if ((rc = __ns_ldap_list(database, searchfilter, init_filter_cb,
135 be->attrs, NULL, 0, &be->result, &error, NULL,
136 userdata)) != NS_LDAP_SUCCESS) {
137 argp->returnval = 0;
138 rc = switch_err(rc, error);
139 (void) __ns_ldap_freeError(&error);
141 return (rc);
143 (void) __ns_ldap_freeError(&error);
144 /* callback function */
145 if ((callbackstat =
146 be->ldapobj2str(be, argp)) != NSS_STR_PARSE_SUCCESS) {
147 goto error_out;
151 * publickey does not have a front end marshaller and expects
152 * a string to be returned in NSS.
153 * No need to convert file format -> struct.
156 if (be->db_type == NSS_LDAP_DB_PUBLICKEY) {
157 argp->returnval = argp->buf.buffer;
158 argp->returnlen = strlen(argp->buf.buffer);
159 be->db_type = NSS_LDAP_DB_NONE;
160 return (NSS_SUCCESS);
163 * Assume the switch engine wants the returned data in the file
164 * format when argp->buf.result == NULL.
165 * The front-end marshaller str2ether(ethers) uses
166 * ent (argp->buf.result) and buffer (argp->buf.buffer)
167 * for different purpose so ethers has to be treated differently.
169 if (argp->buf.result != NULL ||
170 be->db_type == NSS_LDAP_DB_ETHERS) {
171 /* file format -> struct */
172 if (argp->str2ent == NULL) {
173 callbackstat = NSS_STR_PARSE_PARSE;
174 goto error_out;
177 callbackstat = (*argp->str2ent)(be->buffer,
178 be->buflen,
179 argp->buf.result,
180 argp->buf.buffer,
181 argp->buf.buflen);
182 if (callbackstat == NSS_STR_PARSE_SUCCESS) {
183 if (be->db_type == NSS_LDAP_DB_ETHERS &&
184 argp->buf.buffer != NULL) {
185 argp->returnval = argp->buf.buffer;
186 argp->returnlen = strlen(argp->buf.buffer);
187 } else {
188 argp->returnval = argp->buf.result;
189 argp->returnlen = 1; /* irrelevant */
191 if (be->buffer != NULL) {
192 free(be->buffer);
193 be->buffer = NULL;
194 be->buflen = 0;
195 be->db_type = NSS_LDAP_DB_NONE;
197 return ((nss_status_t)NSS_SUCCESS);
199 } else {
200 /* return file format in argp->buf.buffer */
201 argp->returnval = argp->buf.buffer;
202 argp->returnlen = strlen(argp->buf.buffer);
203 return ((nss_status_t)NSS_SUCCESS);
206 error_out:
207 if (be->buffer != NULL) {
208 free(be->buffer);
209 be->buffer = NULL;
210 be->buflen = 0;
211 be->db_type = NSS_LDAP_DB_NONE;
213 /* error */
214 if (callbackstat == NSS_STR_PARSE_PARSE) {
215 argp->returnval = 0;
216 return ((nss_status_t)NSS_NOTFOUND);
218 if (callbackstat == NSS_STR_PARSE_ERANGE) {
219 argp->erange = 1;
220 return ((nss_status_t)NSS_NOTFOUND);
222 if (callbackstat == NSS_STR_PARSE_NO_ADDR) {
223 /* No IPV4 address is found */
224 argp->h_errno = HOST_NOT_FOUND;
225 return ((nss_status_t)NSS_NOTFOUND);
227 return ((nss_status_t)NSS_UNAVAIL);
231 * This function is similar to _nss_ldap_lookup except it does not
232 * do a callback. It is only used by getnetgrent.c
235 /* ARGSUSED */
236 nss_status_t
237 _nss_ldap_nocb_lookup(ldap_backend_ptr be, nss_XbyY_args_t *argp,
238 char *database, char *searchfilter, char *domain,
239 int (*init_filter_cb)(const ns_ldap_search_desc_t *desc,
240 char **realfilter, const void *userdata),
241 const void *userdata)
243 ns_ldap_error_t *error = NULL;
244 int rc;
246 #ifdef DEBUG
247 (void) fprintf(stdout, "\n[ldap_common.c: _nss_ldap_nocb_lookup]\n");
248 (void) fprintf(stdout, "\tsearchfilter: %s\n", searchfilter);
249 (void) fprintf(stdout, "\tdatabase: %s\n", database);
250 (void) fprintf(stdout,
251 "\tuserdata: %s\n", userdata ? userdata : "NULL");
252 #endif /* DEBUG */
254 (void) __ns_ldap_freeResult(&be->result);
256 if ((rc = __ns_ldap_list(database, searchfilter, init_filter_cb,
257 be->attrs, NULL, 0, &be->result, &error, NULL,
258 userdata)) != NS_LDAP_SUCCESS) {
259 if (argp != NULL)
260 argp->returnval = 0;
261 rc = switch_err(rc, error);
262 (void) __ns_ldap_freeError(&error);
263 return (rc);
266 return ((nss_status_t)NSS_SUCCESS);
274 void
275 _clean_ldap_backend(ldap_backend_ptr be)
277 ns_ldap_error_t *error;
279 #ifdef DEBUG
280 (void) fprintf(stdout, "\n[ldap_common.c: _clean_ldap_backend]\n");
281 #endif /* DEBUG */
283 free(be->tablename);
284 if (be->result != NULL)
285 (void) __ns_ldap_freeResult(&be->result);
286 if (be->enumcookie != NULL)
287 (void) __ns_ldap_endEntry(&be->enumcookie, &error);
288 if (be->services_cookie != NULL)
289 _nss_services_cookie_free((void **)&be->services_cookie);
290 if (be->toglue != NULL) {
291 free(be->toglue);
292 be->toglue = NULL;
294 if (be->buffer != NULL) {
295 free(be->buffer);
296 be->buffer = NULL;
298 free(be);
303 * _nss_ldap_destr will free all smalloc'ed variable strings and structures
304 * before exiting this nsswitch shared backend library. This function is
305 * called before returning control back to nsswitch.
308 /*ARGSUSED1*/
309 nss_status_t
310 _nss_ldap_destr(ldap_backend_ptr be, void *a)
313 #ifdef DEBUG
314 (void) fprintf(stdout, "\n[ldap_common.c: _nss_ldap_destr]\n");
315 #endif /* DEBUG */
317 (void) _clean_ldap_backend(be);
319 return ((nss_status_t)NSS_SUCCESS);
324 * _nss_ldap_setent called before _nss_ldap_getent. This function is
325 * required by POSIX.
328 nss_status_t
329 _nss_ldap_setent(ldap_backend_ptr be, void *a)
331 struct gettablefilter *gtf;
333 #ifdef DEBUG
334 (void) fprintf(stdout, "\n[ldap_common.c: _nss_ldap_setent]\n");
335 #endif /* DEBUG */
337 if (be->setcalled == 1)
338 (void) _nss_ldap_endent(be, a);
339 be->filter = NULL;
340 be->sortattr = NULL;
341 for (gtf = gettablefilterent; gtf->tablename != NULL; gtf++) {
342 if (strcmp(gtf->tablename, be->tablename))
343 continue;
344 be->filter = (char *)gtf->tablefilter;
345 be->sortattr = (char *)gtf->sortattr;
346 break;
349 be->setcalled = 1;
350 be->enumcookie = NULL;
351 be->result = NULL;
352 be->services_cookie = NULL;
353 be->buffer = NULL;
354 return ((nss_status_t)NSS_SUCCESS);
359 * _nss_ldap_endent called after _nss_ldap_getent. This function is
360 * required by POSIX.
363 /*ARGSUSED1*/
364 nss_status_t
365 _nss_ldap_endent(ldap_backend_ptr be, void *a)
367 ns_ldap_error_t *error = NULL;
369 #ifdef DEBUG
370 (void) fprintf(stdout, "\n[ldap_common.c: _nss_ldap_endent]\n");
371 #endif /* DEBUG */
373 be->setcalled = 0;
374 be->filter = NULL;
375 be->sortattr = NULL;
376 if (be->enumcookie != NULL) {
377 (void) __ns_ldap_endEntry(&be->enumcookie, &error);
378 (void) __ns_ldap_freeError(&error);
380 if (be->result != NULL) {
381 (void) __ns_ldap_freeResult(&be->result);
383 if (be->services_cookie != NULL) {
384 _nss_services_cookie_free((void **)&be->services_cookie);
386 if (be->buffer != NULL) {
387 free(be->buffer);
388 be->buffer = NULL;
391 return ((nss_status_t)NSS_SUCCESS);
399 nss_status_t
400 _nss_ldap_getent(ldap_backend_ptr be, void *a)
402 nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a;
403 ns_ldap_error_t *error = NULL;
404 int parsestat = 0;
405 int retcode = 0;
407 #ifdef DEBUG
408 (void) fprintf(stdout, "\n[ldap_common.c: _nss_ldap_getent]\n");
409 #endif /* DEBUG */
411 if (be->setcalled == 0)
412 (void) _nss_ldap_setent(be, a);
414 next_entry:
415 if (be->enumcookie == NULL) {
416 retcode = __ns_ldap_firstEntry(be->tablename,
417 be->filter, be->sortattr, _merge_SSD_filter, be->attrs,
418 NULL, 0, &be->enumcookie,
419 &be->result, &error, _F_GETENT_SSD);
420 } else {
421 if (be->services_cookie == NULL) {
422 retcode = __ns_ldap_nextEntry(be->enumcookie,
423 &be->result, &error);
426 if (retcode != NS_LDAP_SUCCESS) {
427 retcode = switch_err(retcode, error);
428 (void) __ns_ldap_freeError(&error);
429 (void) _nss_ldap_endent(be, a);
430 return (retcode);
433 if (be->result == NULL) {
434 parsestat = NSS_STR_PARSE_NO_RESULT;
435 goto error_out;
437 /* ns_ldap_entry_t -> file format */
438 if ((parsestat = be->ldapobj2str(be, argp))
439 == NSS_STR_PARSE_SUCCESS) {
440 if (argp->buf.result != NULL) {
441 /* file format -> struct */
442 if (argp->str2ent == NULL) {
443 parsestat = NSS_STR_PARSE_NO_RESULT;
444 goto error_out;
446 parsestat = (*argp->str2ent)(be->buffer,
447 be->buflen,
448 argp->buf.result,
449 argp->buf.buffer,
450 argp->buf.buflen);
451 if (parsestat == NSS_STR_PARSE_SUCCESS) {
452 if (be->buffer != NULL) {
453 free(be->buffer);
454 be->buffer = NULL;
455 be->buflen = 0;
457 be->result = NULL;
458 argp->returnval = argp->buf.result;
459 argp->returnlen = 1; /* irrevelant */
460 return ((nss_status_t)NSS_SUCCESS);
462 } else {
464 * nscd is not caching the enumerated
465 * entries. This code path would be dormant.
466 * Keep this path for the future references.
468 argp->returnval = argp->buf.buffer;
469 argp->returnlen =
470 strlen(argp->buf.buffer) + 1;
473 error_out:
474 if (be->buffer != NULL) {
475 free(be->buffer);
476 be->buffer = NULL;
477 be->buflen = 0;
479 be->result = NULL;
480 if (parsestat == NSS_STR_PARSE_NO_RESULT) {
481 argp->returnval = 0;
482 (void) _nss_ldap_endent(be, a);
483 return ((nss_status_t)NSS_NOTFOUND);
486 if (parsestat == NSS_STR_PARSE_ERANGE) {
487 argp->erange = 1;
488 (void) _nss_ldap_endent(be, a);
489 return ((nss_status_t)NSS_NOTFOUND);
491 if (parsestat == NSS_STR_PARSE_NO_ADDR)
493 * No IPV4 address is found in the current entry.
494 * It indicates that the entry contains IPV6 addresses
495 * only. Instead of calling _nss_ldap_endent to
496 * terminate, get next entry to continue enumeration.
497 * If it returned NSS_NOTFOUND here,
498 * gethostent() would return NULL
499 * and the enumeration would stop prematurely.
501 goto next_entry;
503 if (parsestat == NSS_STR_PARSE_PARSE)
505 * There has been a parse error. Most likely some
506 * mandatory attributes are missing. Ignore the error
507 * and get the next entry. If we returned an error the
508 * enumeration would stop prematurely.
510 goto next_entry;
512 return ((nss_status_t)NSS_SUCCESS);
520 nss_backend_t *
521 _nss_ldap_constr(ldap_backend_op_t ops[], int nops, char *tablename,
522 const char **attrs, fnf ldapobj2str)
524 ldap_backend_ptr be;
526 #ifdef DEBUG
527 (void) fprintf(stdout, "\n[ldap_common.c: _nss_ldap_constr]\n");
528 #endif /* DEBUG */
530 if ((be = (ldap_backend_ptr) calloc(1, sizeof (*be))) == 0)
531 return (0);
532 be->ops = ops;
533 be->nops = (nss_dbop_t)nops;
534 be->tablename = (char *)strdup(tablename);
535 be->attrs = attrs;
536 be->ldapobj2str = ldapobj2str;
538 return ((nss_backend_t *)be);
546 chophostdomain(char *string, char *host, char *domain)
548 char *dot;
550 if (string == NULL)
551 return (-1);
553 if ((dot = strchr(string, '.')) == NULL) {
554 return (0);
556 *dot = '\0';
557 (void) strcpy(host, string);
558 (void) strcpy(domain, ++dot);
560 return (0);
568 propersubdomain(char *domain, char *subdomain)
570 int domainlen, subdomainlen;
572 /* sanity check */
573 if (domain == NULL || subdomain == NULL)
574 return (-1);
576 domainlen = strlen(domain);
577 subdomainlen = strlen(subdomain);
579 /* is afterdot a substring of domain? */
580 if ((strncasecmp(domain, subdomain, subdomainlen)) != 0)
581 return (-1);
583 if (domainlen == subdomainlen)
584 return (1);
586 if (subdomainlen > domainlen)
587 return (-1);
589 if (*(domain + subdomainlen) != '.')
590 return (-1);
592 return (1);