1*c5c4113dSnw /* 2*c5c4113dSnw * CDDL HEADER START 3*c5c4113dSnw * 4*c5c4113dSnw * The contents of this file are subject to the terms of the 5*c5c4113dSnw * Common Development and Distribution License (the "License"). 6*c5c4113dSnw * You may not use this file except in compliance with the License. 7*c5c4113dSnw * 8*c5c4113dSnw * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*c5c4113dSnw * or http://www.opensolaris.org/os/licensing. 10*c5c4113dSnw * See the License for the specific language governing permissions 11*c5c4113dSnw * and limitations under the License. 12*c5c4113dSnw * 13*c5c4113dSnw * When distributing Covered Code, include this CDDL HEADER in each 14*c5c4113dSnw * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*c5c4113dSnw * If applicable, add the following below this CDDL HEADER, with the 16*c5c4113dSnw * fields enclosed by brackets "[]" replaced with your own identifying 17*c5c4113dSnw * information: Portions Copyright [yyyy] [name of copyright owner] 18*c5c4113dSnw * 19*c5c4113dSnw * CDDL HEADER END 20*c5c4113dSnw */ 21*c5c4113dSnw /* 22*c5c4113dSnw * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 23*c5c4113dSnw * Use is subject to license terms. 24*c5c4113dSnw */ 25*c5c4113dSnw 26*c5c4113dSnw #pragma ident "%Z%%M% %I% %E% SMI" 27*c5c4113dSnw 28*c5c4113dSnw /* 29*c5c4113dSnw * main() of idmapd(1M) 30*c5c4113dSnw */ 31*c5c4113dSnw 32*c5c4113dSnw #include "idmapd.h" 33*c5c4113dSnw #include <signal.h> 34*c5c4113dSnw #include <rpc/pmap_clnt.h> /* for pmap_unset */ 35*c5c4113dSnw #include <string.h> /* strcmp */ 36*c5c4113dSnw #include <unistd.h> /* setsid */ 37*c5c4113dSnw #include <sys/types.h> 38*c5c4113dSnw #include <memory.h> 39*c5c4113dSnw #include <stropts.h> 40*c5c4113dSnw #include <netconfig.h> 41*c5c4113dSnw #include <sys/resource.h> /* rlimit */ 42*c5c4113dSnw #include <syslog.h> 43*c5c4113dSnw #include <rpcsvc/daemon_utils.h> /* DAEMON_UID and DAEMON_GID */ 44*c5c4113dSnw #include <priv_utils.h> /* privileges */ 45*c5c4113dSnw #include <locale.h> 46*c5c4113dSnw #include <sys/systeminfo.h> 47*c5c4113dSnw #include <errno.h> 48*c5c4113dSnw #include <sys/wait.h> 49*c5c4113dSnw #include <sys/time.h> 50*c5c4113dSnw #include <zone.h> 51*c5c4113dSnw #include <door.h> 52*c5c4113dSnw #include <tsol/label.h> 53*c5c4113dSnw #include <sys/resource.h> 54*c5c4113dSnw #include <sys/sid.h> 55*c5c4113dSnw #include <sys/idmap.h> 56*c5c4113dSnw 57*c5c4113dSnw static void hup_handler(int); 58*c5c4113dSnw static void term_handler(int); 59*c5c4113dSnw static void init_idmapd(); 60*c5c4113dSnw static void fini_idmapd(); 61*c5c4113dSnw 62*c5c4113dSnw #ifndef SIG_PF 63*c5c4113dSnw #define SIG_PF void(*)(int) 64*c5c4113dSnw #endif 65*c5c4113dSnw 66*c5c4113dSnw #define _RPCSVC_CLOSEDOWN 120 67*c5c4113dSnw 68*c5c4113dSnw int _rpcsvcstate = _IDLE; /* Set when a request is serviced */ 69*c5c4113dSnw int _rpcsvccount = 0; /* Number of requests being serviced */ 70*c5c4113dSnw mutex_t _svcstate_lock; /* lock for _rpcsvcstate, _rpcsvccount */ 71*c5c4113dSnw idmapd_state_t _idmapdstate; 72*c5c4113dSnw 73*c5c4113dSnw SVCXPRT *xprt = NULL; 74*c5c4113dSnw 75*c5c4113dSnw static int dfd = -1; /* our door server fildes, for unregistration */ 76*c5c4113dSnw 77*c5c4113dSnw #ifdef DEBUG 78*c5c4113dSnw #define RPC_SVC_FG 79*c5c4113dSnw #endif 80*c5c4113dSnw 81*c5c4113dSnw /* 82*c5c4113dSnw * This is needed for mech_krb5 -- we run as daemon, yes, but we want 83*c5c4113dSnw * mech_krb5 to think we're root. 84*c5c4113dSnw * 85*c5c4113dSnw * Someday we'll have gss/mech_krb5 extensions for acquiring initiator 86*c5c4113dSnw * creds with keytabs/raw keys, and someday we'll have extensions to 87*c5c4113dSnw * libsasl to specify creds/name to use on the initiator side, and 88*c5c4113dSnw * someday we'll have extensions to libldap to pass those through to 89*c5c4113dSnw * libsasl. Until then this interposer will have to do. 90*c5c4113dSnw * 91*c5c4113dSnw * Also, we have to tell lint to shut up: it thinks app_krb5_user_uid() 92*c5c4113dSnw * is defined but not used. 93*c5c4113dSnw */ 94*c5c4113dSnw /*LINTLIBRARY*/ 95*c5c4113dSnw uid_t 96*c5c4113dSnw app_krb5_user_uid(void) 97*c5c4113dSnw { 98*c5c4113dSnw return (0); 99*c5c4113dSnw } 100*c5c4113dSnw 101*c5c4113dSnw static void 102*c5c4113dSnw set_signal_handlers() { 103*c5c4113dSnw (void) sigset(SIGPIPE, SIG_IGN); 104*c5c4113dSnw (void) sigset(SIGHUP, hup_handler); 105*c5c4113dSnw (void) sigset(SIGTERM, term_handler); 106*c5c4113dSnw } 107*c5c4113dSnw 108*c5c4113dSnw /*ARGSUSED*/ 109*c5c4113dSnw static void 110*c5c4113dSnw hup_handler(int sig) { 111*c5c4113dSnw (void) idmapdlog(LOG_INFO, "idmapd: Refreshing config."); 112*c5c4113dSnw WRLOCK_CONFIG(); 113*c5c4113dSnw (void) idmap_cfg_fini(_idmapdstate.cfg); 114*c5c4113dSnw _idmapdstate.cfg = NULL; 115*c5c4113dSnw if (load_config() < 0) { 116*c5c4113dSnw UNLOCK_CONFIG(); 117*c5c4113dSnw (void) idmapdlog(LOG_NOTICE, 118*c5c4113dSnw "idmapd: Failed to reload config"); 119*c5c4113dSnw term_handler(sig); 120*c5c4113dSnw } 121*c5c4113dSnw UNLOCK_CONFIG(); 122*c5c4113dSnw print_idmapdstate(); 123*c5c4113dSnw } 124*c5c4113dSnw 125*c5c4113dSnw /*ARGSUSED*/ 126*c5c4113dSnw static void 127*c5c4113dSnw term_handler(int sig) { 128*c5c4113dSnw (void) idmapdlog(LOG_INFO, "idmapd: Terminating."); 129*c5c4113dSnw fini_idmapd(); 130*c5c4113dSnw _exit(0); 131*c5c4113dSnw } 132*c5c4113dSnw 133*c5c4113dSnw static int pipe_fd = -1; 134*c5c4113dSnw 135*c5c4113dSnw static void 136*c5c4113dSnw daemonize_ready(void) { 137*c5c4113dSnw char data = '\0'; 138*c5c4113dSnw /* 139*c5c4113dSnw * wake the parent 140*c5c4113dSnw */ 141*c5c4113dSnw (void) write(pipe_fd, &data, 1); 142*c5c4113dSnw (void) close(pipe_fd); 143*c5c4113dSnw } 144*c5c4113dSnw 145*c5c4113dSnw static int 146*c5c4113dSnw daemonize_start(void) { 147*c5c4113dSnw char data; 148*c5c4113dSnw int status; 149*c5c4113dSnw int devnull; 150*c5c4113dSnw int filedes[2]; 151*c5c4113dSnw pid_t pid; 152*c5c4113dSnw 153*c5c4113dSnw devnull = open("/dev/null", O_RDONLY); 154*c5c4113dSnw if (devnull < 0) 155*c5c4113dSnw return (-1); 156*c5c4113dSnw (void) dup2(devnull, 0); 157*c5c4113dSnw (void) dup2(2, 1); /* stderr only */ 158*c5c4113dSnw if (pipe(filedes) < 0) 159*c5c4113dSnw return (-1); 160*c5c4113dSnw if ((pid = fork1()) < 0) 161*c5c4113dSnw return (-1); 162*c5c4113dSnw if (pid != 0) { 163*c5c4113dSnw /* 164*c5c4113dSnw * parent 165*c5c4113dSnw */ 166*c5c4113dSnw struct sigaction act; 167*c5c4113dSnw act.sa_sigaction = SIG_DFL; 168*c5c4113dSnw (void) sigemptyset(&act.sa_mask); 169*c5c4113dSnw act.sa_flags = 0; 170*c5c4113dSnw (void) sigaction(SIGPIPE, &act, NULL); /* ignore SIGPIPE */ 171*c5c4113dSnw (void) close(filedes[1]); 172*c5c4113dSnw if (read(filedes[0], &data, 1) == 1) { 173*c5c4113dSnw /* presume success */ 174*c5c4113dSnw _exit(0); 175*c5c4113dSnw } 176*c5c4113dSnw status = -1; 177*c5c4113dSnw (void) wait4(pid, &status, 0, NULL); 178*c5c4113dSnw if (WIFEXITED(status)) 179*c5c4113dSnw _exit(WEXITSTATUS(status)); 180*c5c4113dSnw else 181*c5c4113dSnw _exit(-1); 182*c5c4113dSnw } 183*c5c4113dSnw 184*c5c4113dSnw /* 185*c5c4113dSnw * child 186*c5c4113dSnw */ 187*c5c4113dSnw pipe_fd = filedes[1]; 188*c5c4113dSnw (void) close(filedes[0]); 189*c5c4113dSnw (void) setsid(); 190*c5c4113dSnw (void) umask(0077); 191*c5c4113dSnw openlog("idmap", LOG_PID, LOG_DAEMON); 192*c5c4113dSnw _idmapdstate.daemon_mode = TRUE; 193*c5c4113dSnw return (0); 194*c5c4113dSnw } 195*c5c4113dSnw 196*c5c4113dSnw 197*c5c4113dSnw int 198*c5c4113dSnw main(int argc, char **argv) 199*c5c4113dSnw { 200*c5c4113dSnw int c; 201*c5c4113dSnw #ifdef RPC_SVC_FG 202*c5c4113dSnw bool_t daemonize = FALSE; 203*c5c4113dSnw #else 204*c5c4113dSnw bool_t daemonize = TRUE; 205*c5c4113dSnw #endif 206*c5c4113dSnw 207*c5c4113dSnw while ((c = getopt(argc, argv, "d")) != EOF) { 208*c5c4113dSnw switch (c) { 209*c5c4113dSnw case 'd': 210*c5c4113dSnw daemonize = FALSE; 211*c5c4113dSnw break; 212*c5c4113dSnw default: 213*c5c4113dSnw break; 214*c5c4113dSnw } 215*c5c4113dSnw } 216*c5c4113dSnw 217*c5c4113dSnw /* set locale and domain for internationalization */ 218*c5c4113dSnw (void) setlocale(LC_ALL, ""); 219*c5c4113dSnw (void) textdomain(TEXT_DOMAIN); 220*c5c4113dSnw 221*c5c4113dSnw if (is_system_labeled() && (getzoneid() != GLOBAL_ZONEID)) { 222*c5c4113dSnw (void) idmapdlog(LOG_ERR, 223*c5c4113dSnw "idmapd: With TX, idmapd runs only in the global zone"); 224*c5c4113dSnw exit(1); 225*c5c4113dSnw } 226*c5c4113dSnw 227*c5c4113dSnw /* create directories as root and chown to daemon uid */ 228*c5c4113dSnw if (create_directory(IDMAP_DBDIR, DAEMON_UID, DAEMON_GID) < 0) 229*c5c4113dSnw exit(1); 230*c5c4113dSnw if (create_directory(IDMAP_CACHEDIR, DAEMON_UID, DAEMON_GID) < 0) 231*c5c4113dSnw exit(1); 232*c5c4113dSnw 233*c5c4113dSnw INIT_IDMAPD_STATE(); 234*c5c4113dSnw 235*c5c4113dSnw (void) mutex_init(&_svcstate_lock, USYNC_THREAD, NULL); 236*c5c4113dSnw set_signal_handlers(); 237*c5c4113dSnw 238*c5c4113dSnw if (daemonize == TRUE) { 239*c5c4113dSnw if (daemonize_start() < 0) { 240*c5c4113dSnw (void) perror("idmapd: unable to daemonize"); 241*c5c4113dSnw exit(-1); 242*c5c4113dSnw } 243*c5c4113dSnw } else 244*c5c4113dSnw (void) umask(0077); 245*c5c4113dSnw 246*c5c4113dSnw init_idmapd(); 247*c5c4113dSnw 248*c5c4113dSnw if (__init_daemon_priv(PU_RESETGROUPS|PU_CLEARLIMITSET, 249*c5c4113dSnw DAEMON_UID, DAEMON_GID, 250*c5c4113dSnw PRIV_PROC_AUDIT, PRIV_FILE_DAC_READ, 251*c5c4113dSnw (char *)NULL) == -1) { 252*c5c4113dSnw (void) idmapdlog(LOG_ERR, 253*c5c4113dSnw gettext("idmapd: unable to drop privileges")); 254*c5c4113dSnw exit(1); 255*c5c4113dSnw } 256*c5c4113dSnw 257*c5c4113dSnw __fini_daemon_priv(PRIV_PROC_FORK, PRIV_PROC_EXEC, PRIV_PROC_SESSION, 258*c5c4113dSnw PRIV_FILE_LINK_ANY, PRIV_PROC_INFO, (char *)NULL); 259*c5c4113dSnw 260*c5c4113dSnw if (daemonize == TRUE) 261*c5c4113dSnw daemonize_ready(); 262*c5c4113dSnw 263*c5c4113dSnw /* With doors RPC this just wastes this thread, oh well */ 264*c5c4113dSnw svc_run(); 265*c5c4113dSnw return (0); 266*c5c4113dSnw } 267*c5c4113dSnw 268*c5c4113dSnw static void 269*c5c4113dSnw init_idmapd() { 270*c5c4113dSnw int error; 271*c5c4113dSnw 272*c5c4113dSnw memset(&_idmapdstate, 0, sizeof (_idmapdstate)); 273*c5c4113dSnw 274*c5c4113dSnw if (sysinfo(SI_HOSTNAME, _idmapdstate.hostname, 275*c5c4113dSnw sizeof (_idmapdstate.hostname)) == -1) { 276*c5c4113dSnw error = errno; 277*c5c4113dSnw idmapdlog(LOG_ERR, 278*c5c4113dSnw "idmapd: unable to determine hostname, error: %d", 279*c5c4113dSnw error); 280*c5c4113dSnw exit(1); 281*c5c4113dSnw } 282*c5c4113dSnw 283*c5c4113dSnw if (sysinfo(SI_SRPC_DOMAIN, _idmapdstate.domainname, 284*c5c4113dSnw sizeof (_idmapdstate.domainname)) == -1) { 285*c5c4113dSnw error = errno; 286*c5c4113dSnw idmapdlog(LOG_ERR, 287*c5c4113dSnw "idmapd: unable to determine name service domain, error: %d", 288*c5c4113dSnw error); 289*c5c4113dSnw exit(1); 290*c5c4113dSnw } 291*c5c4113dSnw 292*c5c4113dSnw setegid(DAEMON_GID); 293*c5c4113dSnw seteuid(DAEMON_UID); 294*c5c4113dSnw if (init_mapping_system() < 0) { 295*c5c4113dSnw idmapdlog(LOG_ERR, 296*c5c4113dSnw "idmapd: unable to initialize mapping system"); 297*c5c4113dSnw exit(1); 298*c5c4113dSnw } 299*c5c4113dSnw seteuid(0); 300*c5c4113dSnw setegid(0); 301*c5c4113dSnw 302*c5c4113dSnw xprt = svc_door_create(idmap_prog_1, IDMAP_PROG, IDMAP_V1, 0); 303*c5c4113dSnw if (xprt == NULL) { 304*c5c4113dSnw idmapdlog(LOG_ERR, 305*c5c4113dSnw "idmapd: unable to create door RPC service"); 306*c5c4113dSnw goto errout; 307*c5c4113dSnw } 308*c5c4113dSnw 309*c5c4113dSnw dfd = xprt->xp_fd; 310*c5c4113dSnw 311*c5c4113dSnw if (dfd == -1) { 312*c5c4113dSnw idmapdlog(LOG_ERR, "idmapd: unable to register door"); 313*c5c4113dSnw goto errout; 314*c5c4113dSnw } 315*c5c4113dSnw if ((error = idmap_reg(dfd)) != 0) { 316*c5c4113dSnw idmapdlog(LOG_ERR, "idmapd: unable to register door (%s)", 317*c5c4113dSnw strerror(error)); 318*c5c4113dSnw goto errout; 319*c5c4113dSnw } 320*c5c4113dSnw 321*c5c4113dSnw if ((error = allocids(_idmapdstate.new_eph_db, 322*c5c4113dSnw 8192, &_idmapdstate.next_uid, 323*c5c4113dSnw 8192, &_idmapdstate.next_gid)) != 0) { 324*c5c4113dSnw idmapdlog(LOG_ERR, "idmapd: unable to allocate ephemeral IDs " 325*c5c4113dSnw "(%s)", strerror(error)); 326*c5c4113dSnw _idmapdstate.next_uid = _idmapdstate.limit_uid = SENTINEL_PID; 327*c5c4113dSnw _idmapdstate.next_gid = _idmapdstate.limit_gid = SENTINEL_PID; 328*c5c4113dSnw } else { 329*c5c4113dSnw _idmapdstate.limit_uid = _idmapdstate.next_uid + 8192; 330*c5c4113dSnw _idmapdstate.limit_gid = _idmapdstate.next_gid + 8192; 331*c5c4113dSnw } 332*c5c4113dSnw 333*c5c4113dSnw print_idmapdstate(); 334*c5c4113dSnw 335*c5c4113dSnw return; 336*c5c4113dSnw 337*c5c4113dSnw errout: 338*c5c4113dSnw fini_idmapd(); 339*c5c4113dSnw exit(1); 340*c5c4113dSnw } 341*c5c4113dSnw 342*c5c4113dSnw static void 343*c5c4113dSnw fini_idmapd() { 344*c5c4113dSnw idmap_unreg(dfd); 345*c5c4113dSnw fini_mapping_system(); 346*c5c4113dSnw if (xprt != NULL) 347*c5c4113dSnw svc_destroy(xprt); 348*c5c4113dSnw } 349*c5c4113dSnw 350*c5c4113dSnw void 351*c5c4113dSnw idmapdlog(int pri, const char *format, ...) { 352*c5c4113dSnw va_list args; 353*c5c4113dSnw 354*c5c4113dSnw va_start(args, format); 355*c5c4113dSnw if (_idmapdstate.daemon_mode == FALSE) { 356*c5c4113dSnw (void) vfprintf(stderr, format, args); 357*c5c4113dSnw (void) fprintf(stderr, "\n"); 358*c5c4113dSnw } 359*c5c4113dSnw (void) vsyslog(pri, format, args); 360*c5c4113dSnw va_end(args); 361*c5c4113dSnw } 362