c603b7b5805705aa5512d8a87717eaf0dc831c80
[mod_auth_kerb.git] / spnegokrb5 / accept_sec_context.c
1 /*
2  * SPNEGO wrapper for Kerberos5 GSS-API 
3  * kouril@ics.muni.cz, 2003
4  */
5
6 #include "spnegokrb5_locl.h"
7
8 #define ALLOC(X) (X) = calloc(1, sizeof(*(X)))
9
10 #define OID_cmp(o1, o2) \
11         (((o1)->length == (o2)->length) && \
12          (memcmp((o1)->components, (o2)->components,(int) (o1)->length) == 0))
13
14 static int
15 create_reply(OM_uint32 major_status, gss_OID mech, gss_buffer_t mech_token,
16              gss_buffer_t output_token)
17 {
18    NegTokenTarg targ_token;
19    unsigned char *buf = NULL;
20    size_t buf_size;
21    size_t len;
22    int ret;
23
24    memset(&targ_token, 0, sizeof(targ_token));
25    
26    ALLOC(targ_token.negResult);
27    if (targ_token.negResult == NULL)
28       return ENOMEM;
29
30    *targ_token.negResult = (major_status == 0) ? accept_completed : accept_incomplete;
31
32    ALLOC(targ_token.supportedMech);
33    if (targ_token.supportedMech == NULL) {
34       ret = ENOMEM;
35       goto end;
36    }
37    copy_MechType((oid*)mech, targ_token.supportedMech);
38
39    if (mech_token->length > 0) {
40       ALLOC(targ_token.responseToken);
41       if (targ_token.responseToken == NULL) {
42          ret = ENOMEM;
43          goto end;
44       }
45       targ_token.responseToken->data = malloc(mech_token->length);
46       memcpy(targ_token.responseToken->data, mech_token->value, mech_token->length);
47       targ_token.responseToken->length = mech_token->length;
48    }
49
50    ASN1_MALLOC_ENCODE(NegTokenTarg, buf, buf_size, &targ_token, &len, ret);
51    if (ret || buf_size != len) {
52       ret = EINVAL;
53       goto end;
54    }
55
56    output_token->value = buf;
57    output_token->length = buf_size;
58    buf = NULL;
59    ret = 0;
60
61 end:
62    free_NegTokenTarg(&targ_token);
63
64    return ret;
65 }
66
67 OM_uint32 gss_accept_sec_context_spnego
68            (OM_uint32 * minor_status,
69             gss_ctx_id_t * context_handle,
70             const gss_cred_id_t acceptor_cred_handle,
71             const gss_buffer_t input_token_buffer,
72             const gss_channel_bindings_t input_chan_bindings,
73             gss_name_t * src_name,
74             gss_OID * mech_type,
75             gss_buffer_t output_token,
76             OM_uint32 * ret_flags,
77             OM_uint32 * time_rec,
78             gss_cred_id_t * delegated_cred_handle)
79 {
80    NegTokenInit init_token;
81    OM_uint32 major_status;
82    gss_buffer_desc krb5_output_token = GSS_C_EMPTY_BUFFER;
83    gss_buffer_desc krb5_input_token = GSS_C_EMPTY_BUFFER;
84    size_t len;
85    int ret;
86
87    memset(&init_token, 0, sizeof(init_token));
88
89    ret = decode_NegTokenInit(input_token_buffer->value, 
90                              input_token_buffer->length,
91                              &init_token, &len);
92    if (ret) {
93       *minor_status = EINVAL; /* XXX */
94       return GSS_S_DEFECTIVE_TOKEN;
95    }
96
97    if (init_token.mechTypes == NULL || init_token.mechTypes->len == 0 ||
98        OID_cmp(&init_token.mechTypes->val[0], (oid *)GSS_KRB5_MECH)) {
99       *minor_status = EINVAL;
100       ret = GSS_S_BAD_MECH;
101       goto end;
102    }
103        
104    if (init_token.mechToken) {
105       krb5_input_token.value = init_token.mechToken->data;
106       krb5_input_token.length = init_token.mechToken->length;
107    }
108    
109    major_status = gss_accept_sec_context(minor_status,
110                                          context_handle,
111                                          acceptor_cred_handle,
112                                          &krb5_input_token,
113                                          input_chan_bindings,
114                                          src_name,
115                                          mech_type,
116                                          &krb5_output_token,
117                                          ret_flags,
118                                          time_rec,
119                                          delegated_cred_handle);
120    if (GSS_ERROR(major_status)) {
121       ret = major_status;
122       goto end;
123    }
124
125    ret = create_reply(major_status, GSS_KRB5_MECH, &krb5_output_token, output_token);
126    if (ret) {
127       *minor_status = ret;
128       ret = GSS_S_FAILURE;
129       free(output_token);
130    }
131
132 end:
133    free_NegTokenInit(&init_token);
134
135    return ret;
136 }
137