Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
SUSE:SLE-15-SP2:GA
fetchmail.21478
fetchmail-CVE-2021-39272.patch
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File fetchmail-CVE-2021-39272.patch of Package fetchmail.21478
Index: fetchmail-6.3.26/base64.c =================================================================== --- fetchmail-6.3.26.orig/base64.c +++ fetchmail-6.3.26/base64.c @@ -27,6 +27,11 @@ static const char base64val[] = { }; #define DECODE64(c) (isascii((unsigned char)(c)) ? base64val[c] : BAD) +unsigned len64frombits(unsigned inlen) +{ + return (inlen + 2)/3*4; +} + void to64frombits(char *out, const void *in_, int inlen) /* raw bytes in quasi-big-endian order to base 64 string (NUL-terminated) */ { Index: fetchmail-6.3.26/driver.c =================================================================== --- fetchmail-6.3.26.orig/driver.c +++ fetchmail-6.3.26/driver.c @@ -865,6 +865,7 @@ static int do_session( SIGHANDLERTYPE alrmsave; ctl->server.base_protocol = proto; + stage = STAGE_GETAUTH; msgsizes = NULL; pass = 0; @@ -964,6 +965,12 @@ static int do_session( goto closeUp; } + /* initialize protocol */ + if (ctl->server.base_protocol->construct) { + err = (ctl->server.base_protocol->construct)(ctl); + if (err) goto cleanUp; + } + /* open a socket to the mail server */ oldphase = phase; phase = OPEN_WAIT; @@ -1152,7 +1159,6 @@ static int do_session( goto cleanUp; /* try to get authorized to fetch mail */ - stage = STAGE_GETAUTH; if (ctl->server.base_protocol->getauth) { set_timeout(mytimeout); @@ -1242,10 +1248,18 @@ is restored.")); ctl->remotename, ctl->server.truename); } + else if (err == PS_SOCKET) + { + report(stderr, GT_("Socket or TLS error on %s@%s\n"), + ctl->remotename, + ctl->server.truename); + } else + { report(stderr, GT_("Unknown login or authentication error on %s@%s\n"), ctl->remotename, ctl->server.truename); + } goto cleanUp; } @@ -1538,6 +1552,11 @@ is restored.")); cleanupSockClose(mailserver_socket_temp); mailserver_socket_temp = -1; } + + /* clean up protocol */ + if (ctl->server.base_protocol->destruct) { + ctl->server.base_protocol->destruct(ctl); + } } /* no report on PS_AUTHFAIL */ Index: fetchmail-6.3.26/etrn.c =================================================================== --- fetchmail-6.3.26.orig/etrn.c +++ fetchmail-6.3.26/etrn.c @@ -143,6 +143,8 @@ static const struct method etrn = NULL, /* no mailbox support */ etrn_logout, /* log out, we're done */ FALSE, /* no, we can't re-poll */ + NULL, /* no constructor */ + NULL /* no destructor */ }; int doETRN (struct query *ctl) Index: fetchmail-6.3.26/fetchmail.c =================================================================== --- fetchmail-6.3.26.orig/fetchmail.c +++ fetchmail-6.3.26/fetchmail.c @@ -722,7 +722,7 @@ int main(int argc, char **argv) /* Boldly assume that we also have res_init() if we have * res_search(), and call res_init() to re-read the resolv.conf * file, so that we can pick up changes to that file that are - * written by dhpccd, dhclient, pppd, openvpn and similar. */ + * written by dhcpcd, dhclient, pppd, openvpn and similar. */ /* NOTE: This assumes that /etc/resolv.conf is written * atomically (i. e. a temporary file is written, flushed and @@ -1356,6 +1356,16 @@ static int load_params(int argc, char ** ctl->server.pollname); exit(PS_SYNTAX); } + switch (ctl->server.protocol) { + case P_POP3: case P_APOP: + if (port == 995 && !ctl->use_ssl) report(stderr, GT_("WARNING: %s configuration invalid, you normally need --ssl for port 995/service pop3s.\n"), ctl->server.pollname); + if (port == 110 && ctl->use_ssl) report(stderr, GT_("WARNING: %s configuration invalid, you normally need port 995/service pop3s for --ssl.\n"), ctl->server.pollname); + break; + case P_IMAP: + if (port == 993 && !ctl->use_ssl) report(stderr, GT_("WARNING: %s configuration invalid, you normally need --ssl for port 993/service imaps.\n"), ctl->server.pollname); + if (port == 143 && ctl->use_ssl) report(stderr, GT_("WARNING: %s configuration invalid, you normally need port 993/service imaps for --ssl.\n"), ctl->server.pollname); + break; + } } if (ctl->listener == LMTP_MODE) { Index: fetchmail-6.3.26/fetchmail.h =================================================================== --- fetchmail-6.3.26.orig/fetchmail.h +++ fetchmail-6.3.26/fetchmail.h @@ -254,6 +254,8 @@ struct method /* describe methods for p int (*logout_cmd)(int, struct query *); /* logout command */ flag retry; /* can getrange poll for new messages? */ + int (*construct)(struct query *); /* session setup before first command */ + int (*destruct)(struct query *); /* cleanup after session */ }; enum badheader { BHREJECT = 0, BHACCEPT }; @@ -270,7 +272,7 @@ struct hostdata /* shared among all use int interval; /* # cycles to skip between polls */ int authenticate; /* authentication mode to try */ int timeout; /* inactivity timout in seconds */ - char *envelope; /* envelope address list header */ + char *envelope; /* envelope address list header - WARNING - can take value STRING_DISABLED (-1)! */ int envskip; /* skip to numbered envelope header */ char *qvirtual; /* prefix removed from local user id */ flag skip; /* suppress poll in implicit mode? */ @@ -636,6 +638,7 @@ int prc_parse_file(const char *, const f int prc_filecheck(const char *, const flag); /* base64.c */ +unsigned len64frombits(unsigned inlen); /** calculate length needed to encode inlen octets. warnings: 1. caller needs to add 1 for a trailing \0 byte himself. 2. returns 0 for inlen 0! */ void to64frombits(char *, const void *, int); int from64tobits(void *, const char *, int maxlen); Index: fetchmail-6.3.26/fetchmail.man =================================================================== --- fetchmail-6.3.26.orig/fetchmail.man +++ fetchmail-6.3.26/fetchmail.man @@ -69,7 +69,12 @@ language (if supported). However if you please leave it in. The maintainers do not necessarily understand your language, please use English. - +.SH TLS (SSL) QUICKSTART +.PP +Your fetchmail distribution should have come with a README.SSL file, which see. +It is recommended to configure all polls with --ssl --sslproto tls1.2+ +if supported by the server, which configures fetchmail along recent IETF +proposed standards and best current practices, RFC-8314, RFC-8996, RFC-8997. .SS CONCEPTS If \fBfetchmail\fP is used with a POP or an IMAP server (but not with @@ -412,13 +417,11 @@ from. The folder information is written .B \-\-ssl (Keyword: ssl) .br -Causes the connection to the mail server to be encrypted -via SSL. Connect to the server using the specified base protocol over a -connection secured by SSL. This option defeats opportunistic starttls -negotiation. It is highly recommended to use \-\-sslproto 'SSL3' -\-\-sslcertck to validate the certificates presented by the server and -defeat the obsolete SSLv2 negotiation. More information is available in -the \fIREADME.SSL\fP file that ships with fetchmail. +Causes the connection to the mail server to be encrypted via SSL, by +negotiating SSL directly after connecting (called SSL-wrapped mode, or +Implicit TLS by RFC-8314). Please see the description of \-\-sslproto +below! More information is available in the \fIREADME.SSL\fP file that +ships with fetchmail. .IP Note that fetchmail may still try to negotiate SSL through starttls even if this option is omitted. You can use the \-\-sslproto option to defeat Index: fetchmail-6.3.26/imap.c =================================================================== --- fetchmail-6.3.26.orig/imap.c +++ fetchmail-6.3.26/imap.c @@ -34,9 +34,22 @@ static int preauth = FALSE; /* session variables initialized in capa_probe() or imap_getauth() */ static char capabilities[MSGBUFSIZE+1]; static int imap_version = IMAP4; -static flag do_idle = FALSE, has_idle = FALSE; +static flag has_idle = FALSE; static int expunge_period = 1; +static void clear_sessiondata(void) { + /* must match defaults above */ + preauth = FALSE; + memset(capabilities, 0, sizeof(capabilities)); + imap_version = IMAP4; + has_idle = FALSE; + expunge_period = 1; +} + +/* the next ones need to be kept in synch - C89 does not consider strlen() + * a const initializer */ +const char *const capa_begin = " [CAPABILITY "; const unsigned capa_len = 13; + /* mailbox variables initialized in imap_getrange() */ static int count = 0, oldcount = 0, recentcount = 0, unseen = 0, deletions = 0; static unsigned int startcount = 1; @@ -50,6 +63,56 @@ static int actual_deletions = 0; static int saved_timeout = 0, idle_timeout = 0; static time_t idle_start_time = 0; +static int imap_setup(struct query *ctl) +{ + (void)ctl; + clear_sessiondata(); + return PS_SUCCESS; +} + +static int imap_cleanup(struct query *ctl) +{ + (void)ctl; + clear_sessiondata(); + return PS_SUCCESS; +} + +static void copy_capabilities(const char *buf) +{ + strlcpy(capabilities, buf, sizeof(capabilities)); + capabilities[strcspn(capabilities, "]")] = '\0'; /* truncate at ] */ + + /* UW-IMAP server 10.173 notifies in all caps, but RFC2060 says we + should expect a response in mixed-case */ + if (strstr(capabilities, "IMAP4REV1")) { + imap_version = IMAP4rev1; /* RFC-3501 (2060) */ + if (outlevel >= O_DEBUG) + report(stdout, GT_("Protocol identified as IMAP4 rev 1\n")); + } else if (strstr(capabilities, "IMAP4")) { + imap_version = IMAP4; /* RFC-1730 */ + if (outlevel >= O_DEBUG) + report(stdout, GT_("Protocol identified as IMAP4 rev 0\n")); + } else { + imap_version = IMAP2; + if (outlevel >= O_DEBUG) + report(stdout, GT_("Protocol identified as IMAP2 or IMAP2BIS\n")); + } + + /* + * Handle idling. We depend on coming through here on startup + * and after each timeout (including timeouts during idles). + */ + if (strstr(capabilities, "IDLE")) + has_idle = TRUE; + else + has_idle = FALSE; + if (outlevel >= O_VERBOSE) + report(stdout, GT_("will idle after poll\n")); /* FIXME: rename this to can... idle for next release */ + + peek_capable = (imap_version >= IMAP4); +} + + static int imap_untagged_response(int sock, const char *buf) /* interpret untagged status responses */ { @@ -58,7 +121,7 @@ static int imap_untagged_response(int so if (stage == STAGE_GETAUTH && !strncmp(buf, "* CAPABILITY", 12)) { - strlcpy(capabilities, buf + 12, sizeof(capabilities)); + copy_capabilities(buf + 12); } else if (stage == STAGE_GETAUTH && !strncmp(buf, "* PREAUTH", 9)) @@ -183,6 +246,7 @@ static int imap_response(int sock, char /* parse command response */ { char buf[MSGBUFSIZE+1]; + char *tmp; do { int ok; @@ -200,6 +264,9 @@ static int imap_response(int sock, char if (islower((unsigned char)*cp)) *cp = toupper((unsigned char)*cp); + /* FIXME: does not look for or handle command continuation requests, + * i. e. the token "+" instead of tag or "*" */ + /* untagged responses start with "* " */ if (buf[0] == '*' && buf[1] == ' ') { ok = imap_untagged_response(sock, buf); @@ -219,6 +286,19 @@ static int imap_response(int sock, char return(ok); } + /* on login, the server may volunteer new CAPABILITY information + * with the tagged OK response, record it */ + /* WARNING: this must match with what's in imap_getauth()! */ + if (stage == STAGE_GETAUTH + && (tmp = strstr(buf, capa_begin))) + { + copy_capabilities(tmp + capa_len); + + if (outlevel >= O_DEBUG) { + report(stdout, GT_("found updated capabilities list\n")); + } + } + if (stage == STAGE_IDLE) { /* reduce the timeout: servers may not reset their timeout @@ -327,118 +407,89 @@ static void imap_canonicalize(char *resu static int capa_probe(int sock, struct query *ctl) /* set capability variables from a CAPA probe */ { - int ok; + int err; - /* probe to see if we're running IMAP4 and can use RFC822.PEEK */ - capabilities[0] = '\0'; - if ((ok = gen_transact(sock, "CAPABILITY")) == PS_SUCCESS) - { - char *cp; - - /* capability checks are supposed to be caseblind */ - for (cp = capabilities; *cp; cp++) - *cp = toupper((unsigned char)*cp); - - /* UW-IMAP server 10.173 notifies in all caps, but RFC2060 says we - should expect a response in mixed-case */ - if (strstr(capabilities, "IMAP4REV1")) - { - imap_version = IMAP4rev1; - if (outlevel >= O_DEBUG) - report(stdout, GT_("Protocol identified as IMAP4 rev 1\n")); - } - else - { - imap_version = IMAP4; - if (outlevel >= O_DEBUG) - report(stdout, GT_("Protocol identified as IMAP4 rev 0\n")); - } - } - else if (ok == PS_ERROR) - { - imap_version = IMAP2; - if (outlevel >= O_DEBUG) - report(stdout, GT_("Protocol identified as IMAP2 or IMAP2BIS\n")); - } - else - return ok; + (void)ctl; - /* - * Handle idling. We depend on coming through here on startup - * and after each timeout (including timeouts during idles). - */ - do_idle = ctl->idle; - if (ctl->idle) - { - if (strstr(capabilities, "IDLE")) - has_idle = TRUE; - else - has_idle = FALSE; - if (outlevel >= O_VERBOSE) - report(stdout, GT_("will idle after poll\n")); + /* probe to see if we're running IMAP4 and can use RFC822.PEEK */ + memset(capabilities, 0, sizeof capabilities); + err = gen_transact(sock, "CAPABILITY"); + /* if successful, copy_capabilities() will have handled it */ + if (err == PS_ERROR) { + /* this is OK for IMAP2 which did not support a CAPABILITY command */ + err = PS_SUCCESS; } - peek_capable = (imap_version >= IMAP4); - - return PS_SUCCESS; + return err; } -static int do_authcert (int sock, const char *command, const char *name) +static int do_auth_external (int sock, const char *command, const char *name) /* do authentication "external" (authentication provided by client cert) */ { + /* FIXME: not compliant with RFC 4422 (SASL) without RFC 4959 (SASL-IR)- + * does not support the usual server challenge/response + */ char buf[256]; + if (!strstr(capabilities, "SASL-IR")) { + report(stderr, GT_("server did not advertise SASL-IR extension but fetchmail's implementation requires it for AUTHENTICATE EXTERNAL\n")); + return PS_AUTHFAIL; + } + if (name && name[0]) { size_t len = strlen(name); - if ((len / 3) + ((len % 3) ? 4 : 0) < sizeof(buf)) + if (len64frombits(len) + 1 <= sizeof(buf)) /* +1: need to fit \0 byte */ to64frombits (buf, name, strlen(name)); else return PS_AUTHFAIL; /* buffer too small. */ } else - buf[0]=0; + { + strcpy(buf, "="); + } return gen_transact(sock, "%s EXTERNAL %s",command,buf); } +/** apply for connection authorization, possibly executing STARTTLS */ static int imap_getauth(int sock, struct query *ctl, char *greeting) -/* apply for connection authorization */ { int ok = 0; - (void)greeting; + char *commonname; /* * 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); + expunge_period = NUM_VALUE_OUT(ctl->expunge); else - expunge_period = 1; - - if ((ok = capa_probe(sock, ctl))) - return ok; + expunge_period = 1; - /* - * If either (a) we saw a PREAUTH token in the greeting, or - * (b) the user specified ssh preauthentication, then we're done. - */ - if (preauth || ctl->server.authenticate == A_SSH) - { - preauth = FALSE; /* reset for the next session */ - return(PS_SUCCESS); + /* check if imap_ok() has already parsed CAPABILITY from the greeting when + * driver.c ran it on the server's greeting message - note this must match + * with what's in imap_response()! */ + if (!strstr(greeting, capa_begin)) { + int err = capa_probe(sock, ctl); + if (err) return err; } -#ifdef SSL_ENABLE - if (maybe_tls(ctl)) { - char *commonname; - commonname = ctl->server.pollname; if (ctl->server.via) commonname = ctl->server.via; if (ctl->sslcommonname) commonname = ctl->sslcommonname; +#ifdef SSL_ENABLE + /* Defend against a PREAUTH-prevents-STARTTLS attack */ + if (preauth && must_tls(ctl)) { + report(stderr, GT_("%s: configuration requires TLS, but STARTTLS is not permitted " + "because of authenticated state (PREAUTH). Aborting connection. Server permitting, try --ssl instead (see manual).\n"), commonname); + preauth = FALSE; /* reset for the next session */ + return PS_SOCKET; + } + + if (maybe_tls(ctl)) { if (strstr(capabilities, "STARTTLS") || must_tls(ctl)) /* if TLS is mandatory, ignore capabilities */ { @@ -451,6 +502,11 @@ static int imap_getauth(int sock, struct ctl->sslcertfile, ctl->sslcertpath, ctl->sslfingerprint, commonname, ctl->server.pollname, &ctl->remotename)) != -1) { + if (outlevel >= O_VERBOSE) + { + report(stdout, GT_("%s: upgrade to TLS succeeded.\n"), commonname); + } + /* * RFC 2595 says this: * @@ -464,11 +520,10 @@ static int imap_getauth(int sock, struct * Now that we're confident in our TLS connection we can * guarantee a secure capability re-probe. */ + clear_sessiondata(); if ((ok = capa_probe(sock, ctl))) - return ok; - if (outlevel >= O_VERBOSE) { - report(stdout, GT_("%s: upgrade to TLS succeeded.\n"), commonname); + return ok; } } else if (must_tls(ctl)) { /* Config required TLS but we couldn't guarantee it, so we must @@ -496,10 +551,23 @@ static int imap_getauth(int sock, struct #endif /* SSL_ENABLE */ /* + * If either (a) we saw a PREAUTH token in the greeting, or + * (b) the user specified ssh preauthentication, then we're done. + */ + if (preauth || ctl->server.authenticate == A_SSH) + { + 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. */ - ok = PS_AUTHFAIL; + ok = PS_AUTHFAIL; /* formally, never read, + but let's leave this in place as a safe default + for future maintenance */ + (void)ok; /* Yahoo hack - we'll just try ID if it was offered by the server, * and IGNORE errors. */ @@ -510,19 +578,23 @@ static int imap_getauth(int sock, struct } } - if ((ctl->server.authenticate == A_ANY + if (ctl->server.authenticate == A_ANY || ctl->server.authenticate == A_EXTERNAL) - && strstr(capabilities, "AUTH=EXTERNAL")) { - ok = do_authcert(sock, "AUTHENTICATE", ctl->remotename); - if (ok) - { - /* SASL cancellation of authentication */ - gen_send(sock, "*"); - if (ctl->server.authenticate != A_ANY) - return ok; - } else { - return ok; + if (!strstr(capabilities, "AUTH=EXTERNAL")) { + if (ctl->server.authenticate == A_EXTERNAL) { + report(stderr, GT_("%s: --auth external requested but server does not advertise it.\n"), commonname); + return PS_AUTHFAIL; + } + } else { + int err = do_auth_external(sock, "AUTHENTICATE", ctl->remotename); + if (err) + { + if (ctl->server.authenticate != A_ANY) + return err; + } else { + return PS_SUCCESS; + } } } @@ -630,42 +702,44 @@ static int imap_getauth(int sock, struct /* * We're stuck with sending the password en clair. - * The reason for this odd-looking logic is that some - * servers return LOGINDISABLED even though login - * actually works. So arrange things in such a way that - * setting auth passwd makes it ignore this capability. - */ - if((ctl->server.authenticate==A_ANY&&!strstr(capabilities,"LOGINDISABLED")) - || ctl->server.authenticate == A_PASSWORD) - { - /* these sizes guarantee no buffer overflow */ - char *remotename, *password; - size_t rnl, pwl; - rnl = 2 * strlen(ctl->remotename) + 1; - pwl = 2 * strlen(ctl->password) + 1; - remotename = (char *)xmalloc(rnl); - password = (char *)xmalloc(pwl); - - imap_canonicalize(remotename, ctl->remotename, rnl); - imap_canonicalize(password, ctl->password, pwl); - - snprintf(shroud, sizeof (shroud), "\"%s\"", password); - ok = gen_transact(sock, "LOGIN \"%s\" \"%s\"", remotename, password); - memset(shroud, 0x55, sizeof(shroud)); - shroud[0] = '\0'; - memset(password, 0x55, strlen(password)); - free(password); - free(remotename); - if (ok) - { - if(ctl->server.authenticate != A_ANY) - return ok; + * Older fetchmail versions permitted overriding LOGINDISABLED, documenting + * that it still works on some servers, but 6.4.22 disables this. */ + if (ctl->server.authenticate == A_ANY + || ctl->server.authenticate == A_PASSWORD) + { + if (strstr(capabilities, "LOGINDISABLED")) { + if (ctl->server.authenticate == A_PASSWORD) { + report(stderr, GT_("%s: --auth password requested but server forbids it (LOGINDISABLED).\n"), commonname); + return PS_AUTHFAIL; + } + } else { + /* these sizes guarantee no buffer overflow */ + static char *remotename, *password; /* XXX FIXME: not thread-safe but dynamic buffer is leaky on timeout */ + size_t rnl, pwl; + rnl = 2 * strlen(ctl->remotename) + 1; + pwl = 2 * strlen(ctl->password) + 1; + if (remotename) xfree(remotename); + remotename = (char *)xmalloc(rnl); + if (password) xfree(password); + password = (char *)xmalloc(pwl); + + imap_canonicalize(remotename, ctl->remotename, rnl); + imap_canonicalize(password, ctl->password, pwl); + + snprintf(shroud, sizeof (shroud), "\"%s\"", password); + ok = gen_transact(sock, "LOGIN \"%s\" \"%s\"", remotename, password); + memset(shroud, 0x55, sizeof(shroud)); + shroud[0] = '\0'; + memset(password, 0x55, strlen(password)); + xfree(password); + xfree(remotename); + return ok; /* this assumes that password is the last authentication method to try */ } - else - return(ok); } - return(ok); + /* if we're here, we've run out of authentication methods */ + report(stderr, GT_("%s: we've run out of authentication methods and cannot log in.\n"), commonname); + return PS_AUTHFAIL; } static int internal_expunge(int sock) @@ -895,7 +969,7 @@ static int imap_getrange(int sock, * * this is a while loop because imap_idle() might return on other * mailbox changes also */ - while (recentcount == 0 && do_idle) { + while (recentcount == 0 && ctl->idle && has_idle) { smtp_close(ctl, 1); ok = imap_idle(sock); if (ok) @@ -952,7 +1026,7 @@ static int imap_getrange(int sock, count), count); } - if (count == 0 && do_idle) + if (count == 0 && ctl->idle && has_idle) { /* no messages? then we may need to idle until we get some */ while (count == 0) { @@ -1407,6 +1481,8 @@ static const struct method imap = imap_end_mailbox_poll, /* end-of-mailbox processing */ imap_logout, /* expunge and exit */ TRUE, /* yes, we can re-poll */ + imap_setup, /* setup method */ + imap_cleanup /* cleanup method */ }; int doIMAP(struct query *ctl) Index: fetchmail-6.3.26/lock.c =================================================================== --- fetchmail-6.3.26.orig/lock.c +++ fetchmail-6.3.26/lock.c @@ -59,8 +59,11 @@ void fm_lock_setup(struct runctl *ctl) static void unlockit(void) /* must-do actions for exit (but we can't count on being able to do malloc) */ { - if (lockfile && lock_acquired) - unlink(lockfile); + if (lockfile && lock_acquired) { + if (unlink(lockfile)) { + (void)truncate(lockfile, (off_t)0); + } + } } void fm_lock_dispose(void) Index: fetchmail-6.3.26/odmr.c =================================================================== --- fetchmail-6.3.26.orig/odmr.c +++ fetchmail-6.3.26/odmr.c @@ -234,6 +234,8 @@ static const struct method odmr = NULL, /* no mailbox support */ odmr_logout, /* log out, we're done */ FALSE, /* no, we can't re-poll */ + NULL, /* no constructor */ + NULL /* no destructor */ }; int doODMR (struct query *ctl) Index: fetchmail-6.3.26/pop2.c =================================================================== --- fetchmail-6.3.26.orig/pop2.c +++ fetchmail-6.3.26/pop2.c @@ -171,7 +171,9 @@ static const struct method pop2 = NULL, /* how to mark a message as seen */ NULL, /* how to end mailbox processing */ pop2_logout, /* log out, we're done */ - FALSE /* no, we can't re-poll */ + FALSE, /* no, we can't re-poll */ + NULL, /* no constructor */ + NULL /* no destructor */ }; int doPOP2 (struct query *ctl) Index: fetchmail-6.3.26/pop3.c =================================================================== --- fetchmail-6.3.26.orig/pop3.c +++ fetchmail-6.3.26/pop3.c @@ -41,23 +41,29 @@ static char lastok[POPBUFSIZE+1]; #endif /* OPIE_ENABLE */ /* session variables initialized in capa_probe() or pop3_getauth() */ -flag done_capa = FALSE; -#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) */ +/* some of these will not be accessed depending on fetchmail's + * compile-time configuration */ +static flag done_capa = FALSE; +static flag has_gssapi = FALSE; +static flag has_kerberos = FALSE; static flag has_cram = FALSE; -#ifdef OPIE_ENABLE -flag has_otp = FALSE; -#endif /* OPIE_ENABLE */ -#ifdef NTLM_ENABLE -flag has_ntlm = FALSE; -#endif /* NTLM_ENABLE */ -#ifdef SSL_ENABLE +static flag has_otp = FALSE; +static flag has_ntlm = FALSE; static flag has_stls = FALSE; -#endif /* SSL_ENABLE */ + +static void clear_sessiondata(void) { + /* must match defaults above */ +#ifdef OPIE_ENABLE + memset(lastok, 0, sizeof(lastok)); +#endif + done_capa = FALSE; + has_gssapi = FALSE; + has_kerberos = FALSE; + has_cram = FALSE; + has_otp = FALSE; + has_ntlm = FALSE; + has_stls = FALSE; +} /* mailbox variables initialized in pop3_getrange() */ static int last; @@ -106,6 +112,20 @@ static int do_pop3_ntlm(int sock, struct #define DOTLINE(s) (s[0] == '.' && (s[1]=='\r'||s[1]=='\n'||s[1]=='\0')) +static int pop3_setup(struct query *ctl) +{ + (void)ctl; + clear_sessiondata(); + return PS_SUCCESS; +} + +static int pop3_cleanup(struct query *ctl) +{ + (void)ctl; + clear_sessiondata(); + return PS_SUCCESS; +} + static int pop3_ok (int sock, char *argbuf) /* parse command response */ { @@ -129,7 +149,7 @@ static int pop3_ok (int sock, char *argb if (strcmp(buf,"+OK") == 0) { #ifdef OPIE_ENABLE - strcpy(lastok, bufp); + strlcpy(lastok, bufp, sizeof(lastok)); #endif /* OPIE_ENABLE */ ok = 0; } @@ -220,6 +240,7 @@ static int capa_probe(int sock) if (ok == PS_SUCCESS) { char buffer[64]; + char *cp; /* determine what authentication methods we have available */ while ((ok = gen_recv(sock, buffer, sizeof(buffer))) == 0) @@ -227,6 +248,8 @@ static int capa_probe(int sock) if (DOTLINE(buffer)) break; + for (cp = buffer; *cp; cp++) *cp = toupper((unsigned char)*cp); + #ifdef SSL_ENABLE if (strstr(buffer, "STLS")) has_stls = TRUE; @@ -283,21 +306,6 @@ static int pop3_getauth(int sock, struct flag connection_may_have_tls_errors = FALSE; #endif /* SSL_ENABLE */ - done_capa = FALSE; -#if defined(GSSAPI) - has_gssapi = FALSE; -#endif /* defined(GSSAPI) */ -#if defined(KERBEROS_V4) || defined(KERBEROS_V5) - has_kerberos = FALSE; -#endif /* defined(KERBEROS_V4) || defined(KERBEROS_V5) */ - has_cram = FALSE; -#ifdef OPIE_ENABLE - has_otp = FALSE; -#endif /* OPIE_ENABLE */ -#ifdef SSL_ENABLE - has_stls = FALSE; -#endif /* SSL_ENABLE */ - /* Set this up before authentication quits early. */ set_peek_capable(ctl); @@ -329,9 +337,6 @@ static int pop3_getauth(int sock, struct } peek_capable = 0; } - if (ctl->server.authenticate == A_SSH) { - return PS_SUCCESS; - } #ifdef SDPS_ENABLE /* @@ -345,33 +350,6 @@ static int pop3_getauth(int sock, struct switch (ctl->server.protocol) { case P_POP3: -#ifdef RPA_ENABLE - /* XXX FIXME: AUTH probing (RFC1734) should become global */ - /* CompuServe POP3 Servers as of 990730 want AUTH first for RPA */ - if (strstr(ctl->remotename, "@compuserve.com")) - { - /* AUTH command should return a list of available mechanisms */ - if (gen_transact(sock, "AUTH") == 0) - { - char buffer[10]; - flag has_rpa = FALSE; - - while ((ok = gen_recv(sock, buffer, sizeof(buffer))) == 0) - { - if (DOTLINE(buffer)) - break; - if (strncasecmp(buffer, "rpa", 3) == 0) - has_rpa = TRUE; - } - if (has_rpa && !POP3_auth_rpa(ctl->remotename, - ctl->password, sock)) - return(PS_SUCCESS); - } - - return(PS_AUTHFAIL); - } -#endif /* RPA_ENABLE */ - /* * CAPA command may return a list including available * authentication mechanisms and STLS capability. @@ -408,8 +386,8 @@ static int pop3_getauth(int sock, struct #ifdef SSL_ENABLE if (must_tls(ctl)) { /* fail with mandatory STLS without repoll */ - report(stderr, GT_("TLS is mandatory for this session, but server refused CAPA command.\n")); - report(stderr, GT_("The CAPA command is however necessary for TLS.\n")); + report(stderr, GT_("STLS is mandatory for this session, but server refused CAPA command.\n")); + report(stderr, GT_("CAPA command support is, however, necessary for STLS.\n")); return ok; } else if (maybe_tls(ctl)) { /* defeat opportunistic STLS */ @@ -466,15 +444,15 @@ static int pop3_getauth(int sock, struct * guarantee a secure capability re-probe. */ set_timeout(0); - done_capa = FALSE; - ok = capa_probe(sock); - if (ok != PS_SUCCESS) { - return ok; - } if (outlevel >= O_VERBOSE) { report(stdout, GT_("%s: upgrade to TLS succeeded.\n"), commonname); } + clear_sessiondata(); + ok = capa_probe(sock); + if (ok != PS_SUCCESS) { + return ok; + } } else if (must_tls(ctl)) { /* Config required TLS but we couldn't guarantee it, so we must * stop. */ @@ -498,6 +476,48 @@ static int pop3_getauth(int sock, struct } /* maybe_tls() */ #endif /* SSL_ENABLE */ + if (ctl->server.authenticate == A_SSH) { + return PS_SUCCESS; + } + +#ifdef RPA_ENABLE + /* XXX FIXME: AUTH probing (RFC1734) should become global */ + /* CompuServe POP3 Servers as of 990730 want AUTH first for RPA */ + if (strstr(ctl->remotename, "@compuserve.com") + && ctl->server.authenticate == A_ANY) + { + /* AUTH command should return a list of available mechanisms. */ + /* 2021 update: it is unclear which software still supports RPA these days. + This behavior (AUTH without a method argument, to query) + is not sanctioned by RFC-1734 but was/is apparently + supported by Compuserve and Microsoft for their NTLM: + https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-pop3/cb6829e1-d6f4-447b-9092-2671a257563c + */ + if (gen_transact(sock, "AUTH") == 0) + { + char buffer[10]; + flag has_rpa = FALSE; + int err; + + while ((err = gen_recv(sock, buffer, sizeof(buffer))) == 0) + { + if (DOTLINE(buffer)) + break; + if (strncasecmp(buffer, "rpa", 3) == 0) + has_rpa = TRUE; + } + if (err) { + return err; + } + if (has_rpa && !POP3_auth_rpa(ctl->remotename, + ctl->password, sock)) + return PS_SUCCESS; + } + + return PS_AUTHFAIL; + } +#endif /* RPA_ENABLE */ + /* * OK, we have an authentication type now. */ @@ -556,6 +576,7 @@ static int pop3_getauth(int sock, struct { report(stderr, GT_("Required NTLM capability not compiled into fetchmail\n")); + return PS_AUTHFAIL; } #endif @@ -1414,6 +1435,8 @@ static const struct method pop3 = NULL, /* no action at end of mailbox */ pop3_logout, /* log out, we're done */ FALSE, /* no, we can't re-poll */ + pop3_setup, /* setup method */ + pop3_cleanup /* cleanup method */ }; int doPOP3 (struct query *ctl) Index: fetchmail-6.3.26/README.SSL-SERVER =================================================================== --- fetchmail-6.3.26.orig/README.SSL-SERVER +++ fetchmail-6.3.26/README.SSL-SERVER @@ -9,6 +9,11 @@ In order to let any mail client (not jus properly, so that users can be sure their connection is not eavesdropped, there are several requirements that need to be fulfilled. +0. Provide modern TLS implementations: + + Make sure the server supports TLS 1.2 and 1.3. + Older versions are deprecated and may preclude modern clients. + 1. Match certificate and DNS names: The server certificate's "common name" or "subject alternative name" must Index: fetchmail-6.3.26/report.c =================================================================== --- fetchmail-6.3.26.orig/report.c +++ fetchmail-6.3.26/report.c @@ -268,7 +268,7 @@ report_build (FILE *errfp, message, va_a rep_ensuresize(n + 1); VA_START(args, message); - n = report_vbuild(message, args); + (void)report_vbuild(message, args); va_end(args); #else { @@ -332,7 +332,7 @@ report_complete (FILE *errfp, message, v rep_ensuresize(n + 1); VA_START(args, message); - n = report_vbuild(message, args); + (void)report_vbuild(message, args); va_end(args); #else report_build(errfp, message, a1, a2, a3, a4, a5, a6, a7, a8); Index: fetchmail-6.3.26/socket.c =================================================================== --- fetchmail-6.3.26.orig/socket.c +++ fetchmail-6.3.26/socket.c @@ -81,7 +81,20 @@ extern int h_errno; #endif /* ndef h_errno */ #ifdef HAVE_SOCKETPAIR -static char *const *parse_plugin(const char *plugin, const char *host, const char *service) +static void free_plugindata(char **argvec) +{ + if (argvec) { + xfree(*argvec); + xfree(argvec); + } +} + +/** parse plugin and interpolate %h and %p with single-quoted host and service. + * Returns a malloc()ed pointer to a NULL-terminated vector of pointers, of + * which the first is also malloc()ed and the 2nd and later ones (if present) + * are pointers into the same memory region - these serve as input for the + * argument vector of execvp() in handle_plugin. */ +static char **parse_plugin(const char *plugin, const char *host, const char *service) { char **argvec; const char *c, *p; @@ -104,12 +117,7 @@ static char *const *parse_plugin(const c } plugin_copy_len = plugin_len + host_len * host_count + service_len * service_count; - plugin_copy = (char *)malloc(plugin_copy_len + 1); - if (!plugin_copy) - { - report(stderr, GT_("fetchmail: malloc failed\n")); - return NULL; - } + plugin_copy = (char *)xmalloc(plugin_copy_len + 1); while (plugin_copy_offset < plugin_copy_len) { if ((plugin[plugin_offset] == '%') && (plugin[plugin_offset + 1] == 'h')) @@ -138,6 +146,7 @@ static char *const *parse_plugin(const c return NULL; } memset(argvec, 0, s); + argvec[0] = plugin_copy; /* make sure we can free() it in every case */ for (p = cp = plugin_copy, i = 0; *cp; cp++) { if ((!isspace((unsigned char)*cp)) && (cp == p ? 1 : isspace((unsigned char)*p))) { argvec[i] = cp; @@ -157,21 +166,29 @@ static int handle_plugin(const char *hos /* get a socket mediated through a given external command */ { int fds[2]; - char *const *argvec; + char **argvec; /* * The author of this code, Felix von Leitner <felix@convergence.de>, says: * he chose socketpair() instead of pipe() because socketpair creates * bidirectional sockets while allegedly some pipe() implementations don't. */ + argvec = parse_plugin(plugin,host,service); + if (!argvec || !*argvec[0]) { + free_plugindata(argvec); + report(stderr, GT_("fetchmail: plugin for host %s service %s is empty, cannot run!\n"), host, service); + return -1; + } if (socketpair(AF_UNIX,SOCK_STREAM,0,fds)) { report(stderr, GT_("fetchmail: socketpair failed\n")); + free_plugindata(argvec); return -1; } switch (fork()) { case -1: /* error */ + free_plugindata(argvec); report(stderr, GT_("fetchmail: fork failed\n")); return -1; case 0: /* child */ @@ -186,15 +203,12 @@ static int handle_plugin(const char *hos (void) close(fds[0]); if (outlevel >= O_VERBOSE) report(stderr, GT_("running %s (host %s service %s)\n"), plugin, host, service); - argvec = parse_plugin(plugin,host,service); - if (argvec == NULL) - _exit(EXIT_FAILURE); execvp(*argvec, argvec); report(stderr, GT_("execvp(%s) failed\n"), *argvec); _exit(EXIT_FAILURE); break; default: /* parent */ - /* NOP */ + free_plugindata(argvec); break; } /* fds[0] is the child's end; close it for proper EOF detection */ Index: fetchmail-6.3.26/xmalloc.h =================================================================== --- fetchmail-6.3.26.orig/xmalloc.h +++ fetchmail-6.3.26/xmalloc.h @@ -12,8 +12,12 @@ #define XMALLOCTYPE char #endif +#if !defined __GNUC__ || __GNUC__ < 2 +# define __attribute__(xyz) /* Ignore. */ +#endif + /** Allocate \a n characters of memory, abort program on failure. */ -XMALLOCTYPE *xmalloc(size_t n); +XMALLOCTYPE *xmalloc(size_t n) __attribute__((malloc)); /** Reallocate \a n characters of memory, abort program on failure. */ XMALLOCTYPE *xrealloc(/*@null@*/ XMALLOCTYPE *, size_t n); Index: fetchmail-6.3.26/README.SSL =================================================================== --- fetchmail-6.3.26.orig/README.SSL +++ fetchmail-6.3.26/README.SSL @@ -8,12 +8,21 @@ Note: there is a separate document "READ side requirements for proper SSL support. It has checklist-style and is not specific to fetchmail. -In case of troubles, mail the README.SSL-SERVER file to your ISP and +In case of troubles, mail the README.SSL-SERVER file to your ISP and have them check their server configuration against it. -Unfortunately, fetchmail confuses SSL/TLS protocol levels with whether -a service needs to use in-band negotiation (STLS/STARTTLS for POP3/IMAP4) or is -totally SSL-wrapped on a separate port. For compatibility reasons, this cannot +Note that fetchmail up to version 6.3.26 used to confuse SSL/TLS protocol +levels with whether a service needs to use in-band negotiation (STLS/STARTTLS +for POP3/IMAP4) or is totally SSL-wrapped ("Implicit TLS") on a separate port. +Fetchmail 6.4 seeks to fix that to some extent without breaking the +command-line and rcfile interfaces too much (see --ssl and --sslproto options, +below and in the manual). + +fetchmail 6.4.0 will auto-negotiate TLSv1 or newer only. + +Unfortunately, fetchmail confuses SSL/TLS protocol levels with whether +a service needs to use in-band negotiation (STLS/STARTTLS for POP3/IMAP4) or is +totally SSL-wrapped on a separate port. For compatibility reasons, this cannot be fixed in a bugfix release. -- Matthias Andree, 2009-05-09 @@ -22,25 +31,44 @@ be fixed in a bugfix release. Quickstart ---------- -For use of SSL or TLS with in-band negotiation on the regular service's port, -i. e. with STLS or STARTTLS, use these command line options +Use an up-to-date release of OpenSSL v1.1.1 or v3.0.0 or newer, so as to get +TLSv1.3 support. Older OpenSSL versions are unsupported upstream, and +fetchmail rejects versions before v1.0.2 and warns about versions before +v1.1.1 + +In all four examples below, the (--)sslcertck has become redundant +since fetchmail v6.4.0, but since fetchmail 6.3 releases will be in circulation +for too long, (--)sslcertck will remain in the examples below for now. + +For use of SSL or TLS on a separate port (recommended), called Implicit TLS, +the whole TCP connection is SSL-encrypted from the very beginning (SSL- or +TLS-wrapped), use these command line options (in the rcfile, +omit all leading "--"): - --sslproto tls1 --sslcertck + --ssl --sslproto tls1.2+ --sslcertck or these options in the rcfile (after the respective "user"... options) - sslproto tls1 sslcertck + ssl sslproto tls1.2+ sslcertck +For use of SSL or TLS with in-band negotiation on the regular service's port, +i. e. with STLS or STARTTLS, use these command line options (omitting --ssl or +ssl): -For use of SSL or TLS on a separate port, if the whole TCP connection is -SSL-encrypted from the very beginning, use these command line options (in the -rcfile, omit all leading "--"): - - --ssl --sslproto ssl3 --sslcertck + --sslproto tls1.2+ --sslcertck or these options in the rcfile (after the respective "user"... options) - ssl sslproto ssl3 sslcertck + sslproto tls1.2+ sslcertck + +With up to date OpenSSL libraries (1.1.1 or newer), and with recent +software on the server, you can alternatively configure tls1.3+. + +For some older services, you may need to use tls1.1+ or tls1+ for compatibility +instead of the tls1.2+ above. In such situations, you should ask the service +provider or server operator to upgrade their TLS implementation such that +TLS v1.3 be supported, and once that happens, update your fetchmail configuration +to tls1.3+ or tls1.2+. Background and use (long version :-))
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor