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