summaryrefslogtreecommitdiff
path: root/data/lighttpd/lighttpd-1.4.53/src/http_auth.c
blob: 484da8ff2cfaac79ba8a44fdfbce507b5c9755b4 (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
#include "first.h"

#include "http_auth.h"
#include "http_header.h"

#include <stdlib.h>
#include <string.h>


static http_auth_scheme_t http_auth_schemes[8];

const http_auth_scheme_t * http_auth_scheme_get (const buffer *name)
{
    int i = 0;
    while (NULL != http_auth_schemes[i].name
           && 0 != strcmp(http_auth_schemes[i].name, name->ptr)) {
        ++i;
    }
    return (NULL != http_auth_schemes[i].name) ? http_auth_schemes+i : NULL;
}

void http_auth_scheme_set (const http_auth_scheme_t *scheme)
{
    unsigned int i = 0;
    while (NULL != http_auth_schemes[i].name) ++i;
    /*(must resize http_auth_schemes[] if too many different auth schemes)*/
    force_assert(i<(sizeof(http_auth_schemes)/sizeof(http_auth_scheme_t))-1);
    memcpy(http_auth_schemes+i, scheme, sizeof(http_auth_scheme_t));
}


static http_auth_backend_t http_auth_backends[12];

const http_auth_backend_t * http_auth_backend_get (const buffer *name)
{
    int i = 0;
    while (NULL != http_auth_backends[i].name
           && 0 != strcmp(http_auth_backends[i].name, name->ptr)) {
        ++i;
    }
    return (NULL != http_auth_backends[i].name) ? http_auth_backends+i : NULL;
}

void http_auth_backend_set (const http_auth_backend_t *backend)
{
    unsigned int i = 0;
    while (NULL != http_auth_backends[i].name) ++i;
    /*(must resize http_auth_backends[] if too many different auth backends)*/
    force_assert(i<(sizeof(http_auth_backends)/sizeof(http_auth_backend_t))-1);
    memcpy(http_auth_backends+i, backend, sizeof(http_auth_backend_t));
}


int http_auth_const_time_memeq (const char *a, const size_t alen, const char *b, const size_t blen)
{
    /* constant time memory compare, unless compiler figures it out
     * (similar to mod_secdownload.c:const_time_memeq()) */
    /* round to next multiple of 64 to avoid potentially leaking exact
     * password length when subject to high precision timing attacks) */
    size_t lim = ((alen >= blen ? alen : blen) + 0x3F) & ~0x3F;
    int diff = 0;
    for (size_t i = 0, j = 0; lim; --lim) {
        diff |= (a[i] ^ b[j]);
        i += (i < alen);
        j += (j < blen);
    }
    return (0 == diff);
}


void http_auth_dumbdata_reset (void)
{
    memset(http_auth_schemes, 0, sizeof(http_auth_schemes));
    memset(http_auth_backends, 0, sizeof(http_auth_backends));
}


http_auth_require_t * http_auth_require_init (void)
{
    http_auth_require_t *require = calloc(1, sizeof(http_auth_require_t));
    force_assert(NULL != require);

    require->realm = buffer_init();
    require->valid_user = 0;
    require->user = array_init();
    require->group = array_init();
    require->host = array_init();

    return require;
}

void http_auth_require_free (http_auth_require_t * const require)
{
    buffer_free(require->realm);
    array_free(require->user);
    array_free(require->group);
    array_free(require->host);
    free(require);
}

/* (case-sensitive version of array.c:array_get_index(),
 *  and common case expects small num of allowed tokens,
 *  so it is reasonably performant to simply walk the array) */
static int http_auth_array_contains (const array * const a, const char * const k, const size_t klen)
{
    for (size_t i = 0, used = a->used; i < used; ++i) {
        if (buffer_is_equal_string(a->data[i]->key, k, klen)) {
            return 1;
        }
    }
    return 0;
}

int http_auth_match_rules (const http_auth_require_t * const require, const char * const user, const char * const group, const char * const host)
{
    if (NULL != user
        && (require->valid_user
            || http_auth_array_contains(require->user, user, strlen(user)))) {
        return 1; /* match */
    }

    if (NULL != group
        && http_auth_array_contains(require->group, group, strlen(group))) {
        return 1; /* match */
    }

    if (NULL != host
        && http_auth_array_contains(require->host, host, strlen(host))) {
        return 1; /* match */
    }

    return 0; /* no match */
}

void http_auth_setenv(connection *con, const char *username, size_t ulen, const char *auth_type, size_t alen) {
    http_header_env_set(con, CONST_STR_LEN("REMOTE_USER"), username, ulen);
    http_header_env_set(con, CONST_STR_LEN("AUTH_TYPE"), auth_type, alen);
}

int http_auth_md5_hex2bin (const char *md5hex, size_t len, unsigned char md5bin[16])
{
    /* validate and transform 32-byte MD5 hex string to 16-byte binary MD5 */
    if (32 != len) return -1; /*(Note: char *md5hex must be a 32-char string)*/
    for (int i = 0; i < 32; i+=2) {
        int hi = md5hex[i];
        int lo = md5hex[i+1];
        if ('0' <= hi && hi <= '9')                    hi -= '0';
        else if ((hi |= 0x20), 'a' <= hi && hi <= 'f') hi += -'a' + 10;
        else                                           return -1;
        if ('0' <= lo && lo <= '9')                    lo -= '0';
        else if ((lo |= 0x20), 'a' <= lo && lo <= 'f') lo += -'a' + 10;
        else                                           return -1;
        md5bin[(i >> 1)] = (unsigned char)((hi << 4) | lo);
    }
    return 0;
}

#if 0
int http_auth_md5_hex2lc (char *md5hex)
{
    /* validate and transform 32-byte MD5 hex string to lowercase */
    int i;
    for (i = 0; md5hex[i]; ++i) {
        int c = md5hex[i];
        if ('0' <= c && c <= '9')                   continue;
        else if ((c |= 0x20), 'a' <= c && c <= 'f') md5hex[i] = c;
        else                                        return -1;
    }
    return (32 == i) ? 0 : -1; /*(Note: char *md5hex must be a 32-char string)*/
}
#endif