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 /* 224520Snw141292 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 234520Snw141292 * Use is subject to license terms. 244520Snw141292 */ 254520Snw141292 264520Snw141292 #pragma ident "%Z%%M% %I% %E% SMI" 274520Snw141292 284520Snw141292 /* 294520Snw141292 * main() of idmapd(1M) 304520Snw141292 */ 314520Snw141292 324520Snw141292 #include "idmapd.h" 334520Snw141292 #include <signal.h> 344520Snw141292 #include <rpc/pmap_clnt.h> /* for pmap_unset */ 354520Snw141292 #include <string.h> /* strcmp */ 364520Snw141292 #include <unistd.h> /* setsid */ 374520Snw141292 #include <sys/types.h> 384520Snw141292 #include <memory.h> 394520Snw141292 #include <stropts.h> 404520Snw141292 #include <netconfig.h> 414520Snw141292 #include <sys/resource.h> /* rlimit */ 424520Snw141292 #include <syslog.h> 434520Snw141292 #include <rpcsvc/daemon_utils.h> /* DAEMON_UID and DAEMON_GID */ 444520Snw141292 #include <priv_utils.h> /* privileges */ 454520Snw141292 #include <locale.h> 464520Snw141292 #include <sys/systeminfo.h> 474520Snw141292 #include <errno.h> 484520Snw141292 #include <sys/wait.h> 494520Snw141292 #include <sys/time.h> 504520Snw141292 #include <zone.h> 514520Snw141292 #include <door.h> 524520Snw141292 #include <tsol/label.h> 534520Snw141292 #include <sys/resource.h> 544520Snw141292 #include <sys/sid.h> 554520Snw141292 #include <sys/idmap.h> 564520Snw141292 574520Snw141292 static void hup_handler(int); 584520Snw141292 static void term_handler(int); 594520Snw141292 static void init_idmapd(); 604520Snw141292 static void fini_idmapd(); 614520Snw141292 624520Snw141292 #ifndef SIG_PF 634520Snw141292 #define SIG_PF void(*)(int) 644520Snw141292 #endif 654520Snw141292 664520Snw141292 #define _RPCSVC_CLOSEDOWN 120 674520Snw141292 684520Snw141292 int _rpcsvcstate = _IDLE; /* Set when a request is serviced */ 694520Snw141292 int _rpcsvccount = 0; /* Number of requests being serviced */ 704520Snw141292 mutex_t _svcstate_lock; /* lock for _rpcsvcstate, _rpcsvccount */ 714520Snw141292 idmapd_state_t _idmapdstate; 724520Snw141292 734520Snw141292 SVCXPRT *xprt = NULL; 744520Snw141292 754520Snw141292 static int dfd = -1; /* our door server fildes, for unregistration */ 764520Snw141292 774520Snw141292 #ifdef DEBUG 784520Snw141292 #define RPC_SVC_FG 794520Snw141292 #endif 804520Snw141292 814520Snw141292 /* 824520Snw141292 * This is needed for mech_krb5 -- we run as daemon, yes, but we want 835034Snw141292 * mech_krb5 to think we're root so it can get host/nodename.fqdn 845034Snw141292 * tickets for us so we can authenticate to AD as the machine account 855034Snw141292 * that we are. For more details look at the entry point in mech_krb5 865034Snw141292 * corresponding to gss_init_sec_context(). 875034Snw141292 * 885034Snw141292 * As a side effect of faking our effective UID to mech_krb5 we will use 895034Snw141292 * root's default ccache (/tmp/krb5cc_0). But if that's created by 905034Snw141292 * another process then we won't have access to it: we run as daemon and 915034Snw141292 * keep PRIV_FILE_DAC_READ, which is insufficient to share the ccache 925034Snw141292 * with others. We putenv("KRB5CCNAME=/var/run/idmap/ccache") in main() 935034Snw141292 * to avoid this issue; see main(). 944520Snw141292 * 954520Snw141292 * Someday we'll have gss/mech_krb5 extensions for acquiring initiator 964520Snw141292 * creds with keytabs/raw keys, and someday we'll have extensions to 974520Snw141292 * libsasl to specify creds/name to use on the initiator side, and 984520Snw141292 * someday we'll have extensions to libldap to pass those through to 994520Snw141292 * libsasl. Until then this interposer will have to do. 1004520Snw141292 * 1014520Snw141292 * Also, we have to tell lint to shut up: it thinks app_krb5_user_uid() 1024520Snw141292 * is defined but not used. 1034520Snw141292 */ 1044520Snw141292 /*LINTLIBRARY*/ 1054520Snw141292 uid_t 1064520Snw141292 app_krb5_user_uid(void) 1074520Snw141292 { 1084520Snw141292 return (0); 1094520Snw141292 } 1104520Snw141292 1114520Snw141292 /*ARGSUSED*/ 1124520Snw141292 static void 1134520Snw141292 hup_handler(int sig) { 1144520Snw141292 (void) idmapdlog(LOG_INFO, "idmapd: Refreshing config."); 1154520Snw141292 WRLOCK_CONFIG(); 1164520Snw141292 (void) idmap_cfg_fini(_idmapdstate.cfg); 1174520Snw141292 _idmapdstate.cfg = NULL; 1184520Snw141292 if (load_config() < 0) { 1194520Snw141292 UNLOCK_CONFIG(); 1204520Snw141292 (void) idmapdlog(LOG_NOTICE, 1214520Snw141292 "idmapd: Failed to reload config"); 1224520Snw141292 term_handler(sig); 1234520Snw141292 } 1244520Snw141292 UNLOCK_CONFIG(); 1254520Snw141292 print_idmapdstate(); 1264520Snw141292 } 1274520Snw141292 1284520Snw141292 /*ARGSUSED*/ 1294520Snw141292 static void 1304520Snw141292 term_handler(int sig) { 1314520Snw141292 (void) idmapdlog(LOG_INFO, "idmapd: Terminating."); 1324520Snw141292 fini_idmapd(); 1334520Snw141292 _exit(0); 1344520Snw141292 } 1354520Snw141292 1364520Snw141292 static int pipe_fd = -1; 1374520Snw141292 1384520Snw141292 static void 1394520Snw141292 daemonize_ready(void) { 1404520Snw141292 char data = '\0'; 1414520Snw141292 /* 1424520Snw141292 * wake the parent 1434520Snw141292 */ 1444520Snw141292 (void) write(pipe_fd, &data, 1); 1454520Snw141292 (void) close(pipe_fd); 1464520Snw141292 } 1474520Snw141292 1484520Snw141292 static int 1494520Snw141292 daemonize_start(void) { 1504520Snw141292 char data; 1514520Snw141292 int status; 1524520Snw141292 int devnull; 1534520Snw141292 int filedes[2]; 1544520Snw141292 pid_t pid; 1554520Snw141292 1565034Snw141292 (void) sigset(SIGPIPE, SIG_IGN); 1574520Snw141292 devnull = open("/dev/null", O_RDONLY); 1584520Snw141292 if (devnull < 0) 1594520Snw141292 return (-1); 1604520Snw141292 (void) dup2(devnull, 0); 1614520Snw141292 (void) dup2(2, 1); /* stderr only */ 1624520Snw141292 if (pipe(filedes) < 0) 1634520Snw141292 return (-1); 1644520Snw141292 if ((pid = fork1()) < 0) 1654520Snw141292 return (-1); 1664520Snw141292 if (pid != 0) { 1674520Snw141292 /* 1684520Snw141292 * parent 1694520Snw141292 */ 1704520Snw141292 (void) close(filedes[1]); 1714520Snw141292 if (read(filedes[0], &data, 1) == 1) { 1724520Snw141292 /* presume success */ 1734520Snw141292 _exit(0); 1744520Snw141292 } 1754520Snw141292 status = -1; 1764520Snw141292 (void) wait4(pid, &status, 0, NULL); 1774520Snw141292 if (WIFEXITED(status)) 1784520Snw141292 _exit(WEXITSTATUS(status)); 1794520Snw141292 else 1804520Snw141292 _exit(-1); 1814520Snw141292 } 1824520Snw141292 1834520Snw141292 /* 1844520Snw141292 * child 1854520Snw141292 */ 1864520Snw141292 pipe_fd = filedes[1]; 1874520Snw141292 (void) close(filedes[0]); 1884520Snw141292 (void) setsid(); 1894520Snw141292 (void) umask(0077); 1904520Snw141292 openlog("idmap", LOG_PID, LOG_DAEMON); 1914520Snw141292 _idmapdstate.daemon_mode = TRUE; 1924520Snw141292 return (0); 1934520Snw141292 } 1944520Snw141292 1954520Snw141292 1964520Snw141292 int 1974520Snw141292 main(int argc, char **argv) 1984520Snw141292 { 1994520Snw141292 int c; 2004520Snw141292 #ifdef RPC_SVC_FG 2014520Snw141292 bool_t daemonize = FALSE; 2024520Snw141292 #else 2034520Snw141292 bool_t daemonize = TRUE; 2044520Snw141292 #endif 2054520Snw141292 2064520Snw141292 while ((c = getopt(argc, argv, "d")) != EOF) { 2074520Snw141292 switch (c) { 2084520Snw141292 case 'd': 2094520Snw141292 daemonize = FALSE; 2104520Snw141292 break; 2114520Snw141292 default: 2124520Snw141292 break; 2134520Snw141292 } 2144520Snw141292 } 2154520Snw141292 2164520Snw141292 /* set locale and domain for internationalization */ 2174520Snw141292 (void) setlocale(LC_ALL, ""); 2184520Snw141292 (void) textdomain(TEXT_DOMAIN); 2194520Snw141292 2205034Snw141292 if (getzoneid() != GLOBAL_ZONEID) { 2214520Snw141292 (void) idmapdlog(LOG_ERR, 2225034Snw141292 "idmapd: idmapd runs only in the global zone"); 2234520Snw141292 exit(1); 2244520Snw141292 } 2254520Snw141292 2264520Snw141292 (void) mutex_init(&_svcstate_lock, USYNC_THREAD, NULL); 2274520Snw141292 2284520Snw141292 if (daemonize == TRUE) { 2294520Snw141292 if (daemonize_start() < 0) { 2304520Snw141292 (void) perror("idmapd: unable to daemonize"); 2314520Snw141292 exit(-1); 2324520Snw141292 } 2334520Snw141292 } else 2344520Snw141292 (void) umask(0077); 2354520Snw141292 2364884Sjp151216 idmap_init_tsd_key(); 2374884Sjp151216 2384520Snw141292 init_idmapd(); 2394520Snw141292 2405034Snw141292 /* signal handlers that should run only after we're initialized */ 2415034Snw141292 (void) sigset(SIGTERM, term_handler); 2425034Snw141292 (void) sigset(SIGHUP, hup_handler); 2435034Snw141292 2444520Snw141292 if (__init_daemon_priv(PU_RESETGROUPS|PU_CLEARLIMITSET, 2454520Snw141292 DAEMON_UID, DAEMON_GID, 2464520Snw141292 PRIV_PROC_AUDIT, PRIV_FILE_DAC_READ, 2474520Snw141292 (char *)NULL) == -1) { 2484644Sbaban (void) idmapdlog(LOG_ERR, "idmapd: unable to drop privileges"); 2494520Snw141292 exit(1); 2504520Snw141292 } 2514520Snw141292 2524520Snw141292 __fini_daemon_priv(PRIV_PROC_FORK, PRIV_PROC_EXEC, PRIV_PROC_SESSION, 2534520Snw141292 PRIV_FILE_LINK_ANY, PRIV_PROC_INFO, (char *)NULL); 2544520Snw141292 2554520Snw141292 if (daemonize == TRUE) 2564520Snw141292 daemonize_ready(); 2574520Snw141292 2584520Snw141292 /* With doors RPC this just wastes this thread, oh well */ 2594520Snw141292 svc_run(); 2604520Snw141292 return (0); 2614520Snw141292 } 2624520Snw141292 2634520Snw141292 static void 2644520Snw141292 init_idmapd() { 2654520Snw141292 int error; 266*5232Snw141292 int connmaxrec = IDMAP_MAX_DOOR_RPC; 2674520Snw141292 2685034Snw141292 /* create directories as root and chown to daemon uid */ 2695034Snw141292 if (create_directory(IDMAP_DBDIR, DAEMON_UID, DAEMON_GID) < 0) 2705034Snw141292 exit(1); 2715034Snw141292 if (create_directory(IDMAP_CACHEDIR, DAEMON_UID, DAEMON_GID) < 0) 2725034Snw141292 exit(1); 2735034Snw141292 2745034Snw141292 /* 2755034Snw141292 * Set KRB5CCNAME in the environment. See app_krb5_user_uid() 2765034Snw141292 * for more details. 2775034Snw141292 */ 2785034Snw141292 putenv("KRB5CCNAME=" IDMAP_CACHEDIR "/ccache"); 2795034Snw141292 2804520Snw141292 memset(&_idmapdstate, 0, sizeof (_idmapdstate)); 2814520Snw141292 2824520Snw141292 if (sysinfo(SI_HOSTNAME, _idmapdstate.hostname, 2834520Snw141292 sizeof (_idmapdstate.hostname)) == -1) { 2844520Snw141292 error = errno; 2854520Snw141292 idmapdlog(LOG_ERR, 2864520Snw141292 "idmapd: unable to determine hostname, error: %d", 2874520Snw141292 error); 2884520Snw141292 exit(1); 2894520Snw141292 } 2904520Snw141292 2914520Snw141292 if (sysinfo(SI_SRPC_DOMAIN, _idmapdstate.domainname, 2924520Snw141292 sizeof (_idmapdstate.domainname)) == -1) { 2934520Snw141292 error = errno; 2944520Snw141292 idmapdlog(LOG_ERR, 2954520Snw141292 "idmapd: unable to determine name service domain, error: %d", 2964520Snw141292 error); 2974520Snw141292 exit(1); 2984520Snw141292 } 2994520Snw141292 3004520Snw141292 if (init_mapping_system() < 0) { 3014520Snw141292 idmapdlog(LOG_ERR, 3024520Snw141292 "idmapd: unable to initialize mapping system"); 3034520Snw141292 exit(1); 3044520Snw141292 } 3054520Snw141292 306*5232Snw141292 xprt = svc_door_create(idmap_prog_1, IDMAP_PROG, IDMAP_V1, connmaxrec); 3074520Snw141292 if (xprt == NULL) { 3084520Snw141292 idmapdlog(LOG_ERR, 3094520Snw141292 "idmapd: unable to create door RPC service"); 3104520Snw141292 goto errout; 3114520Snw141292 } 3124520Snw141292 3135064Sdm199847 if (!svc_control(xprt, SVCSET_CONNMAXREC, &connmaxrec)) { 3145064Sdm199847 idmapdlog(LOG_ERR, 3155064Sdm199847 "idmapd: unable to limit RPC request size"); 3165064Sdm199847 goto errout; 3175064Sdm199847 } 3185064Sdm199847 3194520Snw141292 dfd = xprt->xp_fd; 3204520Snw141292 3214520Snw141292 if (dfd == -1) { 3224520Snw141292 idmapdlog(LOG_ERR, "idmapd: unable to register door"); 3234520Snw141292 goto errout; 3244520Snw141292 } 3254520Snw141292 if ((error = idmap_reg(dfd)) != 0) { 3264520Snw141292 idmapdlog(LOG_ERR, "idmapd: unable to register door (%s)", 3274520Snw141292 strerror(error)); 3284520Snw141292 goto errout; 3294520Snw141292 } 3304520Snw141292 3314520Snw141292 if ((error = allocids(_idmapdstate.new_eph_db, 3324520Snw141292 8192, &_idmapdstate.next_uid, 3334520Snw141292 8192, &_idmapdstate.next_gid)) != 0) { 3344520Snw141292 idmapdlog(LOG_ERR, "idmapd: unable to allocate ephemeral IDs " 3354520Snw141292 "(%s)", strerror(error)); 3364520Snw141292 _idmapdstate.next_uid = _idmapdstate.limit_uid = SENTINEL_PID; 3374520Snw141292 _idmapdstate.next_gid = _idmapdstate.limit_gid = SENTINEL_PID; 3384520Snw141292 } else { 3394520Snw141292 _idmapdstate.limit_uid = _idmapdstate.next_uid + 8192; 3404520Snw141292 _idmapdstate.limit_gid = _idmapdstate.next_gid + 8192; 3414520Snw141292 } 3424520Snw141292 3434520Snw141292 print_idmapdstate(); 3444520Snw141292 3454520Snw141292 return; 3464520Snw141292 3474520Snw141292 errout: 3484520Snw141292 fini_idmapd(); 3494520Snw141292 exit(1); 3504520Snw141292 } 3514520Snw141292 3524520Snw141292 static void 3534520Snw141292 fini_idmapd() { 3544520Snw141292 idmap_unreg(dfd); 3554520Snw141292 fini_mapping_system(); 3564520Snw141292 if (xprt != NULL) 3574520Snw141292 svc_destroy(xprt); 3584520Snw141292 } 3594520Snw141292 3604520Snw141292 void 3614520Snw141292 idmapdlog(int pri, const char *format, ...) { 3624520Snw141292 va_list args; 3634520Snw141292 3644520Snw141292 va_start(args, format); 3654520Snw141292 if (_idmapdstate.daemon_mode == FALSE) { 3664520Snw141292 (void) vfprintf(stderr, format, args); 3674520Snw141292 (void) fprintf(stderr, "\n"); 3684520Snw141292 } 3694520Snw141292 (void) vsyslog(pri, format, args); 3704520Snw141292 va_end(args); 3714520Snw141292 } 372