File: | lwan-http-authorize.c |
Warning: | line 72, column 17 Potential leak of memory pointed to by 'username' |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* | |||
2 | * lwan - simple web server | |||
3 | * Copyright (c) 2014 L. A. F. Pereira <l@tia.mat.br> | |||
4 | * | |||
5 | * This program is free software; you can redistribute it and/or | |||
6 | * modify it under the terms of the GNU General Public License | |||
7 | * as published by the Free Software Foundation; either version 2 | |||
8 | * of the License, or any later version. | |||
9 | * | |||
10 | * This program is distributed in the hope that it will be useful, | |||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
13 | * GNU General Public License for more details. | |||
14 | * | |||
15 | * You should have received a copy of the GNU General Public License | |||
16 | * along with this program; if not, write to the Free Software | |||
17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, | |||
18 | * USA. | |||
19 | */ | |||
20 | ||||
21 | #include <errno(*__errno_location ()).h> | |||
22 | #include <stdbool.h> | |||
23 | #include <stdlib.h> | |||
24 | #include <string.h> | |||
25 | ||||
26 | #include "base64.h" | |||
27 | #include "lwan-private.h" | |||
28 | #include "lwan-cache.h" | |||
29 | #include "lwan-config.h" | |||
30 | #include "lwan-http-authorize.h" | |||
31 | ||||
32 | struct realm_password_file_t { | |||
33 | struct cache_entry base; | |||
34 | struct hash *entries; | |||
35 | }; | |||
36 | ||||
37 | static struct cache *realm_password_cache = NULL((void*)0); | |||
38 | ||||
39 | static void zero_and_free(void *str) | |||
40 | { | |||
41 | if (LIKELY(str)__builtin_expect((!!(str)), (1))) { | |||
42 | lwan_always_bzero(str, strlen(str)); | |||
43 | free(str); | |||
44 | } | |||
45 | } | |||
46 | ||||
47 | static struct cache_entry * | |||
48 | create_realm_file(const char *key, void *context __attribute__((unused))) | |||
49 | { | |||
50 | struct realm_password_file_t *rpf = malloc(sizeof(*rpf)); | |||
51 | const struct config_line *l; | |||
52 | struct config *f; | |||
53 | ||||
54 | if (UNLIKELY(!rpf)__builtin_expect(((!rpf)), (0))) | |||
| ||||
55 | return NULL((void*)0); | |||
56 | ||||
57 | rpf->entries = hash_str_new(zero_and_free, zero_and_free); | |||
58 | if (UNLIKELY(!rpf->entries)__builtin_expect(((!rpf->entries)), (0))) | |||
59 | goto error_no_close; | |||
60 | ||||
61 | #if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) | |||
62 | static const uint8_t hardcoded_user_config[] = "user=password\n" | |||
63 | "root=hunter2\n"; | |||
64 | f = config_open_for_fuzzing(hardcoded_user_config, | |||
65 | sizeof(hardcoded_user_config)); | |||
66 | #else | |||
67 | f = config_open(key); | |||
68 | #endif | |||
69 | if (!f) | |||
70 | goto error_no_close; | |||
71 | ||||
72 | while ((l = config_read_line(f))) { | |||
| ||||
73 | /* FIXME: Storing plain-text passwords in memory isn't a good idea. */ | |||
74 | switch (l->type) { | |||
75 | case CONFIG_LINE_TYPE_LINE: { | |||
76 | char *username = strdup(l->key); | |||
77 | if (!username) | |||
78 | goto error; | |||
79 | ||||
80 | char *password = strdup(l->value); | |||
81 | if (!password) { | |||
82 | free(username); | |||
83 | goto error; | |||
84 | } | |||
85 | ||||
86 | int err = hash_add_unique(rpf->entries, username, password); | |||
87 | if (LIKELY(!err)__builtin_expect((!!(!err)), (1))) | |||
88 | continue; | |||
89 | ||||
90 | free(username); | |||
91 | free(password); | |||
92 | ||||
93 | if (err == -EEXIST17) { | |||
94 | lwan_status_warning(lwan_status_warning_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-http-authorize.c" , 95, __FUNCTION__, "Username entry already exists, ignoring: \"%s\"" , l->key) | |||
95 | "Username entry already exists, ignoring: \"%s\"", l->key)lwan_status_warning_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-http-authorize.c" , 95, __FUNCTION__, "Username entry already exists, ignoring: \"%s\"" , l->key); | |||
96 | continue; | |||
97 | } | |||
98 | ||||
99 | goto error; | |||
100 | } | |||
101 | default: | |||
102 | config_error(f, "Expected username = password"); | |||
103 | break; | |||
104 | } | |||
105 | } | |||
106 | ||||
107 | if (config_last_error(f)) { | |||
108 | lwan_status_error("Error on password file \"%s\", line %d: %s", key,lwan_status_error_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-http-authorize.c" , 109, __FUNCTION__, "Error on password file \"%s\", line %d: %s" , key, config_cur_line(f), config_last_error(f)) | |||
109 | config_cur_line(f), config_last_error(f))lwan_status_error_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-http-authorize.c" , 109, __FUNCTION__, "Error on password file \"%s\", line %d: %s" , key, config_cur_line(f), config_last_error(f)); | |||
110 | goto error; | |||
111 | } | |||
112 | ||||
113 | config_close(f); | |||
114 | return (struct cache_entry *)rpf; | |||
115 | ||||
116 | error: | |||
117 | config_close(f); | |||
118 | error_no_close: | |||
119 | hash_free(rpf->entries); | |||
120 | free(rpf); | |||
121 | return NULL((void*)0); | |||
122 | } | |||
123 | ||||
124 | static void destroy_realm_file(struct cache_entry *entry, | |||
125 | void *context __attribute__((unused))) | |||
126 | { | |||
127 | struct realm_password_file_t *rpf = (struct realm_password_file_t *)entry; | |||
128 | hash_free(rpf->entries); | |||
129 | free(rpf); | |||
130 | } | |||
131 | ||||
132 | bool_Bool lwan_http_authorize_init(void) | |||
133 | { | |||
134 | realm_password_cache = | |||
135 | cache_create(create_realm_file, destroy_realm_file, NULL((void*)0), 60); | |||
136 | ||||
137 | return !!realm_password_cache; | |||
138 | } | |||
139 | ||||
140 | void lwan_http_authorize_shutdown(void) { cache_destroy(realm_password_cache); } | |||
141 | ||||
142 | static bool_Bool authorize(struct coro *coro, | |||
143 | const char *header, | |||
144 | size_t header_len, | |||
145 | const char *password_file) | |||
146 | { | |||
147 | struct realm_password_file_t *rpf; | |||
148 | unsigned char *decoded; | |||
149 | char *colon; | |||
150 | char *password; | |||
151 | char *looked_password; | |||
152 | size_t decoded_len; | |||
153 | bool_Bool password_ok = false0; | |||
154 | ||||
155 | rpf = (struct realm_password_file_t *)cache_coro_get_and_ref_entry( | |||
156 | realm_password_cache, coro, password_file); | |||
157 | if (UNLIKELY(!rpf)__builtin_expect(((!rpf)), (0))) | |||
158 | return false0; | |||
159 | ||||
160 | decoded = base64_decode((unsigned char *)header, header_len, &decoded_len); | |||
161 | if (UNLIKELY(!decoded)__builtin_expect(((!decoded)), (0))) | |||
162 | return false0; | |||
163 | ||||
164 | colon = memchr(decoded, ':', decoded_len); | |||
165 | if (UNLIKELY(!colon)__builtin_expect(((!colon)), (0))) | |||
166 | goto out; | |||
167 | ||||
168 | *colon = '\0'; | |||
169 | password = colon + 1; | |||
170 | ||||
171 | looked_password = hash_find(rpf->entries, decoded); | |||
172 | if (looked_password) | |||
173 | password_ok = streq(password, looked_password); | |||
174 | ||||
175 | out: | |||
176 | free(decoded); | |||
177 | return password_ok; | |||
178 | } | |||
179 | ||||
180 | bool_Bool lwan_http_authorize(struct lwan_request *request, | |||
181 | const char *realm, | |||
182 | const char *password_file) | |||
183 | { | |||
184 | static const char authenticate_tmpl[] = "Basic realm=\"%s\""; | |||
185 | static const size_t basic_len = sizeof("Basic ") - 1; | |||
186 | const char *authorization = | |||
187 | lwan_request_get_header(request, "Authorization"); | |||
188 | ||||
189 | if (LIKELY(authorization && !strncmp(authorization, "Basic ", basic_len))__builtin_expect((!!(authorization && !strncmp(authorization , "Basic ", basic_len))), (1))) { | |||
190 | const char *header = authorization + basic_len; | |||
191 | size_t header_len = strlen(authorization) - basic_len; | |||
192 | ||||
193 | if (authorize(request->conn->coro, header, header_len, password_file)) | |||
194 | return true1; | |||
195 | } | |||
196 | ||||
197 | const struct lwan_key_value headers[] = { | |||
198 | {"WWW-Authenticate", | |||
199 | coro_printf(request->conn->coro, authenticate_tmpl, realm)}, | |||
200 | {}, | |||
201 | }; | |||
202 | request->response.headers = | |||
203 | coro_memdup(request->conn->coro, headers, sizeof(headers)); | |||
204 | ||||
205 | return false0; | |||
206 | } |