14520Snw141292 /* 24520Snw141292 * CDDL HEADER START 34520Snw141292 * 44520Snw141292 * The contents of this file are subject to the terms of the 54520Snw141292 * Common Development and Distribution License (the "License"). 64520Snw141292 * You may not use this file except in compliance with the License. 74520Snw141292 * 84520Snw141292 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 94520Snw141292 * or http://www.opensolaris.org/os/licensing. 104520Snw141292 * See the License for the specific language governing permissions 114520Snw141292 * and limitations under the License. 124520Snw141292 * 134520Snw141292 * When distributing Covered Code, include this CDDL HEADER in each 144520Snw141292 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 154520Snw141292 * If applicable, add the following below this CDDL HEADER, with the 164520Snw141292 * fields enclosed by brackets "[]" replaced with your own identifying 174520Snw141292 * information: Portions Copyright [yyyy] [name of copyright owner] 184520Snw141292 * 194520Snw141292 * CDDL HEADER END 204520Snw141292 */ 214520Snw141292 /* 2212065SKeyur.Desai@Sun.COM * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. 234520Snw141292 */ 244520Snw141292 254520Snw141292 264520Snw141292 /* 274520Snw141292 * main() of idmapd(1M) 284520Snw141292 */ 294520Snw141292 304520Snw141292 #include "idmapd.h" 316017Snw141292 #include <atomic.h> 324520Snw141292 #include <signal.h> 334520Snw141292 #include <rpc/pmap_clnt.h> /* for pmap_unset */ 344520Snw141292 #include <string.h> /* strcmp */ 354520Snw141292 #include <unistd.h> /* setsid */ 364520Snw141292 #include <sys/types.h> 374520Snw141292 #include <memory.h> 384520Snw141292 #include <stropts.h> 394520Snw141292 #include <netconfig.h> 404520Snw141292 #include <sys/resource.h> /* rlimit */ 414520Snw141292 #include <rpcsvc/daemon_utils.h> /* DAEMON_UID and DAEMON_GID */ 424520Snw141292 #include <priv_utils.h> /* privileges */ 434520Snw141292 #include <locale.h> 444520Snw141292 #include <sys/systeminfo.h> 454520Snw141292 #include <errno.h> 464520Snw141292 #include <sys/wait.h> 474520Snw141292 #include <sys/time.h> 484520Snw141292 #include <zone.h> 494520Snw141292 #include <door.h> 505317Sjp151216 #include <port.h> 514520Snw141292 #include <tsol/label.h> 524520Snw141292 #include <sys/resource.h> 534520Snw141292 #include <sys/sid.h> 544520Snw141292 #include <sys/idmap.h> 556531Sjp151216 #include <pthread.h> 56*12508Samw@Sun.COM #include <stdarg.h> 57*12508Samw@Sun.COM #include <assert.h> 58*12508Samw@Sun.COM #include <note.h> 594520Snw141292 604520Snw141292 static void term_handler(int); 614520Snw141292 static void init_idmapd(); 624520Snw141292 static void fini_idmapd(); 634520Snw141292 644520Snw141292 idmapd_state_t _idmapdstate; 654520Snw141292 664520Snw141292 SVCXPRT *xprt = NULL; 674520Snw141292 684520Snw141292 static int dfd = -1; /* our door server fildes, for unregistration */ 69*12508Samw@Sun.COM static boolean_t degraded = B_FALSE; 704520Snw141292 716531Sjp151216 726531Sjp151216 static uint32_t num_threads = 0; 736531Sjp151216 static pthread_key_t create_threads_key; 746531Sjp151216 static uint32_t max_threads = 40; 756531Sjp151216 766531Sjp151216 /* 776531Sjp151216 * Server door thread start routine. 786531Sjp151216 * 796531Sjp151216 * Set a TSD value to the door thread. This enables the destructor to 806531Sjp151216 * be called when this thread exits. 816531Sjp151216 */ 826531Sjp151216 /*ARGSUSED*/ 836531Sjp151216 static void * 846531Sjp151216 idmapd_door_thread_start(void *arg) 856531Sjp151216 { 866531Sjp151216 static void *value = 0; 876531Sjp151216 886531Sjp151216 /* 896531Sjp151216 * Disable cancellation to avoid memory leaks from not running 906531Sjp151216 * the thread cleanup code. 916531Sjp151216 */ 926531Sjp151216 (void) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); 936531Sjp151216 (void) pthread_setspecific(create_threads_key, value); 946531Sjp151216 (void) door_return(NULL, 0, NULL, 0); 956531Sjp151216 966531Sjp151216 /* make lint happy */ 976531Sjp151216 return (NULL); 986531Sjp151216 } 996531Sjp151216 1006531Sjp151216 /* 1016531Sjp151216 * Server door threads creation 1026531Sjp151216 */ 1036531Sjp151216 /*ARGSUSED*/ 1046531Sjp151216 static void 1056531Sjp151216 idmapd_door_thread_create(door_info_t *dip) 1066531Sjp151216 { 1076531Sjp151216 int num; 1086531Sjp151216 pthread_t thread_id; 1096531Sjp151216 1106531Sjp151216 if ((num = atomic_inc_32_nv(&num_threads)) > max_threads) { 1116531Sjp151216 atomic_dec_32(&num_threads); 1126531Sjp151216 idmapdlog(LOG_DEBUG, 1136531Sjp151216 "thread creation refused - %d threads currently active", 1146531Sjp151216 num - 1); 1156531Sjp151216 return; 1166531Sjp151216 } 1176531Sjp151216 (void) pthread_create(&thread_id, NULL, idmapd_door_thread_start, NULL); 1186531Sjp151216 idmapdlog(LOG_DEBUG, 1196531Sjp151216 "created thread ID %d - %d threads currently active", 1206531Sjp151216 thread_id, num); 1216531Sjp151216 } 1226531Sjp151216 1236531Sjp151216 /* 1246531Sjp151216 * Server door thread cleanup 1256531Sjp151216 */ 1266531Sjp151216 /*ARGSUSED*/ 1276531Sjp151216 static void 1286531Sjp151216 idmapd_door_thread_cleanup(void *arg) 1296531Sjp151216 { 1306531Sjp151216 int num; 1316531Sjp151216 1326531Sjp151216 num = atomic_dec_32_nv(&num_threads); 1336531Sjp151216 idmapdlog(LOG_DEBUG, 1346531Sjp151216 "exiting thread ID %d - %d threads currently active", 1356531Sjp151216 pthread_self(), num); 1366531Sjp151216 } 1376531Sjp151216 1384520Snw141292 /* 1394520Snw141292 * This is needed for mech_krb5 -- we run as daemon, yes, but we want 1405034Snw141292 * mech_krb5 to think we're root so it can get host/nodename.fqdn 1415034Snw141292 * tickets for us so we can authenticate to AD as the machine account 1425034Snw141292 * that we are. For more details look at the entry point in mech_krb5 1435034Snw141292 * corresponding to gss_init_sec_context(). 1445034Snw141292 * 1455034Snw141292 * As a side effect of faking our effective UID to mech_krb5 we will use 1465034Snw141292 * root's default ccache (/tmp/krb5cc_0). But if that's created by 1475034Snw141292 * another process then we won't have access to it: we run as daemon and 1485034Snw141292 * keep PRIV_FILE_DAC_READ, which is insufficient to share the ccache 1495034Snw141292 * with others. We putenv("KRB5CCNAME=/var/run/idmap/ccache") in main() 1505034Snw141292 * to avoid this issue; see main(). 1514520Snw141292 * 1524520Snw141292 * Someday we'll have gss/mech_krb5 extensions for acquiring initiator 1534520Snw141292 * creds with keytabs/raw keys, and someday we'll have extensions to 1544520Snw141292 * libsasl to specify creds/name to use on the initiator side, and 1554520Snw141292 * someday we'll have extensions to libldap to pass those through to 1564520Snw141292 * libsasl. Until then this interposer will have to do. 1574520Snw141292 * 1584520Snw141292 * Also, we have to tell lint to shut up: it thinks app_krb5_user_uid() 1594520Snw141292 * is defined but not used. 1604520Snw141292 */ 1614520Snw141292 /*LINTLIBRARY*/ 1624520Snw141292 uid_t 1634520Snw141292 app_krb5_user_uid(void) 1644520Snw141292 { 1654520Snw141292 return (0); 1664520Snw141292 } 1674520Snw141292 1684520Snw141292 /*ARGSUSED*/ 1694520Snw141292 static void 1705908Sjp151216 term_handler(int sig) 1715908Sjp151216 { 1726017Snw141292 idmapdlog(LOG_INFO, "Terminating."); 1734520Snw141292 fini_idmapd(); 1744520Snw141292 _exit(0); 1754520Snw141292 } 1764520Snw141292 1776017Snw141292 /*ARGSUSED*/ 1786017Snw141292 static void 1796017Snw141292 usr1_handler(int sig) 1806017Snw141292 { 181*12508Samw@Sun.COM NOTE(ARGUNUSED(sig)) 1826017Snw141292 print_idmapdstate(); 1836017Snw141292 } 1846017Snw141292 1854520Snw141292 static int pipe_fd = -1; 1864520Snw141292 1874520Snw141292 static void 1885908Sjp151216 daemonize_ready(void) 1895908Sjp151216 { 1904520Snw141292 char data = '\0'; 1914520Snw141292 /* 1924520Snw141292 * wake the parent 1934520Snw141292 */ 1944520Snw141292 (void) write(pipe_fd, &data, 1); 1954520Snw141292 (void) close(pipe_fd); 1964520Snw141292 } 1974520Snw141292 1984520Snw141292 static int 1995908Sjp151216 daemonize_start(void) 2005908Sjp151216 { 2014520Snw141292 char data; 2024520Snw141292 int status; 2034520Snw141292 int devnull; 2044520Snw141292 int filedes[2]; 2054520Snw141292 pid_t pid; 2064520Snw141292 2075034Snw141292 (void) sigset(SIGPIPE, SIG_IGN); 2084520Snw141292 devnull = open("/dev/null", O_RDONLY); 2094520Snw141292 if (devnull < 0) 2104520Snw141292 return (-1); 2114520Snw141292 (void) dup2(devnull, 0); 2124520Snw141292 (void) dup2(2, 1); /* stderr only */ 2134520Snw141292 if (pipe(filedes) < 0) 2144520Snw141292 return (-1); 2154520Snw141292 if ((pid = fork1()) < 0) 2164520Snw141292 return (-1); 2174520Snw141292 if (pid != 0) { 2184520Snw141292 /* 2194520Snw141292 * parent 2204520Snw141292 */ 2214520Snw141292 (void) close(filedes[1]); 2224520Snw141292 if (read(filedes[0], &data, 1) == 1) { 2234520Snw141292 /* presume success */ 2244520Snw141292 _exit(0); 2254520Snw141292 } 2264520Snw141292 status = -1; 2274520Snw141292 (void) wait4(pid, &status, 0, NULL); 2284520Snw141292 if (WIFEXITED(status)) 2294520Snw141292 _exit(WEXITSTATUS(status)); 2304520Snw141292 else 2314520Snw141292 _exit(-1); 2324520Snw141292 } 2334520Snw141292 2344520Snw141292 /* 2354520Snw141292 * child 2364520Snw141292 */ 2374520Snw141292 pipe_fd = filedes[1]; 2384520Snw141292 (void) close(filedes[0]); 2394520Snw141292 (void) setsid(); 2404520Snw141292 (void) umask(0077); 2414520Snw141292 openlog("idmap", LOG_PID, LOG_DAEMON); 2426616Sdm199847 2434520Snw141292 return (0); 2444520Snw141292 } 2454520Snw141292 2464520Snw141292 2474520Snw141292 int 2484520Snw141292 main(int argc, char **argv) 2494520Snw141292 { 2504520Snw141292 int c; 2516414Sjp151216 struct rlimit rl; 2524520Snw141292 2536017Snw141292 _idmapdstate.daemon_mode = TRUE; 2546017Snw141292 while ((c = getopt(argc, argv, "d")) != -1) { 2554520Snw141292 switch (c) { 2564520Snw141292 case 'd': 2576017Snw141292 _idmapdstate.daemon_mode = FALSE; 2584520Snw141292 break; 2594520Snw141292 default: 26010966SJordan.Brown@Sun.COM (void) fprintf(stderr, 26110966SJordan.Brown@Sun.COM "Usage: /usr/lib/idmapd [-d]\n"); 2626017Snw141292 return (SMF_EXIT_ERR_CONFIG); 2634520Snw141292 } 2644520Snw141292 } 2654520Snw141292 2664520Snw141292 /* set locale and domain for internationalization */ 2674520Snw141292 (void) setlocale(LC_ALL, ""); 2684520Snw141292 (void) textdomain(TEXT_DOMAIN); 2694520Snw141292 2708671SJulian.Pullen@Sun.COM idmap_set_logger(idmapdlog); 27112065SKeyur.Desai@Sun.COM adutils_set_logger(idmapdlog); 2726616Sdm199847 2735771Sjp151216 if (is_system_labeled() && getzoneid() != GLOBAL_ZONEID) { 2746017Snw141292 idmapdlog(LOG_ERR, 2756017Snw141292 "with Trusted Extensions idmapd runs only in the " 2765771Sjp151216 "global zone"); 2774520Snw141292 exit(1); 2784520Snw141292 } 2794520Snw141292 2806414Sjp151216 /* 2816414Sjp151216 * Raise the fd limit to max 2826414Sjp151216 */ 2836414Sjp151216 if (getrlimit(RLIMIT_NOFILE, &rl) != 0) { 2846414Sjp151216 idmapdlog(LOG_ERR, "getrlimit failed"); 2856414Sjp151216 } else if (rl.rlim_cur < rl.rlim_max) { 2866414Sjp151216 rl.rlim_cur = rl.rlim_max; 2876414Sjp151216 if (setrlimit(RLIMIT_NOFILE, &rl) != 0) 2886414Sjp151216 idmapdlog(LOG_ERR, 2896414Sjp151216 "Unable to raise RLIMIT_NOFILE to %d", 2906414Sjp151216 rl.rlim_cur); 2916414Sjp151216 } 2926414Sjp151216 2934520Snw141292 (void) mutex_init(&_svcstate_lock, USYNC_THREAD, NULL); 2944520Snw141292 2956017Snw141292 if (_idmapdstate.daemon_mode == TRUE) { 2964520Snw141292 if (daemonize_start() < 0) { 2978671SJulian.Pullen@Sun.COM idmapdlog(LOG_ERR, "unable to daemonize"); 2984520Snw141292 exit(-1); 2994520Snw141292 } 3004520Snw141292 } else 3014520Snw141292 (void) umask(0077); 3024520Snw141292 3034884Sjp151216 idmap_init_tsd_key(); 3044884Sjp151216 3054520Snw141292 init_idmapd(); 3064520Snw141292 3075034Snw141292 /* signal handlers that should run only after we're initialized */ 3085034Snw141292 (void) sigset(SIGTERM, term_handler); 3096017Snw141292 (void) sigset(SIGUSR1, usr1_handler); 3105968Snw141292 (void) sigset(SIGHUP, idmap_cfg_hup_handler); 3115034Snw141292 3124520Snw141292 if (__init_daemon_priv(PU_RESETGROUPS|PU_CLEARLIMITSET, 3134520Snw141292 DAEMON_UID, DAEMON_GID, 3144520Snw141292 PRIV_PROC_AUDIT, PRIV_FILE_DAC_READ, 3154520Snw141292 (char *)NULL) == -1) { 3166017Snw141292 idmapdlog(LOG_ERR, "unable to drop privileges"); 3174520Snw141292 exit(1); 3184520Snw141292 } 3194520Snw141292 3204520Snw141292 __fini_daemon_priv(PRIV_PROC_FORK, PRIV_PROC_EXEC, PRIV_PROC_SESSION, 3214520Snw141292 PRIV_FILE_LINK_ANY, PRIV_PROC_INFO, (char *)NULL); 3224520Snw141292 3236017Snw141292 if (_idmapdstate.daemon_mode == TRUE) 3244520Snw141292 daemonize_ready(); 3254520Snw141292 3264520Snw141292 /* With doors RPC this just wastes this thread, oh well */ 3274520Snw141292 svc_run(); 3284520Snw141292 return (0); 3294520Snw141292 } 3304520Snw141292 3314520Snw141292 static void 3325908Sjp151216 init_idmapd() 3335908Sjp151216 { 3344520Snw141292 int error; 3356531Sjp151216 int connmaxrec = IDMAP_MAX_DOOR_RPC; 3366531Sjp151216 3374520Snw141292 3385034Snw141292 /* create directories as root and chown to daemon uid */ 3395034Snw141292 if (create_directory(IDMAP_DBDIR, DAEMON_UID, DAEMON_GID) < 0) 3405034Snw141292 exit(1); 3415034Snw141292 if (create_directory(IDMAP_CACHEDIR, DAEMON_UID, DAEMON_GID) < 0) 3425034Snw141292 exit(1); 3435034Snw141292 3445034Snw141292 /* 3455034Snw141292 * Set KRB5CCNAME in the environment. See app_krb5_user_uid() 3465447Snw141292 * for more details. We blow away the existing one, if there is 3475447Snw141292 * one. 3485034Snw141292 */ 3495447Snw141292 (void) unlink(IDMAP_CACHEDIR "/ccache"); 350*12508Samw@Sun.COM (void) putenv("KRB5CCNAME=" IDMAP_CACHEDIR "/ccache"); 3515034Snw141292 3524520Snw141292 if (sysinfo(SI_HOSTNAME, _idmapdstate.hostname, 3535908Sjp151216 sizeof (_idmapdstate.hostname)) == -1) { 3544520Snw141292 error = errno; 3556017Snw141292 idmapdlog(LOG_ERR, "unable to determine hostname, error: %d", 3565908Sjp151216 error); 3574520Snw141292 exit(1); 3584520Snw141292 } 3594520Snw141292 3605731Sbaban if ((error = init_mapping_system()) < 0) { 3616017Snw141292 idmapdlog(LOG_ERR, "unable to initialize mapping system"); 3625731Sbaban exit(error < -2 ? SMF_EXIT_ERR_CONFIG : 1); 3634520Snw141292 } 3644520Snw141292 3656531Sjp151216 (void) door_server_create(idmapd_door_thread_create); 3666531Sjp151216 if ((error = pthread_key_create(&create_threads_key, 3676531Sjp151216 idmapd_door_thread_cleanup)) != 0) { 3686531Sjp151216 idmapdlog(LOG_ERR, "unable to create threads key (%s)", 3696531Sjp151216 strerror(error)); 3706531Sjp151216 goto errout; 3716531Sjp151216 } 3726531Sjp151216 3735232Snw141292 xprt = svc_door_create(idmap_prog_1, IDMAP_PROG, IDMAP_V1, connmaxrec); 3744520Snw141292 if (xprt == NULL) { 3756017Snw141292 idmapdlog(LOG_ERR, "unable to create door RPC service"); 3764520Snw141292 goto errout; 3774520Snw141292 } 3784520Snw141292 3795064Sdm199847 if (!svc_control(xprt, SVCSET_CONNMAXREC, &connmaxrec)) { 3806017Snw141292 idmapdlog(LOG_ERR, "unable to limit RPC request size"); 3815064Sdm199847 goto errout; 3825064Sdm199847 } 3835064Sdm199847 3844520Snw141292 dfd = xprt->xp_fd; 3854520Snw141292 3864520Snw141292 if (dfd == -1) { 3876017Snw141292 idmapdlog(LOG_ERR, "unable to register door"); 3884520Snw141292 goto errout; 3894520Snw141292 } 39011963SAfshin.Ardakani@Sun.COM if ((error = __idmap_reg(dfd)) != 0) { 3916017Snw141292 idmapdlog(LOG_ERR, "unable to register door (%s)", 3925908Sjp151216 strerror(errno)); 3934520Snw141292 goto errout; 3944520Snw141292 } 3954520Snw141292 3964520Snw141292 if ((error = allocids(_idmapdstate.new_eph_db, 3975908Sjp151216 8192, &_idmapdstate.next_uid, 3985908Sjp151216 8192, &_idmapdstate.next_gid)) != 0) { 3996017Snw141292 idmapdlog(LOG_ERR, "unable to allocate ephemeral IDs (%s)", 4006017Snw141292 strerror(errno)); 40111963SAfshin.Ardakani@Sun.COM _idmapdstate.next_uid = IDMAP_SENTINEL_PID; 40211963SAfshin.Ardakani@Sun.COM _idmapdstate.limit_uid = IDMAP_SENTINEL_PID; 40311963SAfshin.Ardakani@Sun.COM _idmapdstate.next_gid = IDMAP_SENTINEL_PID; 40411963SAfshin.Ardakani@Sun.COM _idmapdstate.limit_gid = IDMAP_SENTINEL_PID; 4054520Snw141292 } else { 4064520Snw141292 _idmapdstate.limit_uid = _idmapdstate.next_uid + 8192; 4074520Snw141292 _idmapdstate.limit_gid = _idmapdstate.next_gid + 8192; 4084520Snw141292 } 4094520Snw141292 410*12508Samw@Sun.COM if (DBG(CONFIG, 1)) 411*12508Samw@Sun.COM print_idmapdstate(); 4124520Snw141292 4134520Snw141292 return; 4144520Snw141292 4154520Snw141292 errout: 4164520Snw141292 fini_idmapd(); 4174520Snw141292 exit(1); 4184520Snw141292 } 4194520Snw141292 4204520Snw141292 static void 4215908Sjp151216 fini_idmapd() 4225908Sjp151216 { 423*12508Samw@Sun.COM (void) __idmap_unreg(dfd); 4244520Snw141292 fini_mapping_system(); 4254520Snw141292 if (xprt != NULL) 4264520Snw141292 svc_destroy(xprt); 4274520Snw141292 } 4284520Snw141292 4296017Snw141292 static 4306017Snw141292 const char * 4316017Snw141292 get_fmri(void) 4326017Snw141292 { 4336017Snw141292 static char *fmri = NULL; 4346017Snw141292 static char buf[60]; 4356017Snw141292 char *s; 4366017Snw141292 4376017Snw141292 membar_consumer(); 4386017Snw141292 s = fmri; 4396017Snw141292 if (s != NULL && *s == '\0') 4406017Snw141292 return (NULL); 4416017Snw141292 else if (s != NULL) 4426017Snw141292 return (s); 4436017Snw141292 4446017Snw141292 if ((s = getenv("SMF_FMRI")) == NULL || strlen(s) >= sizeof (buf)) 4456017Snw141292 buf[0] = '\0'; 4466017Snw141292 else 4476017Snw141292 (void) strlcpy(buf, s, sizeof (buf)); 4486017Snw141292 4496017Snw141292 membar_producer(); 4506017Snw141292 fmri = buf; 4516017Snw141292 4526017Snw141292 return (get_fmri()); 4536017Snw141292 } 4546017Snw141292 4556017Snw141292 /* 4566017Snw141292 * Wrappers for smf_degrade/restore_instance() 4576017Snw141292 * 4586017Snw141292 * smf_restore_instance() is too heavy duty to be calling every time we 4596017Snw141292 * have a successful AD name<->SID lookup. 4606017Snw141292 */ 4616017Snw141292 void 4626097Snw141292 degrade_svc(int poke_discovery, const char *reason) 4636017Snw141292 { 4646017Snw141292 const char *fmri; 4656017Snw141292 4666017Snw141292 membar_consumer(); 4676017Snw141292 if (degraded) 4686017Snw141292 return; 4696097Snw141292 470*12508Samw@Sun.COM idmapdlog(LOG_ERR, "Degraded operation (%s).", reason); 4716097Snw141292 4726017Snw141292 membar_producer(); 473*12508Samw@Sun.COM degraded = B_TRUE; 4746017Snw141292 4756017Snw141292 if ((fmri = get_fmri()) != NULL) 4766017Snw141292 (void) smf_degrade_instance(fmri, 0); 47712065SKeyur.Desai@Sun.COM 47812065SKeyur.Desai@Sun.COM /* 47912065SKeyur.Desai@Sun.COM * If the config update thread is in a state where auto-discovery could 48012065SKeyur.Desai@Sun.COM * be re-tried, then this will make it try it -- a sort of auto-refresh. 48112065SKeyur.Desai@Sun.COM */ 48212065SKeyur.Desai@Sun.COM if (poke_discovery) 48312065SKeyur.Desai@Sun.COM idmap_cfg_poke_updates(); 4846017Snw141292 } 4856017Snw141292 4866017Snw141292 void 4876017Snw141292 restore_svc(void) 4886017Snw141292 { 4896017Snw141292 const char *fmri; 4906017Snw141292 4916017Snw141292 membar_consumer(); 4926017Snw141292 if (!degraded) 4936017Snw141292 return; 4946017Snw141292 4956017Snw141292 if ((fmri = get_fmri()) == NULL) 4966017Snw141292 (void) smf_restore_instance(fmri); 4976017Snw141292 4986017Snw141292 membar_producer(); 499*12508Samw@Sun.COM degraded = B_FALSE; 5006616Sdm199847 5016097Snw141292 idmapdlog(LOG_NOTICE, "Normal operation restored"); 5026017Snw141292 } 5036017Snw141292 5048671SJulian.Pullen@Sun.COM 5058671SJulian.Pullen@Sun.COM /* printflike */ 5064520Snw141292 void 5078671SJulian.Pullen@Sun.COM idmapdlog(int pri, const char *format, ...) { 5084520Snw141292 va_list args; 5094520Snw141292 510*12508Samw@Sun.COM va_start(args, format); 511*12508Samw@Sun.COM (void) vfprintf(stderr, format, args); 512*12508Samw@Sun.COM (void) fprintf(stderr, "\n"); 513*12508Samw@Sun.COM va_end(args); 5146017Snw141292 5156017Snw141292 /* 5166017Snw141292 * We don't want to fill up the logs with useless messages when 5176017Snw141292 * we're degraded, but we still want to log. 5186017Snw141292 */ 519*12508Samw@Sun.COM if (degraded) 5206017Snw141292 pri = LOG_DEBUG; 5216017Snw141292 522*12508Samw@Sun.COM va_start(args, format); 523*12508Samw@Sun.COM vsyslog(pri, format, args); 524*12508Samw@Sun.COM va_end(args); 525*12508Samw@Sun.COM } 526*12508Samw@Sun.COM 527*12508Samw@Sun.COM static void 528*12508Samw@Sun.COM trace_str(nvlist_t *entry, char *n1, char *n2, char *str) 529*12508Samw@Sun.COM { 530*12508Samw@Sun.COM char name[IDMAP_TRACE_NAME_MAX+1]; /* Max used is only about 11 */ 531*12508Samw@Sun.COM 532*12508Samw@Sun.COM (void) strlcpy(name, n1, sizeof (name)); 533*12508Samw@Sun.COM if (n2 != NULL) 534*12508Samw@Sun.COM (void) strlcat(name, n2, sizeof (name)); 535*12508Samw@Sun.COM 536*12508Samw@Sun.COM (void) nvlist_add_string(entry, name, str); 537*12508Samw@Sun.COM } 538*12508Samw@Sun.COM 539*12508Samw@Sun.COM static void 540*12508Samw@Sun.COM trace_int(nvlist_t *entry, char *n1, char *n2, int64_t i) 541*12508Samw@Sun.COM { 542*12508Samw@Sun.COM char name[IDMAP_TRACE_NAME_MAX+1]; /* Max used is only about 11 */ 543*12508Samw@Sun.COM 544*12508Samw@Sun.COM (void) strlcpy(name, n1, sizeof (name)); 545*12508Samw@Sun.COM if (n2 != NULL) 546*12508Samw@Sun.COM (void) strlcat(name, n2, sizeof (name)); 547*12508Samw@Sun.COM 548*12508Samw@Sun.COM (void) nvlist_add_int64(entry, name, i); 549*12508Samw@Sun.COM } 550*12508Samw@Sun.COM 551*12508Samw@Sun.COM static void 552*12508Samw@Sun.COM trace_sid(nvlist_t *entry, char *n1, char *n2, idmap_sid *sid) 553*12508Samw@Sun.COM { 554*12508Samw@Sun.COM char *str; 555*12508Samw@Sun.COM 556*12508Samw@Sun.COM (void) asprintf(&str, "%s-%u", sid->prefix, sid->rid); 557*12508Samw@Sun.COM if (str == NULL) 558*12508Samw@Sun.COM return; 559*12508Samw@Sun.COM 560*12508Samw@Sun.COM trace_str(entry, n1, n2, str); 561*12508Samw@Sun.COM free(str); 562*12508Samw@Sun.COM } 563*12508Samw@Sun.COM 564*12508Samw@Sun.COM static void 565*12508Samw@Sun.COM trace_id(nvlist_t *entry, char *fromto, idmap_id *id, char *name, char *domain) 566*12508Samw@Sun.COM { 567*12508Samw@Sun.COM trace_int(entry, fromto, IDMAP_TRACE_TYPE, (int64_t)id->idtype); 568*12508Samw@Sun.COM if (IS_ID_SID(*id)) { 569*12508Samw@Sun.COM if (name != NULL) { 570*12508Samw@Sun.COM char *str; 571*12508Samw@Sun.COM 572*12508Samw@Sun.COM (void) asprintf(&str, "%s%s%s", name, 573*12508Samw@Sun.COM domain == NULL ? "" : "@", 574*12508Samw@Sun.COM domain == NULL ? "" : domain); 575*12508Samw@Sun.COM if (str != NULL) { 576*12508Samw@Sun.COM trace_str(entry, fromto, IDMAP_TRACE_NAME, str); 577*12508Samw@Sun.COM free(str); 578*12508Samw@Sun.COM } 579*12508Samw@Sun.COM } 580*12508Samw@Sun.COM if (id->idmap_id_u.sid.prefix != NULL) { 581*12508Samw@Sun.COM trace_sid(entry, fromto, IDMAP_TRACE_SID, 582*12508Samw@Sun.COM &id->idmap_id_u.sid); 583*12508Samw@Sun.COM } 584*12508Samw@Sun.COM } else if (IS_ID_POSIX(*id)) { 585*12508Samw@Sun.COM if (name != NULL) 586*12508Samw@Sun.COM trace_str(entry, fromto, IDMAP_TRACE_NAME, name); 587*12508Samw@Sun.COM if (id->idmap_id_u.uid != IDMAP_SENTINEL_PID) { 588*12508Samw@Sun.COM trace_int(entry, fromto, IDMAP_TRACE_UNIXID, 589*12508Samw@Sun.COM (int64_t)id->idmap_id_u.uid); 590*12508Samw@Sun.COM } 5918671SJulian.Pullen@Sun.COM } 5928671SJulian.Pullen@Sun.COM } 5938671SJulian.Pullen@Sun.COM 594*12508Samw@Sun.COM /* 595*12508Samw@Sun.COM * Record a trace event. TRACE() has already decided whether or not 596*12508Samw@Sun.COM * tracing is required; what we do here is collect the data and send it 597*12508Samw@Sun.COM * to its destination - to the trace log in the response, if 598*12508Samw@Sun.COM * IDMAP_REQ_FLG_TRACE is set, and to the SMF service log, if debug/mapping 599*12508Samw@Sun.COM * is greater than zero. 600*12508Samw@Sun.COM */ 601*12508Samw@Sun.COM int 602*12508Samw@Sun.COM trace(idmap_mapping *req, idmap_id_res *res, char *fmt, ...) 6038671SJulian.Pullen@Sun.COM { 604*12508Samw@Sun.COM va_list va; 605*12508Samw@Sun.COM char *buf; 606*12508Samw@Sun.COM int err; 607*12508Samw@Sun.COM nvlist_t *entry; 608*12508Samw@Sun.COM 609*12508Samw@Sun.COM assert(req != NULL); 610*12508Samw@Sun.COM assert(res != NULL); 611*12508Samw@Sun.COM 612*12508Samw@Sun.COM err = nvlist_alloc(&entry, NV_UNIQUE_NAME, 0); 613*12508Samw@Sun.COM if (err != 0) { 614*12508Samw@Sun.COM (void) fprintf(stderr, "trace nvlist_alloc(entry): %s\n", 615*12508Samw@Sun.COM strerror(err)); 616*12508Samw@Sun.COM return (0); 617*12508Samw@Sun.COM } 618*12508Samw@Sun.COM 619*12508Samw@Sun.COM trace_id(entry, "from", &req->id1, req->id1name, req->id1domain); 620*12508Samw@Sun.COM trace_id(entry, "to", &res->id, req->id2name, req->id2domain); 621*12508Samw@Sun.COM 622*12508Samw@Sun.COM if (IDMAP_ERROR(res->retcode)) { 623*12508Samw@Sun.COM trace_int(entry, IDMAP_TRACE_ERROR, NULL, 624*12508Samw@Sun.COM (int64_t)res->retcode); 625*12508Samw@Sun.COM } 6268671SJulian.Pullen@Sun.COM 627*12508Samw@Sun.COM va_start(va, fmt); 628*12508Samw@Sun.COM (void) vasprintf(&buf, fmt, va); 629*12508Samw@Sun.COM va_end(va); 630*12508Samw@Sun.COM if (buf != NULL) { 631*12508Samw@Sun.COM trace_str(entry, IDMAP_TRACE_MESSAGE, NULL, buf); 632*12508Samw@Sun.COM free(buf); 633*12508Samw@Sun.COM } 634*12508Samw@Sun.COM 635*12508Samw@Sun.COM if (DBG(MAPPING, 1)) 636*12508Samw@Sun.COM idmap_trace_print_1(stderr, "", entry); 637*12508Samw@Sun.COM 638*12508Samw@Sun.COM if (req->flag & IDMAP_REQ_FLG_TRACE) { 639*12508Samw@Sun.COM /* Lazily allocate the trace list */ 640*12508Samw@Sun.COM if (res->info.trace == NULL) { 641*12508Samw@Sun.COM err = nvlist_alloc(&res->info.trace, 0, 0); 642*12508Samw@Sun.COM if (err != 0) { 643*12508Samw@Sun.COM res->info.trace = NULL; /* just in case */ 644*12508Samw@Sun.COM (void) fprintf(stderr, 645*12508Samw@Sun.COM "trace nvlist_alloc(trace): %s\n", 646*12508Samw@Sun.COM strerror(err)); 647*12508Samw@Sun.COM nvlist_free(entry); 648*12508Samw@Sun.COM return (0); 649*12508Samw@Sun.COM } 650*12508Samw@Sun.COM } 651*12508Samw@Sun.COM (void) nvlist_add_nvlist(res->info.trace, "", entry); 652*12508Samw@Sun.COM /* Note that entry is copied, so we must still free our copy */ 653*12508Samw@Sun.COM } 654*12508Samw@Sun.COM 655*12508Samw@Sun.COM nvlist_free(entry); 656*12508Samw@Sun.COM 657*12508Samw@Sun.COM return (0); 6588671SJulian.Pullen@Sun.COM } 659