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 2015 Nexenta Systems, Inc. All rights reserved.
24 * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved.
25 * Copyright 2012 Milan Jurik. All rights reserved.
26 */
27
28 /*
29 * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved.
30 *
31 * $Id: svc_auth_gssapi.c,v 1.19 1994/10/27 12:38:51 jik Exp $
32 */
33
34 /*
35 * Server side handling of RPCSEC_GSS flavor.
36 */
37
38 #include <sys/systm.h>
39 #include <sys/kstat.h>
40 #include <sys/cmn_err.h>
41 #include <sys/debug.h>
42 #include <sys/types.h>
43 #include <sys/time.h>
44 #include <gssapi/gssapi.h>
45 #include <gssapi/gssapi_ext.h>
357 mutex_exit(&cl->clm);
358 destroy_client(cl);
359 svcauth->svc_ah_private = NULL;
360 } else
361 mutex_exit(&cl->clm);
362 }
363
364 /*
365 * Check for other expired contexts.
366 */
367 if ((gethrestime_sec() - last_swept) > sweep_interval)
368 sweep_clients(FALSE);
369
370 mutex_exit(&ctx_mutex);
371 }
372
373 /*
374 * Shift the array arr of length arrlen right by nbits bits.
375 */
376 static void
377 shift_bits(arr, arrlen, nbits)
378 uint_t *arr;
379 int arrlen;
380 int nbits;
381 {
382 int i, j;
383 uint_t lo, hi;
384
385 /*
386 * If the number of bits to be shifted exceeds SEQ_WIN, just
387 * zero out the array.
388 */
389 if (nbits < SEQ_WIN) {
390 for (i = 0; i < nbits; i++) {
391 hi = 0;
392 for (j = 0; j < arrlen; j++) {
393 lo = arr[j] & SEQ_LO_BIT;
394 arr[j] >>= 1;
395 if (hi)
396 arr[j] |= SEQ_HI_BIT;
397 hi = lo;
398 }
399 }
400 } else {
401 for (j = 0; j < arrlen; j++)
402 arr[j] = 0;
403 }
404 }
405
406 /*
407 * Check that the received sequence number seq_num is valid.
408 */
409 static bool_t
410 check_seq(cl, seq_num, kill_context)
411 svc_rpc_gss_data *cl;
412 uint_t seq_num;
413 bool_t *kill_context;
414 {
415 int i, j;
416 uint_t bit;
417
418 /*
419 * If it exceeds the maximum, kill context.
420 */
421 if (seq_num >= SEQ_MAX) {
422 *kill_context = TRUE;
423 RPCGSS_LOG0(4, "check_seq: seq_num not valid\n");
424 return (FALSE);
425 }
426
427 /*
428 * If greater than the last seen sequence number, just shift
429 * the sequence window so that it starts at the new sequence
430 * number and extends downwards by SEQ_WIN.
431 */
432 if (seq_num > cl->seq_num) {
433 (void) shift_bits(cl->seq_bits, SEQ_ARR_SIZE,
448
449 /*
450 * If within sequence window, set the bit corresponding to it
451 * if not already seen; if already seen, return failure.
452 */
453 j = SEQ_MASK - (i & SEQ_MASK);
454 bit = j > 0 ? (1 << j) : 1;
455 i >>= DIV_BY_32;
456 if (cl->seq_bits[i] & bit) {
457 RPCGSS_LOG0(4, "check_seq: sequence number already seen\n");
458 return (FALSE);
459 }
460 cl->seq_bits[i] |= bit;
461 return (TRUE);
462 }
463
464 /*
465 * Set server callback.
466 */
467 bool_t
468 rpc_gss_set_callback(cb)
469 rpc_gss_callback_t *cb;
470 {
471 rpc_gss_cblist_t *cbl, *tmp;
472
473 if (cb->callback == NULL) {
474 RPCGSS_LOG0(1, "rpc_gss_set_callback: no callback to set\n");
475 return (FALSE);
476 }
477
478 /* check if there is already an entry in the rpc_gss_cblist. */
479 mutex_enter(&cb_mutex);
480 if (rpc_gss_cblist) {
481 for (tmp = rpc_gss_cblist; tmp != NULL; tmp = tmp->next) {
482 if ((tmp->cb.callback == cb->callback) &&
483 (tmp->cb.version == cb->version) &&
484 (tmp->cb.program == cb->program)) {
485 mutex_exit(&cb_mutex);
486 return (TRUE);
487 }
488 }
489 }
491 /* Not in rpc_gss_cblist. Create a new entry. */
492 if ((cbl = (rpc_gss_cblist_t *)kmem_alloc(sizeof (*cbl), KM_SLEEP))
493 == NULL) {
494 mutex_exit(&cb_mutex);
495 return (FALSE);
496 }
497 cbl->cb = *cb;
498 cbl->next = rpc_gss_cblist;
499 rpc_gss_cblist = cbl;
500 mutex_exit(&cb_mutex);
501 return (TRUE);
502 }
503
504 /*
505 * Locate callback (if specified) and call server. Release any
506 * delegated credentials unless passed to server and the server
507 * accepts the context. If a callback is not specified, accept
508 * the incoming context.
509 */
510 static bool_t
511 do_callback(req, client_data)
512 struct svc_req *req;
513 svc_rpc_gss_data *client_data;
514 {
515 rpc_gss_cblist_t *cbl;
516 bool_t ret = TRUE, found = FALSE;
517 rpc_gss_lock_t lock;
518 OM_uint32 minor;
519 mutex_enter(&cb_mutex);
520 for (cbl = rpc_gss_cblist; cbl != NULL; cbl = cbl->next) {
521 if (req->rq_prog != cbl->cb.program ||
522 req->rq_vers != cbl->cb.version)
523 continue;
524 found = TRUE;
525 lock.locked = FALSE;
526 lock.raw_cred = &client_data->raw_cred;
527 ret = (*cbl->cb.callback)(req, client_data->deleg,
528 client_data->context, &lock, &client_data->cookie);
529 req->rq_xprt->xp_cookie = client_data->cookie;
530
531 if (ret) {
532 client_data->locked = lock.locked;
533 client_data->deleg = GSS_C_NO_CREDENTIAL;
534 }
535 break;
536 }
537 if (!found) {
538 if (client_data->deleg != GSS_C_NO_CREDENTIAL) {
539 (void) kgss_release_cred(&minor, &client_data->deleg,
540 crgetuid(CRED()));
541 client_data->deleg = GSS_C_NO_CREDENTIAL;
542 }
543 }
544 mutex_exit(&cb_mutex);
545 return (ret);
546 }
547
548 /*
549 * Get caller credentials.
550 */
551 bool_t
552 rpc_gss_getcred(req, rcred, ucred, cookie)
553 struct svc_req *req;
554 rpc_gss_rawcred_t **rcred;
555 rpc_gss_ucred_t **ucred;
556 void **cookie;
557 {
558 SVCAUTH *svcauth;
559 svc_rpc_gss_data *client_data;
560 int gssstat, gidlen;
561
562 svcauth = &req->rq_xprt->xp_auth;
563 client_data = (svc_rpc_gss_data *)svcauth->svc_ah_private;
564
565 mutex_enter(&client_data->clm);
566
567 if (rcred != NULL) {
568 svcauth->raw_cred = client_data->raw_cred;
569 *rcred = &svcauth->raw_cred;
570 }
571 if (ucred != NULL) {
572 *ucred = &client_data->u_cred;
573
574 if (client_data->u_cred_set == 0 ||
575 client_data->u_cred_set < gethrestime_sec()) {
576 if (client_data->u_cred_set == 0) {
577 if ((gssstat = kgsscred_expname_to_unix_cred(
578 &client_data->client_name,
579 &client_data->u_cred.uid,
580 &client_data->u_cred.gid,
581 &client_data->u_cred.gidlist,
582 &gidlen, crgetuid(CRED()))) != GSS_S_COMPLETE) {
583 RPCGSS_LOG(1, "rpc_gss_getcred: "
584 "kgsscred_expname_to_unix_cred failed %x\n",
585 gssstat);
586 *ucred = NULL;
587 } else {
588 client_data->u_cred.gidlen = (short)gidlen;
589 client_data->u_cred_set =
590 gethrestime_sec() + svc_rpcgss_gid_timeout;
591 }
592 } else if (client_data->u_cred_set < gethrestime_sec()) {
593 if ((gssstat = kgss_get_group_info(
594 client_data->u_cred.uid,
595 &client_data->u_cred.gid,
596 &client_data->u_cred.gidlist,
597 &gidlen, crgetuid(CRED()))) != GSS_S_COMPLETE) {
598 RPCGSS_LOG(1, "rpc_gss_getcred: "
599 "kgss_get_group_info failed %x\n",
600 gssstat);
601 *ucred = NULL;
602 } else {
603 client_data->u_cred.gidlen = (short)gidlen;
604 client_data->u_cred_set =
605 gethrestime_sec() + svc_rpcgss_gid_timeout;
606 }
607 }
608 }
609 }
610
611 if (cookie != NULL)
612 *cookie = client_data->cookie;
613 req->rq_xprt->xp_cookie = client_data->cookie;
614
615 mutex_exit(&client_data->clm);
616
617 return (TRUE);
618 }
619
620 /*
621 * Transfer the context data from the user land to the kernel.
622 */
623 bool_t transfer_sec_context(svc_rpc_gss_data *client_data) {
624
625 gss_buffer_desc process_token;
892 if (free_mech_type && mech_type)
893 kgss_free_oid(mech_type);
894
895 return (ret);
896 }
897
898 static void
899 svcrpcsec_gss_taskq_func(void *svcrpcsecgss_taskq_arg)
900 {
901 enum auth_stat retval;
902 svcrpcsec_gss_taskq_arg_t *arg = svcrpcsecgss_taskq_arg;
903
904 retval = do_gss_accept(arg->rq_xprt, arg->rpc_call_arg, arg->msg,
905 arg->client_data, arg->cr_version, arg->cr_service);
906 if (retval != AUTH_OK) {
907 cmn_err(CE_NOTE,
908 "svcrpcsec_gss_taskq_func: do_gss_accept fail 0x%x",
909 retval);
910 }
911 rpc_msg_free(&arg->msg, MAX_AUTH_BYTES);
912 svc_clone_unlink(arg->rq_xprt);
913 svc_clone_free(arg->rq_xprt);
914 xdr_free(__xdr_rpc_gss_init_arg, (caddr_t)arg->rpc_call_arg);
915 kmem_free(arg->rpc_call_arg, sizeof (*arg->rpc_call_arg));
916
917 kmem_free(arg, sizeof (*arg));
918 }
919
920 static enum auth_stat
921 rpcsec_gss_init(
922 struct svc_req *rqst,
923 struct rpc_msg *msg,
924 rpc_gss_creds creds,
925 bool_t *no_dispatch,
926 svc_rpc_gss_data *c_d) /* client data, can be NULL */
927 {
928 svc_rpc_gss_data *client_data;
929 int ret;
930 svcrpcsec_gss_taskq_arg_t *arg;
931
957 * taskq func must free arg.
958 */
959 arg = kmem_alloc(sizeof (*arg), KM_SLEEP);
960
961 /* taskq func must free rpc_call_arg & deserialized arguments */
962 arg->rpc_call_arg = kmem_zalloc(sizeof (*arg->rpc_call_arg), KM_SLEEP);
963
964 /* deserialize arguments */
965 if (!SVC_GETARGS(rqst->rq_xprt, __xdr_rpc_gss_init_arg,
966 (caddr_t)arg->rpc_call_arg)) {
967 ret = RPCSEC_GSS_FAILED;
968 client_data->stale = TRUE;
969 goto error2;
970 }
971
972 /* get a xprt clone for taskq thread, taskq func must free it */
973 arg->rq_xprt = svc_clone_init();
974 svc_clone_link(rqst->rq_xprt->xp_master, arg->rq_xprt, rqst->rq_xprt);
975 arg->rq_xprt->xp_xid = rqst->rq_xprt->xp_xid;
976
977
978 /* set the appropriate wrap/unwrap routine for RPCSEC_GSS */
979 arg->rq_xprt->xp_auth.svc_ah_ops = svc_rpc_gss_ops;
980 arg->rq_xprt->xp_auth.svc_ah_private = (caddr_t)client_data;
981
982 /* get a dup of rpc msg for taskq thread */
983 arg->msg = rpc_msg_dup(msg); /* taskq func must free msg dup */
984
985 arg->client_data = client_data;
986 arg->cr_version = creds.version;
987 arg->cr_service = creds.service;
988
989 /* should be ok to hold clm lock as taskq will have new thread(s) */
990 ret = ddi_taskq_dispatch(svcrpcsec_gss_init_taskq,
991 svcrpcsec_gss_taskq_func, arg, DDI_SLEEP);
992 if (ret == DDI_FAILURE) {
993 cmn_err(CE_NOTE, "rpcsec_gss_init: taskq dispatch fail");
994 ret = RPCSEC_GSS_FAILED;
995 rpc_msg_free(&arg->msg, MAX_AUTH_BYTES);
996 svc_clone_unlink(arg->rq_xprt);
997 svc_clone_free(arg->rq_xprt);
998 kmem_free(arg, sizeof (*arg));
999 goto error2;
1000 }
1001
1002 mutex_exit(&client_data->clm);
1003 *no_dispatch = TRUE;
1004 return (AUTH_OK);
1005
1006 error2:
1007 ASSERT(client_data->ref_cnt > 0);
1008 client_data->ref_cnt--;
1009 mutex_exit(&client_data->clm);
1010 cmn_err(CE_NOTE, "rpcsec_gss_init: error 0x%x", ret);
1011 return (ret);
1012 }
1013
1014 static enum auth_stat
1015 rpcsec_gss_continue_init(
1456
1457 RPCGSS_LOG(4, "check_verf: msg_buf length %d\n", len);
1458 RPCGSS_LOG(4, "check_verf: msg_buf value 0x%x\n", *(int *)hdr);
1459 RPCGSS_LOG(4, "check_verf: tok_buf length %ld\n",
1460 tok_buf.length);
1461 RPCGSS_LOG(4, "check_verf: tok_buf value 0x%p\n",
1462 (void *)oa->oa_base);
1463 RPCGSS_LOG(4, "check_verf: context 0x%p\n", (void *)context);
1464
1465 return (FALSE);
1466 }
1467 return (TRUE);
1468 }
1469
1470
1471 /*
1472 * Set response verifier. This is the checksum of the given number.
1473 * (e.g. sequence number or sequence window)
1474 */
1475 static bool_t
1476 set_response_verf(rqst, msg, cl, num)
1477 struct svc_req *rqst;
1478 struct rpc_msg *msg;
1479 svc_rpc_gss_data *cl;
1480 uint_t num;
1481 {
1482 OM_uint32 minor;
1483 gss_buffer_desc in_buf, out_buf;
1484 uint_t num_net;
1485
1486 num_net = (uint_t)htonl(num);
1487 in_buf.length = sizeof (num);
1488 in_buf.value = (char *)&num_net;
1489 /* XXX uid ? */
1490
1491 if ((kgss_sign(&minor, cl->context, cl->qop, &in_buf,
1492 &out_buf)) != GSS_S_COMPLETE)
1493 return (FALSE);
1494
1495 rqst->rq_xprt->xp_verf.oa_flavor = RPCSEC_GSS;
1496 rqst->rq_xprt->xp_verf.oa_base = msg->rm_call.cb_verf.oa_base;
1497 rqst->rq_xprt->xp_verf.oa_length = out_buf.length;
1498 bcopy(out_buf.value, rqst->rq_xprt->xp_verf.oa_base, out_buf.length);
1499 (void) gss_release_buffer(&minor, &out_buf);
1500 return (TRUE);
1501 }
1502
1503 /*
1504 * Create client context.
1505 */
1506 static svc_rpc_gss_data *
1507 create_client()
1508 {
1509 svc_rpc_gss_data *client_data;
1510 static uint_t key = 1;
1511
1512 client_data = (svc_rpc_gss_data *) kmem_cache_alloc(svc_data_handle,
1547 * The key is incremented until there is no duplicate for it.
1548 */
1549
1550 svc_rpc_gss_cache_stats.total_entries_allocated++;
1551 mutex_enter(&ctx_mutex);
1552 for (;;) {
1553 client_data->key = key++;
1554 if (find_client(client_data->key) == NULL) {
1555 insert_client(client_data);
1556 mutex_exit(&ctx_mutex);
1557 return (client_data);
1558 }
1559 }
1560 /*NOTREACHED*/
1561 }
1562
1563 /*
1564 * Insert client context into hash list and LRU list.
1565 */
1566 static void
1567 insert_client(client_data)
1568 svc_rpc_gss_data *client_data;
1569 {
1570 svc_rpc_gss_data *cl;
1571 int index = HASH(client_data->key);
1572
1573 ASSERT(mutex_owned(&ctx_mutex));
1574
1575 client_data->prev = NULL;
1576 cl = clients[index];
1577 if ((client_data->next = cl) != NULL)
1578 cl->prev = client_data;
1579 clients[index] = client_data;
1580
1581 client_data->lru_prev = NULL;
1582 if ((client_data->lru_next = lru_first) != NULL)
1583 lru_first->lru_prev = client_data;
1584 else
1585 lru_last = client_data;
1586 lru_first = client_data;
1587
1588 num_gss_contexts++;
1589 }
1590
1591 /*
1592 * Fetch a client, given the client context handle. Move it to the
1593 * top of the LRU list since this is the most recently used context.
1594 */
1595 static svc_rpc_gss_data *
1596 get_client(ctx_handle)
1597 gss_buffer_t ctx_handle;
1598 {
1599 uint_t key = *(uint_t *)ctx_handle->value;
1600 svc_rpc_gss_data *cl;
1601
1602 mutex_enter(&ctx_mutex);
1603 if ((cl = find_client(key)) != NULL) {
1604 mutex_enter(&cl->clm);
1605 if (cl->stale) {
1606 if (cl->ref_cnt == 0) {
1607 mutex_exit(&cl->clm);
1608 destroy_client(cl);
1609 } else {
1610 mutex_exit(&cl->clm);
1611 }
1612 mutex_exit(&ctx_mutex);
1613 return (NULL);
1614 }
1615 cl->ref_cnt++;
1616 cl->last_ref_time = gethrestime_sec();
1617 mutex_exit(&cl->clm);
1619 cl->lru_prev->lru_next = cl->lru_next;
1620 if (cl->lru_next != NULL)
1621 cl->lru_next->lru_prev = cl->lru_prev;
1622 else
1623 lru_last = cl->lru_prev;
1624 cl->lru_prev = NULL;
1625 cl->lru_next = lru_first;
1626 lru_first->lru_prev = cl;
1627 lru_first = cl;
1628 }
1629 }
1630 mutex_exit(&ctx_mutex);
1631 return (cl);
1632 }
1633
1634 /*
1635 * Given the client context handle, find the context corresponding to it.
1636 * Don't change its LRU state since it may not be used.
1637 */
1638 static svc_rpc_gss_data *
1639 find_client(key)
1640 uint_t key;
1641 {
1642 int index = HASH(key);
1643 svc_rpc_gss_data *cl = NULL;
1644
1645 ASSERT(mutex_owned(&ctx_mutex));
1646
1647 for (cl = clients[index]; cl != NULL; cl = cl->next) {
1648 if (cl->key == key)
1649 break;
1650 }
1651 return (cl);
1652 }
1653
1654 /*
1655 * Destroy a client context.
1656 */
1657 static void
1658 destroy_client(client_data)
1659 svc_rpc_gss_data *client_data;
1660 {
1661 OM_uint32 minor;
1662 int index = HASH(client_data->key);
1663
1664 ASSERT(mutex_owned(&ctx_mutex));
1665
1666 /*
1667 * remove from hash list
1668 */
1669 if (client_data->prev == NULL)
1670 clients[index] = client_data->next;
1671 else
1672 client_data->prev->next = client_data->next;
1673 if (client_data->next != NULL)
1674 client_data->next->prev = client_data->prev;
1675
1676 /*
1677 * remove from LRU list
1678 */
1679 if (client_data->lru_prev == NULL)
1756 no_returned_by_reclaim++;
1757 destroy_client(cl);
1758 } else
1759 mutex_exit(&cl->clm);
1760 } else
1761 mutex_exit(&cl->clm);
1762 } else
1763 mutex_exit(&cl->clm);
1764
1765 cl = next;
1766 }
1767
1768 last_swept = gethrestime_sec();
1769 }
1770
1771 /*
1772 * Encrypt the serialized arguments from xdr_func applied to xdr_ptr
1773 * and write the result to xdrs.
1774 */
1775 static bool_t
1776 svc_rpc_gss_wrap(auth, out_xdrs, xdr_func, xdr_ptr)
1777 SVCAUTH *auth;
1778 XDR *out_xdrs;
1779 bool_t (*xdr_func)();
1780 caddr_t xdr_ptr;
1781 {
1782 svc_rpc_gss_parms_t *gss_parms = SVCAUTH_GSSPARMS(auth);
1783 bool_t ret;
1784
1785 /*
1786 * If context is not established, or if neither integrity nor
1787 * privacy service is used, don't wrap - just XDR encode.
1788 * Otherwise, wrap data using service and QOP parameters.
1789 */
1790 if (!gss_parms->established ||
1791 gss_parms->service == rpc_gss_svc_none)
1792 return ((*xdr_func)(out_xdrs, xdr_ptr));
1793
1794 ret = __rpc_gss_wrap_data(gss_parms->service,
1795 (OM_uint32)gss_parms->qop_rcvd,
1796 (gss_ctx_id_t)gss_parms->context,
1797 gss_parms->seq_num,
1798 out_xdrs, xdr_func, xdr_ptr);
1799 return (ret);
1800 }
1801
1802 /*
1803 * Decrypt the serialized arguments and XDR decode them.
1804 */
1805 static bool_t
1806 svc_rpc_gss_unwrap(auth, in_xdrs, xdr_func, xdr_ptr)
1807 SVCAUTH *auth;
1808 XDR *in_xdrs;
1809 bool_t (*xdr_func)();
1810 caddr_t xdr_ptr;
1811 {
1812 svc_rpc_gss_parms_t *gss_parms = SVCAUTH_GSSPARMS(auth);
1813
1814 /*
1815 * If context is not established, or if neither integrity nor
1816 * privacy service is used, don't unwrap - just XDR decode.
1817 * Otherwise, unwrap data.
1818 */
1819 if (!gss_parms->established ||
1820 gss_parms->service == rpc_gss_svc_none)
1821 return ((*xdr_func)(in_xdrs, xdr_ptr));
1822
1823 return (__rpc_gss_unwrap_data(gss_parms->service,
1824 (gss_ctx_id_t)gss_parms->context,
1825 gss_parms->seq_num,
1826 gss_parms->qop_rcvd,
1827 in_xdrs, xdr_func, xdr_ptr));
1828 }
1829
1830
1831 /* ARGSUSED */
1832 int
1833 rpc_gss_svc_max_data_length(struct svc_req *req, int max_tp_unit_len)
1834 {
1835 return (0);
1836 }
1837
1838 /*
1839 * Add retransmit entry to the context cache entry for a new xid.
1840 * If there is already an entry, delete it before adding the new one.
|
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 2015 Nexenta Systems, Inc. All rights reserved.
24 * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved.
25 * Copyright 2012 Milan Jurik. All rights reserved.
26 * Copyright 2012 Marcel Telka <marcel@telka.sk>
27 * Copyright 2018 OmniOS Community Edition (OmniOSce) Association.
28 */
29
30 /*
31 * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved.
32 *
33 * $Id: svc_auth_gssapi.c,v 1.19 1994/10/27 12:38:51 jik Exp $
34 */
35
36 /*
37 * Server side handling of RPCSEC_GSS flavor.
38 */
39
40 #include <sys/systm.h>
41 #include <sys/kstat.h>
42 #include <sys/cmn_err.h>
43 #include <sys/debug.h>
44 #include <sys/types.h>
45 #include <sys/time.h>
46 #include <gssapi/gssapi.h>
47 #include <gssapi/gssapi_ext.h>
359 mutex_exit(&cl->clm);
360 destroy_client(cl);
361 svcauth->svc_ah_private = NULL;
362 } else
363 mutex_exit(&cl->clm);
364 }
365
366 /*
367 * Check for other expired contexts.
368 */
369 if ((gethrestime_sec() - last_swept) > sweep_interval)
370 sweep_clients(FALSE);
371
372 mutex_exit(&ctx_mutex);
373 }
374
375 /*
376 * Shift the array arr of length arrlen right by nbits bits.
377 */
378 static void
379 shift_bits(uint_t *arr, int arrlen, int nbits)
380 {
381 int i, j;
382 uint_t lo, hi;
383
384 /*
385 * If the number of bits to be shifted exceeds SEQ_WIN, just
386 * zero out the array.
387 */
388 if (nbits < SEQ_WIN) {
389 for (i = 0; i < nbits; i++) {
390 hi = 0;
391 for (j = 0; j < arrlen; j++) {
392 lo = arr[j] & SEQ_LO_BIT;
393 arr[j] >>= 1;
394 if (hi)
395 arr[j] |= SEQ_HI_BIT;
396 hi = lo;
397 }
398 }
399 } else {
400 for (j = 0; j < arrlen; j++)
401 arr[j] = 0;
402 }
403 }
404
405 /*
406 * Check that the received sequence number seq_num is valid.
407 */
408 static bool_t
409 check_seq(svc_rpc_gss_data *cl, uint_t seq_num, bool_t *kill_context)
410 {
411 int i, j;
412 uint_t bit;
413
414 /*
415 * If it exceeds the maximum, kill context.
416 */
417 if (seq_num >= SEQ_MAX) {
418 *kill_context = TRUE;
419 RPCGSS_LOG0(4, "check_seq: seq_num not valid\n");
420 return (FALSE);
421 }
422
423 /*
424 * If greater than the last seen sequence number, just shift
425 * the sequence window so that it starts at the new sequence
426 * number and extends downwards by SEQ_WIN.
427 */
428 if (seq_num > cl->seq_num) {
429 (void) shift_bits(cl->seq_bits, SEQ_ARR_SIZE,
444
445 /*
446 * If within sequence window, set the bit corresponding to it
447 * if not already seen; if already seen, return failure.
448 */
449 j = SEQ_MASK - (i & SEQ_MASK);
450 bit = j > 0 ? (1 << j) : 1;
451 i >>= DIV_BY_32;
452 if (cl->seq_bits[i] & bit) {
453 RPCGSS_LOG0(4, "check_seq: sequence number already seen\n");
454 return (FALSE);
455 }
456 cl->seq_bits[i] |= bit;
457 return (TRUE);
458 }
459
460 /*
461 * Set server callback.
462 */
463 bool_t
464 rpc_gss_set_callback(rpc_gss_callback_t *cb)
465 {
466 rpc_gss_cblist_t *cbl, *tmp;
467
468 if (cb->callback == NULL) {
469 RPCGSS_LOG0(1, "rpc_gss_set_callback: no callback to set\n");
470 return (FALSE);
471 }
472
473 /* check if there is already an entry in the rpc_gss_cblist. */
474 mutex_enter(&cb_mutex);
475 if (rpc_gss_cblist) {
476 for (tmp = rpc_gss_cblist; tmp != NULL; tmp = tmp->next) {
477 if ((tmp->cb.callback == cb->callback) &&
478 (tmp->cb.version == cb->version) &&
479 (tmp->cb.program == cb->program)) {
480 mutex_exit(&cb_mutex);
481 return (TRUE);
482 }
483 }
484 }
486 /* Not in rpc_gss_cblist. Create a new entry. */
487 if ((cbl = (rpc_gss_cblist_t *)kmem_alloc(sizeof (*cbl), KM_SLEEP))
488 == NULL) {
489 mutex_exit(&cb_mutex);
490 return (FALSE);
491 }
492 cbl->cb = *cb;
493 cbl->next = rpc_gss_cblist;
494 rpc_gss_cblist = cbl;
495 mutex_exit(&cb_mutex);
496 return (TRUE);
497 }
498
499 /*
500 * Locate callback (if specified) and call server. Release any
501 * delegated credentials unless passed to server and the server
502 * accepts the context. If a callback is not specified, accept
503 * the incoming context.
504 */
505 static bool_t
506 do_callback(struct svc_req *req, svc_rpc_gss_data *client_data)
507 {
508 rpc_gss_cblist_t *cbl;
509 bool_t ret = TRUE, found = FALSE;
510 rpc_gss_lock_t lock;
511 OM_uint32 minor;
512 mutex_enter(&cb_mutex);
513 for (cbl = rpc_gss_cblist; cbl != NULL; cbl = cbl->next) {
514 if (req->rq_prog != cbl->cb.program ||
515 req->rq_vers != cbl->cb.version)
516 continue;
517 found = TRUE;
518 lock.locked = FALSE;
519 lock.raw_cred = &client_data->raw_cred;
520 ret = (*cbl->cb.callback)(req, client_data->deleg,
521 client_data->context, &lock, &client_data->cookie);
522 req->rq_xprt->xp_cookie = client_data->cookie;
523
524 if (ret) {
525 client_data->locked = lock.locked;
526 client_data->deleg = GSS_C_NO_CREDENTIAL;
527 }
528 break;
529 }
530 if (!found) {
531 if (client_data->deleg != GSS_C_NO_CREDENTIAL) {
532 (void) kgss_release_cred(&minor, &client_data->deleg,
533 crgetuid(CRED()));
534 client_data->deleg = GSS_C_NO_CREDENTIAL;
535 }
536 }
537 mutex_exit(&cb_mutex);
538 return (ret);
539 }
540
541 /*
542 * Get caller credentials.
543 */
544 bool_t
545 rpc_gss_getcred(struct svc_req *req, rpc_gss_rawcred_t **rcred,
546 rpc_gss_ucred_t **ucred, void **cookie)
547 {
548 SVCAUTH *svcauth;
549 svc_rpc_gss_data *client_data;
550 int gssstat, gidlen;
551
552 svcauth = &req->rq_xprt->xp_auth;
553 client_data = (svc_rpc_gss_data *)svcauth->svc_ah_private;
554
555 mutex_enter(&client_data->clm);
556
557 if (rcred != NULL) {
558 svcauth->raw_cred = client_data->raw_cred;
559 *rcred = &svcauth->raw_cred;
560 }
561 if (ucred != NULL) {
562 *ucred = &client_data->u_cred;
563
564 if (client_data->u_cred_set == 0 ||
565 client_data->u_cred_set < gethrestime_sec()) {
566 if (client_data->u_cred_set == 0) {
567 if ((gssstat = kgsscred_expname_to_unix_cred(
568 &client_data->client_name,
569 &client_data->u_cred.uid,
570 &client_data->u_cred.gid,
571 &client_data->u_cred.gidlist,
572 &gidlen, crgetuid(CRED())))
573 != GSS_S_COMPLETE) {
574 RPCGSS_LOG(1, "rpc_gss_getcred: "
575 "kgsscred_expname_to_unix_cred "
576 "failed %x\n", gssstat);
577 *ucred = NULL;
578 } else {
579 client_data->u_cred.gidlen =
580 (short)gidlen;
581 client_data->u_cred_set =
582 gethrestime_sec() +
583 svc_rpcgss_gid_timeout;
584 }
585 } else if (client_data->u_cred_set
586 < gethrestime_sec()) {
587 if ((gssstat = kgss_get_group_info(
588 client_data->u_cred.uid,
589 &client_data->u_cred.gid,
590 &client_data->u_cred.gidlist,
591 &gidlen, crgetuid(CRED())))
592 != GSS_S_COMPLETE) {
593 RPCGSS_LOG(1, "rpc_gss_getcred: "
594 "kgss_get_group_info failed %x\n",
595 gssstat);
596 *ucred = NULL;
597 } else {
598 client_data->u_cred.gidlen =
599 (short)gidlen;
600 client_data->u_cred_set =
601 gethrestime_sec() +
602 svc_rpcgss_gid_timeout;
603 }
604 }
605 }
606 }
607
608 if (cookie != NULL)
609 *cookie = client_data->cookie;
610 req->rq_xprt->xp_cookie = client_data->cookie;
611
612 mutex_exit(&client_data->clm);
613
614 return (TRUE);
615 }
616
617 /*
618 * Transfer the context data from the user land to the kernel.
619 */
620 bool_t transfer_sec_context(svc_rpc_gss_data *client_data) {
621
622 gss_buffer_desc process_token;
889 if (free_mech_type && mech_type)
890 kgss_free_oid(mech_type);
891
892 return (ret);
893 }
894
895 static void
896 svcrpcsec_gss_taskq_func(void *svcrpcsecgss_taskq_arg)
897 {
898 enum auth_stat retval;
899 svcrpcsec_gss_taskq_arg_t *arg = svcrpcsecgss_taskq_arg;
900
901 retval = do_gss_accept(arg->rq_xprt, arg->rpc_call_arg, arg->msg,
902 arg->client_data, arg->cr_version, arg->cr_service);
903 if (retval != AUTH_OK) {
904 cmn_err(CE_NOTE,
905 "svcrpcsec_gss_taskq_func: do_gss_accept fail 0x%x",
906 retval);
907 }
908 rpc_msg_free(&arg->msg, MAX_AUTH_BYTES);
909 SVC_RELE(arg->rq_xprt, NULL, FALSE);
910 svc_clone_unlink(arg->rq_xprt);
911 svc_clone_free(arg->rq_xprt);
912 xdr_free(__xdr_rpc_gss_init_arg, (caddr_t)arg->rpc_call_arg);
913 kmem_free(arg->rpc_call_arg, sizeof (*arg->rpc_call_arg));
914
915 kmem_free(arg, sizeof (*arg));
916 }
917
918 static enum auth_stat
919 rpcsec_gss_init(
920 struct svc_req *rqst,
921 struct rpc_msg *msg,
922 rpc_gss_creds creds,
923 bool_t *no_dispatch,
924 svc_rpc_gss_data *c_d) /* client data, can be NULL */
925 {
926 svc_rpc_gss_data *client_data;
927 int ret;
928 svcrpcsec_gss_taskq_arg_t *arg;
929
955 * taskq func must free arg.
956 */
957 arg = kmem_alloc(sizeof (*arg), KM_SLEEP);
958
959 /* taskq func must free rpc_call_arg & deserialized arguments */
960 arg->rpc_call_arg = kmem_zalloc(sizeof (*arg->rpc_call_arg), KM_SLEEP);
961
962 /* deserialize arguments */
963 if (!SVC_GETARGS(rqst->rq_xprt, __xdr_rpc_gss_init_arg,
964 (caddr_t)arg->rpc_call_arg)) {
965 ret = RPCSEC_GSS_FAILED;
966 client_data->stale = TRUE;
967 goto error2;
968 }
969
970 /* get a xprt clone for taskq thread, taskq func must free it */
971 arg->rq_xprt = svc_clone_init();
972 svc_clone_link(rqst->rq_xprt->xp_master, arg->rq_xprt, rqst->rq_xprt);
973 arg->rq_xprt->xp_xid = rqst->rq_xprt->xp_xid;
974
975 /*
976 * Increment the reference count on the rpcmod slot so that is not
977 * freed before the task has finished.
978 */
979 SVC_HOLD(arg->rq_xprt);
980
981 /* set the appropriate wrap/unwrap routine for RPCSEC_GSS */
982 arg->rq_xprt->xp_auth.svc_ah_ops = svc_rpc_gss_ops;
983 arg->rq_xprt->xp_auth.svc_ah_private = (caddr_t)client_data;
984
985 /* get a dup of rpc msg for taskq thread */
986 arg->msg = rpc_msg_dup(msg); /* taskq func must free msg dup */
987
988 arg->client_data = client_data;
989 arg->cr_version = creds.version;
990 arg->cr_service = creds.service;
991
992 /* should be ok to hold clm lock as taskq will have new thread(s) */
993 ret = ddi_taskq_dispatch(svcrpcsec_gss_init_taskq,
994 svcrpcsec_gss_taskq_func, arg, DDI_SLEEP);
995 if (ret == DDI_FAILURE) {
996 cmn_err(CE_NOTE, "rpcsec_gss_init: taskq dispatch fail");
997 ret = RPCSEC_GSS_FAILED;
998 rpc_msg_free(&arg->msg, MAX_AUTH_BYTES);
999 SVC_RELE(arg->rq_xprt, NULL, FALSE);
1000 svc_clone_unlink(arg->rq_xprt);
1001 svc_clone_free(arg->rq_xprt);
1002 kmem_free(arg, sizeof (*arg));
1003 goto error2;
1004 }
1005
1006 mutex_exit(&client_data->clm);
1007 *no_dispatch = TRUE;
1008 return (AUTH_OK);
1009
1010 error2:
1011 ASSERT(client_data->ref_cnt > 0);
1012 client_data->ref_cnt--;
1013 mutex_exit(&client_data->clm);
1014 cmn_err(CE_NOTE, "rpcsec_gss_init: error 0x%x", ret);
1015 return (ret);
1016 }
1017
1018 static enum auth_stat
1019 rpcsec_gss_continue_init(
1460
1461 RPCGSS_LOG(4, "check_verf: msg_buf length %d\n", len);
1462 RPCGSS_LOG(4, "check_verf: msg_buf value 0x%x\n", *(int *)hdr);
1463 RPCGSS_LOG(4, "check_verf: tok_buf length %ld\n",
1464 tok_buf.length);
1465 RPCGSS_LOG(4, "check_verf: tok_buf value 0x%p\n",
1466 (void *)oa->oa_base);
1467 RPCGSS_LOG(4, "check_verf: context 0x%p\n", (void *)context);
1468
1469 return (FALSE);
1470 }
1471 return (TRUE);
1472 }
1473
1474
1475 /*
1476 * Set response verifier. This is the checksum of the given number.
1477 * (e.g. sequence number or sequence window)
1478 */
1479 static bool_t
1480 set_response_verf(struct svc_req *rqst, struct rpc_msg *msg,
1481 svc_rpc_gss_data *cl, uint_t num)
1482 {
1483 OM_uint32 minor;
1484 gss_buffer_desc in_buf, out_buf;
1485 uint_t num_net;
1486
1487 num_net = (uint_t)htonl(num);
1488 in_buf.length = sizeof (num);
1489 in_buf.value = (char *)&num_net;
1490 /* XXX uid ? */
1491
1492 if ((kgss_sign(&minor, cl->context, cl->qop, &in_buf, &out_buf))
1493 != GSS_S_COMPLETE)
1494 return (FALSE);
1495
1496 rqst->rq_xprt->xp_verf.oa_flavor = RPCSEC_GSS;
1497 rqst->rq_xprt->xp_verf.oa_base = msg->rm_call.cb_verf.oa_base;
1498 rqst->rq_xprt->xp_verf.oa_length = out_buf.length;
1499 bcopy(out_buf.value, rqst->rq_xprt->xp_verf.oa_base, out_buf.length);
1500 (void) gss_release_buffer(&minor, &out_buf);
1501 return (TRUE);
1502 }
1503
1504 /*
1505 * Create client context.
1506 */
1507 static svc_rpc_gss_data *
1508 create_client()
1509 {
1510 svc_rpc_gss_data *client_data;
1511 static uint_t key = 1;
1512
1513 client_data = (svc_rpc_gss_data *) kmem_cache_alloc(svc_data_handle,
1548 * The key is incremented until there is no duplicate for it.
1549 */
1550
1551 svc_rpc_gss_cache_stats.total_entries_allocated++;
1552 mutex_enter(&ctx_mutex);
1553 for (;;) {
1554 client_data->key = key++;
1555 if (find_client(client_data->key) == NULL) {
1556 insert_client(client_data);
1557 mutex_exit(&ctx_mutex);
1558 return (client_data);
1559 }
1560 }
1561 /*NOTREACHED*/
1562 }
1563
1564 /*
1565 * Insert client context into hash list and LRU list.
1566 */
1567 static void
1568 insert_client(svc_rpc_gss_data *client_data)
1569 {
1570 svc_rpc_gss_data *cl;
1571 int index = HASH(client_data->key);
1572
1573 ASSERT(mutex_owned(&ctx_mutex));
1574
1575 client_data->prev = NULL;
1576 cl = clients[index];
1577 if ((client_data->next = cl) != NULL)
1578 cl->prev = client_data;
1579 clients[index] = client_data;
1580
1581 client_data->lru_prev = NULL;
1582 if ((client_data->lru_next = lru_first) != NULL)
1583 lru_first->lru_prev = client_data;
1584 else
1585 lru_last = client_data;
1586 lru_first = client_data;
1587
1588 num_gss_contexts++;
1589 }
1590
1591 /*
1592 * Fetch a client, given the client context handle. Move it to the
1593 * top of the LRU list since this is the most recently used context.
1594 */
1595 static svc_rpc_gss_data *
1596 get_client(gss_buffer_t ctx_handle)
1597 {
1598 uint_t key = *(uint_t *)ctx_handle->value;
1599 svc_rpc_gss_data *cl;
1600
1601 mutex_enter(&ctx_mutex);
1602 if ((cl = find_client(key)) != NULL) {
1603 mutex_enter(&cl->clm);
1604 if (cl->stale) {
1605 if (cl->ref_cnt == 0) {
1606 mutex_exit(&cl->clm);
1607 destroy_client(cl);
1608 } else {
1609 mutex_exit(&cl->clm);
1610 }
1611 mutex_exit(&ctx_mutex);
1612 return (NULL);
1613 }
1614 cl->ref_cnt++;
1615 cl->last_ref_time = gethrestime_sec();
1616 mutex_exit(&cl->clm);
1618 cl->lru_prev->lru_next = cl->lru_next;
1619 if (cl->lru_next != NULL)
1620 cl->lru_next->lru_prev = cl->lru_prev;
1621 else
1622 lru_last = cl->lru_prev;
1623 cl->lru_prev = NULL;
1624 cl->lru_next = lru_first;
1625 lru_first->lru_prev = cl;
1626 lru_first = cl;
1627 }
1628 }
1629 mutex_exit(&ctx_mutex);
1630 return (cl);
1631 }
1632
1633 /*
1634 * Given the client context handle, find the context corresponding to it.
1635 * Don't change its LRU state since it may not be used.
1636 */
1637 static svc_rpc_gss_data *
1638 find_client(uint_t key)
1639 {
1640 int index = HASH(key);
1641 svc_rpc_gss_data *cl = NULL;
1642
1643 ASSERT(mutex_owned(&ctx_mutex));
1644
1645 for (cl = clients[index]; cl != NULL; cl = cl->next) {
1646 if (cl->key == key)
1647 break;
1648 }
1649 return (cl);
1650 }
1651
1652 /*
1653 * Destroy a client context.
1654 */
1655 static void
1656 destroy_client(svc_rpc_gss_data *client_data)
1657 {
1658 OM_uint32 minor;
1659 int index = HASH(client_data->key);
1660
1661 ASSERT(mutex_owned(&ctx_mutex));
1662
1663 /*
1664 * remove from hash list
1665 */
1666 if (client_data->prev == NULL)
1667 clients[index] = client_data->next;
1668 else
1669 client_data->prev->next = client_data->next;
1670 if (client_data->next != NULL)
1671 client_data->next->prev = client_data->prev;
1672
1673 /*
1674 * remove from LRU list
1675 */
1676 if (client_data->lru_prev == NULL)
1753 no_returned_by_reclaim++;
1754 destroy_client(cl);
1755 } else
1756 mutex_exit(&cl->clm);
1757 } else
1758 mutex_exit(&cl->clm);
1759 } else
1760 mutex_exit(&cl->clm);
1761
1762 cl = next;
1763 }
1764
1765 last_swept = gethrestime_sec();
1766 }
1767
1768 /*
1769 * Encrypt the serialized arguments from xdr_func applied to xdr_ptr
1770 * and write the result to xdrs.
1771 */
1772 static bool_t
1773 svc_rpc_gss_wrap(SVCAUTH *auth, XDR *out_xdrs, bool_t (*xdr_func)(),
1774 caddr_t xdr_ptr)
1775 {
1776 svc_rpc_gss_parms_t *gss_parms = SVCAUTH_GSSPARMS(auth);
1777 bool_t ret;
1778
1779 /*
1780 * If context is not established, or if neither integrity nor
1781 * privacy service is used, don't wrap - just XDR encode.
1782 * Otherwise, wrap data using service and QOP parameters.
1783 */
1784 if (!gss_parms->established || gss_parms->service == rpc_gss_svc_none)
1785 return ((*xdr_func)(out_xdrs, xdr_ptr));
1786
1787 ret = __rpc_gss_wrap_data(gss_parms->service,
1788 (OM_uint32)gss_parms->qop_rcvd,
1789 (gss_ctx_id_t)gss_parms->context,
1790 gss_parms->seq_num,
1791 out_xdrs, xdr_func, xdr_ptr);
1792 return (ret);
1793 }
1794
1795 /*
1796 * Decrypt the serialized arguments and XDR decode them.
1797 */
1798 static bool_t
1799 svc_rpc_gss_unwrap(SVCAUTH *auth, XDR *in_xdrs, bool_t (*xdr_func)(),
1800 caddr_t xdr_ptr)
1801 {
1802 svc_rpc_gss_parms_t *gss_parms = SVCAUTH_GSSPARMS(auth);
1803
1804 /*
1805 * If context is not established, or if neither integrity nor
1806 * privacy service is used, don't unwrap - just XDR decode.
1807 * Otherwise, unwrap data.
1808 */
1809 if (!gss_parms->established || gss_parms->service == rpc_gss_svc_none)
1810 return ((*xdr_func)(in_xdrs, xdr_ptr));
1811
1812 return (__rpc_gss_unwrap_data(gss_parms->service,
1813 (gss_ctx_id_t)gss_parms->context,
1814 gss_parms->seq_num,
1815 gss_parms->qop_rcvd,
1816 in_xdrs, xdr_func, xdr_ptr));
1817 }
1818
1819
1820 /* ARGSUSED */
1821 int
1822 rpc_gss_svc_max_data_length(struct svc_req *req, int max_tp_unit_len)
1823 {
1824 return (0);
1825 }
1826
1827 /*
1828 * Add retransmit entry to the context cache entry for a new xid.
1829 * If there is already an entry, delete it before adding the new one.
|