blob: 58fc5bea8a575dd4e4dc875c8e7639a942fca540 [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 *
81parse_auth_cond(const char **args, const char *file, int linenum, struct list *known_acl, int *acl_requires)
82{
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
119 if (*args[cur_arg]) {
120 int pol = ACL_COND_NONE;
121 struct acl_cond *cond;
122
123 if (!strcmp(args[cur_arg], "if"))
124 pol = ACL_COND_IF;
125 else if (!strcmp(args[cur_arg], "unless"))
126 pol = ACL_COND_UNLESS;
127 else {
128 Alert("parsing [%s:%d]: '%s' expects 'realm' for 'auth' or"
129 " either 'if' or 'unless' followed by a condition but found '%s'.\n",
130 file, linenum, args[0], args[cur_arg]);
131 return NULL;
132 }
133
134 if ((cond = parse_acl_cond((const char **)args + cur_arg + 1, known_acl, pol)) == NULL) {
135 Alert("parsing [%s:%d]: error detected while parsing 'req' condition.\n",
136 file, linenum);
137 return NULL;
138 }
139
140 cond->file = file;
141 cond->line = linenum;
142 *acl_requires |= cond->requires;
143 req_acl->cond = cond;
144 }
145
146 return req_acl;
147}
148
149void
150userlist_free(struct userlist *ul)
151{
152 struct userlist *tul;
153 struct auth_users *au, *tau;
154 int i;
155
156 while (ul) {
157 au = ul->users;
158 while (au) {
159 tau = au;
160 au = au->next;
161 free(tau->user);
162 free(tau->pass);
163 free(tau);
164 }
165
166 tul = ul;
167 ul = ul->next;
168
169 for (i = 0; i < tul->grpcnt; i++)
170 free(tul->groups[i]);
171
172 free(tul->name);
173 free(tul);
174 };
175}
176
177void
178req_acl_free(struct list *r) {
179 struct req_acl_rule *tr, *pr;
180
181 list_for_each_entry_safe(pr, tr, r, list) {
182 LIST_DEL(&pr->list);
183 if (pr->action == PR_REQ_ACL_ACT_HTTP_AUTH)
184 free(pr->http_auth.realm);
185
186 free(pr);
187 }
188}
189
190/*
191 * Authenticate and authorize user; return 1 if OK, 0 if case of error.
192 */
193int
194check_user(struct userlist *ul, unsigned int group_mask, const char *user, const char *pass)
195{
196
197 struct auth_users *u;
198 const char *ep;
199
200#ifdef DEBUG_AUTH
201 fprintf(stderr, "req: userlist=%s, user=%s, pass=%s, group_mask=%u\n",
202 ul->name, user, pass, group_mask);
203#endif
204
205 for (u = ul->users; u; u = u->next)
206 if (!strcmp(user, u->user))
207 break;
208
209 if (!u)
210 return 0;
211
212#ifdef DEBUG_AUTH
213 fprintf(stderr, "cfg: user=%s, pass=%s, group_mask=%u, flags=%X",
214 u->user, u->pass, u->group_mask, u->flags);
215#endif
216
217 /*
218 * if user matches but group does not,
219 * it makes no sens to check passwords
220 */
221 if (group_mask && !(group_mask & u->group_mask))
222 return 0;
223
224 if (!(u->flags & AU_O_INSECURE)) {
225#ifdef CONFIG_HAP_CRYPT
226 ep = crypt(pass, u->pass);
227#else
228 return 0;
229#endif
230 } else
231 ep = pass;
232
233#ifdef DEBUG_AUTH
234 fprintf(stderr, ", crypt=%s\n", ep);
235#endif
236
237 if (!strcmp(ep, u->pass))
238 return 1;
239 else
240 return 0;
241}