From 4bf87cb9f4f6b9812c06a8d2c500869c48ebc2dc Mon Sep 17 00:00:00 2001 From: Stef Walter Date: Thu, 18 Jun 2009 17:12:22 +0000 Subject: Complete almost all code, compiles. --- module/mod_auth_singleid.c | 1333 +++++++------------------------------------- 1 file changed, 202 insertions(+), 1131 deletions(-) (limited to 'module/mod_auth_singleid.c') diff --git a/module/mod_auth_singleid.c b/module/mod_auth_singleid.c index 6085fec..3b6304a 100644 --- a/module/mod_auth_singleid.c +++ b/module/mod_auth_singleid.c @@ -36,10 +36,6 @@ * */ - -#include "consumer.h" -#include "storage.h" - #include #include @@ -49,6 +45,7 @@ #include #include #include +#include #include #include @@ -57,8 +54,6 @@ #include #include -#include - /* Apache defines these */ #undef PACKAGE_BUGREPORT #undef PACKAGE_NAME @@ -67,6 +62,9 @@ #undef PACKAGE_VERSION #include "config.h" +#include "mod_auth_singleid.h" + +#include #include extern module AP_MODULE_DECLARE_DATA auth_singleid_module; @@ -74,23 +72,24 @@ extern module AP_MODULE_DECLARE_DATA auth_singleid_module; /* * Per directory configuration. */ -typedef struct singleid_context { +typedef struct sid_context { const char *trust_root; - const char *identity; - void *shared_block; -} singleid_context_t; + const char *identifier; + sid_storage_t *store; +} sid_context_t; -#define SINGLEID_AUTHTYPE "SINGLEID" +#define SID_AUTHTYPE "SingleID" /* ------------------------------------------------------------------------------- - * SHARED MEMORY + * SHARED MEMORY and LOCKING */ static apr_global_mutex_t *shared_lock = NULL; static const char *shared_lock_name = NULL; +static size_t shared_size = 64 * 1024; static int -shared_initialize (apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s) +shared_initialize (apr_pool_t *p, server_rec *s) { apr_file_t *file = NULL; const char *tmpdir; @@ -167,6 +166,9 @@ shared_create (apr_pool_t* p, size_t size) void *addr; int rc; + if (!shared_lock) + return NULL; + /* Get the temp directory */ rc = apr_temp_dir_get (&tmpdir, p); if (rc != APR_SUCCESS) { @@ -216,939 +218,100 @@ shared_create (apr_pool_t* p, size_t size) return NULL; } -/* ------------------------------------------------------------------------------------------------- - * COMMON STORAGE - */ - -typedef struct storage_context { - void* shared; - size_t size; -} storage_context_t; - -/* ------------------------------------------------------------------------------------------------- - * OPENID CONSUMER - */ - -#if 0 -static void* storage_shared = NULL; -static size_t storage_size = NULL; -#endif - -#if 0 - -static int -shared_get_if_changed (httpauth_context_t *ctx, int version, httpauth_shared_t *shared) +void +sid_shared_lock (void) { - httpauth_shared_t *block; - int ret = 0; - - if (!ctx->shared_block || !shared_lock) - return 0; - apr_global_mutex_lock (shared_lock); - - block = ctx->shared_block; - if (block->version != version) { - ret = 1; - if (shared) - memcpy (shared, block, sizeof (*shared)); - } - - apr_global_mutex_unlock (shared_lock); - - return ret; } -static void -shared_set_if_changed (httpauth_context_t *ctx, httpauth_shared_t *shared) +void +sid_shared_unlock (void) { - httpauth_shared_t *block; - - if (!ctx->shared_block || !shared_lock) - return; - - apr_global_mutex_lock (shared_lock); - - block = ctx->shared_block; - if (memcmp (shared, block, sizeof (*shared)) != 0) { - - /* Increment the version beyond all */ - if (block->version > shared->version) - shared->version = block->version; - ++shared->version; - - /* And write it out */ - memcpy (block, shared, sizeof (*shared)); - } - apr_global_mutex_unlock (shared_lock); } -#endif /* ------------------------------------------------------------------------------- - * Per Directory Config and Context Code + * CONFIGURATION */ static void* dir_config_creator (apr_pool_t* p, char* dir) { -#if 0 - httpauth_context_t* ctx; - httpauth_shared_t shared; - const char *tmpdir; - char *filename; - apr_file_t *file; - apr_mmap_t *map; - void *addr; - int rc; + sid_context_t* ctx; + void *shared; - ctx = (httpauth_context_t*)apr_pcalloc(p, sizeof(*ctx)); + ctx = (sid_context_t*)apr_pcalloc(p, sizeof(*ctx)); memset(ctx, 0, sizeof(*ctx)); - ctx->socket = -1; - ctx->types = 0xFFFFFFFF; - ctx->child_pool = p; - ctx->needed_groups = NULL; - ctx->alloced_groups = 0; - ctx->shared_version = 0; - ctx->retries = 1; + ctx->identifier = NULL; + ctx->store = NULL; + ctx->trust_root = NULL; if (!dir) return ctx; - /* Get the temp directory */ - rc = apr_temp_dir_get (&tmpdir, p); - if (rc != APR_SUCCESS) - ap_log_error (APLOG_MARK, APLOG_ERR, rc, NULL, - "httpauth: couldn't get temporary directory"); - - /* Create the shared file */ - if (rc == APR_SUCCESS) { - filename = apr_pstrcat (p, tmpdir, "/", "mod-httpauth.board.XXXXXX", NULL); - rc = apr_file_mktemp (&file, filename, 0, p); - if (rc != APR_SUCCESS) - ap_log_error (APLOG_MARK, APLOG_ERR, rc, NULL, - "httpauth: couldn't create temporary file: %s", filename); - } - - /* Write a shared block to file */ - if (rc == APR_SUCCESS) { - memset (&shared, 0, sizeof (shared)); - rc = apr_file_write_full (file, &shared, sizeof (shared), NULL); - if (rc != APR_SUCCESS) - ap_log_error (APLOG_MARK, APLOG_ERR, rc, NULL, - "httpauth: couldn't write to temporary file: %s", filename); - } - - /* Map the shared file into memory */ - if (rc == APR_SUCCESS) { - rc = apr_mmap_create (&map, file, 0, sizeof (shared), - APR_MMAP_READ | APR_MMAP_WRITE, p); - if (rc != APR_SUCCESS) - ap_log_error (APLOG_MARK, APLOG_ERR, rc, NULL, - "httpauth: couldn't map temporary file: %s", filename); - } - - /* Get the actual address of the mapping */ - if (rc == APR_SUCCESS) { - rc = apr_mmap_offset (&addr, map, 0); - if (rc != APR_SUCCESS) - ap_log_error (APLOG_MARK, APLOG_ERR, rc, NULL, - "httpauth: couldn't get shared memory"); - } - - if (rc == APR_SUCCESS) - ctx->shared_block = addr; + shared = shared_create (p, shared_size); + ctx->store = sid_storage_initialize (shared, shared_size); return ctx; -#endif - return NULL; } -#if 0 -static const char* set_socket(cmd_parms* cmd, void* config, const char* val) +static const char* +set_identifier (cmd_parms* cmd, void* config, const char* val) { - struct sockaddr_any sany; - - if (sock_any_pton_n (val, &sany, 1, DEFAULT_PORT | SANY_OPT_NORESOLV) == -1) - return "Invalid socket name or ip in HttpAuthSocket"; - - ((httpauth_context_t*)config)->socketname = val; + sid_context_t *ctx = config; + ctx->identifier = apr_pstrdup (cmd->pool, val); return NULL; } -static const char* set_handler(cmd_parms* cmd, void* config, const char* val) -{ - httpauth_context_t* conf = (httpauth_context_t*)config; - conf->handler = val; - return NULL; -} - -static const char* set_types(cmd_parms* cmd, void* config, const char* val) -{ - httpauth_context_t* conf = (httpauth_context_t*)config; - int type = 0; - - if(strcasecmp(val, AUTH_PREFIX_BASIC) == 0) - type = AUTH_TYPE_BASIC; - else if(strcasecmp(val, AUTH_PREFIX_DIGEST) == 0) - type = AUTH_TYPE_DIGEST; - else if(strcasecmp(val, AUTH_PREFIX_NTLM) == 0) - type = AUTH_TYPE_NTLM; - else if(strcasecmp(val, "any")) - type = AUTH_TYPE_ANY; - else - return "Invalid type in HttpAuthTypes"; - - if(conf->types == 0xFFFFFFFF) - conf->types = type; - else - conf->types |= type; - - return NULL; -} - -static const char* set_domain(cmd_parms* cmd, void* config, const char* val) +static const char* +set_trust_root (cmd_parms* cmd, void* config, const char* val) { - httpauth_context_t* conf = (httpauth_context_t*)config; - conf->domain = trim_space(apr_pstrdup(cmd->pool, val)); - return NULL; + sid_context_t *ctx = config; + if (!ap_is_url (val)) + return "Not a valid URL in SingleTrustRoot"; + ctx->trust_root = apr_pstrdup (cmd->pool, val); + return NULL; } -#endif -static const command_rec command_table[] = -{ -#if 0 - AP_INIT_RAW_ARGS( "HttpAuthSocket", set_socket, NULL, OR_AUTHCFG, - "The socket that httpauthd is listening on" ), - AP_INIT_TAKE1( "HttpAuthHandler", set_handler, NULL, OR_AUTHCFG, - "The handler that httpauthd should use to authenticate" ), - AP_INIT_ITERATE( "HttpAuthTypes", set_types, NULL, OR_AUTHCFG, - "The types of authentiction allowed (Basic, Digest, NTLM ...)" ), - AP_INIT_RAW_ARGS( "HttpAuthDigestDomain", set_domain, NULL, OR_AUTHCFG, - "The domain for which digest authentication is relevant" ), -#endif - { NULL } +static const command_rec command_table[] = { + AP_INIT_TAKE1( "SingleIdentifier", set_identifier, NULL, OR_AUTHCFG, + "The OpenID identifier we should perform ID selection on when authenticating" ), + AP_INIT_TAKE1( "SingleTrustRoot", set_trust_root, NULL, OR_AUTHCFG, + "The OpenID Trust Root of this site."), + { NULL } }; -#if 0 - -/* ------------------------------------------------------------------------------- - * Socket handling code +/* ------------------------------------------------------------------------------------------- + * COOKIE SESSIONS */ -static apr_status_t cleanup_socket(void *fdv) -{ - close((int)(long)fdv); - return OK; -} - -void disconnect_socket(httpauth_context_t* ctx, server_rec* s) -{ - if(ctx->socket != -1) - { - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, - "httpauth: disconnecting from daemon"); - - apr_pool_cleanup_kill(ctx->child_pool, (void*)(long)ctx->socket, - cleanup_socket); - close(ctx->socket); - ctx->socket = -1; - - /* Make sure we send our list of groups to daemon again */ - if (ctx->needed_groups) - ctx->needed_groups[0] = 0; - } -} - -void read_junk(httpauth_context_t* ctx, request_rec* r) -{ - char buf[16]; - const char* t; - int said = 0; - int l; - - if(ctx->socket == -1) - return; - - /* Make it non blocking */ - fcntl(ctx->socket, F_SETFL, fcntl(ctx->socket, F_GETFL, 0) | O_NONBLOCK); - - for(;;) - { - l = read(ctx->socket, buf, sizeof(buf) - 1); - if(l <= 0) - break; - - buf[l] = 0; - t = trim_start(buf); - - if(!said && *t) - { - ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, - "httpauth: received junk data from daemon"); - said = 1; - } - } - - fcntl(ctx->socket, F_SETFL, fcntl(ctx->socket, F_GETFL, 0) & ~O_NONBLOCK); -} - -int read_line(httpauth_context_t* ctx, request_rec* r, char** line) -{ - int l; - int al = 256; - char* t; - const char* e; - - e = t = NULL; - *line = NULL; - - for(;;) - { - if(!*line || t + 2 == e) - { - char* n; - int d; - - n = (char*)apr_palloc(r->pool, al * 2); - - if(*line) - memcpy(n, *line, al); - - al *= 2; - - /* The difference */ - d = t - *line; - - *line = n; - t = n + d; - e = n + al; - } - - l = read(ctx->socket, (void*)t, sizeof(char)); - - /* We got a character */ - if(l == 1) - { - /* Skip junky CRLFs */ - if(*t == '\r') - { - *t = ' '; - continue; - } - - /* End of line */ - else if(*t == '\n') - { - t++; - break; - } - - t++; - } - - /* If it's the end of file then return that */ - else if(l == 0) - { - /* Disconnect from socket quietly so we can reconnect later */ - disconnect_socket(ctx, r->server); - return -1; - } - - /* Transient errors */ - else if(l == -1 && errno == EAGAIN) - continue; - - /* Fatal errors */ - else if(l == -1) - { - ap_log_rerror(APLOG_MARK, APLOG_ERR, APR_FROM_OS_ERROR(errno), r, - "httpauth: couldn't read data from daemon"); - return -1; - } - } - - *t = 0; - return 0; -} - -int -read_response (httpauth_context_t *ctx, request_rec *r, - int *code, int *ccode, char **details, - int return_errors) -{ - int c, ret = -1; - char *line; - char *t; - char *t2; - - if (read_line (ctx, r, &line) == -1) - return -1; - - line = trim_space (line); - - ap_log_rerror (APLOG_MARK, APLOG_DEBUG, 0, r, - "httpauth: received response line from daemon: %s", line); - - /* Get response code */ - t = ap_getword_nc (r->pool, &line, ' '); - c = strtol (t, &t2, 10); - if (*t2 || c < 100 || c > 999) { - ap_log_rerror (APLOG_MARK, APLOG_ERR, 0, r, - "httpauth: protocol error: invalid code: %s", t); - goto finally; - } - - if (code) - *code = c; - - if (c >= 400 && !return_errors) { - ap_log_rerror (APLOG_MARK, APLOG_ERR, 0, r, - "httpauth: received error from httpauthd: %d %s", c, line); - goto finally; - } - - /* Get the second response code if we're a 200 */ - if (c == 200) { - t = ap_getword_nc (r->pool, &line, ' '); - c = strtol (t, &t2, 10); - if (*t2 || c < 100 || c > 999) { - ap_log_rerror (APLOG_MARK, APLOG_ERR, 0, r, - "httpauth: protocol error: invalid code: %s", t); - goto finally; - } - - if (ccode) - *ccode = c; - } - - if (details) - *details = trim_space (line); - - ret = 0; - -finally: - if (ret < 0 && ctx->socket >= 0) { - disconnect_socket (ctx, r->server); - ++ctx->address_seed; - } - - return ret; -} - -static int -read_process_headers(httpauth_context_t* ctx, int ccode, - request_rec* r, char **groups) -{ - char* line; - const char* name; - apr_table_t* headers; - int c = 0; - - if(ccode > 299) - headers = r->err_headers_out; - else - headers = r->headers_out; - - for(;;) - { - if(read_line(ctx, r, &line) == -1) - return -1; - - /* If that's it then break */ - if(!*line) - break; - - if(apr_isspace(*line)) - { - line = (char*)trim_start(line); - - /* End of headers */ - if(!*line) - break; - - if(c > 0) - { - /* - * TODO: We really should be supporting headers split - * across lines. But httpauthd doesn't currently produce - * headers like that, so we don't need to care about it. - */ - ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, - "httpauth: protocol error: server sent us an split header, which we don't support."); - } - else - { - ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, - "httpauth: protocol error: invalid headers."); - } - } - - name = ap_getword_nc(r->pool, &line, ':'); - if(!name || !*name) - break; - - /* - * If that was the end of the line, then it's an - * invalid header :( - */ - if(!*line) - { - ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, - "httpauth: protocol header: invalid headers"); - return -1; - } - - line = trim_space(line); - - if(strcasecmp(name, "WWW-Authenticate") == 0) - { - if(strncasecmp(line, AUTH_PREFIX_BASIC, strlen(AUTH_PREFIX_BASIC)) == 0 && - !(ctx->types & AUTH_TYPE_BASIC)) - continue; - - else if(strncasecmp(line, AUTH_PREFIX_DIGEST, strlen(AUTH_PREFIX_DIGEST)) == 0 && - !(ctx->types & AUTH_TYPE_DIGEST)) - continue; - - /* Only allow unknown if we don't have it */ - else if(!(ctx->types & AUTH_TYPE_ANY)) - continue; - - /* Fix up when we're a proxy */ - if(r->proxyreq == PROXYREQ_PROXY) - name = "Proxy-Authenticate"; - } - - else if(strcasecmp(name, "Authentication-Info") == 0) - { - if(r->proxyreq == PROXYREQ_PROXY) - name = "Proxy-Authentication-Info"; - } - - else if (strcasecmp(name, "X-HttpAuth-Groups") == 0) - { - if (groups && line) - *groups = line; - } - - c++; - apr_table_addn(headers, name, line); - } - - ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, - "httpauth: received %d headers from daemon", c); - - return 0; -} - -int write_data(httpauth_context_t* ctx, server_rec* s, const char* data) -{ - int r; - - if(ctx->socket == -1) - { - ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, - "httpauth: Socket to httpauthd daemon closed. Can't write data."); - return -1; - } - - while(*data != 0) - { - r = write(ctx->socket, data, strlen(data)); - - if(r > 0) - data += r; - - else if(r == -1) - { - if(errno == EAGAIN) - continue; - - /* The other end closed. no message */ - if(errno == EPIPE) - disconnect_socket(ctx, s); - - else - ap_log_error(APLOG_MARK, APLOG_ERR, APR_FROM_OS_ERROR(errno), s, - "httpauth: Couldn't write data to daemon"); - - return -1; - } - } - - return 0; -} - -static int -try_connect_socket (httpauth_context_t *ctx, struct sockaddr_any *sany, - request_rec *r) -{ - char peername[256]; - int rc; - - if (sock_any_ntop (sany, peername, sizeof (peername), 0) < 0) - strcpy (peername, "[unknown]"); - - ctx->socket = socket (SANY_TYPE (*sany), SOCK_STREAM, 0); - if(ctx->socket == -1) { - ap_log_rerror (APLOG_MARK, APLOG_CRIT, APR_FROM_OS_ERROR (errno), r, - "httpauth: Can't create socket"); - return -1; - } - - if (connect (ctx->socket, &SANY_ADDR (*sany), SANY_LEN(*sany)) != 0) { - rc = APR_FROM_OS_ERROR (errno); - ap_log_rerror (APLOG_MARK, APLOG_CRIT, rc, r, - "httpauth: Can't connect to httpauthd at: %s", peername); - close (ctx->socket); - ctx->socket = -1; - return -1; - } - - ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, - "httpauth: connected to daemon: %s", peername); - - return 0; -} - -static int -connect_socket(httpauth_context_t* ctx, request_rec* r) -{ - httpauth_shared_t shared; - struct sockaddr_any sany[16]; - int i, which, count = 0; - int rc = -1; - - disconnect_socket(ctx, r->server); - memset (&shared, 0, sizeof (shared)); - - /* Find out what everyone else is connected to */ - if (shared_get_if_changed (ctx, ctx->shared_version, &shared) && shared.version > 0) { - ap_log_rerror (APLOG_MARK, APLOG_DEBUG, 0, r, - "httpauth: trying shared address..."); - rc = try_connect_socket (ctx, &shared.address, r); - } - - /* Now try to connect to all the other addresses */ - if (rc < 0) { - ap_log_rerror (APLOG_MARK, APLOG_DEBUG, 0, r, - "httpauth: resolving daemon address(s)"); - - count = sock_any_pton_n (ctx->socketname, sany, 16, DEFAULT_PORT); - if (count < 0) { - ap_log_rerror(APLOG_MARK, APLOG_CRIT, 0, r, - "httpauth: Invalid socket name or ip: %s", ctx->socketname); - rc = -1; - } - - /* We know how many addresses we have to retry with */ - if (count > 0) - ctx->retries = count; - - for (i = 0; i != count; ++i) { - which = (i + ctx->address_seed) % count; - rc = try_connect_socket (ctx, &sany[which], r); - - /* Successful, then let others know we're connected here */ - if (rc >= 0) { - memcpy (&shared.address, &sany[which], sizeof (shared.address)); - break; - } - } - } - - /* Yay, successful */ - if (rc >= 0) { - shared_set_if_changed (ctx, &shared); - ctx->shared_version = shared.version; - apr_pool_cleanup_register(ctx->child_pool, (void*)(long)ctx->socket, - cleanup_socket, cleanup_socket); - errno = 0; - } - - return rc; -} - -int connect_httpauth(httpauth_context_t* ctx, request_rec* r) -{ - int ret = -1; - int code; - char* details; - const char* t; - - if(connect_socket(ctx, r) == -1) - goto finally; - - if(read_response(ctx, r, &code, NULL, &details, 0) == -1) - goto finally; - - if(code != 100) - { - ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, - "httpauth: protocol error (Expected 100, got %d)", code); - goto finally; - } - - /* Check theversion number */ - details = trim_space(details); - - if(strcmp(details, "HTTPAUTH/1.0") != 0) - { - ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, - "httpauth: Daemon speaking incompatible protocol version: %s", details); - goto finally; - } - - /* Send our handler */ - if(ctx->handler) - { - t = apr_pstrcat(r->pool, "SET Handler ", ctx->handler, "\n", NULL); - - if(write_data(ctx, r->server, t) == -1) - goto finally; - - ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, - "httpauth: sent handler to daemon: %s", t); - - 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: couldn't send handler to daemon (Expected 202, got %d)", code); - goto finally; - } - } - - /* Send any setup info we have */ - if(ctx->domain) - { - t = apr_pstrcat(r->pool, "SET Domain ", ctx->domain, "\n", NULL); - - if(write_data(ctx, r->server, t) == -1) - goto finally; - - ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, - "httpauth: sent domains to daemon: %s", t); - - 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: couldn't send domain to daemon (Expected 202, got %d)", code); - goto finally; - } - } - - /* We're cool! */ - ret = 0; - ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "httpauth: handshake with daemon completed"); - -finally: - if(ret == -1 && ctx->socket >= 0) { - disconnect_socket(ctx, r->server); - ++ctx->address_seed; - } - - return ret; -} - -/* Make sure our connection identifier is unique */ -static apr_status_t connection_gone (void *data) -{ - conn_current = NULL; - conn_seen++; - return APR_SUCCESS; -} - -int write_request(httpauth_context_t* ctx, request_rec* r) -{ - char pidid[40]; - char connid[40]; - int i, c = 0; - const char* t; - const apr_array_header_t* hdrs_arr; - const apr_table_entry_t* elts; - - /* When the connection goes away, call our handler */ - if(conn_current != r->connection) - { - conn_current = r->connection; - apr_pool_cleanup_register(r->connection->pool, r, - connection_gone, apr_pool_cleanup_null); - } - - /* A unique per connection id */ - snprintf(connid, sizeof(connid), "0x%X-%X-%X", - (unsigned int)r->connection, conn_seen, (unsigned int)r->connection->id); - connid[sizeof(connid) - 1] = 0; - snprintf(pidid, sizeof(pidid), "%d", (unsigned int)getpid()); - pidid[sizeof(pidid) - 1] = 0; - t = apr_pstrcat(r->pool, pidid, ":", connid, NULL); - - /* Send the request header to httpauthd */ - t = apr_pstrcat(r->pool, "AUTH ", t, " ", r->method, - " ", r->unparsed_uri, "\n", NULL); - - if(write_data(ctx, r->server, t) == -1) - return -1; - - ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, - "httpauth: sent auth request to daemon: %s", t); - - /* Now send the headers to httpauthd */ - - hdrs_arr = apr_table_elts(r->headers_in); - elts = (const apr_table_entry_t*)hdrs_arr->elts; - - for(i = 0; i < hdrs_arr->nelts; i++) - { - if(!elts[i].val) - continue; - - /* Filter out headers we don't want */ - if(strcasecmp(elts[i].key, r->proxyreq == PROXYREQ_PROXY ? - "Proxy-Authorization" : "Authorization") == 0) - { - t = trim_start(elts[i].val); - - if(strncasecmp(t, AUTH_PREFIX_BASIC, strlen(AUTH_PREFIX_BASIC)) == 0 && - !(ctx->types & AUTH_TYPE_BASIC)) - continue; - - else if(strncasecmp(t, AUTH_PREFIX_DIGEST, strlen(AUTH_PREFIX_DIGEST)) == 0 && - !(ctx->types & AUTH_TYPE_DIGEST)) - continue; - - else if(strncasecmp(t, AUTH_PREFIX_NTLM, strlen(AUTH_PREFIX_NTLM)) == 0 && - !(ctx->types & AUTH_TYPE_NTLM)) - continue; - - /* Only allow unknown if we don't have it */ - else if(!(ctx->types & AUTH_TYPE_ANY)) - continue; - - /* Extra blank line when at end */ - t = apr_pstrcat(r->pool, "Authorization: ", elts[i].val, "\n", NULL); - - if(write_data(ctx, r->server, t) == -1) - return HTTP_INTERNAL_SERVER_ERROR; - - c++; - } - } - - ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, - "httpauth: sent %d headers to daemon", c); - - 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; - } +typedef struct sid_session { + char *identifier; + time_t expiry; +} sid_session_t; - /* 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; -} +/* Secret used to sign session cookies */ +static unsigned char session_secret[40]; -static httpauth_request_t* -setup_request_hreq (request_rec *r, char *user, char *groups) +static apr_status_t +session_initialize (apr_pool_t *p, server_rec *s) { - httpauth_request_t* hreq; + apr_status_t status; - hreq = (httpauth_request_t*)apr_pcalloc (r->pool, sizeof (*hreq)); - hreq->user = r->user; - hreq->groups = groups; - - if (groups) - apr_table_setn (r->subprocess_env, "HTTPAUTH_GROUPS", groups); - else - apr_table_unset (r->subprocess_env, "HTTPAUTH_GROUPS"); +#if APR_HAS_RANDOM + status = apr_generate_random_bytes (session_secret, sizeof (session_secret)); +#else +#error APR random number support is missing; you probably need to install the truerand library. +#endif - ap_set_module_config (r->request_config, &httpauth_module, hreq); + if (status != APR_SUCCESS) + ap_log_error (APLOG_MARK, APLOG_CRIT, status, s, + "auth-singleid: couldn't generate random secret"); - return hreq; + return status; } -#endif - -typedef struct session_info { - char *identifier; - time_t expiry; -} session_info_t; - static const char* session_cookie_value (request_rec *r, const char *name) { @@ -1192,7 +355,7 @@ session_create_sig (apr_pool_t *p, const char *value) apr_sha1_ctx_t ctx; apr_sha1_init (&ctx); - apr_sha1_update (&ctx, session_secret, strlen (session_secret)); + apr_sha1_update (&ctx, (const char*)session_secret, sizeof (session_secret)); apr_sha1_update (&ctx, "\0", 1); apr_sha1_update (&ctx, value, strlen (value)); apr_sha1_final (digest, &ctx); @@ -1209,10 +372,10 @@ session_validate_sig (apr_pool_t *p, const char *sig, const char *value) return strcmp (sig, valid) == 0; } -static session_info_t* +static sid_session_t* session_load_info (request_rec *r) { - session_info_t *sess; + sid_session_t *sess; const char *value; char *token, *sig, *end; char *identifier; @@ -1246,7 +409,7 @@ session_load_info (request_rec *r) if (!ap_is_url (identifier)) return NULL; - sess = apr_pcalloc (r->pool, sizeof (session_info_t)); + sess = apr_pcalloc (r->pool, sizeof (sid_session_t)); sess->expiry = expiry; sess->identifier = identifier; @@ -1254,7 +417,7 @@ session_load_info (request_rec *r) } static void -session_send_info (request_rec *r, session_info_t *sess) +session_send_info (request_rec *r, sid_session_t *sess) { char *cookie, *sig, *value; @@ -1267,53 +430,152 @@ session_send_info (request_rec *r, session_info_t *sess) apr_table_addn (r->headers_out, "Set-Cookie", cookie); } -static session_info_t* -session_copy_info (apr_pool_t *p, session_info_t *sess) +static sid_session_t* +session_copy_info (apr_pool_t *p, sid_session_t *sess) { - session_info_t *copy = apr_palloc (p, sizeof (*sess)); + sid_session_t *copy = apr_palloc (p, sizeof (*sess)); copy->expiry = sess->expiry; copy->identifier = apr_pstrdup (p, sess->identifier); return copy; } +/* --------------------------------------------------------------------------------------- + * REQUEST ABSTRACTIONS + */ + +struct sid_request { + int result; + request_rec *rec; +}; + + +void +sid_request_log_error (sid_request_t *req, const char *message, const char *detail) +{ + ap_log_rerror (APLOG_MARK, APLOG_ERR, 0, req->rec, + "%s%s%s", message, + detail ? ": " : "", + detail ? detail : ""); + +} + +const char* +sid_request_qs (sid_request_t *req) +{ + return req->rec->args; +} + +const char* +sid_request_url (sid_request_t *req) +{ + /* function to determine if a connection is using https */ + static APR_OPTIONAL_FN_TYPE(ssl_is_https) *using_https = NULL; + static int using_https_inited = 0; + + const char *scheme; + const char *host; + const char *uri; + apr_port_t port; + int is_ssl; + + if (!using_https_inited) { + using_https = APR_RETRIEVE_OPTIONAL_FN (ssl_is_https); + using_https_inited = 1; + } + + is_ssl = using_https && using_https (req->rec->connection); + host = req->rec->hostname ? req->rec->hostname : ap_get_server_name (req->rec); + scheme = is_ssl ? "https" : "http"; + port = ap_get_server_port (req->rec); + uri = req->rec->uri ? req->rec->uri : ""; + + /* Default ports? */ + if ((port == 80 && !is_ssl) || (port == 443 && is_ssl)) + return apr_psprintf (req->rec->pool, "%s://%s%s", scheme, host, uri); + else + return apr_psprintf (req->rec->pool, "%s://%s:%d%s", scheme, host, port, uri); +} + +void +sid_request_respond (sid_request_t *req, int code, const char *reason, + const char *header, ...) +{ + const char *value; + va_list va; + + if (reason) + req->rec->status_line = apr_pstrdup (req->rec->pool, reason); + + va_start(va, header); + while (header) { + value = va_arg (va, const char*); + apr_table_set (req->rec->err_headers_out, header, value); + header = va_arg (va, const char*); + } + va_end(va); + + req->result = code; +} + static void -set_request_authenticated (request_rec *r, session_info_t *sess) +set_request_authenticated (request_rec *r, sid_session_t *sess) { r->user = sess->identifier; - r->ap_auth_type = SINGLEID_AUTHTYPE; + r->ap_auth_type = SID_AUTHTYPE; ap_set_module_config (r->request_config, &auth_singleid_module, sess); } +void +sid_request_authenticated (sid_request_t *req, const char *identifier) +{ + sid_session_t *sess; + + sess = apr_pcalloc (req->rec->pool, sizeof (sid_session_t)); + sess->identifier = apr_pstrdup (req->rec->pool, identifier); + sess->expiry = time (NULL) + 86400; + + set_request_authenticated (req->rec, sess); + session_send_info (req->rec, sess); +} + +/* --------------------------------------------------------------------------------------- + * MAIN HOOKS + */ + +static int +hook_initialize (apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s) +{ + int rc; + + rc = shared_initialize (p, s); + if (rc != OK) + return rc; + + return session_initialize (p, s); +} + +static void +hook_child (apr_pool_t *p, server_rec *s) +{ + shared_child (p, s); +} + static int hook_authenticate (request_rec* r) { - session_info_t *sess; -#if 0 - httpauth_context_t* ctx; - httpauth_request_t* hreq; -#endif + sid_session_t *sess; + sid_context_t *ctx; + sid_request_t req; const char* authtype; -#if 0 - int code = 0; - int ccode = 0; - char *groups = NULL; - char* details = NULL; -#endif request_rec* mainreq; -#if 0 - int retried = 0; -#endif /* Make sure it's for us */ - if (!(authtype = ap_auth_type (r)) || strcasecmp (SINGLEID_AUTHTYPE, authtype) != 0) + if (!(authtype = ap_auth_type (r)) || strcasecmp (SID_AUTHTYPE, authtype) != 0) return DECLINED; -#if 0 - ctx = (httpauth_context_t*)ap_get_module_config(r->per_dir_config, &httpauth_module); - - if(!ctx->socketname || !ctx->handler) + ctx = (sid_context_t*)ap_get_module_config(r->per_dir_config, &auth_singleid_module); + if(ctx->identifier == NULL) return DECLINED; -#endif mainreq = r; @@ -1340,214 +602,23 @@ hook_authenticate (request_rec* r) return OK; } + req.result = OK; + req.rec = r; - /* Otherwise start a new openid authentication */ - return DECLINED; - -#if 0 - /* - * Check if we're in sync with the other processes, - * and connected to the same daemon - */ - if (ctx->socket != -1 && shared_get_if_changed (ctx, ctx->shared_version, NULL)) { - ap_log_rerror (APLOG_MARK, APLOG_INFO, 0, r, - "httpauth: syncing connection with other processes"); - disconnect_socket (ctx, r->server); - } - -/* For jumping to when a connection has been closed */ -retry: - - if (ctx->socket == -1) { - if (connect_httpauth (ctx, r) == -1) { - - if (ctx->socket == -1 && retried < ctx->retries) { - ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, - "httpauth: trying to connect to daemon again"); - ++retried; - goto retry; - } - - return HTTP_INTERNAL_SERVER_ERROR; - } - } - - /* Make sure we're starting on a clean slate */ - read_junk (ctx, r); - - - - /* 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 - * is where we get the error. Just do one retry to - * try and reconnect. This happens often when restarting - * httpauthd. - */ - - if (ctx->socket == -1 && retried < ctx->retries) { - ap_log_rerror (APLOG_MARK, APLOG_WARNING, 0, r, - "httpauth: reconnecting to to httpauthd"); - ++retried; - goto retry; - } - - ap_log_rerror (APLOG_MARK, APLOG_ERR, APR_FROM_OS_ERROR(errno), r, - "httpauth: couldn't send request to httpauthd"); - - return HTTP_INTERNAL_SERVER_ERROR; - } - - if(code != 200) - { - ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, - "httpauth: protocol error: unexpected code while authenticating: %d", code); - return HTTP_INTERNAL_SERVER_ERROR; - } - - /* Copy over other headers */ - 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); - - r->user = apr_pstrdup (r->pool, details); - r->ap_auth_type = HTTPAUTH_AUTHTYPE; - - /* Mark request as successfully authenticated */ - hreq = setup_request_hreq (r, details, groups); - return OK; - } - - return ccode; -#endif -} - - -#if 0 - -static const char* -find_word_quoted (const char *all, const char *word) -{ - 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; - } -} - -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; - 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; + /* Do the OpenID magic */ + sid_consumer_authenticate (&req, ctx->store, ctx->trust_root, ctx->identifier); - 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; + return req.result; } -#endif static void register_hooks(apr_pool_t *p) { ap_log_perror (APLOG_MARK, APLOG_ERR, 0, p, "mod_auth_singleid registering hooks"); -#if 0 - ap_hook_post_config (httpauth_initialize, NULL, NULL, APR_HOOK_MIDDLE); - ap_hook_child_init (httpauth_child, NULL, NULL, APR_HOOK_MIDDLE); + + ap_hook_post_config (hook_initialize, NULL, NULL, APR_HOOK_MIDDLE); + ap_hook_child_init (hook_child, NULL, NULL, APR_HOOK_MIDDLE); ap_hook_check_user_id (hook_authenticate, NULL, NULL, APR_HOOK_MIDDLE); - ap_hook_auth_checker (httpauth_access, NULL, NULL, APR_HOOK_MIDDLE); -#endif } module AP_MODULE_DECLARE_DATA auth_singleid_module = { -- cgit v1.2.3