Coverage Report

Created: 2026-07-12 06:34

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
 */