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, Version 1.0 only
   6  * (the "License").  You may not use this file except in compliance
   7  * with the License.
   8  *
   9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  10  * or http://www.opensolaris.org/os/licensing.
  11  * See the License for the specific language governing permissions
  12  * and limitations under the License.
  13  *
  14  * When distributing Covered Code, include this CDDL HEADER in each
  15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  16  * If applicable, add the following below this CDDL HEADER, with the
  17  * fields enclosed by brackets "[]" replaced with your own identifying
  18  * information: Portions Copyright [yyyy] [name of copyright owner]
  19  *
  20  * CDDL HEADER END
  21  */
  22 /*
  23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
  24  * Use is subject to license terms.
  25  */
  26 
  27 #pragma ident   "%Z%%M% %I%     %E% SMI"
  28 
  29 /*
  30  *  glue routine for gss_accept_sec_context
  31  */
  32 
  33 #include <mechglueP.h>
  34 #ifdef HAVE_STDLIB_H
  35 #include <stdlib.h>
  36 #endif
  37 #include <string.h>
  38 #include <errno.h>
  39 
  40 OM_uint32
  41 gss_accept_sec_context(minor_status,
  42                         context_handle,
  43                         verifier_cred_handle,
  44                         input_token_buffer,
  45                         input_chan_bindings,
  46                         src_name,
  47                         mech_type,
  48                         output_token,
  49                         ret_flags,
  50                         time_rec,
  51                         d_cred)
  52 
  53 OM_uint32                       *minor_status;
  54 gss_ctx_id_t                    *context_handle;
  55 const gss_cred_id_t             verifier_cred_handle;
  56 const gss_buffer_t              input_token_buffer;
  57 const gss_channel_bindings_t    input_chan_bindings;
  58 gss_name_t                      *src_name;
  59 gss_OID                         *mech_type;
  60 gss_buffer_t                    output_token;
  61 OM_uint32                       *ret_flags;
  62 OM_uint32                       *time_rec;
  63 gss_cred_id_t                   *d_cred; /* delegated cred handle */
  64 
  65 {
  66         OM_uint32               status, temp_status, t_minstat;
  67         gss_union_ctx_id_t      union_ctx_id;
  68         gss_union_cred_t        union_cred;
  69         gss_cred_id_t   input_cred_handle = GSS_C_NO_CREDENTIAL;
  70         gss_cred_id_t   tmp_d_cred = GSS_C_NO_CREDENTIAL;
  71         gss_name_t              internal_name = GSS_C_NO_NAME;
  72         gss_name_t              tmp_src_name = GSS_C_NO_NAME;
  73         gss_OID_desc    token_mech_type_desc;
  74         gss_OID         token_mech_type = &token_mech_type_desc;
  75         gss_OID         actual_mech = GSS_C_NO_OID;
  76         OM_uint32       flags;
  77         gss_mechanism   mech;
  78 
  79         /* check parameters first */
  80         if (minor_status == NULL)
  81                 return (GSS_S_CALL_INACCESSIBLE_WRITE);
  82         *minor_status = 0;
  83 
  84         if (context_handle == NULL || output_token == NULL)
  85                 return (GSS_S_CALL_INACCESSIBLE_WRITE);
  86 
  87         /* clear optional fields */
  88         output_token->value = NULL;
  89         output_token->length = 0;
  90         if (src_name)
  91                 *src_name = NULL;
  92 
  93         if (mech_type)
  94                 *mech_type = NULL;
  95 
  96         if (d_cred)
  97                 *d_cred = NULL;
  98         /*
  99          * if context_handle is GSS_C_NO_CONTEXT, allocate a union context
 100          * descriptor to hold the mech type information as well as the
 101          * underlying mechanism context handle. Otherwise, cast the
 102          * value of *context_handle to the union context variable.
 103          */
 104 
 105         if (*context_handle == GSS_C_NO_CONTEXT) {
 106 
 107                 if (GSS_EMPTY_BUFFER(input_token_buffer))
 108                         return (GSS_S_CALL_INACCESSIBLE_READ);
 109 
 110                 /* Get the token mech type */
 111                 status = __gss_get_mech_type(token_mech_type,
 112                                         input_token_buffer);
 113 
 114                 if (status)
 115                         return (status);
 116 
 117                 status = GSS_S_FAILURE;
 118                 union_ctx_id = (gss_union_ctx_id_t)
 119                         malloc(sizeof (gss_union_ctx_id_desc));
 120                 if (!union_ctx_id)
 121                         return (GSS_S_FAILURE);
 122 
 123                 union_ctx_id->internal_ctx_id = GSS_C_NO_CONTEXT;
 124                 status = generic_gss_copy_oid(&t_minstat,
 125                                         token_mech_type,
 126                                         &union_ctx_id->mech_type);
 127                 if (status != GSS_S_COMPLETE) {
 128                         free(union_ctx_id);
 129                         return (status);
 130                 }
 131 
 132                 /* set the new context handle to caller's data */
 133                 *context_handle = (gss_ctx_id_t)union_ctx_id;
 134         } else {
 135                 union_ctx_id = (gss_union_ctx_id_t)*context_handle;
 136                 token_mech_type = union_ctx_id->mech_type;
 137         }
 138 
 139         /*
 140          * get the appropriate cred handle from the union cred struct.
 141          * defaults to GSS_C_NO_CREDENTIAL if there is no cred, which will
 142          * use the default credential.
 143          */
 144         union_cred = (gss_union_cred_t)verifier_cred_handle;
 145         input_cred_handle = __gss_get_mechanism_cred(union_cred,
 146                                                 token_mech_type);
 147 
 148         /*
 149          * now select the approprate underlying mechanism routine and
 150          * call it.
 151          */
 152 
 153         mech = __gss_get_mechanism(token_mech_type);
 154         if (mech && mech->gss_accept_sec_context) {
 155                 status = mech->gss_accept_sec_context(
 156                                         mech->context,
 157                                         minor_status,
 158                                         &union_ctx_id->internal_ctx_id,
 159                                         input_cred_handle,
 160                                         input_token_buffer,
 161                                         input_chan_bindings,
 162                                         &internal_name,
 163                                         &actual_mech,
 164                                         output_token,
 165                                         &flags,
 166                                         time_rec,
 167                                         d_cred ? &tmp_d_cred : NULL);
 168 
 169                 /* If there's more work to do, keep going... */
 170                 if (status == GSS_S_CONTINUE_NEEDED)
 171                         return (GSS_S_CONTINUE_NEEDED);
 172 
 173                 /* if the call failed, return with failure */
 174                 if (status != GSS_S_COMPLETE)
 175                         goto error_out;
 176 
 177                 if (mech_type != NULL)
 178                         *mech_type = actual_mech;
 179 
 180                 /*
 181                  * if src_name is non-NULL,
 182                  * convert internal_name into a union name equivalent
 183                  * First call the mechanism specific display_name()
 184                  * then call gss_import_name() to create
 185                  * the union name struct cast to src_name
 186                  */
 187                 if (internal_name != NULL) {
 188                         temp_status = __gss_convert_name_to_union_name(
 189                                 &t_minstat, mech,
 190                                 internal_name, &tmp_src_name);
 191                         if (temp_status != GSS_S_COMPLETE) {
 192                                 *minor_status = t_minstat;
 193                                 if (output_token->length)
 194                                         (void) gss_release_buffer(
 195                                                 &t_minstat,
 196                                                 output_token);
 197                                 if (internal_name != GSS_C_NO_NAME)
 198                                         mech->gss_release_name(
 199                                                 mech->context,
 200                                                 &t_minstat,
 201                                                 &internal_name);
 202                                 return (temp_status);
 203                         }
 204                         if (src_name != NULL) {
 205                                 *src_name = tmp_src_name;
 206                         }
 207                 } else if (src_name != NULL) {
 208                         *src_name = GSS_C_NO_NAME;
 209                 }
 210 
 211                 /* Ensure we're returning correct creds format */
 212                 if ((flags & GSS_C_DELEG_FLAG) &&
 213                     tmp_d_cred != GSS_C_NO_CREDENTIAL) {
 214                         /*
 215                          * If we got back an OID different from the original
 216                          * token OID, assume the delegated_cred is already
 217                          * a proper union_cred and just return it.  Don't
 218                          * try to re-wrap it.  This is for SPNEGO or other
 219                          * pseudo-mechanisms.
 220                          */
 221                         if (actual_mech != GSS_C_NO_OID &&
 222                             token_mech_type != GSS_C_NO_OID &&
 223                             !g_OID_equal(actual_mech, token_mech_type)) {
 224                                 *d_cred = tmp_d_cred;
 225                         } else {
 226                                 gss_union_cred_t d_u_cred = NULL;
 227 
 228                                 d_u_cred = malloc(sizeof (gss_union_cred_desc));
 229                                 if (d_u_cred == NULL) {
 230                                         status = GSS_S_FAILURE;
 231                                         goto error_out;
 232                                 }
 233                                 (void) memset(d_u_cred, 0,
 234                                             sizeof (gss_union_cred_desc));
 235 
 236                                 d_u_cred->count = 1;
 237 
 238                                 status = generic_gss_copy_oid(
 239                                         &t_minstat,
 240                                         actual_mech,
 241                                         &d_u_cred->mechs_array);
 242 
 243                                 if (status != GSS_S_COMPLETE) {
 244                                         free(d_u_cred);
 245                                         goto error_out;
 246                                 }
 247 
 248                                 d_u_cred->cred_array = malloc(
 249                                                 sizeof (gss_cred_id_t));
 250                                 if (d_u_cred->cred_array != NULL) {
 251                                         d_u_cred->cred_array[0] = tmp_d_cred;
 252                                 } else {
 253                                         free(d_u_cred);
 254                                         status = GSS_S_FAILURE;
 255                                         goto error_out;
 256                                 }
 257 
 258                                 if (status != GSS_S_COMPLETE) {
 259                                         free(d_u_cred->cred_array);
 260                                         free(d_u_cred);
 261                                         goto error_out;
 262                                 }
 263 
 264                                 internal_name = GSS_C_NO_NAME;
 265 
 266                                 d_u_cred->auxinfo.creation_time = time(0);
 267                                 d_u_cred->auxinfo.time_rec = 0;
 268 
 269                                 if (mech->gss_inquire_cred) {
 270                                         status = mech->gss_inquire_cred(
 271                                                 mech->context,
 272                                                 minor_status,
 273                                                 tmp_d_cred,
 274                                                 &internal_name,
 275                                                 &d_u_cred->auxinfo.time_rec,
 276                                                 &d_u_cred->auxinfo.cred_usage,
 277                                                 NULL);
 278                                 }
 279 
 280                                 if (internal_name != NULL) {
 281                                         temp_status =
 282                                             __gss_convert_name_to_union_name(
 283                                                 &t_minstat, mech,
 284                                                 internal_name, &tmp_src_name);
 285                                         if (temp_status != GSS_S_COMPLETE) {
 286                                                 *minor_status = t_minstat;
 287                                                 if (output_token->length)
 288                                                     (void) gss_release_buffer(
 289                                                                 &t_minstat,
 290                                                                 output_token);
 291                                                 free(d_u_cred->cred_array);
 292                                                 free(d_u_cred);
 293                                                 return (temp_status);
 294                                         }
 295                                 }
 296 
 297                                 if (tmp_src_name != NULL) {
 298                                         status = gss_display_name(
 299                                                 &t_minstat,
 300                                                 tmp_src_name,
 301                                                 &d_u_cred->auxinfo.name,
 302                                                 &d_u_cred->auxinfo.name_type);
 303                                 }
 304 
 305                                 *d_cred = (gss_cred_id_t)d_u_cred;
 306                         }
 307                 }
 308                 if (ret_flags != NULL) {
 309                         *ret_flags = flags;
 310                 }
 311 
 312                 if (src_name == NULL && tmp_src_name != NULL)
 313                         (void) gss_release_name(&t_minstat,
 314                                         &tmp_src_name);
 315                 return  (status);
 316         } else {
 317 
 318                 status = GSS_S_BAD_MECH;
 319         }
 320 
 321 error_out:
 322         if (union_ctx_id) {
 323                 if (union_ctx_id->mech_type) {
 324                         if (union_ctx_id->mech_type->elements)
 325                                 free(union_ctx_id->mech_type->elements);
 326                         free(union_ctx_id->mech_type);
 327                 }
 328                 free(union_ctx_id);
 329                 *context_handle = GSS_C_NO_CONTEXT;
 330         }
 331 
 332         if (output_token->length)
 333                 (void) gss_release_buffer(&t_minstat, output_token);
 334 
 335         if (src_name)
 336                 *src_name = GSS_C_NO_NAME;
 337 
 338         if (tmp_src_name != GSS_C_NO_NAME)
 339                 (void) gss_release_buffer(&t_minstat,
 340                         (gss_buffer_t)tmp_src_name);
 341 
 342         return (status);
 343 }