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 (the "License").
6 * You may not use this file except in compliance with the License.
7 *
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.
12 *
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]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
23 * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
24 */
25
26 #include "ldap_common.h"
27 #include <malloc.h>
28 #include <synch.h>
29 #include <syslog.h>
30 #include <rpcsvc/ypclnt.h>
31 #include <rpcsvc/yp_prot.h>
32 #include <thread.h>
33 #include <ctype.h>
34 #include <stdlib.h>
35 #include <signal.h>
36 #include <sys/stat.h>
37
38 /* getent attributes filters */
39 #define _F_GETALIASENT "(objectClass=rfc822MailGroup)"
40 #define _F_GETAUTHNAME "(objectClass=SolarisAuthAttr)"
41 #define _F_GETAUUSERNAME "(objectClass=SolarisAuditUser)"
42 #define _F_GETEXECNAME "(objectClass=SolarisExecAttr)"
43 #define _F_GETGRENT "(objectClass=posixGroup)"
44 #define _F_GETHOSTENT "(objectClass=ipHost)"
45 #define _F_GETNETENT "(objectClass=ipNetwork)"
46 #define _F_GETPROFNAME \
47 "(&(objectClass=SolarisProfAttr)(!(SolarisKernelSecurityPolicy=*)))"
48 #define _F_GETPROTOENT "(objectClass=ipProtocol)"
49 #define _F_GETPWENT "(objectClass=posixAccount)"
50 #define _F_GETPRINTERENT "(objectClass=sunPrinter)"
51 #define _F_GETRPCENT "(objectClass=oncRpc)"
52 #define _F_GETSERVENT "(objectClass=ipService)"
53 #define _F_GETSPENT "(objectclass=shadowAccount)"
54 #define _F_GETUSERNAME "(objectClass=SolarisUserAttr)"
55 #define _F_GETPROJENT "(objectClass=SolarisProject)"
56 #define _F_GETTNRHDB "(objectClass=ipTnetHost)"
57 #define _F_GETTNRHTP "(&(objectClass=ipTnetTemplate)"\
58 "(SolarisAttrKeyValue=*))"
59 #define _F_GETENT_SSD "(%s)"
60
61 /* getent sort attributes */
62 #define _A_UID "uid"
63 #define _A_GIDNUMBER "gidnumber"
64 #define _A_CN "cn"
65 #define _A_IPNETWORKNUM "ipnetworknumber"
66 #define _A_PROJECTNAM "SolarisProjectName"
67 #define _A_IPTNETNUM "ipTnetNumber"
68 #define _A_IPTNETTMPLNAM "ipTnetTemplateName"
69
70 static struct gettablefilter {
71 char *tablename;
72 char *tablefilter;
73 char *sortattr;
74 } gettablefilterent[] = {
75 {(char *)_PASSWD, (char *)_F_GETPWENT, (char *)_A_UID},
76 {(char *)_SHADOW, (char *)_F_GETSPENT, (char *)_A_UID},
77 {(char *)_GROUP, (char *)_F_GETGRENT, (char *)_A_GIDNUMBER},
78 {(char *)_HOSTS, (char *)_F_GETHOSTENT, (char *)_A_CN},
79 {(char *)_NETWORKS, (char *)_F_GETNETENT,
80 (char *)_A_IPNETWORKNUM},
81 {(char *)_PROTOCOLS, (char *)_F_GETPROTOENT, (char *)_A_CN},
82 {(char *)_RPC, (char *)_F_GETRPCENT, (char *)_A_CN},
83 {(char *)_ALIASES, (char *)_F_GETALIASENT, (char *)_A_CN},
84 {(char *)_SERVICES, (char *)_F_GETSERVENT, (char *)_A_CN},
85 {(char *)_AUUSER, (char *)_F_GETAUUSERNAME,
86 (char *)_A_UID},
87 {(char *)_AUTHATTR, (char *)_F_GETAUTHNAME, (char *)_A_CN},
88 {(char *)_EXECATTR, (char *)_F_GETEXECNAME, (char *)_A_CN},
89 {(char *)_PROFATTR, (char *)_F_GETPROFNAME, (char *)_A_CN},
90 {(char *)_USERATTR, (char *)_F_GETUSERNAME, (char *)_A_UID},
91 {(char *)_PROJECT, (char *)_F_GETPROJENT, (char *)_A_PROJECTNAM},
92 {(char *)_PRINTERS, (char *)_F_GETPRINTERENT, (char *)_A_CN},
93 {(char *)_TNRHDB, (char *)_F_GETTNRHDB, (char *)_A_IPTNETNUM},
94 {(char *)_TNRHTP, (char *)_F_GETTNRHTP,
95 (char *)_A_IPTNETTMPLNAM},
96 {(char *)NULL, (char *)NULL, (char *)NULL}
97 };
98
99
100 nss_status_t
switch_err(int rc,ns_ldap_error_t * error)101 switch_err(int rc, ns_ldap_error_t *error)
102 {
103 switch (rc) {
104 case NS_LDAP_SUCCESS:
105 return (NSS_SUCCESS);
106
107 case NS_LDAP_NOTFOUND:
108 errno = 0;
109 return (NSS_NOTFOUND);
110
111 case NS_LDAP_PARTIAL:
112 return (NSS_TRYAGAIN);
113
114 case NS_LDAP_INTERNAL:
115 if (error && (error->status == LDAP_SERVER_DOWN ||
116 error->status == LDAP_TIMEOUT))
117 return (NSS_TRYAGAIN);
118 else
119 return (NSS_UNAVAIL);
120
121 default:
122 return (NSS_UNAVAIL);
123 }
124 }
125 /* ARGSUSED */
126 nss_status_t
_nss_ldap_lookup(ldap_backend_ptr be,nss_XbyY_args_t * argp,char * database,char * searchfilter,char * domain,int (* init_filter_cb)(const ns_ldap_search_desc_t * desc,char ** realfilter,const void * userdata),const void * userdata)127 _nss_ldap_lookup(ldap_backend_ptr be, nss_XbyY_args_t *argp,
128 char *database, char *searchfilter, char *domain,
129 int (*init_filter_cb)(const ns_ldap_search_desc_t *desc,
130 char **realfilter, const void *userdata),
131 const void *userdata)
132 {
133 int callbackstat = 0;
134 ns_ldap_error_t *error = NULL;
135 int rc;
136
137 #ifdef DEBUG
138 (void) fprintf(stdout, "\n[ldap_common.c: _nss_ldap_lookup]\n");
139 (void) fprintf(stdout, "\tsearchfilter: %s\n", searchfilter);
140 (void) fprintf(stdout,
141 "\tuserdata: %s\n", userdata ? userdata : "NULL");
142 (void) fprintf(stdout, "\tdatabase: %s\n", database);
143 #endif /* DEBUG */
144
145 (void) __ns_ldap_freeResult(&be->result);
146
147 if ((rc = __ns_ldap_list(database, searchfilter, init_filter_cb,
148 be->attrs, NULL, 0, &be->result, &error, NULL,
149 userdata)) != NS_LDAP_SUCCESS) {
150 argp->returnval = 0;
151 rc = switch_err(rc, error);
152 (void) __ns_ldap_freeError(&error);
153
154 return (rc);
155 }
156 (void) __ns_ldap_freeError(&error);
157 /* callback function */
158 if ((callbackstat =
159 be->ldapobj2str(be, argp)) != NSS_STR_PARSE_SUCCESS) {
160 goto error_out;
161 }
162
163 /*
164 * publickey does not have a front end marshaller and expects
165 * a string to be returned in NSS.
166 * No need to convert file format -> struct.
167 *
168 */
169 if (be->db_type == NSS_LDAP_DB_PUBLICKEY) {
170 argp->returnval = argp->buf.buffer;
171 argp->returnlen = strlen(argp->buf.buffer);
172 be->db_type = NSS_LDAP_DB_NONE;
173 return (NSS_SUCCESS);
174 }
175 /*
176 * Assume the switch engine wants the returned data in the file
177 * format when argp->buf.result == NULL.
178 * The front-end marshaller str2ether(ethers) uses
179 * ent (argp->buf.result) and buffer (argp->buf.buffer)
180 * for different purpose so ethers has to be treated differently.
181 */
182 if (argp->buf.result != NULL ||
183 be->db_type == NSS_LDAP_DB_ETHERS) {
184 /* file format -> struct */
185 if (argp->str2ent == NULL) {
186 callbackstat = NSS_STR_PARSE_PARSE;
187 goto error_out;
188 }
189
190 callbackstat = (*argp->str2ent)(be->buffer,
191 be->buflen,
192 argp->buf.result,
193 argp->buf.buffer,
194 argp->buf.buflen);
195 if (callbackstat == NSS_STR_PARSE_SUCCESS) {
196 if (be->db_type == NSS_LDAP_DB_ETHERS &&
197 argp->buf.buffer != NULL) {
198 argp->returnval = argp->buf.buffer;
199 argp->returnlen = strlen(argp->buf.buffer);
200 } else {
201 argp->returnval = argp->buf.result;
202 argp->returnlen = 1; /* irrelevant */
203 }
204 if (be->buffer != NULL) {
205 free(be->buffer);
206 be->buffer = NULL;
207 be->buflen = 0;
208 be->db_type = NSS_LDAP_DB_NONE;
209 }
210 return ((nss_status_t)NSS_SUCCESS);
211 }
212 } else {
213 /* return file format in argp->buf.buffer */
214 argp->returnval = argp->buf.buffer;
215 argp->returnlen = strlen(argp->buf.buffer);
216 return ((nss_status_t)NSS_SUCCESS);
217 }
218
219 error_out:
220 if (be->buffer != NULL) {
221 free(be->buffer);
222 be->buffer = NULL;
223 be->buflen = 0;
224 be->db_type = NSS_LDAP_DB_NONE;
225 }
226 /* error */
227 if (callbackstat == NSS_STR_PARSE_PARSE) {
228 argp->returnval = 0;
229 return ((nss_status_t)NSS_NOTFOUND);
230 }
231 if (callbackstat == NSS_STR_PARSE_ERANGE) {
232 argp->erange = 1;
233 return ((nss_status_t)NSS_NOTFOUND);
234 }
235 if (callbackstat == NSS_STR_PARSE_NO_ADDR) {
236 /* No IPV4 address is found */
237 argp->h_errno = HOST_NOT_FOUND;
238 return ((nss_status_t)NSS_NOTFOUND);
239 }
240 return ((nss_status_t)NSS_UNAVAIL);
241 }
242
243 /*
244 * This function is similar to _nss_ldap_lookup except it does not
245 * do a callback. It is only used by getnetgrent.c
246 */
247
248 /* ARGSUSED */
249 nss_status_t
_nss_ldap_nocb_lookup(ldap_backend_ptr be,nss_XbyY_args_t * argp,char * database,char * searchfilter,const char * const * attrs,int (* init_filter_cb)(const ns_ldap_search_desc_t * desc,char ** realfilter,const void * userdata),const void * userdata)250 _nss_ldap_nocb_lookup(ldap_backend_ptr be, nss_XbyY_args_t *argp,
251 char *database, char *searchfilter, const char * const *attrs,
252 int (*init_filter_cb)(const ns_ldap_search_desc_t *desc,
253 char **realfilter, const void *userdata),
254 const void *userdata)
255 {
256 ns_ldap_error_t *error = NULL;
257 int rc;
258
259 if (attrs == NULL)
260 attrs = be->attrs;
261
262 #ifdef DEBUG
263 (void) fprintf(stdout, "\n[ldap_common.c: _nss_ldap_nocb_lookup]\n");
264 (void) fprintf(stdout, "\tsearchfilter: %s\n", searchfilter);
265 (void) fprintf(stdout, "\tdatabase: %s\n", database);
266 (void) fprintf(stdout,
267 "\tuserdata: %s\n", userdata ? userdata : "NULL");
268 #endif /* DEBUG */
269
270 (void) __ns_ldap_freeResult(&be->result);
271
272 if ((rc = __ns_ldap_list(database, searchfilter, init_filter_cb,
273 attrs, NULL, 0, &be->result, &error, NULL,
274 userdata)) != NS_LDAP_SUCCESS) {
275 if (argp != NULL)
276 argp->returnval = 0;
277 rc = switch_err(rc, error);
278 (void) __ns_ldap_freeError(&error);
279 return (rc);
280 }
281
282 return ((nss_status_t)NSS_SUCCESS);
283 }
284
285
286 /*
287 *
288 */
289
290 void
_clean_ldap_backend(ldap_backend_ptr be)291 _clean_ldap_backend(ldap_backend_ptr be)
292 {
293 ns_ldap_error_t *error;
294
295 #ifdef DEBUG
296 (void) fprintf(stdout, "\n[ldap_common.c: _clean_ldap_backend]\n");
297 #endif /* DEBUG */
298
299 if (be->tablename != NULL)
300 free(be->tablename);
301 if (be->result != NULL)
302 (void) __ns_ldap_freeResult(&be->result);
303 if (be->enumcookie != NULL)
304 (void) __ns_ldap_endEntry(&be->enumcookie, &error);
305 if (be->services_cookie != NULL)
306 _nss_services_cookie_free((void **)&be->services_cookie);
307 if (be->toglue != NULL) {
308 free(be->toglue);
309 be->toglue = NULL;
310 }
311 if (be->buffer != NULL) {
312 free(be->buffer);
313 be->buffer = NULL;
314 }
315 free(be);
316 }
317
318
319 /*
320 * _nss_ldap_destr will free all smalloc'ed variable strings and structures
321 * before exiting this nsswitch shared backend library. This function is
322 * called before returning control back to nsswitch.
323 */
324
325 /*ARGSUSED1*/
326 nss_status_t
_nss_ldap_destr(ldap_backend_ptr be,void * a)327 _nss_ldap_destr(ldap_backend_ptr be, void *a)
328 {
329
330 #ifdef DEBUG
331 (void) fprintf(stdout, "\n[ldap_common.c: _nss_ldap_destr]\n");
332 #endif /* DEBUG */
333
334 (void) _clean_ldap_backend(be);
335
336 return ((nss_status_t)NSS_SUCCESS);
337 }
338
339
340 /*
341 * _nss_ldap_setent called before _nss_ldap_getent. This function is
342 * required by POSIX.
343 */
344
345 nss_status_t
_nss_ldap_setent(ldap_backend_ptr be,void * a)346 _nss_ldap_setent(ldap_backend_ptr be, void *a)
347 {
348 struct gettablefilter *gtf;
349
350 #ifdef DEBUG
351 (void) fprintf(stdout, "\n[ldap_common.c: _nss_ldap_setent]\n");
352 #endif /* DEBUG */
353
354 if (be->setcalled == 1)
355 (void) _nss_ldap_endent(be, a);
356 be->filter = NULL;
357 be->sortattr = NULL;
358 for (gtf = gettablefilterent; gtf->tablename != (char *)NULL; gtf++) {
359 if (strcmp(gtf->tablename, be->tablename))
360 continue;
361 be->filter = (char *)gtf->tablefilter;
362 be->sortattr = (char *)gtf->sortattr;
363 break;
364 }
365
366 be->setcalled = 1;
367 be->enumcookie = NULL;
368 be->result = NULL;
369 be->services_cookie = NULL;
370 be->buffer = NULL;
371 return ((nss_status_t)NSS_SUCCESS);
372 }
373
374
375 /*
376 * _nss_ldap_endent called after _nss_ldap_getent. This function is
377 * required by POSIX.
378 */
379
380 /*ARGSUSED1*/
381 nss_status_t
_nss_ldap_endent(ldap_backend_ptr be,void * a)382 _nss_ldap_endent(ldap_backend_ptr be, void *a)
383 {
384 ns_ldap_error_t *error = NULL;
385
386 #ifdef DEBUG
387 (void) fprintf(stdout, "\n[ldap_common.c: _nss_ldap_endent]\n");
388 #endif /* DEBUG */
389
390 be->setcalled = 0;
391 be->filter = NULL;
392 be->sortattr = NULL;
393 if (be->enumcookie != NULL) {
394 (void) __ns_ldap_endEntry(&be->enumcookie, &error);
395 (void) __ns_ldap_freeError(&error);
396 }
397 if (be->result != NULL) {
398 (void) __ns_ldap_freeResult(&be->result);
399 }
400 if (be->services_cookie != NULL) {
401 _nss_services_cookie_free((void **)&be->services_cookie);
402 }
403 if (be->buffer != NULL) {
404 free(be->buffer);
405 be->buffer = NULL;
406 }
407
408 return ((nss_status_t)NSS_SUCCESS);
409 }
410
411
412 /*
413 *
414 */
415
416 nss_status_t
_nss_ldap_getent(ldap_backend_ptr be,void * a)417 _nss_ldap_getent(ldap_backend_ptr be, void *a)
418 {
419 nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a;
420 ns_ldap_error_t *error = NULL;
421 int parsestat = 0;
422 int retcode = 0;
423
424 #ifdef DEBUG
425 (void) fprintf(stdout, "\n[ldap_common.c: _nss_ldap_getent]\n");
426 #endif /* DEBUG */
427
428 if (be->setcalled == 0)
429 (void) _nss_ldap_setent(be, a);
430
431 next_entry:
432 if (be->enumcookie == NULL) {
433 retcode = __ns_ldap_firstEntry(be->tablename,
434 be->filter, be->sortattr, _merge_SSD_filter, be->attrs,
435 NULL, 0, &be->enumcookie,
436 &be->result, &error, _F_GETENT_SSD);
437 } else {
438 if (be->services_cookie == NULL) {
439 retcode = __ns_ldap_nextEntry(be->enumcookie,
440 &be->result, &error);
441 }
442 }
443 if (retcode != NS_LDAP_SUCCESS) {
444 retcode = switch_err(retcode, error);
445 (void) __ns_ldap_freeError(&error);
446 (void) _nss_ldap_endent(be, a);
447 return (retcode);
448 }
449
450 if (be->result == NULL) {
451 parsestat = NSS_STR_PARSE_NO_RESULT;
452 goto error_out;
453 }
454 /* ns_ldap_entry_t -> file format */
455 if ((parsestat = be->ldapobj2str(be, argp))
456 == NSS_STR_PARSE_SUCCESS) {
457 if (argp->buf.result != NULL) {
458 /* file format -> struct */
459 if (argp->str2ent == NULL) {
460 parsestat = NSS_STR_PARSE_NO_RESULT;
461 goto error_out;
462 }
463 parsestat = (*argp->str2ent)(be->buffer,
464 be->buflen,
465 argp->buf.result,
466 argp->buf.buffer,
467 argp->buf.buflen);
468 if (parsestat == NSS_STR_PARSE_SUCCESS) {
469 if (be->buffer != NULL) {
470 free(be->buffer);
471 be->buffer = NULL;
472 be->buflen = 0;
473 }
474 be->result = NULL;
475 argp->returnval = argp->buf.result;
476 argp->returnlen = 1; /* irrevelant */
477 return ((nss_status_t)NSS_SUCCESS);
478 }
479 } else {
480 /*
481 * nscd is not caching the enumerated
482 * entries. This code path would be dormant.
483 * Keep this path for the future references.
484 */
485 argp->returnval = argp->buf.buffer;
486 argp->returnlen =
487 strlen(argp->buf.buffer) + 1;
488 }
489 }
490 error_out:
491 if (be->buffer != NULL) {
492 free(be->buffer);
493 be->buffer = NULL;
494 be->buflen = 0;
495 }
496 be->result = NULL;
497 if (parsestat == NSS_STR_PARSE_NO_RESULT) {
498 argp->returnval = 0;
499 (void) _nss_ldap_endent(be, a);
500 return ((nss_status_t)NSS_NOTFOUND);
501 }
502
503 if (parsestat == NSS_STR_PARSE_ERANGE) {
504 argp->erange = 1;
505 (void) _nss_ldap_endent(be, a);
506 return ((nss_status_t)NSS_NOTFOUND);
507 }
508 if (parsestat == NSS_STR_PARSE_NO_ADDR)
509 /*
510 * No IPV4 address is found in the current entry.
511 * It indicates that the entry contains IPV6 addresses
512 * only. Instead of calling _nss_ldap_endent to
513 * terminate, get next entry to continue enumeration.
514 * If it returned NSS_NOTFOUND here,
515 * gethostent() would return NULL
516 * and the enumeration would stop prematurely.
517 */
518 goto next_entry;
519
520 if (parsestat == NSS_STR_PARSE_PARSE)
521 /*
522 * There has been a parse error. Most likely some
523 * mandatory attributes are missing. Ignore the error
524 * and get the next entry. If we returned an error the
525 * enumeration would stop prematurely.
526 */
527 goto next_entry;
528
529 return ((nss_status_t)NSS_SUCCESS);
530 }
531
532
533 /*
534 *
535 */
536
537 nss_backend_t *
_nss_ldap_constr(ldap_backend_op_t ops[],int nops,char * tablename,const char ** attrs,fnf ldapobj2str)538 _nss_ldap_constr(ldap_backend_op_t ops[], int nops, char *tablename,
539 const char **attrs, fnf ldapobj2str)
540 {
541 ldap_backend_ptr be;
542
543 #ifdef DEBUG
544 (void) fprintf(stdout, "\n[ldap_common.c: _nss_ldap_constr]\n");
545 #endif /* DEBUG */
546
547 if ((be = (ldap_backend_ptr) calloc(1, sizeof (*be))) == 0)
548 return (0);
549 be->ops = ops;
550 be->nops = (nss_dbop_t)nops;
551 be->tablename = (char *)strdup(tablename);
552 be->attrs = attrs;
553 be->ldapobj2str = ldapobj2str;
554
555 return ((nss_backend_t *)be);
556 }
557
558
559 /*
560 *
561 */
562 int
chophostdomain(char * string,char * host,char * domain)563 chophostdomain(char *string, char *host, char *domain)
564 {
565 char *dot;
566
567 if (string == NULL)
568 return (-1);
569
570 if ((dot = strchr(string, '.')) == NULL) {
571 return (0);
572 }
573 *dot = '\0';
574 (void) strcpy(host, string);
575 (void) strcpy(domain, ++dot);
576
577 return (0);
578 }
579
580
581 /*
582 *
583 */
584 int
propersubdomain(char * domain,char * subdomain)585 propersubdomain(char *domain, char *subdomain)
586 {
587 int domainlen, subdomainlen;
588
589 /* sanity check */
590 if (domain == NULL || subdomain == NULL)
591 return (-1);
592
593 domainlen = strlen(domain);
594 subdomainlen = strlen(subdomain);
595
596 /* is afterdot a substring of domain? */
597 if ((strncasecmp(domain, subdomain, subdomainlen)) != 0)
598 return (-1);
599
600 if (domainlen == subdomainlen)
601 return (1);
602
603 if (subdomainlen > domainlen)
604 return (-1);
605
606 if (*(domain + subdomainlen) != '.')
607 return (-1);
608
609 return (1);
610 }
611