- next is 1.4.56
[lighttpd.git] / src / http_auth.c
blobbedb5fe047ef9972981c055bcd28ba650fe51cd5
1 #include "first.h"
3 #include "http_auth.h"
4 #include "http_header.h"
6 #include <stdlib.h>
7 #include <string.h>
10 static http_auth_scheme_t http_auth_schemes[8];
12 const http_auth_scheme_t * http_auth_scheme_get (const buffer *name)
14 int i = 0;
15 while (NULL != http_auth_schemes[i].name
16 && 0 != strcmp(http_auth_schemes[i].name, name->ptr)) {
17 ++i;
19 return (NULL != http_auth_schemes[i].name) ? http_auth_schemes+i : NULL;
22 void http_auth_scheme_set (const http_auth_scheme_t *scheme)
24 unsigned int i = 0;
25 while (NULL != http_auth_schemes[i].name) ++i;
26 /*(must resize http_auth_schemes[] if too many different auth schemes)*/
27 force_assert(i<(sizeof(http_auth_schemes)/sizeof(http_auth_scheme_t))-1);
28 memcpy(http_auth_schemes+i, scheme, sizeof(http_auth_scheme_t));
32 static http_auth_backend_t http_auth_backends[12];
34 const http_auth_backend_t * http_auth_backend_get (const buffer *name)
36 int i = 0;
37 while (NULL != http_auth_backends[i].name
38 && 0 != strcmp(http_auth_backends[i].name, name->ptr)) {
39 ++i;
41 return (NULL != http_auth_backends[i].name) ? http_auth_backends+i : NULL;
44 void http_auth_backend_set (const http_auth_backend_t *backend)
46 unsigned int i = 0;
47 while (NULL != http_auth_backends[i].name) ++i;
48 /*(must resize http_auth_backends[] if too many different auth backends)*/
49 force_assert(i<(sizeof(http_auth_backends)/sizeof(http_auth_backend_t))-1);
50 memcpy(http_auth_backends+i, backend, sizeof(http_auth_backend_t));
54 int http_auth_const_time_memeq (const void *a, const void *b, const size_t len)
56 /* constant time memory compare, unless compiler figures it out
57 * (similar to mod_secdownload.c:const_time_memeq()) */
58 /* caller should prefer http_auth_const_time_memeq_pad()
59 * if not operating on digests, which have defined lengths */
60 /* Note: some libs provide similar funcs, e.g.
61 * OpenSSL:
62 * int CRYPTO_memcmp(const void * in_a, const void * in_b, size_t len)
63 * Note: some OS provide similar funcs, e.g.
64 * OpenBSD: int timingsafe_bcmp(const void *b1, const void *b2, size_t len)
65 * NetBSD: int consttime_memequal(void *b1, void *b2, size_t len)
67 const volatile unsigned char * const av = (const unsigned char *)a;
68 const volatile unsigned char * const bv = (const unsigned char *)b;
69 int diff = 0;
70 for (size_t i = 0; i < len; ++i) {
71 diff |= (av[i] ^ bv[i]);
73 return (0 == diff);
77 int http_auth_const_time_memeq_pad (const void *a, const size_t alen, const void *b, const size_t blen)
79 /* constant time memory compare, unless compiler figures it out
80 * (similar to mod_secdownload.c:const_time_memeq()) */
81 /* round to next multiple of 64 to avoid potentially leaking exact
82 * password length when subject to high precision timing attacks)
83 * (not necessary when comparing digests, which have defined lengths)
85 /* Note: some libs provide similar funcs but might not obscure length, e.g.
86 * OpenSSL:
87 * int CRYPTO_memcmp(const void * in_a, const void * in_b, size_t len)
88 * Note: some OS provide similar funcs but might not obscure length, e.g.
89 * OpenBSD: int timingsafe_bcmp(const void *b1, const void *b2, size_t len)
90 * NetBSD: int consttime_memequal(void *b1, void *b2, size_t len)
92 const volatile unsigned char * const av = (const unsigned char *)a;
93 const volatile unsigned char * const bv = (const unsigned char *)b;
94 size_t lim = ((alen >= blen ? alen : blen) + 0x3F) & ~0x3F;
95 int diff = (alen != blen); /*(never match if string length mismatch)*/
96 for (size_t i = 0, j = 0; lim; --lim) {
97 diff |= (av[i] ^ bv[j]);
98 i += (i < alen);
99 j += (j < blen);
101 return (0 == diff);
105 void http_auth_dumbdata_reset (void)
107 memset(http_auth_schemes, 0, sizeof(http_auth_schemes));
108 memset(http_auth_backends, 0, sizeof(http_auth_backends));
112 http_auth_require_t * http_auth_require_init (void)
114 http_auth_require_t *require = calloc(1, sizeof(http_auth_require_t));
115 force_assert(NULL != require);
117 require->realm = buffer_init();
118 require->valid_user = 0;
119 require->user = array_init();
120 require->group = array_init();
121 require->host = array_init();
123 return require;
126 void http_auth_require_free (http_auth_require_t * const require)
128 buffer_free(require->realm);
129 array_free(require->user);
130 array_free(require->group);
131 array_free(require->host);
132 free(require);
135 /* (case-sensitive version of array.c:array_get_index(),
136 * and common case expects small num of allowed tokens,
137 * so it is reasonably performant to simply walk the array) */
138 static int http_auth_array_contains (const array * const a, const char * const k, const size_t klen)
140 for (size_t i = 0, used = a->used; i < used; ++i) {
141 if (buffer_is_equal_string(a->data[i]->key, k, klen)) {
142 return 1;
145 return 0;
148 int http_auth_match_rules (const http_auth_require_t * const require, const char * const user, const char * const group, const char * const host)
150 if (NULL != user
151 && (require->valid_user
152 || http_auth_array_contains(require->user, user, strlen(user)))) {
153 return 1; /* match */
156 if (NULL != group
157 && http_auth_array_contains(require->group, group, strlen(group))) {
158 return 1; /* match */
161 if (NULL != host
162 && http_auth_array_contains(require->host, host, strlen(host))) {
163 return 1; /* match */
166 return 0; /* no match */
169 void http_auth_setenv(connection *con, const char *username, size_t ulen, const char *auth_type, size_t alen) {
170 http_header_env_set(con, CONST_STR_LEN("REMOTE_USER"), username, ulen);
171 http_header_env_set(con, CONST_STR_LEN("AUTH_TYPE"), auth_type, alen);
174 unsigned int http_auth_digest_len (int algo)
176 if (algo & (HTTP_AUTH_DIGEST_SHA256 | HTTP_AUTH_DIGEST_SHA512_256)) {
177 /* HTTP_AUTH_DIGEST_SHA512_256_BINLEN */
178 return HTTP_AUTH_DIGEST_SHA256_BINLEN;
180 if (algo & HTTP_AUTH_DIGEST_MD5) {
181 return HTTP_AUTH_DIGEST_MD5_BINLEN;
184 return 0;
187 int http_auth_digest_hex2bin (const char *hexstr, size_t len, unsigned char *bin, size_t binlen)
189 /* validate and transform 32-byte MD5 hex string to 16-byte binary MD5,
190 * or 64-byte SHA-256 or SHA-512-256 hex string to 32-byte binary digest */
191 if (len > (binlen << 1)) return -1;
192 for (int i = 0, ilen = (int)len; i < ilen; i+=2) {
193 int hi = hexstr[i];
194 int lo = hexstr[i+1];
195 if ('0' <= hi && hi <= '9') hi -= '0';
196 else if ((hi |= 0x20), 'a' <= hi && hi <= 'f') hi += -'a' + 10;
197 else return -1;
198 if ('0' <= lo && lo <= '9') lo -= '0';
199 else if ((lo |= 0x20), 'a' <= lo && lo <= 'f') lo += -'a' + 10;
200 else return -1;
201 bin[(i >> 1)] = (unsigned char)((hi << 4) | lo);
203 return 0;
206 #if 0
207 int http_auth_md5_hex2lc (char *md5hex)
209 /* validate and transform 32-byte MD5 hex string to lowercase */
210 int i;
211 for (i = 0; md5hex[i]; ++i) {
212 int c = md5hex[i];
213 if ('0' <= c && c <= '9') continue;
214 else if ((c |= 0x20), 'a' <= c && c <= 'f') md5hex[i] = c;
215 else return -1;
217 return (32 == i) ? 0 : -1; /*(Note: char *md5hex must be a 32-char string)*/
219 #endif