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 /*
23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 #pragma ident "%Z%%M% %I% %E% SMI"
28
29 /*
30 * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved.
31 *
32 * $Id: svc_auth_gssapi.c,v 1.19 1994/10/27 12:38:51 jik Exp $
33 */
34
35 /*
36 * Server side handling of RPCSEC_GSS flavor.
37 */
38
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <strings.h>
42 #include <sys/stat.h>
43 #include <sys/time.h>
44 #include <gssapi/gssapi.h>
45 #include <gssapi/gssapi_ext.h>
46 #include <rpc/rpc.h>
47 #include <rpc/rpcsec_defs.h>
48 #include <sys/file.h>
49 #include <fcntl.h>
50 #include <pwd.h>
51 #include <stdio.h>
52 #include <syslog.h>
53
54 /*
55 * Sequence window definitions.
56 */
57 #define SEQ_ARR_SIZE 4
58 #define SEQ_WIN (SEQ_ARR_SIZE*32)
59 #define SEQ_HI_BIT 0x80000000
60 #define SEQ_LO_BIT 1
61 #define DIV_BY_32 5
62 #define SEQ_MASK 0x1f
63 #define SEQ_MAX 0x80000000
64
65
66 /* cache retransmit data */
67 typedef struct _retrans_entry {
68 uint32_t xid;
69 rpc_gss_init_res result;
70 struct _retrans_entry *next, *prev;
71 } retrans_entry;
72
73 /*
74 * Server side RPCSEC_GSS context information.
75 */
76 typedef struct _svc_rpc_gss_data {
77 struct _svc_rpc_gss_data *next, *prev;
78 struct _svc_rpc_gss_data *lru_next, *lru_prev;
79 bool_t established;
80 gss_ctx_id_t context;
81 gss_name_t client_name;
82 gss_cred_id_t server_creds;
83 uint_t expiration;
84 uint_t seq_num;
85 uint_t seq_bits[SEQ_ARR_SIZE];
86 uint_t key;
87 OM_uint32 qop;
88 bool_t done_docallback;
89 bool_t locked;
90 rpc_gss_rawcred_t raw_cred;
91 rpc_gss_ucred_t u_cred;
92 bool_t u_cred_set;
93 void *cookie;
94 gss_cred_id_t deleg;
95 mutex_t clm;
96 int ref_cnt;
97 bool_t stale;
98 time_t time_secs_set;
99 retrans_entry *retrans_data;
100 } svc_rpc_gss_data;
101
102 /*
103 * Data structures used for LRU based context management.
104 */
105 #define HASHMOD 256
106 #define HASHMASK 255
107
108 static svc_rpc_gss_data *clients[HASHMOD];
109 static svc_rpc_gss_data *lru_first, *lru_last;
110 static int num_gss_contexts = 0;
111 static int max_gss_contexts = 128;
112 static int sweep_interval = 10;
113 static int last_swept = 0;
114 static uint_t max_lifetime = GSS_C_INDEFINITE;
115 static int init_lifetime = 0;
116 static uint_t gid_timeout = 43200; /* 43200 secs = 12 hours */
117
118 /*
119 * lock used with context/lru variables
120 */
121 static mutex_t ctx_mutex = DEFAULTMUTEX;
122
123 /*
124 * server credential management data and structures
125 */
126 typedef struct svc_creds_list_s {
127 struct svc_creds_list_s *next;
128 gss_cred_id_t cred;
129 gss_name_t name;
130 rpcprog_t program;
131 rpcvers_t version;
132 gss_OID_set oid_set;
133 OM_uint32 req_time;
134 char *server_name;
135 mutex_t refresh_mutex;
136 } svc_creds_list_t;
137
138
139 static svc_creds_list_t *svc_creds_list;
140 static int svc_creds_count = 0;
141
142 /*
143 * lock used with server credential variables list
144 *
145 * server cred list locking guidelines:
146 * - Writer's lock holder has exclusive access to the list
147 * - Reader's lock holder(s) must also lock (refresh_mutex) each node
148 * before accessing that node's elements (ie. cred)
149 */
150 static rwlock_t cred_lock = DEFAULTRWLOCK;
151
152 /*
153 * server callback list
154 */
155 typedef struct cblist_s {
156 struct cblist_s *next;
157 rpc_gss_callback_t cb;
158 } cblist_t;
159
160 cblist_t *cblist = NULL;
161
162 /*
163 * lock used with callback variables
164 */
165 static mutex_t cb_mutex = DEFAULTMUTEX;
166
167 /*
168 * forward declarations
169 */
170 static bool_t svc_rpc_gss_wrap();
171 static bool_t svc_rpc_gss_unwrap();
172 static svc_rpc_gss_data *create_client();
173 static svc_rpc_gss_data *get_client();
174 static svc_rpc_gss_data *find_client();
175 static void destroy_client();
176 static void sweep_clients();
177 static void drop_lru_client();
178 static void insert_client();
179 static bool_t check_verf();
180 static bool_t rpc_gss_refresh_svc_cred();
181 static bool_t set_response_verf();
182 static void retrans_add(svc_rpc_gss_data *, uint32_t,
183 rpc_gss_init_res *);
184 static void retrans_del(struct _svc_rpc_gss_data *);
185
186
187 /*
188 * server side wrap/unwrap routines
189 */
190 struct svc_auth_ops svc_rpc_gss_ops = {
191 svc_rpc_gss_wrap,
192 svc_rpc_gss_unwrap,
193 };
194
195 /*
196 * Fetch server side authentication structure.
197 */
198 extern SVCAUTH *__svc_get_svcauth();
199
200 /*
201 * Cleanup routine for destroying context, called after service
202 * procedure is executed, for MT safeness.
203 */
204 extern void *__svc_set_proc_cleanup_cb();
205 static void (*old_cleanup_cb)() = NULL;
206 static bool_t cleanup_cb_set = FALSE;
207
208 static void
ctx_cleanup(xprt)209 ctx_cleanup(xprt)
210 SVCXPRT *xprt;
211 {
212 svc_rpc_gss_data *cl;
213 SVCAUTH *svcauth;
214
215 if (old_cleanup_cb != NULL)
216 (*old_cleanup_cb)(xprt);
217
218 /*
219 * First check if current context needs to be cleaned up.
220 */
221 svcauth = __svc_get_svcauth(xprt);
222 /*LINTED*/
223 if ((cl = (svc_rpc_gss_data *)svcauth->svc_ah_private) != NULL) {
224 mutex_lock(&cl->clm);
225 if (--cl->ref_cnt == 0 && cl->stale) {
226 mutex_unlock(&cl->clm);
227 mutex_lock(&ctx_mutex);
228 destroy_client(cl);
229 mutex_unlock(&ctx_mutex);
230 } else
231 mutex_unlock(&cl->clm);
232 }
233
234 /*
235 * Check for other expired contexts.
236 */
237 if ((time(0) - last_swept) > sweep_interval) {
238 mutex_lock(&ctx_mutex);
239 /*
240 * Check again, in case some other thread got in.
241 */
242 if ((time(0) - last_swept) > sweep_interval)
243 sweep_clients();
244 mutex_unlock(&ctx_mutex);
245 }
246 }
247
248 /*
249 * Set server parameters.
250 */
251 void
__rpc_gss_set_server_parms(init_cred_lifetime,max_cred_lifetime,cache_size)252 __rpc_gss_set_server_parms(init_cred_lifetime, max_cred_lifetime, cache_size)
253 int init_cred_lifetime;
254 int max_cred_lifetime;
255 int cache_size;
256 {
257 /*
258 * Ignore parameters unless greater than zero.
259 */
260 mutex_lock(&ctx_mutex);
261 if (cache_size > 0)
262 max_gss_contexts = cache_size;
263 if (max_cred_lifetime > 0)
264 max_lifetime = (uint_t)max_cred_lifetime;
265 if (init_cred_lifetime > 0)
266 init_lifetime = init_cred_lifetime;
267 mutex_unlock(&ctx_mutex);
268 }
269
270 /*
271 * Shift the array arr of length arrlen right by nbits bits.
272 */
273 static void
shift_bits(arr,arrlen,nbits)274 shift_bits(arr, arrlen, nbits)
275 uint_t *arr;
276 int arrlen;
277 int nbits;
278 {
279 int i, j;
280 uint_t lo, hi;
281
282 /*
283 * If the number of bits to be shifted exceeds SEQ_WIN, just
284 * zero out the array.
285 */
286 if (nbits < SEQ_WIN) {
287 for (i = 0; i < nbits; i++) {
288 hi = 0;
289 for (j = 0; j < arrlen; j++) {
290 lo = arr[j] & SEQ_LO_BIT;
291 arr[j] >>= 1;
292 if (hi)
293 arr[j] |= SEQ_HI_BIT;
294 hi = lo;
295 }
296 }
297 } else {
298 for (j = 0; j < arrlen; j++)
299 arr[j] = 0;
300 }
301 }
302
303 /*
304 * Check that the received sequence number seq_num is valid.
305 */
306 static bool_t
check_seq(cl,seq_num,kill_context)307 check_seq(cl, seq_num, kill_context)
308 svc_rpc_gss_data *cl;
309 uint_t seq_num;
310 bool_t *kill_context;
311 {
312 int i, j;
313 uint_t bit;
314
315 /*
316 * If it exceeds the maximum, kill context.
317 */
318 if (seq_num >= SEQ_MAX) {
319 *kill_context = TRUE;
320 return (FALSE);
321 }
322
323 /*
324 * If greater than the last seen sequence number, just shift
325 * the sequence window so that it starts at the new sequence
326 * number and extends downwards by SEQ_WIN.
327 */
328 if (seq_num > cl->seq_num) {
329 shift_bits(cl->seq_bits, SEQ_ARR_SIZE, seq_num - cl->seq_num);
330 cl->seq_bits[0] |= SEQ_HI_BIT;
331 cl->seq_num = seq_num;
332 return (TRUE);
333 }
334
335 /*
336 * If it is outside the sequence window, return failure.
337 */
338 i = cl->seq_num - seq_num;
339 if (i >= SEQ_WIN)
340 return (FALSE);
341
342 /*
343 * If within sequence window, set the bit corresponding to it
344 * if not already seen; if already seen, return failure.
345 */
346 j = SEQ_MASK - (i & SEQ_MASK);
347 bit = j > 0 ? (1 << j) : 1;
348 i >>= DIV_BY_32;
349 if (cl->seq_bits[i] & bit)
350 return (FALSE);
351 cl->seq_bits[i] |= bit;
352 return (TRUE);
353 }
354
355 /*
356 * Convert a name in gss exported type to rpc_gss_principal_t type.
357 */
358 static bool_t
__rpc_gss_make_principal(principal,name)359 __rpc_gss_make_principal(principal, name)
360 rpc_gss_principal_t *principal;
361 gss_buffer_desc *name;
362 {
363 int plen;
364 char *s;
365
366 plen = RNDUP(name->length) + sizeof (int);
367 (*principal) = (rpc_gss_principal_t)malloc(plen);
368 if ((*principal) == NULL)
369 return (FALSE);
370 bzero((caddr_t)(*principal), plen);
371 (*principal)->len = RNDUP(name->length);
372 s = (*principal)->name;
373 memcpy(s, name->value, name->length);
374 return (TRUE);
375 }
376
377 /*
378 * Convert a name in internal form to the exported type.
379 */
380 static bool_t
set_client_principal(g_name,r_name)381 set_client_principal(g_name, r_name)
382 gss_name_t g_name;
383 rpc_gss_principal_t *r_name;
384 {
385 gss_buffer_desc name;
386 OM_uint32 major, minor;
387 bool_t ret = FALSE;
388
389 major = gss_export_name(&minor, g_name, &name);
390 if (major != GSS_S_COMPLETE)
391 return (FALSE);
392 ret = __rpc_gss_make_principal(r_name, &name);
393 (void) gss_release_buffer(&minor, &name);
394 return (ret);
395 }
396
397 /*
398 * Set server callback.
399 */
400 bool_t
__rpc_gss_set_callback(cb)401 __rpc_gss_set_callback(cb)
402 rpc_gss_callback_t *cb;
403 {
404 cblist_t *cbl;
405
406 if (cb->callback == NULL)
407 return (FALSE);
408 if ((cbl = (cblist_t *)malloc(sizeof (*cbl))) == NULL)
409 return (FALSE);
410 cbl->cb = *cb;
411 mutex_lock(&cb_mutex);
412 cbl->next = cblist;
413 cblist = cbl;
414 mutex_unlock(&cb_mutex);
415 return (TRUE);
416 }
417
418 /*
419 * Locate callback (if specified) and call server. Release any
420 * delegated credentials unless passed to server and the server
421 * accepts the context. If a callback is not specified, accept
422 * the incoming context.
423 */
424 static bool_t
do_callback(req,client_data)425 do_callback(req, client_data)
426 struct svc_req *req;
427 svc_rpc_gss_data *client_data;
428 {
429 cblist_t *cbl;
430 bool_t ret = TRUE, found = FALSE;
431 rpc_gss_lock_t lock;
432 OM_uint32 minor;
433
434 mutex_lock(&cb_mutex);
435 for (cbl = cblist; cbl != NULL; cbl = cbl->next) {
436 if (req->rq_prog != cbl->cb.program ||
437 req->rq_vers != cbl->cb.version)
438 continue;
439 found = TRUE;
440 lock.locked = FALSE;
441 lock.raw_cred = &client_data->raw_cred;
442 ret = (*cbl->cb.callback)(req, client_data->deleg,
443 client_data->context, &lock, &client_data->cookie);
444 if (ret) {
445 client_data->locked = lock.locked;
446 client_data->deleg = GSS_C_NO_CREDENTIAL;
447 }
448 break;
449 }
450 if (!found) {
451 if (client_data->deleg != GSS_C_NO_CREDENTIAL) {
452 (void) gss_release_cred(&minor, &client_data->deleg);
453 client_data->deleg = GSS_C_NO_CREDENTIAL;
454 }
455 }
456 mutex_unlock(&cb_mutex);
457 return (ret);
458 }
459
460 /*
461 * Return caller credentials.
462 */
463 bool_t
__rpc_gss_getcred(req,rcred,ucred,cookie)464 __rpc_gss_getcred(req, rcred, ucred, cookie)
465 struct svc_req *req;
466 rpc_gss_rawcred_t **rcred;
467 rpc_gss_ucred_t **ucred;
468 void **cookie;
469 {
470 SVCAUTH *svcauth;
471 svc_rpc_gss_data *client_data;
472 svc_rpc_gss_parms_t *gss_parms;
473 gss_OID oid;
474 OM_uint32 status;
475 int len = 0;
476 struct timeval now;
477
478 svcauth = __svc_get_svcauth(req->rq_xprt);
479 /*LINTED*/
480 client_data = (svc_rpc_gss_data *)svcauth->svc_ah_private;
481 gss_parms = &svcauth->svc_gss_parms;
482
483 mutex_lock(&client_data->clm);
484
485 if (rcred != NULL) {
486 svcauth->raw_cred = client_data->raw_cred;
487 svcauth->raw_cred.service = gss_parms->service;
488 svcauth->raw_cred.qop = __rpc_gss_num_to_qop(
489 svcauth->raw_cred.mechanism, gss_parms->qop_rcvd);
490 *rcred = &svcauth->raw_cred;
491 }
492 if (ucred != NULL) {
493 if (!client_data->u_cred_set) {
494 /*
495 * Double check making sure ucred is not set
496 * after acquiring the lock.
497 */
498 if (!client_data->u_cred_set) {
499 if (!__rpc_gss_mech_to_oid(
500 (*rcred)->mechanism, &oid)) {
501 fprintf(stderr, dgettext(TEXT_DOMAIN,
502 "mech_to_oid failed in getcred.\n"));
503 *ucred = NULL;
504 } else {
505 status = gsscred_name_to_unix_cred(
506 client_data->client_name, oid,
507 &client_data->u_cred.uid,
508 &client_data->u_cred.gid,
509 &client_data->u_cred.gidlist,
510 &len);
511 if (status == GSS_S_COMPLETE) {
512 client_data->u_cred_set = TRUE;
513 client_data->u_cred.gidlen =
514 (short)len;
515 gettimeofday(&now,
516 (struct timezone *)NULL);
517 client_data->time_secs_set =
518 now.tv_sec;
519 *ucred = &client_data->u_cred;
520 } else
521 *ucred = NULL;
522 }
523 }
524 } else {
525 /*
526 * gid's already set;
527 * check if they have expired.
528 */
529 gettimeofday(&now, (struct timezone *)NULL);
530 if ((now.tv_sec - client_data->time_secs_set)
531 > gid_timeout) {
532 /* Refresh gid's */
533 status = gss_get_group_info(
534 client_data->u_cred.uid,
535 &client_data->u_cred.gid,
536 &client_data->u_cred.gidlist,
537 &len);
538 if (status == GSS_S_COMPLETE) {
539 client_data->u_cred.gidlen =
540 (short)len;
541 gettimeofday(&now,
542 (struct timezone *)NULL);
543 client_data->time_secs_set = now.tv_sec;
544 *ucred = &client_data->u_cred;
545 } else {
546 client_data->u_cred_set = FALSE;
547 *ucred = NULL;
548 }
549 }
550 else
551 *ucred = &client_data->u_cred;
552 }
553 }
554 if (cookie != NULL)
555 *cookie = client_data->cookie;
556
557 mutex_unlock(&client_data->clm);
558
559 return (TRUE);
560 }
561
562 /*
563 * Server side authentication for RPCSEC_GSS.
564 */
565
566 enum auth_stat
__svcrpcsec_gss(rqst,msg,no_dispatch)567 __svcrpcsec_gss(rqst, msg, no_dispatch)
568 struct svc_req *rqst;
569 struct rpc_msg *msg;
570 bool_t *no_dispatch;
571 {
572 XDR xdrs;
573 rpc_gss_creds creds;
574 rpc_gss_init_arg call_arg;
575 rpc_gss_init_res call_res, *retrans_result;
576 gss_buffer_desc output_token;
577 OM_uint32 gssstat, minor_stat, time_rec, ret_flags;
578 struct opaque_auth *cred;
579 svc_rpc_gss_data *client_data;
580 int ret;
581 svc_creds_list_t *sc;
582 SVCAUTH *svcauth;
583 svc_rpc_gss_parms_t *gss_parms;
584 gss_OID mech_type = GSS_C_NULL_OID;
585
586 /*
587 * Initialize response verifier to NULL verifier. If
588 * necessary, this will be changed later.
589 */
590 rqst->rq_xprt->xp_verf.oa_flavor = AUTH_NONE;
591 rqst->rq_xprt->xp_verf.oa_base = NULL;
592 rqst->rq_xprt->xp_verf.oa_length = 0;
593 /*
594 * Need to null out results to start with.
595 */
596 memset((char *)&call_res, 0, sizeof (call_res));
597
598 /*
599 * Pull out and check credential and verifier.
600 */
601 cred = &msg->rm_call.cb_cred;
602 if (cred->oa_length == 0) {
603 return (AUTH_BADCRED);
604 }
605
606 xdrmem_create(&xdrs, cred->oa_base, cred->oa_length, XDR_DECODE);
607
608 memset((char *)&creds, 0, sizeof (creds));
609 if (!__xdr_rpc_gss_creds(&xdrs, &creds)) {
610 XDR_DESTROY(&xdrs);
611 ret = AUTH_BADCRED;
612 goto error;
613 }
614 XDR_DESTROY(&xdrs);
615
616 /*
617 * If this is a control message and proc is GSSAPI_INIT, then
618 * create a client handle for this client. Otherwise, look up
619 * the existing handle.
620 */
621 if (creds.gss_proc == RPCSEC_GSS_INIT) {
622 if (creds.ctx_handle.length != 0) {
623 ret = AUTH_BADCRED;
624 goto error;
625 }
626 if ((client_data = create_client()) == NULL) {
627 ret = AUTH_FAILED;
628 goto error;
629 }
630 } else {
631 /*
632 * Only verify values for service parameter when proc
633 * not RPCSEC_GSS_INIT or RPCSEC_GSS_CONTINUE_INIT.
634 * RFC2203 says contents for sequence and service args
635 * are undefined for creation procs.
636 *
637 * Note: only need to check for *CONTINUE_INIT here because
638 * if() clause already checked for RPCSEC_GSS_INIT
639 */
640 if (creds.gss_proc != RPCSEC_GSS_CONTINUE_INIT) {
641 switch (creds.service) {
642 case rpc_gss_svc_none:
643 case rpc_gss_svc_integrity:
644 case rpc_gss_svc_privacy:
645 break;
646 default:
647 ret = AUTH_BADCRED;
648 goto error;
649 }
650 }
651 if (creds.ctx_handle.length == 0) {
652 ret = AUTH_BADCRED;
653 goto error;
654 }
655 if ((client_data = get_client(&creds.ctx_handle)) == NULL) {
656 ret = RPCSEC_GSS_NOCRED;
657 goto error;
658 }
659 }
660
661 /*
662 * lock the client data until it's safe; if it's already stale,
663 * no more processing is possible
664 */
665 mutex_lock(&client_data->clm);
666 if (client_data->stale) {
667 ret = RPCSEC_GSS_NOCRED;
668 goto error2;
669 }
670
671 /*
672 * Any response we send will use ctx_handle, so set it now;
673 * also set seq_window since this won't change.
674 */
675 call_res.ctx_handle.length = sizeof (client_data->key);
676 call_res.ctx_handle.value = (char *)&client_data->key;
677 call_res.seq_window = SEQ_WIN;
678
679 /*
680 * Set the appropriate wrap/unwrap routine for RPCSEC_GSS.
681 */
682 svcauth = __svc_get_svcauth(rqst->rq_xprt);
683 svcauth->svc_ah_ops = svc_rpc_gss_ops;
684 svcauth->svc_ah_private = (caddr_t)client_data;
685
686 /*
687 * Keep copy of parameters we'll need for response, for the
688 * sake of reentrancy (we don't want to look in the context
689 * data because when we are sending a response, another
690 * request may have come in.
691 */
692 gss_parms = &svcauth->svc_gss_parms;
693 gss_parms->established = client_data->established;
694 gss_parms->service = creds.service;
695 gss_parms->qop_rcvd = (uint_t)client_data->qop;
696 gss_parms->context = (void *)client_data->context;
697 gss_parms->seq_num = creds.seq_num;
698
699 if (!client_data->established) {
700 if (creds.gss_proc == RPCSEC_GSS_DATA) {
701 ret = RPCSEC_GSS_FAILED;
702 client_data->stale = TRUE;
703 goto error2;
704 }
705
706 /*
707 * If the context is not established, then only GSSAPI_INIT
708 * and _CONTINUE requests are valid.
709 */
710 if (creds.gss_proc != RPCSEC_GSS_INIT && creds.gss_proc !=
711 RPCSEC_GSS_CONTINUE_INIT) {
712 ret = RPCSEC_GSS_FAILED;
713 client_data->stale = TRUE;
714 goto error2;
715 }
716
717 /*
718 * call is for us, deserialize arguments
719 */
720 memset(&call_arg, 0, sizeof (call_arg));
721 if (!svc_getargs(rqst->rq_xprt, __xdr_rpc_gss_init_arg,
722 (caddr_t)&call_arg)) {
723 ret = RPCSEC_GSS_FAILED;
724 client_data->stale = TRUE;
725 goto error2;
726 }
727
728 gssstat = GSS_S_FAILURE;
729 minor_stat = 0;
730 rw_rdlock(&cred_lock);
731 /*
732 * set next sc to point to the server cred
733 * if the client_data contains server_creds
734 */
735 for (sc = svc_creds_list; sc != NULL; sc = sc->next) {
736 if (rqst->rq_prog != sc->program ||
737 rqst->rq_vers != sc->version)
738 continue;
739
740 mutex_lock(&sc->refresh_mutex);
741 gssstat = gss_accept_sec_context(&minor_stat,
742 &client_data->context,
743 sc->cred,
744 &call_arg,
745 GSS_C_NO_CHANNEL_BINDINGS,
746 &client_data->client_name,
747 &mech_type,
748 &output_token,
749 &ret_flags,
750 &time_rec,
751 NULL);
752
753 if (gssstat == GSS_S_CREDENTIALS_EXPIRED) {
754 if (rpc_gss_refresh_svc_cred(sc)) {
755 gssstat = gss_accept_sec_context(
756 &minor_stat,
757 &client_data->context,
758 sc->cred,
759 &call_arg,
760 GSS_C_NO_CHANNEL_BINDINGS,
761 &client_data->client_name,
762 &mech_type,
763 &output_token,
764 &ret_flags,
765 &time_rec,
766 NULL);
767 mutex_unlock(&sc->refresh_mutex);
768
769 } else {
770 mutex_unlock(&sc->refresh_mutex);
771 gssstat = GSS_S_NO_CRED;
772 break;
773 }
774
775 } else
776 mutex_unlock(&sc->refresh_mutex);
777
778 if (gssstat == GSS_S_COMPLETE) {
779 /*
780 * Server_creds was right - set it. Also
781 * set the raw and unix credentials at this
782 * point. This saves a lot of computation
783 * later when credentials are retrieved.
784 */
785 /*
786 * XXX server_creds will prob be stale
787 * after rpc_gss_refresh_svc_cred(), but
788 * it appears not to ever be referenced
789 * anyways.
790 */
791 mutex_lock(&sc->refresh_mutex);
792 client_data->server_creds = sc->cred;
793 client_data->raw_cred.version = creds.version;
794 client_data->raw_cred.service = creds.service;
795 client_data->raw_cred.svc_principal =
796 sc->server_name;
797 mutex_unlock(&sc->refresh_mutex);
798
799 if ((client_data->raw_cred.mechanism
800 = __rpc_gss_oid_to_mech(mech_type))
801 == NULL) {
802 gssstat = GSS_S_FAILURE;
803 (void) gss_release_buffer(&minor_stat,
804 &output_token);
805 } else if (!set_client_principal(client_data->
806 client_name, &client_data->
807 raw_cred.client_principal)) {
808 gssstat = GSS_S_FAILURE;
809 (void) gss_release_buffer(&minor_stat,
810 &output_token);
811 }
812 break;
813 }
814
815 if (gssstat == GSS_S_CONTINUE_NEEDED) {
816 /*
817 * XXX server_creds will prob be stale
818 * after rpc_gss_refresh_svc_cred(), but
819 * it appears not to ever be referenced
820 * anyways.
821 */
822 mutex_lock(&sc->refresh_mutex);
823 client_data->server_creds = sc->cred;
824 mutex_unlock(&sc->refresh_mutex);
825 break;
826 }
827
828 }
829 rw_unlock(&cred_lock);
830
831 call_res.gss_major = gssstat;
832 call_res.gss_minor = minor_stat;
833
834 xdr_free(__xdr_rpc_gss_init_arg, (caddr_t)&call_arg);
835
836 if (gssstat != GSS_S_COMPLETE &&
837 gssstat != GSS_S_CONTINUE_NEEDED) {
838 /*
839 * We have a failure - send response and delete
840 * the context. Don't dispatch. Set ctx_handle
841 * to NULL and seq_window to 0.
842 */
843 call_res.ctx_handle.length = 0;
844 call_res.ctx_handle.value = NULL;
845 call_res.seq_window = 0;
846
847 svc_sendreply(rqst->rq_xprt, __xdr_rpc_gss_init_res,
848 (caddr_t)&call_res);
849 *no_dispatch = TRUE;
850 ret = AUTH_OK;
851 client_data->stale = TRUE;
852 goto error2;
853 }
854
855 /*
856 * This step succeeded. Send a response, along with
857 * a token if there's one. Don't dispatch.
858 */
859 if (output_token.length != 0) {
860 GSS_COPY_BUFFER(call_res.token, output_token);
861 }
862
863 /*
864 * set response verifier: checksum of SEQ_WIN
865 */
866 if (gssstat == GSS_S_COMPLETE) {
867 if (!set_response_verf(rqst, msg, client_data,
868 (uint_t)SEQ_WIN)) {
869 ret = RPCSEC_GSS_FAILED;
870 client_data->stale = TRUE;
871 (void) gss_release_buffer(&minor_stat,
872 &output_token);
873 goto error2;
874 }
875 }
876
877 svc_sendreply(rqst->rq_xprt, __xdr_rpc_gss_init_res,
878 (caddr_t)&call_res);
879 /*
880 * Cache last response in case it is lost and the client
881 * retries on an established context.
882 */
883 (void) retrans_add(client_data, msg->rm_xid, &call_res);
884 *no_dispatch = TRUE;
885 (void) gss_release_buffer(&minor_stat, &output_token);
886
887 /*
888 * If appropriate, set established to TRUE *after* sending
889 * response (otherwise, the client will receive the final
890 * token encrypted)
891 */
892 if (gssstat == GSS_S_COMPLETE) {
893 /*
894 * Context is established. Set expiry time for
895 * context (the minimum of time_rec and max_lifetime).
896 */
897 client_data->seq_num = 1;
898 if (time_rec == GSS_C_INDEFINITE) {
899 if (max_lifetime != GSS_C_INDEFINITE)
900 client_data->expiration =
901 max_lifetime + time(0);
902 else
903 client_data->expiration =
904 GSS_C_INDEFINITE;
905 } else if (max_lifetime == GSS_C_INDEFINITE ||
906 max_lifetime > time_rec)
907 client_data->expiration = time_rec + time(0);
908 else
909 client_data->expiration = max_lifetime +
910 time(0);
911 client_data->established = TRUE;
912 }
913
914 } else {
915 if ((creds.gss_proc != RPCSEC_GSS_DATA) &&
916 (creds.gss_proc != RPCSEC_GSS_DESTROY)) {
917
918 switch (creds.gss_proc) {
919
920 case RPCSEC_GSS_CONTINUE_INIT:
921 /*
922 * This is an established context. Continue to
923 * satisfy retried continue init requests out of
924 * the retransmit cache. Throw away any that don't
925 * have a matching xid or the cach is empty.
926 * Delete the retransmit cache once the client sends
927 * a data request.
928 */
929 if (client_data->retrans_data &&
930 (client_data->retrans_data->xid == msg->rm_xid)) {
931
932 retrans_result = &client_data->retrans_data->result;
933 if (set_response_verf(rqst, msg, client_data,
934 (uint_t)retrans_result->seq_window)) {
935
936 gss_parms->established = FALSE;
937 svc_sendreply(rqst->rq_xprt,
938 __xdr_rpc_gss_init_res,
939 (caddr_t)retrans_result);
940 *no_dispatch = TRUE;
941 goto success;
942 }
943 }
944 /* fall thru to default */
945
946 default:
947 syslog(LOG_ERR, "_svcrpcsec_gss: non-data request "
948 "on an established context");
949 ret = AUTH_FAILED;
950 goto error2;
951 }
952 }
953
954 /*
955 * Once the context is established and there is no more
956 * retransmission of last continue init request, it is safe
957 * to delete the retransmit cache entry.
958 */
959 if (client_data->retrans_data)
960 retrans_del(client_data);
961
962 /*
963 * Context is already established. Check verifier, and
964 * note parameters we will need for response in gss_parms.
965 */
966 if (!check_verf(msg, client_data->context,
967 &gss_parms->qop_rcvd)) {
968 ret = RPCSEC_GSS_NOCRED;
969 goto error2;
970 }
971 /*
972 * Check and invoke callback if necessary.
973 */
974 if (!client_data->done_docallback) {
975 client_data->done_docallback = TRUE;
976 client_data->qop = gss_parms->qop_rcvd;
977 client_data->raw_cred.qop = __rpc_gss_num_to_qop(
978 client_data->raw_cred.mechanism,
979 gss_parms->qop_rcvd);
980 client_data->raw_cred.service = creds.service;
981 if (!do_callback(rqst, client_data)) {
982 ret = AUTH_FAILED;
983 client_data->stale = TRUE;
984 goto error2;
985 }
986 }
987
988 /*
989 * If the context was locked, make sure that the client
990 * has not changed QOP.
991 */
992 if (client_data->locked &&
993 gss_parms->qop_rcvd != client_data->qop) {
994 ret = AUTH_BADVERF;
995 goto error2;
996 }
997
998 /*
999 * Validate sequence number.
1000 */
1001 if (!check_seq(client_data, creds.seq_num,
1002 &client_data->stale)) {
1003 if (client_data->stale)
1004 ret = RPCSEC_GSS_FAILED;
1005 else {
1006 /*
1007 * Operational error, drop packet silently.
1008 * The client will recover after timing out,
1009 * assuming this is a client error and not
1010 * a relpay attack. Don't dispatch.
1011 */
1012 ret = AUTH_OK;
1013 *no_dispatch = TRUE;
1014 }
1015 goto error2;
1016 }
1017
1018 /*
1019 * set response verifier
1020 */
1021 if (!set_response_verf(rqst, msg, client_data, creds.seq_num)) {
1022 ret = RPCSEC_GSS_FAILED;
1023 client_data->stale = TRUE;
1024 goto error2;
1025 }
1026
1027 /*
1028 * If this is a control message RPCSEC_GSS_DESTROY, process
1029 * the call; otherwise, return AUTH_OK so it will be
1030 * dispatched to the application server.
1031 */
1032 if (creds.gss_proc == RPCSEC_GSS_DESTROY) {
1033 svc_sendreply(rqst->rq_xprt, xdr_void, NULL);
1034 *no_dispatch = TRUE;
1035 client_data->stale = TRUE;
1036
1037 } else {
1038 /*
1039 * This should be an RPCSEC_GSS_DATA request.
1040 * If context is locked, make sure that the client
1041 * has not changed the security service.
1042 */
1043 if (client_data->locked &&
1044 client_data->raw_cred.service != creds.service) {
1045 ret = AUTH_FAILED;
1046 goto error2;
1047 }
1048
1049 /*
1050 * Set client credentials to raw credential
1051 * structure in context. This is okay, since
1052 * this will not change during the lifetime of
1053 * the context (so it's MT safe).
1054 */
1055 rqst->rq_clntcred = (char *)&client_data->raw_cred;
1056 }
1057 }
1058
1059 success:
1060 /*
1061 * Success.
1062 */
1063 if (creds.ctx_handle.length != 0)
1064 xdr_free(__xdr_rpc_gss_creds, (caddr_t)&creds);
1065 mutex_unlock(&client_data->clm);
1066 return (AUTH_OK);
1067 error2:
1068 mutex_unlock(&client_data->clm);
1069 error:
1070 /*
1071 * Failure.
1072 */
1073 if (creds.ctx_handle.length != 0)
1074 xdr_free(__xdr_rpc_gss_creds, (caddr_t)&creds);
1075 return (ret);
1076 }
1077
1078 /*
1079 * Check verifier. The verifier is the checksum of the RPC header
1080 * upto and including the credentials field.
1081 */
1082 static bool_t
check_verf(msg,context,qop_state)1083 check_verf(msg, context, qop_state)
1084 struct rpc_msg *msg;
1085 gss_ctx_id_t context;
1086 int *qop_state;
1087 {
1088 int *buf, *tmp;
1089 int hdr[32];
1090 struct opaque_auth *oa;
1091 int len;
1092 gss_buffer_desc msg_buf;
1093 gss_buffer_desc tok_buf;
1094 OM_uint32 gssstat, minor_stat;
1095
1096 /*
1097 * We have to reconstruct the RPC header from the previously
1098 * parsed information, since we haven't kept the header intact.
1099 */
1100
1101 oa = &msg->rm_call.cb_cred;
1102 if (oa->oa_length > MAX_AUTH_BYTES)
1103 return (FALSE);
1104
1105 /* 8 XDR units from the IXDR macro calls. */
1106 if (sizeof (hdr) < (8 * BYTES_PER_XDR_UNIT +
1107 RNDUP(oa->oa_length)))
1108 return (FALSE);
1109 buf = hdr;
1110
1111 IXDR_PUT_U_INT32(buf, msg->rm_xid);
1112 IXDR_PUT_ENUM(buf, msg->rm_direction);
1113 IXDR_PUT_U_INT32(buf, msg->rm_call.cb_rpcvers);
1114 IXDR_PUT_U_INT32(buf, msg->rm_call.cb_prog);
1115 IXDR_PUT_U_INT32(buf, msg->rm_call.cb_vers);
1116 IXDR_PUT_U_INT32(buf, msg->rm_call.cb_proc);
1117 IXDR_PUT_ENUM(buf, oa->oa_flavor);
1118 IXDR_PUT_U_INT32(buf, oa->oa_length);
1119 if (oa->oa_length) {
1120 len = RNDUP(oa->oa_length);
1121 tmp = buf;
1122 buf += len / sizeof (int);
1123 *(buf - 1) = 0;
1124 (void) memcpy((caddr_t)tmp, oa->oa_base, oa->oa_length);
1125 }
1126 len = ((char *)buf) - (char *)hdr;
1127 msg_buf.length = len;
1128 msg_buf.value = (char *)hdr;
1129 oa = &msg->rm_call.cb_verf;
1130 tok_buf.length = oa->oa_length;
1131 tok_buf.value = oa->oa_base;
1132
1133 gssstat = gss_verify(&minor_stat, context, &msg_buf, &tok_buf,
1134 qop_state);
1135 if (gssstat != GSS_S_COMPLETE)
1136 return (FALSE);
1137 return (TRUE);
1138 }
1139
1140 /*
1141 * Set response verifier. This is the checksum of the given number.
1142 * (e.g. sequence number or sequence window)
1143 */
1144 static bool_t
set_response_verf(rqst,msg,cl,num)1145 set_response_verf(rqst, msg, cl, num)
1146 struct svc_req *rqst;
1147 struct rpc_msg *msg;
1148 svc_rpc_gss_data *cl;
1149 uint_t num;
1150 {
1151 OM_uint32 minor;
1152 gss_buffer_desc in_buf, out_buf;
1153 uint_t num_net;
1154
1155 num_net = (uint_t)htonl(num);
1156 in_buf.length = sizeof (num);
1157 in_buf.value = (char *)&num_net;
1158 if (gss_sign(&minor, cl->context, cl->qop, &in_buf,
1159 &out_buf) != GSS_S_COMPLETE)
1160 return (FALSE);
1161 rqst->rq_xprt->xp_verf.oa_flavor = RPCSEC_GSS;
1162 rqst->rq_xprt->xp_verf.oa_base = msg->rm_call.cb_verf.oa_base;
1163 rqst->rq_xprt->xp_verf.oa_length = out_buf.length;
1164 memcpy(rqst->rq_xprt->xp_verf.oa_base, out_buf.value,
1165 out_buf.length);
1166 (void) gss_release_buffer(&minor, &out_buf);
1167 return (TRUE);
1168 }
1169
1170 /*
1171 * Create client context.
1172 */
1173 static svc_rpc_gss_data *
create_client()1174 create_client()
1175 {
1176 svc_rpc_gss_data *client_data;
1177 static uint_t key = 1;
1178
1179 client_data = (svc_rpc_gss_data *) malloc(sizeof (*client_data));
1180 if (client_data == NULL)
1181 return (NULL);
1182 memset((char *)client_data, 0, sizeof (*client_data));
1183
1184 /*
1185 * set up client data structure
1186 */
1187 client_data->established = FALSE;
1188 client_data->locked = FALSE;
1189 client_data->u_cred_set = FALSE;
1190 client_data->context = GSS_C_NO_CONTEXT;
1191 client_data->expiration = init_lifetime + time(0);
1192 client_data->ref_cnt = 1;
1193 client_data->qop = GSS_C_QOP_DEFAULT;
1194 client_data->done_docallback = FALSE;
1195 client_data->stale = FALSE;
1196 client_data->time_secs_set = 0;
1197 client_data->retrans_data = NULL;
1198 mutex_init(&client_data->clm, USYNC_THREAD, NULL);
1199 /*
1200 * Check totals. If we've hit the limit, we destroy a context
1201 * based on LRU method.
1202 */
1203 mutex_lock(&ctx_mutex);
1204 if (num_gss_contexts >= max_gss_contexts) {
1205 /*
1206 * now try on LRU basis
1207 */
1208 drop_lru_client();
1209 if (num_gss_contexts >= max_gss_contexts) {
1210 mutex_unlock(&ctx_mutex);
1211 free((char *)client_data);
1212 return (NULL);
1213 }
1214 }
1215
1216 /*
1217 * The client context handle is a 32-bit key (unsigned int).
1218 * The key is incremented until there is no duplicate for it.
1219 */
1220 for (;;) {
1221 client_data->key = key++;
1222 if (find_client(client_data->key) == NULL) {
1223 insert_client(client_data);
1224 /*
1225 * Set cleanup callback if we haven't.
1226 */
1227 if (!cleanup_cb_set) {
1228 old_cleanup_cb =
1229 (void (*)()) __svc_set_proc_cleanup_cb(
1230 (void *)ctx_cleanup);
1231 cleanup_cb_set = TRUE;
1232 }
1233 mutex_unlock(&ctx_mutex);
1234 return (client_data);
1235 }
1236 }
1237 /*NOTREACHED*/
1238 }
1239
1240 /*
1241 * Insert client context into hash list and LRU list.
1242 */
1243 static void
insert_client(client_data)1244 insert_client(client_data)
1245 svc_rpc_gss_data *client_data;
1246 {
1247 svc_rpc_gss_data *cl;
1248 int index = (client_data->key & HASHMASK);
1249
1250 client_data->prev = NULL;
1251 cl = clients[index];
1252 if ((client_data->next = cl) != NULL)
1253 cl->prev = client_data;
1254 clients[index] = client_data;
1255
1256 client_data->lru_prev = NULL;
1257 if ((client_data->lru_next = lru_first) != NULL)
1258 lru_first->lru_prev = client_data;
1259 else
1260 lru_last = client_data;
1261 lru_first = client_data;
1262
1263 num_gss_contexts++;
1264 }
1265
1266 /*
1267 * Fetch a client, given the client context handle. Move it to the
1268 * top of the LRU list since this is the most recently used context.
1269 */
1270 static svc_rpc_gss_data *
get_client(ctx_handle)1271 get_client(ctx_handle)
1272 gss_buffer_t ctx_handle;
1273 {
1274 uint_t key = *(uint_t *)ctx_handle->value;
1275 svc_rpc_gss_data *cl;
1276
1277 mutex_lock(&ctx_mutex);
1278 if ((cl = find_client(key)) != NULL) {
1279 mutex_lock(&cl->clm);
1280 if (cl->stale) {
1281 mutex_unlock(&cl->clm);
1282 mutex_unlock(&ctx_mutex);
1283 return (NULL);
1284 }
1285 cl->ref_cnt++;
1286 mutex_unlock(&cl->clm);
1287 if (cl != lru_first) {
1288 cl->lru_prev->lru_next = cl->lru_next;
1289 if (cl->lru_next != NULL)
1290 cl->lru_next->lru_prev = cl->lru_prev;
1291 else
1292 lru_last = cl->lru_prev;
1293 cl->lru_prev = NULL;
1294 cl->lru_next = lru_first;
1295 lru_first->lru_prev = cl;
1296 lru_first = cl;
1297 }
1298 }
1299 mutex_unlock(&ctx_mutex);
1300 return (cl);
1301 }
1302
1303 /*
1304 * Given the client context handle, find the context corresponding to it.
1305 * Don't change its LRU state since it may not be used.
1306 */
1307 static svc_rpc_gss_data *
find_client(key)1308 find_client(key)
1309 uint_t key;
1310 {
1311 int index = (key & HASHMASK);
1312 svc_rpc_gss_data *cl;
1313
1314 for (cl = clients[index]; cl != NULL; cl = cl->next) {
1315 if (cl->key == key)
1316 break;
1317 }
1318 return (cl);
1319 }
1320
1321 /*
1322 * Destroy a client context.
1323 */
1324 static void
destroy_client(client_data)1325 destroy_client(client_data)
1326 svc_rpc_gss_data *client_data;
1327 {
1328 OM_uint32 minor;
1329 int index = (client_data->key & HASHMASK);
1330
1331 /*
1332 * remove from hash list
1333 */
1334 if (client_data->prev == NULL)
1335 clients[index] = client_data->next;
1336 else
1337 client_data->prev->next = client_data->next;
1338 if (client_data->next != NULL)
1339 client_data->next->prev = client_data->prev;
1340
1341 /*
1342 * remove from LRU list
1343 */
1344 if (client_data->lru_prev == NULL)
1345 lru_first = client_data->lru_next;
1346 else
1347 client_data->lru_prev->lru_next = client_data->lru_next;
1348 if (client_data->lru_next != NULL)
1349 client_data->lru_next->lru_prev = client_data->lru_prev;
1350 else
1351 lru_last = client_data->lru_prev;
1352
1353 /*
1354 * If there is a GSS context, clean up GSS state.
1355 */
1356 if (client_data->context != GSS_C_NO_CONTEXT) {
1357 (void) gss_delete_sec_context(&minor, &client_data->context,
1358 NULL);
1359 if (client_data->client_name)
1360 (void) gss_release_name(&minor, &client_data->client_name);
1361 if (client_data->raw_cred.client_principal)
1362 free((char *)client_data->raw_cred.client_principal);
1363 if (client_data->u_cred.gidlist != NULL)
1364 free((char *)client_data->u_cred.gidlist);
1365 if (client_data->deleg != GSS_C_NO_CREDENTIAL)
1366 (void) gss_release_cred(&minor, &client_data->deleg);
1367 }
1368
1369 if (client_data->retrans_data != NULL)
1370 retrans_del(client_data);
1371
1372 free(client_data);
1373 num_gss_contexts--;
1374 }
1375
1376 /*
1377 * Check for expired client contexts.
1378 */
1379 static void
sweep_clients()1380 sweep_clients()
1381 {
1382 svc_rpc_gss_data *cl, *next;
1383 int index;
1384
1385 for (index = 0; index < HASHMOD; index++) {
1386 cl = clients[index];
1387 while (cl) {
1388 next = cl->next;
1389 mutex_lock(&cl->clm);
1390 if ((cl->expiration != GSS_C_INDEFINITE &&
1391 cl->expiration <= time(0)) || cl->stale) {
1392 cl->stale = TRUE;
1393 if (cl->ref_cnt == 0) {
1394 mutex_unlock(&cl->clm);
1395 destroy_client(cl);
1396 } else
1397 mutex_unlock(&cl->clm);
1398 } else
1399 mutex_unlock(&cl->clm);
1400 cl = next;
1401 }
1402 }
1403 last_swept = time(0);
1404 }
1405
1406 /*
1407 * Drop the least recently used client context, if possible.
1408 */
1409 static void
drop_lru_client()1410 drop_lru_client()
1411 {
1412 mutex_lock(&lru_last->clm);
1413 lru_last->stale = TRUE;
1414 mutex_unlock(&lru_last->clm);
1415 if (lru_last->ref_cnt == 0)
1416 destroy_client(lru_last);
1417 else
1418 sweep_clients();
1419 }
1420
1421 /*
1422 * find service credentials
1423 * return cred if found,
1424 * other wise, NULL
1425 */
1426
1427 svc_creds_list_t *
find_svc_cred(char * service_name,uint_t program,uint_t version)1428 find_svc_cred(char *service_name, uint_t program, uint_t version) {
1429
1430 svc_creds_list_t *sc;
1431
1432 if (!svc_creds_list)
1433 return (NULL);
1434
1435 for (sc = svc_creds_list; sc != NULL; sc = sc->next) {
1436 if (program != sc->program || version != sc->version)
1437 continue;
1438
1439 if (strcmp(service_name, sc->server_name) != 0)
1440 continue;
1441 return (sc);
1442 }
1443 return (NULL);
1444 }
1445
1446 /*
1447 * Set the server principal name.
1448 */
1449 bool_t
__rpc_gss_set_svc_name(server_name,mech,req_time,program,version)1450 __rpc_gss_set_svc_name(server_name, mech, req_time, program, version)
1451 char *server_name;
1452 char *mech;
1453 OM_uint32 req_time;
1454 uint_t program;
1455 uint_t version;
1456 {
1457 gss_name_t name;
1458 svc_creds_list_t *svc_cred;
1459 gss_OID mechanism;
1460 gss_OID_set_desc oid_set_desc;
1461 gss_OID_set oid_set;
1462 OM_uint32 ret_time;
1463 OM_uint32 major, minor;
1464 gss_buffer_desc name_buf;
1465
1466 if (!__rpc_gss_mech_to_oid(mech, &mechanism)) {
1467 return (FALSE);
1468 }
1469
1470 name_buf.value = server_name;
1471 name_buf.length = strlen(server_name);
1472 major = gss_import_name(&minor, &name_buf,
1473 (gss_OID) GSS_C_NT_HOSTBASED_SERVICE, &name);
1474 if (major != GSS_S_COMPLETE) {
1475 return (FALSE);
1476 }
1477
1478 /* Check if there is already an entry in the svc_creds_list. */
1479 rw_wrlock(&cred_lock);
1480 if (svc_cred = find_svc_cred(server_name, program, version)) {
1481
1482 major = gss_add_cred(&minor, svc_cred->cred, name,
1483 mechanism, GSS_C_ACCEPT,
1484 0, req_time, NULL,
1485 &oid_set, NULL,
1486 &ret_time);
1487 (void) gss_release_name(&minor, &name);
1488 if (major == GSS_S_COMPLETE) {
1489 /*
1490 * Successfully added the mech to the cred handle
1491 * free the existing oid_set in svc_cred
1492 */
1493 gss_release_oid_set(&minor, &svc_cred->oid_set);
1494 svc_cred->oid_set = oid_set;
1495 rw_unlock(&cred_lock);
1496 return (TRUE);
1497 } else if (major == GSS_S_DUPLICATE_ELEMENT) {
1498 rw_unlock(&cred_lock);
1499 return (TRUE);
1500 } else if (major == GSS_S_CREDENTIALS_EXPIRED) {
1501 if (rpc_gss_refresh_svc_cred(svc_cred)) {
1502 rw_unlock(&cred_lock);
1503 return (TRUE);
1504 } else {
1505 rw_unlock(&cred_lock);
1506 return (FALSE);
1507 }
1508 } else {
1509 rw_unlock(&cred_lock);
1510 return (FALSE);
1511 }
1512 } else {
1513 svc_cred = (svc_creds_list_t *)malloc(sizeof (*svc_cred));
1514 if (svc_cred == NULL) {
1515 (void) gss_release_name(&minor, &name);
1516 rw_unlock(&cred_lock);
1517 return (FALSE);
1518 }
1519 oid_set_desc.count = 1;
1520 oid_set_desc.elements = mechanism;
1521 major = gss_acquire_cred(&minor, name, req_time,
1522 &oid_set_desc,
1523 GSS_C_ACCEPT,
1524 &svc_cred->cred,
1525 &oid_set, &ret_time);
1526
1527 if (major != GSS_S_COMPLETE) {
1528 (void) gss_release_name(&minor, &name);
1529 free(svc_cred);
1530 rw_unlock(&cred_lock);
1531 return (FALSE);
1532 }
1533
1534 svc_cred->name = name;
1535 svc_cred->program = program;
1536 svc_cred->version = version;
1537 svc_cred->req_time = req_time;
1538 svc_cred->oid_set = oid_set;
1539 svc_cred->server_name = strdup(server_name);
1540 if (svc_cred->server_name == NULL) {
1541 (void) gss_release_name(&minor, &name);
1542 free((char *)svc_cred);
1543 rw_unlock(&cred_lock);
1544 return (FALSE);
1545 }
1546 mutex_init(&svc_cred->refresh_mutex, USYNC_THREAD, NULL);
1547
1548 svc_cred->next = svc_creds_list;
1549 svc_creds_list = svc_cred;
1550 svc_creds_count++;
1551 rw_unlock(&cred_lock);
1552
1553 return (TRUE);
1554 }
1555 }
1556 /*
1557 * Refresh server credentials.
1558 */
1559 static bool_t
rpc_gss_refresh_svc_cred(svc_cred)1560 rpc_gss_refresh_svc_cred(svc_cred)
1561 svc_creds_list_t *svc_cred;
1562 {
1563 OM_uint32 major, minor;
1564 gss_OID_set oid_set;
1565 OM_uint32 ret_time;
1566
1567 (void) gss_release_cred(&minor, &svc_cred->cred);
1568 svc_cred->cred = GSS_C_NO_CREDENTIAL;
1569 major = gss_acquire_cred(&minor, svc_cred->name, svc_cred->req_time,
1570 svc_cred->oid_set, GSS_C_ACCEPT, &svc_cred->cred, &oid_set,
1571 &ret_time);
1572 if (major != GSS_S_COMPLETE) {
1573 return (FALSE);
1574 }
1575 gss_release_oid_set(&minor, &svc_cred->oid_set);
1576 svc_cred->oid_set = oid_set;
1577 return (TRUE);
1578 }
1579
1580 /*
1581 * Encrypt the serialized arguments from xdr_func applied to xdr_ptr
1582 * and write the result to xdrs.
1583 */
1584 static bool_t
svc_rpc_gss_wrap(auth,out_xdrs,xdr_func,xdr_ptr)1585 svc_rpc_gss_wrap(auth, out_xdrs, xdr_func, xdr_ptr)
1586 SVCAUTH *auth;
1587 XDR *out_xdrs;
1588 bool_t (*xdr_func)();
1589 caddr_t xdr_ptr;
1590 {
1591 svc_rpc_gss_parms_t *gss_parms = &auth->svc_gss_parms;
1592
1593 /*
1594 * If context is not established, or if neither integrity nor
1595 * privacy service is used, don't wrap - just XDR encode.
1596 * Otherwise, wrap data using service and QOP parameters.
1597 */
1598 if (!gss_parms->established ||
1599 gss_parms->service == rpc_gss_svc_none)
1600 return ((*xdr_func)(out_xdrs, xdr_ptr));
1601
1602 return (__rpc_gss_wrap_data(gss_parms->service,
1603 (OM_uint32)gss_parms->qop_rcvd,
1604 (gss_ctx_id_t)gss_parms->context,
1605 gss_parms->seq_num,
1606 out_xdrs, xdr_func, xdr_ptr));
1607 }
1608
1609 /*
1610 * Decrypt the serialized arguments and XDR decode them.
1611 */
1612 static bool_t
svc_rpc_gss_unwrap(auth,in_xdrs,xdr_func,xdr_ptr)1613 svc_rpc_gss_unwrap(auth, in_xdrs, xdr_func, xdr_ptr)
1614 SVCAUTH *auth;
1615 XDR *in_xdrs;
1616 bool_t (*xdr_func)();
1617 caddr_t xdr_ptr;
1618 {
1619 svc_rpc_gss_parms_t *gss_parms = &auth->svc_gss_parms;
1620
1621 /*
1622 * If context is not established, or if neither integrity nor
1623 * privacy service is used, don't unwrap - just XDR decode.
1624 * Otherwise, unwrap data.
1625 */
1626 if (!gss_parms->established ||
1627 gss_parms->service == rpc_gss_svc_none)
1628 return ((*xdr_func)(in_xdrs, xdr_ptr));
1629
1630 return (__rpc_gss_unwrap_data(gss_parms->service,
1631 (gss_ctx_id_t)gss_parms->context,
1632 gss_parms->seq_num,
1633 gss_parms->qop_rcvd,
1634 in_xdrs, xdr_func, xdr_ptr));
1635 }
1636
1637 int
__rpc_gss_svc_max_data_length(req,max_tp_unit_len)1638 __rpc_gss_svc_max_data_length(req, max_tp_unit_len)
1639 struct svc_req *req;
1640 int max_tp_unit_len;
1641 {
1642 SVCAUTH *svcauth;
1643 svc_rpc_gss_parms_t *gss_parms;
1644
1645 svcauth = __svc_get_svcauth(req->rq_xprt);
1646 gss_parms = &svcauth->svc_gss_parms;
1647
1648 if (!gss_parms->established || max_tp_unit_len <= 0)
1649 return (0);
1650
1651 return (__find_max_data_length(gss_parms->service,
1652 (gss_ctx_id_t)gss_parms->context,
1653 gss_parms->qop_rcvd, max_tp_unit_len));
1654 }
1655
1656 /*
1657 * Add retransmit entry to the context cache entry for a new xid.
1658 * If there is already an entry, delete it before adding the new one.
1659 */
retrans_add(client,xid,result)1660 static void retrans_add(client, xid, result)
1661 svc_rpc_gss_data *client;
1662 uint32_t xid;
1663 rpc_gss_init_res *result;
1664 {
1665 retrans_entry *rdata;
1666
1667 if (client->retrans_data && client->retrans_data->xid == xid)
1668 return;
1669
1670 rdata = (retrans_entry *) malloc(sizeof (*rdata));
1671 if (rdata == NULL)
1672 return;
1673
1674 rdata->xid = xid;
1675 rdata->result = *result;
1676
1677 if (result->token.length != 0) {
1678 GSS_DUP_BUFFER(rdata->result.token, result->token);
1679 }
1680
1681 if (client->retrans_data)
1682 retrans_del(client);
1683
1684 client->retrans_data = rdata;
1685 }
1686
1687 /*
1688 * Delete the retransmit data from the context cache entry.
1689 */
retrans_del(client)1690 static void retrans_del(client)
1691 svc_rpc_gss_data *client;
1692 {
1693 retrans_entry *rdata;
1694 OM_uint32 minor_stat;
1695
1696 if (client->retrans_data == NULL)
1697 return;
1698
1699 rdata = client->retrans_data;
1700 if (rdata->result.token.length != 0) {
1701 (void) gss_release_buffer(&minor_stat, &rdata->result.token);
1702 }
1703
1704 free((caddr_t)rdata);
1705 client->retrans_data = NULL;
1706 }
1707