]> Pileus Git - ~andy/fetchmail/blob - driver.c
Accept MX and canonical names in Received lines.
[~andy/fetchmail] / driver.c
1 /*
2  * driver.c -- generic driver for mail fetch method protocols
3  *
4  * Copyright 1996 by Eric S. Raymond
5  * All rights reserved.
6  * For license terms, see the file COPYING in this directory.
7  */
8
9 #include  <config.h>
10 #include  <stdio.h>
11 #include  <setjmp.h>
12 #include  <errno.h>
13 #include  <ctype.h>
14 #include  <string.h>
15 #if defined(STDC_HEADERS)
16 #include  <stdlib.h>
17 #endif
18 #if defined(HAVE_UNISTD_H)
19 #include <unistd.h>
20 #endif
21 #if defined(HAVE_STDARG_H)
22 #include  <stdarg.h>
23 #else
24 #include  <varargs.h>
25 #endif
26 #if defined(HAVE_ALLOCA_H)
27 #include <alloca.h>
28 #endif
29 #include  <sys/time.h>
30 #include  <signal.h>
31
32 #ifdef HAVE_GETHOSTBYNAME
33 #include <netdb.h>
34 #include "mx.h"
35 #endif /* HAVE_GETHOSTBYNAME */
36
37 #ifdef KERBEROS_V4
38 #include <krb.h>
39 #include <des.h>
40 #include <netinet/in.h>
41 #include <netdb.h>
42 #endif /* KERBEROS_V4 */
43 #include  "socket.h"
44 #include  "fetchmail.h"
45 #include  "smtp.h"
46
47 /* BSD portability hack...I know, this is an ugly place to put it */
48 #if !defined(SIGCHLD) && defined(SIGCLD)
49 #define SIGCHLD SIGCLD
50 #endif
51
52 #define SMTP_PORT       25      /* standard SMTP service port */
53
54 int batchlimit;         /* how often to tear down the delivery connection */
55 int batchcount;         /* count of messages sent in current batch */
56 int peek_capable;       /* can we peek for better error recovery? */
57
58 static const struct method *protocol;
59 static jmp_buf  restart;
60
61 char tag[TAGLEN];
62 static int tagnum;
63 #define GENSYM  (sprintf(tag, "a%04d", ++tagnum), tag)
64
65 static char *shroud;    /* string to shroud in debug output, if  non-NULL */
66 static int mytimeout;   /* value of nonreponse timeout */
67
68 static int strcrlf(dst, src, count)
69 /* replace LFs with CR-LF; return length of string with replacements */
70 char *dst;      /* new string with CR-LFs */
71 char *src;      /* original string with LFs */
72 int count;      /* length of src */
73 {
74   int len = count;
75
76   while (count--)
77   {
78       if (*src == '\n')
79       {
80           *dst++ = '\r';
81           len++;
82       }
83       *dst++ = *src++;
84   }
85   *dst = '\0';
86   return len;
87 }
88
89 static void vtalarm(int timeleft)
90 /* reset the nonresponse-timeout */
91 {
92     struct itimerval ntimeout;
93
94     ntimeout.it_interval.tv_sec = ntimeout.it_interval.tv_usec = 0;
95     ntimeout.it_value.tv_sec  = timeleft;
96     ntimeout.it_value.tv_usec = 0;
97     setitimer(ITIMER_VIRTUAL, &ntimeout, (struct itimerval *)NULL);
98 }
99
100 static void vtalarm_handler (int signal)
101 /* handle server-timeout SIGVTALARM signal */
102 {
103     longjmp(restart, 1);
104 }
105
106 #ifdef HAVE_RES_SEARCH
107 #define MX_RETRIES      3
108
109 static int is_host_alias(const char *name, struct query *ctl)
110 /* determine whether name is a DNS alias of the hostname */
111 {
112     struct hostent      *he;
113     struct mxentry      *mxp, *mxrecords;
114
115     /*
116      * The first two checks are optimizations that will catch a good
117      * many cases.  (1) check against the hostname the user
118      * specified.  Odds are good this will either be the mailserver's
119      * FQDN or a suffix of it with the mailserver's domain's default
120      * host name omitted.  Then check the rest of the `also known as'
121      * cache accumulated by previous DNS checks.  This cache is primed
122      * by the aka list option.
123      *
124      * (2) check against the mailserver's FQDN, in case
125      * it's not the same as the declared hostname.
126      *
127      * Either of these on a mail address is definitive.  Only if the
128      * name doesn't match either is it time to call the bind library.
129      * If this happens odds are good we're looking at an MX name.
130      */
131     if (str_in_list(&ctl->lead_server->servernames, name))
132         return(TRUE);
133     else if (strcmp(name, ctl->canonical_name) == 0)
134         return(TRUE);
135
136     /*
137      * We know DNS service was up at the beginning of this poll cycle.
138      * If it's down, our nameserver has crashed.  We don't want to try
139      * delivering the current message or anything else from this
140      * mailbox until it's back up.
141      */
142     else if ((he = gethostbyname(name)) != (struct hostent *)NULL)
143     {
144         if (strcmp(ctl->canonical_name, he->h_name) == 0)
145             goto match;
146         else
147             return(FALSE);
148     }
149     else
150         switch (h_errno)
151         {
152         case HOST_NOT_FOUND:    /* specified host is unknown */
153         case NO_ADDRESS:        /* valid, but does not have an IP address */
154             break;
155
156         case NO_RECOVERY:       /* non-recoverable name server error */
157         case TRY_AGAIN:         /* temporary error on authoritative server */
158         default:
159             if (outlevel != O_SILENT)
160                 putchar('\n');  /* terminate the progress message */
161             error(0, 0,
162                 "nameserver failure while looking for `%s' during poll of %s.",
163                 name, ctl->servernames->id);
164             ctl->errcount++;
165             longjmp(restart, 2);        /* try again next poll cycle */
166             break;
167         }
168
169     /*
170      * We're only here if DNS was OK but the gethostbyname() failed
171      * with a HOST_NOT_FOUND or NO_ADDRESS error.
172      * Search for a name match on MX records pointing to the server.
173      */
174     h_errno = 0;
175     if ((mxrecords = getmxrecords(name)) == (struct mxentry *)NULL)
176     {
177         switch (h_errno)
178         {
179         case HOST_NOT_FOUND:    /* specified host is unknown */
180             return(FALSE);
181
182         case NO_ADDRESS:        /* valid, but does not have an IP address */
183             for (mxp = mxrecords; mxp->name; mxp++)
184                 if (strcmp(name, mxp->name) == 0)
185                     goto match;
186             return(FALSE);
187             break;
188
189         case NO_RECOVERY:       /* non-recoverable name server error */
190         case TRY_AGAIN:         /* temporary error on authoritative server */
191         default:
192             error(0, 0,
193                 "nameserver failure while looking for `%s' during poll of %s.",
194                 name, ctl->servernames->id);
195             ctl->errcount++;
196             longjmp(restart, 2);        /* try again next poll cycle */
197             break;
198         }
199     }
200
201 match:
202     /* add this name to relevant server's `also known as' list */
203     save_str(&ctl->lead_server->servernames, -1, name);
204     return(TRUE);
205 }
206
207 static void map_name(name, ctl, xmit_names)
208 /* add given name to xmit_names if it matches declared localnames */
209 const char *name;               /* name to map */
210 struct query *ctl;              /* list of permissible aliases */
211 struct idlist **xmit_names;     /* list of recipient names parsed out */
212 {
213     const char  *lname;
214
215     lname = idpair_find(&ctl->localnames, name);
216     if (!lname && ctl->wildcard)
217         lname = name;
218
219     if (lname != (char *)NULL)
220     {
221         if (outlevel == O_VERBOSE)
222             error(0, 0, "mapped %s to local %s", name, lname);
223         save_str(xmit_names, -1, lname);
224     }
225 }
226
227 void find_server_names(hdr, ctl, xmit_names)
228 /* parse names out of a RFC822 header into an ID list */
229 const char *hdr;                /* RFC822 header in question */
230 struct query *ctl;              /* list of permissible aliases */
231 struct idlist **xmit_names;     /* list of recipient names parsed out */
232 {
233     if (hdr == (char *)NULL)
234         return;
235     else
236     {
237         char    *cp, *lname;
238
239         if ((cp = nxtaddr(hdr)) != (char *)NULL)
240             do {
241                 char    *atsign;
242
243                 if ((atsign = strchr(cp, '@')))
244                 {
245                     /*
246                      * Address has an @. Check to see if the right-hand part
247                      * is an alias or MX equivalent of the mailserver.  If it's
248                      * not, skip this name.  If it is, we'll keep going and try
249                      * to find a mapping to a client name.
250                      */
251                     if (!is_host_alias(atsign+1, ctl))
252                         continue;
253                     atsign[0] = '\0';
254                 }
255
256                 map_name(cp, ctl, xmit_names);
257             } while
258                 ((cp = nxtaddr((char *)NULL)) != (char *)NULL);
259     }
260 }
261 #endif /* HAVE_RES_SEARCH */
262
263 static FILE *smtp_open(struct query *ctl)
264 /* try to open a socket to the appropriate SMTP server for this query */ 
265 {
266     ctl = ctl->lead_smtp; /* go to the SMTP leader for this query */
267
268     /* maybe it's time to close the socket in order to force delivery */
269     if (batchlimit && ctl->smtp_sockfp && batchcount++ == batchlimit)
270     {
271         fclose(ctl->smtp_sockfp);
272         ctl->smtp_sockfp = (FILE *)NULL;
273         batchcount = 0;
274     }
275
276     /* if no socket to this host is already set up, try to open one */
277     if (ctl->smtp_sockfp == (FILE *)NULL)
278     {
279         if ((ctl->smtp_sockfp = sockopen(ctl->smtphost, SMTP_PORT)) == (FILE *)NULL)
280             return((FILE *)NULL);
281         else if (SMTP_ok(ctl->smtp_sockfp) != SM_OK
282                  || SMTP_helo(ctl->smtp_sockfp, ctl->servernames->id) != SM_OK)
283         {
284             fclose(ctl->smtp_sockfp);
285             ctl->smtp_sockfp = (FILE *)NULL;
286         }
287     }
288
289     return(ctl->smtp_sockfp);
290 }
291
292 static int SockGets(char *buf, int len, FILE *sockfp)
293 /* get a LF-terminated line, removing \r characters */
294 {
295     int rdlen = 0;
296
297     while (--len)
298     {
299         if ((*buf = fgetc(sockfp)) == EOF)
300             return -1;
301         else
302             rdlen++;
303         if (*buf == '\n')
304             break;
305         if (*buf != '\r') /* remove all CRs */
306             buf++;
307     }
308     *buf = 0;
309     return rdlen;
310 }
311
312 static int gen_readmsg (sockfp, len, delimited, ctl)
313 /* read message content and ship to SMTP or MDA */
314 FILE *sockfp;           /* to which the server is connected */
315 long len;               /* length of message */
316 int delimited;          /* does the protocol use a message delimiter? */
317 struct query *ctl;      /* query control record */
318 {
319     char buf [MSGBUFSIZE+1]; 
320     char *bufp, *headers, *fromhdr,*tohdr,*cchdr,*bcchdr,*received_for,*envto;
321     int n, oldlen;
322     int inheaders,lines,sizeticker;
323     FILE *sinkfp;
324     RETSIGTYPE (*sigchld)();
325 #ifdef HAVE_GETHOSTBYNAME
326     char rbuf[HOSTLEN + USERNAMELEN + 4]; 
327 #endif /* HAVE_GETHOSTBYNAME */
328
329     /* read the message content from the server */
330     inheaders = 1;
331     headers = fromhdr = tohdr = cchdr = bcchdr = received_for = envto = NULL;
332     lines = 0;
333     sizeticker = 0;
334     oldlen = 0;
335     while (delimited || len > 0)
336     {
337         if ((n = SockGets(buf,sizeof(buf),sockfp)) < 0)
338             return(PS_SOCKET);
339         vtalarm(ctl->timeout);
340
341         /* write the message size dots */
342         if (n > 0)
343         {
344             sizeticker += n;
345             while (sizeticker >= SIZETICKER)
346             {
347                 if (outlevel > O_SILENT)
348                     fputc('.',stderr);
349                 sizeticker -= SIZETICKER;
350             }
351         }
352         len -= n;
353         bufp = buf;
354         if (buf[0] == '\0' || buf[0] == '\r' || buf[0] == '\n')
355             inheaders = 0;
356         if (delimited && *bufp == '.') {
357             bufp++;
358             if (*bufp == 0)
359                 break;  /* end of message */
360         }
361         strcat(bufp, "\n");
362      
363         if (inheaders)
364         {
365             if (!ctl->norewrite)
366                 reply_hack(bufp, ctl->servernames->id);
367
368             if (!lines)
369             {
370                 oldlen = strlen(bufp);
371                 headers = xmalloc(oldlen + 1);
372                 (void) strcpy(headers, bufp);
373                 bufp = headers;
374             }
375             else
376             {
377                 int     newlen;
378
379                 /*
380                  * We deal with RFC822 continuation lines here.
381                  * Replace previous '\n' with '\r' so nxtaddr 
382                  * and reply_hack will be able to see past it.
383                  * (We know this is safe because SocketGets stripped
384                  * out all carriage returns in the read loop above
385                  * and we haven't reintroduced any since then.)
386                  * We'll undo this before writing the header.
387                  */
388                 if (isspace(bufp[0]))
389                     headers[oldlen-1] = '\r';
390
391                 newlen = oldlen + strlen(bufp);
392                 headers = realloc(headers, newlen + 1);
393                 if (headers == NULL)
394                     return(PS_IOERR);
395                 strcpy(headers + oldlen, bufp);
396                 bufp = headers + oldlen;
397                 oldlen = newlen;
398             }
399
400             if (!strncasecmp("From:", bufp, 5))
401                 fromhdr = bufp;
402             else if (!fromhdr && !strncasecmp("Resent-From:", bufp, 12))
403                 fromhdr = bufp;
404             else if (!fromhdr && !strncasecmp("Apparently-From:", bufp, 16))
405                 fromhdr = bufp;
406             else if (!strncasecmp("To:", bufp, 3))
407                 tohdr = bufp;
408             else if (!strncasecmp("Apparently-To:", bufp, 14))
409                 envto = bufp;
410             else if (!strncasecmp(ctl->envelope, bufp, 14))
411                 envto = bufp;
412             else if (!strncasecmp("Cc:", bufp, 3))
413                 cchdr = bufp;
414             else if (!strncasecmp("Bcc:", bufp, 4))
415                 bcchdr = bufp;
416 #ifdef HAVE_GETHOSTBYNAME
417             else if (MULTIDROP(ctl) && !strncasecmp("Received:", bufp, 9))
418             {
419                 char *ok;
420
421                 /*
422                  * Try to extract the real envelope addressee.  We look here
423                  * specifically for the mailserver's Received line.
424                  * Note: this will only work for sendmail, or an MTA that
425                  * shares sendmail's convention for embedding the envelope
426                  * address in the Received line.  Sendmail itself only
427                  * does this when the mail has a single recipient.
428                  */
429                 if ((ok = strstr(bufp, "by ")) == (char *)NULL)
430                     ok = (char *)NULL;
431                 else
432                 {
433                     char        *sp, *tp;
434
435                     /* extract space-delimited token after "by " */
436                     tp = rbuf;
437                     for (sp = ok + 3; !isspace(*sp); sp++)
438                         *tp++ = *sp;
439                     *tp = '\0';
440
441                     /*
442                      * If it's a DNS name of the mail server, look for the
443                      * recipient name after a following "for".  Otherwise
444                      * punt.
445                      */
446                     if (is_host_alias(rbuf, ctl))
447                         ok = strstr(sp, "for ");
448                     else
449                         ok = (char *)NULL;
450                 }
451
452                 if (ok != 0)
453                 {
454                     char        *sp, *tp;
455
456                     tp = rbuf;
457                     sp = ok + 4;
458                     if (*ok == '<')
459                         sp++;
460                     while (*sp && *sp != '>' && *sp != '@' && *sp != ';')
461                         if (!isspace(*sp))
462                             *tp++ = *sp++;
463                         else
464                         {
465                             /* uh oh -- whitespace here can't be right! */
466                             ok = (char *)NULL;
467                             break;
468                         }
469                     *tp = '\0';
470                 }
471
472                 if (ok != 0)
473                 {
474                     received_for = alloca(strlen(rbuf)+1);
475                     strcpy(received_for, rbuf);
476                     if (outlevel == O_VERBOSE)
477                         error(0, 0, 
478                                 "found Received address `%s'",
479                                 received_for);
480                 }
481             }
482 #endif /* HAVE_GETHOSTBYNAME */
483
484             goto skipwrite;
485         }
486         else if (headers)       /* OK, we're at end of headers now */
487         {
488             char                *cp;
489             struct idlist       *idp, *xmit_names;
490             int                 good_addresses, bad_addresses;
491 #ifdef HAVE_RES_SEARCH
492             int                 no_local_matches = FALSE;
493 #endif /* HAVE_RES_SEARCH */
494
495             /* cons up a list of local recipients */
496             xmit_names = (struct idlist *)NULL;
497             bad_addresses = good_addresses = 0;
498 #ifdef HAVE_RES_SEARCH
499             /* is this a multidrop box? */
500             if (MULTIDROP(ctl))
501             {
502                 if (envto)          /* We have the actual envelope addressee */
503                     find_server_names(envto, ctl, &xmit_names);
504                 else if (received_for)
505                     /*
506                      * We have the Received for addressee.  
507                      * It has to be a mailserver address, or we
508                      * wouldn't have got here.
509                      */
510                     map_name(received_for, ctl, &xmit_names);
511                 else
512                 {
513                     /*
514                      * We haven't extracted the envelope address.
515                      * So check all the header addresses.
516                      */
517                     find_server_names(tohdr,  ctl, &xmit_names);
518                     find_server_names(cchdr,  ctl, &xmit_names);
519                     find_server_names(bcchdr, ctl, &xmit_names);
520                 }
521                 if (!xmit_names)
522                 {
523                     no_local_matches = TRUE;
524                     save_str(&xmit_names, -1, user);
525                     if (outlevel == O_VERBOSE)
526                         error(0, 0, 
527                                 "no local matches, forwarding to %s",
528                                 user);
529                 }
530             }
531             else        /* it's a single-drop box, use first localname */
532 #endif /* HAVE_RES_SEARCH */
533                 save_str(&xmit_names, -1, ctl->localnames->id);
534
535             /* time to address the message */
536             if (ctl->mda[0])    /* we have a declared MDA */
537             {
538                 int     length = 0;
539                 char    *names, *cmd;
540
541                 /*
542                  * We go through this in order to be able to handle very
543                  * long lists of users and (re)implement %s.
544                  */
545                 for (idp = xmit_names; idp; idp = idp->next)
546                     length += (strlen(idp->id) + 1);
547                 names = (char *)alloca(length);
548                 names[0] = '\0';
549                 for (idp = xmit_names; idp; idp = idp->next)
550                 {
551                     strcat(names, idp->id);
552                     strcat(names, " ");
553                 }
554                 cmd = (char *)alloca(strlen(ctl->mda) + length);
555                 sprintf(cmd, ctl->mda, names);
556                 if (outlevel == O_VERBOSE)
557                     error(0, 0, "about to deliver with: %s", cmd);
558
559 #ifdef HAVE_SETEUID
560                 /*
561                  * Arrange to run with user's permissions if we're root.
562                  * This will initialize the ownership of any files the
563                  * MDA creates properly.  (The seteuid call is available
564                  * under all BSDs and Linux)
565                  */
566                 seteuid(ctl->uid);
567 #endif /* HAVE_SETEUID */
568
569                 sinkfp = popen(cmd, "w");
570
571 #ifdef HAVE_SETEUID
572                 /* this will fail quietly if we didn't start as root */
573                 seteuid(0);
574 #endif /* HAVE_SETEUID */
575
576                 if (!sinkfp)
577                 {
578                     error(0, 0, "MDA open failed");
579                     return(PS_IOERR);
580                 }
581
582                 sigchld = signal(SIGCHLD, SIG_DFL);
583             }
584             else
585             {
586                 char    *ap;
587
588                 /* build a connection to the SMTP listener */
589                 if (ctl->mda[0] == '\0' && ((sinkfp = smtp_open(ctl)) == NULL))
590                 {
591                     free_str_list(&xmit_names);
592                     error(0, 0, "SMTP connect failed");
593                     return(PS_SMTP);
594                 }
595
596                 /*
597                  * Try to get the SMTP listener to take the header
598                  * From address as MAIL FROM (this makes the logging
599                  * nicer).  If it won't, fall back on the calling-user
600                  * ID.  This won't affect replies, which use the header
601                  * From address anyway.
602                  */
603                 if (!fromhdr || !(ap = nxtaddr(fromhdr)))
604                 {
605                     if (SMTP_from(sinkfp, user) != SM_OK)
606                         return(PS_SMTP);        /* should never happen */
607                 }
608                 else if (SMTP_from(sinkfp, ap) != SM_OK)
609                     if (smtp_response == 571)
610                     {
611                         /*
612                          * SMTP listener explicitly refuses to deliver
613                          * mail coming from this address, probably due
614                          * to an anti-spam domain exclusion.  Respect
615                          * this.
616                          */
617                         sinkfp = (FILE *)NULL;
618                         goto skiptext;
619                     }
620                     else if (SMTP_from(sinkfp, user) != SM_OK)
621                         return(PS_SMTP);        /* should never happen */
622
623                 /* now list the recipient addressees */
624                 for (idp = xmit_names; idp; idp = idp->next)
625                     if (SMTP_rcpt(sinkfp, idp->id) == SM_OK)
626                         good_addresses++;
627                     else
628                     {
629                         bad_addresses++;
630                         idp->val.num = 0;
631                         error(0, 0, 
632                                 "SMTP listener doesn't like recipient address `%s'", idp->id);
633                     }
634                 if (!good_addresses && SMTP_rcpt(sinkfp, user) != SM_OK)
635                 {
636                     error(0, 0, 
637                             "can't even send to calling user!");
638                     return(PS_SMTP);
639                 }
640
641                 /* tell it we're ready to send data */
642                 SMTP_data(sinkfp);
643
644             skiptext:;
645             }
646
647             /* change continuation markers back to regular newlines */
648             for (cp = headers; cp < headers + oldlen; cp++)
649                 if (*cp == '\r')
650                     *cp = '\n';
651
652             /* replace all LFs with CR-LF before sending to the SMTP server */
653             if (!ctl->mda[0])
654             {
655                 char *newheaders = xmalloc(1 + oldlen * 2);
656
657                 oldlen = strcrlf(newheaders, headers, oldlen);
658                 free(headers);
659                 headers = newheaders;
660             }
661
662             /* write all the headers */
663             n = 0;
664             if (sinkfp)
665                 n = fwrite(headers, 1, oldlen, sinkfp);
666
667             if (n < 0)
668             {
669                 free(headers);
670                 headers = NULL;
671                 error(0, errno, "writing RFC822 headers");
672                 if (ctl->mda[0])
673                 {
674                     pclose(sinkfp);
675                     signal(SIGCHLD, sigchld);
676                 }
677                 return(PS_IOERR);
678             }
679             else if (outlevel == O_VERBOSE)
680                 fputs("#", stderr);
681             free(headers);
682             headers = NULL;
683
684             /* write error notifications */
685 #ifdef HAVE_RES_SEARCH
686             if (no_local_matches || bad_addresses)
687 #else
688             if (bad_addresses)
689 #endif /* HAVE_RES_SEARCH */
690             {
691                 int     errlen = 0;
692                 char    errhd[USERNAMELEN + POPBUFSIZE], *errmsg;
693
694                 errmsg = errhd;
695                 (void) strcpy(errhd, "X-Fetchmail-Warning: ");
696 #ifdef HAVE_RES_SEARCH
697                 if (no_local_matches)
698                 {
699                     strcat(errhd, "no recipient addresses matched declared local names");
700                     if (bad_addresses)
701                         strcat(errhd, "; ");
702                 }
703 #endif /* HAVE_RES_SEARCH */
704
705                 if (bad_addresses)
706                 {
707                     strcat(errhd, "SMTP listener rejected local recipient addresses: ");
708                     errlen = strlen(errhd);
709                     for (idp = xmit_names; idp; idp = idp->next)
710                         if (!idp->val.num)
711                             errlen += strlen(idp->id) + 2;
712
713                     errmsg = alloca(errlen+3);
714                     (void) strcpy(errmsg, errhd);
715                     for (idp = xmit_names; idp; idp = idp->next)
716                         if (!idp->val.num)
717                         {
718                             strcat(errmsg, idp->id);
719                             if (idp->next)
720                                 strcat(errmsg, ", ");
721                         }
722                 }
723
724                 strcat(errmsg, "\n");
725
726                 if (sinkfp)
727                     fputs(errmsg, sinkfp);
728             }
729
730             free_str_list(&xmit_names);
731         }
732
733         /* SMTP byte-stuffing */
734         if (*bufp == '.' && ctl->mda[0] == 0)
735             if (sinkfp)
736                 fputs(".", sinkfp);
737
738         /* replace all LFs with CR-LF  in the line */
739         if (!ctl->mda[0])
740         {
741             char *newbufp = xmalloc(1 + strlen(bufp) * 2);
742
743             strcrlf(newbufp, bufp, strlen(bufp));
744             bufp = newbufp;
745         }
746
747         /* ship out the text line */
748         n = 0;
749         if (sinkfp)
750             n = fwrite(bufp, 1, strlen(bufp), sinkfp);
751
752         if (!ctl->mda[0])
753             free(bufp);
754         if (n < 0)
755         {
756             error(0, errno, "writing message text");
757             if (ctl->mda[0])
758             {
759                 pclose(sinkfp);
760                 signal(SIGCHLD, sigchld);
761             }
762             return(PS_IOERR);
763         }
764         else if (outlevel == O_VERBOSE)
765             fputc('*', stderr);
766
767     skipwrite:;
768         lines++;
769     }
770
771     if (ctl->mda[0])
772     {
773         int rc;
774
775         /* close the delivery pipe, we'll reopen before next message */
776         rc = pclose(sinkfp);
777         signal(SIGCHLD, sigchld);
778         if (rc)
779         {
780             error(0, 0, "MDA exited abnormally or returned nonzero status");
781             return(PS_IOERR);
782         }
783     }
784     else if (sinkfp)
785     {
786         /* write message terminator */
787         if (SMTP_eom(sinkfp) != SM_OK)
788         {
789             error(0, 0, "SMTP listener refused delivery");
790             return(PS_SMTP);
791         }
792     }
793
794     return(0);
795 }
796
797 #ifdef KERBEROS_V4
798 int
799 kerberos_auth (socket, canonical) 
800 /* authenticate to the server host using Kerberos V4 */
801 int socket;             /* socket to server host */
802 const char *canonical;  /* server name */
803 {
804     char * host_primary;
805     KTEXT ticket;
806     MSG_DAT msg_data;
807     CREDENTIALS cred;
808     Key_schedule schedule;
809     int rem;
810   
811     ticket = ((KTEXT) (malloc (sizeof (KTEXT_ST))));
812     rem = (krb_sendauth (0L, socket, ticket, "pop",
813                          canonical,
814                          ((char *) (krb_realmofhost (canonical))),
815                          ((unsigned long) 0),
816                          (&msg_data),
817                          (&cred),
818                          (schedule),
819                          ((struct sockaddr_in *) 0),
820                          ((struct sockaddr_in *) 0),
821                          "KPOPV0.1"));
822     free (ticket);
823     if (rem != KSUCCESS)
824     {
825         error(0, 0, "kerberos error %s", (krb_get_err_text (rem)));
826         return (PS_ERROR);
827     }
828     return (0);
829 }
830 #endif /* KERBEROS_V4 */
831
832 int do_protocol(ctl, proto)
833 /* retrieve messages from server using given protocol method table */
834 struct query *ctl;              /* parsed options with merged-in defaults */
835 const struct method *proto;     /* protocol method table */
836 {
837     int ok, js;
838     char *msg;
839     void (*sigsave)();
840
841 #ifndef KERBEROS_V4
842     if (ctl->authenticate == A_KERBEROS)
843     {
844         error(0, 0, "Kerberos support not linked.");
845         return(PS_ERROR);
846     }
847 #endif /* KERBEROS_V4 */
848
849     /* lacking methods, there are some options that may fail */
850     if (!proto->is_old)
851     {
852         /* check for unsupported options */
853         if (ctl->flush) {
854             error(0, 0,
855                     "Option --flush is not supported with %s",
856                     proto->name);
857             return(PS_SYNTAX);
858         }
859         else if (ctl->fetchall) {
860             error(0, 0,
861                     "Option --all is not supported with %s",
862                     proto->name);
863             return(PS_SYNTAX);
864         }
865     }
866     if (!proto->getsizes && ctl->limit)
867     {
868         error(0, 0,
869                 "Option --limit is not supported with %s",
870                 proto->name);
871         return(PS_SYNTAX);
872     }
873
874     protocol = proto;
875     tagnum = 0;
876     tag[0] = '\0';      /* nuke any tag hanging out from previous query */
877     ok = 0;
878
879     /* set up the server-nonresponse timeout */
880     sigsave = signal(SIGVTALRM, vtalarm_handler);
881     vtalarm(mytimeout = ctl->timeout);
882
883     if ((js = setjmp(restart)) == 1)
884     {
885         error(0, 0,
886                 "timeout after %d seconds waiting for %s.",
887                 ctl->timeout, ctl->servernames->id);
888         ok = PS_ERROR;
889     }
890     else if (js == 2)
891     {
892         /* error message printed at point of longjmp */
893         ok = PS_ERROR;
894     }
895     else
896     {
897         char buf [POPBUFSIZE+1];
898         int *msgsizes, len, num, count, new, deletions = 0;
899         FILE *sockfp;
900
901         /* open a socket to the mail server */
902         if ((sockfp = sockopen(ctl->servernames->id,
903                              ctl->port ? ctl->port : protocol->port)) == NULL)
904         {
905             error(0, errno, "connecting to host");
906             ok = PS_SOCKET;
907             goto closeUp;
908         }
909
910 #ifdef KERBEROS_V4
911         if (ctl->authenticate == A_KERBEROS)
912         {
913             ok = kerberos_auth(fileno(sockfp), ctl->canonical_name);
914             if (ok != 0)
915                 goto cleanUp;
916             vtalarm(ctl->timeout);
917         }
918 #endif /* KERBEROS_V4 */
919
920         /* accept greeting message from mail server */
921         ok = (protocol->parse_response)(sockfp, buf);
922         if (ok != 0)
923             goto cleanUp;
924         vtalarm(ctl->timeout);
925
926         /* try to get authorized to fetch mail */
927         shroud = ctl->password;
928         ok = (protocol->getauth)(sockfp, ctl, buf);
929         shroud = (char *)NULL;
930         if (ok == PS_ERROR)
931             ok = PS_AUTHFAIL;
932         if (ok != 0)
933             goto cleanUp;
934         vtalarm(ctl->timeout);
935
936         /* compute number of messages and number of new messages waiting */
937         ok = (protocol->getrange)(sockfp, ctl, &count, &new);
938         if (ok != 0)
939             goto cleanUp;
940         vtalarm(ctl->timeout);
941
942         /* show user how many messages we downloaded */
943         if (outlevel > O_SILENT)
944             if (count == 0)
945                 error(0, 0, "No mail from %s@%s", 
946                         ctl->remotename,
947                         ctl->servernames->id);
948             else
949             {
950                 if (new != -1 && (count - new) > 0)
951                     error(0, 0, "%d message%s (%d seen) from %s@%s.",
952                                 count, count > 1 ? "s" : "", count-new,
953                                 ctl->remotename,
954                                 ctl->servernames->id);
955                 else
956                     error(0, 0, "%d message%s from %s@%s.", count, count > 1 ? "s" : "",
957                                 ctl->remotename,
958                                 ctl->servernames->id);
959             }
960
961         /* we may need to get sizes in order to check message limits */
962         msgsizes = (int *)NULL;
963         if (!ctl->fetchall && proto->getsizes && ctl->limit)
964         {
965             msgsizes = (int *)alloca(sizeof(int) * count);
966
967             ok = (proto->getsizes)(sockfp, count, msgsizes);
968             if (ok != 0)
969                 goto cleanUp;
970             vtalarm(ctl->timeout);
971         }
972
973
974         if (check_only)
975         {
976             if (new == -1 || ctl->fetchall)
977                 new = count;
978             ok = ((new > 0) ? PS_SUCCESS : PS_NOMAIL);
979             goto cleanUp;
980         }
981         else if (count > 0)
982         {    
983             /*
984              * What forces this code is that in POP3 and IMAP2BIS you can't
985              * fetch a message without having it marked `seen'.  In IMAP4,
986              * on the other hand, you can (peek_capable is set to convey
987              * this).
988              *
989              * The result of being unable to peek is that if there's
990              * any kind of transient error (DNS lookup failure, or
991              * sendmail refusing delivery due to process-table limits)
992              * the message will be marked "seen" on the server without
993              * having been delivered.  This is not a big problem if
994              * fetchmail is running in foreground, because the user
995              * will see a "skipped" message when it next runs and get
996              * clued in.
997              *
998              * But in daemon mode this leads to the message being silently
999              * ignored forever.  This is not acceptable.
1000              *
1001              * We compensate for this by checking the error count from the 
1002              * previous pass and forcing all messages to be considered new
1003              * if it's nonzero.
1004              */
1005             int force_retrieval = !peek_capable && (ctl->errcount > 0);
1006
1007             ctl->errcount = 0;
1008
1009             /* read, forward, and delete messages */
1010             for (num = 1; num <= count; num++)
1011             {
1012                 int     toolarge = msgsizes && (msgsizes[num-1] > ctl->limit);
1013                 int     fetch_it = ctl->fetchall ||
1014                     (!toolarge && (force_retrieval || !(protocol->is_old && (protocol->is_old)(sockfp,ctl,num))));
1015
1016                 /* we may want to reject this message if it's old */
1017                 if (!fetch_it)
1018                 {
1019                     if (outlevel > O_SILENT)
1020                     {
1021                         fprintf(stderr, "skipping message %d", num);
1022                         if (toolarge)
1023                             fprintf(stderr, " (oversized, %d bytes)", msgsizes[num-1]);
1024                     }
1025                 }
1026                 else
1027                 {
1028                     /* request a message */
1029                     ok = (protocol->fetch)(sockfp, num, &len);
1030                     if (ok != 0)
1031                         goto cleanUp;
1032                     vtalarm(ctl->timeout);
1033
1034                     if (outlevel > O_SILENT)
1035                     {
1036                         fprintf(stderr, "reading message %d", num);
1037                         if (len > 0)
1038                             fprintf(stderr, " (%d bytes)", len);
1039                         if (outlevel == O_VERBOSE)
1040                             fputc('\n', stderr);
1041                         else
1042                             fputc(' ', stderr);
1043                     }
1044
1045                     /* read the message and ship it to the output sink */
1046                     ok = gen_readmsg(sockfp,
1047                                      len, 
1048                                      protocol->delimited,
1049                                      ctl);
1050                     if (ok != 0)
1051                         goto cleanUp;
1052                     vtalarm(ctl->timeout);
1053
1054                     /* tell the server we got it OK and resynchronize */
1055                     if (protocol->trail)
1056                     {
1057                         ok = (protocol->trail)(sockfp, ctl, num);
1058                         if (ok != 0)
1059                             goto cleanUp;
1060                         vtalarm(ctl->timeout);
1061                     }
1062                 }
1063
1064                 /*
1065                  * At this point in flow of control, either we've bombed
1066                  * on a protocol error or had delivery refused by the SMTP
1067                  * server (unlikely -- I've never seen it) or we've seen
1068                  * `accepted for delivery' and the message is shipped.
1069                  * It's safe to mark the message seen and delete it on the
1070                  * server now.
1071                  */
1072
1073                 /* maybe we delete this message now? */
1074                 if (protocol->delete
1075                     && (fetch_it ? !ctl->keep : ctl->flush))
1076                 {
1077                     deletions++;
1078                     if (outlevel > O_SILENT) 
1079                         fprintf(stderr, " flushed\n");
1080                     ok = (protocol->delete)(sockfp, ctl, num);
1081                     if (ok != 0)
1082                         goto cleanUp;
1083                     vtalarm(ctl->timeout);
1084                     delete_str(&ctl->newsaved, num);
1085                 }
1086                 else if (outlevel > O_SILENT) 
1087                     fprintf(stderr, " not flushed\n");
1088             }
1089
1090             /* remove all messages flagged for deletion */
1091             if (protocol->expunge_cmd && deletions > 0)
1092             {
1093                 ok = gen_transact(sockfp, protocol->expunge_cmd);
1094                 if (ok != 0)
1095                     goto cleanUp;
1096                 vtalarm(ctl->timeout);
1097             }
1098
1099             ok = gen_transact(sockfp, protocol->exit_cmd);
1100             if (ok == 0)
1101                 ok = PS_SUCCESS;
1102             vtalarm(0);
1103             fclose(sockfp);
1104             goto closeUp;
1105         }
1106         else {
1107             ok = gen_transact(sockfp, protocol->exit_cmd);
1108             if (ok == 0)
1109                 ok = PS_NOMAIL;
1110             vtalarm(0);
1111             fclose(sockfp);
1112             goto closeUp;
1113         }
1114
1115     cleanUp:
1116         vtalarm(ctl->timeout);
1117         if (ok != 0 && ok != PS_SOCKET)
1118             gen_transact(sockfp, protocol->exit_cmd);
1119         vtalarm(0);
1120         fclose(sockfp);
1121     }
1122
1123     switch (ok)
1124     {
1125     case PS_SOCKET:
1126         msg = "socket";
1127         break;
1128     case PS_AUTHFAIL:
1129         msg = "authorization";
1130         break;
1131     case PS_SYNTAX:
1132         msg = "missing or bad RFC822 header";
1133         break;
1134     case PS_IOERR:
1135         msg = "MDA";
1136         break;
1137     case PS_ERROR:
1138         msg = "client/server synchronization";
1139         break;
1140     case PS_PROTOCOL:
1141         msg = "client/server protocol";
1142         break;
1143     case PS_SMTP:
1144         msg = "SMTP transaction";
1145         break;
1146     case PS_UNDEFINED:
1147         error(0, 0, "undefined");
1148         break;
1149     }
1150     if (ok==PS_SOCKET || ok==PS_AUTHFAIL || ok==PS_SYNTAX || ok==PS_IOERR
1151                 || ok==PS_ERROR || ok==PS_PROTOCOL || ok==PS_SMTP)
1152         error(0, 0, "%s error while talking to %s", msg, ctl->servernames->id);
1153
1154 closeUp:
1155     signal(SIGVTALRM, sigsave);
1156     return(ok);
1157 }
1158
1159 #if defined(HAVE_STDARG_H)
1160 void gen_send(FILE *sockfp, char *fmt, ... )
1161 /* assemble command in printf(3) style and send to the server */
1162 #else
1163 void gen_send(sockfp, fmt, va_alist)
1164 /* assemble command in printf(3) style and send to the server */
1165 FILE *sockfp;           /* socket to which server is connected */
1166 const char *fmt;        /* printf-style format */
1167 va_dcl
1168 #endif
1169 {
1170     char buf [POPBUFSIZE+1];
1171     va_list ap;
1172
1173     if (protocol->tagged)
1174         (void) sprintf(buf, "%s ", GENSYM);
1175     else
1176         buf[0] = '\0';
1177
1178 #if defined(HAVE_STDARG_H)
1179     va_start(ap, fmt) ;
1180 #else
1181     va_start(ap);
1182 #endif
1183     vsprintf(buf + strlen(buf), fmt, ap);
1184     va_end(ap);
1185
1186     strcat(buf, "\r\n");
1187     fputs(buf, sockfp);
1188
1189     if (outlevel == O_VERBOSE)
1190     {
1191         char *cp;
1192
1193         if (shroud && (cp = strstr(buf, shroud)))
1194             memset(cp, '*', strlen(shroud));
1195         buf[strlen(buf)-1] = '\0';
1196         error(0, 0, "%s> %s", protocol->name, buf);
1197     }
1198 }
1199
1200 #if defined(HAVE_STDARG_H)
1201 int gen_transact(FILE *sockfp, char *fmt, ... )
1202 /* assemble command in printf(3) style, send to server, accept a response */
1203 #else
1204 int gen_transact(sockfp, fmt, va_alist)
1205 /* assemble command in printf(3) style, send to server, accept a response */
1206 FILE *sockfp;           /* socket to which server is connected */
1207 const char *fmt;        /* printf-style format */
1208 va_dcl
1209 #endif
1210 {
1211     int ok;
1212     char buf [POPBUFSIZE+1];
1213     va_list ap;
1214
1215     if (protocol->tagged)
1216         (void) sprintf(buf, "%s ", GENSYM);
1217     else
1218         buf[0] = '\0';
1219
1220 #if defined(HAVE_STDARG_H)
1221     va_start(ap, fmt) ;
1222 #else
1223     va_start(ap);
1224 #endif
1225     vsprintf(buf + strlen(buf), fmt, ap);
1226     va_end(ap);
1227
1228     strcat(buf, "\r\n");
1229     fputs(buf, sockfp);
1230     if (outlevel == O_VERBOSE)
1231     {
1232         char *cp;
1233
1234         if (shroud && (cp = strstr(buf, shroud)))
1235             memset(cp, '*', strlen(shroud));
1236         buf[strlen(buf)-1] = '\0';
1237         error(0, 0, "%s> %s", protocol->name, buf);
1238     }
1239
1240     /* we presume this does its own response echoing */
1241     ok = (protocol->parse_response)(sockfp, buf);
1242     vtalarm(mytimeout);
1243
1244     return(ok);
1245 }
1246
1247 /* driver.c ends here */