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 2009 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  * Copyright 2012 Milan Jurik. All rights reserved.
  25  */
  26 
  27 /*
  28  *  GSSAPI library stub module for gssd.
  29  */
  30 
  31 #include <mechglueP.h>
  32 #include "gssd_prot.h"
  33 #include <rpc/rpc.h>
  34 
  35 #include <sys/systm.h>
  36 #include <sys/types.h>
  37 #include <sys/cmn_err.h>
  38 #include <sys/kmem.h>
  39 #include <gssapi/kgssapi_defs.h>
  40 #include <sys/debug.h>
  41 
  42 #ifdef GSSDEBUG
  43 /*
  44  * Kernel kgssd module debugging aid. The global variable "gss_log"
  45  * is a bit mask which allows various types of debugging messages
  46  * to be printed out.
  47  *
  48  *       gss_log & 1  will cause actual failures to be printed.
  49  *       gss_log & 2  will cause informational messages to be
  50  *                       printed on the client side of kgssd.
  51  *       gss_log & 4  will cause informational messages to be
  52  *                       printed on the server side of kgssd.
  53  *       gss_log & 8  will cause informational messages to be
  54  *                       printed on both client and server side of kgssd.
  55  */
  56 
  57 uint_t gss_log = 1;
  58 
  59 #endif /* GSSDEBUG */
  60 
  61 #ifdef  DEBUG
  62 extern void prom_printf(const char *, ...);
  63 #endif
  64 
  65 char *server = "localhost";
  66 
  67 static OM_uint32 kgss_sign_wrapped(void *, OM_uint32 *, gss_ctx_id_t, int,
  68         gss_buffer_t, gss_buffer_t,  OM_uint32);
  69 
  70 static OM_uint32 kgss_verify_wrapped(void *, OM_uint32 *, gss_ctx_id_t,
  71         gss_buffer_t, gss_buffer_t, int *qop_state, OM_uint32);
  72 
  73 static OM_uint32 kgss_seal_wrapped(void *, OM_uint32 *, gss_ctx_id_t,
  74         int, int, gss_buffer_t, int *, gss_buffer_t,  OM_uint32);
  75 
  76 static OM_uint32 kgss_unseal_wrapped(void *, OM_uint32 *, gss_ctx_id_t,
  77         gss_buffer_t, gss_buffer_t, int *conf_state, int *qop_state,
  78         OM_uint32);
  79 
  80 static OM_uint32 kgss_delete_sec_context_wrapped(void *, OM_uint32 *,
  81         gssd_ctx_id_t *, gss_buffer_t, OM_uint32);
  82 
  83 static void __kgss_reset_mech(gss_mechanism *, gss_OID);
  84 
  85 #define DEFAULT_MINOR_STAT      ((OM_uint32) ~0)
  86 
  87 OM_uint32
  88 kgss_acquire_cred_wrapped(minor_status,
  89                         desired_name,
  90                         time_req,
  91                         desired_mechs,
  92                         cred_usage,
  93                         output_cred_handle,
  94                         actual_mechs,
  95                         time_rec,
  96                         uid,
  97                         gssd_cred_verifier)
  98         OM_uint32 *minor_status;
  99         const gss_name_t desired_name;
 100         OM_uint32 time_req;
 101         const gss_OID_set desired_mechs;
 102         int cred_usage;
 103         gssd_cred_id_t *output_cred_handle;
 104         gss_OID_set *actual_mechs;
 105         OM_uint32 *time_rec;
 106         uid_t uid;
 107         OM_uint32 *gssd_cred_verifier;
 108 {
 109         CLIENT *clnt;
 110 
 111         OM_uint32       minor_status_temp;
 112         gss_buffer_desc external_name;
 113         gss_OID         name_type;
 114         enum clnt_stat  client_stat;
 115         int             i;
 116 
 117         gss_acquire_cred_arg arg;
 118         gss_acquire_cred_res res;
 119 
 120         /* get the client handle to GSSD */
 121 
 122         if ((clnt = getgssd_handle()) == NULL) {
 123                 GSSLOG(1, "kgss_acquire_cred: can't connect to server on %s\n",
 124                         server);
 125                 return (GSS_S_FAILURE);
 126         }
 127 
 128         /* convert the desired name from internal to external format */
 129 
 130         if (gss_display_name(&minor_status_temp, desired_name, &external_name,
 131                                 &name_type) != GSS_S_COMPLETE) {
 132 
 133                 *minor_status = (OM_uint32) minor_status_temp;
 134                 killgssd_handle(clnt);
 135                 GSSLOG0(1, "kgss_acquire_cred: display name failed\n");
 136                 return ((OM_uint32) GSS_S_FAILURE);
 137         }
 138 
 139 
 140         /* copy the procedure arguments into the rpc arg parameter */
 141 
 142         arg.uid = (OM_uint32) uid;
 143 
 144         arg.desired_name.GSS_BUFFER_T_len = (uint_t)external_name.length;
 145         arg.desired_name.GSS_BUFFER_T_val = (char *)external_name.value;
 146 
 147         arg.name_type.GSS_OID_len =
 148                 name_type == GSS_C_NULL_OID ?
 149                         0 : (uint_t)name_type->length;
 150 
 151         arg.name_type.GSS_OID_val =
 152                 name_type == GSS_C_NULL_OID ?
 153                         (char *)NULL : (char *)name_type->elements;
 154 
 155         arg.time_req = time_req;
 156 
 157         if (desired_mechs != GSS_C_NULL_OID_SET) {
 158                 arg.desired_mechs.GSS_OID_SET_len =
 159                         (uint_t)desired_mechs->count;
 160                 arg.desired_mechs.GSS_OID_SET_val = (GSS_OID *)
 161                         MALLOC(sizeof (GSS_OID) * desired_mechs->count);
 162 
 163                 for (i = 0; i < desired_mechs->count; i++) {
 164                     arg.desired_mechs.GSS_OID_SET_val[i].GSS_OID_len =
 165                         (uint_t)desired_mechs->elements[i].length;
 166                     arg.desired_mechs.GSS_OID_SET_val[i].GSS_OID_val =
 167                         (char *)MALLOC(desired_mechs->elements[i].length);
 168                     (void) memcpy(
 169                         arg.desired_mechs.GSS_OID_SET_val[i].GSS_OID_val,
 170                         desired_mechs->elements[i].elements,
 171                         desired_mechs->elements[i].length);
 172                 }
 173         } else
 174                 arg.desired_mechs.GSS_OID_SET_len = 0;
 175 
 176         arg.cred_usage = cred_usage;
 177 
 178         /* call the remote procedure */
 179 
 180         bzero((caddr_t)&res, sizeof (res));
 181         client_stat = gss_acquire_cred_1(&arg, &res, clnt);
 182 
 183         (void) gss_release_buffer(&minor_status_temp, &external_name);
 184         if (desired_mechs != GSS_C_NULL_OID_SET) {
 185                 for (i = 0; i < desired_mechs->count; i++)
 186                         FREE(arg.desired_mechs.GSS_OID_SET_val[i].GSS_OID_val,
 187                             arg.desired_mechs.GSS_OID_SET_val[i].GSS_OID_len);
 188                 FREE(arg.desired_mechs.GSS_OID_SET_val,
 189                     arg.desired_mechs.GSS_OID_SET_len * sizeof (GSS_OID));
 190         }
 191 
 192         if (client_stat != RPC_SUCCESS) {
 193 
 194                 /*
 195                  * if the RPC call times out, null out all return arguments,
 196                  * set minor_status to its maximum value, and return
 197                  * GSS_S_FAILURE
 198                  */
 199 
 200                 if (minor_status != NULL)
 201                         *minor_status = DEFAULT_MINOR_STAT;
 202                 if (output_cred_handle != NULL)
 203                         *output_cred_handle = NULL;
 204                 if (actual_mechs != NULL)
 205                         *actual_mechs = NULL;
 206                 if (time_rec != NULL)
 207                         *time_rec = 0;
 208 
 209                 killgssd_handle(clnt);
 210                 GSSLOG0(1, "kgss_acquire_cred: RPC call times out\n");
 211                 return (GSS_S_FAILURE);
 212         }
 213 
 214         /* copy the rpc results into the return arguments */
 215 
 216         if (minor_status != NULL)
 217                 *minor_status = res.minor_status;
 218 
 219         if (output_cred_handle != NULL &&
 220                 (res.status == GSS_S_COMPLETE)) {
 221             *output_cred_handle =
 222                 *((gssd_cred_id_t *)res.output_cred_handle.GSS_CRED_ID_T_val);
 223             *gssd_cred_verifier = res.gssd_cred_verifier;
 224         }
 225 
 226         if (res.status == GSS_S_COMPLETE &&
 227                 res.actual_mechs.GSS_OID_SET_len != 0 &&
 228                 actual_mechs != NULL) {
 229                 *actual_mechs = (gss_OID_set) MALLOC(sizeof (gss_OID_set_desc));
 230                 (*actual_mechs)->count =
 231                                         (int)res.actual_mechs.GSS_OID_SET_len;
 232                 (*actual_mechs)->elements = (gss_OID)
 233                         MALLOC(sizeof (gss_OID_desc) * (*actual_mechs)->count);
 234 
 235                 for (i = 0; i < (*actual_mechs)->count; i++) {
 236                     (*actual_mechs)->elements[i].length = (OM_uint32)
 237                         res.actual_mechs.GSS_OID_SET_val[i].GSS_OID_len;
 238                     (*actual_mechs)->elements[i].elements =
 239                         (void *) MALLOC((*actual_mechs)->elements[i].length);
 240                     (void) memcpy((*actual_mechs)->elements[i].elements,
 241                         res.actual_mechs.GSS_OID_SET_val[i].GSS_OID_val,
 242                         (*actual_mechs)->elements[i].length);
 243                 }
 244         } else {
 245                 if (res.status == GSS_S_COMPLETE &&
 246                         actual_mechs != NULL)
 247                         (*actual_mechs) = NULL;
 248         }
 249 
 250         if (time_rec != NULL)
 251                 *time_rec = res.time_rec;
 252 
 253         /*
 254          * free the memory allocated for the results and return with the status
 255          * received in the rpc call
 256          */
 257 
 258         clnt_freeres(clnt, xdr_gss_acquire_cred_res, (caddr_t)&res);
 259         killgssd_handle(clnt);
 260         return (res.status);
 261 
 262 }
 263 
 264 OM_uint32
 265 kgss_acquire_cred(minor_status,
 266                 desired_name,
 267                 time_req,
 268                 desired_mechs,
 269                 cred_usage,
 270                 output_cred_handle,
 271                 actual_mechs,
 272                 time_rec,
 273                 uid)
 274         OM_uint32 *minor_status;
 275         const gss_name_t desired_name;
 276         OM_uint32 time_req;
 277         const gss_OID_set desired_mechs;
 278         int cred_usage;
 279         gss_cred_id_t *output_cred_handle;
 280         gss_OID_set *actual_mechs;
 281         OM_uint32 *time_rec;
 282         uid_t uid;
 283 {
 284 
 285         OM_uint32       err;
 286         struct kgss_cred *kcred;
 287 
 288         kcred = KGSS_CRED_ALLOC();
 289         *output_cred_handle = (gss_cred_id_t)kcred;
 290         err = kgss_acquire_cred_wrapped(minor_status, desired_name, time_req,
 291                 desired_mechs, cred_usage, &kcred->gssd_cred, actual_mechs,
 292                 time_rec, uid, &kcred->gssd_cred_verifier);
 293         if (GSS_ERROR(err)) {
 294                 KGSS_CRED_FREE(kcred);
 295                 *output_cred_handle = GSS_C_NO_CREDENTIAL;
 296         }
 297         return (err);
 298 }
 299 
 300 OM_uint32
 301 kgss_add_cred_wrapped(minor_status,
 302                         input_cred_handle,
 303                         gssd_cred_verifier,
 304                         desired_name,
 305                         desired_mech_type,
 306                         cred_usage,
 307                         initiator_time_req,
 308                         acceptor_time_req,
 309                         actual_mechs,
 310                         initiator_time_rec,
 311                         acceptor_time_rec,
 312                         uid)
 313         OM_uint32 *minor_status;
 314         gssd_cred_id_t input_cred_handle;
 315         OM_uint32 gssd_cred_verifier;
 316         gss_name_t desired_name;
 317         gss_OID desired_mech_type;
 318         int cred_usage;
 319         int initiator_time_req;
 320         int acceptor_time_req;
 321         gss_OID_set *actual_mechs;
 322         OM_uint32 *initiator_time_rec;
 323         OM_uint32 *acceptor_time_rec;
 324         uid_t uid;
 325 {
 326         CLIENT *clnt;
 327 
 328         OM_uint32       minor_status_temp;
 329         gss_buffer_desc external_name;
 330         gss_OID         name_type;
 331         int             i;
 332 
 333         gss_add_cred_arg arg;
 334         gss_add_cred_res res;
 335 
 336 
 337         /*
 338          * NULL the params here once
 339          * If there are errors then we won't
 340          * have to do it for every error
 341          * case
 342          */
 343 
 344         if (minor_status != NULL)
 345                 *minor_status = DEFAULT_MINOR_STAT;
 346         if (actual_mechs != NULL)
 347                 *actual_mechs = NULL;
 348         if (initiator_time_rec != NULL)
 349                 *initiator_time_rec = 0;
 350         if (acceptor_time_rec != NULL)
 351                         *acceptor_time_rec = 0;
 352         /* get the client handle to GSSD */
 353 
 354         if ((clnt = getgssd_handle()) == NULL) {
 355                 GSSLOG(1, "kgss_add_cred: can't connect to server on %s\n",
 356                         server);
 357                 return (GSS_S_FAILURE);
 358         }
 359 
 360 
 361         /* convert the desired name from internal to external format */
 362 
 363         if (gss_display_name(&minor_status_temp, desired_name, &external_name,
 364                                 &name_type) != GSS_S_COMPLETE) {
 365 
 366                 *minor_status = (OM_uint32) minor_status_temp;
 367                 killgssd_handle(clnt);
 368                 GSSLOG0(1, "kgss_acquire_cred: display name failed\n");
 369                 return ((OM_uint32) GSS_S_FAILURE);
 370         }
 371 
 372 
 373         /* copy the procedure arguments into the rpc arg parameter */
 374 
 375         arg.uid = (OM_uint32)uid;
 376         arg.input_cred_handle.GSS_CRED_ID_T_len =
 377                         input_cred_handle == GSSD_NO_CREDENTIAL ?
 378                         0 : (uint_t)sizeof (gssd_cred_id_t);
 379         arg.input_cred_handle.GSS_CRED_ID_T_val = (char *)&input_cred_handle;
 380         arg.gssd_cred_verifier = gssd_cred_verifier;
 381         arg.desired_name.GSS_BUFFER_T_len = (uint_t)external_name.length;
 382         arg.desired_name.GSS_BUFFER_T_val = (char *)external_name.value;
 383         arg.name_type.GSS_OID_len =
 384                 name_type == GSS_C_NULL_OID ?
 385                         0 : (uint_t)name_type->length;
 386         arg.name_type.GSS_OID_val =
 387                 name_type == GSS_C_NULL_OID ?
 388                         (char *)NULL : (char *)name_type->elements;
 389 
 390         arg.desired_mech_type.GSS_OID_len =
 391                 (uint_t)(desired_mech_type != GSS_C_NULL_OID ?
 392                 desired_mech_type->length : 0);
 393         arg.desired_mech_type.GSS_OID_val =
 394                 (char *)(desired_mech_type != GSS_C_NULL_OID ?
 395                 desired_mech_type->elements : 0);
 396         arg.cred_usage = cred_usage;
 397         arg.initiator_time_req = initiator_time_req;
 398         arg.acceptor_time_req = acceptor_time_req;
 399 
 400         /* call the remote procedure */
 401 
 402         bzero((caddr_t)&res, sizeof (res));
 403         if (gss_add_cred_1(&arg, &res, clnt) != RPC_SUCCESS) {
 404 
 405                 /*
 406                  * if the RPC call times out, null out all return arguments,
 407                  * set minor_status to its maximum value, and return
 408                  * GSS_S_FAILURE
 409                  */
 410 
 411                 killgssd_handle(clnt);
 412                 (void) gss_release_buffer(&minor_status_temp, &external_name);
 413                 GSSLOG0(1, "kgss_add_cred: RPC call times out\n");
 414                 return (GSS_S_FAILURE);
 415         }
 416 
 417         /* free the allocated memory for the flattened name */
 418 
 419         (void) gss_release_buffer(&minor_status_temp, &external_name);
 420 
 421         /* copy the rpc results into the return arguments */
 422 
 423         if (minor_status != NULL)
 424                 *minor_status = res.minor_status;
 425 
 426         if (res.status == GSS_S_COMPLETE &&
 427                 res.actual_mechs.GSS_OID_SET_len != 0 &&
 428                 actual_mechs != NULL) {
 429                 *actual_mechs = (gss_OID_set) MALLOC(sizeof (gss_OID_set_desc));
 430                 (*actual_mechs)->count =
 431                                         (int)res.actual_mechs.GSS_OID_SET_len;
 432                 (*actual_mechs)->elements = (gss_OID)
 433                         MALLOC(sizeof (gss_OID_desc) * (*actual_mechs)->count);
 434 
 435                 for (i = 0; i < (*actual_mechs)->count; i++) {
 436                     (*actual_mechs)->elements[i].length = (OM_uint32)
 437                         res.actual_mechs.GSS_OID_SET_val[i].GSS_OID_len;
 438                     (*actual_mechs)->elements[i].elements =
 439                         (void *) MALLOC((*actual_mechs)->elements[i].length);
 440                     (void) memcpy((*actual_mechs)->elements[i].elements,
 441                         res.actual_mechs.GSS_OID_SET_val[i].GSS_OID_val,
 442                         (*actual_mechs)->elements[i].length);
 443                 }
 444         } else {
 445                 if (res.status == GSS_S_COMPLETE && actual_mechs != NULL)
 446                         (*actual_mechs) = NULL;
 447         }
 448         if (initiator_time_rec != NULL)
 449                 *initiator_time_rec = res.acceptor_time_rec;
 450         if (acceptor_time_rec != NULL)
 451                 *acceptor_time_rec = res.acceptor_time_rec;
 452 
 453         /*
 454          * free the memory allocated for the results and return with the status
 455          * received in the rpc call
 456          */
 457 
 458         clnt_freeres(clnt, xdr_gss_add_cred_res, (caddr_t)&res);
 459         killgssd_handle(clnt);
 460         return (res.status);
 461 
 462 }
 463 
 464 OM_uint32
 465 kgss_add_cred(minor_status,
 466                         input_cred_handle,
 467                         desired_name,
 468                         desired_mech_type,
 469                         cred_usage,
 470                         initiator_time_req,
 471                         acceptor_time_req,
 472                         actual_mechs,
 473                         initiator_time_rec,
 474                         acceptor_time_rec,
 475                         uid)
 476         OM_uint32 *minor_status;
 477         gss_cred_id_t input_cred_handle;
 478         gss_name_t desired_name;
 479         gss_OID desired_mech_type;
 480         int cred_usage;
 481         int initiator_time_req;
 482         int acceptor_time_req;
 483         gss_OID_set *actual_mechs;
 484         OM_uint32 *initiator_time_rec;
 485         OM_uint32 *acceptor_time_rec;
 486         uid_t uid;
 487 {
 488 
 489         OM_uint32       err;
 490         OM_uint32 gssd_cred_verifier;
 491         gssd_cred_id_t gssd_input_cred_handle;
 492 
 493         if (input_cred_handle != GSS_C_NO_CREDENTIAL) {
 494                 gssd_cred_verifier = KCRED_TO_CREDV(input_cred_handle);
 495                 gssd_input_cred_handle = KCRED_TO_CRED(input_cred_handle);
 496         } else {
 497                 gssd_input_cred_handle = GSSD_NO_CREDENTIAL;
 498         }
 499 
 500         err = kgss_add_cred_wrapped(minor_status, gssd_input_cred_handle,
 501                         gssd_cred_verifier, desired_name, desired_mech_type,
 502                         cred_usage, initiator_time_req, acceptor_time_req,
 503                         actual_mechs, initiator_time_rec,
 504                         acceptor_time_rec, uid);
 505         return (err);
 506 }
 507 
 508 
 509 OM_uint32
 510 kgss_release_cred_wrapped(minor_status,
 511                         cred_handle,
 512                         uid,
 513                         gssd_cred_verifier)
 514     OM_uint32 *minor_status;
 515     gssd_cred_id_t *cred_handle;
 516     uid_t uid;
 517     OM_uint32  gssd_cred_verifier;
 518 {
 519         CLIENT *clnt;
 520 
 521         gss_release_cred_arg arg;
 522         gss_release_cred_res res;
 523 
 524 
 525         /* get the client handle to GSSD */
 526 
 527         if ((clnt = getgssd_handle()) == NULL) {
 528                 GSSLOG(1, "kgss_release_cred: can't connect to server on %s\n",
 529                         server);
 530                 return (GSS_S_FAILURE);
 531         }
 532 
 533         /* copy the procedure arguments into the rpc arg parameter */
 534 
 535         arg.uid = (OM_uint32)uid;
 536         arg.gssd_cred_verifier = gssd_cred_verifier;
 537 
 538         if (cred_handle != NULL) {
 539                 arg.cred_handle.GSS_CRED_ID_T_len =
 540                                         (uint_t)sizeof (gssd_cred_id_t);
 541                 arg.cred_handle.GSS_CRED_ID_T_val = (char *)cred_handle;
 542         } else
 543                 arg.cred_handle.GSS_CRED_ID_T_len = 0;
 544 
 545         /* call the remote procedure */
 546 
 547         bzero((caddr_t)&res, sizeof (res));
 548         if (gss_release_cred_1(&arg, &res, clnt) != RPC_SUCCESS) {
 549 
 550         /*
 551          * if the RPC call times out, null out all return arguments, set
 552          * minor_status to its maximum value, and return GSS_S_FAILURE
 553          */
 554 
 555                 if (minor_status != NULL)
 556                         *minor_status = DEFAULT_MINOR_STAT;
 557                 if (cred_handle != NULL)
 558                         *cred_handle = NULL;
 559 
 560                 killgssd_handle(clnt);
 561                 GSSLOG0(1, "kgss_release_cred: RPC call times out\n");
 562                 return (GSS_S_FAILURE);
 563         }
 564 
 565         /* if the release succeeded, null out the cred_handle */
 566 
 567         if (res.status == GSS_S_COMPLETE && cred_handle != NULL)
 568                 *cred_handle = NULL;
 569 
 570         /* copy the rpc results into the return arguments */
 571 
 572         if (minor_status != NULL)
 573                 *minor_status = res.minor_status;
 574 
 575         /* return with status returned in rpc call */
 576 
 577         killgssd_handle(clnt);
 578 
 579         return (res.status);
 580 
 581 }
 582 
 583 OM_uint32
 584 kgss_release_cred(minor_status,
 585                         cred_handle,
 586                         uid)
 587     OM_uint32 *minor_status;
 588     gss_cred_id_t *cred_handle;
 589     uid_t uid;
 590 
 591 {
 592 
 593         OM_uint32       err;
 594         struct kgss_cred *kcred;
 595 
 596         if (*cred_handle == GSS_C_NO_CREDENTIAL)
 597                 return (GSS_S_COMPLETE);
 598         else
 599                 kcred = KCRED_TO_KGSS_CRED(*cred_handle);
 600 
 601         err = kgss_release_cred_wrapped(minor_status, &kcred->gssd_cred,
 602                 uid, kcred->gssd_cred_verifier);
 603         KGSS_CRED_FREE(kcred);
 604         *cred_handle = GSS_C_NO_CREDENTIAL;
 605         return (err);
 606 }
 607 
 608 static OM_uint32
 609 kgss_init_sec_context_wrapped(
 610         OM_uint32 *minor_status,
 611         const gssd_cred_id_t claimant_cred_handle,
 612         OM_uint32 gssd_cred_verifier,
 613         gssd_ctx_id_t *context_handle,
 614         OM_uint32 *gssd_context_verifier,
 615         const gss_name_t target_name,
 616         const gss_OID mech_type,
 617         int req_flags,
 618         OM_uint32 time_req,
 619         const gss_channel_bindings_t input_chan_bindings,
 620         const gss_buffer_t input_token,
 621         gss_OID *actual_mech_type,
 622         gss_buffer_t output_token,
 623         int *ret_flags,
 624         OM_uint32 *time_rec,
 625         uid_t uid)
 626 {
 627         CLIENT *clnt;
 628 
 629         OM_uint32       minor_status_temp;
 630         gss_buffer_desc external_name;
 631         gss_OID         name_type;
 632 
 633         gss_init_sec_context_arg arg;
 634         gss_init_sec_context_res res;
 635 
 636         /* get the client handle to GSSD */
 637 
 638         if ((clnt = getgssd_handle()) == NULL) {
 639                 GSSLOG(1,
 640                     "kgss_init_sec_context: can't connect to server on %s\n",
 641                     server);
 642                 return (GSS_S_FAILURE);
 643         }
 644 
 645         /* convert the target name from internal to external format */
 646 
 647         if (gss_display_name(&minor_status_temp, target_name,
 648             &external_name, &name_type) != GSS_S_COMPLETE) {
 649 
 650                 *minor_status = (OM_uint32) minor_status_temp;
 651                 killgssd_handle(clnt);
 652                 GSSLOG0(1, "kgss_init_sec_context: can't display name\n");
 653                 return ((OM_uint32) GSS_S_FAILURE);
 654         }
 655 
 656 
 657         /* copy the procedure arguments into the rpc arg parameter */
 658 
 659         arg.uid = (OM_uint32)uid;
 660 
 661         arg.context_handle.GSS_CTX_ID_T_len =
 662             *context_handle == GSSD_NO_CONTEXT ?
 663             0 : (uint_t)sizeof (gssd_ctx_id_t);
 664         arg.context_handle.GSS_CTX_ID_T_val =  (char *)context_handle;
 665 
 666         arg.gssd_context_verifier =  *gssd_context_verifier;
 667 
 668         arg.claimant_cred_handle.GSS_CRED_ID_T_len =
 669             claimant_cred_handle == GSSD_NO_CREDENTIAL ?
 670             0 : (uint_t)sizeof (gssd_cred_id_t);
 671         arg.claimant_cred_handle.GSS_CRED_ID_T_val =
 672             (char *)&claimant_cred_handle;
 673         arg.gssd_cred_verifier = gssd_cred_verifier;
 674 
 675         arg.target_name.GSS_BUFFER_T_len = (uint_t)external_name.length;
 676         arg.target_name.GSS_BUFFER_T_val = (char *)external_name.value;
 677 
 678         arg.name_type.GSS_OID_len =
 679             name_type == GSS_C_NULL_OID ? 0 : (uint_t)name_type->length;
 680 
 681         arg.name_type.GSS_OID_val =
 682             name_type == GSS_C_NULL_OID ?
 683             (char *)NULL : (char *)name_type->elements;
 684 
 685         arg.mech_type.GSS_OID_len = (uint_t)(mech_type != GSS_C_NULL_OID ?
 686             mech_type->length : 0);
 687         arg.mech_type.GSS_OID_val = (char *)(mech_type != GSS_C_NULL_OID ?
 688             mech_type->elements : 0);
 689 
 690         arg.req_flags = req_flags;
 691 
 692         arg.time_req = time_req;
 693 
 694         if (input_chan_bindings != GSS_C_NO_CHANNEL_BINDINGS) {
 695                 arg.input_chan_bindings.present = YES;
 696                 arg.input_chan_bindings.initiator_addrtype =
 697                     input_chan_bindings->initiator_addrtype;
 698                 arg.input_chan_bindings.initiator_address.GSS_BUFFER_T_len =
 699                     (uint_t)input_chan_bindings->initiator_address.length;
 700                 arg.input_chan_bindings.initiator_address.GSS_BUFFER_T_val =
 701                     (void *)input_chan_bindings->initiator_address.value;
 702                 arg.input_chan_bindings.acceptor_addrtype =
 703                     input_chan_bindings->acceptor_addrtype;
 704                 arg.input_chan_bindings.acceptor_address.GSS_BUFFER_T_len =
 705                     (uint_t)input_chan_bindings->acceptor_address.length;
 706                 arg.input_chan_bindings.acceptor_address.GSS_BUFFER_T_val =
 707                     (void *)input_chan_bindings->acceptor_address.value;
 708                 arg.input_chan_bindings.application_data.GSS_BUFFER_T_len =
 709                     (uint_t)input_chan_bindings->application_data.length;
 710                 arg.input_chan_bindings.application_data.GSS_BUFFER_T_val =
 711                     (void *)input_chan_bindings->application_data.value;
 712         } else {
 713                 arg.input_chan_bindings.present = NO;
 714                 arg.input_chan_bindings.initiator_addrtype = 0;
 715                 arg.input_chan_bindings.initiator_address.GSS_BUFFER_T_len = 0;
 716                 arg.input_chan_bindings.initiator_address.GSS_BUFFER_T_val = 0;
 717                 arg.input_chan_bindings.acceptor_addrtype = 0;
 718                 arg.input_chan_bindings.acceptor_address.GSS_BUFFER_T_len = 0;
 719                 arg.input_chan_bindings.acceptor_address.GSS_BUFFER_T_val = 0;
 720                 arg.input_chan_bindings.application_data.GSS_BUFFER_T_len = 0;
 721                 arg.input_chan_bindings.application_data.GSS_BUFFER_T_val = 0;
 722         }
 723 
 724         arg.input_token.GSS_BUFFER_T_len =
 725             (uint_t)(input_token != GSS_C_NO_BUFFER ? input_token->length : 0);
 726         arg.input_token.GSS_BUFFER_T_val =
 727             (char *)(input_token != GSS_C_NO_BUFFER ? input_token->value : 0);
 728 
 729         /* call the remote procedure */
 730 
 731         bzero((caddr_t)&res, sizeof (res));
 732         if (gss_init_sec_context_1(&arg, &res, clnt) != RPC_SUCCESS) {
 733 
 734         /*
 735          * if the RPC call times out, null out all return arguments, set
 736          * minor_status to its maximum value, and return GSS_S_FAILURE
 737          */
 738 
 739                 if (minor_status != NULL)
 740                         *minor_status = DEFAULT_MINOR_STAT;
 741                 if (actual_mech_type != NULL)
 742                         *actual_mech_type = NULL;
 743                 if (output_token != NULL)
 744                         output_token->length = 0;
 745                 if (ret_flags != NULL)
 746                         *ret_flags = 0;
 747                 if (time_rec != NULL)
 748                         *time_rec = 0;
 749 
 750                 killgssd_handle(clnt);
 751                 (void) gss_release_buffer(&minor_status_temp, &external_name);
 752                 GSSLOG0(1, "kgss_init_sec_context: RPC call times out\n");
 753                 return (GSS_S_FAILURE);
 754         }
 755 
 756         /* free the allocated memory for the flattened name */
 757 
 758         (void) gss_release_buffer(&minor_status_temp, &external_name);
 759 
 760         if (minor_status != NULL)
 761                 *minor_status = res.minor_status;
 762 
 763         if (output_token != NULL && res.output_token.GSS_BUFFER_T_val != NULL) {
 764                 output_token->length =
 765                     (size_t)res.output_token.GSS_BUFFER_T_len;
 766                 output_token->value =
 767                     (void *)MALLOC(output_token->length);
 768                 (void) memcpy(output_token->value,
 769                     res.output_token.GSS_BUFFER_T_val, output_token->length);
 770         }
 771 
 772         /* if the call was successful, copy out the results */
 773         if (res.status == (OM_uint32) GSS_S_COMPLETE ||
 774             res.status == (OM_uint32) GSS_S_CONTINUE_NEEDED) {
 775                 /*
 776                  * if the return code is GSS_S_CONTINUE_NEEDED
 777                  * ignore all return parameters except for
 778                  * status codes, output token and context handle.
 779                  */
 780                 *context_handle =
 781                     *((gssd_ctx_id_t *)res.context_handle.GSS_CTX_ID_T_val);
 782                 *gssd_context_verifier = res.gssd_context_verifier;
 783 
 784                 if (res.status == GSS_S_COMPLETE) {
 785                         if (actual_mech_type != NULL) {
 786                                 *actual_mech_type =
 787                                     (gss_OID) MALLOC(sizeof (gss_OID_desc));
 788                                 (*actual_mech_type)->length =
 789                                     (OM_UINT32)res.actual_mech_type.GSS_OID_len;
 790                                 (*actual_mech_type)->elements =
 791                                     (void *)MALLOC((*actual_mech_type)->length);
 792                                 (void) memcpy((*actual_mech_type)->elements,
 793                                     (void *)res.actual_mech_type.GSS_OID_val,
 794                                     (*actual_mech_type)->length);
 795                         }
 796 
 797 
 798                         if (ret_flags != NULL)
 799                                 *ret_flags = res.ret_flags;
 800 
 801                         if (time_rec != NULL)
 802                                 *time_rec = res.time_rec;
 803                 }
 804         }
 805 
 806         /*
 807          * free the memory allocated for the results and return with the status
 808          * received in the rpc call
 809          */
 810 
 811         clnt_freeres(clnt, xdr_gss_init_sec_context_res, (caddr_t)&res);
 812         killgssd_handle(clnt);
 813         return (res.status);
 814 
 815 }
 816 
 817 static struct gss_config default_gc = {
 818         { 0, NULL},
 819         NULL,
 820         NULL,
 821         0,
 822         kgss_unseal_wrapped,
 823         NULL,           /* kgss_delete_sec_context_wrapped */
 824         kgss_seal_wrapped,
 825         NULL,           /* kgss_import_sec_context */
 826         kgss_sign_wrapped,
 827         kgss_verify_wrapped
 828 };
 829 
 830 void
 831 kgss_free_oid(gss_OID oid)
 832 {
 833         FREE(oid->elements, oid->length);
 834         FREE(oid, sizeof (gss_OID_desc));
 835 }
 836 
 837 OM_uint32
 838 kgss_init_sec_context(
 839         OM_uint32 *minor_status,
 840         const gss_cred_id_t claimant_cred_handle,
 841         gss_ctx_id_t *context_handle,
 842         const gss_name_t target_name,
 843         const gss_OID mech_type,
 844         int req_flags,
 845         OM_uint32 time_req,
 846         const gss_channel_bindings_t input_chan_bindings,
 847         const gss_buffer_t input_token,
 848         gss_OID *actual_mech_type,
 849         gss_buffer_t output_token,
 850         int *ret_flags,
 851         OM_uint32 *time_rec,
 852         uid_t uid)
 853 {
 854         OM_uint32       err;
 855         struct kgss_ctx *kctx;
 856         gss_OID amt;
 857         gssd_cred_id_t gssd_cl_cred_handle;
 858         OM_uint32 gssd_cred_verifier;
 859 
 860         /*
 861          * If this is an initial call, we'll need to create the
 862          * wrapper struct that contains kernel state information, and
 863          * a reference to the handle from gssd.
 864          */
 865         if (*context_handle == GSS_C_NO_CONTEXT) {
 866                 kctx = KGSS_ALLOC();
 867                 /*
 868                  * The default gss-mechanism struct as pointers to
 869                  * the sign/seal/verify/unseal routines that make
 870                  * upcalls to gssd.
 871                  */
 872                 kctx->mech = &default_gc;
 873                 kctx->gssd_ctx = GSSD_NO_CONTEXT;
 874                 *context_handle = (gss_ctx_id_t)kctx;
 875         } else
 876                 kctx = (struct kgss_ctx *)*context_handle;
 877 
 878         if (claimant_cred_handle != GSS_C_NO_CREDENTIAL) {
 879                 gssd_cred_verifier = KCRED_TO_CREDV(claimant_cred_handle);
 880                 gssd_cl_cred_handle = KCRED_TO_CRED(claimant_cred_handle);
 881         } else {
 882                 gssd_cl_cred_handle = GSSD_NO_CREDENTIAL;
 883         }
 884 
 885         /*
 886          * We need to know the resulting mechanism oid, so allocate
 887          * it if the caller won't.
 888          */
 889         if (actual_mech_type == NULL)
 890                 actual_mech_type = &amt;
 891 
 892         err = kgss_init_sec_context_wrapped(minor_status, gssd_cl_cred_handle,
 893             gssd_cred_verifier, &kctx->gssd_ctx, &kctx->gssd_ctx_verifier,
 894             target_name, mech_type, req_flags, time_req,
 895             input_chan_bindings, input_token, actual_mech_type,
 896             output_token, ret_flags, time_rec, uid);
 897 
 898         if (GSS_ERROR(err)) {
 899                 KGSS_FREE(kctx);
 900                 *context_handle = GSS_C_NO_CONTEXT;
 901         } else if (err == GSS_S_COMPLETE) {
 902                 /*
 903                  * Now check if there is a kernel module for this
 904                  * mechanism OID. If so, set the gss_mechanism structure
 905                  * in the wrapper context to point to the kernel mech.
 906                  */
 907                 __kgss_reset_mech(&kctx->mech, *actual_mech_type);
 908 
 909                 /*
 910                  * If the mech oid was allocated for us, free it.
 911                  */
 912                 if (&amt == actual_mech_type) {
 913                         kgss_free_oid(amt);
 914                 }
 915         }
 916         return (err);
 917 }
 918 
 919 static OM_uint32
 920 kgss_accept_sec_context_wrapped(
 921         OM_uint32 *minor_status,
 922         gssd_ctx_id_t *context_handle,
 923         OM_uint32 *gssd_context_verifier,
 924         const gssd_cred_id_t verifier_cred_handle,
 925         OM_uint32 gssd_cred_verifier,
 926         const gss_buffer_t input_token,
 927         const gss_channel_bindings_t input_chan_bindings,
 928         gss_buffer_t src_name,
 929         gss_OID *mech_type,
 930         gss_buffer_t output_token,
 931         int *ret_flags,
 932         OM_uint32 *time_rec,
 933         gss_cred_id_t *delegated_cred_handle,
 934         uid_t uid)
 935 {
 936         CLIENT *clnt;
 937 
 938         gss_accept_sec_context_arg arg;
 939         gss_accept_sec_context_res res;
 940         struct kgss_cred *kcred;
 941 
 942         /* get the client handle to GSSD */
 943 
 944         if ((clnt = getgssd_handle()) == NULL) {
 945                 GSSLOG(1,
 946                     "kgss_accept_sec_context: can't connect to server on %s\n",
 947                     server);
 948                 return (GSS_S_FAILURE);
 949         }
 950 
 951         /* copy the procedure arguments into the rpc arg parameter */
 952 
 953         arg.uid = (OM_uint32)uid;
 954 
 955         arg.context_handle.GSS_CTX_ID_T_len =
 956             *context_handle == GSSD_NO_CONTEXT ?
 957             0 : (uint_t)sizeof (gssd_ctx_id_t);
 958         arg.context_handle.GSS_CTX_ID_T_val =  (char *)context_handle;
 959         arg.gssd_context_verifier = *gssd_context_verifier;
 960 
 961         arg.verifier_cred_handle.GSS_CRED_ID_T_len =
 962             verifier_cred_handle == GSSD_NO_CREDENTIAL ?
 963             0 : (uint_t)sizeof (gssd_cred_id_t);
 964         arg.verifier_cred_handle.GSS_CRED_ID_T_val =
 965             (char *)&verifier_cred_handle;
 966         arg.gssd_cred_verifier = gssd_cred_verifier;
 967 
 968         arg.input_token_buffer.GSS_BUFFER_T_len =
 969             (uint_t)(input_token != GSS_C_NO_BUFFER ? input_token->length : 0);
 970         arg.input_token_buffer.GSS_BUFFER_T_val =
 971             (char *)(input_token != GSS_C_NO_BUFFER ? input_token->value : 0);
 972 
 973         if (input_chan_bindings != GSS_C_NO_CHANNEL_BINDINGS) {
 974                 arg.input_chan_bindings.present = YES;
 975                 arg.input_chan_bindings.initiator_addrtype =
 976                     input_chan_bindings->initiator_addrtype;
 977                 arg.input_chan_bindings.initiator_address.GSS_BUFFER_T_len =
 978                     (uint_t)input_chan_bindings->initiator_address.length;
 979                 arg.input_chan_bindings.initiator_address.GSS_BUFFER_T_val =
 980                     (void *)input_chan_bindings->initiator_address.value;
 981                 arg.input_chan_bindings.acceptor_addrtype =
 982                     input_chan_bindings->acceptor_addrtype;
 983                 arg.input_chan_bindings.acceptor_address.GSS_BUFFER_T_len =
 984                     (uint_t)input_chan_bindings->acceptor_address.length;
 985                 arg.input_chan_bindings.acceptor_address.GSS_BUFFER_T_val =
 986                     (void *)input_chan_bindings->acceptor_address.value;
 987                 arg.input_chan_bindings.application_data.GSS_BUFFER_T_len =
 988                     (uint_t)input_chan_bindings->application_data.length;
 989                 arg.input_chan_bindings.application_data.GSS_BUFFER_T_val =
 990                     (void *)input_chan_bindings->application_data.value;
 991         } else {
 992 
 993                 arg.input_chan_bindings.present = NO;
 994                 arg.input_chan_bindings.initiator_addrtype = 0;
 995                 arg.input_chan_bindings.initiator_address.GSS_BUFFER_T_len = 0;
 996                 arg.input_chan_bindings.initiator_address.GSS_BUFFER_T_val = 0;
 997                 arg.input_chan_bindings.acceptor_addrtype = 0;
 998                 arg.input_chan_bindings.acceptor_address.GSS_BUFFER_T_len = 0;
 999                 arg.input_chan_bindings.acceptor_address.GSS_BUFFER_T_val = 0;
1000                 arg.input_chan_bindings.application_data.GSS_BUFFER_T_len = 0;
1001                 arg.input_chan_bindings.application_data.GSS_BUFFER_T_val = 0;
1002         }
1003 
1004         /* set the return parameters in case of errors.... */
1005         if (minor_status != NULL)
1006                 *minor_status = DEFAULT_MINOR_STAT;
1007         if (src_name != NULL) {
1008                 src_name->length = 0;
1009                 src_name->value = NULL;
1010         }
1011         if (mech_type != NULL)
1012                 *mech_type = NULL;
1013         if (output_token != NULL)
1014                 output_token->length = 0;
1015         if (ret_flags != NULL)
1016                 *ret_flags = 0;
1017         if (time_rec != NULL)
1018                 *time_rec = 0;
1019         if (delegated_cred_handle != NULL)
1020                 *delegated_cred_handle = NULL;
1021 
1022         /* call the remote procedure */
1023 
1024         bzero((caddr_t)&res, sizeof (res));
1025         if (gss_accept_sec_context_1(&arg, &res, clnt) != RPC_SUCCESS) {
1026                 killgssd_handle(clnt);
1027                 GSSLOG0(1, "kgss_accept_sec_context: RPC call times out\n");
1028                 return (GSS_S_FAILURE);
1029         }
1030 
1031         if (minor_status != NULL)
1032                 *minor_status = res.minor_status;
1033 
1034         if (output_token != NULL && res.output_token.GSS_BUFFER_T_val != NULL) {
1035                 output_token->length = res.output_token.GSS_BUFFER_T_len;
1036                 output_token->value = (void *)MALLOC(output_token->length);
1037                 (void) memcpy(output_token->value,
1038                     res.output_token.GSS_BUFFER_T_val, output_token->length);
1039         }
1040 
1041         /* if the call was successful, copy out the results */
1042 
1043         if (res.status == (OM_uint32)GSS_S_COMPLETE ||
1044             res.status == (OM_uint32)GSS_S_CONTINUE_NEEDED) {
1045 
1046                 /*
1047                  * the only parameters that are ready when we
1048                  * get GSS_S_CONTINUE_NEEDED are: minor, ctxt_handle,
1049                  * and the output token to send to the peer.
1050                  */
1051 
1052                 *context_handle = *((gssd_ctx_id_t *)
1053                     res.context_handle.GSS_CTX_ID_T_val);
1054                 *gssd_context_verifier = res.gssd_context_verifier;
1055 
1056                 /* these other parameters are only ready upon GSS_S_COMPLETE */
1057                 if (res.status == (OM_uint32)GSS_S_COMPLETE) {
1058 
1059                         if (src_name != NULL) {
1060                                 src_name->length =
1061                                     res.src_name.GSS_BUFFER_T_len;
1062                                 src_name->value = res.src_name.GSS_BUFFER_T_val;
1063                                 res.src_name.GSS_BUFFER_T_val = NULL;
1064                                 res.src_name.GSS_BUFFER_T_len = 0;
1065                         }
1066 
1067                         /*
1068                          * move mech type returned to mech_type
1069                          * for gss_import_name_for_mech()
1070                          */
1071                         if (mech_type != NULL) {
1072                                 *mech_type =
1073                                     (gss_OID)MALLOC(sizeof (gss_OID_desc));
1074                                 (*mech_type)->length =
1075                                     (OM_UINT32)res.mech_type.GSS_OID_len;
1076                                 (*mech_type)->elements =
1077                                     (void *)MALLOC((*mech_type)->length);
1078                                 (void) memcpy((*mech_type)->elements,
1079                                     res.mech_type.GSS_OID_val,
1080                                     (*mech_type)->length);
1081                         }
1082 
1083                         if (ret_flags != NULL)
1084                                 *ret_flags = res.ret_flags;
1085 
1086                         if (time_rec != NULL)
1087                                 *time_rec = res.time_rec;
1088 
1089                         if ((delegated_cred_handle != NULL) &&
1090                             (res.delegated_cred_handle.GSS_CRED_ID_T_len
1091                             != 0)) {
1092                                 kcred = KGSS_CRED_ALLOC();
1093                                 kcred->gssd_cred =
1094                                     *((gssd_cred_id_t *)
1095                                     res.delegated_cred_handle.GSS_CRED_ID_T_val);
1096                                 kcred->gssd_cred_verifier =
1097                                     res.gssd_context_verifier;
1098                                 *delegated_cred_handle = (gss_cred_id_t)kcred;
1099                         }
1100 
1101                 }
1102         }
1103 
1104 
1105         /*
1106          * free the memory allocated for the results and return with the status
1107          * received in the rpc call
1108          */
1109 
1110         clnt_freeres(clnt, xdr_gss_accept_sec_context_res, (caddr_t)&res);
1111         killgssd_handle(clnt);
1112         return (res.status);
1113 
1114 }
1115 
1116 OM_uint32
1117 kgss_accept_sec_context(
1118         OM_uint32 *minor_status,
1119         gss_ctx_id_t *context_handle,
1120         const gss_cred_id_t verifier_cred_handle,
1121         const gss_buffer_t input_token,
1122         const gss_channel_bindings_t input_chan_bindings,
1123         gss_buffer_t src_name,
1124         gss_OID *mech_type,
1125         gss_buffer_t output_token,
1126         int *ret_flags,
1127         OM_uint32 *time_rec,
1128         gss_cred_id_t *delegated_cred_handle,
1129         uid_t uid)
1130 {
1131         OM_uint32 err;
1132         struct kgss_ctx *kctx;
1133         gss_OID mt;
1134         OM_uint32 gssd_cred_verifier;
1135         gssd_cred_id_t gssd_ver_cred_handle;
1136 
1137 
1138         /*
1139          * See kgss_init_sec_context() to get an idea of what is going
1140          * on here.
1141          */
1142         if (mech_type == NULL)
1143                 mech_type = &mt;
1144 
1145         if (*context_handle == GSS_C_NO_CONTEXT) {
1146                 kctx = KGSS_ALLOC();
1147                 kctx->mech = &default_gc;
1148                 kctx->gssd_ctx = GSSD_NO_CONTEXT;
1149                 *context_handle = (gss_ctx_id_t)kctx;
1150         } else
1151                 kctx = (struct kgss_ctx *)*context_handle;
1152 
1153         if (verifier_cred_handle != GSS_C_NO_CREDENTIAL) {
1154                 gssd_cred_verifier = KCRED_TO_CREDV(verifier_cred_handle);
1155                 gssd_ver_cred_handle = KCRED_TO_CRED(verifier_cred_handle);
1156         } else {
1157                 gssd_ver_cred_handle = GSSD_NO_CREDENTIAL;
1158         }
1159 
1160         err = kgss_accept_sec_context_wrapped(minor_status,
1161             &kctx->gssd_ctx, &kctx->gssd_ctx_verifier,
1162             gssd_ver_cred_handle, gssd_cred_verifier,
1163             input_token, input_chan_bindings, src_name,
1164             mech_type, output_token, ret_flags,
1165             time_rec, delegated_cred_handle, uid);
1166 
1167         if (GSS_ERROR(err)) {
1168                 KGSS_FREE(kctx);
1169                 *context_handle = GSS_C_NO_CONTEXT;
1170 
1171         } else if (err == GSS_S_COMPLETE) {
1172                 __kgss_reset_mech(&kctx->mech, *mech_type);
1173 
1174                 /*
1175                  * If the mech oid was allocated for us, free it.
1176                  */
1177                 if (&mt == mech_type) {
1178                         kgss_free_oid(mt);
1179                 }
1180         }
1181 
1182         return (err);
1183 }
1184 
1185 OM_uint32
1186 kgss_process_context_token(minor_status,
1187                                 context_handle,
1188                                 token_buffer,
1189                                 uid)
1190         OM_uint32 *minor_status;
1191         const gss_ctx_id_t context_handle;
1192         gss_buffer_t token_buffer;
1193         uid_t uid;
1194 {
1195         CLIENT *clnt;
1196         OM_uint32 gssd_context_verifier;
1197         gssd_ctx_id_t gssd_ctx_handle;
1198         gss_process_context_token_arg arg;
1199         gss_process_context_token_res res;
1200 
1201         gssd_context_verifier = KGSS_CTX_TO_GSSD_CTXV(context_handle);
1202         gssd_ctx_handle = (gssd_ctx_id_t)KGSS_CTX_TO_GSSD_CTX(context_handle);
1203 
1204         /* get the client handle to GSSD */
1205 
1206         if ((clnt = getgssd_handle()) == NULL) {
1207                 GSSLOG(1,
1208                 "kgss_process_context_token: can't connect to server on %s\n",
1209                 server);
1210                 return (GSS_S_FAILURE);
1211         }
1212 
1213         /* copy the procedure arguments into the rpc arg parameter */
1214 
1215         arg.uid = (OM_uint32) uid;
1216 
1217         arg.context_handle.GSS_CTX_ID_T_len = (uint_t)sizeof (gssd_ctx_id_t);
1218         arg.context_handle.GSS_CTX_ID_T_val = (char *)&gssd_ctx_handle;
1219         arg.gssd_context_verifier = gssd_context_verifier;
1220         arg.token_buffer.GSS_BUFFER_T_len = (uint_t)token_buffer->length;
1221         arg.token_buffer.GSS_BUFFER_T_val = (char *)token_buffer->value;
1222 
1223         /* call the remote procedure */
1224 
1225         bzero(&res, sizeof (res));
1226 
1227         if (gss_process_context_token_1(&arg, &res, clnt) != RPC_SUCCESS) {
1228 
1229         /*
1230          * if the RPC call times out, null out all return arguments, set
1231          * minor_status to its maximum value, and return GSS_S_FAILURE
1232          */
1233 
1234                 if (minor_status != NULL)
1235                         *minor_status = DEFAULT_MINOR_STAT;
1236                 GSSLOG0(1, "kgss_process_context_token: RPC call times out\n");
1237                 killgssd_handle(clnt);
1238                 return (GSS_S_FAILURE);
1239         }
1240 
1241         /* copy the rpc results into the return arguments */
1242 
1243         if (minor_status != NULL)
1244                 *minor_status = res.minor_status;
1245 
1246         /* return with status returned in rpc call */
1247 
1248         killgssd_handle(clnt);
1249         return (res.status);
1250 
1251 }
1252 
1253 /*ARGSUSED*/
1254 static OM_uint32
1255 kgss_delete_sec_context_wrapped(void *private,
1256                         OM_uint32 *minor_status,
1257                         gssd_ctx_id_t *context_handle,
1258                         gss_buffer_t output_token,
1259                         OM_uint32 gssd_context_verifier)
1260 
1261 
1262 {
1263         CLIENT *clnt;
1264 
1265         gss_delete_sec_context_arg arg;
1266         gss_delete_sec_context_res res;
1267 
1268 
1269         /* get the client handle to GSSD */
1270 
1271         if ((clnt = getgssd_handle()) == NULL) {
1272                 GSSLOG(1,
1273                 "kgss_delete_sec_context: can't connect to server on %s\n",
1274                 server);
1275                 return (GSS_S_FAILURE);
1276         }
1277 
1278         /* copy the procedure arguments into the rpc arg parameter */
1279 
1280         arg.context_handle.GSS_CTX_ID_T_len =
1281                 *context_handle == GSSD_NO_CONTEXT ?
1282                         0 : (uint_t)sizeof (gssd_ctx_id_t);
1283         arg.context_handle.GSS_CTX_ID_T_val =  (char *)context_handle;
1284 
1285         arg.gssd_context_verifier = gssd_context_verifier;
1286 
1287         /* call the remote procedure */
1288 
1289         bzero((caddr_t)&res, sizeof (res));
1290         if (gss_delete_sec_context_1(&arg, &res, clnt) != RPC_SUCCESS) {
1291 
1292         /*
1293          * if the RPC call times out, null out all return arguments, set
1294          * minor_status to its maximum value, and return GSS_S_FAILURE
1295          */
1296 
1297                 if (minor_status != NULL)
1298                         *minor_status = DEFAULT_MINOR_STAT;
1299                 if (context_handle != NULL)
1300                         *context_handle = NULL;
1301                 if (output_token != NULL)
1302                         output_token->length = 0;
1303 
1304                 killgssd_handle(clnt);
1305                 GSSLOG0(1, "kgssd_delete_sec_context: RPC call times out\n");
1306                 return (GSS_S_FAILURE);
1307         }
1308 
1309         /* copy the rpc results into the return arguments */
1310 
1311         if (minor_status != NULL)
1312                 *minor_status = res.minor_status;
1313 
1314         if (res.context_handle.GSS_CTX_ID_T_len == 0)
1315                 *context_handle = NULL;
1316         else
1317                 *context_handle =
1318                     *((gssd_ctx_id_t *)res.context_handle.GSS_CTX_ID_T_val);
1319 
1320         if (output_token != NULL) {
1321                 output_token->length = res.output_token.GSS_BUFFER_T_len;
1322                 output_token->value = res.output_token.GSS_BUFFER_T_val;
1323                 res.output_token.GSS_BUFFER_T_len = 0;
1324                 res.output_token.GSS_BUFFER_T_val = NULL;
1325         }
1326 
1327         /*
1328          * free the memory allocated for the results and return with the status
1329          * received in the rpc call
1330          */
1331 
1332         clnt_freeres(clnt, xdr_gss_delete_sec_context_res, (caddr_t)&res);
1333         killgssd_handle(clnt);
1334         return (res.status);
1335 
1336 }
1337 
1338 OM_uint32
1339 kgss_delete_sec_context(
1340                 OM_uint32 *minor_status,
1341                 gss_ctx_id_t *context_handle,
1342                 gss_buffer_t output_token)
1343 {
1344         OM_uint32 err;
1345         struct kgss_ctx *kctx;
1346 
1347         if (*context_handle == GSS_C_NO_CONTEXT) {
1348                 GSSLOG0(8, "kgss_delete_sec_context: Null context handle \n");
1349                 return (GSS_S_COMPLETE);
1350         } else
1351                 kctx = (struct kgss_ctx *)*context_handle;
1352 
1353         if (kctx->ctx_imported == FALSE) {
1354                 if (kctx->gssd_ctx == GSSD_NO_CONTEXT) {
1355                         KGSS_FREE(kctx);
1356                         *context_handle = GSS_C_NO_CONTEXT;
1357                         return (GSS_S_COMPLETE);
1358                 }
1359                 err = kgss_delete_sec_context_wrapped(
1360                     KCTX_TO_PRIVATE(*context_handle),
1361                     minor_status,
1362                     &kctx->gssd_ctx,
1363                     output_token,
1364                     kctx->gssd_ctx_verifier);
1365         } else {
1366                 if (kctx->gssd_i_ctx == (gss_ctx_id_t)GSS_C_NO_CONTEXT) {
1367                         KGSS_FREE(kctx);
1368                         *context_handle = GSS_C_NO_CONTEXT;
1369                         return (GSS_S_COMPLETE);
1370                 }
1371                 err = KGSS_DELETE_SEC_CONTEXT(minor_status, kctx,
1372                     &kctx->gssd_i_ctx,  output_token);
1373         }
1374         KGSS_FREE(kctx);
1375         *context_handle = GSS_C_NO_CONTEXT;
1376         return (err);
1377 
1378 }
1379 
1380 
1381 OM_uint32
1382 kgss_export_sec_context_wrapped(minor_status,
1383                                 context_handle,
1384                                 output_token,
1385                                 gssd_context_verifier)
1386         OM_uint32 *minor_status;
1387         gssd_ctx_id_t *context_handle;
1388         gss_buffer_t output_token;
1389         OM_uint32 gssd_context_verifier;
1390 {
1391         CLIENT *clnt;
1392         gss_export_sec_context_arg arg;
1393         gss_export_sec_context_res res;
1394 
1395 
1396         /* get the client handle to GSSD */
1397 
1398         if ((clnt = getgssd_handle()) == NULL) {
1399                 GSSLOG(1, "kgss_export_sec_context_wrapped :"
1400                         " can't connect to server on %s\n", server);
1401                 return (GSS_S_FAILURE);
1402         }
1403 
1404         /* copy the procedure arguments into the rpc arg parameter */
1405 
1406         arg.context_handle.GSS_CTX_ID_T_len = (uint_t)sizeof (gssd_ctx_id_t);
1407         arg.context_handle.GSS_CTX_ID_T_val = (char *)context_handle;
1408         arg.gssd_context_verifier = gssd_context_verifier;
1409 
1410         /* call the remote procedure */
1411 
1412         (void) memset(&res, 0, sizeof (res));
1413         if (gss_export_sec_context_1(&arg, &res, clnt) != RPC_SUCCESS) {
1414 
1415         /*
1416          * if the RPC call times out, null out all return arguments,
1417          * set minor_status to its maximum value, and return
1418          * GSS_S_FAILURE
1419          */
1420 
1421                 if (minor_status != NULL)
1422                         *minor_status = DEFAULT_MINOR_STAT;
1423                 if (context_handle != NULL)
1424                         *context_handle = NULL;
1425                 if (output_token != NULL)
1426                         output_token->length = 0;
1427                 killgssd_handle(clnt);
1428                 GSSLOG0(1,
1429                 "kgss_export_sec_context_wrapped: RPC call times out\n");
1430                 return (GSS_S_FAILURE);
1431         }
1432 
1433         /* copy the rpc results into the return arguments */
1434 
1435         if (minor_status != NULL)
1436                 *minor_status = res.minor_status;
1437 
1438         if (res.context_handle.GSS_CTX_ID_T_len == 0)
1439                 *context_handle = NULL;
1440         else
1441                 *context_handle =
1442                     *((gssd_ctx_id_t *)res.context_handle.GSS_CTX_ID_T_val);
1443 
1444         if (output_token != NULL) {
1445                 output_token->length = res.output_token.GSS_BUFFER_T_len;
1446                 output_token->value =
1447                         (void *)  MALLOC(output_token->length);
1448                 (void) memcpy(output_token->value,
1449                         res.output_token.GSS_BUFFER_T_val,
1450                         output_token->length);
1451         }
1452 
1453         /*
1454          * free the memory allocated for the results and return with the status
1455          * received in the rpc call
1456          */
1457 
1458         clnt_freeres(clnt, xdr_gss_export_sec_context_res, (caddr_t)&res);
1459         killgssd_handle(clnt);
1460         return (res.status);
1461 
1462 }
1463 
1464 OM_uint32
1465 kgss_export_sec_context(minor_status,
1466                         context_handle,
1467                         output_token)
1468         OM_uint32 *minor_status;
1469         gss_ctx_id_t context_handle;
1470         gss_buffer_t output_token;
1471 {
1472         struct kgss_ctx *kctx;
1473 
1474         if (context_handle == GSS_C_NO_CONTEXT)
1475                 return (GSS_S_FAILURE);
1476         else
1477                 kctx = (struct kgss_ctx *)context_handle;
1478 
1479 
1480 
1481         /*
1482          *  If there is a kernel module then import_sec context must be
1483          *  supported and we make an upcall to export_sec_context.
1484          *  If there is no kernel module then we return an error
1485          */
1486 
1487         *minor_status = 0;
1488 
1489         if (kctx->mech->gss_import_sec_context) {
1490                 GSSLOG0(8, "kgss_export_sec_context: Kernel mod available \n");
1491                 return (kgss_export_sec_context_wrapped(minor_status,
1492                                                 &kctx->gssd_ctx,
1493                                                 output_token,
1494                                                 kctx->gssd_ctx_verifier));
1495 
1496         } else {
1497 
1498                 /*
1499                  * This is not the right error value; instead of
1500                  * inventing  new error we return GSS_S_NAME_NOT_MN
1501                  * This error is not returned by the export routine
1502                  */
1503 
1504                 GSSLOG0(8, "kgss_export_sec_context: Kernel mod "
1505                         "unavailable \n");
1506                 return (GSS_S_NAME_NOT_MN);
1507         }
1508 
1509 }
1510 
1511 OM_uint32
1512 kgss_import_sec_context(minor_status,
1513                         interprocess_token,
1514                         context_handle)
1515 
1516 OM_uint32 *             minor_status;
1517 const gss_buffer_t      interprocess_token;
1518 gss_ctx_id_t            context_handle;
1519 
1520 {
1521 OM_uint32 status;
1522 struct kgss_ctx *kctx;
1523 
1524 size_t          length;
1525 char            *p;
1526 gss_buffer_desc token;
1527 gss_ctx_id_t    internal_ctx_id;
1528         kctx = (struct kgss_ctx *)context_handle;
1529 
1530         if (kctx->gssd_ctx != GSSD_NO_CONTEXT) {
1531                 return (GSS_S_FAILURE);
1532         }
1533 
1534         if (!(KCTX_TO_MECH(context_handle)->gss_import_sec_context)) {
1535 
1536         /*
1537          *  This should never happen
1538          *  If Kernel import sec context does not exist the export
1539          *  sec context should have caught this and returned an error
1540          *  and the caller should not have called this routine
1541          */
1542                 GSSLOG0(1, "import_sec_context  called improperly\n");
1543                 return (GSS_S_FAILURE);
1544         }
1545         *minor_status = 0;
1546 
1547         if (interprocess_token->length == 0 || interprocess_token->value == 0)
1548                 return (GSS_S_DEFECTIVE_TOKEN);
1549 
1550         status = GSS_S_FAILURE;
1551 
1552         p = interprocess_token->value;
1553         length = *p++;
1554         length = (length << 8) + *p++;
1555         length = (length << 8) + *p++;
1556         length = (length << 8) + *p++;
1557 
1558         p += length;
1559 
1560         token.length = interprocess_token->length - 4 - length;
1561         token.value = p;
1562 
1563         /*
1564          * select the approprate underlying mechanism routine and
1565          * call it.
1566          */
1567 
1568         status = KGSS_IMPORT_SEC_CONTEXT(minor_status, &token, kctx,
1569                                 &internal_ctx_id);
1570 
1571         if (status == GSS_S_COMPLETE) {
1572                 KCTX_TO_I_CTX(kctx) = internal_ctx_id;
1573                 kctx->ctx_imported = TRUE;
1574                 return (GSS_S_COMPLETE);
1575         } else
1576                 return (status);
1577 }
1578 
1579 /*ARGSUSED*/
1580 OM_uint32
1581 kgss_context_time(minor_status,
1582                 context_handle,
1583                 time_rec,
1584                 uid)
1585         OM_uint32 *minor_status;
1586         const gss_ctx_id_t context_handle;
1587         OM_uint32 *time_rec;
1588         uid_t uid;
1589 {
1590         return (GSS_S_FAILURE);
1591 }
1592 
1593 /*ARGSUSED*/
1594 static OM_uint32
1595 kgss_sign_wrapped(void *private,
1596         OM_uint32 *minor_status,
1597         const gss_ctx_id_t ctx_handle,
1598         int qop_req,
1599         const gss_buffer_t message_buffer,
1600         gss_buffer_t msg_token,
1601         OM_uint32 gssd_context_verifier)
1602 {
1603         CLIENT *clnt;
1604         gssd_ctx_id_t context_handle;
1605 
1606         gss_sign_arg arg;
1607         gss_sign_res res;
1608         context_handle = (gssd_ctx_id_t)KCTX_TO_GSSD_CTX(ctx_handle);
1609         /* get the client handle to GSSD */
1610 
1611         if ((clnt = getgssd_handle()) == NULL) {
1612                 GSSLOG(1, "kgss_sign: can't connect to server on %s\n", server);
1613                 return (GSS_S_FAILURE);
1614         }
1615 
1616         /* copy the procedure arguments into the rpc arg parameter */
1617 
1618         arg.context_handle.GSS_CTX_ID_T_len = (uint_t)sizeof (gssd_ctx_id_t);
1619         arg.context_handle.GSS_CTX_ID_T_val = (char *)&context_handle;
1620 
1621         arg.context_handle.GSS_CTX_ID_T_len = (uint_t)sizeof (gssd_ctx_id_t);
1622         arg.context_handle.GSS_CTX_ID_T_val = (char *)&context_handle;
1623         arg.gssd_context_verifier = gssd_context_verifier;
1624 
1625         arg.qop_req = qop_req;
1626 
1627         arg.message_buffer.GSS_BUFFER_T_len = (uint_t)message_buffer->length;
1628         arg.message_buffer.GSS_BUFFER_T_val = (char *)message_buffer->value;
1629 
1630         /* call the remote procedure */
1631 
1632         bzero((caddr_t)&res, sizeof (res));
1633         if (gss_sign_1(&arg, &res, clnt) != RPC_SUCCESS) {
1634 
1635         /*
1636          * if the RPC call times out, null out all return arguments, set
1637          * minor_status to its maximum value, and return GSS_S_FAILURE
1638          */
1639 
1640                 if (minor_status != NULL)
1641                         *minor_status = DEFAULT_MINOR_STAT;
1642                 if (msg_token != NULL)
1643                         msg_token->length = 0;
1644 
1645                 killgssd_handle(clnt);
1646                 GSSLOG0(1, "kgss_sign: RPC call times out\n");
1647                 return (GSS_S_FAILURE);
1648         }
1649 
1650         /* copy the rpc results into the return arguments */
1651 
1652         if (minor_status != NULL)
1653                 *minor_status = res.minor_status;
1654 
1655         if (msg_token != NULL) {
1656                 msg_token->length = res.msg_token.GSS_BUFFER_T_len;
1657                 msg_token->value = (void *) MALLOC(msg_token->length);
1658                 (void) memcpy(msg_token->value, res.msg_token.GSS_BUFFER_T_val,
1659                     msg_token->length);
1660         }
1661 
1662         /*
1663          * free the memory allocated for the results and return with the status
1664          * received in the rpc call
1665          */
1666 
1667         clnt_freeres(clnt, xdr_gss_sign_res, (caddr_t)&res);
1668         killgssd_handle(clnt);
1669         return (res.status);
1670 
1671 }
1672 
1673 OM_uint32
1674 kgss_sign(
1675         OM_uint32 *minor_status,
1676         const gss_ctx_id_t context_handle,
1677         int qop_req,
1678         const gss_buffer_t message_buffer,
1679         gss_buffer_t msg_token)
1680 {
1681         if (context_handle == GSS_C_NO_CONTEXT)
1682                 return (GSS_S_FAILURE);
1683         return (KGSS_SIGN(minor_status, context_handle, qop_req,
1684             message_buffer, msg_token));
1685 }
1686 
1687 /*ARGSUSED*/
1688 static OM_uint32
1689 kgss_verify_wrapped(void *private,
1690         OM_uint32 *minor_status,
1691         const gss_ctx_id_t ctx_handle,
1692         const gss_buffer_t message_buffer,
1693         const gss_buffer_t token_buffer,
1694         int *qop_state,
1695         OM_uint32 gssd_context_verifier)
1696 {
1697         CLIENT *clnt;
1698 
1699         gssd_ctx_id_t context_handle;
1700         gss_verify_arg arg;
1701         gss_verify_res res;
1702 
1703         context_handle = (gssd_ctx_id_t)KCTX_TO_GSSD_CTX(ctx_handle);
1704 
1705         /* get the client handle to GSSD */
1706 
1707         if ((clnt = getgssd_handle()) == NULL) {
1708                 GSSLOG(1, "kgss_verify: can't connect to server on %s\n",
1709                     server);
1710                 return (GSS_S_FAILURE);
1711         }
1712 
1713         /* copy the procedure arguments into the rpc arg parameter */
1714 
1715         arg.context_handle.GSS_CTX_ID_T_len = (uint_t)sizeof (gss_ctx_id_t);
1716         arg.context_handle.GSS_CTX_ID_T_val = (char *)&context_handle;
1717 
1718         arg.context_handle.GSS_CTX_ID_T_len = (uint_t)sizeof (gssd_ctx_id_t);
1719         arg.context_handle.GSS_CTX_ID_T_val = (char *)&context_handle;
1720         arg.gssd_context_verifier = gssd_context_verifier;
1721 
1722         arg.message_buffer.GSS_BUFFER_T_len = (uint_t)message_buffer->length;
1723         arg.message_buffer.GSS_BUFFER_T_val = (char *)message_buffer->value;
1724 
1725         arg.token_buffer.GSS_BUFFER_T_len = (uint_t)token_buffer->length;
1726         arg.token_buffer.GSS_BUFFER_T_val = (char *)token_buffer->value;
1727 
1728         /* call the remote procedure */
1729 
1730         bzero((caddr_t)&res, sizeof (res));
1731         if (gss_verify_1(&arg, &res, clnt) != RPC_SUCCESS) {
1732 
1733         /*
1734          * if the RPC call times out, null out all return arguments, set
1735          * minor_status to its maximum value, and return GSS_S_FAILURE
1736          */
1737 
1738                 if (minor_status != NULL)
1739                         *minor_status = DEFAULT_MINOR_STAT;
1740                 if (qop_state != NULL)
1741                         *qop_state = 0;
1742 
1743                 killgssd_handle(clnt);
1744                 GSSLOG0(1, "kgss_verify: RPC call times out\n");
1745                 return (GSS_S_FAILURE);
1746         }
1747 
1748         /* copy the rpc results into the return arguments */
1749 
1750         if (minor_status != NULL)
1751                 *minor_status = res.minor_status;
1752 
1753         if (qop_state != NULL)
1754                 *qop_state = res.qop_state;
1755 
1756         /* return with status returned in rpc call */
1757 
1758         killgssd_handle(clnt);
1759         return (res.status);
1760 
1761 }
1762 
1763 OM_uint32
1764 kgss_verify(OM_uint32 *minor_status,
1765                 const gss_ctx_id_t context_handle,
1766                 const gss_buffer_t message_buffer,
1767                 const gss_buffer_t token_buffer,
1768                 int *qop_state)
1769 {
1770         if (context_handle == GSS_C_NO_CONTEXT)
1771                 return (GSS_S_FAILURE);
1772         return (KGSS_VERIFY(minor_status, context_handle,
1773             message_buffer, token_buffer, qop_state));
1774 }
1775 
1776 /*ARGSUSED*/
1777 static OM_uint32
1778 kgss_seal_wrapped(void *private,
1779         OM_uint32 *minor_status,
1780         const gss_ctx_id_t ctx_handle,
1781         int conf_req_flag,
1782         int qop_req,
1783         const gss_buffer_t input_message_buffer,
1784         int *conf_state,
1785         gss_buffer_t output_message_buffer,
1786         OM_uint32 gssd_context_verifier)
1787 {
1788         CLIENT *clnt;
1789         gssd_ctx_id_t   context_handle;
1790 
1791         gss_seal_arg arg;
1792         gss_seal_res res;
1793 
1794         context_handle = (gssd_ctx_id_t)KCTX_TO_GSSD_CTX(ctx_handle);
1795 
1796         /* get the client handle to GSSD */
1797 
1798         if ((clnt = getgssd_handle()) == NULL) {
1799                 GSSLOG(1, "kgss_seal: can't connect to server on %s\n", server);
1800                 return (GSS_S_FAILURE);
1801         }
1802 
1803         /* copy the procedure arguments into the rpc arg parameter */
1804 
1805         arg.context_handle.GSS_CTX_ID_T_len = (uint_t)sizeof (gss_ctx_id_t);
1806         arg.context_handle.GSS_CTX_ID_T_val = (char *)&context_handle;
1807 
1808         arg.context_handle.GSS_CTX_ID_T_len = (uint_t)sizeof (OM_uint32);
1809         arg.context_handle.GSS_CTX_ID_T_val = (char *)&context_handle;
1810         arg.gssd_context_verifier = gssd_context_verifier;
1811 
1812         arg.conf_req_flag = conf_req_flag;
1813 
1814         arg.qop_req = qop_req;
1815 
1816         arg.input_message_buffer.GSS_BUFFER_T_len =
1817             (uint_t)input_message_buffer->length;
1818 
1819         arg.input_message_buffer.GSS_BUFFER_T_val =
1820             (char *)input_message_buffer->value;
1821 
1822         /* call the remote procedure */
1823 
1824         bzero((caddr_t)&res, sizeof (res));
1825         if (gss_seal_1(&arg, &res, clnt) != RPC_SUCCESS) {
1826 
1827         /*
1828          * if the RPC call times out, null out all return arguments, set
1829          * minor_status to its maximum value, and return GSS_S_FAILURE
1830          */
1831 
1832                 if (minor_status != NULL)
1833                         *minor_status = DEFAULT_MINOR_STAT;
1834                 if (conf_state != NULL)
1835                         *conf_state = 0;
1836                 if (output_message_buffer != NULL)
1837                         output_message_buffer->length = 0;
1838 
1839                 killgssd_handle(clnt);
1840                 GSSLOG0(1, "kgss_seal: RPC call times out\n");
1841                 return (GSS_S_FAILURE);
1842         }
1843 
1844         /* copy the rpc results into the return arguments */
1845 
1846         if (minor_status != NULL)
1847                 *minor_status = res.minor_status;
1848 
1849         if (conf_state != NULL)
1850                 *conf_state = res.conf_state;
1851 
1852         if (output_message_buffer != NULL) {
1853                 output_message_buffer->length =
1854                     res.output_message_buffer.GSS_BUFFER_T_len;
1855 
1856                 output_message_buffer->value =
1857                     (void *) MALLOC(output_message_buffer->length);
1858                 (void) memcpy(output_message_buffer->value,
1859                     res.output_message_buffer.GSS_BUFFER_T_val,
1860                     output_message_buffer->length);
1861         }
1862 
1863         /*
1864          * free the memory allocated for the results and return with the status
1865          * received in the rpc call
1866          */
1867 
1868         clnt_freeres(clnt, xdr_gss_seal_res, (caddr_t)&res);
1869         killgssd_handle(clnt);
1870         return (res.status);
1871 }
1872 
1873 /*ARGSUSED*/
1874 OM_uint32
1875 kgss_seal(OM_uint32 *minor_status,
1876         const gss_ctx_id_t context_handle,
1877         int conf_req_flag,
1878         int qop_req,
1879         const gss_buffer_t input_message_buffer,
1880         int *conf_state,
1881         gss_buffer_t output_message_buffer)
1882 
1883 {
1884         if (context_handle == GSS_C_NO_CONTEXT)
1885                 return (GSS_S_FAILURE);
1886         return (KGSS_SEAL(minor_status, context_handle,
1887                 conf_req_flag, qop_req,
1888                 input_message_buffer, conf_state,
1889                 output_message_buffer));
1890 }
1891 
1892 /*ARGSUSED*/
1893 static OM_uint32
1894 kgss_unseal_wrapped(void *private,
1895         OM_uint32 *minor_status,
1896         const gss_ctx_id_t ctx_handle,
1897         const gss_buffer_t input_message_buffer,
1898         gss_buffer_t output_message_buffer,
1899         int *conf_state,
1900         int *qop_state,
1901         OM_uint32 gssd_context_verifier)
1902 {
1903         CLIENT *clnt;
1904 
1905         gss_unseal_arg arg;
1906         gss_unseal_res res;
1907         gssd_ctx_id_t context_handle;
1908 
1909         context_handle = (gssd_ctx_id_t)KCTX_TO_GSSD_CTX(ctx_handle);
1910 
1911         /* get the client handle to GSSD */
1912 
1913         if ((clnt = getgssd_handle()) == NULL) {
1914                 GSSLOG(1, "kgss_unseal: can't connect to server on %s\n",
1915                     server);
1916                 return (GSS_S_FAILURE);
1917         }
1918 
1919         /* copy the procedure arguments into the rpc arg parameter */
1920 
1921         arg.context_handle.GSS_CTX_ID_T_len = (uint_t)sizeof (gss_ctx_id_t);
1922         arg.context_handle.GSS_CTX_ID_T_val = (char *)&context_handle;
1923 
1924         arg.context_handle.GSS_CTX_ID_T_len = (uint_t)sizeof (gssd_ctx_id_t);
1925         arg.context_handle.GSS_CTX_ID_T_val = (char *)&context_handle;
1926         arg.gssd_context_verifier = gssd_context_verifier;
1927 
1928         arg.input_message_buffer.GSS_BUFFER_T_len =
1929             (uint_t)input_message_buffer->length;
1930 
1931         arg.input_message_buffer.GSS_BUFFER_T_val =
1932             (char *)input_message_buffer->value;
1933 
1934         /* call the remote procedure */
1935 
1936         bzero((caddr_t)&res, sizeof (res));
1937         if (gss_unseal_1(&arg, &res, clnt) != RPC_SUCCESS) {
1938 
1939         /*
1940          * if the RPC call times out, null out all return arguments, set
1941          * minor_status to its maximum value, and return GSS_S_FAILURE
1942          */
1943 
1944                 if (minor_status != NULL)
1945                         *minor_status = DEFAULT_MINOR_STAT;
1946                 if (output_message_buffer != NULL)
1947                         output_message_buffer->length = 0;
1948                 if (conf_state != NULL)
1949                         *conf_state = 0;
1950                 if (qop_state != NULL)
1951                         *qop_state = 0;
1952 
1953                 killgssd_handle(clnt);
1954                 GSSLOG0(1, "kgss_unseal: RPC call times out\n");
1955                 return (GSS_S_FAILURE);
1956         }
1957 
1958         /* copy the rpc results into the return arguments */
1959 
1960         if (minor_status != NULL)
1961                 *minor_status = res.minor_status;
1962 
1963         if (output_message_buffer != NULL) {
1964                 output_message_buffer->length =
1965                     res.output_message_buffer.GSS_BUFFER_T_len;
1966 
1967                 output_message_buffer->value =
1968                     (void *) MALLOC(output_message_buffer->length);
1969                 (void) memcpy(output_message_buffer->value,
1970                     res.output_message_buffer.GSS_BUFFER_T_val,
1971                     output_message_buffer->length);
1972         }
1973 
1974         if (conf_state != NULL)
1975                 *conf_state = res.conf_state;
1976 
1977         if (qop_state != NULL)
1978                 *qop_state = res.qop_state;
1979 
1980         /*
1981          * free the memory allocated for the results and return with the
1982          * status received in the rpc call
1983          */
1984 
1985         clnt_freeres(clnt, xdr_gss_unseal_res, (caddr_t)&res);
1986         killgssd_handle(clnt);
1987         return (res.status);
1988 }
1989 
1990 OM_uint32
1991 kgss_unseal(OM_uint32 *minor_status,
1992         const gss_ctx_id_t context_handle,
1993         const gss_buffer_t input_message_buffer,
1994         const gss_buffer_t output_message_buffer,
1995         int *conf_state,
1996         int *qop_state)
1997 {
1998 
1999         if (context_handle == GSS_C_NO_CONTEXT)
2000                 return (GSS_S_FAILURE);
2001 
2002         return (KGSS_UNSEAL(minor_status, context_handle, input_message_buffer,
2003             output_message_buffer, conf_state, qop_state));
2004 }
2005 
2006 OM_uint32
2007 kgss_display_status(minor_status,
2008                 status_value,
2009                 status_type,
2010                 mech_type,
2011                 message_context,
2012                 status_string,
2013                 uid)
2014         OM_uint32 *minor_status;
2015         OM_uint32 status_value;
2016         int status_type;
2017         const gss_OID mech_type;
2018         int *message_context;
2019         gss_buffer_t status_string;
2020         uid_t uid;
2021 {
2022         CLIENT *clnt;
2023 
2024         gss_display_status_arg arg;
2025         gss_display_status_res res;
2026 
2027         /* get the client handle to GSSD */
2028 
2029         if ((clnt = getgssd_handle()) == NULL) {
2030         GSSLOG(1, "kgss_display_status: can't connect to server on %s\n",
2031                         server);
2032                 return (GSS_S_FAILURE);
2033         }
2034 
2035         /* copy the procedure arguments into the rpc arg parameter */
2036 
2037         arg.uid = (OM_uint32) uid;
2038 
2039         arg.status_value = status_value;
2040         arg.status_type = status_type;
2041 
2042         arg.mech_type.GSS_OID_len = (uint_t)(mech_type != GSS_C_NULL_OID ?
2043                                                 mech_type->length : 0);
2044         arg.mech_type.GSS_OID_val = (char *)(mech_type != GSS_C_NULL_OID ?
2045                                                 mech_type->elements : 0);
2046 
2047         arg.message_context = *message_context;
2048 
2049         /* call the remote procedure */
2050 
2051         if (message_context != NULL)
2052                 *message_context = 0;
2053         if (status_string != NULL) {
2054                 status_string->length = 0;
2055                 status_string->value = NULL;
2056         }
2057 
2058         bzero((caddr_t)&res, sizeof (res));
2059         if (gss_display_status_1(&arg, &res, clnt) != RPC_SUCCESS) {
2060 
2061         /*
2062          * if the RPC call times out, null out all return arguments, set
2063          * minor_status to its maximum value, and return GSS_S_FAILURE
2064          */
2065 
2066                 if (minor_status != NULL)
2067                         *minor_status = DEFAULT_MINOR_STAT;
2068 
2069                 killgssd_handle(clnt);
2070                 GSSLOG0(1, "kgss_display_status: RPC call time out\n");
2071                 return (GSS_S_FAILURE);
2072         }
2073 
2074 
2075         /* now process the results and pass them back to the caller */
2076 
2077         if (res.status == GSS_S_COMPLETE) {
2078                 if (minor_status != NULL)
2079                         *minor_status = res.minor_status;
2080                 if (message_context != NULL)
2081                         *message_context = res.message_context;
2082                 if (status_string != NULL) {
2083                         status_string->length =
2084                                 (size_t)res.status_string.GSS_BUFFER_T_len;
2085                         status_string->value =
2086                                 (void *) MALLOC(status_string->length);
2087                         (void) memcpy(status_string->value,
2088                                 res.status_string.GSS_BUFFER_T_val,
2089                                 status_string->length);
2090                 }
2091         }
2092 
2093         clnt_freeres(clnt, xdr_gss_display_status_res, (caddr_t)&res);
2094         killgssd_handle(clnt);
2095         return (res.status);
2096 }
2097 
2098 /*ARGSUSED*/
2099 OM_uint32
2100 kgss_indicate_mechs(minor_status,
2101                         mech_set,
2102                         uid)
2103         OM_uint32 *minor_status;
2104         gss_OID_set *mech_set;
2105         uid_t uid;
2106 {
2107         CLIENT *clnt;
2108         void *arg;
2109         gss_indicate_mechs_res res;
2110         int i;
2111 
2112         /* get the client handle to GSSD */
2113 
2114         if ((clnt = getgssd_handle()) == NULL) {
2115         GSSLOG(1, "kgss_indicate_mechs: can't connect to server on %s\n",
2116                         server);
2117                 return (GSS_S_FAILURE);
2118         }
2119 
2120         bzero((caddr_t)&res, sizeof (res));
2121         if (gss_indicate_mechs_1(&arg, &res, clnt) != RPC_SUCCESS) {
2122 
2123         /*
2124          * if the RPC call times out, null out all return arguments, set
2125          * minor_status to its maximum value, and return GSS_S_FAILURE
2126          */
2127 
2128                 if (minor_status != NULL)
2129                         *minor_status = DEFAULT_MINOR_STAT;
2130                 if (mech_set != NULL)
2131                         *mech_set = NULL;
2132 
2133                 killgssd_handle(clnt);
2134                 GSSLOG0(1, "kgss_indicate_mechs: RPC call times out\n");
2135                 return (GSS_S_FAILURE);
2136         }
2137 
2138         /* copy the rpc results into the return arguments */
2139 
2140         if (minor_status != NULL)
2141                 *minor_status = res.minor_status;
2142 
2143         if (mech_set != NULL) {
2144                 *mech_set = (gss_OID_set) MALLOC(sizeof (gss_OID_set_desc));
2145                 (*mech_set)->count = res.mech_set.GSS_OID_SET_len;
2146                 (*mech_set)->elements = (void *)
2147                         MALLOC ((*mech_set)->count * sizeof (gss_OID_desc));
2148                 for (i = 0; i < (*mech_set)->count; i++) {
2149                         (*mech_set)->elements[i].length =
2150                                 res.mech_set.GSS_OID_SET_val[i].GSS_OID_len;
2151                         (*mech_set)->elements[i].elements = (void *)
2152                                 MALLOC ((*mech_set)->elements[i].length);
2153                         (void) memcpy((*mech_set)->elements[i].elements,
2154                                 res.mech_set.GSS_OID_SET_val[i].GSS_OID_val,
2155                                 (*mech_set)->elements[i].length);
2156                 }
2157         }
2158 
2159         /*
2160          * free the memory allocated for the results and return with the status
2161          * received in the rpc call
2162          */
2163 
2164         clnt_freeres(clnt, xdr_gss_indicate_mechs_res, (caddr_t)&res);
2165         killgssd_handle(clnt);
2166         return (res.status);
2167 }
2168 
2169 
2170 OM_uint32
2171 kgss_inquire_cred_wrapped(minor_status,
2172                 cred_handle,
2173                 gssd_cred_verifier,
2174                 name,
2175                 lifetime,
2176                 cred_usage,
2177                 mechanisms,
2178                 uid)
2179         OM_uint32 *minor_status;
2180         const gssd_cred_id_t cred_handle;
2181         OM_uint32 gssd_cred_verifier;
2182         gss_name_t *name;
2183         OM_uint32 *lifetime;
2184         int *cred_usage;
2185         gss_OID_set *mechanisms;
2186         uid_t uid;
2187 {
2188         CLIENT *clnt;
2189 
2190         OM_uint32       minor_status_temp;
2191         gss_buffer_desc external_name;
2192         gss_OID_desc    name_type;
2193         int             i;
2194 
2195         gss_inquire_cred_arg arg;
2196         gss_inquire_cred_res res;
2197 
2198         /*
2199          * NULL the params here once
2200          * If there are errors then we won't
2201          * have to do it for every error
2202          * case
2203          */
2204         if (minor_status != NULL)
2205                 *minor_status = DEFAULT_MINOR_STAT;
2206         if (name != NULL)
2207                 *name = NULL;
2208         if (lifetime != NULL)
2209                 *lifetime = 0;
2210         if (cred_usage != NULL)
2211                 *cred_usage = 0;
2212         if (mechanisms != NULL)
2213                 *mechanisms = NULL;
2214 
2215         /* get the client handle to GSSD */
2216 
2217         if ((clnt = getgssd_handle()) == NULL) {
2218                 GSSLOG(1, "kgss_inquire_cred: can't connect to server on %s\n",
2219                         server);
2220                 return (GSS_S_FAILURE);
2221         }
2222 
2223 
2224         /* copy the procedure arguments into the rpc arg parameter */
2225 
2226         arg.uid = (OM_uint32) uid;
2227 
2228         arg.cred_handle.GSS_CRED_ID_T_len =
2229             cred_handle == GSSD_NO_CREDENTIAL ?
2230             0 : (uint_t)sizeof (gssd_cred_id_t);
2231         arg.cred_handle.GSS_CRED_ID_T_val = (char *)&cred_handle;
2232         arg.gssd_cred_verifier = gssd_cred_verifier;
2233 
2234         /* call the remote procedure */
2235 
2236         bzero((caddr_t)&res, sizeof (res));
2237         if (gss_inquire_cred_1(&arg, &res, clnt) != RPC_SUCCESS) {
2238 
2239                 /*
2240                  * if the RPC call times out
2241                  * kill the handle and return GSS_S_FAILURE
2242                  * the parameters have been set to NULL already
2243                  */
2244 
2245                 killgssd_handle(clnt);
2246                 GSSLOG0(1, "kgss_inquire_cred: RPC call times out\n");
2247                 return (GSS_S_FAILURE);
2248         }
2249 
2250         /* copy the rpc results into the return arguments */
2251 
2252         if (minor_status != NULL)
2253                 *minor_status = res.minor_status;
2254 
2255         /* convert name from external to internal format */
2256 
2257         if (name != NULL) {
2258                 external_name.length = res.name.GSS_BUFFER_T_len;
2259                 external_name.value = res.name.GSS_BUFFER_T_val;
2260 
2261                 /*
2262                  * we can pass a pointer to res structure
2263                  * since gss_import_name treats the name_type
2264                  * parameter as read only and performs a copy
2265                  */
2266 
2267                 name_type.length = res.name_type.GSS_OID_len;
2268                 name_type.elements = (void *)res.name_type.GSS_OID_val;
2269 
2270                 if (gss_import_name(&minor_status_temp, &external_name,
2271                         &name_type, name) != GSS_S_COMPLETE) {
2272 
2273                         *minor_status = (OM_uint32) minor_status_temp;
2274                         clnt_freeres(clnt, xdr_gss_inquire_cred_res,
2275                                                         (caddr_t)&res);
2276                         killgssd_handle(clnt);
2277                         GSSLOG0(1, "kgss_inquire_cred: import name fails\n");
2278                         return ((OM_uint32) GSS_S_FAILURE);
2279                 }
2280         }
2281 
2282         if (lifetime != NULL)
2283                 *lifetime = res.lifetime;
2284 
2285         if (cred_usage != NULL)
2286                 *cred_usage = res.cred_usage;
2287 
2288         if (res.status == GSS_S_COMPLETE &&
2289                 res.mechanisms.GSS_OID_SET_len != 0 &&
2290                 mechanisms != NULL) {
2291                 *mechanisms = (gss_OID_set) MALLOC(sizeof (gss_OID_set_desc));
2292                 (*mechanisms)->count =
2293                         (int)res.mechanisms.GSS_OID_SET_len;
2294                 (*mechanisms)->elements = (gss_OID)
2295                         MALLOC(sizeof (gss_OID_desc) * (*mechanisms)->count);
2296 
2297                 for (i = 0; i < (*mechanisms)->count; i++) {
2298                     (*mechanisms)->elements[i].length = (OM_uint32)
2299                         res.mechanisms.GSS_OID_SET_val[i].GSS_OID_len;
2300                     (*mechanisms)->elements[i].elements =
2301                         (void *) MALLOC((*mechanisms)->elements[i].length);
2302                     (void) memcpy((*mechanisms)->elements[i].elements,
2303                         res.mechanisms.GSS_OID_SET_val[i].GSS_OID_val,
2304                         (*mechanisms)->elements[i].length);
2305                 }
2306         } else {
2307                 if (res.status == GSS_S_COMPLETE &&
2308                         mechanisms != NULL)
2309                         (*mechanisms) = NULL;
2310         }
2311         /*
2312          * free the memory allocated for the results and return with the status
2313          * received in the rpc call
2314          */
2315 
2316         clnt_freeres(clnt, xdr_gss_inquire_cred_res, (caddr_t)&res);
2317         killgssd_handle(clnt);
2318         return (res.status);
2319 
2320 }
2321 
2322 OM_uint32
2323 kgss_inquire_cred(minor_status,
2324                         cred_handle,
2325                         name,
2326                         lifetime,
2327                         cred_usage,
2328                         mechanisms,
2329                         uid)
2330         OM_uint32 *minor_status;
2331         const gss_cred_id_t cred_handle;
2332         gss_name_t *name;
2333         OM_uint32 *lifetime;
2334         int *cred_usage;
2335         gss_OID_set * mechanisms;
2336         uid_t uid;
2337 {
2338 
2339         OM_uint32 gssd_cred_verifier;
2340         OM_uint32 gssd_cred_handle;
2341 
2342         gssd_cred_verifier = KCRED_TO_CREDV(cred_handle);
2343         gssd_cred_handle = KCRED_TO_CRED(cred_handle);
2344 
2345         return (kgss_inquire_cred_wrapped(minor_status,
2346                         gssd_cred_handle, gssd_cred_verifier,
2347                         name, lifetime, cred_usage, mechanisms, uid));
2348 }
2349 
2350 OM_uint32
2351 kgss_inquire_cred_by_mech_wrapped(minor_status,
2352                 cred_handle,
2353                 gssd_cred_verifier,
2354                 mech_type,
2355                 uid)
2356         OM_uint32 *minor_status;
2357         gssd_cred_id_t cred_handle;
2358         OM_uint32 gssd_cred_verifier;
2359         gss_OID mech_type;
2360         uid_t uid;
2361 {
2362         CLIENT *clnt;
2363 
2364         gss_inquire_cred_by_mech_arg arg;
2365         gss_inquire_cred_by_mech_res res;
2366 
2367         /* get the client handle to GSSD */
2368 
2369         if ((clnt = getgssd_handle()) == NULL) {
2370                 GSSLOG(1, "kgss_inquire_cred: can't connect to server on %s\n",
2371                         server);
2372                 return (GSS_S_FAILURE);
2373         }
2374 
2375 
2376         /* copy the procedure arguments into the rpc arg parameter */
2377 
2378         arg.uid = (OM_uint32) uid;
2379 
2380         arg.cred_handle.GSS_CRED_ID_T_len =
2381             cred_handle == GSSD_NO_CREDENTIAL ?
2382             0 : (uint_t)sizeof (gssd_cred_id_t);
2383         arg.cred_handle.GSS_CRED_ID_T_val = (char *)&cred_handle;
2384         arg.gssd_cred_verifier = gssd_cred_verifier;
2385 
2386         arg.mech_type.GSS_OID_len =
2387                 (uint_t)(mech_type != GSS_C_NULL_OID ?
2388                 mech_type->length : 0);
2389         arg.mech_type.GSS_OID_val =
2390                 (char *)(mech_type != GSS_C_NULL_OID ?
2391                 mech_type->elements : 0);
2392         /* call the remote procedure */
2393 
2394         bzero((caddr_t)&res, sizeof (res));
2395         if (gss_inquire_cred_by_mech_1(&arg, &res, clnt) != RPC_SUCCESS) {
2396 
2397         /*
2398          * if the RPC call times out, null out all return arguments, set
2399          * minor_status to its maximum value, and return GSS_S_FAILURE
2400          */
2401 
2402                 if (minor_status != NULL)
2403                         *minor_status = DEFAULT_MINOR_STAT;
2404                 killgssd_handle(clnt);
2405                 GSSLOG0(1, "kgss_inquire_cred: RPC call times out\n");
2406                 return (GSS_S_FAILURE);
2407         }
2408 
2409         /* copy the rpc results into the return arguments */
2410 
2411         if (minor_status != NULL)
2412                 *minor_status = res.minor_status;
2413 
2414         clnt_freeres(clnt, xdr_gss_inquire_cred_by_mech_res, (caddr_t)&res);
2415         killgssd_handle(clnt);
2416         return (res.status);
2417 
2418 }
2419 
2420 OM_uint32
2421 kgss_inquire_cred_by_mech(minor_status,
2422                         cred_handle,
2423                         mech_type,
2424                         uid)
2425         OM_uint32 *minor_status;
2426         gss_cred_id_t cred_handle;
2427         gss_OID mech_type;
2428         uid_t uid;
2429 {
2430 
2431         OM_uint32 gssd_cred_verifier;
2432         OM_uint32 gssd_cred_handle;
2433 
2434         gssd_cred_verifier = KCRED_TO_CREDV(cred_handle);
2435         gssd_cred_handle = KCRED_TO_CRED(cred_handle);
2436 
2437         return (kgss_inquire_cred_by_mech_wrapped(minor_status,
2438                         gssd_cred_handle, gssd_cred_verifier,
2439                         mech_type, uid));
2440 }
2441 
2442 OM_uint32
2443 kgsscred_expname_to_unix_cred(expName, uidOut, gidOut, gids, gidsLen, uid)
2444         const gss_buffer_t expName;
2445         uid_t *uidOut;
2446         gid_t *gidOut;
2447         gid_t *gids[];
2448         int *gidsLen;
2449         uid_t uid;
2450 {
2451         CLIENT *clnt;
2452         gsscred_expname_to_unix_cred_arg args;
2453         gsscred_expname_to_unix_cred_res res;
2454 
2455         /* check input/output parameters */
2456         if (expName == NULL || expName->value == NULL)
2457                 return (GSS_S_CALL_INACCESSIBLE_READ);
2458 
2459         if (uidOut == NULL)
2460                 return (GSS_S_CALL_INACCESSIBLE_WRITE);
2461 
2462         /* NULL out output parameters */
2463         *uidOut = UID_NOBODY;
2464         if (gidsLen)
2465                 *gidsLen = 0;
2466 
2467         if (gids)
2468                 *gids = NULL;
2469 
2470         /* get the client handle to gssd */
2471         if ((clnt = getgssd_handle()) == NULL)
2472         {
2473                 GSSLOG(1, "kgsscred_expname_to_unix_cred:"
2474                         " can't connect to server on %s\n", server);
2475                 return (GSS_S_FAILURE);
2476         }
2477 
2478         /* copy the procedure arguments */
2479         args.uid = uid;
2480         args.expname.GSS_BUFFER_T_val = expName->value;
2481         args.expname.GSS_BUFFER_T_len = expName->length;
2482 
2483         /* null out the return buffer and call the remote proc */
2484         bzero(&res, sizeof (res));
2485 
2486         if (gsscred_expname_to_unix_cred_1(&args, &res, clnt) != RPC_SUCCESS)
2487         {
2488                 killgssd_handle(clnt);
2489                 GSSLOG0(1,
2490                         "kgsscred_expname_to_unix_cred: RPC call times out\n");
2491                 return (GSS_S_FAILURE);
2492         }
2493 
2494         /* copy the results into the result parameters */
2495         if (res.major == GSS_S_COMPLETE)
2496         {
2497                 *uidOut = res.uid;
2498                 if (gidOut)
2499                         *gidOut = res.gid;
2500                 if (gids && gidsLen)
2501                 {
2502                         *gids = res.gids.GSSCRED_GIDS_val;
2503                         *gidsLen = res.gids.GSSCRED_GIDS_len;
2504                         res.gids.GSSCRED_GIDS_val = NULL;
2505                         res.gids.GSSCRED_GIDS_len = 0;
2506                 }
2507         }
2508 
2509         /* free RPC results */
2510         clnt_freeres(clnt, xdr_gsscred_expname_to_unix_cred_res, (caddr_t)&res);
2511         killgssd_handle(clnt);
2512 
2513         return (res.major);
2514 } /* kgsscred_expname_to_unix_cred */
2515 
2516 OM_uint32
2517 kgsscred_name_to_unix_cred(intName, mechType, uidOut, gidOut, gids,
2518                                 gidsLen, uid)
2519         const gss_name_t intName;
2520         const gss_OID mechType;
2521         uid_t *uidOut;
2522         gid_t *gidOut;
2523         gid_t *gids[];
2524         int *gidsLen;
2525         uid_t uid;
2526 {
2527         CLIENT *clnt;
2528         gsscred_name_to_unix_cred_arg args;
2529         gsscred_name_to_unix_cred_res res;
2530         OM_uint32 major, minor;
2531         gss_OID nameOid;
2532         gss_buffer_desc flatName = GSS_C_EMPTY_BUFFER;
2533 
2534         /* check the input/output parameters */
2535         if (intName == NULL || mechType == NULL)
2536                 return (GSS_S_CALL_INACCESSIBLE_READ);
2537 
2538         if (uidOut == NULL)
2539                 return (GSS_S_CALL_INACCESSIBLE_WRITE);
2540 
2541         /* NULL out the output parameters */
2542         *uidOut = UID_NOBODY;
2543         if (gids)
2544                 *gids = NULL;
2545 
2546         if (gidsLen)
2547                 *gidsLen = 0;
2548 
2549         /* get the client handle to gssd */
2550         if ((clnt = getgssd_handle()) == NULL)
2551         {
2552                 GSSLOG(1,
2553                 "kgsscred_name_to_unix_cred: can't connect to server %s\n",
2554                                 server);
2555                 return (GSS_S_FAILURE);
2556         }
2557 
2558         /* convert the name to flat representation */
2559         if ((major = gss_display_name(&minor, intName, &flatName, &nameOid))
2560                         != GSS_S_COMPLETE)
2561         {
2562                 killgssd_handle(clnt);
2563                 GSSLOG0(1, "kgsscred_name_to_unix_cred: display name failed\n");
2564                 return (major);
2565         }
2566 
2567         /* set the rpc parameters */
2568         args.uid = uid;
2569         args.pname.GSS_BUFFER_T_len = flatName.length;
2570         args.pname.GSS_BUFFER_T_val = flatName.value;
2571         args.name_type.GSS_OID_len = nameOid->length;
2572         args.name_type.GSS_OID_val = nameOid->elements;
2573         args.mech_type.GSS_OID_len = mechType->length;
2574         args.mech_type.GSS_OID_val = mechType->elements;
2575 
2576         /* call the remote procedure */
2577         bzero(&res, sizeof (res));
2578         if (gsscred_name_to_unix_cred_1(&args, &res, clnt) != RPC_SUCCESS) {
2579                 killgssd_handle(clnt);
2580                 (void) gss_release_buffer(&minor, &flatName);
2581                 GSSLOG0(1, "kgsscred_name_to_unix_cred: RPC call times out\n");
2582                 return (GSS_S_FAILURE);
2583         }
2584 
2585         /* delete the flat name buffer */
2586         (void) gss_release_buffer(&minor, &flatName);
2587 
2588         /* copy the output parameters on output */
2589         if (res.major == GSS_S_COMPLETE) {
2590                 *uidOut = res.uid;
2591 
2592                 if (gidOut)
2593                         *gidOut = res.gid;
2594                 if (gids && gidsLen) {
2595                         *gids = res.gids.GSSCRED_GIDS_val;
2596                         *gidsLen = res.gids.GSSCRED_GIDS_len;
2597                         res.gids.GSSCRED_GIDS_val = NULL;
2598                         res.gids.GSSCRED_GIDS_len = 0;
2599                 }
2600         }
2601 
2602         /* delete RPC allocated memory */
2603         clnt_freeres(clnt, xdr_gsscred_name_to_unix_cred_res, (caddr_t)&res);
2604         killgssd_handle(clnt);
2605 
2606         return (res.major);
2607 } /* kgsscred_name_to_unix_cred */
2608 
2609 OM_uint32
2610 kgss_get_group_info(puid, gidOut, gids, gidsLen, uid)
2611         const uid_t puid;
2612         gid_t *gidOut;
2613         gid_t *gids[];
2614         int *gidsLen;
2615         uid_t uid;
2616 {
2617         CLIENT *clnt;
2618         gss_get_group_info_arg args;
2619         gss_get_group_info_res res;
2620 
2621 
2622         /* check the output parameters */
2623         if (gidOut == NULL || gids == NULL || gidsLen == NULL)
2624                 return (GSS_S_CALL_INACCESSIBLE_WRITE);
2625 
2626         /* get the client GSSD handle */
2627         if ((clnt = getgssd_handle()) == NULL) {
2628                 GSSLOG(1,
2629                         "kgss_get_group_info: can't connect to server on %s\n",
2630                         server);
2631                 return (GSS_S_FAILURE);
2632         }
2633 
2634         /* set the input parameters */
2635         args.uid = uid;
2636         args.puid = puid;
2637 
2638         /* call the remote procedure */
2639         bzero(&res, sizeof (res));
2640         if (gss_get_group_info_1(&args, &res, clnt) != RPC_SUCCESS) {
2641                 killgssd_handle(clnt);
2642                 GSSLOG0(1, "kgss_get_group_info: RPC call times out\n");
2643                 return (GSS_S_FAILURE);
2644         }
2645 
2646         /* copy the results */
2647         if (res.major == GSS_S_COMPLETE) {
2648                 *gidOut = res.gid;
2649                 *gids = res.gids.GSSCRED_GIDS_val;
2650                 *gidsLen = res.gids.GSSCRED_GIDS_len;
2651                 res.gids.GSSCRED_GIDS_val = NULL;
2652                 res.gids.GSSCRED_GIDS_len = 0;
2653         }
2654 
2655         /* no results to free */
2656         killgssd_handle(clnt);
2657 
2658         return (res.major);
2659 } /* kgss_get_group_info */
2660 
2661 static char *
2662 kgss_get_kmod(gss_OID mech_oid)
2663 {
2664         CLIENT *clnt;
2665         gss_get_kmod_arg args;
2666         gss_get_kmod_res res;
2667 
2668 
2669         /* get the client GSSD handle */
2670         if ((clnt = getgssd_handle()) == NULL) {
2671                 GSSLOG(1, "kgss_get_kmod: can't connect to server on %s\n",
2672                     server);
2673                 return (NULL);
2674         }
2675 
2676         /* set the input parameters */
2677         args.mech_oid.GSS_OID_len = mech_oid->length;
2678         args.mech_oid.GSS_OID_val = mech_oid->elements;
2679 
2680         /* call the remote procedure */
2681         bzero(&res, sizeof (res));
2682         if (gss_get_kmod_1(&args, &res, clnt) != RPC_SUCCESS) {
2683                 killgssd_handle(clnt);
2684                 GSSLOG0(1, "gss_get_kmod_1: RPC call times out\n");
2685                 return (NULL);
2686         }
2687         /* no results to free */
2688         killgssd_handle(clnt);
2689 
2690         if (res.module_follow == TRUE) {
2691                 return (res.gss_get_kmod_res_u.modname);
2692         } else
2693                 return (NULL);
2694 } /* kgss_get_kmod */
2695 
2696 static gss_mechanism    kgss_mech_head;
2697 static gss_mechanism    kgss_mech_tail;
2698 kmutex_t        __kgss_mech_lock;
2699 
2700 /*
2701  * See if there is kernel mechanism module, and if so, attempt to
2702  * load it and reset the pointer (gss_mechanism) to the sign/seal/etc.
2703  * entry points to that of the kernel module.
2704  */
2705 static void
2706 __kgss_reset_mech(gss_mechanism *mechp, gss_OID mech_oid)
2707 {
2708         gss_mechanism mech;
2709         char *kmod;
2710 
2711         /*
2712          * We can search the list without a mutex, becuase the list never
2713          * shrinks and we always add to the end.
2714          */
2715         mech = __kgss_get_mechanism(mech_oid);
2716         if (mech) {
2717                 *mechp = mech;
2718                 return;
2719         }
2720 
2721         /*
2722          * Get the module name from the kernel.
2723          */
2724         kmod = kgss_get_kmod(mech_oid);
2725 
2726         if (kmod) {
2727                 extern int modload(const char *, const char *);
2728                 if (modload("misc/kgss", kmod) < 0) {
2729                         /*
2730                          * Modload of 'kmod' failed, so log an
2731                          * appropriate comment
2732                          */
2733                         cmn_err(CE_NOTE, "kgss_reset_mech: Algorithm modload "
2734                             "(%s) failed. Userland gssd will now handle "
2735                             "all GSSAPI calls, which may result in "
2736                             "reduced performance.\n", kmod);
2737                 };
2738 
2739                 /*
2740                  * Allocated in the XDR routine called by gss_get_kmod_1().
2741                  */
2742                 FREE(kmod, strlen(kmod)+1);
2743 
2744                 mech = __kgss_get_mechanism(mech_oid);
2745                 if (mech) {
2746                         *mechp = mech;
2747                 }
2748 
2749                 /*
2750                  * If for some reason the module load didn't take,
2751                  * we return anyway and hope that the next context
2752                  * creation succeeds.
2753                  */
2754                 return;
2755         }
2756 
2757 
2758         /*
2759          * No kernel module, so enter this mech oid into the list
2760          * using the default sign/seal/etc. operations that upcall to
2761          * gssd.
2762          */
2763         mutex_enter(&__kgss_mech_lock);
2764         mech = __kgss_get_mechanism(mech_oid);
2765         if (mech) {
2766                 mutex_exit(&__kgss_mech_lock);
2767                 *mechp = mech;
2768                 return;
2769         }
2770 
2771         /*
2772          * Allocate space for the mechanism entry.
2773          */
2774         mech = kmem_zalloc(sizeof (struct gss_config), KM_SLEEP);
2775 
2776         /*
2777          * Copy basic information from default mechanism struct.
2778          */
2779         *mech = default_gc;
2780 
2781         /*
2782          * Record the real mech OID.
2783          */
2784         mech->mech_type.length = mech_oid->length;
2785         mech->mech_type.elements = MALLOC(mech_oid->length);
2786         bcopy(mech_oid->elements,  mech->mech_type.elements, mech_oid->length);
2787 
2788         /*
2789          * Add it to the table.
2790          */
2791         __kgss_add_mechanism(mech);
2792         mutex_exit(&__kgss_mech_lock);
2793         *mechp = mech;
2794 }
2795 
2796 /*
2797  * Called with __kgss_mech_lock held.
2798  */
2799 void
2800 __kgss_add_mechanism(gss_mechanism mech)
2801 {
2802         gss_mechanism tmp;
2803 
2804         tmp = kgss_mech_tail;
2805         kgss_mech_tail = mech;
2806 
2807         if (tmp != NULL)
2808                 tmp->next = mech;
2809 
2810         if (kgss_mech_head == NULL)
2811                 kgss_mech_head = mech;
2812 }
2813 
2814 /*
2815  *  given the mechs_array and a mechanism OID, return the
2816  *  pointer to the mechanism, or NULL if that mechanism is
2817  *  not supported.
2818  */
2819 gss_mechanism
2820 __kgss_get_mechanism(gss_OID type)
2821 {
2822         gss_mechanism mech;
2823 
2824         mech = kgss_mech_head;
2825 
2826         /*
2827          * Note that a reader can scan this list without the mutex held.
2828          * This is safe because we always append, and never shrink the list.
2829          * Moreover, the entry is fully initialized before it is ever
2830          * added to the list.
2831          */
2832         while (mech != NULL) {
2833                 if ((mech->mech_type.length == type->length) &&
2834                     (bcmp(mech->mech_type.elements, type->elements,
2835                     type->length) == 0))
2836                         return (mech);
2837 
2838                 mech = mech->next;
2839         }
2840         return (NULL);
2841 }