Print this page
5910 libnisdb won't build with modern GCC
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/lib/libnisdb/ldap_op.c
+++ new/usr/src/lib/libnisdb/ldap_op.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
↓ open down ↓ |
11 lines elided |
↑ open up ↑ |
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21 /*
22 + * Copyright 2015 Gary Mills
22 23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 24 * Use is subject to license terms.
24 25 */
25 26
26 27 #include <synch.h>
27 28 #include <strings.h>
28 29 #include <sys/time.h>
29 30 #include <ctype.h>
30 31
31 32 #include "ldap_op.h"
32 33 #include "ldap_util.h"
33 34 #include "ldap_structs.h"
34 35 #include "ldap_ruleval.h"
35 36 #include "ldap_attr.h"
36 37 #include "ldap_print.h"
37 38 #include "ldap_glob.h"
38 39
39 40 #include "nis_parse_ldap_conf.h"
40 41
41 42 #ifndef LDAPS_PORT
42 43 #define LDAPS_PORT 636
43 44 #endif
44 45
45 46 static int setupConList(char *serverList, char *who,
46 47 char *cred, auth_method_t method);
47 48
48 49
49 50 /*
50 51 * Build one of our internal LDAP search structures, containing copies of
51 52 * the supplied input. return NULL in case of error.
52 53 *
53 54 * If 'filter' is NULL, build an AND-filter using the filter components.
54 55 */
55 56 __nis_ldap_search_t *
56 57 buildLdapSearch(char *base, int scope, int numFilterComps, char **filterComp,
57 58 char *filter, char **attrs, int attrsonly, int isDN) {
58 59 __nis_ldap_search_t *ls;
59 60 char **a;
60 61 int i, na, err = 0;
61 62 char *myself = "buildLdapSearch";
62 63
63 64 ls = am(myself, sizeof (*ls));
64 65 if (ls == 0)
65 66 return (0);
66 67
67 68 ls->base = sdup(myself, T, base);
68 69 if (ls->base == 0 && base != 0)
69 70 err++;
70 71 ls->scope = scope;
71 72
72 73 if (filterComp != 0 && numFilterComps > 0) {
73 74 ls->filterComp = am(myself, numFilterComps *
74 75 sizeof (ls->filterComp[0]));
75 76 if (ls->filterComp == 0) {
76 77 err++;
77 78 numFilterComps = 0;
78 79 }
79 80 for (i = 0; i < numFilterComps; i++) {
80 81 ls->filterComp[i] = sdup(myself, T, filterComp[i]);
81 82 if (ls->filterComp[i] == 0 && filterComp[i] != 0)
82 83 err++;
83 84 }
84 85 ls->numFilterComps = numFilterComps;
85 86 if (filter == 0) {
86 87 ls->filter = concatenateFilterComps(ls->numFilterComps,
87 88 ls->filterComp);
88 89 if (ls->filter == 0)
89 90 err++;
90 91 }
91 92 } else {
92 93 ls->filterComp = 0;
93 94 ls->numFilterComps = 0;
94 95 ls->filter = sdup(myself, T, filter);
95 96 if (ls->filter == 0 && filter != 0)
96 97 err++;
97 98 }
98 99
99 100 if (attrs != 0) {
100 101 for (na = 0, a = attrs; *a != 0; a++, na++);
101 102 ls->attrs = am(myself, (na + 1) * sizeof (ls->attrs[0]));
102 103 if (ls->attrs != 0) {
103 104 for (i = 0; i < na; i++) {
104 105 ls->attrs[i] = sdup(myself, T, attrs[i]);
105 106 if (ls->attrs[i] == 0 && attrs[i] != 0)
106 107 err++;
107 108 }
108 109 ls->attrs[na] = 0;
109 110 ls->numAttrs = na;
110 111 } else {
111 112 err++;
112 113 }
113 114 } else {
114 115 ls->attrs = 0;
115 116 ls->numAttrs = 0;
116 117 }
117 118
118 119 ls->attrsonly = attrsonly;
119 120 ls->isDN = isDN;
120 121
121 122 if (err > 0) {
122 123 freeLdapSearch(ls);
123 124 ls = 0;
124 125 }
125 126
126 127 return (ls);
127 128 }
128 129
129 130 void
130 131 freeLdapSearch(__nis_ldap_search_t *ls) {
131 132 int i;
132 133
133 134 if (ls == 0)
134 135 return;
135 136
136 137 sfree(ls->base);
137 138 if (ls->filterComp != 0) {
138 139 for (i = 0; i < ls->numFilterComps; i++) {
139 140 sfree(ls->filterComp[i]);
140 141 }
141 142 sfree(ls->filterComp);
142 143 }
143 144 sfree(ls->filter);
144 145 if (ls->attrs != 0) {
145 146 for (i = 0; i < ls->numAttrs; i++) {
146 147 sfree(ls->attrs[i]);
147 148 }
148 149 sfree(ls->attrs);
149 150 }
150 151
151 152 free(ls);
152 153 }
153 154
154 155 /*
155 156 * Given a table mapping, and a rule/value pointer,
156 157 * return an LDAP search structure with values suitable for use
157 158 * by ldap_search() or (if dn != 0) ldap_modify(). The rule/value
158 159 * may be modified.
159 160 *
160 161 * If dn != 0 and *dn == 0, the function attemps to return a pointer
161 162 * to the DN. This may necessitate an ldapSearch, if the rule set doesn't
162 163 * produce a DN directly.
163 164 *
164 165 * if dn == 0, and the rule set produces a DN as well as other attribute/
165 166 * value pairs, the function returns an LDAP search structure with the
166 167 * DN only.
167 168 *
168 169 * If 'fromLDAP' is set, the caller wants base/scope/filter from
169 170 * t->objectDN->read; otherwise, from t->objectDN->write.
170 171 *
171 172 * If 'rv' is NULL, the caller wants an enumeration of the container.
172 173 *
173 174 * Note that this function only creates a search structure for 't' itself;
174 175 * if there are alternative mappings for the table, those must be handled
175 176 * by our caller.
176 177 */
177 178 __nis_ldap_search_t *
178 179 createLdapRequest(__nis_table_mapping_t *t,
179 180 __nis_rule_value_t *rv, char **dn, int fromLDAP,
180 181 int *res, __nis_object_dn_t *obj_dn) {
181 182 int i, j;
182 183 __nis_ldap_search_t *ls = 0;
183 184 char **locDN;
184 185 int numLocDN, stat = 0, count = 0;
185 186 char *myself = "createLdapRequest";
186 187 __nis_object_dn_t *objectDN = NULL;
187 188
188 189 if (t == 0)
189 190 return (0);
190 191
191 192 if (obj_dn == NULL)
192 193 objectDN = t->objectDN;
193 194 else
194 195 objectDN = obj_dn;
195 196
196 197 if (rv == 0) {
197 198 char *base;
198 199 char *filter;
199 200
200 201 if (fromLDAP) {
201 202 base = objectDN->read.base;
202 203 filter = makeFilter(objectDN->read.attrs);
203 204 } else {
204 205 base = objectDN->write.base;
205 206 filter = makeFilter(objectDN->write.attrs);
206 207 }
207 208
208 209 /* Create request to enumerate container */
209 210 ls = buildLdapSearch(base, objectDN->read.scope, 0, 0, filter,
210 211 0, 0, 0);
211 212 sfree(filter);
212 213 return (ls);
213 214 }
214 215
215 216 for (i = 0; i < t->numRulesToLDAP; i++) {
216 217 rv = addLdapRuleValue(t, t->ruleToLDAP[i],
217 218 mit_ldap, mit_nisplus, rv, !fromLDAP, &stat);
218 219 if (rv == 0)
219 220 return (0);
220 221 if (stat == NP_LDAP_RULES_NO_VALUE)
221 222 count++;
222 223 stat = 0;
223 224 }
224 225
225 226 /*
226 227 * If none of the rules produced a value despite
227 228 * having enough NIS+ columns, return error.
228 229 */
229 230 if (rv->numAttrs == 0 && count > 0) {
230 231 *res = NP_LDAP_RULES_NO_VALUE;
231 232 return (0);
232 233 }
233 234
234 235 /*
235 236 * 'rv' now contains everything we know about the attributes and
236 237 * values. Build an LDAP search structure from it.
237 238 */
238 239
239 240 /* Look for a single-valued DN */
240 241 locDN = findDNs(myself, rv, 1,
241 242 fromLDAP ? objectDN->read.base :
242 243 objectDN->write.base,
243 244 &numLocDN);
244 245 if (locDN != 0 && numLocDN == 1) {
245 246 if (dn != 0 && *dn == 0) {
246 247 *dn = locDN[0];
247 248 sfree(locDN);
248 249 } else {
249 250 char *filter;
250 251
251 252 if (fromLDAP)
252 253 filter = makeFilter(objectDN->read.attrs);
253 254 else
254 255 filter = makeFilter(objectDN->write.attrs);
255 256 ls = buildLdapSearch(locDN[0], LDAP_SCOPE_BASE, 0, 0,
256 257 filter, 0, 0, 1);
257 258 sfree(filter);
258 259 freeDNs(locDN, numLocDN);
259 260 }
260 261 } else {
261 262 freeDNs(locDN, numLocDN);
262 263 }
263 264
264 265 if (ls != 0) {
265 266 ls->useCon = 1;
266 267 return (ls);
267 268 }
268 269
269 270 /*
270 271 * No DN, or caller wanted a search structure with the non-DN
271 272 * attributes.
272 273 */
273 274
274 275 /* Initialize search structure */
275 276 {
276 277 char *filter = (fromLDAP) ?
277 278 makeFilter(objectDN->read.attrs) :
278 279 makeFilter(objectDN->write.attrs);
279 280 char **ofc;
280 281 int nofc = 0;
281 282
282 283 ofc = makeFilterComp(filter, &nofc);
283 284
284 285 if (filter != 0 && ofc == 0) {
285 286 logmsg(MSG_NOTIMECHECK, LOG_ERR,
286 287 "%s: Unable to break filter into components: \"%s\"",
287 288 myself, NIL(filter));
288 289 sfree(filter);
289 290 return (0);
290 291 }
291 292
292 293 if (fromLDAP)
293 294 ls = buildLdapSearch(objectDN->read.base,
294 295 objectDN->read.scope,
295 296 nofc, ofc, 0, 0, 0, 0);
296 297 else
297 298 ls = buildLdapSearch(objectDN->write.base,
298 299 objectDN->write.scope,
299 300 nofc, ofc, 0, 0, 0, 0);
300 301 sfree(filter);
301 302 freeFilterComp(ofc, nofc);
302 303 if (ls == 0)
303 304 return (0);
304 305 }
305 306
306 307 /* Build and add the filter components */
307 308 for (i = 0; i < rv->numAttrs; i++) {
308 309 /* Skip DN */
309 310 if (strcasecmp("dn", rv->attrName[i]) == 0)
310 311 continue;
311 312
312 313 /* Skip vt_ber values */
313 314 if (rv->attrVal[i].type == vt_ber)
314 315 continue;
315 316
316 317 for (j = 0; j < rv->attrVal[i].numVals; j++) {
317 318 __nis_buffer_t b = {0, 0};
318 319 char **tmpComp;
319 320
320 321 bp2buf(myself, &b, "%s=%s",
321 322 rv->attrName[i], rv->attrVal[i].val[j].value);
322 323 tmpComp = addFilterComp(b.buf, ls->filterComp,
323 324 &ls->numFilterComps);
324 325 if (tmpComp == 0) {
325 326 logmsg(MSG_NOTIMECHECK, LOG_ERR,
326 327 "%s: Unable to add filter component \"%s\"",
327 328 myself, NIL(b.buf));
328 329 sfree(b.buf);
329 330 freeLdapSearch(ls);
330 331 return (0);
331 332 }
332 333 ls->filterComp = tmpComp;
333 334 sfree(b.buf);
334 335 }
335 336 }
336 337
337 338 if (ls->numFilterComps > 0) {
338 339 sfree(ls->filter);
339 340 ls->filter = concatenateFilterComps(ls->numFilterComps,
340 341 ls->filterComp);
341 342 if (ls->filter == 0) {
342 343 logmsg(MSG_NOTIMECHECK, LOG_ERR,
343 344 "%s: Unable to concatenate filter components",
344 345 myself);
345 346 freeLdapSearch(ls);
346 347 return (0);
347 348 }
348 349 }
349 350
350 351 if (dn != 0 && *dn == 0) {
351 352 /*
352 353 * The caller wants a DN, but we didn't get one from the
353 354 * the rule set. We have an 'ls', so use it to ldapSearch()
354 355 * for an entry from which we can extract the DN.
355 356 */
356 357 __nis_rule_value_t *rvtmp;
357 358 char **locDN;
358 359 int nv = 0, numLocDN;
359 360
360 361 rvtmp = ldapSearch(ls, &nv, 0, 0);
361 362 locDN = findDNs(myself, rvtmp, nv, 0, &numLocDN);
362 363 if (locDN != 0 && numLocDN == 1) {
363 364 *dn = locDN[0];
364 365 sfree(locDN);
365 366 } else {
366 367 freeDNs(locDN, numLocDN);
367 368 }
368 369 freeRuleValue(rvtmp, nv);
369 370 }
370 371
371 372 ls->useCon = 1;
372 373 return (ls);
373 374 }
374 375
375 376 int ldapConnAttemptRetryTimeout = 60; /* seconds */
376 377
377 378 typedef struct {
378 379 LDAP *ld;
379 380 mutex_t mutex; /* Mutex for update of structure */
380 381 pthread_t owner; /* Thread holding mutex */
381 382 mutex_t rcMutex; /* Mutex for refCount */
382 383 int refCount; /* Reference count */
383 384 int isBound; /* Is connection open and usable ? */
384 385 time_t retryTime; /* When should open be retried */
385 386 int status; /* Status of last operation */
386 387 int doDis; /* To be disconnected if refCount==0 */
387 388 int doDel; /* To be deleted if refCount zero */
388 389 int onList; /* True if on the 'ldapCon' list */
389 390 char *sp; /* server string */
390 391 char *who;
391 392 char *cred;
392 393 auth_method_t method;
393 394 int port;
394 395 struct timeval bindTimeout;
395 396 struct timeval searchTimeout;
396 397 struct timeval modifyTimeout;
397 398 struct timeval addTimeout;
398 399 struct timeval deleteTimeout;
399 400 int simplePage; /* Can do simple-page */
400 401 int vlv; /* Can do VLV */
401 402 uint_t batchFrom; /* # entries read in one operation */
402 403 void *next;
403 404 } __nis_ldap_conn_t;
404 405
405 406 /*
406 407 * List of connections, 'ldapCon', protected by an RW lock.
407 408 *
408 409 * The following locking scheme is used:
409 410 *
410 411 * (1) Find a connection structure to use to talk to LDAP
411 412 * Rlock list
412 413 * Locate structure
413 414 * Acquire 'mutex'
414 415 * Acquire 'rcMutex'
415 416 * update refCount
416 417 * Release 'rcMutex'
417 418 * release 'mutex'
418 419 * Unlock list
419 420 * Use structure
420 421 * Release structure when done
421 422 * (2) Insert/delete structure(s) on/from list
422 423 * Wlock list
423 424 * Insert/delete structure; if deleting, must
424 425 * acquire 'mutex', and 'rcMutex' (in that order),
425 426 * and 'refCount' must be zero.
426 427 * Unlock list
427 428 * (3) Modify structure
428 429 * Find structure
429 430 * Acquire 'mutex'
430 431 * Modify (except refCount)
431 432 * Release 'mutex'
432 433 * Release structure
433 434 */
434 435
435 436 __nis_ldap_conn_t *ldapCon = 0;
436 437 __nis_ldap_conn_t *ldapReferralCon = 0;
437 438 static rwlock_t ldapConLock = DEFAULTRWLOCK;
438 439 static rwlock_t referralConLock = DEFAULTRWLOCK;
439 440
440 441 void
441 442 exclusiveLC(__nis_ldap_conn_t *lc) {
442 443 pthread_t me = pthread_self();
443 444 int stat;
444 445
445 446 if (lc == 0)
446 447 return;
447 448
448 449 stat = mutex_trylock(&lc->mutex);
449 450 if (stat == EBUSY && lc->owner != me)
450 451 mutex_lock(&lc->mutex);
451 452
452 453 lc->owner = me;
453 454 }
454 455
455 456 /* Return 1 if mutex held by this thread, 0 otherwise */
456 457 int
457 458 assertExclusive(__nis_ldap_conn_t *lc) {
458 459 pthread_t me;
459 460 int stat;
460 461
461 462 if (lc == 0)
462 463 return (0);
463 464
464 465 stat = mutex_trylock(&lc->mutex);
465 466
466 467 if (stat == 0) {
467 468 mutex_unlock(&lc->mutex);
468 469 return (0);
469 470 }
470 471
471 472 me = pthread_self();
472 473 if (stat != EBUSY || lc->owner != me)
473 474 return (0);
474 475
475 476 return (1);
476 477 }
477 478
478 479 void
479 480 releaseLC(__nis_ldap_conn_t *lc) {
480 481 pthread_t me = pthread_self();
481 482
482 483 if (lc == 0 || lc->owner != me)
483 484 return;
484 485
485 486 lc->owner = 0;
486 487 (void) mutex_unlock(&lc->mutex);
487 488 }
488 489
489 490 void
490 491 incrementRC(__nis_ldap_conn_t *lc) {
491 492 if (lc == 0)
492 493 return;
493 494
494 495 (void) mutex_lock(&lc->rcMutex);
495 496 lc->refCount++;
496 497 (void) mutex_unlock(&lc->rcMutex);
497 498 }
498 499
499 500 void
500 501 decrementRC(__nis_ldap_conn_t *lc) {
501 502 if (lc == 0)
502 503 return;
503 504
504 505 (void) mutex_lock(&lc->rcMutex);
505 506 if (lc->refCount > 0)
506 507 lc->refCount--;
507 508 (void) mutex_unlock(&lc->rcMutex);
↓ open down ↓ |
476 lines elided |
↑ open up ↑ |
508 509 }
509 510
510 511 /* Accept a server/port indication, and call ldap_init() */
511 512 static LDAP *
512 513 ldapInit(char *srv, int port, bool_t use_ssl) {
513 514 LDAP *ld;
514 515 int ldapVersion = LDAP_VERSION3;
515 516 int derefOption = LDAP_DEREF_ALWAYS;
516 517 int timelimit = proxyInfo.search_time_limit;
517 518 int sizelimit = proxyInfo.search_size_limit;
518 - char *myself = "ldapInit";
519 519
520 520 if (srv == 0)
521 521 return (0);
522 522
523 523 if (use_ssl) {
524 524 ld = ldapssl_init(srv, port, 1);
525 525 } else {
526 526 ld = ldap_init(srv, port);
527 527 }
528 528
529 529 if (ld != 0) {
530 530 (void) ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION,
531 531 &ldapVersion);
532 532 (void) ldap_set_option(ld, LDAP_OPT_DEREF, &derefOption);
533 533 (void) ldap_set_option(ld, LDAP_OPT_REFERRALS, LDAP_OPT_OFF);
534 534 (void) ldap_set_option(ld, LDAP_OPT_TIMELIMIT, &timelimit);
535 535 (void) ldap_set_option(ld, LDAP_OPT_SIZELIMIT, &sizelimit);
536 536 (void) ldap_set_option(ld, LDAP_OPT_REBIND_ARG, 0);
537 537 }
538 538
539 539 return (ld);
540 540 }
541 541
542 542 /*
543 543 * Bind the specified LDAP structure per the supplied authentication.
544 544 * Note: tested with none, simple, and digest_md5. May or may not
545 545 * work with other authentication methods, mostly depending on whether
546 546 * or not 'who' and 'cred' contain sufficient information.
547 547 */
548 548 static int
549 549 ldapBind(LDAP **ldP, char *who, char *cred, auth_method_t method,
550 550 struct timeval timeout) {
551 551 int ret;
552 552 LDAP *ld;
553 553 char *myself = "ldapBind";
554 554
555 555 if (ldP == 0 || (ld = *ldP) == 0)
556 556 return (LDAP_PARAM_ERROR);
557 557
558 558 if (method == none) {
559 559 /* No ldap_bind() required (or even possible) */
560 560 ret = LDAP_SUCCESS;
561 561 } else if (method == simple) {
562 562 struct timeval tv;
563 563 LDAPMessage *msg = 0;
564 564
565 565 tv = timeout;
566 566 ret = ldap_bind(ld, who, cred, LDAP_AUTH_SIMPLE);
567 567 if (ret != -1) {
568 568 ret = ldap_result(ld, ret, 0, &tv, &msg);
569 569 if (ret == 0) {
570 570 ret = LDAP_TIMEOUT;
571 571 } else if (ret == -1) {
572 572 (void) ldap_get_option(ld,
573 573 LDAP_OPT_ERROR_NUMBER,
574 574 &ret);
575 575 } else {
576 576 ret = ldap_result2error(ld, msg, 0);
577 577 }
578 578 if (msg != 0)
579 579 (void) ldap_msgfree(msg);
580 580 } else {
581 581 (void) ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER,
582 582 &ret);
583 583 }
584 584 } else if (method == cram_md5) {
585 585 /* Note: there is only a synchronous call for cram-md5 */
586 586 struct berval ber_cred;
587 587
588 588 ber_cred.bv_len = strlen(cred);
589 589 ber_cred.bv_val = cred;
590 590 ret = ldap_sasl_cram_md5_bind_s(ld, who, &ber_cred, NULL, NULL);
591 591 } else if (method == digest_md5) {
592 592 /* Note: there is only a synchronous call for digest-md5 */
593 593 struct berval ber_cred;
594 594
595 595 ber_cred.bv_len = strlen(cred);
596 596 ber_cred.bv_val = cred;
597 597 ret = ldap_x_sasl_digest_md5_bind_s(ld, who, &ber_cred, NULL,
598 598 NULL);
599 599 } else {
600 600 ret = LDAP_AUTH_METHOD_NOT_SUPPORTED;
601 601 }
602 602
603 603 if (ret != LDAP_SUCCESS) {
604 604 (void) ldap_unbind_s(ld);
605 605 *ldP = 0;
606 606 logmsg(MSG_NOTIMECHECK, LOG_WARNING,
607 607 "%s: Unable to bind as: %s: %s",
608 608 myself, who, ldap_err2string(ret));
609 609 }
610 610
↓ open down ↓ |
82 lines elided |
↑ open up ↑ |
611 611 return (ret);
612 612 }
613 613
614 614 /*
615 615 * Free 'lc' and all related memory. Caller must hold the exclusive lock.
616 616 * Return LDAP_UNAVAILABLE upon success, in which case the caller mustn't
617 617 * try to use the structure pointer in any way.
618 618 */
619 619 static int
620 620 freeCon(__nis_ldap_conn_t *lc) {
621 - char *myself = "freeCon";
622 621
623 622 if (!assertExclusive(lc))
624 623 return (LDAP_PARAM_ERROR);
625 624
626 625 incrementRC(lc);
627 626
628 627 /* Must be unused, unbound, and not on the 'ldapCon' list */
629 628 if (lc->onList || lc->refCount != 1 || lc->isBound) {
630 629 lc->doDel++;
631 630 decrementRC(lc);
632 631 return (LDAP_BUSY);
633 632 }
634 633
635 634 sfree(lc->sp);
636 635 sfree(lc->who);
637 636 sfree(lc->cred);
638 637
639 638 /* Delete structure with both mutex:es held */
640 639
641 640 free(lc);
642 641
643 642 return (LDAP_UNAVAILABLE);
644 643 }
645 644
646 645 /*
647 646 * Disconnect the specified LDAP connection. Caller must have acquired 'mutex'.
648 647 *
649 648 * On return, if the status is LDAP_UNAVAILABLE, the caller must not touch
650 649 * the structure in any way.
651 650 */
652 651 static int
653 652 disconnectCon(__nis_ldap_conn_t *lc) {
654 653 int stat;
655 654 char *myself = "disconnectCon";
656 655
657 656 if (lc == 0)
658 657 return (LDAP_SUCCESS);
659 658
660 659 if (!assertExclusive(lc))
661 660 return (LDAP_UNAVAILABLE);
662 661
663 662 if (lc->doDis) {
664 663
665 664 /* Increment refCount to protect against interference */
666 665 incrementRC(lc);
667 666 /* refCount must be one (i.e., just us) */
668 667 if (lc->refCount != 1) {
669 668 /*
670 669 * In use; already marked for disconnect,
671 670 * so do nothing.
672 671 */
673 672 decrementRC(lc);
674 673 return (LDAP_BUSY);
675 674 }
676 675
677 676 stat = ldap_unbind_s(lc->ld);
678 677 if (stat == LDAP_SUCCESS) {
679 678 lc->ld = 0;
680 679 lc->isBound = 0;
681 680 lc->doDis = 0;
682 681 /* Reset simple page and vlv indication */
683 682 lc->simplePage = 0;
684 683 lc->vlv = 0;
685 684 } else if (verbose) {
686 685 logmsg(MSG_NOTIMECHECK, LOG_ERR,
687 686 "%s: ldap_unbind_s() => %d (%s)",
688 687 myself, stat, ldap_err2string(stat));
689 688 }
690 689
691 690 decrementRC(lc);
692 691 }
693 692
694 693 if (lc->doDel) {
695 694 if (LDAP_UNAVAILABLE == freeCon(lc))
696 695 stat = LDAP_UNAVAILABLE;
697 696 }
698 697
699 698 return (stat);
700 699 }
701 700
702 701 /*
703 702 * controlSupported will determine for a given connection whether a set
704 703 * of controls is supported or not. The input parameters:
705 704 * lc The connection
706 705 * ctrl A an array of OID strings, the terminal string should be NULL
707 706 * The returned values if LDAP_SUCCESS is returned:
708 707 * supported A caller supplied array which will be set to TRUE or
709 708 * FALSE depending on whether the corresponding control
710 709 * is reported as supported.
711 710 * Returns LDAP_SUCCESS if the supportedControl attribute is read.
712 711 */
713 712
714 713 static int
715 714 controlSupported(__nis_ldap_conn_t *lc, char **ctrl, bool_t *supported) {
716 715 LDAPMessage *res, *e;
717 716 char *attr[2], *a, **val;
718 717 int stat, i;
719 718 BerElement *ber = 0;
720 719 char *myself = "controlSupported";
721 720
722 721 attr[0] = "supportedControl";
723 722 attr[1] = 0;
724 723
725 724 stat = ldap_search_st(lc->ld, "", LDAP_SCOPE_BASE, "(objectclass=*)",
726 725 attr, 0, &lc->searchTimeout, &res);
727 726 if (stat != LDAP_SUCCESS) {
728 727 logmsg(MSG_NOTIMECHECK, LOG_WARNING,
729 728 "%s: Unable to retrieve supported control information for %s: %s",
730 729 myself, NIL(lc->sp), ldap_err2string(stat));
731 730 return (stat);
732 731 }
733 732
734 733 e = ldap_first_entry(lc->ld, res);
735 734 if (e != 0) {
736 735 a = ldap_first_attribute(lc->ld, e, &ber);
737 736 if (a != 0) {
738 737 val = ldap_get_values(lc->ld, e, a);
739 738 if (val == 0) {
740 739 ldap_memfree(a);
741 740 if (ber != 0)
742 741 ber_free(ber, 0);
743 742 }
744 743 }
745 744 }
746 745 if (e == 0 || a == 0 || val == 0) {
747 746 ldap_msgfree(res);
748 747 logmsg(MSG_NOTIMECHECK, LOG_INFO,
749 748 "%s: Unable to get root DSE for %s",
750 749 myself, NIL(lc->sp));
751 750 return (LDAP_OPERATIONS_ERROR);
752 751 }
753 752
754 753 while (*ctrl != NULL) {
755 754 *supported = FALSE;
756 755 for (i = 0; val[i] != 0; i++) {
757 756 if (strstr(val[i], *ctrl) != 0) {
758 757 *supported = TRUE;
759 758 break;
760 759 }
761 760 }
762 761 logmsg(MSG_NOTIMECHECK, LOG_INFO,
763 762 "%s: %s: %s: %s",
764 763 myself, NIL(lc->sp), NIL(*ctrl),
765 764 *supported ? "enabled" : "disabled");
766 765 ctrl++;
767 766 supported++;
768 767 }
769 768
770 769 ldap_value_free(val);
771 770 ldap_memfree(a);
772 771 if (ber != 0)
773 772 ber_free(ber, 0);
774 773 ldap_msgfree(res);
775 774
776 775 return (stat);
777 776 }
778 777
779 778 /*
780 779 * Connect the LDAP connection 'lc'. Caller must have acquired the 'mutex',
781 780 * and the refCount must be zero.
782 781 *
783 782 * On return, if the status is LDAP_UNAVAILABLE, the caller must not touch
784 783 * the structure in any way.
785 784 */
786 785 static int
787 786 connectCon(__nis_ldap_conn_t *lc, int check_ctrl) {
788 787 struct timeval tp;
789 788 int stat;
790 789 bool_t supported[2] = {FALSE, FALSE};
791 790 char *ctrl[3] = {LDAP_CONTROL_SIMPLE_PAGE,
792 791 LDAP_CONTROL_VLVREQUEST,
793 792 NULL};
794 793
795 794 if (lc == 0)
796 795 return (LDAP_SUCCESS);
797 796
798 797 if (!assertExclusive(lc))
799 798 return (LDAP_PARAM_ERROR);
800 799
801 800 incrementRC(lc);
802 801 if (lc->refCount != 1) {
803 802 /*
804 803 * Don't want to step on structure when it's used by someone
805 804 * else.
806 805 */
807 806 decrementRC(lc);
808 807 return (LDAP_BUSY);
809 808 }
810 809
811 810 (void) gettimeofday(&tp, 0);
812 811
813 812 if (lc->ld != 0) {
814 813 /* Try to disconnect */
815 814 lc->doDis++;
816 815 decrementRC(lc);
817 816 /* disconnctCon() will do the delete if required */
818 817 stat = disconnectCon(lc);
819 818 if (stat != LDAP_SUCCESS)
820 819 return (stat);
821 820 incrementRC(lc);
822 821 if (lc->refCount != 1 || lc->ld != 0) {
823 822 decrementRC(lc);
824 823 return (lc->ld != 0) ? LDAP_SUCCESS :
825 824 LDAP_BUSY;
826 825 }
827 826 } else if (tp.tv_sec < lc->retryTime) {
828 827 /* Too early to retry connect */
829 828 decrementRC(lc);
830 829 return (LDAP_SERVER_DOWN);
831 830 }
832 831
833 832 /* Set new retry time in case we fail below */
834 833 lc->retryTime = tp.tv_sec + ldapConnAttemptRetryTimeout;
835 834
836 835 lc->ld = ldapInit(lc->sp, lc->port, proxyInfo.tls_method != no_tls);
837 836 if (lc->ld == 0) {
838 837 decrementRC(lc);
839 838 return (LDAP_LOCAL_ERROR);
840 839 }
841 840
842 841 stat = lc->status = ldapBind(&lc->ld, lc->who, lc->cred, lc->method,
843 842 lc->bindTimeout);
844 843 if (lc->status == LDAP_SUCCESS) {
845 844 lc->isBound = 1;
846 845 lc->retryTime = 0;
847 846 if (check_ctrl) {
848 847 (void) controlSupported(lc, ctrl, supported);
849 848 lc->simplePage = supported[0];
850 849 lc->vlv = supported[1];
851 850 lc->batchFrom = 50000;
852 851 }
853 852 }
854 853
855 854 decrementRC(lc);
856 855
857 856 return (stat);
858 857 }
859 858
860 859 /*
861 860 * Find and return a connection believed to be OK.
862 861 */
863 862 static __nis_ldap_conn_t *
864 863 findCon(int *stat) {
865 864 __nis_ldap_conn_t *lc;
866 865 int ldapStat;
867 866 char *myself = "findCon";
868 867
869 868 if (stat == 0)
870 869 stat = &ldapStat;
871 870
872 871 (void) rw_rdlock(&ldapConLock);
873 872
874 873 if (ldapCon == 0) {
875 874 /* Probably first call; try to set up the connection list */
876 875 (void) rw_unlock(&ldapConLock);
877 876 if ((*stat = setupConList(proxyInfo.default_servers,
878 877 proxyInfo.proxy_dn,
879 878 proxyInfo.proxy_passwd,
880 879 proxyInfo.auth_method)) !=
881 880 LDAP_SUCCESS)
882 881 return (0);
883 882 (void) rw_rdlock(&ldapConLock);
884 883 }
885 884
886 885 for (lc = ldapCon; lc != 0; lc = lc->next) {
887 886 exclusiveLC(lc);
888 887 if (!lc->isBound) {
889 888 *stat = connectCon(lc, 1);
890 889 if (*stat != LDAP_SUCCESS) {
891 890 if (*stat != LDAP_UNAVAILABLE) {
892 891 logmsg(MSG_NOTIMECHECK, LOG_WARNING,
893 892 "%s: Cannot open connection to LDAP server (%s): %s",
894 893 myself, NIL(lc->sp),
895 894 ldap_err2string(*stat));
896 895 releaseLC(lc);
897 896 }
898 897 continue;
899 898 }
900 899 } else if (lc->doDis || lc->doDel) {
901 900 *stat = disconnectCon(lc);
902 901 if (*stat != LDAP_UNAVAILABLE)
903 902 releaseLC(lc);
904 903 continue;
905 904 }
906 905 incrementRC(lc);
907 906 releaseLC(lc);
908 907 break;
909 908 }
910 909
911 910 (void) rw_unlock(&ldapConLock);
912 911
913 912 return (lc);
914 913 }
915 914
916 915 /* Release connection; decrements ref count for the connection */
917 916 static void
918 917 releaseCon(__nis_ldap_conn_t *lc, int status) {
919 918 int stat;
920 919
921 920 if (lc == 0)
922 921 return;
923 922
924 923 exclusiveLC(lc);
925 924
926 925 lc->status = status;
927 926
928 927 decrementRC(lc);
929 928
930 929 if (lc->doDis)
931 930 stat = disconnectCon(lc);
932 931 else
933 932 stat = LDAP_SUCCESS;
934 933
935 934 if (stat != LDAP_UNAVAILABLE)
936 935 releaseLC(lc);
937 936 }
938 937
939 938 static __nis_ldap_conn_t *
940 939 createCon(char *sp, char *who, char *cred, auth_method_t method, int port) {
941 940 __nis_ldap_conn_t *lc;
942 941 char *myself = "createCon";
943 942 char *r;
944 943
945 944 if (sp == 0)
946 945 return (0);
947 946
948 947 lc = am(myself, sizeof (*lc));
949 948 if (lc == 0)
950 949 return (0);
951 950
952 951 (void) mutex_init(&lc->mutex, 0, 0);
953 952 (void) mutex_init(&lc->rcMutex, 0, 0);
954 953
955 954 /* If we need to delete 'lc', freeCon() wants the mutex held */
956 955 exclusiveLC(lc);
957 956
958 957 lc->sp = sdup(myself, T, sp);
959 958 if (lc->sp == 0) {
960 959 (void) freeCon(lc);
961 960 return (0);
962 961 }
963 962
964 963 if ((r = strchr(lc->sp, ']')) != 0) {
965 964 /*
966 965 * IPv6 address. Does libldap want this with the
967 966 * '[' and ']' left in place ? Assume so for now.
968 967 */
969 968 r = strchr(r, ':');
970 969 } else {
971 970 r = strchr(lc->sp, ':');
972 971 }
973 972
974 973 if (r != NULL) {
975 974 *r++ = '\0';
976 975 port = atoi(r);
977 976 } else if (port == 0)
978 977 port = proxyInfo.tls_method == ssl_tls ? LDAPS_PORT : LDAP_PORT;
979 978
980 979 if (who != 0) {
981 980 lc->who = sdup(myself, T, who);
982 981 if (lc->who == 0) {
983 982 (void) freeCon(lc);
984 983 return (0);
985 984 }
986 985 }
987 986
988 987 if (cred != 0) {
989 988 lc->cred = sdup(myself, T, cred);
990 989 if (lc->cred == 0) {
991 990 (void) freeCon(lc);
992 991 return (0);
993 992 }
994 993 }
995 994
996 995 lc->method = method;
997 996 lc->port = port;
998 997
999 998 lc->bindTimeout = proxyInfo.bind_timeout;
1000 999 lc->searchTimeout = proxyInfo.search_timeout;
1001 1000 lc->modifyTimeout = proxyInfo.modify_timeout;
1002 1001 lc->addTimeout = proxyInfo.add_timeout;
1003 1002 lc->deleteTimeout = proxyInfo.delete_timeout;
1004 1003
1005 1004 /* All other fields OK at zero */
1006 1005
1007 1006 releaseLC(lc);
1008 1007
1009 1008 return (lc);
1010 1009 }
1011 1010
1012 1011 static int
1013 1012 setupConList(char *serverList, char *who, char *cred, auth_method_t method) {
1014 1013 char *sls, *sl, *s, *e;
1015 1014 __nis_ldap_conn_t *lc, *tmp;
1016 1015 char *myself = "setupConList";
1017 1016
1018 1017 if (serverList == 0)
1019 1018 return (LDAP_PARAM_ERROR);
1020 1019
1021 1020 (void) rw_wrlock(&ldapConLock);
1022 1021
1023 1022 if (ldapCon != 0) {
1024 1023 /* Assume we've already been called and done the set-up */
1025 1024 (void) rw_unlock(&ldapConLock);
1026 1025 return (LDAP_SUCCESS);
↓ open down ↓ |
395 lines elided |
↑ open up ↑ |
1027 1026 }
1028 1027
1029 1028 /* Work on a copy of 'serverList' */
1030 1029 sl = sls = sdup(myself, T, serverList);
1031 1030 if (sl == 0) {
1032 1031 (void) rw_unlock(&ldapConLock);
1033 1032 return (LDAP_NO_MEMORY);
1034 1033 }
1035 1034
1036 1035 /* Remove leading white space */
1037 - for (0; *sl == ' ' || *sl == '\t'; sl++);
1036 + for (; *sl == ' ' || *sl == '\t'; sl++);
1038 1037
1039 1038 /* Create connection for each server on the list */
1040 1039 for (s = sl; *s != '\0'; s = e+1) {
1041 1040 int l;
1042 1041
1043 1042 /* Find end of server/port token */
1044 1043 for (e = s; *e != ' ' && *e != '\t' && *e != '\0'; e++);
1045 1044 if (*e != '\0')
1046 1045 *e = '\0';
1047 1046 else
1048 1047 e--;
1049 1048 l = slen(s);
1050 1049
1051 1050 if (l > 0) {
1052 1051 lc = createCon(s, who, cred, method, 0);
1053 1052 if (lc == 0) {
1054 1053 free(sls);
1055 1054 (void) rw_unlock(&ldapConLock);
1056 1055 return (LDAP_NO_MEMORY);
1057 1056 }
1058 1057 lc->onList = 1;
1059 1058 if (ldapCon == 0) {
1060 1059 ldapCon = lc;
1061 1060 } else {
1062 1061 /* Insert at end of list */
1063 1062 for (tmp = ldapCon; tmp->next != 0;
1064 1063 tmp = tmp->next);
1065 1064 tmp->next = lc;
1066 1065 }
1067 1066 }
1068 1067 }
1069 1068
1070 1069 free(sls);
1071 1070
1072 1071 (void) rw_unlock(&ldapConLock);
1073 1072
1074 1073 return (LDAP_SUCCESS);
1075 1074 }
1076 1075
1077 1076 static bool_t
1078 1077 is_same_connection(__nis_ldap_conn_t *lc, LDAPURLDesc *ludpp)
1079 1078 {
1080 1079 return (strcasecmp(ludpp->lud_host, lc->sp) == 0 &&
1081 1080 ludpp->lud_port == lc->port);
1082 1081 }
1083 1082
1084 1083 static __nis_ldap_conn_t *
1085 1084 find_connection_from_list(__nis_ldap_conn_t *list,
1086 1085 LDAPURLDesc *ludpp, int *stat)
1087 1086 {
1088 1087 int ldapStat;
1089 1088 __nis_ldap_conn_t *lc = NULL;
1090 1089 if (stat == 0)
1091 1090 stat = &ldapStat;
1092 1091
1093 1092 *stat = LDAP_SUCCESS;
1094 1093
1095 1094 for (lc = list; lc != 0; lc = lc->next) {
1096 1095 exclusiveLC(lc);
1097 1096 if (is_same_connection(lc, ludpp)) {
1098 1097 if (!lc->isBound) {
1099 1098 *stat = connectCon(lc, 1);
1100 1099 if (*stat != LDAP_SUCCESS) {
1101 1100 releaseLC(lc);
1102 1101 continue;
1103 1102 }
1104 1103 } else if (lc->doDis || lc->doDel) {
1105 1104 (void) disconnectCon(lc);
1106 1105 releaseLC(lc);
1107 1106 continue;
1108 1107 }
1109 1108 incrementRC(lc);
1110 1109 releaseLC(lc);
1111 1110 break;
1112 1111 }
1113 1112 releaseLC(lc);
1114 1113 }
1115 1114 return (lc);
1116 1115 }
1117 1116
1118 1117 static __nis_ldap_conn_t *
1119 1118 findReferralCon(char **referralsp, int *stat)
1120 1119 {
1121 1120 __nis_ldap_conn_t *lc = NULL;
1122 1121 __nis_ldap_conn_t *tmp;
1123 1122 int ldapStat;
1124 1123 int i;
1125 1124 LDAPURLDesc *ludpp = NULL;
1126 1125 char *myself = "findReferralCon";
1127 1126
1128 1127 if (stat == 0)
1129 1128 stat = &ldapStat;
1130 1129
1131 1130 *stat = LDAP_SUCCESS;
1132 1131
1133 1132 /*
1134 1133 * We have the referral lock - to prevent multiple
1135 1134 * threads from creating a referred connection simultaneously
1136 1135 *
1137 1136 * Note that this code assumes that the ldapCon list is a
1138 1137 * static list - that it has previously been created
1139 1138 * (otherwise we wouldn't have gotten a referral) and that
1140 1139 * it will neither grow or shrink - elements may have new
1141 1140 * connections or unbound. If this assumption is no longer valid,
1142 1141 * the locking needs to be reworked.
1143 1142 */
1144 1143 (void) rw_rdlock(&referralConLock);
1145 1144
1146 1145 for (i = 0; referralsp[i] != NULL; i++) {
1147 1146 if (ldap_url_parse(referralsp[i], &ludpp) != LDAP_SUCCESS)
1148 1147 continue;
1149 1148 /* Ignore referrals if not at the appropriate tls level */
1150 1149 #ifdef LDAP_URL_OPT_SECURE
1151 1150 if (ludpp->lud_options & LDAP_URL_OPT_SECURE) {
1152 1151 if (proxyInfo.tls_method != ssl_tls) {
1153 1152 ldap_free_urldesc(ludpp);
1154 1153 continue;
1155 1154 }
1156 1155 } else {
1157 1156 if (proxyInfo.tls_method != no_tls) {
1158 1157 ldap_free_urldesc(ludpp);
1159 1158 continue;
1160 1159 }
1161 1160 }
1162 1161 #endif
1163 1162
1164 1163 /* Determine if we already have a connection to the server */
1165 1164 lc = find_connection_from_list(ldapReferralCon, ludpp, stat);
1166 1165 if (lc == NULL)
1167 1166 lc = find_connection_from_list(ldapCon, ludpp, stat);
1168 1167 ldap_free_urldesc(ludpp);
1169 1168 if (lc != NULL) {
1170 1169 (void) rw_unlock(&referralConLock);
1171 1170 return (lc);
1172 1171 }
1173 1172 }
1174 1173
1175 1174 for (i = 0; referralsp[i] != NULL; i++) {
1176 1175 if (ldap_url_parse(referralsp[i], &ludpp) != LDAP_SUCCESS)
1177 1176 continue;
1178 1177 /* Ignore referrals if not at the appropriate tls level */
1179 1178 #ifdef LDAP_URL_OPT_SECURE
1180 1179 if (ludpp->lud_options & LDAP_URL_OPT_SECURE) {
1181 1180 if (proxyInfo.tls_method != ssl_tls) {
1182 1181 ldap_free_urldesc(ludpp);
1183 1182 continue;
1184 1183 }
1185 1184 } else {
1186 1185 if (proxyInfo.tls_method != no_tls) {
1187 1186 ldap_free_urldesc(ludpp);
1188 1187 continue;
1189 1188 }
1190 1189 }
1191 1190 #endif
1192 1191 lc = createCon(ludpp->lud_host, proxyInfo.proxy_dn,
1193 1192 proxyInfo.proxy_passwd,
1194 1193 proxyInfo.auth_method,
1195 1194 ludpp->lud_port);
1196 1195 if (lc == 0) {
1197 1196 ldap_free_urldesc(ludpp);
1198 1197 (void) rw_unlock(&referralConLock);
1199 1198 *stat = LDAP_NO_MEMORY;
1200 1199 logmsg(MSG_NOTIMECHECK, LOG_INFO,
1201 1200 "%s: Could not connect to host: %s",
1202 1201 myself, NIL(ludpp->lud_host));
1203 1202 return (NULL);
1204 1203 }
1205 1204
1206 1205 lc->onList = 1;
1207 1206 if (ldapReferralCon == 0) {
1208 1207 ldapReferralCon = lc;
1209 1208 } else {
1210 1209 /* Insert at end of list */
1211 1210 for (tmp = ldapReferralCon; tmp->next != 0;
1212 1211 tmp = tmp->next) {}
1213 1212 tmp->next = lc;
1214 1213 }
1215 1214 lc = find_connection_from_list(ldapReferralCon, ludpp, stat);
1216 1215 ldap_free_urldesc(ludpp);
1217 1216 if (lc != NULL)
1218 1217 break;
1219 1218 }
1220 1219 (void) rw_unlock(&referralConLock);
1221 1220 if (lc == NULL) {
1222 1221 logmsg(MSG_NOTIMECHECK, LOG_INFO,
1223 1222 "%s: Could not find a connection to %s, ...",
1224 1223 myself, NIL(referralsp[0]));
1225 1224 }
1226 1225
1227 1226 return (lc);
1228 1227 }
1229 1228
1230 1229 /*
1231 1230 * Find and return a connection believed to be OK and ensure children
1232 1231 * will never use parent's connection.
1233 1232 */
1234 1233 static __nis_ldap_conn_t *
1235 1234 findYPCon(__nis_ldap_search_t *ls, int *stat) {
1236 1235 __nis_ldap_conn_t *lc, *newlc;
1237 1236 int ldapStat, newstat;
1238 1237 char *myself = "findYPCon";
1239 1238
1240 1239 if (stat == 0)
1241 1240 stat = &ldapStat;
1242 1241
1243 1242 (void) rw_rdlock(&ldapConLock);
1244 1243
1245 1244 if (ldapCon == 0) {
1246 1245 /* Probably first call; try to set up the connection list */
1247 1246 (void) rw_unlock(&ldapConLock);
1248 1247 if ((*stat = setupConList(proxyInfo.default_servers,
1249 1248 proxyInfo.proxy_dn,
1250 1249 proxyInfo.proxy_passwd,
1251 1250 proxyInfo.auth_method)) !=
1252 1251 LDAP_SUCCESS)
1253 1252 return (0);
1254 1253 (void) rw_rdlock(&ldapConLock);
1255 1254 }
1256 1255
1257 1256 for (lc = ldapCon; lc != 0; lc = lc->next) {
1258 1257 exclusiveLC(lc);
1259 1258
1260 1259 if (lc->isBound && (lc->doDis || lc->doDel)) {
1261 1260 *stat = disconnectCon(lc);
1262 1261 if (*stat != LDAP_UNAVAILABLE)
1263 1262 releaseLC(lc);
1264 1263 continue;
1265 1264 }
1266 1265
1267 1266 /*
1268 1267 * Use a new connection for all cases except when
1269 1268 * requested by the main thread in the parent ypserv
1270 1269 * process.
1271 1270 */
1272 1271 if (ls->useCon == 0) {
1273 1272 newlc = createCon(lc->sp, lc->who, lc->cred,
1274 1273 lc->method, lc->port);
1275 1274 if (!newlc) {
1276 1275 releaseLC(lc);
1277 1276 continue;
1278 1277 }
1279 1278 if (lc->ld != 0) {
1280 1279 newlc->simplePage = lc->simplePage;
1281 1280 newlc->vlv = lc->vlv;
1282 1281 newlc->batchFrom = lc->batchFrom;
1283 1282 }
1284 1283 releaseLC(lc);
1285 1284 exclusiveLC(newlc);
1286 1285 newstat = connectCon(newlc, 0);
1287 1286 if (newstat != LDAP_SUCCESS) {
1288 1287 if (newstat != LDAP_UNAVAILABLE) {
1289 1288 logmsg(MSG_NOTIMECHECK, LOG_WARNING,
1290 1289 "%s: Cannot open connection to LDAP server (%s): %s",
1291 1290 myself, NIL(newlc->sp),
1292 1291 ldap_err2string(*stat));
1293 1292 }
1294 1293 (void) freeCon(newlc);
1295 1294 newlc = 0;
1296 1295 continue;
1297 1296 }
1298 1297
1299 1298 /*
1300 1299 * No need to put newlc on the ldapCon list as this
1301 1300 * connection will be freed after use.
1302 1301 */
1303 1302 newlc->onList = 0;
1304 1303
1305 1304 lc = newlc;
1306 1305 } else if (!lc->isBound) {
1307 1306 *stat = connectCon(lc, 1);
1308 1307 if (*stat != LDAP_SUCCESS) {
1309 1308 if (*stat != LDAP_UNAVAILABLE) {
1310 1309 logmsg(MSG_NOTIMECHECK, LOG_WARNING,
1311 1310 "%s: Cannot open connection to LDAP server (%s): %s",
1312 1311 myself, NIL(lc->sp),
1313 1312 ldap_err2string(*stat));
1314 1313 releaseLC(lc);
1315 1314 }
1316 1315 continue;
1317 1316 }
1318 1317 }
1319 1318
1320 1319 incrementRC(lc);
1321 1320 releaseLC(lc);
1322 1321 break;
1323 1322 }
1324 1323
1325 1324 (void) rw_unlock(&ldapConLock);
1326 1325
1327 1326 return (lc);
1328 1327 }
1329 1328
1330 1329 #define SORTKEYLIST "cn uid"
1331 1330
1332 1331 /*
1333 1332 * Perform an LDAP search operation per 'ls', adding the result(s) to
1334 1333 * a copy of the 'rvIn' structure; the copy becomes the return value.
1335 1334 * The caller must deallocate both 'rvIn' and the result, if any.
1336 1335 *
1337 1336 * On entry, '*numValues' contains a hint regarding the expected
1338 1337 * number of entries. Zero is the same as one, and negative values
1339 1338 * imply no information. This is used to decide whether or not to
1340 1339 * try an indexed search.
1341 1340 *
1342 1341 * On successful (non-NULL) return, '*numValues' contains the number
1343 1342 * of __nis_rule_value_t elements in the returned array, and '*stat'
1344 1343 * the LDAP operations status.
1345 1344 */
1346 1345 __nis_rule_value_t *
1347 1346 ldapSearch(__nis_ldap_search_t *ls, int *numValues, __nis_rule_value_t *rvIn,
1348 1347 int *ldapStat) {
1349 1348 __nis_rule_value_t *rv = 0;
1350 1349 int stat, numEntries, numVals, tnv, done, lprEc;
1351 1350 LDAPMessage *msg = 0, *m;
1352 1351 __nis_ldap_conn_t *lc;
1353 1352 struct timeval tv, start, now;
1354 1353 LDAPsortkey **sortKeyList = 0;
1355 1354 LDAPControl *ctrls[3], *sortCtrl = 0, *vlvCtrl = 0;
1356 1355 LDAPControl **retCtrls = 0;
1357 1356 LDAPVirtualList vList;
1358 1357 struct berval *spCookie = 0;
1359 1358 int doVLV = 0;
1360 1359 int doSP = 0;
1361 1360 long index;
1362 1361 char *myself = "ldapSearch";
1363 1362 bool_t follow_referral =
1364 1363 proxyInfo.follow_referral == follow;
1365 1364 int doIndex = 1;
1366 1365 char **referralsp = NULL;
1367 1366
1368 1367 ctrls[0] = ctrls[1] = ctrls[2] = 0;
1369 1368
1370 1369 if (ldapStat == 0)
1371 1370 ldapStat = &stat;
1372 1371
1373 1372 if (ls == 0) {
1374 1373 *ldapStat = LDAP_PARAM_ERROR;
1375 1374 return (0);
1376 1375 }
1377 1376
1378 1377 if (yp2ldap) {
1379 1378 /* make sure the parent's connection is not used by child */
1380 1379 if ((lc = findYPCon(ls, ldapStat)) == 0) {
1381 1380 *ldapStat = LDAP_SERVER_DOWN;
1382 1381 return (0);
1383 1382 }
1384 1383 } else {
1385 1384 if ((lc = findCon(ldapStat)) == 0) {
1386 1385 *ldapStat = LDAP_SERVER_DOWN;
1387 1386 return (0);
1388 1387 }
1389 1388 }
1390 1389
1391 1390 if (numValues != 0 && (*numValues == 0 || *numValues == 1))
1392 1391 doIndex = 0;
1393 1392
1394 1393 retry_new_conn:
1395 1394 /* Prefer VLV over simple page, and SP over nothing */
1396 1395 if (doIndex && lc->vlv) {
1397 1396 stat = ldap_create_sort_keylist(&sortKeyList, SORTKEYLIST);
1398 1397 if (stat != LDAP_SUCCESS) {
1399 1398 logmsg(MSG_NOTIMECHECK, LOG_INFO,
1400 1399 "%s: Error creating sort keylist: %s",
1401 1400 myself, ldap_err2string(stat));
1402 1401 freeRuleValue(rv, numVals);
1403 1402 *ldapStat = stat;
1404 1403 rv = 0;
1405 1404 goto retry_noVLV;
1406 1405 }
1407 1406 stat = ldap_create_sort_control(lc->ld, sortKeyList, 1,
1408 1407 &sortCtrl);
1409 1408 if (stat == LDAP_SUCCESS) {
1410 1409 vList.ldvlist_before_count = 0;
1411 1410 vList.ldvlist_after_count = lc->batchFrom - 1;
1412 1411 vList.ldvlist_attrvalue = 0;
1413 1412 vList.ldvlist_extradata = 0;
1414 1413 index = 1;
1415 1414 doVLV = 1;
1416 1415 } else {
1417 1416 ldap_get_option(lc->ld, LDAP_OPT_ERROR_NUMBER, &stat);
1418 1417 logmsg(MSG_NOTIMECHECK, LOG_INFO,
1419 1418 "%s: Error creating VLV sort control: %s",
1420 1419 myself, ldap_err2string(stat));
1421 1420 freeRuleValue(rv, numVals);
1422 1421 *ldapStat = stat;
1423 1422 rv = 0;
1424 1423 }
1425 1424 }
1426 1425
1427 1426 retry_noVLV:
1428 1427
1429 1428 if (doIndex && !doVLV && lc->simplePage) {
1430 1429 spCookie = am(myself, sizeof (*spCookie));
1431 1430 if (spCookie != 0 &&
1432 1431 (spCookie->bv_val = sdup(myself, T, "")) != 0) {
1433 1432 spCookie->bv_len = 0;
1434 1433 doSP = 1;
1435 1434 } else {
1436 1435 logmsg(MSG_NOTIMECHECK, LOG_INFO,
1437 1436 "%s: No memory for simple page cookie; using un-paged LDAP search",
1438 1437 myself);
1439 1438 freeRuleValue(rv, numVals);
1440 1439 *ldapStat = stat;
1441 1440 rv = 0;
1442 1441 goto cleanup;
1443 1442 }
1444 1443 }
1445 1444
1446 1445 if (!doVLV && !doSP)
1447 1446 ctrls[0] = ctrls[1] = 0;
1448 1447
1449 1448 numVals = 0;
1450 1449 done = 0;
1451 1450
1452 1451 if (ls->timeout.tv_sec || ls->timeout.tv_usec) {
1453 1452 tv = ls->timeout;
1454 1453 } else {
1455 1454 tv = lc->searchTimeout;
1456 1455 }
1457 1456 (void) gettimeofday(&start, 0);
1458 1457
1459 1458 do {
1460 1459 /* don't do vlv or simple page for base level searches */
1461 1460 if (doVLV && ls->base != LDAP_SCOPE_BASE) {
1462 1461 vList.ldvlist_index = index;
1463 1462 vList.ldvlist_size = 0;
1464 1463 if (vlvCtrl != 0)
1465 1464 ldap_control_free(vlvCtrl);
1466 1465 stat = ldap_create_virtuallist_control(lc->ld,
1467 1466 &vList, &vlvCtrl);
1468 1467 if (stat != LDAP_SUCCESS) {
1469 1468 ldap_get_option(lc->ld, LDAP_OPT_ERROR_NUMBER,
1470 1469 &stat);
1471 1470 logmsg(MSG_NOTIMECHECK, LOG_ERR,
1472 1471 "%s: Error creating VLV at index %ld: %s",
1473 1472 myself, index, ldap_err2string(stat));
1474 1473 *ldapStat = stat;
1475 1474 freeRuleValue(rv, numVals);
1476 1475 rv = 0;
1477 1476 goto cleanup;
1478 1477 }
1479 1478 ctrls[0] = sortCtrl;
1480 1479 ctrls[1] = vlvCtrl;
1481 1480 ctrls[2] = 0;
1482 1481 stat = ldap_search_ext_s(lc->ld, ls->base,
1483 1482 ls->scope, ls->filter, ls->attrs,
1484 1483 ls->attrsonly, ctrls, 0, &tv,
1485 1484 proxyInfo.search_size_limit, &msg);
1486 1485 /* don't do vlv or simple page for base level searches */
1487 1486 } else if (doSP && ls->base != LDAP_SCOPE_BASE) {
1488 1487 if (ctrls[0] != 0)
1489 1488 ldap_control_free(ctrls[0]);
1490 1489 stat = ldap_create_page_control(lc->ld,
1491 1490 lc->batchFrom, spCookie, 0, &ctrls[0]);
1492 1491 if (stat != LDAP_SUCCESS) {
1493 1492 ber_bvfree(spCookie);
1494 1493 spCookie = 0;
1495 1494 ldap_get_option(lc->ld, LDAP_OPT_ERROR_NUMBER,
1496 1495 &stat);
1497 1496 logmsg(MSG_NOTIMECHECK, LOG_ERR,
1498 1497 "%s: Simple page error: %s",
1499 1498 myself, ldap_err2string(stat));
1500 1499 freeRuleValue(rv, numVals);
1501 1500 *ldapStat = stat;
1502 1501 rv = 0;
1503 1502 goto cleanup;
1504 1503 }
1505 1504 ctrls[1] = 0;
1506 1505 stat = ldap_search_ext_s(lc->ld, ls->base,
1507 1506 ls->scope, ls->filter, ls->attrs,
1508 1507 ls->attrsonly, ctrls, 0, &tv,
1509 1508 proxyInfo.search_size_limit, &msg);
1510 1509 } else {
1511 1510 stat = ldap_search_st(lc->ld, ls->base, ls->scope,
1512 1511 ls->filter, ls->attrs, ls->attrsonly,
1513 1512 &tv, &msg);
1514 1513 }
1515 1514 if (stat == LDAP_SUCCESS)
1516 1515 ldap_get_option(lc->ld, LDAP_OPT_ERROR_NUMBER, &stat);
1517 1516
1518 1517 if (stat == LDAP_SERVER_DOWN) {
1519 1518 lc->doDis++;
1520 1519 releaseCon(lc, stat);
1521 1520 lc = (yp2ldap)?findYPCon(ls, ldapStat):
1522 1521 findCon(ldapStat);
1523 1522 if (lc == 0) {
1524 1523 *ldapStat = LDAP_SERVER_DOWN;
1525 1524 rv = 0;
1526 1525 goto cleanup;
1527 1526 }
1528 1527 goto retry_new_conn;
1529 1528 }
1530 1529
1531 1530 if (stat == LDAP_REFERRAL && follow_referral) {
1532 1531 (void) ldap_parse_result(lc->ld, msg, NULL, NULL, NULL,
1533 1532 &referralsp, NULL, 0);
1534 1533 if (referralsp != NULL) {
1535 1534 /* We support at most one level of referrals */
1536 1535 follow_referral = FALSE;
1537 1536 releaseCon(lc, stat);
1538 1537 lc = findReferralCon(referralsp, &stat);
1539 1538 ldap_value_free(referralsp);
1540 1539 if (lc == NULL) {
1541 1540 freeRuleValue(rv, numVals);
1542 1541 rv = 0;
1543 1542 *ldapStat = stat;
1544 1543 goto cleanup;
1545 1544 }
1546 1545 stat = LDAP_SUCCESS;
1547 1546 goto retry_new_conn;
1548 1547 }
1549 1548 }
1550 1549 *ldapStat = stat;
1551 1550
1552 1551 if (*ldapStat == LDAP_NO_SUCH_OBJECT) {
1553 1552 freeRuleValue(rv, numVals);
1554 1553 rv = 0;
1555 1554 goto cleanup;
1556 1555 } else if (doVLV && *ldapStat == LDAP_INSUFFICIENT_ACCESS) {
1557 1556 /*
1558 1557 * The LDAP server (at least Netscape 4.x) can return
1559 1558 * LDAP_INSUFFICIENT_ACCESS when VLV is supported,
1560 1559 * but not for the bind DN specified. So, just in
1561 1560 * case, we clean up, and try again without VLV.
1562 1561 */
1563 1562 doVLV = 0;
1564 1563 if (msg != 0) {
1565 1564 (void) ldap_msgfree(msg);
1566 1565 msg = 0;
1567 1566 }
1568 1567 if (ctrls[0] != 0) {
1569 1568 ldap_control_free(ctrls[0]);
1570 1569 ctrls[0] = 0;
1571 1570 }
1572 1571 if (ctrls[1] != 0) {
1573 1572 ldap_control_free(ctrls[1]);
1574 1573 ctrls[1] = 0;
1575 1574 }
1576 1575 logmsg(MSG_VLV_INSUFF_ACC, LOG_WARNING,
1577 1576 "%s: VLV insufficient access from server %s; retrying without VLV",
1578 1577 myself, NIL(lc->sp));
1579 1578 goto retry_noVLV;
1580 1579 } else if (*ldapStat != LDAP_SUCCESS) {
1581 1580 logmsg(MSG_NOTIMECHECK, LOG_WARNING,
1582 1581 "ldap_search(0x%x,\n\t\"%s\",\n\t %d,",
1583 1582 lc->ld, NIL(ls->base), ls->scope);
1584 1583 logmsg(MSG_NOTIMECHECK, LOG_WARNING,
1585 1584 "\t\"%s\",\n\t0x%x,\n\t%d) => %d (%s)",
1586 1585 NIL(ls->filter), ls->attrs, ls->attrsonly,
1587 1586 *ldapStat, ldap_err2string(stat));
1588 1587 freeRuleValue(rv, numVals);
1589 1588 rv = 0;
1590 1589 goto cleanup;
1591 1590 }
1592 1591
1593 1592 numEntries = ldap_count_entries(lc->ld, msg);
1594 1593 if (numEntries == 0 && *ldapStat == LDAP_SUCCESS) {
1595 1594 /*
1596 1595 * This is a bit weird, but the server (or, at least,
1597 1596 * ldap_search_ext()) can sometimes return
1598 1597 * LDAP_SUCCESS and no entries when it didn't
1599 1598 * find what we were looking for. Seems it ought to
1600 1599 * return LDAP_NO_SUCH_OBJECT or some such.
1601 1600 */
1602 1601 freeRuleValue(rv, numVals);
1603 1602 rv = 0;
1604 1603 *ldapStat = LDAP_NO_SUCH_OBJECT;
1605 1604 goto cleanup;
1606 1605 }
1607 1606
1608 1607 tnv = numVals + numEntries;
1609 1608 if ((rv = growRuleValue(numVals, tnv, rv, rvIn)) == 0) {
1610 1609 *ldapStat = LDAP_NO_MEMORY;
1611 1610 goto cleanup;
1612 1611 }
1613 1612
1614 1613 for (m = ldap_first_entry(lc->ld, msg); m != 0;
1615 1614 m = ldap_next_entry(lc->ld, m), numVals++) {
1616 1615 char *nm;
1617 1616 BerElement *ber = 0;
1618 1617
1619 1618 if (numVals > tnv) {
1620 1619 logmsg(MSG_NOTIMECHECK, LOG_INFO,
1621 1620 "%s: Inconsistent LDAP entry count > %d",
1622 1621 myself, numEntries);
1623 1622 break;
1624 1623 }
1625 1624
1626 1625 nm = ldap_get_dn(lc->ld, m);
1627 1626 if (nm == 0 || addSAttr2RuleValue("dn", nm,
1628 1627 &rv[numVals])) {
1629 1628 sfree(nm);
1630 1629 *ldapStat = LDAP_NO_MEMORY;
1631 1630 freeRuleValue(rv, tnv);
1632 1631 rv = 0;
1633 1632 goto cleanup;
1634 1633 }
1635 1634 sfree(nm);
1636 1635
1637 1636 for (nm = ldap_first_attribute(lc->ld, m, &ber);
1638 1637 nm != 0;
1639 1638 nm = ldap_next_attribute(lc->ld, m, ber)) {
1640 1639 struct berval **val;
1641 1640 int i, nv;
1642 1641
1643 1642 val = ldap_get_values_len(lc->ld, m, nm);
1644 1643 nv = (val == 0) ? 0 :
1645 1644 ldap_count_values_len(val);
1646 1645 for (i = 0; i < nv; i++) {
1647 1646 /*
1648 1647 * Since we don't know if the value is
1649 1648 * BER-encoded or not, we mark it as a
1650 1649 * string. All is well as long as we
1651 1650 * don't insist on 'vt_ber' when
1652 1651 * interpreting.
1653 1652 */
1654 1653 if (addAttr2RuleValue(vt_string, nm,
1655 1654 val[i]->bv_val,
1656 1655 val[i]->bv_len,
1657 1656 &rv[numVals])) {
1658 1657 if (ber != 0)
1659 1658 ber_free(ber, 0);
1660 1659 ldap_value_free_len(val);
1661 1660 *ldapStat = LDAP_NO_MEMORY;
1662 1661 freeRuleValue(rv, tnv);
1663 1662 rv = 0;
1664 1663 goto cleanup;
1665 1664 }
1666 1665 }
1667 1666 ldap_memfree(nm);
1668 1667 if (val != 0)
1669 1668 ldap_value_free_len(val);
1670 1669 }
1671 1670 if (ber != 0)
1672 1671 ber_free(ber, 0);
1673 1672 }
1674 1673
1675 1674 if (numVals != tnv) {
1676 1675 logmsg(MSG_NOTIMECHECK, LOG_WARNING,
1677 1676 "%s: Inconsistent LDAP entry count, found = %d, expected %d",
1678 1677 myself, numVals, tnv);
1679 1678 }
1680 1679
1681 1680 if (doVLV) {
1682 1681 stat = ldap_parse_result(lc->ld, msg, &lprEc, 0, 0, 0,
1683 1682 &retCtrls, 0);
1684 1683 if (stat != LDAP_SUCCESS) {
1685 1684 ldap_get_option(lc->ld, LDAP_OPT_ERROR_NUMBER,
1686 1685 &stat);
1687 1686 logmsg(MSG_NOTIMECHECK, LOG_ERR,
1688 1687 "%s: VLV parse result error: %s",
1689 1688 myself, ldap_err2string(stat));
1690 1689 *ldapStat = stat;
1691 1690 freeRuleValue(rv, tnv);
1692 1691 rv = 0;
1693 1692 goto cleanup;
1694 1693 }
1695 1694 if (retCtrls != 0) {
1696 1695 unsigned long targetPosP = 0;
1697 1696 unsigned long listSize = 0;
1698 1697
1699 1698 stat = ldap_parse_virtuallist_control(lc->ld,
1700 1699 retCtrls, &targetPosP, &listSize,
1701 1700 &lprEc);
1702 1701 if (stat == LDAP_SUCCESS) {
1703 1702 index = targetPosP + lc->batchFrom;
1704 1703 if (index >= listSize)
1705 1704 done = 1;
1706 1705 }
1707 1706 ldap_controls_free(retCtrls);
1708 1707 retCtrls = 0;
1709 1708 } else {
1710 1709 done = 1;
1711 1710 }
1712 1711 } else if (doSP) {
1713 1712 stat = ldap_parse_result(lc->ld, msg, &lprEc, 0, 0, 0,
1714 1713 &retCtrls, 0);
1715 1714 if (stat != LDAP_SUCCESS) {
1716 1715 ldap_get_option(lc->ld, LDAP_OPT_ERROR_NUMBER,
1717 1716 &stat);
1718 1717 logmsg(MSG_NOTIMECHECK, LOG_ERR,
1719 1718 "%s: Simple page parse result error: %s",
1720 1719 myself, ldap_err2string(stat));
1721 1720 *ldapStat = stat;
1722 1721 freeRuleValue(rv, tnv);
1723 1722 rv = 0;
1724 1723 goto cleanup;
1725 1724 }
1726 1725 if (retCtrls != 0) {
1727 1726 unsigned int count;
1728 1727
1729 1728 if (spCookie != 0) {
1730 1729 ber_bvfree(spCookie);
1731 1730 spCookie = 0;
1732 1731 }
1733 1732 stat = ldap_parse_page_control(lc->ld,
1734 1733 retCtrls, &count, &spCookie);
1735 1734 if (stat == LDAP_SUCCESS) {
1736 1735 if (spCookie == 0 ||
1737 1736 spCookie->bv_val == 0 ||
1738 1737 spCookie->bv_len == 0)
1739 1738 done = 1;
1740 1739 }
1741 1740 ldap_controls_free(retCtrls);
1742 1741 retCtrls = 0;
1743 1742 } else {
1744 1743 done = 1;
1745 1744 }
1746 1745 } else {
1747 1746 done = 1;
1748 1747 }
1749 1748
1750 1749 (void) ldap_msgfree(msg);
1751 1750 msg = 0;
1752 1751
1753 1752 /*
1754 1753 * If we're using VLV or SP, the timeout should apply
1755 1754 * to all calls as an aggregate, so we need to reduce
1756 1755 * 'tv' with the time spent on this chunk of data.
1757 1756 */
1758 1757 if (!done) {
1759 1758 struct timeval tmp;
1760 1759
1761 1760 (void) gettimeofday(&now, 0);
1762 1761 tmp = now;
1763 1762 now.tv_sec -= start.tv_sec;
1764 1763 now.tv_usec -= start.tv_usec;
1765 1764 if (now.tv_usec < 0) {
1766 1765 now.tv_usec += 1000000;
1767 1766 now.tv_sec -= 1;
1768 1767 }
1769 1768 tv.tv_sec -= now.tv_sec;
1770 1769 tv.tv_usec -= now.tv_usec;
1771 1770 if (tv.tv_usec < 0) {
1772 1771 tv.tv_usec += 1000000;
1773 1772 tv.tv_sec -= 1;
1774 1773 }
1775 1774 if (tv.tv_sec < 0) {
1776 1775 *ldapStat = LDAP_TIMEOUT;
1777 1776 freeRuleValue(rv, tnv);
1778 1777 rv = 0;
1779 1778 goto cleanup;
1780 1779 }
1781 1780 start = tmp;
1782 1781 }
1783 1782
1784 1783 } while (!done);
1785 1784
1786 1785 if (numValues != 0)
1787 1786 *numValues = numVals;
1788 1787
1789 1788 cleanup:
1790 1789 if (NULL != lc) {
1791 1790 if (yp2ldap && ls->useCon == 0) {
1792 1791 /* Disconnect and free the connection */
1793 1792 lc->doDis++;
1794 1793 lc->doDel++;
1795 1794 releaseCon(lc, stat);
1796 1795 releaseLC(lc);
1797 1796
1798 1797 } else {
1799 1798 releaseCon(lc, stat);
1800 1799 }
1801 1800 }
1802 1801 if (msg != 0)
1803 1802 (void) ldap_msgfree(msg);
1804 1803 if (ctrls[0] != 0)
1805 1804 ldap_control_free(ctrls[0]);
1806 1805 if (ctrls[1] != 0)
1807 1806 ldap_control_free(ctrls[1]);
1808 1807 if (spCookie != 0)
1809 1808 ber_bvfree(spCookie);
1810 1809 if (sortKeyList != 0)
1811 1810 ldap_free_sort_keylist(sortKeyList);
1812 1811
1813 1812 return (rv);
1814 1813 }
1815 1814
1816 1815 static void
1817 1816 freeLdapModEntry(LDAPMod *m) {
1818 1817
1819 1818 if (m == 0)
1820 1819 return;
1821 1820
1822 1821 sfree(m->mod_type);
1823 1822 if ((m->mod_op & LDAP_MOD_BVALUES) == 0) {
1824 1823 char **v = m->mod_values;
1825 1824
1826 1825 if (v != 0) {
1827 1826 while (*v != 0) {
1828 1827 sfree(*v);
1829 1828 v++;
1830 1829 }
1831 1830 free(m->mod_values);
1832 1831 }
1833 1832 } else {
1834 1833 struct berval **b = m->mod_bvalues;
1835 1834
1836 1835 if (b != 0) {
1837 1836 while (*b != 0) {
1838 1837 sfree((*b)->bv_val);
1839 1838 free(*b);
1840 1839 b++;
1841 1840 }
1842 1841 free(m->mod_bvalues);
1843 1842 }
1844 1843 }
1845 1844
1846 1845 free(m);
1847 1846 }
1848 1847
1849 1848 static void
1850 1849 freeLdapMod(LDAPMod **mods) {
1851 1850 LDAPMod *m, **org = mods;
1852 1851
1853 1852 if (mods == 0)
1854 1853 return;
1855 1854
1856 1855 while ((m = *mods) != 0) {
1857 1856 freeLdapModEntry(m);
1858 1857 mods++;
1859 1858 }
1860 1859
1861 1860 free(org);
1862 1861 }
1863 1862
1864 1863 /*
1865 1864 * Convert a rule-value structure to the corresponding LDAPMod.
1866 1865 * If 'add' is set, attributes/values are added; object classes
1867 1866 * are also added. If 'add' is cleared, attributes/values are modified,
1868 1867 * and 'oc' controls whether or not object classes are added.
1869 1868 */
1870 1869 LDAPMod **
1871 1870 search2LdapMod(__nis_rule_value_t *rv, int add, int oc) {
1872 1871 LDAPMod **mods;
1873 1872 int i, j, nm;
1874 1873 char *myself = "search2LdapMod";
1875 1874
1876 1875 if (rv == 0 || rv->numAttrs <= 0)
1877 1876 return (0);
1878 1877
1879 1878 mods = am(myself, (rv->numAttrs + 1) * sizeof (mods[0]));
1880 1879 if (mods == 0)
1881 1880 return (0);
1882 1881
1883 1882 for (i = 0, nm = 0; i < rv->numAttrs; i++) {
1884 1883 int isOc;
1885 1884 /*
1886 1885 * If we're creating an LDAPMod array for an add operation,
1887 1886 * just skip attributes that should be deleted.
1888 1887 */
1889 1888 if (add && rv->attrVal[i].numVals < 0)
1890 1889 continue;
1891 1890
1892 1891 /*
1893 1892 * Skip DN; it's specified separately to ldap_modify()
1894 1893 * and ldap_add(), and mustn't appear among the
1895 1894 * attributes to be modified/added.
1896 1895 */
1897 1896 if (strcasecmp("dn", rv->attrName[i]) == 0)
1898 1897 continue;
1899 1898
1900 1899 /*
1901 1900 * If modifying, and 'oc' is off, skip object class
1902 1901 * attributes.
1903 1902 */
1904 1903 isOc = (strcasecmp("objectclass", rv->attrName[i]) == 0);
1905 1904 if (!add && !oc && isOc)
1906 1905 continue;
1907 1906
1908 1907 mods[nm] = am(myself, sizeof (*mods[nm]));
1909 1908 if (mods[nm] == 0) {
1910 1909 freeLdapMod(mods);
1911 1910 return (0);
1912 1911 }
1913 1912
1914 1913 /* 'mod_type' is the attribute name */
1915 1914 mods[nm]->mod_type = sdup(myself, T, rv->attrName[i]);
1916 1915 if (mods[nm]->mod_type == 0) {
1917 1916 freeLdapMod(mods);
1918 1917 return (0);
1919 1918 }
1920 1919
1921 1920 /*
1922 1921 * numVals < 0 means attribute and all values should
1923 1922 * be deleted.
1924 1923 */
1925 1924 if (rv->attrVal[i].numVals < 0) {
1926 1925 mods[nm]->mod_op = LDAP_MOD_DELETE;
1927 1926 mods[nm]->mod_values = 0;
1928 1927 nm++;
1929 1928 continue;
1930 1929 }
1931 1930
1932 1931 /* objectClass attributes always added */
1933 1932 mods[nm]->mod_op = (add) ? 0 : ((isOc) ? 0 : LDAP_MOD_REPLACE);
1934 1933
1935 1934 if (rv->attrVal[i].type == vt_string) {
1936 1935 /*
1937 1936 * mods[]->mod_values is a NULL-terminated array
1938 1937 * of (char *)'s.
1939 1938 */
1940 1939 mods[nm]->mod_values = am(myself,
1941 1940 (rv->attrVal[i].numVals + 1) *
1942 1941 sizeof (mods[nm]->mod_values[0]));
1943 1942 if (mods[nm]->mod_values == 0) {
1944 1943 freeLdapMod(mods);
1945 1944 return (0);
1946 1945 }
1947 1946 for (j = 0; j < rv->attrVal[i].numVals; j++) {
1948 1947 /*
1949 1948 * Just in case the string isn't NUL
1950 1949 * terminated, add one byte to the
1951 1950 * allocated length; am() will initialize
1952 1951 * the buffer to zero.
1953 1952 */
1954 1953 mods[nm]->mod_values[j] = am(myself,
1955 1954 rv->attrVal[i].val[j].length + 1);
1956 1955 if (mods[nm]->mod_values[j] == 0) {
1957 1956 freeLdapMod(mods);
1958 1957 return (0);
1959 1958 }
1960 1959 memcpy(mods[nm]->mod_values[j],
1961 1960 rv->attrVal[i].val[j].value,
1962 1961 rv->attrVal[i].val[j].length);
1963 1962 }
1964 1963 } else {
1965 1964 mods[nm]->mod_op |= LDAP_MOD_BVALUES;
1966 1965 mods[nm]->mod_bvalues = am(myself,
1967 1966 (rv->attrVal[i].numVals+1) *
1968 1967 sizeof (mods[nm]->mod_bvalues[0]));
1969 1968 if (mods[nm]->mod_bvalues == 0) {
1970 1969 freeLdapMod(mods);
1971 1970 return (0);
1972 1971 }
1973 1972 for (j = 0; j < rv->attrVal[i].numVals; j++) {
1974 1973 mods[nm]->mod_bvalues[j] = am(myself,
1975 1974 sizeof (*mods[nm]->mod_bvalues[j]));
1976 1975 if (mods[nm]->mod_bvalues[j] == 0) {
1977 1976 freeLdapMod(mods);
1978 1977 return (0);
1979 1978 }
1980 1979 mods[nm]->mod_bvalues[j]->bv_val = am(myself,
1981 1980 rv->attrVal[i].val[j].length);
1982 1981 if (mods[nm]->mod_bvalues[j]->bv_val == 0) {
1983 1982 freeLdapMod(mods);
1984 1983 return (0);
1985 1984 }
1986 1985 mods[nm]->mod_bvalues[j]->bv_len =
1987 1986 rv->attrVal[i].val[j].length;
1988 1987 memcpy(mods[nm]->mod_bvalues[j]->bv_val,
1989 1988 rv->attrVal[i].val[j].value,
1990 1989 mods[nm]->mod_bvalues[j]->bv_len);
1991 1990 }
1992 1991 }
1993 1992 nm++;
1994 1993 }
1995 1994
1996 1995 return (mods);
1997 1996 }
1998 1997
1999 1998 /*
2000 1999 * Remove 'value' from 'val'. If value==0, remove the entire
2001 2000 * __nis_single_value_t array from 'val'.
2002 2001 */
2003 2002 static void
2004 2003 removeSingleValue(__nis_value_t *val, void *value, int length) {
2005 2004 int i;
2006 2005
2007 2006 if (val == 0)
2008 2007 return;
2009 2008
2010 2009 if (value == 0) {
2011 2010 for (i = 0; i < val->numVals; i++) {
2012 2011 sfree(val->val[i].value);
2013 2012 }
2014 2013 sfree(val->val);
2015 2014 val->val = 0;
2016 2015 val->numVals = 0;
2017 2016 return;
2018 2017 }
2019 2018
2020 2019 for (i = 0; i < val->numVals; i++) {
2021 2020 if (val->val[i].value == 0 || (val->val[i].length != length))
2022 2021 continue;
2023 2022 if (memcmp(val->val[i].value, value, length) != 0)
2024 2023 continue;
2025 2024 sfree(val->val[i].value);
2026 2025 if (i != (val->numVals - 1)) {
2027 2026 (void) memmove(&val->val[i], &val->val[i+1],
2028 2027 (val->numVals - 1 - i) * sizeof (val->val[0]));
2029 2028 }
2030 2029 val->numVals -= 1;
2031 2030 break;
2032 2031 }
2033 2032 }
2034 2033
2035 2034 /*
2036 2035 * Helper function for LdapModify
2037 2036 * When a modify operation fails with an object class violation,
2038 2037 * the most probable reason is that the attributes we're modifying are new,
2039 2038 * and the needed object class are not present. So, try the modify again,
2040 2039 * but add the object classes this time.
2041 2040 */
2042 2041
2043 2042 static int
2044 2043 ldapModifyObjectClass(__nis_ldap_conn_t **lc, char *dn,
2045 2044 __nis_rule_value_t *rvIn, char *objClassAttrs)
2046 2045 {
2047 2046 LDAPMod **mods = 0;
2048 2047 int msgid;
2049 2048 int lderr;
2050 2049 struct timeval tv;
2051 2050 int stat;
2052 2051 LDAPMessage *msg = 0;
2053 2052 char **referralsp = NULL;
2054 2053 __nis_rule_value_t *rv, *rvldap;
2055 2054 __nis_ldap_search_t *ls;
2056 2055 int i, ocrv, ocrvldap, nv;
2057 2056 char *oc[2] = { "objectClass", 0};
2058 2057 char *myself = "ldapModifyObjectClass";
2059 2058
2060 2059 rv = initRuleValue(1, rvIn);
2061 2060 if (rv == 0)
2062 2061 return (LDAP_NO_MEMORY);
2063 2062
2064 2063 delAttrFromRuleValue(rv, "objectClass");
2065 2064 rv = addObjectClasses(rv, objClassAttrs);
2066 2065 if (rv == 0) {
2067 2066 stat = LDAP_OPERATIONS_ERROR;
2068 2067 logmsg(MSG_NOTIMECHECK, LOG_WARNING,
2069 2068 "%s: addObjectClasses failed for %s",
2070 2069 myself, NIL(dn));
2071 2070 goto cleanup;
2072 2071 }
2073 2072
2074 2073 /*
2075 2074 * Before adding the object classes whole-sale, try retrieving
2076 2075 * the entry specified by the 'dn'. If it exists, we filter out
2077 2076 * those object classes that already are present in LDAP from our
2078 2077 * update.
2079 2078 */
2080 2079 ls = buildLdapSearch(dn, LDAP_SCOPE_BASE, 0, 0, "objectClass=*",
2081 2080 oc, 0, 1);
2082 2081 if (ls == 0) {
2083 2082 logmsg(MSG_NOTIMECHECK, LOG_INFO,
2084 2083 "%s: Unable to build DN search for \"%s\"",
2085 2084 myself, NIL(dn));
2086 2085 /* Fall through to try just adding the object classes */
2087 2086 goto addObjectClasses;
2088 2087 }
2089 2088
2090 2089 nv = 0;
2091 2090 rvldap = ldapSearch(ls, &nv, 0, &lderr);
2092 2091 freeLdapSearch(ls);
2093 2092 if (rvldap == 0) {
2094 2093 logmsg(MSG_NOTIMECHECK, LOG_INFO,
2095 2094 "%s: No data for DN search (\"%s\"); LDAP status %d",
2096 2095 myself, NIL(dn), lderr);
2097 2096 /* Fall through to try just adding the object classes */
2098 2097 goto addObjectClasses;
2099 2098 }
2100 2099
2101 2100 /*
2102 2101 * Find the indices of the 'objectClass' attribute
2103 2102 * in 'rvldap' and 'rv'.
2104 2103 */
2105 2104 for (i = 0, ocrvldap = -1; i < rvldap->numAttrs; i++) {
2106 2105 if (rvldap->attrName[i] != 0 &&
2107 2106 strcasecmp("objectClass", rvldap->attrName[i]) == 0) {
2108 2107 ocrvldap = i;
2109 2108 break;
2110 2109 }
2111 2110 }
2112 2111 for (i = 0, ocrv = -1; i < rv->numAttrs; i++) {
2113 2112 if (rv->attrName[i] != 0 &&
2114 2113 strcasecmp("objectClass", rv->attrName[i]) == 0) {
2115 2114 ocrv = i;
2116 2115 break;
2117 2116 }
2118 2117 }
2119 2118
2120 2119 /*
2121 2120 * Remove those object classes that already exist
2122 2121 * in LDAP (i.e., in 'rvldap') from 'rv'.
2123 2122 */
2124 2123 if (ocrv >= 0 && ocrvldap >= 0) {
2125 2124 for (i = 0; i < rvldap->attrVal[ocrvldap].numVals; i++) {
2126 2125 removeSingleValue(&rv->attrVal[ocrv],
2127 2126 rvldap->attrVal[ocrvldap].val[i].value,
2128 2127 rvldap->attrVal[ocrvldap].val[i].length);
2129 2128 }
2130 2129 /*
2131 2130 * If no 'objectClass' values left in 'rv', delete
2132 2131 * 'objectClass' from 'rv'.
2133 2132 */
2134 2133 if (rv->attrVal[ocrv].numVals == 0)
2135 2134 delAttrFromRuleValue(rv, "objectClass");
2136 2135 }
2137 2136
2138 2137 /*
2139 2138 * 'rv' now contains the update we want to make, with just the
2140 2139 * object class(es) that need to be added. Fall through to the
2141 2140 * actual LDAP modify operation.
2142 2141 */
2143 2142 freeRuleValue(rvldap, 1);
2144 2143
2145 2144 addObjectClasses:
2146 2145
2147 2146 mods = search2LdapMod(rv, 0, 1);
2148 2147 if (mods == 0) {
2149 2148 stat = LDAP_OPERATIONS_ERROR;
2150 2149 logmsg(MSG_NOTIMECHECK, LOG_WARNING,
2151 2150 "%s: Unable to create LDAP modify changes with object classes for %s",
2152 2151 myself, NIL(dn));
2153 2152 goto cleanup;
2154 2153 }
2155 2154 msgid = ldap_modify((*lc)->ld, dn, mods);
2156 2155 if (msgid != -1) {
2157 2156 tv = (*lc)->modifyTimeout;
2158 2157 stat = ldap_result((*lc)->ld, msgid, 0, &tv, &msg);
2159 2158 if (stat == 0) {
2160 2159 stat = LDAP_TIMEOUT;
2161 2160 } else if (stat == -1) {
2162 2161 (void) ldap_get_option((*lc)->ld,
2163 2162 LDAP_OPT_ERROR_NUMBER, &stat);
2164 2163 } else {
2165 2164 stat = ldap_parse_result((*lc)->ld, msg, &lderr, NULL,
2166 2165 NULL, &referralsp, NULL, 0);
2167 2166 if (stat == LDAP_SUCCESS)
2168 2167 stat = lderr;
2169 2168 stat = ldap_result2error((*lc)->ld, msg, 0);
2170 2169 }
2171 2170 } else {
2172 2171 (void) ldap_get_option((*lc)->ld, LDAP_OPT_ERROR_NUMBER,
2173 2172 &stat);
2174 2173 }
2175 2174 if (proxyInfo.follow_referral == follow &&
2176 2175 stat == LDAP_REFERRAL && referralsp != NULL) {
2177 2176 releaseCon(*lc, stat);
2178 2177 if (msg != NULL)
2179 2178 (void) ldap_msgfree(msg);
2180 2179 msg = NULL;
2181 2180 *lc = findReferralCon(referralsp, &stat);
2182 2181 ldap_value_free(referralsp);
2183 2182 referralsp = NULL;
2184 2183 if (*lc == NULL)
2185 2184 goto cleanup;
2186 2185 msgid = ldap_modify((*lc)->ld, dn, mods);
2187 2186 if (msgid == -1) {
2188 2187 (void) ldap_get_option((*lc)->ld,
2189 2188 LDAP_OPT_ERROR_NUMBER, &stat);
2190 2189 goto cleanup;
2191 2190 }
2192 2191 stat = ldap_result((*lc)->ld, msgid, 0, &tv, &msg);
2193 2192 if (stat == 0) {
2194 2193 stat = LDAP_TIMEOUT;
2195 2194 } else if (stat == -1) {
2196 2195 (void) ldap_get_option((*lc)->ld,
2197 2196 LDAP_OPT_ERROR_NUMBER, &stat);
2198 2197 } else {
2199 2198 stat = ldap_parse_result((*lc)->ld, msg, &lderr,
2200 2199 NULL, NULL, NULL, NULL, 0);
2201 2200 if (stat == LDAP_SUCCESS)
2202 2201 stat = lderr;
2203 2202 }
2204 2203 }
2205 2204 cleanup:
2206 2205 if (mods != 0)
2207 2206 freeLdapMod(mods);
2208 2207 freeRuleValue(rv, 1);
2209 2208 return (stat);
2210 2209 }
2211 2210
2212 2211 /*
2213 2212 * Modify the specified 'dn' per the attribute names/values in 'rv'.
2214 2213 * If 'rv' is NULL, we attempt to delete the entire entry.
2215 2214 *
2216 2215 * The 'objClassAttrs' parameter is needed if the entry must be added
2217 2216 * (i.e., created), or a modify fails with an object class violation.
2218 2217 *
2219 2218 * If 'addFirst' is set, we try an add before a modify; modify before
↓ open down ↓ |
1172 lines elided |
↑ open up ↑ |
2220 2219 * add otherwise (ignored if we're deleting).
2221 2220 */
2222 2221 int
2223 2222 ldapModify(char *dn, __nis_rule_value_t *rv, char *objClassAttrs,
2224 2223 int addFirst) {
2225 2224 int stat, add = 0;
2226 2225 LDAPMod **mods = 0;
2227 2226 __nis_ldap_conn_t *lc;
2228 2227 struct timeval tv;
2229 2228 LDAPMessage *msg = 0;
2230 - char *myself = "ldapModify";
2231 2229 int msgid;
2232 2230 int lderr;
2233 2231 char **referralsp = NULL;
2234 2232 bool_t delete = FALSE;
2235 2233
2236 2234 if (dn == 0)
2237 2235 return (LDAP_PARAM_ERROR);
2238 2236
2239 2237 if ((lc = findCon(&stat)) == 0)
2240 2238 return (stat);
2241 2239
2242 2240 if (rv == 0) {
2243 2241 delete = TRUE;
2244 2242 /* Simple case: if rv == 0, try to delete the entire entry */
2245 2243 msgid = ldap_delete(lc->ld, dn);
2246 2244 if (msgid == -1) {
2247 2245 (void) ldap_get_option(lc->ld, LDAP_OPT_ERROR_NUMBER,
2248 2246 &stat);
2249 2247 goto cleanup;
2250 2248 }
2251 2249 tv = lc->deleteTimeout;
2252 2250 stat = ldap_result(lc->ld, msgid, 0, &tv, &msg);
2253 2251
2254 2252 if (stat == 0) {
2255 2253 stat = LDAP_TIMEOUT;
2256 2254 } else if (stat == -1) {
2257 2255 (void) ldap_get_option(lc->ld, LDAP_OPT_ERROR_NUMBER,
2258 2256 &stat);
2259 2257 } else {
2260 2258 stat = ldap_parse_result(lc->ld, msg, &lderr, NULL,
2261 2259 NULL, &referralsp, NULL, 0);
2262 2260 if (stat == LDAP_SUCCESS)
2263 2261 stat = lderr;
2264 2262 }
2265 2263 if (proxyInfo.follow_referral == follow &&
2266 2264 stat == LDAP_REFERRAL && referralsp != NULL) {
2267 2265 releaseCon(lc, stat);
2268 2266 if (msg != NULL)
2269 2267 (void) ldap_msgfree(msg);
2270 2268 msg = NULL;
2271 2269 lc = findReferralCon(referralsp, &stat);
2272 2270 ldap_value_free(referralsp);
2273 2271 if (lc == NULL)
2274 2272 goto cleanup;
2275 2273 msgid = ldap_delete(lc->ld, dn);
2276 2274 if (msgid == -1) {
2277 2275 (void) ldap_get_option(lc->ld,
2278 2276 LDAP_OPT_ERROR_NUMBER, &stat);
2279 2277 goto cleanup;
2280 2278 }
2281 2279 stat = ldap_result(lc->ld, msgid, 0, &tv, &msg);
2282 2280 if (stat == 0) {
2283 2281 stat = LDAP_TIMEOUT;
2284 2282 } else if (stat == -1) {
2285 2283 (void) ldap_get_option(lc->ld,
2286 2284 LDAP_OPT_ERROR_NUMBER, &stat);
2287 2285 } else {
2288 2286 stat = ldap_parse_result(lc->ld, msg, &lderr,
2289 2287 NULL, NULL, NULL, NULL, 0);
2290 2288 if (stat == LDAP_SUCCESS)
2291 2289 stat = lderr;
2292 2290 }
2293 2291 }
2294 2292 /* No such object means someone else has done our job */
2295 2293 if (stat == LDAP_NO_SUCH_OBJECT)
2296 2294 stat = LDAP_SUCCESS;
2297 2295 } else {
2298 2296 if (addFirst) {
2299 2297 stat = ldapAdd(dn, rv, objClassAttrs, lc);
2300 2298 lc = NULL;
2301 2299 if (stat != LDAP_ALREADY_EXISTS)
2302 2300 goto cleanup;
2303 2301 if ((lc = findCon(&stat)) == 0)
2304 2302 return (stat);
2305 2303 }
2306 2304
2307 2305 /*
2308 2306 * First try the modify without specifying object classes
2309 2307 * (i.e., assume they're already present).
2310 2308 */
2311 2309 mods = search2LdapMod(rv, 0, 0);
2312 2310 if (mods == 0) {
2313 2311 stat = LDAP_PARAM_ERROR;
2314 2312 goto cleanup;
2315 2313 }
2316 2314
2317 2315 msgid = ldap_modify(lc->ld, dn, mods);
2318 2316 if (msgid == -1) {
2319 2317 (void) ldap_get_option(lc->ld, LDAP_OPT_ERROR_NUMBER,
2320 2318 &stat);
2321 2319 goto cleanup;
2322 2320 }
2323 2321 tv = lc->modifyTimeout;
2324 2322 stat = ldap_result(lc->ld, msgid, 0, &tv, &msg);
2325 2323 if (stat == 0) {
2326 2324 stat = LDAP_TIMEOUT;
2327 2325 } else if (stat == -1) {
2328 2326 (void) ldap_get_option(lc->ld, LDAP_OPT_ERROR_NUMBER,
2329 2327 &stat);
2330 2328 } else {
2331 2329 stat = ldap_parse_result(lc->ld, msg, &lderr, NULL,
2332 2330 NULL, &referralsp, NULL, 0);
2333 2331 if (stat == LDAP_SUCCESS)
2334 2332 stat = lderr;
2335 2333 }
2336 2334 if (proxyInfo.follow_referral == follow &&
2337 2335 stat == LDAP_REFERRAL && referralsp != NULL) {
2338 2336 releaseCon(lc, stat);
2339 2337 if (msg != NULL)
2340 2338 (void) ldap_msgfree(msg);
2341 2339 msg = NULL;
2342 2340 lc = findReferralCon(referralsp, &stat);
2343 2341 ldap_value_free(referralsp);
2344 2342 referralsp = NULL;
2345 2343 if (lc == NULL)
2346 2344 goto cleanup;
2347 2345 msgid = ldap_modify(lc->ld, dn, mods);
2348 2346 if (msgid == -1) {
2349 2347 (void) ldap_get_option(lc->ld,
2350 2348 LDAP_OPT_ERROR_NUMBER, &stat);
2351 2349 goto cleanup;
2352 2350 }
2353 2351 stat = ldap_result(lc->ld, msgid, 0, &tv, &msg);
2354 2352 if (stat == 0) {
2355 2353 stat = LDAP_TIMEOUT;
2356 2354 } else if (stat == -1) {
2357 2355 (void) ldap_get_option(lc->ld,
2358 2356 LDAP_OPT_ERROR_NUMBER, &stat);
2359 2357 } else {
2360 2358 stat = ldap_parse_result(lc->ld, msg, &lderr,
2361 2359 NULL, NULL, NULL, NULL, 0);
2362 2360 if (stat == LDAP_SUCCESS)
2363 2361 stat = lderr;
2364 2362 }
2365 2363 }
2366 2364
2367 2365 /*
2368 2366 * If the modify failed with an object class violation,
2369 2367 * the most probable reason is that at least on of the
2370 2368 * attributes we're modifying didn't exist before, and
2371 2369 * neither did its object class. So, try the modify again,
2372 2370 * but add the object classes this time.
2373 2371 */
2374 2372 if (stat == LDAP_OBJECT_CLASS_VIOLATION &&
2375 2373 objClassAttrs != 0) {
2376 2374 freeLdapMod(mods);
2377 2375 mods = 0;
2378 2376 stat = ldapModifyObjectClass(&lc, dn, rv,
2379 2377 objClassAttrs);
2380 2378 }
2381 2379
2382 2380 if (stat == LDAP_NO_SUCH_ATTRIBUTE) {
2383 2381 /*
2384 2382 * If there was at least one attribute delete, then
2385 2383 * the cause of this error could be that said attribute
2386 2384 * didn't exist in LDAP. So, do things the slow way,
2387 2385 * and try to delete one attribute at a time.
2388 2386 */
2389 2387 int d, numDelete, st;
2390 2388 __nis_rule_value_t *rvt;
2391 2389
2392 2390 for (d = 0, numDelete = 0; d < rv->numAttrs; d++) {
2393 2391 if (rv->attrVal[d].numVals < 0)
2394 2392 numDelete++;
2395 2393 }
2396 2394
2397 2395 /* If there's just one, we've already tried */
2398 2396 if (numDelete <= 1)
2399 2397 goto cleanup;
2400 2398
2401 2399 /* Make a copy of the rule value */
2402 2400 rvt = initRuleValue(1, rv);
2403 2401 if (rvt == 0)
2404 2402 goto cleanup;
2405 2403
2406 2404 /*
2407 2405 * Remove all delete attributes from the tmp
2408 2406 * rule value.
2409 2407 */
2410 2408 for (d = 0; d < rv->numAttrs; d++) {
2411 2409 if (rv->attrVal[d].numVals < 0) {
2412 2410 delAttrFromRuleValue(rvt,
2413 2411 rv->attrName[d]);
2414 2412 }
2415 2413 }
2416 2414
2417 2415 /*
2418 2416 * Now put the attributes back in one by one, and
2419 2417 * invoke ourselves.
2420 2418 */
2421 2419 for (d = 0; d < rv->numAttrs; d++) {
2422 2420 if (rv->attrVal[d].numVals >= 0)
2423 2421 continue;
2424 2422 st = addAttr2RuleValue(rv->attrVal[d].type,
2425 2423 rv->attrName[d], 0, 0, rvt);
2426 2424 if (st != 0) {
2427 2425 logmsg(MSG_NOMEM, LOG_ERR,
2428 2426 "%s: Error deleting \"%s\" for \"%s\"",
2429 2427 NIL(rv->attrName[d]), NIL(dn));
2430 2428 stat = LDAP_NO_MEMORY;
2431 2429 freeRuleValue(rvt, 1);
2432 2430 goto cleanup;
2433 2431 }
2434 2432 stat = ldapModify(dn, rvt, objClassAttrs, 0);
2435 2433 if (stat != LDAP_SUCCESS &&
2436 2434 stat != LDAP_NO_SUCH_ATTRIBUTE) {
2437 2435 freeRuleValue(rvt, 1);
2438 2436 goto cleanup;
2439 2437 }
2440 2438 delAttrFromRuleValue(rvt, rv->attrName[d]);
2441 2439 }
2442 2440
2443 2441 /*
2444 2442 * If we got here, then all attributes that should
2445 2443 * be deleted either have been, or didn't exist. For
2446 2444 * our purposes, the latter is as good as the former.
2447 2445 */
2448 2446 stat = LDAP_SUCCESS;
2449 2447 freeRuleValue(rvt, 1);
2450 2448 }
2451 2449
2452 2450 if (stat == LDAP_NO_SUCH_OBJECT && !addFirst) {
2453 2451 /*
2454 2452 * Entry doesn't exist, so try an ldap_add(). If the
2455 2453 * ldap_add() also fails, that could be because someone
2456 2454 * else added it between our modify and add operations.
2457 2455 * If so, we consider that foreign add to be
2458 2456 * authoritative (meaning we don't retry our modify).
2459 2457 *
2460 2458 * Also, if all modify operations specified by 'mods'
2461 2459 * are deletes, LDAP_NO_SUCH_OBJECT is a kind of
2462 2460 * success; we certainly don't want to create the
2463 2461 * entry.
2464 2462 */
2465 2463 int allDelete;
2466 2464 LDAPMod **m;
2467 2465
2468 2466 for (m = mods, allDelete = 1; *m != 0 && allDelete;
2469 2467 m++) {
2470 2468 if (((*m)->mod_op & LDAP_MOD_DELETE) == 0)
2471 2469 allDelete = 0;
2472 2470 }
2473 2471
2474 2472 add = 1;
2475 2473
2476 2474 if (allDelete) {
2477 2475 stat = LDAP_SUCCESS;
2478 2476 } else if (objClassAttrs == 0) {
2479 2477 /* Now we need it, so this is fatal */
2480 2478 stat = LDAP_PARAM_ERROR;
2481 2479 } else {
2482 2480 stat = ldapAdd(dn, rv, objClassAttrs, lc);
2483 2481 lc = NULL;
2484 2482 }
2485 2483 }
2486 2484 }
2487 2485
2488 2486 cleanup:
2489 2487 if (stat != LDAP_SUCCESS) {
2490 2488 logmsg(MSG_NOTIMECHECK, LOG_INFO,
2491 2489 "%s(0x%x (%s), \"%s\") => %d (%s)\n",
2492 2490 !delete ? (add ? "ldap_add" : "ldap_modify") :
2493 2491 "ldap_delete",
2494 2492 lc != NULL ? lc->ld : 0,
2495 2493 lc != NULL ? NIL(lc->sp) : "nil",
2496 2494 dn, stat, ldap_err2string(stat));
2497 2495 }
2498 2496
2499 2497 releaseCon(lc, stat);
2500 2498 freeLdapMod(mods);
2501 2499 if (msg != 0)
2502 2500 (void) ldap_msgfree(msg);
2503 2501
2504 2502 return (stat);
2505 2503 }
2506 2504
2507 2505 /*
2508 2506 * Create the entry specified by 'dn' to have the values per 'rv'.
2509 2507 * The 'objClassAttrs' are the extra object classes we need when
2510 2508 * creating an entry.
2511 2509 *
2512 2510 * If 'lc' is non-NULL, we use that connection; otherwise, we find
2513 2511 * our own. CAUTION: This connection will be released on return. Regardless
2514 2512 * of return value, this connection should not subsequently used by the
2515 2513 * caller.
2516 2514 *
2517 2515 * Returns an LDAP status.
2518 2516 */
2519 2517 int
2520 2518 ldapAdd(char *dn, __nis_rule_value_t *rv, char *objClassAttrs, void *lcv) {
2521 2519 int stat;
2522 2520 LDAPMod **mods = 0;
2523 2521 struct timeval tv;
2524 2522 LDAPMessage *msg = 0;
2525 2523 __nis_ldap_conn_t *lc = lcv;
2526 2524 int msgid;
2527 2525 int lderr;
2528 2526 char **referralsp = NULL;
2529 2527
2530 2528 if (dn == 0 || rv == 0 || objClassAttrs == 0) {
2531 2529 releaseCon(lc, LDAP_SUCCESS);
2532 2530 return (LDAP_PARAM_ERROR);
2533 2531 }
2534 2532
2535 2533 if (lc == 0) {
2536 2534 if ((lc = findCon(&stat)) == 0)
2537 2535 return (stat);
2538 2536 }
2539 2537
2540 2538 rv = addObjectClasses(rv, objClassAttrs);
2541 2539 if (rv == 0) {
2542 2540 stat = LDAP_OPERATIONS_ERROR;
2543 2541 goto cleanup;
2544 2542 }
2545 2543
2546 2544 mods = search2LdapMod(rv, 1, 0);
2547 2545 if (mods == 0) {
2548 2546 stat = LDAP_OPERATIONS_ERROR;
2549 2547 goto cleanup;
2550 2548 }
2551 2549
2552 2550 msgid = ldap_add(lc->ld, dn, mods);
2553 2551 if (msgid == -1) {
2554 2552 (void) ldap_get_option(lc->ld, LDAP_OPT_ERROR_NUMBER, &stat);
2555 2553 goto cleanup;
2556 2554 }
2557 2555 tv = lc->addTimeout;
2558 2556 stat = ldap_result(lc->ld, msgid, 0, &tv, &msg);
2559 2557 if (stat == 0) {
2560 2558 stat = LDAP_TIMEOUT;
2561 2559 } else if (stat == -1) {
2562 2560 (void) ldap_get_option(lc->ld, LDAP_OPT_ERROR_NUMBER, &stat);
2563 2561 } else {
2564 2562 stat = ldap_parse_result(lc->ld, msg, &lderr, NULL, NULL,
2565 2563 &referralsp, NULL, 0);
2566 2564 if (stat == LDAP_SUCCESS)
2567 2565 stat = lderr;
2568 2566 }
2569 2567 if (proxyInfo.follow_referral == follow && stat == LDAP_REFERRAL &&
2570 2568 referralsp != NULL) {
2571 2569 releaseCon(lc, stat);
2572 2570 if (msg != NULL)
2573 2571 (void) ldap_msgfree(msg);
2574 2572 msg = NULL;
2575 2573 lc = findReferralCon(referralsp, &stat);
2576 2574 ldap_value_free(referralsp);
2577 2575 if (lc == NULL)
2578 2576 goto cleanup;
2579 2577 msgid = ldap_add(lc->ld, dn, mods);
2580 2578 if (msgid == -1) {
2581 2579 (void) ldap_get_option(lc->ld,
2582 2580 LDAP_OPT_ERROR_NUMBER, &stat);
2583 2581 goto cleanup;
2584 2582 }
2585 2583 stat = ldap_result(lc->ld, msgid, 0, &tv, &msg);
2586 2584 if (stat == 0) {
2587 2585 stat = LDAP_TIMEOUT;
2588 2586 } else if (stat == -1) {
2589 2587 (void) ldap_get_option(lc->ld, LDAP_OPT_ERROR_NUMBER,
2590 2588 &stat);
2591 2589 } else {
2592 2590 stat = ldap_parse_result(lc->ld, msg, &lderr, NULL,
2593 2591 NULL, NULL, NULL, 0);
2594 2592 if (stat == LDAP_SUCCESS)
2595 2593 stat = lderr;
2596 2594 }
2597 2595 }
2598 2596
2599 2597 cleanup:
2600 2598 if (stat != LDAP_SUCCESS) {
2601 2599 logmsg(MSG_NOTIMECHECK, LOG_INFO,
2602 2600 "ldap_add(0x%x (%s), \"%s\") => %d (%s)\n",
2603 2601 lc != NULL ? lc->ld : 0,
2604 2602 lc != NULL ? NIL(lc->sp) : "nil",
2605 2603 dn, stat, ldap_err2string(stat));
2606 2604 }
2607 2605
2608 2606 releaseCon(lc, stat);
2609 2607 freeLdapMod(mods);
2610 2608 if (msg != 0)
2611 2609 (void) ldap_msgfree(msg);
2612 2610
2613 2611 return (stat);
2614 2612 }
2615 2613
2616 2614 /*
2617 2615 * Change the entry at 'oldDn' to have the new DN (not RDN) 'dn'.
2618 2616 * Returns an LDAP error status.
2619 2617 */
2620 2618 int
2621 2619 ldapChangeDN(char *oldDn, char *dn) {
2622 2620 int stat;
2623 2621 __nis_ldap_conn_t *lc;
2624 2622 int i, j, lo, ln;
2625 2623 char *rdn;
2626 2624 int msgid;
2627 2625 int lderr;
2628 2626 struct timeval tv;
2629 2627 LDAPMessage *msg = 0;
2630 2628 char **referralsp = NULL;
2631 2629 char *myself = "ldapChangeDN";
2632 2630
2633 2631 if ((lo = slen(oldDn)) <= 0 || (ln = slen(dn)) <= 0)
2634 2632 return (LDAP_PARAM_ERROR);
2635 2633
2636 2634 if (strcasecmp(oldDn, dn) == 0)
2637 2635 return (LDAP_SUCCESS);
2638 2636
2639 2637 if ((lc = findCon(&stat)) == 0)
2640 2638 return (stat);
2641 2639
2642 2640 rdn = sdup(myself, T, dn);
2643 2641 if (rdn == 0) {
2644 2642 releaseCon(lc, LDAP_SUCCESS);
2645 2643 return (LDAP_NO_MEMORY);
2646 2644 }
2647 2645
2648 2646 /* Compare old and new DN from the end */
2649 2647 for (i = lo-1, j = ln-1; i >= 0 && j >= 0; i--, j--) {
2650 2648 if (tolower(oldDn[i]) != tolower(rdn[j])) {
2651 2649 /*
2652 2650 * Terminate 'rdn' after this character in order
2653 2651 * to snip off the portion of the new DN that is
2654 2652 * the same as the old DN. What remains in 'rdn'
2655 2653 * is the relative DN.
2656 2654 */
2657 2655 rdn[j+1] = '\0';
2658 2656 break;
2659 2657 }
2660 2658 }
2661 2659
2662 2660 stat = ldap_rename(lc->ld, oldDn, rdn, NULL, 1, NULL, NULL, &msgid);
2663 2661
2664 2662 if (msgid != -1) {
2665 2663 tv = lc->modifyTimeout;
2666 2664 stat = ldap_result(lc->ld, msgid, 0, &tv, &msg);
2667 2665 if (stat == 0) {
2668 2666 stat = LDAP_TIMEOUT;
2669 2667 } else if (stat == -1) {
2670 2668 (void) ldap_get_option(lc->ld,
2671 2669 LDAP_OPT_ERROR_NUMBER, &stat);
2672 2670 } else {
2673 2671 stat = ldap_parse_result(lc->ld, msg, &lderr, NULL,
2674 2672 NULL, &referralsp, NULL, 0);
2675 2673 if (stat == LDAP_SUCCESS)
2676 2674 stat = lderr;
2677 2675 stat = ldap_result2error(lc->ld, msg, 0);
2678 2676 }
2679 2677 } else {
2680 2678 (void) ldap_get_option(lc->ld, LDAP_OPT_ERROR_NUMBER,
2681 2679 &stat);
2682 2680 }
2683 2681 if (proxyInfo.follow_referral == follow &&
2684 2682 stat == LDAP_REFERRAL && referralsp != NULL) {
2685 2683 releaseCon(lc, stat);
2686 2684 if (msg != NULL)
2687 2685 (void) ldap_msgfree(msg);
2688 2686 msg = NULL;
2689 2687 lc = findReferralCon(referralsp, &stat);
2690 2688 ldap_value_free(referralsp);
2691 2689 referralsp = NULL;
2692 2690 if (lc == NULL)
2693 2691 goto cleanup;
2694 2692 msgid = ldap_rename(lc->ld, oldDn, rdn, NULL, 1, NULL, NULL,
2695 2693 &msgid);
2696 2694 if (msgid == -1) {
2697 2695 (void) ldap_get_option(lc->ld,
2698 2696 LDAP_OPT_ERROR_NUMBER, &stat);
2699 2697 goto cleanup;
2700 2698 }
2701 2699 stat = ldap_result(lc->ld, msgid, 0, &tv, &msg);
2702 2700 if (stat == 0) {
2703 2701 stat = LDAP_TIMEOUT;
2704 2702 } else if (stat == -1) {
2705 2703 (void) ldap_get_option(lc->ld,
2706 2704 LDAP_OPT_ERROR_NUMBER, &stat);
2707 2705 } else {
2708 2706 stat = ldap_parse_result(lc->ld, msg, &lderr,
2709 2707 NULL, NULL, NULL, NULL, 0);
2710 2708 if (stat == LDAP_SUCCESS)
2711 2709 stat = lderr;
2712 2710 }
2713 2711 }
2714 2712
2715 2713 cleanup:
2716 2714 if (msg != NULL)
2717 2715 (void) ldap_msgfree(msg);
2718 2716
2719 2717 #if 1
2720 2718 fprintf(stderr, "%s: ldap_modrdn_s(0x%x, %s, %s, 1) => %s\n",
2721 2719 myself, lc == NULL ? 0: lc->ld, NIL(oldDn), NIL(rdn),
2722 2720 ldap_err2string(stat));
2723 2721 logmsg(MSG_NOTIMECHECK, LOG_WARNING,
2724 2722 "%s: ldap_modrdn_s(0x%x, %s, %s, 1) => %s",
2725 2723 myself, lc == NULL ? 0: lc->ld, NIL(oldDn), NIL(rdn),
2726 2724 ldap_err2string(stat));
2727 2725 #endif
2728 2726
2729 2727 if (stat == LDAP_NO_SUCH_OBJECT) {
2730 2728 /*
2731 2729 * Fine from our point of view, since all we want to do
2732 2730 * is to make sure that an update to the new DN doesn't
2733 2731 * leave the old entry around.
2734 2732 */
2735 2733 stat = LDAP_SUCCESS;
2736 2734 }
2737 2735
2738 2736 releaseCon(lc, stat);
2739 2737 sfree(rdn);
2740 2738
2741 2739 return (stat);
2742 2740 }
↓ open down ↓ |
502 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX