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 2017 Nexenta Systems, Inc. All rights reserved.
24 * Copyright 2020 Joyent, Inc.
25 */
26
27 #include <stdio.h>
28 #include <sys/types.h>
29 #include <stdlib.h>
30 #include <libintl.h>
31 #include <ctype.h>
32 #include <syslog.h>
33 #include <sys/stat.h>
34 #include <fcntl.h>
35 #include <unistd.h>
36 #include <string.h>
37 #include <strings.h>
38 #include <priv.h>
39
40 #include "ns_sldap.h"
41 #include "ns_internal.h"
42 #include "ns_cache_door.h"
43 #include "ns_connmgmt.h"
44
45 #define _NIS_FILTER "nisdomain=*"
46 #define _NIS_DOMAIN "nisdomain"
47 static const char *nis_domain_attrs[] = {
48 _NIS_DOMAIN,
49 (char *)NULL
50 };
51
52 static int validate_filter(ns_ldap_cookie_t *cookie);
53
54 void
__ns_ldap_freeEntry(ns_ldap_entry_t * ep)55 __ns_ldap_freeEntry(ns_ldap_entry_t *ep)
56 {
57 int j, k = 0;
58
59 if (ep == NULL)
60 return;
61
62 if (ep->attr_pair == NULL) {
63 free(ep);
64 return;
65 }
66 for (j = 0; j < ep->attr_count; j++) {
67 if (ep->attr_pair[j] == NULL)
68 continue;
69 if (ep->attr_pair[j]->attrname)
70 free(ep->attr_pair[j]->attrname);
71 if (ep->attr_pair[j]->attrvalue) {
72 for (k = 0; (k < ep->attr_pair[j]->value_count) &&
73 (ep->attr_pair[j]->attrvalue[k]); k++) {
74 free(ep->attr_pair[j]->attrvalue[k]);
75 }
76 free(ep->attr_pair[j]->attrvalue);
77 }
78 free(ep->attr_pair[j]);
79 }
80 free(ep->attr_pair);
81 free(ep);
82 }
83
84 static void
_freeControlList(LDAPControl *** ctrls)85 _freeControlList(LDAPControl ***ctrls)
86 {
87 LDAPControl **ctrl;
88
89 if (ctrls == NULL || *ctrls == NULL)
90 return;
91
92 for (ctrl = *ctrls; *ctrl != NULL; ctrl++)
93 ldap_control_free(*ctrl);
94 free(*ctrls);
95 *ctrls = NULL;
96 }
97 /*
98 * Convert attribute type in a RDN that has an attribute mapping to the
99 * original mappped type.
100 * e.g.
101 * cn<->cn-st and iphostnumber<->iphostnumber-st
102 * cn-st=aaa+iphostnumber-st=10.10.01.01
103 * is mapped to
104 * cn=aaa+iphostnumber=10.10.01.01
105 *
106 * Input - service: e.g. hosts, passwd etc.
107 * rdn: RDN
108 * Return: NULL - No attribute mapping in the RDN
109 * Non-NULL - The attribute type(s) in the RDN are mapped and
110 * the memory is allocated for the new rdn.
111 *
112 */
113 static char *
_cvtRDN(const char * service,const char * rdn)114 _cvtRDN(const char *service, const char *rdn)
115 {
116 char **attrs, **mapped_attrs, **mapp, *type, *value, *attr;
117 char *new_rdn = NULL;
118 int nAttr = 0, i, attr_mapped, len = 0;
119
120 /* Break down "type=value\0" pairs. Assume RDN is normalized */
121 if ((attrs = ldap_explode_rdn(rdn, 0)) == NULL)
122 return (NULL);
123
124 for (nAttr = 0; attrs[nAttr] != NULL; nAttr++)
125 ;
126
127 if ((mapped_attrs = (char **)calloc(nAttr, sizeof (char *))) == NULL) {
128 ldap_value_free(attrs);
129 return (NULL);
130 }
131
132 attr_mapped = 0;
133 for (i = 0; i < nAttr; i++) {
134 /* Parse type=value pair */
135 if ((type = strtok_r(attrs[i], "=", &value)) == NULL ||
136 value == NULL)
137 goto cleanup;
138 /* Reverse map: e.g. cn-sm -> cn */
139 mapp = __ns_ldap_getOrigAttribute(service, type);
140 if (mapp != NULL && mapp[0] != NULL) {
141 /* The attribute mapping is found */
142 type = mapp[0];
143 attr_mapped = 1;
144
145 /* "type=value\0" */
146 len = strlen(type) + strlen(value) + 2;
147
148 /* Reconstruct type=value pair. A string is allocated */
149 if ((attr = (char *)calloc(1, len)) == NULL) {
150 __s_api_free2dArray(mapp);
151 goto cleanup;
152 }
153 (void) snprintf(attr, len, "%s=%s", type, value);
154 mapped_attrs[i] = attr;
155 } else {
156 /*
157 * No attribute mapping. attrs[i] is going to be copied
158 * later. Restore "type\0value\0" back to
159 * "type=value\0".
160 */
161 type[strlen(type)] = '=';
162 }
163 __s_api_free2dArray(mapp);
164 }
165 if (attr_mapped == 0)
166 /* No attribute mapping. Don't bother to reconstruct RDN */
167 goto cleanup;
168
169 len = 0;
170 /* Reconstruct RDN from type=value pairs */
171 for (i = 0; i < nAttr; i++) {
172 if (mapped_attrs[i])
173 len += strlen(mapped_attrs[i]);
174 else
175 len += strlen(attrs[i]);
176 /* Add 1 for "+" */
177 len++;
178 }
179 if ((new_rdn = (char *)calloc(1, ++len)) == NULL)
180 goto cleanup;
181 for (i = 0; i < nAttr; i++) {
182 if (i > 0)
183 /* Add seperator */
184 (void) strlcat(new_rdn, "+", len);
185
186 if (mapped_attrs[i])
187 (void) strlcat(new_rdn, mapped_attrs[i], len);
188 else
189 (void) strlcat(new_rdn, attrs[i], len);
190
191 }
192 cleanup:
193 ldap_value_free(attrs);
194 if (mapped_attrs) {
195 if (attr_mapped) {
196 for (i = 0; i < nAttr; i++) {
197 if (mapped_attrs[i])
198 free(mapped_attrs[i]);
199 }
200 }
201 free(mapped_attrs);
202 }
203
204 return (new_rdn);
205 }
206 /*
207 * Convert attribute type in a DN that has an attribute mapping to the
208 * original mappped type.
209 * e.g
210 * The mappings are cn<->cn-sm, iphostnumber<->iphostnumber-sm
211 *
212 * dn: cn-sm=aaa+iphostnumber-sm=9.9.9.9,dc=central,dc=sun,dc=com
213 * is converted to
214 * dn: cn=aaa+iphostnumber=9.9.9.9,dc=central,dc=sun,dc=com
215 *
216 * Input - service: e.g. hosts, passwd etc.
217 * dn: the value of a distinguished name
218 * Return - NULL: error
219 * non-NULL: A converted DN and the memory is allocated
220 */
221 static char *
_cvtDN(const char * service,const char * dn)222 _cvtDN(const char *service, const char *dn)
223 {
224 char **mapped_rdns;
225 char **rdns, *new_rdn, *new_dn = NULL;
226 int nRdn = 0, i, len = 0, rdn_mapped;
227
228 if (service == NULL || dn == NULL)
229 return (NULL);
230
231 if ((rdns = ldap_explode_dn(dn, 0)) == NULL)
232 return (NULL);
233
234 for (nRdn = 0; rdns[nRdn] != NULL; nRdn++)
235 ;
236
237 if ((mapped_rdns = (char **)calloc(nRdn, sizeof (char *))) == NULL) {
238 ldap_value_free(rdns);
239 return (NULL);
240 }
241
242 rdn_mapped = 0;
243 /* Break down RDNs in a DN */
244 for (i = 0; i < nRdn; i++) {
245 if ((new_rdn = _cvtRDN(service, rdns[i])) != NULL) {
246 mapped_rdns[i] = new_rdn;
247 rdn_mapped = 1;
248 }
249 }
250 if (rdn_mapped == 0) {
251 /*
252 * No RDN contains any attribute mapping.
253 * Don't bother to reconstruct DN from RDN. Copy DN directly.
254 */
255 new_dn = strdup(dn);
256 goto cleanup;
257 }
258 /*
259 * Reconstruct dn from RDNs.
260 * Calculate the length first.
261 */
262 for (i = 0; i < nRdn; i++) {
263 if (mapped_rdns[i])
264 len += strlen(mapped_rdns[i]);
265 else
266 len += strlen(rdns[i]);
267
268 /* add 1 for ',' */
269 len ++;
270 }
271 if ((new_dn = (char *)calloc(1, ++len)) == NULL)
272 goto cleanup;
273 for (i = 0; i < nRdn; i++) {
274 if (i > 0)
275 /* Add seperator */
276 (void) strlcat(new_dn, ",", len);
277
278 if (mapped_rdns[i])
279 (void) strlcat(new_dn, mapped_rdns[i], len);
280 else
281 (void) strlcat(new_dn, rdns[i], len);
282
283 }
284
285 cleanup:
286 ldap_value_free(rdns);
287 if (mapped_rdns) {
288 if (rdn_mapped) {
289 for (i = 0; i < nRdn; i++) {
290 if (mapped_rdns[i])
291 free(mapped_rdns[i]);
292 }
293 }
294 free(mapped_rdns);
295 }
296
297 return (new_dn);
298 }
299 /*
300 * Convert a single ldap entry from a LDAPMessage
301 * into an ns_ldap_entry structure.
302 * Schema map the entry if specified in flags
303 */
304
305 static int
__s_api_cvtEntry(LDAP * ld,const char * service,LDAPMessage * e,int flags,ns_ldap_entry_t ** ret,ns_ldap_error_t ** error)306 __s_api_cvtEntry(LDAP *ld, const char *service, LDAPMessage *e, int flags,
307 ns_ldap_entry_t **ret, ns_ldap_error_t **error)
308 {
309
310 ns_ldap_entry_t *ep = NULL;
311 ns_ldap_attr_t **ap = NULL;
312 BerElement *ber;
313 char *attr = NULL;
314 char **vals = NULL;
315 char **mapping;
316 char *dn;
317 int nAttrs = 0;
318 int i, j, k = 0;
319 char **gecos_mapping = NULL;
320 int gecos_val_index[3] = { -1, -1, -1};
321 char errstr[MAXERROR];
322 int schema_mapping_existed = FALSE;
323 int gecos_mapping_existed = FALSE;
324 int gecos_attr_matched;
325 int auto_service = FALSE;
326 int rc = NS_LDAP_SUCCESS;
327
328 if (e == NULL || ret == NULL || error == NULL)
329 return (NS_LDAP_INVALID_PARAM);
330
331 *error = NULL;
332
333 ep = (ns_ldap_entry_t *)calloc(1, sizeof (ns_ldap_entry_t));
334 if (ep == NULL)
335 return (NS_LDAP_MEMORY);
336
337 if (service != NULL &&
338 (strncasecmp(service, "auto_", 5) == 0 ||
339 strcasecmp(service, "automount") == 0))
340 auto_service = TRUE;
341 /*
342 * see if schema mapping existed for the given service
343 */
344 mapping = __ns_ldap_getOrigAttribute(service,
345 NS_HASH_SCHEMA_MAPPING_EXISTED);
346 if (mapping) {
347 schema_mapping_existed = TRUE;
348 __s_api_free2dArray(mapping);
349 mapping = NULL;
350 } else if (auto_service) {
351 /*
352 * If service == auto_* and no
353 * schema mapping found
354 * then try automount
355 * There is certain case that schema mapping exist
356 * but __ns_ldap_getOrigAttribute(service,
357 * NS_HASH_SCHEMA_MAPPING_EXISTED);
358 * returns NULL.
359 * e.g.
360 * NS_LDAP_ATTRIBUTEMAP = automount:automountMapName=AAA
361 * NS_LDAP_OBJECTCLASSMAP = automount:automountMap=MynisMap
362 * NS_LDAP_OBJECTCLASSMAP = automount:automount=MynisObject
363 *
364 * Make a check for schema_mapping_existed here
365 * so later on __s_api_convert_automountmapname won't be called
366 * unnecessarily. It is also used for attribute mapping
367 * and objectclass mapping.
368 */
369 mapping = __ns_ldap_getOrigAttribute("automount",
370 NS_HASH_SCHEMA_MAPPING_EXISTED);
371 if (mapping) {
372 schema_mapping_existed = TRUE;
373 __s_api_free2dArray(mapping);
374 mapping = NULL;
375 }
376 }
377
378 nAttrs = 1; /* start with 1 for the DN attr */
379 for (attr = ldap_first_attribute(ld, e, &ber); attr != NULL;
380 attr = ldap_next_attribute(ld, e, ber)) {
381 nAttrs++;
382 ldap_memfree(attr);
383 attr = NULL;
384 }
385 ber_free(ber, 0);
386 ber = NULL;
387
388 ep->attr_count = nAttrs;
389
390 /*
391 * add 1 for "gecos" 1 to N attribute mapping,
392 * just in case it is needed.
393 * ep->attr_count will be updated later if that is true.
394 */
395 ap = (ns_ldap_attr_t **)calloc(ep->attr_count + 1,
396 sizeof (ns_ldap_attr_t *));
397 if (ap == NULL) {
398 __ns_ldap_freeEntry(ep);
399 ep = NULL;
400 return (NS_LDAP_MEMORY);
401 }
402 ep->attr_pair = ap;
403
404 /* DN attribute */
405 dn = ldap_get_dn(ld, e);
406 ap[0] = (ns_ldap_attr_t *)calloc(1, sizeof (ns_ldap_attr_t));
407 if (ap[0] == NULL) {
408 ldap_memfree(dn);
409 dn = NULL;
410 __ns_ldap_freeEntry(ep);
411 ep = NULL;
412 return (NS_LDAP_MEMORY);
413 }
414
415 if ((ap[0]->attrname = strdup("dn")) == NULL) {
416 ldap_memfree(dn);
417 dn = NULL;
418 __ns_ldap_freeEntry(ep);
419 ep = NULL;
420 return (NS_LDAP_INVALID_PARAM);
421 }
422 ap[0]->value_count = 1;
423 if ((ap[0]->attrvalue = (char **)
424 calloc(2, sizeof (char *))) == NULL) {
425 ldap_memfree(dn);
426 dn = NULL;
427 __ns_ldap_freeEntry(ep);
428 ep = NULL;
429 return (NS_LDAP_MEMORY);
430 }
431
432 if (schema_mapping_existed && ((flags & NS_LDAP_NOT_CVT_DN) == 0))
433 ap[0]->attrvalue[0] = _cvtDN(service, dn);
434 else
435 ap[0]->attrvalue[0] = strdup(dn);
436
437 if (ap[0]->attrvalue[0] == NULL) {
438 ldap_memfree(dn);
439 dn = NULL;
440 __ns_ldap_freeEntry(ep);
441 ep = NULL;
442 return (NS_LDAP_MEMORY);
443 }
444 ldap_memfree(dn);
445 dn = NULL;
446
447 if ((flags & NS_LDAP_NOMAP) == 0 && auto_service &&
448 schema_mapping_existed) {
449 rc = __s_api_convert_automountmapname(service,
450 &ap[0]->attrvalue[0],
451 error);
452 if (rc != NS_LDAP_SUCCESS) {
453 __ns_ldap_freeEntry(ep);
454 ep = NULL;
455 return (rc);
456 }
457 }
458
459 /* other attributes */
460 for (attr = ldap_first_attribute(ld, e, &ber), j = 1;
461 attr != NULL && j != nAttrs;
462 attr = ldap_next_attribute(ld, e, ber), j++) {
463 /* allocate new attr name */
464
465 if ((ap[j] = (ns_ldap_attr_t *)
466 calloc(1, sizeof (ns_ldap_attr_t))) == NULL) {
467 ber_free(ber, 0);
468 ber = NULL;
469 __ns_ldap_freeEntry(ep);
470 ep = NULL;
471 if (gecos_mapping)
472 __s_api_free2dArray(gecos_mapping);
473 gecos_mapping = NULL;
474 return (NS_LDAP_MEMORY);
475 }
476
477 if ((flags & NS_LDAP_NOMAP) || schema_mapping_existed == FALSE)
478 mapping = NULL;
479 else
480 mapping = __ns_ldap_getOrigAttribute(service, attr);
481
482 if (mapping == NULL && auto_service &&
483 schema_mapping_existed && (flags & NS_LDAP_NOMAP) == 0)
484 /*
485 * if service == auto_* and no schema mapping found
486 * and schema_mapping_existed is TRUE and NS_LDAP_NOMAP
487 * is not set then try automount e.g.
488 * NS_LDAP_ATTRIBUTEMAP = automount:automountMapName=AAA
489 */
490 mapping = __ns_ldap_getOrigAttribute("automount",
491 attr);
492
493 if (mapping == NULL) {
494 if ((ap[j]->attrname = strdup(attr)) == NULL) {
495 ber_free(ber, 0);
496 ber = NULL;
497 __ns_ldap_freeEntry(ep);
498 ep = NULL;
499 if (gecos_mapping)
500 __s_api_free2dArray(gecos_mapping);
501 gecos_mapping = NULL;
502 return (NS_LDAP_MEMORY);
503 }
504 } else {
505 /*
506 * for "gecos" 1 to N mapping,
507 * do not remove the mapped attribute,
508 * just create a new gecos attribute
509 * and append it to the end of the attribute list
510 */
511 if (strcasecmp(mapping[0], "gecos") == 0) {
512 ap[j]->attrname = strdup(attr);
513 gecos_mapping_existed = TRUE;
514 } else {
515 ap[j]->attrname = strdup(mapping[0]);
516 }
517
518 if (ap[j]->attrname == NULL) {
519 ber_free(ber, 0);
520 ber = NULL;
521 __ns_ldap_freeEntry(ep);
522 ep = NULL;
523 if (gecos_mapping)
524 __s_api_free2dArray(gecos_mapping);
525 gecos_mapping = NULL;
526 return (NS_LDAP_MEMORY);
527 }
528 /*
529 * 1 to N attribute mapping processing
530 * is only done for "gecos"
531 */
532
533 if (strcasecmp(mapping[0], "gecos") == 0) {
534 /*
535 * get attribute mapping for "gecos",
536 * need to know the number and order of the
537 * mapped attributes
538 */
539 if (gecos_mapping == NULL) {
540 gecos_mapping =
541 __ns_ldap_getMappedAttributes(
542 service, mapping[0]);
543 if (gecos_mapping == NULL ||
544 gecos_mapping[0] == NULL) {
545 /*
546 * this should never happens,
547 * syslog the error
548 */
549 (void) sprintf(errstr,
550 gettext(
551 "Attribute mapping "
552 "inconsistency "
553 "found for attributes "
554 "'%s' and '%s'."),
555 mapping[0], attr);
556 syslog(LOG_ERR, "libsldap: %s",
557 errstr);
558
559 ber_free(ber, 0);
560 ber = NULL;
561 __ns_ldap_freeEntry(ep);
562 ep = NULL;
563 __s_api_free2dArray(mapping);
564 mapping = NULL;
565 if (gecos_mapping)
566 __s_api_free2dArray(
567 gecos_mapping);
568 gecos_mapping = NULL;
569 return (NS_LDAP_INTERNAL);
570 }
571 }
572
573 /*
574 * is this attribute the 1st, 2nd, or
575 * 3rd attr in the mapping list?
576 */
577 gecos_attr_matched = FALSE;
578 for (i = 0; i < 3 && gecos_mapping[i]; i++) {
579 if (gecos_mapping[i] &&
580 strcasecmp(gecos_mapping[i],
581 attr) == 0) {
582 gecos_val_index[i] = j;
583 gecos_attr_matched = TRUE;
584 break;
585 }
586 }
587 if (gecos_attr_matched == FALSE) {
588 /*
589 * Not match found.
590 * This should never happens,
591 * syslog the error
592 */
593 (void) sprintf(errstr,
594 gettext(
595 "Attribute mapping "
596 "inconsistency "
597 "found for attributes "
598 "'%s' and '%s'."),
599 mapping[0], attr);
600 syslog(LOG_ERR, "libsldap: %s", errstr);
601
602 ber_free(ber, 0);
603 ber = NULL;
604 __ns_ldap_freeEntry(ep);
605 ep = NULL;
606 __s_api_free2dArray(mapping);
607 mapping = NULL;
608 __s_api_free2dArray(gecos_mapping);
609 gecos_mapping = NULL;
610 return (NS_LDAP_INTERNAL);
611 }
612 }
613 __s_api_free2dArray(mapping);
614 mapping = NULL;
615 }
616
617 if ((vals = ldap_get_values(ld, e, attr)) != NULL) {
618
619 if ((ap[j]->value_count =
620 ldap_count_values(vals)) == 0) {
621 ldap_value_free(vals);
622 vals = NULL;
623 continue;
624 } else {
625 ap[j]->attrvalue = (char **)
626 calloc(ap[j]->value_count+1,
627 sizeof (char *));
628 if (ap[j]->attrvalue == NULL) {
629 ber_free(ber, 0);
630 ber = NULL;
631 __ns_ldap_freeEntry(ep);
632 ep = NULL;
633 if (gecos_mapping)
634 __s_api_free2dArray(
635 gecos_mapping);
636 gecos_mapping = NULL;
637 return (NS_LDAP_MEMORY);
638 }
639 }
640
641 /* map object classes if necessary */
642 if ((flags & NS_LDAP_NOMAP) == 0 &&
643 schema_mapping_existed && ap[j]->attrname &&
644 strcasecmp(ap[j]->attrname, "objectclass") == 0) {
645 for (k = 0; k < ap[j]->value_count; k++) {
646 mapping =
647 __ns_ldap_getOrigObjectClass(
648 service, vals[k]);
649
650 if (mapping == NULL && auto_service)
651 /*
652 * if service == auto_* and no
653 * schema mapping found
654 * then try automount
655 */
656 mapping =
657 __ns_ldap_getOrigObjectClass(
658 "automount", vals[k]);
659
660 if (mapping == NULL) {
661 ap[j]->attrvalue[k] =
662 strdup(vals[k]);
663 } else {
664 ap[j]->attrvalue[k] =
665 strdup(mapping[0]);
666 __s_api_free2dArray(mapping);
667 mapping = NULL;
668 }
669 if (ap[j]->attrvalue[k] == NULL) {
670 ber_free(ber, 0);
671 ber = NULL;
672 __ns_ldap_freeEntry(ep);
673 ep = NULL;
674 if (gecos_mapping)
675 __s_api_free2dArray(
676 gecos_mapping);
677 gecos_mapping = NULL;
678 return (NS_LDAP_MEMORY);
679 }
680 }
681 } else {
682 for (k = 0; k < ap[j]->value_count; k++) {
683 if ((ap[j]->attrvalue[k] =
684 strdup(vals[k])) == NULL) {
685 ber_free(ber, 0);
686 ber = NULL;
687 __ns_ldap_freeEntry(ep);
688 ep = NULL;
689 if (gecos_mapping)
690 __s_api_free2dArray(
691 gecos_mapping);
692 gecos_mapping = NULL;
693 return (NS_LDAP_MEMORY);
694 }
695 }
696 }
697
698 ap[j]->attrvalue[k] = NULL;
699 ldap_value_free(vals);
700 vals = NULL;
701 }
702
703 ldap_memfree(attr);
704 attr = NULL;
705 }
706
707 ber_free(ber, 0);
708 ber = NULL;
709
710 if (gecos_mapping) {
711 __s_api_free2dArray(gecos_mapping);
712 gecos_mapping = NULL;
713 }
714
715 /* special processing for gecos 1 to up to 3 attribute mapping */
716 if (schema_mapping_existed && gecos_mapping_existed) {
717
718 int f = -1;
719
720 for (i = 0; i < 3; i++) {
721 k = gecos_val_index[i];
722
723 /*
724 * f is the index of the first returned
725 * attribute which "gecos" attribute mapped to
726 */
727 if (k != -1 && f == -1)
728 f = k;
729
730 if (k != -1 && ap[k]->value_count > 0 &&
731 ap[k]->attrvalue[0] &&
732 strlen(ap[k]->attrvalue[0]) > 0) {
733
734 if (k == f) {
735 /*
736 * Create and fill in the last reserved
737 * ap with the data from the "gecos"
738 * mapping attributes
739 */
740 ap[nAttrs] = (ns_ldap_attr_t *)
741 calloc(1,
742 sizeof (ns_ldap_attr_t));
743 if (ap[nAttrs] == NULL) {
744 __ns_ldap_freeEntry(ep);
745 ep = NULL;
746 return (NS_LDAP_MEMORY);
747 }
748 ap[nAttrs]->attrvalue = (char **)calloc(
749 2, sizeof (char *));
750 if (ap[nAttrs]->attrvalue == NULL) {
751 __ns_ldap_freeEntry(ep);
752 ep = NULL;
753 return (NS_LDAP_MEMORY);
754 }
755 /* add 1 more for a possible "," */
756 ap[nAttrs]->attrvalue[0] =
757 (char *)calloc(
758 strlen(ap[f]->attrvalue[0]) +
759 2, 1);
760 if (ap[nAttrs]->attrvalue[0] == NULL) {
761 __ns_ldap_freeEntry(ep);
762 ep = NULL;
763 return (NS_LDAP_MEMORY);
764 }
765 (void) strcpy(ap[nAttrs]->attrvalue[0],
766 ap[f]->attrvalue[0]);
767
768 ap[nAttrs]->attrname = strdup("gecos");
769 if (ap[nAttrs]->attrname == NULL) {
770 __ns_ldap_freeEntry(ep);
771 ep = NULL;
772 return (NS_LDAP_MEMORY);
773 }
774
775 ap[nAttrs]->value_count = 1;
776 ep->attr_count = nAttrs + 1;
777
778 } else {
779 char *tmp = NULL;
780
781 /*
782 * realloc to add "," and
783 * ap[k]->attrvalue[0]
784 */
785 tmp = (char *)realloc(
786 ap[nAttrs]->attrvalue[0],
787 strlen(ap[nAttrs]->
788 attrvalue[0]) +
789 strlen(ap[k]->
790 attrvalue[0]) + 2);
791 if (tmp == NULL) {
792 __ns_ldap_freeEntry(ep);
793 ep = NULL;
794 return (NS_LDAP_MEMORY);
795 }
796 ap[nAttrs]->attrvalue[0] = tmp;
797 (void) strcat(ap[nAttrs]->attrvalue[0],
798 ",");
799 (void) strcat(ap[nAttrs]->attrvalue[0],
800 ap[k]->attrvalue[0]);
801 }
802 }
803 }
804 }
805
806 *ret = ep;
807 return (NS_LDAP_SUCCESS);
808 }
809
810 static int
__s_api_getEntry(ns_ldap_cookie_t * cookie)811 __s_api_getEntry(ns_ldap_cookie_t *cookie)
812 {
813 ns_ldap_entry_t *curEntry = NULL;
814 int ret;
815
816 #ifdef DEBUG
817 (void) fprintf(stderr, "__s_api_getEntry START\n");
818 #endif
819
820 if (cookie->resultMsg == NULL) {
821 return (NS_LDAP_INVALID_PARAM);
822 }
823 ret = __s_api_cvtEntry(cookie->conn->ld, cookie->service,
824 cookie->resultMsg, cookie->i_flags,
825 &curEntry, &cookie->errorp);
826 if (ret != NS_LDAP_SUCCESS) {
827 return (ret);
828 }
829
830 if (cookie->result == NULL) {
831 cookie->result = (ns_ldap_result_t *)
832 calloc(1, sizeof (ns_ldap_result_t));
833 if (cookie->result == NULL) {
834 __ns_ldap_freeEntry(curEntry);
835 curEntry = NULL;
836 return (NS_LDAP_MEMORY);
837 }
838 cookie->result->entry = curEntry;
839 cookie->nextEntry = curEntry;
840 } else {
841 cookie->nextEntry->next = curEntry;
842 cookie->nextEntry = curEntry;
843 }
844 cookie->result->entries_count++;
845
846 return (NS_LDAP_SUCCESS);
847 }
848
849 static int
__s_api_get_cachemgr_data(const char * type,const char * from,char ** to)850 __s_api_get_cachemgr_data(const char *type, const char *from, char **to)
851 {
852 union {
853 ldap_data_t s_d;
854 char s_b[DOORBUFFERSIZE];
855 } space;
856 ldap_data_t *sptr;
857 int ndata;
858 int adata;
859 int rc;
860
861 #ifdef DEBUG
862 (void) fprintf(stderr, "__s_api_get_cachemgr_data START\n");
863 #endif
864 /*
865 * We are not going to perform DN to domain mapping
866 * in the Standalone mode
867 */
868 if (__s_api_isStandalone()) {
869 return (-1);
870 }
871
872 if (from == NULL || from[0] == '\0' || to == NULL)
873 return (-1);
874
875 *to = NULL;
876 (void) memset(space.s_b, 0, DOORBUFFERSIZE);
877
878 space.s_d.ldap_call.ldap_callnumber = GETCACHE;
879 (void) snprintf(space.s_d.ldap_call.ldap_u.domainname,
880 DOORBUFFERSIZE - sizeof (space.s_d.ldap_call.ldap_callnumber),
881 "%s%s%s",
882 type,
883 DOORLINESEP,
884 from);
885 ndata = sizeof (space);
886 adata = sizeof (ldap_call_t) +
887 strlen(space.s_d.ldap_call.ldap_u.domainname) + 1;
888 sptr = &space.s_d;
889
890 rc = __ns_ldap_trydoorcall(&sptr, &ndata, &adata);
891 if (rc != NS_CACHE_SUCCESS)
892 return (-1);
893 else
894 *to = strdup(sptr->ldap_ret.ldap_u.buff);
895 return (NS_LDAP_SUCCESS);
896 }
897
898 static int
__s_api_set_cachemgr_data(const char * type,const char * from,const char * to)899 __s_api_set_cachemgr_data(const char *type, const char *from, const char *to)
900 {
901 union {
902 ldap_data_t s_d;
903 char s_b[DOORBUFFERSIZE];
904 } space;
905 ldap_data_t *sptr;
906 int ndata;
907 int adata;
908 int rc;
909
910 #ifdef DEBUG
911 (void) fprintf(stderr, "__s_api_set_cachemgr_data START\n");
912 #endif
913 /*
914 * We are not going to perform DN to domain mapping
915 * in the Standalone mode
916 */
917 if (__s_api_isStandalone()) {
918 return (-1);
919 }
920
921 if ((from == NULL) || (from[0] == '\0') ||
922 (to == NULL) || (to[0] == '\0'))
923 return (-1);
924
925 (void) memset(space.s_b, 0, DOORBUFFERSIZE);
926
927 space.s_d.ldap_call.ldap_callnumber = SETCACHE;
928 (void) snprintf(space.s_d.ldap_call.ldap_u.domainname,
929 DOORBUFFERSIZE - sizeof (space.s_d.ldap_call.ldap_callnumber),
930 "%s%s%s%s%s",
931 type,
932 DOORLINESEP,
933 from,
934 DOORLINESEP,
935 to);
936
937 ndata = sizeof (space);
938 adata = sizeof (ldap_call_t) +
939 strlen(space.s_d.ldap_call.ldap_u.domainname) + 1;
940 sptr = &space.s_d;
941
942 rc = __ns_ldap_trydoorcall(&sptr, &ndata, &adata);
943 if (rc != NS_CACHE_SUCCESS)
944 return (-1);
945
946 return (NS_LDAP_SUCCESS);
947 }
948
949
950 static char *
__s_api_remove_rdn_space(char * rdn)951 __s_api_remove_rdn_space(char *rdn)
952 {
953 char *tf, *tl, *vf, *vl, *eqsign;
954
955 /* if no space(s) to remove, return */
956 if (strchr(rdn, SPACETOK) == NULL)
957 return (rdn);
958
959 /* if no '=' separator, return */
960 eqsign = strchr(rdn, '=');
961 if (eqsign == NULL)
962 return (rdn);
963
964 tf = rdn;
965 tl = eqsign - 1;
966 vf = eqsign + 1;
967 vl = rdn + strlen(rdn) - 1;
968
969 /* now two strings, type and value */
970 *eqsign = '\0';
971
972 /* remove type's leading spaces */
973 while (tf < tl && *tf == SPACETOK)
974 tf++;
975 /* remove type's trailing spaces */
976 while (tf < tl && *tl == SPACETOK)
977 tl--;
978 /* add '=' separator back */
979 *(++tl) = '=';
980 /* remove value's leading spaces */
981 while (vf < vl && *vf == SPACETOK)
982 vf++;
983 /* remove value's trailing spaces */
984 while (vf < vl && *vl == SPACETOK)
985 *vl-- = '\0';
986
987 /* move value up if necessary */
988 if (vf != tl + 1)
989 (void) strcpy(tl + 1, vf);
990
991 return (tf);
992 }
993
994 static
995 ns_ldap_cookie_t *
init_search_state_machine()996 init_search_state_machine()
997 {
998 ns_ldap_cookie_t *cookie;
999 ns_config_t *cfg;
1000
1001 cookie = (ns_ldap_cookie_t *)calloc(1, sizeof (ns_ldap_cookie_t));
1002 if (cookie == NULL)
1003 return (NULL);
1004 cookie->state = INIT;
1005 /* assign other state variables */
1006 cfg = __s_api_loadrefresh_config();
1007 cookie->connectionId = -1;
1008 if (cfg == NULL ||
1009 cfg->paramList[NS_LDAP_SEARCH_TIME_P].ns_ptype == NS_UNKNOWN) {
1010 cookie->search_timeout.tv_sec = NS_DEFAULT_SEARCH_TIMEOUT;
1011 } else {
1012 cookie->search_timeout.tv_sec =
1013 cfg->paramList[NS_LDAP_SEARCH_TIME_P].ns_i;
1014 }
1015 if (cfg != NULL)
1016 __s_api_release_config(cfg);
1017 cookie->search_timeout.tv_usec = 0;
1018
1019 return (cookie);
1020 }
1021
1022 static void
delete_search_cookie(ns_ldap_cookie_t * cookie)1023 delete_search_cookie(ns_ldap_cookie_t *cookie)
1024 {
1025 if (cookie == NULL)
1026 return;
1027 if (cookie->connectionId > -1)
1028 DropConnection(cookie->connectionId, cookie->i_flags);
1029 if (cookie->filter)
1030 free(cookie->filter);
1031 if (cookie->i_filter)
1032 free(cookie->i_filter);
1033 if (cookie->service)
1034 free(cookie->service);
1035 if (cookie->sdlist)
1036 (void) __ns_ldap_freeSearchDescriptors(&(cookie->sdlist));
1037 if (cookie->result)
1038 (void) __ns_ldap_freeResult(&cookie->result);
1039 if (cookie->attribute)
1040 __s_api_free2dArray(cookie->attribute);
1041 if (cookie->errorp)
1042 (void) __ns_ldap_freeError(&cookie->errorp);
1043 if (cookie->reflist)
1044 __s_api_deleteRefInfo(cookie->reflist);
1045 if (cookie->basedn)
1046 free(cookie->basedn);
1047 if (cookie->ctrlCookie)
1048 ber_bvfree(cookie->ctrlCookie);
1049 _freeControlList(&cookie->p_serverctrls);
1050 if (cookie->resultctrl)
1051 ldap_controls_free(cookie->resultctrl);
1052 free(cookie);
1053 }
1054
1055 static int
get_mapped_filter(ns_ldap_cookie_t * cookie,char ** new_filter)1056 get_mapped_filter(ns_ldap_cookie_t *cookie, char **new_filter)
1057 {
1058
1059 typedef struct filter_mapping_info {
1060 char oc_or_attr;
1061 char *name_start;
1062 char *name_end;
1063 char *veq_pos;
1064 char *from_name;
1065 char *to_name;
1066 char **mapping;
1067 } filter_mapping_info_t;
1068
1069 char *c, *last_copied;
1070 char *filter_c, *filter_c_next;
1071 char *key, *tail, *head;
1072 char errstr[MAXERROR];
1073 int num_eq = 0, num_veq = 0;
1074 boolean_t in_quote = B_FALSE;
1075 boolean_t is_value = B_FALSE;
1076 int i, j, oc_len, len;
1077 boolean_t at_least_one = B_FALSE;
1078 filter_mapping_info_t **info, *info1;
1079 char **mapping;
1080 char *service, *filter, *err;
1081 boolean_t auto_service = B_FALSE;
1082
1083 if (cookie == NULL || new_filter == NULL)
1084 return (NS_LDAP_INVALID_PARAM);
1085
1086 *new_filter = NULL;
1087 service = cookie->service;
1088 filter = cookie->filter;
1089
1090 /*
1091 * count the number of '=' char
1092 */
1093 for (c = filter; *c; c++) {
1094 if (*c == TOKENSEPARATOR)
1095 num_eq++;
1096 }
1097
1098 if (service != NULL && strncasecmp(service, "auto_", 5) == 0)
1099 auto_service = TRUE;
1100
1101 /*
1102 * See if schema mapping existed for the given service.
1103 * If not, just return success.
1104 */
1105 mapping = __ns_ldap_getOrigAttribute(service,
1106 NS_HASH_SCHEMA_MAPPING_EXISTED);
1107
1108 if (mapping == NULL && auto_service)
1109 /*
1110 * if service == auto_* and no
1111 * schema mapping found
1112 * then try automount
1113 */
1114 mapping = __ns_ldap_getOrigAttribute(
1115 "automount", NS_HASH_SCHEMA_MAPPING_EXISTED);
1116
1117 if (mapping)
1118 __s_api_free2dArray(mapping);
1119 else
1120 return (NS_LDAP_SUCCESS);
1121
1122 /*
1123 * no '=' sign, just say OK and return nothing
1124 */
1125 if (num_eq == 0)
1126 return (NS_LDAP_SUCCESS);
1127
1128 /*
1129 * Make a copy of the filter string
1130 * for saving the name of the objectclasses or
1131 * attributes that need to be passed to the
1132 * objectclass or attribute mapping functions.
1133 * pointer "info->from_name" points to the locations
1134 * within this string.
1135 *
1136 * The input filter string, filter, will be used
1137 * to indicate where these names start and end.
1138 * pointers "info->name_start" and "info->name_end"
1139 * point to locations within the input filter string,
1140 * and are used at the end of this function to
1141 * merge the original filter data with the
1142 * mapped objectclass or attribute names.
1143 */
1144 filter_c = strdup(filter);
1145 if (filter_c == NULL)
1146 return (NS_LDAP_MEMORY);
1147 filter_c_next = filter_c;
1148
1149 /*
1150 * get memory for info arrays
1151 */
1152 info = (filter_mapping_info_t **)calloc(num_eq + 1,
1153 sizeof (filter_mapping_info_t *));
1154
1155 if (info == NULL) {
1156 free(filter_c);
1157 return (NS_LDAP_MEMORY);
1158 }
1159
1160 /*
1161 * find valid '=' for further processing,
1162 * ignore the "escaped =" (.i.e. "\="), or
1163 * "=" in quoted string
1164 */
1165 for (c = filter_c; *c; c++) {
1166
1167 switch (*c) {
1168 case TOKENSEPARATOR:
1169 if (!in_quote && !is_value) {
1170 info1 = (filter_mapping_info_t *)calloc(1,
1171 sizeof (filter_mapping_info_t));
1172 if (info1 == NULL) {
1173 free(filter_c);
1174 for (i = 0; i < num_veq; i++)
1175 free(info[i]);
1176 free(info);
1177 return (NS_LDAP_MEMORY);
1178 }
1179 info[num_veq] = info1;
1180
1181 /*
1182 * remember the location of this "="
1183 */
1184 info[num_veq++]->veq_pos = c;
1185
1186 /*
1187 * skip until the end of the attribute value
1188 */
1189 is_value = B_TRUE;
1190 }
1191 break;
1192 case CPARATOK:
1193 /*
1194 * mark the end of the attribute value
1195 */
1196 if (!in_quote)
1197 is_value = B_FALSE;
1198 break;
1199 case QUOTETOK:
1200 /*
1201 * switch on/off the in_quote mode
1202 */
1203 in_quote = (in_quote == B_FALSE);
1204 break;
1205 case '\\':
1206 /*
1207 * ignore escape characters
1208 * don't skip if next char is '\0'
1209 */
1210 if (!in_quote)
1211 if (*(++c) == '\0')
1212 c--;
1213 break;
1214 }
1215
1216 }
1217
1218 /*
1219 * for each valid "=" found, get the name to
1220 * be mapped
1221 */
1222 oc_len = strlen("objectclass");
1223 for (i = 0; i < num_veq; i++) {
1224
1225 /*
1226 * look at the left side of "=" to see
1227 * if assertion is "objectclass=<ocname>"
1228 * or "<attribute name>=<attribute value>"
1229 *
1230 * first skip spaces before "=".
1231 * Note that filter_c_next may not point to the
1232 * start of the filter string. For i > 0,
1233 * it points to the end of the last name processed + 2
1234 */
1235 for (tail = info[i]->veq_pos; (tail > filter_c_next) &&
1236 (*(tail - 1) == SPACETOK); tail--)
1237 ;
1238
1239 /*
1240 * mark the end of the left side string (the key)
1241 */
1242 *tail = '\0';
1243 info[i]->name_end = tail - filter_c - 1 + filter;
1244
1245 /*
1246 * find the start of the key
1247 */
1248 key = filter_c_next;
1249 for (c = tail; filter_c_next <= c; c--) {
1250 /* OPARATOK is '(' */
1251 if (*c == OPARATOK ||
1252 *c == SPACETOK) {
1253 key = c + 1;
1254 break;
1255 }
1256 }
1257 info[i]->name_start = key - filter_c + filter;
1258
1259 if ((key + oc_len) <= tail) {
1260 if (strncasecmp(key, "objectclass",
1261 oc_len) == 0) {
1262 /*
1263 * assertion is "objectclass=ocname",
1264 * ocname is the one needs to be mapped
1265 *
1266 * skip spaces after "=" to find start
1267 * of the ocname
1268 */
1269 head = info[i]->veq_pos;
1270 for (head = info[i]->veq_pos + 1;
1271 *head && *head == SPACETOK; head++)
1272 ;
1273
1274 /* ignore empty ocname */
1275 if (!(*head))
1276 continue;
1277
1278 info[i]->name_start = head - filter_c +
1279 filter;
1280
1281 /*
1282 * now find the end of the ocname
1283 */
1284 for (c = head; ; c++) {
1285 /* CPARATOK is ')' */
1286 if (*c == CPARATOK ||
1287 *c == '\0' ||
1288 *c == SPACETOK) {
1289 *c = '\0';
1290 info[i]->name_end =
1291 c - filter_c - 1 +
1292 filter;
1293 filter_c_next = c + 1;
1294 info[i]->oc_or_attr = 'o';
1295 info[i]->from_name = head;
1296 break;
1297 }
1298 }
1299 }
1300 }
1301
1302 /*
1303 * assertion is not "objectclass=ocname",
1304 * assume assertion is "<key> = <value>",
1305 * <key> is the one needs to be mapped
1306 */
1307 if (info[i]->from_name == NULL && strlen(key) > 0) {
1308 info[i]->oc_or_attr = 'a';
1309 info[i]->from_name = key;
1310 }
1311 }
1312
1313 /* perform schema mapping */
1314 for (i = 0; i < num_veq; i++) {
1315 if (info[i]->from_name == NULL)
1316 continue;
1317
1318 if (info[i]->oc_or_attr == 'a')
1319 info[i]->mapping =
1320 __ns_ldap_getMappedAttributes(service,
1321 info[i]->from_name);
1322 else
1323 info[i]->mapping =
1324 __ns_ldap_getMappedObjectClass(service,
1325 info[i]->from_name);
1326
1327 if (info[i]->mapping == NULL && auto_service) {
1328 /*
1329 * If no mapped attribute/objectclass is found
1330 * and service == auto*
1331 * try to find automount's
1332 * mapped attribute/objectclass
1333 */
1334 if (info[i]->oc_or_attr == 'a')
1335 info[i]->mapping =
1336 __ns_ldap_getMappedAttributes("automount",
1337 info[i]->from_name);
1338 else
1339 info[i]->mapping =
1340 __ns_ldap_getMappedObjectClass("automount",
1341 info[i]->from_name);
1342 }
1343
1344 if (info[i]->mapping == NULL ||
1345 info[i]->mapping[0] == NULL) {
1346 info[i]->to_name = NULL;
1347 } else if (info[i]->mapping[1] == NULL) {
1348 info[i]->to_name = info[i]->mapping[0];
1349 at_least_one = TRUE;
1350 } else {
1351 __s_api_free2dArray(info[i]->mapping);
1352 /*
1353 * multiple mapping
1354 * not allowed
1355 */
1356 (void) sprintf(errstr,
1357 gettext(
1358 "Multiple attribute or objectclass "
1359 "mapping for '%s' in filter "
1360 "'%s' not allowed."),
1361 info[i]->from_name, filter);
1362 err = strdup(errstr);
1363 if (err) {
1364 MKERROR(LOG_WARNING, cookie->errorp,
1365 NS_CONFIG_SYNTAX,
1366 err, NS_LDAP_MEMORY);
1367 }
1368
1369 free(filter_c);
1370 for (j = 0; j < num_veq; j++) {
1371 if (info[j]->mapping)
1372 __s_api_free2dArray(
1373 info[j]->mapping);
1374 free(info[j]);
1375 }
1376 free(info);
1377 return (NS_LDAP_CONFIG);
1378 }
1379 }
1380
1381
1382 if (at_least_one) {
1383
1384 len = strlen(filter);
1385 last_copied = filter - 1;
1386
1387 for (i = 0; i < num_veq; i++) {
1388 if (info[i]->to_name)
1389 len += strlen(info[i]->to_name);
1390 }
1391
1392 *new_filter = (char *)calloc(1, len);
1393 if (*new_filter == NULL) {
1394 free(filter_c);
1395 for (j = 0; j < num_veq; j++) {
1396 if (info[j]->mapping)
1397 __s_api_free2dArray(
1398 info[j]->mapping);
1399 free(info[j]);
1400 }
1401 free(info);
1402 return (NS_LDAP_MEMORY);
1403 }
1404
1405 for (i = 0; i < num_veq; i++) {
1406 if (info[i]->to_name != NULL &&
1407 info[i]->to_name != NULL) {
1408
1409 /*
1410 * copy the original filter data
1411 * between the last name and current
1412 * name
1413 */
1414 if ((last_copied + 1) != info[i]->name_start)
1415 (void) strncat(*new_filter,
1416 last_copied + 1,
1417 info[i]->name_start -
1418 last_copied - 1);
1419
1420 /* the data is copied */
1421 last_copied = info[i]->name_end;
1422
1423 /*
1424 * replace the name with
1425 * the mapped name
1426 */
1427 (void) strcat(*new_filter, info[i]->to_name);
1428 }
1429
1430 /* copy the filter data after the last name */
1431 if (i == (num_veq -1) &&
1432 info[i]->name_end <
1433 (filter + strlen(filter)))
1434 (void) strncat(*new_filter, last_copied + 1,
1435 filter + strlen(filter) -
1436 last_copied - 1);
1437 }
1438
1439 }
1440
1441 /* free memory */
1442 free(filter_c);
1443 for (j = 0; j < num_veq; j++) {
1444 if (info[j]->mapping)
1445 __s_api_free2dArray(info[j]->mapping);
1446 free(info[j]);
1447 }
1448 free(info);
1449
1450 return (NS_LDAP_SUCCESS);
1451 }
1452
1453 static int
setup_next_search(ns_ldap_cookie_t * cookie)1454 setup_next_search(ns_ldap_cookie_t *cookie)
1455 {
1456 ns_ldap_search_desc_t *dptr;
1457 int scope;
1458 char *filter, *str;
1459 int baselen;
1460 int rc;
1461 void **param;
1462
1463 dptr = *cookie->sdpos;
1464 scope = cookie->i_flags & (NS_LDAP_SCOPE_BASE |
1465 NS_LDAP_SCOPE_ONELEVEL |
1466 NS_LDAP_SCOPE_SUBTREE);
1467 if (scope)
1468 cookie->scope = scope;
1469 else
1470 cookie->scope = dptr->scope;
1471 switch (cookie->scope) {
1472 case NS_LDAP_SCOPE_BASE:
1473 cookie->scope = LDAP_SCOPE_BASE;
1474 break;
1475 case NS_LDAP_SCOPE_ONELEVEL:
1476 cookie->scope = LDAP_SCOPE_ONELEVEL;
1477 break;
1478 case NS_LDAP_SCOPE_SUBTREE:
1479 cookie->scope = LDAP_SCOPE_SUBTREE;
1480 break;
1481 }
1482
1483 filter = NULL;
1484 if (cookie->use_filtercb && cookie->init_filter_cb &&
1485 dptr->filter && strlen(dptr->filter) > 0) {
1486 (*cookie->init_filter_cb)(dptr, &filter,
1487 cookie->userdata);
1488 }
1489 if (filter == NULL) {
1490 if (cookie->i_filter == NULL) {
1491 cookie->err_rc = NS_LDAP_INVALID_PARAM;
1492 return (-1);
1493 } else {
1494 if (cookie->filter)
1495 free(cookie->filter);
1496 cookie->filter = strdup(cookie->i_filter);
1497 if (cookie->filter == NULL) {
1498 cookie->err_rc = NS_LDAP_MEMORY;
1499 return (-1);
1500 }
1501 }
1502 } else {
1503 if (cookie->filter)
1504 free(cookie->filter);
1505 cookie->filter = strdup(filter);
1506 free(filter);
1507 if (cookie->filter == NULL) {
1508 cookie->err_rc = NS_LDAP_MEMORY;
1509 return (-1);
1510 }
1511 }
1512
1513 /*
1514 * perform attribute/objectclass mapping on filter
1515 */
1516 filter = NULL;
1517
1518 if (cookie->service) {
1519 rc = get_mapped_filter(cookie, &filter);
1520 if (rc != NS_LDAP_SUCCESS) {
1521 cookie->err_rc = rc;
1522 return (-1);
1523 } else {
1524 /*
1525 * get_mapped_filter returns
1526 * NULL filter pointer, if
1527 * no mapping was done
1528 */
1529 if (filter) {
1530 free(cookie->filter);
1531 cookie->filter = filter;
1532 }
1533 }
1534 }
1535
1536 /*
1537 * validate filter to make sure it's legal
1538 * [remove redundant ()'s]
1539 */
1540 rc = validate_filter(cookie);
1541 if (rc != NS_LDAP_SUCCESS) {
1542 cookie->err_rc = rc;
1543 return (-1);
1544 }
1545
1546 baselen = strlen(dptr->basedn);
1547 if (baselen > 0 && dptr->basedn[baselen-1] == COMMATOK) {
1548 rc = __ns_ldap_getParam(NS_LDAP_SEARCH_BASEDN_P,
1549 (void ***)¶m, &cookie->errorp);
1550 if (rc != NS_LDAP_SUCCESS) {
1551 cookie->err_rc = rc;
1552 return (-1);
1553 }
1554 str = ((char **)param)[0];
1555 baselen += strlen(str)+1;
1556 if (cookie->basedn)
1557 free(cookie->basedn);
1558 cookie->basedn = (char *)malloc(baselen);
1559 if (cookie->basedn == NULL) {
1560 cookie->err_rc = NS_LDAP_MEMORY;
1561 return (-1);
1562 }
1563 (void) strcpy(cookie->basedn, dptr->basedn);
1564 (void) strcat(cookie->basedn, str);
1565 (void) __ns_ldap_freeParam(¶m);
1566 } else {
1567 if (cookie->basedn)
1568 free(cookie->basedn);
1569 cookie->basedn = strdup(dptr->basedn);
1570 }
1571 return (0);
1572 }
1573
1574 static int
setup_referral_search(ns_ldap_cookie_t * cookie)1575 setup_referral_search(ns_ldap_cookie_t *cookie)
1576 {
1577 ns_referral_info_t *ref;
1578
1579 ref = cookie->refpos;
1580 cookie->scope = ref->refScope;
1581 if (cookie->filter) {
1582 free(cookie->filter);
1583 }
1584 cookie->filter = strdup(ref->refFilter);
1585 if (cookie->basedn) {
1586 free(cookie->basedn);
1587 }
1588 cookie->basedn = strdup(ref->refDN);
1589 if (cookie->filter == NULL || cookie->basedn == NULL) {
1590 cookie->err_rc = NS_LDAP_MEMORY;
1591 return (-1);
1592 }
1593 return (0);
1594 }
1595
1596 static int
get_current_session(ns_ldap_cookie_t * cookie)1597 get_current_session(ns_ldap_cookie_t *cookie)
1598 {
1599 ConnectionID connectionId = -1;
1600 Connection *conp = NULL;
1601 int rc;
1602 int fail_if_new_pwd_reqd = 1;
1603
1604 rc = __s_api_getConnection(NULL, cookie->i_flags,
1605 cookie->i_auth, &connectionId, &conp,
1606 &cookie->errorp, fail_if_new_pwd_reqd,
1607 cookie->nopasswd_acct_mgmt, cookie->conn_user);
1608
1609 /*
1610 * If password control attached in *cookie->errorp,
1611 * e.g. rc == NS_LDAP_SUCCESS_WITH_INFO,
1612 * free the error structure (we do not need
1613 * the sec_to_expired info).
1614 * Reset rc to NS_LDAP_SUCCESS.
1615 */
1616 if (rc == NS_LDAP_SUCCESS_WITH_INFO) {
1617 (void) __ns_ldap_freeError(
1618 &cookie->errorp);
1619 cookie->errorp = NULL;
1620 rc = NS_LDAP_SUCCESS;
1621 }
1622
1623 if (rc != NS_LDAP_SUCCESS) {
1624 cookie->err_rc = rc;
1625 return (-1);
1626 }
1627 cookie->conn = conp;
1628 cookie->connectionId = connectionId;
1629
1630 return (0);
1631 }
1632
1633 static int
get_next_session(ns_ldap_cookie_t * cookie)1634 get_next_session(ns_ldap_cookie_t *cookie)
1635 {
1636 ConnectionID connectionId = -1;
1637 Connection *conp = NULL;
1638 int rc;
1639 int fail_if_new_pwd_reqd = 1;
1640
1641 if (cookie->connectionId > -1) {
1642 DropConnection(cookie->connectionId, cookie->i_flags);
1643 cookie->connectionId = -1;
1644 }
1645
1646 /* If using a MT connection, return it. */
1647 if (cookie->conn_user != NULL &&
1648 cookie->conn_user->conn_mt != NULL)
1649 __s_api_conn_mt_return(cookie->conn_user);
1650
1651 rc = __s_api_getConnection(NULL, cookie->i_flags,
1652 cookie->i_auth, &connectionId, &conp,
1653 &cookie->errorp, fail_if_new_pwd_reqd,
1654 cookie->nopasswd_acct_mgmt, cookie->conn_user);
1655
1656 /*
1657 * If password control attached in *cookie->errorp,
1658 * e.g. rc == NS_LDAP_SUCCESS_WITH_INFO,
1659 * free the error structure (we do not need
1660 * the sec_to_expired info).
1661 * Reset rc to NS_LDAP_SUCCESS.
1662 */
1663 if (rc == NS_LDAP_SUCCESS_WITH_INFO) {
1664 (void) __ns_ldap_freeError(
1665 &cookie->errorp);
1666 cookie->errorp = NULL;
1667 rc = NS_LDAP_SUCCESS;
1668 }
1669
1670 if (rc != NS_LDAP_SUCCESS) {
1671 cookie->err_rc = rc;
1672 return (-1);
1673 }
1674 cookie->conn = conp;
1675 cookie->connectionId = connectionId;
1676 return (0);
1677 }
1678
1679 static int
get_referral_session(ns_ldap_cookie_t * cookie)1680 get_referral_session(ns_ldap_cookie_t *cookie)
1681 {
1682 ConnectionID connectionId = -1;
1683 Connection *conp = NULL;
1684 int rc;
1685 int fail_if_new_pwd_reqd = 1;
1686
1687 if (cookie->connectionId > -1) {
1688 DropConnection(cookie->connectionId, cookie->i_flags);
1689 cookie->connectionId = -1;
1690 }
1691
1692 /* set it up to use a connection opened for referral */
1693 if (cookie->conn_user != NULL) {
1694 /* If using a MT connection, return it. */
1695 if (cookie->conn_user->conn_mt != NULL)
1696 __s_api_conn_mt_return(cookie->conn_user);
1697 cookie->conn_user->referral = B_TRUE;
1698 }
1699
1700 rc = __s_api_getConnection(cookie->refpos->refHost, 0,
1701 cookie->i_auth, &connectionId, &conp,
1702 &cookie->errorp, fail_if_new_pwd_reqd,
1703 cookie->nopasswd_acct_mgmt, cookie->conn_user);
1704
1705 /*
1706 * If password control attached in *cookie->errorp,
1707 * e.g. rc == NS_LDAP_SUCCESS_WITH_INFO,
1708 * free the error structure (we do not need
1709 * the sec_to_expired info).
1710 * Reset rc to NS_LDAP_SUCCESS.
1711 */
1712 if (rc == NS_LDAP_SUCCESS_WITH_INFO) {
1713 (void) __ns_ldap_freeError(
1714 &cookie->errorp);
1715 cookie->errorp = NULL;
1716 rc = NS_LDAP_SUCCESS;
1717 }
1718
1719 if (rc != NS_LDAP_SUCCESS) {
1720 cookie->err_rc = rc;
1721 return (-1);
1722 }
1723 cookie->conn = conp;
1724 cookie->connectionId = connectionId;
1725 return (0);
1726 }
1727
1728 static int
paging_supported(ns_ldap_cookie_t * cookie)1729 paging_supported(ns_ldap_cookie_t *cookie)
1730 {
1731 int rc;
1732
1733 cookie->listType = 0;
1734 rc = __s_api_isCtrlSupported(cookie->conn,
1735 LDAP_CONTROL_VLVREQUEST);
1736 if (rc == NS_LDAP_SUCCESS) {
1737 cookie->listType = VLVCTRLFLAG;
1738 return (1);
1739 }
1740 rc = __s_api_isCtrlSupported(cookie->conn,
1741 LDAP_CONTROL_SIMPLE_PAGE);
1742 if (rc == NS_LDAP_SUCCESS) {
1743 cookie->listType = SIMPLEPAGECTRLFLAG;
1744 return (1);
1745 }
1746 return (0);
1747 }
1748
1749 typedef struct servicesorttype {
1750 char *service;
1751 ns_srvsidesort_t type;
1752 } servicesorttype_t;
1753
1754 static servicesorttype_t *sort_type = NULL;
1755 static int sort_type_size = 0;
1756 static int sort_type_hwm = 0;
1757 static mutex_t sort_type_mutex = DEFAULTMUTEX;
1758
1759
1760 static ns_srvsidesort_t
get_srvsidesort_type(char * service)1761 get_srvsidesort_type(char *service)
1762 {
1763 int i;
1764 ns_srvsidesort_t type = SSS_UNKNOWN;
1765
1766 if (service == NULL)
1767 return (type);
1768
1769 (void) mutex_lock(&sort_type_mutex);
1770 if (sort_type != NULL) {
1771 for (i = 0; i < sort_type_hwm; i++) {
1772 if (strcmp(sort_type[i].service, service) == 0) {
1773 type = sort_type[i].type;
1774 break;
1775 }
1776 }
1777 }
1778 (void) mutex_unlock(&sort_type_mutex);
1779 return (type);
1780 }
1781
1782 static void
update_srvsidesort_type(char * service,ns_srvsidesort_t type)1783 update_srvsidesort_type(char *service, ns_srvsidesort_t type)
1784 {
1785 int i, size;
1786 servicesorttype_t *tmp;
1787
1788 if (service == NULL)
1789 return;
1790
1791 (void) mutex_lock(&sort_type_mutex);
1792
1793 for (i = 0; i < sort_type_hwm; i++) {
1794 if (strcmp(sort_type[i].service, service) == 0) {
1795 sort_type[i].type = type;
1796 (void) mutex_unlock(&sort_type_mutex);
1797 return;
1798 }
1799 }
1800 if (sort_type == NULL) {
1801 size = 10;
1802 tmp = malloc(size * sizeof (servicesorttype_t));
1803 if (tmp == NULL) {
1804 (void) mutex_unlock(&sort_type_mutex);
1805 return;
1806 }
1807 sort_type = tmp;
1808 sort_type_size = size;
1809 } else if (sort_type_hwm >= sort_type_size) {
1810 size = sort_type_size + 10;
1811 tmp = realloc(sort_type, size * sizeof (servicesorttype_t));
1812 if (tmp == NULL) {
1813 (void) mutex_unlock(&sort_type_mutex);
1814 return;
1815 }
1816 sort_type = tmp;
1817 sort_type_size = size;
1818 }
1819 sort_type[sort_type_hwm].service = strdup(service);
1820 if (sort_type[sort_type_hwm].service == NULL) {
1821 (void) mutex_unlock(&sort_type_mutex);
1822 return;
1823 }
1824 sort_type[sort_type_hwm].type = type;
1825 sort_type_hwm++;
1826
1827 (void) mutex_unlock(&sort_type_mutex);
1828 }
1829
1830 static int
setup_vlv_params(ns_ldap_cookie_t * cookie)1831 setup_vlv_params(ns_ldap_cookie_t *cookie)
1832 {
1833 LDAPControl **ctrls;
1834 LDAPsortkey **sortkeylist;
1835 LDAPControl *sortctrl = NULL;
1836 LDAPControl *vlvctrl = NULL;
1837 LDAPVirtualList vlist;
1838 char *sortattr;
1839 int rc;
1840 int free_sort = FALSE;
1841
1842 _freeControlList(&cookie->p_serverctrls);
1843
1844 if (cookie->sortTypeTry == SSS_UNKNOWN)
1845 cookie->sortTypeTry = get_srvsidesort_type(cookie->service);
1846 if (cookie->sortTypeTry == SSS_UNKNOWN)
1847 cookie->sortTypeTry = SSS_SINGLE_ATTR;
1848
1849 if (cookie->sortTypeTry == SSS_SINGLE_ATTR) {
1850 if ((cookie->i_flags & NS_LDAP_NOMAP) == 0 &&
1851 cookie->i_sortattr) {
1852 sortattr = __ns_ldap_mapAttribute(cookie->service,
1853 cookie->i_sortattr);
1854 free_sort = TRUE;
1855 } else if (cookie->i_sortattr) {
1856 sortattr = (char *)cookie->i_sortattr;
1857 } else {
1858 sortattr = "cn";
1859 }
1860 } else {
1861 sortattr = "cn uid";
1862 }
1863
1864 rc = ldap_create_sort_keylist(&sortkeylist, sortattr);
1865 if (free_sort)
1866 free(sortattr);
1867 if (rc != LDAP_SUCCESS) {
1868 (void) ldap_get_option(cookie->conn->ld,
1869 LDAP_OPT_ERROR_NUMBER, &rc);
1870 return (rc);
1871 }
1872 rc = ldap_create_sort_control(cookie->conn->ld,
1873 sortkeylist, 1, &sortctrl);
1874 ldap_free_sort_keylist(sortkeylist);
1875 if (rc != LDAP_SUCCESS) {
1876 (void) ldap_get_option(cookie->conn->ld,
1877 LDAP_OPT_ERROR_NUMBER, &rc);
1878 return (rc);
1879 }
1880
1881 vlist.ldvlist_index = cookie->index;
1882 vlist.ldvlist_size = 0;
1883
1884 vlist.ldvlist_before_count = 0;
1885 vlist.ldvlist_after_count = LISTPAGESIZE-1;
1886 vlist.ldvlist_attrvalue = NULL;
1887 vlist.ldvlist_extradata = NULL;
1888
1889 rc = ldap_create_virtuallist_control(cookie->conn->ld,
1890 &vlist, &vlvctrl);
1891 if (rc != LDAP_SUCCESS) {
1892 ldap_control_free(sortctrl);
1893 (void) ldap_get_option(cookie->conn->ld, LDAP_OPT_ERROR_NUMBER,
1894 &rc);
1895 return (rc);
1896 }
1897
1898 ctrls = (LDAPControl **)calloc(3, sizeof (LDAPControl *));
1899 if (ctrls == NULL) {
1900 ldap_control_free(sortctrl);
1901 ldap_control_free(vlvctrl);
1902 return (LDAP_NO_MEMORY);
1903 }
1904
1905 ctrls[0] = sortctrl;
1906 ctrls[1] = vlvctrl;
1907
1908 cookie->p_serverctrls = ctrls;
1909 return (LDAP_SUCCESS);
1910 }
1911
1912 static int
setup_simplepg_params(ns_ldap_cookie_t * cookie)1913 setup_simplepg_params(ns_ldap_cookie_t *cookie)
1914 {
1915 LDAPControl **ctrls;
1916 LDAPControl *pgctrl = NULL;
1917 int rc;
1918
1919 _freeControlList(&cookie->p_serverctrls);
1920
1921 rc = ldap_create_page_control(cookie->conn->ld, LISTPAGESIZE,
1922 cookie->ctrlCookie, (char)0, &pgctrl);
1923 if (rc != LDAP_SUCCESS) {
1924 (void) ldap_get_option(cookie->conn->ld, LDAP_OPT_ERROR_NUMBER,
1925 &rc);
1926 return (rc);
1927 }
1928
1929 ctrls = (LDAPControl **)calloc(2, sizeof (LDAPControl *));
1930 if (ctrls == NULL) {
1931 ldap_control_free(pgctrl);
1932 return (LDAP_NO_MEMORY);
1933 }
1934 ctrls[0] = pgctrl;
1935 cookie->p_serverctrls = ctrls;
1936 return (LDAP_SUCCESS);
1937 }
1938
1939 static void
proc_result_referrals(ns_ldap_cookie_t * cookie)1940 proc_result_referrals(ns_ldap_cookie_t *cookie)
1941 {
1942 int errCode, i, rc;
1943 char **referrals = NULL;
1944
1945 /*
1946 * Only follow one level of referrals, i.e.
1947 * if already in referral mode, do nothing
1948 */
1949 if (cookie->refpos == NULL) {
1950 cookie->new_state = END_RESULT;
1951 rc = ldap_parse_result(cookie->conn->ld,
1952 cookie->resultMsg,
1953 &errCode, NULL,
1954 NULL, &referrals,
1955 NULL, 0);
1956 if (rc != NS_LDAP_SUCCESS) {
1957 (void) ldap_get_option(cookie->conn->ld,
1958 LDAP_OPT_ERROR_NUMBER,
1959 &cookie->err_rc);
1960 cookie->new_state = LDAP_ERROR;
1961 return;
1962 }
1963 if (errCode == LDAP_REFERRAL) {
1964 for (i = 0; referrals[i] != NULL;
1965 i++) {
1966 /* add to referral list */
1967 rc = __s_api_addRefInfo(
1968 &cookie->reflist,
1969 referrals[i],
1970 cookie->basedn,
1971 &cookie->scope,
1972 cookie->filter,
1973 cookie->conn->ld);
1974 if (rc != NS_LDAP_SUCCESS) {
1975 cookie->new_state =
1976 ERROR;
1977 break;
1978 }
1979 }
1980 ldap_value_free(referrals);
1981 }
1982 }
1983 }
1984
1985 static void
proc_search_references(ns_ldap_cookie_t * cookie)1986 proc_search_references(ns_ldap_cookie_t *cookie)
1987 {
1988 char **refurls = NULL;
1989 int i, rc;
1990
1991 /*
1992 * Only follow one level of referrals, i.e.
1993 * if already in referral mode, do nothing
1994 */
1995 if (cookie->refpos == NULL) {
1996 refurls = ldap_get_reference_urls(
1997 cookie->conn->ld,
1998 cookie->resultMsg);
1999 if (refurls == NULL) {
2000 (void) ldap_get_option(cookie->conn->ld,
2001 LDAP_OPT_ERROR_NUMBER,
2002 &cookie->err_rc);
2003 cookie->new_state = LDAP_ERROR;
2004 return;
2005 }
2006 for (i = 0; refurls[i] != NULL; i++) {
2007 /* add to referral list */
2008 rc = __s_api_addRefInfo(
2009 &cookie->reflist,
2010 refurls[i],
2011 cookie->basedn,
2012 &cookie->scope,
2013 cookie->filter,
2014 cookie->conn->ld);
2015 if (rc != NS_LDAP_SUCCESS) {
2016 cookie->new_state =
2017 ERROR;
2018 break;
2019 }
2020 }
2021 /* free allocated storage */
2022 for (i = 0; refurls[i] != NULL; i++)
2023 free(refurls[i]);
2024 }
2025 }
2026
2027 static ns_state_t
multi_result(ns_ldap_cookie_t * cookie)2028 multi_result(ns_ldap_cookie_t *cookie)
2029 {
2030 char errstr[MAXERROR];
2031 char *err;
2032 ns_ldap_error_t **errorp = NULL;
2033 LDAPControl **retCtrls = NULL;
2034 int i, rc;
2035 int errCode;
2036 boolean_t finished = B_FALSE;
2037 unsigned long target_posp = 0;
2038 unsigned long list_size = 0;
2039 unsigned int count = 0;
2040 char **referrals = NULL;
2041
2042 if (cookie->listType == VLVCTRLFLAG) {
2043 rc = ldap_parse_result(cookie->conn->ld, cookie->resultMsg,
2044 &errCode, NULL, NULL, &referrals, &retCtrls, 0);
2045 if (rc != LDAP_SUCCESS) {
2046 (void) ldap_get_option(cookie->conn->ld,
2047 LDAP_OPT_ERROR_NUMBER,
2048 &cookie->err_rc);
2049 (void) sprintf(errstr,
2050 gettext("LDAP ERROR (%d): %s.\n"),
2051 cookie->err_rc,
2052 gettext(ldap_err2string(cookie->err_rc)));
2053 err = strdup(errstr);
2054 MKERROR(LOG_WARNING, *errorp, NS_LDAP_INTERNAL, err,
2055 LDAP_ERROR);
2056 cookie->err_rc = NS_LDAP_INTERNAL;
2057 cookie->errorp = *errorp;
2058 return (LDAP_ERROR);
2059 }
2060 if (errCode == LDAP_REFERRAL) {
2061 for (i = 0; referrals[i] != NULL;
2062 i++) {
2063 /* add to referral list */
2064 rc = __s_api_addRefInfo(
2065 &cookie->reflist,
2066 referrals[i],
2067 cookie->basedn,
2068 &cookie->scope,
2069 cookie->filter,
2070 cookie->conn->ld);
2071 if (rc != NS_LDAP_SUCCESS) {
2072 ldap_value_free(
2073 referrals);
2074 if (retCtrls)
2075 ldap_controls_free(
2076 retCtrls);
2077 return (ERROR);
2078 }
2079 }
2080 ldap_value_free(referrals);
2081 if (retCtrls)
2082 ldap_controls_free(retCtrls);
2083 return (END_RESULT);
2084 }
2085 if (retCtrls) {
2086 rc = ldap_parse_virtuallist_control(
2087 cookie->conn->ld, retCtrls,
2088 &target_posp, &list_size, &errCode);
2089 if (rc == LDAP_SUCCESS) {
2090 /*
2091 * AD does not return valid target_posp
2092 * and list_size
2093 */
2094 if (target_posp != 0 && list_size != 0) {
2095 cookie->index =
2096 target_posp + LISTPAGESIZE;
2097 if (cookie->index > list_size)
2098 finished = B_TRUE;
2099 } else {
2100 if (cookie->entryCount < LISTPAGESIZE)
2101 finished = B_TRUE;
2102 else
2103 cookie->index +=
2104 cookie->entryCount;
2105 }
2106 }
2107 ldap_controls_free(retCtrls);
2108 retCtrls = NULL;
2109 } else {
2110 finished = B_TRUE;
2111 }
2112 } else if (cookie->listType == SIMPLEPAGECTRLFLAG) {
2113 rc = ldap_parse_result(cookie->conn->ld, cookie->resultMsg,
2114 &errCode, NULL, NULL, &referrals, &retCtrls, 0);
2115 if (rc != LDAP_SUCCESS) {
2116 (void) ldap_get_option(cookie->conn->ld,
2117 LDAP_OPT_ERROR_NUMBER,
2118 &cookie->err_rc);
2119 (void) sprintf(errstr,
2120 gettext("LDAP ERROR (%d): %s.\n"),
2121 cookie->err_rc,
2122 gettext(ldap_err2string(cookie->err_rc)));
2123 err = strdup(errstr);
2124 MKERROR(LOG_WARNING, *errorp, NS_LDAP_INTERNAL, err,
2125 LDAP_ERROR);
2126 cookie->err_rc = NS_LDAP_INTERNAL;
2127 cookie->errorp = *errorp;
2128 return (LDAP_ERROR);
2129 }
2130 if (errCode == LDAP_REFERRAL) {
2131 for (i = 0; referrals[i] != NULL;
2132 i++) {
2133 /* add to referral list */
2134 rc = __s_api_addRefInfo(
2135 &cookie->reflist,
2136 referrals[i],
2137 cookie->basedn,
2138 &cookie->scope,
2139 cookie->filter,
2140 cookie->conn->ld);
2141 if (rc != NS_LDAP_SUCCESS) {
2142 ldap_value_free(
2143 referrals);
2144 if (retCtrls)
2145 ldap_controls_free(
2146 retCtrls);
2147 return (ERROR);
2148 }
2149 }
2150 ldap_value_free(referrals);
2151 if (retCtrls)
2152 ldap_controls_free(retCtrls);
2153 return (END_RESULT);
2154 }
2155 if (retCtrls) {
2156 if (cookie->ctrlCookie)
2157 ber_bvfree(cookie->ctrlCookie);
2158 cookie->ctrlCookie = NULL;
2159 rc = ldap_parse_page_control(
2160 cookie->conn->ld, retCtrls,
2161 &count, &cookie->ctrlCookie);
2162 if (rc == LDAP_SUCCESS) {
2163 if ((cookie->ctrlCookie == NULL) ||
2164 (cookie->ctrlCookie->bv_val == NULL) ||
2165 (cookie->ctrlCookie->bv_len == 0))
2166 finished = B_TRUE;
2167 }
2168 ldap_controls_free(retCtrls);
2169 retCtrls = NULL;
2170 } else {
2171 finished = B_TRUE;
2172 }
2173 }
2174 if (!finished && cookie->listType == VLVCTRLFLAG)
2175 return (NEXT_VLV);
2176 if (!finished && cookie->listType == SIMPLEPAGECTRLFLAG)
2177 return (NEXT_PAGE);
2178 if (finished)
2179 return (END_RESULT);
2180 return (ERROR);
2181 }
2182
2183 /*
2184 * clear_results(ns_ldap_cookie_t):
2185 *
2186 * Attempt to obtain remnants of ldap responses and free them. If remnants are
2187 * not obtained within a certain time period tell the server we wish to abandon
2188 * the request.
2189 *
2190 * Note that we do not initially tell the server to abandon the request as that
2191 * can be an expensive operation for the server, while it is cheap for us to
2192 * just flush the input.
2193 *
2194 * If something was to remain in libldap queue as a result of some error then
2195 * it would be freed later during drop connection call or when no other
2196 * requests share the connection.
2197 */
2198 static void
clear_results(ns_ldap_cookie_t * cookie)2199 clear_results(ns_ldap_cookie_t *cookie)
2200 {
2201 int rc;
2202 if (cookie->conn != NULL && cookie->conn->ld != NULL &&
2203 (cookie->connectionId != -1 ||
2204 (cookie->conn_user != NULL &&
2205 cookie->conn_user->conn_mt != NULL)) &&
2206 cookie->msgId != 0) {
2207 /*
2208 * We need to cleanup the rest of response (if there is such)
2209 * and LDAP abandon is too heavy for LDAP servers, so we will
2210 * wait for the rest of response till timeout and "process" it.
2211 */
2212 rc = ldap_result(cookie->conn->ld, cookie->msgId, LDAP_MSG_ALL,
2213 (struct timeval *)&cookie->search_timeout,
2214 &cookie->resultMsg);
2215 if (rc != -1 && rc != 0 && cookie->resultMsg != NULL) {
2216 (void) ldap_msgfree(cookie->resultMsg);
2217 cookie->resultMsg = NULL;
2218 }
2219
2220 /*
2221 * If there was timeout then we will send ABANDON request to
2222 * LDAP server to decrease load.
2223 */
2224 if (rc == 0)
2225 (void) ldap_abandon_ext(cookie->conn->ld, cookie->msgId,
2226 NULL, NULL);
2227 /* Disassociate cookie with msgId */
2228 cookie->msgId = 0;
2229 }
2230 }
2231
2232 /*
2233 * This state machine performs one or more LDAP searches to a given
2234 * directory server using service search descriptors and schema
2235 * mapping as appropriate. The approximate pseudocode for
2236 * this routine is the following:
2237 * Given the current configuration [set/reset connection etc.]
2238 * and the current service search descriptor list
2239 * or default search filter parameters
2240 * foreach (service search filter) {
2241 * initialize the filter [via filter_init if appropriate]
2242 * get a valid session/connection (preferably the current one)
2243 * Recover if the connection is lost
2244 * perform the search
2245 * foreach (result entry) {
2246 * process result [via callback if appropriate]
2247 * save result for caller if accepted.
2248 * exit and return all collected if allResults found;
2249 * }
2250 * }
2251 * return collected results and exit
2252 */
2253
2254 static
2255 ns_state_t
search_state_machine(ns_ldap_cookie_t * cookie,ns_state_t state,int cycle)2256 search_state_machine(ns_ldap_cookie_t *cookie, ns_state_t state, int cycle)
2257 {
2258 char errstr[MAXERROR];
2259 char *err;
2260 int rc, ret;
2261 int rc_save;
2262 ns_ldap_entry_t *nextEntry;
2263 ns_ldap_error_t *error = NULL;
2264 ns_ldap_error_t **errorp;
2265 struct timeval tv;
2266
2267 errorp = &error;
2268 cookie->state = state;
2269 errstr[0] = '\0';
2270
2271 for (;;) {
2272 switch (cookie->state) {
2273 case CLEAR_RESULTS:
2274 clear_results(cookie);
2275 cookie->new_state = EXIT;
2276 break;
2277 case GET_ACCT_MGMT_INFO:
2278 /*
2279 * Set the flag to get ldap account management controls.
2280 */
2281 cookie->nopasswd_acct_mgmt = 1;
2282 cookie->new_state = INIT;
2283 break;
2284 case EXIT:
2285 /* state engine/connection cleaned up in delete */
2286 if (cookie->attribute) {
2287 __s_api_free2dArray(cookie->attribute);
2288 cookie->attribute = NULL;
2289 }
2290 if (cookie->reflist) {
2291 __s_api_deleteRefInfo(cookie->reflist);
2292 cookie->reflist = NULL;
2293 }
2294 return (EXIT);
2295 case INIT:
2296 cookie->sdpos = NULL;
2297 cookie->new_state = NEXT_SEARCH_DESCRIPTOR;
2298 if (cookie->attribute) {
2299 __s_api_free2dArray(cookie->attribute);
2300 cookie->attribute = NULL;
2301 }
2302 if ((cookie->i_flags & NS_LDAP_NOMAP) == 0 &&
2303 cookie->i_attr) {
2304 cookie->attribute =
2305 __ns_ldap_mapAttributeList(
2306 cookie->service,
2307 cookie->i_attr);
2308 }
2309 break;
2310 case REINIT:
2311 /* Check if we've reached MAX retries. */
2312 cookie->retries++;
2313 if (cookie->retries > NS_LIST_TRY_MAX - 1) {
2314 cookie->new_state = LDAP_ERROR;
2315 break;
2316 }
2317
2318 /*
2319 * Even if we still have retries left, check
2320 * if retry is possible.
2321 */
2322 if (cookie->conn_user != NULL) {
2323 int retry;
2324 ns_conn_mgmt_t *cmg;
2325 cmg = cookie->conn_user->conn_mgmt;
2326 retry = cookie->conn_user->retry;
2327 if (cmg != NULL && cmg->cfg_reloaded == 1)
2328 retry = 1;
2329 if (retry == 0) {
2330 cookie->new_state = LDAP_ERROR;
2331 break;
2332 }
2333 }
2334 /*
2335 * Free results if any, reset to the first
2336 * search descriptor and start a new session.
2337 */
2338 if (cookie->resultMsg != NULL) {
2339 (void) ldap_msgfree(cookie->resultMsg);
2340 cookie->resultMsg = NULL;
2341 }
2342 (void) __ns_ldap_freeError(&cookie->errorp);
2343 (void) __ns_ldap_freeResult(&cookie->result);
2344 cookie->sdpos = cookie->sdlist;
2345 cookie->err_from_result = 0;
2346 cookie->err_rc = 0;
2347 cookie->new_state = NEXT_SESSION;
2348 break;
2349 case NEXT_SEARCH_DESCRIPTOR:
2350 /* get next search descriptor */
2351 if (cookie->sdpos == NULL) {
2352 cookie->sdpos = cookie->sdlist;
2353 cookie->new_state = GET_SESSION;
2354 } else {
2355 cookie->sdpos++;
2356 cookie->new_state = NEXT_SEARCH;
2357 }
2358 if (*cookie->sdpos == NULL)
2359 cookie->new_state = EXIT;
2360 break;
2361 case GET_SESSION:
2362 if (get_current_session(cookie) < 0)
2363 cookie->new_state = NEXT_SESSION;
2364 else
2365 cookie->new_state = NEXT_SEARCH;
2366 break;
2367 case NEXT_SESSION:
2368 if (get_next_session(cookie) < 0)
2369 cookie->new_state = RESTART_SESSION;
2370 else
2371 cookie->new_state = NEXT_SEARCH;
2372 break;
2373 case RESTART_SESSION:
2374 if (cookie->i_flags & NS_LDAP_HARD) {
2375 cookie->new_state = NEXT_SESSION;
2376 break;
2377 }
2378 (void) sprintf(errstr,
2379 gettext("Session error no available conn.\n"),
2380 state);
2381 err = strdup(errstr);
2382 MKERROR(LOG_WARNING, *errorp, NS_LDAP_INTERNAL, err,
2383 LDAP_ERROR);
2384 cookie->err_rc = NS_LDAP_INTERNAL;
2385 cookie->errorp = *errorp;
2386 cookie->new_state = EXIT;
2387 break;
2388 case NEXT_SEARCH:
2389 /* setup referrals search if necessary */
2390 if (cookie->refpos) {
2391 if (setup_referral_search(cookie) < 0) {
2392 cookie->new_state = EXIT;
2393 break;
2394 }
2395 } else if (setup_next_search(cookie) < 0) {
2396 cookie->new_state = EXIT;
2397 break;
2398 }
2399 /* only do VLV/PAGE on scopes onelevel/subtree */
2400 if (paging_supported(cookie)) {
2401 if (cookie->use_paging &&
2402 (cookie->scope != LDAP_SCOPE_BASE)) {
2403 cookie->index = 1;
2404 if (cookie->listType == VLVCTRLFLAG)
2405 cookie->new_state = NEXT_VLV;
2406 else
2407 cookie->new_state = NEXT_PAGE;
2408 break;
2409 }
2410 }
2411 cookie->new_state = ONE_SEARCH;
2412 break;
2413 case NEXT_VLV:
2414 rc = setup_vlv_params(cookie);
2415 if (rc != LDAP_SUCCESS) {
2416 cookie->err_rc = rc;
2417 cookie->new_state = LDAP_ERROR;
2418 break;
2419 }
2420 cookie->next_state = MULTI_RESULT;
2421 cookie->new_state = DO_SEARCH;
2422 break;
2423 case NEXT_PAGE:
2424 rc = setup_simplepg_params(cookie);
2425 if (rc != LDAP_SUCCESS) {
2426 cookie->err_rc = rc;
2427 cookie->new_state = LDAP_ERROR;
2428 break;
2429 }
2430 cookie->next_state = MULTI_RESULT;
2431 cookie->new_state = DO_SEARCH;
2432 break;
2433 case ONE_SEARCH:
2434 cookie->next_state = NEXT_RESULT;
2435 cookie->new_state = DO_SEARCH;
2436 break;
2437 case DO_SEARCH:
2438 cookie->entryCount = 0;
2439 rc = ldap_search_ext(cookie->conn->ld,
2440 cookie->basedn,
2441 cookie->scope,
2442 cookie->filter,
2443 cookie->attribute,
2444 0,
2445 cookie->p_serverctrls,
2446 NULL,
2447 &cookie->search_timeout, 0,
2448 &cookie->msgId);
2449 if (rc != LDAP_SUCCESS) {
2450 if (rc == LDAP_BUSY ||
2451 rc == LDAP_UNAVAILABLE ||
2452 rc == LDAP_UNWILLING_TO_PERFORM ||
2453 rc == LDAP_CONNECT_ERROR ||
2454 rc == LDAP_SERVER_DOWN) {
2455
2456 if (cookie->reinit_on_retriable_err) {
2457 cookie->err_rc = rc;
2458 cookie->new_state = REINIT;
2459 } else {
2460 cookie->new_state =
2461 NEXT_SESSION;
2462 }
2463
2464 /*
2465 * If not able to reach the
2466 * server, inform the ldap
2467 * cache manager that the
2468 * server should be removed
2469 * from it's server list.
2470 * Thus, the manager will not
2471 * return this server on the next
2472 * get-server request and will
2473 * also reduce the server list
2474 * refresh TTL, so that it will
2475 * find out sooner when the server
2476 * is up again.
2477 */
2478 if ((rc == LDAP_CONNECT_ERROR ||
2479 rc == LDAP_SERVER_DOWN) &&
2480 (cookie->conn_user == NULL ||
2481 cookie->conn_user->conn_mt ==
2482 NULL)) {
2483 ret = __s_api_removeServer(
2484 cookie->conn->serverAddr);
2485 if (ret == NS_CACHE_NOSERVER &&
2486 cookie->conn_auth_type
2487 == NS_LDAP_AUTH_NONE) {
2488 /*
2489 * Couldn't remove
2490 * server from server
2491 * list.
2492 * Exit to avoid
2493 * potential infinite
2494 * loop.
2495 */
2496 cookie->err_rc = rc;
2497 cookie->new_state =
2498 LDAP_ERROR;
2499 }
2500 if (cookie->connectionId > -1) {
2501 /*
2502 * NS_LDAP_NEW_CONN
2503 * indicates that the
2504 * connection should
2505 * be deleted, not
2506 * kept alive
2507 */
2508 DropConnection(
2509 cookie->
2510 connectionId,
2511 NS_LDAP_NEW_CONN);
2512 cookie->connectionId =
2513 -1;
2514 }
2515 } else if ((rc == LDAP_CONNECT_ERROR ||
2516 rc == LDAP_SERVER_DOWN) &&
2517 cookie->conn_user != NULL) {
2518 if (cookie->
2519 reinit_on_retriable_err) {
2520 /*
2521 * MT connection not
2522 * usable, close it
2523 * before REINIT.
2524 * rc has already
2525 * been saved in
2526 * cookie->err_rc above.
2527 */
2528 __s_api_conn_mt_close(
2529 cookie->conn_user,
2530 rc,
2531 &cookie->errorp);
2532 } else {
2533 /*
2534 * MT connection not
2535 * usable, close it in
2536 * the LDAP_ERROR state.
2537 * A retry will be done
2538 * next if allowed.
2539 */
2540 cookie->err_rc = rc;
2541 cookie->new_state =
2542 LDAP_ERROR;
2543 }
2544 }
2545 break;
2546 }
2547 cookie->err_rc = rc;
2548 cookie->new_state = LDAP_ERROR;
2549 break;
2550 }
2551 cookie->new_state = cookie->next_state;
2552 break;
2553 case NEXT_RESULT:
2554 /*
2555 * Caller (e.g. __ns_ldap_list_batch_add)
2556 * does not want to block on ldap_result().
2557 * Therefore we execute ldap_result() with
2558 * a zeroed timeval.
2559 */
2560 if (cookie->no_wait == B_TRUE)
2561 (void) memset(&tv, 0, sizeof (tv));
2562 else
2563 tv = cookie->search_timeout;
2564 rc = ldap_result(cookie->conn->ld, cookie->msgId,
2565 LDAP_MSG_ONE,
2566 &tv,
2567 &cookie->resultMsg);
2568 if (rc == LDAP_RES_SEARCH_RESULT) {
2569 cookie->new_state = END_RESULT;
2570 /* check and process referrals info */
2571 if (cookie->followRef)
2572 proc_result_referrals(
2573 cookie);
2574 (void) ldap_msgfree(cookie->resultMsg);
2575 cookie->resultMsg = NULL;
2576 break;
2577 }
2578 /* handle referrals if necessary */
2579 if (rc == LDAP_RES_SEARCH_REFERENCE) {
2580 if (cookie->followRef)
2581 proc_search_references(cookie);
2582 (void) ldap_msgfree(cookie->resultMsg);
2583 cookie->resultMsg = NULL;
2584 break;
2585 }
2586 if (rc != LDAP_RES_SEARCH_ENTRY) {
2587 switch (rc) {
2588 case 0:
2589 if (cookie->no_wait == B_TRUE) {
2590 (void) ldap_msgfree(
2591 cookie->resultMsg);
2592 cookie->resultMsg = NULL;
2593 return (cookie->new_state);
2594 }
2595 rc = LDAP_TIMEOUT;
2596 break;
2597 case -1:
2598 rc = ldap_get_lderrno(cookie->conn->ld,
2599 NULL, NULL);
2600 break;
2601 default:
2602 rc = ldap_result2error(cookie->conn->ld,
2603 cookie->resultMsg, 1);
2604 break;
2605 }
2606 if ((rc == LDAP_TIMEOUT ||
2607 rc == LDAP_SERVER_DOWN) &&
2608 (cookie->conn_user == NULL ||
2609 cookie->conn_user->conn_mt == NULL)) {
2610 if (rc == LDAP_TIMEOUT)
2611 (void) __s_api_removeServer(
2612 cookie->conn->serverAddr);
2613 if (cookie->connectionId > -1) {
2614 DropConnection(
2615 cookie->connectionId,
2616 NS_LDAP_NEW_CONN);
2617 cookie->connectionId = -1;
2618 }
2619 cookie->err_from_result = 1;
2620 }
2621 (void) ldap_msgfree(cookie->resultMsg);
2622 cookie->resultMsg = NULL;
2623 if (rc == LDAP_BUSY ||
2624 rc == LDAP_UNAVAILABLE ||
2625 rc == LDAP_UNWILLING_TO_PERFORM) {
2626 if (cookie->reinit_on_retriable_err) {
2627 cookie->err_rc = rc;
2628 cookie->err_from_result = 1;
2629 cookie->new_state = REINIT;
2630 } else {
2631 cookie->new_state =
2632 NEXT_SESSION;
2633 }
2634 break;
2635 }
2636 if ((rc == LDAP_CONNECT_ERROR ||
2637 rc == LDAP_SERVER_DOWN) &&
2638 cookie->reinit_on_retriable_err) {
2639 ns_ldap_error_t *errorp = NULL;
2640 cookie->err_rc = rc;
2641 cookie->err_from_result = 1;
2642 cookie->new_state = REINIT;
2643 if (cookie->conn_user != NULL)
2644 __s_api_conn_mt_close(
2645 cookie->conn_user,
2646 rc, &errorp);
2647 if (errorp != NULL) {
2648 (void) __ns_ldap_freeError(
2649 &cookie->errorp);
2650 cookie->errorp = errorp;
2651 }
2652 break;
2653 }
2654 cookie->err_rc = rc;
2655 cookie->new_state = LDAP_ERROR;
2656 break;
2657 }
2658 /* else LDAP_RES_SEARCH_ENTRY */
2659 /* get account management response control */
2660 if (cookie->nopasswd_acct_mgmt == 1) {
2661 rc = ldap_get_entry_controls(cookie->conn->ld,
2662 cookie->resultMsg,
2663 &(cookie->resultctrl));
2664 if (rc != LDAP_SUCCESS) {
2665 cookie->new_state = LDAP_ERROR;
2666 cookie->err_rc = rc;
2667 break;
2668 }
2669 }
2670 rc = __s_api_getEntry(cookie);
2671 (void) ldap_msgfree(cookie->resultMsg);
2672 cookie->resultMsg = NULL;
2673 if (rc != NS_LDAP_SUCCESS) {
2674 cookie->new_state = LDAP_ERROR;
2675 break;
2676 }
2677 cookie->new_state = PROCESS_RESULT;
2678 cookie->next_state = NEXT_RESULT;
2679 break;
2680 case MULTI_RESULT:
2681 if (cookie->no_wait == B_TRUE)
2682 (void) memset(&tv, 0, sizeof (tv));
2683 else
2684 tv = cookie->search_timeout;
2685 rc = ldap_result(cookie->conn->ld, cookie->msgId,
2686 LDAP_MSG_ONE,
2687 &tv,
2688 &cookie->resultMsg);
2689 if (rc == LDAP_RES_SEARCH_RESULT) {
2690 rc = ldap_result2error(cookie->conn->ld,
2691 cookie->resultMsg, 0);
2692 if (rc == LDAP_ADMINLIMIT_EXCEEDED &&
2693 cookie->listType == VLVCTRLFLAG &&
2694 cookie->sortTypeTry == SSS_SINGLE_ATTR) {
2695 /* Try old "cn uid" server side sort */
2696 cookie->sortTypeTry = SSS_CN_UID_ATTRS;
2697 cookie->new_state = NEXT_VLV;
2698 (void) ldap_msgfree(cookie->resultMsg);
2699 cookie->resultMsg = NULL;
2700 break;
2701 }
2702 if (rc != LDAP_SUCCESS) {
2703 cookie->err_rc = rc;
2704 cookie->new_state = LDAP_ERROR;
2705 (void) ldap_msgfree(cookie->resultMsg);
2706 cookie->resultMsg = NULL;
2707 break;
2708 }
2709 cookie->new_state = multi_result(cookie);
2710 (void) ldap_msgfree(cookie->resultMsg);
2711 cookie->resultMsg = NULL;
2712 break;
2713 }
2714 /* handle referrals if necessary */
2715 if (rc == LDAP_RES_SEARCH_REFERENCE &&
2716 cookie->followRef) {
2717 proc_search_references(cookie);
2718 (void) ldap_msgfree(cookie->resultMsg);
2719 cookie->resultMsg = NULL;
2720 break;
2721 }
2722 if (rc != LDAP_RES_SEARCH_ENTRY) {
2723 switch (rc) {
2724 case 0:
2725 if (cookie->no_wait == B_TRUE) {
2726 (void) ldap_msgfree(
2727 cookie->resultMsg);
2728 cookie->resultMsg = NULL;
2729 return (cookie->new_state);
2730 }
2731 rc = LDAP_TIMEOUT;
2732 break;
2733 case -1:
2734 rc = ldap_get_lderrno(cookie->conn->ld,
2735 NULL, NULL);
2736 break;
2737 default:
2738 rc = ldap_result2error(cookie->conn->ld,
2739 cookie->resultMsg, 1);
2740 break;
2741 }
2742 if ((rc == LDAP_TIMEOUT ||
2743 rc == LDAP_SERVER_DOWN) &&
2744 (cookie->conn_user == NULL ||
2745 cookie->conn_user->conn_mt == NULL)) {
2746 if (rc == LDAP_TIMEOUT)
2747 (void) __s_api_removeServer(
2748 cookie->conn->serverAddr);
2749 if (cookie->connectionId > -1) {
2750 DropConnection(
2751 cookie->connectionId,
2752 NS_LDAP_NEW_CONN);
2753 cookie->connectionId = -1;
2754 }
2755 cookie->err_from_result = 1;
2756 }
2757 (void) ldap_msgfree(cookie->resultMsg);
2758 cookie->resultMsg = NULL;
2759 if (rc == LDAP_BUSY ||
2760 rc == LDAP_UNAVAILABLE ||
2761 rc == LDAP_UNWILLING_TO_PERFORM) {
2762 if (cookie->reinit_on_retriable_err) {
2763 cookie->err_rc = rc;
2764 cookie->err_from_result = 1;
2765 cookie->new_state = REINIT;
2766 } else {
2767 cookie->new_state =
2768 NEXT_SESSION;
2769 }
2770 break;
2771 }
2772
2773 if ((rc == LDAP_CONNECT_ERROR ||
2774 rc == LDAP_SERVER_DOWN) &&
2775 cookie->reinit_on_retriable_err) {
2776 ns_ldap_error_t *errorp = NULL;
2777 cookie->err_rc = rc;
2778 cookie->err_from_result = 1;
2779 cookie->new_state = REINIT;
2780 if (cookie->conn_user != NULL)
2781 __s_api_conn_mt_close(
2782 cookie->conn_user,
2783 rc, &errorp);
2784 if (errorp != NULL) {
2785 (void) __ns_ldap_freeError(
2786 &cookie->errorp);
2787 cookie->errorp = errorp;
2788 }
2789 break;
2790 }
2791 cookie->err_rc = rc;
2792 cookie->new_state = LDAP_ERROR;
2793 break;
2794 }
2795 /* else LDAP_RES_SEARCH_ENTRY */
2796 cookie->entryCount++;
2797 rc = __s_api_getEntry(cookie);
2798 (void) ldap_msgfree(cookie->resultMsg);
2799 cookie->resultMsg = NULL;
2800 if (rc != NS_LDAP_SUCCESS) {
2801 cookie->new_state = LDAP_ERROR;
2802 break;
2803 }
2804 /*
2805 * If VLV search was successfull save the server
2806 * side sort type tried.
2807 */
2808 if (cookie->listType == VLVCTRLFLAG)
2809 update_srvsidesort_type(cookie->service,
2810 cookie->sortTypeTry);
2811
2812 cookie->new_state = PROCESS_RESULT;
2813 cookie->next_state = MULTI_RESULT;
2814 break;
2815 case PROCESS_RESULT:
2816 /* NOTE THIS STATE MAY BE PROCESSED BY CALLER */
2817 if (cookie->use_usercb && cookie->callback) {
2818 rc = 0;
2819 for (nextEntry = cookie->result->entry;
2820 nextEntry != NULL;
2821 nextEntry = nextEntry->next) {
2822 rc = (*cookie->callback)(nextEntry,
2823 cookie->userdata);
2824
2825 if (rc == NS_LDAP_CB_DONE) {
2826 /* cb doesn't want any more data */
2827 rc = NS_LDAP_PARTIAL;
2828 cookie->err_rc = rc;
2829 break;
2830 } else if (rc != NS_LDAP_CB_NEXT) {
2831 /* invalid return code */
2832 rc = NS_LDAP_OP_FAILED;
2833 cookie->err_rc = rc;
2834 break;
2835 }
2836 }
2837 (void) __ns_ldap_freeResult(&cookie->result);
2838 cookie->result = NULL;
2839 }
2840 if (rc != 0) {
2841 cookie->new_state = EXIT;
2842 break;
2843 }
2844 /* NOTE PREVIOUS STATE SPECIFIES NEXT STATE */
2845 cookie->new_state = cookie->next_state;
2846 break;
2847 case END_PROCESS_RESULT:
2848 cookie->new_state = cookie->next_state;
2849 break;
2850 case END_RESULT:
2851 /*
2852 * XXX DO WE NEED THIS CASE?
2853 * if (search is complete) {
2854 * cookie->new_state = EXIT;
2855 * } else
2856 */
2857 /*
2858 * entering referral mode if necessary
2859 */
2860 if (cookie->followRef && cookie->reflist)
2861 cookie->new_state =
2862 NEXT_REFERRAL;
2863 else
2864 cookie->new_state =
2865 NEXT_SEARCH_DESCRIPTOR;
2866 break;
2867 case NEXT_REFERRAL:
2868 /* get next referral info */
2869 if (cookie->refpos == NULL)
2870 cookie->refpos =
2871 cookie->reflist;
2872 else
2873 cookie->refpos =
2874 cookie->refpos->next;
2875 /* check see if done with all referrals */
2876 if (cookie->refpos != NULL) {
2877 cookie->new_state =
2878 GET_REFERRAL_SESSION;
2879 } else {
2880 __s_api_deleteRefInfo(cookie->reflist);
2881 cookie->reflist = NULL;
2882 cookie->new_state =
2883 NEXT_SEARCH_DESCRIPTOR;
2884 if (cookie->conn_user != NULL)
2885 cookie->conn_user->referral = B_FALSE;
2886 }
2887 break;
2888 case GET_REFERRAL_SESSION:
2889 if (get_referral_session(cookie) < 0) {
2890 cookie->new_state = EXIT;
2891 } else {
2892 cookie->new_state = NEXT_SEARCH;
2893 }
2894 break;
2895 case LDAP_ERROR:
2896 rc_save = cookie->err_rc;
2897 if (cookie->err_from_result) {
2898 if (cookie->err_rc == LDAP_SERVER_DOWN) {
2899 (void) sprintf(errstr,
2900 gettext("LDAP ERROR (%d): "
2901 "Error occurred during"
2902 " receiving results. "
2903 "Connection to server lost."),
2904 cookie->err_rc);
2905 } else if (cookie->err_rc == LDAP_TIMEOUT) {
2906 (void) sprintf(errstr,
2907 gettext("LDAP ERROR (%d): "
2908 "Error occurred during"
2909 " receiving results. %s"
2910 "."), cookie->err_rc,
2911 ldap_err2string(
2912 cookie->err_rc));
2913 }
2914 } else {
2915 (void) sprintf(errstr,
2916 gettext("LDAP ERROR (%d): %s."),
2917 cookie->err_rc,
2918 ldap_err2string(cookie->err_rc));
2919 }
2920 err = strdup(errstr);
2921 if (cookie->err_from_result) {
2922 if (cookie->err_rc == LDAP_SERVER_DOWN) {
2923 MKERROR(LOG_INFO, *errorp,
2924 cookie->err_rc, err,
2925 LDAP_ERROR);
2926 } else {
2927 MKERROR(LOG_WARNING, *errorp,
2928 cookie->err_rc, err,
2929 LDAP_ERROR);
2930 }
2931 } else {
2932 MKERROR(LOG_WARNING, *errorp, NS_LDAP_INTERNAL,
2933 err, LDAP_ERROR);
2934 }
2935 cookie->err_rc = NS_LDAP_INTERNAL;
2936 cookie->errorp = *errorp;
2937 if (cookie->conn_user != NULL) {
2938 if (rc_save == LDAP_SERVER_DOWN ||
2939 rc_save == LDAP_CONNECT_ERROR) {
2940 /*
2941 * MT connection is not usable,
2942 * close it.
2943 */
2944 __s_api_conn_mt_close(cookie->conn_user,
2945 rc_save, &cookie->errorp);
2946 return (ERROR);
2947 }
2948 }
2949 return (ERROR);
2950 default:
2951 case ERROR:
2952 (void) sprintf(errstr,
2953 gettext("Internal State machine exit (%d).\n"),
2954 cookie->state);
2955 err = strdup(errstr);
2956 MKERROR(LOG_WARNING, *errorp, NS_LDAP_INTERNAL, err,
2957 LDAP_ERROR);
2958 cookie->err_rc = NS_LDAP_INTERNAL;
2959 cookie->errorp = *errorp;
2960 return (ERROR);
2961 }
2962
2963 if (cookie->conn_user != NULL &&
2964 cookie->conn_user->bad_mt_conn == B_TRUE) {
2965 __s_api_conn_mt_close(cookie->conn_user, 0, NULL);
2966 cookie->err_rc = cookie->conn_user->ns_rc;
2967 cookie->errorp = cookie->conn_user->ns_error;
2968 cookie->conn_user->ns_error = NULL;
2969 return (ERROR);
2970 }
2971
2972 if (cycle == ONE_STEP) {
2973 return (cookie->new_state);
2974 }
2975 cookie->state = cookie->new_state;
2976 }
2977 /*NOTREACHED*/
2978 #if 0
2979 (void) sprintf(errstr,
2980 gettext("Unexpected State machine error.\n"));
2981 err = strdup(errstr);
2982 MKERROR(LOG_WARNING, *errorp, NS_LDAP_INTERNAL, err, NS_LDAP_MEMORY);
2983 cookie->err_rc = NS_LDAP_INTERNAL;
2984 cookie->errorp = *errorp;
2985 return (ERROR);
2986 #endif
2987 }
2988
2989 /*
2990 * For a lookup of shadow data, if shadow update is enabled,
2991 * check the calling process' privilege to ensure it's
2992 * allowed to perform such operation.
2993 */
2994 static int
check_shadow(ns_ldap_cookie_t * cookie,const char * service)2995 check_shadow(ns_ldap_cookie_t *cookie, const char *service)
2996 {
2997 char errstr[MAXERROR];
2998 char *err;
2999 boolean_t priv;
3000 /* caller */
3001 priv_set_t *ps;
3002 /* zone */
3003 priv_set_t *zs;
3004
3005 /*
3006 * If service is "shadow", we may need
3007 * to use privilege credentials.
3008 */
3009 if ((strcmp(service, "shadow") == 0) &&
3010 __ns_ldap_is_shadow_update_enabled()) {
3011 /*
3012 * Since we release admin credentials after
3013 * connection is closed and we do not cache
3014 * them, we allow any root or all zone
3015 * privilege process to read shadow data.
3016 */
3017 priv = (geteuid() == 0);
3018 if (!priv) {
3019 /* caller */
3020 ps = priv_allocset();
3021
3022 (void) getppriv(PRIV_EFFECTIVE, ps);
3023 zs = priv_str_to_set("zone", ",", NULL);
3024 priv = priv_isequalset(ps, zs);
3025 priv_freeset(ps);
3026 priv_freeset(zs);
3027 }
3028 if (!priv) {
3029 (void) sprintf(errstr,
3030 gettext("Permission denied"));
3031 err = strdup(errstr);
3032 if (err == NULL)
3033 return (NS_LDAP_MEMORY);
3034 MKERROR(LOG_INFO, cookie->errorp, NS_LDAP_INTERNAL, err,
3035 NS_LDAP_MEMORY);
3036 return (NS_LDAP_INTERNAL);
3037 }
3038 cookie->i_flags |= NS_LDAP_READ_SHADOW;
3039 /*
3040 * We do not want to reuse connection (hence
3041 * keep it open) with admin credentials.
3042 * If NS_LDAP_KEEP_CONN is set, reject the
3043 * request.
3044 */
3045 if (cookie->i_flags & NS_LDAP_KEEP_CONN)
3046 return (NS_LDAP_INVALID_PARAM);
3047 cookie->i_flags |= NS_LDAP_NEW_CONN;
3048 }
3049
3050 return (NS_LDAP_SUCCESS);
3051 }
3052
3053 /*
3054 * internal function for __ns_ldap_list
3055 */
3056 static int
ldap_list(ns_ldap_list_batch_t * batch,const char * service,const char * filter,const char * sortattr,int (* init_filter_cb)(const ns_ldap_search_desc_t * desc,char ** realfilter,const void * userdata),const char * const * attribute,const ns_cred_t * auth,const int flags,ns_ldap_result_t ** rResult,ns_ldap_error_t ** errorp,int * rcp,int (* callback)(const ns_ldap_entry_t * entry,const void * userdata),const void * userdata,ns_conn_user_t * conn_user)3057 ldap_list(
3058 ns_ldap_list_batch_t *batch,
3059 const char *service,
3060 const char *filter,
3061 const char *sortattr,
3062 int (*init_filter_cb)(const ns_ldap_search_desc_t *desc,
3063 char **realfilter, const void *userdata),
3064 const char * const *attribute,
3065 const ns_cred_t *auth,
3066 const int flags,
3067 ns_ldap_result_t **rResult, /* return result entries */
3068 ns_ldap_error_t **errorp,
3069 int *rcp,
3070 int (*callback)(const ns_ldap_entry_t *entry, const void *userdata),
3071 const void *userdata, ns_conn_user_t *conn_user)
3072 {
3073 ns_ldap_cookie_t *cookie;
3074 ns_ldap_search_desc_t **sdlist = NULL;
3075 ns_ldap_search_desc_t *dptr;
3076 ns_ldap_error_t *error = NULL;
3077 char **dns = NULL;
3078 int scope;
3079 int rc;
3080 int from_result;
3081
3082 *errorp = NULL;
3083 *rResult = NULL;
3084 *rcp = NS_LDAP_SUCCESS;
3085
3086 /*
3087 * Sanity check - NS_LDAP_READ_SHADOW is for our
3088 * own internal use.
3089 */
3090 if (flags & NS_LDAP_READ_SHADOW)
3091 return (NS_LDAP_INVALID_PARAM);
3092
3093 /* Initialize State machine cookie */
3094 cookie = init_search_state_machine();
3095 if (cookie == NULL) {
3096 *rcp = NS_LDAP_MEMORY;
3097 return (NS_LDAP_MEMORY);
3098 }
3099 cookie->conn_user = conn_user;
3100
3101 /* see if need to follow referrals */
3102 rc = __s_api_toFollowReferrals(flags,
3103 &cookie->followRef, errorp);
3104 if (rc != NS_LDAP_SUCCESS) {
3105 delete_search_cookie(cookie);
3106 *rcp = rc;
3107 return (rc);
3108 }
3109
3110 /* get the service descriptor - or create a default one */
3111 rc = __s_api_get_SSD_from_SSDtoUse_service(service,
3112 &sdlist, &error);
3113 if (rc != NS_LDAP_SUCCESS) {
3114 delete_search_cookie(cookie);
3115 *errorp = error;
3116 *rcp = rc;
3117 return (rc);
3118 }
3119
3120 if (sdlist == NULL) {
3121 /* Create default service Desc */
3122 sdlist = (ns_ldap_search_desc_t **)calloc(2,
3123 sizeof (ns_ldap_search_desc_t *));
3124 if (sdlist == NULL) {
3125 delete_search_cookie(cookie);
3126 cookie = NULL;
3127 *rcp = NS_LDAP_MEMORY;
3128 return (NS_LDAP_MEMORY);
3129 }
3130 dptr = (ns_ldap_search_desc_t *)
3131 calloc(1, sizeof (ns_ldap_search_desc_t));
3132 if (dptr == NULL) {
3133 free(sdlist);
3134 delete_search_cookie(cookie);
3135 cookie = NULL;
3136 *rcp = NS_LDAP_MEMORY;
3137 return (NS_LDAP_MEMORY);
3138 }
3139 sdlist[0] = dptr;
3140
3141 /* default base */
3142 rc = __s_api_getDNs(&dns, service, &cookie->errorp);
3143 if (rc != NS_LDAP_SUCCESS) {
3144 if (dns) {
3145 __s_api_free2dArray(dns);
3146 dns = NULL;
3147 }
3148 *errorp = cookie->errorp;
3149 cookie->errorp = NULL;
3150 delete_search_cookie(cookie);
3151 cookie = NULL;
3152 *rcp = rc;
3153 return (rc);
3154 }
3155 dptr->basedn = strdup(dns[0]);
3156 __s_api_free2dArray(dns);
3157 dns = NULL;
3158
3159 /* default scope */
3160 scope = 0;
3161 rc = __s_api_getSearchScope(&scope, &cookie->errorp);
3162 dptr->scope = scope;
3163 }
3164
3165 cookie->sdlist = sdlist;
3166
3167 /*
3168 * use VLV/PAGE control only if NS_LDAP_PAGE_CTRL is set
3169 */
3170 if (flags & NS_LDAP_PAGE_CTRL)
3171 cookie->use_paging = TRUE;
3172 else
3173 cookie->use_paging = FALSE;
3174
3175 /* Set up other arguments */
3176 cookie->userdata = userdata;
3177 if (init_filter_cb != NULL) {
3178 cookie->init_filter_cb = init_filter_cb;
3179 cookie->use_filtercb = 1;
3180 }
3181 if (callback != NULL) {
3182 cookie->callback = callback;
3183 cookie->use_usercb = 1;
3184 }
3185
3186 /* check_shadow() may add extra value to cookie->i_flags */
3187 cookie->i_flags = flags;
3188 if (service) {
3189 cookie->service = strdup(service);
3190 if (cookie->service == NULL) {
3191 delete_search_cookie(cookie);
3192 cookie = NULL;
3193 *rcp = NS_LDAP_MEMORY;
3194 return (NS_LDAP_MEMORY);
3195 }
3196
3197 /*
3198 * If given, use the credential given by the caller, and
3199 * skip the credential check required for shadow update.
3200 */
3201 if (auth == NULL) {
3202 rc = check_shadow(cookie, service);
3203 if (rc != NS_LDAP_SUCCESS) {
3204 *errorp = cookie->errorp;
3205 cookie->errorp = NULL;
3206 delete_search_cookie(cookie);
3207 cookie = NULL;
3208 *rcp = rc;
3209 return (rc);
3210 }
3211 }
3212 }
3213
3214 cookie->i_filter = strdup(filter);
3215 cookie->i_attr = attribute;
3216 cookie->i_auth = auth;
3217 cookie->i_sortattr = sortattr;
3218
3219 if (batch != NULL) {
3220 cookie->batch = batch;
3221 cookie->reinit_on_retriable_err = B_TRUE;
3222 cookie->no_wait = B_TRUE;
3223 (void) search_state_machine(cookie, INIT, 0);
3224 cookie->no_wait = B_FALSE;
3225 rc = cookie->err_rc;
3226
3227 if (rc == NS_LDAP_SUCCESS) {
3228 /*
3229 * Here rc == NS_LDAP_SUCCESS means that the state
3230 * machine init'ed successfully. The actual status
3231 * of the search will be determined by
3232 * __ns_ldap_list_batch_end(). Add the cookie to our
3233 * batch.
3234 */
3235 cookie->caller_result = rResult;
3236 cookie->caller_errorp = errorp;
3237 cookie->caller_rc = rcp;
3238 cookie->next_cookie_in_batch = batch->cookie_list;
3239 batch->cookie_list = cookie;
3240 batch->nactive++;
3241 return (rc);
3242 }
3243 /*
3244 * If state machine init failed then copy error to the caller
3245 * and delete the cookie.
3246 */
3247 } else {
3248 (void) search_state_machine(cookie, INIT, 0);
3249 }
3250
3251 /* Copy results back to user */
3252 rc = cookie->err_rc;
3253 if (rc != NS_LDAP_SUCCESS) {
3254 if (conn_user != NULL && conn_user->ns_error != NULL) {
3255 *errorp = conn_user->ns_error;
3256 conn_user->ns_error = NULL;
3257 } else {
3258 *errorp = cookie->errorp;
3259 }
3260 }
3261 *rResult = cookie->result;
3262 from_result = cookie->err_from_result;
3263
3264 cookie->errorp = NULL;
3265 cookie->result = NULL;
3266 delete_search_cookie(cookie);
3267 cookie = NULL;
3268
3269 if (from_result == 0 && *rResult == NULL)
3270 rc = NS_LDAP_NOTFOUND;
3271 *rcp = rc;
3272 return (rc);
3273 }
3274
3275
3276 /*
3277 * __ns_ldap_list performs one or more LDAP searches to a given
3278 * directory server using service search descriptors and schema
3279 * mapping as appropriate. The operation may be retried a
3280 * couple of times in error situations.
3281 */
3282 int
__ns_ldap_list(const char * service,const char * filter,int (* init_filter_cb)(const ns_ldap_search_desc_t * desc,char ** realfilter,const void * userdata),const char * const * attribute,const ns_cred_t * auth,const int flags,ns_ldap_result_t ** rResult,ns_ldap_error_t ** errorp,int (* callback)(const ns_ldap_entry_t * entry,const void * userdata),const void * userdata)3283 __ns_ldap_list(
3284 const char *service,
3285 const char *filter,
3286 int (*init_filter_cb)(const ns_ldap_search_desc_t *desc,
3287 char **realfilter, const void *userdata),
3288 const char * const *attribute,
3289 const ns_cred_t *auth,
3290 const int flags,
3291 ns_ldap_result_t **rResult, /* return result entries */
3292 ns_ldap_error_t **errorp,
3293 int (*callback)(const ns_ldap_entry_t *entry, const void *userdata),
3294 const void *userdata)
3295 {
3296 int mod_flags;
3297 /*
3298 * Strip the NS_LDAP_PAGE_CTRL option as this interface does not
3299 * support this. If you want to use this option call the API
3300 * __ns_ldap_list_sort() with has the sort attribute.
3301 */
3302 mod_flags = flags & (~NS_LDAP_PAGE_CTRL);
3303
3304 return (__ns_ldap_list_sort(service, filter, NULL, init_filter_cb,
3305 attribute, auth, mod_flags, rResult, errorp,
3306 callback, userdata));
3307 }
3308
3309 /*
3310 * __ns_ldap_list_sort performs one or more LDAP searches to a given
3311 * directory server using service search descriptors and schema
3312 * mapping as appropriate. The operation may be retried a
3313 * couple of times in error situations.
3314 */
3315 int
__ns_ldap_list_sort(const char * service,const char * filter,const char * sortattr,int (* init_filter_cb)(const ns_ldap_search_desc_t * desc,char ** realfilter,const void * userdata),const char * const * attribute,const ns_cred_t * auth,const int flags,ns_ldap_result_t ** rResult,ns_ldap_error_t ** errorp,int (* callback)(const ns_ldap_entry_t * entry,const void * userdata),const void * userdata)3316 __ns_ldap_list_sort(
3317 const char *service,
3318 const char *filter,
3319 const char *sortattr,
3320 int (*init_filter_cb)(const ns_ldap_search_desc_t *desc,
3321 char **realfilter, const void *userdata),
3322 const char * const *attribute,
3323 const ns_cred_t *auth,
3324 const int flags,
3325 ns_ldap_result_t **rResult, /* return result entries */
3326 ns_ldap_error_t **errorp,
3327 int (*callback)(const ns_ldap_entry_t *entry, const void *userdata),
3328 const void *userdata)
3329 {
3330 ns_conn_user_t *cu = NULL;
3331 int try_cnt = 0;
3332 int rc = NS_LDAP_SUCCESS, trc;
3333
3334 for (;;) {
3335 if (__s_api_setup_retry_search(&cu, NS_CONN_USER_SEARCH,
3336 &try_cnt, &rc, errorp) == 0)
3337 break;
3338 rc = ldap_list(NULL, service, filter, sortattr, init_filter_cb,
3339 attribute, auth, flags, rResult, errorp, &trc, callback,
3340 userdata, cu);
3341 }
3342
3343 return (rc);
3344 }
3345
3346 /*
3347 * Create and initialize batch for native LDAP lookups
3348 */
3349 int
__ns_ldap_list_batch_start(ns_ldap_list_batch_t ** batch)3350 __ns_ldap_list_batch_start(ns_ldap_list_batch_t **batch)
3351 {
3352 *batch = calloc(1, sizeof (ns_ldap_list_batch_t));
3353 if (*batch == NULL)
3354 return (NS_LDAP_MEMORY);
3355 return (NS_LDAP_SUCCESS);
3356 }
3357
3358
3359 /*
3360 * Add a LDAP search request to the batch.
3361 */
3362 int
__ns_ldap_list_batch_add(ns_ldap_list_batch_t * batch,const char * service,const char * filter,int (* init_filter_cb)(const ns_ldap_search_desc_t * desc,char ** realfilter,const void * userdata),const char * const * attribute,const ns_cred_t * auth,const int flags,ns_ldap_result_t ** rResult,ns_ldap_error_t ** errorp,int * rcp,int (* callback)(const ns_ldap_entry_t * entry,const void * userdata),const void * userdata)3363 __ns_ldap_list_batch_add(
3364 ns_ldap_list_batch_t *batch,
3365 const char *service,
3366 const char *filter,
3367 int (*init_filter_cb)(const ns_ldap_search_desc_t *desc,
3368 char **realfilter, const void *userdata),
3369 const char * const *attribute,
3370 const ns_cred_t *auth,
3371 const int flags,
3372 ns_ldap_result_t **rResult, /* return result entries */
3373 ns_ldap_error_t **errorp,
3374 int *rcp,
3375 int (*callback)(const ns_ldap_entry_t *entry, const void *userdata),
3376 const void *userdata)
3377 {
3378 ns_conn_user_t *cu;
3379 int rc;
3380 int mod_flags;
3381
3382 cu = __s_api_conn_user_init(NS_CONN_USER_SEARCH, NULL, 0);
3383 if (cu == NULL) {
3384 if (rcp != NULL)
3385 *rcp = NS_LDAP_MEMORY;
3386 return (NS_LDAP_MEMORY);
3387 }
3388
3389 /*
3390 * Strip the NS_LDAP_PAGE_CTRL option as the batch interface does not
3391 * support this.
3392 */
3393 mod_flags = flags & (~NS_LDAP_PAGE_CTRL);
3394
3395 rc = ldap_list(batch, service, filter, NULL, init_filter_cb, attribute,
3396 auth, mod_flags, rResult, errorp, rcp, callback, userdata, cu);
3397
3398 /*
3399 * Free the conn_user if the cookie was not batched. If the cookie
3400 * was batched then __ns_ldap_list_batch_end or release will free the
3401 * conn_user. The batch API instructs the search_state_machine
3402 * to reinit and retry (max 3 times) on retriable LDAP errors.
3403 */
3404 if (rc != NS_LDAP_SUCCESS && cu != NULL) {
3405 if (cu->conn_mt != NULL)
3406 __s_api_conn_mt_return(cu);
3407 __s_api_conn_user_free(cu);
3408 }
3409 return (rc);
3410 }
3411
3412
3413 /*
3414 * Free batch.
3415 */
3416 void
__ns_ldap_list_batch_release(ns_ldap_list_batch_t * batch)3417 __ns_ldap_list_batch_release(ns_ldap_list_batch_t *batch)
3418 {
3419 ns_ldap_cookie_t *c, *next;
3420
3421 for (c = batch->cookie_list; c != NULL; c = next) {
3422 next = c->next_cookie_in_batch;
3423 if (c->conn_user != NULL) {
3424 if (c->conn_user->conn_mt != NULL)
3425 __s_api_conn_mt_return(c->conn_user);
3426 __s_api_conn_user_free(c->conn_user);
3427 c->conn_user = NULL;
3428 }
3429 delete_search_cookie(c);
3430 }
3431 free(batch);
3432 }
3433
3434 #define LD_USING_STATE(st) \
3435 ((st == DO_SEARCH) || (st == MULTI_RESULT) || (st == NEXT_RESULT))
3436
3437 /*
3438 * Process batch. Everytime this function is called it selects an
3439 * active cookie from the batch and single steps through the
3440 * search_state_machine for the selected cookie. If lookup associated
3441 * with the cookie is complete (success or error) then the cookie is
3442 * removed from the batch and its memory freed.
3443 *
3444 * Returns 1 (if batch still has active cookies)
3445 * 0 (if batch has no more active cookies)
3446 * -1 (on errors, *rcp will contain the error code)
3447 *
3448 * The caller should call this function in a loop as long as it returns 1
3449 * to process all the requests added to the batch. The results (and errors)
3450 * will be available in the locations provided by the caller at the time of
3451 * __ns_ldap_list_batch_add().
3452 */
3453 static
3454 int
__ns_ldap_list_batch_process(ns_ldap_list_batch_t * batch,int * rcp)3455 __ns_ldap_list_batch_process(ns_ldap_list_batch_t *batch, int *rcp)
3456 {
3457 ns_ldap_cookie_t *c, *ptr, **prev;
3458 ns_state_t state;
3459 ns_ldap_error_t *errorp = NULL;
3460 int rc;
3461
3462 /* Check if are already done */
3463 if (batch->nactive == 0)
3464 return (0);
3465
3466 /* Get the next cookie from the batch */
3467 c = (batch->next_cookie == NULL) ?
3468 batch->cookie_list : batch->next_cookie;
3469
3470 batch->next_cookie = c->next_cookie_in_batch;
3471
3472 /*
3473 * Checks the status of the cookie's connection if it needs
3474 * to use that connection for ldap_search_ext or ldap_result.
3475 * If the connection is no longer good but worth retrying
3476 * then reinit the search_state_machine for this cookie
3477 * starting from the first search descriptor. REINIT will
3478 * clear any leftover results if max retries have not been
3479 * reached and redo the search (which may also involve
3480 * following referrals again).
3481 *
3482 * Note that each cookie in the batch will make this
3483 * determination when it reaches one of the LD_USING_STATES.
3484 */
3485 if (LD_USING_STATE(c->new_state) && c->conn_user != NULL) {
3486 rc = __s_api_setup_getnext(c->conn_user, &c->err_rc, &errorp);
3487 if (rc == LDAP_BUSY || rc == LDAP_UNAVAILABLE ||
3488 rc == LDAP_UNWILLING_TO_PERFORM) {
3489 if (errorp != NULL) {
3490 (void) __ns_ldap_freeError(&c->errorp);
3491 c->errorp = errorp;
3492 }
3493 c->new_state = REINIT;
3494 } else if (rc == LDAP_CONNECT_ERROR ||
3495 rc == LDAP_SERVER_DOWN) {
3496 if (errorp != NULL) {
3497 (void) __ns_ldap_freeError(&c->errorp);
3498 c->errorp = errorp;
3499 }
3500 c->new_state = REINIT;
3501 /*
3502 * MT connection is not usable,
3503 * close it before REINIT.
3504 */
3505 __s_api_conn_mt_close(
3506 c->conn_user, rc, NULL);
3507 } else if (rc != NS_LDAP_SUCCESS) {
3508 if (rcp != NULL)
3509 *rcp = rc;
3510 *c->caller_result = NULL;
3511 *c->caller_errorp = errorp;
3512 *c->caller_rc = rc;
3513 return (-1);
3514 }
3515 }
3516
3517 for (;;) {
3518 /* Single step through the search_state_machine */
3519 state = search_state_machine(c, c->new_state, ONE_STEP);
3520 switch (state) {
3521 case LDAP_ERROR:
3522 (void) search_state_machine(c, state, ONE_STEP);
3523 (void) search_state_machine(c, CLEAR_RESULTS, ONE_STEP);
3524 /* FALLTHROUGH */
3525 case ERROR:
3526 case EXIT:
3527 *c->caller_result = c->result;
3528 *c->caller_errorp = c->errorp;
3529 *c->caller_rc =
3530 (c->result == NULL && c->err_from_result == 0)
3531 ? NS_LDAP_NOTFOUND : c->err_rc;
3532 c->result = NULL;
3533 c->errorp = NULL;
3534 /* Remove the cookie from the batch */
3535 ptr = batch->cookie_list;
3536 prev = &batch->cookie_list;
3537 while (ptr != NULL) {
3538 if (ptr == c) {
3539 *prev = ptr->next_cookie_in_batch;
3540 break;
3541 }
3542 prev = &ptr->next_cookie_in_batch;
3543 ptr = ptr->next_cookie_in_batch;
3544 }
3545 /* Delete cookie and decrement active cookie count */
3546 if (c->conn_user != NULL) {
3547 if (c->conn_user->conn_mt != NULL)
3548 __s_api_conn_mt_return(c->conn_user);
3549 __s_api_conn_user_free(c->conn_user);
3550 c->conn_user = NULL;
3551 }
3552 delete_search_cookie(c);
3553 batch->nactive--;
3554 break;
3555 case NEXT_RESULT:
3556 case MULTI_RESULT:
3557 /*
3558 * This means that search_state_machine needs to do
3559 * another ldap_result() for the cookie in question.
3560 * We only do at most one ldap_result() per call in
3561 * this function and therefore we return. This allows
3562 * the caller to process results from other cookies
3563 * in the batch without getting tied up on just one
3564 * cookie.
3565 */
3566 break;
3567 default:
3568 /*
3569 * This includes states that follow NEXT_RESULT or
3570 * MULTI_RESULT such as PROCESS_RESULT and
3571 * END_PROCESS_RESULT. We continue processing
3572 * this cookie till we reach either the error, exit
3573 * or the result states.
3574 */
3575 continue;
3576 }
3577 break;
3578 }
3579
3580 /* Return 0 if no more cookies left otherwise 1 */
3581 return ((batch->nactive > 0) ? 1 : 0);
3582 }
3583
3584
3585 /*
3586 * Process all the active cookies in the batch and when none
3587 * remains finalize the batch.
3588 */
3589 int
__ns_ldap_list_batch_end(ns_ldap_list_batch_t * batch)3590 __ns_ldap_list_batch_end(ns_ldap_list_batch_t *batch)
3591 {
3592 int rc = NS_LDAP_SUCCESS;
3593 while (__ns_ldap_list_batch_process(batch, &rc) > 0)
3594 ;
3595 __ns_ldap_list_batch_release(batch);
3596 return (rc);
3597 }
3598
3599 typedef struct lookup_data {
3600 const char *lkd_dn;
3601 const char *lkd_service;
3602 const char *lkd_filter;
3603 const ns_cred_t *lkd_cred;
3604 ns_conn_user_t *lkd_user;
3605 } lookup_data_t;
3606
3607 /*
3608 * This creates a service search descriptor that can be used to
3609 * retrieve a specific DN by using the DN as the basedn with a search
3610 * scope of 'base'. We don't use any service SSDs in this instance since
3611 * they are intended to search specific locations/subtrees and filter the
3612 * results, while here we are wanting to retrieve a specific entry.
3613 */
3614 static int
lookup_create_ssd(lookup_data_t * dn_data,ns_ldap_search_desc_t ** descpp)3615 lookup_create_ssd(lookup_data_t *dn_data, ns_ldap_search_desc_t **descpp)
3616 {
3617 ns_ldap_search_desc_t *dptr;
3618
3619 *descpp = NULL;
3620
3621 dptr = calloc(1, sizeof (ns_ldap_search_desc_t));
3622 if (dptr == NULL)
3623 return (NS_LDAP_MEMORY);
3624
3625 dptr->basedn = strdup(dn_data->lkd_dn);
3626 dptr->scope = NS_LDAP_SCOPE_BASE;
3627 dptr->filter = strdup(dn_data->lkd_filter);
3628
3629 if (dptr->basedn == NULL || dptr->filter == NULL) {
3630 __ns_ldap_freeASearchDesc(dptr);
3631 return (NS_LDAP_MEMORY);
3632 }
3633
3634 *descpp = dptr;
3635 return (NS_LDAP_SUCCESS);
3636 }
3637
3638 static int
lookup_dn(lookup_data_t * dn_data,const char ** attrs,ns_ldap_result_t ** resultp,ns_ldap_error_t ** errorp)3639 lookup_dn(lookup_data_t *dn_data, const char **attrs,
3640 ns_ldap_result_t **resultp, ns_ldap_error_t **errorp)
3641 {
3642 ns_ldap_cookie_t *cookie;
3643 int rc = 0;
3644 int flags = 0;
3645
3646 *errorp = NULL;
3647 *resultp = NULL;
3648
3649 if (dn_data == NULL || dn_data->lkd_dn == NULL ||
3650 dn_data->lkd_dn[0] == '\0' || dn_data->lkd_filter == NULL)
3651 return (NS_LDAP_INVALID_PARAM);
3652
3653 cookie = init_search_state_machine();
3654 if (cookie == NULL)
3655 return (NS_LDAP_MEMORY);
3656
3657 rc = __s_api_toFollowReferrals(flags, &cookie->followRef, errorp);
3658 if (rc != NS_LDAP_SUCCESS)
3659 goto out;
3660
3661 /* 1 for SSD, 1 for terminating NULL */
3662 cookie->sdlist = calloc(2, sizeof (ns_ldap_search_desc_t *));
3663 if (cookie->sdlist == NULL) {
3664 rc = NS_LDAP_MEMORY;
3665 goto out;
3666 }
3667
3668 rc = lookup_create_ssd(dn_data, &cookie->sdlist[0]);
3669 if (rc != NS_LDAP_SUCCESS)
3670 goto out;
3671
3672 if (dn_data->lkd_service != NULL) {
3673 /*
3674 * If a service was specified, set that on the cookie so
3675 * that search_state_machine() will properly map
3676 * attributes and objectclasses.
3677 */
3678 cookie->service = strdup(dn_data->lkd_service);
3679 if (cookie->service == NULL) {
3680 rc = NS_LDAP_MEMORY;
3681 goto out;
3682 }
3683 }
3684
3685 cookie->i_attr = attrs;
3686 cookie->i_auth = dn_data->lkd_cred;
3687 cookie->i_flags = 0;
3688 cookie->i_filter = strdup(dn_data->lkd_filter);
3689 if (cookie->i_filter == NULL) {
3690 rc = NS_LDAP_MEMORY;
3691 goto out;
3692 }
3693
3694 /*
3695 * Actually perform the search. The return value is only used when
3696 * iterating through multiple results. Since we are searching with
3697 * a scope of base, we will always get at most one result entry,
3698 * we ignore the return value and look at err_rc to determine if
3699 * there were any errors.
3700 */
3701 (void) search_state_machine(cookie, INIT, 0);
3702 rc = cookie->err_rc;
3703
3704 if (rc != NS_LDAP_SUCCESS) {
3705 ns_conn_user_t *user = dn_data->lkd_user;
3706
3707 if (user != NULL && user->ns_error != NULL) {
3708 *errorp = user->ns_error;
3709 user->ns_error = NULL;
3710 } else {
3711 *errorp = cookie->errorp;
3712 cookie->errorp = NULL;
3713 }
3714 } else if (cookie->result != NULL) {
3715 *resultp = cookie->result;
3716 cookie->result = NULL;
3717 } else {
3718 rc = NS_LDAP_NOTFOUND;
3719 }
3720
3721 out:
3722 delete_search_cookie(cookie);
3723 return (rc);
3724 }
3725
3726 /*
3727 * find_domainname performs one or more LDAP searches to
3728 * find the value of the nisdomain attribute associated with
3729 * the input DN (with no retry).
3730 */
3731
3732 static int
find_domainname(const char * dn,char ** domainname,const ns_cred_t * cred,ns_ldap_error_t ** errorp,ns_conn_user_t * conn_user)3733 find_domainname(const char *dn, char **domainname, const ns_cred_t *cred,
3734 ns_ldap_error_t **errorp, ns_conn_user_t *conn_user)
3735 {
3736 lookup_data_t ldata;
3737 ns_ldap_result_t *result;
3738 char **value;
3739 int rc;
3740
3741 *domainname = NULL;
3742 *errorp = NULL;
3743
3744 ldata.lkd_dn = dn;
3745 ldata.lkd_service = NULL;
3746 ldata.lkd_filter = _NIS_FILTER;
3747 ldata.lkd_cred = cred;
3748 ldata.lkd_user = conn_user;
3749
3750 rc = lookup_dn(&ldata, nis_domain_attrs, &result, errorp);
3751 if (rc != NS_LDAP_SUCCESS)
3752 return (rc);
3753
3754 value = __ns_ldap_getAttr(result->entry, _NIS_DOMAIN);
3755
3756 if (value != NULL && value[0] != NULL) {
3757 *domainname = strdup(value[0]);
3758 if (*domainname == NULL)
3759 rc = NS_LDAP_MEMORY;
3760 } else {
3761 rc = NS_LDAP_NOTFOUND;
3762 }
3763
3764 (void) __ns_ldap_freeResult(&result);
3765 return (rc);
3766 }
3767
3768 /*
3769 * __s_api_find_domainname performs one or more LDAP searches to
3770 * find the value of the nisdomain attribute associated with
3771 * the input DN (with retry).
3772 */
3773
3774 static int
__s_api_find_domainname(const char * dn,char ** domainname,const ns_cred_t * cred,ns_ldap_error_t ** errorp)3775 __s_api_find_domainname(const char *dn, char **domainname,
3776 const ns_cred_t *cred, ns_ldap_error_t **errorp)
3777 {
3778 ns_conn_user_t *cu = NULL;
3779 int try_cnt = 0;
3780 int rc = NS_LDAP_SUCCESS;
3781
3782 for (;;) {
3783 if (__s_api_setup_retry_search(&cu, NS_CONN_USER_SEARCH,
3784 &try_cnt, &rc, errorp) == 0)
3785 break;
3786 rc = find_domainname(dn, domainname, cred, errorp, cu);
3787 }
3788
3789 return (rc);
3790 }
3791
3792 static int
firstEntry(const char * service,const char * filter,const char * sortattr,int (* init_filter_cb)(const ns_ldap_search_desc_t * desc,char ** realfilter,const void * userdata),const char * const * attribute,const ns_cred_t * auth,const int flags,void ** vcookie,ns_ldap_result_t ** result,ns_ldap_error_t ** errorp,const void * userdata,ns_conn_user_t * conn_user)3793 firstEntry(
3794 const char *service,
3795 const char *filter,
3796 const char *sortattr,
3797 int (*init_filter_cb)(const ns_ldap_search_desc_t *desc,
3798 char **realfilter, const void *userdata),
3799 const char * const *attribute,
3800 const ns_cred_t *auth,
3801 const int flags,
3802 void **vcookie,
3803 ns_ldap_result_t **result,
3804 ns_ldap_error_t ** errorp,
3805 const void *userdata,
3806 ns_conn_user_t *conn_user)
3807 {
3808 ns_ldap_cookie_t *cookie = NULL;
3809 ns_ldap_error_t *error = NULL;
3810 ns_state_t state;
3811 ns_ldap_search_desc_t **sdlist;
3812 ns_ldap_search_desc_t *dptr;
3813 char **dns = NULL;
3814 int scope;
3815 int rc;
3816
3817 *errorp = NULL;
3818 *result = NULL;
3819
3820 /*
3821 * Sanity check - NS_LDAP_READ_SHADOW is for our
3822 * own internal use.
3823 */
3824 if (flags & NS_LDAP_READ_SHADOW)
3825 return (NS_LDAP_INVALID_PARAM);
3826
3827 /* get the service descriptor - or create a default one */
3828 rc = __s_api_get_SSD_from_SSDtoUse_service(service,
3829 &sdlist, &error);
3830 if (rc != NS_LDAP_SUCCESS) {
3831 *errorp = error;
3832 return (rc);
3833 }
3834 if (sdlist == NULL) {
3835 /* Create default service Desc */
3836 sdlist = (ns_ldap_search_desc_t **)calloc(2,
3837 sizeof (ns_ldap_search_desc_t *));
3838 if (sdlist == NULL) {
3839 return (NS_LDAP_MEMORY);
3840 }
3841 dptr = (ns_ldap_search_desc_t *)
3842 calloc(1, sizeof (ns_ldap_search_desc_t));
3843 if (dptr == NULL) {
3844 free(sdlist);
3845 return (NS_LDAP_MEMORY);
3846 }
3847 sdlist[0] = dptr;
3848
3849 /* default base */
3850 rc = __s_api_getDNs(&dns, service, &error);
3851 if (rc != NS_LDAP_SUCCESS) {
3852 if (dns) {
3853 __s_api_free2dArray(dns);
3854 dns = NULL;
3855 }
3856 if (sdlist) {
3857 (void) __ns_ldap_freeSearchDescriptors(
3858 &sdlist);
3859
3860 sdlist = NULL;
3861 }
3862 *errorp = error;
3863 return (rc);
3864 }
3865 dptr->basedn = strdup(dns[0]);
3866 __s_api_free2dArray(dns);
3867 dns = NULL;
3868
3869 /* default scope */
3870 scope = 0;
3871 cookie = init_search_state_machine();
3872 if (cookie == NULL) {
3873 if (sdlist) {
3874 (void) __ns_ldap_freeSearchDescriptors(&sdlist);
3875 sdlist = NULL;
3876 }
3877 return (NS_LDAP_MEMORY);
3878 }
3879 rc = __s_api_getSearchScope(&scope, &cookie->errorp);
3880 dptr->scope = scope;
3881 }
3882
3883 /* Initialize State machine cookie */
3884 if (cookie == NULL)
3885 cookie = init_search_state_machine();
3886 if (cookie == NULL) {
3887 if (sdlist) {
3888 (void) __ns_ldap_freeSearchDescriptors(&sdlist);
3889 sdlist = NULL;
3890 }
3891 return (NS_LDAP_MEMORY);
3892 }
3893
3894 /* identify self as a getent user */
3895 cookie->conn_user = conn_user;
3896
3897 cookie->sdlist = sdlist;
3898
3899 /* see if need to follow referrals */
3900 rc = __s_api_toFollowReferrals(flags,
3901 &cookie->followRef, errorp);
3902 if (rc != NS_LDAP_SUCCESS) {
3903 delete_search_cookie(cookie);
3904 return (rc);
3905 }
3906
3907 /*
3908 * use VLV/PAGE control only if NS_LDAP_NO_PAGE_CTRL is not set
3909 */
3910 if (flags & NS_LDAP_NO_PAGE_CTRL)
3911 cookie->use_paging = FALSE;
3912 else
3913 cookie->use_paging = TRUE;
3914
3915 /* Set up other arguments */
3916 cookie->userdata = userdata;
3917 if (init_filter_cb != NULL) {
3918 cookie->init_filter_cb = init_filter_cb;
3919 cookie->use_filtercb = 1;
3920 }
3921 cookie->use_usercb = 0;
3922 /* check_shadow() may add extra value to cookie->i_flags */
3923 cookie->i_flags = flags;
3924 if (service) {
3925 cookie->service = strdup(service);
3926 if (cookie->service == NULL) {
3927 delete_search_cookie(cookie);
3928 return (NS_LDAP_MEMORY);
3929 }
3930
3931 /*
3932 * If given, use the credential given by the caller, and
3933 * skip the credential check required for shadow update.
3934 */
3935 if (auth == NULL) {
3936 rc = check_shadow(cookie, service);
3937 if (rc != NS_LDAP_SUCCESS) {
3938 *errorp = cookie->errorp;
3939 cookie->errorp = NULL;
3940 delete_search_cookie(cookie);
3941 cookie = NULL;
3942 return (rc);
3943 }
3944 }
3945 }
3946
3947 cookie->i_filter = strdup(filter);
3948 cookie->i_attr = attribute;
3949 cookie->i_sortattr = sortattr;
3950 cookie->i_auth = auth;
3951
3952 state = INIT;
3953 for (;;) {
3954 state = search_state_machine(cookie, state, ONE_STEP);
3955 switch (state) {
3956 case PROCESS_RESULT:
3957 *result = cookie->result;
3958 cookie->result = NULL;
3959 *vcookie = (void *)cookie;
3960 return (NS_LDAP_SUCCESS);
3961 case LDAP_ERROR:
3962 state = search_state_machine(cookie, state, ONE_STEP);
3963 state = search_state_machine(cookie, CLEAR_RESULTS,
3964 ONE_STEP);
3965 /* FALLTHROUGH */
3966 case ERROR:
3967 rc = cookie->err_rc;
3968 if (conn_user != NULL && conn_user->ns_error != NULL) {
3969 *errorp = conn_user->ns_error;
3970 conn_user->ns_error = NULL;
3971 } else {
3972 *errorp = cookie->errorp;
3973 cookie->errorp = NULL;
3974 }
3975 delete_search_cookie(cookie);
3976 return (rc);
3977 case EXIT:
3978 rc = cookie->err_rc;
3979 if (rc != NS_LDAP_SUCCESS) {
3980 *errorp = cookie->errorp;
3981 cookie->errorp = NULL;
3982 } else {
3983 rc = NS_LDAP_NOTFOUND;
3984 }
3985
3986 delete_search_cookie(cookie);
3987 return (rc);
3988
3989 default:
3990 break;
3991 }
3992 }
3993 }
3994
3995 int
__ns_ldap_firstEntry(const char * service,const char * filter,const char * vlv_sort,int (* init_filter_cb)(const ns_ldap_search_desc_t * desc,char ** realfilter,const void * userdata),const char * const * attribute,const ns_cred_t * auth,const int flags,void ** vcookie,ns_ldap_result_t ** result,ns_ldap_error_t ** errorp,const void * userdata)3996 __ns_ldap_firstEntry(
3997 const char *service,
3998 const char *filter,
3999 const char *vlv_sort,
4000 int (*init_filter_cb)(const ns_ldap_search_desc_t *desc,
4001 char **realfilter, const void *userdata),
4002 const char * const *attribute,
4003 const ns_cred_t *auth,
4004 const int flags,
4005 void **vcookie,
4006 ns_ldap_result_t **result,
4007 ns_ldap_error_t ** errorp,
4008 const void *userdata)
4009 {
4010 ns_conn_user_t *cu = NULL;
4011 int try_cnt = 0;
4012 int rc = NS_LDAP_SUCCESS;
4013
4014 for (;;) {
4015 if (__s_api_setup_retry_search(&cu, NS_CONN_USER_GETENT,
4016 &try_cnt, &rc, errorp) == 0)
4017 break;
4018 rc = firstEntry(service, filter, vlv_sort, init_filter_cb,
4019 attribute, auth, flags, vcookie, result, errorp, userdata,
4020 cu);
4021 }
4022 return (rc);
4023 }
4024
4025 /*ARGSUSED2*/
4026 int
__ns_ldap_nextEntry(void * vcookie,ns_ldap_result_t ** result,ns_ldap_error_t ** errorp)4027 __ns_ldap_nextEntry(void *vcookie, ns_ldap_result_t **result,
4028 ns_ldap_error_t ** errorp)
4029 {
4030 ns_ldap_cookie_t *cookie;
4031 ns_state_t state;
4032 int rc;
4033
4034 cookie = (ns_ldap_cookie_t *)vcookie;
4035 cookie->result = NULL;
4036 *result = NULL;
4037
4038 if (cookie->conn_user != NULL) {
4039 rc = __s_api_setup_getnext(cookie->conn_user,
4040 &cookie->err_rc, errorp);
4041 if (rc != NS_LDAP_SUCCESS)
4042 return (rc);
4043 }
4044
4045 state = END_PROCESS_RESULT;
4046 for (;;) {
4047 state = search_state_machine(cookie, state, ONE_STEP);
4048 switch (state) {
4049 case PROCESS_RESULT:
4050 *result = cookie->result;
4051 cookie->result = NULL;
4052 return (NS_LDAP_SUCCESS);
4053 case LDAP_ERROR:
4054 state = search_state_machine(cookie, state, ONE_STEP);
4055 state = search_state_machine(cookie, CLEAR_RESULTS,
4056 ONE_STEP);
4057 /* FALLTHROUGH */
4058 case ERROR:
4059 rc = cookie->err_rc;
4060 *errorp = cookie->errorp;
4061 cookie->errorp = NULL;
4062 return (rc);
4063 case EXIT:
4064 return (NS_LDAP_SUCCESS);
4065 }
4066 }
4067 }
4068
4069 int
__ns_ldap_endEntry(void ** vcookie,ns_ldap_error_t ** errorp)4070 __ns_ldap_endEntry(
4071 void **vcookie,
4072 ns_ldap_error_t ** errorp)
4073 {
4074 ns_ldap_cookie_t *cookie;
4075 int rc;
4076
4077 if (*vcookie == NULL)
4078 return (NS_LDAP_INVALID_PARAM);
4079
4080 cookie = (ns_ldap_cookie_t *)(*vcookie);
4081 cookie->result = NULL;
4082
4083 /* Complete search */
4084 rc = search_state_machine(cookie, CLEAR_RESULTS, 0);
4085
4086 /* Copy results back to user */
4087 rc = cookie->err_rc;
4088 if (rc != NS_LDAP_SUCCESS)
4089 *errorp = cookie->errorp;
4090
4091 cookie->errorp = NULL;
4092 if (cookie->conn_user != NULL) {
4093 if (cookie->conn_user->conn_mt != NULL)
4094 __s_api_conn_mt_return(cookie->conn_user);
4095 __s_api_conn_user_free(cookie->conn_user);
4096 }
4097 delete_search_cookie(cookie);
4098 cookie = NULL;
4099 *vcookie = NULL;
4100
4101 return (rc);
4102 }
4103
4104
4105 int
__ns_ldap_freeResult(ns_ldap_result_t ** result)4106 __ns_ldap_freeResult(ns_ldap_result_t **result)
4107 {
4108
4109 ns_ldap_entry_t *curEntry = NULL;
4110 ns_ldap_entry_t *delEntry = NULL;
4111 int i;
4112 ns_ldap_result_t *res = *result;
4113
4114 #ifdef DEBUG
4115 (void) fprintf(stderr, "__ns_ldap_freeResult START\n");
4116 #endif
4117 if (res == NULL)
4118 return (NS_LDAP_INVALID_PARAM);
4119
4120 if (res->entry != NULL)
4121 curEntry = res->entry;
4122
4123 for (i = 0; i < res->entries_count; i++) {
4124 if (curEntry != NULL) {
4125 delEntry = curEntry;
4126 curEntry = curEntry->next;
4127 __ns_ldap_freeEntry(delEntry);
4128 }
4129 }
4130
4131 free(res);
4132 *result = NULL;
4133 return (NS_LDAP_SUCCESS);
4134 }
4135
4136 int
__ns_ldap_auth(const ns_cred_t * auth,const int flags,ns_ldap_error_t ** errorp,LDAPControl ** serverctrls __unused,LDAPControl ** clientctrls __unused)4137 __ns_ldap_auth(const ns_cred_t *auth, const int flags, ns_ldap_error_t **errorp,
4138 LDAPControl **serverctrls __unused, LDAPControl **clientctrls __unused)
4139 {
4140
4141 ConnectionID connectionId = -1;
4142 Connection *conp;
4143 int rc = 0;
4144 int do_not_fail_if_new_pwd_reqd = 0;
4145 int nopasswd_acct_mgmt = 0;
4146 ns_conn_user_t *conn_user;
4147
4148
4149 #ifdef DEBUG
4150 (void) fprintf(stderr, "__ns_ldap_auth START\n");
4151 #endif
4152
4153 *errorp = NULL;
4154 if (auth == NULL)
4155 return (NS_LDAP_INVALID_PARAM);
4156
4157 conn_user = __s_api_conn_user_init(NS_CONN_USER_AUTH,
4158 NULL, B_FALSE);
4159
4160 rc = __s_api_getConnection(NULL, flags | NS_LDAP_NEW_CONN,
4161 auth, &connectionId, &conp, errorp,
4162 do_not_fail_if_new_pwd_reqd, nopasswd_acct_mgmt,
4163 conn_user);
4164
4165 if (conn_user != NULL)
4166 __s_api_conn_user_free(conn_user);
4167
4168 if (rc == NS_LDAP_OP_FAILED && *errorp)
4169 (void) __ns_ldap_freeError(errorp);
4170
4171 if (connectionId > -1)
4172 DropConnection(connectionId, flags);
4173 return (rc);
4174 }
4175
4176 char **
__ns_ldap_getAttr(const ns_ldap_entry_t * entry,const char * attrname)4177 __ns_ldap_getAttr(const ns_ldap_entry_t *entry, const char *attrname)
4178 {
4179 int i;
4180
4181 if (entry == NULL)
4182 return (NULL);
4183 for (i = 0; i < entry->attr_count; i++) {
4184 if (strcasecmp(entry->attr_pair[i]->attrname, attrname) == 0)
4185 return (entry->attr_pair[i]->attrvalue);
4186 }
4187 return (NULL);
4188 }
4189
4190 ns_ldap_attr_t *
__ns_ldap_getAttrStruct(const ns_ldap_entry_t * entry,const char * attrname)4191 __ns_ldap_getAttrStruct(const ns_ldap_entry_t *entry, const char *attrname)
4192 {
4193 int i;
4194
4195 if (entry == NULL)
4196 return (NULL);
4197 for (i = 0; i < entry->attr_count; i++) {
4198 if (strcasecmp(entry->attr_pair[i]->attrname, attrname) == 0)
4199 return (entry->attr_pair[i]);
4200 }
4201 return (NULL);
4202 }
4203
4204
4205 int
__ns_ldap_uid2dn(const char * uid,char ** userDN,const ns_cred_t * cred,ns_ldap_error_t ** errorp)4206 __ns_ldap_uid2dn(const char *uid, char **userDN, const ns_cred_t *cred,
4207 ns_ldap_error_t **errorp)
4208 {
4209 ns_ldap_result_t *result = NULL;
4210 char *filter, *userdata;
4211 char errstr[MAXERROR];
4212 char **value;
4213 int rc = 0;
4214 int i;
4215 size_t len;
4216
4217 *errorp = NULL;
4218 *userDN = NULL;
4219 if ((uid == NULL) || (uid[0] == '\0'))
4220 return (NS_LDAP_INVALID_PARAM);
4221
4222 for (i = 0; uid[i] != '\0'; i++) {
4223 if (uid[i] == '=') {
4224 *userDN = strdup(uid);
4225 return (NS_LDAP_SUCCESS);
4226 }
4227 }
4228 for (i = 0; (uid[i] != '\0') && isdigit(uid[i]); i++)
4229 ;
4230 if (uid[i] == '\0') {
4231 len = strlen(UIDNUMFILTER) + strlen(uid) + 1;
4232 filter = malloc(len);
4233 if (filter == NULL) {
4234 *userDN = NULL;
4235 return (NS_LDAP_MEMORY);
4236 }
4237 (void) snprintf(filter, len, UIDNUMFILTER, uid);
4238
4239 len = strlen(UIDNUMFILTER_SSD) + strlen(uid) + 1;
4240 userdata = malloc(len);
4241 if (userdata == NULL) {
4242 *userDN = NULL;
4243 free(filter);
4244 return (NS_LDAP_MEMORY);
4245 }
4246 (void) snprintf(userdata, len, UIDNUMFILTER_SSD, uid);
4247 } else {
4248 len = strlen(UIDFILTER) + strlen(uid) + 1;
4249 filter = malloc(len);
4250 if (filter == NULL) {
4251 *userDN = NULL;
4252 return (NS_LDAP_MEMORY);
4253 }
4254 (void) snprintf(filter, len, UIDFILTER, uid);
4255
4256 len = strlen(UIDFILTER_SSD) + strlen(uid) + 1;
4257 userdata = malloc(len);
4258 if (userdata == NULL) {
4259 *userDN = NULL;
4260 free(filter);
4261 return (NS_LDAP_MEMORY);
4262 }
4263 (void) snprintf(userdata, len, UIDFILTER_SSD, uid);
4264 }
4265
4266 /*
4267 * we want to retrieve the DN as it appears in LDAP
4268 * hence the use of NS_LDAP_NOT_CVT_DN in flags
4269 */
4270 rc = __ns_ldap_list("passwd", filter,
4271 __s_api_merge_SSD_filter,
4272 NULL, cred, NS_LDAP_NOT_CVT_DN,
4273 &result, errorp, NULL,
4274 userdata);
4275 free(filter);
4276 filter = NULL;
4277 free(userdata);
4278 userdata = NULL;
4279 if (rc != NS_LDAP_SUCCESS) {
4280 if (result) {
4281 (void) __ns_ldap_freeResult(&result);
4282 result = NULL;
4283 }
4284 return (rc);
4285 }
4286 if (result->entries_count > 1) {
4287 (void) __ns_ldap_freeResult(&result);
4288 result = NULL;
4289 *userDN = NULL;
4290 (void) sprintf(errstr,
4291 gettext("Too many entries are returned for %s"), uid);
4292 MKERROR(LOG_WARNING, *errorp, NS_LDAP_INTERNAL, strdup(errstr),
4293 NS_LDAP_MEMORY);
4294 return (NS_LDAP_INTERNAL);
4295 }
4296
4297 value = __ns_ldap_getAttr(result->entry, "dn");
4298 *userDN = strdup(value[0]);
4299 (void) __ns_ldap_freeResult(&result);
4300 result = NULL;
4301 return (NS_LDAP_SUCCESS);
4302 }
4303
4304 #define _P_UID "uid"
4305 static const char *dn2uid_attrs[] = {
4306 _P_CN,
4307 _P_UID,
4308 (char *)NULL
4309 };
4310
4311 int
__ns_ldap_dn2uid(const char * dn,char ** userIDp,const ns_cred_t * cred,ns_ldap_error_t ** errorp)4312 __ns_ldap_dn2uid(const char *dn, char **userIDp, const ns_cred_t *cred,
4313 ns_ldap_error_t **errorp)
4314 {
4315 lookup_data_t ldata;
4316 ns_ldap_result_t *result;
4317 char **value;
4318 int rc;
4319
4320 *errorp = NULL;
4321 *userIDp = NULL;
4322 if ((dn == NULL) || (dn[0] == '\0'))
4323 return (NS_LDAP_INVALID_PARAM);
4324
4325 /*
4326 * Many LDAP servers do not support using the dn in a search
4327 * filter. As a result, we unfortunately cannot use __ns_ldap_list()
4328 * to lookup the DN. Instead we perform a search with the baseDN
4329 * being the DN we are looking for with a scope of 'base' to
4330 * return the entry, as this should be supported by all LDAP servers.
4331 */
4332 ldata.lkd_dn = dn;
4333
4334 /*
4335 * Since we are looking up a user account by its DN, use the attribute
4336 * and objectclass mappings (if present) for the passwd service.
4337 */
4338 ldata.lkd_service = "passwd";
4339 ldata.lkd_filter = UIDDNFILTER;
4340 ldata.lkd_cred = cred;
4341 ldata.lkd_user = NULL;
4342
4343 rc = lookup_dn(&ldata, dn2uid_attrs, &result, errorp);
4344 if (rc != NS_LDAP_SUCCESS)
4345 return (rc);
4346
4347 value = __ns_ldap_getAttr(result->entry, _P_UID);
4348 if (value != NULL && value[0] != NULL) {
4349 *userIDp = strdup(value[0]);
4350 if (*userIDp == NULL)
4351 rc = NS_LDAP_MEMORY;
4352 } else {
4353 rc = NS_LDAP_NOTFOUND;
4354 }
4355
4356 (void) __ns_ldap_freeResult(&result);
4357 return (rc);
4358 }
4359
4360 int
__ns_ldap_host2dn(const char * host,const char * domain,char ** hostDN,const ns_cred_t * cred,ns_ldap_error_t ** errorp)4361 __ns_ldap_host2dn(const char *host, const char *domain, char **hostDN,
4362 const ns_cred_t *cred, ns_ldap_error_t **errorp)
4363 {
4364 ns_ldap_result_t *result = NULL;
4365 char *filter, *userdata;
4366 char errstr[MAXERROR];
4367 char **value;
4368 int rc;
4369 size_t len;
4370
4371 /*
4372 * XXX
4373 * the domain parameter needs to be used in case domain is not local,
4374 * if this routine is to support multi domain setups, it needs lots
4375 * of work...
4376 */
4377 *errorp = NULL;
4378 *hostDN = NULL;
4379 if ((host == NULL) || (host[0] == '\0'))
4380 return (NS_LDAP_INVALID_PARAM);
4381
4382 len = strlen(HOSTFILTER) + strlen(host) + 1;
4383 filter = malloc(len);
4384 if (filter == NULL) {
4385 return (NS_LDAP_MEMORY);
4386 }
4387 (void) snprintf(filter, len, HOSTFILTER, host);
4388
4389 len = strlen(HOSTFILTER_SSD) + strlen(host) + 1;
4390 userdata = malloc(len);
4391 if (userdata == NULL) {
4392 free(filter);
4393 return (NS_LDAP_MEMORY);
4394 }
4395 (void) snprintf(userdata, len, HOSTFILTER_SSD, host);
4396
4397 /*
4398 * we want to retrieve the DN as it appears in LDAP
4399 * hence the use of NS_LDAP_NOT_CVT_DN in flags
4400 */
4401 rc = __ns_ldap_list("hosts", filter,
4402 __s_api_merge_SSD_filter,
4403 NULL, cred, NS_LDAP_NOT_CVT_DN, &result,
4404 errorp, NULL,
4405 userdata);
4406 free(filter);
4407 filter = NULL;
4408 free(userdata);
4409 userdata = NULL;
4410 if (rc != NS_LDAP_SUCCESS) {
4411 if (result) {
4412 (void) __ns_ldap_freeResult(&result);
4413 result = NULL;
4414 }
4415 return (rc);
4416 }
4417
4418 if (result->entries_count > 1) {
4419 (void) __ns_ldap_freeResult(&result);
4420 result = NULL;
4421 *hostDN = NULL;
4422 (void) sprintf(errstr,
4423 gettext("Too many entries are returned for %s"), host);
4424 MKERROR(LOG_WARNING, *errorp, NS_LDAP_INTERNAL, strdup(errstr),
4425 NS_LDAP_MEMORY);
4426 return (NS_LDAP_INTERNAL);
4427 }
4428
4429 value = __ns_ldap_getAttr(result->entry, "dn");
4430 *hostDN = strdup(value[0]);
4431 (void) __ns_ldap_freeResult(&result);
4432 result = NULL;
4433 return (NS_LDAP_SUCCESS);
4434 }
4435
4436 int
__ns_ldap_dn2domain(const char * dn,char ** domain,const ns_cred_t * cred,ns_ldap_error_t ** errorp)4437 __ns_ldap_dn2domain(const char *dn, char **domain, const ns_cred_t *cred,
4438 ns_ldap_error_t **errorp)
4439 {
4440 int rc, pnum, i, j, len = 0;
4441 char *newdn, **rdns = NULL;
4442 char **dns, *dn1;
4443
4444 *errorp = NULL;
4445
4446 if (domain == NULL)
4447 return (NS_LDAP_INVALID_PARAM);
4448 else
4449 *domain = NULL;
4450
4451 if ((dn == NULL) || (dn[0] == '\0'))
4452 return (NS_LDAP_INVALID_PARAM);
4453
4454 /*
4455 * break dn into rdns
4456 */
4457 dn1 = strdup(dn);
4458 if (dn1 == NULL)
4459 return (NS_LDAP_MEMORY);
4460 rdns = ldap_explode_dn(dn1, 0);
4461 free(dn1);
4462 if (rdns == NULL || *rdns == NULL)
4463 return (NS_LDAP_INVALID_PARAM);
4464
4465 for (i = 0; rdns[i]; i++)
4466 len += strlen(rdns[i]) + 1;
4467 pnum = i;
4468
4469 newdn = (char *)malloc(len + 1);
4470 dns = (char **)calloc(pnum, sizeof (char *));
4471 if (newdn == NULL || dns == NULL) {
4472 if (newdn)
4473 free(newdn);
4474 ldap_value_free(rdns);
4475 return (NS_LDAP_MEMORY);
4476 }
4477
4478 /* construct a semi-normalized dn, newdn */
4479 *newdn = '\0';
4480 for (i = 0; rdns[i]; i++) {
4481 dns[i] = newdn + strlen(newdn);
4482 (void) strcat(newdn,
4483 __s_api_remove_rdn_space(rdns[i]));
4484 (void) strcat(newdn, ",");
4485 }
4486 /* remove the last ',' */
4487 newdn[strlen(newdn) - 1] = '\0';
4488 ldap_value_free(rdns);
4489
4490 /*
4491 * loop and find the domain name associated with newdn,
4492 * removing rdn one by one from left to right
4493 */
4494 for (i = 0; i < pnum; i++) {
4495
4496 if (*errorp)
4497 (void) __ns_ldap_freeError(errorp);
4498
4499 /*
4500 * try cache manager first
4501 */
4502 rc = __s_api_get_cachemgr_data(NS_CACHE_DN2DOMAIN,
4503 dns[i], domain);
4504 if (rc != NS_LDAP_SUCCESS) {
4505 /*
4506 * try ldap server second
4507 */
4508 rc = __s_api_find_domainname(dns[i], domain,
4509 cred, errorp);
4510 } else {
4511 /*
4512 * skip the last one,
4513 * since it is already cached by ldap_cachemgr
4514 */
4515 i--;
4516 }
4517 if (rc == NS_LDAP_SUCCESS) {
4518 if (__s_api_nscd_proc()) {
4519 /*
4520 * If it's nscd, ask cache manager to save the
4521 * dn to domain mapping(s)
4522 */
4523 for (j = 0; j <= i; j++) {
4524 (void) __s_api_set_cachemgr_data(
4525 NS_CACHE_DN2DOMAIN,
4526 dns[j],
4527 *domain);
4528 }
4529 }
4530 break;
4531 }
4532 }
4533
4534 free(dns);
4535 free(newdn);
4536 if (rc != NS_LDAP_SUCCESS)
4537 rc = NS_LDAP_NOTFOUND;
4538 return (rc);
4539 }
4540
4541 int
__ns_ldap_getServiceAuthMethods(const char * service,ns_auth_t *** auth,ns_ldap_error_t ** errorp)4542 __ns_ldap_getServiceAuthMethods(const char *service, ns_auth_t ***auth,
4543 ns_ldap_error_t **errorp)
4544 {
4545 char errstr[MAXERROR];
4546 int rc, i;
4547 boolean_t done = B_FALSE;
4548 int slen;
4549 void **param;
4550 char **sam, *srv, *send;
4551 ns_auth_t **authpp = NULL, *ap;
4552 int cnt, max;
4553 ns_config_t *cfg;
4554 ns_ldap_error_t *error = NULL;
4555
4556 if (errorp == NULL)
4557 return (NS_LDAP_INVALID_PARAM);
4558 *errorp = NULL;
4559
4560 if ((service == NULL) || (service[0] == '\0') ||
4561 (auth == NULL))
4562 return (NS_LDAP_INVALID_PARAM);
4563
4564 *auth = NULL;
4565 rc = __ns_ldap_getParam(NS_LDAP_SERVICE_AUTH_METHOD_P, ¶m, &error);
4566 if (rc != NS_LDAP_SUCCESS || param == NULL) {
4567 *errorp = error;
4568 return (rc);
4569 }
4570 sam = (char **)param;
4571
4572 cfg = __s_api_get_default_config();
4573 cnt = 0;
4574
4575 slen = strlen(service);
4576
4577 for (; *sam; sam++) {
4578 srv = *sam;
4579 if (strncasecmp(service, srv, slen) != 0)
4580 continue;
4581 srv += slen;
4582 if (*srv != COLONTOK)
4583 continue;
4584 send = srv;
4585 srv++;
4586 for (max = 1; (send = strchr(++send, SEMITOK)) != NULL; max++)
4587 ;
4588 authpp = (ns_auth_t **)calloc(++max, sizeof (ns_auth_t *));
4589 if (authpp == NULL) {
4590 (void) __ns_ldap_freeParam(¶m);
4591 __s_api_release_config(cfg);
4592 return (NS_LDAP_MEMORY);
4593 }
4594 while (!done) {
4595 send = strchr(srv, SEMITOK);
4596 if (send != NULL) {
4597 *send = '\0';
4598 send++;
4599 }
4600 i = __s_get_enum_value(cfg, srv, NS_LDAP_AUTH_P);
4601 if (i == -1) {
4602 (void) __ns_ldap_freeParam(¶m);
4603 (void) sprintf(errstr,
4604 gettext("Unsupported "
4605 "serviceAuthenticationMethod: %s.\n"), srv);
4606 MKERROR(LOG_WARNING, *errorp, NS_CONFIG_SYNTAX,
4607 strdup(errstr), NS_LDAP_MEMORY);
4608 __s_api_release_config(cfg);
4609 return (NS_LDAP_CONFIG);
4610 }
4611 ap = __s_api_AuthEnumtoStruct((EnumAuthType_t)i);
4612 if (ap == NULL) {
4613 (void) __ns_ldap_freeParam(¶m);
4614 __s_api_release_config(cfg);
4615 return (NS_LDAP_MEMORY);
4616 }
4617 authpp[cnt++] = ap;
4618 if (send == NULL)
4619 done = B_TRUE;
4620 else
4621 srv = send;
4622 }
4623 }
4624
4625 *auth = authpp;
4626 (void) __ns_ldap_freeParam(¶m);
4627 __s_api_release_config(cfg);
4628 return (NS_LDAP_SUCCESS);
4629 }
4630
4631 /*
4632 * This routine is called when certain scenario occurs
4633 * e.g.
4634 * service == auto_home
4635 * SSD = automount: ou = mytest,
4636 * NS_LDAP_MAPATTRIBUTE= auto_home: automountMapName=AAA
4637 * NS_LDAP_OBJECTCLASSMAP= auto_home:automountMap=MynisMap
4638 * NS_LDAP_OBJECTCLASSMAP= auto_home:automount=MynisObject
4639 *
4640 * The automountMapName is prepended implicitely but is mapped
4641 * to AAA. So dn could appers as
4642 * dn: AAA=auto_home,ou=bar,dc=foo,dc=com
4643 * dn: automountKey=user_01,AAA=auto_home,ou=bar,dc=foo,dc=com
4644 * dn: automountKey=user_02,AAA=auto_home,ou=bar,dc=foo,dc=com
4645 * in the directory.
4646 * This function is called to covert the mapped attr back to
4647 * orig attr when the entries are searched and returned
4648 */
4649
4650 int
__s_api_convert_automountmapname(const char * service,char ** dn,ns_ldap_error_t ** errp)4651 __s_api_convert_automountmapname(const char *service, char **dn,
4652 ns_ldap_error_t **errp)
4653 {
4654
4655 char **mapping = NULL;
4656 char *mapped_attr = NULL;
4657 char *automountmapname = "automountMapName";
4658 char *buffer = NULL;
4659 int rc = NS_LDAP_SUCCESS;
4660 char errstr[MAXERROR];
4661
4662 /*
4663 * dn is an input/out parameter, check it first
4664 */
4665
4666 if (service == NULL || dn == NULL || *dn == NULL)
4667 return (NS_LDAP_INVALID_PARAM);
4668
4669 /*
4670 * Check to see if there is a mapped attribute for auto_xxx
4671 */
4672
4673 mapping = __ns_ldap_getMappedAttributes(service, automountmapname);
4674
4675 /*
4676 * if no mapped attribute for auto_xxx, try automount
4677 */
4678
4679 if (mapping == NULL) {
4680 mapping = __ns_ldap_getMappedAttributes(
4681 "automount", automountmapname);
4682 }
4683
4684 /*
4685 * if no mapped attribute is found, return SUCCESS (no op)
4686 */
4687
4688 if (mapping == NULL)
4689 return (NS_LDAP_SUCCESS);
4690
4691 /*
4692 * if the mapped attribute is found and attr is not empty,
4693 * copy it
4694 */
4695
4696 if (mapping[0] != NULL) {
4697 mapped_attr = strdup(mapping[0]);
4698 __s_api_free2dArray(mapping);
4699 if (mapped_attr == NULL) {
4700 return (NS_LDAP_MEMORY);
4701 }
4702 } else {
4703 __s_api_free2dArray(mapping);
4704
4705 (void) snprintf(errstr, (2 * MAXERROR),
4706 gettext("Attribute nisMapName is mapped to an "
4707 "empty string.\n"));
4708
4709 MKERROR(LOG_ERR, *errp, NS_CONFIG_SYNTAX,
4710 strdup(errstr), NS_LDAP_MEMORY);
4711
4712 return (NS_LDAP_CONFIG);
4713 }
4714
4715 /*
4716 * Locate the mapped attribute in the dn
4717 * and replace it if it exists
4718 */
4719
4720 rc = __s_api_replace_mapped_attr_in_dn(
4721 (const char *) automountmapname, (const char *) mapped_attr,
4722 (const char *) *dn, &buffer);
4723
4724 /* clean up */
4725
4726 free(mapped_attr);
4727
4728 /*
4729 * If mapped attr is found(buffer != NULL)
4730 * a new dn is returned
4731 * If no mapped attribute is in dn,
4732 * return NS_LDAP_SUCCESS (no op)
4733 * If no memory,
4734 * return NS_LDAP_MEMORY (no op)
4735 */
4736
4737 if (buffer != NULL) {
4738 free(*dn);
4739 *dn = buffer;
4740 }
4741
4742 return (rc);
4743 }
4744
4745 /*
4746 * If the mapped attr is found in the dn,
4747 * return NS_LDAP_SUCCESS and a new_dn.
4748 * If no mapped attr is found,
4749 * return NS_LDAP_SUCCESS and *new_dn == NULL
4750 * If there is not enough memory,
4751 * return NS_LDAP_MEMORY and *new_dn == NULL
4752 */
4753
4754 int
__s_api_replace_mapped_attr_in_dn(const char * orig_attr,const char * mapped_attr,const char * dn,char ** new_dn)4755 __s_api_replace_mapped_attr_in_dn(const char *orig_attr,
4756 const char *mapped_attr, const char *dn, char **new_dn)
4757 {
4758
4759 char **dnArray = NULL;
4760 char *cur = NULL, *start = NULL;
4761 int i = 0;
4762 boolean_t found = B_FALSE;
4763 int len = 0, orig_len = 0, mapped_len = 0;
4764 int dn_len = 0, tmp_len = 0;
4765
4766 *new_dn = NULL;
4767
4768 /*
4769 * seperate dn into individual componets
4770 * e.g.
4771 * "automountKey=user_01" , "automountMapName_test=auto_home", ...
4772 */
4773 dnArray = ldap_explode_dn(dn, 0);
4774
4775 /*
4776 * This will find "mapped attr=value" in dn.
4777 * It won't find match if mapped attr appears
4778 * in the value.
4779 */
4780 for (i = 0; dnArray[i] != NULL; i++) {
4781 /*
4782 * This function is called when reading from
4783 * the directory so assume each component has "=".
4784 * Any ill formatted dn should be rejected
4785 * before adding to the directory
4786 */
4787 cur = strchr(dnArray[i], '=');
4788 *cur = '\0';
4789 if (strcasecmp(mapped_attr, dnArray[i]) == 0)
4790 found = B_TRUE;
4791 *cur = '=';
4792 if (found)
4793 break;
4794 }
4795
4796 if (!found) {
4797 __s_api_free2dArray(dnArray);
4798 *new_dn = NULL;
4799 return (NS_LDAP_SUCCESS);
4800 }
4801 /*
4802 * The new length is *dn length + (difference between
4803 * orig attr and mapped attr) + 1 ;
4804 * e.g.
4805 * automountKey=aa,automountMapName_test=auto_home,dc=foo,dc=com
4806 * ==>
4807 * automountKey=aa,automountMapName=auto_home,dc=foo,dc=com
4808 */
4809 mapped_len = strlen(mapped_attr);
4810 orig_len = strlen(orig_attr);
4811 dn_len = strlen(dn);
4812 len = dn_len + orig_len - mapped_len + 1;
4813 *new_dn = (char *)calloc(1, len);
4814 if (*new_dn == NULL) {
4815 __s_api_free2dArray(dnArray);
4816 return (NS_LDAP_MEMORY);
4817 }
4818
4819 /*
4820 * Locate the mapped attr in the dn.
4821 * Use dnArray[i] instead of mapped_attr
4822 * because mapped_attr could appear in
4823 * the value
4824 */
4825
4826 cur = strstr(dn, dnArray[i]);
4827 __s_api_free2dArray(dnArray);
4828 /* copy the portion before mapped attr in dn */
4829 start = *new_dn;
4830 tmp_len = cur - dn;
4831 (void) memcpy(start, dn, tmp_len);
4832
4833 /*
4834 * Copy the orig_attr. e.g. automountMapName
4835 * This replaces mapped attr with orig attr
4836 */
4837 start = start + (cur - dn); /* move cursor in buffer */
4838 (void) memcpy(start, orig_attr, orig_len);
4839
4840 /*
4841 * Copy the portion after mapped attr in dn
4842 */
4843 cur = cur + mapped_len; /* move cursor in dn */
4844 start = start + orig_len; /* move cursor in buffer */
4845 (void) strcpy(start, cur);
4846
4847 return (NS_LDAP_SUCCESS);
4848 }
4849
4850 /*
4851 * Validate Filter functions
4852 */
4853
4854 /* ***** Start of modified libldap.so.5 filter parser ***** */
4855
4856 /* filter parsing routine forward references */
4857 static int adj_filter_list(char *str);
4858 static int adj_simple_filter(char *str);
4859 static int unescape_filterval(char *val);
4860 static int hexchar2int(char c);
4861 static int adj_substring_filter(char *val);
4862
4863
4864 /*
4865 * assumes string manipulation is in-line
4866 * and all strings are sufficient in size
4867 * return value is the position after 'c'
4868 */
4869
4870 static char *
resync_str(char * str,char * next,char c)4871 resync_str(char *str, char *next, char c)
4872 {
4873 char *ret;
4874
4875 ret = str + strlen(str);
4876 *next = c;
4877 if (ret == next)
4878 return (ret);
4879 (void) strcat(str, next);
4880 return (ret);
4881 }
4882
4883 static char *
find_right_paren(char * s)4884 find_right_paren(char *s)
4885 {
4886 int balance;
4887 boolean_t escape;
4888
4889 balance = 1;
4890 escape = B_FALSE;
4891 while (*s && balance) {
4892 if (escape == B_FALSE) {
4893 if (*s == '(')
4894 balance++;
4895 else if (*s == ')')
4896 balance--;
4897 }
4898 if (*s == '\\' && !escape)
4899 escape = B_TRUE;
4900 else
4901 escape = B_FALSE;
4902 if (balance)
4903 s++;
4904 }
4905
4906 return (*s ? s : NULL);
4907 }
4908
4909 static char *
adj_complex_filter(char * str)4910 adj_complex_filter(char *str)
4911 {
4912 char *next;
4913
4914 /*
4915 * We have (x(filter)...) with str sitting on
4916 * the x. We have to find the paren matching
4917 * the one before the x and put the intervening
4918 * filters by calling adj_filter_list().
4919 */
4920
4921 str++;
4922 if ((next = find_right_paren(str)) == NULL)
4923 return (NULL);
4924
4925 *next = '\0';
4926 if (adj_filter_list(str) == -1)
4927 return (NULL);
4928 next = resync_str(str, next, ')');
4929 next++;
4930
4931 return (next);
4932 }
4933
4934 static int
adj_filter(char * str)4935 adj_filter(char *str)
4936 {
4937 char *next;
4938 int parens, balance;
4939 boolean_t escape;
4940 char *np, *cp, *dp;
4941
4942 parens = 0;
4943 while (*str) {
4944 switch (*str) {
4945 case '(':
4946 str++;
4947 parens++;
4948 switch (*str) {
4949 case '&':
4950 if ((str = adj_complex_filter(str)) == NULL)
4951 return (-1);
4952
4953 parens--;
4954 break;
4955
4956 case '|':
4957 if ((str = adj_complex_filter(str)) == NULL)
4958 return (-1);
4959
4960 parens--;
4961 break;
4962
4963 case '!':
4964 if ((str = adj_complex_filter(str)) == NULL)
4965 return (-1);
4966
4967 parens--;
4968 break;
4969
4970 case '(':
4971 /* illegal ((case - generated by conversion */
4972
4973 /* find missing close) */
4974 np = find_right_paren(str+1);
4975
4976 /* error if not found */
4977 if (np == NULL)
4978 return (-1);
4979
4980 /* remove redundant (and) */
4981 for (dp = str, cp = str+1; cp < np; ) {
4982 *dp++ = *cp++;
4983 }
4984 cp++;
4985 while (*cp)
4986 *dp++ = *cp++;
4987 *dp = '\0';
4988
4989 /* re-start test at original ( */
4990 parens--;
4991 str--;
4992 break;
4993
4994 default:
4995 balance = 1;
4996 escape = B_FALSE;
4997 next = str;
4998 while (*next && balance) {
4999 if (escape == B_FALSE) {
5000 if (*next == '(')
5001 balance++;
5002 else if (*next == ')')
5003 balance--;
5004 }
5005 if (*next == '\\' && !escape)
5006 escape = B_TRUE;
5007 else
5008 escape = B_FALSE;
5009 if (balance)
5010 next++;
5011 }
5012 if (balance != 0)
5013 return (-1);
5014
5015 *next = '\0';
5016 if (adj_simple_filter(str) == -1) {
5017 return (-1);
5018 }
5019 next = resync_str(str, next, ')');
5020 next++;
5021 str = next;
5022 parens--;
5023 break;
5024 }
5025 break;
5026
5027 case ')':
5028 str++;
5029 parens--;
5030 break;
5031
5032 case ' ':
5033 str++;
5034 break;
5035
5036 default: /* assume it's a simple type=value filter */
5037 next = strchr(str, '\0');
5038 if (adj_simple_filter(str) == -1) {
5039 return (-1);
5040 }
5041 str = next;
5042 break;
5043 }
5044 }
5045
5046 return (parens ? -1 : 0);
5047 }
5048
5049
5050 /*
5051 * Put a list of filters like this "(filter1)(filter2)..."
5052 */
5053
5054 static int
adj_filter_list(char * str)5055 adj_filter_list(char *str)
5056 {
5057 char *next;
5058 char save;
5059
5060 while (*str) {
5061 while (*str && isspace(*str))
5062 str++;
5063 if (*str == '\0')
5064 break;
5065
5066 if ((next = find_right_paren(str + 1)) == NULL)
5067 return (-1);
5068 save = *++next;
5069
5070 /* now we have "(filter)" with str pointing to it */
5071 *next = '\0';
5072 if (adj_filter(str) == -1)
5073 return (-1);
5074 next = resync_str(str, next, save);
5075
5076 str = next;
5077 }
5078
5079 return (0);
5080 }
5081
5082
5083 /*
5084 * is_valid_attr - returns 1 if a is a syntactically valid left-hand side
5085 * of a filter expression, 0 otherwise. A valid string may contain only
5086 * letters, numbers, hyphens, semi-colons, colons and periods. examples:
5087 * cn
5088 * cn;lang-fr
5089 * 1.2.3.4;binary;dynamic
5090 * mail;dynamic
5091 * cn:dn:1.2.3.4
5092 *
5093 * For compatibility with older servers, we also allow underscores in
5094 * attribute types, even through they are not allowed by the LDAPv3 RFCs.
5095 */
5096 static int
is_valid_attr(char * a)5097 is_valid_attr(char *a)
5098 {
5099 for (; *a; a++) {
5100 if (!isascii(*a)) {
5101 return (0);
5102 } else if (!isalnum(*a)) {
5103 switch (*a) {
5104 case '-':
5105 case '.':
5106 case ';':
5107 case ':':
5108 case '_':
5109 break; /* valid */
5110 default:
5111 return (0);
5112 }
5113 }
5114 }
5115 return (1);
5116 }
5117
5118 static char *
find_star(char * s)5119 find_star(char *s)
5120 {
5121 for (; *s; ++s) {
5122 switch (*s) {
5123 case '*':
5124 return (s);
5125 case '\\':
5126 ++s;
5127 if (hexchar2int(s[0]) >= 0 && hexchar2int(s[1]) >= 0)
5128 ++s;
5129 default:
5130 break;
5131 }
5132 }
5133 return (NULL);
5134 }
5135
5136 static int
adj_simple_filter(char * str)5137 adj_simple_filter(char *str)
5138 {
5139 char *s, *s2, *s3, filterop;
5140 char *value;
5141 int ftype = 0;
5142 int rc;
5143
5144 rc = -1; /* pessimistic */
5145
5146 if ((str = strdup(str)) == NULL) {
5147 return (rc);
5148 }
5149
5150 if ((s = strchr(str, '=')) == NULL) {
5151 goto free_and_return;
5152 }
5153 value = s + 1;
5154 *s-- = '\0';
5155 filterop = *s;
5156 if (filterop == '<' || filterop == '>' || filterop == '~' ||
5157 filterop == ':') {
5158 *s = '\0';
5159 }
5160
5161 if (!is_valid_attr(str)) {
5162 goto free_and_return;
5163 }
5164
5165 switch (filterop) {
5166 case '<': /* LDAP_FILTER_LE */
5167 case '>': /* LDAP_FILTER_GE */
5168 case '~': /* LDAP_FILTER_APPROX */
5169 break;
5170 case ':': /* extended filter - v3 only */
5171 /*
5172 * extended filter looks like this:
5173 *
5174 * [type][':dn'][':'oid]':='value
5175 *
5176 * where one of type or :oid is required.
5177 *
5178 */
5179 s2 = s3 = NULL;
5180 if ((s2 = strrchr(str, ':')) == NULL) {
5181 goto free_and_return;
5182 }
5183 if (strcasecmp(s2, ":dn") == 0) {
5184 *s2 = '\0';
5185 } else {
5186 *s2 = '\0';
5187 if ((s3 = strrchr(str, ':')) != NULL) {
5188 if (strcasecmp(s3, ":dn") != 0) {
5189 goto free_and_return;
5190 }
5191 *s3 = '\0';
5192 }
5193 }
5194 if (unescape_filterval(value) < 0) {
5195 goto free_and_return;
5196 }
5197 rc = 0;
5198 goto free_and_return;
5199 /* break; */
5200 default:
5201 if (find_star(value) == NULL) {
5202 ftype = 0; /* LDAP_FILTER_EQUALITY */
5203 } else if (strcmp(value, "*") == 0) {
5204 ftype = 1; /* LDAP_FILTER_PRESENT */
5205 } else {
5206 rc = adj_substring_filter(value);
5207 goto free_and_return;
5208 }
5209 break;
5210 }
5211
5212 if (ftype != 0) { /* == LDAP_FILTER_PRESENT */
5213 rc = 0;
5214 } else if (unescape_filterval(value) >= 0) {
5215 rc = 0;
5216 }
5217 if (rc != -1) {
5218 rc = 0;
5219 }
5220
5221 free_and_return:
5222 free(str);
5223 return (rc);
5224 }
5225
5226
5227 /*
5228 * Check in place both LDAPv2 (RFC-1960) and LDAPv3 (hexadecimal) escape
5229 * sequences within the null-terminated string 'val'.
5230 *
5231 * If 'val' contains invalid escape sequences we return -1.
5232 * Otherwise return 1
5233 */
5234 static int
unescape_filterval(char * val)5235 unescape_filterval(char *val)
5236 {
5237 boolean_t escape, firstdigit;
5238 char *s;
5239
5240 firstdigit = B_FALSE;
5241 escape = B_FALSE;
5242 for (s = val; *s; s++) {
5243 if (escape) {
5244 /*
5245 * first try LDAPv3 escape (hexadecimal) sequence
5246 */
5247 if (hexchar2int(*s) < 0) {
5248 if (firstdigit) {
5249 /*
5250 * LDAPv2 (RFC1960) escape sequence
5251 */
5252 escape = B_FALSE;
5253 } else {
5254 return (-1);
5255 }
5256 }
5257 if (firstdigit) {
5258 firstdigit = B_FALSE;
5259 } else {
5260 escape = B_FALSE;
5261 }
5262
5263 } else if (*s != '\\') {
5264 escape = B_FALSE;
5265
5266 } else {
5267 escape = B_TRUE;
5268 firstdigit = B_TRUE;
5269 }
5270 }
5271
5272 return (1);
5273 }
5274
5275
5276 /*
5277 * convert character 'c' that represents a hexadecimal digit to an integer.
5278 * if 'c' is not a hexidecimal digit [0-9A-Fa-f], -1 is returned.
5279 * otherwise the converted value is returned.
5280 */
5281 static int
hexchar2int(char c)5282 hexchar2int(char c)
5283 {
5284 if (c >= '0' && c <= '9') {
5285 return (c - '0');
5286 }
5287 if (c >= 'A' && c <= 'F') {
5288 return (c - 'A' + 10);
5289 }
5290 if (c >= 'a' && c <= 'f') {
5291 return (c - 'a' + 10);
5292 }
5293 return (-1);
5294 }
5295
5296 static int
adj_substring_filter(char * val)5297 adj_substring_filter(char *val)
5298 {
5299 char *nextstar;
5300
5301 for (; val != NULL; val = nextstar) {
5302 if ((nextstar = find_star(val)) != NULL) {
5303 *nextstar++ = '\0';
5304 }
5305
5306 if (*val != '\0') {
5307 if (unescape_filterval(val) < 0) {
5308 return (-1);
5309 }
5310 }
5311 }
5312
5313 return (0);
5314 }
5315
5316 /* ***** End of modified libldap.so.5 filter parser ***** */
5317
5318
5319 /*
5320 * Walk filter, remove redundant parentheses in-line
5321 * verify that the filter is reasonable
5322 */
5323 static int
validate_filter(ns_ldap_cookie_t * cookie)5324 validate_filter(ns_ldap_cookie_t *cookie)
5325 {
5326 char *filter = cookie->filter;
5327 int rc;
5328
5329 /* Parse filter looking for illegal values */
5330
5331 rc = adj_filter(filter);
5332 if (rc != 0) {
5333 return (NS_LDAP_OP_FAILED);
5334 }
5335
5336 /* end of filter checking */
5337
5338 return (NS_LDAP_SUCCESS);
5339 }
5340
5341 /*
5342 * Set the account management request control that needs to be sent to server.
5343 * This control is required to get the account management information of
5344 * a user to do local account checking.
5345 */
5346 static int
setup_acctmgmt_params(ns_ldap_cookie_t * cookie)5347 setup_acctmgmt_params(ns_ldap_cookie_t *cookie)
5348 {
5349 LDAPControl *req, **requestctrls;
5350
5351 req = calloc(1, sizeof (LDAPControl));
5352
5353 if (req == NULL)
5354 return (NS_LDAP_MEMORY);
5355
5356 /* fill in the fields of this new control */
5357 req->ldctl_iscritical = 1;
5358 req->ldctl_oid = strdup(NS_LDAP_ACCOUNT_USABLE_CONTROL);
5359 if (req->ldctl_oid == NULL) {
5360 free(req);
5361 return (NS_LDAP_MEMORY);
5362 }
5363
5364 requestctrls = (LDAPControl **)calloc(2, sizeof (LDAPControl *));
5365 if (requestctrls == NULL) {
5366 ldap_control_free(req);
5367 return (NS_LDAP_MEMORY);
5368 }
5369
5370 requestctrls[0] = req;
5371
5372 cookie->p_serverctrls = requestctrls;
5373
5374 return (NS_LDAP_SUCCESS);
5375 }
5376
5377 /*
5378 * int get_new_acct_more_info(BerElement *ber,
5379 * AcctUsableResponse_t *acctResp)
5380 *
5381 * Decode the more_info data from an Account Management control response,
5382 * when the account is not usable and when code style is from recent LDAP
5383 * servers (see below comments for parse_acct_cont_resp_msg() to get more
5384 * details on coding styles and ASN1 description).
5385 *
5386 * Expected BER encoding: {tbtbtbtiti}
5387 * +t: tag is 0
5388 * +b: TRUE if inactive due to account inactivation
5389 * +t: tag is 1
5390 * +b: TRUE if password has been reset
5391 * +t: tag is 2
5392 * +b: TRUE if password is expired
5393 * +t: tag is 3
5394 * +i: contains num of remaining grace, 0 means no grace
5395 * +t: tag is 4
5396 * +i: contains num of seconds before auto-unlock. -1 means acct is locked
5397 * forever (i.e. until reset)
5398 *
5399 * Asumptions:
5400 * - ber is not null
5401 * - acctResp is not null and is initialized with default values for the
5402 * fields in its AcctUsableResp.more_info structure
5403 * - the ber stream is received in the correct order, per the ASN1 description.
5404 * We do not check this order and make the asumption that it is correct.
5405 * Note that the ber stream may not (and will not in most cases) contain
5406 * all fields.
5407 */
5408 static int
get_new_acct_more_info(BerElement * ber,AcctUsableResponse_t * acctResp)5409 get_new_acct_more_info(BerElement *ber, AcctUsableResponse_t *acctResp)
5410 {
5411 int rc = NS_LDAP_SUCCESS;
5412 char errstr[MAXERROR];
5413 ber_tag_t rTag = LBER_DEFAULT;
5414 ber_len_t rLen = 0;
5415 ber_int_t rValue;
5416 char *last;
5417 int berRC = 0;
5418
5419 /*
5420 * Look at what more_info BER element is/are left to be decoded.
5421 * look at each of them 1 by 1, without checking on their order
5422 * and possible multi values.
5423 */
5424 for (rTag = ber_first_element(ber, &rLen, &last);
5425 rTag != LBER_END_OF_SEQORSET;
5426 rTag = ber_next_element(ber, &rLen, last)) {
5427
5428 berRC = 0;
5429 switch (rTag) {
5430 case 0 | LBER_CLASS_CONTEXT | LBER_PRIMITIVE:
5431 /* inactive */
5432 berRC = ber_scanf(ber, "b", &rValue);
5433 if (berRC != LBER_ERROR) {
5434 (acctResp->AcctUsableResp).more_info.
5435 inactive = (rValue != 0) ? 1 : 0;
5436 }
5437 break;
5438
5439 case 1 | LBER_CLASS_CONTEXT | LBER_PRIMITIVE:
5440 /* reset */
5441 berRC = ber_scanf(ber, "b", &rValue);
5442 if (berRC != LBER_ERROR) {
5443 (acctResp->AcctUsableResp).more_info.reset
5444 = (rValue != 0) ? 1 : 0;
5445 }
5446 break;
5447
5448 case 2 | LBER_CLASS_CONTEXT | LBER_PRIMITIVE:
5449 /* expired */
5450 berRC = ber_scanf(ber, "b", &rValue);
5451 if (berRC != LBER_ERROR) {
5452 (acctResp->AcctUsableResp).more_info.expired
5453 = (rValue != 0) ? 1 : 0;
5454 }
5455 break;
5456
5457 case 3 | LBER_CLASS_CONTEXT | LBER_PRIMITIVE:
5458 /* remaining grace */
5459 berRC = ber_scanf(ber, "i", &rValue);
5460 if (berRC != LBER_ERROR) {
5461 (acctResp->AcctUsableResp).more_info.rem_grace
5462 = rValue;
5463 }
5464 break;
5465
5466 case 4 | LBER_CLASS_CONTEXT | LBER_PRIMITIVE:
5467 /* seconds before unlock */
5468 berRC = ber_scanf(ber, "i", &rValue);
5469 if (berRC != LBER_ERROR) {
5470 (acctResp->AcctUsableResp).more_info.
5471 sec_b4_unlock = rValue;
5472 }
5473 break;
5474
5475 default :
5476 (void) sprintf(errstr,
5477 gettext("invalid reason tag 0x%x"), rTag);
5478 syslog(LOG_DEBUG, "libsldap: %s", errstr);
5479 rc = NS_LDAP_INTERNAL;
5480 break;
5481 }
5482 if (berRC == LBER_ERROR) {
5483 (void) sprintf(errstr,
5484 gettext("error 0x%x decoding value for "
5485 "tag 0x%x"), berRC, rTag);
5486 syslog(LOG_DEBUG, "libsldap: %s", errstr);
5487 rc = NS_LDAP_INTERNAL;
5488 }
5489 if (rc != NS_LDAP_SUCCESS) {
5490 /* exit the for loop */
5491 break;
5492 }
5493 }
5494
5495 return (rc);
5496 }
5497
5498 /*
5499 * int get_old_acct_opt_more_info(BerElement *ber,
5500 * AcctUsableResponse_t *acctResp)
5501 *
5502 * Decode the optional more_info data from an Account Management control
5503 * response, when the account is not usable and when code style is from LDAP
5504 * server 5.2p4 (see below comments for parse_acct_cont_resp_msg() to get more
5505 * details on coding styles and ASN1 description).
5506 *
5507 * Expected BER encoding: titi}
5508 * +t: tag is 2
5509 * +i: contains num of remaining grace, 0 means no grace
5510 * +t: tag is 3
5511 * +i: contains num of seconds before auto-unlock. -1 means acct is locked
5512 * forever (i.e. until reset)
5513 *
5514 * Asumptions:
5515 * - ber is a valid BER element
5516 * - acctResp is initialized for the fields in its AcctUsableResp.more_info
5517 * structure
5518 */
5519 static int
get_old_acct_opt_more_info(ber_tag_t tag,BerElement * ber,AcctUsableResponse_t * acctResp)5520 get_old_acct_opt_more_info(ber_tag_t tag, BerElement *ber,
5521 AcctUsableResponse_t *acctResp)
5522 {
5523 int rc = NS_LDAP_SUCCESS;
5524 char errstr[MAXERROR];
5525 ber_len_t len;
5526 int rem_grace, sec_b4_unlock;
5527
5528 switch (tag) {
5529 case 2:
5530 /* decode and maybe 3 is following */
5531 if ((tag = ber_scanf(ber, "i", &rem_grace)) == LBER_ERROR) {
5532 (void) sprintf(errstr, gettext("Can not get "
5533 "rem_grace"));
5534 syslog(LOG_DEBUG, "libsldap: %s", errstr);
5535 rc = NS_LDAP_INTERNAL;
5536 break;
5537 }
5538 (acctResp->AcctUsableResp).more_info.rem_grace = rem_grace;
5539
5540 if ((tag = ber_peek_tag(ber, &len)) == LBER_ERROR) {
5541 /* this is a success case, break to exit */
5542 (void) sprintf(errstr, gettext("No more "
5543 "optional data"));
5544 syslog(LOG_DEBUG, "libsldap: %s", errstr);
5545 break;
5546 }
5547
5548 if (tag == 3) {
5549 if (ber_scanf(ber, "i", &sec_b4_unlock) == LBER_ERROR) {
5550 (void) sprintf(errstr,
5551 gettext("Can not get sec_b4_unlock "
5552 "- 1st case"));
5553 syslog(LOG_DEBUG, "libsldap: %s", errstr);
5554 rc = NS_LDAP_INTERNAL;
5555 break;
5556 }
5557 (acctResp->AcctUsableResp).more_info.sec_b4_unlock =
5558 sec_b4_unlock;
5559 } else { /* unknown tag */
5560 (void) sprintf(errstr, gettext("Unknown tag "
5561 "- 1st case"));
5562 syslog(LOG_DEBUG, "libsldap: %s", errstr);
5563 rc = NS_LDAP_INTERNAL;
5564 break;
5565 }
5566 break;
5567
5568 case 3:
5569 if (ber_scanf(ber, "i", &sec_b4_unlock) == LBER_ERROR) {
5570 (void) sprintf(errstr, gettext("Can not get "
5571 "sec_b4_unlock - 2nd case"));
5572 syslog(LOG_DEBUG, "libsldap: %s", errstr);
5573 rc = NS_LDAP_INTERNAL;
5574 break;
5575 }
5576 (acctResp->AcctUsableResp).more_info.sec_b4_unlock =
5577 sec_b4_unlock;
5578 break;
5579
5580 default: /* unknown tag */
5581 (void) sprintf(errstr, gettext("Unknown tag - 2nd case"));
5582 syslog(LOG_DEBUG, "libsldap: %s", errstr);
5583 rc = NS_LDAP_INTERNAL;
5584 break;
5585 }
5586
5587 return (rc);
5588 }
5589
5590 /*
5591 * **** This function needs to be moved to libldap library ****
5592 * parse_acct_cont_resp_msg() parses the message received by server according to
5593 * following format (ASN1 notation):
5594 *
5595 * ACCOUNT_USABLE_RESPONSE::= CHOICE {
5596 * is_available [0] INTEGER,
5597 * ** seconds before expiration **
5598 * is_not_available [1] more_info
5599 * }
5600 * more_info::= SEQUENCE {
5601 * inactive [0] BOOLEAN DEFAULT FALSE,
5602 * reset [1] BOOLEAN DEFAULT FALSE,
5603 * expired [2] BOOLEAN DEFAULT FALSE,
5604 * remaining_grace [3] INTEGER OPTIONAL,
5605 * seconds_before_unlock [4] INTEGER OPTIONAL
5606 * }
5607 */
5608 /*
5609 * #define used to make the difference between coding style as done
5610 * by LDAP server 5.2p4 and newer LDAP servers. There are 4 values:
5611 * - DS52p4_USABLE: 5.2p4 coding style, account is usable
5612 * - DS52p4_NOT_USABLE: 5.2p4 coding style, account is not usable
5613 * - NEW_USABLE: newer LDAP servers coding style, account is usable
5614 * - NEW_NOT_USABLE: newer LDAP servers coding style, account is not usable
5615 *
5616 * An account would be considered not usable if for instance:
5617 * - it's been made inactive in the LDAP server
5618 * - or its password was reset in the LDAP server database
5619 * - or its password expired
5620 * - or the account has been locked, possibly forever
5621 */
5622 #define DS52p4_USABLE 0x00
5623 #define DS52p4_NOT_USABLE 0x01
5624 #define NEW_USABLE 0x00 | LBER_CLASS_CONTEXT | LBER_PRIMITIVE
5625 #define NEW_NOT_USABLE 0x01 | LBER_CLASS_CONTEXT | LBER_CONSTRUCTED
5626 static int
parse_acct_cont_resp_msg(LDAPControl ** ectrls,AcctUsableResponse_t * acctResp)5627 parse_acct_cont_resp_msg(LDAPControl **ectrls, AcctUsableResponse_t *acctResp)
5628 {
5629 int rc = NS_LDAP_SUCCESS;
5630 BerElement *ber;
5631 ber_tag_t tag;
5632 ber_len_t len;
5633 int i;
5634 char errstr[MAXERROR];
5635 /* used for any coding style when account is usable */
5636 int seconds_before_expiry;
5637 /* used for 5.2p4 coding style when account is not usable */
5638 int inactive, reset, expired;
5639
5640 if (ectrls == NULL) {
5641 (void) sprintf(errstr, gettext("Invalid ectrls parameter"));
5642 syslog(LOG_DEBUG, "libsldap: %s", errstr);
5643 return (NS_LDAP_INVALID_PARAM);
5644 }
5645
5646 for (i = 0; ectrls[i] != NULL; i++) {
5647 if (strcmp(ectrls[i]->ldctl_oid, NS_LDAP_ACCOUNT_USABLE_CONTROL)
5648 == 0) {
5649 break;
5650 }
5651 }
5652
5653 if (ectrls[i] == NULL) {
5654 /* Ldap control is not found */
5655 (void) sprintf(errstr, gettext("Account Usable Control "
5656 "not found"));
5657 syslog(LOG_DEBUG, "libsldap: %s", errstr);
5658 return (NS_LDAP_NOTFOUND);
5659 }
5660
5661 /* Allocate a BER element from the control value and parse it. */
5662 if ((ber = ber_init(&ectrls[i]->ldctl_value)) == NULL)
5663 return (NS_LDAP_MEMORY);
5664
5665 if ((tag = ber_peek_tag(ber, &len)) == LBER_ERROR) {
5666 /* Ldap decoding error */
5667 (void) sprintf(errstr, gettext("Error decoding 1st tag"));
5668 syslog(LOG_DEBUG, "libsldap: %s", errstr);
5669 ber_free(ber, 1);
5670 return (NS_LDAP_INTERNAL);
5671 }
5672
5673 switch (tag) {
5674 case DS52p4_USABLE:
5675 case NEW_USABLE:
5676 acctResp->choice = 0;
5677 if (ber_scanf(ber, "i", &seconds_before_expiry)
5678 == LBER_ERROR) {
5679 /* Ldap decoding error */
5680 (void) sprintf(errstr, gettext("Can not get "
5681 "seconds_before_expiry"));
5682 syslog(LOG_DEBUG, "libsldap: %s", errstr);
5683 rc = NS_LDAP_INTERNAL;
5684 break;
5685 }
5686 /* ber_scanf() succeeded */
5687 (acctResp->AcctUsableResp).seconds_before_expiry =
5688 seconds_before_expiry;
5689 break;
5690
5691 case DS52p4_NOT_USABLE:
5692 acctResp->choice = 1;
5693 if (ber_scanf(ber, "{bbb", &inactive, &reset, &expired)
5694 == LBER_ERROR) {
5695 /* Ldap decoding error */
5696 (void) sprintf(errstr, gettext("Can not get "
5697 "inactive/reset/expired"));
5698 syslog(LOG_DEBUG, "libsldap: %s", errstr);
5699 rc = NS_LDAP_INTERNAL;
5700 break;
5701 }
5702 /* ber_scanf() succeeded */
5703 (acctResp->AcctUsableResp).more_info.inactive =
5704 ((inactive == 0) ? 0 : 1);
5705 (acctResp->AcctUsableResp).more_info.reset =
5706 ((reset == 0) ? 0 : 1);
5707 (acctResp->AcctUsableResp).more_info.expired =
5708 ((expired == 0) ? 0 : 1);
5709 (acctResp->AcctUsableResp).more_info.rem_grace = 0;
5710 (acctResp->AcctUsableResp).more_info.sec_b4_unlock = 0;
5711
5712 if ((tag = ber_peek_tag(ber, &len)) == LBER_ERROR) {
5713 /* this is a success case, break to exit */
5714 (void) sprintf(errstr, gettext("No optional data"));
5715 syslog(LOG_DEBUG, "libsldap: %s", errstr);
5716 break;
5717 }
5718
5719 /*
5720 * Look at what optional more_info BER element is/are
5721 * left to be decoded.
5722 */
5723 rc = get_old_acct_opt_more_info(tag, ber, acctResp);
5724 break;
5725
5726 case NEW_NOT_USABLE:
5727 acctResp->choice = 1;
5728 /*
5729 * Recent LDAP servers won't code more_info data for default
5730 * values (see above comments on ASN1 description for what
5731 * fields have default values & what fields are optional).
5732 */
5733 (acctResp->AcctUsableResp).more_info.inactive = 0;
5734 (acctResp->AcctUsableResp).more_info.reset = 0;
5735 (acctResp->AcctUsableResp).more_info.expired = 0;
5736 (acctResp->AcctUsableResp).more_info.rem_grace = 0;
5737 (acctResp->AcctUsableResp).more_info.sec_b4_unlock = 0;
5738
5739 if (len == 0) {
5740 /*
5741 * Nothing else to decode; this is valid and we
5742 * use default values set above.
5743 */
5744 (void) sprintf(errstr, gettext("more_info is "
5745 "empty, using default values"));
5746 syslog(LOG_DEBUG, "libsldap: %s", errstr);
5747 break;
5748 }
5749
5750 /*
5751 * Look at what more_info BER element is/are left to
5752 * be decoded.
5753 */
5754 rc = get_new_acct_more_info(ber, acctResp);
5755 break;
5756
5757 default:
5758 (void) sprintf(errstr, gettext("unknwon coding style "
5759 "(tag: 0x%x)"), tag);
5760 syslog(LOG_DEBUG, "libsldap: %s", errstr);
5761 rc = NS_LDAP_INTERNAL;
5762 break;
5763 }
5764
5765 ber_free(ber, 1);
5766 return (rc);
5767 }
5768
5769 /*
5770 * internal function for __ns_ldap_getAcctMgmt()
5771 */
5772 static int
getAcctMgmt(const char * user,AcctUsableResponse_t * acctResp,ns_conn_user_t * conn_user)5773 getAcctMgmt(const char *user, AcctUsableResponse_t *acctResp,
5774 ns_conn_user_t *conn_user)
5775 {
5776 int scope, rc;
5777 ns_ldap_cookie_t *cookie;
5778 ns_ldap_search_desc_t **sdlist = NULL;
5779 ns_ldap_search_desc_t *dptr;
5780 ns_ldap_error_t *error = NULL;
5781 char **dns = NULL;
5782 char service[] = "shadow";
5783
5784 if (user == NULL || acctResp == NULL)
5785 return (NS_LDAP_INVALID_PARAM);
5786
5787 /* Initialize State machine cookie */
5788 cookie = init_search_state_machine();
5789 if (cookie == NULL)
5790 return (NS_LDAP_MEMORY);
5791 cookie->conn_user = conn_user;
5792
5793 /* see if need to follow referrals */
5794 rc = __s_api_toFollowReferrals(0,
5795 &cookie->followRef, &error);
5796 if (rc != NS_LDAP_SUCCESS) {
5797 (void) __ns_ldap_freeError(&error);
5798 goto out;
5799 }
5800
5801 /* get the service descriptor - or create a default one */
5802 rc = __s_api_get_SSD_from_SSDtoUse_service(service,
5803 &sdlist, &error);
5804 if (rc != NS_LDAP_SUCCESS) {
5805 (void) __ns_ldap_freeError(&error);
5806 goto out;
5807 }
5808
5809 if (sdlist == NULL) {
5810 /* Create default service Desc */
5811 sdlist = (ns_ldap_search_desc_t **)calloc(2,
5812 sizeof (ns_ldap_search_desc_t *));
5813 if (sdlist == NULL) {
5814 rc = NS_LDAP_MEMORY;
5815 goto out;
5816 }
5817 dptr = (ns_ldap_search_desc_t *)
5818 calloc(1, sizeof (ns_ldap_search_desc_t));
5819 if (dptr == NULL) {
5820 free(sdlist);
5821 rc = NS_LDAP_MEMORY;
5822 goto out;
5823 }
5824 sdlist[0] = dptr;
5825
5826 /* default base */
5827 rc = __s_api_getDNs(&dns, service, &cookie->errorp);
5828 if (rc != NS_LDAP_SUCCESS) {
5829 if (dns) {
5830 __s_api_free2dArray(dns);
5831 dns = NULL;
5832 }
5833 (void) __ns_ldap_freeError(&(cookie->errorp));
5834 cookie->errorp = NULL;
5835 goto out;
5836 }
5837 dptr->basedn = strdup(dns[0]);
5838 if (dptr->basedn == NULL) {
5839 free(sdlist);
5840 free(dptr);
5841 if (dns) {
5842 __s_api_free2dArray(dns);
5843 dns = NULL;
5844 }
5845 rc = NS_LDAP_MEMORY;
5846 goto out;
5847 }
5848 __s_api_free2dArray(dns);
5849 dns = NULL;
5850
5851 /* default scope */
5852 scope = 0;
5853 rc = __s_api_getSearchScope(&scope, &cookie->errorp);
5854 dptr->scope = scope;
5855 }
5856
5857 cookie->sdlist = sdlist;
5858
5859 cookie->service = strdup(service);
5860 if (cookie->service == NULL) {
5861 rc = NS_LDAP_MEMORY;
5862 goto out;
5863 }
5864
5865 /* search for entries for this particular uid */
5866 (void) asprintf(&cookie->i_filter, "(uid=%s)", user);
5867 if (cookie->i_filter == NULL) {
5868 rc = NS_LDAP_MEMORY;
5869 goto out;
5870 }
5871
5872 /* create the control request */
5873 if ((rc = setup_acctmgmt_params(cookie)) != NS_LDAP_SUCCESS)
5874 goto out;
5875
5876 /* Process search */
5877 rc = search_state_machine(cookie, GET_ACCT_MGMT_INFO, 0);
5878
5879 /* Copy results back to user */
5880 rc = cookie->err_rc;
5881 if (rc != NS_LDAP_SUCCESS)
5882 (void) __ns_ldap_freeError(&(cookie->errorp));
5883
5884 if (cookie->result == NULL)
5885 goto out;
5886
5887 if ((rc = parse_acct_cont_resp_msg(cookie->resultctrl, acctResp))
5888 != NS_LDAP_SUCCESS)
5889 goto out;
5890
5891 rc = NS_LDAP_SUCCESS;
5892
5893 out:
5894 delete_search_cookie(cookie);
5895
5896 return (rc);
5897 }
5898
5899 /*
5900 * __ns_ldap_getAcctMgmt() is called from pam account management stack
5901 * for retrieving accounting information of users with no user password -
5902 * eg. rlogin, rsh, etc. This function uses the account management control
5903 * request to do a search on the server for the user in question. The
5904 * response control returned from the server is got from the cookie.
5905 * Input params: username of whose account mgmt information is to be got
5906 * pointer to hold the parsed account management information
5907 * Return values: NS_LDAP_SUCCESS on success or appropriate error
5908 * code on failure
5909 */
5910 int
__ns_ldap_getAcctMgmt(const char * user,AcctUsableResponse_t * acctResp)5911 __ns_ldap_getAcctMgmt(const char *user, AcctUsableResponse_t *acctResp)
5912 {
5913 ns_conn_user_t *cu = NULL;
5914 int try_cnt = 0;
5915 int rc = NS_LDAP_SUCCESS;
5916 ns_ldap_error_t *error = NULL;
5917
5918 for (;;) {
5919 if (__s_api_setup_retry_search(&cu, NS_CONN_USER_SEARCH,
5920 &try_cnt, &rc, &error) == 0)
5921 break;
5922 rc = getAcctMgmt(user, acctResp, cu);
5923 }
5924 return (rc);
5925 }
5926