Whamcloud - gitweb
85d1bd73c06422d91bdf9b2c65fa8cbf37945039
[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 int null_enabled;
63 int krb_enabled;
64 int sk_enabled;
65
66 void
67 closeall(int min)
68 {
69         DIR *dir = opendir("/proc/self/fd");
70         if (dir != NULL) {
71                 int dfd = dirfd(dir);
72                 struct dirent *d;
73
74                 while ((d = readdir(dir)) != NULL) {
75                         char *endp;
76                         long n = strtol(d->d_name, &endp, 10);
77                         if (*endp != '\0' && n >= min && n != dfd)
78                                 (void) close(n);
79                 }
80                 closedir(dir);
81         } else {
82                 int fd = sysconf(_SC_OPEN_MAX);
83                 while (--fd >= min)
84                         (void) close(fd);
85         }
86 }
87
88 /*
89  * mydaemon creates a pipe between the partent and child
90  * process. The parent process will wait until the
91  * child dies or writes a '1' on the pipe signaling
92  * that it started successfully.
93  */
94 int pipefds[2] = { -1, -1};
95
96 static void
97 mydaemon(int nochdir, int noclose)
98 {
99         int pid, status, tempfd;
100
101         if (pipe(pipefds) < 0) {
102                 printerr(1, "mydaemon: pipe() failed: errno %d (%s)\n",
103                         errno, strerror(errno));
104                 exit(1);
105         }
106         if ((pid = fork ()) < 0) {
107                 printerr(1, "mydaemon: fork() failed: errno %d (%s)\n",
108                         errno, strerror(errno));
109                 exit(1);
110         }
111
112         if (pid != 0) {
113                 /*
114                  * Parent. Wait for status from child.
115                  */
116                 close(pipefds[1]);
117                 if (read(pipefds[0], &status, 1) != 1)
118                         exit(1);
119                 exit (0);
120         }
121         /* Child.       */
122         close(pipefds[0]);
123         setsid ();
124         if (nochdir == 0) {
125                 if (chdir ("/") == -1) {
126                         printerr(1, "mydaemon: chdir() failed: errno %d (%s)\n",
127                                 errno, strerror(errno));
128                         exit(1);
129                 }
130         }
131
132         while (pipefds[1] <= 2) {
133                 pipefds[1] = dup(pipefds[1]);
134                 if (pipefds[1] < 0) {
135                         printerr(1, "mydaemon: dup() failed: errno %d (%s)\n",
136                                 errno, strerror(errno));
137                         exit(1);
138                 }
139         }
140
141         if (noclose == 0) {
142                 tempfd = open("/dev/null", O_RDWR);
143                 dup2(tempfd, 0);
144                 dup2(tempfd, 1);
145                 dup2(tempfd, 2);
146                 closeall(3);
147         }
148
149         return;
150 }
151
152 static void
153 release_parent()
154 {
155         int status;
156         ssize_t sret __attribute__ ((unused));
157
158         if (pipefds[1] > 0) {
159                 sret = write(pipefds[1], &status, 1);
160                 close(pipefds[1]);
161                 pipefds[1] = -1;
162         }
163 }
164
165 void
166 sig_die(int signal)
167 {
168         /* destroy krb5 machine creds */
169         cleanup_mapping();
170         printerr(1, "exiting on signal %d\n", signal);
171         exit(1);
172 }
173
174 void
175 sig_hup(int signal)
176 {
177         /* don't exit on SIGHUP */
178         printerr(1, "Received SIGHUP... Ignoring.\n");
179         return;
180 }
181
182 static void
183 usage(FILE *fp, char *progname)
184 {
185         fprintf(fp, "usage: %s [ -fnvmogk ]\n",
186                 progname);
187         fprintf(stderr, "-f      - Run in foreground\n");
188         fprintf(stderr, "-n      - Don't establish kerberos credentials\n");
189         fprintf(stderr, "-v      - Verbosity\n");
190         fprintf(stderr, "-m      - Service MDS\n");
191         fprintf(stderr, "-o      - Service OSS\n");
192         fprintf(stderr, "-g      - Service MGS\n");
193         fprintf(stderr, "-k      - Enable kerberos support\n");
194 #ifdef HAVE_OPENSSL_SSK
195         fprintf(stderr, "-s      - Enable shared key support\n");
196 #endif
197         fprintf(stderr, "-z      - Enable gssnull support\n");
198
199         exit(1);
200 }
201
202 int
203 main(int argc, char *argv[])
204 {
205         int get_creds = 1;
206         int fg = 0;
207         int verbosity = 0;
208         int opt;
209         int must_srv_mds = 0, must_srv_oss = 0, must_srv_mgs = 0;
210         char *progname;
211
212         while ((opt = getopt(argc, argv, "fnvmogksz")) != -1) {
213                 switch (opt) {
214                 case 'f':
215                         fg = 1;
216                         break;
217                 case 'n':
218                         get_creds = 0;
219                         break;
220                 case 'v':
221                         verbosity++;
222                         break;
223                 case 'm':
224                         get_creds = 1;
225                         must_srv_mds = 1;
226                         break;
227                 case 'o':
228                         get_creds = 1;
229                         must_srv_oss = 1;
230                         break;
231                 case 'g':
232                         get_creds = 1;
233                         must_srv_mgs = 1;
234                         break;
235                 case 'k':
236                         krb_enabled = 1;
237                         break;
238                 case 'h':
239                         usage(stdout, argv[0]);
240                         break;
241                 case 's':
242 #ifdef HAVE_OPENSSL_SSK
243                         sk_enabled = 1;
244 #else
245                         printerr(0, "ERROR: Request for sk but service "
246                                  "support not enabled\n");
247 #endif
248                         break;
249                 case 'z':
250                         null_enabled = 1;
251                         break;
252                 default:
253                         usage(stderr, argv[0]);
254                         break;
255                 }
256         }
257
258         if ((progname = strrchr(argv[0], '/')))
259                 progname++;
260         else
261                 progname = argv[0];
262
263         initerr(progname, verbosity, fg);
264
265         /* For kerberos use gss mechanisms but ignore for sk and null */
266         if (krb_enabled) {
267                 if (gssd_check_mechs()) {
268                         printerr(0, "ERROR: problem with gssapi library\n");
269                         exit(1);
270                 }
271                 if (gssd_get_local_realm()) {
272                         printerr(0, "ERROR: Can't get Local Kerberos realm\n");
273                         exit(1);
274                 }
275
276                 if (get_creds &&
277                     gssd_prepare_creds(must_srv_mgs, must_srv_mds,
278                                        must_srv_oss)) {
279                         printerr(0, "unable to obtain root (machine) "
280                                  "credentials\n");
281                         printerr(0, "do you have a keytab entry for "
282                                  "<lustre_xxs>/<your.host>@<YOUR.REALM> in "
283                                  "/etc/krb5.keytab?\n");
284                         exit(1);
285                 }
286         }
287
288         if (!fg)
289                 mydaemon(0, 0);
290
291         /*
292          * XXX: There is risk of memory leak for missing call
293          *      cleanup_mapping() for SIGKILL and SIGSTOP.
294          */
295         signal(SIGINT, sig_die);
296         signal(SIGTERM, sig_die);
297         signal(SIGHUP, sig_hup);
298
299         if (!fg)
300                 release_parent();
301
302         gssd_init_unique(GSSD_SVC);
303
304         svcgssd_run();
305         cleanup_mapping();
306         printerr(0, "gssd_run returned!\n");
307         abort();
308 }