]> git.decadent.org.uk Git - nfs-utils.git/blob - utils/gssd/gssd_main_loop.c
gssd: add upcall support for callback authentication
[nfs-utils.git] / utils / gssd / gssd_main_loop.c
1 /*
2   Copyright (c) 2004 The Regents of the University of Michigan.
3   All rights reserved.
4
5   Redistribution and use in source and binary forms, with or without
6   modification, are permitted provided that the following conditions
7   are met:
8
9   1. Redistributions of source code must retain the above copyright
10      notice, this list of conditions and the following disclaimer.
11   2. Redistributions in binary form must reproduce the above copyright
12      notice, this list of conditions and the following disclaimer in the
13      documentation and/or other materials provided with the distribution.
14   3. Neither the name of the University nor the names of its
15      contributors may be used to endorse or promote products derived
16      from this software without specific prior written permission.
17
18   THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
19   WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
20   MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21   DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
22   FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
25   BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
26   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
27   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31 #ifdef HAVE_CONFIG_H
32 #include <config.h>
33 #endif  /* HAVE_CONFIG_H */
34
35 #ifndef _GNU_SOURCE
36 #define _GNU_SOURCE
37 #endif
38
39 #include <sys/param.h>
40 #include <sys/socket.h>
41 #include <sys/poll.h>
42 #include <netinet/in.h>
43
44 #include <stdio.h>
45 #include <stdlib.h>
46 #include <string.h>
47 #include <memory.h>
48 #include <errno.h>
49 #include <fcntl.h>
50 #include <signal.h>
51 #include <unistd.h>
52 #include <dirent.h>
53
54 #include "gssd.h"
55 #include "err_util.h"
56
57 extern struct pollfd *pollarray;
58 extern int pollsize;
59
60 #define POLL_MILLISECS  500
61
62 static volatile int dir_changed = 1;
63
64 static void dir_notify_handler(int sig, siginfo_t *si, void *data)
65 {
66         dir_changed = 1;
67 }
68
69 static void
70 scan_poll_results(int ret)
71 {
72         int                     i;
73         struct clnt_info        *clp;
74
75         for (clp = clnt_list.tqh_first; clp != NULL; clp = clp->list.tqe_next)
76         {
77                 i = clp->krb5_poll_index;
78                 if (i >= 0 && pollarray[i].revents) {
79                         if (pollarray[i].revents & POLLHUP)
80                                 dir_changed = 1;
81                         if (pollarray[i].revents & POLLIN)
82                                 handle_krb5_upcall(clp);
83                         pollarray[clp->krb5_poll_index].revents = 0;
84                         ret--;
85                         if (!ret)
86                                 break;
87                 }
88                 i = clp->spkm3_poll_index;
89                 if (i >= 0 && pollarray[i].revents) {
90                         if (pollarray[i].revents & POLLHUP)
91                                 dir_changed = 1;
92                         if (pollarray[i].revents & POLLIN)
93                                 handle_spkm3_upcall(clp);
94                         pollarray[clp->spkm3_poll_index].revents = 0;
95                         ret--;
96                         if (!ret)
97                                 break;
98                 }
99         }
100 };
101
102 static int
103 topdirs_add_entry(struct dirent *dent)
104 {
105         struct topdirs_info *tdi;
106
107         tdi = calloc(sizeof(struct topdirs_info), 1);
108         if (tdi == NULL) {
109                 printerr(0, "ERROR: Couldn't allocate struct topdirs_info\n");
110                 return -1;
111         }
112         tdi->dirname = malloc(PATH_MAX);
113         if (tdi->dirname == NULL) {
114                 printerr(0, "ERROR: Couldn't allocate directory name\n");
115                 free(tdi);
116                 return -1;
117         }
118         snprintf(tdi->dirname, PATH_MAX, "%s/%s", pipefs_dir, dent->d_name);
119         tdi->fd = open(tdi->dirname, O_RDONLY);
120         if (tdi->fd != -1) {
121                 fcntl(tdi->fd, F_SETSIG, DNOTIFY_SIGNAL);
122                 fcntl(tdi->fd, F_NOTIFY,
123                       DN_CREATE|DN_DELETE|DN_MODIFY|DN_MULTISHOT);
124         }
125
126         TAILQ_INSERT_HEAD(&topdirs_list, tdi, list);
127         return 0;
128 }
129
130 static void
131 topdirs_free_list(void)
132 {
133         struct topdirs_info *tdi;
134
135         TAILQ_FOREACH(tdi, &topdirs_list, list) {
136                 free(tdi->dirname);
137                 if (tdi->fd != -1)
138                         close(tdi->fd);
139                 TAILQ_REMOVE(&topdirs_list, tdi, list);
140                 free(tdi);
141         }
142 }
143
144 static int
145 topdirs_init_list(void)
146 {
147         DIR             *pipedir;
148         struct dirent   *dent;
149         int             ret;
150
151         TAILQ_INIT(&topdirs_list);
152
153         pipedir = opendir(pipefs_dir);
154         if (pipedir == NULL) {
155                 printerr(0, "ERROR: could not open rpc_pipefs directory '%s': "
156                          "%s\n", pipefs_dir, strerror(errno));
157                 return -1;
158         }
159         for (dent = readdir(pipedir); dent != NULL; dent = readdir(pipedir)) {
160                 if (dent->d_type != DT_DIR ||
161                     strcmp(dent->d_name, ".") == 0  ||
162                     strcmp(dent->d_name, "..") == 0) {
163                         continue;
164                 }
165                 ret = topdirs_add_entry(dent);
166                 if (ret)
167                         goto out_err;
168         }
169         closedir(pipedir);
170         return 0;
171 out_err:
172         topdirs_free_list();
173         return -1;
174 }
175
176 void
177 gssd_run()
178 {
179         int                     ret;
180         struct sigaction        dn_act;
181         sigset_t                set;
182
183         /* Taken from linux/Documentation/dnotify.txt: */
184         dn_act.sa_sigaction = dir_notify_handler;
185         sigemptyset(&dn_act.sa_mask);
186         dn_act.sa_flags = SA_SIGINFO;
187         sigaction(DNOTIFY_SIGNAL, &dn_act, NULL);
188
189         /* just in case the signal is blocked... */
190         sigemptyset(&set);
191         sigaddset(&set, DNOTIFY_SIGNAL);
192         sigprocmask(SIG_UNBLOCK, &set, NULL);
193
194         if (topdirs_init_list() != 0)
195                 return;
196
197         init_client_list();
198
199         printerr(1, "beginning poll\n");
200         while (1) {
201                 while (dir_changed) {
202                         dir_changed = 0;
203                         if (update_client_list()) {
204                                 /* Error msg is already printed */
205                                 exit(1);
206                         }
207                 }
208                 /* race condition here: dir_changed could be set before we
209                  * enter the poll, and we'd never notice if it weren't for the
210                  * timeout. */
211                 ret = poll(pollarray, pollsize, POLL_MILLISECS);
212                 if (ret < 0) {
213                         if (errno != EINTR)
214                                 printerr(0,
215                                          "WARNING: error return from poll\n");
216                 } else if (ret == 0) {
217                         /* timeout */
218                 } else { /* ret > 0 */
219                         scan_poll_results(ret);
220                 }
221         }
222         topdirs_free_list();
223
224         return;
225 }