[MINOR] generic auth support with groups and encrypted passwords
Add generic authentication & authorization support. Groups are implemented as bitmaps so the count is limited to sizeof(int)*8 == 32. Encrypted passwords are supported with libcrypt and crypt(3), so it is possible to use any method supported by your system. For example modern Linux/glibc instalations support MD5/SHA-256/SHA-512 and of course classic, DES-based encryption.
This commit is contained in:
parent
fccbdc8421
commit
961050465e
16
Makefile
16
Makefile
|
@ -108,7 +108,8 @@ SMALL_OPTS =
|
|||
#### Debug settings
|
||||
# You can enable debugging on specific code parts by setting DEBUG=-DDEBUG_xxx.
|
||||
# Currently defined DEBUG macros include DEBUG_FULL, DEBUG_MEMORY, DEBUG_FSM,
|
||||
# and DEBUG_HASH. Please check sources for exact meaning or do not use at all.
|
||||
# DEBUG_HASH and DEBUG_AUTH. Please check sources for exact meaning or do not
|
||||
# use at all.
|
||||
DEBUG =
|
||||
|
||||
#### Additional include and library dirs
|
||||
|
@ -170,6 +171,7 @@ ifeq ($(TARGET),linux22)
|
|||
USE_GETSOCKNAME = implicit
|
||||
USE_POLL = implicit
|
||||
USE_TPROXY = implicit
|
||||
USE_LIBCRYPT = implicit
|
||||
else
|
||||
ifeq ($(TARGET),linux24)
|
||||
# This is for standard Linux 2.4 with netfilter but without epoll()
|
||||
|
@ -177,6 +179,7 @@ ifeq ($(TARGET),linux24)
|
|||
USE_NETFILTER = implicit
|
||||
USE_POLL = implicit
|
||||
USE_TPROXY = implicit
|
||||
USE_LIBCRYPT = implicit
|
||||
else
|
||||
ifeq ($(TARGET),linux24e)
|
||||
# This is for enhanced Linux 2.4 with netfilter and epoll() patch > 0.21
|
||||
|
@ -187,6 +190,7 @@ ifeq ($(TARGET),linux24e)
|
|||
USE_SEPOLL = implicit
|
||||
USE_MY_EPOLL = implicit
|
||||
USE_TPROXY = implicit
|
||||
USE_LIBCRYPT = implicit
|
||||
else
|
||||
ifeq ($(TARGET),linux26)
|
||||
# This is for standard Linux 2.6 with netfilter and standard epoll()
|
||||
|
@ -196,6 +200,7 @@ ifeq ($(TARGET),linux26)
|
|||
USE_EPOLL = implicit
|
||||
USE_SEPOLL = implicit
|
||||
USE_TPROXY = implicit
|
||||
USE_LIBCRYPT = implicit
|
||||
else
|
||||
ifeq ($(TARGET),solaris)
|
||||
# This is for Solaris 8
|
||||
|
@ -209,6 +214,7 @@ ifeq ($(TARGET),freebsd)
|
|||
USE_POLL = implicit
|
||||
USE_KQUEUE = implicit
|
||||
USE_TPROXY = implicit
|
||||
USE_LIBCRYPT = implicit
|
||||
else
|
||||
ifeq ($(TARGET),openbsd)
|
||||
# This is for OpenBSD >= 3.0
|
||||
|
@ -324,6 +330,12 @@ OPTIONS_CFLAGS += -DCONFIG_HAP_LINUX_TPROXY
|
|||
BUILD_OPTIONS += $(call ignore_implicit,USE_LINUX_TPROXY)
|
||||
endif
|
||||
|
||||
ifneq ($(USE_LIBCRYPT),)
|
||||
OPTIONS_CFLAGS += -DCONFIG_HAP_CRYPT
|
||||
BUILD_OPTIONS += $(call ignore_implicit,USE_LIBCRYPT)
|
||||
OPTIONS_LDFLAGS += -lcrypt
|
||||
endif
|
||||
|
||||
ifneq ($(USE_POLL),)
|
||||
OPTIONS_CFLAGS += -DENABLE_POLL
|
||||
OPTIONS_OBJS += src/ev_poll.o
|
||||
|
@ -464,7 +476,7 @@ OBJS = src/haproxy.o src/sessionhash.o src/base64.o src/protocols.o \
|
|||
src/lb_chash.o src/lb_fwlc.o src/lb_fwrr.o src/lb_map.o \
|
||||
src/stream_interface.o src/dumpstats.o src/proto_tcp.o \
|
||||
src/session.o src/hdr_idx.o src/ev_select.o src/signal.o \
|
||||
src/acl.o src/pattern.o src/memory.o src/freq_ctr.o
|
||||
src/acl.o src/pattern.o src/memory.o src/freq_ctr.o src/auth.o
|
||||
|
||||
EBTREE_OBJS = $(EBTREE_DIR)/ebtree.o \
|
||||
$(EBTREE_DIR)/eb32tree.o $(EBTREE_DIR)/eb64tree.o \
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#define CFG_NONE 0
|
||||
#define CFG_GLOBAL 1
|
||||
#define CFG_LISTEN 2
|
||||
#define CFG_USERLIST 3
|
||||
|
||||
struct cfg_keyword {
|
||||
int section; /* section type for this keyword */
|
||||
|
|
|
@ -15,6 +15,8 @@
|
|||
|
||||
#include <common/config.h>
|
||||
|
||||
#include <types/auth.h>
|
||||
|
||||
/* here we find a very basic list of base64-encoded 'user:passwd' strings */
|
||||
struct user_auth {
|
||||
struct user_auth *next; /* next entry, NULL if none */
|
||||
|
@ -46,6 +48,7 @@ struct uri_auth {
|
|||
int flags; /* some flags describing the statistics page */
|
||||
struct user_auth *users; /* linked list of valid user:passwd couples */
|
||||
struct stat_scope *scope; /* linked list of authorized proxies */
|
||||
struct list req_acl; /* */
|
||||
struct uri_auth *next; /* Used at deinit() to build a list of unique elements */
|
||||
};
|
||||
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* User authentication & authorization.
|
||||
*
|
||||
* Copyright 2010 Krzysztof Piotr Oledzki <ole@ans.pl>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version
|
||||
* 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _PROTO_AUTH_H
|
||||
#define _PROTO_AUTH_H
|
||||
|
||||
#include <common/config.h>
|
||||
#include <types/auth.h>
|
||||
|
||||
extern struct userlist *userlist;
|
||||
|
||||
struct userlist *auth_find_userlist(char *name);
|
||||
unsigned int auth_resolve_groups(struct userlist *l, char *groups);
|
||||
struct req_acl_rule *parse_auth_cond(const char **args, const char *file, int linenum, struct list *known_acl, int *acl_requires);
|
||||
void userlist_free(struct userlist *ul);
|
||||
void req_acl_free(struct list *r);
|
||||
int acl_match_auth(struct acl_test *test, struct acl_pattern *pattern);
|
||||
|
||||
#endif /* _PROTO_AUTH_H */
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* c-indent-level: 8
|
||||
* c-basic-offset: 8
|
||||
* End:
|
||||
*/
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
* User authentication & authorization.
|
||||
*
|
||||
* Copyright 2010 Krzysztof Piotr Oledzki <ole@ans.pl>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version
|
||||
* 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _TYPES_AUTH_H
|
||||
#define _TYPES_AUTH_H
|
||||
|
||||
#include <common/config.h>
|
||||
#include <common/mini-clist.h>
|
||||
|
||||
#include <types/auth.h>
|
||||
|
||||
#define MAX_AUTH_GROUPS (unsigned int)(sizeof(int)*8)
|
||||
|
||||
#define AU_O_INSECURE 0x00000001 /* insecure, unencrypted password */
|
||||
|
||||
enum {
|
||||
PR_REQ_ACL_ACT_UNKNOWN = 0,
|
||||
PR_REQ_ACL_ACT_ALLOW,
|
||||
PR_REQ_ACL_ACT_DENY,
|
||||
PR_REQ_ACL_ACT_HTTP_AUTH,
|
||||
|
||||
PR_REQ_ACL_ACT_MAX
|
||||
};
|
||||
|
||||
|
||||
struct req_acl_rule {
|
||||
struct list list;
|
||||
struct acl_cond *cond; /* acl condition to meet */
|
||||
unsigned int action;
|
||||
union {
|
||||
struct {
|
||||
char *realm;
|
||||
} http_auth;
|
||||
};
|
||||
};
|
||||
|
||||
struct auth_users {
|
||||
struct auth_users *next;
|
||||
unsigned int flags;
|
||||
char *user, *pass;
|
||||
union {
|
||||
char *groups;
|
||||
unsigned int group_mask;
|
||||
};
|
||||
};
|
||||
|
||||
struct userlist {
|
||||
struct userlist *next;
|
||||
char *name;
|
||||
struct auth_users *users;
|
||||
int grpcnt;
|
||||
char *groups[MAX_AUTH_GROUPS];
|
||||
char **groupusers;
|
||||
};
|
||||
|
||||
#endif /* _TYPES_AUTH_H */
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* c-indent-level: 8
|
||||
* c-basic-offset: 8
|
||||
* End:
|
||||
*/
|
||||
|
|
@ -0,0 +1,241 @@
|
|||
/*
|
||||
* User authentication & authorization
|
||||
*
|
||||
* Copyright 2010 Krzysztof Piotr Oledzki <ole@ans.pl>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version
|
||||
* 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
*/
|
||||
|
||||
#define _XOPEN_SOURCE 500
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <common/config.h>
|
||||
|
||||
#include <proto/acl.h>
|
||||
#include <proto/log.h>
|
||||
|
||||
#include <types/auth.h>
|
||||
|
||||
struct userlist *userlist = NULL; /* list of all existing userlists */
|
||||
|
||||
/* find targets for selected gropus. The function returns pointer to
|
||||
* the userlist struct ot NULL if name is NULL/empty or unresolvable.
|
||||
*/
|
||||
|
||||
struct userlist *
|
||||
auth_find_userlist(char *name)
|
||||
{
|
||||
struct userlist *l;
|
||||
|
||||
if (!name || !*name)
|
||||
return NULL;
|
||||
|
||||
for (l = userlist; l; l = l->next)
|
||||
if (!strcmp(l->name, name))
|
||||
return l;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* find group_mask for selected gropus. The function returns 1 if OK or nothing to do,
|
||||
* 0 if case of unresolved groupname.
|
||||
* WARING: the function destroys the list (strtok), so it can only be used once.
|
||||
*/
|
||||
|
||||
unsigned int
|
||||
auth_resolve_groups(struct userlist *l, char *groups)
|
||||
{
|
||||
|
||||
char *group = NULL;
|
||||
unsigned int g, group_mask = 0;
|
||||
|
||||
if (!groups || !*groups)
|
||||
return 0;
|
||||
|
||||
while ((group = strtok(group?NULL:groups," "))) {
|
||||
for (g = 0; g < l->grpcnt; g++)
|
||||
if (!strcmp(l->groups[g], group))
|
||||
break;
|
||||
|
||||
if (g == l->grpcnt) {
|
||||
Alert("No such group '%s' in userlist '%s'.\n",
|
||||
group, l->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
group_mask |= (1 << g);
|
||||
}
|
||||
|
||||
return group_mask;
|
||||
}
|
||||
|
||||
struct req_acl_rule *
|
||||
parse_auth_cond(const char **args, const char *file, int linenum, struct list *known_acl, int *acl_requires)
|
||||
{
|
||||
struct req_acl_rule *req_acl;
|
||||
int cur_arg;
|
||||
|
||||
req_acl = (struct req_acl_rule*)calloc(1, sizeof(struct req_acl_rule));
|
||||
if (!req_acl) {
|
||||
Alert("parsing [%s:%d]: out of memory.\n", file, linenum);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!*args[0]) {
|
||||
goto req_error_parsing;
|
||||
} else if (!strcmp(args[0], "allow")) {
|
||||
req_acl->action = PR_REQ_ACL_ACT_ALLOW;
|
||||
cur_arg = 1;
|
||||
} else if (!strcmp(args[0], "deny")) {
|
||||
req_acl->action = PR_REQ_ACL_ACT_DENY;
|
||||
cur_arg = 1;
|
||||
} else if (!strcmp(args[0], "auth")) {
|
||||
req_acl->action = PR_REQ_ACL_ACT_HTTP_AUTH;
|
||||
cur_arg = 1;
|
||||
|
||||
while(*args[cur_arg]) {
|
||||
if (!strcmp(args[cur_arg], "realm")) {
|
||||
req_acl->http_auth.realm = strdup(args[cur_arg + 1]);
|
||||
cur_arg+=2;
|
||||
continue;
|
||||
} else
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
req_error_parsing:
|
||||
Alert("parsing [%s:%d]: %s '%s', expects 'allow', 'deny', 'auth'.\n",
|
||||
file, linenum, *args[1]?"unknown parameter":"missing keyword in", args[*args[1]?1:0]);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (*args[cur_arg]) {
|
||||
int pol = ACL_COND_NONE;
|
||||
struct acl_cond *cond;
|
||||
|
||||
if (!strcmp(args[cur_arg], "if"))
|
||||
pol = ACL_COND_IF;
|
||||
else if (!strcmp(args[cur_arg], "unless"))
|
||||
pol = ACL_COND_UNLESS;
|
||||
else {
|
||||
Alert("parsing [%s:%d]: '%s' expects 'realm' for 'auth' or"
|
||||
" either 'if' or 'unless' followed by a condition but found '%s'.\n",
|
||||
file, linenum, args[0], args[cur_arg]);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ((cond = parse_acl_cond((const char **)args + cur_arg + 1, known_acl, pol)) == NULL) {
|
||||
Alert("parsing [%s:%d]: error detected while parsing 'req' condition.\n",
|
||||
file, linenum);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cond->file = file;
|
||||
cond->line = linenum;
|
||||
*acl_requires |= cond->requires;
|
||||
req_acl->cond = cond;
|
||||
}
|
||||
|
||||
return req_acl;
|
||||
}
|
||||
|
||||
void
|
||||
userlist_free(struct userlist *ul)
|
||||
{
|
||||
struct userlist *tul;
|
||||
struct auth_users *au, *tau;
|
||||
int i;
|
||||
|
||||
while (ul) {
|
||||
au = ul->users;
|
||||
while (au) {
|
||||
tau = au;
|
||||
au = au->next;
|
||||
free(tau->user);
|
||||
free(tau->pass);
|
||||
free(tau);
|
||||
}
|
||||
|
||||
tul = ul;
|
||||
ul = ul->next;
|
||||
|
||||
for (i = 0; i < tul->grpcnt; i++)
|
||||
free(tul->groups[i]);
|
||||
|
||||
free(tul->name);
|
||||
free(tul);
|
||||
};
|
||||
}
|
||||
|
||||
void
|
||||
req_acl_free(struct list *r) {
|
||||
struct req_acl_rule *tr, *pr;
|
||||
|
||||
list_for_each_entry_safe(pr, tr, r, list) {
|
||||
LIST_DEL(&pr->list);
|
||||
if (pr->action == PR_REQ_ACL_ACT_HTTP_AUTH)
|
||||
free(pr->http_auth.realm);
|
||||
|
||||
free(pr);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Authenticate and authorize user; return 1 if OK, 0 if case of error.
|
||||
*/
|
||||
int
|
||||
check_user(struct userlist *ul, unsigned int group_mask, const char *user, const char *pass)
|
||||
{
|
||||
|
||||
struct auth_users *u;
|
||||
const char *ep;
|
||||
|
||||
#ifdef DEBUG_AUTH
|
||||
fprintf(stderr, "req: userlist=%s, user=%s, pass=%s, group_mask=%u\n",
|
||||
ul->name, user, pass, group_mask);
|
||||
#endif
|
||||
|
||||
for (u = ul->users; u; u = u->next)
|
||||
if (!strcmp(user, u->user))
|
||||
break;
|
||||
|
||||
if (!u)
|
||||
return 0;
|
||||
|
||||
#ifdef DEBUG_AUTH
|
||||
fprintf(stderr, "cfg: user=%s, pass=%s, group_mask=%u, flags=%X",
|
||||
u->user, u->pass, u->group_mask, u->flags);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* if user matches but group does not,
|
||||
* it makes no sens to check passwords
|
||||
*/
|
||||
if (group_mask && !(group_mask & u->group_mask))
|
||||
return 0;
|
||||
|
||||
if (!(u->flags & AU_O_INSECURE)) {
|
||||
#ifdef CONFIG_HAP_CRYPT
|
||||
ep = crypt(pass, u->pass);
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
} else
|
||||
ep = pass;
|
||||
|
||||
#ifdef DEBUG_AUTH
|
||||
fprintf(stderr, ", crypt=%s\n", ep);
|
||||
#endif
|
||||
|
||||
if (!strcmp(ep, u->pass))
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
252
src/cfgparse.c
252
src/cfgparse.c
|
@ -37,6 +37,7 @@
|
|||
#include <types/global.h>
|
||||
|
||||
#include <proto/acl.h>
|
||||
#include <proto/auth.h>
|
||||
#include <proto/backend.h>
|
||||
#include <proto/buffers.h>
|
||||
#include <proto/checks.h>
|
||||
|
@ -4008,6 +4009,175 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
|
|||
return err_code;
|
||||
}
|
||||
|
||||
int
|
||||
cfg_parse_users(const char *file, int linenum, char **args, int kwm)
|
||||
{
|
||||
|
||||
int err_code = 0;
|
||||
const char *err;
|
||||
|
||||
if (!strcmp(args[0], "userlist")) { /* new userlist */
|
||||
struct userlist *newul;
|
||||
|
||||
if (!*args[1]) {
|
||||
Alert("parsing [%s:%d]: '%s' expects <name> as arguments.\n",
|
||||
file, linenum, args[0]);
|
||||
err_code |= ERR_ALERT | ERR_FATAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
err = invalid_char(args[1]);
|
||||
if (err) {
|
||||
Alert("parsing [%s:%d]: character '%c' is not permitted in '%s' name '%s'.\n",
|
||||
file, linenum, *err, args[0], args[1]);
|
||||
err_code |= ERR_ALERT | ERR_FATAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (newul = userlist; newul; newul = newul->next)
|
||||
if (!strcmp(newul->name, args[1])) {
|
||||
Warning("parsing [%s:%d]: ignoring duplicated userlist '%s'.\n",
|
||||
file, linenum, args[1]);
|
||||
err_code |= ERR_WARN;
|
||||
goto out;
|
||||
}
|
||||
|
||||
newul = (struct userlist *)calloc(1, sizeof(struct userlist));
|
||||
if (!newul) {
|
||||
Alert("parsing [%s:%d]: out of memory.\n", file, linenum);
|
||||
err_code |= ERR_ALERT | ERR_ABORT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
newul->groupusers = calloc(MAX_AUTH_GROUPS, sizeof(char *));
|
||||
newul->name = strdup(args[1]);
|
||||
|
||||
if (!newul->groupusers | !newul->name) {
|
||||
Alert("parsing [%s:%d]: out of memory.\n", file, linenum);
|
||||
err_code |= ERR_ALERT | ERR_ABORT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
newul->next = userlist;
|
||||
userlist = newul;
|
||||
|
||||
} else if (!strcmp(args[0], "group")) { /* new group */
|
||||
int cur_arg, i;
|
||||
const char *err;
|
||||
|
||||
if (!*args[1]) {
|
||||
Alert("parsing [%s:%d]: '%s' expects <name> as arguments.\n",
|
||||
file, linenum, args[0]);
|
||||
err_code |= ERR_ALERT | ERR_FATAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
err = invalid_char(args[1]);
|
||||
if (err) {
|
||||
Alert("parsing [%s:%d]: character '%c' is not permitted in '%s' name '%s'.\n",
|
||||
file, linenum, *err, args[0], args[1]);
|
||||
err_code |= ERR_ALERT | ERR_FATAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
for(i = 0; i < userlist->grpcnt; i++)
|
||||
if (!strcmp(userlist->groups[i], args[1])) {
|
||||
Warning("parsing [%s:%d]: ignoring duplicated group '%s' in userlist '%s'.\n",
|
||||
file, linenum, args[1], userlist->name);
|
||||
err_code |= ERR_ALERT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (userlist->grpcnt >= MAX_AUTH_GROUPS) {
|
||||
Alert("parsing [%s:%d]: too many groups (%u) in in userlist '%s' while adding group '%s'.\n",
|
||||
file, linenum, MAX_AUTH_GROUPS, userlist->name, args[1]);
|
||||
err_code |= ERR_ALERT | ERR_FATAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
cur_arg = 2;
|
||||
|
||||
while (*args[cur_arg]) {
|
||||
if (!strcmp(args[cur_arg], "users")) {
|
||||
userlist->groupusers[userlist->grpcnt] = strdup(args[cur_arg + 1]);
|
||||
cur_arg += 2;
|
||||
continue;
|
||||
} else {
|
||||
Alert("parsing [%s:%d]: '%s' only supports 'users' option.\n",
|
||||
file, linenum, args[0]);
|
||||
err_code |= ERR_ALERT | ERR_FATAL;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
userlist->groups[userlist->grpcnt++] = strdup(args[1]);
|
||||
} else if (!strcmp(args[0], "user")) { /* new user */
|
||||
struct auth_users *newuser;
|
||||
int cur_arg;
|
||||
|
||||
if (!*args[1]) {
|
||||
Alert("parsing [%s:%d]: '%s' expects <name> as arguments.\n",
|
||||
file, linenum, args[0]);
|
||||
err_code |= ERR_ALERT | ERR_FATAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (newuser = userlist->users; newuser; newuser = newuser->next)
|
||||
if (!strcmp(newuser->user, args[1])) {
|
||||
Warning("parsing [%s:%d]: ignoring duplicated user '%s' in userlist '%s'.\n",
|
||||
file, linenum, args[1], userlist->name);
|
||||
err_code |= ERR_ALERT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
newuser = (struct auth_users *)calloc(1, sizeof(struct auth_users));
|
||||
if (!newuser) {
|
||||
Alert("parsing [%s:%d]: out of memory.\n", file, linenum);
|
||||
err_code |= ERR_ALERT | ERR_ABORT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
newuser->user = strdup(args[1]);
|
||||
|
||||
newuser->next = userlist->users;
|
||||
userlist->users = newuser;
|
||||
|
||||
cur_arg = 2;
|
||||
|
||||
while (*args[cur_arg]) {
|
||||
if (!strcmp(args[cur_arg], "password")) {
|
||||
#ifndef CONFIG_HAP_CRYPT
|
||||
Warning("parsing [%s:%d]: no crypt(3) support compiled, encrypted passwords will not work.\n",
|
||||
file, linenum);
|
||||
err_code |= ERR_ALERT;
|
||||
#endif
|
||||
newuser->pass = strdup(args[cur_arg + 1]);
|
||||
cur_arg += 2;
|
||||
continue;
|
||||
} else if (!strcmp(args[cur_arg], "insecure-password")) {
|
||||
newuser->pass = strdup(args[cur_arg + 1]);
|
||||
newuser->flags |= AU_O_INSECURE;
|
||||
cur_arg += 2;
|
||||
continue;
|
||||
} else if (!strcmp(args[cur_arg], "groups")) {
|
||||
newuser->groups = strdup(args[cur_arg + 1]);
|
||||
cur_arg += 2;
|
||||
continue;
|
||||
} else {
|
||||
Alert("parsing [%s:%d]: '%s' only supports 'password', 'insecure-password' and 'groups' options.\n",
|
||||
file, linenum, args[0]);
|
||||
err_code |= ERR_ALERT | ERR_FATAL;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Alert("parsing [%s:%d]: unknown keyword '%s' in '%s' section\n", file, linenum, args[0], "users");
|
||||
err_code |= ERR_ALERT | ERR_FATAL;
|
||||
}
|
||||
|
||||
out:
|
||||
return err_code;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function reads and parses the configuration file given in the argument.
|
||||
|
@ -4172,6 +4342,10 @@ int readcfgfile(const char *file)
|
|||
confsect = CFG_GLOBAL;
|
||||
free(cursection);
|
||||
cursection = strdup(args[0]);
|
||||
} else if (!strcmp(args[0], "userlist")) {
|
||||
confsect = CFG_USERLIST;
|
||||
free(cursection);
|
||||
cursection = strdup(args[0]);
|
||||
}
|
||||
/* else it's a section keyword */
|
||||
|
||||
|
@ -4182,8 +4356,11 @@ int readcfgfile(const char *file)
|
|||
case CFG_GLOBAL:
|
||||
err_code |= cfg_parse_global(file, linenum, args, kwm);
|
||||
break;
|
||||
case CFG_USERLIST:
|
||||
err_code |= cfg_parse_users(file, linenum, args, kwm);
|
||||
break;
|
||||
default:
|
||||
Alert("parsing [%s:%d] : unknown keyword '%s' out of section.\n", file, linenum, args[0]);
|
||||
Alert("parsing [%s:%d]: unknown keyword '%s' out of section.\n", file, linenum, args[0]);
|
||||
err_code |= ERR_ALERT | ERR_FATAL;
|
||||
}
|
||||
|
||||
|
@ -4210,6 +4387,7 @@ int check_config_validity()
|
|||
int cfgerr = 0;
|
||||
struct proxy *curproxy = NULL;
|
||||
struct server *newsrv = NULL;
|
||||
struct userlist *curuserlist = NULL;
|
||||
int err_code = 0;
|
||||
unsigned int next_pxid = 1;
|
||||
|
||||
|
@ -4817,6 +4995,78 @@ int check_config_validity()
|
|||
curproxy = curproxy->next;
|
||||
}
|
||||
|
||||
for (curuserlist = userlist; curuserlist; curuserlist = curuserlist->next) {
|
||||
struct auth_users *curuser;
|
||||
int g;
|
||||
|
||||
for (curuser = curuserlist->users; curuser; curuser = curuser->next) {
|
||||
unsigned int group_mask = 0;
|
||||
char *group = NULL;
|
||||
|
||||
if (!curuser->groups)
|
||||
continue;
|
||||
|
||||
while ((group = strtok(group?NULL:curuser->groups, ","))) {
|
||||
|
||||
for (g = 0; g < curuserlist->grpcnt; g++)
|
||||
if (!strcmp(curuserlist->groups[g], group))
|
||||
break;
|
||||
|
||||
if (g == curuserlist->grpcnt) {
|
||||
Alert("userlist '%s': no such group '%s' specified in user '%s'\n",
|
||||
curuserlist->name, group, curuser->user);
|
||||
err_code |= ERR_ALERT | ERR_FATAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
group_mask |= (1 << g);
|
||||
}
|
||||
|
||||
free(curuser->groups);
|
||||
curuser->group_mask = group_mask;
|
||||
}
|
||||
|
||||
for (g = 0; g < curuserlist->grpcnt; g++) {
|
||||
char *user = NULL;
|
||||
|
||||
if (!curuserlist->groupusers[g])
|
||||
continue;
|
||||
|
||||
while ((user = strtok(user?NULL:curuserlist->groupusers[g], ","))) {
|
||||
for (curuser = curuserlist->users; curuser; curuser = curuser->next)
|
||||
if (!strcmp(curuser->user, user))
|
||||
break;
|
||||
|
||||
if (!curuser) {
|
||||
Alert("userlist '%s': no such user '%s' specified in group '%s'\n",
|
||||
curuserlist->name, user, curuserlist->groups[g]);
|
||||
err_code |= ERR_ALERT | ERR_FATAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
curuser->group_mask |= (1 << g);
|
||||
}
|
||||
|
||||
free(curuserlist->groupusers[g]);
|
||||
}
|
||||
|
||||
free(curuserlist->groupusers);
|
||||
|
||||
#ifdef DEBUG_AUTH
|
||||
for (g = 0; g < curuserlist->grpcnt; g++) {
|
||||
fprintf(stderr, "group %s, id %d, mask %08X, users:", curuserlist->groups[g], g , 1 << g);
|
||||
|
||||
for (curuser = curuserlist->users; curuser; curuser = curuser->next) {
|
||||
if (curuser->group_mask & (1 << g))
|
||||
fprintf(stderr, " %s", curuser->user);
|
||||
}
|
||||
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Recount currently required checks.
|
||||
*/
|
||||
|
|
|
@ -67,6 +67,7 @@
|
|||
#include <types/capture.h>
|
||||
#include <types/global.h>
|
||||
|
||||
#include <proto/auth.h>
|
||||
#include <proto/acl.h>
|
||||
#include <proto/backend.h>
|
||||
#include <proto/buffers.h>
|
||||
|
@ -177,6 +178,16 @@ void display_build_opts()
|
|||
"\n\n",
|
||||
DEFAULT_MAXCONN, BUFSIZE, MAXREWRITE, MAX_POLL_EVENTS);
|
||||
|
||||
printf("Encrypted password support via crypt(3): "
|
||||
#ifdef CONFIG_HAP_CRYPT
|
||||
"yes"
|
||||
#else
|
||||
"no"
|
||||
#endif
|
||||
"\n");
|
||||
|
||||
putchar('\n');
|
||||
|
||||
list_pollers(stdout);
|
||||
putchar('\n');
|
||||
}
|
||||
|
@ -851,6 +862,7 @@ void deinit(void)
|
|||
pool_destroy2(p->req_cap_pool);
|
||||
pool_destroy2(p->rsp_cap_pool);
|
||||
pool_destroy2(p->hdr_idx_pool);
|
||||
|
||||
p0 = p;
|
||||
p = p->next;
|
||||
free(p0);
|
||||
|
@ -874,6 +886,8 @@ void deinit(void)
|
|||
free(uap);
|
||||
}
|
||||
|
||||
userlist_free(userlist);
|
||||
|
||||
protocol_unbind_all();
|
||||
|
||||
free(global.chroot); global.chroot = NULL;
|
||||
|
|
Loading…
Reference in New Issue