~vcs-imports/samba/main

« back to all changes in this revision

Viewing changes to source/libsmb/spnego.c

  • Committer: jerry
  • Date: 2006-07-14 21:48:39 UTC
  • Revision ID: vcs-imports@canonical.com-20060714214839-586d8c489a8fcead
gutting trunk to move to svn:externals

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* 
2
 
   Unix SMB/CIFS implementation.
3
 
 
4
 
   RFC2478 Compliant SPNEGO implementation
5
 
 
6
 
   Copyright (C) Jim McDonough <jmcd@us.ibm.com>   2003
7
 
 
8
 
   This program is free software; you can redistribute it and/or modify
9
 
   it under the terms of the GNU General Public License as published by
10
 
   the Free Software Foundation; either version 2 of the License, or
11
 
   (at your option) any later version.
12
 
   
13
 
   This program is distributed in the hope that it will be useful,
14
 
   but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
 
   GNU General Public License for more details.
17
 
 
18
 
   
19
 
   You should have received a copy of the GNU General Public License
20
 
   along with this program; if not, write to the Free Software
21
 
   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22
 
*/
23
 
 
24
 
#include "includes.h"
25
 
 
26
 
#undef DBGC_CLASS
27
 
#define DBGC_CLASS DBGC_AUTH
28
 
 
29
 
static BOOL read_negTokenInit(ASN1_DATA *asn1, negTokenInit_t *token)
30
 
{
31
 
        ZERO_STRUCTP(token);
32
 
 
33
 
        asn1_start_tag(asn1, ASN1_CONTEXT(0));
34
 
        asn1_start_tag(asn1, ASN1_SEQUENCE(0));
35
 
 
36
 
        while (!asn1->has_error && 0 < asn1_tag_remaining(asn1)) {
37
 
                int i;
38
 
 
39
 
                switch (asn1->data[asn1->ofs]) {
40
 
                /* Read mechTypes */
41
 
                case ASN1_CONTEXT(0):
42
 
                        asn1_start_tag(asn1, ASN1_CONTEXT(0));
43
 
                        asn1_start_tag(asn1, ASN1_SEQUENCE(0));
44
 
 
45
 
                        token->mechTypes = SMB_MALLOC_P(const char *);
46
 
                        for (i = 0; !asn1->has_error &&
47
 
                                     0 < asn1_tag_remaining(asn1); i++) {
48
 
                                char *p_oid = NULL;
49
 
                                token->mechTypes = 
50
 
                                        SMB_REALLOC_ARRAY(token->mechTypes, const char *, i + 2);
51
 
                                if (!token->mechTypes) {
52
 
                                        asn1->has_error = True;
53
 
                                        return False;
54
 
                                }
55
 
                                asn1_read_OID(asn1, &p_oid);
56
 
                                token->mechTypes[i] = p_oid;
57
 
                        }
58
 
                        token->mechTypes[i] = NULL;
59
 
                        
60
 
                        asn1_end_tag(asn1);
61
 
                        asn1_end_tag(asn1);
62
 
                        break;
63
 
                /* Read reqFlags */
64
 
                case ASN1_CONTEXT(1):
65
 
                        asn1_start_tag(asn1, ASN1_CONTEXT(1));
66
 
                        asn1_read_Integer(asn1, &token->reqFlags);
67
 
                        token->reqFlags |= SPNEGO_REQ_FLAG;
68
 
                        asn1_end_tag(asn1);
69
 
                        break;
70
 
                /* Read mechToken */
71
 
                case ASN1_CONTEXT(2):
72
 
                        asn1_start_tag(asn1, ASN1_CONTEXT(2));
73
 
                        asn1_read_OctetString(asn1, &token->mechToken);
74
 
                        asn1_end_tag(asn1);
75
 
                        break;
76
 
                /* Read mecListMIC */
77
 
                case ASN1_CONTEXT(3):
78
 
                        asn1_start_tag(asn1, ASN1_CONTEXT(3));
79
 
                        if (asn1->data[asn1->ofs] == ASN1_OCTET_STRING) {
80
 
                                asn1_read_OctetString(asn1,
81
 
                                                      &token->mechListMIC);
82
 
                        } else {
83
 
                                /* RFC 2478 says we have an Octet String here,
84
 
                                   but W2k sends something different... */
85
 
                                char *mechListMIC;
86
 
                                asn1_push_tag(asn1, ASN1_SEQUENCE(0));
87
 
                                asn1_push_tag(asn1, ASN1_CONTEXT(0));
88
 
                                asn1_read_GeneralString(asn1, &mechListMIC);
89
 
                                asn1_pop_tag(asn1);
90
 
                                asn1_pop_tag(asn1);
91
 
 
92
 
                                token->mechListMIC =
93
 
                                        data_blob(mechListMIC, strlen(mechListMIC));
94
 
                                SAFE_FREE(mechListMIC);
95
 
                        }
96
 
                        asn1_end_tag(asn1);
97
 
                        break;
98
 
                default:
99
 
                        asn1->has_error = True;
100
 
                        break;
101
 
                }
102
 
        }
103
 
 
104
 
        asn1_end_tag(asn1);
105
 
        asn1_end_tag(asn1);
106
 
 
107
 
        return !asn1->has_error;
108
 
}
109
 
 
110
 
static BOOL write_negTokenInit(ASN1_DATA *asn1, negTokenInit_t *token)
111
 
{
112
 
        asn1_push_tag(asn1, ASN1_CONTEXT(0));
113
 
        asn1_push_tag(asn1, ASN1_SEQUENCE(0));
114
 
 
115
 
        /* Write mechTypes */
116
 
        if (token->mechTypes && *token->mechTypes) {
117
 
                int i;
118
 
 
119
 
                asn1_push_tag(asn1, ASN1_CONTEXT(0));
120
 
                asn1_push_tag(asn1, ASN1_SEQUENCE(0));
121
 
                for (i = 0; token->mechTypes[i]; i++) {
122
 
                        asn1_write_OID(asn1, token->mechTypes[i]);
123
 
                }
124
 
                asn1_pop_tag(asn1);
125
 
                asn1_pop_tag(asn1);
126
 
        }
127
 
 
128
 
        /* write reqFlags */
129
 
        if (token->reqFlags & SPNEGO_REQ_FLAG) {
130
 
                int flags = token->reqFlags & ~SPNEGO_REQ_FLAG;
131
 
 
132
 
                asn1_push_tag(asn1, ASN1_CONTEXT(1));
133
 
                asn1_write_Integer(asn1, flags);
134
 
                asn1_pop_tag(asn1);
135
 
        }
136
 
 
137
 
        /* write mechToken */
138
 
        if (token->mechToken.data) {
139
 
                asn1_push_tag(asn1, ASN1_CONTEXT(2));
140
 
                asn1_write_OctetString(asn1, token->mechToken.data,
141
 
                                       token->mechToken.length);
142
 
                asn1_pop_tag(asn1);
143
 
        }
144
 
 
145
 
        /* write mechListMIC */
146
 
        if (token->mechListMIC.data) {
147
 
                asn1_push_tag(asn1, ASN1_CONTEXT(3));
148
 
#if 0
149
 
                /* This is what RFC 2478 says ... */
150
 
                asn1_write_OctetString(asn1, token->mechListMIC.data,
151
 
                                       token->mechListMIC.length);
152
 
#else
153
 
                /* ... but unfortunately this is what Windows
154
 
                   sends/expects */
155
 
                asn1_push_tag(asn1, ASN1_SEQUENCE(0));
156
 
                asn1_push_tag(asn1, ASN1_CONTEXT(0));
157
 
                asn1_push_tag(asn1, ASN1_GENERAL_STRING);
158
 
                asn1_write(asn1, token->mechListMIC.data,
159
 
                           token->mechListMIC.length);
160
 
                asn1_pop_tag(asn1);
161
 
                asn1_pop_tag(asn1);
162
 
                asn1_pop_tag(asn1);
163
 
#endif          
164
 
                asn1_pop_tag(asn1);
165
 
        }
166
 
 
167
 
        asn1_pop_tag(asn1);
168
 
        asn1_pop_tag(asn1);
169
 
 
170
 
        return !asn1->has_error;
171
 
}
172
 
 
173
 
static BOOL read_negTokenTarg(ASN1_DATA *asn1, negTokenTarg_t *token)
174
 
{
175
 
        ZERO_STRUCTP(token);
176
 
 
177
 
        asn1_start_tag(asn1, ASN1_CONTEXT(1));
178
 
        asn1_start_tag(asn1, ASN1_SEQUENCE(0));
179
 
 
180
 
        while (!asn1->has_error && 0 < asn1_tag_remaining(asn1)) {
181
 
                switch (asn1->data[asn1->ofs]) {
182
 
                case ASN1_CONTEXT(0):
183
 
                        asn1_start_tag(asn1, ASN1_CONTEXT(0));
184
 
                        asn1_start_tag(asn1, ASN1_ENUMERATED);
185
 
                        asn1_read_uint8(asn1, &token->negResult);
186
 
                        asn1_end_tag(asn1);
187
 
                        asn1_end_tag(asn1);
188
 
                        break;
189
 
                case ASN1_CONTEXT(1):
190
 
                        asn1_start_tag(asn1, ASN1_CONTEXT(1));
191
 
                        asn1_read_OID(asn1, &token->supportedMech);
192
 
                        asn1_end_tag(asn1);
193
 
                        break;
194
 
                case ASN1_CONTEXT(2):
195
 
                        asn1_start_tag(asn1, ASN1_CONTEXT(2));
196
 
                        asn1_read_OctetString(asn1, &token->responseToken);
197
 
                        asn1_end_tag(asn1);
198
 
                        break;
199
 
                case ASN1_CONTEXT(3):
200
 
                        asn1_start_tag(asn1, ASN1_CONTEXT(3));
201
 
                        asn1_read_OctetString(asn1, &token->mechListMIC);
202
 
                        asn1_end_tag(asn1);
203
 
                        break;
204
 
                default:
205
 
                        asn1->has_error = True;
206
 
                        break;
207
 
                }
208
 
        }
209
 
 
210
 
        asn1_end_tag(asn1);
211
 
        asn1_end_tag(asn1);
212
 
 
213
 
        return !asn1->has_error;
214
 
}
215
 
 
216
 
static BOOL write_negTokenTarg(ASN1_DATA *asn1, negTokenTarg_t *token)
217
 
{
218
 
        asn1_push_tag(asn1, ASN1_CONTEXT(1));
219
 
        asn1_push_tag(asn1, ASN1_SEQUENCE(0));
220
 
 
221
 
        asn1_push_tag(asn1, ASN1_CONTEXT(0));
222
 
        asn1_write_enumerated(asn1, token->negResult);
223
 
        asn1_pop_tag(asn1);
224
 
 
225
 
        if (token->supportedMech) {
226
 
                asn1_push_tag(asn1, ASN1_CONTEXT(1));
227
 
                asn1_write_OID(asn1, token->supportedMech);
228
 
                asn1_pop_tag(asn1);
229
 
        }
230
 
 
231
 
        if (token->responseToken.data) {
232
 
                asn1_push_tag(asn1, ASN1_CONTEXT(2));
233
 
                asn1_write_OctetString(asn1, token->responseToken.data,
234
 
                                       token->responseToken.length);
235
 
                asn1_pop_tag(asn1);
236
 
        }
237
 
 
238
 
        if (token->mechListMIC.data) {
239
 
                asn1_push_tag(asn1, ASN1_CONTEXT(3));
240
 
                asn1_write_OctetString(asn1, token->mechListMIC.data,
241
 
                                      token->mechListMIC.length);
242
 
                asn1_pop_tag(asn1);
243
 
        }
244
 
 
245
 
        asn1_pop_tag(asn1);
246
 
        asn1_pop_tag(asn1);
247
 
 
248
 
        return !asn1->has_error;
249
 
}
250
 
 
251
 
ssize_t read_spnego_data(DATA_BLOB data, SPNEGO_DATA *token)
252
 
{
253
 
        ASN1_DATA asn1;
254
 
        ssize_t ret = -1;
255
 
 
256
 
        ZERO_STRUCTP(token);
257
 
        ZERO_STRUCT(asn1);
258
 
        asn1_load(&asn1, data);
259
 
 
260
 
        switch (asn1.data[asn1.ofs]) {
261
 
        case ASN1_APPLICATION(0):
262
 
                asn1_start_tag(&asn1, ASN1_APPLICATION(0));
263
 
                asn1_check_OID(&asn1, OID_SPNEGO);
264
 
                if (read_negTokenInit(&asn1, &token->negTokenInit)) {
265
 
                        token->type = SPNEGO_NEG_TOKEN_INIT;
266
 
                }
267
 
                asn1_end_tag(&asn1);
268
 
                break;
269
 
        case ASN1_CONTEXT(1):
270
 
                if (read_negTokenTarg(&asn1, &token->negTokenTarg)) {
271
 
                        token->type = SPNEGO_NEG_TOKEN_TARG;
272
 
                }
273
 
                break;
274
 
        default:
275
 
                break;
276
 
        }
277
 
 
278
 
        if (!asn1.has_error) ret = asn1.ofs;
279
 
        asn1_free(&asn1);
280
 
 
281
 
        return ret;
282
 
}
283
 
 
284
 
ssize_t write_spnego_data(DATA_BLOB *blob, SPNEGO_DATA *spnego)
285
 
{
286
 
        ASN1_DATA asn1;
287
 
        ssize_t ret = -1;
288
 
 
289
 
        ZERO_STRUCT(asn1);
290
 
 
291
 
        switch (spnego->type) {
292
 
        case SPNEGO_NEG_TOKEN_INIT:
293
 
                asn1_push_tag(&asn1, ASN1_APPLICATION(0));
294
 
                asn1_write_OID(&asn1, OID_SPNEGO);
295
 
                write_negTokenInit(&asn1, &spnego->negTokenInit);
296
 
                asn1_pop_tag(&asn1);
297
 
                break;
298
 
        case SPNEGO_NEG_TOKEN_TARG:
299
 
                write_negTokenTarg(&asn1, &spnego->negTokenTarg);
300
 
                break;
301
 
        default:
302
 
                asn1.has_error = True;
303
 
                break;
304
 
        }
305
 
 
306
 
        if (!asn1.has_error) {
307
 
                *blob = data_blob(asn1.data, asn1.length);
308
 
                ret = asn1.ofs;
309
 
        }
310
 
        asn1_free(&asn1);
311
 
 
312
 
        return ret;
313
 
}
314
 
 
315
 
BOOL free_spnego_data(SPNEGO_DATA *spnego)
316
 
{
317
 
        BOOL ret = True;
318
 
 
319
 
        if (!spnego) goto out;
320
 
 
321
 
        switch(spnego->type) {
322
 
        case SPNEGO_NEG_TOKEN_INIT:
323
 
                if (spnego->negTokenInit.mechTypes) {
324
 
                        int i;
325
 
                        for (i = 0; spnego->negTokenInit.mechTypes[i]; i++) {
326
 
                                free(CONST_DISCARD(char *,spnego->negTokenInit.mechTypes[i]));
327
 
                        }
328
 
                        free(spnego->negTokenInit.mechTypes);
329
 
                }
330
 
                data_blob_free(&spnego->negTokenInit.mechToken);
331
 
                data_blob_free(&spnego->negTokenInit.mechListMIC);
332
 
                break;
333
 
        case SPNEGO_NEG_TOKEN_TARG:
334
 
                if (spnego->negTokenTarg.supportedMech) {
335
 
                        free(spnego->negTokenTarg.supportedMech);
336
 
                }
337
 
                data_blob_free(&spnego->negTokenTarg.responseToken);
338
 
                data_blob_free(&spnego->negTokenTarg.mechListMIC);
339
 
                break;
340
 
        default:
341
 
                ret = False;
342
 
                break;
343
 
        }
344
 
        ZERO_STRUCTP(spnego);
345
 
out:
346
 
        return ret;
347
 
}