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 2015 Gary Mills
23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
33 #include "ldap_util.h"
34 #include "ldap_structs.h"
35 #include "ldap_ruleval.h"
36 #include "ldap_attr.h"
37 #include "ldap_print.h"
38 #include "ldap_glob.h"
40 #include "nis_parse_ldap_conf.h"
43 #define LDAPS_PORT 636
46 static int setupConList(char *serverList
, char *who
,
47 char *cred
, auth_method_t method
);
51 * Build one of our internal LDAP search structures, containing copies of
52 * the supplied input. return NULL in case of error.
54 * If 'filter' is NULL, build an AND-filter using the filter components.
57 buildLdapSearch(char *base
, int scope
, int numFilterComps
, char **filterComp
,
58 char *filter
, char **attrs
, int attrsonly
, int isDN
) {
59 __nis_ldap_search_t
*ls
;
62 char *myself
= "buildLdapSearch";
64 ls
= am(myself
, sizeof (*ls
));
68 ls
->base
= sdup(myself
, T
, base
);
69 if (ls
->base
== 0 && base
!= 0)
73 if (filterComp
!= 0 && numFilterComps
> 0) {
74 ls
->filterComp
= am(myself
, numFilterComps
*
75 sizeof (ls
->filterComp
[0]));
76 if (ls
->filterComp
== 0) {
80 for (i
= 0; i
< numFilterComps
; i
++) {
81 ls
->filterComp
[i
] = sdup(myself
, T
, filterComp
[i
]);
82 if (ls
->filterComp
[i
] == 0 && filterComp
[i
] != 0)
85 ls
->numFilterComps
= numFilterComps
;
87 ls
->filter
= concatenateFilterComps(ls
->numFilterComps
,
94 ls
->numFilterComps
= 0;
95 ls
->filter
= sdup(myself
, T
, filter
);
96 if (ls
->filter
== 0 && filter
!= 0)
101 for (na
= 0, a
= attrs
; *a
!= 0; a
++, na
++);
102 ls
->attrs
= am(myself
, (na
+ 1) * sizeof (ls
->attrs
[0]));
103 if (ls
->attrs
!= 0) {
104 for (i
= 0; i
< na
; i
++) {
105 ls
->attrs
[i
] = sdup(myself
, T
, attrs
[i
]);
106 if (ls
->attrs
[i
] == 0 && attrs
[i
] != 0)
119 ls
->attrsonly
= attrsonly
;
131 freeLdapSearch(__nis_ldap_search_t
*ls
) {
138 if (ls
->filterComp
!= 0) {
139 for (i
= 0; i
< ls
->numFilterComps
; i
++) {
140 sfree(ls
->filterComp
[i
]);
142 sfree(ls
->filterComp
);
145 if (ls
->attrs
!= 0) {
146 for (i
= 0; i
< ls
->numAttrs
; i
++) {
156 * Given a table mapping, and a rule/value pointer,
157 * return an LDAP search structure with values suitable for use
158 * by ldap_search() or (if dn != 0) ldap_modify(). The rule/value
161 * If dn != 0 and *dn == 0, the function attemps to return a pointer
162 * to the DN. This may necessitate an ldapSearch, if the rule set doesn't
163 * produce a DN directly.
165 * if dn == 0, and the rule set produces a DN as well as other attribute/
166 * value pairs, the function returns an LDAP search structure with the
169 * If 'fromLDAP' is set, the caller wants base/scope/filter from
170 * t->objectDN->read; otherwise, from t->objectDN->write.
172 * If 'rv' is NULL, the caller wants an enumeration of the container.
174 * Note that this function only creates a search structure for 't' itself;
175 * if there are alternative mappings for the table, those must be handled
178 __nis_ldap_search_t
*
179 createLdapRequest(__nis_table_mapping_t
*t
,
180 __nis_rule_value_t
*rv
, char **dn
, int fromLDAP
,
181 int *res
, __nis_object_dn_t
*obj_dn
) {
183 __nis_ldap_search_t
*ls
= 0;
185 int numLocDN
, stat
= 0, count
= 0;
186 char *myself
= "createLdapRequest";
187 __nis_object_dn_t
*objectDN
= NULL
;
193 objectDN
= t
->objectDN
;
202 base
= objectDN
->read
.base
;
203 filter
= makeFilter(objectDN
->read
.attrs
);
205 base
= objectDN
->write
.base
;
206 filter
= makeFilter(objectDN
->write
.attrs
);
209 /* Create request to enumerate container */
210 ls
= buildLdapSearch(base
, objectDN
->read
.scope
, 0, 0, filter
,
216 for (i
= 0; i
< t
->numRulesToLDAP
; i
++) {
217 rv
= addLdapRuleValue(t
, t
->ruleToLDAP
[i
],
218 mit_ldap
, mit_nisplus
, rv
, !fromLDAP
, &stat
);
221 if (stat
== NP_LDAP_RULES_NO_VALUE
)
227 * If none of the rules produced a value despite
228 * having enough NIS+ columns, return error.
230 if (rv
->numAttrs
== 0 && count
> 0) {
231 *res
= NP_LDAP_RULES_NO_VALUE
;
236 * 'rv' now contains everything we know about the attributes and
237 * values. Build an LDAP search structure from it.
240 /* Look for a single-valued DN */
241 locDN
= findDNs(myself
, rv
, 1,
242 fromLDAP
? objectDN
->read
.base
:
243 objectDN
->write
.base
,
245 if (locDN
!= 0 && numLocDN
== 1) {
246 if (dn
!= 0 && *dn
== 0) {
253 filter
= makeFilter(objectDN
->read
.attrs
);
255 filter
= makeFilter(objectDN
->write
.attrs
);
256 ls
= buildLdapSearch(locDN
[0], LDAP_SCOPE_BASE
, 0, 0,
259 freeDNs(locDN
, numLocDN
);
262 freeDNs(locDN
, numLocDN
);
271 * No DN, or caller wanted a search structure with the non-DN
275 /* Initialize search structure */
277 char *filter
= (fromLDAP
) ?
278 makeFilter(objectDN
->read
.attrs
) :
279 makeFilter(objectDN
->write
.attrs
);
283 ofc
= makeFilterComp(filter
, &nofc
);
285 if (filter
!= 0 && ofc
== 0) {
286 logmsg(MSG_NOTIMECHECK
, LOG_ERR
,
287 "%s: Unable to break filter into components: \"%s\"",
288 myself
, NIL(filter
));
294 ls
= buildLdapSearch(objectDN
->read
.base
,
295 objectDN
->read
.scope
,
296 nofc
, ofc
, 0, 0, 0, 0);
298 ls
= buildLdapSearch(objectDN
->write
.base
,
299 objectDN
->write
.scope
,
300 nofc
, ofc
, 0, 0, 0, 0);
302 freeFilterComp(ofc
, nofc
);
307 /* Build and add the filter components */
308 for (i
= 0; i
< rv
->numAttrs
; i
++) {
310 if (strcasecmp("dn", rv
->attrName
[i
]) == 0)
313 /* Skip vt_ber values */
314 if (rv
->attrVal
[i
].type
== vt_ber
)
317 for (j
= 0; j
< rv
->attrVal
[i
].numVals
; j
++) {
318 __nis_buffer_t b
= {0, 0};
321 bp2buf(myself
, &b
, "%s=%s",
322 rv
->attrName
[i
], rv
->attrVal
[i
].val
[j
].value
);
323 tmpComp
= addFilterComp(b
.buf
, ls
->filterComp
,
324 &ls
->numFilterComps
);
326 logmsg(MSG_NOTIMECHECK
, LOG_ERR
,
327 "%s: Unable to add filter component \"%s\"",
333 ls
->filterComp
= tmpComp
;
338 if (ls
->numFilterComps
> 0) {
340 ls
->filter
= concatenateFilterComps(ls
->numFilterComps
,
342 if (ls
->filter
== 0) {
343 logmsg(MSG_NOTIMECHECK
, LOG_ERR
,
344 "%s: Unable to concatenate filter components",
351 if (dn
!= 0 && *dn
== 0) {
353 * The caller wants a DN, but we didn't get one from the
354 * the rule set. We have an 'ls', so use it to ldapSearch()
355 * for an entry from which we can extract the DN.
357 __nis_rule_value_t
*rvtmp
;
359 int nv
= 0, numLocDN
;
361 rvtmp
= ldapSearch(ls
, &nv
, 0, 0);
362 locDN
= findDNs(myself
, rvtmp
, nv
, 0, &numLocDN
);
363 if (locDN
!= 0 && numLocDN
== 1) {
367 freeDNs(locDN
, numLocDN
);
369 freeRuleValue(rvtmp
, nv
);
376 int ldapConnAttemptRetryTimeout
= 60; /* seconds */
380 mutex_t mutex
; /* Mutex for update of structure */
381 pthread_t owner
; /* Thread holding mutex */
382 mutex_t rcMutex
; /* Mutex for refCount */
383 int refCount
; /* Reference count */
384 int isBound
; /* Is connection open and usable ? */
385 time_t retryTime
; /* When should open be retried */
386 int status
; /* Status of last operation */
387 int doDis
; /* To be disconnected if refCount==0 */
388 int doDel
; /* To be deleted if refCount zero */
389 int onList
; /* True if on the 'ldapCon' list */
390 char *sp
; /* server string */
393 auth_method_t method
;
395 struct timeval bindTimeout
;
396 struct timeval searchTimeout
;
397 struct timeval modifyTimeout
;
398 struct timeval addTimeout
;
399 struct timeval deleteTimeout
;
400 int simplePage
; /* Can do simple-page */
401 int vlv
; /* Can do VLV */
402 uint_t batchFrom
; /* # entries read in one operation */
407 * List of connections, 'ldapCon', protected by an RW lock.
409 * The following locking scheme is used:
411 * (1) Find a connection structure to use to talk to LDAP
421 * Release structure when done
422 * (2) Insert/delete structure(s) on/from list
424 * Insert/delete structure; if deleting, must
425 * acquire 'mutex', and 'rcMutex' (in that order),
426 * and 'refCount' must be zero.
428 * (3) Modify structure
431 * Modify (except refCount)
436 __nis_ldap_conn_t
*ldapCon
= 0;
437 __nis_ldap_conn_t
*ldapReferralCon
= 0;
438 static rwlock_t ldapConLock
= DEFAULTRWLOCK
;
439 static rwlock_t referralConLock
= DEFAULTRWLOCK
;
442 exclusiveLC(__nis_ldap_conn_t
*lc
) {
443 pthread_t me
= pthread_self();
449 stat
= mutex_trylock(&lc
->mutex
);
450 if (stat
== EBUSY
&& lc
->owner
!= me
)
451 mutex_lock(&lc
->mutex
);
456 /* Return 1 if mutex held by this thread, 0 otherwise */
458 assertExclusive(__nis_ldap_conn_t
*lc
) {
465 stat
= mutex_trylock(&lc
->mutex
);
468 mutex_unlock(&lc
->mutex
);
473 if (stat
!= EBUSY
|| lc
->owner
!= me
)
480 releaseLC(__nis_ldap_conn_t
*lc
) {
481 pthread_t me
= pthread_self();
483 if (lc
== 0 || lc
->owner
!= me
)
487 (void) mutex_unlock(&lc
->mutex
);
491 incrementRC(__nis_ldap_conn_t
*lc
) {
495 (void) mutex_lock(&lc
->rcMutex
);
497 (void) mutex_unlock(&lc
->rcMutex
);
501 decrementRC(__nis_ldap_conn_t
*lc
) {
505 (void) mutex_lock(&lc
->rcMutex
);
506 if (lc
->refCount
> 0)
508 (void) mutex_unlock(&lc
->rcMutex
);
511 /* Accept a server/port indication, and call ldap_init() */
513 ldapInit(char *srv
, int port
, bool_t use_ssl
) {
515 int ldapVersion
= LDAP_VERSION3
;
516 int derefOption
= LDAP_DEREF_ALWAYS
;
517 int timelimit
= proxyInfo
.search_time_limit
;
518 int sizelimit
= proxyInfo
.search_size_limit
;
524 ld
= ldapssl_init(srv
, port
, 1);
526 ld
= ldap_init(srv
, port
);
530 (void) ldap_set_option(ld
, LDAP_OPT_PROTOCOL_VERSION
,
532 (void) ldap_set_option(ld
, LDAP_OPT_DEREF
, &derefOption
);
533 (void) ldap_set_option(ld
, LDAP_OPT_REFERRALS
, LDAP_OPT_OFF
);
534 (void) ldap_set_option(ld
, LDAP_OPT_TIMELIMIT
, &timelimit
);
535 (void) ldap_set_option(ld
, LDAP_OPT_SIZELIMIT
, &sizelimit
);
536 (void) ldap_set_option(ld
, LDAP_OPT_REBIND_ARG
, 0);
543 * Bind the specified LDAP structure per the supplied authentication.
544 * Note: tested with none, simple, and digest_md5. May or may not
545 * work with other authentication methods, mostly depending on whether
546 * or not 'who' and 'cred' contain sufficient information.
549 ldapBind(LDAP
**ldP
, char *who
, char *cred
, auth_method_t method
,
550 struct timeval timeout
) {
553 char *myself
= "ldapBind";
555 if (ldP
== 0 || (ld
= *ldP
) == 0)
556 return (LDAP_PARAM_ERROR
);
558 if (method
== none
) {
559 /* No ldap_bind() required (or even possible) */
561 } else if (method
== simple
) {
563 LDAPMessage
*msg
= 0;
566 ret
= ldap_bind(ld
, who
, cred
, LDAP_AUTH_SIMPLE
);
568 ret
= ldap_result(ld
, ret
, 0, &tv
, &msg
);
571 } else if (ret
== -1) {
572 (void) ldap_get_option(ld
,
573 LDAP_OPT_ERROR_NUMBER
,
576 ret
= ldap_result2error(ld
, msg
, 0);
579 (void) ldap_msgfree(msg
);
581 (void) ldap_get_option(ld
, LDAP_OPT_ERROR_NUMBER
,
584 } else if (method
== cram_md5
) {
585 /* Note: there is only a synchronous call for cram-md5 */
586 struct berval ber_cred
;
588 ber_cred
.bv_len
= strlen(cred
);
589 ber_cred
.bv_val
= cred
;
590 ret
= ldap_sasl_cram_md5_bind_s(ld
, who
, &ber_cred
, NULL
, NULL
);
591 } else if (method
== digest_md5
) {
592 /* Note: there is only a synchronous call for digest-md5 */
593 struct berval ber_cred
;
595 ber_cred
.bv_len
= strlen(cred
);
596 ber_cred
.bv_val
= cred
;
597 ret
= ldap_x_sasl_digest_md5_bind_s(ld
, who
, &ber_cred
, NULL
,
600 ret
= LDAP_AUTH_METHOD_NOT_SUPPORTED
;
603 if (ret
!= LDAP_SUCCESS
) {
604 (void) ldap_unbind_s(ld
);
606 logmsg(MSG_NOTIMECHECK
, LOG_WARNING
,
607 "%s: Unable to bind as: %s: %s",
608 myself
, who
, ldap_err2string(ret
));
615 * Free 'lc' and all related memory. Caller must hold the exclusive lock.
616 * Return LDAP_UNAVAILABLE upon success, in which case the caller mustn't
617 * try to use the structure pointer in any way.
620 freeCon(__nis_ldap_conn_t
*lc
) {
622 if (!assertExclusive(lc
))
623 return (LDAP_PARAM_ERROR
);
627 /* Must be unused, unbound, and not on the 'ldapCon' list */
628 if (lc
->onList
|| lc
->refCount
!= 1 || lc
->isBound
) {
638 /* Delete structure with both mutex:es held */
642 return (LDAP_UNAVAILABLE
);
646 * Disconnect the specified LDAP connection. Caller must have acquired 'mutex'.
648 * On return, if the status is LDAP_UNAVAILABLE, the caller must not touch
649 * the structure in any way.
652 disconnectCon(__nis_ldap_conn_t
*lc
) {
654 char *myself
= "disconnectCon";
657 return (LDAP_SUCCESS
);
659 if (!assertExclusive(lc
))
660 return (LDAP_UNAVAILABLE
);
664 /* Increment refCount to protect against interference */
666 /* refCount must be one (i.e., just us) */
667 if (lc
->refCount
!= 1) {
669 * In use; already marked for disconnect,
676 stat
= ldap_unbind_s(lc
->ld
);
677 if (stat
== LDAP_SUCCESS
) {
681 /* Reset simple page and vlv indication */
684 } else if (verbose
) {
685 logmsg(MSG_NOTIMECHECK
, LOG_ERR
,
686 "%s: ldap_unbind_s() => %d (%s)",
687 myself
, stat
, ldap_err2string(stat
));
694 if (LDAP_UNAVAILABLE
== freeCon(lc
))
695 stat
= LDAP_UNAVAILABLE
;
702 * controlSupported will determine for a given connection whether a set
703 * of controls is supported or not. The input parameters:
705 * ctrl A an array of OID strings, the terminal string should be NULL
706 * The returned values if LDAP_SUCCESS is returned:
707 * supported A caller supplied array which will be set to TRUE or
708 * FALSE depending on whether the corresponding control
709 * is reported as supported.
710 * Returns LDAP_SUCCESS if the supportedControl attribute is read.
714 controlSupported(__nis_ldap_conn_t
*lc
, char **ctrl
, bool_t
*supported
) {
715 LDAPMessage
*res
, *e
;
716 char *attr
[2], *a
, **val
;
719 char *myself
= "controlSupported";
721 attr
[0] = "supportedControl";
724 stat
= ldap_search_st(lc
->ld
, "", LDAP_SCOPE_BASE
, "(objectclass=*)",
725 attr
, 0, &lc
->searchTimeout
, &res
);
726 if (stat
!= LDAP_SUCCESS
) {
727 logmsg(MSG_NOTIMECHECK
, LOG_WARNING
,
728 "%s: Unable to retrieve supported control information for %s: %s",
729 myself
, NIL(lc
->sp
), ldap_err2string(stat
));
733 e
= ldap_first_entry(lc
->ld
, res
);
735 a
= ldap_first_attribute(lc
->ld
, e
, &ber
);
737 val
= ldap_get_values(lc
->ld
, e
, a
);
745 if (e
== 0 || a
== 0 || val
== 0) {
747 logmsg(MSG_NOTIMECHECK
, LOG_INFO
,
748 "%s: Unable to get root DSE for %s",
749 myself
, NIL(lc
->sp
));
750 return (LDAP_OPERATIONS_ERROR
);
753 while (*ctrl
!= NULL
) {
755 for (i
= 0; val
[i
] != 0; i
++) {
756 if (strstr(val
[i
], *ctrl
) != 0) {
761 logmsg(MSG_NOTIMECHECK
, LOG_INFO
,
763 myself
, NIL(lc
->sp
), NIL(*ctrl
),
764 *supported
? "enabled" : "disabled");
769 ldap_value_free(val
);
779 * Connect the LDAP connection 'lc'. Caller must have acquired the 'mutex',
780 * and the refCount must be zero.
782 * On return, if the status is LDAP_UNAVAILABLE, the caller must not touch
783 * the structure in any way.
786 connectCon(__nis_ldap_conn_t
*lc
, int check_ctrl
) {
789 bool_t supported
[2] = {FALSE
, FALSE
};
790 char *ctrl
[3] = {LDAP_CONTROL_SIMPLE_PAGE
,
791 LDAP_CONTROL_VLVREQUEST
,
795 return (LDAP_SUCCESS
);
797 if (!assertExclusive(lc
))
798 return (LDAP_PARAM_ERROR
);
801 if (lc
->refCount
!= 1) {
803 * Don't want to step on structure when it's used by someone
810 (void) gettimeofday(&tp
, 0);
813 /* Try to disconnect */
816 /* disconnctCon() will do the delete if required */
817 stat
= disconnectCon(lc
);
818 if (stat
!= LDAP_SUCCESS
)
821 if (lc
->refCount
!= 1 || lc
->ld
!= 0) {
823 return (lc
->ld
!= 0) ? LDAP_SUCCESS
:
826 } else if (tp
.tv_sec
< lc
->retryTime
) {
827 /* Too early to retry connect */
829 return (LDAP_SERVER_DOWN
);
832 /* Set new retry time in case we fail below */
833 lc
->retryTime
= tp
.tv_sec
+ ldapConnAttemptRetryTimeout
;
835 lc
->ld
= ldapInit(lc
->sp
, lc
->port
, proxyInfo
.tls_method
!= no_tls
);
838 return (LDAP_LOCAL_ERROR
);
841 stat
= lc
->status
= ldapBind(&lc
->ld
, lc
->who
, lc
->cred
, lc
->method
,
843 if (lc
->status
== LDAP_SUCCESS
) {
847 (void) controlSupported(lc
, ctrl
, supported
);
848 lc
->simplePage
= supported
[0];
849 lc
->vlv
= supported
[1];
850 lc
->batchFrom
= 50000;
860 * Find and return a connection believed to be OK.
862 static __nis_ldap_conn_t
*
864 __nis_ldap_conn_t
*lc
;
866 char *myself
= "findCon";
871 (void) rw_rdlock(&ldapConLock
);
874 /* Probably first call; try to set up the connection list */
875 (void) rw_unlock(&ldapConLock
);
876 if ((*stat
= setupConList(proxyInfo
.default_servers
,
878 proxyInfo
.proxy_passwd
,
879 proxyInfo
.auth_method
)) !=
882 (void) rw_rdlock(&ldapConLock
);
885 for (lc
= ldapCon
; lc
!= 0; lc
= lc
->next
) {
888 *stat
= connectCon(lc
, 1);
889 if (*stat
!= LDAP_SUCCESS
) {
890 if (*stat
!= LDAP_UNAVAILABLE
) {
891 logmsg(MSG_NOTIMECHECK
, LOG_WARNING
,
892 "%s: Cannot open connection to LDAP server (%s): %s",
894 ldap_err2string(*stat
));
899 } else if (lc
->doDis
|| lc
->doDel
) {
900 *stat
= disconnectCon(lc
);
901 if (*stat
!= LDAP_UNAVAILABLE
)
910 (void) rw_unlock(&ldapConLock
);
915 /* Release connection; decrements ref count for the connection */
917 releaseCon(__nis_ldap_conn_t
*lc
, int status
) {
930 stat
= disconnectCon(lc
);
934 if (stat
!= LDAP_UNAVAILABLE
)
938 static __nis_ldap_conn_t
*
939 createCon(char *sp
, char *who
, char *cred
, auth_method_t method
, int port
) {
940 __nis_ldap_conn_t
*lc
;
941 char *myself
= "createCon";
947 lc
= am(myself
, sizeof (*lc
));
951 (void) mutex_init(&lc
->mutex
, 0, 0);
952 (void) mutex_init(&lc
->rcMutex
, 0, 0);
954 /* If we need to delete 'lc', freeCon() wants the mutex held */
957 lc
->sp
= sdup(myself
, T
, sp
);
963 if ((r
= strchr(lc
->sp
, ']')) != 0) {
965 * IPv6 address. Does libldap want this with the
966 * '[' and ']' left in place ? Assume so for now.
970 r
= strchr(lc
->sp
, ':');
976 } else if (port
== 0)
977 port
= proxyInfo
.tls_method
== ssl_tls
? LDAPS_PORT
: LDAP_PORT
;
980 lc
->who
= sdup(myself
, T
, who
);
988 lc
->cred
= sdup(myself
, T
, cred
);
998 lc
->bindTimeout
= proxyInfo
.bind_timeout
;
999 lc
->searchTimeout
= proxyInfo
.search_timeout
;
1000 lc
->modifyTimeout
= proxyInfo
.modify_timeout
;
1001 lc
->addTimeout
= proxyInfo
.add_timeout
;
1002 lc
->deleteTimeout
= proxyInfo
.delete_timeout
;
1004 /* All other fields OK at zero */
1012 setupConList(char *serverList
, char *who
, char *cred
, auth_method_t method
) {
1013 char *sls
, *sl
, *s
, *e
;
1014 __nis_ldap_conn_t
*lc
, *tmp
;
1015 char *myself
= "setupConList";
1017 if (serverList
== 0)
1018 return (LDAP_PARAM_ERROR
);
1020 (void) rw_wrlock(&ldapConLock
);
1023 /* Assume we've already been called and done the set-up */
1024 (void) rw_unlock(&ldapConLock
);
1025 return (LDAP_SUCCESS
);
1028 /* Work on a copy of 'serverList' */
1029 sl
= sls
= sdup(myself
, T
, serverList
);
1031 (void) rw_unlock(&ldapConLock
);
1032 return (LDAP_NO_MEMORY
);
1035 /* Remove leading white space */
1036 for (; *sl
== ' ' || *sl
== '\t'; sl
++);
1038 /* Create connection for each server on the list */
1039 for (s
= sl
; *s
!= '\0'; s
= e
+1) {
1042 /* Find end of server/port token */
1043 for (e
= s
; *e
!= ' ' && *e
!= '\t' && *e
!= '\0'; e
++);
1051 lc
= createCon(s
, who
, cred
, method
, 0);
1054 (void) rw_unlock(&ldapConLock
);
1055 return (LDAP_NO_MEMORY
);
1061 /* Insert at end of list */
1062 for (tmp
= ldapCon
; tmp
->next
!= 0;
1071 (void) rw_unlock(&ldapConLock
);
1073 return (LDAP_SUCCESS
);
1077 is_same_connection(__nis_ldap_conn_t
*lc
, LDAPURLDesc
*ludpp
)
1079 return (strcasecmp(ludpp
->lud_host
, lc
->sp
) == 0 &&
1080 ludpp
->lud_port
== lc
->port
);
1083 static __nis_ldap_conn_t
*
1084 find_connection_from_list(__nis_ldap_conn_t
*list
,
1085 LDAPURLDesc
*ludpp
, int *stat
)
1088 __nis_ldap_conn_t
*lc
= NULL
;
1092 *stat
= LDAP_SUCCESS
;
1094 for (lc
= list
; lc
!= 0; lc
= lc
->next
) {
1096 if (is_same_connection(lc
, ludpp
)) {
1098 *stat
= connectCon(lc
, 1);
1099 if (*stat
!= LDAP_SUCCESS
) {
1103 } else if (lc
->doDis
|| lc
->doDel
) {
1104 (void) disconnectCon(lc
);
1117 static __nis_ldap_conn_t
*
1118 findReferralCon(char **referralsp
, int *stat
)
1120 __nis_ldap_conn_t
*lc
= NULL
;
1121 __nis_ldap_conn_t
*tmp
;
1124 LDAPURLDesc
*ludpp
= NULL
;
1125 char *myself
= "findReferralCon";
1130 *stat
= LDAP_SUCCESS
;
1133 * We have the referral lock - to prevent multiple
1134 * threads from creating a referred connection simultaneously
1136 * Note that this code assumes that the ldapCon list is a
1137 * static list - that it has previously been created
1138 * (otherwise we wouldn't have gotten a referral) and that
1139 * it will neither grow or shrink - elements may have new
1140 * connections or unbound. If this assumption is no longer valid,
1141 * the locking needs to be reworked.
1143 (void) rw_rdlock(&referralConLock
);
1145 for (i
= 0; referralsp
[i
] != NULL
; i
++) {
1146 if (ldap_url_parse(referralsp
[i
], &ludpp
) != LDAP_SUCCESS
)
1148 /* Ignore referrals if not at the appropriate tls level */
1149 #ifdef LDAP_URL_OPT_SECURE
1150 if (ludpp
->lud_options
& LDAP_URL_OPT_SECURE
) {
1151 if (proxyInfo
.tls_method
!= ssl_tls
) {
1152 ldap_free_urldesc(ludpp
);
1156 if (proxyInfo
.tls_method
!= no_tls
) {
1157 ldap_free_urldesc(ludpp
);
1163 /* Determine if we already have a connection to the server */
1164 lc
= find_connection_from_list(ldapReferralCon
, ludpp
, stat
);
1166 lc
= find_connection_from_list(ldapCon
, ludpp
, stat
);
1167 ldap_free_urldesc(ludpp
);
1169 (void) rw_unlock(&referralConLock
);
1174 for (i
= 0; referralsp
[i
] != NULL
; i
++) {
1175 if (ldap_url_parse(referralsp
[i
], &ludpp
) != LDAP_SUCCESS
)
1177 /* Ignore referrals if not at the appropriate tls level */
1178 #ifdef LDAP_URL_OPT_SECURE
1179 if (ludpp
->lud_options
& LDAP_URL_OPT_SECURE
) {
1180 if (proxyInfo
.tls_method
!= ssl_tls
) {
1181 ldap_free_urldesc(ludpp
);
1185 if (proxyInfo
.tls_method
!= no_tls
) {
1186 ldap_free_urldesc(ludpp
);
1191 lc
= createCon(ludpp
->lud_host
, proxyInfo
.proxy_dn
,
1192 proxyInfo
.proxy_passwd
,
1193 proxyInfo
.auth_method
,
1196 ldap_free_urldesc(ludpp
);
1197 (void) rw_unlock(&referralConLock
);
1198 *stat
= LDAP_NO_MEMORY
;
1199 logmsg(MSG_NOTIMECHECK
, LOG_INFO
,
1200 "%s: Could not connect to host: %s",
1201 myself
, NIL(ludpp
->lud_host
));
1206 if (ldapReferralCon
== 0) {
1207 ldapReferralCon
= lc
;
1209 /* Insert at end of list */
1210 for (tmp
= ldapReferralCon
; tmp
->next
!= 0;
1214 lc
= find_connection_from_list(ldapReferralCon
, ludpp
, stat
);
1215 ldap_free_urldesc(ludpp
);
1219 (void) rw_unlock(&referralConLock
);
1221 logmsg(MSG_NOTIMECHECK
, LOG_INFO
,
1222 "%s: Could not find a connection to %s, ...",
1223 myself
, NIL(referralsp
[0]));
1230 * Find and return a connection believed to be OK and ensure children
1231 * will never use parent's connection.
1233 static __nis_ldap_conn_t
*
1234 findYPCon(__nis_ldap_search_t
*ls
, int *stat
) {
1235 __nis_ldap_conn_t
*lc
, *newlc
;
1236 int ldapStat
, newstat
;
1237 char *myself
= "findYPCon";
1242 (void) rw_rdlock(&ldapConLock
);
1245 /* Probably first call; try to set up the connection list */
1246 (void) rw_unlock(&ldapConLock
);
1247 if ((*stat
= setupConList(proxyInfo
.default_servers
,
1249 proxyInfo
.proxy_passwd
,
1250 proxyInfo
.auth_method
)) !=
1253 (void) rw_rdlock(&ldapConLock
);
1256 for (lc
= ldapCon
; lc
!= 0; lc
= lc
->next
) {
1259 if (lc
->isBound
&& (lc
->doDis
|| lc
->doDel
)) {
1260 *stat
= disconnectCon(lc
);
1261 if (*stat
!= LDAP_UNAVAILABLE
)
1267 * Use a new connection for all cases except when
1268 * requested by the main thread in the parent ypserv
1271 if (ls
->useCon
== 0) {
1272 newlc
= createCon(lc
->sp
, lc
->who
, lc
->cred
,
1273 lc
->method
, lc
->port
);
1279 newlc
->simplePage
= lc
->simplePage
;
1280 newlc
->vlv
= lc
->vlv
;
1281 newlc
->batchFrom
= lc
->batchFrom
;
1285 newstat
= connectCon(newlc
, 0);
1286 if (newstat
!= LDAP_SUCCESS
) {
1287 if (newstat
!= LDAP_UNAVAILABLE
) {
1288 logmsg(MSG_NOTIMECHECK
, LOG_WARNING
,
1289 "%s: Cannot open connection to LDAP server (%s): %s",
1290 myself
, NIL(newlc
->sp
),
1291 ldap_err2string(*stat
));
1293 (void) freeCon(newlc
);
1299 * No need to put newlc on the ldapCon list as this
1300 * connection will be freed after use.
1305 } else if (!lc
->isBound
) {
1306 *stat
= connectCon(lc
, 1);
1307 if (*stat
!= LDAP_SUCCESS
) {
1308 if (*stat
!= LDAP_UNAVAILABLE
) {
1309 logmsg(MSG_NOTIMECHECK
, LOG_WARNING
,
1310 "%s: Cannot open connection to LDAP server (%s): %s",
1311 myself
, NIL(lc
->sp
),
1312 ldap_err2string(*stat
));
1324 (void) rw_unlock(&ldapConLock
);
1329 #define SORTKEYLIST "cn uid"
1332 * Perform an LDAP search operation per 'ls', adding the result(s) to
1333 * a copy of the 'rvIn' structure; the copy becomes the return value.
1334 * The caller must deallocate both 'rvIn' and the result, if any.
1336 * On entry, '*numValues' contains a hint regarding the expected
1337 * number of entries. Zero is the same as one, and negative values
1338 * imply no information. This is used to decide whether or not to
1339 * try an indexed search.
1341 * On successful (non-NULL) return, '*numValues' contains the number
1342 * of __nis_rule_value_t elements in the returned array, and '*stat'
1343 * the LDAP operations status.
1345 __nis_rule_value_t
*
1346 ldapSearch(__nis_ldap_search_t
*ls
, int *numValues
, __nis_rule_value_t
*rvIn
,
1348 __nis_rule_value_t
*rv
= 0;
1349 int stat
, numEntries
, numVals
, tnv
, done
, lprEc
;
1350 LDAPMessage
*msg
= 0, *m
;
1351 __nis_ldap_conn_t
*lc
;
1352 struct timeval tv
, start
, now
;
1353 LDAPsortkey
**sortKeyList
= 0;
1354 LDAPControl
*ctrls
[3], *sortCtrl
= 0, *vlvCtrl
= 0;
1355 LDAPControl
**retCtrls
= 0;
1356 LDAPVirtualList vList
;
1357 struct berval
*spCookie
= 0;
1361 char *myself
= "ldapSearch";
1362 bool_t follow_referral
=
1363 proxyInfo
.follow_referral
== follow
;
1365 char **referralsp
= NULL
;
1367 ctrls
[0] = ctrls
[1] = ctrls
[2] = 0;
1373 *ldapStat
= LDAP_PARAM_ERROR
;
1378 /* make sure the parent's connection is not used by child */
1379 if ((lc
= findYPCon(ls
, ldapStat
)) == 0) {
1380 *ldapStat
= LDAP_SERVER_DOWN
;
1384 if ((lc
= findCon(ldapStat
)) == 0) {
1385 *ldapStat
= LDAP_SERVER_DOWN
;
1390 if (numValues
!= 0 && (*numValues
== 0 || *numValues
== 1))
1394 /* Prefer VLV over simple page, and SP over nothing */
1395 if (doIndex
&& lc
->vlv
) {
1396 stat
= ldap_create_sort_keylist(&sortKeyList
, SORTKEYLIST
);
1397 if (stat
!= LDAP_SUCCESS
) {
1398 logmsg(MSG_NOTIMECHECK
, LOG_INFO
,
1399 "%s: Error creating sort keylist: %s",
1400 myself
, ldap_err2string(stat
));
1401 freeRuleValue(rv
, numVals
);
1406 stat
= ldap_create_sort_control(lc
->ld
, sortKeyList
, 1,
1408 if (stat
== LDAP_SUCCESS
) {
1409 vList
.ldvlist_before_count
= 0;
1410 vList
.ldvlist_after_count
= lc
->batchFrom
- 1;
1411 vList
.ldvlist_attrvalue
= 0;
1412 vList
.ldvlist_extradata
= 0;
1416 ldap_get_option(lc
->ld
, LDAP_OPT_ERROR_NUMBER
, &stat
);
1417 logmsg(MSG_NOTIMECHECK
, LOG_INFO
,
1418 "%s: Error creating VLV sort control: %s",
1419 myself
, ldap_err2string(stat
));
1420 freeRuleValue(rv
, numVals
);
1428 if (doIndex
&& !doVLV
&& lc
->simplePage
) {
1429 spCookie
= am(myself
, sizeof (*spCookie
));
1430 if (spCookie
!= 0 &&
1431 (spCookie
->bv_val
= sdup(myself
, T
, "")) != 0) {
1432 spCookie
->bv_len
= 0;
1435 logmsg(MSG_NOTIMECHECK
, LOG_INFO
,
1436 "%s: No memory for simple page cookie; using un-paged LDAP search",
1438 freeRuleValue(rv
, numVals
);
1445 if (!doVLV
&& !doSP
)
1446 ctrls
[0] = ctrls
[1] = 0;
1451 if (ls
->timeout
.tv_sec
|| ls
->timeout
.tv_usec
) {
1454 tv
= lc
->searchTimeout
;
1456 (void) gettimeofday(&start
, 0);
1459 /* don't do vlv or simple page for base level searches */
1460 if (doVLV
&& ls
->base
!= LDAP_SCOPE_BASE
) {
1461 vList
.ldvlist_index
= index
;
1462 vList
.ldvlist_size
= 0;
1464 ldap_control_free(vlvCtrl
);
1465 stat
= ldap_create_virtuallist_control(lc
->ld
,
1467 if (stat
!= LDAP_SUCCESS
) {
1468 ldap_get_option(lc
->ld
, LDAP_OPT_ERROR_NUMBER
,
1470 logmsg(MSG_NOTIMECHECK
, LOG_ERR
,
1471 "%s: Error creating VLV at index %ld: %s",
1472 myself
, index
, ldap_err2string(stat
));
1474 freeRuleValue(rv
, numVals
);
1478 ctrls
[0] = sortCtrl
;
1481 stat
= ldap_search_ext_s(lc
->ld
, ls
->base
,
1482 ls
->scope
, ls
->filter
, ls
->attrs
,
1483 ls
->attrsonly
, ctrls
, 0, &tv
,
1484 proxyInfo
.search_size_limit
, &msg
);
1485 /* don't do vlv or simple page for base level searches */
1486 } else if (doSP
&& ls
->base
!= LDAP_SCOPE_BASE
) {
1488 ldap_control_free(ctrls
[0]);
1489 stat
= ldap_create_page_control(lc
->ld
,
1490 lc
->batchFrom
, spCookie
, 0, &ctrls
[0]);
1491 if (stat
!= LDAP_SUCCESS
) {
1492 ber_bvfree(spCookie
);
1494 ldap_get_option(lc
->ld
, LDAP_OPT_ERROR_NUMBER
,
1496 logmsg(MSG_NOTIMECHECK
, LOG_ERR
,
1497 "%s: Simple page error: %s",
1498 myself
, ldap_err2string(stat
));
1499 freeRuleValue(rv
, numVals
);
1505 stat
= ldap_search_ext_s(lc
->ld
, ls
->base
,
1506 ls
->scope
, ls
->filter
, ls
->attrs
,
1507 ls
->attrsonly
, ctrls
, 0, &tv
,
1508 proxyInfo
.search_size_limit
, &msg
);
1510 stat
= ldap_search_st(lc
->ld
, ls
->base
, ls
->scope
,
1511 ls
->filter
, ls
->attrs
, ls
->attrsonly
,
1514 if (stat
== LDAP_SUCCESS
)
1515 ldap_get_option(lc
->ld
, LDAP_OPT_ERROR_NUMBER
, &stat
);
1517 if (stat
== LDAP_SERVER_DOWN
) {
1519 releaseCon(lc
, stat
);
1520 lc
= (yp2ldap
)?findYPCon(ls
, ldapStat
):
1523 *ldapStat
= LDAP_SERVER_DOWN
;
1527 goto retry_new_conn
;
1530 if (stat
== LDAP_REFERRAL
&& follow_referral
) {
1531 (void) ldap_parse_result(lc
->ld
, msg
, NULL
, NULL
, NULL
,
1532 &referralsp
, NULL
, 0);
1533 if (referralsp
!= NULL
) {
1534 /* We support at most one level of referrals */
1535 follow_referral
= FALSE
;
1536 releaseCon(lc
, stat
);
1537 lc
= findReferralCon(referralsp
, &stat
);
1538 ldap_value_free(referralsp
);
1540 freeRuleValue(rv
, numVals
);
1545 stat
= LDAP_SUCCESS
;
1546 goto retry_new_conn
;
1551 if (*ldapStat
== LDAP_NO_SUCH_OBJECT
) {
1552 freeRuleValue(rv
, numVals
);
1555 } else if (doVLV
&& *ldapStat
== LDAP_INSUFFICIENT_ACCESS
) {
1557 * The LDAP server (at least Netscape 4.x) can return
1558 * LDAP_INSUFFICIENT_ACCESS when VLV is supported,
1559 * but not for the bind DN specified. So, just in
1560 * case, we clean up, and try again without VLV.
1564 (void) ldap_msgfree(msg
);
1567 if (ctrls
[0] != 0) {
1568 ldap_control_free(ctrls
[0]);
1571 if (ctrls
[1] != 0) {
1572 ldap_control_free(ctrls
[1]);
1575 logmsg(MSG_VLV_INSUFF_ACC
, LOG_WARNING
,
1576 "%s: VLV insufficient access from server %s; retrying without VLV",
1577 myself
, NIL(lc
->sp
));
1579 } else if (*ldapStat
!= LDAP_SUCCESS
) {
1580 logmsg(MSG_NOTIMECHECK
, LOG_WARNING
,
1581 "ldap_search(0x%x,\n\t\"%s\",\n\t %d,",
1582 lc
->ld
, NIL(ls
->base
), ls
->scope
);
1583 logmsg(MSG_NOTIMECHECK
, LOG_WARNING
,
1584 "\t\"%s\",\n\t0x%x,\n\t%d) => %d (%s)",
1585 NIL(ls
->filter
), ls
->attrs
, ls
->attrsonly
,
1586 *ldapStat
, ldap_err2string(stat
));
1587 freeRuleValue(rv
, numVals
);
1592 numEntries
= ldap_count_entries(lc
->ld
, msg
);
1593 if (numEntries
== 0 && *ldapStat
== LDAP_SUCCESS
) {
1595 * This is a bit weird, but the server (or, at least,
1596 * ldap_search_ext()) can sometimes return
1597 * LDAP_SUCCESS and no entries when it didn't
1598 * find what we were looking for. Seems it ought to
1599 * return LDAP_NO_SUCH_OBJECT or some such.
1601 freeRuleValue(rv
, numVals
);
1603 *ldapStat
= LDAP_NO_SUCH_OBJECT
;
1607 tnv
= numVals
+ numEntries
;
1608 if ((rv
= growRuleValue(numVals
, tnv
, rv
, rvIn
)) == 0) {
1609 *ldapStat
= LDAP_NO_MEMORY
;
1613 for (m
= ldap_first_entry(lc
->ld
, msg
); m
!= 0;
1614 m
= ldap_next_entry(lc
->ld
, m
), numVals
++) {
1616 BerElement
*ber
= 0;
1618 if (numVals
> tnv
) {
1619 logmsg(MSG_NOTIMECHECK
, LOG_INFO
,
1620 "%s: Inconsistent LDAP entry count > %d",
1621 myself
, numEntries
);
1625 nm
= ldap_get_dn(lc
->ld
, m
);
1626 if (nm
== 0 || addSAttr2RuleValue("dn", nm
,
1629 *ldapStat
= LDAP_NO_MEMORY
;
1630 freeRuleValue(rv
, tnv
);
1636 for (nm
= ldap_first_attribute(lc
->ld
, m
, &ber
);
1638 nm
= ldap_next_attribute(lc
->ld
, m
, ber
)) {
1639 struct berval
**val
;
1642 val
= ldap_get_values_len(lc
->ld
, m
, nm
);
1643 nv
= (val
== 0) ? 0 :
1644 ldap_count_values_len(val
);
1645 for (i
= 0; i
< nv
; i
++) {
1647 * Since we don't know if the value is
1648 * BER-encoded or not, we mark it as a
1649 * string. All is well as long as we
1650 * don't insist on 'vt_ber' when
1653 if (addAttr2RuleValue(vt_string
, nm
,
1659 ldap_value_free_len(val
);
1660 *ldapStat
= LDAP_NO_MEMORY
;
1661 freeRuleValue(rv
, tnv
);
1668 ldap_value_free_len(val
);
1674 if (numVals
!= tnv
) {
1675 logmsg(MSG_NOTIMECHECK
, LOG_WARNING
,
1676 "%s: Inconsistent LDAP entry count, found = %d, expected %d",
1677 myself
, numVals
, tnv
);
1681 stat
= ldap_parse_result(lc
->ld
, msg
, &lprEc
, 0, 0, 0,
1683 if (stat
!= LDAP_SUCCESS
) {
1684 ldap_get_option(lc
->ld
, LDAP_OPT_ERROR_NUMBER
,
1686 logmsg(MSG_NOTIMECHECK
, LOG_ERR
,
1687 "%s: VLV parse result error: %s",
1688 myself
, ldap_err2string(stat
));
1690 freeRuleValue(rv
, tnv
);
1694 if (retCtrls
!= 0) {
1695 unsigned long targetPosP
= 0;
1696 unsigned long listSize
= 0;
1698 stat
= ldap_parse_virtuallist_control(lc
->ld
,
1699 retCtrls
, &targetPosP
, &listSize
,
1701 if (stat
== LDAP_SUCCESS
) {
1702 index
= targetPosP
+ lc
->batchFrom
;
1703 if (index
>= listSize
)
1706 ldap_controls_free(retCtrls
);
1712 stat
= ldap_parse_result(lc
->ld
, msg
, &lprEc
, 0, 0, 0,
1714 if (stat
!= LDAP_SUCCESS
) {
1715 ldap_get_option(lc
->ld
, LDAP_OPT_ERROR_NUMBER
,
1717 logmsg(MSG_NOTIMECHECK
, LOG_ERR
,
1718 "%s: Simple page parse result error: %s",
1719 myself
, ldap_err2string(stat
));
1721 freeRuleValue(rv
, tnv
);
1725 if (retCtrls
!= 0) {
1728 if (spCookie
!= 0) {
1729 ber_bvfree(spCookie
);
1732 stat
= ldap_parse_page_control(lc
->ld
,
1733 retCtrls
, &count
, &spCookie
);
1734 if (stat
== LDAP_SUCCESS
) {
1735 if (spCookie
== 0 ||
1736 spCookie
->bv_val
== 0 ||
1737 spCookie
->bv_len
== 0)
1740 ldap_controls_free(retCtrls
);
1749 (void) ldap_msgfree(msg
);
1753 * If we're using VLV or SP, the timeout should apply
1754 * to all calls as an aggregate, so we need to reduce
1755 * 'tv' with the time spent on this chunk of data.
1760 (void) gettimeofday(&now
, 0);
1762 now
.tv_sec
-= start
.tv_sec
;
1763 now
.tv_usec
-= start
.tv_usec
;
1764 if (now
.tv_usec
< 0) {
1765 now
.tv_usec
+= 1000000;
1768 tv
.tv_sec
-= now
.tv_sec
;
1769 tv
.tv_usec
-= now
.tv_usec
;
1770 if (tv
.tv_usec
< 0) {
1771 tv
.tv_usec
+= 1000000;
1774 if (tv
.tv_sec
< 0) {
1775 *ldapStat
= LDAP_TIMEOUT
;
1776 freeRuleValue(rv
, tnv
);
1786 *numValues
= numVals
;
1790 if (yp2ldap
&& ls
->useCon
== 0) {
1791 /* Disconnect and free the connection */
1794 releaseCon(lc
, stat
);
1798 releaseCon(lc
, stat
);
1802 (void) ldap_msgfree(msg
);
1804 ldap_control_free(ctrls
[0]);
1806 ldap_control_free(ctrls
[1]);
1808 ber_bvfree(spCookie
);
1809 if (sortKeyList
!= 0)
1810 ldap_free_sort_keylist(sortKeyList
);
1816 freeLdapModEntry(LDAPMod
*m
) {
1822 if ((m
->mod_op
& LDAP_MOD_BVALUES
) == 0) {
1823 char **v
= m
->mod_values
;
1830 free(m
->mod_values
);
1833 struct berval
**b
= m
->mod_bvalues
;
1837 sfree((*b
)->bv_val
);
1841 free(m
->mod_bvalues
);
1849 freeLdapMod(LDAPMod
**mods
) {
1850 LDAPMod
*m
, **org
= mods
;
1855 while ((m
= *mods
) != 0) {
1856 freeLdapModEntry(m
);
1864 * Convert a rule-value structure to the corresponding LDAPMod.
1865 * If 'add' is set, attributes/values are added; object classes
1866 * are also added. If 'add' is cleared, attributes/values are modified,
1867 * and 'oc' controls whether or not object classes are added.
1870 search2LdapMod(__nis_rule_value_t
*rv
, int add
, int oc
) {
1873 char *myself
= "search2LdapMod";
1875 if (rv
== 0 || rv
->numAttrs
<= 0)
1878 mods
= am(myself
, (rv
->numAttrs
+ 1) * sizeof (mods
[0]));
1882 for (i
= 0, nm
= 0; i
< rv
->numAttrs
; i
++) {
1885 * If we're creating an LDAPMod array for an add operation,
1886 * just skip attributes that should be deleted.
1888 if (add
&& rv
->attrVal
[i
].numVals
< 0)
1892 * Skip DN; it's specified separately to ldap_modify()
1893 * and ldap_add(), and mustn't appear among the
1894 * attributes to be modified/added.
1896 if (strcasecmp("dn", rv
->attrName
[i
]) == 0)
1900 * If modifying, and 'oc' is off, skip object class
1903 isOc
= (strcasecmp("objectclass", rv
->attrName
[i
]) == 0);
1904 if (!add
&& !oc
&& isOc
)
1907 mods
[nm
] = am(myself
, sizeof (*mods
[nm
]));
1908 if (mods
[nm
] == 0) {
1913 /* 'mod_type' is the attribute name */
1914 mods
[nm
]->mod_type
= sdup(myself
, T
, rv
->attrName
[i
]);
1915 if (mods
[nm
]->mod_type
== 0) {
1921 * numVals < 0 means attribute and all values should
1924 if (rv
->attrVal
[i
].numVals
< 0) {
1925 mods
[nm
]->mod_op
= LDAP_MOD_DELETE
;
1926 mods
[nm
]->mod_values
= 0;
1931 /* objectClass attributes always added */
1932 mods
[nm
]->mod_op
= (add
) ? 0 : ((isOc
) ? 0 : LDAP_MOD_REPLACE
);
1934 if (rv
->attrVal
[i
].type
== vt_string
) {
1936 * mods[]->mod_values is a NULL-terminated array
1939 mods
[nm
]->mod_values
= am(myself
,
1940 (rv
->attrVal
[i
].numVals
+ 1) *
1941 sizeof (mods
[nm
]->mod_values
[0]));
1942 if (mods
[nm
]->mod_values
== 0) {
1946 for (j
= 0; j
< rv
->attrVal
[i
].numVals
; j
++) {
1948 * Just in case the string isn't NUL
1949 * terminated, add one byte to the
1950 * allocated length; am() will initialize
1951 * the buffer to zero.
1953 mods
[nm
]->mod_values
[j
] = am(myself
,
1954 rv
->attrVal
[i
].val
[j
].length
+ 1);
1955 if (mods
[nm
]->mod_values
[j
] == 0) {
1959 memcpy(mods
[nm
]->mod_values
[j
],
1960 rv
->attrVal
[i
].val
[j
].value
,
1961 rv
->attrVal
[i
].val
[j
].length
);
1964 mods
[nm
]->mod_op
|= LDAP_MOD_BVALUES
;
1965 mods
[nm
]->mod_bvalues
= am(myself
,
1966 (rv
->attrVal
[i
].numVals
+1) *
1967 sizeof (mods
[nm
]->mod_bvalues
[0]));
1968 if (mods
[nm
]->mod_bvalues
== 0) {
1972 for (j
= 0; j
< rv
->attrVal
[i
].numVals
; j
++) {
1973 mods
[nm
]->mod_bvalues
[j
] = am(myself
,
1974 sizeof (*mods
[nm
]->mod_bvalues
[j
]));
1975 if (mods
[nm
]->mod_bvalues
[j
] == 0) {
1979 mods
[nm
]->mod_bvalues
[j
]->bv_val
= am(myself
,
1980 rv
->attrVal
[i
].val
[j
].length
);
1981 if (mods
[nm
]->mod_bvalues
[j
]->bv_val
== 0) {
1985 mods
[nm
]->mod_bvalues
[j
]->bv_len
=
1986 rv
->attrVal
[i
].val
[j
].length
;
1987 memcpy(mods
[nm
]->mod_bvalues
[j
]->bv_val
,
1988 rv
->attrVal
[i
].val
[j
].value
,
1989 mods
[nm
]->mod_bvalues
[j
]->bv_len
);
1999 * Remove 'value' from 'val'. If value==0, remove the entire
2000 * __nis_single_value_t array from 'val'.
2003 removeSingleValue(__nis_value_t
*val
, void *value
, int length
) {
2010 for (i
= 0; i
< val
->numVals
; i
++) {
2011 sfree(val
->val
[i
].value
);
2019 for (i
= 0; i
< val
->numVals
; i
++) {
2020 if (val
->val
[i
].value
== 0 || (val
->val
[i
].length
!= length
))
2022 if (memcmp(val
->val
[i
].value
, value
, length
) != 0)
2024 sfree(val
->val
[i
].value
);
2025 if (i
!= (val
->numVals
- 1)) {
2026 (void) memmove(&val
->val
[i
], &val
->val
[i
+1],
2027 (val
->numVals
- 1 - i
) * sizeof (val
->val
[0]));
2035 * Helper function for LdapModify
2036 * When a modify operation fails with an object class violation,
2037 * the most probable reason is that the attributes we're modifying are new,
2038 * and the needed object class are not present. So, try the modify again,
2039 * but add the object classes this time.
2043 ldapModifyObjectClass(__nis_ldap_conn_t
**lc
, char *dn
,
2044 __nis_rule_value_t
*rvIn
, char *objClassAttrs
)
2051 LDAPMessage
*msg
= 0;
2052 char **referralsp
= NULL
;
2053 __nis_rule_value_t
*rv
, *rvldap
;
2054 __nis_ldap_search_t
*ls
;
2055 int i
, ocrv
, ocrvldap
, nv
;
2056 char *oc
[2] = { "objectClass", 0};
2057 char *myself
= "ldapModifyObjectClass";
2059 rv
= initRuleValue(1, rvIn
);
2061 return (LDAP_NO_MEMORY
);
2063 delAttrFromRuleValue(rv
, "objectClass");
2064 rv
= addObjectClasses(rv
, objClassAttrs
);
2066 stat
= LDAP_OPERATIONS_ERROR
;
2067 logmsg(MSG_NOTIMECHECK
, LOG_WARNING
,
2068 "%s: addObjectClasses failed for %s",
2074 * Before adding the object classes whole-sale, try retrieving
2075 * the entry specified by the 'dn'. If it exists, we filter out
2076 * those object classes that already are present in LDAP from our
2079 ls
= buildLdapSearch(dn
, LDAP_SCOPE_BASE
, 0, 0, "objectClass=*",
2082 logmsg(MSG_NOTIMECHECK
, LOG_INFO
,
2083 "%s: Unable to build DN search for \"%s\"",
2085 /* Fall through to try just adding the object classes */
2086 goto addObjectClasses
;
2090 rvldap
= ldapSearch(ls
, &nv
, 0, &lderr
);
2093 logmsg(MSG_NOTIMECHECK
, LOG_INFO
,
2094 "%s: No data for DN search (\"%s\"); LDAP status %d",
2095 myself
, NIL(dn
), lderr
);
2096 /* Fall through to try just adding the object classes */
2097 goto addObjectClasses
;
2101 * Find the indices of the 'objectClass' attribute
2102 * in 'rvldap' and 'rv'.
2104 for (i
= 0, ocrvldap
= -1; i
< rvldap
->numAttrs
; i
++) {
2105 if (rvldap
->attrName
[i
] != 0 &&
2106 strcasecmp("objectClass", rvldap
->attrName
[i
]) == 0) {
2111 for (i
= 0, ocrv
= -1; i
< rv
->numAttrs
; i
++) {
2112 if (rv
->attrName
[i
] != 0 &&
2113 strcasecmp("objectClass", rv
->attrName
[i
]) == 0) {
2120 * Remove those object classes that already exist
2121 * in LDAP (i.e., in 'rvldap') from 'rv'.
2123 if (ocrv
>= 0 && ocrvldap
>= 0) {
2124 for (i
= 0; i
< rvldap
->attrVal
[ocrvldap
].numVals
; i
++) {
2125 removeSingleValue(&rv
->attrVal
[ocrv
],
2126 rvldap
->attrVal
[ocrvldap
].val
[i
].value
,
2127 rvldap
->attrVal
[ocrvldap
].val
[i
].length
);
2130 * If no 'objectClass' values left in 'rv', delete
2131 * 'objectClass' from 'rv'.
2133 if (rv
->attrVal
[ocrv
].numVals
== 0)
2134 delAttrFromRuleValue(rv
, "objectClass");
2138 * 'rv' now contains the update we want to make, with just the
2139 * object class(es) that need to be added. Fall through to the
2140 * actual LDAP modify operation.
2142 freeRuleValue(rvldap
, 1);
2146 mods
= search2LdapMod(rv
, 0, 1);
2148 stat
= LDAP_OPERATIONS_ERROR
;
2149 logmsg(MSG_NOTIMECHECK
, LOG_WARNING
,
2150 "%s: Unable to create LDAP modify changes with object classes for %s",
2154 msgid
= ldap_modify((*lc
)->ld
, dn
, mods
);
2156 tv
= (*lc
)->modifyTimeout
;
2157 stat
= ldap_result((*lc
)->ld
, msgid
, 0, &tv
, &msg
);
2159 stat
= LDAP_TIMEOUT
;
2160 } else if (stat
== -1) {
2161 (void) ldap_get_option((*lc
)->ld
,
2162 LDAP_OPT_ERROR_NUMBER
, &stat
);
2164 stat
= ldap_parse_result((*lc
)->ld
, msg
, &lderr
, NULL
,
2165 NULL
, &referralsp
, NULL
, 0);
2166 if (stat
== LDAP_SUCCESS
)
2168 stat
= ldap_result2error((*lc
)->ld
, msg
, 0);
2171 (void) ldap_get_option((*lc
)->ld
, LDAP_OPT_ERROR_NUMBER
,
2174 if (proxyInfo
.follow_referral
== follow
&&
2175 stat
== LDAP_REFERRAL
&& referralsp
!= NULL
) {
2176 releaseCon(*lc
, stat
);
2178 (void) ldap_msgfree(msg
);
2180 *lc
= findReferralCon(referralsp
, &stat
);
2181 ldap_value_free(referralsp
);
2185 msgid
= ldap_modify((*lc
)->ld
, dn
, mods
);
2187 (void) ldap_get_option((*lc
)->ld
,
2188 LDAP_OPT_ERROR_NUMBER
, &stat
);
2191 stat
= ldap_result((*lc
)->ld
, msgid
, 0, &tv
, &msg
);
2193 stat
= LDAP_TIMEOUT
;
2194 } else if (stat
== -1) {
2195 (void) ldap_get_option((*lc
)->ld
,
2196 LDAP_OPT_ERROR_NUMBER
, &stat
);
2198 stat
= ldap_parse_result((*lc
)->ld
, msg
, &lderr
,
2199 NULL
, NULL
, NULL
, NULL
, 0);
2200 if (stat
== LDAP_SUCCESS
)
2207 freeRuleValue(rv
, 1);
2212 * Modify the specified 'dn' per the attribute names/values in 'rv'.
2213 * If 'rv' is NULL, we attempt to delete the entire entry.
2215 * The 'objClassAttrs' parameter is needed if the entry must be added
2216 * (i.e., created), or a modify fails with an object class violation.
2218 * If 'addFirst' is set, we try an add before a modify; modify before
2219 * add otherwise (ignored if we're deleting).
2222 ldapModify(char *dn
, __nis_rule_value_t
*rv
, char *objClassAttrs
,
2226 __nis_ldap_conn_t
*lc
;
2228 LDAPMessage
*msg
= 0;
2231 char **referralsp
= NULL
;
2232 bool_t
delete = FALSE
;
2235 return (LDAP_PARAM_ERROR
);
2237 if ((lc
= findCon(&stat
)) == 0)
2242 /* Simple case: if rv == 0, try to delete the entire entry */
2243 msgid
= ldap_delete(lc
->ld
, dn
);
2245 (void) ldap_get_option(lc
->ld
, LDAP_OPT_ERROR_NUMBER
,
2249 tv
= lc
->deleteTimeout
;
2250 stat
= ldap_result(lc
->ld
, msgid
, 0, &tv
, &msg
);
2253 stat
= LDAP_TIMEOUT
;
2254 } else if (stat
== -1) {
2255 (void) ldap_get_option(lc
->ld
, LDAP_OPT_ERROR_NUMBER
,
2258 stat
= ldap_parse_result(lc
->ld
, msg
, &lderr
, NULL
,
2259 NULL
, &referralsp
, NULL
, 0);
2260 if (stat
== LDAP_SUCCESS
)
2263 if (proxyInfo
.follow_referral
== follow
&&
2264 stat
== LDAP_REFERRAL
&& referralsp
!= NULL
) {
2265 releaseCon(lc
, stat
);
2267 (void) ldap_msgfree(msg
);
2269 lc
= findReferralCon(referralsp
, &stat
);
2270 ldap_value_free(referralsp
);
2273 msgid
= ldap_delete(lc
->ld
, dn
);
2275 (void) ldap_get_option(lc
->ld
,
2276 LDAP_OPT_ERROR_NUMBER
, &stat
);
2279 stat
= ldap_result(lc
->ld
, msgid
, 0, &tv
, &msg
);
2281 stat
= LDAP_TIMEOUT
;
2282 } else if (stat
== -1) {
2283 (void) ldap_get_option(lc
->ld
,
2284 LDAP_OPT_ERROR_NUMBER
, &stat
);
2286 stat
= ldap_parse_result(lc
->ld
, msg
, &lderr
,
2287 NULL
, NULL
, NULL
, NULL
, 0);
2288 if (stat
== LDAP_SUCCESS
)
2292 /* No such object means someone else has done our job */
2293 if (stat
== LDAP_NO_SUCH_OBJECT
)
2294 stat
= LDAP_SUCCESS
;
2297 stat
= ldapAdd(dn
, rv
, objClassAttrs
, lc
);
2299 if (stat
!= LDAP_ALREADY_EXISTS
)
2301 if ((lc
= findCon(&stat
)) == 0)
2306 * First try the modify without specifying object classes
2307 * (i.e., assume they're already present).
2309 mods
= search2LdapMod(rv
, 0, 0);
2311 stat
= LDAP_PARAM_ERROR
;
2315 msgid
= ldap_modify(lc
->ld
, dn
, mods
);
2317 (void) ldap_get_option(lc
->ld
, LDAP_OPT_ERROR_NUMBER
,
2321 tv
= lc
->modifyTimeout
;
2322 stat
= ldap_result(lc
->ld
, msgid
, 0, &tv
, &msg
);
2324 stat
= LDAP_TIMEOUT
;
2325 } else if (stat
== -1) {
2326 (void) ldap_get_option(lc
->ld
, LDAP_OPT_ERROR_NUMBER
,
2329 stat
= ldap_parse_result(lc
->ld
, msg
, &lderr
, NULL
,
2330 NULL
, &referralsp
, NULL
, 0);
2331 if (stat
== LDAP_SUCCESS
)
2334 if (proxyInfo
.follow_referral
== follow
&&
2335 stat
== LDAP_REFERRAL
&& referralsp
!= NULL
) {
2336 releaseCon(lc
, stat
);
2338 (void) ldap_msgfree(msg
);
2340 lc
= findReferralCon(referralsp
, &stat
);
2341 ldap_value_free(referralsp
);
2345 msgid
= ldap_modify(lc
->ld
, dn
, mods
);
2347 (void) ldap_get_option(lc
->ld
,
2348 LDAP_OPT_ERROR_NUMBER
, &stat
);
2351 stat
= ldap_result(lc
->ld
, msgid
, 0, &tv
, &msg
);
2353 stat
= LDAP_TIMEOUT
;
2354 } else if (stat
== -1) {
2355 (void) ldap_get_option(lc
->ld
,
2356 LDAP_OPT_ERROR_NUMBER
, &stat
);
2358 stat
= ldap_parse_result(lc
->ld
, msg
, &lderr
,
2359 NULL
, NULL
, NULL
, NULL
, 0);
2360 if (stat
== LDAP_SUCCESS
)
2366 * If the modify failed with an object class violation,
2367 * the most probable reason is that at least on of the
2368 * attributes we're modifying didn't exist before, and
2369 * neither did its object class. So, try the modify again,
2370 * but add the object classes this time.
2372 if (stat
== LDAP_OBJECT_CLASS_VIOLATION
&&
2373 objClassAttrs
!= 0) {
2376 stat
= ldapModifyObjectClass(&lc
, dn
, rv
,
2380 if (stat
== LDAP_NO_SUCH_ATTRIBUTE
) {
2382 * If there was at least one attribute delete, then
2383 * the cause of this error could be that said attribute
2384 * didn't exist in LDAP. So, do things the slow way,
2385 * and try to delete one attribute at a time.
2387 int d
, numDelete
, st
;
2388 __nis_rule_value_t
*rvt
;
2390 for (d
= 0, numDelete
= 0; d
< rv
->numAttrs
; d
++) {
2391 if (rv
->attrVal
[d
].numVals
< 0)
2395 /* If there's just one, we've already tried */
2399 /* Make a copy of the rule value */
2400 rvt
= initRuleValue(1, rv
);
2405 * Remove all delete attributes from the tmp
2408 for (d
= 0; d
< rv
->numAttrs
; d
++) {
2409 if (rv
->attrVal
[d
].numVals
< 0) {
2410 delAttrFromRuleValue(rvt
,
2416 * Now put the attributes back in one by one, and
2419 for (d
= 0; d
< rv
->numAttrs
; d
++) {
2420 if (rv
->attrVal
[d
].numVals
>= 0)
2422 st
= addAttr2RuleValue(rv
->attrVal
[d
].type
,
2423 rv
->attrName
[d
], 0, 0, rvt
);
2425 logmsg(MSG_NOMEM
, LOG_ERR
,
2426 "%s: Error deleting \"%s\" for \"%s\"",
2427 NIL(rv
->attrName
[d
]), NIL(dn
));
2428 stat
= LDAP_NO_MEMORY
;
2429 freeRuleValue(rvt
, 1);
2432 stat
= ldapModify(dn
, rvt
, objClassAttrs
, 0);
2433 if (stat
!= LDAP_SUCCESS
&&
2434 stat
!= LDAP_NO_SUCH_ATTRIBUTE
) {
2435 freeRuleValue(rvt
, 1);
2438 delAttrFromRuleValue(rvt
, rv
->attrName
[d
]);
2442 * If we got here, then all attributes that should
2443 * be deleted either have been, or didn't exist. For
2444 * our purposes, the latter is as good as the former.
2446 stat
= LDAP_SUCCESS
;
2447 freeRuleValue(rvt
, 1);
2450 if (stat
== LDAP_NO_SUCH_OBJECT
&& !addFirst
) {
2452 * Entry doesn't exist, so try an ldap_add(). If the
2453 * ldap_add() also fails, that could be because someone
2454 * else added it between our modify and add operations.
2455 * If so, we consider that foreign add to be
2456 * authoritative (meaning we don't retry our modify).
2458 * Also, if all modify operations specified by 'mods'
2459 * are deletes, LDAP_NO_SUCH_OBJECT is a kind of
2460 * success; we certainly don't want to create the
2466 for (m
= mods
, allDelete
= 1; *m
!= 0 && allDelete
;
2468 if (((*m
)->mod_op
& LDAP_MOD_DELETE
) == 0)
2475 stat
= LDAP_SUCCESS
;
2476 } else if (objClassAttrs
== 0) {
2477 /* Now we need it, so this is fatal */
2478 stat
= LDAP_PARAM_ERROR
;
2480 stat
= ldapAdd(dn
, rv
, objClassAttrs
, lc
);
2487 if (stat
!= LDAP_SUCCESS
) {
2488 logmsg(MSG_NOTIMECHECK
, LOG_INFO
,
2489 "%s(0x%x (%s), \"%s\") => %d (%s)\n",
2490 !delete ? (add
? "ldap_add" : "ldap_modify") :
2492 lc
!= NULL
? lc
->ld
: 0,
2493 lc
!= NULL
? NIL(lc
->sp
) : "nil",
2494 dn
, stat
, ldap_err2string(stat
));
2497 releaseCon(lc
, stat
);
2500 (void) ldap_msgfree(msg
);
2506 * Create the entry specified by 'dn' to have the values per 'rv'.
2507 * The 'objClassAttrs' are the extra object classes we need when
2508 * creating an entry.
2510 * If 'lc' is non-NULL, we use that connection; otherwise, we find
2511 * our own. CAUTION: This connection will be released on return. Regardless
2512 * of return value, this connection should not subsequently used by the
2515 * Returns an LDAP status.
2518 ldapAdd(char *dn
, __nis_rule_value_t
*rv
, char *objClassAttrs
, void *lcv
) {
2522 LDAPMessage
*msg
= 0;
2523 __nis_ldap_conn_t
*lc
= lcv
;
2526 char **referralsp
= NULL
;
2528 if (dn
== 0 || rv
== 0 || objClassAttrs
== 0) {
2529 releaseCon(lc
, LDAP_SUCCESS
);
2530 return (LDAP_PARAM_ERROR
);
2534 if ((lc
= findCon(&stat
)) == 0)
2538 rv
= addObjectClasses(rv
, objClassAttrs
);
2540 stat
= LDAP_OPERATIONS_ERROR
;
2544 mods
= search2LdapMod(rv
, 1, 0);
2546 stat
= LDAP_OPERATIONS_ERROR
;
2550 msgid
= ldap_add(lc
->ld
, dn
, mods
);
2552 (void) ldap_get_option(lc
->ld
, LDAP_OPT_ERROR_NUMBER
, &stat
);
2555 tv
= lc
->addTimeout
;
2556 stat
= ldap_result(lc
->ld
, msgid
, 0, &tv
, &msg
);
2558 stat
= LDAP_TIMEOUT
;
2559 } else if (stat
== -1) {
2560 (void) ldap_get_option(lc
->ld
, LDAP_OPT_ERROR_NUMBER
, &stat
);
2562 stat
= ldap_parse_result(lc
->ld
, msg
, &lderr
, NULL
, NULL
,
2563 &referralsp
, NULL
, 0);
2564 if (stat
== LDAP_SUCCESS
)
2567 if (proxyInfo
.follow_referral
== follow
&& stat
== LDAP_REFERRAL
&&
2568 referralsp
!= NULL
) {
2569 releaseCon(lc
, stat
);
2571 (void) ldap_msgfree(msg
);
2573 lc
= findReferralCon(referralsp
, &stat
);
2574 ldap_value_free(referralsp
);
2577 msgid
= ldap_add(lc
->ld
, dn
, mods
);
2579 (void) ldap_get_option(lc
->ld
,
2580 LDAP_OPT_ERROR_NUMBER
, &stat
);
2583 stat
= ldap_result(lc
->ld
, msgid
, 0, &tv
, &msg
);
2585 stat
= LDAP_TIMEOUT
;
2586 } else if (stat
== -1) {
2587 (void) ldap_get_option(lc
->ld
, LDAP_OPT_ERROR_NUMBER
,
2590 stat
= ldap_parse_result(lc
->ld
, msg
, &lderr
, NULL
,
2591 NULL
, NULL
, NULL
, 0);
2592 if (stat
== LDAP_SUCCESS
)
2598 if (stat
!= LDAP_SUCCESS
) {
2599 logmsg(MSG_NOTIMECHECK
, LOG_INFO
,
2600 "ldap_add(0x%x (%s), \"%s\") => %d (%s)\n",
2601 lc
!= NULL
? lc
->ld
: 0,
2602 lc
!= NULL
? NIL(lc
->sp
) : "nil",
2603 dn
, stat
, ldap_err2string(stat
));
2606 releaseCon(lc
, stat
);
2609 (void) ldap_msgfree(msg
);
2615 * Change the entry at 'oldDn' to have the new DN (not RDN) 'dn'.
2616 * Returns an LDAP error status.
2619 ldapChangeDN(char *oldDn
, char *dn
) {
2621 __nis_ldap_conn_t
*lc
;
2627 LDAPMessage
*msg
= 0;
2628 char **referralsp
= NULL
;
2629 char *myself
= "ldapChangeDN";
2631 if ((lo
= slen(oldDn
)) <= 0 || (ln
= slen(dn
)) <= 0)
2632 return (LDAP_PARAM_ERROR
);
2634 if (strcasecmp(oldDn
, dn
) == 0)
2635 return (LDAP_SUCCESS
);
2637 if ((lc
= findCon(&stat
)) == 0)
2640 rdn
= sdup(myself
, T
, dn
);
2642 releaseCon(lc
, LDAP_SUCCESS
);
2643 return (LDAP_NO_MEMORY
);
2646 /* Compare old and new DN from the end */
2647 for (i
= lo
-1, j
= ln
-1; i
>= 0 && j
>= 0; i
--, j
--) {
2648 if (tolower(oldDn
[i
]) != tolower(rdn
[j
])) {
2650 * Terminate 'rdn' after this character in order
2651 * to snip off the portion of the new DN that is
2652 * the same as the old DN. What remains in 'rdn'
2653 * is the relative DN.
2660 stat
= ldap_rename(lc
->ld
, oldDn
, rdn
, NULL
, 1, NULL
, NULL
, &msgid
);
2663 tv
= lc
->modifyTimeout
;
2664 stat
= ldap_result(lc
->ld
, msgid
, 0, &tv
, &msg
);
2666 stat
= LDAP_TIMEOUT
;
2667 } else if (stat
== -1) {
2668 (void) ldap_get_option(lc
->ld
,
2669 LDAP_OPT_ERROR_NUMBER
, &stat
);
2671 stat
= ldap_parse_result(lc
->ld
, msg
, &lderr
, NULL
,
2672 NULL
, &referralsp
, NULL
, 0);
2673 if (stat
== LDAP_SUCCESS
)
2675 stat
= ldap_result2error(lc
->ld
, msg
, 0);
2678 (void) ldap_get_option(lc
->ld
, LDAP_OPT_ERROR_NUMBER
,
2681 if (proxyInfo
.follow_referral
== follow
&&
2682 stat
== LDAP_REFERRAL
&& referralsp
!= NULL
) {
2683 releaseCon(lc
, stat
);
2685 (void) ldap_msgfree(msg
);
2687 lc
= findReferralCon(referralsp
, &stat
);
2688 ldap_value_free(referralsp
);
2692 msgid
= ldap_rename(lc
->ld
, oldDn
, rdn
, NULL
, 1, NULL
, NULL
,
2695 (void) ldap_get_option(lc
->ld
,
2696 LDAP_OPT_ERROR_NUMBER
, &stat
);
2699 stat
= ldap_result(lc
->ld
, msgid
, 0, &tv
, &msg
);
2701 stat
= LDAP_TIMEOUT
;
2702 } else if (stat
== -1) {
2703 (void) ldap_get_option(lc
->ld
,
2704 LDAP_OPT_ERROR_NUMBER
, &stat
);
2706 stat
= ldap_parse_result(lc
->ld
, msg
, &lderr
,
2707 NULL
, NULL
, NULL
, NULL
, 0);
2708 if (stat
== LDAP_SUCCESS
)
2715 (void) ldap_msgfree(msg
);
2718 fprintf(stderr
, "%s: ldap_modrdn_s(0x%x, %s, %s, 1) => %s\n",
2719 myself
, lc
== NULL
? 0: lc
->ld
, NIL(oldDn
), NIL(rdn
),
2720 ldap_err2string(stat
));
2721 logmsg(MSG_NOTIMECHECK
, LOG_WARNING
,
2722 "%s: ldap_modrdn_s(0x%x, %s, %s, 1) => %s",
2723 myself
, lc
== NULL
? 0: lc
->ld
, NIL(oldDn
), NIL(rdn
),
2724 ldap_err2string(stat
));
2727 if (stat
== LDAP_NO_SUCH_OBJECT
) {
2729 * Fine from our point of view, since all we want to do
2730 * is to make sure that an update to the new DN doesn't
2731 * leave the old entry around.
2733 stat
= LDAP_SUCCESS
;
2736 releaseCon(lc
, stat
);