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