Added wrapping calls (gss_init_sec_context_spnego() and gss_accept_sec_context_spnego...
[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  */
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 static int
14 add_mech(MechTypeList *mech_list, oid *mech)
15 {
16    MechType *tmp;
17
18    tmp = realloc(mech_list->val, (mech_list->len + 1) * sizeof(*tmp));
19    if (tmp == NULL)
20       return ENOMEM;
21    mech_list->val = tmp;
22    copy_MechType(mech, mech_list->val + mech_list->len);
23    mech_list->len++;
24    return 0;
25 }
26
27 static int
28 set_context_flags(OM_uint32 req_flags, ContextFlags *flags)
29 {
30    if (req_flags & GSS_C_DELEG_FLAG)
31       flags->delegFlag = 1;
32    if (req_flags & GSS_C_MUTUAL_FLAG)
33       flags->mutualFlag = 1;
34    if (req_flags & GSS_C_REPLAY_FLAG)
35       flags->replayFlag = 1;
36    if (req_flags & GSS_C_SEQUENCE_FLAG)
37       flags->sequenceFlag = 1;
38    if (req_flags & GSS_C_ANON_FLAG)
39       flags->anonFlag = 1;
40    if (req_flags & GSS_C_CONF_FLAG)
41       flags->confFlag = 1;
42    if (req_flags & GSS_C_INTEG_FLAG)
43       flags->integFlag = 1;
44    return 0;
45 }
46
47 OM_uint32 gss_init_sec_context_spnego(
48             OM_uint32 * minor_status,
49             const gss_cred_id_t initiator_cred_handle,
50             gss_ctx_id_t * context_handle,
51             const gss_name_t target_name,
52             const gss_OID mech_type,
53             OM_uint32 req_flags,
54             OM_uint32 time_req,
55             const gss_channel_bindings_t input_chan_bindings,
56             const gss_buffer_t input_token,
57             gss_OID * actual_mech_type,
58             gss_buffer_t output_token,
59             OM_uint32 * ret_flags,
60             OM_uint32 * time_rec)
61 {
62    NegTokenInit token_init;
63    OM_uint32 major_status, minor_status2;
64    gss_buffer_desc krb5_output_token = GSS_C_EMPTY_BUFFER;
65    unsigned char *buf = NULL;
66    size_t buf_size;
67    size_t len;
68    int ret;
69    unsigned krb5_oid_array[] = 
70         {0x2a, 0x86, 0x48, 0x86, 0xf7, 0x12, 0x01, 0x02, 0x02};
71    oid krb5_oid;
72
73    memset(&token_init, 0, sizeof(token_init));
74
75    krb5_oid.length = sizeof(krb5_oid_array);
76    krb5_oid.components = krb5_oid_array;
77
78    ALLOC(token_init.mechTypes);
79    if (token_init.mechTypes == NULL) {
80       *minor_status = ENOMEM;
81       return GSS_S_FAILURE;
82    }
83
84    ret = add_mech(token_init.mechTypes, &krb5_oid);
85    if (ret) {
86       *minor_status = ret;
87       ret = GSS_S_FAILURE;
88       goto end;
89    }
90
91    ALLOC(token_init.reqFlags);
92    if (token_init.reqFlags == NULL) {
93       *minor_status = ENOMEM;
94       ret = GSS_S_FAILURE;
95       goto end;
96    }
97    set_context_flags(req_flags, token_init.reqFlags);
98
99    major_status = gss_init_sec_context(minor_status,
100                                        initiator_cred_handle,
101                                        context_handle,
102                                        target_name,
103                                        (gss_OID) &krb5_oid,
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    ASN1_MALLOC_ENCODE(NegTokenInit, buf, buf_size, &token_init, &len, ret);
133    if (ret || buf_size != len) {
134       *minor_status = EINVAL; /* XXX */
135       ret = GSS_S_FAILURE;
136       goto end;
137    }
138
139    output_token->value = buf;
140    output_token->length = buf_size;
141    buf = NULL;
142    ret = major_status;
143
144 end:
145    free_NegTokenInit(&token_init);
146    if (krb5_output_token.length > 0)
147       gss_release_buffer(&minor_status2, &krb5_output_token);
148    if (buf)
149       free(buf);
150
151    return ret;
152 }