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