summaryrefslogtreecommitdiff
path: root/apache2x/mod_httpauth.c
diff options
context:
space:
mode:
authorStef Walter <stef@memberwebs.com>2008-06-11 21:48:27 +0000
committerStef Walter <stef@memberwebs.com>2008-06-11 21:48:27 +0000
commit0cb3f6098d959479a96c26a92d91becc2110b30d (patch)
tree22f1447d6c7ad77d802c476297cf9547f822f81a /apache2x/mod_httpauth.c
parent67d7a6cc4d3234ac93e521632701e8d42513e042 (diff)
Support getting groups from the server and limiting access based on LDAP groups. See #112
Diffstat (limited to 'apache2x/mod_httpauth.c')
-rw-r--r--apache2x/mod_httpauth.c323
1 files changed, 233 insertions, 90 deletions
diff --git a/apache2x/mod_httpauth.c b/apache2x/mod_httpauth.c
index 3e11750..d6697ae 100644
--- a/apache2x/mod_httpauth.c
+++ b/apache2x/mod_httpauth.c
@@ -67,10 +67,17 @@ typedef struct httpauth_context
int types;
const char* handler;
const char* domain;
+ char* needed_groups;
+ int alloced_groups;
apr_pool_t* child_pool;
}
httpauth_context_t;
+typedef struct httpauth_request {
+ const char *user;
+ const char *groups;
+} httpauth_request_t;
+
/* TODO: Support proxy authentication properly */
#define AUTH_PREFIX_BASIC "Basic"
@@ -98,6 +105,8 @@ static void* httpauth_dir_config(apr_pool_t* p, char* dir)
ctx->socket = -1;
ctx->types = 0xFFFFFFFF;
ctx->child_pool = p;
+ ctx->needed_groups = NULL;
+ ctx->alloced_groups = 0;
return ctx;
}
@@ -184,6 +193,8 @@ void disconnect_socket(httpauth_context_t* ctx, server_rec* s)
cleanup_socket);
close(ctx->socket);
ctx->socket = -1;
+ if (ctx->needed_groups)
+ ctx->needed_groups[0] = 0;
}
}
@@ -223,7 +234,7 @@ void read_junk(httpauth_context_t* ctx, request_rec* r)
int read_line(httpauth_context_t* ctx, request_rec* r, char** line)
{
int l;
- int al = 128;
+ int al = 256;
char* t;
const char* e;
@@ -300,7 +311,8 @@ int read_line(httpauth_context_t* ctx, request_rec* r, char** line)
}
int read_response(httpauth_context_t* ctx, request_rec* r,
- int* code, int* ccode, char** details)
+ int* code, int* ccode, char** details,
+ int return_errors)
{
int c;
char* line;
@@ -328,7 +340,7 @@ int read_response(httpauth_context_t* ctx, request_rec* r,
if(code)
*code = c;
- if(c >= 400)
+ if(c >= 400 && !return_errors)
{
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
"httpauth: received error from httpauthd: %d %s", c, line);
@@ -357,7 +369,9 @@ int read_response(httpauth_context_t* ctx, request_rec* r,
return 0;
}
-int read_copy_headers(httpauth_context_t* ctx, int ccode, request_rec* r)
+static int
+read_process_headers(httpauth_context_t* ctx, int ccode,
+ request_rec* r, char **groups)
{
char* line;
const char* name;
@@ -445,6 +459,12 @@ int read_copy_headers(httpauth_context_t* ctx, int ccode, request_rec* r)
name = "Proxy-Authentication-Info";
}
+ else if (strcasecmp(name, "X-HttpAuth-Groups") == 0)
+ {
+ if (groups && line)
+ *groups = line;
+ }
+
c++;
apr_table_addn(headers, name, line);
}
@@ -545,7 +565,7 @@ int connect_httpauth(httpauth_context_t* ctx, request_rec* r)
if(connect_socket(ctx, r) == -1)
goto finally;
- if(read_response(ctx, r, &code, NULL, &details) == -1)
+ if(read_response(ctx, r, &code, NULL, &details, 0) == -1)
goto finally;
if(code != 100)
@@ -576,13 +596,13 @@ int connect_httpauth(httpauth_context_t* ctx, request_rec* r)
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
"httpauth: sent handler to daemon: %s", t);
- if(read_response(ctx, r, &code, NULL, NULL) == -1)
+ if(read_response(ctx, r, &code, NULL, NULL, 0) == -1)
goto finally;
if(code != 202)
{
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
- "httpauth: protocol error (Expected 202, got %d)", code);
+ "httpauth: protocol error: couldn't send handler to daemon (Expected 202, got %d)", code);
goto finally;
}
}
@@ -598,13 +618,13 @@ int connect_httpauth(httpauth_context_t* ctx, request_rec* r)
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
"httpauth: sent domains to daemon: %s", t);
- if(read_response(ctx, r, &code, NULL, NULL) == -1)
+ if(read_response(ctx, r, &code, NULL, NULL, 0) == -1)
goto finally;
if(code != 202)
{
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
- "httpauth: protocol error (Expected 202, got %d)", code);
+ "httpauth: protocol error: couldn't send domain to daemon (Expected 202, got %d)", code);
goto finally;
}
}
@@ -711,12 +731,88 @@ int write_request(httpauth_context_t* ctx, request_rec* r)
return write_data(ctx, r->server, "\n");
}
+static int
+write_needed_groups(httpauth_context_t *ctx, request_rec *r)
+{
+ const apr_array_header_t *reqs_arr = ap_requires(r);
+ require_line *reqs;
+ const char *groups = NULL;
+ const char *text;
+ char *word;
+ register int x;
+ int m = r->method_number;
+ int code, len;
+
+ if(reqs_arr) {
+ reqs = (require_line*)reqs_arr->elts;
+ for (x = 0; x < reqs_arr->nelts; x++) {
+ if (!(reqs[x].method_mask & (AP_METHOD_BIT << m)))
+ continue;
+
+ text = reqs[x].requirement;
+ word = ap_getword_white (r->pool, &text);
+
+ /* Append all groups to the string */
+ if (strcmp (word, "group") == 0 && text && text[0]) {
+ if (!groups)
+ groups = text;
+ else
+ groups = apr_pstrcat (r->pool, text, " ", groups, NULL);
+ }
+ }
+ }
+
+ /* No groups, no need to send */
+ if (!groups && !ctx->needed_groups)
+ return 0;
+
+ if (!groups)
+ groups = "";
+
+ /* Equal groups, no need to send */
+ if (ctx->needed_groups && strcmp (groups, ctx->needed_groups) == 0)
+ return 0;
+
+ /* Groups changed, send to daemon */
+ text = apr_pstrcat (r->pool, "SET Groups ", groups, "\n", NULL);
+
+ if (write_data (ctx, r->server, text) < 0)
+ return -1;
+
+ ap_log_rerror (APLOG_MARK, APLOG_DEBUG, 0, r,
+ "httpauth: sent groups to daemon: %s", text);
+
+ if (read_response (ctx, r, &code, NULL, NULL, 1) < 0)
+ return -1;
+
+ if (code != 202) {
+ ap_log_rerror (APLOG_MARK, APLOG_ERR, 0, r,
+ "httpauth: couldn't send groups to daemon (Expected 202, got %d)", code);
+ /* Older versions of the daemon did not support the 'SET Groups' command */
+ if (code != 400)
+ return -1;
+ }
+
+ /* Save away the groups for next time */
+ len = strlen (groups);
+ if (len >= ctx->alloced_groups) {
+ if (len < 512)
+ len = 512;
+ ctx->needed_groups = (char*)apr_pcalloc (ctx->child_pool, len * 2);
+ ctx->alloced_groups = len * 2;
+ }
+ strcpy (ctx->needed_groups, groups);
+ return 0;
+}
+
static int httpauth_authenticate(request_rec* r)
{
httpauth_context_t* ctx;
+ httpauth_request_t* hreq;
const char* authtype;
int code = 0;
int ccode = 0;
+ char *groups = NULL;
char* details = NULL;
request_rec* mainreq;
int retried = 0;
@@ -739,14 +835,13 @@ static int httpauth_authenticate(request_rec* r)
while(mainreq->prev != NULL)
mainreq = mainreq->prev;
- /* Check if we've already authenticated this request */
- details = ap_get_module_config(mainreq->request_config, &httpauth_module);
- if(details)
- {
- r->user = apr_pstrdup(r->pool, details);
- r->ap_auth_type = HTTPAUTH_AUTHTYPE;
- return OK;
- }
+ /* Check if we've already authenticated this request */
+ hreq = ap_get_module_config (mainreq->request_config, &httpauth_module);
+ if (hreq) {
+ r->user = apr_pstrdup (r->pool, hreq->user);
+ r->ap_auth_type = HTTPAUTH_AUTHTYPE;
+ return OK;
+ }
/* For jumping to when a connection has been closed */
retry:
@@ -760,9 +855,10 @@ retry:
/* Make sure we're starting on a clean slate */
read_junk(ctx, r);
- /* Send off a request */
- if(write_request(ctx, r) == -1 ||
- read_response(ctx, r, &code, &ccode, &details) == -1)
+ /* Send off a request, along with groups, and read response */
+ if(write_needed_groups(ctx, r) == -1 ||
+ write_request(ctx, r) == -1 ||
+ read_response(ctx, r, &code, &ccode, &details, 0) == -1)
{
/*
* If our connection was closed by httpauthd then this
@@ -788,89 +884,136 @@ retry:
if(code != 200)
{
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
- "httpauth: protocol error: unexpected code: %d", code);
+ "httpauth: protocol error: unexpected code while authenticating: %d", code);
return HTTP_INTERNAL_SERVER_ERROR;
}
/* Copy over other headers */
- if(read_copy_headers(ctx, ccode, r) == -1)
+ if(read_process_headers(ctx, ccode, r, &groups) == -1)
return HTTP_INTERNAL_SERVER_ERROR;
- if(ccode == 200)
- {
- ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
- "httpauth: successful authentication for user: %s", details);
+ if (ccode == 200) {
+ ap_log_rerror (APLOG_MARK, APLOG_INFO, 0, r,
+ "httpauth: successful authentication for user: %s", details);
- r->user = apr_pstrdup(r->pool, details);
- r->ap_auth_type = HTTPAUTH_AUTHTYPE;
+ r->user = apr_pstrdup (r->pool, details);
+ r->ap_auth_type = HTTPAUTH_AUTHTYPE;
- /* Mark request as successfully authenticated */
- ap_set_module_config(r->request_config, &httpauth_module, details);
- return OK;
- }
+ hreq = (httpauth_request_t*)apr_pcalloc (r->pool, sizeof (*hreq));
+ hreq->user = details;
+ hreq->groups = groups;
- return ccode;
+ /* Mark request as successfully authenticated */
+ ap_set_module_config (r->request_config, &httpauth_module, hreq);
+ return OK;
+ }
+
+ return ccode;
}
-static int httpauth_access(request_rec *r)
+static const char*
+find_word_quoted (const char *all, const char *word)
{
- httpauth_context_t* ctx;
- const char* authtype;
- char *user = r->user;
- int m = r->method_number;
- int method_restricted = 0;
- register int x;
- const char *t, *w;
- const apr_array_header_t *reqs_arr = ap_requires(r);
- require_line *reqs;
-
- /* Make sure it's for us */
- if(!(authtype = ap_auth_type(r)) || strcasecmp(HTTPAUTH_AUTHTYPE, authtype) != 0)
- return DECLINED;
-
- ctx = (httpauth_context_t*)ap_get_module_config(r->per_dir_config,
- &httpauth_module);
-
- if (!reqs_arr)
- return OK;
- reqs = (require_line *)reqs_arr->elts;
-
- for (x = 0; x < reqs_arr->nelts; x++)
- {
- if (!(reqs[x].method_mask & (AP_METHOD_BIT << m)))
- continue;
-
- method_restricted = 1;
-
- t = reqs[x].requirement;
- w = ap_getword_white(r->pool, &t);
- if(!strcmp(w, "valid-user"))
- return OK;
- else if(!strcmp(w, "user"))
- {
- while (t[0])
- {
- w = ap_getword_conf(r->pool, &t);
- if (!strcmp(user, w)) {
- return OK;
- }
- }
- }
- else
- {
- ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
- "access to %s failed, reason: unknown require "
- "directive:\"%s\"", r->uri, reqs[x].requirement);
- }
- }
-
- if (!method_restricted)
- return OK;
+ const char *at;
+ char before, after;
+ size_t len = strlen (word);
+
+ at = all;
+ for (;;) {
+ at = strstr (at, word);
+ if (!at)
+ return NULL;
+
+ before = (at == all) ? 0 : *(at - 1);
+ after = *(at + len);
+
+ /* Beginning and end of a space delimited word */
+ if ((!before || isspace (before)) &&
+ (!after || isspace (after))) {
+ return at;
+ }
+
+ /* Beginning and end of a quoted word */
+ if ((before == '"' || before == '\'') && after == before)
+ return at;
+
+ at += len;
+ }
+}
- ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
- "access to %s failed, reason: user %s not allowed access",
- r->uri, user);
- return HTTP_UNAUTHORIZED;
+static int
+httpauth_access(request_rec *r)
+{
+ httpauth_context_t *ctx;
+ httpauth_request_t *hreq;
+ const char* authtype;
+ char *user = r->user;
+ int m = r->method_number;
+ int method_restricted = 0;
+ register int x;
+ const char *text, *word, *at;
+ const apr_array_header_t *reqs_arr = ap_requires (r);
+ require_line *reqs;
+
+ /* Make sure it's for us */
+ if (!(authtype = ap_auth_type (r)) || strcasecmp (HTTPAUTH_AUTHTYPE, authtype) != 0)
+ return DECLINED;
+
+ if (!reqs_arr)
+ return OK;
+
+ /* Dig out our configuration */
+ ctx = ap_get_module_config (r->per_dir_config, &httpauth_module);
+ hreq = ap_get_module_config (r->request_config, &httpauth_module);
+ reqs = (require_line *)reqs_arr->elts;
+
+ for (x = 0; x < reqs_arr->nelts; x++) {
+ if (!(reqs[x].method_mask & (AP_METHOD_BIT << m)))
+ continue;
+
+ method_restricted = 1;
+
+ text = reqs[x].requirement;
+ word = ap_getword_white(r->pool, &text);
+
+ /* Any valid user */
+ if (strcmp (word, "valid-user") == 0) {
+ return OK;
+
+ /* Specific listed users */
+ } else if (strcmp (word, "user") == 0) {
+ while (text[0]) {
+ word = ap_getword_conf (r->pool, &text);
+ if (strcmp (user, word) == 0) {
+ return OK;
+ }
+ }
+
+ /* Specific groups */
+ } else if (strcmp (word, "group") == 0) {
+ if (hreq && hreq->groups) {
+ while (text[0]) {
+ word = ap_getword_conf (r->pool, &text);
+ if (find_word_quoted (hreq->groups, word))
+ return OK;
+ }
+ }
+
+ /* What is this? */
+ } else {
+ ap_log_rerror (APLOG_MARK, APLOG_ERR, 0, r,
+ "access to %s failed, reason: unknown require "
+ "directive:\"%s\"", r->uri, reqs[x].requirement);
+ }
+ }
+
+ if (!method_restricted)
+ return OK;
+
+ ap_log_rerror (APLOG_MARK, APLOG_ERR, 0, r,
+ "access to %s failed, reason: user %s not allowed access",
+ r->uri, user);
+ return HTTP_UNAUTHORIZED;
}
static void register_hooks(apr_pool_t *p)