/*************************************************
*     Exim - an Internet mail transport agent    *
*************************************************/

/* Copyright (c) University of Cambridge 1995 - 1999 */
/* See the file NOTICE for conditions of use and distribution. */


#include "../exim.h"
#include "localuser.h"



/* Options specific to the localuser director. */

optionlist localuser_director_options[] = {
  { "current_directory", opt_stringptr,
      (void *)(offsetof(localuser_director_options_block, current_dir)) },
  { "directory",         opt_stringptr | opt_hidden,
      (void *)(offsetof(localuser_director_options_block, pw_dir)) },
  { "home_directory",    opt_stringptr,
      (void *)(offsetof(localuser_director_options_block, home_dir)) },
  { "match_directory",   opt_stringptr,
      (void *)(offsetof(localuser_director_options_block, pw_dir)) }
};

/* Size of the options list. An extern variable has to be used so that its
address can appear in the tables drtables.c. */

int localuser_director_options_count =
  sizeof(localuser_director_options)/sizeof(optionlist);

/* Default private options block for the localuser director. */

localuser_director_options_block localuser_director_option_defaults = {
  NULL,        /* pw_dir */
  NULL,        /* home_dir */
  NULL,        /* current_dir */
  NULL,        /* re_pw_dir */
};



/*************************************************
*          Initialization entry point            *
*************************************************/

/* Called for each instance, after its options have been read, to
enable consistency checks to be done, or anything else that needs
to be set up. */

void localuser_director_init(director_instance *dblock)
{
/*
localuser_director_options_block *ob =
  (localuser_director_options_block *)(dblock->options_block);
*/

if (dblock->transport == NULL &&
    dblock->expand_transport == NULL &&
    !dblock->verify_only)
  log_write(0, LOG_PANIC_DIE|LOG_CONFIG2, "%s director:\n  "
  "a transport is required by the localuser director driver", dblock->name);
}



/*************************************************
*              Main entry point                  *
*************************************************/

/* See local README for interface description. */

int localuser_director_entry(
  director_instance *dblock,      /* data for this instantiation */
  address_item *addr,             /* address we are working on */
  address_item **addr_local,      /* add it to this if it's local */
  address_item **addr_remote,     /* add it to this if it's remote */
  address_item **addr_new,        /* put new addresses on here */
  address_item **addr_succeed,    /* put finished with addresses here */
  BOOL verify)                    /* TRUE when verifying */
{
localuser_director_options_block *ob =
  (localuser_director_options_block *)(dblock->options_block);
struct passwd *pw;
char *errors_to;
char *remove_headers;
header_line *extra_headers;
int rc;

addr_new = addr_new;          /* Keep picky compilers happy */
addr_succeed = addr_succeed;

/* The third argument to direct_finduser() must be NULL here, to prevent a
digit string being taken as a numeric uid. */

if (!direct_finduser(addr->local_part, &pw, NULL))
  {
  DEBUG(2) debug_printf("%s director failed for %s: no such user\n",
    dblock->name, addr->local_part);
  return FAIL;
  }

/* Set the home directory, and if there is a setting of match_directory, check
for a match. The resetting of deliver_home happens at the outer level. */

deliver_home = pw->pw_dir;
if (ob->pw_dir != NULL)
  {
  rc = direct_match_directory(addr, pw->pw_dir, ob->pw_dir, &(ob->re_pw_dir),
    dblock->name);
  if (rc != OK) return rc;
  }

/* Perform file existence and sender verification checks now that we
have $home available. */

rc = direct_check_fsc(dblock, addr);
if (rc != OK) return rc;

/* Set up the errors address, if any. */

rc = direct_get_errors_address(addr, dblock, "director", verify, &errors_to);
if (rc != OK) return rc;

/* Set up the additional and removeable headers for the address. */

rc = direct_get_munge_headers(addr, dblock, "director", &extra_headers,
  &remove_headers);
if (rc != OK) return rc;

/* This local user is OK; set the transport and accept the address; update its
errors address and header munging. */

if (!route_get_transport(dblock->transport, dblock->expand_transport,
  addr, &(addr->transport), dblock->name)) return ERROR;

addr->errors_address = errors_to;
addr->extra_headers = extra_headers;
addr->remove_headers = remove_headers;

/* Default uid/gid are from the passwd file, but can be overridden by
explicit settings, which will be filled in by the route_queue() function. */

addr->uid = pw->pw_uid;
addr->uid_set = TRUE;
addr->gid = pw->pw_gid;
addr->gid_set = TRUE;

if (ob->home_dir != NULL) addr->home_dir = ob->home_dir;
  else addr->home_dir = string_copy(pw->pw_dir);
addr->current_dir = ob->current_dir;

return route_queue(addr, addr_local, addr_remote, (router_instance *)dblock,
  "director")? OK : ERROR;
}

/* End of director/localuser.c */
