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