blob: b0418892e8fbf2a1adfb3290b9ed21873c88e7e3 [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
Willy Tarreaue8692b42016-12-21 19:36:25 +010028#include <types/global.h>
Krzysztof Piotr Oledzki96105042010-01-29 17:50:44 +010029#include <common/config.h>
Thierry FOURNIER9eec0a62014-01-22 18:38:02 +010030#include <common/errors.h>
Krzysztof Piotr Oledzki96105042010-01-29 17:50:44 +010031
32#include <proto/acl.h>
33#include <proto/log.h>
34
35#include <types/auth.h>
Thierry FOURNIERa65b3432013-11-28 18:22:00 +010036#include <types/pattern.h>
Krzysztof Piotr Oledzki96105042010-01-29 17:50:44 +010037
38struct userlist *userlist = NULL; /* list of all existing userlists */
39
40/* find targets for selected gropus. The function returns pointer to
41 * the userlist struct ot NULL if name is NULL/empty or unresolvable.
42 */
43
44struct userlist *
45auth_find_userlist(char *name)
46{
47 struct userlist *l;
48
49 if (!name || !*name)
50 return NULL;
51
52 for (l = userlist; l; l = l->next)
53 if (!strcmp(l->name, name))
54 return l;
55
56 return NULL;
57}
58
Thierry FOURNIER9eec0a62014-01-22 18:38:02 +010059int check_group(struct userlist *ul, char *name)
Krzysztof Piotr Oledzki96105042010-01-29 17:50:44 +010060{
Thierry FOURNIER9eec0a62014-01-22 18:38:02 +010061 struct auth_groups *ag;
Krzysztof Piotr Oledzki96105042010-01-29 17:50:44 +010062
Thierry FOURNIER9eec0a62014-01-22 18:38:02 +010063 for (ag = ul->groups; ag; ag = ag->next)
64 if (strcmp(name, ag->name) == 0)
65 return 1;
66 return 0;
Krzysztof Piotr Oledzki96105042010-01-29 17:50:44 +010067}
68
Krzysztof Piotr Oledzki96105042010-01-29 17:50:44 +010069void
70userlist_free(struct userlist *ul)
71{
72 struct userlist *tul;
73 struct auth_users *au, *tau;
Thierry FOURNIER9eec0a62014-01-22 18:38:02 +010074 struct auth_groups_list *agl, *tagl;
75 struct auth_groups *ag, *tag;
Krzysztof Piotr Oledzki96105042010-01-29 17:50:44 +010076
77 while (ul) {
Thierry FOURNIER9eec0a62014-01-22 18:38:02 +010078 /* Free users. */
Krzysztof Piotr Oledzki96105042010-01-29 17:50:44 +010079 au = ul->users;
80 while (au) {
Thierry FOURNIER9eec0a62014-01-22 18:38:02 +010081 /* Free groups that own current user. */
82 agl = au->u.groups;
83 while (agl) {
84 tagl = agl;
85 agl = agl->next;
86 free(tagl);
87 }
88
Krzysztof Piotr Oledzki96105042010-01-29 17:50:44 +010089 tau = au;
90 au = au->next;
91 free(tau->user);
92 free(tau->pass);
93 free(tau);
94 }
95
Thierry FOURNIER9eec0a62014-01-22 18:38:02 +010096 /* Free grouplist. */
97 ag = ul->groups;
98 while (ag) {
99 tag = ag;
100 ag = ag->next;
101 free(tag->name);
102 free(tag);
103 }
104
Krzysztof Piotr Oledzki96105042010-01-29 17:50:44 +0100105 tul = ul;
106 ul = ul->next;
Krzysztof Piotr Oledzki96105042010-01-29 17:50:44 +0100107 free(tul->name);
108 free(tul);
109 };
110}
111
Thierry FOURNIER9eec0a62014-01-22 18:38:02 +0100112int userlist_postinit()
113{
114 struct userlist *curuserlist = NULL;
115
116 /* Resolve usernames and groupnames. */
117 for (curuserlist = userlist; curuserlist; curuserlist = curuserlist->next) {
118 struct auth_groups *ag;
119 struct auth_users *curuser;
120 struct auth_groups_list *grl;
121
122 for (curuser = curuserlist->users; curuser; curuser = curuser->next) {
123 char *group = NULL;
124 struct auth_groups_list *groups = NULL;
125
126 if (!curuser->u.groups_names)
127 continue;
128
129 while ((group = strtok(group?NULL:curuser->u.groups_names, ","))) {
130 for (ag = curuserlist->groups; ag; ag = ag->next) {
131 if (!strcmp(ag->name, group))
132 break;
133 }
134
135 if (!ag) {
136 Alert("userlist '%s': no such group '%s' specified in user '%s'\n",
137 curuserlist->name, group, curuser->user);
Dirkjan Bussink07fcaaa2014-04-28 22:57:16 +0000138 free(groups);
Thierry FOURNIER9eec0a62014-01-22 18:38:02 +0100139 return ERR_ALERT | ERR_FATAL;
140 }
141
142 /* Add this group at the group userlist. */
143 grl = calloc(1, sizeof(*grl));
144 if (!grl) {
145 Alert("userlist '%s': no more memory when trying to allocate the user groups.\n",
146 curuserlist->name);
Dirkjan Bussink07fcaaa2014-04-28 22:57:16 +0000147 free(groups);
148 return ERR_ALERT | ERR_FATAL;
Thierry FOURNIER9eec0a62014-01-22 18:38:02 +0100149 }
150
151 grl->group = ag;
152 grl->next = groups;
153 groups = grl;
154 }
155
156 free(curuser->u.groups);
157 curuser->u.groups = groups;
158 }
159
160 for (ag = curuserlist->groups; ag; ag = ag->next) {
161 char *user = NULL;
162
163 if (!ag->groupusers)
164 continue;
165
166 while ((user = strtok(user?NULL:ag->groupusers, ","))) {
167 for (curuser = curuserlist->users; curuser; curuser = curuser->next) {
168 if (!strcmp(curuser->user, user))
169 break;
170 }
171
172 if (!curuser) {
173 Alert("userlist '%s': no such user '%s' specified in group '%s'\n",
174 curuserlist->name, user, ag->name);
175 return ERR_ALERT | ERR_FATAL;
176 }
177
178 /* Add this group at the group userlist. */
179 grl = calloc(1, sizeof(*grl));
180 if (!grl) {
181 Alert("userlist '%s': no more memory when trying to allocate the user groups.\n",
182 curuserlist->name);
183 return ERR_ALERT | ERR_FATAL;
184 }
185
186 grl->group = ag;
187 grl->next = curuser->u.groups;
188 curuser->u.groups = grl;
189 }
190
191 free(ag->groupusers);
192 ag->groupusers = NULL;
193 }
194
195#ifdef DEBUG_AUTH
196 for (ag = curuserlist->groups; ag; ag = ag->next) {
197 struct auth_groups_list *agl;
198
199 fprintf(stderr, "group %s, id %p, users:", ag->name, ag);
200 for (curuser = curuserlist->users; curuser; curuser = curuser->next) {
201 for (agl = curuser->u.groups; agl; agl = agl->next) {
202 if (agl->group == ag)
203 fprintf(stderr, " %s", curuser->user);
204 }
205 }
206 fprintf(stderr, "\n");
207 }
208#endif
209 }
210
211 return ERR_NONE;
212}
213
Krzysztof Piotr Oledzki96105042010-01-29 17:50:44 +0100214/*
215 * Authenticate and authorize user; return 1 if OK, 0 if case of error.
216 */
217int
Thierry FOURNIER9eec0a62014-01-22 18:38:02 +0100218check_user(struct userlist *ul, const char *user, const char *pass)
Krzysztof Piotr Oledzki96105042010-01-29 17:50:44 +0100219{
220
221 struct auth_users *u;
CJ Ess6eac32e2015-05-02 16:35:24 -0400222#ifdef DEBUG_AUTH
223 struct auth_groups_list *agl;
224#endif
Krzysztof Piotr Oledzki96105042010-01-29 17:50:44 +0100225 const char *ep;
226
227#ifdef DEBUG_AUTH
CJ Ess6eac32e2015-05-02 16:35:24 -0400228 fprintf(stderr, "req: userlist=%s, user=%s, pass=%s\n",
229 ul->name, user, pass);
Krzysztof Piotr Oledzki96105042010-01-29 17:50:44 +0100230#endif
231
232 for (u = ul->users; u; u = u->next)
233 if (!strcmp(user, u->user))
234 break;
235
236 if (!u)
237 return 0;
238
239#ifdef DEBUG_AUTH
Thierry FOURNIER9eec0a62014-01-22 18:38:02 +0100240 fprintf(stderr, "cfg: user=%s, pass=%s, flags=%X, groups=",
241 u->user, u->pass, u->flags);
242 for (agl = u->u.groups; agl; agl = agl->next)
243 fprintf(stderr, " %s", agl->group->name);
Krzysztof Piotr Oledzki96105042010-01-29 17:50:44 +0100244#endif
245
Krzysztof Piotr Oledzki96105042010-01-29 17:50:44 +0100246 if (!(u->flags & AU_O_INSECURE)) {
247#ifdef CONFIG_HAP_CRYPT
248 ep = crypt(pass, u->pass);
249#else
250 return 0;
251#endif
252 } else
253 ep = pass;
254
255#ifdef DEBUG_AUTH
256 fprintf(stderr, ", crypt=%s\n", ep);
257#endif
258
Cyril Bontéc82279c2014-08-29 20:20:01 +0200259 if (ep && strcmp(ep, u->pass) == 0)
Krzysztof Piotr Oledzki96105042010-01-29 17:50:44 +0100260 return 1;
261 else
262 return 0;
263}
Krzysztof Piotr Oledzkif9423ae2010-01-29 19:26:18 +0100264
Thierry FOURNIER5338eea2013-12-16 14:22:13 +0100265struct pattern *
266pat_match_auth(struct sample *smp, struct pattern_expr *expr, int fill)
Krzysztof Piotr Oledzkif9423ae2010-01-29 19:26:18 +0100267{
Willy Tarreau37406352012-04-23 16:16:37 +0200268 struct userlist *ul = smp->ctx.a[0];
Thierry FOURNIER5338eea2013-12-16 14:22:13 +0100269 struct pattern_list *lst;
Thierry FOURNIER9eec0a62014-01-22 18:38:02 +0100270 struct auth_users *u;
271 struct auth_groups_list *agl;
Thierry FOURNIER5338eea2013-12-16 14:22:13 +0100272 struct pattern *pattern;
Krzysztof Piotr Oledzkif9423ae2010-01-29 19:26:18 +0100273
Thierry FOURNIER9eec0a62014-01-22 18:38:02 +0100274 /* Check if the userlist is present in the context data. */
275 if (!ul)
Willy Tarreau86e0fc12014-04-29 19:52:16 +0200276 return NULL;
Thierry FOURNIER9eec0a62014-01-22 18:38:02 +0100277
278 /* Browse the userlist for searching user. */
279 for (u = ul->users; u; u = u->next) {
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200280 if (strcmp(smp->data.u.str.str, u->user) == 0)
Thierry FOURNIER9eec0a62014-01-22 18:38:02 +0100281 break;
282 }
283 if (!u)
Thierry FOURNIER5338eea2013-12-16 14:22:13 +0100284 return NULL;
Thierry FOURNIER9eec0a62014-01-22 18:38:02 +0100285
Thierry FOURNIER5338eea2013-12-16 14:22:13 +0100286 /* Browse each pattern. */
287 list_for_each_entry(lst, &expr->patterns, list) {
288 pattern = &lst->pat;
289
290 /* Browse each group for searching group name that match the pattern. */
291 for (agl = u->u.groups; agl; agl = agl->next) {
292 if (strcmp(agl->group->name, pattern->ptr.str) == 0)
293 return pattern;
294 }
Thierry FOURNIER9eec0a62014-01-22 18:38:02 +0100295 }
Thierry FOURNIER5338eea2013-12-16 14:22:13 +0100296 return NULL;
Krzysztof Piotr Oledzkif9423ae2010-01-29 19:26:18 +0100297}
Willy Tarreaue8692b42016-12-21 19:36:25 +0100298
299__attribute__((constructor))
300static void __auth_init(void)
301{
302 hap_register_build_opts("Encrypted password support via crypt(3): yes", 0);
303}