3b5a981e3f2f3d780fec724716d95b14de6b17a8
[nfs-utils.git] / utils / svcgssd / 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 <rpc/rpc.h>
47 #include <fcntl.h>
48 #include <errno.h>
49
50
51 #include <unistd.h>
52 #include <err.h>
53 #include <stdio.h>
54 #include <stdlib.h>
55 #include <string.h>
56 #include <signal.h>
57 #include "svcgssd.h"
58 #include "gss_util.h"
59 #include "err_util.h"
60
61 /*
62  * mydaemon creates a pipe between the partent and child
63  * process. The parent process will wait until the
64  * child dies or writes a '1' on the pipe signaling
65  * that it started successfully.
66  */
67 int pipefds[2] = { -1, -1};
68
69 static void
70 mydaemon(int nochdir, int noclose)
71 {
72         int pid, status, tempfd, fdmax, filedes;
73
74         if (pipe(pipefds) < 0) {
75                 printerr(1, "mydaemon: pipe() failed: errno %d (%s)\n",
76                         errno, strerror(errno));
77                 exit(1);
78         }
79         if ((pid = fork ()) < 0) {
80                 printerr(1, "mydaemon: fork() failed: errno %d (%s)\n",
81                         errno, strerror(errno));
82                 exit(1);
83         }
84
85         if (pid != 0) {
86                 /*
87                  * Parent. Wait for status from child.
88                  */
89                 close(pipefds[1]);
90                 if (read(pipefds[0], &status, 1) != 1)
91                         exit(1);
92                 exit (0);
93         }
94         /* Child.       */
95         close(pipefds[0]);
96         setsid ();
97         if (nochdir == 0) {
98                 if (chdir ("/") == -1) {
99                         printerr(1, "mydaemon: chdir() failed: errno %d (%s)\n",
100                                 errno, strerror(errno));
101                         exit(1);
102                 }
103         }
104
105         while (pipefds[1] <= 2) {
106                 pipefds[1] = dup(pipefds[1]);
107                 if (pipefds[1] < 0) {
108                         printerr(1, "mydaemon: dup() failed: errno %d (%s)\n",
109                                 errno, strerror(errno));
110                         exit(1);
111                 }
112         }
113
114         if (noclose == 0) {
115                 tempfd = open("/dev/null", O_RDWR);
116                 close(0); dup2(tempfd, 0);
117                 close(1); dup2(tempfd, 1);
118                 close(2); dup2(tempfd, 2);
119                 fdmax = sysconf (_SC_OPEN_MAX);
120                 for (filedes = 3; filedes < fdmax; filedes++)
121                         if (filedes != pipefds[1])
122                                 close (filedes);
123         }
124
125         return;
126 }
127
128 static void
129 release_parent()
130 {
131         int status;
132
133         if (pipefds[1] > 0) {
134                 write(pipefds[1], &status, 1);
135                 close(pipefds[1]);
136                 pipefds[1] = -1;
137         }
138 }
139
140 void
141 sig_die(int signal)
142 {
143         /* destroy krb5 machine creds */
144         printerr(1, "exiting on signal %d\n", signal);
145         exit(1);
146 }
147
148 void
149 sig_hup(int signal)
150 {
151         /* don't exit on SIGHUP */
152         printerr(1, "Received SIGHUP... Ignoring.\n");
153         return;
154 }
155
156 static void
157 usage(char *progname)
158 {
159         fprintf(stderr, "usage: %s [-n] [-f] [-v] [-r]\n",
160                 progname);
161         exit(1);
162 }
163
164 int
165 main(int argc, char *argv[])
166 {
167         int get_creds = 1;
168         int fg = 0;
169         int verbosity = 0;
170         int rpc_verbosity = 0;
171         int opt;
172         extern char *optarg;
173         char *progname;
174
175         while ((opt = getopt(argc, argv, "fvrnp:")) != -1) {
176                 switch (opt) {
177                         case 'f':
178                                 fg = 1;
179                                 break;
180                         case 'n':
181                                 get_creds = 0;
182                                 break;
183                         case 'v':
184                                 verbosity++;
185                                 break;
186                         case 'r':
187                                 rpc_verbosity++;
188                                 break;
189                         default:
190                                 usage(argv[0]);
191                                 break;
192                 }
193         }
194
195         if ((progname = strrchr(argv[0], '/')))
196                 progname++;
197         else
198                 progname = argv[0];
199
200         initerr(progname, verbosity, fg);
201 #ifdef HAVE_AUTHGSS_SET_DEBUG_LEVEL
202         authgss_set_debug_level(rpc_verbosity);
203 #else
204         if (rpc_verbosity > 0)
205                 printerr(0, "Warning: rpcsec_gss library does not "
206                             "support setting debug level\n");
207 #endif
208
209         if (!fg)
210                 mydaemon(0, 0);
211
212         signal(SIGINT, sig_die);
213         signal(SIGTERM, sig_die);
214         signal(SIGHUP, sig_hup);
215
216         if (get_creds && !gssd_acquire_cred(GSSD_SERVICE_NAME)) {
217                 printerr(0, "unable to obtain root (machine) credentials\n");
218                 printerr(0, "do you have a keytab entry for "
219                             "nfs/<your.host>@<YOUR.REALM> in "
220                             "/etc/krb5.keytab?\n");
221                 exit(1);
222         }
223
224         if (!fg)
225                 release_parent();
226
227         gssd_run();
228         printerr(0, "gssd_run returned!\n");
229         abort();
230 }