2 * nfsdcld.c -- NFSv4 client name tracking daemon
4 * Copyright (C) 2011 Red Hat, Jeff Layton <jlayton@redhat.com>
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301, USA.
24 #endif /* HAVE_CONFIG_H */
32 #include <sys/types.h>
36 #include <sys/inotify.h>
37 #ifdef HAVE_SYS_CAPABILITY_H
38 #include <sys/prctl.h>
39 #include <sys/capability.h>
48 #define PIPEFS_DIR NFS_STATEDIR "/rpc_pipefs"
51 #define DEFAULT_CLD_PATH PIPEFS_DIR "/nfsd/cld"
53 #ifndef CLD_DEFAULT_STORAGEDIR
54 #define CLD_DEFAULT_STORAGEDIR NFS_STATEDIR "/nfsdcld"
57 #define UPCALL_VERSION 1
59 /* private data structures */
62 struct event cl_event;
63 struct cld_msg cl_msg;
66 /* global variables */
67 static char *pipepath = DEFAULT_CLD_PATH;
68 static int inotify_fd = -1;
69 static struct event pipedir_event;
71 static struct option longopts[] =
73 { "help", 0, NULL, 'h' },
74 { "foreground", 0, NULL, 'F' },
75 { "debug", 0, NULL, 'd' },
76 { "pipe", 1, NULL, 'p' },
77 { "storagedir", 1, NULL, 's' },
81 /* forward declarations */
82 static void cldcb(int UNUSED(fd), short which, void *data);
87 printf("%s [ -hFd ] [ -p pipe ] [ -s dir ]\n", progname);
94 #ifdef HAVE_SYS_CAPABILITY_H
99 xlog(L_ERROR, "Not running as root. Daemon won't be able to "
100 "open the pipe after dropping capabilities!");
104 /* prune the bounding set to nothing */
105 for (i = 0; prctl(PR_CAPBSET_READ, i, 0, 0, 0) >= 0 ; ++i) {
106 ret = prctl(PR_CAPBSET_DROP, i, 0, 0, 0);
108 xlog(L_ERROR, "Unable to prune capability %lu from "
109 "bounding set: %m", i);
114 /* get a blank capset */
117 xlog(L_ERROR, "Unable to get blank capability set: %m");
121 /* reset the process capabilities */
122 if (cap_set_proc(caps) != 0) {
123 xlog(L_ERROR, "Unable to set process capabilities: %m");
131 #define INOTIFY_EVENT_MAX (sizeof(struct inotify_event) + NAME_MAX)
134 cld_pipe_open(struct cld_client *clnt)
138 xlog(D_GENERAL, "%s: opening upcall pipe %s", __func__, pipepath);
139 fd = open(pipepath, O_RDWR, 0);
141 xlog(D_GENERAL, "%s: open of %s failed: %m", __func__, pipepath);
145 if (clnt->cl_event.ev_flags & EVLIST_INIT)
146 event_del(&clnt->cl_event);
147 if (clnt->cl_fd >= 0)
151 event_set(&clnt->cl_event, clnt->cl_fd, EV_READ, cldcb, clnt);
152 /* event_add is done by the caller */
157 cld_inotify_cb(int UNUSED(fd), short which, void *data)
162 char evbuf[INOTIFY_EVENT_MAX];
163 char *dirc = NULL, *pname;
164 struct inotify_event *event = (struct inotify_event *)evbuf;
165 struct cld_client *clnt = data;
167 if (which != EV_READ)
170 xlog(D_GENERAL, "%s: called for EV_READ", __func__);
172 dirc = strndup(pipepath, PATH_MAX);
174 xlog(L_ERROR, "%s: unable to allocate memory", __func__);
178 rret = read(inotify_fd, evbuf, INOTIFY_EVENT_MAX);
180 xlog(L_ERROR, "%s: read from inotify fd failed: %m", __func__);
184 /* check to see if we have a filename in the evbuf */
186 xlog(D_GENERAL, "%s: no filename in inotify event", __func__);
190 pname = basename(dirc);
191 elen = strnlen(event->name, event->len);
193 /* does the filename match our pipe? */
194 if (strlen(pname) != elen || memcmp(pname, event->name, elen)) {
195 xlog(D_GENERAL, "%s: wrong filename (%s)", __func__,
200 ret = cld_pipe_open(clnt);
203 /* readd the event for the cl_event pipe */
204 event_add(&clnt->cl_event, NULL);
207 /* pipe must have disappeared, wait for it to come back */
210 /* anything else is fatal */
211 xlog(L_FATAL, "%s: unable to open new pipe (%d). Aborting.",
217 event_add(&pipedir_event, NULL);
222 cld_inotify_setup(void)
227 dirc = strndup(pipepath, PATH_MAX);
229 xlog_err("%s: unable to allocate memory", __func__);
234 dname = dirname(dirc);
236 inotify_fd = inotify_init();
237 if (inotify_fd < 0) {
238 xlog_err("%s: inotify_init failed: %m", __func__);
243 ret = inotify_add_watch(inotify_fd, dname, IN_CREATE);
245 xlog_err("%s: inotify_add_watch failed: %m", __func__);
259 * Set an inotify watch on the directory that should contain the pipe, and then
260 * try to open it. If it fails with anything but -ENOENT, return the error
263 * If it succeeds, then set up the pipe event handler. At that point, set up
264 * the inotify event handler and go ahead and return success.
267 cld_pipe_init(struct cld_client *clnt)
271 xlog(D_GENERAL, "%s: init pipe handlers", __func__);
273 ret = cld_inotify_setup();
278 ret = cld_pipe_open(clnt);
281 /* add the event and we're good to go */
282 event_add(&clnt->cl_event, NULL);
285 /* ignore this error -- cld_inotify_cb will handle it */
289 /* anything else is fatal */
294 /* set event for inotify read */
295 event_set(&pipedir_event, inotify_fd, EV_READ, cld_inotify_cb, clnt);
296 event_add(&pipedir_event, NULL);
302 cld_not_implemented(struct cld_client *clnt)
305 ssize_t bsize, wsize;
306 struct cld_msg *cmsg = &clnt->cl_msg;
308 xlog(D_GENERAL, "%s: downcalling with not implemented error", __func__);
311 cmsg->cm_status = -EOPNOTSUPP;
313 bsize = sizeof(*cmsg);
315 wsize = atomicio((void *)write, clnt->cl_fd, cmsg, bsize);
317 xlog(L_ERROR, "%s: problem writing to cld pipe (%ld): %m",
320 /* reopen pipe, just to be sure */
321 ret = cld_pipe_open(clnt);
323 xlog(L_FATAL, "%s: unable to reopen pipe: %d", __func__, ret);
329 cld_create(struct cld_client *clnt)
332 ssize_t bsize, wsize;
333 struct cld_msg *cmsg = &clnt->cl_msg;
335 xlog(D_GENERAL, "%s: create client record.", __func__);
337 ret = sqlite_insert_client(cmsg->cm_u.cm_name.cn_id,
338 cmsg->cm_u.cm_name.cn_len);
340 cmsg->cm_status = ret ? -EREMOTEIO : ret;
342 bsize = sizeof(*cmsg);
344 xlog(D_GENERAL, "Doing downcall with status %d", cmsg->cm_status);
345 wsize = atomicio((void *)write, clnt->cl_fd, cmsg, bsize);
346 if (wsize != bsize) {
347 xlog(L_ERROR, "%s: problem writing to cld pipe (%ld): %m",
349 ret = cld_pipe_open(clnt);
351 xlog(L_FATAL, "%s: unable to reopen pipe: %d",
359 cld_remove(struct cld_client *clnt)
362 ssize_t bsize, wsize;
363 struct cld_msg *cmsg = &clnt->cl_msg;
365 xlog(D_GENERAL, "%s: remove client record.", __func__);
367 ret = sqlite_remove_client(cmsg->cm_u.cm_name.cn_id,
368 cmsg->cm_u.cm_name.cn_len);
370 cmsg->cm_status = ret ? -EREMOTEIO : ret;
372 bsize = sizeof(*cmsg);
374 xlog(D_GENERAL, "%s: downcall with status %d", __func__,
376 wsize = atomicio((void *)write, clnt->cl_fd, cmsg, bsize);
377 if (wsize != bsize) {
378 xlog(L_ERROR, "%s: problem writing to cld pipe (%ld): %m",
380 ret = cld_pipe_open(clnt);
382 xlog(L_FATAL, "%s: unable to reopen pipe: %d",
390 cld_check(struct cld_client *clnt)
393 ssize_t bsize, wsize;
394 struct cld_msg *cmsg = &clnt->cl_msg;
396 xlog(D_GENERAL, "%s: check client record", __func__);
398 ret = sqlite_check_client(cmsg->cm_u.cm_name.cn_id,
399 cmsg->cm_u.cm_name.cn_len);
402 cmsg->cm_status = ret ? -EACCES : ret;
404 bsize = sizeof(*cmsg);
406 xlog(D_GENERAL, "%s: downcall with status %d", __func__,
408 wsize = atomicio((void *)write, clnt->cl_fd, cmsg, bsize);
409 if (wsize != bsize) {
410 xlog(L_ERROR, "%s: problem writing to cld pipe (%ld): %m",
412 ret = cld_pipe_open(clnt);
414 xlog(L_FATAL, "%s: unable to reopen pipe: %d",
422 cld_gracedone(struct cld_client *clnt)
425 ssize_t bsize, wsize;
426 struct cld_msg *cmsg = &clnt->cl_msg;
428 xlog(D_GENERAL, "%s: grace done. cm_gracetime=%ld", __func__,
429 cmsg->cm_u.cm_gracetime);
431 ret = sqlite_remove_unreclaimed(cmsg->cm_u.cm_gracetime);
433 /* set up reply: downcall with 0 status */
434 cmsg->cm_status = ret ? -EREMOTEIO : ret;
436 bsize = sizeof(*cmsg);
438 xlog(D_GENERAL, "Doing downcall with status %d", cmsg->cm_status);
439 wsize = atomicio((void *)write, clnt->cl_fd, cmsg, bsize);
440 if (wsize != bsize) {
441 xlog(L_ERROR, "%s: problem writing to cld pipe (%ld): %m",
443 ret = cld_pipe_open(clnt);
445 xlog(L_FATAL, "%s: unable to reopen pipe: %d",
453 cldcb(int UNUSED(fd), short which, void *data)
456 struct cld_client *clnt = data;
457 struct cld_msg *cmsg = &clnt->cl_msg;
459 if (which != EV_READ)
462 len = atomicio(read, clnt->cl_fd, cmsg, sizeof(*cmsg));
464 xlog(L_ERROR, "%s: pipe read failed: %m", __func__);
469 if (cmsg->cm_vers != UPCALL_VERSION) {
470 xlog(L_ERROR, "%s: unsupported upcall version: %hu",
476 switch(cmsg->cm_cmd) {
490 xlog(L_WARNING, "%s: command %u is not yet implemented",
491 __func__, cmsg->cm_cmd);
492 cld_not_implemented(clnt);
495 event_add(&clnt->cl_event, NULL);
499 main(int argc, char **argv)
503 bool foreground = false;
505 char *storagedir = CLD_DEFAULT_STORAGEDIR;
506 struct cld_client clnt;
508 memset(&clnt, 0, sizeof(clnt));
510 progname = strdup(basename(argv[0]));
512 fprintf(stderr, "%s: unable to allocate memory.\n", argv[0]);
520 /* process command-line options */
521 while ((arg = getopt_long(argc, argv, "hdFp:s:", longopts,
525 xlog_config(D_ALL, 1);
549 xlog(L_ERROR, "Unable to daemonize: %m");
554 /* drop all capabilities */
560 * now see if the storagedir is writable by root w/o CAP_DAC_OVERRIDE.
561 * If it isn't then give the user a warning but proceed as if
562 * everything is OK. If the DB has already been created, then
563 * everything might still work. If it doesn't exist at all, then
564 * assume that the maindb init will be able to create it. Fail on
567 if (access(storagedir, W_OK) == -1) {
570 xlog(L_WARNING, "Storage directory %s is not writable. "
571 "Should be owned by root and writable "
572 "by owner!", storagedir);
575 /* ignore and assume that we can create dir as root */
578 xlog(L_ERROR, "Unexpected error when checking access "
579 "on %s: %m", storagedir);
585 /* set up storage db */
586 rc = sqlite_maindb_init(storagedir);
588 xlog(L_ERROR, "Failed to open main database: %d", rc);
592 /* set up event handler */
593 rc = cld_pipe_init(&clnt);
597 xlog(D_GENERAL, "%s: Starting event dispatch handler.", __func__);
598 rc = event_dispatch();
600 xlog(L_ERROR, "%s: event_dispatch failed: %m", __func__);