The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/rpc/rpcsec_gss/rpcsec_gss.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * Copyright (c) 2008 Doug Rabson
    3  * All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer.
   10  * 2. Redistributions in binary form must reproduce the above copyright
   11  *    notice, this list of conditions and the following disclaimer in the
   12  *    documentation and/or other materials provided with the distribution.
   13  *
   14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   24  * SUCH DAMAGE.
   25  */
   26 /*
   27   auth_gss.c
   28 
   29   RPCSEC_GSS client routines.
   30   
   31   Copyright (c) 2000 The Regents of the University of Michigan.
   32   All rights reserved.
   33 
   34   Copyright (c) 2000 Dug Song <dugsong@UMICH.EDU>.
   35   All rights reserved, all wrongs reversed.
   36 
   37   Redistribution and use in source and binary forms, with or without
   38   modification, are permitted provided that the following conditions
   39   are met:
   40 
   41   1. Redistributions of source code must retain the above copyright
   42      notice, this list of conditions and the following disclaimer.
   43   2. Redistributions in binary form must reproduce the above copyright
   44      notice, this list of conditions and the following disclaimer in the
   45      documentation and/or other materials provided with the distribution.
   46   3. Neither the name of the University nor the names of its
   47      contributors may be used to endorse or promote products derived
   48      from this software without specific prior written permission.
   49 
   50   THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
   51   WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
   52   MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   53   DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   54   FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   55   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   56   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
   57   BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
   58   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
   59   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
   60   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   61 
   62   $Id: auth_gss.c,v 1.32 2002/01/15 15:43:00 andros Exp $
   63 */
   64 
   65 #include <sys/cdefs.h>
   66 __FBSDID("$FreeBSD: releng/10.2/sys/rpc/rpcsec_gss/rpcsec_gss.c 253049 2013-07-09 01:05:28Z rmacklem $");
   67 
   68 #include <sys/param.h>
   69 #include <sys/systm.h>
   70 #include <sys/hash.h>
   71 #include <sys/kernel.h>
   72 #include <sys/kobj.h>
   73 #include <sys/lock.h>
   74 #include <sys/malloc.h>
   75 #include <sys/mbuf.h>
   76 #include <sys/mutex.h>
   77 #include <sys/proc.h>
   78 #include <sys/refcount.h>
   79 #include <sys/sx.h>
   80 #include <sys/ucred.h>
   81 
   82 #include <rpc/rpc.h>
   83 #include <rpc/rpcsec_gss.h>
   84 
   85 #include <kgssapi/krb5/kcrypto.h>
   86 
   87 #include "rpcsec_gss_int.h"
   88 
   89 static void     rpc_gss_nextverf(AUTH*);
   90 static bool_t   rpc_gss_marshal(AUTH *, uint32_t, XDR *, struct mbuf *);
   91 static bool_t   rpc_gss_init(AUTH *auth, rpc_gss_options_ret_t *options_ret);
   92 static bool_t   rpc_gss_refresh(AUTH *, void *);
   93 static bool_t   rpc_gss_validate(AUTH *, uint32_t, struct opaque_auth *,
   94     struct mbuf **);
   95 static void     rpc_gss_destroy(AUTH *);
   96 static void     rpc_gss_destroy_context(AUTH *, bool_t);
   97 
   98 static struct auth_ops rpc_gss_ops = {
   99         rpc_gss_nextverf,
  100         rpc_gss_marshal,
  101         rpc_gss_validate,
  102         rpc_gss_refresh,
  103         rpc_gss_destroy,
  104 };
  105 
  106 enum rpcsec_gss_state {
  107         RPCSEC_GSS_START,
  108         RPCSEC_GSS_CONTEXT,
  109         RPCSEC_GSS_ESTABLISHED,
  110         RPCSEC_GSS_DESTROYING
  111 };
  112 
  113 struct rpc_pending_request {
  114         uint32_t                pr_xid;         /* XID of rpc */
  115         uint32_t                pr_seq;         /* matching GSS seq */
  116         LIST_ENTRY(rpc_pending_request) pr_link;
  117 };
  118 LIST_HEAD(rpc_pending_request_list, rpc_pending_request);
  119 
  120 struct rpc_gss_data {
  121         volatile u_int          gd_refs;        /* number of current users */
  122         struct mtx              gd_lock;
  123         uint32_t                gd_hash;
  124         AUTH                    *gd_auth;       /* link back to AUTH */
  125         struct ucred            *gd_ucred;      /* matching local cred */
  126         char                    *gd_principal;  /* server principal name */
  127         char                    *gd_clntprincipal; /* client principal name */
  128         rpc_gss_options_req_t   gd_options;     /* GSS context options */
  129         enum rpcsec_gss_state   gd_state;       /* connection state */
  130         gss_buffer_desc         gd_verf;        /* save GSS_S_COMPLETE
  131                                                  * NULL RPC verfier to
  132                                                  * process at end of
  133                                                  * context negotiation */
  134         CLIENT                  *gd_clnt;       /* client handle */
  135         gss_OID                 gd_mech;        /* mechanism to use */
  136         gss_qop_t               gd_qop;         /* quality of protection */
  137         gss_ctx_id_t            gd_ctx;         /* context id */
  138         struct rpc_gss_cred     gd_cred;        /* client credentials */
  139         uint32_t                gd_seq;         /* next sequence number */
  140         u_int                   gd_win;         /* sequence window */
  141         struct rpc_pending_request_list gd_reqs;
  142         TAILQ_ENTRY(rpc_gss_data) gd_link;
  143         TAILQ_ENTRY(rpc_gss_data) gd_alllink;
  144 };
  145 TAILQ_HEAD(rpc_gss_data_list, rpc_gss_data);
  146 
  147 #define AUTH_PRIVATE(auth)      ((struct rpc_gss_data *)auth->ah_private)
  148 
  149 static struct timeval AUTH_TIMEOUT = { 25, 0 };
  150 
  151 #define RPC_GSS_HASH_SIZE       11
  152 #define RPC_GSS_MAX             256
  153 static struct rpc_gss_data_list rpc_gss_cache[RPC_GSS_HASH_SIZE];
  154 static struct rpc_gss_data_list rpc_gss_all;
  155 static struct sx rpc_gss_lock;
  156 static int rpc_gss_count;
  157 
  158 static AUTH *rpc_gss_seccreate_int(CLIENT *, struct ucred *, const char *,
  159     const char *, gss_OID, rpc_gss_service_t, u_int, rpc_gss_options_req_t *,
  160     rpc_gss_options_ret_t *);
  161 
  162 static void
  163 rpc_gss_hashinit(void *dummy)
  164 {
  165         int i;
  166 
  167         for (i = 0; i < RPC_GSS_HASH_SIZE; i++)
  168                 TAILQ_INIT(&rpc_gss_cache[i]);
  169         TAILQ_INIT(&rpc_gss_all);
  170         sx_init(&rpc_gss_lock, "rpc_gss_lock");
  171 }
  172 SYSINIT(rpc_gss_hashinit, SI_SUB_KMEM, SI_ORDER_ANY, rpc_gss_hashinit, NULL);
  173 
  174 static uint32_t
  175 rpc_gss_hash(const char *principal, gss_OID mech,
  176     struct ucred *cred, rpc_gss_service_t service)
  177 {
  178         uint32_t h;
  179 
  180         h = HASHSTEP(HASHINIT, cred->cr_uid);
  181         h = hash32_str(principal, h);
  182         h = hash32_buf(mech->elements, mech->length, h);
  183         h = HASHSTEP(h, (int) service);
  184 
  185         return (h % RPC_GSS_HASH_SIZE);
  186 }
  187 
  188 /*
  189  * Simplified interface to create a security association for the
  190  * current thread's * ucred.
  191  */
  192 AUTH *
  193 rpc_gss_secfind(CLIENT *clnt, struct ucred *cred, const char *principal,
  194     gss_OID mech_oid, rpc_gss_service_t service)
  195 {
  196         uint32_t                h, th;
  197         AUTH                    *auth;
  198         struct rpc_gss_data     *gd, *tgd;
  199         rpc_gss_options_ret_t   options;
  200 
  201         if (rpc_gss_count > RPC_GSS_MAX) {
  202                 while (rpc_gss_count > RPC_GSS_MAX) {
  203                         sx_xlock(&rpc_gss_lock);
  204                         tgd = TAILQ_FIRST(&rpc_gss_all);
  205                         th = tgd->gd_hash;
  206                         TAILQ_REMOVE(&rpc_gss_cache[th], tgd, gd_link);
  207                         TAILQ_REMOVE(&rpc_gss_all, tgd, gd_alllink);
  208                         rpc_gss_count--;
  209                         sx_xunlock(&rpc_gss_lock);
  210                         AUTH_DESTROY(tgd->gd_auth);
  211                 }
  212         }
  213 
  214         /*
  215          * See if we already have an AUTH which matches.
  216          */
  217         h = rpc_gss_hash(principal, mech_oid, cred, service);
  218 
  219 again:
  220         sx_slock(&rpc_gss_lock);
  221         TAILQ_FOREACH(gd, &rpc_gss_cache[h], gd_link) {
  222                 if (gd->gd_ucred->cr_uid == cred->cr_uid
  223                     && !strcmp(gd->gd_principal, principal)
  224                     && gd->gd_mech == mech_oid
  225                     && gd->gd_cred.gc_svc == service) {
  226                         refcount_acquire(&gd->gd_refs);
  227                         if (sx_try_upgrade(&rpc_gss_lock)) {
  228                                 /*
  229                                  * Keep rpc_gss_all LRU sorted.
  230                                  */
  231                                 TAILQ_REMOVE(&rpc_gss_all, gd, gd_alllink);
  232                                 TAILQ_INSERT_TAIL(&rpc_gss_all, gd,
  233                                     gd_alllink);
  234                                 sx_xunlock(&rpc_gss_lock);
  235                         } else {
  236                                 sx_sunlock(&rpc_gss_lock);
  237                         }
  238 
  239                         /*
  240                          * If the state != ESTABLISHED, try and initialize
  241                          * the authenticator again. This will happen if the
  242                          * user's credentials have expired. It may succeed now,
  243                          * if they have done a kinit or similar.
  244                          */
  245                         if (gd->gd_state != RPCSEC_GSS_ESTABLISHED) {
  246                                 memset(&options, 0, sizeof (options));
  247                                 (void) rpc_gss_init(gd->gd_auth, &options);
  248                         }
  249                         return (gd->gd_auth);
  250                 }
  251         }
  252         sx_sunlock(&rpc_gss_lock);
  253 
  254         /*
  255          * We missed in the cache - create a new association.
  256          */
  257         auth = rpc_gss_seccreate_int(clnt, cred, NULL, principal, mech_oid,
  258             service, GSS_C_QOP_DEFAULT, NULL, NULL);
  259         if (!auth)
  260                 return (NULL);
  261 
  262         gd = AUTH_PRIVATE(auth);
  263         gd->gd_hash = h;
  264         
  265         sx_xlock(&rpc_gss_lock);
  266         TAILQ_FOREACH(tgd, &rpc_gss_cache[h], gd_link) {
  267                 if (tgd->gd_ucred->cr_uid == cred->cr_uid
  268                     && !strcmp(tgd->gd_principal, principal)
  269                     && tgd->gd_mech == mech_oid
  270                     && tgd->gd_cred.gc_svc == service) {
  271                         /*
  272                          * We lost a race to create the AUTH that
  273                          * matches this cred.
  274                          */
  275                         sx_xunlock(&rpc_gss_lock);
  276                         AUTH_DESTROY(auth);
  277                         goto again;
  278                 }
  279         }
  280 
  281         rpc_gss_count++;
  282         TAILQ_INSERT_TAIL(&rpc_gss_cache[h], gd, gd_link);
  283         TAILQ_INSERT_TAIL(&rpc_gss_all, gd, gd_alllink);
  284         refcount_acquire(&gd->gd_refs); /* one for the cache, one for user */
  285         sx_xunlock(&rpc_gss_lock);
  286 
  287         return (auth);
  288 }
  289 
  290 void
  291 rpc_gss_secpurge(CLIENT *clnt)
  292 {
  293         uint32_t                h;
  294         struct rpc_gss_data     *gd, *tgd;
  295 
  296         TAILQ_FOREACH_SAFE(gd, &rpc_gss_all, gd_alllink, tgd) {
  297                 if (gd->gd_clnt == clnt) {
  298                         sx_xlock(&rpc_gss_lock);
  299                         h = gd->gd_hash;
  300                         TAILQ_REMOVE(&rpc_gss_cache[h], gd, gd_link);
  301                         TAILQ_REMOVE(&rpc_gss_all, gd, gd_alllink);
  302                         rpc_gss_count--;
  303                         sx_xunlock(&rpc_gss_lock);
  304                         AUTH_DESTROY(gd->gd_auth);
  305                 }
  306         }
  307 }
  308 
  309 AUTH *
  310 rpc_gss_seccreate(CLIENT *clnt, struct ucred *cred, const char *clnt_principal,
  311     const char *principal, const char *mechanism, rpc_gss_service_t service,
  312     const char *qop, rpc_gss_options_req_t *options_req,
  313     rpc_gss_options_ret_t *options_ret)
  314 {
  315         gss_OID                 oid;
  316         u_int                   qop_num;
  317 
  318         /*
  319          * Bail out now if we don't know this mechanism.
  320          */
  321         if (!rpc_gss_mech_to_oid(mechanism, &oid))
  322                 return (NULL);
  323 
  324         if (qop) {
  325                 if (!rpc_gss_qop_to_num(qop, mechanism, &qop_num))
  326                         return (NULL);
  327         } else {
  328                 qop_num = GSS_C_QOP_DEFAULT;
  329         }
  330 
  331         return (rpc_gss_seccreate_int(clnt, cred, clnt_principal, principal,
  332                 oid, service, qop_num, options_req, options_ret));
  333 }
  334 
  335 void
  336 rpc_gss_refresh_auth(AUTH *auth)
  337 {
  338         struct rpc_gss_data     *gd;
  339         rpc_gss_options_ret_t   options;
  340 
  341         gd = AUTH_PRIVATE(auth);
  342         /*
  343          * If the state != ESTABLISHED, try and initialize
  344          * the authenticator again. This will happen if the
  345          * user's credentials have expired. It may succeed now,
  346          * if they have done a kinit or similar.
  347          */
  348         if (gd->gd_state != RPCSEC_GSS_ESTABLISHED) {
  349                 memset(&options, 0, sizeof (options));
  350                 (void) rpc_gss_init(auth, &options);
  351         }
  352 }
  353 
  354 static AUTH *
  355 rpc_gss_seccreate_int(CLIENT *clnt, struct ucred *cred,
  356     const char *clnt_principal, const char *principal, gss_OID mech_oid,
  357     rpc_gss_service_t service, u_int qop_num,
  358     rpc_gss_options_req_t *options_req, rpc_gss_options_ret_t *options_ret)
  359 {
  360         AUTH                    *auth;
  361         rpc_gss_options_ret_t   options;
  362         struct rpc_gss_data     *gd;
  363 
  364         /*
  365          * If the caller doesn't want the options, point at local
  366          * storage to simplify the code below.
  367          */
  368         if (!options_ret)
  369                 options_ret = &options;
  370 
  371         /*
  372          * Default service is integrity.
  373          */
  374         if (service == rpc_gss_svc_default)
  375                 service = rpc_gss_svc_integrity;
  376 
  377         memset(options_ret, 0, sizeof(*options_ret));
  378 
  379         rpc_gss_log_debug("in rpc_gss_seccreate()");
  380         
  381         memset(&rpc_createerr, 0, sizeof(rpc_createerr));
  382         
  383         auth = mem_alloc(sizeof(*auth));
  384         if (auth == NULL) {
  385                 rpc_createerr.cf_stat = RPC_SYSTEMERROR;
  386                 rpc_createerr.cf_error.re_errno = ENOMEM;
  387                 return (NULL);
  388         }
  389         gd = mem_alloc(sizeof(*gd));
  390         if (gd == NULL) {
  391                 rpc_createerr.cf_stat = RPC_SYSTEMERROR;
  392                 rpc_createerr.cf_error.re_errno = ENOMEM;
  393                 mem_free(auth, sizeof(*auth));
  394                 return (NULL);
  395         }
  396 
  397         auth->ah_ops = &rpc_gss_ops;
  398         auth->ah_private = (caddr_t) gd;
  399         auth->ah_cred.oa_flavor = RPCSEC_GSS;
  400         
  401         refcount_init(&gd->gd_refs, 1);
  402         mtx_init(&gd->gd_lock, "gd->gd_lock", NULL, MTX_DEF);
  403         gd->gd_auth = auth;
  404         gd->gd_ucred = crdup(cred);
  405         gd->gd_principal = strdup(principal, M_RPC);
  406         if (clnt_principal != NULL)
  407                 gd->gd_clntprincipal = strdup(clnt_principal, M_RPC);
  408         else
  409                 gd->gd_clntprincipal = NULL;
  410 
  411 
  412         if (options_req) {
  413                 gd->gd_options = *options_req;
  414         } else {
  415                 gd->gd_options.req_flags = GSS_C_MUTUAL_FLAG;
  416                 gd->gd_options.time_req = 0;
  417                 gd->gd_options.my_cred = GSS_C_NO_CREDENTIAL;
  418                 gd->gd_options.input_channel_bindings = NULL;
  419         }
  420         CLNT_ACQUIRE(clnt);
  421         gd->gd_clnt = clnt;
  422         gd->gd_ctx = GSS_C_NO_CONTEXT;
  423         gd->gd_mech = mech_oid;
  424         gd->gd_qop = qop_num;
  425 
  426         gd->gd_cred.gc_version = RPCSEC_GSS_VERSION;
  427         gd->gd_cred.gc_proc = RPCSEC_GSS_INIT;
  428         gd->gd_cred.gc_seq = 0;
  429         gd->gd_cred.gc_svc = service;
  430         LIST_INIT(&gd->gd_reqs);
  431         
  432         if (!rpc_gss_init(auth, options_ret)) {
  433                 goto bad;
  434         }
  435         
  436         return (auth);
  437 
  438  bad:
  439         AUTH_DESTROY(auth);
  440         return (NULL);
  441 }
  442 
  443 bool_t
  444 rpc_gss_set_defaults(AUTH *auth, rpc_gss_service_t service, const char *qop)
  445 {
  446         struct rpc_gss_data     *gd;
  447         u_int                   qop_num;
  448         const char              *mechanism;
  449 
  450         gd = AUTH_PRIVATE(auth);
  451         if (!rpc_gss_oid_to_mech(gd->gd_mech, &mechanism)) {
  452                 return (FALSE);
  453         }
  454 
  455         if (qop) {
  456                 if (!rpc_gss_qop_to_num(qop, mechanism, &qop_num)) {
  457                         return (FALSE);
  458                 }
  459         } else {
  460                 qop_num = GSS_C_QOP_DEFAULT;
  461         }
  462 
  463         gd->gd_cred.gc_svc = service;
  464         gd->gd_qop = qop_num;
  465         return (TRUE);
  466 }
  467 
  468 static void
  469 rpc_gss_purge_xid(struct rpc_gss_data *gd, uint32_t xid)
  470 {
  471         struct rpc_pending_request *pr, *npr;
  472         struct rpc_pending_request_list reqs;
  473 
  474         LIST_INIT(&reqs);
  475         mtx_lock(&gd->gd_lock);
  476         LIST_FOREACH_SAFE(pr, &gd->gd_reqs, pr_link, npr) {
  477                 if (pr->pr_xid == xid) {
  478                         LIST_REMOVE(pr, pr_link);
  479                         LIST_INSERT_HEAD(&reqs, pr, pr_link);
  480                 }
  481         }
  482 
  483         mtx_unlock(&gd->gd_lock);
  484 
  485         LIST_FOREACH_SAFE(pr, &reqs, pr_link, npr) {
  486                 mem_free(pr, sizeof(*pr));
  487         }
  488 }
  489 
  490 static uint32_t
  491 rpc_gss_alloc_seq(struct rpc_gss_data *gd)
  492 {
  493         uint32_t seq;
  494 
  495         mtx_lock(&gd->gd_lock);
  496         seq = gd->gd_seq;
  497         gd->gd_seq++;
  498         mtx_unlock(&gd->gd_lock);
  499 
  500         return (seq);
  501 }
  502 
  503 static void
  504 rpc_gss_nextverf(__unused AUTH *auth)
  505 {
  506 
  507         /* not used */
  508 }
  509 
  510 static bool_t
  511 rpc_gss_marshal(AUTH *auth, uint32_t xid, XDR *xdrs, struct mbuf *args)
  512 {
  513         struct rpc_gss_data     *gd;
  514         struct rpc_pending_request *pr;
  515         uint32_t                 seq;
  516         XDR                      tmpxdrs;
  517         struct rpc_gss_cred      gsscred;
  518         char                     credbuf[MAX_AUTH_BYTES];
  519         struct opaque_auth       creds, verf;
  520         gss_buffer_desc          rpcbuf, checksum;
  521         OM_uint32                maj_stat, min_stat;
  522         bool_t                   xdr_stat;
  523 
  524         rpc_gss_log_debug("in rpc_gss_marshal()");
  525 
  526         gd = AUTH_PRIVATE(auth);
  527         
  528         gsscred = gd->gd_cred;
  529         seq = rpc_gss_alloc_seq(gd);
  530         gsscred.gc_seq = seq;
  531 
  532         xdrmem_create(&tmpxdrs, credbuf, sizeof(credbuf), XDR_ENCODE);
  533         if (!xdr_rpc_gss_cred(&tmpxdrs, &gsscred)) {
  534                 XDR_DESTROY(&tmpxdrs);
  535                 _rpc_gss_set_error(RPC_GSS_ER_SYSTEMERROR, ENOMEM);
  536                 return (FALSE);
  537         }
  538         creds.oa_flavor = RPCSEC_GSS;
  539         creds.oa_base = credbuf;
  540         creds.oa_length = XDR_GETPOS(&tmpxdrs);
  541         XDR_DESTROY(&tmpxdrs);
  542 
  543         xdr_opaque_auth(xdrs, &creds);
  544 
  545         if (gd->gd_cred.gc_proc == RPCSEC_GSS_INIT ||
  546             gd->gd_cred.gc_proc == RPCSEC_GSS_CONTINUE_INIT) {
  547                 if (!xdr_opaque_auth(xdrs, &_null_auth)) {
  548                         _rpc_gss_set_error(RPC_GSS_ER_SYSTEMERROR, ENOMEM);
  549                         return (FALSE);
  550                 }
  551                 xdrmbuf_append(xdrs, args);
  552                 return (TRUE);
  553         } else {
  554                 /*
  555                  * Keep track of this XID + seq pair so that we can do
  556                  * the matching gss_verify_mic in AUTH_VALIDATE.
  557                  */
  558                 pr = mem_alloc(sizeof(struct rpc_pending_request));
  559                 mtx_lock(&gd->gd_lock);
  560                 pr->pr_xid = xid;
  561                 pr->pr_seq = seq;
  562                 LIST_INSERT_HEAD(&gd->gd_reqs, pr, pr_link);
  563                 mtx_unlock(&gd->gd_lock);
  564 
  565                 /*
  566                  * Checksum serialized RPC header, up to and including
  567                  * credential. For the in-kernel environment, we
  568                  * assume that our XDR stream is on a contiguous
  569                  * memory buffer (e.g. an mbuf).
  570                  */
  571                 rpcbuf.length = XDR_GETPOS(xdrs);
  572                 XDR_SETPOS(xdrs, 0);
  573                 rpcbuf.value = XDR_INLINE(xdrs, rpcbuf.length);
  574 
  575                 maj_stat = gss_get_mic(&min_stat, gd->gd_ctx, gd->gd_qop,
  576                     &rpcbuf, &checksum);
  577 
  578                 if (maj_stat != GSS_S_COMPLETE) {
  579                         rpc_gss_log_status("gss_get_mic", gd->gd_mech,
  580                             maj_stat, min_stat);
  581                         if (maj_stat == GSS_S_CONTEXT_EXPIRED) {
  582                                 rpc_gss_destroy_context(auth, TRUE);
  583                         }
  584                         _rpc_gss_set_error(RPC_GSS_ER_SYSTEMERROR, EPERM);
  585                         return (FALSE);
  586                 }
  587 
  588                 verf.oa_flavor = RPCSEC_GSS;
  589                 verf.oa_base = checksum.value;
  590                 verf.oa_length = checksum.length;
  591 
  592                 xdr_stat = xdr_opaque_auth(xdrs, &verf);
  593                 gss_release_buffer(&min_stat, &checksum);
  594                 if (!xdr_stat) {
  595                         _rpc_gss_set_error(RPC_GSS_ER_SYSTEMERROR, ENOMEM);
  596                         return (FALSE);
  597                 }
  598                 if (gd->gd_state != RPCSEC_GSS_ESTABLISHED ||
  599                     gd->gd_cred.gc_svc == rpc_gss_svc_none) {
  600                         xdrmbuf_append(xdrs, args);
  601                         return (TRUE);
  602                 } else {
  603                         if (!xdr_rpc_gss_wrap_data(&args,
  604                                 gd->gd_ctx, gd->gd_qop, gd->gd_cred.gc_svc,
  605                                 seq))
  606                                 return (FALSE);
  607                         xdrmbuf_append(xdrs, args);
  608                         return (TRUE);
  609                 }
  610         }
  611 
  612         return (TRUE);
  613 }
  614 
  615 static bool_t
  616 rpc_gss_validate(AUTH *auth, uint32_t xid, struct opaque_auth *verf,
  617     struct mbuf **resultsp)
  618 {
  619         struct rpc_gss_data     *gd;
  620         struct rpc_pending_request *pr, *npr;
  621         struct rpc_pending_request_list reqs;
  622         gss_qop_t               qop_state;
  623         uint32_t                num, seq;
  624         gss_buffer_desc         signbuf, checksum;
  625         OM_uint32               maj_stat, min_stat;
  626 
  627         rpc_gss_log_debug("in rpc_gss_validate()");
  628         
  629         gd = AUTH_PRIVATE(auth);
  630 
  631         /*
  632          * The client will call us with a NULL verf when it gives up
  633          * on an XID.
  634          */
  635         if (!verf) {
  636                 rpc_gss_purge_xid(gd, xid);
  637                 return (TRUE);
  638         }
  639 
  640         if (gd->gd_state == RPCSEC_GSS_CONTEXT) {
  641                 /*
  642                  * Save the on the wire verifier to validate last INIT
  643                  * phase packet after decode if the major status is
  644                  * GSS_S_COMPLETE.
  645                  */
  646                 if (gd->gd_verf.value)
  647                         xdr_free((xdrproc_t) xdr_gss_buffer_desc,
  648                             (char *) &gd->gd_verf);
  649                 gd->gd_verf.value = mem_alloc(verf->oa_length);
  650                 if (gd->gd_verf.value == NULL) {
  651                         printf("gss_validate: out of memory\n");
  652                         _rpc_gss_set_error(RPC_GSS_ER_SYSTEMERROR, ENOMEM);
  653                         m_freem(*resultsp);
  654                         *resultsp = NULL;
  655                         return (FALSE);
  656                 }
  657                 memcpy(gd->gd_verf.value, verf->oa_base, verf->oa_length);
  658                 gd->gd_verf.length = verf->oa_length;
  659 
  660                 return (TRUE);
  661         }
  662 
  663         /*
  664          * We need to check the verifier against all the requests
  665          * we've send for this XID - for unreliable protocols, we
  666          * retransmit with the same XID but different sequence
  667          * number. We temporarily take this set of requests out of the
  668          * list so that we can work through the list without having to
  669          * hold the lock.
  670          */
  671         mtx_lock(&gd->gd_lock);
  672         LIST_INIT(&reqs);
  673         LIST_FOREACH_SAFE(pr, &gd->gd_reqs, pr_link, npr) {
  674                 if (pr->pr_xid == xid) {
  675                         LIST_REMOVE(pr, pr_link);
  676                         LIST_INSERT_HEAD(&reqs, pr, pr_link);
  677                 }
  678         }
  679         mtx_unlock(&gd->gd_lock);
  680         LIST_FOREACH(pr, &reqs, pr_link) {
  681                 if (pr->pr_xid == xid) {
  682                         seq = pr->pr_seq;
  683                         num = htonl(seq);
  684                         signbuf.value = &num;
  685                         signbuf.length = sizeof(num);
  686         
  687                         checksum.value = verf->oa_base;
  688                         checksum.length = verf->oa_length;
  689         
  690                         maj_stat = gss_verify_mic(&min_stat, gd->gd_ctx,
  691                             &signbuf, &checksum, &qop_state);
  692                         if (maj_stat != GSS_S_COMPLETE
  693                             || qop_state != gd->gd_qop) {
  694                                 continue;
  695                         }
  696                         if (maj_stat == GSS_S_CONTEXT_EXPIRED) {
  697                                 rpc_gss_destroy_context(auth, TRUE);
  698                                 break;
  699                         }
  700                         //rpc_gss_purge_reqs(gd, seq);
  701                         LIST_FOREACH_SAFE(pr, &reqs, pr_link, npr)
  702                                 mem_free(pr, sizeof(*pr));
  703 
  704                         if (gd->gd_cred.gc_svc == rpc_gss_svc_none) {
  705                                 return (TRUE);
  706                         } else {
  707                                 if (!xdr_rpc_gss_unwrap_data(resultsp,
  708                                         gd->gd_ctx, gd->gd_qop,
  709                                         gd->gd_cred.gc_svc, seq)) {
  710                                         return (FALSE);
  711                                 }
  712                         }
  713                         return (TRUE);
  714                 }
  715         }
  716 
  717         /*
  718          * We didn't match - put back any entries for this XID so that
  719          * a future call to validate can retry.
  720          */
  721         mtx_lock(&gd->gd_lock);
  722         LIST_FOREACH_SAFE(pr, &reqs, pr_link, npr) {
  723                 LIST_REMOVE(pr, pr_link);
  724                 LIST_INSERT_HEAD(&gd->gd_reqs, pr, pr_link);
  725         }
  726         mtx_unlock(&gd->gd_lock);
  727 
  728         /*
  729          * Nothing matches - give up.
  730          */
  731         _rpc_gss_set_error(RPC_GSS_ER_SYSTEMERROR, EPERM);
  732         m_freem(*resultsp);
  733         *resultsp = NULL;
  734         return (FALSE);
  735 }
  736 
  737 static bool_t
  738 rpc_gss_init(AUTH *auth, rpc_gss_options_ret_t *options_ret)
  739 {
  740         struct thread           *td = curthread;
  741         struct ucred            *crsave;
  742         struct rpc_gss_data     *gd;
  743         struct rpc_gss_init_res  gr;
  744         gss_buffer_desc         principal_desc;
  745         gss_buffer_desc         *recv_tokenp, recv_token, send_token;
  746         gss_name_t              name;
  747         OM_uint32                maj_stat, min_stat, call_stat;
  748         const char              *mech;
  749         struct rpc_callextra     ext;
  750         gss_OID                 mech_oid;
  751         gss_OID_set             mechlist;
  752 
  753         rpc_gss_log_debug("in rpc_gss_refresh()");
  754         
  755         gd = AUTH_PRIVATE(auth);
  756         
  757         mtx_lock(&gd->gd_lock);
  758         /*
  759          * If the context isn't in START state, someone else is
  760          * refreshing - we wait till they are done. If they fail, they
  761          * will put the state back to START and we can try (most
  762          * likely to also fail).
  763          */
  764         while (gd->gd_state != RPCSEC_GSS_START
  765             && gd->gd_state != RPCSEC_GSS_ESTABLISHED) {
  766                 msleep(gd, &gd->gd_lock, 0, "gssstate", 0);
  767         }
  768         if (gd->gd_state == RPCSEC_GSS_ESTABLISHED) {
  769                 mtx_unlock(&gd->gd_lock);
  770                 return (TRUE);
  771         }
  772         gd->gd_state = RPCSEC_GSS_CONTEXT;
  773         mtx_unlock(&gd->gd_lock);
  774 
  775         gd->gd_cred.gc_proc = RPCSEC_GSS_INIT;
  776         gd->gd_cred.gc_seq = 0;
  777 
  778         /*
  779          * For KerberosV, if there is a client principal name, that implies
  780          * that this is a host based initiator credential in the default
  781          * keytab file. For this case, it is necessary to do a
  782          * gss_acquire_cred(). When this is done, the gssd daemon will
  783          * do the equivalent of "kinit -k" to put a TGT for the name in
  784          * the credential cache file for the gssd daemon.
  785          */
  786         if (gd->gd_clntprincipal != NULL &&
  787             rpc_gss_mech_to_oid("kerberosv5", &mech_oid) &&
  788             gd->gd_mech == mech_oid) {
  789                 /* Get rid of any old credential. */
  790                 if (gd->gd_options.my_cred != GSS_C_NO_CREDENTIAL) {
  791                         gss_release_cred(&min_stat, &gd->gd_options.my_cred);
  792                         gd->gd_options.my_cred = GSS_C_NO_CREDENTIAL;
  793                 }
  794         
  795                 /*
  796                  * The mechanism must be set to KerberosV for acquisition
  797                  * of credentials to work reliably.
  798                  */
  799                 maj_stat = gss_create_empty_oid_set(&min_stat, &mechlist);
  800                 if (maj_stat != GSS_S_COMPLETE) {
  801                         options_ret->major_status = maj_stat;
  802                         options_ret->minor_status = min_stat;
  803                         goto out;
  804                 }
  805                 maj_stat = gss_add_oid_set_member(&min_stat, gd->gd_mech,
  806                     &mechlist);
  807                 if (maj_stat != GSS_S_COMPLETE) {
  808                         options_ret->major_status = maj_stat;
  809                         options_ret->minor_status = min_stat;
  810                         gss_release_oid_set(&min_stat, &mechlist);
  811                         goto out;
  812                 }
  813         
  814                 principal_desc.value = (void *)gd->gd_clntprincipal;
  815                 principal_desc.length = strlen(gd->gd_clntprincipal);
  816                 maj_stat = gss_import_name(&min_stat, &principal_desc,
  817                     GSS_C_NT_HOSTBASED_SERVICE, &name);
  818                 if (maj_stat != GSS_S_COMPLETE) {
  819                         options_ret->major_status = maj_stat;
  820                         options_ret->minor_status = min_stat;
  821                         gss_release_oid_set(&min_stat, &mechlist);
  822                         goto out;
  823                 }
  824                 /* Acquire the credentials. */
  825                 maj_stat = gss_acquire_cred(&min_stat, name, 0,
  826                     mechlist, GSS_C_INITIATE,
  827                     &gd->gd_options.my_cred, NULL, NULL);
  828                 gss_release_name(&min_stat, &name);
  829                 gss_release_oid_set(&min_stat, &mechlist);
  830                 if (maj_stat != GSS_S_COMPLETE) {
  831                         options_ret->major_status = maj_stat;
  832                         options_ret->minor_status = min_stat;
  833                         goto out;
  834                 }
  835         }
  836 
  837         principal_desc.value = (void *)gd->gd_principal;
  838         principal_desc.length = strlen(gd->gd_principal);
  839         maj_stat = gss_import_name(&min_stat, &principal_desc,
  840             GSS_C_NT_HOSTBASED_SERVICE, &name);
  841         if (maj_stat != GSS_S_COMPLETE) {
  842                 options_ret->major_status = maj_stat;
  843                 options_ret->minor_status = min_stat;
  844                 goto out;
  845         }
  846 
  847         /* GSS context establishment loop. */
  848         memset(&recv_token, 0, sizeof(recv_token));
  849         memset(&gr, 0, sizeof(gr));
  850         memset(options_ret, 0, sizeof(*options_ret));
  851         options_ret->major_status = GSS_S_FAILURE;
  852         recv_tokenp = GSS_C_NO_BUFFER;
  853         
  854         for (;;) {
  855                 crsave = td->td_ucred;
  856                 td->td_ucred = gd->gd_ucred;
  857                 maj_stat = gss_init_sec_context(&min_stat,
  858                     gd->gd_options.my_cred,
  859                     &gd->gd_ctx,
  860                     name,
  861                     gd->gd_mech,
  862                     gd->gd_options.req_flags,
  863                     gd->gd_options.time_req,
  864                     gd->gd_options.input_channel_bindings,
  865                     recv_tokenp,
  866                     &gd->gd_mech,       /* used mech */
  867                     &send_token,
  868                     &options_ret->ret_flags,
  869                     &options_ret->time_req);
  870                 td->td_ucred = crsave;
  871                 
  872                 /*
  873                  * Free the token which we got from the server (if
  874                  * any).  Remember that this was allocated by XDR, not
  875                  * GSS-API.
  876                  */
  877                 if (recv_tokenp != GSS_C_NO_BUFFER) {
  878                         xdr_free((xdrproc_t) xdr_gss_buffer_desc,
  879                             (char *) &recv_token);
  880                         recv_tokenp = GSS_C_NO_BUFFER;
  881                 }
  882                 if (gd->gd_mech && rpc_gss_oid_to_mech(gd->gd_mech, &mech)) {
  883                         strlcpy(options_ret->actual_mechanism,
  884                             mech,
  885                             sizeof(options_ret->actual_mechanism));
  886                 }
  887                 if (maj_stat != GSS_S_COMPLETE &&
  888                     maj_stat != GSS_S_CONTINUE_NEEDED) {
  889                         rpc_gss_log_status("gss_init_sec_context", gd->gd_mech,
  890                             maj_stat, min_stat);
  891                         options_ret->major_status = maj_stat;
  892                         options_ret->minor_status = min_stat;
  893                         break;
  894                 }
  895                 if (send_token.length != 0) {
  896                         memset(&gr, 0, sizeof(gr));
  897                         
  898                         bzero(&ext, sizeof(ext));
  899                         ext.rc_auth = auth;
  900                         call_stat = CLNT_CALL_EXT(gd->gd_clnt, &ext, NULLPROC,
  901                             (xdrproc_t)xdr_gss_buffer_desc,
  902                             &send_token,
  903                             (xdrproc_t)xdr_rpc_gss_init_res,
  904                             (caddr_t)&gr, AUTH_TIMEOUT);
  905                         
  906                         gss_release_buffer(&min_stat, &send_token);
  907                         
  908                         if (call_stat != RPC_SUCCESS)
  909                                 break;
  910 
  911                         if (gr.gr_major != GSS_S_COMPLETE &&
  912                             gr.gr_major != GSS_S_CONTINUE_NEEDED) {
  913                                 rpc_gss_log_status("server reply", gd->gd_mech,
  914                                     gr.gr_major, gr.gr_minor);
  915                                 options_ret->major_status = gr.gr_major;
  916                                 options_ret->minor_status = gr.gr_minor;
  917                                 break;
  918                         }
  919                         
  920                         /*
  921                          * Save the server's gr_handle value, freeing
  922                          * what we have already (remember that this
  923                          * was allocated by XDR, not GSS-API).
  924                          */
  925                         if (gr.gr_handle.length != 0) {
  926                                 xdr_free((xdrproc_t) xdr_gss_buffer_desc,
  927                                     (char *) &gd->gd_cred.gc_handle);
  928                                 gd->gd_cred.gc_handle = gr.gr_handle;
  929                         }
  930 
  931                         /*
  932                          * Save the server's token as well.
  933                          */
  934                         if (gr.gr_token.length != 0) {
  935                                 recv_token = gr.gr_token;
  936                                 recv_tokenp = &recv_token;
  937                         }
  938 
  939                         /*
  940                          * Since we have copied out all the bits of gr
  941                          * which XDR allocated for us, we don't need
  942                          * to free it.
  943                          */
  944                         gd->gd_cred.gc_proc = RPCSEC_GSS_CONTINUE_INIT;
  945                 }
  946 
  947                 if (maj_stat == GSS_S_COMPLETE) {
  948                         gss_buffer_desc   bufin;
  949                         u_int seq, qop_state = 0;
  950 
  951                         /* 
  952                          * gss header verifier,
  953                          * usually checked in gss_validate
  954                          */
  955                         seq = htonl(gr.gr_win);
  956                         bufin.value = (unsigned char *)&seq;
  957                         bufin.length = sizeof(seq);
  958 
  959                         maj_stat = gss_verify_mic(&min_stat, gd->gd_ctx,
  960                             &bufin, &gd->gd_verf, &qop_state);
  961 
  962                         if (maj_stat != GSS_S_COMPLETE ||
  963                             qop_state != gd->gd_qop) {
  964                                 rpc_gss_log_status("gss_verify_mic", gd->gd_mech,
  965                                     maj_stat, min_stat);
  966                                 if (maj_stat == GSS_S_CONTEXT_EXPIRED) {
  967                                         rpc_gss_destroy_context(auth, TRUE);
  968                                 }
  969                                 _rpc_gss_set_error(RPC_GSS_ER_SYSTEMERROR,
  970                                     EPERM);
  971                                 options_ret->major_status = maj_stat;
  972                                 options_ret->minor_status = min_stat;
  973                                 break;
  974                         }
  975 
  976                         options_ret->major_status = GSS_S_COMPLETE;
  977                         options_ret->minor_status = 0;
  978                         options_ret->rpcsec_version = gd->gd_cred.gc_version;
  979                         options_ret->gss_context = gd->gd_ctx;
  980 
  981                         gd->gd_cred.gc_proc = RPCSEC_GSS_DATA;
  982                         gd->gd_seq = 1;
  983                         gd->gd_win = gr.gr_win;
  984                         break;
  985                 }
  986         }
  987 
  988         gss_release_name(&min_stat, &name);
  989         xdr_free((xdrproc_t) xdr_gss_buffer_desc,
  990             (char *) &gd->gd_verf);
  991 
  992 out:
  993         /* End context negotiation loop. */
  994         if (gd->gd_cred.gc_proc != RPCSEC_GSS_DATA) {
  995                 rpc_createerr.cf_stat = RPC_AUTHERROR;
  996                 _rpc_gss_set_error(RPC_GSS_ER_SYSTEMERROR, EPERM);
  997                 if (gd->gd_ctx) {
  998                         gss_delete_sec_context(&min_stat, &gd->gd_ctx,
  999                                 GSS_C_NO_BUFFER);
 1000                 }
 1001                 mtx_lock(&gd->gd_lock);
 1002                 gd->gd_state = RPCSEC_GSS_START;
 1003                 wakeup(gd);
 1004                 mtx_unlock(&gd->gd_lock);
 1005                 return (FALSE);
 1006         }
 1007         
 1008         mtx_lock(&gd->gd_lock);
 1009         gd->gd_state = RPCSEC_GSS_ESTABLISHED;
 1010         wakeup(gd);
 1011         mtx_unlock(&gd->gd_lock);
 1012 
 1013         return (TRUE);
 1014 }
 1015 
 1016 static bool_t
 1017 rpc_gss_refresh(AUTH *auth, void *msg)
 1018 {
 1019         struct rpc_msg *reply = (struct rpc_msg *) msg;
 1020         rpc_gss_options_ret_t options;
 1021         struct rpc_gss_data *gd;
 1022 
 1023         gd = AUTH_PRIVATE(auth);
 1024         
 1025         /*
 1026          * If the context is in DESTROYING state, then just return, since
 1027          * there is no point in refreshing the credentials.
 1028          */
 1029         mtx_lock(&gd->gd_lock);
 1030         if (gd->gd_state == RPCSEC_GSS_DESTROYING) {
 1031                 mtx_unlock(&gd->gd_lock);
 1032                 return (FALSE);
 1033         }
 1034         mtx_unlock(&gd->gd_lock);
 1035 
 1036         /*
 1037          * If the error was RPCSEC_GSS_CREDPROBLEM of
 1038          * RPCSEC_GSS_CTXPROBLEM we start again from scratch. All
 1039          * other errors are fatal.
 1040          */
 1041         if (reply->rm_reply.rp_stat == MSG_DENIED
 1042             && reply->rm_reply.rp_rjct.rj_stat == AUTH_ERROR
 1043             && (reply->rm_reply.rp_rjct.rj_why == RPCSEC_GSS_CREDPROBLEM
 1044                 || reply->rm_reply.rp_rjct.rj_why == RPCSEC_GSS_CTXPROBLEM)) {
 1045                 rpc_gss_destroy_context(auth, FALSE);
 1046                 memset(&options, 0, sizeof(options));
 1047                 return (rpc_gss_init(auth, &options));
 1048         }
 1049 
 1050         return (FALSE);
 1051 }
 1052 
 1053 static void
 1054 rpc_gss_destroy_context(AUTH *auth, bool_t send_destroy)
 1055 {
 1056         struct rpc_gss_data     *gd;
 1057         struct rpc_pending_request *pr;
 1058         OM_uint32                min_stat;
 1059         struct rpc_callextra     ext;
 1060 
 1061         rpc_gss_log_debug("in rpc_gss_destroy_context()");
 1062         
 1063         gd = AUTH_PRIVATE(auth);
 1064         
 1065         mtx_lock(&gd->gd_lock);
 1066         /*
 1067          * If the context isn't in ESTABISHED state, someone else is
 1068          * destroying/refreshing - we wait till they are done.
 1069          */
 1070         if (gd->gd_state != RPCSEC_GSS_ESTABLISHED) {
 1071                 while (gd->gd_state != RPCSEC_GSS_START
 1072                     && gd->gd_state != RPCSEC_GSS_ESTABLISHED)
 1073                         msleep(gd, &gd->gd_lock, 0, "gssstate", 0);
 1074                 mtx_unlock(&gd->gd_lock);
 1075                 return;
 1076         }
 1077         gd->gd_state = RPCSEC_GSS_DESTROYING;
 1078         mtx_unlock(&gd->gd_lock);
 1079 
 1080         if (send_destroy) {
 1081                 gd->gd_cred.gc_proc = RPCSEC_GSS_DESTROY;
 1082                 bzero(&ext, sizeof(ext));
 1083                 ext.rc_auth = auth;
 1084                 CLNT_CALL_EXT(gd->gd_clnt, &ext, NULLPROC,
 1085                     (xdrproc_t)xdr_void, NULL,
 1086                     (xdrproc_t)xdr_void, NULL, AUTH_TIMEOUT);
 1087         }
 1088 
 1089         while ((pr = LIST_FIRST(&gd->gd_reqs)) != NULL) {
 1090                 LIST_REMOVE(pr, pr_link);
 1091                 mem_free(pr, sizeof(*pr));
 1092         }
 1093 
 1094         /*
 1095          * Free the context token. Remember that this was
 1096          * allocated by XDR, not GSS-API.
 1097          */
 1098         xdr_free((xdrproc_t) xdr_gss_buffer_desc,
 1099             (char *) &gd->gd_cred.gc_handle);
 1100         gd->gd_cred.gc_handle.length = 0;
 1101 
 1102         if (gd->gd_ctx != GSS_C_NO_CONTEXT)
 1103                 gss_delete_sec_context(&min_stat, &gd->gd_ctx, NULL);
 1104 
 1105         mtx_lock(&gd->gd_lock);
 1106         gd->gd_state = RPCSEC_GSS_START;
 1107         wakeup(gd);
 1108         mtx_unlock(&gd->gd_lock);
 1109 }
 1110 
 1111 static void
 1112 rpc_gss_destroy(AUTH *auth)
 1113 {
 1114         struct rpc_gss_data     *gd;
 1115         
 1116         rpc_gss_log_debug("in rpc_gss_destroy()");
 1117         
 1118         gd = AUTH_PRIVATE(auth);
 1119         
 1120         if (!refcount_release(&gd->gd_refs))
 1121                 return;
 1122 
 1123         rpc_gss_destroy_context(auth, TRUE);
 1124         
 1125         CLNT_RELEASE(gd->gd_clnt);
 1126         crfree(gd->gd_ucred);
 1127         free(gd->gd_principal, M_RPC);
 1128         if (gd->gd_clntprincipal != NULL)
 1129                 free(gd->gd_clntprincipal, M_RPC);
 1130         if (gd->gd_verf.value)
 1131                 xdr_free((xdrproc_t) xdr_gss_buffer_desc,
 1132                     (char *) &gd->gd_verf);
 1133         mtx_destroy(&gd->gd_lock);
 1134 
 1135         mem_free(gd, sizeof(*gd));
 1136         mem_free(auth, sizeof(*auth));
 1137 }
 1138 
 1139 int
 1140 rpc_gss_max_data_length(AUTH *auth, int max_tp_unit_len)
 1141 {
 1142         struct rpc_gss_data     *gd;
 1143         int                     want_conf;
 1144         OM_uint32               max;
 1145         OM_uint32               maj_stat, min_stat;
 1146         int                     result;
 1147 
 1148         gd = AUTH_PRIVATE(auth);
 1149 
 1150         switch (gd->gd_cred.gc_svc) {
 1151         case rpc_gss_svc_none:
 1152                 return (max_tp_unit_len);
 1153                 break;
 1154 
 1155         case rpc_gss_svc_default:
 1156         case rpc_gss_svc_integrity:
 1157                 want_conf = FALSE;
 1158                 break;
 1159 
 1160         case rpc_gss_svc_privacy:
 1161                 want_conf = TRUE;
 1162                 break;
 1163 
 1164         default:
 1165                 return (0);
 1166         }
 1167 
 1168         maj_stat = gss_wrap_size_limit(&min_stat, gd->gd_ctx, want_conf,
 1169             gd->gd_qop, max_tp_unit_len, &max);
 1170 
 1171         if (maj_stat == GSS_S_COMPLETE) {
 1172                 result = (int) max;
 1173                 if (result < 0)
 1174                         result = 0;
 1175                 return (result);
 1176         } else {
 1177                 rpc_gss_log_status("gss_wrap_size_limit", gd->gd_mech,
 1178                     maj_stat, min_stat);
 1179                 return (0);
 1180         }
 1181 }

Cache object: 98ab283015df3ee1a797f1c34d7c9115


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.