]> git.decadent.org.uk Git - nfs-utils.git/blob - utils/svcgssd/svcgssd.c
Assorted changes from Steve Dickson
[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                 dup2(tempfd, 0);
117                 dup2(tempfd, 1);
118                 dup2(tempfd, 2);
119                 closeall(3);
120         }
121
122         return;
123 }
124
125 static void
126 release_parent()
127 {
128         int status;
129
130         if (pipefds[1] > 0) {
131                 write(pipefds[1], &status, 1);
132                 close(pipefds[1]);
133                 pipefds[1] = -1;
134         }
135 }
136
137 void
138 sig_die(int signal)
139 {
140         /* destroy krb5 machine creds */
141         printerr(1, "exiting on signal %d\n", signal);
142         exit(1);
143 }
144
145 void
146 sig_hup(int signal)
147 {
148         /* don't exit on SIGHUP */
149         printerr(1, "Received SIGHUP... Ignoring.\n");
150         return;
151 }
152
153 static void
154 usage(char *progname)
155 {
156         fprintf(stderr, "usage: %s [-n] [-f] [-v] [-r]\n",
157                 progname);
158         exit(1);
159 }
160
161 int
162 main(int argc, char *argv[])
163 {
164         int get_creds = 1;
165         int fg = 0;
166         int verbosity = 0;
167         int rpc_verbosity = 0;
168         int opt;
169         extern char *optarg;
170         char *progname;
171
172         while ((opt = getopt(argc, argv, "fvrnp:")) != -1) {
173                 switch (opt) {
174                         case 'f':
175                                 fg = 1;
176                                 break;
177                         case 'n':
178                                 get_creds = 0;
179                                 break;
180                         case 'v':
181                                 verbosity++;
182                                 break;
183                         case 'r':
184                                 rpc_verbosity++;
185                                 break;
186                         default:
187                                 usage(argv[0]);
188                                 break;
189                 }
190         }
191
192         if ((progname = strrchr(argv[0], '/')))
193                 progname++;
194         else
195                 progname = argv[0];
196
197         initerr(progname, verbosity, fg);
198 #ifdef HAVE_AUTHGSS_SET_DEBUG_LEVEL
199         authgss_set_debug_level(rpc_verbosity);
200 #else
201         if (rpc_verbosity > 0)
202                 printerr(0, "Warning: rpcsec_gss library does not "
203                             "support setting debug level\n");
204 #endif
205
206         if (!fg)
207                 mydaemon(0, 0);
208
209         signal(SIGINT, sig_die);
210         signal(SIGTERM, sig_die);
211         signal(SIGHUP, sig_hup);
212
213         if (get_creds && !gssd_acquire_cred(GSSD_SERVICE_NAME)) {
214                 printerr(0, "unable to obtain root (machine) credentials\n");
215                 printerr(0, "do you have a keytab entry for "
216                             "nfs/<your.host>@<YOUR.REALM> in "
217                             "/etc/krb5.keytab?\n");
218                 exit(1);
219         }
220
221         if (!fg)
222                 release_parent();
223
224         gssd_run();
225         printerr(0, "gssd_run returned!\n");
226         abort();
227 }