/src/haproxy/src/uri_auth.c
Line | Count | Source |
1 | | /* |
2 | | * URI-based user authentication using the HTTP basic method. |
3 | | * |
4 | | * Copyright 2006-2007 Willy Tarreau <w@1wt.eu> |
5 | | * |
6 | | * This program is free software; you can redistribute it and/or |
7 | | * modify it under the terms of the GNU General Public License |
8 | | * as published by the Free Software Foundation; either version |
9 | | * 2 of the License, or (at your option) any later version. |
10 | | * |
11 | | */ |
12 | | |
13 | | #include <stdlib.h> |
14 | | #include <string.h> |
15 | | |
16 | | #include <haproxy/acl.h> |
17 | | #include <haproxy/action.h> |
18 | | #include <haproxy/api.h> |
19 | | #include <haproxy/auth.h> |
20 | | #include <haproxy/base64.h> |
21 | | #include <haproxy/errors.h> |
22 | | #include <haproxy/list.h> |
23 | | #include <haproxy/uri_auth.h> |
24 | | |
25 | | |
26 | | /* |
27 | | * Initializes a basic uri_auth structure header and returns a pointer to it. |
28 | | * Uses the pointer provided if not NULL and not initialized. |
29 | | */ |
30 | | struct uri_auth *stats_check_init_uri_auth(struct uri_auth **root) |
31 | 0 | { |
32 | 0 | struct uri_auth *u; |
33 | |
|
34 | 0 | if (!root || !*root) { |
35 | 0 | if ((u = calloc(1, sizeof (*u))) == NULL) |
36 | 0 | goto out_u; |
37 | | |
38 | 0 | LIST_INIT(&u->http_req_rules); |
39 | 0 | LIST_INIT(&u->admin_rules); |
40 | 0 | stats_uri_auth_take(u); |
41 | 0 | } else |
42 | 0 | u = *root; |
43 | | |
44 | 0 | if (!u->uri_prefix) { |
45 | 0 | u->uri_len = strlen(STATS_DEFAULT_URI); |
46 | 0 | if ((u->uri_prefix = strdup(STATS_DEFAULT_URI)) == NULL) |
47 | 0 | goto out_uri; |
48 | 0 | } |
49 | | |
50 | 0 | if (root && !*root) |
51 | 0 | *root = u; |
52 | |
|
53 | 0 | return u; |
54 | | |
55 | 0 | out_uri: |
56 | 0 | if (!root || !*root) |
57 | 0 | free(u); |
58 | 0 | out_u: |
59 | 0 | return NULL; |
60 | 0 | } |
61 | | |
62 | | /* |
63 | | * Returns a default uri_auth with <uri> set as the uri_prefix. |
64 | | * Uses the pointer provided if not NULL and not initialized. |
65 | | */ |
66 | | struct uri_auth *stats_set_uri(struct uri_auth **root, char *uri) |
67 | 0 | { |
68 | 0 | struct uri_auth *u; |
69 | 0 | char *uri_copy; |
70 | 0 | int uri_len; |
71 | |
|
72 | 0 | uri_len = strlen(uri); |
73 | 0 | if ((uri_copy = strdup(uri)) == NULL) |
74 | 0 | goto out_uri; |
75 | | |
76 | 0 | if ((u = stats_check_init_uri_auth(root)) == NULL) |
77 | 0 | goto out_u; |
78 | | |
79 | 0 | free(u->uri_prefix); |
80 | 0 | u->uri_prefix = uri_copy; |
81 | 0 | u->uri_len = uri_len; |
82 | 0 | return u; |
83 | | |
84 | 0 | out_u: |
85 | 0 | free(uri_copy); |
86 | 0 | out_uri: |
87 | 0 | return NULL; |
88 | 0 | } |
89 | | |
90 | | /* |
91 | | * Returns a default uri_auth with <realm> set as the realm. |
92 | | * Uses the pointer provided if not NULL and not initialized. |
93 | | */ |
94 | | struct uri_auth *stats_set_realm(struct uri_auth **root, char *realm) |
95 | 0 | { |
96 | 0 | struct uri_auth *u; |
97 | 0 | char *realm_copy; |
98 | |
|
99 | 0 | if ((realm_copy = strdup(realm)) == NULL) |
100 | 0 | goto out_realm; |
101 | | |
102 | 0 | if ((u = stats_check_init_uri_auth(root)) == NULL) |
103 | 0 | goto out_u; |
104 | | |
105 | 0 | free(u->auth_realm); |
106 | 0 | u->auth_realm = realm_copy; |
107 | 0 | return u; |
108 | | |
109 | 0 | out_u: |
110 | 0 | free(realm_copy); |
111 | 0 | out_realm: |
112 | 0 | return NULL; |
113 | 0 | } |
114 | | |
115 | | /* |
116 | | * Returns a default uri_auth with STAT_F_SHNODE flag enabled and |
117 | | * <node> set as the name if it is not empty. |
118 | | * Uses the pointer provided if not NULL and not initialized. |
119 | | */ |
120 | | struct uri_auth *stats_set_node(struct uri_auth **root, char *name) |
121 | 0 | { |
122 | 0 | struct uri_auth *u; |
123 | 0 | char *node_copy = NULL; |
124 | |
|
125 | 0 | if (name && *name) { |
126 | 0 | node_copy = strdup(name); |
127 | 0 | if (node_copy == NULL) |
128 | 0 | goto out_realm; |
129 | 0 | } |
130 | | |
131 | 0 | if ((u = stats_check_init_uri_auth(root)) == NULL) |
132 | 0 | goto out_u; |
133 | | |
134 | 0 | if (!stats_set_flag(root, STAT_F_SHNODE)) |
135 | 0 | goto out_u; |
136 | | |
137 | 0 | if (node_copy) { |
138 | 0 | free(u->node); |
139 | 0 | u->node = node_copy; |
140 | 0 | } |
141 | |
|
142 | 0 | return u; |
143 | | |
144 | 0 | out_u: |
145 | 0 | free(node_copy); |
146 | 0 | out_realm: |
147 | 0 | return NULL; |
148 | 0 | } |
149 | | |
150 | | /* |
151 | | * Returns a default uri_auth with STAT_F_SHDESC flag enabled and |
152 | | * <description> set as the desc if it is not empty. |
153 | | * Uses the pointer provided if not NULL and not initialized. |
154 | | */ |
155 | | struct uri_auth *stats_set_desc(struct uri_auth **root, char *desc) |
156 | 0 | { |
157 | 0 | struct uri_auth *u; |
158 | 0 | char *desc_copy = NULL; |
159 | |
|
160 | 0 | if (desc && *desc) { |
161 | 0 | desc_copy = strdup(desc); |
162 | 0 | if (desc_copy == NULL) |
163 | 0 | goto out_realm; |
164 | 0 | } |
165 | | |
166 | 0 | if ((u = stats_check_init_uri_auth(root)) == NULL) |
167 | 0 | goto out_u; |
168 | | |
169 | 0 | if (!stats_set_flag(root, STAT_F_SHDESC)) |
170 | 0 | goto out_u; |
171 | | |
172 | 0 | if (desc_copy) { |
173 | 0 | free(u->desc); |
174 | 0 | u->desc = desc_copy; |
175 | 0 | } |
176 | |
|
177 | 0 | return u; |
178 | | |
179 | 0 | out_u: |
180 | 0 | free(desc_copy); |
181 | 0 | out_realm: |
182 | 0 | return NULL; |
183 | 0 | } |
184 | | |
185 | | /* |
186 | | * Returns a default uri_auth with the <refresh> refresh interval. |
187 | | * Uses the pointer provided if not NULL and not initialized. |
188 | | */ |
189 | | struct uri_auth *stats_set_refresh(struct uri_auth **root, int interval) |
190 | 0 | { |
191 | 0 | struct uri_auth *u; |
192 | | |
193 | 0 | if ((u = stats_check_init_uri_auth(root)) != NULL) |
194 | 0 | u->refresh = interval; |
195 | 0 | return u; |
196 | 0 | } |
197 | | |
198 | | /* |
199 | | * Returns a default uri_auth with the <flag> set. |
200 | | * Uses the pointer provided if not NULL and not initialized. |
201 | | */ |
202 | | struct uri_auth *stats_set_flag(struct uri_auth **root, int flag) |
203 | 0 | { |
204 | 0 | struct uri_auth *u; |
205 | | |
206 | 0 | if ((u = stats_check_init_uri_auth(root)) != NULL) |
207 | 0 | u->flags |= flag; |
208 | 0 | return u; |
209 | 0 | } |
210 | | |
211 | | /* |
212 | | * Returns a default uri_auth with a <user:passwd> entry added to the list of |
213 | | * authorized users. If a matching entry is found, no update will be performed. |
214 | | * Uses the pointer provided if not NULL and not initialized. |
215 | | */ |
216 | | struct uri_auth *stats_add_auth(struct uri_auth **root, char *user) |
217 | 0 | { |
218 | 0 | struct uri_auth *u, *old_u; |
219 | 0 | struct auth_users *newuser = NULL; |
220 | 0 | char *pass; |
221 | |
|
222 | 0 | pass = strchr(user, ':'); |
223 | 0 | if (pass) |
224 | 0 | *pass++ = '\0'; |
225 | 0 | else |
226 | 0 | pass = ""; |
227 | |
|
228 | 0 | old_u = root ? *root : NULL; |
229 | 0 | if ((u = stats_check_init_uri_auth(root)) == NULL) |
230 | 0 | goto fail; |
231 | | |
232 | 0 | if (!u->userlist) |
233 | 0 | u->userlist = calloc(1, sizeof(*u->userlist)); |
234 | |
|
235 | 0 | if (!u->userlist) |
236 | 0 | goto fail; |
237 | | |
238 | 0 | if (!u->userlist->name) |
239 | 0 | u->userlist->name = strdup(".internal-stats-userlist"); |
240 | |
|
241 | 0 | if (!u->userlist->name) |
242 | 0 | goto fail; |
243 | | |
244 | 0 | for (newuser = u->userlist->users; newuser; newuser = newuser->next) |
245 | 0 | if (strcmp(newuser->user, user) == 0) { |
246 | 0 | ha_warning("uri auth: ignoring duplicated user '%s'.\n", |
247 | 0 | user); |
248 | 0 | return u; |
249 | 0 | } |
250 | | |
251 | 0 | newuser = calloc(1, sizeof(*newuser)); |
252 | 0 | if (!newuser) |
253 | 0 | goto fail; |
254 | | |
255 | 0 | newuser->user = strdup(user); |
256 | 0 | if (!newuser->user) |
257 | 0 | goto fail; |
258 | | |
259 | 0 | newuser->pass = strdup(pass); |
260 | 0 | if (!newuser->pass) |
261 | 0 | goto fail; |
262 | | |
263 | 0 | newuser->flags |= AU_O_INSECURE; |
264 | 0 | newuser->next = u->userlist->users; |
265 | 0 | u->userlist->users = newuser; |
266 | 0 | return u; |
267 | 0 | fail: |
268 | 0 | if (newuser) { |
269 | 0 | free(newuser->user); |
270 | 0 | free(newuser); |
271 | 0 | } |
272 | 0 | if (u && !old_u) { |
273 | 0 | if (u->userlist) { |
274 | 0 | free(u->userlist->name); |
275 | 0 | free(u->userlist); |
276 | 0 | } |
277 | 0 | free(u); |
278 | 0 | *root = NULL; |
279 | 0 | } |
280 | 0 | return NULL; |
281 | 0 | } |
282 | | |
283 | | /* |
284 | | * Returns a default uri_auth with a <scope> entry added to the list of |
285 | | * allowed scopes. If a matching entry is found, no update will be performed. |
286 | | * Uses the pointer provided if not NULL and not initialized. |
287 | | */ |
288 | | struct uri_auth *stats_add_scope(struct uri_auth **root, char *scope) |
289 | 0 | { |
290 | 0 | struct uri_auth *u, *old_u; |
291 | 0 | char *new_name; |
292 | 0 | struct stat_scope *old_scope, **scope_list; |
293 | |
|
294 | 0 | old_u = root ? *root : NULL; |
295 | 0 | if ((u = stats_check_init_uri_auth(root)) == NULL) |
296 | 0 | goto out; |
297 | | |
298 | 0 | scope_list = &u->scope; |
299 | 0 | while ((old_scope = *scope_list)) { |
300 | 0 | if (strcmp(old_scope->px_id, scope) == 0) |
301 | 0 | break; |
302 | 0 | scope_list = &old_scope->next; |
303 | 0 | } |
304 | |
|
305 | 0 | if (!old_scope) { |
306 | 0 | if ((new_name = strdup(scope)) == NULL) |
307 | 0 | goto out_u; |
308 | | |
309 | 0 | if ((old_scope = calloc(1, sizeof(*old_scope))) == NULL) |
310 | 0 | goto out_name; |
311 | | |
312 | 0 | old_scope->px_id = new_name; |
313 | 0 | old_scope->px_len = strlen(new_name); |
314 | 0 | *scope_list = old_scope; |
315 | 0 | } |
316 | 0 | return u; |
317 | | |
318 | 0 | out_name: |
319 | 0 | free(new_name); |
320 | 0 | out_u: |
321 | 0 | if (!old_u) { |
322 | 0 | free(u); |
323 | 0 | *root = NULL; |
324 | 0 | } |
325 | 0 | out: |
326 | 0 | return NULL; |
327 | 0 | } |
328 | | |
329 | | void stats_uri_auth_free(struct uri_auth *uri_auth) |
330 | 0 | { |
331 | 0 | struct stat_scope *scope, *scopep; |
332 | 0 | struct stats_admin_rule *rule, *ruleb; |
333 | |
|
334 | 0 | free(uri_auth->uri_prefix); |
335 | 0 | free(uri_auth->auth_realm); |
336 | 0 | free(uri_auth->node); |
337 | 0 | free(uri_auth->desc); |
338 | |
|
339 | 0 | userlist_free(uri_auth->userlist); |
340 | 0 | free_act_rules(&uri_auth->http_req_rules); |
341 | 0 | list_for_each_entry_safe(rule, ruleb, &uri_auth->admin_rules, list) { |
342 | 0 | LIST_DELETE(&rule->list); |
343 | 0 | free_acl_cond(rule->cond); |
344 | 0 | free(rule); |
345 | 0 | } |
346 | |
|
347 | 0 | scope = uri_auth->scope; |
348 | 0 | while (scope) { |
349 | 0 | scopep = scope; |
350 | 0 | scope = scope->next; |
351 | 0 | free(scopep->px_id); |
352 | 0 | free(scopep); |
353 | 0 | } |
354 | |
|
355 | 0 | free(uri_auth); |
356 | 0 | } |
357 | | |
358 | | void stats_uri_auth_drop(struct uri_auth *uri_auth) |
359 | 0 | { |
360 | 0 | if (!uri_auth) |
361 | 0 | return; |
362 | 0 | if (HA_ATOMIC_SUB_FETCH(&uri_auth->refcount, 1) == 0) |
363 | 0 | stats_uri_auth_free(uri_auth); |
364 | 0 | } |
365 | | |
366 | | void stats_uri_auth_take(struct uri_auth *uri_auth) |
367 | 0 | { |
368 | 0 | if (!uri_auth) |
369 | 0 | return; |
370 | 0 | HA_ATOMIC_INC(&uri_auth->refcount); |
371 | 0 | } |
372 | | |
373 | | /* |
374 | | * Local variables: |
375 | | * c-indent-level: 8 |
376 | | * c-basic-offset: 8 |
377 | | * End: |
378 | | */ |