fewer #includes
[hcoop/debian/libapache-mod-waklog.git] / mod_waklog.c
index 5da9a1e..e802d3a 100644 (file)
 #include <sys/ioccom.h>
 #endif /* sun */
 #include <stropts.h>
-#include <kerberosIV/krb.h>
-#include <kerberosIV/des.h>
 #include <afs/venus.h>
 #include <afs/auth.h>
 #include <rx/rxkad.h>
 
-#include <asm/bitops.h>
-#include <sys/shm.h>
+#define KEYTAB                 "/home/drh/keytab.umweb.drhtest"
+#define KEYTAB_PRINCIPAL       "umweb/drhtest"
 
-#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      5*60 /* should be TKT_LIFE */
 
-#define K5PATH "FILE:/tmp/waklog.creds.k5"
-#define K4PATH "/tmp/waklog.creds.k4"
+#define AFS_CELL       "umich.edu" /* NB: lower case */
+
+#define K5PATH         "FILE:/tmp/waklog.creds.k5"
+#define K4PATH         "/tmp/waklog.creds.k4"
 
 module waklog_module;
 
@@ -44,21 +42,14 @@ typedef struct {
     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;
+
 
     static void *
 waklog_create_dir_config( pool *p, char *path )
@@ -68,9 +59,9 @@ 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 );
 }
@@ -84,77 +75,55 @@ 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;
 
     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 ( params->path == NULL ) {
+        cfg = (waklog_host_config *) ap_get_module_config(
+                params->server->module_config, &waklog_module );
+    } else {
+        cfg = (waklog_host_config *)mconfig;
+    }
 
-    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 ( params->path == NULL ) {
+        cfg = (waklog_host_config *) ap_get_module_config(
+                params->server->module_config, &waklog_module );
+    } else {
+        cfg = (waklog_host_config *)mconfig;
     }
 
-    mod->endtime = 0;
-    mod->getting_tgt = 0;
+    ap_log_error( APLOG_MARK, APLOG_INFO|APLOG_NOERRNO, params->server,
+           "mod_waklog: using keytab: %s", file );
 
-    return;
+    cfg->keytab = 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;
 
@@ -165,14 +134,17 @@ set_waklog_protect( cmd_parms *params, void *mconfig, int flag )
         cfg = (waklog_host_config *)mconfig;
     }
 
-    cfg->protect = flag;
+    ap_log_error( APLOG_MARK, APLOG_INFO|APLOG_NOERRNO, params->server,
+           "mod_waklog: using keytab_principal: %s", file );
+
+    cfg->keytab_principal = 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;
 
@@ -184,9 +156,9 @@ set_waklog_use_keytab( cmd_parms *params, void *mconfig, char *file  )
     }
 
     ap_log_error( APLOG_MARK, APLOG_INFO|APLOG_NOERRNO, params->server,
-           "mod_waklog: using keytab: %s", file );
+           "mod_waklog: using afs_cell: %s", file );
 
-    cfg->keytab = file;
+    cfg->afs_cell = file;
     cfg->configured = 1;
     return( NULL );
 }
@@ -196,17 +168,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 +182,149 @@ command_rec waklog_cmds[ ] =
     NULL, RSRC_CONF | ACCESS_CONF, FLAG,
     "enable waklog on a location or directory basis" },
 
-    { "WaklogUseKeytab", set_waklog_use_keytab,
+    { "WaklogUseKeytabPath", set_waklog_use_keytab,
+    NULL, RSRC_CONF, TAKE1,
+    "Use the supplied keytab rather than the default" },
+
+    { "WaklogUseKeytabPrincipal", set_waklog_use_keytab_principal,
     NULL, RSRC_CONF, TAKE1,
-    "Use the supplied keytab file rather than the user's TGT" },
+    "Use the supplied keytab principal rather than the default" },
+
+    { "WaklogUseAFSCell", set_waklog_use_afs_cell,
+    NULL, RSRC_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;
 
-    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" );
 
-    /* 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 );
-
-#define SOON 300
-
-    /* will we need another tgt soon? */
-    now = time( NULL );
-    if ( !mod->getting_tgt && mod->endtime < now + SOON ) {
-
-       ap_log_error( APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r->server,
-               "mod_waklog: mod->endtime: %u, now: %u", mod->endtime, now );
+    if (( kerror = krb5_init_context( &kcontext ))) {
+       ap_log_error( APLOG_MARK, APLOG_ERR, s,
+               (char *)error_message( kerror ));
 
-       /*
-       ** 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 ) ) {
+        goto cleanup;
+    }
 
-           if (( kerror = krb5_init_context( &kcontext ))) {
-               ap_log_error( APLOG_MARK, APLOG_ERR, r->server,
-               (char *)error_message( kerror ));
+    /* use the path */
+    if (( kerror = krb5_cc_resolve( kcontext, K5PATH, &kccache )) != 0 ) {
+       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 (( kerror = krb5_parse_name( kcontext, cfg->keytab_principal, &kprinc ))) {
+       ap_log_error( APLOG_MARK, APLOG_ERR, s,
+               (char *)error_message( kerror ));
 
-               goto cleanup2;
-           }
+               goto cleanup;
+    }
 
-           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 );
+    /* get the krbtgt */
+    if (( kerror = krb5_get_init_creds_keytab( kcontext, &v5creds, 
+               kprinc, keytab, 0, NULL, &kopts ))) {
 
-           /* initialize ticket cache */
-           ap_log_error( APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r->server,
-                   "mod_waklog: before in_tkt" );
+       ap_log_error( APLOG_MARK, APLOG_ERR, s,
+               (char *)error_message( kerror ));
 
-           if (( kerror = in_tkt( v4creds.pname, v4creds.pinst )) != KSUCCESS ) {
-               ap_log_error( APLOG_MARK, APLOG_ERR, r->server,
-                   (char *)error_message( kerror ));
+       goto cleanup;
+    }
 
-               goto cleanup6;
-           }
+   if (( kerror = krb5_verify_init_creds( kcontext, &v5creds,
+           kprinc, keytab, NULL, NULL )) != 0 ) {
 
-           /* 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" );
+       ap_log_error( APLOG_MARK, APLOG_ERR, s,
+               (char *)error_message( kerror ));
 
-           if (( kerror = krb_save_credentials( v4creds.service,
-                   v4creds.instance,
-                   v4creds.realm,
-                   v4creds.session,
-                   v4creds.lifetime,
-                   v4creds.kvno,
-                   &(v4creds.ticket_st),
-                   v4creds.issue_date )) != 0 ) {
+       goto cleanup;
+    }
 
-               ap_log_error( APLOG_MARK, APLOG_ERR, r->server,
-                       (char *)error_message( kerror ));
+    if (( kerror = krb5_cc_initialize( kcontext, kccache, kprinc )) != 0 ) {
+       ap_log_error( APLOG_MARK, APLOG_ERR, s,
+               (char *)error_message( kerror ));
 
-               goto cleanup6;
-           }
+       goto cleanup;
+    }
 
-           /* 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 );
+    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 ));
 
-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 );
+       goto cleanup;
+    }
 
-           /* exit the critical region */
-cleanup1:   mod->getting_tgt = 0;
-       }
+    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, r->server,
-       "mod_waklog: waklog_ktinit: exiting" );
+    ap_log_error( APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, s,
+       "mod_waklog: waklog_kinit: exiting" );
 
     return( 0 );
 }
@@ -450,18 +334,19 @@ cleanup1:   mod->getting_tgt = 0;
 waklog_aklog( request_rec *r )
 {
     int                                rc;
-    char                       buf[ 1024 ];
+    char                       buf[ 2048 ];
     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 +357,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 +369,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/<cell> 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 +409,57 @@ 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 overflor */
+    if ( v5credsp->ticket.length >= 344 ) {    /* from krb524d.c */
+       ap_log_error( APLOG_MARK, APLOG_ERR, r->server,
+           "mod_waklog: ticket size (%d) to 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, v5credsp->client->data[0].length );
+       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, v5credsp->client->data[1].length );
+               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, v5credsp->client->realm.length );
+       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 +476,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 );
 }
 
 
@@ -626,10 +569,11 @@ waklog_phase0( request_rec *r )
     }
 
     /* do this only if we are still unauthenticated */
-    if ( !child->token.ticketLen ) {
+    if ( !child.token.ticketLen ) {
 
-       /* authenticate using keytab file */
-       waklog_ktinit( r , cfg->keytab );
+       /* set our environment variables */
+       ap_table_set( r->subprocess_env, "KRB5CCNAME", K5PATH );
+       ap_table_set( r->subprocess_env, "KRBTKFILE", K4PATH );
 
        /* stuff the credentials into the kernel */
        waklog_aklog( r );
@@ -675,7 +619,7 @@ 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;
 }