summaryrefslogtreecommitdiff
path: root/src/http_auth.c
blob: 6d2ed2058d667cd964a09f608e97d5b65e813cf6 (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
#include "first.h"

#include "http_auth.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[8];

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));
}

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(array *env, const char *username, size_t ulen, const char *auth_type, size_t alen) {
    data_string *ds;

    /* REMOTE_USER */

    if (NULL == (ds = (data_string *)array_get_element(env, "REMOTE_USER"))) {
        if (NULL == (ds = (data_string *)array_get_unused_element(env, TYPE_STRING))) {
            ds = data_string_init();
        }
        buffer_copy_string_len(ds->key, CONST_STR_LEN("REMOTE_USER"));
        array_insert_unique(env, (data_unset *)ds);
    }
    buffer_copy_string_len(ds->value, username, ulen);

    /* AUTH_TYPE */

    if (NULL == (ds = (data_string *)array_get_element(env, "AUTH_TYPE"))) {
        if (NULL == (ds = (data_string *)array_get_unused_element(env, TYPE_STRING))) {
            ds = data_string_init();
        }
        buffer_copy_string_len(ds->key, CONST_STR_LEN("AUTH_TYPE"));
        array_insert_unique(env, (data_unset *)ds);
    }
    buffer_copy_string_len(ds->value, 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