2 * init_sec.c --- initialize security context
8 * Copyright 1991 by the Massachusetts Institute of Technology.
11 * For copying and distribution information, please see the file
18 extern krb5_flags krb5_kdc_default_options;
21 * To do in the future:
23 * * Support replay cache
25 * * Support delegation of credentials
27 * * Do something with time_rec
29 * * Should handle Kerberos error packets being sent back and
33 gss_cred_id_t gss_default_credentials = {
34 (krb5_principal) NULL, (gss_OID) NULL, 0, (krb5_ccache) NULL,
35 (krb5_kvno) 0, { (krb5_keytype) 0, 0, (krb5_octet *) NULL }
39 OM_uint32 gss_init_sec_context(minor_status, claimant_cred_handle,
40 context_handle, target_name,
41 mech_type, req_flags, time_req,
43 actual_mech_type, output_token,
45 OM_uint32 *minor_status;
46 gss_cred_id_t claimant_cred_handle;
47 gss_ctx_id_t *context_handle;
48 gss_name_t target_name;
52 gss_channel_bindings channel;
53 gss_buffer_t input_token;
54 gss_OID *actual_mech_type;
55 gss_buffer_t output_token;
59 krb5_flags kdc_options = krb5_kdc_default_options;
60 krb5_flags ap_req_options = 0;
63 krb5_authenticator authent;
64 krb5_data inbuf, outbuf;
65 krb5_ap_rep_enc_part *repl;
71 if (!context_handle) {
73 * This is first call to init_sec_context
75 * We only handle Kerberos V5...
77 if ((mech_type != GSS_C_NULL_OID) &&
78 !gss_compare_OID(mech_type, &gss_OID_krb5)) {
79 return(gss_make_re(GSS_RE_BAD_MECH));
82 *actual_mech_type = &gss_OID_krb5;
84 * Sanitize the incoming flags
86 * We don't support delegation or replay detection --- yet.
88 req_flags &= ~GSS_C_DELEG_FLAG;
89 req_flags &= ~GSS_C_REPLAY_FLAG;
91 * If no credentials were passed in, get our own
93 if (claimant_cred_handle.ccache)
94 ccache = claimant_cred_handle.ccache;
97 * Default (or NULL) credentials, we need to
98 * fill in with defaults.
100 if (*minor_status = krb5_cc_default(&ccache)) {
101 return(gss_make_re(GSS_RE_FAILURE));
103 claimant_cred_handle.ccache = ccache;
105 krb5_cc_get_principal(ccache,
106 &claimant_cred_handle.principal))
107 return(gss_make_re(GSS_RE_FAILURE));
110 * Allocate the context handle structure
112 if (!(context = malloc(sizeof(struct gss_ctx_id_desc)))) {
113 *minor_status = ENOMEM;
114 return(gss_make_re(GSS_RE_FAILURE));
116 context->mech_type = &gss_OID_krb5;
117 context->state = GSS_KRB_STATE_DOWN;
119 * Fill in context handle structure
122 krb5_copy_principal(claimant_cred_handle.principal,
124 return(gss_make_re(GSS_RE_FAILURE));
126 krb5_copy_principal(target_name,
128 return(gss_make_re(GSS_RE_FAILURE));
129 context->flags = req_flags | GSS_C_CONF_FLAG;;
130 context->am_client = 1;
131 context->session_key = NULL;
132 context->my_address.addrtype = channel.sender_addrtype;
133 context->my_address.length = channel.sender_address.length;
134 if (!(context->my_address.contents =
135 malloc(context->my_address.length))) {
137 return(gss_make_re(GSS_RE_FAILURE));
139 memcpy((char *) context->my_address.contents,
140 (char *) channel.sender_address.value,
141 context->my_address.length);
142 context->his_address.addrtype = channel.receiver_addrtype;
143 context->his_address.length = channel.receiver_address.length;
144 if (!(context->his_address.contents =
145 malloc(context->my_address.length))) {
146 xfree(context->my_address.contents);
148 return(gss_make_re(GSS_RE_FAILURE));
150 memcpy((char *) context->his_address.contents,
151 (char *) channel.receiver_address.value,
152 context->his_address.length);
154 * Generate a random sequence number
157 krb5_generate_seq_number(&creds.keyblock,
158 &context->my_seq_num)) {
159 xfree(context->his_address.contents);
160 xfree(context->my_address.contents);
161 free((char *)context);
162 return(make_gss_re(GSS_RE_FAILURE));
164 context->his_seq_num = 0;
166 * Make a credentials structure
168 memset((char *)&creds, 0, sizeof(creds));
169 creds.server = context->him;
170 creds.client = context->me;
171 /* creds.times.endtime = 0; -- memset 0 takes care of this
172 zero means "as long as possible" */
173 /* creds.keyblock.keytype = 0; -- as well as this.
174 zero means no session keytype
176 if (*minor_status = krb5_get_credentials(0,
179 krb5_free_cred_contents(&creds);
180 free((char *)context);
181 return(gss_make_re(GSS_RE_FAILURE));
184 * Setup the ap_req_options
186 if ((req_flags & GSS_C_MUTUAL_FLAG) ||
187 (req_flags & GSS_C_SEQUENCE_FLAG))
188 ap_req_options |= AP_OPTS_MUTUAL_REQUIRED;
190 * OK, get the authentication header!
192 if (*minor_status = krb5_mk_req_extended(ap_req_options, 0,
195 context->my_seq_num, 0,
196 ccache, &creds, &authent,
198 memset((char *)&authent, 0, sizeof(authent));
199 krb5_free_cred_contents(&creds);
200 free((char *)context);
201 return(gss_make_re(GSS_RE_FAILURE));
203 context->cusec = authent.cusec;
204 context->ctime = authent.ctime;
205 memset((char *)&authent, 0, sizeof(authent));
208 krb5_copy_keyblock(&creds.keyblock,
209 &context->session_key)) {
211 krb5_free_cred_contents(&creds);
212 free((char *)context);
213 return(gss_make_re(GSS_RE_FAILURE));
216 if (*minor_status = gss_make_token(minor_status,
223 krb5_free_cred_contents(&creds);
224 free((char *) context);
225 return(gss_make_re(GSS_RE_FAILURE));
228 * Send over the requested flags information
230 ((char *) output_token->value)[4] = context->flags;
232 *context_handle = context;
233 context->state = GSS_KRB_STATE_DOWN;
234 *ret_flags = context->flags;
236 * Don't free server and client because we need them
237 * for the context structure.
241 krb5_free_cred_contents(&creds);
242 if (ap_req_options & AP_OPTS_MUTUAL_REQUIRED) {
243 context->state = GSS_KRB_STATE_MUTWAIT;
244 return(GSS_SS_CONTINUE_NEEDED);
246 context->state = GSS_KRB_STATE_UP;
247 return(GSS_S_COMPLETE);
251 context = *context_handle;
253 if (context->state != GSS_KRB_STATE_MUTWAIT)
254 return(gss_make_re(GSS_RE_FAILURE));
255 if (retval = gss_check_token(minor_status, input_token,
259 inbuf.length = input_token->length-4;
260 inbuf.data = ((char *)input_token->value)+4;
262 if (*minor_status = krb5_rd_rep(&inbuf, context->session_key,
264 return(gss_make_re(GSS_RE_FAILURE));
265 if ((repl->ctime != context->ctime) ||
266 (repl->cusec != context->cusec)) {
267 *minor_status = KRB5_SENDAUTH_MUTUAL_FAILED;
268 return(gss_make_re(GSS_RE_FAILURE));
270 context->his_seq_num = repl->seq_number;
271 context->state = GSS_KRB_STATE_UP;
272 krb5_free_ap_rep_enc_part(repl);
273 return(GSS_S_COMPLETE);