~ubuntu-branches/ubuntu/trusty/pykerberos/trusty-proposed

« back to all changes in this revision

Viewing changes to src/kerberosgss.c

  • Committer: Bazaar Package Importer
  • Author(s): Guido Guenther
  • Date: 2006-11-03 18:01:08 UTC
  • Revision ID: james.westby@ubuntu.com-20061103180108-evdnxtjrrs6b0nkd
Tags: upstream-0.0.svn271
ImportĀ upstreamĀ versionĀ 0.0.svn271

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/**
 
2
 * Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
 
3
 *
 
4
 * Licensed under the Apache License, Version 2.0 (the "License");
 
5
 * you may not use this file except in compliance with the License.
 
6
 * You may obtain a copy of the License at
 
7
 *
 
8
 *     http://www.apache.org/licenses/LICENSE-2.0
 
9
 *
 
10
 * Unless required by applicable law or agreed to in writing, software
 
11
 * distributed under the License is distributed on an "AS IS" BASIS,
 
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 
13
 * See the License for the specific language governing permissions and
 
14
 * limitations under the License.
 
15
 *
 
16
 * DRI: Cyrus Daboo, cdaboo@apple.com
 
17
 **/
 
18
 
 
19
#include <Python.h>
 
20
#include "kerberosgss.h"
 
21
 
 
22
#include "base64.h"
 
23
 
 
24
#include <stdio.h>
 
25
#include <stdlib.h>
 
26
#include <string.h>
 
27
 
 
28
static void set_gss_error(OM_uint32 err_maj, OM_uint32 err_min);
 
29
 
 
30
extern PyObject *GssException_class;
 
31
extern PyObject *KrbException_class;
 
32
 
 
33
int authenticate_gss_client_init(const char* service, gss_client_state *state)
 
34
{
 
35
        OM_uint32 maj_stat;
 
36
        OM_uint32 min_stat;
 
37
        gss_buffer_desc name_token = GSS_C_EMPTY_BUFFER;
 
38
        int ret = AUTH_GSS_COMPLETE;
 
39
 
 
40
        state->server_name = GSS_C_NO_NAME;
 
41
        state->context = GSS_C_NO_CONTEXT;
 
42
        state->username = NULL;
 
43
        state->response = NULL;
 
44
        
 
45
        // Import server name first
 
46
        name_token.length = strlen(service);
 
47
        name_token.value = (char *)service;
 
48
        
 
49
        maj_stat = gss_import_name(&min_stat, &name_token, gss_krb5_nt_service_name, &state->server_name);
 
50
        
 
51
        if (GSS_ERROR(maj_stat))
 
52
        {
 
53
                set_gss_error(maj_stat, min_stat);
 
54
                ret = AUTH_GSS_ERROR;
 
55
                goto end;
 
56
        }
 
57
        
 
58
end:
 
59
        return ret;
 
60
}
 
61
 
 
62
int authenticate_gss_client_clean(gss_client_state *state)
 
63
{
 
64
        OM_uint32 maj_stat;
 
65
        OM_uint32 min_stat;
 
66
        int ret = AUTH_GSS_COMPLETE;
 
67
 
 
68
        if (state->context != GSS_C_NO_CONTEXT)
 
69
                maj_stat = gss_delete_sec_context(&min_stat, &state->context, GSS_C_NO_BUFFER);
 
70
        if (state->server_name != GSS_C_NO_NAME)
 
71
                maj_stat = gss_release_name(&min_stat, &state->server_name);
 
72
        if (state->username != NULL)
 
73
        {
 
74
                free(state->username);
 
75
                state->username = NULL;
 
76
        }
 
77
        if (state->response != NULL)
 
78
        {
 
79
                free(state->response);
 
80
                state->response = NULL;
 
81
        }
 
82
                
 
83
        return ret;
 
84
}
 
85
 
 
86
int authenticate_gss_client_step(gss_client_state *state, const char* challenge)
 
87
{
 
88
        OM_uint32 maj_stat;
 
89
        OM_uint32 min_stat;
 
90
        gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER;
 
91
        gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER;
 
92
        int ret = AUTH_GSS_CONTINUE;
 
93
    
 
94
        // Always clear out the old response
 
95
        if (state->response != NULL)
 
96
        {
 
97
                free(state->response);
 
98
                state->response = NULL;
 
99
        }
 
100
        
 
101
        // If there is a challenge (data from the server) we need to give it to GSS
 
102
        if (challenge && *challenge)
 
103
        {
 
104
                int len;
 
105
                input_token.value = base64_decode(challenge, &len);
 
106
                input_token.length = len;
 
107
        }
 
108
        
 
109
        // Do GSSAPI step
 
110
        maj_stat = gss_init_sec_context(&min_stat,
 
111
                                                                          GSS_C_NO_CREDENTIAL,
 
112
                                                                          &state->context,
 
113
                                                                          state->server_name,
 
114
                                                                          GSS_C_NO_OID,
 
115
                                                                          GSS_C_MUTUAL_FLAG | GSS_C_SEQUENCE_FLAG,
 
116
                                                                          0,
 
117
                                                                          GSS_C_NO_CHANNEL_BINDINGS,
 
118
                                                                          &input_token,
 
119
                                                                          NULL,
 
120
                                                                          &output_token,
 
121
                                                                          NULL,
 
122
                                                                          NULL);
 
123
        
 
124
        if ((maj_stat != GSS_S_COMPLETE) && (maj_stat != GSS_S_CONTINUE_NEEDED))
 
125
        {
 
126
                set_gss_error(maj_stat, min_stat);
 
127
                ret = AUTH_GSS_ERROR;
 
128
                goto end;
 
129
        }
 
130
 
 
131
        ret = (maj_stat == GSS_S_COMPLETE) ? AUTH_GSS_COMPLETE : AUTH_GSS_CONTINUE;
 
132
        // Grab the client response to send back to the server
 
133
        if (output_token.length)
 
134
        {
 
135
                state->response = base64_encode((const unsigned char *)output_token.value, output_token.length);;
 
136
                maj_stat = gss_release_buffer(&min_stat, &output_token);
 
137
        }
 
138
        
 
139
        // Try to get the user name if we have completed all GSS operations
 
140
        if (ret == AUTH_GSS_COMPLETE)
 
141
        {
 
142
                gss_name_t gssuser = GSS_C_NO_NAME;
 
143
            maj_stat = gss_inquire_context(&min_stat, state->context, &gssuser, NULL, NULL, NULL,  NULL, NULL, NULL);
 
144
                if (GSS_ERROR(maj_stat))
 
145
                {
 
146
                        set_gss_error(maj_stat, min_stat);
 
147
                        ret = AUTH_GSS_ERROR;
 
148
                        goto end;
 
149
                }
 
150
                
 
151
                gss_buffer_desc name_token;
 
152
            name_token.length = 0;
 
153
                maj_stat = gss_display_name(&min_stat, gssuser, &name_token, NULL);
 
154
                if (GSS_ERROR(maj_stat))
 
155
                {
 
156
                        if (name_token.value)
 
157
                            gss_release_buffer(&min_stat, &name_token);
 
158
                        gss_release_name(&min_stat, &gssuser);
 
159
                        
 
160
                        set_gss_error(maj_stat, min_stat);
 
161
                        ret = AUTH_GSS_ERROR;
 
162
                        goto end;
 
163
                }
 
164
                else
 
165
                {
 
166
                        state->username = (char *)malloc(name_token.length + 1);
 
167
                        strncpy(state->username, (char*) name_token.value, name_token.length);
 
168
                        state->username[name_token.length] = 0;
 
169
                    gss_release_buffer(&min_stat, &name_token);
 
170
                        gss_release_name(&min_stat, &gssuser);
 
171
                }
 
172
        }
 
173
end:
 
174
        if (output_token.value)
 
175
                gss_release_buffer(&min_stat, &output_token);
 
176
        if (input_token.value)
 
177
                free(input_token.value);
 
178
        return ret;
 
179
}
 
180
 
 
181
int authenticate_gss_server_init(const char* service, gss_server_state *state)
 
182
{
 
183
        OM_uint32 maj_stat;
 
184
        OM_uint32 min_stat;
 
185
        gss_buffer_desc name_token = GSS_C_EMPTY_BUFFER;
 
186
        int ret = AUTH_GSS_COMPLETE;
 
187
        
 
188
        state->context = GSS_C_NO_CONTEXT;
 
189
        state->server_name = GSS_C_NO_NAME;
 
190
        state->client_name = GSS_C_NO_NAME;
 
191
        state->server_creds = GSS_C_NO_CREDENTIAL;
 
192
        state->client_creds = GSS_C_NO_CREDENTIAL;
 
193
        state->username = NULL;
 
194
        state->response = NULL;
 
195
        
 
196
        // Import server name first
 
197
        name_token.length = strlen(service);
 
198
    name_token.value = (char *)service;
 
199
        
 
200
        maj_stat = gss_import_name(&min_stat, &name_token, GSS_C_NT_HOSTBASED_SERVICE, &state->server_name);
 
201
        
 
202
        if (GSS_ERROR(maj_stat))
 
203
        {
 
204
                set_gss_error(maj_stat, min_stat);
 
205
                ret = AUTH_GSS_ERROR;
 
206
                goto end;
 
207
        }
 
208
 
 
209
        // Get credentials
 
210
        maj_stat = gss_acquire_cred(&min_stat, state->server_name, GSS_C_INDEFINITE,
 
211
                                                                        GSS_C_NO_OID_SET, GSS_C_ACCEPT, &state->server_creds, NULL, NULL);
 
212
 
 
213
        if (GSS_ERROR(maj_stat))
 
214
        {
 
215
                set_gss_error(maj_stat, min_stat);
 
216
                ret = AUTH_GSS_ERROR;
 
217
                goto end;
 
218
        }
 
219
        
 
220
end:
 
221
        return ret;
 
222
}
 
223
 
 
224
int authenticate_gss_server_clean(gss_server_state *state)
 
225
{
 
226
        OM_uint32 maj_stat;
 
227
        OM_uint32 min_stat;
 
228
        int ret = AUTH_GSS_COMPLETE;
 
229
        
 
230
        if (state->context != GSS_C_NO_CONTEXT)
 
231
                maj_stat = gss_delete_sec_context(&min_stat, &state->context, GSS_C_NO_BUFFER);
 
232
        if (state->server_name != GSS_C_NO_NAME)
 
233
                maj_stat = gss_release_name(&min_stat, &state->server_name);
 
234
        if (state->client_name != GSS_C_NO_NAME)
 
235
                maj_stat = gss_release_name(&min_stat, &state->client_name);
 
236
        if (state->server_creds != GSS_C_NO_CREDENTIAL)
 
237
                maj_stat = gss_release_cred(&min_stat, &state->server_creds);
 
238
        if (state->client_creds != GSS_C_NO_CREDENTIAL)
 
239
                maj_stat = gss_release_cred(&min_stat, &state->client_creds);
 
240
        if (state->username != NULL)
 
241
        {
 
242
                free(state->username);
 
243
                state->username = NULL;
 
244
        }
 
245
        if (state->response != NULL)
 
246
        {
 
247
                free(state->response);
 
248
                state->response = NULL;
 
249
        }
 
250
        
 
251
        return ret;
 
252
}
 
253
 
 
254
int authenticate_gss_server_step(gss_server_state *state, const char *challenge)
 
255
{
 
256
        OM_uint32 maj_stat;
 
257
        OM_uint32 min_stat;
 
258
        gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER;
 
259
        gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER;
 
260
        int ret = AUTH_GSS_CONTINUE;
 
261
        
 
262
        // Always clear out the old response
 
263
        if (state->response != NULL)
 
264
        {
 
265
                free(state->response);
 
266
                state->response = NULL;
 
267
        }
 
268
 
 
269
        // If there is a challenge (data from the server) we need to give it to GSS
 
270
        if (challenge && *challenge)
 
271
        {
 
272
                int len;
 
273
                input_token.value = base64_decode(challenge, &len);
 
274
                input_token.length = len;
 
275
        }
 
276
        else
 
277
        {
 
278
                PyErr_SetString(KrbException_class, "No challenge parameter in request from client");
 
279
                ret = AUTH_GSS_ERROR;
 
280
                goto end;
 
281
        }
 
282
 
 
283
        maj_stat = gss_accept_sec_context(&min_stat,
 
284
                                                                        &state->context,
 
285
                                                                        state->server_creds,
 
286
                                                                        &input_token,
 
287
                                                                        GSS_C_NO_CHANNEL_BINDINGS,
 
288
                                                                        &state->client_name,
 
289
                                                                        NULL,
 
290
                                                                        &output_token,
 
291
                                                                        NULL,
 
292
                                                                        NULL,
 
293
                                                                        &state->client_creds);
 
294
        
 
295
        if (GSS_ERROR(maj_stat))
 
296
        {
 
297
                set_gss_error(maj_stat, min_stat);
 
298
                ret = AUTH_GSS_ERROR;
 
299
                goto end;
 
300
        }
 
301
 
 
302
        // Grab the server response to send back to the client
 
303
        if (output_token.length)
 
304
        {
 
305
                state->response = base64_encode((const unsigned char *)output_token.value, output_token.length);;
 
306
                maj_stat = gss_release_buffer(&min_stat, &output_token);
 
307
        }
 
308
        
 
309
        maj_stat = gss_display_name(&min_stat, state->client_name, &output_token, NULL);
 
310
        if (GSS_ERROR(maj_stat))
 
311
        {
 
312
                set_gss_error(maj_stat, min_stat);
 
313
                ret = AUTH_GSS_ERROR;
 
314
                goto end;
 
315
        }
 
316
        state->username = (char *)malloc(output_token.length + 1);
 
317
        strncpy(state->username, (char*) output_token.value, output_token.length);
 
318
        state->username[output_token.length] = 0;
 
319
        
 
320
        ret = AUTH_GSS_COMPLETE;
 
321
        
 
322
end:
 
323
        if (output_token.length) 
 
324
                gss_release_buffer(&min_stat, &output_token);
 
325
        if (input_token.value)
 
326
                free(input_token.value);
 
327
        return ret;
 
328
}
 
329
 
 
330
 
 
331
static void set_gss_error(OM_uint32 err_maj, OM_uint32 err_min)
 
332
{
 
333
        OM_uint32 maj_stat, min_stat; 
 
334
        OM_uint32 msg_ctx = 0;
 
335
        gss_buffer_desc status_string;
 
336
        char buf_maj[512];
 
337
        char buf_min[512];
 
338
        
 
339
        do
 
340
        {
 
341
                maj_stat = gss_display_status (&min_stat,
 
342
                                                                           err_maj,
 
343
                                                                           GSS_C_GSS_CODE,
 
344
                                                                           GSS_C_NO_OID,
 
345
                                                                           &msg_ctx,
 
346
                                                                           &status_string);
 
347
                if (GSS_ERROR(maj_stat))
 
348
                        break;
 
349
                strncpy(buf_maj, (char*) status_string.value, sizeof(buf_maj));
 
350
                gss_release_buffer(&min_stat, &status_string);
 
351
                
 
352
                maj_stat = gss_display_status (&min_stat,
 
353
                                                                           err_min,
 
354
                                                                           GSS_C_MECH_CODE,
 
355
                                                                           GSS_C_NULL_OID,
 
356
                                                                           &msg_ctx,
 
357
                                                                           &status_string);
 
358
                if (!GSS_ERROR(maj_stat))
 
359
                {
 
360
                        strncpy(buf_min, (char*) status_string.value, sizeof(buf_min));
 
361
                        gss_release_buffer(&min_stat, &status_string);
 
362
                }
 
363
        } while (!GSS_ERROR(maj_stat) && msg_ctx != 0);
 
364
        
 
365
        PyErr_SetObject(GssException_class, Py_BuildValue("((s:i)(s:i))", buf_maj, err_maj, buf_min, err_min));
 
366
}
 
367