Whamcloud - gitweb
457d99155473aa7bcce3d5891953587e44e0c0a8
[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(char *progname)
180 {
181         fprintf(stderr, "usage: %s [-n] [-f] [-v] [-r] [-m] [-o] [-g]\n",
182                 progname);
183         exit(1);
184 }
185
186 int
187 main(int argc, char *argv[])
188 {
189         int get_creds = 1;
190         int fg = 0;
191         int verbosity = 0;
192         int opt;
193         int must_srv_mds = 0, must_srv_oss = 0, must_srv_mgs = 0;
194         extern char *optarg;
195         char *progname;
196
197         while ((opt = getopt(argc, argv, "fvrnmog:")) != -1) {
198                 switch (opt) {
199                         case 'f':
200                                 fg = 1;
201                                 break;
202                         case 'n':
203                                 get_creds = 0;
204                                 break;
205                         case 'v':
206                                 verbosity++;
207                                 break;
208                         case 'm':
209                                 get_creds = 1;
210                                 must_srv_mds = 1;
211                                 break;
212                         case 'o':
213                                 get_creds = 1;
214                                 must_srv_oss = 1;
215                                 break;
216                         case 'g':
217                                 get_creds = 1;
218                                 must_srv_mgs = 1;
219                                 break;
220                         default:
221                                 usage(argv[0]);
222                                 break;
223                 }
224         }
225
226         if ((progname = strrchr(argv[0], '/')))
227                 progname++;
228         else
229                 progname = argv[0];
230
231         initerr(progname, verbosity, fg);
232
233         if (gssd_check_mechs() != 0) {
234                 printerr(0, "ERROR: Problem with gssapi library\n");
235                 exit(1);
236         }
237
238         if (gssd_get_local_realm()) {
239                 printerr(0, "ERROR: Can't get Local Kerberos realm\n");
240                 exit(1);
241         }
242   
243         if (get_creds &&
244             gssd_prepare_creds(must_srv_mgs, must_srv_mds, must_srv_oss)) {
245                 printerr(0, "unable to obtain root (machine) credentials\n");
246                 printerr(0, "do you have a keytab entry for "
247                             "<lustre_xxs>/<your.host>@<YOUR.REALM> in "
248                             "/etc/krb5.keytab?\n");
249                 exit(1);
250         }
251
252         if (!fg)
253                 mydaemon(0, 0);
254
255         /*
256          * XXX: There is risk of memory leak for missing call
257          *      cleanup_mapping() for SIGKILL and SIGSTOP.
258          */
259         signal(SIGINT, sig_die);
260         signal(SIGTERM, sig_die);
261         signal(SIGHUP, sig_hup);
262
263         if (!fg)
264                 release_parent();
265
266         gssd_init_unique(GSSD_SVC);
267
268         svcgssd_run();
269         cleanup_mapping();
270         printerr(0, "gssd_run returned!\n");
271         abort();
272 }