xref: /freebsd/usr.sbin/gssd/gssd.c (revision 765782e799165d2a549d5a7a68f75e21baa0984b)
1a9148abdSDoug Rabson /*-
2a9148abdSDoug Rabson  * Copyright (c) 2008 Isilon Inc http://www.isilon.com/
3a9148abdSDoug Rabson  * Authors: Doug Rabson <dfr@rabson.org>
4a9148abdSDoug Rabson  * Developed with Red Inc: Alfred Perlstein <alfred@freebsd.org>
5a9148abdSDoug Rabson  *
6a9148abdSDoug Rabson  * Redistribution and use in source and binary forms, with or without
7a9148abdSDoug Rabson  * modification, are permitted provided that the following conditions
8a9148abdSDoug Rabson  * are met:
9a9148abdSDoug Rabson  * 1. Redistributions of source code must retain the above copyright
10a9148abdSDoug Rabson  *    notice, this list of conditions and the following disclaimer.
11a9148abdSDoug Rabson  * 2. Redistributions in binary form must reproduce the above copyright
12a9148abdSDoug Rabson  *    notice, this list of conditions and the following disclaimer in the
13a9148abdSDoug Rabson  *    documentation and/or other materials provided with the distribution.
14a9148abdSDoug Rabson  *
15a9148abdSDoug Rabson  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16a9148abdSDoug Rabson  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17a9148abdSDoug Rabson  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18a9148abdSDoug Rabson  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19a9148abdSDoug Rabson  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20a9148abdSDoug Rabson  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21a9148abdSDoug Rabson  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22a9148abdSDoug Rabson  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23a9148abdSDoug Rabson  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24a9148abdSDoug Rabson  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25a9148abdSDoug Rabson  * SUCH DAMAGE.
26a9148abdSDoug Rabson  */
27a9148abdSDoug Rabson 
28a9148abdSDoug Rabson #include <sys/cdefs.h>
29a9148abdSDoug Rabson __FBSDID("$FreeBSD$");
30a9148abdSDoug Rabson 
31a9148abdSDoug Rabson #include <sys/param.h>
32a9148abdSDoug Rabson #include <sys/stat.h>
33a9148abdSDoug Rabson #include <sys/linker.h>
34a9148abdSDoug Rabson #include <sys/module.h>
35a9148abdSDoug Rabson #include <sys/queue.h>
36*765782e7SRick Macklem #include <sys/syslog.h>
37a9148abdSDoug Rabson #include <ctype.h>
38a9148abdSDoug Rabson #include <err.h>
39a9148abdSDoug Rabson #include <pwd.h>
40a9148abdSDoug Rabson #include <stdio.h>
41a9148abdSDoug Rabson #include <stdlib.h>
42a9148abdSDoug Rabson #include <string.h>
43a9148abdSDoug Rabson #include <unistd.h>
44a9148abdSDoug Rabson #include <gssapi/gssapi.h>
45a9148abdSDoug Rabson #include <rpc/rpc.h>
46a9148abdSDoug Rabson #include <rpc/rpc_com.h>
47a9148abdSDoug Rabson 
48a9148abdSDoug Rabson #include "gssd.h"
49a9148abdSDoug Rabson 
50a9148abdSDoug Rabson #ifndef _PATH_GSS_MECH
51a9148abdSDoug Rabson #define _PATH_GSS_MECH	"/etc/gss/mech"
52a9148abdSDoug Rabson #endif
53a9148abdSDoug Rabson #ifndef _PATH_GSSDSOCK
54a9148abdSDoug Rabson #define _PATH_GSSDSOCK	"/var/run/gssd.sock"
55a9148abdSDoug Rabson #endif
56a9148abdSDoug Rabson 
57a9148abdSDoug Rabson struct gss_resource {
58a9148abdSDoug Rabson 	LIST_ENTRY(gss_resource) gr_link;
59a9148abdSDoug Rabson 	uint64_t	gr_id;	/* indentifier exported to kernel */
60a9148abdSDoug Rabson 	void*		gr_res;	/* GSS-API resource pointer */
61a9148abdSDoug Rabson };
62a9148abdSDoug Rabson LIST_HEAD(gss_resource_list, gss_resource) gss_resources;
63a9148abdSDoug Rabson int gss_resource_count;
64a9148abdSDoug Rabson uint32_t gss_next_id;
65a9148abdSDoug Rabson uint32_t gss_start_time;
66a9148abdSDoug Rabson int debug_level;
67a9148abdSDoug Rabson 
68a9148abdSDoug Rabson static void gssd_load_mech(void);
69a9148abdSDoug Rabson 
70a9148abdSDoug Rabson extern void gssd_1(struct svc_req *rqstp, SVCXPRT *transp);
71a9148abdSDoug Rabson extern int gssd_syscall(char *path);
72a9148abdSDoug Rabson 
73a9148abdSDoug Rabson int
74a9148abdSDoug Rabson main(int argc, char **argv)
75a9148abdSDoug Rabson {
76a9148abdSDoug Rabson 	/*
77a9148abdSDoug Rabson 	 * We provide an RPC service on a local-domain socket. The
78a9148abdSDoug Rabson 	 * kernel's GSS-API code will pass what it can't handle
79a9148abdSDoug Rabson 	 * directly to us.
80a9148abdSDoug Rabson 	 */
81a9148abdSDoug Rabson 	struct sockaddr_un sun;
82a9148abdSDoug Rabson 	int fd, oldmask, ch, debug;
83a9148abdSDoug Rabson 	SVCXPRT *xprt;
84a9148abdSDoug Rabson 
85a9148abdSDoug Rabson 	debug = 0;
86a9148abdSDoug Rabson 	while ((ch = getopt(argc, argv, "d")) != -1) {
87a9148abdSDoug Rabson 		switch (ch) {
88a9148abdSDoug Rabson 		case 'd':
89a9148abdSDoug Rabson 			debug_level++;
90a9148abdSDoug Rabson 			break;
91a9148abdSDoug Rabson 		default:
92a9148abdSDoug Rabson 			fprintf(stderr, "usage: %s [-d]\n", argv[0]);
93a9148abdSDoug Rabson 			exit(1);
94a9148abdSDoug Rabson 			break;
95a9148abdSDoug Rabson 		}
96a9148abdSDoug Rabson 	}
97a9148abdSDoug Rabson 
98a9148abdSDoug Rabson 	gssd_load_mech();
99a9148abdSDoug Rabson 
100a9148abdSDoug Rabson 	if (!debug_level)
101a9148abdSDoug Rabson 		daemon(0, 0);
102a9148abdSDoug Rabson 
103a9148abdSDoug Rabson 	memset(&sun, 0, sizeof sun);
104a9148abdSDoug Rabson 	sun.sun_family = AF_LOCAL;
105a9148abdSDoug Rabson 	unlink(_PATH_GSSDSOCK);
106a9148abdSDoug Rabson 	strcpy(sun.sun_path, _PATH_GSSDSOCK);
107a9148abdSDoug Rabson 	sun.sun_len = SUN_LEN(&sun);
108a9148abdSDoug Rabson 	fd = socket(AF_LOCAL, SOCK_STREAM, 0);
109a9148abdSDoug Rabson 	if (!fd) {
110*765782e7SRick Macklem 		if (debug_level == 0) {
111*765782e7SRick Macklem 			syslog(LOG_ERR, "Can't create local gssd socket");
112*765782e7SRick Macklem 			exit(1);
113*765782e7SRick Macklem 		}
114a9148abdSDoug Rabson 		err(1, "Can't create local gssd socket");
115a9148abdSDoug Rabson 	}
116a9148abdSDoug Rabson 	oldmask = umask(S_IXUSR|S_IRWXG|S_IRWXO);
117a9148abdSDoug Rabson 	if (bind(fd, (struct sockaddr *) &sun, sun.sun_len) < 0) {
118*765782e7SRick Macklem 		if (debug_level == 0) {
119*765782e7SRick Macklem 			syslog(LOG_ERR, "Can't bind local gssd socket");
120*765782e7SRick Macklem 			exit(1);
121*765782e7SRick Macklem 		}
122a9148abdSDoug Rabson 		err(1, "Can't bind local gssd socket");
123a9148abdSDoug Rabson 	}
124a9148abdSDoug Rabson 	umask(oldmask);
125a9148abdSDoug Rabson 	if (listen(fd, SOMAXCONN) < 0) {
126*765782e7SRick Macklem 		if (debug_level == 0) {
127*765782e7SRick Macklem 			syslog(LOG_ERR, "Can't listen on local gssd socket");
128*765782e7SRick Macklem 			exit(1);
129*765782e7SRick Macklem 		}
130a9148abdSDoug Rabson 		err(1, "Can't listen on local gssd socket");
131a9148abdSDoug Rabson 	}
132a9148abdSDoug Rabson 	xprt = svc_vc_create(fd, RPC_MAXDATASIZE, RPC_MAXDATASIZE);
133a9148abdSDoug Rabson 	if (!xprt) {
134*765782e7SRick Macklem 		if (debug_level == 0) {
135*765782e7SRick Macklem 			syslog(LOG_ERR,
136*765782e7SRick Macklem 			    "Can't create transport for local gssd socket");
137*765782e7SRick Macklem 			exit(1);
138*765782e7SRick Macklem 		}
139a9148abdSDoug Rabson 		err(1, "Can't create transport for local gssd socket");
140a9148abdSDoug Rabson 	}
141a9148abdSDoug Rabson 	if (!svc_reg(xprt, GSSD, GSSDVERS, gssd_1, NULL)) {
142*765782e7SRick Macklem 		if (debug_level == 0) {
143*765782e7SRick Macklem 			syslog(LOG_ERR,
144*765782e7SRick Macklem 			    "Can't register service for local gssd socket");
145*765782e7SRick Macklem 			exit(1);
146*765782e7SRick Macklem 		}
147a9148abdSDoug Rabson 		err(1, "Can't register service for local gssd socket");
148a9148abdSDoug Rabson 	}
149a9148abdSDoug Rabson 
150a9148abdSDoug Rabson 	LIST_INIT(&gss_resources);
151a9148abdSDoug Rabson 	gss_next_id = 1;
152a9148abdSDoug Rabson 	gss_start_time = time(0);
153a9148abdSDoug Rabson 
154a9148abdSDoug Rabson 	gssd_syscall(_PATH_GSSDSOCK);
155a9148abdSDoug Rabson 	svc_run();
156a9148abdSDoug Rabson 
157a9148abdSDoug Rabson 	return (0);
158a9148abdSDoug Rabson }
159a9148abdSDoug Rabson 
160a9148abdSDoug Rabson static void
161a9148abdSDoug Rabson gssd_load_mech(void)
162a9148abdSDoug Rabson {
163a9148abdSDoug Rabson 	FILE		*fp;
164a9148abdSDoug Rabson 	char		buf[256];
165a9148abdSDoug Rabson 	char		*p;
166a9148abdSDoug Rabson 	char		*name, *oid, *lib, *kobj;
167a9148abdSDoug Rabson 
168a9148abdSDoug Rabson 	fp = fopen(_PATH_GSS_MECH, "r");
169a9148abdSDoug Rabson 	if (!fp)
170a9148abdSDoug Rabson 		return;
171a9148abdSDoug Rabson 
172a9148abdSDoug Rabson 	while (fgets(buf, sizeof(buf), fp)) {
173a9148abdSDoug Rabson 		if (*buf == '#')
174a9148abdSDoug Rabson 			continue;
175a9148abdSDoug Rabson 		p = buf;
176a9148abdSDoug Rabson 		name = strsep(&p, "\t\n ");
177a9148abdSDoug Rabson 		if (p) while (isspace(*p)) p++;
178a9148abdSDoug Rabson 		oid = strsep(&p, "\t\n ");
179a9148abdSDoug Rabson 		if (p) while (isspace(*p)) p++;
180a9148abdSDoug Rabson 		lib = strsep(&p, "\t\n ");
181a9148abdSDoug Rabson 		if (p) while (isspace(*p)) p++;
182a9148abdSDoug Rabson 		kobj = strsep(&p, "\t\n ");
183a9148abdSDoug Rabson 		if (!name || !oid || !lib || !kobj)
184a9148abdSDoug Rabson 			continue;
185a9148abdSDoug Rabson 
186a9148abdSDoug Rabson 		if (strcmp(kobj, "-")) {
187a9148abdSDoug Rabson 			/*
188a9148abdSDoug Rabson 			 * Attempt to load the kernel module if its
189a9148abdSDoug Rabson 			 * not already present.
190a9148abdSDoug Rabson 			 */
191a9148abdSDoug Rabson 			if (modfind(kobj) < 0) {
192a9148abdSDoug Rabson 				if (kldload(kobj) < 0) {
193a9148abdSDoug Rabson 					fprintf(stderr,
194a9148abdSDoug Rabson 			"%s: can't find or load kernel module %s for %s\n",
195a9148abdSDoug Rabson 					    getprogname(), kobj, name);
196a9148abdSDoug Rabson 				}
197a9148abdSDoug Rabson 			}
198a9148abdSDoug Rabson 		}
199a9148abdSDoug Rabson 	}
200a9148abdSDoug Rabson 	fclose(fp);
201a9148abdSDoug Rabson }
202a9148abdSDoug Rabson 
203a9148abdSDoug Rabson static void *
204a9148abdSDoug Rabson gssd_find_resource(uint64_t id)
205a9148abdSDoug Rabson {
206a9148abdSDoug Rabson 	struct gss_resource *gr;
207a9148abdSDoug Rabson 
208a9148abdSDoug Rabson 	if (!id)
209a9148abdSDoug Rabson 		return (NULL);
210a9148abdSDoug Rabson 
211a9148abdSDoug Rabson 	LIST_FOREACH(gr, &gss_resources, gr_link)
212a9148abdSDoug Rabson 		if (gr->gr_id == id)
213a9148abdSDoug Rabson 			return (gr->gr_res);
214a9148abdSDoug Rabson 
215a9148abdSDoug Rabson 	return (NULL);
216a9148abdSDoug Rabson }
217a9148abdSDoug Rabson 
218a9148abdSDoug Rabson static uint64_t
219a9148abdSDoug Rabson gssd_make_resource(void *res)
220a9148abdSDoug Rabson {
221a9148abdSDoug Rabson 	struct gss_resource *gr;
222a9148abdSDoug Rabson 
223a9148abdSDoug Rabson 	if (!res)
224a9148abdSDoug Rabson 		return (0);
225a9148abdSDoug Rabson 
226a9148abdSDoug Rabson 	gr = malloc(sizeof(struct gss_resource));
227a9148abdSDoug Rabson 	if (!gr)
228a9148abdSDoug Rabson 		return (0);
229a9148abdSDoug Rabson 	gr->gr_id = (gss_next_id++) + ((uint64_t) gss_start_time << 32);
230a9148abdSDoug Rabson 	gr->gr_res = res;
231a9148abdSDoug Rabson 	LIST_INSERT_HEAD(&gss_resources, gr, gr_link);
232a9148abdSDoug Rabson 	gss_resource_count++;
233a9148abdSDoug Rabson 	if (debug_level > 1)
234a9148abdSDoug Rabson 		printf("%d resources allocated\n", gss_resource_count);
235a9148abdSDoug Rabson 
236a9148abdSDoug Rabson 	return (gr->gr_id);
237a9148abdSDoug Rabson }
238a9148abdSDoug Rabson 
239a9148abdSDoug Rabson static void
240a9148abdSDoug Rabson gssd_delete_resource(uint64_t id)
241a9148abdSDoug Rabson {
242a9148abdSDoug Rabson 	struct gss_resource *gr;
243a9148abdSDoug Rabson 
244a9148abdSDoug Rabson 	LIST_FOREACH(gr, &gss_resources, gr_link) {
245a9148abdSDoug Rabson 		if (gr->gr_id == id) {
246a9148abdSDoug Rabson 			LIST_REMOVE(gr, gr_link);
247a9148abdSDoug Rabson 			free(gr);
248a9148abdSDoug Rabson 			gss_resource_count--;
249a9148abdSDoug Rabson 			if (debug_level > 1)
250a9148abdSDoug Rabson 				printf("%d resources allocated\n",
251a9148abdSDoug Rabson 				    gss_resource_count);
252a9148abdSDoug Rabson 			return;
253a9148abdSDoug Rabson 		}
254a9148abdSDoug Rabson 	}
255a9148abdSDoug Rabson }
256a9148abdSDoug Rabson 
257a9148abdSDoug Rabson bool_t
258a9148abdSDoug Rabson gssd_null_1_svc(void *argp, void *result, struct svc_req *rqstp)
259a9148abdSDoug Rabson {
260a9148abdSDoug Rabson 
261a9148abdSDoug Rabson 	return (TRUE);
262a9148abdSDoug Rabson }
263a9148abdSDoug Rabson 
264a9148abdSDoug Rabson bool_t
265a9148abdSDoug Rabson gssd_init_sec_context_1_svc(init_sec_context_args *argp, init_sec_context_res *result, struct svc_req *rqstp)
266a9148abdSDoug Rabson {
267a9148abdSDoug Rabson 	gss_cred_id_t cred = GSS_C_NO_CREDENTIAL;
268a9148abdSDoug Rabson 	gss_ctx_id_t ctx = GSS_C_NO_CONTEXT;
269a9148abdSDoug Rabson 	gss_name_t name = GSS_C_NO_NAME;
270a9148abdSDoug Rabson 	char ccname[strlen("FILE:/tmp/krb5cc_") + 6 + 1];
271a9148abdSDoug Rabson 
272a9148abdSDoug Rabson 	snprintf(ccname, sizeof(ccname), "FILE:/tmp/krb5cc_%d",
273a9148abdSDoug Rabson 	    (int) argp->uid);
274a9148abdSDoug Rabson 	setenv("KRB5CCNAME", ccname, TRUE);
275a9148abdSDoug Rabson 
276a9148abdSDoug Rabson 	memset(result, 0, sizeof(*result));
277a9148abdSDoug Rabson 	if (argp->cred) {
278a9148abdSDoug Rabson 		cred = gssd_find_resource(argp->cred);
279a9148abdSDoug Rabson 		if (!cred) {
280a9148abdSDoug Rabson 			result->major_status = GSS_S_CREDENTIALS_EXPIRED;
281a9148abdSDoug Rabson 			return (TRUE);
282a9148abdSDoug Rabson 		}
283a9148abdSDoug Rabson 	}
284a9148abdSDoug Rabson 	if (argp->ctx) {
285a9148abdSDoug Rabson 		ctx = gssd_find_resource(argp->ctx);
286a9148abdSDoug Rabson 		if (!ctx) {
287a9148abdSDoug Rabson 			result->major_status = GSS_S_CONTEXT_EXPIRED;
288a9148abdSDoug Rabson 			return (TRUE);
289a9148abdSDoug Rabson 		}
290a9148abdSDoug Rabson 	}
291a9148abdSDoug Rabson 	if (argp->name) {
292a9148abdSDoug Rabson 		name = gssd_find_resource(argp->name);
293a9148abdSDoug Rabson 		if (!name) {
294a9148abdSDoug Rabson 			result->major_status = GSS_S_BAD_NAME;
295a9148abdSDoug Rabson 			return (TRUE);
296a9148abdSDoug Rabson 		}
297a9148abdSDoug Rabson 	}
298a9148abdSDoug Rabson 
299a9148abdSDoug Rabson 	memset(result, 0, sizeof(*result));
300a9148abdSDoug Rabson 	result->major_status = gss_init_sec_context(&result->minor_status,
301a9148abdSDoug Rabson 	    cred, &ctx, name, argp->mech_type,
302a9148abdSDoug Rabson 	    argp->req_flags, argp->time_req, argp->input_chan_bindings,
303a9148abdSDoug Rabson 	    &argp->input_token, &result->actual_mech_type,
304a9148abdSDoug Rabson 	    &result->output_token, &result->ret_flags, &result->time_rec);
305a9148abdSDoug Rabson 
306a9148abdSDoug Rabson 	if (result->major_status == GSS_S_COMPLETE
307a9148abdSDoug Rabson 	    || result->major_status == GSS_S_CONTINUE_NEEDED) {
308a9148abdSDoug Rabson 		if (argp->ctx)
309a9148abdSDoug Rabson 			result->ctx = argp->ctx;
310a9148abdSDoug Rabson 		else
311a9148abdSDoug Rabson 			result->ctx = gssd_make_resource(ctx);
312a9148abdSDoug Rabson 	}
313a9148abdSDoug Rabson 
314a9148abdSDoug Rabson 	return (TRUE);
315a9148abdSDoug Rabson }
316a9148abdSDoug Rabson 
317a9148abdSDoug Rabson bool_t
318a9148abdSDoug Rabson gssd_accept_sec_context_1_svc(accept_sec_context_args *argp, accept_sec_context_res *result, struct svc_req *rqstp)
319a9148abdSDoug Rabson {
320a9148abdSDoug Rabson 	gss_ctx_id_t ctx = GSS_C_NO_CONTEXT;
321a9148abdSDoug Rabson 	gss_cred_id_t cred = GSS_C_NO_CREDENTIAL;
322a9148abdSDoug Rabson 	gss_name_t src_name;
323a9148abdSDoug Rabson 	gss_cred_id_t delegated_cred_handle;
324a9148abdSDoug Rabson 
325a9148abdSDoug Rabson 	memset(result, 0, sizeof(*result));
326a9148abdSDoug Rabson 	if (argp->ctx) {
327a9148abdSDoug Rabson 		ctx = gssd_find_resource(argp->ctx);
328a9148abdSDoug Rabson 		if (!ctx) {
329a9148abdSDoug Rabson 			result->major_status = GSS_S_CONTEXT_EXPIRED;
330a9148abdSDoug Rabson 			return (TRUE);
331a9148abdSDoug Rabson 		}
332a9148abdSDoug Rabson 	}
333a9148abdSDoug Rabson 	if (argp->cred) {
334a9148abdSDoug Rabson 		cred = gssd_find_resource(argp->cred);
335a9148abdSDoug Rabson 		if (!cred) {
336a9148abdSDoug Rabson 			result->major_status = GSS_S_CREDENTIALS_EXPIRED;
337a9148abdSDoug Rabson 			return (TRUE);
338a9148abdSDoug Rabson 		}
339a9148abdSDoug Rabson 	}
340a9148abdSDoug Rabson 
341a9148abdSDoug Rabson 	memset(result, 0, sizeof(*result));
342a9148abdSDoug Rabson 	result->major_status = gss_accept_sec_context(&result->minor_status,
343a9148abdSDoug Rabson 	    &ctx, cred, &argp->input_token, argp->input_chan_bindings,
344a9148abdSDoug Rabson 	    &src_name, &result->mech_type, &result->output_token,
345a9148abdSDoug Rabson 	    &result->ret_flags, &result->time_rec,
346a9148abdSDoug Rabson 	    &delegated_cred_handle);
347a9148abdSDoug Rabson 
348a9148abdSDoug Rabson 	if (result->major_status == GSS_S_COMPLETE
349a9148abdSDoug Rabson 	    || result->major_status == GSS_S_CONTINUE_NEEDED) {
350a9148abdSDoug Rabson 		if (argp->ctx)
351a9148abdSDoug Rabson 			result->ctx = argp->ctx;
352a9148abdSDoug Rabson 		else
353a9148abdSDoug Rabson 			result->ctx = gssd_make_resource(ctx);
354a9148abdSDoug Rabson 		result->src_name = gssd_make_resource(src_name);
355a9148abdSDoug Rabson 		result->delegated_cred_handle =
356a9148abdSDoug Rabson 			gssd_make_resource(delegated_cred_handle);
357a9148abdSDoug Rabson 	}
358a9148abdSDoug Rabson 
359a9148abdSDoug Rabson 	return (TRUE);
360a9148abdSDoug Rabson }
361a9148abdSDoug Rabson 
362a9148abdSDoug Rabson bool_t
363a9148abdSDoug Rabson gssd_delete_sec_context_1_svc(delete_sec_context_args *argp, delete_sec_context_res *result, struct svc_req *rqstp)
364a9148abdSDoug Rabson {
365a9148abdSDoug Rabson 	gss_ctx_id_t ctx = gssd_find_resource(argp->ctx);
366a9148abdSDoug Rabson 
367a9148abdSDoug Rabson 	if (ctx) {
368a9148abdSDoug Rabson 		result->major_status = gss_delete_sec_context(
369a9148abdSDoug Rabson 			&result->minor_status, &ctx, &result->output_token);
370a9148abdSDoug Rabson 		gssd_delete_resource(argp->ctx);
371a9148abdSDoug Rabson 	} else {
372a9148abdSDoug Rabson 		result->major_status = GSS_S_COMPLETE;
373a9148abdSDoug Rabson 		result->minor_status = 0;
374a9148abdSDoug Rabson 	}
375a9148abdSDoug Rabson 
376a9148abdSDoug Rabson 	return (TRUE);
377a9148abdSDoug Rabson }
378a9148abdSDoug Rabson 
379a9148abdSDoug Rabson bool_t
380a9148abdSDoug Rabson gssd_export_sec_context_1_svc(export_sec_context_args *argp, export_sec_context_res *result, struct svc_req *rqstp)
381a9148abdSDoug Rabson {
382a9148abdSDoug Rabson 	gss_ctx_id_t ctx = gssd_find_resource(argp->ctx);
383a9148abdSDoug Rabson 
384a9148abdSDoug Rabson 	if (ctx) {
385a9148abdSDoug Rabson 		result->major_status = gss_export_sec_context(
386a9148abdSDoug Rabson 			&result->minor_status, &ctx,
387a9148abdSDoug Rabson 			&result->interprocess_token);
388a9148abdSDoug Rabson 		result->format = KGSS_HEIMDAL_1_1;
389a9148abdSDoug Rabson 		gssd_delete_resource(argp->ctx);
390a9148abdSDoug Rabson 	} else {
391a9148abdSDoug Rabson 		result->major_status = GSS_S_FAILURE;
392a9148abdSDoug Rabson 		result->minor_status = 0;
393a9148abdSDoug Rabson 		result->interprocess_token.length = 0;
394a9148abdSDoug Rabson 		result->interprocess_token.value = NULL;
395a9148abdSDoug Rabson 	}
396a9148abdSDoug Rabson 
397a9148abdSDoug Rabson 	return (TRUE);
398a9148abdSDoug Rabson }
399a9148abdSDoug Rabson 
400a9148abdSDoug Rabson bool_t
401a9148abdSDoug Rabson gssd_import_name_1_svc(import_name_args *argp, import_name_res *result, struct svc_req *rqstp)
402a9148abdSDoug Rabson {
403a9148abdSDoug Rabson 	gss_name_t name;
404a9148abdSDoug Rabson 
405a9148abdSDoug Rabson 	result->major_status = gss_import_name(&result->minor_status,
406a9148abdSDoug Rabson 	    &argp->input_name_buffer, argp->input_name_type, &name);
407a9148abdSDoug Rabson 
408a9148abdSDoug Rabson 	if (result->major_status == GSS_S_COMPLETE)
409a9148abdSDoug Rabson 		result->output_name = gssd_make_resource(name);
410a9148abdSDoug Rabson 	else
411a9148abdSDoug Rabson 		result->output_name = 0;
412a9148abdSDoug Rabson 
413a9148abdSDoug Rabson 	return (TRUE);
414a9148abdSDoug Rabson }
415a9148abdSDoug Rabson 
416a9148abdSDoug Rabson bool_t
417a9148abdSDoug Rabson gssd_canonicalize_name_1_svc(canonicalize_name_args *argp, canonicalize_name_res *result, struct svc_req *rqstp)
418a9148abdSDoug Rabson {
419a9148abdSDoug Rabson 	gss_name_t name = gssd_find_resource(argp->input_name);
420a9148abdSDoug Rabson 	gss_name_t output_name;
421a9148abdSDoug Rabson 
422a9148abdSDoug Rabson 	memset(result, 0, sizeof(*result));
423a9148abdSDoug Rabson 	if (!name) {
424a9148abdSDoug Rabson 		result->major_status = GSS_S_BAD_NAME;
425a9148abdSDoug Rabson 		return (TRUE);
426a9148abdSDoug Rabson 	}
427a9148abdSDoug Rabson 
428a9148abdSDoug Rabson 	result->major_status = gss_canonicalize_name(&result->minor_status,
429a9148abdSDoug Rabson 	    name, argp->mech_type, &output_name);
430a9148abdSDoug Rabson 
431a9148abdSDoug Rabson 	if (result->major_status == GSS_S_COMPLETE)
432a9148abdSDoug Rabson 		result->output_name = gssd_make_resource(output_name);
433a9148abdSDoug Rabson 	else
434a9148abdSDoug Rabson 		result->output_name = 0;
435a9148abdSDoug Rabson 
436a9148abdSDoug Rabson 	return (TRUE);
437a9148abdSDoug Rabson }
438a9148abdSDoug Rabson 
439a9148abdSDoug Rabson bool_t
440a9148abdSDoug Rabson gssd_export_name_1_svc(export_name_args *argp, export_name_res *result, struct svc_req *rqstp)
441a9148abdSDoug Rabson {
442a9148abdSDoug Rabson 	gss_name_t name = gssd_find_resource(argp->input_name);
443a9148abdSDoug Rabson 
444a9148abdSDoug Rabson 	memset(result, 0, sizeof(*result));
445a9148abdSDoug Rabson 	if (!name) {
446a9148abdSDoug Rabson 		result->major_status = GSS_S_BAD_NAME;
447a9148abdSDoug Rabson 		return (TRUE);
448a9148abdSDoug Rabson 	}
449a9148abdSDoug Rabson 
450a9148abdSDoug Rabson 	result->major_status = gss_export_name(&result->minor_status,
451a9148abdSDoug Rabson 	    name, &result->exported_name);
452a9148abdSDoug Rabson 
453a9148abdSDoug Rabson 	return (TRUE);
454a9148abdSDoug Rabson }
455a9148abdSDoug Rabson 
456a9148abdSDoug Rabson bool_t
457a9148abdSDoug Rabson gssd_release_name_1_svc(release_name_args *argp, release_name_res *result, struct svc_req *rqstp)
458a9148abdSDoug Rabson {
459a9148abdSDoug Rabson 	gss_name_t name = gssd_find_resource(argp->input_name);
460a9148abdSDoug Rabson 
461a9148abdSDoug Rabson 	if (name) {
462a9148abdSDoug Rabson 		result->major_status = gss_release_name(&result->minor_status,
463a9148abdSDoug Rabson 		    &name);
464a9148abdSDoug Rabson 		gssd_delete_resource(argp->input_name);
465a9148abdSDoug Rabson 	} else {
466a9148abdSDoug Rabson 		result->major_status = GSS_S_COMPLETE;
467a9148abdSDoug Rabson 		result->minor_status = 0;
468a9148abdSDoug Rabson 	}
469a9148abdSDoug Rabson 
470a9148abdSDoug Rabson 	return (TRUE);
471a9148abdSDoug Rabson }
472a9148abdSDoug Rabson 
473a9148abdSDoug Rabson bool_t
474a9148abdSDoug Rabson gssd_pname_to_uid_1_svc(pname_to_uid_args *argp, pname_to_uid_res *result, struct svc_req *rqstp)
475a9148abdSDoug Rabson {
476a9148abdSDoug Rabson 	gss_name_t name = gssd_find_resource(argp->pname);
477a9148abdSDoug Rabson 	uid_t uid;
478a9148abdSDoug Rabson 	char buf[128];
479a9148abdSDoug Rabson 	struct passwd pwd, *pw;
480a9148abdSDoug Rabson 
481a9148abdSDoug Rabson 	memset(result, 0, sizeof(*result));
482a9148abdSDoug Rabson 	if (name) {
483a9148abdSDoug Rabson 		result->major_status =
484a9148abdSDoug Rabson 			gss_pname_to_uid(&result->minor_status,
485a9148abdSDoug Rabson 			    name, argp->mech, &uid);
486a9148abdSDoug Rabson 		if (result->major_status == GSS_S_COMPLETE) {
487a9148abdSDoug Rabson 			result->uid = uid;
488a9148abdSDoug Rabson 			getpwuid_r(uid, &pwd, buf, sizeof(buf), &pw);
489a9148abdSDoug Rabson 			if (pw) {
490a9148abdSDoug Rabson 				int len = NGRPS;
491a9148abdSDoug Rabson 				int groups[NGRPS];
492a9148abdSDoug Rabson 				result->gid = pw->pw_gid;
493a9148abdSDoug Rabson 				getgrouplist(pw->pw_name, pw->pw_gid,
494a9148abdSDoug Rabson 				    groups, &len);
495a9148abdSDoug Rabson 				result->gidlist.gidlist_len = len;
496a9148abdSDoug Rabson 				result->gidlist.gidlist_val =
497a9148abdSDoug Rabson 					mem_alloc(len * sizeof(int));
498a9148abdSDoug Rabson 				memcpy(result->gidlist.gidlist_val, groups,
499a9148abdSDoug Rabson 				    len * sizeof(int));
500a9148abdSDoug Rabson 			} else {
501a9148abdSDoug Rabson 				result->gid = 65534;
502a9148abdSDoug Rabson 				result->gidlist.gidlist_len = 0;
503a9148abdSDoug Rabson 				result->gidlist.gidlist_val = NULL;
504a9148abdSDoug Rabson 			}
505a9148abdSDoug Rabson 		}
506a9148abdSDoug Rabson 	} else {
507a9148abdSDoug Rabson 		result->major_status = GSS_S_BAD_NAME;
508a9148abdSDoug Rabson 		result->minor_status = 0;
509a9148abdSDoug Rabson 	}
510a9148abdSDoug Rabson 
511a9148abdSDoug Rabson 	return (TRUE);
512a9148abdSDoug Rabson }
513a9148abdSDoug Rabson 
514a9148abdSDoug Rabson bool_t
515a9148abdSDoug Rabson gssd_acquire_cred_1_svc(acquire_cred_args *argp, acquire_cred_res *result, struct svc_req *rqstp)
516a9148abdSDoug Rabson {
517a9148abdSDoug Rabson 	gss_name_t desired_name = GSS_C_NO_NAME;
518a9148abdSDoug Rabson 	gss_cred_id_t cred;
519a9148abdSDoug Rabson 	char ccname[strlen("FILE:/tmp/krb5cc_") + 6 + 1];
520a9148abdSDoug Rabson 
521a9148abdSDoug Rabson 	snprintf(ccname, sizeof(ccname), "FILE:/tmp/krb5cc_%d",
522a9148abdSDoug Rabson 	    (int) argp->uid);
523a9148abdSDoug Rabson 	setenv("KRB5CCNAME", ccname, TRUE);
524a9148abdSDoug Rabson 
525a9148abdSDoug Rabson 	memset(result, 0, sizeof(*result));
526a9148abdSDoug Rabson 	if (argp->desired_name) {
527a9148abdSDoug Rabson 		desired_name = gssd_find_resource(argp->desired_name);
528a9148abdSDoug Rabson 		if (!desired_name) {
529a9148abdSDoug Rabson 			result->major_status = GSS_S_BAD_NAME;
530a9148abdSDoug Rabson 			return (TRUE);
531a9148abdSDoug Rabson 		}
532a9148abdSDoug Rabson 	}
533a9148abdSDoug Rabson 
534a9148abdSDoug Rabson 	result->major_status = gss_acquire_cred(&result->minor_status,
535a9148abdSDoug Rabson 	    desired_name, argp->time_req, argp->desired_mechs,
536a9148abdSDoug Rabson 	    argp->cred_usage, &cred, &result->actual_mechs, &result->time_rec);
537a9148abdSDoug Rabson 
538a9148abdSDoug Rabson 	if (result->major_status == GSS_S_COMPLETE)
539a9148abdSDoug Rabson 		result->output_cred = gssd_make_resource(cred);
540a9148abdSDoug Rabson 	else
541a9148abdSDoug Rabson 		result->output_cred = 0;
542a9148abdSDoug Rabson 
543a9148abdSDoug Rabson 	return (TRUE);
544a9148abdSDoug Rabson }
545a9148abdSDoug Rabson 
546a9148abdSDoug Rabson bool_t
547a9148abdSDoug Rabson gssd_set_cred_option_1_svc(set_cred_option_args *argp, set_cred_option_res *result, struct svc_req *rqstp)
548a9148abdSDoug Rabson {
549a9148abdSDoug Rabson 	gss_cred_id_t cred = gssd_find_resource(argp->cred);
550a9148abdSDoug Rabson 
551a9148abdSDoug Rabson 	memset(result, 0, sizeof(*result));
552a9148abdSDoug Rabson 	if (!cred) {
553a9148abdSDoug Rabson 		result->major_status = GSS_S_CREDENTIALS_EXPIRED;
554a9148abdSDoug Rabson 		return (TRUE);
555a9148abdSDoug Rabson 	}
556a9148abdSDoug Rabson 
557a9148abdSDoug Rabson 	result->major_status = gss_set_cred_option(&result->minor_status,
558a9148abdSDoug Rabson 	    &cred, argp->option_name, &argp->option_value);
559a9148abdSDoug Rabson 
560a9148abdSDoug Rabson 	return (TRUE);
561a9148abdSDoug Rabson }
562a9148abdSDoug Rabson 
563a9148abdSDoug Rabson bool_t
564a9148abdSDoug Rabson gssd_release_cred_1_svc(release_cred_args *argp, release_cred_res *result, struct svc_req *rqstp)
565a9148abdSDoug Rabson {
566a9148abdSDoug Rabson 	gss_cred_id_t cred = gssd_find_resource(argp->cred);
567a9148abdSDoug Rabson 
568a9148abdSDoug Rabson 	if (cred) {
569a9148abdSDoug Rabson 		result->major_status = gss_release_cred(&result->minor_status,
570a9148abdSDoug Rabson 		    &cred);
571a9148abdSDoug Rabson 		gssd_delete_resource(argp->cred);
572a9148abdSDoug Rabson 	} else {
573a9148abdSDoug Rabson 		result->major_status = GSS_S_COMPLETE;
574a9148abdSDoug Rabson 		result->minor_status = 0;
575a9148abdSDoug Rabson 	}
576a9148abdSDoug Rabson 
577a9148abdSDoug Rabson 	return (TRUE);
578a9148abdSDoug Rabson }
579a9148abdSDoug Rabson 
580a9148abdSDoug Rabson bool_t
581a9148abdSDoug Rabson gssd_display_status_1_svc(display_status_args *argp, display_status_res *result, struct svc_req *rqstp)
582a9148abdSDoug Rabson {
583a9148abdSDoug Rabson 
584a9148abdSDoug Rabson 	result->message_context = argp->message_context;
585a9148abdSDoug Rabson 	result->major_status = gss_display_status(&result->minor_status,
586a9148abdSDoug Rabson 	    argp->status_value, argp->status_type, argp->mech_type,
587a9148abdSDoug Rabson 	    &result->message_context, &result->status_string);
588a9148abdSDoug Rabson 
589a9148abdSDoug Rabson 	return (TRUE);
590a9148abdSDoug Rabson }
591a9148abdSDoug Rabson 
592a9148abdSDoug Rabson int
593a9148abdSDoug Rabson gssd_1_freeresult(SVCXPRT *transp, xdrproc_t xdr_result, caddr_t result)
594a9148abdSDoug Rabson {
595a9148abdSDoug Rabson 	/*
596a9148abdSDoug Rabson 	 * We don't use XDR to free the results - anything which was
597a9148abdSDoug Rabson 	 * allocated came from GSS-API. We use xdr_result to figure
598a9148abdSDoug Rabson 	 * out what to do.
599a9148abdSDoug Rabson 	 */
600a9148abdSDoug Rabson 	OM_uint32 junk;
601a9148abdSDoug Rabson 
602a9148abdSDoug Rabson 	if (xdr_result == (xdrproc_t) xdr_init_sec_context_res) {
603a9148abdSDoug Rabson 		init_sec_context_res *p = (init_sec_context_res *) result;
604a9148abdSDoug Rabson 		gss_release_buffer(&junk, &p->output_token);
605a9148abdSDoug Rabson 	} else if (xdr_result == (xdrproc_t) xdr_accept_sec_context_res) {
606a9148abdSDoug Rabson 		accept_sec_context_res *p = (accept_sec_context_res *) result;
607a9148abdSDoug Rabson 		gss_release_buffer(&junk, &p->output_token);
608a9148abdSDoug Rabson 	} else if (xdr_result == (xdrproc_t) xdr_delete_sec_context_res) {
609a9148abdSDoug Rabson 		delete_sec_context_res *p = (delete_sec_context_res *) result;
610a9148abdSDoug Rabson 		gss_release_buffer(&junk, &p->output_token);
611a9148abdSDoug Rabson 	} else if (xdr_result == (xdrproc_t) xdr_export_sec_context_res) {
612a9148abdSDoug Rabson 		export_sec_context_res *p = (export_sec_context_res *) result;
613a9148abdSDoug Rabson 		if (p->interprocess_token.length)
614a9148abdSDoug Rabson 			memset(p->interprocess_token.value, 0,
615a9148abdSDoug Rabson 			    p->interprocess_token.length);
616a9148abdSDoug Rabson 		gss_release_buffer(&junk, &p->interprocess_token);
617a9148abdSDoug Rabson 	} else if (xdr_result == (xdrproc_t) xdr_export_name_res) {
618a9148abdSDoug Rabson 		export_name_res *p = (export_name_res *) result;
619a9148abdSDoug Rabson 		gss_release_buffer(&junk, &p->exported_name);
620a9148abdSDoug Rabson 	} else if (xdr_result == (xdrproc_t) xdr_acquire_cred_res) {
621a9148abdSDoug Rabson 		acquire_cred_res *p = (acquire_cred_res *) result;
622a9148abdSDoug Rabson 		gss_release_oid_set(&junk, &p->actual_mechs);
623a9148abdSDoug Rabson 	} else if (xdr_result == (xdrproc_t) xdr_pname_to_uid_res) {
624a9148abdSDoug Rabson 		pname_to_uid_res *p = (pname_to_uid_res *) result;
625a9148abdSDoug Rabson 		if (p->gidlist.gidlist_val)
626a9148abdSDoug Rabson 			free(p->gidlist.gidlist_val);
627a9148abdSDoug Rabson 	} else if (xdr_result == (xdrproc_t) xdr_display_status_res) {
628a9148abdSDoug Rabson 		display_status_res *p = (display_status_res *) result;
629a9148abdSDoug Rabson 		gss_release_buffer(&junk, &p->status_string);
630a9148abdSDoug Rabson 	}
631a9148abdSDoug Rabson 
632a9148abdSDoug Rabson 	return (TRUE);
633a9148abdSDoug Rabson }
634