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