dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / cmd / fs.d / nfs / nfsmapid / nfsmapid.c
blob9c567637cc7802c1b8c8a02d4415e70ab387c5d5
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <stropts.h>
29 #include <signal.h>
30 #include <fcntl.h>
31 #include <door.h>
32 #include <thread.h>
33 #include <priv_utils.h>
34 #include <locale.h>
35 #include <strings.h>
36 #include <syslog.h>
37 #include <unistd.h>
38 #include <nfs/nfs4.h>
39 #include <nfs/nfsid_map.h>
40 #include <rpcsvc/daemon_utils.h>
41 #include <arpa/nameser.h>
42 #include <nfs/nfssys.h>
43 #include <errno.h>
44 #include <pwd.h>
45 #include <grp.h>
47 extern struct group *_uncached_getgrgid_r(gid_t, struct group *, char *, int);
48 extern struct group *_uncached_getgrnam_r(const char *, struct group *,
49 char *, int);
50 extern struct passwd *_uncached_getpwuid_r(uid_t, struct passwd *, char *, int);
51 extern struct passwd *_uncached_getpwnam_r(const char *, struct passwd *,
52 char *, int);
55 * seconds to cache nfsmapid domain info
57 #define NFSCFG_DEFAULT_DOMAIN_TMOUT (5 * 60)
58 #define NFSMAPID_DOOR "/var/run/nfsmapid_door"
60 extern void nfsmapid_func(void *, char *, size_t, door_desc_t *, uint_t);
62 extern void check_domain(int);
63 extern void idmap_kcall(int);
64 extern void open_diag_file(void);
66 size_t pwd_buflen = 0;
67 size_t grp_buflen = 0;
68 thread_t sig_thread;
69 static char *MyName;
72 * nfscfg_domain_tmout is used by nfsv4-test scripts to query
73 * the nfsmapid daemon for the proper timeout. Don't delete !
75 time_t nfscfg_domain_tmout = NFSCFG_DEFAULT_DOMAIN_TMOUT;
78 * Processing for daemonization
80 static void
81 daemonize(void)
83 switch (fork()) {
84 case -1:
85 perror("nfsmapid: can't fork");
86 exit(2);
87 /* NOTREACHED */
88 case 0: /* child */
89 break;
91 default: /* parent */
92 _exit(0);
95 if (chdir("/") < 0)
96 syslog(LOG_ERR, gettext("chdir /: %m"));
99 * Close stdin, stdout, and stderr.
100 * Open again to redirect input+output
102 (void) close(0);
103 (void) close(1);
104 (void) close(2);
105 (void) open("/dev/null", O_RDONLY);
106 (void) open("/dev/null", O_WRONLY);
107 (void) dup(1);
108 (void) setsid();
111 /* ARGSUSED */
112 static void *
113 sig_handler(void *arg)
115 siginfo_t si;
116 sigset_t sigset;
117 struct timespec tmout;
118 int ret;
120 tmout.tv_nsec = 0;
121 (void) sigemptyset(&sigset);
122 (void) sigaddset(&sigset, SIGHUP);
123 (void) sigaddset(&sigset, SIGTERM);
124 #ifdef DEBUG
125 (void) sigaddset(&sigset, SIGINT);
126 #endif
128 /*CONSTCOND*/
129 while (1) {
130 tmout.tv_sec = nfscfg_domain_tmout;
131 if ((ret = sigtimedwait(&sigset, &si, &tmout)) != 0) {
133 * EAGAIN: no signals arrived during timeout.
134 * check/update config files and continue.
136 if (ret == -1 && errno == EAGAIN) {
137 check_domain(0);
138 continue;
141 switch (si.si_signo) {
142 case SIGHUP:
143 check_domain(1);
144 break;
145 #ifdef DEBUG
146 case SIGINT:
147 exit(0);
148 #endif
149 case SIGTERM:
150 default:
151 exit(si.si_signo);
155 /*NOTREACHED*/
156 return (NULL);
160 * Thread initialization. Mask out all signals we want our
161 * signal handler to handle for us from any other threads.
163 static void
164 thr_init(void)
166 sigset_t sigset;
167 long thr_flags = (THR_NEW_LWP|THR_DAEMON|THR_SUSPENDED);
170 * Before we kick off any other threads, mask out desired
171 * signals from main thread so that any subsequent threads
172 * don't receive said signals.
174 (void) thr_sigsetmask(0, NULL, &sigset);
175 (void) sigaddset(&sigset, SIGHUP);
176 (void) sigaddset(&sigset, SIGTERM);
177 #ifdef DEBUG
178 (void) sigaddset(&sigset, SIGINT);
179 #endif
180 (void) thr_sigsetmask(SIG_SETMASK, &sigset, NULL);
183 * Create the signal handler thread suspended ! We do things
184 * this way at setup time to minimize the probability of
185 * introducing any race conditions _if_ the process were to
186 * get a SIGHUP signal while creating a new DNS query thread
187 * in get_dns_txt_domain().
189 if (thr_create(NULL, 0, sig_handler, 0, thr_flags, &sig_thread)) {
190 syslog(LOG_ERR,
191 gettext("Failed to create signal handling thread"));
192 exit(4);
196 static void
197 daemon_init(void)
199 struct passwd pwd;
200 struct group grp;
201 char *pwd_buf;
202 char *grp_buf;
205 * passwd/group reentrant interfaces limits
207 pwd_buflen = (size_t)sysconf(_SC_GETPW_R_SIZE_MAX);
208 grp_buflen = (size_t)sysconf(_SC_GETGR_R_SIZE_MAX);
211 * MT initialization is done first so that if there is the
212 * need to fire an additional thread to continue to query
213 * DNS, that thread is started off with the main thread's
214 * sigmask.
216 thr_init();
219 * Determine nfsmapid domain.
221 check_domain(0);
224 * In the case of nfsmapid running diskless, it is important
225 * to get the initial connections to the nameservices
226 * established to prevent problems like opening a devfs
227 * node to contact a nameservice being blocked by the
228 * resolution of an active devfs lookup.
229 * First issue a set*ent to "open" the databases and then
230 * get an entry and finally lookup a bogus entry to trigger
231 * any lazy opens.
233 setpwent();
234 setgrent();
235 (void) getpwent();
236 (void) getgrent();
237 if ((pwd_buf = malloc(pwd_buflen)) == NULL)
238 return;
240 (void) _uncached_getpwnam_r("NF21dmvP", &pwd, pwd_buf, pwd_buflen);
241 (void) _uncached_getpwuid_r(1181794, &pwd, pwd_buf, pwd_buflen);
243 if ((grp_buf = realloc(pwd_buf, grp_buflen)) == NULL) {
244 free(pwd_buf);
245 return;
248 (void) _uncached_getgrnam_r("NF21dmvP", &grp, grp_buf, grp_buflen);
249 (void) _uncached_getgrgid_r(1181794, &grp, grp_buf, grp_buflen);
250 free(grp_buf);
253 static int
254 start_svcs(void)
256 int doorfd = -1;
257 #ifdef DEBUG
258 int dfd;
259 #endif
261 if ((doorfd = door_create(nfsmapid_func, NULL,
262 DOOR_REFUSE_DESC | DOOR_NO_CANCEL)) == -1) {
263 syslog(LOG_ERR, "Unable to create door: %m\n");
264 return (1);
267 #ifdef DEBUG
269 * Create a file system path for the door
271 if ((dfd = open(NFSMAPID_DOOR, O_RDWR|O_CREAT|O_TRUNC,
272 S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)) == -1) {
273 syslog(LOG_ERR, "Unable to open %s: %m\n", NFSMAPID_DOOR);
274 (void) close(doorfd);
275 return (1);
279 * Clean up any stale associations
281 (void) fdetach(NFSMAPID_DOOR);
284 * Register in namespace to pass to the kernel to door_ki_open
286 if (fattach(doorfd, NFSMAPID_DOOR) == -1) {
287 syslog(LOG_ERR, "Unable to fattach door: %m\n");
288 (void) close(dfd);
289 (void) close(doorfd);
290 return (1);
292 (void) close(dfd);
293 #endif
296 * Now that we're actually running, go
297 * ahead and flush the kernel flushes
298 * Pass door name to kernel for door_ki_open
300 idmap_kcall(doorfd);
303 * Wait for incoming calls
305 /*CONSTCOND*/
306 while (1)
307 (void) pause();
309 syslog(LOG_ERR, gettext("Door server exited"));
310 return (10);
313 /* ARGSUSED */
315 main(int argc, char **argv)
317 MyName = argv[0];
319 (void) setlocale(LC_ALL, "");
320 (void) textdomain(TEXT_DOMAIN);
322 /* _check_services() framework setup */
323 (void) _create_daemon_lock(NFSMAPID, DAEMON_UID, DAEMON_GID);
326 * Open diag file in /var/run while we've got the perms
328 open_diag_file();
331 * Initialize the daemon to basic + sys_nfs
333 #ifndef DEBUG
334 if (__init_daemon_priv(PU_RESETGROUPS|PU_CLEARLIMITSET,
335 DAEMON_UID, DAEMON_GID, PRIV_SYS_NFS, NULL) == -1) {
336 (void) fprintf(stderr, gettext("%s PRIV_SYS_NFS privilege "
337 "missing\n"), MyName);
338 exit(1);
340 #endif
343 * Take away a subset of basic, while this is not the absolute
344 * minimum, it is important that it is unique among other
345 * daemons to insure that we get a unique cred that will
346 * result in a unique open_owner. If not, we run the risk
347 * of a diskless client deadlocking with a thread holding
348 * the open_owner seqid lock while upcalling the daemon.
349 * XXX This restriction will go away once we stop holding
350 * XXX open_owner lock across rfscalls!
352 (void) priv_set(PRIV_OFF, PRIV_PERMITTED, PRIV_FILE_LINK_ANY,
353 PRIV_PROC_SESSION, NULL);
355 #ifndef DEBUG
356 daemonize();
357 switch (_enter_daemon_lock(NFSMAPID)) {
358 case 0:
359 break;
361 case -1:
362 syslog(LOG_ERR, "error locking for %s: %s", NFSMAPID,
363 strerror(errno));
364 exit(3);
366 default:
367 /* daemon was already running */
368 exit(0);
370 #endif
371 openlog(MyName, LOG_PID | LOG_NDELAY, LOG_DAEMON);
373 /* Initialize daemon subsystems */
374 daemon_init();
376 /* start services */
377 return (start_svcs());