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 free(ep
->attr_pair
[j
]->attrname
);
68 if (ep
->attr_pair
[j
]->attrvalue
) {
69 for (k
= 0; (k
< ep
->attr_pair
[j
]->value_count
) &&
70 (ep
->attr_pair
[j
]->attrvalue
[k
]); k
++) {
71 free(ep
->attr_pair
[j
]->attrvalue
[k
]);
73 free(ep
->attr_pair
[j
]->attrvalue
);
75 free(ep
->attr_pair
[j
]);
82 _freeControlList(LDAPControl
***ctrls
)
86 if (ctrls
== NULL
|| *ctrls
== NULL
)
89 for (ctrl
= *ctrls
; *ctrl
!= NULL
; ctrl
++)
90 ldap_control_free(*ctrl
);
95 * Convert attribute type in a RDN that has an attribute mapping to the
96 * original mappped type.
98 * cn<->cn-st and iphostnumber<->iphostnumber-st
99 * cn-st=aaa+iphostnumber-st=10.10.01.01
101 * cn=aaa+iphostnumber=10.10.01.01
103 * Input - service: e.g. hosts, passwd etc.
105 * Return: NULL - No attribute mapping in the RDN
106 * Non-NULL - The attribute type(s) in the RDN are mapped and
107 * the memory is allocated for the new rdn.
111 _cvtRDN(const char *service
, const char *rdn
) {
112 char **attrs
, **mapped_attrs
, **mapp
, *type
, *value
, *attr
;
113 char *new_rdn
= NULL
;
114 int nAttr
= 0, i
, attr_mapped
, len
= 0;
116 /* Break down "type=value\0" pairs. Assume RDN is normalized */
117 if ((attrs
= ldap_explode_rdn(rdn
, 0)) == NULL
)
120 for (nAttr
= 0; attrs
[nAttr
] != NULL
; nAttr
++);
122 if ((mapped_attrs
= (char **)calloc(nAttr
, sizeof (char *))) == NULL
) {
123 ldap_value_free(attrs
);
128 for (i
= 0; i
< nAttr
; i
++) {
129 /* Parse type=value pair */
130 if ((type
= strtok_r(attrs
[i
], "=", &value
)) == NULL
||
133 /* Reverse map: e.g. cn-sm -> cn */
134 mapp
= __ns_ldap_getOrigAttribute(service
, type
);
135 if (mapp
!= NULL
&& mapp
[0] != NULL
) {
136 /* The attribute mapping is found */
141 len
= strlen(type
) + strlen(value
) + 2;
143 /* Reconstruct type=value pair. A string is allocated */
144 if ((attr
= (char *)calloc(1, len
)) == NULL
) {
145 __s_api_free2dArray(mapp
);
148 (void) snprintf(attr
, len
, "%s=%s",
150 mapped_attrs
[i
] = attr
;
153 * No attribute mapping. attrs[i] is going to be copied
154 * later. Restore "type\0value\0" back to
157 type
[strlen(type
)] = '=';
159 __s_api_free2dArray(mapp
);
161 if (attr_mapped
== 0)
162 /* No attribute mapping. Don't bother to reconstruct RDN */
166 /* Reconstruct RDN from type=value pairs */
167 for (i
= 0; i
< nAttr
; i
++) {
169 len
+= strlen(mapped_attrs
[i
]);
171 len
+= strlen(attrs
[i
]);
175 if ((new_rdn
= (char *)calloc(1, ++len
)) == NULL
)
177 for (i
= 0; i
< nAttr
; i
++) {
180 (void) strlcat(new_rdn
, "+", len
);
183 (void) strlcat(new_rdn
, mapped_attrs
[i
], len
);
185 (void) strlcat(new_rdn
, attrs
[i
], len
);
189 ldap_value_free(attrs
);
192 for (i
= 0; i
< nAttr
; i
++) {
193 free(mapped_attrs
[i
]);
202 * Convert attribute type in a DN that has an attribute mapping to the
203 * original mappped type.
205 * The mappings are cn<->cn-sm, iphostnumber<->iphostnumber-sm
207 * dn: cn-sm=aaa+iphostnumber-sm=9.9.9.9,dc=central,dc=sun,dc=com
209 * dn: cn=aaa+iphostnumber=9.9.9.9,dc=central,dc=sun,dc=com
211 * Input - service: e.g. hosts, passwd etc.
212 * dn: the value of a distinguished name
213 * Return - NULL: error
214 * non-NULL: A converted DN and the memory is allocated
217 _cvtDN(const char *service
, const char *dn
) {
219 char **rdns
, *new_rdn
, *new_dn
= NULL
;
220 int nRdn
= 0, i
, len
= 0, rdn_mapped
;
222 if (service
== NULL
|| dn
== NULL
)
225 if ((rdns
= ldap_explode_dn(dn
, 0)) == NULL
)
228 for (nRdn
= 0; rdns
[nRdn
] != NULL
; nRdn
++);
230 if ((mapped_rdns
= (char **)calloc(nRdn
, sizeof (char *))) == NULL
) {
231 ldap_value_free(rdns
);
236 /* Break down RDNs in a DN */
237 for (i
= 0; i
< nRdn
; i
++) {
238 if ((new_rdn
= _cvtRDN(service
, rdns
[i
])) != NULL
) {
239 mapped_rdns
[i
] = new_rdn
;
243 if (rdn_mapped
== 0) {
245 * No RDN contains any attribute mapping.
246 * Don't bother to reconstruct DN from RDN. Copy DN directly.
252 * Reconstruct dn from RDNs.
253 * Calculate the length first.
255 for (i
= 0; i
< nRdn
; i
++) {
257 len
+= strlen(mapped_rdns
[i
]);
259 len
+= strlen(rdns
[i
]);
264 if ((new_dn
= (char *)calloc(1, ++len
)) == NULL
)
266 for (i
= 0; i
< nRdn
; i
++) {
269 (void) strlcat(new_dn
, ",", len
);
272 (void) strlcat(new_dn
, mapped_rdns
[i
], len
);
274 (void) strlcat(new_dn
, rdns
[i
], len
);
279 ldap_value_free(rdns
);
282 for (i
= 0; i
< nRdn
; i
++) {
283 free(mapped_rdns
[i
]);
292 * Convert a single ldap entry from a LDAPMessage
293 * into an ns_ldap_entry structure.
294 * Schema map the entry if specified in flags
298 __s_api_cvtEntry(LDAP
*ld
,
302 ns_ldap_entry_t
**ret
,
303 ns_ldap_error_t
**error
)
306 ns_ldap_entry_t
*ep
= NULL
;
307 ns_ldap_attr_t
**ap
= NULL
;
315 char **gecos_mapping
= NULL
;
316 int gecos_val_index
[3] = { -1, -1, -1};
317 char errstr
[MAXERROR
];
318 int schema_mapping_existed
= FALSE
;
319 int gecos_mapping_existed
= FALSE
;
320 int gecos_attr_matched
;
321 int auto_service
= FALSE
;
322 int rc
= NS_LDAP_SUCCESS
;
324 if (e
== NULL
|| ret
== NULL
|| error
== NULL
)
325 return (NS_LDAP_INVALID_PARAM
);
329 ep
= (ns_ldap_entry_t
*)calloc(1, sizeof (ns_ldap_entry_t
));
331 return (NS_LDAP_MEMORY
);
333 if (service
!= NULL
&&
334 (strncasecmp(service
, "auto_", 5) == 0 ||
335 strcasecmp(service
, "automount") == 0))
338 * see if schema mapping existed for the given service
340 mapping
= __ns_ldap_getOrigAttribute(service
,
341 NS_HASH_SCHEMA_MAPPING_EXISTED
);
343 schema_mapping_existed
= TRUE
;
344 __s_api_free2dArray(mapping
);
346 } else if (auto_service
) {
348 * If service == auto_* and no
349 * schema mapping found
351 * There is certain case that schema mapping exist
352 * but __ns_ldap_getOrigAttribute(service,
353 * NS_HASH_SCHEMA_MAPPING_EXISTED);
356 * NS_LDAP_ATTRIBUTEMAP = automount:automountMapName=AAA
357 * NS_LDAP_OBJECTCLASSMAP = automount:automountMap=MynisMap
358 * NS_LDAP_OBJECTCLASSMAP = automount:automount=MynisObject
360 * Make a check for schema_mapping_existed here
361 * so later on __s_api_convert_automountmapname won't be called
362 * unnecessarily. It is also used for attribute mapping
363 * and objectclass mapping.
365 mapping
= __ns_ldap_getOrigAttribute("automount",
366 NS_HASH_SCHEMA_MAPPING_EXISTED
);
368 schema_mapping_existed
= TRUE
;
369 __s_api_free2dArray(mapping
);
374 nAttrs
= 1; /* start with 1 for the DN attr */
375 for (attr
= ldap_first_attribute(ld
, e
, &ber
); attr
!= NULL
;
376 attr
= ldap_next_attribute(ld
, e
, ber
)) {
384 ep
->attr_count
= nAttrs
;
387 * add 1 for "gecos" 1 to N attribute mapping,
388 * just in case it is needed.
389 * ep->attr_count will be updated later if that is true.
391 ap
= (ns_ldap_attr_t
**)calloc(ep
->attr_count
+ 1,
392 sizeof (ns_ldap_attr_t
*));
394 __ns_ldap_freeEntry(ep
);
396 return (NS_LDAP_MEMORY
);
401 dn
= ldap_get_dn(ld
, e
);
402 ap
[0] = (ns_ldap_attr_t
*)calloc(1, sizeof (ns_ldap_attr_t
));
406 __ns_ldap_freeEntry(ep
);
408 return (NS_LDAP_MEMORY
);
411 if ((ap
[0]->attrname
= strdup("dn")) == NULL
) {
414 __ns_ldap_freeEntry(ep
);
416 return (NS_LDAP_INVALID_PARAM
);
418 ap
[0]->value_count
= 1;
419 if ((ap
[0]->attrvalue
= (char **)
420 calloc(2, sizeof (char *))) == NULL
) {
423 __ns_ldap_freeEntry(ep
);
425 return (NS_LDAP_MEMORY
);
428 if (schema_mapping_existed
&& ((flags
& NS_LDAP_NOT_CVT_DN
) == 0))
429 ap
[0]->attrvalue
[0] = _cvtDN(service
, dn
);
431 ap
[0]->attrvalue
[0] = strdup(dn
);
433 if (ap
[0]->attrvalue
[0] == NULL
) {
436 __ns_ldap_freeEntry(ep
);
438 return (NS_LDAP_MEMORY
);
443 if ((flags
& NS_LDAP_NOMAP
) == 0 && auto_service
&&
444 schema_mapping_existed
) {
445 rc
= __s_api_convert_automountmapname(service
,
446 &ap
[0]->attrvalue
[0],
448 if (rc
!= NS_LDAP_SUCCESS
) {
449 __ns_ldap_freeEntry(ep
);
455 /* other attributes */
456 for (attr
= ldap_first_attribute(ld
, e
, &ber
), j
= 1;
457 attr
!= NULL
&& j
!= nAttrs
;
458 attr
= ldap_next_attribute(ld
, e
, ber
), j
++) {
459 /* allocate new attr name */
461 if ((ap
[j
] = (ns_ldap_attr_t
*)
462 calloc(1, sizeof (ns_ldap_attr_t
))) == NULL
) {
465 __ns_ldap_freeEntry(ep
);
468 __s_api_free2dArray(gecos_mapping
);
469 gecos_mapping
= NULL
;
470 return (NS_LDAP_MEMORY
);
473 if ((flags
& NS_LDAP_NOMAP
) || schema_mapping_existed
== FALSE
)
476 mapping
= __ns_ldap_getOrigAttribute(service
, attr
);
478 if (mapping
== NULL
&& auto_service
&&
479 schema_mapping_existed
&& (flags
& NS_LDAP_NOMAP
) == 0)
481 * if service == auto_* and no schema mapping found
482 * and schema_mapping_existed is TRUE and NS_LDAP_NOMAP
483 * is not set then try automount e.g.
484 * NS_LDAP_ATTRIBUTEMAP = automount:automountMapName=AAA
486 mapping
= __ns_ldap_getOrigAttribute("automount",
489 if (mapping
== NULL
) {
490 if ((ap
[j
]->attrname
= strdup(attr
)) == NULL
) {
493 __ns_ldap_freeEntry(ep
);
496 __s_api_free2dArray(gecos_mapping
);
497 gecos_mapping
= NULL
;
498 return (NS_LDAP_MEMORY
);
502 * for "gecos" 1 to N mapping,
503 * do not remove the mapped attribute,
504 * just create a new gecos attribute
505 * and append it to the end of the attribute list
507 if (strcasecmp(mapping
[0], "gecos") == 0) {
508 ap
[j
]->attrname
= strdup(attr
);
509 gecos_mapping_existed
= TRUE
;
511 ap
[j
]->attrname
= strdup(mapping
[0]);
513 if (ap
[j
]->attrname
== NULL
) {
516 __ns_ldap_freeEntry(ep
);
519 __s_api_free2dArray(gecos_mapping
);
520 gecos_mapping
= NULL
;
521 return (NS_LDAP_MEMORY
);
524 * 1 to N attribute mapping processing
525 * is only done for "gecos"
528 if (strcasecmp(mapping
[0], "gecos") == 0) {
530 * get attribute mapping for "gecos",
531 * need to know the number and order of the
534 if (gecos_mapping
== NULL
) {
536 __ns_ldap_getMappedAttributes(
537 service
, mapping
[0]);
538 if (gecos_mapping
== NULL
||
539 gecos_mapping
[0] == NULL
) {
541 * this should never happens,
544 (void) sprintf(errstr
,
548 "found for attributes "
551 syslog(LOG_ERR
, "libsldap: %s",
556 __ns_ldap_freeEntry(ep
);
558 __s_api_free2dArray(mapping
);
563 gecos_mapping
= NULL
;
564 return (NS_LDAP_INTERNAL
);
569 * is this attribute the 1st, 2nd, or
570 * 3rd attr in the mapping list?
572 gecos_attr_matched
= FALSE
;
573 for (i
= 0; i
< 3 && gecos_mapping
[i
]; i
++) {
574 if (gecos_mapping
[i
] &&
575 strcasecmp(gecos_mapping
[i
],
577 gecos_val_index
[i
] = j
;
578 gecos_attr_matched
= TRUE
;
582 if (gecos_attr_matched
== FALSE
) {
585 * This should never happens,
588 (void) sprintf(errstr
,
592 "found for attributes "
595 syslog(LOG_ERR
, "libsldap: %s", errstr
);
599 __ns_ldap_freeEntry(ep
);
601 __s_api_free2dArray(mapping
);
603 __s_api_free2dArray(gecos_mapping
);
604 gecos_mapping
= NULL
;
605 return (NS_LDAP_INTERNAL
);
608 __s_api_free2dArray(mapping
);
612 if ((vals
= ldap_get_values(ld
, e
, attr
)) != NULL
) {
614 if ((ap
[j
]->value_count
=
615 ldap_count_values(vals
)) == 0) {
616 ldap_value_free(vals
);
620 ap
[j
]->attrvalue
= (char **)
621 calloc(ap
[j
]->value_count
+1,
623 if (ap
[j
]->attrvalue
== NULL
) {
626 __ns_ldap_freeEntry(ep
);
631 gecos_mapping
= NULL
;
632 return (NS_LDAP_MEMORY
);
636 /* map object classes if necessary */
637 if ((flags
& NS_LDAP_NOMAP
) == 0 &&
638 schema_mapping_existed
&& ap
[j
]->attrname
&&
639 strcasecmp(ap
[j
]->attrname
, "objectclass") == 0) {
640 for (k
= 0; k
< ap
[j
]->value_count
; k
++) {
642 __ns_ldap_getOrigObjectClass(
645 if (mapping
== NULL
&& auto_service
)
647 * if service == auto_* and no
648 * schema mapping found
652 __ns_ldap_getOrigObjectClass(
653 "automount", vals
[k
]);
655 if (mapping
== NULL
) {
656 ap
[j
]->attrvalue
[k
] =
659 ap
[j
]->attrvalue
[k
] =
661 __s_api_free2dArray(mapping
);
664 if (ap
[j
]->attrvalue
[k
] == NULL
) {
667 __ns_ldap_freeEntry(ep
);
672 gecos_mapping
= NULL
;
673 return (NS_LDAP_MEMORY
);
677 for (k
= 0; k
< ap
[j
]->value_count
; k
++) {
678 if ((ap
[j
]->attrvalue
[k
] =
679 strdup(vals
[k
])) == NULL
) {
682 __ns_ldap_freeEntry(ep
);
687 gecos_mapping
= NULL
;
688 return (NS_LDAP_MEMORY
);
693 ap
[j
]->attrvalue
[k
] = NULL
;
694 ldap_value_free(vals
);
706 __s_api_free2dArray(gecos_mapping
);
707 gecos_mapping
= NULL
;
710 /* special processing for gecos 1 to up to 3 attribute mapping */
711 if (schema_mapping_existed
&& gecos_mapping_existed
) {
715 for (i
= 0; i
< 3; i
++) {
716 k
= gecos_val_index
[i
];
719 * f is the index of the first returned
720 * attribute which "gecos" attribute mapped to
722 if (k
!= -1 && f
== -1)
725 if (k
!= -1 && ap
[k
]->value_count
> 0 &&
726 ap
[k
]->attrvalue
[0] &&
727 strlen(ap
[k
]->attrvalue
[0]) > 0) {
731 * Create and fill in the last reserved
732 * ap with the data from the "gecos"
735 ap
[nAttrs
] = (ns_ldap_attr_t
*)
737 sizeof (ns_ldap_attr_t
));
738 if (ap
[nAttrs
] == NULL
) {
739 __ns_ldap_freeEntry(ep
);
741 return (NS_LDAP_MEMORY
);
743 ap
[nAttrs
]->attrvalue
= (char **)calloc(
745 if (ap
[nAttrs
]->attrvalue
== NULL
) {
746 __ns_ldap_freeEntry(ep
);
748 return (NS_LDAP_MEMORY
);
750 /* add 1 more for a possible "," */
751 ap
[nAttrs
]->attrvalue
[0] =
753 strlen(ap
[f
]->attrvalue
[0]) +
755 if (ap
[nAttrs
]->attrvalue
[0] == NULL
) {
756 __ns_ldap_freeEntry(ep
);
758 return (NS_LDAP_MEMORY
);
760 (void) strcpy(ap
[nAttrs
]->attrvalue
[0],
761 ap
[f
]->attrvalue
[0]);
763 ap
[nAttrs
]->attrname
= strdup("gecos");
764 if (ap
[nAttrs
]->attrname
== NULL
) {
765 __ns_ldap_freeEntry(ep
);
767 return (NS_LDAP_MEMORY
);
770 ap
[nAttrs
]->value_count
= 1;
771 ep
->attr_count
= nAttrs
+ 1;
777 * realloc to add "," and
778 * ap[k]->attrvalue[0]
780 tmp
= (char *)realloc(
781 ap
[nAttrs
]->attrvalue
[0],
787 __ns_ldap_freeEntry(ep
);
789 return (NS_LDAP_MEMORY
);
791 ap
[nAttrs
]->attrvalue
[0] = tmp
;
792 (void) strcat(ap
[nAttrs
]->attrvalue
[0],
794 (void) strcat(ap
[nAttrs
]->attrvalue
[0],
795 ap
[k
]->attrvalue
[0]);
802 return (NS_LDAP_SUCCESS
);
806 __s_api_getEntry(ns_ldap_cookie_t
*cookie
)
808 ns_ldap_entry_t
*curEntry
= NULL
;
812 (void) fprintf(stderr
, "__s_api_getEntry START\n");
815 if (cookie
->resultMsg
== NULL
) {
816 return (NS_LDAP_INVALID_PARAM
);
818 ret
= __s_api_cvtEntry(cookie
->conn
->ld
, cookie
->service
,
819 cookie
->resultMsg
, cookie
->i_flags
,
820 &curEntry
, &cookie
->errorp
);
821 if (ret
!= NS_LDAP_SUCCESS
) {
825 if (cookie
->result
== NULL
) {
826 cookie
->result
= (ns_ldap_result_t
*)
827 calloc(1, sizeof (ns_ldap_result_t
));
828 if (cookie
->result
== NULL
) {
829 __ns_ldap_freeEntry(curEntry
);
831 return (NS_LDAP_MEMORY
);
833 cookie
->result
->entry
= curEntry
;
834 cookie
->nextEntry
= curEntry
;
836 cookie
->nextEntry
->next
= curEntry
;
837 cookie
->nextEntry
= curEntry
;
839 cookie
->result
->entries_count
++;
841 return (NS_LDAP_SUCCESS
);
845 __s_api_get_cachemgr_data(const char *type
,
846 const char *from
, char **to
)
850 char s_b
[DOORBUFFERSIZE
];
858 (void) fprintf(stderr
, "__s_api_get_cachemgr_data START\n");
861 * We are not going to perform DN to domain mapping
862 * in the Standalone mode
864 if (__s_api_isStandalone()) {
868 if (from
== NULL
|| from
[0] == '\0' || to
== NULL
)
872 (void) memset(space
.s_b
, 0, DOORBUFFERSIZE
);
874 space
.s_d
.ldap_call
.ldap_callnumber
= GETCACHE
;
875 (void) snprintf(space
.s_d
.ldap_call
.ldap_u
.domainname
,
876 DOORBUFFERSIZE
- sizeof (space
.s_d
.ldap_call
.ldap_callnumber
),
881 ndata
= sizeof (space
);
882 adata
= sizeof (ldap_call_t
) +
883 strlen(space
.s_d
.ldap_call
.ldap_u
.domainname
) + 1;
886 rc
= __ns_ldap_trydoorcall(&sptr
, &ndata
, &adata
);
887 if (rc
!= NS_CACHE_SUCCESS
)
890 *to
= strdup(sptr
->ldap_ret
.ldap_u
.buff
);
891 return (NS_LDAP_SUCCESS
);
895 __s_api_set_cachemgr_data(const char *type
,
896 const char *from
, const char *to
)
900 char s_b
[DOORBUFFERSIZE
];
908 (void) fprintf(stderr
, "__s_api_set_cachemgr_data START\n");
911 * We are not going to perform DN to domain mapping
912 * in the Standalone mode
914 if (__s_api_isStandalone()) {
918 if ((from
== NULL
) || (from
[0] == '\0') ||
919 (to
== NULL
) || (to
[0] == '\0'))
922 (void) memset(space
.s_b
, 0, DOORBUFFERSIZE
);
924 space
.s_d
.ldap_call
.ldap_callnumber
= SETCACHE
;
925 (void) snprintf(space
.s_d
.ldap_call
.ldap_u
.domainname
,
926 DOORBUFFERSIZE
- sizeof (space
.s_d
.ldap_call
.ldap_callnumber
),
934 ndata
= sizeof (space
);
935 adata
= sizeof (ldap_call_t
) +
936 strlen(space
.s_d
.ldap_call
.ldap_u
.domainname
) + 1;
939 rc
= __ns_ldap_trydoorcall(&sptr
, &ndata
, &adata
);
940 if (rc
!= NS_CACHE_SUCCESS
)
943 return (NS_LDAP_SUCCESS
);
948 __s_api_remove_rdn_space(char *rdn
)
950 char *tf
, *tl
, *vf
, *vl
, *eqsign
;
952 /* if no space(s) to remove, return */
953 if (strchr(rdn
, SPACETOK
) == NULL
)
956 /* if no '=' separator, return */
957 eqsign
= strchr(rdn
, '=');
964 vl
= rdn
+ strlen(rdn
) - 1;
966 /* now two strings, type and value */
969 /* remove type's leading spaces */
970 while (tf
< tl
&& *tf
== SPACETOK
)
972 /* remove type's trailing spaces */
973 while (tf
< tl
&& *tl
== SPACETOK
)
975 /* add '=' separator back */
977 /* remove value's leading spaces */
978 while (vf
< vl
&& *vf
== SPACETOK
)
980 /* remove value's trailing spaces */
981 while (vf
< vl
&& *vl
== SPACETOK
)
984 /* move value up if necessary */
986 (void) strcpy(tl
+ 1, vf
);
993 init_search_state_machine()
995 ns_ldap_cookie_t
*cookie
;
998 cookie
= (ns_ldap_cookie_t
*)calloc(1, sizeof (ns_ldap_cookie_t
));
1001 cookie
->state
= INIT
;
1002 /* assign other state variables */
1003 cfg
= __s_api_loadrefresh_config();
1004 cookie
->connectionId
= -1;
1006 cfg
->paramList
[NS_LDAP_SEARCH_TIME_P
].ns_ptype
== NS_UNKNOWN
) {
1007 cookie
->search_timeout
.tv_sec
= NS_DEFAULT_SEARCH_TIMEOUT
;
1009 cookie
->search_timeout
.tv_sec
=
1010 cfg
->paramList
[NS_LDAP_SEARCH_TIME_P
].ns_i
;
1013 __s_api_release_config(cfg
);
1014 cookie
->search_timeout
.tv_usec
= 0;
1020 delete_search_cookie(ns_ldap_cookie_t
*cookie
)
1024 if (cookie
->connectionId
> -1)
1025 DropConnection(cookie
->connectionId
, cookie
->i_flags
);
1026 free(cookie
->filter
);
1027 free(cookie
->i_filter
);
1028 free(cookie
->service
);
1030 (void) __ns_ldap_freeSearchDescriptors(&(cookie
->sdlist
));
1032 (void) __ns_ldap_freeResult(&cookie
->result
);
1033 if (cookie
->attribute
)
1034 __s_api_free2dArray(cookie
->attribute
);
1036 (void) __ns_ldap_freeError(&cookie
->errorp
);
1037 if (cookie
->reflist
)
1038 __s_api_deleteRefInfo(cookie
->reflist
);
1039 free(cookie
->basedn
);
1040 if (cookie
->ctrlCookie
)
1041 ber_bvfree(cookie
->ctrlCookie
);
1042 _freeControlList(&cookie
->p_serverctrls
);
1043 if (cookie
->resultctrl
)
1044 ldap_controls_free(cookie
->resultctrl
);
1049 get_mapped_filter(ns_ldap_cookie_t
*cookie
, char **new_filter
)
1052 typedef struct filter_mapping_info
{
1060 } filter_mapping_info_t
;
1062 char *c
, *last_copied
;
1063 char *filter_c
, *filter_c_next
;
1064 char *key
, *tail
, *head
;
1065 char errstr
[MAXERROR
];
1066 int num_eq
= 0, num_veq
= 0;
1067 int in_quote
= FALSE
;
1068 int is_value
= FALSE
;
1069 int i
, j
, oc_len
, len
;
1070 int at_least_one
= FALSE
;
1071 filter_mapping_info_t
**info
, *info1
;
1073 char *service
, *filter
, *err
;
1074 int auto_service
= FALSE
;
1076 if (cookie
== NULL
|| new_filter
== NULL
)
1077 return (NS_LDAP_INVALID_PARAM
);
1080 service
= cookie
->service
;
1081 filter
= cookie
->filter
;
1084 * count the number of '=' char
1086 for (c
= filter
; *c
; c
++) {
1087 if (*c
== TOKENSEPARATOR
)
1091 if (service
!= NULL
&& strncasecmp(service
, "auto_", 5) == 0)
1092 auto_service
= TRUE
;
1095 * See if schema mapping existed for the given service.
1096 * If not, just return success.
1098 mapping
= __ns_ldap_getOrigAttribute(service
,
1099 NS_HASH_SCHEMA_MAPPING_EXISTED
);
1101 if (mapping
== NULL
&& auto_service
)
1103 * if service == auto_* and no
1104 * schema mapping found
1105 * then try automount
1107 mapping
= __ns_ldap_getOrigAttribute(
1108 "automount", NS_HASH_SCHEMA_MAPPING_EXISTED
);
1111 __s_api_free2dArray(mapping
);
1113 return (NS_LDAP_SUCCESS
);
1116 * no '=' sign, just say OK and return nothing
1119 return (NS_LDAP_SUCCESS
);
1122 * Make a copy of the filter string
1123 * for saving the name of the objectclasses or
1124 * attributes that need to be passed to the
1125 * objectclass or attribute mapping functions.
1126 * pointer "info->from_name" points to the locations
1127 * within this string.
1129 * The input filter string, filter, will be used
1130 * to indicate where these names start and end.
1131 * pointers "info->name_start" and "info->name_end"
1132 * point to locations within the input filter string,
1133 * and are used at the end of this function to
1134 * merge the original filter data with the
1135 * mapped objectclass or attribute names.
1137 filter_c
= strdup(filter
);
1138 if (filter_c
== NULL
)
1139 return (NS_LDAP_MEMORY
);
1140 filter_c_next
= filter_c
;
1143 * get memory for info arrays
1145 info
= (filter_mapping_info_t
**)calloc(num_eq
+ 1,
1146 sizeof (filter_mapping_info_t
*));
1150 return (NS_LDAP_MEMORY
);
1154 * find valid '=' for further processing,
1155 * ignore the "escaped =" (.i.e. "\="), or
1156 * "=" in quoted string
1158 for (c
= filter_c
; *c
; c
++) {
1161 case TOKENSEPARATOR
:
1162 if (!in_quote
&& !is_value
) {
1163 info1
= (filter_mapping_info_t
*)calloc(1,
1164 sizeof (filter_mapping_info_t
));
1167 for (i
= 0; i
< num_veq
; i
++)
1170 return (NS_LDAP_MEMORY
);
1172 info
[num_veq
] = info1
;
1175 * remember the location of this "="
1177 info
[num_veq
++]->veq_pos
= c
;
1180 * skip until the end of the attribute value
1187 * mark the end of the attribute value
1194 * switch on/off the in_quote mode
1196 in_quote
= (in_quote
== FALSE
);
1200 * ignore escape characters
1201 * don't skip if next char is '\0'
1212 * for each valid "=" found, get the name to
1215 oc_len
= strlen("objectclass");
1216 for (i
= 0; i
< num_veq
; i
++) {
1219 * look at the left side of "=" to see
1220 * if assertion is "objectclass=<ocname>"
1221 * or "<attribute name>=<attribute value>"
1223 * first skip spaces before "=".
1224 * Note that filter_c_next may not point to the
1225 * start of the filter string. For i > 0,
1226 * it points to the end of the last name processed + 2
1228 for (tail
= info
[i
]->veq_pos
; (tail
> filter_c_next
) &&
1229 (*(tail
- 1) == SPACETOK
); tail
--)
1233 * mark the end of the left side string (the key)
1236 info
[i
]->name_end
= tail
- filter_c
- 1 + filter
;
1239 * find the start of the key
1241 key
= filter_c_next
;
1242 for (c
= tail
; filter_c_next
<= c
; c
--) {
1243 /* OPARATOK is '(' */
1244 if (*c
== OPARATOK
||
1250 info
[i
]->name_start
= key
- filter_c
+ filter
;
1252 if ((key
+ oc_len
) <= tail
) {
1253 if (strncasecmp(key
, "objectclass",
1256 * assertion is "objectclass=ocname",
1257 * ocname is the one needs to be mapped
1259 * skip spaces after "=" to find start
1262 head
= info
[i
]->veq_pos
;
1263 for (head
= info
[i
]->veq_pos
+ 1;
1264 *head
&& *head
== SPACETOK
; head
++)
1267 /* ignore empty ocname */
1271 info
[i
]->name_start
= head
- filter_c
+
1275 * now find the end of the ocname
1277 for (c
= head
; ; c
++) {
1278 /* CPARATOK is ')' */
1279 if (*c
== CPARATOK
||
1286 filter_c_next
= c
+ 1;
1287 info
[i
]->oc_or_attr
= 'o';
1288 info
[i
]->from_name
= head
;
1296 * assertion is not "objectclass=ocname",
1297 * assume assertion is "<key> = <value>",
1298 * <key> is the one needs to be mapped
1300 if (info
[i
]->from_name
== NULL
&& strlen(key
) > 0) {
1301 info
[i
]->oc_or_attr
= 'a';
1302 info
[i
]->from_name
= key
;
1306 /* perform schema mapping */
1307 for (i
= 0; i
< num_veq
; i
++) {
1308 if (info
[i
]->from_name
== NULL
)
1311 if (info
[i
]->oc_or_attr
== 'a')
1313 __ns_ldap_getMappedAttributes(service
,
1314 info
[i
]->from_name
);
1317 __ns_ldap_getMappedObjectClass(service
,
1318 info
[i
]->from_name
);
1320 if (info
[i
]->mapping
== NULL
&& auto_service
) {
1322 * If no mapped attribute/objectclass is found
1323 * and service == auto*
1324 * try to find automount's
1325 * mapped attribute/objectclass
1327 if (info
[i
]->oc_or_attr
== 'a')
1329 __ns_ldap_getMappedAttributes("automount",
1330 info
[i
]->from_name
);
1333 __ns_ldap_getMappedObjectClass("automount",
1334 info
[i
]->from_name
);
1337 if (info
[i
]->mapping
== NULL
||
1338 info
[i
]->mapping
[0] == NULL
) {
1339 info
[i
]->to_name
= NULL
;
1340 } else if (info
[i
]->mapping
[1] == NULL
) {
1341 info
[i
]->to_name
= info
[i
]->mapping
[0];
1342 at_least_one
= TRUE
;
1344 __s_api_free2dArray(info
[i
]->mapping
);
1349 (void) sprintf(errstr
,
1351 "Multiple attribute or objectclass "
1352 "mapping for '%s' in filter "
1353 "'%s' not allowed."),
1354 info
[i
]->from_name
, filter
);
1355 err
= strdup(errstr
);
1357 MKERROR(LOG_WARNING
, cookie
->errorp
,
1362 for (j
= 0; j
< num_veq
; j
++) {
1363 if (info
[j
]->mapping
)
1364 __s_api_free2dArray(
1369 return (NS_LDAP_CONFIG
);
1376 len
= strlen(filter
);
1377 last_copied
= filter
- 1;
1379 for (i
= 0; i
< num_veq
; i
++) {
1380 if (info
[i
]->to_name
)
1381 len
+= strlen(info
[i
]->to_name
);
1384 *new_filter
= (char *)calloc(1, len
);
1385 if (*new_filter
== NULL
) {
1387 for (j
= 0; j
< num_veq
; j
++) {
1388 if (info
[j
]->mapping
)
1389 __s_api_free2dArray(
1394 return (NS_LDAP_MEMORY
);
1397 for (i
= 0; i
< num_veq
; i
++) {
1398 if (info
[i
]->to_name
!= NULL
&&
1399 info
[i
]->to_name
!= NULL
) {
1402 * copy the original filter data
1403 * between the last name and current
1406 if ((last_copied
+ 1) != info
[i
]->name_start
)
1407 (void) strncat(*new_filter
,
1409 info
[i
]->name_start
-
1412 /* the data is copied */
1413 last_copied
= info
[i
]->name_end
;
1416 * replace the name with
1419 (void) strcat(*new_filter
, info
[i
]->to_name
);
1422 /* copy the filter data after the last name */
1423 if (i
== (num_veq
-1) &&
1425 (filter
+ strlen(filter
)))
1426 (void) strncat(*new_filter
, last_copied
+ 1,
1427 filter
+ strlen(filter
) -
1435 for (j
= 0; j
< num_veq
; j
++) {
1436 if (info
[j
]->mapping
)
1437 __s_api_free2dArray(info
[j
]->mapping
);
1442 return (NS_LDAP_SUCCESS
);
1446 setup_next_search(ns_ldap_cookie_t
*cookie
)
1448 ns_ldap_search_desc_t
*dptr
;
1455 dptr
= *cookie
->sdpos
;
1456 scope
= cookie
->i_flags
& (NS_LDAP_SCOPE_BASE
|
1457 NS_LDAP_SCOPE_ONELEVEL
|
1458 NS_LDAP_SCOPE_SUBTREE
);
1460 cookie
->scope
= scope
;
1462 cookie
->scope
= dptr
->scope
;
1463 switch (cookie
->scope
) {
1464 case NS_LDAP_SCOPE_BASE
:
1465 cookie
->scope
= LDAP_SCOPE_BASE
;
1467 case NS_LDAP_SCOPE_ONELEVEL
:
1468 cookie
->scope
= LDAP_SCOPE_ONELEVEL
;
1470 case NS_LDAP_SCOPE_SUBTREE
:
1471 cookie
->scope
= LDAP_SCOPE_SUBTREE
;
1476 if (cookie
->use_filtercb
&& cookie
->init_filter_cb
&&
1477 dptr
->filter
&& strlen(dptr
->filter
) > 0) {
1478 (*cookie
->init_filter_cb
)(dptr
, &filter
,
1481 if (filter
== NULL
) {
1482 if (cookie
->i_filter
== NULL
) {
1483 cookie
->err_rc
= NS_LDAP_INVALID_PARAM
;
1486 free(cookie
->filter
);
1487 cookie
->filter
= strdup(cookie
->i_filter
);
1488 if (cookie
->filter
== NULL
) {
1489 cookie
->err_rc
= NS_LDAP_MEMORY
;
1494 free(cookie
->filter
);
1495 cookie
->filter
= strdup(filter
);
1497 if (cookie
->filter
== NULL
) {
1498 cookie
->err_rc
= NS_LDAP_MEMORY
;
1504 * perform attribute/objectclass mapping on filter
1508 if (cookie
->service
) {
1509 rc
= get_mapped_filter(cookie
, &filter
);
1510 if (rc
!= NS_LDAP_SUCCESS
) {
1511 cookie
->err_rc
= rc
;
1515 * get_mapped_filter returns
1516 * NULL filter pointer, if
1517 * no mapping was done
1520 free(cookie
->filter
);
1521 cookie
->filter
= filter
;
1527 * validate filter to make sure it's legal
1528 * [remove redundant ()'s]
1530 rc
= validate_filter(cookie
);
1531 if (rc
!= NS_LDAP_SUCCESS
) {
1532 cookie
->err_rc
= rc
;
1536 baselen
= strlen(dptr
->basedn
);
1537 if (baselen
> 0 && dptr
->basedn
[baselen
-1] == COMMATOK
) {
1538 rc
= __ns_ldap_getParam(NS_LDAP_SEARCH_BASEDN_P
,
1539 (void ***)¶m
, &cookie
->errorp
);
1540 if (rc
!= NS_LDAP_SUCCESS
) {
1541 cookie
->err_rc
= rc
;
1544 str
= ((char **)param
)[0];
1545 baselen
+= strlen(str
)+1;
1546 free(cookie
->basedn
);
1547 cookie
->basedn
= (char *)malloc(baselen
);
1548 if (cookie
->basedn
== NULL
) {
1549 cookie
->err_rc
= NS_LDAP_MEMORY
;
1552 (void) strcpy(cookie
->basedn
, dptr
->basedn
);
1553 (void) strcat(cookie
->basedn
, str
);
1554 (void) __ns_ldap_freeParam(¶m
);
1556 free(cookie
->basedn
);
1557 cookie
->basedn
= strdup(dptr
->basedn
);
1563 setup_referral_search(ns_ldap_cookie_t
*cookie
)
1565 ns_referral_info_t
*ref
;
1567 ref
= cookie
->refpos
;
1568 cookie
->scope
= ref
->refScope
;
1569 if (cookie
->filter
) {
1570 free(cookie
->filter
);
1572 cookie
->filter
= strdup(ref
->refFilter
);
1573 if (cookie
->basedn
) {
1574 free(cookie
->basedn
);
1576 cookie
->basedn
= strdup(ref
->refDN
);
1577 if (cookie
->filter
== NULL
|| cookie
->basedn
== NULL
) {
1578 cookie
->err_rc
= NS_LDAP_MEMORY
;
1585 get_current_session(ns_ldap_cookie_t
*cookie
)
1587 ConnectionID connectionId
= -1;
1588 Connection
*conp
= NULL
;
1590 int fail_if_new_pwd_reqd
= 1;
1592 rc
= __s_api_getConnection(NULL
, cookie
->i_flags
,
1593 cookie
->i_auth
, &connectionId
, &conp
,
1594 &cookie
->errorp
, fail_if_new_pwd_reqd
,
1595 cookie
->nopasswd_acct_mgmt
, cookie
->conn_user
);
1598 * If password control attached in *cookie->errorp,
1599 * e.g. rc == NS_LDAP_SUCCESS_WITH_INFO,
1600 * free the error structure (we do not need
1601 * the sec_to_expired info).
1602 * Reset rc to NS_LDAP_SUCCESS.
1604 if (rc
== NS_LDAP_SUCCESS_WITH_INFO
) {
1605 (void) __ns_ldap_freeError(
1607 cookie
->errorp
= NULL
;
1608 rc
= NS_LDAP_SUCCESS
;
1611 if (rc
!= NS_LDAP_SUCCESS
) {
1612 cookie
->err_rc
= rc
;
1615 cookie
->conn
= conp
;
1616 cookie
->connectionId
= connectionId
;
1622 get_next_session(ns_ldap_cookie_t
*cookie
)
1624 ConnectionID connectionId
= -1;
1625 Connection
*conp
= NULL
;
1627 int fail_if_new_pwd_reqd
= 1;
1629 if (cookie
->connectionId
> -1) {
1630 DropConnection(cookie
->connectionId
, cookie
->i_flags
);
1631 cookie
->connectionId
= -1;
1634 /* If using a MT connection, return it. */
1635 if (cookie
->conn_user
!= NULL
&&
1636 cookie
->conn_user
->conn_mt
!= NULL
)
1637 __s_api_conn_mt_return(cookie
->conn_user
);
1639 rc
= __s_api_getConnection(NULL
, cookie
->i_flags
,
1640 cookie
->i_auth
, &connectionId
, &conp
,
1641 &cookie
->errorp
, fail_if_new_pwd_reqd
,
1642 cookie
->nopasswd_acct_mgmt
, cookie
->conn_user
);
1645 * If password control attached in *cookie->errorp,
1646 * e.g. rc == NS_LDAP_SUCCESS_WITH_INFO,
1647 * free the error structure (we do not need
1648 * the sec_to_expired info).
1649 * Reset rc to NS_LDAP_SUCCESS.
1651 if (rc
== NS_LDAP_SUCCESS_WITH_INFO
) {
1652 (void) __ns_ldap_freeError(
1654 cookie
->errorp
= NULL
;
1655 rc
= NS_LDAP_SUCCESS
;
1658 if (rc
!= NS_LDAP_SUCCESS
) {
1659 cookie
->err_rc
= rc
;
1662 cookie
->conn
= conp
;
1663 cookie
->connectionId
= connectionId
;
1668 get_referral_session(ns_ldap_cookie_t
*cookie
)
1670 ConnectionID connectionId
= -1;
1671 Connection
*conp
= NULL
;
1673 int fail_if_new_pwd_reqd
= 1;
1675 if (cookie
->connectionId
> -1) {
1676 DropConnection(cookie
->connectionId
, cookie
->i_flags
);
1677 cookie
->connectionId
= -1;
1680 /* set it up to use a connection opened for referral */
1681 if (cookie
->conn_user
!= NULL
) {
1682 /* If using a MT connection, return it. */
1683 if (cookie
->conn_user
->conn_mt
!= NULL
)
1684 __s_api_conn_mt_return(cookie
->conn_user
);
1685 cookie
->conn_user
->referral
= B_TRUE
;
1688 rc
= __s_api_getConnection(cookie
->refpos
->refHost
, 0,
1689 cookie
->i_auth
, &connectionId
, &conp
,
1690 &cookie
->errorp
, fail_if_new_pwd_reqd
,
1691 cookie
->nopasswd_acct_mgmt
, cookie
->conn_user
);
1694 * If password control attached in *cookie->errorp,
1695 * e.g. rc == NS_LDAP_SUCCESS_WITH_INFO,
1696 * free the error structure (we do not need
1697 * the sec_to_expired info).
1698 * Reset rc to NS_LDAP_SUCCESS.
1700 if (rc
== NS_LDAP_SUCCESS_WITH_INFO
) {
1701 (void) __ns_ldap_freeError(
1703 cookie
->errorp
= NULL
;
1704 rc
= NS_LDAP_SUCCESS
;
1707 if (rc
!= NS_LDAP_SUCCESS
) {
1708 cookie
->err_rc
= rc
;
1711 cookie
->conn
= conp
;
1712 cookie
->connectionId
= connectionId
;
1717 paging_supported(ns_ldap_cookie_t
*cookie
)
1721 cookie
->listType
= 0;
1722 rc
= __s_api_isCtrlSupported(cookie
->conn
,
1723 LDAP_CONTROL_VLVREQUEST
);
1724 if (rc
== NS_LDAP_SUCCESS
) {
1725 cookie
->listType
= VLVCTRLFLAG
;
1728 rc
= __s_api_isCtrlSupported(cookie
->conn
,
1729 LDAP_CONTROL_SIMPLE_PAGE
);
1730 if (rc
== NS_LDAP_SUCCESS
) {
1731 cookie
->listType
= SIMPLEPAGECTRLFLAG
;
1737 typedef struct servicesorttype
{
1739 ns_srvsidesort_t type
;
1740 } servicesorttype_t
;
1742 static servicesorttype_t
*sort_type
= NULL
;
1743 static int sort_type_size
= 0;
1744 static int sort_type_hwm
= 0;
1745 static mutex_t sort_type_mutex
= DEFAULTMUTEX
;
1748 static ns_srvsidesort_t
1749 get_srvsidesort_type(char *service
)
1752 ns_srvsidesort_t type
= SSS_UNKNOWN
;
1754 if (service
== NULL
)
1757 (void) mutex_lock(&sort_type_mutex
);
1758 if (sort_type
!= NULL
) {
1759 for (i
= 0; i
< sort_type_hwm
; i
++) {
1760 if (strcmp(sort_type
[i
].service
, service
) == 0) {
1761 type
= sort_type
[i
].type
;
1766 (void) mutex_unlock(&sort_type_mutex
);
1771 update_srvsidesort_type(char *service
, ns_srvsidesort_t type
)
1774 servicesorttype_t
*tmp
;
1776 if (service
== NULL
)
1779 (void) mutex_lock(&sort_type_mutex
);
1781 for (i
= 0; i
< sort_type_hwm
; i
++) {
1782 if (strcmp(sort_type
[i
].service
, service
) == 0) {
1783 sort_type
[i
].type
= type
;
1784 (void) mutex_unlock(&sort_type_mutex
);
1788 if (sort_type
== NULL
) {
1790 tmp
= malloc(size
* sizeof (servicesorttype_t
));
1792 (void) mutex_unlock(&sort_type_mutex
);
1796 sort_type_size
= size
;
1797 } else if (sort_type_hwm
>= sort_type_size
) {
1798 size
= sort_type_size
+ 10;
1799 tmp
= reallocarray(sort_type
, size
, sizeof (servicesorttype_t
));
1801 (void) mutex_unlock(&sort_type_mutex
);
1805 sort_type_size
= size
;
1807 sort_type
[sort_type_hwm
].service
= strdup(service
);
1808 if (sort_type
[sort_type_hwm
].service
== NULL
) {
1809 (void) mutex_unlock(&sort_type_mutex
);
1812 sort_type
[sort_type_hwm
].type
= type
;
1815 (void) mutex_unlock(&sort_type_mutex
);
1819 setup_vlv_params(ns_ldap_cookie_t
*cookie
)
1821 LDAPControl
**ctrls
;
1822 LDAPsortkey
**sortkeylist
;
1823 LDAPControl
*sortctrl
= NULL
;
1824 LDAPControl
*vlvctrl
= NULL
;
1825 LDAPVirtualList vlist
;
1828 int free_sort
= FALSE
;
1830 _freeControlList(&cookie
->p_serverctrls
);
1832 if (cookie
->sortTypeTry
== SSS_UNKNOWN
)
1833 cookie
->sortTypeTry
= get_srvsidesort_type(cookie
->service
);
1834 if (cookie
->sortTypeTry
== SSS_UNKNOWN
)
1835 cookie
->sortTypeTry
= SSS_SINGLE_ATTR
;
1837 if (cookie
->sortTypeTry
== SSS_SINGLE_ATTR
) {
1838 if ((cookie
->i_flags
& NS_LDAP_NOMAP
) == 0 &&
1839 cookie
->i_sortattr
) {
1840 sortattr
= __ns_ldap_mapAttribute(cookie
->service
,
1841 cookie
->i_sortattr
);
1843 } else if (cookie
->i_sortattr
) {
1844 sortattr
= (char *)cookie
->i_sortattr
;
1849 sortattr
= "cn uid";
1852 rc
= ldap_create_sort_keylist(&sortkeylist
, sortattr
);
1855 if (rc
!= LDAP_SUCCESS
) {
1856 (void) ldap_get_option(cookie
->conn
->ld
,
1857 LDAP_OPT_ERROR_NUMBER
, &rc
);
1860 rc
= ldap_create_sort_control(cookie
->conn
->ld
,
1861 sortkeylist
, 1, &sortctrl
);
1862 ldap_free_sort_keylist(sortkeylist
);
1863 if (rc
!= LDAP_SUCCESS
) {
1864 (void) ldap_get_option(cookie
->conn
->ld
,
1865 LDAP_OPT_ERROR_NUMBER
, &rc
);
1869 vlist
.ldvlist_index
= cookie
->index
;
1870 vlist
.ldvlist_size
= 0;
1872 vlist
.ldvlist_before_count
= 0;
1873 vlist
.ldvlist_after_count
= LISTPAGESIZE
-1;
1874 vlist
.ldvlist_attrvalue
= NULL
;
1875 vlist
.ldvlist_extradata
= NULL
;
1877 rc
= ldap_create_virtuallist_control(cookie
->conn
->ld
,
1879 if (rc
!= LDAP_SUCCESS
) {
1880 ldap_control_free(sortctrl
);
1881 (void) ldap_get_option(cookie
->conn
->ld
, LDAP_OPT_ERROR_NUMBER
,
1886 ctrls
= (LDAPControl
**)calloc(3, sizeof (LDAPControl
*));
1887 if (ctrls
== NULL
) {
1888 ldap_control_free(sortctrl
);
1889 ldap_control_free(vlvctrl
);
1890 return (LDAP_NO_MEMORY
);
1893 ctrls
[0] = sortctrl
;
1896 cookie
->p_serverctrls
= ctrls
;
1897 return (LDAP_SUCCESS
);
1901 setup_simplepg_params(ns_ldap_cookie_t
*cookie
)
1903 LDAPControl
**ctrls
;
1904 LDAPControl
*pgctrl
= NULL
;
1907 _freeControlList(&cookie
->p_serverctrls
);
1909 rc
= ldap_create_page_control(cookie
->conn
->ld
, LISTPAGESIZE
,
1910 cookie
->ctrlCookie
, '\0', &pgctrl
);
1911 if (rc
!= LDAP_SUCCESS
) {
1912 (void) ldap_get_option(cookie
->conn
->ld
, LDAP_OPT_ERROR_NUMBER
,
1917 ctrls
= (LDAPControl
**)calloc(2, sizeof (LDAPControl
*));
1918 if (ctrls
== NULL
) {
1919 ldap_control_free(pgctrl
);
1920 return (LDAP_NO_MEMORY
);
1923 cookie
->p_serverctrls
= ctrls
;
1924 return (LDAP_SUCCESS
);
1928 proc_result_referrals(ns_ldap_cookie_t
*cookie
)
1931 char **referrals
= NULL
;
1934 * Only follow one level of referrals, i.e.
1935 * if already in referral mode, do nothing
1937 if (cookie
->refpos
== NULL
) {
1938 cookie
->new_state
= END_RESULT
;
1939 rc
= ldap_parse_result(cookie
->conn
->ld
,
1944 if (rc
!= NS_LDAP_SUCCESS
) {
1945 (void) ldap_get_option(cookie
->conn
->ld
,
1946 LDAP_OPT_ERROR_NUMBER
,
1948 cookie
->new_state
= LDAP_ERROR
;
1951 if (errCode
== LDAP_REFERRAL
) {
1952 for (i
= 0; referrals
[i
] != NULL
;
1954 /* add to referral list */
1955 rc
= __s_api_addRefInfo(
1962 if (rc
!= NS_LDAP_SUCCESS
) {
1968 ldap_value_free(referrals
);
1974 proc_search_references(ns_ldap_cookie_t
*cookie
)
1976 char **refurls
= NULL
;
1980 * Only follow one level of referrals, i.e.
1981 * if already in referral mode, do nothing
1983 if (cookie
->refpos
== NULL
) {
1984 refurls
= ldap_get_reference_urls(
1987 if (refurls
== NULL
) {
1988 (void) ldap_get_option(cookie
->conn
->ld
,
1989 LDAP_OPT_ERROR_NUMBER
,
1991 cookie
->new_state
= LDAP_ERROR
;
1994 for (i
= 0; refurls
[i
] != NULL
; i
++) {
1995 /* add to referral list */
1996 rc
= __s_api_addRefInfo(
2003 if (rc
!= NS_LDAP_SUCCESS
) {
2009 /* free allocated storage */
2010 for (i
= 0; refurls
[i
] != NULL
; i
++)
2016 multi_result(ns_ldap_cookie_t
*cookie
)
2018 char errstr
[MAXERROR
];
2020 ns_ldap_error_t
**errorp
= NULL
;
2021 LDAPControl
**retCtrls
= NULL
;
2025 unsigned long target_posp
= 0;
2026 unsigned long list_size
= 0;
2027 unsigned int count
= 0;
2028 char **referrals
= NULL
;
2030 if (cookie
->listType
== VLVCTRLFLAG
) {
2031 rc
= ldap_parse_result(cookie
->conn
->ld
, cookie
->resultMsg
,
2032 &errCode
, NULL
, NULL
, &referrals
, &retCtrls
, 0);
2033 if (rc
!= LDAP_SUCCESS
) {
2034 (void) ldap_get_option(cookie
->conn
->ld
,
2035 LDAP_OPT_ERROR_NUMBER
,
2037 (void) sprintf(errstr
,
2038 gettext("LDAP ERROR (%d): %s.\n"),
2040 gettext(ldap_err2string(cookie
->err_rc
)));
2041 err
= strdup(errstr
);
2042 MKERROR(LOG_WARNING
, *errorp
, NS_LDAP_INTERNAL
, err
,
2044 cookie
->err_rc
= NS_LDAP_INTERNAL
;
2045 cookie
->errorp
= *errorp
;
2046 return (LDAP_ERROR
);
2048 if (errCode
== LDAP_REFERRAL
) {
2049 for (i
= 0; referrals
[i
] != NULL
;
2051 /* add to referral list */
2052 rc
= __s_api_addRefInfo(
2059 if (rc
!= NS_LDAP_SUCCESS
) {
2068 ldap_value_free(referrals
);
2070 ldap_controls_free(retCtrls
);
2071 return (END_RESULT
);
2074 rc
= ldap_parse_virtuallist_control(
2075 cookie
->conn
->ld
, retCtrls
,
2076 &target_posp
, &list_size
, &errCode
);
2077 if (rc
== LDAP_SUCCESS
) {
2079 * AD does not return valid target_posp
2082 if (target_posp
!= 0 && list_size
!= 0) {
2084 target_posp
+ LISTPAGESIZE
;
2085 if (cookie
->index
> list_size
)
2088 if (cookie
->entryCount
< LISTPAGESIZE
)
2095 ldap_controls_free(retCtrls
);
2100 } else if (cookie
->listType
== SIMPLEPAGECTRLFLAG
) {
2101 rc
= ldap_parse_result(cookie
->conn
->ld
, cookie
->resultMsg
,
2102 &errCode
, NULL
, NULL
, &referrals
, &retCtrls
, 0);
2103 if (rc
!= LDAP_SUCCESS
) {
2104 (void) ldap_get_option(cookie
->conn
->ld
,
2105 LDAP_OPT_ERROR_NUMBER
,
2107 (void) sprintf(errstr
,
2108 gettext("LDAP ERROR (%d): %s.\n"),
2110 gettext(ldap_err2string(cookie
->err_rc
)));
2111 err
= strdup(errstr
);
2112 MKERROR(LOG_WARNING
, *errorp
, NS_LDAP_INTERNAL
, err
,
2114 cookie
->err_rc
= NS_LDAP_INTERNAL
;
2115 cookie
->errorp
= *errorp
;
2116 return (LDAP_ERROR
);
2118 if (errCode
== LDAP_REFERRAL
) {
2119 for (i
= 0; referrals
[i
] != NULL
;
2121 /* add to referral list */
2122 rc
= __s_api_addRefInfo(
2129 if (rc
!= NS_LDAP_SUCCESS
) {
2138 ldap_value_free(referrals
);
2140 ldap_controls_free(retCtrls
);
2141 return (END_RESULT
);
2144 if (cookie
->ctrlCookie
)
2145 ber_bvfree(cookie
->ctrlCookie
);
2146 cookie
->ctrlCookie
= NULL
;
2147 rc
= ldap_parse_page_control(
2148 cookie
->conn
->ld
, retCtrls
,
2149 &count
, &cookie
->ctrlCookie
);
2150 if (rc
== LDAP_SUCCESS
) {
2151 if ((cookie
->ctrlCookie
== NULL
) ||
2152 (cookie
->ctrlCookie
->bv_val
== NULL
) ||
2153 (cookie
->ctrlCookie
->bv_len
== 0))
2156 ldap_controls_free(retCtrls
);
2162 if (!finished
&& cookie
->listType
== VLVCTRLFLAG
)
2164 if (!finished
&& cookie
->listType
== SIMPLEPAGECTRLFLAG
)
2167 return (END_RESULT
);
2172 * clear_results(ns_ldap_cookie_t):
2174 * Attempt to obtain remnants of ldap responses and free them. If remnants are
2175 * not obtained within a certain time period tell the server we wish to abandon
2178 * Note that we do not initially tell the server to abandon the request as that
2179 * can be an expensive operation for the server, while it is cheap for us to
2180 * just flush the input.
2182 * If something was to remain in libldap queue as a result of some error then
2183 * it would be freed later during drop connection call or when no other
2184 * requests share the connection.
2187 clear_results(ns_ldap_cookie_t
*cookie
)
2190 if (cookie
->conn
!= NULL
&& cookie
->conn
->ld
!= NULL
&&
2191 (cookie
->connectionId
!= -1 ||
2192 (cookie
->conn_user
!= NULL
&&
2193 cookie
->conn_user
->conn_mt
!= NULL
)) &&
2194 cookie
->msgId
!= 0) {
2196 * We need to cleanup the rest of response (if there is such)
2197 * and LDAP abandon is too heavy for LDAP servers, so we will
2198 * wait for the rest of response till timeout and "process" it.
2200 rc
= ldap_result(cookie
->conn
->ld
, cookie
->msgId
, LDAP_MSG_ALL
,
2201 (struct timeval
*)&cookie
->search_timeout
,
2202 &cookie
->resultMsg
);
2203 if (rc
!= -1 && rc
!= 0 && cookie
->resultMsg
!= NULL
) {
2204 (void) ldap_msgfree(cookie
->resultMsg
);
2205 cookie
->resultMsg
= NULL
;
2209 * If there was timeout then we will send ABANDON request to
2210 * LDAP server to decrease load.
2213 (void) ldap_abandon_ext(cookie
->conn
->ld
, cookie
->msgId
,
2215 /* Disassociate cookie with msgId */
2221 * This state machine performs one or more LDAP searches to a given
2222 * directory server using service search descriptors and schema
2223 * mapping as appropriate. The approximate pseudocode for
2224 * this routine is the following:
2225 * Given the current configuration [set/reset connection etc.]
2226 * and the current service search descriptor list
2227 * or default search filter parameters
2228 * foreach (service search filter) {
2229 * initialize the filter [via filter_init if appropriate]
2230 * get a valid session/connection (preferably the current one)
2231 * Recover if the connection is lost
2232 * perform the search
2233 * foreach (result entry) {
2234 * process result [via callback if appropriate]
2235 * save result for caller if accepted.
2236 * exit and return all collected if allResults found;
2239 * return collected results and exit
2244 search_state_machine(ns_ldap_cookie_t
*cookie
, ns_state_t state
, int cycle
)
2246 char errstr
[MAXERROR
];
2250 ns_ldap_entry_t
*nextEntry
;
2251 ns_ldap_error_t
*error
= NULL
;
2252 ns_ldap_error_t
**errorp
;
2256 cookie
->state
= state
;
2260 switch (cookie
->state
) {
2262 clear_results(cookie
);
2263 cookie
->new_state
= EXIT
;
2265 case GET_ACCT_MGMT_INFO
:
2267 * Set the flag to get ldap account management controls.
2269 cookie
->nopasswd_acct_mgmt
= 1;
2270 cookie
->new_state
= INIT
;
2273 /* state engine/connection cleaned up in delete */
2274 if (cookie
->attribute
) {
2275 __s_api_free2dArray(cookie
->attribute
);
2276 cookie
->attribute
= NULL
;
2278 if (cookie
->reflist
) {
2279 __s_api_deleteRefInfo(cookie
->reflist
);
2280 cookie
->reflist
= NULL
;
2284 cookie
->sdpos
= NULL
;
2285 cookie
->new_state
= NEXT_SEARCH_DESCRIPTOR
;
2286 if (cookie
->attribute
) {
2287 __s_api_free2dArray(cookie
->attribute
);
2288 cookie
->attribute
= NULL
;
2290 if ((cookie
->i_flags
& NS_LDAP_NOMAP
) == 0 &&
2293 __ns_ldap_mapAttributeList(
2299 /* Check if we've reached MAX retries. */
2301 if (cookie
->retries
> NS_LIST_TRY_MAX
- 1) {
2302 cookie
->new_state
= LDAP_ERROR
;
2307 * Even if we still have retries left, check
2308 * if retry is possible.
2310 if (cookie
->conn_user
!= NULL
) {
2312 ns_conn_mgmt_t
*cmg
;
2313 cmg
= cookie
->conn_user
->conn_mgmt
;
2314 retry
= cookie
->conn_user
->retry
;
2315 if (cmg
!= NULL
&& cmg
->cfg_reloaded
== 1)
2318 cookie
->new_state
= LDAP_ERROR
;
2323 * Free results if any, reset to the first
2324 * search descriptor and start a new session.
2326 if (cookie
->resultMsg
!= NULL
) {
2327 (void) ldap_msgfree(cookie
->resultMsg
);
2328 cookie
->resultMsg
= NULL
;
2330 (void) __ns_ldap_freeError(&cookie
->errorp
);
2331 (void) __ns_ldap_freeResult(&cookie
->result
);
2332 cookie
->sdpos
= cookie
->sdlist
;
2333 cookie
->err_from_result
= 0;
2335 cookie
->new_state
= NEXT_SESSION
;
2337 case NEXT_SEARCH_DESCRIPTOR
:
2338 /* get next search descriptor */
2339 if (cookie
->sdpos
== NULL
) {
2340 cookie
->sdpos
= cookie
->sdlist
;
2341 cookie
->new_state
= GET_SESSION
;
2344 cookie
->new_state
= NEXT_SEARCH
;
2346 if (*cookie
->sdpos
== NULL
)
2347 cookie
->new_state
= EXIT
;
2350 if (get_current_session(cookie
) < 0)
2351 cookie
->new_state
= NEXT_SESSION
;
2353 cookie
->new_state
= NEXT_SEARCH
;
2356 if (get_next_session(cookie
) < 0)
2357 cookie
->new_state
= RESTART_SESSION
;
2359 cookie
->new_state
= NEXT_SEARCH
;
2361 case RESTART_SESSION
:
2362 if (cookie
->i_flags
& NS_LDAP_HARD
) {
2363 cookie
->new_state
= NEXT_SESSION
;
2366 (void) sprintf(errstr
,
2367 gettext("Session error no available conn.\n"),
2369 err
= strdup(errstr
);
2370 MKERROR(LOG_WARNING
, *errorp
, NS_LDAP_INTERNAL
, err
,
2372 cookie
->err_rc
= NS_LDAP_INTERNAL
;
2373 cookie
->errorp
= *errorp
;
2374 cookie
->new_state
= EXIT
;
2377 /* setup referrals search if necessary */
2378 if (cookie
->refpos
) {
2379 if (setup_referral_search(cookie
) < 0) {
2380 cookie
->new_state
= EXIT
;
2383 } else if (setup_next_search(cookie
) < 0) {
2384 cookie
->new_state
= EXIT
;
2387 /* only do VLV/PAGE on scopes onelevel/subtree */
2388 if (paging_supported(cookie
)) {
2389 if (cookie
->use_paging
&&
2390 (cookie
->scope
!= LDAP_SCOPE_BASE
)) {
2392 if (cookie
->listType
== VLVCTRLFLAG
)
2393 cookie
->new_state
= NEXT_VLV
;
2395 cookie
->new_state
= NEXT_PAGE
;
2399 cookie
->new_state
= ONE_SEARCH
;
2402 rc
= setup_vlv_params(cookie
);
2403 if (rc
!= LDAP_SUCCESS
) {
2404 cookie
->err_rc
= rc
;
2405 cookie
->new_state
= LDAP_ERROR
;
2408 cookie
->next_state
= MULTI_RESULT
;
2409 cookie
->new_state
= DO_SEARCH
;
2412 rc
= setup_simplepg_params(cookie
);
2413 if (rc
!= LDAP_SUCCESS
) {
2414 cookie
->err_rc
= rc
;
2415 cookie
->new_state
= LDAP_ERROR
;
2418 cookie
->next_state
= MULTI_RESULT
;
2419 cookie
->new_state
= DO_SEARCH
;
2422 cookie
->next_state
= NEXT_RESULT
;
2423 cookie
->new_state
= DO_SEARCH
;
2426 cookie
->entryCount
= 0;
2427 rc
= ldap_search_ext(cookie
->conn
->ld
,
2433 cookie
->p_serverctrls
,
2435 &cookie
->search_timeout
, 0,
2437 if (rc
!= LDAP_SUCCESS
) {
2438 if (rc
== LDAP_BUSY
||
2439 rc
== LDAP_UNAVAILABLE
||
2440 rc
== LDAP_UNWILLING_TO_PERFORM
||
2441 rc
== LDAP_CONNECT_ERROR
||
2442 rc
== LDAP_SERVER_DOWN
) {
2444 if (cookie
->reinit_on_retriable_err
) {
2445 cookie
->err_rc
= rc
;
2446 cookie
->new_state
= REINIT
;
2452 * If not able to reach the
2453 * server, inform the ldap
2454 * cache manager that the
2455 * server should be removed
2456 * from it's server list.
2457 * Thus, the manager will not
2458 * return this server on the next
2459 * get-server request and will
2460 * also reduce the server list
2461 * refresh TTL, so that it will
2462 * find out sooner when the server
2465 if ((rc
== LDAP_CONNECT_ERROR
||
2466 rc
== LDAP_SERVER_DOWN
) &&
2467 (cookie
->conn_user
== NULL
||
2468 cookie
->conn_user
->conn_mt
==
2470 ret
= __s_api_removeServer(
2471 cookie
->conn
->serverAddr
);
2472 if (ret
== NS_CACHE_NOSERVER
&&
2473 cookie
->conn_auth_type
2474 == NS_LDAP_AUTH_NONE
) {
2477 * server from server
2480 * potential infinite
2483 cookie
->err_rc
= rc
;
2487 if (cookie
->connectionId
> -1) {
2490 * indicates that the
2499 cookie
->connectionId
=
2502 } else if ((rc
== LDAP_CONNECT_ERROR
||
2503 rc
== LDAP_SERVER_DOWN
) &&
2504 cookie
->conn_user
!= NULL
) {
2506 reinit_on_retriable_err
) {
2513 * cookie->err_rc above.
2515 __s_api_conn_mt_close(
2522 * usable, close it in
2523 * the LDAP_ERROR state.
2524 * A retry will be done
2527 cookie
->err_rc
= rc
;
2534 cookie
->err_rc
= rc
;
2535 cookie
->new_state
= LDAP_ERROR
;
2538 cookie
->new_state
= cookie
->next_state
;
2542 * Caller (e.g. __ns_ldap_list_batch_add)
2543 * does not want to block on ldap_result().
2544 * Therefore we execute ldap_result() with
2547 if (cookie
->no_wait
== B_TRUE
)
2548 (void) memset(&tv
, 0, sizeof (tv
));
2550 tv
= cookie
->search_timeout
;
2551 rc
= ldap_result(cookie
->conn
->ld
, cookie
->msgId
,
2554 &cookie
->resultMsg
);
2555 if (rc
== LDAP_RES_SEARCH_RESULT
) {
2556 cookie
->new_state
= END_RESULT
;
2557 /* check and process referrals info */
2558 if (cookie
->followRef
)
2559 proc_result_referrals(
2561 (void) ldap_msgfree(cookie
->resultMsg
);
2562 cookie
->resultMsg
= NULL
;
2565 /* handle referrals if necessary */
2566 if (rc
== LDAP_RES_SEARCH_REFERENCE
) {
2567 if (cookie
->followRef
)
2568 proc_search_references(cookie
);
2569 (void) ldap_msgfree(cookie
->resultMsg
);
2570 cookie
->resultMsg
= NULL
;
2573 if (rc
!= LDAP_RES_SEARCH_ENTRY
) {
2576 if (cookie
->no_wait
== B_TRUE
) {
2577 (void) ldap_msgfree(
2579 cookie
->resultMsg
= NULL
;
2580 return (cookie
->new_state
);
2585 rc
= ldap_get_lderrno(cookie
->conn
->ld
,
2589 rc
= ldap_result2error(cookie
->conn
->ld
,
2590 cookie
->resultMsg
, 1);
2593 if ((rc
== LDAP_TIMEOUT
||
2594 rc
== LDAP_SERVER_DOWN
) &&
2595 (cookie
->conn_user
== NULL
||
2596 cookie
->conn_user
->conn_mt
== NULL
)) {
2597 if (rc
== LDAP_TIMEOUT
)
2598 (void) __s_api_removeServer(
2599 cookie
->conn
->serverAddr
);
2600 if (cookie
->connectionId
> -1) {
2602 cookie
->connectionId
,
2604 cookie
->connectionId
= -1;
2606 cookie
->err_from_result
= 1;
2608 (void) ldap_msgfree(cookie
->resultMsg
);
2609 cookie
->resultMsg
= NULL
;
2610 if (rc
== LDAP_BUSY
||
2611 rc
== LDAP_UNAVAILABLE
||
2612 rc
== LDAP_UNWILLING_TO_PERFORM
) {
2613 if (cookie
->reinit_on_retriable_err
) {
2614 cookie
->err_rc
= rc
;
2615 cookie
->err_from_result
= 1;
2616 cookie
->new_state
= REINIT
;
2622 if ((rc
== LDAP_CONNECT_ERROR
||
2623 rc
== LDAP_SERVER_DOWN
) &&
2624 cookie
->reinit_on_retriable_err
) {
2625 ns_ldap_error_t
*errorp
= NULL
;
2626 cookie
->err_rc
= rc
;
2627 cookie
->err_from_result
= 1;
2628 cookie
->new_state
= REINIT
;
2629 if (cookie
->conn_user
!= NULL
)
2630 __s_api_conn_mt_close(
2633 if (errorp
!= NULL
) {
2634 (void) __ns_ldap_freeError(
2636 cookie
->errorp
= errorp
;
2640 cookie
->err_rc
= rc
;
2641 cookie
->new_state
= LDAP_ERROR
;
2644 /* else LDAP_RES_SEARCH_ENTRY */
2645 /* get account management response control */
2646 if (cookie
->nopasswd_acct_mgmt
== 1) {
2647 rc
= ldap_get_entry_controls(cookie
->conn
->ld
,
2649 &(cookie
->resultctrl
));
2650 if (rc
!= LDAP_SUCCESS
) {
2651 cookie
->new_state
= LDAP_ERROR
;
2652 cookie
->err_rc
= rc
;
2656 rc
= __s_api_getEntry(cookie
);
2657 (void) ldap_msgfree(cookie
->resultMsg
);
2658 cookie
->resultMsg
= NULL
;
2659 if (rc
!= NS_LDAP_SUCCESS
) {
2660 cookie
->new_state
= LDAP_ERROR
;
2663 cookie
->new_state
= PROCESS_RESULT
;
2664 cookie
->next_state
= NEXT_RESULT
;
2667 if (cookie
->no_wait
== B_TRUE
)
2668 (void) memset(&tv
, 0, sizeof (tv
));
2670 tv
= cookie
->search_timeout
;
2671 rc
= ldap_result(cookie
->conn
->ld
, cookie
->msgId
,
2674 &cookie
->resultMsg
);
2675 if (rc
== LDAP_RES_SEARCH_RESULT
) {
2676 rc
= ldap_result2error(cookie
->conn
->ld
,
2677 cookie
->resultMsg
, 0);
2678 if (rc
== LDAP_ADMINLIMIT_EXCEEDED
&&
2679 cookie
->listType
== VLVCTRLFLAG
&&
2680 cookie
->sortTypeTry
== SSS_SINGLE_ATTR
) {
2681 /* Try old "cn uid" server side sort */
2682 cookie
->sortTypeTry
= SSS_CN_UID_ATTRS
;
2683 cookie
->new_state
= NEXT_VLV
;
2684 (void) ldap_msgfree(cookie
->resultMsg
);
2685 cookie
->resultMsg
= NULL
;
2688 if (rc
!= LDAP_SUCCESS
) {
2689 cookie
->err_rc
= rc
;
2690 cookie
->new_state
= LDAP_ERROR
;
2691 (void) ldap_msgfree(cookie
->resultMsg
);
2692 cookie
->resultMsg
= NULL
;
2695 cookie
->new_state
= multi_result(cookie
);
2696 (void) ldap_msgfree(cookie
->resultMsg
);
2697 cookie
->resultMsg
= NULL
;
2700 /* handle referrals if necessary */
2701 if (rc
== LDAP_RES_SEARCH_REFERENCE
&&
2702 cookie
->followRef
) {
2703 proc_search_references(cookie
);
2704 (void) ldap_msgfree(cookie
->resultMsg
);
2705 cookie
->resultMsg
= NULL
;
2708 if (rc
!= LDAP_RES_SEARCH_ENTRY
) {
2711 if (cookie
->no_wait
== B_TRUE
) {
2712 (void) ldap_msgfree(
2714 cookie
->resultMsg
= NULL
;
2715 return (cookie
->new_state
);
2720 rc
= ldap_get_lderrno(cookie
->conn
->ld
,
2724 rc
= ldap_result2error(cookie
->conn
->ld
,
2725 cookie
->resultMsg
, 1);
2728 if ((rc
== LDAP_TIMEOUT
||
2729 rc
== LDAP_SERVER_DOWN
) &&
2730 (cookie
->conn_user
== NULL
||
2731 cookie
->conn_user
->conn_mt
== NULL
)) {
2732 if (rc
== LDAP_TIMEOUT
)
2733 (void) __s_api_removeServer(
2734 cookie
->conn
->serverAddr
);
2735 if (cookie
->connectionId
> -1) {
2737 cookie
->connectionId
,
2739 cookie
->connectionId
= -1;
2741 cookie
->err_from_result
= 1;
2743 (void) ldap_msgfree(cookie
->resultMsg
);
2744 cookie
->resultMsg
= NULL
;
2745 if (rc
== LDAP_BUSY
||
2746 rc
== LDAP_UNAVAILABLE
||
2747 rc
== LDAP_UNWILLING_TO_PERFORM
) {
2748 if (cookie
->reinit_on_retriable_err
) {
2749 cookie
->err_rc
= rc
;
2750 cookie
->err_from_result
= 1;
2751 cookie
->new_state
= REINIT
;
2758 if ((rc
== LDAP_CONNECT_ERROR
||
2759 rc
== LDAP_SERVER_DOWN
) &&
2760 cookie
->reinit_on_retriable_err
) {
2761 ns_ldap_error_t
*errorp
= NULL
;
2762 cookie
->err_rc
= rc
;
2763 cookie
->err_from_result
= 1;
2764 cookie
->new_state
= REINIT
;
2765 if (cookie
->conn_user
!= NULL
)
2766 __s_api_conn_mt_close(
2769 if (errorp
!= NULL
) {
2770 (void) __ns_ldap_freeError(
2772 cookie
->errorp
= errorp
;
2776 cookie
->err_rc
= rc
;
2777 cookie
->new_state
= LDAP_ERROR
;
2780 /* else LDAP_RES_SEARCH_ENTRY */
2781 cookie
->entryCount
++;
2782 rc
= __s_api_getEntry(cookie
);
2783 (void) ldap_msgfree(cookie
->resultMsg
);
2784 cookie
->resultMsg
= NULL
;
2785 if (rc
!= NS_LDAP_SUCCESS
) {
2786 cookie
->new_state
= LDAP_ERROR
;
2790 * If VLV search was successfull save the server
2791 * side sort type tried.
2793 if (cookie
->listType
== VLVCTRLFLAG
)
2794 update_srvsidesort_type(cookie
->service
,
2795 cookie
->sortTypeTry
);
2797 cookie
->new_state
= PROCESS_RESULT
;
2798 cookie
->next_state
= MULTI_RESULT
;
2800 case PROCESS_RESULT
:
2801 /* NOTE THIS STATE MAY BE PROCESSED BY CALLER */
2802 if (cookie
->use_usercb
&& cookie
->callback
) {
2804 for (nextEntry
= cookie
->result
->entry
;
2806 nextEntry
= nextEntry
->next
) {
2807 rc
= (*cookie
->callback
)(nextEntry
,
2810 if (rc
== NS_LDAP_CB_DONE
) {
2811 /* cb doesn't want any more data */
2812 rc
= NS_LDAP_PARTIAL
;
2813 cookie
->err_rc
= rc
;
2815 } else if (rc
!= NS_LDAP_CB_NEXT
) {
2816 /* invalid return code */
2817 rc
= NS_LDAP_OP_FAILED
;
2818 cookie
->err_rc
= rc
;
2822 (void) __ns_ldap_freeResult(&cookie
->result
);
2823 cookie
->result
= NULL
;
2826 cookie
->new_state
= EXIT
;
2829 /* NOTE PREVIOUS STATE SPECIFIES NEXT STATE */
2830 cookie
->new_state
= cookie
->next_state
;
2832 case END_PROCESS_RESULT
:
2833 cookie
->new_state
= cookie
->next_state
;
2837 * XXX DO WE NEED THIS CASE?
2838 * if (search is complete) {
2839 * cookie->new_state = EXIT;
2843 * entering referral mode if necessary
2845 if (cookie
->followRef
&& cookie
->reflist
)
2850 NEXT_SEARCH_DESCRIPTOR
;
2853 /* get next referral info */
2854 if (cookie
->refpos
== NULL
)
2859 cookie
->refpos
->next
;
2860 /* check see if done with all referrals */
2861 if (cookie
->refpos
!= NULL
)
2863 GET_REFERRAL_SESSION
;
2865 __s_api_deleteRefInfo(cookie
->reflist
);
2866 cookie
->reflist
= NULL
;
2868 NEXT_SEARCH_DESCRIPTOR
;
2869 if (cookie
->conn_user
!= NULL
)
2870 cookie
->conn_user
->referral
= B_FALSE
;
2873 case GET_REFERRAL_SESSION
:
2874 if (get_referral_session(cookie
) < 0)
2875 cookie
->new_state
= EXIT
;
2877 cookie
->new_state
= NEXT_SEARCH
;
2881 rc_save
= cookie
->err_rc
;
2882 if (cookie
->err_from_result
) {
2883 if (cookie
->err_rc
== LDAP_SERVER_DOWN
) {
2884 (void) sprintf(errstr
,
2885 gettext("LDAP ERROR (%d): "
2886 "Error occurred during"
2887 " receiving results. "
2888 "Connection to server lost."),
2890 } else if (cookie
->err_rc
== LDAP_TIMEOUT
) {
2891 (void) sprintf(errstr
,
2892 gettext("LDAP ERROR (%d): "
2893 "Error occurred during"
2894 " receiving results. %s"
2895 "."), cookie
->err_rc
,
2900 (void) sprintf(errstr
,
2901 gettext("LDAP ERROR (%d): %s."),
2903 ldap_err2string(cookie
->err_rc
));
2904 err
= strdup(errstr
);
2905 if (cookie
->err_from_result
) {
2906 if (cookie
->err_rc
== LDAP_SERVER_DOWN
) {
2907 MKERROR(LOG_INFO
, *errorp
,
2908 cookie
->err_rc
, err
, 0);
2910 MKERROR(LOG_WARNING
, *errorp
,
2911 cookie
->err_rc
, err
, 0);
2914 MKERROR(LOG_WARNING
, *errorp
, NS_LDAP_INTERNAL
,
2917 cookie
->err_rc
= NS_LDAP_INTERNAL
;
2918 cookie
->errorp
= *errorp
;
2919 if (cookie
->conn_user
!= NULL
) {
2920 if (rc_save
== LDAP_SERVER_DOWN
||
2921 rc_save
== LDAP_CONNECT_ERROR
) {
2923 * MT connection is not usable,
2926 __s_api_conn_mt_close(cookie
->conn_user
,
2927 rc_save
, &cookie
->errorp
);
2934 (void) sprintf(errstr
,
2935 gettext("Internal State machine exit (%d).\n"),
2937 err
= strdup(errstr
);
2938 MKERROR(LOG_WARNING
, *errorp
, NS_LDAP_INTERNAL
, err
,
2940 cookie
->err_rc
= NS_LDAP_INTERNAL
;
2941 cookie
->errorp
= *errorp
;
2945 if (cookie
->conn_user
!= NULL
&&
2946 cookie
->conn_user
->bad_mt_conn
== B_TRUE
) {
2947 __s_api_conn_mt_close(cookie
->conn_user
, 0, NULL
);
2948 cookie
->err_rc
= cookie
->conn_user
->ns_rc
;
2949 cookie
->errorp
= cookie
->conn_user
->ns_error
;
2950 cookie
->conn_user
->ns_error
= NULL
;
2954 if (cycle
== ONE_STEP
) {
2955 return (cookie
->new_state
);
2957 cookie
->state
= cookie
->new_state
;
2961 (void) sprintf(errstr
,
2962 gettext("Unexpected State machine error.\n"));
2963 err
= strdup(errstr
);
2964 MKERROR(LOG_WARNING
, *errorp
, NS_LDAP_INTERNAL
, err
, NULL
);
2965 cookie
->err_rc
= NS_LDAP_INTERNAL
;
2966 cookie
->errorp
= *errorp
;
2972 * For a lookup of shadow data, if shadow update is enabled,
2973 * check the calling process' privilege to ensure it's
2974 * allowed to perform such operation.
2977 check_shadow(ns_ldap_cookie_t
*cookie
, const char *service
)
2979 char errstr
[MAXERROR
];
2988 * If service is "shadow", we may need
2989 * to use privilege credentials.
2991 if ((strcmp(service
, "shadow") == 0) &&
2992 __ns_ldap_is_shadow_update_enabled()) {
2994 * Since we release admin credentials after
2995 * connection is closed and we do not cache
2996 * them, we allow any root or all zone
2997 * privilege process to read shadow data.
2999 priv
= (geteuid() == 0);
3002 ps
= priv_allocset();
3004 (void) getppriv(PRIV_EFFECTIVE
, ps
);
3005 zs
= priv_str_to_set("zone", ",", NULL
);
3006 priv
= priv_isequalset(ps
, zs
);
3011 (void) sprintf(errstr
,
3012 gettext("Permission denied"));
3013 err
= strdup(errstr
);
3015 return (NS_LDAP_MEMORY
);
3016 MKERROR(LOG_INFO
, cookie
->errorp
, NS_LDAP_INTERNAL
, err
,
3018 return (NS_LDAP_INTERNAL
);
3020 cookie
->i_flags
|= NS_LDAP_READ_SHADOW
;
3022 * We do not want to reuse connection (hence
3023 * keep it open) with admin credentials.
3024 * If NS_LDAP_KEEP_CONN is set, reject the
3027 if (cookie
->i_flags
& NS_LDAP_KEEP_CONN
)
3028 return (NS_LDAP_INVALID_PARAM
);
3029 cookie
->i_flags
|= NS_LDAP_NEW_CONN
;
3032 return (NS_LDAP_SUCCESS
);
3036 * internal function for __ns_ldap_list
3040 ns_ldap_list_batch_t
*batch
,
3041 const char *service
,
3043 const char *sortattr
,
3044 int (*init_filter_cb
)(const ns_ldap_search_desc_t
*desc
,
3045 char **realfilter
, const void *userdata
),
3046 const char * const *attribute
,
3047 const ns_cred_t
*auth
,
3049 ns_ldap_result_t
**rResult
, /* return result entries */
3050 ns_ldap_error_t
**errorp
,
3052 int (*callback
)(const ns_ldap_entry_t
*entry
, const void *userdata
),
3053 const void *userdata
, ns_conn_user_t
*conn_user
)
3055 ns_ldap_cookie_t
*cookie
;
3056 ns_ldap_search_desc_t
**sdlist
= NULL
;
3057 ns_ldap_search_desc_t
*dptr
;
3058 ns_ldap_error_t
*error
= NULL
;
3066 *rcp
= NS_LDAP_SUCCESS
;
3069 * Sanity check - NS_LDAP_READ_SHADOW is for our
3072 if (flags
& NS_LDAP_READ_SHADOW
)
3073 return (NS_LDAP_INVALID_PARAM
);
3075 /* Initialize State machine cookie */
3076 cookie
= init_search_state_machine();
3077 if (cookie
== NULL
) {
3078 *rcp
= NS_LDAP_MEMORY
;
3079 return (NS_LDAP_MEMORY
);
3081 cookie
->conn_user
= conn_user
;
3083 /* see if need to follow referrals */
3084 rc
= __s_api_toFollowReferrals(flags
,
3085 &cookie
->followRef
, errorp
);
3086 if (rc
!= NS_LDAP_SUCCESS
) {
3087 delete_search_cookie(cookie
);
3092 /* get the service descriptor - or create a default one */
3093 rc
= __s_api_get_SSD_from_SSDtoUse_service(service
,
3095 if (rc
!= NS_LDAP_SUCCESS
) {
3096 delete_search_cookie(cookie
);
3102 if (sdlist
== NULL
) {
3103 /* Create default service Desc */
3104 sdlist
= (ns_ldap_search_desc_t
**)calloc(2,
3105 sizeof (ns_ldap_search_desc_t
*));
3106 if (sdlist
== NULL
) {
3107 delete_search_cookie(cookie
);
3109 *rcp
= NS_LDAP_MEMORY
;
3110 return (NS_LDAP_MEMORY
);
3112 dptr
= (ns_ldap_search_desc_t
*)
3113 calloc(1, sizeof (ns_ldap_search_desc_t
));
3116 delete_search_cookie(cookie
);
3118 *rcp
= NS_LDAP_MEMORY
;
3119 return (NS_LDAP_MEMORY
);
3124 rc
= __s_api_getDNs(&dns
, service
, &cookie
->errorp
);
3125 if (rc
!= NS_LDAP_SUCCESS
) {
3127 __s_api_free2dArray(dns
);
3130 *errorp
= cookie
->errorp
;
3131 cookie
->errorp
= NULL
;
3132 delete_search_cookie(cookie
);
3137 dptr
->basedn
= strdup(dns
[0]);
3138 __s_api_free2dArray(dns
);
3143 rc
= __s_api_getSearchScope(&scope
, &cookie
->errorp
);
3144 dptr
->scope
= scope
;
3147 cookie
->sdlist
= sdlist
;
3150 * use VLV/PAGE control only if NS_LDAP_PAGE_CTRL is set
3152 if (flags
& NS_LDAP_PAGE_CTRL
)
3153 cookie
->use_paging
= TRUE
;
3155 cookie
->use_paging
= FALSE
;
3157 /* Set up other arguments */
3158 cookie
->userdata
= userdata
;
3159 if (init_filter_cb
!= NULL
) {
3160 cookie
->init_filter_cb
= init_filter_cb
;
3161 cookie
->use_filtercb
= 1;
3163 if (callback
!= NULL
) {
3164 cookie
->callback
= callback
;
3165 cookie
->use_usercb
= 1;
3168 /* check_shadow() may add extra value to cookie->i_flags */
3169 cookie
->i_flags
= flags
;
3171 cookie
->service
= strdup(service
);
3172 if (cookie
->service
== NULL
) {
3173 delete_search_cookie(cookie
);
3175 *rcp
= NS_LDAP_MEMORY
;
3176 return (NS_LDAP_MEMORY
);
3180 * If given, use the credential given by the caller, and
3181 * skip the credential check required for shadow update.
3184 rc
= check_shadow(cookie
, service
);
3185 if (rc
!= NS_LDAP_SUCCESS
) {
3186 *errorp
= cookie
->errorp
;
3187 cookie
->errorp
= NULL
;
3188 delete_search_cookie(cookie
);
3196 cookie
->i_filter
= strdup(filter
);
3197 cookie
->i_attr
= attribute
;
3198 cookie
->i_auth
= auth
;
3199 cookie
->i_sortattr
= sortattr
;
3201 if (batch
!= NULL
) {
3202 cookie
->batch
= batch
;
3203 cookie
->reinit_on_retriable_err
= B_TRUE
;
3204 cookie
->no_wait
= B_TRUE
;
3205 (void) search_state_machine(cookie
, INIT
, 0);
3206 cookie
->no_wait
= B_FALSE
;
3207 rc
= cookie
->err_rc
;
3209 if (rc
== NS_LDAP_SUCCESS
) {
3211 * Here rc == NS_LDAP_SUCCESS means that the state
3212 * machine init'ed successfully. The actual status
3213 * of the search will be determined by
3214 * __ns_ldap_list_batch_end(). Add the cookie to our
3217 cookie
->caller_result
= rResult
;
3218 cookie
->caller_errorp
= errorp
;
3219 cookie
->caller_rc
= rcp
;
3220 cookie
->next_cookie_in_batch
= batch
->cookie_list
;
3221 batch
->cookie_list
= cookie
;
3226 * If state machine init failed then copy error to the caller
3227 * and delete the cookie.
3230 (void) search_state_machine(cookie
, INIT
, 0);
3233 /* Copy results back to user */
3234 rc
= cookie
->err_rc
;
3235 if (rc
!= NS_LDAP_SUCCESS
) {
3236 if (conn_user
!= NULL
&& conn_user
->ns_error
!= NULL
) {
3237 *errorp
= conn_user
->ns_error
;
3238 conn_user
->ns_error
= NULL
;
3240 *errorp
= cookie
->errorp
;
3242 *rResult
= cookie
->result
;
3243 from_result
= cookie
->err_from_result
;
3245 cookie
->errorp
= NULL
;
3246 cookie
->result
= NULL
;
3247 delete_search_cookie(cookie
);
3250 if (from_result
== 0 && *rResult
== NULL
)
3251 rc
= NS_LDAP_NOTFOUND
;
3258 * __ns_ldap_list performs one or more LDAP searches to a given
3259 * directory server using service search descriptors and schema
3260 * mapping as appropriate. The operation may be retried a
3261 * couple of times in error situations.
3265 const char *service
,
3267 int (*init_filter_cb
)(const ns_ldap_search_desc_t
*desc
,
3268 char **realfilter
, const void *userdata
),
3269 const char * const *attribute
,
3270 const ns_cred_t
*auth
,
3272 ns_ldap_result_t
**rResult
, /* return result entries */
3273 ns_ldap_error_t
**errorp
,
3274 int (*callback
)(const ns_ldap_entry_t
*entry
, const void *userdata
),
3275 const void *userdata
)
3279 * Strip the NS_LDAP_PAGE_CTRL option as this interface does not
3280 * support this. If you want to use this option call the API
3281 * __ns_ldap_list_sort() with has the sort attribute.
3283 mod_flags
= flags
& (~NS_LDAP_PAGE_CTRL
);
3285 return (__ns_ldap_list_sort(service
, filter
, NULL
, init_filter_cb
,
3286 attribute
, auth
, mod_flags
, rResult
, errorp
,
3287 callback
, userdata
));
3291 * __ns_ldap_list_sort performs one or more LDAP searches to a given
3292 * directory server using service search descriptors and schema
3293 * mapping as appropriate. The operation may be retried a
3294 * couple of times in error situations.
3297 __ns_ldap_list_sort(
3298 const char *service
,
3300 const char *sortattr
,
3301 int (*init_filter_cb
)(const ns_ldap_search_desc_t
*desc
,
3302 char **realfilter
, const void *userdata
),
3303 const char * const *attribute
,
3304 const ns_cred_t
*auth
,
3306 ns_ldap_result_t
**rResult
, /* return result entries */
3307 ns_ldap_error_t
**errorp
,
3308 int (*callback
)(const ns_ldap_entry_t
*entry
, const void *userdata
),
3309 const void *userdata
)
3311 ns_conn_user_t
*cu
= NULL
;
3313 int rc
= NS_LDAP_SUCCESS
, trc
;
3316 if (__s_api_setup_retry_search(&cu
, NS_CONN_USER_SEARCH
,
3317 &try_cnt
, &rc
, errorp
) == 0)
3319 rc
= ldap_list(NULL
, service
, filter
, sortattr
, init_filter_cb
,
3320 attribute
, auth
, flags
, rResult
, errorp
, &trc
, callback
,
3328 * Create and initialize batch for native LDAP lookups
3331 __ns_ldap_list_batch_start(ns_ldap_list_batch_t
**batch
)
3333 *batch
= calloc(1, sizeof (ns_ldap_list_batch_t
));
3335 return (NS_LDAP_MEMORY
);
3336 return (NS_LDAP_SUCCESS
);
3341 * Add a LDAP search request to the batch.
3344 __ns_ldap_list_batch_add(
3345 ns_ldap_list_batch_t
*batch
,
3346 const char *service
,
3348 int (*init_filter_cb
)(const ns_ldap_search_desc_t
*desc
,
3349 char **realfilter
, const void *userdata
),
3350 const char * const *attribute
,
3351 const ns_cred_t
*auth
,
3353 ns_ldap_result_t
**rResult
, /* return result entries */
3354 ns_ldap_error_t
**errorp
,
3356 int (*callback
)(const ns_ldap_entry_t
*entry
, const void *userdata
),
3357 const void *userdata
)
3363 cu
= __s_api_conn_user_init(NS_CONN_USER_SEARCH
, NULL
, 0);
3366 *rcp
= NS_LDAP_MEMORY
;
3367 return (NS_LDAP_MEMORY
);
3371 * Strip the NS_LDAP_PAGE_CTRL option as the batch interface does not
3374 mod_flags
= flags
& (~NS_LDAP_PAGE_CTRL
);
3376 rc
= ldap_list(batch
, service
, filter
, NULL
, init_filter_cb
, attribute
,
3377 auth
, mod_flags
, rResult
, errorp
, rcp
, callback
, userdata
, cu
);
3380 * Free the conn_user if the cookie was not batched. If the cookie
3381 * was batched then __ns_ldap_list_batch_end or release will free the
3382 * conn_user. The batch API instructs the search_state_machine
3383 * to reinit and retry (max 3 times) on retriable LDAP errors.
3385 if (rc
!= NS_LDAP_SUCCESS
&& cu
!= NULL
) {
3386 if (cu
->conn_mt
!= NULL
)
3387 __s_api_conn_mt_return(cu
);
3388 __s_api_conn_user_free(cu
);
3398 __ns_ldap_list_batch_release(ns_ldap_list_batch_t
*batch
)
3400 ns_ldap_cookie_t
*c
, *next
;
3402 for (c
= batch
->cookie_list
; c
!= NULL
; c
= next
) {
3403 next
= c
->next_cookie_in_batch
;
3404 if (c
->conn_user
!= NULL
) {
3405 if (c
->conn_user
->conn_mt
!= NULL
)
3406 __s_api_conn_mt_return(c
->conn_user
);
3407 __s_api_conn_user_free(c
->conn_user
);
3408 c
->conn_user
= NULL
;
3410 delete_search_cookie(c
);
3415 #define LD_USING_STATE(st) \
3416 ((st == DO_SEARCH) || (st == MULTI_RESULT) || (st == NEXT_RESULT))
3419 * Process batch. Everytime this function is called it selects an
3420 * active cookie from the batch and single steps through the
3421 * search_state_machine for the selected cookie. If lookup associated
3422 * with the cookie is complete (success or error) then the cookie is
3423 * removed from the batch and its memory freed.
3425 * Returns 1 (if batch still has active cookies)
3426 * 0 (if batch has no more active cookies)
3427 * -1 (on errors, *rcp will contain the error code)
3429 * The caller should call this function in a loop as long as it returns 1
3430 * to process all the requests added to the batch. The results (and errors)
3431 * will be available in the locations provided by the caller at the time of
3432 * __ns_ldap_list_batch_add().
3436 __ns_ldap_list_batch_process(ns_ldap_list_batch_t
*batch
, int *rcp
)
3438 ns_ldap_cookie_t
*c
, *ptr
, **prev
;
3440 ns_ldap_error_t
*errorp
= NULL
;
3443 /* Check if are already done */
3444 if (batch
->nactive
== 0)
3447 /* Get the next cookie from the batch */
3448 c
= (batch
->next_cookie
== NULL
) ?
3449 batch
->cookie_list
: batch
->next_cookie
;
3451 batch
->next_cookie
= c
->next_cookie_in_batch
;
3454 * Checks the status of the cookie's connection if it needs
3455 * to use that connection for ldap_search_ext or ldap_result.
3456 * If the connection is no longer good but worth retrying
3457 * then reinit the search_state_machine for this cookie
3458 * starting from the first search descriptor. REINIT will
3459 * clear any leftover results if max retries have not been
3460 * reached and redo the search (which may also involve
3461 * following referrals again).
3463 * Note that each cookie in the batch will make this
3464 * determination when it reaches one of the LD_USING_STATES.
3466 if (LD_USING_STATE(c
->new_state
) && c
->conn_user
!= NULL
) {
3467 rc
= __s_api_setup_getnext(c
->conn_user
, &c
->err_rc
, &errorp
);
3468 if (rc
== LDAP_BUSY
|| rc
== LDAP_UNAVAILABLE
||
3469 rc
== LDAP_UNWILLING_TO_PERFORM
) {
3470 if (errorp
!= NULL
) {
3471 (void) __ns_ldap_freeError(&c
->errorp
);
3474 c
->new_state
= REINIT
;
3475 } else if (rc
== LDAP_CONNECT_ERROR
||
3476 rc
== LDAP_SERVER_DOWN
) {
3477 if (errorp
!= NULL
) {
3478 (void) __ns_ldap_freeError(&c
->errorp
);
3481 c
->new_state
= REINIT
;
3483 * MT connection is not usable,
3484 * close it before REINIT.
3486 __s_api_conn_mt_close(
3487 c
->conn_user
, rc
, NULL
);
3488 } else if (rc
!= NS_LDAP_SUCCESS
) {
3491 *c
->caller_result
= NULL
;
3492 *c
->caller_errorp
= errorp
;
3499 /* Single step through the search_state_machine */
3500 state
= search_state_machine(c
, c
->new_state
, ONE_STEP
);
3503 (void) search_state_machine(c
, state
, ONE_STEP
);
3504 (void) search_state_machine(c
, CLEAR_RESULTS
, ONE_STEP
);
3508 *c
->caller_result
= c
->result
;
3509 *c
->caller_errorp
= c
->errorp
;
3511 (c
->result
== NULL
&& c
->err_from_result
== 0)
3512 ? NS_LDAP_NOTFOUND
: c
->err_rc
;
3515 /* Remove the cookie from the batch */
3516 ptr
= batch
->cookie_list
;
3517 prev
= &batch
->cookie_list
;
3518 while (ptr
!= NULL
) {
3520 *prev
= ptr
->next_cookie_in_batch
;
3523 prev
= &ptr
->next_cookie_in_batch
;
3524 ptr
= ptr
->next_cookie_in_batch
;
3526 /* Delete cookie and decrement active cookie count */
3527 if (c
->conn_user
!= NULL
) {
3528 if (c
->conn_user
->conn_mt
!= NULL
)
3529 __s_api_conn_mt_return(c
->conn_user
);
3530 __s_api_conn_user_free(c
->conn_user
);
3531 c
->conn_user
= NULL
;
3533 delete_search_cookie(c
);
3539 * This means that search_state_machine needs to do
3540 * another ldap_result() for the cookie in question.
3541 * We only do at most one ldap_result() per call in
3542 * this function and therefore we return. This allows
3543 * the caller to process results from other cookies
3544 * in the batch without getting tied up on just one
3550 * This includes states that follow NEXT_RESULT or
3551 * MULTI_RESULT such as PROCESS_RESULT and
3552 * END_PROCESS_RESULT. We continue processing
3553 * this cookie till we reach either the error, exit
3554 * or the result states.
3561 /* Return 0 if no more cookies left otherwise 1 */
3562 return ((batch
->nactive
> 0) ? 1 : 0);
3567 * Process all the active cookies in the batch and when none
3568 * remains finalize the batch.
3571 __ns_ldap_list_batch_end(ns_ldap_list_batch_t
*batch
)
3573 int rc
= NS_LDAP_SUCCESS
;
3574 while (__ns_ldap_list_batch_process(batch
, &rc
) > 0)
3576 __ns_ldap_list_batch_release(batch
);
3581 * find_domainname performs one or more LDAP searches to
3582 * find the value of the nisdomain attribute associated with
3583 * the input DN (with no retry).
3587 find_domainname(const char *dn
, char **domainname
, const ns_cred_t
*cred
,
3588 ns_ldap_error_t
**errorp
, ns_conn_user_t
*conn_user
)
3591 ns_ldap_cookie_t
*cookie
;
3592 ns_ldap_search_desc_t
**sdlist
;
3593 ns_ldap_search_desc_t
*dptr
;
3601 /* Initialize State machine cookie */
3602 cookie
= init_search_state_machine();
3603 if (cookie
== NULL
) {
3604 return (NS_LDAP_MEMORY
);
3606 cookie
->conn_user
= conn_user
;
3608 /* see if need to follow referrals */
3609 rc
= __s_api_toFollowReferrals(flags
,
3610 &cookie
->followRef
, errorp
);
3611 if (rc
!= NS_LDAP_SUCCESS
) {
3612 delete_search_cookie(cookie
);
3616 /* Create default service Desc */
3617 sdlist
= (ns_ldap_search_desc_t
**)calloc(2,
3618 sizeof (ns_ldap_search_desc_t
*));
3619 if (sdlist
== NULL
) {
3620 delete_search_cookie(cookie
);
3622 return (NS_LDAP_MEMORY
);
3624 dptr
= (ns_ldap_search_desc_t
*)
3625 calloc(1, sizeof (ns_ldap_search_desc_t
));
3628 delete_search_cookie(cookie
);
3630 return (NS_LDAP_MEMORY
);
3634 /* search base is dn */
3635 dptr
->basedn
= strdup(dn
);
3637 /* search scope is base */
3638 dptr
->scope
= NS_LDAP_SCOPE_BASE
;
3640 /* search filter is "nisdomain=*" */
3641 dptr
->filter
= strdup(_NIS_FILTER
);
3643 cookie
->sdlist
= sdlist
;
3644 cookie
->i_filter
= strdup(dptr
->filter
);
3645 cookie
->i_attr
= nis_domain_attrs
;
3646 cookie
->i_auth
= cred
;
3647 cookie
->i_flags
= 0;
3649 /* Process search */
3650 rc
= search_state_machine(cookie
, INIT
, 0);
3652 /* Copy domain name if found */
3653 rc
= cookie
->err_rc
;
3654 if (rc
!= NS_LDAP_SUCCESS
) {
3655 if (conn_user
!= NULL
&& conn_user
->ns_error
!= NULL
) {
3656 *errorp
= conn_user
->ns_error
;
3657 conn_user
->ns_error
= NULL
;
3659 *errorp
= cookie
->errorp
;
3661 if (cookie
->result
== NULL
)
3662 rc
= NS_LDAP_NOTFOUND
;
3663 if (rc
== NS_LDAP_SUCCESS
) {
3664 value
= __ns_ldap_getAttr(cookie
->result
->entry
,
3667 *domainname
= strdup(value
[0]);
3669 rc
= NS_LDAP_NOTFOUND
;
3671 if (cookie
->result
!= NULL
)
3672 (void) __ns_ldap_freeResult(&cookie
->result
);
3673 cookie
->errorp
= NULL
;
3674 delete_search_cookie(cookie
);
3680 * __s_api_find_domainname performs one or more LDAP searches to
3681 * find the value of the nisdomain attribute associated with
3682 * the input DN (with retry).
3686 __s_api_find_domainname(const char *dn
, char **domainname
,
3687 const ns_cred_t
*cred
, ns_ldap_error_t
**errorp
)
3689 ns_conn_user_t
*cu
= NULL
;
3691 int rc
= NS_LDAP_SUCCESS
;
3694 if (__s_api_setup_retry_search(&cu
, NS_CONN_USER_SEARCH
,
3695 &try_cnt
, &rc
, errorp
) == 0)
3697 rc
= find_domainname(dn
, domainname
, cred
, errorp
, cu
);
3705 const char *service
,
3707 const char *sortattr
,
3708 int (*init_filter_cb
)(const ns_ldap_search_desc_t
*desc
,
3709 char **realfilter
, const void *userdata
),
3710 const char * const *attribute
,
3711 const ns_cred_t
*auth
,
3714 ns_ldap_result_t
**result
,
3715 ns_ldap_error_t
** errorp
,
3716 const void *userdata
,
3717 ns_conn_user_t
*conn_user
)
3719 ns_ldap_cookie_t
*cookie
= NULL
;
3720 ns_ldap_error_t
*error
= NULL
;
3722 ns_ldap_search_desc_t
**sdlist
;
3723 ns_ldap_search_desc_t
*dptr
;
3732 * Sanity check - NS_LDAP_READ_SHADOW is for our
3735 if (flags
& NS_LDAP_READ_SHADOW
)
3736 return (NS_LDAP_INVALID_PARAM
);
3738 /* get the service descriptor - or create a default one */
3739 rc
= __s_api_get_SSD_from_SSDtoUse_service(service
,
3741 if (rc
!= NS_LDAP_SUCCESS
) {
3745 if (sdlist
== NULL
) {
3746 /* Create default service Desc */
3747 sdlist
= (ns_ldap_search_desc_t
**)calloc(2,
3748 sizeof (ns_ldap_search_desc_t
*));
3749 if (sdlist
== NULL
) {
3750 return (NS_LDAP_MEMORY
);
3752 dptr
= (ns_ldap_search_desc_t
*)
3753 calloc(1, sizeof (ns_ldap_search_desc_t
));
3756 return (NS_LDAP_MEMORY
);
3761 rc
= __s_api_getDNs(&dns
, service
, &error
);
3762 if (rc
!= NS_LDAP_SUCCESS
) {
3764 __s_api_free2dArray(dns
);
3768 (void) __ns_ldap_freeSearchDescriptors(
3776 dptr
->basedn
= strdup(dns
[0]);
3777 __s_api_free2dArray(dns
);
3782 cookie
= init_search_state_machine();
3783 if (cookie
== NULL
) {
3785 (void) __ns_ldap_freeSearchDescriptors(&sdlist
);
3788 return (NS_LDAP_MEMORY
);
3790 rc
= __s_api_getSearchScope(&scope
, &cookie
->errorp
);
3791 dptr
->scope
= scope
;
3794 /* Initialize State machine cookie */
3796 cookie
= init_search_state_machine();
3797 if (cookie
== NULL
) {
3799 (void) __ns_ldap_freeSearchDescriptors(&sdlist
);
3802 return (NS_LDAP_MEMORY
);
3805 /* identify self as a getent user */
3806 cookie
->conn_user
= conn_user
;
3808 cookie
->sdlist
= sdlist
;
3810 /* see if need to follow referrals */
3811 rc
= __s_api_toFollowReferrals(flags
,
3812 &cookie
->followRef
, errorp
);
3813 if (rc
!= NS_LDAP_SUCCESS
) {
3814 delete_search_cookie(cookie
);
3819 * use VLV/PAGE control only if NS_LDAP_NO_PAGE_CTRL is not set
3821 if (flags
& NS_LDAP_NO_PAGE_CTRL
)
3822 cookie
->use_paging
= FALSE
;
3824 cookie
->use_paging
= TRUE
;
3826 /* Set up other arguments */
3827 cookie
->userdata
= userdata
;
3828 if (init_filter_cb
!= NULL
) {
3829 cookie
->init_filter_cb
= init_filter_cb
;
3830 cookie
->use_filtercb
= 1;
3832 cookie
->use_usercb
= 0;
3833 /* check_shadow() may add extra value to cookie->i_flags */
3834 cookie
->i_flags
= flags
;
3836 cookie
->service
= strdup(service
);
3837 if (cookie
->service
== NULL
) {
3838 delete_search_cookie(cookie
);
3839 return (NS_LDAP_MEMORY
);
3843 * If given, use the credential given by the caller, and
3844 * skip the credential check required for shadow update.
3847 rc
= check_shadow(cookie
, service
);
3848 if (rc
!= NS_LDAP_SUCCESS
) {
3849 *errorp
= cookie
->errorp
;
3850 cookie
->errorp
= NULL
;
3851 delete_search_cookie(cookie
);
3858 cookie
->i_filter
= strdup(filter
);
3859 cookie
->i_attr
= attribute
;
3860 cookie
->i_sortattr
= sortattr
;
3861 cookie
->i_auth
= auth
;
3865 state
= search_state_machine(cookie
, state
, ONE_STEP
);
3867 case PROCESS_RESULT
:
3868 *result
= cookie
->result
;
3869 cookie
->result
= NULL
;
3870 *vcookie
= (void *)cookie
;
3871 return (NS_LDAP_SUCCESS
);
3873 state
= search_state_machine(cookie
, state
, ONE_STEP
);
3874 state
= search_state_machine(cookie
, CLEAR_RESULTS
,
3878 rc
= cookie
->err_rc
;
3879 if (conn_user
!= NULL
&& conn_user
->ns_error
!= NULL
) {
3880 *errorp
= conn_user
->ns_error
;
3881 conn_user
->ns_error
= NULL
;
3883 *errorp
= cookie
->errorp
;
3884 cookie
->errorp
= NULL
;
3886 delete_search_cookie(cookie
);
3889 rc
= cookie
->err_rc
;
3890 if (rc
!= NS_LDAP_SUCCESS
) {
3891 *errorp
= cookie
->errorp
;
3892 cookie
->errorp
= NULL
;
3894 rc
= NS_LDAP_NOTFOUND
;
3897 delete_search_cookie(cookie
);
3907 __ns_ldap_firstEntry(
3908 const char *service
,
3910 const char *vlv_sort
,
3911 int (*init_filter_cb
)(const ns_ldap_search_desc_t
*desc
,
3912 char **realfilter
, const void *userdata
),
3913 const char * const *attribute
,
3914 const ns_cred_t
*auth
,
3917 ns_ldap_result_t
**result
,
3918 ns_ldap_error_t
** errorp
,
3919 const void *userdata
)
3921 ns_conn_user_t
*cu
= NULL
;
3923 int rc
= NS_LDAP_SUCCESS
;
3926 if (__s_api_setup_retry_search(&cu
, NS_CONN_USER_GETENT
,
3927 &try_cnt
, &rc
, errorp
) == 0)
3929 rc
= firstEntry(service
, filter
, vlv_sort
, init_filter_cb
,
3930 attribute
, auth
, flags
, vcookie
, result
, errorp
, userdata
,
3938 __ns_ldap_nextEntry(void *vcookie
, ns_ldap_result_t
**result
,
3939 ns_ldap_error_t
** errorp
)
3941 ns_ldap_cookie_t
*cookie
;
3945 cookie
= (ns_ldap_cookie_t
*)vcookie
;
3946 cookie
->result
= NULL
;
3949 if (cookie
->conn_user
!= NULL
) {
3950 rc
= __s_api_setup_getnext(cookie
->conn_user
,
3951 &cookie
->err_rc
, errorp
);
3952 if (rc
!= NS_LDAP_SUCCESS
)
3956 state
= END_PROCESS_RESULT
;
3958 state
= search_state_machine(cookie
, state
, ONE_STEP
);
3960 case PROCESS_RESULT
:
3961 *result
= cookie
->result
;
3962 cookie
->result
= NULL
;
3963 return (NS_LDAP_SUCCESS
);
3965 state
= search_state_machine(cookie
, state
, ONE_STEP
);
3966 state
= search_state_machine(cookie
, CLEAR_RESULTS
,
3970 rc
= cookie
->err_rc
;
3971 *errorp
= cookie
->errorp
;
3972 cookie
->errorp
= NULL
;
3975 return (NS_LDAP_SUCCESS
);
3983 ns_ldap_error_t
** errorp
)
3985 ns_ldap_cookie_t
*cookie
;
3988 if (*vcookie
== NULL
)
3989 return (NS_LDAP_INVALID_PARAM
);
3991 cookie
= (ns_ldap_cookie_t
*)(*vcookie
);
3992 cookie
->result
= NULL
;
3994 /* Complete search */
3995 rc
= search_state_machine(cookie
, CLEAR_RESULTS
, 0);
3997 /* Copy results back to user */
3998 rc
= cookie
->err_rc
;
3999 if (rc
!= NS_LDAP_SUCCESS
)
4000 *errorp
= cookie
->errorp
;
4002 cookie
->errorp
= NULL
;
4003 if (cookie
->conn_user
!= NULL
) {
4004 if (cookie
->conn_user
->conn_mt
!= NULL
)
4005 __s_api_conn_mt_return(cookie
->conn_user
);
4006 __s_api_conn_user_free(cookie
->conn_user
);
4008 delete_search_cookie(cookie
);
4017 __ns_ldap_freeResult(ns_ldap_result_t
**result
)
4020 ns_ldap_entry_t
*curEntry
= NULL
;
4021 ns_ldap_entry_t
*delEntry
= NULL
;
4023 ns_ldap_result_t
*res
= *result
;
4026 (void) fprintf(stderr
, "__ns_ldap_freeResult START\n");
4029 return (NS_LDAP_INVALID_PARAM
);
4031 if (res
->entry
!= NULL
)
4032 curEntry
= res
->entry
;
4034 for (i
= 0; i
< res
->entries_count
; i
++) {
4035 if (curEntry
!= NULL
) {
4036 delEntry
= curEntry
;
4037 curEntry
= curEntry
->next
;
4038 __ns_ldap_freeEntry(delEntry
);
4044 return (NS_LDAP_SUCCESS
);
4049 __ns_ldap_auth(const ns_cred_t
*auth
,
4051 ns_ldap_error_t
**errorp
,
4052 LDAPControl
**serverctrls
,
4053 LDAPControl
**clientctrls
)
4056 ConnectionID connectionId
= -1;
4059 int do_not_fail_if_new_pwd_reqd
= 0;
4060 int nopasswd_acct_mgmt
= 0;
4061 ns_conn_user_t
*conn_user
;
4065 (void) fprintf(stderr
, "__ns_ldap_auth START\n");
4070 return (NS_LDAP_INVALID_PARAM
);
4072 conn_user
= __s_api_conn_user_init(NS_CONN_USER_AUTH
,
4075 rc
= __s_api_getConnection(NULL
, flags
| NS_LDAP_NEW_CONN
,
4076 auth
, &connectionId
, &conp
, errorp
,
4077 do_not_fail_if_new_pwd_reqd
, nopasswd_acct_mgmt
,
4080 if (conn_user
!= NULL
)
4081 __s_api_conn_user_free(conn_user
);
4083 if (rc
== NS_LDAP_OP_FAILED
&& *errorp
)
4084 (void) __ns_ldap_freeError(errorp
);
4086 if (connectionId
> -1)
4087 DropConnection(connectionId
, flags
);
4092 __ns_ldap_getAttr(const ns_ldap_entry_t
*entry
, const char *attrname
)
4098 for (i
= 0; i
< entry
->attr_count
; i
++) {
4099 if (strcasecmp(entry
->attr_pair
[i
]->attrname
, attrname
) == 0)
4100 return (entry
->attr_pair
[i
]->attrvalue
);
4106 __ns_ldap_getAttrStruct(const ns_ldap_entry_t
*entry
, const char *attrname
)
4112 for (i
= 0; i
< entry
->attr_count
; i
++) {
4113 if (strcasecmp(entry
->attr_pair
[i
]->attrname
, attrname
) == 0)
4114 return (entry
->attr_pair
[i
]);
4122 __ns_ldap_uid2dn(const char *uid
,
4124 const ns_cred_t
*cred
, /* cred is ignored */
4125 ns_ldap_error_t
**errorp
)
4127 ns_ldap_result_t
*result
= NULL
;
4128 char *filter
, *userdata
;
4129 char errstr
[MAXERROR
];
4137 if ((uid
== NULL
) || (uid
[0] == '\0'))
4138 return (NS_LDAP_INVALID_PARAM
);
4140 while (uid
[i
] != '\0') {
4141 if (uid
[i
] == '=') {
4142 *userDN
= strdup(uid
);
4143 return (NS_LDAP_SUCCESS
);
4148 while ((uid
[i
] != '\0') && (isdigit(uid
[i
])))
4150 if (uid
[i
] == '\0') {
4151 len
= strlen(UIDNUMFILTER
) + strlen(uid
) + 1;
4152 filter
= (char *)malloc(len
);
4153 if (filter
== NULL
) {
4155 return (NS_LDAP_MEMORY
);
4157 (void) snprintf(filter
, len
, UIDNUMFILTER
, uid
);
4159 len
= strlen(UIDNUMFILTER_SSD
) + strlen(uid
) + 1;
4160 userdata
= (char *)malloc(len
);
4161 if (userdata
== NULL
) {
4163 return (NS_LDAP_MEMORY
);
4165 (void) snprintf(userdata
, len
, UIDNUMFILTER_SSD
, uid
);
4167 len
= strlen(UIDFILTER
) + strlen(uid
) + 1;
4168 filter
= (char *)malloc(len
);
4169 if (filter
== NULL
) {
4171 return (NS_LDAP_MEMORY
);
4173 (void) snprintf(filter
, len
, UIDFILTER
, uid
);
4175 len
= strlen(UIDFILTER_SSD
) + strlen(uid
) + 1;
4176 userdata
= (char *)malloc(len
);
4177 if (userdata
== NULL
) {
4179 return (NS_LDAP_MEMORY
);
4181 (void) snprintf(userdata
, len
, UIDFILTER_SSD
, uid
);
4185 * we want to retrieve the DN as it appears in LDAP
4186 * hence the use of NS_LDAP_NOT_CVT_DN in flags
4188 rc
= __ns_ldap_list("passwd", filter
,
4189 __s_api_merge_SSD_filter
,
4190 NULL
, cred
, NS_LDAP_NOT_CVT_DN
,
4191 &result
, errorp
, NULL
,
4197 if (rc
!= NS_LDAP_SUCCESS
) {
4199 (void) __ns_ldap_freeResult(&result
);
4204 if (result
->entries_count
> 1) {
4205 (void) __ns_ldap_freeResult(&result
);
4208 (void) sprintf(errstr
,
4209 gettext("Too many entries are returned for %s"), uid
);
4210 MKERROR(LOG_WARNING
, *errorp
, NS_LDAP_INTERNAL
, strdup(errstr
),
4212 return (NS_LDAP_INTERNAL
);
4215 value
= __ns_ldap_getAttr(result
->entry
, "dn");
4216 *userDN
= strdup(value
[0]);
4217 (void) __ns_ldap_freeResult(&result
);
4219 return (NS_LDAP_SUCCESS
);
4225 __ns_ldap_host2dn(const char *host
,
4228 const ns_cred_t
*cred
, /* cred is ignored */
4229 ns_ldap_error_t
**errorp
)
4231 ns_ldap_result_t
*result
= NULL
;
4232 char *filter
, *userdata
;
4233 char errstr
[MAXERROR
];
4240 * the domain parameter needs to be used in case domain is not local, if
4241 * this routine is to support multi domain setups, it needs lots of work...
4245 if ((host
== NULL
) || (host
[0] == '\0'))
4246 return (NS_LDAP_INVALID_PARAM
);
4248 len
= strlen(HOSTFILTER
) + strlen(host
) + 1;
4249 filter
= (char *)malloc(len
);
4250 if (filter
== NULL
) {
4251 return (NS_LDAP_MEMORY
);
4253 (void) snprintf(filter
, len
, HOSTFILTER
, host
);
4255 len
= strlen(HOSTFILTER_SSD
) + strlen(host
) + 1;
4256 userdata
= (char *)malloc(len
);
4257 if (userdata
== NULL
) {
4258 return (NS_LDAP_MEMORY
);
4260 (void) snprintf(userdata
, len
, HOSTFILTER_SSD
, host
);
4263 * we want to retrieve the DN as it appears in LDAP
4264 * hence the use of NS_LDAP_NOT_CVT_DN in flags
4266 rc
= __ns_ldap_list("hosts", filter
,
4267 __s_api_merge_SSD_filter
,
4268 NULL
, cred
, NS_LDAP_NOT_CVT_DN
, &result
,
4275 if (rc
!= NS_LDAP_SUCCESS
) {
4277 (void) __ns_ldap_freeResult(&result
);
4283 if (result
->entries_count
> 1) {
4284 (void) __ns_ldap_freeResult(&result
);
4287 (void) sprintf(errstr
,
4288 gettext("Too many entries are returned for %s"), host
);
4289 MKERROR(LOG_WARNING
, *errorp
, NS_LDAP_INTERNAL
, strdup(errstr
),
4291 return (NS_LDAP_INTERNAL
);
4294 value
= __ns_ldap_getAttr(result
->entry
, "dn");
4295 *hostDN
= strdup(value
[0]);
4296 (void) __ns_ldap_freeResult(&result
);
4298 return (NS_LDAP_SUCCESS
);
4303 __ns_ldap_dn2domain(const char *dn
,
4305 const ns_cred_t
*cred
,
4306 ns_ldap_error_t
**errorp
)
4308 int rc
, pnum
, i
, j
, len
= 0;
4309 char *newdn
, **rdns
= NULL
;
4315 return (NS_LDAP_INVALID_PARAM
);
4319 if ((dn
== NULL
) || (dn
[0] == '\0'))
4320 return (NS_LDAP_INVALID_PARAM
);
4323 * break dn into rdns
4327 return (NS_LDAP_MEMORY
);
4328 rdns
= ldap_explode_dn(dn1
, 0);
4330 if (rdns
== NULL
|| *rdns
== NULL
)
4331 return (NS_LDAP_INVALID_PARAM
);
4333 for (i
= 0; rdns
[i
]; i
++)
4334 len
+= strlen(rdns
[i
]) + 1;
4337 newdn
= (char *)malloc(len
+ 1);
4338 dns
= (char **)calloc(pnum
, sizeof (char *));
4339 if (newdn
== NULL
|| dns
== NULL
) {
4341 ldap_value_free(rdns
);
4342 return (NS_LDAP_MEMORY
);
4345 /* construct a semi-normalized dn, newdn */
4347 for (i
= 0; rdns
[i
]; i
++) {
4348 dns
[i
] = newdn
+ strlen(newdn
);
4349 (void) strcat(newdn
,
4350 __s_api_remove_rdn_space(rdns
[i
]));
4351 (void) strcat(newdn
, ",");
4353 /* remove the last ',' */
4354 newdn
[strlen(newdn
) - 1] = '\0';
4355 ldap_value_free(rdns
);
4358 * loop and find the domain name associated with newdn,
4359 * removing rdn one by one from left to right
4361 for (i
= 0; i
< pnum
; i
++) {
4364 (void) __ns_ldap_freeError(errorp
);
4367 * try cache manager first
4369 rc
= __s_api_get_cachemgr_data(NS_CACHE_DN2DOMAIN
,
4371 if (rc
!= NS_LDAP_SUCCESS
) {
4373 * try ldap server second
4375 rc
= __s_api_find_domainname(dns
[i
], domain
,
4379 * skip the last one,
4380 * since it is already cached by ldap_cachemgr
4384 if (rc
== NS_LDAP_SUCCESS
) {
4385 if (__s_api_nscd_proc()) {
4387 * If it's nscd, ask cache manager to save the
4388 * dn to domain mapping(s)
4390 for (j
= 0; j
<= i
; j
++) {
4391 (void) __s_api_set_cachemgr_data(
4403 if (rc
!= NS_LDAP_SUCCESS
)
4404 rc
= NS_LDAP_NOTFOUND
;
4410 __ns_ldap_getServiceAuthMethods(const char *service
,
4412 ns_ldap_error_t
**errorp
)
4414 char errstr
[MAXERROR
];
4415 int rc
, i
, done
= 0;
4418 char **sam
, *srv
, *send
;
4419 ns_auth_t
**authpp
= NULL
, *ap
;
4422 ns_ldap_error_t
*error
= NULL
;
4425 return (NS_LDAP_INVALID_PARAM
);
4428 if ((service
== NULL
) || (service
[0] == '\0') ||
4430 return (NS_LDAP_INVALID_PARAM
);
4433 rc
= __ns_ldap_getParam(NS_LDAP_SERVICE_AUTH_METHOD_P
, ¶m
, &error
);
4434 if (rc
!= NS_LDAP_SUCCESS
|| param
== NULL
) {
4438 sam
= (char **)param
;
4440 cfg
= __s_api_get_default_config();
4443 slen
= strlen(service
);
4445 for (; *sam
; sam
++) {
4447 if (strncasecmp(service
, srv
, slen
) != 0)
4450 if (*srv
!= COLONTOK
)
4454 for (max
= 1; (send
= strchr(++send
, SEMITOK
)) != NULL
;
4456 authpp
= (ns_auth_t
**)calloc(++max
, sizeof (ns_auth_t
*));
4457 if (authpp
== NULL
) {
4458 (void) __ns_ldap_freeParam(¶m
);
4459 __s_api_release_config(cfg
);
4460 return (NS_LDAP_MEMORY
);
4463 send
= strchr(srv
, SEMITOK
);
4468 i
= __s_get_enum_value(cfg
, srv
, NS_LDAP_AUTH_P
);
4470 (void) __ns_ldap_freeParam(¶m
);
4471 (void) sprintf(errstr
,
4472 gettext("Unsupported "
4473 "serviceAuthenticationMethod: %s.\n"), srv
);
4474 MKERROR(LOG_WARNING
, *errorp
, NS_CONFIG_SYNTAX
,
4476 __s_api_release_config(cfg
);
4477 return (NS_LDAP_CONFIG
);
4479 ap
= __s_api_AuthEnumtoStruct((EnumAuthType_t
)i
);
4481 (void) __ns_ldap_freeParam(¶m
);
4482 __s_api_release_config(cfg
);
4483 return (NS_LDAP_MEMORY
);
4494 (void) __ns_ldap_freeParam(¶m
);
4495 __s_api_release_config(cfg
);
4496 return (NS_LDAP_SUCCESS
);
4500 * This routine is called when certain scenario occurs
4502 * service == auto_home
4503 * SSD = automount: ou = mytest,
4504 * NS_LDAP_MAPATTRIBUTE= auto_home: automountMapName=AAA
4505 * NS_LDAP_OBJECTCLASSMAP= auto_home:automountMap=MynisMap
4506 * NS_LDAP_OBJECTCLASSMAP= auto_home:automount=MynisObject
4508 * The automountMapName is prepended implicitely but is mapped
4509 * to AAA. So dn could appers as
4510 * dn: AAA=auto_home,ou=bar,dc=foo,dc=com
4511 * dn: automountKey=user_01,AAA=auto_home,ou=bar,dc=foo,dc=com
4512 * dn: automountKey=user_02,AAA=auto_home,ou=bar,dc=foo,dc=com
4514 * This function is called to covert the mapped attr back to
4515 * orig attr when the entries are searched and returned
4519 __s_api_convert_automountmapname(const char *service
, char **dn
,
4520 ns_ldap_error_t
**errp
) {
4522 char **mapping
= NULL
;
4523 char *mapped_attr
= NULL
;
4524 char *automountmapname
= "automountMapName";
4525 char *buffer
= NULL
;
4526 int rc
= NS_LDAP_SUCCESS
;
4527 char errstr
[MAXERROR
];
4530 * dn is an input/out parameter, check it first
4533 if (service
== NULL
|| dn
== NULL
|| *dn
== NULL
)
4534 return (NS_LDAP_INVALID_PARAM
);
4537 * Check to see if there is a mapped attribute for auto_xxx
4540 mapping
= __ns_ldap_getMappedAttributes(service
, automountmapname
);
4543 * if no mapped attribute for auto_xxx, try automount
4546 if (mapping
== NULL
)
4547 mapping
= __ns_ldap_getMappedAttributes(
4548 "automount", automountmapname
);
4551 * if no mapped attribute is found, return SUCCESS (no op)
4554 if (mapping
== NULL
)
4555 return (NS_LDAP_SUCCESS
);
4558 * if the mapped attribute is found and attr is not empty,
4562 if (mapping
[0] != NULL
) {
4563 mapped_attr
= strdup(mapping
[0]);
4564 __s_api_free2dArray(mapping
);
4565 if (mapped_attr
== NULL
) {
4566 return (NS_LDAP_MEMORY
);
4569 __s_api_free2dArray(mapping
);
4571 (void) snprintf(errstr
, (2 * MAXERROR
),
4573 "Attribute nisMapName is mapped to an "
4574 "empty string.\n"));
4576 MKERROR(LOG_ERR
, *errp
, NS_CONFIG_SYNTAX
,
4579 return (NS_LDAP_CONFIG
);
4583 * Locate the mapped attribute in the dn
4584 * and replace it if it exists
4587 rc
= __s_api_replace_mapped_attr_in_dn(
4588 (const char *) automountmapname
, (const char *) mapped_attr
,
4589 (const char *) *dn
, &buffer
);
4596 * If mapped attr is found(buffer != NULL)
4597 * a new dn is returned
4598 * If no mapped attribute is in dn,
4599 * return NS_LDAP_SUCCESS (no op)
4601 * return NS_LDAP_MEMORY (no op)
4604 if (buffer
!= NULL
) {
4613 * If the mapped attr is found in the dn,
4614 * return NS_LDAP_SUCCESS and a new_dn.
4615 * If no mapped attr is found,
4616 * return NS_LDAP_SUCCESS and *new_dn == NULL
4617 * If there is not enough memory,
4618 * return NS_LDAP_MEMORY and *new_dn == NULL
4622 __s_api_replace_mapped_attr_in_dn(
4623 const char *orig_attr
, const char *mapped_attr
,
4624 const char *dn
, char **new_dn
) {
4626 char **dnArray
= NULL
;
4627 char *cur
= NULL
, *start
= NULL
;
4628 int i
= 0, found
= 0;
4629 int len
= 0, orig_len
= 0, mapped_len
= 0;
4630 int dn_len
= 0, tmp_len
= 0;
4635 * seperate dn into individual componets
4637 * "automountKey=user_01" , "automountMapName_test=auto_home", ...
4639 dnArray
= ldap_explode_dn(dn
, 0);
4642 * This will find "mapped attr=value" in dn.
4643 * It won't find match if mapped attr appears
4646 for (i
= 0; dnArray
[i
] != NULL
; i
++) {
4648 * This function is called when reading from
4649 * the directory so assume each component has "=".
4650 * Any ill formatted dn should be rejected
4651 * before adding to the directory
4653 cur
= strchr(dnArray
[i
], '=');
4655 if (strcasecmp(mapped_attr
, dnArray
[i
]) == 0)
4662 __s_api_free2dArray(dnArray
);
4664 return (NS_LDAP_SUCCESS
);
4667 * The new length is *dn length + (difference between
4668 * orig attr and mapped attr) + 1 ;
4670 * automountKey=aa,automountMapName_test=auto_home,dc=foo,dc=com
4672 * automountKey=aa,automountMapName=auto_home,dc=foo,dc=com
4674 mapped_len
= strlen(mapped_attr
);
4675 orig_len
= strlen(orig_attr
);
4676 dn_len
= strlen(dn
);
4677 len
= dn_len
+ orig_len
- mapped_len
+ 1;
4678 *new_dn
= (char *)calloc(1, len
);
4679 if (*new_dn
== NULL
) {
4680 __s_api_free2dArray(dnArray
);
4681 return (NS_LDAP_MEMORY
);
4685 * Locate the mapped attr in the dn.
4686 * Use dnArray[i] instead of mapped_attr
4687 * because mapped_attr could appear in
4691 cur
= strstr(dn
, dnArray
[i
]);
4692 __s_api_free2dArray(dnArray
);
4693 /* copy the portion before mapped attr in dn */
4696 (void) memcpy((void *) start
, (const void*) dn
, tmp_len
);
4699 * Copy the orig_attr. e.g. automountMapName
4700 * This replaces mapped attr with orig attr
4702 start
= start
+ (cur
- dn
); /* move cursor in buffer */
4703 (void) memcpy((void *) start
, (const void*) orig_attr
, orig_len
);
4706 * Copy the portion after mapped attr in dn
4708 cur
= cur
+ mapped_len
; /* move cursor in dn */
4709 start
= start
+ orig_len
; /* move cursor in buffer */
4710 (void) strcpy(start
, cur
);
4712 return (NS_LDAP_SUCCESS
);
4716 * Validate Filter functions
4719 /* ***** Start of modified libldap.so.5 filter parser ***** */
4721 /* filter parsing routine forward references */
4722 static int adj_filter_list(char *str
);
4723 static int adj_simple_filter(char *str
);
4724 static int unescape_filterval(char *val
);
4725 static int hexchar2int(char c
);
4726 static int adj_substring_filter(char *val
);
4730 * assumes string manipulation is in-line
4731 * and all strings are sufficient in size
4732 * return value is the position after 'c'
4736 resync_str(char *str
, char *next
, char c
)
4740 ret
= str
+ strlen(str
);
4744 (void) strcat(str
, next
);
4749 find_right_paren(char *s
)
4751 int balance
, escape
;
4755 while (*s
&& balance
) {
4762 if (*s
== '\\' && ! escape
)
4770 return (*s
? s
: NULL
);
4774 adj_complex_filter(char *str
)
4779 * We have (x(filter)...) with str sitting on
4780 * the x. We have to find the paren matching
4781 * the one before the x and put the intervening
4782 * filters by calling adj_filter_list().
4786 if ((next
= find_right_paren(str
)) == NULL
)
4790 if (adj_filter_list(str
) == -1)
4792 next
= resync_str(str
, next
, ')');
4799 adj_filter(char *str
)
4802 int parens
, balance
, escape
;
4813 if ((str
= adj_complex_filter(str
)) == NULL
)
4820 if ((str
= adj_complex_filter(str
)) == NULL
)
4827 if ((str
= adj_complex_filter(str
)) == NULL
)
4834 /* illegal ((case - generated by conversion */
4836 /* find missing close) */
4837 np
= find_right_paren(str
+1);
4839 /* error if not found */
4843 /* remove redundant (and) */
4844 for (dp
= str
, cp
= str
+1; cp
< np
; ) {
4852 /* re-start test at original ( */
4861 while (*next
&& balance
) {
4865 else if (*next
== ')')
4868 if (*next
== '\\' && ! escape
)
4879 if (adj_simple_filter(str
) == -1) {
4882 next
= resync_str(str
, next
, ')');
4899 default: /* assume it's a simple type=value filter */
4900 next
= strchr(str
, '\0');
4901 if (adj_simple_filter(str
) == -1) {
4909 return (parens
? -1 : 0);
4914 * Put a list of filters like this "(filter1)(filter2)..."
4918 adj_filter_list(char *str
)
4924 while (*str
&& isspace(*str
))
4929 if ((next
= find_right_paren(str
+ 1)) == NULL
)
4933 /* now we have "(filter)" with str pointing to it */
4935 if (adj_filter(str
) == -1)
4937 next
= resync_str(str
, next
, save
);
4947 * is_valid_attr - returns 1 if a is a syntactically valid left-hand side
4948 * of a filter expression, 0 otherwise. A valid string may contain only
4949 * letters, numbers, hyphens, semi-colons, colons and periods. examples:
4952 * 1.2.3.4;binary;dynamic
4956 * For compatibility with older servers, we also allow underscores in
4957 * attribute types, even through they are not allowed by the LDAPv3 RFCs.
4960 is_valid_attr(char *a
)
4965 } else if (!isalnum(*a
)) {
4990 if (hexchar2int(s
[0]) >= 0 && hexchar2int(s
[1]) >= 0)
5000 adj_simple_filter(char *str
)
5002 char *s
, *s2
, *s3
, filterop
;
5007 rc
= -1; /* pessimistic */
5009 if ((str
= strdup(str
)) == NULL
) {
5013 if ((s
= strchr(str
, '=')) == NULL
) {
5014 goto free_and_return
;
5019 if (filterop
== '<' || filterop
== '>' || filterop
== '~' ||
5024 if (! is_valid_attr(str
)) {
5025 goto free_and_return
;
5029 case '<': /* LDAP_FILTER_LE */
5030 case '>': /* LDAP_FILTER_GE */
5031 case '~': /* LDAP_FILTER_APPROX */
5033 case ':': /* extended filter - v3 only */
5035 * extended filter looks like this:
5037 * [type][':dn'][':'oid]':='value
5039 * where one of type or :oid is required.
5043 if ((s2
= strrchr(str
, ':')) == NULL
) {
5044 goto free_and_return
;
5046 if (strcasecmp(s2
, ":dn") == 0) {
5050 if ((s3
= strrchr(str
, ':')) != NULL
) {
5051 if (strcasecmp(s3
, ":dn") != 0) {
5052 goto free_and_return
;
5057 if (unescape_filterval(value
) < 0) {
5058 goto free_and_return
;
5061 goto free_and_return
;
5064 if (find_star(value
) == NULL
) {
5065 ftype
= 0; /* LDAP_FILTER_EQUALITY */
5066 } else if (strcmp(value
, "*") == 0) {
5067 ftype
= 1; /* LDAP_FILTER_PRESENT */
5069 rc
= adj_substring_filter(value
);
5070 goto free_and_return
;
5075 if (ftype
!= 0) { /* == LDAP_FILTER_PRESENT */
5077 } else if (unescape_filterval(value
) >= 0) {
5091 * Check in place both LDAPv2 (RFC-1960) and LDAPv3 (hexadecimal) escape
5092 * sequences within the null-terminated string 'val'.
5094 * If 'val' contains invalid escape sequences we return -1.
5095 * Otherwise return 1
5098 unescape_filterval(char *val
)
5100 int escape
, firstdigit
;
5105 for (s
= val
; *s
; s
++) {
5108 * first try LDAPv3 escape (hexadecimal) sequence
5110 if (hexchar2int(*s
) < 0) {
5113 * LDAPv2 (RFC1960) escape sequence
5126 } else if (*s
!= '\\') {
5140 * convert character 'c' that represents a hexadecimal digit to an integer.
5141 * if 'c' is not a hexidecimal digit [0-9A-Fa-f], -1 is returned.
5142 * otherwise the converted value is returned.
5147 if (c
>= '0' && c
<= '9') {
5150 if (c
>= 'A' && c
<= 'F') {
5151 return (c
- 'A' + 10);
5153 if (c
>= 'a' && c
<= 'f') {
5154 return (c
- 'a' + 10);
5160 adj_substring_filter(char *val
)
5164 for (; val
!= NULL
; val
= nextstar
) {
5165 if ((nextstar
= find_star(val
)) != NULL
) {
5170 if (unescape_filterval(val
) < 0) {
5179 /* ***** End of modified libldap.so.5 filter parser ***** */
5183 * Walk filter, remove redundant parentheses in-line
5184 * verify that the filter is reasonable
5187 validate_filter(ns_ldap_cookie_t
*cookie
)
5189 char *filter
= cookie
->filter
;
5192 /* Parse filter looking for illegal values */
5194 rc
= adj_filter(filter
);
5196 return (NS_LDAP_OP_FAILED
);
5199 /* end of filter checking */
5201 return (NS_LDAP_SUCCESS
);
5205 * Set the account management request control that needs to be sent to server.
5206 * This control is required to get the account management information of
5207 * a user to do local account checking.
5210 setup_acctmgmt_params(ns_ldap_cookie_t
*cookie
)
5212 LDAPControl
*req
= NULL
, **requestctrls
;
5214 req
= (LDAPControl
*)malloc(sizeof (LDAPControl
));
5217 return (NS_LDAP_MEMORY
);
5219 /* fill in the fields of this new control */
5220 req
->ldctl_iscritical
= 1;
5221 req
->ldctl_oid
= strdup(NS_LDAP_ACCOUNT_USABLE_CONTROL
);
5222 if (req
->ldctl_oid
== NULL
) {
5224 return (NS_LDAP_MEMORY
);
5226 req
->ldctl_value
.bv_len
= 0;
5227 req
->ldctl_value
.bv_val
= NULL
;
5229 requestctrls
= (LDAPControl
**)calloc(2, sizeof (LDAPControl
*));
5230 if (requestctrls
== NULL
) {
5231 ldap_control_free(req
);
5232 return (NS_LDAP_MEMORY
);
5235 requestctrls
[0] = req
;
5237 cookie
->p_serverctrls
= requestctrls
;
5239 return (NS_LDAP_SUCCESS
);
5243 * int get_new_acct_more_info(BerElement *ber,
5244 * AcctUsableResponse_t *acctResp)
5246 * Decode the more_info data from an Account Management control response,
5247 * when the account is not usable and when code style is from recent LDAP
5248 * servers (see below comments for parse_acct_cont_resp_msg() to get more
5249 * details on coding styles and ASN1 description).
5251 * Expected BER encoding: {tbtbtbtiti}
5253 * +b: TRUE if inactive due to account inactivation
5255 * +b: TRUE if password has been reset
5257 * +b: TRUE if password is expired
5259 * +i: contains num of remaining grace, 0 means no grace
5261 * +i: contains num of seconds before auto-unlock. -1 means acct is locked
5262 * forever (i.e. until reset)
5266 * - acctResp is not null and is initialized with default values for the
5267 * fields in its AcctUsableResp.more_info structure
5268 * - the ber stream is received in the correct order, per the ASN1 description.
5269 * We do not check this order and make the asumption that it is correct.
5270 * Note that the ber stream may not (and will not in most cases) contain
5274 get_new_acct_more_info(BerElement
*ber
, AcctUsableResponse_t
*acctResp
)
5276 int rc
= NS_LDAP_SUCCESS
;
5277 char errstr
[MAXERROR
];
5278 ber_tag_t rTag
= LBER_DEFAULT
;
5285 * Look at what more_info BER element is/are left to be decoded.
5286 * look at each of them 1 by 1, without checking on their order
5287 * and possible multi values.
5289 for (rTag
= ber_first_element(ber
, &rLen
, &last
);
5290 rTag
!= LBER_END_OF_SEQORSET
;
5291 rTag
= ber_next_element(ber
, &rLen
, last
)) {
5295 case 0 | LBER_CLASS_CONTEXT
| LBER_PRIMITIVE
:
5297 berRC
= ber_scanf(ber
, "b", &rValue
);
5298 if (berRC
!= LBER_ERROR
) {
5299 (acctResp
->AcctUsableResp
).more_info
.
5300 inactive
= (rValue
!= 0) ? 1 : 0;
5304 case 1 | LBER_CLASS_CONTEXT
| LBER_PRIMITIVE
:
5306 berRC
= ber_scanf(ber
, "b", &rValue
);
5307 if (berRC
!= LBER_ERROR
) {
5308 (acctResp
->AcctUsableResp
).more_info
.reset
5309 = (rValue
!= 0) ? 1 : 0;
5313 case 2 | LBER_CLASS_CONTEXT
| LBER_PRIMITIVE
:
5315 berRC
= ber_scanf(ber
, "b", &rValue
);
5316 if (berRC
!= LBER_ERROR
) {
5317 (acctResp
->AcctUsableResp
).more_info
.expired
5318 = (rValue
!= 0) ? 1 : 0;
5322 case 3 | LBER_CLASS_CONTEXT
| LBER_PRIMITIVE
:
5323 /* remaining grace */
5324 berRC
= ber_scanf(ber
, "i", &rValue
);
5325 if (berRC
!= LBER_ERROR
) {
5326 (acctResp
->AcctUsableResp
).more_info
.rem_grace
5331 case 4 | LBER_CLASS_CONTEXT
| LBER_PRIMITIVE
:
5332 /* seconds before unlock */
5333 berRC
= ber_scanf(ber
, "i", &rValue
);
5334 if (berRC
!= LBER_ERROR
) {
5335 (acctResp
->AcctUsableResp
).more_info
.
5336 sec_b4_unlock
= rValue
;
5341 (void) sprintf(errstr
,
5342 gettext("invalid reason tag 0x%x"), rTag
);
5343 syslog(LOG_DEBUG
, "libsldap: %s", errstr
);
5344 rc
= NS_LDAP_INTERNAL
;
5347 if (berRC
== LBER_ERROR
) {
5348 (void) sprintf(errstr
,
5349 gettext("error 0x%x decoding value for "
5350 "tag 0x%x"), berRC
, rTag
);
5351 syslog(LOG_DEBUG
, "libsldap: %s", errstr
);
5352 rc
= NS_LDAP_INTERNAL
;
5354 if (rc
!= NS_LDAP_SUCCESS
) {
5355 /* exit the for loop */
5364 * int get_old_acct_opt_more_info(BerElement *ber,
5365 * AcctUsableResponse_t *acctResp)
5367 * Decode the optional more_info data from an Account Management control
5368 * response, when the account is not usable and when code style is from LDAP
5369 * server 5.2p4 (see below comments for parse_acct_cont_resp_msg() to get more
5370 * details on coding styles and ASN1 description).
5372 * Expected BER encoding: titi}
5374 * +i: contains num of remaining grace, 0 means no grace
5376 * +i: contains num of seconds before auto-unlock. -1 means acct is locked
5377 * forever (i.e. until reset)
5380 * - ber is a valid BER element
5381 * - acctResp is initialized for the fields in its AcctUsableResp.more_info
5385 get_old_acct_opt_more_info(ber_tag_t tag
, BerElement
*ber
,
5386 AcctUsableResponse_t
*acctResp
)
5388 int rc
= NS_LDAP_SUCCESS
;
5389 char errstr
[MAXERROR
];
5391 int rem_grace
, sec_b4_unlock
;
5395 /* decode and maybe 3 is following */
5396 if ((tag
= ber_scanf(ber
, "i", &rem_grace
)) == LBER_ERROR
) {
5397 (void) sprintf(errstr
, gettext("Can not get "
5399 syslog(LOG_DEBUG
, "libsldap: %s", errstr
);
5400 rc
= NS_LDAP_INTERNAL
;
5403 (acctResp
->AcctUsableResp
).more_info
.rem_grace
= rem_grace
;
5405 if ((tag
= ber_peek_tag(ber
, &len
)) == LBER_ERROR
) {
5406 /* this is a success case, break to exit */
5407 (void) sprintf(errstr
, gettext("No more "
5409 syslog(LOG_DEBUG
, "libsldap: %s", errstr
);
5414 if (ber_scanf(ber
, "i", &sec_b4_unlock
) == LBER_ERROR
) {
5415 (void) sprintf(errstr
,
5416 gettext("Can not get sec_b4_unlock "
5418 syslog(LOG_DEBUG
, "libsldap: %s", errstr
);
5419 rc
= NS_LDAP_INTERNAL
;
5422 (acctResp
->AcctUsableResp
).more_info
.sec_b4_unlock
=
5424 } else { /* unknown tag */
5425 (void) sprintf(errstr
, gettext("Unknown tag "
5427 syslog(LOG_DEBUG
, "libsldap: %s", errstr
);
5428 rc
= NS_LDAP_INTERNAL
;
5434 if (ber_scanf(ber
, "i", &sec_b4_unlock
) == LBER_ERROR
) {
5435 (void) sprintf(errstr
, gettext("Can not get "
5436 "sec_b4_unlock - 2nd case"));
5437 syslog(LOG_DEBUG
, "libsldap: %s", errstr
);
5438 rc
= NS_LDAP_INTERNAL
;
5441 (acctResp
->AcctUsableResp
).more_info
.sec_b4_unlock
=
5445 default: /* unknown tag */
5446 (void) sprintf(errstr
, gettext("Unknown tag - 2nd case"));
5447 syslog(LOG_DEBUG
, "libsldap: %s", errstr
);
5448 rc
= NS_LDAP_INTERNAL
;
5456 * **** This function needs to be moved to libldap library ****
5457 * parse_acct_cont_resp_msg() parses the message received by server according to
5458 * following format (ASN1 notation):
5460 * ACCOUNT_USABLE_RESPONSE::= CHOICE {
5461 * is_available [0] INTEGER,
5462 * ** seconds before expiration **
5463 * is_not_available [1] more_info
5465 * more_info::= SEQUENCE {
5466 * inactive [0] BOOLEAN DEFAULT FALSE,
5467 * reset [1] BOOLEAN DEFAULT FALSE,
5468 * expired [2] BOOLEAN DEFAULT FALSE,
5469 * remaining_grace [3] INTEGER OPTIONAL,
5470 * seconds_before_unlock [4] INTEGER OPTIONAL
5474 * #define used to make the difference between coding style as done
5475 * by LDAP server 5.2p4 and newer LDAP servers. There are 4 values:
5476 * - DS52p4_USABLE: 5.2p4 coding style, account is usable
5477 * - DS52p4_NOT_USABLE: 5.2p4 coding style, account is not usable
5478 * - NEW_USABLE: newer LDAP servers coding style, account is usable
5479 * - NEW_NOT_USABLE: newer LDAP servers coding style, account is not usable
5481 * An account would be considered not usable if for instance:
5482 * - it's been made inactive in the LDAP server
5483 * - or its password was reset in the LDAP server database
5484 * - or its password expired
5485 * - or the account has been locked, possibly forever
5487 #define DS52p4_USABLE 0x00
5488 #define DS52p4_NOT_USABLE 0x01
5489 #define NEW_USABLE 0x00 | LBER_CLASS_CONTEXT | LBER_PRIMITIVE
5490 #define NEW_NOT_USABLE 0x01 | LBER_CLASS_CONTEXT | LBER_CONSTRUCTED
5492 parse_acct_cont_resp_msg(LDAPControl
**ectrls
, AcctUsableResponse_t
*acctResp
)
5494 int rc
= NS_LDAP_SUCCESS
;
5499 char errstr
[MAXERROR
];
5500 /* used for any coding style when account is usable */
5501 int seconds_before_expiry
;
5502 /* used for 5.2p4 coding style when account is not usable */
5503 int inactive
, reset
, expired
;
5505 if (ectrls
== NULL
) {
5506 (void) sprintf(errstr
, gettext("Invalid ectrls parameter"));
5507 syslog(LOG_DEBUG
, "libsldap: %s", errstr
);
5508 return (NS_LDAP_INVALID_PARAM
);
5511 for (i
= 0; ectrls
[i
] != NULL
; i
++) {
5512 if (strcmp(ectrls
[i
]->ldctl_oid
, NS_LDAP_ACCOUNT_USABLE_CONTROL
)
5518 if (ectrls
[i
] == NULL
) {
5519 /* Ldap control is not found */
5520 (void) sprintf(errstr
, gettext("Account Usable Control "
5522 syslog(LOG_DEBUG
, "libsldap: %s", errstr
);
5523 return (NS_LDAP_NOTFOUND
);
5526 /* Allocate a BER element from the control value and parse it. */
5527 if ((ber
= ber_init(&ectrls
[i
]->ldctl_value
)) == NULL
)
5528 return (NS_LDAP_MEMORY
);
5530 if ((tag
= ber_peek_tag(ber
, &len
)) == LBER_ERROR
) {
5531 /* Ldap decoding error */
5532 (void) sprintf(errstr
, gettext("Error decoding 1st tag"));
5533 syslog(LOG_DEBUG
, "libsldap: %s", errstr
);
5535 return (NS_LDAP_INTERNAL
);
5541 acctResp
->choice
= 0;
5542 if (ber_scanf(ber
, "i", &seconds_before_expiry
)
5544 /* Ldap decoding error */
5545 (void) sprintf(errstr
, gettext("Can not get "
5546 "seconds_before_expiry"));
5547 syslog(LOG_DEBUG
, "libsldap: %s", errstr
);
5548 rc
= NS_LDAP_INTERNAL
;
5551 /* ber_scanf() succeeded */
5552 (acctResp
->AcctUsableResp
).seconds_before_expiry
=
5553 seconds_before_expiry
;
5556 case DS52p4_NOT_USABLE
:
5557 acctResp
->choice
= 1;
5558 if (ber_scanf(ber
, "{bbb", &inactive
, &reset
, &expired
)
5560 /* Ldap decoding error */
5561 (void) sprintf(errstr
, gettext("Can not get "
5562 "inactive/reset/expired"));
5563 syslog(LOG_DEBUG
, "libsldap: %s", errstr
);
5564 rc
= NS_LDAP_INTERNAL
;
5567 /* ber_scanf() succeeded */
5568 (acctResp
->AcctUsableResp
).more_info
.inactive
=
5569 ((inactive
== 0) ? 0 : 1);
5570 (acctResp
->AcctUsableResp
).more_info
.reset
=
5571 ((reset
== 0) ? 0 : 1);
5572 (acctResp
->AcctUsableResp
).more_info
.expired
=
5573 ((expired
== 0) ? 0 : 1);
5574 (acctResp
->AcctUsableResp
).more_info
.rem_grace
= 0;
5575 (acctResp
->AcctUsableResp
).more_info
.sec_b4_unlock
= 0;
5577 if ((tag
= ber_peek_tag(ber
, &len
)) == LBER_ERROR
) {
5578 /* this is a success case, break to exit */
5579 (void) sprintf(errstr
, gettext("No optional data"));
5580 syslog(LOG_DEBUG
, "libsldap: %s", errstr
);
5585 * Look at what optional more_info BER element is/are
5586 * left to be decoded.
5588 rc
= get_old_acct_opt_more_info(tag
, ber
, acctResp
);
5591 case NEW_NOT_USABLE
:
5592 acctResp
->choice
= 1;
5594 * Recent LDAP servers won't code more_info data for default
5595 * values (see above comments on ASN1 description for what
5596 * fields have default values & what fields are optional).
5598 (acctResp
->AcctUsableResp
).more_info
.inactive
= 0;
5599 (acctResp
->AcctUsableResp
).more_info
.reset
= 0;
5600 (acctResp
->AcctUsableResp
).more_info
.expired
= 0;
5601 (acctResp
->AcctUsableResp
).more_info
.rem_grace
= 0;
5602 (acctResp
->AcctUsableResp
).more_info
.sec_b4_unlock
= 0;
5606 * Nothing else to decode; this is valid and we
5607 * use default values set above.
5609 (void) sprintf(errstr
, gettext("more_info is "
5610 "empty, using default values"));
5611 syslog(LOG_DEBUG
, "libsldap: %s", errstr
);
5616 * Look at what more_info BER element is/are left to
5619 rc
= get_new_acct_more_info(ber
, acctResp
);
5623 (void) sprintf(errstr
, gettext("unknwon coding style "
5624 "(tag: 0x%x)"), tag
);
5625 syslog(LOG_DEBUG
, "libsldap: %s", errstr
);
5626 rc
= NS_LDAP_INTERNAL
;
5635 * internal function for __ns_ldap_getAcctMgmt()
5638 getAcctMgmt(const char *user
, AcctUsableResponse_t
*acctResp
,
5639 ns_conn_user_t
*conn_user
)
5642 char ldapfilter
[1024];
5643 ns_ldap_cookie_t
*cookie
;
5644 ns_ldap_search_desc_t
**sdlist
= NULL
;
5645 ns_ldap_search_desc_t
*dptr
;
5646 ns_ldap_error_t
*error
= NULL
;
5648 char service
[] = "shadow";
5650 if (user
== NULL
|| acctResp
== NULL
)
5651 return (NS_LDAP_INVALID_PARAM
);
5653 /* Initialize State machine cookie */
5654 cookie
= init_search_state_machine();
5656 return (NS_LDAP_MEMORY
);
5657 cookie
->conn_user
= conn_user
;
5659 /* see if need to follow referrals */
5660 rc
= __s_api_toFollowReferrals(0,
5661 &cookie
->followRef
, &error
);
5662 if (rc
!= NS_LDAP_SUCCESS
) {
5663 (void) __ns_ldap_freeError(&error
);
5667 /* get the service descriptor - or create a default one */
5668 rc
= __s_api_get_SSD_from_SSDtoUse_service(service
,
5670 if (rc
!= NS_LDAP_SUCCESS
) {
5671 (void) __ns_ldap_freeError(&error
);
5675 if (sdlist
== NULL
) {
5676 /* Create default service Desc */
5677 sdlist
= (ns_ldap_search_desc_t
**)calloc(2,
5678 sizeof (ns_ldap_search_desc_t
*));
5679 if (sdlist
== NULL
) {
5680 rc
= NS_LDAP_MEMORY
;
5683 dptr
= (ns_ldap_search_desc_t
*)
5684 calloc(1, sizeof (ns_ldap_search_desc_t
));
5687 rc
= NS_LDAP_MEMORY
;
5693 rc
= __s_api_getDNs(&dns
, service
, &cookie
->errorp
);
5694 if (rc
!= NS_LDAP_SUCCESS
) {
5696 __s_api_free2dArray(dns
);
5699 (void) __ns_ldap_freeError(&(cookie
->errorp
));
5700 cookie
->errorp
= NULL
;
5703 dptr
->basedn
= strdup(dns
[0]);
5704 if (dptr
->basedn
== NULL
) {
5708 __s_api_free2dArray(dns
);
5711 rc
= NS_LDAP_MEMORY
;
5714 __s_api_free2dArray(dns
);
5719 rc
= __s_api_getSearchScope(&scope
, &cookie
->errorp
);
5720 dptr
->scope
= scope
;
5723 cookie
->sdlist
= sdlist
;
5725 cookie
->service
= strdup(service
);
5726 if (cookie
->service
== NULL
) {
5727 rc
= NS_LDAP_MEMORY
;
5731 /* search for entries for this particular uid */
5732 (void) snprintf(ldapfilter
, sizeof (ldapfilter
), "(uid=%s)", user
);
5733 cookie
->i_filter
= strdup(ldapfilter
);
5734 if (cookie
->i_filter
== NULL
) {
5735 rc
= NS_LDAP_MEMORY
;
5739 /* create the control request */
5740 if ((rc
= setup_acctmgmt_params(cookie
)) != NS_LDAP_SUCCESS
)
5743 /* Process search */
5744 rc
= search_state_machine(cookie
, GET_ACCT_MGMT_INFO
, 0);
5746 /* Copy results back to user */
5747 rc
= cookie
->err_rc
;
5748 if (rc
!= NS_LDAP_SUCCESS
)
5749 (void) __ns_ldap_freeError(&(cookie
->errorp
));
5751 if (cookie
->result
== NULL
)
5754 if ((rc
= parse_acct_cont_resp_msg(cookie
->resultctrl
, acctResp
))
5758 rc
= NS_LDAP_SUCCESS
;
5761 delete_search_cookie(cookie
);
5767 * __ns_ldap_getAcctMgmt() is called from pam account management stack
5768 * for retrieving accounting information of users with no user password -
5769 * eg. rlogin, rsh, etc. This function uses the account management control
5770 * request to do a search on the server for the user in question. The
5771 * response control returned from the server is got from the cookie.
5772 * Input params: username of whose account mgmt information is to be got
5773 * pointer to hold the parsed account management information
5774 * Return values: NS_LDAP_SUCCESS on success or appropriate error
5778 __ns_ldap_getAcctMgmt(const char *user
, AcctUsableResponse_t
*acctResp
)
5780 ns_conn_user_t
*cu
= NULL
;
5782 int rc
= NS_LDAP_SUCCESS
;
5783 ns_ldap_error_t
*error
= NULL
;
5786 if (__s_api_setup_retry_search(&cu
, NS_CONN_USER_SEARCH
,
5787 &try_cnt
, &rc
, &error
) == 0)
5789 rc
= getAcctMgmt(user
, acctResp
, cu
);