diff options
-rw-r--r-- | Makefile.in | 16 | ||||
-rw-r--r-- | NEWS | 10 | ||||
-rw-r--r-- | fetchmail.h | 2 | ||||
-rw-r--r-- | imap.c | 255 | ||||
-rw-r--r-- | pop3.c | 29 |
5 files changed, 47 insertions, 265 deletions
diff --git a/Makefile.in b/Makefile.in index a862035e..1488f96f 100644 --- a/Makefile.in +++ b/Makefile.in @@ -97,8 +97,9 @@ CTAGS = ctags protobjs = rcfile_y.o rcfile_l.o socket.o getpass.o pop2.o pop3.o imap.o \ etrn.o odmr.o fetchmail.o idle.o env.o options.o daemon.o driver.o \ sink.o rfc822.o smtp.o xmalloc.o uid.o mxget.o md5ify.o cram.o \ - kerberos.o rpa.o interface.o netrc.o base64.o error.o unmime.o conf.o \ - checkalias.o smbdes.o smbencrypt.o smbmd4.o smbutil.o ipv6-connect.o + kerberos.o gssapi.o opie.o rpa.o interface.o netrc.o base64.o \ + error.o unmime.o conf.o checkalias.o smbdes.o smbencrypt.o smbmd4.o \ + smbutil.o ipv6-connect.o objs = $(protobjs) $(extras) $(EXTRAOBJ) @@ -109,11 +110,12 @@ srcs = $(srcdir)/socket.c $(srcdir)/getpass.c $(srcdir)/pop2.c \ $(srcdir)/driver.c $(srcdir)/sink.c $(srcdir)/rfc822.c \ $(srcdir)/smtp.c $(srcdir)/xmalloc.c $(srcdir)/uid.c \ $(srcdir)/mxget.c $(srcdir)/md5ify.c $(srcdir)/cram.c \ - $(srcdir)/kerberos.c $(srcdir)/rpa.c $(srcdir)/interface.c \ - $(srcdir)/netrc.c $(srcdir)/base64.c $(srcdir)/error.c \ - $(srcdir)/unmime.c $(srcdir)/conf.c $(srcdir)/checkalias.c \ - $(srcdir)/smbdes.c $(srcdir)/smbencrypt.c $(srcdir)/smbmd4.c \ - $(srcdir)/smbutil.c $(srcdir)/ipv6-connect.c + $(srcdir)/kerberos.c $(srcdir)/gssapi.c $(srcdir)/opie.c \ + $(srcdir)/rpa.c $(srcdir)/interface.c $(srcdir)/netrc.c \ + $(srcdir)/base64.c $(srcdir)/error.c $(srcdir)/unmime.c \ + $(srcdir)/conf.c $(srcdir)/checkalias.c $(srcdir)/smbdes.c \ + $(srcdir)/smbencrypt.c $(srcdir)/smbmd4.c $(srcdir)/smbutil.c \ + $(srcdir)/ipv6-connect.c .SUFFIXES: .SUFFIXES: .o .c .h .y .l .ps .dvi .info .texi @@ -2,7 +2,15 @@ (The `lines' figures total .c, .h, .l, and .y files under version control.) -fetchmail-5.6.3 (Sun Feb 11 00:43:14 EST 2001), 20085 lines: +* CRAM-MD5 authentication of IMAP and POP3 is working. Tested against + IMAP4rev1 2000.287 and v2000.70 POP3 gateway at neo.netnea.com. +* Full support for POP3 AUTH (RFC1734) with KERBEROS_IV, GSSAPI, OTP. +* Noted that Debian bugs #78963, #63064, #81312, #78796, #78363, #78149, + #68627, #67559, #63308, #63088, #71428 are fixed. +* Resolved Debian bug #65505: fetchmail now returns a nonzero exit status + when interrupted before a successful fetch. + +fetchmail-5.6.4 (Sun Feb 11 00:43:14 EST 2001), 20085 lines: * ODMR port fix for AIX. * Dave Zarzycki's fix for former FAQ item F5 (%h and %p not being expanded). diff --git a/fetchmail.h b/fetchmail.h index 51d5bfeb..3f931bf2 100644 --- a/fetchmail.h +++ b/fetchmail.h @@ -521,6 +521,8 @@ int doETRN (struct query *); /* authentication functions */ int do_cram_md5(int sock, char *command, struct query *ctl); int do_rfc1731(int sock, char *command, char *truename); +int do_gssauth(int sock, char *command, char *hostname, char *username); +int do_otp(int sock, char *command, struct query *ctl); /* miscellanea */ struct query *hostalloc(struct query *); @@ -15,25 +15,9 @@ #include "fetchmail.h" #include "socket.h" -#ifdef GSSAPI -#ifdef HAVE_GSSAPI_H -#include <gssapi.h> -#endif -#ifdef HAVE_GSSAPI_GSSAPI_H -#include <gssapi/gssapi.h> -#endif -#ifdef HAVE_GSSAPI_GSSAPI_GENERIC_H -#include <gssapi/gssapi_generic.h> -#endif -#ifndef HAVE_GSS_C_NT_HOSTBASED_SERVICE -#define GSS_C_NT_HOSTBASED_SERVICE gss_nt_service_name -#endif -#endif - #include "i18n.h" #if OPIE_ENABLE -#include <opie.h> #endif /* OPIE_ENABLE */ #ifndef strstr /* glibc-2.1 declares this as a macro */ @@ -133,245 +117,6 @@ int imap_ok(int sock, char *argbuf) } } -#if OPIE_ENABLE -static int do_otp(int sock, struct query *ctl) -{ - int i, rval; - char buffer[128]; - char challenge[OPIE_CHALLENGE_MAX+1]; - char response[OPIE_RESPONSE_MAX+1]; - - gen_send(sock, "AUTHENTICATE X-OTP"); - - if (rval = gen_recv(sock, buffer, sizeof(buffer))) - return rval; - - if ((i = from64tobits(challenge, buffer)) < 0) { - report(stderr, _("Could not decode initial BASE64 challenge\n")); - return PS_AUTHFAIL; - }; - - - to64frombits(buffer, ctl->remotename, strlen(ctl->remotename)); - - if (outlevel >= O_MONITOR) - report(stdout, "IMAP> %s\n", buffer); - - /* best not to count on the challenge code handling multiple writes */ - strcat(buffer, "\r\n"); - SockWrite(sock, buffer, strlen(buffer)); - - if (rval = gen_recv(sock, buffer, sizeof(buffer))) - return rval; - - if ((i = from64tobits(challenge, buffer)) < 0) { - report(stderr, _("Could not decode OTP challenge\n")); - return PS_AUTHFAIL; - }; - - rval = opiegenerator(challenge, !strcmp(ctl->password, "opie") ? "" : ctl->password, response); - if ((rval == -2) && !run.poll_interval) { - char secret[OPIE_SECRET_MAX+1]; - fprintf(stderr, _("Secret pass phrase: ")); - if (opiereadpass(secret, sizeof(secret), 0)) - rval = opiegenerator(challenge, secret, response); - memset(secret, 0, sizeof(secret)); - }; - - if (rval) - return(PS_AUTHFAIL); - - to64frombits(buffer, response, strlen(response)); - - if (outlevel >= O_MONITOR) - report(stdout, "IMAP> %s\n", buffer); - strcat(buffer, "\r\n"); - SockWrite(sock, buffer, strlen(buffer)); - - if (rval = gen_recv(sock, buffer, sizeof(buffer))) - return rval; - - if (strstr(buffer, "OK")) - return PS_SUCCESS; - else - return PS_AUTHFAIL; -}; -#endif /* OPIE_ENABLE */ - -#ifdef GSSAPI -#define GSSAUTH_P_NONE 1 -#define GSSAUTH_P_INTEGRITY 2 -#define GSSAUTH_P_PRIVACY 4 - -static int do_gssauth(int sock, char *hostname, char *username) -{ - gss_buffer_desc request_buf, send_token; - gss_buffer_t sec_token; - gss_name_t target_name; - gss_ctx_id_t context; - gss_OID mech_name; - gss_qop_t quality; - int cflags; - OM_uint32 maj_stat, min_stat; - char buf1[8192], buf2[8192], server_conf_flags; - unsigned long buf_size; - int result; - - /* first things first: get an imap ticket for host */ - sprintf(buf1, "imap@%s", hostname); - request_buf.value = buf1; - request_buf.length = strlen(buf1) + 1; - maj_stat = gss_import_name(&min_stat, &request_buf, GSS_C_NT_HOSTBASED_SERVICE, - &target_name); - if (maj_stat != GSS_S_COMPLETE) { - report(stderr, _("Couldn't get service name for [%s]\n"), buf1); - return PS_AUTHFAIL; - } - else if (outlevel >= O_DEBUG) { - maj_stat = gss_display_name(&min_stat, target_name, &request_buf, - &mech_name); - report(stderr, _("Using service name [%s]\n"),request_buf.value); - maj_stat = gss_release_buffer(&min_stat, &request_buf); - } - - gen_send(sock, "AUTHENTICATE GSSAPI"); - - /* upon receipt of the GSSAPI authentication request, server returns - * null data ready response. */ - if (result = gen_recv(sock, buf1, sizeof buf1)) { - return result; - } - - /* now start the security context initialisation loop... */ - sec_token = GSS_C_NO_BUFFER; - context = GSS_C_NO_CONTEXT; - if (outlevel >= O_VERBOSE) - report(stdout, _("Sending credentials\n")); - do { - send_token.length = 0; - send_token.value = NULL; - maj_stat = gss_init_sec_context(&min_stat, - GSS_C_NO_CREDENTIAL, - &context, - target_name, - GSS_C_NO_OID, - GSS_C_MUTUAL_FLAG | GSS_C_SEQUENCE_FLAG, - 0, - GSS_C_NO_CHANNEL_BINDINGS, - sec_token, - NULL, - &send_token, - NULL, - NULL); - if (maj_stat!=GSS_S_COMPLETE && maj_stat!=GSS_S_CONTINUE_NEEDED) { - report(stderr, _("Error exchanging credentials\n")); - gss_release_name(&min_stat, &target_name); - /* wake up server and await NO response */ - SockWrite(sock, "\r\n", 2); - if (result = gen_recv(sock, buf1, sizeof buf1)) - return result; - return PS_AUTHFAIL; - } - to64frombits(buf1, send_token.value, send_token.length); - gss_release_buffer(&min_stat, &send_token); - strcat(buf1, "\r\n"); - SockWrite(sock, buf1, strlen(buf1)); - if (outlevel >= O_MONITOR) - report(stdout, "IMAP> %s\n", buf1); - if (maj_stat == GSS_S_CONTINUE_NEEDED) { - if (result = gen_recv(sock, buf1, sizeof buf1)) { - gss_release_name(&min_stat, &target_name); - return result; - } - request_buf.length = from64tobits(buf2, buf1 + 2); - request_buf.value = buf2; - sec_token = &request_buf; - } - } while (maj_stat == GSS_S_CONTINUE_NEEDED); - gss_release_name(&min_stat, &target_name); - - /* get security flags and buffer size */ - if (result = gen_recv(sock, buf1, sizeof buf1)) { - return result; - } - request_buf.length = from64tobits(buf2, buf1 + 2); - request_buf.value = buf2; - - maj_stat = gss_unwrap(&min_stat, context, &request_buf, &send_token, - &cflags, &quality); - if (maj_stat != GSS_S_COMPLETE) { - report(stderr, _("Couldn't unwrap security level data\n")); - gss_release_buffer(&min_stat, &send_token); - return PS_AUTHFAIL; - } - if (outlevel >= O_DEBUG) - report(stdout, _("Credential exchange complete\n")); - /* first octet is security levels supported. We want none, for now */ - server_conf_flags = ((char *)send_token.value)[0]; - if ( !(((char *)send_token.value)[0] & GSSAUTH_P_NONE) ) { - report(stderr, _("Server requires integrity and/or privacy\n")); - gss_release_buffer(&min_stat, &send_token); - return PS_AUTHFAIL; - } - ((char *)send_token.value)[0] = 0; - buf_size = ntohl(*((long *)send_token.value)); - /* we don't care about buffer size if we don't wrap data */ - gss_release_buffer(&min_stat, &send_token); - if (outlevel >= O_DEBUG) { - report(stdout, _("Unwrapped security level flags: %s%s%s\n"), - server_conf_flags & GSSAUTH_P_NONE ? "N" : "-", - server_conf_flags & GSSAUTH_P_INTEGRITY ? "I" : "-", - server_conf_flags & GSSAUTH_P_PRIVACY ? "C" : "-"); - report(stdout, _("Maximum GSS token size is %ld\n"),buf_size); - } - - /* now respond in kind (hack!!!) */ - buf_size = htonl(buf_size); /* do as they do... only matters if we do enc */ - memcpy(buf1, &buf_size, 4); - buf1[0] = GSSAUTH_P_NONE; - strcpy(buf1+4, username); /* server decides if princ is user */ - request_buf.length = 4 + strlen(username) + 1; - request_buf.value = buf1; - maj_stat = gss_wrap(&min_stat, context, 0, GSS_C_QOP_DEFAULT, &request_buf, - &cflags, &send_token); - if (maj_stat != GSS_S_COMPLETE) { - report(stderr, _("Error creating security level request\n")); - return PS_AUTHFAIL; - } - to64frombits(buf1, send_token.value, send_token.length); - if (outlevel >= O_DEBUG) { - report(stdout, _("Requesting authorization as %s\n"), username); - report(stdout, "IMAP> %s\n",buf1); - } - strcat(buf1, "\r\n"); - SockWrite(sock, buf1, strlen(buf1)); - - /* we should be done. Get status and finish up */ - do { - if (result = gen_recv(sock, buf1, sizeof buf1)) - return result; - } while(strncmp(buf1, tag, strlen(tag)) != 0); - if (strstr(buf1, "OK")) { - /* flush security context */ - if (outlevel >= O_DEBUG) - report(stdout, _("Releasing GSS credentials\n")); - maj_stat = gss_delete_sec_context(&min_stat, &context, &send_token); - if (maj_stat != GSS_S_COMPLETE) { - report(stderr, _("Error releasing credentials\n")); - return PS_AUTHFAIL; - } - /* send_token may contain a notification to the server to flush - * credentials. RFC 1731 doesn't specify what to do, and since this - * support is only for authentication, we'll assume the server - * knows enough to flush its own credentials */ - gss_release_buffer(&min_stat, &send_token); - return PS_SUCCESS; - } - - return PS_AUTHFAIL; -} -#endif /* GSSAPI */ - #if NTLM_ENABLE #include "ntlm.h" @@ -204,11 +204,20 @@ int pop3_getauth(int sock, struct query *ctl, char *greeting) * don't implement this, so don't do it at all unless the * server advertises APOP with <> in the greeting line. This * certainly catches IMAP-2000's POP3 gateway. + * + * These authentication methods are blessed by RFC1734, + * POP3 AUTHentication command. */ if (strchr(greeting, '<') && gen_transact(sock, "AUTH") == 0) { char buffer[10]; flag has_cram = FALSE; +#if defined(KERBEROS_IV) + flag has_kerberos = FALSE; +#endif /* defined(KERBEROS_IV) */ +#ifdef OPIE_ENABLE + flag has_opie = FALSE; +#endif /* OPIE_ENABLE */ while ((ok = gen_recv(sock, buffer, sizeof(buffer))) == 0) { @@ -216,9 +225,25 @@ int pop3_getauth(int sock, struct query *ctl, char *greeting) break; if (strncasecmp(buffer, "CRAM-MD5", 8) == 0) has_cram = TRUE; +#if defined(KERBEROS_IV) + if (strncasecmp(buffer, "KERBEROS_V4", 8) == 0) + has_kerberos = TRUE; +#endif /* defined(KERBEROS_IV) */ +#ifdef OPIE_ENABLE + if (strncasecmp(buffer, "SKEY", 8) == 0) + has_opie = TRUE; +#endif /* OPIE_ENABLE */ } - if (has_cram && !do_cram_md5(sock, "AUTH", ctl)) - return(PS_SUCCESS); +#if defined(KERBEROS_IV) + if (has_kerberos) + return(do_rfc1731(sock, "AUTH", ctl->server.truename)); +#endif /* defined(KERBEROS_IV) */ +#ifdef OPIE_ENABLE + if (has_opie) + do_otp(sock, ctl) +#endif /* OPIE_ENABLE */ + if (has_cram) + return(do_cram_md5(sock, "AUTH", ctl)); } /* ordinary validation, no one-time password or RPA */ |