Whamcloud - gitweb
- make HEAD from b_post_cmd3
[fs/lustre-release.git] / lustre / utils / gss / svcgssd.c
1 /*
2   gssd.c
3
4   Copyright (c) 2000 The Regents of the University of Michigan.
5   All rights reserved.
6
7   Copyright (c) 2000 Dug Song <dugsong@UMICH.EDU>.
8   Copyright (c) 2002 Andy Adamson <andros@UMICH.EDU>.
9   Copyright (c) 2002 Marius Aamodt Eriksen <marius@UMICH.EDU>.
10   Copyright (c) 2002 J. Bruce Fields <bfields@UMICH.EDU>.
11   All rights reserved, all wrongs reversed.
12
13   Redistribution and use in source and binary forms, with or without
14   modification, are permitted provided that the following conditions
15   are met:
16
17   1. Redistributions of source code must retain the above copyright
18      notice, this list of conditions and the following disclaimer.
19   2. Redistributions in binary form must reproduce the above copyright
20      notice, this list of conditions and the following disclaimer in the
21      documentation and/or other materials provided with the distribution.
22   3. Neither the name of the University nor the names of its
23      contributors may be used to endorse or promote products derived
24      from this software without specific prior written permission.
25
26   THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
27   WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
28   MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
29   DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30   FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
33   BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
34   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
35   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
36   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37
38 */
39
40 #include "config.h"
41
42 #include <sys/param.h>
43 #include <sys/types.h>
44 #include <sys/stat.h>
45 #include <sys/socket.h>
46 #include <fcntl.h>
47 #include <errno.h>
48
49
50 #include <unistd.h>
51 #include <err.h>
52 #include <stdio.h>
53 #include <stdlib.h>
54 #include <string.h>
55 #include <signal.h>
56 #include <dirent.h>
57 #include "svcgssd.h"
58 #include "gss_util.h"
59 #include "err_util.h"
60 #include "lsupport.h"
61
62 void
63 closeall(int min)
64 {
65         DIR *dir = opendir("/proc/self/fd");
66         if (dir != NULL) {
67                 int dfd = dirfd(dir);
68                 struct dirent *d;
69
70                 while ((d = readdir(dir)) != NULL) {
71                         char *endp;
72                         long n = strtol(d->d_name, &endp, 10);
73                         if (*endp != '\0' && n >= min && n != dfd)
74                                 (void) close(n);
75                 }
76                 closedir(dir);
77         } else {
78                 int fd = sysconf(_SC_OPEN_MAX);
79                 while (--fd >= min)
80                         (void) close(fd);
81         }
82 }
83 /*
84  * mydaemon creates a pipe between the partent and child
85  * process. The parent process will wait until the
86  * child dies or writes a '1' on the pipe signaling
87  * that it started successfully.
88  */
89 int pipefds[2] = { -1, -1};
90
91 static void
92 mydaemon(int nochdir, int noclose)
93 {
94         int pid, status, tempfd;
95
96         if (pipe(pipefds) < 0) {
97                 printerr(1, "mydaemon: pipe() failed: errno %d (%s)\n",
98                         errno, strerror(errno));
99                 exit(1);
100         }
101         if ((pid = fork ()) < 0) {
102                 printerr(1, "mydaemon: fork() failed: errno %d (%s)\n",
103                         errno, strerror(errno));
104                 exit(1);
105         }
106
107         if (pid != 0) {
108                 /*
109                  * Parent. Wait for status from child.
110                  */
111                 close(pipefds[1]);
112                 if (read(pipefds[0], &status, 1) != 1)
113                         exit(1);
114                 exit (0);
115         }
116         /* Child.       */
117         close(pipefds[0]);
118         setsid ();
119         if (nochdir == 0) {
120                 if (chdir ("/") == -1) {
121                         printerr(1, "mydaemon: chdir() failed: errno %d (%s)\n",
122                                 errno, strerror(errno));
123                         exit(1);
124                 }
125         }
126
127         while (pipefds[1] <= 2) {
128                 pipefds[1] = dup(pipefds[1]);
129                 if (pipefds[1] < 0) {
130                         printerr(1, "mydaemon: dup() failed: errno %d (%s)\n",
131                                 errno, strerror(errno));
132                         exit(1);
133                 }
134         }
135
136         if (noclose == 0) {
137                 tempfd = open("/dev/null", O_RDWR);
138                 dup2(tempfd, 0);
139                 dup2(tempfd, 1);
140                 dup2(tempfd, 2);
141                 closeall(3);
142         }
143
144         return;
145 }
146
147 static void
148 release_parent()
149 {
150         int status;
151
152         if (pipefds[1] > 0) {
153                 write(pipefds[1], &status, 1);
154                 close(pipefds[1]);
155                 pipefds[1] = -1;
156         }
157 }
158
159 void
160 sig_die(int signal)
161 {
162         /* destroy krb5 machine creds */
163         cleanup_mapping();
164         printerr(1, "exiting on signal %d\n", signal);
165         exit(1);
166 }
167
168 void
169 sig_hup(int signal)
170 {
171         /* don't exit on SIGHUP */
172         printerr(1, "Received SIGHUP... Ignoring.\n");
173         return;
174 }
175
176 static void
177 usage(char *progname)
178 {
179         fprintf(stderr, "usage: %s [-n] [-f] [-v] [-r]\n",
180                 progname);
181         exit(1);
182 }
183
184 int
185 main(int argc, char *argv[])
186 {
187         int get_creds = 1;
188         int fg = 0;
189         int verbosity = 0;
190         int opt;
191         int must_srv_mds = 0, must_srv_oss = 0;
192         extern char *optarg;
193         char *progname;
194
195         while ((opt = getopt(argc, argv, "fvrnp:")) != -1) {
196                 switch (opt) {
197                         case 'f':
198                                 fg = 1;
199                                 break;
200                         case 'n':
201                                 get_creds = 0;
202                                 break;
203                         case 'v':
204                                 verbosity++;
205                                 break;
206                         case 'm':
207                                 get_creds = 1;
208                                 must_srv_mds = 1;
209                                 break;
210                         case 'o':
211                                 get_creds = 1;
212                                 must_srv_oss = 1;
213                                 break;
214                         default:
215                                 usage(argv[0]);
216                                 break;
217                 }
218         }
219
220         if ((progname = strrchr(argv[0], '/')))
221                 progname++;
222         else
223                 progname = argv[0];
224
225         initerr(progname, verbosity, fg);
226
227         if (gssd_check_mechs() != 0) {
228                 printerr(0, "ERROR: Problem with gssapi library\n");
229                 exit(1);
230         }
231
232         if (gssd_get_local_realm()) {
233                 printerr(0, "ERROR: Can't get Local Kerberos realm\n");
234                 exit(1);
235         }
236
237         if (get_creds && gssd_prepare_creds(must_srv_mds, must_srv_oss)) {
238                 printerr(0, "unable to obtain root (machine) credentials\n");
239                 printerr(0, "do you have a keytab entry for "
240                             "nfs/<your.host>@<YOUR.REALM> in "
241                             "/etc/krb5.keytab?\n");
242                 exit(1);
243         }
244
245         if (!fg)
246                 mydaemon(0, 0);
247
248         /*
249          * XXX: There is risk of memory leak for missing call
250          *      cleanup_mapping() for SIGKILL and SIGSTOP.
251          */
252         signal(SIGINT, sig_die);
253         signal(SIGTERM, sig_die);
254         signal(SIGHUP, sig_hup);
255
256         if (!fg)
257                 release_parent();
258
259         gssd_init_unique(GSSD_SVC);
260
261         svcgssd_run();
262         cleanup_mapping();
263         printerr(0, "gssd_run returned!\n");
264         abort();
265 }