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