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 /* 22c5866007SKeyur Desai * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. 23fea136a0SMatt Barden * Copyright 2018 Nexenta Systems, Inc. All rights reserved. 24c5c4113dSnw */ 25c5c4113dSnw 26c5c4113dSnw 27c5c4113dSnw /* 28c5c4113dSnw * main() of idmapd(1M) 29c5c4113dSnw */ 30c5c4113dSnw 31c5c4113dSnw #include "idmapd.h" 3271590c90Snw #include <atomic.h> 33c5c4113dSnw #include <signal.h> 34c5c4113dSnw #include <rpc/pmap_clnt.h> /* for pmap_unset */ 35c5c4113dSnw #include <string.h> /* strcmp */ 36c5c4113dSnw #include <unistd.h> /* setsid */ 37c5c4113dSnw #include <sys/types.h> 38c5c4113dSnw #include <memory.h> 39c5c4113dSnw #include <stropts.h> 40c5c4113dSnw #include <netconfig.h> 41c5c4113dSnw #include <sys/resource.h> /* rlimit */ 42c5c4113dSnw #include <rpcsvc/daemon_utils.h> /* DAEMON_UID and DAEMON_GID */ 43c5c4113dSnw #include <priv_utils.h> /* privileges */ 44c5c4113dSnw #include <locale.h> 45c5c4113dSnw #include <sys/systeminfo.h> 46c5c4113dSnw #include <errno.h> 47c5c4113dSnw #include <sys/wait.h> 48c5c4113dSnw #include <sys/time.h> 49c5c4113dSnw #include <zone.h> 50c5c4113dSnw #include <door.h> 51c8e26105Sjp #include <port.h> 52c5c4113dSnw #include <tsol/label.h> 53c5c4113dSnw #include <sys/resource.h> 54c5c4113dSnw #include <sys/sid.h> 55c5c4113dSnw #include <sys/idmap.h> 56bcced03bSjp #include <pthread.h> 57148c5f43SAlan Wright #include <stdarg.h> 58148c5f43SAlan Wright #include <assert.h> 59148c5f43SAlan Wright #include <note.h> 60c5c4113dSnw 61b3700b07SGordon Ross #define CBUFSIZ 26 /* ctime(3c) */ 62b3700b07SGordon Ross 63c5c4113dSnw static void term_handler(int); 64c5c4113dSnw static void init_idmapd(); 65c5c4113dSnw static void fini_idmapd(); 66c5c4113dSnw 67b3700b07SGordon Ross /* The DC Locator lives inside idmap (for now). */ 68b3700b07SGordon Ross extern void init_dc_locator(void); 69b3700b07SGordon Ross extern void fini_dc_locator(void); 70b3700b07SGordon Ross 71c5c4113dSnw idmapd_state_t _idmapdstate; 72*60414d47SToomas Soome mutex_t _svcstate_lock = ERRORCHECKMUTEX; 73c5c4113dSnw 74c5c4113dSnw SVCXPRT *xprt = NULL; 75c5c4113dSnw 76c5c4113dSnw static int dfd = -1; /* our door server fildes, for unregistration */ 77148c5f43SAlan Wright static boolean_t degraded = B_FALSE; 78c5c4113dSnw 79bcced03bSjp 80bcced03bSjp static uint32_t num_threads = 0; 81bcced03bSjp static pthread_key_t create_threads_key; 82bcced03bSjp static uint32_t max_threads = 40; 83bcced03bSjp 84bcced03bSjp /* 85bcced03bSjp * Server door thread start routine. 86bcced03bSjp * 87bcced03bSjp * Set a TSD value to the door thread. This enables the destructor to 88fea136a0SMatt Barden * be called when this thread exits. Note that we need a non-NULL 89fea136a0SMatt Barden * value for this or the TSD destructor is not called. 90bcced03bSjp */ 91bcced03bSjp /*ARGSUSED*/ 92bcced03bSjp static void * 93bcced03bSjp idmapd_door_thread_start(void *arg) 94bcced03bSjp { 95fea136a0SMatt Barden static void *value = "NON-NULL TSD"; 96bcced03bSjp 97bcced03bSjp /* 98bcced03bSjp * Disable cancellation to avoid memory leaks from not running 99bcced03bSjp * the thread cleanup code. 100bcced03bSjp */ 101bcced03bSjp (void) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); 102bcced03bSjp (void) pthread_setspecific(create_threads_key, value); 103bcced03bSjp (void) door_return(NULL, 0, NULL, 0); 104bcced03bSjp 105bcced03bSjp /* make lint happy */ 106bcced03bSjp return (NULL); 107bcced03bSjp } 108bcced03bSjp 109bcced03bSjp /* 110bcced03bSjp * Server door threads creation 111bcced03bSjp */ 112bcced03bSjp /*ARGSUSED*/ 113bcced03bSjp static void 114bcced03bSjp idmapd_door_thread_create(door_info_t *dip) 115bcced03bSjp { 116bcced03bSjp int num; 117bcced03bSjp pthread_t thread_id; 118bcced03bSjp 119bcced03bSjp if ((num = atomic_inc_32_nv(&num_threads)) > max_threads) { 120bcced03bSjp atomic_dec_32(&num_threads); 121bcced03bSjp idmapdlog(LOG_DEBUG, 122bcced03bSjp "thread creation refused - %d threads currently active", 123bcced03bSjp num - 1); 124bcced03bSjp return; 125bcced03bSjp } 126bcced03bSjp (void) pthread_create(&thread_id, NULL, idmapd_door_thread_start, NULL); 127bcced03bSjp idmapdlog(LOG_DEBUG, 128bcced03bSjp "created thread ID %d - %d threads currently active", 129bcced03bSjp thread_id, num); 130bcced03bSjp } 131bcced03bSjp 132bcced03bSjp /* 133bcced03bSjp * Server door thread cleanup 134bcced03bSjp */ 135bcced03bSjp /*ARGSUSED*/ 136bcced03bSjp static void 137bcced03bSjp idmapd_door_thread_cleanup(void *arg) 138bcced03bSjp { 139bcced03bSjp int num; 140bcced03bSjp 141fea136a0SMatt Barden /* set TSD to NULL so we don't loop infinitely */ 142fea136a0SMatt Barden (void) pthread_setspecific(create_threads_key, NULL); 143bcced03bSjp num = atomic_dec_32_nv(&num_threads); 144bcced03bSjp idmapdlog(LOG_DEBUG, 145bcced03bSjp "exiting thread ID %d - %d threads currently active", 146bcced03bSjp pthread_self(), num); 147bcced03bSjp } 148bcced03bSjp 149c5c4113dSnw /* 150c5c4113dSnw * This is needed for mech_krb5 -- we run as daemon, yes, but we want 15178b2cb9aSnw * mech_krb5 to think we're root so it can get host/nodename.fqdn 15278b2cb9aSnw * tickets for us so we can authenticate to AD as the machine account 15378b2cb9aSnw * that we are. For more details look at the entry point in mech_krb5 15478b2cb9aSnw * corresponding to gss_init_sec_context(). 15578b2cb9aSnw * 15678b2cb9aSnw * As a side effect of faking our effective UID to mech_krb5 we will use 15778b2cb9aSnw * root's default ccache (/tmp/krb5cc_0). But if that's created by 15878b2cb9aSnw * another process then we won't have access to it: we run as daemon and 15978b2cb9aSnw * keep PRIV_FILE_DAC_READ, which is insufficient to share the ccache 16078b2cb9aSnw * with others. We putenv("KRB5CCNAME=/var/run/idmap/ccache") in main() 16178b2cb9aSnw * to avoid this issue; see main(). 162c5c4113dSnw * 163c5c4113dSnw * Someday we'll have gss/mech_krb5 extensions for acquiring initiator 164c5c4113dSnw * creds with keytabs/raw keys, and someday we'll have extensions to 165c5c4113dSnw * libsasl to specify creds/name to use on the initiator side, and 166c5c4113dSnw * someday we'll have extensions to libldap to pass those through to 167c5c4113dSnw * libsasl. Until then this interposer will have to do. 168c5c4113dSnw * 169c5c4113dSnw * Also, we have to tell lint to shut up: it thinks app_krb5_user_uid() 170c5c4113dSnw * is defined but not used. 171c5c4113dSnw */ 172c5c4113dSnw /*LINTLIBRARY*/ 173c5c4113dSnw uid_t 174c5c4113dSnw app_krb5_user_uid(void) 175c5c4113dSnw { 176c5c4113dSnw return (0); 177c5c4113dSnw } 178c5c4113dSnw 179c5c4113dSnw /*ARGSUSED*/ 180c5c4113dSnw static void 1814edd44c5Sjp term_handler(int sig) 1824edd44c5Sjp { 18371590c90Snw idmapdlog(LOG_INFO, "Terminating."); 184b3700b07SGordon Ross fini_dc_locator(); 185c5c4113dSnw fini_idmapd(); 186c5c4113dSnw _exit(0); 187c5c4113dSnw } 188c5c4113dSnw 18971590c90Snw /*ARGSUSED*/ 19071590c90Snw static void 19171590c90Snw usr1_handler(int sig) 19271590c90Snw { 193148c5f43SAlan Wright NOTE(ARGUNUSED(sig)) 19471590c90Snw print_idmapdstate(); 19571590c90Snw } 19671590c90Snw 197c5c4113dSnw static int pipe_fd = -1; 198c5c4113dSnw 199c5c4113dSnw static void 2004edd44c5Sjp daemonize_ready(void) 2014edd44c5Sjp { 202c5c4113dSnw char data = '\0'; 203c5c4113dSnw /* 204c5c4113dSnw * wake the parent 205c5c4113dSnw */ 206c5c4113dSnw (void) write(pipe_fd, &data, 1); 207c5c4113dSnw (void) close(pipe_fd); 208c5c4113dSnw } 209c5c4113dSnw 210c5c4113dSnw static int 2114edd44c5Sjp daemonize_start(void) 2124edd44c5Sjp { 213c5c4113dSnw char data; 214c5c4113dSnw int status; 215c5c4113dSnw int devnull; 216c5c4113dSnw int filedes[2]; 217c5c4113dSnw pid_t pid; 218c5c4113dSnw 21978b2cb9aSnw (void) sigset(SIGPIPE, SIG_IGN); 220c5c4113dSnw devnull = open("/dev/null", O_RDONLY); 221c5c4113dSnw if (devnull < 0) 222c5c4113dSnw return (-1); 223c5c4113dSnw (void) dup2(devnull, 0); 224c5c4113dSnw (void) dup2(2, 1); /* stderr only */ 225c5c4113dSnw if (pipe(filedes) < 0) 226c5c4113dSnw return (-1); 227c5c4113dSnw if ((pid = fork1()) < 0) 228c5c4113dSnw return (-1); 229c5c4113dSnw if (pid != 0) { 230c5c4113dSnw /* 231c5c4113dSnw * parent 232c5c4113dSnw */ 233c5c4113dSnw (void) close(filedes[1]); 234c5c4113dSnw if (read(filedes[0], &data, 1) == 1) { 235c5c4113dSnw /* presume success */ 236c5c4113dSnw _exit(0); 237c5c4113dSnw } 238c5c4113dSnw status = -1; 239c5c4113dSnw (void) wait4(pid, &status, 0, NULL); 240c5c4113dSnw if (WIFEXITED(status)) 241c5c4113dSnw _exit(WEXITSTATUS(status)); 242c5c4113dSnw else 243c5c4113dSnw _exit(-1); 244c5c4113dSnw } 245c5c4113dSnw 246c5c4113dSnw /* 247c5c4113dSnw * child 248c5c4113dSnw */ 249c5c4113dSnw pipe_fd = filedes[1]; 250c5c4113dSnw (void) close(filedes[0]); 251c5c4113dSnw (void) setsid(); 252c5c4113dSnw (void) umask(0077); 253c5c4113dSnw openlog("idmap", LOG_PID, LOG_DAEMON); 254479ac375Sdm 255c5c4113dSnw return (0); 256c5c4113dSnw } 257c5c4113dSnw 258c5c4113dSnw 259c5c4113dSnw int 260c5c4113dSnw main(int argc, char **argv) 261c5c4113dSnw { 262c5c4113dSnw int c; 2632b3ecdebSjp struct rlimit rl; 264c5c4113dSnw 265b3700b07SGordon Ross if (rwlock_init(&_idmapdstate.rwlk_cfg, USYNC_THREAD, NULL) != 0) 266b3700b07SGordon Ross return (-1); 267b3700b07SGordon Ross if (mutex_init(&_idmapdstate.addisc_lk, USYNC_THREAD, NULL) != 0) 268b3700b07SGordon Ross return (-1); 269b3700b07SGordon Ross if (cond_init(&_idmapdstate.addisc_cv, USYNC_THREAD, NULL) != 0) 270b3700b07SGordon Ross return (-1); 271b3700b07SGordon Ross 27271590c90Snw _idmapdstate.daemon_mode = TRUE; 27371590c90Snw while ((c = getopt(argc, argv, "d")) != -1) { 274c5c4113dSnw switch (c) { 275c5c4113dSnw case 'd': 27671590c90Snw _idmapdstate.daemon_mode = FALSE; 277c5c4113dSnw break; 278c5c4113dSnw default: 279bbf6f00cSJordan Brown (void) fprintf(stderr, 280bbf6f00cSJordan Brown "Usage: /usr/lib/idmapd [-d]\n"); 28171590c90Snw return (SMF_EXIT_ERR_CONFIG); 282c5c4113dSnw } 283c5c4113dSnw } 284c5c4113dSnw 285c5c4113dSnw /* set locale and domain for internationalization */ 286c5c4113dSnw (void) setlocale(LC_ALL, ""); 287c5c4113dSnw (void) textdomain(TEXT_DOMAIN); 288c5c4113dSnw 2897a8a68f5SJulian Pullen idmap_set_logger(idmapdlog); 290c5866007SKeyur Desai adutils_set_logger(idmapdlog); 291479ac375Sdm 292bda89588Sjp if (is_system_labeled() && getzoneid() != GLOBAL_ZONEID) { 29371590c90Snw idmapdlog(LOG_ERR, 29471590c90Snw "with Trusted Extensions idmapd runs only in the " 295bda89588Sjp "global zone"); 296c5c4113dSnw exit(1); 297c5c4113dSnw } 298c5c4113dSnw 2992b3ecdebSjp /* 3002b3ecdebSjp * Raise the fd limit to max 3012b3ecdebSjp */ 3022b3ecdebSjp if (getrlimit(RLIMIT_NOFILE, &rl) != 0) { 3032b3ecdebSjp idmapdlog(LOG_ERR, "getrlimit failed"); 3042b3ecdebSjp } else if (rl.rlim_cur < rl.rlim_max) { 3052b3ecdebSjp rl.rlim_cur = rl.rlim_max; 3062b3ecdebSjp if (setrlimit(RLIMIT_NOFILE, &rl) != 0) 3072b3ecdebSjp idmapdlog(LOG_ERR, 3082b3ecdebSjp "Unable to raise RLIMIT_NOFILE to %d", 3092b3ecdebSjp rl.rlim_cur); 3102b3ecdebSjp } 3112b3ecdebSjp 31271590c90Snw if (_idmapdstate.daemon_mode == TRUE) { 313c5c4113dSnw if (daemonize_start() < 0) { 3147a8a68f5SJulian Pullen idmapdlog(LOG_ERR, "unable to daemonize"); 315c5c4113dSnw exit(-1); 316c5c4113dSnw } 317c5c4113dSnw } else 318c5c4113dSnw (void) umask(0077); 319c5c4113dSnw 32084decf41Sjp idmap_init_tsd_key(); 32184decf41Sjp 322c5c4113dSnw init_idmapd(); 323b3700b07SGordon Ross init_dc_locator(); 324c5c4113dSnw 32578b2cb9aSnw /* signal handlers that should run only after we're initialized */ 32678b2cb9aSnw (void) sigset(SIGTERM, term_handler); 32771590c90Snw (void) sigset(SIGUSR1, usr1_handler); 3280dcc7149Snw (void) sigset(SIGHUP, idmap_cfg_hup_handler); 32978b2cb9aSnw 330c5c4113dSnw if (__init_daemon_priv(PU_RESETGROUPS|PU_CLEARLIMITSET, 331c5c4113dSnw DAEMON_UID, DAEMON_GID, 332c5c4113dSnw PRIV_PROC_AUDIT, PRIV_FILE_DAC_READ, 333c5c4113dSnw (char *)NULL) == -1) { 33471590c90Snw idmapdlog(LOG_ERR, "unable to drop privileges"); 335c5c4113dSnw exit(1); 336c5c4113dSnw } 337c5c4113dSnw 338c5c4113dSnw __fini_daemon_priv(PRIV_PROC_FORK, PRIV_PROC_EXEC, PRIV_PROC_SESSION, 339c5c4113dSnw PRIV_FILE_LINK_ANY, PRIV_PROC_INFO, (char *)NULL); 340c5c4113dSnw 34171590c90Snw if (_idmapdstate.daemon_mode == TRUE) 342c5c4113dSnw daemonize_ready(); 343c5c4113dSnw 344c5c4113dSnw /* With doors RPC this just wastes this thread, oh well */ 345c5c4113dSnw svc_run(); 346c5c4113dSnw return (0); 347c5c4113dSnw } 348c5c4113dSnw 349c5c4113dSnw static void 3504edd44c5Sjp init_idmapd() 3514edd44c5Sjp { 352c5c4113dSnw int error; 353bcced03bSjp int connmaxrec = IDMAP_MAX_DOOR_RPC; 354bcced03bSjp 355c5c4113dSnw 35678b2cb9aSnw /* create directories as root and chown to daemon uid */ 35778b2cb9aSnw if (create_directory(IDMAP_DBDIR, DAEMON_UID, DAEMON_GID) < 0) 35878b2cb9aSnw exit(1); 35978b2cb9aSnw if (create_directory(IDMAP_CACHEDIR, DAEMON_UID, DAEMON_GID) < 0) 36078b2cb9aSnw exit(1); 36178b2cb9aSnw 36278b2cb9aSnw /* 36378b2cb9aSnw * Set KRB5CCNAME in the environment. See app_krb5_user_uid() 364e3c2d6aaSnw * for more details. We blow away the existing one, if there is 365e3c2d6aaSnw * one. 36678b2cb9aSnw */ 367e3c2d6aaSnw (void) unlink(IDMAP_CACHEDIR "/ccache"); 368148c5f43SAlan Wright (void) putenv("KRB5CCNAME=" IDMAP_CACHEDIR "/ccache"); 369b3700b07SGordon Ross (void) putenv("MS_INTEROP=1"); 37078b2cb9aSnw 371c5c4113dSnw if (sysinfo(SI_HOSTNAME, _idmapdstate.hostname, 3724edd44c5Sjp sizeof (_idmapdstate.hostname)) == -1) { 373c5c4113dSnw error = errno; 37471590c90Snw idmapdlog(LOG_ERR, "unable to determine hostname, error: %d", 3754edd44c5Sjp error); 376c5c4113dSnw exit(1); 377c5c4113dSnw } 378c5c4113dSnw 379e8c27ec8Sbaban if ((error = init_mapping_system()) < 0) { 38071590c90Snw idmapdlog(LOG_ERR, "unable to initialize mapping system"); 381e8c27ec8Sbaban exit(error < -2 ? SMF_EXIT_ERR_CONFIG : 1); 382c5c4113dSnw } 383c5c4113dSnw 384fea136a0SMatt Barden /* 385fea136a0SMatt Barden * This means max_threads can't be updated without restarting idmap. 386fea136a0SMatt Barden */ 387fea136a0SMatt Barden RDLOCK_CONFIG(); 388fea136a0SMatt Barden max_threads = _idmapdstate.cfg->pgcfg.max_threads; 389fea136a0SMatt Barden UNLOCK_CONFIG(); 390fea136a0SMatt Barden 391bcced03bSjp (void) door_server_create(idmapd_door_thread_create); 392bcced03bSjp if ((error = pthread_key_create(&create_threads_key, 393bcced03bSjp idmapd_door_thread_cleanup)) != 0) { 394bcced03bSjp idmapdlog(LOG_ERR, "unable to create threads key (%s)", 395bcced03bSjp strerror(error)); 396bcced03bSjp goto errout; 397bcced03bSjp } 398bcced03bSjp 399d3a612caSnw xprt = svc_door_create(idmap_prog_1, IDMAP_PROG, IDMAP_V1, connmaxrec); 400c5c4113dSnw if (xprt == NULL) { 40171590c90Snw idmapdlog(LOG_ERR, "unable to create door RPC service"); 402c5c4113dSnw goto errout; 403c5c4113dSnw } 404c5c4113dSnw 4058e228215Sdm if (!svc_control(xprt, SVCSET_CONNMAXREC, &connmaxrec)) { 40671590c90Snw idmapdlog(LOG_ERR, "unable to limit RPC request size"); 4078e228215Sdm goto errout; 4088e228215Sdm } 4098e228215Sdm 410c5c4113dSnw dfd = xprt->xp_fd; 411c5c4113dSnw 412c5c4113dSnw if (dfd == -1) { 41371590c90Snw idmapdlog(LOG_ERR, "unable to register door"); 414c5c4113dSnw goto errout; 415c5c4113dSnw } 4169fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States if ((error = __idmap_reg(dfd)) != 0) { 41771590c90Snw idmapdlog(LOG_ERR, "unable to register door (%s)", 4184edd44c5Sjp strerror(errno)); 419c5c4113dSnw goto errout; 420c5c4113dSnw } 421c5c4113dSnw 422c5c4113dSnw if ((error = allocids(_idmapdstate.new_eph_db, 4234edd44c5Sjp 8192, &_idmapdstate.next_uid, 4244edd44c5Sjp 8192, &_idmapdstate.next_gid)) != 0) { 42571590c90Snw idmapdlog(LOG_ERR, "unable to allocate ephemeral IDs (%s)", 42671590c90Snw strerror(errno)); 4279fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States _idmapdstate.next_uid = IDMAP_SENTINEL_PID; 4289fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States _idmapdstate.limit_uid = IDMAP_SENTINEL_PID; 4299fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States _idmapdstate.next_gid = IDMAP_SENTINEL_PID; 4309fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States _idmapdstate.limit_gid = IDMAP_SENTINEL_PID; 431c5c4113dSnw } else { 432c5c4113dSnw _idmapdstate.limit_uid = _idmapdstate.next_uid + 8192; 433c5c4113dSnw _idmapdstate.limit_gid = _idmapdstate.next_gid + 8192; 434c5c4113dSnw } 435c5c4113dSnw 436148c5f43SAlan Wright if (DBG(CONFIG, 1)) 437148c5f43SAlan Wright print_idmapdstate(); 438c5c4113dSnw 439c5c4113dSnw return; 440c5c4113dSnw 441c5c4113dSnw errout: 442c5c4113dSnw fini_idmapd(); 443c5c4113dSnw exit(1); 444c5c4113dSnw } 445c5c4113dSnw 446c5c4113dSnw static void 4474edd44c5Sjp fini_idmapd() 4484edd44c5Sjp { 449148c5f43SAlan Wright (void) __idmap_unreg(dfd); 450c5c4113dSnw fini_mapping_system(); 451c5c4113dSnw if (xprt != NULL) 452c5c4113dSnw svc_destroy(xprt); 453c5c4113dSnw } 454c5c4113dSnw 45571590c90Snw static 45671590c90Snw const char * 45771590c90Snw get_fmri(void) 45871590c90Snw { 45971590c90Snw static char *fmri = NULL; 46071590c90Snw static char buf[60]; 46171590c90Snw char *s; 46271590c90Snw 46371590c90Snw membar_consumer(); 46471590c90Snw s = fmri; 46571590c90Snw if (s != NULL && *s == '\0') 46671590c90Snw return (NULL); 46771590c90Snw else if (s != NULL) 46871590c90Snw return (s); 46971590c90Snw 47071590c90Snw if ((s = getenv("SMF_FMRI")) == NULL || strlen(s) >= sizeof (buf)) 47171590c90Snw buf[0] = '\0'; 47271590c90Snw else 47371590c90Snw (void) strlcpy(buf, s, sizeof (buf)); 47471590c90Snw 47571590c90Snw membar_producer(); 47671590c90Snw fmri = buf; 47771590c90Snw 47871590c90Snw return (get_fmri()); 47971590c90Snw } 48071590c90Snw 48171590c90Snw /* 48271590c90Snw * Wrappers for smf_degrade/restore_instance() 48371590c90Snw * 48471590c90Snw * smf_restore_instance() is too heavy duty to be calling every time we 48571590c90Snw * have a successful AD name<->SID lookup. 48671590c90Snw */ 48771590c90Snw void 488349d5d8fSnw degrade_svc(int poke_discovery, const char *reason) 48971590c90Snw { 49071590c90Snw const char *fmri; 49171590c90Snw 49271590c90Snw membar_consumer(); 49371590c90Snw if (degraded) 49471590c90Snw return; 495349d5d8fSnw 496148c5f43SAlan Wright idmapdlog(LOG_ERR, "Degraded operation (%s).", reason); 497349d5d8fSnw 49871590c90Snw membar_producer(); 499148c5f43SAlan Wright degraded = B_TRUE; 50071590c90Snw 50171590c90Snw if ((fmri = get_fmri()) != NULL) 50271590c90Snw (void) smf_degrade_instance(fmri, 0); 503c5866007SKeyur Desai 504c5866007SKeyur Desai /* 505c5866007SKeyur Desai * If the config update thread is in a state where auto-discovery could 506c5866007SKeyur Desai * be re-tried, then this will make it try it -- a sort of auto-refresh. 507c5866007SKeyur Desai */ 508c5866007SKeyur Desai if (poke_discovery) 509c5866007SKeyur Desai idmap_cfg_poke_updates(); 51071590c90Snw } 51171590c90Snw 51271590c90Snw void 51371590c90Snw restore_svc(void) 51471590c90Snw { 51571590c90Snw const char *fmri; 51671590c90Snw 51771590c90Snw membar_consumer(); 51871590c90Snw if (!degraded) 51971590c90Snw return; 52071590c90Snw 52171590c90Snw if ((fmri = get_fmri()) == NULL) 52271590c90Snw (void) smf_restore_instance(fmri); 52371590c90Snw 52471590c90Snw membar_producer(); 525148c5f43SAlan Wright degraded = B_FALSE; 526479ac375Sdm 527349d5d8fSnw idmapdlog(LOG_NOTICE, "Normal operation restored"); 52871590c90Snw } 52971590c90Snw 5307a8a68f5SJulian Pullen 5317a8a68f5SJulian Pullen /* printflike */ 532c5c4113dSnw void 533fea136a0SMatt Barden idmapdlog(int pri, const char *format, ...) 534fea136a0SMatt Barden { 535b3700b07SGordon Ross static time_t prev_ts; 536c5c4113dSnw va_list args; 537b3700b07SGordon Ross char cbuf[CBUFSIZ]; 538b3700b07SGordon Ross time_t ts; 539b3700b07SGordon Ross 540b3700b07SGordon Ross ts = time(NULL); 541b3700b07SGordon Ross if (prev_ts != ts) { 542b3700b07SGordon Ross prev_ts = ts; 543b3700b07SGordon Ross /* NB: cbuf has \n */ 544b3700b07SGordon Ross (void) fprintf(stderr, "@ %s", 545b3700b07SGordon Ross ctime_r(&ts, cbuf, sizeof (cbuf))); 546b3700b07SGordon Ross } 547c5c4113dSnw 548148c5f43SAlan Wright va_start(args, format); 549148c5f43SAlan Wright (void) vfprintf(stderr, format, args); 550148c5f43SAlan Wright (void) fprintf(stderr, "\n"); 551148c5f43SAlan Wright va_end(args); 55271590c90Snw 55371590c90Snw /* 55471590c90Snw * We don't want to fill up the logs with useless messages when 55571590c90Snw * we're degraded, but we still want to log. 55671590c90Snw */ 557148c5f43SAlan Wright if (degraded) 55871590c90Snw pri = LOG_DEBUG; 55971590c90Snw 560148c5f43SAlan Wright va_start(args, format); 561148c5f43SAlan Wright vsyslog(pri, format, args); 562148c5f43SAlan Wright va_end(args); 5637a8a68f5SJulian Pullen } 5647a8a68f5SJulian Pullen 565148c5f43SAlan Wright static void 566148c5f43SAlan Wright trace_str(nvlist_t *entry, char *n1, char *n2, char *str) 5677a8a68f5SJulian Pullen { 568148c5f43SAlan Wright char name[IDMAP_TRACE_NAME_MAX+1]; /* Max used is only about 11 */ 569148c5f43SAlan Wright 570148c5f43SAlan Wright (void) strlcpy(name, n1, sizeof (name)); 571148c5f43SAlan Wright if (n2 != NULL) 572148c5f43SAlan Wright (void) strlcat(name, n2, sizeof (name)); 573148c5f43SAlan Wright 574148c5f43SAlan Wright (void) nvlist_add_string(entry, name, str); 5757a8a68f5SJulian Pullen } 5767a8a68f5SJulian Pullen 577148c5f43SAlan Wright static void 578148c5f43SAlan Wright trace_int(nvlist_t *entry, char *n1, char *n2, int64_t i) 5797a8a68f5SJulian Pullen { 580148c5f43SAlan Wright char name[IDMAP_TRACE_NAME_MAX+1]; /* Max used is only about 11 */ 581148c5f43SAlan Wright 582148c5f43SAlan Wright (void) strlcpy(name, n1, sizeof (name)); 583148c5f43SAlan Wright if (n2 != NULL) 584148c5f43SAlan Wright (void) strlcat(name, n2, sizeof (name)); 585148c5f43SAlan Wright 586148c5f43SAlan Wright (void) nvlist_add_int64(entry, name, i); 5877a8a68f5SJulian Pullen } 5887a8a68f5SJulian Pullen 589148c5f43SAlan Wright static void 590148c5f43SAlan Wright trace_sid(nvlist_t *entry, char *n1, char *n2, idmap_sid *sid) 591148c5f43SAlan Wright { 592148c5f43SAlan Wright char *str; 593148c5f43SAlan Wright 594148c5f43SAlan Wright (void) asprintf(&str, "%s-%u", sid->prefix, sid->rid); 595148c5f43SAlan Wright if (str == NULL) 596148c5f43SAlan Wright return; 597148c5f43SAlan Wright 598148c5f43SAlan Wright trace_str(entry, n1, n2, str); 599148c5f43SAlan Wright free(str); 600148c5f43SAlan Wright } 601148c5f43SAlan Wright 602148c5f43SAlan Wright static void 603148c5f43SAlan Wright trace_id(nvlist_t *entry, char *fromto, idmap_id *id, char *name, char *domain) 604148c5f43SAlan Wright { 605148c5f43SAlan Wright trace_int(entry, fromto, IDMAP_TRACE_TYPE, (int64_t)id->idtype); 606148c5f43SAlan Wright if (IS_ID_SID(*id)) { 607148c5f43SAlan Wright if (name != NULL) { 608148c5f43SAlan Wright char *str; 609148c5f43SAlan Wright 610148c5f43SAlan Wright (void) asprintf(&str, "%s%s%s", name, 611148c5f43SAlan Wright domain == NULL ? "" : "@", 612148c5f43SAlan Wright domain == NULL ? "" : domain); 613148c5f43SAlan Wright if (str != NULL) { 614148c5f43SAlan Wright trace_str(entry, fromto, IDMAP_TRACE_NAME, str); 615148c5f43SAlan Wright free(str); 616148c5f43SAlan Wright } 617148c5f43SAlan Wright } 618148c5f43SAlan Wright if (id->idmap_id_u.sid.prefix != NULL) { 619148c5f43SAlan Wright trace_sid(entry, fromto, IDMAP_TRACE_SID, 620148c5f43SAlan Wright &id->idmap_id_u.sid); 621148c5f43SAlan Wright } 622148c5f43SAlan Wright } else if (IS_ID_POSIX(*id)) { 623148c5f43SAlan Wright if (name != NULL) 624148c5f43SAlan Wright trace_str(entry, fromto, IDMAP_TRACE_NAME, name); 625148c5f43SAlan Wright if (id->idmap_id_u.uid != IDMAP_SENTINEL_PID) { 626148c5f43SAlan Wright trace_int(entry, fromto, IDMAP_TRACE_UNIXID, 627148c5f43SAlan Wright (int64_t)id->idmap_id_u.uid); 628148c5f43SAlan Wright } 629148c5f43SAlan Wright } 630148c5f43SAlan Wright } 631148c5f43SAlan Wright 632148c5f43SAlan Wright /* 633148c5f43SAlan Wright * Record a trace event. TRACE() has already decided whether or not 634148c5f43SAlan Wright * tracing is required; what we do here is collect the data and send it 635148c5f43SAlan Wright * to its destination - to the trace log in the response, if 636148c5f43SAlan Wright * IDMAP_REQ_FLG_TRACE is set, and to the SMF service log, if debug/mapping 637148c5f43SAlan Wright * is greater than zero. 638148c5f43SAlan Wright */ 639148c5f43SAlan Wright int 640148c5f43SAlan Wright trace(idmap_mapping *req, idmap_id_res *res, char *fmt, ...) 6417a8a68f5SJulian Pullen { 642148c5f43SAlan Wright va_list va; 643148c5f43SAlan Wright char *buf; 644148c5f43SAlan Wright int err; 645148c5f43SAlan Wright nvlist_t *entry; 646148c5f43SAlan Wright 647148c5f43SAlan Wright assert(req != NULL); 648148c5f43SAlan Wright assert(res != NULL); 649148c5f43SAlan Wright 650148c5f43SAlan Wright err = nvlist_alloc(&entry, NV_UNIQUE_NAME, 0); 651148c5f43SAlan Wright if (err != 0) { 652148c5f43SAlan Wright (void) fprintf(stderr, "trace nvlist_alloc(entry): %s\n", 653148c5f43SAlan Wright strerror(err)); 654148c5f43SAlan Wright return (0); 655148c5f43SAlan Wright } 656148c5f43SAlan Wright 657148c5f43SAlan Wright trace_id(entry, "from", &req->id1, req->id1name, req->id1domain); 658148c5f43SAlan Wright trace_id(entry, "to", &res->id, req->id2name, req->id2domain); 659148c5f43SAlan Wright 660148c5f43SAlan Wright if (IDMAP_ERROR(res->retcode)) { 661148c5f43SAlan Wright trace_int(entry, IDMAP_TRACE_ERROR, NULL, 662148c5f43SAlan Wright (int64_t)res->retcode); 663148c5f43SAlan Wright } 664148c5f43SAlan Wright 665148c5f43SAlan Wright va_start(va, fmt); 666148c5f43SAlan Wright (void) vasprintf(&buf, fmt, va); 667148c5f43SAlan Wright va_end(va); 668148c5f43SAlan Wright if (buf != NULL) { 669148c5f43SAlan Wright trace_str(entry, IDMAP_TRACE_MESSAGE, NULL, buf); 670148c5f43SAlan Wright free(buf); 671148c5f43SAlan Wright } 672148c5f43SAlan Wright 673148c5f43SAlan Wright if (DBG(MAPPING, 1)) 674148c5f43SAlan Wright idmap_trace_print_1(stderr, "", entry); 675148c5f43SAlan Wright 676148c5f43SAlan Wright if (req->flag & IDMAP_REQ_FLG_TRACE) { 677148c5f43SAlan Wright /* Lazily allocate the trace list */ 678148c5f43SAlan Wright if (res->info.trace == NULL) { 679148c5f43SAlan Wright err = nvlist_alloc(&res->info.trace, 0, 0); 680148c5f43SAlan Wright if (err != 0) { 681148c5f43SAlan Wright res->info.trace = NULL; /* just in case */ 682148c5f43SAlan Wright (void) fprintf(stderr, 683148c5f43SAlan Wright "trace nvlist_alloc(trace): %s\n", 684148c5f43SAlan Wright strerror(err)); 685148c5f43SAlan Wright nvlist_free(entry); 686148c5f43SAlan Wright return (0); 687148c5f43SAlan Wright } 688148c5f43SAlan Wright } 689148c5f43SAlan Wright (void) nvlist_add_nvlist(res->info.trace, "", entry); 690148c5f43SAlan Wright /* Note that entry is copied, so we must still free our copy */ 691148c5f43SAlan Wright } 692148c5f43SAlan Wright 693148c5f43SAlan Wright nvlist_free(entry); 694148c5f43SAlan Wright 695148c5f43SAlan Wright return (0); 696c5c4113dSnw } 697