qmail-qmtpd.c
changeset 0 068428edee47
equal deleted inserted replaced
-1:000000000000 0:068428edee47
       
     1 #include "stralloc.h"
       
     2 #include "substdio.h"
       
     3 #include "qmail.h"
       
     4 #include "now.h"
       
     5 #include "str.h"
       
     6 #include "fmt.h"
       
     7 #include "env.h"
       
     8 #include "sig.h"
       
     9 #include "rcpthosts.h"
       
    10 #include "auto_qmail.h"
       
    11 #include "readwrite.h"
       
    12 #include "control.h"
       
    13 #include "received.h"
       
    14 
       
    15 void badproto() { _exit(100); }
       
    16 void resources() { _exit(111); }
       
    17 
       
    18 int safewrite(fd,buf,len) int fd; char *buf; int len;
       
    19 {
       
    20   int r;
       
    21   r = write(fd,buf,len);
       
    22   if (r <= 0) _exit(0);
       
    23   return r;
       
    24 }
       
    25 
       
    26 char ssoutbuf[256];
       
    27 substdio ssout = SUBSTDIO_FDBUF(safewrite,1,ssoutbuf,sizeof ssoutbuf);
       
    28 
       
    29 int saferead(fd,buf,len) int fd; char *buf; int len;
       
    30 {
       
    31   int r;
       
    32   substdio_flush(&ssout);
       
    33   r = read(fd,buf,len);
       
    34   if (r <= 0) _exit(0);
       
    35   return r;
       
    36 }
       
    37 
       
    38 char ssinbuf[512];
       
    39 substdio ssin = SUBSTDIO_FDBUF(saferead,0,ssinbuf,sizeof ssinbuf);
       
    40 
       
    41 unsigned long getlen()
       
    42 {
       
    43   unsigned long len = 0;
       
    44   char ch;
       
    45   for (;;) {
       
    46     substdio_get(&ssin,&ch,1);
       
    47     if (ch == ':') return len;
       
    48     if (len > 200000000) resources();
       
    49     len = 10 * len + (ch - '0');
       
    50   }
       
    51 }
       
    52 
       
    53 void getcomma()
       
    54 {
       
    55   char ch;
       
    56   substdio_get(&ssin,&ch,1);
       
    57   if (ch != ',') badproto();
       
    58 }
       
    59 
       
    60 unsigned int databytes = 0;
       
    61 unsigned int bytestooverflow = 0;
       
    62 struct qmail qq;
       
    63 
       
    64 char buf[1000];
       
    65 char buf2[100];
       
    66 
       
    67 char *remotehost;
       
    68 char *remoteinfo;
       
    69 char *remoteip;
       
    70 char *local;
       
    71 
       
    72 stralloc failure = {0};
       
    73 
       
    74 char *relayclient;
       
    75 int relayclientlen;
       
    76 
       
    77 main()
       
    78 {
       
    79   char ch;
       
    80   int i;
       
    81   unsigned long biglen;
       
    82   unsigned long len;
       
    83   int flagdos;
       
    84   int flagsenderok;
       
    85   int flagbother;
       
    86   unsigned long qp;
       
    87   char *result;
       
    88   char *x;
       
    89   unsigned long u;
       
    90  
       
    91   sig_pipeignore();
       
    92   sig_alarmcatch(resources);
       
    93   alarm(3600);
       
    94  
       
    95   if (chdir(auto_qmail) == -1) resources();
       
    96  
       
    97   if (control_init() == -1) resources();
       
    98   if (rcpthosts_init() == -1) resources();
       
    99   relayclient = env_get("RELAYCLIENT");
       
   100   relayclientlen = relayclient ? str_len(relayclient) : 0;
       
   101  
       
   102   if (control_readint(&databytes,"control/databytes") == -1) resources();
       
   103   x = env_get("DATABYTES");
       
   104   if (x) { scan_ulong(x,&u); databytes = u; }
       
   105   if (!(databytes + 1)) --databytes;
       
   106  
       
   107   remotehost = env_get("TCPREMOTEHOST");
       
   108   if (!remotehost) remotehost = "unknown";
       
   109   remoteinfo = env_get("TCPREMOTEINFO");
       
   110   remoteip = env_get("TCPREMOTEIP");
       
   111   if (!remoteip) remoteip = "unknown";
       
   112   local = env_get("TCPLOCALHOST");
       
   113   if (!local) local = env_get("TCPLOCALIP");
       
   114   if (!local) local = "unknown";
       
   115  
       
   116   for (;;) {
       
   117     if (!stralloc_copys(&failure,"")) resources();
       
   118     flagsenderok = 1;
       
   119  
       
   120     len = getlen();
       
   121     if (len == 0) badproto();
       
   122  
       
   123     if (databytes) bytestooverflow = databytes + 1;
       
   124     if (qmail_open(&qq) == -1) resources();
       
   125     qp = qmail_qp(&qq);
       
   126  
       
   127     substdio_get(&ssin,&ch,1);
       
   128     --len;
       
   129     if (ch == 10) flagdos = 0;
       
   130     else if (ch == 13) flagdos = 1;
       
   131     else badproto();
       
   132  
       
   133     received(&qq,"QMTP",local,remoteip,remotehost,remoteinfo,(char *) 0);
       
   134  
       
   135     /* XXX: check for loops? only if len is big? */
       
   136  
       
   137     if (flagdos)
       
   138       while (len > 0) {
       
   139         substdio_get(&ssin,&ch,1);
       
   140         --len;
       
   141         while ((ch == 13) && len) {
       
   142           substdio_get(&ssin,&ch,1);
       
   143           --len;
       
   144           if (ch == 10) break;
       
   145           if (bytestooverflow) if (!--bytestooverflow) qmail_fail(&qq);
       
   146           qmail_put(&qq,"\015",1);
       
   147         }
       
   148         if (bytestooverflow) if (!--bytestooverflow) qmail_fail(&qq);
       
   149         qmail_put(&qq,&ch,1);
       
   150       }
       
   151     else {
       
   152       if (databytes)
       
   153         if (len > databytes) {
       
   154           bytestooverflow = 0;
       
   155           qmail_fail(&qq);
       
   156         }
       
   157       while (len > 0) { /* XXX: could speed this up, obviously */
       
   158         substdio_get(&ssin,&ch,1);
       
   159         --len;
       
   160         qmail_put(&qq,&ch,1);
       
   161       }
       
   162     }
       
   163     getcomma();
       
   164  
       
   165     len = getlen();
       
   166  
       
   167     if (len >= 1000) {
       
   168       buf[0] = 0;
       
   169       flagsenderok = 0;
       
   170       for (i = 0;i < len;++i)
       
   171         substdio_get(&ssin,&ch,1);
       
   172     }
       
   173     else {
       
   174       for (i = 0;i < len;++i) {
       
   175         substdio_get(&ssin,buf + i,1);
       
   176         if (!buf[i]) flagsenderok = 0;
       
   177       }
       
   178       buf[len] = 0;
       
   179     }
       
   180     getcomma();
       
   181  
       
   182     flagbother = 0;
       
   183     qmail_from(&qq,buf);
       
   184     if (!flagsenderok) qmail_fail(&qq);
       
   185  
       
   186     biglen = getlen();
       
   187     while (biglen > 0) {
       
   188       if (!stralloc_append(&failure,"")) resources();
       
   189  
       
   190       len = 0;
       
   191       for (;;) {
       
   192         if (!biglen) badproto();
       
   193         substdio_get(&ssin,&ch,1);
       
   194         --biglen;
       
   195         if (ch == ':') break;
       
   196         if (len > 200000000) resources();
       
   197         len = 10 * len + (ch - '0');
       
   198       }
       
   199       if (len >= biglen) badproto();
       
   200       if (len + relayclientlen >= 1000) {
       
   201         failure.s[failure.len - 1] = 'L';
       
   202         for (i = 0;i < len;++i)
       
   203           substdio_get(&ssin,&ch,1);
       
   204       }
       
   205       else {
       
   206         for (i = 0;i < len;++i) {
       
   207           substdio_get(&ssin,buf + i,1);
       
   208           if (!buf[i]) failure.s[failure.len - 1] = 'N';
       
   209         }
       
   210         buf[len] = 0;
       
   211  
       
   212         if (relayclient)
       
   213           str_copy(buf + len,relayclient);
       
   214         else
       
   215           switch(rcpthosts(buf,len)) {
       
   216             case -1: resources();
       
   217             case 0: failure.s[failure.len - 1] = 'D';
       
   218           }
       
   219  
       
   220         if (!failure.s[failure.len - 1]) {
       
   221           qmail_to(&qq,buf);
       
   222           flagbother = 1;
       
   223         }
       
   224       }
       
   225       getcomma();
       
   226       biglen -= (len + 1);
       
   227     }
       
   228     getcomma();
       
   229  
       
   230     if (!flagbother) qmail_fail(&qq);
       
   231     result = qmail_close(&qq);
       
   232     if (!flagsenderok) result = "Dunacceptable sender (#5.1.7)";
       
   233     if (databytes) if (!bytestooverflow) result = "Dsorry, that message size exceeds my databytes limit (#5.3.4)";
       
   234  
       
   235     if (*result)
       
   236       len = str_len(result);
       
   237     else {
       
   238       /* success! */
       
   239       len = 0;
       
   240       len += fmt_str(buf2 + len,"Kok ");
       
   241       len += fmt_ulong(buf2 + len,(unsigned long) now());
       
   242       len += fmt_str(buf2 + len," qp ");
       
   243       len += fmt_ulong(buf2 + len,qp);
       
   244       buf2[len] = 0;
       
   245       result = buf2;
       
   246     }
       
   247       
       
   248     len = fmt_ulong(buf,len);
       
   249     buf[len++] = ':';
       
   250     len += fmt_str(buf + len,result);
       
   251     buf[len++] = ',';
       
   252  
       
   253     for (i = 0;i < failure.len;++i)
       
   254       switch(failure.s[i]) {
       
   255         case 0:
       
   256           substdio_put(&ssout,buf,len);
       
   257           break;
       
   258         case 'D':
       
   259           substdio_puts(&ssout,"66:Dsorry, that domain isn't in my list of allowed rcpthosts (#5.7.1),");
       
   260           break;
       
   261         default:
       
   262           substdio_puts(&ssout,"46:Dsorry, I can't handle that recipient (#5.1.3),");
       
   263           break;
       
   264       }
       
   265  
       
   266     /* ssout will be flushed when we read from the network again */
       
   267   }
       
   268 }