Print this page
8158 Want named threads API
9857 proc manpages should have LIBRARY section
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/cmd/ldapcachemgr/cachemgr_getldap.c
+++ new/usr/src/cmd/ldapcachemgr/cachemgr_getldap.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 + *
24 + * Copyright 2018 Joyent, Inc.
23 25 */
24 26
25 27 #include <assert.h>
26 28 #include <errno.h>
27 29 #include <memory.h>
28 30 #include <signal.h>
29 31 #include <stdlib.h>
30 32 #include <stdio.h>
31 33 #include <string.h>
32 34 #include <libintl.h>
33 35 #include <syslog.h>
34 36 #include <sys/door.h>
35 37 #include <sys/stat.h>
36 38 #include <sys/time.h>
37 39 #include <sys/types.h>
38 40 #include <sys/wait.h>
39 41 #include <synch.h>
40 42 #include <pthread.h>
41 43 #include <unistd.h>
42 44 #include <lber.h>
43 45 #include <ldap.h>
44 46 #include <ctype.h> /* tolower */
45 47 #include <sys/socket.h>
46 48 #include <netinet/in.h>
47 49 #include <arpa/inet.h>
48 50 #include <ucred.h>
49 51 #include "cachemgr.h"
50 52 #include "solaris-priv.h"
51 53 #include "ns_connmgmt.h"
52 54
53 55 static rwlock_t ldap_lock = DEFAULTRWLOCK;
54 56 static int sighup_update = FALSE;
55 57 extern admin_t current_admin;
56 58
57 59 extern int is_root_or_all_privs(char *dc_str, ucred_t **ucp);
58 60
59 61 /* variables used for SIGHUP wakeup on sleep */
60 62 static mutex_t sighuplock;
61 63 static cond_t cond;
62 64
63 65 /* refresh time statistics */
64 66 static time_t prev_refresh_time = 0;
65 67
66 68 /* variables used for signaling parent process */
67 69 static mutex_t sig_mutex;
68 70 static int signal_done = FALSE;
69 71
70 72 /* TCP connection timeout (in milliseconds) */
71 73 static int tcptimeout = NS_DEFAULT_BIND_TIMEOUT * 1000;
72 74
73 75 #ifdef SLP
74 76 extern int use_slp;
75 77 #endif /* SLP */
76 78
77 79 /* nis domain information */
78 80 #define _NIS_FILTER "objectclass=nisDomainObject"
79 81 #define _NIS_DOMAIN "nisdomain"
80 82
81 83 #define CACHESLEEPTIME 600
82 84 /*
83 85 * server list refresh delay when in "no server" mode
84 86 * (1 second)
85 87 */
86 88 #define REFRESH_DELAY_WHEN_NO_SERVER 1
87 89
88 90 typedef enum {
89 91 INFO_OP_CREATE = 0,
90 92 INFO_OP_DELETE = 1,
91 93 INFO_OP_REFRESH = 2,
92 94 INFO_OP_REFRESH_WAIT = 3,
93 95 INFO_OP_GETSERVER = 4,
94 96 INFO_OP_GETSTAT = 5,
95 97 INFO_OP_REMOVESERVER = 6
96 98 } info_op_t;
97 99
98 100 typedef enum {
99 101 INFO_RW_UNKNOWN = 0,
100 102 INFO_RW_READONLY = 1,
101 103 INFO_RW_WRITEABLE = 2
102 104 } info_rw_t;
103 105
104 106 typedef enum {
105 107 INFO_SERVER_JUST_INITED = -1,
106 108 INFO_SERVER_UNKNOWN = 0,
107 109 INFO_SERVER_CONNECTING = 1,
108 110 INFO_SERVER_UP = 2,
109 111 INFO_SERVER_ERROR = 3,
110 112 INFO_SERVER_REMOVED = 4
111 113 } info_server_t;
112 114
113 115 typedef enum {
114 116 INFO_STATUS_UNKNOWN = 0,
115 117 INFO_STATUS_ERROR = 1,
116 118 INFO_STATUS_NEW = 2,
117 119 INFO_STATUS_OLD = 3
118 120 } info_status_t;
119 121
120 122 typedef enum {
121 123 CACHE_OP_CREATE = 0,
122 124 CACHE_OP_DELETE = 1,
123 125 CACHE_OP_FIND = 2,
124 126 CACHE_OP_ADD = 3,
125 127 CACHE_OP_GETSTAT = 4
126 128 } cache_op_t;
127 129
128 130 typedef enum {
129 131 CACHE_MAP_UNKNOWN = 0,
130 132 CACHE_MAP_DN2DOMAIN = 1
131 133 } cache_type_t;
132 134
133 135 typedef struct server_info_ext {
134 136 char *addr;
135 137 char *hostname;
136 138 char *rootDSE_data;
137 139 char *errormsg;
138 140 info_rw_t type;
139 141 info_server_t server_status;
140 142 info_server_t prev_server_status;
141 143 info_status_t info_status;
142 144 ns_server_status_t change;
143 145 } server_info_ext_t;
144 146
145 147 typedef struct server_info {
146 148 struct server_info *next;
147 149 mutex_t mutex[2]; /* 0: current copy lock */
148 150 /* 1: update copy lock */
149 151 server_info_ext_t sinfo[2]; /* 0: current, 1: update copy */
150 152 } server_info_t;
151 153
152 154 typedef struct cache_hash {
153 155 cache_type_t type;
154 156 char *from;
155 157 char *to;
156 158 struct cache_hash *next;
157 159 } cache_hash_t;
158 160
159 161 /*
160 162 * The status of a server to be removed. It can be up or down.
161 163 */
162 164 typedef struct rm_svr {
163 165 char *addr;
164 166 int up; /* 1: up, 0: down */
165 167 } rm_svr_t;
166 168
167 169 static int getldap_destroy_serverInfo(server_info_t *head);
168 170 static void test_server_change(server_info_t *head);
169 171 static void remove_server(char *addr);
170 172 static ns_server_status_t set_server_status(char *input, server_info_t *head);
171 173 static void create_buf_and_notify(char *input, ns_server_status_t st);
172 174
173 175 /*
174 176 * Load configuration
175 177 * The code was in signal handler getldap_revalidate
176 178 * It's moved out of the handler because it could cause deadlock
177 179 * return: 1 SUCCESS
178 180 * 0 FAIL
179 181 */
180 182 static int
181 183 load_config() {
182 184 ns_ldap_error_t *error;
183 185 int rc = 1;
184 186
185 187 (void) __ns_ldap_setServer(TRUE);
186 188
187 189 (void) rw_wrlock(&ldap_lock);
188 190 if ((error = __ns_ldap_LoadConfiguration()) != NULL) {
189 191 logit("Error: Unable to read '%s': %s\n",
190 192 NSCONFIGFILE, error->message);
191 193 __ns_ldap_freeError(&error);
192 194 rc = 0; /* FAIL */
193 195 } else
194 196 sighup_update = TRUE;
195 197
196 198 (void) rw_unlock(&ldap_lock);
197 199
198 200 return (rc);
199 201 }
200 202
201 203 /*
202 204 * Calculate a hash for a string
203 205 * Based on elf_hash algorithm, hash is case insensitive
204 206 * Uses tolower instead of _tolower because of I18N
205 207 */
206 208
207 209 static unsigned long
208 210 getldap_hash(const char *str)
209 211 {
210 212 unsigned int hval = 0;
211 213
212 214 while (*str) {
213 215 unsigned int g;
214 216
215 217 hval = (hval << 4) + tolower(*str++);
216 218 if ((g = (hval & 0xf0000000)) != 0)
217 219 hval ^= g >> 24;
218 220 hval &= ~g;
219 221 }
220 222 return ((unsigned long)hval);
221 223 }
222 224
223 225 /*
224 226 * Remove a hash table entry.
225 227 * This function expects a lock in place when called.
226 228 */
227 229
228 230 static cache_hash_t *
229 231 getldap_free_hash(cache_hash_t *p)
230 232 {
231 233 cache_hash_t *next;
232 234
233 235 p->type = CACHE_MAP_UNKNOWN;
234 236 if (p->from)
235 237 free(p->from);
236 238 if (p->to)
237 239 free(p->to);
238 240 next = p->next;
239 241 p->next = NULL;
240 242 free(p);
241 243 return (next);
242 244 }
243 245
244 246 /*
245 247 * Scan a hash table hit for a matching hash entry.
246 248 * This function expects a lock in place when called.
247 249 */
248 250 static cache_hash_t *
249 251 getldap_scan_hash(cache_type_t type, char *from,
250 252 cache_hash_t *idx)
251 253 {
252 254 while (idx) {
253 255 if (idx->type == type &&
254 256 strcasecmp(from, idx->from) == 0) {
255 257 return (idx);
256 258 }
257 259 idx = idx->next;
258 260 }
259 261 return ((cache_hash_t *)NULL);
260 262 }
261 263
262 264 /*
263 265 * Format and return the cache data statistics
264 266 */
265 267 static int
266 268 getldap_get_cacheData_stat(int max, int current, char **output)
267 269 {
268 270 #define C_HEADER0 "Cache data information: "
269 271 #define C_HEADER1 " Maximum cache entries: "
270 272 #define C_HEADER2 " Number of cache entries: "
271 273 int hdr0_len = strlen(gettext(C_HEADER0));
272 274 int hdr1_len = strlen(gettext(C_HEADER1));
273 275 int hdr2_len = strlen(gettext(C_HEADER2));
274 276 int len;
275 277
276 278 if (current_admin.debug_level >= DBG_ALL) {
277 279 logit("getldap_get_cacheData_stat()...\n");
278 280 }
279 281
280 282 *output = NULL;
281 283
282 284 len = hdr0_len + hdr1_len + hdr2_len +
283 285 3 * strlen(DOORLINESEP) + 21;
284 286 *output = malloc(len);
285 287 if (*output == NULL)
286 288 return (-1);
287 289
288 290 (void) snprintf(*output, len, "%s%s%s%10d%s%s%10d%s",
289 291 gettext(C_HEADER0), DOORLINESEP,
290 292 gettext(C_HEADER1), max, DOORLINESEP,
291 293 gettext(C_HEADER2), current, DOORLINESEP);
292 294
293 295 return (NS_LDAP_SUCCESS);
294 296 }
295 297
296 298 static int
297 299 getldap_cache_op(cache_op_t op, cache_type_t type,
298 300 char *from, char **to)
299 301 {
300 302 #define CACHE_HASH_MAX 257
301 303 #define CACHE_HASH_MAX_ENTRY 256
302 304 static cache_hash_t *hashTbl[CACHE_HASH_MAX];
303 305 cache_hash_t *next, *idx, *newp;
304 306 unsigned long hash;
305 307 static rwlock_t cache_lock = DEFAULTRWLOCK;
306 308 int i;
307 309 static int entry_num = 0;
308 310
309 311 if (current_admin.debug_level >= DBG_ALL) {
310 312 logit("getldap_cache_op()...\n");
311 313 }
312 314 switch (op) {
313 315 case CACHE_OP_CREATE:
314 316 if (current_admin.debug_level >= DBG_ALL) {
315 317 logit("operation is CACHE_OP_CREATE...\n");
316 318 }
317 319 (void) rw_wrlock(&cache_lock);
318 320
319 321 for (i = 0; i < CACHE_HASH_MAX; i++) {
320 322 hashTbl[i] = NULL;
321 323 }
322 324 entry_num = 0;
323 325
324 326 (void) rw_unlock(&cache_lock);
325 327 break;
326 328
327 329 case CACHE_OP_DELETE:
328 330 if (current_admin.debug_level >= DBG_ALL) {
329 331 logit("operation is CACHE_OP_DELETE...\n");
330 332 }
331 333 (void) rw_wrlock(&cache_lock);
332 334
333 335 for (i = 0; i < CACHE_HASH_MAX; i++) {
334 336 next = hashTbl[i];
335 337 while (next != NULL) {
336 338 next = getldap_free_hash(next);
337 339 }
338 340 hashTbl[i] = NULL;
339 341 }
340 342 entry_num = 0;
341 343
342 344 (void) rw_unlock(&cache_lock);
343 345 break;
344 346
345 347 case CACHE_OP_ADD:
346 348 if (current_admin.debug_level >= DBG_ALL) {
347 349 logit("operation is CACHE_OP_ADD...\n");
348 350 }
349 351 if (from == NULL || to == NULL || *to == NULL)
350 352 return (-1);
351 353 hash = getldap_hash(from) % CACHE_HASH_MAX;
352 354 (void) rw_wrlock(&cache_lock);
353 355 idx = hashTbl[hash];
354 356 /*
355 357 * replace old "to" value with new one
356 358 * if an entry with same "from"
357 359 * already exists
358 360 */
359 361 if (idx) {
360 362 newp = getldap_scan_hash(type, from, idx);
361 363 if (newp) {
362 364 free(newp->to);
363 365 newp->to = strdup(*to);
364 366 (void) rw_unlock(&cache_lock);
365 367 return (NS_LDAP_SUCCESS);
366 368 }
367 369 }
368 370
369 371 if (entry_num > CACHE_HASH_MAX_ENTRY) {
370 372 (void) rw_unlock(&cache_lock);
371 373 return (-1);
372 374 }
373 375
374 376 newp = (cache_hash_t *)malloc(sizeof (cache_hash_t));
375 377 if (newp == NULL) {
376 378 (void) rw_unlock(&cache_lock);
377 379 return (NS_LDAP_MEMORY);
378 380 }
379 381 newp->type = type;
380 382 newp->from = strdup(from);
381 383 newp->to = strdup(*to);
382 384 newp->next = idx;
383 385 hashTbl[hash] = newp;
384 386 entry_num++;
385 387 (void) rw_unlock(&cache_lock);
386 388 break;
387 389
388 390 case CACHE_OP_FIND:
389 391 if (current_admin.debug_level >= DBG_ALL) {
390 392 logit("operation is CACHE_OP_FIND...\n");
391 393 }
392 394 if (from == NULL || to == NULL)
393 395 return (-1);
394 396 *to = NULL;
395 397 hash = getldap_hash(from) % CACHE_HASH_MAX;
396 398 (void) rw_rdlock(&cache_lock);
397 399 idx = hashTbl[hash];
398 400 idx = getldap_scan_hash(type, from, idx);
399 401 if (idx)
400 402 *to = strdup(idx->to);
401 403 (void) rw_unlock(&cache_lock);
402 404 if (idx == NULL)
403 405 return (-1);
404 406 break;
405 407
406 408 case CACHE_OP_GETSTAT:
407 409 if (current_admin.debug_level >= DBG_ALL) {
408 410 logit("operation is CACHE_OP_GETSTAT...\n");
409 411 }
410 412 if (to == NULL)
411 413 return (-1);
412 414
413 415 return (getldap_get_cacheData_stat(CACHE_HASH_MAX_ENTRY,
414 416 entry_num, to));
415 417 break;
416 418
417 419 default:
418 420 logit("getldap_cache_op(): "
419 421 "invalid operation code (%d).\n", op);
420 422 return (-1);
421 423 break;
422 424 }
423 425 return (NS_LDAP_SUCCESS);
424 426 }
425 427 /*
426 428 * Function: sync_current_with_update_copy
427 429 *
428 430 * This function syncs up the 2 sinfo copies in info.
429 431 *
430 432 * The 2 copies are identical most of time.
431 433 * The update copy(sinfo[1]) could be different when
432 434 * getldap_serverInfo_refresh thread is refreshing the server list
433 435 * and calls getldap_get_rootDSE to update info. getldap_get_rootDSE
434 436 * calls sync_current_with_update_copy to sync up 2 copies before thr_exit.
435 437 * The calling sequence is
436 438 * getldap_serverInfo_refresh->
437 439 * getldap_get_serverInfo_op(INFO_OP_CREATE,...)->
438 440 * getldap_set_serverInfo->
439 441 * getldap_get_rootDSE
440 442 *
441 443 * The original server_info_t has one copy of server info. When libsldap
442 444 * makes door call GETLDAPSERVER to get the server info and getldap_get_rootDSE
443 445 * is updating the server info, it would hit a unprotected window in
444 446 * getldap_rootDSE. The door call will not get server info and libsldap
445 447 * fails at making ldap connection.
446 448 *
447 449 * The new server_info_t provides GETLDAPSERVER thread with a current
448 450 * copy(sinfo[0]). getldap_get_rootDSE only works on the update copy(sinfo[1])
449 451 * and syncs up 2 copies before thr_exit. This will close the window in
450 452 * getldap_get_rootDSE.
451 453 *
452 454 */
453 455 static void
454 456 sync_current_with_update_copy(server_info_t *info)
455 457 {
456 458 if (current_admin.debug_level >= DBG_ALL) {
457 459 logit("sync_current_with_update_copy()...\n");
458 460 }
459 461
460 462 (void) mutex_lock(&info->mutex[1]);
461 463 (void) mutex_lock(&info->mutex[0]);
462 464
463 465 if (info->sinfo[1].server_status == INFO_SERVER_UP &&
464 466 info->sinfo[0].server_status != INFO_SERVER_UP)
465 467 info->sinfo[1].change = NS_SERVER_UP;
466 468 else if (info->sinfo[1].server_status != INFO_SERVER_UP &&
467 469 info->sinfo[0].server_status == INFO_SERVER_UP)
468 470 info->sinfo[1].change = NS_SERVER_DOWN;
469 471 else
470 472 info->sinfo[1].change = 0;
471 473
472 474
473 475 /* free memory in current copy first */
474 476 if (info->sinfo[0].addr)
475 477 free(info->sinfo[0].addr);
476 478 info->sinfo[0].addr = NULL;
477 479
478 480 if (info->sinfo[0].hostname)
479 481 free(info->sinfo[0].hostname);
480 482 info->sinfo[0].hostname = NULL;
481 483
482 484 if (info->sinfo[0].rootDSE_data)
483 485 free(info->sinfo[0].rootDSE_data);
484 486 info->sinfo[0].rootDSE_data = NULL;
485 487
486 488 if (info->sinfo[0].errormsg)
487 489 free(info->sinfo[0].errormsg);
488 490 info->sinfo[0].errormsg = NULL;
489 491
490 492 /*
491 493 * make current and update copy identical
492 494 */
493 495 info->sinfo[0] = info->sinfo[1];
494 496
495 497 /*
496 498 * getldap_get_server_stat() reads the update copy sinfo[1]
497 499 * so it can't be freed or nullified yet at this point.
498 500 *
499 501 * The sinfo[0] and sinfo[1] have identical string pointers.
500 502 * strdup the strings to avoid the double free problem.
501 503 * The strings of sinfo[1] are freed in
502 504 * getldap_get_rootDSE() and the strings of sinfo[0]
503 505 * are freed earlier in this function. If the pointers are the
504 506 * same, they will be freed twice.
505 507 */
506 508 if (info->sinfo[1].addr)
507 509 info->sinfo[0].addr = strdup(info->sinfo[1].addr);
508 510 if (info->sinfo[1].hostname)
509 511 info->sinfo[0].hostname = strdup(info->sinfo[1].hostname);
510 512 if (info->sinfo[1].rootDSE_data)
511 513 info->sinfo[0].rootDSE_data =
512 514 strdup(info->sinfo[1].rootDSE_data);
513 515 if (info->sinfo[1].errormsg)
514 516 info->sinfo[0].errormsg = strdup(info->sinfo[1].errormsg);
515 517
516 518 (void) mutex_unlock(&info->mutex[0]);
517 519 (void) mutex_unlock(&info->mutex[1]);
518 520
519 521 }
520 522
521 523 static void *
522 524 getldap_get_rootDSE(void *arg)
523 525 {
524 526 server_info_t *serverInfo = (server_info_t *)arg;
525 527 char *rootDSE;
526 528 int exitrc = NS_LDAP_SUCCESS;
527 529 pid_t ppid;
528 530 int server_found = 0;
529 531 char errmsg[MAXERROR];
530 532 ns_ldap_return_code rc;
531 533 ns_ldap_error_t *error = NULL;
532 534
533 535 if (current_admin.debug_level >= DBG_ALL) {
534 536 logit("getldap_get_rootDSE()....\n");
535 537 }
536 538
537 539 /* initialize the server info element */
538 540 (void) mutex_lock(&serverInfo->mutex[1]);
539 541 serverInfo->sinfo[1].type = INFO_RW_UNKNOWN;
540 542 serverInfo->sinfo[1].info_status =
541 543 INFO_STATUS_UNKNOWN;
542 544 /*
543 545 * When the sever list is refreshed over and over,
544 546 * this function is called each time it is refreshed.
545 547 * The previous server status of the update copy(sinfo[1])
546 548 * is the status of the current copy
547 549 */
548 550 (void) mutex_lock(&serverInfo->mutex[0]);
549 551 serverInfo->sinfo[1].prev_server_status =
550 552 serverInfo->sinfo[0].server_status;
551 553 (void) mutex_unlock(&serverInfo->mutex[0]);
552 554
553 555 serverInfo->sinfo[1].server_status =
554 556 INFO_SERVER_UNKNOWN;
555 557 if (serverInfo->sinfo[1].rootDSE_data)
556 558 free(serverInfo->sinfo[1].rootDSE_data);
557 559 serverInfo->sinfo[1].rootDSE_data = NULL;
558 560 if (serverInfo->sinfo[1].errormsg)
559 561 free(serverInfo->sinfo[1].errormsg);
560 562 serverInfo->sinfo[1].errormsg = NULL;
561 563 (void) mutex_unlock(&serverInfo->mutex[1]);
562 564
563 565 (void) mutex_lock(&serverInfo->mutex[1]);
564 566 serverInfo->sinfo[1].server_status = INFO_SERVER_CONNECTING;
565 567 (void) mutex_unlock(&serverInfo->mutex[1]);
566 568
567 569 /*
568 570 * WARNING: anon_fallback == 1 (last argument) means that when
569 571 * __ns_ldap_getRootDSE is unable to bind using the configured
570 572 * credentials, it will try to fall back to using anonymous, non-SSL
571 573 * mode of operation.
572 574 *
573 575 * This is for backward compatibility reasons - we might have machines
574 576 * in the field with broken configuration (invalid credentials) and we
575 577 * don't want them to be disturbed.
576 578 */
577 579 if (rc = __ns_ldap_getRootDSE(serverInfo->sinfo[1].addr,
578 580 &rootDSE,
579 581 &error,
580 582 SA_ALLOW_FALLBACK) != NS_LDAP_SUCCESS) {
581 583 (void) mutex_lock(&serverInfo->mutex[1]);
582 584 serverInfo->sinfo[1].server_status = INFO_SERVER_ERROR;
583 585 serverInfo->sinfo[1].info_status = INFO_STATUS_ERROR;
584 586 if (error && error->message) {
585 587 serverInfo->sinfo[1].errormsg = strdup(error->message);
586 588 } else {
587 589 (void) snprintf(errmsg, sizeof (errmsg), "%s %s "
588 590 "(rc = %d)", gettext("Can not get the root DSE from"
589 591 " server"), serverInfo->sinfo[1].addr, rc);
590 592 serverInfo->sinfo[1].errormsg = strdup(errmsg);
591 593 }
592 594
593 595 if (error != NULL) {
594 596 (void) __ns_ldap_freeError(&error);
595 597 }
596 598
597 599 if (current_admin.debug_level >= DBG_ALL) {
598 600 logit("getldap_get_rootDSE: %s.\n",
599 601 serverInfo->sinfo[1].errormsg);
600 602 }
601 603 (void) mutex_unlock(&serverInfo->mutex[1]);
602 604 /*
603 605 * sync sinfo copies in the serverInfo.
604 606 * protected by mutex
605 607 */
606 608 sync_current_with_update_copy(serverInfo);
607 609 thr_exit((void *) -1);
608 610 }
609 611
610 612 (void) mutex_lock(&serverInfo->mutex[1]);
611 613
612 614 /* assume writeable, i.e., can do modify */
613 615 serverInfo->sinfo[1].type = INFO_RW_WRITEABLE;
614 616 serverInfo->sinfo[1].server_status = INFO_SERVER_UP;
615 617 serverInfo->sinfo[1].info_status = INFO_STATUS_NEW;
616 618 /* remove the last DOORLINESEP */
617 619 *(rootDSE+strlen(rootDSE)-1) = '\0';
618 620 serverInfo->sinfo[1].rootDSE_data = rootDSE;
619 621
620 622 server_found = 1;
621 623
622 624 (void) mutex_unlock(&serverInfo->mutex[1]);
623 625
624 626 /*
625 627 * sync sinfo copies in the serverInfo.
626 628 * protected by mutex
627 629 */
628 630 sync_current_with_update_copy(serverInfo);
629 631 /*
630 632 * signal that the ldap_cachemgr parent process
631 633 * should exit now, if it is still waiting
632 634 */
633 635 (void) mutex_lock(&sig_mutex);
634 636 if (signal_done == FALSE && server_found) {
635 637 ppid = getppid();
636 638 (void) kill(ppid, SIGUSR1);
637 639 if (current_admin.debug_level >= DBG_ALL) {
638 640 logit("getldap_get_rootDSE(): "
639 641 "SIGUSR1 signal sent to "
640 642 "parent process(%ld).\n", ppid);
641 643 }
642 644 signal_done = TRUE;
643 645 }
644 646 (void) mutex_unlock(&sig_mutex);
645 647
646 648 thr_exit((void *) exitrc);
647 649
648 650 return ((void *) NULL);
649 651 }
650 652
651 653 static int
652 654 getldap_init_serverInfo(server_info_t **head)
653 655 {
654 656 char **servers = NULL;
655 657 int rc = 0, i, exitrc = NS_LDAP_SUCCESS;
656 658 ns_ldap_error_t *errorp = NULL;
657 659 server_info_t *info, *tail = NULL;
658 660
659 661 *head = NULL;
660 662 if (current_admin.debug_level >= DBG_ALL) {
661 663 logit("getldap_init_serverInfo()...\n");
662 664 }
663 665 rc = __s_api_getServers(&servers, &errorp);
664 666
665 667 if (rc != NS_LDAP_SUCCESS) {
666 668 logit("getldap_init_serverInfo: "
667 669 "__s_api_getServers failed.\n");
668 670 if (errorp)
669 671 __ns_ldap_freeError(&errorp);
670 672 return (-1);
671 673 }
672 674 for (i = 0; servers[i] != NULL; i++) {
673 675 info = (server_info_t *)calloc(1, sizeof (server_info_t));
674 676 if (info == NULL) {
675 677 logit("getldap_init_serverInfo: "
676 678 "not enough memory.\n");
677 679 exitrc = NS_LDAP_MEMORY;
678 680 break;
679 681 }
680 682 if (i == 0) {
681 683 *head = info;
682 684 tail = info;
683 685 } else {
684 686 tail->next = info;
685 687 tail = info;
686 688 }
687 689
688 690 info->sinfo[0].addr = strdup(servers[i]);
689 691 if (info->sinfo[0].addr == NULL) {
690 692 logit("getldap_init_serverInfo: "
691 693 "not enough memory.\n");
692 694 exitrc = NS_LDAP_MEMORY;
693 695 break;
694 696 }
695 697 info->sinfo[1].addr = strdup(servers[i]);
696 698 if (info->sinfo[1].addr == NULL) {
697 699 logit("getldap_init_serverInfo: "
698 700 "not enough memory.\n");
699 701 exitrc = NS_LDAP_MEMORY;
700 702 break;
701 703 }
702 704
703 705 info->sinfo[0].type = INFO_RW_UNKNOWN;
704 706 info->sinfo[1].type = INFO_RW_UNKNOWN;
705 707 info->sinfo[0].info_status = INFO_STATUS_UNKNOWN;
706 708 info->sinfo[1].info_status = INFO_STATUS_UNKNOWN;
707 709 info->sinfo[0].server_status = INFO_SERVER_UNKNOWN;
708 710 info->sinfo[1].server_status = INFO_SERVER_UNKNOWN;
709 711
710 712 /*
711 713 * Assume at startup or after the configuration
712 714 * profile is refreshed, all servers are good.
713 715 */
714 716 info->sinfo[0].prev_server_status =
715 717 INFO_SERVER_UP;
716 718 info->sinfo[1].prev_server_status =
717 719 INFO_SERVER_UP;
718 720 info->sinfo[0].hostname = NULL;
719 721 info->sinfo[1].hostname = NULL;
720 722 info->sinfo[0].rootDSE_data = NULL;
721 723 info->sinfo[1].rootDSE_data = NULL;
722 724 info->sinfo[0].errormsg = NULL;
723 725 info->sinfo[1].errormsg = NULL;
724 726 info->next = NULL;
725 727 }
726 728 __s_api_free2dArray(servers);
727 729 if (exitrc != NS_LDAP_SUCCESS) {
728 730 if (head && *head) {
729 731 (void) getldap_destroy_serverInfo(*head);
730 732 *head = NULL;
731 733 }
732 734 }
733 735 return (exitrc);
734 736 }
735 737
736 738 static int
737 739 getldap_destroy_serverInfo(server_info_t *head)
738 740 {
739 741 server_info_t *info, *next;
740 742
741 743 if (current_admin.debug_level >= DBG_ALL) {
742 744 logit("getldap_destroy_serverInfo()...\n");
743 745 }
744 746
745 747 if (head == NULL) {
746 748 logit("getldap_destroy_serverInfo: "
747 749 "invalid serverInfo list.\n");
748 750 return (-1);
749 751 }
750 752
751 753 for (info = head; info; info = next) {
752 754 if (info->sinfo[0].addr)
753 755 free(info->sinfo[0].addr);
754 756 if (info->sinfo[1].addr)
755 757 free(info->sinfo[1].addr);
756 758 if (info->sinfo[0].hostname)
757 759 free(info->sinfo[0].hostname);
758 760 if (info->sinfo[1].hostname)
759 761 free(info->sinfo[1].hostname);
760 762 if (info->sinfo[0].rootDSE_data)
761 763 free(info->sinfo[0].rootDSE_data);
762 764 if (info->sinfo[1].rootDSE_data)
763 765 free(info->sinfo[1].rootDSE_data);
764 766 if (info->sinfo[0].errormsg)
765 767 free(info->sinfo[0].errormsg);
766 768 if (info->sinfo[1].errormsg)
767 769 free(info->sinfo[1].errormsg);
768 770 next = info->next;
769 771 free(info);
770 772 }
771 773 return (NS_LDAP_SUCCESS);
772 774 }
773 775
774 776 static int
775 777 getldap_set_serverInfo(server_info_t *head, int reset_bindtime, info_op_t op)
776 778 {
777 779 server_info_t *info;
778 780 int atleast1 = 0;
779 781 thread_t *tid;
780 782 int num_threads = 0, i, j;
781 783 void *status;
782 784 void **paramVal = NULL;
783 785 ns_ldap_error_t *error = NULL;
784 786
785 787 if (current_admin.debug_level >= DBG_ALL) {
786 788 logit("getldap_set_serverInfo()...\n");
787 789 }
788 790
789 791 if (head == NULL) {
790 792 logit("getldap_set_serverInfo: "
791 793 "invalid serverInfo list.\n");
792 794 return (-1);
793 795 }
794 796
795 797 /* Get the bind timeout value */
796 798 if (reset_bindtime == 1) {
797 799 tcptimeout = NS_DEFAULT_BIND_TIMEOUT * 1000;
798 800 (void) __ns_ldap_getParam(NS_LDAP_BIND_TIME_P,
799 801 ¶mVal, &error);
800 802 if (paramVal != NULL && *paramVal != NULL) {
801 803 /* convert to milliseconds */
802 804 tcptimeout = **((int **)paramVal);
803 805 tcptimeout *= 1000;
804 806 (void) __ns_ldap_freeParam(¶mVal);
805 807 }
806 808 if (error)
807 809 (void) __ns_ldap_freeError(&error);
808 810 }
809 811
810 812 for (info = head; info; info = info->next)
811 813 num_threads++;
812 814
813 815 if (num_threads == 0) {
814 816 logit("getldap_set_serverInfo: "
815 817 "empty serverInfo list.\n");
816 818 return (-1);
817 819 }
818 820
819 821 tid = (thread_t *) calloc(1, sizeof (thread_t) * num_threads);
820 822 if (tid == NULL) {
821 823 logit("getldap_set_serverInfo: "
822 824 "No memory to create thread ID list.\n");
823 825 return (-1);
824 826 }
825 827
826 828 for (info = head, i = 0; info; info = info->next, i++) {
827 829 if (thr_create(NULL, 0,
828 830 (void *(*)(void*))getldap_get_rootDSE,
829 831 (void *)info, 0, &tid[i])) {
830 832 logit("getldap_set_serverInfo: "
831 833 "can not create thread %d.\n", i + 1);
832 834 for (j = 0; j < i; j++)
833 835 (void) thr_join(tid[j], NULL, NULL);
834 836 free(tid);
835 837 return (-1);
836 838 }
837 839 }
838 840
839 841 for (i = 0; i < num_threads; i++) {
840 842 if (thr_join(tid[i], NULL, &status) == 0) {
841 843 if ((int)status == NS_LDAP_SUCCESS)
842 844 atleast1 = 1;
843 845 }
844 846 }
845 847
846 848 free(tid);
847 849
848 850 if (op == INFO_OP_REFRESH)
849 851 test_server_change(head);
850 852 if (atleast1) {
851 853 return (NS_LDAP_SUCCESS);
852 854 } else
853 855 return (-1);
854 856 }
855 857
856 858 /*
857 859 * getldap_get_serverInfo processes the GETLDAPSERVER door request passed
858 860 * to this function from getldap_serverInfo_op().
859 861 * input:
860 862 * a buffer containing an empty string (e.g., input[0]='\0';) or a string
861 863 * as the "input" in printf(input, "%s%s%s%s", req, addrtype, DOORLINESEP,
862 864 * addr);
863 865 * where addr is the address of a server and
864 866 * req is one of the following:
865 867 * NS_CACHE_NEW: send a new server address, addr is ignored.
866 868 * NS_CACHE_NORESP: send the next one, remove addr from list.
867 869 * NS_CACHE_NEXT: send the next one, keep addr on list.
868 870 * NS_CACHE_WRITE: send a non-replica server, if possible, if not, same
869 871 * as NS_CACHE_NEXT.
870 872 * addrtype:
871 873 * NS_CACHE_ADDR_IP: return server address as is, this is default.
872 874 * NS_CACHE_ADDR_HOSTNAME: return both server address and its FQDN format,
873 875 * only self credential case requires such format.
874 876 * output:
875 877 * a buffer containing server info in the following format:
876 878 * serveraddress DOORLINESEP [ serveraddress FQDN DOORLINESEP ]
877 879 * [ attr=value [DOORLINESEP attr=value ]...]
878 880 * For example: ( here | used as DOORLINESEP for visual purposes)
879 881 * 1) simple bind and sasl/DIGEST-MD5 bind :
880 882 * 1.2.3.4|supportedControl=1.1.1.1|supportedSASLmechanisms=EXTERNAL|
881 883 * supportedSASLmechanisms=GSSAPI
882 884 * 2) sasl/GSSAPI bind (self credential):
883 885 * 1.2.3.4|foo.sun.com|supportedControl=1.1.1.1|
884 886 * supportedSASLmechanisms=EXTERNAL|supportedSASLmechanisms=GSSAPI
885 887 * NOTE: caller should free this buffer when done using it
886 888 */
887 889 static int
888 890 getldap_get_serverInfo(server_info_t *head, char *input,
889 891 char **output, int *svr_removed)
890 892 {
891 893 server_info_t *info = NULL;
892 894 server_info_t *server = NULL;
893 895 char *addr = NULL;
894 896 char *req = NULL;
895 897 char req_new[] = NS_CACHE_NEW;
896 898 char addr_type[] = NS_CACHE_ADDR_IP;
897 899 int matched = FALSE, len = 0, rc = 0;
898 900 char *ret_addr = NULL, *ret_addrFQDN = NULL;
899 901 char *new_addr = NULL;
900 902 pid_t pid;
901 903
902 904 if (current_admin.debug_level >= DBG_ALL) {
903 905 logit("getldap_get_serverInfo()...\n");
904 906 }
905 907
906 908 if (input == NULL || output == NULL) {
907 909 logit("getldap_get_serverInfo: "
908 910 "No input or output buffer.\n");
909 911 return (-1);
910 912 }
911 913
912 914 *output = NULL;
913 915 *svr_removed = FALSE;
914 916
915 917 if (head == NULL) {
916 918 logit("getldap_get_serverInfo: "
917 919 "invalid serverInfo list.\n");
918 920 return (-1);
919 921 }
920 922 /*
921 923 * parse the input string to get req and addr,
922 924 * if input is empty, i.e., input[0] == '\0',
923 925 * treat it as an NS_CACHE_NEW request
924 926 */
925 927 req = req_new;
926 928 if (input[0] != '\0') {
927 929 req = input;
928 930 /* Save addr type flag */
929 931 addr_type[0] = input[1];
930 932 input[strlen(NS_CACHE_NEW)] = '\0';
931 933 /* skip acion type flag, addr type flag and DOORLINESEP */
932 934 addr = input + strlen(DOORLINESEP) + strlen(NS_CACHE_NEW)
933 935 + strlen(NS_CACHE_ADDR_IP);
934 936 }
935 937 /*
936 938 * if NS_CACHE_NEW,
937 939 * or the server info is new,
938 940 * starts from the
939 941 * beginning of the list
940 942 */
941 943 if ((strcmp(req, NS_CACHE_NEW) == 0) ||
942 944 (head->sinfo[0].info_status == INFO_STATUS_NEW))
943 945 matched = TRUE;
944 946 for (info = head; info; info = info->next) {
945 947 /*
946 948 * make sure the server info stays the same
947 949 * while the data is being processed
948 950 */
949 951
950 952 /*
951 953 * This function is called to get server info list
952 954 * and pass it back to door call clients.
953 955 * Access the current copy (sinfo[0]) to get such
954 956 * information
955 957 */
956 958 (void) mutex_lock(&info->mutex[0]);
957 959
958 960 if (matched == FALSE &&
959 961 strcmp(info->sinfo[0].addr, addr) == 0) {
960 962 matched = TRUE;
961 963 if (strcmp(req, NS_CACHE_NORESP) == 0) {
962 964 if (chg_is_called_from_nscd_or_peruser_nscd(
963 965 "REMOVE SERVER", &pid) == 0) {
964 966 (void) mutex_unlock(&info->mutex[0]);
965 967 if (current_admin.debug_level >=
966 968 DBG_ALL)
967 969 logit("Only nscd can remove "
968 970 "servers. pid %ld", pid);
969 971 continue;
970 972 }
971 973
972 974 /*
973 975 * if the information is new,
974 976 * give this server one more chance
975 977 */
976 978 if (info->sinfo[0].info_status ==
977 979 INFO_STATUS_NEW &&
978 980 info->sinfo[0].server_status ==
979 981 INFO_SERVER_UP) {
980 982 server = info;
981 983 break;
982 984 } else {
983 985 /*
984 986 * it is recommended that
985 987 * before removing the
986 988 * server from the list,
987 989 * the server should be
988 990 * contacted one more time
989 991 * to make sure that it is
990 992 * really unavailable.
991 993 * For now, just trust the client
992 994 * (i.e., the sldap library)
993 995 * that it knows what it is
994 996 * doing and would not try
995 997 * to mess up the server
996 998 * list.
997 999 */
998 1000 /*
999 1001 * Make a copy of addr to contact
1000 1002 * it later. It's not doing it here
1001 1003 * to avoid long wait and possible
1002 1004 * recursion to contact an LDAP server.
1003 1005 */
1004 1006 new_addr = strdup(info->sinfo[0].addr);
1005 1007 if (new_addr)
1006 1008 remove_server(new_addr);
1007 1009 *svr_removed = TRUE;
1008 1010 (void) mutex_unlock(&info->mutex[0]);
1009 1011 break;
1010 1012 }
1011 1013 } else {
1012 1014 /*
1013 1015 * req == NS_CACHE_NEXT or NS_CACHE_WRITE
1014 1016 */
1015 1017 (void) mutex_unlock(&info->mutex[0]);
1016 1018 continue;
1017 1019 }
1018 1020 }
1019 1021
1020 1022 if (matched) {
1021 1023 if (strcmp(req, NS_CACHE_WRITE) == 0) {
1022 1024 if (info->sinfo[0].type ==
1023 1025 INFO_RW_WRITEABLE &&
1024 1026 info->sinfo[0].server_status ==
1025 1027 INFO_SERVER_UP) {
1026 1028 server = info;
1027 1029 break;
1028 1030 }
1029 1031 } else if (info->sinfo[0].server_status ==
1030 1032 INFO_SERVER_UP) {
1031 1033 server = info;
1032 1034 break;
1033 1035 }
1034 1036 }
1035 1037
1036 1038 (void) mutex_unlock(&info->mutex[0]);
1037 1039 }
1038 1040
1039 1041 if (server) {
1040 1042 if (strcmp(addr_type, NS_CACHE_ADDR_HOSTNAME) == 0) {
1041 1043 /*
1042 1044 * In SASL/GSSAPI case, a hostname is required for
1043 1045 * Kerberos's service principal.
1044 1046 * e.g.
1045 1047 * ldap/foo.sun.com@SUN.COM
1046 1048 */
1047 1049 if (server->sinfo[0].hostname == NULL) {
1048 1050 rc = __s_api_ip2hostname(server->sinfo[0].addr,
1049 1051 &server->sinfo[0].hostname);
1050 1052 if (rc != NS_LDAP_SUCCESS) {
1051 1053 (void) mutex_unlock(&info->mutex[0]);
1052 1054 return (rc);
1053 1055 }
1054 1056 if (current_admin.debug_level >= DBG_ALL) {
1055 1057 logit("getldap_get_serverInfo: "
1056 1058 "%s is converted to %s\n",
1057 1059 server->sinfo[0].addr,
1058 1060 server->sinfo[0].hostname);
1059 1061 }
1060 1062 }
1061 1063 ret_addr = server->sinfo[0].addr;
1062 1064 ret_addrFQDN = server->sinfo[0].hostname;
1063 1065
1064 1066 } else
1065 1067 ret_addr = server->sinfo[0].addr;
1066 1068
1067 1069
1068 1070 len = strlen(ret_addr) +
1069 1071 strlen(server->sinfo[0].rootDSE_data) +
1070 1072 strlen(DOORLINESEP) + 1;
1071 1073 if (ret_addrFQDN != NULL)
1072 1074 len += strlen(ret_addrFQDN) + strlen(DOORLINESEP);
1073 1075 *output = (char *)malloc(len);
1074 1076 if (*output == NULL) {
1075 1077 (void) mutex_unlock(&info->mutex[0]);
1076 1078 return (NS_LDAP_MEMORY);
1077 1079 }
1078 1080 if (ret_addrFQDN == NULL)
1079 1081 (void) snprintf(*output, len, "%s%s%s",
1080 1082 ret_addr, DOORLINESEP,
1081 1083 server->sinfo[0].rootDSE_data);
1082 1084 else
1083 1085 (void) snprintf(*output, len, "%s%s%s%s%s",
1084 1086 ret_addr, DOORLINESEP,
1085 1087 ret_addrFQDN, DOORLINESEP,
1086 1088 server->sinfo[0].rootDSE_data);
1087 1089 server->sinfo[0].info_status = INFO_STATUS_OLD;
1088 1090 (void) mutex_unlock(&info->mutex[0]);
1089 1091 return (NS_LDAP_SUCCESS);
1090 1092 }
1091 1093 else
1092 1094 return (-99);
1093 1095 }
1094 1096
1095 1097 /*
1096 1098 * Format previous and next refresh time
1097 1099 */
1098 1100 static int
1099 1101 getldap_format_refresh_time(char **output, time_t *prev, time_t *next)
1100 1102 {
1101 1103 #define TIME_FORMAT "%Y/%m/%d %H:%M:%S"
1102 1104 #define TIME_HEADER1 " Previous refresh time: "
1103 1105 #define TIME_HEADER2 " Next refresh time: "
1104 1106 int hdr1_len = strlen(gettext(TIME_HEADER1));
1105 1107 int hdr2_len = strlen(gettext(TIME_HEADER2));
1106 1108 struct tm tm;
1107 1109 char nbuf[256];
1108 1110 char pbuf[256];
1109 1111 int len;
1110 1112
1111 1113 if (current_admin.debug_level >= DBG_ALL) {
1112 1114 logit("getldap_format_refresh_time()...\n");
1113 1115 }
1114 1116
1115 1117 *output = NULL;
1116 1118
1117 1119 /* format the time of previous refresh */
1118 1120 if (*prev != 0) {
1119 1121 (void) localtime_r(prev, &tm);
1120 1122 (void) strftime(pbuf, sizeof (pbuf) - 1, TIME_FORMAT, &tm);
1121 1123 } else {
1122 1124 (void) strcpy(pbuf, gettext("NOT DONE"));
1123 1125 }
1124 1126
1125 1127 /* format the time of next refresh */
1126 1128 if (*next != 0) {
1127 1129 (void) localtime_r(next, &tm);
1128 1130 (void) strftime(nbuf, sizeof (nbuf) - 1, TIME_FORMAT, &tm);
1129 1131 } else {
1130 1132 (void) strcpy(nbuf, gettext("NOT SET"));
1131 1133 }
1132 1134
1133 1135 len = hdr1_len + hdr2_len + strlen(nbuf) +
1134 1136 strlen(pbuf) + 2 * strlen(DOORLINESEP) + 1;
1135 1137
1136 1138 *output = malloc(len);
1137 1139 if (*output == NULL)
1138 1140 return (-1);
1139 1141
1140 1142 (void) snprintf(*output, len, "%s%s%s%s%s%s",
1141 1143 gettext(TIME_HEADER1), pbuf, DOORLINESEP,
1142 1144 gettext(TIME_HEADER2), nbuf, DOORLINESEP);
1143 1145
1144 1146 return (NS_LDAP_SUCCESS);
1145 1147 }
1146 1148
1147 1149 /*
1148 1150 * getldap_get_server_stat processes the GETSTAT request passed
1149 1151 * to this function from getldap_serverInfo_op().
1150 1152 * output:
1151 1153 * a buffer containing info for all the servers.
1152 1154 * For each server, the data is in the following format:
1153 1155 * server: server address or name, status: unknown|up|down|removed DOORLINESEP
1154 1156 * for example: ( here | used as DOORLINESEP for visual purposes)
1155 1157 * server: 1.2.3.4, status: down|server: 2.2.2.2, status: up|
1156 1158 * NOTE: caller should free this buffer when done using it
1157 1159 */
1158 1160 static int
1159 1161 getldap_get_server_stat(server_info_t *head, char **output,
1160 1162 time_t *prev, time_t *next)
1161 1163 {
1162 1164 #define S_HEADER "Server information: "
1163 1165 #define S_FORMAT " server: %s, status: %s%s"
1164 1166 #define S_ERROR " error message: %s%s"
1165 1167 server_info_t *info = NULL;
1166 1168 int header_len = strlen(gettext(S_HEADER));
1167 1169 int format_len = strlen(gettext(S_FORMAT));
1168 1170 int error_len = strlen(gettext(S_ERROR));
1169 1171 int len = header_len + strlen(DOORLINESEP);
1170 1172 int len1 = 0;
1171 1173 char *status, *output1 = NULL, *tmpptr;
1172 1174
1173 1175 *output = NULL;
1174 1176
1175 1177 if (current_admin.debug_level >= DBG_ALL) {
1176 1178 logit("getldap_get_server_stat()...\n");
1177 1179 }
1178 1180
1179 1181 if (head == NULL) {
1180 1182 logit("getldap_get_server_stat: "
1181 1183 "invalid serverInfo list.\n");
1182 1184 return (-1);
1183 1185 }
1184 1186
1185 1187 /* format previous and next refresh time */
1186 1188 (void) getldap_format_refresh_time(&output1, prev, next);
1187 1189 if (output1 == NULL)
1188 1190 return (-1);
1189 1191 len += strlen(output1);
1190 1192 len1 = len + strlen(DOORLINESEP) + 1;
1191 1193
1192 1194 *output = (char *)calloc(1, len1);
1193 1195 if (*output == NULL) {
1194 1196 free(output1);
1195 1197 return (-1);
1196 1198 }
1197 1199
1198 1200 /* insert header string and refresh time info */
1199 1201 (void) snprintf(*output, len1, "%s%s%s",
1200 1202 gettext(S_HEADER), DOORLINESEP, output1);
1201 1203
1202 1204 for (info = head; info; info = info->next) {
1203 1205
1204 1206 /*
1205 1207 * make sure the server info stays the same
1206 1208 * while the data is being processed
1207 1209 */
1208 1210 (void) mutex_lock(&info->mutex[1]);
1209 1211
1210 1212 /*
1211 1213 * When the updating process is under way(getldap_get_rootDSE)
1212 1214 * the update copy(sinfo[1] is the latest copy.
1213 1215 * When the updating process
1214 1216 * is done, the current copy (sinfo[0]) has the latest status,
1215 1217 * which is still identical to the update copy.
1216 1218 * So update copy has the latest status.
1217 1219 * Use the update copy(sinfo[1]) to show status
1218 1220 * (ldap_cachemgr -g).
1219 1221 *
1220 1222 */
1221 1223
1222 1224 switch (info->sinfo[1].server_status) {
1223 1225 case INFO_SERVER_UNKNOWN:
1224 1226 status = gettext("UNKNOWN");
1225 1227 break;
1226 1228 case INFO_SERVER_CONNECTING:
1227 1229 status = gettext("CONNECTING");
1228 1230 break;
1229 1231 case INFO_SERVER_UP:
1230 1232 status = gettext("UP");
1231 1233 break;
1232 1234 case INFO_SERVER_ERROR:
1233 1235 status = gettext("ERROR");
1234 1236 break;
1235 1237 case INFO_SERVER_REMOVED:
1236 1238 status = gettext("REMOVED");
1237 1239 break;
1238 1240 }
1239 1241
1240 1242 len += format_len + strlen(status) +
1241 1243 strlen(info->sinfo[1].addr) +
1242 1244 strlen(DOORLINESEP);
1243 1245 if (info->sinfo[1].errormsg != NULL)
1244 1246 len += error_len +
1245 1247 strlen(info->sinfo[1].errormsg) +
1246 1248 strlen(DOORLINESEP);
1247 1249
1248 1250 tmpptr = (char *)realloc(*output, len);
1249 1251 if (tmpptr == NULL) {
1250 1252 free(output1);
1251 1253 free(*output);
1252 1254 *output = NULL;
1253 1255 (void) mutex_unlock(&info->mutex[1]);
1254 1256 return (-1);
1255 1257 } else
1256 1258 *output = tmpptr;
1257 1259
1258 1260 /* insert server IP addr or name and status */
1259 1261 len1 = len - strlen(*output);
1260 1262 (void) snprintf(*output + strlen(*output), len1,
1261 1263 gettext(S_FORMAT), info->sinfo[1].addr,
1262 1264 status, DOORLINESEP);
1263 1265 /* insert error message if any */
1264 1266 len1 = len - strlen(*output);
1265 1267 if (info->sinfo[1].errormsg != NULL)
1266 1268 (void) snprintf(*output + strlen(*output), len1,
1267 1269 gettext(S_ERROR),
1268 1270 info->sinfo[1].errormsg,
1269 1271 DOORLINESEP);
1270 1272
1271 1273 (void) mutex_unlock(&info->mutex[1]);
1272 1274
1273 1275 }
1274 1276
1275 1277 free(output1);
1276 1278 return (NS_LDAP_SUCCESS);
1277 1279 }
1278 1280
1279 1281 /*
1280 1282 * Format and return the refresh time statistics
1281 1283 */
1282 1284 static int
1283 1285 getldap_get_refresh_stat(char **output)
1284 1286 {
1285 1287 #define R_HEADER0 "Configuration refresh information: "
1286 1288 #define R_HEADER1 " Configured to NO REFRESH."
1287 1289 int hdr0_len = strlen(gettext(R_HEADER0));
1288 1290 int hdr1_len = strlen(gettext(R_HEADER1));
1289 1291 int cache_ttl = -1, len = 0;
1290 1292 time_t expire = 0;
1291 1293 void **paramVal = NULL;
1292 1294 ns_ldap_error_t *errorp = NULL;
1293 1295 char *output1 = NULL;
1294 1296
1295 1297 if (current_admin.debug_level >= DBG_ALL) {
1296 1298 logit("getldap_get_refresh_stat()...\n");
1297 1299 }
1298 1300
1299 1301 *output = NULL;
1300 1302
1301 1303 /* get configured cache TTL */
1302 1304 if ((__ns_ldap_getParam(NS_LDAP_CACHETTL_P,
1303 1305 ¶mVal, &errorp) == NS_LDAP_SUCCESS) &&
1304 1306 paramVal != NULL &&
1305 1307 (char *)*paramVal != NULL) {
1306 1308 cache_ttl = atol((char *)*paramVal);
1307 1309 } else {
1308 1310 if (errorp)
1309 1311 __ns_ldap_freeError(&errorp);
1310 1312 }
1311 1313 (void) __ns_ldap_freeParam(¶mVal);
1312 1314
1313 1315 /* cound not get cache TTL */
1314 1316 if (cache_ttl == -1)
1315 1317 return (-1);
1316 1318
1317 1319 if (cache_ttl == 0) {
1318 1320 len = hdr0_len + hdr1_len +
1319 1321 2 * strlen(DOORLINESEP) + 1;
1320 1322 *output = malloc(len);
1321 1323 if (*output == NULL)
1322 1324 return (-1);
1323 1325 (void) snprintf(*output, len, "%s%s%s%s",
1324 1326 gettext(R_HEADER0), DOORLINESEP,
1325 1327 gettext(R_HEADER1), DOORLINESEP);
1326 1328 } else {
1327 1329
1328 1330 /* get configuration expiration time */
1329 1331 if ((__ns_ldap_getParam(NS_LDAP_EXP_P,
1330 1332 ¶mVal, &errorp) == NS_LDAP_SUCCESS) &&
1331 1333 paramVal != NULL &&
1332 1334 (char *)*paramVal != NULL) {
1333 1335 expire = (time_t)atol((char *)*paramVal);
1334 1336 } else {
1335 1337 if (errorp)
1336 1338 __ns_ldap_freeError(&errorp);
1337 1339 }
1338 1340
1339 1341 (void) __ns_ldap_freeParam(¶mVal);
1340 1342
1341 1343 /* cound not get expiration time */
1342 1344 if (expire == -1)
1343 1345 return (-1);
1344 1346
1345 1347 /* format previous and next refresh time */
1346 1348 (void) getldap_format_refresh_time(&output1,
1347 1349 &prev_refresh_time, &expire);
1348 1350 if (output1 == NULL)
1349 1351 return (-1);
1350 1352
1351 1353 len = hdr0_len + strlen(output1) +
1352 1354 2 * strlen(DOORLINESEP) + 1;
1353 1355 *output = malloc(len);
1354 1356 if (*output == NULL) {
1355 1357 free(output1);
1356 1358 return (-1);
1357 1359 }
1358 1360 (void) snprintf(*output, len, "%s%s%s%s",
1359 1361 gettext(R_HEADER0), DOORLINESEP,
1360 1362 output1, DOORLINESEP);
1361 1363 free(output1);
1362 1364 }
1363 1365
1364 1366 return (NS_LDAP_SUCCESS);
1365 1367 }
1366 1368
1367 1369 static int
1368 1370 getldap_get_cacheTTL()
1369 1371 {
1370 1372 void **paramVal = NULL;
1371 1373 ns_ldap_error_t *error;
1372 1374 int rc = 0, cachettl;
1373 1375
1374 1376
1375 1377 if (current_admin.debug_level >= DBG_ALL) {
1376 1378 logit("getldap_get_cacheTTL()....\n");
1377 1379 }
1378 1380
1379 1381 if ((rc = __ns_ldap_getParam(NS_LDAP_CACHETTL_P,
1380 1382 ¶mVal, &error)) != NS_LDAP_SUCCESS) {
1381 1383 if (error != NULL && error->message != NULL)
1382 1384 logit("Error: Unable to get configuration "
1383 1385 "refresh TTL: %s\n",
1384 1386 error->message);
1385 1387 else {
1386 1388 char *tmp;
1387 1389
1388 1390 __ns_ldap_err2str(rc, &tmp);
1389 1391 logit("Error: Unable to get configuration "
1390 1392 "refresh TTL: %s\n", tmp);
1391 1393 }
1392 1394 (void) __ns_ldap_freeParam(¶mVal);
1393 1395 (void) __ns_ldap_freeError(&error);
1394 1396 return (-1);
1395 1397 }
1396 1398 if (paramVal == NULL || (char *)*paramVal == NULL)
1397 1399 return (-1);
1398 1400 cachettl = atol((char *)*paramVal);
1399 1401 (void) __ns_ldap_freeParam(¶mVal);
1400 1402 return (cachettl);
1401 1403 }
1402 1404
1403 1405
1404 1406 /*
1405 1407 * This function implements the adaptive server list refresh
1406 1408 * algorithm used by ldap_cachemgr. The idea is to have the
1407 1409 * refresh TTL adjust itself between maximum and minimum
1408 1410 * values. If the server list has been walked three times
1409 1411 * in a row without errors, the TTL will be doubled. This will
1410 1412 * be done repeatedly until the maximum value is reached
1411 1413 * or passed. If passed, the maximum value will be used.
1412 1414 * If any time a server is found to be down/bad, either
1413 1415 * after another server list walk or informed by libsldap via
1414 1416 * the GETLDAPSERVER door calls, the TTL will be set to half
1415 1417 * of its value, again repeatedly, but no less than the minimum
1416 1418 * value. Also, at any time, if all the servers on the list
1417 1419 * are found to be down/bad, the TTL will be set to minimum,
1418 1420 * so that a "no-server" refresh loop should be entered to try
1419 1421 * to find a good server as soon as possible. The caller
1420 1422 * could check the no_gd_server flag for this situation.
1421 1423 * The maximum and minimum values are initialized when the input
1422 1424 * refresh_ttl is set to zero, this should occur during
1423 1425 * ldap_cachemgr startup or every time the server list is
1424 1426 * recreated after the configuration profile is refreshed
1425 1427 * from an LDAP server. The maximum is set to the value of
1426 1428 * the NS_LDAP_CACHETTL parameter (configuration profile
1427 1429 * refresh TTL), but if it is zero (never refreshed) or can
1428 1430 * not be retrieved, the maximum is set to the macro
1429 1431 * REFRESHTTL_MAX (12 hours) defined below. The minimum is
1430 1432 * set to REFRESHTTL_MIN, which is the TCP connection timeout
1431 1433 * (tcptimeout) set via the LDAP API ldap_set_option()
1432 1434 * with the new LDAP_X_OPT_CONNECT_TIMEOUT option plus 10 seconds.
1433 1435 * This accounts for the maximum possible timeout value for an
1434 1436 * LDAP TCP connect call.The first refresh TTL, initial value of
1435 1437 * refresh_ttl, will be set to the smaller of the two,
1436 1438 * REFRESHTTL_REGULAR (10 minutes) or (REFRESHTTL_MAX + REFRESHTTL_MIN)/2.
1437 1439 * The idea is to have a low starting value and have the value
1438 1440 * stay low if the network/server is unstable, but eventually
1439 1441 * the value will move up to maximum and stay there if the
1440 1442 * network/server is stable.
1441 1443 */
1442 1444 static int
1443 1445 getldap_set_refresh_ttl(server_info_t *head, int *refresh_ttl,
1444 1446 int *no_gd_server)
1445 1447 {
1446 1448 #define REFRESHTTL_REGULAR 600
1447 1449 #define REFRESHTTL_MAX 43200
1448 1450 /* tcptimeout is in milliseconds */
1449 1451 #define REFRESHTTL_MIN (tcptimeout/1000) + 10
1450 1452 #define UP_REFRESH_TTL_NUM 2
1451 1453
1452 1454 static mutex_t refresh_mutex;
1453 1455 static int refresh_ttl_max = 0;
1454 1456 static int refresh_ttl_min = 0;
1455 1457 static int num_walked_ok = 0;
1456 1458 int num_servers = 0;
1457 1459 int num_good_servers = 0;
1458 1460 int num_prev_good_servers = 0;
1459 1461 server_info_t *info;
1460 1462
1461 1463 /* allow one thread at a time */
1462 1464 (void) mutex_lock(&refresh_mutex);
1463 1465
1464 1466 if (current_admin.debug_level >= DBG_ALL) {
1465 1467 logit("getldap_set_refresh_ttl()...\n");
1466 1468 }
1467 1469
1468 1470 if (!head || !refresh_ttl || !no_gd_server) {
1469 1471 logit("getldap_set_refresh_ttl: head is "
1470 1472 "NULL or refresh_ttl is NULL or "
1471 1473 "no_gd_server is NULL");
1472 1474 (void) mutex_unlock(&refresh_mutex);
1473 1475 return (-1);
1474 1476 }
1475 1477 *no_gd_server = FALSE;
1476 1478
1477 1479 /*
1478 1480 * init max. min. TTLs if first time through or a fresh one
1479 1481 */
1480 1482 if (current_admin.debug_level >= DBG_SERVER_LIST_REFRESH) {
1481 1483 logit("getldap_set_refresh_ttl:(1) refresh ttl is %d "
1482 1484 "seconds\n", *refresh_ttl);
1483 1485 }
1484 1486 if (*refresh_ttl == 0) {
1485 1487 num_walked_ok = 0;
1486 1488 /*
1487 1489 * init cache manager server list TTL:
1488 1490 *
1489 1491 * init the min. TTL to
1490 1492 * REFRESHTTL_MIN ( 2*(TCP MSL) + 10 seconds)
1491 1493 */
1492 1494 refresh_ttl_min = REFRESHTTL_MIN;
1493 1495
1494 1496 /*
1495 1497 * try to set the max. TTL to
1496 1498 * configuration refresh TTL (NS_LDAP_CACHETTL),
1497 1499 * if error (-1), or never refreshed (0),
1498 1500 * set it to REFRESHTTL_MAX (12 hours)
1499 1501 */
1500 1502 refresh_ttl_max = getldap_get_cacheTTL();
1501 1503 if (current_admin.debug_level >= DBG_SERVER_LIST_REFRESH) {
1502 1504 logit("getldap_set_refresh_ttl:(2) refresh ttl is %d "
1503 1505 "seconds\n", *refresh_ttl);
1504 1506 logit("getldap_set_refresh_ttl:(2) max ttl is %d, "
1505 1507 "min ttl is %d seconds\n",
1506 1508 refresh_ttl_max, refresh_ttl_min);
1507 1509 }
1508 1510 if (refresh_ttl_max <= 0)
1509 1511 refresh_ttl_max = REFRESHTTL_MAX;
1510 1512 else if (refresh_ttl_max < refresh_ttl_min)
1511 1513 refresh_ttl_max = refresh_ttl_min;
1512 1514
1513 1515 /*
1514 1516 * init the first TTL to the smaller of the two:
1515 1517 * REFRESHTTL_REGULAR ( 10 minutes),
1516 1518 * (refresh_ttl_max + refresh_ttl_min)/2
1517 1519 */
1518 1520 *refresh_ttl = REFRESHTTL_REGULAR;
1519 1521 if (*refresh_ttl > (refresh_ttl_max + refresh_ttl_min) / 2)
1520 1522 *refresh_ttl = (refresh_ttl_max + refresh_ttl_min) / 2;
1521 1523 if (current_admin.debug_level >= DBG_SERVER_LIST_REFRESH) {
1522 1524 logit("getldap_set_refresh_ttl:(3) refresh ttl is %d "
1523 1525 "seconds\n", *refresh_ttl);
1524 1526 logit("getldap_set_refresh_ttl:(3) max ttl is %d, "
1525 1527 "min ttl is %d seconds\n",
1526 1528 refresh_ttl_max, refresh_ttl_min);
1527 1529 }
1528 1530 }
1529 1531
1530 1532 /*
1531 1533 * get the servers statistics:
1532 1534 * number of servers on list
1533 1535 * number of good servers on list
1534 1536 * number of pevious good servers on list
1535 1537 */
1536 1538 for (info = head; info; info = info->next) {
1537 1539 num_servers++;
1538 1540 (void) mutex_lock(&info->mutex[0]);
1539 1541 if (info->sinfo[0].server_status == INFO_SERVER_UP)
1540 1542 num_good_servers++;
1541 1543 /*
1542 1544 * Server's previous status could be UNKNOWN
1543 1545 * only between the very first and second
1544 1546 * refresh. Treat that UNKNOWN status as up
1545 1547 */
1546 1548 if (info->sinfo[0].prev_server_status
1547 1549 == INFO_SERVER_UP ||
1548 1550 info->sinfo[0].prev_server_status
1549 1551 == INFO_SERVER_UNKNOWN)
1550 1552 num_prev_good_servers++;
1551 1553 (void) mutex_unlock(&info->mutex[0]);
1552 1554 }
1553 1555
1554 1556 /*
1555 1557 * if the server list is walked three times in a row
1556 1558 * without problems, double the refresh TTL but no more
1557 1559 * than the max. refresh TTL
1558 1560 */
1559 1561 if (num_good_servers == num_servers) {
1560 1562 num_walked_ok++;
1561 1563 if (num_walked_ok > UP_REFRESH_TTL_NUM) {
1562 1564
1563 1565 *refresh_ttl = *refresh_ttl * 2;
1564 1566 if (*refresh_ttl > refresh_ttl_max)
1565 1567 *refresh_ttl = refresh_ttl_max;
1566 1568
1567 1569 num_walked_ok = 0;
1568 1570 }
1569 1571 if (current_admin.debug_level >= DBG_SERVER_LIST_REFRESH) {
1570 1572 logit("getldap_set_refresh_ttl:(4) refresh ttl is %d "
1571 1573 "seconds\n", *refresh_ttl);
1572 1574 }
1573 1575 } else if (num_good_servers == 0) {
1574 1576 /*
1575 1577 * if no good server found,
1576 1578 * set refresh TTL to miminum
1577 1579 */
1578 1580 *refresh_ttl = refresh_ttl_min;
1579 1581 *no_gd_server = TRUE;
1580 1582 num_walked_ok = 0;
1581 1583 if (current_admin.debug_level >= DBG_SERVER_LIST_REFRESH) {
1582 1584 logit("getldap_set_refresh_ttl:(5) refresh ttl is %d "
1583 1585 "seconds\n", *refresh_ttl);
1584 1586 }
1585 1587 } else if (num_prev_good_servers > num_good_servers) {
1586 1588 /*
1587 1589 * if more down/bad servers found,
1588 1590 * decrease the refresh TTL by half
1589 1591 * but no less than the min. refresh TTL
1590 1592 */
1591 1593 *refresh_ttl = *refresh_ttl / 2;
1592 1594 if (*refresh_ttl < refresh_ttl_min)
1593 1595 *refresh_ttl = refresh_ttl_min;
1594 1596 num_walked_ok = 0;
1595 1597 logit("getldap_set_refresh_ttl:(6) refresh ttl is %d "
1596 1598 "seconds\n", *refresh_ttl);
1597 1599
1598 1600 }
1599 1601
1600 1602 if (current_admin.debug_level >= DBG_SERVER_LIST_REFRESH) {
1601 1603 logit("getldap_set_refresh_ttl:(7) refresh ttl is %d seconds\n",
1602 1604 *refresh_ttl);
1603 1605 }
1604 1606 (void) mutex_unlock(&refresh_mutex);
1605 1607 return (0);
1606 1608 }
1607 1609
1608 1610 static int
1609 1611 getldap_serverInfo_op(info_op_t op, char *input, char **output)
1610 1612 {
1611 1613
1612 1614 static rwlock_t info_lock = DEFAULTRWLOCK;
1613 1615 static rwlock_t info_lock_old = DEFAULTRWLOCK;
1614 1616 static mutex_t info_mutex;
1615 1617 static cond_t info_cond;
1616 1618 static int creating = FALSE;
1617 1619 static int refresh_ttl = 0;
1618 1620 static int sec_to_refresh = 0;
1619 1621 static int in_no_server_mode = FALSE;
1620 1622
1621 1623 static server_info_t *serverInfo = NULL;
1622 1624 static server_info_t *serverInfo_old = NULL;
1623 1625 server_info_t *serverInfo_1;
↓ open down ↓ |
1591 lines elided |
↑ open up ↑ |
1624 1626 int is_creating;
1625 1627 int err, no_server_good = FALSE;
1626 1628 int server_removed = FALSE;
1627 1629 int fall_thru = FALSE;
1628 1630 static struct timespec timeout;
1629 1631 struct timespec new_timeout;
1630 1632 struct timeval tp;
1631 1633 static time_t prev_refresh = 0, next_refresh = 0;
1632 1634 ns_server_status_t changed = 0;
1633 1635
1636 + (void) pthread_setname_np(pthread_self(), "getldap_serverinfo");
1637 +
1634 1638 if (current_admin.debug_level >= DBG_ALL) {
1635 1639 logit("getldap_serverInfo_op()...\n");
1636 1640 }
1637 1641 switch (op) {
1638 1642 case INFO_OP_CREATE:
1639 1643 if (current_admin.debug_level >= DBG_ALL) {
1640 1644 logit("operation is INFO_OP_CREATE...\n");
1641 1645 }
1642 1646
1643 1647 /*
1644 1648 * indicate that the server info is being
1645 1649 * (re)created, so that the refresh thread
1646 1650 * will not refresh the info list right
1647 1651 * after the list got (re)created
1648 1652 */
1649 1653 (void) mutex_lock(&info_mutex);
1650 1654 is_creating = creating;
1651 1655 creating = TRUE;
1652 1656 (void) mutex_unlock(&info_mutex);
1653 1657
1654 1658 if (is_creating)
1655 1659 break;
1656 1660 /*
1657 1661 * create an empty info list
1658 1662 */
1659 1663 (void) getldap_init_serverInfo(&serverInfo_1);
1660 1664 /*
1661 1665 * exit if list not created
1662 1666 */
1663 1667 if (serverInfo_1 == NULL) {
1664 1668 (void) mutex_lock(&info_mutex);
1665 1669 creating = FALSE;
1666 1670 (void) mutex_unlock(&info_mutex);
1667 1671 break;
1668 1672 }
1669 1673 /*
1670 1674 * make the new server info available:
1671 1675 * use writer lock here, so that the switch
1672 1676 * is done after all the reader locks have
1673 1677 * been released.
1674 1678 */
1675 1679 (void) rw_wrlock(&info_lock);
1676 1680 serverInfo = serverInfo_1;
1677 1681 /*
1678 1682 * if this is the first time
1679 1683 * the server list is being created,
1680 1684 * (i.e., serverInfo_old is NULL)
1681 1685 * make the old list same as the new
1682 1686 * so the GETSERVER code can do its work
1683 1687 */
1684 1688 if (serverInfo_old == NULL)
1685 1689 serverInfo_old = serverInfo_1;
1686 1690 (void) rw_unlock(&info_lock);
1687 1691
1688 1692 /*
1689 1693 * fill the new info list
1690 1694 */
1691 1695 (void) rw_rdlock(&info_lock);
1692 1696 /* reset bind time (tcptimeout) */
1693 1697 (void) getldap_set_serverInfo(serverInfo, 1, INFO_OP_CREATE);
1694 1698
1695 1699 (void) mutex_lock(&info_mutex);
1696 1700 /*
1697 1701 * set cache manager server list TTL,
1698 1702 * set refresh_ttl to zero to indicate a fresh one
1699 1703 */
1700 1704 refresh_ttl = 0;
1701 1705 (void) getldap_set_refresh_ttl(serverInfo,
1702 1706 &refresh_ttl, &no_server_good);
1703 1707 sec_to_refresh = refresh_ttl;
1704 1708
1705 1709 /* statistics: previous refresh time */
1706 1710 if (gettimeofday(&tp, NULL) == 0)
1707 1711 prev_refresh = tp.tv_sec;
1708 1712
1709 1713 creating = FALSE;
1710 1714
1711 1715 /*
1712 1716 * if no server found or available,
1713 1717 * tell the server info refresh thread
1714 1718 * to start the "no-server" refresh loop
1715 1719 * otherwise reset the in_no_server_mode flag
1716 1720 */
1717 1721 if (no_server_good) {
1718 1722 sec_to_refresh = 0;
1719 1723 in_no_server_mode = TRUE;
1720 1724 } else
1721 1725 in_no_server_mode = FALSE;
1722 1726 /*
1723 1727 * awake the sleeping refresh thread
1724 1728 */
1725 1729 (void) cond_signal(&info_cond);
1726 1730
1727 1731 (void) mutex_unlock(&info_mutex);
1728 1732 (void) rw_unlock(&info_lock);
1729 1733
1730 1734 /*
1731 1735 * delete the old server info
1732 1736 */
1733 1737 (void) rw_wrlock(&info_lock_old);
1734 1738 if (serverInfo_old != serverInfo)
1735 1739 (void) getldap_destroy_serverInfo(serverInfo_old);
1736 1740 /*
1737 1741 * serverInfo_old needs to be the same as
1738 1742 * serverinfo now.
1739 1743 * it will be used by GETSERVER processing.
1740 1744 */
1741 1745 serverInfo_old = serverInfo;
1742 1746 (void) rw_unlock(&info_lock_old);
1743 1747 break;
1744 1748 case INFO_OP_DELETE:
1745 1749 if (current_admin.debug_level >= DBG_ALL) {
1746 1750 logit("operation is INFO_OP_DELETE...\n");
1747 1751 }
1748 1752 /*
1749 1753 * use writer lock here, so that the delete would
1750 1754 * not start until all the reader locks have
1751 1755 * been released.
1752 1756 */
1753 1757 (void) rw_wrlock(&info_lock);
1754 1758 if (serverInfo)
1755 1759 (void) getldap_destroy_serverInfo(serverInfo);
1756 1760 serverInfo = NULL;
1757 1761 (void) rw_unlock(&info_lock);
1758 1762 break;
1759 1763 case INFO_OP_REFRESH:
1760 1764 if (current_admin.debug_level >= DBG_SERVER_LIST_REFRESH) {
1761 1765 logit("operation is INFO_OP_REFRESH...\n");
1762 1766 }
1763 1767 /*
1764 1768 * if server info is currently being
1765 1769 * (re)created, do nothing
1766 1770 */
1767 1771 (void) mutex_lock(&info_mutex);
1768 1772 is_creating = creating;
1769 1773 (void) mutex_unlock(&info_mutex);
1770 1774 if (is_creating)
1771 1775 break;
1772 1776
1773 1777 (void) rw_rdlock(&info_lock);
1774 1778 if (serverInfo) {
1775 1779 /* do not reset bind time (tcptimeout) */
1776 1780 (void) getldap_set_serverInfo(serverInfo, 0,
1777 1781 INFO_OP_REFRESH);
1778 1782
1779 1783 (void) mutex_lock(&info_mutex);
1780 1784
1781 1785 /* statistics: previous refresh time */
1782 1786 if (gettimeofday(&tp, NULL) == 0)
1783 1787 prev_refresh = tp.tv_sec;
1784 1788 /*
1785 1789 * set cache manager server list TTL
1786 1790 */
1787 1791 (void) getldap_set_refresh_ttl(serverInfo,
1788 1792 &refresh_ttl, &no_server_good);
1789 1793 /*
1790 1794 * if no good server found,
1791 1795 * tell the server info refresh thread
1792 1796 * to start the "no-server" refresh loop
1793 1797 * otherwise reset the in_no_server_mode flag
1794 1798 */
1795 1799 if (no_server_good) {
1796 1800 in_no_server_mode = TRUE;
1797 1801 sec_to_refresh = 0;
1798 1802 } else {
1799 1803 in_no_server_mode = FALSE;
1800 1804 sec_to_refresh = refresh_ttl;
1801 1805 }
1802 1806 if (current_admin.debug_level >=
1803 1807 DBG_SERVER_LIST_REFRESH) {
1804 1808 logit("getldap_serverInfo_op("
1805 1809 "INFO_OP_REFRESH):"
1806 1810 " seconds refresh: %d second(s)....\n",
1807 1811 sec_to_refresh);
1808 1812 }
1809 1813 (void) mutex_unlock(&info_mutex);
1810 1814 }
1811 1815 (void) rw_unlock(&info_lock);
1812 1816
1813 1817 break;
1814 1818 case INFO_OP_REFRESH_WAIT:
1815 1819 if (current_admin.debug_level >= DBG_SERVER_LIST_REFRESH) {
1816 1820 logit("operation is INFO_OP_REFRESH_WAIT...\n");
1817 1821 }
1818 1822 (void) cond_init(&info_cond, NULL, NULL);
1819 1823 (void) mutex_lock(&info_mutex);
1820 1824 err = 0;
1821 1825 while (err != ETIME) {
1822 1826 int sleeptime;
1823 1827 /*
1824 1828 * if need to go into the "no-server" refresh
1825 1829 * loop, set timout value to
1826 1830 * REFRESH_DELAY_WHEN_NO_SERVER
1827 1831 */
1828 1832 if (sec_to_refresh == 0) {
1829 1833 sec_to_refresh = refresh_ttl;
1830 1834 timeout.tv_sec = time(NULL) +
1831 1835 REFRESH_DELAY_WHEN_NO_SERVER;
1832 1836 sleeptime = REFRESH_DELAY_WHEN_NO_SERVER;
1833 1837 if (current_admin.debug_level >=
1834 1838 DBG_SERVER_LIST_REFRESH) {
1835 1839 logit("getldap_serverInfo_op("
1836 1840 "INFO_OP_REFRESH_WAIT):"
1837 1841 " entering no-server "
1838 1842 "refresh loop...\n");
1839 1843 }
1840 1844 } else {
1841 1845 timeout.tv_sec = time(NULL) + sec_to_refresh;
1842 1846 sleeptime = sec_to_refresh;
1843 1847 }
1844 1848 timeout.tv_nsec = 0;
1845 1849
1846 1850 /* statistics: next refresh time */
1847 1851 next_refresh = timeout.tv_sec;
1848 1852
1849 1853 if (current_admin.debug_level >=
1850 1854 DBG_SERVER_LIST_REFRESH) {
1851 1855 logit("getldap_serverInfo_op("
1852 1856 "INFO_OP_REFRESH_WAIT):"
1853 1857 " about to sleep for %d second(s)...\n",
1854 1858 sleeptime);
1855 1859 }
1856 1860 err = cond_timedwait(&info_cond,
1857 1861 &info_mutex, &timeout);
1858 1862 }
1859 1863 (void) cond_destroy(&info_cond);
1860 1864 (void) mutex_unlock(&info_mutex);
1861 1865 break;
1862 1866 case INFO_OP_GETSERVER:
1863 1867 if (current_admin.debug_level >= DBG_ALL) {
1864 1868 logit("operation is INFO_OP_GETSERVER...\n");
1865 1869 }
1866 1870 *output = NULL;
1867 1871 /*
1868 1872 * GETSERVER processing always use
1869 1873 * serverInfo_old to retrieve server infomation.
1870 1874 * serverInfo_old is equal to serverInfo
1871 1875 * most of the time, except when a new
1872 1876 * server list is being created.
1873 1877 * This is why the check for is_creating
1874 1878 * is needed below.
1875 1879 */
1876 1880 (void) rw_rdlock(&info_lock_old);
1877 1881
1878 1882 if (serverInfo_old == NULL) {
1879 1883 (void) rw_unlock(&info_lock_old);
1880 1884 break;
1881 1885 } else
1882 1886 (void) getldap_get_serverInfo(serverInfo_old,
1883 1887 input, output, &server_removed);
1884 1888 (void) rw_unlock(&info_lock_old);
1885 1889
1886 1890 /*
1887 1891 * Return here and let remove server thread do its job in
1888 1892 * another thread. It executes INFO_OP_REMOVESERVER code later.
1889 1893 */
1890 1894 if (server_removed)
1891 1895 break;
1892 1896
1893 1897 fall_thru = TRUE;
1894 1898
1895 1899 /* FALL THROUGH */
1896 1900
1897 1901 case INFO_OP_REMOVESERVER:
1898 1902 /*
1899 1903 * INFO_OP_GETSERVER and INFO_OP_REMOVESERVER share the
1900 1904 * following code except (!fall thru) part.
1901 1905 */
1902 1906
1903 1907 /*
1904 1908 * if server info is currently being
1905 1909 * (re)created, do nothing
1906 1910 */
1907 1911
1908 1912 (void) mutex_lock(&info_mutex);
1909 1913 is_creating = creating;
1910 1914 (void) mutex_unlock(&info_mutex);
1911 1915 if (is_creating)
1912 1916 break;
1913 1917
1914 1918 if (!fall_thru) {
1915 1919 if (current_admin.debug_level >= DBG_ALL)
1916 1920 logit("operation is INFO_OP_REMOVESERVER...\n");
1917 1921 (void) rw_rdlock(&info_lock_old);
1918 1922 changed = set_server_status(input, serverInfo_old);
1919 1923 (void) rw_unlock(&info_lock_old);
1920 1924 if (changed)
1921 1925 create_buf_and_notify(input, changed);
1922 1926 else
1923 1927 break;
1924 1928 }
1925 1929
1926 1930 /*
1927 1931 * set cache manager server list TTL if necessary
1928 1932 */
1929 1933 if (*output == NULL || changed) {
1930 1934 (void) rw_rdlock(&info_lock);
1931 1935 (void) mutex_lock(&info_mutex);
1932 1936
1933 1937 (void) getldap_set_refresh_ttl(serverInfo,
1934 1938 &refresh_ttl, &no_server_good);
1935 1939
1936 1940 /*
1937 1941 * if no good server found, need to go into
1938 1942 * the "no-server" refresh loop
1939 1943 * to find a server as soon as possible
1940 1944 * otherwise reset the in_no_server_mode flag
1941 1945 */
1942 1946 if (no_server_good) {
1943 1947 /*
1944 1948 * if already in no-server mode,
1945 1949 * don't brother
1946 1950 */
1947 1951 if (in_no_server_mode == FALSE) {
1948 1952 sec_to_refresh = 0;
1949 1953 in_no_server_mode = TRUE;
1950 1954 (void) cond_signal(&info_cond);
1951 1955 }
1952 1956 (void) mutex_unlock(&info_mutex);
1953 1957 (void) rw_unlock(&info_lock);
1954 1958 break;
1955 1959 } else {
1956 1960 in_no_server_mode = FALSE;
1957 1961 sec_to_refresh = refresh_ttl;
1958 1962 }
1959 1963 /*
1960 1964 * if the refresh thread will be timed out
1961 1965 * longer than refresh_ttl seconds,
1962 1966 * wake it up to make it wait on the new
1963 1967 * time out value
1964 1968 */
1965 1969 new_timeout.tv_sec = time(NULL) + refresh_ttl;
1966 1970 if (new_timeout.tv_sec < timeout.tv_sec)
1967 1971 (void) cond_signal(&info_cond);
1968 1972
1969 1973 (void) mutex_unlock(&info_mutex);
1970 1974 (void) rw_unlock(&info_lock);
1971 1975 }
1972 1976 break;
1973 1977 case INFO_OP_GETSTAT:
1974 1978 if (current_admin.debug_level >= DBG_ALL) {
1975 1979 logit("operation is INFO_OP_GETSTAT...\n");
1976 1980 }
1977 1981 *output = NULL;
1978 1982 (void) rw_rdlock(&info_lock);
1979 1983 if (serverInfo) {
1980 1984 (void) getldap_get_server_stat(serverInfo,
1981 1985 output, &prev_refresh, &next_refresh);
1982 1986 }
1983 1987 (void) rw_unlock(&info_lock);
1984 1988 break;
1985 1989 default:
1986 1990 logit("getldap_serverInfo_op(): "
1987 1991 "invalid operation code (%d).\n", op);
1988 1992 return (-1);
1989 1993 break;
1990 1994 }
1991 1995 return (NS_LDAP_SUCCESS);
1992 1996 }
1993 1997
1994 1998 void
1995 1999 getldap_serverInfo_refresh()
1996 2000 {
1997 2001 int always = 1;
1998 2002
1999 2003 if (current_admin.debug_level >= DBG_ALL) {
2000 2004 logit("getldap_serverInfo_refresh()...\n");
2001 2005 }
2002 2006
2003 2007 /* create the server info list */
2004 2008 (void) getldap_serverInfo_op(INFO_OP_CREATE, NULL, NULL);
2005 2009
2006 2010 while (always) {
2007 2011 /*
2008 2012 * the operation INFO_OP_REFRESH_WAIT
2009 2013 * causes this thread to wait until
2010 2014 * it is time to do refresh,
2011 2015 * see getldap_serverInfo_op() for details
2012 2016 */
2013 2017 (void) getldap_serverInfo_op(INFO_OP_REFRESH_WAIT, NULL, NULL);
2014 2018 (void) getldap_serverInfo_op(INFO_OP_REFRESH, NULL, NULL);
2015 2019 }
2016 2020 }
2017 2021
2018 2022 void
2019 2023 getldap_getserver(LineBuf *config_info, ldap_call_t *in)
2020 2024 {
2021 2025 char req[] = "0";
2022 2026
2023 2027 if (current_admin.debug_level >= DBG_ALL) {
2024 2028 logit("getldap_getserver()...\n");
2025 2029 }
2026 2030
2027 2031 config_info->len = 0;
2028 2032
2029 2033 /* make sure the request is valid */
2030 2034 req[0] = (in->ldap_u.servername)[0];
2031 2035 if ((req[0] != '\0') &&
2032 2036 (strcmp(req, NS_CACHE_NEW) != 0) &&
2033 2037 (strcmp(req, NS_CACHE_NORESP) != 0) &&
2034 2038 (strcmp(req, NS_CACHE_NEXT) != 0) &&
2035 2039 (strcmp(req, NS_CACHE_WRITE) != 0)) {
2036 2040 return;
2037 2041 }
2038 2042
2039 2043 (void) getldap_serverInfo_op(INFO_OP_GETSERVER,
2040 2044 in->ldap_u.domainname, &config_info->str);
2041 2045
2042 2046 if (config_info->str == NULL)
2043 2047 return;
2044 2048
2045 2049 config_info->len = strlen(config_info->str) + 1;
2046 2050
2047 2051 if (current_admin.debug_level >= DBG_PROFILE_REFRESH) {
2048 2052 /* Log server IP */
2049 2053 char *ptr,
2050 2054 separator;
2051 2055 ptr = strstr(config_info->str, DOORLINESEP);
2052 2056 if (ptr) {
2053 2057 separator = *ptr;
2054 2058 *ptr = '\0';
2055 2059 logit("getldap_getserver: got server %s\n",
2056 2060 config_info->str);
2057 2061 *ptr = separator;
2058 2062 } else
2059 2063 logit("getldap_getserver: Missing %s."
2060 2064 " Internal error\n", DOORLINESEP);
2061 2065 }
2062 2066 }
2063 2067
2064 2068 void
2065 2069 getldap_get_cacheData(LineBuf *config_info, ldap_call_t *in)
2066 2070 {
2067 2071 char *instr = NULL;
2068 2072 int datatype = CACHE_MAP_UNKNOWN;
2069 2073
2070 2074 if (current_admin.debug_level >= DBG_ALL) {
2071 2075 logit("getldap_get_cacheData()...\n");
2072 2076 }
2073 2077
2074 2078 config_info->len = 0;
2075 2079 config_info->str = NULL;
2076 2080
2077 2081 /* make sure the request is valid */
2078 2082 if (strncmp(in->ldap_u.servername,
2079 2083 NS_CACHE_DN2DOMAIN, strlen(NS_CACHE_DN2DOMAIN)) == 0)
2080 2084 datatype = CACHE_MAP_DN2DOMAIN;
2081 2085
2082 2086 if (datatype == CACHE_MAP_UNKNOWN)
2083 2087 return;
2084 2088
2085 2089 instr = strstr(in->ldap_u.servername, DOORLINESEP);
2086 2090 if (instr == NULL)
2087 2091 return;
2088 2092 instr += strlen(DOORLINESEP);
2089 2093 if (*instr == '\0')
2090 2094 return;
2091 2095
2092 2096 (void) getldap_cache_op(CACHE_OP_FIND, datatype,
2093 2097 instr, &config_info->str);
2094 2098
2095 2099 if (config_info->str != NULL) {
2096 2100 config_info->len = strlen(config_info->str) + 1;
2097 2101 }
2098 2102 }
2099 2103
2100 2104 int
2101 2105 getldap_set_cacheData(ldap_call_t *in)
2102 2106 {
2103 2107 char *instr1 = NULL;
2104 2108 char *instr2 = NULL;
2105 2109 int datatype = CACHE_MAP_UNKNOWN;
2106 2110 int rc = 0;
2107 2111
2108 2112 if (current_admin.debug_level >= DBG_ALL) {
2109 2113 logit("getldap_set_cacheData()...\n");
2110 2114 }
2111 2115
2112 2116 /* make sure the request is valid */
2113 2117 if (strncmp(in->ldap_u.servername,
2114 2118 NS_CACHE_DN2DOMAIN, strlen(NS_CACHE_DN2DOMAIN)) == 0)
2115 2119 datatype = CACHE_MAP_DN2DOMAIN;
2116 2120
2117 2121 if (datatype == CACHE_MAP_UNKNOWN)
2118 2122 return (-1);
2119 2123
2120 2124 instr1 = strstr(in->ldap_u.servername, DOORLINESEP);
2121 2125 if (instr1 == NULL)
2122 2126 return (-1);
2123 2127 *instr1 = '\0';
2124 2128 instr1 += strlen(DOORLINESEP);
2125 2129 if (*instr1 == '\0')
2126 2130 return (-1);
2127 2131 instr2 = strstr(instr1, DOORLINESEP);
2128 2132 if (instr2 == NULL)
2129 2133 return (-1);
2130 2134 *instr2 = '\0';
2131 2135 instr2 += strlen(DOORLINESEP);
2132 2136 if (*instr2 == '\0')
2133 2137 return (-1);
2134 2138
2135 2139 rc = getldap_cache_op(CACHE_OP_ADD, datatype,
2136 2140 instr1, &instr2);
2137 2141 if (rc != NS_LDAP_SUCCESS)
2138 2142 return (-1);
2139 2143
2140 2144 return (0);
2141 2145 }
2142 2146
2143 2147 void
2144 2148 getldap_get_cacheStat(LineBuf *stat_info)
2145 2149 {
2146 2150 char *foutstr = NULL;
2147 2151 char *soutstr = NULL;
2148 2152 char *coutstr = NULL;
2149 2153 int infoSize;
2150 2154
2151 2155 if (current_admin.debug_level >= DBG_ALL) {
2152 2156 logit("getldap_get_cacheStat()...\n");
2153 2157 }
2154 2158
2155 2159 stat_info->str = NULL;
2156 2160 stat_info->len = 0;
2157 2161
2158 2162 /* get refersh statisitcs */
2159 2163 (void) getldap_get_refresh_stat(&foutstr);
2160 2164 if (foutstr == NULL)
2161 2165 return;
2162 2166
2163 2167 /* get server statisitcs */
2164 2168 (void) getldap_serverInfo_op(INFO_OP_GETSTAT, NULL, &soutstr);
2165 2169 if (soutstr == NULL) {
2166 2170 free(foutstr);
2167 2171 return;
2168 2172 }
2169 2173 /* get cache data statisitcs */
2170 2174 (void) getldap_cache_op(CACHE_OP_GETSTAT, NULL, NULL, &coutstr);
2171 2175 if (coutstr == NULL) {
2172 2176 free(foutstr);
2173 2177 free(soutstr);
2174 2178 return;
2175 2179 }
2176 2180
2177 2181 infoSize = strlen(foutstr) + strlen(soutstr) + strlen(coutstr) + 3;
2178 2182 stat_info->str = calloc(infoSize, sizeof (char));
2179 2183 if (stat_info->str != NULL) {
2180 2184 (void) strncpy(stat_info->str,
2181 2185 foutstr,
2182 2186 strlen(foutstr) + 1);
2183 2187 (void) strncat(stat_info->str,
2184 2188 soutstr,
2185 2189 strlen(soutstr) + 1);
2186 2190 (void) strncat(stat_info->str,
2187 2191 coutstr,
2188 2192 strlen(coutstr) + 1);
2189 2193 stat_info->len = infoSize;
2190 2194 }
2191 2195
2192 2196 free(foutstr);
2193 2197 free(soutstr);
2194 2198 free(coutstr);
2195 2199 }
2196 2200
2197 2201 static int
2198 2202 checkupdate(int sighup)
2199 2203 {
2200 2204 int value;
2201 2205
2202 2206 (void) rw_wrlock(&ldap_lock);
2203 2207 value = sighup;
2204 2208 (void) rw_unlock(&ldap_lock);
2205 2209
2206 2210 return (value == TRUE);
2207 2211 }
2208 2212
2209 2213
2210 2214 static int
2211 2215 update_from_profile(int *change_status)
2212 2216 {
2213 2217 ns_ldap_result_t *result = NULL;
2214 2218 char searchfilter[BUFSIZ];
2215 2219 ns_ldap_error_t *error;
2216 2220 int rc;
2217 2221 void **paramVal = NULL;
2218 2222 ns_config_t *ptr = NULL;
2219 2223 char *profile = NULL;
2220 2224 char errstr[MAXERROR];
2221 2225
2222 2226 if (current_admin.debug_level >= DBG_ALL) {
2223 2227 logit("update_from_profile....\n");
2224 2228 }
2225 2229 do {
2226 2230 (void) rw_wrlock(&ldap_lock);
2227 2231 sighup_update = FALSE;
2228 2232 (void) rw_unlock(&ldap_lock);
2229 2233
2230 2234 if ((rc = __ns_ldap_getParam(NS_LDAP_PROFILE_P,
2231 2235 ¶mVal, &error)) != NS_LDAP_SUCCESS) {
2232 2236 if (error != NULL && error->message != NULL)
2233 2237 logit("Error: Unable to profile name: %s\n",
2234 2238 error->message);
2235 2239 else {
2236 2240 char *tmp;
2237 2241
2238 2242 __ns_ldap_err2str(rc, &tmp);
2239 2243 logit("Error: Unable to profile name: %s\n",
2240 2244 tmp);
2241 2245 }
2242 2246 (void) __ns_ldap_freeParam(¶mVal);
2243 2247 (void) __ns_ldap_freeError(&error);
2244 2248 return (-1);
2245 2249 }
2246 2250
2247 2251 if (paramVal && *paramVal)
2248 2252 profile = strdup((char *)*paramVal);
2249 2253 (void) __ns_ldap_freeParam(¶mVal);
2250 2254
2251 2255 if (profile == NULL) {
2252 2256 return (-1);
2253 2257 }
2254 2258
2255 2259 (void) snprintf(searchfilter, BUFSIZ, _PROFILE_FILTER,
2256 2260 _PROFILE1_OBJECTCLASS, _PROFILE2_OBJECTCLASS, profile);
2257 2261
2258 2262 if ((rc = __ns_ldap_list(_PROFILE_CONTAINER,
2259 2263 (const char *)searchfilter, NULL,
2260 2264 NULL, NULL, 0,
2261 2265 &result, &error, NULL, NULL)) != NS_LDAP_SUCCESS) {
2262 2266
2263 2267 /*
2264 2268 * Is profile name the DEFAULTCONFIGNAME?
2265 2269 * syslog Warning, otherwise syslog error.
2266 2270 */
2267 2271 if (strcmp(profile, DEFAULTCONFIGNAME) == 0) {
2268 2272 syslog(LOG_WARNING,
2269 2273 "Ignoring attempt to refresh nonexistent "
2270 2274 "default profile: %s.\n",
2271 2275 profile);
2272 2276 logit("Ignoring attempt to refresh nonexistent "
2273 2277 "default profile: %s.\n",
2274 2278 profile);
2275 2279 } else if ((error != NULL) &&
2276 2280 (error->message != NULL)) {
2277 2281 syslog(LOG_ERR,
2278 2282 "Error: Unable to refresh profile:%s:"
2279 2283 " %s\n", profile, error->message);
2280 2284 logit("Error: Unable to refresh profile:"
2281 2285 "%s:%s\n", profile, error->message);
2282 2286 } else {
2283 2287 syslog(LOG_ERR, "Error: Unable to refresh "
2284 2288 "from profile:%s. (error=%d)\n",
2285 2289 profile, rc);
2286 2290 logit("Error: Unable to refresh from profile "
2287 2291 "%s (error=%d)\n", profile, rc);
2288 2292 }
2289 2293
2290 2294 (void) __ns_ldap_freeError(&error);
2291 2295 (void) __ns_ldap_freeResult(&result);
2292 2296 free(profile);
2293 2297 return (-1);
2294 2298 }
2295 2299 free(profile);
2296 2300
2297 2301
2298 2302 } while (checkupdate(sighup_update) == TRUE);
2299 2303
2300 2304 (void) rw_wrlock(&ldap_lock);
2301 2305
2302 2306 ptr = __ns_ldap_make_config(result);
2303 2307 (void) __ns_ldap_freeResult(&result);
2304 2308
2305 2309 if (ptr == NULL) {
2306 2310 logit("Error: __ns_ldap_make_config failed.\n");
2307 2311 (void) rw_unlock(&ldap_lock);
2308 2312 return (-1);
2309 2313 }
2310 2314
2311 2315 /*
2312 2316 * cross check the config parameters
2313 2317 */
2314 2318 if (__s_api_crosscheck(ptr, errstr, B_TRUE) == NS_SUCCESS) {
2315 2319 /*
2316 2320 * reset the local profile TTL
2317 2321 */
2318 2322 if (ptr->paramList[NS_LDAP_CACHETTL_P].ns_pc)
2319 2323 current_admin.ldap_stat.ldap_ttl =
2320 2324 atol(ptr->paramList[NS_LDAP_CACHETTL_P].ns_pc);
2321 2325
2322 2326 if (current_admin.debug_level >= DBG_PROFILE_REFRESH) {
2323 2327 logit("update_from_profile: reset profile TTL to %d"
2324 2328 " seconds\n",
2325 2329 current_admin.ldap_stat.ldap_ttl);
2326 2330 logit("update_from_profile: expire time %ld "
2327 2331 "seconds\n",
2328 2332 ptr->paramList[NS_LDAP_EXP_P].ns_tm);
2329 2333 }
2330 2334
2331 2335 /* set ptr as current_config if the config is changed */
2332 2336 chg_test_config_change(ptr, change_status);
2333 2337 rc = 0;
2334 2338 } else {
2335 2339 __s_api_destroy_config(ptr);
2336 2340 logit("Error: downloaded profile failed to pass "
2337 2341 "crosscheck (%s).\n", errstr);
2338 2342 syslog(LOG_ERR, "ldap_cachemgr: %s", errstr);
2339 2343 rc = -1;
2340 2344 }
2341 2345 (void) rw_unlock(&ldap_lock);
2342 2346
2343 2347 return (rc);
2344 2348 }
2345 2349
2346 2350 int
2347 2351 getldap_init()
2348 2352 {
2349 2353 ns_ldap_error_t *error;
2350 2354 struct timeval tp;
2351 2355 ldap_get_chg_cookie_t cookie;
2352 2356
2353 2357 if (current_admin.debug_level >= DBG_ALL) {
2354 2358 logit("getldap_init()...\n");
2355 2359 }
2356 2360
2357 2361 (void) __ns_ldap_setServer(TRUE);
2358 2362
2359 2363 (void) rw_wrlock(&ldap_lock);
2360 2364 if ((error = __ns_ldap_LoadConfiguration()) != NULL) {
2361 2365 logit("Error: Unable to read '%s': %s\n",
2362 2366 NSCONFIGFILE, error->message);
2363 2367 (void) fprintf(stderr,
2364 2368 gettext("\nError: Unable to read '%s': %s\n"),
2365 2369 NSCONFIGFILE, error->message);
2366 2370 __ns_ldap_freeError(&error);
2367 2371 (void) rw_unlock(&ldap_lock);
2368 2372 return (-1);
2369 2373 }
2370 2374 (void) rw_unlock(&ldap_lock);
2371 2375
2372 2376 if (gettimeofday(&tp, NULL) == 0) {
2373 2377 /* statistics: previous refresh time */
2374 2378 prev_refresh_time = tp.tv_sec;
2375 2379 }
2376 2380
2377 2381 /* initialize the data cache */
2378 2382 (void) getldap_cache_op(CACHE_OP_CREATE,
2379 2383 0, NULL, NULL);
2380 2384
2381 2385 cookie.mgr_pid = getpid();
2382 2386 cookie.seq_num = 0;
2383 2387 chg_config_cookie_set(&cookie);
2384 2388 return (0);
2385 2389 }
2386 2390
2387 2391 static void
2388 2392 perform_update(void)
2389 2393 {
2390 2394 ns_ldap_error_t *error = NULL;
2391 2395 struct timeval tp;
2392 2396 char buf[20];
2393 2397 int rc, rc1;
2394 2398 int changed = 0;
2395 2399 void **paramVal = NULL;
2396 2400 ns_ldap_self_gssapi_config_t config;
2397 2401
2398 2402 if (current_admin.debug_level >= DBG_ALL) {
2399 2403 logit("perform_update()...\n");
2400 2404 }
2401 2405
2402 2406 (void) __ns_ldap_setServer(TRUE);
2403 2407
2404 2408 if (gettimeofday(&tp, NULL) != 0)
2405 2409 return;
2406 2410
2407 2411 rc = __ns_ldap_getParam(NS_LDAP_CACHETTL_P, ¶mVal, &error);
2408 2412
2409 2413 if (rc == NS_LDAP_SUCCESS && paramVal != NULL) {
2410 2414 current_admin.ldap_stat.ldap_ttl = atol((char *)*paramVal);
2411 2415 }
2412 2416
2413 2417 if (error != NULL)
2414 2418 (void) __ns_ldap_freeError(&error);
2415 2419
2416 2420 if (paramVal != NULL)
2417 2421 (void) __ns_ldap_freeParam(¶mVal);
2418 2422
2419 2423 if (current_admin.debug_level >= DBG_PROFILE_REFRESH) {
2420 2424 logit("perform_update: current profile TTL is %d seconds\n",
2421 2425 current_admin.ldap_stat.ldap_ttl);
2422 2426 }
2423 2427
2424 2428 if (current_admin.ldap_stat.ldap_ttl > 0) {
2425 2429 /*
2426 2430 * set the profile TTL parameter, just
2427 2431 * in case that the downloading of
2428 2432 * the profile from server would fail
2429 2433 */
2430 2434
2431 2435 /*
2432 2436 * NS_LDAP_EXP_P is a no op for __ns_ldap_setParam
2433 2437 * It depends on NS_LDAP_CACHETTL_P to set it's value
2434 2438 * Set NS_LDAP_CACHETTL_P here so NS_LDAP_EXP_P value
2435 2439 * can be set.
2436 2440 * NS_LDAP_CACHETTL_P value can be reset after the profile is
2437 2441 * downloaded from the server, so is NS_LDAP_EXP_P.
2438 2442 */
2439 2443 buf[19] = '\0'; /* null terminated the buffer */
2440 2444 if (__ns_ldap_setParam(NS_LDAP_CACHETTL_P,
2441 2445 lltostr((long long)current_admin.ldap_stat.ldap_ttl,
2442 2446 &buf[19]),
2443 2447 &error) != NS_LDAP_SUCCESS) {
2444 2448 logit("Error: __ns_ldap_setParam failed, status: %d "
2445 2449 "message: %s\n", error->status, error->message);
2446 2450 (void) __ns_ldap_freeError(&error);
2447 2451 return;
2448 2452 }
2449 2453
2450 2454 (void) rw_wrlock(&ldap_lock);
2451 2455 sighup_update = FALSE;
2452 2456 (void) rw_unlock(&ldap_lock);
2453 2457
2454 2458 do {
2455 2459 rc = update_from_profile(&changed);
2456 2460 if (rc != 0) {
2457 2461 logit("Error: Unable to update from profile\n");
2458 2462 }
2459 2463 } while (checkupdate(sighup_update) == TRUE);
2460 2464 } else {
2461 2465 rc = 0;
2462 2466 }
2463 2467
2464 2468 /*
2465 2469 * recreate the server info list
2466 2470 */
2467 2471 if (rc == 0) {
2468 2472 (void) getldap_serverInfo_op(INFO_OP_CREATE, NULL, NULL);
2469 2473
2470 2474 /* flush the data cache */
2471 2475 (void) getldap_cache_op(CACHE_OP_DELETE,
2472 2476 0, NULL, NULL);
2473 2477
2474 2478 /* statistics: previous refresh time */
2475 2479 prev_refresh_time = tp.tv_sec;
2476 2480 }
2477 2481 rc1 = __ns_ldap_self_gssapi_config(&config);
2478 2482 if (rc1 == NS_LDAP_SUCCESS) {
2479 2483 if (config != NS_LDAP_SELF_GSSAPI_CONFIG_NONE) {
2480 2484 rc1 = __ns_ldap_check_all_preq(0, 0, 0, config, &error);
2481 2485 (void) __ns_ldap_freeError(&error);
2482 2486 if (rc1 != NS_LDAP_SUCCESS) {
2483 2487 logit("Error: Check on self credential "
2484 2488 "prerquesites failed: %d\n",
2485 2489 rc1);
2486 2490 exit(rc1);
2487 2491 }
2488 2492 }
2489 2493 } else {
2490 2494 logit("Error: Failed to get self credential configuration %d\n",
2491 2495 rc1);
2492 2496 exit(rc1);
2493 2497 }
2494 2498
2495 2499 if (!changed)
2496 2500 return;
2497 2501
2498 2502 (void) rw_rdlock(&ldap_lock);
2499 2503 if (((error = __ns_ldap_DumpConfiguration(NSCONFIGREFRESH)) != NULL) ||
2500 2504 ((error = __ns_ldap_DumpConfiguration(NSCREDREFRESH)) != NULL)) {
2501 2505 logit("Error: __ns_ldap_DumpConfiguration failed, "
2502 2506 "status: %d message: %s\n", error->status, error->message);
2503 2507 __ns_ldap_freeError(&error);
2504 2508 (void) rw_unlock(&ldap_lock);
2505 2509 return;
2506 2510 }
2507 2511 if (rename(NSCONFIGREFRESH, NSCONFIGFILE) != 0) {
2508 2512 logit("Error: unlink failed - errno: %s\n", strerror(errno));
2509 2513 syslog(LOG_ERR, "Unable to refresh profile, LDAP configuration"
2510 2514 "files not written");
2511 2515 (void) rw_unlock(&ldap_lock);
2512 2516 return;
2513 2517 }
2514 2518 if (rename(NSCREDREFRESH, NSCREDFILE) != 0) {
2515 2519 /*
2516 2520 * We probably have inconsistent configuration at this point.
2517 2521 * If we were to create a backup file and rename it here, that
2518 2522 * operation might also fail. Consequently there is no safe way
2519 2523 * to roll back.
2520 2524 */
2521 2525 logit("Error: unlink failed - errno: %s\n", strerror(errno));
2522 2526 syslog(LOG_ERR, "Unable to refresh profile consistently, "
2523 2527 "LDAP configuration files inconsistent");
2524 2528 (void) rw_unlock(&ldap_lock);
2525 2529 return;
2526 2530 }
2527 2531
2528 2532 (void) rw_unlock(&ldap_lock);
2529 2533 }
2530 2534
2531 2535 void
2532 2536 getldap_refresh()
2533 2537 {
2534 2538 struct timespec timeout;
↓ open down ↓ |
891 lines elided |
↑ open up ↑ |
2535 2539 int sleeptime;
2536 2540 struct timeval tp;
2537 2541 long expire = 0;
2538 2542 void **paramVal = NULL;
2539 2543 ns_ldap_error_t *errorp;
2540 2544 int always = 1, err;
2541 2545 int first_time = 1;
2542 2546 int sig_done = 0;
2543 2547 int dbg_level;
2544 2548
2549 + (void) pthread_setname_np(pthread_self(), "getldap_refresh");
2550 +
2545 2551 if (current_admin.debug_level >= DBG_ALL) {
2546 2552 logit("getldap_refresh()...\n");
2547 2553 }
2548 2554
2549 2555 /*
2550 2556 * wait for an available server
2551 2557 */
2552 2558 while (sig_done == 0) {
2553 2559 (void) mutex_lock(&sig_mutex);
2554 2560 sig_done = signal_done;
2555 2561 (void) mutex_unlock(&sig_mutex);
2556 2562 }
2557 2563
2558 2564 (void) __ns_ldap_setServer(TRUE);
2559 2565 while (always) {
2560 2566 dbg_level = current_admin.debug_level;
2561 2567 (void) rw_rdlock(&ldap_lock);
2562 2568 sleeptime = current_admin.ldap_stat.ldap_ttl;
2563 2569 if (dbg_level >= DBG_PROFILE_REFRESH) {
2564 2570 logit("getldap_refresh: current profile TTL is %d "
2565 2571 "seconds\n", current_admin.ldap_stat.ldap_ttl);
2566 2572 }
2567 2573 if (gettimeofday(&tp, NULL) == 0) {
2568 2574 if ((__ns_ldap_getParam(NS_LDAP_EXP_P,
2569 2575 ¶mVal, &errorp) == NS_LDAP_SUCCESS) &&
2570 2576 paramVal != NULL &&
2571 2577 (char *)*paramVal != NULL) {
2572 2578 errno = 0;
2573 2579 expire = atol((char *)*paramVal);
2574 2580 (void) __ns_ldap_freeParam(¶mVal);
2575 2581 if (errno == 0) {
2576 2582 if (expire == 0) {
2577 2583 first_time = 0;
2578 2584 (void) rw_unlock(&ldap_lock);
2579 2585 (void) cond_init(&cond,
2580 2586 NULL, NULL);
2581 2587 (void) mutex_lock(&sighuplock);
2582 2588 timeout.tv_sec =
2583 2589 CACHESLEEPTIME;
2584 2590 timeout.tv_nsec = 0;
2585 2591 if (dbg_level >=
2586 2592 DBG_PROFILE_REFRESH) {
2587 2593 logit("getldap_refresh:"
2588 2594 "(1)about to sleep"
2589 2595 " for %d seconds\n",
2590 2596 CACHESLEEPTIME);
2591 2597 }
2592 2598 err = cond_reltimedwait(&cond,
2593 2599 &sighuplock, &timeout);
2594 2600 (void) cond_destroy(&cond);
2595 2601 (void) mutex_unlock(
2596 2602 &sighuplock);
2597 2603 /*
2598 2604 * if woke up by
2599 2605 * getldap_revalidate(),
2600 2606 * do update right away
2601 2607 */
2602 2608 if (err == ETIME)
2603 2609 continue;
2604 2610 else {
2605 2611 /*
2606 2612 * if load
2607 2613 * configuration failed
2608 2614 * don't do update
2609 2615 */
2610 2616 if (load_config())
2611 2617 perform_update
2612 2618 ();
2613 2619 continue;
2614 2620 }
2615 2621 }
2616 2622 sleeptime = expire - tp.tv_sec;
2617 2623 if (dbg_level >= DBG_PROFILE_REFRESH) {
2618 2624 logit("getldap_refresh: expire "
2619 2625 "time = %ld\n", expire);
2620 2626 }
2621 2627
2622 2628 }
2623 2629 }
2624 2630 }
2625 2631
2626 2632 (void) rw_unlock(&ldap_lock);
2627 2633
2628 2634 /*
2629 2635 * if this is the first time downloading
2630 2636 * the profile or expire time already passed,
2631 2637 * do not wait, do update
2632 2638 */
2633 2639 if (first_time == 0 && sleeptime > 0) {
2634 2640 if (dbg_level >= DBG_PROFILE_REFRESH) {
2635 2641 logit("getldap_refresh: (2)about to sleep "
2636 2642 "for %d seconds\n", sleeptime);
2637 2643 }
2638 2644 (void) cond_init(&cond, NULL, NULL);
2639 2645 (void) mutex_lock(&sighuplock);
2640 2646 timeout.tv_sec = sleeptime;
2641 2647 timeout.tv_nsec = 0;
2642 2648 err = cond_reltimedwait(&cond,
2643 2649 &sighuplock, &timeout);
2644 2650 (void) cond_destroy(&cond);
2645 2651 (void) mutex_unlock(&sighuplock);
2646 2652 }
2647 2653 /*
2648 2654 * if load concfiguration failed
2649 2655 * don't do update
2650 2656 */
2651 2657 if (load_config())
2652 2658 perform_update();
2653 2659 first_time = 0;
2654 2660 }
2655 2661 }
2656 2662
2657 2663 void
2658 2664 getldap_revalidate()
2659 2665 {
2660 2666 if (current_admin.debug_level >= DBG_ALL) {
2661 2667 logit("getldap_revalidate()...\n");
2662 2668 }
2663 2669 /* block signal SIGHUP */
2664 2670 (void) sighold(SIGHUP);
2665 2671
2666 2672 /* now awake the sleeping refresh thread */
2667 2673 (void) cond_signal(&cond);
2668 2674
2669 2675 /* release signal SIGHUP */
2670 2676 (void) sigrelse(SIGHUP);
2671 2677
2672 2678 }
2673 2679
2674 2680 void
2675 2681 getldap_admincred(LineBuf *config_info, ldap_call_t *in)
2676 2682 {
2677 2683 ns_ldap_error_t *error;
2678 2684 ldap_config_out_t *cout;
2679 2685 ucred_t *uc = NULL;
2680 2686
2681 2687 if (current_admin.debug_level >= DBG_ALL) {
2682 2688 logit("getldap_admincred()...\n");
2683 2689 }
2684 2690 /* check privileges */
2685 2691 if (is_root_or_all_privs("GETADMINCRED", &uc) == 0) {
2686 2692 logit("admin credential requested by a non-root and no ALL "
2687 2693 "privilege user not allowed");
2688 2694 config_info->str = NULL;
2689 2695 config_info->len = 0;
2690 2696 } else {
2691 2697 (void) rw_rdlock(&ldap_lock);
2692 2698 if ((error = __ns_ldap_LoadDoorInfo(config_info,
2693 2699 in->ldap_u.domainname, NULL, 1)) != NULL) {
2694 2700 if (error != NULL && error->message != NULL)
2695 2701 logit("Error: ldap_lookup: %s\n",
2696 2702 error->message);
2697 2703 (void) __ns_ldap_freeError(&error);
2698 2704
2699 2705 config_info->str = NULL;
2700 2706 config_info->len = 0;
2701 2707 }
2702 2708 /* set change cookie */
2703 2709 cout = (ldap_config_out_t *)config_info->str;
2704 2710 if (cout)
2705 2711 cout->cookie = chg_config_cookie_get();
2706 2712 (void) rw_unlock(&ldap_lock);
2707 2713 }
2708 2714 }
2709 2715
2710 2716 void
2711 2717 getldap_lookup(LineBuf *config_info, ldap_call_t *in)
2712 2718 {
2713 2719 ns_ldap_error_t *error;
2714 2720 ldap_config_out_t *cout;
2715 2721
2716 2722 if (current_admin.debug_level >= DBG_ALL) {
2717 2723 logit("getldap_lookup()...\n");
2718 2724 }
2719 2725 (void) rw_rdlock(&ldap_lock);
2720 2726 if ((error = __ns_ldap_LoadDoorInfo(config_info,
2721 2727 in->ldap_u.domainname, NULL, 0)) != NULL) {
2722 2728 if (error != NULL && error->message != NULL)
2723 2729 logit("Error: ldap_lookup: %s\n", error->message);
2724 2730 (void) __ns_ldap_freeError(&error);
2725 2731
2726 2732 config_info->str = NULL;
2727 2733 config_info->len = 0;
2728 2734 }
2729 2735 /* set change cookie */
2730 2736 cout = (ldap_config_out_t *)config_info->str;
2731 2737 if (cout)
2732 2738 cout->cookie = chg_config_cookie_get();
2733 2739 (void) rw_unlock(&ldap_lock);
2734 2740 }
2735 2741 /*
2736 2742 * It creates the header and data stream to be door returned and notify
2737 2743 * chg_get_statusChange() threads.
2738 2744 * This is called after all getldap_get_rootDSE() threads are joined.
2739 2745 */
2740 2746 void
2741 2747 test_server_change(server_info_t *head)
2742 2748 {
2743 2749 server_info_t *info;
2744 2750 int len = 0, num = 0, ds_len = 0, new_len = 0, tlen = 0;
2745 2751 char *tmp_buf = NULL, *ptr = NULL, *status = NULL;
2746 2752 ldap_get_change_out_t *cout;
2747 2753
2748 2754 ds_len = strlen(DOORLINESEP);
2749 2755
2750 2756 for (info = head; info; info = info->next) {
2751 2757 (void) mutex_lock(&info->mutex[0]);
2752 2758 if (info->sinfo[0].change != 0) {
2753 2759 /* "9.9.9.9|NS_SERVER_CHANGE_UP|" */
2754 2760 len += 2 * ds_len + strlen(info->sinfo[0].addr) +
2755 2761 strlen(NS_SERVER_CHANGE_UP);
2756 2762 num++;
2757 2763 }
2758 2764 (void) mutex_unlock(&info->mutex[0]);
2759 2765 }
2760 2766
2761 2767 if (len == 0)
2762 2768 return;
2763 2769
2764 2770 len++; /* '\0' */
2765 2771
2766 2772 tlen = sizeof (ldap_get_change_out_t) - sizeof (int) + len;
2767 2773 if ((tmp_buf = malloc(tlen)) == NULL)
2768 2774 return;
2769 2775
2770 2776 cout = (ldap_get_change_out_t *)tmp_buf;
2771 2777 cout->type = NS_STATUS_CHANGE_TYPE_SERVER;
2772 2778 /* cout->cookie is set by chg_notify_statusChange */
2773 2779 cout->server_count = num;
2774 2780 cout->data_size = len;
2775 2781
2776 2782 /* Create IP|UP or DOWN|IP|UP or DOWN| ... */
2777 2783 ptr = cout->data;
2778 2784 new_len = len;
2779 2785 for (info = head; info; info = info->next) {
2780 2786 (void) mutex_lock(&info->mutex[0]);
2781 2787 if (info->sinfo[0].change == 0) {
2782 2788 (void) mutex_unlock(&info->mutex[0]);
2783 2789 continue;
2784 2790 }
2785 2791
2786 2792 if (info->sinfo[0].change == NS_SERVER_UP)
2787 2793 status = NS_SERVER_CHANGE_UP;
2788 2794 else if (info->sinfo[0].change == NS_SERVER_DOWN)
2789 2795 status = NS_SERVER_CHANGE_DOWN;
2790 2796 else {
2791 2797 syslog(LOG_WARNING, gettext("Bad change value %d"),
2792 2798 info->sinfo[0].change);
2793 2799 (void) mutex_unlock(&info->mutex[0]);
2794 2800 free(tmp_buf);
2795 2801 return;
2796 2802 }
2797 2803
2798 2804 if ((snprintf(ptr, new_len, "%s%s%s%s",
2799 2805 info->sinfo[0].addr, DOORLINESEP,
2800 2806 status, DOORLINESEP)) >= new_len) {
2801 2807 (void) mutex_unlock(&info->mutex[0]);
2802 2808 break;
2803 2809 }
2804 2810 new_len -= strlen(ptr);
2805 2811 ptr += strlen(ptr);
2806 2812
2807 2813 (void) mutex_unlock(&info->mutex[0]);
2808 2814 }
2809 2815 (void) chg_notify_statusChange(tmp_buf);
2810 2816 }
2811 2817 /*
2812 2818 * It creates the header and data stream to be door returned and notify
2813 2819 * chg_get_statusChange() threads.
2814 2820 * This is called in removing server case.
2815 2821 */
2816 2822 static void
2817 2823 create_buf_and_notify(char *input, ns_server_status_t st)
2818 2824 {
2819 2825 rm_svr_t *rms = (rm_svr_t *)input;
2820 2826 char *tmp_buf, *ptr, *status;
2821 2827 int len, tlen;
2822 2828 ldap_get_change_out_t *cout;
2823 2829
2824 2830 /* IP|UP or DOWN| */
2825 2831 len = 2 * strlen(DOORLINESEP) + strlen(rms->addr) +
2826 2832 strlen(NS_SERVER_CHANGE_UP) + 1;
2827 2833
2828 2834 tlen = sizeof (ldap_get_change_out_t) - sizeof (int) + len;
2829 2835
2830 2836 if ((tmp_buf = malloc(tlen)) == NULL)
2831 2837 return;
2832 2838
2833 2839 cout = (ldap_get_change_out_t *)tmp_buf;
2834 2840 cout->type = NS_STATUS_CHANGE_TYPE_SERVER;
2835 2841 /* cout->cookie is set by chg_notify_statusChange */
2836 2842 cout->server_count = 1;
2837 2843 cout->data_size = len;
2838 2844
2839 2845 /* Create IP|DOWN| */
2840 2846 ptr = cout->data;
2841 2847 if (st == NS_SERVER_UP)
2842 2848 status = NS_SERVER_CHANGE_UP;
2843 2849 else if (st == NS_SERVER_DOWN)
2844 2850 status = NS_SERVER_CHANGE_DOWN;
2845 2851
2846 2852 (void) snprintf(ptr, len, "%s%s%s%s",
2847 2853 rms->addr, DOORLINESEP, status, DOORLINESEP);
2848 2854
2849 2855 (void) chg_notify_statusChange(tmp_buf);
2850 2856
2851 2857 }
2852 2858
2853 2859 /*
2854 2860 * Return: 0 server is down, 1 server is up
2855 2861 */
2856 2862 static int
2857 2863 contact_server(char *addr)
2858 2864 {
2859 2865 char *rootDSE = NULL;
2860 2866 ns_ldap_error_t *error = NULL;
2861 2867 int rc;
2862 2868
2863 2869 if (__ns_ldap_getRootDSE(addr, &rootDSE, &error,
2864 2870 SA_ALLOW_FALLBACK) != NS_LDAP_SUCCESS) {
2865 2871 if (current_admin.debug_level >= DBG_ALL)
2866 2872 logit("get rootDSE %s failed. %s", addr,
2867 2873 error->message ? error->message : "");
2868 2874 rc = 0;
2869 2875 } else
2870 2876 rc = 1;
2871 2877
2872 2878 if (rootDSE)
2873 2879 free(rootDSE);
2874 2880 if (error)
2875 2881 (void) __ns_ldap_freeError(&error);
2876 2882
2877 2883 return (rc);
2878 2884 }
2879 2885
2880 2886 /*
2881 2887 * The thread is spawned to do contact_server() so it won't be blocking
2882 2888 * getldap_serverInfo_op(INFO_OP_GETSERVER, ...) case.
2883 2889 * After contact_server() is done, it calls
2884 2890 * getldap_serverInfo_op(INFO_OP_REMOVESERVER, ...) to return to the remaining
↓ open down ↓ |
330 lines elided |
↑ open up ↑ |
2885 2891 * program flow. It's meant to maintain the original program flow yet be
2886 2892 * non-blocking when it's contacting server.
2887 2893 */
2888 2894 static void *
2889 2895 remove_server_thread(void *arg)
2890 2896 {
2891 2897 char *addr = (char *)arg, *out = NULL;
2892 2898 int up;
2893 2899 rm_svr_t rms;
2894 2900
2901 + (void) pthread_setname_np(pthread_self(), "remove_server");
2902 +
2895 2903 up = contact_server(addr);
2896 2904
2897 2905 rms.addr = addr;
2898 2906 rms.up = up;
2899 2907
2900 2908 (void) getldap_serverInfo_op(INFO_OP_REMOVESERVER, (char *)&rms, &out);
2901 2909
2902 2910 free(addr);
2903 2911
2904 2912 thr_exit(NULL);
2905 2913 return (NULL);
2906 2914 }
2907 2915 /*
2908 2916 * addr is allocated and is freed by remove_server_thread
2909 2917 * It starts a thread to contact server and remove server to avoid long wait
2910 2918 * or recursion.
2911 2919 */
2912 2920 static void
2913 2921 remove_server(char *addr)
2914 2922 {
2915 2923 if (thr_create(NULL, 0, remove_server_thread,
2916 2924 (void *)addr, THR_BOUND|THR_DETACHED, NULL) != 0) {
2917 2925 free(addr);
2918 2926 syslog(LOG_ERR, "thr_create failed for remove_server_thread");
2919 2927 }
2920 2928 }
2921 2929 /*
2922 2930 * Compare the server_status and mark it up or down accordingly.
2923 2931 * This is called in removing server case.
2924 2932 */
2925 2933 static ns_server_status_t
2926 2934 set_server_status(char *input, server_info_t *head)
2927 2935 {
2928 2936 rm_svr_t *rms = (rm_svr_t *)input;
2929 2937 ns_server_status_t changed = 0;
2930 2938 server_info_t *info;
2931 2939
2932 2940 for (info = head; info != NULL; info = info->next) {
2933 2941 (void) mutex_lock(&info->mutex[0]);
2934 2942 if (strcmp(info->sinfo[0].addr, rms->addr) == 0) {
2935 2943 if (info->sinfo[0].server_status == INFO_SERVER_UP &&
2936 2944 rms->up == FALSE) {
2937 2945 info->sinfo[0].prev_server_status =
2938 2946 info->sinfo[0].server_status;
2939 2947 info->sinfo[0].server_status =
2940 2948 INFO_SERVER_ERROR;
2941 2949 info->sinfo[0].change = NS_SERVER_DOWN;
2942 2950 changed = NS_SERVER_DOWN;
2943 2951
2944 2952 } else if (info->sinfo[0].server_status ==
2945 2953 INFO_SERVER_ERROR && rms->up == TRUE) {
2946 2954 /*
2947 2955 * It should be INFO_SERVER_UP, but check here
2948 2956 */
2949 2957 info->sinfo[0].prev_server_status =
2950 2958 info->sinfo[0].server_status;
2951 2959 info->sinfo[0].server_status =
2952 2960 INFO_SERVER_UP;
2953 2961 info->sinfo[0].change = NS_SERVER_UP;
2954 2962 changed = NS_SERVER_UP;
2955 2963 }
2956 2964 (void) mutex_unlock(&info->mutex[0]);
2957 2965 break;
2958 2966 }
2959 2967 (void) mutex_unlock(&info->mutex[0]);
2960 2968 }
2961 2969 if (changed) {
2962 2970 /* ldap_cachemgr -g option looks up [1] */
2963 2971 (void) mutex_lock(&info->mutex[1]);
2964 2972 info->sinfo[1].prev_server_status =
2965 2973 info->sinfo[1].server_status;
2966 2974 if (changed == NS_SERVER_DOWN)
2967 2975 info->sinfo[1].server_status = INFO_SERVER_ERROR;
2968 2976 else if (changed == NS_SERVER_UP)
2969 2977 info->sinfo[1].server_status = INFO_SERVER_UP;
2970 2978 (void) mutex_unlock(&info->mutex[1]);
2971 2979 }
2972 2980 return (changed);
2973 2981 }
↓ open down ↓ |
69 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX