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
52extern int gssd_debug;			/* declared in gssd.c */
53static OM_uint32 gssd_time_verf;	/* verifies same gssd */
54static OM_uint32 context_verf;		/* context sequence numbers */
55
56struct 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
66struct gssd_ctx_slot *gssd_ctx_slot_tbl;
67struct gssd_ctx_slot *gssd_lru_head;
68
69static int max_contexts;
70
71static int checkfrom(struct svc_req *, uid_t *);
72extern void set_gssd_uid(uid_t);
73extern 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 */
79static void
80syslog_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
129void
130gssd_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
191static OM_uint32 syslog_interval = 60;
192
193static struct gssd_ctx_slot *
194gssd_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
250static struct gssd_ctx_slot *
251gssd_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
269static void
270gssd_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
303static void
304gssd_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
337bool_t
338gss_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
581bool_t
582gss_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
765bool_t
766gss_release_cred_1_svc(argp, res, rqstp)
767gss_release_cred_arg *argp;
768gss_release_cred_res *res;
769struct 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
819bool_t
820gss_init_sec_context_1_svc(argp, res, rqstp)
821gss_init_sec_context_arg *argp;
822gss_init_sec_context_res *res;
823struct 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
1097bool_t
1098gss_accept_sec_context_1_svc(argp, res, rqstp)
1099gss_accept_sec_context_arg *argp;
1100gss_accept_sec_context_res *res;
1101struct 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
1389bool_t
1390gss_process_context_token_1_svc(argp, res, rqstp)
1391gss_process_context_token_arg *argp;
1392gss_process_context_token_res *res;
1393struct 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
1449bool_t
1450gss_delete_sec_context_1_svc(argp, res, rqstp)
1451gss_delete_sec_context_arg *argp;
1452gss_delete_sec_context_res *res;
1453struct 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
1564bool_t
1565gss_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 */
1674bool_t
1675gss_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
1741bool_t
1742gss_context_time_1_svc(argp, res, rqstp)
1743gss_context_time_arg *argp;
1744gss_context_time_res *res;
1745struct 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
1773bool_t
1774gss_sign_1_svc(argp, res, rqstp)
1775gss_sign_arg *argp;
1776gss_sign_res *res;
1777struct 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
1847bool_t
1848gss_verify_1_svc(argp, res, rqstp)
1849gss_verify_arg *argp;
1850gss_verify_res *res;
1851struct 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
1911bool_t
1912gss_seal_1_svc(argp, res, rqstp)
1913gss_seal_arg *argp;
1914gss_seal_res *res;
1915struct 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
1993bool_t
1994gss_unseal_1_svc(argp, res, rqstp)
1995gss_unseal_arg *argp;
1996gss_unseal_res *res;
1997struct 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
2075bool_t
2076gss_display_status_1_svc(argp, res, rqstp)
2077gss_display_status_arg *argp;
2078gss_display_status_res *res;
2079struct 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*/
2147bool_t
2148gss_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
2206bool_t
2207gss_inquire_cred_1_svc(argp, res, rqstp)
2208gss_inquire_cred_arg *argp;
2209gss_inquire_cred_res *res;
2210struct 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
2370bool_t
2371gss_inquire_cred_by_mech_1_svc(argp, res, rqstp)
2372gss_inquire_cred_by_mech_arg *argp;
2373gss_inquire_cred_by_mech_res *res;
2374struct 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
2443bool_t
2444gsscred_name_to_unix_cred_1_svc(argsp, res, rqstp)
2445gsscred_name_to_unix_cred_arg *argsp;
2446gsscred_name_to_unix_cred_res *res;
2447struct 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
2504bool_t
2505gsscred_expname_to_unix_cred_1_svc(argsp, res, rqstp)
2506gsscred_expname_to_unix_cred_arg *argsp;
2507gsscred_expname_to_unix_cred_res *res;
2508struct 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
2550bool_t
2551gss_get_group_info_1_svc(argsp, res, rqstp)
2552gss_get_group_info_arg *argsp;
2553gss_get_group_info_res *res;
2554struct 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*/
2590bool_t
2591gss_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 */
2619static int
2620checkfrom(rqstp, uidp)
2621struct svc_req *rqstp;
2622uid_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