X-Git-Url: https://git.hcoop.net/hcoop/debian/libapache-mod-waklog.git/blobdiff_plain/891fb45869db9d1aaa33e6951d3a200917b05fdd..e6db60c3d5cdfc390fe319e16f8e3fb58947058e:/mod_waklog.c diff --git a/mod_waklog.c b/mod_waklog.c index c85352a..eca89ad 100644 --- a/mod_waklog.c +++ b/mod_waklog.c @@ -10,6 +10,8 @@ #ifdef sun #include +#include +#include #elif linux #define use_pthreads #include @@ -31,9 +33,6 @@ /********************* APACHE1 ******************************************************************************/ #ifndef APACHE2 #include "ap_config.h" -#if defined(sun) -#include -#endif /* sun */ #include #define MK_POOL pool #define MK_TABLE_GET ap_table_get @@ -42,66 +41,58 @@ { name, func, \ NULL , \ RSRC_CONF | ACCESS_CONF , type, usage } +module waklog_module; /********************* APACHE2 ******************************************************************************/ #else +#include "http_connection.h" #include #include -//#include +#include #define ap_pcalloc apr_pcalloc #define ap_pdupstr apr_pdupstr #define ap_pstrdup apr_pstrdup - -module AP_MODULE_DECLARE_DATA waklog_module; - #define MK_POOL apr_pool_t #define MK_TABLE_GET apr_table_get #define MK_TABLE_SET apr_table_set -#include "unixd.h" -extern unixd_config_rec unixd_config; -#define ap_user_id unixd_config.user_id -#define ap_group_id unixd_config.group_id -#define ap_user_name unixd_config.user_name #define command(name, func, var, type, usage) \ AP_INIT_ ## type (name, (void*) func, \ NULL, \ RSRC_CONF | ACCESS_CONF, usage) -typedef struct -{ - int dummy; -} -child_info; - +module AP_MODULE_DECLARE_DATA waklog_module; +typedef struct { int dummy; } child_info; const char *userdata_key = "waklog_init"; + +/* Apache 2.4 */ +#ifdef APLOG_USE_MODULE +APLOG_USE_MODULE(waklog); +#endif + #endif /* APACHE2 */ /**************************************************************************************************/ #include -#include +#include + +#include + #include #include #include #include +#include #include #define TKT_LIFE ( 12 * 60 * 60 ) #define SLEEP_TIME ( TKT_LIFE - 5*60 ) -#define WAKLOG_ON 1 -#define WAKLOG_OFF 2 -#define WAKLOG_UNSET 0 +#define WAKLOG_UNSET -1 #ifdef WAKLOG_DEBUG #undef APLOG_DEBUG #define APLOG_DEBUG APLOG_ERR #endif -#ifndef CELL_IN_PRINCIPAL -int cell_in_principal = 1; -#else -int cell_in_principal = 0; -#endif - /* this is used to turn off pag generation for the backround worker child during startup */ int pag_for_children = 1; @@ -111,11 +102,14 @@ typedef struct int configured; int protect; int usertokens; + int cell_in_principal; + int disable_token_cache; char *keytab; char *principal; char *default_principal; char *default_keytab; char *afs_cell; + char *afs_cell_realm; char *path; MK_POOL *p; } @@ -168,32 +162,20 @@ struct renew_ent renewtable[SHARED_TABLE_SIZE]; int renewcount = 0; -module waklog_module; #define getModConfig(P, X) P = (waklog_config *) ap_get_module_config( (X)->module_config, &waklog_module ); -#include - -#if defined(sun) -#include -#endif /* sun */ -#include -#include -#include -#include -#include -#include - -/* If there's an error, retry more aggressively */ -#define ERR_SLEEP_TIME 5*60 - - -#define K5PATH "FILE:/tmp/waklog.creds.k5" +#ifdef APLOG_USE_MODULE +static void +log_error (const char *file, int line, int module_index, int level, int status, + const server_rec * s, const char *fmt, ...) +#else static void log_error (const char *file, int line, int level, int status, const server_rec * s, const char *fmt, ...) +#endif { char errstr[4096]; va_list ap; @@ -203,7 +185,12 @@ log_error (const char *file, int line, int level, int status, va_end (ap); #ifdef APACHE2 + #ifdef APLOG_USE_MODULE + /* Apache 2.4 */ + ap_log_error (file, line, module_index, level | APLOG_NOERRNO, status, s, "%s", errstr); + #else ap_log_error (file, line, level | APLOG_NOERRNO, status, s, "(%d) %s", getpid(), errstr); + #endif #else ap_log_error (file, line, level | APLOG_NOERRNO, s, "(%d) %s", getpid(), errstr); #endif @@ -247,6 +234,7 @@ set_auth ( server_rec *s, request_rec *r, int self, char *principal, char *keyta krb5_get_init_creds_opt kopts; krb5_creds v5creds; krb5_creds increds; + krb5_ccache clientccache; struct ktc_principal server = { "afs", "", "" }; struct ktc_principal client; struct ktc_token token; @@ -257,29 +245,50 @@ set_auth ( server_rec *s, request_rec *r, int self, char *principal, char *keyta int rc = 0; int buflen = 0; time_t oldest_time = 0; - int oldest; + int oldest = 0; int stored = -1; time_t mytime; int indentical; + int cell_in_principal; + int attempt; + int use_client_credentials = 0; - char k5user[MAXNAMELEN]; - char *k5secret; + char k5user[MAXNAMELEN] = ""; + char *k5secret = NULL; + + char *k5path = NULL; memset((char *) &increds, 0, sizeof(increds)); - /* init some stuff if it ain't already */ - + /* XXX - In what situation will these not be initialized? */ + if ( ! child.kcontext ) { - kerror = krb5_init_context(&child.kcontext); + if ((kerror = krb5_init_context(&child.kcontext))) { + log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: can't initialize Kerberos context err=%d", + kerror); + return(-1); + } } - - if ( ( ! child.ccache ) && ( kerror = krb5_cc_resolve(child.kcontext, "MEMORY:tmpcache", &child.ccache) ) ) { - log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: can't initialize in-memory credentials cache %d", kerror ); + + if ( !child.ccache) { + if ((kerror = krb5_cc_resolve(child.kcontext, "MEMORY:tmpcache", &child.ccache))) { + log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: can't initialize credentials cache %s err=%d", + k5path, kerror ); + return(-1); + } } - - log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "mod_waklog: set_auth: %d, %s, %s, %d", self, principal ? principal : "NULL", - keytab ? keytab : "NULL", storeonly); + log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "mod_waklog: set_auth: %d, %s, %s, %d, KRB5CC=%s user=%s", + self, principal ? principal : "NULL", + keytab ? keytab : "NULL", + storeonly, + k5path ? k5path : "NULL", +#ifdef APACHE2 + (r && r->user) ? r->user : "NULL" +#else + (r && r->connection && r->connection->user) ? r->connection->user : "NULL" +#endif + ); /* pull the server config record that we care about... */ @@ -294,34 +303,51 @@ set_auth ( server_rec *s, request_rec *r, int self, char *principal, char *keyta if ( ! cfg ) { log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "mod_waklog: cfg is %d", cfg ); } - -#ifdef APACHE2 + + if ( self ) { /* pull out our principal name and stuff from the environment -- webauth better have sent - through. This here is also where you'd suck stuff out of KRB5CCNAME if we were - using something like Cosign */ - + through. */ + +#ifdef APACHE2 if ( ! ( r && r->connection && r->user )) { log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: self authentication selected, but no data available"); + log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: r->user=%s", (r->user==NULL ? "null" : r->user)); return -1; } strncpy(k5user, r->user, sizeof(k5user)); - - /* the other thing we need is someone's password */ - if ( ! ( k5secret = (char *) MK_TABLE_GET( r->notes, "ATTR_PASSWORD" ) ) ) { - log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: cant do self auth without a secret"); +#else + if ( ! (r && r->connection && r->connection->user)) { + log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: self authentication selected, but no username available"); return -1; - } + } + + strncpy(k5user, r->connection->user, sizeof(k5user)); +#endif + /* if they've supplied a credentials cache */ + k5path = (char *) MK_TABLE_GET( r->subprocess_env, "KRB5CCNAME" ); + + /* the other thing we need is someone's password */ + k5secret = (char *) MK_TABLE_GET( r->notes, "ATTR_PASSWORD" ); /* we'll pick this up later after we've checked the cache and current state */ } else -#endif if ( principal ) { - strncpy( k5user, principal, sizeof(k5user)); + strncpy(k5user, principal, sizeof(k5user)); + } else +#ifdef APACHE2 + if (r && r->user) { + strncpy(k5user, r->user, sizeof(k5user)); + } +#else + if (r && r->connection && r->connection->user) { + strncpy(k5user, r->connection->user, sizeof(k5user)); } +#endif + log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "mod_waklog: set_auth: k5user=%s", k5user); mytime = time(0); /* see if we should just go ahead and ignore this call, since we already should be set to these @@ -390,18 +416,17 @@ set_auth ( server_rec *s, request_rec *r, int self, char *principal, char *keyta } } - + /* if 'usecached' isn't set, we've got to get our tokens from somewhere... */ - - if (( ! usecached ) && ( k5user )) { + if ( ! usecached ) { /* clear out the creds structure */ memset((void *) &v5creds, 0, sizeof(v5creds)); /* create a principal out of our k5user string */ - if ( kerror = krb5_parse_name (child.kcontext, k5user, &kprinc ) ) { - log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: krb5_parse_name %s", (char *) error_message(kerror) ); + if ( ( kerror = krb5_parse_name (child.kcontext, k5user, &kprinc ) ) ) { + log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: krb5_parse_name %s", (char *) afs_error_message(kerror) ); goto cleanup; } @@ -413,110 +438,129 @@ set_auth ( server_rec *s, request_rec *r, int self, char *principal, char *keyta krb5_get_init_creds_opt_set_forwardable ( &kopts, 0 ); krb5_get_init_creds_opt_set_proxiable ( &kopts, 0 ); - if ( keytab ) { + if ( keytab || k5secret ) { - /* if we've been passed a keytab, we're going to be getting our credentials from it */ + if (keytab) { + /* if we've been passed a keytab, we're going to be getting our credentials from it */ - log_error( APLOG_MARK, APLOG_DEBUG, 0, s, "mod_waklog: using keytab %s", keytab); + log_error( APLOG_MARK, APLOG_DEBUG, 0, s, "mod_waklog: using keytab %s", keytab); - if ( kerror = krb5_kt_resolve(child.kcontext, keytab, &krb5kt ) ) { - log_error( APLOG_MARK, APLOG_ERR, 0, s, - "mod_waklog: krb5_kt_resolve %s", error_message(kerror) ); - goto cleanup; - } + if ( ( kerror = krb5_kt_resolve(child.kcontext, keytab, &krb5kt ) ) ) { + log_error( APLOG_MARK, APLOG_ERR, 0, s, + "mod_waklog: krb5_kt_resolve %s", afs_error_message(kerror) ); + goto cleanup; + } - if ((kerror = krb5_get_init_creds_keytab (child.kcontext, &v5creds, - kprinc, krb5kt, 0, NULL, &kopts ) ) ) { - log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: krb5_get_init_creds_keytab %s", - error_message(kerror) ); - goto cleanup; - } + if ((kerror = krb5_get_init_creds_keytab (child.kcontext, &v5creds, + kprinc, krb5kt, 0, NULL, &kopts ) ) ) { + log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: krb5_get_init_creds_keytab %s", + afs_error_message(kerror) ); + goto cleanup; + } + } else if (k5secret) { - } else if ( self ) { + /* If the WebSSO is lame enough to provide a secret, then try and use that to get a token */ - /* if 'self' is set, we're going to use the credentials provided in the credential information */ - /* if you're using CoSign, you'd actually just set the ccache to the KRB5CCNAME credentials */ - /* and skip ahead... Our WebSSO is lame, but has a way for us to snarf the password out of */ - /* the encrypted token for proxy-authentication stuff. We only hand out keys that allow this */ - /* functionality to VERY special people. */ + if ((kerror = krb5_get_init_creds_password ( child.kcontext, &v5creds, + kprinc, k5secret, NULL, NULL, 0, NULL, &kopts ) ) ) { + log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: krb5_get_init_creds_password %s", + afs_error_message(kerror) ); + /* nuke the password so it doesn't end up in core files */ + memset(k5secret, 0, strlen(k5secret)); + goto cleanup; + } - if ((kerror = krb5_get_init_creds_password ( child.kcontext, &v5creds, - kprinc, k5secret, NULL, NULL, 0, NULL, &kopts ) ) ) { - log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: krb5_get_init_creds_password %s", - error_message(kerror) ); - /* nuke the password so it doesn't end up in core files */ - memset(k5secret, 0, sizeof(k5secret)); - goto cleanup; + memset(k5secret, 0, strlen(k5secret)); } - - memset(k5secret, 0, sizeof(k5secret)); - - } else { - - /* degenerate case -- we don't have enough information to do anything */ - - log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: no keytab, no self?"); - kerror = -1; - goto cleanup; - - } - + /* initialize the credentials cache and store the stuff we just got */ + if ( ( kerror = krb5_cc_initialize (child.kcontext, child.ccache, kprinc) ) ) { + log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: init credentials cache %s", + afs_error_message(kerror)); + goto cleanup; + } - if ( kerror = krb5_cc_initialize (child.kcontext, child.ccache, kprinc)) { - log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: init credentials cache %s", - error_message(kerror)); - goto cleanup; - } - - if ( kerror = krb5_cc_store_cred(child.kcontext, child.ccache, &v5creds) ) { - log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: cannot store credentials %s", - error_message(kerror)); - goto cleanup; - } + if ( ( kerror = krb5_cc_store_cred(child.kcontext, child.ccache, &v5creds) ) ) { + log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: cannot store credentials %s", + afs_error_message(kerror)); + goto cleanup; + } - krb5_free_cred_contents(child.kcontext, &v5creds); + krb5_free_cred_contents(child.kcontext, &v5creds); + + if ( kerror ) { + log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: store cred %s", afs_error_message(kerror)); + goto cleanup; + } + + log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "mod_waklog: kinit ok for %s", k5user ); + + } else if (k5path) { + /* If we've got a path to a credentials cache, then try and use that. We can't just + * replace child.creds, because we want to ensure that only this request gets access to + * that cache */ + + if ( ( kerror = krb5_cc_resolve(child.kcontext, k5path, &clientccache ) ) ) { + log_error(APLOG_MARK, APLOG_ERR, 0, s, + "mod_waklog: can't open provided credentials cache %s err=%d", + k5path, kerror ); + goto cleanup; + } + + use_client_credentials = 1; + } - if ( kerror ) { - log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: store cred %s", error_message(kerror)); - goto cleanup; - } - - log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "mod_waklog: kinit ok for %s", k5user ); - /* now, to the 'aklog' portion of our program. */ - strncpy( buf, "afs", sizeof(buf) - 1 ); - - if (cell_in_principal) { - strncat(buf, "/", sizeof(buf) - strlen(buf) - 1); - strncat(buf, cfg->afs_cell, sizeof(buf) - strlen(buf) - 1); - } + /** we make two attempts here, one for afs@REALM and one for afs/cell@REALM */ + for(attempt = 0; attempt <= 1; attempt++) { + strncpy( buf, "afs", sizeof(buf) - 1 ); + cell_in_principal = (cfg->cell_in_principal + attempt) % 2; + + log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "mod_waklog: cell_in_principal=%d", cell_in_principal ); + if (cell_in_principal) { + strncat(buf, "/", sizeof(buf) - strlen(buf) - 1); + strncat(buf, cfg->afs_cell, sizeof(buf) - strlen(buf) - 1); + } + if (cfg->afs_cell_realm != NULL) { + strncat(buf, "@", sizeof(buf) - strlen(buf) - 1); + strncat(buf, cfg->afs_cell_realm, sizeof(buf) - strlen(buf) - 1); + } + + log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "mod_waklog: using AFS principal: %s", buf); + + if ((kerror = krb5_parse_name (child.kcontext, buf, &increds.server))) { + log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: krb5_parse name %s", afs_error_message(kerror)); + goto cleanup; + } - log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "mod_waklog: using AFS principal: %s", buf); - - if ((kerror = krb5_parse_name (child.kcontext, buf, &increds.server))) { - log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: krb5_parse name %s", error_message(kerror)); - goto cleanup; - } - - if ((kerror = krb5_cc_get_principal(child.kcontext, child.ccache, &increds.client))) { - log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: krb5_cc_get_princ %s", error_message(kerror)); - goto cleanup; - } - - log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "mod_waklog: retrieved data from ccache for %s", k5user); - - increds.times.endtime = 0; - - increds.keyblock.enctype = ENCTYPE_DES_CBC_CRC; - - if (kerror = krb5_get_credentials (child.kcontext, 0, child.ccache, &increds, &v5credsp )) { - log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: krb5_get_credentials: %s", - error_message(kerror)); - goto cleanup; + if (!use_client_credentials) { + clientccache = child.ccache; + } + + if ((kerror = krb5_cc_get_principal(child.kcontext, clientccache, &increds.client))) { + log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: krb5_cc_get_princ %s %p", afs_error_message(kerror), clientccache); + goto cleanup; + } + + log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "mod_waklog: retrieved data from ccache for %s", k5user); + + increds.times.endtime = 0; + + if ( ( kerror = krb5_get_credentials (child.kcontext, 0, clientccache, &increds, &v5credsp ) ) ) { + /* only complain once we've tried both afs@REALM and afs/cell@REALM */ + if (attempt>=1) { + log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: krb5_get_credentials: %s", + afs_error_message(kerror)); + goto cleanup; + } else { + continue; + } + } + cfg->cell_in_principal = cell_in_principal; + break; } - + log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "mod_waklog: get_credentials passed for %s", k5user); if ( v5credsp->ticket.length >= MAXKTCTICKETLEN ) { @@ -530,7 +574,12 @@ set_auth ( server_rec *s, request_rec *r, int self, char *principal, char *keyta token.startTime = v5credsp->times.starttime ? v5credsp->times.starttime : v5credsp->times.authtime; token.endTime = v5credsp->times.endtime; - memmove( &token.sessionKey, v5credsp->keyblock.contents, v5credsp->keyblock.length); + if (tkt_DeriveDesKey(v5credsp->keyblock.enctype, v5credsp->keyblock.contents, + v5credsp->keyblock.length, &token.sessionKey) != 0) { + log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: tkt_DeriveDesKey failure (enctype: %d)", + v5credsp->keyblock.enctype); + goto cleanup; + } token.kvno = RXKAD_TKT_TYPE_KERBEROS_V5; token.ticketLen = v5credsp->ticket.length; memmove( token.ticket, v5credsp->ticket.data, token.ticketLen); @@ -665,15 +714,17 @@ set_auth ( server_rec *s, request_rec *r, int self, char *principal, char *keyta if ((rc = ktc_SetToken(&child.server, &child.token, &child.client, 0))) { log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "mod_waklog: settoken returned %s for %s -- trying again", - error_message(rc), k5user); + afs_error_message(rc), k5user); if ((rc = ktc_SetToken(&child.server, &child.token, &child.client, 0))) { log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: settoken2 returned %s for %s", - error_message(rc), k5user); + afs_error_message(rc), k5user); goto cleanup; } } cleanup: + if (use_client_credentials) + krb5_cc_close(child.kcontext, clientccache); if ( v5credsp ) krb5_free_cred_contents(child.kcontext, v5credsp); if ( increds.client ) @@ -688,7 +739,7 @@ set_auth ( server_rec *s, request_rec *r, int self, char *principal, char *keyta if ( rc ) { log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: set_auth ending with %d", rc ); } else if ( kerror ) { - log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: set_auth ending with krb5 error %d, %s", kerror, error_message(kerror)); + log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: set_auth ending with krb5 error %d, %s", kerror, afs_error_message(kerror)); } else { log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "mod_waklog: set_auth ending ok"); } @@ -698,6 +749,27 @@ set_auth ( server_rec *s, request_rec *r, int self, char *principal, char *keyta } +int get_cfg_usertokens(waklog_config *cfg) +{ + if (cfg->usertokens==WAKLOG_UNSET) + return 0; /* default */ + return cfg->usertokens; +} + +int get_cfg_protect(waklog_config *cfg) +{ + if (cfg->protect==WAKLOG_UNSET) + return 0; /* default */ + return cfg->protect; +} + +int get_cfg_disable_token_cache(waklog_config *cfg) +{ + if (cfg->disable_token_cache==WAKLOG_UNSET) + return 0; /* default */ + return cfg->disable_token_cache; +} + static void * waklog_create_server_config (MK_POOL * p, server_rec * s) @@ -710,11 +782,13 @@ waklog_create_server_config (MK_POOL * p, server_rec * s) cfg->path = "(server)"; cfg->protect = WAKLOG_UNSET; cfg->usertokens = WAKLOG_UNSET; - cfg->keytab = WAKLOG_UNSET; - cfg->principal = WAKLOG_UNSET; - cfg->default_principal = WAKLOG_UNSET; - cfg->default_keytab = WAKLOG_UNSET; - cfg->afs_cell = WAKLOG_UNSET; + cfg->disable_token_cache = WAKLOG_UNSET; + cfg->keytab = NULL; + cfg->principal = NULL; + cfg->default_principal = NULL; + cfg->default_keytab = NULL; + cfg->afs_cell = NULL; + cfg->afs_cell_realm = NULL; cfg->forked = 0; cfg->configured = 0; @@ -737,11 +811,13 @@ waklog_create_dir_config (MK_POOL * p, char *dir) cfg->path = ap_pstrdup(p, dir ); cfg->protect = WAKLOG_UNSET; cfg->usertokens = WAKLOG_UNSET; - cfg->keytab = WAKLOG_UNSET; - cfg->principal = WAKLOG_UNSET; - cfg->default_principal = WAKLOG_UNSET; - cfg->default_keytab = WAKLOG_UNSET; - cfg->afs_cell = WAKLOG_UNSET; + cfg->disable_token_cache = WAKLOG_UNSET; + cfg->keytab = NULL; + cfg->principal = NULL; + cfg->default_principal = NULL; + cfg->default_keytab = NULL; + cfg->afs_cell = NULL; + cfg->afs_cell_realm = NULL; cfg->forked = 0; cfg->configured = 0; @@ -756,19 +832,23 @@ static void *waklog_merge_dir_config(MK_POOL *p, void *parent_conf, void *newloc merged->protect = child->protect != WAKLOG_UNSET ? child->protect : parent->protect; - merged->path = child->path != WAKLOG_UNSET ? child->path : parent->path; + merged->path = child->path != NULL ? child->path : parent->path; merged->usertokens = child->usertokens != WAKLOG_UNSET ? child->usertokens : parent->usertokens; + + merged->disable_token_cache = child->disable_token_cache != WAKLOG_UNSET ? child->disable_token_cache : parent->disable_token_cache; - merged->principal = child->principal != WAKLOG_UNSET ? child->principal : parent->principal; + merged->principal = child->principal != NULL ? child->principal : parent->principal; - merged->keytab = child->keytab != WAKLOG_UNSET ? child->keytab : parent->keytab; + merged->keytab = child->keytab != NULL ? child->keytab : parent->keytab; - merged->default_keytab = child->default_keytab != WAKLOG_UNSET ? child->default_keytab : parent->default_keytab; + merged->default_keytab = child->default_keytab != NULL ? child->default_keytab : parent->default_keytab; - merged->default_principal = child->default_principal != WAKLOG_UNSET ? child->default_principal : parent->default_principal; + merged->default_principal = child->default_principal != NULL ? child->default_principal : parent->default_principal; - merged->afs_cell = child->afs_cell != WAKLOG_UNSET ? child->afs_cell : parent->afs_cell; + merged->afs_cell = child->afs_cell != NULL ? child->afs_cell : parent->afs_cell; + + merged->afs_cell_realm = child->afs_cell_realm != NULL ? child->afs_cell_realm : parent->afs_cell_realm; return (void *) merged; @@ -784,20 +864,25 @@ static void *waklog_merge_server_config(MK_POOL *p, void *parent_conf, void *new merged->usertokens = nconf->usertokens == WAKLOG_UNSET ? pconf->usertokens : nconf->usertokens; - merged->keytab = nconf->keytab == WAKLOG_UNSET ? ap_pstrdup(p, pconf->keytab) : - ( nconf->keytab == WAKLOG_UNSET ? WAKLOG_UNSET : ap_pstrdup(p, pconf->keytab) ); + merged->disable_token_cache = nconf->disable_token_cache == WAKLOG_UNSET ? pconf->disable_token_cache : nconf->disable_token_cache; + + merged->keytab = nconf->keytab == NULL ? ap_pstrdup(p, pconf->keytab) : + ( nconf->keytab == NULL ? NULL : ap_pstrdup(p, nconf->keytab) ); - merged->principal = nconf->principal == WAKLOG_UNSET ? ap_pstrdup(p, pconf->principal) : - ( nconf->principal == WAKLOG_UNSET ? WAKLOG_UNSET : ap_pstrdup(p, pconf->principal) ); + merged->principal = nconf->principal == NULL ? ap_pstrdup(p, pconf->principal) : + ( nconf->principal == NULL ? NULL : ap_pstrdup(p, nconf->principal) ); - merged->afs_cell = nconf->afs_cell == WAKLOG_UNSET ? ap_pstrdup(p, pconf->afs_cell) : - ( nconf->afs_cell == WAKLOG_UNSET ? WAKLOG_UNSET : ap_pstrdup(p, pconf->afs_cell) ); + merged->afs_cell = nconf->afs_cell == NULL ? ap_pstrdup(p, pconf->afs_cell) : + ( nconf->afs_cell == NULL ? NULL : ap_pstrdup(p, nconf->afs_cell) ); + + merged->afs_cell_realm = nconf->afs_cell_realm == NULL ? ap_pstrdup(p, pconf->afs_cell_realm) : + ( nconf->afs_cell_realm == NULL ? NULL : ap_pstrdup(p, nconf->afs_cell_realm) ); - merged->default_keytab = nconf->default_keytab == WAKLOG_UNSET ? ap_pstrdup(p, pconf->default_keytab) : - ( nconf->default_keytab == WAKLOG_UNSET ? WAKLOG_UNSET : ap_pstrdup(p, pconf->default_keytab) ); + merged->default_keytab = nconf->default_keytab == NULL ? ap_pstrdup(p, pconf->default_keytab) : + ( nconf->default_keytab == NULL ? NULL : ap_pstrdup(p, nconf->default_keytab) ); - merged->default_principal = nconf->default_principal == WAKLOG_UNSET ? ap_pstrdup(p, pconf->default_principal) : - ( nconf->default_principal == WAKLOG_UNSET ? WAKLOG_UNSET : ap_pstrdup(p, pconf->default_principal) ); + merged->default_principal = nconf->default_principal == NULL ? ap_pstrdup(p, pconf->default_principal) : + ( nconf->default_principal == NULL ? NULL : ap_pstrdup(p, nconf->default_principal) ); return (void *) merged; @@ -805,7 +890,7 @@ static void *waklog_merge_server_config(MK_POOL *p, void *parent_conf, void *new } static const char * -set_waklog_protect (cmd_parms * params, void *mconfig, int flag) +set_waklog_enabled (cmd_parms * params, void *mconfig, int flag) { waklog_config *cfg = mconfig ? ( waklog_config * ) mconfig : ( waklog_config * ) ap_get_module_config(params->server->module_config, &waklog_module ); @@ -813,7 +898,7 @@ set_waklog_protect (cmd_parms * params, void *mconfig, int flag) cfg->protect = flag; cfg->configured = 1; log_error (APLOG_MARK, APLOG_DEBUG, 0, params->server, - "mod_waklog: waklog_protect set on %s", cfg->path ? cfg->path : "NULL"); + "mod_waklog: waklog_enabled set on %s", cfg->path ? cfg->path : "NULL"); return (NULL); } @@ -847,7 +932,7 @@ void add_to_renewtable(MK_POOL *p, char *keytab, char *principal) { } static const char * -set_waklog_principal (cmd_parms *params, void *mconfig, char *principal, char *keytab) +set_waklog_location_principal (cmd_parms *params, void *mconfig, char *principal, char *keytab) { waklog_config *cfg = mconfig ? ( waklog_config * ) mconfig : ( waklog_config * ) ap_get_module_config(params->server->module_config, &waklog_module ); @@ -866,7 +951,7 @@ set_waklog_principal (cmd_parms *params, void *mconfig, char *principal, char *k } static const char * -set_waklog_use_afs_cell (cmd_parms * params, void *mconfig, char *file) +set_waklog_afs_cell (cmd_parms * params, void *mconfig, char *file) { waklog_config *waklog_mconfig = ( waklog_config * ) mconfig; waklog_config *waklog_srvconfig = @@ -875,16 +960,38 @@ set_waklog_use_afs_cell (cmd_parms * params, void *mconfig, char *file) log_error (APLOG_MARK, APLOG_INFO, 0, params->server, "mod_waklog: will use afs_cell: %s", file); + // Prefer afs/cell@REALM over afs@REALM, just like the OpenAFS tools + waklog_srvconfig->cell_in_principal = 1; + waklog_srvconfig->afs_cell = ap_pstrdup (params->pool, file); waklog_srvconfig->configured = 1; if (waklog_mconfig != NULL) { + waklog_mconfig->cell_in_principal = waklog_srvconfig->cell_in_principal; waklog_mconfig->afs_cell = ap_pstrdup (params->pool, file); waklog_mconfig->configured = 1; } return (NULL); } +static const char * +set_waklog_afs_cell_realm (cmd_parms * params, void *mconfig, char *file) +{ + waklog_config *waklog_mconfig = ( waklog_config * ) mconfig; + waklog_config *waklog_srvconfig = + ( waklog_config * ) ap_get_module_config(params->server->module_config, &waklog_module ); + + log_error (APLOG_MARK, APLOG_INFO, 0, params->server, + "mod_waklog: will use afs_cell_realm: %s", file); + + waklog_srvconfig->afs_cell_realm = ap_pstrdup (params->pool, file); + + if (waklog_mconfig != NULL) { + waklog_mconfig->afs_cell_realm = ap_pstrdup (params->pool, file); + } + return (NULL); +} + static const char * set_waklog_default_principal (cmd_parms * params, void *mconfig, char *principal, char *keytab) { @@ -931,6 +1038,22 @@ set_waklog_use_usertokens (cmd_parms * params, void *mconfig, int flag) } +static const char * +set_waklog_disable_token_cache (cmd_parms * params, void *mconfig, int flag) +{ + waklog_config *cfg = mconfig ? ( waklog_config * ) mconfig : + ( waklog_config * ) ap_get_module_config(params->server->module_config, &waklog_module ); + + cfg->disable_token_cache = flag; + + cfg->configured = 1; + + log_error (APLOG_MARK, APLOG_DEBUG, 0, params->server, + "mod_waklog: waklog_disable_token_cache set"); + return (NULL); +} + + #ifndef APACHE2 static void waklog_child_exit( server_rec *s, MK_POOL *p ) { #else @@ -984,21 +1107,21 @@ waklog_child_init (server_rec * s, MK_POOL * p) memset (&child, 0, sizeof(child)); - if ( code = krb5_init_context(&child.kcontext) ) { + if ( ( code = krb5_init_context(&child.kcontext) ) ) { log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: can't init kerberos context %d", code ); } - if ( code = krb5_cc_resolve(child.kcontext, "MEMORY:tmpcache", &child.ccache) ) { + if ( ( code = krb5_cc_resolve(child.kcontext, "MEMORY:tmpcache", &child.ccache) ) ) { log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: can't initialize in-memory credentials cache %d", code ); } if ( pag_for_children ) { - setpag (); + k_setpag (); } getModConfig (cfg, s); - if ( cfg->default_principal != WAKLOG_UNSET ) { + if ( cfg->default_principal != NULL ) { log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "mod_waklog: child_init setting default user %s, %s", cfg->default_principal, cfg->default_keytab); set_auth( s, NULL, 0, cfg->default_principal, cfg->default_keytab, 0); } @@ -1018,21 +1141,27 @@ waklog_child_init (server_rec * s, MK_POOL * p) command_rec waklog_cmds[] = { - command ("WaklogProtected", set_waklog_protect, 0, FLAG, - "enable waklog on a location or directory basis"), - - command ("WaklogPrincipal", set_waklog_principal, 0, TAKE2, - "Use the supplied keytab rather than the default"), + command ("WaklogAFSCell", set_waklog_afs_cell, 0, TAKE1, + "Use the supplied AFS cell (required)"), - command ("WaklogUseAFSCell", set_waklog_use_afs_cell, 0, TAKE1, - "Use the supplied AFS cell rather than the default"), + command ("WaklogAFSCellRealm", set_waklog_afs_cell_realm, 0, TAKE1, + "Assume that the AFS cell belongs to the specified Kerberos realm (optional)"), - command ("WaklogUseUserTokens", set_waklog_use_usertokens, 0, FLAG, - "Use the requesting user tokens (from webauth)"), + command ("WaklogEnabled", set_waklog_enabled, 0, FLAG, + "enable waklog on a server, location, or directory basis"), command ("WaklogDefaultPrincipal", set_waklog_default_principal, 0, TAKE2, - "Set the default principal that the server runs as"), - + "Set the default principal that the server runs as"), + + command ("WaklogLocationPrincipal", set_waklog_location_principal, 0, TAKE2, + "Set the principal on a -specific basis"), + + command ("WaklogDisableTokenCache", set_waklog_disable_token_cache, 0, FLAG, + "Ignore the token cache (location-specific); useful for scripts that need kerberos tickets."), + + command ("WaklogUseUserTokens", set_waklog_use_usertokens, 0, FLAG, + "Use the requesting user tokens (from webauth)"), + {NULL} }; @@ -1057,7 +1186,15 @@ token_cleanup (void *data) return 0; } +/* This function doesn't return anything but is passed to ap_bspawn_child on + * Apache 1 which expects it to return a pid as an int. For want of better + * understanding, err on the side of not changing Apache 1 code while fixing + * the compile warning on Apache 2. */ +#ifdef APACHE2 +static void +#else static int +#endif waklog_child_routine (void *data, child_info * pinfo) { int i; @@ -1075,18 +1212,22 @@ waklog_child_routine (void *data, child_info * pinfo) memset (&child, 0, sizeof(child)); - if ( code = krb5_init_context(&child.kcontext) ) { + if ( ( code = krb5_init_context(&child.kcontext) ) ) { log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: can't init kerberos context %d", code ); } - if ( code = krb5_cc_resolve(child.kcontext, "MEMORY:tmpcache", &child.ccache) ) { + if ( ( code = krb5_cc_resolve(child.kcontext, "MEMORY:tmpcache", &child.ccache) ) ) { log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: can't initialize in-memory credentials cache %d", code ); } + log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "mod_waklog: about to pr_Initialize"); + /* need to do this so we can make PTS calls */ cell = strdup(cfg->afs_cell); /* stupid */ pr_Initialize( 0, AFSDIR_CLIENT_ETC_DIR, cell ); - + + log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "mod_waklog: still here"); + while(1) { for ( i = 0; i < renewcount; ++i ) { @@ -1154,7 +1295,7 @@ waklog_init_handler (apr_pool_t * p, apr_pool_t * plog, if (cfg->afs_cell==NULL) { log_error (APLOG_MARK, APLOG_ERR, 0, s, - "mod_waklog: afs_cell==NULL; please provide the WaklogUseAFSCell directive"); + "mod_waklog: afs_cell==NULL; please provide the WaklogAFSCell directive"); /** clobber apache */ exit(-1); } @@ -1194,15 +1335,24 @@ waklog_init_handler (apr_pool_t * p, apr_pool_t * plog, struct sharedspace_s bob; log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: sizing our cache file %d to %d", fd, sizeof(struct sharedspace_s) ); memset( &bob, 0, sizeof(struct sharedspace_s)); - write(fd, &bob, sizeof(struct sharedspace_s)); + if ( write(fd, &bob, sizeof(struct sharedspace_s)) != sizeof(struct sharedspace_s) ) { + log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: failed to write to our cache file %s (%d)", cache_file, errno ); + exit(errno); + } log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: done sizing our cache file to %d", sizeof(struct sharedspace_s) ); } /* mmap the region */ if ( ( sharedspace = (struct sharedspace_s *) mmap ( NULL, sizeof(struct sharedspace_s), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0 ) ) != MAP_FAILED ) { + int err = 0; log_error( APLOG_MARK, APLOG_DEBUG, 0, s, "mod_waklog: shared mmap region ok %d", sharedspace ); - close(fd); + err = unlink(cache_file); + if (err) { + log_error( APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: unable to delete %s due to %d", cache_file, errno); + } else { + log_error( APLOG_MARK, APLOG_DEBUG, 0, s, "mod_waklog: shared cache unlinked (will be deleted when Apache quits)"); + } } else { log_error( APLOG_MARK, APLOG_DEBUG, 0, s, "mod_waklog: mmap failed %d", errno ); exit(errno); @@ -1215,7 +1365,7 @@ waklog_init_handler (apr_pool_t * p, apr_pool_t * plog, #define locktype rwlock_t #endif - if ( sharedlock = ( locktype * ) mmap ( NULL, sizeof(locktype), PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANON, -1, 0 ) ) { + if ( ( sharedlock = ( locktype * ) mmap ( NULL, sizeof(locktype), PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANON, -1, 0 ) ) != NULL ) { #ifndef use_pthreads rwlock_init(sharedlock, USYNC_PROCESS, NULL ); #else @@ -1255,7 +1405,7 @@ waklog_init_handler (apr_pool_t * p, apr_pool_t * plog, /* wait here until our child process has gone and done it's renewing thing. */ while( sharedspace->renewcount == oldrenewcount ) { log_error( APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: waiting for tokens..." ); - sleep(2); + apr_sleep(150000); } } @@ -1272,7 +1422,6 @@ waklog_init (server_rec * s, MK_POOL * p) extern char *version; int pid; waklog_config *cfg; - char *cell; int fd = -1; int use_existing = 1; int oldrenewcount; @@ -1316,7 +1465,7 @@ waklog_init (server_rec * s, MK_POOL * p) /* mmap the region */ - if ( ( sharedspace = (struct sharedspace_s *) mmap ( NULL, sizeof(struct sharedspace_s), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0 ) ) != -1 ) { + if ( ( sharedspace = (struct sharedspace_s *) mmap ( NULL, sizeof(struct sharedspace_s), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0 ) ) != (void *) -1 ) { log_error( APLOG_MARK, APLOG_DEBUG, 0, s, "mod_waklog: shared mmap region ok %d", sharedspace ); close(fd); } else { @@ -1332,7 +1481,7 @@ waklog_init (server_rec * s, MK_POOL * p) #endif /* mmap our shared space for our lock */ - if ( sharedlock = ( locktype * ) mmap ( NULL, sizeof(locktype), PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANON, -1, 0 ) ) { + if ( ( sharedlock = ( locktype * ) mmap ( NULL, sizeof(locktype), PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANON, -1, 0 ) ) ) { #ifndef use_pthreads rwlock_init(sharedlock, USYNC_PROCESS, NULL ); #else @@ -1387,13 +1536,19 @@ waklog_phase0 (request_rec * r) cfg = retrieve_config(r); - if ( cfg->protect && cfg->principal ) { + if ( get_cfg_protect(cfg) && cfg->principal ) { log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "mod_waklog: phase0 using user %s", cfg->principal); set_auth(r->server, r, 0, cfg->principal, cfg->keytab, 0); } else if ( cfg->default_principal ) { log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "mod_waklog: phase0 using default user %s", cfg->default_principal); set_auth(r->server, r, 0, cfg->default_principal, cfg->default_keytab, 0); } else { + + if (child.token.ticketLen) { + memset( &child.token, 0, sizeof (struct ktc_token) ); + ktc_ForgetAllTokens(); + } + log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "mod_waklog: phase0 not doing nothin."); } @@ -1410,7 +1565,7 @@ waklog_phase1 (request_rec * r) cfg = retrieve_config(r); - if ( cfg->protect && cfg->principal ) { + if ( get_cfg_protect(cfg) && cfg->principal ) { log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "mod_waklog: phase1 using user %s", cfg->principal); set_auth(r->server, r, 0, cfg->principal, cfg->keytab, 0); } else if ( cfg->default_principal ) { @@ -1433,7 +1588,7 @@ waklog_phase3 (request_rec * r) cfg = retrieve_config(r); - if ( cfg->protect && cfg->principal ) { + if ( get_cfg_protect(cfg) && cfg->principal ) { log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "mod_waklog: phase3 using user %s", cfg->principal); set_auth(r->server, r, 0, cfg->principal, cfg->keytab, 0); } else if ( cfg->default_principal ) { @@ -1456,7 +1611,7 @@ waklog_phase6 (request_rec * r) cfg = retrieve_config(r); - if ( cfg->protect && cfg->principal ) { + if ( get_cfg_protect(cfg) && cfg->principal ) { log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "mod_waklog: phase6 using user %s", cfg->principal); set_auth(r->server, r, 0, cfg->principal, cfg->keytab, 0); } else if ( cfg->default_principal ) { @@ -1480,15 +1635,21 @@ waklog_phase7 (request_rec * r) cfg = retrieve_config (r); - if ( cfg->protect && cfg->usertokens ) { + if ( get_cfg_protect(cfg) && get_cfg_usertokens(cfg) ) { log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "mod_waklog: phase7 using usertokens"); rc = set_auth( r->server, r, 1, NULL, NULL, 0); - } else if ( cfg->protect && cfg->principal ) { + } else if ( get_cfg_protect(cfg) && cfg->principal ) { log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "mod_waklog: phase7 using user %s", cfg->principal); rc = set_auth( r->server, r, 0, cfg->principal, cfg->keytab, 0); } else if ( cfg->default_principal ) { log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "mod_waklog: phase7 using default user %s", cfg->default_principal); rc = set_auth( r->server, r, 0, cfg->default_principal, cfg->default_keytab, 0); + } else { + log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "mod_waklog: no tokens"); + if (child.token.ticketLen) { + memset(&child.token, 0, sizeof(struct ktc_token)); + ktc_ForgetAllTokens(); + } } if ( rc ) { @@ -1602,7 +1763,7 @@ module MODULE_VAR_EXPORT waklog_module = { waklog_phase6, /* [#6] determine MIME type */ waklog_phase7, /* [#7] pre-run fixups */ waklog_phase9, /* [#9] log a transaction */ - NULL, /* [#2] header parser */ + waklog_phase2, /* [#2] header parser */ waklog_child_init, /* child_init */ waklog_child_exit, /* child_exit */ waklog_phase0 /* [#0] post read-request */