1/* $NetBSD: gss_init_sec_context.c,v 1.2 2017/01/28 21:31:46 christos Exp $ */ 2 3/*- 4 * Copyright (c) 2005 Doug Rabson 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 * 28 * $FreeBSD: src/lib/libgssapi/gss_init_sec_context.c,v 1.1 2005/12/29 14:40:20 dfr Exp $ 29 */ 30 31#include "mech_locl.h" 32 33static gss_cred_id_t 34_gss_mech_cred_find(gss_const_cred_id_t cred_handle, gss_OID mech_type) 35{ 36 struct _gss_cred *cred = (struct _gss_cred *)cred_handle; 37 struct _gss_mechanism_cred *mc; 38 39 if (cred == NULL) 40 return GSS_C_NO_CREDENTIAL; 41 42 HEIM_SLIST_FOREACH(mc, &cred->gc_mc, gmc_link) { 43 if (gss_oid_equal(mech_type, mc->gmc_mech_oid)) 44 return mc->gmc_cred; 45 } 46 return GSS_C_NO_CREDENTIAL; 47} 48 49/** 50 * As the initiator build a context with an acceptor. 51 * 52 * Returns in the major 53 * - GSS_S_COMPLETE - if the context if build 54 * - GSS_S_CONTINUE_NEEDED - if the caller needs to continue another 55 * round of gss_i nit_sec_context 56 * - error code - any other error code 57 * 58 * @param minor_status minor status code. 59 * 60 * @param initiator_cred_handle the credential to use when building 61 * the context, if GSS_C_NO_CREDENTIAL is passed, the default 62 * credential for the mechanism will be used. 63 * 64 * @param context_handle a pointer to a context handle, will be 65 * returned as long as there is not an error. 66 * 67 * @param target_name the target name of acceptor, created using 68 * gss_import_name(). The name is can be of any name types the 69 * mechanism supports, check supported name types with 70 * gss_inquire_names_for_mech(). 71 * 72 * @param input_mech_type mechanism type to use, if GSS_C_NO_OID is 73 * used, Kerberos (GSS_KRB5_MECHANISM) will be tried. Other 74 * available mechanism are listed in the @ref gssapi_mechs_intro 75 * section. 76 * 77 * @param req_flags flags using when building the context, see @ref 78 * gssapi_context_flags 79 * 80 * @param time_req time requested this context should be valid in 81 * seconds, common used value is GSS_C_INDEFINITE 82 * 83 * @param input_chan_bindings Channel bindings used, if not exepected 84 * otherwise, used GSS_C_NO_CHANNEL_BINDINGS 85 * 86 * @param input_token input token sent from the acceptor, for the 87 * initial packet the buffer of { NULL, 0 } should be used. 88 * 89 * @param actual_mech_type the actual mech used, MUST NOT be freed 90 * since it pointing to static memory. 91 * 92 * @param output_token if there is an output token, regardless of 93 * complete, continue_needed, or error it should be sent to the 94 * acceptor 95 * 96 * @param ret_flags return what flags was negotitated, caller should 97 * check if they are accetable. For example, if 98 * GSS_C_MUTUAL_FLAG was negotiated with the acceptor or not. 99 * 100 * @param time_rec amount of time this context is valid for 101 * 102 * @returns a gss_error code, see gss_display_status() about printing 103 * the error code. 104 * 105 * @ingroup gssapi 106 */ 107 108 109 110GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL 111gss_init_sec_context(OM_uint32 * minor_status, 112 gss_const_cred_id_t initiator_cred_handle, 113 gss_ctx_id_t * context_handle, 114 gss_const_name_t target_name, 115 const gss_OID input_mech_type, 116 OM_uint32 req_flags, 117 OM_uint32 time_req, 118 const gss_channel_bindings_t input_chan_bindings, 119 const gss_buffer_t input_token, 120 gss_OID * actual_mech_type, 121 gss_buffer_t output_token, 122 OM_uint32 * ret_flags, 123 OM_uint32 * time_rec) 124{ 125 OM_uint32 major_status; 126 gssapi_mech_interface m; 127 struct _gss_name *name = (struct _gss_name *) target_name; 128 struct _gss_mechanism_name *mn; 129 struct _gss_context *ctx = (struct _gss_context *) *context_handle; 130 gss_const_cred_id_t cred_handle; 131 int allocated_ctx; 132 gss_OID mech_type = input_mech_type; 133 134 *minor_status = 0; 135 136 _mg_buffer_zero(output_token); 137 if (actual_mech_type) 138 *actual_mech_type = GSS_C_NO_OID; 139 if (ret_flags) 140 *ret_flags = 0; 141 if (time_rec) 142 *time_rec = 0; 143 144 /* 145 * If we haven't allocated a context yet, do so now and lookup 146 * the mechanism switch table. If we have one already, make 147 * sure we use the same mechanism switch as before. 148 */ 149 if (!ctx) { 150 if (mech_type == NULL) 151 mech_type = GSS_KRB5_MECHANISM; 152 153 ctx = malloc(sizeof(struct _gss_context)); 154 if (!ctx) { 155 *minor_status = ENOMEM; 156 return (GSS_S_FAILURE); 157 } 158 memset(ctx, 0, sizeof(struct _gss_context)); 159 m = ctx->gc_mech = __gss_get_mechanism(mech_type); 160 if (!m) { 161 free(ctx); 162 return (GSS_S_BAD_MECH); 163 } 164 allocated_ctx = 1; 165 } else { 166 m = ctx->gc_mech; 167 mech_type = &ctx->gc_mech->gm_mech_oid; 168 allocated_ctx = 0; 169 } 170 171 /* 172 * Find the MN for this mechanism. 173 */ 174 major_status = _gss_find_mn(minor_status, name, mech_type, &mn); 175 if (major_status != GSS_S_COMPLETE) { 176 if (allocated_ctx) 177 free(ctx); 178 return major_status; 179 } 180 181 /* 182 * If we have a cred, find the cred for this mechanism. 183 */ 184 if (m->gm_flags & GM_USE_MG_CRED) 185 cred_handle = initiator_cred_handle; 186 else 187 cred_handle = _gss_mech_cred_find(initiator_cred_handle, mech_type); 188 189 if (initiator_cred_handle != GSS_C_NO_CREDENTIAL && 190 cred_handle == NULL) { 191 if (allocated_ctx) 192 free(ctx); 193 return GSS_S_NO_CRED; 194 } 195 196 major_status = m->gm_init_sec_context(minor_status, 197 cred_handle, 198 &ctx->gc_ctx, 199 mn->gmn_name, 200 mech_type, 201 req_flags, 202 time_req, 203 input_chan_bindings, 204 input_token, 205 actual_mech_type, 206 output_token, 207 ret_flags, 208 time_rec); 209 210 if (major_status != GSS_S_COMPLETE 211 && major_status != GSS_S_CONTINUE_NEEDED) { 212 if (allocated_ctx) 213 free(ctx); 214 _mg_buffer_zero(output_token); 215 _gss_mg_error(m, major_status, *minor_status); 216 } else { 217 *context_handle = (gss_ctx_id_t) ctx; 218 } 219 220 return (major_status); 221} 222