#include "httpd.h"
#include "http_config.h"
#include "http_core.h"
#include "http_log.h"
#include "http_protocol.h"
typedef
struct
auth_config_struct {
char
*auth_pwfile;
char
*auth_grpfile;
int
auth_authoritative;
} auth_config_rec;
static
void
*create_auth_dir_config(pool *p,
char
*d)
{
auth_config_rec *sec =
(auth_config_rec *) ap_pcalloc(p,
sizeof
(auth_config_rec));
sec->auth_pwfile = NULL;
sec->auth_grpfile = NULL;
sec->auth_authoritative = 1;
return
sec;
}
static
const
char
*set_auth_slot(cmd_parms *cmd,
void
*offset,
char
*f,
char
*t)
{
if
(t &&
strcmp
(t,
"standard"
))
return
ap_pstrcat(cmd->pool,
"Invalid auth file type: "
, t, NULL);
return
ap_set_file_slot(cmd, offset, f);
}
static
const
command_rec auth_cmds[] =
{
{
"AuthUserFile"
, set_auth_slot,
(
void
*) XtOffsetOf(auth_config_rec, auth_pwfile), OR_AUTHCFG, TAKE12,
"text file containing user IDs and passwords"
},
{
"AuthGroupFile"
, set_auth_slot,
(
void
*) XtOffsetOf(auth_config_rec, auth_grpfile), OR_AUTHCFG, TAKE12,
"text file containing group names and member user IDs"
},
{
"AuthAuthoritative"
, ap_set_flag_slot,
(
void
*) XtOffsetOf(auth_config_rec, auth_authoritative),
OR_AUTHCFG, FLAG,
"Set to 'off' to allow access control to be passed along to "
"lower modules if the UserID is not known to this module"
},
{NULL}
};
module MODULE_VAR_EXPORT auth_module;
static
char
*get_pw(request_rec *r,
char
*user,
char
*auth_pwfile)
{
configfile_t *f;
char
l[MAX_STRING_LEN];
const
char
*rpw, *w;
if
(!(f = ap_pcfg_openfile(r->pool, auth_pwfile))) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, r,
"Could not open password file: %s"
, auth_pwfile);
return
NULL;
}
while
(!(ap_cfg_getline(l, MAX_STRING_LEN, f))) {
if
((l[0] ==
'#'
) || (!l[0]))
continue
;
rpw = l;
w = ap_getword(r->pool, &rpw,
':'
);
if
(!
strcmp
(user, w)) {
ap_cfg_closefile(f);
return
ap_getword(r->pool, &rpw,
':'
);
}
}
ap_cfg_closefile(f);
return
NULL;
}
static
table *groups_for_user(pool *p,
char
*user,
char
*grpfile)
{
configfile_t *f;
table *grps = ap_make_table(p, 15);
pool *sp;
char
l[MAX_STRING_LEN];
const
char
*group_name, *ll, *w;
if
(!(f = ap_pcfg_openfile(p, grpfile))) {
return
NULL;
}
sp = ap_make_sub_pool(p);
while
(!(ap_cfg_getline(l, MAX_STRING_LEN, f))) {
if
((l[0] ==
'#'
) || (!l[0]))
continue
;
ll = l;
ap_clear_pool(sp);
group_name = ap_getword(sp, &ll,
':'
);
while
(ll[0]) {
w = ap_getword_conf(sp, &ll);
if
(!
strcmp
(w, user)) {
ap_table_setn(grps, ap_pstrdup(p, group_name),
"in"
);
break
;
}
}
}
ap_cfg_closefile(f);
ap_destroy_pool(sp);
return
grps;
}
static
int
authenticate_basic_user(request_rec *r)
{
auth_config_rec *sec =
(auth_config_rec *) ap_get_module_config(r->per_dir_config, &auth_module);
conn_rec *c = r->connection;
const
char
*sent_pw;
char
*real_pw;
char
*invalid_pw;
int
res;
if
((res = ap_get_basic_auth_pw(r, &sent_pw)))
return
res;
if
(!sec->auth_pwfile)
return
DECLINED;
if
(!(real_pw = get_pw(r, c->user, sec->auth_pwfile))) {
if
(!(sec->auth_authoritative))
return
DECLINED;
ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r,
"user %s not found: %s"
, c->user, r->uri);
ap_note_basic_auth_failure(r);
return
AUTH_REQUIRED;
}
invalid_pw = ap_validate_password(sent_pw, real_pw);
if
(invalid_pw != NULL) {
ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r,
"user %s: authentication failure for \"%s\": %s"
,
c->user, r->uri, invalid_pw);
ap_note_basic_auth_failure(r);
return
AUTH_REQUIRED;
}
return
OK;
}
static
int
check_user_access(request_rec *r)
{
auth_config_rec *sec =
(auth_config_rec *) ap_get_module_config(r->per_dir_config, &auth_module);
char
*user = r->connection->user;
int
m = r->method_number;
int
method_restricted = 0;
register
int
x;
const
char
*t, *w;
table *grpstatus;
const
array_header *reqs_arr = ap_requires(r);
require_line *reqs;
if
(reqs_arr == NULL) {
return
(OK);
}
reqs = (require_line *) reqs_arr->elts;
if
(sec->auth_grpfile) {
grpstatus = groups_for_user(r->pool, user, sec->auth_grpfile);
}
else
{
grpstatus = NULL;
}
for
(x = 0; x < reqs_arr->nelts; x++) {
if
(! (reqs[x].method_mask & (1 << m))) {
continue
;
}
method_restricted = 1;
t = reqs[x].requirement;
w = ap_getword_white(r->pool, &t);
if
(
strcmp
(w,
"valid-user"
) == 0) {
return
OK;
}
if
(
strcmp
(w,
"file-owner"
) == 0) {
#if defined(WIN32) || defined(NETWARE) || defined(OS2)
ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO, r,
"'Require file-user' not supported "
"on this platform, ignored"
);
continue
;
#else
struct
passwd *pwent;
ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_DEBUG, r,
"checking for 'owner' access for file '%s'"
,
r->filename);
if
(r->finfo.st_ino == 0) {
ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_DEBUG, r,
"no stat info for '%s'"
, r->filename);
continue
;
}
pwent = getpwuid(r->finfo.st_uid);
if
(pwent == NULL) {
ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_DEBUG, r,
"no username for UID %d (owner of '%s')"
,
r->finfo.st_uid, r->filename);
}
else
{
ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_DEBUG, r,
"checking authenticated user '%s' "
"against owner '%s' of '%s'"
,
user, pwent->pw_name, r->filename);
if
(
strcmp
(user, pwent->pw_name) == 0) {
return
OK;
}
else
{
continue
;
}
}
#endif
}
if
(
strcmp
(w,
"file-group"
) == 0) {
#if defined(WIN32) || defined(NETWARE) || defined(OS2)
ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO, r,
"'Require file-group' not supported "
"on this platform, ignored"
);
continue
;
#else
struct
group *grent;
if
(sec->auth_grpfile == NULL) {
ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO, r,
"no AuthGroupFile, so 'file-group' "
"requirement cannot succeed for file '%s'"
,
r->filename);
continue
;
}
if
(grpstatus == NULL) {
ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING, r,
"authenticated user '%s' not a member of "
"any groups, so 'file-group' requirement "
"cannot succeed for file '%s'"
,
user, r->filename);
continue
;
}
ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_DEBUG, r,
"checking for 'group' access for file '%s'"
,
r->filename);
if
(r->finfo.st_ino == 0) {
ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_DEBUG, r,
"no stat info for '%s'"
, r->filename);
continue
;
}
grent = getgrgid(r->finfo.st_gid);
if
(grent == NULL) {
ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_DEBUG, r,
"no group name for GID %d (owner of '%s')"
,
r->finfo.st_gid, r->filename);
}
else
{
ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_DEBUG, r,
"checking groups of authenticated user '%s' "
"against owner group '%s' of '%s'"
,
user, grent->gr_name, r->filename);
if
(ap_table_get(grpstatus, grent->gr_name) != NULL) {
return
OK;
}
else
{
continue
;
}
}
#endif
}
if
(
strcmp
(w,
"user"
) == 0) {
while
(t[0] !=
'\0'
) {
w = ap_getword_conf(r->pool, &t);
if
(
strcmp
(user, w) == 0) {
return
OK;
}
}
}
else
if
(
strcmp
(w,
"group"
) == 0) {
if
(grpstatus == NULL) {
return
DECLINED;
}
while
(t[0]) {
w = ap_getword_conf(r->pool, &t);
if
(ap_table_get(grpstatus, w)) {
return
OK;
}
}
}
else
if
(sec->auth_authoritative) {
ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r,
"access to %s failed, "
"reason: unknown require directive:"
"\"%s\""
, r->uri, reqs[x].requirement);
}
}
if
(! method_restricted) {
return
OK;
}
if
(! sec->auth_authoritative) {
return
DECLINED;
}
ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r,
"access to %s failed, reason: user %s not allowed access"
,
r->uri, user);
ap_note_basic_auth_failure(r);
return
AUTH_REQUIRED;
}
module MODULE_VAR_EXPORT auth_module =
{
STANDARD_MODULE_STUFF,
NULL,
create_auth_dir_config,
NULL,
NULL,
NULL,
auth_cmds,
NULL,
NULL,
authenticate_basic_user,
check_user_access,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL
};