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