xref: /freebsd/crypto/krb5/src/lib/rpc/svc_auth_gss.c (revision 7f2fe78b9dd5f51c821d771b63d2e096f6fd49e9)
1 /* lib/rpc/svc_auth_gss.c */
2 /*
3   Copyright (c) 2000 The Regents of the University of Michigan.
4   All rights reserved.
5 
6   Copyright (c) 2000 Dug Song <dugsong@UMICH.EDU>.
7   All rights reserved, all wrongs reversed.
8 
9   Redistribution and use in source and binary forms, with or without
10   modification, are permitted provided that the following conditions
11   are met:
12 
13   1. Redistributions of source code must retain the above copyright
14      notice, this list of conditions and the following disclaimer.
15   2. Redistributions in binary form must reproduce the above copyright
16      notice, this list of conditions and the following disclaimer in the
17      documentation and/or other materials provided with the distribution.
18   3. Neither the name of the University nor the names of its
19      contributors may be used to endorse or promote products derived
20      from this software without specific prior written permission.
21 
22   THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
23   WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
24   MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
25   DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26   FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
29   BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
30   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
31   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
32   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 
34   Id: svc_auth_gss.c,v 1.28 2002/10/15 21:29:36 kwc Exp
35  */
36 
37 #include "k5-platform.h"
38 #include <gssrpc/rpc.h>
39 #include <gssrpc/auth_gssapi.h>
40 #ifdef HAVE_HEIMDAL
41 #include <gssapi.h>
42 #define gss_nt_service_name GSS_C_NT_HOSTBASED_SERVICE
43 #else
44 #include <gssapi/gssapi.h>
45 #include <gssapi/gssapi_generic.h>
46 #endif
47 
48 #ifdef DEBUG_GSSAPI
49 int svc_debug_gss = DEBUG_GSSAPI;
50 #endif
51 
52 #ifdef SPKM
53 
54 #ifndef OID_EQ
55 #define g_OID_equal(o1,o2) \
56    (((o1)->length == (o2)->length) && \
57     ((o1)->elements != 0) && ((o2)->elements != 0) && \
58     (memcmp((o1)->elements,(o2)->elements,(int) (o1)->length) == 0))
59 #define OID_EQ 1
60 #endif /* OID_EQ */
61 
62 extern const gss_OID_desc * const gss_mech_spkm3;
63 
64 #endif /* SPKM */
65 
66 extern SVCAUTH svc_auth_none;
67 
68 static auth_gssapi_log_badauth_func log_badauth = NULL;
69 static caddr_t log_badauth_data = NULL;
70 static auth_gssapi_log_badauth2_func log_badauth2 = NULL;
71 static caddr_t log_badauth2_data = NULL;
72 static auth_gssapi_log_badverf_func log_badverf = NULL;
73 static caddr_t log_badverf_data = NULL;
74 static auth_gssapi_log_miscerr_func log_miscerr = NULL;
75 static caddr_t log_miscerr_data = NULL;
76 
77 #define LOG_MISCERR(arg) if (log_miscerr) \
78         (*log_miscerr)(rqst, msg, arg, log_miscerr_data)
79 
80 static bool_t	svcauth_gss_destroy(SVCAUTH *);
81 static bool_t   svcauth_gss_wrap(SVCAUTH *, XDR *, xdrproc_t, caddr_t);
82 static bool_t   svcauth_gss_unwrap(SVCAUTH *, XDR *, xdrproc_t, caddr_t);
83 
84 static bool_t	svcauth_gss_nextverf(struct svc_req *, u_int);
85 
86 struct svc_auth_ops svc_auth_gss_ops = {
87 	svcauth_gss_wrap,
88 	svcauth_gss_unwrap,
89 	svcauth_gss_destroy
90 };
91 
92 struct svc_rpc_gss_data {
93 	bool_t			established;	/* context established */
94 	gss_cred_id_t		cred;		/* credential */
95 	gss_ctx_id_t		ctx;		/* context id */
96 	struct rpc_gss_sec	sec;		/* security triple */
97 	gss_buffer_desc		cname;		/* GSS client name */
98 	u_int			seq;		/* sequence number */
99 	u_int			win;		/* sequence window */
100 	u_int			seqlast;	/* last sequence number */
101 	uint32_t		seqmask;	/* bitmask of seqnums */
102 	gss_name_t		client_name;	/* unparsed name string */
103 	gss_buffer_desc		checksum;	/* so we can free it */
104 };
105 
106 #define SVCAUTH_PRIVATE(auth) \
107 	(*(struct svc_rpc_gss_data **)&(auth)->svc_ah_private)
108 
109 /* Global server credentials. */
110 static gss_name_t	svcauth_gss_name = NULL;
111 
112 bool_t
svcauth_gss_set_svc_name(gss_name_t name)113 svcauth_gss_set_svc_name(gss_name_t name)
114 {
115 	OM_uint32	maj_stat, min_stat;
116 
117 	log_debug("in svcauth_gss_set_svc_name()");
118 
119 	if (svcauth_gss_name != NULL) {
120 		maj_stat = gss_release_name(&min_stat, &svcauth_gss_name);
121 
122 		if (maj_stat != GSS_S_COMPLETE) {
123 			log_status("gss_release_name", maj_stat, min_stat);
124 			return (FALSE);
125 		}
126 		svcauth_gss_name = NULL;
127 	}
128 	if (svcauth_gss_name == GSS_C_NO_NAME)
129 		return (TRUE);
130 
131 	maj_stat = gss_duplicate_name(&min_stat, name, &svcauth_gss_name);
132 
133 	if (maj_stat != GSS_S_COMPLETE) {
134 		log_status("gss_duplicate_name", maj_stat, min_stat);
135 		return (FALSE);
136 	}
137 
138 	return (TRUE);
139 }
140 
141 static bool_t
svcauth_gss_acquire_cred(struct svc_rpc_gss_data * gd)142 svcauth_gss_acquire_cred(struct svc_rpc_gss_data *gd)
143 {
144 	OM_uint32	maj_stat, min_stat;
145 
146 	log_debug("in svcauth_gss_acquire_cred()");
147 
148 	/* We don't need to acquire a credential if using the default name. */
149 	if (svcauth_gss_name == GSS_C_NO_NAME)
150 		return (TRUE);
151 
152 	/* Only acquire a credential once per authentication. */
153 	if (gd->cred != GSS_C_NO_CREDENTIAL)
154 		return (TRUE);
155 
156 	maj_stat = gss_acquire_cred(&min_stat, svcauth_gss_name, 0,
157 				    GSS_C_NULL_OID_SET, GSS_C_ACCEPT,
158 				    &gd->cred, NULL, NULL);
159 
160 	if (maj_stat != GSS_S_COMPLETE) {
161 		log_status("gss_acquire_cred", maj_stat, min_stat);
162 		return (FALSE);
163 	}
164 	return (TRUE);
165 }
166 
167 /* Invoke log_badauth callbacks for an authentication failure. */
168 static void
badauth(OM_uint32 maj,OM_uint32 minor,SVCXPRT * xprt)169 badauth(OM_uint32 maj, OM_uint32 minor, SVCXPRT *xprt)
170 {
171 	if (log_badauth != NULL)
172 		(*log_badauth)(maj, minor, &xprt->xp_raddr, log_badauth_data);
173 	if (log_badauth2 != NULL)
174 		(*log_badauth2)(maj, minor, xprt, log_badauth2_data);
175 }
176 
177 static bool_t
svcauth_gss_accept_sec_context(struct svc_req * rqst,struct rpc_gss_init_res * gr)178 svcauth_gss_accept_sec_context(struct svc_req *rqst,
179 			       struct rpc_gss_init_res *gr)
180 {
181 	struct svc_rpc_gss_data	*gd;
182 	struct rpc_gss_cred	*gc;
183 	gss_buffer_desc		 recv_tok, seqbuf;
184 	gss_OID			 mech;
185 	OM_uint32		 maj_stat = 0, min_stat = 0, ret_flags, seq;
186 
187 	log_debug("in svcauth_gss_accept_context()");
188 
189 	gd = SVCAUTH_PRIVATE(rqst->rq_xprt->xp_auth);
190 	gc = (struct rpc_gss_cred *)rqst->rq_clntcred;
191 	memset(gr, 0, sizeof(*gr));
192 
193 	/* Deserialize arguments. */
194 	memset(&recv_tok, 0, sizeof(recv_tok));
195 
196 	if (!svc_getargs(rqst->rq_xprt, xdr_rpc_gss_init_args,
197 			 (caddr_t)&recv_tok))
198 		return (FALSE);
199 
200 	gr->gr_major = gss_accept_sec_context(&gr->gr_minor,
201 					      &gd->ctx,
202 					      gd->cred,
203 					      &recv_tok,
204 					      GSS_C_NO_CHANNEL_BINDINGS,
205 					      &gd->client_name,
206 					      &mech,
207 					      &gr->gr_token,
208 					      &ret_flags,
209 					      NULL,
210 					      NULL);
211 
212 	svc_freeargs(rqst->rq_xprt, xdr_rpc_gss_init_args, (caddr_t)&recv_tok);
213 
214 	log_status("accept_sec_context", gr->gr_major, gr->gr_minor);
215 	if (gr->gr_major != GSS_S_COMPLETE &&
216 	    gr->gr_major != GSS_S_CONTINUE_NEEDED) {
217 		badauth(gr->gr_major, gr->gr_minor, rqst->rq_xprt);
218 		gd->ctx = GSS_C_NO_CONTEXT;
219 		goto errout;
220 	}
221 	gr->gr_ctx.value = "xxxx";
222 	gr->gr_ctx.length = 4;
223 
224 	/* gr->gr_win = 0x00000005; ANDROS: for debugging linux kernel version...  */
225 	gr->gr_win = sizeof(gd->seqmask) * 8;
226 
227 	/* Save client info. */
228 	gd->sec.mech = mech;
229 	gd->sec.qop = GSS_C_QOP_DEFAULT;
230 	gd->sec.svc = gc->gc_svc;
231 	gd->seq = gc->gc_seq;
232 	gd->win = gr->gr_win;
233 
234 	if (gr->gr_major == GSS_S_COMPLETE) {
235 #ifdef SPKM
236 		/* spkm3: no src_name (anonymous) */
237 		if(!g_OID_equal(gss_mech_spkm3, mech)) {
238 #endif
239 		    maj_stat = gss_display_name(&min_stat, gd->client_name,
240 					    &gd->cname, &gd->sec.mech);
241 #ifdef SPKM
242 		}
243 #endif
244 		if (maj_stat != GSS_S_COMPLETE) {
245 			log_status("display_name", maj_stat, min_stat);
246 			goto errout;
247 		}
248 #ifdef DEBUG
249 #ifdef HAVE_HEIMDAL
250 		log_debug("accepted context for %.*s with "
251 			  "<mech {}, qop %d, svc %d>",
252 			  gd->cname.length, (char *)gd->cname.value,
253 			  gd->sec.qop, gd->sec.svc);
254 #else
255 		{
256 			gss_buffer_desc mechname;
257 
258 			gss_oid_to_str(&min_stat, mech, &mechname);
259 
260 			log_debug("accepted context for %.*s with "
261 				  "<mech %.*s, qop %d, svc %d>",
262 				  gd->cname.length, (char *)gd->cname.value,
263 				  mechname.length, (char *)mechname.value,
264 				  gd->sec.qop, gd->sec.svc);
265 
266 			gss_release_buffer(&min_stat, &mechname);
267 		}
268 #endif
269 #endif /* DEBUG */
270 		seq = htonl(gr->gr_win);
271 		seqbuf.value = &seq;
272 		seqbuf.length = sizeof(seq);
273 
274 		gss_release_buffer(&min_stat, &gd->checksum);
275 		maj_stat = gss_sign(&min_stat, gd->ctx, GSS_C_QOP_DEFAULT,
276 				    &seqbuf, &gd->checksum);
277 
278 		if (maj_stat != GSS_S_COMPLETE) {
279 			goto errout;
280 		}
281 
282 
283 		rqst->rq_xprt->xp_verf.oa_flavor = RPCSEC_GSS;
284 		rqst->rq_xprt->xp_verf.oa_base = gd->checksum.value;
285 		rqst->rq_xprt->xp_verf.oa_length = gd->checksum.length;
286 	}
287 	return (TRUE);
288 errout:
289 	gss_release_buffer(&min_stat, &gr->gr_token);
290 	return (FALSE);
291 }
292 
293 static bool_t
svcauth_gss_validate(struct svc_req * rqst,struct svc_rpc_gss_data * gd,struct rpc_msg * msg)294 svcauth_gss_validate(struct svc_req *rqst, struct svc_rpc_gss_data *gd, struct rpc_msg *msg)
295 {
296 	struct opaque_auth	*oa;
297 	gss_buffer_desc		 rpcbuf, checksum;
298 	OM_uint32		 maj_stat, min_stat, qop_state;
299 	u_char			 rpchdr[128];
300 	int32_t			*buf;
301 
302 	log_debug("in svcauth_gss_validate()");
303 
304 	memset(rpchdr, 0, sizeof(rpchdr));
305 
306 	/* XXX - Reconstruct RPC header for signing (from xdr_callmsg). */
307 	oa = &msg->rm_call.cb_cred;
308 	if (oa->oa_length > MAX_AUTH_BYTES)
309 		return (FALSE);
310 
311 	/* 8 XDR units from the IXDR macro calls. */
312 	if (sizeof(rpchdr) < (8 * BYTES_PER_XDR_UNIT +
313 			      RNDUP(oa->oa_length)))
314 		return (FALSE);
315 
316 	buf = (int32_t *)(void *)rpchdr;
317 	IXDR_PUT_LONG(buf, msg->rm_xid);
318 	IXDR_PUT_ENUM(buf, msg->rm_direction);
319 	IXDR_PUT_LONG(buf, msg->rm_call.cb_rpcvers);
320 	IXDR_PUT_LONG(buf, msg->rm_call.cb_prog);
321 	IXDR_PUT_LONG(buf, msg->rm_call.cb_vers);
322 	IXDR_PUT_LONG(buf, msg->rm_call.cb_proc);
323 	IXDR_PUT_ENUM(buf, oa->oa_flavor);
324 	IXDR_PUT_LONG(buf, oa->oa_length);
325 	if (oa->oa_length) {
326 		memcpy((caddr_t)buf, oa->oa_base, oa->oa_length);
327 		buf += RNDUP(oa->oa_length) / sizeof(int32_t);
328 	}
329 	rpcbuf.value = rpchdr;
330 	rpcbuf.length = (u_char *)buf - rpchdr;
331 
332 	checksum.value = msg->rm_call.cb_verf.oa_base;
333 	checksum.length = msg->rm_call.cb_verf.oa_length;
334 
335 	maj_stat = gss_verify_mic(&min_stat, gd->ctx, &rpcbuf, &checksum,
336 				  &qop_state);
337 
338 	if (maj_stat != GSS_S_COMPLETE) {
339 		log_status("gss_verify_mic", maj_stat, min_stat);
340 		if (log_badverf != NULL)
341 			(*log_badverf)(gd->client_name,
342 			       svcauth_gss_name,
343 			       rqst, msg, log_badverf_data);
344 		return (FALSE);
345 	}
346 	return (TRUE);
347 }
348 
349 static bool_t
svcauth_gss_nextverf(struct svc_req * rqst,u_int num)350 svcauth_gss_nextverf(struct svc_req *rqst, u_int num)
351 {
352 	struct svc_rpc_gss_data	*gd;
353 	gss_buffer_desc		 signbuf;
354 	OM_uint32		 maj_stat, min_stat;
355 
356 	log_debug("in svcauth_gss_nextverf()");
357 
358 	if (rqst->rq_xprt->xp_auth == NULL)
359 		return (FALSE);
360 
361 	gd = SVCAUTH_PRIVATE(rqst->rq_xprt->xp_auth);
362 
363 	gss_release_buffer(&min_stat, &gd->checksum);
364 
365 	signbuf.value = &num;
366 	signbuf.length = sizeof(num);
367 
368 	maj_stat = gss_get_mic(&min_stat, gd->ctx, gd->sec.qop,
369 			       &signbuf, &gd->checksum);
370 
371 	if (maj_stat != GSS_S_COMPLETE) {
372 		log_status("gss_get_mic", maj_stat, min_stat);
373 		return (FALSE);
374 	}
375 	rqst->rq_xprt->xp_verf.oa_flavor = RPCSEC_GSS;
376 	rqst->rq_xprt->xp_verf.oa_base = (caddr_t)gd->checksum.value;
377 	rqst->rq_xprt->xp_verf.oa_length = (u_int)gd->checksum.length;
378 
379 	return (TRUE);
380 }
381 
382 enum auth_stat
gssrpc__svcauth_gss(struct svc_req * rqst,struct rpc_msg * msg,bool_t * no_dispatch)383 gssrpc__svcauth_gss(struct svc_req *rqst, struct rpc_msg *msg,
384 	bool_t *no_dispatch)
385 {
386 	enum auth_stat		 retstat;
387 	XDR	 		 xdrs;
388 	SVCAUTH			*auth;
389 	struct svc_rpc_gss_data	*gd;
390 	struct rpc_gss_cred	*gc;
391 	struct rpc_gss_init_res	 gr;
392 	int			 call_stat, offset;
393 	OM_uint32		 min_stat;
394 
395 	log_debug("in svcauth_gss()");
396 
397 	/* Initialize reply. */
398 	rqst->rq_xprt->xp_verf = gssrpc__null_auth;
399 
400 	/* Allocate and set up server auth handle. */
401 	if (rqst->rq_xprt->xp_auth == NULL ||
402 	    rqst->rq_xprt->xp_auth == &svc_auth_none) {
403 		if ((auth = calloc(sizeof(*auth), 1)) == NULL) {
404 			fprintf(stderr, "svcauth_gss: out_of_memory\n");
405 			return (AUTH_FAILED);
406 		}
407 		if ((gd = calloc(sizeof(*gd), 1)) == NULL) {
408 			fprintf(stderr, "svcauth_gss: out_of_memory\n");
409 			return (AUTH_FAILED);
410 		}
411 		auth->svc_ah_ops = &svc_auth_gss_ops;
412 		SVCAUTH_PRIVATE(auth) = gd;
413 		rqst->rq_xprt->xp_auth = auth;
414 	}
415 	else gd = SVCAUTH_PRIVATE(rqst->rq_xprt->xp_auth);
416 
417 	log_debug("xp_auth=%p, gd=%p", rqst->rq_xprt->xp_auth, gd);
418 
419 	/* Deserialize client credentials. */
420 	if (rqst->rq_cred.oa_length <= 0)
421 		return (AUTH_BADCRED);
422 
423 	gc = (struct rpc_gss_cred *)rqst->rq_clntcred;
424 	memset(gc, 0, sizeof(*gc));
425 
426 	log_debug("calling xdrmem_create()");
427 	log_debug("oa_base=%p, oa_length=%u", rqst->rq_cred.oa_base,
428 		  rqst->rq_cred.oa_length);
429 	xdrmem_create(&xdrs, rqst->rq_cred.oa_base,
430 		      rqst->rq_cred.oa_length, XDR_DECODE);
431 	log_debug("xdrmem_create() returned");
432 
433 	if (!xdr_rpc_gss_cred(&xdrs, gc)) {
434 		log_debug("xdr_rpc_gss_cred() failed");
435 		XDR_DESTROY(&xdrs);
436 		return (AUTH_BADCRED);
437 	}
438 	XDR_DESTROY(&xdrs);
439 
440 	retstat = AUTH_FAILED;
441 
442 #define ret_freegc(code) do { retstat = code; goto freegc; } while (0)
443 
444 	/* Check version. */
445 	if (gc->gc_v != RPCSEC_GSS_VERSION)
446 		ret_freegc (AUTH_BADCRED);
447 
448 	/* Check RPCSEC_GSS service. */
449 	if (gc->gc_svc != RPCSEC_GSS_SVC_NONE &&
450 	    gc->gc_svc != RPCSEC_GSS_SVC_INTEGRITY &&
451 	    gc->gc_svc != RPCSEC_GSS_SVC_PRIVACY)
452 		ret_freegc (AUTH_BADCRED);
453 
454 	/* Check sequence number. */
455 	if (gd->established) {
456 		if (gc->gc_seq > MAXSEQ)
457 			ret_freegc (RPCSEC_GSS_CTXPROBLEM);
458 
459 		if ((offset = gd->seqlast - gc->gc_seq) < 0) {
460 			gd->seqlast = gc->gc_seq;
461 			offset = 0 - offset;
462 			gd->seqmask <<= offset;
463 			offset = 0;
464 		} else if ((u_int)offset >= gd->win ||
465 			   (gd->seqmask & (1 << offset))) {
466 			*no_dispatch = 1;
467 			ret_freegc (RPCSEC_GSS_CTXPROBLEM);
468 		}
469 		gd->seq = gc->gc_seq;
470 		gd->seqmask |= (1 << offset);
471 	}
472 
473 	if (gd->established) {
474 		rqst->rq_clntname = (char *)gd->client_name;
475 		rqst->rq_svccred = (char *)gd->ctx;
476 	}
477 
478 	/* Handle RPCSEC_GSS control procedure. */
479 	switch (gc->gc_proc) {
480 
481 	case RPCSEC_GSS_INIT:
482 	case RPCSEC_GSS_CONTINUE_INIT:
483 		if (rqst->rq_proc != NULLPROC)
484 			ret_freegc (AUTH_FAILED);		/* XXX ? */
485 
486 		if (!svcauth_gss_acquire_cred(gd))
487 			ret_freegc (AUTH_FAILED);
488 
489 		if (!svcauth_gss_accept_sec_context(rqst, &gr))
490 			ret_freegc (AUTH_REJECTEDCRED);
491 
492 		if (!svcauth_gss_nextverf(rqst, htonl(gr.gr_win))) {
493 			gss_release_buffer(&min_stat, &gr.gr_token);
494 			ret_freegc (AUTH_FAILED);
495 		}
496 		*no_dispatch = TRUE;
497 
498 		call_stat = svc_sendreply(rqst->rq_xprt, xdr_rpc_gss_init_res,
499 					  (caddr_t)&gr);
500 
501 		gss_release_buffer(&min_stat, &gr.gr_token);
502 		gss_release_buffer(&min_stat, &gd->checksum);
503 		if (!call_stat)
504 			ret_freegc (AUTH_FAILED);
505 
506 		if (gr.gr_major == GSS_S_COMPLETE)
507 			gd->established = TRUE;
508 
509 		break;
510 
511 	case RPCSEC_GSS_DATA:
512 		if (!svcauth_gss_validate(rqst, gd, msg))
513 			ret_freegc (RPCSEC_GSS_CREDPROBLEM);
514 
515 		if (!svcauth_gss_nextverf(rqst, htonl(gc->gc_seq)))
516  			ret_freegc (AUTH_FAILED);
517 		break;
518 
519 	case RPCSEC_GSS_DESTROY:
520 		if (rqst->rq_proc != NULLPROC)
521 			ret_freegc (AUTH_FAILED);		/* XXX ? */
522 
523 		if (!svcauth_gss_validate(rqst, gd, msg))
524 			ret_freegc (RPCSEC_GSS_CREDPROBLEM);
525 
526 		if (!svcauth_gss_nextverf(rqst, htonl(gc->gc_seq)))
527 			ret_freegc (AUTH_FAILED);
528 
529 		*no_dispatch = TRUE;
530 
531 		call_stat = svc_sendreply(rqst->rq_xprt,
532 					  xdr_void, (caddr_t)NULL);
533 
534 		log_debug("sendreply in destroy: %d", call_stat);
535 
536 		SVCAUTH_DESTROY(rqst->rq_xprt->xp_auth);
537 		rqst->rq_xprt->xp_auth = &svc_auth_none;
538 
539 		break;
540 
541 	default:
542 		ret_freegc (AUTH_REJECTEDCRED);
543 		break;
544 	}
545 	retstat = AUTH_OK;
546 freegc:
547 	xdr_free(xdr_rpc_gss_cred, gc);
548 	log_debug("returning %d from svcauth_gss()", retstat);
549 	return (retstat);
550 }
551 
552 static bool_t
svcauth_gss_destroy(SVCAUTH * auth)553 svcauth_gss_destroy(SVCAUTH *auth)
554 {
555 	struct svc_rpc_gss_data	*gd;
556 	OM_uint32		 min_stat;
557 
558 	log_debug("in svcauth_gss_destroy()");
559 
560 	gd = SVCAUTH_PRIVATE(auth);
561 
562 	gss_delete_sec_context(&min_stat, &gd->ctx, GSS_C_NO_BUFFER);
563 	gss_release_cred(&min_stat, &gd->cred);
564 	gss_release_buffer(&min_stat, &gd->cname);
565 	gss_release_buffer(&min_stat, &gd->checksum);
566 
567 	if (gd->client_name)
568 		gss_release_name(&min_stat, &gd->client_name);
569 
570 	mem_free(gd, sizeof(*gd));
571 	mem_free(auth, sizeof(*auth));
572 
573 	return (TRUE);
574 }
575 
576 static bool_t
svcauth_gss_wrap(SVCAUTH * auth,XDR * xdrs,xdrproc_t xdr_func,caddr_t xdr_ptr)577 svcauth_gss_wrap(SVCAUTH *auth, XDR *xdrs, xdrproc_t xdr_func, caddr_t xdr_ptr)
578 {
579 	struct svc_rpc_gss_data	*gd;
580 
581 	log_debug("in svcauth_gss_wrap()");
582 
583 	gd = SVCAUTH_PRIVATE(auth);
584 
585 	if (!gd->established || gd->sec.svc == RPCSEC_GSS_SVC_NONE) {
586 		return ((*xdr_func)(xdrs, xdr_ptr));
587 	}
588 	return (xdr_rpc_gss_data(xdrs, xdr_func, xdr_ptr,
589 				 gd->ctx, gd->sec.qop,
590 				 gd->sec.svc, gd->seq));
591 }
592 
593 static bool_t
svcauth_gss_unwrap(SVCAUTH * auth,XDR * xdrs,xdrproc_t xdr_func,caddr_t xdr_ptr)594 svcauth_gss_unwrap(SVCAUTH *auth, XDR *xdrs, xdrproc_t xdr_func, caddr_t xdr_ptr)
595 {
596 	struct svc_rpc_gss_data	*gd;
597 
598 	log_debug("in svcauth_gss_unwrap()");
599 
600 	gd = SVCAUTH_PRIVATE(auth);
601 
602 	if (!gd->established || gd->sec.svc == RPCSEC_GSS_SVC_NONE) {
603 		return ((*xdr_func)(xdrs, xdr_ptr));
604 	}
605 	return (xdr_rpc_gss_data(xdrs, xdr_func, xdr_ptr,
606 				 gd->ctx, gd->sec.qop,
607 				 gd->sec.svc, gd->seq));
608 }
609 
610 char *
svcauth_gss_get_principal(SVCAUTH * auth)611 svcauth_gss_get_principal(SVCAUTH *auth)
612 {
613 	struct svc_rpc_gss_data *gd;
614 	char *pname;
615 
616 	gd = SVCAUTH_PRIVATE(auth);
617 
618 	if (gd->cname.length == 0 || gd->cname.length >= SIZE_MAX)
619 		return (NULL);
620 
621 	if ((pname = malloc(gd->cname.length + 1)) == NULL)
622 		return (NULL);
623 
624 	memcpy(pname, gd->cname.value, gd->cname.length);
625 	pname[gd->cname.length] = '\0';
626 
627 	return (pname);
628 }
629 
630 /*
631  * Function: svcauth_gss_set_log_badauth_func
632  *
633  * Purpose: sets the logging function called when an invalid RPC call
634  * arrives
635  *
636  * See functional specifications.
637  */
svcauth_gss_set_log_badauth_func(auth_gssapi_log_badauth_func func,caddr_t data)638 void svcauth_gss_set_log_badauth_func(
639 	auth_gssapi_log_badauth_func func,
640 	caddr_t data)
641 {
642 	log_badauth = func;
643 	log_badauth_data = data;
644 }
645 
646 void
svcauth_gss_set_log_badauth2_func(auth_gssapi_log_badauth2_func func,caddr_t data)647 svcauth_gss_set_log_badauth2_func(auth_gssapi_log_badauth2_func func,
648 				  caddr_t data)
649 {
650 	log_badauth2 = func;
651 	log_badauth2_data = data;
652 }
653 
654 /*
655  * Function: svcauth_gss_set_log_badverf_func
656  *
657  * Purpose: sets the logging function called when an invalid RPC call
658  * arrives
659  *
660  * See functional specifications.
661  */
svcauth_gss_set_log_badverf_func(auth_gssapi_log_badverf_func func,caddr_t data)662 void svcauth_gss_set_log_badverf_func(
663 	auth_gssapi_log_badverf_func func,
664 	caddr_t data)
665 {
666 	log_badverf = func;
667 	log_badverf_data = data;
668 }
669 
670 /*
671  * Function: svcauth_gss_set_log_miscerr_func
672  *
673  * Purpose: sets the logging function called when a miscellaneous
674  * AUTH_GSSAPI error occurs
675  *
676  * See functional specifications.
677  */
svcauth_gss_set_log_miscerr_func(auth_gssapi_log_miscerr_func func,caddr_t data)678 void svcauth_gss_set_log_miscerr_func(
679 	auth_gssapi_log_miscerr_func func,
680 	caddr_t data)
681 {
682 	log_miscerr = func;
683 	log_miscerr_data = data;
684 }
685