|
|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T i
Length: 21837 (0x554d)
Types: TextFile
Names: »include.c«
└─⟦9ae75bfbd⟧ Bits:30007242 EUUGD3: Starter Kit
└─⟦2fafebccf⟧ »EurOpenD3/mail/smail3.1.19.tar.Z«
└─⟦bcd2bc73f⟧
└─⟦this⟧ »src/directors/include.c«
/* @(#)include.c 3.19 3/17/89 17:18:25 */
/*
* Copyright (C) 1987, 1988 Ronald S. Karr and Landon Curt Noll
*
* See the file COPYING, distributed with smail, for restriction
* and warranty information.
*/
/*
* include.c:
* direct mail for addresses which are mailing lists. In the
* future there will be two sets of entry points, one set to
* match include files generated from aliases and another to
* match include files generated from forward files. Also in
* the future security options will be added. For now, just
* ensure that an include file address comes from an alias file
* or forward file.
*
* Specifications for the include directing driver:
*
* private attribute data:
*
* modemask (number): specifies bits that are not allowed
* to be set. If some of these bits are set, the
* ALIAS_CAUTION flag is set for the resultant
* addr structures.
*
* owners (string): list of possible owners for the file.
* For files owned by others, the ADDR_CAUTION bit is
* set in the resultant addr structures.
*
* owngroups (string): like the `owners' attribute except
* that it applies to groups.
*
* matchdirector (string): names the director that this
* instance of the include driver is a match for.
*
* private attribute flags:
* copyowners - get owners and owngroups from the director
* responsible for an addr.
* copysecure - copy modemask from the director responsible
* for an addr.
*/
#include <stdio.h>
#include <pwd.h>
#include <grp.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "defs.h"
#ifdef UNIX_BSD
# include <sys/file.h>
#endif
#include "../smail.h"
#include "../smailconf.h"
#include "../parse.h"
#include "../addr.h"
#include "../field.h"
#include "../log.h"
#include "../direct.h"
#include "../exitcodes.h"
#include "../dys.h"
#include "fwdfile.h"
#include "aliasfile.h"
#include "include.h"
#ifndef DEPEND
# include "../extern.h"
# include "../debug.h"
# include "../error.h"
#endif
/* functions local to this file */
static void include_internal();
static int include_secure();
static void dtr_include_internal();
static void forwardfile_call_include();
static void aliasfile_call_include();
\f
/*
* the following private data is used if the director.private field
* is NULL. Since the COPY_SECURE flag overrides the modemask field
* and COPY_OWNERS overrides the owner and owngroup fields, this is
* primarily useful as a source for the matchdirector, retries and
* interval fields.
*/
static struct include_private default_include_priv = {
0000, /* no restrictions on mode */
NULL, /* no ownership checks */
NULL, /* no group ownership checks */
NULL, /* don't match a particular director */
2, /* two retries */
2, /* at two second intervals */
};
/*
* include_internal - low level routine for the mailing list drivers
*/
/*ARGSUSED*/
static void
include_internal(dp, in, new, modemask, owners, owngroups, other_owner,
defer, fail)
struct director *dp; /* director entry */
struct addr *in; /* one input local-form addr */
struct addr **new; /* output new addrs to resolve */
int modemask; /* copied mode mask */
char *owners; /* list of possible owners */
char *owngroups; /* list of possible groups */
char *other_owner; /* one additional owner */
struct addr **defer; /* addrs to defer to a later time */
struct addr **fail; /* unresolvable addrs */
{
struct include_private *priv;
int flags; /* flags for new addr structures */
FILE *f; /* open list file */
struct stat statbuf; /* need stat to get size of file */
int ct; /* returned count from read */
char *buf; /* buffer for reading file */
struct addr *list; /* list from process_field */
struct addr *list_next; /* next element of list */
char *fn; /* name of file to open */
char *error; /* error messages */
priv = (struct include_private *)dp->private;
if (priv == NULL) {
priv = &default_include_priv;
}
DEBUG(DBG_DRIVER_HI, "dtd_include called\n");
in->director = dp; /* matched if we reached this point */
/* mode mask from private structure, if `copy_secure' attribute is off */
if ( !(dp->flags & COPY_SECURE) ) {
modemask = priv->modemask;
}
/* owners come from private structure, if `copy_owners' attribute is off */
if ( !(dp->flags & COPY_OWNERS) ) {
owners = priv->owners;
owngroups = priv->owngroups;
other_owner = NULL;
}
/*
* Try to open the file
*/
fn = expand_string(in->remainder + sizeof(":include:")-1,
in->parent, (char *)NULL, (char *)NULL);
if (fn == NULL) {
/*
* ERR_116 - include name expansion failed
*
* DESCRIPTION
* The filename part of a :include:filename address failed to
* be expanded by expand_string().
*
* ACTIONS
* Fail the address and send an error to the address owner or
* to the postmaster. Report the parent address which produced
* the :include:filename address in the error message.
*
* RESOLUTION
* The postmaster or address owner should correct the address.
*/
in->error = note_error(ERR_NPOWNER|ERR_116,
xprintf(
"director %s: include name expansion failed (parent %s)",
dp->name, in->parent->in_addr));
in->succ = *fail;
*fail = in;
return;
}
fn = COPY_STRING(fn);
DEBUG2(DBG_DRIVER_MID, "director %s: opened file %s\n",
dp->name, fn);
f = fopen_as_user(fn, "r", (dp->flags & INC_CHECK_PATH) != 0,
in->uid != BOGUS_USER? in->uid: nobody_uid,
in->gid != BOGUS_GROUP? in->gid: nobody_gid);
if (f == NULL) {
int left = priv->retries;
while (left -- > 0) {
(void) sleep(priv->interval);
f = fopen_as_user(fn, "r", (dp->flags & INC_CHECK_PATH) != 0,
in->uid != BOGUS_USER? in->uid: nobody_uid,
in->gid != BOGUS_GROUP? in->gid: nobody_gid);
if (f == NULL) break;
}
}
if (f == NULL) {
/*
* ERR_117 - include file open failed
*
* DESCRIPTION
* The open failed on an :include:filename address. Errno
* should detail the actual error.
*
* ACTIONS
* The address is failed and an error is sent to the address
* owner or to the postmaster.
*
* RESOLUTION
* The address owner or postmaster should ensure that the
* address is correct or that the file exists and is readable
* from the mailer.
*/
in->error = note_error(ERR_NPOWNER|ERR_117,
xprintf(
"director %s: include file open failed (parent %s): %s",
dp->name,
in->parent->in_addr,
strerrno()));
in->succ = *fail;
*fail = in;
return;
}
#ifdef lock_fd_rd_wait
lock_fd_rd_wait(fileno(f));
#endif
(void) fstat(fileno(f), &statbuf);
if (in->parent->flags & ADDR_CAUTION ||
! include_secure(dp, &statbuf, modemask,
owners, owngroups, other_owner))
{
flags = ADDR_CAUTION|ADDR_LISTTYPE;
} else {
flags = ADDR_LISTTYPE;
}
buf = xmalloc((unsigned)statbuf.st_size + 1);
ct = read(fileno(f), buf, statbuf.st_size);
(void) fclose(f);
if (ct < 0) {
/*
* ERR_118 - include file read failed
*
* DESCRIPTION
* The read failed on an :include:filename address. Errno
* should detail the actual error.
*
* ACTIONS
* The address is failed and an error is sent to the address
* owner or to the postmaster.
*
* RESOLUTION
* This generally means filesystem problems and the error
* should be brought up with the site administrator.
*/
in->error = note_error(ERR_NPOWNER|ERR_118,
xprintf(
"director %s: include file read failed (parent %s): %s",
dp->name,
in->parent->in_addr,
strerrno()));
in->succ = *fail;
*fail = in;
return;
}
buf[ct] = '\0'; /* terminate the region */
list = NULL;
error = NULL;
(void) process_field((char *)NULL, buf, (char *)NULL,
(char *)NULL, &list, F_ALIAS, &error);
if (error) {
/*
* ERR_119 - include file parse error
*
* DESCRIPTION
* process_field() encountered an error in parsing the contents
* of the file specified by a :include:filename address. The
* actual parsing error was returned in `error'.
*
* ACTIONS
* The address is failed and an error is sent to the address
* owner or to the postmaster.
*
* RESOLUTION
* The file should be changed to take care of the parsing error.
*/
in->error = note_error(ERR_NPOWNER|ERR_119,
xprintf(
"director %s: include file parse error (parent %s): %s",
dp->name,
in->parent->in_addr,
error));
in->succ = *fail;
*fail = in;
return;
}
for (; list; list = list_next) {
list_next = list->succ;
list->parent = in;
list->flags = flags;
list->home = in->home;
list->uid = in->uid;
list->gid = in->gid;
list->succ = *new;
*new = list;
}
DEBUG2(DBG_DRIVER_LO, "director %s matched <%s>\n",
dp->name, in->remainder);
xfree(fn);
}
/*
* include_secure - determine if a mailing list file is secure
*
* return TRUE if secure, otherwise false.
*/
/*ARGSUSED*/
static int
include_secure(dp, statp, modemask, owners, owngroups, other_owner)
struct director *dp; /* director */
struct stat *statp; /* stat of mailing list file */
int modemask; /* disallowed mode bits, ala umask */
char *owners; /* possible owners */
char *owngroups; /* possible groups */
char *other_owner; /* one more possible owner */
{
int other_uid; /* uid for other_owner */
/* check the mode bits */
if (modemask & statp->st_mode) {
return FALSE; /* not secure */
}
if (other_owner) {
struct passwd *pw; /* passwd entry for other_owner */
pw = getpwbyname(other_owner);
if (pw) {
other_uid = pw->pw_uid;
} else {
other_owner = NULL;
}
}
if (owners) {
if (other_owner && other_uid != statp->st_uid) {
/* checkowner fails and owners attribute exists */
char *temp = owners;
int found = FALSE;
/* check against passwd file uid */
for (temp = strcolon(temp); temp; temp = strcolon((char *)NULL)) {
struct passwd *pw = getpwbyname(temp);
if (pw == NULL) {
write_log(LOG_SYS, "include_secure: no such owner %s\n",
temp);
} else {
if (statp->st_uid == pw->pw_uid) {
found = TRUE;
break;
}
}
}
if (!found) {
return FALSE; /* not secure */
}
}
} else if (other_owner) {
/* no owners attribute, so checkowner attribute is the final word */
if (other_uid != statp->st_uid) {
return FALSE; /* not secure */
}
}
if (owngroups) {
/* verify owning group */
char *temp = owngroups;
int found = FALSE;
/* check against passwd file uid */
for (temp = strcolon(temp); temp; temp = strcolon((char *)NULL)) {
struct group *gr = getgrbyname(temp);
if (gr == NULL) {
write_log(LOG_SYS, "include_secure: no such owngroup %s\n",
temp);
} else {
if (statp->st_gid == gr->gr_gid) {
found = TRUE;
break;
}
}
}
if (!found) {
return FALSE; /* not secure */
}
}
return TRUE;
}
/*
* dtb_internal_include - read the configuration file attributes
*/
char *
dtb_internal_include(dp, attrs)
struct director *dp; /* director entry being defined */
struct attribute *attrs; /* list of per-driver attributes */
{
char *error;
static struct attr_table include_attributes[] = {
{ "modemask", t_int, NULL, NULL, OFFSET(include_private, modemask) },
{ "owners", t_string, NULL, NULL, OFFSET(include_private, owners) },
{ "owngroups", t_string, NULL, NULL,
OFFSET(include_private, owngroups) },
{ "matchdirector", t_string, NULL, NULL,
OFFSET(include_private, matchdirector) },
{ "retries", t_int, NULL, NULL, OFFSET(include_private, retries) },
{ "interval", t_int, NULL, NULL, OFFSET(include_private, interval) },
{ "copysecure", t_boolean, NULL, NULL, COPY_SECURE },
{ "copyowners", t_boolean, NULL, NULL, COPY_OWNERS },
{ "checkpath", t_boolean, NULL, NULL, INC_CHECK_PATH },
};
static struct attr_table *end_include_attributes =
ENDTABLE(include_attributes);
static struct include_private include_template = {
002, /* modemask */
NULL, /* owners */
NULL, /* owngroups */
NULL, /* matchdirector */
#ifdef HAVE_RENAME
0, /* retries */
#else /* not HAVE_RENAME */
1, /* retries */
#endif /* not HAVE_RENAME */
2, /* interval */
};
struct include_private *priv; /* new include_private structure */
/* copy the template private data */
priv = (struct include_private *)xmalloc(sizeof(*priv));
(void) memcpy((char *)priv, (char *)&include_template, sizeof(*priv));
dp->private = (char *)priv;
/* fill in the attributes of the private data */
error = fill_attributes((char *)priv,
attrs,
&dp->flags,
include_attributes,
end_include_attributes);
if (error) {
return error;
} else {
return NULL;
}
}
/*
* dtd_forwardinclude - mailing list driver complementing forwardfile driver
*/
/*ARGSUSED*/
struct addr *
dtd_forwardinclude(dp, in, out, new, defer, fail)
struct director *dp; /* director entry */
struct addr *in; /* input local-form addrs */
struct addr **out; /* output resolved addrs */
struct addr **new; /* output new addrs to resolve */
struct addr **defer; /* addrs to defer to a later time */
struct addr **fail; /* unresolvable addrs */
{
struct include_private *priv; /* private storage */
struct addr *pass = NULL; /* addr structures to return */
struct addr *cur; /* addr being processed */
struct addr *next; /* next addr to process */
int put_back = TRUE; /* FALSE to put addr on pass list */
struct addr *temp; /* temp for scanning parent addrs */
priv = (struct include_private *)dp->private;
for (cur = in; cur; cur = next) {
next = cur->succ;
if (strncmpic(cur->remainder, ":include:", sizeof(":include:")-1)) {
/* not equal to :include:* */
cur->succ = pass;
pass = cur;
continue;
}
/* scan backward for something that was not a mailing list */
for (temp = cur; temp; temp = temp->parent) {
if ( !(temp->flags & ADDR_LISTTYPE) ) {
if (temp->director &&
EQ(temp->director->driver, "forwardfile"))
{
if (priv &&
priv->matchdirector &&
!EQ(priv->matchdirector, temp->director->name))
{
continue;
}
forwardfile_call_include(dp, cur, temp, new, defer, fail);
put_back = FALSE;
break;
}
}
}
/* we did not match the address */
if (put_back) {
cur->succ = pass;
pass = cur;
}
}
return pass;
}
/*ARGSUSED*/
void
dtv_forwardinclude(dp, in, retry, okay, defer, fail)
struct director *dp; /* director entry */
struct addr *in; /* input local-form addrs */
struct addr **retry; /* output list of unmatched addrs */
struct addr **okay; /* output list of verified addrs */
struct addr **defer; /* temporariliy unverifiable addrs */
struct addr **fail; /* unverified addrs */
{
/*
* mailing list form addresses must have a parent. Since verifies
* are only one level deep, mailing never match for verifies.
*/
insert_addr_list(in, retry, (struct error *)NULL);
}
char *
dtb_forwardinclude(dp, attrs)
struct director *dp; /* director entry being defined */
struct attribute *attrs; /* list of per-driver attributes */
{
dtb_internal_include(dp, attrs);
}
static void
forwardfile_call_include(dp, in, fwdaddr, new, defer, fail)
struct director *dp; /* director entry */
struct addr *in; /* addr to process */
struct addr *fwdaddr; /* addr from forwadfile driver */
struct addr **new; /* new addr list */
struct addr **defer; /* addrs to defer to a later time */
struct addr **fail; /* unresolvable addrs */
{
struct forwardfile_private *fpriv;
char *other_owner = NULL;
fpriv = (struct forwardfile_private *)fwdaddr->director->private;
if (fwdaddr->director->flags & FWD_CHECKOWNER) {
/* user is in the addr stucture that resolved to a forward file */
other_owner = fwdaddr->parent->remainder;
}
include_internal(dp, in, new, fpriv->modemask, fpriv->owners,
fpriv->owngroups, other_owner, defer, fail);
}
/*
* dtd_aliasinclude - mailing list driver complementing aliasfile driver
*/
/*ARGSUSED*/
struct addr *
dtd_aliasinclude(dp, in, out, new, defer, fail)
struct director *dp; /* director entry */
struct addr *in; /* input local-form addrs */
struct addr **out; /* output resolved addrs */
struct addr **new; /* output new addrs to resolve */
struct addr **defer; /* addrs to defer to a later time */
struct addr **fail; /* unresolvable addrs */
{
struct include_private *priv; /* private storage */
struct addr *pass = NULL; /* addr structures to return */
struct addr *cur; /* addr being processed */
struct addr *next; /* next addr to process */
priv = (struct include_private *)dp->private;
for (cur = in; cur; cur = next) {
next = cur->succ;
if (strncmpic(cur->remainder, ":include:", sizeof(":include:")-1)) {
/* not equal to :include:* */
cur->succ = pass;
pass = cur;
} else {
int put_back = TRUE;
struct addr *temp;
for (temp = cur; temp; temp = temp->parent) {
if ( !(temp->flags & ADDR_LISTTYPE) ) {
if (temp->director &&
EQ(temp->director->driver, "aliasfile"))
{
if (priv &&
priv->matchdirector &&
!EQ(priv->matchdirector, temp->director->name))
{
continue;
}
aliasfile_call_include(dp, cur, temp, new,
defer, fail);
put_back = FALSE;
break;
}
}
}
if (put_back) {
cur->succ = pass;
pass = cur;
}
}
}
return pass;
}
/*ARGSUSED*/
void
dtv_aliasinclude(dp, in, retry, okay, defer, fail)
struct director *dp; /* director entry */
struct addr *in; /* input local-form addrs */
struct addr **retry; /* output list of unmatched addrs */
struct addr **okay; /* output list of verified addrs */
struct addr **defer; /* temporariliy unverifiable addrs */
struct addr **fail; /* unverified addrs */
{
/*
* mailing list form addresses must have a parent. Since verifies
* are only one level deep, mailing never match for verifies.
*/
insert_addr_list(in, retry, (struct error *)NULL);
}
char *
dtb_aliasinclude(dp, attrs)
struct director *dp; /* director entry being defined */
struct attribute *attrs; /* list of per-driver attributes */
{
dtb_internal_include(dp, attrs);
}
static void
aliasfile_call_include(dp, in, fwdaddr, new, defer, fail)
struct director *dp; /* director entry */
struct addr *in; /* addr to process */
struct addr *fwdaddr; /* addr from forwadfile driver */
struct addr **new; /* new addr list */
struct addr **defer; /* addrs to defer to a later time */
struct addr **fail; /* unresolvable addrs */
{
struct aliasfile_private *apriv;
apriv = (struct aliasfile_private *)fwdaddr->director->private;
include_internal(dp, in, new, apriv->modemask, apriv->owners,
apriv->owngroups, (char *)NULL, defer, fail);
}
/*
* dtd_genericinclude - generic mailing list driver
*
* the generic mailing list driver catches any mailing list addresses.
* it is useful for catching mailing list addresses from directors
* besides aliasfile and forwardfile-type directors, if any other
* directors are considered secure address sources.
*/
/*ARGSUSED*/
struct addr *
dtd_genericinclude(dp, in, out, new, defer, fail)
struct director *dp; /* director entry */
struct addr *in; /* input local-form addrs */
struct addr **out; /* output resolved addrs */
struct addr **new; /* output new addrs to resolve */
struct addr **defer; /* addrs to defer to a later time */
struct addr **fail; /* unresolvable addrs */
{
struct include_private *priv; /* private storage */
struct addr *pass = NULL; /* addr structures to return */
struct addr *cur; /* addr being processed */
struct addr *next; /* next addr to process */
priv = (struct include_private *)dp->private;
for (cur = in; cur; cur = next) {
next = cur->succ;
if (strncmpic(cur->remainder, ":include:", sizeof(":include:")-1)) {
/* not equal to :include:* */
cur->succ = pass;
pass = cur;
} else {
/* a mailing list */
if (priv->matchdirector &&
cur->parent &&
cur->parent->director &&
!EQ(priv->matchdirector, cur->parent->director->name))
{
continue;
}
include_internal(dp, cur, new, 0, (char *)NULL,
(char *)NULL, (char *)NULL, defer, fail);
}
}
return pass;
}
/*ARGSUSED*/
void
dtv_genericinclude(dp, in, retry, okay, defer, fail)
struct director *dp; /* director entry */
struct addr *in; /* input local-form addrs */
struct addr **retry; /* output list of unmatched addrs */
struct addr **okay; /* output list of verified addrs */
struct addr **defer; /* temporariliy unverifiable addrs */
struct addr **fail; /* unverified addrs */
{
/*
* mailing list form addresses must have a parent. Since verifies
* are only one level deep, mailing never match for verifies.
*/
insert_addr_list(in, retry, (struct error *)NULL);
}
char *
dtb_genericinclude(dp, attrs)
struct director *dp; /* director entry being defined */
struct attribute *attrs; /* list of per-driver attributes */
{
dtb_internal_include(dp, attrs);
}