1c5c4113dSnw /* 2c5c4113dSnw * CDDL HEADER START 3c5c4113dSnw * 4c5c4113dSnw * The contents of this file are subject to the terms of the 5c5c4113dSnw * Common Development and Distribution License (the "License"). 6c5c4113dSnw * You may not use this file except in compliance with the License. 7c5c4113dSnw * 8c5c4113dSnw * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9c5c4113dSnw * or http://www.opensolaris.org/os/licensing. 10c5c4113dSnw * See the License for the specific language governing permissions 11c5c4113dSnw * and limitations under the License. 12c5c4113dSnw * 13c5c4113dSnw * When distributing Covered Code, include this CDDL HEADER in each 14c5c4113dSnw * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15c5c4113dSnw * If applicable, add the following below this CDDL HEADER, with the 16c5c4113dSnw * fields enclosed by brackets "[]" replaced with your own identifying 17c5c4113dSnw * information: Portions Copyright [yyyy] [name of copyright owner] 18c5c4113dSnw * 19c5c4113dSnw * CDDL HEADER END 20c5c4113dSnw */ 21c5c4113dSnw /* 22bda89588Sjp * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23c5c4113dSnw * Use is subject to license terms. 24c5c4113dSnw */ 25c5c4113dSnw 26c5c4113dSnw #pragma ident "%Z%%M% %I% %E% SMI" 27c5c4113dSnw 28c5c4113dSnw /* 29c5c4113dSnw * main() of idmapd(1M) 30c5c4113dSnw */ 31c5c4113dSnw 32c5c4113dSnw #include "idmapd.h" 3371590c90Snw #include <atomic.h> 34c5c4113dSnw #include <signal.h> 35c5c4113dSnw #include <rpc/pmap_clnt.h> /* for pmap_unset */ 36c5c4113dSnw #include <string.h> /* strcmp */ 37c5c4113dSnw #include <unistd.h> /* setsid */ 38c5c4113dSnw #include <sys/types.h> 39c5c4113dSnw #include <memory.h> 40c5c4113dSnw #include <stropts.h> 41c5c4113dSnw #include <netconfig.h> 42c5c4113dSnw #include <sys/resource.h> /* rlimit */ 43c5c4113dSnw #include <syslog.h> 44c5c4113dSnw #include <rpcsvc/daemon_utils.h> /* DAEMON_UID and DAEMON_GID */ 45c5c4113dSnw #include <priv_utils.h> /* privileges */ 46c5c4113dSnw #include <locale.h> 47c5c4113dSnw #include <sys/systeminfo.h> 48c5c4113dSnw #include <errno.h> 49c5c4113dSnw #include <sys/wait.h> 50c5c4113dSnw #include <sys/time.h> 51c5c4113dSnw #include <zone.h> 52c5c4113dSnw #include <door.h> 53c8e26105Sjp #include <port.h> 54c5c4113dSnw #include <tsol/label.h> 55c5c4113dSnw #include <sys/resource.h> 56c5c4113dSnw #include <sys/sid.h> 57c5c4113dSnw #include <sys/idmap.h> 58*bcced03bSjp #include <pthread.h> 59c5c4113dSnw 60c5c4113dSnw static void term_handler(int); 61c5c4113dSnw static void init_idmapd(); 62c5c4113dSnw static void fini_idmapd(); 63c5c4113dSnw 64c5c4113dSnw #define _RPCSVC_CLOSEDOWN 120 65c5c4113dSnw 66c5c4113dSnw int _rpcsvcstate = _IDLE; /* Set when a request is serviced */ 67c5c4113dSnw int _rpcsvccount = 0; /* Number of requests being serviced */ 68c5c4113dSnw mutex_t _svcstate_lock; /* lock for _rpcsvcstate, _rpcsvccount */ 69c5c4113dSnw idmapd_state_t _idmapdstate; 70c5c4113dSnw 71c5c4113dSnw SVCXPRT *xprt = NULL; 72c5c4113dSnw 73c5c4113dSnw static int dfd = -1; /* our door server fildes, for unregistration */ 7471590c90Snw static int degraded = 0; /* whether the FMRI has been marked degraded */ 75c5c4113dSnw 76*bcced03bSjp 77*bcced03bSjp static uint32_t num_threads = 0; 78*bcced03bSjp static pthread_key_t create_threads_key; 79*bcced03bSjp static uint32_t max_threads = 40; 80*bcced03bSjp 81*bcced03bSjp /* 82*bcced03bSjp * Server door thread start routine. 83*bcced03bSjp * 84*bcced03bSjp * Set a TSD value to the door thread. This enables the destructor to 85*bcced03bSjp * be called when this thread exits. 86*bcced03bSjp */ 87*bcced03bSjp /*ARGSUSED*/ 88*bcced03bSjp static void * 89*bcced03bSjp idmapd_door_thread_start(void *arg) 90*bcced03bSjp { 91*bcced03bSjp static void *value = 0; 92*bcced03bSjp 93*bcced03bSjp /* 94*bcced03bSjp * Disable cancellation to avoid memory leaks from not running 95*bcced03bSjp * the thread cleanup code. 96*bcced03bSjp */ 97*bcced03bSjp (void) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); 98*bcced03bSjp (void) pthread_setspecific(create_threads_key, value); 99*bcced03bSjp (void) door_return(NULL, 0, NULL, 0); 100*bcced03bSjp 101*bcced03bSjp /* make lint happy */ 102*bcced03bSjp return (NULL); 103*bcced03bSjp } 104*bcced03bSjp 105*bcced03bSjp /* 106*bcced03bSjp * Server door threads creation 107*bcced03bSjp */ 108*bcced03bSjp /*ARGSUSED*/ 109*bcced03bSjp static void 110*bcced03bSjp idmapd_door_thread_create(door_info_t *dip) 111*bcced03bSjp { 112*bcced03bSjp int num; 113*bcced03bSjp pthread_t thread_id; 114*bcced03bSjp 115*bcced03bSjp if ((num = atomic_inc_32_nv(&num_threads)) > max_threads) { 116*bcced03bSjp atomic_dec_32(&num_threads); 117*bcced03bSjp idmapdlog(LOG_DEBUG, 118*bcced03bSjp "thread creation refused - %d threads currently active", 119*bcced03bSjp num - 1); 120*bcced03bSjp return; 121*bcced03bSjp } 122*bcced03bSjp (void) pthread_create(&thread_id, NULL, idmapd_door_thread_start, NULL); 123*bcced03bSjp idmapdlog(LOG_DEBUG, 124*bcced03bSjp "created thread ID %d - %d threads currently active", 125*bcced03bSjp thread_id, num); 126*bcced03bSjp } 127*bcced03bSjp 128*bcced03bSjp /* 129*bcced03bSjp * Server door thread cleanup 130*bcced03bSjp */ 131*bcced03bSjp /*ARGSUSED*/ 132*bcced03bSjp static void 133*bcced03bSjp idmapd_door_thread_cleanup(void *arg) 134*bcced03bSjp { 135*bcced03bSjp int num; 136*bcced03bSjp 137*bcced03bSjp num = atomic_dec_32_nv(&num_threads); 138*bcced03bSjp idmapdlog(LOG_DEBUG, 139*bcced03bSjp "exiting thread ID %d - %d threads currently active", 140*bcced03bSjp pthread_self(), num); 141*bcced03bSjp } 142*bcced03bSjp 143c5c4113dSnw /* 144c5c4113dSnw * This is needed for mech_krb5 -- we run as daemon, yes, but we want 14578b2cb9aSnw * mech_krb5 to think we're root so it can get host/nodename.fqdn 14678b2cb9aSnw * tickets for us so we can authenticate to AD as the machine account 14778b2cb9aSnw * that we are. For more details look at the entry point in mech_krb5 14878b2cb9aSnw * corresponding to gss_init_sec_context(). 14978b2cb9aSnw * 15078b2cb9aSnw * As a side effect of faking our effective UID to mech_krb5 we will use 15178b2cb9aSnw * root's default ccache (/tmp/krb5cc_0). But if that's created by 15278b2cb9aSnw * another process then we won't have access to it: we run as daemon and 15378b2cb9aSnw * keep PRIV_FILE_DAC_READ, which is insufficient to share the ccache 15478b2cb9aSnw * with others. We putenv("KRB5CCNAME=/var/run/idmap/ccache") in main() 15578b2cb9aSnw * to avoid this issue; see main(). 156c5c4113dSnw * 157c5c4113dSnw * Someday we'll have gss/mech_krb5 extensions for acquiring initiator 158c5c4113dSnw * creds with keytabs/raw keys, and someday we'll have extensions to 159c5c4113dSnw * libsasl to specify creds/name to use on the initiator side, and 160c5c4113dSnw * someday we'll have extensions to libldap to pass those through to 161c5c4113dSnw * libsasl. Until then this interposer will have to do. 162c5c4113dSnw * 163c5c4113dSnw * Also, we have to tell lint to shut up: it thinks app_krb5_user_uid() 164c5c4113dSnw * is defined but not used. 165c5c4113dSnw */ 166c5c4113dSnw /*LINTLIBRARY*/ 167c5c4113dSnw uid_t 168c5c4113dSnw app_krb5_user_uid(void) 169c5c4113dSnw { 170c5c4113dSnw return (0); 171c5c4113dSnw } 172c5c4113dSnw 173c5c4113dSnw /*ARGSUSED*/ 174c5c4113dSnw static void 1754edd44c5Sjp term_handler(int sig) 1764edd44c5Sjp { 17771590c90Snw idmapdlog(LOG_INFO, "Terminating."); 178c5c4113dSnw fini_idmapd(); 179c5c4113dSnw _exit(0); 180c5c4113dSnw } 181c5c4113dSnw 18271590c90Snw /*ARGSUSED*/ 18371590c90Snw static void 18471590c90Snw usr1_handler(int sig) 18571590c90Snw { 18671590c90Snw bool_t saved_debug_mode = _idmapdstate.debug_mode; 18771590c90Snw 18871590c90Snw _idmapdstate.debug_mode = TRUE; 18971590c90Snw print_idmapdstate(); 19071590c90Snw _idmapdstate.debug_mode = saved_debug_mode; 19171590c90Snw } 19271590c90Snw 193c5c4113dSnw static int pipe_fd = -1; 194c5c4113dSnw 195c5c4113dSnw static void 1964edd44c5Sjp daemonize_ready(void) 1974edd44c5Sjp { 198c5c4113dSnw char data = '\0'; 199c5c4113dSnw /* 200c5c4113dSnw * wake the parent 201c5c4113dSnw */ 202c5c4113dSnw (void) write(pipe_fd, &data, 1); 203c5c4113dSnw (void) close(pipe_fd); 204c5c4113dSnw } 205c5c4113dSnw 206c5c4113dSnw static int 2074edd44c5Sjp daemonize_start(void) 2084edd44c5Sjp { 209c5c4113dSnw char data; 210c5c4113dSnw int status; 211c5c4113dSnw int devnull; 212c5c4113dSnw int filedes[2]; 213c5c4113dSnw pid_t pid; 214c5c4113dSnw 21578b2cb9aSnw (void) sigset(SIGPIPE, SIG_IGN); 216c5c4113dSnw devnull = open("/dev/null", O_RDONLY); 217c5c4113dSnw if (devnull < 0) 218c5c4113dSnw return (-1); 219c5c4113dSnw (void) dup2(devnull, 0); 220c5c4113dSnw (void) dup2(2, 1); /* stderr only */ 221c5c4113dSnw if (pipe(filedes) < 0) 222c5c4113dSnw return (-1); 223c5c4113dSnw if ((pid = fork1()) < 0) 224c5c4113dSnw return (-1); 225c5c4113dSnw if (pid != 0) { 226c5c4113dSnw /* 227c5c4113dSnw * parent 228c5c4113dSnw */ 229c5c4113dSnw (void) close(filedes[1]); 230c5c4113dSnw if (read(filedes[0], &data, 1) == 1) { 231c5c4113dSnw /* presume success */ 232c5c4113dSnw _exit(0); 233c5c4113dSnw } 234c5c4113dSnw status = -1; 235c5c4113dSnw (void) wait4(pid, &status, 0, NULL); 236c5c4113dSnw if (WIFEXITED(status)) 237c5c4113dSnw _exit(WEXITSTATUS(status)); 238c5c4113dSnw else 239c5c4113dSnw _exit(-1); 240c5c4113dSnw } 241c5c4113dSnw 242c5c4113dSnw /* 243c5c4113dSnw * child 244c5c4113dSnw */ 245c5c4113dSnw pipe_fd = filedes[1]; 246c5c4113dSnw (void) close(filedes[0]); 247c5c4113dSnw (void) setsid(); 248c5c4113dSnw (void) umask(0077); 249c5c4113dSnw openlog("idmap", LOG_PID, LOG_DAEMON); 250c5c4113dSnw return (0); 251c5c4113dSnw } 252c5c4113dSnw 253c5c4113dSnw 254c5c4113dSnw int 255c5c4113dSnw main(int argc, char **argv) 256c5c4113dSnw { 257c5c4113dSnw int c; 2582b3ecdebSjp struct rlimit rl; 259c5c4113dSnw 26071590c90Snw _idmapdstate.daemon_mode = TRUE; 26171590c90Snw _idmapdstate.debug_mode = FALSE; 26271590c90Snw while ((c = getopt(argc, argv, "d")) != -1) { 263c5c4113dSnw switch (c) { 264c5c4113dSnw case 'd': 26571590c90Snw _idmapdstate.daemon_mode = FALSE; 266c5c4113dSnw break; 267c5c4113dSnw default: 26871590c90Snw fprintf(stderr, "Usage: /usr/lib/idmapd"); 26971590c90Snw return (SMF_EXIT_ERR_CONFIG); 270c5c4113dSnw break; 271c5c4113dSnw } 272c5c4113dSnw } 273c5c4113dSnw 274c5c4113dSnw /* set locale and domain for internationalization */ 275c5c4113dSnw (void) setlocale(LC_ALL, ""); 276c5c4113dSnw (void) textdomain(TEXT_DOMAIN); 277c5c4113dSnw 278bda89588Sjp if (is_system_labeled() && getzoneid() != GLOBAL_ZONEID) { 27971590c90Snw idmapdlog(LOG_ERR, 28071590c90Snw "with Trusted Extensions idmapd runs only in the " 281bda89588Sjp "global zone"); 282c5c4113dSnw exit(1); 283c5c4113dSnw } 284c5c4113dSnw 2852b3ecdebSjp /* 2862b3ecdebSjp * Raise the fd limit to max 2872b3ecdebSjp */ 2882b3ecdebSjp if (getrlimit(RLIMIT_NOFILE, &rl) != 0) { 2892b3ecdebSjp idmapdlog(LOG_ERR, "getrlimit failed"); 2902b3ecdebSjp } else if (rl.rlim_cur < rl.rlim_max) { 2912b3ecdebSjp rl.rlim_cur = rl.rlim_max; 2922b3ecdebSjp if (setrlimit(RLIMIT_NOFILE, &rl) != 0) 2932b3ecdebSjp idmapdlog(LOG_ERR, 2942b3ecdebSjp "Unable to raise RLIMIT_NOFILE to %d", 2952b3ecdebSjp rl.rlim_cur); 2962b3ecdebSjp } 2972b3ecdebSjp 298c5c4113dSnw (void) mutex_init(&_svcstate_lock, USYNC_THREAD, NULL); 299c5c4113dSnw 30071590c90Snw if (_idmapdstate.daemon_mode == TRUE) { 301c5c4113dSnw if (daemonize_start() < 0) { 30271590c90Snw (void) idmapdlog(LOG_ERR, "unable to daemonize"); 303c5c4113dSnw exit(-1); 304c5c4113dSnw } 305c5c4113dSnw } else 306c5c4113dSnw (void) umask(0077); 307c5c4113dSnw 30884decf41Sjp idmap_init_tsd_key(); 30984decf41Sjp 310c5c4113dSnw init_idmapd(); 311c5c4113dSnw 31278b2cb9aSnw /* signal handlers that should run only after we're initialized */ 31378b2cb9aSnw (void) sigset(SIGTERM, term_handler); 31471590c90Snw (void) sigset(SIGUSR1, usr1_handler); 3150dcc7149Snw (void) sigset(SIGHUP, idmap_cfg_hup_handler); 31678b2cb9aSnw 317c5c4113dSnw if (__init_daemon_priv(PU_RESETGROUPS|PU_CLEARLIMITSET, 318c5c4113dSnw DAEMON_UID, DAEMON_GID, 319c5c4113dSnw PRIV_PROC_AUDIT, PRIV_FILE_DAC_READ, 320c5c4113dSnw (char *)NULL) == -1) { 32171590c90Snw idmapdlog(LOG_ERR, "unable to drop privileges"); 322c5c4113dSnw exit(1); 323c5c4113dSnw } 324c5c4113dSnw 325c5c4113dSnw __fini_daemon_priv(PRIV_PROC_FORK, PRIV_PROC_EXEC, PRIV_PROC_SESSION, 326c5c4113dSnw PRIV_FILE_LINK_ANY, PRIV_PROC_INFO, (char *)NULL); 327c5c4113dSnw 32871590c90Snw if (_idmapdstate.daemon_mode == TRUE) 329c5c4113dSnw daemonize_ready(); 330c5c4113dSnw 331c5c4113dSnw /* With doors RPC this just wastes this thread, oh well */ 332c5c4113dSnw svc_run(); 333c5c4113dSnw return (0); 334c5c4113dSnw } 335c5c4113dSnw 336c5c4113dSnw static void 3374edd44c5Sjp init_idmapd() 3384edd44c5Sjp { 339c5c4113dSnw int error; 340*bcced03bSjp int connmaxrec = IDMAP_MAX_DOOR_RPC; 341*bcced03bSjp 342c5c4113dSnw 34378b2cb9aSnw /* create directories as root and chown to daemon uid */ 34478b2cb9aSnw if (create_directory(IDMAP_DBDIR, DAEMON_UID, DAEMON_GID) < 0) 34578b2cb9aSnw exit(1); 34678b2cb9aSnw if (create_directory(IDMAP_CACHEDIR, DAEMON_UID, DAEMON_GID) < 0) 34778b2cb9aSnw exit(1); 34878b2cb9aSnw 34978b2cb9aSnw /* 35078b2cb9aSnw * Set KRB5CCNAME in the environment. See app_krb5_user_uid() 351e3c2d6aaSnw * for more details. We blow away the existing one, if there is 352e3c2d6aaSnw * one. 35378b2cb9aSnw */ 354e3c2d6aaSnw (void) unlink(IDMAP_CACHEDIR "/ccache"); 35578b2cb9aSnw putenv("KRB5CCNAME=" IDMAP_CACHEDIR "/ccache"); 35678b2cb9aSnw 357c5c4113dSnw if (sysinfo(SI_HOSTNAME, _idmapdstate.hostname, 3584edd44c5Sjp sizeof (_idmapdstate.hostname)) == -1) { 359c5c4113dSnw error = errno; 36071590c90Snw idmapdlog(LOG_ERR, "unable to determine hostname, error: %d", 3614edd44c5Sjp error); 362c5c4113dSnw exit(1); 363c5c4113dSnw } 364c5c4113dSnw 365e8c27ec8Sbaban if ((error = init_mapping_system()) < 0) { 36671590c90Snw idmapdlog(LOG_ERR, "unable to initialize mapping system"); 367e8c27ec8Sbaban exit(error < -2 ? SMF_EXIT_ERR_CONFIG : 1); 368c5c4113dSnw } 369c5c4113dSnw 370*bcced03bSjp (void) door_server_create(idmapd_door_thread_create); 371*bcced03bSjp if ((error = pthread_key_create(&create_threads_key, 372*bcced03bSjp idmapd_door_thread_cleanup)) != 0) { 373*bcced03bSjp idmapdlog(LOG_ERR, "unable to create threads key (%s)", 374*bcced03bSjp strerror(error)); 375*bcced03bSjp goto errout; 376*bcced03bSjp } 377*bcced03bSjp 378d3a612caSnw xprt = svc_door_create(idmap_prog_1, IDMAP_PROG, IDMAP_V1, connmaxrec); 379c5c4113dSnw if (xprt == NULL) { 38071590c90Snw idmapdlog(LOG_ERR, "unable to create door RPC service"); 381c5c4113dSnw goto errout; 382c5c4113dSnw } 383c5c4113dSnw 3848e228215Sdm if (!svc_control(xprt, SVCSET_CONNMAXREC, &connmaxrec)) { 38571590c90Snw idmapdlog(LOG_ERR, "unable to limit RPC request size"); 3868e228215Sdm goto errout; 3878e228215Sdm } 3888e228215Sdm 389c5c4113dSnw dfd = xprt->xp_fd; 390c5c4113dSnw 391c5c4113dSnw if (dfd == -1) { 39271590c90Snw idmapdlog(LOG_ERR, "unable to register door"); 393c5c4113dSnw goto errout; 394c5c4113dSnw } 395c5c4113dSnw if ((error = idmap_reg(dfd)) != 0) { 39671590c90Snw idmapdlog(LOG_ERR, "unable to register door (%s)", 3974edd44c5Sjp strerror(errno)); 398c5c4113dSnw goto errout; 399c5c4113dSnw } 400c5c4113dSnw 401c5c4113dSnw if ((error = allocids(_idmapdstate.new_eph_db, 4024edd44c5Sjp 8192, &_idmapdstate.next_uid, 4034edd44c5Sjp 8192, &_idmapdstate.next_gid)) != 0) { 40471590c90Snw idmapdlog(LOG_ERR, "unable to allocate ephemeral IDs (%s)", 40571590c90Snw strerror(errno)); 406c5c4113dSnw _idmapdstate.next_uid = _idmapdstate.limit_uid = SENTINEL_PID; 407c5c4113dSnw _idmapdstate.next_gid = _idmapdstate.limit_gid = SENTINEL_PID; 408c5c4113dSnw } else { 409c5c4113dSnw _idmapdstate.limit_uid = _idmapdstate.next_uid + 8192; 410c5c4113dSnw _idmapdstate.limit_gid = _idmapdstate.next_gid + 8192; 411c5c4113dSnw } 412c5c4113dSnw 413c5c4113dSnw print_idmapdstate(); 414c5c4113dSnw 415c5c4113dSnw return; 416c5c4113dSnw 417c5c4113dSnw errout: 418c5c4113dSnw fini_idmapd(); 419c5c4113dSnw exit(1); 420c5c4113dSnw } 421c5c4113dSnw 422c5c4113dSnw static void 4234edd44c5Sjp fini_idmapd() 4244edd44c5Sjp { 425c5c4113dSnw idmap_unreg(dfd); 426c5c4113dSnw fini_mapping_system(); 427c5c4113dSnw if (xprt != NULL) 428c5c4113dSnw svc_destroy(xprt); 429c5c4113dSnw } 430c5c4113dSnw 43171590c90Snw static 43271590c90Snw const char * 43371590c90Snw get_fmri(void) 43471590c90Snw { 43571590c90Snw static char *fmri = NULL; 43671590c90Snw static char buf[60]; 43771590c90Snw char *s; 43871590c90Snw 43971590c90Snw membar_consumer(); 44071590c90Snw s = fmri; 44171590c90Snw if (s != NULL && *s == '\0') 44271590c90Snw return (NULL); 44371590c90Snw else if (s != NULL) 44471590c90Snw return (s); 44571590c90Snw 44671590c90Snw if ((s = getenv("SMF_FMRI")) == NULL || strlen(s) >= sizeof (buf)) 44771590c90Snw buf[0] = '\0'; 44871590c90Snw else 44971590c90Snw (void) strlcpy(buf, s, sizeof (buf)); 45071590c90Snw 45171590c90Snw membar_producer(); 45271590c90Snw fmri = buf; 45371590c90Snw 45471590c90Snw return (get_fmri()); 45571590c90Snw } 45671590c90Snw 45771590c90Snw /* 45871590c90Snw * Wrappers for smf_degrade/restore_instance() 45971590c90Snw * 46071590c90Snw * smf_restore_instance() is too heavy duty to be calling every time we 46171590c90Snw * have a successful AD name<->SID lookup. 46271590c90Snw */ 46371590c90Snw void 464349d5d8fSnw degrade_svc(int poke_discovery, const char *reason) 46571590c90Snw { 46671590c90Snw const char *fmri; 46771590c90Snw 46871590c90Snw /* 46971590c90Snw * If the config update thread is in a state where auto-discovery could 47071590c90Snw * be re-tried, then this will make it try it -- a sort of auto-refresh. 47171590c90Snw */ 472349d5d8fSnw if (poke_discovery) 473349d5d8fSnw idmap_cfg_poke_updates(); 47471590c90Snw 47571590c90Snw membar_consumer(); 47671590c90Snw if (degraded) 47771590c90Snw return; 478349d5d8fSnw 479349d5d8fSnw idmapdlog(LOG_ERR, "Degraded operation (%s). If you are running an " 480349d5d8fSnw "SMB server in workgroup mode, or if you're not running an SMB " 481349d5d8fSnw "server, then you can ignore this message", reason); 482349d5d8fSnw 48371590c90Snw membar_producer(); 48471590c90Snw degraded = 1; 48571590c90Snw 48671590c90Snw if ((fmri = get_fmri()) != NULL) 48771590c90Snw (void) smf_degrade_instance(fmri, 0); 48871590c90Snw } 48971590c90Snw 49071590c90Snw void 49171590c90Snw restore_svc(void) 49271590c90Snw { 49371590c90Snw const char *fmri; 49471590c90Snw 49571590c90Snw membar_consumer(); 49671590c90Snw if (!degraded) 49771590c90Snw return; 49871590c90Snw 49971590c90Snw if ((fmri = get_fmri()) == NULL) 50071590c90Snw (void) smf_restore_instance(fmri); 50171590c90Snw 50271590c90Snw membar_producer(); 50371590c90Snw degraded = 0; 504349d5d8fSnw idmapdlog(LOG_NOTICE, "Normal operation restored"); 50571590c90Snw } 50671590c90Snw 507c5c4113dSnw void 5084edd44c5Sjp idmapdlog(int pri, const char *format, ...) 5094edd44c5Sjp { 510c5c4113dSnw va_list args; 511c5c4113dSnw 512c5c4113dSnw va_start(args, format); 51371590c90Snw 51471590c90Snw if (_idmapdstate.debug_mode == TRUE || 51571590c90Snw _idmapdstate.daemon_mode == FALSE) { 516c5c4113dSnw (void) vfprintf(stderr, format, args); 517c5c4113dSnw (void) fprintf(stderr, "\n"); 518c5c4113dSnw } 51971590c90Snw 52071590c90Snw /* 52171590c90Snw * We don't want to fill up the logs with useless messages when 52271590c90Snw * we're degraded, but we still want to log. 52371590c90Snw */ 52471590c90Snw if (degraded) 52571590c90Snw pri = LOG_DEBUG; 52671590c90Snw 527c5c4113dSnw (void) vsyslog(pri, format, args); 528c5c4113dSnw va_end(args); 529c5c4113dSnw } 530