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.
 
 |