xref: /freebsd/crypto/krb5/src/lib/rpc/svc_auth_gss.c (revision f1c4c3daccbaf3820f0e2224de53df12fc952fcc)
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, (xdrproc_t)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, (xdrproc_t)xdr_rpc_gss_init_args,
213 		     (caddr_t)&recv_tok);
214 
215 	log_status("accept_sec_context", gr->gr_major, gr->gr_minor);
216 	if (gr->gr_major != GSS_S_COMPLETE &&
217 	    gr->gr_major != GSS_S_CONTINUE_NEEDED) {
218 		badauth(gr->gr_major, gr->gr_minor, rqst->rq_xprt);
219 		gd->ctx = GSS_C_NO_CONTEXT;
220 		goto errout;
221 	}
222 	gr->gr_ctx.value = "xxxx";
223 	gr->gr_ctx.length = 4;
224 
225 	/* gr->gr_win = 0x00000005; ANDROS: for debugging linux kernel version...  */
226 	gr->gr_win = sizeof(gd->seqmask) * 8;
227 
228 	/* Save client info. */
229 	gd->sec.mech = mech;
230 	gd->sec.qop = GSS_C_QOP_DEFAULT;
231 	gd->sec.svc = gc->gc_svc;
232 	gd->seq = gc->gc_seq;
233 	gd->win = gr->gr_win;
234 
235 	if (gr->gr_major == GSS_S_COMPLETE) {
236 #ifdef SPKM
237 		/* spkm3: no src_name (anonymous) */
238 		if(!g_OID_equal(gss_mech_spkm3, mech)) {
239 #endif
240 		    maj_stat = gss_display_name(&min_stat, gd->client_name,
241 					    &gd->cname, &gd->sec.mech);
242 #ifdef SPKM
243 		}
244 #endif
245 		if (maj_stat != GSS_S_COMPLETE) {
246 			log_status("display_name", maj_stat, min_stat);
247 			goto errout;
248 		}
249 #ifdef DEBUG
250 #ifdef HAVE_HEIMDAL
251 		log_debug("accepted context for %.*s with "
252 			  "<mech {}, qop %d, svc %d>",
253 			  gd->cname.length, (char *)gd->cname.value,
254 			  gd->sec.qop, gd->sec.svc);
255 #else
256 		{
257 			gss_buffer_desc mechname;
258 
259 			gss_oid_to_str(&min_stat, mech, &mechname);
260 
261 			log_debug("accepted context for %.*s with "
262 				  "<mech %.*s, qop %d, svc %d>",
263 				  gd->cname.length, (char *)gd->cname.value,
264 				  mechname.length, (char *)mechname.value,
265 				  gd->sec.qop, gd->sec.svc);
266 
267 			gss_release_buffer(&min_stat, &mechname);
268 		}
269 #endif
270 #endif /* DEBUG */
271 		seq = htonl(gr->gr_win);
272 		seqbuf.value = &seq;
273 		seqbuf.length = sizeof(seq);
274 
275 		gss_release_buffer(&min_stat, &gd->checksum);
276 		maj_stat = gss_sign(&min_stat, gd->ctx, GSS_C_QOP_DEFAULT,
277 				    &seqbuf, &gd->checksum);
278 
279 		if (maj_stat != GSS_S_COMPLETE) {
280 			goto errout;
281 		}
282 
283 
284 		rqst->rq_xprt->xp_verf.oa_flavor = RPCSEC_GSS;
285 		rqst->rq_xprt->xp_verf.oa_base = gd->checksum.value;
286 		rqst->rq_xprt->xp_verf.oa_length = gd->checksum.length;
287 	}
288 	return (TRUE);
289 errout:
290 	gss_release_buffer(&min_stat, &gr->gr_token);
291 	return (FALSE);
292 }
293 
294 static bool_t
svcauth_gss_validate(struct svc_req * rqst,struct svc_rpc_gss_data * gd,struct rpc_msg * msg)295 svcauth_gss_validate(struct svc_req *rqst, struct svc_rpc_gss_data *gd, struct rpc_msg *msg)
296 {
297 	struct opaque_auth	*oa;
298 	gss_buffer_desc		 rpcbuf, checksum;
299 	OM_uint32		 maj_stat, min_stat, qop_state;
300 	u_char			 rpchdr[32 + MAX_AUTH_BYTES];
301 	int32_t			*buf;
302 
303 	log_debug("in svcauth_gss_validate()");
304 
305 	memset(rpchdr, 0, sizeof(rpchdr));
306 
307 	/* XXX - Reconstruct RPC header for signing (from xdr_callmsg). */
308 	oa = &msg->rm_call.cb_cred;
309 	if (oa->oa_length > MAX_AUTH_BYTES)
310 		return (FALSE);
311 
312 	/* 8 XDR units from the IXDR macro calls. */
313 	if (sizeof(rpchdr) < (8 * BYTES_PER_XDR_UNIT +
314 			      RNDUP(oa->oa_length)))
315 		return (FALSE);
316 
317 	buf = (int32_t *)(void *)rpchdr;
318 
319 	/* Write the 32 first bytes of the header. */
320 	IXDR_PUT_LONG(buf, msg->rm_xid);
321 	IXDR_PUT_ENUM(buf, msg->rm_direction);
322 	IXDR_PUT_LONG(buf, msg->rm_call.cb_rpcvers);
323 	IXDR_PUT_LONG(buf, msg->rm_call.cb_prog);
324 	IXDR_PUT_LONG(buf, msg->rm_call.cb_vers);
325 	IXDR_PUT_LONG(buf, msg->rm_call.cb_proc);
326 	IXDR_PUT_ENUM(buf, oa->oa_flavor);
327 	IXDR_PUT_LONG(buf, oa->oa_length);
328 
329 	if (oa->oa_length) {
330 		memcpy((caddr_t)buf, oa->oa_base, oa->oa_length);
331 		buf += RNDUP(oa->oa_length) / sizeof(int32_t);
332 	}
333 	rpcbuf.value = rpchdr;
334 	rpcbuf.length = (u_char *)buf - rpchdr;
335 
336 	checksum.value = msg->rm_call.cb_verf.oa_base;
337 	checksum.length = msg->rm_call.cb_verf.oa_length;
338 
339 	maj_stat = gss_verify_mic(&min_stat, gd->ctx, &rpcbuf, &checksum,
340 				  &qop_state);
341 
342 	if (maj_stat != GSS_S_COMPLETE) {
343 		log_status("gss_verify_mic", maj_stat, min_stat);
344 		if (log_badverf != NULL)
345 			(*log_badverf)(gd->client_name,
346 			       svcauth_gss_name,
347 			       rqst, msg, log_badverf_data);
348 		return (FALSE);
349 	}
350 	return (TRUE);
351 }
352 
353 static bool_t
svcauth_gss_nextverf(struct svc_req * rqst,u_int num)354 svcauth_gss_nextverf(struct svc_req *rqst, u_int num)
355 {
356 	struct svc_rpc_gss_data	*gd;
357 	gss_buffer_desc		 signbuf;
358 	OM_uint32		 maj_stat, min_stat;
359 
360 	log_debug("in svcauth_gss_nextverf()");
361 
362 	if (rqst->rq_xprt->xp_auth == NULL)
363 		return (FALSE);
364 
365 	gd = SVCAUTH_PRIVATE(rqst->rq_xprt->xp_auth);
366 
367 	gss_release_buffer(&min_stat, &gd->checksum);
368 
369 	signbuf.value = &num;
370 	signbuf.length = sizeof(num);
371 
372 	maj_stat = gss_get_mic(&min_stat, gd->ctx, gd->sec.qop,
373 			       &signbuf, &gd->checksum);
374 
375 	if (maj_stat != GSS_S_COMPLETE) {
376 		log_status("gss_get_mic", maj_stat, min_stat);
377 		return (FALSE);
378 	}
379 	rqst->rq_xprt->xp_verf.oa_flavor = RPCSEC_GSS;
380 	rqst->rq_xprt->xp_verf.oa_base = (caddr_t)gd->checksum.value;
381 	rqst->rq_xprt->xp_verf.oa_length = (u_int)gd->checksum.length;
382 
383 	return (TRUE);
384 }
385 
386 enum auth_stat
gssrpc__svcauth_gss(struct svc_req * rqst,struct rpc_msg * msg,bool_t * no_dispatch)387 gssrpc__svcauth_gss(struct svc_req *rqst, struct rpc_msg *msg,
388 	bool_t *no_dispatch)
389 {
390 	enum auth_stat		 retstat;
391 	XDR	 		 xdrs;
392 	SVCAUTH			*auth;
393 	struct svc_rpc_gss_data	*gd;
394 	struct rpc_gss_cred	*gc;
395 	struct rpc_gss_init_res	 gr;
396 	int			 call_stat, offset;
397 	OM_uint32		 min_stat;
398 
399 	log_debug("in svcauth_gss()");
400 
401 	/* Initialize reply. */
402 	rqst->rq_xprt->xp_verf = gssrpc__null_auth;
403 
404 	/* Allocate and set up server auth handle. */
405 	if (rqst->rq_xprt->xp_auth == NULL ||
406 	    rqst->rq_xprt->xp_auth == &svc_auth_none) {
407 		if ((auth = calloc(sizeof(*auth), 1)) == NULL) {
408 			fprintf(stderr, "svcauth_gss: out_of_memory\n");
409 			return (AUTH_FAILED);
410 		}
411 		if ((gd = calloc(sizeof(*gd), 1)) == NULL) {
412 			fprintf(stderr, "svcauth_gss: out_of_memory\n");
413 			return (AUTH_FAILED);
414 		}
415 		auth->svc_ah_ops = &svc_auth_gss_ops;
416 		SVCAUTH_PRIVATE(auth) = gd;
417 		rqst->rq_xprt->xp_auth = auth;
418 	}
419 	else gd = SVCAUTH_PRIVATE(rqst->rq_xprt->xp_auth);
420 
421 	log_debug("xp_auth=%p, gd=%p", rqst->rq_xprt->xp_auth, gd);
422 
423 	/* Deserialize client credentials. */
424 	if (rqst->rq_cred.oa_length <= 0)
425 		return (AUTH_BADCRED);
426 
427 	gc = (struct rpc_gss_cred *)rqst->rq_clntcred;
428 	memset(gc, 0, sizeof(*gc));
429 
430 	log_debug("calling xdrmem_create()");
431 	log_debug("oa_base=%p, oa_length=%u", rqst->rq_cred.oa_base,
432 		  rqst->rq_cred.oa_length);
433 	xdrmem_create(&xdrs, rqst->rq_cred.oa_base,
434 		      rqst->rq_cred.oa_length, XDR_DECODE);
435 	log_debug("xdrmem_create() returned");
436 
437 	if (!xdr_rpc_gss_cred(&xdrs, gc)) {
438 		log_debug("xdr_rpc_gss_cred() failed");
439 		XDR_DESTROY(&xdrs);
440 		return (AUTH_BADCRED);
441 	}
442 	XDR_DESTROY(&xdrs);
443 
444 	retstat = AUTH_FAILED;
445 
446 #define ret_freegc(code) do { retstat = code; goto freegc; } while (0)
447 
448 	/* Check version. */
449 	if (gc->gc_v != RPCSEC_GSS_VERSION)
450 		ret_freegc (AUTH_BADCRED);
451 
452 	/* Check RPCSEC_GSS service. */
453 	if (gc->gc_svc != RPCSEC_GSS_SVC_NONE &&
454 	    gc->gc_svc != RPCSEC_GSS_SVC_INTEGRITY &&
455 	    gc->gc_svc != RPCSEC_GSS_SVC_PRIVACY)
456 		ret_freegc (AUTH_BADCRED);
457 
458 	/* Check sequence number. */
459 	if (gd->established) {
460 		if (gc->gc_seq > MAXSEQ)
461 			ret_freegc (RPCSEC_GSS_CTXPROBLEM);
462 
463 		if ((offset = gd->seqlast - gc->gc_seq) < 0) {
464 			gd->seqlast = gc->gc_seq;
465 			offset = 0 - offset;
466 			gd->seqmask <<= offset;
467 			offset = 0;
468 		} else if ((u_int)offset >= gd->win ||
469 			   (gd->seqmask & (1 << offset))) {
470 			*no_dispatch = 1;
471 			ret_freegc (RPCSEC_GSS_CTXPROBLEM);
472 		}
473 		gd->seq = gc->gc_seq;
474 		gd->seqmask |= (1 << offset);
475 	}
476 
477 	if (gd->established) {
478 		rqst->rq_clntname = (char *)gd->client_name;
479 		rqst->rq_svccred = (char *)gd->ctx;
480 	}
481 
482 	/* Handle RPCSEC_GSS control procedure. */
483 	switch (gc->gc_proc) {
484 
485 	case RPCSEC_GSS_INIT:
486 	case RPCSEC_GSS_CONTINUE_INIT:
487 		if (rqst->rq_proc != NULLPROC)
488 			ret_freegc (AUTH_FAILED);		/* XXX ? */
489 
490 		if (!svcauth_gss_acquire_cred(gd))
491 			ret_freegc (AUTH_FAILED);
492 
493 		if (!svcauth_gss_accept_sec_context(rqst, &gr))
494 			ret_freegc (AUTH_REJECTEDCRED);
495 
496 		if (!svcauth_gss_nextverf(rqst, htonl(gr.gr_win))) {
497 			gss_release_buffer(&min_stat, &gr.gr_token);
498 			ret_freegc (AUTH_FAILED);
499 		}
500 		*no_dispatch = TRUE;
501 
502 		call_stat = svc_sendreply(rqst->rq_xprt,
503 					  (xdrproc_t)xdr_rpc_gss_init_res,
504 					  (caddr_t)&gr);
505 
506 		gss_release_buffer(&min_stat, &gr.gr_token);
507 		gss_release_buffer(&min_stat, &gd->checksum);
508 		if (!call_stat)
509 			ret_freegc (AUTH_FAILED);
510 
511 		if (gr.gr_major == GSS_S_COMPLETE)
512 			gd->established = TRUE;
513 
514 		break;
515 
516 	case RPCSEC_GSS_DATA:
517 		if (!svcauth_gss_validate(rqst, gd, msg))
518 			ret_freegc (RPCSEC_GSS_CREDPROBLEM);
519 
520 		if (!svcauth_gss_nextverf(rqst, htonl(gc->gc_seq)))
521  			ret_freegc (AUTH_FAILED);
522 		break;
523 
524 	case RPCSEC_GSS_DESTROY:
525 		if (rqst->rq_proc != NULLPROC)
526 			ret_freegc (AUTH_FAILED);		/* XXX ? */
527 
528 		if (!svcauth_gss_validate(rqst, gd, msg))
529 			ret_freegc (RPCSEC_GSS_CREDPROBLEM);
530 
531 		if (!svcauth_gss_nextverf(rqst, htonl(gc->gc_seq)))
532 			ret_freegc (AUTH_FAILED);
533 
534 		*no_dispatch = TRUE;
535 
536 		call_stat = svc_sendreply(rqst->rq_xprt,
537 					  xdr_void, (caddr_t)NULL);
538 
539 		log_debug("sendreply in destroy: %d", call_stat);
540 
541 		SVCAUTH_DESTROY(rqst->rq_xprt->xp_auth);
542 		rqst->rq_xprt->xp_auth = &svc_auth_none;
543 
544 		break;
545 
546 	default:
547 		ret_freegc (AUTH_REJECTEDCRED);
548 		break;
549 	}
550 	retstat = AUTH_OK;
551 freegc:
552 	xdr_free((xdrproc_t)xdr_rpc_gss_cred, gc);
553 	log_debug("returning %d from svcauth_gss()", retstat);
554 	return (retstat);
555 }
556 
557 static bool_t
svcauth_gss_destroy(SVCAUTH * auth)558 svcauth_gss_destroy(SVCAUTH *auth)
559 {
560 	struct svc_rpc_gss_data	*gd;
561 	OM_uint32		 min_stat;
562 
563 	log_debug("in svcauth_gss_destroy()");
564 
565 	gd = SVCAUTH_PRIVATE(auth);
566 
567 	gss_delete_sec_context(&min_stat, &gd->ctx, GSS_C_NO_BUFFER);
568 	gss_release_cred(&min_stat, &gd->cred);
569 	gss_release_buffer(&min_stat, &gd->cname);
570 	gss_release_buffer(&min_stat, &gd->checksum);
571 
572 	if (gd->client_name)
573 		gss_release_name(&min_stat, &gd->client_name);
574 
575 	mem_free(gd, sizeof(*gd));
576 	mem_free(auth, sizeof(*auth));
577 
578 	return (TRUE);
579 }
580 
581 static bool_t
svcauth_gss_wrap(SVCAUTH * auth,XDR * xdrs,xdrproc_t xdr_func,caddr_t xdr_ptr)582 svcauth_gss_wrap(SVCAUTH *auth, XDR *xdrs, xdrproc_t xdr_func, caddr_t xdr_ptr)
583 {
584 	struct svc_rpc_gss_data	*gd;
585 
586 	log_debug("in svcauth_gss_wrap()");
587 
588 	gd = SVCAUTH_PRIVATE(auth);
589 
590 	if (!gd->established || gd->sec.svc == RPCSEC_GSS_SVC_NONE) {
591 		return ((*xdr_func)(xdrs, xdr_ptr));
592 	}
593 	return (xdr_rpc_gss_data(xdrs, xdr_func, xdr_ptr,
594 				 gd->ctx, gd->sec.qop,
595 				 gd->sec.svc, gd->seq));
596 }
597 
598 static bool_t
svcauth_gss_unwrap(SVCAUTH * auth,XDR * xdrs,xdrproc_t xdr_func,caddr_t xdr_ptr)599 svcauth_gss_unwrap(SVCAUTH *auth, XDR *xdrs, xdrproc_t xdr_func, caddr_t xdr_ptr)
600 {
601 	struct svc_rpc_gss_data	*gd;
602 
603 	log_debug("in svcauth_gss_unwrap()");
604 
605 	gd = SVCAUTH_PRIVATE(auth);
606 
607 	if (!gd->established || gd->sec.svc == RPCSEC_GSS_SVC_NONE) {
608 		return ((*xdr_func)(xdrs, xdr_ptr));
609 	}
610 	return (xdr_rpc_gss_data(xdrs, xdr_func, xdr_ptr,
611 				 gd->ctx, gd->sec.qop,
612 				 gd->sec.svc, gd->seq));
613 }
614 
615 char *
svcauth_gss_get_principal(SVCAUTH * auth)616 svcauth_gss_get_principal(SVCAUTH *auth)
617 {
618 	struct svc_rpc_gss_data *gd;
619 	char *pname;
620 
621 	gd = SVCAUTH_PRIVATE(auth);
622 
623 	if (gd->cname.length == 0 || gd->cname.length >= SIZE_MAX)
624 		return (NULL);
625 
626 	if ((pname = malloc(gd->cname.length + 1)) == NULL)
627 		return (NULL);
628 
629 	memcpy(pname, gd->cname.value, gd->cname.length);
630 	pname[gd->cname.length] = '\0';
631 
632 	return (pname);
633 }
634 
635 /*
636  * Function: svcauth_gss_set_log_badauth_func
637  *
638  * Purpose: sets the logging function called when an invalid RPC call
639  * arrives
640  *
641  * See functional specifications.
642  */
svcauth_gss_set_log_badauth_func(auth_gssapi_log_badauth_func func,caddr_t data)643 void svcauth_gss_set_log_badauth_func(
644 	auth_gssapi_log_badauth_func func,
645 	caddr_t data)
646 {
647 	log_badauth = func;
648 	log_badauth_data = data;
649 }
650 
651 void
svcauth_gss_set_log_badauth2_func(auth_gssapi_log_badauth2_func func,caddr_t data)652 svcauth_gss_set_log_badauth2_func(auth_gssapi_log_badauth2_func func,
653 				  caddr_t data)
654 {
655 	log_badauth2 = func;
656 	log_badauth2_data = data;
657 }
658 
659 /*
660  * Function: svcauth_gss_set_log_badverf_func
661  *
662  * Purpose: sets the logging function called when an invalid RPC call
663  * arrives
664  *
665  * See functional specifications.
666  */
svcauth_gss_set_log_badverf_func(auth_gssapi_log_badverf_func func,caddr_t data)667 void svcauth_gss_set_log_badverf_func(
668 	auth_gssapi_log_badverf_func func,
669 	caddr_t data)
670 {
671 	log_badverf = func;
672 	log_badverf_data = data;
673 }
674 
675 /*
676  * Function: svcauth_gss_set_log_miscerr_func
677  *
678  * Purpose: sets the logging function called when a miscellaneous
679  * AUTH_GSSAPI error occurs
680  *
681  * See functional specifications.
682  */
svcauth_gss_set_log_miscerr_func(auth_gssapi_log_miscerr_func func,caddr_t data)683 void svcauth_gss_set_log_miscerr_func(
684 	auth_gssapi_log_miscerr_func func,
685 	caddr_t data)
686 {
687 	log_miscerr = func;
688 	log_miscerr_data = data;
689 }
690