blob: 42c08083e3f0f9f4d0a72b7ef89fd5d681e22aa1 [file] [log] [blame]
Krzysztof Piotr Oledzki96105042010-01-29 17:50:44 +01001/*
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
Willy Tarreau890a33e2010-03-04 19:10:14 +010013#ifdef CONFIG_HAP_CRYPT
14/* This is to have crypt() defined on Linux */
15#define _GNU_SOURCE
16
17#ifdef NEED_CRYPT_H
18/* some platforms such as Solaris need this */
19#include <crypt.h>
20#endif
21#endif /* CONFIG_HAP_CRYPT */
Krzysztof Piotr Oledzki96105042010-01-29 17:50:44 +010022
23#include <stdio.h>
24#include <stdlib.h>
25#include <string.h>
26#include <unistd.h>
27
28#include <common/config.h>
Thierry FOURNIER9eec0a62014-01-22 18:38:02 +010029#include <common/errors.h>
Krzysztof Piotr Oledzki96105042010-01-29 17:50:44 +010030
31#include <proto/acl.h>
32#include <proto/log.h>
33
34#include <types/auth.h>
Thierry FOURNIERa65b3432013-11-28 18:22:00 +010035#include <types/pattern.h>
Krzysztof Piotr Oledzki96105042010-01-29 17:50:44 +010036
37struct userlist *userlist = NULL; /* list of all existing userlists */
38
39/* find targets for selected gropus. The function returns pointer to
40 * the userlist struct ot NULL if name is NULL/empty or unresolvable.
41 */
42
43struct userlist *
44auth_find_userlist(char *name)
45{
46 struct userlist *l;
47
48 if (!name || !*name)
49 return NULL;
50
51 for (l = userlist; l; l = l->next)
52 if (!strcmp(l->name, name))
53 return l;
54
55 return NULL;
56}
57
Thierry FOURNIER9eec0a62014-01-22 18:38:02 +010058int check_group(struct userlist *ul, char *name)
Krzysztof Piotr Oledzki96105042010-01-29 17:50:44 +010059{
Thierry FOURNIER9eec0a62014-01-22 18:38:02 +010060 struct auth_groups *ag;
Krzysztof Piotr Oledzki96105042010-01-29 17:50:44 +010061
Thierry FOURNIER9eec0a62014-01-22 18:38:02 +010062 for (ag = ul->groups; ag; ag = ag->next)
63 if (strcmp(name, ag->name) == 0)
64 return 1;
65 return 0;
Krzysztof Piotr Oledzki96105042010-01-29 17:50:44 +010066}
67
Krzysztof Piotr Oledzki96105042010-01-29 17:50:44 +010068void
69userlist_free(struct userlist *ul)
70{
71 struct userlist *tul;
72 struct auth_users *au, *tau;
Thierry FOURNIER9eec0a62014-01-22 18:38:02 +010073 struct auth_groups_list *agl, *tagl;
74 struct auth_groups *ag, *tag;
Krzysztof Piotr Oledzki96105042010-01-29 17:50:44 +010075
76 while (ul) {
Thierry FOURNIER9eec0a62014-01-22 18:38:02 +010077 /* Free users. */
Krzysztof Piotr Oledzki96105042010-01-29 17:50:44 +010078 au = ul->users;
79 while (au) {
Thierry FOURNIER9eec0a62014-01-22 18:38:02 +010080 /* Free groups that own current user. */
81 agl = au->u.groups;
82 while (agl) {
83 tagl = agl;
84 agl = agl->next;
85 free(tagl);
86 }
87
Krzysztof Piotr Oledzki96105042010-01-29 17:50:44 +010088 tau = au;
89 au = au->next;
90 free(tau->user);
91 free(tau->pass);
92 free(tau);
93 }
94
Thierry FOURNIER9eec0a62014-01-22 18:38:02 +010095 /* Free grouplist. */
96 ag = ul->groups;
97 while (ag) {
98 tag = ag;
99 ag = ag->next;
100 free(tag->name);
101 free(tag);
102 }
103
Krzysztof Piotr Oledzki96105042010-01-29 17:50:44 +0100104 tul = ul;
105 ul = ul->next;
Krzysztof Piotr Oledzki96105042010-01-29 17:50:44 +0100106 free(tul->name);
107 free(tul);
108 };
109}
110
Thierry FOURNIER9eec0a62014-01-22 18:38:02 +0100111int userlist_postinit()
112{
113 struct userlist *curuserlist = NULL;
114
115 /* Resolve usernames and groupnames. */
116 for (curuserlist = userlist; curuserlist; curuserlist = curuserlist->next) {
117 struct auth_groups *ag;
118 struct auth_users *curuser;
119 struct auth_groups_list *grl;
120
121 for (curuser = curuserlist->users; curuser; curuser = curuser->next) {
122 char *group = NULL;
123 struct auth_groups_list *groups = NULL;
124
125 if (!curuser->u.groups_names)
126 continue;
127
128 while ((group = strtok(group?NULL:curuser->u.groups_names, ","))) {
129 for (ag = curuserlist->groups; ag; ag = ag->next) {
130 if (!strcmp(ag->name, group))
131 break;
132 }
133
134 if (!ag) {
135 Alert("userlist '%s': no such group '%s' specified in user '%s'\n",
136 curuserlist->name, group, curuser->user);
Dirkjan Bussink07fcaaa2014-04-28 22:57:16 +0000137 free(groups);
Thierry FOURNIER9eec0a62014-01-22 18:38:02 +0100138 return ERR_ALERT | ERR_FATAL;
139 }
140
141 /* Add this group at the group userlist. */
142 grl = calloc(1, sizeof(*grl));
143 if (!grl) {
144 Alert("userlist '%s': no more memory when trying to allocate the user groups.\n",
145 curuserlist->name);
Dirkjan Bussink07fcaaa2014-04-28 22:57:16 +0000146 free(groups);
147 return ERR_ALERT | ERR_FATAL;
Thierry FOURNIER9eec0a62014-01-22 18:38:02 +0100148 }
149
150 grl->group = ag;
151 grl->next = groups;
152 groups = grl;
153 }
154
155 free(curuser->u.groups);
156 curuser->u.groups = groups;
157 }
158
159 for (ag = curuserlist->groups; ag; ag = ag->next) {
160 char *user = NULL;
161
162 if (!ag->groupusers)
163 continue;
164
165 while ((user = strtok(user?NULL:ag->groupusers, ","))) {
166 for (curuser = curuserlist->users; curuser; curuser = curuser->next) {
167 if (!strcmp(curuser->user, user))
168 break;
169 }
170
171 if (!curuser) {
172 Alert("userlist '%s': no such user '%s' specified in group '%s'\n",
173 curuserlist->name, user, ag->name);
174 return ERR_ALERT | ERR_FATAL;
175 }
176
177 /* Add this group at the group userlist. */
178 grl = calloc(1, sizeof(*grl));
179 if (!grl) {
180 Alert("userlist '%s': no more memory when trying to allocate the user groups.\n",
181 curuserlist->name);
182 return ERR_ALERT | ERR_FATAL;
183 }
184
185 grl->group = ag;
186 grl->next = curuser->u.groups;
187 curuser->u.groups = grl;
188 }
189
190 free(ag->groupusers);
191 ag->groupusers = NULL;
192 }
193
194#ifdef DEBUG_AUTH
195 for (ag = curuserlist->groups; ag; ag = ag->next) {
196 struct auth_groups_list *agl;
197
198 fprintf(stderr, "group %s, id %p, users:", ag->name, ag);
199 for (curuser = curuserlist->users; curuser; curuser = curuser->next) {
200 for (agl = curuser->u.groups; agl; agl = agl->next) {
201 if (agl->group == ag)
202 fprintf(stderr, " %s", curuser->user);
203 }
204 }
205 fprintf(stderr, "\n");
206 }
207#endif
208 }
209
210 return ERR_NONE;
211}
212
Krzysztof Piotr Oledzki96105042010-01-29 17:50:44 +0100213/*
214 * Authenticate and authorize user; return 1 if OK, 0 if case of error.
215 */
216int
Thierry FOURNIER9eec0a62014-01-22 18:38:02 +0100217check_user(struct userlist *ul, const char *user, const char *pass)
Krzysztof Piotr Oledzki96105042010-01-29 17:50:44 +0100218{
219
220 struct auth_users *u;
221 const char *ep;
222
223#ifdef DEBUG_AUTH
Thierry FOURNIER9eec0a62014-01-22 18:38:02 +0100224 fprintf(stderr, "req: userlist=%s, user=%s, pass=%s, group=%s\n",
225 ul->name, user, pass, group);
Krzysztof Piotr Oledzki96105042010-01-29 17:50:44 +0100226#endif
227
228 for (u = ul->users; u; u = u->next)
229 if (!strcmp(user, u->user))
230 break;
231
232 if (!u)
233 return 0;
234
235#ifdef DEBUG_AUTH
Thierry FOURNIER9eec0a62014-01-22 18:38:02 +0100236 fprintf(stderr, "cfg: user=%s, pass=%s, flags=%X, groups=",
237 u->user, u->pass, u->flags);
238 for (agl = u->u.groups; agl; agl = agl->next)
239 fprintf(stderr, " %s", agl->group->name);
Krzysztof Piotr Oledzki96105042010-01-29 17:50:44 +0100240#endif
241
Krzysztof Piotr Oledzki96105042010-01-29 17:50:44 +0100242 if (!(u->flags & AU_O_INSECURE)) {
243#ifdef CONFIG_HAP_CRYPT
244 ep = crypt(pass, u->pass);
245#else
246 return 0;
247#endif
248 } else
249 ep = pass;
250
251#ifdef DEBUG_AUTH
252 fprintf(stderr, ", crypt=%s\n", ep);
253#endif
254
Cyril Bontéf09c9fe2014-08-29 20:20:01 +0200255 if (ep && strcmp(ep, u->pass) == 0)
Krzysztof Piotr Oledzki96105042010-01-29 17:50:44 +0100256 return 1;
257 else
258 return 0;
259}
Krzysztof Piotr Oledzkif9423ae2010-01-29 19:26:18 +0100260
Thierry FOURNIER5338eea2013-12-16 14:22:13 +0100261struct pattern *
262pat_match_auth(struct sample *smp, struct pattern_expr *expr, int fill)
Krzysztof Piotr Oledzkif9423ae2010-01-29 19:26:18 +0100263{
Willy Tarreau37406352012-04-23 16:16:37 +0200264 struct userlist *ul = smp->ctx.a[0];
Thierry FOURNIER5338eea2013-12-16 14:22:13 +0100265 struct pattern_list *lst;
Thierry FOURNIER9eec0a62014-01-22 18:38:02 +0100266 struct auth_users *u;
267 struct auth_groups_list *agl;
Thierry FOURNIER5338eea2013-12-16 14:22:13 +0100268 struct pattern *pattern;
Krzysztof Piotr Oledzkif9423ae2010-01-29 19:26:18 +0100269
Thierry FOURNIER9eec0a62014-01-22 18:38:02 +0100270 /* Check if the userlist is present in the context data. */
271 if (!ul)
Willy Tarreau86e0fc12014-04-29 19:52:16 +0200272 return NULL;
Thierry FOURNIER9eec0a62014-01-22 18:38:02 +0100273
274 /* Browse the userlist for searching user. */
275 for (u = ul->users; u; u = u->next) {
276 if (strcmp(smp->data.str.str, u->user) == 0)
277 break;
278 }
279 if (!u)
Thierry FOURNIER5338eea2013-12-16 14:22:13 +0100280 return NULL;
Thierry FOURNIER9eec0a62014-01-22 18:38:02 +0100281
Thierry FOURNIER5338eea2013-12-16 14:22:13 +0100282 /* Browse each pattern. */
283 list_for_each_entry(lst, &expr->patterns, list) {
284 pattern = &lst->pat;
285
286 /* Browse each group for searching group name that match the pattern. */
287 for (agl = u->u.groups; agl; agl = agl->next) {
288 if (strcmp(agl->group->name, pattern->ptr.str) == 0)
289 return pattern;
290 }
Thierry FOURNIER9eec0a62014-01-22 18:38:02 +0100291 }
Thierry FOURNIER5338eea2013-12-16 14:22:13 +0100292 return NULL;
Krzysztof Piotr Oledzkif9423ae2010-01-29 19:26:18 +0100293}