aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric S. Raymond <esr@thyrsus.com>2001-02-11 21:32:24 +0000
committerEric S. Raymond <esr@thyrsus.com>2001-02-11 21:32:24 +0000
commitb749096ca1c0842db21742e53d8f9766412d2c5d (patch)
tree831465249d25b943252696e13e6133c449a7199d
parent49e1f41ffef6834125db955993f99f1ac17c0bcf (diff)
downloadfetchmail-b749096ca1c0842db21742e53d8f9766412d2c5d.tar.gz
fetchmail-b749096ca1c0842db21742e53d8f9766412d2c5d.tar.bz2
fetchmail-b749096ca1c0842db21742e53d8f9766412d2c5d.zip
Authentication completely refactored.
svn path=/trunk/; revision=3067
-rw-r--r--Makefile.in16
-rw-r--r--NEWS10
-rw-r--r--fetchmail.h2
-rw-r--r--imap.c255
-rw-r--r--pop3.c29
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
diff --git a/NEWS b/NEWS
index bb1ea9d4..b130d869 100644
--- a/NEWS
+++ b/NEWS
@@ -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 *);
diff --git a/imap.c b/imap.c
index f74c3977..199c3c53 100644
--- a/imap.c
+++ b/imap.c
@@ -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"
diff --git a/pop3.c b/pop3.c
index 7f0c9798..43aeace3 100644
--- a/pop3.c
+++ b/pop3.c
@@ -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 */