[Pkg-wmaker-commits] [wmbiff] 08/14: rewrite of authentication code to a) allow users to specify authentication type, b) fall back to other authentication methods when hash-based authentication fails (because not everybody uses the cleartext password file) c) fix debug messages

Doug Torrance dtorrance-guest at moszumanska.debian.org
Thu Aug 20 03:00:07 UTC 2015


This is an automated email from the git hooks/post-receive script.

dtorrance-guest pushed a commit to tag wmbiff_0_3_4
in repository wmbiff.

commit 05bd5bfc33bb787d78409f5477506b9c8ab8fd2b
Author: bluehal <bluehal>
Date:   Fri Nov 16 01:13:36 2001 +0000

    rewrite of authentication code to a) allow users to specify authentication type, b) fall back to other authentication methods when hash-based authentication fails (because not everybody uses the cleartext password file) c) fix debug messages
---
 wmbiff/Client.h      |   8 +-
 wmbiff/Imap4Client.c | 283 +++++++++++++++++++++-------------------
 wmbiff/Makefile      |  10 +-
 wmbiff/Pop3Client.c  | 357 +++++++++++++++++++++++----------------------------
 wmbiff/charutil.c    |  70 +++++++++-
 5 files changed, 395 insertions(+), 333 deletions(-)

diff --git a/wmbiff/Client.h b/wmbiff/Client.h
index 2cb45f3..f8c9d12 100644
--- a/wmbiff/Client.h
+++ b/wmbiff/Client.h
@@ -1,4 +1,4 @@
-/* $Id: Client.h,v 1.5 2001/10/04 09:50:59 jordi Exp $ */
+/* $Id: Client.h,v 1.6 2001/11/16 01:13:36 bluehal Exp $ */
 /* Author : Scott Holden ( scotth at thezone.net )
    Modified : Yong-iL Joh ( tolkien at mizi.com )
    Modified : Jorge Garc�a ( Jorge.Garcia at uv.es )
@@ -54,6 +54,7 @@ typedef struct _mbox_t {
 			char serverName[256];
 			int serverPort;
 			int localPort;
+			char authList[100];
 		} pop;
 		struct {
 			char password[32];
@@ -61,6 +62,7 @@ typedef struct _mbox_t {
 			char serverName[256];
 			int serverPort;
 			int localPort;
+			char authList[100];
 			unsigned int dossl:1;
 		} imap;
 	} u;
@@ -76,14 +78,12 @@ typedef struct _mbox_t {
 #define BUF_SIZE 1024
 
 int sock_connect(const char *hostname, int port);
-int pop3Create(Pop3 pc, char *str);
+int pop3Create(Pop3 pc, const char *str);
 int imap4Create(Pop3 pc, const char *str);
 int licqCreate(Pop3 pc, char *str);
 int mboxCreate(Pop3 pc, char *str);
 int maildirCreate(Pop3 pc, char *str);
 FILE *openMailbox(Pop3 pc);
-int parse_old_pop3_path(Pop3 pc, char *str);
-int parse_new_pop3_path(Pop3 pc, char *str);
 
 #endif
 /* vim:set ts=4: */
diff --git a/wmbiff/Imap4Client.c b/wmbiff/Imap4Client.c
index c112421..ccd5ba3 100644
--- a/wmbiff/Imap4Client.c
+++ b/wmbiff/Imap4Client.c
@@ -25,6 +25,18 @@
 #include <dmalloc.h>
 #endif
 
+/* emulates what 'variadic macros' are great for */
+#ifdef DEBUG_IMAP4
+#define DM printf
+#else
+#define DM nullie
+/*@unused@*/
+static void nullie( /*@unused@ */ const char *format, ...)
+{
+	return;
+}
+#endif
+
 #define	PCU	(pc->u).imap
 
 #ifdef __LCLINT__
@@ -42,10 +54,25 @@ static struct fdmap_struct {
 } fdmap[FDMAP_SIZE];
 
 
-int imap4Create(Pop3 pc, const char *str);
-#ifdef WITH_GCRYPT
-static int authenticate_md5(Pop3 pc, struct connection_state *scs);
-#endif
+/* authentication callbacks */
+static int authenticate_md5(Pop3 pc, struct connection_state *scs,
+							const char *capabilities);
+static int authenticate_plaintext(Pop3 pc, struct connection_state *scs,
+								  const char *capabilities);
+
+/* the auth_methods array maps authentication identifiers
+   to the callback that will attempt to authenticate */
+static struct imap_authentication_method {
+	const char *name;
+	/* callback returns 1 if successful, 0 if failed */
+	int (*auth_callback) (Pop3 pc, struct connection_state * scs,
+						  const char *capabilities);
+} auth_methods[] = {
+	{
+	"cram-md5", authenticate_md5}, {
+	"plaintext", authenticate_plaintext}, {
+	NULL, NULL}
+};
 
 
 /* recover a socket from the connection cache */
@@ -80,6 +107,7 @@ static void bind_state_to_pcu(Pop3 pc,
 			 PCU.password, PCU.serverName, PCU.serverPort);
 	for (i = 0; i < FDMAP_SIZE && fdmap[i].cs != NULL; i++);
 	if (i == FDMAP_SIZE) {
+		/* should never happen */
 		printf
 			("wmbiff: Tried to open too many IMAP connections. Sorry!\n");
 		exit(EXIT_FAILURE);
@@ -91,13 +119,13 @@ static void bind_state_to_pcu(Pop3 pc,
 /* remove from the connection cache */
 static
 /*@owned@*//*@null@ */
-struct connection_state *unbind(struct connection_state *scs)
+struct connection_state *unbind( /*@returned@ */ struct connection_state
+								*scs)
 {
 	int i;
 	struct connection_state *retval = NULL;
-	if (scs == NULL) {
-		abort();
-	}
+	assert(scs != NULL);
+
 	for (i = 0; i < FDMAP_SIZE && fdmap[i].cs != scs; i++);
 	if (i < FDMAP_SIZE) {
 		free((char *) fdmap[i].user_password_server_port);
@@ -108,12 +136,15 @@ struct connection_state *unbind(struct connection_state *scs)
 }
 
 /* creates a connection to the server, if a matching one doesn't exist. */
+/* *always* returns null, just declared this wasy to match other protocols. */
 /*@null@*/
 FILE *imap_open(Pop3 pc)
 {
 	struct connection_state *scs;
+	struct imap_authentication_method *a;
 	char *connection_name;
 	int sd;
+	char capabilities[BUF_SIZE];
 	char buf[BUF_SIZE];
 
 
@@ -122,14 +153,29 @@ FILE *imap_open(Pop3 pc)
 		return NULL;
 	}
 
+	/* got this far; we're going to create a connection_state 
+	   structure, although it might be a blacklist entry */
+	asprintf(&connection_name, "%s:%d", PCU.serverName, PCU.serverPort);
+
 	/* no cached connection */
 	sd = sock_connect((const char *) PCU.serverName, PCU.serverPort);
 	if (sd == -1) {
-		fprintf(stderr, "Couldn't connect to %s:%d\n",
-				PCU.serverName, PCU.serverPort);
+		fprintf(stderr, "Couldn't connect to %s:%d: %s\n",
+				PCU.serverName, PCU.serverPort, strerror(errno));
+		if (errno == ETIMEDOUT) {
+			/* only give up if it was a time-consuming error */
+			/* try again later if it was just a connection refused */
+			fprintf(stderr,
+					"Will not retry because this attempt to connect timed out.\n");
+			fprintf(stderr,
+					"This is done so that other mailboxes can be updated in a timely manner.\n");
+			fprintf(stderr,
+					"To try again to connect to %s:%d, restart wmbiff.\n",
+					PCU.serverName, PCU.serverPort);
+			bind_state_to_pcu(pc, initialize_blacklist(connection_name));
+		}
 		return NULL;
 	}
-	asprintf(&connection_name, "%s:%d", PCU.serverName, PCU.serverPort);
 
 	/* build the connection using STARTTLS */
 	if (PCU.dossl && (PCU.serverPort == 143)) {
@@ -138,18 +184,16 @@ FILE *imap_open(Pop3 pc)
 
 		/* can we? */
 		tlscomm_printf(scs, "a000 CAPABILITY\r\n");
-		if (!tlscomm_expect(scs, "* CAPABILITY", buf, BUF_SIZE))
+		if (!tlscomm_expect(scs, "* CAPABILITY", capabilities, BUF_SIZE))
 			goto communication_failure;
 
-		if (!strstr(buf, "STARTTLS")) {
+		if (!strstr(capabilities, "STARTTLS")) {
 			printf("server doesn't support ssl imap on port 143.");
 			goto communication_failure;
 		}
 
 		/* we sure can! */
-#ifdef DEBUG_IMAP
-		printf("Negotiating TLS within IMAP");
-#endif
+		DM("Negotiating TLS within IMAP");
 		tlscomm_printf(scs, "a001 STARTTLS\r\n");
 
 		if (!tlscomm_expect(scs, "a001 ", buf, BUF_SIZE))
@@ -163,7 +207,7 @@ FILE *imap_open(Pop3 pc)
 		/* we don't need the unencrypted state anymore */
 		/* note that communication_failure will close the 
 		   socket and free via tls_close() */
-		free(scs);				// fall through will scs = initialize_gnutls(sd);
+		free(scs);				/* fall through will scs = initialize_gnutls(sd); */
 	}
 
 	/* either we've negotiated ssl from starttls, or
@@ -184,48 +228,29 @@ FILE *imap_open(Pop3 pc)
 	   server will allow plain password login within an 
 	   encrypted session. */
 	tlscomm_printf(scs, "a000 CAPABILITY\r\n");
-	if (!tlscomm_expect(scs, "* CAPABILITY", buf, BUF_SIZE)) {
+	if (!tlscomm_expect(scs, "* CAPABILITY", capabilities, BUF_SIZE)) {
 		printf("unable to query capability string");
 		goto communication_failure;
 	}
-#ifdef WITH_GCRYPT
-	/* is cram-md5 permitted? */
-	if (strstr(buf, "AUTH=CRAM-MD5")) {
-		if (authenticate_md5(pc, scs) == 0) {
-			return NULL;
-		}
-		goto success;
-	}
-#endif
 
-	/* is login prohibited? */
-	if (strstr(buf, "LOGINDISABLED")) {
-		printf
-			("I don't know how to login to this server (LOGINDISABLED).\n");
-		goto communication_failure;
-	}
-
-	/* login */
-	tlscomm_printf(scs, "a001 LOGIN %s %s\r\n", PCU.userName,
-				   PCU.password);
-	if (!tlscomm_expect(scs, "a001 ", buf, BUF_SIZE)) {
-		printf("unable to login");
-		goto communication_failure;
-	}
-
-	if (buf[5] != 'O') {
-		tlscomm_printf(scs, "a002 LOGOUT\r\n");
-		printf("login failed\n");
-		goto communication_failure;
+	/* try each authentication method in turn. */
+	for (a = auth_methods; a->name != NULL; a++) {
+		/* was it specified or did the user leave it up to us? */
+		if (PCU.authList[0] == '\0' || strstr(PCU.authList, a->name))
+			/* try the authentication method */
+			if ((a->auth_callback(pc, scs, capabilities)) != 0) {
+				/* store this well setup connection in the cache */
+				bind_state_to_pcu(pc, scs);
+				return NULL;
+			}
 	}
 
-  success:
-	/* store this well setup connection in the cache */
-	bind_state_to_pcu(pc, scs);
-	/* I don't do file handles. */
-	return NULL;
-
+	/* if authentication worked, we won't get here */
+	fprintf(stderr,
+			"All Imap4 authentication methods failed for '%s@%s:%d'\n",
+			PCU.userName, PCU.serverName, PCU.serverPort);
   communication_failure:
+	tlscomm_printf(scs, "a002 LOGOUT\r\n");
 	tlscomm_close(scs);
 	return NULL;
 
@@ -242,46 +267,35 @@ int imap_checkmail(Pop3 pc)
 		(void) pc->open(pc);
 		scs = state_for_pcu(pc);
 	}
+	if (scs == NULL) {
+		return -1;
+	}
+
+	if (tlscomm_is_blacklisted(scs)) {
+		/* unresponsive server, don't bother. */
+		return -1;
+	}
 
 	/* if we've got it by now, try the status query */
-	if (scs) {
-		tlscomm_printf(scs, "a003 STATUS %s (MESSAGES UNSEEN)\r\n",
-					   pc->path);
-		if (tlscomm_expect(scs, "* STATUS", buf, 127)) {
-			/* a valid response? */
-			(void) sscanf(buf, "* STATUS %*s (MESSAGES %d UNSEEN %d)",
-						  &(pc->TotalMsgs), &(pc->UnreadMsgs));
-		} else {
-			/* something went wrong. bail. */
-			tlscomm_close(unbind(scs));
-			return -1;
-		}
+	tlscomm_printf(scs, "a003 STATUS %s (MESSAGES UNSEEN)\r\n", pc->path);
+	if (tlscomm_expect(scs, "* STATUS", buf, 127)) {
+		/* a valid response? */
+		(void) sscanf(buf, "* STATUS %*s (MESSAGES %d UNSEEN %d)",
+					  &(pc->TotalMsgs), &(pc->UnreadMsgs));
 	} else {
-		/* login must've failed */
+		/* something went wrong. bail. */
+		tlscomm_close(unbind(scs));
 		return -1;
 	}
 	return 0;
 }
 
-/* helper function for the configuration line parser */
-static void assign(char *destination,
-				   int startidx, int endidx, const char *source)
-{
-	if (startidx > -1) {
-		strncpy(destination, source + startidx, endidx - startidx);
-		destination[endidx - startidx] = '\0';
-	}
-}
-
 /* parse the config line to setup the Pop3 structure */
 int imap4Create(Pop3 pc, const char *const str)
 {
-	int matchedchars;
-	struct re_pattern_buffer rpbuf;
 	struct re_registers regs;
-	const char *errstr;
 	const char *regex =
-		".*imaps?:([^:]+):([^@]+)@([^/:]+)(/[^:]+)?(:[0-9]+)?";
+		".*imaps?:([^:]+):([^@]+)@([^/: ]+)(/[^: ]+)?(:[0-9]+)? *";
 
 	/* IMAP4 format: imap:user:password at server/mailbox[:port] */
 	/* If 'str' line is badly formatted, wmbiff won't display the mailbox. */
@@ -306,41 +320,18 @@ int imap4Create(Pop3 pc, const char *const str)
 	} else
 		PCU.dossl = 0;
 
-	/* compile the regex pattern */
-	memset(&rpbuf, 0, sizeof(struct re_pattern_buffer));
-	re_syntax_options = RE_SYNTAX_EGREP;
-	errstr = re_compile_pattern(regex, strlen(regex), &rpbuf);
-	if (errstr != NULL) {
+	if (compile_and_match_regex(regex, str, &regs) <= 0) {
 		pc->label[0] = '\0';
-		fprintf(stderr, "error in compiling regular expression: %s\n",
-				errstr);
+		fprintf(stderr, "Couldn't parse line %s\n", str);
 		return -1;
 	}
 
-	/* match the regex */
-	regs.num_regs = REGS_UNALLOCATED;
-	matchedchars = re_match(&rpbuf, str, strlen(str), 0, &regs);
-	if (matchedchars <= 0) {
-		pc->label[0] = '\0';
-		fprintf(stderr, "Couldn't parse line %s (%d)\n", str,
-				matchedchars);
-		return -1;
-	}
-#ifdef undef
-	printf("--\n");
-	for (i = 1; i < 6; i++) {
-		printf("%d %d, (%.*s)\n", regs.start[i], regs.end[i],
-			   (regs.end[i] - regs.start[i]),
-			   (regs.start[i] >= 0) ? &str[regs.start[i]] : "");
-	}
-#endif
-
 	/* copy matches where they belong */
-	assign(PCU.userName, regs.start[1], regs.end[1], str);
-	assign(PCU.password, regs.start[2], regs.end[2], str);
-	assign(PCU.serverName, regs.start[3], regs.end[3], str);
+	copy_substring(PCU.userName, regs.start[1], regs.end[1], str);
+	copy_substring(PCU.password, regs.start[2], regs.end[2], str);
+	copy_substring(PCU.serverName, regs.start[3], regs.end[3], str);
 	if (regs.start[4] != -1)
-		assign(pc->path, regs.start[4] + 1, regs.end[4], str);
+		copy_substring(pc->path, regs.start[4] + 1, regs.end[4], str);
 	else
 		strcpy(pc->path, "INBOX");
 	if (regs.start[5] != -1)
@@ -348,13 +339,14 @@ int imap4Create(Pop3 pc, const char *const str)
 	else
 		PCU.serverPort = (PCU.dossl) ? 993 : 143;
 
-#ifdef DEBUG_IMAP4
-	printf("imap4: userName= '%s'\n", PCU.userName);
-	printf("imap4: password= '%s'\n", PCU.password);
-	printf("imap4: serverName= '%s'\n", PCU.serverName);
-	printf("imap4: serverPath= '%s'\n", pc->path);
-	printf("imap4: serverPort= '%d'\n", PCU.serverPort);
-#endif
+	grab_authList(str + regs.end[0], PCU.authList);
+
+	DM("imap4: userName= '%s'\n", PCU.userName);
+	DM("imap4: password= '%s'\n", PCU.password);
+	DM("imap4: serverName= '%s'\n", PCU.serverName);
+	DM("imap4: serverPath= '%s'\n", pc->path);
+	DM("imap4: serverPort= '%d'\n", PCU.serverPort);
+	DM("imap4: authList= '%s'\n", PCU.authList);
 
 	pc->open = imap_open;
 	pc->checkMail = imap_checkmail;
@@ -365,22 +357,58 @@ int imap4Create(Pop3 pc, const char *const str)
 	return 0;
 }
 
-#ifdef WITH_GCRYPT
-static int authenticate_md5(Pop3 pc, struct connection_state *scs)
+static int authenticate_plaintext(Pop3 pc,
+								  struct connection_state *scs,
+								  const char *capabilities)
+{
+	char buf[BUF_SIZE];
+	/* is login prohibited? */
+	/* "An IMAP client which complies with [rfc2525, section 3.2] 
+	 *  MUST NOT issue the LOGIN command if this capability is present.
+	 */
+	if (strstr(capabilities, "LOGINDISABLED")) {
+		printf("Plaintext auth prohibited by server: (LOGINDISABLED).\n");
+		goto plaintext_failed;
+	}
+
+	/* login */
+	tlscomm_printf(scs, "a001 LOGIN %s %s\r\n", PCU.userName,
+				   PCU.password);
+	if (!tlscomm_expect(scs, "a001 ", buf, BUF_SIZE)) {
+		printf("unable to login");
+		goto plaintext_failed;
+	}
+
+	if (buf[5] != 'O') {
+		printf("login failed\n");
+		goto plaintext_failed;
+	}
+	return (1);
+  plaintext_failed:
+	return (0);
+}
+
+static int authenticate_md5(Pop3 pc,
+							struct connection_state *scs,
+							const char *capabilities)
 {
+#ifdef WITH_GCRYPT
 	char buf[BUF_SIZE];
 	char buf2[BUF_SIZE];
 	unsigned char *md5;
 	GCRY_MD_HD gmh;
 
+	if (!strstr(capabilities, "AUTH=CRAM-MD5")) {
+		/* server doesn't support cram-md5. */
+		return 0;
+	}
+
 	tlscomm_printf(scs, "a007 AUTHENTICATE CRAM-MD5\r\n");
 	if (!tlscomm_expect(scs, "+ ", buf, BUF_SIZE))
 		goto expect_failure;
 
 	Decode_Base64(buf + 2, buf2);
-#ifdef DEBUG_IMAP4
-	fprintf(stderr, "IMAP4 CRAM-MD5 challenge: %s\n", buf2);
-#endif
+	DM("IMAP4 CRAM-MD5 challenge: %s\n", buf2);
 
 	strcpy(buf, PCU.userName);
 	strcat(buf, " ");
@@ -393,9 +421,7 @@ static int authenticate_md5(Pop3 pc, struct connection_state *scs)
 	gcry_md_close(gmh);
 
 	strcat(buf, buf2);
-#ifdef DEBUG_IMAP4
-	fprintf(stderr, "IMAP4 CRAM-MD5 response: %s\n", buf);
-#endif
+	DM("IMAP4 CRAM-MD5 response: %s\n", buf);
 	Encode_Base64(buf, buf2);
 
 	tlscomm_printf(scs, "%s\r\n", buf2);
@@ -409,14 +435,13 @@ static int authenticate_md5(Pop3 pc, struct connection_state *scs)
 			"IMAP4 CRAM-MD5 AUTH failed for user '%s@%s:%d'\n",
 			PCU.userName, PCU.serverName, PCU.serverPort);
 	fprintf(stderr, "It said %s", buf);
-	tlscomm_printf(scs, "a002 LOGOUT\r\n");
-	tlscomm_close(scs);
 	return 0;
 
   expect_failure:
-	fprintf(stderr, "tlscomm_expect failed: %s", buf);
-	tlscomm_printf(scs, "a002 LOGOUT\r\n");
-	tlscomm_close(scs);
+	fprintf(stderr, "tlscomm_expect failed during cram-md5 auth: %s", buf);
+	return 0;
+#else
+	/* not compiled with gcrypt. */
 	return 0;
-}
 #endif
+}
diff --git a/wmbiff/Makefile b/wmbiff/Makefile
index 257b734..f80101d 100644
--- a/wmbiff/Makefile
+++ b/wmbiff/Makefile
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.13 2001/10/28 23:32:55 jordi Exp $
+# $Id: Makefile,v 1.14 2001/11/16 01:13:36 bluehal Exp $
 
 WMBIFF_VERSION = "0.3.3"
 
@@ -11,8 +11,9 @@ CONF=/etc
 CC     = gcc
 LIBDIR = -L/usr/X11R6/lib
 LIBS   = -lXpm -lXext -lX11 
-CFLAGS = -O2 -Wall -Wpointer-arith
-#CFLAGS = -g -Wall -pedantic 
+CFLAGS = -O2 -Wall -Wpointer-arith 
+#CFLAGS = -g -Wall -Wpointer-arith -Wwrite-strings -pedantic
+#-W -Wmissing-noreturn -Wtraditional
 
 EXTRAFLAGS = -DWMBIFF_VERSION='$(WMBIFF_VERSION)' 
 
@@ -22,7 +23,7 @@ LIBS   += -lgnutls -lgcrypt
 
 #EXTRAFLAGS += -DDEBUG_POP3 -DDEBUG_IMAP4 -DDEBUG_LICQ \
 #	-DDEBUG_MBOX -DDEBUG_MAILDIR -DDEBUG -DDEBUG_MAIL_COUNT \
-#       -DDEBUG_COMM
+#	-DDEBUG_COMM
 
 #CFLAGS += -DUSE_DMALLOC
 #LIBS   += -ldmalloc
@@ -47,7 +48,6 @@ Imap4Client.o: Imap4Client.c Client.h Makefile
 .c.o:
 	$(CC) $(CFLAGS) $(EXTRAFLAGS) -c $< -o $*.o
 
-
 wmbiff-master.xpm:
 	ln -s wmbiff-master-led.xpm wmbiff-master.xpm
 
diff --git a/wmbiff/Pop3Client.c b/wmbiff/Pop3Client.c
index 1195141..fecd063 100644
--- a/wmbiff/Pop3Client.c
+++ b/wmbiff/Pop3Client.c
@@ -1,25 +1,53 @@
-/* $Id: Pop3Client.c,v 1.3 2001/10/04 09:50:59 jordi Exp $ */
+/* $Id: Pop3Client.c,v 1.4 2001/11/16 01:13:36 bluehal Exp $ */
 /* Author : Scott Holden ( scotth at thezone.net )
    Modified : Yong-iL Joh ( tolkien at mizi.com )
    Modified : Jorge Garc�a ( Jorge.Garcia at uv.es )
    Modified ; Mark Hurley ( debian4tux at telocity.com )
+   Modified : Neil Spring ( nspring at cs.washington.edu )
  * 
  * Pop3 Email checker.
  *
- * Last Updated : Apr 29, 23:04:57 EDT 2001     
+ * Last Updated : Tue Nov 13 13:45:23 PST 2001
  *
  */
 
 #include "Client.h"
 #include "charutil.h"
+#include <regex.h>
+
 #ifdef USE_DMALLOC
 #include <dmalloc.h>
 #endif
 
 #define	PCU	(pc->u).pop
 
-FILE *authenticate_md5(Pop3 pc, FILE * fp, char *buf);
-FILE *authenticate_apop(Pop3 pc, FILE * fp, char *apop_str);
+/* emulates what 'variadic macros' are great for */
+#ifdef DEBUG_POP3
+#define DM printf
+#else
+#define DM nullie
+static void nullie(const char *format, ...)
+{
+	return;
+}
+#endif
+
+static FILE *authenticate_md5(Pop3 pc, FILE * fp, char *unused);
+static FILE *authenticate_apop(Pop3 pc, FILE * fp, char *apop_str);
+static FILE *authenticate_plaintext(Pop3 pc, FILE * fp, char *unused);
+
+static struct authentication_method {
+	const char *name;
+	/* callback returns the filehandle if successful, 
+	   NULL if failed */
+	FILE *(*auth_callback) (Pop3 pc, FILE * fp, char *apop_str);
+} auth_methods[] = {
+	{
+	"cram-md5", authenticate_md5}, {
+	"apop", authenticate_apop}, {
+	"plaintext", authenticate_plaintext}, {
+	NULL, NULL}
+};
 
 FILE *pop3Login(Pop3 pc)
 {
@@ -28,7 +56,9 @@ FILE *pop3Login(Pop3 pc)
 	char buf[BUF_SIZE];
 	char apop_str[BUF_SIZE];
 	char *ptr1, *ptr2;
-	int has_apop = 0;
+	struct authentication_method *a;
+
+	apop_str[0] = '\0';			/* if defined, server supports apop */
 
 	if ((fd = sock_connect(PCU.serverName, PCU.serverPort)) == -1) {
 		fprintf(stderr, "Not Connected To Server '%s:%d'\n",
@@ -39,16 +69,14 @@ FILE *pop3Login(Pop3 pc)
 	fp = fdopen(fd, "r+");
 	fgets(buf, BUF_SIZE, fp);
 	fflush(fp);
-#ifdef DEBUG_POP3
-	fprintf(stderr, "%s", buf);
-#endif
-	/* Detect APOP */
+	DM("%s", buf);
+
+	/* Detect APOP, copy challenge into apop_str */
 	for (ptr1 = buf + strlen(buf), ptr2 = NULL; ptr1 > buf; --ptr1) {
 		if (*ptr1 == '>') {
 			ptr2 = ptr1;
 		} else if (*ptr1 == '<') {
 			if (ptr2) {
-				has_apop = 1;
 				*(ptr2 + 1) = 0;
 				strncpy(apop_str, ptr1, BUF_SIZE);
 			}
@@ -56,53 +84,22 @@ FILE *pop3Login(Pop3 pc)
 		}
 	}
 
-#ifdef WITH_GCRYPT
-	/* Try to authenticate using AUTH CRAM-MD5 first */
-	fprintf(fp, "AUTH CRAM-MD5\r\n");
-	fflush(fp);
-	fgets(buf, BUF_SIZE, fp);
-#ifdef DEBUG_POP3
-	fprintf(stderr, "%s", buf);
-#endif
-
-	if (buf[0] == '+' && buf[1] == ' ') {
-		return (authenticate_md5(pc, fp, buf));
+	/* try each authentication method in turn. */
+	for (a = auth_methods; a->name != NULL; a++) {
+		/* was it specified or did the user leave it up to us? */
+		if (PCU.authList[0] == '\0' || strstr(PCU.authList, a->name))
+			/* did it work? */
+			if ((a->auth_callback(pc, fp, apop_str)) != NULL)
+				return (fp);
 	}
 
-	if (has_apop) {				/* APOP is better than nothing */
-		return (authenticate_apop(pc, fp, apop_str));
-	}
-#endif
-	/* A brave man has nothing to hide */
-
-	fprintf(fp, "USER %s\r\n", PCU.userName);
-	fflush(fp);
-	fgets(buf, BUF_SIZE, fp);
-	if (buf[0] != '+') {
-		fprintf(stderr, "Invalid User Name '%s@%s:%d'\n",
-				PCU.userName, PCU.serverName, PCU.serverPort);
-#ifdef DEBUG_POP3
-		fprintf(stderr, "%s\n", buf);
-#endif
-		fprintf(fp, "QUIT\r\n");
-		fclose(fp);
-		return NULL;
-	};
-
-	fflush(fp);
-	fprintf(fp, "PASS %s\r\n", PCU.password);
-	fflush(fp);
-	fgets(buf, BUF_SIZE, fp);
-	if (buf[0] != '+') {
-		fprintf(stderr, "Incorrect Password for user '%s@%s:%d'\n",
-				PCU.userName, PCU.serverName, PCU.serverPort);
-		fprintf(stderr, "It said %s", buf);
-		fprintf(fp, "QUIT\r\n");
-		fclose(fp);
-		return NULL;
-	};
-
-	return fp;
+	/* if authentication worked, we won't get here */
+	fprintf(stderr,
+			"All Pop3 authentication methods failed for '%s@%s:%d'\n",
+			PCU.userName, PCU.serverName, PCU.serverPort);
+	fprintf(fp, "QUIT\r\n");
+	fclose(fp);
+	return NULL;
 }
 
 int pop3CheckMail(Pop3 pc)
@@ -154,164 +151,106 @@ int pop3CheckMail(Pop3 pc)
 	return 0;
 }
 
-int pop3Create(Pop3 pc, char *str)
+int pop3Create(Pop3 pc, const char *str)
 {
 	/* POP3 format: pop3:user:password at server[:port] */
 	/* new POP3 format: pop3:user password server [port] */
 	/* If 'str' line is badly formatted, wmbiff won't display the mailbox. */
+	int i;
+	int matchedchars;
+	struct re_registers regs;
+	/* ([^: ]+) user
+	   ([^@]+) or ([^ ]+) password 
+	   ([^: ]+) server 
+	   ([: ][0-9]+)? optional port 
+	   ' *' gobbles trailing whitespace before authentication types.
+	   use separate regexes for old and new types to permit
+	   use of '@' in passwords
+	 */
+	const char *regexes[] = {
+		"pop3:([^: ]+) ([^ ]+) ([^: ]+)( [0-9]+)? *",
+		"pop3:([^: ]+):([^@]+)@([^: ]+)(:[0-9]+)? *",
+		NULL
+	};
 
-	/* old config file style... */
-	if (parse_old_pop3_path(pc, str) != 0)
-
-		/* new config file style... */
-		if (parse_new_pop3_path(pc, str) != 0) {
-
-			/* The line is badly formatted,
-			 * we're not creating the mailbox line */
-			pc->label[0] = 0;
-			fprintf(stderr, "config line with bad format '%s'.\n", str);
-			return -1;
-		}
-
-	return 0;
-}
-
-/* parse the pop3 config line
- * one simple function with a delimiter won't work,
- * because of the '@' before server in old style!
- */
-int parse_old_pop3_path(Pop3 pc, char *str)
-{
-	char *tmp;
-	char *p;
-
-#ifdef DEBUG_POP3
-	printf("pop3: str = '%s'\n", str);
-#endif
-
-	strcpy(PCU.password, "");
-	strcpy(PCU.userName, "");
-	strcpy(PCU.serverName, "");
-	PCU.serverPort = 110;
-
-	tmp = strdup(str);
-
-	p = strtok(tmp, ":");		/* cut off 'pop3:' */
-
-	if ((p = strtok(NULL, ":"))) {	/* p -> username */
-		strcpy(PCU.userName, p);
-		if ((p = strtok(NULL, "@"))) {	/* p -> password */
-			strcpy(PCU.password, p);
-			if ((p = strtok(NULL, ":"))) {	/* p -> server */
-				strcpy(PCU.serverName, p);
-				strcpy(pc->path, "");	/* p -> mailbox */
-				if ((p = strtok(NULL, ":"))) {	/* p -> port */
-					PCU.serverPort = atoi(p);
-				}
-				free(tmp);
-
-#ifdef DEBUG_POP3
-				printf("pop3: userName= '%s'\n", PCU.userName);
-				printf("pop3: password= '%s'\n", PCU.password);
-				printf("pop3: serverName= '%s'\n", PCU.serverName);
-				printf("pop3: serverPort= '%d'\n", PCU.serverPort);
-#endif
-				pc->open = pop3Login;
-				pc->checkMail = pop3CheckMail;
-				pc->TotalMsgs = 0;
-				pc->UnreadMsgs = 0;
-				pc->OldMsgs = -1;
-				pc->OldUnreadMsgs = -1;
-				return 0;
-			}
-		}
+	for (matchedchars = 0, i = 0;
+		 regexes[i] != NULL && matchedchars <= 0; i++) {
+		matchedchars = compile_and_match_regex(regexes[i], str, &regs);
 	}
 
-	return 1;
-}
-
-/* delimiter is a "space" */
-int parse_new_pop3_path(Pop3 pc, char *str)
-{
-	char *tmp;
-	char *p;
-	char *delim = " ";
-
-#ifdef DEBUG_POP3
-	printf("pop3: str = '%s'\n", str);
-#endif
-
-	strcpy(PCU.password, "");
-	strcpy(PCU.userName, "");
-	strcpy(PCU.serverName, "");
-	PCU.serverPort = 110;
-
-	tmp = strdup(str);
-
-	p = strtok(tmp, ":");		/* cut off 'pop3:' */
-
-	if ((p = strtok(NULL, delim))) {	/* p -> username */
-		strcpy(PCU.userName, p);
-		if ((p = strtok(NULL, delim))) {	/* p -> password */
-			strcpy(PCU.password, p);
-			if ((p = strtok(NULL, delim))) {	/* p -> server */
-				strcpy(PCU.serverName, p);
-				strcpy(pc->path, "");	/* p -> mailbox */
-				if ((p = strtok(NULL, delim))) {	/* p -> port */
-					PCU.serverPort = atoi(p);
-				}
-				free(tmp);
-
-#ifdef DEBUG_POP3
-				printf("pop3: userName= '%s'\n", PCU.userName);
-				printf("pop3: password= '%s'\n", PCU.password);
-				printf("pop3: serverName= '%s'\n", PCU.serverName);
-				printf("pop3: serverPort= '%d'\n", PCU.serverPort);
-#endif
-				pc->open = pop3Login;
-				pc->checkMail = pop3CheckMail;
-				pc->TotalMsgs = 0;
-				pc->UnreadMsgs = 0;
-				pc->OldMsgs = -1;
-				pc->OldUnreadMsgs = -1;
-				return 0;
-			}
-		}
+	/* failed to match either regex */
+	if (matchedchars <= 0) {
+		pc->label[0] = '\0';
+		fprintf(stderr, "Couldn't parse line %s (%d)\n", str,
+				matchedchars);
+		return -1;
 	}
 
-	return 1;
+	/* copy matches where they belong */
+	copy_substring(PCU.userName, regs.start[1], regs.end[1], str);
+	copy_substring(PCU.password, regs.start[2], regs.end[2], str);
+	copy_substring(PCU.serverName, regs.start[3], regs.end[3], str);
+	if (regs.start[4] != -1)
+		PCU.serverPort = atoi(str + regs.start[4] + 1);
+	else
+		PCU.serverPort = 110;
+
+	grab_authList(str + regs.end[0], PCU.authList);
+
+	DM("pop3: userName= '%s'\n", PCU.userName);
+	DM("pop3: password= '%s'\n", PCU.password);
+	DM("pop3: serverName= '%s'\n", PCU.serverName);
+	DM("pop3: serverPort= '%d'\n", PCU.serverPort);
+	DM("pop3: authList= '%s'\n", PCU.authList);
+
+	pc->open = pop3Login;
+	pc->checkMail = pop3CheckMail;
+	pc->TotalMsgs = 0;
+	pc->UnreadMsgs = 0;
+	pc->OldMsgs = -1;
+	pc->OldUnreadMsgs = -1;
+	return 0;
 }
 
-#ifdef WITH_GCRYPT
 
-FILE *authenticate_md5(Pop3 pc, FILE * fp, char *buf)
+static FILE *authenticate_md5(Pop3 pc, FILE * fp, char *apop_str)
 {
+#ifdef WITH_GCRYPT
+	char buf[BUF_SIZE];
 	char buf2[BUF_SIZE];
 	unsigned char *md5;
 	GCRY_MD_HD gmh;
 
+	/* See if MD5 is supported */
+	fprintf(fp, "AUTH CRAM-MD5\r\n");
+	fflush(fp);
+	fgets(buf, BUF_SIZE, fp);
+	DM("%s", buf);
+
+	if (buf[0] != '+' || buf[1] != ' ') {
+		/* nope, not supported. */
+		return NULL;
+	}
+
 	Decode_Base64(buf + 2, buf2);
-#ifdef DEBUG_POP3
-	fprintf(stderr, "POP3 CRAM-MD5 challenge: %s\n", buf2);
-#endif
+	DM("POP3 CRAM-MD5 challenge: %s\n", buf2);
 
 	strcpy(buf, PCU.userName);
 	strcat(buf, " ");
 
+
 	gmh = gcry_md_open(GCRY_MD_MD5, GCRY_MD_FLAG_HMAC);
 	gcry_md_setkey(gmh, PCU.password, strlen(PCU.password));
 	gcry_md_write(gmh, (unsigned char *) buf2, strlen(buf2));
 	gcry_md_final(gmh);
 	md5 = gcry_md_read(gmh, 0);
-	//hmac_md5(buf2, strlen(buf2), PCU.password,
-	//      strlen(PCU.password), md5);
+	/* hmac_md5(buf2, strlen(buf2), PCU.password,
+	   strlen(PCU.password), md5); */
 	Bin2Hex(md5, 16, buf2);
 	gcry_md_close(gmh);
 
 	strcat(buf, buf2);
-#ifdef DEBUG_POP3
-	fprintf(stderr, "POP3 CRAM-MD5 response: %s\n", buf);
-#endif
+	DM("POP3 CRAM-MD5 response: %s\n", buf);
 	Encode_Base64(buf, buf2);
 
 	fprintf(fp, "%s\r\n", buf2);
@@ -325,21 +264,25 @@ FILE *authenticate_md5(Pop3 pc, FILE * fp, char *buf)
 				"POP3 CRAM-MD5 AUTH failed for user '%s@%s:%d'\n",
 				PCU.userName, PCU.serverName, PCU.serverPort);
 		fprintf(stderr, "It said %s", buf);
-		fprintf(fp, "QUIT\r\n");
-		fclose(fp);
 		return NULL;
 	}
+#else
+	return NULL;
+#endif
 }
 
-FILE *authenticate_apop(Pop3 pc, FILE * fp, char *apop_str)
+static FILE *authenticate_apop(Pop3 pc, FILE * fp, char *apop_str)
 {
+#ifdef WITH_GCRYPT
 	GCRY_MD_HD gmh;
 	char buf[BUF_SIZE];
 	unsigned char *md5;
 
-#ifdef DEBUG_POP3
-	fprintf(stderr, "POP3 APOP challenge: %s\n", apop_str);
-#endif
+	if (apop_str[0] == '\0') {
+		/* server doesn't support apop. */
+		return (NULL);
+	}
+	DM("POP3 APOP challenge: %s\n", apop_str);
 	strcat(apop_str, PCU.password);
 
 	gmh = gcry_md_open(GCRY_MD_MD5, 0);
@@ -349,9 +292,7 @@ FILE *authenticate_apop(Pop3 pc, FILE * fp, char *apop_str)
 	Bin2Hex(md5, 16, buf);
 	gcry_md_close(gmh);
 
-#ifdef DEBUG_POP3
-	fprintf(stderr, "POP3 APOP response: %s %s\n", PCU.userName, buf);
-#endif
+	DM("POP3 APOP response: %s %s\n", PCU.userName, buf);
 	fprintf(fp, "APOP %s %s\r\n", PCU.userName, buf);
 	fflush(fp);
 	fgets(buf, BUF_SIZE, fp);
@@ -362,11 +303,39 @@ FILE *authenticate_apop(Pop3 pc, FILE * fp, char *apop_str)
 		fprintf(stderr, "POP3 APOP AUTH failed for user '%s@%s:%d'\n",
 				PCU.userName, PCU.serverName, PCU.serverPort);
 		fprintf(stderr, "It said %s", buf);
-		fprintf(fp, "QUIT\r\n");
-		fclose(fp);
 		return NULL;
 	}
+#else
+	return NULL;
+#endif							/* WITH_GCRYPT */
+}
+
+static FILE *authenticate_plaintext(Pop3 pc, FILE * fp, char *apop_str)
+{
+	char buf[BUF_SIZE];
+
+	fprintf(fp, "USER %s\r\n", PCU.userName);
+	fflush(fp);
+	fgets(buf, BUF_SIZE, fp);
+	if (buf[0] != '+') {
+		fprintf(stderr, "Invalid User Name '%s@%s:%d'\n",
+				PCU.userName, PCU.serverName, PCU.serverPort);
+		DM("%s\n", buf);
+		return NULL;
+	};
+
+	fflush(fp);
+	fprintf(fp, "PASS %s\r\n", PCU.password);
+	fflush(fp);
+	fgets(buf, BUF_SIZE, fp);
+	if (buf[0] != '+') {
+		fprintf(stderr, "Incorrect Password for user '%s@%s:%d'\n",
+				PCU.userName, PCU.serverName, PCU.serverPort);
+		fprintf(stderr, "It said %s", buf);
+		return NULL;
+	};
+
+	return fp;
 }
-#endif
 
 /* vim:set ts=4: */
diff --git a/wmbiff/charutil.c b/wmbiff/charutil.c
index d4a9f23..59e406b 100644
--- a/wmbiff/charutil.c
+++ b/wmbiff/charutil.c
@@ -1,7 +1,8 @@
-/* $Id: charutil.c,v 1.4 2001/10/04 09:50:59 jordi Exp $ */
+/* $Id: charutil.c,v 1.5 2001/11/16 01:13:36 bluehal Exp $ */
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
+#include <ctype.h>
 #ifdef USE_DMALLOC
 #include <dmalloc.h>
 #endif
@@ -150,3 +151,70 @@ void Decode_Base64(char *src, char *dst)
 	}
 	*dst = 0;
 }
+
+/* helper function for the configuration line parser */
+void copy_substring(char *destination,
+					int startidx, int endidx, const char *source)
+{
+	if (startidx > -1) {
+		strncpy(destination, source + startidx, endidx - startidx);
+		destination[endidx - startidx] = '\0';
+	}
+}
+
+/* common to Pop3 and Imap4 authentication list grabber. */
+void grab_authList(const char *source, char *destination)
+{
+	int i;
+	/* regex isn't all that helpful for lists of things. */
+	/* but does leave the end of the matched region in  regs.end[0] */
+	/* what remains is a list of legal authentication schemes. */
+	if (isalnum(source[0])) {
+		/* copy, while turning caps into lower case */
+		for (i = 0; i < 99 && source[i] != '\0'; i++) {
+			destination[i] = tolower(source[i]);
+		}
+		destination[i] = '\0';
+	} else {
+		destination[0] = '\0';
+	}
+}
+
+
+int compile_and_match_regex(const char *regex,
+							const char *str, /*@out@ */
+							struct re_registers *regs)
+{
+
+	const char *errstr;
+	int matchedchars;
+	struct re_pattern_buffer rpbuf;
+
+	/* compile the regex pattern */
+	memset(&rpbuf, 0, sizeof(struct re_pattern_buffer));
+	re_syntax_options = RE_SYNTAX_EGREP;
+	errstr = re_compile_pattern(regex, strlen(regex), &rpbuf);
+	if (errstr != NULL) {
+		fprintf(stderr, "error in compiling regular expression: %s\n",
+				errstr);
+		return -1;
+	}
+
+	/* match the regex */
+	regs->num_regs = REGS_UNALLOCATED;
+	matchedchars = re_match(&rpbuf, str, strlen(str), 0, regs);
+	/* this can fail (return -1 or 0) without being an error,
+	   if we're trying to apply a regex just to see if it
+	   matched. */
+
+#ifdef undef
+	printf("--\n");
+	for (i = 1; i < 6; i++) {
+		printf("%d %d, (%.*s)\n", regs.start[i], regs.end[i],
+			   (regs.end[i] - regs.start[i]),
+			   (regs.start[i] >= 0) ? &str[regs.start[i]] : "");
+	}
+#endif
+
+	return matchedchars;
+}

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-wmaker/wmbiff.git



More information about the Pkg-wmaker-commits mailing list