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 2008 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 <strings.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 56 #include <alloca.h> 57 #include <ucontext.h> 58 59 #include "getxby_door.h" 60 #include "cachemgr.h" 61 62 static void detachfromtty(); 63 admin_t current_admin; 64 static int will_become_server; 65 66 static void switcher(void *cookie, char *argp, size_t arg_size, 67 door_desc_t *dp, uint_t n_desc); 68 static void usage(char *s); 69 static int cachemgr_set_lf(admin_t *ptr, char *logfile); 70 static int client_getadmin(admin_t *ptr); 71 static int setadmin(ldap_call_t *ptr); 72 static int client_setadmin(admin_t *ptr); 73 static int client_showstats(admin_t *ptr); 74 static int is_root(int free_uc, char *dc_str, ucred_t **uc); 75 76 #ifdef SLP 77 int use_slp = 0; 78 static unsigned int refresh = 10800; /* dynamic discovery interval */ 79 #endif /* SLP */ 80 81 static ldap_stat_t * 82 getcacheptr(char *s) 83 { 84 static const char *caches[1] = {"ldap"}; 85 86 if (strncmp(caches[0], s, strlen(caches[0])) == 0) 87 return (¤t_admin.ldap_stat); 88 89 return (NULL); 90 } 91 92 char * 93 getcacheopt(char *s) 94 { 95 while (*s && *s != ',') 96 s++; 97 return ((*s == ',') ? (s + 1) : NULL); 98 } 99 100 /* 101 * This is here to prevent the ldap_cachemgr becomes 102 * daemonlized to early to soon during boot time. 103 * This causes problems during boot when automounter 104 * and others try to use libsldap before ldap_cachemgr 105 * finishes walking the server list. 106 */ 107 static void 108 sig_ok_to_exit(int signo) 109 { 110 if (signo == SIGUSR1) { 111 logit("sig_ok_to_exit(): parent exiting...\n"); 112 exit(0); 113 } else { 114 logit("sig_ok_to_exit(): invalid signal(%d) received.\n", 115 signo); 116 syslog(LOG_ERR, gettext("ldap_cachemgr: " 117 "invalid signal(%d) received."), signo); 118 exit(1); 119 } 120 } 121 #define LDAP_TABLES 1 /* ldap */ 122 #define TABLE_THREADS 10 123 #define COMMON_THREADS 20 124 #define CACHE_MISS_THREADS (COMMON_THREADS + LDAP_TABLES * TABLE_THREADS) 125 #define CACHE_HIT_THREADS 20 126 /* 127 * There is only one thread handling GETSTATUSCHANGE START from main nscd 128 * most of time. But it could happen that a main nscd is restarted, old main 129 * nscd's handling thread is still alive when new main nscd starts and sends 130 * START, or old main dies. STOP is not sent in both cases. 131 * The main nscd requires 2 threads to handle START and STOP. So max number 132 * of change threads is set to 4. 133 */ 134 #define MAX_CHG_THREADS 4 135 #define MAX_SERVER_THREADS (CACHE_HIT_THREADS + CACHE_MISS_THREADS + \ 136 MAX_CHG_THREADS) 137 138 static sema_t common_sema; 139 static sema_t ldap_sema; 140 static thread_key_t lookup_state_key; 141 static int chg_threads_num = 0; 142 static mutex_t chg_threads_num_lock = DEFAULTMUTEX; 143 144 static void 145 initialize_lookup_clearance() 146 { 147 (void) thr_keycreate(&lookup_state_key, NULL); 148 (void) sema_init(&common_sema, COMMON_THREADS, USYNC_THREAD, 0); 149 (void) sema_init(&ldap_sema, TABLE_THREADS, USYNC_THREAD, 0); 150 } 151 152 int 153 get_clearance(int callnumber) 154 { 155 sema_t *table_sema = NULL; 156 char *tab; 157 158 if (sema_trywait(&common_sema) == 0) { 159 (void) thr_setspecific(lookup_state_key, NULL); 160 return (0); 161 } 162 163 switch (callnumber) { 164 case GETLDAPCONFIG: 165 tab = "ldap"; 166 table_sema = &ldap_sema; 167 break; 168 default: 169 logit("Internal Error: get_clearance\n"); 170 break; 171 } 172 173 if (sema_trywait(table_sema) == 0) { 174 (void) thr_setspecific(lookup_state_key, (void*)1); 175 return (0); 176 } 177 178 if (current_admin.debug_level >= DBG_CANT_FIND) { 179 logit("get_clearance: throttling load for %s table\n", tab); 180 } 181 182 return (-1); 183 } 184 185 int 186 release_clearance(int callnumber) 187 { 188 int which; 189 sema_t *table_sema = NULL; 190 191 (void) thr_getspecific(lookup_state_key, (void**)&which); 192 if (which == 0) /* from common pool */ { 193 (void) sema_post(&common_sema); 194 return (0); 195 } 196 197 switch (callnumber) { 198 case GETLDAPCONFIG: 199 table_sema = &ldap_sema; 200 break; 201 default: 202 logit("Internal Error: release_clearance\n"); 203 break; 204 } 205 (void) sema_post(table_sema); 206 207 return (0); 208 } 209 210 211 static mutex_t create_lock; 212 static int num_servers = 0; 213 static thread_key_t server_key; 214 215 216 /* 217 * Bind a TSD value to a server thread. This enables the destructor to 218 * be called if/when this thread exits. This would be a programming error, 219 * but better safe than sorry. 220 */ 221 222 /*ARGSUSED*/ 223 static void * 224 server_tsd_bind(void *arg) 225 { 226 static void *value = 0; 227 228 /* 229 * disable cancellation to prevent hangs when server 230 * threads disappear 231 */ 232 233 (void) thr_setspecific(server_key, value); 234 (void) door_return(NULL, 0, NULL, 0); 235 236 return (value); 237 } 238 239 /* 240 * Server threads are created here. 241 */ 242 243 /*ARGSUSED*/ 244 static void 245 server_create(door_info_t *dip) 246 { 247 (void) mutex_lock(&create_lock); 248 if (++num_servers > MAX_SERVER_THREADS) { 249 num_servers--; 250 (void) mutex_unlock(&create_lock); 251 return; 252 } 253 (void) mutex_unlock(&create_lock); 254 (void) thr_create(NULL, 0, server_tsd_bind, NULL, 255 THR_BOUND|THR_DETACHED, NULL); 256 } 257 258 /* 259 * Server thread are destroyed here 260 */ 261 262 /*ARGSUSED*/ 263 static void 264 server_destroy(void *arg) 265 { 266 (void) mutex_lock(&create_lock); 267 num_servers--; 268 (void) mutex_unlock(&create_lock); 269 } 270 271 int 272 main(int argc, char ** argv) 273 { 274 int did; 275 int opt; 276 int errflg = 0; 277 int showstats = 0; 278 int doset = 0; 279 int dofg = 0; 280 struct stat buf; 281 sigset_t myset; 282 struct sigaction sighupaction; 283 static void client_killserver(); 284 int debug_level = 0; 285 286 /* setup for localization */ 287 (void) setlocale(LC_ALL, ""); 288 (void) textdomain(TEXT_DOMAIN); 289 290 openlog("ldap_cachemgr", LOG_PID, LOG_DAEMON); 291 292 if (chdir(NSLDAPDIRECTORY) < 0) { 293 (void) fprintf(stderr, gettext("chdir(\"%s\") failed: %s\n"), 294 NSLDAPDIRECTORY, strerror(errno)); 295 exit(1); 296 } 297 298 /* 299 * Correctly set file mode creation mask, so to make the new files 300 * created for door calls being readable by all. 301 */ 302 (void) umask(0); 303 304 /* 305 * Special case non-root user here - he/she/they/it can just print 306 * stats 307 */ 308 309 if (geteuid()) { 310 if (argc != 2 || strcmp(argv[1], "-g")) { 311 (void) fprintf(stderr, 312 gettext("Must be root to use any option " 313 "other than -g.\n\n")); 314 usage(argv[0]); 315 } 316 317 if ((__ns_ldap_cache_ping() != NS_CACHE_SUCCESS) || 318 (client_getadmin(¤t_admin) != 0)) { 319 (void) fprintf(stderr, 320 gettext("%s doesn't appear to be running.\n"), 321 argv[0]); 322 exit(1); 323 } 324 (void) client_showstats(¤t_admin); 325 exit(0); 326 } 327 328 329 330 /* 331 * Determine if there is already a daemon running 332 */ 333 334 will_become_server = (__ns_ldap_cache_ping() != NS_CACHE_SUCCESS); 335 336 /* 337 * load normal config file 338 */ 339 340 if (will_become_server) { 341 static const ldap_stat_t defaults = { 342 0, /* stat */ 343 DEFAULTTTL}; /* ttl */ 344 345 current_admin.ldap_stat = defaults; 346 (void) strcpy(current_admin.logfile, LOGFILE); 347 } else { 348 if (client_getadmin(¤t_admin)) { 349 (void) fprintf(stderr, gettext("Cannot contact %s " 350 "properly(?)\n"), argv[0]); 351 exit(1); 352 } 353 } 354 355 #ifndef SLP 356 while ((opt = getopt(argc, argv, "fKgl:r:d:")) != EOF) { 357 #else 358 while ((opt = getopt(argc, argv, "fKgs:l:r:d:")) != EOF) { 359 #endif /* SLP */ 360 ldap_stat_t *cache; 361 362 switch (opt) { 363 case 'K': 364 client_killserver(); 365 exit(0); 366 break; 367 case 'g': 368 showstats++; 369 break; 370 case 'f': 371 dofg++; 372 break; 373 case 'r': 374 doset++; 375 cache = getcacheptr("ldap"); 376 if (!optarg) { 377 errflg++; 378 break; 379 } 380 cache->ldap_ttl = atoi(optarg); 381 break; 382 case 'l': 383 doset++; 384 (void) strlcpy(current_admin.logfile, 385 optarg, sizeof (current_admin.logfile)); 386 break; 387 case 'd': 388 doset++; 389 debug_level = atoi(optarg); 390 break; 391 #ifdef SLP 392 case 's': /* undocumented: use dynamic (SLP) config */ 393 use_slp = 1; 394 break; 395 #endif /* SLP */ 396 default: 397 errflg++; 398 break; 399 } 400 } 401 402 if (errflg) 403 usage(argv[0]); 404 405 /* 406 * will not show statistics if no daemon running 407 */ 408 if (will_become_server && showstats) { 409 (void) fprintf(stderr, 410 gettext("%s doesn't appear to be running.\n"), 411 argv[0]); 412 exit(1); 413 } 414 415 if (!will_become_server) { 416 if (showstats) { 417 (void) client_showstats(¤t_admin); 418 } 419 if (doset) { 420 current_admin.debug_level = debug_level; 421 if (client_setadmin(¤t_admin) < 0) { 422 (void) fprintf(stderr, 423 gettext("Error during admin call\n")); 424 exit(1); 425 } 426 } 427 if (!showstats && !doset) { 428 (void) fprintf(stderr, 429 gettext("%s already running....use '%s " 430 "-K' to stop\n"), argv[0], argv[0]); 431 } 432 exit(0); 433 } 434 435 /* 436 * daemon from here on 437 */ 438 439 if (debug_level) { 440 /* 441 * we're debugging... 442 */ 443 if (strlen(current_admin.logfile) == 0) 444 /* 445 * no specified log file 446 */ 447 (void) strcpy(current_admin.logfile, LOGFILE); 448 else 449 (void) cachemgr_set_lf(¤t_admin, 450 current_admin.logfile); 451 /* 452 * validate the range of debug level number 453 * and set the number to current_admin.debug_level 454 */ 455 if (cachemgr_set_dl(¤t_admin, debug_level) < 0) { 456 /* 457 * print error messages to the screen 458 * cachemgr_set_dl prints msgs to cachemgr.log 459 * only 460 */ 461 (void) fprintf(stderr, 462 gettext("Incorrect Debug Level: %d\n" 463 "It should be between %d and %d\n"), 464 debug_level, DBG_OFF, MAXDEBUG); 465 exit(-1); 466 } 467 } else { 468 if (strlen(current_admin.logfile) == 0) 469 (void) strcpy(current_admin.logfile, "/dev/null"); 470 (void) cachemgr_set_lf(¤t_admin, 471 current_admin.logfile); 472 } 473 474 if (dofg == 0) 475 detachfromtty(argv[0]); 476 477 /* 478 * perform some initialization 479 */ 480 481 initialize_lookup_clearance(); 482 483 if (getldap_init() != 0) 484 exit(-1); 485 486 /* 487 * Establish our own server thread pool 488 */ 489 490 (void) door_server_create(server_create); 491 if (thr_keycreate(&server_key, server_destroy) != 0) { 492 logit("thr_keycreate() call failed\n"); 493 syslog(LOG_ERR, 494 gettext("ldap_cachemgr: thr_keycreate() call failed")); 495 perror("thr_keycreate"); 496 exit(-1); 497 } 498 499 /* 500 * Create a door 501 */ 502 503 if ((did = door_create(switcher, LDAP_CACHE_DOOR_COOKIE, 504 DOOR_UNREF | DOOR_REFUSE_DESC | DOOR_NO_CANCEL)) < 0) { 505 logit("door_create() call failed\n"); 506 syslog(LOG_ERR, gettext( 507 "ldap_cachemgr: door_create() call failed")); 508 perror("door_create"); 509 exit(-1); 510 } 511 512 /* 513 * bind to file system 514 */ 515 516 if (stat(LDAP_CACHE_DOOR, &buf) < 0) { 517 int newfd; 518 519 if ((newfd = creat(LDAP_CACHE_DOOR, 0444)) < 0) { 520 logit("Cannot create %s:%s\n", 521 LDAP_CACHE_DOOR, 522 strerror(errno)); 523 exit(1); 524 } 525 (void) close(newfd); 526 } 527 528 if (fattach(did, LDAP_CACHE_DOOR) < 0) { 529 if ((errno != EBUSY) || 530 (fdetach(LDAP_CACHE_DOOR) < 0) || 531 (fattach(did, LDAP_CACHE_DOOR) < 0)) { 532 logit("fattach() call failed\n"); 533 syslog(LOG_ERR, gettext( 534 "ldap_cachemgr: fattach() call failed")); 535 perror("fattach"); 536 exit(2); 537 } 538 } 539 540 /* catch SIGHUP revalid signals */ 541 sighupaction.sa_handler = getldap_revalidate; 542 sighupaction.sa_flags = 0; 543 (void) sigemptyset(&sighupaction.sa_mask); 544 (void) sigemptyset(&myset); 545 (void) sigaddset(&myset, SIGHUP); 546 547 if (sigaction(SIGHUP, &sighupaction, NULL) < 0) { 548 logit("sigaction() call failed\n"); 549 syslog(LOG_ERR, 550 gettext("ldap_cachemgr: sigaction() call failed")); 551 perror("sigaction"); 552 exit(1); 553 } 554 555 if (thr_sigsetmask(SIG_BLOCK, &myset, NULL) < 0) { 556 logit("thr_sigsetmask() call failed\n"); 557 syslog(LOG_ERR, 558 gettext("ldap_cachemgr: thr_sigsetmask() call failed")); 559 perror("thr_sigsetmask"); 560 exit(1); 561 } 562 563 /* 564 * kick off revalidate threads only if ttl != 0 565 */ 566 567 if (thr_create(NULL, 0, (void *(*)(void*))getldap_refresh, 568 NULL, 0, NULL) != 0) { 569 logit("thr_create() call failed\n"); 570 syslog(LOG_ERR, 571 gettext("ldap_cachemgr: thr_create() call failed")); 572 perror("thr_create"); 573 exit(1); 574 } 575 576 /* 577 * kick off the thread which refreshes the server info 578 */ 579 580 if (thr_create(NULL, 0, (void *(*)(void*))getldap_serverInfo_refresh, 581 NULL, 0, NULL) != 0) { 582 logit("thr_create() call failed\n"); 583 syslog(LOG_ERR, 584 gettext("ldap_cachemgr: thr_create() call failed")); 585 perror("thr_create"); 586 exit(1); 587 } 588 589 /* 590 * kick off the thread which cleans up waiting threads for 591 * GETSTATUSCHANGE 592 */ 593 594 if (thr_create(NULL, 0, chg_cleanup_waiting_threads, 595 NULL, 0, NULL) != 0) { 596 logit("thr_create() chg_cleanup_waiting_threads call failed\n"); 597 syslog(LOG_ERR, 598 gettext("ldap_cachemgr: thr_create() " 599 "chg_cleanup_waiting_threads call failed")); 600 exit(1); 601 } 602 603 #ifdef SLP 604 if (use_slp) { 605 /* kick off SLP discovery thread */ 606 if (thr_create(NULL, 0, (void *(*)(void *))discover, 607 (void *)&refresh, 0, NULL) != 0) { 608 logit("thr_create() call failed\n"); 609 syslog(LOG_ERR, gettext("ldap_cachemgr: thr_create() " 610 "call failed")); 611 perror("thr_create"); 612 exit(1); 613 } 614 } 615 #endif /* SLP */ 616 617 if (thr_sigsetmask(SIG_UNBLOCK, &myset, NULL) < 0) { 618 logit("thr_sigsetmask() call failed\n"); 619 syslog(LOG_ERR, 620 gettext("ldap_cachemgr: the_sigsetmask() call failed")); 621 perror("thr_sigsetmask"); 622 exit(1); 623 } 624 625 /*CONSTCOND*/ 626 while (1) { 627 (void) pause(); 628 } 629 /* NOTREACHED */ 630 /*LINTED E_FUNC_HAS_NO_RETURN_STMT*/ 631 } 632 633 634 /* 635 * Before calling the alloca() function we have to be sure that we won't get 636 * beyond the stack. Since we don't know the precise layout of the stack, 637 * the address of an automatic of the function gives us a rough idea, plus/minus 638 * a bit. We also need a bit more of stackspace after the call to be able 639 * to call further functions. Even something as simple as making a system call 640 * from within this function can take ~100 Bytes of stackspace. 641 */ 642 #define SAFETY_BUFFER 32 * 1024 /* 32KB */ 643 644 static 645 size_t 646 get_data_size(LineBuf *config_info, int *err_code) 647 { 648 size_t configSize = sizeof (ldap_return_t); 649 dataunion *buf = NULL; /* For the 'sizeof' purpose */ 650 651 if (config_info->str != NULL && 652 config_info->len >= sizeof (buf->data.ldap_ret.ldap_u.config)) { 653 configSize = sizeof (buf->space) + 654 config_info->len - 655 sizeof (buf->data.ldap_ret.ldap_u.config); 656 657 if (!stack_inbounds((char *)&buf - 658 (configSize + SAFETY_BUFFER))) { 659 /* 660 * We do not have enough space on the stack 661 * to accomodate the whole DUAProfile 662 */ 663 logit("The DUAProfile is too big. There is not enough " 664 "space to process it. Ignoring it.\n"); 665 syslog(LOG_ERR, gettext("ldap_cachemgr: The DUAProfile " 666 "is too big. There is not enough space " 667 "to process it. Ignoring it.")); 668 669 *err_code = NS_CACHE_SERVERERROR; 670 671 free(config_info->str); 672 config_info->str = NULL; 673 config_info->len = 0; 674 configSize = sizeof (ldap_return_t); 675 } 676 } 677 678 return (configSize); 679 } 680 681 /*ARGSUSED*/ 682 static void 683 switcher(void *cookie, char *argp, size_t arg_size, 684 door_desc_t *dp, uint_t n_desc) 685 { 686 #define GETSIZE 1000 687 #define ALLOCATE 1001 688 689 ldap_call_t *ptr = (ldap_call_t *)argp; 690 ucred_t *uc = NULL; 691 692 LineBuf configInfo; 693 dataunion *buf = NULL; 694 695 /* 696 * By default the size of a buffer to be passed down to a client 697 * is equal to the size of the ldap_return_t structure. We need 698 * a bigger buffer in a few cases. 699 */ 700 size_t configSize = sizeof (ldap_return_t); 701 int ldapErrno = 0, state, callnumber; 702 struct { 703 void *begin; 704 size_t size; 705 uint8_t destroy; 706 } dataSource; 707 708 if (argp == DOOR_UNREF_DATA) { 709 logit("Door Slam... invalid door param\n"); 710 syslog(LOG_ERR, gettext("ldap_cachemgr: Door Slam... " 711 "invalid door param")); 712 (void) printf(gettext("Door Slam... invalid door param\n")); 713 exit(0); 714 } 715 716 if (ptr == NULL) { /* empty door call */ 717 (void) door_return(NULL, 0, 0, 0); /* return the favor */ 718 } 719 720 bzero(&dataSource, sizeof (dataSource)); 721 722 /* 723 * We presume that sizeof (ldap_return_t) bytes are always available 724 * on the stack 725 */ 726 callnumber = ptr->ldap_callnumber; 727 728 switch (callnumber) { 729 case NULLCALL: 730 /* 731 * Just a 'ping'. Use the default size 732 * of the buffer and set the 733 * 'OK' error code. 734 */ 735 state = ALLOCATE; 736 break; 737 case GETLDAPCONFIG: 738 /* 739 * Get the current LDAP configuration. 740 * Since this is dynamic data and its size can exceed 741 * the size of ldap_return_t, the next step will 742 * calculate who much space exactly is required. 743 */ 744 getldap_lookup(&configInfo, ptr); 745 746 state = GETSIZE; 747 break; 748 case GETLDAPSERVER: 749 /* 750 * Get the root DSE for a next server in the list. 751 * Since this is dynamic data and its size can exceed 752 * the size of ldap_return_t, the next step will 753 * calculate who much space exactly is required. 754 */ 755 getldap_getserver(&configInfo, ptr); 756 757 state = GETSIZE; 758 break; 759 case GETCACHESTAT: 760 /* 761 * Get the cache stattistics. 762 * Since this is dynamic data and its size can exceed 763 * the size of ldap_return_t, the next step will 764 * calculate how much space exactly is required. 765 */ 766 getldap_get_cacheStat(&configInfo); 767 768 state = GETSIZE; 769 break; 770 case GETADMIN: 771 /* 772 * Get current configuration and statistics. 773 * The size of the statistics structure is less then 774 * sizeof (ldap_return_t). So specify the source 775 * where to take the info and proceed with the memory 776 * allocation. 777 */ 778 state = ALLOCATE; 779 780 if (ldapErrno == 0) { 781 dataSource.begin = ¤t_admin; 782 dataSource.size = sizeof (current_admin); 783 dataSource.destroy = 0; 784 } 785 break; 786 case KILLSERVER: 787 /* 788 * Process the request and proceed with the default 789 * buffer allocation. 790 */ 791 if (is_root(1, "KILLSERVER", &uc)) 792 exit(0); 793 794 ldapErrno = -1; 795 state = ALLOCATE; 796 break; 797 case SETADMIN: 798 /* 799 * Process the request and proceed with the default 800 * buffer allocation. 801 */ 802 if (is_root(1, "SETADMIN", &uc)) 803 ldapErrno = setadmin(ptr); 804 else 805 ldapErrno = -1; 806 807 state = ALLOCATE; 808 break; 809 case GETCACHE: 810 /* 811 * Get the cache stattistics. 812 * Since this is dynamic data and its size can exceed 813 * the size of ldap_return_t, the next step will 814 * calculate how much space exactly is required. 815 */ 816 getldap_get_cacheData(&configInfo, ptr); 817 818 state = GETSIZE; 819 break; 820 case SETCACHE: 821 /* 822 * Process the request and proceed with the default 823 * buffer allocation. 824 */ 825 if (is_root(0, "SETCACHE", &uc) && 826 is_called_from_nscd(ucred_getpid(uc))) { 827 ldapErrno = getldap_set_cacheData(ptr); 828 current_admin.ldap_stat.ldap_numbercalls++; 829 } else 830 ldapErrno = -1; 831 832 if (uc != NULL) 833 ucred_free(uc); 834 state = ALLOCATE; 835 break; 836 case GETSTATUSCHANGE: 837 /* 838 * Process the request and proceed with the default 839 * buffer allocation. 840 */ 841 (void) mutex_lock(&chg_threads_num_lock); 842 chg_threads_num++; 843 if (chg_threads_num > MAX_CHG_THREADS) { 844 chg_threads_num--; 845 (void) mutex_unlock(&chg_threads_num_lock); 846 ldapErrno = CHG_EXCEED_MAX_THREADS; 847 state = ALLOCATE; 848 break; 849 } 850 (void) mutex_unlock(&chg_threads_num_lock); 851 852 if (is_root(0, "GETSTATUSCHANGE", &uc) && 853 is_called_from_nscd(ucred_getpid(uc))) { 854 ldapErrno = chg_get_statusChange( 855 &configInfo, ptr, ucred_getpid(uc)); 856 state = GETSIZE; 857 } else { 858 ldapErrno = -1; 859 state = ALLOCATE; 860 } 861 if (uc != NULL) 862 ucred_free(uc); 863 864 (void) mutex_lock(&chg_threads_num_lock); 865 chg_threads_num--; 866 (void) mutex_unlock(&chg_threads_num_lock); 867 break; 868 default: 869 /* 870 * This means an unknown request type. Proceed with 871 * the default buffer allocation. 872 */ 873 logit("Unknown ldap service door call op %d\n", 874 ptr->ldap_callnumber); 875 ldapErrno = -99; 876 877 state = ALLOCATE; 878 break; 879 } 880 881 switch (state) { 882 case GETSIZE: 883 /* 884 * This stage calculates how much data will be 885 * passed down to the client, checks if there is 886 * enough space on the stack to accommodate the data, 887 * increases the value of the configSize variable 888 * if necessary and specifies the data source. 889 * In case of any error occurred ldapErrno will be set 890 * appropriately. 891 */ 892 if (configInfo.str == NULL) { 893 ldapErrno = -1; 894 } 895 896 configSize = get_data_size(&configInfo, &ldapErrno); 897 898 if (ldapErrno == 0) { 899 dataSource.begin = configInfo.str; 900 dataSource.size = configInfo.len; 901 dataSource.destroy = 1; 902 } 903 904 current_admin.ldap_stat.ldap_numbercalls++; 905 /* FALLTHRU */ 906 case ALLOCATE: 907 /* 908 * Allocate a buffer of the calculated (or default) size 909 * and proceed with populating it with data. 910 */ 911 buf = (dataunion *) alloca(configSize); 912 913 /* 914 * Set a return code and, if a data source is specified, 915 * copy data from the source to the buffer. 916 */ 917 buf->data.ldap_ret.ldap_errno = ldapErrno; 918 buf->data.ldap_ret.ldap_return_code = ldapErrno; 919 buf->data.ldap_ret.ldap_bufferbytesused = configSize; 920 921 if (dataSource.begin != NULL) { 922 (void) memcpy(buf->data.ldap_ret.ldap_u.config, 923 dataSource.begin, 924 dataSource.size); 925 if (dataSource.destroy) { 926 free(dataSource.begin); 927 } 928 } 929 930 } 931 (void) door_return((char *)&buf->data, 932 buf->data.ldap_ret.ldap_bufferbytesused, 933 NULL, 934 0); 935 #undef GETSIZE 936 #undef ALLOCATE 937 } 938 939 static void 940 usage(char *s) 941 { 942 (void) fprintf(stderr, 943 gettext("Usage: %s [-d debug_level] [-l logfilename]\n"), s); 944 (void) fprintf(stderr, gettext(" [-K] " 945 "[-r revalidate_interval] ")); 946 #ifndef SLP 947 (void) fprintf(stderr, gettext(" [-g]\n")); 948 #else 949 (void) fprintf(stderr, gettext(" [-g] [-s]\n")); 950 #endif /* SLP */ 951 exit(1); 952 } 953 954 955 static int logfd = -1; 956 957 static int 958 cachemgr_set_lf(admin_t *ptr, char *logfile) 959 { 960 int newlogfd; 961 962 /* 963 * we don't really want to try and open the log file 964 * /dev/null since that will fail w/ our security fixes 965 */ 966 967 if (logfile == NULL || *logfile == 0) { 968 /*EMPTY*/; 969 } else if (strcmp(logfile, "/dev/null") == 0) { 970 (void) strcpy(current_admin.logfile, "/dev/null"); 971 (void) close(logfd); 972 logfd = -1; 973 } else { 974 if ((newlogfd = 975 open(logfile, O_EXCL|O_WRONLY|O_CREAT, 0644)) < 0) { 976 /* 977 * File already exists... now we need to get cute 978 * since opening a file in a world-writeable directory 979 * safely is hard = it could be a hard link or a 980 * symbolic link to a system file. 981 * 982 */ 983 struct stat before; 984 985 if (lstat(logfile, &before) < 0) { 986 logit("Cannot open new logfile \"%s\": %sn", 987 logfile, strerror(errno)); 988 return (-1); 989 } 990 if (S_ISREG(before.st_mode) && /* no symbolic links */ 991 (before.st_nlink == 1) && /* no hard links */ 992 (before.st_uid == 0)) { /* owned by root */ 993 if ((newlogfd = 994 open(logfile, 995 O_APPEND|O_WRONLY, 0644)) < 0) { 996 logit("Cannot open new logfile " 997 "\"%s\": %s\n", 998 logfile, strerror(errno)); 999 return (-1); 1000 } 1001 } else { 1002 logit("Cannot use specified logfile " 1003 "\"%s\": file is/has links or isn't " 1004 "owned by root\n", logfile); 1005 return (-1); 1006 } 1007 } 1008 (void) strlcpy(ptr->logfile, logfile, sizeof (ptr->logfile)); 1009 (void) close(logfd); 1010 logfd = newlogfd; 1011 logit("Starting ldap_cachemgr, logfile %s\n", logfile); 1012 } 1013 return (0); 1014 } 1015 1016 /*PRINTFLIKE1*/ 1017 void 1018 logit(char *format, ...) 1019 { 1020 static mutex_t loglock; 1021 struct timeval tv; 1022 char buffer[BUFSIZ]; 1023 va_list ap; 1024 1025 va_start(ap, format); 1026 1027 if (logfd >= 0) { 1028 int safechars; 1029 1030 (void) gettimeofday(&tv, NULL); 1031 (void) ctime_r(&tv.tv_sec, buffer, BUFSIZ); 1032 (void) snprintf(buffer+19, BUFSIZE, ".%.4ld ", 1033 tv.tv_usec/100); 1034 safechars = sizeof (buffer) - 30; 1035 if (vsnprintf(buffer+25, safechars, format, ap) > safechars) 1036 (void) strcat(buffer, "...\n"); 1037 (void) mutex_lock(&loglock); 1038 (void) write(logfd, buffer, strlen(buffer)); 1039 (void) mutex_unlock(&loglock); 1040 } 1041 va_end(ap); 1042 } 1043 1044 1045 static int 1046 client_getadmin(admin_t *ptr) 1047 { 1048 dataunion u; 1049 ldap_data_t *dptr; 1050 int ndata; 1051 int adata; 1052 1053 u.data.ldap_call.ldap_callnumber = GETADMIN; 1054 ndata = sizeof (u); 1055 adata = sizeof (u.data); 1056 dptr = &u.data; 1057 1058 if (__ns_ldap_trydoorcall(&dptr, &ndata, &adata) != NS_CACHE_SUCCESS) { 1059 return (-1); 1060 } 1061 (void) memcpy(ptr, dptr->ldap_ret.ldap_u.buff, sizeof (*ptr)); 1062 1063 return (0); 1064 } 1065 1066 1067 static int 1068 setadmin(ldap_call_t *ptr) 1069 { 1070 admin_t *new; 1071 1072 new = (admin_t *)ptr->ldap_u.domainname; 1073 1074 /* 1075 * global admin stuff 1076 */ 1077 1078 if ((cachemgr_set_lf(¤t_admin, new->logfile) < 0) || 1079 cachemgr_set_dl(¤t_admin, new->debug_level) < 0) { 1080 return (-1); 1081 } 1082 1083 if (cachemgr_set_ttl(¤t_admin.ldap_stat, 1084 "ldap", 1085 new->ldap_stat.ldap_ttl) < 0) { 1086 return (-1); 1087 } 1088 1089 return (0); 1090 } 1091 1092 1093 static void 1094 client_killserver() 1095 { 1096 dataunion u; 1097 ldap_data_t *dptr; 1098 int ndata; 1099 int adata; 1100 1101 u.data.ldap_call.ldap_callnumber = KILLSERVER; 1102 ndata = sizeof (u); 1103 adata = sizeof (ldap_call_t); 1104 dptr = &u.data; 1105 1106 __ns_ldap_trydoorcall(&dptr, &ndata, &adata); 1107 } 1108 1109 1110 static int 1111 client_setadmin(admin_t *ptr) 1112 { 1113 dataunion u; 1114 ldap_data_t *dptr; 1115 int ndata; 1116 int adata; 1117 1118 u.data.ldap_call.ldap_callnumber = SETADMIN; 1119 (void) memcpy(u.data.ldap_call.ldap_u.domainname, ptr, sizeof (*ptr)); 1120 ndata = sizeof (u); 1121 adata = sizeof (*ptr); 1122 dptr = &u.data; 1123 1124 if (__ns_ldap_trydoorcall(&dptr, &ndata, &adata) != NS_CACHE_SUCCESS) { 1125 return (-1); 1126 } 1127 1128 return (0); 1129 } 1130 1131 static int 1132 client_showstats(admin_t *ptr) 1133 { 1134 dataunion u; 1135 ldap_data_t *dptr; 1136 int ndata; 1137 int adata; 1138 char *rbuf, *sptr, *rest; 1139 1140 /* 1141 * print admin data 1142 */ 1143 (void) printf(gettext("\ncachemgr configuration:\n")); 1144 (void) printf(gettext("server debug level %10d\n"), ptr->debug_level); 1145 (void) printf(gettext("server log file\t\"%s\"\n"), ptr->logfile); 1146 (void) printf(gettext("number of calls to ldapcachemgr %10d\n"), 1147 ptr->ldap_stat.ldap_numbercalls); 1148 1149 /* 1150 * get cache data statistics 1151 */ 1152 u.data.ldap_call.ldap_callnumber = GETCACHESTAT; 1153 ndata = sizeof (u); 1154 adata = sizeof (ldap_call_t); 1155 dptr = &u.data; 1156 1157 if (__ns_ldap_trydoorcall(&dptr, &ndata, &adata) != NS_CACHE_SUCCESS) { 1158 (void) printf( 1159 gettext("\nCache data statistics not available!\n")); 1160 return (0); 1161 } 1162 1163 /* 1164 * print cache data statistics line by line 1165 */ 1166 (void) printf(gettext("\ncachemgr cache data statistics:\n")); 1167 rbuf = dptr->ldap_ret.ldap_u.buff; 1168 sptr = strtok_r(rbuf, DOORLINESEP, &rest); 1169 for (;;) { 1170 (void) printf("%s\n", sptr); 1171 sptr = strtok_r(NULL, DOORLINESEP, &rest); 1172 if (sptr == NULL) 1173 break; 1174 } 1175 return (0); 1176 } 1177 1178 1179 /* 1180 * detach from tty 1181 */ 1182 static void 1183 detachfromtty(char *pgm) 1184 { 1185 int status; 1186 pid_t pid, wret; 1187 1188 (void) close(0); 1189 (void) close(1); 1190 /* 1191 * Block the SIGUSR1 signal 1192 * just in case that the child 1193 * process may run faster than 1194 * the parent process and 1195 * send this signal before 1196 * the signal handler is ready 1197 * in the parent process. 1198 * This error will cause the parent 1199 * to exit with the User Signal 1 1200 * exit code (144). 1201 */ 1202 (void) sighold(SIGUSR1); 1203 pid = fork1(); 1204 switch (pid) { 1205 case (pid_t)-1: 1206 logit("detachfromtty(): fork1() call failed\n"); 1207 (void) fprintf(stderr, 1208 gettext("%s: fork1() call failed.\n"), 1209 pgm); 1210 syslog(LOG_ERR, 1211 gettext("ldap_cachemgr: fork1() call failed.")); 1212 exit(1); 1213 break; 1214 case 0: 1215 /* 1216 * child process does not 1217 * need to worry about 1218 * the SIGUSR1 signal 1219 */ 1220 (void) sigrelse(SIGUSR1); 1221 (void) close(2); 1222 break; 1223 default: 1224 /* 1225 * Wait forever until the child process 1226 * has exited, or has signalled that at 1227 * least one server in the server list 1228 * is up. 1229 */ 1230 if (signal(SIGUSR1, sig_ok_to_exit) == SIG_ERR) { 1231 logit("detachfromtty(): " 1232 "can't set up signal handler to " 1233 " catch SIGUSR1.\n"); 1234 (void) fprintf(stderr, 1235 gettext("%s: signal() call failed.\n"), 1236 pgm); 1237 syslog(LOG_ERR, gettext("ldap_cachemgr: " 1238 "can't set up signal handler to " 1239 " catch SIGUSR1.")); 1240 exit(1); 1241 } 1242 1243 /* 1244 * now unblock the SIGUSR1 signal 1245 * to handle the pending or 1246 * soon to arrive SIGUSR1 signal 1247 */ 1248 (void) sigrelse(SIGUSR1); 1249 wret = waitpid(pid, &status, 0); 1250 1251 if (wret == -1) { 1252 logit("detachfromtty(): " 1253 "waitpid() call failed\n"); 1254 (void) fprintf(stderr, 1255 gettext("%s: waitpid() call failed.\n"), 1256 pgm); 1257 syslog(LOG_ERR, 1258 gettext("ldap_cachemgr: waitpid() " 1259 "call failed.")); 1260 exit(1); 1261 } 1262 if (wret != pid) { 1263 logit("detachfromtty(): " 1264 "waitpid() returned %ld when " 1265 "child pid was %ld\n", 1266 wret, pid); 1267 (void) fprintf(stderr, 1268 gettext( 1269 "%s: waitpid() returned %ld when " 1270 "child pid was %ld.\n"), 1271 pgm, wret, pid); 1272 syslog(LOG_ERR, 1273 gettext("ldap_cachemgr: waitpid() " 1274 "returned different " 1275 "child pid.")); 1276 exit(1); 1277 } 1278 1279 /* evaluate return status */ 1280 if (WIFEXITED(status)) { 1281 if (WEXITSTATUS(status) == 0) { 1282 exit(0); 1283 } 1284 logit("detachfromtty(): " 1285 "child failed (rc = %d).\n", 1286 WEXITSTATUS(status)); 1287 (void) fprintf(stderr, 1288 gettext("%s: failed. Please see " 1289 "syslog for details.\n"), 1290 pgm); 1291 syslog(LOG_ERR, 1292 gettext("ldap_cachemgr: failed " 1293 "(rc = %d)."), 1294 WEXITSTATUS(status)); 1295 } else if (WIFSIGNALED(status)) { 1296 logit("detachfromtty(): " 1297 "child terminated by signal %d.\n", 1298 WTERMSIG(status)); 1299 (void) fprintf(stderr, 1300 gettext("%s: terminated by signal %d.\n"), 1301 pgm, WTERMSIG(status)); 1302 syslog(LOG_ERR, 1303 gettext("ldap_cachemgr: terminated by " 1304 "signal %d.\n"), 1305 WTERMSIG(status)); 1306 } else if (WCOREDUMP(status)) { 1307 logit("detachfromtty(): child core dumped.\n"), 1308 (void) fprintf(stderr, 1309 gettext("%s: core dumped.\n"), 1310 pgm); 1311 syslog(LOG_ERR, 1312 gettext("ldap_cachemgr: " 1313 "core dumped.\n")); 1314 } 1315 1316 exit(1); 1317 } 1318 (void) setsid(); 1319 if (open("/dev/null", O_RDWR, 0) != -1) { 1320 (void) dup(0); 1321 (void) dup(0); 1322 } 1323 } 1324 1325 /* 1326 * Check if the door client's euid is 0 1327 * 1328 * We could check for some privilege or re-design the interfaces that 1329 * lead to is_root() being called so that we rely on SMF and RBAC, but 1330 * we need this check only for dealing with undocumented-but-possibly- 1331 * used interfaces. Anything beyond checking for euid == 0 here would 1332 * be overkill considering that those are undocumented interfaces. 1333 * 1334 * If free_uc is 0, the caller is responsible for freeing *ucp. 1335 * 1336 * return - 0 euid != 0 1337 * 1 euid == 0 1338 */ 1339 static int 1340 is_root(int free_uc, char *dc_str, ucred_t **ucp) 1341 { 1342 int rc; 1343 1344 if (door_ucred(ucp) != 0) { 1345 rc = errno; 1346 logit("door_ucred() call failed %s\n", strerror(rc)); 1347 syslog(LOG_ERR, gettext("ldap_cachemgr: door_ucred() call %s " 1348 "failed %s"), strerror(rc)); 1349 return (0); 1350 } 1351 1352 1353 if (ucred_geteuid(*ucp) != 0) { 1354 1355 if (current_admin.debug_level >= DBG_CANT_FIND) 1356 logit("%s call failed(cred): caller pid %ld, uid %u, " 1357 "euid %u\n", dc_str, ucred_getpid(*ucp), 1358 ucred_getruid(*ucp), ucred_geteuid(*ucp)); 1359 1360 rc = 0; 1361 } else { 1362 1363 if (current_admin.debug_level >= DBG_ALL) 1364 logit("ldap_cachemgr received %s call from pid %ld, " 1365 "uid %u, euid %u\n", dc_str, ucred_getpid(*ucp), 1366 ucred_getruid(*ucp), ucred_geteuid(*ucp)); 1367 rc = 1; 1368 } 1369 1370 if (free_uc) 1371 ucred_free(*ucp); 1372 1373 return (rc); 1374 } 1375 1376 /* 1377 * Check if pid is nscd 1378 * 1379 * Input: pid - process id of the door client that calls ldap_cachemgr 1380 * 1381 * Return: 0 - No 1382 * 1 - Yes 1383 */ 1384 1385 int 1386 is_called_from_nscd(pid_t pid) 1387 1388 { 1389 static mutex_t _door_lock = DEFAULTMUTEX; 1390 static int doorfd = -1; 1391 int match; 1392 door_info_t my_door; 1393 1394 /* 1395 * the first time in we try and open and validate the door. 1396 * the validations are that the door must have been 1397 * created with the door cookie and 1398 * that the file attached to the door is owned by root 1399 * and readonly by user, group and other. If any of these 1400 * validations fail we refuse to use the door. 1401 */ 1402 1403 (void) mutex_lock(&_door_lock); 1404 1405 try_again: 1406 1407 if (doorfd == -1) { 1408 1409 if ((doorfd = open(NAME_SERVICE_DOOR, O_RDONLY, 0)) 1410 == -1) { 1411 (void) mutex_unlock(&_door_lock); 1412 return (0); 1413 } 1414 1415 if (door_info(doorfd, &my_door) == -1 || 1416 (my_door.di_attributes & DOOR_REVOKED) || 1417 my_door.di_data != (uintptr_t)NAME_SERVICE_DOOR_COOKIE) { 1418 /* 1419 * we should close doorfd because we just opened it 1420 */ 1421 (void) close(doorfd); 1422 doorfd = -1; 1423 (void) mutex_unlock(&_door_lock); 1424 return (0); 1425 } 1426 } else { 1427 /* 1428 * doorfd is cached. Double check just in case 1429 * the door server is restarted or is down. 1430 */ 1431 if (door_info(doorfd, &my_door) == -1 || 1432 my_door.di_data != (uintptr_t)NAME_SERVICE_DOOR_COOKIE) { 1433 /* 1434 * don't close it - 1435 * someone else has clobbered fd 1436 */ 1437 doorfd = -1; 1438 goto try_again; 1439 } 1440 1441 if (my_door.di_attributes & DOOR_REVOKED) { 1442 (void) close(doorfd); 1443 doorfd = -1; /* try and restart connection */ 1444 goto try_again; 1445 } 1446 } 1447 1448 /* 1449 * door descriptor exists and is valid 1450 */ 1451 if (pid == my_door.di_target) 1452 match = 1; 1453 else 1454 match = 0; 1455 1456 (void) mutex_unlock(&_door_lock); 1457 1458 return (match); 1459 1460 } 1461