Print this page
3285 memory leaks in libsldap
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/lib/libsldap/common/ns_standalone.c
+++ new/usr/src/lib/libsldap/common/ns_standalone.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 *
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.
↓ open down ↓ |
14 lines elided |
↑ open up ↑ |
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 2009 Sun Microsystems, Inc. All rights reserved.
23 23 * Use is subject to license terms.
24 24 * Copyright 2012 Milan Jurik. All rights reserved.
25 + * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
25 26 */
26 27
27 28 #define __STANDALONE_MODULE__
28 29
29 30 #include <stdio.h>
30 31 #include <sys/types.h>
31 32 #include <stdlib.h>
32 33 #include <libintl.h>
33 34 #include <string.h>
34 35 #include <ctype.h>
35 36
36 37 #include <sys/stat.h>
37 38 #include <fcntl.h>
38 39 #include <unistd.h>
39 40 #include <syslog.h>
40 41 #include <locale.h>
41 42 #include <errno.h>
42 43 #include <sys/time.h>
43 44
44 45 #include <arpa/inet.h>
45 46 #include <netdb.h>
46 47 #include <strings.h>
47 48
48 49 #include <thread.h>
49 50
50 51 #include <nsswitch.h>
51 52 #include <nss_dbdefs.h>
52 53 #include <nss.h>
53 54
54 55 #include "ns_cache_door.h"
55 56 #include "ns_internal.h"
56 57 #include "ns_connmgmt.h"
57 58
58 59 typedef enum {
59 60 INFO_SERVER_JUST_INITED = -1,
60 61 INFO_SERVER_UNKNOWN = 0,
61 62 INFO_SERVER_CONNECTING = 1,
62 63 INFO_SERVER_UP = 2,
63 64 INFO_SERVER_ERROR = 3,
64 65 INFO_SERVER_REMOVED = 4
65 66 } dir_server_status_t;
66 67
67 68 typedef enum {
68 69 INFO_STATUS_NEW = 2,
69 70 INFO_STATUS_OLD = 3
70 71 } dir_server_info_t;
71 72
72 73 typedef struct dir_server {
73 74 char *ip;
74 75 char **controls;
75 76 char **saslMech;
76 77 dir_server_status_t status;
77 78 mutex_t updateStatus;
78 79 dir_server_info_t info;
79 80 } dir_server_t;
80 81
81 82 typedef struct dir_server_list {
82 83 dir_server_t **nsServers;
83 84
84 85 rwlock_t listDestroyLock;
85 86 } dir_server_list_t;
86 87
87 88 struct {
88 89 /* The local list of the directory servers' root DSEs. */
89 90 dir_server_list_t *list;
90 91 /* The flag indicating if libsldap is in the 'Standalone' mode. */
91 92 int standalone;
92 93 /*
93 94 * The mutex ensuring that only one thread performs
94 95 * the initialization of the list.
95 96 */
96 97 mutex_t listReplaceLock;
97 98 /*
98 99 * A flag indicating that a particular thread is
99 100 * in the 'ldap_cachemgr' mode. It is stored by thread as
100 101 * a thread specific data.
101 102 */
102 103 const int initFlag;
103 104 /*
104 105 * A thread specific key storing
105 106 * the the 'ldap_cachemgr' mode indicator.
106 107 */
107 108 thread_key_t standaloneInitKey;
108 109 } dir_servers = {NULL, 0, DEFAULTMUTEX, '1'};
109 110
110 111 typedef struct switchDatabase {
111 112 char *conf;
112 113 uint32_t alloced;
113 114 } switch_database_t;
114 115
115 116 static thread_key_t switchConfigKey;
116 117
117 118 #pragma init(createStandaloneKey)
118 119
119 120 #define DONT_INCLUDE_ATTR_NAMES 0
120 121 #define INCLUDE_ATTR_NAMES 1
121 122 #define IS_PROFILE 1
122 123 #define NOT_PROFILE 0
123 124 /* INET6_ADDRSTRLEN + ":" + <5-digit port> + some round-up */
124 125 #define MAX_HOSTADDR_LEN (INET6_ADDRSTRLEN + 6 + 12)
125 126
126 127 static
127 128 void
128 129 switch_conf_disposer(void *data)
129 130 {
130 131 switch_database_t *localData = (switch_database_t *)data;
131 132
132 133 free(localData->conf);
133 134 free(localData);
134 135 }
135 136
136 137 /*
137 138 * This function initializes an indication that a thread obtaining a root DSE
138 139 * will be switched to the 'ldap_cachemgr' mode. Within the thread libsldap
139 140 * will not invoke the __s_api_requestServer function. Instead, the library
140 141 * will establish a connection to the server specified by
141 142 * the __ns_ldap_getRootDSE function.
142 143 * Since ldap_cachmgr can obtain a DUAProfile and root DSEs at the same time
143 144 * and we do not want to affect a thread obtaining a DUAProfile,
144 145 * the 'ldap_cachemgr' mode is thread private.
145 146 * In addition, this function creates a key holding temporary configuration
146 147 * for the "hosts" and "ipnodes" databases which is used by the "SKIPDB"
147 148 * mechanism (__s_api_ip2hostname() & _s_api_hostname2ip()).
148 149 */
149 150 static
150 151 void
151 152 createStandaloneKey()
152 153 {
153 154 if (thr_keycreate(&dir_servers.standaloneInitKey, NULL) != 0) {
154 155 syslog(LOG_ERR, gettext("libsldap: unable to create a thread "
155 156 "key needed for sharing ldap connections"));
156 157 }
157 158 if (thr_keycreate(&switchConfigKey, switch_conf_disposer) != 0) {
158 159 syslog(LOG_ERR, gettext("libsldap: unable to create a thread "
159 160 "key containing current nsswitch configuration"));
160 161 }
161 162 }
162 163
163 164 /*
164 165 * This function sets the 'ldap_cachemgr' mode indication.
165 166 */
166 167 void
167 168 __s_api_setInitMode()
168 169 {
169 170 (void) thr_setspecific(dir_servers.standaloneInitKey,
170 171 (void *) &dir_servers.initFlag);
171 172 }
172 173
173 174 /*
174 175 * This function unset the 'ldap_cachemgr' mode indication.
175 176 */
176 177 void
177 178 __s_api_unsetInitMode()
178 179 {
179 180 (void) thr_setspecific(dir_servers.standaloneInitKey, NULL);
180 181 }
181 182
182 183 /*
183 184 * This function checks if the 'ldap_cachemgr' mode indication is set.
184 185 */
185 186 int
186 187 __s_api_isInitializing() {
187 188 int *flag = NULL;
188 189
189 190 (void) thr_getspecific(dir_servers.standaloneInitKey, (void **) &flag);
190 191
191 192 return (flag != NULL && *flag == dir_servers.initFlag);
192 193 }
193 194
194 195 /*
195 196 * This function checks if the process runs in the 'Standalone' mode.
196 197 * In this mode libsldap will check the local, process private list of root DSEs
197 198 * instead of requesting them via a door call to ldap_cachemgr.
198 199 */
199 200 int
200 201 __s_api_isStandalone()
201 202 {
202 203 int mode;
203 204
204 205 (void) mutex_lock(&dir_servers.listReplaceLock);
205 206 mode = dir_servers.standalone;
206 207 (void) mutex_unlock(&dir_servers.listReplaceLock);
207 208
208 209 return (mode);
209 210 }
210 211
211 212
212 213 static
213 214 int
214 215 remove_ldap(char *dst, char *src, int dst_buf_len)
215 216 {
216 217 int i = 0;
217 218
218 219 if (strlen(src) >= dst_buf_len)
219 220 return (0);
220 221
221 222 while (*src != '\0') {
222 223 /* Copy up to one space from source. */
223 224 if (isspace(*src)) {
224 225 dst[i++] = *src;
225 226 while (isspace(*src))
226 227 src++;
227 228 }
228 229
229 230 /* If not "ldap", just copy. */
230 231 if (strncmp(src, "ldap", 4) != 0) {
231 232 while (!isspace(*src)) {
232 233 dst[i++] = *src++;
233 234 /* At the end of string? */
234 235 if (dst[i-1] == '\0')
235 236 return (1);
236 237 }
237 238 /* Copy up to one space from source. */
238 239 if (isspace(*src)) {
239 240 dst[i++] = *src;
240 241 while (isspace(*src))
241 242 src++;
242 243 }
243 244 /* Copy also the criteria section */
244 245 if (*src == '[')
245 246 while (*src != ']') {
246 247 dst[i++] = *src++;
247 248 /* Shouln't happen if format is right */
248 249 if (dst[i-1] == '\0')
249 250 return (1);
250 251 }
251 252 }
252 253
253 254 /* If next part is ldap, skip over it ... */
254 255 if (strncmp(src, "ldap", 4) == 0) {
255 256 if (isspace(*(src+4)) || *(src+4) == '\0') {
256 257 src += 4;
257 258 while (isspace(*src))
258 259 src++;
259 260 if (*src == '[') {
260 261 while (*src++ != ']') {
261 262 /*
262 263 * See comment above about
263 264 * correct format.
264 265 */
265 266 if (*src == '\0') {
266 267 dst[i++] = '\0';
267 268 return (1);
268 269 }
269 270 }
270 271 }
271 272 while (isspace(*src))
272 273 src++;
273 274 }
274 275 }
275 276 if (*src == '\0')
276 277 dst[i++] = '\0';
277 278 }
278 279
279 280 return (1);
280 281 }
281 282
282 283 static
283 284 char *
284 285 get_db(const char *db_name)
285 286 {
286 287 char *ptr;
287 288 switch_database_t *hostService = NULL;
288 289 FILE *fp = fopen(__NSW_CONFIG_FILE, "rF");
289 290 char *linep, line[NSS_BUFSIZ];
290 291
291 292 if (fp == NULL) {
292 293 syslog(LOG_WARNING, gettext("libsldap: can not read %s"),
293 294 __NSW_CONFIG_FILE);
294 295 return (NULL);
295 296 }
296 297
297 298 while ((linep = fgets(line, NSS_BUFSIZ, fp)) != NULL) {
298 299 while (isspace(*linep)) {
299 300 ++linep;
300 301 }
301 302 if (*linep == '#') {
302 303 continue;
303 304 }
304 305 if (strncmp(linep, db_name, strlen(db_name)) != 0) {
305 306 continue;
306 307 }
307 308 if ((linep = strchr(linep, ':')) != NULL) {
308 309 if (linep[strlen(linep) - 1] == '\n') {
309 310 linep[strlen(linep) - 1] = '\0';
310 311 }
311 312
312 313 while (isspace(*++linep))
313 314 ;
314 315
315 316 if ((ptr = strchr(linep, '#')) != NULL) {
316 317 while (--ptr >= linep && isspace(*ptr))
317 318 ;
318 319 *(ptr + 1) = '\0';
319 320 }
320 321
321 322 if (strlen(linep) == 0) {
322 323 continue;
323 324 }
324 325 break;
325 326 }
326 327 }
327 328
328 329 (void) fclose(fp);
329 330
330 331 if (linep == NULL) {
331 332 syslog(LOG_WARNING,
332 333 gettext("libsldap: the %s database "
333 334 "is missing from %s"),
334 335 db_name,
335 336 __NSW_CONFIG_FILE);
336 337 return (NULL);
337 338 }
338 339
339 340 (void) thr_getspecific(switchConfigKey, (void **) &hostService);
340 341 if (hostService == NULL) {
341 342 hostService = calloc(1, sizeof (switch_database_t));
342 343 if (hostService == NULL) {
343 344 return (NULL);
344 345 }
345 346 (void) thr_setspecific(switchConfigKey, hostService);
346 347 }
347 348
348 349 /*
349 350 * In a long-living process threads can perform several
350 351 * getXbyY requests. And the windows between those requests
351 352 * can be long. The nsswitch configuration can change from time
352 353 * to time. So instead of allocating/freeing memory every time
353 354 * the API is called, reallocate memory only when the current
354 355 * configuration for the database being used is longer than
355 356 * the previous one.
356 357 */
357 358 if (strlen(linep) >= hostService->alloced) {
358 359 ptr = (char *)realloc((void *)hostService->conf,
359 360 strlen(linep) + 1);
360 361 if (ptr == NULL) {
361 362 free((void *)hostService->conf);
362 363 hostService->conf = NULL;
363 364 hostService->alloced = 0;
364 365 return (NULL);
365 366 }
366 367 bzero(ptr, strlen(linep) + 1);
367 368 hostService->conf = ptr;
368 369 hostService->alloced = strlen(linep) + 1;
369 370 }
370 371
371 372 if (remove_ldap(hostService->conf, linep, hostService->alloced))
372 373 return (hostService->conf);
373 374 else
374 375 return (NULL);
375 376 }
376 377
377 378 static
378 379 void
379 380 _initf_ipnodes(nss_db_params_t *p)
380 381 {
381 382 char *services = get_db("ipnodes");
382 383
383 384 p->name = NSS_DBNAM_IPNODES;
384 385 p->flags |= NSS_USE_DEFAULT_CONFIG;
385 386 p->default_config = services == NULL ? "" : services;
386 387 }
387 388
388 389 static
389 390 void
390 391 _initf_hosts(nss_db_params_t *p)
391 392 {
392 393 char *services = get_db("hosts");
393 394
394 395 p->name = NSS_DBNAM_HOSTS;
395 396 p->flags |= NSS_USE_DEFAULT_CONFIG;
396 397 p->default_config = services == NULL ? "" : services;
397 398 }
398 399
399 400 /*
400 401 * This function is an analog of the standard gethostbyaddr_r()
401 402 * function with an exception that it removes the 'ldap' back-end
402 403 * (if any) from the host/ipnodes nsswitch's databases and then
403 404 * looks up using remaining back-ends.
404 405 */
405 406 static
406 407 struct hostent *
407 408 _filter_gethostbyaddr_r(const char *addr, int len, int type,
408 409 struct hostent *result, char *buffer, int buflen,
409 410 int *h_errnop)
410 411 {
411 412 DEFINE_NSS_DB_ROOT(db_root_hosts);
412 413 DEFINE_NSS_DB_ROOT(db_root_ipnodes);
413 414 nss_XbyY_args_t arg;
414 415 nss_status_t res;
415 416 int (*str2ent)();
416 417 void (*nss_initf)();
417 418 nss_db_root_t *nss_db_root;
418 419 int dbop;
419 420
420 421 switch (type) {
421 422 case AF_INET:
422 423 str2ent = str2hostent;
423 424 nss_initf = _initf_hosts;
424 425 nss_db_root = &db_root_hosts;
425 426 dbop = NSS_DBOP_HOSTS_BYADDR;
426 427 break;
427 428 case AF_INET6:
428 429 str2ent = str2hostent6;
429 430 nss_initf = _initf_ipnodes;
430 431 nss_db_root = &db_root_ipnodes;
431 432 dbop = NSS_DBOP_IPNODES_BYADDR;
432 433 default:
433 434 return (NULL);
434 435 }
435 436
436 437 NSS_XbyY_INIT(&arg, result, buffer, buflen, str2ent);
437 438
438 439 arg.key.hostaddr.addr = addr;
439 440 arg.key.hostaddr.len = len;
440 441 arg.key.hostaddr.type = type;
441 442 arg.stayopen = 0;
442 443 arg.h_errno = NETDB_SUCCESS;
443 444
444 445 res = nss_search(nss_db_root, nss_initf, dbop, &arg);
445 446 arg.status = res;
446 447 *h_errnop = arg.h_errno;
447 448 return (struct hostent *)NSS_XbyY_FINI(&arg);
448 449 }
449 450
450 451 /*
451 452 * This routine is an analog of gethostbyaddr_r().
452 453 * But in addition __s_api_hostname2ip() performs the "LDAP SKIPDB" activity
453 454 * prior to querying the name services.
454 455 * If the buffer is not big enough to accommodate a returning data,
455 456 * NULL is returned and h_errnop is set to TRY_AGAIN.
456 457 */
457 458 struct hostent *
458 459 __s_api_hostname2ip(const char *name,
459 460 struct hostent *result, char *buffer, int buflen,
460 461 int *h_errnop)
461 462 {
462 463 DEFINE_NSS_DB_ROOT(db_root_ipnodes);
463 464 DEFINE_NSS_DB_ROOT(db_root_hosts);
464 465 nss_XbyY_args_t arg;
465 466 nss_status_t res;
466 467 struct in_addr addr;
467 468 struct in6_addr addr6;
468 469
469 470 if (inet_pton(AF_INET, name, &addr) > 0) {
470 471 if (buflen < strlen(name) + 1 +
471 472 sizeof (char *) * 2 + /* The h_aliases member */
472 473 sizeof (struct in_addr) +
473 474 sizeof (struct in_addr *) * 2) {
474 475 *h_errnop = TRY_AGAIN;
475 476 return (NULL);
476 477 }
477 478
478 479 result->h_addrtype = AF_INET;
479 480 result->h_length = sizeof (struct in_addr);
480 481 (void) strncpy(buffer, name, buflen);
481 482
482 483 result->h_addr_list = (char **)ROUND_UP(
483 484 buffer + strlen(name) + 1,
484 485 sizeof (char *));
485 486 result->h_aliases = (char **)ROUND_UP(result->h_addr_list,
486 487 sizeof (char *));
487 488 result->h_aliases[0] = buffer;
488 489 result->h_aliases[1] = NULL;
489 490 bcopy(&addr,
490 491 buffer + buflen - sizeof (struct in_addr),
491 492 sizeof (struct in_addr));
492 493 result->h_addr_list[0] = buffer + buflen -
493 494 sizeof (struct in_addr);
494 495 result->h_addr_list[1] = NULL;
495 496 result->h_aliases = result->h_addr_list;
496 497 result->h_name = buffer;
497 498
498 499 *h_errnop = NETDB_SUCCESS;
499 500 return (result);
500 501 }
501 502 if (inet_pton(AF_INET6, name, &addr6) > 0) {
502 503 if (buflen < strlen(name) + 1 +
503 504 sizeof (char *) * 2 + /* The h_aliases member */
504 505 sizeof (struct in6_addr) +
505 506 sizeof (struct in6_addr *) * 2) {
506 507 *h_errnop = TRY_AGAIN;
507 508 return (NULL);
508 509 }
509 510
510 511 result->h_addrtype = AF_INET6;
511 512 result->h_length = sizeof (struct in6_addr);
512 513 (void) strncpy(buffer, name, buflen);
513 514
514 515 result->h_addr_list = (char **)ROUND_UP(
515 516 buffer + strlen(name) + 1,
516 517 sizeof (char *));
517 518 result->h_aliases = (char **)ROUND_UP(result->h_addr_list,
518 519 sizeof (char *));
519 520 result->h_aliases[0] = buffer;
520 521 result->h_aliases[1] = NULL;
521 522 bcopy(&addr6,
522 523 buffer + buflen - sizeof (struct in6_addr),
523 524 sizeof (struct in6_addr));
524 525 result->h_addr_list[0] = buffer + buflen -
525 526 sizeof (struct in6_addr);
526 527 result->h_addr_list[1] = NULL;
527 528 result->h_aliases = result->h_addr_list;
528 529 result->h_name = buffer;
529 530
530 531 *h_errnop = NETDB_SUCCESS;
531 532 return (result);
532 533 }
533 534
534 535 NSS_XbyY_INIT(&arg, result, buffer, buflen, str2hostent);
535 536
536 537 arg.key.name = name;
537 538 arg.stayopen = 0;
538 539 arg.h_errno = NETDB_SUCCESS;
539 540
540 541 res = nss_search(&db_root_ipnodes, _initf_ipnodes,
541 542 NSS_DBOP_IPNODES_BYNAME, &arg);
542 543 if (res == NSS_NOTFOUND || res == NSS_UNAVAIL) {
543 544 arg.h_errno = NETDB_SUCCESS;
544 545 res = nss_search(&db_root_hosts, _initf_hosts,
545 546 NSS_DBOP_HOSTS_BYNAME, &arg);
546 547 }
547 548 arg.status = res;
548 549 *h_errnop = arg.h_errno;
549 550 return ((struct hostent *)NSS_XbyY_FINI(&arg));
550 551 }
551 552
552 553 /*
553 554 * Convert an IP to a host name.
554 555 */
555 556 ns_ldap_return_code
556 557 __s_api_ip2hostname(char *ipaddr, char **hostname) {
557 558 struct in_addr in;
558 559 struct in6_addr in6;
559 560 struct hostent *hp = NULL, hostEnt;
560 561 char buffer[NSS_BUFLEN_HOSTS];
561 562 int buflen = NSS_BUFLEN_HOSTS;
562 563 char *start = NULL,
563 564 *end = NULL,
564 565 delim = '\0';
565 566 char *port = NULL,
566 567 *addr = NULL;
567 568 int errorNum = 0,
568 569 len = 0;
569 570
570 571 if (ipaddr == NULL || hostname == NULL)
571 572 return (NS_LDAP_INVALID_PARAM);
572 573 *hostname = NULL;
573 574 if ((addr = strdup(ipaddr)) == NULL)
574 575 return (NS_LDAP_MEMORY);
575 576
576 577 if (addr[0] == '[') {
577 578 /*
578 579 * Assume it's [ipv6]:port
579 580 * Extract ipv6 IP
580 581 */
581 582 start = &addr[1];
582 583 if ((end = strchr(addr, ']')) != NULL) {
583 584 *end = '\0';
584 585 delim = ']';
585 586 if (*(end + 1) == ':')
586 587 /* extract port */
587 588 port = end + 2;
588 589 } else {
589 590 free(addr);
590 591 return (NS_LDAP_INVALID_PARAM);
591 592 }
592 593 } else if ((end = strchr(addr, ':')) != NULL) {
593 594 /* assume it's ipv4:port */
594 595 *end = '\0';
595 596 delim = ':';
596 597 start = addr;
597 598 port = end + 1;
598 599 } else
599 600 /* No port */
600 601 start = addr;
601 602
602 603
603 604 if (inet_pton(AF_INET, start, &in) == 1) {
604 605 /* IPv4 */
605 606 hp = _filter_gethostbyaddr_r((char *)&in,
606 607 sizeof (in.s_addr),
607 608 AF_INET,
608 609 &hostEnt,
609 610 buffer,
610 611 buflen,
611 612 &errorNum);
612 613 if (hp && hp->h_name) {
613 614 /* hostname + '\0' */
614 615 len = strlen(hp->h_name) + 1;
615 616 if (port)
616 617 /* ':' + port */
617 618 len += strlen(port) + 1;
618 619 if ((*hostname = malloc(len)) == NULL) {
619 620 free(addr);
620 621 return (NS_LDAP_MEMORY);
621 622 }
622 623
623 624 if (port)
624 625 (void) snprintf(*hostname, len, "%s:%s",
625 626 hp->h_name, port);
626 627 else
627 628 (void) strlcpy(*hostname, hp->h_name, len);
628 629
629 630 free(addr);
630 631 return (NS_LDAP_SUCCESS);
631 632 } else {
632 633 free(addr);
633 634 return (NS_LDAP_NOTFOUND);
634 635 }
635 636 } else if (inet_pton(AF_INET6, start, &in6) == 1) {
636 637 /* IPv6 */
637 638 hp = _filter_gethostbyaddr_r((char *)&in6,
638 639 sizeof (in6.s6_addr),
639 640 AF_INET6,
640 641 &hostEnt,
641 642 buffer,
642 643 buflen,
643 644 &errorNum);
644 645 if (hp && hp->h_name) {
645 646 /* hostname + '\0' */
646 647 len = strlen(hp->h_name) + 1;
647 648 if (port)
648 649 /* ':' + port */
649 650 len += strlen(port) + 1;
650 651 if ((*hostname = malloc(len)) == NULL) {
651 652 free(addr);
652 653 return (NS_LDAP_MEMORY);
653 654 }
654 655
655 656 if (port)
656 657 (void) snprintf(*hostname, len, "%s:%s",
657 658 hp->h_name, port);
658 659 else
659 660 (void) strlcpy(*hostname, hp->h_name, len);
660 661
661 662 free(addr);
662 663 return (NS_LDAP_SUCCESS);
663 664 } else {
664 665 free(addr);
665 666 return (NS_LDAP_NOTFOUND);
666 667 }
667 668 } else {
668 669 /*
669 670 * A hostname
670 671 * Return it as is
671 672 */
672 673 if (end)
673 674 *end = delim;
674 675 *hostname = addr;
675 676 return (NS_LDAP_SUCCESS);
676 677 }
677 678 }
678 679
679 680 /*
680 681 * This function obtains data returned by an LDAP search request and puts it
681 682 * in a string in the ldap_cachmgr(1) door call format.
682 683 *
683 684 * INPUT:
684 685 * ld - a pointer to an LDAP structure used for a search operation,
685 686 * result_msg - a pointer to an LDAPMessage returned by the search,
686 687 * include_names - if set to INCLUDE_ATTR_NAMES, the output buffer will
687 688 * contain attribute names.
688 689 * Otherwise, only values will be return.
689 690 *
690 691 * OUTPUT:
691 692 * a buffer containing server info in the following format:
692 693 * [<attribute name>=]value [DOORLINESEP [<attribute name>=]value ]...]
693 694 * Should be free'ed by the caller.
694 695 */
695 696 static
696 697 ns_ldap_return_code
697 698 convert_to_door_line(LDAP* ld,
698 699 LDAPMessage *result_msg,
699 700 int include_names,
700 701 int is_profile,
701 702 char **door_line)
702 703 {
703 704 uint32_t total_length = 0, attr_len = 0, i;
704 705 LDAPMessage *e;
705 706 char *a, **vals;
706 707 BerElement *ber;
707 708 int seen_objectclass = 0, rewind = 0;
708 709
709 710 if (!door_line) {
710 711 return (NS_LDAP_INVALID_PARAM);
711 712 }
712 713 *door_line = NULL;
713 714
714 715 if ((e = ldap_first_entry(ld, result_msg)) == NULL) {
715 716 return (NS_LDAP_NOTFOUND);
716 717 }
717 718
718 719 /* calculate length of received data */
719 720 for (a = ldap_first_attribute(ld, e, &ber);
720 721 a != NULL;
721 722 a = ldap_next_attribute(ld, e, ber)) {
722 723
723 724 if ((vals = ldap_get_values(ld, e, a)) != NULL) {
724 725 for (i = 0; vals[i] != NULL; i++) {
725 726 total_length += (include_names ?
726 727 strlen(a) : 0) +
727 728 strlen(vals[i]) +
728 729 strlen(DOORLINESEP) +1;
729 730 }
730 731 ldap_value_free(vals);
731 732 }
732 733 ldap_memfree(a);
733 734 }
734 735 if (ber != NULL) {
735 736 ber_free(ber, 0);
736 737 }
737 738
738 739 if (total_length == 0) {
739 740 return (NS_LDAP_NOTFOUND);
740 741 }
741 742
742 743 /* copy the data */
743 744 /* add 1 for the last '\0' */
744 745 *door_line = (char *)malloc(total_length + 1);
745 746 if (*door_line == NULL) {
746 747 return (NS_LDAP_MEMORY);
747 748 }
748 749
749 750 /* make it an empty string first */
750 751 **door_line = '\0';
751 752 a = ldap_first_attribute(ld, e, &ber);
752 753 while (a != NULL) {
753 754 if (is_profile) {
754 755 /*
755 756 * If we're processing DUAConfigProfile, we need to make
756 757 * sure we put objectclass attribute first.
757 758 * __s_api_create_config_door_str depends on that.
758 759 */
759 760 if (seen_objectclass) {
760 761 if (strcasecmp(a, "objectclass") == 0) {
761 762 /* Skip objectclass now. */
762 763 a = ldap_next_attribute(ld, e, ber);
763 764 continue;
764 765 }
765 766 } else {
766 767 if (strcasecmp(a, "objectclass") == 0) {
767 768 seen_objectclass = 1;
768 769 rewind = 1;
769 770 } else {
770 771 /* Skip all but objectclass first. */
771 772 a = ldap_next_attribute(ld, e, ber);
772 773 continue;
773 774 }
774 775 }
775 776 }
776 777
777 778 if ((vals = ldap_get_values(ld, e, a)) != NULL) {
778 779 for (i = 0; vals[i] != NULL; i++) {
779 780 if (include_names) {
780 781 attr_len += strlen(a);
781 782 }
782 783 attr_len += strlen(vals[i]) +
783 784 strlen(DOORLINESEP) + 2;
784 785 if (include_names) {
785 786 (void) snprintf(*door_line +
786 787 strlen(*door_line),
787 788 attr_len,
788 789 "%s=%s%s",
789 790 a, vals[i],
790 791 DOORLINESEP);
791 792 } else {
792 793 (void) snprintf(*door_line +
793 794 strlen(*door_line),
794 795 attr_len,
795 796 "%s%s",
796 797 vals[i],
797 798 DOORLINESEP);
798 799 }
799 800 }
800 801 ldap_value_free(vals);
801 802 }
802 803 ldap_memfree(a);
803 804
804 805 /* Rewind */
805 806 if (rewind) {
806 807 if (ber != NULL) {
807 808 ber_free(ber, 0);
808 809 }
809 810 a = ldap_first_attribute(ld, e, &ber);
810 811 rewind = 0;
811 812 } else {
812 813 a = ldap_next_attribute(ld, e, ber);
813 814 }
814 815 }
815 816 if (ber != NULL) {
816 817 ber_free(ber, 0);
817 818 }
818 819
819 820 if (e != result_msg) {
820 821 (void) ldap_msgfree(e);
821 822 }
822 823
823 824 return (NS_LDAP_SUCCESS);
824 825 }
825 826
826 827 /*
827 828 * This function looks up the base DN of a directory serving
828 829 * a specified domain name.
829 830 *
830 831 * INPUT:
831 832 * ld - a pointer to an LDAP structure used for the search operation,
832 833 * domain_name - the name of a domain.
833 834 *
834 835 * OUTPUT:
835 836 * a buffer containing a directory's base DN found.
836 837 * Should be free'ed by the caller.
837 838 */
838 839 static
839 840 ns_ldap_return_code
840 841 getDirBaseDN(LDAP *ld, const char *domain_name, char **dir_base_dn)
841 842 {
842 843 struct timeval tv = {NS_DEFAULT_SEARCH_TIMEOUT, 0};
843 844 char *attrs[2], *DNlist, *rest, *ptr;
844 845 char filter[BUFSIZ], *a = NULL;
845 846 int ldap_rc;
846 847 LDAPMessage *resultMsg = NULL;
847 848 ns_ldap_return_code ret_code;
848 849
849 850 /* Get the whole list of naming contexts residing on the server */
850 851 attrs[0] = "namingcontexts";
851 852 attrs[1] = NULL;
852 853 ldap_rc = ldap_search_ext_s(ld, "", LDAP_SCOPE_BASE, "(objectclass=*)",
853 854 attrs, 0, NULL, NULL, &tv, 0, &resultMsg);
854 855 switch (ldap_rc) {
855 856 /* If successful, the root DSE was found. */
856 857 case LDAP_SUCCESS:
857 858 break;
858 859 /*
859 860 * If the root DSE was not found, the server does
860 861 * not comply with the LDAP v3 protocol.
861 862 */
862 863 default:
863 864 if (resultMsg) {
864 865 (void) ldap_msgfree(resultMsg);
865 866 resultMsg = NULL;
866 867 }
867 868
868 869 return (NS_LDAP_OP_FAILED);
869 870 }
870 871
871 872 if ((ret_code = convert_to_door_line(ld,
872 873 resultMsg,
873 874 DONT_INCLUDE_ATTR_NAMES,
874 875 NOT_PROFILE,
875 876 &DNlist)) != NS_LDAP_SUCCESS) {
876 877 if (resultMsg) {
877 878 (void) ldap_msgfree(resultMsg);
878 879 resultMsg = NULL;
879 880 }
880 881 return (ret_code);
881 882 }
882 883
883 884 if (resultMsg) {
884 885 (void) ldap_msgfree(resultMsg);
885 886 resultMsg = NULL;
886 887 }
887 888
888 889 if (DNlist == NULL ||
889 890 (ptr = strtok_r(DNlist, DOORLINESEP, &rest)) == NULL) {
890 891 return (NS_LDAP_NOTFOUND);
891 892 }
892 893 attrs[0] = "dn";
893 894 do {
894 895 /*
895 896 * For each context try to find a NIS domain object
896 897 * which 'nisdomain' attribute's value matches the domain name
897 898 */
898 899 (void) snprintf(filter,
899 900 BUFSIZ,
900 901 "(&(objectclass=nisDomainObject)"
901 902 "(nisdomain=%s))",
902 903 domain_name);
903 904 ldap_rc = ldap_search_ext_s(ld,
904 905 ptr,
905 906 LDAP_SCOPE_SUBTREE,
906 907 filter,
907 908 attrs,
908 909 0,
909 910 NULL,
910 911 NULL,
911 912 &tv,
912 913 0,
913 914 &resultMsg);
914 915 if (ldap_rc != LDAP_SUCCESS) {
915 916 if (resultMsg) {
916 917 (void) ldap_msgfree(resultMsg);
917 918 resultMsg = NULL;
918 919 }
919 920 continue;
920 921 }
921 922 if ((a = ldap_get_dn(ld, resultMsg)) != NULL) {
922 923 *dir_base_dn = strdup(a);
923 924 ldap_memfree(a);
924 925
925 926 if (resultMsg) {
926 927 (void) ldap_msgfree(resultMsg);
927 928 resultMsg = NULL;
928 929 }
929 930
930 931 if (!*dir_base_dn) {
931 932 free(DNlist);
932 933 return (NS_LDAP_MEMORY);
933 934 }
934 935 break;
935 936 }
936 937
937 938 if (resultMsg) {
938 939 (void) ldap_msgfree(resultMsg);
939 940 resultMsg = NULL;
940 941 }
941 942 } while (ptr = strtok_r(NULL, DOORLINESEP, &rest));
942 943
943 944 free(DNlist);
944 945
945 946 if (!*dir_base_dn) {
946 947 return (NS_LDAP_NOTFOUND);
947 948 }
948 949
949 950 return (NS_LDAP_SUCCESS);
950 951 }
951 952
952 953 /*
953 954 * This function parses the results of a search operation
954 955 * requesting a DUAProfile.
955 956 *
956 957 * INPUT:
957 958 * ld - a pointer to an LDAP structure used for the search operation,
958 959 * dir_base_dn - the name of a directory's base DN,
959 960 * profile_name - the name of a DUAProfile to be obtained.
960 961 *
961 962 * OUTPUT:
962 963 * a buffer containing the DUAProfile in the following format:
963 964 * [<attribute name>=]value [DOORLINESEP [<attribute name>=]value ]...]
964 965 * Should be free'ed by the caller.
965 966 */
966 967 static
967 968 ns_ldap_return_code
968 969 getDUAProfile(LDAP *ld,
969 970 const char *dir_base_dn,
970 971 const char *profile_name,
971 972 char **profile)
972 973 {
973 974 char searchBaseDN[BUFSIZ], filter[BUFSIZ];
974 975 LDAPMessage *resultMsg = NULL;
975 976 struct timeval tv = {NS_DEFAULT_SEARCH_TIMEOUT, 0};
976 977 int ldap_rc;
977 978 ns_ldap_return_code ret_code;
978 979
979 980 (void) snprintf(searchBaseDN, BUFSIZ, "ou=profile,%s", dir_base_dn);
980 981 (void) snprintf(filter,
981 982 BUFSIZ,
982 983 _PROFILE_FILTER,
983 984 _PROFILE1_OBJECTCLASS,
984 985 _PROFILE2_OBJECTCLASS,
985 986 profile_name);
986 987 ldap_rc = ldap_search_ext_s(ld,
987 988 searchBaseDN,
988 989 LDAP_SCOPE_SUBTREE,
989 990 filter,
990 991 NULL,
991 992 0,
992 993 NULL,
993 994 NULL,
994 995 &tv,
995 996 0,
996 997 &resultMsg);
997 998
998 999 switch (ldap_rc) {
999 1000 /* If successful, the DUA profile was found. */
1000 1001 case LDAP_SUCCESS:
1001 1002 break;
1002 1003 /*
1003 1004 * If the root DSE was not found, the server does
1004 1005 * not comply with the LDAP v3 protocol.
1005 1006 */
1006 1007 default:
1007 1008 if (resultMsg) {
1008 1009 (void) ldap_msgfree(resultMsg);
1009 1010 resultMsg = NULL;
1010 1011 }
1011 1012
1012 1013 return (NS_LDAP_OP_FAILED);
1013 1014 }
1014 1015
1015 1016 ret_code = convert_to_door_line(ld,
1016 1017 resultMsg,
1017 1018 INCLUDE_ATTR_NAMES,
1018 1019 IS_PROFILE,
1019 1020 profile);
1020 1021 if (resultMsg) {
1021 1022 (void) ldap_msgfree(resultMsg);
1022 1023 resultMsg = NULL;
1023 1024 }
1024 1025 return (ret_code);
1025 1026 }
1026 1027
1027 1028 /*
1028 1029 * This function derives the directory's base DN from a provided domain name.
1029 1030 *
1030 1031 * INPUT:
1031 1032 * domain_name - the name of a domain to be converted into a base DN,
1032 1033 * buffer - contains the derived base DN,
1033 1034 * buf_len - the length of the buffer.
1034 1035 *
1035 1036 * OUTPUT:
1036 1037 * The function returns the address of the buffer or NULL.
1037 1038 */
1038 1039 static
1039 1040 char *
1040 1041 domainname2baseDN(char *domain_name, char *buffer, uint16_t buf_len)
1041 1042 {
1042 1043 char *nextDC, *chr;
1043 1044 uint16_t i, length;
1044 1045
1045 1046 if (!domain_name || !buffer || buf_len == 0) {
1046 1047 return (NULL);
1047 1048 }
1048 1049
1049 1050 buffer[0] = '\0';
1050 1051 nextDC = chr = domain_name;
1051 1052 length = strlen(domain_name);
1052 1053 for (i = 0; i < length + 1; ++i, ++chr) {
1053 1054 /* Simply replace dots with "dc=" */
1054 1055 if (*chr != '.' && *chr != '\0') {
1055 1056 continue;
1056 1057 }
1057 1058 *chr = '\0';
1058 1059 if (strlcat(buffer, "dc=", buf_len) >= buf_len)
1059 1060 return (NULL);
1060 1061 if (strlcat(buffer, nextDC, buf_len) >= buf_len)
1061 1062 return (NULL);
1062 1063 if (i < length) {
1063 1064 /*
1064 1065 * The end of the domain name
1065 1066 * has not been reached yet
1066 1067 */
1067 1068 if (strlcat(buffer, ",", buf_len) >= buf_len)
1068 1069 return (NULL);
1069 1070 nextDC = chr + 1;
1070 1071 *chr = '.';
1071 1072 }
1072 1073 }
1073 1074
1074 1075 return (buffer);
1075 1076 }
1076 1077
1077 1078 /*
1078 1079 * This function obtains the directory's base DN and a DUAProfile
1079 1080 * from a specified server.
1080 1081 *
1081 1082 * INPUT:
1082 1083 * server - a structure describing a server to connect to and
1083 1084 * a DUAProfile to be obtained from the server,
1084 1085 * cred - credentials to be used during establishing connections to
1085 1086 * the server.
1086 1087 *
1087 1088 * OUTPUT:
1088 1089 * dua_profile - a buffer containing the DUAProfile in the following format:
1089 1090 * [<attribute name>=]value [DOORLINESEP [<attribute name>=]value ]...]
1090 1091 * dir_base_dn - a buffer containing the base DN,
1091 1092 * errorp - an error object describing an error, if any.
1092 1093 *
1093 1094 * All the output data structures should be free'ed by the caller.
1094 1095 */
1095 1096 ns_ldap_return_code
1096 1097 __ns_ldap_getConnectionInfoFromDUA(const ns_dir_server_t *server,
1097 1098 const ns_cred_t *cred,
1098 1099 char **dua_profile,
1099 1100 char **dir_base_dn,
1100 1101 ns_ldap_error_t **errorp)
1101 1102 {
1102 1103 char serverAddr[MAX_HOSTADDR_LEN];
1103 1104 char *dirBaseDN = NULL, *duaProfile = NULL;
1104 1105 ns_cred_t default_cred;
1105 1106 ns_ldap_return_code ret_code;
1106 1107
1107 1108 ns_config_t *config_struct = __s_api_create_config();
1108 1109 ConnectionID sessionId = 0;
1109 1110 Connection *session = NULL;
1110 1111 char errmsg[MAXERROR];
1111 1112 char buffer[NSS_BUFLEN_HOSTS];
1112 1113 ns_conn_user_t *cu = NULL;
1113 1114
1114 1115 if (errorp == NULL) {
1115 1116 __s_api_destroy_config(config_struct);
1116 1117 return (NS_LDAP_INVALID_PARAM);
1117 1118 }
1118 1119
1119 1120 *errorp = NULL;
1120 1121
1121 1122 if (server == NULL) {
1122 1123 __s_api_destroy_config(config_struct);
1123 1124 return (NS_LDAP_INVALID_PARAM);
1124 1125 }
1125 1126
1126 1127 if (config_struct == NULL) {
1127 1128 return (NS_LDAP_MEMORY);
1128 1129 }
1129 1130
1130 1131 /*
1131 1132 * If no credentials are specified, try to establish a connection
1132 1133 * as anonymous.
1133 1134 */
1134 1135 if (!cred) {
1135 1136 default_cred.cred.unix_cred.passwd = NULL;
1136 1137 default_cred.cred.unix_cred.userID = NULL;
1137 1138 default_cred.auth.type = NS_LDAP_AUTH_NONE;
1138 1139 }
1139 1140
1140 1141 /* Now create a default LDAP configuration */
1141 1142
1142 1143 (void) strncpy(buffer, server->server, sizeof (buffer));
1143 1144 if (__ns_ldap_setParamValue(config_struct, NS_LDAP_SERVERS_P, buffer,
1144 1145 errorp) != NS_LDAP_SUCCESS) {
1145 1146 __s_api_destroy_config(config_struct);
1146 1147 return (NS_LDAP_CONFIG);
1147 1148 }
1148 1149
1149 1150 /* Put together the address and the port specified by the user app. */
1150 1151 if (server->port > 0) {
1151 1152 (void) snprintf(serverAddr,
1152 1153 sizeof (serverAddr),
1153 1154 "%s:%hu",
1154 1155 buffer,
1155 1156 server->port);
1156 1157 } else {
1157 1158 (void) strncpy(serverAddr, buffer, sizeof (serverAddr));
1158 1159 }
1159 1160
1160 1161 /*
1161 1162 * There is no default value for the 'Default Search Base DN' attribute.
1162 1163 * Derive one from the domain name to make __s_api_crosscheck() happy.
1163 1164 */
1164 1165 if (domainname2baseDN(server->domainName ?
1165 1166 server->domainName : config_struct->domainName,
1166 1167 buffer, NSS_BUFLEN_HOSTS) == NULL) {
1167 1168 (void) snprintf(errmsg,
1168 1169 sizeof (errmsg),
1169 1170 gettext("Can not convert %s into a base DN name"),
1170 1171 server->domainName ?
1171 1172 server->domainName : config_struct->domainName);
1172 1173 MKERROR(LOG_ERR,
1173 1174 *errorp,
1174 1175 NS_LDAP_INTERNAL,
1175 1176 strdup(errmsg),
1176 1177 NS_LDAP_MEMORY);
1177 1178 __s_api_destroy_config(config_struct);
1178 1179 return (NS_LDAP_INTERNAL);
1179 1180 }
1180 1181 if (__ns_ldap_setParamValue(config_struct, NS_LDAP_SEARCH_BASEDN_P,
1181 1182 buffer, errorp) != NS_LDAP_SUCCESS) {
1182 1183 __s_api_destroy_config(config_struct);
1183 1184 return (NS_LDAP_CONFIG);
1184 1185 }
1185 1186
1186 1187 if (__s_api_crosscheck(config_struct, errmsg, B_FALSE) != NS_SUCCESS) {
1187 1188 __s_api_destroy_config(config_struct);
1188 1189 return (NS_LDAP_CONFIG);
1189 1190 }
1190 1191
1191 1192 __s_api_init_config(config_struct);
1192 1193
1193 1194 __s_api_setInitMode();
1194 1195
1195 1196 cu = __s_api_conn_user_init(NS_CONN_USER_SEARCH, NULL, B_FALSE);
1196 1197 if (cu == NULL) {
1197 1198 return (NS_LDAP_INTERNAL);
1198 1199 }
1199 1200
1200 1201 if ((ret_code = __s_api_getConnection(serverAddr,
1201 1202 NS_LDAP_NEW_CONN,
1202 1203 cred ? cred : &default_cred,
1203 1204 &sessionId,
1204 1205 &session,
1205 1206 errorp,
1206 1207 0,
1207 1208 0,
1208 1209 cu)) != NS_LDAP_SUCCESS) {
1209 1210 __s_api_conn_user_free(cu);
1210 1211 __s_api_unsetInitMode();
1211 1212 return (ret_code);
1212 1213 }
1213 1214
1214 1215 __s_api_unsetInitMode();
1215 1216
1216 1217 if ((ret_code = getDirBaseDN(session->ld,
1217 1218 server->domainName ?
1218 1219 server->domainName :
1219 1220 config_struct->domainName,
1220 1221 &dirBaseDN)) != NS_LDAP_SUCCESS) {
1221 1222 (void) snprintf(errmsg,
1222 1223 sizeof (errmsg),
1223 1224 gettext("Can not find the "
1224 1225 "nisDomainObject for domain %s\n"),
1225 1226 server->domainName ?
1226 1227 server->domainName : config_struct->domainName);
1227 1228 MKERROR(LOG_ERR,
1228 1229 *errorp,
1229 1230 ret_code,
1230 1231 strdup(errmsg),
1231 1232 NS_LDAP_MEMORY);
1232 1233 __s_api_conn_user_free(cu);
1233 1234 DropConnection(sessionId, NS_LDAP_NEW_CONN);
1234 1235 return (ret_code);
1235 1236 }
1236 1237
1237 1238 /*
1238 1239 * And here obtain a DUAProfile which will be used
1239 1240 * as a real configuration.
1240 1241 */
1241 1242 if ((ret_code = getDUAProfile(session->ld,
1242 1243 dirBaseDN,
1243 1244 server->profileName ?
1244 1245 server->profileName : "default",
1245 1246 &duaProfile)) != NS_LDAP_SUCCESS) {
1246 1247 (void) snprintf(errmsg,
1247 1248 sizeof (errmsg),
1248 1249 gettext("Can not find the "
1249 1250 "%s DUAProfile\n"),
1250 1251 server->profileName ?
1251 1252 server->profileName : "default");
1252 1253 MKERROR(LOG_ERR,
1253 1254 *errorp,
1254 1255 ret_code,
1255 1256 strdup(errmsg),
1256 1257 NS_LDAP_MEMORY);
1257 1258 __s_api_conn_user_free(cu);
1258 1259 DropConnection(sessionId, NS_LDAP_NEW_CONN);
1259 1260 return (ret_code);
1260 1261 }
1261 1262
1262 1263 if (dir_base_dn) {
1263 1264 *dir_base_dn = dirBaseDN;
1264 1265 } else {
1265 1266 free(dirBaseDN);
1266 1267 }
1267 1268
1268 1269 if (dua_profile) {
1269 1270 *dua_profile = duaProfile;
1270 1271 } else {
1271 1272 free(duaProfile);
1272 1273 }
1273 1274
1274 1275 __s_api_conn_user_free(cu);
1275 1276 DropConnection(sessionId, NS_LDAP_NEW_CONN);
1276 1277
1277 1278 return (NS_LDAP_SUCCESS);
1278 1279 }
1279 1280
1280 1281 /*
1281 1282 * This function obtains the root DSE from a specified server.
1282 1283 *
1283 1284 * INPUT:
1284 1285 * server_addr - an adress of a server to be connected to.
1285 1286 *
1286 1287 * OUTPUT:
1287 1288 * root_dse - a buffer containing the root DSE in the following format:
1288 1289 * [<attribute name>=]value [DOORLINESEP [<attribute name>=]value ]...]
1289 1290 * For example: ( here | used as DOORLINESEP for visual purposes)
1290 1291 * supportedControl=1.1.1.1|supportedSASLmechanisms=EXTERNAL
1291 1292 * Should be free'ed by the caller.
1292 1293 */
1293 1294 ns_ldap_return_code
1294 1295 __ns_ldap_getRootDSE(const char *server_addr,
1295 1296 char **root_dse,
1296 1297 ns_ldap_error_t **errorp,
1297 1298 int anon_fallback)
1298 1299 {
1299 1300 char errmsg[MAXERROR];
1300 1301 ns_ldap_return_code ret_code;
1301 1302
1302 1303 ConnectionID sessionId = 0;
1303 1304 Connection *session = NULL;
1304 1305
1305 1306 struct timeval tv = {NS_DEFAULT_SEARCH_TIMEOUT, 0};
1306 1307 char *attrs[3];
1307 1308 int ldap_rc, ldaperrno = 0;
1308 1309 LDAPMessage *resultMsg = NULL;
1309 1310 void **paramVal = NULL;
1310 1311
1311 1312 ns_cred_t anon;
1312 1313 ns_conn_user_t *cu = NULL;
1313 1314
1314 1315 if (errorp == NULL) {
1315 1316 return (NS_LDAP_INVALID_PARAM);
1316 1317 }
1317 1318
1318 1319 *errorp = NULL;
1319 1320
1320 1321 if (!root_dse) {
1321 1322 return (NS_LDAP_INVALID_PARAM);
1322 1323 }
1323 1324
1324 1325 if (!server_addr) {
1325 1326 return (NS_LDAP_INVALID_PARAM);
1326 1327 }
1327 1328
1328 1329 __s_api_setInitMode();
1329 1330
1330 1331 cu = __s_api_conn_user_init(NS_CONN_USER_SEARCH, NULL, B_FALSE);
1331 1332 if (cu == NULL) {
1332 1333 return (NS_LDAP_INTERNAL);
1333 1334 }
1334 1335
1335 1336 /*
1336 1337 * All the credentials will be taken from the current
1337 1338 * libsldap configuration.
1338 1339 */
1339 1340 if ((ret_code = __s_api_getConnection(server_addr,
1340 1341 NS_LDAP_NEW_CONN,
1341 1342 NULL,
1342 1343 &sessionId,
1343 1344 &session,
1344 1345 errorp,
1345 1346 0,
1346 1347 0,
1347 1348 cu)) != NS_LDAP_SUCCESS) {
1348 1349 /* Fallback to anonymous mode is disabled. Stop. */
1349 1350 if (anon_fallback == 0) {
1350 1351 syslog(LOG_WARNING,
1351 1352 gettext("libsldap: can not get the root DSE from "
1352 1353 " the %s server: %s. "
1353 1354 "Falling back to anonymous disabled.\n"),
1354 1355 server_addr,
1355 1356 errorp && *errorp && (*errorp)->message ?
1356 1357 (*errorp)->message : "");
1357 1358 if (errorp != NULL && *errorp != NULL) {
1358 1359 (void) __ns_ldap_freeError(errorp);
1359 1360 }
1360 1361 __s_api_unsetInitMode();
1361 1362 return (ret_code);
1362 1363 }
1363 1364
1364 1365 /*
1365 1366 * Fallback to anonymous, non-SSL mode for backward
1366 1367 * compatibility reasons. This mode should only be used when
1367 1368 * this function (__ns_ldap_getRootDSE) is called from
1368 1369 * ldap_cachemgr(1M).
1369 1370 */
1370 1371 syslog(LOG_WARNING,
1371 1372 gettext("libsldap: Falling back to anonymous, non-SSL"
1372 1373 " mode for __ns_ldap_getRootDSE. %s\n"),
1373 1374 errorp && *errorp && (*errorp)->message ?
1374 1375 (*errorp)->message : "");
1375 1376
1376 1377 /* Setup the anon credential for anonymous connection. */
1377 1378 (void) memset(&anon, 0, sizeof (ns_cred_t));
1378 1379 anon.auth.type = NS_LDAP_AUTH_NONE;
1379 1380
1380 1381 if (*errorp != NULL) {
1381 1382 (void) __ns_ldap_freeError(errorp);
1382 1383 }
1383 1384 *errorp = NULL;
1384 1385
1385 1386 ret_code = __s_api_getConnection(server_addr,
1386 1387 NS_LDAP_NEW_CONN,
1387 1388 &anon,
1388 1389 &sessionId,
1389 1390 &session,
1390 1391 errorp,
1391 1392 0,
1392 1393 0,
1393 1394 cu);
1394 1395
1395 1396 if (ret_code != NS_LDAP_SUCCESS) {
1396 1397 __s_api_conn_user_free(cu);
1397 1398 __s_api_unsetInitMode();
1398 1399 return (ret_code);
1399 1400 }
1400 1401 }
1401 1402
1402 1403 __s_api_unsetInitMode();
1403 1404
1404 1405 /* get search timeout value */
1405 1406 (void) __ns_ldap_getParam(NS_LDAP_SEARCH_TIME_P, ¶mVal, errorp);
1406 1407 if (paramVal != NULL && *paramVal != NULL) {
1407 1408 tv.tv_sec = **((int **)paramVal);
1408 1409 (void) __ns_ldap_freeParam(¶mVal);
1409 1410 }
1410 1411 if (*errorp != NULL) {
1411 1412 (void) __ns_ldap_freeError(errorp);
1412 1413 }
1413 1414
1414 1415 /* Get root DSE from the server specified by the caller. */
1415 1416 attrs[0] = "supportedControl";
1416 1417 attrs[1] = "supportedsaslmechanisms";
1417 1418 attrs[2] = NULL;
1418 1419 ldap_rc = ldap_search_ext_s(session->ld,
1419 1420 "",
1420 1421 LDAP_SCOPE_BASE,
1421 1422 "(objectclass=*)",
1422 1423 attrs,
1423 1424 0,
1424 1425 NULL,
1425 1426 NULL,
1426 1427 &tv,
1427 1428 0,
1428 1429 &resultMsg);
1429 1430
1430 1431 if (ldap_rc != LDAP_SUCCESS) {
1431 1432 /*
1432 1433 * If the root DSE was not found, the server does
1433 1434 * not comply with the LDAP v3 protocol.
1434 1435 */
1435 1436 (void) ldap_get_option(session->ld,
1436 1437 LDAP_OPT_ERROR_NUMBER,
1437 1438 &ldaperrno);
1438 1439 (void) snprintf(errmsg,
1439 1440 sizeof (errmsg),
1440 1441 gettext(ldap_err2string(ldaperrno)));
1441 1442 MKERROR(LOG_ERR,
1442 1443 *errorp,
↓ open down ↓ |
1408 lines elided |
↑ open up ↑ |
1443 1444 NS_LDAP_OP_FAILED,
1444 1445 strdup(errmsg),
1445 1446 NS_LDAP_MEMORY);
1446 1447
1447 1448 if (resultMsg) {
1448 1449 (void) ldap_msgfree(resultMsg);
1449 1450 resultMsg = NULL;
1450 1451 }
1451 1452
1452 1453 __s_api_conn_user_free(cu);
1454 + DropConnection(sessionId, NS_LDAP_NEW_CONN);
1453 1455 return (NS_LDAP_OP_FAILED);
1454 1456 }
1455 1457 __s_api_conn_user_free(cu);
1456 1458
1457 1459 ret_code = convert_to_door_line(session->ld,
1458 1460 resultMsg,
1459 1461 INCLUDE_ATTR_NAMES,
1460 1462 NOT_PROFILE,
1461 1463 root_dse);
1462 1464 if (ret_code == NS_LDAP_NOTFOUND) {
1463 1465 (void) snprintf(errmsg,
1464 1466 sizeof (errmsg),
1465 1467 gettext("No root DSE data "
1466 1468 "for server %s returned."),
1467 1469 server_addr);
1468 1470 MKERROR(LOG_ERR,
1469 1471 *errorp,
1470 1472 NS_LDAP_NOTFOUND,
1471 1473 strdup(errmsg),
1472 1474 NS_LDAP_MEMORY);
1473 1475 }
1474 1476
1475 1477 if (resultMsg) {
1476 1478 (void) ldap_msgfree(resultMsg);
1477 1479 resultMsg = NULL;
1478 1480 }
1479 1481
1480 1482 DropConnection(sessionId, NS_LDAP_NEW_CONN);
1481 1483
1482 1484 return (ret_code);
1483 1485 }
1484 1486
1485 1487 /*
1486 1488 * This function destroys the local list of root DSEs. The input parameter is
1487 1489 * a pointer to the list to be erased.
1488 1490 * The type of the pointer passed to this function should be
1489 1491 * (dir_server_list_t *).
1490 1492 */
1491 1493 static
1492 1494 void *
1493 1495 disposeOfOldList(void *param)
1494 1496 {
1495 1497 dir_server_list_t *old_list = (dir_server_list_t *)param;
1496 1498 long i = 0, j;
1497 1499
1498 1500 (void) rw_wrlock(&old_list->listDestroyLock);
1499 1501 /* Destroy the old list */
1500 1502 while (old_list->nsServers[i]) {
1501 1503 free(old_list->nsServers[i]->ip);
1502 1504 j = 0;
1503 1505 while (old_list->nsServers[i]->controls &&
1504 1506 old_list->nsServers[i]->controls[j]) {
1505 1507 free(old_list->nsServers[i]->controls[j]);
1506 1508 ++j;
1507 1509 }
1508 1510 free(old_list->nsServers[i]->controls);
1509 1511 j = 0;
1510 1512 while (old_list->nsServers[i]->saslMech &&
1511 1513 old_list->nsServers[i]->saslMech[j]) {
1512 1514 free(old_list->nsServers[i]->saslMech[j]);
1513 1515 ++j;
1514 1516 }
1515 1517 free(old_list->nsServers[i]->saslMech);
1516 1518 ++i;
1517 1519 }
1518 1520 /*
1519 1521 * All the structures pointed by old_list->nsServers were allocated
1520 1522 * in one chunck. The nsServers[0] pointer points to the beginning
1521 1523 * of that chunck.
1522 1524 */
1523 1525 free(old_list->nsServers[0]);
1524 1526 free(old_list->nsServers);
1525 1527 (void) rw_unlock(&old_list->listDestroyLock);
1526 1528 (void) rwlock_destroy(&old_list->listDestroyLock);
1527 1529 free(old_list);
1528 1530
1529 1531 return (NULL);
1530 1532 }
1531 1533
1532 1534 /*
1533 1535 * This function cancels the Standalone mode and destroys the list of root DSEs.
1534 1536 */
1535 1537 void
1536 1538 __ns_ldap_cancelStandalone(void)
1537 1539 {
1538 1540 dir_server_list_t *old_list;
1539 1541
1540 1542 (void) mutex_lock(&dir_servers.listReplaceLock);
1541 1543 dir_servers.standalone = 0;
1542 1544 if (!dir_servers.list) {
1543 1545 (void) mutex_unlock(&dir_servers.listReplaceLock);
1544 1546 return;
1545 1547 }
1546 1548 old_list = dir_servers.list;
1547 1549 dir_servers.list = NULL;
1548 1550 (void) mutex_unlock(&dir_servers.listReplaceLock);
1549 1551
1550 1552 (void) disposeOfOldList(old_list);
1551 1553 }
1552 1554
1553 1555
1554 1556 static
1555 1557 void*
1556 1558 create_ns_servers_entry(void *param)
1557 1559 {
1558 1560 #define CHUNK_SIZE 16
1559 1561
1560 1562 dir_server_t *server = (dir_server_t *)param;
1561 1563 ns_ldap_return_code *retCode = calloc(1,
1562 1564 sizeof (ns_ldap_return_code));
1563 1565 uint32_t sc_counter = 0, sm_counter = 0;
1564 1566 uint32_t sc_mem_blocks = 1, sm_mem_blocks = 1;
1565 1567 char *rootDSE = NULL, *attr, *val, *rest, **ptr;
1566 1568 ns_ldap_error_t *error = NULL;
1567 1569
1568 1570 if (retCode == NULL) {
1569 1571 return (NULL);
1570 1572 }
1571 1573
1572 1574 /*
1573 1575 * We call this function in non anon-fallback mode because we
1574 1576 * want the whole procedure to fail as soon as possible to
1575 1577 * indicate there are problems with connecting to the server.
1576 1578 */
1577 1579 *retCode = __ns_ldap_getRootDSE(server->ip,
1578 1580 &rootDSE,
1579 1581 &error,
1580 1582 SA_ALLOW_FALLBACK);
1581 1583
1582 1584 if (*retCode == NS_LDAP_MEMORY) {
1583 1585 free(retCode);
1584 1586 return (NULL);
1585 1587 }
1586 1588
1587 1589 /*
1588 1590 * If the root DSE can not be obtained, log an error and keep the
1589 1591 * server.
1590 1592 */
1591 1593 if (*retCode != NS_LDAP_SUCCESS) {
1592 1594 server->status = INFO_SERVER_ERROR;
1593 1595 syslog(LOG_WARNING,
1594 1596 gettext("libsldap (\"standalone\" mode): "
1595 1597 "can not obtain the root DSE from %s. %s"),
1596 1598 server->ip,
1597 1599 error && error->message ? error->message : "");
1598 1600 if (error) {
1599 1601 (void) __ns_ldap_freeError(&error);
1600 1602 }
1601 1603 return (retCode);
1602 1604 }
1603 1605
1604 1606 /* Get the first attribute of the root DSE. */
1605 1607 attr = strtok_r(rootDSE, DOORLINESEP, &rest);
1606 1608 if (attr == NULL) {
1607 1609 free(rootDSE);
1608 1610 server->status = INFO_SERVER_ERROR;
1609 1611 syslog(LOG_WARNING,
1610 1612 gettext("libsldap (\"standalone\" mode): "
1611 1613 "the root DSE from %s is empty or corrupted."),
1612 1614 server->ip);
1613 1615 *retCode = NS_LDAP_INTERNAL;
1614 1616 return (retCode);
1615 1617 }
1616 1618
1617 1619 server->controls = (char **)calloc(CHUNK_SIZE, sizeof (char *));
1618 1620 server->saslMech = (char **)calloc(CHUNK_SIZE, sizeof (char *));
1619 1621 if (server->controls == NULL || server->saslMech == NULL) {
1620 1622 free(rootDSE);
1621 1623 free(retCode);
1622 1624 return (NULL);
1623 1625 }
1624 1626
1625 1627 do {
1626 1628 if ((val = strchr(attr, '=')) == NULL) {
1627 1629 continue;
1628 1630 }
1629 1631 ++val;
1630 1632
1631 1633 if (strncasecmp(attr,
1632 1634 _SASLMECHANISM,
1633 1635 _SASLMECHANISM_LEN) == 0) {
1634 1636 if (sm_counter == CHUNK_SIZE * sm_mem_blocks - 1) {
1635 1637 ptr = (char **)realloc(server->saslMech,
1636 1638 CHUNK_SIZE *
1637 1639 ++sm_mem_blocks *
1638 1640 sizeof (char *));
1639 1641 if (ptr == NULL) {
1640 1642 *retCode = NS_LDAP_MEMORY;
1641 1643 break;
1642 1644 }
1643 1645 bzero((char *)ptr +
1644 1646 (sm_counter + 1) *
1645 1647 sizeof (char *),
1646 1648 CHUNK_SIZE *
1647 1649 sm_mem_blocks *
1648 1650 sizeof (char *) -
1649 1651 (sm_counter + 1) *
1650 1652 sizeof (char *));
1651 1653 server->saslMech = ptr;
1652 1654 }
1653 1655 server->saslMech[sm_counter] = strdup(val);
1654 1656 if (server->saslMech[sm_counter] == NULL) {
1655 1657 *retCode = NS_LDAP_MEMORY;
1656 1658 break;
1657 1659 }
1658 1660 ++sm_counter;
1659 1661 continue;
1660 1662 }
1661 1663 if (strncasecmp(attr,
1662 1664 _SUPPORTEDCONTROL,
1663 1665 _SUPPORTEDCONTROL_LEN) == 0) {
1664 1666 if (sc_counter == CHUNK_SIZE * sc_mem_blocks - 1) {
1665 1667 ptr = (char **)realloc(server->controls,
1666 1668 CHUNK_SIZE *
1667 1669 ++sc_mem_blocks *
1668 1670 sizeof (char *));
1669 1671 if (ptr == NULL) {
1670 1672 *retCode = NS_LDAP_MEMORY;
1671 1673 break;
1672 1674 }
1673 1675 bzero((char *)ptr +
1674 1676 (sc_counter + 1) *
1675 1677 sizeof (char *),
1676 1678 CHUNK_SIZE *
1677 1679 sc_mem_blocks *
1678 1680 sizeof (char *) -
1679 1681 (sc_counter + 1) *
1680 1682 sizeof (char *));
1681 1683 server->controls = ptr;
1682 1684 }
1683 1685
1684 1686 server->controls[sc_counter] = strdup(val);
1685 1687 if (server->controls[sc_counter] == NULL) {
1686 1688 *retCode = NS_LDAP_MEMORY;
1687 1689 break;
1688 1690 }
1689 1691 ++sc_counter;
1690 1692 continue;
1691 1693 }
1692 1694
1693 1695 } while (attr = strtok_r(NULL, DOORLINESEP, &rest));
1694 1696
1695 1697 free(rootDSE);
1696 1698
1697 1699 if (*retCode == NS_LDAP_MEMORY) {
1698 1700 free(retCode);
1699 1701 return (NULL);
1700 1702 }
1701 1703
1702 1704 server->controls[sc_counter] = NULL;
1703 1705 server->saslMech[sm_counter] = NULL;
1704 1706
1705 1707 server->status = INFO_SERVER_UP;
1706 1708
1707 1709 return (retCode);
1708 1710 #undef CHUNK_SIZE
1709 1711 }
1710 1712
1711 1713
1712 1714 /*
1713 1715 * This function creates a new local list of root DSEs from all the servers
1714 1716 * mentioned in the DUAProfile (or local NS BEC) and returns
1715 1717 * a pointer to the list.
1716 1718 */
1717 1719 static
1718 1720 ns_ldap_return_code
1719 1721 createDirServerList(dir_server_list_t **new_list,
1720 1722 ns_ldap_error_t **errorp)
1721 1723 {
1722 1724 char **serverList;
1723 1725 ns_ldap_return_code retCode = NS_LDAP_SUCCESS;
1724 1726 dir_server_t *tmpSrvArray;
1725 1727 long srvListLength, i;
1726 1728 thread_t *thrPool, thrID;
1727 1729 void *status = NULL;
1728 1730
1729 1731 if (errorp == NULL) {
1730 1732 return (NS_LDAP_INVALID_PARAM);
1731 1733 }
1732 1734
1733 1735 *errorp = NULL;
1734 1736
1735 1737 if (new_list == NULL) {
1736 1738 return (NS_LDAP_INVALID_PARAM);
1737 1739 }
1738 1740
1739 1741 retCode = __s_api_getServers(&serverList, errorp);
1740 1742 if (retCode != NS_LDAP_SUCCESS || serverList == NULL) {
1741 1743 return (retCode);
1742 1744 }
1743 1745
1744 1746 for (i = 0; serverList[i]; ++i) {
1745 1747 ;
1746 1748 }
1747 1749 srvListLength = i;
1748 1750
1749 1751 thrPool = calloc(srvListLength, sizeof (thread_t));
1750 1752 if (thrPool == NULL) {
1751 1753 __s_api_free2dArray(serverList);
1752 1754 return (NS_LDAP_MEMORY);
1753 1755 }
1754 1756
1755 1757 *new_list = (dir_server_list_t *)calloc(1,
1756 1758 sizeof (dir_server_list_t));
1757 1759 if (*new_list == NULL) {
1758 1760 __s_api_free2dArray(serverList);
1759 1761 free(thrPool);
1760 1762 return (NS_LDAP_MEMORY);
1761 1763 }
1762 1764 (void) rwlock_init(&(*new_list)->listDestroyLock, USYNC_THREAD, NULL);
1763 1765
1764 1766 (*new_list)->nsServers = (dir_server_t **)calloc(srvListLength + 1,
1765 1767 sizeof (dir_server_t *));
1766 1768 if ((*new_list)->nsServers == NULL) {
1767 1769 free(*new_list);
1768 1770 *new_list = NULL;
1769 1771 __s_api_free2dArray(serverList);
1770 1772 free(thrPool);
1771 1773 return (NS_LDAP_MEMORY);
1772 1774 }
1773 1775
1774 1776 /*
1775 1777 * Allocate a set of dir_server_t structures as an array,
1776 1778 * with one alloc call and then initialize the nsServers pointers
1777 1779 * with the addresses of the array's members.
1778 1780 */
1779 1781 tmpSrvArray = (dir_server_t *)calloc(srvListLength,
1780 1782 sizeof (dir_server_t));
1781 1783 for (i = 0; i < srvListLength; ++i) {
1782 1784 (*new_list)->nsServers[i] = &tmpSrvArray[i];
1783 1785
1784 1786 (*new_list)->nsServers[i]->info = INFO_STATUS_NEW;
1785 1787 (void) mutex_init(&(*new_list)->nsServers[i]->updateStatus,
1786 1788 USYNC_THREAD,
1787 1789 NULL);
1788 1790
1789 1791 (*new_list)->nsServers[i]->ip = strdup(serverList[i]);
1790 1792 if ((*new_list)->nsServers[i]->ip == NULL) {
1791 1793 retCode = NS_LDAP_MEMORY;
1792 1794 break;
1793 1795 }
1794 1796
1795 1797 (*new_list)->nsServers[i]->status = INFO_SERVER_CONNECTING;
1796 1798
1797 1799 switch (thr_create(NULL,
1798 1800 0,
1799 1801 create_ns_servers_entry,
1800 1802 (*new_list)->nsServers[i],
1801 1803 0,
1802 1804 &thrID)) {
1803 1805 case EAGAIN:
1804 1806 (*new_list)->nsServers[i]->status =
1805 1807 INFO_SERVER_ERROR;
1806 1808 continue;
1807 1809 case ENOMEM:
1808 1810 (*new_list)->nsServers[i]->status =
1809 1811 INFO_SERVER_ERROR;
1810 1812 continue;
1811 1813 default:
1812 1814 thrPool[i] = thrID;
1813 1815 continue;
1814 1816 }
1815 1817 }
1816 1818
1817 1819 for (i = 0; i < srvListLength; ++i) {
1818 1820 if (thrPool[i] != 0 &&
1819 1821 thr_join(thrPool[i], NULL, &status) == 0) {
1820 1822 if (status == NULL) {
1821 1823 /*
1822 1824 * Some memory allocation problems occured. Just
1823 1825 * ignore the server and hope there will be some
1824 1826 * other good ones.
1825 1827 */
1826 1828 (*new_list)->nsServers[i]->status =
1827 1829 INFO_SERVER_ERROR;
1828 1830 }
1829 1831 free(status);
1830 1832 }
1831 1833 }
1832 1834
1833 1835 __s_api_free2dArray(serverList);
1834 1836 free(thrPool);
1835 1837
1836 1838 if (retCode == NS_LDAP_MEMORY) {
1837 1839 (void) disposeOfOldList(*new_list);
1838 1840 return (NS_LDAP_MEMORY);
1839 1841 }
1840 1842
1841 1843 return (NS_LDAP_SUCCESS);
1842 1844 }
1843 1845
1844 1846 /*
1845 1847 * This functions replaces the local list of root DSEs with a new one and starts
1846 1848 * a thread destroying the old list. There is no need for other threads to wait
1847 1849 * until the old list will be destroyed.
1848 1850 * Since it is possible that more than one thread can start creating the list,
1849 1851 * this function should be protected by mutexes to be sure that only one thread
1850 1852 * performs the initialization.
1851 1853 */
1852 1854 static
1853 1855 ns_ldap_return_code
1854 1856 initGlobalList(ns_ldap_error_t **error)
1855 1857 {
1856 1858 dir_server_list_t *new_list, *old_list;
1857 1859 ns_ldap_return_code ret_code;
1858 1860 thread_t tid;
1859 1861
1860 1862 ret_code = createDirServerList(&new_list, error);
1861 1863 if (ret_code != NS_LDAP_SUCCESS) {
1862 1864 return (ret_code);
1863 1865 }
1864 1866
1865 1867 old_list = dir_servers.list;
1866 1868 dir_servers.list = new_list;
1867 1869
1868 1870 if (old_list) {
1869 1871 (void) thr_create(NULL,
1870 1872 0,
1871 1873 disposeOfOldList,
1872 1874 old_list,
1873 1875 THR_DETACHED,
1874 1876 &tid);
1875 1877 }
1876 1878
1877 1879 return (NS_LDAP_SUCCESS);
1878 1880 }
1879 1881
1880 1882 static
1881 1883 struct {
1882 1884 char *authMech;
1883 1885 ns_auth_t auth;
1884 1886 } authArray[] = {{"none", {NS_LDAP_AUTH_NONE,
1885 1887 NS_LDAP_TLS_NONE,
1886 1888 NS_LDAP_SASL_NONE,
1887 1889 NS_LDAP_SASLOPT_NONE}},
1888 1890 {"simple", {NS_LDAP_AUTH_SIMPLE,
1889 1891 NS_LDAP_TLS_NONE,
1890 1892 NS_LDAP_SASL_NONE,
1891 1893 NS_LDAP_SASLOPT_NONE}},
1892 1894 {"tls:simple", {NS_LDAP_AUTH_TLS,
1893 1895 NS_LDAP_TLS_SIMPLE,
1894 1896 NS_LDAP_SASL_NONE,
1895 1897 NS_LDAP_SASLOPT_NONE}},
1896 1898 {"tls:sasl/CRAM-MD5", {NS_LDAP_AUTH_TLS,
1897 1899 NS_LDAP_TLS_SASL,
1898 1900 NS_LDAP_SASL_CRAM_MD5,
1899 1901 NS_LDAP_SASLOPT_NONE}},
1900 1902 {"tls:sasl/DIGEST-MD5", {NS_LDAP_AUTH_TLS,
1901 1903 NS_LDAP_TLS_SASL,
1902 1904 NS_LDAP_SASL_DIGEST_MD5,
1903 1905 NS_LDAP_SASLOPT_NONE}},
1904 1906 {"sasl/CRAM-MD5", {NS_LDAP_AUTH_SASL,
1905 1907 NS_LDAP_TLS_SASL,
1906 1908 NS_LDAP_SASL_CRAM_MD5,
1907 1909 NS_LDAP_SASLOPT_NONE}},
1908 1910 {"sasl/DIGEST-MD5", {NS_LDAP_AUTH_SASL,
1909 1911 NS_LDAP_TLS_SASL,
1910 1912 NS_LDAP_SASL_DIGEST_MD5,
1911 1913 NS_LDAP_SASLOPT_NONE}},
1912 1914 {"sasl/GSSAPI", {NS_LDAP_AUTH_SASL,
1913 1915 NS_LDAP_TLS_SASL,
1914 1916 NS_LDAP_SASL_GSSAPI,
1915 1917 NS_LDAP_SASLOPT_PRIV | NS_LDAP_SASLOPT_INT}},
1916 1918 {NULL, {NS_LDAP_AUTH_NONE,
1917 1919 NS_LDAP_TLS_NONE,
1918 1920 NS_LDAP_SASL_NONE,
1919 1921 NS_LDAP_SASLOPT_NONE}}};
1920 1922
1921 1923 ns_ldap_return_code
1922 1924 __ns_ldap_initAuth(const char *auth_mech,
1923 1925 ns_auth_t *auth,
1924 1926 ns_ldap_error_t **errorp)
1925 1927 {
1926 1928 uint32_t i;
1927 1929 char errmsg[MAXERROR];
1928 1930
1929 1931 if (auth_mech == NULL) {
1930 1932 (void) snprintf(errmsg,
1931 1933 sizeof (errmsg),
1932 1934 gettext("Invalid authentication method specified\n"));
1933 1935 MKERROR(LOG_WARNING,
1934 1936 *errorp,
1935 1937 NS_LDAP_INTERNAL,
1936 1938 strdup(errmsg),
1937 1939 NS_LDAP_MEMORY);
1938 1940 return (NS_LDAP_INTERNAL);
1939 1941 }
1940 1942
1941 1943 for (i = 0; authArray[i].authMech != NULL; ++i) {
1942 1944 if (strcasecmp(auth_mech, authArray[i].authMech) == 0) {
1943 1945 *auth = authArray[i].auth;
1944 1946 return (NS_LDAP_SUCCESS);
1945 1947 }
1946 1948 }
1947 1949
1948 1950 (void) snprintf(errmsg,
1949 1951 sizeof (errmsg),
1950 1952 gettext("Invalid authentication method specified\n"));
1951 1953 MKERROR(LOG_WARNING,
1952 1954 *errorp,
1953 1955 NS_LDAP_INTERNAL,
1954 1956 strdup(errmsg),
1955 1957 NS_LDAP_MEMORY);
1956 1958 return (NS_LDAP_INTERNAL);
1957 1959 }
1958 1960
1959 1961 /*
1960 1962 * This function "informs" libsldap that a client application has specified
1961 1963 * a directory to use. The function obtains a DUAProfile, credentials,
1962 1964 * and naming context. During all further operations on behalf
1963 1965 * of the application requested a standalone schema libsldap will use
1964 1966 * the information obtained by __ns_ldap_initStandalone() instead of
1965 1967 * door_call(3C)ing ldap_cachemgr(1M).
1966 1968 *
1967 1969 * INPUT:
1968 1970 * sa_conf - a structure describing where and in which way to obtain all
1969 1971 * the configuration describing how to communicate to
1970 1972 * a choosen LDAP directory,
1971 1973 * errorp - an error object describing an error occured.
1972 1974 */
1973 1975 ns_ldap_return_code
1974 1976 __ns_ldap_initStandalone(const ns_standalone_conf_t *sa_conf,
1975 1977 ns_ldap_error_t **errorp) {
1976 1978
1977 1979 ns_cred_t user_cred = {{NS_LDAP_AUTH_NONE,
1978 1980 NS_LDAP_TLS_NONE,
1979 1981 NS_LDAP_SASL_NONE,
1980 1982 NS_LDAP_SASLOPT_NONE},
1981 1983 NULL,
1982 1984 {NULL, NULL}};
1983 1985 char *dua_profile = NULL;
1984 1986 char errmsg[MAXERROR];
1985 1987 ns_config_t *cfg;
1986 1988 int ret_code;
1987 1989
1988 1990 if (sa_conf->SA_BIND_DN == NULL && sa_conf->SA_BIND_PWD != NULL ||
1989 1991 sa_conf->SA_BIND_DN != NULL && sa_conf->SA_BIND_PWD == NULL) {
1990 1992 (void) snprintf(errmsg,
1991 1993 sizeof (errmsg),
1992 1994 gettext("Bind DN and bind password"
1993 1995 " must both be provided\n"));
1994 1996 MKERROR(LOG_ERR,
1995 1997 *errorp,
1996 1998 NS_CONFIG_NOTLOADED,
1997 1999 strdup(errmsg),
1998 2000 NS_LDAP_MEMORY);
1999 2001 return (NS_LDAP_INTERNAL);
2000 2002 }
2001 2003
2002 2004 switch (sa_conf->type) {
2003 2005 case NS_LDAP_SERVER:
2004 2006 if (sa_conf->SA_BIND_DN != NULL) {
2005 2007 user_cred.cred.unix_cred.userID = sa_conf->SA_BIND_DN;
2006 2008 user_cred.auth.type = NS_LDAP_AUTH_SIMPLE;
2007 2009 }
2008 2010
2009 2011 if (sa_conf->SA_BIND_PWD != NULL) {
2010 2012 user_cred.cred.unix_cred.passwd = sa_conf->SA_BIND_PWD;
2011 2013 }
2012 2014
2013 2015 if (sa_conf->SA_AUTH != NULL) {
2014 2016 user_cred.auth.type = sa_conf->SA_AUTH->type;
2015 2017 user_cred.auth.tlstype = sa_conf->SA_AUTH->tlstype;
2016 2018 user_cred.auth.saslmech = sa_conf->SA_AUTH->saslmech;
2017 2019 user_cred.auth.saslopt = sa_conf->SA_AUTH->saslopt;
2018 2020 }
2019 2021
2020 2022 if (sa_conf->SA_CERT_PATH != NULL) {
2021 2023 user_cred.hostcertpath = sa_conf->SA_CERT_PATH;
2022 2024 }
2023 2025
2024 2026 ret_code = __ns_ldap_getConnectionInfoFromDUA(
2025 2027 &sa_conf->ds_profile.server,
2026 2028 &user_cred,
2027 2029 &dua_profile,
2028 2030 NULL,
2029 2031 errorp);
2030 2032 if (ret_code != NS_LDAP_SUCCESS) {
2031 2033 return (ret_code);
2032 2034 }
2033 2035
2034 2036 cfg = __s_api_create_config_door_str(dua_profile, errorp);
2035 2037 if (cfg == NULL) {
2036 2038 free(dua_profile);
2037 2039 return (NS_LDAP_CONFIG);
2038 2040 }
2039 2041
2040 2042 if (sa_conf->SA_CERT_PATH != NULL) {
2041 2043 char *certPathAttr;
2042 2044 ParamIndexType type;
2043 2045
2044 2046 switch (cfg->version) {
2045 2047 case NS_LDAP_V1:
2046 2048 certPathAttr = "NS_LDAP_CERT_PATH";
2047 2049 break;
2048 2050 default: /* Version 2 */
2049 2051 certPathAttr = "NS_LDAP_HOST_CERTPATH";
2050 2052 break;
2051 2053 }
2052 2054
2053 2055 if (__s_api_get_versiontype(cfg,
2054 2056 certPathAttr,
2055 2057 &type) == 0 &&
2056 2058 (ret_code = __ns_ldap_setParamValue(cfg,
2057 2059 type,
2058 2060 sa_conf->SA_CERT_PATH,
2059 2061 errorp)) != NS_LDAP_SUCCESS) {
2060 2062 __s_api_destroy_config(cfg);
2061 2063 return (ret_code);
2062 2064 }
2063 2065 }
2064 2066
2065 2067 if (sa_conf->SA_BIND_DN != NULL &&
2066 2068 sa_conf->SA_BIND_PWD != NULL) {
2067 2069 char *authMethods;
2068 2070
2069 2071 authMethods = __s_api_strValue(cfg, NS_LDAP_AUTH_P,
2070 2072 NS_FILE_FMT);
2071 2073 if (authMethods != NULL &&
2072 2074 strstr(authMethods, "sasl/GSSAPI") != NULL) {
2073 2075 /*
2074 2076 * The received DUAProfile specifies
2075 2077 * sasl/GSSAPI as an auth. mechanism.
2076 2078 * The bind DN and password will be
2077 2079 * ignored.
2078 2080 */
2079 2081 syslog(LOG_INFO, gettext("sasl/GSSAPI will be "
2080 2082 "used as an authentication method. "
2081 2083 "The bind DN and password will "
2082 2084 "be ignored.\n"));
2083 2085 free(authMethods);
2084 2086 break;
2085 2087 }
2086 2088
2087 2089 if (authMethods != NULL)
2088 2090 free(authMethods);
2089 2091
2090 2092 if (__ns_ldap_setParamValue(cfg,
2091 2093 NS_LDAP_BINDDN_P,
2092 2094 sa_conf->SA_BIND_DN,
2093 2095 errorp) != NS_LDAP_SUCCESS) {
2094 2096 __s_api_destroy_config(cfg);
2095 2097 return (NS_LDAP_CONFIG);
2096 2098 }
2097 2099
2098 2100 if (__ns_ldap_setParamValue(cfg,
2099 2101 NS_LDAP_BINDPASSWD_P,
2100 2102 sa_conf->SA_BIND_PWD,
2101 2103 errorp) != NS_LDAP_SUCCESS) {
2102 2104 __s_api_destroy_config(cfg);
2103 2105 return (NS_LDAP_CONFIG);
2104 2106 }
2105 2107 }
2106 2108
2107 2109 break;
2108 2110 default: /* NS_CACHEMGR */
2109 2111 return (NS_LDAP_SUCCESS);
2110 2112 }
2111 2113
2112 2114 __s_api_init_config(cfg);
2113 2115 /* Connection management should use the new config now. */
2114 2116 __s_api_reinit_conn_mgmt_new_config(cfg);
2115 2117 __ns_ldap_setServer(TRUE);
2116 2118
2117 2119 (void) mutex_lock(&dir_servers.listReplaceLock);
2118 2120 if ((ret_code = initGlobalList(errorp)) != NS_SUCCESS) {
2119 2121 (void) mutex_unlock(&dir_servers.listReplaceLock);
2120 2122 return (ret_code);
2121 2123 }
2122 2124 dir_servers.standalone = 1;
2123 2125 (void) mutex_unlock(&dir_servers.listReplaceLock);
2124 2126
2125 2127 return (NS_LDAP_SUCCESS);
2126 2128 }
2127 2129
2128 2130 /*
2129 2131 * INPUT:
2130 2132 * serverAddr is the address of a server and
2131 2133 * request is one of the following:
2132 2134 * NS_CACHE_NEW: get a new server address, addr is ignored.
2133 2135 * NS_CACHE_NORESP: get the next one, remove addr from list.
2134 2136 * NS_CACHE_NEXT: get the next one, keep addr on list.
2135 2137 * NS_CACHE_WRITE: get a non-replica server, if possible, if not, same
2136 2138 * as NS_CACHE_NEXT.
2137 2139 * addrType:
2138 2140 * NS_CACHE_ADDR_IP: return server address as is, this is default.
2139 2141 * NS_CACHE_ADDR_HOSTNAME: return server addess as FQDN format, only
2140 2142 * self credential case requires such format.
2141 2143 * OUTPUT:
2142 2144 * ret
2143 2145 *
2144 2146 * a structure of type ns_server_info_t containing the server address
2145 2147 * or name, server controls and supported SASL mechanisms.
2146 2148 * NOTE: Caller should allocate space for the structure and free
2147 2149 * all the space allocated by the function for the information contained
2148 2150 * in the structure.
2149 2151 *
2150 2152 * error - an error object describing an error, if any.
2151 2153 */
2152 2154 ns_ldap_return_code
2153 2155 __s_api_findRootDSE(const char *request,
2154 2156 const char *serverAddr,
2155 2157 const char *addrType,
2156 2158 ns_server_info_t *ret,
2157 2159 ns_ldap_error_t **error)
2158 2160 {
2159 2161 dir_server_list_t *current_list = NULL;
2160 2162 ns_ldap_return_code ret_code;
2161 2163 long i = 0;
2162 2164 int matched = FALSE;
2163 2165 dir_server_t *server = NULL;
2164 2166 char errmsg[MAXERROR];
2165 2167
2166 2168 (void) mutex_lock(&dir_servers.listReplaceLock);
2167 2169 if (dir_servers.list == NULL) {
2168 2170 (void) mutex_unlock(&dir_servers.listReplaceLock);
2169 2171 (void) snprintf(errmsg,
2170 2172 sizeof (errmsg),
2171 2173 gettext("The list of root DSEs is empty: "
2172 2174 "the Standalone mode was not properly initialized"));
2173 2175 MKERROR(LOG_ERR,
2174 2176 *error,
2175 2177 NS_CONFIG_NOTLOADED,
2176 2178 strdup(errmsg),
2177 2179 NS_LDAP_MEMORY);
2178 2180 return (NS_LDAP_INTERNAL);
2179 2181 }
2180 2182
2181 2183 current_list = dir_servers.list;
2182 2184 (void) rw_rdlock(¤t_list->listDestroyLock);
2183 2185 (void) mutex_unlock(&dir_servers.listReplaceLock);
2184 2186
2185 2187 /*
2186 2188 * The code below is mostly the clone of the
2187 2189 * ldap_cachemgr::cachemgr_getldap.c::getldap_get_serverInfo() function.
2188 2190 * Currently we have two different server lists: one is maintained
2189 2191 * by libsldap ('standalone' mode), the other is in ldap_cachemgr
2190 2192 * (a part of its standard functionality).
2191 2193 */
2192 2194
2193 2195 /*
2194 2196 * If NS_CACHE_NEW, or the server info is new,
2195 2197 * starts from the beginning of the list.
2196 2198 */
2197 2199 (void) mutex_lock(¤t_list->nsServers[0]->updateStatus);
2198 2200 if (strcmp(request, NS_CACHE_NEW) == 0 ||
2199 2201 current_list->nsServers[0]->info == INFO_STATUS_NEW) {
2200 2202 matched = TRUE;
2201 2203 }
2202 2204 (void) mutex_unlock(¤t_list->nsServers[i]->updateStatus);
2203 2205
2204 2206 for (i = 0; current_list->nsServers[i]; ++i) {
2205 2207 /*
2206 2208 * Lock the updateStatus mutex to
2207 2209 * make sure the server status stays the same
2208 2210 * while the data is being processed.
2209 2211 */
2210 2212 if (matched == FALSE &&
2211 2213 strcmp(current_list->nsServers[i]->ip,
2212 2214 serverAddr) == 0) {
2213 2215 matched = TRUE;
2214 2216 if (strcmp(request, NS_CACHE_NORESP) == 0) {
2215 2217
2216 2218 /*
2217 2219 * if the server has already been removed,
2218 2220 * don't bother.
2219 2221 */
2220 2222 (void) mutex_lock(¤t_list->
2221 2223 nsServers[i]->updateStatus);
2222 2224 if (current_list->nsServers[i]->status ==
2223 2225 INFO_SERVER_REMOVED) {
2224 2226 (void) mutex_unlock(¤t_list->
2225 2227 nsServers[i]->
2226 2228 updateStatus);
2227 2229 continue;
2228 2230 }
2229 2231 (void) mutex_unlock(¤t_list->
2230 2232 nsServers[i]->
2231 2233 updateStatus);
2232 2234
2233 2235 /*
2234 2236 * if the information is new,
2235 2237 * give this server one more chance.
2236 2238 */
2237 2239 (void) mutex_lock(¤t_list->
2238 2240 nsServers[i]->
2239 2241 updateStatus);
2240 2242 if (current_list->nsServers[i]->info ==
2241 2243 INFO_STATUS_NEW &&
2242 2244 current_list->nsServers[i]->status ==
2243 2245 INFO_SERVER_UP) {
2244 2246 server = current_list->nsServers[i];
2245 2247 (void) mutex_unlock(¤t_list->
2246 2248 nsServers[i]->
2247 2249 updateStatus);
2248 2250 break;
2249 2251 } else {
2250 2252 /*
2251 2253 * it is recommended that
2252 2254 * before removing the
2253 2255 * server from the list,
2254 2256 * the server should be
2255 2257 * contacted one more time
2256 2258 * to make sure that it is
2257 2259 * really unavailable.
2258 2260 * For now, just trust the client
2259 2261 * (i.e., the sldap library)
2260 2262 * that it knows what it is
2261 2263 * doing and would not try
2262 2264 * to mess up the server
2263 2265 * list.
2264 2266 */
2265 2267 current_list->nsServers[i]->status =
2266 2268 INFO_SERVER_REMOVED;
2267 2269 (void) mutex_unlock(¤t_list->
2268 2270 nsServers[i]->
2269 2271 updateStatus);
2270 2272 continue;
2271 2273 }
2272 2274 } else {
2273 2275 /*
2274 2276 * req == NS_CACHE_NEXT or NS_CACHE_WRITE
2275 2277 */
2276 2278 continue;
2277 2279 }
2278 2280 }
2279 2281
2280 2282 if (matched) {
2281 2283 if (strcmp(request, NS_CACHE_WRITE) == 0) {
2282 2284 /*
2283 2285 * ldap_cachemgr checks here if the server
2284 2286 * is not a non-replica server (a server
2285 2287 * of type INFO_RW_WRITEABLE). But currently
2286 2288 * it considers all the servers in its list
2287 2289 * as those.
2288 2290 */
2289 2291 (void) mutex_lock(¤t_list->
2290 2292 nsServers[i]->
2291 2293 updateStatus);
2292 2294 if (current_list->nsServers[i]->status ==
2293 2295 INFO_SERVER_UP) {
2294 2296 (void) mutex_unlock(¤t_list->
2295 2297 nsServers[i]->
2296 2298 updateStatus);
2297 2299 server = current_list->nsServers[i];
2298 2300 break;
2299 2301 }
2300 2302 } else {
2301 2303 (void) mutex_lock(¤t_list->
2302 2304 nsServers[i]->
2303 2305 updateStatus);
2304 2306 if (current_list->nsServers[i]->status ==
2305 2307 INFO_SERVER_UP) {
2306 2308 (void) mutex_unlock(¤t_list->
2307 2309 nsServers[i]->
2308 2310 updateStatus);
2309 2311 server = current_list->nsServers[i];
2310 2312 break;
2311 2313 }
2312 2314 }
2313 2315
2314 2316 (void) mutex_unlock(¤t_list->
2315 2317 nsServers[i]->
2316 2318 updateStatus);
2317 2319 }
2318 2320 }
2319 2321
2320 2322 if (server == NULL) {
2321 2323 (void) rw_unlock(¤t_list->listDestroyLock);
2322 2324 (void) snprintf(errmsg,
2323 2325 sizeof (errmsg),
2324 2326 gettext("No servers are available"));
2325 2327 MKERROR(LOG_ERR,
2326 2328 *error,
2327 2329 NS_CONFIG_NOTLOADED,
2328 2330 strdup(errmsg),
2329 2331 NS_LDAP_MEMORY);
2330 2332 return (NS_LDAP_NOTFOUND);
2331 2333 }
2332 2334
2333 2335 (void) mutex_lock(&server->updateStatus);
2334 2336 server->info = INFO_STATUS_OLD;
2335 2337 (void) mutex_unlock(&server->updateStatus);
2336 2338
2337 2339 if (ret == NULL) {
2338 2340 (void) rw_unlock(¤t_list->listDestroyLock);
2339 2341 return (NS_LDAP_SUCCESS);
2340 2342 }
2341 2343
2342 2344 if (strcmp(addrType, NS_CACHE_ADDR_HOSTNAME) == 0) {
2343 2345 ret_code = __s_api_ip2hostname(server->ip, &ret->serverFQDN);
2344 2346 if (ret_code != NS_LDAP_SUCCESS) {
2345 2347 (void) snprintf(errmsg,
2346 2348 sizeof (errmsg),
2347 2349 gettext("The %s address "
2348 2350 "can not be resolved into "
2349 2351 "a host name. Returning "
2350 2352 "the address as it is."),
2351 2353 server->ip);
2352 2354 MKERROR(LOG_ERR,
2353 2355 *error,
2354 2356 NS_CONFIG_NOTLOADED,
2355 2357 strdup(errmsg),
2356 2358 NS_LDAP_MEMORY);
2357 2359 return (NS_LDAP_INTERNAL);
2358 2360 }
2359 2361 }
2360 2362
2361 2363 ret->server = strdup(server->ip);
2362 2364
2363 2365 ret->controls = __s_api_cp2dArray(server->controls);
2364 2366 ret->saslMechanisms = __s_api_cp2dArray(server->saslMech);
2365 2367
2366 2368 (void) rw_unlock(¤t_list->listDestroyLock);
2367 2369
2368 2370 return (NS_LDAP_SUCCESS);
2369 2371 }
2370 2372
2371 2373 /*
2372 2374 * This function iterates through the list of the configured LDAP servers
2373 2375 * and "pings" those which are marked as removed or if any error occurred
2374 2376 * during the previous receiving of the server's root DSE. If the
2375 2377 * function is able to reach such a server and get its root DSE, it
2376 2378 * marks the server as on-line. Otherwise, the server's status is set
2377 2379 * to "Error".
2378 2380 * For each server the function tries to connect to, it fires up
2379 2381 * a separate thread and then waits until all the treads finish.
2380 2382 * The function returns NS_LDAP_INTERNAL if the Standalone mode was not
2381 2383 * initialized or was canceled prior to an invocation of
2382 2384 * __ns_ldap_pingOfflineServers().
2383 2385 */
2384 2386 ns_ldap_return_code
2385 2387 __ns_ldap_pingOfflineServers(void)
2386 2388 {
2387 2389 dir_server_list_t *current_list = NULL;
2388 2390 ns_ldap_return_code retCode = NS_LDAP_SUCCESS;
2389 2391 long srvListLength, i = 0;
2390 2392 thread_t *thrPool, thrID;
2391 2393 void *status = NULL;
2392 2394
2393 2395 (void) mutex_lock(&dir_servers.listReplaceLock);
2394 2396 if (dir_servers.list == NULL) {
2395 2397 (void) mutex_unlock(&dir_servers.listReplaceLock);
2396 2398 return (NS_LDAP_INTERNAL);
2397 2399 }
2398 2400
2399 2401 current_list = dir_servers.list;
2400 2402 (void) rw_wrlock(¤t_list->listDestroyLock);
2401 2403 (void) mutex_unlock(&dir_servers.listReplaceLock);
2402 2404
2403 2405 while (current_list->nsServers[i] != NULL) {
2404 2406 ++i;
2405 2407 }
2406 2408 srvListLength = i;
2407 2409
2408 2410 thrPool = calloc(srvListLength, sizeof (thread_t));
2409 2411 if (thrPool == NULL) {
2410 2412 (void) rw_unlock(¤t_list->listDestroyLock);
2411 2413 return (NS_LDAP_MEMORY);
2412 2414 }
2413 2415
2414 2416 for (i = 0; i < srvListLength; ++i) {
2415 2417 if (current_list->nsServers[i]->status != INFO_SERVER_REMOVED &&
2416 2418 current_list->nsServers[i]->status != INFO_SERVER_ERROR) {
2417 2419 continue;
2418 2420 }
2419 2421 current_list->nsServers[i]->status = INFO_SERVER_CONNECTING;
2420 2422 current_list->nsServers[i]->info = INFO_STATUS_NEW;
2421 2423
2422 2424 __s_api_free2dArray(current_list->nsServers[i]->controls);
2423 2425 current_list->nsServers[i]->controls = NULL;
2424 2426 __s_api_free2dArray(current_list->nsServers[i]->saslMech);
2425 2427 current_list->nsServers[i]->saslMech = NULL;
2426 2428
2427 2429 switch (thr_create(NULL,
2428 2430 0,
2429 2431 create_ns_servers_entry,
2430 2432 current_list->nsServers[i],
2431 2433 0,
2432 2434 &thrID)) {
2433 2435 case EAGAIN:
2434 2436 current_list->nsServers[i]->status = INFO_SERVER_ERROR;
2435 2437 continue;
2436 2438 case ENOMEM:
2437 2439 current_list->nsServers[i]->status = INFO_SERVER_ERROR;
2438 2440 retCode = NS_LDAP_MEMORY;
2439 2441 break;
2440 2442 default:
2441 2443 thrPool[i] = thrID;
2442 2444 continue;
2443 2445 }
2444 2446 /* A memory allocation error has occured */
2445 2447 break;
2446 2448
2447 2449 }
2448 2450
2449 2451 for (i = 0; i < srvListLength; ++i) {
2450 2452 if (thrPool[i] != 0 &&
2451 2453 thr_join(thrPool[i], NULL, &status) == 0) {
2452 2454 if (status == NULL) {
2453 2455 current_list->nsServers[i]->status =
2454 2456 INFO_SERVER_ERROR;
2455 2457 retCode = NS_LDAP_MEMORY;
2456 2458 }
2457 2459 free(status);
2458 2460 }
2459 2461 }
2460 2462
2461 2463 (void) rw_unlock(¤t_list->listDestroyLock);
2462 2464
2463 2465 free(thrPool);
2464 2466
2465 2467 return (retCode);
2466 2468 }
↓ open down ↓ |
1004 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX