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