OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [ecos-3.0/] [packages/] [net/] [athttpd/] [current/] [src/] [auth.c] - Blame information for rev 867

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 786 skrzyp
/* =================================================================
2
 *
3
 *      auth.c
4
 *
5
 *      Handles basic authentication.
6
 *
7
 * =================================================================
8
 * ####ECOSGPLCOPYRIGHTBEGIN####
9
 * -------------------------------------------
10
 * This file is part of eCos, the Embedded Configurable Operating System.
11
 * Copyright (C) 2005 Free Software Foundation, Inc.
12
 *
13
 * eCos is free software; you can redistribute it and/or modify it under
14
 * the terms of the GNU General Public License as published by the Free
15
 * Software Foundation; either version 2 or (at your option) any later
16
 * version.
17
 *
18
 * eCos is distributed in the hope that it will be useful, but WITHOUT
19
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
20
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
21
 * for more details.
22
 *
23
 * You should have received a copy of the GNU General Public License
24
 * along with eCos; if not, write to the Free Software Foundation, Inc.,
25
 * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
26
 *
27
 * As a special exception, if other files instantiate templates or use
28
 * macros or inline functions from this file, or you compile this file
29
 * and link it with other works to produce a work based on this file,
30
 * this file does not by itself cause the resulting work to be covered by
31
 * the GNU General Public License. However the source code for this file
32
 * must still be made available in accordance with section (3) of the GNU
33
 * General Public License v2.
34
 *
35
 * This exception does not invalidate any other reasons why a work based
36
 * on this file might be covered by the GNU General Public License.
37
 * -------------------------------------------
38
 * ####ECOSGPLCOPYRIGHTEND####
39
 * =================================================================
40
 * #####DESCRIPTIONBEGIN####
41
 *
42
 *  Author(s):    Anthony Tonizzo (atonizzo@gmail.com)
43
 *  Contributors:
44
 *  Date:         2006-06-12
45
 *  Purpose:
46
 *  Description:
47
 *
48
 * ####DESCRIPTIONEND####
49
 *
50
 * =================================================================
51
 */
52
#include <pkgconf/hal.h>
53
#include <pkgconf/kernel.h>
54
#include <cyg/kernel/kapi.h>           // Kernel API.
55
#include <cyg/hal/hal_tables.h>
56
 
57
#include <stdio.h>
58
 
59
#include <network.h>
60
#include <string.h>
61
 
62
#include <cyg/athttpd/http.h>
63
#include <cyg/athttpd/md5.h>
64
 
65
// This is a string that contains the domain that is currently authorized.
66
cyg_uint8 *cyg_httpd_current_authName;
67
 
68
CYG_HAL_TABLE_BEGIN(cyg_httpd_auth_table, httpd_auth_table );
69
CYG_HAL_TABLE_END(cyg_httpd_auth_table_end, httpd_auth_table );
70
 
71
__externC cyg_httpd_auth_table_entry cyg_httpd_auth_table[];
72
__externC cyg_httpd_auth_table_entry cyg_httpd_auth_table_end[];
73
 
74
// Variables used for authorization. The header parsing code will only copy
75
//  up to AUTH_STORAGE_BUFFER_LENGTH bytes into cyg_httpd_md5_response to
76
//  avoid overflow.
77
char cyg_httpd_md5_response[AUTH_STORAGE_BUFFER_LENGTH + 1];
78
char cyg_httpd_md5_digest[AUTH_STORAGE_BUFFER_LENGTH + 1];
79
char cyg_httpd_md5_nonce[33];
80
char cyg_httpd_md5_cnonce[33];
81
char cyg_httpd_md5_noncecount[9];
82
char cyg_httpd_md5_ha2[HASHHEXLEN+1] = {'\0'};
83
char cyg_httpd_md5_ha1[HASHHEXLEN+1];
84
 
85
char b64string[] =
86
    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
87
 
88
cyg_httpd_auth_table_entry*
89
cyg_httpd_auth_entry_from_path(char *authPath)
90
{
91
    cyg_httpd_auth_table_entry *entry = cyg_httpd_auth_table;
92
    if (strcmp(authPath, "/") != 0)
93
        while (entry != cyg_httpd_auth_table_end)
94
        {
95
            if (strncmp(entry->auth_dirname,
96
                        authPath,
97
                        strlen(entry->auth_dirname)) == 0)
98
                return entry;
99
            entry++;
100
        }
101
    else
102
        while (entry != cyg_httpd_auth_table_end)
103
        {
104
            if (strcmp(entry->auth_dirname, authPath) == 0)
105
                return entry;
106
            entry++;
107
        }
108
 
109
    return (cyg_httpd_auth_table_entry *)0;
110
}
111
 
112
cyg_httpd_auth_table_entry*
113
cyg_httpd_auth_entry_from_domain(char *authDomain)
114
{
115
    cyg_httpd_auth_table_entry *entry = cyg_httpd_auth_table;
116
    while (entry != cyg_httpd_auth_table_end)
117
    {
118
        if (!strncmp((const char*)authDomain,
119
                       entry->auth_domainname,
120
                       strlen(entry->auth_domainname)))
121
            return entry;
122
        entry++;
123
    }
124
 
125
    return (cyg_httpd_auth_table_entry *)0;
126
}
127
 
128
static cyg_int32
129
cyg_httpd_base64_decode(char* to, char* from, cyg_uint32 len )
130
{
131
    char     *fromp = from;
132
    char     *top = to;
133
    char     *p;
134
    char      cbyte;
135
    char      obyte;
136
    cyg_int32 padding = 0;
137
 
138
    for (; len >= 4; len -= 4)
139
    {
140
        if ((cbyte = *fromp++) == '=')
141
            cbyte = 0;
142
        else
143
        {
144
            if (badchar(cbyte, p ) )
145
                return -1;
146
            cbyte = (p - b64string);
147
        }
148
        obyte = cbyte << 2;
149
 
150
        if ((cbyte = *fromp++) == '=')
151
            cbyte = 0;
152
        else
153
        {
154
            if (badchar(cbyte, p))
155
                return -1;
156
            cbyte = p - b64string;
157
        }
158
        obyte |= cbyte >> 4;
159
        *top++ = obyte;
160
 
161
        obyte = cbyte << 4;
162
        if ((cbyte = *fromp++) == '=')
163
        {
164
            cbyte = 0;
165
            padding++;
166
        }
167
        else
168
        {
169
            padding = 0;
170
            if (badchar(cbyte, p))
171
                return -1;
172
            cbyte = p - b64string;
173
        }
174
        obyte |= cbyte >> 2;
175
        *top++ = obyte;
176
 
177
        obyte = cbyte << 6;
178
        if ((cbyte = *fromp++) == '=')
179
        {
180
            cbyte = 0;
181
            padding++;
182
        }
183
        else
184
        {
185
            padding = 0;
186
            if (badchar(cbyte, p))
187
                return -1;
188
            cbyte = p - b64string;
189
        }
190
        obyte |= cbyte;
191
        *top++ = obyte;
192
    }
193
 
194
    *top = 0;
195
    if (len)
196
        return -1;
197
    return (top - to) - padding;
198
}
199
 
200
// The following code is a slightly modified version of those available at the
201
//  end of RFC1270.
202
static void cyg_httpd_cvthex(HASH Bin, HASHHEX Hex)
203
{
204
    unsigned short i;
205
    unsigned char j;
206
 
207
    for (i = 0; i < HASHLEN; i++)
208
    {
209
        j = (Bin[i] >> 4) & 0xf;
210
        if (j <= 9)
211
            Hex[i*2] = (j + '0');
212
         else
213
            Hex[i*2] = (j + 'a' - 10);
214
        j = Bin[i] & 0xf;
215
        if (j <= 9)
216
            Hex[i*2+1] = (j + '0');
217
         else
218
            Hex[i*2+1] = (j + 'a' - 10);
219
    };
220
    Hex[HASHHEXLEN] = '\0';
221
};
222
 
223
// Calculate H(A1) as per spec.
224
static void
225
cyg_httpd_digest_calc_HA1( char    *pszAlg,
226
                           char    *pszUserName,
227
                           char    *pszRealm,
228
                           char    *pszPassword,
229
                           char    *pszNonce,
230
                           char    *pszCNonce,
231
                           HASHHEX  SessionKey )
232
{
233
      MD5_CTX Md5Ctx;
234
      HASH HA1;
235
 
236
      MD5Init(&Md5Ctx);
237
      MD5Update(&Md5Ctx, (unsigned char*)pszUserName, strlen(pszUserName));
238
      MD5Update(&Md5Ctx, (unsigned char*)":", 1);
239
      MD5Update(&Md5Ctx, (unsigned char*)pszRealm, strlen(pszRealm));
240
      MD5Update(&Md5Ctx, (unsigned char*)":", 1);
241
      MD5Update(&Md5Ctx, (unsigned char*)pszPassword, strlen(pszPassword));
242
      MD5Final((unsigned char*)HA1, &Md5Ctx);
243
      if (strcmp(pszAlg, "md5-sess") == 0)
244
      {
245
          MD5Init(&Md5Ctx);
246
          MD5Update(&Md5Ctx, (unsigned char*)HA1, HASHLEN);
247
          MD5Update(&Md5Ctx, (unsigned char*)":", 1);
248
          MD5Update(&Md5Ctx, (unsigned char*)pszNonce, strlen(pszNonce));
249
          MD5Update(&Md5Ctx, (unsigned char*)":", 1);
250
          MD5Update(&Md5Ctx, (unsigned char*)pszCNonce, strlen(pszCNonce));
251
          MD5Final((unsigned char*)HA1, &Md5Ctx);
252
      };
253
      cyg_httpd_cvthex(HA1, SessionKey);
254
};
255
 
256
// Calculate request-digest/response-digest as per HTTP Digest spec.
257
void
258
cyg_httpd_digest_calc_response(HASHHEX  HA1,
259
                               char    *pszNonce,
260
                               char    *pszNonceCount,
261
                               char    *pszCNonce,
262
                               char    *pszQop,
263
                               char    *pszMethod,
264
                               char    *pszDigestUri,
265
                               HASHHEX  HEntity,
266
                               HASHHEX  Response)
267
{
268
    MD5_CTX Md5Ctx;
269
    HASH HA2;
270
    HASH RespHash;
271
    HASHHEX HA2Hex;
272
 
273
    // Calculate H(A2).
274
    MD5Init(&Md5Ctx);
275
    MD5Update(&Md5Ctx, (unsigned char*)pszMethod, strlen(pszMethod));
276
    MD5Update(&Md5Ctx, (unsigned char*)":", 1);
277
    MD5Update(&Md5Ctx, (unsigned char*)pszDigestUri, strlen(pszDigestUri));
278
    if (strcmp(pszQop, "auth-int") == 0) {
279
        MD5Update(&Md5Ctx, (unsigned char*)":", 1);
280
        MD5Update(&Md5Ctx, (unsigned char*)HEntity, HASHHEXLEN);
281
    };
282
    MD5Final((unsigned char*)HA2, &Md5Ctx);
283
    cyg_httpd_cvthex(HA2, HA2Hex);
284
 
285
    // calculate response
286
    MD5Init(&Md5Ctx);
287
    MD5Update(&Md5Ctx, (unsigned char*)HA1, HASHHEXLEN);
288
    MD5Update(&Md5Ctx, (unsigned char*)":", 1);
289
    MD5Update(&Md5Ctx, (unsigned char*)pszNonce, strlen(pszNonce));
290
    MD5Update(&Md5Ctx, (unsigned char*)":", 1);
291
    if (*pszQop)
292
    {
293
        MD5Update(&Md5Ctx, (unsigned char*)pszNonceCount, strlen(pszNonceCount));
294
        MD5Update(&Md5Ctx, (unsigned char*)":", 1);
295
        MD5Update(&Md5Ctx, (unsigned char*)pszCNonce, strlen(pszCNonce));
296
        MD5Update(&Md5Ctx, (unsigned char*)":", 1);
297
        MD5Update(&Md5Ctx, (unsigned char*)pszQop, strlen(pszQop));
298
        MD5Update(&Md5Ctx, (unsigned char*)":", 1);
299
    };
300
    MD5Update(&Md5Ctx, (unsigned char*)HA2Hex, HASHHEXLEN);
301
    MD5Final((unsigned char*)RespHash, &Md5Ctx);
302
    cyg_httpd_cvthex(RespHash, Response);
303
};
304
 
305
cyg_httpd_auth_table_entry*
306
cyg_httpd_is_authenticated(char* fname)
307
{
308
    // Let's check if the directory access needs authorization. The 
309
    //  authentication is done on the directory name.
310
    cyg_httpd_auth_table_entry* entry =
311
                                cyg_httpd_auth_entry_from_path(fname);
312
    if (entry != 0)
313
    {
314
        if (entry->auth_mode == CYG_HTTPD_AUTH_BASIC)
315
        {
316
            cyg_httpd_base64_decode(cyg_httpd_md5_digest,
317
                                    cyg_httpd_md5_response,
318
                                    strlen(cyg_httpd_md5_response));
319
            char *colon = rindex(cyg_httpd_md5_digest, ':');
320
            if (colon == NULL)
321
            {
322
                return (httpstate.needs_auth = entry);
323
            }
324
            else
325
            {
326
                *colon = '\0'; // Crypto now has the username.
327
 
328
                // In the case of a 'Basic" authentication, the HTTP header
329
                //  did not return to us the domain name that we sent when we
330
                //  challenged the request: The only things that are returned 
331
                //  are the username:password duo. In this case I will just 
332
                //  compare the entry's username/password to those read from 
333
                //  the header.
334
                if ((strcmp(entry->auth_username,cyg_httpd_md5_digest) != 0) ||
335
                                 (strcmp(entry->auth_password, ++colon) != 0))
336
                    return (httpstate.needs_auth = entry);
337
            }
338
        }
339
        else
340
        {
341
            char *cyg_httpd_md5_method;
342
 
343
            switch (httpstate.method)
344
            {
345
            case CYG_HTTPD_METHOD_GET:
346
                cyg_httpd_md5_method = "GET";
347
                break;
348
            case CYG_HTTPD_METHOD_POST:
349
                cyg_httpd_md5_method = "POST";
350
                break;
351
            default:
352
                cyg_httpd_md5_method = "HEAD";
353
                break;
354
            }
355
            cyg_httpd_digest_calc_HA1(CYG_HTTPD_MD5_AUTH_NAME,
356
                                      entry->auth_username,
357
                                      entry->auth_domainname,
358
                                      entry->auth_password,
359
                                      cyg_httpd_md5_nonce,
360
                                      cyg_httpd_md5_cnonce,
361
                                      cyg_httpd_md5_ha1);
362
            cyg_httpd_digest_calc_response(cyg_httpd_md5_ha1,
363
                                           cyg_httpd_md5_nonce,
364
                                           cyg_httpd_md5_noncecount,
365
                                           cyg_httpd_md5_cnonce,
366
                                           CYG_HTTPD_MD5_AUTH_QOP,
367
                                           cyg_httpd_md5_method,
368
                                           httpstate.url,
369
                                           cyg_httpd_md5_ha2,
370
                                           cyg_httpd_md5_digest);
371
            if (strcmp(cyg_httpd_md5_response, cyg_httpd_md5_digest) != 0)
372
                return (httpstate.needs_auth = entry);
373
        }
374
    }
375
    // No need for authentication...
376
    return (cyg_httpd_auth_table_entry*)0;
377
}
378
 
379
char*
380
cyg_httpd_digest_data(char *dest, char *src)
381
{
382
    int exit = 0;
383
    while (exit == 0)
384
    {
385
        switch (*src )
386
        {
387
        case '\r':
388
        case '\n':
389
            *dest = '\0';
390
            exit = 1;
391
            break;
392
        case ',':
393
            // If it is a comma there might or might not be a blank space
394
            //  following it (IE7 inserts no spaces, everyone else does...)
395
            //  so before exiting the loop remove any blank space that follows.
396
            if (src[1] == ' ')
397
                src++;
398
        case ' ':
399
            src++;
400
            *dest = '\0';
401
            exit = 1;
402
            break;
403
        case '"':
404
            src++;
405
            break;
406
        default:
407
            *dest++ = *src++;
408
        }
409
    }
410
    return src;
411
}
412
 
413
// Skips through fields we do not need.
414
char*
415
cyg_httpd_digest_skip(char *p)
416
{
417
    if (*p == '"')
418
    {
419
        p++;
420
        while ((*p != '"') && (*p != '\n'))
421
            p++;
422
        p++;
423
        if (*p == ',')
424
            p++;
425
        if (*p == ' ')
426
            p++;
427
        if (*p == '\n')
428
            p++;
429
    }
430
    else
431
    {
432
        while ((*p != ' ') && (*p != '\n'))
433
            p++;
434
        if (*p == ',')
435
            p++;
436
        if (*p == ' ')
437
            p++;
438
        if (*p == '\n')
439
            p++;
440
    }
441
    return p;
442
}

powered by: WebSVN 2.1.0

© copyright 1999-2025 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.