[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
CRAM-MD5 for POP3 patch - please review
- To: qmail@xxxxxxxxxxxxx
- Subject: CRAM-MD5 for POP3 patch - please review
- From: Alex Pleiner <pleiner@xxxxxxxxxxx>
- Date: Mon, 01 Mar 2004 14:31:17 +0100
- Delivered-to: de5-qmail@sws5.ornl.gov
- Delivered-to: mailing list qmail@list.cr.yp.to
- Mail-followup-to: qmail@list.cr.yp.to
- Mailing-list: contact qmail-help@list.cr.yp.to; run by ezmlm
- Organization: zeitform Internet Dienste, http://www.zeitform.de
- User-agent: Mutt/1.5.6i
I have created a patch for qmail-popup that adds the CAPA command and
CRAM-MD5 as authentication mechanism. This patch is based on the current
SMTP AUTH patch provided by Erwin Hoffmann at [1] with small
changes to make it work for POP3.
Well, I know there is no real need for AUTH CRAM-MD5 as the transmission
of cleartext passwords may be avoided by using APOP or an SSL connection
(e.g. via stunnel). On the other hand there are POP3-Clients that
support CRAM-MD5 and we have customers to migrate that currently use it.
Could you please have a look at the code and direct me to problems or
bugs within. Your help is appreciated very much.
BTW, using this patch with current vpopmail requires the addition of two
lines to vchkpw.c:
/* Check APOP auth */
if(ConnType == POP_CONN) {
apopaccepted = authapop(ThePass,TheChallenge,vpw->pw_clear_passwd);
if(apopaccepted == 0) strcpy(AuthType, "APOP");
/* --- add these two lines --- */
cramaccepted = authcram(ThePass,TheChallenge,vpw->pw_clear_passwd);
if(cramaccepted == 0) strcpy(AuthType, "CRAM-MD5");
Alex
[1] http://www.fehcom.de/qmail/smtpauth.html
--
Alex Pleiner
zeitform Internet Dienste Fraunhoferstrasse 5
64283 Darmstadt, Germany
http://www.zeitform.de Tel.: +49 (0)6151 155-635
mailto:pleiner@xxxxxxxxxxx Fax: +49 (0)6151 155-634
GnuPG/PGP Key-ID: 0x613C21EA
--- ../qmail-1.03-unpatched/qmail-popup.c 1998-06-15 12:53:16.000000000 +0200
+++ qmail-popup.c 2004-02-27 16:34:06.000000000 +0100
@@ -14,6 +14,9 @@
#include "timeoutread.h"
#include "timeoutwrite.h"
+#include "case.h"
+#include "base64.h"
+
void die() { _exit(1); }
int saferead(fd,buf,len) int fd; char *buf; int len;
@@ -72,7 +75,12 @@
char unique[FMT_ULONG + FMT_ULONG + 3];
char *hostname;
-stralloc username = {0};
+stralloc authin = {0}; /* input from POP3 client */
+stralloc username = {0}; /* username */
+stralloc chal = {0}; /* challenge */
+stralloc slop = {0}; /* b64 challenge */
+stralloc resp = {0}; /* b64 response */
+
int seenuser = 0;
char **childargs;
substdio ssup;
@@ -133,6 +141,19 @@
puts(">\r\n");
flush();
}
+void pop3_capa(arg) char *arg;
+{
+ puts("+OK Capability list follows\r\n");
+ puts("TOP\r\n");
+ puts("UIDL\r\n");
+ puts("LAST\r\n");
+ puts("USER\r\n");
+ puts("APOP\r\n");
+ puts("SASL CRAM-MD5\r\n");
+ puts(".\r\n");
+ flush();
+}
+
void pop3_user(arg) char *arg;
{
if (!*arg) { err_syntax(); return; }
@@ -156,11 +177,99 @@
doanddie(arg,space - arg,space);
}
+int authgetl(void) {
+ int i;
+
+ if (!stralloc_copys(&authin,"")) die_nomem();
+ for (;;) {
+ if (!stralloc_readyplus(&authin,1)) die_nomem(); /* XXX */
+ i = substdio_get(&ssin,authin.s + authin.len,1);
+ if (i != 1) die();
+ if (authin.s[authin.len] == '\n') break;
+ ++authin.len;
+ }
+
+ if (authin.len > 0) if (authin.s[authin.len - 1] == '\r') --authin.len;
+ authin.s[authin.len] = 0;
+ if (*authin.s == '*' && *(authin.s + 1) == 0) { die_badauth(); }
+ if (authin.len == 0) { die_badauth(); }
+ return authin.len;
+}
+
+
+void pop3_auth_cram(arg) char *arg;
+{
+ int i, r;
+ char *s;
+
+
+ s = unique;
+ s += fmt_uint(s,getpid());
+ *s++ = '.';
+ s += fmt_ulong(s,(unsigned long) now());
+ *s++ = '@';
+ *s++ = 0;
+
+ if (!stralloc_copys(&chal,"<")) die_nomem(); /* generate challenge */
+ if (!stralloc_cats(&chal,unique)) die_nomem();
+ if (!stralloc_cats(&chal,hostname)) die_nomem();
+ if (!stralloc_cats(&chal,">")) die_nomem();
+ if (b64encode(&chal,&slop) < 0) die_nomem();
+ if (!stralloc_0(&slop)) die_nomem();
+
+ puts("+ ");
+ puts(slop.s);
+ puts("\r\n");
+ flush();
+
+ if (authgetl() < 0) die_badauth(); /* got response */
+
+ if (r = b64decode(authin.s,authin.len,&resp) == 1) die_badauth();
+
+ /* if (r == -1 || !stralloc_0(&resp)) die_nomem(); */
+
+ i = str_chr(resp.s,' ');
+ s = resp.s + i;
+ while (*s == ' ') ++s;
+ resp.s[i] = 0;
+
+ if (!stralloc_copys(&username,resp.s)) die_nomem(); /* userid */
+ if (!stralloc_0(&username)) die_nomem();
+ if (!username.len || !s) die_badauth();
+
+ doanddie(username.s,username.len,s);
+}
+struct authcmd {
+ char *text;
+ void (*fun)();
+} authcmds[] = {
+ { "cram-md5",pop3_auth_cram }
+, { 0,die_badauth }
+};
+
+void pop3_auth(arg) char *arg;
+{
+ int i;
+ char *cmd = arg;
+
+ i = str_chr(cmd,' ');
+ arg = cmd + i;
+ while (*arg == ' ') ++arg;
+ cmd[i] = 0;
+
+ for (i = 0;authcmds[i].text;++i)
+ if (case_equals(authcmds[i].text,cmd)) authcmds[i].fun(arg);
+
+ puts("-ERR unsupported method\r\n"); flush(); return;
+}
+
struct commands pop3commands[] = {
{ "user", pop3_user, 0 }
, { "pass", pop3_pass, 0 }
, { "apop", pop3_apop, 0 }
+, { "auth", pop3_auth, 0 }
, { "quit", pop3_quit, 0 }
+, { "capa", pop3_capa, 0 }
, { "noop", okay, 0 }
, { 0, err_authoriz, 0 }
} ;