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