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