xref: /illumos-gate/usr/src/cmd/gss/gssd/gssd_proc.c (revision 9890ff8357a674572254e0be06b175a1e8eab4b0)
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 (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2017 Joyent Inc
23  * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
24  */
25 
26 /*
27  *  RPC server procedures for the gssapi usermode daemon gssd.
28  */
29 
30 #include <stdio.h>
31 #include <stdio_ext.h>
32 #include <unistd.h>
33 #include <pwd.h>
34 #include <grp.h>
35 #include <strings.h>
36 #include <limits.h>
37 #include <sys/param.h>
38 #include <mechglueP.h>
39 #include "gssd.h"
40 #include <gssapi/gssapi.h>
41 #include <rpc/rpc.h>
42 #include <stdlib.h>
43 #include <syslog.h>
44 #include <sys/resource.h>
45 #include <sys/debug.h>
46 
47 #define	SRVTAB	""
48 #define	FDCACHE_PERCENTAGE	.75	/* Percentage of total FD limit */
49 #define	FDCACHE_DEFAULT		16	/* Default LRU cache size */
50 #define	GSSD_FD_LIMIT		255	/* Increase number of fds allowed */
51 
52 extern int gssd_debug;			/* declared in gssd.c */
53 static OM_uint32 gssd_time_verf;	/* verifies same gssd */
54 static OM_uint32 context_verf;		/* context sequence numbers */
55 
56 struct gssd_ctx_slot {
57 	struct gssd_ctx_slot *lru_next;
58 	struct gssd_ctx_slot *lru_prev;
59 	bool_t		inuse;
60 	OM_uint32	create_time;
61 	OM_uint32	verf;
62 	gss_ctx_id_t	ctx;
63 	gss_ctx_id_t	rpcctx;
64 };
65 
66 struct gssd_ctx_slot *gssd_ctx_slot_tbl;
67 struct gssd_ctx_slot *gssd_lru_head;
68 
69 static int max_contexts;
70 
71 static int checkfrom(struct svc_req *, uid_t *);
72 extern void set_gssd_uid(uid_t);
73 extern int __rpc_get_local_uid(SVCXPRT *, uid_t *);
74 
75 /*
76  * Syslog (and output to stderr if debug set) the GSSAPI major
77  * and minor numbers.
78  */
79 static void
80 syslog_gss_error(OM_uint32 maj_stat, OM_uint32 min_stat, char *errstr)
81 {
82 	OM_uint32 gmaj_stat, gmin_stat;
83 	gss_buffer_desc msg;
84 	OM_uint32 msg_ctx = 0;
85 
86 
87 	if (gssd_debug)
88 		fprintf(stderr,
89 		    "gssd: syslog_gss_err: called from %s: maj=%d min=%d\n",
90 		    errstr ? errstr : "<null>", maj_stat, min_stat);
91 
92 	/* Print the major status error from the mech. */
93 	/* msg_ctx - skip the check for it as is probably unnecesary */
94 	gmaj_stat = gss_display_status(&gmin_stat, maj_stat,
95 	    GSS_C_GSS_CODE,
96 	    GSS_C_NULL_OID, &msg_ctx, &msg);
97 	if ((gmaj_stat == GSS_S_COMPLETE)||
98 	    (gmaj_stat == GSS_S_CONTINUE_NEEDED)) {
99 		syslog(LOG_DAEMON|LOG_NOTICE,
100 		    "GSSAPI error major: %s", (char *)msg.value);
101 		if (gssd_debug)
102 			(void) fprintf(stderr,
103 			    "gssd: GSSAPI error major: %s\n",
104 			    (char *)msg.value);
105 
106 		(void) gss_release_buffer(&gmin_stat, &msg);
107 	}
108 
109 	/* Print the minor status error from the mech. */
110 	msg_ctx = 0;
111 	/* msg_ctx - skip the check for it as is probably unnecesary */
112 	gmaj_stat = gss_display_status(&gmin_stat, min_stat,
113 	    GSS_C_MECH_CODE,
114 	    GSS_C_NULL_OID,
115 	    &msg_ctx, &msg);
116 	if ((gmaj_stat == GSS_S_COMPLETE)||
117 	    (gmaj_stat == GSS_S_CONTINUE_NEEDED)) {
118 		syslog(LOG_DAEMON|LOG_NOTICE,
119 		    "GSSAPI error minor: %s",
120 		    (char *)msg.value);
121 		if (gssd_debug)
122 			(void) fprintf(stderr,
123 			    "gssd: GSSAPI error minor: %s\n",
124 			    (char *)msg.value);
125 		(void) gss_release_buffer(&gmin_stat, &msg);
126 	}
127 }
128 
129 void
130 gssd_setup(char *arg)
131 {
132 	int i;
133 	struct rlimit rl;
134 	hrtime_t high_res_time;
135 
136 	gssd_time_verf = (OM_uint32)time(NULL);
137 	max_contexts = FDCACHE_DEFAULT;
138 
139 	/*
140 	 * Use low order bits of high resolution time to get a reasonably
141 	 * random number to start the context sequencing.  This alternative
142 	 * to using a time value avoid clock resets via NTP or ntpdate.
143 	 */
144 	high_res_time = gethrtime();
145 	context_verf = (OM_uint32)high_res_time;
146 
147 	/*
148 	 * Increase resource limit of FDs in case we get alot accept/init_
149 	 * sec_context calls before we're able to export them.  This can
150 	 * happen in very heavily load environments where gssd doesn't get
151 	 * much time to work on its backlog.
152 	 */
153 	if ((getrlimit(RLIMIT_NOFILE, &rl)) == 0) {
154 		rl.rlim_cur = (rl.rlim_max >= GSSD_FD_LIMIT) ?
155 				GSSD_FD_LIMIT : rl.rlim_max;
156 		if ((setrlimit(RLIMIT_NOFILE, &rl)) == 0)
157 			max_contexts = rl.rlim_cur * FDCACHE_PERCENTAGE;
158 		(void) enable_extended_FILE_stdio(-1, -1);
159 	}
160 
161 	gssd_ctx_slot_tbl = (struct gssd_ctx_slot *)
162 		malloc(sizeof (struct gssd_ctx_slot) * max_contexts);
163 
164 	if (gssd_ctx_slot_tbl == NULL) {
165 		(void) fprintf(stderr,
166 			gettext("[%s] could not allocate %d byte context table"
167 			"\n"), arg,
168 			(sizeof (struct gssd_ctx_slot) * max_contexts));
169 		exit(1);
170 	}
171 
172 	for (i = 1; i < max_contexts; i++) {
173 		gssd_ctx_slot_tbl[i-1].lru_next = &gssd_ctx_slot_tbl[i];
174 		gssd_ctx_slot_tbl[i].lru_prev = &gssd_ctx_slot_tbl[i-1];
175 		gssd_ctx_slot_tbl[i].inuse = FALSE;
176 		gssd_ctx_slot_tbl[i].verf = 0;
177 		gssd_ctx_slot_tbl[i].create_time = 0;
178 		gssd_ctx_slot_tbl[i].rpcctx = (gss_ctx_id_t)(i + 1);
179 	}
180 
181 	gssd_ctx_slot_tbl[max_contexts - 1].lru_next = &gssd_ctx_slot_tbl[0];
182 	gssd_ctx_slot_tbl[0].lru_prev = &gssd_ctx_slot_tbl[max_contexts - 1];
183 	gssd_ctx_slot_tbl[0].inuse = FALSE;
184 	gssd_ctx_slot_tbl[0].verf = 0;
185 	gssd_ctx_slot_tbl[0].create_time = 0;
186 	gssd_ctx_slot_tbl[0].rpcctx = (gss_ctx_id_t)1;
187 
188 	gssd_lru_head = &gssd_ctx_slot_tbl[0];
189 }
190 
191 static OM_uint32 syslog_interval = 60;
192 
193 static struct gssd_ctx_slot *
194 gssd_alloc_slot(gss_ctx_id_t ctx)
195 {
196 	struct gssd_ctx_slot *lru;
197 	OM_uint32 current_time;
198 	static OM_uint32 last_syslog = 0;
199 	static bool_t first_take = TRUE;
200 	static int tooks;
201 	OM_uint32 minor_status;
202 
203 	lru = gssd_lru_head;
204 	gssd_lru_head = lru->lru_next;
205 
206 	current_time = (OM_uint32) time(NULL);
207 
208 	if (last_syslog == 0)
209 		last_syslog = current_time;	/* Save 1st alloc time */
210 
211 	if (lru->inuse) {
212 		if (lru->ctx != GSS_C_NO_CONTEXT)
213 			(void) gss_delete_sec_context(&minor_status,
214 				&lru->ctx, NULL);
215 		tooks++;
216 
217 		if (((current_time - last_syslog) > syslog_interval) ||
218 			first_take) {
219 			syslog(LOG_WARNING, gettext("re-used an existing "
220 				"context slot of age %u seconds (%d slots re-"
221 				"used during last %u seconds)"),
222 				current_time - lru->create_time, tooks,
223 				current_time - last_syslog);
224 
225 			last_syslog = current_time;
226 			tooks = 0;
227 			first_take = FALSE;
228 		}
229 	}
230 
231 	/*
232 	 * Assign the next context verifier to the context (avoiding zero).
233 	 */
234 	context_verf++;
235 	if (context_verf == 0)
236 		context_verf = 1;
237 	lru->verf = context_verf;
238 
239 	lru->create_time = current_time;
240 	lru->ctx = ctx;
241 	lru->inuse = TRUE;
242 	return (lru);
243 }
244 
245 /*
246  * We always add 1 because we don't want slot 0 to be confused
247  * with GSS_C_NO_CONTEXT.
248  */
249 
250 static struct gssd_ctx_slot *
251 gssd_handle_to_slot(GSS_CTX_ID_T *h)
252 {
253 	intptr_t i;
254 
255 	if (h->GSS_CTX_ID_T_len == 0) {
256 		return (NULL);
257 	}
258 	if (h->GSS_CTX_ID_T_len != sizeof (i))
259 		return (NULL);
260 
261 	i = (*(intptr_t *)(h->GSS_CTX_ID_T_val)) - 1;
262 
263 	if (i < 0 || i >= max_contexts)
264 		return (NULL);
265 
266 	return (&gssd_ctx_slot_tbl[i]);
267 }
268 
269 static void
270 gssd_rel_slot(struct gssd_ctx_slot *lru)
271 {
272 	struct gssd_ctx_slot *prev, *next;
273 
274 	if (lru == NULL)
275 		return;
276 
277 	lru->inuse = FALSE;
278 
279 	/*
280 	 * Remove entry from its current location in list
281 	 */
282 	prev = lru->lru_prev;
283 	next = lru->lru_next;
284 	prev->lru_next = next;
285 	next->lru_prev = prev;
286 
287 	/*
288 	 * Since it is no longer in use, it is the least recently
289 	 * used.
290 	 */
291 	prev = gssd_lru_head->lru_prev;
292 	next = gssd_lru_head;
293 
294 	prev->lru_next = lru;
295 	lru->lru_prev = prev;
296 
297 	next->lru_prev = lru;
298 	lru->lru_next = next;
299 
300 	gssd_lru_head = lru;
301 }
302 
303 static void
304 gssd_convert_context_handle(GSS_CTX_ID_T *h,
305 	gss_ctx_id_t *context_handle,
306 	OM_uint32 verf,
307 	bool_t *context_verf_ok,
308 	struct gssd_ctx_slot **slotp)
309 {
310 	struct gssd_ctx_slot *slot;
311 
312 	*context_verf_ok = FALSE;
313 	*context_handle = (gss_ctx_id_t)1;
314 	if (slotp != NULL)
315 		*slotp = NULL;
316 
317 	if (h->GSS_CTX_ID_T_len == 0) {
318 		*context_handle = GSS_C_NO_CONTEXT;
319 		*context_verf_ok = TRUE;
320 		return;
321 	}
322 
323 	slot = gssd_handle_to_slot(h);
324 
325 	if (slot == NULL)
326 		return;
327 
328 	if (verf != slot->verf)
329 		return;
330 
331 	*context_verf_ok = TRUE;
332 	*context_handle = slot->ctx;
333 	if (slotp != NULL)
334 		*slotp = slot;
335 }
336 
337 bool_t
338 gss_acquire_cred_1_svc(argp, res, rqstp)
339 	gss_acquire_cred_arg *argp;
340 	gss_acquire_cred_res *res;
341 	struct svc_req *rqstp;
342 {
343 	OM_uint32 		minor_status;
344 	gss_name_t		desired_name;
345 	gss_OID_desc		name_type_desc;
346 	gss_OID			name_type = &name_type_desc;
347 	OM_uint32		time_req;
348 	gss_OID_set_desc	desired_mechs_desc;
349 	gss_OID_set		desired_mechs;
350 	int			cred_usage;
351 	gss_cred_id_t 		output_cred_handle;
352 	gss_OID_set 		actual_mechs;
353 	gss_buffer_desc		external_name;
354 	uid_t			uid;
355 	int			i, j;
356 
357 	if (gssd_debug)
358 		fprintf(stderr, gettext("gss_acquire_cred\n"));
359 
360 	memset(res, 0, sizeof (*res));
361 
362 	/*
363 	 * if the request isn't from root, null out the result pointer
364 	 * entries, so the next time through xdr_free won't try to
365 	 * free unmalloc'd memory and then return NULL
366 	 */
367 
368 	if (checkfrom(rqstp, &uid) == 0) {
369 		res->output_cred_handle.GSS_CRED_ID_T_val = NULL;
370 		res->actual_mechs.GSS_OID_SET_val = NULL;
371 		return (FALSE);
372 	}
373 
374 /* set the uid sent as the RPC argument */
375 
376 	uid = argp->uid;
377 	set_gssd_uid(uid);
378 
379 /* convert the desired name from external to internal format */
380 
381 	external_name.length = argp->desired_name.GSS_BUFFER_T_len;
382 	external_name.value = (void *)malloc(external_name.length);
383 	if (!external_name.value)
384 		return (GSS_S_FAILURE);
385 	memcpy(external_name.value, argp->desired_name.GSS_BUFFER_T_val,
386 		external_name.length);
387 
388 	if (argp->name_type.GSS_OID_len == 0) {
389 		name_type = GSS_C_NULL_OID;
390 	} else {
391 		name_type->length = argp->name_type.GSS_OID_len;
392 		name_type->elements = (void *)malloc(name_type->length);
393 		if (!name_type->elements) {
394 			free(external_name.value);
395 			return (GSS_S_FAILURE);
396 		}
397 		memcpy(name_type->elements, argp->name_type.GSS_OID_val,
398 			name_type->length);
399 	}
400 
401 	if (gss_import_name(&minor_status, &external_name, name_type,
402 			    &desired_name) != GSS_S_COMPLETE) {
403 
404 		res->status = (OM_uint32) GSS_S_FAILURE;
405 		res->minor_status = minor_status;
406 
407 		free(external_name.value);
408 		if (name_type != GSS_C_NULL_OID)
409 			free(name_type->elements);
410 
411 		return (TRUE);
412 	}
413 
414 /*
415  * copy the XDR structured arguments into their corresponding local GSSAPI
416  * variables.
417  */
418 
419 	cred_usage = argp->cred_usage;
420 	time_req = argp->time_req;
421 
422 	if (argp->desired_mechs.GSS_OID_SET_len != 0) {
423 		desired_mechs = &desired_mechs_desc;
424 		desired_mechs->count =
425 			(int)argp->desired_mechs.GSS_OID_SET_len;
426 		desired_mechs->elements = (gss_OID)
427 			malloc(sizeof (gss_OID_desc) * desired_mechs->count);
428 		if (!desired_mechs->elements) {
429 			free(external_name.value);
430 			free(name_type->elements);
431 			return (GSS_S_FAILURE);
432 		}
433 		for (i = 0; i < desired_mechs->count; i++) {
434 			desired_mechs->elements[i].length =
435 				(OM_uint32)argp->desired_mechs.
436 				GSS_OID_SET_val[i].GSS_OID_len;
437 			desired_mechs->elements[i].elements =
438 				(void *)malloc(desired_mechs->elements[i].
439 						length);
440 			if (!desired_mechs->elements[i].elements) {
441 				free(external_name.value);
442 				free(name_type->elements);
443 				for (j = 0; j < (i -1); j++) {
444 					free
445 					(desired_mechs->elements[j].elements);
446 				}
447 				free(desired_mechs->elements);
448 				return (GSS_S_FAILURE);
449 			}
450 			memcpy(desired_mechs->elements[i].elements,
451 				argp->desired_mechs.GSS_OID_SET_val[i].
452 				GSS_OID_val,
453 				desired_mechs->elements[i].length);
454 		}
455 	} else
456 		desired_mechs = GSS_C_NULL_OID_SET;
457 
458 	/* call the gssapi routine */
459 
460 	res->status = (OM_uint32)gss_acquire_cred(&res->minor_status,
461 				desired_name,
462 				time_req,
463 				desired_mechs,
464 				cred_usage,
465 				&output_cred_handle,
466 				&actual_mechs,
467 				&res->time_rec);
468 
469 	/*
470 	 * convert the output args from the parameter given in the call to the
471 	 * variable in the XDR result
472 	 */
473 
474 	res->output_cred_handle.GSS_CRED_ID_T_len = sizeof (gss_cred_id_t);
475 	res->output_cred_handle.GSS_CRED_ID_T_val =
476 		(void *)malloc(sizeof (gss_cred_id_t));
477 	if (!res->output_cred_handle.GSS_CRED_ID_T_val) {
478 		free(external_name.value);
479 		free(name_type->elements);
480 		for (i = 0; i < desired_mechs->count; i++) {
481 			free(desired_mechs->elements[i].elements);
482 			}
483 		free(desired_mechs->elements);
484 		return (GSS_S_FAILURE);
485 	}
486 	memcpy(res->output_cred_handle.GSS_CRED_ID_T_val, &output_cred_handle,
487 		sizeof (gss_cred_id_t));
488 
489 	if (actual_mechs != GSS_C_NULL_OID_SET) {
490 		res->actual_mechs.GSS_OID_SET_len =
491 			(uint_t)actual_mechs->count;
492 		res->actual_mechs.GSS_OID_SET_val = (GSS_OID *)
493 			malloc(sizeof (GSS_OID) * actual_mechs->count);
494 		if (!res->actual_mechs.GSS_OID_SET_val) {
495 			free(external_name.value);
496 			free(name_type->elements);
497 			for (i = 0; i < desired_mechs->count; i++) {
498 				free(desired_mechs->elements[i].elements);
499 			}
500 			free(desired_mechs->elements);
501 			free(res->output_cred_handle.GSS_CRED_ID_T_val);
502 			return (GSS_S_FAILURE);
503 		}
504 		for (i = 0; i < actual_mechs->count; i++) {
505 			res->actual_mechs.GSS_OID_SET_val[i].GSS_OID_len =
506 				(uint_t)actual_mechs->elements[i].length;
507 			res->actual_mechs.GSS_OID_SET_val[i].GSS_OID_val =
508 				(char *)malloc(actual_mechs->elements[i].
509 						length);
510 			if (!res->actual_mechs.GSS_OID_SET_val[i].GSS_OID_val) {
511 				free(external_name.value);
512 				free(name_type->elements);
513 				free(desired_mechs->elements);
514 				for (j = 0; j < desired_mechs->count; j++) {
515 					free
516 					(desired_mechs->elements[i].elements);
517 				}
518 				free(res->actual_mechs.GSS_OID_SET_val);
519 				for (j = 0; j < (i - 1); j++) {
520 					free
521 					(res->actual_mechs.
522 						GSS_OID_SET_val[j].GSS_OID_val);
523 				}
524 				return (GSS_S_FAILURE);
525 			}
526 			memcpy(res->actual_mechs.GSS_OID_SET_val[i].GSS_OID_val,
527 				actual_mechs->elements[i].elements,
528 				actual_mechs->elements[i].length);
529 		}
530 	} else
531 		res->actual_mechs.GSS_OID_SET_len = 0;
532 
533 	/*
534 	 * set the time verifier for credential handle.  To ensure that the
535 	 * timestamp is not the same as previous gssd process, verify that
536 	 * time is not the same as set earlier at start of process.  If it
537 	 * is, sleep one second and reset. (due to one second granularity)
538 	 */
539 
540 	if (res->status == GSS_S_COMPLETE) {
541 		res->gssd_cred_verifier = (OM_uint32)time(NULL);
542 		if (res->gssd_cred_verifier == gssd_time_verf) {
543 			sleep(1);
544 			gssd_time_verf = (OM_uint32)time(NULL);
545 		}
546 		res->gssd_cred_verifier = gssd_time_verf;
547 	} else
548 		syslog_gss_error(res->status, res->minor_status,
549 		    "acquire_cred");
550 
551 	/*
552 	 * now release the space allocated by the underlying gssapi mechanism
553 	 * library for actual_mechs as well as by this routine for
554 	 * external_name, name_type and desired_name
555 	 */
556 
557 	free(external_name.value);
558 	if (name_type != GSS_C_NULL_OID)
559 		free(name_type->elements);
560 	gss_release_name(&minor_status, &desired_name);
561 
562 	if (actual_mechs != GSS_C_NULL_OID_SET) {
563 		for (i = 0; i < actual_mechs->count; i++)
564 			free(actual_mechs->elements[i].elements);
565 		free(actual_mechs->elements);
566 		free(actual_mechs);
567 	}
568 
569 	if (desired_mechs != GSS_C_NULL_OID_SET) {
570 		for (i = 0; i < desired_mechs->count; i++)
571 			free(desired_mechs->elements[i].elements);
572 		free(desired_mechs->elements);
573 
574 	}
575 
576 /* return to caller */
577 
578 	return (TRUE);
579 }
580 
581 bool_t
582 gss_add_cred_1_svc(argp, res, rqstp)
583 	gss_add_cred_arg *argp;
584 	gss_add_cred_res *res;
585 	struct svc_req *rqstp;
586 {
587 
588 	OM_uint32 		minor_status;
589 	gss_name_t		desired_name;
590 	gss_OID_desc		name_type_desc;
591 	gss_OID			name_type = &name_type_desc;
592 	gss_OID_desc		desired_mech_type_desc;
593 	gss_OID			desired_mech_type = &desired_mech_type_desc;
594 	int			cred_usage;
595 	gss_cred_id_t 		input_cred_handle;
596 	gss_OID_set 		actual_mechs;
597 	gss_buffer_desc		external_name;
598 	uid_t			uid;
599 	int			i, j;
600 
601 	if (gssd_debug)
602 		fprintf(stderr, gettext("gss_add_cred\n"));
603 
604 	if (argp->gssd_cred_verifier != gssd_time_verf) {
605 		res->status = (OM_uint32)GSS_S_DEFECTIVE_CREDENTIAL;
606 		res->minor_status = 0;
607 		res->actual_mechs.GSS_OID_SET_len = 0;
608 		res->actual_mechs.GSS_OID_SET_val = NULL;
609 		res->initiator_time_rec = 0;
610 		res->acceptor_time_rec = 0;
611 		fprintf(stderr, gettext("gss_add_cred defective cred\n"));
612 		return (TRUE);
613 	}
614 	memset(res, 0, sizeof (*res));
615 
616 	/*
617 	 * if the request isn't from root, null out the result pointer
618 	 * entries, so the next time through xdr_free won't try to
619 	 * free unmalloc'd memory and then return NULL
620 	 */
621 
622 	if (checkfrom(rqstp, &uid) == 0) {
623 		return (FALSE);
624 	}
625 
626 /* set the uid sent as the RPC argument */
627 
628 	uid = argp->uid;
629 	set_gssd_uid(uid);
630 
631 /* convert the desired name from external to internal format */
632 
633 	external_name.length = argp->desired_name.GSS_BUFFER_T_len;
634 	external_name.value = (void *)argp->desired_name.GSS_BUFFER_T_val;
635 	name_type->length = argp->name_type.GSS_OID_len;
636 	name_type->elements = (void *)argp->name_type.GSS_OID_val;
637 
638 	if (gss_import_name(&minor_status, &external_name, name_type,
639 			    &desired_name) != GSS_S_COMPLETE) {
640 
641 		if (gssd_debug)
642 			fprintf(stderr,
643 				gettext("gss_add_cred:import name"),
644 				gettext(" failed status %d \n"),
645 				res->status);
646 		res->status = (OM_uint32)GSS_S_FAILURE;
647 		res->minor_status = minor_status;
648 		return (TRUE);
649 	}
650 
651 /*
652  * copy the XDR structured arguments into their corresponding local GSSAPI
653  * variables.
654  */
655 
656 	cred_usage = argp->cred_usage;
657 	if (argp->desired_mech_type.GSS_OID_len == 0)
658 		desired_mech_type = GSS_C_NULL_OID;
659 	else {
660 		desired_mech_type->length =
661 			(OM_uint32)argp->desired_mech_type.GSS_OID_len;
662 		desired_mech_type->elements =
663 			(void *)malloc(desired_mech_type->length);
664 		if (!desired_mech_type->elements) {
665 			return (GSS_S_FAILURE);
666 		}
667 		memcpy(desired_mech_type->elements,
668 			argp->desired_mech_type.GSS_OID_val,
669 			desired_mech_type->length);
670 	}
671 	input_cred_handle =
672 		(argp->input_cred_handle.GSS_CRED_ID_T_len == 0 ?
673 			GSS_C_NO_CREDENTIAL :
674 			/*LINTED*/
675 			*((gss_cred_id_t *)argp->input_cred_handle.
676 				GSS_CRED_ID_T_val));
677 
678 	if (input_cred_handle != GSS_C_NO_CREDENTIAL)
679 	/* verify the input_cred_handle */
680 		if (argp->gssd_cred_verifier != gssd_time_verf) {
681 			res->status = (OM_uint32)GSS_S_DEFECTIVE_CREDENTIAL;
682 			res->minor_status = 0;
683 			return (TRUE);
684 		}
685 
686 	/* call the gssapi routine */
687 
688 	res->status = (OM_uint32)gss_add_cred(&res->minor_status,
689 				input_cred_handle,
690 				desired_name,
691 				desired_mech_type,
692 				cred_usage,
693 				argp->initiator_time_req,
694 				argp->acceptor_time_req,
695 				NULL,
696 				&actual_mechs,
697 				&res->initiator_time_rec,
698 				&res->acceptor_time_rec);
699 
700 	if ((res->status != GSS_S_COMPLETE) &&
701 		(res->status != GSS_S_DUPLICATE_ELEMENT))
702 		syslog_gss_error(res->status, res->minor_status, "add_cred");
703 
704 	/*
705 	 * convert the output args from the parameter given in the call to the
706 	 * variable in the XDR result
707 	 */
708 	if (actual_mechs != GSS_C_NULL_OID_SET) {
709 		res->actual_mechs.GSS_OID_SET_len =
710 			(uint_t)actual_mechs->count;
711 		res->actual_mechs.GSS_OID_SET_val = (GSS_OID *)
712 			malloc(sizeof (GSS_OID) * actual_mechs->count);
713 		if (!res->actual_mechs.GSS_OID_SET_val) {
714 			free(desired_mech_type->elements);
715 			free(desired_mech_type);
716 			return (GSS_S_FAILURE);
717 		}
718 		for (i = 0; i < actual_mechs->count; i++) {
719 			res->actual_mechs.GSS_OID_SET_val[i].GSS_OID_len =
720 				(uint_t)actual_mechs->elements[i].length;
721 			res->actual_mechs.GSS_OID_SET_val[i].GSS_OID_val =
722 				(char *)malloc(actual_mechs->elements[i].
723 						length);
724 			if (!res->actual_mechs.GSS_OID_SET_val[i].GSS_OID_val) {
725 				free(desired_mech_type->elements);
726 				free(desired_mech_type);
727 				free(res->actual_mechs.GSS_OID_SET_val);
728 				for (j = 0; j < (i - 1); j++) {
729 					free
730 					(res->actual_mechs.
731 						GSS_OID_SET_val[j].GSS_OID_val);
732 				}
733 				return (GSS_S_FAILURE);
734 			}
735 			memcpy(res->actual_mechs.GSS_OID_SET_val[i].GSS_OID_val,
736 				actual_mechs->elements[i].elements,
737 				actual_mechs->elements[i].length);
738 		}
739 	} else
740 		res->actual_mechs.GSS_OID_SET_len = 0;
741 
742 	/*
743 	 * now release the space allocated for
744 	 * desired_name  and desired_mech_type
745 	 */
746 
747 	gss_release_name(&minor_status, &desired_name);
748 	free(desired_mech_type->elements);
749 	gss_release_oid_set(&minor_status, &actual_mechs);
750 	/*
751 	 * if (actual_mechs != GSS_C_NULL_OID_SET) {
752 	 * 	for (i = 0; i < actual_mechs->count; i++)
753 	 * 		free(actual_mechs->elements[i].elements);
754 	 * 	free(actual_mechs->elements);
755 	 * 	free(actual_mechs);
756 	 * }
757 	 */
758 
759 
760 /* return to caller */
761 
762 	return (TRUE);
763 }
764 
765 bool_t
766 gss_release_cred_1_svc(argp, res, rqstp)
767 gss_release_cred_arg *argp;
768 gss_release_cred_res *res;
769 struct svc_req *rqstp;
770 {
771 
772 	uid_t uid;
773 	gss_cred_id_t cred_handle;
774 
775 	memset(res, 0, sizeof (*res));
776 
777 	if (gssd_debug)
778 		fprintf(stderr, gettext("gss_release_cred\n"));
779 
780 	if (checkfrom(rqstp, &uid) == 0)
781 		return (FALSE);
782 
783 	/* set the uid sent as the RPC argument */
784 
785 	uid = argp->uid;
786 	set_gssd_uid(uid);
787 
788 	/*
789 	 * if the cred_handle verifier is not correct,
790 	 * set status to GSS_S_DEFECTIVE_CREDENTIAL and return
791 	 */
792 
793 	if (argp->gssd_cred_verifier != gssd_time_verf) {
794 		res->status = (OM_uint32)GSS_S_DEFECTIVE_CREDENTIAL;
795 		return (TRUE);
796 	}
797 
798 	/*
799 	 * if the cred_handle length is 0
800 	 * set cred_handle argument to GSS_S_NO_CREDENTIAL
801 	 */
802 
803 	if (argp->cred_handle.GSS_CRED_ID_T_len == 0)
804 		cred_handle = GSS_C_NO_CREDENTIAL;
805 	else
806 		cred_handle =
807 		(gss_cred_id_t)argp->cred_handle.GSS_CRED_ID_T_val;
808 
809 	/* call the gssapi routine */
810 
811 	res->status = (OM_uint32)gss_release_cred(&res->minor_status,
812 					&cred_handle);
813 
814 	/* return to caller */
815 
816 	return (TRUE);
817 }
818 
819 bool_t
820 gss_init_sec_context_1_svc(argp, res, rqstp)
821 gss_init_sec_context_arg *argp;
822 gss_init_sec_context_res *res;
823 struct svc_req *rqstp;
824 {
825 
826 	OM_uint32 	minor_status;
827 	gss_ctx_id_t	context_handle;
828 	bool_t context_verf_ok;
829 	gss_cred_id_t	claimant_cred_handle;
830 	gss_buffer_desc	external_name;
831 	gss_OID_desc	name_type_desc;
832 	gss_OID		name_type = &name_type_desc;
833 	gss_name_t	internal_name;
834 
835 	gss_OID_desc	mech_type_desc;
836 	gss_OID		mech_type = &mech_type_desc;
837 	struct gss_channel_bindings_struct
838 			input_chan_bindings;
839 	gss_channel_bindings_t input_chan_bindings_ptr;
840 	gss_buffer_desc input_token;
841 	gss_buffer_desc output_token;
842 	gss_buffer_t input_token_ptr;
843 	gss_OID actual_mech_type;
844 	struct gssd_ctx_slot *slot = NULL;
845 
846 	uid_t uid;
847 
848 	memset(res, 0, sizeof (*res));
849 
850 	if (gssd_debug)
851 		fprintf(stderr, gettext("gss_init_sec_context\n"));
852 
853 	/*
854 	 * if the request isn't from root, null out the result pointer
855 	 * entries, so the next time through xdr_free won't try to
856 	 * free unmalloc'd memory and then return NULL
857 	 */
858 
859 	if (checkfrom(rqstp, &uid) == 0) {
860 		res->context_handle.GSS_CTX_ID_T_val =  NULL;
861 		res->actual_mech_type.GSS_OID_val = NULL;
862 		res->output_token.GSS_BUFFER_T_val = NULL;
863 		return (FALSE);
864 	}
865 
866 /* set the uid sent as the RPC argument */
867 
868 	uid = argp->uid;
869 	set_gssd_uid(uid);
870 
871 /*
872  * copy the supplied context handle into the local context handle, so it
873  * can be supplied to the gss_init_sec_context call
874  */
875 
876 	gssd_convert_context_handle(&argp->context_handle, &context_handle,
877 		argp->gssd_context_verifier, &context_verf_ok, &slot);
878 
879 	claimant_cred_handle =
880 		(argp->claimant_cred_handle.GSS_CRED_ID_T_len == 0 ?
881 		GSS_C_NO_CREDENTIAL :
882 		/*LINTED*/
883 		*((gss_cred_id_t *)argp->claimant_cred_handle.
884 			GSS_CRED_ID_T_val));
885 
886 	if (claimant_cred_handle != GSS_C_NO_CREDENTIAL) {
887 		/* verify the verifier_cred_handle */
888 		if (argp->gssd_cred_verifier != gssd_time_verf) {
889 			res->context_handle.GSS_CTX_ID_T_val = NULL;
890 			res->output_token.GSS_BUFFER_T_val = NULL;
891 			res->actual_mech_type.GSS_OID_val = NULL;
892 			res->context_handle.GSS_CTX_ID_T_len = 0;
893 			res->output_token.GSS_BUFFER_T_len = 0;
894 			res->actual_mech_type.GSS_OID_len = 0;
895 			res->status = (OM_uint32)GSS_S_DEFECTIVE_CREDENTIAL;
896 			res->minor_status = 0;
897 			return (TRUE);
898 		}
899 	}
900 
901 	if (context_handle != GSS_C_NO_CONTEXT) {
902 		/* verify the verifier_context_handle */
903 
904 		if (!context_verf_ok) {
905 			res->context_handle.GSS_CTX_ID_T_val = NULL;
906 			res->output_token.GSS_BUFFER_T_val = NULL;
907 			res->actual_mech_type.GSS_OID_val = NULL;
908 			res->context_handle.GSS_CTX_ID_T_len = 0;
909 			res->output_token.GSS_BUFFER_T_len = 0;
910 			res->actual_mech_type.GSS_OID_len = 0;
911 			res->status = (OM_uint32)GSS_S_NO_CONTEXT;
912 			res->minor_status = 0;
913 			return (TRUE);
914 		}
915 	}
916 
917 	/* convert the target name from external to internal format */
918 
919 	external_name.length = argp->target_name.GSS_BUFFER_T_len;
920 	external_name.value = (void *)argp->target_name.GSS_BUFFER_T_val;
921 
922 	if (argp->name_type.GSS_OID_len == 0) {
923 		name_type = GSS_C_NULL_OID;
924 	} else {
925 		name_type->length = argp->name_type.GSS_OID_len;
926 		name_type->elements = (void *)malloc(name_type->length);
927 		if (!name_type->elements)
928 			return (GSS_S_FAILURE);
929 		memcpy(name_type->elements, argp->name_type.GSS_OID_val,
930 			name_type->length);
931 	}
932 
933 	if (argp->mech_type.GSS_OID_len == 0)
934 		mech_type = GSS_C_NULL_OID;
935 	else {
936 		mech_type->length = (OM_uint32)argp->mech_type.GSS_OID_len;
937 		mech_type->elements = (void *)argp->mech_type.GSS_OID_val;
938 	}
939 
940 	if (gss_import_name(&minor_status, &external_name, name_type,
941 			    &internal_name) != GSS_S_COMPLETE) {
942 
943 		if (name_type != GSS_C_NULL_OID)
944 			free(name_type->elements);
945 		res->status = (OM_uint32)GSS_S_FAILURE;
946 		res->minor_status = minor_status;
947 
948 		return (TRUE);
949 	}
950 /*
951  * copy the XDR structured arguments into their corresponding local GSSAPI
952  * variables.
953  */
954 
955 	if (argp->input_chan_bindings.present == YES) {
956 		input_chan_bindings_ptr = &input_chan_bindings;
957 		input_chan_bindings.initiator_addrtype =
958 			(OM_uint32)argp->input_chan_bindings.
959 			initiator_addrtype;
960 		input_chan_bindings.initiator_address.length =
961 			(uint_t)argp->input_chan_bindings.initiator_address.
962 			GSS_BUFFER_T_len;
963 		input_chan_bindings.initiator_address.value =
964 			(void *)argp->input_chan_bindings.initiator_address.
965 			GSS_BUFFER_T_val;
966 		input_chan_bindings.acceptor_addrtype =
967 			(OM_uint32)argp->input_chan_bindings.acceptor_addrtype;
968 		input_chan_bindings.acceptor_address.length =
969 			(uint_t)argp->input_chan_bindings.acceptor_address.
970 			GSS_BUFFER_T_len;
971 		input_chan_bindings.acceptor_address.value =
972 			(void *)argp->input_chan_bindings.acceptor_address.
973 			GSS_BUFFER_T_val;
974 		input_chan_bindings.application_data.length =
975 			(uint_t)argp->input_chan_bindings.application_data.
976 			GSS_BUFFER_T_len;
977 		input_chan_bindings.application_data.value =
978 			(void *)argp->input_chan_bindings.application_data.
979 			GSS_BUFFER_T_val;
980 	} else {
981 		input_chan_bindings_ptr = GSS_C_NO_CHANNEL_BINDINGS;
982 		input_chan_bindings.initiator_addrtype = 0;
983 		input_chan_bindings.initiator_address.length = 0;
984 		input_chan_bindings.initiator_address.value = 0;
985 		input_chan_bindings.acceptor_addrtype = 0;
986 		input_chan_bindings.acceptor_address.length = 0;
987 		input_chan_bindings.acceptor_address.value = 0;
988 		input_chan_bindings.application_data.length = 0;
989 		input_chan_bindings.application_data.value = 0;
990 	}
991 
992 	if (argp->input_token.GSS_BUFFER_T_len == 0) {
993 		input_token_ptr = GSS_C_NO_BUFFER;
994 	} else {
995 		input_token_ptr = &input_token;
996 		input_token.length = (size_t)
997 				argp->input_token.GSS_BUFFER_T_len;
998 		input_token.value = (void *)argp->input_token.GSS_BUFFER_T_val;
999 	}
1000 
1001 /* call the gssapi routine */
1002 
1003 	res->status = (OM_uint32)gss_init_sec_context(&res->minor_status,
1004 			(gss_cred_id_t)argp->claimant_cred_handle.
1005 						GSS_CRED_ID_T_val,
1006 					&context_handle,
1007 					internal_name,
1008 					mech_type,
1009 					argp->req_flags,
1010 					argp->time_req,
1011 					input_chan_bindings_ptr,
1012 					input_token_ptr,
1013 					&actual_mech_type,
1014 					&output_token,
1015 					&res->ret_flags,
1016 					&res->time_rec);
1017 
1018 	/*
1019 	 * convert the output args from the parameter given in the call to the
1020 	 * variable in the XDR result
1021 	 */
1022 
1023 	if (res->status == (OM_uint32)GSS_S_COMPLETE ||
1024 		res->status == (OM_uint32)GSS_S_CONTINUE_NEEDED) {
1025 
1026 		if (slot == NULL || slot->ctx != context_handle) {
1027 			/*
1028 			 * Note that gssd_alloc_slot() will delete ctx's as long
1029 			 * as we don't call gssd_rel_slot().
1030 			 */
1031 			slot = gssd_alloc_slot(context_handle);
1032 		}
1033 
1034 		res->gssd_context_verifier = slot->verf;
1035 
1036 		res->context_handle.GSS_CTX_ID_T_len = sizeof (gss_ctx_id_t);
1037 		res->context_handle.GSS_CTX_ID_T_val =
1038 			(void *)malloc(sizeof (gss_ctx_id_t));
1039 		if (!res->context_handle.GSS_CTX_ID_T_val) {
1040 			free(name_type->elements);
1041 			return (GSS_S_FAILURE);
1042 		}
1043 
1044 		memcpy(res->context_handle.GSS_CTX_ID_T_val, &slot->rpcctx,
1045 			sizeof (gss_ctx_id_t));
1046 
1047 		res->output_token.GSS_BUFFER_T_len =
1048 			(uint_t)output_token.length;
1049 		res->output_token.GSS_BUFFER_T_val =
1050 			(char *)output_token.value;
1051 
1052 		/*
1053 		 * the actual mech type parameter
1054 		 * is ready only upon GSS_S_COMPLETE
1055 		 */
1056 		if (res->status == GSS_S_COMPLETE) {
1057 			res->actual_mech_type.GSS_OID_len =
1058 				(uint_t)actual_mech_type->length;
1059 			res->actual_mech_type.GSS_OID_val =
1060 				(void *)malloc(actual_mech_type->length);
1061 			if (!res->actual_mech_type.GSS_OID_val) {
1062 				free(name_type->elements);
1063 				free(res->context_handle.GSS_CTX_ID_T_val);
1064 				return (GSS_S_FAILURE);
1065 			}
1066 			memcpy(res->actual_mech_type.GSS_OID_val,
1067 				(char *)actual_mech_type->elements,
1068 				actual_mech_type->length);
1069 		} else
1070 			res->actual_mech_type.GSS_OID_len = 0;
1071 	} else {
1072 		syslog_gss_error(res->status, res->minor_status,
1073 			    "init_sec_context");
1074 		if (context_handle != GSS_C_NO_CONTEXT) {
1075 			(void) gss_delete_sec_context(&minor_status,
1076 				&context_handle, NULL);
1077 		}
1078 		res->context_handle.GSS_CTX_ID_T_len = 0;
1079 		res->actual_mech_type.GSS_OID_len = 0;
1080 		res->output_token.GSS_BUFFER_T_len = 0;
1081 	}
1082 
1083 	/*
1084 	 * now release the space allocated by the underlying gssapi mechanism
1085 	 * library for internal_name and for the name_type.
1086 	 */
1087 
1088 	gss_release_name(&minor_status, &internal_name);
1089 	if (name_type != GSS_C_NULL_OID)
1090 		free(name_type->elements);
1091 
1092 
1093 	/* return to caller */
1094 	return (TRUE);
1095 }
1096 
1097 bool_t
1098 gss_accept_sec_context_1_svc(argp, res, rqstp)
1099 gss_accept_sec_context_arg *argp;
1100 gss_accept_sec_context_res *res;
1101 struct svc_req *rqstp;
1102 {
1103 	uid_t uid;
1104 	OM_uint32 minor_status;
1105 	gss_ctx_id_t context_handle = NULL;
1106 	gss_cred_id_t verifier_cred_handle;
1107 	gss_buffer_desc external_name;
1108 	gss_name_t internal_name = NULL;
1109 
1110 	gss_buffer_desc input_token_buffer;
1111 	gss_buffer_t input_token_buffer_ptr;
1112 	struct gss_channel_bindings_struct
1113 			input_chan_bindings;
1114 	gss_channel_bindings_t input_chan_bindings_ptr;
1115 	gss_OID mech_type;
1116 	gss_buffer_desc output_token;
1117 	gss_cred_id_t delegated_cred_handle;
1118 	bool_t context_verf_ok;
1119 	struct gssd_ctx_slot *slot = NULL;
1120 
1121 	memset(res, 0, sizeof (*res));
1122 
1123 	if (gssd_debug)
1124 		fprintf(stderr, gettext("gss_accept_sec_context\n"));
1125 
1126 	/*
1127 	 * if the request isn't from root, null out the result pointer
1128 	 * entries, so the next time through xdr_free won't try to
1129 	 * free unmalloc'd memory and then return NULL
1130 	 */
1131 
1132 	if (checkfrom(rqstp, &uid) == 0) {
1133 		res->context_handle.GSS_CTX_ID_T_val = NULL;
1134 		res->src_name.GSS_BUFFER_T_val = NULL;
1135 		res->mech_type.GSS_OID_val = NULL;
1136 		res->output_token.GSS_BUFFER_T_val = NULL;
1137 		res->delegated_cred_handle.GSS_CRED_ID_T_val = NULL;
1138 		return (FALSE);
1139 	}
1140 
1141 	/* set the uid sent as the RPC argument */
1142 
1143 	uid = argp->uid;
1144 	set_gssd_uid(uid);
1145 
1146 	/*
1147 	 * copy the supplied context handle into the local context handle, so
1148 	 * it can be supplied to the gss_accept_sec_context call
1149 	 */
1150 
1151 	gssd_convert_context_handle(&argp->context_handle, &context_handle,
1152 		argp->gssd_context_verifier, &context_verf_ok, &slot);
1153 
1154 	if (context_handle != GSS_C_NO_CONTEXT)
1155 		/* verify the context_handle */
1156 		if (!context_verf_ok) {
1157 			res->context_handle.GSS_CTX_ID_T_val = NULL;
1158 			res->src_name.GSS_BUFFER_T_val = NULL;
1159 			res->mech_type.GSS_OID_val = NULL;
1160 			res->output_token.GSS_BUFFER_T_val = NULL;
1161 			res->delegated_cred_handle.GSS_CRED_ID_T_val = NULL;
1162 			res->src_name.GSS_BUFFER_T_len = 0;
1163 			res->context_handle.GSS_CTX_ID_T_len = 0;
1164 			res->delegated_cred_handle.GSS_CRED_ID_T_len = 0;
1165 			res->output_token.GSS_BUFFER_T_len = 0;
1166 			res->mech_type.GSS_OID_len = 0;
1167 			res->status = (OM_uint32)GSS_S_NO_CONTEXT;
1168 			res->minor_status = 0;
1169 			return (TRUE);
1170 		}
1171 
1172 	/*
1173 	 * copy the XDR structured arguments into their corresponding local
1174 	 * GSSAPI variable equivalents.
1175 	 */
1176 
1177 
1178 	verifier_cred_handle =
1179 		(argp->verifier_cred_handle.GSS_CRED_ID_T_len == 0 ?
1180 			GSS_C_NO_CREDENTIAL :
1181 			/*LINTED*/
1182 			*((gss_cred_id_t *)argp->verifier_cred_handle.
1183 				GSS_CRED_ID_T_val));
1184 
1185 	if (verifier_cred_handle != GSS_C_NO_CREDENTIAL)
1186 	/* verify the verifier_cred_handle */
1187 		if (argp->gssd_cred_verifier != gssd_time_verf) {
1188 			res->context_handle.GSS_CTX_ID_T_val = NULL;
1189 			res->src_name.GSS_BUFFER_T_val = NULL;
1190 			res->mech_type.GSS_OID_val = NULL;
1191 			res->output_token.GSS_BUFFER_T_val = NULL;
1192 			res->delegated_cred_handle.GSS_CRED_ID_T_val = NULL;
1193 			res->src_name.GSS_BUFFER_T_len = 0;
1194 			res->context_handle.GSS_CTX_ID_T_len = 0;
1195 			res->delegated_cred_handle.GSS_CRED_ID_T_len = 0;
1196 			res->output_token.GSS_BUFFER_T_len = 0;
1197 			res->mech_type.GSS_OID_len = 0;
1198 			res->status = (OM_uint32)GSS_S_DEFECTIVE_CREDENTIAL;
1199 			res->minor_status = 0;
1200 			return (TRUE);
1201 		}
1202 
1203 	input_token_buffer_ptr = &input_token_buffer;
1204 	input_token_buffer.length = (size_t)argp->input_token_buffer.
1205 		GSS_BUFFER_T_len;
1206 	input_token_buffer.value = (void *)argp->input_token_buffer.
1207 		GSS_BUFFER_T_val;
1208 
1209 	if (argp->input_chan_bindings.present == YES) {
1210 		input_chan_bindings_ptr = &input_chan_bindings;
1211 		input_chan_bindings.initiator_addrtype =
1212 			(OM_uint32)argp->input_chan_bindings.
1213 					initiator_addrtype;
1214 		input_chan_bindings.initiator_address.length =
1215 			(uint_t)argp->input_chan_bindings.initiator_address.
1216 					GSS_BUFFER_T_len;
1217 		input_chan_bindings.initiator_address.value =
1218 			(void *)argp->input_chan_bindings.initiator_address.
1219 					GSS_BUFFER_T_val;
1220 		input_chan_bindings.acceptor_addrtype =
1221 			(OM_uint32)argp->input_chan_bindings.
1222 					acceptor_addrtype;
1223 		input_chan_bindings.acceptor_address.length =
1224 			(uint_t)argp->input_chan_bindings.acceptor_address.
1225 					GSS_BUFFER_T_len;
1226 		input_chan_bindings.acceptor_address.value =
1227 			(void *)argp->input_chan_bindings.acceptor_address.
1228 					GSS_BUFFER_T_val;
1229 		input_chan_bindings.application_data.length =
1230 			(uint_t)argp->input_chan_bindings.application_data.
1231 					GSS_BUFFER_T_len;
1232 		input_chan_bindings.application_data.value =
1233 			(void *)argp->input_chan_bindings.application_data.
1234 					GSS_BUFFER_T_val;
1235 	} else {
1236 		input_chan_bindings_ptr = GSS_C_NO_CHANNEL_BINDINGS;
1237 		input_chan_bindings.initiator_addrtype = 0;
1238 		input_chan_bindings.initiator_address.length = 0;
1239 		input_chan_bindings.initiator_address.value = 0;
1240 		input_chan_bindings.acceptor_addrtype = 0;
1241 		input_chan_bindings.acceptor_address.length = 0;
1242 		input_chan_bindings.acceptor_address.value = 0;
1243 		input_chan_bindings.application_data.length = 0;
1244 		input_chan_bindings.application_data.value = 0;
1245 	}
1246 
1247 
1248 	/* call the gssapi routine */
1249 
1250 	res->status = (OM_uint32)gss_accept_sec_context(&res->minor_status,
1251 						&context_handle,
1252 						verifier_cred_handle,
1253 						input_token_buffer_ptr,
1254 						input_chan_bindings_ptr,
1255 						&internal_name,
1256 						&mech_type,
1257 						&output_token,
1258 						&res->ret_flags,
1259 						&res->time_rec,
1260 						&delegated_cred_handle);
1261 
1262 	/* convert the src name from internal to external format */
1263 
1264 	if (res->status == (OM_uint32)GSS_S_COMPLETE ||
1265 		res->status == (OM_uint32)GSS_S_CONTINUE_NEEDED) {
1266 
1267 		/*
1268 		 * upon GSS_S_CONTINUE_NEEDED only the following
1269 		 * parameters are ready: minor, ctxt, and output token
1270 		 */
1271 		res->context_handle.GSS_CTX_ID_T_len = sizeof (gss_ctx_id_t);
1272 		res->context_handle.GSS_CTX_ID_T_val =
1273 			(void *)malloc(sizeof (gss_ctx_id_t));
1274 		if (!res->context_handle.GSS_CTX_ID_T_val) {
1275 			res->status = (OM_uint32)GSS_S_FAILURE;
1276 			res->minor_status = 0;
1277 			return (TRUE);
1278 		}
1279 
1280 		if (slot == NULL || slot->ctx != context_handle) {
1281 			/*
1282 			 * Note that gssd_alloc_slot() will delete ctx's as long
1283 			 * as we don't call gssd_rel_slot().
1284 			 */
1285 			slot = gssd_alloc_slot(context_handle);
1286 		}
1287 
1288 		memcpy(res->context_handle.GSS_CTX_ID_T_val, &slot->rpcctx,
1289 			sizeof (gss_ctx_id_t));
1290 		res->gssd_context_verifier = slot->verf;
1291 
1292 		res->output_token.GSS_BUFFER_T_len =
1293 				(uint_t)output_token.length;
1294 		res->output_token.GSS_BUFFER_T_val =
1295 				(char *)output_token.value;
1296 
1297 		if (res->status == GSS_S_COMPLETE) {
1298 			if (gss_export_name(&minor_status, internal_name,
1299 					&external_name)
1300 				!= GSS_S_COMPLETE) {
1301 
1302 				res->status = (OM_uint32)GSS_S_FAILURE;
1303 				res->minor_status = minor_status;
1304 				gss_release_name(&minor_status, &internal_name);
1305 				gss_delete_sec_context(&minor_status,
1306 						&context_handle, NULL);
1307 				free(res->context_handle.GSS_CTX_ID_T_val);
1308 				res->context_handle.GSS_CTX_ID_T_val = NULL;
1309 				res->context_handle.GSS_CTX_ID_T_len = 0;
1310 				gss_release_buffer(&minor_status,
1311 						&output_token);
1312 				res->output_token.GSS_BUFFER_T_len = 0;
1313 				res->output_token.GSS_BUFFER_T_val = NULL;
1314 				return (TRUE);
1315 			}
1316 			res->src_name.GSS_BUFFER_T_len =
1317 				(uint_t)external_name.length;
1318 			res->src_name.GSS_BUFFER_T_val =
1319 				(void *)external_name.value;
1320 
1321 			res->delegated_cred_handle.GSS_CRED_ID_T_len =
1322 				sizeof (gss_cred_id_t);
1323 			res->delegated_cred_handle.GSS_CRED_ID_T_val =
1324 				(void *)malloc(sizeof (gss_cred_id_t));
1325 			if (!res->delegated_cred_handle.GSS_CRED_ID_T_val) {
1326 				free(res->context_handle.GSS_CTX_ID_T_val);
1327 				gss_release_name(&minor_status, &internal_name);
1328 				gss_delete_sec_context(&minor_status,
1329 						&context_handle, NULL);
1330 				gss_release_buffer(&minor_status,
1331 						&external_name);
1332 				res->status = (OM_uint32)GSS_S_FAILURE;
1333 				res->minor_status = 0;
1334 				return (TRUE);
1335 			}
1336 			memcpy(res->delegated_cred_handle.GSS_CRED_ID_T_val,
1337 				&delegated_cred_handle,
1338 				sizeof (gss_cred_id_t));
1339 
1340 			res->mech_type.GSS_OID_len = (uint_t)mech_type->length;
1341 			res->mech_type.GSS_OID_val =
1342 				(void *)malloc(mech_type->length);
1343 			if (!res->mech_type.GSS_OID_val) {
1344 			    free(res->context_handle.GSS_CTX_ID_T_val);
1345 			    free(res->delegated_cred_handle.GSS_CRED_ID_T_val);
1346 			    gss_release_name(&minor_status, &internal_name);
1347 			    gss_delete_sec_context(&minor_status,
1348 						&context_handle, NULL);
1349 			    gss_release_buffer(&minor_status, &external_name);
1350 			    res->status = (OM_uint32)GSS_S_FAILURE;
1351 			    res->minor_status = 0;
1352 			    return (TRUE);
1353 			}
1354 			memcpy(res->mech_type.GSS_OID_val, mech_type->elements,
1355 				mech_type->length);
1356 
1357 			/* release the space allocated for internal_name */
1358 			gss_release_name(&minor_status, &internal_name);
1359 
1360 		} else {    /* GSS_S_CONTINUE_NEEDED */
1361 			res->src_name.GSS_BUFFER_T_len = 0;
1362 			res->delegated_cred_handle.GSS_CRED_ID_T_len = 0;
1363 			res->mech_type.GSS_OID_len = 0;
1364 		}
1365 	} else {
1366 		syslog_gss_error(res->status, res->minor_status,
1367 			    "accept_sec_context");
1368 
1369 		if (context_handle != GSS_C_NO_CONTEXT) {
1370 			(void) gss_delete_sec_context(&minor_status,
1371 				&context_handle, NULL);
1372 		}
1373 		res->src_name.GSS_BUFFER_T_len = 0;
1374 		res->context_handle.GSS_CTX_ID_T_len = 0;
1375                 res->delegated_cred_handle.GSS_CRED_ID_T_len = 0;
1376                 res->output_token.GSS_BUFFER_T_len =
1377 			(uint_t)output_token.length;
1378                 res->output_token.GSS_BUFFER_T_val =
1379 			(char *)output_token.value;
1380 
1381                 res->mech_type.GSS_OID_len = 0;
1382 	}
1383 
1384 /* return to caller */
1385 
1386 	return (TRUE);
1387 }
1388 
1389 bool_t
1390 gss_process_context_token_1_svc(argp, res, rqstp)
1391 gss_process_context_token_arg *argp;
1392 gss_process_context_token_res *res;
1393 struct svc_req *rqstp;
1394 {
1395 
1396 	uid_t uid;
1397 	gss_buffer_desc token_buffer;
1398 	gss_ctx_id_t context_handle;
1399 	bool_t context_verf_ok;
1400 
1401 	memset(res, 0, sizeof (*res));
1402 
1403 	if (gssd_debug)
1404 		fprintf(stderr, gettext("gss_process_context_token\n"));
1405 
1406 	if (checkfrom(rqstp, &uid) == 0)
1407 		return (FALSE);
1408 
1409 	gssd_convert_context_handle(&argp->context_handle, &context_handle,
1410 		argp->gssd_context_verifier, &context_verf_ok, NULL);
1411 
1412 	/* verify the context_handle */
1413 
1414 	if (!context_verf_ok) {
1415 		res->status = (OM_uint32) GSS_S_NO_CONTEXT;
1416 		res->minor_status = 0;
1417 		return (TRUE);
1418 	}
1419 
1420 	/* set the uid sent as the RPC argument */
1421 
1422 	uid = argp->uid;
1423 	set_gssd_uid(uid);
1424 
1425 	/*
1426 	 * copy the XDR structured arguments into their corresponding local
1427 	 * GSSAPI variable equivalents.
1428 	 */
1429 
1430 	token_buffer.length = (size_t)argp->token_buffer.GSS_BUFFER_T_len;
1431 	token_buffer.value = (void *)argp->token_buffer.GSS_BUFFER_T_val;
1432 
1433 
1434 	/* call the gssapi routine */
1435 
1436 	res->status = (OM_uint32)gss_process_context_token(&res->minor_status,
1437 				context_handle,
1438 				&token_buffer);
1439 
1440 	if (GSS_ERROR(res->status))
1441 		syslog_gss_error(res->status, res->minor_status,
1442 			    "process_context_token");
1443 
1444 	/* return to caller */
1445 
1446 	return (TRUE);
1447 }
1448 
1449 bool_t
1450 gss_delete_sec_context_1_svc(argp, res, rqstp)
1451 gss_delete_sec_context_arg *argp;
1452 gss_delete_sec_context_res *res;
1453 struct svc_req *rqstp;
1454 {
1455 	uid_t uid;
1456 	gss_ctx_id_t  context_handle;
1457 	gss_buffer_desc output_token;
1458 	bool_t context_verf_ok;
1459 	struct gssd_ctx_slot *slot = NULL;
1460 
1461 	memset(res, 0, sizeof (*res));
1462 
1463 	if (gssd_debug)
1464 		fprintf(stderr, gettext("gss_delete_sec_context\n"));
1465 
1466 
1467 	/*
1468 	 * copy the supplied context handle into the local context handle, so it
1469 	 * can be supplied to the gss_delete_sec_context call
1470 	 */
1471 	gssd_convert_context_handle(&argp->context_handle, &context_handle,
1472 		argp->gssd_context_verifier, &context_verf_ok, &slot);
1473 
1474 	/* verify the context_handle */
1475 	if (!context_verf_ok) {
1476 		res->context_handle.GSS_CTX_ID_T_val = NULL;
1477 		res->context_handle.GSS_CTX_ID_T_len = 0;
1478 		res->output_token.GSS_BUFFER_T_val = NULL;
1479 		res->output_token.GSS_BUFFER_T_len = 0;
1480 		res->status = (OM_uint32)GSS_S_NO_CONTEXT;
1481 		res->minor_status = 0;
1482 		return (TRUE);
1483 	}
1484 
1485 	/*
1486 	 * if the request isn't from root, null out the result pointer
1487 	 * entries, so the next time through xdr_free won't try to
1488 	 * free unmalloc'd memory and then return NULL
1489 	 */
1490 
1491 	if (checkfrom(rqstp, &uid) == 0) {
1492 		res->context_handle.GSS_CTX_ID_T_val = NULL;
1493 		res->output_token.GSS_BUFFER_T_val = NULL;
1494 		return (FALSE);
1495 	}
1496 
1497 	/* call the gssapi routine */
1498 
1499 	res->status = (OM_uint32)gss_delete_sec_context(&res->minor_status,
1500 						&context_handle,
1501 						&output_token);
1502 
1503 	/*
1504 	 * convert the output args from the parameter given in the call to the
1505 	 * variable in the XDR result. If the delete succeeded, return a zero
1506 	 * context handle.
1507 	 */
1508 
1509 	if (res->status == GSS_S_COMPLETE) {
1510 		if (context_handle != GSS_C_NO_CONTEXT)
1511 			return (GSS_S_FAILURE);
1512 		res->context_handle.GSS_CTX_ID_T_len = 0;
1513 		res->context_handle.GSS_CTX_ID_T_val = NULL;
1514 		res->output_token.GSS_BUFFER_T_len =
1515 			(uint_t)output_token.length;
1516 		res->output_token.GSS_BUFFER_T_val =
1517 			(char *)output_token.value;
1518 
1519 		if (slot != NULL) {
1520 			/*
1521 			 * gss_delete_sec_context deletes the context if it
1522 			 * succeeds so clear slot->ctx to avoid a dangling
1523 			 * reference.
1524 			 */
1525 			slot->ctx = GSS_C_NO_CONTEXT;
1526 			gssd_rel_slot(slot);
1527 		}
1528 	} else {
1529 		res->context_handle.GSS_CTX_ID_T_len = sizeof (gss_ctx_id_t);
1530 		res->context_handle.GSS_CTX_ID_T_val =
1531 			(void *)malloc(sizeof (gss_ctx_id_t));
1532 		if (!res->context_handle.GSS_CTX_ID_T_val) {
1533 			return (GSS_S_FAILURE);
1534 		}
1535 
1536 		if (slot == NULL || slot->ctx != context_handle) {
1537 			/*
1538 			 * Note that gssd_alloc_slot() will delete ctx's as long
1539 			 * as we don't call gssd_rel_slot().
1540 			 */
1541 			slot = gssd_alloc_slot(context_handle);
1542 			/*
1543 			 * Note that no verifier is returned in the .x
1544 			 * protocol. So if the context changes, we won't
1545 			 * be able to release it now. So it will have to
1546 			 * be LRUed out.
1547 			 */
1548 		}
1549 
1550 		memcpy(res->context_handle.GSS_CTX_ID_T_val, &slot->rpcctx,
1551 			sizeof (gss_ctx_id_t));
1552 
1553 		res->output_token.GSS_BUFFER_T_len = 0;
1554 		res->output_token.GSS_BUFFER_T_val = NULL;
1555 	}
1556 
1557 	/* return to caller */
1558 
1559 
1560 	return (TRUE);
1561 }
1562 
1563 
1564 bool_t
1565 gss_export_sec_context_1_svc(argp, res, rqstp)
1566 	gss_export_sec_context_arg *argp;
1567 	gss_export_sec_context_res *res;
1568 	struct svc_req *rqstp;
1569 {
1570 
1571 	uid_t		uid;
1572 	gss_ctx_id_t	context_handle;
1573 	gss_buffer_desc	output_token;
1574 	bool_t		context_verf_ok;
1575 	struct gssd_ctx_slot *slot = NULL;
1576 
1577 	memset(res, 0, sizeof (*res));
1578 
1579 	if (gssd_debug)
1580 		fprintf(stderr, "gss_export_sec_context\n");
1581 
1582 	/*
1583 	 * if the request isn't from root, null out the result pointer
1584 	 * entries, so the next time through xdr_free won't try to
1585 	 * free unmalloc'd memory and then return NULL
1586 	 */
1587 
1588 	if (checkfrom(rqstp, &uid) == 0) {
1589 		res->context_handle.GSS_CTX_ID_T_val = NULL;
1590 		res->output_token.GSS_BUFFER_T_val = NULL;
1591 		return (FALSE);
1592 	}
1593 
1594 /*
1595  * copy the supplied context handle into the local context handle, so it
1596  * can be supplied to the gss_export_sec_context call
1597  */
1598 
1599 	gssd_convert_context_handle(&argp->context_handle, &context_handle,
1600 		argp->gssd_context_verifier, &context_verf_ok, &slot);
1601 
1602 	/* verify the context_handle */
1603 
1604 	if (!context_verf_ok) {
1605 		res->status = (OM_uint32)GSS_S_NO_CONTEXT;
1606 		/* the rest of "res" was cleared by a previous memset() */
1607 		return (TRUE);
1608 	}
1609 
1610 	/* call the gssapi routine */
1611 
1612 	res->status = (OM_uint32)gss_export_sec_context(&res->minor_status,
1613 					&context_handle,
1614 					&output_token);
1615 
1616 /*
1617  * convert the output args from the parameter given in the call to the
1618  * variable in the XDR result. If the delete succeeded, return a zero context
1619  * handle.
1620  */
1621 	if (res->status == GSS_S_COMPLETE) {
1622 		if (context_handle != GSS_C_NO_CONTEXT)
1623 			return (GSS_S_FAILURE);
1624 		res->context_handle.GSS_CTX_ID_T_len = 0;
1625 		res->context_handle.GSS_CTX_ID_T_val = NULL;
1626 		res->output_token.GSS_BUFFER_T_len =
1627 						(uint_t)output_token.length;
1628 		res->output_token.GSS_BUFFER_T_val =
1629 						(char *)output_token.value;
1630 
1631 		if (slot != NULL) {
1632 			/*
1633 			 * gss_export_sec_context deletes the context if it
1634 			 * succeeds so set slot->ctx to avoid a dangling
1635 			 * reference.
1636 			 */
1637 			slot->ctx = GSS_C_NO_CONTEXT;
1638 			gssd_rel_slot(slot);
1639 		}
1640 	} else {
1641 		res->context_handle.GSS_CTX_ID_T_len = sizeof (gss_ctx_id_t);
1642 		res->context_handle.GSS_CTX_ID_T_val =
1643 					(void *)malloc(sizeof (gss_ctx_id_t));
1644 
1645 		if (slot == NULL || slot->ctx != context_handle) {
1646 			/*
1647 			 * Note that gssd_alloc_slot() will delete ctx's as long
1648 			 * as we don't call gssd_rel_slot().
1649 			 */
1650 			slot = gssd_alloc_slot(context_handle);
1651 			/*
1652 			 * Note that no verifier is returned in the .x
1653 			 * protocol. So if the context changes, we won't
1654 			 * be able to release it now. So it will have to
1655 			 * be LRUed out.
1656 			 */
1657 		}
1658 
1659 		memcpy(res->context_handle.GSS_CTX_ID_T_val, &slot->rpcctx,
1660 			sizeof (gss_ctx_id_t));
1661 		res->output_token.GSS_BUFFER_T_len = 0;
1662 		res->output_token.GSS_BUFFER_T_val = NULL;
1663 	}
1664 
1665 
1666 	/* return to caller */
1667 
1668 	return (TRUE);
1669 }
1670 
1671 /*
1672  * This routine doesn't appear to ever be called.
1673  */
1674 bool_t
1675 gss_import_sec_context_1_svc(argp, res, rqstp)
1676 	gss_import_sec_context_arg *argp;
1677 	gss_import_sec_context_res *res;
1678 	struct svc_req *rqstp;
1679 {
1680 
1681 	uid_t		uid;
1682 	gss_ctx_id_t	context_handle;
1683 	gss_buffer_desc	input_token;
1684 	gss_buffer_t input_token_ptr;
1685 
1686 	memset(res, 0, sizeof (*res));
1687 
1688 	if (gssd_debug)
1689 		fprintf(stderr, "gss_export_sec_context\n");
1690 
1691 	/*
1692 	 * if the request isn't from root, null out the result pointer
1693 	 * entries, so the next time through xdr_free won't try to
1694 	 * free unmalloc'd memory and then return NULL
1695 	 */
1696 
1697 	if (checkfrom(rqstp, &uid) == 0) {
1698 		res->context_handle.GSS_CTX_ID_T_val = NULL;
1699 		return (FALSE);
1700 	}
1701 
1702 
1703 	if (argp->input_token.GSS_BUFFER_T_len == 0) {
1704 		input_token_ptr = GSS_C_NO_BUFFER;
1705 	} else {
1706 		input_token_ptr = &input_token;
1707 		input_token.length = (size_t)
1708 				argp->input_token.GSS_BUFFER_T_len;
1709 		input_token.value = (void *) argp->input_token.GSS_BUFFER_T_val;
1710 	}
1711 
1712 
1713 /* call the gssapi routine */
1714 
1715 	res->status = (OM_uint32) gss_import_sec_context(&res->minor_status,
1716 					input_token_ptr,
1717 					&context_handle);
1718 
1719 /*
1720  * convert the output args from the parameter given in the call to the
1721  * variable in the XDR result. If the delete succeeded, return a zero context
1722  * handle.
1723  */
1724 	if (res->status == GSS_S_COMPLETE) {
1725 		res->context_handle.GSS_CTX_ID_T_len = sizeof (gss_ctx_id_t);
1726 		res->context_handle.GSS_CTX_ID_T_val =
1727 					(void *) malloc(sizeof (gss_ctx_id_t));
1728 		memcpy(res->context_handle.GSS_CTX_ID_T_val, &context_handle,
1729 			sizeof (gss_ctx_id_t));
1730 	} else {
1731 		res->context_handle.GSS_CTX_ID_T_len = 0;
1732 		res->context_handle.GSS_CTX_ID_T_val = NULL;
1733 	}
1734 
1735 
1736 	/* return to caller */
1737 
1738 	return (TRUE);
1739 }
1740 
1741 bool_t
1742 gss_context_time_1_svc(argp, res, rqstp)
1743 gss_context_time_arg *argp;
1744 gss_context_time_res *res;
1745 struct svc_req *rqstp;
1746 {
1747 	uid_t uid;
1748 
1749 	memset(res, 0, sizeof (*res));
1750 
1751 	if (gssd_debug)
1752 		fprintf(stderr, gettext("gss_context_time\n"));
1753 
1754 	/*
1755 	 * if the request isn't from root, null out the result pointer
1756 	 * entries, so the next time through xdr_free won't try to
1757 	 * free unmalloc'd memory and then return NULL
1758 	 */
1759 
1760 	if (checkfrom(rqstp, &uid) == 0)
1761 		return (FALSE);
1762 
1763 	/* set the uid sent as the RPC argument */
1764 
1765 	uid = argp->uid;
1766 	set_gssd_uid(uid);
1767 
1768 	/* Semantics go here */
1769 
1770 	return (TRUE);
1771 }
1772 
1773 bool_t
1774 gss_sign_1_svc(argp, res, rqstp)
1775 gss_sign_arg *argp;
1776 gss_sign_res *res;
1777 struct svc_req *rqstp;
1778 {
1779 
1780 	uid_t uid;
1781 
1782 	gss_buffer_desc message_buffer;
1783 	gss_buffer_desc msg_token;
1784 	gss_ctx_id_t	context_handle;
1785 	bool_t context_verf_ok;
1786 
1787 	memset(res, 0, sizeof (*res));
1788 
1789 	if (gssd_debug)
1790 		fprintf(stderr, gettext("gss_sign\n"));
1791 
1792 	gssd_convert_context_handle(&argp->context_handle, &context_handle,
1793 		argp->gssd_context_verifier, &context_verf_ok, NULL);
1794 
1795 	/* verify the context_handle */
1796 	if (!context_verf_ok) {
1797 		res->msg_token.GSS_BUFFER_T_val = NULL;
1798 		res->msg_token.GSS_BUFFER_T_len = 0;
1799 		res->status = (OM_uint32) GSS_S_NO_CONTEXT;
1800 		res->minor_status = 0;
1801 		return (TRUE);
1802 	}
1803 
1804 
1805 	/*
1806 	 * if the request isn't from root, null out the result pointer
1807 	 * entries, so the next time through xdr_free won't try to
1808 	 * free unmalloc'd memory and then return NULL
1809 	 */
1810 
1811 	if (checkfrom(rqstp, &uid) == 0) {
1812 		res->msg_token.GSS_BUFFER_T_val = NULL;
1813 		return (FALSE);
1814 	}
1815 
1816 	/*
1817 	 * copy the XDR structured arguments into their corresponding local
1818 	 * GSSAPI variable equivalents.
1819 	 */
1820 
1821 	message_buffer.length = (size_t)argp->message_buffer.GSS_BUFFER_T_len;
1822 	message_buffer.value = (void *)argp->message_buffer.GSS_BUFFER_T_val;
1823 
1824 	/* call the gssapi routine */
1825 
1826 	res->status = (OM_uint32)gss_sign(&res->minor_status,
1827 					context_handle,
1828 					argp->qop_req,
1829 					(gss_buffer_t)&message_buffer,
1830 					(gss_buffer_t)&msg_token);
1831 	/*
1832 	 * convert the output args from the parameter given in the call to
1833 	 * the variable in the XDR result
1834 	 */
1835 
1836 	if (res->status == GSS_S_COMPLETE) {
1837 		res->msg_token.GSS_BUFFER_T_len = (uint_t)msg_token.length;
1838 		res->msg_token.GSS_BUFFER_T_val = (char *)msg_token.value;
1839 	} else
1840 		syslog_gss_error(res->status, res->minor_status, "sign");
1841 
1842 	/* return to caller */
1843 
1844 	return (TRUE);
1845 }
1846 
1847 bool_t
1848 gss_verify_1_svc(argp, res, rqstp)
1849 gss_verify_arg *argp;
1850 gss_verify_res *res;
1851 struct svc_req *rqstp;
1852 {
1853 
1854 	uid_t uid;
1855 
1856 	gss_buffer_desc message_buffer;
1857 	gss_buffer_desc token_buffer;
1858 	gss_ctx_id_t context_handle;
1859 	bool_t context_verf_ok;
1860 
1861 	memset(res, 0, sizeof (*res));
1862 
1863 	if (gssd_debug)
1864 		fprintf(stderr, gettext("gss_verify\n"));
1865 
1866 	gssd_convert_context_handle(&argp->context_handle, &context_handle,
1867 		argp->gssd_context_verifier, &context_verf_ok, NULL);
1868 
1869 	/* verify the context_handle */
1870 	if (!context_verf_ok) {
1871 		res->status = (OM_uint32) GSS_S_NO_CONTEXT;
1872 		res->minor_status = 0;
1873 		return (TRUE);
1874 	}
1875 
1876 	/*
1877 	 * if the request isn't from root, null out the result pointer
1878 	 * entries, so the next time through xdr_free won't try to
1879 	 * free unmalloc'd memory and then return NULL
1880 	 */
1881 
1882 	if (checkfrom(rqstp, &uid) == 0)
1883 		return (FALSE);
1884 
1885 	/*
1886 	 * copy the XDR structured arguments into their corresponding local
1887 	 * GSSAPI variable equivalents.
1888 	 */
1889 
1890 	message_buffer.length = (size_t)argp->message_buffer.GSS_BUFFER_T_len;
1891 	message_buffer.value = (void *)argp->message_buffer.GSS_BUFFER_T_val;
1892 
1893 	token_buffer.length = (size_t)argp->token_buffer.GSS_BUFFER_T_len;
1894 	token_buffer.value = (void *)argp->token_buffer.GSS_BUFFER_T_val;
1895 
1896 	/* call the gssapi routine */
1897 
1898 	res->status = (OM_uint32)gss_verify(&res->minor_status,
1899 				context_handle,
1900 				&message_buffer,
1901 				&token_buffer,
1902 				&res->qop_state);
1903 
1904 	if (GSS_ERROR(res->status))
1905 		syslog_gss_error(res->status, res->minor_status, "verify");
1906 
1907 	/* return to caller */
1908 	return (TRUE);
1909 }
1910 
1911 bool_t
1912 gss_seal_1_svc(argp, res, rqstp)
1913 gss_seal_arg *argp;
1914 gss_seal_res *res;
1915 struct svc_req *rqstp;
1916 {
1917 	uid_t uid;
1918 
1919 	gss_buffer_desc input_message_buffer;
1920 	gss_buffer_desc output_message_buffer;
1921 	gss_ctx_id_t context_handle;
1922 	bool_t context_verf_ok;
1923 
1924 	memset(res, 0, sizeof (*res));
1925 
1926 	if (gssd_debug)
1927 		fprintf(stderr, gettext("gss_seal\n"));
1928 
1929 	gssd_convert_context_handle(&argp->context_handle, &context_handle,
1930 		argp->gssd_context_verifier, &context_verf_ok, NULL);
1931 
1932 	/* verify the context_handle */
1933 
1934 	if (!context_verf_ok) {
1935 		res->output_message_buffer.GSS_BUFFER_T_val = NULL;
1936 		res->output_message_buffer.GSS_BUFFER_T_len = 0;
1937 		res->status = (OM_uint32) GSS_S_NO_CONTEXT;
1938 		res->minor_status = 0;
1939 		return (TRUE);
1940 	}
1941 
1942 	/*
1943 	 * if the request isn't from root, null out the result pointer
1944 	 * entries, so the next time through xdr_free won't try to
1945 	 * free unmalloc'd memory and then return NULL
1946 	 */
1947 
1948 	if (checkfrom(rqstp, &uid) == 0) {
1949 		res->output_message_buffer.GSS_BUFFER_T_val = NULL;
1950 		return (FALSE);
1951 
1952 	}
1953 
1954 
1955 	/*
1956 	 * copy the XDR structured arguments into their corresponding local
1957 	 * GSSAPI variable equivalents.
1958 	 */
1959 
1960 	input_message_buffer.length = (size_t)argp->input_message_buffer.
1961 					GSS_BUFFER_T_len;
1962 	input_message_buffer.value = (void *)argp->input_message_buffer.
1963 					GSS_BUFFER_T_val;
1964 
1965 
1966 	/* call the gssapi routine */
1967 
1968 	res->status = (OM_uint32)gss_seal(&res->minor_status,
1969 				context_handle,
1970 				argp->conf_req_flag,
1971 				argp->qop_req,
1972 				&input_message_buffer,
1973 				&res->conf_state,
1974 				&output_message_buffer);
1975 	/*
1976 	 * convert the output args from the parameter given in the call to the
1977 	 * variable in the XDR result
1978 	 */
1979 
1980 	if (res->status == GSS_S_COMPLETE) {
1981 		res->output_message_buffer.GSS_BUFFER_T_len =
1982 				(uint_t)output_message_buffer.length;
1983 		res->output_message_buffer.GSS_BUFFER_T_val =
1984 				(char *)output_message_buffer.value;
1985 	} else
1986 		syslog_gss_error(res->status, res->minor_status, "seal");
1987 
1988 /* return to caller */
1989 
1990 	return (TRUE);
1991 }
1992 
1993 bool_t
1994 gss_unseal_1_svc(argp, res, rqstp)
1995 gss_unseal_arg *argp;
1996 gss_unseal_res *res;
1997 struct svc_req *rqstp;
1998 {
1999 
2000 	uid_t uid;
2001 
2002 	gss_buffer_desc input_message_buffer;
2003 	gss_buffer_desc output_message_buffer;
2004 	gss_ctx_id_t context_handle;
2005 	bool_t context_verf_ok;
2006 
2007 	memset(res, 0, sizeof (*res));
2008 
2009 	if (gssd_debug)
2010 		fprintf(stderr, gettext("gss_unseal\n"));
2011 
2012 	/* verify the context_handle */
2013 	gssd_convert_context_handle(&argp->context_handle, &context_handle,
2014 		argp->gssd_context_verifier, &context_verf_ok, NULL);
2015 
2016 	/* verify the context_handle */
2017 	if (!context_verf_ok) {
2018 		res->output_message_buffer.GSS_BUFFER_T_val = NULL;
2019 		res->output_message_buffer.GSS_BUFFER_T_len = 0;
2020 		res->status = (OM_uint32)GSS_S_NO_CONTEXT;
2021 		res->minor_status = 0;
2022 		return (TRUE);
2023 	}
2024 
2025 	/*
2026 	 * if the request isn't from root, null out the result pointer
2027 	 * entries, so the next time through xdr_free won't try to
2028 	 * free unmalloc'd memory and then return NULL
2029 	 */
2030 
2031 	if (checkfrom(rqstp, &uid) == 0) {
2032 		res->output_message_buffer.GSS_BUFFER_T_val = NULL;
2033 		return (FALSE);
2034 	}
2035 
2036 
2037 	/*
2038 	 * copy the XDR structured arguments into their corresponding local
2039 	 * GSSAPI variable equivalents.
2040 	 */
2041 
2042 	input_message_buffer.length = (size_t)argp->input_message_buffer.
2043 					GSS_BUFFER_T_len;
2044 	input_message_buffer.value = (void *)argp->input_message_buffer.
2045 					GSS_BUFFER_T_val;
2046 
2047 	/* call the gssapi routine */
2048 
2049 	res->status = (OM_uint32)gss_unseal(&res->minor_status,
2050 				context_handle,
2051 				&input_message_buffer,
2052 				&output_message_buffer,
2053 				&res->conf_state,
2054 				&res->qop_state);
2055 
2056 	/*
2057 	 * convert the output args from the parameter given in the call to the
2058 	 * variable in the XDR result
2059 	 */
2060 
2061 	if (res->status == GSS_S_COMPLETE) {
2062 		res->output_message_buffer.GSS_BUFFER_T_len =
2063 				(uint_t)output_message_buffer.length;
2064 		res->output_message_buffer.GSS_BUFFER_T_val =
2065 				(char *)output_message_buffer.value;
2066 	} else
2067 		syslog_gss_error(res->status, res->minor_status, "unseal");
2068 
2069 
2070 	/* return to caller */
2071 
2072 	return (TRUE);
2073 }
2074 
2075 bool_t
2076 gss_display_status_1_svc(argp, res, rqstp)
2077 gss_display_status_arg *argp;
2078 gss_display_status_res *res;
2079 struct svc_req *rqstp;
2080 {
2081 	uid_t uid;
2082 	gss_OID mech_type;
2083 	gss_OID_desc mech_type_desc;
2084 	gss_buffer_desc status_string;
2085 
2086 	memset(res, 0, sizeof (*res));
2087 
2088 	if (gssd_debug)
2089 		fprintf(stderr, gettext("gss_display_status\n"));
2090 
2091 	/*
2092 	 * if the request isn't from root, null out the result pointer
2093 	 * entries, so the next time through xdr_free won't try to
2094 	 * free unmalloc'd memory and then return NULL
2095 	 */
2096 
2097 	if (checkfrom(rqstp, &uid) == 0) {
2098 		res->status_string.GSS_BUFFER_T_val = NULL;
2099 		return (FALSE);
2100 	}
2101 
2102 	/* set the uid sent as the RPC argument */
2103 
2104 	uid = argp->uid;
2105 	set_gssd_uid(uid);
2106 
2107 	/*
2108 	 * copy the XDR structured arguments into their corresponding local
2109 	 * GSSAPI variables.
2110 	 */
2111 
2112 	if (argp->mech_type.GSS_OID_len == 0)
2113 		mech_type = GSS_C_NULL_OID;
2114 	else {
2115 		mech_type = &mech_type_desc;
2116 		mech_type_desc.length = (OM_uint32) argp->mech_type.GSS_OID_len;
2117 		mech_type_desc.elements = (void *) argp->mech_type.GSS_OID_val;
2118 	}
2119 
2120 
2121 	/* call the gssapi routine */
2122 
2123 	res->status = (OM_uint32) gss_display_status(&res->minor_status,
2124 					argp->status_value,
2125 					argp->status_type,
2126 					mech_type,
2127 					(OM_uint32 *)&res->message_context,
2128 					&status_string);
2129 
2130 	/*
2131 	 * convert the output args from the parameter given in the call to the
2132 	 * variable in the XDR result
2133 	 */
2134 
2135 	if (res->status == GSS_S_COMPLETE) {
2136 		res->status_string.GSS_BUFFER_T_len =
2137 			(uint_t)status_string.length;
2138 		res->status_string.GSS_BUFFER_T_val =
2139 			(char *)status_string.value;
2140 	}
2141 
2142 	return (TRUE);
2143 
2144 }
2145 
2146 /*ARGSUSED*/
2147 bool_t
2148 gss_indicate_mechs_1_svc(argp, res, rqstp)
2149 	void *argp;
2150 	gss_indicate_mechs_res *res;
2151 	struct svc_req *rqstp;
2152 {
2153 	gss_OID_set oid_set;
2154 	uid_t uid;
2155 
2156 	memset(res, 0, sizeof (*res));
2157 
2158 	if (gssd_debug)
2159 		fprintf(stderr, gettext("gss_indicate_mechs\n"));
2160 
2161 	res->mech_set.GSS_OID_SET_val = NULL;
2162 
2163 	/*
2164 	 * if the request isn't from root, null out the result pointer
2165 	 * entries, so the next time through xdr_free won't try to
2166 	 * free unmalloc'd memory and then return NULL
2167 	 */
2168 
2169 	if (checkfrom(rqstp, &uid) == 0) {
2170 		return (FALSE);
2171 	}
2172 
2173 	res->status = gss_indicate_mechs(&res->minor_status, &oid_set);
2174 
2175 	if (res->status == GSS_S_COMPLETE) {
2176 		int i, j;
2177 
2178 		res->mech_set.GSS_OID_SET_len = oid_set->count;
2179 		res->mech_set.GSS_OID_SET_val = (void *)
2180 				malloc(oid_set->count * sizeof (GSS_OID));
2181 		if (!res->mech_set.GSS_OID_SET_val) {
2182 			return (GSS_S_FAILURE);
2183 		}
2184 		for (i = 0; i < oid_set->count; i++) {
2185 			res->mech_set.GSS_OID_SET_val[i].GSS_OID_len =
2186 				oid_set->elements[i].length;
2187 			res->mech_set.GSS_OID_SET_val[i].GSS_OID_val =
2188 				(char *)malloc(oid_set->elements[i].length);
2189 			if (!res->mech_set.GSS_OID_SET_val[i].GSS_OID_val) {
2190 				for (j = 0; j < (i -1); j++) {
2191 				free
2192 				(res->mech_set.GSS_OID_SET_val[i].GSS_OID_val);
2193 				}
2194 				free(res->mech_set.GSS_OID_SET_val);
2195 				return (GSS_S_FAILURE);
2196 			}
2197 			memcpy(res->mech_set.GSS_OID_SET_val[i].GSS_OID_val,
2198 				oid_set->elements[i].elements,
2199 				oid_set->elements[i].length);
2200 		}
2201 	}
2202 
2203 	return (TRUE);
2204 }
2205 
2206 bool_t
2207 gss_inquire_cred_1_svc(argp, res, rqstp)
2208 gss_inquire_cred_arg *argp;
2209 gss_inquire_cred_res *res;
2210 struct svc_req *rqstp;
2211 {
2212 
2213 	uid_t uid;
2214 
2215 	OM_uint32 minor_status;
2216 	gss_cred_id_t cred_handle;
2217 	gss_buffer_desc external_name;
2218 	gss_OID name_type;
2219 	gss_name_t internal_name;
2220 	gss_OID_set mechanisms;
2221 	int i, j;
2222 
2223 	memset(res, 0, sizeof (*res));
2224 
2225 	if (gssd_debug)
2226 		fprintf(stderr, gettext("gss_inquire_cred\n"));
2227 
2228 	/* verify the verifier_cred_handle */
2229 
2230 	if (argp->gssd_cred_verifier != gssd_time_verf) {
2231 		res->name.GSS_BUFFER_T_val = NULL;
2232 		res->name_type.GSS_OID_val = NULL;
2233 		res->mechanisms.GSS_OID_SET_val = NULL;
2234 		res->status = (OM_uint32) GSS_S_DEFECTIVE_CREDENTIAL;
2235 		res->minor_status = 0;
2236 		return (TRUE);
2237 	}
2238 
2239 	/*
2240 	 * if the request isn't from root, null out the result pointer
2241 	 * entries, so the next time through xdr_free won't try to
2242 	 * free unmalloc'd memory and then return NULL
2243 	 */
2244 
2245 	if (checkfrom(rqstp, &uid) == 0) {
2246 		res->name.GSS_BUFFER_T_val = NULL;
2247 		res->name_type.GSS_OID_val = NULL;
2248 		res->mechanisms.GSS_OID_SET_val = NULL;
2249 		return (FALSE);
2250 	}
2251 
2252 	/* set the uid sent as the RPC argument */
2253 
2254 	uid = argp->uid;
2255 	set_gssd_uid(uid);
2256 
2257 	cred_handle = (argp->cred_handle.GSS_CRED_ID_T_len == 0 ?
2258 			GSS_C_NO_CREDENTIAL :
2259 			/*LINTED*/
2260 			*((gss_cred_id_t *)argp->cred_handle.
2261 				GSS_CRED_ID_T_val));
2262 
2263 	/* call the gssapi routine */
2264 
2265 	res->status = (OM_uint32)gss_inquire_cred(&res->minor_status,
2266 					cred_handle,
2267 					&internal_name,
2268 					&res->lifetime,
2269 					&res->cred_usage,
2270 					&mechanisms);
2271 
2272 	if (res->status != GSS_S_COMPLETE) {
2273 		syslog_gss_error(res->status, res->minor_status,
2274 				"inquire_cred");
2275 		return (TRUE);
2276 	}
2277 
2278 	/* convert the returned name from internal to external format */
2279 
2280 	if (gss_display_name(&minor_status, internal_name,
2281 				&external_name, &name_type)
2282 			!= GSS_S_COMPLETE) {
2283 
2284 		res->status = (OM_uint32)GSS_S_FAILURE;
2285 		res->minor_status = minor_status;
2286 
2287 		gss_release_name(&minor_status, &internal_name);
2288 
2289 		if (mechanisms != GSS_C_NULL_OID_SET) {
2290 			for (i = 0; i < mechanisms->count; i++)
2291 				free(mechanisms->elements[i].elements);
2292 			free(mechanisms->elements);
2293 			free(mechanisms);
2294 		}
2295 
2296 		return (TRUE);
2297 	}
2298 
2299 	/*
2300 	 * convert the output args from the parameter given in the call to the
2301 	 * variable in the XDR result
2302 	 */
2303 
2304 
2305 	res->name.GSS_BUFFER_T_len = (uint_t)external_name.length;
2306 	res->name.GSS_BUFFER_T_val = (void *)external_name.value;
2307 
2308 	/*
2309 	 * we have to allocate storage for name_type here, since the value
2310 	 * returned from gss_display_name points to the underlying mechanism
2311 	 * static storage. If we didn't allocate storage, the next time
2312 	 * through this routine, the xdr_free() call at the beginning would
2313 	 * try to free up that static storage.
2314 	 */
2315 
2316 	res->name_type.GSS_OID_len = (uint_t)name_type->length;
2317 	res->name_type.GSS_OID_val = (void *)malloc(name_type->length);
2318 	if (!res->name_type.GSS_OID_val) {
2319 		return (GSS_S_FAILURE);
2320 	}
2321 	memcpy(res->name_type.GSS_OID_val, name_type->elements,
2322 		name_type->length);
2323 
2324 	if (mechanisms != GSS_C_NULL_OID_SET) {
2325 		res->mechanisms.GSS_OID_SET_len =
2326 			(uint_t)mechanisms->count;
2327 		res->mechanisms.GSS_OID_SET_val = (GSS_OID *)
2328 				malloc(sizeof (GSS_OID) * mechanisms->count);
2329 		if (!res->mechanisms.GSS_OID_SET_val) {
2330 			free(res->name_type.GSS_OID_val);
2331 			return (GSS_S_FAILURE);
2332 		}
2333 		for (i = 0; i < mechanisms->count; i++) {
2334 			res->mechanisms.GSS_OID_SET_val[i].GSS_OID_len =
2335 				(uint_t)mechanisms->elements[i].length;
2336 			res->mechanisms.GSS_OID_SET_val[i].GSS_OID_val =
2337 				(char *)malloc(mechanisms->elements[i].
2338 						length);
2339 			if (!res->mechanisms.GSS_OID_SET_val[i].GSS_OID_val) {
2340 				free(res->name_type.GSS_OID_val);
2341 				for (j = 0; j < i; j++) {
2342 				free(res->mechanisms.
2343 					GSS_OID_SET_val[i].GSS_OID_val);
2344 				}
2345 				free(res->mechanisms.GSS_OID_SET_val);
2346 				return (GSS_S_FAILURE);
2347 			}
2348 			memcpy(res->mechanisms.GSS_OID_SET_val[i].GSS_OID_val,
2349 				mechanisms->elements[i].elements,
2350 				mechanisms->elements[i].length);
2351 		}
2352 	} else
2353 		res->mechanisms.GSS_OID_SET_len = 0;
2354 
2355 	/* release the space allocated for internal_name and mechanisms */
2356 	gss_release_name(&minor_status, &internal_name);
2357 
2358 	if (mechanisms != GSS_C_NULL_OID_SET) {
2359 		for (i = 0; i < mechanisms->count; i++)
2360 			free(mechanisms->elements[i].elements);
2361 		free(mechanisms->elements);
2362 		free(mechanisms);
2363 	}
2364 
2365 	/* return to caller */
2366 	return (TRUE);
2367 }
2368 
2369 
2370 bool_t
2371 gss_inquire_cred_by_mech_1_svc(argp, res, rqstp)
2372 gss_inquire_cred_by_mech_arg *argp;
2373 gss_inquire_cred_by_mech_res *res;
2374 struct svc_req *rqstp;
2375 {
2376 
2377 	uid_t uid;
2378 
2379 	gss_cred_id_t cred_handle;
2380 	gss_OID_desc		mech_type_desc;
2381 	gss_OID 		mech_type = &mech_type_desc;
2382 
2383 	memset(res, 0, sizeof (*res));
2384 
2385 	if (gssd_debug)
2386 		fprintf(stderr, gettext("gss_inquire_cred\n"));
2387 
2388 	/* verify the verifier_cred_handle */
2389 
2390 	if (argp->gssd_cred_verifier != gssd_time_verf) {
2391 		res->status = (OM_uint32) GSS_S_DEFECTIVE_CREDENTIAL;
2392 		res->minor_status = 0;
2393 		return (TRUE);
2394 	}
2395 
2396 	/*
2397 	 * if the request isn't from root, null out the result pointer
2398 	 * entries, so the next time through xdr_free won't try to
2399 	 * free unmalloc'd memory and then return NULL
2400 	 */
2401 
2402 	if (checkfrom(rqstp, &uid) == 0) {
2403 		return (FALSE);
2404 	}
2405 
2406 	/* set the uid sent as the RPC argument */
2407 
2408 	uid = argp->uid;
2409 	set_gssd_uid(uid);
2410 
2411 	cred_handle = (argp->cred_handle.GSS_CRED_ID_T_len == 0 ?
2412 			GSS_C_NO_CREDENTIAL :
2413 			/*LINTED*/
2414 			*((gss_cred_id_t *)argp->cred_handle.
2415 				GSS_CRED_ID_T_val));
2416 
2417 	/* call the gssapi routine */
2418 
2419 	if (argp->mech_type.GSS_OID_len == 0)
2420 		mech_type = GSS_C_NULL_OID;
2421 	else {
2422 		mech_type->length =
2423 			(OM_uint32)argp->mech_type.GSS_OID_len;
2424 		mech_type->elements =
2425 			(void *)malloc(mech_type->length);
2426 		if (!mech_type->elements) {
2427 			return (GSS_S_FAILURE);
2428 		}
2429 		memcpy(mech_type->elements,
2430 			argp->mech_type.GSS_OID_val,
2431 			mech_type->length);
2432 	}
2433 	res->status = (OM_uint32)gss_inquire_cred_by_mech(
2434 					&res->minor_status, cred_handle,
2435 					mech_type, NULL, NULL,
2436 					NULL, NULL);
2437 
2438 	/* return to caller */
2439 	return (TRUE);
2440 }
2441 
2442 
2443 bool_t
2444 gsscred_name_to_unix_cred_1_svc(argsp, res, rqstp)
2445 gsscred_name_to_unix_cred_arg *argsp;
2446 gsscred_name_to_unix_cred_res *res;
2447 struct svc_req *rqstp;
2448 {
2449 	uid_t uid;
2450 	gss_OID_desc oid;
2451 	gss_name_t gssName;
2452 	gss_buffer_desc gssBuf = GSS_C_EMPTY_BUFFER;
2453 	OM_uint32 minor;
2454 	int gidsLen;
2455 	gid_t *gids, gidOut;
2456 
2457 	if (gssd_debug)
2458 		fprintf(stderr, gettext("gsscred_name_to_unix_cred\n"));
2459 
2460 	memset(res, 0, sizeof (*res));
2461 
2462 	/*
2463 	 * check the request originator
2464 	 */
2465 	if (checkfrom(rqstp, &uid) == 0)
2466 		return (FALSE);
2467 
2468 	/* set the uid from the rpc request */
2469 	uid = argsp->uid;
2470 	set_gssd_uid(uid);
2471 
2472 	/*
2473 	 * convert the principal name to gss internal format
2474 	 * need not malloc the input parameters
2475 	 */
2476 	gssBuf.length = argsp->pname.GSS_BUFFER_T_len;
2477 	gssBuf.value = (void*)argsp->pname.GSS_BUFFER_T_val;
2478 	oid.length = argsp->name_type.GSS_OID_len;
2479 	oid.elements = (void*)argsp->name_type.GSS_OID_val;
2480 
2481 	res->major = gss_import_name(&minor, &gssBuf, &oid, &gssName);
2482 	if (res->major != GSS_S_COMPLETE)
2483 		return (TRUE);
2484 
2485 	/* retrieve the mechanism type from the arguments */
2486 	oid.length = argsp->mech_type.GSS_OID_len;
2487 	oid.elements = (void*)argsp->mech_type.GSS_OID_val;
2488 
2489 	/* call the gss extensions to map the principal name to unix creds */
2490 	res->major = gsscred_name_to_unix_cred(gssName, &oid, &uid, &gidOut,
2491 					&gids, &gidsLen);
2492 	gss_release_name(&minor, &gssName);
2493 
2494 	if (res->major == GSS_S_COMPLETE) {
2495 		res->uid = uid;
2496 		res->gid = gidOut;
2497 		res->gids.GSSCRED_GIDS_val = gids;
2498 		res->gids.GSSCRED_GIDS_len = gidsLen;
2499 	}
2500 
2501 	return (TRUE);
2502 } /* gsscred_name_to_unix_cred_svc_1 */
2503 
2504 bool_t
2505 gsscred_expname_to_unix_cred_1_svc(argsp, res, rqstp)
2506 gsscred_expname_to_unix_cred_arg *argsp;
2507 gsscred_expname_to_unix_cred_res *res;
2508 struct svc_req *rqstp;
2509 {
2510 	uid_t uid;
2511 	gss_buffer_desc expName = GSS_C_EMPTY_BUFFER;
2512 	int gidsLen;
2513 	gid_t *gids, gidOut;
2514 
2515 	if (gssd_debug)
2516 		fprintf(stderr, gettext("gsscred_expname_to_unix_cred\n"));
2517 
2518 	memset(res, 0, sizeof (*res));
2519 
2520 	/*
2521 	 * check the request originator
2522 	 */
2523 	if (checkfrom(rqstp, &uid) == 0)
2524 		return (FALSE);
2525 
2526 	/* set the uid from the rpc request */
2527 	uid = argsp->uid;
2528 	set_gssd_uid(uid);
2529 
2530 	/*
2531 	 * extract the export name from arguments
2532 	 * need not malloc the input parameters
2533 	 */
2534 	expName.length = argsp->expname.GSS_BUFFER_T_len;
2535 	expName.value = (void*)argsp->expname.GSS_BUFFER_T_val;
2536 
2537 	res->major = gsscred_expname_to_unix_cred(&expName, &uid,
2538 					&gidOut, &gids, &gidsLen);
2539 
2540 	if (res->major == GSS_S_COMPLETE) {
2541 		res->uid = uid;
2542 		res->gid = gidOut;
2543 		res->gids.GSSCRED_GIDS_val = gids;
2544 		res->gids.GSSCRED_GIDS_len = gidsLen;
2545 	}
2546 
2547 	return (TRUE);
2548 } /* gsscred_expname_to_unix_cred_1_svc */
2549 
2550 bool_t
2551 gss_get_group_info_1_svc(argsp, res, rqstp)
2552 gss_get_group_info_arg *argsp;
2553 gss_get_group_info_res *res;
2554 struct svc_req *rqstp;
2555 {
2556 	uid_t uid;
2557 	int gidsLen;
2558 	gid_t *gids, gidOut;
2559 
2560 	if (gssd_debug)
2561 		fprintf(stderr, gettext("gss_get_group_info\n"));
2562 
2563 	memset(res, 0, sizeof (*res));
2564 
2565 	/*
2566 	 * check the request originator
2567 	 */
2568 	if (checkfrom(rqstp, &uid) == 0)
2569 		return (FALSE);
2570 
2571 	/* set the uid from the rpc request */
2572 	uid = argsp->uid;
2573 	set_gssd_uid(uid);
2574 
2575 	/*
2576 	 * extract the uid from the arguments
2577 	 */
2578 	uid = argsp->puid;
2579 	res->major = gss_get_group_info(uid, &gidOut, &gids, &gidsLen);
2580 	if (res->major == GSS_S_COMPLETE) {
2581 		res->gid = gidOut;
2582 		res->gids.GSSCRED_GIDS_val = gids;
2583 		res->gids.GSSCRED_GIDS_len = gidsLen;
2584 	}
2585 
2586 	return (TRUE);
2587 } /* gss_get_group_info_1_svc */
2588 
2589 /*ARGSUSED*/
2590 bool_t
2591 gss_get_kmod_1_svc(argsp, res, rqstp)
2592 	gss_get_kmod_arg *argsp;
2593 	gss_get_kmod_res *res;
2594 	struct svc_req *rqstp;
2595 {
2596 	gss_OID_desc oid;
2597 	char *kmodName;
2598 
2599 	if (gssd_debug)
2600 		fprintf(stderr, gettext("gss_get_kmod\n"));
2601 
2602 	res->module_follow = FALSE;
2603 	oid.length = argsp->mech_oid.GSS_OID_len;
2604 	oid.elements = (void *)argsp->mech_oid.GSS_OID_val;
2605 	kmodName = __gss_get_kmodName(&oid);
2606 
2607 	if (kmodName != NULL) {
2608 		res->module_follow = TRUE;
2609 		res->gss_get_kmod_res_u.modname = kmodName;
2610 	}
2611 
2612 	return (TRUE);
2613 }
2614 
2615 /*
2616  *  Returns 1 if caller is ok, else 0.
2617  *  If caller ok, the uid is returned in uidp.
2618  */
2619 static int
2620 checkfrom(rqstp, uidp)
2621 struct svc_req *rqstp;
2622 uid_t *uidp;
2623 {
2624 	SVCXPRT *xprt = rqstp->rq_xprt;
2625 	struct authunix_parms *aup;
2626 	uid_t uid;
2627 
2628 	/* check client agent uid to ensure it is privileged */
2629 	if (__rpc_get_local_uid(xprt, &uid) < 0) {
2630 		syslog(LOG_ERR, gettext("__rpc_get_local_uid failed %s %s"),
2631 			xprt->xp_netid, xprt->xp_tp);
2632 		goto weakauth;
2633 	}
2634 	if (gssd_debug)
2635 		fprintf(stderr, gettext("checkfrom: local_uid  %d\n"), uid);
2636 	if (uid != 0) {
2637 		syslog(LOG_ERR,
2638 			gettext("checkfrom: caller (uid %d) not privileged"),
2639 			uid);
2640 		goto weakauth;
2641 	}
2642 
2643 	/*
2644 	 *  Request came from local privileged process.
2645 	 *  Proceed to get uid of client if needed by caller.
2646 	 */
2647 	if (uidp) {
2648 		if (rqstp->rq_cred.oa_flavor != AUTH_SYS) {
2649 		syslog(LOG_ERR, gettext("checkfrom: not UNIX credentials"));
2650 			goto weakauth;
2651 		}
2652 		CTASSERT(sizeof (struct authunix_parms) <= RQCRED_SIZE);
2653 		/*LINTED*/
2654 		aup = (struct authunix_parms *)rqstp->rq_clntcred;
2655 		*uidp = aup->aup_uid;
2656 		if (gssd_debug) {
2657 			fprintf(stderr,
2658 				gettext("checkfrom: caller's uid %d\n"), *uidp);
2659 		}
2660 	}
2661 	return (1);
2662 
2663 	weakauth:
2664 	svcerr_weakauth(xprt);
2665 	return (0);
2666 }
2667