Back to index

courier  0.68.2
esmtp.c
Go to the documentation of this file.
00001 /*
00002 ** Copyright 1998 - 2002 Double Precision, Inc.
00003 ** See COPYING for distribution information.
00004 */
00005 
00006 #if    HAVE_CONFIG_H
00007 #include      "config.h"
00008 #endif
00009 #include      "courier.h"
00010 #include      "rw.h"
00011 #include      "rfc822.h"
00012 #include      "dbobj.h"
00013 #include      "comfax.h"
00014 #include      <string.h>
00015 #include      <ctype.h>
00016 #include      <stdlib.h>
00017 #if    HAVE_UNISTD_H
00018 #include      <unistd.h>
00019 #endif
00020 
00021 static int acceptdomain(const struct rfc822token *);
00022 static void rw_esmtp(struct rw_info *, void (*)(struct rw_info *));
00023 
00024 static void rw_del_esmtp(struct rw_info *, void (*)(struct rw_info *),
00025               void (*)(struct rw_info *, const struct rfc822token *,
00026                      const struct rfc822token *));
00027 
00028 struct rw_list *esmtp_rw_install(const struct rw_install_info *p)
00029 {
00030 static struct rw_list esmtp_info={0, "module.esmtp - " COURIER_COPYRIGHT,
00031                              rw_esmtp, rw_del_esmtp, 0};
00032 
00033        return (&esmtp_info);
00034 }
00035 
00036 const char *esmtp_rw_init()
00037 {
00038        return (0);
00039 }
00040 
00041 static struct rfc822token *rfc822check(int err_code,
00042        struct rw_info *info, int allow_faxdomain)
00043 {
00044 struct rfc822token *p, *s;
00045 
00046        for (p=0, s=info->ptr; s; s=s->next)
00047               if (s->token == '@') p=s;
00048        if (p)
00049        {
00050        int    seendot=1;
00051        int    seen1dot=0;
00052        int    dummy;
00053 
00054               for (s=p->next; s; s=s->next)
00055               {
00056                      if (s->token == 0)
00057                      {
00058                             if (!seendot) break;
00059                             seendot=0;
00060                      }
00061                      else if (s->token == '.')
00062                      {
00063                             if (seendot)  break;
00064                             seendot=1;
00065                             seen1dot=1;
00066                      }
00067                      else   break;
00068               }
00069 
00070               /*
00071               ** Normally, @fax-lowres would trip the above check.
00072               ** If rfc822check is being called to validate the recipient
00073               ** address, relax this syntax check.
00074               */
00075 
00076               if (s == 0 && !seen1dot && allow_faxdomain &&
00077                   p->next && !p->next->next && p->next->token == 0 &&
00078                   comgetfaxoptsn(p->next->ptr, p->next->len, &dummy) == 0 &&
00079                   getenv("FAXRELAYCLIENT") != NULL)
00080                      return (p);
00081                   
00082               if (s == 0 && seen1dot)     return (p);
00083        }
00084 
00085        (*info->err_func)(err_code, "Syntax error.", info);
00086        return (0);
00087 }
00088 
00089 static int rwrecip(struct rw_info *info)
00090 {
00091 struct rfc822token *p, *q;
00092 
00093        if (rfc822check(513, info, 1) == 0)       return (-1);
00094 
00095        /*
00096               Rewrite @foobar:foo@bar into foo@bar if @foobar is us.
00097        */
00098 
00099        for (;;)
00100        {
00101               if (info->ptr == 0 || info->ptr->token != '@')
00102                      break;
00103               for (p=info->ptr; p->next; p=p->next)
00104                      if (p->next->token == ':')  break;
00105               if (!p->next) break;
00106               q=p->next;
00107               p->next=0;
00108               if (configt_islocal(info->ptr->next, 0))
00109               {
00110                      info->ptr=q->next;
00111                      continue;
00112               }
00113               /* foobar is nonlocal, rewrite as foo%bar@foobar */
00114               p=info->ptr;
00115               info->ptr=q->next;
00116               while (q->next)
00117                      q=q->next;
00118               q->next=p;
00119               break;
00120        }
00121 
00122        /* Rewrite foo@bar@foobar as foo%bar@foobar */
00123 
00124        for (p=info->ptr, q=p; p; p=p->next)
00125               if (p->token == ':') q=p->next;
00126 
00127        p=0;
00128        while (q)
00129        {
00130               if (q->token == '@' || q->token == '%')
00131               {
00132                      if (p) p->token='%';
00133                      p=q;
00134               }
00135               q=q->next;
00136        }
00137        if (p) p->token='@';
00138 
00139        /* One more time */
00140 
00141        if ((p=rfc822check(513, info, 1)) == 0)   return (-1);
00142 
00143        /* When called from submit (initial receipt of a message),
00144        ** either RELAYCLIENT must be set, or this must be one of our domains.
00145        */
00146 
00147        if (!getenv("RELAYCLIENT") && !acceptdomain(p->next))
00148        {
00149               (*info->err_func)(513, "Relaying denied.", info);
00150               return (-1);
00151        }
00152        return (0);
00153 }
00154 
00155 static int isindomaindb(char *address, struct dbobj *db)
00156 {
00157 char   *p;
00158 int    n=8;
00159 
00160        for (p=address; *p; p++)
00161               *p=tolower(*p);
00162 
00163        p=address;
00164 
00165        while (*p && n)
00166        {
00167               if (dbobj_exists(db, p, strlen(p)))
00168                      return (1);
00169               if (*p == '.')       ++p;
00170               while (*p && *p != '.')
00171                      ++p;
00172        }
00173        return (0);
00174 }
00175 
00176 static int ispercenthack(struct rfc822token *ptr)
00177 {
00178 static char *percenthack=0;
00179 static struct dbobj percenthackdat;
00180 char   *p;
00181 
00182        if (!percenthack)    /* First time */
00183        {
00184               p=config_localfilename("esmtppercentrelay");
00185 
00186               percenthack=readfile(p, 0);
00187               free(p);
00188 
00189               if (percenthack)
00190                      removecomments(percenthack);
00191               else
00192                      percenthack="";
00193               dbobj_init(&percenthackdat);
00194               p=config_localfilename("esmtppercentrelay.dat");
00195               dbobj_open(&percenthackdat, p, "R");
00196               free(p);
00197        }
00198 
00199        if (*percenthack == 0 && !dbobj_isopen(&percenthackdat))
00200               return (0);   /* Don't bother */
00201 
00202        p=rfc822_gettok(ptr);
00203        if (config_is_indomain(p, percenthack) ||
00204               (dbobj_isopen(&percenthackdat) &&
00205                      isindomaindb(p, &percenthackdat)))
00206        {
00207               free(p);
00208               return (1);
00209        }
00210 
00211        free(p);
00212        return (0);
00213 }
00214 
00215 /*
00216 ** Transform  foo%bar@foobar into foo@bar, if foobar is a local domain,
00217 ** and bar can be found in percenthack.
00218 */
00219 
00220 static void rwinput(struct rw_info *info, void (*func)(struct rw_info *))
00221 {
00222 struct rfc822token *p, *q, **start, **ptr;
00223 
00224        for (start= &info->ptr, p=info->ptr; p; p=p->next)
00225               if (p->token == ':')
00226                      start =&p->next;
00227 
00228        for (p=0, ptr=start; *ptr; ptr= &(*ptr)->next)
00229        {
00230               if ( (*ptr)->token == '%' )
00231                      p= *ptr;
00232               if ( (*ptr)->token == '@' )
00233                      break;
00234        }
00235        if (!p || *ptr == 0 || !configt_islocal((*ptr)->next, 0))
00236        {
00237               (*func)(info);
00238               return;
00239        }
00240 
00241        q= *ptr;
00242        *ptr=0;
00243        if (ispercenthack(p->next))
00244               p->token='@';
00245        else   *ptr=q;
00246        (*func)(info);
00247 }
00248 
00249 /* Do the opposite of rwinput */
00250 
00251 static void rwoutput(struct rw_info *info, void (*func)(struct rw_info *))
00252 {
00253 struct rfc822token *p, *q, **r;
00254 const char *me;
00255 struct rfc822t       *tp;
00256 struct rfc822token at;
00257 
00258        if (info->ptr == 0)
00259        {
00260               (*func)(info);
00261               return;
00262        }
00263 
00264        for (q=0, p=info->ptr; p; p=p->next)
00265               if (p->token == '@') q=p;
00266 
00267        if (q)
00268        {
00269               if (!ispercenthack(q->next))
00270               {
00271                      (*func)(info);
00272                      return;
00273               }
00274 
00275               q->token='%';
00276        }
00277 
00278        for (r= &info->ptr; *r; r= &(*r)->next)
00279               ;
00280 
00281        at.token='@';
00282        at.ptr=0;
00283        at.len=0;
00284        me=config_defaultdomain();
00285        tp=rw_rewrite_tokenize(me);
00286        at.next=tp->tokens;
00287 
00288        *r=&at;
00289        (*func)(info);
00290        *r=0;
00291        rfc822t_free(tp);
00292 }
00293 
00294 static void rw_esmtp(struct rw_info *info, void (*func)(struct rw_info *))
00295 {
00296        if ((info->mode & RW_SUBMIT)       /* From submit process */
00297               && (info->mode & RW_OUTPUT) == 0)
00298                             /* NOT for output rewriting */
00299        {
00300               if (info->mode & RW_ENVSENDER)
00301               {
00302                      if (info->ptr &&
00303                             (info->ptr->token || info->ptr->len))
00304                                    /* NULL sender OK */
00305                      {
00306                             if (rfc822check(517, info, 0) == 0)
00307                                    return;
00308                      }
00309               }
00310               else if (info->mode & RW_ENVRECIPIENT)
00311               {
00312                      if (rwrecip(info))   return;
00313               }
00314        }
00315 
00316        if (info->mode & RW_OUTPUT)
00317               rwoutput(info, func);
00318        else
00319               rwinput(info, func);
00320 }
00321 
00322 static void rw_del_esmtp(struct rw_info *rwi,
00323               void (*nextfunc)(struct rw_info *),
00324               void (*delfunc)(struct rw_info *, const struct rfc822token *,
00325                      const struct rfc822token *))
00326 {
00327 struct rfc822token *p;
00328 char   *c;
00329 struct rfc822token host, addr;
00330 
00331        for (p=rwi->ptr; p; p=p->next)
00332        {
00333               if (p->token == '!')
00334               {
00335                      (*nextfunc)(rwi);    /* We don't talk UUCP */
00336                      return;
00337               }
00338               if (p->token == '@') break;
00339        }
00340 
00341        if (!p)
00342        {
00343               (*nextfunc)(rwi);
00344               return;
00345        }
00346 
00347        if (configt_islocal(p->next, 0))
00348        {
00349               (*nextfunc)(rwi);
00350                             /* Local module should handle it */
00351               return;
00352        }
00353 
00354        if (rwi->mode & RW_VERIFY)
00355        {
00356               (*rwi->err_func)(550, "Remote address.", rwi);
00357               return;
00358        }
00359 
00360        c=rfc822_gettok(rwi->ptr);
00361        if (!c)       clog_msg_errno();
00362        domainlower(c);
00363        host.next=0;
00364        host.token=0;
00365        host.ptr=strchr(c, '@')+1;
00366        host.len=strlen(host.ptr);
00367        addr.next=0;
00368        addr.token=0;
00369        addr.ptr=c;
00370        addr.len=strlen(c);
00371 
00372        (*delfunc)(rwi, &host, &addr);
00373        free(c);
00374 }
00375 
00376 
00377 /************************************************************************/
00378 /*               Should we accept mail for this domain?                 */
00379 /************************************************************************/
00380 
00381 static int acceptdomain(const struct rfc822token *t)
00382 {
00383 char   *address=rfc822_gettok(t);
00384 int    rc;
00385 
00386 static const char *acceptdomains=0;
00387 static struct dbobj acceptdomainsdb;
00388 
00389        if (!address) clog_msg_errno();
00390 
00391        if (!acceptdomains)
00392        {
00393         char *filename=config_localfilename("esmtpacceptmailfor");
00394        char   *buf;
00395 
00396               buf=readfile(filename, 0);
00397 
00398                 free(filename);
00399                 if (!buf)
00400                      acceptdomains=config_me();
00401                 else
00402                 {
00403                         removecomments(buf);
00404                      acceptdomains=buf;
00405                 }
00406 
00407               dbobj_init(&acceptdomainsdb);
00408               filename=config_localfilename("esmtpacceptmailfor.dat");
00409               dbobj_open(&acceptdomainsdb, filename, "R");
00410               free(filename);
00411        }
00412 
00413        rc=config_is_indomain(address, acceptdomains);
00414        if (rc == 0 && dbobj_isopen(&acceptdomainsdb))
00415               rc=isindomaindb(address, &acceptdomainsdb);
00416 
00417        free(address);
00418        return (rc);
00419 }