Whamcloud - gitweb
branch: b_new_cmd
[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  * mydaemon creates a pipe between the partent and child
85  * process. The parent process will wait until the
86  * child dies or writes a '1' on the pipe signaling
87  * that it started successfully.
88  */
89 int pipefds[2] = { -1, -1};
90
91 static void
92 mydaemon(int nochdir, int noclose)
93 {
94         int pid, status, tempfd;
95
96         if (pipe(pipefds) < 0) {
97                 printerr(1, "mydaemon: pipe() failed: errno %d (%s)\n",
98                         errno, strerror(errno));
99                 exit(1);
100         }
101         if ((pid = fork ()) < 0) {
102                 printerr(1, "mydaemon: fork() failed: errno %d (%s)\n",
103                         errno, strerror(errno));
104                 exit(1);
105         }
106
107         if (pid != 0) {
108                 /*
109                  * Parent. Wait for status from child.
110                  */
111                 close(pipefds[1]);
112                 if (read(pipefds[0], &status, 1) != 1)
113                         exit(1);
114                 exit (0);
115         }
116         /* Child.       */
117         close(pipefds[0]);
118         setsid ();
119         if (nochdir == 0) {
120                 if (chdir ("/") == -1) {
121                         printerr(1, "mydaemon: chdir() failed: errno %d (%s)\n",
122                                 errno, strerror(errno));
123                         exit(1);
124                 }
125         }
126
127         while (pipefds[1] <= 2) {
128                 pipefds[1] = dup(pipefds[1]);
129                 if (pipefds[1] < 0) {
130                         printerr(1, "mydaemon: dup() failed: errno %d (%s)\n",
131                                 errno, strerror(errno));
132                         exit(1);
133                 }
134         }
135
136         if (noclose == 0) {
137                 tempfd = open("/dev/null", O_RDWR);
138                 dup2(tempfd, 0);
139                 dup2(tempfd, 1);
140                 dup2(tempfd, 2);
141                 closeall(3);
142         }
143
144         return;
145 }
146
147 static void
148 release_parent()
149 {
150         int status;
151
152         if (pipefds[1] > 0) {
153                 write(pipefds[1], &status, 1);
154                 close(pipefds[1]);
155                 pipefds[1] = -1;
156         }
157 }
158
159 void
160 sig_die(int signal)
161 {
162         /* destroy krb5 machine creds */
163         printerr(1, "exiting on signal %d\n", signal);
164         exit(1);
165 }
166
167 void
168 sig_hup(int signal)
169 {
170         /* don't exit on SIGHUP */
171         printerr(1, "Received SIGHUP... Ignoring.\n");
172         return;
173 }
174
175 static void
176 usage(char *progname)
177 {
178         fprintf(stderr, "usage: %s [-n] [-f] [-v] [-r]\n",
179                 progname);
180         exit(1);
181 }
182
183 int
184 main(int argc, char *argv[])
185 {
186         int get_creds = 1;
187         int fg = 0;
188         int verbosity = 0;
189         int opt;
190         int must_srv_mds = 0, must_srv_oss = 0;
191         extern char *optarg;
192         char *progname;
193
194         while ((opt = getopt(argc, argv, "fvrnp:")) != -1) {
195                 switch (opt) {
196                         case 'f':
197                                 fg = 1;
198                                 break;
199                         case 'n':
200                                 get_creds = 0;
201                                 break;
202                         case 'v':
203                                 verbosity++;
204                                 break;
205                         case 'm':
206                                 get_creds = 1;
207                                 must_srv_mds = 1;
208                                 break;
209                         case 'o':
210                                 get_creds = 1;
211                                 must_srv_oss = 1;
212                                 break;
213                         default:
214                                 usage(argv[0]);
215                                 break;
216                 }
217         }
218
219         if ((progname = strrchr(argv[0], '/')))
220                 progname++;
221         else
222                 progname = argv[0];
223
224         initerr(progname, verbosity, fg);
225
226         if (gssd_check_mechs() != 0) {
227                 printerr(0, "ERROR: Problem with gssapi library\n");
228                 exit(1);
229         }
230
231         if (get_creds && gssd_prepare_creds(must_srv_mds, must_srv_oss)) {
232                 printerr(0, "unable to obtain root (machine) credentials\n");
233                 printerr(0, "do you have a keytab entry for "
234                             "nfs/<your.host>@<YOUR.REALM> in "
235                             "/etc/krb5.keytab?\n");
236                 exit(1);
237         }
238
239         if (!fg)
240                 mydaemon(0, 0);
241
242         signal(SIGINT, sig_die);
243         signal(SIGTERM, sig_die);
244         signal(SIGHUP, sig_hup);
245
246         if (!fg)
247                 release_parent();
248
249         gssd_init_unique(GSSD_SVC);
250
251         svcgssd_run();
252         printerr(0, "gssd_run returned!\n");
253         abort();
254 }