1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 /* 29 * Simple doors ldap cache daemon 30 */ 31 32 #include <stdio.h> 33 #include <stdlib.h> 34 #include <signal.h> 35 #include <door.h> 36 #include <time.h> 37 #include <string.h> 38 #include <libintl.h> 39 #include <sys/stat.h> 40 #include <sys/time.h> 41 #include <sys/wait.h> 42 #include <stdlib.h> 43 #include <errno.h> 44 #include <pthread.h> 45 #include <thread.h> 46 #include <stdarg.h> 47 #include <fcntl.h> 48 #include <assert.h> 49 #include <unistd.h> 50 #include <memory.h> 51 #include <sys/types.h> 52 #include <syslog.h> 53 #include <locale.h> /* LC_ALL */ 54 #include "cachemgr.h" 55 56 static void detachfromtty(); 57 admin_t current_admin; 58 static int will_become_server; 59 60 static void switcher(void *cookie, char *argp, size_t arg_size, 61 door_desc_t *dp, uint_t n_desc); 62 static void usage(char *s); 63 static int cachemgr_set_lf(admin_t *ptr, char *logfile); 64 static int client_getadmin(admin_t *ptr); 65 static int getadmin(ldap_return_t *out); 66 static int setadmin(ldap_return_t *out, ldap_call_t *ptr); 67 static int client_setadmin(admin_t *ptr); 68 static int client_showstats(admin_t *ptr); 69 70 #ifdef SLP 71 int use_slp = 0; 72 static unsigned int refresh = 10800; /* dynamic discovery interval */ 73 #endif /* SLP */ 74 75 static ldap_stat_t * 76 getcacheptr(char *s) 77 { 78 static const char *caches[1] = {"ldap"}; 79 80 if (strncmp(caches[0], s, strlen(caches[0])) == 0) 81 return (¤t_admin.ldap_stat); 82 83 return (NULL); 84 } 85 86 char * 87 getcacheopt(char *s) 88 { 89 while (*s && *s != ',') 90 s++; 91 return ((*s == ',') ? (s + 1) : NULL); 92 } 93 94 /* 95 * This is here to prevent the ldap_cachemgr becomes 96 * daemonlized to early to soon during boot time. 97 * This causes problems during boot when automounter 98 * and others try to use libsldap before ldap_cachemgr 99 * finishes walking the server list. 100 */ 101 static void 102 sig_ok_to_exit(int signo) 103 { 104 if (signo == SIGUSR1) { 105 logit("sig_ok_to_exit(): parent exiting...\n"); 106 exit(0); 107 } else { 108 logit("sig_ok_to_exit(): invalid signal(%d) received.\n", 109 signo); 110 syslog(LOG_ERR, gettext("ldap_cachemgr: " 111 "invalid signal(%d) received."), signo); 112 exit(1); 113 } 114 } 115 #define LDAP_TABLES 1 /* ldap */ 116 #define TABLE_THREADS 10 117 #define COMMON_THREADS 20 118 #define CACHE_MISS_THREADS (COMMON_THREADS + LDAP_TABLES * TABLE_THREADS) 119 #define CACHE_HIT_THREADS 20 120 #define MAX_SERVER_THREADS (CACHE_HIT_THREADS + CACHE_MISS_THREADS) 121 122 static sema_t common_sema; 123 static sema_t ldap_sema; 124 static thread_key_t lookup_state_key; 125 126 static void 127 initialize_lookup_clearance() 128 { 129 (void) thr_keycreate(&lookup_state_key, NULL); 130 (void) sema_init(&common_sema, COMMON_THREADS, USYNC_THREAD, 0); 131 (void) sema_init(&ldap_sema, TABLE_THREADS, USYNC_THREAD, 0); 132 } 133 134 int 135 get_clearance(int callnumber) 136 { 137 sema_t *table_sema = NULL; 138 char *tab; 139 140 if (sema_trywait(&common_sema) == 0) { 141 (void) thr_setspecific(lookup_state_key, NULL); 142 return (0); 143 } 144 145 switch (callnumber) { 146 case GETLDAPCONFIG: 147 tab = "ldap"; 148 table_sema = &ldap_sema; 149 break; 150 default: 151 logit("Internal Error: get_clearance\n"); 152 break; 153 } 154 155 if (sema_trywait(table_sema) == 0) { 156 (void) thr_setspecific(lookup_state_key, (void*)1); 157 return (0); 158 } 159 160 if (current_admin.debug_level >= DBG_CANT_FIND) { 161 logit("get_clearance: throttling load for %s table\n", tab); 162 } 163 164 return (-1); 165 } 166 167 int 168 release_clearance(int callnumber) 169 { 170 int which; 171 sema_t *table_sema = NULL; 172 173 (void) thr_getspecific(lookup_state_key, (void**)&which); 174 if (which == 0) /* from common pool */ { 175 (void) sema_post(&common_sema); 176 return (0); 177 } 178 179 switch (callnumber) { 180 case GETLDAPCONFIG: 181 table_sema = &ldap_sema; 182 break; 183 default: 184 logit("Internal Error: release_clearance\n"); 185 break; 186 } 187 (void) sema_post(table_sema); 188 189 return (0); 190 } 191 192 193 static mutex_t create_lock; 194 static int num_servers = 0; 195 static thread_key_t server_key; 196 197 198 /* 199 * Bind a TSD value to a server thread. This enables the destructor to 200 * be called if/when this thread exits. This would be a programming error, 201 * but better safe than sorry. 202 */ 203 204 /*ARGSUSED*/ 205 static void * 206 server_tsd_bind(void *arg) 207 { 208 static void *value = 0; 209 210 /* 211 * disable cancellation to prevent hangs when server 212 * threads disappear 213 */ 214 215 (void) thr_setspecific(server_key, value); 216 (void) door_return(NULL, 0, NULL, 0); 217 218 return (value); 219 } 220 221 /* 222 * Server threads are created here. 223 */ 224 225 /*ARGSUSED*/ 226 static void 227 server_create(door_info_t *dip) 228 { 229 (void) mutex_lock(&create_lock); 230 if (++num_servers > MAX_SERVER_THREADS) { 231 num_servers--; 232 (void) mutex_unlock(&create_lock); 233 return; 234 } 235 (void) mutex_unlock(&create_lock); 236 (void) thr_create(NULL, 0, server_tsd_bind, NULL, 237 THR_BOUND|THR_DETACHED, NULL); 238 } 239 240 /* 241 * Server thread are destroyed here 242 */ 243 244 /*ARGSUSED*/ 245 static void 246 server_destroy(void *arg) 247 { 248 (void) mutex_lock(&create_lock); 249 num_servers--; 250 (void) mutex_unlock(&create_lock); 251 } 252 253 int 254 main(int argc, char ** argv) 255 { 256 int did; 257 int opt; 258 int errflg = 0; 259 int showstats = 0; 260 int doset = 0; 261 int dofg = 0; 262 struct stat buf; 263 sigset_t myset; 264 struct sigaction sighupaction; 265 static void client_killserver(); 266 int debug_level = 0; 267 268 /* setup for localization */ 269 (void) setlocale(LC_ALL, ""); 270 (void) textdomain(TEXT_DOMAIN); 271 272 openlog("ldap_cachemgr", LOG_PID, LOG_DAEMON); 273 274 if (chdir(NSLDAPDIRECTORY) < 0) { 275 (void) fprintf(stderr, gettext("chdir(\"%s\") failed: %s\n"), 276 NSLDAPDIRECTORY, strerror(errno)); 277 exit(1); 278 } 279 280 /* 281 * Correctly set file mode creation mask, so to make the new files 282 * created for door calls being readable by all. 283 */ 284 (void) umask(0); 285 286 /* 287 * Special case non-root user here - he/she/they/it can just print 288 * stats 289 */ 290 291 if (geteuid()) { 292 if (argc != 2 || strcmp(argv[1], "-g")) { 293 (void) fprintf(stderr, 294 gettext("Must be root to use any option " 295 "other than -g.\n\n")); 296 usage(argv[0]); 297 } 298 299 if ((__ns_ldap_cache_ping() != SUCCESS) || 300 (client_getadmin(¤t_admin) != 0)) { 301 (void) fprintf(stderr, 302 gettext("%s doesn't appear to be running.\n"), 303 argv[0]); 304 exit(1); 305 } 306 (void) client_showstats(¤t_admin); 307 exit(0); 308 } 309 310 311 312 /* 313 * Determine if there is already a daemon running 314 */ 315 316 will_become_server = (__ns_ldap_cache_ping() != SUCCESS); 317 318 /* 319 * load normal config file 320 */ 321 322 if (will_become_server) { 323 static const ldap_stat_t defaults = { 324 0, /* stat */ 325 DEFAULTTTL}; /* ttl */ 326 327 current_admin.ldap_stat = defaults; 328 (void) strcpy(current_admin.logfile, LOGFILE); 329 } else { 330 if (client_getadmin(¤t_admin)) { 331 (void) fprintf(stderr, gettext("Cannot contact %s " 332 "properly(?)\n"), argv[0]); 333 exit(1); 334 } 335 } 336 337 #ifndef SLP 338 while ((opt = getopt(argc, argv, "fKgl:r:d:")) != EOF) { 339 #else 340 while ((opt = getopt(argc, argv, "fKgs:l:r:d:")) != EOF) { 341 #endif /* SLP */ 342 ldap_stat_t *cache; 343 344 switch (opt) { 345 case 'K': 346 client_killserver(); 347 exit(0); 348 break; 349 case 'g': 350 showstats++; 351 break; 352 case 'f': 353 dofg++; 354 break; 355 case 'r': 356 doset++; 357 cache = getcacheptr("ldap"); 358 if (!optarg) { 359 errflg++; 360 break; 361 } 362 cache->ldap_ttl = atoi(optarg); 363 break; 364 case 'l': 365 doset++; 366 (void) strlcpy(current_admin.logfile, 367 optarg, sizeof (current_admin.logfile)); 368 break; 369 case 'd': 370 doset++; 371 debug_level = atoi(optarg); 372 break; 373 #ifdef SLP 374 case 's': /* undocumented: use dynamic (SLP) config */ 375 use_slp = 1; 376 break; 377 #endif /* SLP */ 378 default: 379 errflg++; 380 break; 381 } 382 } 383 384 if (errflg) 385 usage(argv[0]); 386 387 /* 388 * will not show statistics if no daemon running 389 */ 390 if (will_become_server && showstats) { 391 (void) fprintf(stderr, 392 gettext("%s doesn't appear to be running.\n"), 393 argv[0]); 394 exit(1); 395 } 396 397 if (!will_become_server) { 398 if (showstats) { 399 (void) client_showstats(¤t_admin); 400 } 401 if (doset) { 402 current_admin.debug_level = debug_level; 403 if (client_setadmin(¤t_admin) < 0) { 404 (void) fprintf(stderr, 405 gettext("Error during admin call\n")); 406 exit(1); 407 } 408 } 409 if (!showstats && !doset) { 410 (void) fprintf(stderr, 411 gettext("%s already running....use '%s " 412 "-K' to stop\n"), argv[0], argv[0]); 413 } 414 exit(0); 415 } 416 417 /* 418 * daemon from here on 419 */ 420 421 if (debug_level) { 422 /* 423 * we're debugging... 424 */ 425 if (strlen(current_admin.logfile) == 0) 426 /* 427 * no specified log file 428 */ 429 (void) strcpy(current_admin.logfile, LOGFILE); 430 else 431 (void) cachemgr_set_lf(¤t_admin, 432 current_admin.logfile); 433 /* 434 * validate the range of debug level number 435 * and set the number to current_admin.debug_level 436 */ 437 if (cachemgr_set_dl(¤t_admin, debug_level) < 0) { 438 /* 439 * print error messages to the screen 440 * cachemgr_set_dl prints msgs to cachemgr.log 441 * only 442 */ 443 (void) fprintf(stderr, 444 gettext("Incorrect Debug Level: %d\n" 445 "It should be between %d and %d\n"), 446 debug_level, DBG_OFF, MAXDEBUG); 447 exit(-1); 448 } 449 } else { 450 if (strlen(current_admin.logfile) == 0) 451 (void) strcpy(current_admin.logfile, "/dev/null"); 452 (void) cachemgr_set_lf(¤t_admin, 453 current_admin.logfile); 454 } 455 456 if (dofg == 0) 457 detachfromtty(argv[0]); 458 459 /* 460 * perform some initialization 461 */ 462 463 initialize_lookup_clearance(); 464 465 if (getldap_init() != 0) 466 exit(-1); 467 468 /* 469 * Establish our own server thread pool 470 */ 471 472 (void) door_server_create(server_create); 473 if (thr_keycreate(&server_key, server_destroy) != 0) { 474 logit("thr_keycreate() call failed\n"); 475 syslog(LOG_ERR, 476 gettext("ldap_cachemgr: thr_keycreate() call failed")); 477 perror("thr_keycreate"); 478 exit(-1); 479 } 480 481 /* 482 * Create a door 483 */ 484 485 if ((did = door_create(switcher, LDAP_CACHE_DOOR_COOKIE, 486 DOOR_UNREF | DOOR_REFUSE_DESC | DOOR_NO_CANCEL)) < 0) { 487 logit("door_create() call failed\n"); 488 syslog(LOG_ERR, gettext( 489 "ldap_cachemgr: door_create() call failed")); 490 perror("door_create"); 491 exit(-1); 492 } 493 494 /* 495 * bind to file system 496 */ 497 498 if (stat(LDAP_CACHE_DOOR, &buf) < 0) { 499 int newfd; 500 501 if ((newfd = creat(LDAP_CACHE_DOOR, 0444)) < 0) { 502 logit("Cannot create %s:%s\n", 503 LDAP_CACHE_DOOR, 504 strerror(errno)); 505 exit(1); 506 } 507 (void) close(newfd); 508 } 509 510 if (fattach(did, LDAP_CACHE_DOOR) < 0) { 511 if ((errno != EBUSY) || 512 (fdetach(LDAP_CACHE_DOOR) < 0) || 513 (fattach(did, LDAP_CACHE_DOOR) < 0)) { 514 logit("fattach() call failed\n"); 515 syslog(LOG_ERR, gettext( 516 "ldap_cachemgr: fattach() call failed")); 517 perror("fattach"); 518 exit(2); 519 } 520 } 521 522 /* catch SIGHUP revalid signals */ 523 sighupaction.sa_handler = getldap_revalidate; 524 sighupaction.sa_flags = 0; 525 (void) sigemptyset(&sighupaction.sa_mask); 526 (void) sigemptyset(&myset); 527 (void) sigaddset(&myset, SIGHUP); 528 529 if (sigaction(SIGHUP, &sighupaction, NULL) < 0) { 530 logit("sigaction() call failed\n"); 531 syslog(LOG_ERR, 532 gettext("ldap_cachemgr: sigaction() call failed")); 533 perror("sigaction"); 534 exit(1); 535 } 536 537 if (thr_sigsetmask(SIG_BLOCK, &myset, NULL) < 0) { 538 logit("thr_sigsetmask() call failed\n"); 539 syslog(LOG_ERR, 540 gettext("ldap_cachemgr: thr_sigsetmask() call failed")); 541 perror("thr_sigsetmask"); 542 exit(1); 543 } 544 545 /* 546 * kick off revalidate threads only if ttl != 0 547 */ 548 549 if (thr_create(NULL, NULL, (void *(*)(void*))getldap_refresh, 550 0, 0, NULL) != 0) { 551 logit("thr_create() call failed\n"); 552 syslog(LOG_ERR, 553 gettext("ldap_cachemgr: thr_create() call failed")); 554 perror("thr_create"); 555 exit(1); 556 } 557 558 /* 559 * kick off the thread which refreshes the server info 560 */ 561 562 if (thr_create(NULL, NULL, (void *(*)(void*))getldap_serverInfo_refresh, 563 0, 0, NULL) != 0) { 564 logit("thr_create() call failed\n"); 565 syslog(LOG_ERR, 566 gettext("ldap_cachemgr: thr_create() call failed")); 567 perror("thr_create"); 568 exit(1); 569 } 570 571 #ifdef SLP 572 if (use_slp) { 573 /* kick off SLP discovery thread */ 574 if (thr_create(NULL, NULL, (void *(*)(void *))discover, 575 (void *)&refresh, 0, NULL) != 0) { 576 logit("thr_create() call failed\n"); 577 syslog(LOG_ERR, gettext("ldap_cachemgr: thr_create() " 578 "call failed")); 579 perror("thr_create"); 580 exit(1); 581 } 582 } 583 #endif /* SLP */ 584 585 if (thr_sigsetmask(SIG_UNBLOCK, &myset, NULL) < 0) { 586 logit("thr_sigsetmask() call failed\n"); 587 syslog(LOG_ERR, 588 gettext("ldap_cachemgr: the_sigsetmask() call failed")); 589 perror("thr_sigsetmask"); 590 exit(1); 591 } 592 593 /*CONSTCOND*/ 594 while (1) { 595 (void) pause(); 596 } 597 /* NOTREACHED */ 598 /*LINTED E_FUNC_HAS_NO_RETURN_STMT*/ 599 } 600 601 602 /*ARGSUSED*/ 603 static void 604 switcher(void *cookie, char *argp, size_t arg_size, 605 door_desc_t *dp, uint_t n_desc) 606 { 607 dataunion u; 608 ldap_call_t *ptr = (ldap_call_t *)argp; 609 door_cred_t dc; 610 611 if (argp == DOOR_UNREF_DATA) { 612 logit("Door Slam... invalid door param\n"); 613 syslog(LOG_ERR, gettext("ldap_cachemgr: Door Slam... " 614 "invalid door param")); 615 (void) printf(gettext("Door Slam... invalid door param\n")); 616 exit(0); 617 } 618 619 if (ptr == NULL) { /* empty door call */ 620 (void) door_return(NULL, 0, 0, 0); /* return the favor */ 621 } 622 623 switch (ptr->ldap_callnumber) { 624 case NULLCALL: 625 u.data.ldap_ret.ldap_return_code = SUCCESS; 626 u.data.ldap_ret.ldap_bufferbytesused = sizeof (ldap_return_t); 627 break; 628 case GETLDAPCONFIG: 629 getldap_lookup(&u.data.ldap_ret, ptr); 630 current_admin.ldap_stat.ldap_numbercalls++; 631 break; 632 case GETADMIN: 633 (void) getadmin(&u.data.ldap_ret); 634 break; 635 case SETADMIN: 636 case KILLSERVER: 637 if (door_cred(&dc) < 0) { 638 logit("door_cred() call failed\n"); 639 syslog(LOG_ERR, gettext("ldap_cachemgr: door_cred() " 640 "call failed")); 641 perror("door_cred"); 642 break; 643 } 644 if (dc.dc_euid != 0 && ptr->ldap_callnumber == SETADMIN) { 645 logit("SETADMIN call failed (cred): caller " 646 "pid %ld, uid %ld, euid %ld\n", 647 dc.dc_pid, dc.dc_ruid, dc.dc_euid); 648 u.data.ldap_ret.ldap_return_code = NOTFOUND; 649 break; 650 } 651 if (ptr->ldap_callnumber == KILLSERVER) { 652 logit("ldap_cachemgr received KILLSERVER cmd from " 653 "pid %ld, uid %ld, euid %ld\n", 654 dc.dc_pid, dc.dc_ruid, dc.dc_euid); 655 exit(0); 656 } else { 657 (void) setadmin(&u.data.ldap_ret, ptr); 658 } 659 break; 660 case GETLDAPSERVER: 661 getldap_getserver(&u.data.ldap_ret, ptr); 662 current_admin.ldap_stat.ldap_numbercalls++; 663 break; 664 case GETCACHE: 665 getldap_get_cacheData(&u.data.ldap_ret, ptr); 666 current_admin.ldap_stat.ldap_numbercalls++; 667 break; 668 case SETCACHE: 669 getldap_set_cacheData(&u.data.ldap_ret, ptr); 670 current_admin.ldap_stat.ldap_numbercalls++; 671 break; 672 case GETCACHESTAT: 673 getldap_get_cacheStat(&u.data.ldap_ret); 674 current_admin.ldap_stat.ldap_numbercalls++; 675 break; 676 default: 677 logit("Unknown ldap service door call op %d\n", 678 ptr->ldap_callnumber); 679 u.data.ldap_ret.ldap_return_code = -99; 680 u.data.ldap_ret.ldap_bufferbytesused = sizeof (ldap_return_t); 681 break; 682 } 683 (void) door_return((char *)&u.data, 684 u.data.ldap_ret.ldap_bufferbytesused, NULL, 0); 685 } 686 687 static void 688 usage(char *s) 689 { 690 (void) fprintf(stderr, 691 gettext("Usage: %s [-d debug_level] [-l logfilename]\n"), s); 692 (void) fprintf(stderr, gettext(" [-K] " 693 "[-r revalidate_interval] ")); 694 #ifndef SLP 695 (void) fprintf(stderr, gettext(" [-g]\n")); 696 #else 697 (void) fprintf(stderr, gettext(" [-g] [-s]\n")); 698 #endif /* SLP */ 699 exit(1); 700 } 701 702 703 static int logfd = -1; 704 705 static int 706 cachemgr_set_lf(admin_t *ptr, char *logfile) 707 { 708 int newlogfd; 709 710 /* 711 * we don't really want to try and open the log file 712 * /dev/null since that will fail w/ our security fixes 713 */ 714 715 if (logfile == NULL || *logfile == 0) { 716 /*EMPTY*/; 717 } else if (strcmp(logfile, "/dev/null") == 0) { 718 (void) strcpy(current_admin.logfile, "/dev/null"); 719 (void) close(logfd); 720 logfd = -1; 721 } else { 722 if ((newlogfd = 723 open(logfile, O_EXCL|O_WRONLY|O_CREAT, 0644)) < 0) { 724 /* 725 * File already exists... now we need to get cute 726 * since opening a file in a world-writeable directory 727 * safely is hard = it could be a hard link or a 728 * symbolic link to a system file. 729 * 730 */ 731 struct stat before; 732 733 if (lstat(logfile, &before) < 0) { 734 logit("Cannot open new logfile \"%s\": %sn", 735 logfile, strerror(errno)); 736 return (-1); 737 } 738 if (S_ISREG(before.st_mode) && /* no symbolic links */ 739 (before.st_nlink == 1) && /* no hard links */ 740 (before.st_uid == 0)) { /* owned by root */ 741 if ((newlogfd = 742 open(logfile, 743 O_APPEND|O_WRONLY, 0644)) < 0) { 744 logit("Cannot open new logfile " 745 "\"%s\": %s\n", 746 logfile, strerror(errno)); 747 return (-1); 748 } 749 } else { 750 logit("Cannot use specified logfile " 751 "\"%s\": file is/has links or isn't " 752 "owned by root\n", logfile); 753 return (-1); 754 } 755 } 756 (void) strlcpy(ptr->logfile, logfile, sizeof (ptr->logfile)); 757 (void) close(logfd); 758 logfd = newlogfd; 759 logit("Starting ldap_cachemgr, logfile %s\n", logfile); 760 } 761 return (0); 762 } 763 764 /*PRINTFLIKE1*/ 765 void 766 logit(char *format, ...) 767 { 768 static mutex_t loglock; 769 struct timeval tv; 770 char buffer[BUFSIZ]; 771 va_list ap; 772 773 va_start(ap, format); 774 775 if (logfd >= 0) { 776 int safechars; 777 778 (void) gettimeofday(&tv, NULL); 779 (void) ctime_r(&tv.tv_sec, buffer, BUFSIZ); 780 (void) snprintf(buffer+19, BUFSIZE, ".%.4ld ", 781 tv.tv_usec/100); 782 safechars = sizeof (buffer) - 30; 783 if (vsnprintf(buffer+25, safechars, format, ap) > safechars) 784 (void) strcat(buffer, "...\n"); 785 (void) mutex_lock(&loglock); 786 (void) write(logfd, buffer, strlen(buffer)); 787 (void) mutex_unlock(&loglock); 788 } 789 va_end(ap); 790 } 791 792 793 void 794 do_update(ldap_call_t *in) 795 { 796 dataunion u; 797 798 switch (in->ldap_callnumber) { 799 case GETLDAPCONFIG: 800 getldap_lookup(&u.data.ldap_ret, in); 801 break; 802 default: 803 assert(0); 804 break; 805 } 806 807 free(in); 808 } 809 810 811 static int 812 client_getadmin(admin_t *ptr) 813 { 814 dataunion u; 815 ldap_data_t *dptr; 816 int ndata; 817 int adata; 818 819 u.data.ldap_call.ldap_callnumber = GETADMIN; 820 ndata = sizeof (u); 821 adata = sizeof (u.data); 822 dptr = &u.data; 823 824 if (__ns_ldap_trydoorcall(&dptr, &ndata, &adata) != SUCCESS) { 825 return (-1); 826 } 827 (void) memcpy(ptr, dptr->ldap_ret.ldap_u.buff, sizeof (*ptr)); 828 829 return (0); 830 } 831 832 static int 833 getadmin(ldap_return_t *out) 834 { 835 out->ldap_return_code = SUCCESS; 836 out->ldap_bufferbytesused = sizeof (current_admin); 837 (void) memcpy(out->ldap_u.buff, ¤t_admin, sizeof (current_admin)); 838 839 return (0); 840 } 841 842 843 static int 844 setadmin(ldap_return_t *out, ldap_call_t *ptr) 845 { 846 admin_t *new; 847 848 out->ldap_return_code = SUCCESS; 849 out->ldap_bufferbytesused = sizeof (ldap_return_t); 850 new = (admin_t *)ptr->ldap_u.domainname; 851 852 /* 853 * global admin stuff 854 */ 855 856 if ((cachemgr_set_lf(¤t_admin, new->logfile) < 0) || 857 cachemgr_set_dl(¤t_admin, new->debug_level) < 0) { 858 out->ldap_return_code = NOTFOUND; 859 return (-1); 860 } 861 862 if (cachemgr_set_ttl(¤t_admin.ldap_stat, 863 "ldap", 864 new->ldap_stat.ldap_ttl) < 0) { 865 out->ldap_return_code = NOTFOUND; 866 return (-1); 867 } 868 out->ldap_return_code = SUCCESS; 869 870 return (0); 871 } 872 873 874 static void 875 client_killserver() 876 { 877 dataunion u; 878 ldap_data_t *dptr; 879 int ndata; 880 int adata; 881 882 u.data.ldap_call.ldap_callnumber = KILLSERVER; 883 ndata = sizeof (u); 884 adata = sizeof (ldap_call_t); 885 dptr = &u.data; 886 887 __ns_ldap_trydoorcall(&dptr, &ndata, &adata); 888 } 889 890 891 static int 892 client_setadmin(admin_t *ptr) 893 { 894 dataunion u; 895 ldap_data_t *dptr; 896 int ndata; 897 int adata; 898 899 u.data.ldap_call.ldap_callnumber = SETADMIN; 900 (void) memcpy(u.data.ldap_call.ldap_u.domainname, ptr, sizeof (*ptr)); 901 ndata = sizeof (u); 902 adata = sizeof (*ptr); 903 dptr = &u.data; 904 905 if (__ns_ldap_trydoorcall(&dptr, &ndata, &adata) != SUCCESS) { 906 return (-1); 907 } 908 909 return (0); 910 } 911 912 static int 913 client_showstats(admin_t *ptr) 914 { 915 dataunion u; 916 ldap_data_t *dptr; 917 int ndata; 918 int adata; 919 char *rbuf, *sptr, *rest; 920 921 /* 922 * print admin data 923 */ 924 (void) printf(gettext("\ncachemgr configuration:\n")); 925 (void) printf(gettext("server debug level %10d\n"), ptr->debug_level); 926 (void) printf(gettext("server log file\t\"%s\"\n"), ptr->logfile); 927 (void) printf(gettext("number of calls to ldapcachemgr %10d\n"), 928 ptr->ldap_stat.ldap_numbercalls); 929 930 /* 931 * get cache data statistics 932 */ 933 u.data.ldap_call.ldap_callnumber = GETCACHESTAT; 934 ndata = sizeof (u); 935 adata = sizeof (ldap_call_t); 936 dptr = &u.data; 937 938 if (__ns_ldap_trydoorcall(&dptr, &ndata, &adata) != SUCCESS) { 939 (void) printf( 940 gettext("\nCache data statistics not available!\n")); 941 return (0); 942 } 943 944 /* 945 * print cache data statistics line by line 946 */ 947 (void) printf(gettext("\ncachemgr cache data statistics:\n")); 948 rbuf = dptr->ldap_ret.ldap_u.buff; 949 sptr = strtok_r(rbuf, DOORLINESEP, &rest); 950 for (;;) { 951 (void) printf("%s\n", sptr); 952 sptr = strtok_r(NULL, DOORLINESEP, &rest); 953 if (sptr == NULL) 954 break; 955 } 956 return (0); 957 } 958 959 960 /* 961 * detach from tty 962 */ 963 static void 964 detachfromtty(char *pgm) 965 { 966 int status; 967 pid_t pid, wret; 968 969 (void) close(0); 970 (void) close(1); 971 /* 972 * Block the SIGUSR1 signal 973 * just in case that the child 974 * process may run faster than 975 * the parent process and 976 * send this signal before 977 * the signal handler is ready 978 * in the parent process. 979 * This error will cause the parent 980 * to exit with the User Signal 1 981 * exit code (144). 982 */ 983 (void) sighold(SIGUSR1); 984 pid = fork1(); 985 switch (pid) { 986 case (pid_t)-1: 987 logit("detachfromtty(): fork1() call failed\n"); 988 (void) fprintf(stderr, 989 gettext("%s: fork1() call failed.\n"), 990 pgm); 991 syslog(LOG_ERR, 992 gettext("ldap_cachemgr: fork1() call failed.")); 993 exit(1); 994 break; 995 case 0: 996 /* 997 * child process does not 998 * need to worry about 999 * the SIGUSR1 signal 1000 */ 1001 (void) sigrelse(SIGUSR1); 1002 (void) close(2); 1003 break; 1004 default: 1005 /* 1006 * Wait forever until the child process 1007 * has exited, or has signalled that at 1008 * least one server in the server list 1009 * is up. 1010 */ 1011 if (signal(SIGUSR1, sig_ok_to_exit) == SIG_ERR) { 1012 logit("detachfromtty(): " 1013 "can't set up signal handler to " 1014 " catch SIGUSR1.\n"); 1015 (void) fprintf(stderr, 1016 gettext("%s: signal() call failed.\n"), 1017 pgm); 1018 syslog(LOG_ERR, gettext("ldap_cachemgr: " 1019 "can't set up signal handler to " 1020 " catch SIGUSR1.")); 1021 exit(1); 1022 } 1023 1024 /* 1025 * now unblock the SIGUSR1 signal 1026 * to handle the pending or 1027 * soon to arrive SIGUSR1 signal 1028 */ 1029 (void) sigrelse(SIGUSR1); 1030 wret = waitpid(pid, &status, 0); 1031 1032 if (wret == -1) { 1033 logit("detachfromtty(): " 1034 "waitpid() call failed\n"); 1035 (void) fprintf(stderr, 1036 gettext("%s: waitpid() call failed.\n"), 1037 pgm); 1038 syslog(LOG_ERR, 1039 gettext("ldap_cachemgr: waitpid() " 1040 "call failed.")); 1041 exit(1); 1042 } 1043 if (wret != pid) { 1044 logit("detachfromtty(): " 1045 "waitpid() returned %ld when " 1046 "child pid was %ld\n", 1047 wret, pid); 1048 (void) fprintf(stderr, 1049 gettext( 1050 "%s: waitpid() returned %ld when " 1051 "child pid was %ld.\n"), 1052 pgm, wret, pid); 1053 syslog(LOG_ERR, 1054 gettext("ldap_cachemgr: waitpid() " 1055 "returned different " 1056 "child pid.")); 1057 exit(1); 1058 } 1059 1060 /* evaluate return status */ 1061 if (WIFEXITED(status)) { 1062 if (WEXITSTATUS(status) == 0) { 1063 exit(0); 1064 } 1065 logit("detachfromtty(): " 1066 "child failed (rc = %d).\n", 1067 WEXITSTATUS(status)); 1068 (void) fprintf(stderr, 1069 gettext("%s: failed. Please see " 1070 "syslog for details.\n"), 1071 pgm); 1072 syslog(LOG_ERR, 1073 gettext("ldap_cachemgr: failed " 1074 "(rc = %d)."), 1075 WEXITSTATUS(status)); 1076 } else if (WIFSIGNALED(status)) { 1077 logit("detachfromtty(): " 1078 "child terminated by signal %d.\n", 1079 WTERMSIG(status)); 1080 (void) fprintf(stderr, 1081 gettext("%s: terminated by signal %d.\n"), 1082 pgm, WTERMSIG(status)); 1083 syslog(LOG_ERR, 1084 gettext("ldap_cachemgr: terminated by " 1085 "signal %d.\n"), 1086 WTERMSIG(status)); 1087 } else if (WCOREDUMP(status)) { 1088 logit("detachfromtty(): child core dumped.\n"), 1089 (void) fprintf(stderr, 1090 gettext("%s: core dumped.\n"), 1091 pgm); 1092 syslog(LOG_ERR, 1093 gettext("ldap_cachemgr: " 1094 "core dumped.\n")); 1095 } 1096 1097 exit(1); 1098 } 1099 (void) setsid(); 1100 if (open("/dev/null", O_RDWR, 0) != -1) { 1101 (void) dup(0); 1102 (void) dup(0); 1103 } 1104 } 1105