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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <stdio.h> 30 #include <stdlib.h> 31 #include <stropts.h> 32 #include <signal.h> 33 #include <fcntl.h> 34 #include <door.h> 35 #include <priv_utils.h> 36 #include <locale.h> 37 #include <strings.h> 38 #include <syslog.h> 39 #include <unistd.h> 40 #include <nfs/nfs4.h> 41 #include <nfs/nfsid_map.h> 42 #include <rpcsvc/daemon_utils.h> 43 #include <arpa/nameser.h> 44 #include <nfs/nfssys.h> 45 #include <errno.h> 46 #include <pwd.h> 47 #include <grp.h> 48 #include "nfsmapid_resolv.h" 49 50 extern struct group *_uncached_getgrgid_r(gid_t, struct group *, char *, int); 51 extern struct group *_uncached_getgrnam_r(const char *, struct group *, 52 char *, int); 53 extern struct passwd *_uncached_getpwuid_r(uid_t, struct passwd *, char *, int); 54 extern struct passwd *_uncached_getpwnam_r(const char *, struct passwd *, 55 char *, int); 56 57 /* 58 * seconds to cache nfsmapid domain info 59 */ 60 #define NFSCFG_DEFAULT_DOMAIN_TMOUT (5 * 60) 61 #define NFSMAPID_DOOR "/var/run/nfsmapid_door" 62 63 extern void nfsmapid_func(void *, char *, size_t, door_desc_t *, uint_t); 64 65 extern void check_domain(int); 66 extern void idmap_kcall(int); 67 extern rwlock_t domain_cfg_lock; 68 extern void open_diag_file(void); 69 70 size_t pwd_buflen = 0; 71 size_t grp_buflen = 0; 72 thread_t sig_thread; 73 static char *MyName; 74 75 /* 76 * nfscfg_domain_tmout is used by nfsv4-test scripts to query 77 * the nfsmapid daemon for the proper timeout. Don't delete ! 78 */ 79 time_t nfscfg_domain_tmout = NFSCFG_DEFAULT_DOMAIN_TMOUT; 80 81 /* 82 * Processing for daemonization 83 */ 84 static void 85 daemonize(void) 86 { 87 switch (fork()) { 88 case -1: 89 perror("nfsmapid: can't fork"); 90 exit(2); 91 /* NOTREACHED */ 92 case 0: /* child */ 93 break; 94 95 default: /* parent */ 96 _exit(0); 97 } 98 99 if (chdir("/") < 0) 100 syslog(LOG_ERR, gettext("chdir /: %m")); 101 102 /* 103 * Close stdin, stdout, and stderr. 104 * Open again to redirect input+output 105 */ 106 (void) close(0); 107 (void) close(1); 108 (void) close(2); 109 (void) open("/dev/null", O_RDONLY); 110 (void) open("/dev/null", O_WRONLY); 111 (void) dup(1); 112 (void) setsid(); 113 } 114 115 /* ARGSUSED */ 116 static void * 117 sig_handler(void *arg) 118 { 119 siginfo_t si; 120 sigset_t sigset; 121 struct timespec tmout; 122 int ret; 123 124 tmout.tv_sec = nfscfg_domain_tmout; 125 tmout.tv_nsec = 0; 126 (void) sigemptyset(&sigset); 127 (void) sigaddset(&sigset, SIGHUP); 128 (void) sigaddset(&sigset, SIGTERM); 129 #ifdef DEBUG 130 (void) sigaddset(&sigset, SIGINT); 131 #endif 132 IDMAP_DBG("sig_handler started !", NULL, NULL); 133 134 /*CONSTCOND*/ 135 while (1) { 136 if ((ret = sigtimedwait(&sigset, &si, &tmout)) != 0) { 137 /* 138 * EAGAIN: no signals arrived during timeout. 139 * check/update config files and continue. 140 */ 141 if (ret == -1 && errno == EAGAIN) { 142 check_domain(0); 143 continue; 144 } 145 146 switch (si.si_signo) { 147 case SIGHUP: 148 check_domain(1); 149 break; 150 #ifdef DEBUG 151 case SIGINT: 152 exit(0); 153 #endif 154 case SIGTERM: 155 default: 156 exit(si.si_signo); 157 } 158 } 159 } 160 /*NOTREACHED*/ 161 return (NULL); 162 } 163 164 /* 165 * Thread initialization. Mask out all signals we want our 166 * signal handler to handle for us from any other threads. 167 */ 168 static void 169 thr_init(void) 170 { 171 sigset_t sigset; 172 long thr_flags = (THR_NEW_LWP|THR_DAEMON|THR_SUSPENDED); 173 174 /* 175 * Before we kick off any other threads, mask out desired 176 * signals from main thread so that any subsequent threads 177 * don't receive said signals. 178 */ 179 (void) thr_sigsetmask(NULL, NULL, &sigset); 180 (void) sigaddset(&sigset, SIGHUP); 181 (void) sigaddset(&sigset, SIGTERM); 182 #ifdef DEBUG 183 (void) sigaddset(&sigset, SIGINT); 184 #endif 185 (void) thr_sigsetmask(SIG_SETMASK, &sigset, NULL); 186 187 /* 188 * Create the signal handler thread suspended ! We do things 189 * this way at setup time to minimize the probability of 190 * introducing any race conditions _if_ the process were to 191 * get a SIGHUP signal while creating a new DNS query thread 192 * in get_dns_txt_domain(). 193 */ 194 if (thr_create(NULL, 0, sig_handler, 0, thr_flags, &sig_thread)) { 195 syslog(LOG_ERR, 196 gettext("Failed to create signal handling thread")); 197 exit(4); 198 } 199 } 200 201 static void 202 daemon_init(void) 203 { 204 struct passwd pwd; 205 struct group grp; 206 char *pwd_buf; 207 char *grp_buf; 208 209 /* 210 * Initialize resolver 211 */ 212 (void) resolv_init(); 213 214 /* 215 * passwd/group reentrant interfaces limits 216 */ 217 pwd_buflen = (size_t)sysconf(_SC_GETPW_R_SIZE_MAX); 218 grp_buflen = (size_t)sysconf(_SC_GETGR_R_SIZE_MAX); 219 220 /* 221 * Initialize lock 222 */ 223 (void) rwlock_init(&domain_cfg_lock, USYNC_THREAD, NULL); 224 225 /* 226 * MT initialization is done first so that if there is the 227 * need to fire an additional thread to continue to query 228 * DNS, that thread is started off with the main thread's 229 * sigmask. 230 */ 231 thr_init(); 232 233 /* 234 * Determine nfsmapid domain. 235 */ 236 check_domain(0); 237 238 /* 239 * In the case of nfsmapid running diskless, it is important 240 * to get the initial connections to the nameservices 241 * established to prevent problems like opening a devfs 242 * node to contact a nameservice being blocked by the 243 * resolution of an active devfs lookup. 244 * First issue a set*ent to "open" the databases and then 245 * get an entry and finally lookup a bogus entry to trigger 246 * any lazy opens. 247 */ 248 setpwent(); 249 setgrent(); 250 (void) getpwent(); 251 (void) getgrent(); 252 if ((pwd_buf = malloc(pwd_buflen)) == NULL) 253 return; 254 255 (void) _uncached_getpwnam_r("NF21dmvP", &pwd, pwd_buf, pwd_buflen); 256 (void) _uncached_getpwuid_r(1181794, &pwd, pwd_buf, pwd_buflen); 257 258 if ((grp_buf = realloc(pwd_buf, grp_buflen)) == NULL) { 259 free(pwd_buf); 260 return; 261 } 262 263 (void) _uncached_getgrnam_r("NF21dmvP", &grp, grp_buf, grp_buflen); 264 (void) _uncached_getgrgid_r(1181794, &grp, grp_buf, grp_buflen); 265 free(grp_buf); 266 } 267 268 static int 269 start_svcs(void) 270 { 271 int doorfd = -1; 272 #ifdef DEBUG 273 int dfd; 274 #endif 275 276 if ((doorfd = door_create(nfsmapid_func, NULL, 277 DOOR_REFUSE_DESC | DOOR_NO_CANCEL)) == -1) { 278 syslog(LOG_ERR, "Unable to create door: %m\n"); 279 return (1); 280 } 281 282 #ifdef DEBUG 283 /* 284 * Create a file system path for the door 285 */ 286 if ((dfd = open(NFSMAPID_DOOR, O_RDWR|O_CREAT|O_TRUNC, 287 S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)) == -1) { 288 syslog(LOG_ERR, "Unable to open %s: %m\n", NFSMAPID_DOOR); 289 (void) close(doorfd); 290 return (1); 291 } 292 293 /* 294 * Clean up any stale associations 295 */ 296 (void) fdetach(NFSMAPID_DOOR); 297 298 /* 299 * Register in namespace to pass to the kernel to door_ki_open 300 */ 301 if (fattach(doorfd, NFSMAPID_DOOR) == -1) { 302 syslog(LOG_ERR, "Unable to fattach door: %m\n"); 303 (void) close(dfd); 304 (void) close(doorfd); 305 return (1); 306 } 307 (void) close(dfd); 308 #endif 309 310 /* 311 * Now that we're actually running, go 312 * ahead and flush the kernel flushes 313 * Pass door name to kernel for door_ki_open 314 */ 315 idmap_kcall(doorfd); 316 317 /* 318 * Wait for incoming calls 319 */ 320 /*CONSTCOND*/ 321 while (1) 322 (void) pause(); 323 324 syslog(LOG_ERR, gettext("Door server exited")); 325 return (10); 326 } 327 328 /* ARGSUSED */ 329 int 330 main(int argc, char **argv) 331 { 332 MyName = argv[0]; 333 334 (void) setlocale(LC_ALL, ""); 335 (void) textdomain(TEXT_DOMAIN); 336 337 /* _check_services() framework setup */ 338 (void) _create_daemon_lock(NFSMAPID, DAEMON_UID, DAEMON_GID); 339 340 /* 341 * Open diag file in /var/run while we've got the perms 342 */ 343 open_diag_file(); 344 345 /* 346 * Initialize the daemon to basic + sys_nfs 347 */ 348 if (__init_daemon_priv(PU_RESETGROUPS|PU_CLEARLIMITSET, 349 DAEMON_UID, DAEMON_GID, PRIV_SYS_NFS, (char *)NULL) == -1) { 350 (void) fprintf(stderr, gettext("%s PRIV_SYS_NFS privilege " 351 "missing\n"), MyName); 352 exit(1); 353 } 354 355 /* 356 * Take away a subset of basic, while this is not the absolute 357 * minimum, it is important that it is unique among other 358 * daemons to insure that we get a unique cred that will 359 * result in a unique open_owner. If not, we run the risk 360 * of a diskless client deadlocking with a thread holding 361 * the open_owner seqid lock while upcalling the daemon. 362 * XXX This restriction will go away once we stop holding 363 * XXX open_owner lock across rfscalls! 364 */ 365 (void) priv_set(PRIV_OFF, PRIV_PERMITTED, 366 PRIV_FILE_LINK_ANY, PRIV_PROC_SESSION, 367 (char *)NULL); 368 369 #ifndef DEBUG 370 daemonize(); 371 switch (_enter_daemon_lock(NFSMAPID)) { 372 case 0: 373 break; 374 375 case -1: 376 syslog(LOG_ERR, "error locking for %s: %s", NFSMAPID, 377 strerror(errno)); 378 exit(3); 379 380 default: 381 /* daemon was already running */ 382 exit(0); 383 } 384 #endif 385 openlog(MyName, LOG_PID | LOG_NDELAY, LOG_DAEMON); 386 387 /* Initialize daemon subsystems */ 388 daemon_init(); 389 390 /* start services */ 391 return (start_svcs()); 392 } 393