X-Git-Url: http://git.hcoop.net/hcoop/debian/libapache-mod-waklog.git/blobdiff_plain/7193eb01f9a9f97a71c55b1c60571d10dfc82d22..bd173fe7d3bc057e7ddb1be054aa843ad6c5351d:/mod_waklog.c diff --git a/mod_waklog.c b/mod_waklog.c index 5da9a1e..5fb26a1 100644 --- a/mod_waklog.c +++ b/mod_waklog.c @@ -12,54 +12,37 @@ #include #endif /* sun */ #include -#include -#include #include #include #include -#include -#include +#define KEYTAB "/home/drh/keytab.itdwww" +#define KEYTAB_PRINCIPAL "itdwww" -#define KEYTAB_PATH "/home/drh/keytab.umweb.drhtest" -#define PRINCIPAL "umweb/drhtest" -#define AFS "afs" -#define IN_TKT_SERVICE "krbtgt/UMICH.EDU" +#define TKT_LIFE 10*60*60 +#define SLEEP_TIME TKT_LIFE - 5*60 -#define K5PATH "FILE:/tmp/waklog.creds.k5" -#define K4PATH "/tmp/waklog.creds.k4" +#define AFS_CELL "umich.edu" /* NB: lower case */ -module waklog_module; +#define K5PATH "FILE:/tmp/waklog.creds.k5" +#define K4PATH "/tmp/waklog.creds.k4" -struct ClearToken { - long AuthHandle; - char HandShakeKey[ 8 ]; - long ViceId; - long BeginTimestamp; - long EndTimestamp; -}; +module waklog_module; typedef struct { int configured; int protect; char *keytab; char *keytab_principal; - char *afs_instance; + char *afs_cell; } waklog_host_config; -typedef struct { - krb5_timestamp endtime; /* time krbtgt expires */ - int getting_tgt; /* TAS flag, protecting above */ -} waklog_mod_config; -waklog_mod_config *mod = NULL; - -int shmid = -1; - typedef struct { struct ktc_token token; } waklog_child_config; -waklog_child_config *child = NULL; +waklog_child_config child; +#if 0 static void * waklog_create_dir_config( pool *p, char *path ) { @@ -68,12 +51,13 @@ waklog_create_dir_config( pool *p, char *path ) cfg = (waklog_host_config *)ap_pcalloc( p, sizeof( waklog_host_config )); cfg->configured = 0; cfg->protect = 0; - cfg->keytab = 0; - cfg->keytab_principal = 0; - cfg->afs_instance = 0; + cfg->keytab = KEYTAB; + cfg->keytab_principal = KEYTAB_PRINCIPAL; + cfg->afs_cell = AFS_CELL; return( cfg ); } +#endif /* 0 */ static void * @@ -84,109 +68,110 @@ waklog_create_server_config( pool *p, server_rec *s ) cfg = (waklog_host_config *)ap_pcalloc( p, sizeof( waklog_host_config )); cfg->configured = 0; cfg->protect = 0; - cfg->keytab = 0; - cfg->keytab_principal = 0; - cfg->afs_instance = 0; + cfg->keytab = KEYTAB; + cfg->keytab_principal = KEYTAB_PRINCIPAL; + cfg->afs_cell = AFS_CELL; + +#if 0 + ap_set_module_config( s->module_config, &waklog_module, cfg); +#endif /* 0 */ return( cfg ); } - static void -waklog_init( server_rec *s, pool *p ) + static const char * +set_waklog_protect( cmd_parms *params, void *mconfig, int flag ) { - extern char *version; - static key_t shmkey = IPC_PRIVATE; - struct shmid_ds shmbuf; + waklog_host_config *cfg; - ap_log_error( APLOG_MARK, APLOG_INFO|APLOG_NOERRNO, s, - "mod_waklog: version %s initialized.", version ); +#if 0 + if ( params->path == NULL ) { +#endif /* 0 */ + cfg = (waklog_host_config *) ap_get_module_config( + params->server->module_config, &waklog_module ); +#if 0 + } else { + cfg = (waklog_host_config *)mconfig; + } +#endif /* 0 */ - if ( mod == NULL ) { - if (( shmid = shmget( shmkey, sizeof( waklog_mod_config ), - IPC_CREAT | SHM_R | SHM_W )) == -1 ) { - ap_log_error( APLOG_MARK, APLOG_ERR, s, - "mod_waklog: shmget failed" ); - exit ( -1 ); - } + cfg->protect = flag; + cfg->configured = 1; + return( NULL ); +} - ap_log_error( APLOG_MARK, APLOG_INFO|APLOG_NOERRNO, s, - "mod_waklog: waklog_init: created shared memory segment %d", shmid ); - - if (( mod = (waklog_mod_config *) shmat( shmid, 0, 0 ) ) == - (waklog_mod_config *) -1 ) { - ap_log_error( APLOG_MARK, APLOG_ERR, s, - "mod_waklog: shmat failed" ); - /* we'll exit after removing the segment */ - - } else { - if ( shmctl( shmid, IPC_STAT, &shmbuf ) != 0 ) { - ap_log_error( APLOG_MARK, APLOG_ERR, s, - "mod_waklog: shmctl failed to stat" ); - - } else { - shmbuf.shm_perm.uid = ap_user_id; - shmbuf.shm_perm.gid = ap_group_id; - - if ( shmctl( shmid, IPC_SET, &shmbuf ) != 0 ) { - ap_log_error( APLOG_MARK, APLOG_ERR, s, - "mod_waklog: shmctl failed to set" ); - } - } - - } - if ( shmctl( shmid, IPC_RMID, NULL ) != 0 ) { - ap_log_error( APLOG_MARK, APLOG_ERR, s, - "mod_waklog: shmctl failed to remove" ); - } + static const char * +set_waklog_use_keytab( cmd_parms *params, void *mconfig, char *file ) +{ + waklog_host_config *cfg; - if ( mod == (waklog_mod_config *) -1 ) { - exit ( -1 ); - } +#if 0 + if ( params->path == NULL ) { +#endif /* 0 */ + cfg = (waklog_host_config *) ap_get_module_config( + params->server->module_config, &waklog_module ); +#if 0 + } else { + cfg = (waklog_host_config *)mconfig; } +#endif /* 0 */ - mod->endtime = 0; - mod->getting_tgt = 0; + ap_log_error( APLOG_MARK, APLOG_INFO|APLOG_NOERRNO, params->server, + "mod_waklog: will use keytab: %s", file ); - return; + cfg->keytab = ap_pstrdup ( params->pool, file ); + cfg->configured = 1; + return( NULL ); } static const char * -set_waklog_protect( cmd_parms *params, void *mconfig, int flag ) +set_waklog_use_keytab_principal( cmd_parms *params, void *mconfig, char *file ) { waklog_host_config *cfg; +#if 0 if ( params->path == NULL ) { +#endif /* 0 */ cfg = (waklog_host_config *) ap_get_module_config( params->server->module_config, &waklog_module ); +#if 0 } else { cfg = (waklog_host_config *)mconfig; } +#endif /* 0 */ - cfg->protect = flag; + ap_log_error( APLOG_MARK, APLOG_INFO|APLOG_NOERRNO, params->server, + "mod_waklog: will use keytab_principal: %s", file ); + + cfg->keytab_principal = ap_pstrdup ( params->pool, file ); cfg->configured = 1; return( NULL ); } static const char * -set_waklog_use_keytab( cmd_parms *params, void *mconfig, char *file ) +set_waklog_use_afs_cell( cmd_parms *params, void *mconfig, char *file ) { waklog_host_config *cfg; +#if 0 if ( params->path == NULL ) { +#endif /* 0 */ cfg = (waklog_host_config *) ap_get_module_config( params->server->module_config, &waklog_module ); +#if 0 } else { cfg = (waklog_host_config *)mconfig; } +#endif /* 0 */ ap_log_error( APLOG_MARK, APLOG_INFO|APLOG_NOERRNO, params->server, - "mod_waklog: using keytab: %s", file ); + "mod_waklog: will use afs_cell: %s", file ); - cfg->keytab = file; + cfg->afs_cell = ap_pstrdup( params->pool, file ); cfg->configured = 1; return( NULL ); } @@ -196,17 +181,10 @@ set_waklog_use_keytab( cmd_parms *params, void *mconfig, char *file ) waklog_child_init( server_rec *s, pool *p ) { - if ( child == NULL ) { - child = (waklog_child_config *) ap_palloc( p, sizeof( waklog_child_config ) ); - } - - memset( &child->token, 0, sizeof( struct ktc_token ) ); + memset( &child.token, 0, sizeof( struct ktc_token ) ); setpag(); - ap_log_error( APLOG_MARK, APLOG_INFO|APLOG_NOERRNO, s, - "mod_waklog: waklog_child_init: child: 0x%08x", child ); - return; } @@ -217,230 +195,201 @@ command_rec waklog_cmds[ ] = NULL, RSRC_CONF | ACCESS_CONF, FLAG, "enable waklog on a location or directory basis" }, - { "WaklogUseKeytab", set_waklog_use_keytab, - NULL, RSRC_CONF, TAKE1, - "Use the supplied keytab file rather than the user's TGT" }, + { "WaklogUseKeytabPath", set_waklog_use_keytab, + NULL, RSRC_CONF | ACCESS_CONF, TAKE1, + "Use the supplied keytab rather than the default" }, + + { "WaklogUseKeytabPrincipal", set_waklog_use_keytab_principal, + NULL, RSRC_CONF | ACCESS_CONF, TAKE1, + "Use the supplied keytab principal rather than the default" }, + + { "WaklogUseAFSCell", set_waklog_use_afs_cell, + NULL, RSRC_CONF | ACCESS_CONF, TAKE1, + "Use the supplied AFS cell rather than the default" }, { NULL } }; static void -pioctl_cleanup( void *data ) +token_cleanup( void *data ) { request_rec *r = (request_rec *)data; - if ( child->token.ticketLen ) { - memset( &child->token, 0, sizeof( struct ktc_token ) ); + if ( child.token.ticketLen ) { + memset( &child.token, 0, sizeof( struct ktc_token ) ); ktc_ForgetAllTokens(); ap_log_error( APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r->server, - "mod_waklog: ktc_ForgetAllTokens succeeded" ); + "mod_waklog: ktc_ForgetAllTokens succeeded: pid: %d", getpid() ); } return; } static int -waklog_ktinit( request_rec *r, char *keytab_path ) +waklog_kinit( server_rec *s ) { krb5_error_code kerror; - krb5_context kcontext; - krb5_principal kprinc; + krb5_context kcontext = NULL; + krb5_principal kprinc = NULL; krb5_get_init_creds_opt kopts; krb5_creds v5creds; - CREDENTIALS v4creds; - krb5_ccache kccache; - krb5_keytab keytab = 0; + krb5_ccache kccache = NULL; + krb5_keytab keytab = NULL; char ktbuf[ MAX_KEYTAB_NAME_LEN + 1 ]; - krb5_timestamp now; + waklog_host_config *cfg; + int i; - ap_log_error( APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r->server, - "mod_waklog: waklog_ktinit called" ); + ap_log_error( APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, s, + "mod_waklog: waklog_kinit called: pid: %d", getpid() ); - /* set our environment variables */ - ap_table_set( r->subprocess_env, "KRB5CCNAME", K5PATH ); - ap_table_set( r->subprocess_env, "KRBTKFILE", K4PATH ); + cfg = (waklog_host_config *) ap_get_module_config( s->module_config, + &waklog_module ); - ap_log_error( APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r->server, - "mod_waklog: KRB5CCNAME: %s, KRBTKFILE: %s", K5PATH, K4PATH ); + if (( kerror = krb5_init_context( &kcontext ))) { + ap_log_error( APLOG_MARK, APLOG_ERR, s, + (char *)error_message( kerror )); -#define SOON 300 + goto cleanup; + } - /* will we need another tgt soon? */ - now = time( NULL ); - if ( !mod->getting_tgt && mod->endtime < now + SOON ) { + /* use the path */ + if (( kerror = krb5_cc_resolve( kcontext, K5PATH, &kccache )) != 0 ) { + ap_log_error( APLOG_MARK, APLOG_ERR, s, + (char *)error_message( kerror )); - ap_log_error( APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r->server, - "mod_waklog: mod->endtime: %u, now: %u", mod->endtime, now ); + goto cleanup; + } - /* - ** Only one process will get into the critical region below and - ** replace the soon-to-be-expired credential; the rest will just - ** use the still-good credential until the new one shows up. - ** - ** The TAS flag will stop other processes from entering the - ** first half of the conditional above, and the critical region - ** below will not exit until mod->endtime has been updated to - ** reflect that of the new credentials (or fail). - ** - ** (While it is possible for all child processes to get past the - ** first half of the conditional above, and then for one - ** process to get into the critical region below and run to the - ** end (clearing the TAS flag), a fair scheduler would not - ** do this; but even so, it really wouldn't kill us if ALL of - ** the child processes got credentials, anyway. - */ - if ( !test_and_set_bit( 0, &mod->getting_tgt ) ) { + ap_log_error( APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, s, + "mod_waklog: keytab_principal: %s", cfg->keytab_principal ); - if (( kerror = krb5_init_context( &kcontext ))) { - ap_log_error( APLOG_MARK, APLOG_ERR, r->server, - (char *)error_message( kerror )); + if (( kerror = krb5_parse_name( kcontext, cfg->keytab_principal, &kprinc ))) { + ap_log_error( APLOG_MARK, APLOG_ERR, s, + (char *)error_message( kerror )); - goto cleanup1; - } + goto cleanup; + } - /* use the path */ - if (( kerror = krb5_cc_resolve( kcontext, K5PATH, &kccache )) != 0 ) { - ap_log_error( APLOG_MARK, APLOG_ERR, r->server, - (char *)error_message( kerror )); +#if 0 + ap_log_error( APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, s, + "mod_waklog: kprinc->realm: %.*s", kprinc->realm.length, kprinc->realm.data ); - goto cleanup2; - } + ap_log_error( APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, s, + "mod_waklog: kprinc->length: %d", kprinc->length ); + for ( i = 0; i < kprinc->length; i++ ) { + ap_log_error( APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, s, + "mod_waklog: kprinc->data[%d].data: %.*s", i, kprinc->data[i].length, kprinc->data[i].data ); + } +#endif /* 0 */ - if (( kerror = krb5_parse_name( kcontext, PRINCIPAL, &kprinc ))) { - ap_log_error( APLOG_MARK, APLOG_ERR, r->server, - (char *)error_message( kerror )); - - goto cleanup3; - } + krb5_get_init_creds_opt_init( &kopts ); + krb5_get_init_creds_opt_set_tkt_life( &kopts, TKT_LIFE ); + krb5_get_init_creds_opt_set_renew_life( &kopts, 0 ); + krb5_get_init_creds_opt_set_forwardable( &kopts, 1 ); + krb5_get_init_creds_opt_set_proxiable( &kopts, 0 ); - krb5_get_init_creds_opt_init( &kopts ); - krb5_get_init_creds_opt_set_tkt_life( &kopts, 10*60*60 ); - krb5_get_init_creds_opt_set_renew_life( &kopts, 0 ); - krb5_get_init_creds_opt_set_forwardable( &kopts, 1 ); - krb5_get_init_creds_opt_set_proxiable( &kopts, 0 ); + /* keytab from config */ + strncpy( ktbuf, cfg->keytab, sizeof( ktbuf ) - 1 ); - /* which keytab should we use? */ - strcpy( ktbuf, keytab_path ? keytab_path : KEYTAB_PATH ); - - if ( strlen( ktbuf ) > MAX_KEYTAB_NAME_LEN ) { - ap_log_error( APLOG_MARK, APLOG_ERR, r->server, - "server configuration error" ); - - goto cleanup4; - } - - ap_log_error( APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r->server, - "mod_waklog: waklog_ktinit using: %s", ktbuf ); - - if (( kerror = krb5_kt_resolve( kcontext, ktbuf, &keytab )) != 0 ) { - ap_log_error( APLOG_MARK, APLOG_ERR, r->server, - (char *)error_message( kerror )); - - goto cleanup4; - } - - /* get the krbtgt */ - if (( kerror = krb5_get_init_creds_keytab( kcontext, &v5creds, - kprinc, keytab, 0, IN_TKT_SERVICE, &kopts ))) { - - ap_log_error( APLOG_MARK, APLOG_ERR, r->server, - (char *)error_message( kerror )); - - goto cleanup5; - } - - if (( kerror = krb5_verify_init_creds( kcontext, &v5creds, - kprinc, keytab, NULL, NULL )) != 0 ) { - - ap_log_error( APLOG_MARK, APLOG_ERR, r->server, - (char *)error_message( kerror )); - - goto cleanup6; - } - - if (( kerror = krb5_cc_initialize( kcontext, kccache, kprinc )) != 0 ) { - ap_log_error( APLOG_MARK, APLOG_ERR, r->server, - (char *)error_message( kerror )); - - goto cleanup6; - } - - if (( kerror = krb5_cc_store_cred( kcontext, kccache, &v5creds )) != 0 ) { - ap_log_error( APLOG_MARK, APLOG_ERR, r->server, - (char *)error_message( kerror )); - - goto cleanup6; - } - - /* convert K5 => K4 */ - ap_log_error( APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r->server, - "mod_waklog: before krb524_convert_creds" ); - - if (( kerror = krb524_convert_creds_kdc( kcontext, - &v5creds, &v4creds )) != 0 ) { + ap_log_error( APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, s, + "mod_waklog: waklog_kinit using: %s", ktbuf ); - ap_log_error( APLOG_MARK, APLOG_ERR, r->server, - (char *)error_message( kerror )); + if (( kerror = krb5_kt_resolve( kcontext, ktbuf, &keytab )) != 0 ) { + ap_log_error( APLOG_MARK, APLOG_ERR, s, + (char *)error_message( kerror )); - goto cleanup6; - } + goto cleanup; + } - /* use the path */ - krb_set_tkt_string( (char *)K4PATH ); + memset( (char *)&v5creds, 0, sizeof(v5creds)); - /* initialize ticket cache */ - ap_log_error( APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r->server, - "mod_waklog: before in_tkt" ); + /* get the krbtgt */ + if (( kerror = krb5_get_init_creds_keytab( kcontext, &v5creds, + kprinc, keytab, 0, NULL, &kopts ))) { - if (( kerror = in_tkt( v4creds.pname, v4creds.pinst )) != KSUCCESS ) { - ap_log_error( APLOG_MARK, APLOG_ERR, r->server, - (char *)error_message( kerror )); + ap_log_error( APLOG_MARK, APLOG_ERR, s, + (char *)error_message( kerror )); - goto cleanup6; - } + goto cleanup; + } - /* stash, ticket, session key, etc for future use */ - ap_log_error( APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r->server, - "mod_waklog: before krb_save_credentials" ); +#if 0 + ap_log_error( APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, s, + "mod_waklog: v5creds.client->realm: %.*s", v5creds.client->realm.length, v5creds.client->realm.data ); - if (( kerror = krb_save_credentials( v4creds.service, - v4creds.instance, - v4creds.realm, - v4creds.session, - v4creds.lifetime, - v4creds.kvno, - &(v4creds.ticket_st), - v4creds.issue_date )) != 0 ) { + ap_log_error( APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, s, + "mod_waklog: v5creds.client->length: %d", v5creds.client->length ); + for ( i = 0; i < v5creds.client->length; i++ ) { + ap_log_error( APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, s, + "mod_waklog: v5creds.client->data[%d].data: %.*s", + i, v5creds.client->data[i].length, v5creds.client->data[i].data ); + } - ap_log_error( APLOG_MARK, APLOG_ERR, r->server, - (char *)error_message( kerror )); + ap_log_error( APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, s, + "mod_waklog: v5creds.server->realm: %.*s", v5creds.server->realm.length, v5creds.server->realm.data ); - goto cleanup6; - } + ap_log_error( APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, s, + "mod_waklog: v5creds.server->length: %d", v5creds.server->length ); + for ( i = 0; i < v5creds.server->length; i++ ) { + ap_log_error( APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, s, + "mod_waklog: v5creds.server->data[%d].data: %.*s", + i, v5creds.server->data[i].length, v5creds.server->data[i].data ); + } - /* save this */ - mod->endtime = v5creds.times.endtime; - ap_log_error( APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r->server, - "mod_waklog: mod->endtime: %u, mod->getting_tgt: %d", - mod->endtime, mod->getting_tgt ); + ap_log_error( APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, s, + "mod_waklog: waklog_kinit #4" ); -cleanup6: krb5_free_cred_contents( kcontext, &v5creds ); -cleanup5: (void)krb5_kt_close( kcontext, keytab ); -cleanup4: krb5_free_principal( kcontext, kprinc ); -cleanup3: krb5_cc_close( kcontext, kccache ); -cleanup2: krb5_free_context( kcontext ); + ap_log_error( APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, s, + "mod_waklog: waklog_kinit kprinc==v5creds.server: %s", + krb5_principal_compare( kcontext, kprinc, v5creds.server ) ? "true" : "false" ); +#endif /* 0 */ - /* exit the critical region */ -cleanup1: mod->getting_tgt = 0; - } +#if 0 +#error the proof of the pudding is in the eating + if (( kerror = krb5_verify_init_creds( kcontext, &v5creds, + v5creds.server, keytab, NULL, &vopts )) != 0 ) { + ap_log_error( APLOG_MARK, APLOG_ERR, s, + (char *)error_message( kerror )); + + goto cleanup; } +#endif /* 0 */ - ap_log_error( APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r->server, - "mod_waklog: waklog_ktinit: exiting" ); + if (( kerror = krb5_cc_initialize( kcontext, kccache, kprinc )) != 0 ) { + ap_log_error( APLOG_MARK, APLOG_ERR, s, + (char *)error_message( kerror )); + + goto cleanup; + } + + kerror = krb5_cc_store_cred( kcontext, kccache, &v5creds ); + krb5_free_cred_contents( kcontext, &v5creds ); + if ( kerror != 0 ) { + ap_log_error( APLOG_MARK, APLOG_ERR, s, + (char *)error_message( kerror )); + + goto cleanup; + } + + ap_log_error( APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, s, + "mod_waklog: waklog_kinit success" ); + +cleanup: + if ( keytab ) + (void)krb5_kt_close( kcontext, keytab ); + if ( kprinc ) + krb5_free_principal( kcontext, kprinc ); + if ( kccache ) + krb5_cc_close( kcontext, kccache ); + if ( kcontext ) + krb5_free_context( kcontext ); + + ap_log_error( APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, s, + "mod_waklog: waklog_kinit: exiting" ); return( 0 ); } @@ -450,18 +399,19 @@ cleanup1: mod->getting_tgt = 0; waklog_aklog( request_rec *r ) { int rc; - char buf[ 1024 ]; + char buf[ MAXKTCTICKETLEN ]; const char *k4path = NULL; const char *k5path = NULL; krb5_error_code kerror; - krb5_context kcontext; + krb5_context kcontext = NULL; krb5_creds increds; krb5_creds *v5credsp = NULL; - CREDENTIALS v4creds; - krb5_ccache kccache; - struct ktc_principal server = { "afs", "", "umich.edu" }; + krb5_ccache kccache = NULL; + struct ktc_principal server = { "afs", "", "" }; struct ktc_principal client; struct ktc_token token; + waklog_host_config *cfg; + int buflen; k5path = ap_table_get( r->subprocess_env, "KRB5CCNAME" ); k4path = ap_table_get( r->subprocess_env, "KRBTKFILE" ); @@ -472,7 +422,7 @@ waklog_aklog( request_rec *r ) if ( !k5path || !k4path ) { ap_log_error( APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r->server, "mod_waklog: waklog_aklog giving up" ); - return; + goto cleanup; } /* @@ -484,24 +434,34 @@ waklog_aklog( request_rec *r ) ap_log_error( APLOG_MARK, APLOG_ERR, r->server, (char *)error_message( kerror )); - return; + goto cleanup; } memset( (char *)&increds, 0, sizeof(increds)); + cfg = (waklog_host_config *) ap_get_module_config( + r->server->module_config, &waklog_module ); + + /* afs/ or afs */ + strncpy( buf, "afs", sizeof( buf ) - 1 ); + if ( strcmp( cfg->afs_cell, AFS_CELL ) ) { + strncat( buf, "/" , sizeof( buf ) - strlen( buf ) - 1 ); + strncat( buf, cfg->afs_cell, sizeof( buf ) - strlen( buf ) - 1 ); + } + /* set server part */ - if (( kerror = krb5_parse_name( kcontext, AFS, &increds.server ))) { + if (( kerror = krb5_parse_name( kcontext, buf, &increds.server ))) { ap_log_error( APLOG_MARK, APLOG_ERR, r->server, (char *)error_message( kerror )); - return; + goto cleanup; } if (( kerror = krb5_cc_resolve( kcontext, k5path, &kccache )) != 0 ) { ap_log_error( APLOG_MARK, APLOG_ERR, r->server, (char *)error_message( kerror )); - return; + goto cleanup; } /* set client part */ @@ -514,55 +474,60 @@ waklog_aklog( request_rec *r ) /* get the V5 credentials */ if (( kerror = krb5_get_credentials( kcontext, 0, kccache, &increds, &v5credsp ) ) ) { - ap_log_error( APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r->server, - "mod_waklog: krb5_get_credentials: %s", krb_err_txt[ kerror ] ); - return; + ap_log_error( APLOG_MARK, APLOG_ERR, r->server, + "mod_waklog: krb5_get_credentials: %s", error_message( kerror )); + goto cleanup; } - /* get the V4 credentials */ - if (( kerror = krb524_convert_creds_kdc( kcontext, v5credsp, &v4creds ) ) ) { - ap_log_error( APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r->server, - "mod_waklog: krb524_convert_creds_kdc: %s", krb_err_txt[ kerror ] ); - return; + /* don't overflow */ + if ( v5credsp->ticket.length >= MAXKTCTICKETLEN ) { /* from krb524d.c */ + ap_log_error( APLOG_MARK, APLOG_ERR, r->server, + "mod_waklog: ticket size (%d) too big to fake", v5credsp->ticket.length ); + goto cleanup; } /* assemble the token */ - token.kvno = v4creds.kvno; - token.startTime = v4creds.issue_date; + memset( &token, 0, sizeof( struct ktc_token ) ); + + token.startTime = v5credsp->times.starttime ? v5credsp->times.starttime : v5credsp->times.authtime; token.endTime = v5credsp->times.endtime; - memmove( &token.sessionKey, v4creds.session, 8 ); - token.ticketLen = v4creds.ticket_st.length ; - memmove( token.ticket, v4creds.ticket_st.dat, token.ticketLen ); + memmove( &token.sessionKey, v5credsp->keyblock.contents, v5credsp->keyblock.length ); + token.kvno = RXKAD_TKT_TYPE_KERBEROS_V5; + token.ticketLen = v5credsp->ticket.length; + memmove( token.ticket, v5credsp->ticket.data, token.ticketLen ); /* make sure we have to do this */ - if ( child->token.kvno != token.kvno || - child->token.ticketLen != token.ticketLen || - memcmp( &child->token.sessionKey, &token.sessionKey, - sizeof( token.sessionKey ) ) || - memcmp( child->token.ticket, token.ticket, token.ticketLen ) ) { + if ( child.token.kvno != token.kvno || + child.token.ticketLen != token.ticketLen || + (memcmp( &child.token.sessionKey, &token.sessionKey, + sizeof( token.sessionKey ) )) || + (memcmp( child.token.ticket, token.ticket, token.ticketLen )) ) { ap_log_error( APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r->server, - "mod_waklog: %s.%s@%s", v4creds.service, v4creds.instance, - v4creds.realm ); - ap_log_error( APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r->server, - "mod_waklog: %d %d %d", v4creds.lifetime, v4creds.kvno, - v4creds.issue_date ); - ap_log_error( APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r->server, - "mod_waklog: %s %s", v4creds.pname, v4creds.pinst ); - ap_log_error( APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r->server, - "mod_waklog: %d", v4creds.ticket_st.length ); + "mod_waklog: client: %s", buf ); /* build the name */ - strcpy( buf, v4creds.pname ); - if ( v4creds.pinst[ 0 ] ) { - strcat( buf, "." ); - strcat( buf, v4creds.pinst ); + memmove( buf, v5credsp->client->data[0].data, + min( v5credsp->client->data[0].length, MAXKTCNAMELEN - 1 ) ); + buf[ v5credsp->client->data[0].length ] = '\0'; + if ( v5credsp->client->length > 1 ) { + strncat( buf, ".", sizeof( buf ) - strlen( buf ) - 1 ); + buflen = strlen( buf ); + memmove( buf + buflen, v5credsp->client->data[1].data, + min( v5credsp->client->data[1].length, MAXKTCNAMELEN - strlen( buf ) - 1 ) ); + buf[ buflen + v5credsp->client->data[1].length ] = '\0'; } /* assemble the client */ - strncpy( client.name, buf, MAXKTCNAMELEN - 1 ); - strcpy( client.instance, "" ); - strncpy( client.cell, v4creds.realm, MAXKTCNAMELEN - 1 ); + strncpy( client.name, buf, sizeof( client.name ) - 1 ); + strncpy( client.instance, "", sizeof( client.instance) - 1 ); + memmove( buf, v5credsp->client->realm.data, + min( v5credsp->client->realm.length, MAXKTCNAMELEN - 1 ) ); + buf[ v5credsp->client->realm.length ] = '\0'; + strncpy( client.cell, buf, sizeof( client.cell ) - 1 ); + + /* assemble the server's cell */ + strncpy( server.cell, cfg->afs_cell , sizeof( server.cell ) - 1 ); ap_log_error( APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r->server, "mod_waklog: server: name=%s, instance=%s, cell=%s", @@ -579,25 +544,71 @@ waklog_aklog( request_rec *r ) write( 2, "", 0 ); if ( ( rc = ktc_SetToken( &server, &token, &client, 0 ) ) ) { - ap_log_error( APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r->server, + ap_log_error( APLOG_MARK, APLOG_ERR, r->server, "mod_waklog: settoken returned %d", rc ); + goto cleanup; } /* save this */ - memmove( &child->token, &token, sizeof( struct ktc_token ) ); + memmove( &child.token, &token, sizeof( struct ktc_token ) ); /* we'll need to unlog when this connection is done. */ - ap_register_cleanup( r->pool, (void *)r, pioctl_cleanup, ap_null_cleanup ); + ap_register_cleanup( r->pool, (void *)r, token_cleanup, ap_null_cleanup ); } - krb5_free_cred_contents( kcontext, v5credsp ); - krb5_free_principal( kcontext, increds.client ); - krb5_cc_close( kcontext, kccache ); - krb5_free_context( kcontext ); +cleanup: + if ( v5credsp ) + krb5_free_cred_contents( kcontext, v5credsp ); + if ( increds.client ) + krb5_free_principal( kcontext, increds.client ); + if ( increds.server ) + krb5_free_principal( kcontext, increds.server ); + if ( kccache ) + krb5_cc_close( kcontext, kccache ); + if ( kcontext ) + krb5_free_context( kcontext ); ap_log_error( APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r->server, "mod_waklog: finished with waklog_aklog" ); + return; + +} + + static int +waklog_child_routine( void *s, child_info *pinfo ) +{ + if ( !getuid() ) { + ap_log_error( APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, s, + "mod_waklog: waklog_child_routine called as root" ); + + /* this was causing the credential file to get owned by root */ + setgid(ap_group_id); + setuid(ap_user_id); + } + + while( 1 ) { + waklog_kinit( s ); + sleep( SLEEP_TIME ); + } + +} + + + static void +waklog_init( server_rec *s, pool *p ) +{ + extern char *version; + int pid; + + ap_log_error( APLOG_MARK, APLOG_INFO|APLOG_NOERRNO, s, + "mod_waklog: version %s initialized.", version ); + + pid = ap_bspawn_child( p, waklog_child_routine, s, kill_always, + NULL, NULL, NULL ); + + ap_log_error( APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, s, + "mod_waklog: ap_bspawn_child: %d.", pid ); } @@ -609,15 +620,20 @@ waklog_phase0( request_rec *r ) ap_log_error( APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r->server, "mod_waklog: phase0 called" ); +#if 0 /* directory config? */ cfg = (waklog_host_config *)ap_get_module_config( r->per_dir_config, &waklog_module); + /* server config? */ if ( !cfg->configured ) { +#endif /* 0 */ cfg = (waklog_host_config *)ap_get_module_config( r->server->module_config, &waklog_module); +#if 0 } +#endif /* 0 */ if ( !cfg->protect ) { ap_log_error( APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r->server, @@ -625,11 +641,12 @@ waklog_phase0( request_rec *r ) return( DECLINED ); } - /* do this only if we are still unauthenticated */ - if ( !child->token.ticketLen ) { + /* set our environment variables */ + ap_table_set( r->subprocess_env, "KRB5CCNAME", K5PATH ); + ap_table_set( r->subprocess_env, "KRBTKFILE", K4PATH ); - /* authenticate using keytab file */ - waklog_ktinit( r , cfg->keytab ); + /* do this only if we are still unauthenticated */ + if ( !child.token.ticketLen ) { /* stuff the credentials into the kernel */ waklog_aklog( r ); @@ -649,15 +666,19 @@ waklog_phase7( request_rec *r ) ap_log_error( APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r->server, "mod_waklog: phase7 called" ); +#if 0 /* directory config? */ cfg = (waklog_host_config *)ap_get_module_config( r->per_dir_config, &waklog_module); /* server config? */ if ( !cfg->configured ) { +#endif /* 0 */ cfg = (waklog_host_config *)ap_get_module_config( r->server->module_config, &waklog_module); +#if 0 } +#endif /* 0 */ if ( !cfg->protect ) { return( DECLINED ); @@ -675,14 +696,72 @@ waklog_phase7( request_rec *r ) static void waklog_new_connection( conn_rec *c ) { ap_log_error( APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, c->server, - "mod_waklog: new_connection called: conn_rec: 0x%08x pid: %d", c, getpid() ); + "mod_waklog: new_connection called: pid: %d", getpid() ); return; } + +static int waklog_phase2( request_rec *r ) +{ + ap_log_error( APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r->server, "mod_waklog: phase2 called" ); + if ( child.token.ticketLen ) { + memset( &child.token, 0, sizeof( struct ktc_token ) ); + + ktc_ForgetAllTokens(); + + ap_log_error( APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r->server, + "mod_waklog: ktc_ForgetAllTokens succeeded: pid: %d", getpid() ); + } + ap_log_error( APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r->server, "mod_waklog: phase2 returning" ); + return DECLINED; +} + +#if 0 +static int waklog_phase1( request_rec *r ) +{ + ap_log_error( APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r->server, "mod_waklog: phase1 returning" ); + return DECLINED; +} +static int waklog_phase3( request_rec *r ) +{ + ap_log_error( APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r->server, "mod_waklog: phase3 returning" ); + return DECLINED; +} +static int waklog_phase4( request_rec *r ) +{ + ap_log_error( APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r->server, "mod_waklog: phase4 returning" ); + return DECLINED; +} +static int waklog_phase5( request_rec *r ) +{ + ap_log_error( APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r->server, "mod_waklog: phase5 returning" ); + return DECLINED; +} +static int waklog_phase6( request_rec *r ) +{ + ap_log_error( APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r->server, "mod_waklog: phase6 returning" ); + return DECLINED; +} +static void waklog_phase8( request_rec *r ) +{ + ap_log_error( APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r->server, "mod_waklog: phase8 returning" ); + return; +} +static int waklog_phase9( request_rec *r ) +{ + ap_log_error( APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r->server, "mod_waklog: phase9 returning" ); + return DECLINED; +} +#endif /* 0 */ + module MODULE_VAR_EXPORT waklog_module = { STANDARD_MODULE_STUFF, - waklog_init, /* module initializer */ + waklog_init, /* module initializer */ +#if 0 waklog_create_dir_config, /* create per-dir config structures */ +#else /* 0 */ + NULL, /* create per-dir config structures */ +#endif /* 0 */ NULL, /* merge per-dir config structures */ waklog_create_server_config, /* create per-server config structures */ NULL, /* merge per-server config structures */ @@ -695,7 +774,7 @@ module MODULE_VAR_EXPORT waklog_module = { NULL, /* [#6] determine MIME type */ waklog_phase7, /* [#7] pre-run fixups */ NULL, /* [#9] log a transaction */ - NULL, /* [#2] header parser */ + waklog_phase2, /* [#2] header parser */ waklog_child_init, /* child_init */ NULL, /* child_exit */ waklog_phase0 /* [#0] post read-request */