Whamcloud - gitweb
LU-3289 gss: Cleanup gss code
[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         fprintf(stderr, "-s      - Enable shared key support\n");
195         fprintf(stderr, "-z      - Enable gssnull support\n");
196
197         exit(1);
198 }
199
200 int
201 main(int argc, char *argv[])
202 {
203         int get_creds = 1;
204         int fg = 0;
205         int verbosity = 0;
206         int opt;
207         int must_srv_mds = 0, must_srv_oss = 0, must_srv_mgs = 0;
208         char *progname;
209
210         while ((opt = getopt(argc, argv, "fnvmogksz")) != -1) {
211                 switch (opt) {
212                 case 'f':
213                         fg = 1;
214                         break;
215                 case 'n':
216                         get_creds = 0;
217                         break;
218                 case 'v':
219                         verbosity++;
220                         break;
221                 case 'm':
222                         get_creds = 1;
223                         must_srv_mds = 1;
224                         break;
225                 case 'o':
226                         get_creds = 1;
227                         must_srv_oss = 1;
228                         break;
229                 case 'g':
230                         get_creds = 1;
231                         must_srv_mgs = 1;
232                         break;
233                 case 'k':
234                         krb_enabled = 1;
235                         break;
236                 case 'h':
237                         usage(stdout, argv[0]);
238                         break;
239                 case 's':
240                         sk_enabled = 1;
241                         break;
242                 case 'z':
243                         null_enabled = 1;
244                         break;
245                 default:
246                         usage(stderr, argv[0]);
247                         break;
248                 }
249         }
250
251         if ((progname = strrchr(argv[0], '/')))
252                 progname++;
253         else
254                 progname = argv[0];
255
256         initerr(progname, verbosity, fg);
257
258         /* For kerberos use gss mechanisms but ignore for sk and null */
259         if (krb_enabled) {
260                 if (gssd_check_mechs()) {
261                         printerr(0, "ERROR: problem with gssapi library\n");
262                         exit(1);
263                 }
264                 if (gssd_get_local_realm()) {
265                         printerr(0, "ERROR: Can't get Local Kerberos realm\n");
266                         exit(1);
267                 }
268
269                 if (get_creds &&
270                     gssd_prepare_creds(must_srv_mgs, must_srv_mds,
271                                        must_srv_oss)) {
272                         printerr(0, "unable to obtain root (machine) "
273                                  "credentials\n");
274                         printerr(0, "do you have a keytab entry for "
275                                  "<lustre_xxs>/<your.host>@<YOUR.REALM> in "
276                                  "/etc/krb5.keytab?\n");
277                         exit(1);
278                 }
279         }
280
281         if (!fg)
282                 mydaemon(0, 0);
283
284         /*
285          * XXX: There is risk of memory leak for missing call
286          *      cleanup_mapping() for SIGKILL and SIGSTOP.
287          */
288         signal(SIGINT, sig_die);
289         signal(SIGTERM, sig_die);
290         signal(SIGHUP, sig_hup);
291
292         if (!fg)
293                 release_parent();
294
295         gssd_init_unique(GSSD_SVC);
296
297         svcgssd_run();
298         cleanup_mapping();
299         printerr(0, "gssd_run returned!\n");
300         abort();
301 }