~ubuntu-branches/ubuntu/vivid/haproxy/vivid

« back to all changes in this revision

Viewing changes to src/auth.c

  • Committer: Package Import Robot
  • Author(s): Apollon Oikonomopoulos
  • Date: 2014-06-20 11:05:17 UTC
  • mfrom: (1.1.15) (15.1.12 experimental)
  • Revision ID: package-import@ubuntu.com-20140620110517-u6q5p9kyy2f3ozw9
Tags: 1.5.0-1
* New upstream stable series. Notable changes since the 1.4 series:
  + Native SSL support on both sides with SNI/NPN/ALPN and OCSP stapling.
  + IPv6 and UNIX sockets are supported everywhere
  + End-to-end HTTP keep-alive for better support of NTLM and improved
    efficiency in static farms
  + HTTP/1.1 response compression (deflate, gzip) to save bandwidth
  + PROXY protocol versions 1 and 2 on both sides
  + Data sampling on everything in request or response, including payload
  + ACLs can use any matching method with any input sample
  + Maps and dynamic ACLs updatable from the CLI
  + Stick-tables support counters to track activity on any input sample
  + Custom format for logs, unique-id, header rewriting, and redirects
  + Improved health checks (SSL, scripted TCP, check agent, ...)
  + Much more scalable configuration supports hundreds of thousands of
    backends and certificates without sweating

* Upload to unstable, merge all 1.5 work from experimental. Most important
  packaging changes since 1.4.25-1 include:
  + systemd support.
  + A more sane default config file.
  + Zero-downtime upgrades between 1.5 releases by gracefully reloading
    HAProxy during upgrades.
  + HTML documentation shipped in the haproxy-doc package.
  + kqueue support for kfreebsd.

* Packaging changes since 1.5~dev26-2:
  + Drop patches merged upstream:
    o Fix-reference-location-in-manpage.patch
    o 0001-BUILD-stats-workaround-stupid-and-bogus-Werror-forma.patch
  + d/watch: look for stable 1.5 releases
  + systemd: respect CONFIG and EXTRAOPTS when specified in
    /etc/default/haproxy.
  + initscript: test the configuration before start or reload.
  + initscript: remove the ENABLED flag and logic.

Show diffs side-by-side

added added

removed removed

Lines of Context:
26
26
#include <unistd.h>
27
27
 
28
28
#include <common/config.h>
 
29
#include <common/errors.h>
29
30
 
30
31
#include <proto/acl.h>
31
32
#include <proto/log.h>
32
33
 
33
34
#include <types/auth.h>
 
35
#include <types/pattern.h>
34
36
 
35
37
struct userlist *userlist = NULL;    /* list of all existing userlists */
36
38
 
53
55
        return NULL;
54
56
}
55
57
 
56
 
/* find group_mask for selected gropus. The function returns 1 if OK or nothing to do,
57
 
 * 0 if case of unresolved groupname.
58
 
 * WARING: the function destroys the list (strtok), so it can only be used once.
59
 
 */
60
 
 
61
 
unsigned int
62
 
auth_resolve_groups(struct userlist *l, char *groups)
63
 
{
64
 
 
65
 
        char *group = NULL;
66
 
        unsigned int g, group_mask = 0;
67
 
 
68
 
        if (!groups || !*groups)
69
 
                return 0;
70
 
 
71
 
        while ((group = strtok(group?NULL:groups," "))) {
72
 
                for (g = 0; g < l->grpcnt; g++)
73
 
                        if (!strcmp(l->groups[g], group))
74
 
                                break;
75
 
 
76
 
                if (g == l->grpcnt) {
77
 
                        Alert("No such group '%s' in userlist '%s'.\n",
78
 
                                group, l->name);
79
 
                        return 0;
80
 
                }
81
 
 
82
 
                group_mask |= (1 << g);
83
 
        }
84
 
 
85
 
        return group_mask;
86
 
}
87
 
 
88
 
struct req_acl_rule *
89
 
parse_auth_cond(const char **args, const char *file, int linenum, struct proxy *proxy)
90
 
{
91
 
        struct req_acl_rule *req_acl;
92
 
        int cur_arg;
93
 
 
94
 
        req_acl = (struct req_acl_rule*)calloc(1, sizeof(struct req_acl_rule));
95
 
        if (!req_acl) {
96
 
                Alert("parsing [%s:%d]: out of memory.\n", file, linenum);
97
 
                return NULL;
98
 
        }
99
 
 
100
 
        if (!*args[0]) {
101
 
                goto req_error_parsing;
102
 
        } else if (!strcmp(args[0], "allow")) {
103
 
                req_acl->action = PR_REQ_ACL_ACT_ALLOW;
104
 
                cur_arg = 1;
105
 
        } else if (!strcmp(args[0], "deny")) {
106
 
                req_acl->action = PR_REQ_ACL_ACT_DENY;
107
 
                cur_arg = 1;
108
 
        } else if (!strcmp(args[0], "auth")) {
109
 
                req_acl->action = PR_REQ_ACL_ACT_HTTP_AUTH;
110
 
                cur_arg = 1;
111
 
 
112
 
                while(*args[cur_arg]) {
113
 
                        if (!strcmp(args[cur_arg], "realm")) {
114
 
                                req_acl->http_auth.realm = strdup(args[cur_arg + 1]);
115
 
                                cur_arg+=2;
116
 
                                continue;
117
 
                        } else
118
 
                                break;
119
 
                }
120
 
        } else {
121
 
req_error_parsing:
122
 
                Alert("parsing [%s:%d]: %s '%s', expects 'allow', 'deny', 'auth'.\n",
123
 
                        file, linenum, *args[1]?"unknown parameter":"missing keyword in", args[*args[1]?1:0]);
124
 
                return NULL;
125
 
        }
126
 
 
127
 
        if (strcmp(args[cur_arg], "if") == 0 || strcmp(args[cur_arg], "unless") == 0) {
128
 
                struct acl_cond *cond;
129
 
 
130
 
                if ((cond = build_acl_cond(file, linenum, proxy, args+cur_arg)) == NULL) {
131
 
                        Alert("parsing [%s:%d] : error detected while parsing an 'http-request %s' condition.\n",
132
 
                              file, linenum, args[0]);
133
 
                        return NULL;
134
 
                }
135
 
                req_acl->cond = cond;
136
 
        }
137
 
        else if (*args[cur_arg]) {
138
 
                Alert("parsing [%s:%d]: 'http-request %s' expects 'realm' for 'auth' or"
139
 
                      " either 'if' or 'unless' followed by a condition but found '%s'.\n",
140
 
                      file, linenum, args[0], args[cur_arg]);
141
 
                return NULL;
142
 
        }
143
 
 
144
 
        return req_acl;
 
58
int check_group(struct userlist *ul, char *name)
 
59
{
 
60
        struct auth_groups *ag;
 
61
 
 
62
        for (ag = ul->groups; ag; ag = ag->next)
 
63
                if (strcmp(name, ag->name) == 0)
 
64
                        return 1;
 
65
        return 0;
145
66
}
146
67
 
147
68
void
149
70
{
150
71
        struct userlist *tul;
151
72
        struct auth_users *au, *tau;
152
 
        int i;
 
73
        struct auth_groups_list *agl, *tagl;
 
74
        struct auth_groups *ag, *tag;
153
75
 
154
76
        while (ul) {
 
77
                /* Free users. */
155
78
                au = ul->users;
156
79
                while (au) {
 
80
                        /* 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
 
157
88
                        tau = au;
158
89
                        au = au->next;
159
90
                        free(tau->user);
161
92
                        free(tau);
162
93
                }
163
94
 
 
95
                /* 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
 
164
104
                tul = ul;
165
105
                ul = ul->next;
166
 
 
167
 
                for (i = 0; i < tul->grpcnt; i++)
168
 
                        free(tul->groups[i]);
169
 
 
170
106
                free(tul->name);
171
107
                free(tul);
172
108
        };
173
109
}
174
110
 
175
 
void
176
 
req_acl_free(struct list *r) {
177
 
        struct req_acl_rule *tr, *pr;
178
 
 
179
 
        list_for_each_entry_safe(pr, tr, r, list) {
180
 
                LIST_DEL(&pr->list);
181
 
                if (pr->action == PR_REQ_ACL_ACT_HTTP_AUTH)
182
 
                        free(pr->http_auth.realm);
183
 
 
184
 
                free(pr);
 
111
int 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);
 
137
                                        free(groups);
 
138
                                        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);
 
146
                                        free(groups);
 
147
                                        return ERR_ALERT | ERR_FATAL;
 
148
                                }
 
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
185
208
        }
 
209
 
 
210
        return ERR_NONE;
186
211
}
187
212
 
188
213
/*
189
214
 * Authenticate and authorize user; return 1 if OK, 0 if case of error.
190
215
 */
191
216
int
192
 
check_user(struct userlist *ul, unsigned int group_mask, const char *user, const char *pass)
 
217
check_user(struct userlist *ul, const char *user, const char *pass)
193
218
{
194
219
 
195
220
        struct auth_users *u;
196
221
        const char *ep;
197
222
 
198
223
#ifdef DEBUG_AUTH
199
 
        fprintf(stderr, "req: userlist=%s, user=%s, pass=%s, group_mask=%u\n",
200
 
                ul->name, user, pass, group_mask);
 
224
        fprintf(stderr, "req: userlist=%s, user=%s, pass=%s, group=%s\n",
 
225
                ul->name, user, pass, group);
201
226
#endif
202
227
 
203
228
        for (u = ul->users; u; u = u->next)
208
233
                return 0;
209
234
 
210
235
#ifdef DEBUG_AUTH
211
 
        fprintf(stderr, "cfg: user=%s, pass=%s, group_mask=%u, flags=%X",
212
 
                u->user, u->pass, u->group_mask, u->flags);
 
236
        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);
213
240
#endif
214
241
 
215
 
        /*
216
 
         * if user matches but group does not,
217
 
         * it makes no sens to check passwords
218
 
         */
219
 
        if (group_mask && !(group_mask & u->u.group_mask))
220
 
                return 0;
221
 
 
222
242
        if (!(u->flags & AU_O_INSECURE)) {
223
243
#ifdef CONFIG_HAP_CRYPT
224
244
                ep = crypt(pass, u->pass);
238
258
                return 0;
239
259
}
240
260
 
241
 
int
242
 
acl_match_auth(struct acl_test *test, struct acl_pattern *pattern)
 
261
struct pattern *
 
262
pat_match_auth(struct sample *smp, struct pattern_expr *expr, int fill)
243
263
{
244
 
 
245
 
        struct userlist *ul = test->ctx.a[0];
246
 
        char *user = test->ctx.a[1];
247
 
        char *pass = test->ctx.a[2];
248
 
        unsigned int group_mask;
249
 
 
250
 
        if (pattern)
251
 
                group_mask = pattern->val.group_mask;
252
 
        else
253
 
                group_mask = 0;
254
 
 
255
 
        if (check_user(ul, group_mask, user, pass))
256
 
                return ACL_PAT_PASS;
257
 
        else
258
 
                return ACL_PAT_FAIL;
 
264
        struct userlist *ul = smp->ctx.a[0];
 
265
        struct pattern_list *lst;
 
266
        struct auth_users *u;
 
267
        struct auth_groups_list *agl;
 
268
        struct pattern *pattern;
 
269
 
 
270
        /* Check if the userlist is present in the context data. */
 
271
        if (!ul)
 
272
                return NULL;
 
273
 
 
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)
 
280
                return NULL;
 
281
 
 
282
        /* 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
                }
 
291
        }
 
292
        return NULL;
259
293
}