4 #include "http_header.h"
10 static http_auth_scheme_t http_auth_schemes
[8];
12 const http_auth_scheme_t
* http_auth_scheme_get (const buffer
*name
)
15 while (NULL
!= http_auth_schemes
[i
].name
16 && 0 != strcmp(http_auth_schemes
[i
].name
, name
->ptr
)) {
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
)
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
)
37 while (NULL
!= http_auth_backends
[i
].name
38 && 0 != strcmp(http_auth_backends
[i
].name
, name
->ptr
)) {
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
)
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 char *a
, const size_t alen
, const char *b
, const size_t blen
)
56 /* constant time memory compare, unless compiler figures it out
57 * (similar to mod_secdownload.c:const_time_memeq()) */
58 /* round to next multiple of 64 to avoid potentially leaking exact
59 * password length when subject to high precision timing attacks)
60 * (not necessary when comparing digests, which have defined lengths)
62 /* Note: some libs provide similar funcs but might not obscure length, e.g.
64 * int CRYPTO_memcmp(const void * in_a, const void * in_b, size_t len)
65 * Note: some OS provide similar funcs but might not obscure length, e.g.
66 * OpenBSD: int timingsafe_bcmp(const void *b1, const void *b2, size_t len)
67 * NetBSD: int consttime_memequal(void *b1, void *b2, size_t len)
69 const volatile unsigned char * const av
= (const unsigned char *)a
;
70 const volatile unsigned char * const bv
= (const unsigned char *)b
;
71 size_t lim
= ((alen
>= blen
? alen
: blen
) + 0x3F) & ~0x3F;
72 int diff
= (alen
!= blen
); /*(never match if string length mismatch)*/
73 for (size_t i
= 0, j
= 0; lim
; --lim
) {
74 diff
|= (av
[i
] ^ bv
[j
]);
82 void http_auth_dumbdata_reset (void)
84 memset(http_auth_schemes
, 0, sizeof(http_auth_schemes
));
85 memset(http_auth_backends
, 0, sizeof(http_auth_backends
));
89 http_auth_require_t
* http_auth_require_init (void)
91 http_auth_require_t
*require
= calloc(1, sizeof(http_auth_require_t
));
92 force_assert(NULL
!= require
);
94 require
->realm
= buffer_init();
95 require
->valid_user
= 0;
96 require
->user
= array_init();
97 require
->group
= array_init();
98 require
->host
= array_init();
103 void http_auth_require_free (http_auth_require_t
* const require
)
105 buffer_free(require
->realm
);
106 array_free(require
->user
);
107 array_free(require
->group
);
108 array_free(require
->host
);
112 /* (case-sensitive version of array.c:array_get_index(),
113 * and common case expects small num of allowed tokens,
114 * so it is reasonably performant to simply walk the array) */
115 static int http_auth_array_contains (const array
* const a
, const char * const k
, const size_t klen
)
117 for (size_t i
= 0, used
= a
->used
; i
< used
; ++i
) {
118 if (buffer_is_equal_string(a
->data
[i
]->key
, k
, klen
)) {
125 int http_auth_match_rules (const http_auth_require_t
* const require
, const char * const user
, const char * const group
, const char * const host
)
128 && (require
->valid_user
129 || http_auth_array_contains(require
->user
, user
, strlen(user
)))) {
130 return 1; /* match */
134 && http_auth_array_contains(require
->group
, group
, strlen(group
))) {
135 return 1; /* match */
139 && http_auth_array_contains(require
->host
, host
, strlen(host
))) {
140 return 1; /* match */
143 return 0; /* no match */
146 void http_auth_setenv(connection
*con
, const char *username
, size_t ulen
, const char *auth_type
, size_t alen
) {
147 http_header_env_set(con
, CONST_STR_LEN("REMOTE_USER"), username
, ulen
);
148 http_header_env_set(con
, CONST_STR_LEN("AUTH_TYPE"), auth_type
, alen
);
151 unsigned int http_auth_digest_len (int algo
)
153 if (algo
& (HTTP_AUTH_DIGEST_SHA256
| HTTP_AUTH_DIGEST_SHA512_256
)) {
154 /* HTTP_AUTH_DIGEST_SHA512_256_BINLEN */
155 return HTTP_AUTH_DIGEST_SHA256_BINLEN
;
157 if (algo
& HTTP_AUTH_DIGEST_MD5
) {
158 return HTTP_AUTH_DIGEST_MD5_BINLEN
;
164 int http_auth_digest_hex2bin (const char *hexstr
, size_t len
, unsigned char *bin
, size_t binlen
)
166 /* validate and transform 32-byte MD5 hex string to 16-byte binary MD5,
167 * or 64-byte SHA-256 or SHA-512-256 hex string to 32-byte binary digest */
168 if (len
> (binlen
<< 1)) return -1;
169 for (int i
= 0, ilen
= (int)len
; i
< ilen
; i
+=2) {
171 int lo
= hexstr
[i
+1];
172 if ('0' <= hi
&& hi
<= '9') hi
-= '0';
173 else if ((hi
|= 0x20), 'a' <= hi
&& hi
<= 'f') hi
+= -'a' + 10;
175 if ('0' <= lo
&& lo
<= '9') lo
-= '0';
176 else if ((lo
|= 0x20), 'a' <= lo
&& lo
<= 'f') lo
+= -'a' + 10;
178 bin
[(i
>> 1)] = (unsigned char)((hi
<< 4) | lo
);
184 int http_auth_md5_hex2lc (char *md5hex
)
186 /* validate and transform 32-byte MD5 hex string to lowercase */
188 for (i
= 0; md5hex
[i
]; ++i
) {
190 if ('0' <= c
&& c
<= '9') continue;
191 else if ((c
|= 0x20), 'a' <= c
&& c
<= 'f') md5hex
[i
] = c
;
194 return (32 == i
) ? 0 : -1; /*(Note: char *md5hex must be a 32-char string)*/