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
};

Reply via email to