blob: 93af8d68cce922d64400d1a5fe6d5bdd72a6d887 [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
13#define _XOPEN_SOURCE 500
14
15#include <stdio.h>
16#include <stdlib.h>
17#include <string.h>
18#include <unistd.h>
19
20#include <common/config.h>
21
22#include <proto/acl.h>
23#include <proto/log.h>
24
25#include <types/auth.h>
26
27struct userlist *userlist = NULL; /* list of all existing userlists */
28
29/* find targets for selected gropus. The function returns pointer to
30 * the userlist struct ot NULL if name is NULL/empty or unresolvable.
31 */
32
33struct userlist *
34auth_find_userlist(char *name)
35{
36 struct userlist *l;
37
38 if (!name || !*name)
39 return NULL;
40
41 for (l = userlist; l; l = l->next)
42 if (!strcmp(l->name, name))
43 return l;
44
45 return NULL;
46}
47
48/* find group_mask for selected gropus. The function returns 1 if OK or nothing to do,
49 * 0 if case of unresolved groupname.
50 * WARING: the function destroys the list (strtok), so it can only be used once.
51 */
52
53unsigned int
54auth_resolve_groups(struct userlist *l, char *groups)
55{
56
57 char *group = NULL;
58 unsigned int g, group_mask = 0;
59
60 if (!groups || !*groups)
61 return 0;
62
63 while ((group = strtok(group?NULL:groups," "))) {
64 for (g = 0; g < l->grpcnt; g++)
65 if (!strcmp(l->groups[g], group))
66 break;
67
68 if (g == l->grpcnt) {
69 Alert("No such group '%s' in userlist '%s'.\n",
70 group, l->name);
71 return 0;
72 }
73
74 group_mask |= (1 << g);
75 }
76
77 return group_mask;
78}
79
80struct req_acl_rule *
Willy Tarreau9cc670f2010-02-01 10:43:44 +010081parse_auth_cond(const char **args, const char *file, int linenum, struct proxy *proxy)
Krzysztof Piotr Oledzki96105042010-01-29 17:50:44 +010082{
83 struct req_acl_rule *req_acl;
84 int cur_arg;
85
86 req_acl = (struct req_acl_rule*)calloc(1, sizeof(struct req_acl_rule));
87 if (!req_acl) {
88 Alert("parsing [%s:%d]: out of memory.\n", file, linenum);
89 return NULL;
90 }
91
92 if (!*args[0]) {
93 goto req_error_parsing;
94 } else if (!strcmp(args[0], "allow")) {
95 req_acl->action = PR_REQ_ACL_ACT_ALLOW;
96 cur_arg = 1;
97 } else if (!strcmp(args[0], "deny")) {
98 req_acl->action = PR_REQ_ACL_ACT_DENY;
99 cur_arg = 1;
100 } else if (!strcmp(args[0], "auth")) {
101 req_acl->action = PR_REQ_ACL_ACT_HTTP_AUTH;
102 cur_arg = 1;
103
104 while(*args[cur_arg]) {
105 if (!strcmp(args[cur_arg], "realm")) {
106 req_acl->http_auth.realm = strdup(args[cur_arg + 1]);
107 cur_arg+=2;
108 continue;
109 } else
110 break;
111 }
112 } else {
113req_error_parsing:
114 Alert("parsing [%s:%d]: %s '%s', expects 'allow', 'deny', 'auth'.\n",
115 file, linenum, *args[1]?"unknown parameter":"missing keyword in", args[*args[1]?1:0]);
116 return NULL;
117 }
118
Willy Tarreau9cc670f2010-02-01 10:43:44 +0100119 if (strcmp(args[cur_arg], "if") == 0 || strcmp(args[cur_arg], "unless") == 0) {
Krzysztof Piotr Oledzki96105042010-01-29 17:50:44 +0100120 struct acl_cond *cond;
121
Willy Tarreau9cc670f2010-02-01 10:43:44 +0100122 if ((cond = build_acl_cond(file, linenum, proxy, args+cur_arg)) == NULL) {
123 Alert("parsing [%s:%d] : error detected while parsing an 'http-request %s' condition.\n",
124 file, linenum, args[0]);
Krzysztof Piotr Oledzki96105042010-01-29 17:50:44 +0100125 return NULL;
126 }
Krzysztof Piotr Oledzki96105042010-01-29 17:50:44 +0100127 req_acl->cond = cond;
128 }
Willy Tarreau9cc670f2010-02-01 10:43:44 +0100129 else if (*args[cur_arg]) {
130 Alert("parsing [%s:%d]: 'http-request %s' expects 'realm' for 'auth' or"
131 " either 'if' or 'unless' followed by a condition but found '%s'.\n",
132 file, linenum, args[0], args[cur_arg]);
133 return NULL;
134 }
Krzysztof Piotr Oledzki96105042010-01-29 17:50:44 +0100135
136 return req_acl;
137}
138
139void
140userlist_free(struct userlist *ul)
141{
142 struct userlist *tul;
143 struct auth_users *au, *tau;
144 int i;
145
146 while (ul) {
147 au = ul->users;
148 while (au) {
149 tau = au;
150 au = au->next;
151 free(tau->user);
152 free(tau->pass);
153 free(tau);
154 }
155
156 tul = ul;
157 ul = ul->next;
158
159 for (i = 0; i < tul->grpcnt; i++)
160 free(tul->groups[i]);
161
162 free(tul->name);
163 free(tul);
164 };
165}
166
167void
168req_acl_free(struct list *r) {
169 struct req_acl_rule *tr, *pr;
170
171 list_for_each_entry_safe(pr, tr, r, list) {
172 LIST_DEL(&pr->list);
173 if (pr->action == PR_REQ_ACL_ACT_HTTP_AUTH)
174 free(pr->http_auth.realm);
175
176 free(pr);
177 }
178}
179
180/*
181 * Authenticate and authorize user; return 1 if OK, 0 if case of error.
182 */
183int
184check_user(struct userlist *ul, unsigned int group_mask, const char *user, const char *pass)
185{
186
187 struct auth_users *u;
188 const char *ep;
189
190#ifdef DEBUG_AUTH
191 fprintf(stderr, "req: userlist=%s, user=%s, pass=%s, group_mask=%u\n",
192 ul->name, user, pass, group_mask);
193#endif
194
195 for (u = ul->users; u; u = u->next)
196 if (!strcmp(user, u->user))
197 break;
198
199 if (!u)
200 return 0;
201
202#ifdef DEBUG_AUTH
203 fprintf(stderr, "cfg: user=%s, pass=%s, group_mask=%u, flags=%X",
204 u->user, u->pass, u->group_mask, u->flags);
205#endif
206
207 /*
208 * if user matches but group does not,
209 * it makes no sens to check passwords
210 */
Willy Tarreaub4c06b72010-02-02 11:28:20 +0100211 if (group_mask && !(group_mask & u->u.group_mask))
Krzysztof Piotr Oledzki96105042010-01-29 17:50:44 +0100212 return 0;
213
214 if (!(u->flags & AU_O_INSECURE)) {
215#ifdef CONFIG_HAP_CRYPT
216 ep = crypt(pass, u->pass);
217#else
218 return 0;
219#endif
220 } else
221 ep = pass;
222
223#ifdef DEBUG_AUTH
224 fprintf(stderr, ", crypt=%s\n", ep);
225#endif
226
227 if (!strcmp(ep, u->pass))
228 return 1;
229 else
230 return 0;
231}
Krzysztof Piotr Oledzkif9423ae2010-01-29 19:26:18 +0100232
233int
234acl_match_auth(struct acl_test *test, struct acl_pattern *pattern)
235{
236
237 struct userlist *ul = test->ctx.a[0];
238 char *user = test->ctx.a[1];
239 char *pass = test->ctx.a[2];
240 unsigned int group_mask;
241
242 if (pattern)
243 group_mask = pattern->val.group_mask;
244 else
245 group_mask = 0;
246
247 if (check_user(ul, group_mask, user, pass))
248 return ACL_PAT_PASS;
249 else
250 return ACL_PAT_FAIL;
251}