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 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.
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
;
70 for (size_t i
= 0; i
< len
; ++i
) {
71 diff
|= (av
[i
] ^ bv
[i
]);
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.
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
]);
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();
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
);
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
)) {
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
)
151 && (require
->valid_user
152 || http_auth_array_contains(require
->user
, user
, strlen(user
)))) {
153 return 1; /* match */
157 && http_auth_array_contains(require
->group
, group
, strlen(group
))) {
158 return 1; /* match */
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
;
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) {
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;
198 if ('0' <= lo
&& lo
<= '9') lo
-= '0';
199 else if ((lo
|= 0x20), 'a' <= lo
&& lo
<= 'f') lo
+= -'a' + 10;
201 bin
[(i
>> 1)] = (unsigned char)((hi
<< 4) | lo
);
207 int http_auth_md5_hex2lc (char *md5hex
)
209 /* validate and transform 32-byte MD5 hex string to lowercase */
211 for (i
= 0; md5hex
[i
]; ++i
) {
213 if ('0' <= c
&& c
<= '9') continue;
214 else if ((c
|= 0x20), 'a' <= c
&& c
<= 'f') md5hex
[i
] = c
;
217 return (32 == i
) ? 0 : -1; /*(Note: char *md5hex must be a 32-char string)*/