Back to index

courier  0.68.2
Classes | Defines | Functions | Variables
local.c File Reference
#include "courier.h"
#include "rw.h"
#include "rfc822.h"
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>
#include <stdio.h>
#include <pwd.h>
#include "waitlib/waitlib.h"
#include "modulelist.h"
#include "sysconfdir.h"
#include <courierauth.h>

Go to the source code of this file.

Classes

struct  localauthinfo

Defines

#define syslog(a, b)
#define DEFAULTNAME   "alias@"

Functions

char * local_dotcourier (const char *, const char *, const char **)
static void rw_local (struct rw_info *, void(*)(struct rw_info *))
static void rw_del_local (struct rw_info *, void(*)(struct rw_info *), void(*)(struct rw_info *, const struct rfc822token *, const struct rfc822token *))
static int rw_local_filter (const char *, int, const char *, const char *, const char *, char *, unsigned)
struct rw_list * local_rw_install (const struct rw_install_info *p)
const char * local_rw_init ()
static int local_callback (struct authinfo *, void *)
static void cleanup ()

Variables

static int cleanup_set = 0

Define Documentation

#define DEFAULTNAME   "alias@"

Definition at line 36 of file local.c.

#define syslog (   a,
 
)

Definition at line 33 of file local.c.


Function Documentation

static void cleanup ( ) [static]

Definition at line 110 of file local.c.

{
}

Here is the caller graph for this function:

static int local_callback ( struct authinfo *  a,
void *  vp 
) [static]

Definition at line 432 of file local.c.

{
struct localauthinfo *lai=(struct localauthinfo *)vp;
struct rfc822token tacct, text, tuid, tgid, thomedir, tmaildir, tquota, trecip;
struct rfc822token te1, te2, te3, te4, te5, te6;
char   ubuf[40], gbuf[40];
char   *p;
uid_t  un;
gid_t  gn;

       lai->found=1;
       lai->exists=0;

       if (lai->ext && *lai->ext)
       {
       char   *ext=local_dotcourier(a->homedir, lai->ext, 0);

              if (!ext && errno == ENOENT)
                     return (0);   /* Not found */

              if (ext)      free(ext);
       }
       if (a->homedir == 0 || strchr(a->homedir, '\n') ||
              strchr(a->homedir, '!') ||
              (a->maildir && (strchr(a->maildir, '\n') ||
                     strchr(a->maildir, '!'))))
       {
              syslog(LOG_DAEMON|LOG_CRIT,
                     "Invalid homedir or maildir for %s - has \\n, !, is null.",
                            lai->address);
              return (1);
       }

       lai->exists=1;
/*
       Ok, we return the following information:

Host:

       account ! ext ! uid ! gid ! homedir ! maildir ! quota

Ext:
       non standard mailbox
*/
       tacct.next= &te1;
       tacct.token=0;
       tacct.ptr=a->address;
       tacct.len=strlen(tacct.ptr);

       te1.next= &text;
       te1.token='!';
       te1.ptr="!";
       te1.len=1;

       text.next= &te2;
       text.token=0;
       text.ptr=lai->ext;
       if (text.ptr == 0)   text.ptr="";
       text.len=strlen(text.ptr);

       te2.next= &tuid;
       te2.token='!';
       te2.ptr="!";
       te2.len=1;

       if (a->sysuserid)
              un= *a->sysuserid;
       else
       {
       struct passwd *pw=getpwnam(a->sysusername);

              if (!pw)
              {
                     syslog(LOG_DAEMON|LOG_CRIT,
                            "getpw(%s) failed - returned by authlib.",
                                   a->sysusername);

                     return (1);
              }
              un= pw->pw_uid;
       }

#if ALLOW_ROOT

#else
       if (un == 0)
       {
              return (-1);         /* Do not deliver to root */
       }
#endif
       gn=a->sysgroupid;

       p=ubuf+sizeof(ubuf)-1;
       *p=0;

       do
       {
              *--p= "0123456789"[ un % 10];
              un=un/10;
       } while (un);

       tuid.next=&te3;
       tuid.token=0;
       tuid.ptr=p;
       tuid.len=strlen(p);

       te3.next= &tgid;
       te3.token='!';
       te3.ptr="!";
       te3.len=1;

       p=gbuf+sizeof(gbuf)-1;
       *p=0;
       do
       {
              *--p= "0123456789"[ gn % 10];
              gn=gn/10;
       } while (gn);

       tgid.next= &te4;
       tgid.token=0;
       tgid.ptr=p;
       tgid.len=strlen(p);

       te4.next= &thomedir;
       te4.token='!';
       te4.ptr="!";
       te4.len=1;

       thomedir.next=&te5;
       thomedir.token=0;
       thomedir.ptr= a->homedir;
       thomedir.len=strlen(thomedir.ptr);

       te5.next= &tmaildir;
       te5.token='!';
       te5.ptr="!";
       te5.len=1;

       tmaildir.next=&te6;
       tmaildir.token=0;
       tmaildir.ptr= a->maildir;
       if (tmaildir.ptr == 0)      tmaildir.ptr="";
       tmaildir.len=strlen(tmaildir.ptr);

       te6.next= &tquota;
       te6.token='!';
       te6.ptr="!";

       tquota.next=0;
       tquota.token=0;
       tquota.ptr= a->quota;
       if (tquota.ptr == 0) tquota.ptr="";
       tquota.len=strlen(tquota.ptr);

       trecip.next=0;
       trecip.token=0;
       trecip.ptr=lai->address;
       trecip.len=strlen(trecip.ptr);

       (*lai->delfunc)(lai->rwi, &tacct, &trecip);
       return (0);
}

Here is the call graph for this function:

Here is the caller graph for this function:

char* local_dotcourier ( const char *  ,
const char *  ,
const char **   
)

Definition at line 44 of file dotcourier.c.

{
char   *extbuf;
char   *x=local_extension();

       extbuf=(char *)courier_malloc(sizeof("." "--default")
                     +strlen(x) +strlen(ext));

       strcat(strcpy( extbuf, "." ), x);
       if (defaultptr)      *defaultptr=ext;

#if LOCAL_EXTENSIONS

       if (*ext)
       {
       char   *c;
       char   *filebuf=courier_malloc(sizeof("/." "--default")
                     +strlen(x) +strlen(ext)+strlen(homedir));
       int    isfirst=1;
       struct stat   stat_buf;

              strcat(strcat(extbuf, "-"), ext);
              for (c=extbuf+1; *c; c++)
                     if (*c == '.')       *c=':';

              if (defaultptr)
                     *defaultptr=0;

              while (lstat(
                     strcat(strcat(strcpy(filebuf, homedir), "/"),
                            extbuf), &stat_buf) < 0)
              {
                     /* We simply may not have the permissions to read
                     ** someone's home directory.  This can happen if
                     ** rewriting is carried out in a non-privileged
                     ** process which is submitting a mail message.
                     **
                     ** Unless we have an ENOENT at this point, assume
                     ** that this is the case, and presume that the
                     ** address is valid.  The downshot is that the
                     ** message will be accepted, and an internal bounce
                     ** is later generated.
                     */

                     if (errno != ENOENT)
                     {
                            free(extbuf);
                            free(filebuf);
                            return (0);
                     }

                     *strrchr(extbuf, '-')=0;
                     if (!isfirst)
                     {
                            if ((c=strrchr(extbuf, '-')) == 0)
                            {
                                   free(extbuf);
                                   free(filebuf);
                                   return (0);
                            }
                            *c=0;
                     }
                     isfirst=0;
                     if (defaultptr)
                            *defaultptr=ext+ (strlen(extbuf)-sizeof(".")
                                   -strlen(x)+1);
                     strcat(extbuf, "-default");
              }
              free(filebuf);
       }
#endif
       return (extbuf);
}

Here is the call graph for this function:

const char* local_rw_init ( )

Definition at line 62 of file local.c.

{
       return (0);
}
struct rw_list* local_rw_install ( const struct rw_install_info *  p) [read]

Definition at line 54 of file local.c.

{
static struct rw_list local_info={0, "module.local - " COURIER_COPYRIGHT,
                      rw_local, rw_del_local, rw_local_filter};

       return (&local_info);
}

Here is the call graph for this function:

static void rw_del_local ( struct rw_info *  rwi,
void(*)(struct rw_info *)  nextfunc,
void(*)(struct rw_info *, const struct rfc822token *,const struct rfc822token *)  delfunc 
) [static]

Definition at line 124 of file local.c.

{
struct rfc822token *p, **prevp;
char   *addr, *ext;
int    i;
struct localauthinfo lai;
char   *hostdomain=NULL;
struct rfc822token   hostdomaint;
#if LOCAL_EXTENSIONS
char *atdomain;
#endif

       if (!cleanup_set)
       {
              atexit(cleanup);
              cleanup_set=1;
       }

       prevp=0;
       for (p= *(prevp=&rwi->ptr); p; p= *(prevp= &p->next))
       {
              if (p->token == '!')
              {
                     (*nextfunc)(rwi);
                     return;
              }
              if (p->token == '@') break;
       }

       if (p)
       {
              /* If not a local domain, ignore */

              if (!configt_islocal(p->next, &hostdomain))
              {
                     (*nextfunc)(rwi);
                     return;
              }

              if (hostdomain)
              {
                     char *pp;

                     p->next= &hostdomaint;

                     for (pp=hostdomain; *pp; pp++)
                            *pp=tolower((int)(unsigned char)*pp);

                     hostdomaint.next=0;
                     hostdomaint.token=0;
                     hostdomaint.ptr=hostdomain;
                     hostdomaint.len=strlen(hostdomain);
              }
              else
                     *prevp=0;
       }

       /* Remove quotes from the local portion */

       for (p=rwi->ptr; p; p=p->next)
              if (p->token == '"') p->token=0;
       addr=rfc822_gettok(rwi->ptr);

       if (!addr)    clog_msg_errno();
       locallower(addr);

       if (strchr(addr, '!') || *addr == 0)
       {
              /* Can't have !s in an address, that's used a delimiter
              ** for the returned data.
              ** Can't have NULL addresses either.
              */

              goto not_found;
       }

       /*
       ** We do not accept local addresses that start with a period.  That is
       ** reserved for legacy alias handling.  If this is called from
       ** submit, we reject explicit addresses of that form.  These addresses
       ** are expanded from aliases, and then are inserted without calling
       ** the rewriting functions.  Subsequently we get here when
       ** we're in courierd, but RW_SUBMIT is not set.
       */

       if (*addr == '.')
       {
              if ((rwi->mode & (RW_SUBMIT|RW_SUBMITALIAS))
                     == RW_SUBMIT)
                     goto not_found;             /* Sorry */

              goto toalias;               /* Sorry again */
       }

#if LOCAL_EXTENSIONS
       atdomain=strrchr(addr, '@');
       if (atdomain)
              *atdomain++=0;
#endif

       i=0;
       for (ext=addr; *ext; ext++)
       {
#if LOCAL_EXTENSIONS
              if (*ext == '-' && ++i > 3)
                     break;
#endif
       }

       for (;;)
       {
       char *search_addr=addr;

#if LOCAL_EXTENSIONS
       char   c;
       char *alloc_buf=0;

              c= *ext;
              *ext=0;

              lai.ext=c ? ext+1:ext;

              if (atdomain)
              {
                     alloc_buf=malloc(strlen(addr)+strlen(atdomain)+2);
                     if (!alloc_buf)
                            clog_msg_errno();
                     strcat(strcat(strcpy(alloc_buf, addr), "@"),
                            atdomain);
                     search_addr=alloc_buf;
              }
#else
              lai.ext=0;
#endif
              lai.address=search_addr;
              lai.delfunc=delfunc;
              lai.rwi=rwi;
              lai.found=0;

              i=auth_getuserinfo("courier", search_addr,
                               local_callback, &lai);

#if LOCAL_EXTENSIONS
              if (alloc_buf)
                     free(alloc_buf);
#endif
              if (i == 0)
              {
                     if (lai.exists)
                     {
                            free(addr);
                            if (hostdomain)      free(hostdomain);
                            return;
                     }
                     goto not_found;
              }

              if (i > 0)
              {
                     free(addr);
                     if (hostdomain)      free(hostdomain);
                     (*rwi->err_func)(450,
                            "Service temporarily unavailable.", rwi);
                     return;
              }
#if LOCAL_EXTENSIONS
              *ext=c;

              while (ext > addr)
                     if (*--ext == '-')   break;
              if (ext == addr)
              {
                     if (atdomain)
                     {
                            lai.ext=addr;
                            lai.delfunc=delfunc;
                            lai.rwi=rwi;
                            lai.found=0;

                            alloc_buf=malloc(sizeof(DEFAULTNAME)
                                           +strlen(atdomain));
                            if (!alloc_buf)
                                   clog_msg_errno();

                            strcat(strcpy(alloc_buf, DEFAULTNAME),
                                   atdomain);

                            i=auth_getuserinfo("courier",
                                             alloc_buf,
                                             &local_callback, &lai);
                            free(alloc_buf);
                            if (i == 0)
                            {
                                   if (lai.exists)
                                   {
                                          free(addr);
                                          if (hostdomain)
                                                 free(hostdomain);
                                          return;
                                   }
                                   goto not_found;
                            }
                            if (i > 0)
                            {
                                   free(addr);
                                   if (hostdomain)      free(hostdomain);
                                   (*rwi->err_func)(450,
                                                  "Service temporarily unavailable.", rwi);
                                   return;
                            }
                     }
                     break;
              }
#else
              break;
#endif
       }

#if LOCAL_EXTENSIONS
       if (atdomain)
              atdomain[-1]='@';    /* Put back what was taken */
#endif

       /* Try to deliver to an alias defined in ${sysconfdir}/aliasdir */

toalias:

       {
       struct authinfo aa;
       static const uid_t   mailuid=MAILUID;

              memset(&aa, 0, sizeof(aa));
              aa.homedir= ALIASDIR;
              aa.sysuserid= &mailuid;
              aa.sysgroupid=MAILGID;
              lai.address=aa.address="alias";

              lai.ext=addr;
              lai.delfunc=delfunc;
              lai.rwi=rwi;
              lai.found=0;

              i=local_callback( &aa, &lai );

              if (i == 0)
              {
                     if (lai.exists)
                     {
                            free(addr);
                            if (hostdomain)      free(hostdomain);
                            return;
                     }
                     goto not_found;
              }

              if (i > 0)
              {
                     free(addr);
                     if (hostdomain)      free(hostdomain);
                     (*rwi->err_func)(450,
                            "Service temporarily unavailable.", rwi);
                     return;
              }
       }

not_found:
       /*
       ** When submit is being called by the sendmail command line,
       ** don't reject unknown addresses, instead accept them (and bounce
       ** them later, when we get here from courierd's main loop).
       ** Otherwise, couriermlm will barf when a local address disappears.
       */

       if ((rwi->mode & (RW_SUBMIT|RW_EXPN|RW_VERIFY)) == RW_SUBMIT &&
           rwi->smodule &&
           (strcmp(rwi->smodule, "local") == 0 ||
            strcmp(rwi->smodule, "uucp") == 0))
       {
              free(addr);
              (*delfunc)(rwi, rwi->ptr, rwi->ptr);
              if (hostdomain)      free(hostdomain);

              return;
       }

       {
              char buf[256];

              char *orig_addr=rfc822_gettok(rwi->ptr);

              buf[255]=0;

              snprintf(buf, 255, "User <%s> unknown",
                      orig_addr ? orig_addr:"");
              free(addr);
              if (hostdomain)      free(hostdomain);

              if (orig_addr)
                     free(orig_addr);
              (*rwi->err_func)(550, buf, rwi);
       }
       return;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void rw_local ( struct rw_info *  p,
void(*)(struct rw_info *)  func 
) [static]

Definition at line 67 of file local.c.

{
       if (p->mode & RW_SUBMIT)
       {
              if (p->mode & RW_ENVSENDER)
              {
              char   *q=rfc822_gettok(p->ptr);

                     if (!q)       clog_msg_errno();

/*********************************************************************
**
** To filter messages originating from the command line based on the
** sender, insert code here to call p->rw_info to reject the message.
**
** The sender can be identified via getuid().  Note, though, that the
** process is running setgid to MAILGID.
**
*********************************************************************/

                     free(q);
              }
       }

       rw_local_defaulthost(p, func);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int rw_local_filter ( const char *  smodule,
int  fd,
const char *  host,
const char *  addr,
const char *  sender,
char *  buf,
unsigned  bufsize 
) [static]

Definition at line 613 of file local.c.

{
int    p[2];
pid_t  pid;
const  char *maildrop;
char   errbuf[256];
int    l;
char   *s, *t;
const char *uidgids;
const char *homedir;
const char *defaults;
const char *quota;

       if ((maildrop=config_maildropfilter()) == 0 || *maildrop != '/')
              return (0);

       /* host is account!ext!blah... */

       s=strdup(host);
       if (!s)
       {
              strcpy(buf, "450 malloc() failed.");
              return (1);
       }
       
       host=s;

       t=strchr(s, '!');
       if (!t)
       {
              free(s);
              return (0);
       }
       *t++=0;
       addr=t;
       t=strchr(t, '!');
       if (!t)
       {
              free(s);
              return (0);
       }
       *t++=0;
       uidgids=t;
       t=strchr(t, '!');
       if (!t)
       {
              free(s);
              return (0);
       }
       *t++ = '/';
       t=strchr(t, '!');
       if (!t)
       {
              free(s);
              return (0);
       }
       *t++=0;
       homedir=t;
       t=strchr(t, '!');
       if (!t)
       {
              free(s);
              return (0);
       }
       *t++=0;
       defaults=t;
       t=strchr(t, '!');
       if (!t)
       {
              free(s);
              return (0);
       }
       *t++=0;
       quota=t;

       if (pipe(p) < 0)
       {
              free(s);
              strcpy(buf, "450 pipe() failed.");
              return (1);
       }

       if ((pid=fork()) < 0)
       {
              free(s);
              strcpy(buf, "450 fork() failed.");
              return (1);
       }

       if (pid == 0)
       {
       char   *argv[11];

              close(0);
              if (fd < 0)
                     open("/dev/null", O_RDONLY);
              else
              {
                     dup2(fd, 0);
                     close(fd);
              }
              dup2(p[1], 1);
              dup2(p[1], 2);
              close(p[0]);
              close(p[1]);

              argv[0]=strrchr(maildrop, '/')+1;
              argv[1]="-D";
              argv[2]=(char *)uidgids;
              argv[3]="-M";
              argv[4]=malloc((addr ? strlen(addr):0)+sizeof("smtpfilter-"));
              if (!argv[4])
              {
                     printf("450 Out of memory.\n");
                     fflush(stdout);
                     _exit(0);
              }
              strcpy(argv[4], fd < 0 ? "rcptfilter":"smtpfilter");
              if (addr && *addr)
                     strcat(strcat(argv[4], "-"), addr);
              argv[5]=getenv("TCPREMOTEHOST");
              if (!argv[5]) argv[5]="";
              argv[6]=getenv("TCPREMOTEIP");
              if (!argv[6]) argv[6]="";
              argv[7]=(char *)sender;
              if (!argv[7]) argv[7]="";
              putenv(strcat(strcpy(courier_malloc(sizeof("SENDER=")+
                                   strlen(argv[7])), "SENDER="),
                                   argv[7]));

              putenv(strcat(strcpy(courier_malloc(sizeof("HOME=")+
                     strlen(homedir)), "HOME="), homedir));
              putenv(strcat(strcpy(courier_malloc(sizeof("DEFAULT=")+
                     strlen(defaults)), "DEFAULT="), defaults));
              putenv(strcat(strcpy(courier_malloc(sizeof("MAILDIRQUOTA=")+
                     strlen(quota)), "MAILDIRQUOTA="), quota));


              argv[8]=getenv("BOUNCE");
              if (!argv[8]) argv[8]="";
              argv[9]=getenv("BOUNCE2");
              if (!argv[9]) argv[9]="";
              argv[10]=0;
              execv(maildrop, argv);
              _exit(0);     /* Assume spam filter isn't installed */
       }
       free(s);

       close(p[1]);

       while ((l=read(p[0], errbuf, sizeof(errbuf))) > 0)
       {
              if (l > bufsize-1)
                     l=bufsize-1;
              memcpy(buf, errbuf, l);
              buf += l;
              bufsize -= l;
       }
       close(p[0]);
       *buf=0;

       while (wait(&l) != pid)
              ;

       if (WIFEXITED(l))
              return (WEXITSTATUS(l));

       return (1);
}

Here is the call graph for this function:

Here is the caller graph for this function:


Variable Documentation

int cleanup_set = 0 [static]

Definition at line 106 of file local.c.