Conf file is now in source tree
[mod_auth_kerb.cvs/.git] / spnegokrb5 / init_sec_context.c
1 /*
2  *  SPNEGO wrapper for Kerberos5 GSS-API
3  *  kouril@ics.muni.cz, 2003
4  *  (mostly based on Heimdal code)
5  */
6
7 #include "spnegokrb5_locl.h"
8
9 static int
10 add_mech(MechTypeList *mech_list, gss_OID mech)
11 {
12    MechType *tmp;
13    int ret;
14
15    tmp = realloc(mech_list->val, (mech_list->len + 1) * sizeof(*tmp));
16    if (tmp == NULL)
17       return ENOMEM;
18    mech_list->val = tmp;
19
20    ret = der_get_oid(mech->elements, mech->length, 
21                      &mech_list->val[mech_list->len], NULL);
22    if (ret)
23      return ret;
24
25    mech_list->len++;
26    return 0;
27 }
28
29 #if 0
30 static int
31 set_context_flags(OM_uint32 req_flags, ContextFlags *flags)
32 {
33    if (req_flags & GSS_C_DELEG_FLAG)
34       flags->delegFlag = 1;
35    if (req_flags & GSS_C_MUTUAL_FLAG)
36       flags->mutualFlag = 1;
37    if (req_flags & GSS_C_REPLAY_FLAG)
38       flags->replayFlag = 1;
39    if (req_flags & GSS_C_SEQUENCE_FLAG)
40       flags->sequenceFlag = 1;
41    if (req_flags & GSS_C_ANON_FLAG)
42       flags->anonFlag = 1;
43    if (req_flags & GSS_C_CONF_FLAG)
44       flags->confFlag = 1;
45    if (req_flags & GSS_C_INTEG_FLAG)
46       flags->integFlag = 1;
47    return 0;
48 }
49 #endif
50
51 OM_uint32 KRB5_LIB_FUNCTION gss_init_sec_context_spnego(
52             OM_uint32 * minor_status,
53             const gss_cred_id_t initiator_cred_handle,
54             gss_ctx_id_t * context_handle,
55             const gss_name_t target_name,
56             const gss_OID mech_type,
57             OM_uint32 req_flags,
58             OM_uint32 time_req,
59             const gss_channel_bindings_t input_chan_bindings,
60             const gss_buffer_t input_token,
61             gss_OID * actual_mech_type,
62             gss_buffer_t output_token,
63             OM_uint32 * ret_flags,
64             OM_uint32 * time_rec)
65 {
66    NegTokenInit token_init;
67    OM_uint32 major_status, minor_status2;
68    gss_buffer_desc krb5_output_token = GSS_C_EMPTY_BUFFER;
69    unsigned char *buf = NULL;
70    size_t buf_size;
71    size_t len;
72    int ret;
73
74    memset(&token_init, 0, sizeof(token_init));
75
76    ALLOC(token_init.mechTypes);
77    if (token_init.mechTypes == NULL) {
78       *minor_status = ENOMEM;
79       return GSS_S_FAILURE;
80    }
81
82    ret = add_mech(token_init.mechTypes, GSS_KRB5_MECH);
83    if (ret) {
84       *minor_status = ret;
85       ret = GSS_S_FAILURE;
86       goto end;
87    }
88
89 #if 0
90    ALLOC(token_init.reqFlags);
91    if (token_init.reqFlags == NULL) {
92       *minor_status = ENOMEM;
93       ret = GSS_S_FAILURE;
94       goto end;
95    }
96    set_context_flags(req_flags, token_init.reqFlags);
97 #endif
98
99    major_status = gss_init_sec_context(minor_status,
100                                        initiator_cred_handle,
101                                        context_handle,
102                                        target_name,
103                                        GSS_KRB5_MECH,
104                                        req_flags,
105                                        time_req,
106                                        input_chan_bindings,
107                                        input_token,
108                                        actual_mech_type,
109                                        &krb5_output_token,
110                                        ret_flags,
111                                        time_rec);
112    if (GSS_ERROR(major_status)) {
113       ret = major_status;
114       goto end;
115    }
116
117    if (krb5_output_token.length > 0) {
118       ALLOC(token_init.mechToken);
119       if (token_init.mechToken == NULL) {
120          *minor_status = ENOMEM;
121          ret = GSS_S_FAILURE;
122          goto end;
123       }
124       token_init.mechToken->data = krb5_output_token.value;
125       token_init.mechToken->length = krb5_output_token.length;
126       krb5_output_token.length = 0; /* don't free it later */
127    }
128
129    /* The MS implementation of SPNEGO seems to not like the mechListMIC field,
130     * so we omit it (it's optional anyway) */
131
132    buf_size = 1024;
133    buf = malloc(buf_size);
134
135     do {
136         ret = encode_NegTokenInit(buf + buf_size -1,
137                                   buf_size,
138                                   &token_init, &len);
139         if (ret == 0) {
140             size_t tmp;
141
142             ret = der_put_length_and_tag(buf + buf_size - len - 1,
143                                          buf_size - len,
144                                          len,
145                                          KERB_CTXT,
146                                          CONS,
147                                          0,
148                                          &tmp);
149             if (ret == 0)
150                 len += tmp;
151         }
152         if (ret) {
153             if (ret == ASN1_OVERFLOW) {
154                 u_char *tmp;
155
156                 buf_size *= 2;
157                 tmp = realloc (buf, buf_size);
158                 if (tmp == NULL) {
159                     *minor_status = ENOMEM;
160                     ret = GSS_S_FAILURE;
161                     goto end;
162                 }
163                 buf = tmp;
164             } else {
165                 *minor_status = ret;
166                 ret = GSS_S_FAILURE;
167                 goto end;
168             }
169         }
170     } while (ret == ASN1_OVERFLOW);
171
172     ret = gssapi_spnego_encapsulate(minor_status,
173                                     buf + buf_size - len, len,
174                                     output_token, GSS_SPNEGO_MECH);
175
176    ret = major_status;
177
178 end:
179    free_NegTokenInit(&token_init);
180    if (krb5_output_token.length > 0)
181       gss_release_buffer(&minor_status2, &krb5_output_token);
182    if (buf)
183       free(buf);
184
185    return ret;
186 }