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