xref: /freebsd/crypto/krb5/src/lib/gssapi/mechglue/g_init_sec_context.c (revision f1c4c3daccbaf3820f0e2224de53df12fc952fcc)
1 /* #pragma ident	"@(#)g_init_sec_context.c	1.20	03/10/24 SMI" */
2 
3 /*
4  * Copyright 1996 by Sun Microsystems, Inc.
5  *
6  * Permission to use, copy, modify, distribute, and sell this software
7  * and its documentation for any purpose is hereby granted without fee,
8  * provided that the above copyright notice appears in all copies and
9  * that both that copyright notice and this permission notice appear in
10  * supporting documentation, and that the name of Sun Microsystems not be used
11  * in advertising or publicity pertaining to distribution of the software
12  * without specific, written prior permission. Sun Microsystems makes no
13  * representations about the suitability of this software for any
14  * purpose.  It is provided "as is" without express or implied warranty.
15  *
16  * SUN MICROSYSTEMS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
17  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
18  * EVENT SHALL SUN MICROSYSTEMS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
19  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
20  * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
21  * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
22  * PERFORMANCE OF THIS SOFTWARE.
23  */
24 
25 /*
26  *  glue routine for gss_init_sec_context
27  */
28 
29 #include "mglueP.h"
30 #include <stdio.h>
31 #ifdef HAVE_STDLIB_H
32 #include <stdlib.h>
33 #endif
34 #include <string.h>
35 
36 static OM_uint32
val_init_sec_ctx_args(OM_uint32 * minor_status,gss_cred_id_t claimant_cred_handle,gss_ctx_id_t * context_handle,gss_name_t target_name,gss_OID req_mech_type,OM_uint32 req_flags,OM_uint32 time_req,gss_channel_bindings_t input_chan_bindings,gss_buffer_t input_token,gss_OID * actual_mech_type,gss_buffer_t output_token,OM_uint32 * ret_flags,OM_uint32 * time_rec)37 val_init_sec_ctx_args(
38     OM_uint32 *minor_status,
39     gss_cred_id_t claimant_cred_handle,
40     gss_ctx_id_t *context_handle,
41     gss_name_t target_name,
42     gss_OID req_mech_type,
43     OM_uint32 req_flags,
44     OM_uint32 time_req,
45     gss_channel_bindings_t input_chan_bindings,
46     gss_buffer_t input_token,
47     gss_OID *actual_mech_type,
48     gss_buffer_t output_token,
49     OM_uint32 *ret_flags,
50     OM_uint32 *time_rec)
51 {
52 
53     /* Initialize outputs. */
54 
55     if (minor_status != NULL)
56 	*minor_status = 0;
57 
58     if (actual_mech_type != NULL)
59 	*actual_mech_type = GSS_C_NO_OID;
60 
61     if (output_token != GSS_C_NO_BUFFER) {
62 	output_token->length = 0;
63 	output_token->value = NULL;
64     }
65 
66     if (ret_flags != NULL)
67 	*ret_flags = 0;
68 
69     if (time_rec != NULL)
70 	*time_rec = 0;
71 
72     /* Validate arguments. */
73 
74     if (minor_status == NULL)
75 	return (GSS_S_CALL_INACCESSIBLE_WRITE);
76 
77     if (context_handle == NULL)
78 	return (GSS_S_CALL_INACCESSIBLE_WRITE | GSS_S_NO_CONTEXT);
79 
80     if (target_name == NULL)
81 	return (GSS_S_CALL_INACCESSIBLE_READ | GSS_S_BAD_NAME);
82 
83     if (output_token == NULL)
84 	return (GSS_S_CALL_INACCESSIBLE_WRITE);
85 
86     return (GSS_S_COMPLETE);
87 }
88 
89 
90 OM_uint32 KRB5_CALLCONV
gss_init_sec_context(OM_uint32 * minor_status,gss_cred_id_t claimant_cred_handle,gss_ctx_id_t * context_handle,gss_name_t target_name,gss_OID req_mech_type,OM_uint32 req_flags,OM_uint32 time_req,gss_channel_bindings_t input_chan_bindings,gss_buffer_t input_token,gss_OID * actual_mech_type,gss_buffer_t output_token,OM_uint32 * ret_flags,OM_uint32 * time_rec)91 gss_init_sec_context(OM_uint32 *minor_status,
92 		     gss_cred_id_t claimant_cred_handle,
93 		     gss_ctx_id_t *context_handle, gss_name_t target_name,
94 		     gss_OID req_mech_type, OM_uint32 req_flags,
95 		     OM_uint32 time_req,
96 		     gss_channel_bindings_t input_chan_bindings,
97 		     gss_buffer_t input_token, gss_OID *actual_mech_type,
98 		     gss_buffer_t output_token, OM_uint32 *ret_flags,
99 		     OM_uint32 *time_rec)
100 {
101     OM_uint32		status, temp_minor_status;
102     gss_union_name_t	union_name;
103     gss_union_cred_t	union_cred;
104     gss_name_t		internal_name;
105     gss_union_ctx_id_t	union_ctx_id;
106     gss_OID		selected_mech;
107     gss_mechanism	mech;
108     gss_cred_id_t	input_cred_handle;
109 
110     status = val_init_sec_ctx_args(minor_status,
111 				   claimant_cred_handle,
112 				   context_handle,
113 				   target_name,
114 				   req_mech_type,
115 				   req_flags,
116 				   time_req,
117 				   input_chan_bindings,
118 				   input_token,
119 				   actual_mech_type,
120 				   output_token,
121 				   ret_flags,
122 				   time_rec);
123     if (status != GSS_S_COMPLETE)
124 	return (status);
125 
126     status = gssint_select_mech_type(minor_status, req_mech_type,
127 				     &selected_mech);
128     if (status != GSS_S_COMPLETE)
129 	return (status);
130 
131     union_name = (gss_union_name_t)target_name;
132 
133     /*
134      * obtain the gss mechanism information for the requested
135      * mechanism.  If mech_type is NULL, set it to the resultant
136      * mechanism
137      */
138     mech = gssint_get_mechanism(selected_mech);
139     if (mech == NULL)
140 	return (GSS_S_BAD_MECH);
141 
142     if (mech->gss_init_sec_context == NULL)
143 	return (GSS_S_UNAVAILABLE);
144 
145     /*
146      * If target_name is mechanism_specific, then it must match the
147      * mech_type that we're about to use.  Otherwise, do an import on
148      * the external_name form of the target name.
149      */
150     if (union_name->mech_type &&
151 	g_OID_equal(union_name->mech_type, selected_mech)) {
152 	internal_name = union_name->mech_name;
153     } else {
154 	if ((status = gssint_import_internal_name(minor_status, selected_mech,
155 						 union_name,
156 						 &internal_name)) != GSS_S_COMPLETE)
157 	    return (status);
158     }
159 
160     /*
161      * if context_handle is GSS_C_NO_CONTEXT, allocate a union context
162      * descriptor to hold the mech type information as well as the
163      * underlying mechanism context handle. Otherwise, cast the
164      * value of *context_handle to the union context variable.
165      */
166 
167     if(*context_handle == GSS_C_NO_CONTEXT) {
168 	status = gssint_create_union_context(minor_status, selected_mech,
169 					     &union_ctx_id);
170 	if (status != GSS_S_COMPLETE)
171 	    goto end;
172     } else {
173 	union_ctx_id = (gss_union_ctx_id_t)*context_handle;
174 	if (union_ctx_id->internal_ctx_id == GSS_C_NO_CONTEXT) {
175 	    status = GSS_S_NO_CONTEXT;
176 	    goto end;
177 	}
178     }
179 
180     /*
181      * get the appropriate cred handle from the union cred struct.
182      * defaults to GSS_C_NO_CREDENTIAL if there is no cred, which will
183      * use the default credential.
184      */
185     union_cred = (gss_union_cred_t) claimant_cred_handle;
186     input_cred_handle = gssint_get_mechanism_cred(union_cred, selected_mech);
187 
188     /*
189      * now call the approprate underlying mechanism routine
190      */
191 
192     status = mech->gss_init_sec_context(
193 	minor_status,
194 	input_cred_handle,
195 	&union_ctx_id->internal_ctx_id,
196 	internal_name,
197 	gssint_get_public_oid(selected_mech),
198 	req_flags,
199 	time_req,
200 	input_chan_bindings,
201 	input_token,
202 	actual_mech_type,
203 	output_token,
204 	ret_flags,
205 	time_rec);
206 
207     if (status != GSS_S_COMPLETE && status != GSS_S_CONTINUE_NEEDED) {
208 	/*
209 	 * RFC 2744 5.19 requires that we not create a context on a failed
210 	 * first call to init, and recommends that on a failed subsequent call
211 	 * we make the caller responsible for calling gss_delete_sec_context.
212 	 * Even if the mech deleted its context, keep the union context around
213 	 * for the caller to delete.
214 	 */
215 	map_error(minor_status, mech);
216 	if (*context_handle == GSS_C_NO_CONTEXT) {
217 	    free(union_ctx_id->mech_type->elements);
218 	    free(union_ctx_id->mech_type);
219 	    free(union_ctx_id);
220 	}
221     } else if (*context_handle == GSS_C_NO_CONTEXT) {
222 	*context_handle = (gss_ctx_id_t)union_ctx_id;
223     }
224 
225 end:
226     if (union_name->mech_name == NULL ||
227 	union_name->mech_name != internal_name) {
228 	(void) gssint_release_internal_name(&temp_minor_status,
229 					    selected_mech, &internal_name);
230     }
231 
232     return(status);
233 }
234