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

Cache object: 04b510f2334cd559544d57e5be11eb3e


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