
/* ====================================================================
 * Copyright (c) 1995 The Apache Group.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer. 
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. All advertising materials mentioning features or use of this
 *    software must display the following acknowledgment:
 *    "This product includes software developed by the Apache Group
 *    for use in the Apache HTTP server project (http://www.apache.org/)."
 *
 * 4. The names "Apache Server" and "Apache Group" must not be used to
 *    endorse or promote products derived from this software without
 *    prior written permission.
 *
 * 5. Redistributions of any form whatsoever must retain the following
 *    acknowledgment:
 *    "This product includes software developed by the Apache Group
 *    for use in the Apache HTTP server project (http://www.apache.org/)."
 *
 * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE APACHE GROUP OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Group and was originally based
 * on public domain software written at the National Center for
 * Supercomputing Applications, University of Illinois, Urbana-Champaign.
 * For more information on the Apache Group and the Apache HTTP server
 * project, please see <http://www.apache.org/>.
 *
 */

/*
 * http_afs.c: Stuff for dealing with files in AFS
 * 
 * By Matthew Gray
 *
 */

#include <hesiod.h>
#include <stdio.h>
#include <sys/stat.h>
#if defined(SOLARIS2)
#define AFS_ST_DEV 1
#elif defined(ULTRIX)
#define AFS_ST_DEV -30975
#elif defined(SUNOS4)
#define AFS_ST_DEV 1
#else
#define AFS_ST_DEV 1
#endif
#include "httpd.h"
#include "http_config.h"

typedef struct {
  char hesiod_on;
  char afs_hesiod_checking_on;
} hesiod_server_conf;


module hesiod_module;

/* lookup_locker -- translate a locker name into an AFS path
 *   locker --  name of the locker
 *   returns:   AFS path (or NULL on failure)
 */
static char* lookup_locker (pool *p, char* locker)
{
  char **cpp;
  cpp = hes_resolve(locker, "filsys");
  if (cpp) {
    char* hesi = *cpp;         /* we only look at the first locker entry */
    if (hesi && !strncmp(hesi,"AFS ",4)) {
      char *spc, *ret;


      hesi += 4;               /* skip "AFS " */
#ifdef SKIP_ATHENA_CELL
      if (!strncmp(hesi,"/afs/athena.mit.edu",19))
        hesi += 19;            /* skip "/afs/athena.mit.edu" */
#endif

      spc = strchr(hesi, 32);  /* strip the remaining fields */
      if (spc) *spc='\0';

      ret = (char*)palloc(p, strlen(hesi)+1);

      /* for now, we'll fail without indicating what happened if we get NULL */
      if (!ret) return NULL;

      strcpy(ret, hesi);
      return ret;
    }
  }
  return NULL;
}



/* get_path_into_locker -- translate a locker URL into a full AFS gateway path
 *   current --  current request path
 *   returns:    translated path
 * NOTE: most of this code was taken from CERN's get_user_dir() in HTConfig.c
 */
char* get_path_into_locker (request_rec * r)
{
  int statr;
  struct stat finfo;
  /* lockername = substr(uri, 2, index(uri, "/")); */
    char * lockername = ((r)->uri)+2;
    char * end = strchr(lockername, '/');
    if (end) 
      *end++ = 0;

    if (*lockername) {
        char* lpath = lookup_locker(r->pool, lockername);
        if (lpath) {
            int homelen = strlen(lpath);
            char * d = (char*)palloc(r->pool, homelen +
                                     (end ? strlen(end) : 0) + 6);

	    if(!d) return NULL;

            strcpy(d, lpath);
            if (lpath[homelen-1] != '/')
                strcat(d, "/");
	    strcat(d, "www/");
            if (end) {
                strcat(d, end);
            }
	    	    statr=stat(d,&finfo);
	    if(statr != 0){
	      return NULL;
	    } 
            return d;
        }
    }
    return NULL;
}

void *create_hesiod_config (pool *p, server_rec *s)
{
  hesiod_server_conf *hsc = (hesiod_server_conf *) pcalloc(p, sizeof(hesiod_server_conf));
  hsc->hesiod_on = 0;
  hsc->afs_hesiod_checking_on = 0;
  return hsc;
}

static char *
hesiod_switch(cmd_parms *parms, void *dummy, int flag)
{
  hesiod_server_conf *hsc = get_module_config(parms->server->module_config, &hesiod_module);
  hsc->hesiod_on = flag;
  return NULL;
}

static char *
hesiod_afs_switch(cmd_parms *parms, void *dummy, int flag)
{
  hesiod_server_conf *hsc = get_module_config(parms->server->module_config, &hesiod_module);
  hsc->afs_hesiod_checking_on = flag;
  return NULL;
}

command_rec hesiod_cmds[] = {
  { "Hesiod", hesiod_switch, NULL, RSRC_CONF, FLAG, 
    "a flag to turn on or off hesiod stuff" },

  { "HesiodAFS", hesiod_afs_switch, NULL, RSRC_CONF, FLAG, 
    "a flag to turn on or off afs checking for hesiod stuff" },

  { NULL }
};


int translate_hesiod(request_rec *r)
{
  char *ret;
  char *thefile;
  char *uritmp;
  char *redirect;
  char *end;
  int statr;
  struct stat finfo;
  void *sconf = r->server->module_config;
  hesiod_server_conf *hsc = (hesiod_server_conf *) get_module_config(sconf, &hesiod_module);

  if(hsc->hesiod_on){
    uritmp = palloc(r->pool, strlen(r->uri)+1);
    strcpy(uritmp, r->uri);
    if(uritmp[1] != '~')
      return DECLINED;
    if(!strchr(uritmp+1, '/')){
      redirect = pstrcat(r->pool, uritmp, "/", NULL);
      table_set(r->headers_out, "Location", redirect);
      return REDIRECT;
    }
    if((ret=get_path_into_locker(r))){
      r->uri = ret;
      if(hsc->afs_hesiod_checking_on){
	statr = stat(ret, &finfo);
	if((statr == -1) || (finfo.st_dev != AFS_ST_DEV)){
	  return FORBIDDEN;
	}
      }
    }
  }
  return DECLINED;
}

module hesiod_module = {
   STANDARD_MODULE_STUFF,
   NULL,                        /* initializer */
   NULL,                        /* dir config creater */
   NULL,                        /* dir merger --- default is to override */
   create_hesiod_config,           /* server config */
   NULL,            /* merge server configs */
   hesiod_cmds,                    /* command table */
   NULL,                        /* handlers */
   translate_hesiod, /* filename translation */
   NULL,                        /* check_user_id */
   NULL,                        /* check auth */
   NULL,                        /* check access */
   NULL,                /* type_checker */
   NULL,                        /* fixups */
   NULL                         /* logger */
};

