1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright 2015 Nexenta Systems, Inc.  All rights reserved.
  24  * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved.
  25  * Copyright 2012 Milan Jurik. All rights reserved.
  26  * Copyright 2012 Marcel Telka <marcel@telka.sk>
  27  * Copyright 2018 OmniOS Community Edition (OmniOSce) Association.
  28  */
  29 
  30 /*
  31  * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved.
  32  *
  33  * $Id: svc_auth_gssapi.c,v 1.19 1994/10/27 12:38:51 jik Exp $
  34  */
  35 
  36 /*
  37  * Server side handling of RPCSEC_GSS flavor.
  38  */
  39 
  40 #include <sys/systm.h>
  41 #include <sys/kstat.h>
  42 #include <sys/cmn_err.h>
  43 #include <sys/debug.h>
  44 #include <sys/types.h>
  45 #include <sys/time.h>
  46 #include <gssapi/gssapi.h>
  47 #include <gssapi/gssapi_ext.h>
  48 #include <rpc/rpc.h>
  49 #include <rpc/rpcsec_defs.h>
  50 #include <sys/sunddi.h>
  51 #include <sys/atomic.h>
  52 
  53 extern bool_t __rpc_gss_make_principal(rpc_gss_principal_t *, gss_buffer_t);
  54 
  55 #ifdef  DEBUG
  56 extern void prom_printf(const char *, ...);
  57 #endif
  58 
  59 #ifdef  _KERNEL
  60 #define memcmp(a, b, l) bcmp((a), (b), (l))
  61 #endif
  62 
  63 
  64 /*
  65  * Sequence window definitions.
  66  */
  67 #define SEQ_ARR_SIZE    4
  68 #define SEQ_WIN         (SEQ_ARR_SIZE*32)
  69 #define SEQ_HI_BIT      0x80000000
  70 #define SEQ_LO_BIT      1
  71 #define DIV_BY_32       5
  72 #define SEQ_MASK        0x1f
  73 #define SEQ_MAX         ((unsigned int)0x80000000)
  74 
  75 
  76 /* cache retransmit data */
  77 typedef struct _retrans_entry {
  78         uint32_t        xid;
  79         rpc_gss_init_res result;
  80 } retrans_entry;
  81 
  82 /*
  83  * Server side RPCSEC_GSS context information.
  84  */
  85 typedef struct _svc_rpc_gss_data {
  86         struct _svc_rpc_gss_data        *next, *prev;
  87         struct _svc_rpc_gss_data        *lru_next, *lru_prev;
  88         bool_t                          established;
  89         gss_ctx_id_t                    context;
  90         gss_buffer_desc                 client_name;
  91         time_t                          expiration;
  92         uint_t                          seq_num;
  93         uint_t                          seq_bits[SEQ_ARR_SIZE];
  94         uint_t                          key;
  95         OM_uint32                       qop;
  96         bool_t                          done_docallback;
  97         bool_t                          locked;
  98         rpc_gss_rawcred_t               raw_cred;
  99         rpc_gss_ucred_t                 u_cred;
 100         time_t                          u_cred_set;
 101         void                            *cookie;
 102         gss_cred_id_t                   deleg;
 103         kmutex_t                        clm;
 104         int                             ref_cnt;
 105         time_t                          last_ref_time;
 106         bool_t                          stale;
 107         retrans_entry                   *retrans_data;
 108 } svc_rpc_gss_data;
 109 
 110 /*
 111  * Data structures used for LRU based context management.
 112  */
 113 
 114 
 115 #define HASH(key) ((key) % svc_rpc_gss_hashmod)
 116 /* Size of hash table for svc_rpc_gss_data structures */
 117 #define GSS_DATA_HASH_SIZE      1024
 118 
 119 /*
 120  * The following two defines specify a time delta that is used in
 121  * sweep_clients. When the last_ref_time of a context is older than
 122  * than the current time minus the delta, i.e, the context has not
 123  * been referenced in the last delta seconds, we will return the
 124  * context back to the cache if the ref_cnt is zero. The first delta
 125  * value will be used when sweep_clients is called from
 126  * svc_data_reclaim, the kmem_cache reclaim call back. We will reclaim
 127  * all entries except those that are currently "active". By active we
 128  * mean those that have been referenced in the last ACTIVE_DELTA
 129  * seconds. If sweep_client is not being called from reclaim, then we
 130  * will reclaim all entries that are "inactive". By inactive we mean
 131  * those entries that have not been accessed in INACTIVE_DELTA
 132  * seconds.  Note we always assume that ACTIVE_DELTA is less than
 133  * INACTIVE_DELTA, so that reaping entries from a reclaim operation
 134  * will necessarily imply reaping all "inactive" entries and then
 135  * some.
 136  */
 137 
 138 /*
 139  * If low on memory reap cache entries that have not been active for
 140  * ACTIVE_DELTA seconds and have a ref_cnt equal to zero.
 141  */
 142 #define ACTIVE_DELTA            30*60           /* 30 minutes */
 143 
 144 /*
 145  * If in sweeping contexts we find contexts with a ref_cnt equal to zero
 146  * and the context has not been referenced in INACTIVE_DELTA seconds, return
 147  * the entry to the cache.
 148  */
 149 #define INACTIVE_DELTA          8*60*60         /* 8 hours */
 150 
 151 int                             svc_rpc_gss_hashmod = GSS_DATA_HASH_SIZE;
 152 static svc_rpc_gss_data         **clients;
 153 static svc_rpc_gss_data         *lru_first, *lru_last;
 154 static time_t                   sweep_interval = 60*60;
 155 static time_t                   last_swept = 0;
 156 static int                      num_gss_contexts = 0;
 157 static time_t                   svc_rpcgss_gid_timeout = 60*60*12;
 158 static kmem_cache_t             *svc_data_handle;
 159 static time_t                   svc_rpc_gss_active_delta = ACTIVE_DELTA;
 160 static time_t                   svc_rpc_gss_inactive_delta = INACTIVE_DELTA;
 161 
 162 /*
 163  * lock used with context/lru variables
 164  */
 165 static kmutex_t                 ctx_mutex;
 166 
 167 /*
 168  * Data structure to contain cache statistics
 169  */
 170 
 171 static struct {
 172         int64_t total_entries_allocated;
 173         int64_t no_reclaims;
 174         int64_t no_returned_by_reclaim;
 175 } svc_rpc_gss_cache_stats;
 176 
 177 
 178 /*
 179  * lock used with server credential variables list
 180  *
 181  * server cred list locking guidelines:
 182  * - Writer's lock holder has exclusive access to the list
 183  */
 184 static krwlock_t                cred_lock;
 185 
 186 /*
 187  * server callback list
 188  */
 189 typedef struct rpc_gss_cblist_s {
 190         struct rpc_gss_cblist_s         *next;
 191         rpc_gss_callback_t      cb;
 192 } rpc_gss_cblist_t;
 193 
 194 static rpc_gss_cblist_t                 *rpc_gss_cblist = NULL;
 195 
 196 /*
 197  * lock used with callback variables
 198  */
 199 static kmutex_t                 cb_mutex;
 200 
 201 /*
 202  * forward declarations
 203  */
 204 static bool_t                   svc_rpc_gss_wrap();
 205 static bool_t                   svc_rpc_gss_unwrap();
 206 static svc_rpc_gss_data         *create_client();
 207 static svc_rpc_gss_data         *get_client();
 208 static svc_rpc_gss_data         *find_client();
 209 static void                     destroy_client();
 210 static void                     sweep_clients(bool_t);
 211 static void                     insert_client();
 212 static bool_t                   check_verf(struct rpc_msg *, gss_ctx_id_t,
 213                                         int *, uid_t);
 214 static bool_t                   set_response_verf();
 215 static void                     retrans_add(svc_rpc_gss_data *, uint32_t,
 216                                         rpc_gss_init_res *);
 217 static void                     retrans_del(svc_rpc_gss_data *);
 218 static bool_t                   transfer_sec_context(svc_rpc_gss_data *);
 219 static void                     common_client_data_free(svc_rpc_gss_data *);
 220 
 221 /*
 222  * server side wrap/unwrap routines
 223  */
 224 struct svc_auth_ops svc_rpc_gss_ops = {
 225         svc_rpc_gss_wrap,
 226         svc_rpc_gss_unwrap,
 227 };
 228 
 229 /* taskq(9F) */
 230 typedef struct svcrpcsec_gss_taskq_arg {
 231         SVCXPRT                 *rq_xprt;
 232         rpc_gss_init_arg        *rpc_call_arg;
 233         struct rpc_msg          *msg;
 234         svc_rpc_gss_data        *client_data;
 235         uint_t                  cr_version;
 236         rpc_gss_service_t       cr_service;
 237 } svcrpcsec_gss_taskq_arg_t;
 238 
 239 /* gssd is single threaded, so 1 thread for the taskq is probably good/ok */
 240 int rpcsec_gss_init_taskq_nthreads = 1;
 241 static ddi_taskq_t *svcrpcsec_gss_init_taskq = NULL;
 242 
 243 extern struct rpc_msg *rpc_msg_dup(struct rpc_msg *);
 244 extern void rpc_msg_free(struct rpc_msg **, int);
 245 
 246 /*
 247  * from svc_clts.c:
 248  * Transport private data.
 249  * Kept in xprt->xp_p2buf.
 250  */
 251 struct udp_data {
 252         mblk_t  *ud_resp;                       /* buffer for response */
 253         mblk_t  *ud_inmp;                       /* mblk chain of request */
 254 };
 255 
 256 /*ARGSUSED*/
 257 static int
 258 svc_gss_data_create(void *buf, void *pdata, int kmflag)
 259 {
 260         svc_rpc_gss_data *client_data = (svc_rpc_gss_data *)buf;
 261 
 262         mutex_init(&client_data->clm, NULL, MUTEX_DEFAULT, NULL);
 263 
 264         return (0);
 265 }
 266 
 267 /*ARGSUSED*/
 268 static void
 269 svc_gss_data_destroy(void *buf, void *pdata)
 270 {
 271         svc_rpc_gss_data *client_data = (svc_rpc_gss_data *)buf;
 272 
 273         mutex_destroy(&client_data->clm);
 274 }
 275 
 276 
 277 /*ARGSUSED*/
 278 static void
 279 svc_gss_data_reclaim(void *pdata)
 280 {
 281         mutex_enter(&ctx_mutex);
 282 
 283         svc_rpc_gss_cache_stats.no_reclaims++;
 284         sweep_clients(TRUE);
 285 
 286         mutex_exit(&ctx_mutex);
 287 }
 288 
 289 /*
 290  *  Init stuff on the server side.
 291  */
 292 void
 293 svc_gss_init()
 294 {
 295         mutex_init(&cb_mutex, NULL, MUTEX_DEFAULT, NULL);
 296         mutex_init(&ctx_mutex, NULL, MUTEX_DEFAULT, NULL);
 297         rw_init(&cred_lock, NULL, RW_DEFAULT, NULL);
 298         clients = (svc_rpc_gss_data **)
 299             kmem_zalloc(svc_rpc_gss_hashmod * sizeof (svc_rpc_gss_data *),
 300             KM_SLEEP);
 301         svc_data_handle = kmem_cache_create("rpc_gss_data_cache",
 302             sizeof (svc_rpc_gss_data), 0,
 303             svc_gss_data_create,
 304             svc_gss_data_destroy,
 305             svc_gss_data_reclaim,
 306             NULL, NULL, 0);
 307 
 308         if (svcrpcsec_gss_init_taskq == NULL) {
 309                 svcrpcsec_gss_init_taskq = ddi_taskq_create(NULL,
 310                     "rpcsec_gss_init_taskq", rpcsec_gss_init_taskq_nthreads,
 311                     TASKQ_DEFAULTPRI, 0);
 312                 if (svcrpcsec_gss_init_taskq == NULL)
 313                         cmn_err(CE_NOTE,
 314                             "svc_gss_init: ddi_taskq_create failed");
 315         }
 316 }
 317 
 318 /*
 319  * Destroy structures allocated in svc_gss_init().
 320  * This routine is called by _init() if mod_install() failed.
 321  */
 322 void
 323 svc_gss_fini()
 324 {
 325         mutex_destroy(&cb_mutex);
 326         mutex_destroy(&ctx_mutex);
 327         rw_destroy(&cred_lock);
 328         kmem_free(clients, svc_rpc_gss_hashmod * sizeof (svc_rpc_gss_data *));
 329         kmem_cache_destroy(svc_data_handle);
 330 }
 331 
 332 /*
 333  * Cleanup routine for destroying context, called after service
 334  * procedure is executed. Actually we just decrement the reference count
 335  * associated with this context. If the reference count is zero and the
 336  * context is marked as stale, we would then destroy the context. Additionally,
 337  * we check if its been longer than sweep_interval since the last sweep_clients
 338  * was run, and if so run sweep_clients to free all stale contexts with zero
 339  * reference counts or contexts that are old. (Haven't been access in
 340  * svc_rpc_inactive_delta seconds).
 341  */
 342 void
 343 rpc_gss_cleanup(SVCXPRT *clone_xprt)
 344 {
 345         svc_rpc_gss_data        *cl;
 346         SVCAUTH                 *svcauth;
 347 
 348         /*
 349          * First check if current context needs to be cleaned up.
 350          * There might be other threads stale this client data
 351          * in between.
 352          */
 353         svcauth = &clone_xprt->xp_auth;
 354         mutex_enter(&ctx_mutex);
 355         if ((cl = (svc_rpc_gss_data *)svcauth->svc_ah_private) != NULL) {
 356                 mutex_enter(&cl->clm);
 357                 ASSERT(cl->ref_cnt > 0);
 358                 if (--cl->ref_cnt == 0 && cl->stale) {
 359                         mutex_exit(&cl->clm);
 360                         destroy_client(cl);
 361                         svcauth->svc_ah_private = NULL;
 362                 } else
 363                         mutex_exit(&cl->clm);
 364         }
 365 
 366         /*
 367          * Check for other expired contexts.
 368          */
 369         if ((gethrestime_sec() - last_swept) > sweep_interval)
 370                 sweep_clients(FALSE);
 371 
 372         mutex_exit(&ctx_mutex);
 373 }
 374 
 375 /*
 376  * Shift the array arr of length arrlen right by nbits bits.
 377  */
 378 static void
 379 shift_bits(uint_t *arr, int arrlen, int nbits)
 380 {
 381         int     i, j;
 382         uint_t  lo, hi;
 383 
 384         /*
 385          * If the number of bits to be shifted exceeds SEQ_WIN, just
 386          * zero out the array.
 387          */
 388         if (nbits < SEQ_WIN) {
 389                 for (i = 0; i < nbits; i++) {
 390                         hi = 0;
 391                         for (j = 0; j < arrlen; j++) {
 392                                 lo = arr[j] & SEQ_LO_BIT;
 393                                 arr[j] >>= 1;
 394                                 if (hi)
 395                                         arr[j] |= SEQ_HI_BIT;
 396                                 hi = lo;
 397                         }
 398                 }
 399         } else {
 400                 for (j = 0; j < arrlen; j++)
 401                         arr[j] = 0;
 402         }
 403 }
 404 
 405 /*
 406  * Check that the received sequence number seq_num is valid.
 407  */
 408 static bool_t
 409 check_seq(svc_rpc_gss_data *cl, uint_t seq_num, bool_t *kill_context)
 410 {
 411         int                     i, j;
 412         uint_t                  bit;
 413 
 414         /*
 415          * If it exceeds the maximum, kill context.
 416          */
 417         if (seq_num >= SEQ_MAX) {
 418                 *kill_context = TRUE;
 419                 RPCGSS_LOG0(4, "check_seq: seq_num not valid\n");
 420                 return (FALSE);
 421         }
 422 
 423         /*
 424          * If greater than the last seen sequence number, just shift
 425          * the sequence window so that it starts at the new sequence
 426          * number and extends downwards by SEQ_WIN.
 427          */
 428         if (seq_num > cl->seq_num) {
 429                 (void) shift_bits(cl->seq_bits, SEQ_ARR_SIZE,
 430                     (int)(seq_num - cl->seq_num));
 431                 cl->seq_bits[0] |= SEQ_HI_BIT;
 432                 cl->seq_num = seq_num;
 433                 return (TRUE);
 434         }
 435 
 436         /*
 437          * If it is outside the sequence window, return failure.
 438          */
 439         i = cl->seq_num - seq_num;
 440         if (i >= SEQ_WIN) {
 441                 RPCGSS_LOG0(4, "check_seq: seq_num is outside the window\n");
 442                 return (FALSE);
 443         }
 444 
 445         /*
 446          * If within sequence window, set the bit corresponding to it
 447          * if not already seen;  if already seen, return failure.
 448          */
 449         j = SEQ_MASK - (i & SEQ_MASK);
 450         bit = j > 0 ? (1 << j) : 1;
 451         i >>= DIV_BY_32;
 452         if (cl->seq_bits[i] & bit) {
 453                 RPCGSS_LOG0(4, "check_seq: sequence number already seen\n");
 454                 return (FALSE);
 455         }
 456         cl->seq_bits[i] |= bit;
 457         return (TRUE);
 458 }
 459 
 460 /*
 461  * Set server callback.
 462  */
 463 bool_t
 464 rpc_gss_set_callback(rpc_gss_callback_t *cb)
 465 {
 466         rpc_gss_cblist_t                *cbl, *tmp;
 467 
 468         if (cb->callback == NULL) {
 469                 RPCGSS_LOG0(1, "rpc_gss_set_callback: no callback to set\n");
 470                 return (FALSE);
 471         }
 472 
 473         /* check if there is already an entry in the rpc_gss_cblist. */
 474         mutex_enter(&cb_mutex);
 475         if (rpc_gss_cblist) {
 476                 for (tmp = rpc_gss_cblist; tmp != NULL; tmp = tmp->next) {
 477                         if ((tmp->cb.callback == cb->callback) &&
 478                             (tmp->cb.version == cb->version) &&
 479                             (tmp->cb.program == cb->program)) {
 480                                 mutex_exit(&cb_mutex);
 481                                 return (TRUE);
 482                         }
 483                 }
 484         }
 485 
 486         /* Not in rpc_gss_cblist.  Create a new entry. */
 487         if ((cbl = (rpc_gss_cblist_t *)kmem_alloc(sizeof (*cbl), KM_SLEEP))
 488             == NULL) {
 489                 mutex_exit(&cb_mutex);
 490                 return (FALSE);
 491         }
 492         cbl->cb = *cb;
 493         cbl->next = rpc_gss_cblist;
 494         rpc_gss_cblist = cbl;
 495         mutex_exit(&cb_mutex);
 496         return (TRUE);
 497 }
 498 
 499 /*
 500  * Locate callback (if specified) and call server.  Release any
 501  * delegated credentials unless passed to server and the server
 502  * accepts the context.  If a callback is not specified, accept
 503  * the incoming context.
 504  */
 505 static bool_t
 506 do_callback(struct svc_req *req, svc_rpc_gss_data *client_data)
 507 {
 508         rpc_gss_cblist_t                *cbl;
 509         bool_t                  ret = TRUE, found = FALSE;
 510         rpc_gss_lock_t          lock;
 511         OM_uint32               minor;
 512         mutex_enter(&cb_mutex);
 513         for (cbl = rpc_gss_cblist; cbl != NULL; cbl = cbl->next) {
 514                 if (req->rq_prog != cbl->cb.program ||
 515                     req->rq_vers != cbl->cb.version)
 516                         continue;
 517                 found = TRUE;
 518                 lock.locked = FALSE;
 519                 lock.raw_cred = &client_data->raw_cred;
 520                 ret = (*cbl->cb.callback)(req, client_data->deleg,
 521                     client_data->context, &lock, &client_data->cookie);
 522                 req->rq_xprt->xp_cookie = client_data->cookie;
 523 
 524                 if (ret) {
 525                         client_data->locked = lock.locked;
 526                         client_data->deleg = GSS_C_NO_CREDENTIAL;
 527                 }
 528                 break;
 529         }
 530         if (!found) {
 531                 if (client_data->deleg != GSS_C_NO_CREDENTIAL) {
 532                         (void) kgss_release_cred(&minor, &client_data->deleg,
 533                             crgetuid(CRED()));
 534                         client_data->deleg = GSS_C_NO_CREDENTIAL;
 535                 }
 536         }
 537         mutex_exit(&cb_mutex);
 538         return (ret);
 539 }
 540 
 541 /*
 542  * Get caller credentials.
 543  */
 544 bool_t
 545 rpc_gss_getcred(struct svc_req *req, rpc_gss_rawcred_t **rcred,
 546     rpc_gss_ucred_t **ucred, void **cookie)
 547 {
 548         SVCAUTH                 *svcauth;
 549         svc_rpc_gss_data        *client_data;
 550         int                     gssstat, gidlen;
 551 
 552         svcauth = &req->rq_xprt->xp_auth;
 553         client_data = (svc_rpc_gss_data *)svcauth->svc_ah_private;
 554 
 555         mutex_enter(&client_data->clm);
 556 
 557         if (rcred != NULL) {
 558                 svcauth->raw_cred = client_data->raw_cred;
 559                 *rcred = &svcauth->raw_cred;
 560         }
 561         if (ucred != NULL) {
 562                 *ucred = &client_data->u_cred;
 563 
 564                 if (client_data->u_cred_set == 0 ||
 565                     client_data->u_cred_set < gethrestime_sec()) {
 566                         if (client_data->u_cred_set == 0) {
 567                                 if ((gssstat = kgsscred_expname_to_unix_cred(
 568                                     &client_data->client_name,
 569                                     &client_data->u_cred.uid,
 570                                     &client_data->u_cred.gid,
 571                                     &client_data->u_cred.gidlist,
 572                                     &gidlen, crgetuid(CRED())))
 573                                     != GSS_S_COMPLETE) {
 574                                         RPCGSS_LOG(1, "rpc_gss_getcred: "
 575                                             "kgsscred_expname_to_unix_cred "
 576                                             "failed %x\n", gssstat);
 577                                         *ucred = NULL;
 578                                 } else {
 579                                         client_data->u_cred.gidlen =
 580                                             (short)gidlen;
 581                                         client_data->u_cred_set =
 582                                             gethrestime_sec() +
 583                                             svc_rpcgss_gid_timeout;
 584                                 }
 585                         } else if (client_data->u_cred_set
 586                             < gethrestime_sec()) {
 587                                 if ((gssstat = kgss_get_group_info(
 588                                     client_data->u_cred.uid,
 589                                     &client_data->u_cred.gid,
 590                                     &client_data->u_cred.gidlist,
 591                                     &gidlen, crgetuid(CRED())))
 592                                     != GSS_S_COMPLETE) {
 593                                         RPCGSS_LOG(1, "rpc_gss_getcred: "
 594                                             "kgss_get_group_info failed %x\n",
 595                                             gssstat);
 596                                         *ucred = NULL;
 597                                 } else {
 598                                         client_data->u_cred.gidlen =
 599                                             (short)gidlen;
 600                                         client_data->u_cred_set =
 601                                             gethrestime_sec() +
 602                                             svc_rpcgss_gid_timeout;
 603                                 }
 604                         }
 605                 }
 606         }
 607 
 608         if (cookie != NULL)
 609                 *cookie = client_data->cookie;
 610         req->rq_xprt->xp_cookie = client_data->cookie;
 611 
 612         mutex_exit(&client_data->clm);
 613 
 614         return (TRUE);
 615 }
 616 
 617 /*
 618  * Transfer the context data from the user land to the kernel.
 619  */
 620 bool_t transfer_sec_context(svc_rpc_gss_data *client_data) {
 621 
 622         gss_buffer_desc process_token;
 623         OM_uint32 gssstat, minor;
 624 
 625         /*
 626          * Call kgss_export_sec_context
 627          * if an error is returned log a message
 628          * go to error handling
 629          * Otherwise call kgss_import_sec_context to
 630          * convert the token into a context
 631          */
 632         gssstat  = kgss_export_sec_context(&minor, client_data->context,
 633                                 &process_token);
 634         /*
 635          * if export_sec_context returns an error we delete the
 636          * context just to be safe.
 637          */
 638         if (gssstat == GSS_S_NAME_NOT_MN) {
 639                 RPCGSS_LOG0(4, "svc_rpcsec_gss: export sec context "
 640                                 "Kernel mod unavailable\n");
 641 
 642         } else if (gssstat != GSS_S_COMPLETE) {
 643                 RPCGSS_LOG(1, "svc_rpcsec_gss: export sec context failed  "
 644                                 " gssstat = 0x%x\n", gssstat);
 645                 (void) gss_release_buffer(&minor, &process_token);
 646                 (void) kgss_delete_sec_context(&minor, &client_data->context,
 647                                 NULL);
 648                 return (FALSE);
 649 
 650         } else if (process_token.length == 0) {
 651                 RPCGSS_LOG0(1, "svc_rpcsec_gss:zero length token in response "
 652                                 "for export_sec_context, but "
 653                                 "gsstat == GSS_S_COMPLETE\n");
 654                 (void) kgss_delete_sec_context(&minor, &client_data->context,
 655                                 NULL);
 656                 return (FALSE);
 657 
 658         } else {
 659                 gssstat = kgss_import_sec_context(&minor, &process_token,
 660                                         client_data->context);
 661                 if (gssstat != GSS_S_COMPLETE) {
 662                         RPCGSS_LOG(1, "svc_rpcsec_gss: import sec context "
 663                                 " failed gssstat = 0x%x\n", gssstat);
 664                         (void) kgss_delete_sec_context(&minor,
 665                                 &client_data->context, NULL);
 666                         (void) gss_release_buffer(&minor, &process_token);
 667                         return (FALSE);
 668                 }
 669 
 670                 RPCGSS_LOG0(4, "gss_import_sec_context successful\n");
 671                 (void) gss_release_buffer(&minor, &process_token);
 672         }
 673 
 674         return (TRUE);
 675 }
 676 
 677 /*
 678  * do_gss_accept is called from a taskq and does all the work for a
 679  * RPCSEC_GSS_INIT call (mostly calling kgss_accept_sec_context()).
 680  */
 681 static enum auth_stat
 682 do_gss_accept(
 683         SVCXPRT *xprt,
 684         rpc_gss_init_arg *call_arg,
 685         struct rpc_msg *msg,
 686         svc_rpc_gss_data *client_data,
 687         uint_t cr_version,
 688         rpc_gss_service_t cr_service)
 689 {
 690         rpc_gss_init_res        call_res;
 691         gss_buffer_desc         output_token;
 692         OM_uint32               gssstat, minor, minor_stat, time_rec;
 693         int                     ret_flags, ret;
 694         gss_OID                 mech_type = GSS_C_NULL_OID;
 695         int                     free_mech_type = 1;
 696         struct svc_req          r, *rqst;
 697 
 698         rqst = &r;
 699         rqst->rq_xprt = xprt;
 700 
 701         /*
 702          * Initialize output_token.
 703          */
 704         output_token.length = 0;
 705         output_token.value = NULL;
 706 
 707         bzero((char *)&call_res, sizeof (call_res));
 708 
 709         mutex_enter(&client_data->clm);
 710         if (client_data->stale) {
 711                 ret = RPCSEC_GSS_NOCRED;
 712                 RPCGSS_LOG0(1, "_svcrpcsec_gss: client data stale\n");
 713                 goto error2;
 714         }
 715 
 716         /*
 717          * Any response we send will use ctx_handle, so set it now;
 718          * also set seq_window since this won't change.
 719          */
 720         call_res.ctx_handle.length = sizeof (client_data->key);
 721         call_res.ctx_handle.value = (char *)&client_data->key;
 722         call_res.seq_window = SEQ_WIN;
 723 
 724         gssstat = GSS_S_FAILURE;
 725         minor = 0;
 726         minor_stat = 0;
 727         rw_enter(&cred_lock, RW_READER);
 728 
 729         if (client_data->client_name.length) {
 730                 (void) gss_release_buffer(&minor,
 731                     &client_data->client_name);
 732         }
 733         gssstat = kgss_accept_sec_context(&minor_stat,
 734             &client_data->context,
 735             GSS_C_NO_CREDENTIAL,
 736             call_arg,
 737             GSS_C_NO_CHANNEL_BINDINGS,
 738             &client_data->client_name,
 739             &mech_type,
 740             &output_token,
 741             &ret_flags,
 742             &time_rec,
 743             NULL,               /* don't need a delegated cred back */
 744             crgetuid(CRED()));
 745 
 746         RPCGSS_LOG(4, "gssstat 0x%x \n", gssstat);
 747 
 748         if (gssstat == GSS_S_COMPLETE) {
 749                 /*
 750                  * Set the raw and unix credentials at this
 751                  * point.  This saves a lot of computation
 752                  * later when credentials are retrieved.
 753                  */
 754                 client_data->raw_cred.version = cr_version;
 755                 client_data->raw_cred.service = cr_service;
 756 
 757                 if (client_data->raw_cred.mechanism) {
 758                         kgss_free_oid(client_data->raw_cred.mechanism);
 759                         client_data->raw_cred.mechanism = NULL;
 760                 }
 761                 client_data->raw_cred.mechanism = (rpc_gss_OID) mech_type;
 762                 /*
 763                  * client_data is now responsible for freeing
 764                  * the data of 'mech_type'.
 765                  */
 766                 free_mech_type = 0;
 767 
 768                 if (client_data->raw_cred.client_principal) {
 769                         kmem_free((caddr_t)client_data->\
 770                             raw_cred.client_principal,
 771                             client_data->raw_cred.\
 772                             client_principal->len + sizeof (int));
 773                         client_data->raw_cred.client_principal = NULL;
 774                 }
 775 
 776                 /*
 777                  *  The client_name returned from
 778                  *  kgss_accept_sec_context() is in an
 779                  *  exported flat format.
 780                  */
 781                 if (! __rpc_gss_make_principal(
 782                     &client_data->raw_cred.client_principal,
 783                     &client_data->client_name)) {
 784                         RPCGSS_LOG0(1, "_svcrpcsec_gss: "
 785                             "make principal failed\n");
 786                         gssstat = GSS_S_FAILURE;
 787                         (void) gss_release_buffer(&minor_stat, &output_token);
 788                 }
 789         }
 790 
 791         rw_exit(&cred_lock);
 792 
 793         call_res.gss_major = gssstat;
 794         call_res.gss_minor = minor_stat;
 795 
 796         if (gssstat != GSS_S_COMPLETE &&
 797             gssstat != GSS_S_CONTINUE_NEEDED) {
 798                 call_res.ctx_handle.length = 0;
 799                 call_res.ctx_handle.value = NULL;
 800                 call_res.seq_window = 0;
 801                 rpc_gss_display_status(gssstat, minor_stat, mech_type,
 802                     crgetuid(CRED()),
 803                     "_svc_rpcsec_gss gss_accept_sec_context");
 804                 (void) svc_sendreply(rqst->rq_xprt,
 805                     __xdr_rpc_gss_init_res, (caddr_t)&call_res);
 806                 client_data->stale = TRUE;
 807                 ret = AUTH_OK;
 808                 goto error2;
 809         }
 810 
 811         /*
 812          * If appropriate, set established to TRUE *after* sending
 813          * response (otherwise, the client will receive the final
 814          * token encrypted)
 815          */
 816         if (gssstat == GSS_S_COMPLETE) {
 817                 /*
 818                  * Context is established.  Set expiration time
 819                  * for the context.
 820                  */
 821                 client_data->seq_num = 1;
 822                 if ((time_rec == GSS_C_INDEFINITE) || (time_rec == 0)) {
 823                         client_data->expiration = GSS_C_INDEFINITE;
 824                 } else {
 825                         client_data->expiration =
 826                             time_rec + gethrestime_sec();
 827                 }
 828 
 829                 if (!transfer_sec_context(client_data)) {
 830                         ret = RPCSEC_GSS_FAILED;
 831                         client_data->stale = TRUE;
 832                         RPCGSS_LOG0(1,
 833                             "_svc_rpcsec_gss: transfer sec context failed\n");
 834                         goto error2;
 835                 }
 836 
 837                 client_data->established = TRUE;
 838         }
 839 
 840         /*
 841          * This step succeeded.  Send a response, along with
 842          * a token if there's one.  Don't dispatch.
 843          */
 844 
 845         if (output_token.length != 0)
 846                 GSS_COPY_BUFFER(call_res.token, output_token);
 847 
 848         /*
 849          * If GSS_S_COMPLETE: set response verifier to
 850          * checksum of SEQ_WIN
 851          */
 852         if (gssstat == GSS_S_COMPLETE) {
 853                 if (!set_response_verf(rqst, msg, client_data,
 854                     (uint_t)SEQ_WIN)) {
 855                         ret = RPCSEC_GSS_FAILED;
 856                         client_data->stale = TRUE;
 857                         RPCGSS_LOG0(1,
 858                             "_svc_rpcsec_gss:set response verifier failed\n");
 859                         goto error2;
 860                 }
 861         }
 862 
 863         if (!svc_sendreply(rqst->rq_xprt, __xdr_rpc_gss_init_res,
 864             (caddr_t)&call_res)) {
 865                 ret = RPCSEC_GSS_FAILED;
 866                 client_data->stale = TRUE;
 867                 RPCGSS_LOG0(1, "_svc_rpcsec_gss:send reply failed\n");
 868                 goto error2;
 869         }
 870 
 871         /*
 872          * Cache last response in case it is lost and the client
 873          * retries on an established context.
 874          */
 875         (void) retrans_add(client_data, msg->rm_xid, &call_res);
 876         ASSERT(client_data->ref_cnt > 0);
 877         client_data->ref_cnt--;
 878         mutex_exit(&client_data->clm);
 879 
 880         (void) gss_release_buffer(&minor_stat, &output_token);
 881 
 882         return (AUTH_OK);
 883 
 884 error2:
 885         ASSERT(client_data->ref_cnt > 0);
 886         client_data->ref_cnt--;
 887         mutex_exit(&client_data->clm);
 888         (void) gss_release_buffer(&minor_stat, &output_token);
 889         if (free_mech_type && mech_type)
 890                 kgss_free_oid(mech_type);
 891 
 892         return (ret);
 893 }
 894 
 895 static void
 896 svcrpcsec_gss_taskq_func(void *svcrpcsecgss_taskq_arg)
 897 {
 898         enum auth_stat retval;
 899         svcrpcsec_gss_taskq_arg_t *arg = svcrpcsecgss_taskq_arg;
 900 
 901         retval = do_gss_accept(arg->rq_xprt, arg->rpc_call_arg, arg->msg,
 902             arg->client_data, arg->cr_version, arg->cr_service);
 903         if (retval != AUTH_OK) {
 904                 cmn_err(CE_NOTE,
 905                     "svcrpcsec_gss_taskq_func:  do_gss_accept fail 0x%x",
 906                     retval);
 907         }
 908         rpc_msg_free(&arg->msg, MAX_AUTH_BYTES);
 909         SVC_RELE(arg->rq_xprt, NULL, FALSE);
 910         svc_clone_unlink(arg->rq_xprt);
 911         svc_clone_free(arg->rq_xprt);
 912         xdr_free(__xdr_rpc_gss_init_arg, (caddr_t)arg->rpc_call_arg);
 913         kmem_free(arg->rpc_call_arg, sizeof (*arg->rpc_call_arg));
 914 
 915         kmem_free(arg, sizeof (*arg));
 916 }
 917 
 918 static enum auth_stat
 919 rpcsec_gss_init(
 920         struct svc_req          *rqst,
 921         struct rpc_msg          *msg,
 922         rpc_gss_creds           creds,
 923         bool_t                  *no_dispatch,
 924         svc_rpc_gss_data        *c_d) /* client data, can be NULL */
 925 {
 926         svc_rpc_gss_data        *client_data;
 927         int ret;
 928         svcrpcsec_gss_taskq_arg_t *arg;
 929 
 930         if (creds.ctx_handle.length != 0) {
 931                 RPCGSS_LOG0(1, "_svcrpcsec_gss: ctx_handle not null\n");
 932                 ret = AUTH_BADCRED;
 933                 return (ret);
 934         }
 935 
 936         client_data = c_d ? c_d : create_client();
 937         if (client_data == NULL) {
 938                 RPCGSS_LOG0(1,
 939                     "_svcrpcsec_gss: can't create a new cache entry\n");
 940                 ret = AUTH_FAILED;
 941                 return (ret);
 942         }
 943 
 944         mutex_enter(&client_data->clm);
 945         if (client_data->stale) {
 946                 ret = RPCSEC_GSS_NOCRED;
 947                 RPCGSS_LOG0(1, "_svcrpcsec_gss: client data stale\n");
 948                 goto error2;
 949         }
 950 
 951         /*
 952          * kgss_accept_sec_context()/gssd(1M) can be overly time
 953          * consuming so let's queue it and return asap.
 954          *
 955          * taskq func must free arg.
 956          */
 957         arg = kmem_alloc(sizeof (*arg), KM_SLEEP);
 958 
 959         /* taskq func must free rpc_call_arg & deserialized arguments */
 960         arg->rpc_call_arg = kmem_zalloc(sizeof (*arg->rpc_call_arg), KM_SLEEP);
 961 
 962         /* deserialize arguments */
 963         if (!SVC_GETARGS(rqst->rq_xprt, __xdr_rpc_gss_init_arg,
 964             (caddr_t)arg->rpc_call_arg)) {
 965                 ret = RPCSEC_GSS_FAILED;
 966                 client_data->stale = TRUE;
 967                 goto error2;
 968         }
 969 
 970         /* get a xprt clone for taskq thread, taskq func must free it */
 971         arg->rq_xprt = svc_clone_init();
 972         svc_clone_link(rqst->rq_xprt->xp_master, arg->rq_xprt, rqst->rq_xprt);
 973         arg->rq_xprt->xp_xid = rqst->rq_xprt->xp_xid;
 974 
 975         /*
 976          * Increment the reference count on the rpcmod slot so that is not
 977          * freed before the task has finished.
 978          */
 979         SVC_HOLD(arg->rq_xprt);
 980 
 981         /* set the appropriate wrap/unwrap routine for RPCSEC_GSS */
 982         arg->rq_xprt->xp_auth.svc_ah_ops = svc_rpc_gss_ops;
 983         arg->rq_xprt->xp_auth.svc_ah_private = (caddr_t)client_data;
 984 
 985         /* get a dup of rpc msg for taskq thread */
 986         arg->msg = rpc_msg_dup(msg);  /* taskq func must free msg dup */
 987 
 988         arg->client_data = client_data;
 989         arg->cr_version = creds.version;
 990         arg->cr_service = creds.service;
 991 
 992         /* should be ok to hold clm lock as taskq will have new thread(s) */
 993         ret = ddi_taskq_dispatch(svcrpcsec_gss_init_taskq,
 994             svcrpcsec_gss_taskq_func, arg, DDI_SLEEP);
 995         if (ret == DDI_FAILURE) {
 996                 cmn_err(CE_NOTE, "rpcsec_gss_init: taskq dispatch fail");
 997                 ret = RPCSEC_GSS_FAILED;
 998                 rpc_msg_free(&arg->msg, MAX_AUTH_BYTES);
 999                 SVC_RELE(arg->rq_xprt, NULL, FALSE);
1000                 svc_clone_unlink(arg->rq_xprt);
1001                 svc_clone_free(arg->rq_xprt);
1002                 kmem_free(arg, sizeof (*arg));
1003                 goto error2;
1004         }
1005 
1006         mutex_exit(&client_data->clm);
1007         *no_dispatch = TRUE;
1008         return (AUTH_OK);
1009 
1010 error2:
1011         ASSERT(client_data->ref_cnt > 0);
1012         client_data->ref_cnt--;
1013         mutex_exit(&client_data->clm);
1014         cmn_err(CE_NOTE, "rpcsec_gss_init: error 0x%x", ret);
1015         return (ret);
1016 }
1017 
1018 static enum auth_stat
1019 rpcsec_gss_continue_init(
1020         struct svc_req          *rqst,
1021         struct rpc_msg          *msg,
1022         rpc_gss_creds           creds,
1023         bool_t                  *no_dispatch)
1024 {
1025         int ret;
1026         svc_rpc_gss_data        *client_data;
1027         svc_rpc_gss_parms_t     *gss_parms;
1028         rpc_gss_init_res        *retrans_result;
1029 
1030         if (creds.ctx_handle.length == 0) {
1031                 RPCGSS_LOG0(1, "_svcrpcsec_gss: no ctx_handle\n");
1032                 ret = AUTH_BADCRED;
1033                 return (ret);
1034         }
1035         if ((client_data = get_client(&creds.ctx_handle)) == NULL) {
1036                 ret = RPCSEC_GSS_NOCRED;
1037                 RPCGSS_LOG0(1, "_svcrpcsec_gss: no security context\n");
1038                 return (ret);
1039         }
1040 
1041         mutex_enter(&client_data->clm);
1042         if (client_data->stale) {
1043                 ret = RPCSEC_GSS_NOCRED;
1044                 RPCGSS_LOG0(1, "_svcrpcsec_gss: client data stale\n");
1045                 goto error2;
1046         }
1047 
1048         /*
1049          * If context not established, go thru INIT code but with
1050          * this client handle.
1051          */
1052         if (!client_data->established) {
1053                 mutex_exit(&client_data->clm);
1054                 return (rpcsec_gss_init(rqst, msg, creds, no_dispatch,
1055                     client_data));
1056         }
1057 
1058         /*
1059          * Set the appropriate wrap/unwrap routine for RPCSEC_GSS.
1060          */
1061         rqst->rq_xprt->xp_auth.svc_ah_ops = svc_rpc_gss_ops;
1062         rqst->rq_xprt->xp_auth.svc_ah_private = (caddr_t)client_data;
1063 
1064         /*
1065          * Keep copy of parameters we'll need for response, for the
1066          * sake of reentrancy (we don't want to look in the context
1067          * data because when we are sending a response, another
1068          * request may have come in).
1069          */
1070         gss_parms = &rqst->rq_xprt->xp_auth.svc_gss_parms;
1071         gss_parms->established = client_data->established;
1072         gss_parms->service = creds.service;
1073         gss_parms->qop_rcvd = (uint_t)client_data->qop;
1074         gss_parms->context = (void *)client_data->context;
1075         gss_parms->seq_num = creds.seq_num;
1076 
1077         /*
1078          * This is an established context. Continue to
1079          * satisfy retried continue init requests out of
1080          * the retransmit cache.  Throw away any that don't
1081          * have a matching xid or the cach is empty.
1082          * Delete the retransmit cache once the client sends
1083          * a data request.
1084          */
1085         if (client_data->retrans_data &&
1086             (client_data->retrans_data->xid == msg->rm_xid)) {
1087                 retrans_result = &client_data->retrans_data->result;
1088                 if (set_response_verf(rqst, msg, client_data,
1089                     (uint_t)retrans_result->seq_window)) {
1090                         gss_parms->established = FALSE;
1091                         (void) svc_sendreply(rqst->rq_xprt,
1092                             __xdr_rpc_gss_init_res, (caddr_t)retrans_result);
1093                         *no_dispatch = TRUE;
1094                         ASSERT(client_data->ref_cnt > 0);
1095                         client_data->ref_cnt--;
1096                 }
1097         }
1098         mutex_exit(&client_data->clm);
1099 
1100         return (AUTH_OK);
1101 
1102 error2:
1103         ASSERT(client_data->ref_cnt > 0);
1104         client_data->ref_cnt--;
1105         mutex_exit(&client_data->clm);
1106         return (ret);
1107 }
1108 
1109 static enum auth_stat
1110 rpcsec_gss_data(
1111         struct svc_req          *rqst,
1112         struct rpc_msg          *msg,
1113         rpc_gss_creds           creds,
1114         bool_t                  *no_dispatch)
1115 {
1116         int ret;
1117         svc_rpc_gss_parms_t     *gss_parms;
1118         svc_rpc_gss_data        *client_data;
1119 
1120         switch (creds.service) {
1121         case rpc_gss_svc_none:
1122         case rpc_gss_svc_integrity:
1123         case rpc_gss_svc_privacy:
1124                 break;
1125         default:
1126                 cmn_err(CE_NOTE, "__svcrpcsec_gss: unknown service type=0x%x",
1127                     creds.service);
1128                 RPCGSS_LOG(1, "_svcrpcsec_gss: unknown service type: 0x%x\n",
1129                     creds.service);
1130                 ret = AUTH_BADCRED;
1131                 return (ret);
1132         }
1133 
1134         if (creds.ctx_handle.length == 0) {
1135                 RPCGSS_LOG0(1, "_svcrpcsec_gss: no ctx_handle\n");
1136                 ret = AUTH_BADCRED;
1137                 return (ret);
1138         }
1139         if ((client_data = get_client(&creds.ctx_handle)) == NULL) {
1140                 ret = RPCSEC_GSS_NOCRED;
1141                 RPCGSS_LOG0(1, "_svcrpcsec_gss: no security context\n");
1142                 return (ret);
1143         }
1144 
1145 
1146         mutex_enter(&client_data->clm);
1147         if (!client_data->established) {
1148                 ret = AUTH_FAILED;
1149                 goto error2;
1150         }
1151         if (client_data->stale) {
1152                 ret = RPCSEC_GSS_NOCRED;
1153                 RPCGSS_LOG0(1, "_svcrpcsec_gss: client data stale\n");
1154                 goto error2;
1155         }
1156 
1157         /*
1158          * Once the context is established and there is no more
1159          * retransmission of last continue init request, it is safe
1160          * to delete the retransmit cache entry.
1161          */
1162         if (client_data->retrans_data)
1163                 retrans_del(client_data);
1164 
1165         /*
1166          * Set the appropriate wrap/unwrap routine for RPCSEC_GSS.
1167          */
1168         rqst->rq_xprt->xp_auth.svc_ah_ops = svc_rpc_gss_ops;
1169         rqst->rq_xprt->xp_auth.svc_ah_private = (caddr_t)client_data;
1170 
1171         /*
1172          * Keep copy of parameters we'll need for response, for the
1173          * sake of reentrancy (we don't want to look in the context
1174          * data because when we are sending a response, another
1175          * request may have come in).
1176          */
1177         gss_parms = &rqst->rq_xprt->xp_auth.svc_gss_parms;
1178         gss_parms->established = client_data->established;
1179         gss_parms->service = creds.service;
1180         gss_parms->qop_rcvd = (uint_t)client_data->qop;
1181         gss_parms->context = (void *)client_data->context;
1182         gss_parms->seq_num = creds.seq_num;
1183 
1184         /*
1185          * Context is already established.  Check verifier, and
1186          * note parameters we will need for response in gss_parms.
1187          */
1188         if (!check_verf(msg, client_data->context,
1189             (int *)&gss_parms->qop_rcvd, client_data->u_cred.uid)) {
1190                 ret = RPCSEC_GSS_NOCRED;
1191                 RPCGSS_LOG0(1, "_svcrpcsec_gss: check verf failed\n");
1192                 goto error2;
1193         }
1194 
1195         /*
1196          *  Check and invoke callback if necessary.
1197          */
1198         if (!client_data->done_docallback) {
1199                 client_data->done_docallback = TRUE;
1200                 client_data->qop = gss_parms->qop_rcvd;
1201                 client_data->raw_cred.qop = gss_parms->qop_rcvd;
1202                 client_data->raw_cred.service = creds.service;
1203                 if (!do_callback(rqst, client_data)) {
1204                         ret = AUTH_FAILED;
1205                         RPCGSS_LOG0(1, "_svc_rpcsec_gss:callback failed\n");
1206                         goto error2;
1207                 }
1208         }
1209 
1210         /*
1211          * If the context was locked, make sure that the client
1212          * has not changed QOP.
1213          */
1214         if (client_data->locked && gss_parms->qop_rcvd != client_data->qop) {
1215                 ret = AUTH_BADVERF;
1216                 RPCGSS_LOG0(1, "_svcrpcsec_gss: can not change qop\n");
1217                 goto error2;
1218         }
1219 
1220         /*
1221          * Validate sequence number.
1222          */
1223         if (!check_seq(client_data, creds.seq_num, &client_data->stale)) {
1224                 if (client_data->stale) {
1225                         ret = RPCSEC_GSS_FAILED;
1226                         RPCGSS_LOG0(1,
1227                             "_svc_rpcsec_gss:check seq failed\n");
1228                 } else {
1229                         RPCGSS_LOG0(4, "_svc_rpcsec_gss:check seq "
1230                             "failed on good context. Ignoring "
1231                             "request\n");
1232                         /*
1233                          * Operational error, drop packet silently.
1234                          * The client will recover after timing out,
1235                          * assuming this is a client error and not
1236                          * a relpay attack.  Don't dispatch.
1237                          */
1238                         ret = AUTH_OK;
1239                         *no_dispatch = TRUE;
1240                 }
1241                 goto error2;
1242         }
1243 
1244         /*
1245          * set response verifier
1246          */
1247         if (!set_response_verf(rqst, msg, client_data, creds.seq_num)) {
1248                 ret = RPCSEC_GSS_FAILED;
1249                 client_data->stale = TRUE;
1250                 RPCGSS_LOG0(1,
1251                     "_svc_rpcsec_gss:set response verifier failed\n");
1252                 goto error2;
1253         }
1254 
1255         /*
1256          * If context is locked, make sure that the client
1257          * has not changed the security service.
1258          */
1259         if (client_data->locked &&
1260             client_data->raw_cred.service != creds.service) {
1261                 RPCGSS_LOG0(1, "_svc_rpcsec_gss: "
1262                     "security service changed.\n");
1263                 ret = AUTH_FAILED;
1264                 goto error2;
1265         }
1266 
1267         /*
1268          * Set client credentials to raw credential
1269          * structure in context.  This is okay, since
1270          * this will not change during the lifetime of
1271          * the context (so it's MT safe).
1272          */
1273         rqst->rq_clntcred = (char *)&client_data->raw_cred;
1274 
1275         mutex_exit(&client_data->clm);
1276         return (AUTH_OK);
1277 
1278 error2:
1279         ASSERT(client_data->ref_cnt > 0);
1280         client_data->ref_cnt--;
1281         mutex_exit(&client_data->clm);
1282         return (ret);
1283 }
1284 
1285 /*
1286  * Note we don't have a client yet to use this routine and test it.
1287  */
1288 static enum auth_stat
1289 rpcsec_gss_destroy(
1290         struct svc_req          *rqst,
1291         rpc_gss_creds           creds,
1292         bool_t                  *no_dispatch)
1293 {
1294         svc_rpc_gss_data        *client_data;
1295         int ret;
1296 
1297         if (creds.ctx_handle.length == 0) {
1298                 RPCGSS_LOG0(1, "_svcrpcsec_gss: no ctx_handle\n");
1299                 ret = AUTH_BADCRED;
1300                 return (ret);
1301         }
1302         if ((client_data = get_client(&creds.ctx_handle)) == NULL) {
1303                 ret = RPCSEC_GSS_NOCRED;
1304                 RPCGSS_LOG0(1, "_svcrpcsec_gss: no security context\n");
1305                 return (ret);
1306         }
1307 
1308         mutex_enter(&client_data->clm);
1309         if (!client_data->established) {
1310                 ret = AUTH_FAILED;
1311                 goto error2;
1312         }
1313         if (client_data->stale) {
1314                 ret = RPCSEC_GSS_NOCRED;
1315                 RPCGSS_LOG0(1, "_svcrpcsec_gss: client data stale\n");
1316                 goto error2;
1317         }
1318 
1319         (void) svc_sendreply(rqst->rq_xprt, xdr_void, NULL);
1320         *no_dispatch = TRUE;
1321         ASSERT(client_data->ref_cnt > 0);
1322         client_data->ref_cnt--;
1323         client_data->stale = TRUE;
1324         mutex_exit(&client_data->clm);
1325         return (AUTH_OK);
1326 
1327 error2:
1328         ASSERT(client_data->ref_cnt > 0);
1329         client_data->ref_cnt--;
1330         client_data->stale = TRUE;
1331         mutex_exit(&client_data->clm);
1332         return (ret);
1333 }
1334 
1335 /*
1336  * Server side authentication for RPCSEC_GSS.
1337  */
1338 enum auth_stat
1339 __svcrpcsec_gss(
1340         struct svc_req          *rqst,
1341         struct rpc_msg          *msg,
1342         bool_t                  *no_dispatch)
1343 {
1344         XDR                     xdrs;
1345         rpc_gss_creds           creds;
1346         struct opaque_auth      *cred;
1347         int                     ret;
1348 
1349         *no_dispatch = FALSE;
1350 
1351         /*
1352          * Initialize response verifier to NULL verifier.  If
1353          * necessary, this will be changed later.
1354          */
1355         rqst->rq_xprt->xp_verf.oa_flavor = AUTH_NONE;
1356         rqst->rq_xprt->xp_verf.oa_base = NULL;
1357         rqst->rq_xprt->xp_verf.oa_length = 0;
1358 
1359         /*
1360          * Pull out and check credential and verifier.
1361          */
1362         cred = &msg->rm_call.cb_cred;
1363 
1364         if (cred->oa_length == 0) {
1365                 RPCGSS_LOG0(1, "_svcrpcsec_gss: zero length cred\n");
1366                 return (AUTH_BADCRED);
1367         }
1368 
1369         xdrmem_create(&xdrs, cred->oa_base, cred->oa_length, XDR_DECODE);
1370         bzero((char *)&creds, sizeof (creds));
1371         if (!__xdr_rpc_gss_creds(&xdrs, &creds)) {
1372                 XDR_DESTROY(&xdrs);
1373                 RPCGSS_LOG0(1, "_svcrpcsec_gss: can't decode creds\n");
1374                 ret = AUTH_BADCRED;
1375                 return (AUTH_BADCRED);
1376         }
1377         XDR_DESTROY(&xdrs);
1378 
1379         switch (creds.gss_proc) {
1380         case RPCSEC_GSS_INIT:
1381                 ret = rpcsec_gss_init(rqst, msg, creds, no_dispatch, NULL);
1382                 break;
1383         case RPCSEC_GSS_CONTINUE_INIT:
1384                 ret = rpcsec_gss_continue_init(rqst, msg, creds, no_dispatch);
1385                 break;
1386         case RPCSEC_GSS_DATA:
1387                 ret = rpcsec_gss_data(rqst, msg, creds, no_dispatch);
1388                 break;
1389         case RPCSEC_GSS_DESTROY:
1390                 ret = rpcsec_gss_destroy(rqst, creds, no_dispatch);
1391                 break;
1392         default:
1393                 cmn_err(CE_NOTE, "__svcrpcsec_gss: bad proc=%d",
1394                     creds.gss_proc);
1395                 ret = AUTH_BADCRED;
1396         }
1397 
1398         if (creds.ctx_handle.length != 0)
1399                 xdr_free(__xdr_rpc_gss_creds, (caddr_t)&creds);
1400         return (ret);
1401 }
1402 
1403 /*
1404  * Check verifier.  The verifier is the checksum of the RPC header
1405  * upto and including the credentials field.
1406  */
1407 
1408 /* ARGSUSED */
1409 static bool_t
1410 check_verf(struct rpc_msg *msg, gss_ctx_id_t context, int *qop_state, uid_t uid)
1411 {
1412         int                     *buf, *tmp;
1413         char                    hdr[128];
1414         struct opaque_auth      *oa;
1415         int                     len;
1416         gss_buffer_desc         msg_buf;
1417         gss_buffer_desc         tok_buf;
1418         OM_uint32               gssstat, minor_stat;
1419 
1420         /*
1421          * We have to reconstruct the RPC header from the previously
1422          * parsed information, since we haven't kept the header intact.
1423          */
1424 
1425         oa = &msg->rm_call.cb_cred;
1426         if (oa->oa_length > MAX_AUTH_BYTES)
1427                 return (FALSE);
1428 
1429         /* 8 XDR units from the IXDR macro calls. */
1430         if (sizeof (hdr) < (8 * BYTES_PER_XDR_UNIT +
1431             RNDUP(oa->oa_length)))
1432                 return (FALSE);
1433         buf = (int *)hdr;
1434         IXDR_PUT_U_INT32(buf, msg->rm_xid);
1435         IXDR_PUT_ENUM(buf, msg->rm_direction);
1436         IXDR_PUT_U_INT32(buf, msg->rm_call.cb_rpcvers);
1437         IXDR_PUT_U_INT32(buf, msg->rm_call.cb_prog);
1438         IXDR_PUT_U_INT32(buf, msg->rm_call.cb_vers);
1439         IXDR_PUT_U_INT32(buf, msg->rm_call.cb_proc);
1440         IXDR_PUT_ENUM(buf, oa->oa_flavor);
1441         IXDR_PUT_U_INT32(buf, oa->oa_length);
1442         if (oa->oa_length) {
1443                 len = RNDUP(oa->oa_length);
1444                 tmp = buf;
1445                 buf += len / sizeof (int);
1446                 *(buf - 1) = 0;
1447                 (void) bcopy(oa->oa_base, (caddr_t)tmp, oa->oa_length);
1448         }
1449         len = ((char *)buf) - hdr;
1450         msg_buf.length = len;
1451         msg_buf.value = hdr;
1452         oa = &msg->rm_call.cb_verf;
1453         tok_buf.length = oa->oa_length;
1454         tok_buf.value = oa->oa_base;
1455 
1456         gssstat = kgss_verify(&minor_stat, context, &msg_buf, &tok_buf,
1457             qop_state);
1458         if (gssstat != GSS_S_COMPLETE) {
1459                 RPCGSS_LOG(1, "check_verf: kgss_verify status 0x%x\n", gssstat);
1460 
1461                 RPCGSS_LOG(4, "check_verf: msg_buf length %d\n", len);
1462                 RPCGSS_LOG(4, "check_verf: msg_buf value 0x%x\n", *(int *)hdr);
1463                 RPCGSS_LOG(4, "check_verf: tok_buf length %ld\n",
1464                     tok_buf.length);
1465                 RPCGSS_LOG(4, "check_verf: tok_buf value 0x%p\n",
1466                     (void *)oa->oa_base);
1467                 RPCGSS_LOG(4, "check_verf: context 0x%p\n", (void *)context);
1468 
1469                 return (FALSE);
1470         }
1471         return (TRUE);
1472 }
1473 
1474 
1475 /*
1476  * Set response verifier.  This is the checksum of the given number.
1477  * (e.g. sequence number or sequence window)
1478  */
1479 static bool_t
1480 set_response_verf(struct svc_req *rqst, struct rpc_msg *msg,
1481     svc_rpc_gss_data *cl, uint_t num)
1482 {
1483         OM_uint32               minor;
1484         gss_buffer_desc         in_buf, out_buf;
1485         uint_t                  num_net;
1486 
1487         num_net = (uint_t)htonl(num);
1488         in_buf.length = sizeof (num);
1489         in_buf.value = (char *)&num_net;
1490 /* XXX uid ? */
1491 
1492         if ((kgss_sign(&minor, cl->context, cl->qop, &in_buf, &out_buf))
1493             != GSS_S_COMPLETE)
1494                 return (FALSE);
1495 
1496         rqst->rq_xprt->xp_verf.oa_flavor = RPCSEC_GSS;
1497         rqst->rq_xprt->xp_verf.oa_base = msg->rm_call.cb_verf.oa_base;
1498         rqst->rq_xprt->xp_verf.oa_length = out_buf.length;
1499         bcopy(out_buf.value, rqst->rq_xprt->xp_verf.oa_base, out_buf.length);
1500         (void) gss_release_buffer(&minor, &out_buf);
1501         return (TRUE);
1502 }
1503 
1504 /*
1505  * Create client context.
1506  */
1507 static svc_rpc_gss_data *
1508 create_client()
1509 {
1510         svc_rpc_gss_data        *client_data;
1511         static uint_t           key = 1;
1512 
1513         client_data = (svc_rpc_gss_data *) kmem_cache_alloc(svc_data_handle,
1514             KM_SLEEP);
1515         if (client_data == NULL)
1516                 return (NULL);
1517 
1518         /*
1519          * set up client data structure
1520          */
1521         client_data->next = NULL;
1522         client_data->prev = NULL;
1523         client_data->lru_next = NULL;
1524         client_data->lru_prev = NULL;
1525         client_data->client_name.length = 0;
1526         client_data->client_name.value = NULL;
1527         client_data->seq_num = 0;
1528         bzero(client_data->seq_bits, sizeof (client_data->seq_bits));
1529         client_data->key = 0;
1530         client_data->cookie = NULL;
1531         bzero(&client_data->u_cred, sizeof (client_data->u_cred));
1532         client_data->established = FALSE;
1533         client_data->locked = FALSE;
1534         client_data->u_cred_set = 0;
1535         client_data->context = GSS_C_NO_CONTEXT;
1536         client_data->expiration = GSS_C_INDEFINITE;
1537         client_data->deleg = GSS_C_NO_CREDENTIAL;
1538         client_data->ref_cnt = 1;
1539         client_data->last_ref_time = gethrestime_sec();
1540         client_data->qop = GSS_C_QOP_DEFAULT;
1541         client_data->done_docallback = FALSE;
1542         client_data->stale = FALSE;
1543         client_data->retrans_data = NULL;
1544         bzero(&client_data->raw_cred, sizeof (client_data->raw_cred));
1545 
1546         /*
1547          * The client context handle is a 32-bit key (unsigned int).
1548          * The key is incremented until there is no duplicate for it.
1549          */
1550 
1551         svc_rpc_gss_cache_stats.total_entries_allocated++;
1552         mutex_enter(&ctx_mutex);
1553         for (;;) {
1554                 client_data->key = key++;
1555                 if (find_client(client_data->key) == NULL) {
1556                         insert_client(client_data);
1557                         mutex_exit(&ctx_mutex);
1558                         return (client_data);
1559                 }
1560         }
1561         /*NOTREACHED*/
1562 }
1563 
1564 /*
1565  * Insert client context into hash list and LRU list.
1566  */
1567 static void
1568 insert_client(svc_rpc_gss_data *client_data)
1569 {
1570         svc_rpc_gss_data        *cl;
1571         int                     index = HASH(client_data->key);
1572 
1573         ASSERT(mutex_owned(&ctx_mutex));
1574 
1575         client_data->prev = NULL;
1576         cl = clients[index];
1577         if ((client_data->next = cl) != NULL)
1578                 cl->prev = client_data;
1579         clients[index] = client_data;
1580 
1581         client_data->lru_prev = NULL;
1582         if ((client_data->lru_next = lru_first) != NULL)
1583                 lru_first->lru_prev = client_data;
1584         else
1585                 lru_last = client_data;
1586         lru_first = client_data;
1587 
1588         num_gss_contexts++;
1589 }
1590 
1591 /*
1592  * Fetch a client, given the client context handle.  Move it to the
1593  * top of the LRU list since this is the most recently used context.
1594  */
1595 static svc_rpc_gss_data *
1596 get_client(gss_buffer_t ctx_handle)
1597 {
1598         uint_t                  key = *(uint_t *)ctx_handle->value;
1599         svc_rpc_gss_data        *cl;
1600 
1601         mutex_enter(&ctx_mutex);
1602         if ((cl = find_client(key)) != NULL) {
1603                 mutex_enter(&cl->clm);
1604                 if (cl->stale) {
1605                         if (cl->ref_cnt == 0) {
1606                                 mutex_exit(&cl->clm);
1607                                 destroy_client(cl);
1608                         } else {
1609                                 mutex_exit(&cl->clm);
1610                         }
1611                         mutex_exit(&ctx_mutex);
1612                         return (NULL);
1613                 }
1614                 cl->ref_cnt++;
1615                 cl->last_ref_time = gethrestime_sec();
1616                 mutex_exit(&cl->clm);
1617                 if (cl != lru_first) {
1618                         cl->lru_prev->lru_next = cl->lru_next;
1619                         if (cl->lru_next != NULL)
1620                                 cl->lru_next->lru_prev = cl->lru_prev;
1621                         else
1622                                 lru_last = cl->lru_prev;
1623                         cl->lru_prev = NULL;
1624                         cl->lru_next = lru_first;
1625                         lru_first->lru_prev = cl;
1626                         lru_first = cl;
1627                 }
1628         }
1629         mutex_exit(&ctx_mutex);
1630         return (cl);
1631 }
1632 
1633 /*
1634  * Given the client context handle, find the context corresponding to it.
1635  * Don't change its LRU state since it may not be used.
1636  */
1637 static svc_rpc_gss_data *
1638 find_client(uint_t key)
1639 {
1640         int                     index = HASH(key);
1641         svc_rpc_gss_data        *cl = NULL;
1642 
1643         ASSERT(mutex_owned(&ctx_mutex));
1644 
1645         for (cl = clients[index]; cl != NULL; cl = cl->next) {
1646                 if (cl->key == key)
1647                         break;
1648         }
1649         return (cl);
1650 }
1651 
1652 /*
1653  * Destroy a client context.
1654  */
1655 static void
1656 destroy_client(svc_rpc_gss_data *client_data)
1657 {
1658         OM_uint32               minor;
1659         int                     index = HASH(client_data->key);
1660 
1661         ASSERT(mutex_owned(&ctx_mutex));
1662 
1663         /*
1664          * remove from hash list
1665          */
1666         if (client_data->prev == NULL)
1667                 clients[index] = client_data->next;
1668         else
1669                 client_data->prev->next = client_data->next;
1670         if (client_data->next != NULL)
1671                 client_data->next->prev = client_data->prev;
1672 
1673         /*
1674          * remove from LRU list
1675          */
1676         if (client_data->lru_prev == NULL)
1677                 lru_first = client_data->lru_next;
1678         else
1679                 client_data->lru_prev->lru_next = client_data->lru_next;
1680         if (client_data->lru_next != NULL)
1681                 client_data->lru_next->lru_prev = client_data->lru_prev;
1682         else
1683                 lru_last = client_data->lru_prev;
1684 
1685         /*
1686          * If there is a GSS context, clean up GSS state.
1687          */
1688         if (client_data->context != GSS_C_NO_CONTEXT) {
1689                 (void) kgss_delete_sec_context(&minor, &client_data->context,
1690                     NULL);
1691 
1692                 common_client_data_free(client_data);
1693 
1694                 if (client_data->deleg != GSS_C_NO_CREDENTIAL) {
1695                         (void) kgss_release_cred(&minor, &client_data->deleg,
1696                             crgetuid(CRED()));
1697                 }
1698         }
1699 
1700         if (client_data->u_cred.gidlist != NULL) {
1701                 kmem_free((char *)client_data->u_cred.gidlist,
1702                     client_data->u_cred.gidlen * sizeof (gid_t));
1703                 client_data->u_cred.gidlist = NULL;
1704         }
1705         if (client_data->retrans_data != NULL)
1706                 retrans_del(client_data);
1707 
1708         kmem_cache_free(svc_data_handle, client_data);
1709         num_gss_contexts--;
1710 }
1711 
1712 /*
1713  * Check for expired and stale client contexts.
1714  */
1715 static void
1716 sweep_clients(bool_t from_reclaim)
1717 {
1718         svc_rpc_gss_data        *cl, *next;
1719         time_t                  last_reference_needed;
1720         time_t                  now = gethrestime_sec();
1721 
1722         ASSERT(mutex_owned(&ctx_mutex));
1723 
1724         last_reference_needed = now - (from_reclaim ?
1725             svc_rpc_gss_active_delta : svc_rpc_gss_inactive_delta);
1726 
1727         cl = lru_last;
1728         while (cl) {
1729                 /*
1730                  * We assume here that any manipulation of the LRU pointers
1731                  * and hash bucket pointers are only done when holding the
1732                  * ctx_mutex.
1733                  */
1734                 next = cl->lru_prev;
1735 
1736                 mutex_enter(&cl->clm);
1737 
1738                 if ((cl->expiration != GSS_C_INDEFINITE &&
1739                     cl->expiration <= now) || cl->stale ||
1740                     cl->last_ref_time <= last_reference_needed) {
1741 
1742                         if ((cl->expiration != GSS_C_INDEFINITE &&
1743                             cl->expiration <= now) || cl->stale ||
1744                             (cl->last_ref_time <= last_reference_needed &&
1745                             cl->ref_cnt == 0)) {
1746 
1747                                 cl->stale = TRUE;
1748 
1749                                 if (cl->ref_cnt == 0) {
1750                                         mutex_exit(&cl->clm);
1751                                         if (from_reclaim)
1752                                                 svc_rpc_gss_cache_stats.
1753                                                     no_returned_by_reclaim++;
1754                                         destroy_client(cl);
1755                                 } else
1756                                         mutex_exit(&cl->clm);
1757                         } else
1758                                 mutex_exit(&cl->clm);
1759                 } else
1760                         mutex_exit(&cl->clm);
1761 
1762                 cl = next;
1763         }
1764 
1765         last_swept = gethrestime_sec();
1766 }
1767 
1768 /*
1769  * Encrypt the serialized arguments from xdr_func applied to xdr_ptr
1770  * and write the result to xdrs.
1771  */
1772 static bool_t
1773 svc_rpc_gss_wrap(SVCAUTH *auth, XDR *out_xdrs, bool_t (*xdr_func)(),
1774     caddr_t xdr_ptr)
1775 {
1776         svc_rpc_gss_parms_t     *gss_parms = SVCAUTH_GSSPARMS(auth);
1777         bool_t ret;
1778 
1779         /*
1780          * If context is not established, or if neither integrity nor
1781          * privacy service is used, don't wrap - just XDR encode.
1782          * Otherwise, wrap data using service and QOP parameters.
1783          */
1784         if (!gss_parms->established || gss_parms->service == rpc_gss_svc_none)
1785                 return ((*xdr_func)(out_xdrs, xdr_ptr));
1786 
1787         ret = __rpc_gss_wrap_data(gss_parms->service,
1788             (OM_uint32)gss_parms->qop_rcvd,
1789             (gss_ctx_id_t)gss_parms->context,
1790             gss_parms->seq_num,
1791             out_xdrs, xdr_func, xdr_ptr);
1792         return (ret);
1793 }
1794 
1795 /*
1796  * Decrypt the serialized arguments and XDR decode them.
1797  */
1798 static bool_t
1799 svc_rpc_gss_unwrap(SVCAUTH *auth, XDR *in_xdrs, bool_t (*xdr_func)(),
1800     caddr_t xdr_ptr)
1801 {
1802         svc_rpc_gss_parms_t     *gss_parms = SVCAUTH_GSSPARMS(auth);
1803 
1804         /*
1805          * If context is not established, or if neither integrity nor
1806          * privacy service is used, don't unwrap - just XDR decode.
1807          * Otherwise, unwrap data.
1808          */
1809         if (!gss_parms->established || gss_parms->service == rpc_gss_svc_none)
1810                 return ((*xdr_func)(in_xdrs, xdr_ptr));
1811 
1812         return (__rpc_gss_unwrap_data(gss_parms->service,
1813             (gss_ctx_id_t)gss_parms->context,
1814             gss_parms->seq_num,
1815             gss_parms->qop_rcvd,
1816             in_xdrs, xdr_func, xdr_ptr));
1817 }
1818 
1819 
1820 /* ARGSUSED */
1821 int
1822 rpc_gss_svc_max_data_length(struct svc_req *req, int max_tp_unit_len)
1823 {
1824         return (0);
1825 }
1826 
1827 /*
1828  * Add retransmit entry to the context cache entry for a new xid.
1829  * If there is already an entry, delete it before adding the new one.
1830  */
1831 static void retrans_add(client, xid, result)
1832         svc_rpc_gss_data *client;
1833         uint32_t        xid;
1834         rpc_gss_init_res *result;
1835 {
1836         retrans_entry   *rdata;
1837 
1838         if (client->retrans_data && client->retrans_data->xid == xid)
1839                 return;
1840 
1841         rdata = kmem_zalloc(sizeof (*rdata), KM_SLEEP);
1842 
1843         if (rdata == NULL)
1844                 return;
1845 
1846         rdata->xid = xid;
1847         rdata->result = *result;
1848 
1849         if (result->token.length != 0) {
1850                 GSS_DUP_BUFFER(rdata->result.token, result->token);
1851         }
1852 
1853         if (client->retrans_data)
1854                 retrans_del(client);
1855 
1856         client->retrans_data = rdata;
1857 }
1858 
1859 /*
1860  * Delete the retransmit data from the context cache entry.
1861  */
1862 static void retrans_del(client)
1863         svc_rpc_gss_data *client;
1864 {
1865         retrans_entry *rdata;
1866         OM_uint32 minor_stat;
1867 
1868         if (client->retrans_data == NULL)
1869                 return;
1870 
1871         rdata = client->retrans_data;
1872         if (rdata->result.token.length != 0) {
1873             (void) gss_release_buffer(&minor_stat, &rdata->result.token);
1874         }
1875 
1876         kmem_free((caddr_t)rdata, sizeof (*rdata));
1877         client->retrans_data = NULL;
1878 }
1879 
1880 /*
1881  * This function frees the following fields of svc_rpc_gss_data:
1882  *      client_name, raw_cred.client_principal, raw_cred.mechanism.
1883  */
1884 static void
1885 common_client_data_free(svc_rpc_gss_data *client_data)
1886 {
1887         if (client_data->client_name.length > 0) {
1888                 (void) gss_release_buffer(NULL, &client_data->client_name);
1889         }
1890 
1891         if (client_data->raw_cred.client_principal) {
1892                 kmem_free((caddr_t)client_data->raw_cred.client_principal,
1893                     client_data->raw_cred.client_principal->len +
1894                     sizeof (int));
1895                 client_data->raw_cred.client_principal = NULL;
1896         }
1897 
1898         /*
1899          * In the user GSS-API library, mechanism (mech_type returned
1900          * by gss_accept_sec_context) is static storage, however
1901          * since all the work is done for gss_accept_sec_context under
1902          * gssd, what is returned in the kernel, is a copy from the oid
1903          * obtained under from gssd, so need to free it when destroying
1904          * the client data.
1905          */
1906 
1907         if (client_data->raw_cred.mechanism) {
1908                 kgss_free_oid(client_data->raw_cred.mechanism);
1909                 client_data->raw_cred.mechanism = NULL;
1910         }
1911 }