mirror of
http://git.haproxy.org/git/haproxy.git/
synced 2024-12-17 17:04:35 +00:00
b8888ab557
This is 15th iteration of typo fixes
317 lines
6.9 KiB
C
317 lines
6.9 KiB
C
/*
|
|
* 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.
|
|
*
|
|
*/
|
|
|
|
#ifdef USE_LIBCRYPT
|
|
/* This is to have crypt() defined on Linux */
|
|
#define _GNU_SOURCE
|
|
|
|
#ifdef USE_CRYPT_H
|
|
/* some platforms such as Solaris need this */
|
|
#include <crypt.h>
|
|
#endif
|
|
#endif /* USE_LIBCRYPT */
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
|
|
#include <haproxy/api.h>
|
|
#include <haproxy/auth-t.h>
|
|
#include <haproxy/errors.h>
|
|
#include <haproxy/global.h>
|
|
#include <haproxy/pattern-t.h>
|
|
#include <haproxy/sample-t.h>
|
|
#include <haproxy/thread.h>
|
|
|
|
struct userlist *userlist = NULL; /* list of all existing userlists */
|
|
|
|
#ifdef USE_LIBCRYPT
|
|
#define CRYPT_STATE_MSG "yes"
|
|
#ifdef HA_HAVE_CRYPT_R
|
|
/* context for crypt_r() */
|
|
static THREAD_LOCAL struct crypt_data crypt_data = { .initialized = 0 };
|
|
#else
|
|
/* lock for crypt() */
|
|
__decl_thread(static HA_SPINLOCK_T auth_lock);
|
|
#endif
|
|
#else /* USE_LIBCRYPT */
|
|
#define CRYPT_STATE_MSG "no"
|
|
#endif
|
|
|
|
/* find targets for selected groups. The function returns pointer to
|
|
* the userlist struct or 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) == 0)
|
|
return l;
|
|
|
|
return NULL;
|
|
}
|
|
|
|
int check_group(struct userlist *ul, char *name)
|
|
{
|
|
struct auth_groups *ag;
|
|
|
|
for (ag = ul->groups; ag; ag = ag->next)
|
|
if (strcmp(name, ag->name) == 0)
|
|
return 1;
|
|
return 0;
|
|
}
|
|
|
|
void
|
|
userlist_free(struct userlist *ul)
|
|
{
|
|
struct userlist *tul;
|
|
struct auth_users *au, *tau;
|
|
struct auth_groups_list *agl, *tagl;
|
|
struct auth_groups *ag, *tag;
|
|
|
|
while (ul) {
|
|
/* Free users. */
|
|
au = ul->users;
|
|
while (au) {
|
|
/* Free groups that own current user. */
|
|
agl = au->u.groups;
|
|
while (agl) {
|
|
tagl = agl;
|
|
agl = agl->next;
|
|
free(tagl);
|
|
}
|
|
|
|
tau = au;
|
|
au = au->next;
|
|
free(tau->user);
|
|
free(tau->pass);
|
|
free(tau);
|
|
}
|
|
|
|
/* Free grouplist. */
|
|
ag = ul->groups;
|
|
while (ag) {
|
|
tag = ag;
|
|
ag = ag->next;
|
|
free(tag->name);
|
|
free(tag);
|
|
}
|
|
|
|
tul = ul;
|
|
ul = ul->next;
|
|
free(tul->name);
|
|
free(tul);
|
|
};
|
|
}
|
|
|
|
int userlist_postinit()
|
|
{
|
|
struct userlist *curuserlist = NULL;
|
|
|
|
/* Resolve usernames and groupnames. */
|
|
for (curuserlist = userlist; curuserlist; curuserlist = curuserlist->next) {
|
|
struct auth_groups *ag;
|
|
struct auth_users *curuser;
|
|
struct auth_groups_list *grl;
|
|
|
|
for (curuser = curuserlist->users; curuser; curuser = curuser->next) {
|
|
char *group = NULL;
|
|
struct auth_groups_list *groups = NULL;
|
|
|
|
if (!curuser->u.groups_names)
|
|
continue;
|
|
|
|
while ((group = strtok(group?NULL:curuser->u.groups_names, ","))) {
|
|
for (ag = curuserlist->groups; ag; ag = ag->next) {
|
|
if (strcmp(ag->name, group) == 0)
|
|
break;
|
|
}
|
|
|
|
if (!ag) {
|
|
ha_alert("userlist '%s': no such group '%s' specified in user '%s'\n",
|
|
curuserlist->name, group, curuser->user);
|
|
free(groups);
|
|
return ERR_ALERT | ERR_FATAL;
|
|
}
|
|
|
|
/* Add this group at the group userlist. */
|
|
grl = calloc(1, sizeof(*grl));
|
|
if (!grl) {
|
|
ha_alert("userlist '%s': no more memory when trying to allocate the user groups.\n",
|
|
curuserlist->name);
|
|
free(groups);
|
|
return ERR_ALERT | ERR_FATAL;
|
|
}
|
|
|
|
grl->group = ag;
|
|
grl->next = groups;
|
|
groups = grl;
|
|
}
|
|
|
|
free(curuser->u.groups);
|
|
curuser->u.groups = groups;
|
|
}
|
|
|
|
for (ag = curuserlist->groups; ag; ag = ag->next) {
|
|
char *user = NULL;
|
|
|
|
if (!ag->groupusers)
|
|
continue;
|
|
|
|
while ((user = strtok(user?NULL:ag->groupusers, ","))) {
|
|
for (curuser = curuserlist->users; curuser; curuser = curuser->next) {
|
|
if (strcmp(curuser->user, user) == 0)
|
|
break;
|
|
}
|
|
|
|
if (!curuser) {
|
|
ha_alert("userlist '%s': no such user '%s' specified in group '%s'\n",
|
|
curuserlist->name, user, ag->name);
|
|
return ERR_ALERT | ERR_FATAL;
|
|
}
|
|
|
|
/* Add this group at the group userlist. */
|
|
grl = calloc(1, sizeof(*grl));
|
|
if (!grl) {
|
|
ha_alert("userlist '%s': no more memory when trying to allocate the user groups.\n",
|
|
curuserlist->name);
|
|
return ERR_ALERT | ERR_FATAL;
|
|
}
|
|
|
|
grl->group = ag;
|
|
grl->next = curuser->u.groups;
|
|
curuser->u.groups = grl;
|
|
}
|
|
|
|
free(ag->groupusers);
|
|
ag->groupusers = NULL;
|
|
}
|
|
|
|
#ifdef DEBUG_AUTH
|
|
for (ag = curuserlist->groups; ag; ag = ag->next) {
|
|
struct auth_groups_list *agl;
|
|
|
|
fprintf(stderr, "group %s, id %p, users:", ag->name, ag);
|
|
for (curuser = curuserlist->users; curuser; curuser = curuser->next) {
|
|
for (agl = curuser->u.groups; agl; agl = agl->next) {
|
|
if (agl->group == ag)
|
|
fprintf(stderr, " %s", curuser->user);
|
|
}
|
|
}
|
|
fprintf(stderr, "\n");
|
|
}
|
|
#endif
|
|
}
|
|
|
|
return ERR_NONE;
|
|
}
|
|
|
|
/*
|
|
* Authenticate and authorize user; return 1 if OK, 0 if case of error.
|
|
*/
|
|
int
|
|
check_user(struct userlist *ul, const char *user, const char *pass)
|
|
{
|
|
|
|
struct auth_users *u;
|
|
#ifdef DEBUG_AUTH
|
|
struct auth_groups_list *agl;
|
|
#endif
|
|
const char *ep;
|
|
|
|
#ifdef DEBUG_AUTH
|
|
fprintf(stderr, "req: userlist=%s, user=%s, pass=%s\n",
|
|
ul->name, user, pass);
|
|
#endif
|
|
|
|
for (u = ul->users; u; u = u->next)
|
|
if (strcmp(user, u->user) == 0)
|
|
break;
|
|
|
|
if (!u)
|
|
return 0;
|
|
|
|
#ifdef DEBUG_AUTH
|
|
fprintf(stderr, "cfg: user=%s, pass=%s, flags=%X, groups=",
|
|
u->user, u->pass, u->flags);
|
|
for (agl = u->u.groups; agl; agl = agl->next)
|
|
fprintf(stderr, " %s", agl->group->name);
|
|
#endif
|
|
|
|
if (!(u->flags & AU_O_INSECURE)) {
|
|
#ifdef USE_LIBCRYPT
|
|
#ifdef HA_HAVE_CRYPT_R
|
|
ep = crypt_r(pass, u->pass, &crypt_data);
|
|
#else
|
|
HA_SPIN_LOCK(AUTH_LOCK, &auth_lock);
|
|
ep = crypt(pass, u->pass);
|
|
HA_SPIN_UNLOCK(AUTH_LOCK, &auth_lock);
|
|
#endif
|
|
#else
|
|
return 0;
|
|
#endif
|
|
} else
|
|
ep = pass;
|
|
|
|
#ifdef DEBUG_AUTH
|
|
fprintf(stderr, ", crypt=%s\n", ep);
|
|
#endif
|
|
|
|
if (ep && strcmp(ep, u->pass) == 0)
|
|
return 1;
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
struct pattern *
|
|
pat_match_auth(struct sample *smp, struct pattern_expr *expr, int fill)
|
|
{
|
|
struct userlist *ul = smp->ctx.a[0];
|
|
struct pattern_list *lst;
|
|
struct auth_users *u;
|
|
struct auth_groups_list *agl;
|
|
struct pattern *pattern;
|
|
|
|
/* Check if the userlist is present in the context data. */
|
|
if (!ul)
|
|
return NULL;
|
|
|
|
/* Browse the userlist for searching user. */
|
|
for (u = ul->users; u; u = u->next) {
|
|
if (strcmp(smp->data.u.str.area, u->user) == 0)
|
|
break;
|
|
}
|
|
if (!u)
|
|
return NULL;
|
|
|
|
/* Browse each pattern. */
|
|
list_for_each_entry(lst, &expr->patterns, list) {
|
|
pattern = &lst->pat;
|
|
|
|
/* Browse each group for searching group name that match the pattern. */
|
|
for (agl = u->u.groups; agl; agl = agl->next) {
|
|
if (strcmp(agl->group->name, pattern->ptr.str) == 0)
|
|
return pattern;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
REGISTER_BUILD_OPTS("Encrypted password support via crypt(3): "CRYPT_STATE_MSG);
|