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