Print this page
NEX-14547 Get UNIX group info. from AD/LDAP with partial RFC2307 schema
NEX-13132 smbd dumping core in nss_ldap.so.1`getbymember
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
| Split |
Close |
| Expand all |
| Collapse all |
--- old/usr/src/lib/libsldap/common/ns_reads.c
+++ new/usr/src/lib/libsldap/common/ns_reads.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.
12 12 *
|
↓ open down ↓ |
12 lines elided |
↑ open up ↑ |
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 22 * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
23 + * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
23 24 */
24 25
25 26 #include <stdio.h>
26 27 #include <sys/types.h>
27 28 #include <stdlib.h>
28 29 #include <libintl.h>
29 30 #include <ctype.h>
30 31 #include <syslog.h>
31 32 #include <sys/stat.h>
32 33 #include <fcntl.h>
33 34 #include <unistd.h>
34 35 #include <string.h>
35 36 #include <strings.h>
36 37 #include <priv.h>
37 38
38 39 #include "ns_sldap.h"
39 40 #include "ns_internal.h"
40 41 #include "ns_cache_door.h"
41 42 #include "ns_connmgmt.h"
42 43
43 44 #define _NIS_FILTER "nisdomain=*"
44 45 #define _NIS_DOMAIN "nisdomain"
45 46 static const char *nis_domain_attrs[] = {
46 47 _NIS_DOMAIN,
47 48 (char *)NULL
48 49 };
49 50
50 51 static int validate_filter(ns_ldap_cookie_t *cookie);
51 52
52 53 void
53 54 __ns_ldap_freeEntry(ns_ldap_entry_t *ep)
54 55 {
55 56 int j, k = 0;
56 57
57 58 if (ep == NULL)
58 59 return;
59 60
60 61 if (ep->attr_pair == NULL) {
61 62 free(ep);
62 63 return;
63 64 }
64 65 for (j = 0; j < ep->attr_count; j++) {
65 66 if (ep->attr_pair[j] == NULL)
66 67 continue;
67 68 if (ep->attr_pair[j]->attrname)
68 69 free(ep->attr_pair[j]->attrname);
69 70 if (ep->attr_pair[j]->attrvalue) {
70 71 for (k = 0; (k < ep->attr_pair[j]->value_count) &&
71 72 (ep->attr_pair[j]->attrvalue[k]); k++) {
72 73 free(ep->attr_pair[j]->attrvalue[k]);
73 74 }
74 75 free(ep->attr_pair[j]->attrvalue);
75 76 }
76 77 free(ep->attr_pair[j]);
77 78 }
78 79 free(ep->attr_pair);
79 80 free(ep);
80 81 }
81 82
82 83 static void
83 84 _freeControlList(LDAPControl ***ctrls)
84 85 {
85 86 LDAPControl **ctrl;
86 87
87 88 if (ctrls == NULL || *ctrls == NULL)
88 89 return;
89 90
90 91 for (ctrl = *ctrls; *ctrl != NULL; ctrl++)
91 92 ldap_control_free(*ctrl);
92 93 free(*ctrls);
93 94 *ctrls = NULL;
94 95 }
95 96 /*
96 97 * Convert attribute type in a RDN that has an attribute mapping to the
97 98 * original mappped type.
98 99 * e.g.
99 100 * cn<->cn-st and iphostnumber<->iphostnumber-st
100 101 * cn-st=aaa+iphostnumber-st=10.10.01.01
101 102 * is mapped to
102 103 * cn=aaa+iphostnumber=10.10.01.01
103 104 *
104 105 * Input - service: e.g. hosts, passwd etc.
105 106 * rdn: RDN
106 107 * Return: NULL - No attribute mapping in the RDN
107 108 * Non-NULL - The attribute type(s) in the RDN are mapped and
108 109 * the memory is allocated for the new rdn.
109 110 *
110 111 */
111 112 static char *
112 113 _cvtRDN(const char *service, const char *rdn) {
113 114 char **attrs, **mapped_attrs, **mapp, *type, *value, *attr;
114 115 char *new_rdn = NULL;
115 116 int nAttr = 0, i, attr_mapped, len = 0;
116 117
117 118 /* Break down "type=value\0" pairs. Assume RDN is normalized */
118 119 if ((attrs = ldap_explode_rdn(rdn, 0)) == NULL)
119 120 return (NULL);
120 121
121 122 for (nAttr = 0; attrs[nAttr] != NULL; nAttr++);
122 123
123 124 if ((mapped_attrs = (char **)calloc(nAttr, sizeof (char *))) == NULL) {
124 125 ldap_value_free(attrs);
125 126 return (NULL);
126 127 }
127 128
128 129 attr_mapped = 0;
129 130 for (i = 0; i < nAttr; i++) {
130 131 /* Parse type=value pair */
131 132 if ((type = strtok_r(attrs[i], "=", &value)) == NULL ||
132 133 value == NULL)
133 134 goto cleanup;
134 135 /* Reverse map: e.g. cn-sm -> cn */
135 136 mapp = __ns_ldap_getOrigAttribute(service, type);
136 137 if (mapp != NULL && mapp[0] != NULL) {
137 138 /* The attribute mapping is found */
138 139 type = mapp[0];
139 140 attr_mapped = 1;
140 141
141 142 /* "type=value\0" */
142 143 len = strlen(type) + strlen(value) + 2;
143 144
144 145 /* Reconstruct type=value pair. A string is allocated */
145 146 if ((attr = (char *)calloc(1, len)) == NULL) {
146 147 __s_api_free2dArray(mapp);
147 148 goto cleanup;
148 149 }
149 150 (void) snprintf(attr, len, "%s=%s",
150 151 type, value);
151 152 mapped_attrs[i] = attr;
152 153 } else {
153 154 /*
154 155 * No attribute mapping. attrs[i] is going to be copied
155 156 * later. Restore "type\0value\0" back to
156 157 * "type=value\0".
157 158 */
158 159 type[strlen(type)] = '=';
159 160 }
160 161 __s_api_free2dArray(mapp);
161 162 }
162 163 if (attr_mapped == 0)
163 164 /* No attribute mapping. Don't bother to reconstruct RDN */
164 165 goto cleanup;
165 166
166 167 len = 0;
167 168 /* Reconstruct RDN from type=value pairs */
168 169 for (i = 0; i < nAttr; i++) {
169 170 if (mapped_attrs[i])
170 171 len += strlen(mapped_attrs[i]);
171 172 else
172 173 len += strlen(attrs[i]);
173 174 /* Add 1 for "+" */
174 175 len++;
175 176 }
176 177 if ((new_rdn = (char *)calloc(1, ++len)) == NULL)
177 178 goto cleanup;
178 179 for (i = 0; i < nAttr; i++) {
179 180 if (i > 0)
180 181 /* Add seperator */
181 182 (void) strlcat(new_rdn, "+", len);
182 183
183 184 if (mapped_attrs[i])
184 185 (void) strlcat(new_rdn, mapped_attrs[i], len);
185 186 else
186 187 (void) strlcat(new_rdn, attrs[i], len);
187 188
188 189 }
189 190 cleanup:
190 191 ldap_value_free(attrs);
191 192 if (mapped_attrs) {
192 193 if (attr_mapped) {
193 194 for (i = 0; i < nAttr; i++) {
194 195 if (mapped_attrs[i])
195 196 free(mapped_attrs[i]);
196 197 }
197 198 }
198 199 free(mapped_attrs);
199 200 }
200 201
201 202 return (new_rdn);
202 203 }
203 204 /*
204 205 * Convert attribute type in a DN that has an attribute mapping to the
205 206 * original mappped type.
206 207 * e.g
207 208 * The mappings are cn<->cn-sm, iphostnumber<->iphostnumber-sm
208 209 *
209 210 * dn: cn-sm=aaa+iphostnumber-sm=9.9.9.9,dc=central,dc=sun,dc=com
210 211 * is converted to
211 212 * dn: cn=aaa+iphostnumber=9.9.9.9,dc=central,dc=sun,dc=com
212 213 *
213 214 * Input - service: e.g. hosts, passwd etc.
214 215 * dn: the value of a distinguished name
215 216 * Return - NULL: error
216 217 * non-NULL: A converted DN and the memory is allocated
217 218 */
218 219 static char *
219 220 _cvtDN(const char *service, const char *dn) {
|
↓ open down ↓ |
187 lines elided |
↑ open up ↑ |
220 221 char **mapped_rdns;
221 222 char **rdns, *new_rdn, *new_dn = NULL;
222 223 int nRdn = 0, i, len = 0, rdn_mapped;
223 224
224 225 if (service == NULL || dn == NULL)
225 226 return (NULL);
226 227
227 228 if ((rdns = ldap_explode_dn(dn, 0)) == NULL)
228 229 return (NULL);
229 230
230 - for (nRdn = 0; rdns[nRdn] != NULL; nRdn++);
231 + for (nRdn = 0; rdns[nRdn] != NULL; nRdn++)
232 + ;
231 233
232 234 if ((mapped_rdns = (char **)calloc(nRdn, sizeof (char *))) == NULL) {
233 235 ldap_value_free(rdns);
234 236 return (NULL);
235 237 }
236 238
237 239 rdn_mapped = 0;
238 240 /* Break down RDNs in a DN */
239 241 for (i = 0; i < nRdn; i++) {
240 242 if ((new_rdn = _cvtRDN(service, rdns[i])) != NULL) {
241 243 mapped_rdns[i] = new_rdn;
242 244 rdn_mapped = 1;
243 245 }
244 246 }
245 247 if (rdn_mapped == 0) {
246 248 /*
247 249 * No RDN contains any attribute mapping.
248 250 * Don't bother to reconstruct DN from RDN. Copy DN directly.
249 251 */
250 252 new_dn = strdup(dn);
251 253 goto cleanup;
252 254 }
253 255 /*
254 256 * Reconstruct dn from RDNs.
255 257 * Calculate the length first.
256 258 */
257 259 for (i = 0; i < nRdn; i++) {
258 260 if (mapped_rdns[i])
259 261 len += strlen(mapped_rdns[i]);
260 262 else
261 263 len += strlen(rdns[i]);
262 264
263 265 /* add 1 for ',' */
264 266 len ++;
265 267 }
266 268 if ((new_dn = (char *)calloc(1, ++len)) == NULL)
267 269 goto cleanup;
268 270 for (i = 0; i < nRdn; i++) {
269 271 if (i > 0)
270 272 /* Add seperator */
271 273 (void) strlcat(new_dn, ",", len);
272 274
273 275 if (mapped_rdns[i])
274 276 (void) strlcat(new_dn, mapped_rdns[i], len);
275 277 else
276 278 (void) strlcat(new_dn, rdns[i], len);
277 279
278 280 }
279 281
280 282 cleanup:
281 283 ldap_value_free(rdns);
282 284 if (mapped_rdns) {
283 285 if (rdn_mapped) {
284 286 for (i = 0; i < nRdn; i++) {
285 287 if (mapped_rdns[i])
286 288 free(mapped_rdns[i]);
287 289 }
288 290 }
289 291 free(mapped_rdns);
290 292 }
291 293
292 294 return (new_dn);
293 295 }
294 296 /*
295 297 * Convert a single ldap entry from a LDAPMessage
296 298 * into an ns_ldap_entry structure.
297 299 * Schema map the entry if specified in flags
298 300 */
299 301
300 302 static int
301 303 __s_api_cvtEntry(LDAP *ld,
302 304 const char *service,
303 305 LDAPMessage *e,
304 306 int flags,
305 307 ns_ldap_entry_t **ret,
306 308 ns_ldap_error_t **error)
307 309 {
308 310
309 311 ns_ldap_entry_t *ep = NULL;
310 312 ns_ldap_attr_t **ap = NULL;
311 313 BerElement *ber;
312 314 char *attr = NULL;
313 315 char **vals = NULL;
314 316 char **mapping;
315 317 char *dn;
316 318 int nAttrs = 0;
317 319 int i, j, k = 0;
318 320 char **gecos_mapping = NULL;
319 321 int gecos_val_index[3] = { -1, -1, -1};
320 322 char errstr[MAXERROR];
321 323 int schema_mapping_existed = FALSE;
322 324 int gecos_mapping_existed = FALSE;
323 325 int gecos_attr_matched;
324 326 int auto_service = FALSE;
325 327 int rc = NS_LDAP_SUCCESS;
326 328
327 329 if (e == NULL || ret == NULL || error == NULL)
328 330 return (NS_LDAP_INVALID_PARAM);
329 331
330 332 *error = NULL;
331 333
332 334 ep = (ns_ldap_entry_t *)calloc(1, sizeof (ns_ldap_entry_t));
333 335 if (ep == NULL)
334 336 return (NS_LDAP_MEMORY);
335 337
336 338 if (service != NULL &&
337 339 (strncasecmp(service, "auto_", 5) == 0 ||
338 340 strcasecmp(service, "automount") == 0))
339 341 auto_service = TRUE;
340 342 /*
341 343 * see if schema mapping existed for the given service
342 344 */
343 345 mapping = __ns_ldap_getOrigAttribute(service,
344 346 NS_HASH_SCHEMA_MAPPING_EXISTED);
345 347 if (mapping) {
346 348 schema_mapping_existed = TRUE;
347 349 __s_api_free2dArray(mapping);
348 350 mapping = NULL;
349 351 } else if (auto_service) {
350 352 /*
351 353 * If service == auto_* and no
352 354 * schema mapping found
353 355 * then try automount
354 356 * There is certain case that schema mapping exist
355 357 * but __ns_ldap_getOrigAttribute(service,
356 358 * NS_HASH_SCHEMA_MAPPING_EXISTED);
357 359 * returns NULL.
358 360 * e.g.
359 361 * NS_LDAP_ATTRIBUTEMAP = automount:automountMapName=AAA
360 362 * NS_LDAP_OBJECTCLASSMAP = automount:automountMap=MynisMap
361 363 * NS_LDAP_OBJECTCLASSMAP = automount:automount=MynisObject
362 364 *
363 365 * Make a check for schema_mapping_existed here
364 366 * so later on __s_api_convert_automountmapname won't be called
365 367 * unnecessarily. It is also used for attribute mapping
366 368 * and objectclass mapping.
367 369 */
368 370 mapping = __ns_ldap_getOrigAttribute("automount",
369 371 NS_HASH_SCHEMA_MAPPING_EXISTED);
370 372 if (mapping) {
371 373 schema_mapping_existed = TRUE;
372 374 __s_api_free2dArray(mapping);
373 375 mapping = NULL;
374 376 }
375 377 }
376 378
377 379 nAttrs = 1; /* start with 1 for the DN attr */
378 380 for (attr = ldap_first_attribute(ld, e, &ber); attr != NULL;
379 381 attr = ldap_next_attribute(ld, e, ber)) {
380 382 nAttrs++;
381 383 ldap_memfree(attr);
382 384 attr = NULL;
383 385 }
384 386 ber_free(ber, 0);
385 387 ber = NULL;
386 388
387 389 ep->attr_count = nAttrs;
388 390
389 391 /*
390 392 * add 1 for "gecos" 1 to N attribute mapping,
391 393 * just in case it is needed.
392 394 * ep->attr_count will be updated later if that is true.
393 395 */
394 396 ap = (ns_ldap_attr_t **)calloc(ep->attr_count + 1,
395 397 sizeof (ns_ldap_attr_t *));
396 398 if (ap == NULL) {
397 399 __ns_ldap_freeEntry(ep);
398 400 ep = NULL;
399 401 return (NS_LDAP_MEMORY);
400 402 }
401 403 ep->attr_pair = ap;
402 404
403 405 /* DN attribute */
404 406 dn = ldap_get_dn(ld, e);
405 407 ap[0] = (ns_ldap_attr_t *)calloc(1, sizeof (ns_ldap_attr_t));
406 408 if (ap[0] == NULL) {
407 409 ldap_memfree(dn);
408 410 dn = NULL;
409 411 __ns_ldap_freeEntry(ep);
410 412 ep = NULL;
411 413 return (NS_LDAP_MEMORY);
412 414 }
413 415
414 416 if ((ap[0]->attrname = strdup("dn")) == NULL) {
415 417 ldap_memfree(dn);
416 418 dn = NULL;
417 419 __ns_ldap_freeEntry(ep);
418 420 ep = NULL;
419 421 return (NS_LDAP_INVALID_PARAM);
420 422 }
421 423 ap[0]->value_count = 1;
422 424 if ((ap[0]->attrvalue = (char **)
423 425 calloc(2, sizeof (char *))) == NULL) {
424 426 ldap_memfree(dn);
425 427 dn = NULL;
426 428 __ns_ldap_freeEntry(ep);
427 429 ep = NULL;
428 430 return (NS_LDAP_MEMORY);
429 431 }
430 432
431 433 if (schema_mapping_existed && ((flags & NS_LDAP_NOT_CVT_DN) == 0))
432 434 ap[0]->attrvalue[0] = _cvtDN(service, dn);
433 435 else
434 436 ap[0]->attrvalue[0] = strdup(dn);
435 437
436 438 if (ap[0]->attrvalue[0] == NULL) {
437 439 ldap_memfree(dn);
438 440 dn = NULL;
439 441 __ns_ldap_freeEntry(ep);
440 442 ep = NULL;
441 443 return (NS_LDAP_MEMORY);
442 444 }
443 445 ldap_memfree(dn);
444 446 dn = NULL;
445 447
446 448 if ((flags & NS_LDAP_NOMAP) == 0 && auto_service &&
447 449 schema_mapping_existed) {
448 450 rc = __s_api_convert_automountmapname(service,
449 451 &ap[0]->attrvalue[0],
450 452 error);
451 453 if (rc != NS_LDAP_SUCCESS) {
452 454 __ns_ldap_freeEntry(ep);
453 455 ep = NULL;
454 456 return (rc);
455 457 }
456 458 }
457 459
458 460 /* other attributes */
459 461 for (attr = ldap_first_attribute(ld, e, &ber), j = 1;
460 462 attr != NULL && j != nAttrs;
461 463 attr = ldap_next_attribute(ld, e, ber), j++) {
462 464 /* allocate new attr name */
463 465
464 466 if ((ap[j] = (ns_ldap_attr_t *)
465 467 calloc(1, sizeof (ns_ldap_attr_t))) == NULL) {
466 468 ber_free(ber, 0);
467 469 ber = NULL;
468 470 __ns_ldap_freeEntry(ep);
469 471 ep = NULL;
470 472 if (gecos_mapping)
471 473 __s_api_free2dArray(gecos_mapping);
472 474 gecos_mapping = NULL;
473 475 return (NS_LDAP_MEMORY);
474 476 }
475 477
476 478 if ((flags & NS_LDAP_NOMAP) || schema_mapping_existed == FALSE)
477 479 mapping = NULL;
478 480 else
479 481 mapping = __ns_ldap_getOrigAttribute(service, attr);
480 482
481 483 if (mapping == NULL && auto_service &&
482 484 schema_mapping_existed && (flags & NS_LDAP_NOMAP) == 0)
483 485 /*
484 486 * if service == auto_* and no schema mapping found
485 487 * and schema_mapping_existed is TRUE and NS_LDAP_NOMAP
486 488 * is not set then try automount e.g.
487 489 * NS_LDAP_ATTRIBUTEMAP = automount:automountMapName=AAA
488 490 */
489 491 mapping = __ns_ldap_getOrigAttribute("automount",
490 492 attr);
491 493
492 494 if (mapping == NULL) {
493 495 if ((ap[j]->attrname = strdup(attr)) == NULL) {
494 496 ber_free(ber, 0);
495 497 ber = NULL;
496 498 __ns_ldap_freeEntry(ep);
497 499 ep = NULL;
498 500 if (gecos_mapping)
499 501 __s_api_free2dArray(gecos_mapping);
500 502 gecos_mapping = NULL;
501 503 return (NS_LDAP_MEMORY);
502 504 }
503 505 } else {
504 506 /*
505 507 * for "gecos" 1 to N mapping,
506 508 * do not remove the mapped attribute,
507 509 * just create a new gecos attribute
508 510 * and append it to the end of the attribute list
509 511 */
510 512 if (strcasecmp(mapping[0], "gecos") == 0) {
511 513 ap[j]->attrname = strdup(attr);
512 514 gecos_mapping_existed = TRUE;
513 515 } else
514 516 ap[j]->attrname = strdup(mapping[0]);
515 517
516 518 if (ap[j]->attrname == NULL) {
517 519 ber_free(ber, 0);
518 520 ber = NULL;
519 521 __ns_ldap_freeEntry(ep);
520 522 ep = NULL;
521 523 if (gecos_mapping)
522 524 __s_api_free2dArray(gecos_mapping);
523 525 gecos_mapping = NULL;
524 526 return (NS_LDAP_MEMORY);
525 527 }
526 528 /*
527 529 * 1 to N attribute mapping processing
528 530 * is only done for "gecos"
529 531 */
530 532
531 533 if (strcasecmp(mapping[0], "gecos") == 0) {
532 534 /*
533 535 * get attribute mapping for "gecos",
534 536 * need to know the number and order of the
535 537 * mapped attributes
536 538 */
537 539 if (gecos_mapping == NULL) {
538 540 gecos_mapping =
539 541 __ns_ldap_getMappedAttributes(
540 542 service, mapping[0]);
541 543 if (gecos_mapping == NULL ||
542 544 gecos_mapping[0] == NULL) {
543 545 /*
544 546 * this should never happens,
545 547 * syslog the error
546 548 */
547 549 (void) sprintf(errstr,
548 550 gettext(
549 551 "Attribute mapping "
550 552 "inconsistency "
551 553 "found for attributes "
552 554 "'%s' and '%s'."),
553 555 mapping[0], attr);
554 556 syslog(LOG_ERR, "libsldap: %s",
555 557 errstr);
556 558
557 559 ber_free(ber, 0);
558 560 ber = NULL;
559 561 __ns_ldap_freeEntry(ep);
560 562 ep = NULL;
561 563 __s_api_free2dArray(mapping);
562 564 mapping = NULL;
563 565 if (gecos_mapping)
564 566 __s_api_free2dArray(
565 567 gecos_mapping);
566 568 gecos_mapping = NULL;
567 569 return (NS_LDAP_INTERNAL);
568 570 }
569 571 }
570 572
571 573 /*
572 574 * is this attribute the 1st, 2nd, or
573 575 * 3rd attr in the mapping list?
574 576 */
575 577 gecos_attr_matched = FALSE;
576 578 for (i = 0; i < 3 && gecos_mapping[i]; i++) {
577 579 if (gecos_mapping[i] &&
578 580 strcasecmp(gecos_mapping[i],
579 581 attr) == 0) {
580 582 gecos_val_index[i] = j;
581 583 gecos_attr_matched = TRUE;
582 584 break;
583 585 }
584 586 }
585 587 if (gecos_attr_matched == FALSE) {
586 588 /*
587 589 * Not match found.
588 590 * This should never happens,
589 591 * syslog the error
590 592 */
591 593 (void) sprintf(errstr,
592 594 gettext(
593 595 "Attribute mapping "
594 596 "inconsistency "
595 597 "found for attributes "
596 598 "'%s' and '%s'."),
597 599 mapping[0], attr);
598 600 syslog(LOG_ERR, "libsldap: %s", errstr);
599 601
600 602 ber_free(ber, 0);
601 603 ber = NULL;
602 604 __ns_ldap_freeEntry(ep);
603 605 ep = NULL;
604 606 __s_api_free2dArray(mapping);
605 607 mapping = NULL;
606 608 __s_api_free2dArray(gecos_mapping);
607 609 gecos_mapping = NULL;
608 610 return (NS_LDAP_INTERNAL);
609 611 }
610 612 }
611 613 __s_api_free2dArray(mapping);
612 614 mapping = NULL;
613 615 }
614 616
615 617 if ((vals = ldap_get_values(ld, e, attr)) != NULL) {
616 618
617 619 if ((ap[j]->value_count =
618 620 ldap_count_values(vals)) == 0) {
619 621 ldap_value_free(vals);
620 622 vals = NULL;
621 623 continue;
622 624 } else {
623 625 ap[j]->attrvalue = (char **)
624 626 calloc(ap[j]->value_count+1,
625 627 sizeof (char *));
626 628 if (ap[j]->attrvalue == NULL) {
627 629 ber_free(ber, 0);
628 630 ber = NULL;
629 631 __ns_ldap_freeEntry(ep);
630 632 ep = NULL;
631 633 if (gecos_mapping)
632 634 __s_api_free2dArray(
633 635 gecos_mapping);
634 636 gecos_mapping = NULL;
635 637 return (NS_LDAP_MEMORY);
636 638 }
637 639 }
638 640
639 641 /* map object classes if necessary */
640 642 if ((flags & NS_LDAP_NOMAP) == 0 &&
641 643 schema_mapping_existed && ap[j]->attrname &&
642 644 strcasecmp(ap[j]->attrname, "objectclass") == 0) {
643 645 for (k = 0; k < ap[j]->value_count; k++) {
644 646 mapping =
645 647 __ns_ldap_getOrigObjectClass(
646 648 service, vals[k]);
647 649
648 650 if (mapping == NULL && auto_service)
649 651 /*
650 652 * if service == auto_* and no
651 653 * schema mapping found
652 654 * then try automount
653 655 */
654 656 mapping =
655 657 __ns_ldap_getOrigObjectClass(
656 658 "automount", vals[k]);
657 659
658 660 if (mapping == NULL) {
659 661 ap[j]->attrvalue[k] =
660 662 strdup(vals[k]);
661 663 } else {
662 664 ap[j]->attrvalue[k] =
663 665 strdup(mapping[0]);
664 666 __s_api_free2dArray(mapping);
665 667 mapping = NULL;
666 668 }
667 669 if (ap[j]->attrvalue[k] == NULL) {
668 670 ber_free(ber, 0);
669 671 ber = NULL;
670 672 __ns_ldap_freeEntry(ep);
671 673 ep = NULL;
672 674 if (gecos_mapping)
673 675 __s_api_free2dArray(
674 676 gecos_mapping);
675 677 gecos_mapping = NULL;
676 678 return (NS_LDAP_MEMORY);
677 679 }
678 680 }
679 681 } else {
680 682 for (k = 0; k < ap[j]->value_count; k++) {
681 683 if ((ap[j]->attrvalue[k] =
682 684 strdup(vals[k])) == NULL) {
683 685 ber_free(ber, 0);
684 686 ber = NULL;
685 687 __ns_ldap_freeEntry(ep);
686 688 ep = NULL;
687 689 if (gecos_mapping)
688 690 __s_api_free2dArray(
689 691 gecos_mapping);
690 692 gecos_mapping = NULL;
691 693 return (NS_LDAP_MEMORY);
692 694 }
693 695 }
694 696 }
695 697
696 698 ap[j]->attrvalue[k] = NULL;
697 699 ldap_value_free(vals);
698 700 vals = NULL;
699 701 }
700 702
701 703 ldap_memfree(attr);
702 704 attr = NULL;
703 705 }
704 706
705 707 ber_free(ber, 0);
706 708 ber = NULL;
707 709
708 710 if (gecos_mapping) {
709 711 __s_api_free2dArray(gecos_mapping);
710 712 gecos_mapping = NULL;
711 713 }
712 714
713 715 /* special processing for gecos 1 to up to 3 attribute mapping */
714 716 if (schema_mapping_existed && gecos_mapping_existed) {
715 717
716 718 int f = -1;
717 719
718 720 for (i = 0; i < 3; i++) {
719 721 k = gecos_val_index[i];
720 722
721 723 /*
722 724 * f is the index of the first returned
723 725 * attribute which "gecos" attribute mapped to
724 726 */
725 727 if (k != -1 && f == -1)
726 728 f = k;
727 729
728 730 if (k != -1 && ap[k]->value_count > 0 &&
729 731 ap[k]->attrvalue[0] &&
730 732 strlen(ap[k]->attrvalue[0]) > 0) {
731 733
732 734 if (k == f) {
733 735 /*
734 736 * Create and fill in the last reserved
735 737 * ap with the data from the "gecos"
736 738 * mapping attributes
737 739 */
738 740 ap[nAttrs] = (ns_ldap_attr_t *)
739 741 calloc(1,
740 742 sizeof (ns_ldap_attr_t));
741 743 if (ap[nAttrs] == NULL) {
742 744 __ns_ldap_freeEntry(ep);
743 745 ep = NULL;
744 746 return (NS_LDAP_MEMORY);
745 747 }
746 748 ap[nAttrs]->attrvalue = (char **)calloc(
747 749 2, sizeof (char *));
748 750 if (ap[nAttrs]->attrvalue == NULL) {
749 751 __ns_ldap_freeEntry(ep);
750 752 ep = NULL;
751 753 return (NS_LDAP_MEMORY);
752 754 }
753 755 /* add 1 more for a possible "," */
754 756 ap[nAttrs]->attrvalue[0] =
755 757 (char *)calloc(
756 758 strlen(ap[f]->attrvalue[0]) +
757 759 2, 1);
758 760 if (ap[nAttrs]->attrvalue[0] == NULL) {
759 761 __ns_ldap_freeEntry(ep);
760 762 ep = NULL;
761 763 return (NS_LDAP_MEMORY);
762 764 }
763 765 (void) strcpy(ap[nAttrs]->attrvalue[0],
764 766 ap[f]->attrvalue[0]);
765 767
766 768 ap[nAttrs]->attrname = strdup("gecos");
767 769 if (ap[nAttrs]->attrname == NULL) {
768 770 __ns_ldap_freeEntry(ep);
769 771 ep = NULL;
770 772 return (NS_LDAP_MEMORY);
771 773 }
772 774
773 775 ap[nAttrs]->value_count = 1;
774 776 ep->attr_count = nAttrs + 1;
775 777
776 778 } else {
777 779 char *tmp = NULL;
778 780
779 781 /*
780 782 * realloc to add "," and
781 783 * ap[k]->attrvalue[0]
782 784 */
783 785 tmp = (char *)realloc(
784 786 ap[nAttrs]->attrvalue[0],
785 787 strlen(ap[nAttrs]->
786 788 attrvalue[0]) +
787 789 strlen(ap[k]->
788 790 attrvalue[0]) + 2);
789 791 if (tmp == NULL) {
790 792 __ns_ldap_freeEntry(ep);
791 793 ep = NULL;
792 794 return (NS_LDAP_MEMORY);
793 795 }
794 796 ap[nAttrs]->attrvalue[0] = tmp;
795 797 (void) strcat(ap[nAttrs]->attrvalue[0],
796 798 ",");
797 799 (void) strcat(ap[nAttrs]->attrvalue[0],
798 800 ap[k]->attrvalue[0]);
799 801 }
800 802 }
801 803 }
802 804 }
803 805
804 806 *ret = ep;
805 807 return (NS_LDAP_SUCCESS);
806 808 }
807 809
808 810 static int
809 811 __s_api_getEntry(ns_ldap_cookie_t *cookie)
810 812 {
811 813 ns_ldap_entry_t *curEntry = NULL;
812 814 int ret;
813 815
814 816 #ifdef DEBUG
815 817 (void) fprintf(stderr, "__s_api_getEntry START\n");
816 818 #endif
817 819
818 820 if (cookie->resultMsg == NULL) {
819 821 return (NS_LDAP_INVALID_PARAM);
820 822 }
821 823 ret = __s_api_cvtEntry(cookie->conn->ld, cookie->service,
822 824 cookie->resultMsg, cookie->i_flags,
823 825 &curEntry, &cookie->errorp);
824 826 if (ret != NS_LDAP_SUCCESS) {
825 827 return (ret);
826 828 }
827 829
828 830 if (cookie->result == NULL) {
829 831 cookie->result = (ns_ldap_result_t *)
830 832 calloc(1, sizeof (ns_ldap_result_t));
831 833 if (cookie->result == NULL) {
832 834 __ns_ldap_freeEntry(curEntry);
833 835 curEntry = NULL;
834 836 return (NS_LDAP_MEMORY);
835 837 }
836 838 cookie->result->entry = curEntry;
837 839 cookie->nextEntry = curEntry;
838 840 } else {
839 841 cookie->nextEntry->next = curEntry;
840 842 cookie->nextEntry = curEntry;
841 843 }
842 844 cookie->result->entries_count++;
843 845
844 846 return (NS_LDAP_SUCCESS);
845 847 }
846 848
847 849 static int
848 850 __s_api_get_cachemgr_data(const char *type,
849 851 const char *from, char **to)
850 852 {
851 853 union {
852 854 ldap_data_t s_d;
853 855 char s_b[DOORBUFFERSIZE];
854 856 } space;
855 857 ldap_data_t *sptr;
856 858 int ndata;
857 859 int adata;
858 860 int rc;
859 861
860 862 #ifdef DEBUG
861 863 (void) fprintf(stderr, "__s_api_get_cachemgr_data START\n");
862 864 #endif
863 865 /*
864 866 * We are not going to perform DN to domain mapping
865 867 * in the Standalone mode
866 868 */
867 869 if (__s_api_isStandalone()) {
868 870 return (-1);
869 871 }
870 872
871 873 if (from == NULL || from[0] == '\0' || to == NULL)
872 874 return (-1);
873 875
874 876 *to = NULL;
875 877 (void) memset(space.s_b, 0, DOORBUFFERSIZE);
876 878
877 879 space.s_d.ldap_call.ldap_callnumber = GETCACHE;
878 880 (void) snprintf(space.s_d.ldap_call.ldap_u.domainname,
879 881 DOORBUFFERSIZE - sizeof (space.s_d.ldap_call.ldap_callnumber),
880 882 "%s%s%s",
881 883 type,
882 884 DOORLINESEP,
883 885 from);
884 886 ndata = sizeof (space);
885 887 adata = sizeof (ldap_call_t) +
886 888 strlen(space.s_d.ldap_call.ldap_u.domainname) + 1;
887 889 sptr = &space.s_d;
888 890
889 891 rc = __ns_ldap_trydoorcall(&sptr, &ndata, &adata);
890 892 if (rc != NS_CACHE_SUCCESS)
891 893 return (-1);
892 894 else
893 895 *to = strdup(sptr->ldap_ret.ldap_u.buff);
894 896 return (NS_LDAP_SUCCESS);
895 897 }
896 898
897 899 static int
898 900 __s_api_set_cachemgr_data(const char *type,
899 901 const char *from, const char *to)
900 902 {
901 903 union {
902 904 ldap_data_t s_d;
903 905 char s_b[DOORBUFFERSIZE];
904 906 } space;
905 907 ldap_data_t *sptr;
906 908 int ndata;
907 909 int adata;
908 910 int rc;
909 911
910 912 #ifdef DEBUG
911 913 (void) fprintf(stderr, "__s_api_set_cachemgr_data START\n");
912 914 #endif
913 915 /*
914 916 * We are not going to perform DN to domain mapping
915 917 * in the Standalone mode
916 918 */
917 919 if (__s_api_isStandalone()) {
918 920 return (-1);
919 921 }
920 922
921 923 if ((from == NULL) || (from[0] == '\0') ||
922 924 (to == NULL) || (to[0] == '\0'))
923 925 return (-1);
924 926
925 927 (void) memset(space.s_b, 0, DOORBUFFERSIZE);
926 928
927 929 space.s_d.ldap_call.ldap_callnumber = SETCACHE;
928 930 (void) snprintf(space.s_d.ldap_call.ldap_u.domainname,
929 931 DOORBUFFERSIZE - sizeof (space.s_d.ldap_call.ldap_callnumber),
930 932 "%s%s%s%s%s",
931 933 type,
932 934 DOORLINESEP,
933 935 from,
934 936 DOORLINESEP,
935 937 to);
936 938
937 939 ndata = sizeof (space);
938 940 adata = sizeof (ldap_call_t) +
939 941 strlen(space.s_d.ldap_call.ldap_u.domainname) + 1;
940 942 sptr = &space.s_d;
941 943
942 944 rc = __ns_ldap_trydoorcall(&sptr, &ndata, &adata);
943 945 if (rc != NS_CACHE_SUCCESS)
944 946 return (-1);
945 947
946 948 return (NS_LDAP_SUCCESS);
947 949 }
948 950
949 951
950 952 static char *
951 953 __s_api_remove_rdn_space(char *rdn)
952 954 {
953 955 char *tf, *tl, *vf, *vl, *eqsign;
954 956
955 957 /* if no space(s) to remove, return */
956 958 if (strchr(rdn, SPACETOK) == NULL)
957 959 return (rdn);
958 960
959 961 /* if no '=' separator, return */
960 962 eqsign = strchr(rdn, '=');
961 963 if (eqsign == NULL)
962 964 return (rdn);
963 965
964 966 tf = rdn;
965 967 tl = eqsign - 1;
966 968 vf = eqsign + 1;
967 969 vl = rdn + strlen(rdn) - 1;
968 970
969 971 /* now two strings, type and value */
970 972 *eqsign = '\0';
971 973
972 974 /* remove type's leading spaces */
973 975 while (tf < tl && *tf == SPACETOK)
974 976 tf++;
975 977 /* remove type's trailing spaces */
976 978 while (tf < tl && *tl == SPACETOK)
977 979 tl--;
978 980 /* add '=' separator back */
979 981 *(++tl) = '=';
980 982 /* remove value's leading spaces */
981 983 while (vf < vl && *vf == SPACETOK)
982 984 vf++;
983 985 /* remove value's trailing spaces */
984 986 while (vf < vl && *vl == SPACETOK)
985 987 *vl-- = '\0';
986 988
987 989 /* move value up if necessary */
988 990 if (vf != tl + 1)
989 991 (void) strcpy(tl + 1, vf);
990 992
991 993 return (tf);
992 994 }
993 995
994 996 static
995 997 ns_ldap_cookie_t *
996 998 init_search_state_machine()
997 999 {
998 1000 ns_ldap_cookie_t *cookie;
999 1001 ns_config_t *cfg;
1000 1002
1001 1003 cookie = (ns_ldap_cookie_t *)calloc(1, sizeof (ns_ldap_cookie_t));
1002 1004 if (cookie == NULL)
1003 1005 return (NULL);
1004 1006 cookie->state = INIT;
1005 1007 /* assign other state variables */
1006 1008 cfg = __s_api_loadrefresh_config();
1007 1009 cookie->connectionId = -1;
1008 1010 if (cfg == NULL ||
1009 1011 cfg->paramList[NS_LDAP_SEARCH_TIME_P].ns_ptype == NS_UNKNOWN) {
1010 1012 cookie->search_timeout.tv_sec = NS_DEFAULT_SEARCH_TIMEOUT;
1011 1013 } else {
1012 1014 cookie->search_timeout.tv_sec =
1013 1015 cfg->paramList[NS_LDAP_SEARCH_TIME_P].ns_i;
1014 1016 }
1015 1017 if (cfg != NULL)
1016 1018 __s_api_release_config(cfg);
1017 1019 cookie->search_timeout.tv_usec = 0;
1018 1020
1019 1021 return (cookie);
1020 1022 }
1021 1023
1022 1024 static void
1023 1025 delete_search_cookie(ns_ldap_cookie_t *cookie)
1024 1026 {
1025 1027 if (cookie == NULL)
1026 1028 return;
1027 1029 if (cookie->connectionId > -1)
1028 1030 DropConnection(cookie->connectionId, cookie->i_flags);
1029 1031 if (cookie->filter)
1030 1032 free(cookie->filter);
1031 1033 if (cookie->i_filter)
1032 1034 free(cookie->i_filter);
1033 1035 if (cookie->service)
1034 1036 free(cookie->service);
1035 1037 if (cookie->sdlist)
1036 1038 (void) __ns_ldap_freeSearchDescriptors(&(cookie->sdlist));
1037 1039 if (cookie->result)
1038 1040 (void) __ns_ldap_freeResult(&cookie->result);
1039 1041 if (cookie->attribute)
1040 1042 __s_api_free2dArray(cookie->attribute);
1041 1043 if (cookie->errorp)
1042 1044 (void) __ns_ldap_freeError(&cookie->errorp);
1043 1045 if (cookie->reflist)
1044 1046 __s_api_deleteRefInfo(cookie->reflist);
1045 1047 if (cookie->basedn)
1046 1048 free(cookie->basedn);
1047 1049 if (cookie->ctrlCookie)
1048 1050 ber_bvfree(cookie->ctrlCookie);
1049 1051 _freeControlList(&cookie->p_serverctrls);
1050 1052 if (cookie->resultctrl)
1051 1053 ldap_controls_free(cookie->resultctrl);
1052 1054 free(cookie);
1053 1055 }
1054 1056
1055 1057 static int
1056 1058 get_mapped_filter(ns_ldap_cookie_t *cookie, char **new_filter)
1057 1059 {
1058 1060
1059 1061 typedef struct filter_mapping_info {
1060 1062 char oc_or_attr;
1061 1063 char *name_start;
1062 1064 char *name_end;
1063 1065 char *veq_pos;
1064 1066 char *from_name;
1065 1067 char *to_name;
1066 1068 char **mapping;
1067 1069 } filter_mapping_info_t;
1068 1070
1069 1071 char *c, *last_copied;
1070 1072 char *filter_c, *filter_c_next;
1071 1073 char *key, *tail, *head;
1072 1074 char errstr[MAXERROR];
1073 1075 int num_eq = 0, num_veq = 0;
1074 1076 int in_quote = FALSE;
1075 1077 int is_value = FALSE;
1076 1078 int i, j, oc_len, len;
1077 1079 int at_least_one = FALSE;
1078 1080 filter_mapping_info_t **info, *info1;
1079 1081 char **mapping;
1080 1082 char *service, *filter, *err;
1081 1083 int auto_service = FALSE;
1082 1084
1083 1085 if (cookie == NULL || new_filter == NULL)
1084 1086 return (NS_LDAP_INVALID_PARAM);
1085 1087
1086 1088 *new_filter = NULL;
1087 1089 service = cookie->service;
1088 1090 filter = cookie->filter;
1089 1091
1090 1092 /*
1091 1093 * count the number of '=' char
1092 1094 */
1093 1095 for (c = filter; *c; c++) {
1094 1096 if (*c == TOKENSEPARATOR)
1095 1097 num_eq++;
1096 1098 }
1097 1099
1098 1100 if (service != NULL && strncasecmp(service, "auto_", 5) == 0)
1099 1101 auto_service = TRUE;
1100 1102
1101 1103 /*
1102 1104 * See if schema mapping existed for the given service.
1103 1105 * If not, just return success.
1104 1106 */
1105 1107 mapping = __ns_ldap_getOrigAttribute(service,
1106 1108 NS_HASH_SCHEMA_MAPPING_EXISTED);
1107 1109
1108 1110 if (mapping == NULL && auto_service)
1109 1111 /*
1110 1112 * if service == auto_* and no
1111 1113 * schema mapping found
1112 1114 * then try automount
1113 1115 */
1114 1116 mapping = __ns_ldap_getOrigAttribute(
1115 1117 "automount", NS_HASH_SCHEMA_MAPPING_EXISTED);
1116 1118
1117 1119 if (mapping)
1118 1120 __s_api_free2dArray(mapping);
1119 1121 else
1120 1122 return (NS_LDAP_SUCCESS);
1121 1123
1122 1124 /*
1123 1125 * no '=' sign, just say OK and return nothing
1124 1126 */
1125 1127 if (num_eq == 0)
1126 1128 return (NS_LDAP_SUCCESS);
1127 1129
1128 1130 /*
1129 1131 * Make a copy of the filter string
1130 1132 * for saving the name of the objectclasses or
1131 1133 * attributes that need to be passed to the
1132 1134 * objectclass or attribute mapping functions.
1133 1135 * pointer "info->from_name" points to the locations
1134 1136 * within this string.
1135 1137 *
1136 1138 * The input filter string, filter, will be used
1137 1139 * to indicate where these names start and end.
1138 1140 * pointers "info->name_start" and "info->name_end"
1139 1141 * point to locations within the input filter string,
1140 1142 * and are used at the end of this function to
1141 1143 * merge the original filter data with the
1142 1144 * mapped objectclass or attribute names.
1143 1145 */
1144 1146 filter_c = strdup(filter);
1145 1147 if (filter_c == NULL)
1146 1148 return (NS_LDAP_MEMORY);
1147 1149 filter_c_next = filter_c;
1148 1150
1149 1151 /*
1150 1152 * get memory for info arrays
1151 1153 */
1152 1154 info = (filter_mapping_info_t **)calloc(num_eq + 1,
1153 1155 sizeof (filter_mapping_info_t *));
1154 1156
1155 1157 if (info == NULL) {
1156 1158 free(filter_c);
1157 1159 return (NS_LDAP_MEMORY);
1158 1160 }
1159 1161
1160 1162 /*
1161 1163 * find valid '=' for further processing,
1162 1164 * ignore the "escaped =" (.i.e. "\="), or
1163 1165 * "=" in quoted string
1164 1166 */
1165 1167 for (c = filter_c; *c; c++) {
1166 1168
1167 1169 switch (*c) {
1168 1170 case TOKENSEPARATOR:
1169 1171 if (!in_quote && !is_value) {
1170 1172 info1 = (filter_mapping_info_t *)calloc(1,
1171 1173 sizeof (filter_mapping_info_t));
1172 1174 if (!info1) {
1173 1175 free(filter_c);
1174 1176 for (i = 0; i < num_veq; i++)
1175 1177 free(info[i]);
1176 1178 free(info);
1177 1179 return (NS_LDAP_MEMORY);
1178 1180 }
1179 1181 info[num_veq] = info1;
1180 1182
1181 1183 /*
1182 1184 * remember the location of this "="
1183 1185 */
1184 1186 info[num_veq++]->veq_pos = c;
1185 1187
1186 1188 /*
1187 1189 * skip until the end of the attribute value
1188 1190 */
1189 1191 is_value = TRUE;
1190 1192 }
1191 1193 break;
1192 1194 case CPARATOK:
1193 1195 /*
1194 1196 * mark the end of the attribute value
1195 1197 */
1196 1198 if (!in_quote)
1197 1199 is_value = FALSE;
1198 1200 break;
1199 1201 case QUOTETOK:
1200 1202 /*
1201 1203 * switch on/off the in_quote mode
1202 1204 */
1203 1205 in_quote = (in_quote == FALSE);
1204 1206 break;
1205 1207 case '\\':
1206 1208 /*
1207 1209 * ignore escape characters
1208 1210 * don't skip if next char is '\0'
1209 1211 */
1210 1212 if (!in_quote)
1211 1213 if (*(++c) == '\0')
1212 1214 c--;
1213 1215 break;
1214 1216 }
1215 1217
1216 1218 }
1217 1219
1218 1220 /*
1219 1221 * for each valid "=" found, get the name to
1220 1222 * be mapped
1221 1223 */
1222 1224 oc_len = strlen("objectclass");
1223 1225 for (i = 0; i < num_veq; i++) {
1224 1226
1225 1227 /*
1226 1228 * look at the left side of "=" to see
1227 1229 * if assertion is "objectclass=<ocname>"
1228 1230 * or "<attribute name>=<attribute value>"
1229 1231 *
1230 1232 * first skip spaces before "=".
1231 1233 * Note that filter_c_next may not point to the
1232 1234 * start of the filter string. For i > 0,
1233 1235 * it points to the end of the last name processed + 2
1234 1236 */
1235 1237 for (tail = info[i]->veq_pos; (tail > filter_c_next) &&
1236 1238 (*(tail - 1) == SPACETOK); tail--)
1237 1239 ;
1238 1240
1239 1241 /*
1240 1242 * mark the end of the left side string (the key)
1241 1243 */
1242 1244 *tail = '\0';
1243 1245 info[i]->name_end = tail - filter_c - 1 + filter;
1244 1246
1245 1247 /*
1246 1248 * find the start of the key
1247 1249 */
1248 1250 key = filter_c_next;
1249 1251 for (c = tail; filter_c_next <= c; c--) {
1250 1252 /* OPARATOK is '(' */
1251 1253 if (*c == OPARATOK ||
1252 1254 *c == SPACETOK) {
1253 1255 key = c + 1;
1254 1256 break;
1255 1257 }
1256 1258 }
1257 1259 info[i]->name_start = key - filter_c + filter;
1258 1260
1259 1261 if ((key + oc_len) <= tail) {
1260 1262 if (strncasecmp(key, "objectclass",
1261 1263 oc_len) == 0) {
1262 1264 /*
1263 1265 * assertion is "objectclass=ocname",
1264 1266 * ocname is the one needs to be mapped
1265 1267 *
1266 1268 * skip spaces after "=" to find start
1267 1269 * of the ocname
1268 1270 */
1269 1271 head = info[i]->veq_pos;
1270 1272 for (head = info[i]->veq_pos + 1;
1271 1273 *head && *head == SPACETOK; head++)
1272 1274 ;
1273 1275
1274 1276 /* ignore empty ocname */
1275 1277 if (!(*head))
1276 1278 continue;
1277 1279
1278 1280 info[i]->name_start = head - filter_c +
1279 1281 filter;
1280 1282
1281 1283 /*
1282 1284 * now find the end of the ocname
1283 1285 */
1284 1286 for (c = head; ; c++) {
1285 1287 /* CPARATOK is ')' */
1286 1288 if (*c == CPARATOK ||
1287 1289 *c == '\0' ||
1288 1290 *c == SPACETOK) {
1289 1291 *c = '\0';
1290 1292 info[i]->name_end =
1291 1293 c - filter_c - 1 +
1292 1294 filter;
1293 1295 filter_c_next = c + 1;
1294 1296 info[i]->oc_or_attr = 'o';
1295 1297 info[i]->from_name = head;
1296 1298 break;
1297 1299 }
1298 1300 }
1299 1301 }
1300 1302 }
1301 1303
1302 1304 /*
1303 1305 * assertion is not "objectclass=ocname",
1304 1306 * assume assertion is "<key> = <value>",
1305 1307 * <key> is the one needs to be mapped
1306 1308 */
1307 1309 if (info[i]->from_name == NULL && strlen(key) > 0) {
1308 1310 info[i]->oc_or_attr = 'a';
1309 1311 info[i]->from_name = key;
1310 1312 }
1311 1313 }
1312 1314
1313 1315 /* perform schema mapping */
1314 1316 for (i = 0; i < num_veq; i++) {
1315 1317 if (info[i]->from_name == NULL)
1316 1318 continue;
1317 1319
1318 1320 if (info[i]->oc_or_attr == 'a')
1319 1321 info[i]->mapping =
1320 1322 __ns_ldap_getMappedAttributes(service,
1321 1323 info[i]->from_name);
1322 1324 else
1323 1325 info[i]->mapping =
1324 1326 __ns_ldap_getMappedObjectClass(service,
1325 1327 info[i]->from_name);
1326 1328
1327 1329 if (info[i]->mapping == NULL && auto_service) {
1328 1330 /*
1329 1331 * If no mapped attribute/objectclass is found
1330 1332 * and service == auto*
1331 1333 * try to find automount's
1332 1334 * mapped attribute/objectclass
1333 1335 */
1334 1336 if (info[i]->oc_or_attr == 'a')
1335 1337 info[i]->mapping =
1336 1338 __ns_ldap_getMappedAttributes("automount",
1337 1339 info[i]->from_name);
1338 1340 else
1339 1341 info[i]->mapping =
1340 1342 __ns_ldap_getMappedObjectClass("automount",
1341 1343 info[i]->from_name);
1342 1344 }
1343 1345
1344 1346 if (info[i]->mapping == NULL ||
1345 1347 info[i]->mapping[0] == NULL) {
1346 1348 info[i]->to_name = NULL;
1347 1349 } else if (info[i]->mapping[1] == NULL) {
1348 1350 info[i]->to_name = info[i]->mapping[0];
1349 1351 at_least_one = TRUE;
1350 1352 } else {
1351 1353 __s_api_free2dArray(info[i]->mapping);
1352 1354 /*
1353 1355 * multiple mapping
1354 1356 * not allowed
1355 1357 */
1356 1358 (void) sprintf(errstr,
1357 1359 gettext(
1358 1360 "Multiple attribute or objectclass "
1359 1361 "mapping for '%s' in filter "
1360 1362 "'%s' not allowed."),
1361 1363 info[i]->from_name, filter);
1362 1364 err = strdup(errstr);
1363 1365 if (err)
1364 1366 MKERROR(LOG_WARNING, cookie->errorp,
1365 1367 NS_CONFIG_SYNTAX,
1366 1368 err, NULL);
1367 1369
1368 1370 free(filter_c);
1369 1371 for (j = 0; j < num_veq; j++) {
1370 1372 if (info[j]->mapping)
1371 1373 __s_api_free2dArray(
1372 1374 info[j]->mapping);
1373 1375 free(info[j]);
1374 1376 }
1375 1377 free(info);
1376 1378 return (NS_LDAP_CONFIG);
1377 1379 }
1378 1380 }
1379 1381
1380 1382
1381 1383 if (at_least_one) {
1382 1384
1383 1385 len = strlen(filter);
1384 1386 last_copied = filter - 1;
1385 1387
1386 1388 for (i = 0; i < num_veq; i++) {
1387 1389 if (info[i]->to_name)
1388 1390 len += strlen(info[i]->to_name);
1389 1391 }
1390 1392
1391 1393 *new_filter = (char *)calloc(1, len);
1392 1394 if (*new_filter == NULL) {
1393 1395 free(filter_c);
1394 1396 for (j = 0; j < num_veq; j++) {
1395 1397 if (info[j]->mapping)
1396 1398 __s_api_free2dArray(
1397 1399 info[j]->mapping);
1398 1400 free(info[j]);
1399 1401 }
1400 1402 free(info);
1401 1403 return (NS_LDAP_MEMORY);
1402 1404 }
1403 1405
1404 1406 for (i = 0; i < num_veq; i++) {
1405 1407 if (info[i]->to_name != NULL &&
1406 1408 info[i]->to_name != NULL) {
1407 1409
1408 1410 /*
1409 1411 * copy the original filter data
1410 1412 * between the last name and current
1411 1413 * name
1412 1414 */
1413 1415 if ((last_copied + 1) != info[i]->name_start)
1414 1416 (void) strncat(*new_filter,
1415 1417 last_copied + 1,
1416 1418 info[i]->name_start -
1417 1419 last_copied - 1);
1418 1420
1419 1421 /* the data is copied */
1420 1422 last_copied = info[i]->name_end;
1421 1423
1422 1424 /*
1423 1425 * replace the name with
1424 1426 * the mapped name
1425 1427 */
1426 1428 (void) strcat(*new_filter, info[i]->to_name);
1427 1429 }
1428 1430
1429 1431 /* copy the filter data after the last name */
1430 1432 if (i == (num_veq -1) &&
1431 1433 info[i]->name_end <
1432 1434 (filter + strlen(filter)))
1433 1435 (void) strncat(*new_filter, last_copied + 1,
1434 1436 filter + strlen(filter) -
1435 1437 last_copied - 1);
1436 1438 }
1437 1439
1438 1440 }
1439 1441
1440 1442 /* free memory */
1441 1443 free(filter_c);
1442 1444 for (j = 0; j < num_veq; j++) {
1443 1445 if (info[j]->mapping)
1444 1446 __s_api_free2dArray(info[j]->mapping);
1445 1447 free(info[j]);
1446 1448 }
1447 1449 free(info);
1448 1450
1449 1451 return (NS_LDAP_SUCCESS);
1450 1452 }
1451 1453
1452 1454 static int
1453 1455 setup_next_search(ns_ldap_cookie_t *cookie)
1454 1456 {
1455 1457 ns_ldap_search_desc_t *dptr;
1456 1458 int scope;
1457 1459 char *filter, *str;
1458 1460 int baselen;
1459 1461 int rc;
1460 1462 void **param;
1461 1463
1462 1464 dptr = *cookie->sdpos;
1463 1465 scope = cookie->i_flags & (NS_LDAP_SCOPE_BASE |
1464 1466 NS_LDAP_SCOPE_ONELEVEL |
1465 1467 NS_LDAP_SCOPE_SUBTREE);
1466 1468 if (scope)
1467 1469 cookie->scope = scope;
1468 1470 else
1469 1471 cookie->scope = dptr->scope;
1470 1472 switch (cookie->scope) {
1471 1473 case NS_LDAP_SCOPE_BASE:
1472 1474 cookie->scope = LDAP_SCOPE_BASE;
1473 1475 break;
1474 1476 case NS_LDAP_SCOPE_ONELEVEL:
1475 1477 cookie->scope = LDAP_SCOPE_ONELEVEL;
1476 1478 break;
1477 1479 case NS_LDAP_SCOPE_SUBTREE:
1478 1480 cookie->scope = LDAP_SCOPE_SUBTREE;
1479 1481 break;
1480 1482 }
1481 1483
1482 1484 filter = NULL;
1483 1485 if (cookie->use_filtercb && cookie->init_filter_cb &&
1484 1486 dptr->filter && strlen(dptr->filter) > 0) {
1485 1487 (*cookie->init_filter_cb)(dptr, &filter,
1486 1488 cookie->userdata);
1487 1489 }
1488 1490 if (filter == NULL) {
1489 1491 if (cookie->i_filter == NULL) {
1490 1492 cookie->err_rc = NS_LDAP_INVALID_PARAM;
1491 1493 return (-1);
1492 1494 } else {
1493 1495 if (cookie->filter)
1494 1496 free(cookie->filter);
1495 1497 cookie->filter = strdup(cookie->i_filter);
1496 1498 if (cookie->filter == NULL) {
1497 1499 cookie->err_rc = NS_LDAP_MEMORY;
1498 1500 return (-1);
1499 1501 }
1500 1502 }
1501 1503 } else {
1502 1504 if (cookie->filter)
1503 1505 free(cookie->filter);
1504 1506 cookie->filter = strdup(filter);
1505 1507 free(filter);
1506 1508 if (cookie->filter == NULL) {
1507 1509 cookie->err_rc = NS_LDAP_MEMORY;
1508 1510 return (-1);
1509 1511 }
1510 1512 }
1511 1513
1512 1514 /*
1513 1515 * perform attribute/objectclass mapping on filter
1514 1516 */
1515 1517 filter = NULL;
1516 1518
1517 1519 if (cookie->service) {
1518 1520 rc = get_mapped_filter(cookie, &filter);
1519 1521 if (rc != NS_LDAP_SUCCESS) {
1520 1522 cookie->err_rc = rc;
1521 1523 return (-1);
1522 1524 } else {
1523 1525 /*
1524 1526 * get_mapped_filter returns
1525 1527 * NULL filter pointer, if
1526 1528 * no mapping was done
1527 1529 */
1528 1530 if (filter) {
1529 1531 free(cookie->filter);
1530 1532 cookie->filter = filter;
1531 1533 }
1532 1534 }
1533 1535 }
1534 1536
1535 1537 /*
1536 1538 * validate filter to make sure it's legal
1537 1539 * [remove redundant ()'s]
1538 1540 */
1539 1541 rc = validate_filter(cookie);
1540 1542 if (rc != NS_LDAP_SUCCESS) {
1541 1543 cookie->err_rc = rc;
1542 1544 return (-1);
1543 1545 }
1544 1546
1545 1547 baselen = strlen(dptr->basedn);
1546 1548 if (baselen > 0 && dptr->basedn[baselen-1] == COMMATOK) {
1547 1549 rc = __ns_ldap_getParam(NS_LDAP_SEARCH_BASEDN_P,
1548 1550 (void ***)¶m, &cookie->errorp);
1549 1551 if (rc != NS_LDAP_SUCCESS) {
1550 1552 cookie->err_rc = rc;
1551 1553 return (-1);
1552 1554 }
1553 1555 str = ((char **)param)[0];
1554 1556 baselen += strlen(str)+1;
1555 1557 if (cookie->basedn)
1556 1558 free(cookie->basedn);
1557 1559 cookie->basedn = (char *)malloc(baselen);
1558 1560 if (cookie->basedn == NULL) {
1559 1561 cookie->err_rc = NS_LDAP_MEMORY;
1560 1562 return (-1);
1561 1563 }
1562 1564 (void) strcpy(cookie->basedn, dptr->basedn);
1563 1565 (void) strcat(cookie->basedn, str);
1564 1566 (void) __ns_ldap_freeParam(¶m);
1565 1567 } else {
1566 1568 if (cookie->basedn)
1567 1569 free(cookie->basedn);
1568 1570 cookie->basedn = strdup(dptr->basedn);
1569 1571 }
1570 1572 return (0);
1571 1573 }
1572 1574
1573 1575 static int
1574 1576 setup_referral_search(ns_ldap_cookie_t *cookie)
1575 1577 {
1576 1578 ns_referral_info_t *ref;
1577 1579
1578 1580 ref = cookie->refpos;
1579 1581 cookie->scope = ref->refScope;
1580 1582 if (cookie->filter) {
1581 1583 free(cookie->filter);
1582 1584 }
1583 1585 cookie->filter = strdup(ref->refFilter);
1584 1586 if (cookie->basedn) {
1585 1587 free(cookie->basedn);
1586 1588 }
1587 1589 cookie->basedn = strdup(ref->refDN);
1588 1590 if (cookie->filter == NULL || cookie->basedn == NULL) {
1589 1591 cookie->err_rc = NS_LDAP_MEMORY;
1590 1592 return (-1);
1591 1593 }
1592 1594 return (0);
1593 1595 }
1594 1596
1595 1597 static int
1596 1598 get_current_session(ns_ldap_cookie_t *cookie)
1597 1599 {
1598 1600 ConnectionID connectionId = -1;
1599 1601 Connection *conp = NULL;
1600 1602 int rc;
1601 1603 int fail_if_new_pwd_reqd = 1;
1602 1604
1603 1605 rc = __s_api_getConnection(NULL, cookie->i_flags,
1604 1606 cookie->i_auth, &connectionId, &conp,
1605 1607 &cookie->errorp, fail_if_new_pwd_reqd,
1606 1608 cookie->nopasswd_acct_mgmt, cookie->conn_user);
1607 1609
1608 1610 /*
1609 1611 * If password control attached in *cookie->errorp,
1610 1612 * e.g. rc == NS_LDAP_SUCCESS_WITH_INFO,
1611 1613 * free the error structure (we do not need
1612 1614 * the sec_to_expired info).
1613 1615 * Reset rc to NS_LDAP_SUCCESS.
1614 1616 */
1615 1617 if (rc == NS_LDAP_SUCCESS_WITH_INFO) {
1616 1618 (void) __ns_ldap_freeError(
1617 1619 &cookie->errorp);
1618 1620 cookie->errorp = NULL;
1619 1621 rc = NS_LDAP_SUCCESS;
1620 1622 }
1621 1623
1622 1624 if (rc != NS_LDAP_SUCCESS) {
1623 1625 cookie->err_rc = rc;
1624 1626 return (-1);
1625 1627 }
1626 1628 cookie->conn = conp;
1627 1629 cookie->connectionId = connectionId;
1628 1630
1629 1631 return (0);
1630 1632 }
1631 1633
1632 1634 static int
1633 1635 get_next_session(ns_ldap_cookie_t *cookie)
1634 1636 {
1635 1637 ConnectionID connectionId = -1;
1636 1638 Connection *conp = NULL;
1637 1639 int rc;
1638 1640 int fail_if_new_pwd_reqd = 1;
1639 1641
1640 1642 if (cookie->connectionId > -1) {
1641 1643 DropConnection(cookie->connectionId, cookie->i_flags);
1642 1644 cookie->connectionId = -1;
1643 1645 }
1644 1646
1645 1647 /* If using a MT connection, return it. */
1646 1648 if (cookie->conn_user != NULL &&
1647 1649 cookie->conn_user->conn_mt != NULL)
1648 1650 __s_api_conn_mt_return(cookie->conn_user);
1649 1651
1650 1652 rc = __s_api_getConnection(NULL, cookie->i_flags,
1651 1653 cookie->i_auth, &connectionId, &conp,
1652 1654 &cookie->errorp, fail_if_new_pwd_reqd,
1653 1655 cookie->nopasswd_acct_mgmt, cookie->conn_user);
1654 1656
1655 1657 /*
1656 1658 * If password control attached in *cookie->errorp,
1657 1659 * e.g. rc == NS_LDAP_SUCCESS_WITH_INFO,
1658 1660 * free the error structure (we do not need
1659 1661 * the sec_to_expired info).
1660 1662 * Reset rc to NS_LDAP_SUCCESS.
1661 1663 */
1662 1664 if (rc == NS_LDAP_SUCCESS_WITH_INFO) {
1663 1665 (void) __ns_ldap_freeError(
1664 1666 &cookie->errorp);
1665 1667 cookie->errorp = NULL;
1666 1668 rc = NS_LDAP_SUCCESS;
1667 1669 }
1668 1670
1669 1671 if (rc != NS_LDAP_SUCCESS) {
1670 1672 cookie->err_rc = rc;
1671 1673 return (-1);
1672 1674 }
1673 1675 cookie->conn = conp;
1674 1676 cookie->connectionId = connectionId;
1675 1677 return (0);
1676 1678 }
1677 1679
1678 1680 static int
1679 1681 get_referral_session(ns_ldap_cookie_t *cookie)
1680 1682 {
1681 1683 ConnectionID connectionId = -1;
1682 1684 Connection *conp = NULL;
1683 1685 int rc;
1684 1686 int fail_if_new_pwd_reqd = 1;
1685 1687
1686 1688 if (cookie->connectionId > -1) {
1687 1689 DropConnection(cookie->connectionId, cookie->i_flags);
1688 1690 cookie->connectionId = -1;
1689 1691 }
1690 1692
1691 1693 /* set it up to use a connection opened for referral */
1692 1694 if (cookie->conn_user != NULL) {
1693 1695 /* If using a MT connection, return it. */
1694 1696 if (cookie->conn_user->conn_mt != NULL)
1695 1697 __s_api_conn_mt_return(cookie->conn_user);
1696 1698 cookie->conn_user->referral = B_TRUE;
1697 1699 }
1698 1700
1699 1701 rc = __s_api_getConnection(cookie->refpos->refHost, 0,
1700 1702 cookie->i_auth, &connectionId, &conp,
1701 1703 &cookie->errorp, fail_if_new_pwd_reqd,
1702 1704 cookie->nopasswd_acct_mgmt, cookie->conn_user);
1703 1705
1704 1706 /*
1705 1707 * If password control attached in *cookie->errorp,
1706 1708 * e.g. rc == NS_LDAP_SUCCESS_WITH_INFO,
1707 1709 * free the error structure (we do not need
1708 1710 * the sec_to_expired info).
1709 1711 * Reset rc to NS_LDAP_SUCCESS.
1710 1712 */
1711 1713 if (rc == NS_LDAP_SUCCESS_WITH_INFO) {
1712 1714 (void) __ns_ldap_freeError(
1713 1715 &cookie->errorp);
1714 1716 cookie->errorp = NULL;
1715 1717 rc = NS_LDAP_SUCCESS;
1716 1718 }
1717 1719
1718 1720 if (rc != NS_LDAP_SUCCESS) {
1719 1721 cookie->err_rc = rc;
1720 1722 return (-1);
1721 1723 }
1722 1724 cookie->conn = conp;
1723 1725 cookie->connectionId = connectionId;
1724 1726 return (0);
1725 1727 }
1726 1728
1727 1729 static int
1728 1730 paging_supported(ns_ldap_cookie_t *cookie)
1729 1731 {
1730 1732 int rc;
1731 1733
1732 1734 cookie->listType = 0;
1733 1735 rc = __s_api_isCtrlSupported(cookie->conn,
1734 1736 LDAP_CONTROL_VLVREQUEST);
1735 1737 if (rc == NS_LDAP_SUCCESS) {
1736 1738 cookie->listType = VLVCTRLFLAG;
1737 1739 return (1);
1738 1740 }
1739 1741 rc = __s_api_isCtrlSupported(cookie->conn,
1740 1742 LDAP_CONTROL_SIMPLE_PAGE);
1741 1743 if (rc == NS_LDAP_SUCCESS) {
1742 1744 cookie->listType = SIMPLEPAGECTRLFLAG;
1743 1745 return (1);
1744 1746 }
1745 1747 return (0);
1746 1748 }
1747 1749
1748 1750 typedef struct servicesorttype {
1749 1751 char *service;
1750 1752 ns_srvsidesort_t type;
1751 1753 } servicesorttype_t;
1752 1754
1753 1755 static servicesorttype_t *sort_type = NULL;
1754 1756 static int sort_type_size = 0;
1755 1757 static int sort_type_hwm = 0;
1756 1758 static mutex_t sort_type_mutex = DEFAULTMUTEX;
1757 1759
1758 1760
1759 1761 static ns_srvsidesort_t
1760 1762 get_srvsidesort_type(char *service)
1761 1763 {
1762 1764 int i;
1763 1765 ns_srvsidesort_t type = SSS_UNKNOWN;
1764 1766
1765 1767 if (service == NULL)
1766 1768 return (type);
1767 1769
1768 1770 (void) mutex_lock(&sort_type_mutex);
1769 1771 if (sort_type != NULL) {
1770 1772 for (i = 0; i < sort_type_hwm; i++) {
1771 1773 if (strcmp(sort_type[i].service, service) == 0) {
1772 1774 type = sort_type[i].type;
1773 1775 break;
1774 1776 }
1775 1777 }
1776 1778 }
1777 1779 (void) mutex_unlock(&sort_type_mutex);
1778 1780 return (type);
1779 1781 }
1780 1782
1781 1783 static void
1782 1784 update_srvsidesort_type(char *service, ns_srvsidesort_t type)
1783 1785 {
1784 1786 int i, size;
1785 1787 servicesorttype_t *tmp;
1786 1788
1787 1789 if (service == NULL)
1788 1790 return;
1789 1791
1790 1792 (void) mutex_lock(&sort_type_mutex);
1791 1793
1792 1794 for (i = 0; i < sort_type_hwm; i++) {
1793 1795 if (strcmp(sort_type[i].service, service) == 0) {
1794 1796 sort_type[i].type = type;
1795 1797 (void) mutex_unlock(&sort_type_mutex);
1796 1798 return;
1797 1799 }
1798 1800 }
1799 1801 if (sort_type == NULL) {
1800 1802 size = 10;
1801 1803 tmp = malloc(size * sizeof (servicesorttype_t));
1802 1804 if (tmp == NULL) {
1803 1805 (void) mutex_unlock(&sort_type_mutex);
1804 1806 return;
1805 1807 }
1806 1808 sort_type = tmp;
1807 1809 sort_type_size = size;
1808 1810 } else if (sort_type_hwm >= sort_type_size) {
1809 1811 size = sort_type_size + 10;
1810 1812 tmp = realloc(sort_type, size * sizeof (servicesorttype_t));
1811 1813 if (tmp == NULL) {
1812 1814 (void) mutex_unlock(&sort_type_mutex);
1813 1815 return;
1814 1816 }
1815 1817 sort_type = tmp;
1816 1818 sort_type_size = size;
1817 1819 }
1818 1820 sort_type[sort_type_hwm].service = strdup(service);
1819 1821 if (sort_type[sort_type_hwm].service == NULL) {
1820 1822 (void) mutex_unlock(&sort_type_mutex);
1821 1823 return;
1822 1824 }
1823 1825 sort_type[sort_type_hwm].type = type;
1824 1826 sort_type_hwm++;
1825 1827
1826 1828 (void) mutex_unlock(&sort_type_mutex);
1827 1829 }
1828 1830
1829 1831 static int
1830 1832 setup_vlv_params(ns_ldap_cookie_t *cookie)
1831 1833 {
1832 1834 LDAPControl **ctrls;
1833 1835 LDAPsortkey **sortkeylist;
1834 1836 LDAPControl *sortctrl = NULL;
1835 1837 LDAPControl *vlvctrl = NULL;
1836 1838 LDAPVirtualList vlist;
1837 1839 char *sortattr;
1838 1840 int rc;
1839 1841 int free_sort = FALSE;
1840 1842
1841 1843 _freeControlList(&cookie->p_serverctrls);
1842 1844
1843 1845 if (cookie->sortTypeTry == SSS_UNKNOWN)
1844 1846 cookie->sortTypeTry = get_srvsidesort_type(cookie->service);
1845 1847 if (cookie->sortTypeTry == SSS_UNKNOWN)
1846 1848 cookie->sortTypeTry = SSS_SINGLE_ATTR;
1847 1849
1848 1850 if (cookie->sortTypeTry == SSS_SINGLE_ATTR) {
1849 1851 if ((cookie->i_flags & NS_LDAP_NOMAP) == 0 &&
1850 1852 cookie->i_sortattr) {
1851 1853 sortattr = __ns_ldap_mapAttribute(cookie->service,
1852 1854 cookie->i_sortattr);
1853 1855 free_sort = TRUE;
1854 1856 } else if (cookie->i_sortattr) {
1855 1857 sortattr = (char *)cookie->i_sortattr;
1856 1858 } else {
1857 1859 sortattr = "cn";
1858 1860 }
1859 1861 } else {
1860 1862 sortattr = "cn uid";
1861 1863 }
1862 1864
1863 1865 rc = ldap_create_sort_keylist(&sortkeylist, sortattr);
1864 1866 if (free_sort)
1865 1867 free(sortattr);
1866 1868 if (rc != LDAP_SUCCESS) {
1867 1869 (void) ldap_get_option(cookie->conn->ld,
1868 1870 LDAP_OPT_ERROR_NUMBER, &rc);
1869 1871 return (rc);
1870 1872 }
1871 1873 rc = ldap_create_sort_control(cookie->conn->ld,
1872 1874 sortkeylist, 1, &sortctrl);
1873 1875 ldap_free_sort_keylist(sortkeylist);
1874 1876 if (rc != LDAP_SUCCESS) {
1875 1877 (void) ldap_get_option(cookie->conn->ld,
1876 1878 LDAP_OPT_ERROR_NUMBER, &rc);
1877 1879 return (rc);
1878 1880 }
1879 1881
1880 1882 vlist.ldvlist_index = cookie->index;
1881 1883 vlist.ldvlist_size = 0;
1882 1884
1883 1885 vlist.ldvlist_before_count = 0;
1884 1886 vlist.ldvlist_after_count = LISTPAGESIZE-1;
1885 1887 vlist.ldvlist_attrvalue = NULL;
1886 1888 vlist.ldvlist_extradata = NULL;
1887 1889
1888 1890 rc = ldap_create_virtuallist_control(cookie->conn->ld,
1889 1891 &vlist, &vlvctrl);
1890 1892 if (rc != LDAP_SUCCESS) {
1891 1893 ldap_control_free(sortctrl);
1892 1894 (void) ldap_get_option(cookie->conn->ld, LDAP_OPT_ERROR_NUMBER,
1893 1895 &rc);
1894 1896 return (rc);
1895 1897 }
1896 1898
1897 1899 ctrls = (LDAPControl **)calloc(3, sizeof (LDAPControl *));
1898 1900 if (ctrls == NULL) {
1899 1901 ldap_control_free(sortctrl);
1900 1902 ldap_control_free(vlvctrl);
1901 1903 return (LDAP_NO_MEMORY);
1902 1904 }
1903 1905
1904 1906 ctrls[0] = sortctrl;
1905 1907 ctrls[1] = vlvctrl;
1906 1908
1907 1909 cookie->p_serverctrls = ctrls;
1908 1910 return (LDAP_SUCCESS);
1909 1911 }
1910 1912
1911 1913 static int
1912 1914 setup_simplepg_params(ns_ldap_cookie_t *cookie)
1913 1915 {
1914 1916 LDAPControl **ctrls;
1915 1917 LDAPControl *pgctrl = NULL;
1916 1918 int rc;
1917 1919
1918 1920 _freeControlList(&cookie->p_serverctrls);
1919 1921
1920 1922 rc = ldap_create_page_control(cookie->conn->ld, LISTPAGESIZE,
1921 1923 cookie->ctrlCookie, (char)0, &pgctrl);
1922 1924 if (rc != LDAP_SUCCESS) {
1923 1925 (void) ldap_get_option(cookie->conn->ld, LDAP_OPT_ERROR_NUMBER,
1924 1926 &rc);
1925 1927 return (rc);
1926 1928 }
1927 1929
1928 1930 ctrls = (LDAPControl **)calloc(2, sizeof (LDAPControl *));
1929 1931 if (ctrls == NULL) {
1930 1932 ldap_control_free(pgctrl);
1931 1933 return (LDAP_NO_MEMORY);
1932 1934 }
1933 1935 ctrls[0] = pgctrl;
1934 1936 cookie->p_serverctrls = ctrls;
1935 1937 return (LDAP_SUCCESS);
1936 1938 }
1937 1939
1938 1940 static void
1939 1941 proc_result_referrals(ns_ldap_cookie_t *cookie)
1940 1942 {
1941 1943 int errCode, i, rc;
1942 1944 char **referrals = NULL;
1943 1945
1944 1946 /*
1945 1947 * Only follow one level of referrals, i.e.
1946 1948 * if already in referral mode, do nothing
1947 1949 */
1948 1950 if (cookie->refpos == NULL) {
1949 1951 cookie->new_state = END_RESULT;
1950 1952 rc = ldap_parse_result(cookie->conn->ld,
1951 1953 cookie->resultMsg,
1952 1954 &errCode, NULL,
1953 1955 NULL, &referrals,
1954 1956 NULL, 0);
1955 1957 if (rc != NS_LDAP_SUCCESS) {
1956 1958 (void) ldap_get_option(cookie->conn->ld,
1957 1959 LDAP_OPT_ERROR_NUMBER,
1958 1960 &cookie->err_rc);
1959 1961 cookie->new_state = LDAP_ERROR;
1960 1962 return;
1961 1963 }
1962 1964 if (errCode == LDAP_REFERRAL) {
1963 1965 for (i = 0; referrals[i] != NULL;
1964 1966 i++) {
1965 1967 /* add to referral list */
1966 1968 rc = __s_api_addRefInfo(
1967 1969 &cookie->reflist,
1968 1970 referrals[i],
1969 1971 cookie->basedn,
1970 1972 &cookie->scope,
1971 1973 cookie->filter,
1972 1974 cookie->conn->ld);
1973 1975 if (rc != NS_LDAP_SUCCESS) {
1974 1976 cookie->new_state =
1975 1977 ERROR;
1976 1978 break;
1977 1979 }
1978 1980 }
1979 1981 ldap_value_free(referrals);
1980 1982 }
1981 1983 }
1982 1984 }
1983 1985
1984 1986 static void
1985 1987 proc_search_references(ns_ldap_cookie_t *cookie)
1986 1988 {
1987 1989 char **refurls = NULL;
1988 1990 int i, rc;
1989 1991
1990 1992 /*
1991 1993 * Only follow one level of referrals, i.e.
1992 1994 * if already in referral mode, do nothing
1993 1995 */
1994 1996 if (cookie->refpos == NULL) {
1995 1997 refurls = ldap_get_reference_urls(
1996 1998 cookie->conn->ld,
1997 1999 cookie->resultMsg);
1998 2000 if (refurls == NULL) {
1999 2001 (void) ldap_get_option(cookie->conn->ld,
2000 2002 LDAP_OPT_ERROR_NUMBER,
2001 2003 &cookie->err_rc);
2002 2004 cookie->new_state = LDAP_ERROR;
2003 2005 return;
2004 2006 }
2005 2007 for (i = 0; refurls[i] != NULL; i++) {
2006 2008 /* add to referral list */
2007 2009 rc = __s_api_addRefInfo(
2008 2010 &cookie->reflist,
2009 2011 refurls[i],
2010 2012 cookie->basedn,
2011 2013 &cookie->scope,
2012 2014 cookie->filter,
2013 2015 cookie->conn->ld);
2014 2016 if (rc != NS_LDAP_SUCCESS) {
2015 2017 cookie->new_state =
2016 2018 ERROR;
2017 2019 break;
2018 2020 }
2019 2021 }
2020 2022 /* free allocated storage */
2021 2023 for (i = 0; refurls[i] != NULL; i++)
2022 2024 free(refurls[i]);
2023 2025 }
2024 2026 }
2025 2027
2026 2028 static ns_state_t
2027 2029 multi_result(ns_ldap_cookie_t *cookie)
2028 2030 {
2029 2031 char errstr[MAXERROR];
2030 2032 char *err;
2031 2033 ns_ldap_error_t **errorp = NULL;
2032 2034 LDAPControl **retCtrls = NULL;
2033 2035 int i, rc;
2034 2036 int errCode;
2035 2037 int finished = 0;
2036 2038 unsigned long target_posp = 0;
2037 2039 unsigned long list_size = 0;
2038 2040 unsigned int count = 0;
2039 2041 char **referrals = NULL;
2040 2042
2041 2043 if (cookie->listType == VLVCTRLFLAG) {
2042 2044 rc = ldap_parse_result(cookie->conn->ld, cookie->resultMsg,
2043 2045 &errCode, NULL, NULL, &referrals, &retCtrls, 0);
2044 2046 if (rc != LDAP_SUCCESS) {
2045 2047 (void) ldap_get_option(cookie->conn->ld,
2046 2048 LDAP_OPT_ERROR_NUMBER,
2047 2049 &cookie->err_rc);
2048 2050 (void) sprintf(errstr,
2049 2051 gettext("LDAP ERROR (%d): %s.\n"),
2050 2052 cookie->err_rc,
2051 2053 gettext(ldap_err2string(cookie->err_rc)));
2052 2054 err = strdup(errstr);
2053 2055 MKERROR(LOG_WARNING, *errorp, NS_LDAP_INTERNAL, err,
2054 2056 NULL);
2055 2057 cookie->err_rc = NS_LDAP_INTERNAL;
2056 2058 cookie->errorp = *errorp;
2057 2059 return (LDAP_ERROR);
2058 2060 }
2059 2061 if (errCode == LDAP_REFERRAL) {
2060 2062 for (i = 0; referrals[i] != NULL;
2061 2063 i++) {
2062 2064 /* add to referral list */
2063 2065 rc = __s_api_addRefInfo(
2064 2066 &cookie->reflist,
2065 2067 referrals[i],
2066 2068 cookie->basedn,
2067 2069 &cookie->scope,
2068 2070 cookie->filter,
2069 2071 cookie->conn->ld);
2070 2072 if (rc != NS_LDAP_SUCCESS) {
2071 2073 ldap_value_free(
2072 2074 referrals);
2073 2075 if (retCtrls)
2074 2076 ldap_controls_free(
2075 2077 retCtrls);
2076 2078 return (ERROR);
2077 2079 }
2078 2080 }
2079 2081 ldap_value_free(referrals);
2080 2082 if (retCtrls)
2081 2083 ldap_controls_free(retCtrls);
2082 2084 return (END_RESULT);
2083 2085 }
2084 2086 if (retCtrls) {
2085 2087 rc = ldap_parse_virtuallist_control(
2086 2088 cookie->conn->ld, retCtrls,
2087 2089 &target_posp, &list_size, &errCode);
2088 2090 if (rc == LDAP_SUCCESS) {
2089 2091 /*
2090 2092 * AD does not return valid target_posp
2091 2093 * and list_size
2092 2094 */
2093 2095 if (target_posp != 0 && list_size != 0) {
2094 2096 cookie->index =
2095 2097 target_posp + LISTPAGESIZE;
2096 2098 if (cookie->index > list_size)
2097 2099 finished = 1;
2098 2100 } else {
2099 2101 if (cookie->entryCount < LISTPAGESIZE)
2100 2102 finished = 1;
2101 2103 else
2102 2104 cookie->index +=
2103 2105 cookie->entryCount;
2104 2106 }
2105 2107 }
2106 2108 ldap_controls_free(retCtrls);
2107 2109 retCtrls = NULL;
2108 2110 }
2109 2111 else
2110 2112 finished = 1;
2111 2113 } else if (cookie->listType == SIMPLEPAGECTRLFLAG) {
2112 2114 rc = ldap_parse_result(cookie->conn->ld, cookie->resultMsg,
2113 2115 &errCode, NULL, NULL, &referrals, &retCtrls, 0);
2114 2116 if (rc != LDAP_SUCCESS) {
2115 2117 (void) ldap_get_option(cookie->conn->ld,
2116 2118 LDAP_OPT_ERROR_NUMBER,
2117 2119 &cookie->err_rc);
2118 2120 (void) sprintf(errstr,
2119 2121 gettext("LDAP ERROR (%d): %s.\n"),
2120 2122 cookie->err_rc,
2121 2123 gettext(ldap_err2string(cookie->err_rc)));
2122 2124 err = strdup(errstr);
2123 2125 MKERROR(LOG_WARNING, *errorp, NS_LDAP_INTERNAL, err,
2124 2126 NULL);
2125 2127 cookie->err_rc = NS_LDAP_INTERNAL;
2126 2128 cookie->errorp = *errorp;
2127 2129 return (LDAP_ERROR);
2128 2130 }
2129 2131 if (errCode == LDAP_REFERRAL) {
2130 2132 for (i = 0; referrals[i] != NULL;
2131 2133 i++) {
2132 2134 /* add to referral list */
2133 2135 rc = __s_api_addRefInfo(
2134 2136 &cookie->reflist,
2135 2137 referrals[i],
2136 2138 cookie->basedn,
2137 2139 &cookie->scope,
2138 2140 cookie->filter,
2139 2141 cookie->conn->ld);
2140 2142 if (rc != NS_LDAP_SUCCESS) {
2141 2143 ldap_value_free(
2142 2144 referrals);
2143 2145 if (retCtrls)
2144 2146 ldap_controls_free(
2145 2147 retCtrls);
2146 2148 return (ERROR);
2147 2149 }
2148 2150 }
2149 2151 ldap_value_free(referrals);
2150 2152 if (retCtrls)
2151 2153 ldap_controls_free(retCtrls);
2152 2154 return (END_RESULT);
2153 2155 }
2154 2156 if (retCtrls) {
2155 2157 if (cookie->ctrlCookie)
2156 2158 ber_bvfree(cookie->ctrlCookie);
2157 2159 cookie->ctrlCookie = NULL;
2158 2160 rc = ldap_parse_page_control(
2159 2161 cookie->conn->ld, retCtrls,
2160 2162 &count, &cookie->ctrlCookie);
2161 2163 if (rc == LDAP_SUCCESS) {
2162 2164 if ((cookie->ctrlCookie == NULL) ||
2163 2165 (cookie->ctrlCookie->bv_val == NULL) ||
2164 2166 (cookie->ctrlCookie->bv_len == 0))
2165 2167 finished = 1;
2166 2168 }
2167 2169 ldap_controls_free(retCtrls);
2168 2170 retCtrls = NULL;
2169 2171 }
2170 2172 else
2171 2173 finished = 1;
2172 2174 }
2173 2175 if (!finished && cookie->listType == VLVCTRLFLAG)
2174 2176 return (NEXT_VLV);
2175 2177 if (!finished && cookie->listType == SIMPLEPAGECTRLFLAG)
2176 2178 return (NEXT_PAGE);
2177 2179 if (finished)
2178 2180 return (END_RESULT);
2179 2181 return (ERROR);
2180 2182 }
2181 2183
2182 2184 /*
2183 2185 * clear_results(ns_ldap_cookie_t):
2184 2186 *
2185 2187 * Attempt to obtain remnants of ldap responses and free them. If remnants are
2186 2188 * not obtained within a certain time period tell the server we wish to abandon
2187 2189 * the request.
2188 2190 *
2189 2191 * Note that we do not initially tell the server to abandon the request as that
2190 2192 * can be an expensive operation for the server, while it is cheap for us to
2191 2193 * just flush the input.
2192 2194 *
2193 2195 * If something was to remain in libldap queue as a result of some error then
2194 2196 * it would be freed later during drop connection call or when no other
2195 2197 * requests share the connection.
2196 2198 */
2197 2199 static void
2198 2200 clear_results(ns_ldap_cookie_t *cookie)
2199 2201 {
2200 2202 int rc;
2201 2203 if (cookie->conn != NULL && cookie->conn->ld != NULL &&
2202 2204 (cookie->connectionId != -1 ||
2203 2205 (cookie->conn_user != NULL &&
2204 2206 cookie->conn_user->conn_mt != NULL)) &&
2205 2207 cookie->msgId != 0) {
2206 2208 /*
2207 2209 * We need to cleanup the rest of response (if there is such)
2208 2210 * and LDAP abandon is too heavy for LDAP servers, so we will
2209 2211 * wait for the rest of response till timeout and "process" it.
2210 2212 */
2211 2213 rc = ldap_result(cookie->conn->ld, cookie->msgId, LDAP_MSG_ALL,
2212 2214 (struct timeval *)&cookie->search_timeout,
2213 2215 &cookie->resultMsg);
2214 2216 if (rc != -1 && rc != 0 && cookie->resultMsg != NULL) {
2215 2217 (void) ldap_msgfree(cookie->resultMsg);
2216 2218 cookie->resultMsg = NULL;
2217 2219 }
2218 2220
2219 2221 /*
2220 2222 * If there was timeout then we will send ABANDON request to
2221 2223 * LDAP server to decrease load.
2222 2224 */
2223 2225 if (rc == 0)
2224 2226 (void) ldap_abandon_ext(cookie->conn->ld, cookie->msgId,
2225 2227 NULL, NULL);
2226 2228 /* Disassociate cookie with msgId */
2227 2229 cookie->msgId = 0;
2228 2230 }
2229 2231 }
2230 2232
2231 2233 /*
2232 2234 * This state machine performs one or more LDAP searches to a given
2233 2235 * directory server using service search descriptors and schema
2234 2236 * mapping as appropriate. The approximate pseudocode for
2235 2237 * this routine is the following:
2236 2238 * Given the current configuration [set/reset connection etc.]
2237 2239 * and the current service search descriptor list
2238 2240 * or default search filter parameters
2239 2241 * foreach (service search filter) {
2240 2242 * initialize the filter [via filter_init if appropriate]
2241 2243 * get a valid session/connection (preferably the current one)
2242 2244 * Recover if the connection is lost
2243 2245 * perform the search
2244 2246 * foreach (result entry) {
2245 2247 * process result [via callback if appropriate]
2246 2248 * save result for caller if accepted.
2247 2249 * exit and return all collected if allResults found;
2248 2250 * }
2249 2251 * }
2250 2252 * return collected results and exit
2251 2253 */
2252 2254
2253 2255 static
2254 2256 ns_state_t
2255 2257 search_state_machine(ns_ldap_cookie_t *cookie, ns_state_t state, int cycle)
2256 2258 {
2257 2259 char errstr[MAXERROR];
2258 2260 char *err;
2259 2261 int rc, ret;
2260 2262 int rc_save;
2261 2263 ns_ldap_entry_t *nextEntry;
2262 2264 ns_ldap_error_t *error = NULL;
2263 2265 ns_ldap_error_t **errorp;
2264 2266 struct timeval tv;
2265 2267
2266 2268 errorp = &error;
2267 2269 cookie->state = state;
2268 2270 errstr[0] = '\0';
2269 2271
2270 2272 for (;;) {
2271 2273 switch (cookie->state) {
2272 2274 case CLEAR_RESULTS:
2273 2275 clear_results(cookie);
2274 2276 cookie->new_state = EXIT;
2275 2277 break;
2276 2278 case GET_ACCT_MGMT_INFO:
2277 2279 /*
2278 2280 * Set the flag to get ldap account management controls.
2279 2281 */
2280 2282 cookie->nopasswd_acct_mgmt = 1;
2281 2283 cookie->new_state = INIT;
2282 2284 break;
2283 2285 case EXIT:
2284 2286 /* state engine/connection cleaned up in delete */
2285 2287 if (cookie->attribute) {
2286 2288 __s_api_free2dArray(cookie->attribute);
2287 2289 cookie->attribute = NULL;
2288 2290 }
2289 2291 if (cookie->reflist) {
2290 2292 __s_api_deleteRefInfo(cookie->reflist);
2291 2293 cookie->reflist = NULL;
2292 2294 }
2293 2295 return (EXIT);
2294 2296 case INIT:
2295 2297 cookie->sdpos = NULL;
2296 2298 cookie->new_state = NEXT_SEARCH_DESCRIPTOR;
2297 2299 if (cookie->attribute) {
2298 2300 __s_api_free2dArray(cookie->attribute);
2299 2301 cookie->attribute = NULL;
2300 2302 }
2301 2303 if ((cookie->i_flags & NS_LDAP_NOMAP) == 0 &&
2302 2304 cookie->i_attr) {
2303 2305 cookie->attribute =
2304 2306 __ns_ldap_mapAttributeList(
2305 2307 cookie->service,
2306 2308 cookie->i_attr);
2307 2309 }
2308 2310 break;
2309 2311 case REINIT:
2310 2312 /* Check if we've reached MAX retries. */
2311 2313 cookie->retries++;
2312 2314 if (cookie->retries > NS_LIST_TRY_MAX - 1) {
2313 2315 cookie->new_state = LDAP_ERROR;
2314 2316 break;
2315 2317 }
2316 2318
2317 2319 /*
2318 2320 * Even if we still have retries left, check
2319 2321 * if retry is possible.
2320 2322 */
2321 2323 if (cookie->conn_user != NULL) {
2322 2324 int retry;
2323 2325 ns_conn_mgmt_t *cmg;
2324 2326 cmg = cookie->conn_user->conn_mgmt;
2325 2327 retry = cookie->conn_user->retry;
2326 2328 if (cmg != NULL && cmg->cfg_reloaded == 1)
2327 2329 retry = 1;
2328 2330 if (retry == 0) {
2329 2331 cookie->new_state = LDAP_ERROR;
2330 2332 break;
2331 2333 }
2332 2334 }
2333 2335 /*
2334 2336 * Free results if any, reset to the first
2335 2337 * search descriptor and start a new session.
2336 2338 */
2337 2339 if (cookie->resultMsg != NULL) {
2338 2340 (void) ldap_msgfree(cookie->resultMsg);
2339 2341 cookie->resultMsg = NULL;
2340 2342 }
2341 2343 (void) __ns_ldap_freeError(&cookie->errorp);
2342 2344 (void) __ns_ldap_freeResult(&cookie->result);
2343 2345 cookie->sdpos = cookie->sdlist;
2344 2346 cookie->err_from_result = 0;
2345 2347 cookie->err_rc = 0;
2346 2348 cookie->new_state = NEXT_SESSION;
2347 2349 break;
2348 2350 case NEXT_SEARCH_DESCRIPTOR:
2349 2351 /* get next search descriptor */
2350 2352 if (cookie->sdpos == NULL) {
2351 2353 cookie->sdpos = cookie->sdlist;
2352 2354 cookie->new_state = GET_SESSION;
2353 2355 } else {
2354 2356 cookie->sdpos++;
2355 2357 cookie->new_state = NEXT_SEARCH;
2356 2358 }
2357 2359 if (*cookie->sdpos == NULL)
2358 2360 cookie->new_state = EXIT;
2359 2361 break;
2360 2362 case GET_SESSION:
2361 2363 if (get_current_session(cookie) < 0)
2362 2364 cookie->new_state = NEXT_SESSION;
2363 2365 else
2364 2366 cookie->new_state = NEXT_SEARCH;
2365 2367 break;
2366 2368 case NEXT_SESSION:
2367 2369 if (get_next_session(cookie) < 0)
2368 2370 cookie->new_state = RESTART_SESSION;
2369 2371 else
2370 2372 cookie->new_state = NEXT_SEARCH;
2371 2373 break;
2372 2374 case RESTART_SESSION:
2373 2375 if (cookie->i_flags & NS_LDAP_HARD) {
2374 2376 cookie->new_state = NEXT_SESSION;
2375 2377 break;
2376 2378 }
2377 2379 (void) sprintf(errstr,
2378 2380 gettext("Session error no available conn.\n"),
2379 2381 state);
2380 2382 err = strdup(errstr);
2381 2383 MKERROR(LOG_WARNING, *errorp, NS_LDAP_INTERNAL, err,
2382 2384 NULL);
2383 2385 cookie->err_rc = NS_LDAP_INTERNAL;
2384 2386 cookie->errorp = *errorp;
2385 2387 cookie->new_state = EXIT;
2386 2388 break;
2387 2389 case NEXT_SEARCH:
2388 2390 /* setup referrals search if necessary */
2389 2391 if (cookie->refpos) {
2390 2392 if (setup_referral_search(cookie) < 0) {
2391 2393 cookie->new_state = EXIT;
2392 2394 break;
2393 2395 }
2394 2396 } else if (setup_next_search(cookie) < 0) {
2395 2397 cookie->new_state = EXIT;
2396 2398 break;
2397 2399 }
2398 2400 /* only do VLV/PAGE on scopes onelevel/subtree */
2399 2401 if (paging_supported(cookie)) {
2400 2402 if (cookie->use_paging &&
2401 2403 (cookie->scope != LDAP_SCOPE_BASE)) {
2402 2404 cookie->index = 1;
2403 2405 if (cookie->listType == VLVCTRLFLAG)
2404 2406 cookie->new_state = NEXT_VLV;
2405 2407 else
2406 2408 cookie->new_state = NEXT_PAGE;
2407 2409 break;
2408 2410 }
2409 2411 }
2410 2412 cookie->new_state = ONE_SEARCH;
2411 2413 break;
2412 2414 case NEXT_VLV:
2413 2415 rc = setup_vlv_params(cookie);
2414 2416 if (rc != LDAP_SUCCESS) {
2415 2417 cookie->err_rc = rc;
2416 2418 cookie->new_state = LDAP_ERROR;
2417 2419 break;
2418 2420 }
2419 2421 cookie->next_state = MULTI_RESULT;
2420 2422 cookie->new_state = DO_SEARCH;
2421 2423 break;
2422 2424 case NEXT_PAGE:
2423 2425 rc = setup_simplepg_params(cookie);
2424 2426 if (rc != LDAP_SUCCESS) {
2425 2427 cookie->err_rc = rc;
2426 2428 cookie->new_state = LDAP_ERROR;
2427 2429 break;
2428 2430 }
2429 2431 cookie->next_state = MULTI_RESULT;
2430 2432 cookie->new_state = DO_SEARCH;
2431 2433 break;
2432 2434 case ONE_SEARCH:
2433 2435 cookie->next_state = NEXT_RESULT;
2434 2436 cookie->new_state = DO_SEARCH;
2435 2437 break;
2436 2438 case DO_SEARCH:
2437 2439 cookie->entryCount = 0;
2438 2440 rc = ldap_search_ext(cookie->conn->ld,
2439 2441 cookie->basedn,
2440 2442 cookie->scope,
2441 2443 cookie->filter,
2442 2444 cookie->attribute,
2443 2445 0,
2444 2446 cookie->p_serverctrls,
2445 2447 NULL,
2446 2448 &cookie->search_timeout, 0,
2447 2449 &cookie->msgId);
2448 2450 if (rc != LDAP_SUCCESS) {
2449 2451 if (rc == LDAP_BUSY ||
2450 2452 rc == LDAP_UNAVAILABLE ||
2451 2453 rc == LDAP_UNWILLING_TO_PERFORM ||
2452 2454 rc == LDAP_CONNECT_ERROR ||
2453 2455 rc == LDAP_SERVER_DOWN) {
2454 2456
2455 2457 if (cookie->reinit_on_retriable_err) {
2456 2458 cookie->err_rc = rc;
2457 2459 cookie->new_state = REINIT;
2458 2460 } else
2459 2461 cookie->new_state =
2460 2462 NEXT_SESSION;
2461 2463
2462 2464 /*
2463 2465 * If not able to reach the
2464 2466 * server, inform the ldap
2465 2467 * cache manager that the
2466 2468 * server should be removed
2467 2469 * from it's server list.
2468 2470 * Thus, the manager will not
2469 2471 * return this server on the next
2470 2472 * get-server request and will
2471 2473 * also reduce the server list
2472 2474 * refresh TTL, so that it will
2473 2475 * find out sooner when the server
2474 2476 * is up again.
2475 2477 */
2476 2478 if ((rc == LDAP_CONNECT_ERROR ||
2477 2479 rc == LDAP_SERVER_DOWN) &&
2478 2480 (cookie->conn_user == NULL ||
2479 2481 cookie->conn_user->conn_mt ==
2480 2482 NULL)) {
2481 2483 ret = __s_api_removeServer(
2482 2484 cookie->conn->serverAddr);
2483 2485 if (ret == NS_CACHE_NOSERVER &&
2484 2486 cookie->conn_auth_type
2485 2487 == NS_LDAP_AUTH_NONE) {
2486 2488 /*
2487 2489 * Couldn't remove
2488 2490 * server from server
2489 2491 * list.
2490 2492 * Exit to avoid
2491 2493 * potential infinite
2492 2494 * loop.
2493 2495 */
2494 2496 cookie->err_rc = rc;
2495 2497 cookie->new_state =
2496 2498 LDAP_ERROR;
2497 2499 }
2498 2500 if (cookie->connectionId > -1) {
2499 2501 /*
2500 2502 * NS_LDAP_NEW_CONN
2501 2503 * indicates that the
2502 2504 * connection should
2503 2505 * be deleted, not
2504 2506 * kept alive
2505 2507 */
2506 2508 DropConnection(
2507 2509 cookie->
2508 2510 connectionId,
2509 2511 NS_LDAP_NEW_CONN);
2510 2512 cookie->connectionId =
2511 2513 -1;
2512 2514 }
2513 2515 } else if ((rc == LDAP_CONNECT_ERROR ||
2514 2516 rc == LDAP_SERVER_DOWN) &&
2515 2517 cookie->conn_user != NULL) {
2516 2518 if (cookie->
2517 2519 reinit_on_retriable_err) {
2518 2520 /*
2519 2521 * MT connection not
2520 2522 * usable, close it
2521 2523 * before REINIT.
2522 2524 * rc has already
2523 2525 * been saved in
2524 2526 * cookie->err_rc above.
2525 2527 */
2526 2528 __s_api_conn_mt_close(
2527 2529 cookie->conn_user,
2528 2530 rc,
2529 2531 &cookie->errorp);
2530 2532 } else {
2531 2533 /*
2532 2534 * MT connection not
2533 2535 * usable, close it in
2534 2536 * the LDAP_ERROR state.
2535 2537 * A retry will be done
2536 2538 * next if allowed.
2537 2539 */
2538 2540 cookie->err_rc = rc;
2539 2541 cookie->new_state =
2540 2542 LDAP_ERROR;
2541 2543 }
2542 2544 }
2543 2545 break;
2544 2546 }
2545 2547 cookie->err_rc = rc;
2546 2548 cookie->new_state = LDAP_ERROR;
2547 2549 break;
2548 2550 }
2549 2551 cookie->new_state = cookie->next_state;
2550 2552 break;
2551 2553 case NEXT_RESULT:
2552 2554 /*
2553 2555 * Caller (e.g. __ns_ldap_list_batch_add)
2554 2556 * does not want to block on ldap_result().
2555 2557 * Therefore we execute ldap_result() with
2556 2558 * a zeroed timeval.
2557 2559 */
2558 2560 if (cookie->no_wait == B_TRUE)
2559 2561 (void) memset(&tv, 0, sizeof (tv));
2560 2562 else
2561 2563 tv = cookie->search_timeout;
2562 2564 rc = ldap_result(cookie->conn->ld, cookie->msgId,
2563 2565 LDAP_MSG_ONE,
2564 2566 &tv,
2565 2567 &cookie->resultMsg);
2566 2568 if (rc == LDAP_RES_SEARCH_RESULT) {
2567 2569 cookie->new_state = END_RESULT;
2568 2570 /* check and process referrals info */
2569 2571 if (cookie->followRef)
2570 2572 proc_result_referrals(
2571 2573 cookie);
2572 2574 (void) ldap_msgfree(cookie->resultMsg);
2573 2575 cookie->resultMsg = NULL;
2574 2576 break;
2575 2577 }
2576 2578 /* handle referrals if necessary */
2577 2579 if (rc == LDAP_RES_SEARCH_REFERENCE) {
2578 2580 if (cookie->followRef)
2579 2581 proc_search_references(cookie);
2580 2582 (void) ldap_msgfree(cookie->resultMsg);
2581 2583 cookie->resultMsg = NULL;
2582 2584 break;
2583 2585 }
2584 2586 if (rc != LDAP_RES_SEARCH_ENTRY) {
2585 2587 switch (rc) {
2586 2588 case 0:
2587 2589 if (cookie->no_wait == B_TRUE) {
2588 2590 (void) ldap_msgfree(
2589 2591 cookie->resultMsg);
2590 2592 cookie->resultMsg = NULL;
2591 2593 return (cookie->new_state);
2592 2594 }
2593 2595 rc = LDAP_TIMEOUT;
2594 2596 break;
2595 2597 case -1:
2596 2598 rc = ldap_get_lderrno(cookie->conn->ld,
2597 2599 NULL, NULL);
2598 2600 break;
2599 2601 default:
2600 2602 rc = ldap_result2error(cookie->conn->ld,
2601 2603 cookie->resultMsg, 1);
2602 2604 break;
2603 2605 }
2604 2606 if ((rc == LDAP_TIMEOUT ||
2605 2607 rc == LDAP_SERVER_DOWN) &&
2606 2608 (cookie->conn_user == NULL ||
2607 2609 cookie->conn_user->conn_mt == NULL)) {
2608 2610 if (rc == LDAP_TIMEOUT)
2609 2611 (void) __s_api_removeServer(
2610 2612 cookie->conn->serverAddr);
2611 2613 if (cookie->connectionId > -1) {
2612 2614 DropConnection(
2613 2615 cookie->connectionId,
2614 2616 NS_LDAP_NEW_CONN);
2615 2617 cookie->connectionId = -1;
2616 2618 }
2617 2619 cookie->err_from_result = 1;
2618 2620 }
2619 2621 (void) ldap_msgfree(cookie->resultMsg);
2620 2622 cookie->resultMsg = NULL;
2621 2623 if (rc == LDAP_BUSY ||
2622 2624 rc == LDAP_UNAVAILABLE ||
2623 2625 rc == LDAP_UNWILLING_TO_PERFORM) {
2624 2626 if (cookie->reinit_on_retriable_err) {
2625 2627 cookie->err_rc = rc;
2626 2628 cookie->err_from_result = 1;
2627 2629 cookie->new_state = REINIT;
2628 2630 } else
2629 2631 cookie->new_state =
2630 2632 NEXT_SESSION;
2631 2633 break;
2632 2634 }
2633 2635 if ((rc == LDAP_CONNECT_ERROR ||
2634 2636 rc == LDAP_SERVER_DOWN) &&
2635 2637 cookie->reinit_on_retriable_err) {
2636 2638 ns_ldap_error_t *errorp = NULL;
2637 2639 cookie->err_rc = rc;
2638 2640 cookie->err_from_result = 1;
2639 2641 cookie->new_state = REINIT;
2640 2642 if (cookie->conn_user != NULL)
2641 2643 __s_api_conn_mt_close(
2642 2644 cookie->conn_user,
2643 2645 rc, &errorp);
2644 2646 if (errorp != NULL) {
2645 2647 (void) __ns_ldap_freeError(
2646 2648 &cookie->errorp);
2647 2649 cookie->errorp = errorp;
2648 2650 }
2649 2651 break;
2650 2652 }
2651 2653 cookie->err_rc = rc;
2652 2654 cookie->new_state = LDAP_ERROR;
2653 2655 break;
2654 2656 }
2655 2657 /* else LDAP_RES_SEARCH_ENTRY */
2656 2658 /* get account management response control */
2657 2659 if (cookie->nopasswd_acct_mgmt == 1) {
2658 2660 rc = ldap_get_entry_controls(cookie->conn->ld,
2659 2661 cookie->resultMsg,
2660 2662 &(cookie->resultctrl));
2661 2663 if (rc != LDAP_SUCCESS) {
2662 2664 cookie->new_state = LDAP_ERROR;
2663 2665 cookie->err_rc = rc;
2664 2666 break;
2665 2667 }
2666 2668 }
2667 2669 rc = __s_api_getEntry(cookie);
2668 2670 (void) ldap_msgfree(cookie->resultMsg);
2669 2671 cookie->resultMsg = NULL;
2670 2672 if (rc != NS_LDAP_SUCCESS) {
2671 2673 cookie->new_state = LDAP_ERROR;
2672 2674 break;
2673 2675 }
2674 2676 cookie->new_state = PROCESS_RESULT;
2675 2677 cookie->next_state = NEXT_RESULT;
2676 2678 break;
2677 2679 case MULTI_RESULT:
2678 2680 if (cookie->no_wait == B_TRUE)
2679 2681 (void) memset(&tv, 0, sizeof (tv));
2680 2682 else
2681 2683 tv = cookie->search_timeout;
2682 2684 rc = ldap_result(cookie->conn->ld, cookie->msgId,
2683 2685 LDAP_MSG_ONE,
2684 2686 &tv,
2685 2687 &cookie->resultMsg);
2686 2688 if (rc == LDAP_RES_SEARCH_RESULT) {
2687 2689 rc = ldap_result2error(cookie->conn->ld,
2688 2690 cookie->resultMsg, 0);
2689 2691 if (rc == LDAP_ADMINLIMIT_EXCEEDED &&
2690 2692 cookie->listType == VLVCTRLFLAG &&
2691 2693 cookie->sortTypeTry == SSS_SINGLE_ATTR) {
2692 2694 /* Try old "cn uid" server side sort */
2693 2695 cookie->sortTypeTry = SSS_CN_UID_ATTRS;
2694 2696 cookie->new_state = NEXT_VLV;
2695 2697 (void) ldap_msgfree(cookie->resultMsg);
2696 2698 cookie->resultMsg = NULL;
2697 2699 break;
2698 2700 }
2699 2701 if (rc != LDAP_SUCCESS) {
2700 2702 cookie->err_rc = rc;
2701 2703 cookie->new_state = LDAP_ERROR;
2702 2704 (void) ldap_msgfree(cookie->resultMsg);
2703 2705 cookie->resultMsg = NULL;
2704 2706 break;
2705 2707 }
2706 2708 cookie->new_state = multi_result(cookie);
2707 2709 (void) ldap_msgfree(cookie->resultMsg);
2708 2710 cookie->resultMsg = NULL;
2709 2711 break;
2710 2712 }
2711 2713 /* handle referrals if necessary */
2712 2714 if (rc == LDAP_RES_SEARCH_REFERENCE &&
2713 2715 cookie->followRef) {
2714 2716 proc_search_references(cookie);
2715 2717 (void) ldap_msgfree(cookie->resultMsg);
2716 2718 cookie->resultMsg = NULL;
2717 2719 break;
2718 2720 }
2719 2721 if (rc != LDAP_RES_SEARCH_ENTRY) {
2720 2722 switch (rc) {
2721 2723 case 0:
2722 2724 if (cookie->no_wait == B_TRUE) {
2723 2725 (void) ldap_msgfree(
2724 2726 cookie->resultMsg);
2725 2727 cookie->resultMsg = NULL;
2726 2728 return (cookie->new_state);
2727 2729 }
2728 2730 rc = LDAP_TIMEOUT;
2729 2731 break;
2730 2732 case -1:
2731 2733 rc = ldap_get_lderrno(cookie->conn->ld,
2732 2734 NULL, NULL);
2733 2735 break;
2734 2736 default:
2735 2737 rc = ldap_result2error(cookie->conn->ld,
2736 2738 cookie->resultMsg, 1);
2737 2739 break;
2738 2740 }
2739 2741 if ((rc == LDAP_TIMEOUT ||
2740 2742 rc == LDAP_SERVER_DOWN) &&
2741 2743 (cookie->conn_user == NULL ||
2742 2744 cookie->conn_user->conn_mt == NULL)) {
2743 2745 if (rc == LDAP_TIMEOUT)
2744 2746 (void) __s_api_removeServer(
2745 2747 cookie->conn->serverAddr);
2746 2748 if (cookie->connectionId > -1) {
2747 2749 DropConnection(
2748 2750 cookie->connectionId,
2749 2751 NS_LDAP_NEW_CONN);
2750 2752 cookie->connectionId = -1;
2751 2753 }
2752 2754 cookie->err_from_result = 1;
2753 2755 }
2754 2756 (void) ldap_msgfree(cookie->resultMsg);
2755 2757 cookie->resultMsg = NULL;
2756 2758 if (rc == LDAP_BUSY ||
2757 2759 rc == LDAP_UNAVAILABLE ||
2758 2760 rc == LDAP_UNWILLING_TO_PERFORM) {
2759 2761 if (cookie->reinit_on_retriable_err) {
2760 2762 cookie->err_rc = rc;
2761 2763 cookie->err_from_result = 1;
2762 2764 cookie->new_state = REINIT;
2763 2765 } else
2764 2766 cookie->new_state =
2765 2767 NEXT_SESSION;
2766 2768 break;
2767 2769 }
2768 2770
2769 2771 if ((rc == LDAP_CONNECT_ERROR ||
2770 2772 rc == LDAP_SERVER_DOWN) &&
2771 2773 cookie->reinit_on_retriable_err) {
2772 2774 ns_ldap_error_t *errorp = NULL;
2773 2775 cookie->err_rc = rc;
2774 2776 cookie->err_from_result = 1;
2775 2777 cookie->new_state = REINIT;
2776 2778 if (cookie->conn_user != NULL)
2777 2779 __s_api_conn_mt_close(
2778 2780 cookie->conn_user,
2779 2781 rc, &errorp);
2780 2782 if (errorp != NULL) {
2781 2783 (void) __ns_ldap_freeError(
2782 2784 &cookie->errorp);
2783 2785 cookie->errorp = errorp;
2784 2786 }
2785 2787 break;
2786 2788 }
2787 2789 cookie->err_rc = rc;
2788 2790 cookie->new_state = LDAP_ERROR;
2789 2791 break;
2790 2792 }
2791 2793 /* else LDAP_RES_SEARCH_ENTRY */
2792 2794 cookie->entryCount++;
2793 2795 rc = __s_api_getEntry(cookie);
2794 2796 (void) ldap_msgfree(cookie->resultMsg);
2795 2797 cookie->resultMsg = NULL;
2796 2798 if (rc != NS_LDAP_SUCCESS) {
2797 2799 cookie->new_state = LDAP_ERROR;
2798 2800 break;
2799 2801 }
2800 2802 /*
2801 2803 * If VLV search was successfull save the server
2802 2804 * side sort type tried.
2803 2805 */
2804 2806 if (cookie->listType == VLVCTRLFLAG)
2805 2807 update_srvsidesort_type(cookie->service,
2806 2808 cookie->sortTypeTry);
2807 2809
2808 2810 cookie->new_state = PROCESS_RESULT;
2809 2811 cookie->next_state = MULTI_RESULT;
2810 2812 break;
2811 2813 case PROCESS_RESULT:
2812 2814 /* NOTE THIS STATE MAY BE PROCESSED BY CALLER */
2813 2815 if (cookie->use_usercb && cookie->callback) {
2814 2816 rc = 0;
2815 2817 for (nextEntry = cookie->result->entry;
2816 2818 nextEntry != NULL;
2817 2819 nextEntry = nextEntry->next) {
2818 2820 rc = (*cookie->callback)(nextEntry,
2819 2821 cookie->userdata);
2820 2822
2821 2823 if (rc == NS_LDAP_CB_DONE) {
2822 2824 /* cb doesn't want any more data */
2823 2825 rc = NS_LDAP_PARTIAL;
2824 2826 cookie->err_rc = rc;
2825 2827 break;
2826 2828 } else if (rc != NS_LDAP_CB_NEXT) {
2827 2829 /* invalid return code */
2828 2830 rc = NS_LDAP_OP_FAILED;
2829 2831 cookie->err_rc = rc;
2830 2832 break;
2831 2833 }
2832 2834 }
2833 2835 (void) __ns_ldap_freeResult(&cookie->result);
2834 2836 cookie->result = NULL;
2835 2837 }
2836 2838 if (rc != 0) {
2837 2839 cookie->new_state = EXIT;
2838 2840 break;
2839 2841 }
2840 2842 /* NOTE PREVIOUS STATE SPECIFIES NEXT STATE */
2841 2843 cookie->new_state = cookie->next_state;
2842 2844 break;
2843 2845 case END_PROCESS_RESULT:
2844 2846 cookie->new_state = cookie->next_state;
2845 2847 break;
2846 2848 case END_RESULT:
2847 2849 /*
2848 2850 * XXX DO WE NEED THIS CASE?
2849 2851 * if (search is complete) {
2850 2852 * cookie->new_state = EXIT;
2851 2853 * } else
2852 2854 */
2853 2855 /*
2854 2856 * entering referral mode if necessary
2855 2857 */
2856 2858 if (cookie->followRef && cookie->reflist)
2857 2859 cookie->new_state =
2858 2860 NEXT_REFERRAL;
2859 2861 else
2860 2862 cookie->new_state =
2861 2863 NEXT_SEARCH_DESCRIPTOR;
2862 2864 break;
2863 2865 case NEXT_REFERRAL:
2864 2866 /* get next referral info */
2865 2867 if (cookie->refpos == NULL)
2866 2868 cookie->refpos =
2867 2869 cookie->reflist;
2868 2870 else
2869 2871 cookie->refpos =
2870 2872 cookie->refpos->next;
2871 2873 /* check see if done with all referrals */
2872 2874 if (cookie->refpos != NULL)
2873 2875 cookie->new_state =
2874 2876 GET_REFERRAL_SESSION;
2875 2877 else {
2876 2878 __s_api_deleteRefInfo(cookie->reflist);
2877 2879 cookie->reflist = NULL;
2878 2880 cookie->new_state =
2879 2881 NEXT_SEARCH_DESCRIPTOR;
2880 2882 if (cookie->conn_user != NULL)
2881 2883 cookie->conn_user->referral = B_FALSE;
2882 2884 }
2883 2885 break;
2884 2886 case GET_REFERRAL_SESSION:
2885 2887 if (get_referral_session(cookie) < 0)
2886 2888 cookie->new_state = EXIT;
2887 2889 else {
2888 2890 cookie->new_state = NEXT_SEARCH;
2889 2891 }
2890 2892 break;
2891 2893 case LDAP_ERROR:
2892 2894 rc_save = cookie->err_rc;
2893 2895 if (cookie->err_from_result) {
2894 2896 if (cookie->err_rc == LDAP_SERVER_DOWN) {
2895 2897 (void) sprintf(errstr,
2896 2898 gettext("LDAP ERROR (%d): "
2897 2899 "Error occurred during"
2898 2900 " receiving results. "
2899 2901 "Connection to server lost."),
2900 2902 cookie->err_rc);
2901 2903 } else if (cookie->err_rc == LDAP_TIMEOUT) {
2902 2904 (void) sprintf(errstr,
2903 2905 gettext("LDAP ERROR (%d): "
2904 2906 "Error occurred during"
2905 2907 " receiving results. %s"
2906 2908 "."), cookie->err_rc,
2907 2909 ldap_err2string(
2908 2910 cookie->err_rc));
2909 2911 }
2910 2912 } else
2911 2913 (void) sprintf(errstr,
2912 2914 gettext("LDAP ERROR (%d): %s."),
2913 2915 cookie->err_rc,
2914 2916 ldap_err2string(cookie->err_rc));
2915 2917 err = strdup(errstr);
2916 2918 if (cookie->err_from_result) {
2917 2919 if (cookie->err_rc == LDAP_SERVER_DOWN) {
2918 2920 MKERROR(LOG_INFO, *errorp,
2919 2921 cookie->err_rc, err, NULL);
2920 2922 } else {
2921 2923 MKERROR(LOG_WARNING, *errorp,
2922 2924 cookie->err_rc, err, NULL);
2923 2925 }
2924 2926 } else {
2925 2927 MKERROR(LOG_WARNING, *errorp, NS_LDAP_INTERNAL,
2926 2928 err, NULL);
2927 2929 }
2928 2930 cookie->err_rc = NS_LDAP_INTERNAL;
2929 2931 cookie->errorp = *errorp;
2930 2932 if (cookie->conn_user != NULL) {
2931 2933 if (rc_save == LDAP_SERVER_DOWN ||
2932 2934 rc_save == LDAP_CONNECT_ERROR) {
2933 2935 /*
2934 2936 * MT connection is not usable,
2935 2937 * close it.
2936 2938 */
2937 2939 __s_api_conn_mt_close(cookie->conn_user,
2938 2940 rc_save, &cookie->errorp);
2939 2941 return (ERROR);
2940 2942 }
2941 2943 }
2942 2944 return (ERROR);
2943 2945 default:
2944 2946 case ERROR:
2945 2947 (void) sprintf(errstr,
2946 2948 gettext("Internal State machine exit (%d).\n"),
2947 2949 cookie->state);
2948 2950 err = strdup(errstr);
2949 2951 MKERROR(LOG_WARNING, *errorp, NS_LDAP_INTERNAL, err,
2950 2952 NULL);
2951 2953 cookie->err_rc = NS_LDAP_INTERNAL;
2952 2954 cookie->errorp = *errorp;
2953 2955 return (ERROR);
2954 2956 }
2955 2957
2956 2958 if (cookie->conn_user != NULL &&
2957 2959 cookie->conn_user->bad_mt_conn == B_TRUE) {
2958 2960 __s_api_conn_mt_close(cookie->conn_user, 0, NULL);
2959 2961 cookie->err_rc = cookie->conn_user->ns_rc;
2960 2962 cookie->errorp = cookie->conn_user->ns_error;
2961 2963 cookie->conn_user->ns_error = NULL;
2962 2964 return (ERROR);
2963 2965 }
2964 2966
2965 2967 if (cycle == ONE_STEP) {
2966 2968 return (cookie->new_state);
2967 2969 }
2968 2970 cookie->state = cookie->new_state;
2969 2971 }
2970 2972 /*NOTREACHED*/
2971 2973 #if 0
2972 2974 (void) sprintf(errstr,
2973 2975 gettext("Unexpected State machine error.\n"));
2974 2976 err = strdup(errstr);
2975 2977 MKERROR(LOG_WARNING, *errorp, NS_LDAP_INTERNAL, err, NULL);
2976 2978 cookie->err_rc = NS_LDAP_INTERNAL;
2977 2979 cookie->errorp = *errorp;
2978 2980 return (ERROR);
2979 2981 #endif
2980 2982 }
2981 2983
2982 2984 /*
2983 2985 * For a lookup of shadow data, if shadow update is enabled,
2984 2986 * check the calling process' privilege to ensure it's
2985 2987 * allowed to perform such operation.
2986 2988 */
2987 2989 static int
2988 2990 check_shadow(ns_ldap_cookie_t *cookie, const char *service)
2989 2991 {
2990 2992 char errstr[MAXERROR];
2991 2993 char *err;
2992 2994 boolean_t priv;
2993 2995 /* caller */
2994 2996 priv_set_t *ps;
2995 2997 /* zone */
2996 2998 priv_set_t *zs;
2997 2999
2998 3000 /*
2999 3001 * If service is "shadow", we may need
3000 3002 * to use privilege credentials.
3001 3003 */
3002 3004 if ((strcmp(service, "shadow") == 0) &&
3003 3005 __ns_ldap_is_shadow_update_enabled()) {
3004 3006 /*
3005 3007 * Since we release admin credentials after
3006 3008 * connection is closed and we do not cache
3007 3009 * them, we allow any root or all zone
3008 3010 * privilege process to read shadow data.
3009 3011 */
3010 3012 priv = (geteuid() == 0);
3011 3013 if (!priv) {
3012 3014 /* caller */
3013 3015 ps = priv_allocset();
3014 3016
3015 3017 (void) getppriv(PRIV_EFFECTIVE, ps);
3016 3018 zs = priv_str_to_set("zone", ",", NULL);
3017 3019 priv = priv_isequalset(ps, zs);
3018 3020 priv_freeset(ps);
3019 3021 priv_freeset(zs);
3020 3022 }
3021 3023 if (!priv) {
3022 3024 (void) sprintf(errstr,
3023 3025 gettext("Permission denied"));
3024 3026 err = strdup(errstr);
3025 3027 if (err == NULL)
3026 3028 return (NS_LDAP_MEMORY);
3027 3029 MKERROR(LOG_INFO, cookie->errorp, NS_LDAP_INTERNAL, err,
3028 3030 NULL);
3029 3031 return (NS_LDAP_INTERNAL);
3030 3032 }
3031 3033 cookie->i_flags |= NS_LDAP_READ_SHADOW;
3032 3034 /*
3033 3035 * We do not want to reuse connection (hence
3034 3036 * keep it open) with admin credentials.
3035 3037 * If NS_LDAP_KEEP_CONN is set, reject the
3036 3038 * request.
3037 3039 */
3038 3040 if (cookie->i_flags & NS_LDAP_KEEP_CONN)
3039 3041 return (NS_LDAP_INVALID_PARAM);
3040 3042 cookie->i_flags |= NS_LDAP_NEW_CONN;
3041 3043 }
3042 3044
3043 3045 return (NS_LDAP_SUCCESS);
3044 3046 }
3045 3047
3046 3048 /*
3047 3049 * internal function for __ns_ldap_list
3048 3050 */
3049 3051 static int
3050 3052 ldap_list(
3051 3053 ns_ldap_list_batch_t *batch,
3052 3054 const char *service,
3053 3055 const char *filter,
3054 3056 const char *sortattr,
3055 3057 int (*init_filter_cb)(const ns_ldap_search_desc_t *desc,
3056 3058 char **realfilter, const void *userdata),
3057 3059 const char * const *attribute,
3058 3060 const ns_cred_t *auth,
3059 3061 const int flags,
3060 3062 ns_ldap_result_t **rResult, /* return result entries */
3061 3063 ns_ldap_error_t **errorp,
3062 3064 int *rcp,
3063 3065 int (*callback)(const ns_ldap_entry_t *entry, const void *userdata),
3064 3066 const void *userdata, ns_conn_user_t *conn_user)
3065 3067 {
3066 3068 ns_ldap_cookie_t *cookie;
3067 3069 ns_ldap_search_desc_t **sdlist = NULL;
3068 3070 ns_ldap_search_desc_t *dptr;
3069 3071 ns_ldap_error_t *error = NULL;
3070 3072 char **dns = NULL;
3071 3073 int scope;
3072 3074 int rc;
3073 3075 int from_result;
3074 3076
3075 3077 *errorp = NULL;
3076 3078 *rResult = NULL;
3077 3079 *rcp = NS_LDAP_SUCCESS;
3078 3080
3079 3081 /*
3080 3082 * Sanity check - NS_LDAP_READ_SHADOW is for our
3081 3083 * own internal use.
3082 3084 */
3083 3085 if (flags & NS_LDAP_READ_SHADOW)
3084 3086 return (NS_LDAP_INVALID_PARAM);
3085 3087
3086 3088 /* Initialize State machine cookie */
3087 3089 cookie = init_search_state_machine();
3088 3090 if (cookie == NULL) {
3089 3091 *rcp = NS_LDAP_MEMORY;
3090 3092 return (NS_LDAP_MEMORY);
3091 3093 }
3092 3094 cookie->conn_user = conn_user;
3093 3095
3094 3096 /* see if need to follow referrals */
3095 3097 rc = __s_api_toFollowReferrals(flags,
3096 3098 &cookie->followRef, errorp);
3097 3099 if (rc != NS_LDAP_SUCCESS) {
3098 3100 delete_search_cookie(cookie);
3099 3101 *rcp = rc;
3100 3102 return (rc);
3101 3103 }
3102 3104
3103 3105 /* get the service descriptor - or create a default one */
3104 3106 rc = __s_api_get_SSD_from_SSDtoUse_service(service,
3105 3107 &sdlist, &error);
3106 3108 if (rc != NS_LDAP_SUCCESS) {
3107 3109 delete_search_cookie(cookie);
3108 3110 *errorp = error;
3109 3111 *rcp = rc;
3110 3112 return (rc);
3111 3113 }
3112 3114
3113 3115 if (sdlist == NULL) {
3114 3116 /* Create default service Desc */
3115 3117 sdlist = (ns_ldap_search_desc_t **)calloc(2,
3116 3118 sizeof (ns_ldap_search_desc_t *));
3117 3119 if (sdlist == NULL) {
3118 3120 delete_search_cookie(cookie);
3119 3121 cookie = NULL;
3120 3122 *rcp = NS_LDAP_MEMORY;
3121 3123 return (NS_LDAP_MEMORY);
3122 3124 }
3123 3125 dptr = (ns_ldap_search_desc_t *)
3124 3126 calloc(1, sizeof (ns_ldap_search_desc_t));
3125 3127 if (dptr == NULL) {
3126 3128 free(sdlist);
3127 3129 delete_search_cookie(cookie);
3128 3130 cookie = NULL;
3129 3131 *rcp = NS_LDAP_MEMORY;
3130 3132 return (NS_LDAP_MEMORY);
3131 3133 }
3132 3134 sdlist[0] = dptr;
3133 3135
3134 3136 /* default base */
3135 3137 rc = __s_api_getDNs(&dns, service, &cookie->errorp);
3136 3138 if (rc != NS_LDAP_SUCCESS) {
3137 3139 if (dns) {
3138 3140 __s_api_free2dArray(dns);
3139 3141 dns = NULL;
3140 3142 }
3141 3143 *errorp = cookie->errorp;
3142 3144 cookie->errorp = NULL;
3143 3145 delete_search_cookie(cookie);
3144 3146 cookie = NULL;
3145 3147 *rcp = rc;
3146 3148 return (rc);
3147 3149 }
3148 3150 dptr->basedn = strdup(dns[0]);
3149 3151 __s_api_free2dArray(dns);
3150 3152 dns = NULL;
3151 3153
3152 3154 /* default scope */
3153 3155 scope = 0;
3154 3156 rc = __s_api_getSearchScope(&scope, &cookie->errorp);
3155 3157 dptr->scope = scope;
3156 3158 }
3157 3159
3158 3160 cookie->sdlist = sdlist;
3159 3161
3160 3162 /*
3161 3163 * use VLV/PAGE control only if NS_LDAP_PAGE_CTRL is set
3162 3164 */
3163 3165 if (flags & NS_LDAP_PAGE_CTRL)
3164 3166 cookie->use_paging = TRUE;
3165 3167 else
3166 3168 cookie->use_paging = FALSE;
3167 3169
3168 3170 /* Set up other arguments */
3169 3171 cookie->userdata = userdata;
3170 3172 if (init_filter_cb != NULL) {
3171 3173 cookie->init_filter_cb = init_filter_cb;
3172 3174 cookie->use_filtercb = 1;
3173 3175 }
3174 3176 if (callback != NULL) {
3175 3177 cookie->callback = callback;
3176 3178 cookie->use_usercb = 1;
3177 3179 }
3178 3180
3179 3181 /* check_shadow() may add extra value to cookie->i_flags */
3180 3182 cookie->i_flags = flags;
3181 3183 if (service) {
3182 3184 cookie->service = strdup(service);
3183 3185 if (cookie->service == NULL) {
3184 3186 delete_search_cookie(cookie);
3185 3187 cookie = NULL;
3186 3188 *rcp = NS_LDAP_MEMORY;
3187 3189 return (NS_LDAP_MEMORY);
3188 3190 }
3189 3191
3190 3192 /*
3191 3193 * If given, use the credential given by the caller, and
3192 3194 * skip the credential check required for shadow update.
3193 3195 */
3194 3196 if (auth == NULL) {
3195 3197 rc = check_shadow(cookie, service);
3196 3198 if (rc != NS_LDAP_SUCCESS) {
3197 3199 *errorp = cookie->errorp;
3198 3200 cookie->errorp = NULL;
3199 3201 delete_search_cookie(cookie);
3200 3202 cookie = NULL;
3201 3203 *rcp = rc;
3202 3204 return (rc);
3203 3205 }
3204 3206 }
3205 3207 }
3206 3208
3207 3209 cookie->i_filter = strdup(filter);
3208 3210 cookie->i_attr = attribute;
3209 3211 cookie->i_auth = auth;
3210 3212 cookie->i_sortattr = sortattr;
3211 3213
3212 3214 if (batch != NULL) {
3213 3215 cookie->batch = batch;
3214 3216 cookie->reinit_on_retriable_err = B_TRUE;
3215 3217 cookie->no_wait = B_TRUE;
3216 3218 (void) search_state_machine(cookie, INIT, 0);
3217 3219 cookie->no_wait = B_FALSE;
3218 3220 rc = cookie->err_rc;
3219 3221
3220 3222 if (rc == NS_LDAP_SUCCESS) {
3221 3223 /*
3222 3224 * Here rc == NS_LDAP_SUCCESS means that the state
3223 3225 * machine init'ed successfully. The actual status
3224 3226 * of the search will be determined by
3225 3227 * __ns_ldap_list_batch_end(). Add the cookie to our
3226 3228 * batch.
3227 3229 */
3228 3230 cookie->caller_result = rResult;
3229 3231 cookie->caller_errorp = errorp;
3230 3232 cookie->caller_rc = rcp;
3231 3233 cookie->next_cookie_in_batch = batch->cookie_list;
3232 3234 batch->cookie_list = cookie;
3233 3235 batch->nactive++;
3234 3236 return (rc);
3235 3237 }
3236 3238 /*
3237 3239 * If state machine init failed then copy error to the caller
3238 3240 * and delete the cookie.
3239 3241 */
3240 3242 } else {
3241 3243 (void) search_state_machine(cookie, INIT, 0);
3242 3244 }
3243 3245
3244 3246 /* Copy results back to user */
3245 3247 rc = cookie->err_rc;
3246 3248 if (rc != NS_LDAP_SUCCESS) {
3247 3249 if (conn_user != NULL && conn_user->ns_error != NULL) {
3248 3250 *errorp = conn_user->ns_error;
3249 3251 conn_user->ns_error = NULL;
3250 3252 } else
3251 3253 *errorp = cookie->errorp;
3252 3254 }
3253 3255 *rResult = cookie->result;
3254 3256 from_result = cookie->err_from_result;
3255 3257
3256 3258 cookie->errorp = NULL;
3257 3259 cookie->result = NULL;
3258 3260 delete_search_cookie(cookie);
3259 3261 cookie = NULL;
3260 3262
3261 3263 if (from_result == 0 && *rResult == NULL)
3262 3264 rc = NS_LDAP_NOTFOUND;
3263 3265 *rcp = rc;
3264 3266 return (rc);
3265 3267 }
3266 3268
3267 3269
3268 3270 /*
3269 3271 * __ns_ldap_list performs one or more LDAP searches to a given
3270 3272 * directory server using service search descriptors and schema
3271 3273 * mapping as appropriate. The operation may be retried a
3272 3274 * couple of times in error situations.
3273 3275 */
3274 3276 int
3275 3277 __ns_ldap_list(
3276 3278 const char *service,
3277 3279 const char *filter,
3278 3280 int (*init_filter_cb)(const ns_ldap_search_desc_t *desc,
3279 3281 char **realfilter, const void *userdata),
3280 3282 const char * const *attribute,
3281 3283 const ns_cred_t *auth,
3282 3284 const int flags,
3283 3285 ns_ldap_result_t **rResult, /* return result entries */
3284 3286 ns_ldap_error_t **errorp,
3285 3287 int (*callback)(const ns_ldap_entry_t *entry, const void *userdata),
3286 3288 const void *userdata)
3287 3289 {
3288 3290 int mod_flags;
3289 3291 /*
3290 3292 * Strip the NS_LDAP_PAGE_CTRL option as this interface does not
3291 3293 * support this. If you want to use this option call the API
3292 3294 * __ns_ldap_list_sort() with has the sort attribute.
3293 3295 */
3294 3296 mod_flags = flags & (~NS_LDAP_PAGE_CTRL);
3295 3297
3296 3298 return (__ns_ldap_list_sort(service, filter, NULL, init_filter_cb,
3297 3299 attribute, auth, mod_flags, rResult, errorp,
3298 3300 callback, userdata));
3299 3301 }
3300 3302
3301 3303 /*
3302 3304 * __ns_ldap_list_sort performs one or more LDAP searches to a given
3303 3305 * directory server using service search descriptors and schema
3304 3306 * mapping as appropriate. The operation may be retried a
3305 3307 * couple of times in error situations.
3306 3308 */
3307 3309 int
3308 3310 __ns_ldap_list_sort(
3309 3311 const char *service,
3310 3312 const char *filter,
3311 3313 const char *sortattr,
3312 3314 int (*init_filter_cb)(const ns_ldap_search_desc_t *desc,
3313 3315 char **realfilter, const void *userdata),
3314 3316 const char * const *attribute,
3315 3317 const ns_cred_t *auth,
3316 3318 const int flags,
3317 3319 ns_ldap_result_t **rResult, /* return result entries */
3318 3320 ns_ldap_error_t **errorp,
3319 3321 int (*callback)(const ns_ldap_entry_t *entry, const void *userdata),
3320 3322 const void *userdata)
3321 3323 {
3322 3324 ns_conn_user_t *cu = NULL;
3323 3325 int try_cnt = 0;
3324 3326 int rc = NS_LDAP_SUCCESS, trc;
3325 3327
3326 3328 for (;;) {
3327 3329 if (__s_api_setup_retry_search(&cu, NS_CONN_USER_SEARCH,
3328 3330 &try_cnt, &rc, errorp) == 0)
3329 3331 break;
3330 3332 rc = ldap_list(NULL, service, filter, sortattr, init_filter_cb,
3331 3333 attribute, auth, flags, rResult, errorp, &trc, callback,
3332 3334 userdata, cu);
3333 3335 }
3334 3336
3335 3337 return (rc);
3336 3338 }
3337 3339
3338 3340 /*
3339 3341 * Create and initialize batch for native LDAP lookups
3340 3342 */
3341 3343 int
3342 3344 __ns_ldap_list_batch_start(ns_ldap_list_batch_t **batch)
3343 3345 {
3344 3346 *batch = calloc(1, sizeof (ns_ldap_list_batch_t));
3345 3347 if (*batch == NULL)
3346 3348 return (NS_LDAP_MEMORY);
3347 3349 return (NS_LDAP_SUCCESS);
3348 3350 }
3349 3351
3350 3352
3351 3353 /*
3352 3354 * Add a LDAP search request to the batch.
3353 3355 */
3354 3356 int
3355 3357 __ns_ldap_list_batch_add(
3356 3358 ns_ldap_list_batch_t *batch,
3357 3359 const char *service,
3358 3360 const char *filter,
3359 3361 int (*init_filter_cb)(const ns_ldap_search_desc_t *desc,
3360 3362 char **realfilter, const void *userdata),
3361 3363 const char * const *attribute,
3362 3364 const ns_cred_t *auth,
3363 3365 const int flags,
3364 3366 ns_ldap_result_t **rResult, /* return result entries */
3365 3367 ns_ldap_error_t **errorp,
3366 3368 int *rcp,
3367 3369 int (*callback)(const ns_ldap_entry_t *entry, const void *userdata),
3368 3370 const void *userdata)
3369 3371 {
3370 3372 ns_conn_user_t *cu;
3371 3373 int rc;
3372 3374 int mod_flags;
3373 3375
3374 3376 cu = __s_api_conn_user_init(NS_CONN_USER_SEARCH, NULL, 0);
3375 3377 if (cu == NULL) {
3376 3378 if (rcp != NULL)
3377 3379 *rcp = NS_LDAP_MEMORY;
3378 3380 return (NS_LDAP_MEMORY);
3379 3381 }
3380 3382
3381 3383 /*
3382 3384 * Strip the NS_LDAP_PAGE_CTRL option as the batch interface does not
3383 3385 * support this.
3384 3386 */
3385 3387 mod_flags = flags & (~NS_LDAP_PAGE_CTRL);
3386 3388
3387 3389 rc = ldap_list(batch, service, filter, NULL, init_filter_cb, attribute,
3388 3390 auth, mod_flags, rResult, errorp, rcp, callback, userdata, cu);
3389 3391
3390 3392 /*
3391 3393 * Free the conn_user if the cookie was not batched. If the cookie
3392 3394 * was batched then __ns_ldap_list_batch_end or release will free the
3393 3395 * conn_user. The batch API instructs the search_state_machine
3394 3396 * to reinit and retry (max 3 times) on retriable LDAP errors.
3395 3397 */
3396 3398 if (rc != NS_LDAP_SUCCESS && cu != NULL) {
3397 3399 if (cu->conn_mt != NULL)
3398 3400 __s_api_conn_mt_return(cu);
3399 3401 __s_api_conn_user_free(cu);
3400 3402 }
3401 3403 return (rc);
3402 3404 }
3403 3405
3404 3406
3405 3407 /*
3406 3408 * Free batch.
3407 3409 */
3408 3410 void
3409 3411 __ns_ldap_list_batch_release(ns_ldap_list_batch_t *batch)
3410 3412 {
3411 3413 ns_ldap_cookie_t *c, *next;
3412 3414
3413 3415 for (c = batch->cookie_list; c != NULL; c = next) {
3414 3416 next = c->next_cookie_in_batch;
3415 3417 if (c->conn_user != NULL) {
3416 3418 if (c->conn_user->conn_mt != NULL)
3417 3419 __s_api_conn_mt_return(c->conn_user);
3418 3420 __s_api_conn_user_free(c->conn_user);
3419 3421 c->conn_user = NULL;
3420 3422 }
3421 3423 delete_search_cookie(c);
3422 3424 }
3423 3425 free(batch);
3424 3426 }
3425 3427
3426 3428 #define LD_USING_STATE(st) \
3427 3429 ((st == DO_SEARCH) || (st == MULTI_RESULT) || (st == NEXT_RESULT))
3428 3430
3429 3431 /*
3430 3432 * Process batch. Everytime this function is called it selects an
3431 3433 * active cookie from the batch and single steps through the
3432 3434 * search_state_machine for the selected cookie. If lookup associated
3433 3435 * with the cookie is complete (success or error) then the cookie is
3434 3436 * removed from the batch and its memory freed.
3435 3437 *
3436 3438 * Returns 1 (if batch still has active cookies)
3437 3439 * 0 (if batch has no more active cookies)
3438 3440 * -1 (on errors, *rcp will contain the error code)
3439 3441 *
3440 3442 * The caller should call this function in a loop as long as it returns 1
3441 3443 * to process all the requests added to the batch. The results (and errors)
3442 3444 * will be available in the locations provided by the caller at the time of
3443 3445 * __ns_ldap_list_batch_add().
3444 3446 */
3445 3447 static
3446 3448 int
3447 3449 __ns_ldap_list_batch_process(ns_ldap_list_batch_t *batch, int *rcp)
3448 3450 {
3449 3451 ns_ldap_cookie_t *c, *ptr, **prev;
3450 3452 ns_state_t state;
3451 3453 ns_ldap_error_t *errorp = NULL;
3452 3454 int rc;
3453 3455
3454 3456 /* Check if are already done */
3455 3457 if (batch->nactive == 0)
3456 3458 return (0);
3457 3459
3458 3460 /* Get the next cookie from the batch */
3459 3461 c = (batch->next_cookie == NULL) ?
3460 3462 batch->cookie_list : batch->next_cookie;
3461 3463
3462 3464 batch->next_cookie = c->next_cookie_in_batch;
3463 3465
3464 3466 /*
3465 3467 * Checks the status of the cookie's connection if it needs
3466 3468 * to use that connection for ldap_search_ext or ldap_result.
3467 3469 * If the connection is no longer good but worth retrying
3468 3470 * then reinit the search_state_machine for this cookie
3469 3471 * starting from the first search descriptor. REINIT will
3470 3472 * clear any leftover results if max retries have not been
3471 3473 * reached and redo the search (which may also involve
3472 3474 * following referrals again).
3473 3475 *
3474 3476 * Note that each cookie in the batch will make this
3475 3477 * determination when it reaches one of the LD_USING_STATES.
3476 3478 */
3477 3479 if (LD_USING_STATE(c->new_state) && c->conn_user != NULL) {
3478 3480 rc = __s_api_setup_getnext(c->conn_user, &c->err_rc, &errorp);
3479 3481 if (rc == LDAP_BUSY || rc == LDAP_UNAVAILABLE ||
3480 3482 rc == LDAP_UNWILLING_TO_PERFORM) {
3481 3483 if (errorp != NULL) {
3482 3484 (void) __ns_ldap_freeError(&c->errorp);
3483 3485 c->errorp = errorp;
3484 3486 }
3485 3487 c->new_state = REINIT;
3486 3488 } else if (rc == LDAP_CONNECT_ERROR ||
3487 3489 rc == LDAP_SERVER_DOWN) {
3488 3490 if (errorp != NULL) {
3489 3491 (void) __ns_ldap_freeError(&c->errorp);
3490 3492 c->errorp = errorp;
3491 3493 }
3492 3494 c->new_state = REINIT;
3493 3495 /*
3494 3496 * MT connection is not usable,
3495 3497 * close it before REINIT.
3496 3498 */
3497 3499 __s_api_conn_mt_close(
3498 3500 c->conn_user, rc, NULL);
3499 3501 } else if (rc != NS_LDAP_SUCCESS) {
3500 3502 if (rcp != NULL)
3501 3503 *rcp = rc;
3502 3504 *c->caller_result = NULL;
3503 3505 *c->caller_errorp = errorp;
3504 3506 *c->caller_rc = rc;
3505 3507 return (-1);
3506 3508 }
3507 3509 }
3508 3510
3509 3511 for (;;) {
3510 3512 /* Single step through the search_state_machine */
3511 3513 state = search_state_machine(c, c->new_state, ONE_STEP);
3512 3514 switch (state) {
3513 3515 case LDAP_ERROR:
3514 3516 (void) search_state_machine(c, state, ONE_STEP);
3515 3517 (void) search_state_machine(c, CLEAR_RESULTS, ONE_STEP);
3516 3518 /* FALLTHROUGH */
3517 3519 case ERROR:
3518 3520 case EXIT:
3519 3521 *c->caller_result = c->result;
3520 3522 *c->caller_errorp = c->errorp;
3521 3523 *c->caller_rc =
3522 3524 (c->result == NULL && c->err_from_result == 0)
3523 3525 ? NS_LDAP_NOTFOUND : c->err_rc;
3524 3526 c->result = NULL;
3525 3527 c->errorp = NULL;
3526 3528 /* Remove the cookie from the batch */
3527 3529 ptr = batch->cookie_list;
3528 3530 prev = &batch->cookie_list;
3529 3531 while (ptr != NULL) {
3530 3532 if (ptr == c) {
3531 3533 *prev = ptr->next_cookie_in_batch;
3532 3534 break;
3533 3535 }
3534 3536 prev = &ptr->next_cookie_in_batch;
3535 3537 ptr = ptr->next_cookie_in_batch;
3536 3538 }
3537 3539 /* Delete cookie and decrement active cookie count */
3538 3540 if (c->conn_user != NULL) {
3539 3541 if (c->conn_user->conn_mt != NULL)
3540 3542 __s_api_conn_mt_return(c->conn_user);
3541 3543 __s_api_conn_user_free(c->conn_user);
3542 3544 c->conn_user = NULL;
3543 3545 }
3544 3546 delete_search_cookie(c);
3545 3547 batch->nactive--;
3546 3548 break;
3547 3549 case NEXT_RESULT:
3548 3550 case MULTI_RESULT:
3549 3551 /*
3550 3552 * This means that search_state_machine needs to do
3551 3553 * another ldap_result() for the cookie in question.
3552 3554 * We only do at most one ldap_result() per call in
3553 3555 * this function and therefore we return. This allows
3554 3556 * the caller to process results from other cookies
3555 3557 * in the batch without getting tied up on just one
3556 3558 * cookie.
3557 3559 */
3558 3560 break;
3559 3561 default:
3560 3562 /*
3561 3563 * This includes states that follow NEXT_RESULT or
3562 3564 * MULTI_RESULT such as PROCESS_RESULT and
3563 3565 * END_PROCESS_RESULT. We continue processing
3564 3566 * this cookie till we reach either the error, exit
3565 3567 * or the result states.
3566 3568 */
3567 3569 continue;
3568 3570 }
3569 3571 break;
3570 3572 }
3571 3573
3572 3574 /* Return 0 if no more cookies left otherwise 1 */
3573 3575 return ((batch->nactive > 0) ? 1 : 0);
3574 3576 }
3575 3577
3576 3578
3577 3579 /*
3578 3580 * Process all the active cookies in the batch and when none
3579 3581 * remains finalize the batch.
3580 3582 */
3581 3583 int
3582 3584 __ns_ldap_list_batch_end(ns_ldap_list_batch_t *batch)
3583 3585 {
3584 3586 int rc = NS_LDAP_SUCCESS;
3585 3587 while (__ns_ldap_list_batch_process(batch, &rc) > 0)
3586 3588 ;
3587 3589 __ns_ldap_list_batch_release(batch);
3588 3590 return (rc);
3589 3591 }
3590 3592
3591 3593 /*
3592 3594 * find_domainname performs one or more LDAP searches to
3593 3595 * find the value of the nisdomain attribute associated with
3594 3596 * the input DN (with no retry).
3595 3597 */
3596 3598
3597 3599 static int
3598 3600 find_domainname(const char *dn, char **domainname, const ns_cred_t *cred,
3599 3601 ns_ldap_error_t **errorp, ns_conn_user_t *conn_user)
3600 3602 {
3601 3603
3602 3604 ns_ldap_cookie_t *cookie;
3603 3605 ns_ldap_search_desc_t **sdlist;
3604 3606 ns_ldap_search_desc_t *dptr;
3605 3607 int rc;
3606 3608 char **value;
3607 3609 int flags = 0;
3608 3610
3609 3611 *domainname = NULL;
3610 3612 *errorp = NULL;
3611 3613
3612 3614 /* Initialize State machine cookie */
3613 3615 cookie = init_search_state_machine();
3614 3616 if (cookie == NULL) {
3615 3617 return (NS_LDAP_MEMORY);
3616 3618 }
3617 3619 cookie->conn_user = conn_user;
3618 3620
3619 3621 /* see if need to follow referrals */
3620 3622 rc = __s_api_toFollowReferrals(flags,
3621 3623 &cookie->followRef, errorp);
3622 3624 if (rc != NS_LDAP_SUCCESS) {
3623 3625 delete_search_cookie(cookie);
3624 3626 return (rc);
3625 3627 }
3626 3628
3627 3629 /* Create default service Desc */
3628 3630 sdlist = (ns_ldap_search_desc_t **)calloc(2,
3629 3631 sizeof (ns_ldap_search_desc_t *));
3630 3632 if (sdlist == NULL) {
3631 3633 delete_search_cookie(cookie);
3632 3634 cookie = NULL;
3633 3635 return (NS_LDAP_MEMORY);
3634 3636 }
3635 3637 dptr = (ns_ldap_search_desc_t *)
3636 3638 calloc(1, sizeof (ns_ldap_search_desc_t));
3637 3639 if (dptr == NULL) {
3638 3640 free(sdlist);
3639 3641 delete_search_cookie(cookie);
3640 3642 cookie = NULL;
3641 3643 return (NS_LDAP_MEMORY);
3642 3644 }
3643 3645 sdlist[0] = dptr;
3644 3646
3645 3647 /* search base is dn */
3646 3648 dptr->basedn = strdup(dn);
3647 3649
3648 3650 /* search scope is base */
3649 3651 dptr->scope = NS_LDAP_SCOPE_BASE;
3650 3652
3651 3653 /* search filter is "nisdomain=*" */
3652 3654 dptr->filter = strdup(_NIS_FILTER);
3653 3655
3654 3656 cookie->sdlist = sdlist;
3655 3657 cookie->i_filter = strdup(dptr->filter);
3656 3658 cookie->i_attr = nis_domain_attrs;
3657 3659 cookie->i_auth = cred;
3658 3660 cookie->i_flags = 0;
3659 3661
3660 3662 /* Process search */
3661 3663 rc = search_state_machine(cookie, INIT, 0);
3662 3664
3663 3665 /* Copy domain name if found */
3664 3666 rc = cookie->err_rc;
3665 3667 if (rc != NS_LDAP_SUCCESS) {
3666 3668 if (conn_user != NULL && conn_user->ns_error != NULL) {
3667 3669 *errorp = conn_user->ns_error;
3668 3670 conn_user->ns_error = NULL;
3669 3671 } else
3670 3672 *errorp = cookie->errorp;
3671 3673 }
3672 3674 if (cookie->result == NULL)
3673 3675 rc = NS_LDAP_NOTFOUND;
3674 3676 if (rc == NS_LDAP_SUCCESS) {
3675 3677 value = __ns_ldap_getAttr(cookie->result->entry,
3676 3678 _NIS_DOMAIN);
3677 3679 if (value[0])
3678 3680 *domainname = strdup(value[0]);
3679 3681 else
3680 3682 rc = NS_LDAP_NOTFOUND;
3681 3683 }
3682 3684 if (cookie->result != NULL)
3683 3685 (void) __ns_ldap_freeResult(&cookie->result);
3684 3686 cookie->errorp = NULL;
3685 3687 delete_search_cookie(cookie);
3686 3688 cookie = NULL;
3687 3689 return (rc);
3688 3690 }
3689 3691
3690 3692 /*
3691 3693 * __s_api_find_domainname performs one or more LDAP searches to
3692 3694 * find the value of the nisdomain attribute associated with
3693 3695 * the input DN (with retry).
3694 3696 */
3695 3697
3696 3698 static int
3697 3699 __s_api_find_domainname(const char *dn, char **domainname,
3698 3700 const ns_cred_t *cred, ns_ldap_error_t **errorp)
3699 3701 {
3700 3702 ns_conn_user_t *cu = NULL;
3701 3703 int try_cnt = 0;
3702 3704 int rc = NS_LDAP_SUCCESS;
3703 3705
3704 3706 for (;;) {
3705 3707 if (__s_api_setup_retry_search(&cu, NS_CONN_USER_SEARCH,
3706 3708 &try_cnt, &rc, errorp) == 0)
3707 3709 break;
3708 3710 rc = find_domainname(dn, domainname, cred, errorp, cu);
3709 3711 }
3710 3712
3711 3713 return (rc);
3712 3714 }
3713 3715
3714 3716 static int
3715 3717 firstEntry(
3716 3718 const char *service,
3717 3719 const char *filter,
3718 3720 const char *sortattr,
3719 3721 int (*init_filter_cb)(const ns_ldap_search_desc_t *desc,
3720 3722 char **realfilter, const void *userdata),
3721 3723 const char * const *attribute,
3722 3724 const ns_cred_t *auth,
3723 3725 const int flags,
3724 3726 void **vcookie,
3725 3727 ns_ldap_result_t **result,
3726 3728 ns_ldap_error_t ** errorp,
3727 3729 const void *userdata,
3728 3730 ns_conn_user_t *conn_user)
3729 3731 {
3730 3732 ns_ldap_cookie_t *cookie = NULL;
3731 3733 ns_ldap_error_t *error = NULL;
3732 3734 ns_state_t state;
3733 3735 ns_ldap_search_desc_t **sdlist;
3734 3736 ns_ldap_search_desc_t *dptr;
3735 3737 char **dns = NULL;
3736 3738 int scope;
3737 3739 int rc;
3738 3740
3739 3741 *errorp = NULL;
3740 3742 *result = NULL;
3741 3743
3742 3744 /*
3743 3745 * Sanity check - NS_LDAP_READ_SHADOW is for our
3744 3746 * own internal use.
3745 3747 */
3746 3748 if (flags & NS_LDAP_READ_SHADOW)
3747 3749 return (NS_LDAP_INVALID_PARAM);
3748 3750
3749 3751 /* get the service descriptor - or create a default one */
3750 3752 rc = __s_api_get_SSD_from_SSDtoUse_service(service,
3751 3753 &sdlist, &error);
3752 3754 if (rc != NS_LDAP_SUCCESS) {
3753 3755 *errorp = error;
3754 3756 return (rc);
3755 3757 }
3756 3758 if (sdlist == NULL) {
3757 3759 /* Create default service Desc */
3758 3760 sdlist = (ns_ldap_search_desc_t **)calloc(2,
3759 3761 sizeof (ns_ldap_search_desc_t *));
3760 3762 if (sdlist == NULL) {
3761 3763 return (NS_LDAP_MEMORY);
3762 3764 }
3763 3765 dptr = (ns_ldap_search_desc_t *)
3764 3766 calloc(1, sizeof (ns_ldap_search_desc_t));
3765 3767 if (dptr == NULL) {
3766 3768 free(sdlist);
3767 3769 return (NS_LDAP_MEMORY);
3768 3770 }
3769 3771 sdlist[0] = dptr;
3770 3772
3771 3773 /* default base */
3772 3774 rc = __s_api_getDNs(&dns, service, &error);
3773 3775 if (rc != NS_LDAP_SUCCESS) {
3774 3776 if (dns) {
3775 3777 __s_api_free2dArray(dns);
3776 3778 dns = NULL;
3777 3779 }
3778 3780 if (sdlist) {
3779 3781 (void) __ns_ldap_freeSearchDescriptors(
3780 3782 &sdlist);
3781 3783
3782 3784 sdlist = NULL;
3783 3785 }
3784 3786 *errorp = error;
3785 3787 return (rc);
3786 3788 }
3787 3789 dptr->basedn = strdup(dns[0]);
3788 3790 __s_api_free2dArray(dns);
3789 3791 dns = NULL;
3790 3792
3791 3793 /* default scope */
3792 3794 scope = 0;
3793 3795 cookie = init_search_state_machine();
3794 3796 if (cookie == NULL) {
3795 3797 if (sdlist) {
3796 3798 (void) __ns_ldap_freeSearchDescriptors(&sdlist);
3797 3799 sdlist = NULL;
3798 3800 }
3799 3801 return (NS_LDAP_MEMORY);
3800 3802 }
3801 3803 rc = __s_api_getSearchScope(&scope, &cookie->errorp);
3802 3804 dptr->scope = scope;
3803 3805 }
3804 3806
3805 3807 /* Initialize State machine cookie */
3806 3808 if (cookie == NULL)
3807 3809 cookie = init_search_state_machine();
3808 3810 if (cookie == NULL) {
3809 3811 if (sdlist) {
3810 3812 (void) __ns_ldap_freeSearchDescriptors(&sdlist);
3811 3813 sdlist = NULL;
3812 3814 }
3813 3815 return (NS_LDAP_MEMORY);
3814 3816 }
3815 3817
3816 3818 /* identify self as a getent user */
3817 3819 cookie->conn_user = conn_user;
3818 3820
3819 3821 cookie->sdlist = sdlist;
3820 3822
3821 3823 /* see if need to follow referrals */
3822 3824 rc = __s_api_toFollowReferrals(flags,
3823 3825 &cookie->followRef, errorp);
3824 3826 if (rc != NS_LDAP_SUCCESS) {
3825 3827 delete_search_cookie(cookie);
3826 3828 return (rc);
3827 3829 }
3828 3830
3829 3831 /*
3830 3832 * use VLV/PAGE control only if NS_LDAP_NO_PAGE_CTRL is not set
3831 3833 */
3832 3834 if (flags & NS_LDAP_NO_PAGE_CTRL)
3833 3835 cookie->use_paging = FALSE;
3834 3836 else
3835 3837 cookie->use_paging = TRUE;
3836 3838
3837 3839 /* Set up other arguments */
3838 3840 cookie->userdata = userdata;
3839 3841 if (init_filter_cb != NULL) {
3840 3842 cookie->init_filter_cb = init_filter_cb;
3841 3843 cookie->use_filtercb = 1;
3842 3844 }
3843 3845 cookie->use_usercb = 0;
3844 3846 /* check_shadow() may add extra value to cookie->i_flags */
3845 3847 cookie->i_flags = flags;
3846 3848 if (service) {
3847 3849 cookie->service = strdup(service);
3848 3850 if (cookie->service == NULL) {
3849 3851 delete_search_cookie(cookie);
3850 3852 return (NS_LDAP_MEMORY);
3851 3853 }
3852 3854
3853 3855 /*
3854 3856 * If given, use the credential given by the caller, and
3855 3857 * skip the credential check required for shadow update.
3856 3858 */
3857 3859 if (auth == NULL) {
3858 3860 rc = check_shadow(cookie, service);
3859 3861 if (rc != NS_LDAP_SUCCESS) {
3860 3862 *errorp = cookie->errorp;
3861 3863 cookie->errorp = NULL;
3862 3864 delete_search_cookie(cookie);
3863 3865 cookie = NULL;
3864 3866 return (rc);
3865 3867 }
3866 3868 }
3867 3869 }
3868 3870
3869 3871 cookie->i_filter = strdup(filter);
3870 3872 cookie->i_attr = attribute;
3871 3873 cookie->i_sortattr = sortattr;
3872 3874 cookie->i_auth = auth;
3873 3875
3874 3876 state = INIT;
3875 3877 for (;;) {
3876 3878 state = search_state_machine(cookie, state, ONE_STEP);
3877 3879 switch (state) {
3878 3880 case PROCESS_RESULT:
3879 3881 *result = cookie->result;
3880 3882 cookie->result = NULL;
3881 3883 *vcookie = (void *)cookie;
3882 3884 return (NS_LDAP_SUCCESS);
3883 3885 case LDAP_ERROR:
3884 3886 state = search_state_machine(cookie, state, ONE_STEP);
3885 3887 state = search_state_machine(cookie, CLEAR_RESULTS,
3886 3888 ONE_STEP);
3887 3889 /* FALLTHROUGH */
3888 3890 case ERROR:
3889 3891 rc = cookie->err_rc;
3890 3892 if (conn_user != NULL && conn_user->ns_error != NULL) {
3891 3893 *errorp = conn_user->ns_error;
3892 3894 conn_user->ns_error = NULL;
3893 3895 } else {
3894 3896 *errorp = cookie->errorp;
3895 3897 cookie->errorp = NULL;
3896 3898 }
3897 3899 delete_search_cookie(cookie);
3898 3900 return (rc);
3899 3901 case EXIT:
3900 3902 rc = cookie->err_rc;
3901 3903 if (rc != NS_LDAP_SUCCESS) {
3902 3904 *errorp = cookie->errorp;
3903 3905 cookie->errorp = NULL;
3904 3906 } else {
3905 3907 rc = NS_LDAP_NOTFOUND;
3906 3908 }
3907 3909
3908 3910 delete_search_cookie(cookie);
3909 3911 return (rc);
3910 3912
3911 3913 default:
3912 3914 break;
3913 3915 }
3914 3916 }
3915 3917 }
3916 3918
3917 3919 int
3918 3920 __ns_ldap_firstEntry(
3919 3921 const char *service,
3920 3922 const char *filter,
3921 3923 const char *vlv_sort,
3922 3924 int (*init_filter_cb)(const ns_ldap_search_desc_t *desc,
3923 3925 char **realfilter, const void *userdata),
3924 3926 const char * const *attribute,
3925 3927 const ns_cred_t *auth,
3926 3928 const int flags,
3927 3929 void **vcookie,
3928 3930 ns_ldap_result_t **result,
3929 3931 ns_ldap_error_t ** errorp,
3930 3932 const void *userdata)
3931 3933 {
3932 3934 ns_conn_user_t *cu = NULL;
3933 3935 int try_cnt = 0;
3934 3936 int rc = NS_LDAP_SUCCESS;
3935 3937
3936 3938 for (;;) {
3937 3939 if (__s_api_setup_retry_search(&cu, NS_CONN_USER_GETENT,
3938 3940 &try_cnt, &rc, errorp) == 0)
3939 3941 break;
3940 3942 rc = firstEntry(service, filter, vlv_sort, init_filter_cb,
3941 3943 attribute, auth, flags, vcookie, result, errorp, userdata,
3942 3944 cu);
3943 3945 }
3944 3946 return (rc);
3945 3947 }
3946 3948
3947 3949 /*ARGSUSED2*/
3948 3950 int
3949 3951 __ns_ldap_nextEntry(void *vcookie, ns_ldap_result_t **result,
3950 3952 ns_ldap_error_t ** errorp)
3951 3953 {
3952 3954 ns_ldap_cookie_t *cookie;
3953 3955 ns_state_t state;
3954 3956 int rc;
3955 3957
3956 3958 cookie = (ns_ldap_cookie_t *)vcookie;
3957 3959 cookie->result = NULL;
3958 3960 *result = NULL;
3959 3961
3960 3962 if (cookie->conn_user != NULL) {
3961 3963 rc = __s_api_setup_getnext(cookie->conn_user,
3962 3964 &cookie->err_rc, errorp);
3963 3965 if (rc != NS_LDAP_SUCCESS)
3964 3966 return (rc);
3965 3967 }
3966 3968
3967 3969 state = END_PROCESS_RESULT;
3968 3970 for (;;) {
3969 3971 state = search_state_machine(cookie, state, ONE_STEP);
3970 3972 switch (state) {
3971 3973 case PROCESS_RESULT:
3972 3974 *result = cookie->result;
3973 3975 cookie->result = NULL;
3974 3976 return (NS_LDAP_SUCCESS);
3975 3977 case LDAP_ERROR:
3976 3978 state = search_state_machine(cookie, state, ONE_STEP);
3977 3979 state = search_state_machine(cookie, CLEAR_RESULTS,
3978 3980 ONE_STEP);
3979 3981 /* FALLTHROUGH */
3980 3982 case ERROR:
3981 3983 rc = cookie->err_rc;
3982 3984 *errorp = cookie->errorp;
3983 3985 cookie->errorp = NULL;
3984 3986 return (rc);
3985 3987 case EXIT:
3986 3988 return (NS_LDAP_SUCCESS);
3987 3989 }
3988 3990 }
3989 3991 }
3990 3992
3991 3993 int
3992 3994 __ns_ldap_endEntry(
3993 3995 void **vcookie,
3994 3996 ns_ldap_error_t ** errorp)
3995 3997 {
3996 3998 ns_ldap_cookie_t *cookie;
3997 3999 int rc;
3998 4000
3999 4001 if (*vcookie == NULL)
4000 4002 return (NS_LDAP_INVALID_PARAM);
4001 4003
4002 4004 cookie = (ns_ldap_cookie_t *)(*vcookie);
4003 4005 cookie->result = NULL;
4004 4006
4005 4007 /* Complete search */
4006 4008 rc = search_state_machine(cookie, CLEAR_RESULTS, 0);
4007 4009
4008 4010 /* Copy results back to user */
4009 4011 rc = cookie->err_rc;
4010 4012 if (rc != NS_LDAP_SUCCESS)
4011 4013 *errorp = cookie->errorp;
4012 4014
4013 4015 cookie->errorp = NULL;
4014 4016 if (cookie->conn_user != NULL) {
4015 4017 if (cookie->conn_user->conn_mt != NULL)
4016 4018 __s_api_conn_mt_return(cookie->conn_user);
4017 4019 __s_api_conn_user_free(cookie->conn_user);
4018 4020 }
4019 4021 delete_search_cookie(cookie);
4020 4022 cookie = NULL;
4021 4023 *vcookie = NULL;
4022 4024
4023 4025 return (rc);
4024 4026 }
4025 4027
4026 4028
4027 4029 int
4028 4030 __ns_ldap_freeResult(ns_ldap_result_t **result)
4029 4031 {
4030 4032
4031 4033 ns_ldap_entry_t *curEntry = NULL;
4032 4034 ns_ldap_entry_t *delEntry = NULL;
4033 4035 int i;
4034 4036 ns_ldap_result_t *res = *result;
4035 4037
4036 4038 #ifdef DEBUG
4037 4039 (void) fprintf(stderr, "__ns_ldap_freeResult START\n");
4038 4040 #endif
4039 4041 if (res == NULL)
4040 4042 return (NS_LDAP_INVALID_PARAM);
4041 4043
4042 4044 if (res->entry != NULL)
4043 4045 curEntry = res->entry;
4044 4046
4045 4047 for (i = 0; i < res->entries_count; i++) {
4046 4048 if (curEntry != NULL) {
4047 4049 delEntry = curEntry;
4048 4050 curEntry = curEntry->next;
4049 4051 __ns_ldap_freeEntry(delEntry);
4050 4052 }
4051 4053 }
4052 4054
4053 4055 free(res);
4054 4056 *result = NULL;
4055 4057 return (NS_LDAP_SUCCESS);
4056 4058 }
4057 4059
4058 4060 /*ARGSUSED*/
4059 4061 int
4060 4062 __ns_ldap_auth(const ns_cred_t *auth,
4061 4063 const int flags,
4062 4064 ns_ldap_error_t **errorp,
4063 4065 LDAPControl **serverctrls,
4064 4066 LDAPControl **clientctrls)
4065 4067 {
4066 4068
4067 4069 ConnectionID connectionId = -1;
4068 4070 Connection *conp;
4069 4071 int rc = 0;
4070 4072 int do_not_fail_if_new_pwd_reqd = 0;
4071 4073 int nopasswd_acct_mgmt = 0;
4072 4074 ns_conn_user_t *conn_user;
4073 4075
4074 4076
4075 4077 #ifdef DEBUG
4076 4078 (void) fprintf(stderr, "__ns_ldap_auth START\n");
4077 4079 #endif
4078 4080
4079 4081 *errorp = NULL;
4080 4082 if (!auth)
4081 4083 return (NS_LDAP_INVALID_PARAM);
4082 4084
4083 4085 conn_user = __s_api_conn_user_init(NS_CONN_USER_AUTH,
4084 4086 NULL, B_FALSE);
4085 4087
4086 4088 rc = __s_api_getConnection(NULL, flags | NS_LDAP_NEW_CONN,
4087 4089 auth, &connectionId, &conp, errorp,
4088 4090 do_not_fail_if_new_pwd_reqd, nopasswd_acct_mgmt,
4089 4091 conn_user);
4090 4092
4091 4093 if (conn_user != NULL)
4092 4094 __s_api_conn_user_free(conn_user);
4093 4095
4094 4096 if (rc == NS_LDAP_OP_FAILED && *errorp)
4095 4097 (void) __ns_ldap_freeError(errorp);
4096 4098
4097 4099 if (connectionId > -1)
4098 4100 DropConnection(connectionId, flags);
4099 4101 return (rc);
4100 4102 }
4101 4103
4102 4104 char **
4103 4105 __ns_ldap_getAttr(const ns_ldap_entry_t *entry, const char *attrname)
4104 4106 {
4105 4107 int i;
4106 4108
4107 4109 if (entry == NULL)
4108 4110 return (NULL);
4109 4111 for (i = 0; i < entry->attr_count; i++) {
4110 4112 if (strcasecmp(entry->attr_pair[i]->attrname, attrname) == NULL)
4111 4113 return (entry->attr_pair[i]->attrvalue);
4112 4114 }
4113 4115 return (NULL);
4114 4116 }
4115 4117
4116 4118 ns_ldap_attr_t *
4117 4119 __ns_ldap_getAttrStruct(const ns_ldap_entry_t *entry, const char *attrname)
4118 4120 {
4119 4121 int i;
4120 4122
4121 4123 if (entry == NULL)
4122 4124 return (NULL);
4123 4125 for (i = 0; i < entry->attr_count; i++) {
4124 4126 if (strcasecmp(entry->attr_pair[i]->attrname, attrname) == NULL)
4125 4127 return (entry->attr_pair[i]);
4126 4128 }
4127 4129 return (NULL);
4128 4130 }
4129 4131
4130 4132
4131 4133 /*ARGSUSED*/
4132 4134 int
4133 4135 __ns_ldap_uid2dn(const char *uid,
4134 4136 char **userDN,
4135 4137 const ns_cred_t *cred, /* cred is ignored */
4136 4138 ns_ldap_error_t **errorp)
4137 4139 {
4138 4140 ns_ldap_result_t *result = NULL;
4139 4141 char *filter, *userdata;
4140 4142 char errstr[MAXERROR];
4141 4143 char **value;
4142 4144 int rc = 0;
4143 4145 int i = 0;
4144 4146 size_t len;
4145 4147
4146 4148 *errorp = NULL;
4147 4149 *userDN = NULL;
4148 4150 if ((uid == NULL) || (uid[0] == '\0'))
4149 4151 return (NS_LDAP_INVALID_PARAM);
4150 4152
4151 4153 while (uid[i] != '\0') {
4152 4154 if (uid[i] == '=') {
4153 4155 *userDN = strdup(uid);
4154 4156 return (NS_LDAP_SUCCESS);
4155 4157 }
4156 4158 i++;
4157 4159 }
4158 4160 i = 0;
4159 4161 while ((uid[i] != '\0') && (isdigit(uid[i])))
4160 4162 i++;
4161 4163 if (uid[i] == '\0') {
4162 4164 len = strlen(UIDNUMFILTER) + strlen(uid) + 1;
4163 4165 filter = (char *)malloc(len);
4164 4166 if (filter == NULL) {
4165 4167 *userDN = NULL;
4166 4168 return (NS_LDAP_MEMORY);
4167 4169 }
4168 4170 (void) snprintf(filter, len, UIDNUMFILTER, uid);
4169 4171
4170 4172 len = strlen(UIDNUMFILTER_SSD) + strlen(uid) + 1;
4171 4173 userdata = (char *)malloc(len);
4172 4174 if (userdata == NULL) {
4173 4175 *userDN = NULL;
4174 4176 return (NS_LDAP_MEMORY);
4175 4177 }
4176 4178 (void) snprintf(userdata, len, UIDNUMFILTER_SSD, uid);
4177 4179 } else {
4178 4180 len = strlen(UIDFILTER) + strlen(uid) + 1;
4179 4181 filter = (char *)malloc(len);
4180 4182 if (filter == NULL) {
4181 4183 *userDN = NULL;
4182 4184 return (NS_LDAP_MEMORY);
4183 4185 }
4184 4186 (void) snprintf(filter, len, UIDFILTER, uid);
4185 4187
4186 4188 len = strlen(UIDFILTER_SSD) + strlen(uid) + 1;
4187 4189 userdata = (char *)malloc(len);
4188 4190 if (userdata == NULL) {
4189 4191 *userDN = NULL;
4190 4192 return (NS_LDAP_MEMORY);
4191 4193 }
4192 4194 (void) snprintf(userdata, len, UIDFILTER_SSD, uid);
4193 4195 }
4194 4196
4195 4197 /*
4196 4198 * we want to retrieve the DN as it appears in LDAP
4197 4199 * hence the use of NS_LDAP_NOT_CVT_DN in flags
4198 4200 */
4199 4201 rc = __ns_ldap_list("passwd", filter,
4200 4202 __s_api_merge_SSD_filter,
4201 4203 NULL, cred, NS_LDAP_NOT_CVT_DN,
4202 4204 &result, errorp, NULL,
4203 4205 userdata);
4204 4206 free(filter);
4205 4207 filter = NULL;
4206 4208 free(userdata);
4207 4209 userdata = NULL;
4208 4210 if (rc != NS_LDAP_SUCCESS) {
4209 4211 if (result) {
4210 4212 (void) __ns_ldap_freeResult(&result);
4211 4213 result = NULL;
4212 4214 }
4213 4215 return (rc);
4214 4216 }
4215 4217 if (result->entries_count > 1) {
4216 4218 (void) __ns_ldap_freeResult(&result);
4217 4219 result = NULL;
4218 4220 *userDN = NULL;
4219 4221 (void) sprintf(errstr,
4220 4222 gettext("Too many entries are returned for %s"), uid);
4221 4223 MKERROR(LOG_WARNING, *errorp, NS_LDAP_INTERNAL, strdup(errstr),
4222 4224 NULL);
|
↓ open down ↓ |
3982 lines elided |
↑ open up ↑ |
4223 4225 return (NS_LDAP_INTERNAL);
4224 4226 }
4225 4227
4226 4228 value = __ns_ldap_getAttr(result->entry, "dn");
4227 4229 *userDN = strdup(value[0]);
4228 4230 (void) __ns_ldap_freeResult(&result);
4229 4231 result = NULL;
4230 4232 return (NS_LDAP_SUCCESS);
4231 4233 }
4232 4234
4235 +#define _P_UID "uid"
4236 +static const char *dn2uid_attrs[] = {
4237 + _P_CN,
4238 + _P_UID,
4239 + (char *)NULL
4240 +};
4233 4241
4234 4242 /*ARGSUSED*/
4243 +int
4244 +__ns_ldap_dn2uid(const char *dn,
4245 + char **userID,
4246 + const ns_cred_t *cred, /* cred is ignored */
4247 + ns_ldap_error_t **errorp)
4248 +{
4249 + ns_ldap_result_t *result = NULL;
4250 + char *filter, *userdata;
4251 + char errstr[MAXERROR];
4252 + char **value;
4253 + int rc = 0;
4254 + size_t len;
4255 +
4256 + *errorp = NULL;
4257 + *userID = NULL;
4258 + if ((dn == NULL) || (dn[0] == '\0'))
4259 + return (NS_LDAP_INVALID_PARAM);
4260 +
4261 + len = strlen(UIDDNFILTER) + strlen(dn) + 1;
4262 + filter = (char *)malloc(len);
4263 + if (filter == NULL) {
4264 + return (NS_LDAP_MEMORY);
4265 + }
4266 + (void) snprintf(filter, len, UIDDNFILTER, dn);
4267 +
4268 + len = strlen(UIDDNFILTER_SSD) + strlen(dn) + 1;
4269 + userdata = (char *)malloc(len);
4270 + if (userdata == NULL) {
4271 + return (NS_LDAP_MEMORY);
4272 + }
4273 + (void) snprintf(userdata, len, UIDDNFILTER_SSD, dn);
4274 +
4275 + /*
4276 + * Unlike uid2dn, we DO want attribute mapping, so that
4277 + * "uid" is mapped to/from samAccountName, for example.
4278 + */
4279 + rc = __ns_ldap_list("passwd", filter,
4280 + __s_api_merge_SSD_filter,
4281 + dn2uid_attrs, cred, 0,
4282 + &result, errorp, NULL,
4283 + userdata);
4284 + free(filter);
4285 + filter = NULL;
4286 + free(userdata);
4287 + userdata = NULL;
4288 + if (rc != NS_LDAP_SUCCESS)
4289 + goto out;
4290 +
4291 + if (result->entries_count > 1) {
4292 + (void) sprintf(errstr,
4293 + gettext("Too many entries are returned for %s"), dn);
4294 + MKERROR(LOG_WARNING, *errorp, NS_LDAP_INTERNAL, strdup(errstr),
4295 + NULL);
4296 + rc = NS_LDAP_INTERNAL;
4297 + goto out;
4298 + }
4299 +
4300 + value = __ns_ldap_getAttr(result->entry, _P_UID);
4301 + if (value == NULL || value[0] == NULL) {
4302 + rc = NS_LDAP_NOTFOUND;
4303 + goto out;
4304 + }
4305 +
4306 + *userID = strdup(value[0]);
4307 + rc = NS_LDAP_SUCCESS;
4308 +
4309 +out:
4310 + (void) __ns_ldap_freeResult(&result);
4311 + result = NULL;
4312 + return (rc);
4313 +}
4314 +
4315 +/*ARGSUSED*/
4235 4316 int
4236 4317 __ns_ldap_host2dn(const char *host,
4237 4318 const char *domain,
4238 4319 char **hostDN,
4239 4320 const ns_cred_t *cred, /* cred is ignored */
4240 4321 ns_ldap_error_t **errorp)
4241 4322 {
4242 4323 ns_ldap_result_t *result = NULL;
4243 4324 char *filter, *userdata;
4244 4325 char errstr[MAXERROR];
4245 4326 char **value;
4246 4327 int rc;
4247 4328 size_t len;
4248 4329
4249 4330 /*
4250 4331 * XXX
4251 4332 * the domain parameter needs to be used in case domain is not local, if
4252 4333 * this routine is to support multi domain setups, it needs lots of work...
4253 4334 */
4254 4335 *errorp = NULL;
4255 4336 *hostDN = NULL;
4256 4337 if ((host == NULL) || (host[0] == '\0'))
4257 4338 return (NS_LDAP_INVALID_PARAM);
4258 4339
4259 4340 len = strlen(HOSTFILTER) + strlen(host) + 1;
4260 4341 filter = (char *)malloc(len);
4261 4342 if (filter == NULL) {
4262 4343 return (NS_LDAP_MEMORY);
4263 4344 }
4264 4345 (void) snprintf(filter, len, HOSTFILTER, host);
4265 4346
4266 4347 len = strlen(HOSTFILTER_SSD) + strlen(host) + 1;
4267 4348 userdata = (char *)malloc(len);
4268 4349 if (userdata == NULL) {
4269 4350 return (NS_LDAP_MEMORY);
4270 4351 }
4271 4352 (void) snprintf(userdata, len, HOSTFILTER_SSD, host);
4272 4353
4273 4354 /*
4274 4355 * we want to retrieve the DN as it appears in LDAP
4275 4356 * hence the use of NS_LDAP_NOT_CVT_DN in flags
4276 4357 */
4277 4358 rc = __ns_ldap_list("hosts", filter,
4278 4359 __s_api_merge_SSD_filter,
4279 4360 NULL, cred, NS_LDAP_NOT_CVT_DN, &result,
4280 4361 errorp, NULL,
4281 4362 userdata);
4282 4363 free(filter);
4283 4364 filter = NULL;
4284 4365 free(userdata);
4285 4366 userdata = NULL;
4286 4367 if (rc != NS_LDAP_SUCCESS) {
4287 4368 if (result) {
4288 4369 (void) __ns_ldap_freeResult(&result);
4289 4370 result = NULL;
4290 4371 }
4291 4372 return (rc);
4292 4373 }
4293 4374
4294 4375 if (result->entries_count > 1) {
4295 4376 (void) __ns_ldap_freeResult(&result);
4296 4377 result = NULL;
4297 4378 *hostDN = NULL;
4298 4379 (void) sprintf(errstr,
4299 4380 gettext("Too many entries are returned for %s"), host);
4300 4381 MKERROR(LOG_WARNING, *errorp, NS_LDAP_INTERNAL, strdup(errstr),
4301 4382 NULL);
4302 4383 return (NS_LDAP_INTERNAL);
4303 4384 }
4304 4385
4305 4386 value = __ns_ldap_getAttr(result->entry, "dn");
4306 4387 *hostDN = strdup(value[0]);
4307 4388 (void) __ns_ldap_freeResult(&result);
4308 4389 result = NULL;
4309 4390 return (NS_LDAP_SUCCESS);
4310 4391 }
4311 4392
4312 4393 /*ARGSUSED*/
4313 4394 int
4314 4395 __ns_ldap_dn2domain(const char *dn,
4315 4396 char **domain,
4316 4397 const ns_cred_t *cred,
4317 4398 ns_ldap_error_t **errorp)
4318 4399 {
4319 4400 int rc, pnum, i, j, len = 0;
4320 4401 char *newdn, **rdns = NULL;
4321 4402 char **dns, *dn1;
4322 4403
4323 4404 *errorp = NULL;
4324 4405
4325 4406 if (domain == NULL)
4326 4407 return (NS_LDAP_INVALID_PARAM);
4327 4408 else
4328 4409 *domain = NULL;
4329 4410
4330 4411 if ((dn == NULL) || (dn[0] == '\0'))
4331 4412 return (NS_LDAP_INVALID_PARAM);
4332 4413
4333 4414 /*
4334 4415 * break dn into rdns
4335 4416 */
4336 4417 dn1 = strdup(dn);
4337 4418 if (dn1 == NULL)
4338 4419 return (NS_LDAP_MEMORY);
4339 4420 rdns = ldap_explode_dn(dn1, 0);
4340 4421 free(dn1);
4341 4422 if (rdns == NULL || *rdns == NULL)
4342 4423 return (NS_LDAP_INVALID_PARAM);
4343 4424
4344 4425 for (i = 0; rdns[i]; i++)
4345 4426 len += strlen(rdns[i]) + 1;
4346 4427 pnum = i;
4347 4428
4348 4429 newdn = (char *)malloc(len + 1);
4349 4430 dns = (char **)calloc(pnum, sizeof (char *));
4350 4431 if (newdn == NULL || dns == NULL) {
4351 4432 if (newdn)
4352 4433 free(newdn);
4353 4434 ldap_value_free(rdns);
4354 4435 return (NS_LDAP_MEMORY);
4355 4436 }
4356 4437
4357 4438 /* construct a semi-normalized dn, newdn */
4358 4439 *newdn = '\0';
4359 4440 for (i = 0; rdns[i]; i++) {
4360 4441 dns[i] = newdn + strlen(newdn);
4361 4442 (void) strcat(newdn,
4362 4443 __s_api_remove_rdn_space(rdns[i]));
4363 4444 (void) strcat(newdn, ",");
4364 4445 }
4365 4446 /* remove the last ',' */
4366 4447 newdn[strlen(newdn) - 1] = '\0';
4367 4448 ldap_value_free(rdns);
4368 4449
4369 4450 /*
4370 4451 * loop and find the domain name associated with newdn,
4371 4452 * removing rdn one by one from left to right
4372 4453 */
4373 4454 for (i = 0; i < pnum; i++) {
4374 4455
4375 4456 if (*errorp)
4376 4457 (void) __ns_ldap_freeError(errorp);
4377 4458
4378 4459 /*
4379 4460 * try cache manager first
4380 4461 */
4381 4462 rc = __s_api_get_cachemgr_data(NS_CACHE_DN2DOMAIN,
4382 4463 dns[i], domain);
4383 4464 if (rc != NS_LDAP_SUCCESS) {
4384 4465 /*
4385 4466 * try ldap server second
4386 4467 */
4387 4468 rc = __s_api_find_domainname(dns[i], domain,
4388 4469 cred, errorp);
4389 4470 } else {
4390 4471 /*
4391 4472 * skip the last one,
4392 4473 * since it is already cached by ldap_cachemgr
4393 4474 */
4394 4475 i--;
4395 4476 }
4396 4477 if (rc == NS_LDAP_SUCCESS) {
4397 4478 if (__s_api_nscd_proc()) {
4398 4479 /*
4399 4480 * If it's nscd, ask cache manager to save the
4400 4481 * dn to domain mapping(s)
4401 4482 */
4402 4483 for (j = 0; j <= i; j++) {
4403 4484 (void) __s_api_set_cachemgr_data(
4404 4485 NS_CACHE_DN2DOMAIN,
4405 4486 dns[j],
4406 4487 *domain);
4407 4488 }
4408 4489 }
4409 4490 break;
4410 4491 }
4411 4492 }
4412 4493
4413 4494 free(dns);
4414 4495 free(newdn);
4415 4496 if (rc != NS_LDAP_SUCCESS)
4416 4497 rc = NS_LDAP_NOTFOUND;
4417 4498 return (rc);
4418 4499 }
4419 4500
4420 4501 /*ARGSUSED*/
4421 4502 int
4422 4503 __ns_ldap_getServiceAuthMethods(const char *service,
4423 4504 ns_auth_t ***auth,
4424 4505 ns_ldap_error_t **errorp)
4425 4506 {
4426 4507 char errstr[MAXERROR];
4427 4508 int rc, i, done = 0;
4428 4509 int slen;
4429 4510 void **param;
4430 4511 char **sam, *srv, *send;
4431 4512 ns_auth_t **authpp = NULL, *ap;
4432 4513 int cnt, max;
4433 4514 ns_config_t *cfg;
4434 4515 ns_ldap_error_t *error = NULL;
4435 4516
4436 4517 if (errorp == NULL)
4437 4518 return (NS_LDAP_INVALID_PARAM);
4438 4519 *errorp = NULL;
4439 4520
4440 4521 if ((service == NULL) || (service[0] == '\0') ||
4441 4522 (auth == NULL))
4442 4523 return (NS_LDAP_INVALID_PARAM);
4443 4524
4444 4525 *auth = NULL;
4445 4526 rc = __ns_ldap_getParam(NS_LDAP_SERVICE_AUTH_METHOD_P, ¶m, &error);
4446 4527 if (rc != NS_LDAP_SUCCESS || param == NULL) {
4447 4528 *errorp = error;
4448 4529 return (rc);
4449 4530 }
4450 4531 sam = (char **)param;
4451 4532
4452 4533 cfg = __s_api_get_default_config();
4453 4534 cnt = 0;
4454 4535
4455 4536 slen = strlen(service);
4456 4537
4457 4538 for (; *sam; sam++) {
4458 4539 srv = *sam;
4459 4540 if (strncasecmp(service, srv, slen) != 0)
4460 4541 continue;
4461 4542 srv += slen;
4462 4543 if (*srv != COLONTOK)
4463 4544 continue;
4464 4545 send = srv;
4465 4546 srv++;
4466 4547 for (max = 1; (send = strchr(++send, SEMITOK)) != NULL;
4467 4548 max++) {}
4468 4549 authpp = (ns_auth_t **)calloc(++max, sizeof (ns_auth_t *));
4469 4550 if (authpp == NULL) {
4470 4551 (void) __ns_ldap_freeParam(¶m);
4471 4552 __s_api_release_config(cfg);
4472 4553 return (NS_LDAP_MEMORY);
4473 4554 }
4474 4555 while (!done) {
4475 4556 send = strchr(srv, SEMITOK);
4476 4557 if (send != NULL) {
4477 4558 *send = '\0';
4478 4559 send++;
4479 4560 }
4480 4561 i = __s_get_enum_value(cfg, srv, NS_LDAP_AUTH_P);
4481 4562 if (i == -1) {
4482 4563 (void) __ns_ldap_freeParam(¶m);
4483 4564 (void) sprintf(errstr,
4484 4565 gettext("Unsupported "
4485 4566 "serviceAuthenticationMethod: %s.\n"), srv);
4486 4567 MKERROR(LOG_WARNING, *errorp, NS_CONFIG_SYNTAX,
4487 4568 strdup(errstr), NULL);
4488 4569 __s_api_release_config(cfg);
4489 4570 return (NS_LDAP_CONFIG);
4490 4571 }
4491 4572 ap = __s_api_AuthEnumtoStruct((EnumAuthType_t)i);
4492 4573 if (ap == NULL) {
4493 4574 (void) __ns_ldap_freeParam(¶m);
4494 4575 __s_api_release_config(cfg);
4495 4576 return (NS_LDAP_MEMORY);
4496 4577 }
4497 4578 authpp[cnt++] = ap;
4498 4579 if (send == NULL)
4499 4580 done = TRUE;
4500 4581 else
4501 4582 srv = send;
4502 4583 }
4503 4584 }
4504 4585
4505 4586 *auth = authpp;
4506 4587 (void) __ns_ldap_freeParam(¶m);
4507 4588 __s_api_release_config(cfg);
4508 4589 return (NS_LDAP_SUCCESS);
4509 4590 }
4510 4591
4511 4592 /*
4512 4593 * This routine is called when certain scenario occurs
4513 4594 * e.g.
4514 4595 * service == auto_home
4515 4596 * SSD = automount: ou = mytest,
4516 4597 * NS_LDAP_MAPATTRIBUTE= auto_home: automountMapName=AAA
4517 4598 * NS_LDAP_OBJECTCLASSMAP= auto_home:automountMap=MynisMap
4518 4599 * NS_LDAP_OBJECTCLASSMAP= auto_home:automount=MynisObject
4519 4600 *
4520 4601 * The automountMapName is prepended implicitely but is mapped
4521 4602 * to AAA. So dn could appers as
4522 4603 * dn: AAA=auto_home,ou=bar,dc=foo,dc=com
4523 4604 * dn: automountKey=user_01,AAA=auto_home,ou=bar,dc=foo,dc=com
4524 4605 * dn: automountKey=user_02,AAA=auto_home,ou=bar,dc=foo,dc=com
4525 4606 * in the directory.
4526 4607 * This function is called to covert the mapped attr back to
4527 4608 * orig attr when the entries are searched and returned
4528 4609 */
4529 4610
4530 4611 int
4531 4612 __s_api_convert_automountmapname(const char *service, char **dn,
4532 4613 ns_ldap_error_t **errp) {
4533 4614
4534 4615 char **mapping = NULL;
4535 4616 char *mapped_attr = NULL;
4536 4617 char *automountmapname = "automountMapName";
4537 4618 char *buffer = NULL;
4538 4619 int rc = NS_LDAP_SUCCESS;
4539 4620 char errstr[MAXERROR];
4540 4621
4541 4622 /*
4542 4623 * dn is an input/out parameter, check it first
4543 4624 */
4544 4625
4545 4626 if (service == NULL || dn == NULL || *dn == NULL)
4546 4627 return (NS_LDAP_INVALID_PARAM);
4547 4628
4548 4629 /*
4549 4630 * Check to see if there is a mapped attribute for auto_xxx
4550 4631 */
4551 4632
4552 4633 mapping = __ns_ldap_getMappedAttributes(service, automountmapname);
4553 4634
4554 4635 /*
4555 4636 * if no mapped attribute for auto_xxx, try automount
4556 4637 */
4557 4638
4558 4639 if (mapping == NULL)
4559 4640 mapping = __ns_ldap_getMappedAttributes(
4560 4641 "automount", automountmapname);
4561 4642
4562 4643 /*
4563 4644 * if no mapped attribute is found, return SUCCESS (no op)
4564 4645 */
4565 4646
4566 4647 if (mapping == NULL)
4567 4648 return (NS_LDAP_SUCCESS);
4568 4649
4569 4650 /*
4570 4651 * if the mapped attribute is found and attr is not empty,
4571 4652 * copy it
4572 4653 */
4573 4654
4574 4655 if (mapping[0] != NULL) {
4575 4656 mapped_attr = strdup(mapping[0]);
4576 4657 __s_api_free2dArray(mapping);
4577 4658 if (mapped_attr == NULL) {
4578 4659 return (NS_LDAP_MEMORY);
4579 4660 }
4580 4661 } else {
4581 4662 __s_api_free2dArray(mapping);
4582 4663
4583 4664 (void) snprintf(errstr, (2 * MAXERROR),
4584 4665 gettext(
4585 4666 "Attribute nisMapName is mapped to an "
4586 4667 "empty string.\n"));
4587 4668
4588 4669 MKERROR(LOG_ERR, *errp, NS_CONFIG_SYNTAX,
4589 4670 strdup(errstr), NULL);
4590 4671
4591 4672 return (NS_LDAP_CONFIG);
4592 4673 }
4593 4674
4594 4675 /*
4595 4676 * Locate the mapped attribute in the dn
4596 4677 * and replace it if it exists
4597 4678 */
4598 4679
4599 4680 rc = __s_api_replace_mapped_attr_in_dn(
4600 4681 (const char *) automountmapname, (const char *) mapped_attr,
4601 4682 (const char *) *dn, &buffer);
4602 4683
4603 4684 /* clean up */
4604 4685
4605 4686 free(mapped_attr);
4606 4687
4607 4688 /*
4608 4689 * If mapped attr is found(buffer != NULL)
4609 4690 * a new dn is returned
4610 4691 * If no mapped attribute is in dn,
4611 4692 * return NS_LDAP_SUCCESS (no op)
4612 4693 * If no memory,
4613 4694 * return NS_LDAP_MEMORY (no op)
4614 4695 */
4615 4696
4616 4697 if (buffer != NULL) {
4617 4698 free(*dn);
4618 4699 *dn = buffer;
4619 4700 }
4620 4701
4621 4702 return (rc);
4622 4703 }
4623 4704
4624 4705 /*
4625 4706 * If the mapped attr is found in the dn,
4626 4707 * return NS_LDAP_SUCCESS and a new_dn.
4627 4708 * If no mapped attr is found,
4628 4709 * return NS_LDAP_SUCCESS and *new_dn == NULL
4629 4710 * If there is not enough memory,
4630 4711 * return NS_LDAP_MEMORY and *new_dn == NULL
4631 4712 */
4632 4713
4633 4714 int
4634 4715 __s_api_replace_mapped_attr_in_dn(
4635 4716 const char *orig_attr, const char *mapped_attr,
4636 4717 const char *dn, char **new_dn) {
4637 4718
4638 4719 char **dnArray = NULL;
4639 4720 char *cur = NULL, *start = NULL;
4640 4721 int i = 0, found = 0;
4641 4722 int len = 0, orig_len = 0, mapped_len = 0;
4642 4723 int dn_len = 0, tmp_len = 0;
4643 4724
4644 4725 *new_dn = NULL;
4645 4726
4646 4727 /*
4647 4728 * seperate dn into individual componets
4648 4729 * e.g.
4649 4730 * "automountKey=user_01" , "automountMapName_test=auto_home", ...
4650 4731 */
4651 4732 dnArray = ldap_explode_dn(dn, 0);
4652 4733
4653 4734 /*
4654 4735 * This will find "mapped attr=value" in dn.
4655 4736 * It won't find match if mapped attr appears
4656 4737 * in the value.
4657 4738 */
4658 4739 for (i = 0; dnArray[i] != NULL; i++) {
4659 4740 /*
4660 4741 * This function is called when reading from
4661 4742 * the directory so assume each component has "=".
4662 4743 * Any ill formatted dn should be rejected
4663 4744 * before adding to the directory
4664 4745 */
4665 4746 cur = strchr(dnArray[i], '=');
4666 4747 *cur = '\0';
4667 4748 if (strcasecmp(mapped_attr, dnArray[i]) == 0)
4668 4749 found = 1;
4669 4750 *cur = '=';
4670 4751 if (found) break;
4671 4752 }
4672 4753
4673 4754 if (!found) {
4674 4755 __s_api_free2dArray(dnArray);
4675 4756 *new_dn = NULL;
4676 4757 return (NS_LDAP_SUCCESS);
4677 4758 }
4678 4759 /*
4679 4760 * The new length is *dn length + (difference between
4680 4761 * orig attr and mapped attr) + 1 ;
4681 4762 * e.g.
4682 4763 * automountKey=aa,automountMapName_test=auto_home,dc=foo,dc=com
4683 4764 * ==>
4684 4765 * automountKey=aa,automountMapName=auto_home,dc=foo,dc=com
4685 4766 */
4686 4767 mapped_len = strlen(mapped_attr);
4687 4768 orig_len = strlen(orig_attr);
4688 4769 dn_len = strlen(dn);
4689 4770 len = dn_len + orig_len - mapped_len + 1;
4690 4771 *new_dn = (char *)calloc(1, len);
4691 4772 if (*new_dn == NULL) {
4692 4773 __s_api_free2dArray(dnArray);
4693 4774 return (NS_LDAP_MEMORY);
4694 4775 }
4695 4776
4696 4777 /*
4697 4778 * Locate the mapped attr in the dn.
4698 4779 * Use dnArray[i] instead of mapped_attr
4699 4780 * because mapped_attr could appear in
4700 4781 * the value
4701 4782 */
4702 4783
4703 4784 cur = strstr(dn, dnArray[i]);
4704 4785 __s_api_free2dArray(dnArray);
4705 4786 /* copy the portion before mapped attr in dn */
4706 4787 start = *new_dn;
4707 4788 tmp_len = cur - dn;
4708 4789 (void) memcpy((void *) start, (const void*) dn, tmp_len);
4709 4790
4710 4791 /*
4711 4792 * Copy the orig_attr. e.g. automountMapName
4712 4793 * This replaces mapped attr with orig attr
4713 4794 */
4714 4795 start = start + (cur - dn); /* move cursor in buffer */
4715 4796 (void) memcpy((void *) start, (const void*) orig_attr, orig_len);
4716 4797
4717 4798 /*
4718 4799 * Copy the portion after mapped attr in dn
4719 4800 */
4720 4801 cur = cur + mapped_len; /* move cursor in dn */
4721 4802 start = start + orig_len; /* move cursor in buffer */
4722 4803 (void) strcpy(start, cur);
4723 4804
4724 4805 return (NS_LDAP_SUCCESS);
4725 4806 }
4726 4807
4727 4808 /*
4728 4809 * Validate Filter functions
4729 4810 */
4730 4811
4731 4812 /* ***** Start of modified libldap.so.5 filter parser ***** */
4732 4813
4733 4814 /* filter parsing routine forward references */
4734 4815 static int adj_filter_list(char *str);
4735 4816 static int adj_simple_filter(char *str);
4736 4817 static int unescape_filterval(char *val);
4737 4818 static int hexchar2int(char c);
4738 4819 static int adj_substring_filter(char *val);
4739 4820
4740 4821
4741 4822 /*
4742 4823 * assumes string manipulation is in-line
4743 4824 * and all strings are sufficient in size
4744 4825 * return value is the position after 'c'
4745 4826 */
4746 4827
4747 4828 static char *
4748 4829 resync_str(char *str, char *next, char c)
4749 4830 {
4750 4831 char *ret;
4751 4832
4752 4833 ret = str + strlen(str);
4753 4834 *next = c;
4754 4835 if (ret == next)
4755 4836 return (ret);
4756 4837 (void) strcat(str, next);
4757 4838 return (ret);
4758 4839 }
4759 4840
4760 4841 static char *
4761 4842 find_right_paren(char *s)
4762 4843 {
4763 4844 int balance, escape;
4764 4845
4765 4846 balance = 1;
4766 4847 escape = 0;
4767 4848 while (*s && balance) {
4768 4849 if (escape == 0) {
4769 4850 if (*s == '(')
4770 4851 balance++;
4771 4852 else if (*s == ')')
4772 4853 balance--;
4773 4854 }
4774 4855 if (*s == '\\' && ! escape)
4775 4856 escape = 1;
4776 4857 else
4777 4858 escape = 0;
4778 4859 if (balance)
4779 4860 s++;
4780 4861 }
4781 4862
4782 4863 return (*s ? s : NULL);
4783 4864 }
4784 4865
4785 4866 static char *
4786 4867 adj_complex_filter(char *str)
4787 4868 {
4788 4869 char *next;
4789 4870
4790 4871 /*
4791 4872 * We have (x(filter)...) with str sitting on
4792 4873 * the x. We have to find the paren matching
4793 4874 * the one before the x and put the intervening
4794 4875 * filters by calling adj_filter_list().
4795 4876 */
4796 4877
4797 4878 str++;
4798 4879 if ((next = find_right_paren(str)) == NULL)
4799 4880 return (NULL);
4800 4881
4801 4882 *next = '\0';
4802 4883 if (adj_filter_list(str) == -1)
4803 4884 return (NULL);
4804 4885 next = resync_str(str, next, ')');
4805 4886 next++;
4806 4887
4807 4888 return (next);
4808 4889 }
4809 4890
4810 4891 static int
4811 4892 adj_filter(char *str)
4812 4893 {
4813 4894 char *next;
4814 4895 int parens, balance, escape;
4815 4896 char *np, *cp, *dp;
4816 4897
4817 4898 parens = 0;
4818 4899 while (*str) {
4819 4900 switch (*str) {
4820 4901 case '(':
4821 4902 str++;
4822 4903 parens++;
4823 4904 switch (*str) {
4824 4905 case '&':
4825 4906 if ((str = adj_complex_filter(str)) == NULL)
4826 4907 return (-1);
4827 4908
4828 4909 parens--;
4829 4910 break;
4830 4911
4831 4912 case '|':
4832 4913 if ((str = adj_complex_filter(str)) == NULL)
4833 4914 return (-1);
4834 4915
4835 4916 parens--;
4836 4917 break;
4837 4918
4838 4919 case '!':
4839 4920 if ((str = adj_complex_filter(str)) == NULL)
4840 4921 return (-1);
4841 4922
4842 4923 parens--;
4843 4924 break;
4844 4925
4845 4926 case '(':
4846 4927 /* illegal ((case - generated by conversion */
4847 4928
4848 4929 /* find missing close) */
4849 4930 np = find_right_paren(str+1);
4850 4931
4851 4932 /* error if not found */
4852 4933 if (np == NULL)
4853 4934 return (-1);
4854 4935
4855 4936 /* remove redundant (and) */
4856 4937 for (dp = str, cp = str+1; cp < np; ) {
4857 4938 *dp++ = *cp++;
4858 4939 }
4859 4940 cp++;
4860 4941 while (*cp)
4861 4942 *dp++ = *cp++;
4862 4943 *dp = '\0';
4863 4944
4864 4945 /* re-start test at original ( */
4865 4946 parens--;
4866 4947 str--;
4867 4948 break;
4868 4949
4869 4950 default:
4870 4951 balance = 1;
4871 4952 escape = 0;
4872 4953 next = str;
4873 4954 while (*next && balance) {
4874 4955 if (escape == 0) {
4875 4956 if (*next == '(')
4876 4957 balance++;
4877 4958 else if (*next == ')')
4878 4959 balance--;
4879 4960 }
4880 4961 if (*next == '\\' && ! escape)
4881 4962 escape = 1;
4882 4963 else
4883 4964 escape = 0;
4884 4965 if (balance)
4885 4966 next++;
4886 4967 }
4887 4968 if (balance != 0)
4888 4969 return (-1);
4889 4970
4890 4971 *next = '\0';
4891 4972 if (adj_simple_filter(str) == -1) {
4892 4973 return (-1);
4893 4974 }
4894 4975 next = resync_str(str, next, ')');
4895 4976 next++;
4896 4977 str = next;
4897 4978 parens--;
4898 4979 break;
4899 4980 }
4900 4981 break;
4901 4982
4902 4983 case ')':
4903 4984 str++;
4904 4985 parens--;
4905 4986 break;
4906 4987
4907 4988 case ' ':
4908 4989 str++;
4909 4990 break;
4910 4991
4911 4992 default: /* assume it's a simple type=value filter */
4912 4993 next = strchr(str, '\0');
4913 4994 if (adj_simple_filter(str) == -1) {
4914 4995 return (-1);
4915 4996 }
4916 4997 str = next;
4917 4998 break;
4918 4999 }
4919 5000 }
4920 5001
4921 5002 return (parens ? -1 : 0);
4922 5003 }
4923 5004
4924 5005
4925 5006 /*
4926 5007 * Put a list of filters like this "(filter1)(filter2)..."
4927 5008 */
4928 5009
4929 5010 static int
4930 5011 adj_filter_list(char *str)
4931 5012 {
4932 5013 char *next;
4933 5014 char save;
4934 5015
4935 5016 while (*str) {
4936 5017 while (*str && isspace(*str))
4937 5018 str++;
4938 5019 if (*str == '\0')
4939 5020 break;
4940 5021
4941 5022 if ((next = find_right_paren(str + 1)) == NULL)
4942 5023 return (-1);
4943 5024 save = *++next;
4944 5025
4945 5026 /* now we have "(filter)" with str pointing to it */
4946 5027 *next = '\0';
4947 5028 if (adj_filter(str) == -1)
4948 5029 return (-1);
4949 5030 next = resync_str(str, next, save);
4950 5031
4951 5032 str = next;
4952 5033 }
4953 5034
4954 5035 return (0);
4955 5036 }
4956 5037
4957 5038
4958 5039 /*
4959 5040 * is_valid_attr - returns 1 if a is a syntactically valid left-hand side
4960 5041 * of a filter expression, 0 otherwise. A valid string may contain only
4961 5042 * letters, numbers, hyphens, semi-colons, colons and periods. examples:
4962 5043 * cn
4963 5044 * cn;lang-fr
4964 5045 * 1.2.3.4;binary;dynamic
4965 5046 * mail;dynamic
4966 5047 * cn:dn:1.2.3.4
4967 5048 *
4968 5049 * For compatibility with older servers, we also allow underscores in
4969 5050 * attribute types, even through they are not allowed by the LDAPv3 RFCs.
4970 5051 */
4971 5052 static int
4972 5053 is_valid_attr(char *a)
4973 5054 {
4974 5055 for (; *a; a++) {
4975 5056 if (!isascii(*a)) {
4976 5057 return (0);
4977 5058 } else if (!isalnum(*a)) {
4978 5059 switch (*a) {
4979 5060 case '-':
4980 5061 case '.':
4981 5062 case ';':
4982 5063 case ':':
4983 5064 case '_':
4984 5065 break; /* valid */
4985 5066 default:
4986 5067 return (0);
4987 5068 }
4988 5069 }
4989 5070 }
4990 5071 return (1);
4991 5072 }
4992 5073
4993 5074 static char *
4994 5075 find_star(char *s)
4995 5076 {
4996 5077 for (; *s; ++s) {
4997 5078 switch (*s) {
4998 5079 case '*':
4999 5080 return (s);
5000 5081 case '\\':
5001 5082 ++s;
5002 5083 if (hexchar2int(s[0]) >= 0 && hexchar2int(s[1]) >= 0)
5003 5084 ++s;
5004 5085 default:
5005 5086 break;
5006 5087 }
5007 5088 }
5008 5089 return (NULL);
5009 5090 }
5010 5091
5011 5092 static int
5012 5093 adj_simple_filter(char *str)
5013 5094 {
5014 5095 char *s, *s2, *s3, filterop;
5015 5096 char *value;
5016 5097 int ftype = 0;
5017 5098 int rc;
5018 5099
5019 5100 rc = -1; /* pessimistic */
5020 5101
5021 5102 if ((str = strdup(str)) == NULL) {
5022 5103 return (rc);
5023 5104 }
5024 5105
5025 5106 if ((s = strchr(str, '=')) == NULL) {
5026 5107 goto free_and_return;
5027 5108 }
5028 5109 value = s + 1;
5029 5110 *s-- = '\0';
5030 5111 filterop = *s;
5031 5112 if (filterop == '<' || filterop == '>' || filterop == '~' ||
5032 5113 filterop == ':') {
5033 5114 *s = '\0';
5034 5115 }
5035 5116
5036 5117 if (! is_valid_attr(str)) {
5037 5118 goto free_and_return;
5038 5119 }
5039 5120
5040 5121 switch (filterop) {
5041 5122 case '<': /* LDAP_FILTER_LE */
5042 5123 case '>': /* LDAP_FILTER_GE */
5043 5124 case '~': /* LDAP_FILTER_APPROX */
5044 5125 break;
5045 5126 case ':': /* extended filter - v3 only */
5046 5127 /*
5047 5128 * extended filter looks like this:
5048 5129 *
5049 5130 * [type][':dn'][':'oid]':='value
5050 5131 *
5051 5132 * where one of type or :oid is required.
5052 5133 *
5053 5134 */
5054 5135 s2 = s3 = NULL;
5055 5136 if ((s2 = strrchr(str, ':')) == NULL) {
5056 5137 goto free_and_return;
5057 5138 }
5058 5139 if (strcasecmp(s2, ":dn") == 0) {
5059 5140 *s2 = '\0';
5060 5141 } else {
5061 5142 *s2 = '\0';
5062 5143 if ((s3 = strrchr(str, ':')) != NULL) {
5063 5144 if (strcasecmp(s3, ":dn") != 0) {
5064 5145 goto free_and_return;
5065 5146 }
5066 5147 *s3 = '\0';
5067 5148 }
5068 5149 }
5069 5150 if (unescape_filterval(value) < 0) {
5070 5151 goto free_and_return;
5071 5152 }
5072 5153 rc = 0;
5073 5154 goto free_and_return;
5074 5155 /* break; */
5075 5156 default:
5076 5157 if (find_star(value) == NULL) {
5077 5158 ftype = 0; /* LDAP_FILTER_EQUALITY */
5078 5159 } else if (strcmp(value, "*") == 0) {
5079 5160 ftype = 1; /* LDAP_FILTER_PRESENT */
5080 5161 } else {
5081 5162 rc = adj_substring_filter(value);
5082 5163 goto free_and_return;
5083 5164 }
5084 5165 break;
5085 5166 }
5086 5167
5087 5168 if (ftype != 0) { /* == LDAP_FILTER_PRESENT */
5088 5169 rc = 0;
5089 5170 } else if (unescape_filterval(value) >= 0) {
5090 5171 rc = 0;
5091 5172 }
5092 5173 if (rc != -1) {
5093 5174 rc = 0;
5094 5175 }
5095 5176
5096 5177 free_and_return:
5097 5178 free(str);
5098 5179 return (rc);
5099 5180 }
5100 5181
5101 5182
5102 5183 /*
5103 5184 * Check in place both LDAPv2 (RFC-1960) and LDAPv3 (hexadecimal) escape
5104 5185 * sequences within the null-terminated string 'val'.
5105 5186 *
5106 5187 * If 'val' contains invalid escape sequences we return -1.
5107 5188 * Otherwise return 1
5108 5189 */
5109 5190 static int
5110 5191 unescape_filterval(char *val)
5111 5192 {
5112 5193 int escape, firstdigit;
5113 5194 char *s;
5114 5195
5115 5196 firstdigit = 0;
5116 5197 escape = 0;
5117 5198 for (s = val; *s; s++) {
5118 5199 if (escape) {
5119 5200 /*
5120 5201 * first try LDAPv3 escape (hexadecimal) sequence
5121 5202 */
5122 5203 if (hexchar2int(*s) < 0) {
5123 5204 if (firstdigit) {
5124 5205 /*
5125 5206 * LDAPv2 (RFC1960) escape sequence
5126 5207 */
5127 5208 escape = 0;
5128 5209 } else {
5129 5210 return (-1);
5130 5211 }
5131 5212 }
5132 5213 if (firstdigit) {
5133 5214 firstdigit = 0;
5134 5215 } else {
5135 5216 escape = 0;
5136 5217 }
5137 5218
5138 5219 } else if (*s != '\\') {
5139 5220 escape = 0;
5140 5221
5141 5222 } else {
5142 5223 escape = 1;
5143 5224 firstdigit = 1;
5144 5225 }
5145 5226 }
5146 5227
5147 5228 return (1);
5148 5229 }
5149 5230
5150 5231
5151 5232 /*
5152 5233 * convert character 'c' that represents a hexadecimal digit to an integer.
5153 5234 * if 'c' is not a hexidecimal digit [0-9A-Fa-f], -1 is returned.
5154 5235 * otherwise the converted value is returned.
5155 5236 */
5156 5237 static int
5157 5238 hexchar2int(char c)
5158 5239 {
5159 5240 if (c >= '0' && c <= '9') {
5160 5241 return (c - '0');
5161 5242 }
5162 5243 if (c >= 'A' && c <= 'F') {
5163 5244 return (c - 'A' + 10);
5164 5245 }
5165 5246 if (c >= 'a' && c <= 'f') {
5166 5247 return (c - 'a' + 10);
5167 5248 }
5168 5249 return (-1);
5169 5250 }
5170 5251
5171 5252 static int
5172 5253 adj_substring_filter(char *val)
5173 5254 {
5174 5255 char *nextstar;
5175 5256
5176 5257 for (; val != NULL; val = nextstar) {
5177 5258 if ((nextstar = find_star(val)) != NULL) {
5178 5259 *nextstar++ = '\0';
5179 5260 }
5180 5261
5181 5262 if (*val != '\0') {
5182 5263 if (unescape_filterval(val) < 0) {
5183 5264 return (-1);
5184 5265 }
5185 5266 }
5186 5267 }
5187 5268
5188 5269 return (0);
5189 5270 }
5190 5271
5191 5272 /* ***** End of modified libldap.so.5 filter parser ***** */
5192 5273
5193 5274
5194 5275 /*
5195 5276 * Walk filter, remove redundant parentheses in-line
5196 5277 * verify that the filter is reasonable
5197 5278 */
5198 5279 static int
5199 5280 validate_filter(ns_ldap_cookie_t *cookie)
5200 5281 {
5201 5282 char *filter = cookie->filter;
5202 5283 int rc;
5203 5284
5204 5285 /* Parse filter looking for illegal values */
5205 5286
5206 5287 rc = adj_filter(filter);
5207 5288 if (rc != 0) {
5208 5289 return (NS_LDAP_OP_FAILED);
5209 5290 }
5210 5291
5211 5292 /* end of filter checking */
5212 5293
5213 5294 return (NS_LDAP_SUCCESS);
5214 5295 }
5215 5296
5216 5297 /*
5217 5298 * Set the account management request control that needs to be sent to server.
5218 5299 * This control is required to get the account management information of
5219 5300 * a user to do local account checking.
5220 5301 */
5221 5302 static int
5222 5303 setup_acctmgmt_params(ns_ldap_cookie_t *cookie)
5223 5304 {
5224 5305 LDAPControl *req = NULL, **requestctrls;
5225 5306
5226 5307 req = (LDAPControl *)malloc(sizeof (LDAPControl));
5227 5308
5228 5309 if (req == NULL)
5229 5310 return (NS_LDAP_MEMORY);
5230 5311
5231 5312 /* fill in the fields of this new control */
5232 5313 req->ldctl_iscritical = 1;
5233 5314 req->ldctl_oid = strdup(NS_LDAP_ACCOUNT_USABLE_CONTROL);
5234 5315 if (req->ldctl_oid == NULL) {
5235 5316 free(req);
5236 5317 return (NS_LDAP_MEMORY);
5237 5318 }
5238 5319 req->ldctl_value.bv_len = 0;
5239 5320 req->ldctl_value.bv_val = NULL;
5240 5321
5241 5322 requestctrls = (LDAPControl **)calloc(2, sizeof (LDAPControl *));
5242 5323 if (requestctrls == NULL) {
5243 5324 ldap_control_free(req);
5244 5325 return (NS_LDAP_MEMORY);
5245 5326 }
5246 5327
5247 5328 requestctrls[0] = req;
5248 5329
5249 5330 cookie->p_serverctrls = requestctrls;
5250 5331
5251 5332 return (NS_LDAP_SUCCESS);
5252 5333 }
5253 5334
5254 5335 /*
5255 5336 * int get_new_acct_more_info(BerElement *ber,
5256 5337 * AcctUsableResponse_t *acctResp)
5257 5338 *
5258 5339 * Decode the more_info data from an Account Management control response,
5259 5340 * when the account is not usable and when code style is from recent LDAP
5260 5341 * servers (see below comments for parse_acct_cont_resp_msg() to get more
5261 5342 * details on coding styles and ASN1 description).
5262 5343 *
5263 5344 * Expected BER encoding: {tbtbtbtiti}
5264 5345 * +t: tag is 0
5265 5346 * +b: TRUE if inactive due to account inactivation
5266 5347 * +t: tag is 1
5267 5348 * +b: TRUE if password has been reset
5268 5349 * +t: tag is 2
5269 5350 * +b: TRUE if password is expired
5270 5351 * +t: tag is 3
5271 5352 * +i: contains num of remaining grace, 0 means no grace
5272 5353 * +t: tag is 4
5273 5354 * +i: contains num of seconds before auto-unlock. -1 means acct is locked
5274 5355 * forever (i.e. until reset)
5275 5356 *
5276 5357 * Asumptions:
5277 5358 * - ber is not null
5278 5359 * - acctResp is not null and is initialized with default values for the
5279 5360 * fields in its AcctUsableResp.more_info structure
5280 5361 * - the ber stream is received in the correct order, per the ASN1 description.
5281 5362 * We do not check this order and make the asumption that it is correct.
5282 5363 * Note that the ber stream may not (and will not in most cases) contain
5283 5364 * all fields.
5284 5365 */
5285 5366 static int
5286 5367 get_new_acct_more_info(BerElement *ber, AcctUsableResponse_t *acctResp)
5287 5368 {
5288 5369 int rc = NS_LDAP_SUCCESS;
5289 5370 char errstr[MAXERROR];
5290 5371 ber_tag_t rTag = LBER_DEFAULT;
5291 5372 ber_len_t rLen = 0;
5292 5373 ber_int_t rValue;
5293 5374 char *last;
5294 5375 int berRC = 0;
5295 5376
5296 5377 /*
5297 5378 * Look at what more_info BER element is/are left to be decoded.
5298 5379 * look at each of them 1 by 1, without checking on their order
5299 5380 * and possible multi values.
5300 5381 */
5301 5382 for (rTag = ber_first_element(ber, &rLen, &last);
5302 5383 rTag != LBER_END_OF_SEQORSET;
5303 5384 rTag = ber_next_element(ber, &rLen, last)) {
5304 5385
5305 5386 berRC = 0;
5306 5387 switch (rTag) {
5307 5388 case 0 | LBER_CLASS_CONTEXT | LBER_PRIMITIVE:
5308 5389 /* inactive */
5309 5390 berRC = ber_scanf(ber, "b", &rValue);
5310 5391 if (berRC != LBER_ERROR) {
5311 5392 (acctResp->AcctUsableResp).more_info.
5312 5393 inactive = (rValue != 0) ? 1 : 0;
5313 5394 }
5314 5395 break;
5315 5396
5316 5397 case 1 | LBER_CLASS_CONTEXT | LBER_PRIMITIVE:
5317 5398 /* reset */
5318 5399 berRC = ber_scanf(ber, "b", &rValue);
5319 5400 if (berRC != LBER_ERROR) {
5320 5401 (acctResp->AcctUsableResp).more_info.reset
5321 5402 = (rValue != 0) ? 1 : 0;
5322 5403 }
5323 5404 break;
5324 5405
5325 5406 case 2 | LBER_CLASS_CONTEXT | LBER_PRIMITIVE:
5326 5407 /* expired */
5327 5408 berRC = ber_scanf(ber, "b", &rValue);
5328 5409 if (berRC != LBER_ERROR) {
5329 5410 (acctResp->AcctUsableResp).more_info.expired
5330 5411 = (rValue != 0) ? 1 : 0;
5331 5412 }
5332 5413 break;
5333 5414
5334 5415 case 3 | LBER_CLASS_CONTEXT | LBER_PRIMITIVE:
5335 5416 /* remaining grace */
5336 5417 berRC = ber_scanf(ber, "i", &rValue);
5337 5418 if (berRC != LBER_ERROR) {
5338 5419 (acctResp->AcctUsableResp).more_info.rem_grace
5339 5420 = rValue;
5340 5421 }
5341 5422 break;
5342 5423
5343 5424 case 4 | LBER_CLASS_CONTEXT | LBER_PRIMITIVE:
5344 5425 /* seconds before unlock */
5345 5426 berRC = ber_scanf(ber, "i", &rValue);
5346 5427 if (berRC != LBER_ERROR) {
5347 5428 (acctResp->AcctUsableResp).more_info.
5348 5429 sec_b4_unlock = rValue;
5349 5430 }
5350 5431 break;
5351 5432
5352 5433 default :
5353 5434 (void) sprintf(errstr,
5354 5435 gettext("invalid reason tag 0x%x"), rTag);
5355 5436 syslog(LOG_DEBUG, "libsldap: %s", errstr);
5356 5437 rc = NS_LDAP_INTERNAL;
5357 5438 break;
5358 5439 }
5359 5440 if (berRC == LBER_ERROR) {
5360 5441 (void) sprintf(errstr,
5361 5442 gettext("error 0x%x decoding value for "
5362 5443 "tag 0x%x"), berRC, rTag);
5363 5444 syslog(LOG_DEBUG, "libsldap: %s", errstr);
5364 5445 rc = NS_LDAP_INTERNAL;
5365 5446 }
5366 5447 if (rc != NS_LDAP_SUCCESS) {
5367 5448 /* exit the for loop */
5368 5449 break;
5369 5450 }
5370 5451 }
5371 5452
5372 5453 return (rc);
5373 5454 }
5374 5455
5375 5456 /*
5376 5457 * int get_old_acct_opt_more_info(BerElement *ber,
5377 5458 * AcctUsableResponse_t *acctResp)
5378 5459 *
5379 5460 * Decode the optional more_info data from an Account Management control
5380 5461 * response, when the account is not usable and when code style is from LDAP
5381 5462 * server 5.2p4 (see below comments for parse_acct_cont_resp_msg() to get more
5382 5463 * details on coding styles and ASN1 description).
5383 5464 *
5384 5465 * Expected BER encoding: titi}
5385 5466 * +t: tag is 2
5386 5467 * +i: contains num of remaining grace, 0 means no grace
5387 5468 * +t: tag is 3
5388 5469 * +i: contains num of seconds before auto-unlock. -1 means acct is locked
5389 5470 * forever (i.e. until reset)
5390 5471 *
5391 5472 * Asumptions:
5392 5473 * - ber is a valid BER element
5393 5474 * - acctResp is initialized for the fields in its AcctUsableResp.more_info
5394 5475 * structure
5395 5476 */
5396 5477 static int
5397 5478 get_old_acct_opt_more_info(ber_tag_t tag, BerElement *ber,
5398 5479 AcctUsableResponse_t *acctResp)
5399 5480 {
5400 5481 int rc = NS_LDAP_SUCCESS;
5401 5482 char errstr[MAXERROR];
5402 5483 ber_len_t len;
5403 5484 int rem_grace, sec_b4_unlock;
5404 5485
5405 5486 switch (tag) {
5406 5487 case 2:
5407 5488 /* decode and maybe 3 is following */
5408 5489 if ((tag = ber_scanf(ber, "i", &rem_grace)) == LBER_ERROR) {
5409 5490 (void) sprintf(errstr, gettext("Can not get "
5410 5491 "rem_grace"));
5411 5492 syslog(LOG_DEBUG, "libsldap: %s", errstr);
5412 5493 rc = NS_LDAP_INTERNAL;
5413 5494 break;
5414 5495 }
5415 5496 (acctResp->AcctUsableResp).more_info.rem_grace = rem_grace;
5416 5497
5417 5498 if ((tag = ber_peek_tag(ber, &len)) == LBER_ERROR) {
5418 5499 /* this is a success case, break to exit */
5419 5500 (void) sprintf(errstr, gettext("No more "
5420 5501 "optional data"));
5421 5502 syslog(LOG_DEBUG, "libsldap: %s", errstr);
5422 5503 break;
5423 5504 }
5424 5505
5425 5506 if (tag == 3) {
5426 5507 if (ber_scanf(ber, "i", &sec_b4_unlock) == LBER_ERROR) {
5427 5508 (void) sprintf(errstr,
5428 5509 gettext("Can not get sec_b4_unlock "
5429 5510 "- 1st case"));
5430 5511 syslog(LOG_DEBUG, "libsldap: %s", errstr);
5431 5512 rc = NS_LDAP_INTERNAL;
5432 5513 break;
5433 5514 }
5434 5515 (acctResp->AcctUsableResp).more_info.sec_b4_unlock =
5435 5516 sec_b4_unlock;
5436 5517 } else { /* unknown tag */
5437 5518 (void) sprintf(errstr, gettext("Unknown tag "
5438 5519 "- 1st case"));
5439 5520 syslog(LOG_DEBUG, "libsldap: %s", errstr);
5440 5521 rc = NS_LDAP_INTERNAL;
5441 5522 break;
5442 5523 }
5443 5524 break;
5444 5525
5445 5526 case 3:
5446 5527 if (ber_scanf(ber, "i", &sec_b4_unlock) == LBER_ERROR) {
5447 5528 (void) sprintf(errstr, gettext("Can not get "
5448 5529 "sec_b4_unlock - 2nd case"));
5449 5530 syslog(LOG_DEBUG, "libsldap: %s", errstr);
5450 5531 rc = NS_LDAP_INTERNAL;
5451 5532 break;
5452 5533 }
5453 5534 (acctResp->AcctUsableResp).more_info.sec_b4_unlock =
5454 5535 sec_b4_unlock;
5455 5536 break;
5456 5537
5457 5538 default: /* unknown tag */
5458 5539 (void) sprintf(errstr, gettext("Unknown tag - 2nd case"));
5459 5540 syslog(LOG_DEBUG, "libsldap: %s", errstr);
5460 5541 rc = NS_LDAP_INTERNAL;
5461 5542 break;
5462 5543 }
5463 5544
5464 5545 return (rc);
5465 5546 }
5466 5547
5467 5548 /*
5468 5549 * **** This function needs to be moved to libldap library ****
5469 5550 * parse_acct_cont_resp_msg() parses the message received by server according to
5470 5551 * following format (ASN1 notation):
5471 5552 *
5472 5553 * ACCOUNT_USABLE_RESPONSE::= CHOICE {
5473 5554 * is_available [0] INTEGER,
5474 5555 * ** seconds before expiration **
5475 5556 * is_not_available [1] more_info
5476 5557 * }
5477 5558 * more_info::= SEQUENCE {
5478 5559 * inactive [0] BOOLEAN DEFAULT FALSE,
5479 5560 * reset [1] BOOLEAN DEFAULT FALSE,
5480 5561 * expired [2] BOOLEAN DEFAULT FALSE,
5481 5562 * remaining_grace [3] INTEGER OPTIONAL,
5482 5563 * seconds_before_unlock [4] INTEGER OPTIONAL
5483 5564 * }
5484 5565 */
5485 5566 /*
5486 5567 * #define used to make the difference between coding style as done
5487 5568 * by LDAP server 5.2p4 and newer LDAP servers. There are 4 values:
5488 5569 * - DS52p4_USABLE: 5.2p4 coding style, account is usable
5489 5570 * - DS52p4_NOT_USABLE: 5.2p4 coding style, account is not usable
5490 5571 * - NEW_USABLE: newer LDAP servers coding style, account is usable
5491 5572 * - NEW_NOT_USABLE: newer LDAP servers coding style, account is not usable
5492 5573 *
5493 5574 * An account would be considered not usable if for instance:
5494 5575 * - it's been made inactive in the LDAP server
5495 5576 * - or its password was reset in the LDAP server database
5496 5577 * - or its password expired
5497 5578 * - or the account has been locked, possibly forever
5498 5579 */
5499 5580 #define DS52p4_USABLE 0x00
5500 5581 #define DS52p4_NOT_USABLE 0x01
5501 5582 #define NEW_USABLE 0x00 | LBER_CLASS_CONTEXT | LBER_PRIMITIVE
5502 5583 #define NEW_NOT_USABLE 0x01 | LBER_CLASS_CONTEXT | LBER_CONSTRUCTED
5503 5584 static int
5504 5585 parse_acct_cont_resp_msg(LDAPControl **ectrls, AcctUsableResponse_t *acctResp)
5505 5586 {
5506 5587 int rc = NS_LDAP_SUCCESS;
5507 5588 BerElement *ber;
5508 5589 ber_tag_t tag;
5509 5590 ber_len_t len;
5510 5591 int i;
5511 5592 char errstr[MAXERROR];
5512 5593 /* used for any coding style when account is usable */
5513 5594 int seconds_before_expiry;
5514 5595 /* used for 5.2p4 coding style when account is not usable */
5515 5596 int inactive, reset, expired;
5516 5597
5517 5598 if (ectrls == NULL) {
5518 5599 (void) sprintf(errstr, gettext("Invalid ectrls parameter"));
5519 5600 syslog(LOG_DEBUG, "libsldap: %s", errstr);
5520 5601 return (NS_LDAP_INVALID_PARAM);
5521 5602 }
5522 5603
5523 5604 for (i = 0; ectrls[i] != NULL; i++) {
5524 5605 if (strcmp(ectrls[i]->ldctl_oid, NS_LDAP_ACCOUNT_USABLE_CONTROL)
5525 5606 == 0) {
5526 5607 break;
5527 5608 }
5528 5609 }
5529 5610
5530 5611 if (ectrls[i] == NULL) {
5531 5612 /* Ldap control is not found */
5532 5613 (void) sprintf(errstr, gettext("Account Usable Control "
5533 5614 "not found"));
5534 5615 syslog(LOG_DEBUG, "libsldap: %s", errstr);
5535 5616 return (NS_LDAP_NOTFOUND);
5536 5617 }
5537 5618
5538 5619 /* Allocate a BER element from the control value and parse it. */
5539 5620 if ((ber = ber_init(&ectrls[i]->ldctl_value)) == NULL)
5540 5621 return (NS_LDAP_MEMORY);
5541 5622
5542 5623 if ((tag = ber_peek_tag(ber, &len)) == LBER_ERROR) {
5543 5624 /* Ldap decoding error */
5544 5625 (void) sprintf(errstr, gettext("Error decoding 1st tag"));
5545 5626 syslog(LOG_DEBUG, "libsldap: %s", errstr);
5546 5627 ber_free(ber, 1);
5547 5628 return (NS_LDAP_INTERNAL);
5548 5629 }
5549 5630
5550 5631 switch (tag) {
5551 5632 case DS52p4_USABLE:
5552 5633 case NEW_USABLE:
5553 5634 acctResp->choice = 0;
5554 5635 if (ber_scanf(ber, "i", &seconds_before_expiry)
5555 5636 == LBER_ERROR) {
5556 5637 /* Ldap decoding error */
5557 5638 (void) sprintf(errstr, gettext("Can not get "
5558 5639 "seconds_before_expiry"));
5559 5640 syslog(LOG_DEBUG, "libsldap: %s", errstr);
5560 5641 rc = NS_LDAP_INTERNAL;
5561 5642 break;
5562 5643 }
5563 5644 /* ber_scanf() succeeded */
5564 5645 (acctResp->AcctUsableResp).seconds_before_expiry =
5565 5646 seconds_before_expiry;
5566 5647 break;
5567 5648
5568 5649 case DS52p4_NOT_USABLE:
5569 5650 acctResp->choice = 1;
5570 5651 if (ber_scanf(ber, "{bbb", &inactive, &reset, &expired)
5571 5652 == LBER_ERROR) {
5572 5653 /* Ldap decoding error */
5573 5654 (void) sprintf(errstr, gettext("Can not get "
5574 5655 "inactive/reset/expired"));
5575 5656 syslog(LOG_DEBUG, "libsldap: %s", errstr);
5576 5657 rc = NS_LDAP_INTERNAL;
5577 5658 break;
5578 5659 }
5579 5660 /* ber_scanf() succeeded */
5580 5661 (acctResp->AcctUsableResp).more_info.inactive =
5581 5662 ((inactive == 0) ? 0 : 1);
5582 5663 (acctResp->AcctUsableResp).more_info.reset =
5583 5664 ((reset == 0) ? 0 : 1);
5584 5665 (acctResp->AcctUsableResp).more_info.expired =
5585 5666 ((expired == 0) ? 0 : 1);
5586 5667 (acctResp->AcctUsableResp).more_info.rem_grace = 0;
5587 5668 (acctResp->AcctUsableResp).more_info.sec_b4_unlock = 0;
5588 5669
5589 5670 if ((tag = ber_peek_tag(ber, &len)) == LBER_ERROR) {
5590 5671 /* this is a success case, break to exit */
5591 5672 (void) sprintf(errstr, gettext("No optional data"));
5592 5673 syslog(LOG_DEBUG, "libsldap: %s", errstr);
5593 5674 break;
5594 5675 }
5595 5676
5596 5677 /*
5597 5678 * Look at what optional more_info BER element is/are
5598 5679 * left to be decoded.
5599 5680 */
5600 5681 rc = get_old_acct_opt_more_info(tag, ber, acctResp);
5601 5682 break;
5602 5683
5603 5684 case NEW_NOT_USABLE:
5604 5685 acctResp->choice = 1;
5605 5686 /*
5606 5687 * Recent LDAP servers won't code more_info data for default
5607 5688 * values (see above comments on ASN1 description for what
5608 5689 * fields have default values & what fields are optional).
5609 5690 */
5610 5691 (acctResp->AcctUsableResp).more_info.inactive = 0;
5611 5692 (acctResp->AcctUsableResp).more_info.reset = 0;
5612 5693 (acctResp->AcctUsableResp).more_info.expired = 0;
5613 5694 (acctResp->AcctUsableResp).more_info.rem_grace = 0;
5614 5695 (acctResp->AcctUsableResp).more_info.sec_b4_unlock = 0;
5615 5696
5616 5697 if (len == 0) {
5617 5698 /*
5618 5699 * Nothing else to decode; this is valid and we
5619 5700 * use default values set above.
5620 5701 */
5621 5702 (void) sprintf(errstr, gettext("more_info is "
5622 5703 "empty, using default values"));
5623 5704 syslog(LOG_DEBUG, "libsldap: %s", errstr);
5624 5705 break;
5625 5706 }
5626 5707
5627 5708 /*
5628 5709 * Look at what more_info BER element is/are left to
5629 5710 * be decoded.
5630 5711 */
5631 5712 rc = get_new_acct_more_info(ber, acctResp);
5632 5713 break;
5633 5714
5634 5715 default:
5635 5716 (void) sprintf(errstr, gettext("unknwon coding style "
5636 5717 "(tag: 0x%x)"), tag);
5637 5718 syslog(LOG_DEBUG, "libsldap: %s", errstr);
5638 5719 rc = NS_LDAP_INTERNAL;
5639 5720 break;
5640 5721 }
5641 5722
5642 5723 ber_free(ber, 1);
5643 5724 return (rc);
5644 5725 }
5645 5726
5646 5727 /*
5647 5728 * internal function for __ns_ldap_getAcctMgmt()
5648 5729 */
5649 5730 static int
5650 5731 getAcctMgmt(const char *user, AcctUsableResponse_t *acctResp,
5651 5732 ns_conn_user_t *conn_user)
5652 5733 {
5653 5734 int scope, rc;
5654 5735 char ldapfilter[1024];
5655 5736 ns_ldap_cookie_t *cookie;
5656 5737 ns_ldap_search_desc_t **sdlist = NULL;
5657 5738 ns_ldap_search_desc_t *dptr;
5658 5739 ns_ldap_error_t *error = NULL;
5659 5740 char **dns = NULL;
5660 5741 char service[] = "shadow";
5661 5742
5662 5743 if (user == NULL || acctResp == NULL)
5663 5744 return (NS_LDAP_INVALID_PARAM);
5664 5745
5665 5746 /* Initialize State machine cookie */
5666 5747 cookie = init_search_state_machine();
5667 5748 if (cookie == NULL)
5668 5749 return (NS_LDAP_MEMORY);
5669 5750 cookie->conn_user = conn_user;
5670 5751
5671 5752 /* see if need to follow referrals */
5672 5753 rc = __s_api_toFollowReferrals(0,
5673 5754 &cookie->followRef, &error);
5674 5755 if (rc != NS_LDAP_SUCCESS) {
5675 5756 (void) __ns_ldap_freeError(&error);
5676 5757 goto out;
5677 5758 }
5678 5759
5679 5760 /* get the service descriptor - or create a default one */
5680 5761 rc = __s_api_get_SSD_from_SSDtoUse_service(service,
5681 5762 &sdlist, &error);
5682 5763 if (rc != NS_LDAP_SUCCESS) {
5683 5764 (void) __ns_ldap_freeError(&error);
5684 5765 goto out;
5685 5766 }
5686 5767
5687 5768 if (sdlist == NULL) {
5688 5769 /* Create default service Desc */
5689 5770 sdlist = (ns_ldap_search_desc_t **)calloc(2,
5690 5771 sizeof (ns_ldap_search_desc_t *));
5691 5772 if (sdlist == NULL) {
5692 5773 rc = NS_LDAP_MEMORY;
5693 5774 goto out;
5694 5775 }
5695 5776 dptr = (ns_ldap_search_desc_t *)
5696 5777 calloc(1, sizeof (ns_ldap_search_desc_t));
5697 5778 if (dptr == NULL) {
5698 5779 free(sdlist);
5699 5780 rc = NS_LDAP_MEMORY;
5700 5781 goto out;
5701 5782 }
5702 5783 sdlist[0] = dptr;
5703 5784
5704 5785 /* default base */
5705 5786 rc = __s_api_getDNs(&dns, service, &cookie->errorp);
5706 5787 if (rc != NS_LDAP_SUCCESS) {
5707 5788 if (dns) {
5708 5789 __s_api_free2dArray(dns);
5709 5790 dns = NULL;
5710 5791 }
5711 5792 (void) __ns_ldap_freeError(&(cookie->errorp));
5712 5793 cookie->errorp = NULL;
5713 5794 goto out;
5714 5795 }
5715 5796 dptr->basedn = strdup(dns[0]);
5716 5797 if (dptr->basedn == NULL) {
5717 5798 free(sdlist);
5718 5799 free(dptr);
5719 5800 if (dns) {
5720 5801 __s_api_free2dArray(dns);
5721 5802 dns = NULL;
5722 5803 }
5723 5804 rc = NS_LDAP_MEMORY;
5724 5805 goto out;
5725 5806 }
5726 5807 __s_api_free2dArray(dns);
5727 5808 dns = NULL;
5728 5809
5729 5810 /* default scope */
5730 5811 scope = 0;
5731 5812 rc = __s_api_getSearchScope(&scope, &cookie->errorp);
5732 5813 dptr->scope = scope;
5733 5814 }
5734 5815
5735 5816 cookie->sdlist = sdlist;
5736 5817
5737 5818 cookie->service = strdup(service);
5738 5819 if (cookie->service == NULL) {
5739 5820 rc = NS_LDAP_MEMORY;
5740 5821 goto out;
5741 5822 }
5742 5823
5743 5824 /* search for entries for this particular uid */
5744 5825 (void) snprintf(ldapfilter, sizeof (ldapfilter), "(uid=%s)", user);
5745 5826 cookie->i_filter = strdup(ldapfilter);
5746 5827 if (cookie->i_filter == NULL) {
5747 5828 rc = NS_LDAP_MEMORY;
5748 5829 goto out;
5749 5830 }
5750 5831
5751 5832 /* create the control request */
5752 5833 if ((rc = setup_acctmgmt_params(cookie)) != NS_LDAP_SUCCESS)
5753 5834 goto out;
5754 5835
5755 5836 /* Process search */
5756 5837 rc = search_state_machine(cookie, GET_ACCT_MGMT_INFO, 0);
5757 5838
5758 5839 /* Copy results back to user */
5759 5840 rc = cookie->err_rc;
5760 5841 if (rc != NS_LDAP_SUCCESS)
5761 5842 (void) __ns_ldap_freeError(&(cookie->errorp));
5762 5843
5763 5844 if (cookie->result == NULL)
5764 5845 goto out;
5765 5846
5766 5847 if ((rc = parse_acct_cont_resp_msg(cookie->resultctrl, acctResp))
5767 5848 != NS_LDAP_SUCCESS)
5768 5849 goto out;
5769 5850
5770 5851 rc = NS_LDAP_SUCCESS;
5771 5852
5772 5853 out:
5773 5854 delete_search_cookie(cookie);
5774 5855
5775 5856 return (rc);
5776 5857 }
5777 5858
5778 5859 /*
5779 5860 * __ns_ldap_getAcctMgmt() is called from pam account management stack
5780 5861 * for retrieving accounting information of users with no user password -
5781 5862 * eg. rlogin, rsh, etc. This function uses the account management control
5782 5863 * request to do a search on the server for the user in question. The
5783 5864 * response control returned from the server is got from the cookie.
5784 5865 * Input params: username of whose account mgmt information is to be got
5785 5866 * pointer to hold the parsed account management information
5786 5867 * Return values: NS_LDAP_SUCCESS on success or appropriate error
5787 5868 * code on failure
5788 5869 */
5789 5870 int
5790 5871 __ns_ldap_getAcctMgmt(const char *user, AcctUsableResponse_t *acctResp)
5791 5872 {
5792 5873 ns_conn_user_t *cu = NULL;
5793 5874 int try_cnt = 0;
5794 5875 int rc = NS_LDAP_SUCCESS;
5795 5876 ns_ldap_error_t *error = NULL;
5796 5877
5797 5878 for (;;) {
5798 5879 if (__s_api_setup_retry_search(&cu, NS_CONN_USER_SEARCH,
5799 5880 &try_cnt, &rc, &error) == 0)
5800 5881 break;
5801 5882 rc = getAcctMgmt(user, acctResp, cu);
5802 5883 }
5803 5884 return (rc);
5804 5885 }
|
↓ open down ↓ |
1560 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX