dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / lib / libsldap / common / ns_reads.c
blob5319671a2ad4e39f122475771467a7032873619e
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
19 * CDDL HEADER END
22 * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
25 #include <stdio.h>
26 #include <sys/types.h>
27 #include <stdlib.h>
28 #include <libintl.h>
29 #include <ctype.h>
30 #include <syslog.h>
31 #include <sys/stat.h>
32 #include <fcntl.h>
33 #include <unistd.h>
34 #include <string.h>
35 #include <strings.h>
36 #include <priv.h>
38 #include "ns_sldap.h"
39 #include "ns_internal.h"
40 #include "ns_cache_door.h"
41 #include "ns_connmgmt.h"
43 #define _NIS_FILTER "nisdomain=*"
44 #define _NIS_DOMAIN "nisdomain"
45 static const char *nis_domain_attrs[] = {
46 _NIS_DOMAIN,
47 NULL
50 static int validate_filter(ns_ldap_cookie_t *cookie);
52 void
53 __ns_ldap_freeEntry(ns_ldap_entry_t *ep)
55 int j, k = 0;
57 if (ep == NULL)
58 return;
60 if (ep->attr_pair == NULL) {
61 free(ep);
62 return;
64 for (j = 0; j < ep->attr_count; j++) {
65 if (ep->attr_pair[j] == NULL)
66 continue;
67 free(ep->attr_pair[j]->attrname);
68 if (ep->attr_pair[j]->attrvalue) {
69 for (k = 0; (k < ep->attr_pair[j]->value_count) &&
70 (ep->attr_pair[j]->attrvalue[k]); k++) {
71 free(ep->attr_pair[j]->attrvalue[k]);
73 free(ep->attr_pair[j]->attrvalue);
75 free(ep->attr_pair[j]);
77 free(ep->attr_pair);
78 free(ep);
81 static void
82 _freeControlList(LDAPControl ***ctrls)
84 LDAPControl **ctrl;
86 if (ctrls == NULL || *ctrls == NULL)
87 return;
89 for (ctrl = *ctrls; *ctrl != NULL; ctrl++)
90 ldap_control_free(*ctrl);
91 free(*ctrls);
92 *ctrls = NULL;
95 * Convert attribute type in a RDN that has an attribute mapping to the
96 * original mappped type.
97 * e.g.
98 * cn<->cn-st and iphostnumber<->iphostnumber-st
99 * cn-st=aaa+iphostnumber-st=10.10.01.01
100 * is mapped to
101 * cn=aaa+iphostnumber=10.10.01.01
103 * Input - service: e.g. hosts, passwd etc.
104 * rdn: RDN
105 * Return: NULL - No attribute mapping in the RDN
106 * Non-NULL - The attribute type(s) in the RDN are mapped and
107 * the memory is allocated for the new rdn.
110 static char *
111 _cvtRDN(const char *service, const char *rdn) {
112 char **attrs, **mapped_attrs, **mapp, *type, *value, *attr;
113 char *new_rdn = NULL;
114 int nAttr = 0, i, attr_mapped, len = 0;
116 /* Break down "type=value\0" pairs. Assume RDN is normalized */
117 if ((attrs = ldap_explode_rdn(rdn, 0)) == NULL)
118 return (NULL);
120 for (nAttr = 0; attrs[nAttr] != NULL; nAttr++);
122 if ((mapped_attrs = (char **)calloc(nAttr, sizeof (char *))) == NULL) {
123 ldap_value_free(attrs);
124 return (NULL);
127 attr_mapped = 0;
128 for (i = 0; i < nAttr; i++) {
129 /* Parse type=value pair */
130 if ((type = strtok_r(attrs[i], "=", &value)) == NULL ||
131 value == NULL)
132 goto cleanup;
133 /* Reverse map: e.g. cn-sm -> cn */
134 mapp = __ns_ldap_getOrigAttribute(service, type);
135 if (mapp != NULL && mapp[0] != NULL) {
136 /* The attribute mapping is found */
137 type = mapp[0];
138 attr_mapped = 1;
140 /* "type=value\0" */
141 len = strlen(type) + strlen(value) + 2;
143 /* Reconstruct type=value pair. A string is allocated */
144 if ((attr = (char *)calloc(1, len)) == NULL) {
145 __s_api_free2dArray(mapp);
146 goto cleanup;
148 (void) snprintf(attr, len, "%s=%s",
149 type, value);
150 mapped_attrs[i] = attr;
151 } else {
153 * No attribute mapping. attrs[i] is going to be copied
154 * later. Restore "type\0value\0" back to
155 * "type=value\0".
157 type[strlen(type)] = '=';
159 __s_api_free2dArray(mapp);
161 if (attr_mapped == 0)
162 /* No attribute mapping. Don't bother to reconstruct RDN */
163 goto cleanup;
165 len = 0;
166 /* Reconstruct RDN from type=value pairs */
167 for (i = 0; i < nAttr; i++) {
168 if (mapped_attrs[i])
169 len += strlen(mapped_attrs[i]);
170 else
171 len += strlen(attrs[i]);
172 /* Add 1 for "+" */
173 len++;
175 if ((new_rdn = (char *)calloc(1, ++len)) == NULL)
176 goto cleanup;
177 for (i = 0; i < nAttr; i++) {
178 if (i > 0)
179 /* Add seperator */
180 (void) strlcat(new_rdn, "+", len);
182 if (mapped_attrs[i])
183 (void) strlcat(new_rdn, mapped_attrs[i], len);
184 else
185 (void) strlcat(new_rdn, attrs[i], len);
188 cleanup:
189 ldap_value_free(attrs);
190 if (mapped_attrs) {
191 if (attr_mapped) {
192 for (i = 0; i < nAttr; i++) {
193 free(mapped_attrs[i]);
196 free(mapped_attrs);
199 return (new_rdn);
202 * Convert attribute type in a DN that has an attribute mapping to the
203 * original mappped type.
204 * e.g
205 * The mappings are cn<->cn-sm, iphostnumber<->iphostnumber-sm
207 * dn: cn-sm=aaa+iphostnumber-sm=9.9.9.9,dc=central,dc=sun,dc=com
208 * is converted to
209 * dn: cn=aaa+iphostnumber=9.9.9.9,dc=central,dc=sun,dc=com
211 * Input - service: e.g. hosts, passwd etc.
212 * dn: the value of a distinguished name
213 * Return - NULL: error
214 * non-NULL: A converted DN and the memory is allocated
216 static char *
217 _cvtDN(const char *service, const char *dn) {
218 char **mapped_rdns;
219 char **rdns, *new_rdn, *new_dn = NULL;
220 int nRdn = 0, i, len = 0, rdn_mapped;
222 if (service == NULL || dn == NULL)
223 return (NULL);
225 if ((rdns = ldap_explode_dn(dn, 0)) == NULL)
226 return (NULL);
228 for (nRdn = 0; rdns[nRdn] != NULL; nRdn++);
230 if ((mapped_rdns = (char **)calloc(nRdn, sizeof (char *))) == NULL) {
231 ldap_value_free(rdns);
232 return (NULL);
235 rdn_mapped = 0;
236 /* Break down RDNs in a DN */
237 for (i = 0; i < nRdn; i++) {
238 if ((new_rdn = _cvtRDN(service, rdns[i])) != NULL) {
239 mapped_rdns[i] = new_rdn;
240 rdn_mapped = 1;
243 if (rdn_mapped == 0) {
245 * No RDN contains any attribute mapping.
246 * Don't bother to reconstruct DN from RDN. Copy DN directly.
248 new_dn = strdup(dn);
249 goto cleanup;
252 * Reconstruct dn from RDNs.
253 * Calculate the length first.
255 for (i = 0; i < nRdn; i++) {
256 if (mapped_rdns[i])
257 len += strlen(mapped_rdns[i]);
258 else
259 len += strlen(rdns[i]);
261 /* add 1 for ',' */
262 len ++;
264 if ((new_dn = (char *)calloc(1, ++len)) == NULL)
265 goto cleanup;
266 for (i = 0; i < nRdn; i++) {
267 if (i > 0)
268 /* Add seperator */
269 (void) strlcat(new_dn, ",", len);
271 if (mapped_rdns[i])
272 (void) strlcat(new_dn, mapped_rdns[i], len);
273 else
274 (void) strlcat(new_dn, rdns[i], len);
278 cleanup:
279 ldap_value_free(rdns);
280 if (mapped_rdns) {
281 if (rdn_mapped) {
282 for (i = 0; i < nRdn; i++) {
283 free(mapped_rdns[i]);
286 free(mapped_rdns);
289 return (new_dn);
292 * Convert a single ldap entry from a LDAPMessage
293 * into an ns_ldap_entry structure.
294 * Schema map the entry if specified in flags
297 static int
298 __s_api_cvtEntry(LDAP *ld,
299 const char *service,
300 LDAPMessage *e,
301 int flags,
302 ns_ldap_entry_t **ret,
303 ns_ldap_error_t **error)
306 ns_ldap_entry_t *ep = NULL;
307 ns_ldap_attr_t **ap = NULL;
308 BerElement *ber;
309 char *attr = NULL;
310 char **vals = NULL;
311 char **mapping;
312 char *dn;
313 int nAttrs = 0;
314 int i, j, k = 0;
315 char **gecos_mapping = NULL;
316 int gecos_val_index[3] = { -1, -1, -1};
317 char errstr[MAXERROR];
318 int schema_mapping_existed = FALSE;
319 int gecos_mapping_existed = FALSE;
320 int gecos_attr_matched;
321 int auto_service = FALSE;
322 int rc = NS_LDAP_SUCCESS;
324 if (e == NULL || ret == NULL || error == NULL)
325 return (NS_LDAP_INVALID_PARAM);
327 *error = NULL;
329 ep = (ns_ldap_entry_t *)calloc(1, sizeof (ns_ldap_entry_t));
330 if (ep == NULL)
331 return (NS_LDAP_MEMORY);
333 if (service != NULL &&
334 (strncasecmp(service, "auto_", 5) == 0 ||
335 strcasecmp(service, "automount") == 0))
336 auto_service = TRUE;
338 * see if schema mapping existed for the given service
340 mapping = __ns_ldap_getOrigAttribute(service,
341 NS_HASH_SCHEMA_MAPPING_EXISTED);
342 if (mapping) {
343 schema_mapping_existed = TRUE;
344 __s_api_free2dArray(mapping);
345 mapping = NULL;
346 } else if (auto_service) {
348 * If service == auto_* and no
349 * schema mapping found
350 * then try automount
351 * There is certain case that schema mapping exist
352 * but __ns_ldap_getOrigAttribute(service,
353 * NS_HASH_SCHEMA_MAPPING_EXISTED);
354 * returns NULL.
355 * e.g.
356 * NS_LDAP_ATTRIBUTEMAP = automount:automountMapName=AAA
357 * NS_LDAP_OBJECTCLASSMAP = automount:automountMap=MynisMap
358 * NS_LDAP_OBJECTCLASSMAP = automount:automount=MynisObject
360 * Make a check for schema_mapping_existed here
361 * so later on __s_api_convert_automountmapname won't be called
362 * unnecessarily. It is also used for attribute mapping
363 * and objectclass mapping.
365 mapping = __ns_ldap_getOrigAttribute("automount",
366 NS_HASH_SCHEMA_MAPPING_EXISTED);
367 if (mapping) {
368 schema_mapping_existed = TRUE;
369 __s_api_free2dArray(mapping);
370 mapping = NULL;
374 nAttrs = 1; /* start with 1 for the DN attr */
375 for (attr = ldap_first_attribute(ld, e, &ber); attr != NULL;
376 attr = ldap_next_attribute(ld, e, ber)) {
377 nAttrs++;
378 ldap_memfree(attr);
379 attr = NULL;
381 ber_free(ber, 0);
382 ber = NULL;
384 ep->attr_count = nAttrs;
387 * add 1 for "gecos" 1 to N attribute mapping,
388 * just in case it is needed.
389 * ep->attr_count will be updated later if that is true.
391 ap = (ns_ldap_attr_t **)calloc(ep->attr_count + 1,
392 sizeof (ns_ldap_attr_t *));
393 if (ap == NULL) {
394 __ns_ldap_freeEntry(ep);
395 ep = NULL;
396 return (NS_LDAP_MEMORY);
398 ep->attr_pair = ap;
400 /* DN attribute */
401 dn = ldap_get_dn(ld, e);
402 ap[0] = (ns_ldap_attr_t *)calloc(1, sizeof (ns_ldap_attr_t));
403 if (ap[0] == NULL) {
404 ldap_memfree(dn);
405 dn = NULL;
406 __ns_ldap_freeEntry(ep);
407 ep = NULL;
408 return (NS_LDAP_MEMORY);
411 if ((ap[0]->attrname = strdup("dn")) == NULL) {
412 ldap_memfree(dn);
413 dn = NULL;
414 __ns_ldap_freeEntry(ep);
415 ep = NULL;
416 return (NS_LDAP_INVALID_PARAM);
418 ap[0]->value_count = 1;
419 if ((ap[0]->attrvalue = (char **)
420 calloc(2, sizeof (char *))) == NULL) {
421 ldap_memfree(dn);
422 dn = NULL;
423 __ns_ldap_freeEntry(ep);
424 ep = NULL;
425 return (NS_LDAP_MEMORY);
428 if (schema_mapping_existed && ((flags & NS_LDAP_NOT_CVT_DN) == 0))
429 ap[0]->attrvalue[0] = _cvtDN(service, dn);
430 else
431 ap[0]->attrvalue[0] = strdup(dn);
433 if (ap[0]->attrvalue[0] == NULL) {
434 ldap_memfree(dn);
435 dn = NULL;
436 __ns_ldap_freeEntry(ep);
437 ep = NULL;
438 return (NS_LDAP_MEMORY);
440 ldap_memfree(dn);
441 dn = NULL;
443 if ((flags & NS_LDAP_NOMAP) == 0 && auto_service &&
444 schema_mapping_existed) {
445 rc = __s_api_convert_automountmapname(service,
446 &ap[0]->attrvalue[0],
447 error);
448 if (rc != NS_LDAP_SUCCESS) {
449 __ns_ldap_freeEntry(ep);
450 ep = NULL;
451 return (rc);
455 /* other attributes */
456 for (attr = ldap_first_attribute(ld, e, &ber), j = 1;
457 attr != NULL && j != nAttrs;
458 attr = ldap_next_attribute(ld, e, ber), j++) {
459 /* allocate new attr name */
461 if ((ap[j] = (ns_ldap_attr_t *)
462 calloc(1, sizeof (ns_ldap_attr_t))) == NULL) {
463 ber_free(ber, 0);
464 ber = NULL;
465 __ns_ldap_freeEntry(ep);
466 ep = NULL;
467 if (gecos_mapping)
468 __s_api_free2dArray(gecos_mapping);
469 gecos_mapping = NULL;
470 return (NS_LDAP_MEMORY);
473 if ((flags & NS_LDAP_NOMAP) || schema_mapping_existed == FALSE)
474 mapping = NULL;
475 else
476 mapping = __ns_ldap_getOrigAttribute(service, attr);
478 if (mapping == NULL && auto_service &&
479 schema_mapping_existed && (flags & NS_LDAP_NOMAP) == 0)
481 * if service == auto_* and no schema mapping found
482 * and schema_mapping_existed is TRUE and NS_LDAP_NOMAP
483 * is not set then try automount e.g.
484 * NS_LDAP_ATTRIBUTEMAP = automount:automountMapName=AAA
486 mapping = __ns_ldap_getOrigAttribute("automount",
487 attr);
489 if (mapping == NULL) {
490 if ((ap[j]->attrname = strdup(attr)) == NULL) {
491 ber_free(ber, 0);
492 ber = NULL;
493 __ns_ldap_freeEntry(ep);
494 ep = NULL;
495 if (gecos_mapping)
496 __s_api_free2dArray(gecos_mapping);
497 gecos_mapping = NULL;
498 return (NS_LDAP_MEMORY);
500 } else {
502 * for "gecos" 1 to N mapping,
503 * do not remove the mapped attribute,
504 * just create a new gecos attribute
505 * and append it to the end of the attribute list
507 if (strcasecmp(mapping[0], "gecos") == 0) {
508 ap[j]->attrname = strdup(attr);
509 gecos_mapping_existed = TRUE;
510 } else
511 ap[j]->attrname = strdup(mapping[0]);
513 if (ap[j]->attrname == NULL) {
514 ber_free(ber, 0);
515 ber = NULL;
516 __ns_ldap_freeEntry(ep);
517 ep = NULL;
518 if (gecos_mapping)
519 __s_api_free2dArray(gecos_mapping);
520 gecos_mapping = NULL;
521 return (NS_LDAP_MEMORY);
524 * 1 to N attribute mapping processing
525 * is only done for "gecos"
528 if (strcasecmp(mapping[0], "gecos") == 0) {
530 * get attribute mapping for "gecos",
531 * need to know the number and order of the
532 * mapped attributes
534 if (gecos_mapping == NULL) {
535 gecos_mapping =
536 __ns_ldap_getMappedAttributes(
537 service, mapping[0]);
538 if (gecos_mapping == NULL ||
539 gecos_mapping[0] == NULL) {
541 * this should never happens,
542 * syslog the error
544 (void) sprintf(errstr,
545 gettext(
546 "Attribute mapping "
547 "inconsistency "
548 "found for attributes "
549 "'%s' and '%s'."),
550 mapping[0], attr);
551 syslog(LOG_ERR, "libsldap: %s",
552 errstr);
554 ber_free(ber, 0);
555 ber = NULL;
556 __ns_ldap_freeEntry(ep);
557 ep = NULL;
558 __s_api_free2dArray(mapping);
559 mapping = NULL;
560 if (gecos_mapping)
561 __s_api_free2dArray(
562 gecos_mapping);
563 gecos_mapping = NULL;
564 return (NS_LDAP_INTERNAL);
569 * is this attribute the 1st, 2nd, or
570 * 3rd attr in the mapping list?
572 gecos_attr_matched = FALSE;
573 for (i = 0; i < 3 && gecos_mapping[i]; i++) {
574 if (gecos_mapping[i] &&
575 strcasecmp(gecos_mapping[i],
576 attr) == 0) {
577 gecos_val_index[i] = j;
578 gecos_attr_matched = TRUE;
579 break;
582 if (gecos_attr_matched == FALSE) {
584 * Not match found.
585 * This should never happens,
586 * syslog the error
588 (void) sprintf(errstr,
589 gettext(
590 "Attribute mapping "
591 "inconsistency "
592 "found for attributes "
593 "'%s' and '%s'."),
594 mapping[0], attr);
595 syslog(LOG_ERR, "libsldap: %s", errstr);
597 ber_free(ber, 0);
598 ber = NULL;
599 __ns_ldap_freeEntry(ep);
600 ep = NULL;
601 __s_api_free2dArray(mapping);
602 mapping = NULL;
603 __s_api_free2dArray(gecos_mapping);
604 gecos_mapping = NULL;
605 return (NS_LDAP_INTERNAL);
608 __s_api_free2dArray(mapping);
609 mapping = NULL;
612 if ((vals = ldap_get_values(ld, e, attr)) != NULL) {
614 if ((ap[j]->value_count =
615 ldap_count_values(vals)) == 0) {
616 ldap_value_free(vals);
617 vals = NULL;
618 continue;
619 } else {
620 ap[j]->attrvalue = (char **)
621 calloc(ap[j]->value_count+1,
622 sizeof (char *));
623 if (ap[j]->attrvalue == NULL) {
624 ber_free(ber, 0);
625 ber = NULL;
626 __ns_ldap_freeEntry(ep);
627 ep = NULL;
628 if (gecos_mapping)
629 __s_api_free2dArray(
630 gecos_mapping);
631 gecos_mapping = NULL;
632 return (NS_LDAP_MEMORY);
636 /* map object classes if necessary */
637 if ((flags & NS_LDAP_NOMAP) == 0 &&
638 schema_mapping_existed && ap[j]->attrname &&
639 strcasecmp(ap[j]->attrname, "objectclass") == 0) {
640 for (k = 0; k < ap[j]->value_count; k++) {
641 mapping =
642 __ns_ldap_getOrigObjectClass(
643 service, vals[k]);
645 if (mapping == NULL && auto_service)
647 * if service == auto_* and no
648 * schema mapping found
649 * then try automount
651 mapping =
652 __ns_ldap_getOrigObjectClass(
653 "automount", vals[k]);
655 if (mapping == NULL) {
656 ap[j]->attrvalue[k] =
657 strdup(vals[k]);
658 } else {
659 ap[j]->attrvalue[k] =
660 strdup(mapping[0]);
661 __s_api_free2dArray(mapping);
662 mapping = NULL;
664 if (ap[j]->attrvalue[k] == NULL) {
665 ber_free(ber, 0);
666 ber = NULL;
667 __ns_ldap_freeEntry(ep);
668 ep = NULL;
669 if (gecos_mapping)
670 __s_api_free2dArray(
671 gecos_mapping);
672 gecos_mapping = NULL;
673 return (NS_LDAP_MEMORY);
676 } else {
677 for (k = 0; k < ap[j]->value_count; k++) {
678 if ((ap[j]->attrvalue[k] =
679 strdup(vals[k])) == NULL) {
680 ber_free(ber, 0);
681 ber = NULL;
682 __ns_ldap_freeEntry(ep);
683 ep = NULL;
684 if (gecos_mapping)
685 __s_api_free2dArray(
686 gecos_mapping);
687 gecos_mapping = NULL;
688 return (NS_LDAP_MEMORY);
693 ap[j]->attrvalue[k] = NULL;
694 ldap_value_free(vals);
695 vals = NULL;
698 ldap_memfree(attr);
699 attr = NULL;
702 ber_free(ber, 0);
703 ber = NULL;
705 if (gecos_mapping) {
706 __s_api_free2dArray(gecos_mapping);
707 gecos_mapping = NULL;
710 /* special processing for gecos 1 to up to 3 attribute mapping */
711 if (schema_mapping_existed && gecos_mapping_existed) {
713 int f = -1;
715 for (i = 0; i < 3; i++) {
716 k = gecos_val_index[i];
719 * f is the index of the first returned
720 * attribute which "gecos" attribute mapped to
722 if (k != -1 && f == -1)
723 f = k;
725 if (k != -1 && ap[k]->value_count > 0 &&
726 ap[k]->attrvalue[0] &&
727 strlen(ap[k]->attrvalue[0]) > 0) {
729 if (k == f) {
731 * Create and fill in the last reserved
732 * ap with the data from the "gecos"
733 * mapping attributes
735 ap[nAttrs] = (ns_ldap_attr_t *)
736 calloc(1,
737 sizeof (ns_ldap_attr_t));
738 if (ap[nAttrs] == NULL) {
739 __ns_ldap_freeEntry(ep);
740 ep = NULL;
741 return (NS_LDAP_MEMORY);
743 ap[nAttrs]->attrvalue = (char **)calloc(
744 2, sizeof (char *));
745 if (ap[nAttrs]->attrvalue == NULL) {
746 __ns_ldap_freeEntry(ep);
747 ep = NULL;
748 return (NS_LDAP_MEMORY);
750 /* add 1 more for a possible "," */
751 ap[nAttrs]->attrvalue[0] =
752 (char *)calloc(
753 strlen(ap[f]->attrvalue[0]) +
754 2, 1);
755 if (ap[nAttrs]->attrvalue[0] == NULL) {
756 __ns_ldap_freeEntry(ep);
757 ep = NULL;
758 return (NS_LDAP_MEMORY);
760 (void) strcpy(ap[nAttrs]->attrvalue[0],
761 ap[f]->attrvalue[0]);
763 ap[nAttrs]->attrname = strdup("gecos");
764 if (ap[nAttrs]->attrname == NULL) {
765 __ns_ldap_freeEntry(ep);
766 ep = NULL;
767 return (NS_LDAP_MEMORY);
770 ap[nAttrs]->value_count = 1;
771 ep->attr_count = nAttrs + 1;
773 } else {
774 char *tmp = NULL;
777 * realloc to add "," and
778 * ap[k]->attrvalue[0]
780 tmp = (char *)realloc(
781 ap[nAttrs]->attrvalue[0],
782 strlen(ap[nAttrs]->
783 attrvalue[0]) +
784 strlen(ap[k]->
785 attrvalue[0]) + 2);
786 if (tmp == NULL) {
787 __ns_ldap_freeEntry(ep);
788 ep = NULL;
789 return (NS_LDAP_MEMORY);
791 ap[nAttrs]->attrvalue[0] = tmp;
792 (void) strcat(ap[nAttrs]->attrvalue[0],
793 ",");
794 (void) strcat(ap[nAttrs]->attrvalue[0],
795 ap[k]->attrvalue[0]);
801 *ret = ep;
802 return (NS_LDAP_SUCCESS);
805 static int
806 __s_api_getEntry(ns_ldap_cookie_t *cookie)
808 ns_ldap_entry_t *curEntry = NULL;
809 int ret;
811 #ifdef DEBUG
812 (void) fprintf(stderr, "__s_api_getEntry START\n");
813 #endif
815 if (cookie->resultMsg == NULL) {
816 return (NS_LDAP_INVALID_PARAM);
818 ret = __s_api_cvtEntry(cookie->conn->ld, cookie->service,
819 cookie->resultMsg, cookie->i_flags,
820 &curEntry, &cookie->errorp);
821 if (ret != NS_LDAP_SUCCESS) {
822 return (ret);
825 if (cookie->result == NULL) {
826 cookie->result = (ns_ldap_result_t *)
827 calloc(1, sizeof (ns_ldap_result_t));
828 if (cookie->result == NULL) {
829 __ns_ldap_freeEntry(curEntry);
830 curEntry = NULL;
831 return (NS_LDAP_MEMORY);
833 cookie->result->entry = curEntry;
834 cookie->nextEntry = curEntry;
835 } else {
836 cookie->nextEntry->next = curEntry;
837 cookie->nextEntry = curEntry;
839 cookie->result->entries_count++;
841 return (NS_LDAP_SUCCESS);
844 static int
845 __s_api_get_cachemgr_data(const char *type,
846 const char *from, char **to)
848 union {
849 ldap_data_t s_d;
850 char s_b[DOORBUFFERSIZE];
851 } space;
852 ldap_data_t *sptr;
853 int ndata;
854 int adata;
855 int rc;
857 #ifdef DEBUG
858 (void) fprintf(stderr, "__s_api_get_cachemgr_data START\n");
859 #endif
861 * We are not going to perform DN to domain mapping
862 * in the Standalone mode
864 if (__s_api_isStandalone()) {
865 return (-1);
868 if (from == NULL || from[0] == '\0' || to == NULL)
869 return (-1);
871 *to = NULL;
872 (void) memset(space.s_b, 0, DOORBUFFERSIZE);
874 space.s_d.ldap_call.ldap_callnumber = GETCACHE;
875 (void) snprintf(space.s_d.ldap_call.ldap_u.domainname,
876 DOORBUFFERSIZE - sizeof (space.s_d.ldap_call.ldap_callnumber),
877 "%s%s%s",
878 type,
879 DOORLINESEP,
880 from);
881 ndata = sizeof (space);
882 adata = sizeof (ldap_call_t) +
883 strlen(space.s_d.ldap_call.ldap_u.domainname) + 1;
884 sptr = &space.s_d;
886 rc = __ns_ldap_trydoorcall(&sptr, &ndata, &adata);
887 if (rc != NS_CACHE_SUCCESS)
888 return (-1);
889 else
890 *to = strdup(sptr->ldap_ret.ldap_u.buff);
891 return (NS_LDAP_SUCCESS);
894 static int
895 __s_api_set_cachemgr_data(const char *type,
896 const char *from, const char *to)
898 union {
899 ldap_data_t s_d;
900 char s_b[DOORBUFFERSIZE];
901 } space;
902 ldap_data_t *sptr;
903 int ndata;
904 int adata;
905 int rc;
907 #ifdef DEBUG
908 (void) fprintf(stderr, "__s_api_set_cachemgr_data START\n");
909 #endif
911 * We are not going to perform DN to domain mapping
912 * in the Standalone mode
914 if (__s_api_isStandalone()) {
915 return (-1);
918 if ((from == NULL) || (from[0] == '\0') ||
919 (to == NULL) || (to[0] == '\0'))
920 return (-1);
922 (void) memset(space.s_b, 0, DOORBUFFERSIZE);
924 space.s_d.ldap_call.ldap_callnumber = SETCACHE;
925 (void) snprintf(space.s_d.ldap_call.ldap_u.domainname,
926 DOORBUFFERSIZE - sizeof (space.s_d.ldap_call.ldap_callnumber),
927 "%s%s%s%s%s",
928 type,
929 DOORLINESEP,
930 from,
931 DOORLINESEP,
932 to);
934 ndata = sizeof (space);
935 adata = sizeof (ldap_call_t) +
936 strlen(space.s_d.ldap_call.ldap_u.domainname) + 1;
937 sptr = &space.s_d;
939 rc = __ns_ldap_trydoorcall(&sptr, &ndata, &adata);
940 if (rc != NS_CACHE_SUCCESS)
941 return (-1);
943 return (NS_LDAP_SUCCESS);
947 static char *
948 __s_api_remove_rdn_space(char *rdn)
950 char *tf, *tl, *vf, *vl, *eqsign;
952 /* if no space(s) to remove, return */
953 if (strchr(rdn, SPACETOK) == NULL)
954 return (rdn);
956 /* if no '=' separator, return */
957 eqsign = strchr(rdn, '=');
958 if (eqsign == NULL)
959 return (rdn);
961 tf = rdn;
962 tl = eqsign - 1;
963 vf = eqsign + 1;
964 vl = rdn + strlen(rdn) - 1;
966 /* now two strings, type and value */
967 *eqsign = '\0';
969 /* remove type's leading spaces */
970 while (tf < tl && *tf == SPACETOK)
971 tf++;
972 /* remove type's trailing spaces */
973 while (tf < tl && *tl == SPACETOK)
974 tl--;
975 /* add '=' separator back */
976 *(++tl) = '=';
977 /* remove value's leading spaces */
978 while (vf < vl && *vf == SPACETOK)
979 vf++;
980 /* remove value's trailing spaces */
981 while (vf < vl && *vl == SPACETOK)
982 *vl-- = '\0';
984 /* move value up if necessary */
985 if (vf != tl + 1)
986 (void) strcpy(tl + 1, vf);
988 return (tf);
991 static
992 ns_ldap_cookie_t *
993 init_search_state_machine()
995 ns_ldap_cookie_t *cookie;
996 ns_config_t *cfg;
998 cookie = (ns_ldap_cookie_t *)calloc(1, sizeof (ns_ldap_cookie_t));
999 if (cookie == NULL)
1000 return (NULL);
1001 cookie->state = INIT;
1002 /* assign other state variables */
1003 cfg = __s_api_loadrefresh_config();
1004 cookie->connectionId = -1;
1005 if (cfg == NULL ||
1006 cfg->paramList[NS_LDAP_SEARCH_TIME_P].ns_ptype == NS_UNKNOWN) {
1007 cookie->search_timeout.tv_sec = NS_DEFAULT_SEARCH_TIMEOUT;
1008 } else {
1009 cookie->search_timeout.tv_sec =
1010 cfg->paramList[NS_LDAP_SEARCH_TIME_P].ns_i;
1012 if (cfg != NULL)
1013 __s_api_release_config(cfg);
1014 cookie->search_timeout.tv_usec = 0;
1016 return (cookie);
1019 static void
1020 delete_search_cookie(ns_ldap_cookie_t *cookie)
1022 if (cookie == NULL)
1023 return;
1024 if (cookie->connectionId > -1)
1025 DropConnection(cookie->connectionId, cookie->i_flags);
1026 free(cookie->filter);
1027 free(cookie->i_filter);
1028 free(cookie->service);
1029 if (cookie->sdlist)
1030 (void) __ns_ldap_freeSearchDescriptors(&(cookie->sdlist));
1031 if (cookie->result)
1032 (void) __ns_ldap_freeResult(&cookie->result);
1033 if (cookie->attribute)
1034 __s_api_free2dArray(cookie->attribute);
1035 if (cookie->errorp)
1036 (void) __ns_ldap_freeError(&cookie->errorp);
1037 if (cookie->reflist)
1038 __s_api_deleteRefInfo(cookie->reflist);
1039 free(cookie->basedn);
1040 if (cookie->ctrlCookie)
1041 ber_bvfree(cookie->ctrlCookie);
1042 _freeControlList(&cookie->p_serverctrls);
1043 if (cookie->resultctrl)
1044 ldap_controls_free(cookie->resultctrl);
1045 free(cookie);
1048 static int
1049 get_mapped_filter(ns_ldap_cookie_t *cookie, char **new_filter)
1052 typedef struct filter_mapping_info {
1053 char oc_or_attr;
1054 char *name_start;
1055 char *name_end;
1056 char *veq_pos;
1057 char *from_name;
1058 char *to_name;
1059 char **mapping;
1060 } filter_mapping_info_t;
1062 char *c, *last_copied;
1063 char *filter_c, *filter_c_next;
1064 char *key, *tail, *head;
1065 char errstr[MAXERROR];
1066 int num_eq = 0, num_veq = 0;
1067 int in_quote = FALSE;
1068 int is_value = FALSE;
1069 int i, j, oc_len, len;
1070 int at_least_one = FALSE;
1071 filter_mapping_info_t **info, *info1;
1072 char **mapping;
1073 char *service, *filter, *err;
1074 int auto_service = FALSE;
1076 if (cookie == NULL || new_filter == NULL)
1077 return (NS_LDAP_INVALID_PARAM);
1079 *new_filter = NULL;
1080 service = cookie->service;
1081 filter = cookie->filter;
1084 * count the number of '=' char
1086 for (c = filter; *c; c++) {
1087 if (*c == TOKENSEPARATOR)
1088 num_eq++;
1091 if (service != NULL && strncasecmp(service, "auto_", 5) == 0)
1092 auto_service = TRUE;
1095 * See if schema mapping existed for the given service.
1096 * If not, just return success.
1098 mapping = __ns_ldap_getOrigAttribute(service,
1099 NS_HASH_SCHEMA_MAPPING_EXISTED);
1101 if (mapping == NULL && auto_service)
1103 * if service == auto_* and no
1104 * schema mapping found
1105 * then try automount
1107 mapping = __ns_ldap_getOrigAttribute(
1108 "automount", NS_HASH_SCHEMA_MAPPING_EXISTED);
1110 if (mapping)
1111 __s_api_free2dArray(mapping);
1112 else
1113 return (NS_LDAP_SUCCESS);
1116 * no '=' sign, just say OK and return nothing
1118 if (num_eq == 0)
1119 return (NS_LDAP_SUCCESS);
1122 * Make a copy of the filter string
1123 * for saving the name of the objectclasses or
1124 * attributes that need to be passed to the
1125 * objectclass or attribute mapping functions.
1126 * pointer "info->from_name" points to the locations
1127 * within this string.
1129 * The input filter string, filter, will be used
1130 * to indicate where these names start and end.
1131 * pointers "info->name_start" and "info->name_end"
1132 * point to locations within the input filter string,
1133 * and are used at the end of this function to
1134 * merge the original filter data with the
1135 * mapped objectclass or attribute names.
1137 filter_c = strdup(filter);
1138 if (filter_c == NULL)
1139 return (NS_LDAP_MEMORY);
1140 filter_c_next = filter_c;
1143 * get memory for info arrays
1145 info = (filter_mapping_info_t **)calloc(num_eq + 1,
1146 sizeof (filter_mapping_info_t *));
1148 if (info == NULL) {
1149 free(filter_c);
1150 return (NS_LDAP_MEMORY);
1154 * find valid '=' for further processing,
1155 * ignore the "escaped =" (.i.e. "\="), or
1156 * "=" in quoted string
1158 for (c = filter_c; *c; c++) {
1160 switch (*c) {
1161 case TOKENSEPARATOR:
1162 if (!in_quote && !is_value) {
1163 info1 = (filter_mapping_info_t *)calloc(1,
1164 sizeof (filter_mapping_info_t));
1165 if (!info1) {
1166 free(filter_c);
1167 for (i = 0; i < num_veq; i++)
1168 free(info[i]);
1169 free(info);
1170 return (NS_LDAP_MEMORY);
1172 info[num_veq] = info1;
1175 * remember the location of this "="
1177 info[num_veq++]->veq_pos = c;
1180 * skip until the end of the attribute value
1182 is_value = TRUE;
1184 break;
1185 case CPARATOK:
1187 * mark the end of the attribute value
1189 if (!in_quote)
1190 is_value = FALSE;
1191 break;
1192 case QUOTETOK:
1194 * switch on/off the in_quote mode
1196 in_quote = (in_quote == FALSE);
1197 break;
1198 case '\\':
1200 * ignore escape characters
1201 * don't skip if next char is '\0'
1203 if (!in_quote)
1204 if (*(++c) == '\0')
1205 c--;
1206 break;
1212 * for each valid "=" found, get the name to
1213 * be mapped
1215 oc_len = strlen("objectclass");
1216 for (i = 0; i < num_veq; i++) {
1219 * look at the left side of "=" to see
1220 * if assertion is "objectclass=<ocname>"
1221 * or "<attribute name>=<attribute value>"
1223 * first skip spaces before "=".
1224 * Note that filter_c_next may not point to the
1225 * start of the filter string. For i > 0,
1226 * it points to the end of the last name processed + 2
1228 for (tail = info[i]->veq_pos; (tail > filter_c_next) &&
1229 (*(tail - 1) == SPACETOK); tail--)
1233 * mark the end of the left side string (the key)
1235 *tail = '\0';
1236 info[i]->name_end = tail - filter_c - 1 + filter;
1239 * find the start of the key
1241 key = filter_c_next;
1242 for (c = tail; filter_c_next <= c; c--) {
1243 /* OPARATOK is '(' */
1244 if (*c == OPARATOK ||
1245 *c == SPACETOK) {
1246 key = c + 1;
1247 break;
1250 info[i]->name_start = key - filter_c + filter;
1252 if ((key + oc_len) <= tail) {
1253 if (strncasecmp(key, "objectclass",
1254 oc_len) == 0) {
1256 * assertion is "objectclass=ocname",
1257 * ocname is the one needs to be mapped
1259 * skip spaces after "=" to find start
1260 * of the ocname
1262 head = info[i]->veq_pos;
1263 for (head = info[i]->veq_pos + 1;
1264 *head && *head == SPACETOK; head++)
1267 /* ignore empty ocname */
1268 if (!(*head))
1269 continue;
1271 info[i]->name_start = head - filter_c +
1272 filter;
1275 * now find the end of the ocname
1277 for (c = head; ; c++) {
1278 /* CPARATOK is ')' */
1279 if (*c == CPARATOK ||
1280 *c == '\0' ||
1281 *c == SPACETOK) {
1282 *c = '\0';
1283 info[i]->name_end =
1284 c - filter_c - 1 +
1285 filter;
1286 filter_c_next = c + 1;
1287 info[i]->oc_or_attr = 'o';
1288 info[i]->from_name = head;
1289 break;
1296 * assertion is not "objectclass=ocname",
1297 * assume assertion is "<key> = <value>",
1298 * <key> is the one needs to be mapped
1300 if (info[i]->from_name == NULL && strlen(key) > 0) {
1301 info[i]->oc_or_attr = 'a';
1302 info[i]->from_name = key;
1306 /* perform schema mapping */
1307 for (i = 0; i < num_veq; i++) {
1308 if (info[i]->from_name == NULL)
1309 continue;
1311 if (info[i]->oc_or_attr == 'a')
1312 info[i]->mapping =
1313 __ns_ldap_getMappedAttributes(service,
1314 info[i]->from_name);
1315 else
1316 info[i]->mapping =
1317 __ns_ldap_getMappedObjectClass(service,
1318 info[i]->from_name);
1320 if (info[i]->mapping == NULL && auto_service) {
1322 * If no mapped attribute/objectclass is found
1323 * and service == auto*
1324 * try to find automount's
1325 * mapped attribute/objectclass
1327 if (info[i]->oc_or_attr == 'a')
1328 info[i]->mapping =
1329 __ns_ldap_getMappedAttributes("automount",
1330 info[i]->from_name);
1331 else
1332 info[i]->mapping =
1333 __ns_ldap_getMappedObjectClass("automount",
1334 info[i]->from_name);
1337 if (info[i]->mapping == NULL ||
1338 info[i]->mapping[0] == NULL) {
1339 info[i]->to_name = NULL;
1340 } else if (info[i]->mapping[1] == NULL) {
1341 info[i]->to_name = info[i]->mapping[0];
1342 at_least_one = TRUE;
1343 } else {
1344 __s_api_free2dArray(info[i]->mapping);
1346 * multiple mapping
1347 * not allowed
1349 (void) sprintf(errstr,
1350 gettext(
1351 "Multiple attribute or objectclass "
1352 "mapping for '%s' in filter "
1353 "'%s' not allowed."),
1354 info[i]->from_name, filter);
1355 err = strdup(errstr);
1356 if (err)
1357 MKERROR(LOG_WARNING, cookie->errorp,
1358 NS_CONFIG_SYNTAX,
1359 err, 0);
1361 free(filter_c);
1362 for (j = 0; j < num_veq; j++) {
1363 if (info[j]->mapping)
1364 __s_api_free2dArray(
1365 info[j]->mapping);
1366 free(info[j]);
1368 free(info);
1369 return (NS_LDAP_CONFIG);
1374 if (at_least_one) {
1376 len = strlen(filter);
1377 last_copied = filter - 1;
1379 for (i = 0; i < num_veq; i++) {
1380 if (info[i]->to_name)
1381 len += strlen(info[i]->to_name);
1384 *new_filter = (char *)calloc(1, len);
1385 if (*new_filter == NULL) {
1386 free(filter_c);
1387 for (j = 0; j < num_veq; j++) {
1388 if (info[j]->mapping)
1389 __s_api_free2dArray(
1390 info[j]->mapping);
1391 free(info[j]);
1393 free(info);
1394 return (NS_LDAP_MEMORY);
1397 for (i = 0; i < num_veq; i++) {
1398 if (info[i]->to_name != NULL &&
1399 info[i]->to_name != NULL) {
1402 * copy the original filter data
1403 * between the last name and current
1404 * name
1406 if ((last_copied + 1) != info[i]->name_start)
1407 (void) strncat(*new_filter,
1408 last_copied + 1,
1409 info[i]->name_start -
1410 last_copied - 1);
1412 /* the data is copied */
1413 last_copied = info[i]->name_end;
1416 * replace the name with
1417 * the mapped name
1419 (void) strcat(*new_filter, info[i]->to_name);
1422 /* copy the filter data after the last name */
1423 if (i == (num_veq -1) &&
1424 info[i]->name_end <
1425 (filter + strlen(filter)))
1426 (void) strncat(*new_filter, last_copied + 1,
1427 filter + strlen(filter) -
1428 last_copied - 1);
1433 /* free memory */
1434 free(filter_c);
1435 for (j = 0; j < num_veq; j++) {
1436 if (info[j]->mapping)
1437 __s_api_free2dArray(info[j]->mapping);
1438 free(info[j]);
1440 free(info);
1442 return (NS_LDAP_SUCCESS);
1445 static int
1446 setup_next_search(ns_ldap_cookie_t *cookie)
1448 ns_ldap_search_desc_t *dptr;
1449 int scope;
1450 char *filter, *str;
1451 int baselen;
1452 int rc;
1453 void **param;
1455 dptr = *cookie->sdpos;
1456 scope = cookie->i_flags & (NS_LDAP_SCOPE_BASE |
1457 NS_LDAP_SCOPE_ONELEVEL |
1458 NS_LDAP_SCOPE_SUBTREE);
1459 if (scope)
1460 cookie->scope = scope;
1461 else
1462 cookie->scope = dptr->scope;
1463 switch (cookie->scope) {
1464 case NS_LDAP_SCOPE_BASE:
1465 cookie->scope = LDAP_SCOPE_BASE;
1466 break;
1467 case NS_LDAP_SCOPE_ONELEVEL:
1468 cookie->scope = LDAP_SCOPE_ONELEVEL;
1469 break;
1470 case NS_LDAP_SCOPE_SUBTREE:
1471 cookie->scope = LDAP_SCOPE_SUBTREE;
1472 break;
1475 filter = NULL;
1476 if (cookie->use_filtercb && cookie->init_filter_cb &&
1477 dptr->filter && strlen(dptr->filter) > 0) {
1478 (*cookie->init_filter_cb)(dptr, &filter,
1479 cookie->userdata);
1481 if (filter == NULL) {
1482 if (cookie->i_filter == NULL) {
1483 cookie->err_rc = NS_LDAP_INVALID_PARAM;
1484 return (-1);
1485 } else {
1486 free(cookie->filter);
1487 cookie->filter = strdup(cookie->i_filter);
1488 if (cookie->filter == NULL) {
1489 cookie->err_rc = NS_LDAP_MEMORY;
1490 return (-1);
1493 } else {
1494 free(cookie->filter);
1495 cookie->filter = strdup(filter);
1496 free(filter);
1497 if (cookie->filter == NULL) {
1498 cookie->err_rc = NS_LDAP_MEMORY;
1499 return (-1);
1504 * perform attribute/objectclass mapping on filter
1506 filter = NULL;
1508 if (cookie->service) {
1509 rc = get_mapped_filter(cookie, &filter);
1510 if (rc != NS_LDAP_SUCCESS) {
1511 cookie->err_rc = rc;
1512 return (-1);
1513 } else {
1515 * get_mapped_filter returns
1516 * NULL filter pointer, if
1517 * no mapping was done
1519 if (filter) {
1520 free(cookie->filter);
1521 cookie->filter = filter;
1527 * validate filter to make sure it's legal
1528 * [remove redundant ()'s]
1530 rc = validate_filter(cookie);
1531 if (rc != NS_LDAP_SUCCESS) {
1532 cookie->err_rc = rc;
1533 return (-1);
1536 baselen = strlen(dptr->basedn);
1537 if (baselen > 0 && dptr->basedn[baselen-1] == COMMATOK) {
1538 rc = __ns_ldap_getParam(NS_LDAP_SEARCH_BASEDN_P,
1539 (void ***)&param, &cookie->errorp);
1540 if (rc != NS_LDAP_SUCCESS) {
1541 cookie->err_rc = rc;
1542 return (-1);
1544 str = ((char **)param)[0];
1545 baselen += strlen(str)+1;
1546 free(cookie->basedn);
1547 cookie->basedn = (char *)malloc(baselen);
1548 if (cookie->basedn == NULL) {
1549 cookie->err_rc = NS_LDAP_MEMORY;
1550 return (-1);
1552 (void) strcpy(cookie->basedn, dptr->basedn);
1553 (void) strcat(cookie->basedn, str);
1554 (void) __ns_ldap_freeParam(&param);
1555 } else {
1556 free(cookie->basedn);
1557 cookie->basedn = strdup(dptr->basedn);
1559 return (0);
1562 static int
1563 setup_referral_search(ns_ldap_cookie_t *cookie)
1565 ns_referral_info_t *ref;
1567 ref = cookie->refpos;
1568 cookie->scope = ref->refScope;
1569 if (cookie->filter) {
1570 free(cookie->filter);
1572 cookie->filter = strdup(ref->refFilter);
1573 if (cookie->basedn) {
1574 free(cookie->basedn);
1576 cookie->basedn = strdup(ref->refDN);
1577 if (cookie->filter == NULL || cookie->basedn == NULL) {
1578 cookie->err_rc = NS_LDAP_MEMORY;
1579 return (-1);
1581 return (0);
1584 static int
1585 get_current_session(ns_ldap_cookie_t *cookie)
1587 ConnectionID connectionId = -1;
1588 Connection *conp = NULL;
1589 int rc;
1590 int fail_if_new_pwd_reqd = 1;
1592 rc = __s_api_getConnection(NULL, cookie->i_flags,
1593 cookie->i_auth, &connectionId, &conp,
1594 &cookie->errorp, fail_if_new_pwd_reqd,
1595 cookie->nopasswd_acct_mgmt, cookie->conn_user);
1598 * If password control attached in *cookie->errorp,
1599 * e.g. rc == NS_LDAP_SUCCESS_WITH_INFO,
1600 * free the error structure (we do not need
1601 * the sec_to_expired info).
1602 * Reset rc to NS_LDAP_SUCCESS.
1604 if (rc == NS_LDAP_SUCCESS_WITH_INFO) {
1605 (void) __ns_ldap_freeError(
1606 &cookie->errorp);
1607 cookie->errorp = NULL;
1608 rc = NS_LDAP_SUCCESS;
1611 if (rc != NS_LDAP_SUCCESS) {
1612 cookie->err_rc = rc;
1613 return (-1);
1615 cookie->conn = conp;
1616 cookie->connectionId = connectionId;
1618 return (0);
1621 static int
1622 get_next_session(ns_ldap_cookie_t *cookie)
1624 ConnectionID connectionId = -1;
1625 Connection *conp = NULL;
1626 int rc;
1627 int fail_if_new_pwd_reqd = 1;
1629 if (cookie->connectionId > -1) {
1630 DropConnection(cookie->connectionId, cookie->i_flags);
1631 cookie->connectionId = -1;
1634 /* If using a MT connection, return it. */
1635 if (cookie->conn_user != NULL &&
1636 cookie->conn_user->conn_mt != NULL)
1637 __s_api_conn_mt_return(cookie->conn_user);
1639 rc = __s_api_getConnection(NULL, cookie->i_flags,
1640 cookie->i_auth, &connectionId, &conp,
1641 &cookie->errorp, fail_if_new_pwd_reqd,
1642 cookie->nopasswd_acct_mgmt, cookie->conn_user);
1645 * If password control attached in *cookie->errorp,
1646 * e.g. rc == NS_LDAP_SUCCESS_WITH_INFO,
1647 * free the error structure (we do not need
1648 * the sec_to_expired info).
1649 * Reset rc to NS_LDAP_SUCCESS.
1651 if (rc == NS_LDAP_SUCCESS_WITH_INFO) {
1652 (void) __ns_ldap_freeError(
1653 &cookie->errorp);
1654 cookie->errorp = NULL;
1655 rc = NS_LDAP_SUCCESS;
1658 if (rc != NS_LDAP_SUCCESS) {
1659 cookie->err_rc = rc;
1660 return (-1);
1662 cookie->conn = conp;
1663 cookie->connectionId = connectionId;
1664 return (0);
1667 static int
1668 get_referral_session(ns_ldap_cookie_t *cookie)
1670 ConnectionID connectionId = -1;
1671 Connection *conp = NULL;
1672 int rc;
1673 int fail_if_new_pwd_reqd = 1;
1675 if (cookie->connectionId > -1) {
1676 DropConnection(cookie->connectionId, cookie->i_flags);
1677 cookie->connectionId = -1;
1680 /* set it up to use a connection opened for referral */
1681 if (cookie->conn_user != NULL) {
1682 /* If using a MT connection, return it. */
1683 if (cookie->conn_user->conn_mt != NULL)
1684 __s_api_conn_mt_return(cookie->conn_user);
1685 cookie->conn_user->referral = B_TRUE;
1688 rc = __s_api_getConnection(cookie->refpos->refHost, 0,
1689 cookie->i_auth, &connectionId, &conp,
1690 &cookie->errorp, fail_if_new_pwd_reqd,
1691 cookie->nopasswd_acct_mgmt, cookie->conn_user);
1694 * If password control attached in *cookie->errorp,
1695 * e.g. rc == NS_LDAP_SUCCESS_WITH_INFO,
1696 * free the error structure (we do not need
1697 * the sec_to_expired info).
1698 * Reset rc to NS_LDAP_SUCCESS.
1700 if (rc == NS_LDAP_SUCCESS_WITH_INFO) {
1701 (void) __ns_ldap_freeError(
1702 &cookie->errorp);
1703 cookie->errorp = NULL;
1704 rc = NS_LDAP_SUCCESS;
1707 if (rc != NS_LDAP_SUCCESS) {
1708 cookie->err_rc = rc;
1709 return (-1);
1711 cookie->conn = conp;
1712 cookie->connectionId = connectionId;
1713 return (0);
1716 static int
1717 paging_supported(ns_ldap_cookie_t *cookie)
1719 int rc;
1721 cookie->listType = 0;
1722 rc = __s_api_isCtrlSupported(cookie->conn,
1723 LDAP_CONTROL_VLVREQUEST);
1724 if (rc == NS_LDAP_SUCCESS) {
1725 cookie->listType = VLVCTRLFLAG;
1726 return (1);
1728 rc = __s_api_isCtrlSupported(cookie->conn,
1729 LDAP_CONTROL_SIMPLE_PAGE);
1730 if (rc == NS_LDAP_SUCCESS) {
1731 cookie->listType = SIMPLEPAGECTRLFLAG;
1732 return (1);
1734 return (0);
1737 typedef struct servicesorttype {
1738 char *service;
1739 ns_srvsidesort_t type;
1740 } servicesorttype_t;
1742 static servicesorttype_t *sort_type = NULL;
1743 static int sort_type_size = 0;
1744 static int sort_type_hwm = 0;
1745 static mutex_t sort_type_mutex = DEFAULTMUTEX;
1748 static ns_srvsidesort_t
1749 get_srvsidesort_type(char *service)
1751 int i;
1752 ns_srvsidesort_t type = SSS_UNKNOWN;
1754 if (service == NULL)
1755 return (type);
1757 (void) mutex_lock(&sort_type_mutex);
1758 if (sort_type != NULL) {
1759 for (i = 0; i < sort_type_hwm; i++) {
1760 if (strcmp(sort_type[i].service, service) == 0) {
1761 type = sort_type[i].type;
1762 break;
1766 (void) mutex_unlock(&sort_type_mutex);
1767 return (type);
1770 static void
1771 update_srvsidesort_type(char *service, ns_srvsidesort_t type)
1773 int i, size;
1774 servicesorttype_t *tmp;
1776 if (service == NULL)
1777 return;
1779 (void) mutex_lock(&sort_type_mutex);
1781 for (i = 0; i < sort_type_hwm; i++) {
1782 if (strcmp(sort_type[i].service, service) == 0) {
1783 sort_type[i].type = type;
1784 (void) mutex_unlock(&sort_type_mutex);
1785 return;
1788 if (sort_type == NULL) {
1789 size = 10;
1790 tmp = malloc(size * sizeof (servicesorttype_t));
1791 if (tmp == NULL) {
1792 (void) mutex_unlock(&sort_type_mutex);
1793 return;
1795 sort_type = tmp;
1796 sort_type_size = size;
1797 } else if (sort_type_hwm >= sort_type_size) {
1798 size = sort_type_size + 10;
1799 tmp = reallocarray(sort_type, size, sizeof (servicesorttype_t));
1800 if (tmp == NULL) {
1801 (void) mutex_unlock(&sort_type_mutex);
1802 return;
1804 sort_type = tmp;
1805 sort_type_size = size;
1807 sort_type[sort_type_hwm].service = strdup(service);
1808 if (sort_type[sort_type_hwm].service == NULL) {
1809 (void) mutex_unlock(&sort_type_mutex);
1810 return;
1812 sort_type[sort_type_hwm].type = type;
1813 sort_type_hwm++;
1815 (void) mutex_unlock(&sort_type_mutex);
1818 static int
1819 setup_vlv_params(ns_ldap_cookie_t *cookie)
1821 LDAPControl **ctrls;
1822 LDAPsortkey **sortkeylist;
1823 LDAPControl *sortctrl = NULL;
1824 LDAPControl *vlvctrl = NULL;
1825 LDAPVirtualList vlist;
1826 char *sortattr;
1827 int rc;
1828 int free_sort = FALSE;
1830 _freeControlList(&cookie->p_serverctrls);
1832 if (cookie->sortTypeTry == SSS_UNKNOWN)
1833 cookie->sortTypeTry = get_srvsidesort_type(cookie->service);
1834 if (cookie->sortTypeTry == SSS_UNKNOWN)
1835 cookie->sortTypeTry = SSS_SINGLE_ATTR;
1837 if (cookie->sortTypeTry == SSS_SINGLE_ATTR) {
1838 if ((cookie->i_flags & NS_LDAP_NOMAP) == 0 &&
1839 cookie->i_sortattr) {
1840 sortattr = __ns_ldap_mapAttribute(cookie->service,
1841 cookie->i_sortattr);
1842 free_sort = TRUE;
1843 } else if (cookie->i_sortattr) {
1844 sortattr = (char *)cookie->i_sortattr;
1845 } else {
1846 sortattr = "cn";
1848 } else {
1849 sortattr = "cn uid";
1852 rc = ldap_create_sort_keylist(&sortkeylist, sortattr);
1853 if (free_sort)
1854 free(sortattr);
1855 if (rc != LDAP_SUCCESS) {
1856 (void) ldap_get_option(cookie->conn->ld,
1857 LDAP_OPT_ERROR_NUMBER, &rc);
1858 return (rc);
1860 rc = ldap_create_sort_control(cookie->conn->ld,
1861 sortkeylist, 1, &sortctrl);
1862 ldap_free_sort_keylist(sortkeylist);
1863 if (rc != LDAP_SUCCESS) {
1864 (void) ldap_get_option(cookie->conn->ld,
1865 LDAP_OPT_ERROR_NUMBER, &rc);
1866 return (rc);
1869 vlist.ldvlist_index = cookie->index;
1870 vlist.ldvlist_size = 0;
1872 vlist.ldvlist_before_count = 0;
1873 vlist.ldvlist_after_count = LISTPAGESIZE-1;
1874 vlist.ldvlist_attrvalue = NULL;
1875 vlist.ldvlist_extradata = NULL;
1877 rc = ldap_create_virtuallist_control(cookie->conn->ld,
1878 &vlist, &vlvctrl);
1879 if (rc != LDAP_SUCCESS) {
1880 ldap_control_free(sortctrl);
1881 (void) ldap_get_option(cookie->conn->ld, LDAP_OPT_ERROR_NUMBER,
1882 &rc);
1883 return (rc);
1886 ctrls = (LDAPControl **)calloc(3, sizeof (LDAPControl *));
1887 if (ctrls == NULL) {
1888 ldap_control_free(sortctrl);
1889 ldap_control_free(vlvctrl);
1890 return (LDAP_NO_MEMORY);
1893 ctrls[0] = sortctrl;
1894 ctrls[1] = vlvctrl;
1896 cookie->p_serverctrls = ctrls;
1897 return (LDAP_SUCCESS);
1900 static int
1901 setup_simplepg_params(ns_ldap_cookie_t *cookie)
1903 LDAPControl **ctrls;
1904 LDAPControl *pgctrl = NULL;
1905 int rc;
1907 _freeControlList(&cookie->p_serverctrls);
1909 rc = ldap_create_page_control(cookie->conn->ld, LISTPAGESIZE,
1910 cookie->ctrlCookie, '\0', &pgctrl);
1911 if (rc != LDAP_SUCCESS) {
1912 (void) ldap_get_option(cookie->conn->ld, LDAP_OPT_ERROR_NUMBER,
1913 &rc);
1914 return (rc);
1917 ctrls = (LDAPControl **)calloc(2, sizeof (LDAPControl *));
1918 if (ctrls == NULL) {
1919 ldap_control_free(pgctrl);
1920 return (LDAP_NO_MEMORY);
1922 ctrls[0] = pgctrl;
1923 cookie->p_serverctrls = ctrls;
1924 return (LDAP_SUCCESS);
1927 static void
1928 proc_result_referrals(ns_ldap_cookie_t *cookie)
1930 int errCode, i, rc;
1931 char **referrals = NULL;
1934 * Only follow one level of referrals, i.e.
1935 * if already in referral mode, do nothing
1937 if (cookie->refpos == NULL) {
1938 cookie->new_state = END_RESULT;
1939 rc = ldap_parse_result(cookie->conn->ld,
1940 cookie->resultMsg,
1941 &errCode, NULL,
1942 NULL, &referrals,
1943 NULL, 0);
1944 if (rc != NS_LDAP_SUCCESS) {
1945 (void) ldap_get_option(cookie->conn->ld,
1946 LDAP_OPT_ERROR_NUMBER,
1947 &cookie->err_rc);
1948 cookie->new_state = LDAP_ERROR;
1949 return;
1951 if (errCode == LDAP_REFERRAL) {
1952 for (i = 0; referrals[i] != NULL;
1953 i++) {
1954 /* add to referral list */
1955 rc = __s_api_addRefInfo(
1956 &cookie->reflist,
1957 referrals[i],
1958 cookie->basedn,
1959 &cookie->scope,
1960 cookie->filter,
1961 cookie->conn->ld);
1962 if (rc != NS_LDAP_SUCCESS) {
1963 cookie->new_state =
1964 ERROR;
1965 break;
1968 ldap_value_free(referrals);
1973 static void
1974 proc_search_references(ns_ldap_cookie_t *cookie)
1976 char **refurls = NULL;
1977 int i, rc;
1980 * Only follow one level of referrals, i.e.
1981 * if already in referral mode, do nothing
1983 if (cookie->refpos == NULL) {
1984 refurls = ldap_get_reference_urls(
1985 cookie->conn->ld,
1986 cookie->resultMsg);
1987 if (refurls == NULL) {
1988 (void) ldap_get_option(cookie->conn->ld,
1989 LDAP_OPT_ERROR_NUMBER,
1990 &cookie->err_rc);
1991 cookie->new_state = LDAP_ERROR;
1992 return;
1994 for (i = 0; refurls[i] != NULL; i++) {
1995 /* add to referral list */
1996 rc = __s_api_addRefInfo(
1997 &cookie->reflist,
1998 refurls[i],
1999 cookie->basedn,
2000 &cookie->scope,
2001 cookie->filter,
2002 cookie->conn->ld);
2003 if (rc != NS_LDAP_SUCCESS) {
2004 cookie->new_state =
2005 ERROR;
2006 break;
2009 /* free allocated storage */
2010 for (i = 0; refurls[i] != NULL; i++)
2011 free(refurls[i]);
2015 static ns_state_t
2016 multi_result(ns_ldap_cookie_t *cookie)
2018 char errstr[MAXERROR];
2019 char *err;
2020 ns_ldap_error_t **errorp = NULL;
2021 LDAPControl **retCtrls = NULL;
2022 int i, rc;
2023 int errCode;
2024 int finished = 0;
2025 unsigned long target_posp = 0;
2026 unsigned long list_size = 0;
2027 unsigned int count = 0;
2028 char **referrals = NULL;
2030 if (cookie->listType == VLVCTRLFLAG) {
2031 rc = ldap_parse_result(cookie->conn->ld, cookie->resultMsg,
2032 &errCode, NULL, NULL, &referrals, &retCtrls, 0);
2033 if (rc != LDAP_SUCCESS) {
2034 (void) ldap_get_option(cookie->conn->ld,
2035 LDAP_OPT_ERROR_NUMBER,
2036 &cookie->err_rc);
2037 (void) sprintf(errstr,
2038 gettext("LDAP ERROR (%d): %s.\n"),
2039 cookie->err_rc,
2040 gettext(ldap_err2string(cookie->err_rc)));
2041 err = strdup(errstr);
2042 MKERROR(LOG_WARNING, *errorp, NS_LDAP_INTERNAL, err,
2044 cookie->err_rc = NS_LDAP_INTERNAL;
2045 cookie->errorp = *errorp;
2046 return (LDAP_ERROR);
2048 if (errCode == LDAP_REFERRAL) {
2049 for (i = 0; referrals[i] != NULL;
2050 i++) {
2051 /* add to referral list */
2052 rc = __s_api_addRefInfo(
2053 &cookie->reflist,
2054 referrals[i],
2055 cookie->basedn,
2056 &cookie->scope,
2057 cookie->filter,
2058 cookie->conn->ld);
2059 if (rc != NS_LDAP_SUCCESS) {
2060 ldap_value_free(
2061 referrals);
2062 if (retCtrls)
2063 ldap_controls_free(
2064 retCtrls);
2065 return (ERROR);
2068 ldap_value_free(referrals);
2069 if (retCtrls)
2070 ldap_controls_free(retCtrls);
2071 return (END_RESULT);
2073 if (retCtrls) {
2074 rc = ldap_parse_virtuallist_control(
2075 cookie->conn->ld, retCtrls,
2076 &target_posp, &list_size, &errCode);
2077 if (rc == LDAP_SUCCESS) {
2079 * AD does not return valid target_posp
2080 * and list_size
2082 if (target_posp != 0 && list_size != 0) {
2083 cookie->index =
2084 target_posp + LISTPAGESIZE;
2085 if (cookie->index > list_size)
2086 finished = 1;
2087 } else {
2088 if (cookie->entryCount < LISTPAGESIZE)
2089 finished = 1;
2090 else
2091 cookie->index +=
2092 cookie->entryCount;
2095 ldap_controls_free(retCtrls);
2096 retCtrls = NULL;
2098 else
2099 finished = 1;
2100 } else if (cookie->listType == SIMPLEPAGECTRLFLAG) {
2101 rc = ldap_parse_result(cookie->conn->ld, cookie->resultMsg,
2102 &errCode, NULL, NULL, &referrals, &retCtrls, 0);
2103 if (rc != LDAP_SUCCESS) {
2104 (void) ldap_get_option(cookie->conn->ld,
2105 LDAP_OPT_ERROR_NUMBER,
2106 &cookie->err_rc);
2107 (void) sprintf(errstr,
2108 gettext("LDAP ERROR (%d): %s.\n"),
2109 cookie->err_rc,
2110 gettext(ldap_err2string(cookie->err_rc)));
2111 err = strdup(errstr);
2112 MKERROR(LOG_WARNING, *errorp, NS_LDAP_INTERNAL, err,
2114 cookie->err_rc = NS_LDAP_INTERNAL;
2115 cookie->errorp = *errorp;
2116 return (LDAP_ERROR);
2118 if (errCode == LDAP_REFERRAL) {
2119 for (i = 0; referrals[i] != NULL;
2120 i++) {
2121 /* add to referral list */
2122 rc = __s_api_addRefInfo(
2123 &cookie->reflist,
2124 referrals[i],
2125 cookie->basedn,
2126 &cookie->scope,
2127 cookie->filter,
2128 cookie->conn->ld);
2129 if (rc != NS_LDAP_SUCCESS) {
2130 ldap_value_free(
2131 referrals);
2132 if (retCtrls)
2133 ldap_controls_free(
2134 retCtrls);
2135 return (ERROR);
2138 ldap_value_free(referrals);
2139 if (retCtrls)
2140 ldap_controls_free(retCtrls);
2141 return (END_RESULT);
2143 if (retCtrls) {
2144 if (cookie->ctrlCookie)
2145 ber_bvfree(cookie->ctrlCookie);
2146 cookie->ctrlCookie = NULL;
2147 rc = ldap_parse_page_control(
2148 cookie->conn->ld, retCtrls,
2149 &count, &cookie->ctrlCookie);
2150 if (rc == LDAP_SUCCESS) {
2151 if ((cookie->ctrlCookie == NULL) ||
2152 (cookie->ctrlCookie->bv_val == NULL) ||
2153 (cookie->ctrlCookie->bv_len == 0))
2154 finished = 1;
2156 ldap_controls_free(retCtrls);
2157 retCtrls = NULL;
2159 else
2160 finished = 1;
2162 if (!finished && cookie->listType == VLVCTRLFLAG)
2163 return (NEXT_VLV);
2164 if (!finished && cookie->listType == SIMPLEPAGECTRLFLAG)
2165 return (NEXT_PAGE);
2166 if (finished)
2167 return (END_RESULT);
2168 return (ERROR);
2172 * clear_results(ns_ldap_cookie_t):
2174 * Attempt to obtain remnants of ldap responses and free them. If remnants are
2175 * not obtained within a certain time period tell the server we wish to abandon
2176 * the request.
2178 * Note that we do not initially tell the server to abandon the request as that
2179 * can be an expensive operation for the server, while it is cheap for us to
2180 * just flush the input.
2182 * If something was to remain in libldap queue as a result of some error then
2183 * it would be freed later during drop connection call or when no other
2184 * requests share the connection.
2186 static void
2187 clear_results(ns_ldap_cookie_t *cookie)
2189 int rc;
2190 if (cookie->conn != NULL && cookie->conn->ld != NULL &&
2191 (cookie->connectionId != -1 ||
2192 (cookie->conn_user != NULL &&
2193 cookie->conn_user->conn_mt != NULL)) &&
2194 cookie->msgId != 0) {
2196 * We need to cleanup the rest of response (if there is such)
2197 * and LDAP abandon is too heavy for LDAP servers, so we will
2198 * wait for the rest of response till timeout and "process" it.
2200 rc = ldap_result(cookie->conn->ld, cookie->msgId, LDAP_MSG_ALL,
2201 (struct timeval *)&cookie->search_timeout,
2202 &cookie->resultMsg);
2203 if (rc != -1 && rc != 0 && cookie->resultMsg != NULL) {
2204 (void) ldap_msgfree(cookie->resultMsg);
2205 cookie->resultMsg = NULL;
2209 * If there was timeout then we will send ABANDON request to
2210 * LDAP server to decrease load.
2212 if (rc == 0)
2213 (void) ldap_abandon_ext(cookie->conn->ld, cookie->msgId,
2214 NULL, NULL);
2215 /* Disassociate cookie with msgId */
2216 cookie->msgId = 0;
2221 * This state machine performs one or more LDAP searches to a given
2222 * directory server using service search descriptors and schema
2223 * mapping as appropriate. The approximate pseudocode for
2224 * this routine is the following:
2225 * Given the current configuration [set/reset connection etc.]
2226 * and the current service search descriptor list
2227 * or default search filter parameters
2228 * foreach (service search filter) {
2229 * initialize the filter [via filter_init if appropriate]
2230 * get a valid session/connection (preferably the current one)
2231 * Recover if the connection is lost
2232 * perform the search
2233 * foreach (result entry) {
2234 * process result [via callback if appropriate]
2235 * save result for caller if accepted.
2236 * exit and return all collected if allResults found;
2239 * return collected results and exit
2242 static
2243 ns_state_t
2244 search_state_machine(ns_ldap_cookie_t *cookie, ns_state_t state, int cycle)
2246 char errstr[MAXERROR];
2247 char *err;
2248 int rc, ret;
2249 int rc_save;
2250 ns_ldap_entry_t *nextEntry;
2251 ns_ldap_error_t *error = NULL;
2252 ns_ldap_error_t **errorp;
2253 struct timeval tv;
2255 errorp = &error;
2256 cookie->state = state;
2257 errstr[0] = '\0';
2259 for (;;) {
2260 switch (cookie->state) {
2261 case CLEAR_RESULTS:
2262 clear_results(cookie);
2263 cookie->new_state = EXIT;
2264 break;
2265 case GET_ACCT_MGMT_INFO:
2267 * Set the flag to get ldap account management controls.
2269 cookie->nopasswd_acct_mgmt = 1;
2270 cookie->new_state = INIT;
2271 break;
2272 case EXIT:
2273 /* state engine/connection cleaned up in delete */
2274 if (cookie->attribute) {
2275 __s_api_free2dArray(cookie->attribute);
2276 cookie->attribute = NULL;
2278 if (cookie->reflist) {
2279 __s_api_deleteRefInfo(cookie->reflist);
2280 cookie->reflist = NULL;
2282 return (EXIT);
2283 case INIT:
2284 cookie->sdpos = NULL;
2285 cookie->new_state = NEXT_SEARCH_DESCRIPTOR;
2286 if (cookie->attribute) {
2287 __s_api_free2dArray(cookie->attribute);
2288 cookie->attribute = NULL;
2290 if ((cookie->i_flags & NS_LDAP_NOMAP) == 0 &&
2291 cookie->i_attr) {
2292 cookie->attribute =
2293 __ns_ldap_mapAttributeList(
2294 cookie->service,
2295 cookie->i_attr);
2297 break;
2298 case REINIT:
2299 /* Check if we've reached MAX retries. */
2300 cookie->retries++;
2301 if (cookie->retries > NS_LIST_TRY_MAX - 1) {
2302 cookie->new_state = LDAP_ERROR;
2303 break;
2307 * Even if we still have retries left, check
2308 * if retry is possible.
2310 if (cookie->conn_user != NULL) {
2311 int retry;
2312 ns_conn_mgmt_t *cmg;
2313 cmg = cookie->conn_user->conn_mgmt;
2314 retry = cookie->conn_user->retry;
2315 if (cmg != NULL && cmg->cfg_reloaded == 1)
2316 retry = 1;
2317 if (retry == 0) {
2318 cookie->new_state = LDAP_ERROR;
2319 break;
2323 * Free results if any, reset to the first
2324 * search descriptor and start a new session.
2326 if (cookie->resultMsg != NULL) {
2327 (void) ldap_msgfree(cookie->resultMsg);
2328 cookie->resultMsg = NULL;
2330 (void) __ns_ldap_freeError(&cookie->errorp);
2331 (void) __ns_ldap_freeResult(&cookie->result);
2332 cookie->sdpos = cookie->sdlist;
2333 cookie->err_from_result = 0;
2334 cookie->err_rc = 0;
2335 cookie->new_state = NEXT_SESSION;
2336 break;
2337 case NEXT_SEARCH_DESCRIPTOR:
2338 /* get next search descriptor */
2339 if (cookie->sdpos == NULL) {
2340 cookie->sdpos = cookie->sdlist;
2341 cookie->new_state = GET_SESSION;
2342 } else {
2343 cookie->sdpos++;
2344 cookie->new_state = NEXT_SEARCH;
2346 if (*cookie->sdpos == NULL)
2347 cookie->new_state = EXIT;
2348 break;
2349 case GET_SESSION:
2350 if (get_current_session(cookie) < 0)
2351 cookie->new_state = NEXT_SESSION;
2352 else
2353 cookie->new_state = NEXT_SEARCH;
2354 break;
2355 case NEXT_SESSION:
2356 if (get_next_session(cookie) < 0)
2357 cookie->new_state = RESTART_SESSION;
2358 else
2359 cookie->new_state = NEXT_SEARCH;
2360 break;
2361 case RESTART_SESSION:
2362 if (cookie->i_flags & NS_LDAP_HARD) {
2363 cookie->new_state = NEXT_SESSION;
2364 break;
2366 (void) sprintf(errstr,
2367 gettext("Session error no available conn.\n"),
2368 state);
2369 err = strdup(errstr);
2370 MKERROR(LOG_WARNING, *errorp, NS_LDAP_INTERNAL, err,
2372 cookie->err_rc = NS_LDAP_INTERNAL;
2373 cookie->errorp = *errorp;
2374 cookie->new_state = EXIT;
2375 break;
2376 case NEXT_SEARCH:
2377 /* setup referrals search if necessary */
2378 if (cookie->refpos) {
2379 if (setup_referral_search(cookie) < 0) {
2380 cookie->new_state = EXIT;
2381 break;
2383 } else if (setup_next_search(cookie) < 0) {
2384 cookie->new_state = EXIT;
2385 break;
2387 /* only do VLV/PAGE on scopes onelevel/subtree */
2388 if (paging_supported(cookie)) {
2389 if (cookie->use_paging &&
2390 (cookie->scope != LDAP_SCOPE_BASE)) {
2391 cookie->index = 1;
2392 if (cookie->listType == VLVCTRLFLAG)
2393 cookie->new_state = NEXT_VLV;
2394 else
2395 cookie->new_state = NEXT_PAGE;
2396 break;
2399 cookie->new_state = ONE_SEARCH;
2400 break;
2401 case NEXT_VLV:
2402 rc = setup_vlv_params(cookie);
2403 if (rc != LDAP_SUCCESS) {
2404 cookie->err_rc = rc;
2405 cookie->new_state = LDAP_ERROR;
2406 break;
2408 cookie->next_state = MULTI_RESULT;
2409 cookie->new_state = DO_SEARCH;
2410 break;
2411 case NEXT_PAGE:
2412 rc = setup_simplepg_params(cookie);
2413 if (rc != LDAP_SUCCESS) {
2414 cookie->err_rc = rc;
2415 cookie->new_state = LDAP_ERROR;
2416 break;
2418 cookie->next_state = MULTI_RESULT;
2419 cookie->new_state = DO_SEARCH;
2420 break;
2421 case ONE_SEARCH:
2422 cookie->next_state = NEXT_RESULT;
2423 cookie->new_state = DO_SEARCH;
2424 break;
2425 case DO_SEARCH:
2426 cookie->entryCount = 0;
2427 rc = ldap_search_ext(cookie->conn->ld,
2428 cookie->basedn,
2429 cookie->scope,
2430 cookie->filter,
2431 cookie->attribute,
2433 cookie->p_serverctrls,
2434 NULL,
2435 &cookie->search_timeout, 0,
2436 &cookie->msgId);
2437 if (rc != LDAP_SUCCESS) {
2438 if (rc == LDAP_BUSY ||
2439 rc == LDAP_UNAVAILABLE ||
2440 rc == LDAP_UNWILLING_TO_PERFORM ||
2441 rc == LDAP_CONNECT_ERROR ||
2442 rc == LDAP_SERVER_DOWN) {
2444 if (cookie->reinit_on_retriable_err) {
2445 cookie->err_rc = rc;
2446 cookie->new_state = REINIT;
2447 } else
2448 cookie->new_state =
2449 NEXT_SESSION;
2452 * If not able to reach the
2453 * server, inform the ldap
2454 * cache manager that the
2455 * server should be removed
2456 * from it's server list.
2457 * Thus, the manager will not
2458 * return this server on the next
2459 * get-server request and will
2460 * also reduce the server list
2461 * refresh TTL, so that it will
2462 * find out sooner when the server
2463 * is up again.
2465 if ((rc == LDAP_CONNECT_ERROR ||
2466 rc == LDAP_SERVER_DOWN) &&
2467 (cookie->conn_user == NULL ||
2468 cookie->conn_user->conn_mt ==
2469 NULL)) {
2470 ret = __s_api_removeServer(
2471 cookie->conn->serverAddr);
2472 if (ret == NS_CACHE_NOSERVER &&
2473 cookie->conn_auth_type
2474 == NS_LDAP_AUTH_NONE) {
2476 * Couldn't remove
2477 * server from server
2478 * list.
2479 * Exit to avoid
2480 * potential infinite
2481 * loop.
2483 cookie->err_rc = rc;
2484 cookie->new_state =
2485 LDAP_ERROR;
2487 if (cookie->connectionId > -1) {
2489 * NS_LDAP_NEW_CONN
2490 * indicates that the
2491 * connection should
2492 * be deleted, not
2493 * kept alive
2495 DropConnection(
2496 cookie->
2497 connectionId,
2498 NS_LDAP_NEW_CONN);
2499 cookie->connectionId =
2502 } else if ((rc == LDAP_CONNECT_ERROR ||
2503 rc == LDAP_SERVER_DOWN) &&
2504 cookie->conn_user != NULL) {
2505 if (cookie->
2506 reinit_on_retriable_err) {
2508 * MT connection not
2509 * usable, close it
2510 * before REINIT.
2511 * rc has already
2512 * been saved in
2513 * cookie->err_rc above.
2515 __s_api_conn_mt_close(
2516 cookie->conn_user,
2518 &cookie->errorp);
2519 } else {
2521 * MT connection not
2522 * usable, close it in
2523 * the LDAP_ERROR state.
2524 * A retry will be done
2525 * next if allowed.
2527 cookie->err_rc = rc;
2528 cookie->new_state =
2529 LDAP_ERROR;
2532 break;
2534 cookie->err_rc = rc;
2535 cookie->new_state = LDAP_ERROR;
2536 break;
2538 cookie->new_state = cookie->next_state;
2539 break;
2540 case NEXT_RESULT:
2542 * Caller (e.g. __ns_ldap_list_batch_add)
2543 * does not want to block on ldap_result().
2544 * Therefore we execute ldap_result() with
2545 * a zeroed timeval.
2547 if (cookie->no_wait == B_TRUE)
2548 (void) memset(&tv, 0, sizeof (tv));
2549 else
2550 tv = cookie->search_timeout;
2551 rc = ldap_result(cookie->conn->ld, cookie->msgId,
2552 LDAP_MSG_ONE,
2553 &tv,
2554 &cookie->resultMsg);
2555 if (rc == LDAP_RES_SEARCH_RESULT) {
2556 cookie->new_state = END_RESULT;
2557 /* check and process referrals info */
2558 if (cookie->followRef)
2559 proc_result_referrals(
2560 cookie);
2561 (void) ldap_msgfree(cookie->resultMsg);
2562 cookie->resultMsg = NULL;
2563 break;
2565 /* handle referrals if necessary */
2566 if (rc == LDAP_RES_SEARCH_REFERENCE) {
2567 if (cookie->followRef)
2568 proc_search_references(cookie);
2569 (void) ldap_msgfree(cookie->resultMsg);
2570 cookie->resultMsg = NULL;
2571 break;
2573 if (rc != LDAP_RES_SEARCH_ENTRY) {
2574 switch (rc) {
2575 case 0:
2576 if (cookie->no_wait == B_TRUE) {
2577 (void) ldap_msgfree(
2578 cookie->resultMsg);
2579 cookie->resultMsg = NULL;
2580 return (cookie->new_state);
2582 rc = LDAP_TIMEOUT;
2583 break;
2584 case -1:
2585 rc = ldap_get_lderrno(cookie->conn->ld,
2586 NULL, NULL);
2587 break;
2588 default:
2589 rc = ldap_result2error(cookie->conn->ld,
2590 cookie->resultMsg, 1);
2591 break;
2593 if ((rc == LDAP_TIMEOUT ||
2594 rc == LDAP_SERVER_DOWN) &&
2595 (cookie->conn_user == NULL ||
2596 cookie->conn_user->conn_mt == NULL)) {
2597 if (rc == LDAP_TIMEOUT)
2598 (void) __s_api_removeServer(
2599 cookie->conn->serverAddr);
2600 if (cookie->connectionId > -1) {
2601 DropConnection(
2602 cookie->connectionId,
2603 NS_LDAP_NEW_CONN);
2604 cookie->connectionId = -1;
2606 cookie->err_from_result = 1;
2608 (void) ldap_msgfree(cookie->resultMsg);
2609 cookie->resultMsg = NULL;
2610 if (rc == LDAP_BUSY ||
2611 rc == LDAP_UNAVAILABLE ||
2612 rc == LDAP_UNWILLING_TO_PERFORM) {
2613 if (cookie->reinit_on_retriable_err) {
2614 cookie->err_rc = rc;
2615 cookie->err_from_result = 1;
2616 cookie->new_state = REINIT;
2617 } else
2618 cookie->new_state =
2619 NEXT_SESSION;
2620 break;
2622 if ((rc == LDAP_CONNECT_ERROR ||
2623 rc == LDAP_SERVER_DOWN) &&
2624 cookie->reinit_on_retriable_err) {
2625 ns_ldap_error_t *errorp = NULL;
2626 cookie->err_rc = rc;
2627 cookie->err_from_result = 1;
2628 cookie->new_state = REINIT;
2629 if (cookie->conn_user != NULL)
2630 __s_api_conn_mt_close(
2631 cookie->conn_user,
2632 rc, &errorp);
2633 if (errorp != NULL) {
2634 (void) __ns_ldap_freeError(
2635 &cookie->errorp);
2636 cookie->errorp = errorp;
2638 break;
2640 cookie->err_rc = rc;
2641 cookie->new_state = LDAP_ERROR;
2642 break;
2644 /* else LDAP_RES_SEARCH_ENTRY */
2645 /* get account management response control */
2646 if (cookie->nopasswd_acct_mgmt == 1) {
2647 rc = ldap_get_entry_controls(cookie->conn->ld,
2648 cookie->resultMsg,
2649 &(cookie->resultctrl));
2650 if (rc != LDAP_SUCCESS) {
2651 cookie->new_state = LDAP_ERROR;
2652 cookie->err_rc = rc;
2653 break;
2656 rc = __s_api_getEntry(cookie);
2657 (void) ldap_msgfree(cookie->resultMsg);
2658 cookie->resultMsg = NULL;
2659 if (rc != NS_LDAP_SUCCESS) {
2660 cookie->new_state = LDAP_ERROR;
2661 break;
2663 cookie->new_state = PROCESS_RESULT;
2664 cookie->next_state = NEXT_RESULT;
2665 break;
2666 case MULTI_RESULT:
2667 if (cookie->no_wait == B_TRUE)
2668 (void) memset(&tv, 0, sizeof (tv));
2669 else
2670 tv = cookie->search_timeout;
2671 rc = ldap_result(cookie->conn->ld, cookie->msgId,
2672 LDAP_MSG_ONE,
2673 &tv,
2674 &cookie->resultMsg);
2675 if (rc == LDAP_RES_SEARCH_RESULT) {
2676 rc = ldap_result2error(cookie->conn->ld,
2677 cookie->resultMsg, 0);
2678 if (rc == LDAP_ADMINLIMIT_EXCEEDED &&
2679 cookie->listType == VLVCTRLFLAG &&
2680 cookie->sortTypeTry == SSS_SINGLE_ATTR) {
2681 /* Try old "cn uid" server side sort */
2682 cookie->sortTypeTry = SSS_CN_UID_ATTRS;
2683 cookie->new_state = NEXT_VLV;
2684 (void) ldap_msgfree(cookie->resultMsg);
2685 cookie->resultMsg = NULL;
2686 break;
2688 if (rc != LDAP_SUCCESS) {
2689 cookie->err_rc = rc;
2690 cookie->new_state = LDAP_ERROR;
2691 (void) ldap_msgfree(cookie->resultMsg);
2692 cookie->resultMsg = NULL;
2693 break;
2695 cookie->new_state = multi_result(cookie);
2696 (void) ldap_msgfree(cookie->resultMsg);
2697 cookie->resultMsg = NULL;
2698 break;
2700 /* handle referrals if necessary */
2701 if (rc == LDAP_RES_SEARCH_REFERENCE &&
2702 cookie->followRef) {
2703 proc_search_references(cookie);
2704 (void) ldap_msgfree(cookie->resultMsg);
2705 cookie->resultMsg = NULL;
2706 break;
2708 if (rc != LDAP_RES_SEARCH_ENTRY) {
2709 switch (rc) {
2710 case 0:
2711 if (cookie->no_wait == B_TRUE) {
2712 (void) ldap_msgfree(
2713 cookie->resultMsg);
2714 cookie->resultMsg = NULL;
2715 return (cookie->new_state);
2717 rc = LDAP_TIMEOUT;
2718 break;
2719 case -1:
2720 rc = ldap_get_lderrno(cookie->conn->ld,
2721 NULL, NULL);
2722 break;
2723 default:
2724 rc = ldap_result2error(cookie->conn->ld,
2725 cookie->resultMsg, 1);
2726 break;
2728 if ((rc == LDAP_TIMEOUT ||
2729 rc == LDAP_SERVER_DOWN) &&
2730 (cookie->conn_user == NULL ||
2731 cookie->conn_user->conn_mt == NULL)) {
2732 if (rc == LDAP_TIMEOUT)
2733 (void) __s_api_removeServer(
2734 cookie->conn->serverAddr);
2735 if (cookie->connectionId > -1) {
2736 DropConnection(
2737 cookie->connectionId,
2738 NS_LDAP_NEW_CONN);
2739 cookie->connectionId = -1;
2741 cookie->err_from_result = 1;
2743 (void) ldap_msgfree(cookie->resultMsg);
2744 cookie->resultMsg = NULL;
2745 if (rc == LDAP_BUSY ||
2746 rc == LDAP_UNAVAILABLE ||
2747 rc == LDAP_UNWILLING_TO_PERFORM) {
2748 if (cookie->reinit_on_retriable_err) {
2749 cookie->err_rc = rc;
2750 cookie->err_from_result = 1;
2751 cookie->new_state = REINIT;
2752 } else
2753 cookie->new_state =
2754 NEXT_SESSION;
2755 break;
2758 if ((rc == LDAP_CONNECT_ERROR ||
2759 rc == LDAP_SERVER_DOWN) &&
2760 cookie->reinit_on_retriable_err) {
2761 ns_ldap_error_t *errorp = NULL;
2762 cookie->err_rc = rc;
2763 cookie->err_from_result = 1;
2764 cookie->new_state = REINIT;
2765 if (cookie->conn_user != NULL)
2766 __s_api_conn_mt_close(
2767 cookie->conn_user,
2768 rc, &errorp);
2769 if (errorp != NULL) {
2770 (void) __ns_ldap_freeError(
2771 &cookie->errorp);
2772 cookie->errorp = errorp;
2774 break;
2776 cookie->err_rc = rc;
2777 cookie->new_state = LDAP_ERROR;
2778 break;
2780 /* else LDAP_RES_SEARCH_ENTRY */
2781 cookie->entryCount++;
2782 rc = __s_api_getEntry(cookie);
2783 (void) ldap_msgfree(cookie->resultMsg);
2784 cookie->resultMsg = NULL;
2785 if (rc != NS_LDAP_SUCCESS) {
2786 cookie->new_state = LDAP_ERROR;
2787 break;
2790 * If VLV search was successfull save the server
2791 * side sort type tried.
2793 if (cookie->listType == VLVCTRLFLAG)
2794 update_srvsidesort_type(cookie->service,
2795 cookie->sortTypeTry);
2797 cookie->new_state = PROCESS_RESULT;
2798 cookie->next_state = MULTI_RESULT;
2799 break;
2800 case PROCESS_RESULT:
2801 /* NOTE THIS STATE MAY BE PROCESSED BY CALLER */
2802 if (cookie->use_usercb && cookie->callback) {
2803 rc = 0;
2804 for (nextEntry = cookie->result->entry;
2805 nextEntry != NULL;
2806 nextEntry = nextEntry->next) {
2807 rc = (*cookie->callback)(nextEntry,
2808 cookie->userdata);
2810 if (rc == NS_LDAP_CB_DONE) {
2811 /* cb doesn't want any more data */
2812 rc = NS_LDAP_PARTIAL;
2813 cookie->err_rc = rc;
2814 break;
2815 } else if (rc != NS_LDAP_CB_NEXT) {
2816 /* invalid return code */
2817 rc = NS_LDAP_OP_FAILED;
2818 cookie->err_rc = rc;
2819 break;
2822 (void) __ns_ldap_freeResult(&cookie->result);
2823 cookie->result = NULL;
2825 if (rc != 0) {
2826 cookie->new_state = EXIT;
2827 break;
2829 /* NOTE PREVIOUS STATE SPECIFIES NEXT STATE */
2830 cookie->new_state = cookie->next_state;
2831 break;
2832 case END_PROCESS_RESULT:
2833 cookie->new_state = cookie->next_state;
2834 break;
2835 case END_RESULT:
2837 * XXX DO WE NEED THIS CASE?
2838 * if (search is complete) {
2839 * cookie->new_state = EXIT;
2840 * } else
2843 * entering referral mode if necessary
2845 if (cookie->followRef && cookie->reflist)
2846 cookie->new_state =
2847 NEXT_REFERRAL;
2848 else
2849 cookie->new_state =
2850 NEXT_SEARCH_DESCRIPTOR;
2851 break;
2852 case NEXT_REFERRAL:
2853 /* get next referral info */
2854 if (cookie->refpos == NULL)
2855 cookie->refpos =
2856 cookie->reflist;
2857 else
2858 cookie->refpos =
2859 cookie->refpos->next;
2860 /* check see if done with all referrals */
2861 if (cookie->refpos != NULL)
2862 cookie->new_state =
2863 GET_REFERRAL_SESSION;
2864 else {
2865 __s_api_deleteRefInfo(cookie->reflist);
2866 cookie->reflist = NULL;
2867 cookie->new_state =
2868 NEXT_SEARCH_DESCRIPTOR;
2869 if (cookie->conn_user != NULL)
2870 cookie->conn_user->referral = B_FALSE;
2872 break;
2873 case GET_REFERRAL_SESSION:
2874 if (get_referral_session(cookie) < 0)
2875 cookie->new_state = EXIT;
2876 else {
2877 cookie->new_state = NEXT_SEARCH;
2879 break;
2880 case LDAP_ERROR:
2881 rc_save = cookie->err_rc;
2882 if (cookie->err_from_result) {
2883 if (cookie->err_rc == LDAP_SERVER_DOWN) {
2884 (void) sprintf(errstr,
2885 gettext("LDAP ERROR (%d): "
2886 "Error occurred during"
2887 " receiving results. "
2888 "Connection to server lost."),
2889 cookie->err_rc);
2890 } else if (cookie->err_rc == LDAP_TIMEOUT) {
2891 (void) sprintf(errstr,
2892 gettext("LDAP ERROR (%d): "
2893 "Error occurred during"
2894 " receiving results. %s"
2895 "."), cookie->err_rc,
2896 ldap_err2string(
2897 cookie->err_rc));
2899 } else
2900 (void) sprintf(errstr,
2901 gettext("LDAP ERROR (%d): %s."),
2902 cookie->err_rc,
2903 ldap_err2string(cookie->err_rc));
2904 err = strdup(errstr);
2905 if (cookie->err_from_result) {
2906 if (cookie->err_rc == LDAP_SERVER_DOWN) {
2907 MKERROR(LOG_INFO, *errorp,
2908 cookie->err_rc, err, 0);
2909 } else {
2910 MKERROR(LOG_WARNING, *errorp,
2911 cookie->err_rc, err, 0);
2913 } else {
2914 MKERROR(LOG_WARNING, *errorp, NS_LDAP_INTERNAL,
2915 err, 0);
2917 cookie->err_rc = NS_LDAP_INTERNAL;
2918 cookie->errorp = *errorp;
2919 if (cookie->conn_user != NULL) {
2920 if (rc_save == LDAP_SERVER_DOWN ||
2921 rc_save == LDAP_CONNECT_ERROR) {
2923 * MT connection is not usable,
2924 * close it.
2926 __s_api_conn_mt_close(cookie->conn_user,
2927 rc_save, &cookie->errorp);
2928 return (ERROR);
2931 return (ERROR);
2932 default:
2933 case ERROR:
2934 (void) sprintf(errstr,
2935 gettext("Internal State machine exit (%d).\n"),
2936 cookie->state);
2937 err = strdup(errstr);
2938 MKERROR(LOG_WARNING, *errorp, NS_LDAP_INTERNAL, err,
2940 cookie->err_rc = NS_LDAP_INTERNAL;
2941 cookie->errorp = *errorp;
2942 return (ERROR);
2945 if (cookie->conn_user != NULL &&
2946 cookie->conn_user->bad_mt_conn == B_TRUE) {
2947 __s_api_conn_mt_close(cookie->conn_user, 0, NULL);
2948 cookie->err_rc = cookie->conn_user->ns_rc;
2949 cookie->errorp = cookie->conn_user->ns_error;
2950 cookie->conn_user->ns_error = NULL;
2951 return (ERROR);
2954 if (cycle == ONE_STEP) {
2955 return (cookie->new_state);
2957 cookie->state = cookie->new_state;
2959 /*NOTREACHED*/
2960 #if 0
2961 (void) sprintf(errstr,
2962 gettext("Unexpected State machine error.\n"));
2963 err = strdup(errstr);
2964 MKERROR(LOG_WARNING, *errorp, NS_LDAP_INTERNAL, err, NULL);
2965 cookie->err_rc = NS_LDAP_INTERNAL;
2966 cookie->errorp = *errorp;
2967 return (ERROR);
2968 #endif
2972 * For a lookup of shadow data, if shadow update is enabled,
2973 * check the calling process' privilege to ensure it's
2974 * allowed to perform such operation.
2976 static int
2977 check_shadow(ns_ldap_cookie_t *cookie, const char *service)
2979 char errstr[MAXERROR];
2980 char *err;
2981 boolean_t priv;
2982 /* caller */
2983 priv_set_t *ps;
2984 /* zone */
2985 priv_set_t *zs;
2988 * If service is "shadow", we may need
2989 * to use privilege credentials.
2991 if ((strcmp(service, "shadow") == 0) &&
2992 __ns_ldap_is_shadow_update_enabled()) {
2994 * Since we release admin credentials after
2995 * connection is closed and we do not cache
2996 * them, we allow any root or all zone
2997 * privilege process to read shadow data.
2999 priv = (geteuid() == 0);
3000 if (!priv) {
3001 /* caller */
3002 ps = priv_allocset();
3004 (void) getppriv(PRIV_EFFECTIVE, ps);
3005 zs = priv_str_to_set("zone", ",", NULL);
3006 priv = priv_isequalset(ps, zs);
3007 priv_freeset(ps);
3008 priv_freeset(zs);
3010 if (!priv) {
3011 (void) sprintf(errstr,
3012 gettext("Permission denied"));
3013 err = strdup(errstr);
3014 if (err == NULL)
3015 return (NS_LDAP_MEMORY);
3016 MKERROR(LOG_INFO, cookie->errorp, NS_LDAP_INTERNAL, err,
3018 return (NS_LDAP_INTERNAL);
3020 cookie->i_flags |= NS_LDAP_READ_SHADOW;
3022 * We do not want to reuse connection (hence
3023 * keep it open) with admin credentials.
3024 * If NS_LDAP_KEEP_CONN is set, reject the
3025 * request.
3027 if (cookie->i_flags & NS_LDAP_KEEP_CONN)
3028 return (NS_LDAP_INVALID_PARAM);
3029 cookie->i_flags |= NS_LDAP_NEW_CONN;
3032 return (NS_LDAP_SUCCESS);
3036 * internal function for __ns_ldap_list
3038 static int
3039 ldap_list(
3040 ns_ldap_list_batch_t *batch,
3041 const char *service,
3042 const char *filter,
3043 const char *sortattr,
3044 int (*init_filter_cb)(const ns_ldap_search_desc_t *desc,
3045 char **realfilter, const void *userdata),
3046 const char * const *attribute,
3047 const ns_cred_t *auth,
3048 const int flags,
3049 ns_ldap_result_t **rResult, /* return result entries */
3050 ns_ldap_error_t **errorp,
3051 int *rcp,
3052 int (*callback)(const ns_ldap_entry_t *entry, const void *userdata),
3053 const void *userdata, ns_conn_user_t *conn_user)
3055 ns_ldap_cookie_t *cookie;
3056 ns_ldap_search_desc_t **sdlist = NULL;
3057 ns_ldap_search_desc_t *dptr;
3058 ns_ldap_error_t *error = NULL;
3059 char **dns = NULL;
3060 int scope;
3061 int rc;
3062 int from_result;
3064 *errorp = NULL;
3065 *rResult = NULL;
3066 *rcp = NS_LDAP_SUCCESS;
3069 * Sanity check - NS_LDAP_READ_SHADOW is for our
3070 * own internal use.
3072 if (flags & NS_LDAP_READ_SHADOW)
3073 return (NS_LDAP_INVALID_PARAM);
3075 /* Initialize State machine cookie */
3076 cookie = init_search_state_machine();
3077 if (cookie == NULL) {
3078 *rcp = NS_LDAP_MEMORY;
3079 return (NS_LDAP_MEMORY);
3081 cookie->conn_user = conn_user;
3083 /* see if need to follow referrals */
3084 rc = __s_api_toFollowReferrals(flags,
3085 &cookie->followRef, errorp);
3086 if (rc != NS_LDAP_SUCCESS) {
3087 delete_search_cookie(cookie);
3088 *rcp = rc;
3089 return (rc);
3092 /* get the service descriptor - or create a default one */
3093 rc = __s_api_get_SSD_from_SSDtoUse_service(service,
3094 &sdlist, &error);
3095 if (rc != NS_LDAP_SUCCESS) {
3096 delete_search_cookie(cookie);
3097 *errorp = error;
3098 *rcp = rc;
3099 return (rc);
3102 if (sdlist == NULL) {
3103 /* Create default service Desc */
3104 sdlist = (ns_ldap_search_desc_t **)calloc(2,
3105 sizeof (ns_ldap_search_desc_t *));
3106 if (sdlist == NULL) {
3107 delete_search_cookie(cookie);
3108 cookie = NULL;
3109 *rcp = NS_LDAP_MEMORY;
3110 return (NS_LDAP_MEMORY);
3112 dptr = (ns_ldap_search_desc_t *)
3113 calloc(1, sizeof (ns_ldap_search_desc_t));
3114 if (dptr == NULL) {
3115 free(sdlist);
3116 delete_search_cookie(cookie);
3117 cookie = NULL;
3118 *rcp = NS_LDAP_MEMORY;
3119 return (NS_LDAP_MEMORY);
3121 sdlist[0] = dptr;
3123 /* default base */
3124 rc = __s_api_getDNs(&dns, service, &cookie->errorp);
3125 if (rc != NS_LDAP_SUCCESS) {
3126 if (dns) {
3127 __s_api_free2dArray(dns);
3128 dns = NULL;
3130 *errorp = cookie->errorp;
3131 cookie->errorp = NULL;
3132 delete_search_cookie(cookie);
3133 cookie = NULL;
3134 *rcp = rc;
3135 return (rc);
3137 dptr->basedn = strdup(dns[0]);
3138 __s_api_free2dArray(dns);
3139 dns = NULL;
3141 /* default scope */
3142 scope = 0;
3143 rc = __s_api_getSearchScope(&scope, &cookie->errorp);
3144 dptr->scope = scope;
3147 cookie->sdlist = sdlist;
3150 * use VLV/PAGE control only if NS_LDAP_PAGE_CTRL is set
3152 if (flags & NS_LDAP_PAGE_CTRL)
3153 cookie->use_paging = TRUE;
3154 else
3155 cookie->use_paging = FALSE;
3157 /* Set up other arguments */
3158 cookie->userdata = userdata;
3159 if (init_filter_cb != NULL) {
3160 cookie->init_filter_cb = init_filter_cb;
3161 cookie->use_filtercb = 1;
3163 if (callback != NULL) {
3164 cookie->callback = callback;
3165 cookie->use_usercb = 1;
3168 /* check_shadow() may add extra value to cookie->i_flags */
3169 cookie->i_flags = flags;
3170 if (service) {
3171 cookie->service = strdup(service);
3172 if (cookie->service == NULL) {
3173 delete_search_cookie(cookie);
3174 cookie = NULL;
3175 *rcp = NS_LDAP_MEMORY;
3176 return (NS_LDAP_MEMORY);
3180 * If given, use the credential given by the caller, and
3181 * skip the credential check required for shadow update.
3183 if (auth == NULL) {
3184 rc = check_shadow(cookie, service);
3185 if (rc != NS_LDAP_SUCCESS) {
3186 *errorp = cookie->errorp;
3187 cookie->errorp = NULL;
3188 delete_search_cookie(cookie);
3189 cookie = NULL;
3190 *rcp = rc;
3191 return (rc);
3196 cookie->i_filter = strdup(filter);
3197 cookie->i_attr = attribute;
3198 cookie->i_auth = auth;
3199 cookie->i_sortattr = sortattr;
3201 if (batch != NULL) {
3202 cookie->batch = batch;
3203 cookie->reinit_on_retriable_err = B_TRUE;
3204 cookie->no_wait = B_TRUE;
3205 (void) search_state_machine(cookie, INIT, 0);
3206 cookie->no_wait = B_FALSE;
3207 rc = cookie->err_rc;
3209 if (rc == NS_LDAP_SUCCESS) {
3211 * Here rc == NS_LDAP_SUCCESS means that the state
3212 * machine init'ed successfully. The actual status
3213 * of the search will be determined by
3214 * __ns_ldap_list_batch_end(). Add the cookie to our
3215 * batch.
3217 cookie->caller_result = rResult;
3218 cookie->caller_errorp = errorp;
3219 cookie->caller_rc = rcp;
3220 cookie->next_cookie_in_batch = batch->cookie_list;
3221 batch->cookie_list = cookie;
3222 batch->nactive++;
3223 return (rc);
3226 * If state machine init failed then copy error to the caller
3227 * and delete the cookie.
3229 } else {
3230 (void) search_state_machine(cookie, INIT, 0);
3233 /* Copy results back to user */
3234 rc = cookie->err_rc;
3235 if (rc != NS_LDAP_SUCCESS) {
3236 if (conn_user != NULL && conn_user->ns_error != NULL) {
3237 *errorp = conn_user->ns_error;
3238 conn_user->ns_error = NULL;
3239 } else
3240 *errorp = cookie->errorp;
3242 *rResult = cookie->result;
3243 from_result = cookie->err_from_result;
3245 cookie->errorp = NULL;
3246 cookie->result = NULL;
3247 delete_search_cookie(cookie);
3248 cookie = NULL;
3250 if (from_result == 0 && *rResult == NULL)
3251 rc = NS_LDAP_NOTFOUND;
3252 *rcp = rc;
3253 return (rc);
3258 * __ns_ldap_list performs one or more LDAP searches to a given
3259 * directory server using service search descriptors and schema
3260 * mapping as appropriate. The operation may be retried a
3261 * couple of times in error situations.
3264 __ns_ldap_list(
3265 const char *service,
3266 const char *filter,
3267 int (*init_filter_cb)(const ns_ldap_search_desc_t *desc,
3268 char **realfilter, const void *userdata),
3269 const char * const *attribute,
3270 const ns_cred_t *auth,
3271 const int flags,
3272 ns_ldap_result_t **rResult, /* return result entries */
3273 ns_ldap_error_t **errorp,
3274 int (*callback)(const ns_ldap_entry_t *entry, const void *userdata),
3275 const void *userdata)
3277 int mod_flags;
3279 * Strip the NS_LDAP_PAGE_CTRL option as this interface does not
3280 * support this. If you want to use this option call the API
3281 * __ns_ldap_list_sort() with has the sort attribute.
3283 mod_flags = flags & (~NS_LDAP_PAGE_CTRL);
3285 return (__ns_ldap_list_sort(service, filter, NULL, init_filter_cb,
3286 attribute, auth, mod_flags, rResult, errorp,
3287 callback, userdata));
3291 * __ns_ldap_list_sort performs one or more LDAP searches to a given
3292 * directory server using service search descriptors and schema
3293 * mapping as appropriate. The operation may be retried a
3294 * couple of times in error situations.
3297 __ns_ldap_list_sort(
3298 const char *service,
3299 const char *filter,
3300 const char *sortattr,
3301 int (*init_filter_cb)(const ns_ldap_search_desc_t *desc,
3302 char **realfilter, const void *userdata),
3303 const char * const *attribute,
3304 const ns_cred_t *auth,
3305 const int flags,
3306 ns_ldap_result_t **rResult, /* return result entries */
3307 ns_ldap_error_t **errorp,
3308 int (*callback)(const ns_ldap_entry_t *entry, const void *userdata),
3309 const void *userdata)
3311 ns_conn_user_t *cu = NULL;
3312 int try_cnt = 0;
3313 int rc = NS_LDAP_SUCCESS, trc;
3315 for (;;) {
3316 if (__s_api_setup_retry_search(&cu, NS_CONN_USER_SEARCH,
3317 &try_cnt, &rc, errorp) == 0)
3318 break;
3319 rc = ldap_list(NULL, service, filter, sortattr, init_filter_cb,
3320 attribute, auth, flags, rResult, errorp, &trc, callback,
3321 userdata, cu);
3324 return (rc);
3328 * Create and initialize batch for native LDAP lookups
3331 __ns_ldap_list_batch_start(ns_ldap_list_batch_t **batch)
3333 *batch = calloc(1, sizeof (ns_ldap_list_batch_t));
3334 if (*batch == NULL)
3335 return (NS_LDAP_MEMORY);
3336 return (NS_LDAP_SUCCESS);
3341 * Add a LDAP search request to the batch.
3344 __ns_ldap_list_batch_add(
3345 ns_ldap_list_batch_t *batch,
3346 const char *service,
3347 const char *filter,
3348 int (*init_filter_cb)(const ns_ldap_search_desc_t *desc,
3349 char **realfilter, const void *userdata),
3350 const char * const *attribute,
3351 const ns_cred_t *auth,
3352 const int flags,
3353 ns_ldap_result_t **rResult, /* return result entries */
3354 ns_ldap_error_t **errorp,
3355 int *rcp,
3356 int (*callback)(const ns_ldap_entry_t *entry, const void *userdata),
3357 const void *userdata)
3359 ns_conn_user_t *cu;
3360 int rc;
3361 int mod_flags;
3363 cu = __s_api_conn_user_init(NS_CONN_USER_SEARCH, NULL, 0);
3364 if (cu == NULL) {
3365 if (rcp != NULL)
3366 *rcp = NS_LDAP_MEMORY;
3367 return (NS_LDAP_MEMORY);
3371 * Strip the NS_LDAP_PAGE_CTRL option as the batch interface does not
3372 * support this.
3374 mod_flags = flags & (~NS_LDAP_PAGE_CTRL);
3376 rc = ldap_list(batch, service, filter, NULL, init_filter_cb, attribute,
3377 auth, mod_flags, rResult, errorp, rcp, callback, userdata, cu);
3380 * Free the conn_user if the cookie was not batched. If the cookie
3381 * was batched then __ns_ldap_list_batch_end or release will free the
3382 * conn_user. The batch API instructs the search_state_machine
3383 * to reinit and retry (max 3 times) on retriable LDAP errors.
3385 if (rc != NS_LDAP_SUCCESS && cu != NULL) {
3386 if (cu->conn_mt != NULL)
3387 __s_api_conn_mt_return(cu);
3388 __s_api_conn_user_free(cu);
3390 return (rc);
3395 * Free batch.
3397 void
3398 __ns_ldap_list_batch_release(ns_ldap_list_batch_t *batch)
3400 ns_ldap_cookie_t *c, *next;
3402 for (c = batch->cookie_list; c != NULL; c = next) {
3403 next = c->next_cookie_in_batch;
3404 if (c->conn_user != NULL) {
3405 if (c->conn_user->conn_mt != NULL)
3406 __s_api_conn_mt_return(c->conn_user);
3407 __s_api_conn_user_free(c->conn_user);
3408 c->conn_user = NULL;
3410 delete_search_cookie(c);
3412 free(batch);
3415 #define LD_USING_STATE(st) \
3416 ((st == DO_SEARCH) || (st == MULTI_RESULT) || (st == NEXT_RESULT))
3419 * Process batch. Everytime this function is called it selects an
3420 * active cookie from the batch and single steps through the
3421 * search_state_machine for the selected cookie. If lookup associated
3422 * with the cookie is complete (success or error) then the cookie is
3423 * removed from the batch and its memory freed.
3425 * Returns 1 (if batch still has active cookies)
3426 * 0 (if batch has no more active cookies)
3427 * -1 (on errors, *rcp will contain the error code)
3429 * The caller should call this function in a loop as long as it returns 1
3430 * to process all the requests added to the batch. The results (and errors)
3431 * will be available in the locations provided by the caller at the time of
3432 * __ns_ldap_list_batch_add().
3434 static
3436 __ns_ldap_list_batch_process(ns_ldap_list_batch_t *batch, int *rcp)
3438 ns_ldap_cookie_t *c, *ptr, **prev;
3439 ns_state_t state;
3440 ns_ldap_error_t *errorp = NULL;
3441 int rc;
3443 /* Check if are already done */
3444 if (batch->nactive == 0)
3445 return (0);
3447 /* Get the next cookie from the batch */
3448 c = (batch->next_cookie == NULL) ?
3449 batch->cookie_list : batch->next_cookie;
3451 batch->next_cookie = c->next_cookie_in_batch;
3454 * Checks the status of the cookie's connection if it needs
3455 * to use that connection for ldap_search_ext or ldap_result.
3456 * If the connection is no longer good but worth retrying
3457 * then reinit the search_state_machine for this cookie
3458 * starting from the first search descriptor. REINIT will
3459 * clear any leftover results if max retries have not been
3460 * reached and redo the search (which may also involve
3461 * following referrals again).
3463 * Note that each cookie in the batch will make this
3464 * determination when it reaches one of the LD_USING_STATES.
3466 if (LD_USING_STATE(c->new_state) && c->conn_user != NULL) {
3467 rc = __s_api_setup_getnext(c->conn_user, &c->err_rc, &errorp);
3468 if (rc == LDAP_BUSY || rc == LDAP_UNAVAILABLE ||
3469 rc == LDAP_UNWILLING_TO_PERFORM) {
3470 if (errorp != NULL) {
3471 (void) __ns_ldap_freeError(&c->errorp);
3472 c->errorp = errorp;
3474 c->new_state = REINIT;
3475 } else if (rc == LDAP_CONNECT_ERROR ||
3476 rc == LDAP_SERVER_DOWN) {
3477 if (errorp != NULL) {
3478 (void) __ns_ldap_freeError(&c->errorp);
3479 c->errorp = errorp;
3481 c->new_state = REINIT;
3483 * MT connection is not usable,
3484 * close it before REINIT.
3486 __s_api_conn_mt_close(
3487 c->conn_user, rc, NULL);
3488 } else if (rc != NS_LDAP_SUCCESS) {
3489 if (rcp != NULL)
3490 *rcp = rc;
3491 *c->caller_result = NULL;
3492 *c->caller_errorp = errorp;
3493 *c->caller_rc = rc;
3494 return (-1);
3498 for (;;) {
3499 /* Single step through the search_state_machine */
3500 state = search_state_machine(c, c->new_state, ONE_STEP);
3501 switch (state) {
3502 case LDAP_ERROR:
3503 (void) search_state_machine(c, state, ONE_STEP);
3504 (void) search_state_machine(c, CLEAR_RESULTS, ONE_STEP);
3505 /* FALLTHROUGH */
3506 case ERROR:
3507 case EXIT:
3508 *c->caller_result = c->result;
3509 *c->caller_errorp = c->errorp;
3510 *c->caller_rc =
3511 (c->result == NULL && c->err_from_result == 0)
3512 ? NS_LDAP_NOTFOUND : c->err_rc;
3513 c->result = NULL;
3514 c->errorp = NULL;
3515 /* Remove the cookie from the batch */
3516 ptr = batch->cookie_list;
3517 prev = &batch->cookie_list;
3518 while (ptr != NULL) {
3519 if (ptr == c) {
3520 *prev = ptr->next_cookie_in_batch;
3521 break;
3523 prev = &ptr->next_cookie_in_batch;
3524 ptr = ptr->next_cookie_in_batch;
3526 /* Delete cookie and decrement active cookie count */
3527 if (c->conn_user != NULL) {
3528 if (c->conn_user->conn_mt != NULL)
3529 __s_api_conn_mt_return(c->conn_user);
3530 __s_api_conn_user_free(c->conn_user);
3531 c->conn_user = NULL;
3533 delete_search_cookie(c);
3534 batch->nactive--;
3535 break;
3536 case NEXT_RESULT:
3537 case MULTI_RESULT:
3539 * This means that search_state_machine needs to do
3540 * another ldap_result() for the cookie in question.
3541 * We only do at most one ldap_result() per call in
3542 * this function and therefore we return. This allows
3543 * the caller to process results from other cookies
3544 * in the batch without getting tied up on just one
3545 * cookie.
3547 break;
3548 default:
3550 * This includes states that follow NEXT_RESULT or
3551 * MULTI_RESULT such as PROCESS_RESULT and
3552 * END_PROCESS_RESULT. We continue processing
3553 * this cookie till we reach either the error, exit
3554 * or the result states.
3556 continue;
3558 break;
3561 /* Return 0 if no more cookies left otherwise 1 */
3562 return ((batch->nactive > 0) ? 1 : 0);
3567 * Process all the active cookies in the batch and when none
3568 * remains finalize the batch.
3571 __ns_ldap_list_batch_end(ns_ldap_list_batch_t *batch)
3573 int rc = NS_LDAP_SUCCESS;
3574 while (__ns_ldap_list_batch_process(batch, &rc) > 0)
3576 __ns_ldap_list_batch_release(batch);
3577 return (rc);
3581 * find_domainname performs one or more LDAP searches to
3582 * find the value of the nisdomain attribute associated with
3583 * the input DN (with no retry).
3586 static int
3587 find_domainname(const char *dn, char **domainname, const ns_cred_t *cred,
3588 ns_ldap_error_t **errorp, ns_conn_user_t *conn_user)
3591 ns_ldap_cookie_t *cookie;
3592 ns_ldap_search_desc_t **sdlist;
3593 ns_ldap_search_desc_t *dptr;
3594 int rc;
3595 char **value;
3596 int flags = 0;
3598 *domainname = NULL;
3599 *errorp = NULL;
3601 /* Initialize State machine cookie */
3602 cookie = init_search_state_machine();
3603 if (cookie == NULL) {
3604 return (NS_LDAP_MEMORY);
3606 cookie->conn_user = conn_user;
3608 /* see if need to follow referrals */
3609 rc = __s_api_toFollowReferrals(flags,
3610 &cookie->followRef, errorp);
3611 if (rc != NS_LDAP_SUCCESS) {
3612 delete_search_cookie(cookie);
3613 return (rc);
3616 /* Create default service Desc */
3617 sdlist = (ns_ldap_search_desc_t **)calloc(2,
3618 sizeof (ns_ldap_search_desc_t *));
3619 if (sdlist == NULL) {
3620 delete_search_cookie(cookie);
3621 cookie = NULL;
3622 return (NS_LDAP_MEMORY);
3624 dptr = (ns_ldap_search_desc_t *)
3625 calloc(1, sizeof (ns_ldap_search_desc_t));
3626 if (dptr == NULL) {
3627 free(sdlist);
3628 delete_search_cookie(cookie);
3629 cookie = NULL;
3630 return (NS_LDAP_MEMORY);
3632 sdlist[0] = dptr;
3634 /* search base is dn */
3635 dptr->basedn = strdup(dn);
3637 /* search scope is base */
3638 dptr->scope = NS_LDAP_SCOPE_BASE;
3640 /* search filter is "nisdomain=*" */
3641 dptr->filter = strdup(_NIS_FILTER);
3643 cookie->sdlist = sdlist;
3644 cookie->i_filter = strdup(dptr->filter);
3645 cookie->i_attr = nis_domain_attrs;
3646 cookie->i_auth = cred;
3647 cookie->i_flags = 0;
3649 /* Process search */
3650 rc = search_state_machine(cookie, INIT, 0);
3652 /* Copy domain name if found */
3653 rc = cookie->err_rc;
3654 if (rc != NS_LDAP_SUCCESS) {
3655 if (conn_user != NULL && conn_user->ns_error != NULL) {
3656 *errorp = conn_user->ns_error;
3657 conn_user->ns_error = NULL;
3658 } else
3659 *errorp = cookie->errorp;
3661 if (cookie->result == NULL)
3662 rc = NS_LDAP_NOTFOUND;
3663 if (rc == NS_LDAP_SUCCESS) {
3664 value = __ns_ldap_getAttr(cookie->result->entry,
3665 _NIS_DOMAIN);
3666 if (value[0])
3667 *domainname = strdup(value[0]);
3668 else
3669 rc = NS_LDAP_NOTFOUND;
3671 if (cookie->result != NULL)
3672 (void) __ns_ldap_freeResult(&cookie->result);
3673 cookie->errorp = NULL;
3674 delete_search_cookie(cookie);
3675 cookie = NULL;
3676 return (rc);
3680 * __s_api_find_domainname performs one or more LDAP searches to
3681 * find the value of the nisdomain attribute associated with
3682 * the input DN (with retry).
3685 static int
3686 __s_api_find_domainname(const char *dn, char **domainname,
3687 const ns_cred_t *cred, ns_ldap_error_t **errorp)
3689 ns_conn_user_t *cu = NULL;
3690 int try_cnt = 0;
3691 int rc = NS_LDAP_SUCCESS;
3693 for (;;) {
3694 if (__s_api_setup_retry_search(&cu, NS_CONN_USER_SEARCH,
3695 &try_cnt, &rc, errorp) == 0)
3696 break;
3697 rc = find_domainname(dn, domainname, cred, errorp, cu);
3700 return (rc);
3703 static int
3704 firstEntry(
3705 const char *service,
3706 const char *filter,
3707 const char *sortattr,
3708 int (*init_filter_cb)(const ns_ldap_search_desc_t *desc,
3709 char **realfilter, const void *userdata),
3710 const char * const *attribute,
3711 const ns_cred_t *auth,
3712 const int flags,
3713 void **vcookie,
3714 ns_ldap_result_t **result,
3715 ns_ldap_error_t ** errorp,
3716 const void *userdata,
3717 ns_conn_user_t *conn_user)
3719 ns_ldap_cookie_t *cookie = NULL;
3720 ns_ldap_error_t *error = NULL;
3721 ns_state_t state;
3722 ns_ldap_search_desc_t **sdlist;
3723 ns_ldap_search_desc_t *dptr;
3724 char **dns = NULL;
3725 int scope;
3726 int rc;
3728 *errorp = NULL;
3729 *result = NULL;
3732 * Sanity check - NS_LDAP_READ_SHADOW is for our
3733 * own internal use.
3735 if (flags & NS_LDAP_READ_SHADOW)
3736 return (NS_LDAP_INVALID_PARAM);
3738 /* get the service descriptor - or create a default one */
3739 rc = __s_api_get_SSD_from_SSDtoUse_service(service,
3740 &sdlist, &error);
3741 if (rc != NS_LDAP_SUCCESS) {
3742 *errorp = error;
3743 return (rc);
3745 if (sdlist == NULL) {
3746 /* Create default service Desc */
3747 sdlist = (ns_ldap_search_desc_t **)calloc(2,
3748 sizeof (ns_ldap_search_desc_t *));
3749 if (sdlist == NULL) {
3750 return (NS_LDAP_MEMORY);
3752 dptr = (ns_ldap_search_desc_t *)
3753 calloc(1, sizeof (ns_ldap_search_desc_t));
3754 if (dptr == NULL) {
3755 free(sdlist);
3756 return (NS_LDAP_MEMORY);
3758 sdlist[0] = dptr;
3760 /* default base */
3761 rc = __s_api_getDNs(&dns, service, &error);
3762 if (rc != NS_LDAP_SUCCESS) {
3763 if (dns) {
3764 __s_api_free2dArray(dns);
3765 dns = NULL;
3767 if (sdlist) {
3768 (void) __ns_ldap_freeSearchDescriptors(
3769 &sdlist);
3771 sdlist = NULL;
3773 *errorp = error;
3774 return (rc);
3776 dptr->basedn = strdup(dns[0]);
3777 __s_api_free2dArray(dns);
3778 dns = NULL;
3780 /* default scope */
3781 scope = 0;
3782 cookie = init_search_state_machine();
3783 if (cookie == NULL) {
3784 if (sdlist) {
3785 (void) __ns_ldap_freeSearchDescriptors(&sdlist);
3786 sdlist = NULL;
3788 return (NS_LDAP_MEMORY);
3790 rc = __s_api_getSearchScope(&scope, &cookie->errorp);
3791 dptr->scope = scope;
3794 /* Initialize State machine cookie */
3795 if (cookie == NULL)
3796 cookie = init_search_state_machine();
3797 if (cookie == NULL) {
3798 if (sdlist) {
3799 (void) __ns_ldap_freeSearchDescriptors(&sdlist);
3800 sdlist = NULL;
3802 return (NS_LDAP_MEMORY);
3805 /* identify self as a getent user */
3806 cookie->conn_user = conn_user;
3808 cookie->sdlist = sdlist;
3810 /* see if need to follow referrals */
3811 rc = __s_api_toFollowReferrals(flags,
3812 &cookie->followRef, errorp);
3813 if (rc != NS_LDAP_SUCCESS) {
3814 delete_search_cookie(cookie);
3815 return (rc);
3819 * use VLV/PAGE control only if NS_LDAP_NO_PAGE_CTRL is not set
3821 if (flags & NS_LDAP_NO_PAGE_CTRL)
3822 cookie->use_paging = FALSE;
3823 else
3824 cookie->use_paging = TRUE;
3826 /* Set up other arguments */
3827 cookie->userdata = userdata;
3828 if (init_filter_cb != NULL) {
3829 cookie->init_filter_cb = init_filter_cb;
3830 cookie->use_filtercb = 1;
3832 cookie->use_usercb = 0;
3833 /* check_shadow() may add extra value to cookie->i_flags */
3834 cookie->i_flags = flags;
3835 if (service) {
3836 cookie->service = strdup(service);
3837 if (cookie->service == NULL) {
3838 delete_search_cookie(cookie);
3839 return (NS_LDAP_MEMORY);
3843 * If given, use the credential given by the caller, and
3844 * skip the credential check required for shadow update.
3846 if (auth == NULL) {
3847 rc = check_shadow(cookie, service);
3848 if (rc != NS_LDAP_SUCCESS) {
3849 *errorp = cookie->errorp;
3850 cookie->errorp = NULL;
3851 delete_search_cookie(cookie);
3852 cookie = NULL;
3853 return (rc);
3858 cookie->i_filter = strdup(filter);
3859 cookie->i_attr = attribute;
3860 cookie->i_sortattr = sortattr;
3861 cookie->i_auth = auth;
3863 state = INIT;
3864 for (;;) {
3865 state = search_state_machine(cookie, state, ONE_STEP);
3866 switch (state) {
3867 case PROCESS_RESULT:
3868 *result = cookie->result;
3869 cookie->result = NULL;
3870 *vcookie = (void *)cookie;
3871 return (NS_LDAP_SUCCESS);
3872 case LDAP_ERROR:
3873 state = search_state_machine(cookie, state, ONE_STEP);
3874 state = search_state_machine(cookie, CLEAR_RESULTS,
3875 ONE_STEP);
3876 /* FALLTHROUGH */
3877 case ERROR:
3878 rc = cookie->err_rc;
3879 if (conn_user != NULL && conn_user->ns_error != NULL) {
3880 *errorp = conn_user->ns_error;
3881 conn_user->ns_error = NULL;
3882 } else {
3883 *errorp = cookie->errorp;
3884 cookie->errorp = NULL;
3886 delete_search_cookie(cookie);
3887 return (rc);
3888 case EXIT:
3889 rc = cookie->err_rc;
3890 if (rc != NS_LDAP_SUCCESS) {
3891 *errorp = cookie->errorp;
3892 cookie->errorp = NULL;
3893 } else {
3894 rc = NS_LDAP_NOTFOUND;
3897 delete_search_cookie(cookie);
3898 return (rc);
3900 default:
3901 break;
3907 __ns_ldap_firstEntry(
3908 const char *service,
3909 const char *filter,
3910 const char *vlv_sort,
3911 int (*init_filter_cb)(const ns_ldap_search_desc_t *desc,
3912 char **realfilter, const void *userdata),
3913 const char * const *attribute,
3914 const ns_cred_t *auth,
3915 const int flags,
3916 void **vcookie,
3917 ns_ldap_result_t **result,
3918 ns_ldap_error_t ** errorp,
3919 const void *userdata)
3921 ns_conn_user_t *cu = NULL;
3922 int try_cnt = 0;
3923 int rc = NS_LDAP_SUCCESS;
3925 for (;;) {
3926 if (__s_api_setup_retry_search(&cu, NS_CONN_USER_GETENT,
3927 &try_cnt, &rc, errorp) == 0)
3928 break;
3929 rc = firstEntry(service, filter, vlv_sort, init_filter_cb,
3930 attribute, auth, flags, vcookie, result, errorp, userdata,
3931 cu);
3933 return (rc);
3936 /*ARGSUSED2*/
3938 __ns_ldap_nextEntry(void *vcookie, ns_ldap_result_t **result,
3939 ns_ldap_error_t ** errorp)
3941 ns_ldap_cookie_t *cookie;
3942 ns_state_t state;
3943 int rc;
3945 cookie = (ns_ldap_cookie_t *)vcookie;
3946 cookie->result = NULL;
3947 *result = NULL;
3949 if (cookie->conn_user != NULL) {
3950 rc = __s_api_setup_getnext(cookie->conn_user,
3951 &cookie->err_rc, errorp);
3952 if (rc != NS_LDAP_SUCCESS)
3953 return (rc);
3956 state = END_PROCESS_RESULT;
3957 for (;;) {
3958 state = search_state_machine(cookie, state, ONE_STEP);
3959 switch (state) {
3960 case PROCESS_RESULT:
3961 *result = cookie->result;
3962 cookie->result = NULL;
3963 return (NS_LDAP_SUCCESS);
3964 case LDAP_ERROR:
3965 state = search_state_machine(cookie, state, ONE_STEP);
3966 state = search_state_machine(cookie, CLEAR_RESULTS,
3967 ONE_STEP);
3968 /* FALLTHROUGH */
3969 case ERROR:
3970 rc = cookie->err_rc;
3971 *errorp = cookie->errorp;
3972 cookie->errorp = NULL;
3973 return (rc);
3974 case EXIT:
3975 return (NS_LDAP_SUCCESS);
3981 __ns_ldap_endEntry(
3982 void **vcookie,
3983 ns_ldap_error_t ** errorp)
3985 ns_ldap_cookie_t *cookie;
3986 int rc;
3988 if (*vcookie == NULL)
3989 return (NS_LDAP_INVALID_PARAM);
3991 cookie = (ns_ldap_cookie_t *)(*vcookie);
3992 cookie->result = NULL;
3994 /* Complete search */
3995 rc = search_state_machine(cookie, CLEAR_RESULTS, 0);
3997 /* Copy results back to user */
3998 rc = cookie->err_rc;
3999 if (rc != NS_LDAP_SUCCESS)
4000 *errorp = cookie->errorp;
4002 cookie->errorp = NULL;
4003 if (cookie->conn_user != NULL) {
4004 if (cookie->conn_user->conn_mt != NULL)
4005 __s_api_conn_mt_return(cookie->conn_user);
4006 __s_api_conn_user_free(cookie->conn_user);
4008 delete_search_cookie(cookie);
4009 cookie = NULL;
4010 *vcookie = NULL;
4012 return (rc);
4017 __ns_ldap_freeResult(ns_ldap_result_t **result)
4020 ns_ldap_entry_t *curEntry = NULL;
4021 ns_ldap_entry_t *delEntry = NULL;
4022 int i;
4023 ns_ldap_result_t *res = *result;
4025 #ifdef DEBUG
4026 (void) fprintf(stderr, "__ns_ldap_freeResult START\n");
4027 #endif
4028 if (res == NULL)
4029 return (NS_LDAP_INVALID_PARAM);
4031 if (res->entry != NULL)
4032 curEntry = res->entry;
4034 for (i = 0; i < res->entries_count; i++) {
4035 if (curEntry != NULL) {
4036 delEntry = curEntry;
4037 curEntry = curEntry->next;
4038 __ns_ldap_freeEntry(delEntry);
4042 free(res);
4043 *result = NULL;
4044 return (NS_LDAP_SUCCESS);
4047 /*ARGSUSED*/
4049 __ns_ldap_auth(const ns_cred_t *auth,
4050 const int flags,
4051 ns_ldap_error_t **errorp,
4052 LDAPControl **serverctrls,
4053 LDAPControl **clientctrls)
4056 ConnectionID connectionId = -1;
4057 Connection *conp;
4058 int rc = 0;
4059 int do_not_fail_if_new_pwd_reqd = 0;
4060 int nopasswd_acct_mgmt = 0;
4061 ns_conn_user_t *conn_user;
4064 #ifdef DEBUG
4065 (void) fprintf(stderr, "__ns_ldap_auth START\n");
4066 #endif
4068 *errorp = NULL;
4069 if (!auth)
4070 return (NS_LDAP_INVALID_PARAM);
4072 conn_user = __s_api_conn_user_init(NS_CONN_USER_AUTH,
4073 NULL, B_FALSE);
4075 rc = __s_api_getConnection(NULL, flags | NS_LDAP_NEW_CONN,
4076 auth, &connectionId, &conp, errorp,
4077 do_not_fail_if_new_pwd_reqd, nopasswd_acct_mgmt,
4078 conn_user);
4080 if (conn_user != NULL)
4081 __s_api_conn_user_free(conn_user);
4083 if (rc == NS_LDAP_OP_FAILED && *errorp)
4084 (void) __ns_ldap_freeError(errorp);
4086 if (connectionId > -1)
4087 DropConnection(connectionId, flags);
4088 return (rc);
4091 char **
4092 __ns_ldap_getAttr(const ns_ldap_entry_t *entry, const char *attrname)
4094 int i;
4096 if (entry == NULL)
4097 return (NULL);
4098 for (i = 0; i < entry->attr_count; i++) {
4099 if (strcasecmp(entry->attr_pair[i]->attrname, attrname) == 0)
4100 return (entry->attr_pair[i]->attrvalue);
4102 return (NULL);
4105 ns_ldap_attr_t *
4106 __ns_ldap_getAttrStruct(const ns_ldap_entry_t *entry, const char *attrname)
4108 int i;
4110 if (entry == NULL)
4111 return (NULL);
4112 for (i = 0; i < entry->attr_count; i++) {
4113 if (strcasecmp(entry->attr_pair[i]->attrname, attrname) == 0)
4114 return (entry->attr_pair[i]);
4116 return (NULL);
4120 /*ARGSUSED*/
4122 __ns_ldap_uid2dn(const char *uid,
4123 char **userDN,
4124 const ns_cred_t *cred, /* cred is ignored */
4125 ns_ldap_error_t **errorp)
4127 ns_ldap_result_t *result = NULL;
4128 char *filter, *userdata;
4129 char errstr[MAXERROR];
4130 char **value;
4131 int rc = 0;
4132 int i = 0;
4133 size_t len;
4135 *errorp = NULL;
4136 *userDN = NULL;
4137 if ((uid == NULL) || (uid[0] == '\0'))
4138 return (NS_LDAP_INVALID_PARAM);
4140 while (uid[i] != '\0') {
4141 if (uid[i] == '=') {
4142 *userDN = strdup(uid);
4143 return (NS_LDAP_SUCCESS);
4145 i++;
4147 i = 0;
4148 while ((uid[i] != '\0') && (isdigit(uid[i])))
4149 i++;
4150 if (uid[i] == '\0') {
4151 len = strlen(UIDNUMFILTER) + strlen(uid) + 1;
4152 filter = (char *)malloc(len);
4153 if (filter == NULL) {
4154 *userDN = NULL;
4155 return (NS_LDAP_MEMORY);
4157 (void) snprintf(filter, len, UIDNUMFILTER, uid);
4159 len = strlen(UIDNUMFILTER_SSD) + strlen(uid) + 1;
4160 userdata = (char *)malloc(len);
4161 if (userdata == NULL) {
4162 *userDN = NULL;
4163 return (NS_LDAP_MEMORY);
4165 (void) snprintf(userdata, len, UIDNUMFILTER_SSD, uid);
4166 } else {
4167 len = strlen(UIDFILTER) + strlen(uid) + 1;
4168 filter = (char *)malloc(len);
4169 if (filter == NULL) {
4170 *userDN = NULL;
4171 return (NS_LDAP_MEMORY);
4173 (void) snprintf(filter, len, UIDFILTER, uid);
4175 len = strlen(UIDFILTER_SSD) + strlen(uid) + 1;
4176 userdata = (char *)malloc(len);
4177 if (userdata == NULL) {
4178 *userDN = NULL;
4179 return (NS_LDAP_MEMORY);
4181 (void) snprintf(userdata, len, UIDFILTER_SSD, uid);
4185 * we want to retrieve the DN as it appears in LDAP
4186 * hence the use of NS_LDAP_NOT_CVT_DN in flags
4188 rc = __ns_ldap_list("passwd", filter,
4189 __s_api_merge_SSD_filter,
4190 NULL, cred, NS_LDAP_NOT_CVT_DN,
4191 &result, errorp, NULL,
4192 userdata);
4193 free(filter);
4194 filter = NULL;
4195 free(userdata);
4196 userdata = NULL;
4197 if (rc != NS_LDAP_SUCCESS) {
4198 if (result) {
4199 (void) __ns_ldap_freeResult(&result);
4200 result = NULL;
4202 return (rc);
4204 if (result->entries_count > 1) {
4205 (void) __ns_ldap_freeResult(&result);
4206 result = NULL;
4207 *userDN = NULL;
4208 (void) sprintf(errstr,
4209 gettext("Too many entries are returned for %s"), uid);
4210 MKERROR(LOG_WARNING, *errorp, NS_LDAP_INTERNAL, strdup(errstr),
4212 return (NS_LDAP_INTERNAL);
4215 value = __ns_ldap_getAttr(result->entry, "dn");
4216 *userDN = strdup(value[0]);
4217 (void) __ns_ldap_freeResult(&result);
4218 result = NULL;
4219 return (NS_LDAP_SUCCESS);
4223 /*ARGSUSED*/
4225 __ns_ldap_host2dn(const char *host,
4226 const char *domain,
4227 char **hostDN,
4228 const ns_cred_t *cred, /* cred is ignored */
4229 ns_ldap_error_t **errorp)
4231 ns_ldap_result_t *result = NULL;
4232 char *filter, *userdata;
4233 char errstr[MAXERROR];
4234 char **value;
4235 int rc;
4236 size_t len;
4239 * XXX
4240 * the domain parameter needs to be used in case domain is not local, if
4241 * this routine is to support multi domain setups, it needs lots of work...
4243 *errorp = NULL;
4244 *hostDN = NULL;
4245 if ((host == NULL) || (host[0] == '\0'))
4246 return (NS_LDAP_INVALID_PARAM);
4248 len = strlen(HOSTFILTER) + strlen(host) + 1;
4249 filter = (char *)malloc(len);
4250 if (filter == NULL) {
4251 return (NS_LDAP_MEMORY);
4253 (void) snprintf(filter, len, HOSTFILTER, host);
4255 len = strlen(HOSTFILTER_SSD) + strlen(host) + 1;
4256 userdata = (char *)malloc(len);
4257 if (userdata == NULL) {
4258 return (NS_LDAP_MEMORY);
4260 (void) snprintf(userdata, len, HOSTFILTER_SSD, host);
4263 * we want to retrieve the DN as it appears in LDAP
4264 * hence the use of NS_LDAP_NOT_CVT_DN in flags
4266 rc = __ns_ldap_list("hosts", filter,
4267 __s_api_merge_SSD_filter,
4268 NULL, cred, NS_LDAP_NOT_CVT_DN, &result,
4269 errorp, NULL,
4270 userdata);
4271 free(filter);
4272 filter = NULL;
4273 free(userdata);
4274 userdata = NULL;
4275 if (rc != NS_LDAP_SUCCESS) {
4276 if (result) {
4277 (void) __ns_ldap_freeResult(&result);
4278 result = NULL;
4280 return (rc);
4283 if (result->entries_count > 1) {
4284 (void) __ns_ldap_freeResult(&result);
4285 result = NULL;
4286 *hostDN = NULL;
4287 (void) sprintf(errstr,
4288 gettext("Too many entries are returned for %s"), host);
4289 MKERROR(LOG_WARNING, *errorp, NS_LDAP_INTERNAL, strdup(errstr),
4291 return (NS_LDAP_INTERNAL);
4294 value = __ns_ldap_getAttr(result->entry, "dn");
4295 *hostDN = strdup(value[0]);
4296 (void) __ns_ldap_freeResult(&result);
4297 result = NULL;
4298 return (NS_LDAP_SUCCESS);
4301 /*ARGSUSED*/
4303 __ns_ldap_dn2domain(const char *dn,
4304 char **domain,
4305 const ns_cred_t *cred,
4306 ns_ldap_error_t **errorp)
4308 int rc, pnum, i, j, len = 0;
4309 char *newdn, **rdns = NULL;
4310 char **dns, *dn1;
4312 *errorp = NULL;
4314 if (domain == NULL)
4315 return (NS_LDAP_INVALID_PARAM);
4316 else
4317 *domain = NULL;
4319 if ((dn == NULL) || (dn[0] == '\0'))
4320 return (NS_LDAP_INVALID_PARAM);
4323 * break dn into rdns
4325 dn1 = strdup(dn);
4326 if (dn1 == NULL)
4327 return (NS_LDAP_MEMORY);
4328 rdns = ldap_explode_dn(dn1, 0);
4329 free(dn1);
4330 if (rdns == NULL || *rdns == NULL)
4331 return (NS_LDAP_INVALID_PARAM);
4333 for (i = 0; rdns[i]; i++)
4334 len += strlen(rdns[i]) + 1;
4335 pnum = i;
4337 newdn = (char *)malloc(len + 1);
4338 dns = (char **)calloc(pnum, sizeof (char *));
4339 if (newdn == NULL || dns == NULL) {
4340 free(newdn);
4341 ldap_value_free(rdns);
4342 return (NS_LDAP_MEMORY);
4345 /* construct a semi-normalized dn, newdn */
4346 *newdn = '\0';
4347 for (i = 0; rdns[i]; i++) {
4348 dns[i] = newdn + strlen(newdn);
4349 (void) strcat(newdn,
4350 __s_api_remove_rdn_space(rdns[i]));
4351 (void) strcat(newdn, ",");
4353 /* remove the last ',' */
4354 newdn[strlen(newdn) - 1] = '\0';
4355 ldap_value_free(rdns);
4358 * loop and find the domain name associated with newdn,
4359 * removing rdn one by one from left to right
4361 for (i = 0; i < pnum; i++) {
4363 if (*errorp)
4364 (void) __ns_ldap_freeError(errorp);
4367 * try cache manager first
4369 rc = __s_api_get_cachemgr_data(NS_CACHE_DN2DOMAIN,
4370 dns[i], domain);
4371 if (rc != NS_LDAP_SUCCESS) {
4373 * try ldap server second
4375 rc = __s_api_find_domainname(dns[i], domain,
4376 cred, errorp);
4377 } else {
4379 * skip the last one,
4380 * since it is already cached by ldap_cachemgr
4382 i--;
4384 if (rc == NS_LDAP_SUCCESS) {
4385 if (__s_api_nscd_proc()) {
4387 * If it's nscd, ask cache manager to save the
4388 * dn to domain mapping(s)
4390 for (j = 0; j <= i; j++) {
4391 (void) __s_api_set_cachemgr_data(
4392 NS_CACHE_DN2DOMAIN,
4393 dns[j],
4394 *domain);
4397 break;
4401 free(dns);
4402 free(newdn);
4403 if (rc != NS_LDAP_SUCCESS)
4404 rc = NS_LDAP_NOTFOUND;
4405 return (rc);
4408 /*ARGSUSED*/
4410 __ns_ldap_getServiceAuthMethods(const char *service,
4411 ns_auth_t ***auth,
4412 ns_ldap_error_t **errorp)
4414 char errstr[MAXERROR];
4415 int rc, i, done = 0;
4416 int slen;
4417 void **param;
4418 char **sam, *srv, *send;
4419 ns_auth_t **authpp = NULL, *ap;
4420 int cnt, max;
4421 ns_config_t *cfg;
4422 ns_ldap_error_t *error = NULL;
4424 if (errorp == NULL)
4425 return (NS_LDAP_INVALID_PARAM);
4426 *errorp = NULL;
4428 if ((service == NULL) || (service[0] == '\0') ||
4429 (auth == NULL))
4430 return (NS_LDAP_INVALID_PARAM);
4432 *auth = NULL;
4433 rc = __ns_ldap_getParam(NS_LDAP_SERVICE_AUTH_METHOD_P, &param, &error);
4434 if (rc != NS_LDAP_SUCCESS || param == NULL) {
4435 *errorp = error;
4436 return (rc);
4438 sam = (char **)param;
4440 cfg = __s_api_get_default_config();
4441 cnt = 0;
4443 slen = strlen(service);
4445 for (; *sam; sam++) {
4446 srv = *sam;
4447 if (strncasecmp(service, srv, slen) != 0)
4448 continue;
4449 srv += slen;
4450 if (*srv != COLONTOK)
4451 continue;
4452 send = srv;
4453 srv++;
4454 for (max = 1; (send = strchr(++send, SEMITOK)) != NULL;
4455 max++) {}
4456 authpp = (ns_auth_t **)calloc(++max, sizeof (ns_auth_t *));
4457 if (authpp == NULL) {
4458 (void) __ns_ldap_freeParam(&param);
4459 __s_api_release_config(cfg);
4460 return (NS_LDAP_MEMORY);
4462 while (!done) {
4463 send = strchr(srv, SEMITOK);
4464 if (send != NULL) {
4465 *send = '\0';
4466 send++;
4468 i = __s_get_enum_value(cfg, srv, NS_LDAP_AUTH_P);
4469 if (i == -1) {
4470 (void) __ns_ldap_freeParam(&param);
4471 (void) sprintf(errstr,
4472 gettext("Unsupported "
4473 "serviceAuthenticationMethod: %s.\n"), srv);
4474 MKERROR(LOG_WARNING, *errorp, NS_CONFIG_SYNTAX,
4475 strdup(errstr), 0);
4476 __s_api_release_config(cfg);
4477 return (NS_LDAP_CONFIG);
4479 ap = __s_api_AuthEnumtoStruct((EnumAuthType_t)i);
4480 if (ap == NULL) {
4481 (void) __ns_ldap_freeParam(&param);
4482 __s_api_release_config(cfg);
4483 return (NS_LDAP_MEMORY);
4485 authpp[cnt++] = ap;
4486 if (send == NULL)
4487 done = TRUE;
4488 else
4489 srv = send;
4493 *auth = authpp;
4494 (void) __ns_ldap_freeParam(&param);
4495 __s_api_release_config(cfg);
4496 return (NS_LDAP_SUCCESS);
4500 * This routine is called when certain scenario occurs
4501 * e.g.
4502 * service == auto_home
4503 * SSD = automount: ou = mytest,
4504 * NS_LDAP_MAPATTRIBUTE= auto_home: automountMapName=AAA
4505 * NS_LDAP_OBJECTCLASSMAP= auto_home:automountMap=MynisMap
4506 * NS_LDAP_OBJECTCLASSMAP= auto_home:automount=MynisObject
4508 * The automountMapName is prepended implicitely but is mapped
4509 * to AAA. So dn could appers as
4510 * dn: AAA=auto_home,ou=bar,dc=foo,dc=com
4511 * dn: automountKey=user_01,AAA=auto_home,ou=bar,dc=foo,dc=com
4512 * dn: automountKey=user_02,AAA=auto_home,ou=bar,dc=foo,dc=com
4513 * in the directory.
4514 * This function is called to covert the mapped attr back to
4515 * orig attr when the entries are searched and returned
4519 __s_api_convert_automountmapname(const char *service, char **dn,
4520 ns_ldap_error_t **errp) {
4522 char **mapping = NULL;
4523 char *mapped_attr = NULL;
4524 char *automountmapname = "automountMapName";
4525 char *buffer = NULL;
4526 int rc = NS_LDAP_SUCCESS;
4527 char errstr[MAXERROR];
4530 * dn is an input/out parameter, check it first
4533 if (service == NULL || dn == NULL || *dn == NULL)
4534 return (NS_LDAP_INVALID_PARAM);
4537 * Check to see if there is a mapped attribute for auto_xxx
4540 mapping = __ns_ldap_getMappedAttributes(service, automountmapname);
4543 * if no mapped attribute for auto_xxx, try automount
4546 if (mapping == NULL)
4547 mapping = __ns_ldap_getMappedAttributes(
4548 "automount", automountmapname);
4551 * if no mapped attribute is found, return SUCCESS (no op)
4554 if (mapping == NULL)
4555 return (NS_LDAP_SUCCESS);
4558 * if the mapped attribute is found and attr is not empty,
4559 * copy it
4562 if (mapping[0] != NULL) {
4563 mapped_attr = strdup(mapping[0]);
4564 __s_api_free2dArray(mapping);
4565 if (mapped_attr == NULL) {
4566 return (NS_LDAP_MEMORY);
4568 } else {
4569 __s_api_free2dArray(mapping);
4571 (void) snprintf(errstr, (2 * MAXERROR),
4572 gettext(
4573 "Attribute nisMapName is mapped to an "
4574 "empty string.\n"));
4576 MKERROR(LOG_ERR, *errp, NS_CONFIG_SYNTAX,
4577 strdup(errstr), 0);
4579 return (NS_LDAP_CONFIG);
4583 * Locate the mapped attribute in the dn
4584 * and replace it if it exists
4587 rc = __s_api_replace_mapped_attr_in_dn(
4588 (const char *) automountmapname, (const char *) mapped_attr,
4589 (const char *) *dn, &buffer);
4591 /* clean up */
4593 free(mapped_attr);
4596 * If mapped attr is found(buffer != NULL)
4597 * a new dn is returned
4598 * If no mapped attribute is in dn,
4599 * return NS_LDAP_SUCCESS (no op)
4600 * If no memory,
4601 * return NS_LDAP_MEMORY (no op)
4604 if (buffer != NULL) {
4605 free(*dn);
4606 *dn = buffer;
4609 return (rc);
4613 * If the mapped attr is found in the dn,
4614 * return NS_LDAP_SUCCESS and a new_dn.
4615 * If no mapped attr is found,
4616 * return NS_LDAP_SUCCESS and *new_dn == NULL
4617 * If there is not enough memory,
4618 * return NS_LDAP_MEMORY and *new_dn == NULL
4622 __s_api_replace_mapped_attr_in_dn(
4623 const char *orig_attr, const char *mapped_attr,
4624 const char *dn, char **new_dn) {
4626 char **dnArray = NULL;
4627 char *cur = NULL, *start = NULL;
4628 int i = 0, found = 0;
4629 int len = 0, orig_len = 0, mapped_len = 0;
4630 int dn_len = 0, tmp_len = 0;
4632 *new_dn = NULL;
4635 * seperate dn into individual componets
4636 * e.g.
4637 * "automountKey=user_01" , "automountMapName_test=auto_home", ...
4639 dnArray = ldap_explode_dn(dn, 0);
4642 * This will find "mapped attr=value" in dn.
4643 * It won't find match if mapped attr appears
4644 * in the value.
4646 for (i = 0; dnArray[i] != NULL; i++) {
4648 * This function is called when reading from
4649 * the directory so assume each component has "=".
4650 * Any ill formatted dn should be rejected
4651 * before adding to the directory
4653 cur = strchr(dnArray[i], '=');
4654 *cur = '\0';
4655 if (strcasecmp(mapped_attr, dnArray[i]) == 0)
4656 found = 1;
4657 *cur = '=';
4658 if (found) break;
4661 if (!found) {
4662 __s_api_free2dArray(dnArray);
4663 *new_dn = NULL;
4664 return (NS_LDAP_SUCCESS);
4667 * The new length is *dn length + (difference between
4668 * orig attr and mapped attr) + 1 ;
4669 * e.g.
4670 * automountKey=aa,automountMapName_test=auto_home,dc=foo,dc=com
4671 * ==>
4672 * automountKey=aa,automountMapName=auto_home,dc=foo,dc=com
4674 mapped_len = strlen(mapped_attr);
4675 orig_len = strlen(orig_attr);
4676 dn_len = strlen(dn);
4677 len = dn_len + orig_len - mapped_len + 1;
4678 *new_dn = (char *)calloc(1, len);
4679 if (*new_dn == NULL) {
4680 __s_api_free2dArray(dnArray);
4681 return (NS_LDAP_MEMORY);
4685 * Locate the mapped attr in the dn.
4686 * Use dnArray[i] instead of mapped_attr
4687 * because mapped_attr could appear in
4688 * the value
4691 cur = strstr(dn, dnArray[i]);
4692 __s_api_free2dArray(dnArray);
4693 /* copy the portion before mapped attr in dn */
4694 start = *new_dn;
4695 tmp_len = cur - dn;
4696 (void) memcpy((void *) start, (const void*) dn, tmp_len);
4699 * Copy the orig_attr. e.g. automountMapName
4700 * This replaces mapped attr with orig attr
4702 start = start + (cur - dn); /* move cursor in buffer */
4703 (void) memcpy((void *) start, (const void*) orig_attr, orig_len);
4706 * Copy the portion after mapped attr in dn
4708 cur = cur + mapped_len; /* move cursor in dn */
4709 start = start + orig_len; /* move cursor in buffer */
4710 (void) strcpy(start, cur);
4712 return (NS_LDAP_SUCCESS);
4716 * Validate Filter functions
4719 /* ***** Start of modified libldap.so.5 filter parser ***** */
4721 /* filter parsing routine forward references */
4722 static int adj_filter_list(char *str);
4723 static int adj_simple_filter(char *str);
4724 static int unescape_filterval(char *val);
4725 static int hexchar2int(char c);
4726 static int adj_substring_filter(char *val);
4730 * assumes string manipulation is in-line
4731 * and all strings are sufficient in size
4732 * return value is the position after 'c'
4735 static char *
4736 resync_str(char *str, char *next, char c)
4738 char *ret;
4740 ret = str + strlen(str);
4741 *next = c;
4742 if (ret == next)
4743 return (ret);
4744 (void) strcat(str, next);
4745 return (ret);
4748 static char *
4749 find_right_paren(char *s)
4751 int balance, escape;
4753 balance = 1;
4754 escape = 0;
4755 while (*s && balance) {
4756 if (escape == 0) {
4757 if (*s == '(')
4758 balance++;
4759 else if (*s == ')')
4760 balance--;
4762 if (*s == '\\' && ! escape)
4763 escape = 1;
4764 else
4765 escape = 0;
4766 if (balance)
4767 s++;
4770 return (*s ? s : NULL);
4773 static char *
4774 adj_complex_filter(char *str)
4776 char *next;
4779 * We have (x(filter)...) with str sitting on
4780 * the x. We have to find the paren matching
4781 * the one before the x and put the intervening
4782 * filters by calling adj_filter_list().
4785 str++;
4786 if ((next = find_right_paren(str)) == NULL)
4787 return (NULL);
4789 *next = '\0';
4790 if (adj_filter_list(str) == -1)
4791 return (NULL);
4792 next = resync_str(str, next, ')');
4793 next++;
4795 return (next);
4798 static int
4799 adj_filter(char *str)
4801 char *next;
4802 int parens, balance, escape;
4803 char *np, *cp, *dp;
4805 parens = 0;
4806 while (*str) {
4807 switch (*str) {
4808 case '(':
4809 str++;
4810 parens++;
4811 switch (*str) {
4812 case '&':
4813 if ((str = adj_complex_filter(str)) == NULL)
4814 return (-1);
4816 parens--;
4817 break;
4819 case '|':
4820 if ((str = adj_complex_filter(str)) == NULL)
4821 return (-1);
4823 parens--;
4824 break;
4826 case '!':
4827 if ((str = adj_complex_filter(str)) == NULL)
4828 return (-1);
4830 parens--;
4831 break;
4833 case '(':
4834 /* illegal ((case - generated by conversion */
4836 /* find missing close) */
4837 np = find_right_paren(str+1);
4839 /* error if not found */
4840 if (np == NULL)
4841 return (-1);
4843 /* remove redundant (and) */
4844 for (dp = str, cp = str+1; cp < np; ) {
4845 *dp++ = *cp++;
4847 cp++;
4848 while (*cp)
4849 *dp++ = *cp++;
4850 *dp = '\0';
4852 /* re-start test at original ( */
4853 parens--;
4854 str--;
4855 break;
4857 default:
4858 balance = 1;
4859 escape = 0;
4860 next = str;
4861 while (*next && balance) {
4862 if (escape == 0) {
4863 if (*next == '(')
4864 balance++;
4865 else if (*next == ')')
4866 balance--;
4868 if (*next == '\\' && ! escape)
4869 escape = 1;
4870 else
4871 escape = 0;
4872 if (balance)
4873 next++;
4875 if (balance != 0)
4876 return (-1);
4878 *next = '\0';
4879 if (adj_simple_filter(str) == -1) {
4880 return (-1);
4882 next = resync_str(str, next, ')');
4883 next++;
4884 str = next;
4885 parens--;
4886 break;
4888 break;
4890 case ')':
4891 str++;
4892 parens--;
4893 break;
4895 case ' ':
4896 str++;
4897 break;
4899 default: /* assume it's a simple type=value filter */
4900 next = strchr(str, '\0');
4901 if (adj_simple_filter(str) == -1) {
4902 return (-1);
4904 str = next;
4905 break;
4909 return (parens ? -1 : 0);
4914 * Put a list of filters like this "(filter1)(filter2)..."
4917 static int
4918 adj_filter_list(char *str)
4920 char *next;
4921 char save;
4923 while (*str) {
4924 while (*str && isspace(*str))
4925 str++;
4926 if (*str == '\0')
4927 break;
4929 if ((next = find_right_paren(str + 1)) == NULL)
4930 return (-1);
4931 save = *++next;
4933 /* now we have "(filter)" with str pointing to it */
4934 *next = '\0';
4935 if (adj_filter(str) == -1)
4936 return (-1);
4937 next = resync_str(str, next, save);
4939 str = next;
4942 return (0);
4947 * is_valid_attr - returns 1 if a is a syntactically valid left-hand side
4948 * of a filter expression, 0 otherwise. A valid string may contain only
4949 * letters, numbers, hyphens, semi-colons, colons and periods. examples:
4950 * cn
4951 * cn;lang-fr
4952 * 1.2.3.4;binary;dynamic
4953 * mail;dynamic
4954 * cn:dn:1.2.3.4
4956 * For compatibility with older servers, we also allow underscores in
4957 * attribute types, even through they are not allowed by the LDAPv3 RFCs.
4959 static int
4960 is_valid_attr(char *a)
4962 for (; *a; a++) {
4963 if (!isascii(*a)) {
4964 return (0);
4965 } else if (!isalnum(*a)) {
4966 switch (*a) {
4967 case '-':
4968 case '.':
4969 case ';':
4970 case ':':
4971 case '_':
4972 break; /* valid */
4973 default:
4974 return (0);
4978 return (1);
4981 static char *
4982 find_star(char *s)
4984 for (; *s; ++s) {
4985 switch (*s) {
4986 case '*':
4987 return (s);
4988 case '\\':
4989 ++s;
4990 if (hexchar2int(s[0]) >= 0 && hexchar2int(s[1]) >= 0)
4991 ++s;
4992 default:
4993 break;
4996 return (NULL);
4999 static int
5000 adj_simple_filter(char *str)
5002 char *s, *s2, *s3, filterop;
5003 char *value;
5004 int ftype = 0;
5005 int rc;
5007 rc = -1; /* pessimistic */
5009 if ((str = strdup(str)) == NULL) {
5010 return (rc);
5013 if ((s = strchr(str, '=')) == NULL) {
5014 goto free_and_return;
5016 value = s + 1;
5017 *s-- = '\0';
5018 filterop = *s;
5019 if (filterop == '<' || filterop == '>' || filterop == '~' ||
5020 filterop == ':') {
5021 *s = '\0';
5024 if (! is_valid_attr(str)) {
5025 goto free_and_return;
5028 switch (filterop) {
5029 case '<': /* LDAP_FILTER_LE */
5030 case '>': /* LDAP_FILTER_GE */
5031 case '~': /* LDAP_FILTER_APPROX */
5032 break;
5033 case ':': /* extended filter - v3 only */
5035 * extended filter looks like this:
5037 * [type][':dn'][':'oid]':='value
5039 * where one of type or :oid is required.
5042 s2 = s3 = NULL;
5043 if ((s2 = strrchr(str, ':')) == NULL) {
5044 goto free_and_return;
5046 if (strcasecmp(s2, ":dn") == 0) {
5047 *s2 = '\0';
5048 } else {
5049 *s2 = '\0';
5050 if ((s3 = strrchr(str, ':')) != NULL) {
5051 if (strcasecmp(s3, ":dn") != 0) {
5052 goto free_and_return;
5054 *s3 = '\0';
5057 if (unescape_filterval(value) < 0) {
5058 goto free_and_return;
5060 rc = 0;
5061 goto free_and_return;
5062 /* break; */
5063 default:
5064 if (find_star(value) == NULL) {
5065 ftype = 0; /* LDAP_FILTER_EQUALITY */
5066 } else if (strcmp(value, "*") == 0) {
5067 ftype = 1; /* LDAP_FILTER_PRESENT */
5068 } else {
5069 rc = adj_substring_filter(value);
5070 goto free_and_return;
5072 break;
5075 if (ftype != 0) { /* == LDAP_FILTER_PRESENT */
5076 rc = 0;
5077 } else if (unescape_filterval(value) >= 0) {
5078 rc = 0;
5080 if (rc != -1) {
5081 rc = 0;
5084 free_and_return:
5085 free(str);
5086 return (rc);
5091 * Check in place both LDAPv2 (RFC-1960) and LDAPv3 (hexadecimal) escape
5092 * sequences within the null-terminated string 'val'.
5094 * If 'val' contains invalid escape sequences we return -1.
5095 * Otherwise return 1
5097 static int
5098 unescape_filterval(char *val)
5100 int escape, firstdigit;
5101 char *s;
5103 firstdigit = 0;
5104 escape = 0;
5105 for (s = val; *s; s++) {
5106 if (escape) {
5108 * first try LDAPv3 escape (hexadecimal) sequence
5110 if (hexchar2int(*s) < 0) {
5111 if (firstdigit) {
5113 * LDAPv2 (RFC1960) escape sequence
5115 escape = 0;
5116 } else {
5117 return (-1);
5120 if (firstdigit) {
5121 firstdigit = 0;
5122 } else {
5123 escape = 0;
5126 } else if (*s != '\\') {
5127 escape = 0;
5129 } else {
5130 escape = 1;
5131 firstdigit = 1;
5135 return (1);
5140 * convert character 'c' that represents a hexadecimal digit to an integer.
5141 * if 'c' is not a hexidecimal digit [0-9A-Fa-f], -1 is returned.
5142 * otherwise the converted value is returned.
5144 static int
5145 hexchar2int(char c)
5147 if (c >= '0' && c <= '9') {
5148 return (c - '0');
5150 if (c >= 'A' && c <= 'F') {
5151 return (c - 'A' + 10);
5153 if (c >= 'a' && c <= 'f') {
5154 return (c - 'a' + 10);
5156 return (-1);
5159 static int
5160 adj_substring_filter(char *val)
5162 char *nextstar;
5164 for (; val != NULL; val = nextstar) {
5165 if ((nextstar = find_star(val)) != NULL) {
5166 *nextstar++ = '\0';
5169 if (*val != '\0') {
5170 if (unescape_filterval(val) < 0) {
5171 return (-1);
5176 return (0);
5179 /* ***** End of modified libldap.so.5 filter parser ***** */
5183 * Walk filter, remove redundant parentheses in-line
5184 * verify that the filter is reasonable
5186 static int
5187 validate_filter(ns_ldap_cookie_t *cookie)
5189 char *filter = cookie->filter;
5190 int rc;
5192 /* Parse filter looking for illegal values */
5194 rc = adj_filter(filter);
5195 if (rc != 0) {
5196 return (NS_LDAP_OP_FAILED);
5199 /* end of filter checking */
5201 return (NS_LDAP_SUCCESS);
5205 * Set the account management request control that needs to be sent to server.
5206 * This control is required to get the account management information of
5207 * a user to do local account checking.
5209 static int
5210 setup_acctmgmt_params(ns_ldap_cookie_t *cookie)
5212 LDAPControl *req = NULL, **requestctrls;
5214 req = (LDAPControl *)malloc(sizeof (LDAPControl));
5216 if (req == NULL)
5217 return (NS_LDAP_MEMORY);
5219 /* fill in the fields of this new control */
5220 req->ldctl_iscritical = 1;
5221 req->ldctl_oid = strdup(NS_LDAP_ACCOUNT_USABLE_CONTROL);
5222 if (req->ldctl_oid == NULL) {
5223 free(req);
5224 return (NS_LDAP_MEMORY);
5226 req->ldctl_value.bv_len = 0;
5227 req->ldctl_value.bv_val = NULL;
5229 requestctrls = (LDAPControl **)calloc(2, sizeof (LDAPControl *));
5230 if (requestctrls == NULL) {
5231 ldap_control_free(req);
5232 return (NS_LDAP_MEMORY);
5235 requestctrls[0] = req;
5237 cookie->p_serverctrls = requestctrls;
5239 return (NS_LDAP_SUCCESS);
5243 * int get_new_acct_more_info(BerElement *ber,
5244 * AcctUsableResponse_t *acctResp)
5246 * Decode the more_info data from an Account Management control response,
5247 * when the account is not usable and when code style is from recent LDAP
5248 * servers (see below comments for parse_acct_cont_resp_msg() to get more
5249 * details on coding styles and ASN1 description).
5251 * Expected BER encoding: {tbtbtbtiti}
5252 * +t: tag is 0
5253 * +b: TRUE if inactive due to account inactivation
5254 * +t: tag is 1
5255 * +b: TRUE if password has been reset
5256 * +t: tag is 2
5257 * +b: TRUE if password is expired
5258 * +t: tag is 3
5259 * +i: contains num of remaining grace, 0 means no grace
5260 * +t: tag is 4
5261 * +i: contains num of seconds before auto-unlock. -1 means acct is locked
5262 * forever (i.e. until reset)
5264 * Asumptions:
5265 * - ber is not null
5266 * - acctResp is not null and is initialized with default values for the
5267 * fields in its AcctUsableResp.more_info structure
5268 * - the ber stream is received in the correct order, per the ASN1 description.
5269 * We do not check this order and make the asumption that it is correct.
5270 * Note that the ber stream may not (and will not in most cases) contain
5271 * all fields.
5273 static int
5274 get_new_acct_more_info(BerElement *ber, AcctUsableResponse_t *acctResp)
5276 int rc = NS_LDAP_SUCCESS;
5277 char errstr[MAXERROR];
5278 ber_tag_t rTag = LBER_DEFAULT;
5279 ber_len_t rLen = 0;
5280 ber_int_t rValue;
5281 char *last;
5282 int berRC = 0;
5285 * Look at what more_info BER element is/are left to be decoded.
5286 * look at each of them 1 by 1, without checking on their order
5287 * and possible multi values.
5289 for (rTag = ber_first_element(ber, &rLen, &last);
5290 rTag != LBER_END_OF_SEQORSET;
5291 rTag = ber_next_element(ber, &rLen, last)) {
5293 berRC = 0;
5294 switch (rTag) {
5295 case 0 | LBER_CLASS_CONTEXT | LBER_PRIMITIVE:
5296 /* inactive */
5297 berRC = ber_scanf(ber, "b", &rValue);
5298 if (berRC != LBER_ERROR) {
5299 (acctResp->AcctUsableResp).more_info.
5300 inactive = (rValue != 0) ? 1 : 0;
5302 break;
5304 case 1 | LBER_CLASS_CONTEXT | LBER_PRIMITIVE:
5305 /* reset */
5306 berRC = ber_scanf(ber, "b", &rValue);
5307 if (berRC != LBER_ERROR) {
5308 (acctResp->AcctUsableResp).more_info.reset
5309 = (rValue != 0) ? 1 : 0;
5311 break;
5313 case 2 | LBER_CLASS_CONTEXT | LBER_PRIMITIVE:
5314 /* expired */
5315 berRC = ber_scanf(ber, "b", &rValue);
5316 if (berRC != LBER_ERROR) {
5317 (acctResp->AcctUsableResp).more_info.expired
5318 = (rValue != 0) ? 1 : 0;
5320 break;
5322 case 3 | LBER_CLASS_CONTEXT | LBER_PRIMITIVE:
5323 /* remaining grace */
5324 berRC = ber_scanf(ber, "i", &rValue);
5325 if (berRC != LBER_ERROR) {
5326 (acctResp->AcctUsableResp).more_info.rem_grace
5327 = rValue;
5329 break;
5331 case 4 | LBER_CLASS_CONTEXT | LBER_PRIMITIVE:
5332 /* seconds before unlock */
5333 berRC = ber_scanf(ber, "i", &rValue);
5334 if (berRC != LBER_ERROR) {
5335 (acctResp->AcctUsableResp).more_info.
5336 sec_b4_unlock = rValue;
5338 break;
5340 default :
5341 (void) sprintf(errstr,
5342 gettext("invalid reason tag 0x%x"), rTag);
5343 syslog(LOG_DEBUG, "libsldap: %s", errstr);
5344 rc = NS_LDAP_INTERNAL;
5345 break;
5347 if (berRC == LBER_ERROR) {
5348 (void) sprintf(errstr,
5349 gettext("error 0x%x decoding value for "
5350 "tag 0x%x"), berRC, rTag);
5351 syslog(LOG_DEBUG, "libsldap: %s", errstr);
5352 rc = NS_LDAP_INTERNAL;
5354 if (rc != NS_LDAP_SUCCESS) {
5355 /* exit the for loop */
5356 break;
5360 return (rc);
5364 * int get_old_acct_opt_more_info(BerElement *ber,
5365 * AcctUsableResponse_t *acctResp)
5367 * Decode the optional more_info data from an Account Management control
5368 * response, when the account is not usable and when code style is from LDAP
5369 * server 5.2p4 (see below comments for parse_acct_cont_resp_msg() to get more
5370 * details on coding styles and ASN1 description).
5372 * Expected BER encoding: titi}
5373 * +t: tag is 2
5374 * +i: contains num of remaining grace, 0 means no grace
5375 * +t: tag is 3
5376 * +i: contains num of seconds before auto-unlock. -1 means acct is locked
5377 * forever (i.e. until reset)
5379 * Asumptions:
5380 * - ber is a valid BER element
5381 * - acctResp is initialized for the fields in its AcctUsableResp.more_info
5382 * structure
5384 static int
5385 get_old_acct_opt_more_info(ber_tag_t tag, BerElement *ber,
5386 AcctUsableResponse_t *acctResp)
5388 int rc = NS_LDAP_SUCCESS;
5389 char errstr[MAXERROR];
5390 ber_len_t len;
5391 int rem_grace, sec_b4_unlock;
5393 switch (tag) {
5394 case 2:
5395 /* decode and maybe 3 is following */
5396 if ((tag = ber_scanf(ber, "i", &rem_grace)) == LBER_ERROR) {
5397 (void) sprintf(errstr, gettext("Can not get "
5398 "rem_grace"));
5399 syslog(LOG_DEBUG, "libsldap: %s", errstr);
5400 rc = NS_LDAP_INTERNAL;
5401 break;
5403 (acctResp->AcctUsableResp).more_info.rem_grace = rem_grace;
5405 if ((tag = ber_peek_tag(ber, &len)) == LBER_ERROR) {
5406 /* this is a success case, break to exit */
5407 (void) sprintf(errstr, gettext("No more "
5408 "optional data"));
5409 syslog(LOG_DEBUG, "libsldap: %s", errstr);
5410 break;
5413 if (tag == 3) {
5414 if (ber_scanf(ber, "i", &sec_b4_unlock) == LBER_ERROR) {
5415 (void) sprintf(errstr,
5416 gettext("Can not get sec_b4_unlock "
5417 "- 1st case"));
5418 syslog(LOG_DEBUG, "libsldap: %s", errstr);
5419 rc = NS_LDAP_INTERNAL;
5420 break;
5422 (acctResp->AcctUsableResp).more_info.sec_b4_unlock =
5423 sec_b4_unlock;
5424 } else { /* unknown tag */
5425 (void) sprintf(errstr, gettext("Unknown tag "
5426 "- 1st case"));
5427 syslog(LOG_DEBUG, "libsldap: %s", errstr);
5428 rc = NS_LDAP_INTERNAL;
5429 break;
5431 break;
5433 case 3:
5434 if (ber_scanf(ber, "i", &sec_b4_unlock) == LBER_ERROR) {
5435 (void) sprintf(errstr, gettext("Can not get "
5436 "sec_b4_unlock - 2nd case"));
5437 syslog(LOG_DEBUG, "libsldap: %s", errstr);
5438 rc = NS_LDAP_INTERNAL;
5439 break;
5441 (acctResp->AcctUsableResp).more_info.sec_b4_unlock =
5442 sec_b4_unlock;
5443 break;
5445 default: /* unknown tag */
5446 (void) sprintf(errstr, gettext("Unknown tag - 2nd case"));
5447 syslog(LOG_DEBUG, "libsldap: %s", errstr);
5448 rc = NS_LDAP_INTERNAL;
5449 break;
5452 return (rc);
5456 * **** This function needs to be moved to libldap library ****
5457 * parse_acct_cont_resp_msg() parses the message received by server according to
5458 * following format (ASN1 notation):
5460 * ACCOUNT_USABLE_RESPONSE::= CHOICE {
5461 * is_available [0] INTEGER,
5462 * ** seconds before expiration **
5463 * is_not_available [1] more_info
5465 * more_info::= SEQUENCE {
5466 * inactive [0] BOOLEAN DEFAULT FALSE,
5467 * reset [1] BOOLEAN DEFAULT FALSE,
5468 * expired [2] BOOLEAN DEFAULT FALSE,
5469 * remaining_grace [3] INTEGER OPTIONAL,
5470 * seconds_before_unlock [4] INTEGER OPTIONAL
5474 * #define used to make the difference between coding style as done
5475 * by LDAP server 5.2p4 and newer LDAP servers. There are 4 values:
5476 * - DS52p4_USABLE: 5.2p4 coding style, account is usable
5477 * - DS52p4_NOT_USABLE: 5.2p4 coding style, account is not usable
5478 * - NEW_USABLE: newer LDAP servers coding style, account is usable
5479 * - NEW_NOT_USABLE: newer LDAP servers coding style, account is not usable
5481 * An account would be considered not usable if for instance:
5482 * - it's been made inactive in the LDAP server
5483 * - or its password was reset in the LDAP server database
5484 * - or its password expired
5485 * - or the account has been locked, possibly forever
5487 #define DS52p4_USABLE 0x00
5488 #define DS52p4_NOT_USABLE 0x01
5489 #define NEW_USABLE 0x00 | LBER_CLASS_CONTEXT | LBER_PRIMITIVE
5490 #define NEW_NOT_USABLE 0x01 | LBER_CLASS_CONTEXT | LBER_CONSTRUCTED
5491 static int
5492 parse_acct_cont_resp_msg(LDAPControl **ectrls, AcctUsableResponse_t *acctResp)
5494 int rc = NS_LDAP_SUCCESS;
5495 BerElement *ber;
5496 ber_tag_t tag;
5497 ber_len_t len;
5498 int i;
5499 char errstr[MAXERROR];
5500 /* used for any coding style when account is usable */
5501 int seconds_before_expiry;
5502 /* used for 5.2p4 coding style when account is not usable */
5503 int inactive, reset, expired;
5505 if (ectrls == NULL) {
5506 (void) sprintf(errstr, gettext("Invalid ectrls parameter"));
5507 syslog(LOG_DEBUG, "libsldap: %s", errstr);
5508 return (NS_LDAP_INVALID_PARAM);
5511 for (i = 0; ectrls[i] != NULL; i++) {
5512 if (strcmp(ectrls[i]->ldctl_oid, NS_LDAP_ACCOUNT_USABLE_CONTROL)
5513 == 0) {
5514 break;
5518 if (ectrls[i] == NULL) {
5519 /* Ldap control is not found */
5520 (void) sprintf(errstr, gettext("Account Usable Control "
5521 "not found"));
5522 syslog(LOG_DEBUG, "libsldap: %s", errstr);
5523 return (NS_LDAP_NOTFOUND);
5526 /* Allocate a BER element from the control value and parse it. */
5527 if ((ber = ber_init(&ectrls[i]->ldctl_value)) == NULL)
5528 return (NS_LDAP_MEMORY);
5530 if ((tag = ber_peek_tag(ber, &len)) == LBER_ERROR) {
5531 /* Ldap decoding error */
5532 (void) sprintf(errstr, gettext("Error decoding 1st tag"));
5533 syslog(LOG_DEBUG, "libsldap: %s", errstr);
5534 ber_free(ber, 1);
5535 return (NS_LDAP_INTERNAL);
5538 switch (tag) {
5539 case DS52p4_USABLE:
5540 case NEW_USABLE:
5541 acctResp->choice = 0;
5542 if (ber_scanf(ber, "i", &seconds_before_expiry)
5543 == LBER_ERROR) {
5544 /* Ldap decoding error */
5545 (void) sprintf(errstr, gettext("Can not get "
5546 "seconds_before_expiry"));
5547 syslog(LOG_DEBUG, "libsldap: %s", errstr);
5548 rc = NS_LDAP_INTERNAL;
5549 break;
5551 /* ber_scanf() succeeded */
5552 (acctResp->AcctUsableResp).seconds_before_expiry =
5553 seconds_before_expiry;
5554 break;
5556 case DS52p4_NOT_USABLE:
5557 acctResp->choice = 1;
5558 if (ber_scanf(ber, "{bbb", &inactive, &reset, &expired)
5559 == LBER_ERROR) {
5560 /* Ldap decoding error */
5561 (void) sprintf(errstr, gettext("Can not get "
5562 "inactive/reset/expired"));
5563 syslog(LOG_DEBUG, "libsldap: %s", errstr);
5564 rc = NS_LDAP_INTERNAL;
5565 break;
5567 /* ber_scanf() succeeded */
5568 (acctResp->AcctUsableResp).more_info.inactive =
5569 ((inactive == 0) ? 0 : 1);
5570 (acctResp->AcctUsableResp).more_info.reset =
5571 ((reset == 0) ? 0 : 1);
5572 (acctResp->AcctUsableResp).more_info.expired =
5573 ((expired == 0) ? 0 : 1);
5574 (acctResp->AcctUsableResp).more_info.rem_grace = 0;
5575 (acctResp->AcctUsableResp).more_info.sec_b4_unlock = 0;
5577 if ((tag = ber_peek_tag(ber, &len)) == LBER_ERROR) {
5578 /* this is a success case, break to exit */
5579 (void) sprintf(errstr, gettext("No optional data"));
5580 syslog(LOG_DEBUG, "libsldap: %s", errstr);
5581 break;
5585 * Look at what optional more_info BER element is/are
5586 * left to be decoded.
5588 rc = get_old_acct_opt_more_info(tag, ber, acctResp);
5589 break;
5591 case NEW_NOT_USABLE:
5592 acctResp->choice = 1;
5594 * Recent LDAP servers won't code more_info data for default
5595 * values (see above comments on ASN1 description for what
5596 * fields have default values & what fields are optional).
5598 (acctResp->AcctUsableResp).more_info.inactive = 0;
5599 (acctResp->AcctUsableResp).more_info.reset = 0;
5600 (acctResp->AcctUsableResp).more_info.expired = 0;
5601 (acctResp->AcctUsableResp).more_info.rem_grace = 0;
5602 (acctResp->AcctUsableResp).more_info.sec_b4_unlock = 0;
5604 if (len == 0) {
5606 * Nothing else to decode; this is valid and we
5607 * use default values set above.
5609 (void) sprintf(errstr, gettext("more_info is "
5610 "empty, using default values"));
5611 syslog(LOG_DEBUG, "libsldap: %s", errstr);
5612 break;
5616 * Look at what more_info BER element is/are left to
5617 * be decoded.
5619 rc = get_new_acct_more_info(ber, acctResp);
5620 break;
5622 default:
5623 (void) sprintf(errstr, gettext("unknwon coding style "
5624 "(tag: 0x%x)"), tag);
5625 syslog(LOG_DEBUG, "libsldap: %s", errstr);
5626 rc = NS_LDAP_INTERNAL;
5627 break;
5630 ber_free(ber, 1);
5631 return (rc);
5635 * internal function for __ns_ldap_getAcctMgmt()
5637 static int
5638 getAcctMgmt(const char *user, AcctUsableResponse_t *acctResp,
5639 ns_conn_user_t *conn_user)
5641 int scope, rc;
5642 char ldapfilter[1024];
5643 ns_ldap_cookie_t *cookie;
5644 ns_ldap_search_desc_t **sdlist = NULL;
5645 ns_ldap_search_desc_t *dptr;
5646 ns_ldap_error_t *error = NULL;
5647 char **dns = NULL;
5648 char service[] = "shadow";
5650 if (user == NULL || acctResp == NULL)
5651 return (NS_LDAP_INVALID_PARAM);
5653 /* Initialize State machine cookie */
5654 cookie = init_search_state_machine();
5655 if (cookie == NULL)
5656 return (NS_LDAP_MEMORY);
5657 cookie->conn_user = conn_user;
5659 /* see if need to follow referrals */
5660 rc = __s_api_toFollowReferrals(0,
5661 &cookie->followRef, &error);
5662 if (rc != NS_LDAP_SUCCESS) {
5663 (void) __ns_ldap_freeError(&error);
5664 goto out;
5667 /* get the service descriptor - or create a default one */
5668 rc = __s_api_get_SSD_from_SSDtoUse_service(service,
5669 &sdlist, &error);
5670 if (rc != NS_LDAP_SUCCESS) {
5671 (void) __ns_ldap_freeError(&error);
5672 goto out;
5675 if (sdlist == NULL) {
5676 /* Create default service Desc */
5677 sdlist = (ns_ldap_search_desc_t **)calloc(2,
5678 sizeof (ns_ldap_search_desc_t *));
5679 if (sdlist == NULL) {
5680 rc = NS_LDAP_MEMORY;
5681 goto out;
5683 dptr = (ns_ldap_search_desc_t *)
5684 calloc(1, sizeof (ns_ldap_search_desc_t));
5685 if (dptr == NULL) {
5686 free(sdlist);
5687 rc = NS_LDAP_MEMORY;
5688 goto out;
5690 sdlist[0] = dptr;
5692 /* default base */
5693 rc = __s_api_getDNs(&dns, service, &cookie->errorp);
5694 if (rc != NS_LDAP_SUCCESS) {
5695 if (dns) {
5696 __s_api_free2dArray(dns);
5697 dns = NULL;
5699 (void) __ns_ldap_freeError(&(cookie->errorp));
5700 cookie->errorp = NULL;
5701 goto out;
5703 dptr->basedn = strdup(dns[0]);
5704 if (dptr->basedn == NULL) {
5705 free(sdlist);
5706 free(dptr);
5707 if (dns) {
5708 __s_api_free2dArray(dns);
5709 dns = NULL;
5711 rc = NS_LDAP_MEMORY;
5712 goto out;
5714 __s_api_free2dArray(dns);
5715 dns = NULL;
5717 /* default scope */
5718 scope = 0;
5719 rc = __s_api_getSearchScope(&scope, &cookie->errorp);
5720 dptr->scope = scope;
5723 cookie->sdlist = sdlist;
5725 cookie->service = strdup(service);
5726 if (cookie->service == NULL) {
5727 rc = NS_LDAP_MEMORY;
5728 goto out;
5731 /* search for entries for this particular uid */
5732 (void) snprintf(ldapfilter, sizeof (ldapfilter), "(uid=%s)", user);
5733 cookie->i_filter = strdup(ldapfilter);
5734 if (cookie->i_filter == NULL) {
5735 rc = NS_LDAP_MEMORY;
5736 goto out;
5739 /* create the control request */
5740 if ((rc = setup_acctmgmt_params(cookie)) != NS_LDAP_SUCCESS)
5741 goto out;
5743 /* Process search */
5744 rc = search_state_machine(cookie, GET_ACCT_MGMT_INFO, 0);
5746 /* Copy results back to user */
5747 rc = cookie->err_rc;
5748 if (rc != NS_LDAP_SUCCESS)
5749 (void) __ns_ldap_freeError(&(cookie->errorp));
5751 if (cookie->result == NULL)
5752 goto out;
5754 if ((rc = parse_acct_cont_resp_msg(cookie->resultctrl, acctResp))
5755 != NS_LDAP_SUCCESS)
5756 goto out;
5758 rc = NS_LDAP_SUCCESS;
5760 out:
5761 delete_search_cookie(cookie);
5763 return (rc);
5767 * __ns_ldap_getAcctMgmt() is called from pam account management stack
5768 * for retrieving accounting information of users with no user password -
5769 * eg. rlogin, rsh, etc. This function uses the account management control
5770 * request to do a search on the server for the user in question. The
5771 * response control returned from the server is got from the cookie.
5772 * Input params: username of whose account mgmt information is to be got
5773 * pointer to hold the parsed account management information
5774 * Return values: NS_LDAP_SUCCESS on success or appropriate error
5775 * code on failure
5778 __ns_ldap_getAcctMgmt(const char *user, AcctUsableResponse_t *acctResp)
5780 ns_conn_user_t *cu = NULL;
5781 int try_cnt = 0;
5782 int rc = NS_LDAP_SUCCESS;
5783 ns_ldap_error_t *error = NULL;
5785 for (;;) {
5786 if (__s_api_setup_retry_search(&cu, NS_CONN_USER_SEARCH,
5787 &try_cnt, &rc, &error) == 0)
5788 break;
5789 rc = getAcctMgmt(user, acctResp, cu);
5791 return (rc);