xref: /illumos-gate/usr/src/cmd/gss/gssd/gssd.c (revision 23c352973f956f97f817e65150aad7e1cebeb228)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 /*
30  * Usermode daemon which assists the kernel when handling gssapi calls.
31  * It is gssd that actually implements all gssapi calls.
32  * Some calls, such as gss_sign, are implemented in the kernel on a per
33  * mechanism basis.
34  */
35 
36 #include <stdio.h>
37 #include <rpc/rpc.h>
38 #include <rpc/rpc_com.h>
39 #include <sys/syslog.h>
40 #include <sys/termios.h>
41 #include <unistd.h>
42 #include <sys/utsname.h>
43 #include <sys/systeminfo.h>
44 #include <stdlib.h>
45 #include <stropts.h>
46 #include <fcntl.h>
47 #include <strings.h>
48 #include <signal.h>
49 #include <syslog.h>
50 #include "gssd.h"
51 
52 int gssd_debug = 0;		/* enable debugging printfs */
53 extern void gsscred_set_options(void);
54 
55 void gssprog_1();
56 void gssd_setup(char *);
57 static void usage(void);
58 static void daemonize_start();
59 static void daemonize_ready(unsigned char status);
60 extern int  svc_create_local_service();
61 
62 /* following declarations needed in rpcgen-generated code */
63 int _rpcpmstart = 0;		/* Started by a port monitor ? */
64 int _rpcfdtype;			/* Whether Stream or Datagram ? */
65 int _rpcsvcdirty;		/* Still serving ? */
66 
67 
68 static void
69 /* LINTED */
70 catch_hup(int sig_num)
71 {
72 	sigset_t mask_set;  /* used to set a signal masking set. */
73 	sigset_t old_set;   /* used to store the old mask set.   */
74 
75 	/* re-set the signal handler again to catch_hup, for next time */
76 	(void) signal(SIGHUP, catch_hup);
77 	/* mask any further signals while we're inside the handler. */
78 	(void) sigfillset(&mask_set);
79 	(void) sigprocmask(SIG_SETMASK, &mask_set, &old_set);
80 
81 	gsscred_set_options();
82 
83 	/* let admin know the sighup was caught and conf file re-read */
84 	syslog(LOG_INFO,
85 	    "catch_hup: read gsscred.conf opts");
86 	if (gssd_debug)
87 		(void) fprintf(stderr,
88 			"catch_hup: read gsscred.conf opts");
89 
90 	(void) sigprocmask(SIG_SETMASK, &old_set, NULL);
91 }
92 
93 
94 int
95 main(argc, argv)
96 int argc;
97 char **argv;
98 {
99 	register SVCXPRT *transp;
100 	int maxrecsz = RPC_MAXDATASIZE;
101 	extern int optind;
102 	int c;
103 	char mname[FMNAMESZ + 1];
104 	extern int _getuid();
105 
106 	/* set locale and domain for internationalization */
107 	setlocale(LC_ALL, "");
108 	textdomain(TEXT_DOMAIN);
109 
110 
111 	/*
112 	 * take special note that "_getuid()" is called here. This is necessary
113 	 * since we must fake out the mechanism libraries calls to getuid()
114 	 * with a special routine that is provided as part of gssd. However,
115 	 * the call below MUST call the real getuid() to ensure it is running
116 	 * as root.
117 	 */
118 
119 #ifdef DEBUG
120 	(void) setuid(0);		/* DEBUG: set ruid to root */
121 #endif /* DEBUG */
122 	if (_getuid()) {
123 		(void) fprintf(stderr,
124 				gettext("[%s] must be run as root\n"), argv[0]);
125 #ifdef DEBUG
126 		(void) fprintf(stderr, gettext(" warning only\n"));
127 #else /* DEBUG */
128 		exit(1);
129 #endif /* DEBUG */
130 	}
131 
132 	gssd_setup(argv[0]);
133 
134 	while ((c = getopt(argc, argv, "d")) != -1)
135 		switch (c) {
136 		    case 'd':
137 			/* turn on debugging */
138 			gssd_debug = 1;
139 			break;
140 		    default:
141 			usage();
142 		}
143 
144 	if (optind != argc) {
145 		usage();
146 	}
147 
148 	gsscred_set_options();
149 	(void) signal(SIGHUP, catch_hup);
150 
151 	/*
152 	 * Started by inetd if name of module just below stream
153 	 * head is either a sockmod or timod.
154 	 */
155 	if (!ioctl(0, I_LOOK, mname) &&
156 		((strcmp(mname, "sockmod") == 0) ||
157 			(strcmp(mname, "timod") == 0))) {
158 
159 		char *netid;
160 		struct netconfig *nconf;
161 
162 		openlog("gssd", LOG_PID, LOG_DAEMON);
163 
164 		if ((netid = getenv("NLSPROVIDER")) ==  NULL) {
165 			netid = "ticotsord";
166 		}
167 
168 		if ((nconf = getnetconfigent(netid)) == NULL) {
169 			syslog(LOG_ERR, gettext("cannot get transport info"));
170 			exit(1);
171 		}
172 
173 		if (strcmp(mname, "sockmod") == 0) {
174 			if (ioctl(0, I_POP, 0) || ioctl(0, I_PUSH, "timod")) {
175 				syslog(LOG_ERR,
176 					gettext("could not get the "
177 						"right module"));
178 				exit(1);
179 			}
180 		}
181 		if (!rpc_control(RPC_SVC_CONNMAXREC_SET, &maxrecsz)) {
182 			syslog(LOG_ERR,
183 				gettext("unable to set RPC max record size"));
184 			exit(1);
185 		}
186 		/* XXX - is nconf even needed here? */
187 		if ((transp = svc_tli_create(0, nconf, NULL, 0, 0)) == NULL) {
188 			syslog(LOG_ERR, gettext("cannot create server handle"));
189 			exit(1);
190 		}
191 
192 		/*
193 		 * We use a NULL nconf because GSSPROG has already been
194 		 * registered with rpcbind.
195 		 */
196 		if (!svc_reg(transp, GSSPROG, GSSVERS, gssprog_1, NULL)) {
197 			syslog(LOG_ERR,
198 				gettext("unable to register "
199 					"(GSSPROG, GSSVERS)"));
200 			exit(1);
201 		}
202 
203 		if (nconf)
204 			freenetconfigent(nconf);
205 	} else {
206 		if (!gssd_debug)
207 			daemonize_start();
208 
209 		openlog("gssd", LOG_PID, LOG_DAEMON);
210 
211 		if (svc_create_local_service(gssprog_1, GSSPROG, GSSVERS,
212 		    "netpath", "gssd") == 0) {
213 			syslog(LOG_ERR, gettext("unable to create service"));
214 			exit(1);
215 		}
216 
217 		/* service created, now the daemon parent can exit */
218 		daemonize_ready(0);
219 	}
220 
221 
222 	if (gssd_debug) {
223 		fprintf(stderr,
224 		    gettext("gssd start: \n"));
225 	}
226 	svc_run();
227 	abort();
228 	/*NOTREACHED*/
229 #ifdef	lint
230 	return (1);
231 #endif
232 }
233 
234 static void
235 usage(void)
236 {
237 	(void) fprintf(stderr, gettext("usage: gssd [-dg]\n"));
238 	exit(1);
239 }
240 
241 
242 /*
243  * Fork, detach from tty, etc...
244  */
245 static int write_pipe_fd = -1;
246 static
247 void
248 daemonize_start()
249 {
250 	int pipe_fds[2];
251 	unsigned char status = 1;
252 
253 	closefrom(0);
254 
255 	/* Open stdin/out/err, chdir, get a pipe */
256 	if (open("/dev/null", O_RDONLY) < 0 ||
257 	    open("/dev/null", O_WRONLY) < 0 || dup(1) < 0 ||
258 	    chdir("/") < 0 || pipe(pipe_fds) < 0)
259 		exit(1);
260 
261 	/* For daemonize_ready() */
262 	write_pipe_fd = pipe_fds[1];
263 
264 	switch (fork()) {
265 	case -1:
266 		exit(1);
267 		/* NOTREACHED */
268 	case 0:
269 		break;
270 	default:
271 		/* Wait for child to be ready befor exiting */
272 		(void) close(pipe_fds[1]);
273 		(void) signal(SIGPIPE, SIG_DFL);
274 		(void) read(pipe_fds[0], &status, sizeof (status));
275 		exit(status);
276 	}
277 
278 	(void) close(pipe_fds[0]);
279 	(void) setsid();
280 }
281 
282 static
283 void
284 daemonize_ready(unsigned char status)
285 {
286 	if (write_pipe_fd == -1)
287 		return;
288 
289 	(void) write(write_pipe_fd, &status, sizeof (status));
290 	(void) close(write_pipe_fd);
291 	write_pipe_fd = -1;
292 }
293 
294 /*ARGSUSED*/
295 int
296 gssprog_1_freeresult(SVCXPRT *transport, xdrproc_t xdr_res, caddr_t res)
297 {
298 	xdr_free(xdr_res, res);
299 	return (1);
300 }
301