[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, ®s) <= 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, ®s);
- 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, ®s);
}
- 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