From 5283e32c823c36f7904691441c1241edde8ca7b1 Mon Sep 17 00:00:00 2001 From: "Eric S. Raymond" Date: Fri, 28 Feb 2003 10:53:49 +0000 Subject: [PATCH] Before the IDLE patch. svn path=/trunk/; revision=3792 --- NEWS | 6 +++ imap.c | 62 ++++++++++++++--------- indexgen.sh | 2 +- pop3.c | 138 +++++++++++++++++++++++++++++++--------------------- rcfile_y.y | 6 +-- transact.c | 22 ++++----- 6 files changed, 142 insertions(+), 94 deletions(-) diff --git a/NEWS b/NEWS index 3f76e34c..f52f1035 100644 --- a/NEWS +++ b/NEWS @@ -2,6 +2,12 @@ (The `lines' figures total .c, .h, .l, and .y files under version control.) +* Sunil Shetye's patch to imprive behavior in empty messages. +* Conform to RFC2595; reissue capability probes after successful + STARTTLS negotiation. +* Sunil's patch to make handling of failed STARTTLS more graceful. +* Sunil's JF2 fix patch for .fetchmailrc security fix. + fetchmail-6.2.1 (Tue Jan 14 08:17:19 EST 2003), 22219 lines: * Updated German, Turkish, Spanish, and Danish translation files. diff --git a/imap.c b/imap.c index 3ea5c27d..9d4a506d 100644 --- a/imap.c +++ b/imap.c @@ -248,13 +248,10 @@ static int imap_canonicalize(char *result, char *raw, int maxlen) return(i); } -static int imap_getauth(int sock, struct query *ctl, char *greeting) -/* apply for connection authorization */ +static void capa_probe(int sock, struct query *ctl) +/* set capability variables from a CAPA probe */ { - int ok = 0; -#ifdef SSL_ENABLE - flag did_stls = FALSE; -#endif /* SSL_ENABLE */ + int ok; /* probe to see if we're running IMAP4 and can use RFC822.PEEK */ capabilities[0] = '\0'; @@ -287,19 +284,6 @@ static int imap_getauth(int sock, struct query *ctl, char *greeting) if (outlevel >= O_DEBUG) report(stdout, GT_("Protocol identified as IMAP2 or IMAP2BIS\n")); } - else - return(ok); - - peek_capable = (imap_version >= IMAP4); - - /* - * Assumption: expunges are cheap, so we want to do them - * after every message unless user said otherwise. - */ - if (NUM_SPECIFIED(ctl->expunge)) - expunge_period = NUM_VALUE_OUT(ctl->expunge); - else - expunge_period = 1; /* * Handle idling. We depend on coming through here on startup @@ -311,6 +295,17 @@ static int imap_getauth(int sock, struct query *ctl, char *greeting) if (outlevel >= O_VERBOSE) report(stdout, GT_("will idle after poll\n")); } +} + +static int imap_getauth(int sock, struct query *ctl, char *greeting) +/* apply for connection authorization */ +{ + int ok = 0; +#ifdef SSL_ENABLE + flag did_stls = FALSE; +#endif /* SSL_ENABLE */ + + capa_probe(sock, ctl); /* * If either (a) we saw a PREAUTH token in the greeting, or @@ -321,7 +316,6 @@ static int imap_getauth(int sock, struct query *ctl, char *greeting) preauth = FALSE; /* reset for the next session */ return(PS_SUCCESS); } - /* * Time to authenticate the user. * Try the protocol variants that don't require passwords first. @@ -369,12 +363,13 @@ static int imap_getauth(int sock, struct query *ctl, char *greeting) char *realhost; realhost = ctl->server.via ? ctl->server.via : ctl->server.pollname; - gen_transact(sock, "STARTTLS"); + ok = gen_transact(sock, "STARTTLS"); /* We use "tls1" instead of ctl->sslproto, as we want STARTTLS, * not other SSL protocols */ - if (SSLOpen(sock,ctl->sslcert,ctl->sslkey,"tls1",ctl->sslcertck, ctl->sslcertpath,ctl->sslfingerprint,realhost,ctl->server.pollname) == -1) + if (ok == PS_SUCCESS && + SSLOpen(sock,ctl->sslcert,ctl->sslkey,"tls1",ctl->sslcertck, ctl->sslcertpath,ctl->sslfingerprint,realhost,ctl->server.pollname) == -1) { if (!ctl->sslproto && !ctl->wehaveauthed) { @@ -387,9 +382,32 @@ static int imap_getauth(int sock, struct query *ctl, char *greeting) return(PS_AUTHFAIL); } did_stls = TRUE; + + /* + * RFC 2595 says this: + * + * "Once TLS has been started, the client MUST discard cached + * information about server capabilities and SHOULD re-issue the + * CAPABILITY command. This is necessary to protect against + * man-in-the-middle attacks which alter the capabilities list prior + * to STARTTLS. The server MAY advertise different capabilities + * after STARTTLS." + */ + capa_probe(sock, ctl); } #endif /* SSL_ENABLE */ + peek_capable = (imap_version >= IMAP4); + + /* + * Assumption: expunges are cheap, so we want to do them + * after every message unless user said otherwise. + */ + if (NUM_SPECIFIED(ctl->expunge)) + expunge_period = NUM_VALUE_OUT(ctl->expunge); + else + expunge_period = 1; + /* * No such luck. OK, now try the variants that mask your password * in a challenge-response. diff --git a/indexgen.sh b/indexgen.sh index 7917b501..0843952c 100755 --- a/indexgen.sh +++ b/indexgen.sh @@ -278,7 +278,7 @@ as a technical effort. I ran it as a test of some theories about why the Linux development model works.

I wrote a paper, The +href="http://www.catb.org/~esr/writings/cathedral-bazaar/">The Cathedral And The Bazaar, about these theories and the project. I developed the line of analysis it suggested in two later essays. These papers became quite popular and (to my continuing astonishment) may diff --git a/pop3.c b/pop3.c index a2f7d5f0..123e1b81 100644 --- a/pop3.c +++ b/pop3.c @@ -39,6 +39,21 @@ char *sdps_envto; static char lastok[POPBUFSIZE+1]; #endif /* OPIE_ENABLE */ +/* these variables are shared between the CAPA probe and the authenticator */ +#if defined(GSSAPI) + flag has_gssapi = FALSE; +#endif /* defined(GSSAPI) */ +#if defined(KERBEROS_V4) || defined(KERBEROS_V5) + flag has_kerberos = FALSE; +#endif /* defined(KERBEROS_V4) || defined(KERBEROS_V5) */ + flag has_cram = FALSE; +#ifdef OPIE_ENABLE + flag has_otp = FALSE; +#endif /* OPIE_ENABLE */ +#ifdef SSL_ENABLE + flag has_ssl = FALSE; +#endif /* SSL_ENABLE */ + #define DOTLINE(s) (s[0] == '.' && (s[1]=='\r'||s[1]=='\n'||s[1]=='\0')) static int pop3_ok (int sock, char *argbuf) @@ -124,6 +139,46 @@ static int pop3_ok (int sock, char *argbuf) return(ok); } + + +static int capa_probe(sock) +/* probe the capabilities of the remote server */ +{ + int ok; + + ok = gen_transact(sock, "CAPA"); + if (ok == PS_SUCCESS) + { + char buffer[64]; + + /* determine what authentication methods we have available */ + while ((ok = gen_recv(sock, buffer, sizeof(buffer))) == 0) + { + if (DOTLINE(buffer)) + break; +#ifdef SSL_ENABLE + if (strstr(buffer, "STLS")) + has_ssl = TRUE; +#endif /* SSL_ENABLE */ +#if defined(GSSAPI) + if (strstr(buffer, "GSSAPI")) + has_gssapi = TRUE; +#endif /* defined(GSSAPI) */ +#if defined(KERBEROS_V4) + if (strstr(buffer, "KERBEROS_V4")) + has_kerberos = TRUE; +#endif /* defined(KERBEROS_V4) */ +#ifdef OPIE_ENABLE + if (strstr(buffer, "X-OTP")) + has_otp = TRUE; +#endif /* OPIE_ENABLE */ + if (strstr(buffer, "CRAM-MD5")) + has_cram = TRUE; + } + } + return(ok); +} + static int pop3_getauth(int sock, struct query *ctl, char *greeting) /* apply for connection authorization */ { @@ -133,18 +188,7 @@ static int pop3_getauth(int sock, struct query *ctl, char *greeting) #if OPIE_ENABLE char *challenge; #endif /* OPIE_ENABLE */ -#if defined(GSSAPI) - flag has_gssapi = FALSE; -#endif /* defined(GSSAPI) */ -#if defined(KERBEROS_V4) || defined(KERBEROS_V5) - flag has_kerberos = FALSE; -#endif /* defined(KERBEROS_V4) || defined(KERBEROS_V5) */ - flag has_cram = FALSE; -#ifdef OPIE_ENABLE - flag has_otp = FALSE; -#endif /* OPIE_ENABLE */ #ifdef SSL_ENABLE - flag has_ssl = FALSE; flag did_stls = FALSE; #endif /* SSL_ENABLE */ @@ -201,50 +245,21 @@ static int pop3_getauth(int sock, struct query *ctl, char *greeting) */ if (ctl->server.authenticate == A_ANY) { - ok = gen_transact(sock, "CAPA"); - if (ok == PS_SUCCESS) - { - char buffer[64]; - - /* determine what authentication methods we have available */ - while ((ok = gen_recv(sock, buffer, sizeof(buffer))) == 0) + if (capa_probe(sock) != PS_SUCCESS) + /* we are in STAGE_GETAUTH! */ + if (ok == PS_AUTHFAIL || + /* Some servers directly close the socket. However, if we + * have already authenticated before, then a previous CAPA + * must have succeeded. In that case, treat this as a + * genuine socket error and do not change the auth method. + */ + (ok == PS_SOCKET && !ctl->wehaveauthed)) { - if (DOTLINE(buffer)) - break; -#ifdef SSL_ENABLE - if (strstr(buffer, "STLS")) - has_ssl = TRUE; -#endif /* SSL_ENABLE */ -#if defined(GSSAPI) - if (strstr(buffer, "GSSAPI")) - has_gssapi = TRUE; -#endif /* defined(GSSAPI) */ -#if defined(KERBEROS_V4) - if (strstr(buffer, "KERBEROS_V4")) - has_kerberos = TRUE; -#endif /* defined(KERBEROS_V4) */ -#ifdef OPIE_ENABLE - if (strstr(buffer, "X-OTP")) - has_otp = TRUE; -#endif /* OPIE_ENABLE */ - if (strstr(buffer, "CRAM-MD5")) - has_cram = TRUE; + ctl->server.authenticate = A_PASSWORD; + /* repoll immediately */ + ok = PS_REPOLL; + break; } - } - /* we are in STAGE_GETAUTH! */ - else if (ok == PS_AUTHFAIL || - /* Some servers directly close the socket. However, if we - * have already authenticated before, then a previous CAPA - * must have succeeded. In that case, treat this as a - * genuine socket error and do not change the auth method. - */ - (ok == PS_SOCKET && !ctl->wehaveauthed)) - { - ctl->server.authenticate = A_PASSWORD; - /* repoll immediately */ - ok = PS_REPOLL; - break; - } } #ifdef SSL_ENABLE @@ -255,12 +270,13 @@ static int pop3_getauth(int sock, struct query *ctl, char *greeting) char *realhost; realhost = ctl->server.via ? ctl->server.via : ctl->server.pollname; - gen_transact(sock, "STLS"); + ok = gen_transact(sock, "STLS"); /* We use "tls1" instead of ctl->sslproto, as we want STLS, * not other SSL protocols */ - if (SSLOpen(sock,ctl->sslcert,ctl->sslkey,"tls1",ctl->sslcertck, ctl->sslcertpath,ctl->sslfingerprint,realhost,ctl->server.pollname) == -1) + if (ok == PS_SUCCESS && + SSLOpen(sock,ctl->sslcert,ctl->sslkey,"tls1",ctl->sslcertck, ctl->sslcertpath,ctl->sslfingerprint,realhost,ctl->server.pollname) == -1) { if (!ctl->sslproto && !ctl->wehaveauthed) { @@ -273,6 +289,18 @@ static int pop3_getauth(int sock, struct query *ctl, char *greeting) return(PS_AUTHFAIL); } did_stls = TRUE; + + /* + * RFC 2595 says this: + * + * "Once TLS has been started, the client MUST discard cached + * information about server capabilities and SHOULD re-issue the + * CAPABILITY command. This is necessary to protect against + * man-in-the-middle attacks which alter the capabilities list prior + * to STARTTLS. The server MAY advertise different capabilities + * after STARTTLS." + */ + capa_probe(sock); } #endif /* SSL_ENABLE */ diff --git a/rcfile_y.y b/rcfile_y.y index 3dac325b..bd5faa6d 100644 --- a/rcfile_y.y +++ b/rcfile_y.y @@ -428,14 +428,14 @@ int prc_filecheck(const char *pathname, const flag securecheck) if (!securecheck) return PS_SUCCESS; - if ((statbuf.st_mode & S_IFLNK) == S_IFLNK) + if (!S_ISREG(statbuf.st_mode)) { - fprintf(stderr, GT_("File %s must not be a symbolic link.\n"), pathname); + fprintf(stderr, GT_("File %s must be a regular file.\n"), pathname); return(PS_IOERR); } #ifndef __BEOS__ - if (statbuf.st_mode & ~(S_IFREG | S_IREAD | S_IWRITE | S_IEXEC | S_IXGRP)) + if (statbuf.st_mode & (S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH | S_IXOTH)) { fprintf(stderr, GT_("File %s must have no more than -rwx--x--- (0710) permissions.\n"), pathname); diff --git a/transact.c b/transact.c index f419828e..6fbe1879 100644 --- a/transact.c +++ b/transact.c @@ -864,18 +864,6 @@ int readheaders(int sock, } } - /* - * We want to detect this early in case there are so few headers that the - * dispatch logic barfs. - */ - if (!headers_ok) - { - if (outlevel > O_SILENT) - report(stdout, - GT_("message delimiter found while scanning headers\n")); - return(PS_TRUNCATED); - } - /* * Hack time. If the first line of the message was blank, with no headers * (this happens occasionally due to bad gatewaying software) cons up @@ -1255,7 +1243,15 @@ int readheaders(int sock, *cp++ = '\0'; stuffline(ctl, buf); - return(headers_ok ? PS_SUCCESS : PS_TRUNCATED); + if (!headers_ok) + { + if (outlevel > O_SILENT) + report(stdout, + GT_("message delimiter found while scanning headers\n")); + return(PS_TRUNCATED); + } + + return(PS_SUCCESS); } int readbody(int sock, struct query *ctl, flag forward, int len) -- 2.43.2