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