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]
22 * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
26 #include <sys/types.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
[] = {
50 static int validate_filter(ns_ldap_cookie_t
*cookie
);
53 __ns_ldap_freeEntry(ns_ldap_entry_t
*ep
)
60 if (ep
->attr_pair
== NULL
) {
64 for (j
= 0; j
< ep
->attr_count
; j
++) {
65 if (ep
->attr_pair
[j
] == NULL
)
67 if (ep
->attr_pair
[j
]->attrname
)
68 free(ep
->attr_pair
[j
]->attrname
);
69 if (ep
->attr_pair
[j
]->attrvalue
) {
70 for (k
= 0; (k
< ep
->attr_pair
[j
]->value_count
) &&
71 (ep
->attr_pair
[j
]->attrvalue
[k
]); k
++) {
72 free(ep
->attr_pair
[j
]->attrvalue
[k
]);
74 free(ep
->attr_pair
[j
]->attrvalue
);
76 free(ep
->attr_pair
[j
]);
83 _freeControlList(LDAPControl
***ctrls
)
87 if (ctrls
== NULL
|| *ctrls
== NULL
)
90 for (ctrl
= *ctrls
; *ctrl
!= NULL
; ctrl
++)
91 ldap_control_free(*ctrl
);
96 * Convert attribute type in a RDN that has an attribute mapping to the
97 * original mappped type.
99 * cn<->cn-st and iphostnumber<->iphostnumber-st
100 * cn-st=aaa+iphostnumber-st=10.10.01.01
102 * cn=aaa+iphostnumber=10.10.01.01
104 * Input - service: e.g. hosts, passwd etc.
106 * Return: NULL - No attribute mapping in the RDN
107 * Non-NULL - The attribute type(s) in the RDN are mapped and
108 * the memory is allocated for the new rdn.
112 _cvtRDN(const char *service
, const char *rdn
) {
113 char **attrs
, **mapped_attrs
, **mapp
, *type
, *value
, *attr
;
114 char *new_rdn
= NULL
;
115 int nAttr
= 0, i
, attr_mapped
, len
= 0;
117 /* Break down "type=value\0" pairs. Assume RDN is normalized */
118 if ((attrs
= ldap_explode_rdn(rdn
, 0)) == NULL
)
121 for (nAttr
= 0; attrs
[nAttr
] != NULL
; nAttr
++);
123 if ((mapped_attrs
= (char **)calloc(nAttr
, sizeof (char *))) == NULL
) {
124 ldap_value_free(attrs
);
129 for (i
= 0; i
< nAttr
; i
++) {
130 /* Parse type=value pair */
131 if ((type
= strtok_r(attrs
[i
], "=", &value
)) == NULL
||
134 /* Reverse map: e.g. cn-sm -> cn */
135 mapp
= __ns_ldap_getOrigAttribute(service
, type
);
136 if (mapp
!= NULL
&& mapp
[0] != NULL
) {
137 /* The attribute mapping is found */
142 len
= strlen(type
) + strlen(value
) + 2;
144 /* Reconstruct type=value pair. A string is allocated */
145 if ((attr
= (char *)calloc(1, len
)) == NULL
) {
146 __s_api_free2dArray(mapp
);
149 (void) snprintf(attr
, len
, "%s=%s",
151 mapped_attrs
[i
] = attr
;
154 * No attribute mapping. attrs[i] is going to be copied
155 * later. Restore "type\0value\0" back to
158 type
[strlen(type
)] = '=';
160 __s_api_free2dArray(mapp
);
162 if (attr_mapped
== 0)
163 /* No attribute mapping. Don't bother to reconstruct RDN */
167 /* Reconstruct RDN from type=value pairs */
168 for (i
= 0; i
< nAttr
; i
++) {
170 len
+= strlen(mapped_attrs
[i
]);
172 len
+= strlen(attrs
[i
]);
176 if ((new_rdn
= (char *)calloc(1, ++len
)) == NULL
)
178 for (i
= 0; i
< nAttr
; i
++) {
181 (void) strlcat(new_rdn
, "+", len
);
184 (void) strlcat(new_rdn
, mapped_attrs
[i
], len
);
186 (void) strlcat(new_rdn
, attrs
[i
], len
);
190 ldap_value_free(attrs
);
193 for (i
= 0; i
< nAttr
; i
++) {
195 free(mapped_attrs
[i
]);
204 * Convert attribute type in a DN that has an attribute mapping to the
205 * original mappped type.
207 * The mappings are cn<->cn-sm, iphostnumber<->iphostnumber-sm
209 * dn: cn-sm=aaa+iphostnumber-sm=9.9.9.9,dc=central,dc=sun,dc=com
211 * dn: cn=aaa+iphostnumber=9.9.9.9,dc=central,dc=sun,dc=com
213 * Input - service: e.g. hosts, passwd etc.
214 * dn: the value of a distinguished name
215 * Return - NULL: error
216 * non-NULL: A converted DN and the memory is allocated
219 _cvtDN(const char *service
, const char *dn
) {
221 char **rdns
, *new_rdn
, *new_dn
= NULL
;
222 int nRdn
= 0, i
, len
= 0, rdn_mapped
;
224 if (service
== NULL
|| dn
== NULL
)
227 if ((rdns
= ldap_explode_dn(dn
, 0)) == NULL
)
230 for (nRdn
= 0; rdns
[nRdn
] != NULL
; nRdn
++);
232 if ((mapped_rdns
= (char **)calloc(nRdn
, sizeof (char *))) == NULL
) {
233 ldap_value_free(rdns
);
238 /* Break down RDNs in a DN */
239 for (i
= 0; i
< nRdn
; i
++) {
240 if ((new_rdn
= _cvtRDN(service
, rdns
[i
])) != NULL
) {
241 mapped_rdns
[i
] = new_rdn
;
245 if (rdn_mapped
== 0) {
247 * No RDN contains any attribute mapping.
248 * Don't bother to reconstruct DN from RDN. Copy DN directly.
254 * Reconstruct dn from RDNs.
255 * Calculate the length first.
257 for (i
= 0; i
< nRdn
; i
++) {
259 len
+= strlen(mapped_rdns
[i
]);
261 len
+= strlen(rdns
[i
]);
266 if ((new_dn
= (char *)calloc(1, ++len
)) == NULL
)
268 for (i
= 0; i
< nRdn
; i
++) {
271 (void) strlcat(new_dn
, ",", len
);
274 (void) strlcat(new_dn
, mapped_rdns
[i
], len
);
276 (void) strlcat(new_dn
, rdns
[i
], len
);
281 ldap_value_free(rdns
);
284 for (i
= 0; i
< nRdn
; i
++) {
286 free(mapped_rdns
[i
]);
295 * Convert a single ldap entry from a LDAPMessage
296 * into an ns_ldap_entry structure.
297 * Schema map the entry if specified in flags
301 __s_api_cvtEntry(LDAP
*ld
,
305 ns_ldap_entry_t
**ret
,
306 ns_ldap_error_t
**error
)
309 ns_ldap_entry_t
*ep
= NULL
;
310 ns_ldap_attr_t
**ap
= NULL
;
318 char **gecos_mapping
= NULL
;
319 int gecos_val_index
[3] = { -1, -1, -1};
320 char errstr
[MAXERROR
];
321 int schema_mapping_existed
= FALSE
;
322 int gecos_mapping_existed
= FALSE
;
323 int gecos_attr_matched
;
324 int auto_service
= FALSE
;
325 int rc
= NS_LDAP_SUCCESS
;
327 if (e
== NULL
|| ret
== NULL
|| error
== NULL
)
328 return (NS_LDAP_INVALID_PARAM
);
332 ep
= (ns_ldap_entry_t
*)calloc(1, sizeof (ns_ldap_entry_t
));
334 return (NS_LDAP_MEMORY
);
336 if (service
!= NULL
&&
337 (strncasecmp(service
, "auto_", 5) == 0 ||
338 strcasecmp(service
, "automount") == 0))
341 * see if schema mapping existed for the given service
343 mapping
= __ns_ldap_getOrigAttribute(service
,
344 NS_HASH_SCHEMA_MAPPING_EXISTED
);
346 schema_mapping_existed
= TRUE
;
347 __s_api_free2dArray(mapping
);
349 } else if (auto_service
) {
351 * If service == auto_* and no
352 * schema mapping found
354 * There is certain case that schema mapping exist
355 * but __ns_ldap_getOrigAttribute(service,
356 * NS_HASH_SCHEMA_MAPPING_EXISTED);
359 * NS_LDAP_ATTRIBUTEMAP = automount:automountMapName=AAA
360 * NS_LDAP_OBJECTCLASSMAP = automount:automountMap=MynisMap
361 * NS_LDAP_OBJECTCLASSMAP = automount:automount=MynisObject
363 * Make a check for schema_mapping_existed here
364 * so later on __s_api_convert_automountmapname won't be called
365 * unnecessarily. It is also used for attribute mapping
366 * and objectclass mapping.
368 mapping
= __ns_ldap_getOrigAttribute("automount",
369 NS_HASH_SCHEMA_MAPPING_EXISTED
);
371 schema_mapping_existed
= TRUE
;
372 __s_api_free2dArray(mapping
);
377 nAttrs
= 1; /* start with 1 for the DN attr */
378 for (attr
= ldap_first_attribute(ld
, e
, &ber
); attr
!= NULL
;
379 attr
= ldap_next_attribute(ld
, e
, ber
)) {
387 ep
->attr_count
= nAttrs
;
390 * add 1 for "gecos" 1 to N attribute mapping,
391 * just in case it is needed.
392 * ep->attr_count will be updated later if that is true.
394 ap
= (ns_ldap_attr_t
**)calloc(ep
->attr_count
+ 1,
395 sizeof (ns_ldap_attr_t
*));
397 __ns_ldap_freeEntry(ep
);
399 return (NS_LDAP_MEMORY
);
404 dn
= ldap_get_dn(ld
, e
);
405 ap
[0] = (ns_ldap_attr_t
*)calloc(1, sizeof (ns_ldap_attr_t
));
409 __ns_ldap_freeEntry(ep
);
411 return (NS_LDAP_MEMORY
);
414 if ((ap
[0]->attrname
= strdup("dn")) == NULL
) {
417 __ns_ldap_freeEntry(ep
);
419 return (NS_LDAP_INVALID_PARAM
);
421 ap
[0]->value_count
= 1;
422 if ((ap
[0]->attrvalue
= (char **)
423 calloc(2, sizeof (char *))) == NULL
) {
426 __ns_ldap_freeEntry(ep
);
428 return (NS_LDAP_MEMORY
);
431 if (schema_mapping_existed
&& ((flags
& NS_LDAP_NOT_CVT_DN
) == 0))
432 ap
[0]->attrvalue
[0] = _cvtDN(service
, dn
);
434 ap
[0]->attrvalue
[0] = strdup(dn
);
436 if (ap
[0]->attrvalue
[0] == NULL
) {
439 __ns_ldap_freeEntry(ep
);
441 return (NS_LDAP_MEMORY
);
446 if ((flags
& NS_LDAP_NOMAP
) == 0 && auto_service
&&
447 schema_mapping_existed
) {
448 rc
= __s_api_convert_automountmapname(service
,
449 &ap
[0]->attrvalue
[0],
451 if (rc
!= NS_LDAP_SUCCESS
) {
452 __ns_ldap_freeEntry(ep
);
458 /* other attributes */
459 for (attr
= ldap_first_attribute(ld
, e
, &ber
), j
= 1;
460 attr
!= NULL
&& j
!= nAttrs
;
461 attr
= ldap_next_attribute(ld
, e
, ber
), j
++) {
462 /* allocate new attr name */
464 if ((ap
[j
] = (ns_ldap_attr_t
*)
465 calloc(1, sizeof (ns_ldap_attr_t
))) == NULL
) {
468 __ns_ldap_freeEntry(ep
);
471 __s_api_free2dArray(gecos_mapping
);
472 gecos_mapping
= NULL
;
473 return (NS_LDAP_MEMORY
);
476 if ((flags
& NS_LDAP_NOMAP
) || schema_mapping_existed
== FALSE
)
479 mapping
= __ns_ldap_getOrigAttribute(service
, attr
);
481 if (mapping
== NULL
&& auto_service
&&
482 schema_mapping_existed
&& (flags
& NS_LDAP_NOMAP
) == 0)
484 * if service == auto_* and no schema mapping found
485 * and schema_mapping_existed is TRUE and NS_LDAP_NOMAP
486 * is not set then try automount e.g.
487 * NS_LDAP_ATTRIBUTEMAP = automount:automountMapName=AAA
489 mapping
= __ns_ldap_getOrigAttribute("automount",
492 if (mapping
== NULL
) {
493 if ((ap
[j
]->attrname
= strdup(attr
)) == NULL
) {
496 __ns_ldap_freeEntry(ep
);
499 __s_api_free2dArray(gecos_mapping
);
500 gecos_mapping
= NULL
;
501 return (NS_LDAP_MEMORY
);
505 * for "gecos" 1 to N mapping,
506 * do not remove the mapped attribute,
507 * just create a new gecos attribute
508 * and append it to the end of the attribute list
510 if (strcasecmp(mapping
[0], "gecos") == 0) {
511 ap
[j
]->attrname
= strdup(attr
);
512 gecos_mapping_existed
= TRUE
;
514 ap
[j
]->attrname
= strdup(mapping
[0]);
516 if (ap
[j
]->attrname
== NULL
) {
519 __ns_ldap_freeEntry(ep
);
522 __s_api_free2dArray(gecos_mapping
);
523 gecos_mapping
= NULL
;
524 return (NS_LDAP_MEMORY
);
527 * 1 to N attribute mapping processing
528 * is only done for "gecos"
531 if (strcasecmp(mapping
[0], "gecos") == 0) {
533 * get attribute mapping for "gecos",
534 * need to know the number and order of the
537 if (gecos_mapping
== NULL
) {
539 __ns_ldap_getMappedAttributes(
540 service
, mapping
[0]);
541 if (gecos_mapping
== NULL
||
542 gecos_mapping
[0] == NULL
) {
544 * this should never happens,
547 (void) sprintf(errstr
,
551 "found for attributes "
554 syslog(LOG_ERR
, "libsldap: %s",
559 __ns_ldap_freeEntry(ep
);
561 __s_api_free2dArray(mapping
);
566 gecos_mapping
= NULL
;
567 return (NS_LDAP_INTERNAL
);
572 * is this attribute the 1st, 2nd, or
573 * 3rd attr in the mapping list?
575 gecos_attr_matched
= FALSE
;
576 for (i
= 0; i
< 3 && gecos_mapping
[i
]; i
++) {
577 if (gecos_mapping
[i
] &&
578 strcasecmp(gecos_mapping
[i
],
580 gecos_val_index
[i
] = j
;
581 gecos_attr_matched
= TRUE
;
585 if (gecos_attr_matched
== FALSE
) {
588 * This should never happens,
591 (void) sprintf(errstr
,
595 "found for attributes "
598 syslog(LOG_ERR
, "libsldap: %s", errstr
);
602 __ns_ldap_freeEntry(ep
);
604 __s_api_free2dArray(mapping
);
606 __s_api_free2dArray(gecos_mapping
);
607 gecos_mapping
= NULL
;
608 return (NS_LDAP_INTERNAL
);
611 __s_api_free2dArray(mapping
);
615 if ((vals
= ldap_get_values(ld
, e
, attr
)) != NULL
) {
617 if ((ap
[j
]->value_count
=
618 ldap_count_values(vals
)) == 0) {
619 ldap_value_free(vals
);
623 ap
[j
]->attrvalue
= (char **)
624 calloc(ap
[j
]->value_count
+1,
626 if (ap
[j
]->attrvalue
== NULL
) {
629 __ns_ldap_freeEntry(ep
);
634 gecos_mapping
= NULL
;
635 return (NS_LDAP_MEMORY
);
639 /* map object classes if necessary */
640 if ((flags
& NS_LDAP_NOMAP
) == 0 &&
641 schema_mapping_existed
&& ap
[j
]->attrname
&&
642 strcasecmp(ap
[j
]->attrname
, "objectclass") == 0) {
643 for (k
= 0; k
< ap
[j
]->value_count
; k
++) {
645 __ns_ldap_getOrigObjectClass(
648 if (mapping
== NULL
&& auto_service
)
650 * if service == auto_* and no
651 * schema mapping found
655 __ns_ldap_getOrigObjectClass(
656 "automount", vals
[k
]);
658 if (mapping
== NULL
) {
659 ap
[j
]->attrvalue
[k
] =
662 ap
[j
]->attrvalue
[k
] =
664 __s_api_free2dArray(mapping
);
667 if (ap
[j
]->attrvalue
[k
] == NULL
) {
670 __ns_ldap_freeEntry(ep
);
675 gecos_mapping
= NULL
;
676 return (NS_LDAP_MEMORY
);
680 for (k
= 0; k
< ap
[j
]->value_count
; k
++) {
681 if ((ap
[j
]->attrvalue
[k
] =
682 strdup(vals
[k
])) == NULL
) {
685 __ns_ldap_freeEntry(ep
);
690 gecos_mapping
= NULL
;
691 return (NS_LDAP_MEMORY
);
696 ap
[j
]->attrvalue
[k
] = NULL
;
697 ldap_value_free(vals
);
709 __s_api_free2dArray(gecos_mapping
);
710 gecos_mapping
= NULL
;
713 /* special processing for gecos 1 to up to 3 attribute mapping */
714 if (schema_mapping_existed
&& gecos_mapping_existed
) {
718 for (i
= 0; i
< 3; i
++) {
719 k
= gecos_val_index
[i
];
722 * f is the index of the first returned
723 * attribute which "gecos" attribute mapped to
725 if (k
!= -1 && f
== -1)
728 if (k
!= -1 && ap
[k
]->value_count
> 0 &&
729 ap
[k
]->attrvalue
[0] &&
730 strlen(ap
[k
]->attrvalue
[0]) > 0) {
734 * Create and fill in the last reserved
735 * ap with the data from the "gecos"
738 ap
[nAttrs
] = (ns_ldap_attr_t
*)
740 sizeof (ns_ldap_attr_t
));
741 if (ap
[nAttrs
] == NULL
) {
742 __ns_ldap_freeEntry(ep
);
744 return (NS_LDAP_MEMORY
);
746 ap
[nAttrs
]->attrvalue
= (char **)calloc(
748 if (ap
[nAttrs
]->attrvalue
== NULL
) {
749 __ns_ldap_freeEntry(ep
);
751 return (NS_LDAP_MEMORY
);
753 /* add 1 more for a possible "," */
754 ap
[nAttrs
]->attrvalue
[0] =
756 strlen(ap
[f
]->attrvalue
[0]) +
758 if (ap
[nAttrs
]->attrvalue
[0] == NULL
) {
759 __ns_ldap_freeEntry(ep
);
761 return (NS_LDAP_MEMORY
);
763 (void) strcpy(ap
[nAttrs
]->attrvalue
[0],
764 ap
[f
]->attrvalue
[0]);
766 ap
[nAttrs
]->attrname
= strdup("gecos");
767 if (ap
[nAttrs
]->attrname
== NULL
) {
768 __ns_ldap_freeEntry(ep
);
770 return (NS_LDAP_MEMORY
);
773 ap
[nAttrs
]->value_count
= 1;
774 ep
->attr_count
= nAttrs
+ 1;
780 * realloc to add "," and
781 * ap[k]->attrvalue[0]
783 tmp
= (char *)realloc(
784 ap
[nAttrs
]->attrvalue
[0],
790 __ns_ldap_freeEntry(ep
);
792 return (NS_LDAP_MEMORY
);
794 ap
[nAttrs
]->attrvalue
[0] = tmp
;
795 (void) strcat(ap
[nAttrs
]->attrvalue
[0],
797 (void) strcat(ap
[nAttrs
]->attrvalue
[0],
798 ap
[k
]->attrvalue
[0]);
805 return (NS_LDAP_SUCCESS
);
809 __s_api_getEntry(ns_ldap_cookie_t
*cookie
)
811 ns_ldap_entry_t
*curEntry
= NULL
;
815 (void) fprintf(stderr
, "__s_api_getEntry START\n");
818 if (cookie
->resultMsg
== NULL
) {
819 return (NS_LDAP_INVALID_PARAM
);
821 ret
= __s_api_cvtEntry(cookie
->conn
->ld
, cookie
->service
,
822 cookie
->resultMsg
, cookie
->i_flags
,
823 &curEntry
, &cookie
->errorp
);
824 if (ret
!= NS_LDAP_SUCCESS
) {
828 if (cookie
->result
== NULL
) {
829 cookie
->result
= (ns_ldap_result_t
*)
830 calloc(1, sizeof (ns_ldap_result_t
));
831 if (cookie
->result
== NULL
) {
832 __ns_ldap_freeEntry(curEntry
);
834 return (NS_LDAP_MEMORY
);
836 cookie
->result
->entry
= curEntry
;
837 cookie
->nextEntry
= curEntry
;
839 cookie
->nextEntry
->next
= curEntry
;
840 cookie
->nextEntry
= curEntry
;
842 cookie
->result
->entries_count
++;
844 return (NS_LDAP_SUCCESS
);
848 __s_api_get_cachemgr_data(const char *type
,
849 const char *from
, char **to
)
853 char s_b
[DOORBUFFERSIZE
];
861 (void) fprintf(stderr
, "__s_api_get_cachemgr_data START\n");
864 * We are not going to perform DN to domain mapping
865 * in the Standalone mode
867 if (__s_api_isStandalone()) {
871 if (from
== NULL
|| from
[0] == '\0' || to
== NULL
)
875 (void) memset(space
.s_b
, 0, DOORBUFFERSIZE
);
877 space
.s_d
.ldap_call
.ldap_callnumber
= GETCACHE
;
878 (void) snprintf(space
.s_d
.ldap_call
.ldap_u
.domainname
,
879 DOORBUFFERSIZE
- sizeof (space
.s_d
.ldap_call
.ldap_callnumber
),
884 ndata
= sizeof (space
);
885 adata
= sizeof (ldap_call_t
) +
886 strlen(space
.s_d
.ldap_call
.ldap_u
.domainname
) + 1;
889 rc
= __ns_ldap_trydoorcall(&sptr
, &ndata
, &adata
);
890 if (rc
!= NS_CACHE_SUCCESS
)
893 *to
= strdup(sptr
->ldap_ret
.ldap_u
.buff
);
894 return (NS_LDAP_SUCCESS
);
898 __s_api_set_cachemgr_data(const char *type
,
899 const char *from
, const char *to
)
903 char s_b
[DOORBUFFERSIZE
];
911 (void) fprintf(stderr
, "__s_api_set_cachemgr_data START\n");
914 * We are not going to perform DN to domain mapping
915 * in the Standalone mode
917 if (__s_api_isStandalone()) {
921 if ((from
== NULL
) || (from
[0] == '\0') ||
922 (to
== NULL
) || (to
[0] == '\0'))
925 (void) memset(space
.s_b
, 0, DOORBUFFERSIZE
);
927 space
.s_d
.ldap_call
.ldap_callnumber
= SETCACHE
;
928 (void) snprintf(space
.s_d
.ldap_call
.ldap_u
.domainname
,
929 DOORBUFFERSIZE
- sizeof (space
.s_d
.ldap_call
.ldap_callnumber
),
937 ndata
= sizeof (space
);
938 adata
= sizeof (ldap_call_t
) +
939 strlen(space
.s_d
.ldap_call
.ldap_u
.domainname
) + 1;
942 rc
= __ns_ldap_trydoorcall(&sptr
, &ndata
, &adata
);
943 if (rc
!= NS_CACHE_SUCCESS
)
946 return (NS_LDAP_SUCCESS
);
951 __s_api_remove_rdn_space(char *rdn
)
953 char *tf
, *tl
, *vf
, *vl
, *eqsign
;
955 /* if no space(s) to remove, return */
956 if (strchr(rdn
, SPACETOK
) == NULL
)
959 /* if no '=' separator, return */
960 eqsign
= strchr(rdn
, '=');
967 vl
= rdn
+ strlen(rdn
) - 1;
969 /* now two strings, type and value */
972 /* remove type's leading spaces */
973 while (tf
< tl
&& *tf
== SPACETOK
)
975 /* remove type's trailing spaces */
976 while (tf
< tl
&& *tl
== SPACETOK
)
978 /* add '=' separator back */
980 /* remove value's leading spaces */
981 while (vf
< vl
&& *vf
== SPACETOK
)
983 /* remove value's trailing spaces */
984 while (vf
< vl
&& *vl
== SPACETOK
)
987 /* move value up if necessary */
989 (void) strcpy(tl
+ 1, vf
);
996 init_search_state_machine()
998 ns_ldap_cookie_t
*cookie
;
1001 cookie
= (ns_ldap_cookie_t
*)calloc(1, sizeof (ns_ldap_cookie_t
));
1004 cookie
->state
= INIT
;
1005 /* assign other state variables */
1006 cfg
= __s_api_loadrefresh_config();
1007 cookie
->connectionId
= -1;
1009 cfg
->paramList
[NS_LDAP_SEARCH_TIME_P
].ns_ptype
== NS_UNKNOWN
) {
1010 cookie
->search_timeout
.tv_sec
= NS_DEFAULT_SEARCH_TIMEOUT
;
1012 cookie
->search_timeout
.tv_sec
=
1013 cfg
->paramList
[NS_LDAP_SEARCH_TIME_P
].ns_i
;
1016 __s_api_release_config(cfg
);
1017 cookie
->search_timeout
.tv_usec
= 0;
1023 delete_search_cookie(ns_ldap_cookie_t
*cookie
)
1027 if (cookie
->connectionId
> -1)
1028 DropConnection(cookie
->connectionId
, cookie
->i_flags
);
1030 free(cookie
->filter
);
1031 if (cookie
->i_filter
)
1032 free(cookie
->i_filter
);
1033 if (cookie
->service
)
1034 free(cookie
->service
);
1036 (void) __ns_ldap_freeSearchDescriptors(&(cookie
->sdlist
));
1038 (void) __ns_ldap_freeResult(&cookie
->result
);
1039 if (cookie
->attribute
)
1040 __s_api_free2dArray(cookie
->attribute
);
1042 (void) __ns_ldap_freeError(&cookie
->errorp
);
1043 if (cookie
->reflist
)
1044 __s_api_deleteRefInfo(cookie
->reflist
);
1046 free(cookie
->basedn
);
1047 if (cookie
->ctrlCookie
)
1048 ber_bvfree(cookie
->ctrlCookie
);
1049 _freeControlList(&cookie
->p_serverctrls
);
1050 if (cookie
->resultctrl
)
1051 ldap_controls_free(cookie
->resultctrl
);
1056 get_mapped_filter(ns_ldap_cookie_t
*cookie
, char **new_filter
)
1059 typedef struct filter_mapping_info
{
1067 } filter_mapping_info_t
;
1069 char *c
, *last_copied
;
1070 char *filter_c
, *filter_c_next
;
1071 char *key
, *tail
, *head
;
1072 char errstr
[MAXERROR
];
1073 int num_eq
= 0, num_veq
= 0;
1074 int in_quote
= FALSE
;
1075 int is_value
= FALSE
;
1076 int i
, j
, oc_len
, len
;
1077 int at_least_one
= FALSE
;
1078 filter_mapping_info_t
**info
, *info1
;
1080 char *service
, *filter
, *err
;
1081 int auto_service
= FALSE
;
1083 if (cookie
== NULL
|| new_filter
== NULL
)
1084 return (NS_LDAP_INVALID_PARAM
);
1087 service
= cookie
->service
;
1088 filter
= cookie
->filter
;
1091 * count the number of '=' char
1093 for (c
= filter
; *c
; c
++) {
1094 if (*c
== TOKENSEPARATOR
)
1098 if (service
!= NULL
&& strncasecmp(service
, "auto_", 5) == 0)
1099 auto_service
= TRUE
;
1102 * See if schema mapping existed for the given service.
1103 * If not, just return success.
1105 mapping
= __ns_ldap_getOrigAttribute(service
,
1106 NS_HASH_SCHEMA_MAPPING_EXISTED
);
1108 if (mapping
== NULL
&& auto_service
)
1110 * if service == auto_* and no
1111 * schema mapping found
1112 * then try automount
1114 mapping
= __ns_ldap_getOrigAttribute(
1115 "automount", NS_HASH_SCHEMA_MAPPING_EXISTED
);
1118 __s_api_free2dArray(mapping
);
1120 return (NS_LDAP_SUCCESS
);
1123 * no '=' sign, just say OK and return nothing
1126 return (NS_LDAP_SUCCESS
);
1129 * Make a copy of the filter string
1130 * for saving the name of the objectclasses or
1131 * attributes that need to be passed to the
1132 * objectclass or attribute mapping functions.
1133 * pointer "info->from_name" points to the locations
1134 * within this string.
1136 * The input filter string, filter, will be used
1137 * to indicate where these names start and end.
1138 * pointers "info->name_start" and "info->name_end"
1139 * point to locations within the input filter string,
1140 * and are used at the end of this function to
1141 * merge the original filter data with the
1142 * mapped objectclass or attribute names.
1144 filter_c
= strdup(filter
);
1145 if (filter_c
== NULL
)
1146 return (NS_LDAP_MEMORY
);
1147 filter_c_next
= filter_c
;
1150 * get memory for info arrays
1152 info
= (filter_mapping_info_t
**)calloc(num_eq
+ 1,
1153 sizeof (filter_mapping_info_t
*));
1157 return (NS_LDAP_MEMORY
);
1161 * find valid '=' for further processing,
1162 * ignore the "escaped =" (.i.e. "\="), or
1163 * "=" in quoted string
1165 for (c
= filter_c
; *c
; c
++) {
1168 case TOKENSEPARATOR
:
1169 if (!in_quote
&& !is_value
) {
1170 info1
= (filter_mapping_info_t
*)calloc(1,
1171 sizeof (filter_mapping_info_t
));
1174 for (i
= 0; i
< num_veq
; i
++)
1177 return (NS_LDAP_MEMORY
);
1179 info
[num_veq
] = info1
;
1182 * remember the location of this "="
1184 info
[num_veq
++]->veq_pos
= c
;
1187 * skip until the end of the attribute value
1194 * mark the end of the attribute value
1201 * switch on/off the in_quote mode
1203 in_quote
= (in_quote
== FALSE
);
1207 * ignore escape characters
1208 * don't skip if next char is '\0'
1219 * for each valid "=" found, get the name to
1222 oc_len
= strlen("objectclass");
1223 for (i
= 0; i
< num_veq
; i
++) {
1226 * look at the left side of "=" to see
1227 * if assertion is "objectclass=<ocname>"
1228 * or "<attribute name>=<attribute value>"
1230 * first skip spaces before "=".
1231 * Note that filter_c_next may not point to the
1232 * start of the filter string. For i > 0,
1233 * it points to the end of the last name processed + 2
1235 for (tail
= info
[i
]->veq_pos
; (tail
> filter_c_next
) &&
1236 (*(tail
- 1) == SPACETOK
); tail
--)
1240 * mark the end of the left side string (the key)
1243 info
[i
]->name_end
= tail
- filter_c
- 1 + filter
;
1246 * find the start of the key
1248 key
= filter_c_next
;
1249 for (c
= tail
; filter_c_next
<= c
; c
--) {
1250 /* OPARATOK is '(' */
1251 if (*c
== OPARATOK
||
1257 info
[i
]->name_start
= key
- filter_c
+ filter
;
1259 if ((key
+ oc_len
) <= tail
) {
1260 if (strncasecmp(key
, "objectclass",
1263 * assertion is "objectclass=ocname",
1264 * ocname is the one needs to be mapped
1266 * skip spaces after "=" to find start
1269 head
= info
[i
]->veq_pos
;
1270 for (head
= info
[i
]->veq_pos
+ 1;
1271 *head
&& *head
== SPACETOK
; head
++)
1274 /* ignore empty ocname */
1278 info
[i
]->name_start
= head
- filter_c
+
1282 * now find the end of the ocname
1284 for (c
= head
; ; c
++) {
1285 /* CPARATOK is ')' */
1286 if (*c
== CPARATOK
||
1293 filter_c_next
= c
+ 1;
1294 info
[i
]->oc_or_attr
= 'o';
1295 info
[i
]->from_name
= head
;
1303 * assertion is not "objectclass=ocname",
1304 * assume assertion is "<key> = <value>",
1305 * <key> is the one needs to be mapped
1307 if (info
[i
]->from_name
== NULL
&& strlen(key
) > 0) {
1308 info
[i
]->oc_or_attr
= 'a';
1309 info
[i
]->from_name
= key
;
1313 /* perform schema mapping */
1314 for (i
= 0; i
< num_veq
; i
++) {
1315 if (info
[i
]->from_name
== NULL
)
1318 if (info
[i
]->oc_or_attr
== 'a')
1320 __ns_ldap_getMappedAttributes(service
,
1321 info
[i
]->from_name
);
1324 __ns_ldap_getMappedObjectClass(service
,
1325 info
[i
]->from_name
);
1327 if (info
[i
]->mapping
== NULL
&& auto_service
) {
1329 * If no mapped attribute/objectclass is found
1330 * and service == auto*
1331 * try to find automount's
1332 * mapped attribute/objectclass
1334 if (info
[i
]->oc_or_attr
== 'a')
1336 __ns_ldap_getMappedAttributes("automount",
1337 info
[i
]->from_name
);
1340 __ns_ldap_getMappedObjectClass("automount",
1341 info
[i
]->from_name
);
1344 if (info
[i
]->mapping
== NULL
||
1345 info
[i
]->mapping
[0] == NULL
) {
1346 info
[i
]->to_name
= NULL
;
1347 } else if (info
[i
]->mapping
[1] == NULL
) {
1348 info
[i
]->to_name
= info
[i
]->mapping
[0];
1349 at_least_one
= TRUE
;
1351 __s_api_free2dArray(info
[i
]->mapping
);
1356 (void) sprintf(errstr
,
1358 "Multiple attribute or objectclass "
1359 "mapping for '%s' in filter "
1360 "'%s' not allowed."),
1361 info
[i
]->from_name
, filter
);
1362 err
= strdup(errstr
);
1364 MKERROR(LOG_WARNING
, cookie
->errorp
,
1369 for (j
= 0; j
< num_veq
; j
++) {
1370 if (info
[j
]->mapping
)
1371 __s_api_free2dArray(
1376 return (NS_LDAP_CONFIG
);
1383 len
= strlen(filter
);
1384 last_copied
= filter
- 1;
1386 for (i
= 0; i
< num_veq
; i
++) {
1387 if (info
[i
]->to_name
)
1388 len
+= strlen(info
[i
]->to_name
);
1391 *new_filter
= (char *)calloc(1, len
);
1392 if (*new_filter
== NULL
) {
1394 for (j
= 0; j
< num_veq
; j
++) {
1395 if (info
[j
]->mapping
)
1396 __s_api_free2dArray(
1401 return (NS_LDAP_MEMORY
);
1404 for (i
= 0; i
< num_veq
; i
++) {
1405 if (info
[i
]->to_name
!= NULL
&&
1406 info
[i
]->to_name
!= NULL
) {
1409 * copy the original filter data
1410 * between the last name and current
1413 if ((last_copied
+ 1) != info
[i
]->name_start
)
1414 (void) strncat(*new_filter
,
1416 info
[i
]->name_start
-
1419 /* the data is copied */
1420 last_copied
= info
[i
]->name_end
;
1423 * replace the name with
1426 (void) strcat(*new_filter
, info
[i
]->to_name
);
1429 /* copy the filter data after the last name */
1430 if (i
== (num_veq
-1) &&
1432 (filter
+ strlen(filter
)))
1433 (void) strncat(*new_filter
, last_copied
+ 1,
1434 filter
+ strlen(filter
) -
1442 for (j
= 0; j
< num_veq
; j
++) {
1443 if (info
[j
]->mapping
)
1444 __s_api_free2dArray(info
[j
]->mapping
);
1449 return (NS_LDAP_SUCCESS
);
1453 setup_next_search(ns_ldap_cookie_t
*cookie
)
1455 ns_ldap_search_desc_t
*dptr
;
1462 dptr
= *cookie
->sdpos
;
1463 scope
= cookie
->i_flags
& (NS_LDAP_SCOPE_BASE
|
1464 NS_LDAP_SCOPE_ONELEVEL
|
1465 NS_LDAP_SCOPE_SUBTREE
);
1467 cookie
->scope
= scope
;
1469 cookie
->scope
= dptr
->scope
;
1470 switch (cookie
->scope
) {
1471 case NS_LDAP_SCOPE_BASE
:
1472 cookie
->scope
= LDAP_SCOPE_BASE
;
1474 case NS_LDAP_SCOPE_ONELEVEL
:
1475 cookie
->scope
= LDAP_SCOPE_ONELEVEL
;
1477 case NS_LDAP_SCOPE_SUBTREE
:
1478 cookie
->scope
= LDAP_SCOPE_SUBTREE
;
1483 if (cookie
->use_filtercb
&& cookie
->init_filter_cb
&&
1484 dptr
->filter
&& strlen(dptr
->filter
) > 0) {
1485 (*cookie
->init_filter_cb
)(dptr
, &filter
,
1488 if (filter
== NULL
) {
1489 if (cookie
->i_filter
== NULL
) {
1490 cookie
->err_rc
= NS_LDAP_INVALID_PARAM
;
1494 free(cookie
->filter
);
1495 cookie
->filter
= strdup(cookie
->i_filter
);
1496 if (cookie
->filter
== NULL
) {
1497 cookie
->err_rc
= NS_LDAP_MEMORY
;
1503 free(cookie
->filter
);
1504 cookie
->filter
= strdup(filter
);
1506 if (cookie
->filter
== NULL
) {
1507 cookie
->err_rc
= NS_LDAP_MEMORY
;
1513 * perform attribute/objectclass mapping on filter
1517 if (cookie
->service
) {
1518 rc
= get_mapped_filter(cookie
, &filter
);
1519 if (rc
!= NS_LDAP_SUCCESS
) {
1520 cookie
->err_rc
= rc
;
1524 * get_mapped_filter returns
1525 * NULL filter pointer, if
1526 * no mapping was done
1529 free(cookie
->filter
);
1530 cookie
->filter
= filter
;
1536 * validate filter to make sure it's legal
1537 * [remove redundant ()'s]
1539 rc
= validate_filter(cookie
);
1540 if (rc
!= NS_LDAP_SUCCESS
) {
1541 cookie
->err_rc
= rc
;
1545 baselen
= strlen(dptr
->basedn
);
1546 if (baselen
> 0 && dptr
->basedn
[baselen
-1] == COMMATOK
) {
1547 rc
= __ns_ldap_getParam(NS_LDAP_SEARCH_BASEDN_P
,
1548 (void ***)¶m
, &cookie
->errorp
);
1549 if (rc
!= NS_LDAP_SUCCESS
) {
1550 cookie
->err_rc
= rc
;
1553 str
= ((char **)param
)[0];
1554 baselen
+= strlen(str
)+1;
1556 free(cookie
->basedn
);
1557 cookie
->basedn
= (char *)malloc(baselen
);
1558 if (cookie
->basedn
== NULL
) {
1559 cookie
->err_rc
= NS_LDAP_MEMORY
;
1562 (void) strcpy(cookie
->basedn
, dptr
->basedn
);
1563 (void) strcat(cookie
->basedn
, str
);
1564 (void) __ns_ldap_freeParam(¶m
);
1567 free(cookie
->basedn
);
1568 cookie
->basedn
= strdup(dptr
->basedn
);
1574 setup_referral_search(ns_ldap_cookie_t
*cookie
)
1576 ns_referral_info_t
*ref
;
1578 ref
= cookie
->refpos
;
1579 cookie
->scope
= ref
->refScope
;
1580 if (cookie
->filter
) {
1581 free(cookie
->filter
);
1583 cookie
->filter
= strdup(ref
->refFilter
);
1584 if (cookie
->basedn
) {
1585 free(cookie
->basedn
);
1587 cookie
->basedn
= strdup(ref
->refDN
);
1588 if (cookie
->filter
== NULL
|| cookie
->basedn
== NULL
) {
1589 cookie
->err_rc
= NS_LDAP_MEMORY
;
1596 get_current_session(ns_ldap_cookie_t
*cookie
)
1598 ConnectionID connectionId
= -1;
1599 Connection
*conp
= NULL
;
1601 int fail_if_new_pwd_reqd
= 1;
1603 rc
= __s_api_getConnection(NULL
, cookie
->i_flags
,
1604 cookie
->i_auth
, &connectionId
, &conp
,
1605 &cookie
->errorp
, fail_if_new_pwd_reqd
,
1606 cookie
->nopasswd_acct_mgmt
, cookie
->conn_user
);
1609 * If password control attached in *cookie->errorp,
1610 * e.g. rc == NS_LDAP_SUCCESS_WITH_INFO,
1611 * free the error structure (we do not need
1612 * the sec_to_expired info).
1613 * Reset rc to NS_LDAP_SUCCESS.
1615 if (rc
== NS_LDAP_SUCCESS_WITH_INFO
) {
1616 (void) __ns_ldap_freeError(
1618 cookie
->errorp
= NULL
;
1619 rc
= NS_LDAP_SUCCESS
;
1622 if (rc
!= NS_LDAP_SUCCESS
) {
1623 cookie
->err_rc
= rc
;
1626 cookie
->conn
= conp
;
1627 cookie
->connectionId
= connectionId
;
1633 get_next_session(ns_ldap_cookie_t
*cookie
)
1635 ConnectionID connectionId
= -1;
1636 Connection
*conp
= NULL
;
1638 int fail_if_new_pwd_reqd
= 1;
1640 if (cookie
->connectionId
> -1) {
1641 DropConnection(cookie
->connectionId
, cookie
->i_flags
);
1642 cookie
->connectionId
= -1;
1645 /* If using a MT connection, return it. */
1646 if (cookie
->conn_user
!= NULL
&&
1647 cookie
->conn_user
->conn_mt
!= NULL
)
1648 __s_api_conn_mt_return(cookie
->conn_user
);
1650 rc
= __s_api_getConnection(NULL
, cookie
->i_flags
,
1651 cookie
->i_auth
, &connectionId
, &conp
,
1652 &cookie
->errorp
, fail_if_new_pwd_reqd
,
1653 cookie
->nopasswd_acct_mgmt
, cookie
->conn_user
);
1656 * If password control attached in *cookie->errorp,
1657 * e.g. rc == NS_LDAP_SUCCESS_WITH_INFO,
1658 * free the error structure (we do not need
1659 * the sec_to_expired info).
1660 * Reset rc to NS_LDAP_SUCCESS.
1662 if (rc
== NS_LDAP_SUCCESS_WITH_INFO
) {
1663 (void) __ns_ldap_freeError(
1665 cookie
->errorp
= NULL
;
1666 rc
= NS_LDAP_SUCCESS
;
1669 if (rc
!= NS_LDAP_SUCCESS
) {
1670 cookie
->err_rc
= rc
;
1673 cookie
->conn
= conp
;
1674 cookie
->connectionId
= connectionId
;
1679 get_referral_session(ns_ldap_cookie_t
*cookie
)
1681 ConnectionID connectionId
= -1;
1682 Connection
*conp
= NULL
;
1684 int fail_if_new_pwd_reqd
= 1;
1686 if (cookie
->connectionId
> -1) {
1687 DropConnection(cookie
->connectionId
, cookie
->i_flags
);
1688 cookie
->connectionId
= -1;
1691 /* set it up to use a connection opened for referral */
1692 if (cookie
->conn_user
!= NULL
) {
1693 /* If using a MT connection, return it. */
1694 if (cookie
->conn_user
->conn_mt
!= NULL
)
1695 __s_api_conn_mt_return(cookie
->conn_user
);
1696 cookie
->conn_user
->referral
= B_TRUE
;
1699 rc
= __s_api_getConnection(cookie
->refpos
->refHost
, 0,
1700 cookie
->i_auth
, &connectionId
, &conp
,
1701 &cookie
->errorp
, fail_if_new_pwd_reqd
,
1702 cookie
->nopasswd_acct_mgmt
, cookie
->conn_user
);
1705 * If password control attached in *cookie->errorp,
1706 * e.g. rc == NS_LDAP_SUCCESS_WITH_INFO,
1707 * free the error structure (we do not need
1708 * the sec_to_expired info).
1709 * Reset rc to NS_LDAP_SUCCESS.
1711 if (rc
== NS_LDAP_SUCCESS_WITH_INFO
) {
1712 (void) __ns_ldap_freeError(
1714 cookie
->errorp
= NULL
;
1715 rc
= NS_LDAP_SUCCESS
;
1718 if (rc
!= NS_LDAP_SUCCESS
) {
1719 cookie
->err_rc
= rc
;
1722 cookie
->conn
= conp
;
1723 cookie
->connectionId
= connectionId
;
1728 paging_supported(ns_ldap_cookie_t
*cookie
)
1732 cookie
->listType
= 0;
1733 rc
= __s_api_isCtrlSupported(cookie
->conn
,
1734 LDAP_CONTROL_VLVREQUEST
);
1735 if (rc
== NS_LDAP_SUCCESS
) {
1736 cookie
->listType
= VLVCTRLFLAG
;
1739 rc
= __s_api_isCtrlSupported(cookie
->conn
,
1740 LDAP_CONTROL_SIMPLE_PAGE
);
1741 if (rc
== NS_LDAP_SUCCESS
) {
1742 cookie
->listType
= SIMPLEPAGECTRLFLAG
;
1748 typedef struct servicesorttype
{
1750 ns_srvsidesort_t type
;
1751 } servicesorttype_t
;
1753 static servicesorttype_t
*sort_type
= NULL
;
1754 static int sort_type_size
= 0;
1755 static int sort_type_hwm
= 0;
1756 static mutex_t sort_type_mutex
= DEFAULTMUTEX
;
1759 static ns_srvsidesort_t
1760 get_srvsidesort_type(char *service
)
1763 ns_srvsidesort_t type
= SSS_UNKNOWN
;
1765 if (service
== NULL
)
1768 (void) mutex_lock(&sort_type_mutex
);
1769 if (sort_type
!= NULL
) {
1770 for (i
= 0; i
< sort_type_hwm
; i
++) {
1771 if (strcmp(sort_type
[i
].service
, service
) == 0) {
1772 type
= sort_type
[i
].type
;
1777 (void) mutex_unlock(&sort_type_mutex
);
1782 update_srvsidesort_type(char *service
, ns_srvsidesort_t type
)
1785 servicesorttype_t
*tmp
;
1787 if (service
== NULL
)
1790 (void) mutex_lock(&sort_type_mutex
);
1792 for (i
= 0; i
< sort_type_hwm
; i
++) {
1793 if (strcmp(sort_type
[i
].service
, service
) == 0) {
1794 sort_type
[i
].type
= type
;
1795 (void) mutex_unlock(&sort_type_mutex
);
1799 if (sort_type
== NULL
) {
1801 tmp
= malloc(size
* sizeof (servicesorttype_t
));
1803 (void) mutex_unlock(&sort_type_mutex
);
1807 sort_type_size
= size
;
1808 } else if (sort_type_hwm
>= sort_type_size
) {
1809 size
= sort_type_size
+ 10;
1810 tmp
= realloc(sort_type
, size
* sizeof (servicesorttype_t
));
1812 (void) mutex_unlock(&sort_type_mutex
);
1816 sort_type_size
= size
;
1818 sort_type
[sort_type_hwm
].service
= strdup(service
);
1819 if (sort_type
[sort_type_hwm
].service
== NULL
) {
1820 (void) mutex_unlock(&sort_type_mutex
);
1823 sort_type
[sort_type_hwm
].type
= type
;
1826 (void) mutex_unlock(&sort_type_mutex
);
1830 setup_vlv_params(ns_ldap_cookie_t
*cookie
)
1832 LDAPControl
**ctrls
;
1833 LDAPsortkey
**sortkeylist
;
1834 LDAPControl
*sortctrl
= NULL
;
1835 LDAPControl
*vlvctrl
= NULL
;
1836 LDAPVirtualList vlist
;
1839 int free_sort
= FALSE
;
1841 _freeControlList(&cookie
->p_serverctrls
);
1843 if (cookie
->sortTypeTry
== SSS_UNKNOWN
)
1844 cookie
->sortTypeTry
= get_srvsidesort_type(cookie
->service
);
1845 if (cookie
->sortTypeTry
== SSS_UNKNOWN
)
1846 cookie
->sortTypeTry
= SSS_SINGLE_ATTR
;
1848 if (cookie
->sortTypeTry
== SSS_SINGLE_ATTR
) {
1849 if ((cookie
->i_flags
& NS_LDAP_NOMAP
) == 0 &&
1850 cookie
->i_sortattr
) {
1851 sortattr
= __ns_ldap_mapAttribute(cookie
->service
,
1852 cookie
->i_sortattr
);
1854 } else if (cookie
->i_sortattr
) {
1855 sortattr
= (char *)cookie
->i_sortattr
;
1860 sortattr
= "cn uid";
1863 rc
= ldap_create_sort_keylist(&sortkeylist
, sortattr
);
1866 if (rc
!= LDAP_SUCCESS
) {
1867 (void) ldap_get_option(cookie
->conn
->ld
,
1868 LDAP_OPT_ERROR_NUMBER
, &rc
);
1871 rc
= ldap_create_sort_control(cookie
->conn
->ld
,
1872 sortkeylist
, 1, &sortctrl
);
1873 ldap_free_sort_keylist(sortkeylist
);
1874 if (rc
!= LDAP_SUCCESS
) {
1875 (void) ldap_get_option(cookie
->conn
->ld
,
1876 LDAP_OPT_ERROR_NUMBER
, &rc
);
1880 vlist
.ldvlist_index
= cookie
->index
;
1881 vlist
.ldvlist_size
= 0;
1883 vlist
.ldvlist_before_count
= 0;
1884 vlist
.ldvlist_after_count
= LISTPAGESIZE
-1;
1885 vlist
.ldvlist_attrvalue
= NULL
;
1886 vlist
.ldvlist_extradata
= NULL
;
1888 rc
= ldap_create_virtuallist_control(cookie
->conn
->ld
,
1890 if (rc
!= LDAP_SUCCESS
) {
1891 ldap_control_free(sortctrl
);
1892 (void) ldap_get_option(cookie
->conn
->ld
, LDAP_OPT_ERROR_NUMBER
,
1897 ctrls
= (LDAPControl
**)calloc(3, sizeof (LDAPControl
*));
1898 if (ctrls
== NULL
) {
1899 ldap_control_free(sortctrl
);
1900 ldap_control_free(vlvctrl
);
1901 return (LDAP_NO_MEMORY
);
1904 ctrls
[0] = sortctrl
;
1907 cookie
->p_serverctrls
= ctrls
;
1908 return (LDAP_SUCCESS
);
1912 setup_simplepg_params(ns_ldap_cookie_t
*cookie
)
1914 LDAPControl
**ctrls
;
1915 LDAPControl
*pgctrl
= NULL
;
1918 _freeControlList(&cookie
->p_serverctrls
);
1920 rc
= ldap_create_page_control(cookie
->conn
->ld
, LISTPAGESIZE
,
1921 cookie
->ctrlCookie
, (char)0, &pgctrl
);
1922 if (rc
!= LDAP_SUCCESS
) {
1923 (void) ldap_get_option(cookie
->conn
->ld
, LDAP_OPT_ERROR_NUMBER
,
1928 ctrls
= (LDAPControl
**)calloc(2, sizeof (LDAPControl
*));
1929 if (ctrls
== NULL
) {
1930 ldap_control_free(pgctrl
);
1931 return (LDAP_NO_MEMORY
);
1934 cookie
->p_serverctrls
= ctrls
;
1935 return (LDAP_SUCCESS
);
1939 proc_result_referrals(ns_ldap_cookie_t
*cookie
)
1942 char **referrals
= NULL
;
1945 * Only follow one level of referrals, i.e.
1946 * if already in referral mode, do nothing
1948 if (cookie
->refpos
== NULL
) {
1949 cookie
->new_state
= END_RESULT
;
1950 rc
= ldap_parse_result(cookie
->conn
->ld
,
1955 if (rc
!= NS_LDAP_SUCCESS
) {
1956 (void) ldap_get_option(cookie
->conn
->ld
,
1957 LDAP_OPT_ERROR_NUMBER
,
1959 cookie
->new_state
= LDAP_ERROR
;
1962 if (errCode
== LDAP_REFERRAL
) {
1963 for (i
= 0; referrals
[i
] != NULL
;
1965 /* add to referral list */
1966 rc
= __s_api_addRefInfo(
1973 if (rc
!= NS_LDAP_SUCCESS
) {
1979 ldap_value_free(referrals
);
1985 proc_search_references(ns_ldap_cookie_t
*cookie
)
1987 char **refurls
= NULL
;
1991 * Only follow one level of referrals, i.e.
1992 * if already in referral mode, do nothing
1994 if (cookie
->refpos
== NULL
) {
1995 refurls
= ldap_get_reference_urls(
1998 if (refurls
== NULL
) {
1999 (void) ldap_get_option(cookie
->conn
->ld
,
2000 LDAP_OPT_ERROR_NUMBER
,
2002 cookie
->new_state
= LDAP_ERROR
;
2005 for (i
= 0; refurls
[i
] != NULL
; i
++) {
2006 /* add to referral list */
2007 rc
= __s_api_addRefInfo(
2014 if (rc
!= NS_LDAP_SUCCESS
) {
2020 /* free allocated storage */
2021 for (i
= 0; refurls
[i
] != NULL
; i
++)
2027 multi_result(ns_ldap_cookie_t
*cookie
)
2029 char errstr
[MAXERROR
];
2031 ns_ldap_error_t
**errorp
= NULL
;
2032 LDAPControl
**retCtrls
= NULL
;
2036 unsigned long target_posp
= 0;
2037 unsigned long list_size
= 0;
2038 unsigned int count
= 0;
2039 char **referrals
= NULL
;
2041 if (cookie
->listType
== VLVCTRLFLAG
) {
2042 rc
= ldap_parse_result(cookie
->conn
->ld
, cookie
->resultMsg
,
2043 &errCode
, NULL
, NULL
, &referrals
, &retCtrls
, 0);
2044 if (rc
!= LDAP_SUCCESS
) {
2045 (void) ldap_get_option(cookie
->conn
->ld
,
2046 LDAP_OPT_ERROR_NUMBER
,
2048 (void) sprintf(errstr
,
2049 gettext("LDAP ERROR (%d): %s.\n"),
2051 gettext(ldap_err2string(cookie
->err_rc
)));
2052 err
= strdup(errstr
);
2053 MKERROR(LOG_WARNING
, *errorp
, NS_LDAP_INTERNAL
, err
,
2055 cookie
->err_rc
= NS_LDAP_INTERNAL
;
2056 cookie
->errorp
= *errorp
;
2057 return (LDAP_ERROR
);
2059 if (errCode
== LDAP_REFERRAL
) {
2060 for (i
= 0; referrals
[i
] != NULL
;
2062 /* add to referral list */
2063 rc
= __s_api_addRefInfo(
2070 if (rc
!= NS_LDAP_SUCCESS
) {
2079 ldap_value_free(referrals
);
2081 ldap_controls_free(retCtrls
);
2082 return (END_RESULT
);
2085 rc
= ldap_parse_virtuallist_control(
2086 cookie
->conn
->ld
, retCtrls
,
2087 &target_posp
, &list_size
, &errCode
);
2088 if (rc
== LDAP_SUCCESS
) {
2090 * AD does not return valid target_posp
2093 if (target_posp
!= 0 && list_size
!= 0) {
2095 target_posp
+ LISTPAGESIZE
;
2096 if (cookie
->index
> list_size
)
2099 if (cookie
->entryCount
< LISTPAGESIZE
)
2106 ldap_controls_free(retCtrls
);
2111 } else if (cookie
->listType
== SIMPLEPAGECTRLFLAG
) {
2112 rc
= ldap_parse_result(cookie
->conn
->ld
, cookie
->resultMsg
,
2113 &errCode
, NULL
, NULL
, &referrals
, &retCtrls
, 0);
2114 if (rc
!= LDAP_SUCCESS
) {
2115 (void) ldap_get_option(cookie
->conn
->ld
,
2116 LDAP_OPT_ERROR_NUMBER
,
2118 (void) sprintf(errstr
,
2119 gettext("LDAP ERROR (%d): %s.\n"),
2121 gettext(ldap_err2string(cookie
->err_rc
)));
2122 err
= strdup(errstr
);
2123 MKERROR(LOG_WARNING
, *errorp
, NS_LDAP_INTERNAL
, err
,
2125 cookie
->err_rc
= NS_LDAP_INTERNAL
;
2126 cookie
->errorp
= *errorp
;
2127 return (LDAP_ERROR
);
2129 if (errCode
== LDAP_REFERRAL
) {
2130 for (i
= 0; referrals
[i
] != NULL
;
2132 /* add to referral list */
2133 rc
= __s_api_addRefInfo(
2140 if (rc
!= NS_LDAP_SUCCESS
) {
2149 ldap_value_free(referrals
);
2151 ldap_controls_free(retCtrls
);
2152 return (END_RESULT
);
2155 if (cookie
->ctrlCookie
)
2156 ber_bvfree(cookie
->ctrlCookie
);
2157 cookie
->ctrlCookie
= NULL
;
2158 rc
= ldap_parse_page_control(
2159 cookie
->conn
->ld
, retCtrls
,
2160 &count
, &cookie
->ctrlCookie
);
2161 if (rc
== LDAP_SUCCESS
) {
2162 if ((cookie
->ctrlCookie
== NULL
) ||
2163 (cookie
->ctrlCookie
->bv_val
== NULL
) ||
2164 (cookie
->ctrlCookie
->bv_len
== 0))
2167 ldap_controls_free(retCtrls
);
2173 if (!finished
&& cookie
->listType
== VLVCTRLFLAG
)
2175 if (!finished
&& cookie
->listType
== SIMPLEPAGECTRLFLAG
)
2178 return (END_RESULT
);
2183 * clear_results(ns_ldap_cookie_t):
2185 * Attempt to obtain remnants of ldap responses and free them. If remnants are
2186 * not obtained within a certain time period tell the server we wish to abandon
2189 * Note that we do not initially tell the server to abandon the request as that
2190 * can be an expensive operation for the server, while it is cheap for us to
2191 * just flush the input.
2193 * If something was to remain in libldap queue as a result of some error then
2194 * it would be freed later during drop connection call or when no other
2195 * requests share the connection.
2198 clear_results(ns_ldap_cookie_t
*cookie
)
2201 if (cookie
->conn
!= NULL
&& cookie
->conn
->ld
!= NULL
&&
2202 (cookie
->connectionId
!= -1 ||
2203 (cookie
->conn_user
!= NULL
&&
2204 cookie
->conn_user
->conn_mt
!= NULL
)) &&
2205 cookie
->msgId
!= 0) {
2207 * We need to cleanup the rest of response (if there is such)
2208 * and LDAP abandon is too heavy for LDAP servers, so we will
2209 * wait for the rest of response till timeout and "process" it.
2211 rc
= ldap_result(cookie
->conn
->ld
, cookie
->msgId
, LDAP_MSG_ALL
,
2212 (struct timeval
*)&cookie
->search_timeout
,
2213 &cookie
->resultMsg
);
2214 if (rc
!= -1 && rc
!= 0 && cookie
->resultMsg
!= NULL
) {
2215 (void) ldap_msgfree(cookie
->resultMsg
);
2216 cookie
->resultMsg
= NULL
;
2220 * If there was timeout then we will send ABANDON request to
2221 * LDAP server to decrease load.
2224 (void) ldap_abandon_ext(cookie
->conn
->ld
, cookie
->msgId
,
2226 /* Disassociate cookie with msgId */
2232 * This state machine performs one or more LDAP searches to a given
2233 * directory server using service search descriptors and schema
2234 * mapping as appropriate. The approximate pseudocode for
2235 * this routine is the following:
2236 * Given the current configuration [set/reset connection etc.]
2237 * and the current service search descriptor list
2238 * or default search filter parameters
2239 * foreach (service search filter) {
2240 * initialize the filter [via filter_init if appropriate]
2241 * get a valid session/connection (preferably the current one)
2242 * Recover if the connection is lost
2243 * perform the search
2244 * foreach (result entry) {
2245 * process result [via callback if appropriate]
2246 * save result for caller if accepted.
2247 * exit and return all collected if allResults found;
2250 * return collected results and exit
2255 search_state_machine(ns_ldap_cookie_t
*cookie
, ns_state_t state
, int cycle
)
2257 char errstr
[MAXERROR
];
2261 ns_ldap_entry_t
*nextEntry
;
2262 ns_ldap_error_t
*error
= NULL
;
2263 ns_ldap_error_t
**errorp
;
2267 cookie
->state
= state
;
2271 switch (cookie
->state
) {
2273 clear_results(cookie
);
2274 cookie
->new_state
= EXIT
;
2276 case GET_ACCT_MGMT_INFO
:
2278 * Set the flag to get ldap account management controls.
2280 cookie
->nopasswd_acct_mgmt
= 1;
2281 cookie
->new_state
= INIT
;
2284 /* state engine/connection cleaned up in delete */
2285 if (cookie
->attribute
) {
2286 __s_api_free2dArray(cookie
->attribute
);
2287 cookie
->attribute
= NULL
;
2289 if (cookie
->reflist
) {
2290 __s_api_deleteRefInfo(cookie
->reflist
);
2291 cookie
->reflist
= NULL
;
2295 cookie
->sdpos
= NULL
;
2296 cookie
->new_state
= NEXT_SEARCH_DESCRIPTOR
;
2297 if (cookie
->attribute
) {
2298 __s_api_free2dArray(cookie
->attribute
);
2299 cookie
->attribute
= NULL
;
2301 if ((cookie
->i_flags
& NS_LDAP_NOMAP
) == 0 &&
2304 __ns_ldap_mapAttributeList(
2310 /* Check if we've reached MAX retries. */
2312 if (cookie
->retries
> NS_LIST_TRY_MAX
- 1) {
2313 cookie
->new_state
= LDAP_ERROR
;
2318 * Even if we still have retries left, check
2319 * if retry is possible.
2321 if (cookie
->conn_user
!= NULL
) {
2323 ns_conn_mgmt_t
*cmg
;
2324 cmg
= cookie
->conn_user
->conn_mgmt
;
2325 retry
= cookie
->conn_user
->retry
;
2326 if (cmg
!= NULL
&& cmg
->cfg_reloaded
== 1)
2329 cookie
->new_state
= LDAP_ERROR
;
2334 * Free results if any, reset to the first
2335 * search descriptor and start a new session.
2337 if (cookie
->resultMsg
!= NULL
) {
2338 (void) ldap_msgfree(cookie
->resultMsg
);
2339 cookie
->resultMsg
= NULL
;
2341 (void) __ns_ldap_freeError(&cookie
->errorp
);
2342 (void) __ns_ldap_freeResult(&cookie
->result
);
2343 cookie
->sdpos
= cookie
->sdlist
;
2344 cookie
->err_from_result
= 0;
2346 cookie
->new_state
= NEXT_SESSION
;
2348 case NEXT_SEARCH_DESCRIPTOR
:
2349 /* get next search descriptor */
2350 if (cookie
->sdpos
== NULL
) {
2351 cookie
->sdpos
= cookie
->sdlist
;
2352 cookie
->new_state
= GET_SESSION
;
2355 cookie
->new_state
= NEXT_SEARCH
;
2357 if (*cookie
->sdpos
== NULL
)
2358 cookie
->new_state
= EXIT
;
2361 if (get_current_session(cookie
) < 0)
2362 cookie
->new_state
= NEXT_SESSION
;
2364 cookie
->new_state
= NEXT_SEARCH
;
2367 if (get_next_session(cookie
) < 0)
2368 cookie
->new_state
= RESTART_SESSION
;
2370 cookie
->new_state
= NEXT_SEARCH
;
2372 case RESTART_SESSION
:
2373 if (cookie
->i_flags
& NS_LDAP_HARD
) {
2374 cookie
->new_state
= NEXT_SESSION
;
2377 (void) sprintf(errstr
,
2378 gettext("Session error no available conn.\n"),
2380 err
= strdup(errstr
);
2381 MKERROR(LOG_WARNING
, *errorp
, NS_LDAP_INTERNAL
, err
,
2383 cookie
->err_rc
= NS_LDAP_INTERNAL
;
2384 cookie
->errorp
= *errorp
;
2385 cookie
->new_state
= EXIT
;
2388 /* setup referrals search if necessary */
2389 if (cookie
->refpos
) {
2390 if (setup_referral_search(cookie
) < 0) {
2391 cookie
->new_state
= EXIT
;
2394 } else if (setup_next_search(cookie
) < 0) {
2395 cookie
->new_state
= EXIT
;
2398 /* only do VLV/PAGE on scopes onelevel/subtree */
2399 if (paging_supported(cookie
)) {
2400 if (cookie
->use_paging
&&
2401 (cookie
->scope
!= LDAP_SCOPE_BASE
)) {
2403 if (cookie
->listType
== VLVCTRLFLAG
)
2404 cookie
->new_state
= NEXT_VLV
;
2406 cookie
->new_state
= NEXT_PAGE
;
2410 cookie
->new_state
= ONE_SEARCH
;
2413 rc
= setup_vlv_params(cookie
);
2414 if (rc
!= LDAP_SUCCESS
) {
2415 cookie
->err_rc
= rc
;
2416 cookie
->new_state
= LDAP_ERROR
;
2419 cookie
->next_state
= MULTI_RESULT
;
2420 cookie
->new_state
= DO_SEARCH
;
2423 rc
= setup_simplepg_params(cookie
);
2424 if (rc
!= LDAP_SUCCESS
) {
2425 cookie
->err_rc
= rc
;
2426 cookie
->new_state
= LDAP_ERROR
;
2429 cookie
->next_state
= MULTI_RESULT
;
2430 cookie
->new_state
= DO_SEARCH
;
2433 cookie
->next_state
= NEXT_RESULT
;
2434 cookie
->new_state
= DO_SEARCH
;
2437 cookie
->entryCount
= 0;
2438 rc
= ldap_search_ext(cookie
->conn
->ld
,
2444 cookie
->p_serverctrls
,
2446 &cookie
->search_timeout
, 0,
2448 if (rc
!= LDAP_SUCCESS
) {
2449 if (rc
== LDAP_BUSY
||
2450 rc
== LDAP_UNAVAILABLE
||
2451 rc
== LDAP_UNWILLING_TO_PERFORM
||
2452 rc
== LDAP_CONNECT_ERROR
||
2453 rc
== LDAP_SERVER_DOWN
) {
2455 if (cookie
->reinit_on_retriable_err
) {
2456 cookie
->err_rc
= rc
;
2457 cookie
->new_state
= REINIT
;
2463 * If not able to reach the
2464 * server, inform the ldap
2465 * cache manager that the
2466 * server should be removed
2467 * from it's server list.
2468 * Thus, the manager will not
2469 * return this server on the next
2470 * get-server request and will
2471 * also reduce the server list
2472 * refresh TTL, so that it will
2473 * find out sooner when the server
2476 if ((rc
== LDAP_CONNECT_ERROR
||
2477 rc
== LDAP_SERVER_DOWN
) &&
2478 (cookie
->conn_user
== NULL
||
2479 cookie
->conn_user
->conn_mt
==
2481 ret
= __s_api_removeServer(
2482 cookie
->conn
->serverAddr
);
2483 if (ret
== NS_CACHE_NOSERVER
&&
2484 cookie
->conn_auth_type
2485 == NS_LDAP_AUTH_NONE
) {
2488 * server from server
2491 * potential infinite
2494 cookie
->err_rc
= rc
;
2498 if (cookie
->connectionId
> -1) {
2501 * indicates that the
2510 cookie
->connectionId
=
2513 } else if ((rc
== LDAP_CONNECT_ERROR
||
2514 rc
== LDAP_SERVER_DOWN
) &&
2515 cookie
->conn_user
!= NULL
) {
2517 reinit_on_retriable_err
) {
2524 * cookie->err_rc above.
2526 __s_api_conn_mt_close(
2533 * usable, close it in
2534 * the LDAP_ERROR state.
2535 * A retry will be done
2538 cookie
->err_rc
= rc
;
2545 cookie
->err_rc
= rc
;
2546 cookie
->new_state
= LDAP_ERROR
;
2549 cookie
->new_state
= cookie
->next_state
;
2553 * Caller (e.g. __ns_ldap_list_batch_add)
2554 * does not want to block on ldap_result().
2555 * Therefore we execute ldap_result() with
2558 if (cookie
->no_wait
== B_TRUE
)
2559 (void) memset(&tv
, 0, sizeof (tv
));
2561 tv
= cookie
->search_timeout
;
2562 rc
= ldap_result(cookie
->conn
->ld
, cookie
->msgId
,
2565 &cookie
->resultMsg
);
2566 if (rc
== LDAP_RES_SEARCH_RESULT
) {
2567 cookie
->new_state
= END_RESULT
;
2568 /* check and process referrals info */
2569 if (cookie
->followRef
)
2570 proc_result_referrals(
2572 (void) ldap_msgfree(cookie
->resultMsg
);
2573 cookie
->resultMsg
= NULL
;
2576 /* handle referrals if necessary */
2577 if (rc
== LDAP_RES_SEARCH_REFERENCE
) {
2578 if (cookie
->followRef
)
2579 proc_search_references(cookie
);
2580 (void) ldap_msgfree(cookie
->resultMsg
);
2581 cookie
->resultMsg
= NULL
;
2584 if (rc
!= LDAP_RES_SEARCH_ENTRY
) {
2587 if (cookie
->no_wait
== B_TRUE
) {
2588 (void) ldap_msgfree(
2590 cookie
->resultMsg
= NULL
;
2591 return (cookie
->new_state
);
2596 rc
= ldap_get_lderrno(cookie
->conn
->ld
,
2600 rc
= ldap_result2error(cookie
->conn
->ld
,
2601 cookie
->resultMsg
, 1);
2604 if ((rc
== LDAP_TIMEOUT
||
2605 rc
== LDAP_SERVER_DOWN
) &&
2606 (cookie
->conn_user
== NULL
||
2607 cookie
->conn_user
->conn_mt
== NULL
)) {
2608 if (rc
== LDAP_TIMEOUT
)
2609 (void) __s_api_removeServer(
2610 cookie
->conn
->serverAddr
);
2611 if (cookie
->connectionId
> -1) {
2613 cookie
->connectionId
,
2615 cookie
->connectionId
= -1;
2617 cookie
->err_from_result
= 1;
2619 (void) ldap_msgfree(cookie
->resultMsg
);
2620 cookie
->resultMsg
= NULL
;
2621 if (rc
== LDAP_BUSY
||
2622 rc
== LDAP_UNAVAILABLE
||
2623 rc
== LDAP_UNWILLING_TO_PERFORM
) {
2624 if (cookie
->reinit_on_retriable_err
) {
2625 cookie
->err_rc
= rc
;
2626 cookie
->err_from_result
= 1;
2627 cookie
->new_state
= REINIT
;
2633 if ((rc
== LDAP_CONNECT_ERROR
||
2634 rc
== LDAP_SERVER_DOWN
) &&
2635 cookie
->reinit_on_retriable_err
) {
2636 ns_ldap_error_t
*errorp
= NULL
;
2637 cookie
->err_rc
= rc
;
2638 cookie
->err_from_result
= 1;
2639 cookie
->new_state
= REINIT
;
2640 if (cookie
->conn_user
!= NULL
)
2641 __s_api_conn_mt_close(
2644 if (errorp
!= NULL
) {
2645 (void) __ns_ldap_freeError(
2647 cookie
->errorp
= errorp
;
2651 cookie
->err_rc
= rc
;
2652 cookie
->new_state
= LDAP_ERROR
;
2655 /* else LDAP_RES_SEARCH_ENTRY */
2656 /* get account management response control */
2657 if (cookie
->nopasswd_acct_mgmt
== 1) {
2658 rc
= ldap_get_entry_controls(cookie
->conn
->ld
,
2660 &(cookie
->resultctrl
));
2661 if (rc
!= LDAP_SUCCESS
) {
2662 cookie
->new_state
= LDAP_ERROR
;
2663 cookie
->err_rc
= rc
;
2667 rc
= __s_api_getEntry(cookie
);
2668 (void) ldap_msgfree(cookie
->resultMsg
);
2669 cookie
->resultMsg
= NULL
;
2670 if (rc
!= NS_LDAP_SUCCESS
) {
2671 cookie
->new_state
= LDAP_ERROR
;
2674 cookie
->new_state
= PROCESS_RESULT
;
2675 cookie
->next_state
= NEXT_RESULT
;
2678 if (cookie
->no_wait
== B_TRUE
)
2679 (void) memset(&tv
, 0, sizeof (tv
));
2681 tv
= cookie
->search_timeout
;
2682 rc
= ldap_result(cookie
->conn
->ld
, cookie
->msgId
,
2685 &cookie
->resultMsg
);
2686 if (rc
== LDAP_RES_SEARCH_RESULT
) {
2687 rc
= ldap_result2error(cookie
->conn
->ld
,
2688 cookie
->resultMsg
, 0);
2689 if (rc
== LDAP_ADMINLIMIT_EXCEEDED
&&
2690 cookie
->listType
== VLVCTRLFLAG
&&
2691 cookie
->sortTypeTry
== SSS_SINGLE_ATTR
) {
2692 /* Try old "cn uid" server side sort */
2693 cookie
->sortTypeTry
= SSS_CN_UID_ATTRS
;
2694 cookie
->new_state
= NEXT_VLV
;
2695 (void) ldap_msgfree(cookie
->resultMsg
);
2696 cookie
->resultMsg
= NULL
;
2699 if (rc
!= LDAP_SUCCESS
) {
2700 cookie
->err_rc
= rc
;
2701 cookie
->new_state
= LDAP_ERROR
;
2702 (void) ldap_msgfree(cookie
->resultMsg
);
2703 cookie
->resultMsg
= NULL
;
2706 cookie
->new_state
= multi_result(cookie
);
2707 (void) ldap_msgfree(cookie
->resultMsg
);
2708 cookie
->resultMsg
= NULL
;
2711 /* handle referrals if necessary */
2712 if (rc
== LDAP_RES_SEARCH_REFERENCE
&&
2713 cookie
->followRef
) {
2714 proc_search_references(cookie
);
2715 (void) ldap_msgfree(cookie
->resultMsg
);
2716 cookie
->resultMsg
= NULL
;
2719 if (rc
!= LDAP_RES_SEARCH_ENTRY
) {
2722 if (cookie
->no_wait
== B_TRUE
) {
2723 (void) ldap_msgfree(
2725 cookie
->resultMsg
= NULL
;
2726 return (cookie
->new_state
);
2731 rc
= ldap_get_lderrno(cookie
->conn
->ld
,
2735 rc
= ldap_result2error(cookie
->conn
->ld
,
2736 cookie
->resultMsg
, 1);
2739 if ((rc
== LDAP_TIMEOUT
||
2740 rc
== LDAP_SERVER_DOWN
) &&
2741 (cookie
->conn_user
== NULL
||
2742 cookie
->conn_user
->conn_mt
== NULL
)) {
2743 if (rc
== LDAP_TIMEOUT
)
2744 (void) __s_api_removeServer(
2745 cookie
->conn
->serverAddr
);
2746 if (cookie
->connectionId
> -1) {
2748 cookie
->connectionId
,
2750 cookie
->connectionId
= -1;
2752 cookie
->err_from_result
= 1;
2754 (void) ldap_msgfree(cookie
->resultMsg
);
2755 cookie
->resultMsg
= NULL
;
2756 if (rc
== LDAP_BUSY
||
2757 rc
== LDAP_UNAVAILABLE
||
2758 rc
== LDAP_UNWILLING_TO_PERFORM
) {
2759 if (cookie
->reinit_on_retriable_err
) {
2760 cookie
->err_rc
= rc
;
2761 cookie
->err_from_result
= 1;
2762 cookie
->new_state
= REINIT
;
2769 if ((rc
== LDAP_CONNECT_ERROR
||
2770 rc
== LDAP_SERVER_DOWN
) &&
2771 cookie
->reinit_on_retriable_err
) {
2772 ns_ldap_error_t
*errorp
= NULL
;
2773 cookie
->err_rc
= rc
;
2774 cookie
->err_from_result
= 1;
2775 cookie
->new_state
= REINIT
;
2776 if (cookie
->conn_user
!= NULL
)
2777 __s_api_conn_mt_close(
2780 if (errorp
!= NULL
) {
2781 (void) __ns_ldap_freeError(
2783 cookie
->errorp
= errorp
;
2787 cookie
->err_rc
= rc
;
2788 cookie
->new_state
= LDAP_ERROR
;
2791 /* else LDAP_RES_SEARCH_ENTRY */
2792 cookie
->entryCount
++;
2793 rc
= __s_api_getEntry(cookie
);
2794 (void) ldap_msgfree(cookie
->resultMsg
);
2795 cookie
->resultMsg
= NULL
;
2796 if (rc
!= NS_LDAP_SUCCESS
) {
2797 cookie
->new_state
= LDAP_ERROR
;
2801 * If VLV search was successfull save the server
2802 * side sort type tried.
2804 if (cookie
->listType
== VLVCTRLFLAG
)
2805 update_srvsidesort_type(cookie
->service
,
2806 cookie
->sortTypeTry
);
2808 cookie
->new_state
= PROCESS_RESULT
;
2809 cookie
->next_state
= MULTI_RESULT
;
2811 case PROCESS_RESULT
:
2812 /* NOTE THIS STATE MAY BE PROCESSED BY CALLER */
2813 if (cookie
->use_usercb
&& cookie
->callback
) {
2815 for (nextEntry
= cookie
->result
->entry
;
2817 nextEntry
= nextEntry
->next
) {
2818 rc
= (*cookie
->callback
)(nextEntry
,
2821 if (rc
== NS_LDAP_CB_DONE
) {
2822 /* cb doesn't want any more data */
2823 rc
= NS_LDAP_PARTIAL
;
2824 cookie
->err_rc
= rc
;
2826 } else if (rc
!= NS_LDAP_CB_NEXT
) {
2827 /* invalid return code */
2828 rc
= NS_LDAP_OP_FAILED
;
2829 cookie
->err_rc
= rc
;
2833 (void) __ns_ldap_freeResult(&cookie
->result
);
2834 cookie
->result
= NULL
;
2837 cookie
->new_state
= EXIT
;
2840 /* NOTE PREVIOUS STATE SPECIFIES NEXT STATE */
2841 cookie
->new_state
= cookie
->next_state
;
2843 case END_PROCESS_RESULT
:
2844 cookie
->new_state
= cookie
->next_state
;
2848 * XXX DO WE NEED THIS CASE?
2849 * if (search is complete) {
2850 * cookie->new_state = EXIT;
2854 * entering referral mode if necessary
2856 if (cookie
->followRef
&& cookie
->reflist
)
2861 NEXT_SEARCH_DESCRIPTOR
;
2864 /* get next referral info */
2865 if (cookie
->refpos
== NULL
)
2870 cookie
->refpos
->next
;
2871 /* check see if done with all referrals */
2872 if (cookie
->refpos
!= NULL
)
2874 GET_REFERRAL_SESSION
;
2876 __s_api_deleteRefInfo(cookie
->reflist
);
2877 cookie
->reflist
= NULL
;
2879 NEXT_SEARCH_DESCRIPTOR
;
2880 if (cookie
->conn_user
!= NULL
)
2881 cookie
->conn_user
->referral
= B_FALSE
;
2884 case GET_REFERRAL_SESSION
:
2885 if (get_referral_session(cookie
) < 0)
2886 cookie
->new_state
= EXIT
;
2888 cookie
->new_state
= NEXT_SEARCH
;
2892 rc_save
= cookie
->err_rc
;
2893 if (cookie
->err_from_result
) {
2894 if (cookie
->err_rc
== LDAP_SERVER_DOWN
) {
2895 (void) sprintf(errstr
,
2896 gettext("LDAP ERROR (%d): "
2897 "Error occurred during"
2898 " receiving results. "
2899 "Connection to server lost."),
2901 } else if (cookie
->err_rc
== LDAP_TIMEOUT
) {
2902 (void) sprintf(errstr
,
2903 gettext("LDAP ERROR (%d): "
2904 "Error occurred during"
2905 " receiving results. %s"
2906 "."), cookie
->err_rc
,
2911 (void) sprintf(errstr
,
2912 gettext("LDAP ERROR (%d): %s."),
2914 ldap_err2string(cookie
->err_rc
));
2915 err
= strdup(errstr
);
2916 if (cookie
->err_from_result
) {
2917 if (cookie
->err_rc
== LDAP_SERVER_DOWN
) {
2918 MKERROR(LOG_INFO
, *errorp
,
2919 cookie
->err_rc
, err
, NULL
);
2921 MKERROR(LOG_WARNING
, *errorp
,
2922 cookie
->err_rc
, err
, NULL
);
2925 MKERROR(LOG_WARNING
, *errorp
, NS_LDAP_INTERNAL
,
2928 cookie
->err_rc
= NS_LDAP_INTERNAL
;
2929 cookie
->errorp
= *errorp
;
2930 if (cookie
->conn_user
!= NULL
) {
2931 if (rc_save
== LDAP_SERVER_DOWN
||
2932 rc_save
== LDAP_CONNECT_ERROR
) {
2934 * MT connection is not usable,
2937 __s_api_conn_mt_close(cookie
->conn_user
,
2938 rc_save
, &cookie
->errorp
);
2945 (void) sprintf(errstr
,
2946 gettext("Internal State machine exit (%d).\n"),
2948 err
= strdup(errstr
);
2949 MKERROR(LOG_WARNING
, *errorp
, NS_LDAP_INTERNAL
, err
,
2951 cookie
->err_rc
= NS_LDAP_INTERNAL
;
2952 cookie
->errorp
= *errorp
;
2956 if (cookie
->conn_user
!= NULL
&&
2957 cookie
->conn_user
->bad_mt_conn
== B_TRUE
) {
2958 __s_api_conn_mt_close(cookie
->conn_user
, 0, NULL
);
2959 cookie
->err_rc
= cookie
->conn_user
->ns_rc
;
2960 cookie
->errorp
= cookie
->conn_user
->ns_error
;
2961 cookie
->conn_user
->ns_error
= NULL
;
2965 if (cycle
== ONE_STEP
) {
2966 return (cookie
->new_state
);
2968 cookie
->state
= cookie
->new_state
;
2972 (void) sprintf(errstr
,
2973 gettext("Unexpected State machine error.\n"));
2974 err
= strdup(errstr
);
2975 MKERROR(LOG_WARNING
, *errorp
, NS_LDAP_INTERNAL
, err
, NULL
);
2976 cookie
->err_rc
= NS_LDAP_INTERNAL
;
2977 cookie
->errorp
= *errorp
;
2983 * For a lookup of shadow data, if shadow update is enabled,
2984 * check the calling process' privilege to ensure it's
2985 * allowed to perform such operation.
2988 check_shadow(ns_ldap_cookie_t
*cookie
, const char *service
)
2990 char errstr
[MAXERROR
];
2999 * If service is "shadow", we may need
3000 * to use privilege credentials.
3002 if ((strcmp(service
, "shadow") == 0) &&
3003 __ns_ldap_is_shadow_update_enabled()) {
3005 * Since we release admin credentials after
3006 * connection is closed and we do not cache
3007 * them, we allow any root or all zone
3008 * privilege process to read shadow data.
3010 priv
= (geteuid() == 0);
3013 ps
= priv_allocset();
3015 (void) getppriv(PRIV_EFFECTIVE
, ps
);
3016 zs
= priv_str_to_set("zone", ",", NULL
);
3017 priv
= priv_isequalset(ps
, zs
);
3022 (void) sprintf(errstr
,
3023 gettext("Permission denied"));
3024 err
= strdup(errstr
);
3026 return (NS_LDAP_MEMORY
);
3027 MKERROR(LOG_INFO
, cookie
->errorp
, NS_LDAP_INTERNAL
, err
,
3029 return (NS_LDAP_INTERNAL
);
3031 cookie
->i_flags
|= NS_LDAP_READ_SHADOW
;
3033 * We do not want to reuse connection (hence
3034 * keep it open) with admin credentials.
3035 * If NS_LDAP_KEEP_CONN is set, reject the
3038 if (cookie
->i_flags
& NS_LDAP_KEEP_CONN
)
3039 return (NS_LDAP_INVALID_PARAM
);
3040 cookie
->i_flags
|= NS_LDAP_NEW_CONN
;
3043 return (NS_LDAP_SUCCESS
);
3047 * internal function for __ns_ldap_list
3051 ns_ldap_list_batch_t
*batch
,
3052 const char *service
,
3054 const char *sortattr
,
3055 int (*init_filter_cb
)(const ns_ldap_search_desc_t
*desc
,
3056 char **realfilter
, const void *userdata
),
3057 const char * const *attribute
,
3058 const ns_cred_t
*auth
,
3060 ns_ldap_result_t
**rResult
, /* return result entries */
3061 ns_ldap_error_t
**errorp
,
3063 int (*callback
)(const ns_ldap_entry_t
*entry
, const void *userdata
),
3064 const void *userdata
, ns_conn_user_t
*conn_user
)
3066 ns_ldap_cookie_t
*cookie
;
3067 ns_ldap_search_desc_t
**sdlist
= NULL
;
3068 ns_ldap_search_desc_t
*dptr
;
3069 ns_ldap_error_t
*error
= NULL
;
3077 *rcp
= NS_LDAP_SUCCESS
;
3080 * Sanity check - NS_LDAP_READ_SHADOW is for our
3083 if (flags
& NS_LDAP_READ_SHADOW
)
3084 return (NS_LDAP_INVALID_PARAM
);
3086 /* Initialize State machine cookie */
3087 cookie
= init_search_state_machine();
3088 if (cookie
== NULL
) {
3089 *rcp
= NS_LDAP_MEMORY
;
3090 return (NS_LDAP_MEMORY
);
3092 cookie
->conn_user
= conn_user
;
3094 /* see if need to follow referrals */
3095 rc
= __s_api_toFollowReferrals(flags
,
3096 &cookie
->followRef
, errorp
);
3097 if (rc
!= NS_LDAP_SUCCESS
) {
3098 delete_search_cookie(cookie
);
3103 /* get the service descriptor - or create a default one */
3104 rc
= __s_api_get_SSD_from_SSDtoUse_service(service
,
3106 if (rc
!= NS_LDAP_SUCCESS
) {
3107 delete_search_cookie(cookie
);
3113 if (sdlist
== NULL
) {
3114 /* Create default service Desc */
3115 sdlist
= (ns_ldap_search_desc_t
**)calloc(2,
3116 sizeof (ns_ldap_search_desc_t
*));
3117 if (sdlist
== NULL
) {
3118 delete_search_cookie(cookie
);
3120 *rcp
= NS_LDAP_MEMORY
;
3121 return (NS_LDAP_MEMORY
);
3123 dptr
= (ns_ldap_search_desc_t
*)
3124 calloc(1, sizeof (ns_ldap_search_desc_t
));
3127 delete_search_cookie(cookie
);
3129 *rcp
= NS_LDAP_MEMORY
;
3130 return (NS_LDAP_MEMORY
);
3135 rc
= __s_api_getDNs(&dns
, service
, &cookie
->errorp
);
3136 if (rc
!= NS_LDAP_SUCCESS
) {
3138 __s_api_free2dArray(dns
);
3141 *errorp
= cookie
->errorp
;
3142 cookie
->errorp
= NULL
;
3143 delete_search_cookie(cookie
);
3148 dptr
->basedn
= strdup(dns
[0]);
3149 __s_api_free2dArray(dns
);
3154 rc
= __s_api_getSearchScope(&scope
, &cookie
->errorp
);
3155 dptr
->scope
= scope
;
3158 cookie
->sdlist
= sdlist
;
3161 * use VLV/PAGE control only if NS_LDAP_PAGE_CTRL is set
3163 if (flags
& NS_LDAP_PAGE_CTRL
)
3164 cookie
->use_paging
= TRUE
;
3166 cookie
->use_paging
= FALSE
;
3168 /* Set up other arguments */
3169 cookie
->userdata
= userdata
;
3170 if (init_filter_cb
!= NULL
) {
3171 cookie
->init_filter_cb
= init_filter_cb
;
3172 cookie
->use_filtercb
= 1;
3174 if (callback
!= NULL
) {
3175 cookie
->callback
= callback
;
3176 cookie
->use_usercb
= 1;
3179 /* check_shadow() may add extra value to cookie->i_flags */
3180 cookie
->i_flags
= flags
;
3182 cookie
->service
= strdup(service
);
3183 if (cookie
->service
== NULL
) {
3184 delete_search_cookie(cookie
);
3186 *rcp
= NS_LDAP_MEMORY
;
3187 return (NS_LDAP_MEMORY
);
3191 * If given, use the credential given by the caller, and
3192 * skip the credential check required for shadow update.
3195 rc
= check_shadow(cookie
, service
);
3196 if (rc
!= NS_LDAP_SUCCESS
) {
3197 *errorp
= cookie
->errorp
;
3198 cookie
->errorp
= NULL
;
3199 delete_search_cookie(cookie
);
3207 cookie
->i_filter
= strdup(filter
);
3208 cookie
->i_attr
= attribute
;
3209 cookie
->i_auth
= auth
;
3210 cookie
->i_sortattr
= sortattr
;
3212 if (batch
!= NULL
) {
3213 cookie
->batch
= batch
;
3214 cookie
->reinit_on_retriable_err
= B_TRUE
;
3215 cookie
->no_wait
= B_TRUE
;
3216 (void) search_state_machine(cookie
, INIT
, 0);
3217 cookie
->no_wait
= B_FALSE
;
3218 rc
= cookie
->err_rc
;
3220 if (rc
== NS_LDAP_SUCCESS
) {
3222 * Here rc == NS_LDAP_SUCCESS means that the state
3223 * machine init'ed successfully. The actual status
3224 * of the search will be determined by
3225 * __ns_ldap_list_batch_end(). Add the cookie to our
3228 cookie
->caller_result
= rResult
;
3229 cookie
->caller_errorp
= errorp
;
3230 cookie
->caller_rc
= rcp
;
3231 cookie
->next_cookie_in_batch
= batch
->cookie_list
;
3232 batch
->cookie_list
= cookie
;
3237 * If state machine init failed then copy error to the caller
3238 * and delete the cookie.
3241 (void) search_state_machine(cookie
, INIT
, 0);
3244 /* Copy results back to user */
3245 rc
= cookie
->err_rc
;
3246 if (rc
!= NS_LDAP_SUCCESS
) {
3247 if (conn_user
!= NULL
&& conn_user
->ns_error
!= NULL
) {
3248 *errorp
= conn_user
->ns_error
;
3249 conn_user
->ns_error
= NULL
;
3251 *errorp
= cookie
->errorp
;
3253 *rResult
= cookie
->result
;
3254 from_result
= cookie
->err_from_result
;
3256 cookie
->errorp
= NULL
;
3257 cookie
->result
= NULL
;
3258 delete_search_cookie(cookie
);
3261 if (from_result
== 0 && *rResult
== NULL
)
3262 rc
= NS_LDAP_NOTFOUND
;
3269 * __ns_ldap_list performs one or more LDAP searches to a given
3270 * directory server using service search descriptors and schema
3271 * mapping as appropriate. The operation may be retried a
3272 * couple of times in error situations.
3276 const char *service
,
3278 int (*init_filter_cb
)(const ns_ldap_search_desc_t
*desc
,
3279 char **realfilter
, const void *userdata
),
3280 const char * const *attribute
,
3281 const ns_cred_t
*auth
,
3283 ns_ldap_result_t
**rResult
, /* return result entries */
3284 ns_ldap_error_t
**errorp
,
3285 int (*callback
)(const ns_ldap_entry_t
*entry
, const void *userdata
),
3286 const void *userdata
)
3290 * Strip the NS_LDAP_PAGE_CTRL option as this interface does not
3291 * support this. If you want to use this option call the API
3292 * __ns_ldap_list_sort() with has the sort attribute.
3294 mod_flags
= flags
& (~NS_LDAP_PAGE_CTRL
);
3296 return (__ns_ldap_list_sort(service
, filter
, NULL
, init_filter_cb
,
3297 attribute
, auth
, mod_flags
, rResult
, errorp
,
3298 callback
, userdata
));
3302 * __ns_ldap_list_sort performs one or more LDAP searches to a given
3303 * directory server using service search descriptors and schema
3304 * mapping as appropriate. The operation may be retried a
3305 * couple of times in error situations.
3308 __ns_ldap_list_sort(
3309 const char *service
,
3311 const char *sortattr
,
3312 int (*init_filter_cb
)(const ns_ldap_search_desc_t
*desc
,
3313 char **realfilter
, const void *userdata
),
3314 const char * const *attribute
,
3315 const ns_cred_t
*auth
,
3317 ns_ldap_result_t
**rResult
, /* return result entries */
3318 ns_ldap_error_t
**errorp
,
3319 int (*callback
)(const ns_ldap_entry_t
*entry
, const void *userdata
),
3320 const void *userdata
)
3322 ns_conn_user_t
*cu
= NULL
;
3324 int rc
= NS_LDAP_SUCCESS
, trc
;
3327 if (__s_api_setup_retry_search(&cu
, NS_CONN_USER_SEARCH
,
3328 &try_cnt
, &rc
, errorp
) == 0)
3330 rc
= ldap_list(NULL
, service
, filter
, sortattr
, init_filter_cb
,
3331 attribute
, auth
, flags
, rResult
, errorp
, &trc
, callback
,
3339 * Create and initialize batch for native LDAP lookups
3342 __ns_ldap_list_batch_start(ns_ldap_list_batch_t
**batch
)
3344 *batch
= calloc(1, sizeof (ns_ldap_list_batch_t
));
3346 return (NS_LDAP_MEMORY
);
3347 return (NS_LDAP_SUCCESS
);
3352 * Add a LDAP search request to the batch.
3355 __ns_ldap_list_batch_add(
3356 ns_ldap_list_batch_t
*batch
,
3357 const char *service
,
3359 int (*init_filter_cb
)(const ns_ldap_search_desc_t
*desc
,
3360 char **realfilter
, const void *userdata
),
3361 const char * const *attribute
,
3362 const ns_cred_t
*auth
,
3364 ns_ldap_result_t
**rResult
, /* return result entries */
3365 ns_ldap_error_t
**errorp
,
3367 int (*callback
)(const ns_ldap_entry_t
*entry
, const void *userdata
),
3368 const void *userdata
)
3374 cu
= __s_api_conn_user_init(NS_CONN_USER_SEARCH
, NULL
, 0);
3377 *rcp
= NS_LDAP_MEMORY
;
3378 return (NS_LDAP_MEMORY
);
3382 * Strip the NS_LDAP_PAGE_CTRL option as the batch interface does not
3385 mod_flags
= flags
& (~NS_LDAP_PAGE_CTRL
);
3387 rc
= ldap_list(batch
, service
, filter
, NULL
, init_filter_cb
, attribute
,
3388 auth
, mod_flags
, rResult
, errorp
, rcp
, callback
, userdata
, cu
);
3391 * Free the conn_user if the cookie was not batched. If the cookie
3392 * was batched then __ns_ldap_list_batch_end or release will free the
3393 * conn_user. The batch API instructs the search_state_machine
3394 * to reinit and retry (max 3 times) on retriable LDAP errors.
3396 if (rc
!= NS_LDAP_SUCCESS
&& cu
!= NULL
) {
3397 if (cu
->conn_mt
!= NULL
)
3398 __s_api_conn_mt_return(cu
);
3399 __s_api_conn_user_free(cu
);
3409 __ns_ldap_list_batch_release(ns_ldap_list_batch_t
*batch
)
3411 ns_ldap_cookie_t
*c
, *next
;
3413 for (c
= batch
->cookie_list
; c
!= NULL
; c
= next
) {
3414 next
= c
->next_cookie_in_batch
;
3415 if (c
->conn_user
!= NULL
) {
3416 if (c
->conn_user
->conn_mt
!= NULL
)
3417 __s_api_conn_mt_return(c
->conn_user
);
3418 __s_api_conn_user_free(c
->conn_user
);
3419 c
->conn_user
= NULL
;
3421 delete_search_cookie(c
);
3426 #define LD_USING_STATE(st) \
3427 ((st == DO_SEARCH) || (st == MULTI_RESULT) || (st == NEXT_RESULT))
3430 * Process batch. Everytime this function is called it selects an
3431 * active cookie from the batch and single steps through the
3432 * search_state_machine for the selected cookie. If lookup associated
3433 * with the cookie is complete (success or error) then the cookie is
3434 * removed from the batch and its memory freed.
3436 * Returns 1 (if batch still has active cookies)
3437 * 0 (if batch has no more active cookies)
3438 * -1 (on errors, *rcp will contain the error code)
3440 * The caller should call this function in a loop as long as it returns 1
3441 * to process all the requests added to the batch. The results (and errors)
3442 * will be available in the locations provided by the caller at the time of
3443 * __ns_ldap_list_batch_add().
3447 __ns_ldap_list_batch_process(ns_ldap_list_batch_t
*batch
, int *rcp
)
3449 ns_ldap_cookie_t
*c
, *ptr
, **prev
;
3451 ns_ldap_error_t
*errorp
= NULL
;
3454 /* Check if are already done */
3455 if (batch
->nactive
== 0)
3458 /* Get the next cookie from the batch */
3459 c
= (batch
->next_cookie
== NULL
) ?
3460 batch
->cookie_list
: batch
->next_cookie
;
3462 batch
->next_cookie
= c
->next_cookie_in_batch
;
3465 * Checks the status of the cookie's connection if it needs
3466 * to use that connection for ldap_search_ext or ldap_result.
3467 * If the connection is no longer good but worth retrying
3468 * then reinit the search_state_machine for this cookie
3469 * starting from the first search descriptor. REINIT will
3470 * clear any leftover results if max retries have not been
3471 * reached and redo the search (which may also involve
3472 * following referrals again).
3474 * Note that each cookie in the batch will make this
3475 * determination when it reaches one of the LD_USING_STATES.
3477 if (LD_USING_STATE(c
->new_state
) && c
->conn_user
!= NULL
) {
3478 rc
= __s_api_setup_getnext(c
->conn_user
, &c
->err_rc
, &errorp
);
3479 if (rc
== LDAP_BUSY
|| rc
== LDAP_UNAVAILABLE
||
3480 rc
== LDAP_UNWILLING_TO_PERFORM
) {
3481 if (errorp
!= NULL
) {
3482 (void) __ns_ldap_freeError(&c
->errorp
);
3485 c
->new_state
= REINIT
;
3486 } else if (rc
== LDAP_CONNECT_ERROR
||
3487 rc
== LDAP_SERVER_DOWN
) {
3488 if (errorp
!= NULL
) {
3489 (void) __ns_ldap_freeError(&c
->errorp
);
3492 c
->new_state
= REINIT
;
3494 * MT connection is not usable,
3495 * close it before REINIT.
3497 __s_api_conn_mt_close(
3498 c
->conn_user
, rc
, NULL
);
3499 } else if (rc
!= NS_LDAP_SUCCESS
) {
3502 *c
->caller_result
= NULL
;
3503 *c
->caller_errorp
= errorp
;
3510 /* Single step through the search_state_machine */
3511 state
= search_state_machine(c
, c
->new_state
, ONE_STEP
);
3514 (void) search_state_machine(c
, state
, ONE_STEP
);
3515 (void) search_state_machine(c
, CLEAR_RESULTS
, ONE_STEP
);
3519 *c
->caller_result
= c
->result
;
3520 *c
->caller_errorp
= c
->errorp
;
3522 (c
->result
== NULL
&& c
->err_from_result
== 0)
3523 ? NS_LDAP_NOTFOUND
: c
->err_rc
;
3526 /* Remove the cookie from the batch */
3527 ptr
= batch
->cookie_list
;
3528 prev
= &batch
->cookie_list
;
3529 while (ptr
!= NULL
) {
3531 *prev
= ptr
->next_cookie_in_batch
;
3534 prev
= &ptr
->next_cookie_in_batch
;
3535 ptr
= ptr
->next_cookie_in_batch
;
3537 /* Delete cookie and decrement active cookie count */
3538 if (c
->conn_user
!= NULL
) {
3539 if (c
->conn_user
->conn_mt
!= NULL
)
3540 __s_api_conn_mt_return(c
->conn_user
);
3541 __s_api_conn_user_free(c
->conn_user
);
3542 c
->conn_user
= NULL
;
3544 delete_search_cookie(c
);
3550 * This means that search_state_machine needs to do
3551 * another ldap_result() for the cookie in question.
3552 * We only do at most one ldap_result() per call in
3553 * this function and therefore we return. This allows
3554 * the caller to process results from other cookies
3555 * in the batch without getting tied up on just one
3561 * This includes states that follow NEXT_RESULT or
3562 * MULTI_RESULT such as PROCESS_RESULT and
3563 * END_PROCESS_RESULT. We continue processing
3564 * this cookie till we reach either the error, exit
3565 * or the result states.
3572 /* Return 0 if no more cookies left otherwise 1 */
3573 return ((batch
->nactive
> 0) ? 1 : 0);
3578 * Process all the active cookies in the batch and when none
3579 * remains finalize the batch.
3582 __ns_ldap_list_batch_end(ns_ldap_list_batch_t
*batch
)
3584 int rc
= NS_LDAP_SUCCESS
;
3585 while (__ns_ldap_list_batch_process(batch
, &rc
) > 0)
3587 __ns_ldap_list_batch_release(batch
);
3592 * find_domainname performs one or more LDAP searches to
3593 * find the value of the nisdomain attribute associated with
3594 * the input DN (with no retry).
3598 find_domainname(const char *dn
, char **domainname
, const ns_cred_t
*cred
,
3599 ns_ldap_error_t
**errorp
, ns_conn_user_t
*conn_user
)
3602 ns_ldap_cookie_t
*cookie
;
3603 ns_ldap_search_desc_t
**sdlist
;
3604 ns_ldap_search_desc_t
*dptr
;
3612 /* Initialize State machine cookie */
3613 cookie
= init_search_state_machine();
3614 if (cookie
== NULL
) {
3615 return (NS_LDAP_MEMORY
);
3617 cookie
->conn_user
= conn_user
;
3619 /* see if need to follow referrals */
3620 rc
= __s_api_toFollowReferrals(flags
,
3621 &cookie
->followRef
, errorp
);
3622 if (rc
!= NS_LDAP_SUCCESS
) {
3623 delete_search_cookie(cookie
);
3627 /* Create default service Desc */
3628 sdlist
= (ns_ldap_search_desc_t
**)calloc(2,
3629 sizeof (ns_ldap_search_desc_t
*));
3630 if (sdlist
== NULL
) {
3631 delete_search_cookie(cookie
);
3633 return (NS_LDAP_MEMORY
);
3635 dptr
= (ns_ldap_search_desc_t
*)
3636 calloc(1, sizeof (ns_ldap_search_desc_t
));
3639 delete_search_cookie(cookie
);
3641 return (NS_LDAP_MEMORY
);
3645 /* search base is dn */
3646 dptr
->basedn
= strdup(dn
);
3648 /* search scope is base */
3649 dptr
->scope
= NS_LDAP_SCOPE_BASE
;
3651 /* search filter is "nisdomain=*" */
3652 dptr
->filter
= strdup(_NIS_FILTER
);
3654 cookie
->sdlist
= sdlist
;
3655 cookie
->i_filter
= strdup(dptr
->filter
);
3656 cookie
->i_attr
= nis_domain_attrs
;
3657 cookie
->i_auth
= cred
;
3658 cookie
->i_flags
= 0;
3660 /* Process search */
3661 rc
= search_state_machine(cookie
, INIT
, 0);
3663 /* Copy domain name if found */
3664 rc
= cookie
->err_rc
;
3665 if (rc
!= NS_LDAP_SUCCESS
) {
3666 if (conn_user
!= NULL
&& conn_user
->ns_error
!= NULL
) {
3667 *errorp
= conn_user
->ns_error
;
3668 conn_user
->ns_error
= NULL
;
3670 *errorp
= cookie
->errorp
;
3672 if (cookie
->result
== NULL
)
3673 rc
= NS_LDAP_NOTFOUND
;
3674 if (rc
== NS_LDAP_SUCCESS
) {
3675 value
= __ns_ldap_getAttr(cookie
->result
->entry
,
3678 *domainname
= strdup(value
[0]);
3680 rc
= NS_LDAP_NOTFOUND
;
3682 if (cookie
->result
!= NULL
)
3683 (void) __ns_ldap_freeResult(&cookie
->result
);
3684 cookie
->errorp
= NULL
;
3685 delete_search_cookie(cookie
);
3691 * __s_api_find_domainname performs one or more LDAP searches to
3692 * find the value of the nisdomain attribute associated with
3693 * the input DN (with retry).
3697 __s_api_find_domainname(const char *dn
, char **domainname
,
3698 const ns_cred_t
*cred
, ns_ldap_error_t
**errorp
)
3700 ns_conn_user_t
*cu
= NULL
;
3702 int rc
= NS_LDAP_SUCCESS
;
3705 if (__s_api_setup_retry_search(&cu
, NS_CONN_USER_SEARCH
,
3706 &try_cnt
, &rc
, errorp
) == 0)
3708 rc
= find_domainname(dn
, domainname
, cred
, errorp
, cu
);
3716 const char *service
,
3718 const char *sortattr
,
3719 int (*init_filter_cb
)(const ns_ldap_search_desc_t
*desc
,
3720 char **realfilter
, const void *userdata
),
3721 const char * const *attribute
,
3722 const ns_cred_t
*auth
,
3725 ns_ldap_result_t
**result
,
3726 ns_ldap_error_t
** errorp
,
3727 const void *userdata
,
3728 ns_conn_user_t
*conn_user
)
3730 ns_ldap_cookie_t
*cookie
= NULL
;
3731 ns_ldap_error_t
*error
= NULL
;
3733 ns_ldap_search_desc_t
**sdlist
;
3734 ns_ldap_search_desc_t
*dptr
;
3743 * Sanity check - NS_LDAP_READ_SHADOW is for our
3746 if (flags
& NS_LDAP_READ_SHADOW
)
3747 return (NS_LDAP_INVALID_PARAM
);
3749 /* get the service descriptor - or create a default one */
3750 rc
= __s_api_get_SSD_from_SSDtoUse_service(service
,
3752 if (rc
!= NS_LDAP_SUCCESS
) {
3756 if (sdlist
== NULL
) {
3757 /* Create default service Desc */
3758 sdlist
= (ns_ldap_search_desc_t
**)calloc(2,
3759 sizeof (ns_ldap_search_desc_t
*));
3760 if (sdlist
== NULL
) {
3761 return (NS_LDAP_MEMORY
);
3763 dptr
= (ns_ldap_search_desc_t
*)
3764 calloc(1, sizeof (ns_ldap_search_desc_t
));
3767 return (NS_LDAP_MEMORY
);
3772 rc
= __s_api_getDNs(&dns
, service
, &error
);
3773 if (rc
!= NS_LDAP_SUCCESS
) {
3775 __s_api_free2dArray(dns
);
3779 (void) __ns_ldap_freeSearchDescriptors(
3787 dptr
->basedn
= strdup(dns
[0]);
3788 __s_api_free2dArray(dns
);
3793 cookie
= init_search_state_machine();
3794 if (cookie
== NULL
) {
3796 (void) __ns_ldap_freeSearchDescriptors(&sdlist
);
3799 return (NS_LDAP_MEMORY
);
3801 rc
= __s_api_getSearchScope(&scope
, &cookie
->errorp
);
3802 dptr
->scope
= scope
;
3805 /* Initialize State machine cookie */
3807 cookie
= init_search_state_machine();
3808 if (cookie
== NULL
) {
3810 (void) __ns_ldap_freeSearchDescriptors(&sdlist
);
3813 return (NS_LDAP_MEMORY
);
3816 /* identify self as a getent user */
3817 cookie
->conn_user
= conn_user
;
3819 cookie
->sdlist
= sdlist
;
3821 /* see if need to follow referrals */
3822 rc
= __s_api_toFollowReferrals(flags
,
3823 &cookie
->followRef
, errorp
);
3824 if (rc
!= NS_LDAP_SUCCESS
) {
3825 delete_search_cookie(cookie
);
3830 * use VLV/PAGE control only if NS_LDAP_NO_PAGE_CTRL is not set
3832 if (flags
& NS_LDAP_NO_PAGE_CTRL
)
3833 cookie
->use_paging
= FALSE
;
3835 cookie
->use_paging
= TRUE
;
3837 /* Set up other arguments */
3838 cookie
->userdata
= userdata
;
3839 if (init_filter_cb
!= NULL
) {
3840 cookie
->init_filter_cb
= init_filter_cb
;
3841 cookie
->use_filtercb
= 1;
3843 cookie
->use_usercb
= 0;
3844 /* check_shadow() may add extra value to cookie->i_flags */
3845 cookie
->i_flags
= flags
;
3847 cookie
->service
= strdup(service
);
3848 if (cookie
->service
== NULL
) {
3849 delete_search_cookie(cookie
);
3850 return (NS_LDAP_MEMORY
);
3854 * If given, use the credential given by the caller, and
3855 * skip the credential check required for shadow update.
3858 rc
= check_shadow(cookie
, service
);
3859 if (rc
!= NS_LDAP_SUCCESS
) {
3860 *errorp
= cookie
->errorp
;
3861 cookie
->errorp
= NULL
;
3862 delete_search_cookie(cookie
);
3869 cookie
->i_filter
= strdup(filter
);
3870 cookie
->i_attr
= attribute
;
3871 cookie
->i_sortattr
= sortattr
;
3872 cookie
->i_auth
= auth
;
3876 state
= search_state_machine(cookie
, state
, ONE_STEP
);
3878 case PROCESS_RESULT
:
3879 *result
= cookie
->result
;
3880 cookie
->result
= NULL
;
3881 *vcookie
= (void *)cookie
;
3882 return (NS_LDAP_SUCCESS
);
3884 state
= search_state_machine(cookie
, state
, ONE_STEP
);
3885 state
= search_state_machine(cookie
, CLEAR_RESULTS
,
3889 rc
= cookie
->err_rc
;
3890 if (conn_user
!= NULL
&& conn_user
->ns_error
!= NULL
) {
3891 *errorp
= conn_user
->ns_error
;
3892 conn_user
->ns_error
= NULL
;
3894 *errorp
= cookie
->errorp
;
3895 cookie
->errorp
= NULL
;
3897 delete_search_cookie(cookie
);
3900 rc
= cookie
->err_rc
;
3901 if (rc
!= NS_LDAP_SUCCESS
) {
3902 *errorp
= cookie
->errorp
;
3903 cookie
->errorp
= NULL
;
3905 rc
= NS_LDAP_NOTFOUND
;
3908 delete_search_cookie(cookie
);
3918 __ns_ldap_firstEntry(
3919 const char *service
,
3921 const char *vlv_sort
,
3922 int (*init_filter_cb
)(const ns_ldap_search_desc_t
*desc
,
3923 char **realfilter
, const void *userdata
),
3924 const char * const *attribute
,
3925 const ns_cred_t
*auth
,
3928 ns_ldap_result_t
**result
,
3929 ns_ldap_error_t
** errorp
,
3930 const void *userdata
)
3932 ns_conn_user_t
*cu
= NULL
;
3934 int rc
= NS_LDAP_SUCCESS
;
3937 if (__s_api_setup_retry_search(&cu
, NS_CONN_USER_GETENT
,
3938 &try_cnt
, &rc
, errorp
) == 0)
3940 rc
= firstEntry(service
, filter
, vlv_sort
, init_filter_cb
,
3941 attribute
, auth
, flags
, vcookie
, result
, errorp
, userdata
,
3949 __ns_ldap_nextEntry(void *vcookie
, ns_ldap_result_t
**result
,
3950 ns_ldap_error_t
** errorp
)
3952 ns_ldap_cookie_t
*cookie
;
3956 cookie
= (ns_ldap_cookie_t
*)vcookie
;
3957 cookie
->result
= NULL
;
3960 if (cookie
->conn_user
!= NULL
) {
3961 rc
= __s_api_setup_getnext(cookie
->conn_user
,
3962 &cookie
->err_rc
, errorp
);
3963 if (rc
!= NS_LDAP_SUCCESS
)
3967 state
= END_PROCESS_RESULT
;
3969 state
= search_state_machine(cookie
, state
, ONE_STEP
);
3971 case PROCESS_RESULT
:
3972 *result
= cookie
->result
;
3973 cookie
->result
= NULL
;
3974 return (NS_LDAP_SUCCESS
);
3976 state
= search_state_machine(cookie
, state
, ONE_STEP
);
3977 state
= search_state_machine(cookie
, CLEAR_RESULTS
,
3981 rc
= cookie
->err_rc
;
3982 *errorp
= cookie
->errorp
;
3983 cookie
->errorp
= NULL
;
3986 return (NS_LDAP_SUCCESS
);
3994 ns_ldap_error_t
** errorp
)
3996 ns_ldap_cookie_t
*cookie
;
3999 if (*vcookie
== NULL
)
4000 return (NS_LDAP_INVALID_PARAM
);
4002 cookie
= (ns_ldap_cookie_t
*)(*vcookie
);
4003 cookie
->result
= NULL
;
4005 /* Complete search */
4006 rc
= search_state_machine(cookie
, CLEAR_RESULTS
, 0);
4008 /* Copy results back to user */
4009 rc
= cookie
->err_rc
;
4010 if (rc
!= NS_LDAP_SUCCESS
)
4011 *errorp
= cookie
->errorp
;
4013 cookie
->errorp
= NULL
;
4014 if (cookie
->conn_user
!= NULL
) {
4015 if (cookie
->conn_user
->conn_mt
!= NULL
)
4016 __s_api_conn_mt_return(cookie
->conn_user
);
4017 __s_api_conn_user_free(cookie
->conn_user
);
4019 delete_search_cookie(cookie
);
4028 __ns_ldap_freeResult(ns_ldap_result_t
**result
)
4031 ns_ldap_entry_t
*curEntry
= NULL
;
4032 ns_ldap_entry_t
*delEntry
= NULL
;
4034 ns_ldap_result_t
*res
= *result
;
4037 (void) fprintf(stderr
, "__ns_ldap_freeResult START\n");
4040 return (NS_LDAP_INVALID_PARAM
);
4042 if (res
->entry
!= NULL
)
4043 curEntry
= res
->entry
;
4045 for (i
= 0; i
< res
->entries_count
; i
++) {
4046 if (curEntry
!= NULL
) {
4047 delEntry
= curEntry
;
4048 curEntry
= curEntry
->next
;
4049 __ns_ldap_freeEntry(delEntry
);
4055 return (NS_LDAP_SUCCESS
);
4060 __ns_ldap_auth(const ns_cred_t
*auth
,
4062 ns_ldap_error_t
**errorp
,
4063 LDAPControl
**serverctrls
,
4064 LDAPControl
**clientctrls
)
4067 ConnectionID connectionId
= -1;
4070 int do_not_fail_if_new_pwd_reqd
= 0;
4071 int nopasswd_acct_mgmt
= 0;
4072 ns_conn_user_t
*conn_user
;
4076 (void) fprintf(stderr
, "__ns_ldap_auth START\n");
4081 return (NS_LDAP_INVALID_PARAM
);
4083 conn_user
= __s_api_conn_user_init(NS_CONN_USER_AUTH
,
4086 rc
= __s_api_getConnection(NULL
, flags
| NS_LDAP_NEW_CONN
,
4087 auth
, &connectionId
, &conp
, errorp
,
4088 do_not_fail_if_new_pwd_reqd
, nopasswd_acct_mgmt
,
4091 if (conn_user
!= NULL
)
4092 __s_api_conn_user_free(conn_user
);
4094 if (rc
== NS_LDAP_OP_FAILED
&& *errorp
)
4095 (void) __ns_ldap_freeError(errorp
);
4097 if (connectionId
> -1)
4098 DropConnection(connectionId
, flags
);
4103 __ns_ldap_getAttr(const ns_ldap_entry_t
*entry
, const char *attrname
)
4109 for (i
= 0; i
< entry
->attr_count
; i
++) {
4110 if (strcasecmp(entry
->attr_pair
[i
]->attrname
, attrname
) == NULL
)
4111 return (entry
->attr_pair
[i
]->attrvalue
);
4117 __ns_ldap_getAttrStruct(const ns_ldap_entry_t
*entry
, const char *attrname
)
4123 for (i
= 0; i
< entry
->attr_count
; i
++) {
4124 if (strcasecmp(entry
->attr_pair
[i
]->attrname
, attrname
) == NULL
)
4125 return (entry
->attr_pair
[i
]);
4133 __ns_ldap_uid2dn(const char *uid
,
4135 const ns_cred_t
*cred
, /* cred is ignored */
4136 ns_ldap_error_t
**errorp
)
4138 ns_ldap_result_t
*result
= NULL
;
4139 char *filter
, *userdata
;
4140 char errstr
[MAXERROR
];
4148 if ((uid
== NULL
) || (uid
[0] == '\0'))
4149 return (NS_LDAP_INVALID_PARAM
);
4151 while (uid
[i
] != '\0') {
4152 if (uid
[i
] == '=') {
4153 *userDN
= strdup(uid
);
4154 return (NS_LDAP_SUCCESS
);
4159 while ((uid
[i
] != '\0') && (isdigit(uid
[i
])))
4161 if (uid
[i
] == '\0') {
4162 len
= strlen(UIDNUMFILTER
) + strlen(uid
) + 1;
4163 filter
= (char *)malloc(len
);
4164 if (filter
== NULL
) {
4166 return (NS_LDAP_MEMORY
);
4168 (void) snprintf(filter
, len
, UIDNUMFILTER
, uid
);
4170 len
= strlen(UIDNUMFILTER_SSD
) + strlen(uid
) + 1;
4171 userdata
= (char *)malloc(len
);
4172 if (userdata
== NULL
) {
4174 return (NS_LDAP_MEMORY
);
4176 (void) snprintf(userdata
, len
, UIDNUMFILTER_SSD
, uid
);
4178 len
= strlen(UIDFILTER
) + strlen(uid
) + 1;
4179 filter
= (char *)malloc(len
);
4180 if (filter
== NULL
) {
4182 return (NS_LDAP_MEMORY
);
4184 (void) snprintf(filter
, len
, UIDFILTER
, uid
);
4186 len
= strlen(UIDFILTER_SSD
) + strlen(uid
) + 1;
4187 userdata
= (char *)malloc(len
);
4188 if (userdata
== NULL
) {
4190 return (NS_LDAP_MEMORY
);
4192 (void) snprintf(userdata
, len
, UIDFILTER_SSD
, uid
);
4196 * we want to retrieve the DN as it appears in LDAP
4197 * hence the use of NS_LDAP_NOT_CVT_DN in flags
4199 rc
= __ns_ldap_list("passwd", filter
,
4200 __s_api_merge_SSD_filter
,
4201 NULL
, cred
, NS_LDAP_NOT_CVT_DN
,
4202 &result
, errorp
, NULL
,
4208 if (rc
!= NS_LDAP_SUCCESS
) {
4210 (void) __ns_ldap_freeResult(&result
);
4215 if (result
->entries_count
> 1) {
4216 (void) __ns_ldap_freeResult(&result
);
4219 (void) sprintf(errstr
,
4220 gettext("Too many entries are returned for %s"), uid
);
4221 MKERROR(LOG_WARNING
, *errorp
, NS_LDAP_INTERNAL
, strdup(errstr
),
4223 return (NS_LDAP_INTERNAL
);
4226 value
= __ns_ldap_getAttr(result
->entry
, "dn");
4227 *userDN
= strdup(value
[0]);
4228 (void) __ns_ldap_freeResult(&result
);
4230 return (NS_LDAP_SUCCESS
);
4236 __ns_ldap_host2dn(const char *host
,
4239 const ns_cred_t
*cred
, /* cred is ignored */
4240 ns_ldap_error_t
**errorp
)
4242 ns_ldap_result_t
*result
= NULL
;
4243 char *filter
, *userdata
;
4244 char errstr
[MAXERROR
];
4251 * the domain parameter needs to be used in case domain is not local, if
4252 * this routine is to support multi domain setups, it needs lots of work...
4256 if ((host
== NULL
) || (host
[0] == '\0'))
4257 return (NS_LDAP_INVALID_PARAM
);
4259 len
= strlen(HOSTFILTER
) + strlen(host
) + 1;
4260 filter
= (char *)malloc(len
);
4261 if (filter
== NULL
) {
4262 return (NS_LDAP_MEMORY
);
4264 (void) snprintf(filter
, len
, HOSTFILTER
, host
);
4266 len
= strlen(HOSTFILTER_SSD
) + strlen(host
) + 1;
4267 userdata
= (char *)malloc(len
);
4268 if (userdata
== NULL
) {
4269 return (NS_LDAP_MEMORY
);
4271 (void) snprintf(userdata
, len
, HOSTFILTER_SSD
, host
);
4274 * we want to retrieve the DN as it appears in LDAP
4275 * hence the use of NS_LDAP_NOT_CVT_DN in flags
4277 rc
= __ns_ldap_list("hosts", filter
,
4278 __s_api_merge_SSD_filter
,
4279 NULL
, cred
, NS_LDAP_NOT_CVT_DN
, &result
,
4286 if (rc
!= NS_LDAP_SUCCESS
) {
4288 (void) __ns_ldap_freeResult(&result
);
4294 if (result
->entries_count
> 1) {
4295 (void) __ns_ldap_freeResult(&result
);
4298 (void) sprintf(errstr
,
4299 gettext("Too many entries are returned for %s"), host
);
4300 MKERROR(LOG_WARNING
, *errorp
, NS_LDAP_INTERNAL
, strdup(errstr
),
4302 return (NS_LDAP_INTERNAL
);
4305 value
= __ns_ldap_getAttr(result
->entry
, "dn");
4306 *hostDN
= strdup(value
[0]);
4307 (void) __ns_ldap_freeResult(&result
);
4309 return (NS_LDAP_SUCCESS
);
4314 __ns_ldap_dn2domain(const char *dn
,
4316 const ns_cred_t
*cred
,
4317 ns_ldap_error_t
**errorp
)
4319 int rc
, pnum
, i
, j
, len
= 0;
4320 char *newdn
, **rdns
= NULL
;
4326 return (NS_LDAP_INVALID_PARAM
);
4330 if ((dn
== NULL
) || (dn
[0] == '\0'))
4331 return (NS_LDAP_INVALID_PARAM
);
4334 * break dn into rdns
4338 return (NS_LDAP_MEMORY
);
4339 rdns
= ldap_explode_dn(dn1
, 0);
4341 if (rdns
== NULL
|| *rdns
== NULL
)
4342 return (NS_LDAP_INVALID_PARAM
);
4344 for (i
= 0; rdns
[i
]; i
++)
4345 len
+= strlen(rdns
[i
]) + 1;
4348 newdn
= (char *)malloc(len
+ 1);
4349 dns
= (char **)calloc(pnum
, sizeof (char *));
4350 if (newdn
== NULL
|| dns
== NULL
) {
4353 ldap_value_free(rdns
);
4354 return (NS_LDAP_MEMORY
);
4357 /* construct a semi-normalized dn, newdn */
4359 for (i
= 0; rdns
[i
]; i
++) {
4360 dns
[i
] = newdn
+ strlen(newdn
);
4361 (void) strcat(newdn
,
4362 __s_api_remove_rdn_space(rdns
[i
]));
4363 (void) strcat(newdn
, ",");
4365 /* remove the last ',' */
4366 newdn
[strlen(newdn
) - 1] = '\0';
4367 ldap_value_free(rdns
);
4370 * loop and find the domain name associated with newdn,
4371 * removing rdn one by one from left to right
4373 for (i
= 0; i
< pnum
; i
++) {
4376 (void) __ns_ldap_freeError(errorp
);
4379 * try cache manager first
4381 rc
= __s_api_get_cachemgr_data(NS_CACHE_DN2DOMAIN
,
4383 if (rc
!= NS_LDAP_SUCCESS
) {
4385 * try ldap server second
4387 rc
= __s_api_find_domainname(dns
[i
], domain
,
4391 * skip the last one,
4392 * since it is already cached by ldap_cachemgr
4396 if (rc
== NS_LDAP_SUCCESS
) {
4397 if (__s_api_nscd_proc()) {
4399 * If it's nscd, ask cache manager to save the
4400 * dn to domain mapping(s)
4402 for (j
= 0; j
<= i
; j
++) {
4403 (void) __s_api_set_cachemgr_data(
4415 if (rc
!= NS_LDAP_SUCCESS
)
4416 rc
= NS_LDAP_NOTFOUND
;
4422 __ns_ldap_getServiceAuthMethods(const char *service
,
4424 ns_ldap_error_t
**errorp
)
4426 char errstr
[MAXERROR
];
4427 int rc
, i
, done
= 0;
4430 char **sam
, *srv
, *send
;
4431 ns_auth_t
**authpp
= NULL
, *ap
;
4434 ns_ldap_error_t
*error
= NULL
;
4437 return (NS_LDAP_INVALID_PARAM
);
4440 if ((service
== NULL
) || (service
[0] == '\0') ||
4442 return (NS_LDAP_INVALID_PARAM
);
4445 rc
= __ns_ldap_getParam(NS_LDAP_SERVICE_AUTH_METHOD_P
, ¶m
, &error
);
4446 if (rc
!= NS_LDAP_SUCCESS
|| param
== NULL
) {
4450 sam
= (char **)param
;
4452 cfg
= __s_api_get_default_config();
4455 slen
= strlen(service
);
4457 for (; *sam
; sam
++) {
4459 if (strncasecmp(service
, srv
, slen
) != 0)
4462 if (*srv
!= COLONTOK
)
4466 for (max
= 1; (send
= strchr(++send
, SEMITOK
)) != NULL
;
4468 authpp
= (ns_auth_t
**)calloc(++max
, sizeof (ns_auth_t
*));
4469 if (authpp
== NULL
) {
4470 (void) __ns_ldap_freeParam(¶m
);
4471 __s_api_release_config(cfg
);
4472 return (NS_LDAP_MEMORY
);
4475 send
= strchr(srv
, SEMITOK
);
4480 i
= __s_get_enum_value(cfg
, srv
, NS_LDAP_AUTH_P
);
4482 (void) __ns_ldap_freeParam(¶m
);
4483 (void) sprintf(errstr
,
4484 gettext("Unsupported "
4485 "serviceAuthenticationMethod: %s.\n"), srv
);
4486 MKERROR(LOG_WARNING
, *errorp
, NS_CONFIG_SYNTAX
,
4487 strdup(errstr
), NULL
);
4488 __s_api_release_config(cfg
);
4489 return (NS_LDAP_CONFIG
);
4491 ap
= __s_api_AuthEnumtoStruct((EnumAuthType_t
)i
);
4493 (void) __ns_ldap_freeParam(¶m
);
4494 __s_api_release_config(cfg
);
4495 return (NS_LDAP_MEMORY
);
4506 (void) __ns_ldap_freeParam(¶m
);
4507 __s_api_release_config(cfg
);
4508 return (NS_LDAP_SUCCESS
);
4512 * This routine is called when certain scenario occurs
4514 * service == auto_home
4515 * SSD = automount: ou = mytest,
4516 * NS_LDAP_MAPATTRIBUTE= auto_home: automountMapName=AAA
4517 * NS_LDAP_OBJECTCLASSMAP= auto_home:automountMap=MynisMap
4518 * NS_LDAP_OBJECTCLASSMAP= auto_home:automount=MynisObject
4520 * The automountMapName is prepended implicitely but is mapped
4521 * to AAA. So dn could appers as
4522 * dn: AAA=auto_home,ou=bar,dc=foo,dc=com
4523 * dn: automountKey=user_01,AAA=auto_home,ou=bar,dc=foo,dc=com
4524 * dn: automountKey=user_02,AAA=auto_home,ou=bar,dc=foo,dc=com
4526 * This function is called to covert the mapped attr back to
4527 * orig attr when the entries are searched and returned
4531 __s_api_convert_automountmapname(const char *service
, char **dn
,
4532 ns_ldap_error_t
**errp
) {
4534 char **mapping
= NULL
;
4535 char *mapped_attr
= NULL
;
4536 char *automountmapname
= "automountMapName";
4537 char *buffer
= NULL
;
4538 int rc
= NS_LDAP_SUCCESS
;
4539 char errstr
[MAXERROR
];
4542 * dn is an input/out parameter, check it first
4545 if (service
== NULL
|| dn
== NULL
|| *dn
== NULL
)
4546 return (NS_LDAP_INVALID_PARAM
);
4549 * Check to see if there is a mapped attribute for auto_xxx
4552 mapping
= __ns_ldap_getMappedAttributes(service
, automountmapname
);
4555 * if no mapped attribute for auto_xxx, try automount
4558 if (mapping
== NULL
)
4559 mapping
= __ns_ldap_getMappedAttributes(
4560 "automount", automountmapname
);
4563 * if no mapped attribute is found, return SUCCESS (no op)
4566 if (mapping
== NULL
)
4567 return (NS_LDAP_SUCCESS
);
4570 * if the mapped attribute is found and attr is not empty,
4574 if (mapping
[0] != NULL
) {
4575 mapped_attr
= strdup(mapping
[0]);
4576 __s_api_free2dArray(mapping
);
4577 if (mapped_attr
== NULL
) {
4578 return (NS_LDAP_MEMORY
);
4581 __s_api_free2dArray(mapping
);
4583 (void) snprintf(errstr
, (2 * MAXERROR
),
4585 "Attribute nisMapName is mapped to an "
4586 "empty string.\n"));
4588 MKERROR(LOG_ERR
, *errp
, NS_CONFIG_SYNTAX
,
4589 strdup(errstr
), NULL
);
4591 return (NS_LDAP_CONFIG
);
4595 * Locate the mapped attribute in the dn
4596 * and replace it if it exists
4599 rc
= __s_api_replace_mapped_attr_in_dn(
4600 (const char *) automountmapname
, (const char *) mapped_attr
,
4601 (const char *) *dn
, &buffer
);
4608 * If mapped attr is found(buffer != NULL)
4609 * a new dn is returned
4610 * If no mapped attribute is in dn,
4611 * return NS_LDAP_SUCCESS (no op)
4613 * return NS_LDAP_MEMORY (no op)
4616 if (buffer
!= NULL
) {
4625 * If the mapped attr is found in the dn,
4626 * return NS_LDAP_SUCCESS and a new_dn.
4627 * If no mapped attr is found,
4628 * return NS_LDAP_SUCCESS and *new_dn == NULL
4629 * If there is not enough memory,
4630 * return NS_LDAP_MEMORY and *new_dn == NULL
4634 __s_api_replace_mapped_attr_in_dn(
4635 const char *orig_attr
, const char *mapped_attr
,
4636 const char *dn
, char **new_dn
) {
4638 char **dnArray
= NULL
;
4639 char *cur
= NULL
, *start
= NULL
;
4640 int i
= 0, found
= 0;
4641 int len
= 0, orig_len
= 0, mapped_len
= 0;
4642 int dn_len
= 0, tmp_len
= 0;
4647 * seperate dn into individual componets
4649 * "automountKey=user_01" , "automountMapName_test=auto_home", ...
4651 dnArray
= ldap_explode_dn(dn
, 0);
4654 * This will find "mapped attr=value" in dn.
4655 * It won't find match if mapped attr appears
4658 for (i
= 0; dnArray
[i
] != NULL
; i
++) {
4660 * This function is called when reading from
4661 * the directory so assume each component has "=".
4662 * Any ill formatted dn should be rejected
4663 * before adding to the directory
4665 cur
= strchr(dnArray
[i
], '=');
4667 if (strcasecmp(mapped_attr
, dnArray
[i
]) == 0)
4674 __s_api_free2dArray(dnArray
);
4676 return (NS_LDAP_SUCCESS
);
4679 * The new length is *dn length + (difference between
4680 * orig attr and mapped attr) + 1 ;
4682 * automountKey=aa,automountMapName_test=auto_home,dc=foo,dc=com
4684 * automountKey=aa,automountMapName=auto_home,dc=foo,dc=com
4686 mapped_len
= strlen(mapped_attr
);
4687 orig_len
= strlen(orig_attr
);
4688 dn_len
= strlen(dn
);
4689 len
= dn_len
+ orig_len
- mapped_len
+ 1;
4690 *new_dn
= (char *)calloc(1, len
);
4691 if (*new_dn
== NULL
) {
4692 __s_api_free2dArray(dnArray
);
4693 return (NS_LDAP_MEMORY
);
4697 * Locate the mapped attr in the dn.
4698 * Use dnArray[i] instead of mapped_attr
4699 * because mapped_attr could appear in
4703 cur
= strstr(dn
, dnArray
[i
]);
4704 __s_api_free2dArray(dnArray
);
4705 /* copy the portion before mapped attr in dn */
4708 (void) memcpy((void *) start
, (const void*) dn
, tmp_len
);
4711 * Copy the orig_attr. e.g. automountMapName
4712 * This replaces mapped attr with orig attr
4714 start
= start
+ (cur
- dn
); /* move cursor in buffer */
4715 (void) memcpy((void *) start
, (const void*) orig_attr
, orig_len
);
4718 * Copy the portion after mapped attr in dn
4720 cur
= cur
+ mapped_len
; /* move cursor in dn */
4721 start
= start
+ orig_len
; /* move cursor in buffer */
4722 (void) strcpy(start
, cur
);
4724 return (NS_LDAP_SUCCESS
);
4728 * Validate Filter functions
4731 /* ***** Start of modified libldap.so.5 filter parser ***** */
4733 /* filter parsing routine forward references */
4734 static int adj_filter_list(char *str
);
4735 static int adj_simple_filter(char *str
);
4736 static int unescape_filterval(char *val
);
4737 static int hexchar2int(char c
);
4738 static int adj_substring_filter(char *val
);
4742 * assumes string manipulation is in-line
4743 * and all strings are sufficient in size
4744 * return value is the position after 'c'
4748 resync_str(char *str
, char *next
, char c
)
4752 ret
= str
+ strlen(str
);
4756 (void) strcat(str
, next
);
4761 find_right_paren(char *s
)
4763 int balance
, escape
;
4767 while (*s
&& balance
) {
4774 if (*s
== '\\' && ! escape
)
4782 return (*s
? s
: NULL
);
4786 adj_complex_filter(char *str
)
4791 * We have (x(filter)...) with str sitting on
4792 * the x. We have to find the paren matching
4793 * the one before the x and put the intervening
4794 * filters by calling adj_filter_list().
4798 if ((next
= find_right_paren(str
)) == NULL
)
4802 if (adj_filter_list(str
) == -1)
4804 next
= resync_str(str
, next
, ')');
4811 adj_filter(char *str
)
4814 int parens
, balance
, escape
;
4825 if ((str
= adj_complex_filter(str
)) == NULL
)
4832 if ((str
= adj_complex_filter(str
)) == NULL
)
4839 if ((str
= adj_complex_filter(str
)) == NULL
)
4846 /* illegal ((case - generated by conversion */
4848 /* find missing close) */
4849 np
= find_right_paren(str
+1);
4851 /* error if not found */
4855 /* remove redundant (and) */
4856 for (dp
= str
, cp
= str
+1; cp
< np
; ) {
4864 /* re-start test at original ( */
4873 while (*next
&& balance
) {
4877 else if (*next
== ')')
4880 if (*next
== '\\' && ! escape
)
4891 if (adj_simple_filter(str
) == -1) {
4894 next
= resync_str(str
, next
, ')');
4911 default: /* assume it's a simple type=value filter */
4912 next
= strchr(str
, '\0');
4913 if (adj_simple_filter(str
) == -1) {
4921 return (parens
? -1 : 0);
4926 * Put a list of filters like this "(filter1)(filter2)..."
4930 adj_filter_list(char *str
)
4936 while (*str
&& isspace(*str
))
4941 if ((next
= find_right_paren(str
+ 1)) == NULL
)
4945 /* now we have "(filter)" with str pointing to it */
4947 if (adj_filter(str
) == -1)
4949 next
= resync_str(str
, next
, save
);
4959 * is_valid_attr - returns 1 if a is a syntactically valid left-hand side
4960 * of a filter expression, 0 otherwise. A valid string may contain only
4961 * letters, numbers, hyphens, semi-colons, colons and periods. examples:
4964 * 1.2.3.4;binary;dynamic
4968 * For compatibility with older servers, we also allow underscores in
4969 * attribute types, even through they are not allowed by the LDAPv3 RFCs.
4972 is_valid_attr(char *a
)
4977 } else if (!isalnum(*a
)) {
5002 if (hexchar2int(s
[0]) >= 0 && hexchar2int(s
[1]) >= 0)
5012 adj_simple_filter(char *str
)
5014 char *s
, *s2
, *s3
, filterop
;
5019 rc
= -1; /* pessimistic */
5021 if ((str
= strdup(str
)) == NULL
) {
5025 if ((s
= strchr(str
, '=')) == NULL
) {
5026 goto free_and_return
;
5031 if (filterop
== '<' || filterop
== '>' || filterop
== '~' ||
5036 if (! is_valid_attr(str
)) {
5037 goto free_and_return
;
5041 case '<': /* LDAP_FILTER_LE */
5042 case '>': /* LDAP_FILTER_GE */
5043 case '~': /* LDAP_FILTER_APPROX */
5045 case ':': /* extended filter - v3 only */
5047 * extended filter looks like this:
5049 * [type][':dn'][':'oid]':='value
5051 * where one of type or :oid is required.
5055 if ((s2
= strrchr(str
, ':')) == NULL
) {
5056 goto free_and_return
;
5058 if (strcasecmp(s2
, ":dn") == 0) {
5062 if ((s3
= strrchr(str
, ':')) != NULL
) {
5063 if (strcasecmp(s3
, ":dn") != 0) {
5064 goto free_and_return
;
5069 if (unescape_filterval(value
) < 0) {
5070 goto free_and_return
;
5073 goto free_and_return
;
5076 if (find_star(value
) == NULL
) {
5077 ftype
= 0; /* LDAP_FILTER_EQUALITY */
5078 } else if (strcmp(value
, "*") == 0) {
5079 ftype
= 1; /* LDAP_FILTER_PRESENT */
5081 rc
= adj_substring_filter(value
);
5082 goto free_and_return
;
5087 if (ftype
!= 0) { /* == LDAP_FILTER_PRESENT */
5089 } else if (unescape_filterval(value
) >= 0) {
5103 * Check in place both LDAPv2 (RFC-1960) and LDAPv3 (hexadecimal) escape
5104 * sequences within the null-terminated string 'val'.
5106 * If 'val' contains invalid escape sequences we return -1.
5107 * Otherwise return 1
5110 unescape_filterval(char *val
)
5112 int escape
, firstdigit
;
5117 for (s
= val
; *s
; s
++) {
5120 * first try LDAPv3 escape (hexadecimal) sequence
5122 if (hexchar2int(*s
) < 0) {
5125 * LDAPv2 (RFC1960) escape sequence
5138 } else if (*s
!= '\\') {
5152 * convert character 'c' that represents a hexadecimal digit to an integer.
5153 * if 'c' is not a hexidecimal digit [0-9A-Fa-f], -1 is returned.
5154 * otherwise the converted value is returned.
5159 if (c
>= '0' && c
<= '9') {
5162 if (c
>= 'A' && c
<= 'F') {
5163 return (c
- 'A' + 10);
5165 if (c
>= 'a' && c
<= 'f') {
5166 return (c
- 'a' + 10);
5172 adj_substring_filter(char *val
)
5176 for (; val
!= NULL
; val
= nextstar
) {
5177 if ((nextstar
= find_star(val
)) != NULL
) {
5182 if (unescape_filterval(val
) < 0) {
5191 /* ***** End of modified libldap.so.5 filter parser ***** */
5195 * Walk filter, remove redundant parentheses in-line
5196 * verify that the filter is reasonable
5199 validate_filter(ns_ldap_cookie_t
*cookie
)
5201 char *filter
= cookie
->filter
;
5204 /* Parse filter looking for illegal values */
5206 rc
= adj_filter(filter
);
5208 return (NS_LDAP_OP_FAILED
);
5211 /* end of filter checking */
5213 return (NS_LDAP_SUCCESS
);
5217 * Set the account management request control that needs to be sent to server.
5218 * This control is required to get the account management information of
5219 * a user to do local account checking.
5222 setup_acctmgmt_params(ns_ldap_cookie_t
*cookie
)
5224 LDAPControl
*req
= NULL
, **requestctrls
;
5226 req
= (LDAPControl
*)malloc(sizeof (LDAPControl
));
5229 return (NS_LDAP_MEMORY
);
5231 /* fill in the fields of this new control */
5232 req
->ldctl_iscritical
= 1;
5233 req
->ldctl_oid
= strdup(NS_LDAP_ACCOUNT_USABLE_CONTROL
);
5234 if (req
->ldctl_oid
== NULL
) {
5236 return (NS_LDAP_MEMORY
);
5238 req
->ldctl_value
.bv_len
= 0;
5239 req
->ldctl_value
.bv_val
= NULL
;
5241 requestctrls
= (LDAPControl
**)calloc(2, sizeof (LDAPControl
*));
5242 if (requestctrls
== NULL
) {
5243 ldap_control_free(req
);
5244 return (NS_LDAP_MEMORY
);
5247 requestctrls
[0] = req
;
5249 cookie
->p_serverctrls
= requestctrls
;
5251 return (NS_LDAP_SUCCESS
);
5255 * int get_new_acct_more_info(BerElement *ber,
5256 * AcctUsableResponse_t *acctResp)
5258 * Decode the more_info data from an Account Management control response,
5259 * when the account is not usable and when code style is from recent LDAP
5260 * servers (see below comments for parse_acct_cont_resp_msg() to get more
5261 * details on coding styles and ASN1 description).
5263 * Expected BER encoding: {tbtbtbtiti}
5265 * +b: TRUE if inactive due to account inactivation
5267 * +b: TRUE if password has been reset
5269 * +b: TRUE if password is expired
5271 * +i: contains num of remaining grace, 0 means no grace
5273 * +i: contains num of seconds before auto-unlock. -1 means acct is locked
5274 * forever (i.e. until reset)
5278 * - acctResp is not null and is initialized with default values for the
5279 * fields in its AcctUsableResp.more_info structure
5280 * - the ber stream is received in the correct order, per the ASN1 description.
5281 * We do not check this order and make the asumption that it is correct.
5282 * Note that the ber stream may not (and will not in most cases) contain
5286 get_new_acct_more_info(BerElement
*ber
, AcctUsableResponse_t
*acctResp
)
5288 int rc
= NS_LDAP_SUCCESS
;
5289 char errstr
[MAXERROR
];
5290 ber_tag_t rTag
= LBER_DEFAULT
;
5297 * Look at what more_info BER element is/are left to be decoded.
5298 * look at each of them 1 by 1, without checking on their order
5299 * and possible multi values.
5301 for (rTag
= ber_first_element(ber
, &rLen
, &last
);
5302 rTag
!= LBER_END_OF_SEQORSET
;
5303 rTag
= ber_next_element(ber
, &rLen
, last
)) {
5307 case 0 | LBER_CLASS_CONTEXT
| LBER_PRIMITIVE
:
5309 berRC
= ber_scanf(ber
, "b", &rValue
);
5310 if (berRC
!= LBER_ERROR
) {
5311 (acctResp
->AcctUsableResp
).more_info
.
5312 inactive
= (rValue
!= 0) ? 1 : 0;
5316 case 1 | LBER_CLASS_CONTEXT
| LBER_PRIMITIVE
:
5318 berRC
= ber_scanf(ber
, "b", &rValue
);
5319 if (berRC
!= LBER_ERROR
) {
5320 (acctResp
->AcctUsableResp
).more_info
.reset
5321 = (rValue
!= 0) ? 1 : 0;
5325 case 2 | LBER_CLASS_CONTEXT
| LBER_PRIMITIVE
:
5327 berRC
= ber_scanf(ber
, "b", &rValue
);
5328 if (berRC
!= LBER_ERROR
) {
5329 (acctResp
->AcctUsableResp
).more_info
.expired
5330 = (rValue
!= 0) ? 1 : 0;
5334 case 3 | LBER_CLASS_CONTEXT
| LBER_PRIMITIVE
:
5335 /* remaining grace */
5336 berRC
= ber_scanf(ber
, "i", &rValue
);
5337 if (berRC
!= LBER_ERROR
) {
5338 (acctResp
->AcctUsableResp
).more_info
.rem_grace
5343 case 4 | LBER_CLASS_CONTEXT
| LBER_PRIMITIVE
:
5344 /* seconds before unlock */
5345 berRC
= ber_scanf(ber
, "i", &rValue
);
5346 if (berRC
!= LBER_ERROR
) {
5347 (acctResp
->AcctUsableResp
).more_info
.
5348 sec_b4_unlock
= rValue
;
5353 (void) sprintf(errstr
,
5354 gettext("invalid reason tag 0x%x"), rTag
);
5355 syslog(LOG_DEBUG
, "libsldap: %s", errstr
);
5356 rc
= NS_LDAP_INTERNAL
;
5359 if (berRC
== LBER_ERROR
) {
5360 (void) sprintf(errstr
,
5361 gettext("error 0x%x decoding value for "
5362 "tag 0x%x"), berRC
, rTag
);
5363 syslog(LOG_DEBUG
, "libsldap: %s", errstr
);
5364 rc
= NS_LDAP_INTERNAL
;
5366 if (rc
!= NS_LDAP_SUCCESS
) {
5367 /* exit the for loop */
5376 * int get_old_acct_opt_more_info(BerElement *ber,
5377 * AcctUsableResponse_t *acctResp)
5379 * Decode the optional more_info data from an Account Management control
5380 * response, when the account is not usable and when code style is from LDAP
5381 * server 5.2p4 (see below comments for parse_acct_cont_resp_msg() to get more
5382 * details on coding styles and ASN1 description).
5384 * Expected BER encoding: titi}
5386 * +i: contains num of remaining grace, 0 means no grace
5388 * +i: contains num of seconds before auto-unlock. -1 means acct is locked
5389 * forever (i.e. until reset)
5392 * - ber is a valid BER element
5393 * - acctResp is initialized for the fields in its AcctUsableResp.more_info
5397 get_old_acct_opt_more_info(ber_tag_t tag
, BerElement
*ber
,
5398 AcctUsableResponse_t
*acctResp
)
5400 int rc
= NS_LDAP_SUCCESS
;
5401 char errstr
[MAXERROR
];
5403 int rem_grace
, sec_b4_unlock
;
5407 /* decode and maybe 3 is following */
5408 if ((tag
= ber_scanf(ber
, "i", &rem_grace
)) == LBER_ERROR
) {
5409 (void) sprintf(errstr
, gettext("Can not get "
5411 syslog(LOG_DEBUG
, "libsldap: %s", errstr
);
5412 rc
= NS_LDAP_INTERNAL
;
5415 (acctResp
->AcctUsableResp
).more_info
.rem_grace
= rem_grace
;
5417 if ((tag
= ber_peek_tag(ber
, &len
)) == LBER_ERROR
) {
5418 /* this is a success case, break to exit */
5419 (void) sprintf(errstr
, gettext("No more "
5421 syslog(LOG_DEBUG
, "libsldap: %s", errstr
);
5426 if (ber_scanf(ber
, "i", &sec_b4_unlock
) == LBER_ERROR
) {
5427 (void) sprintf(errstr
,
5428 gettext("Can not get sec_b4_unlock "
5430 syslog(LOG_DEBUG
, "libsldap: %s", errstr
);
5431 rc
= NS_LDAP_INTERNAL
;
5434 (acctResp
->AcctUsableResp
).more_info
.sec_b4_unlock
=
5436 } else { /* unknown tag */
5437 (void) sprintf(errstr
, gettext("Unknown tag "
5439 syslog(LOG_DEBUG
, "libsldap: %s", errstr
);
5440 rc
= NS_LDAP_INTERNAL
;
5446 if (ber_scanf(ber
, "i", &sec_b4_unlock
) == LBER_ERROR
) {
5447 (void) sprintf(errstr
, gettext("Can not get "
5448 "sec_b4_unlock - 2nd case"));
5449 syslog(LOG_DEBUG
, "libsldap: %s", errstr
);
5450 rc
= NS_LDAP_INTERNAL
;
5453 (acctResp
->AcctUsableResp
).more_info
.sec_b4_unlock
=
5457 default: /* unknown tag */
5458 (void) sprintf(errstr
, gettext("Unknown tag - 2nd case"));
5459 syslog(LOG_DEBUG
, "libsldap: %s", errstr
);
5460 rc
= NS_LDAP_INTERNAL
;
5468 * **** This function needs to be moved to libldap library ****
5469 * parse_acct_cont_resp_msg() parses the message received by server according to
5470 * following format (ASN1 notation):
5472 * ACCOUNT_USABLE_RESPONSE::= CHOICE {
5473 * is_available [0] INTEGER,
5474 * ** seconds before expiration **
5475 * is_not_available [1] more_info
5477 * more_info::= SEQUENCE {
5478 * inactive [0] BOOLEAN DEFAULT FALSE,
5479 * reset [1] BOOLEAN DEFAULT FALSE,
5480 * expired [2] BOOLEAN DEFAULT FALSE,
5481 * remaining_grace [3] INTEGER OPTIONAL,
5482 * seconds_before_unlock [4] INTEGER OPTIONAL
5486 * #define used to make the difference between coding style as done
5487 * by LDAP server 5.2p4 and newer LDAP servers. There are 4 values:
5488 * - DS52p4_USABLE: 5.2p4 coding style, account is usable
5489 * - DS52p4_NOT_USABLE: 5.2p4 coding style, account is not usable
5490 * - NEW_USABLE: newer LDAP servers coding style, account is usable
5491 * - NEW_NOT_USABLE: newer LDAP servers coding style, account is not usable
5493 * An account would be considered not usable if for instance:
5494 * - it's been made inactive in the LDAP server
5495 * - or its password was reset in the LDAP server database
5496 * - or its password expired
5497 * - or the account has been locked, possibly forever
5499 #define DS52p4_USABLE 0x00
5500 #define DS52p4_NOT_USABLE 0x01
5501 #define NEW_USABLE 0x00 | LBER_CLASS_CONTEXT | LBER_PRIMITIVE
5502 #define NEW_NOT_USABLE 0x01 | LBER_CLASS_CONTEXT | LBER_CONSTRUCTED
5504 parse_acct_cont_resp_msg(LDAPControl
**ectrls
, AcctUsableResponse_t
*acctResp
)
5506 int rc
= NS_LDAP_SUCCESS
;
5511 char errstr
[MAXERROR
];
5512 /* used for any coding style when account is usable */
5513 int seconds_before_expiry
;
5514 /* used for 5.2p4 coding style when account is not usable */
5515 int inactive
, reset
, expired
;
5517 if (ectrls
== NULL
) {
5518 (void) sprintf(errstr
, gettext("Invalid ectrls parameter"));
5519 syslog(LOG_DEBUG
, "libsldap: %s", errstr
);
5520 return (NS_LDAP_INVALID_PARAM
);
5523 for (i
= 0; ectrls
[i
] != NULL
; i
++) {
5524 if (strcmp(ectrls
[i
]->ldctl_oid
, NS_LDAP_ACCOUNT_USABLE_CONTROL
)
5530 if (ectrls
[i
] == NULL
) {
5531 /* Ldap control is not found */
5532 (void) sprintf(errstr
, gettext("Account Usable Control "
5534 syslog(LOG_DEBUG
, "libsldap: %s", errstr
);
5535 return (NS_LDAP_NOTFOUND
);
5538 /* Allocate a BER element from the control value and parse it. */
5539 if ((ber
= ber_init(&ectrls
[i
]->ldctl_value
)) == NULL
)
5540 return (NS_LDAP_MEMORY
);
5542 if ((tag
= ber_peek_tag(ber
, &len
)) == LBER_ERROR
) {
5543 /* Ldap decoding error */
5544 (void) sprintf(errstr
, gettext("Error decoding 1st tag"));
5545 syslog(LOG_DEBUG
, "libsldap: %s", errstr
);
5547 return (NS_LDAP_INTERNAL
);
5553 acctResp
->choice
= 0;
5554 if (ber_scanf(ber
, "i", &seconds_before_expiry
)
5556 /* Ldap decoding error */
5557 (void) sprintf(errstr
, gettext("Can not get "
5558 "seconds_before_expiry"));
5559 syslog(LOG_DEBUG
, "libsldap: %s", errstr
);
5560 rc
= NS_LDAP_INTERNAL
;
5563 /* ber_scanf() succeeded */
5564 (acctResp
->AcctUsableResp
).seconds_before_expiry
=
5565 seconds_before_expiry
;
5568 case DS52p4_NOT_USABLE
:
5569 acctResp
->choice
= 1;
5570 if (ber_scanf(ber
, "{bbb", &inactive
, &reset
, &expired
)
5572 /* Ldap decoding error */
5573 (void) sprintf(errstr
, gettext("Can not get "
5574 "inactive/reset/expired"));
5575 syslog(LOG_DEBUG
, "libsldap: %s", errstr
);
5576 rc
= NS_LDAP_INTERNAL
;
5579 /* ber_scanf() succeeded */
5580 (acctResp
->AcctUsableResp
).more_info
.inactive
=
5581 ((inactive
== 0) ? 0 : 1);
5582 (acctResp
->AcctUsableResp
).more_info
.reset
=
5583 ((reset
== 0) ? 0 : 1);
5584 (acctResp
->AcctUsableResp
).more_info
.expired
=
5585 ((expired
== 0) ? 0 : 1);
5586 (acctResp
->AcctUsableResp
).more_info
.rem_grace
= 0;
5587 (acctResp
->AcctUsableResp
).more_info
.sec_b4_unlock
= 0;
5589 if ((tag
= ber_peek_tag(ber
, &len
)) == LBER_ERROR
) {
5590 /* this is a success case, break to exit */
5591 (void) sprintf(errstr
, gettext("No optional data"));
5592 syslog(LOG_DEBUG
, "libsldap: %s", errstr
);
5597 * Look at what optional more_info BER element is/are
5598 * left to be decoded.
5600 rc
= get_old_acct_opt_more_info(tag
, ber
, acctResp
);
5603 case NEW_NOT_USABLE
:
5604 acctResp
->choice
= 1;
5606 * Recent LDAP servers won't code more_info data for default
5607 * values (see above comments on ASN1 description for what
5608 * fields have default values & what fields are optional).
5610 (acctResp
->AcctUsableResp
).more_info
.inactive
= 0;
5611 (acctResp
->AcctUsableResp
).more_info
.reset
= 0;
5612 (acctResp
->AcctUsableResp
).more_info
.expired
= 0;
5613 (acctResp
->AcctUsableResp
).more_info
.rem_grace
= 0;
5614 (acctResp
->AcctUsableResp
).more_info
.sec_b4_unlock
= 0;
5618 * Nothing else to decode; this is valid and we
5619 * use default values set above.
5621 (void) sprintf(errstr
, gettext("more_info is "
5622 "empty, using default values"));
5623 syslog(LOG_DEBUG
, "libsldap: %s", errstr
);
5628 * Look at what more_info BER element is/are left to
5631 rc
= get_new_acct_more_info(ber
, acctResp
);
5635 (void) sprintf(errstr
, gettext("unknwon coding style "
5636 "(tag: 0x%x)"), tag
);
5637 syslog(LOG_DEBUG
, "libsldap: %s", errstr
);
5638 rc
= NS_LDAP_INTERNAL
;
5647 * internal function for __ns_ldap_getAcctMgmt()
5650 getAcctMgmt(const char *user
, AcctUsableResponse_t
*acctResp
,
5651 ns_conn_user_t
*conn_user
)
5654 char ldapfilter
[1024];
5655 ns_ldap_cookie_t
*cookie
;
5656 ns_ldap_search_desc_t
**sdlist
= NULL
;
5657 ns_ldap_search_desc_t
*dptr
;
5658 ns_ldap_error_t
*error
= NULL
;
5660 char service
[] = "shadow";
5662 if (user
== NULL
|| acctResp
== NULL
)
5663 return (NS_LDAP_INVALID_PARAM
);
5665 /* Initialize State machine cookie */
5666 cookie
= init_search_state_machine();
5668 return (NS_LDAP_MEMORY
);
5669 cookie
->conn_user
= conn_user
;
5671 /* see if need to follow referrals */
5672 rc
= __s_api_toFollowReferrals(0,
5673 &cookie
->followRef
, &error
);
5674 if (rc
!= NS_LDAP_SUCCESS
) {
5675 (void) __ns_ldap_freeError(&error
);
5679 /* get the service descriptor - or create a default one */
5680 rc
= __s_api_get_SSD_from_SSDtoUse_service(service
,
5682 if (rc
!= NS_LDAP_SUCCESS
) {
5683 (void) __ns_ldap_freeError(&error
);
5687 if (sdlist
== NULL
) {
5688 /* Create default service Desc */
5689 sdlist
= (ns_ldap_search_desc_t
**)calloc(2,
5690 sizeof (ns_ldap_search_desc_t
*));
5691 if (sdlist
== NULL
) {
5692 rc
= NS_LDAP_MEMORY
;
5695 dptr
= (ns_ldap_search_desc_t
*)
5696 calloc(1, sizeof (ns_ldap_search_desc_t
));
5699 rc
= NS_LDAP_MEMORY
;
5705 rc
= __s_api_getDNs(&dns
, service
, &cookie
->errorp
);
5706 if (rc
!= NS_LDAP_SUCCESS
) {
5708 __s_api_free2dArray(dns
);
5711 (void) __ns_ldap_freeError(&(cookie
->errorp
));
5712 cookie
->errorp
= NULL
;
5715 dptr
->basedn
= strdup(dns
[0]);
5716 if (dptr
->basedn
== NULL
) {
5720 __s_api_free2dArray(dns
);
5723 rc
= NS_LDAP_MEMORY
;
5726 __s_api_free2dArray(dns
);
5731 rc
= __s_api_getSearchScope(&scope
, &cookie
->errorp
);
5732 dptr
->scope
= scope
;
5735 cookie
->sdlist
= sdlist
;
5737 cookie
->service
= strdup(service
);
5738 if (cookie
->service
== NULL
) {
5739 rc
= NS_LDAP_MEMORY
;
5743 /* search for entries for this particular uid */
5744 (void) snprintf(ldapfilter
, sizeof (ldapfilter
), "(uid=%s)", user
);
5745 cookie
->i_filter
= strdup(ldapfilter
);
5746 if (cookie
->i_filter
== NULL
) {
5747 rc
= NS_LDAP_MEMORY
;
5751 /* create the control request */
5752 if ((rc
= setup_acctmgmt_params(cookie
)) != NS_LDAP_SUCCESS
)
5755 /* Process search */
5756 rc
= search_state_machine(cookie
, GET_ACCT_MGMT_INFO
, 0);
5758 /* Copy results back to user */
5759 rc
= cookie
->err_rc
;
5760 if (rc
!= NS_LDAP_SUCCESS
)
5761 (void) __ns_ldap_freeError(&(cookie
->errorp
));
5763 if (cookie
->result
== NULL
)
5766 if ((rc
= parse_acct_cont_resp_msg(cookie
->resultctrl
, acctResp
))
5770 rc
= NS_LDAP_SUCCESS
;
5773 delete_search_cookie(cookie
);
5779 * __ns_ldap_getAcctMgmt() is called from pam account management stack
5780 * for retrieving accounting information of users with no user password -
5781 * eg. rlogin, rsh, etc. This function uses the account management control
5782 * request to do a search on the server for the user in question. The
5783 * response control returned from the server is got from the cookie.
5784 * Input params: username of whose account mgmt information is to be got
5785 * pointer to hold the parsed account management information
5786 * Return values: NS_LDAP_SUCCESS on success or appropriate error
5790 __ns_ldap_getAcctMgmt(const char *user
, AcctUsableResponse_t
*acctResp
)
5792 ns_conn_user_t
*cu
= NULL
;
5794 int rc
= NS_LDAP_SUCCESS
;
5795 ns_ldap_error_t
*error
= NULL
;
5798 if (__s_api_setup_retry_search(&cu
, NS_CONN_USER_SEARCH
,
5799 &try_cnt
, &rc
, &error
) == 0)
5801 rc
= getAcctMgmt(user
, acctResp
, cu
);