Hi All
Im trying to make apache able to read AFS. I have found some examples on the net but they are all fro apache 1.3, AFS 1.2 and Kerberos 4
I need apache 2, AFS 1.3.74 and Kerberos IV.
Using the attached module I get in /var/log/message "Dec 10 15:54:08 frodo kernel: afs: Tokens for user of AFS id 48 for cell linet.dk are discarded (rxkad error=19270407)", which I think means bad ticket.
I don't really know what Im doing, since I havent hacked in AFS or Kerberos's API before, so this is a learning process. But my question is:
In the examples they all copy the "v4creds.session" into "ClearToken.HandShakeKey" but in v5creds there is no session key, I think it is called keyblock. What is the sessionKey in Kerberos IV ?
If anyone would like to help me out coding the module I would appreciate it.
If there already is a module I would really like the link :)
/Mikkel
/* Copyright 2004 Mikkel Kruse Johnsen, Linet <[EMAIL PROTECTED]>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Templete from: Kevin O'Donnell, Thanks
*/
//#define KERNEL 1
/*
* Include the core server components.
*/
#include "httpd.h"
#include "http_config.h"
/* krb5 includes */
#include <krb5.h>
#include <kerberosIV/krb.h>
#include <et/com_err.h>
/* afs includes */
#include <sys/ioctl.h>
#include <afs/vice.h>
/*
* The default value for the error string.
*/
#ifndef DEFAULT_MODAFS_STRING
#define DEFAULT_MODAFS_STRING "apache2_mod_afs: A request was made."
#endif
/*
* This module
*/
#define BUFF_SIZE 1024
#define AFS_PRINCIPAL "afs/[EMAIL PROTECTED]"
#define MODULE_NAME "afs_module"
module AP_MODULE_DECLARE_DATA afs_module;
struct ClearToken {
long AuthHandle;
char HandShakeKey[8];
long ViceId;
long BeginTimestamp;
long EndTimestamp;
};
/*
* This modules per-server configuration structure.
*/
typedef struct {
int on;
char *string;
char *keytab;
char *principal;
} modafs_config;
/*
* This function is registered as a handler for HTTP methods and will
* therefore be invoked for all GET requests (and others). Regardless
* of the request type, this function simply sends a message to
* STDERR (which httpd redirects to logs/error_log). A real module
* would do *alot* more at this point.
*/
static int
mod_afs_method_handler (request_rec *r)
{
// Get the module configuration
modafs_config *s_cfg = ap_get_module_config(r->server->module_config,
&afs_module);
// Send a message to the log file.
fprintf(stderr, "Method Handler: %s\n", s_cfg->string);
// We need to flush the stream so that the message appears right away.
// Performing an fflush() in a production system is not good for
// performance - don't do this for real.
fflush(stderr);
// Return DECLINED so that the Apache core will keep looking for
// other modules to handle this request. This effectively makes
// this module completely transparent.
return DECLINED;
}
static char *
ma_get_cache_file()
{
return "FILE:/tmp/krb5cc_48";
}
static int
ticket_to_token(krb5_creds *v5creds)
{
long tmp, code;
int ViceId = 0;
struct ClearToken ct;
struct ViceIoctl iob;
unsigned char tbuffer[BUFF_SIZE];
unsigned char cell[BUFF_SIZE] = "linet.dk";
unsigned char *key = NULL;
register unsigned char *tp = tbuffer;
int res;
struct timeval t_local;
ct.AuthHandle = 3; //v5creds.kvno; // hide auth handle here
bcopy(&v5creds->keyblock.contents, &ct.HandShakeKey, 8);
ct.ViceId = geteuid();
gettimeofday(&t_local, (struct timezone *)0);
ct.BeginTimestamp = t_local.tv_sec;
ct.EndTimestamp = t_local.tv_sec + 5*60;
bcopy(&v5creds->ticket.length, tp, sizeof(long));
tp += sizeof(long);
bcopy(v5creds->ticket.data, tp, v5creds->ticket.length);
tp += v5creds->ticket.length;
tmp = sizeof(struct ClearToken);
bcopy(&tmp, tp, sizeof(long));
tp += sizeof(long);
bcopy(&ct, tp, sizeof(struct ClearToken));
tp += sizeof(struct ClearToken);
tmp = 0;
bcopy(&tmp, tp, sizeof(long));
tp += sizeof(long);
strcpy(tp, cell);
tp += strlen(tp)+1;
iob.in = tbuffer;
iob.in_size = (short)(tp - tbuffer);
iob.out = tbuffer;
iob.out_size = sizeof(tbuffer);
res = lpioctl(0, _VICEIOCTL(3), &iob, 0);
return res;
}
static int
is_ticket_expired(krb5_creds *v5creds)
{
struct timeval cTime;
gettimeofday(&cTime, (struct timezone *)0);
if(((cTime.tv_sec - v5creds->times.endtime) >= 0) || (abs(cTime.tv_sec -
v5creds->times.endtime) <= 300)) {
fprintf(stderr, "c=%ld e=%ld ticket expired\n", cTime.tv_sec,
v5creds->times.endtime);
return 1;
}
return 0;
}
static int
mod_afs_post_read_request(request_rec *r)
{
char *cachename;
krb5_principal princ;
krb5_error_code retval;
krb5_context context;
krb5_ccache ccache;
krb5_creds v5creds;
krb5_creds in_creds;
// Get the module configuration
modafs_config *s_cfg = ap_get_module_config(r->server->module_config,
&afs_module);
if((retval = krb5_init_context(&context)) != 0) {
com_err(MODULE_NAME, retval, "while initializing krb5");
goto cleanup;
}
cachename = ma_get_cache_file();
if((retval = krb5_cc_resolve(context, cachename, &ccache)) != 0) {
com_err(MODULE_NAME, retval, ":unable to resolve krb cache\n");
goto cleanup;
}
if((retval = krb5_cc_get_principal(context, ccache, &in_creds.client)) != 0) {
com_err(MODULE_NAME, retval, ":unable to get the default principal");
goto cleanup;
}
if((retval = krb5_parse_name(context, AFS_PRINCIPAL, &in_creds.server)) != 0)
{
com_err(MODULE_NAME, retval, ":unable to convert %s to a principal",
AFS_PRINCIPAL);
goto cleanup;
}
if ((retval = krb5_cc_retrieve_cred(context, ccache,
KRB5_TC_MATCH_SRV_NAMEONLY, &in_creds, &v5creds)) != 0) {
com_err(MODULE_NAME, retval, ":while retrieving creds: %s\n",
in_creds.server->data->data);
goto cleanup;
}
if(!is_ticket_expired(&v5creds)) {
ticket_to_token(&v5creds);
}
cleanup:
krb5_cc_close(context, ccache);
krb5_free_context(context);
return DECLINED;
}
static int
mod_afs_post_config (apr_pool_t *p,
apr_pool_t *plog,
apr_pool_t *ptemp,
server_rec *s)
{
setpag();
return DECLINED;
}
static void
mod_afs_register_hooks (apr_pool_t *p)
{
ap_hook_handler(mod_afs_method_handler, NULL, NULL, APR_HOOK_MIDDLE);
ap_hook_post_config(mod_afs_post_config, NULL, NULL, APR_HOOK_MIDDLE);
ap_hook_post_read_request(mod_afs_post_read_request, NULL, NULL,
APR_HOOK_MIDDLE);
}
static const char *
set_modafs_engine(cmd_parms *parms, void *mconfig, const char *arg)
{
// get the module configuration (this is the structure created by
create_modafs_config())
modafs_config *s_cfg = ap_get_module_config(parms->server->module_config,
&afs_module);
// make a duplicate of the argument's value using the command parameters pool.
if (!strcmp (arg, "on")) {
s_cfg->on = 1;
} else {
s_cfg->on = 0;
}
//fprintf(stderr, "apache2_mod_afs: Engine: %s\n", s_cfg->on);
//fflush(stderr);
// success
return NULL;
}
static const char *
set_modafs_keytab(cmd_parms *parms, void *mconfig, const char *arg)
{
// get the module configuration (this is the structure created by
create_modafs_config())
modafs_config *s_cfg = ap_get_module_config(parms->server->module_config,
&afs_module);
// make a duplicate of the argument's value using the command parameters pool.
s_cfg->keytab = (char *) arg;
//fprintf(stderr, "apache2_mod_afs: Keytab: %s\n", s_cfg->keytab);
//fflush(stderr);
// success
return NULL;
}
static const char *
set_modafs_principal(cmd_parms *parms, void *mconfig, const char *arg)
{
// get the module configuration (this is the structure created by
create_modafs_config())
modafs_config *s_cfg = ap_get_module_config(parms->server->module_config,
&afs_module);
// make a duplicate of the argument's value using the command parameters pool.
s_cfg->principal = (char *) arg;
// success
return NULL;
}
/**
* A declaration of the configuration directives that are supported by this
module.
*/
static const command_rec mod_afs_cmds[] =
{
AP_INIT_TAKE1(
"AFSEngine",
set_modafs_engine,
NULL,
RSRC_CONF,
"AFSEngine <string> -- Turn AFS Engine on/off."
),
AP_INIT_TAKE1(
"AFSKeytab",
set_modafs_keytab,
NULL,
RSRC_CONF,
"AFSKeytab <string> -- Path to the keytab file."
),
AP_INIT_TAKE1(
"AFSPrincipal",
set_modafs_principal,
NULL,
RSRC_CONF,
"AFSPrincipal <string> -- Principal."
),
{NULL}
};
/**
* Creates the per-server configuration records.
*/
static void *
create_modafs_config(apr_pool_t *p, server_rec *s)
{
modafs_config *newcfg;
// allocate space for the configuration structure from the provided pool p.
newcfg = (modafs_config *) apr_pcalloc(p, sizeof(modafs_config));
// set the default value for the error string.
newcfg->string = strdup(DEFAULT_MODAFS_STRING);
// return the new server configuration structure.
return (void *) newcfg;
}
/*
* Declare and populate the module's data structure. The
* name of this structure ('afs_module') is important - it
* must match the name of the module. This structure is the
* only "glue" between the httpd core and the module.
*/
module AP_MODULE_DECLARE_DATA afs_module =
{
STANDARD20_MODULE_STUFF, // standard stuff; no need to mess with this.
NULL, // create per-directory configuration
structures - we do not.
NULL, // merge per-directory - no need to merge if we
are not creating anything.
create_modafs_config, // create per-server configuration structures.
NULL, // merge per-server - hrm - examples I have
been reading don't bother with this for trivial cases.
mod_afs_cmds, // configuration directive handlers
mod_afs_register_hooks, // request handlers
};
