summaryrefslogtreecommitdiffstats
path: root/proxy/src/mechglue/gss_plugin.c
blob: fd976a55acd948d4c7d6487957ca133646b8d8ff (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
/*
   GSS-PROXY

   Copyright (C) 2012 Red Hat, Inc.
   Copyright (C) 2012 Simo Sorce <simo.sorce@redhat.com>

   Permission is hereby granted, free of charge, to any person obtaining a
   copy of this software and associated documentation files (the "Software"),
   to deal in the Software without restriction, including without limitation
   the rights to use, copy, modify, merge, publish, distribute, sublicense,
   and/or sell copies of the Software, and to permit persons to whom the
   Software is furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included in
   all copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
   THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
   DEALINGS IN THE SOFTWARE.
*/

#include "gss_plugin.h"
#include <gssapi/gssapi_krb5.h>

#define KRB5_OID_LEN 9
#define KRB5_OID "\052\206\110\206\367\022\001\002\002"

#define KRB5_OLD_OID_LEN 5
#define KRB5_OLD_OID "\053\005\001\005\002"

/* Incorrect krb5 mech OID emitted by MS. */
#define KRB5_WRONG_OID_LEN 9
#define KRB5_WRONG_OID "\052\206\110\202\367\022\001\002\002"

#define IAKERB_OID_LEN 6
#define IAKERB_OID "\053\006\001\005\002\005"

const gss_OID_desc gpoid_krb5 = {
    .length = KRB5_OID_LEN,
    .elements = KRB5_OID
};
const gss_OID_desc gpoid_krb5_old = {
    .length = KRB5_OLD_OID_LEN,
    .elements = KRB5_OLD_OID
};
const gss_OID_desc gpoid_krb5_wrong = {
    .length = KRB5_WRONG_OID_LEN,
    .elements = KRB5_WRONG_OID
};
const gss_OID_desc gpoid_iakerb = {
    .length = IAKERB_OID_LEN,
    .elements = IAKERB_OID
};

/* 2.16.840.1.113730.3.8.15.1 */
const gss_OID_desc gssproxy_mech_interposer = {
    .length = 11,
    .elements = "\140\206\110\001\206\370\102\003\010\017\001"
};

gss_OID_set gss_mech_interposer(gss_OID mech_type)
{
    gss_OID_set interposed_mechs;
    OM_uint32 maj, min;
    char *envval;

    /* avoid looping in the gssproxy daemon by avoiding to interpose
     * any mechanism */
    envval = getenv("_GSSPROXY_LOOPS");
    if (envval && strcmp(envval, "NO") == 0) {
        return NULL;
    }

    interposed_mechs = NULL;
    maj = 0;
    if (gss_oid_equal(&gssproxy_mech_interposer, mech_type)) {
        maj = gss_create_empty_oid_set(&min, &interposed_mechs);
        if (maj != 0) {
            return NULL;
        }
        maj = gss_add_oid_set_member(&min, no_const(&gpoid_krb5),
                                     &interposed_mechs);
        if (maj != 0) {
            goto done;
        }
        maj = gss_add_oid_set_member(&min, no_const(&gpoid_krb5_old),
                                     &interposed_mechs);
        if (maj != 0) {
            goto done;
        }
        maj = gss_add_oid_set_member(&min, no_const(&gpoid_krb5_wrong),
                                     &interposed_mechs);
        if (maj != 0) {
            goto done;
        }
        maj = gss_add_oid_set_member(&min, no_const(&gpoid_iakerb),
                                     &interposed_mechs);
        if (maj != 0) {
            goto done;
        }
    }

done:
    if (maj != 0) {
        (void)gss_release_oid_set(&min, &interposed_mechs);
        interposed_mechs = NULL;
    }

    return interposed_mechs;
}


#define SP_KRB5_OID_LEN (KRB5_OID_LEN + 1)
#define SP_KRB5_OID "\377" KRB5_OID

#define SP_KRB5_OLD_OID_LEN  (KRB5_OLD_OID_LEN + 1)
#define SP_KRB5_OLD_OID "\377" KRB5_OLD_OID

#define SP_KRB5_WRONG_OID_LEN (KRB5_WRONG_OID_LEN + 1)
#define SP_KRB5_WRONG_OID "\377" KRB5_WRONG_OID

#define SP_IAKERB_OID_LEN (IAKERB_OID_LEN + 1)
#define SP_IAKERB_OID "\377" IAKERB_OID

const gss_OID_desc gpoid_sp_krb5 = {
    .length = SP_KRB5_OID_LEN,
    .elements = SP_KRB5_OID
};
const gss_OID_desc gpoid_sp_krb5_old = {
    .length = SP_KRB5_OLD_OID_LEN,
    .elements = SP_KRB5_OLD_OID
};
const gss_OID_desc gpoid_sp_krb5_wrong = {
    .length = SP_KRB5_WRONG_OID_LEN,
    .elements = SP_KRB5_WRONG_OID
};
const gss_OID_desc gpoid_sp_iakerb = {
    .length = SP_IAKERB_OID_LEN,
    .elements = SP_IAKERB_OID
};
/* In future we may want to make this structure dynamic so we can proxy
 * arbitrary mechanisms based on what the server returns. */
struct gpm_mechs {
    gss_OID_desc const * real;
    gss_OID_desc const * special;
} gpm_mechs[] = {
    { &gpoid_krb5, &gpoid_sp_krb5, },
    { &gpoid_krb5_old, &gpoid_sp_krb5_old, },
    { &gpoid_krb5_wrong, &gpoid_sp_krb5_wrong, },
    { &gpoid_iakerb, &gpoid_sp_iakerb, },
    { NULL, NULL }
};

const gss_OID gpm_special_mech(const gss_OID mech_type)
{
    int i;

    if (mech_type == GSS_C_NO_OID) {
        /* return the first special one if none specified */
        return (const gss_OID)gpm_mechs[0].special;
    }

    for (i = 0; gpm_mechs[i].real != NULL; i++) {
        if (gss_oid_equal(gpm_mechs[i].real, mech_type)) {
            return (const gss_OID)gpm_mechs[i].special;
        }
    }

    return mech_type;
}

gss_OID_set gpm_special_available_mechs(const gss_OID_set mechs)
{
    gss_OID_set amechs = GSS_C_NO_OID_SET;
    uint32_t maj, min;
    unsigned i, j;

    maj = gss_create_empty_oid_set(&min, &amechs);
    if (maj) {
        return GSS_C_NO_OID_SET;
    }
    for (i = 0; i < mechs->count; i++) {
        for (j = 0; gpm_mechs[j].real != NULL; j++) {
            if (gss_oid_equal(gpm_mechs[i].real,
                              &mechs->elements[i])) {
                maj = gss_add_oid_set_member(&min,
                                             no_const(gpm_mechs[i].special),
                                             &amechs);
                if (maj) {
                    goto done;
                }
                break;
            }
        }
        /* none of the ones we intercept */
        if (gpm_mechs[j].real == NULL) {

            /* check if one is our own OID */
            if (gss_oid_equal(&gssproxy_mech_interposer,
                              &mechs->elements[i])) {
                /* just skip */
                continue;
            }
            /* If nothing matched just copy verbatim */
            maj = gss_add_oid_set_member(&min, &mechs->elements[i], &amechs);
            if (maj) {
                goto done;
            }
        }
    }

    if (amechs->count == 0) {
        maj = GSS_S_FAILURE;
    } else {
        maj = GSS_S_COMPLETE;
    }

done:
    if (maj) {
        (void)gss_release_oid_set(&min, &amechs);
    }
    return amechs;
}

#define MAP_ERROR_BASE 0x04200000

uint32_t gpm_map_error(uint32_t err)
{
    /* placeholder,
     * we will need an actual map but to speed up testing just make a sum with
     * a special base and hope no conflicts will happen in the mechglue */
    if (err) {
        err += MAP_ERROR_BASE;
    }
    return err;
}

uint32_t gpm_unmap_error(uint32_t err)
{
    /* placeholder,
     * we will need an actual map but to speed up testing just make a sum with
     * a special base and hope no conflicts will happen in the mechglue */
    if (err) {
        err -= MAP_ERROR_BASE;
    }
    return err;
}

/*
gssi_acquire_cred
gssi_release_cred
gssi_init_sec_context
gssi_accept_sec_context
gssi_process_context_token
gssi_delete_sec_context
gssi_context_time
gssi_get_mic
gssi_verify_mic
gssi_wrap
gssi_unwrap
gssi_display_status
gssi_indicate_mechs
gssi_compare_name
gssi_display_name
gssi_import_name
gssi_release_name
gssi_inquire_cred
gssi_add_cred
gssi_export_sec_context
gssi_import_sec_context
gssi_inquire_cred_by_mech
gssi_inquire_names_for_mech
gssi_inquire_context
gssi_internal_release_oid
gssi_wrap_size_limit
gssi_localname
gssi_authorize_localname
gssi_export_name
gssi_duplicate_name
gssi_store_cred
gssi_inquire_sec_context_by_oid
gssi_inquire_cred_by_oid
gssi_set_sec_context_option
gssi_set_cred_option
gssi_mech_invoke
gssi_wrap_aead
gssi_unwrap_aead
gssi_wrap_iov
gssi_unwrap_iov
gssi_wrap_iov_length
gssi_complete_auth_token
gssi_acquire_cred_impersonate_name
gssi_add_cred_impersonate_name
gssi_display_name_ext
gssi_inquire_name
gssi_get_name_attribute
gssi_set_name_attribute
gssi_delete_name_attribute
gssi_export_name_composite
gssi_map_name_to_any
gssi_release_any_name_mapping
gssi_pseudo_random
gssi_set_neg_mechs
gssi_inquire_saslname_for_mech
gssi_inquire_mech_for_saslname
gssi_inquire_attrs_for_mech
*/