From 73bf9bf6300063e94b19aa0a8fde8becaf28817e Mon Sep 17 00:00:00 2001
From: "Eric S. Raymond" <esr@thyrsus.com>
Date: Tue, 10 Apr 2001 13:31:56 +0000
Subject: Nalin Dahyabai's changes.

svn path=/trunk/; revision=3290
---
 imap.c    | 95 +++++++++++++++++++++++++++++++++++++++++++++------------------
 options.c | 12 ++++++++
 pop3.c    | 77 +++++++++++++++++++++++++--------------------------
 3 files changed, 118 insertions(+), 66 deletions(-)

diff --git a/imap.c b/imap.c
index 915ed920..3dce0a8d 100644
--- a/imap.c
+++ b/imap.c
@@ -236,8 +236,10 @@ static int imap_getauth(int sock, struct query *ctl, char *greeting)
     capabilities[0] = '\0';
     if ((ok = gen_transact(sock, "CAPABILITY")) == PS_SUCCESS)
     {
-	/* UW-IMAP server 10.173 notifies in all caps */
-	if (strstr(capabilities, "IMAP4REV1"))
+	/* UW-IMAP server 10.173 notifies in all caps, but RFC2060 says we
+	   should expect a response in mixed-case */
+	if (strstr(capabilities, "IMAP4REV1") ||
+	    strstr(capabilities, "IMAP4rev1"))
 	{
 	    imap_version = IMAP4rev1;
 	    if (outlevel >= O_DEBUG)
@@ -295,26 +297,38 @@ static int imap_getauth(int sock, struct query *ctl, char *greeting)
      * Time to authenticate the user.
      * Try the protocol variants that don't require passwords first.
      */
+    ok = PS_AUTHFAIL;
+
 #ifdef GSSAPI
     if ((ctl->server.authenticate == A_ANY 
-	 || ctl->server.authenticate==A_GSSAPI)
+	 || ctl->server.authenticate == A_GSSAPI)
 	&& strstr(capabilities, "AUTH=GSSAPI"))
-	if(!(ok = do_gssauth(sock, "AUTHENTICATE", ctl->server.truename, ctl->remotename)))
-        {
-            return ok;
-        }
+	if(ok = do_gssauth(sock, "AUTHENTICATE", ctl->server.truename, ctl->remotename))
+	{
+	    /* SASL cancellation of authentication */
+	    gen_send(sock, "*");
+	    if(ctl->server.authenticate != A_ANY)
+                return ok;
+	}
+	else
+	    return ok;
 #endif /* GSSAPI */
 
 #ifdef KERBEROS_V4
     if ((ctl->server.authenticate == A_ANY 
-	 || ctl->server.authenticate==A_KERBEROS_V4
-	 || ctl->server.authenticate==A_KERBEROS_V5) 
+	 || ctl->server.authenticate == A_KERBEROS_V4
+	 || ctl->server.authenticate == A_KERBEROS_V5) 
 	&& strstr(capabilities, "AUTH=KERBEROS_V4"))
     {
-	if (!(ok = do_rfc1731(sock, "AUTHENTICATE", ctl->server.truename)))
+	if ((ok = do_rfc1731(sock, "AUTHENTICATE", ctl->server.truename)))
+	{
 	    /* SASL cancellation of authentication */
 	    gen_send(sock, "*");
-	return(ok);
+	    if(ctl->server.authenticate != A_ANY)
+                return ok;
+	}
+	else
+	    return ok;
     }
 #endif /* KERBEROS_V4 */
 
@@ -324,40 +338,59 @@ static int imap_getauth(int sock, struct query *ctl, char *greeting)
      */
 
     if ((ctl->server.authenticate == A_ANY 
-	 || ctl->server.authenticate==A_CRAM_MD5)
+	 || ctl->server.authenticate == A_CRAM_MD5)
 	&& strstr(capabilities, "AUTH=CRAM-MD5"))
     {
 	if ((ok = do_cram_md5 (sock, "AUTHENTICATE", ctl)))
+	{
 	    /* SASL cancellation of authentication */
 	    gen_send(sock, "*");
-	return(ok);
+	    if(ctl->server.authenticate != A_ANY)
+                return ok;
+	}
+	else
+	    return ok;
     }
 
 #if OPIE_ENABLE
     if ((ctl->server.authenticate == A_ANY 
-	 || ctl->server.authenticate==A_OTP)
+	 || ctl->server.authenticate == A_OTP)
 	&& strstr(capabilities, "AUTH=X-OTP"))
-	return(do_otp(sock, "AUTHENTICATE", ctl));
+	if ((ok = do_otp(sock, "AUTHENTICATE", ctl)))
+	{
+	    /* SASL cancellation of authentication */
+	    gen_send(sock, "*");
+	    if(ctl->server.authenticate != A_ANY)
+                return ok;
+	}
+	else
+	    return ok;
 #else
-    if (ctl->server.authenticate==A_NTLM)
+    if (ctl->server.authenticate == A_NTLM)
     {
 	report(stderr, 
 	   _("Required OTP capability not compiled into fetchmail\n"));
-	return(PS_AUTHFAIL);
     }
 #endif /* OPIE_ENABLE */
 
 #ifdef NTLM_ENABLE
     if ((ctl->server.authenticate == A_ANY 
-	 || ctl->server.authenticate==A_NTLM) 
+	 || ctl->server.authenticate == A_NTLM) 
 	&& strstr (capabilities, "AUTH=NTLM"))
-	return(do_imap_ntlm(sock, ctl));
+	if ((ok = do_imap_ntlm(sock, ctl)))
+	{
+	    /* SASL cancellation of authentication */
+	    gen_send(sock, "*");
+	    if(ctl->server.authenticate != A_ANY)
+                return ok;
+	}
+	else
+	    return(ok);
 #else
-    if (ctl->server.authenticate==A_NTLM)
+    if (ctl->server.authenticate == A_NTLM)
     {
 	report(stderr, 
 	   _("Required NTLM capability not compiled into fetchmail\n"));
-	return(PS_AUTHFAIL);
     }
 #endif /* NTLM_ENABLE */
 
@@ -367,26 +400,34 @@ static int imap_getauth(int sock, struct query *ctl, char *greeting)
     {
 	report(stderr, 
 	       _("Required LOGIN capability not supported by server\n"));
-	return PS_AUTHFAIL;
     }
 #endif /* __UNUSED__ */
 
     /* we're stuck with sending the password en clair */
+    if ((ctl->server.authenticate == A_ANY 
+ 	 || ctl->server.authenticate == A_PASSWORD) 
+ 	&& !strstr (capabilities, "LOGINDISABLED"))
     {
 	/* these sizes guarantee no buffer overflow */
 	char	remotename[NAMELEN*2+1], password[PASSWORDLEN*2+1];
 
 	imap_canonicalize(remotename, ctl->remotename, NAMELEN);
 	imap_canonicalize(password, ctl->password, PASSWORDLEN);
-	imap_canonicalize(shroud, ctl->password, PASSWORDLEN);
+
 	ok = gen_transact(sock, "LOGIN \"%s\" \"%s\"", remotename, password);
 	shroud[0] = '\0';
+	if (ok)
+	{
+	    /* SASL cancellation of authentication */
+	    gen_send(sock, "*");
+	    if(ctl->server.authenticate != A_ANY)
+                return ok;
+	}
+	else
+	    return(ok);
     }
 
-    if (ok)
-	return(ok);
-    
-    return(PS_SUCCESS);
+    return(ok);
 }
 
 static int internal_expunge(int sock)
diff --git a/options.c b/options.c
index 97d6b7bb..71003d21 100644
--- a/options.c
+++ b/options.c
@@ -396,6 +396,18 @@ struct query *ctl;	/* option record to be initialized */
 		ctl->server.authenticate = A_KERBEROS_V4;
 	    else if (strcmp(optarg, "ssh") == 0)
 		ctl->server.authenticate = A_SSH;
+	    else if (strcmp(optarg, "otp") == 0)
+		ctl->server.authenticate = A_OTP;
+	    else if (strcmp(optarg, "ntlm") == 0)
+		ctl->server.authenticate = A_NTLM;
+	    else if (strcmp(optarg, "cram") == 0)
+		ctl->server.authenticate = A_CRAM_MD5;
+	    else if (strcmp(optarg, "cram-md5") == 0)
+		ctl->server.authenticate = A_CRAM_MD5;
+	    else if (strcmp(optarg, "gssapi") == 0)
+		ctl->server.authenticate = A_GSSAPI;
+	    else if (strcmp(optarg, "any") == 0)
+		ctl->server.authenticate = A_ANY;
 	    else {
 		fprintf(stderr,_("Invalid authentication `%s' specified.\n"), optarg);
 		errflag++;
diff --git a/pop3.c b/pop3.c
index 718c09c8..0ff1cd45 100644
--- a/pop3.c
+++ b/pop3.c
@@ -131,6 +131,16 @@ 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 SDPS_ENABLE
     /*
@@ -190,16 +200,6 @@ static int pop3_getauth(int sock, struct query *ctl, char *greeting)
 	    && strchr(greeting, '<') 
 	    && gen_transact(sock, "CAPA") == 0)
 	{
-#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 */
 	    char buffer[64];
 
 	    /* determine what authentication methods we have available */
@@ -222,25 +222,6 @@ static int pop3_getauth(int sock, struct query *ctl, char *greeting)
 		if (strstr(buffer, "CRAM-MD5"))
 		    has_cram = TRUE;
 	    }
-
-	    /*
-	     * Here's where we set priorities.  Note that we must do tests
-	     * in *reverse* order of desirability.
-	     */
-	    if (has_cram)
-		ctl->server.authenticate = A_CRAM_MD5;
-#ifdef OPIE_ENABLE
-	    if (has_otp)
-		ctl->server.authenticate = A_OTP;
-#endif /* OPIE_ENABLE */
-#if defined(GSSAPI)
-	    if (has_gssapi)
-		ctl->server.authenticate = A_GSSAPI;
-#endif /* defined(GSSAPI) */
-#if defined(KERBEROS_V4) || defined(KERBEROS_V5)
-	    if (has_kerberos)
-		ctl->server.authenticate = A_KERBEROS_V4;
-#endif /* defined(KERBEROS_V4) || defined(KERBEROS_V5) */
 	}
 
 	/*
@@ -251,27 +232,45 @@ static int pop3_getauth(int sock, struct query *ctl, char *greeting)
 	 * Servers doing KPOP have to go through a dummy login sequence
 	 * rather than doing SASL.
 	 */
-	if (
+	if (has_kerberos &&
 #if INET6_ENABLE
 	    ctl->server.service && (strcmp(ctl->server.service, KPOP_PORT)!=0)
 #else /* INET6_ENABLE */
 	    ctl->server.port != KPOP_PORT
 #endif /* INET6_ENABLE */
 	    && (ctl->server.authenticate == A_KERBEROS_V4
-	     || ctl->server.authenticate == A_KERBEROS_V5))
-	    return(do_rfc1731(sock, "AUTH", ctl->server.truename));
+	     || ctl->server.authenticate == A_KERBEROS_V5
+	     || ctl->server.authenticate == A_ANY))
+	    if(ok = do_rfc1731(sock, "AUTH", ctl->server.truename))
+	        if(ctl->server.authenticate != A_ANY)
+                    break;
 #endif /* defined(KERBEROS_V4) || defined(KERBEROS_V5) */
+
 #if defined(GSSAPI)
-	if (ctl->server.authenticate==A_GSSAPI)
-	    return(do_gssauth(sock, "AUTH", 
-			      ctl->server.truename, ctl->remotename));
+	if (has_gssapi &&
+	    (ctl->server.authenticate == A_GSSAPI ||
+	     ctl->server.authenticate == A_ANY))
+	    if(ok = do_gssauth(sock, "AUTH", 
+			       ctl->server.truename, ctl->remotename))
+	        if(ctl->server.authenticate != A_ANY)
+                    break;
 #endif /* defined(GSSAPI) */
+
 #ifdef OPIE_ENABLE
-	if (ctl->server.authenticate == A_OTP)
-	    do_otp(sock, "AUTH", ctl);
+	if (has_otp &&
+	    (ctl->server.authenticate == A_OTP ||
+	     ctl->server.authenticate == A_ANY))
+	    if(ok = do_otp(sock, "AUTH", ctl))
+	        if(ctl->server.authenticate != A_ANY)
+                    break;
 #endif /* OPIE_ENABLE */
-	if (ctl->server.authenticate == A_CRAM_MD5)
-	    return(do_cram_md5(sock, "AUTH", ctl));
+
+	if (has_cram &&
+	    (ctl->server.authenticate == A_CRAM_MD5 ||
+	     ctl->server.authenticate == A_ANY))
+	    if(ok = do_cram_md5(sock, "AUTH", ctl))
+	        if(ctl->server.authenticate != A_ANY)
+                    break;
 
 	/* ordinary validation, no one-time password or RPA */ 
 	gen_transact(sock, "USER %s", ctl->remotename);
-- 
cgit v1.2.3