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