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 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 /* 27 * Simple doors ldap cache daemon 28 */ 29 30 #include <stdio.h> 31 #include <stdlib.h> 32 #include <signal.h> 33 #include <door.h> 34 #include <time.h> 35 #include <string.h> 36 #include <strings.h> 37 #include <libintl.h> 38 #include <sys/stat.h> 39 #include <sys/time.h> 40 #include <sys/wait.h> 41 #include <stdlib.h> 42 #include <errno.h> 43 #include <pthread.h> 44 #include <thread.h> 45 #include <stdarg.h> 46 #include <fcntl.h> 47 #include <assert.h> 48 #include <unistd.h> 49 #include <memory.h> 50 #include <sys/types.h> 51 #include <syslog.h> 52 #include <locale.h> /* LC_ALL */ 53 54 #include <alloca.h> 55 #include <ucontext.h> 56 #include <stddef.h> /* offsetof */ 57 #include <priv.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_root_or_all_privs(char *dc_str, ucred_t **ucp); 76 static void admin_modify(LineBuf *config_info, ldap_call_t *in); 77 78 #ifdef SLP 79 int use_slp = 0; 80 static unsigned int refresh = 10800; /* dynamic discovery interval */ 81 #endif /* SLP */ 82 83 static ldap_stat_t * 84 getcacheptr(char *s) 85 { 86 static const char *caches[1] = {"ldap"}; 87 88 if (strncmp(caches[0], s, strlen(caches[0])) == 0) 89 return (¤t_admin.ldap_stat); 90 91 return (NULL); 92 } 93 94 char * 95 getcacheopt(char *s) 96 { 97 while (*s && *s != ',') 98 s++; 99 return ((*s == ',') ? (s + 1) : NULL); 100 } 101 102 /* 103 * This is here to prevent the ldap_cachemgr becomes 104 * daemonlized to early to soon during boot time. 105 * This causes problems during boot when automounter 106 * and others try to use libsldap before ldap_cachemgr 107 * finishes walking the server list. 108 */ 109 static void 110 sig_ok_to_exit(int signo) 111 { 112 if (signo == SIGUSR1) { 113 logit("sig_ok_to_exit(): parent exiting...\n"); 114 exit(0); 115 } else { 116 logit("sig_ok_to_exit(): invalid signal(%d) received.\n", 117 signo); 118 syslog(LOG_ERR, gettext("ldap_cachemgr: " 119 "invalid signal(%d) received."), signo); 120 exit(1); 121 } 122 } 123 #define LDAP_TABLES 1 /* ldap */ 124 #define TABLE_THREADS 10 125 #define COMMON_THREADS 20 126 #define CACHE_MISS_THREADS (COMMON_THREADS + LDAP_TABLES * TABLE_THREADS) 127 #define CACHE_HIT_THREADS 20 128 /* 129 * There is only one thread handling GETSTATUSCHANGE START from main nscd 130 * most of time. But it could happen that a main nscd is restarted, old main 131 * nscd's handling thread is still alive when new main nscd starts and sends 132 * START, or old main dies. STOP is not sent in both cases. 133 * The main nscd requires 2 threads to handle START and STOP. So max number 134 * of change threads is set to 4. 135 */ 136 #define MAX_CHG_THREADS 4 137 #define MAX_SERVER_THREADS (CACHE_HIT_THREADS + CACHE_MISS_THREADS + \ 138 MAX_CHG_THREADS) 139 140 static sema_t common_sema; 141 static sema_t ldap_sema; 142 static thread_key_t lookup_state_key; 143 static int chg_threads_num = 0; 144 static mutex_t chg_threads_num_lock = DEFAULTMUTEX; 145 146 static void 147 initialize_lookup_clearance() 148 { 149 (void) thr_keycreate(&lookup_state_key, NULL); 150 (void) sema_init(&common_sema, COMMON_THREADS, USYNC_THREAD, 0); 151 (void) sema_init(&ldap_sema, TABLE_THREADS, USYNC_THREAD, 0); 152 } 153 154 int 155 get_clearance(int callnumber) 156 { 157 sema_t *table_sema = NULL; 158 char *tab; 159 160 if (sema_trywait(&common_sema) == 0) { 161 (void) thr_setspecific(lookup_state_key, NULL); 162 return (0); 163 } 164 165 switch (callnumber) { 166 case GETLDAPCONFIG: 167 tab = "ldap"; 168 table_sema = &ldap_sema; 169 break; 170 default: 171 logit("Internal Error: get_clearance\n"); 172 break; 173 } 174 175 if (sema_trywait(table_sema) == 0) { 176 (void) thr_setspecific(lookup_state_key, (void*)1); 177 return (0); 178 } 179 180 if (current_admin.debug_level >= DBG_CANT_FIND) { 181 logit("get_clearance: throttling load for %s table\n", tab); 182 } 183 184 return (-1); 185 } 186 187 int 188 release_clearance(int callnumber) 189 { 190 int which; 191 sema_t *table_sema = NULL; 192 193 (void) thr_getspecific(lookup_state_key, (void**)&which); 194 if (which == 0) /* from common pool */ { 195 (void) sema_post(&common_sema); 196 return (0); 197 } 198 199 switch (callnumber) { 200 case GETLDAPCONFIG: 201 table_sema = &ldap_sema; 202 break; 203 default: 204 logit("Internal Error: release_clearance\n"); 205 break; 206 } 207 (void) sema_post(table_sema); 208 209 return (0); 210 } 211 212 213 static mutex_t create_lock; 214 static int num_servers = 0; 215 static thread_key_t server_key; 216 217 218 /* 219 * Bind a TSD value to a server thread. This enables the destructor to 220 * be called if/when this thread exits. This would be a programming error, 221 * but better safe than sorry. 222 */ 223 224 /*ARGSUSED*/ 225 static void * 226 server_tsd_bind(void *arg) 227 { 228 static void *value = 0; 229 230 /* 231 * disable cancellation to prevent hangs when server 232 * threads disappear 233 */ 234 235 (void) thr_setspecific(server_key, value); 236 (void) door_return(NULL, 0, NULL, 0); 237 238 return (value); 239 } 240 241 /* 242 * Server threads are created here. 243 */ 244 245 /*ARGSUSED*/ 246 static void 247 server_create(door_info_t *dip) 248 { 249 (void) mutex_lock(&create_lock); 250 if (++num_servers > MAX_SERVER_THREADS) { 251 num_servers--; 252 (void) mutex_unlock(&create_lock); 253 return; 254 } 255 (void) mutex_unlock(&create_lock); 256 (void) thr_create(NULL, 0, server_tsd_bind, NULL, 257 THR_BOUND|THR_DETACHED, NULL); 258 } 259 260 /* 261 * Server thread are destroyed here 262 */ 263 264 /*ARGSUSED*/ 265 static void 266 server_destroy(void *arg) 267 { 268 (void) mutex_lock(&create_lock); 269 num_servers--; 270 (void) mutex_unlock(&create_lock); 271 } 272 273 int 274 main(int argc, char ** argv) 275 { 276 int did; 277 int opt; 278 int errflg = 0; 279 int showstats = 0; 280 int doset = 0; 281 int dofg = 0; 282 struct stat buf; 283 sigset_t myset; 284 struct sigaction sighupaction; 285 static void client_killserver(); 286 int debug_level = 0; 287 288 /* setup for localization */ 289 (void) setlocale(LC_ALL, ""); 290 (void) textdomain(TEXT_DOMAIN); 291 292 openlog("ldap_cachemgr", LOG_PID, LOG_DAEMON); 293 294 if (chdir(NSLDAPDIRECTORY) < 0) { 295 (void) fprintf(stderr, gettext("chdir(\"%s\") failed: %s\n"), 296 NSLDAPDIRECTORY, strerror(errno)); 297 exit(1); 298 } 299 300 /* 301 * Correctly set file mode creation mask, so to make the new files 302 * created for door calls being readable by all. 303 */ 304 (void) umask(0); 305 306 /* 307 * Special case non-root user here - he/she/they/it can just print 308 * stats 309 */ 310 311 if (geteuid()) { 312 if (argc != 2 || strcmp(argv[1], "-g")) { 313 (void) fprintf(stderr, 314 gettext("Must be root to use any option " 315 "other than -g.\n\n")); 316 usage(argv[0]); 317 } 318 319 if ((__ns_ldap_cache_ping() != NS_CACHE_SUCCESS) || 320 (client_getadmin(¤t_admin) != 0)) { 321 (void) fprintf(stderr, 322 gettext("%s doesn't appear to be running.\n"), 323 argv[0]); 324 exit(1); 325 } 326 (void) client_showstats(¤t_admin); 327 exit(0); 328 } 329 330 331 332 /* 333 * Determine if there is already a daemon running 334 */ 335 336 will_become_server = (__ns_ldap_cache_ping() != NS_CACHE_SUCCESS); 337 338 /* 339 * load normal config file 340 */ 341 342 if (will_become_server) { 343 static const ldap_stat_t defaults = { 344 0, /* stat */ 345 DEFAULTTTL}; /* ttl */ 346 347 current_admin.ldap_stat = defaults; 348 (void) strcpy(current_admin.logfile, LOGFILE); 349 } else { 350 if (client_getadmin(¤t_admin)) { 351 (void) fprintf(stderr, gettext("Cannot contact %s " 352 "properly(?)\n"), argv[0]); 353 exit(1); 354 } 355 } 356 357 #ifndef SLP 358 while ((opt = getopt(argc, argv, "fKgl:r:d:")) != EOF) { 359 #else 360 while ((opt = getopt(argc, argv, "fKgs:l:r:d:")) != EOF) { 361 #endif /* SLP */ 362 ldap_stat_t *cache; 363 364 switch (opt) { 365 case 'K': 366 client_killserver(); 367 exit(0); 368 break; 369 case 'g': 370 showstats++; 371 break; 372 case 'f': 373 dofg++; 374 break; 375 case 'r': 376 doset++; 377 cache = getcacheptr("ldap"); 378 if (!optarg) { 379 errflg++; 380 break; 381 } 382 cache->ldap_ttl = atoi(optarg); 383 break; 384 case 'l': 385 doset++; 386 (void) strlcpy(current_admin.logfile, 387 optarg, sizeof (current_admin.logfile)); 388 break; 389 case 'd': 390 doset++; 391 debug_level = atoi(optarg); 392 break; 393 #ifdef SLP 394 case 's': /* undocumented: use dynamic (SLP) config */ 395 use_slp = 1; 396 break; 397 #endif /* SLP */ 398 default: 399 errflg++; 400 break; 401 } 402 } 403 404 if (errflg) 405 usage(argv[0]); 406 407 /* 408 * will not show statistics if no daemon running 409 */ 410 if (will_become_server && showstats) { 411 (void) fprintf(stderr, 412 gettext("%s doesn't appear to be running.\n"), 413 argv[0]); 414 exit(1); 415 } 416 417 if (!will_become_server) { 418 if (showstats) { 419 (void) client_showstats(¤t_admin); 420 } 421 if (doset) { 422 current_admin.debug_level = debug_level; 423 if (client_setadmin(¤t_admin) < 0) { 424 (void) fprintf(stderr, 425 gettext("Error during admin call\n")); 426 exit(1); 427 } 428 } 429 if (!showstats && !doset) { 430 (void) fprintf(stderr, 431 gettext("%s already running....use '%s " 432 "-K' to stop\n"), argv[0], argv[0]); 433 } 434 exit(0); 435 } 436 437 /* 438 * daemon from here on 439 */ 440 441 if (debug_level) { 442 /* 443 * we're debugging... 444 */ 445 if (strlen(current_admin.logfile) == 0) 446 /* 447 * no specified log file 448 */ 449 (void) strcpy(current_admin.logfile, LOGFILE); 450 else 451 (void) cachemgr_set_lf(¤t_admin, 452 current_admin.logfile); 453 /* 454 * validate the range of debug level number 455 * and set the number to current_admin.debug_level 456 */ 457 if (cachemgr_set_dl(¤t_admin, debug_level) < 0) { 458 /* 459 * print error messages to the screen 460 * cachemgr_set_dl prints msgs to cachemgr.log 461 * only 462 */ 463 (void) fprintf(stderr, 464 gettext("Incorrect Debug Level: %d\n" 465 "It should be between %d and %d\n"), 466 debug_level, DBG_OFF, MAXDEBUG); 467 exit(-1); 468 } 469 } else { 470 if (strlen(current_admin.logfile) == 0) 471 (void) strcpy(current_admin.logfile, "/dev/null"); 472 (void) cachemgr_set_lf(¤t_admin, 473 current_admin.logfile); 474 } 475 476 if (dofg == 0) 477 detachfromtty(argv[0]); 478 479 /* 480 * perform some initialization 481 */ 482 483 initialize_lookup_clearance(); 484 485 if (getldap_init() != 0) 486 exit(-1); 487 488 /* 489 * Establish our own server thread pool 490 */ 491 492 (void) door_server_create(server_create); 493 if (thr_keycreate(&server_key, server_destroy) != 0) { 494 logit("thr_keycreate() call failed\n"); 495 syslog(LOG_ERR, 496 gettext("ldap_cachemgr: thr_keycreate() call failed")); 497 perror("thr_keycreate"); 498 exit(-1); 499 } 500 501 /* 502 * Create a door 503 */ 504 505 if ((did = door_create(switcher, LDAP_CACHE_DOOR_COOKIE, 506 DOOR_UNREF | DOOR_REFUSE_DESC | DOOR_NO_CANCEL)) < 0) { 507 logit("door_create() call failed\n"); 508 syslog(LOG_ERR, gettext( 509 "ldap_cachemgr: door_create() call failed")); 510 perror("door_create"); 511 exit(-1); 512 } 513 514 /* 515 * bind to file system 516 */ 517 518 if (stat(LDAP_CACHE_DOOR, &buf) < 0) { 519 int newfd; 520 521 if ((newfd = creat(LDAP_CACHE_DOOR, 0444)) < 0) { 522 logit("Cannot create %s:%s\n", 523 LDAP_CACHE_DOOR, 524 strerror(errno)); 525 exit(1); 526 } 527 (void) close(newfd); 528 } 529 530 if (fattach(did, LDAP_CACHE_DOOR) < 0) { 531 if ((errno != EBUSY) || 532 (fdetach(LDAP_CACHE_DOOR) < 0) || 533 (fattach(did, LDAP_CACHE_DOOR) < 0)) { 534 logit("fattach() call failed\n"); 535 syslog(LOG_ERR, gettext( 536 "ldap_cachemgr: fattach() call failed")); 537 perror("fattach"); 538 exit(2); 539 } 540 } 541 542 /* catch SIGHUP revalid signals */ 543 sighupaction.sa_handler = getldap_revalidate; 544 sighupaction.sa_flags = 0; 545 (void) sigemptyset(&sighupaction.sa_mask); 546 (void) sigemptyset(&myset); 547 (void) sigaddset(&myset, SIGHUP); 548 549 if (sigaction(SIGHUP, &sighupaction, NULL) < 0) { 550 logit("sigaction() call failed\n"); 551 syslog(LOG_ERR, 552 gettext("ldap_cachemgr: sigaction() call failed")); 553 perror("sigaction"); 554 exit(1); 555 } 556 557 if (thr_sigsetmask(SIG_BLOCK, &myset, NULL) < 0) { 558 logit("thr_sigsetmask() call failed\n"); 559 syslog(LOG_ERR, 560 gettext("ldap_cachemgr: thr_sigsetmask() call failed")); 561 perror("thr_sigsetmask"); 562 exit(1); 563 } 564 565 /* 566 * kick off revalidate threads only if ttl != 0 567 */ 568 569 if (thr_create(NULL, 0, (void *(*)(void*))getldap_refresh, 570 NULL, 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 /* 579 * kick off the thread which refreshes the server info 580 */ 581 582 if (thr_create(NULL, 0, (void *(*)(void*))getldap_serverInfo_refresh, 583 NULL, 0, NULL) != 0) { 584 logit("thr_create() call failed\n"); 585 syslog(LOG_ERR, 586 gettext("ldap_cachemgr: thr_create() call failed")); 587 perror("thr_create"); 588 exit(1); 589 } 590 591 /* 592 * kick off the thread which cleans up waiting threads for 593 * GETSTATUSCHANGE 594 */ 595 596 if (thr_create(NULL, 0, chg_cleanup_waiting_threads, 597 NULL, 0, NULL) != 0) { 598 logit("thr_create() chg_cleanup_waiting_threads call failed\n"); 599 syslog(LOG_ERR, 600 gettext("ldap_cachemgr: thr_create() " 601 "chg_cleanup_waiting_threads call failed")); 602 exit(1); 603 } 604 605 #ifdef SLP 606 if (use_slp) { 607 /* kick off SLP discovery thread */ 608 if (thr_create(NULL, 0, (void *(*)(void *))discover, 609 (void *)&refresh, 0, NULL) != 0) { 610 logit("thr_create() call failed\n"); 611 syslog(LOG_ERR, gettext("ldap_cachemgr: thr_create() " 612 "call failed")); 613 perror("thr_create"); 614 exit(1); 615 } 616 } 617 #endif /* SLP */ 618 619 if (thr_sigsetmask(SIG_UNBLOCK, &myset, NULL) < 0) { 620 logit("thr_sigsetmask() call failed\n"); 621 syslog(LOG_ERR, 622 gettext("ldap_cachemgr: the_sigsetmask() call failed")); 623 perror("thr_sigsetmask"); 624 exit(1); 625 } 626 627 /*CONSTCOND*/ 628 while (1) { 629 (void) pause(); 630 } 631 /* NOTREACHED */ 632 /*LINTED E_FUNC_HAS_NO_RETURN_STMT*/ 633 } 634 635 636 /* 637 * Before calling the alloca() function we have to be sure that we won't get 638 * beyond the stack. Since we don't know the precise layout of the stack, 639 * the address of an automatic of the function gives us a rough idea, plus/minus 640 * a bit. We also need a bit more of stackspace after the call to be able 641 * to call further functions. Even something as simple as making a system call 642 * from within this function can take ~100 Bytes of stackspace. 643 */ 644 #define SAFETY_BUFFER 32 * 1024 /* 32KB */ 645 646 static 647 size_t 648 get_data_size(LineBuf *config_info, int *err_code) 649 { 650 size_t configSize = sizeof (ldap_return_t); 651 dataunion *buf = NULL; /* For the 'sizeof' purpose */ 652 653 if (config_info->str != NULL && 654 config_info->len >= sizeof (buf->data.ldap_ret.ldap_u.config)) { 655 configSize = sizeof (buf->space) + 656 config_info->len - 657 sizeof (buf->data.ldap_ret.ldap_u.config); 658 659 if (!stack_inbounds((char *)&buf - 660 (configSize + SAFETY_BUFFER))) { 661 /* 662 * We do not have enough space on the stack 663 * to accomodate the whole DUAProfile 664 */ 665 logit("The DUAProfile is too big. There is not enough " 666 "space to process it. Ignoring it.\n"); 667 syslog(LOG_ERR, gettext("ldap_cachemgr: The DUAProfile " 668 "is too big. There is not enough space " 669 "to process it. Ignoring it.")); 670 671 *err_code = NS_CACHE_SERVERERROR; 672 673 free(config_info->str); 674 config_info->str = NULL; 675 config_info->len = 0; 676 configSize = sizeof (ldap_return_t); 677 } 678 } 679 680 return (configSize); 681 } 682 683 /*ARGSUSED*/ 684 static void 685 switcher(void *cookie, char *argp, size_t arg_size, 686 door_desc_t *dp, uint_t n_desc) 687 { 688 #define GETSIZE 1000 689 #define ALLOCATE 1001 690 691 ldap_call_t *ptr = (ldap_call_t *)argp; 692 ucred_t *uc = NULL; 693 694 LineBuf configInfo; 695 dataunion *buf = NULL; 696 697 /* 698 * By default the size of a buffer to be passed down to a client 699 * is equal to the size of the ldap_return_t structure. We need 700 * a bigger buffer in a few cases. 701 */ 702 size_t configSize = sizeof (ldap_return_t); 703 int ldapErrno = 0, state, callnumber; 704 struct { 705 void *begin; 706 size_t size; 707 uint8_t destroy; 708 } dataSource; 709 710 if (argp == DOOR_UNREF_DATA) { 711 logit("Door Slam... invalid door param\n"); 712 syslog(LOG_ERR, gettext("ldap_cachemgr: Door Slam... " 713 "invalid door param")); 714 (void) printf(gettext("Door Slam... invalid door param\n")); 715 exit(0); 716 } 717 718 if (ptr == NULL) { /* empty door call */ 719 (void) door_return(NULL, 0, 0, 0); /* return the favor */ 720 } 721 722 bzero(&dataSource, sizeof (dataSource)); 723 724 /* 725 * We presume that sizeof (ldap_return_t) bytes are always available 726 * on the stack 727 */ 728 callnumber = ptr->ldap_callnumber; 729 730 switch (callnumber) { 731 case NULLCALL: 732 /* 733 * Just a 'ping'. Use the default size 734 * of the buffer and set the 735 * 'OK' error code. 736 */ 737 state = ALLOCATE; 738 break; 739 case GETLDAPCONFIG: 740 /* 741 * Get the current LDAP configuration. 742 * Since this is dynamic data and its size can exceed 743 * the size of ldap_return_t, the next step will 744 * calculate who much space exactly is required. 745 */ 746 getldap_lookup(&configInfo, ptr); 747 748 state = GETSIZE; 749 break; 750 case GETLDAPSERVER: 751 /* 752 * Get the root DSE for a next server in the list. 753 * Since this is dynamic data and its size can exceed 754 * the size of ldap_return_t, the next step will 755 * calculate who much space exactly is required. 756 */ 757 getldap_getserver(&configInfo, ptr); 758 759 state = GETSIZE; 760 break; 761 case GETCACHESTAT: 762 /* 763 * Get the cache stattistics. 764 * Since this is dynamic data and its size can exceed 765 * the size of ldap_return_t, the next step will 766 * calculate how much space exactly is required. 767 */ 768 getldap_get_cacheStat(&configInfo); 769 770 state = GETSIZE; 771 break; 772 case GETADMIN: 773 /* 774 * Get current configuration and statistics. 775 * The size of the statistics structure is less then 776 * sizeof (ldap_return_t). So specify the source 777 * where to take the info and proceed with the memory 778 * allocation. 779 */ 780 state = ALLOCATE; 781 782 if (ldapErrno == 0) { 783 dataSource.begin = ¤t_admin; 784 dataSource.size = sizeof (current_admin); 785 dataSource.destroy = 0; 786 } 787 break; 788 case KILLSERVER: 789 /* 790 * Process the request and proceed with the default 791 * buffer allocation. 792 */ 793 if (is_root(1, "KILLSERVER", &uc)) 794 exit(0); 795 796 ldapErrno = -1; 797 state = ALLOCATE; 798 break; 799 case SETADMIN: 800 /* 801 * Process the request and proceed with the default 802 * buffer allocation. 803 */ 804 if (is_root(1, "SETADMIN", &uc)) 805 ldapErrno = setadmin(ptr); 806 else 807 ldapErrno = -1; 808 809 state = ALLOCATE; 810 break; 811 case GETCACHE: 812 /* 813 * Get the cache stattistics. 814 * Since this is dynamic data and its size can exceed 815 * the size of ldap_return_t, the next step will 816 * calculate how much space exactly is required. 817 */ 818 getldap_get_cacheData(&configInfo, ptr); 819 820 state = GETSIZE; 821 break; 822 case SETCACHE: 823 /* 824 * Process the request and proceed with the default 825 * buffer allocation. 826 */ 827 if (is_root(0, "SETCACHE", &uc) && 828 is_called_from_nscd(ucred_getpid(uc))) { 829 ldapErrno = getldap_set_cacheData(ptr); 830 current_admin.ldap_stat.ldap_numbercalls++; 831 } else 832 ldapErrno = -1; 833 834 if (uc != NULL) 835 ucred_free(uc); 836 state = ALLOCATE; 837 break; 838 case ADMINMODIFY: 839 admin_modify(&configInfo, ptr); 840 841 state = GETSIZE; 842 break; 843 case GETSTATUSCHANGE: 844 /* 845 * Process the request and proceed with the default 846 * buffer allocation. 847 */ 848 (void) mutex_lock(&chg_threads_num_lock); 849 chg_threads_num++; 850 if (chg_threads_num > MAX_CHG_THREADS) { 851 chg_threads_num--; 852 (void) mutex_unlock(&chg_threads_num_lock); 853 ldapErrno = CHG_EXCEED_MAX_THREADS; 854 state = ALLOCATE; 855 break; 856 } 857 (void) mutex_unlock(&chg_threads_num_lock); 858 859 if (is_root(0, "GETSTATUSCHANGE", &uc) && 860 is_called_from_nscd(ucred_getpid(uc))) { 861 ldapErrno = chg_get_statusChange( 862 &configInfo, ptr, ucred_getpid(uc)); 863 state = GETSIZE; 864 } else { 865 ldapErrno = -1; 866 state = ALLOCATE; 867 } 868 if (uc != NULL) 869 ucred_free(uc); 870 871 (void) mutex_lock(&chg_threads_num_lock); 872 chg_threads_num--; 873 (void) mutex_unlock(&chg_threads_num_lock); 874 break; 875 default: 876 /* 877 * This means an unknown request type. Proceed with 878 * the default buffer allocation. 879 */ 880 logit("Unknown ldap service door call op %d\n", 881 ptr->ldap_callnumber); 882 ldapErrno = -99; 883 884 state = ALLOCATE; 885 break; 886 } 887 888 switch (state) { 889 case GETSIZE: 890 /* 891 * This stage calculates how much data will be 892 * passed down to the client, checks if there is 893 * enough space on the stack to accommodate the data, 894 * increases the value of the configSize variable 895 * if necessary and specifies the data source. 896 * In case of any error occurred ldapErrno will be set 897 * appropriately. 898 */ 899 if (configInfo.str == NULL) { 900 ldapErrno = -1; 901 } 902 903 configSize = get_data_size(&configInfo, &ldapErrno); 904 905 if (ldapErrno == 0) { 906 dataSource.begin = configInfo.str; 907 dataSource.size = configInfo.len; 908 dataSource.destroy = 1; 909 } 910 911 current_admin.ldap_stat.ldap_numbercalls++; 912 /* FALLTHRU */ 913 case ALLOCATE: 914 /* 915 * Allocate a buffer of the calculated (or default) size 916 * and proceed with populating it with data. 917 */ 918 buf = (dataunion *) alloca(configSize); 919 920 /* 921 * Set a return code and, if a data source is specified, 922 * copy data from the source to the buffer. 923 */ 924 buf->data.ldap_ret.ldap_errno = ldapErrno; 925 buf->data.ldap_ret.ldap_return_code = ldapErrno; 926 buf->data.ldap_ret.ldap_bufferbytesused = configSize; 927 928 if (dataSource.begin != NULL) { 929 (void) memcpy(buf->data.ldap_ret.ldap_u.config, 930 dataSource.begin, 931 dataSource.size); 932 if (dataSource.destroy) { 933 free(dataSource.begin); 934 } 935 } 936 937 } 938 (void) door_return((char *)&buf->data, 939 buf->data.ldap_ret.ldap_bufferbytesused, 940 NULL, 941 0); 942 #undef GETSIZE 943 #undef ALLOCATE 944 } 945 946 static void 947 usage(char *s) 948 { 949 (void) fprintf(stderr, 950 gettext("Usage: %s [-d debug_level] [-l logfilename]\n"), s); 951 (void) fprintf(stderr, gettext(" [-K] " 952 "[-r revalidate_interval] ")); 953 #ifndef SLP 954 (void) fprintf(stderr, gettext(" [-g]\n")); 955 #else 956 (void) fprintf(stderr, gettext(" [-g] [-s]\n")); 957 #endif /* SLP */ 958 exit(1); 959 } 960 961 962 static int logfd = -1; 963 964 static int 965 cachemgr_set_lf(admin_t *ptr, char *logfile) 966 { 967 int newlogfd; 968 969 /* 970 * we don't really want to try and open the log file 971 * /dev/null since that will fail w/ our security fixes 972 */ 973 974 if (logfile == NULL || *logfile == 0) { 975 /*EMPTY*/; 976 } else if (strcmp(logfile, "/dev/null") == 0) { 977 (void) strcpy(current_admin.logfile, "/dev/null"); 978 (void) close(logfd); 979 logfd = -1; 980 } else { 981 if ((newlogfd = 982 open(logfile, O_EXCL|O_WRONLY|O_CREAT, 0644)) < 0) { 983 /* 984 * File already exists... now we need to get cute 985 * since opening a file in a world-writeable directory 986 * safely is hard = it could be a hard link or a 987 * symbolic link to a system file. 988 * 989 */ 990 struct stat before; 991 992 if (lstat(logfile, &before) < 0) { 993 logit("Cannot open new logfile \"%s\": %sn", 994 logfile, strerror(errno)); 995 return (-1); 996 } 997 if (S_ISREG(before.st_mode) && /* no symbolic links */ 998 (before.st_nlink == 1) && /* no hard links */ 999 (before.st_uid == 0)) { /* owned by root */ 1000 if ((newlogfd = 1001 open(logfile, 1002 O_APPEND|O_WRONLY, 0644)) < 0) { 1003 logit("Cannot open new logfile " 1004 "\"%s\": %s\n", 1005 logfile, strerror(errno)); 1006 return (-1); 1007 } 1008 } else { 1009 logit("Cannot use specified logfile " 1010 "\"%s\": file is/has links or isn't " 1011 "owned by root\n", logfile); 1012 return (-1); 1013 } 1014 } 1015 (void) strlcpy(ptr->logfile, logfile, sizeof (ptr->logfile)); 1016 (void) close(logfd); 1017 logfd = newlogfd; 1018 logit("Starting ldap_cachemgr, logfile %s\n", logfile); 1019 } 1020 return (0); 1021 } 1022 1023 /*PRINTFLIKE1*/ 1024 void 1025 logit(char *format, ...) 1026 { 1027 static mutex_t loglock; 1028 struct timeval tv; 1029 char buffer[BUFSIZ]; 1030 va_list ap; 1031 1032 va_start(ap, format); 1033 1034 if (logfd >= 0) { 1035 int safechars; 1036 1037 (void) gettimeofday(&tv, NULL); 1038 (void) ctime_r(&tv.tv_sec, buffer, BUFSIZ); 1039 (void) snprintf(buffer+19, BUFSIZE, ".%.4ld ", 1040 tv.tv_usec/100); 1041 safechars = sizeof (buffer) - 30; 1042 if (vsnprintf(buffer+25, safechars, format, ap) > safechars) 1043 (void) strcat(buffer, "...\n"); 1044 (void) mutex_lock(&loglock); 1045 (void) write(logfd, buffer, strlen(buffer)); 1046 (void) mutex_unlock(&loglock); 1047 } 1048 va_end(ap); 1049 } 1050 1051 1052 static int 1053 client_getadmin(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 = GETADMIN; 1061 ndata = sizeof (u); 1062 adata = sizeof (u.data); 1063 dptr = &u.data; 1064 1065 if (__ns_ldap_trydoorcall(&dptr, &ndata, &adata) != NS_CACHE_SUCCESS) { 1066 return (-1); 1067 } 1068 (void) memcpy(ptr, dptr->ldap_ret.ldap_u.buff, sizeof (*ptr)); 1069 1070 return (0); 1071 } 1072 1073 1074 static int 1075 setadmin(ldap_call_t *ptr) 1076 { 1077 admin_t *new; 1078 1079 new = (admin_t *)ptr->ldap_u.domainname; 1080 1081 /* 1082 * global admin stuff 1083 */ 1084 1085 if ((cachemgr_set_lf(¤t_admin, new->logfile) < 0) || 1086 cachemgr_set_dl(¤t_admin, new->debug_level) < 0) { 1087 return (-1); 1088 } 1089 1090 if (cachemgr_set_ttl(¤t_admin.ldap_stat, 1091 "ldap", 1092 new->ldap_stat.ldap_ttl) < 0) { 1093 return (-1); 1094 } 1095 1096 return (0); 1097 } 1098 1099 1100 static void 1101 client_killserver() 1102 { 1103 dataunion u; 1104 ldap_data_t *dptr; 1105 int ndata; 1106 int adata; 1107 1108 u.data.ldap_call.ldap_callnumber = KILLSERVER; 1109 ndata = sizeof (u); 1110 adata = sizeof (ldap_call_t); 1111 dptr = &u.data; 1112 1113 __ns_ldap_trydoorcall(&dptr, &ndata, &adata); 1114 } 1115 1116 1117 static int 1118 client_setadmin(admin_t *ptr) 1119 { 1120 dataunion u; 1121 ldap_data_t *dptr; 1122 int ndata; 1123 int adata; 1124 1125 u.data.ldap_call.ldap_callnumber = SETADMIN; 1126 (void) memcpy(u.data.ldap_call.ldap_u.domainname, ptr, sizeof (*ptr)); 1127 ndata = sizeof (u); 1128 adata = sizeof (*ptr); 1129 dptr = &u.data; 1130 1131 if (__ns_ldap_trydoorcall(&dptr, &ndata, &adata) != NS_CACHE_SUCCESS) { 1132 return (-1); 1133 } 1134 1135 return (0); 1136 } 1137 1138 static int 1139 client_showstats(admin_t *ptr) 1140 { 1141 dataunion u; 1142 ldap_data_t *dptr; 1143 int ndata; 1144 int adata; 1145 char *rbuf, *sptr, *rest; 1146 1147 /* 1148 * print admin data 1149 */ 1150 (void) printf(gettext("\ncachemgr configuration:\n")); 1151 (void) printf(gettext("server debug level %10d\n"), ptr->debug_level); 1152 (void) printf(gettext("server log file\t\"%s\"\n"), ptr->logfile); 1153 (void) printf(gettext("number of calls to ldapcachemgr %10d\n"), 1154 ptr->ldap_stat.ldap_numbercalls); 1155 1156 /* 1157 * get cache data statistics 1158 */ 1159 u.data.ldap_call.ldap_callnumber = GETCACHESTAT; 1160 ndata = sizeof (u); 1161 adata = sizeof (ldap_call_t); 1162 dptr = &u.data; 1163 1164 if (__ns_ldap_trydoorcall(&dptr, &ndata, &adata) != NS_CACHE_SUCCESS) { 1165 (void) printf( 1166 gettext("\nCache data statistics not available!\n")); 1167 return (0); 1168 } 1169 1170 /* 1171 * print cache data statistics line by line 1172 */ 1173 (void) printf(gettext("\ncachemgr cache data statistics:\n")); 1174 rbuf = dptr->ldap_ret.ldap_u.buff; 1175 sptr = strtok_r(rbuf, DOORLINESEP, &rest); 1176 for (;;) { 1177 (void) printf("%s\n", sptr); 1178 sptr = strtok_r(NULL, DOORLINESEP, &rest); 1179 if (sptr == NULL) 1180 break; 1181 } 1182 return (0); 1183 } 1184 1185 1186 /* 1187 * detach from tty 1188 */ 1189 static void 1190 detachfromtty(char *pgm) 1191 { 1192 int status; 1193 pid_t pid, wret; 1194 1195 (void) close(0); 1196 (void) close(1); 1197 /* 1198 * Block the SIGUSR1 signal 1199 * just in case that the child 1200 * process may run faster than 1201 * the parent process and 1202 * send this signal before 1203 * the signal handler is ready 1204 * in the parent process. 1205 * This error will cause the parent 1206 * to exit with the User Signal 1 1207 * exit code (144). 1208 */ 1209 (void) sighold(SIGUSR1); 1210 pid = fork1(); 1211 switch (pid) { 1212 case (pid_t)-1: 1213 logit("detachfromtty(): fork1() call failed\n"); 1214 (void) fprintf(stderr, 1215 gettext("%s: fork1() call failed.\n"), 1216 pgm); 1217 syslog(LOG_ERR, 1218 gettext("ldap_cachemgr: fork1() call failed.")); 1219 exit(1); 1220 break; 1221 case 0: 1222 /* 1223 * child process does not 1224 * need to worry about 1225 * the SIGUSR1 signal 1226 */ 1227 (void) sigrelse(SIGUSR1); 1228 (void) close(2); 1229 break; 1230 default: 1231 /* 1232 * Wait forever until the child process 1233 * has exited, or has signalled that at 1234 * least one server in the server list 1235 * is up. 1236 */ 1237 if (signal(SIGUSR1, sig_ok_to_exit) == SIG_ERR) { 1238 logit("detachfromtty(): " 1239 "can't set up signal handler to " 1240 " catch SIGUSR1.\n"); 1241 (void) fprintf(stderr, 1242 gettext("%s: signal() call failed.\n"), 1243 pgm); 1244 syslog(LOG_ERR, gettext("ldap_cachemgr: " 1245 "can't set up signal handler to " 1246 " catch SIGUSR1.")); 1247 exit(1); 1248 } 1249 1250 /* 1251 * now unblock the SIGUSR1 signal 1252 * to handle the pending or 1253 * soon to arrive SIGUSR1 signal 1254 */ 1255 (void) sigrelse(SIGUSR1); 1256 wret = waitpid(pid, &status, 0); 1257 1258 if (wret == -1) { 1259 logit("detachfromtty(): " 1260 "waitpid() call failed\n"); 1261 (void) fprintf(stderr, 1262 gettext("%s: waitpid() call failed.\n"), 1263 pgm); 1264 syslog(LOG_ERR, 1265 gettext("ldap_cachemgr: waitpid() " 1266 "call failed.")); 1267 exit(1); 1268 } 1269 if (wret != pid) { 1270 logit("detachfromtty(): " 1271 "waitpid() returned %ld when " 1272 "child pid was %ld\n", 1273 wret, pid); 1274 (void) fprintf(stderr, 1275 gettext( 1276 "%s: waitpid() returned %ld when " 1277 "child pid was %ld.\n"), 1278 pgm, wret, pid); 1279 syslog(LOG_ERR, 1280 gettext("ldap_cachemgr: waitpid() " 1281 "returned different " 1282 "child pid.")); 1283 exit(1); 1284 } 1285 1286 /* evaluate return status */ 1287 if (WIFEXITED(status)) { 1288 if (WEXITSTATUS(status) == 0) { 1289 exit(0); 1290 } 1291 logit("detachfromtty(): " 1292 "child failed (rc = %d).\n", 1293 WEXITSTATUS(status)); 1294 (void) fprintf(stderr, 1295 gettext("%s: failed. Please see " 1296 "syslog for details.\n"), 1297 pgm); 1298 syslog(LOG_ERR, 1299 gettext("ldap_cachemgr: failed " 1300 "(rc = %d)."), 1301 WEXITSTATUS(status)); 1302 } else if (WIFSIGNALED(status)) { 1303 logit("detachfromtty(): " 1304 "child terminated by signal %d.\n", 1305 WTERMSIG(status)); 1306 (void) fprintf(stderr, 1307 gettext("%s: terminated by signal %d.\n"), 1308 pgm, WTERMSIG(status)); 1309 syslog(LOG_ERR, 1310 gettext("ldap_cachemgr: terminated by " 1311 "signal %d.\n"), 1312 WTERMSIG(status)); 1313 } else if (WCOREDUMP(status)) { 1314 logit("detachfromtty(): child core dumped.\n"), 1315 (void) fprintf(stderr, 1316 gettext("%s: core dumped.\n"), 1317 pgm); 1318 syslog(LOG_ERR, 1319 gettext("ldap_cachemgr: " 1320 "core dumped.\n")); 1321 } 1322 1323 exit(1); 1324 } 1325 (void) setsid(); 1326 if (open("/dev/null", O_RDWR, 0) != -1) { 1327 (void) dup(0); 1328 (void) dup(0); 1329 } 1330 } 1331 1332 /* 1333 * Check if the door client's euid is 0 1334 * 1335 * We could check for some privilege or re-design the interfaces that 1336 * lead to is_root() being called so that we rely on SMF and RBAC, but 1337 * we need this check only for dealing with undocumented-but-possibly- 1338 * used interfaces. Anything beyond checking for euid == 0 here would 1339 * be overkill considering that those are undocumented interfaces. 1340 * 1341 * If free_uc is 0, the caller is responsible for freeing *ucp. 1342 * 1343 * return - 0 euid != 0 1344 * 1 euid == 0 1345 */ 1346 static int 1347 is_root(int free_uc, char *dc_str, ucred_t **ucp) 1348 { 1349 int rc; 1350 1351 if (door_ucred(ucp) != 0) { 1352 rc = errno; 1353 logit("door_ucred() call failed %s\n", strerror(rc)); 1354 syslog(LOG_ERR, gettext("ldap_cachemgr: door_ucred() call %s " 1355 "failed %s"), strerror(rc)); 1356 return (0); 1357 } 1358 1359 1360 if (ucred_geteuid(*ucp) != 0) { 1361 1362 if (current_admin.debug_level >= DBG_CANT_FIND) 1363 logit("%s call failed(cred): caller pid %ld, uid %u, " 1364 "euid %u (if uid or euid is %u, it may be " 1365 "unavailable)\n", dc_str, ucred_getpid(*ucp), 1366 ucred_getruid(*ucp), ucred_geteuid(*ucp), -1); 1367 1368 rc = 0; 1369 } else { 1370 1371 if (current_admin.debug_level >= DBG_ALL) 1372 logit("received %s call from pid %ld, uid %u, euid %u " 1373 "(if uid or euid is %u, it may be unavailable)\n", 1374 dc_str, ucred_getpid(*ucp), ucred_getruid(*ucp), 1375 ucred_geteuid(*ucp), -1); 1376 rc = 1; 1377 } 1378 1379 if (free_uc) 1380 ucred_free(*ucp); 1381 1382 return (rc); 1383 } 1384 1385 /* 1386 * Check if pid is nscd 1387 * 1388 * Input: pid - process id of the door client that calls ldap_cachemgr 1389 * 1390 * Return: 0 - No 1391 * 1 - Yes 1392 */ 1393 1394 int 1395 is_called_from_nscd(pid_t pid) 1396 1397 { 1398 static mutex_t _door_lock = DEFAULTMUTEX; 1399 static int doorfd = -1; 1400 int match; 1401 door_info_t my_door; 1402 1403 /* 1404 * the first time in we try and open and validate the door. 1405 * the validations are that the door must have been 1406 * created with the door cookie and 1407 * that the file attached to the door is owned by root 1408 * and readonly by user, group and other. If any of these 1409 * validations fail we refuse to use the door. 1410 */ 1411 1412 (void) mutex_lock(&_door_lock); 1413 1414 try_again: 1415 1416 if (doorfd == -1) { 1417 1418 if ((doorfd = open(NAME_SERVICE_DOOR, O_RDONLY, 0)) 1419 == -1) { 1420 (void) mutex_unlock(&_door_lock); 1421 return (0); 1422 } 1423 1424 if (door_info(doorfd, &my_door) == -1 || 1425 (my_door.di_attributes & DOOR_REVOKED) || 1426 my_door.di_data != (uintptr_t)NAME_SERVICE_DOOR_COOKIE) { 1427 /* 1428 * we should close doorfd because we just opened it 1429 */ 1430 (void) close(doorfd); 1431 doorfd = -1; 1432 (void) mutex_unlock(&_door_lock); 1433 return (0); 1434 } 1435 } else { 1436 /* 1437 * doorfd is cached. Double check just in case 1438 * the door server is restarted or is down. 1439 */ 1440 if (door_info(doorfd, &my_door) == -1 || 1441 my_door.di_data != (uintptr_t)NAME_SERVICE_DOOR_COOKIE) { 1442 /* 1443 * don't close it - 1444 * someone else has clobbered fd 1445 */ 1446 doorfd = -1; 1447 goto try_again; 1448 } 1449 1450 if (my_door.di_attributes & DOOR_REVOKED) { 1451 (void) close(doorfd); 1452 doorfd = -1; /* try and restart connection */ 1453 goto try_again; 1454 } 1455 } 1456 1457 /* 1458 * door descriptor exists and is valid 1459 */ 1460 if (pid == my_door.di_target) 1461 match = 1; 1462 else 1463 match = 0; 1464 1465 (void) mutex_unlock(&_door_lock); 1466 1467 return (match); 1468 1469 } 1470 1471 /* 1472 * new_attr(name, value) 1473 * 1474 * create a new LDAP attribute to be sent to the server 1475 */ 1476 static ns_ldap_attr_t * 1477 new_attr(char *name, char *value) 1478 { 1479 ns_ldap_attr_t *tmp; 1480 1481 tmp = malloc(sizeof (*tmp)); 1482 if (tmp != NULL) { 1483 tmp->attrname = name; 1484 tmp->attrvalue = (char **)calloc(2, sizeof (char *)); 1485 if (tmp->attrvalue == NULL) { 1486 free(tmp); 1487 return (NULL); 1488 } 1489 tmp->attrvalue[0] = value; 1490 tmp->value_count = 1; 1491 } 1492 1493 return (tmp); 1494 } 1495 1496 /* 1497 * Convert the flatten ldap attributes in a ns_ldap_attr_t back 1498 * to an ns_ldap_attr_t array. 1499 * 1500 * strlist->ldap_offsets[] contains offsets to strings: 1501 * "dn", <dn value>, <attr 1>, <attrval 1>, ... <attr n>, <attrval n> 1502 * where n is (strlist->ldap_count/2 -1). 1503 * The output ns_ldap_attr_t array has a size of (strlist->ldap_count/2) 1504 * the first (strlist->ldap_count/2 -1) contains all the attribute data, 1505 * the last one is a NULL pointer. DN will be extracted out and pointed 1506 * to by *dn. 1507 */ 1508 static ns_ldap_attr_t ** 1509 str2attrs(ldap_strlist_t *strlist, char **dn) 1510 { 1511 int c; 1512 int i; 1513 int j; 1514 ns_ldap_attr_t **ret; 1515 1516 c = strlist->ldap_count; 1517 ret = calloc(c/2, sizeof (ns_ldap_attr_t *)); 1518 if (ret == NULL) 1519 return (NULL); 1520 *dn = (char *)strlist + strlist->ldap_offsets[1]; 1521 1522 /* 1523 * skip the first 'dn'/<dn value> pair, for all other attr type/value 1524 * pairs, get pointers to the attr type (offset [i]) and attr value 1525 * (offset [i+1]) and put in ns_ldap_attr_t at ret[j] 1526 */ 1527 for (i = 2, j = 0; i < c; i = i + 2, j++) { 1528 ret[j] = new_attr((char *)strlist + strlist->ldap_offsets[i], 1529 (char *)strlist + strlist->ldap_offsets[i + 1]); 1530 } 1531 return (ret); 1532 } 1533 1534 static int 1535 get_admin_dn(ns_cred_t *credp, int *status, ns_ldap_error_t **errorp) 1536 { 1537 void **paramVal = NULL; 1538 int rc; 1539 1540 /* get bind DN for shadow update */ 1541 rc = __ns_ldap_getParam(NS_LDAP_ADMIN_BINDDN_P, 1542 ¶mVal, errorp); 1543 if (rc != NS_LDAP_SUCCESS) 1544 return (rc); 1545 1546 if (paramVal == NULL || *paramVal == NULL) { 1547 rc = NS_LDAP_CONFIG; 1548 *status = NS_CONFIG_NOTALLOW; 1549 if (paramVal != NULL) 1550 (void) __ns_ldap_freeParam(¶mVal); 1551 return (rc); 1552 } 1553 credp->cred.unix_cred.userID = strdup((char *)*paramVal); 1554 (void) __ns_ldap_freeParam(¶mVal); 1555 if (credp->cred.unix_cred.userID == NULL) 1556 return (NS_LDAP_MEMORY); 1557 1558 return (NS_LDAP_SUCCESS); 1559 } 1560 1561 /* 1562 * admin_modify() does a privileged modify within the ldap_cachemgr daemon 1563 * process using the admin DN/password configured with parameters 1564 * NS_LDAP_ADMIN_BINDDN and NS_LDAP_ADMIN_BINDPASSWD. It will only 1565 * be done if NS_LDAP_ENABLE_SHADOW_UPDATE is set to TRUE. 1566 * 1567 * The input ldap_call_t (*in) contains LDAP shadowAccount attributes to 1568 * be modified. The data is a flatten ns_ldap_attr_t arrary stored in 1569 * the strlist element of the input ldap_call_t. 1570 * The output will be in LineBuf (*config_info), an ldap_admin_mod_result_t 1571 * structure that contains error code, error status, and error message. 1572 */ 1573 static void 1574 admin_modify(LineBuf *config_info, ldap_call_t *in) 1575 { 1576 int rc = NS_LDAP_SUCCESS; 1577 int authstried = 0; 1578 int shadow_enabled = 0; 1579 char *dn = NULL; 1580 char **certpath = NULL; 1581 char **enable_shadow = NULL; 1582 ns_auth_t **app; 1583 ns_auth_t **authpp = NULL; 1584 ns_auth_t *authp = NULL; 1585 ns_cred_t *credp = NULL; 1586 char buffer[MAXERROR]; 1587 const int rlen = offsetof(ldap_admin_mod_result_t, msg); 1588 int mlen = 0; 1589 const int msgmax = MAXERROR - rlen; 1590 int status = 0; 1591 ucred_t *uc = NULL; 1592 ldap_strlist_t *strlist; 1593 ns_ldap_attr_t **attrs = NULL; 1594 ns_ldap_error_t *error = NULL; 1595 ldap_admin_mod_result_t *result; 1596 1597 (void) memset((char *)config_info, 0, sizeof (LineBuf)); 1598 1599 /* only root or an ALL privs user can do admin modify */ 1600 if (is_root_or_all_privs("ADMINMODIFY", &uc) == 0) { 1601 mlen = snprintf(buffer, msgmax, "%s", 1602 gettext("shadow update by a non-root and no ALL privilege " 1603 "user not allowed")); 1604 rc = NS_LDAP_CONFIG; 1605 goto out; 1606 } 1607 1608 /* check to see if shadow update is enabled */ 1609 rc = __ns_ldap_getParam(NS_LDAP_ENABLE_SHADOW_UPDATE_P, 1610 (void ***)&enable_shadow, &error); 1611 if (rc != NS_LDAP_SUCCESS) 1612 goto out; 1613 if (enable_shadow != NULL && *enable_shadow != NULL) { 1614 shadow_enabled = (*(int *)enable_shadow[0] == 1615 NS_LDAP_ENABLE_SHADOW_UPDATE_TRUE); 1616 } 1617 if (enable_shadow != NULL) 1618 (void) __ns_ldap_freeParam((void ***)&enable_shadow); 1619 if (shadow_enabled == 0) { 1620 rc = NS_LDAP_CONFIG; 1621 status = NS_CONFIG_NOTALLOW; 1622 mlen = snprintf(buffer, msgmax, "%s", 1623 gettext("shadow update not enabled")); 1624 goto out; 1625 } 1626 1627 /* convert attributes in string buffer into an ldap attribute array */ 1628 strlist = &in->ldap_u.strlist; 1629 attrs = str2attrs(strlist, &dn); 1630 if (attrs == NULL || *attrs == NULL || dn == NULL || *dn == '\0') { 1631 rc = NS_LDAP_INVALID_PARAM; 1632 goto out; 1633 } 1634 1635 if ((credp = (ns_cred_t *)calloc(1, sizeof (ns_cred_t))) == NULL) { 1636 rc = NS_LDAP_MEMORY; 1637 goto out; 1638 } 1639 1640 /* get host certificate path, if one is configured */ 1641 rc = __ns_ldap_getParam(NS_LDAP_HOST_CERTPATH_P, 1642 (void ***)&certpath, &error); 1643 if (rc != NS_LDAP_SUCCESS) 1644 goto out; 1645 if (certpath != NULL && *certpath != NULL) { 1646 credp->hostcertpath = strdup(*certpath); 1647 if (credp->hostcertpath == NULL) 1648 rc = NS_LDAP_MEMORY; 1649 } 1650 if (certpath != NULL) 1651 (void) __ns_ldap_freeParam((void ***)&certpath); 1652 if (rc != NS_LDAP_SUCCESS) 1653 goto out; 1654 1655 /* Load the service specific authentication method */ 1656 rc = __ns_ldap_getServiceAuthMethods("passwd-cmd", &authpp, 1657 &error); 1658 if (rc != NS_LDAP_SUCCESS) { 1659 if (credp->hostcertpath != NULL) 1660 free(credp->hostcertpath); 1661 goto out; 1662 } 1663 1664 /* 1665 * if authpp is null, there is no serviceAuthenticationMethod 1666 * try default authenticationMethod 1667 */ 1668 if (authpp == NULL) { 1669 rc = __ns_ldap_getParam(NS_LDAP_AUTH_P, (void ***)&authpp, 1670 &error); 1671 if (rc != NS_LDAP_SUCCESS) 1672 goto out; 1673 } 1674 1675 /* 1676 * if authpp is still null, then can not authenticate, syslog 1677 * error message and return error 1678 */ 1679 if (authpp == NULL) { 1680 rc = NS_LDAP_CONFIG; 1681 mlen = snprintf(buffer, msgmax, "%s", 1682 gettext("No legal LDAP authentication method configured")); 1683 goto out; 1684 } 1685 1686 /* 1687 * Walk the array and try all authentication methods in order except 1688 * for "none". 1689 */ 1690 for (app = authpp; *app; app++) { 1691 authp = *app; 1692 if (authp->type == NS_LDAP_AUTH_NONE) 1693 continue; 1694 authstried++; 1695 credp->auth.type = authp->type; 1696 credp->auth.tlstype = authp->tlstype; 1697 credp->auth.saslmech = authp->saslmech; 1698 credp->auth.saslopt = authp->saslopt; 1699 1700 /* 1701 * For GSSAPI, host credential will be used. No admin 1702 * DN is needed. For other authentication methods, 1703 * we need to set admin. 1704 */ 1705 if (credp->auth.saslmech != NS_LDAP_SASL_GSSAPI) { 1706 if ((rc = get_admin_dn(credp, &status, 1707 &error)) != NS_LDAP_SUCCESS) { 1708 if (error != NULL) 1709 goto out; 1710 if (status == NS_CONFIG_NOTALLOW) { 1711 mlen = snprintf(buffer, msgmax, "%s", 1712 gettext("Admin bind DN not " 1713 "configured")); 1714 goto out; 1715 } 1716 } 1717 } 1718 1719 rc = __ns_ldap_repAttr(NS_ADMIN_SHADOW_UPDATE, dn, 1720 (const ns_ldap_attr_t * const *)attrs, 1721 credp, 0, &error); 1722 if (rc == NS_LDAP_SUCCESS) 1723 goto out; 1724 1725 /* 1726 * Other errors might need to be added to this list, for 1727 * the current supported mechanisms this is sufficient. 1728 */ 1729 if (rc == NS_LDAP_INTERNAL && 1730 error->pwd_mgmt.status == NS_PASSWD_GOOD && 1731 (error->status == LDAP_INAPPROPRIATE_AUTH || 1732 error->status == LDAP_INVALID_CREDENTIALS)) 1733 goto out; 1734 1735 /* 1736 * If there is error related to password policy, 1737 * return it to caller. 1738 */ 1739 if (rc == NS_LDAP_INTERNAL && 1740 error->pwd_mgmt.status != NS_PASSWD_GOOD) { 1741 rc = NS_LDAP_CONFIG; 1742 status = NS_CONFIG_NOTALLOW; 1743 (void) __ns_ldap_freeError(&error); 1744 mlen = snprintf(buffer, msgmax, "%s", 1745 gettext("update failed due to " 1746 "password policy on server (%d)"), 1747 error->pwd_mgmt.status); 1748 goto out; 1749 } 1750 1751 /* we don't really care about the error, just clean it up */ 1752 if (error) 1753 (void) __ns_ldap_freeError(&error); 1754 } 1755 if (authstried == 0) { 1756 rc = NS_LDAP_CONFIG; 1757 mlen = snprintf(buffer, msgmax, "%s", 1758 gettext("No legal LDAP authentication method configured")); 1759 goto out; 1760 } 1761 1762 rc = NS_LDAP_OP_FAILED; 1763 1764 out: 1765 if (credp != NULL) 1766 (void) __ns_ldap_freeCred(&credp); 1767 1768 if (authpp != NULL) 1769 (void) __ns_ldap_freeParam((void ***)&authpp); 1770 1771 if (error != NULL) { 1772 mlen = snprintf(buffer, msgmax, "%s", error->message); 1773 status = error->status; 1774 (void) __ns_ldap_freeError(&error); 1775 } 1776 1777 if (attrs != NULL) { 1778 int i; 1779 for (i = 0; attrs[i]; i++) { 1780 free(attrs[i]->attrvalue); 1781 free(attrs[i]); 1782 } 1783 } 1784 1785 config_info->len = rlen + mlen + 1; 1786 config_info->str = malloc(config_info->len); 1787 if (config_info->str == NULL) { 1788 config_info->len = 0; 1789 return; 1790 } 1791 result = (ldap_admin_mod_result_t *)config_info->str; 1792 result->ns_err = rc; 1793 result->status = status; 1794 if (mlen != 0) { 1795 result->msg_size = mlen + 1; 1796 (void) strcpy(config_info->str + rlen, buffer); 1797 } 1798 } 1799 1800 /* 1801 * Check to see if the door client's euid is 0 or if it has ALL zone privilege. 1802 * return - 0 No or error 1803 * 1 Yes 1804 */ 1805 static int 1806 is_root_or_all_privs(char *dc_str, ucred_t **ucp) 1807 { 1808 const priv_set_t *ps; /* door client */ 1809 priv_set_t *zs; /* zone */ 1810 int rc = 0; 1811 1812 *ucp = NULL; 1813 1814 /* no more to do if door client's euid is 0 */ 1815 if (is_root(0, dc_str, ucp) == 1) { 1816 ucred_free(*ucp); 1817 return (1); 1818 } 1819 1820 /* error if couldn't get the ucred_t */ 1821 if (*ucp == NULL) 1822 return (0); 1823 1824 if ((ps = ucred_getprivset(*ucp, PRIV_EFFECTIVE)) != NULL) { 1825 zs = priv_str_to_set("zone", ",", NULL); 1826 if (priv_isequalset(ps, zs)) 1827 rc = 1; /* has all zone privs */ 1828 else { 1829 if (current_admin.debug_level >= DBG_CANT_FIND) 1830 logit("%s call failed (no all zone privs): " 1831 "caller pid %ld, uid %u, euid %u " 1832 "(if uid or euid is %u, it may " 1833 "be unavailable)\n", dc_str, 1834 ucred_getpid(*ucp), ucred_getruid(*ucp), 1835 ucred_geteuid(*ucp), -1); 1836 } 1837 priv_freeset(zs); 1838 } 1839 1840 ucred_free(*ucp); 1841 return (rc); 1842 } 1843