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