kill tsol ("Trusted Solaris") aka TX ("Trusted Extensions")
[unleashed.git] / usr / src / lib / nsswitch / ldap / common / ldap_common.c
blob4663237eb9d56053b3da9191cf64dccbcd383aea
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_GETAUUSERNAME "(objectClass=SolarisAuditUser)"
41 #define _F_GETEXECNAME "(objectClass=SolarisExecAttr)"
42 #define _F_GETGRENT "(objectClass=posixGroup)"
43 #define _F_GETHOSTENT "(objectClass=ipHost)"
44 #define _F_GETNETENT "(objectClass=ipNetwork)"
45 #define _F_GETPROFNAME \
46 "(&(objectClass=SolarisProfAttr)(!(SolarisKernelSecurityPolicy=*)))"
47 #define _F_GETPROTOENT "(objectClass=ipProtocol)"
48 #define _F_GETPWENT "(objectClass=posixAccount)"
49 #define _F_GETPRINTERENT "(objectClass=sunPrinter)"
50 #define _F_GETRPCENT "(objectClass=oncRpc)"
51 #define _F_GETSERVENT "(objectClass=ipService)"
52 #define _F_GETSPENT "(objectclass=shadowAccount)"
53 #define _F_GETUSERNAME "(objectClass=SolarisUserAttr)"
54 #define _F_GETPROJENT "(objectClass=SolarisProject)"
55 #define _F_GETENT_SSD "(%s)"
57 /* getent sort attributes */
58 #define _A_UID "uid"
59 #define _A_GIDNUMBER "gidnumber"
60 #define _A_CN "cn"
61 #define _A_IPNETWORKNUM "ipnetworknumber"
62 #define _A_PROJECTNAM "SolarisProjectName"
64 static struct gettablefilter {
65 char *tablename;
66 char *tablefilter;
67 char *sortattr;
68 } gettablefilterent[] = {
69 {(char *)_PASSWD, (char *)_F_GETPWENT, (char *)_A_UID},
70 {(char *)_SHADOW, (char *)_F_GETSPENT, (char *)_A_UID},
71 {(char *)_GROUP, (char *)_F_GETGRENT, (char *)_A_GIDNUMBER},
72 {(char *)_HOSTS, (char *)_F_GETHOSTENT, (char *)_A_CN},
73 {(char *)_NETWORKS, (char *)_F_GETNETENT,
74 (char *)_A_IPNETWORKNUM},
75 {(char *)_PROTOCOLS, (char *)_F_GETPROTOENT, (char *)_A_CN},
76 {(char *)_RPC, (char *)_F_GETRPCENT, (char *)_A_CN},
77 {(char *)_ALIASES, (char *)_F_GETALIASENT, (char *)_A_CN},
78 {(char *)_SERVICES, (char *)_F_GETSERVENT, (char *)_A_CN},
79 {(char *)_AUUSER, (char *)_F_GETAUUSERNAME,
80 (char *)_A_UID},
81 {(char *)_AUTHATTR, (char *)_F_GETAUTHNAME, (char *)_A_CN},
82 {(char *)_EXECATTR, (char *)_F_GETEXECNAME, (char *)_A_CN},
83 {(char *)_PROFATTR, (char *)_F_GETPROFNAME, (char *)_A_CN},
84 {(char *)_USERATTR, (char *)_F_GETUSERNAME, (char *)_A_UID},
85 {(char *)_PROJECT, (char *)_F_GETPROJENT, (char *)_A_PROJECTNAM},
86 {(char *)_PRINTERS, (char *)_F_GETPRINTERENT, (char *)_A_CN},
87 {(char *)NULL, (char *)NULL, (char *)NULL}
91 nss_status_t
92 switch_err(int rc, ns_ldap_error_t *error)
94 switch (rc) {
95 case NS_LDAP_SUCCESS:
96 return (NSS_SUCCESS);
98 case NS_LDAP_NOTFOUND:
99 return (NSS_NOTFOUND);
101 case NS_LDAP_PARTIAL:
102 return (NSS_TRYAGAIN);
104 case NS_LDAP_INTERNAL:
105 if (error && (error->status == LDAP_SERVER_DOWN ||
106 error->status == LDAP_TIMEOUT))
107 return (NSS_TRYAGAIN);
108 else
109 return (NSS_UNAVAIL);
111 default:
112 return (NSS_UNAVAIL);
115 /* ARGSUSED */
116 nss_status_t
117 _nss_ldap_lookup(ldap_backend_ptr be, nss_XbyY_args_t *argp,
118 char *database, char *searchfilter, char *domain,
119 int (*init_filter_cb)(const ns_ldap_search_desc_t *desc,
120 char **realfilter, const void *userdata),
121 const void *userdata)
123 int callbackstat = 0;
124 ns_ldap_error_t *error = NULL;
125 int rc;
127 #ifdef DEBUG
128 (void) fprintf(stdout, "\n[ldap_common.c: _nss_ldap_lookup]\n");
129 (void) fprintf(stdout, "\tsearchfilter: %s\n", searchfilter);
130 (void) fprintf(stdout,
131 "\tuserdata: %s\n", userdata ? userdata : "NULL");
132 (void) fprintf(stdout, "\tdatabase: %s\n", database);
133 #endif /* DEBUG */
135 (void) __ns_ldap_freeResult(&be->result);
137 if ((rc = __ns_ldap_list(database, searchfilter, init_filter_cb,
138 be->attrs, NULL, 0, &be->result, &error, NULL,
139 userdata)) != NS_LDAP_SUCCESS) {
140 argp->returnval = 0;
141 rc = switch_err(rc, error);
142 (void) __ns_ldap_freeError(&error);
144 return (rc);
146 (void) __ns_ldap_freeError(&error);
147 /* callback function */
148 if ((callbackstat =
149 be->ldapobj2str(be, argp)) != NSS_STR_PARSE_SUCCESS) {
150 goto error_out;
154 * publickey does not have a front end marshaller and expects
155 * a string to be returned in NSS.
156 * No need to convert file format -> struct.
159 if (be->db_type == NSS_LDAP_DB_PUBLICKEY) {
160 argp->returnval = argp->buf.buffer;
161 argp->returnlen = strlen(argp->buf.buffer);
162 be->db_type = NSS_LDAP_DB_NONE;
163 return (NSS_SUCCESS);
166 * Assume the switch engine wants the returned data in the file
167 * format when argp->buf.result == NULL.
168 * The front-end marshaller str2ether(ethers) uses
169 * ent (argp->buf.result) and buffer (argp->buf.buffer)
170 * for different purpose so ethers has to be treated differently.
172 if (argp->buf.result != NULL ||
173 be->db_type == NSS_LDAP_DB_ETHERS) {
174 /* file format -> struct */
175 if (argp->str2ent == NULL) {
176 callbackstat = NSS_STR_PARSE_PARSE;
177 goto error_out;
180 callbackstat = (*argp->str2ent)(be->buffer,
181 be->buflen,
182 argp->buf.result,
183 argp->buf.buffer,
184 argp->buf.buflen);
185 if (callbackstat == NSS_STR_PARSE_SUCCESS) {
186 if (be->db_type == NSS_LDAP_DB_ETHERS &&
187 argp->buf.buffer != NULL) {
188 argp->returnval = argp->buf.buffer;
189 argp->returnlen = strlen(argp->buf.buffer);
190 } else {
191 argp->returnval = argp->buf.result;
192 argp->returnlen = 1; /* irrelevant */
194 if (be->buffer != NULL) {
195 free(be->buffer);
196 be->buffer = NULL;
197 be->buflen = 0;
198 be->db_type = NSS_LDAP_DB_NONE;
200 return ((nss_status_t)NSS_SUCCESS);
202 } else {
203 /* return file format in argp->buf.buffer */
204 argp->returnval = argp->buf.buffer;
205 argp->returnlen = strlen(argp->buf.buffer);
206 return ((nss_status_t)NSS_SUCCESS);
209 error_out:
210 if (be->buffer != NULL) {
211 free(be->buffer);
212 be->buffer = NULL;
213 be->buflen = 0;
214 be->db_type = NSS_LDAP_DB_NONE;
216 /* error */
217 if (callbackstat == NSS_STR_PARSE_PARSE) {
218 argp->returnval = 0;
219 return ((nss_status_t)NSS_NOTFOUND);
221 if (callbackstat == NSS_STR_PARSE_ERANGE) {
222 argp->erange = 1;
223 return ((nss_status_t)NSS_NOTFOUND);
225 if (callbackstat == NSS_STR_PARSE_NO_ADDR) {
226 /* No IPV4 address is found */
227 argp->h_errno = HOST_NOT_FOUND;
228 return ((nss_status_t)NSS_NOTFOUND);
230 return ((nss_status_t)NSS_UNAVAIL);
234 * This function is similar to _nss_ldap_lookup except it does not
235 * do a callback. It is only used by getnetgrent.c
238 /* ARGSUSED */
239 nss_status_t
240 _nss_ldap_nocb_lookup(ldap_backend_ptr be, nss_XbyY_args_t *argp,
241 char *database, char *searchfilter, char *domain,
242 int (*init_filter_cb)(const ns_ldap_search_desc_t *desc,
243 char **realfilter, const void *userdata),
244 const void *userdata)
246 ns_ldap_error_t *error = NULL;
247 int rc;
249 #ifdef DEBUG
250 (void) fprintf(stdout, "\n[ldap_common.c: _nss_ldap_nocb_lookup]\n");
251 (void) fprintf(stdout, "\tsearchfilter: %s\n", searchfilter);
252 (void) fprintf(stdout, "\tdatabase: %s\n", database);
253 (void) fprintf(stdout,
254 "\tuserdata: %s\n", userdata ? userdata : "NULL");
255 #endif /* DEBUG */
257 (void) __ns_ldap_freeResult(&be->result);
259 if ((rc = __ns_ldap_list(database, searchfilter, init_filter_cb,
260 be->attrs, NULL, 0, &be->result, &error, NULL,
261 userdata)) != NS_LDAP_SUCCESS) {
262 if (argp != NULL)
263 argp->returnval = 0;
264 rc = switch_err(rc, error);
265 (void) __ns_ldap_freeError(&error);
266 return (rc);
269 return ((nss_status_t)NSS_SUCCESS);
277 void
278 _clean_ldap_backend(ldap_backend_ptr be)
280 ns_ldap_error_t *error;
282 #ifdef DEBUG
283 (void) fprintf(stdout, "\n[ldap_common.c: _clean_ldap_backend]\n");
284 #endif /* DEBUG */
286 free(be->tablename);
287 if (be->result != NULL)
288 (void) __ns_ldap_freeResult(&be->result);
289 if (be->enumcookie != NULL)
290 (void) __ns_ldap_endEntry(&be->enumcookie, &error);
291 if (be->services_cookie != NULL)
292 _nss_services_cookie_free((void **)&be->services_cookie);
293 if (be->toglue != NULL) {
294 free(be->toglue);
295 be->toglue = NULL;
297 if (be->buffer != NULL) {
298 free(be->buffer);
299 be->buffer = NULL;
301 free(be);
306 * _nss_ldap_destr will free all smalloc'ed variable strings and structures
307 * before exiting this nsswitch shared backend library. This function is
308 * called before returning control back to nsswitch.
311 /*ARGSUSED1*/
312 nss_status_t
313 _nss_ldap_destr(ldap_backend_ptr be, void *a)
316 #ifdef DEBUG
317 (void) fprintf(stdout, "\n[ldap_common.c: _nss_ldap_destr]\n");
318 #endif /* DEBUG */
320 (void) _clean_ldap_backend(be);
322 return ((nss_status_t)NSS_SUCCESS);
327 * _nss_ldap_setent called before _nss_ldap_getent. This function is
328 * required by POSIX.
331 nss_status_t
332 _nss_ldap_setent(ldap_backend_ptr be, void *a)
334 struct gettablefilter *gtf;
336 #ifdef DEBUG
337 (void) fprintf(stdout, "\n[ldap_common.c: _nss_ldap_setent]\n");
338 #endif /* DEBUG */
340 if (be->setcalled == 1)
341 (void) _nss_ldap_endent(be, a);
342 be->filter = NULL;
343 be->sortattr = NULL;
344 for (gtf = gettablefilterent; gtf->tablename != (char *)NULL; gtf++) {
345 if (strcmp(gtf->tablename, be->tablename))
346 continue;
347 be->filter = (char *)gtf->tablefilter;
348 be->sortattr = (char *)gtf->sortattr;
349 break;
352 be->setcalled = 1;
353 be->enumcookie = NULL;
354 be->result = NULL;
355 be->services_cookie = NULL;
356 be->buffer = NULL;
357 return ((nss_status_t)NSS_SUCCESS);
362 * _nss_ldap_endent called after _nss_ldap_getent. This function is
363 * required by POSIX.
366 /*ARGSUSED1*/
367 nss_status_t
368 _nss_ldap_endent(ldap_backend_ptr be, void *a)
370 ns_ldap_error_t *error = NULL;
372 #ifdef DEBUG
373 (void) fprintf(stdout, "\n[ldap_common.c: _nss_ldap_endent]\n");
374 #endif /* DEBUG */
376 be->setcalled = 0;
377 be->filter = NULL;
378 be->sortattr = NULL;
379 if (be->enumcookie != NULL) {
380 (void) __ns_ldap_endEntry(&be->enumcookie, &error);
381 (void) __ns_ldap_freeError(&error);
383 if (be->result != NULL) {
384 (void) __ns_ldap_freeResult(&be->result);
386 if (be->services_cookie != NULL) {
387 _nss_services_cookie_free((void **)&be->services_cookie);
389 if (be->buffer != NULL) {
390 free(be->buffer);
391 be->buffer = NULL;
394 return ((nss_status_t)NSS_SUCCESS);
402 nss_status_t
403 _nss_ldap_getent(ldap_backend_ptr be, void *a)
405 nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a;
406 ns_ldap_error_t *error = NULL;
407 int parsestat = 0;
408 int retcode = 0;
410 #ifdef DEBUG
411 (void) fprintf(stdout, "\n[ldap_common.c: _nss_ldap_getent]\n");
412 #endif /* DEBUG */
414 if (be->setcalled == 0)
415 (void) _nss_ldap_setent(be, a);
417 next_entry:
418 if (be->enumcookie == NULL) {
419 retcode = __ns_ldap_firstEntry(be->tablename,
420 be->filter, be->sortattr, _merge_SSD_filter, be->attrs,
421 NULL, 0, &be->enumcookie,
422 &be->result, &error, _F_GETENT_SSD);
423 } else {
424 if (be->services_cookie == NULL) {
425 retcode = __ns_ldap_nextEntry(be->enumcookie,
426 &be->result, &error);
429 if (retcode != NS_LDAP_SUCCESS) {
430 retcode = switch_err(retcode, error);
431 (void) __ns_ldap_freeError(&error);
432 (void) _nss_ldap_endent(be, a);
433 return (retcode);
436 if (be->result == NULL) {
437 parsestat = NSS_STR_PARSE_NO_RESULT;
438 goto error_out;
440 /* ns_ldap_entry_t -> file format */
441 if ((parsestat = be->ldapobj2str(be, argp))
442 == NSS_STR_PARSE_SUCCESS) {
443 if (argp->buf.result != NULL) {
444 /* file format -> struct */
445 if (argp->str2ent == NULL) {
446 parsestat = NSS_STR_PARSE_NO_RESULT;
447 goto error_out;
449 parsestat = (*argp->str2ent)(be->buffer,
450 be->buflen,
451 argp->buf.result,
452 argp->buf.buffer,
453 argp->buf.buflen);
454 if (parsestat == NSS_STR_PARSE_SUCCESS) {
455 if (be->buffer != NULL) {
456 free(be->buffer);
457 be->buffer = NULL;
458 be->buflen = 0;
460 be->result = NULL;
461 argp->returnval = argp->buf.result;
462 argp->returnlen = 1; /* irrevelant */
463 return ((nss_status_t)NSS_SUCCESS);
465 } else {
467 * nscd is not caching the enumerated
468 * entries. This code path would be dormant.
469 * Keep this path for the future references.
471 argp->returnval = argp->buf.buffer;
472 argp->returnlen =
473 strlen(argp->buf.buffer) + 1;
476 error_out:
477 if (be->buffer != NULL) {
478 free(be->buffer);
479 be->buffer = NULL;
480 be->buflen = 0;
482 be->result = NULL;
483 if (parsestat == NSS_STR_PARSE_NO_RESULT) {
484 argp->returnval = 0;
485 (void) _nss_ldap_endent(be, a);
486 return ((nss_status_t)NSS_NOTFOUND);
489 if (parsestat == NSS_STR_PARSE_ERANGE) {
490 argp->erange = 1;
491 (void) _nss_ldap_endent(be, a);
492 return ((nss_status_t)NSS_NOTFOUND);
494 if (parsestat == NSS_STR_PARSE_NO_ADDR)
496 * No IPV4 address is found in the current entry.
497 * It indicates that the entry contains IPV6 addresses
498 * only. Instead of calling _nss_ldap_endent to
499 * terminate, get next entry to continue enumeration.
500 * If it returned NSS_NOTFOUND here,
501 * gethostent() would return NULL
502 * and the enumeration would stop prematurely.
504 goto next_entry;
506 if (parsestat == NSS_STR_PARSE_PARSE)
508 * There has been a parse error. Most likely some
509 * mandatory attributes are missing. Ignore the error
510 * and get the next entry. If we returned an error the
511 * enumeration would stop prematurely.
513 goto next_entry;
515 return ((nss_status_t)NSS_SUCCESS);
523 nss_backend_t *
524 _nss_ldap_constr(ldap_backend_op_t ops[], int nops, char *tablename,
525 const char **attrs, fnf ldapobj2str)
527 ldap_backend_ptr be;
529 #ifdef DEBUG
530 (void) fprintf(stdout, "\n[ldap_common.c: _nss_ldap_constr]\n");
531 #endif /* DEBUG */
533 if ((be = (ldap_backend_ptr) calloc(1, sizeof (*be))) == 0)
534 return (0);
535 be->ops = ops;
536 be->nops = (nss_dbop_t)nops;
537 be->tablename = (char *)strdup(tablename);
538 be->attrs = attrs;
539 be->ldapobj2str = ldapobj2str;
541 return ((nss_backend_t *)be);
549 chophostdomain(char *string, char *host, char *domain)
551 char *dot;
553 if (string == NULL)
554 return (-1);
556 if ((dot = strchr(string, '.')) == NULL) {
557 return (0);
559 *dot = '\0';
560 (void) strcpy(host, string);
561 (void) strcpy(domain, ++dot);
563 return (0);
571 propersubdomain(char *domain, char *subdomain)
573 int domainlen, subdomainlen;
575 /* sanity check */
576 if (domain == NULL || subdomain == NULL)
577 return (-1);
579 domainlen = strlen(domain);
580 subdomainlen = strlen(subdomain);
582 /* is afterdot a substring of domain? */
583 if ((strncasecmp(domain, subdomain, subdomainlen)) != 0)
584 return (-1);
586 if (domainlen == subdomainlen)
587 return (1);
589 if (subdomainlen > domainlen)
590 return (-1);
592 if (*(domain + subdomainlen) != '.')
593 return (-1);
595 return (1);