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