1cb5caa98Sdjl /* 2cb5caa98Sdjl * CDDL HEADER START 3cb5caa98Sdjl * 4cb5caa98Sdjl * The contents of this file are subject to the terms of the 5cb5caa98Sdjl * Common Development and Distribution License (the "License"). 6cb5caa98Sdjl * You may not use this file except in compliance with the License. 7cb5caa98Sdjl * 8cb5caa98Sdjl * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9cb5caa98Sdjl * or http://www.opensolaris.org/os/licensing. 10cb5caa98Sdjl * See the License for the specific language governing permissions 11cb5caa98Sdjl * and limitations under the License. 12cb5caa98Sdjl * 13cb5caa98Sdjl * When distributing Covered Code, include this CDDL HEADER in each 14cb5caa98Sdjl * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15cb5caa98Sdjl * If applicable, add the following below this CDDL HEADER, with the 16cb5caa98Sdjl * fields enclosed by brackets "[]" replaced with your own identifying 17cb5caa98Sdjl * information: Portions Copyright [yyyy] [name of copyright owner] 18cb5caa98Sdjl * 19cb5caa98Sdjl * CDDL HEADER END 20cb5caa98Sdjl */ 21cb5caa98Sdjl /* 22b57459abSJulian Pullen * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23cb5caa98Sdjl * Use is subject to license terms. 24*7d7551bcSMilan Jurik * Copyright 2012 Milan Jurik. All rights reserved. 25cb5caa98Sdjl */ 26cb5caa98Sdjl 27cb5caa98Sdjl #include <stdlib.h> 28cb5caa98Sdjl #include <alloca.h> 29cb5caa98Sdjl #include <signal.h> 30cb5caa98Sdjl #include <sys/stat.h> 31cb5caa98Sdjl #include <unistd.h> 32cb5caa98Sdjl #include <pthread.h> 33cb5caa98Sdjl #include <time.h> 34cb5caa98Sdjl #include <errno.h> 35cb5caa98Sdjl #include <door.h> 36cb5caa98Sdjl #include <zone.h> 37cb5caa98Sdjl #include <resolv.h> 38cb5caa98Sdjl #include <sys/socket.h> 39cb5caa98Sdjl #include <net/route.h> 40cb5caa98Sdjl #include <string.h> 41cb5caa98Sdjl #include <net/if.h> 42cb5caa98Sdjl #include <sys/stat.h> 43cb5caa98Sdjl #include <fcntl.h> 44cb5caa98Sdjl #include "nscd_common.h" 45cb5caa98Sdjl #include "nscd_door.h" 46cb5caa98Sdjl #include "nscd_config.h" 47cb5caa98Sdjl #include "nscd_switch.h" 48cb5caa98Sdjl #include "nscd_log.h" 49cb5caa98Sdjl #include "nscd_selfcred.h" 50cb5caa98Sdjl #include "nscd_frontend.h" 51cb5caa98Sdjl #include "nscd_admin.h" 52cb5caa98Sdjl 53cb5caa98Sdjl static void rts_mon(void); 54cb5caa98Sdjl static void keep_open_dns_socket(void); 55cb5caa98Sdjl 56cb5caa98Sdjl extern nsc_ctx_t *cache_ctx_p[]; 57cb5caa98Sdjl 58cb5caa98Sdjl /* 59cb5caa98Sdjl * Current active Configuration data for the frontend component 60cb5caa98Sdjl */ 61cb5caa98Sdjl static nscd_cfg_global_frontend_t frontend_cfg_g; 62cb5caa98Sdjl static nscd_cfg_frontend_t *frontend_cfg; 63cb5caa98Sdjl 64cb5caa98Sdjl static int max_servers = 0; 65cb5caa98Sdjl static int max_servers_set = 0; 66cb5caa98Sdjl static int per_user_is_on = 1; 67cb5caa98Sdjl 68cb5caa98Sdjl static char *main_execname; 69cb5caa98Sdjl static char **main_argv; 70cb5caa98Sdjl extern int _whoami; 71cb5caa98Sdjl extern long activity; 72cb5caa98Sdjl extern mutex_t activity_lock; 73cb5caa98Sdjl 74cb5caa98Sdjl static sema_t common_sema; 75cb5caa98Sdjl 76cb5caa98Sdjl static thread_key_t lookup_state_key; 77cb5caa98Sdjl static mutex_t create_lock = DEFAULTMUTEX; 78cb5caa98Sdjl static int num_servers = 0; 79cb5caa98Sdjl static thread_key_t server_key; 80cb5caa98Sdjl 81cb5caa98Sdjl /* 82cb5caa98Sdjl * Bind a TSD value to a server thread. This enables the destructor to 83cb5caa98Sdjl * be called if/when this thread exits. This would be a programming 84cb5caa98Sdjl * error, but better safe than sorry. 85cb5caa98Sdjl */ 86cb5caa98Sdjl /*ARGSUSED*/ 87cb5caa98Sdjl static void * 88cb5caa98Sdjl server_tsd_bind(void *arg) 89cb5caa98Sdjl { 90cb5caa98Sdjl static void *value = 0; 91cb5caa98Sdjl 92cb5caa98Sdjl /* disable cancellation to avoid hangs if server threads disappear */ 93cb5caa98Sdjl (void) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); 94cb5caa98Sdjl (void) thr_setspecific(server_key, value); 95cb5caa98Sdjl (void) door_return(NULL, 0, NULL, 0); 96cb5caa98Sdjl 97cb5caa98Sdjl /* make lint happy */ 98cb5caa98Sdjl return (NULL); 99cb5caa98Sdjl } 100cb5caa98Sdjl 101cb5caa98Sdjl /* 102cb5caa98Sdjl * Server threads are created here. 103cb5caa98Sdjl */ 104cb5caa98Sdjl /*ARGSUSED*/ 105cb5caa98Sdjl static void 106cb5caa98Sdjl server_create(door_info_t *dip) 107cb5caa98Sdjl { 108cb5caa98Sdjl (void) mutex_lock(&create_lock); 109cb5caa98Sdjl if (++num_servers > max_servers) { 110cb5caa98Sdjl num_servers--; 111cb5caa98Sdjl (void) mutex_unlock(&create_lock); 112cb5caa98Sdjl return; 113cb5caa98Sdjl } 114cb5caa98Sdjl (void) mutex_unlock(&create_lock); 115cb5caa98Sdjl (void) thr_create(NULL, 0, server_tsd_bind, NULL, 116cb5caa98Sdjl THR_BOUND|THR_DETACHED, NULL); 117cb5caa98Sdjl } 118cb5caa98Sdjl 119cb5caa98Sdjl /* 120cb5caa98Sdjl * Server thread are destroyed here 121cb5caa98Sdjl */ 122cb5caa98Sdjl /*ARGSUSED*/ 123cb5caa98Sdjl static void 124cb5caa98Sdjl server_destroy(void *arg) 125cb5caa98Sdjl { 126cb5caa98Sdjl (void) mutex_lock(&create_lock); 127cb5caa98Sdjl num_servers--; 128cb5caa98Sdjl (void) mutex_unlock(&create_lock); 129cb5caa98Sdjl } 130cb5caa98Sdjl 131cb5caa98Sdjl /* 132cb5caa98Sdjl * get clearance 133cb5caa98Sdjl */ 134cb5caa98Sdjl int 135cb5caa98Sdjl _nscd_get_clearance(sema_t *sema) { 136cb5caa98Sdjl if (sema_trywait(&common_sema) == 0) { 137cb5caa98Sdjl (void) thr_setspecific(lookup_state_key, NULL); 138cb5caa98Sdjl return (0); 139cb5caa98Sdjl } 140cb5caa98Sdjl 141cb5caa98Sdjl if (sema_trywait(sema) == 0) { 142cb5caa98Sdjl (void) thr_setspecific(lookup_state_key, (void*)1); 143cb5caa98Sdjl return (0); 144cb5caa98Sdjl } 145cb5caa98Sdjl 146cb5caa98Sdjl return (1); 147cb5caa98Sdjl } 148cb5caa98Sdjl 149cb5caa98Sdjl 150cb5caa98Sdjl /* 151cb5caa98Sdjl * release clearance 152cb5caa98Sdjl */ 153cb5caa98Sdjl int 154cb5caa98Sdjl _nscd_release_clearance(sema_t *sema) { 155cb5caa98Sdjl int which; 156cb5caa98Sdjl 157cb5caa98Sdjl (void) thr_getspecific(lookup_state_key, (void**)&which); 158cb5caa98Sdjl if (which == 0) /* from common pool */ { 159cb5caa98Sdjl (void) sema_post(&common_sema); 160cb5caa98Sdjl return (0); 161cb5caa98Sdjl } 162cb5caa98Sdjl 163cb5caa98Sdjl (void) sema_post(sema); 164cb5caa98Sdjl return (1); 165cb5caa98Sdjl } 166cb5caa98Sdjl 167cb5caa98Sdjl static void 168cb5caa98Sdjl dozip(void) 169cb5caa98Sdjl { 170cb5caa98Sdjl /* not much here */ 171cb5caa98Sdjl } 172cb5caa98Sdjl 173940a40eaSsm26363 /* 174940a40eaSsm26363 * _nscd_restart_if_cfgfile_changed() 175940a40eaSsm26363 * Restart if modification times of nsswitch.conf or resolv.conf have changed. 176940a40eaSsm26363 * 177940a40eaSsm26363 * If nsswitch.conf has changed then it is possible that sources for 178940a40eaSsm26363 * various backends have changed and therefore the current cached 179940a40eaSsm26363 * data may not be consistent with the new data sources. By 180940a40eaSsm26363 * restarting the cache will be cleared and the new configuration will 181940a40eaSsm26363 * be used. 182940a40eaSsm26363 * 183940a40eaSsm26363 * The check for resolv.conf is made as only the first call to 184940a40eaSsm26363 * res_gethostbyname() or res_getaddrbyname() causes a call to 185940a40eaSsm26363 * res_ninit() to occur which in turn parses resolv.conf. Therefore 186940a40eaSsm26363 * to benefit from changes to resolv.conf nscd must be restarted when 187940a40eaSsm26363 * resolv.conf is updated, removed or created. If res_getXbyY calls 188940a40eaSsm26363 * are removed from NSS then this check could be removed. 189940a40eaSsm26363 * 190940a40eaSsm26363 */ 19180b80bf0Smichen void 19280b80bf0Smichen _nscd_restart_if_cfgfile_changed() 193cb5caa98Sdjl { 194cb5caa98Sdjl 195cb5caa98Sdjl static mutex_t nsswitch_lock = DEFAULTMUTEX; 19680b80bf0Smichen static timestruc_t last_nsswitch_check = { 0 }; 19780b80bf0Smichen static timestruc_t last_nsswitch_modified = { 0 }; 198940a40eaSsm26363 static timestruc_t last_resolv_modified = { -1, 0 }; 19986f95553Smichen static mutex_t restarting_lock = DEFAULTMUTEX; 20086f95553Smichen static int restarting = 0; 20186f95553Smichen int restart = 0; 202cb5caa98Sdjl time_t now = time(NULL); 20380b80bf0Smichen char *me = "_nscd_restart_if_cfgfile_changed"; 204cb5caa98Sdjl 205940a40eaSsm26363 #define FLAG_RESTART_REQUIRED if (restarting == 0) {\ 206940a40eaSsm26363 (void) mutex_lock(&restarting_lock);\ 207940a40eaSsm26363 if (restarting == 0) {\ 208940a40eaSsm26363 restarting = 1;\ 209940a40eaSsm26363 restart = 1;\ 210940a40eaSsm26363 }\ 211940a40eaSsm26363 (void) mutex_unlock(&restarting_lock);\ 212940a40eaSsm26363 } 213940a40eaSsm26363 21486f95553Smichen if (restarting == 1) 21586f95553Smichen return; 21686f95553Smichen 21780b80bf0Smichen if (now - last_nsswitch_check.tv_sec < _NSC_FILE_CHECK_TIME) 218cb5caa98Sdjl return; 219cb5caa98Sdjl 220cb5caa98Sdjl (void) mutex_lock(&nsswitch_lock); 221cb5caa98Sdjl 22280b80bf0Smichen if (now - last_nsswitch_check.tv_sec >= _NSC_FILE_CHECK_TIME) { 223cb5caa98Sdjl struct stat nss_buf; 224cb5caa98Sdjl struct stat res_buf; 225cb5caa98Sdjl 22680b80bf0Smichen last_nsswitch_check.tv_sec = now; 22780b80bf0Smichen last_nsswitch_check.tv_nsec = 0; 228cb5caa98Sdjl 229cb5caa98Sdjl (void) mutex_unlock(&nsswitch_lock); /* let others continue */ 230cb5caa98Sdjl 231cb5caa98Sdjl if (stat("/etc/nsswitch.conf", &nss_buf) < 0) { 23280b80bf0Smichen return; 23380b80bf0Smichen } else if (last_nsswitch_modified.tv_sec == 0) { 23480b80bf0Smichen last_nsswitch_modified = nss_buf.st_mtim; 23580b80bf0Smichen } 236cb5caa98Sdjl 23780b80bf0Smichen if (last_nsswitch_modified.tv_sec < nss_buf.st_mtim.tv_sec || 23880b80bf0Smichen (last_nsswitch_modified.tv_sec == nss_buf.st_mtim.tv_sec && 239940a40eaSsm26363 last_nsswitch_modified.tv_nsec < nss_buf.st_mtim.tv_nsec)) { 240940a40eaSsm26363 FLAG_RESTART_REQUIRED; 24186f95553Smichen } 242940a40eaSsm26363 243940a40eaSsm26363 if (restart == 0) { 244940a40eaSsm26363 if (stat("/etc/resolv.conf", &res_buf) < 0) { 245940a40eaSsm26363 /* Unable to stat file, were we previously? */ 246940a40eaSsm26363 if (last_resolv_modified.tv_sec > 0) { 247940a40eaSsm26363 /* Yes, it must have been removed. */ 248940a40eaSsm26363 FLAG_RESTART_REQUIRED; 249940a40eaSsm26363 } else if (last_resolv_modified.tv_sec == -1) { 250940a40eaSsm26363 /* No, then we've never seen it. */ 251940a40eaSsm26363 last_resolv_modified.tv_sec = 0; 252940a40eaSsm26363 } 253940a40eaSsm26363 } else if (last_resolv_modified.tv_sec == -1) { 254940a40eaSsm26363 /* We've just started and file is present. */ 255940a40eaSsm26363 last_resolv_modified = res_buf.st_mtim; 256940a40eaSsm26363 } else if (last_resolv_modified.tv_sec == 0) { 257940a40eaSsm26363 /* Wasn't there at start-up. */ 258940a40eaSsm26363 FLAG_RESTART_REQUIRED; 259940a40eaSsm26363 } else if (last_resolv_modified.tv_sec < 260940a40eaSsm26363 res_buf.st_mtim.tv_sec || 261940a40eaSsm26363 (last_resolv_modified.tv_sec == 262940a40eaSsm26363 res_buf.st_mtim.tv_sec && 263940a40eaSsm26363 last_resolv_modified.tv_nsec < 264940a40eaSsm26363 res_buf.st_mtim.tv_nsec)) { 265940a40eaSsm26363 FLAG_RESTART_REQUIRED; 26686f95553Smichen } 26786f95553Smichen } 26886f95553Smichen 26986f95553Smichen if (restart == 1) { 270cb5caa98Sdjl char *fmri; 271cb5caa98Sdjl 272cb5caa98Sdjl /* 273cb5caa98Sdjl * if in self cred mode, kill the forker and 274cb5caa98Sdjl * child nscds 275cb5caa98Sdjl */ 276cb5caa98Sdjl if (_nscd_is_self_cred_on(0, NULL)) { 277cb5caa98Sdjl _nscd_kill_forker(); 278cb5caa98Sdjl _nscd_kill_all_children(); 279cb5caa98Sdjl } 280cb5caa98Sdjl 281cb5caa98Sdjl /* 282cb5caa98Sdjl * time for restart 283cb5caa98Sdjl */ 284cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_INFO) 285cb5caa98Sdjl (me, "nscd restart due to %s or %s change\n", 286cb5caa98Sdjl "/etc/nsswitch.conf", "resolv.conf"); 287cb5caa98Sdjl /* 288cb5caa98Sdjl * try to restart under smf 289cb5caa98Sdjl */ 290cb5caa98Sdjl if ((fmri = getenv("SMF_FMRI")) == NULL) { 291cb5caa98Sdjl /* not running under smf - reexec */ 292cb5caa98Sdjl (void) execv(main_execname, main_argv); 293cb5caa98Sdjl exit(1); /* just in case */ 294cb5caa98Sdjl } 295cb5caa98Sdjl 296cb5caa98Sdjl if (smf_restart_instance(fmri) == 0) 297cb5caa98Sdjl (void) sleep(10); /* wait a bit */ 298cb5caa98Sdjl exit(1); /* give up waiting for resurrection */ 299cb5caa98Sdjl } 300cb5caa98Sdjl 301cb5caa98Sdjl } else 302cb5caa98Sdjl (void) mutex_unlock(&nsswitch_lock); 303cb5caa98Sdjl } 304cb5caa98Sdjl 305cb5caa98Sdjl uid_t 306cb5caa98Sdjl _nscd_get_client_euid() 307cb5caa98Sdjl { 308cb5caa98Sdjl ucred_t *uc = NULL; 309cb5caa98Sdjl uid_t id; 310cb5caa98Sdjl char *me = "get_client_euid"; 311cb5caa98Sdjl 312cb5caa98Sdjl if (door_ucred(&uc) != 0) { 313cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG) 314cb5caa98Sdjl (me, "door_ucred: %s\n", strerror(errno)); 315cb5caa98Sdjl return ((uid_t)-1); 316cb5caa98Sdjl } 317cb5caa98Sdjl 318cb5caa98Sdjl id = ucred_geteuid(uc); 319cb5caa98Sdjl ucred_free(uc); 320cb5caa98Sdjl return (id); 321cb5caa98Sdjl } 322cb5caa98Sdjl 323bf1e3beeSmichen /* 324b57459abSJulian Pullen * Check to see if the door client's euid is 0 or if it has required_priv 3256392794bSMichen Chang * privilege. Return 0 if yes, -1 otherwise. 326b57459abSJulian Pullen * Supported values for required_priv are: 327b57459abSJulian Pullen * - NSCD_ALL_PRIV: for all zones privileges 328b57459abSJulian Pullen * - NSCD_READ_PRIV: for PRIV_FILE_DAC_READ privilege 329bf1e3beeSmichen */ 330bf1e3beeSmichen int 331b57459abSJulian Pullen _nscd_check_client_priv(int required_priv) 332bf1e3beeSmichen { 333bf1e3beeSmichen int rc = 0; 334bf1e3beeSmichen ucred_t *uc = NULL; 335bf1e3beeSmichen const priv_set_t *eset; 336bf1e3beeSmichen char *me = "_nscd_check_client_read_priv"; 337b57459abSJulian Pullen priv_set_t *zs; /* zone */ 338bf1e3beeSmichen 339bf1e3beeSmichen if (door_ucred(&uc) != 0) { 340bf1e3beeSmichen _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR) 341bf1e3beeSmichen (me, "door_ucred: %s\n", strerror(errno)); 342bf1e3beeSmichen return (-1); 343bf1e3beeSmichen } 3446392794bSMichen Chang 3456392794bSMichen Chang if (ucred_geteuid(uc) == 0) { 3466392794bSMichen Chang ucred_free(uc); 3476392794bSMichen Chang return (0); 3486392794bSMichen Chang } 3496392794bSMichen Chang 350bf1e3beeSmichen eset = ucred_getprivset(uc, PRIV_EFFECTIVE); 351b57459abSJulian Pullen switch (required_priv) { 352b57459abSJulian Pullen case NSCD_ALL_PRIV: 353b57459abSJulian Pullen zs = priv_str_to_set("zone", ",", NULL); 354b57459abSJulian Pullen if (!priv_isequalset(eset, zs)) { 355b57459abSJulian Pullen _NSCD_LOG(NSCD_LOG_FRONT_END, 356b57459abSJulian Pullen NSCD_LOG_LEVEL_ERROR) 357b57459abSJulian Pullen (me, "missing all zones privileges\n"); 358b57459abSJulian Pullen rc = -1; 359b57459abSJulian Pullen } 360b57459abSJulian Pullen priv_freeset(zs); 361b57459abSJulian Pullen break; 362b57459abSJulian Pullen case NSCD_READ_PRIV: 363bf1e3beeSmichen if (!priv_ismember(eset, PRIV_FILE_DAC_READ)) 364bf1e3beeSmichen rc = -1; 365b57459abSJulian Pullen break; 366b57459abSJulian Pullen default: 367b57459abSJulian Pullen _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR) 368b57459abSJulian Pullen (me, "unknown required_priv: %d\n", required_priv); 369b57459abSJulian Pullen rc = -1; 370b57459abSJulian Pullen break; 371b57459abSJulian Pullen } 372bf1e3beeSmichen ucred_free(uc); 373bf1e3beeSmichen return (rc); 374bf1e3beeSmichen } 375bf1e3beeSmichen 376cb5caa98Sdjl static void 377cb5caa98Sdjl N2N_check_priv( 378cb5caa98Sdjl void *buf, 379cb5caa98Sdjl char *dc_str) 380cb5caa98Sdjl { 381cb5caa98Sdjl nss_pheader_t *phdr = (nss_pheader_t *)buf; 382cb5caa98Sdjl ucred_t *uc = NULL; 383cb5caa98Sdjl const priv_set_t *eset; 384cb5caa98Sdjl zoneid_t zoneid; 385cb5caa98Sdjl int errnum; 386cb5caa98Sdjl char *me = "N2N_check_priv"; 387cb5caa98Sdjl 388cb5caa98Sdjl if (door_ucred(&uc) != 0) { 389cb5caa98Sdjl errnum = errno; 390cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG) 391cb5caa98Sdjl (me, "door_ucred: %s\n", strerror(errno)); 392cb5caa98Sdjl 393*7d7551bcSMilan Jurik NSCD_SET_STATUS(phdr, NSS_ERROR, errnum); 394*7d7551bcSMilan Jurik return; 395cb5caa98Sdjl } 396cb5caa98Sdjl 397cb5caa98Sdjl eset = ucred_getprivset(uc, PRIV_EFFECTIVE); 398cb5caa98Sdjl zoneid = ucred_getzoneid(uc); 399cb5caa98Sdjl 400cb5caa98Sdjl if ((zoneid != GLOBAL_ZONEID && zoneid != getzoneid()) || 401cb5caa98Sdjl eset != NULL ? !priv_ismember(eset, PRIV_SYS_ADMIN) : 402cb5caa98Sdjl ucred_geteuid(uc) != 0) { 403cb5caa98Sdjl 404cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ALERT) 405cb5caa98Sdjl (me, "%s call failed(cred): caller pid %d, uid %d, " 406cb5caa98Sdjl "euid %d, zoneid %d\n", dc_str, ucred_getpid(uc), 407cb5caa98Sdjl ucred_getruid(uc), ucred_geteuid(uc), zoneid); 408cb5caa98Sdjl ucred_free(uc); 409cb5caa98Sdjl 410*7d7551bcSMilan Jurik NSCD_SET_STATUS(phdr, NSS_ERROR, EACCES); 411*7d7551bcSMilan Jurik return; 412cb5caa98Sdjl } 413cb5caa98Sdjl 414cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG) 415cb5caa98Sdjl (me, "nscd received %s cmd from pid %d, uid %d, " 416cb5caa98Sdjl "euid %d, zoneid %d\n", dc_str, ucred_getpid(uc), 417cb5caa98Sdjl ucred_getruid(uc), ucred_geteuid(uc), zoneid); 418cb5caa98Sdjl 419cb5caa98Sdjl ucred_free(uc); 420cb5caa98Sdjl 421*7d7551bcSMilan Jurik NSCD_SET_STATUS_SUCCESS(phdr); 422cb5caa98Sdjl } 423cb5caa98Sdjl 424e37190e5Smichen void 425e37190e5Smichen _nscd_APP_check_cred( 426cb5caa98Sdjl void *buf, 427cb5caa98Sdjl pid_t *pidp, 428e37190e5Smichen char *dc_str, 429e37190e5Smichen int log_comp, 430e37190e5Smichen int log_level) 431cb5caa98Sdjl { 432cb5caa98Sdjl nss_pheader_t *phdr = (nss_pheader_t *)buf; 433cb5caa98Sdjl ucred_t *uc = NULL; 434cb5caa98Sdjl uid_t ruid; 435cb5caa98Sdjl uid_t euid; 436e37190e5Smichen pid_t pid; 437cb5caa98Sdjl int errnum; 438e37190e5Smichen char *me = "_nscd_APP_check_cred"; 439cb5caa98Sdjl 440cb5caa98Sdjl if (door_ucred(&uc) != 0) { 441cb5caa98Sdjl errnum = errno; 442e37190e5Smichen _NSCD_LOG(log_comp, NSCD_LOG_LEVEL_ERROR) 443cb5caa98Sdjl (me, "door_ucred: %s\n", strerror(errno)); 444cb5caa98Sdjl 445*7d7551bcSMilan Jurik NSCD_SET_STATUS(phdr, NSS_ERROR, errnum); 446*7d7551bcSMilan Jurik return; 447cb5caa98Sdjl } 448cb5caa98Sdjl 449e37190e5Smichen NSCD_SET_STATUS_SUCCESS(phdr); 450e37190e5Smichen pid = ucred_getpid(uc); 451cb5caa98Sdjl if (NSS_PACKED_CRED_CHECK(buf, ruid = ucred_getruid(uc), 452cb5caa98Sdjl euid = ucred_geteuid(uc))) { 453e37190e5Smichen if (pidp != NULL) { 454e37190e5Smichen if (*pidp == (pid_t)-1) 455e37190e5Smichen *pidp = pid; 456e37190e5Smichen else if (*pidp != pid) { 457e37190e5Smichen NSCD_SET_STATUS(phdr, NSS_ERROR, EACCES); 458e37190e5Smichen } 459e37190e5Smichen } 460e37190e5Smichen } else { 461e37190e5Smichen NSCD_SET_STATUS(phdr, NSS_ERROR, EACCES); 462cb5caa98Sdjl } 463cb5caa98Sdjl 464cb5caa98Sdjl ucred_free(uc); 465cb5caa98Sdjl 466e37190e5Smichen if (NSCD_STATUS_IS_NOT_OK(phdr)) { 467e37190e5Smichen _NSCD_LOG(log_comp, log_level) 468e37190e5Smichen (me, "%s call failed: caller pid %d (input pid = %d), ruid %d, " 469e37190e5Smichen "euid %d, header ruid %d, header euid %d\n", dc_str, 470e37190e5Smichen pid, (pidp != NULL) ? *pidp : -1, ruid, euid, 471e37190e5Smichen ((nss_pheader_t *)(buf))->p_ruid, 472e37190e5Smichen ((nss_pheader_t *)(buf))->p_euid); 473e37190e5Smichen } 474cb5caa98Sdjl } 475cb5caa98Sdjl 476606f6aa3Smichen /* log error and return -1 when an invalid packed buffer header is found */ 477606f6aa3Smichen static int 478606f6aa3Smichen pheader_error(nss_pheader_t *phdr, uint32_t call_number) 479606f6aa3Smichen { 480606f6aa3Smichen char *call_num_str; 481606f6aa3Smichen 482606f6aa3Smichen switch (call_number) { 483606f6aa3Smichen case NSCD_SEARCH: 484606f6aa3Smichen call_num_str = "NSCD_SEARCH"; 485606f6aa3Smichen break; 486606f6aa3Smichen case NSCD_SETENT: 487606f6aa3Smichen call_num_str = "NSCD_SETENT"; 488606f6aa3Smichen break; 489606f6aa3Smichen case NSCD_GETENT: 490606f6aa3Smichen call_num_str = "NSCD_GETENT"; 491606f6aa3Smichen break; 492606f6aa3Smichen case NSCD_ENDENT: 493606f6aa3Smichen call_num_str = "NSCD_ENDENT"; 494606f6aa3Smichen break; 495606f6aa3Smichen case NSCD_PUT: 496606f6aa3Smichen call_num_str = "NSCD_PUT"; 497606f6aa3Smichen break; 498606f6aa3Smichen case NSCD_GETHINTS: 499606f6aa3Smichen call_num_str = "NSCD_GETHINTS"; 500606f6aa3Smichen break; 501606f6aa3Smichen default: 502606f6aa3Smichen call_num_str = "UNKNOWN"; 503606f6aa3Smichen break; 504606f6aa3Smichen } 505606f6aa3Smichen 506606f6aa3Smichen _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ALERT) 507606f6aa3Smichen ("pheader_error", "call number %s: invalid packed buffer header\n", 508606f6aa3Smichen call_num_str); 509606f6aa3Smichen 510606f6aa3Smichen NSCD_SET_STATUS(phdr, NSS_ERROR, EINVAL); 511606f6aa3Smichen return (-1); 512606f6aa3Smichen } 513606f6aa3Smichen 514606f6aa3Smichen /* 515606f6aa3Smichen * Validate the header of a getXbyY or setent/getent/endent request. 516606f6aa3Smichen * Return 0 if good, -1 otherwise. 517606f6aa3Smichen * 518606f6aa3Smichen * A valid header looks like the following (size is arg_size, does 519606f6aa3Smichen * not include the output area): 520606f6aa3Smichen * +----------------------------------+ -- 521606f6aa3Smichen * | nss_pheader_t (header fixed part)| ^ 522606f6aa3Smichen * | | | 523606f6aa3Smichen * | pbufsiz, dbd,off, key_off, | len = sizeof(nss_pheader_t) 524606f6aa3Smichen * | data_off .... | | 525606f6aa3Smichen * | | v 526606f6aa3Smichen * +----------------------------------+ <----- dbd_off 527606f6aa3Smichen * | dbd (database description) | ^ 528606f6aa3Smichen * | nss_dbd_t + up to 3 strings | | 529606f6aa3Smichen * | length = sizeof(nss_dbd_t) + | len = key_off - dbd_off 530606f6aa3Smichen * | length of 3 strings + | | 531606f6aa3Smichen * | length of padding | | 532606f6aa3Smichen * | (total length in multiple of 4) | v 533606f6aa3Smichen * +----------------------------------+ <----- key_off 534606f6aa3Smichen * | lookup key | ^ 535606f6aa3Smichen * | nss_XbyY_key_t, content varies, | | 536606f6aa3Smichen * | based on database and lookup op | len = data_off - key_off 537606f6aa3Smichen * | length = data_off - key_off | | 538606f6aa3Smichen * | including padding, multiple of 4 | v 539606f6aa3Smichen * +----------------------------------+ <----- data_off (= arg_size) 540606f6aa3Smichen * | | ^ 541606f6aa3Smichen * | area to hold results | | 542606f6aa3Smichen * | | len = data_len (= pbufsiz - 543606f6aa3Smichen * | | | data_off) 544606f6aa3Smichen * | | v 545606f6aa3Smichen * +----------------------------------+ <----- pbufsiz 546606f6aa3Smichen */ 547606f6aa3Smichen static int 548606f6aa3Smichen validate_pheader( 549606f6aa3Smichen void *argp, 550606f6aa3Smichen size_t arg_size, 551606f6aa3Smichen uint32_t call_number) 552606f6aa3Smichen { 553606f6aa3Smichen nss_pheader_t *phdr = (nss_pheader_t *)(void *)argp; 554606f6aa3Smichen nssuint_t l1, l2; 555606f6aa3Smichen 556606f6aa3Smichen /* 557606f6aa3Smichen * current version is NSCD_HEADER_REV, length of the fixed part 558606f6aa3Smichen * of the header must match the size of nss_pheader_t 559606f6aa3Smichen */ 560606f6aa3Smichen if (phdr->p_version != NSCD_HEADER_REV || 561606f6aa3Smichen phdr->dbd_off != sizeof (nss_pheader_t)) 562606f6aa3Smichen return (pheader_error(phdr, call_number)); 563606f6aa3Smichen 564606f6aa3Smichen /* 565606f6aa3Smichen * buffer size and offsets must be in multiple of 4 566606f6aa3Smichen */ 567606f6aa3Smichen if ((arg_size & 3) || (phdr->dbd_off & 3) || (phdr->key_off & 3) || 568606f6aa3Smichen (phdr->data_off & 3)) 569606f6aa3Smichen return (pheader_error(phdr, call_number)); 570606f6aa3Smichen 571606f6aa3Smichen /* 572606f6aa3Smichen * the input arg_size is the length of the request header 573606f6aa3Smichen * and should be less than NSCD_PHDR_MAXLEN 574606f6aa3Smichen */ 575606f6aa3Smichen if (phdr->data_off != arg_size || arg_size > NSCD_PHDR_MAXLEN) 576606f6aa3Smichen return (pheader_error(phdr, call_number)); 577606f6aa3Smichen 578606f6aa3Smichen /* get length of the dbd area */ 579606f6aa3Smichen l1 = phdr->key_off - phdr-> dbd_off; 580606f6aa3Smichen 581606f6aa3Smichen /* 582606f6aa3Smichen * dbd area may contain padding, so length of dbd should 583606f6aa3Smichen * not be less than the length of the actual data 584606f6aa3Smichen */ 585606f6aa3Smichen if (l1 < phdr->dbd_len) 586606f6aa3Smichen return (pheader_error(phdr, call_number)); 587606f6aa3Smichen 588606f6aa3Smichen /* get length of the key area */ 589606f6aa3Smichen l2 = phdr->data_off - phdr->key_off; 590606f6aa3Smichen 591606f6aa3Smichen /* 592606f6aa3Smichen * key area may contain padding, so length of key area should 593606f6aa3Smichen * not be less than the length of the actual data 594606f6aa3Smichen */ 595606f6aa3Smichen if (l2 < phdr->key_len) 596606f6aa3Smichen return (pheader_error(phdr, call_number)); 597606f6aa3Smichen 598606f6aa3Smichen /* 599606f6aa3Smichen * length of fixed part + lengths of dbd and key area = length of 600606f6aa3Smichen * the request header 601606f6aa3Smichen */ 602606f6aa3Smichen if (sizeof (nss_pheader_t) + l1 + l2 != phdr->data_off) 603606f6aa3Smichen return (pheader_error(phdr, call_number)); 604606f6aa3Smichen 605606f6aa3Smichen /* header length + data length = buffer length */ 606606f6aa3Smichen if (phdr->data_off + phdr->data_len != phdr->pbufsiz) 607606f6aa3Smichen return (pheader_error(phdr, call_number)); 608606f6aa3Smichen 609606f6aa3Smichen return (0); 610606f6aa3Smichen } 611606f6aa3Smichen 612606f6aa3Smichen /* log error and return -1 when an invalid nscd to nscd buffer is found */ 613606f6aa3Smichen static int 614606f6aa3Smichen N2Nbuf_error(nss_pheader_t *phdr, uint32_t call_number) 615606f6aa3Smichen { 616606f6aa3Smichen char *call_num_str; 617606f6aa3Smichen 618606f6aa3Smichen switch (call_number) { 619606f6aa3Smichen case NSCD_PING: 620606f6aa3Smichen call_num_str = "NSCD_PING"; 621606f6aa3Smichen break; 622606f6aa3Smichen 623606f6aa3Smichen case NSCD_IMHERE: 624606f6aa3Smichen call_num_str = "NSCD_IMHERE"; 625606f6aa3Smichen break; 626606f6aa3Smichen 627606f6aa3Smichen case NSCD_PULSE: 628606f6aa3Smichen call_num_str = "NSCD_PULSE"; 629606f6aa3Smichen break; 630606f6aa3Smichen 631606f6aa3Smichen case NSCD_FORK: 632606f6aa3Smichen call_num_str = "NSCD_FORK"; 633606f6aa3Smichen break; 634606f6aa3Smichen 635606f6aa3Smichen case NSCD_KILL: 636606f6aa3Smichen call_num_str = "NSCD_KILL"; 637606f6aa3Smichen break; 638606f6aa3Smichen 639606f6aa3Smichen case NSCD_REFRESH: 640606f6aa3Smichen call_num_str = "NSCD_REFRESH"; 641606f6aa3Smichen break; 642606f6aa3Smichen 643606f6aa3Smichen case NSCD_GETPUADMIN: 644606f6aa3Smichen call_num_str = "NSCD_GETPUADMIN"; 645606f6aa3Smichen break; 646606f6aa3Smichen 647606f6aa3Smichen case NSCD_GETADMIN: 648606f6aa3Smichen call_num_str = "NSCD_GETADMIN"; 649606f6aa3Smichen break; 650606f6aa3Smichen 651606f6aa3Smichen case NSCD_SETADMIN: 652606f6aa3Smichen call_num_str = "NSCD_SETADMIN"; 653606f6aa3Smichen break; 654606f6aa3Smichen 655606f6aa3Smichen case NSCD_KILLSERVER: 656606f6aa3Smichen call_num_str = "NSCD_KILLSERVER"; 657606f6aa3Smichen break; 658606f6aa3Smichen default: 659606f6aa3Smichen call_num_str = "UNKNOWN"; 660606f6aa3Smichen break; 661606f6aa3Smichen } 662606f6aa3Smichen 663606f6aa3Smichen _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ALERT) 664bf1e3beeSmichen ("N2Nbuf_error", "call number %s: invalid N2N buffer\n", call_num_str); 665606f6aa3Smichen 666606f6aa3Smichen NSCD_SET_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0, 667606f6aa3Smichen NSCD_DOOR_BUFFER_CHECK_FAILED); 668606f6aa3Smichen 669606f6aa3Smichen return (-1); 670606f6aa3Smichen } 671606f6aa3Smichen 672606f6aa3Smichen /* 673606f6aa3Smichen * Validate the buffer of an nscd to nscd request. 674606f6aa3Smichen * Return 0 if good, -1 otherwise. 675606f6aa3Smichen * 676606f6aa3Smichen * A valid buffer looks like the following (size is arg_size): 677606f6aa3Smichen * +----------------------------------+ -- 678606f6aa3Smichen * | nss_pheader_t (header fixed part)| ^ 679606f6aa3Smichen * | | | 680606f6aa3Smichen * | pbufsiz, dbd,off, key_off, | len = sizeof(nss_pheader_t) 681606f6aa3Smichen * | data_off .... | | 682606f6aa3Smichen * | | v 683606f6aa3Smichen * +----------------------------------+ <---dbd_off = key_off = data_off 684606f6aa3Smichen * | | ^ 685606f6aa3Smichen * | input data/output data | | 686606f6aa3Smichen * | OR no data | len = data_len (= pbufsiz - 687606f6aa3Smichen * | | | data_off) 688606f6aa3Smichen * | | | len could be zero 689606f6aa3Smichen * | | v 690606f6aa3Smichen * +----------------------------------+ <--- pbufsiz 691606f6aa3Smichen */ 692606f6aa3Smichen static int 693606f6aa3Smichen validate_N2Nbuf( 694606f6aa3Smichen void *argp, 695606f6aa3Smichen size_t arg_size, 696606f6aa3Smichen uint32_t call_number) 697606f6aa3Smichen { 698606f6aa3Smichen nss_pheader_t *phdr = (nss_pheader_t *)(void *)argp; 699606f6aa3Smichen 700606f6aa3Smichen /* 701606f6aa3Smichen * current version is NSCD_HEADER_REV, length of the fixed part 702606f6aa3Smichen * of the header must match the size of nss_pheader_t 703606f6aa3Smichen */ 704606f6aa3Smichen if (phdr->p_version != NSCD_HEADER_REV || 705606f6aa3Smichen phdr->dbd_off != sizeof (nss_pheader_t)) 706606f6aa3Smichen return (N2Nbuf_error(phdr, call_number)); 707606f6aa3Smichen 708606f6aa3Smichen /* 709606f6aa3Smichen * There are no dbd and key data, so the dbd, key, data 710606f6aa3Smichen * offsets should be equal 711606f6aa3Smichen */ 712606f6aa3Smichen if (phdr->dbd_off != phdr->key_off || 713606f6aa3Smichen phdr->dbd_off != phdr->data_off) 714606f6aa3Smichen return (N2Nbuf_error(phdr, call_number)); 715606f6aa3Smichen 716606f6aa3Smichen /* 717606f6aa3Smichen * the input arg_size is the buffer length and should 718606f6aa3Smichen * be less or equal than NSCD_N2NBUF_MAXLEN 719606f6aa3Smichen */ 720606f6aa3Smichen if (phdr->pbufsiz != arg_size || arg_size > NSCD_N2NBUF_MAXLEN) 721606f6aa3Smichen return (N2Nbuf_error(phdr, call_number)); 722606f6aa3Smichen 723606f6aa3Smichen /* header length + data length = buffer length */ 724606f6aa3Smichen if (phdr->data_off + phdr->data_len != phdr->pbufsiz) 725606f6aa3Smichen return (N2Nbuf_error(phdr, call_number)); 726606f6aa3Smichen 727606f6aa3Smichen return (0); 728606f6aa3Smichen } 729606f6aa3Smichen 730cb5caa98Sdjl static void 731cb5caa98Sdjl lookup(char *argp, size_t arg_size) 732cb5caa98Sdjl { 733cb5caa98Sdjl nsc_lookup_args_t largs; 734cb5caa98Sdjl char space[NSCD_LOOKUP_BUFSIZE]; 735cb5caa98Sdjl nss_pheader_t *phdr = (nss_pheader_t *)(void *)argp; 736cb5caa98Sdjl 737cb5caa98Sdjl NSCD_ALLOC_LOOKUP_BUFFER(argp, arg_size, phdr, space, 738cb5caa98Sdjl sizeof (space)); 739cb5caa98Sdjl 740606f6aa3Smichen /* 741606f6aa3Smichen * make sure the first couple bytes of the data area is null, 742606f6aa3Smichen * so that bad strings in the packed header stop here 743606f6aa3Smichen */ 744606f6aa3Smichen (void) memset((char *)phdr + phdr->data_off, 0, 16); 745606f6aa3Smichen 746cb5caa98Sdjl (void) memset(&largs, 0, sizeof (largs)); 747cb5caa98Sdjl largs.buffer = argp; 748cb5caa98Sdjl largs.bufsize = arg_size; 749cb5caa98Sdjl nsc_lookup(&largs, 0); 750cb5caa98Sdjl 751cb5caa98Sdjl /* 752cb5caa98Sdjl * only the PUN needs to keep track of the 753cb5caa98Sdjl * activity count to determine when to 754cb5caa98Sdjl * terminate itself 755cb5caa98Sdjl */ 756cb5caa98Sdjl if (_whoami == NSCD_CHILD) { 757cb5caa98Sdjl (void) mutex_lock(&activity_lock); 758cb5caa98Sdjl ++activity; 759cb5caa98Sdjl (void) mutex_unlock(&activity_lock); 760cb5caa98Sdjl } 761cb5caa98Sdjl 762cb5caa98Sdjl NSCD_SET_RETURN_ARG(phdr, arg_size); 763cb5caa98Sdjl (void) door_return(argp, arg_size, NULL, 0); 764cb5caa98Sdjl } 765cb5caa98Sdjl 766cb5caa98Sdjl static void 767cb5caa98Sdjl getent(char *argp, size_t arg_size) 768cb5caa98Sdjl { 769cb5caa98Sdjl char space[NSCD_LOOKUP_BUFSIZE]; 770cb5caa98Sdjl nss_pheader_t *phdr = (nss_pheader_t *)(void *)argp; 771cb5caa98Sdjl 772bf1e3beeSmichen NSCD_ALLOC_LOOKUP_BUFFER(argp, arg_size, phdr, space, sizeof (space)); 773cb5caa98Sdjl 774cb5caa98Sdjl nss_pgetent(argp, arg_size); 775cb5caa98Sdjl 776cb5caa98Sdjl NSCD_SET_RETURN_ARG(phdr, arg_size); 777cb5caa98Sdjl (void) door_return(argp, arg_size, NULL, 0); 778cb5caa98Sdjl } 779cb5caa98Sdjl 780cb5caa98Sdjl static int 781cb5caa98Sdjl is_db_per_user(void *buf, char *dblist) 782cb5caa98Sdjl { 783cb5caa98Sdjl nss_pheader_t *phdr = (nss_pheader_t *)buf; 784cb5caa98Sdjl nss_dbd_t *pdbd; 785cb5caa98Sdjl char *dbname, *dbn; 786cb5caa98Sdjl int len; 787cb5caa98Sdjl 788cb5caa98Sdjl /* copy db name into a temp buffer */ 789cb5caa98Sdjl pdbd = (nss_dbd_t *)((void *)((char *)buf + phdr->dbd_off)); 790cb5caa98Sdjl dbname = (char *)pdbd + pdbd->o_name; 791cb5caa98Sdjl len = strlen(dbname); 792cb5caa98Sdjl dbn = alloca(len + 2); 793cb5caa98Sdjl (void) memcpy(dbn, dbname, len); 794cb5caa98Sdjl 795cb5caa98Sdjl /* check if <dbname> + ',' can be found in the dblist string */ 796cb5caa98Sdjl dbn[len] = ','; 797cb5caa98Sdjl dbn[len + 1] = '\0'; 798cb5caa98Sdjl if (strstr(dblist, dbn) != NULL) 799cb5caa98Sdjl return (1); 800cb5caa98Sdjl 801cb5caa98Sdjl /* 802cb5caa98Sdjl * check if <dbname> can be found in the last part 803cb5caa98Sdjl * of the dblist string 804cb5caa98Sdjl */ 805cb5caa98Sdjl dbn[len] = '\0'; 806cb5caa98Sdjl if (strstr(dblist, dbn) != NULL) 807cb5caa98Sdjl return (1); 808cb5caa98Sdjl 809cb5caa98Sdjl return (0); 810cb5caa98Sdjl } 811cb5caa98Sdjl 812cb5caa98Sdjl /* 813cb5caa98Sdjl * Check to see if all conditions are met for processing per-user 814cb5caa98Sdjl * requests. Returns 1 if yes, -1 if backend is not configured, 815cb5caa98Sdjl * 0 otherwise. 816cb5caa98Sdjl */ 817cb5caa98Sdjl static int 818cb5caa98Sdjl need_per_user_door(void *buf, int whoami, uid_t uid, char **dblist) 819cb5caa98Sdjl { 820cb5caa98Sdjl nss_pheader_t *phdr = (nss_pheader_t *)buf; 821cb5caa98Sdjl 822cb5caa98Sdjl NSCD_SET_STATUS_SUCCESS(phdr); 823cb5caa98Sdjl 824cb5caa98Sdjl /* if already a per-user nscd, no need to get per-user door */ 825cb5caa98Sdjl if (whoami == NSCD_CHILD) 826cb5caa98Sdjl return (0); 827cb5caa98Sdjl 828cb5caa98Sdjl /* forker shouldn't be asked */ 829cb5caa98Sdjl if (whoami == NSCD_FORKER) { 830cb5caa98Sdjl NSCD_SET_STATUS(phdr, NSS_ERROR, ENOTSUP); 831cb5caa98Sdjl return (0); 832cb5caa98Sdjl } 833cb5caa98Sdjl 834cb5caa98Sdjl /* if door client is root, no need for a per-user door */ 835cb5caa98Sdjl if (uid == 0) 836cb5caa98Sdjl return (0); 837cb5caa98Sdjl 838cb5caa98Sdjl /* 839cb5caa98Sdjl * if per-user lookup is not configured, no per-user 840cb5caa98Sdjl * door available 841cb5caa98Sdjl */ 842cb5caa98Sdjl if (_nscd_is_self_cred_on(0, dblist) == 0) 843cb5caa98Sdjl return (-1); 844cb5caa98Sdjl 845cb5caa98Sdjl /* 846cb5caa98Sdjl * if per-user lookup is not configured for the db, 847cb5caa98Sdjl * don't bother 848cb5caa98Sdjl */ 849cb5caa98Sdjl if (is_db_per_user(phdr, *dblist) == 0) 850cb5caa98Sdjl return (0); 851cb5caa98Sdjl 852cb5caa98Sdjl return (1); 853cb5caa98Sdjl } 854cb5caa98Sdjl 855cb5caa98Sdjl static void 856cb5caa98Sdjl if_selfcred_return_per_user_door(char *argp, size_t arg_size, 857cb5caa98Sdjl door_desc_t *dp, int whoami) 858cb5caa98Sdjl { 859cb5caa98Sdjl nss_pheader_t *phdr = (nss_pheader_t *)((void *)argp); 860cb5caa98Sdjl char *dblist; 861cb5caa98Sdjl int door = -1; 862cb5caa98Sdjl int rc = 0; 863cb5caa98Sdjl door_desc_t desc; 864606f6aa3Smichen char *space; 865606f6aa3Smichen int len; 866cb5caa98Sdjl 867cb5caa98Sdjl /* 868cb5caa98Sdjl * check to see if self-cred is configured and 869cb5caa98Sdjl * need to return an alternate PUN door 870cb5caa98Sdjl */ 871cb5caa98Sdjl if (per_user_is_on == 1) { 872cb5caa98Sdjl rc = need_per_user_door(argp, whoami, 873cb5caa98Sdjl _nscd_get_client_euid(), &dblist); 874cb5caa98Sdjl if (rc == -1) 875cb5caa98Sdjl per_user_is_on = 0; 876cb5caa98Sdjl } 877cb5caa98Sdjl if (rc <= 0) { 878cb5caa98Sdjl /* 879cb5caa98Sdjl * self-cred not configured, and no error detected, 880cb5caa98Sdjl * return to continue the door call processing 881cb5caa98Sdjl */ 882cb5caa98Sdjl if (NSCD_STATUS_IS_OK(phdr)) 883cb5caa98Sdjl return; 884cb5caa98Sdjl else 885cb5caa98Sdjl /* 886cb5caa98Sdjl * configured but error detected, 887cb5caa98Sdjl * stop the door call processing 888cb5caa98Sdjl */ 889cb5caa98Sdjl (void) door_return(argp, phdr->data_off, NULL, 0); 890cb5caa98Sdjl } 891cb5caa98Sdjl 892cb5caa98Sdjl /* get the alternate PUN door */ 893cb5caa98Sdjl _nscd_proc_alt_get(argp, &door); 894cb5caa98Sdjl if (NSCD_GET_STATUS(phdr) != NSS_ALTRETRY) { 895cb5caa98Sdjl (void) door_return(argp, phdr->data_off, NULL, 0); 896cb5caa98Sdjl } 897cb5caa98Sdjl 898cb5caa98Sdjl /* return the alternate door descriptor */ 899606f6aa3Smichen len = strlen(dblist) + 1; 900606f6aa3Smichen space = alloca(arg_size + len); 901606f6aa3Smichen phdr->data_len = len; 902606f6aa3Smichen (void) memcpy(space, phdr, arg_size); 903606f6aa3Smichen (void) strncpy((char *)space + arg_size, dblist, len); 904cb5caa98Sdjl dp = &desc; 905cb5caa98Sdjl dp->d_attributes = DOOR_DESCRIPTOR; 906cb5caa98Sdjl dp->d_data.d_desc.d_descriptor = door; 907606f6aa3Smichen arg_size += len; 908606f6aa3Smichen (void) door_return(space, arg_size, dp, 1); 909cb5caa98Sdjl } 910cb5caa98Sdjl 911cb5caa98Sdjl /*ARGSUSED*/ 912cb5caa98Sdjl static void 913cb5caa98Sdjl switcher(void *cookie, char *argp, size_t arg_size, 914cb5caa98Sdjl door_desc_t *dp, uint_t n_desc) 915cb5caa98Sdjl { 916cb5caa98Sdjl int iam; 917cb5caa98Sdjl pid_t ent_pid = -1; 918cb5caa98Sdjl nss_pheader_t *phdr = (nss_pheader_t *)((void *)argp); 919cb5caa98Sdjl void *uptr; 920606f6aa3Smichen int len; 921606f6aa3Smichen size_t buflen; 922cb5caa98Sdjl int callnum; 923cb5caa98Sdjl char *me = "switcher"; 924cb5caa98Sdjl 925cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG) 926cb5caa98Sdjl (me, "switcher ...\n"); 927cb5caa98Sdjl 928cb5caa98Sdjl if (argp == DOOR_UNREF_DATA) { 929cb5caa98Sdjl (void) printf("Door Slam... exiting\n"); 930cb5caa98Sdjl exit(0); 931cb5caa98Sdjl } 932cb5caa98Sdjl 933cb5caa98Sdjl if (argp == NULL) { /* empty door call */ 934cb5caa98Sdjl (void) door_return(NULL, 0, 0, 0); /* return the favor */ 935cb5caa98Sdjl } 936cb5caa98Sdjl 937cb5caa98Sdjl /* 938cb5caa98Sdjl * need to restart if main nscd and config file(s) changed 939cb5caa98Sdjl */ 940cb5caa98Sdjl if (_whoami == NSCD_MAIN) 94180b80bf0Smichen _nscd_restart_if_cfgfile_changed(); 942cb5caa98Sdjl 943cb5caa98Sdjl if ((phdr->nsc_callnumber & NSCDV2CATMASK) == NSCD_CALLCAT_APP) { 944606f6aa3Smichen 945606f6aa3Smichen /* make sure the packed buffer header is good */ 946606f6aa3Smichen if (validate_pheader(argp, arg_size, 947606f6aa3Smichen phdr->nsc_callnumber) == -1) 948606f6aa3Smichen (void) door_return(argp, arg_size, NULL, 0); 949606f6aa3Smichen 950cb5caa98Sdjl switch (phdr->nsc_callnumber) { 951606f6aa3Smichen 952cb5caa98Sdjl case NSCD_SEARCH: 953cb5caa98Sdjl 954cb5caa98Sdjl /* if a fallback to main nscd, skip per-user setup */ 955cb5caa98Sdjl if (phdr->p_status != NSS_ALTRETRY) 956cb5caa98Sdjl if_selfcred_return_per_user_door(argp, arg_size, 957cb5caa98Sdjl dp, _whoami); 958cb5caa98Sdjl lookup(argp, arg_size); 959cb5caa98Sdjl 960cb5caa98Sdjl break; 961cb5caa98Sdjl 962cb5caa98Sdjl case NSCD_SETENT: 963cb5caa98Sdjl 964e37190e5Smichen _nscd_APP_check_cred(argp, &ent_pid, "NSCD_SETENT", 965e37190e5Smichen NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ALERT); 966cb5caa98Sdjl if (NSCD_STATUS_IS_OK(phdr)) { 967cb5caa98Sdjl if_selfcred_return_per_user_door(argp, arg_size, 968cb5caa98Sdjl dp, _whoami); 969cb5caa98Sdjl nss_psetent(argp, arg_size, ent_pid); 970cb5caa98Sdjl } 971cb5caa98Sdjl break; 972cb5caa98Sdjl 973cb5caa98Sdjl case NSCD_GETENT: 974cb5caa98Sdjl 975cb5caa98Sdjl getent(argp, arg_size); 976cb5caa98Sdjl break; 977cb5caa98Sdjl 978cb5caa98Sdjl case NSCD_ENDENT: 979cb5caa98Sdjl 980cb5caa98Sdjl nss_pendent(argp, arg_size); 981cb5caa98Sdjl break; 982cb5caa98Sdjl 983cb5caa98Sdjl case NSCD_PUT: 984cb5caa98Sdjl 985cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR) 986cb5caa98Sdjl (me, "door call NSCD_PUT not supported yet\n"); 987cb5caa98Sdjl 988cb5caa98Sdjl NSCD_SET_STATUS(phdr, NSS_ERROR, ENOTSUP); 989cb5caa98Sdjl break; 990cb5caa98Sdjl 991cb5caa98Sdjl case NSCD_GETHINTS: 992cb5caa98Sdjl 993cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR) 994cb5caa98Sdjl (me, "door call NSCD_GETHINTS not supported yet\n"); 995cb5caa98Sdjl 996cb5caa98Sdjl NSCD_SET_STATUS(phdr, NSS_ERROR, ENOTSUP); 997cb5caa98Sdjl break; 998cb5caa98Sdjl 999cb5caa98Sdjl default: 1000cb5caa98Sdjl 1001cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR) 1002cb5caa98Sdjl (me, "Unknown name service door call op %x\n", 1003cb5caa98Sdjl phdr->nsc_callnumber); 1004cb5caa98Sdjl 1005cb5caa98Sdjl NSCD_SET_STATUS(phdr, NSS_ERROR, EINVAL); 1006cb5caa98Sdjl break; 1007cb5caa98Sdjl } 1008cb5caa98Sdjl 1009cb5caa98Sdjl (void) door_return(argp, arg_size, NULL, 0); 1010cb5caa98Sdjl } 1011cb5caa98Sdjl 1012cb5caa98Sdjl iam = NSCD_MAIN; 1013cb5caa98Sdjl callnum = phdr->nsc_callnumber & ~NSCD_WHOAMI; 1014cb5caa98Sdjl if (callnum == NSCD_IMHERE || 1015cb5caa98Sdjl callnum == NSCD_PULSE || callnum == NSCD_FORK) 1016cb5caa98Sdjl iam = phdr->nsc_callnumber & NSCD_WHOAMI; 1017cb5caa98Sdjl else 1018cb5caa98Sdjl callnum = phdr->nsc_callnumber; 1019cb5caa98Sdjl 1020cb5caa98Sdjl /* nscd -> nscd v2 calls */ 1021606f6aa3Smichen 1022606f6aa3Smichen /* make sure the buffer is good */ 1023606f6aa3Smichen if (validate_N2Nbuf(argp, arg_size, callnum) == -1) 1024606f6aa3Smichen (void) door_return(argp, arg_size, NULL, 0); 1025606f6aa3Smichen 1026cb5caa98Sdjl switch (callnum) { 1027cb5caa98Sdjl 1028cb5caa98Sdjl case NSCD_PING: 1029cb5caa98Sdjl NSCD_SET_STATUS_SUCCESS(phdr); 1030cb5caa98Sdjl break; 1031cb5caa98Sdjl 1032cb5caa98Sdjl case NSCD_IMHERE: 1033cb5caa98Sdjl _nscd_proc_iamhere(argp, dp, n_desc, iam); 1034cb5caa98Sdjl break; 1035cb5caa98Sdjl 1036cb5caa98Sdjl case NSCD_PULSE: 1037cb5caa98Sdjl N2N_check_priv(argp, "NSCD_PULSE"); 1038cb5caa98Sdjl if (NSCD_STATUS_IS_OK(phdr)) 1039cb5caa98Sdjl _nscd_proc_pulse(argp, iam); 1040cb5caa98Sdjl break; 1041cb5caa98Sdjl 1042cb5caa98Sdjl case NSCD_FORK: 1043cb5caa98Sdjl N2N_check_priv(argp, "NSCD_FORK"); 1044cb5caa98Sdjl if (NSCD_STATUS_IS_OK(phdr)) 1045cb5caa98Sdjl _nscd_proc_fork(argp, iam); 1046cb5caa98Sdjl break; 1047cb5caa98Sdjl 1048cb5caa98Sdjl case NSCD_KILL: 1049cb5caa98Sdjl N2N_check_priv(argp, "NSCD_KILL"); 1050cb5caa98Sdjl if (NSCD_STATUS_IS_OK(phdr)) 1051cb5caa98Sdjl exit(0); 1052cb5caa98Sdjl break; 1053cb5caa98Sdjl 1054cb5caa98Sdjl case NSCD_REFRESH: 1055606f6aa3Smichen N2N_check_priv(argp, "NSCD_REFRESH"); 1056606f6aa3Smichen if (NSCD_STATUS_IS_OK(phdr)) { 1057cb5caa98Sdjl if (_nscd_refresh() != NSCD_SUCCESS) 1058cb5caa98Sdjl exit(1); 1059cb5caa98Sdjl NSCD_SET_STATUS_SUCCESS(phdr); 1060606f6aa3Smichen } 1061cb5caa98Sdjl break; 1062cb5caa98Sdjl 1063cb5caa98Sdjl case NSCD_GETPUADMIN: 1064cb5caa98Sdjl 1065cb5caa98Sdjl if (_nscd_is_self_cred_on(0, NULL)) { 1066cb5caa98Sdjl _nscd_peruser_getadmin(argp, sizeof (nscd_admin_t)); 1067cb5caa98Sdjl } else { 1068cb5caa98Sdjl NSCD_SET_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0, 1069cb5caa98Sdjl NSCD_SELF_CRED_NOT_CONFIGURED); 1070cb5caa98Sdjl } 1071cb5caa98Sdjl break; 1072cb5caa98Sdjl 1073cb5caa98Sdjl case NSCD_GETADMIN: 1074cb5caa98Sdjl 1075cb5caa98Sdjl len = _nscd_door_getadmin((void *)argp); 1076cb5caa98Sdjl if (len == 0) 1077cb5caa98Sdjl break; 1078cb5caa98Sdjl 1079cb5caa98Sdjl /* size of door buffer not big enough, allocate one */ 1080cb5caa98Sdjl NSCD_ALLOC_DOORBUF(NSCD_GETADMIN, len, uptr, buflen); 1081cb5caa98Sdjl 1082cb5caa98Sdjl /* copy packed header */ 1083cb5caa98Sdjl *(nss_pheader_t *)uptr = *(nss_pheader_t *)((void *)argp); 1084cb5caa98Sdjl 1085cb5caa98Sdjl /* set new buffer size */ 1086cb5caa98Sdjl ((nss_pheader_t *)uptr)->pbufsiz = buflen; 1087cb5caa98Sdjl 1088cb5caa98Sdjl /* try one more time */ 1089cb5caa98Sdjl (void) _nscd_door_getadmin((void *)uptr); 1090cb5caa98Sdjl (void) door_return(uptr, buflen, NULL, 0); 1091cb5caa98Sdjl break; 1092cb5caa98Sdjl 1093cb5caa98Sdjl case NSCD_SETADMIN: 1094cb5caa98Sdjl N2N_check_priv(argp, "NSCD_SETADMIN"); 1095cb5caa98Sdjl if (NSCD_STATUS_IS_OK(phdr)) 1096cb5caa98Sdjl _nscd_door_setadmin(argp); 1097cb5caa98Sdjl break; 1098cb5caa98Sdjl 1099cb5caa98Sdjl case NSCD_KILLSERVER: 1100cb5caa98Sdjl N2N_check_priv(argp, "NSCD_KILLSERVER"); 1101cb5caa98Sdjl if (NSCD_STATUS_IS_OK(phdr)) { 1102cb5caa98Sdjl /* also kill the forker nscd if one is running */ 1103cb5caa98Sdjl _nscd_kill_forker(); 1104cb5caa98Sdjl exit(0); 1105cb5caa98Sdjl } 1106cb5caa98Sdjl break; 1107cb5caa98Sdjl 1108cb5caa98Sdjl default: 1109cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR) 1110cb5caa98Sdjl (me, "Unknown name service door call op %d\n", 1111cb5caa98Sdjl phdr->nsc_callnumber); 1112cb5caa98Sdjl 1113cb5caa98Sdjl NSCD_SET_STATUS(phdr, NSS_ERROR, EINVAL); 1114cb5caa98Sdjl 1115cb5caa98Sdjl (void) door_return(argp, arg_size, NULL, 0); 1116cb5caa98Sdjl break; 1117cb5caa98Sdjl 1118cb5caa98Sdjl } 1119cb5caa98Sdjl (void) door_return(argp, arg_size, NULL, 0); 1120cb5caa98Sdjl } 1121cb5caa98Sdjl 1122cb5caa98Sdjl int 1123cb5caa98Sdjl _nscd_setup_server(char *execname, char **argv) 1124cb5caa98Sdjl { 1125cb5caa98Sdjl 1126cb5caa98Sdjl int fd; 1127cb5caa98Sdjl int errnum; 1128cb5caa98Sdjl int bind_failed = 0; 112980b80bf0Smichen mode_t old_mask; 1130cb5caa98Sdjl struct stat buf; 1131cb5caa98Sdjl sigset_t myset; 1132cb5caa98Sdjl struct sigaction action; 1133cb5caa98Sdjl char *me = "_nscd_setup_server"; 1134cb5caa98Sdjl 1135cb5caa98Sdjl main_execname = execname; 1136cb5caa98Sdjl main_argv = argv; 1137cb5caa98Sdjl 113882714199Ssdussud /* Any nscd process is to ignore SIGPIPE */ 113982714199Ssdussud if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) { 114082714199Ssdussud errnum = errno; 114182714199Ssdussud _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR) 114282714199Ssdussud (me, "signal (SIGPIPE): %s\n", strerror(errnum)); 114382714199Ssdussud return (-1); 114482714199Ssdussud } 114582714199Ssdussud 1146cb5caa98Sdjl keep_open_dns_socket(); 1147cb5caa98Sdjl 1148cb5caa98Sdjl /* 1149cb5caa98Sdjl * the max number of server threads should be fixed now, so 1150cb5caa98Sdjl * set flag to indicate that no in-flight change is allowed 1151cb5caa98Sdjl */ 1152cb5caa98Sdjl max_servers_set = 1; 1153cb5caa98Sdjl 1154cb5caa98Sdjl (void) thr_keycreate(&lookup_state_key, NULL); 1155bf1e3beeSmichen (void) sema_init(&common_sema, frontend_cfg_g.common_worker_threads, 1156cb5caa98Sdjl USYNC_THREAD, 0); 1157cb5caa98Sdjl 1158cb5caa98Sdjl /* Establish server thread pool */ 1159cb5caa98Sdjl (void) door_server_create(server_create); 1160cb5caa98Sdjl if (thr_keycreate(&server_key, server_destroy) != 0) { 1161cb5caa98Sdjl errnum = errno; 1162cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR) 1163cb5caa98Sdjl (me, "thr_keycreate (server thread): %s\n", 1164cb5caa98Sdjl strerror(errnum)); 1165cb5caa98Sdjl return (-1); 1166cb5caa98Sdjl } 1167cb5caa98Sdjl 1168cb5caa98Sdjl /* Create a door */ 1169cb5caa98Sdjl if ((fd = door_create(switcher, NAME_SERVICE_DOOR_COOKIE, 1170cb5caa98Sdjl DOOR_UNREF | DOOR_NO_CANCEL)) < 0) { 1171cb5caa98Sdjl errnum = errno; 1172cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR) 1173cb5caa98Sdjl (me, "door_create: %s\n", strerror(errnum)); 1174cb5caa98Sdjl return (-1); 1175cb5caa98Sdjl } 1176cb5caa98Sdjl 1177cb5caa98Sdjl /* if not main nscd, no more setup to do */ 1178cb5caa98Sdjl if (_whoami != NSCD_MAIN) 1179cb5caa98Sdjl return (fd); 1180cb5caa98Sdjl 1181cb5caa98Sdjl /* bind to file system */ 1182bf1e3beeSmichen if (is_system_labeled() && (getzoneid() == GLOBAL_ZONEID)) { 1183cb5caa98Sdjl if (stat(TSOL_NAME_SERVICE_DOOR, &buf) < 0) { 1184cb5caa98Sdjl int newfd; 118580b80bf0Smichen 118680b80bf0Smichen /* make sure the door will be readable by all */ 118780b80bf0Smichen old_mask = umask(0); 1188cb5caa98Sdjl if ((newfd = creat(TSOL_NAME_SERVICE_DOOR, 0444)) < 0) { 1189cb5caa98Sdjl errnum = errno; 1190cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_FRONT_END, 1191cb5caa98Sdjl NSCD_LOG_LEVEL_ERROR) 1192cb5caa98Sdjl (me, "Cannot create %s: %s\n", 1193cb5caa98Sdjl TSOL_NAME_SERVICE_DOOR, 1194cb5caa98Sdjl strerror(errnum)); 1195cb5caa98Sdjl bind_failed = 1; 1196cb5caa98Sdjl } 119780b80bf0Smichen /* rstore the old file mode creation mask */ 119880b80bf0Smichen (void) umask(old_mask); 1199cb5caa98Sdjl (void) close(newfd); 1200cb5caa98Sdjl } 1201cb5caa98Sdjl if (symlink(TSOL_NAME_SERVICE_DOOR, NAME_SERVICE_DOOR) != 0) { 1202cb5caa98Sdjl if (errno != EEXIST) { 1203cb5caa98Sdjl errnum = errno; 1204cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_FRONT_END, 1205cb5caa98Sdjl NSCD_LOG_LEVEL_ERROR) 1206cb5caa98Sdjl (me, "Cannot symlink %s: %s\n", 1207bf1e3beeSmichen NAME_SERVICE_DOOR, strerror(errnum)); 1208cb5caa98Sdjl bind_failed = 1; 1209cb5caa98Sdjl } 1210cb5caa98Sdjl } 1211cb5caa98Sdjl } else if (stat(NAME_SERVICE_DOOR, &buf) < 0) { 1212cb5caa98Sdjl int newfd; 121380b80bf0Smichen 121480b80bf0Smichen /* make sure the door will be readable by all */ 121580b80bf0Smichen old_mask = umask(0); 1216cb5caa98Sdjl if ((newfd = creat(NAME_SERVICE_DOOR, 0444)) < 0) { 1217cb5caa98Sdjl errnum = errno; 1218cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR) 1219cb5caa98Sdjl (me, "Cannot create %s: %s\n", NAME_SERVICE_DOOR, 1220cb5caa98Sdjl strerror(errnum)); 1221cb5caa98Sdjl bind_failed = 1; 1222cb5caa98Sdjl } 122380b80bf0Smichen /* rstore the old file mode creation mask */ 122480b80bf0Smichen (void) umask(old_mask); 1225cb5caa98Sdjl (void) close(newfd); 1226cb5caa98Sdjl } 1227cb5caa98Sdjl 1228cb5caa98Sdjl if (bind_failed == 1) { 1229cb5caa98Sdjl (void) door_revoke(fd); 1230cb5caa98Sdjl return (-1); 1231cb5caa98Sdjl } 1232cb5caa98Sdjl 1233cb5caa98Sdjl if (fattach(fd, NAME_SERVICE_DOOR) < 0) { 1234cb5caa98Sdjl if ((errno != EBUSY) || 1235cb5caa98Sdjl (fdetach(NAME_SERVICE_DOOR) < 0) || 1236cb5caa98Sdjl (fattach(fd, NAME_SERVICE_DOOR) < 0)) { 1237cb5caa98Sdjl errnum = errno; 1238bf1e3beeSmichen _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR) 1239cb5caa98Sdjl (me, "fattach: %s\n", strerror(errnum)); 1240cb5caa98Sdjl (void) door_revoke(fd); 1241cb5caa98Sdjl return (-1); 1242cb5caa98Sdjl } 1243cb5caa98Sdjl } 1244cb5caa98Sdjl 1245cb5caa98Sdjl /* 1246cb5caa98Sdjl * kick off routing socket monitor thread 1247cb5caa98Sdjl */ 1248cb5caa98Sdjl if (thr_create(NULL, NULL, 1249cb5caa98Sdjl (void *(*)(void *))rts_mon, 0, 0, NULL) != 0) { 1250cb5caa98Sdjl errnum = errno; 1251cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR) 1252cb5caa98Sdjl (me, "thr_create (routing socket monitor): %s\n", 1253cb5caa98Sdjl strerror(errnum)); 1254cb5caa98Sdjl 1255cb5caa98Sdjl (void) door_revoke(fd); 1256cb5caa98Sdjl return (-1); 1257cb5caa98Sdjl } 1258cb5caa98Sdjl 1259cb5caa98Sdjl /* 1260cb5caa98Sdjl * set up signal handler for SIGHUP 1261cb5caa98Sdjl */ 1262cb5caa98Sdjl action.sa_handler = dozip; 1263cb5caa98Sdjl action.sa_flags = 0; 1264cb5caa98Sdjl (void) sigemptyset(&action.sa_mask); 1265cb5caa98Sdjl (void) sigemptyset(&myset); 1266cb5caa98Sdjl (void) sigaddset(&myset, SIGHUP); 1267cb5caa98Sdjl 1268cb5caa98Sdjl if (sigaction(SIGHUP, &action, NULL) < 0) { 1269cb5caa98Sdjl errnum = errno; 1270cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR) 1271cb5caa98Sdjl (me, "sigaction (SIGHUP): %s\n", strerror(errnum)); 1272cb5caa98Sdjl 1273cb5caa98Sdjl (void) door_revoke(fd); 1274cb5caa98Sdjl return (-1); 1275cb5caa98Sdjl } 1276cb5caa98Sdjl 1277cb5caa98Sdjl return (fd); 1278cb5caa98Sdjl } 1279cb5caa98Sdjl 1280cb5caa98Sdjl int 1281cb5caa98Sdjl _nscd_setup_child_server(int did) 1282cb5caa98Sdjl { 1283cb5caa98Sdjl 1284cb5caa98Sdjl int errnum; 1285cb5caa98Sdjl int fd; 1286cb5caa98Sdjl nscd_rc_t rc; 1287cb5caa98Sdjl char *me = "_nscd_setup_child_server"; 1288cb5caa98Sdjl 1289cb5caa98Sdjl /* Re-establish our own server thread pool */ 1290cb5caa98Sdjl (void) door_server_create(server_create); 1291cb5caa98Sdjl if (thr_keycreate(&server_key, server_destroy) != 0) { 1292cb5caa98Sdjl errnum = errno; 1293cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG) 1294cb5caa98Sdjl (me, "thr_keycreate failed: %s", strerror(errnum)); 1295cb5caa98Sdjl return (-1); 1296cb5caa98Sdjl } 1297cb5caa98Sdjl 1298cb5caa98Sdjl /* 1299cb5caa98Sdjl * Create a new door. 1300cb5caa98Sdjl * Keep DOOR_REFUSE_DESC (self-cred nscds don't fork) 1301cb5caa98Sdjl */ 1302cb5caa98Sdjl (void) close(did); 1303bf1e3beeSmichen if ((fd = door_create(switcher, NAME_SERVICE_DOOR_COOKIE, 1304cb5caa98Sdjl DOOR_REFUSE_DESC|DOOR_UNREF|DOOR_NO_CANCEL)) < 0) { 1305cb5caa98Sdjl errnum = errno; 1306cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG) 1307cb5caa98Sdjl (me, "door_create failed: %s", strerror(errnum)); 1308cb5caa98Sdjl return (-1); 1309cb5caa98Sdjl } 1310cb5caa98Sdjl 1311cb5caa98Sdjl /* 1312cb5caa98Sdjl * kick off routing socket monitor thread 1313cb5caa98Sdjl */ 1314cb5caa98Sdjl if (thr_create(NULL, NULL, 1315cb5caa98Sdjl (void *(*)(void *))rts_mon, 0, 0, NULL) != 0) { 1316cb5caa98Sdjl errnum = errno; 1317cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR) 1318cb5caa98Sdjl (me, "thr_create (routing socket monitor): %s\n", 1319cb5caa98Sdjl strerror(errnum)); 1320cb5caa98Sdjl (void) door_revoke(fd); 1321cb5caa98Sdjl return (-1); 1322cb5caa98Sdjl } 1323cb5caa98Sdjl 1324cb5caa98Sdjl /* 1325cb5caa98Sdjl * start monitoring the states of the name service clients 1326cb5caa98Sdjl */ 1327cb5caa98Sdjl rc = _nscd_init_smf_monitor(); 1328cb5caa98Sdjl if (rc != NSCD_SUCCESS) { 1329cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR) 1330cb5caa98Sdjl (me, "unable to start the SMF monitor (rc = %d)\n", rc); 1331cb5caa98Sdjl 1332cb5caa98Sdjl (void) door_revoke(fd); 1333cb5caa98Sdjl return (-1); 1334cb5caa98Sdjl } 1335cb5caa98Sdjl 1336cb5caa98Sdjl return (fd); 1337cb5caa98Sdjl } 1338cb5caa98Sdjl 1339cb5caa98Sdjl nscd_rc_t 1340cb5caa98Sdjl _nscd_alloc_frontend_cfg() 1341cb5caa98Sdjl { 1342cb5caa98Sdjl frontend_cfg = calloc(NSCD_NUM_DB, sizeof (nscd_cfg_frontend_t)); 1343cb5caa98Sdjl if (frontend_cfg == NULL) 1344cb5caa98Sdjl return (NSCD_NO_MEMORY); 1345cb5caa98Sdjl 1346cb5caa98Sdjl return (NSCD_SUCCESS); 1347cb5caa98Sdjl } 1348cb5caa98Sdjl 1349cb5caa98Sdjl 1350cb5caa98Sdjl /* ARGSUSED */ 1351cb5caa98Sdjl nscd_rc_t 1352cb5caa98Sdjl _nscd_cfg_frontend_notify( 1353cb5caa98Sdjl void *data, 1354cb5caa98Sdjl struct nscd_cfg_param_desc *pdesc, 1355cb5caa98Sdjl nscd_cfg_id_t *nswdb, 1356cb5caa98Sdjl nscd_cfg_flag_t dflag, 1357cb5caa98Sdjl nscd_cfg_error_t **errorp, 1358cb5caa98Sdjl void *cookie) 1359cb5caa98Sdjl { 1360cb5caa98Sdjl void *dp; 1361cb5caa98Sdjl 1362cb5caa98Sdjl /* 1363cb5caa98Sdjl * At init time, the whole group of config params are received. 1364cb5caa98Sdjl * At update time, group or individual parameter value could 1365cb5caa98Sdjl * be received. 1366cb5caa98Sdjl */ 1367cb5caa98Sdjl 1368cb5caa98Sdjl if (_nscd_cfg_flag_is_set(dflag, NSCD_CFG_DFLAG_INIT) || 1369cb5caa98Sdjl _nscd_cfg_flag_is_set(dflag, NSCD_CFG_DFLAG_GROUP)) { 1370cb5caa98Sdjl /* 1371cb5caa98Sdjl * group data is received, copy in the 1372cb5caa98Sdjl * entire strcture 1373cb5caa98Sdjl */ 1374bf1e3beeSmichen if (_nscd_cfg_flag_is_set(pdesc->pflag, NSCD_CFG_PFLAG_GLOBAL)) 1375bf1e3beeSmichen frontend_cfg_g = *(nscd_cfg_global_frontend_t *)data; 1376cb5caa98Sdjl else 1377cb5caa98Sdjl frontend_cfg[nswdb->index] = 1378cb5caa98Sdjl *(nscd_cfg_frontend_t *)data; 1379cb5caa98Sdjl 1380cb5caa98Sdjl } else { 1381cb5caa98Sdjl /* 1382cb5caa98Sdjl * individual paramater is received: copy in the 1383cb5caa98Sdjl * parameter value. 1384cb5caa98Sdjl */ 1385bf1e3beeSmichen if (_nscd_cfg_flag_is_set(pdesc->pflag, NSCD_CFG_PFLAG_GLOBAL)) 1386cb5caa98Sdjl dp = (char *)&frontend_cfg_g + pdesc->p_offset; 1387cb5caa98Sdjl else 1388cb5caa98Sdjl dp = (char *)&frontend_cfg[nswdb->index] + 1389cb5caa98Sdjl pdesc->p_offset; 1390cb5caa98Sdjl (void) memcpy(dp, data, pdesc->p_size); 1391cb5caa98Sdjl } 1392cb5caa98Sdjl 1393cb5caa98Sdjl return (NSCD_SUCCESS); 1394cb5caa98Sdjl } 1395cb5caa98Sdjl 1396cb5caa98Sdjl /* ARGSUSED */ 1397cb5caa98Sdjl nscd_rc_t 1398cb5caa98Sdjl _nscd_cfg_frontend_verify( 1399cb5caa98Sdjl void *data, 1400cb5caa98Sdjl struct nscd_cfg_param_desc *pdesc, 1401cb5caa98Sdjl nscd_cfg_id_t *nswdb, 1402cb5caa98Sdjl nscd_cfg_flag_t dflag, 1403cb5caa98Sdjl nscd_cfg_error_t **errorp, 1404cb5caa98Sdjl void **cookie) 1405cb5caa98Sdjl { 1406cb5caa98Sdjl 1407cb5caa98Sdjl char *me = "_nscd_cfg_frontend_verify"; 1408cb5caa98Sdjl 1409cb5caa98Sdjl /* 1410cb5caa98Sdjl * if max. number of server threads is set and in effect, 1411cb5caa98Sdjl * don't allow changing of the frontend configuration 1412cb5caa98Sdjl */ 1413cb5caa98Sdjl if (max_servers_set) { 1414cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_INFO) 1415cb5caa98Sdjl (me, "changing of the frontend configuration not allowed now"); 1416cb5caa98Sdjl 1417cb5caa98Sdjl return (NSCD_CFG_CHANGE_NOT_ALLOWED); 1418cb5caa98Sdjl } 1419cb5caa98Sdjl 1420cb5caa98Sdjl return (NSCD_SUCCESS); 1421cb5caa98Sdjl } 1422cb5caa98Sdjl 1423cb5caa98Sdjl /* ARGSUSED */ 1424cb5caa98Sdjl nscd_rc_t 1425cb5caa98Sdjl _nscd_cfg_frontend_get_stat( 1426cb5caa98Sdjl void **stat, 1427cb5caa98Sdjl struct nscd_cfg_stat_desc *sdesc, 1428cb5caa98Sdjl nscd_cfg_id_t *nswdb, 1429cb5caa98Sdjl nscd_cfg_flag_t *dflag, 1430cb5caa98Sdjl void (**free_stat)(void *stat), 1431cb5caa98Sdjl nscd_cfg_error_t **errorp) 1432cb5caa98Sdjl { 1433cb5caa98Sdjl return (NSCD_SUCCESS); 1434cb5caa98Sdjl } 1435cb5caa98Sdjl 1436cb5caa98Sdjl void 1437cb5caa98Sdjl _nscd_init_cache_sema(sema_t *sema, char *cache_name) 1438cb5caa98Sdjl { 1439cb5caa98Sdjl int i, j; 1440cb5caa98Sdjl char *dbn; 1441cb5caa98Sdjl 1442cb5caa98Sdjl if (max_servers == 0) 1443cb5caa98Sdjl max_servers = frontend_cfg_g.common_worker_threads + 1444cb5caa98Sdjl frontend_cfg_g.cache_hit_threads; 1445cb5caa98Sdjl 1446cb5caa98Sdjl for (i = 0; i < NSCD_NUM_DB; i++) { 1447cb5caa98Sdjl 1448cb5caa98Sdjl dbn = NSCD_NSW_DB_NAME(i); 1449cb5caa98Sdjl if (strcasecmp(dbn, cache_name) == 0) { 1450cb5caa98Sdjl j = frontend_cfg[i].worker_thread_per_nsw_db; 1451cb5caa98Sdjl (void) sema_init(sema, j, USYNC_THREAD, 0); 1452cb5caa98Sdjl max_servers += j; 1453cb5caa98Sdjl break; 1454cb5caa98Sdjl } 1455cb5caa98Sdjl } 1456cb5caa98Sdjl } 1457cb5caa98Sdjl 1458cb5caa98Sdjl /* 1459cb5caa98Sdjl * Monitor the routing socket. Address lists stored in the ipnodes 1460cb5caa98Sdjl * cache are sorted based on destination address selection rules, 1461cb5caa98Sdjl * so when things change that could affect that sorting (interfaces 1462cb5caa98Sdjl * go up or down, flags change, etc.), we clear that cache so the 1463cb5caa98Sdjl * list will be re-ordered the next time the hostname is resolved. 1464cb5caa98Sdjl */ 1465cb5caa98Sdjl static void 1466cb5caa98Sdjl rts_mon(void) 1467cb5caa98Sdjl { 1468cb5caa98Sdjl int rt_sock, rdlen, idx; 1469cb5caa98Sdjl union { 1470cb5caa98Sdjl struct { 1471cb5caa98Sdjl struct rt_msghdr rtm; 1472cb5caa98Sdjl struct sockaddr_storage addrs[RTA_NUMBITS]; 1473cb5caa98Sdjl } r; 1474cb5caa98Sdjl struct if_msghdr ifm; 1475cb5caa98Sdjl struct ifa_msghdr ifam; 1476cb5caa98Sdjl } mbuf; 1477cb5caa98Sdjl struct ifa_msghdr *ifam = &mbuf.ifam; 1478cb5caa98Sdjl char *me = "rts_mon"; 1479cb5caa98Sdjl 1480cb5caa98Sdjl rt_sock = socket(PF_ROUTE, SOCK_RAW, 0); 1481cb5caa98Sdjl if (rt_sock < 0) { 1482cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR) 1483cb5caa98Sdjl (me, "Failed to open routing socket: %s\n", strerror(errno)); 1484cb5caa98Sdjl thr_exit(0); 1485cb5caa98Sdjl } 1486cb5caa98Sdjl 1487cb5caa98Sdjl for (;;) { 1488cb5caa98Sdjl rdlen = read(rt_sock, &mbuf, sizeof (mbuf)); 1489cb5caa98Sdjl if (rdlen <= 0) { 1490cb5caa98Sdjl if (rdlen == 0 || (errno != EINTR && errno != EAGAIN)) { 1491cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_FRONT_END, 1492cb5caa98Sdjl NSCD_LOG_LEVEL_ERROR) 1493cb5caa98Sdjl (me, "routing socket read: %s\n", 1494cb5caa98Sdjl strerror(errno)); 1495cb5caa98Sdjl thr_exit(0); 1496cb5caa98Sdjl } 1497cb5caa98Sdjl continue; 1498cb5caa98Sdjl } 1499cb5caa98Sdjl if (ifam->ifam_version != RTM_VERSION) { 1500cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_FRONT_END, 1501cb5caa98Sdjl NSCD_LOG_LEVEL_ERROR) 1502cb5caa98Sdjl (me, "rx unknown version (%d) on " 1503cb5caa98Sdjl "routing socket.\n", 1504cb5caa98Sdjl ifam->ifam_version); 1505cb5caa98Sdjl continue; 1506cb5caa98Sdjl } 1507cb5caa98Sdjl switch (ifam->ifam_type) { 1508cb5caa98Sdjl case RTM_NEWADDR: 1509cb5caa98Sdjl case RTM_DELADDR: 1510cb5caa98Sdjl /* if no ipnodes cache, then nothing to do */ 1511cb5caa98Sdjl idx = get_cache_idx("ipnodes"); 1512cb5caa98Sdjl if (cache_ctx_p[idx] == NULL || 1513cb5caa98Sdjl cache_ctx_p[idx]->reaper_on != nscd_true) 1514cb5caa98Sdjl break; 1515cb5caa98Sdjl nsc_invalidate(cache_ctx_p[idx], NULL, NULL); 1516cb5caa98Sdjl break; 1517cb5caa98Sdjl case RTM_ADD: 1518cb5caa98Sdjl case RTM_DELETE: 1519cb5caa98Sdjl case RTM_CHANGE: 1520cb5caa98Sdjl case RTM_GET: 1521cb5caa98Sdjl case RTM_LOSING: 1522cb5caa98Sdjl case RTM_REDIRECT: 1523cb5caa98Sdjl case RTM_MISS: 1524cb5caa98Sdjl case RTM_LOCK: 1525cb5caa98Sdjl case RTM_OLDADD: 1526cb5caa98Sdjl case RTM_OLDDEL: 1527cb5caa98Sdjl case RTM_RESOLVE: 1528cb5caa98Sdjl case RTM_IFINFO: 15291cb875aeSCathy Zhou case RTM_CHGADDR: 15301cb875aeSCathy Zhou case RTM_FREEADDR: 1531cb5caa98Sdjl break; 1532cb5caa98Sdjl default: 1533cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR) 1534cb5caa98Sdjl (me, "rx unknown msg type (%d) on routing socket.\n", 1535cb5caa98Sdjl ifam->ifam_type); 1536cb5caa98Sdjl break; 1537cb5caa98Sdjl } 1538cb5caa98Sdjl } 1539cb5caa98Sdjl } 1540cb5caa98Sdjl 1541cb5caa98Sdjl static void 1542cb5caa98Sdjl keep_open_dns_socket(void) 1543cb5caa98Sdjl { 1544cb5caa98Sdjl _res.options |= RES_STAYOPEN; /* just keep this udp socket open */ 1545cb5caa98Sdjl } 1546