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