source: trunk/third/sendmail/sendmail/collect.c @ 22421

Revision 22421, 23.9 KB checked in by zacheiss, 18 years ago (diff)
Apply patches from 3-22-06 CERT advisory.
Line 
1/*
2 * Copyright (c) 1998-2002 Sendmail, Inc. and its suppliers.
3 *      All rights reserved.
4 * Copyright (c) 1983, 1995-1997 Eric P. Allman.  All rights reserved.
5 * Copyright (c) 1988, 1993
6 *      The Regents of the University of California.  All rights reserved.
7 *
8 * By using this file, you agree to the terms and conditions set
9 * forth in the LICENSE file which can be found at the top level of
10 * the sendmail distribution.
11 *
12 */
13
14#include <sendmail.h>
15
16SM_RCSID("@(#)$Id: collect.c,v 1.2 2006-03-23 21:02:45 zacheiss Exp $")
17
18static void     dferror __P((SM_FILE_T *volatile, char *, ENVELOPE *));
19static void     eatfrom __P((char *volatile, ENVELOPE *));
20static void     collect_doheader __P((ENVELOPE *));
21static SM_FILE_T *collect_dfopen __P((ENVELOPE *));
22static SM_FILE_T *collect_eoh __P((ENVELOPE *, int, int));
23
24/*
25**  COLLECT_EOH -- end-of-header processing in collect()
26**
27**      Called by collect() when it encounters the blank line
28**      separating the header from the message body, or when it
29**      encounters EOF in a message that contains only a header.
30**
31**      Parameters:
32**              e -- envelope
33**              numhdrs -- number of headers
34**              hdrslen -- length of headers
35**
36**      Results:
37**              NULL, or handle to open data file
38**
39**      Side Effects:
40**              end-of-header check ruleset is invoked.
41**              envelope state is updated.
42**              headers may be added and deleted.
43**              selects the queue.
44**              opens the data file.
45*/
46
47static SM_FILE_T *
48collect_eoh(e, numhdrs, hdrslen)
49        ENVELOPE *e;
50        int numhdrs;
51        int hdrslen;
52{
53        char hnum[16];
54        char hsize[16];
55
56        /* call the end-of-header check ruleset */
57        (void) sm_snprintf(hnum, sizeof hnum, "%d", numhdrs);
58        (void) sm_snprintf(hsize, sizeof hsize, "%d", hdrslen);
59        if (tTd(30, 10))
60                sm_dprintf("collect: rscheck(\"check_eoh\", \"%s $| %s\")\n",
61                           hnum, hsize);
62        (void) rscheck("check_eoh", hnum, hsize, e, RSF_UNSTRUCTURED|RSF_COUNT,
63                        3, NULL, e->e_id);
64
65        /*
66        **  Process the header,
67        **  select the queue, open the data file.
68        */
69
70        collect_doheader(e);
71        return collect_dfopen(e);
72}
73
74/*
75**  COLLECT_DOHEADER -- process header in collect()
76**
77**      Called by collect() after it has finished parsing the header,
78**      but before it selects the queue and creates the data file.
79**      The results of processing the header will affect queue selection.
80**
81**      Parameters:
82**              e -- envelope
83**
84**      Results:
85**              none.
86**
87**      Side Effects:
88**              envelope state is updated.
89**              headers may be added and deleted.
90*/
91
92static void
93collect_doheader(e)
94        ENVELOPE *e;
95{
96        /*
97        **  Find out some information from the headers.
98        **      Examples are who is the from person & the date.
99        */
100
101        eatheader(e, true, false);
102
103        if (GrabTo && e->e_sendqueue == NULL)
104                usrerr("No recipient addresses found in header");
105
106        /*
107        **  If we have a Return-Receipt-To:, turn it into a DSN.
108        */
109
110        if (RrtImpliesDsn && hvalue("return-receipt-to", e->e_header) != NULL)
111        {
112                ADDRESS *q;
113
114                for (q = e->e_sendqueue; q != NULL; q = q->q_next)
115                        if (!bitset(QHASNOTIFY, q->q_flags))
116                                q->q_flags |= QHASNOTIFY|QPINGONSUCCESS;
117        }
118
119        /*
120        **  Add an appropriate recipient line if we have none.
121        */
122
123        if (hvalue("to", e->e_header) != NULL ||
124            hvalue("cc", e->e_header) != NULL ||
125            hvalue("apparently-to", e->e_header) != NULL)
126        {
127                /* have a valid recipient header -- delete Bcc: headers */
128                e->e_flags |= EF_DELETE_BCC;
129        }
130        else if (hvalue("bcc", e->e_header) == NULL)
131        {
132                /* no valid recipient headers */
133                register ADDRESS *q;
134                char *hdr = NULL;
135
136                /* create a recipient field */
137                switch (NoRecipientAction)
138                {
139                  case NRA_ADD_APPARENTLY_TO:
140                        hdr = "Apparently-To";
141                        break;
142
143                  case NRA_ADD_TO:
144                        hdr = "To";
145                        break;
146
147                  case NRA_ADD_BCC:
148                        addheader("Bcc", " ", 0, e);
149                        break;
150
151                  case NRA_ADD_TO_UNDISCLOSED:
152                        addheader("To", "undisclosed-recipients:;", 0, e);
153                        break;
154                }
155
156                if (hdr != NULL)
157                {
158                        for (q = e->e_sendqueue; q != NULL; q = q->q_next)
159                        {
160                                if (q->q_alias != NULL)
161                                        continue;
162                                if (tTd(30, 3))
163                                        sm_dprintf("Adding %s: %s\n",
164                                                hdr, q->q_paddr);
165                                addheader(hdr, q->q_paddr, 0, e);
166                        }
167                }
168        }
169}
170
171/*
172**  COLLECT_DFOPEN -- open the message data file
173**
174**      Called by collect() after it has finished processing the header.
175**      Queue selection occurs at this point, possibly based on the
176**      envelope's recipient list and on header information.
177**
178**      Parameters:
179**              e -- envelope
180**
181**      Results:
182**              NULL, or a pointer to an open data file,
183**              into which the message body will be written by collect().
184**
185**      Side Effects:
186**              Calls syserr, sets EF_FATALERRS and returns NULL
187**              if there is insufficient disk space.
188**              Aborts process if data file could not be opened.
189**              Otherwise, the queue is selected,
190**              e->e_{dfino,dfdev,msgsize,flags} are updated,
191**              and a pointer to an open data file is returned.
192*/
193
194static SM_FILE_T *
195collect_dfopen(e)
196        ENVELOPE *e;
197{
198        MODE_T oldumask = 0;
199        int dfd;
200        struct stat stbuf;
201        SM_FILE_T *df;
202        char *dfname;
203
204        if (!setnewqueue(e))
205                return NULL;
206
207        dfname = queuename(e, DATAFL_LETTER);
208        if (bitset(S_IWGRP, QueueFileMode))
209                oldumask = umask(002);
210        df = bfopen(dfname, QueueFileMode, DataFileBufferSize,
211                    SFF_OPENASROOT);
212        if (bitset(S_IWGRP, QueueFileMode))
213                (void) umask(oldumask);
214        if (df == NULL)
215        {
216                syserr("@Cannot create %s", dfname);
217                e->e_flags |= EF_NO_BODY_RETN;
218                flush_errors(true);
219                finis(true, true, ExitStat);
220                /* NOTREACHED */
221        }
222        dfd = sm_io_getinfo(df, SM_IO_WHAT_FD, NULL);
223        if (dfd < 0 || fstat(dfd, &stbuf) < 0)
224                e->e_dfino = -1;
225        else
226        {
227                e->e_dfdev = stbuf.st_dev;
228                e->e_dfino = stbuf.st_ino;
229        }
230        e->e_flags |= EF_HAS_DF;
231        return df;
232}
233
234/*
235**  COLLECT -- read & parse message header & make temp file.
236**
237**      Creates a temporary file name and copies the standard
238**      input to that file.  Leading UNIX-style "From" lines are
239**      stripped off (after important information is extracted).
240**
241**      Parameters:
242**              fp -- file to read.
243**              smtpmode -- if set, we are running SMTP: give an RFC821
244**                      style message to say we are ready to collect
245**                      input, and never ignore a single dot to mean
246**                      end of message.
247**              hdrp -- the location to stash the header.
248**              e -- the current envelope.
249**
250**      Returns:
251**              none.
252**
253**      Side Effects:
254**              If successful,
255**              - Data file is created and filled, and e->e_dfp is set.
256**              - The from person may be set.
257**              If the "enough disk space" check fails,
258**              - syserr is called.
259**              - e->e_dfp is NULL.
260**              - e->e_flags & EF_FATALERRS is set.
261**              - collect() returns.
262**              If data file cannot be created, the process is terminated.
263*/
264
265/* values for input state machine */
266#define IS_NORM         0       /* middle of line */
267#define IS_BOL          1       /* beginning of line */
268#define IS_DOT          2       /* read a dot at beginning of line */
269#define IS_DOTCR        3       /* read ".\r" at beginning of line */
270#define IS_CR           4       /* read a carriage return */
271
272/* values for message state machine */
273#define MS_UFROM        0       /* reading Unix from line */
274#define MS_HEADER       1       /* reading message header */
275#define MS_BODY         2       /* reading message body */
276#define MS_DISCARD      3       /* discarding rest of message */
277
278void
279collect(fp, smtpmode, hdrp, e)
280        SM_FILE_T *fp;
281        bool smtpmode;
282        HDR **hdrp;
283        register ENVELOPE *e;
284{
285        register SM_FILE_T *volatile df;
286        bool ignrdot;
287        int dbto;
288        register char *volatile bp;
289        int c;
290        bool inputerr;
291        bool headeronly;
292        char *buf;
293        int buflen;
294        int istate;
295        int mstate;
296        int hdrslen;
297        int numhdrs;
298        int afd;
299        unsigned char *pbp;
300        unsigned char peekbuf[8];
301        char bufbuf[MAXLINE];
302
303        df = NULL;
304        ignrdot = smtpmode ? false : IgnrDot;
305
306        /* timeout for I/O functions is in milliseconds */
307        dbto = smtpmode ? ((int) TimeOuts.to_datablock * 1000)
308                        : SM_TIME_FOREVER;
309        sm_io_setinfo(fp, SM_IO_WHAT_TIMEOUT, &dbto);
310        c = SM_IO_EOF;
311        inputerr = false;
312        headeronly = hdrp != NULL;
313        hdrslen = 0;
314        numhdrs = 0;
315        HasEightBits = false;
316        buf = bp = bufbuf;
317        buflen = sizeof bufbuf;
318        pbp = peekbuf;
319        istate = IS_BOL;
320        mstate = SaveFrom ? MS_HEADER : MS_UFROM;
321
322        /*
323        **  Tell ARPANET to go ahead.
324        */
325
326        if (smtpmode)
327                message("354 Enter mail, end with \".\" on a line by itself");
328
329        if (tTd(30, 2))
330                sm_dprintf("collect\n");
331
332        /*
333        **  Read the message.
334        **
335        **      This is done using two interleaved state machines.
336        **      The input state machine is looking for things like
337        **      hidden dots; the message state machine is handling
338        **      the larger picture (e.g., header versus body).
339        */
340
341        e->e_msgsize = 0;
342        for (;;)
343        {
344                if (tTd(30, 35))
345                        sm_dprintf("top, istate=%d, mstate=%d\n", istate,
346                                   mstate);
347                for (;;)
348                {
349                        if (pbp > peekbuf)
350                                c = *--pbp;
351                        else
352                        {
353                                while (!sm_io_eof(fp) && !sm_io_error(fp))
354                                {
355                                        errno = 0;
356                                        c = sm_io_getc(fp, SM_TIME_DEFAULT);
357                                        if (c == SM_IO_EOF && errno == EINTR)
358                                        {
359                                                /* Interrupted, retry */
360                                                sm_io_clearerr(fp);
361                                                continue;
362                                        }
363
364                                        /* timeout? */
365                                        if (c == SM_IO_EOF && errno == EAGAIN
366                                            && smtpmode)
367                                        {
368                                                /*
369                                                **  Override e_message in
370                                                **  usrerr() as this is the
371                                                **  reason for failure that
372                                                **  should be logged for
373                                                **  undelivered recipients.
374                                                */
375
376                                                e->e_message = NULL;
377                                                errno = 0;
378                                                inputerr = true;
379                                                goto readabort;
380                                        }
381                                        break;
382                                }
383                                if (TrafficLogFile != NULL && !headeronly)
384                                {
385                                        if (istate == IS_BOL)
386                                                (void) sm_io_fprintf(TrafficLogFile,
387                                                        SM_TIME_DEFAULT,
388                                                        "%05d <<< ",
389                                                        (int) CurrentPid);
390                                        if (c == SM_IO_EOF)
391                                                (void) sm_io_fprintf(TrafficLogFile,
392                                                        SM_TIME_DEFAULT,
393                                                        "[EOF]\n");
394                                        else
395                                                (void) sm_io_putc(TrafficLogFile,
396                                                        SM_TIME_DEFAULT,
397                                                        c);
398                                }
399                                if (c == SM_IO_EOF)
400                                        goto readerr;
401                                if (SevenBitInput)
402                                        c &= 0x7f;
403                                else
404                                        HasEightBits |= bitset(0x80, c);
405                        }
406                        if (tTd(30, 94))
407                                sm_dprintf("istate=%d, c=%c (0x%x)\n",
408                                        istate, (char) c, c);
409                        switch (istate)
410                        {
411                          case IS_BOL:
412                                if (c == '.')
413                                {
414                                        istate = IS_DOT;
415                                        continue;
416                                }
417                                break;
418
419                          case IS_DOT:
420                                if (c == '\n' && !ignrdot &&
421                                    !bitset(EF_NL_NOT_EOL, e->e_flags))
422                                        goto readerr;
423                                else if (c == '\r' &&
424                                         !bitset(EF_CRLF_NOT_EOL, e->e_flags))
425                                {
426                                        istate = IS_DOTCR;
427                                        continue;
428                                }
429                                else if (ignrdot ||
430                                         (c != '.' &&
431                                          OpMode != MD_SMTP &&
432                                          OpMode != MD_DAEMON &&
433                                          OpMode != MD_ARPAFTP))
434
435                                {
436                                        SM_ASSERT(pbp < peekbuf + sizeof(peekbuf));
437                                        *pbp++ = c;
438                                        c = '.';
439                                }
440                                break;
441
442                          case IS_DOTCR:
443                                if (c == '\n' && !ignrdot)
444                                        goto readerr;
445                                else
446                                {
447                                        /* push back the ".\rx" */
448                                        SM_ASSERT(pbp < peekbuf + sizeof(peekbuf));
449                                        *pbp++ = c;
450                                        if (OpMode != MD_SMTP &&
451                                            OpMode != MD_DAEMON &&
452                                            OpMode != MD_ARPAFTP)
453                                        {
454                                                SM_ASSERT(pbp < peekbuf +
455                                                         sizeof(peekbuf));
456                                                *pbp++ = '\r';
457                                                c = '.';
458                                        }
459                                        else
460                                                c = '\r';
461                                }
462                                break;
463
464                          case IS_CR:
465                                if (c == '\n')
466                                        istate = IS_BOL;
467                                else
468                                {
469                                        (void) sm_io_ungetc(fp, SM_TIME_DEFAULT,
470                                                            c);
471                                        c = '\r';
472                                        istate = IS_NORM;
473                                }
474                                goto bufferchar;
475                        }
476
477                        if (c == '\r' && !bitset(EF_CRLF_NOT_EOL, e->e_flags))
478                        {
479                                istate = IS_CR;
480                                continue;
481                        }
482                        else if (c == '\n' && !bitset(EF_NL_NOT_EOL,
483                                                      e->e_flags))
484                                istate = IS_BOL;
485                        else
486                                istate = IS_NORM;
487
488bufferchar:
489                        if (!headeronly)
490                        {
491                                /* no overflow? */
492                                if (e->e_msgsize >= 0)
493                                {
494                                        e->e_msgsize++;
495                                        if (MaxMessageSize > 0 &&
496                                            !bitset(EF_TOOBIG, e->e_flags) &&
497                                            e->e_msgsize > MaxMessageSize)
498                                                 e->e_flags |= EF_TOOBIG;
499                                }
500                        }
501                        switch (mstate)
502                        {
503                          case MS_BODY:
504                                /* just put the character out */
505                                if (!bitset(EF_TOOBIG, e->e_flags))
506                                        (void) sm_io_putc(df, SM_TIME_DEFAULT,
507                                                          c);
508
509                                /* FALLTHROUGH */
510
511                          case MS_DISCARD:
512                                continue;
513                        }
514
515                        /* header -- buffer up */
516                        if (bp >= &buf[buflen - 2])
517                        {
518                                char *obuf;
519
520                                if (mstate != MS_HEADER)
521                                        break;
522
523                                /* out of space for header */
524                                obuf = buf;
525                                if (buflen < MEMCHUNKSIZE)
526                                        buflen *= 2;
527                                else
528                                        buflen += MEMCHUNKSIZE;
529                                if (buflen <= 0)
530                                {
531                                        sm_syslog(LOG_NOTICE, e->e_id,
532                                                  "header overflow from %s during message collect",
533                                                  CURHOSTNAME);
534                                        errno = 0;
535                                        e->e_flags |= EF_CLRQUEUE;
536                                        e->e_status = "5.6.0";
537                                        usrerrenh(e->e_status,
538                                                  "552 Headers too large");
539                                        goto discard;
540                                }
541                                buf = xalloc(buflen);
542                                memmove(buf, obuf, bp - obuf);
543                                bp = &buf[bp - obuf];
544                                if (obuf != bufbuf)
545                                        sm_free(obuf);  /* XXX */
546                        }
547
548                        /*
549                        **  XXX Notice: the logic here is broken.
550                        **  An input to sendmail that doesn't contain a
551                        **  header but starts immediately with the body whose
552                        **  first line contain characters which match the
553                        **  following "if" will cause problems: those
554                        **  characters will NOT appear in the output...
555                        **  Do we care?
556                        */
557
558                        if (c >= 0200 && c <= 0237)
559                        {
560#if 0   /* causes complaints -- figure out something for 8.n+1 */
561                                usrerr("Illegal character 0x%x in header", c);
562#else /* 0 */
563                                /* EMPTY */
564#endif /* 0 */
565                        }
566                        else if (c != '\0')
567                        {
568                                *bp++ = c;
569                                ++hdrslen;
570                                if (!headeronly &&
571                                    MaxHeadersLength > 0 &&
572                                    hdrslen > MaxHeadersLength)
573                                {
574                                        sm_syslog(LOG_NOTICE, e->e_id,
575                                                  "headers too large (%d max) from %s during message collect",
576                                                  MaxHeadersLength,
577                                                  CURHOSTNAME);
578                                        errno = 0;
579                                        e->e_flags |= EF_CLRQUEUE;
580                                        e->e_status = "5.6.0";
581                                        usrerrenh(e->e_status,
582                                                  "552 Headers too large (%d max)",
583                                                  MaxHeadersLength);
584  discard:
585                                        mstate = MS_DISCARD;
586                                }
587                        }
588                        if (istate == IS_BOL)
589                                break;
590                }
591                *bp = '\0';
592
593nextstate:
594                if (tTd(30, 35))
595                        sm_dprintf("nextstate, istate=%d, mstate=%d, line = \"%s\"\n",
596                                istate, mstate, buf);
597                switch (mstate)
598                {
599                  case MS_UFROM:
600                        mstate = MS_HEADER;
601#ifndef NOTUNIX
602                        if (strncmp(buf, "From ", 5) == 0)
603                        {
604                                bp = buf;
605                                eatfrom(buf, e);
606                                continue;
607                        }
608#endif /* ! NOTUNIX */
609                        /* FALLTHROUGH */
610
611                  case MS_HEADER:
612                        if (!isheader(buf))
613                        {
614                                mstate = MS_BODY;
615                                goto nextstate;
616                        }
617
618                        /* check for possible continuation line */
619                        do
620                        {
621                                sm_io_clearerr(fp);
622                                errno = 0;
623                                c = sm_io_getc(fp, SM_TIME_DEFAULT);
624
625                                /* timeout? */
626                                if (c == SM_IO_EOF && errno == EAGAIN
627                                    && smtpmode)
628                                {
629                                        /*
630                                        **  Override e_message in
631                                        **  usrerr() as this is the
632                                        **  reason for failure that
633                                        **  should be logged for
634                                        **  undelivered recipients.
635                                        */
636
637                                        e->e_message = NULL;
638                                        errno = 0;
639                                        inputerr = true;
640                                        goto readabort;
641                                }
642                        } while (c == SM_IO_EOF && errno == EINTR);
643                        if (c != SM_IO_EOF)
644                                (void) sm_io_ungetc(fp, SM_TIME_DEFAULT, c);
645                        if (c == ' ' || c == '\t')
646                        {
647                                /* yep -- defer this */
648                                continue;
649                        }
650
651                        SM_ASSERT(bp > buf);
652
653                        /* guaranteed by isheader(buf) */
654                        SM_ASSERT(*(bp - 1) != '\n' || bp > buf + 1);
655
656                        /* trim off trailing CRLF or NL */
657                        if (*--bp != '\n' || *--bp != '\r')
658                                bp++;
659                        *bp = '\0';
660
661                        if (bitset(H_EOH, chompheader(buf,
662                                                      CHHDR_CHECK | CHHDR_USER,
663                                                      hdrp, e)))
664                        {
665                                mstate = MS_BODY;
666                                goto nextstate;
667                        }
668                        numhdrs++;
669                        break;
670
671                  case MS_BODY:
672                        if (tTd(30, 1))
673                                sm_dprintf("EOH\n");
674
675                        if (headeronly)
676                                goto readerr;
677
678                        df = collect_eoh(e, numhdrs, hdrslen);
679                        if (df == NULL)
680                                e->e_flags |= EF_TOOBIG;
681
682                        bp = buf;
683
684                        /* toss blank line */
685                        if ((!bitset(EF_CRLF_NOT_EOL, e->e_flags) &&
686                                bp[0] == '\r' && bp[1] == '\n') ||
687                            (!bitset(EF_NL_NOT_EOL, e->e_flags) &&
688                                bp[0] == '\n'))
689                        {
690                                break;
691                        }
692
693                        /* if not a blank separator, write it out */
694                        if (!bitset(EF_TOOBIG, e->e_flags))
695                        {
696                                while (*bp != '\0')
697                                        (void) sm_io_putc(df, SM_TIME_DEFAULT,
698                                                          *bp++);
699                        }
700                        break;
701                }
702                bp = buf;
703        }
704
705readerr:
706        if ((sm_io_eof(fp) && smtpmode) || sm_io_error(fp))
707        {
708                const char *errmsg;
709
710                if (sm_io_eof(fp))
711                        errmsg = "unexpected close";
712                else
713                        errmsg = sm_errstring(errno);
714                if (tTd(30, 1))
715                        sm_dprintf("collect: premature EOM: %s\n", errmsg);
716                if (LogLevel > 1)
717                        sm_syslog(LOG_WARNING, e->e_id,
718                                "collect: premature EOM: %s", errmsg);
719                inputerr = true;
720        }
721
722        if (headeronly)
723                return;
724
725        if (mstate != MS_BODY)
726        {
727                /* no body or discard, so we never opened the data file */
728                SM_ASSERT(df == NULL);
729                df = collect_eoh(e, numhdrs, hdrslen);
730        }
731
732        if (df == NULL)
733        {
734                /* skip next few clauses */
735                /* EMPTY */
736        }
737        else if (sm_io_flush(df, SM_TIME_DEFAULT) != 0 || sm_io_error(df))
738        {
739                dferror(df, "sm_io_flush||sm_io_error", e);
740                flush_errors(true);
741                finis(true, true, ExitStat);
742                /* NOTREACHED */
743        }
744        else if (SuperSafe != SAFE_REALLY)
745        {
746                /* skip next few clauses */
747                /* EMPTY */
748        }
749        else if (sm_io_setinfo(df, SM_BF_COMMIT, NULL) < 0 && errno != EINVAL)
750        {
751                int save_errno = errno;
752
753                if (save_errno == EEXIST)
754                {
755                        char *dfile;
756                        struct stat st;
757                        int dfd;
758
759                        dfile = queuename(e, DATAFL_LETTER);
760                        if (stat(dfile, &st) < 0)
761                                st.st_size = -1;
762                        errno = EEXIST;
763                        syserr("@collect: bfcommit(%s): already on disk, size = %ld",
764                               dfile, (long) st.st_size);
765                        dfd = sm_io_getinfo(df, SM_IO_WHAT_FD, NULL);
766                        if (dfd >= 0)
767                                dumpfd(dfd, true, true);
768                }
769                errno = save_errno;
770                dferror(df, "bfcommit", e);
771                flush_errors(true);
772                finis(save_errno != EEXIST, true, ExitStat);
773        }
774        else if ((afd = sm_io_getinfo(df, SM_IO_WHAT_FD, NULL)) >= 0 &&
775                 fsync(afd) < 0)
776        {
777                dferror(df, "fsync", e);
778                flush_errors(true);
779                finis(true, true, ExitStat);
780                /* NOTREACHED */
781        }
782        else if (sm_io_close(df, SM_TIME_DEFAULT) < 0)
783        {
784                dferror(df, "sm_io_close", e);
785                flush_errors(true);
786                finis(true, true, ExitStat);
787                /* NOTREACHED */
788        }
789        else
790        {
791                /* everything is happily flushed to disk */
792                df = NULL;
793
794                /* remove from available space in filesystem */
795                updfs(e, false, true);
796        }
797
798        /* An EOF when running SMTP is an error */
799  readabort:
800        if (inputerr && (OpMode == MD_SMTP || OpMode == MD_DAEMON))
801        {
802                char *host;
803                char *problem;
804                ADDRESS *q;
805
806                host = RealHostName;
807                if (host == NULL)
808                        host = "localhost";
809
810                if (sm_io_eof(fp))
811                        problem = "unexpected close";
812                else if (sm_io_error(fp))
813                        problem = "I/O error";
814                else
815                        problem = "read timeout";
816                if (LogLevel > 0 && sm_io_eof(fp))
817                        sm_syslog(LOG_NOTICE, e->e_id,
818                                "collect: %s on connection from %.100s, sender=%s",
819                                problem, host,
820                                shortenstring(e->e_from.q_paddr, MAXSHORTSTR));
821                if (sm_io_eof(fp))
822                        usrerr("421 4.4.1 collect: %s on connection from %s, from=%s",
823                                problem, host,
824                                shortenstring(e->e_from.q_paddr, MAXSHORTSTR));
825                else
826                        syserr("421 4.4.1 collect: %s on connection from %s, from=%s",
827                                problem, host,
828                                shortenstring(e->e_from.q_paddr, MAXSHORTSTR));
829                flush_errors(true);
830
831                /* don't return an error indication */
832                e->e_to = NULL;
833                e->e_flags &= ~EF_FATALERRS;
834                e->e_flags |= EF_CLRQUEUE;
835
836                /* Don't send any message notification to sender */
837                for (q = e->e_sendqueue; q != NULL; q = q->q_next)
838                {
839                        if (QS_IS_DEAD(q->q_state))
840                                continue;
841                        q->q_state = QS_FATALERR;
842                }
843
844                finis(true, true, ExitStat);
845                /* NOTREACHED */
846        }
847
848        /* Log collection information. */
849        if (bitset(EF_LOGSENDER, e->e_flags) && LogLevel > 4)
850        {
851                logsender(e, e->e_msgid);
852                e->e_flags &= ~EF_LOGSENDER;
853        }
854
855        /* check for message too large */
856        if (bitset(EF_TOOBIG, e->e_flags))
857        {
858                e->e_flags |= EF_NO_BODY_RETN|EF_CLRQUEUE;
859                if (!bitset(EF_FATALERRS, e->e_flags))
860                {
861                        e->e_status = "5.2.3";
862                        usrerrenh(e->e_status,
863                                "552 Message exceeds maximum fixed size (%ld)",
864                                MaxMessageSize);
865                        if (LogLevel > 6)
866                                sm_syslog(LOG_NOTICE, e->e_id,
867                                        "message size (%ld) exceeds maximum (%ld)",
868                                        e->e_msgsize, MaxMessageSize);
869                }
870        }
871
872        /* check for illegal 8-bit data */
873        if (HasEightBits)
874        {
875                e->e_flags |= EF_HAS8BIT;
876                if (!bitset(MM_PASS8BIT|MM_MIME8BIT, MimeMode) &&
877                    !bitset(EF_IS_MIME, e->e_flags))
878                {
879                        e->e_status = "5.6.1";
880                        usrerrenh(e->e_status, "554 Eight bit data not allowed");
881                }
882        }
883        else
884        {
885                /* if it claimed to be 8 bits, well, it lied.... */
886                if (e->e_bodytype != NULL &&
887                    sm_strcasecmp(e->e_bodytype, "8BITMIME") == 0)
888                        e->e_bodytype = "7BIT";
889        }
890
891        if (SuperSafe == SAFE_REALLY && !bitset(EF_FATALERRS, e->e_flags))
892        {
893                char *dfname = queuename(e, DATAFL_LETTER);
894                if ((e->e_dfp = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, dfname,
895                                           SM_IO_RDONLY, NULL)) == NULL)
896                {
897                        /* we haven't acked receipt yet, so just chuck this */
898                        syserr("@Cannot reopen %s", dfname);
899                        finis(true, true, ExitStat);
900                        /* NOTREACHED */
901                }
902        }
903        else
904                e->e_dfp = df;
905
906        /* collect statistics */
907        if (OpMode != MD_VERIFY)
908                markstats(e, (ADDRESS *) NULL, STATS_NORMAL);
909}
910
911/*
912**  DFERROR -- signal error on writing the data file.
913**
914**      Called by collect().  Collect() always terminates the process
915**      immediately after calling dferror(), which means that the SMTP
916**      session will be terminated, which means that any error message
917**      issued by dferror must be a 421 error, as per RFC 821.
918**
919**      Parameters:
920**              df -- the file pointer for the data file.
921**              msg -- detailed message.
922**              e -- the current envelope.
923**
924**      Returns:
925**              none.
926**
927**      Side Effects:
928**              Gives an error message.
929**              Arranges for following output to go elsewhere.
930*/
931
932static void
933dferror(df, msg, e)
934        SM_FILE_T *volatile df;
935        char *msg;
936        register ENVELOPE *e;
937{
938        char *dfname;
939
940        dfname = queuename(e, DATAFL_LETTER);
941        setstat(EX_IOERR);
942        if (errno == ENOSPC)
943        {
944#if STAT64 > 0
945                struct stat64 st;
946#else /* STAT64 > 0 */
947                struct stat st;
948#endif /* STAT64 > 0 */
949                long avail;
950                long bsize;
951
952                e->e_flags |= EF_NO_BODY_RETN;
953
954                if (
955#if STAT64 > 0
956                    fstat64(sm_io_getinfo(df, SM_IO_WHAT_FD, NULL), &st)
957#else /* STAT64 > 0 */
958                    fstat(sm_io_getinfo(df, SM_IO_WHAT_FD, NULL), &st)
959#endif /* STAT64 > 0 */
960                    < 0)
961                  st.st_size = 0;
962                (void) sm_io_reopen(SmFtStdio, SM_TIME_DEFAULT, dfname,
963                                    SM_IO_WRONLY, NULL, df);
964                if (st.st_size <= 0)
965                        (void) sm_io_fprintf(df, SM_TIME_DEFAULT,
966                                "\n*** Mail could not be accepted");
967                else
968                        (void) sm_io_fprintf(df, SM_TIME_DEFAULT,
969                                "\n*** Mail of at least %llu bytes could not be accepted\n",
970                                (ULONGLONG_T) st.st_size);
971                (void) sm_io_fprintf(df, SM_TIME_DEFAULT,
972                        "*** at %s due to lack of disk space for temp file.\n",
973                        MyHostName);
974                avail = freediskspace(qid_printqueue(e->e_qgrp, e->e_qdir),
975                                      &bsize);
976                if (avail > 0)
977                {
978                        if (bsize > 1024)
979                                avail *= bsize / 1024;
980                        else if (bsize < 1024)
981                                avail /= 1024 / bsize;
982                        (void) sm_io_fprintf(df, SM_TIME_DEFAULT,
983                                "*** Currently, %ld kilobytes are available for mail temp files.\n",
984                                avail);
985                }
986#if 0
987                /* Wrong response code; should be 421. */
988                e->e_status = "4.3.1";
989                usrerrenh(e->e_status, "452 Out of disk space for temp file");
990#else /* 0 */
991                syserr("421 4.3.1 Out of disk space for temp file");
992#endif /* 0 */
993        }
994        else
995                syserr("421 4.3.0 collect: Cannot write %s (%s, uid=%d, gid=%d)",
996                        dfname, msg, (int) geteuid(), (int) getegid());
997        if (sm_io_reopen(SmFtStdio, SM_TIME_DEFAULT, SM_PATH_DEVNULL,
998                         SM_IO_WRONLY, NULL, df) == NULL)
999                sm_syslog(LOG_ERR, e->e_id,
1000                          "dferror: sm_io_reopen(\"/dev/null\") failed: %s",
1001                          sm_errstring(errno));
1002}
1003/*
1004**  EATFROM -- chew up a UNIX style from line and process
1005**
1006**      This does indeed make some assumptions about the format
1007**      of UNIX messages.
1008**
1009**      Parameters:
1010**              fm -- the from line.
1011**
1012**      Returns:
1013**              none.
1014**
1015**      Side Effects:
1016**              extracts what information it can from the header,
1017**              such as the date.
1018*/
1019
1020#ifndef NOTUNIX
1021
1022static char     *DowList[] =
1023{
1024        "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", NULL
1025};
1026
1027static char     *MonthList[] =
1028{
1029        "Jan", "Feb", "Mar", "Apr", "May", "Jun",
1030        "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
1031        NULL
1032};
1033
1034static void
1035eatfrom(fm, e)
1036        char *volatile fm;
1037        register ENVELOPE *e;
1038{
1039        register char *p;
1040        register char **dt;
1041
1042        if (tTd(30, 2))
1043                sm_dprintf("eatfrom(%s)\n", fm);
1044
1045        /* find the date part */
1046        p = fm;
1047        while (*p != '\0')
1048        {
1049                /* skip a word */
1050                while (*p != '\0' && *p != ' ')
1051                        p++;
1052                while (*p == ' ')
1053                        p++;
1054                if (strlen(p) < 17)
1055                {
1056                        /* no room for the date */
1057                        return;
1058                }
1059                if (!(isascii(*p) && isupper(*p)) ||
1060                    p[3] != ' ' || p[13] != ':' || p[16] != ':')
1061                        continue;
1062
1063                /* we have a possible date */
1064                for (dt = DowList; *dt != NULL; dt++)
1065                        if (strncmp(*dt, p, 3) == 0)
1066                                break;
1067                if (*dt == NULL)
1068                        continue;
1069
1070                for (dt = MonthList; *dt != NULL; dt++)
1071                {
1072                        if (strncmp(*dt, &p[4], 3) == 0)
1073                                break;
1074                }
1075                if (*dt != NULL)
1076                        break;
1077        }
1078
1079        if (*p != '\0')
1080        {
1081                char *q, buf[25];
1082
1083                /* we have found a date */
1084                (void) sm_strlcpy(buf, p, sizeof(buf));
1085                q = arpadate(buf);
1086                macdefine(&e->e_macro, A_TEMP, 'a', q);
1087        }
1088}
1089#endif /* ! NOTUNIX */
Note: See TracBrowser for help on using the repository browser.