Coverage Report

Created: 2026-08-13 07:18

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/haproxy/src/auth.c
Line
Count
Source
1
/*
2
 * User authentication & authorization
3
 *
4
 * Copyright 2010 Krzysztof Piotr Oledzki <ole@ans.pl>
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
#ifdef USE_LIBCRYPT
14
/* This is to have crypt() defined on Linux */
15
#define _GNU_SOURCE
16
17
#ifdef USE_CRYPT_H
18
/* some platforms such as Solaris need this */
19
#include <crypt.h>
20
#endif
21
#endif /* USE_LIBCRYPT */
22
23
#include <stdio.h>
24
#include <stdlib.h>
25
#include <string.h>
26
#include <unistd.h>
27
28
#include <haproxy/api.h>
29
#include <haproxy/auth-t.h>
30
#include <haproxy/errors.h>
31
#include <haproxy/global.h>
32
#include <haproxy/list.h>
33
#include <haproxy/pattern-t.h>
34
#include <haproxy/sample-t.h>
35
#include <haproxy/thread.h>
36
37
struct userlist *userlist = NULL;    /* list of all existing userlists */
38
39
#ifdef USE_LIBCRYPT
40
#define CRYPT_STATE_MSG "yes"
41
#ifdef HA_HAVE_CRYPT_R
42
/* context for crypt_r() */
43
static THREAD_LOCAL struct crypt_data crypt_data = { .initialized = 0 };
44
#else
45
/* lock for crypt() */
46
__decl_thread(static HA_SPINLOCK_T auth_lock);
47
#endif
48
#else /* USE_LIBCRYPT */
49
#define CRYPT_STATE_MSG "no"
50
#endif
51
52
/* find targets for selected groups. The function returns pointer to
53
 * the userlist struct or NULL if name is NULL/empty or unresolvable.
54
 */
55
56
struct userlist *
57
auth_find_userlist(char *name)
58
0
{
59
0
  struct userlist *l;
60
61
0
  if (!name || !*name)
62
0
    return NULL;
63
64
0
  for (l = userlist; l; l = l->next)
65
0
    if (strcmp(l->name, name) == 0)
66
0
      return l;
67
68
0
  return NULL;
69
0
}
70
71
int check_group(struct userlist *ul, char *name)
72
0
{
73
0
  struct auth_groups *ag;
74
75
0
  for (ag = ul->groups; ag; ag = ag->next)
76
0
    if (strcmp(name, ag->name) == 0)
77
0
      return 1;
78
0
  return 0;
79
0
}
80
81
void
82
userlist_free(struct userlist *ul)
83
0
{
84
0
  struct userlist *tul;
85
0
  struct auth_users *au, *tau;
86
0
  struct auth_groups_list *agl, *tagl;
87
0
  struct auth_groups *ag, *tag;
88
89
0
  while (ul) {
90
    /* Free users. */
91
0
    au = ul->users;
92
0
    while (au) {
93
      /* Free groups that own current user. */
94
0
      agl = au->u.groups;
95
0
      while (agl) {
96
0
        tagl = agl;
97
0
        agl = agl->next;
98
0
        free(tagl);
99
0
      }
100
101
0
      tau = au;
102
0
      au = au->next;
103
0
      free(tau->user);
104
0
      free(tau->pass);
105
0
      free(tau);
106
0
    }
107
108
    /* Free grouplist. */
109
0
    ag = ul->groups;
110
0
    while (ag) {
111
0
      tag = ag;
112
0
      ag = ag->next;
113
0
      free(tag->name);
114
0
      free(tag);
115
0
    }
116
117
0
    tul = ul;
118
0
    ul = ul->next;
119
0
    free(tul->name);
120
0
    free(tul);
121
0
  };
122
0
}
123
124
int userlist_postinit()
125
0
{
126
0
  struct userlist *curuserlist = NULL;
127
128
  /* Resolve usernames and groupnames. */
129
0
  for (curuserlist = userlist; curuserlist; curuserlist = curuserlist->next) {
130
0
    struct auth_groups *ag;
131
0
    struct auth_users *curuser;
132
0
    struct auth_groups_list *grl, *tmp;
133
134
0
    for (curuser = curuserlist->users; curuser; curuser = curuser->next) {
135
0
      char *group = NULL;
136
0
      struct auth_groups_list *groups = NULL;
137
138
0
      if (!curuser->u.groups_names)
139
0
        continue;
140
141
0
      while ((group = strtok(group?NULL:curuser->u.groups_names, ","))) {
142
0
        for (ag = curuserlist->groups; ag; ag = ag->next) {
143
0
          if (strcmp(ag->name, group) == 0)
144
0
            break;
145
0
        }
146
147
0
        if (!ag) {
148
0
          ha_alert("userlist '%s': no such group '%s' specified in user '%s'\n",
149
0
             curuserlist->name, group, curuser->user);
150
0
          while (groups) {
151
0
            grl = groups;
152
0
            groups = groups->next;
153
0
            free(grl);
154
0
          }
155
0
          goto free_groups;
156
0
        }
157
158
        /* Add this group at the group userlist. */
159
0
        grl = calloc(1, sizeof(*grl));
160
0
        if (!grl) {
161
0
          ha_alert("userlist '%s': no more memory when trying to allocate the user groups.\n",
162
0
             curuserlist->name);
163
0
          while (groups) {
164
0
            grl = groups;
165
0
            groups = groups->next;
166
0
            free(grl);
167
0
          }
168
0
          goto free_groups;
169
0
        }
170
171
0
        grl->group = ag;
172
0
        grl->next = groups;
173
0
        groups = grl;
174
0
      }
175
176
0
      free(curuser->u.groups);
177
0
      curuser->u.groups = groups;
178
0
    }
179
180
0
    for (ag = curuserlist->groups; ag; ag = ag->next) {
181
0
      char *user = NULL;
182
183
0
      if (!ag->groupusers)
184
0
        continue;
185
186
0
      while ((user = strtok(user?NULL:ag->groupusers, ","))) {
187
0
        for (curuser = curuserlist->users; curuser; curuser = curuser->next) {
188
0
          if (strcmp(curuser->user, user) == 0)
189
0
            break;
190
0
        }
191
192
0
        if (!curuser) {
193
0
          ha_alert("userlist '%s': no such user '%s' specified in group '%s'\n",
194
0
             curuserlist->name, user, ag->name);
195
0
          goto free_groups;
196
0
        }
197
198
        /* Add this group at the group userlist. */
199
0
        grl = calloc(1, sizeof(*grl));
200
0
        if (!grl) {
201
0
          ha_alert("userlist '%s': no more memory when trying to allocate the user groups.\n",
202
0
             curuserlist->name);
203
0
          goto free_groups;
204
0
        }
205
206
0
        grl->group = ag;
207
0
        grl->next = curuser->u.groups;
208
0
        curuser->u.groups = grl;
209
0
      }
210
211
0
      ha_free(&ag->groupusers);
212
0
    }
213
214
0
    goto next_userlist;
215
216
0
   free_groups:
217
    /* Free already-assigned groups for all users in this userlist. */
218
0
    for (curuser = curuserlist->users; curuser; curuser = curuser->next) {
219
0
      grl = curuser->u.groups;
220
0
      while (grl) {
221
0
        tmp = grl;
222
0
        grl = grl->next;
223
0
        free(tmp);
224
0
      }
225
0
      curuser->u.groups = NULL;
226
0
    }
227
0
    return ERR_ALERT | ERR_FATAL;
228
229
0
  next_userlist:;
230
#ifdef DEBUG_AUTH
231
    for (ag = curuserlist->groups; ag; ag = ag->next) {
232
      struct auth_groups_list *agl;
233
234
      fprintf(stderr, "group %s, id %p, users:", ag->name, ag);
235
      for (curuser = curuserlist->users; curuser; curuser = curuser->next) {
236
        for (agl = curuser->u.groups; agl; agl = agl->next) {
237
          if (agl->group == ag)
238
            fprintf(stderr, " %s", curuser->user);
239
        }
240
      }
241
      fprintf(stderr, "\n");
242
    }
243
#endif
244
0
  }
245
246
0
  return ERR_NONE;
247
0
}
248
249
/*
250
 * Authenticate and authorize user; return 1 if OK, 0 if case of error.
251
 */
252
int
253
check_user(struct userlist *ul, const char *user, const char *pass)
254
0
{
255
256
0
  struct auth_users *u;
257
#ifdef DEBUG_AUTH
258
  struct auth_groups_list *agl;
259
#endif
260
0
  const char *ep;
261
262
#ifdef DEBUG_AUTH
263
  fprintf(stderr, "req: userlist=%s, user=%s, pass=%s\n",
264
          ul->name, user, pass);
265
#endif
266
267
0
  for (u = ul->users; u; u = u->next)
268
0
    if (strcmp(user, u->user) == 0)
269
0
      break;
270
271
0
  if (!u)
272
0
    return 0;
273
274
#ifdef DEBUG_AUTH
275
  fprintf(stderr, "cfg: user=%s, pass=%s, flags=%X, groups=",
276
    u->user, u->pass, u->flags);
277
  for (agl = u->u.groups; agl; agl = agl->next)
278
    fprintf(stderr, " %s", agl->group->name);
279
#endif
280
281
0
  if (!(u->flags & AU_O_INSECURE)) {
282
#ifdef USE_LIBCRYPT
283
#ifdef HA_HAVE_CRYPT_R
284
    ep = crypt_r(pass, u->pass, &crypt_data);
285
#else
286
    HA_SPIN_LOCK(AUTH_LOCK, &auth_lock);
287
    ep = crypt(pass, u->pass);
288
    HA_SPIN_UNLOCK(AUTH_LOCK, &auth_lock);
289
#endif
290
#else
291
0
    return 0;
292
0
#endif
293
0
  } else
294
0
    ep = pass;
295
296
#ifdef DEBUG_AUTH
297
  fprintf(stderr, ", crypt=%s\n", ((ep) ? ep : ""));
298
#endif
299
300
0
  if (ep && u->pass && strcmp(ep, u->pass) == 0)
301
0
    return 1;
302
0
  else
303
0
    return 0;
304
0
}
305
306
struct pattern *
307
pat_match_auth(struct sample *smp, struct pattern_expr *expr, int fill)
308
0
{
309
0
  struct userlist *ul = smp->ctx.a[0];
310
0
  struct pattern_list *lst;
311
0
  struct auth_users *u;
312
0
  struct auth_groups_list *agl;
313
0
  struct pattern *pattern;
314
315
  /* Check if the userlist is present in the context data. */
316
0
  if (!ul)
317
0
    return NULL;
318
319
  /* Browse the userlist for searching user. */
320
0
  for (u = ul->users; u; u = u->next) {
321
0
    if (strcmp(smp->data.u.str.area, u->user) == 0)
322
0
      break;
323
0
  }
324
0
  if (!u)
325
0
    return NULL;
326
327
  /* Browse each pattern. */
328
0
  list_for_each_entry(lst, &expr->patterns, list) {
329
0
    pattern = &lst->pat;
330
331
    /* Browse each group for searching group name that match the pattern. */
332
0
    for (agl = u->u.groups; agl; agl = agl->next) {
333
0
      if (strcmp(agl->group->name, pattern->ptr.str) == 0)
334
0
        return pattern;
335
0
    }
336
0
  }
337
0
  return NULL;
338
0
}
339
340
REGISTER_BUILD_OPTS("Encrypted password support via crypt(3): "CRYPT_STATE_MSG);