Thanks to John Cummings.
This commit is contained in:
parent
cd37451963
commit
5cdb17983a
94 changed files with 26853 additions and 0 deletions
16
src/cmd/upas/pop3/mkfile
Normal file
16
src/cmd/upas/pop3/mkfile
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
</$objtype/mkfile
|
||||
|
||||
TARG=pop3
|
||||
|
||||
OFILES=pop3.$O
|
||||
|
||||
BIN=/$objtype/bin/upas
|
||||
LIB=../common/libcommon.a$O
|
||||
|
||||
UPDATE=\
|
||||
mkfile\
|
||||
${OFILES:%.$O=%.c}\
|
||||
|
||||
</sys/src/cmd/mkone
|
||||
|
||||
CFLAGS=$CFLAGS -I../common
|
||||
804
src/cmd/upas/pop3/pop3.c
Normal file
804
src/cmd/upas/pop3/pop3.c
Normal file
|
|
@ -0,0 +1,804 @@
|
|||
#include "common.h"
|
||||
#include <ctype.h>
|
||||
#include <auth.h>
|
||||
#include <libsec.h>
|
||||
|
||||
typedef struct Cmd Cmd;
|
||||
struct Cmd
|
||||
{
|
||||
char *name;
|
||||
int needauth;
|
||||
int (*f)(char*);
|
||||
};
|
||||
|
||||
static void hello(void);
|
||||
static int apopcmd(char*);
|
||||
static int capacmd(char*);
|
||||
static int delecmd(char*);
|
||||
static int listcmd(char*);
|
||||
static int noopcmd(char*);
|
||||
static int passcmd(char*);
|
||||
static int quitcmd(char*);
|
||||
static int rsetcmd(char*);
|
||||
static int retrcmd(char*);
|
||||
static int statcmd(char*);
|
||||
static int stlscmd(char*);
|
||||
static int topcmd(char*);
|
||||
static int synccmd(char*);
|
||||
static int uidlcmd(char*);
|
||||
static int usercmd(char*);
|
||||
static char *nextarg(char*);
|
||||
static int getcrnl(char*, int);
|
||||
static int readmbox(char*);
|
||||
static void sendcrnl(char*, ...);
|
||||
static int senderr(char*, ...);
|
||||
static int sendok(char*, ...);
|
||||
#pragma varargck argpos sendcrnl 1
|
||||
#pragma varargck argpos senderr 1
|
||||
#pragma varargck argpos sendok 1
|
||||
|
||||
Cmd cmdtab[] =
|
||||
{
|
||||
"apop", 0, apopcmd,
|
||||
"capa", 0, capacmd,
|
||||
"dele", 1, delecmd,
|
||||
"list", 1, listcmd,
|
||||
"noop", 0, noopcmd,
|
||||
"pass", 0, passcmd,
|
||||
"quit", 0, quitcmd,
|
||||
"rset", 0, rsetcmd,
|
||||
"retr", 1, retrcmd,
|
||||
"stat", 1, statcmd,
|
||||
"stls", 0, stlscmd,
|
||||
"sync", 1, synccmd,
|
||||
"top", 1, topcmd,
|
||||
"uidl", 1, uidlcmd,
|
||||
"user", 0, usercmd,
|
||||
0, 0, 0,
|
||||
};
|
||||
|
||||
static Biobuf in;
|
||||
static Biobuf out;
|
||||
static int passwordinclear;
|
||||
static int didtls;
|
||||
|
||||
typedef struct Msg Msg;
|
||||
struct Msg
|
||||
{
|
||||
int upasnum;
|
||||
char digest[64];
|
||||
int bytes;
|
||||
int deleted;
|
||||
};
|
||||
|
||||
static int totalbytes;
|
||||
static int totalmsgs;
|
||||
static Msg *msg;
|
||||
static int nmsg;
|
||||
static int loggedin;
|
||||
static int debug;
|
||||
static uchar *tlscert;
|
||||
static int ntlscert;
|
||||
static char *peeraddr;
|
||||
static char tmpaddr[64];
|
||||
|
||||
void
|
||||
usage(void)
|
||||
{
|
||||
fprint(2, "usage: upas/pop3 [-a authmboxfile] [-d debugfile] [-p]\n");
|
||||
exits("usage");
|
||||
}
|
||||
|
||||
void
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
int fd;
|
||||
char *arg, cmdbuf[1024];
|
||||
Cmd *c;
|
||||
|
||||
rfork(RFNAMEG);
|
||||
Binit(&in, 0, OREAD);
|
||||
Binit(&out, 1, OWRITE);
|
||||
|
||||
ARGBEGIN{
|
||||
case 'a':
|
||||
loggedin = 1;
|
||||
if(readmbox(EARGF(usage())) < 0)
|
||||
exits(nil);
|
||||
break;
|
||||
case 'd':
|
||||
debug++;
|
||||
if((fd = create(EARGF(usage()), OWRITE, 0666)) >= 0 && fd != 2){
|
||||
dup(fd, 2);
|
||||
close(fd);
|
||||
}
|
||||
break;
|
||||
case 'r':
|
||||
strecpy(tmpaddr, tmpaddr+sizeof tmpaddr, EARGF(usage()));
|
||||
if(arg = strchr(tmpaddr, '!'))
|
||||
*arg = '\0';
|
||||
peeraddr = tmpaddr;
|
||||
break;
|
||||
case 't':
|
||||
tlscert = readcert(EARGF(usage()), &ntlscert);
|
||||
if(tlscert == nil){
|
||||
senderr("cannot read TLS certificate: %r");
|
||||
exits(nil);
|
||||
}
|
||||
break;
|
||||
case 'p':
|
||||
passwordinclear = 1;
|
||||
break;
|
||||
}ARGEND
|
||||
|
||||
/* do before TLS */
|
||||
if(peeraddr == nil)
|
||||
peeraddr = remoteaddr(0,0);
|
||||
|
||||
hello();
|
||||
|
||||
while(Bflush(&out), getcrnl(cmdbuf, sizeof cmdbuf) > 0){
|
||||
arg = nextarg(cmdbuf);
|
||||
for(c=cmdtab; c->name; c++)
|
||||
if(cistrcmp(c->name, cmdbuf) == 0)
|
||||
break;
|
||||
if(c->name == 0){
|
||||
senderr("unknown command %s", cmdbuf);
|
||||
continue;
|
||||
}
|
||||
if(c->needauth && !loggedin){
|
||||
senderr("%s requires authentication", cmdbuf);
|
||||
continue;
|
||||
}
|
||||
(*c->f)(arg);
|
||||
}
|
||||
exits(nil);
|
||||
}
|
||||
|
||||
/* sort directories in increasing message number order */
|
||||
static int
|
||||
dircmp(void *a, void *b)
|
||||
{
|
||||
return atoi(((Dir*)a)->name) - atoi(((Dir*)b)->name);
|
||||
}
|
||||
|
||||
static int
|
||||
readmbox(char *box)
|
||||
{
|
||||
int fd, i, n, nd, lines, pid;
|
||||
char buf[100], err[ERRMAX];
|
||||
char *p;
|
||||
Biobuf *b;
|
||||
Dir *d, *draw;
|
||||
Msg *m;
|
||||
Waitmsg *w;
|
||||
|
||||
unmount(nil, "/mail/fs");
|
||||
switch(pid = fork()){
|
||||
case -1:
|
||||
return senderr("can't fork to start upas/fs");
|
||||
|
||||
case 0:
|
||||
close(0);
|
||||
close(1);
|
||||
open("/dev/null", OREAD);
|
||||
open("/dev/null", OWRITE);
|
||||
execl("/bin/upas/fs", "upas/fs", "-np", "-f", box, nil);
|
||||
snprint(err, sizeof err, "upas/fs: %r");
|
||||
_exits(err);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if((w = wait()) == nil || w->pid != pid || w->msg[0] != '\0'){
|
||||
if(w && w->pid==pid)
|
||||
return senderr("%s", w->msg);
|
||||
else
|
||||
return senderr("can't initialize upas/fs");
|
||||
}
|
||||
free(w);
|
||||
|
||||
if(chdir("/mail/fs/mbox") < 0)
|
||||
return senderr("can't initialize upas/fs: %r");
|
||||
|
||||
if((fd = open(".", OREAD)) < 0)
|
||||
return senderr("cannot open /mail/fs/mbox: %r");
|
||||
nd = dirreadall(fd, &d);
|
||||
close(fd);
|
||||
if(nd < 0)
|
||||
return senderr("cannot read from /mail/fs/mbox: %r");
|
||||
|
||||
msg = mallocz(sizeof(Msg)*nd, 1);
|
||||
if(msg == nil)
|
||||
return senderr("out of memory");
|
||||
|
||||
if(nd == 0)
|
||||
return 0;
|
||||
qsort(d, nd, sizeof(d[0]), dircmp);
|
||||
|
||||
for(i=0; i<nd; i++){
|
||||
m = &msg[nmsg];
|
||||
m->upasnum = atoi(d[i].name);
|
||||
sprint(buf, "%d/digest", m->upasnum);
|
||||
if((fd = open(buf, OREAD)) < 0)
|
||||
continue;
|
||||
n = readn(fd, m->digest, sizeof m->digest - 1);
|
||||
close(fd);
|
||||
if(n < 0)
|
||||
continue;
|
||||
m->digest[n] = '\0';
|
||||
|
||||
/*
|
||||
* We need the number of message lines so that we
|
||||
* can adjust the byte count to include \r's.
|
||||
* Upas/fs gives us the number of lines in the raw body
|
||||
* in the lines file, but we have to count rawheader ourselves.
|
||||
* There is one blank line between raw header and raw body.
|
||||
*/
|
||||
sprint(buf, "%d/rawheader", m->upasnum);
|
||||
if((b = Bopen(buf, OREAD)) == nil)
|
||||
continue;
|
||||
lines = 0;
|
||||
for(;;){
|
||||
p = Brdline(b, '\n');
|
||||
if(p == nil){
|
||||
if((n = Blinelen(b)) == 0)
|
||||
break;
|
||||
Bseek(b, n, 1);
|
||||
}else
|
||||
lines++;
|
||||
}
|
||||
Bterm(b);
|
||||
lines++;
|
||||
sprint(buf, "%d/lines", m->upasnum);
|
||||
if((fd = open(buf, OREAD)) < 0)
|
||||
continue;
|
||||
n = readn(fd, buf, sizeof buf - 1);
|
||||
close(fd);
|
||||
if(n < 0)
|
||||
continue;
|
||||
buf[n] = '\0';
|
||||
lines += atoi(buf);
|
||||
|
||||
sprint(buf, "%d/raw", m->upasnum);
|
||||
if((draw = dirstat(buf)) == nil)
|
||||
continue;
|
||||
m->bytes = lines+draw->length;
|
||||
free(draw);
|
||||
nmsg++;
|
||||
totalmsgs++;
|
||||
totalbytes += m->bytes;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* get a line that ends in crnl or cr, turn terminating crnl into a nl
|
||||
*
|
||||
* return 0 on EOF
|
||||
*/
|
||||
static int
|
||||
getcrnl(char *buf, int n)
|
||||
{
|
||||
int c;
|
||||
char *ep;
|
||||
char *bp;
|
||||
Biobuf *fp = ∈
|
||||
|
||||
Bflush(&out);
|
||||
|
||||
bp = buf;
|
||||
ep = bp + n - 1;
|
||||
while(bp != ep){
|
||||
c = Bgetc(fp);
|
||||
if(debug) {
|
||||
seek(2, 0, 2);
|
||||
fprint(2, "%c", c);
|
||||
}
|
||||
switch(c){
|
||||
case -1:
|
||||
*bp = 0;
|
||||
if(bp==buf)
|
||||
return 0;
|
||||
else
|
||||
return bp-buf;
|
||||
case '\r':
|
||||
c = Bgetc(fp);
|
||||
if(c == '\n'){
|
||||
if(debug) {
|
||||
seek(2, 0, 2);
|
||||
fprint(2, "%c", c);
|
||||
}
|
||||
*bp = 0;
|
||||
return bp-buf;
|
||||
}
|
||||
Bungetc(fp);
|
||||
c = '\r';
|
||||
break;
|
||||
case '\n':
|
||||
*bp = 0;
|
||||
return bp-buf;
|
||||
}
|
||||
*bp++ = c;
|
||||
}
|
||||
*bp = 0;
|
||||
return bp-buf;
|
||||
}
|
||||
|
||||
static void
|
||||
sendcrnl(char *fmt, ...)
|
||||
{
|
||||
char buf[1024];
|
||||
va_list arg;
|
||||
|
||||
va_start(arg, fmt);
|
||||
vseprint(buf, buf+sizeof(buf), fmt, arg);
|
||||
va_end(arg);
|
||||
if(debug)
|
||||
fprint(2, "-> %s\n", buf);
|
||||
Bprint(&out, "%s\r\n", buf);
|
||||
}
|
||||
|
||||
static int
|
||||
senderr(char *fmt, ...)
|
||||
{
|
||||
char buf[1024];
|
||||
va_list arg;
|
||||
|
||||
va_start(arg, fmt);
|
||||
vseprint(buf, buf+sizeof(buf), fmt, arg);
|
||||
va_end(arg);
|
||||
if(debug)
|
||||
fprint(2, "-> -ERR %s\n", buf);
|
||||
Bprint(&out, "-ERR %s\r\n", buf);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
sendok(char *fmt, ...)
|
||||
{
|
||||
char buf[1024];
|
||||
va_list arg;
|
||||
|
||||
va_start(arg, fmt);
|
||||
vseprint(buf, buf+sizeof(buf), fmt, arg);
|
||||
va_end(arg);
|
||||
if(*buf){
|
||||
if(debug)
|
||||
fprint(2, "-> +OK %s\n", buf);
|
||||
Bprint(&out, "+OK %s\r\n", buf);
|
||||
} else {
|
||||
if(debug)
|
||||
fprint(2, "-> +OK\n");
|
||||
Bprint(&out, "+OK\r\n");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
capacmd(char*)
|
||||
{
|
||||
sendok("");
|
||||
sendcrnl("TOP");
|
||||
if(passwordinclear || didtls)
|
||||
sendcrnl("USER");
|
||||
sendcrnl("PIPELINING");
|
||||
sendcrnl("UIDL");
|
||||
sendcrnl("STLS");
|
||||
sendcrnl(".");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
delecmd(char *arg)
|
||||
{
|
||||
int n;
|
||||
|
||||
if(*arg==0)
|
||||
return senderr("DELE requires a message number");
|
||||
|
||||
n = atoi(arg)-1;
|
||||
if(n < 0 || n >= nmsg || msg[n].deleted)
|
||||
return senderr("no such message");
|
||||
|
||||
msg[n].deleted = 1;
|
||||
totalmsgs--;
|
||||
totalbytes -= msg[n].bytes;
|
||||
sendok("message %d deleted", n+1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
listcmd(char *arg)
|
||||
{
|
||||
int i, n;
|
||||
|
||||
if(*arg == 0){
|
||||
sendok("+%d message%s (%d octets)", totalmsgs, totalmsgs==1 ? "":"s", totalbytes);
|
||||
for(i=0; i<nmsg; i++){
|
||||
if(msg[i].deleted)
|
||||
continue;
|
||||
sendcrnl("%d %d", i+1, msg[i].bytes);
|
||||
}
|
||||
sendcrnl(".");
|
||||
}else{
|
||||
n = atoi(arg)-1;
|
||||
if(n < 0 || n >= nmsg || msg[n].deleted)
|
||||
return senderr("no such message");
|
||||
sendok("%d %d", n+1, msg[n].bytes);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
noopcmd(char *arg)
|
||||
{
|
||||
USED(arg);
|
||||
sendok("");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
_synccmd(char*)
|
||||
{
|
||||
int i, fd;
|
||||
char *s;
|
||||
Fmt f;
|
||||
|
||||
if(!loggedin){
|
||||
sendok("");
|
||||
return;
|
||||
}
|
||||
|
||||
fmtstrinit(&f);
|
||||
fmtprint(&f, "delete mbox");
|
||||
for(i=0; i<nmsg; i++)
|
||||
if(msg[i].deleted)
|
||||
fmtprint(&f, " %d", msg[i].upasnum);
|
||||
s = fmtstrflush(&f);
|
||||
if(strcmp(s, "delete mbox") != 0){ /* must have something to delete */
|
||||
if((fd = open("../ctl", OWRITE)) < 0){
|
||||
senderr("open ctl to delete messages: %r");
|
||||
return;
|
||||
}
|
||||
if(write(fd, s, strlen(s)) < 0){
|
||||
senderr("error deleting messages: %r");
|
||||
return;
|
||||
}
|
||||
}
|
||||
sendok("");
|
||||
}
|
||||
|
||||
static int
|
||||
synccmd(char*)
|
||||
{
|
||||
_synccmd(nil);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
quitcmd(char*)
|
||||
{
|
||||
synccmd(nil);
|
||||
exits(nil);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
retrcmd(char *arg)
|
||||
{
|
||||
int n;
|
||||
Biobuf *b;
|
||||
char buf[40], *p;
|
||||
|
||||
if(*arg == 0)
|
||||
return senderr("RETR requires a message number");
|
||||
n = atoi(arg)-1;
|
||||
if(n < 0 || n >= nmsg || msg[n].deleted)
|
||||
return senderr("no such message");
|
||||
snprint(buf, sizeof buf, "%d/raw", msg[n].upasnum);
|
||||
if((b = Bopen(buf, OREAD)) == nil)
|
||||
return senderr("message disappeared");
|
||||
sendok("");
|
||||
while((p = Brdstr(b, '\n', 1)) != nil){
|
||||
if(p[0]=='.')
|
||||
Bwrite(&out, ".", 1);
|
||||
Bwrite(&out, p, strlen(p));
|
||||
Bwrite(&out, "\r\n", 2);
|
||||
free(p);
|
||||
}
|
||||
Bterm(b);
|
||||
sendcrnl(".");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
rsetcmd(char*)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i=0; i<nmsg; i++){
|
||||
if(msg[i].deleted){
|
||||
msg[i].deleted = 0;
|
||||
totalmsgs++;
|
||||
totalbytes += msg[i].bytes;
|
||||
}
|
||||
}
|
||||
return sendok("");
|
||||
}
|
||||
|
||||
static int
|
||||
statcmd(char*)
|
||||
{
|
||||
return sendok("%d %d", totalmsgs, totalbytes);
|
||||
}
|
||||
|
||||
static int
|
||||
trace(char *fmt, ...)
|
||||
{
|
||||
va_list arg;
|
||||
int n;
|
||||
|
||||
va_start(arg, fmt);
|
||||
n = vfprint(2, fmt, arg);
|
||||
va_end(arg);
|
||||
return n;
|
||||
}
|
||||
|
||||
static int
|
||||
stlscmd(char*)
|
||||
{
|
||||
int fd;
|
||||
TLSconn conn;
|
||||
|
||||
if(didtls)
|
||||
return senderr("tls already started");
|
||||
if(!tlscert)
|
||||
return senderr("don't have any tls credentials");
|
||||
sendok("");
|
||||
Bflush(&out);
|
||||
|
||||
memset(&conn, 0, sizeof conn);
|
||||
conn.cert = tlscert;
|
||||
conn.certlen = ntlscert;
|
||||
if(debug)
|
||||
conn.trace = trace;
|
||||
fd = tlsServer(0, &conn);
|
||||
if(fd < 0)
|
||||
sysfatal("tlsServer: %r");
|
||||
dup(fd, 0);
|
||||
dup(fd, 1);
|
||||
close(fd);
|
||||
Binit(&in, 0, OREAD);
|
||||
Binit(&out, 1, OWRITE);
|
||||
didtls = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
topcmd(char *arg)
|
||||
{
|
||||
int done, i, lines, n;
|
||||
char buf[40], *p;
|
||||
Biobuf *b;
|
||||
|
||||
if(*arg == 0)
|
||||
return senderr("TOP requires a message number");
|
||||
n = atoi(arg)-1;
|
||||
if(n < 0 || n >= nmsg || msg[n].deleted)
|
||||
return senderr("no such message");
|
||||
arg = nextarg(arg);
|
||||
if(*arg == 0)
|
||||
return senderr("TOP requires a line count");
|
||||
lines = atoi(arg);
|
||||
if(lines < 0)
|
||||
return senderr("bad args to TOP");
|
||||
snprint(buf, sizeof buf, "%d/raw", msg[n].upasnum);
|
||||
if((b = Bopen(buf, OREAD)) == nil)
|
||||
return senderr("message disappeared");
|
||||
sendok("");
|
||||
while(p = Brdstr(b, '\n', 1)){
|
||||
if(p[0]=='.')
|
||||
Bputc(&out, '.');
|
||||
Bwrite(&out, p, strlen(p));
|
||||
Bwrite(&out, "\r\n", 2);
|
||||
done = p[0]=='\0';
|
||||
free(p);
|
||||
if(done)
|
||||
break;
|
||||
}
|
||||
for(i=0; i<lines; i++){
|
||||
p = Brdstr(b, '\n', 1);
|
||||
if(p == nil)
|
||||
break;
|
||||
if(p[0]=='.')
|
||||
Bwrite(&out, ".", 1);
|
||||
Bwrite(&out, p, strlen(p));
|
||||
Bwrite(&out, "\r\n", 2);
|
||||
free(p);
|
||||
}
|
||||
sendcrnl(".");
|
||||
Bterm(b);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
uidlcmd(char *arg)
|
||||
{
|
||||
int n;
|
||||
|
||||
if(*arg==0){
|
||||
sendok("");
|
||||
for(n=0; n<nmsg; n++){
|
||||
if(msg[n].deleted)
|
||||
continue;
|
||||
sendcrnl("%d %s", n+1, msg[n].digest);
|
||||
}
|
||||
sendcrnl(".");
|
||||
}else{
|
||||
n = atoi(arg)-1;
|
||||
if(n < 0 || n >= nmsg || msg[n].deleted)
|
||||
return senderr("no such message");
|
||||
sendok("%d %s", n+1, msg[n].digest);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static char*
|
||||
nextarg(char *p)
|
||||
{
|
||||
while(*p && *p != ' ' && *p != '\t')
|
||||
p++;
|
||||
while(*p == ' ' || *p == '\t')
|
||||
*p++ = 0;
|
||||
return p;
|
||||
}
|
||||
|
||||
/*
|
||||
* authentication
|
||||
*/
|
||||
Chalstate *chs;
|
||||
char user[256];
|
||||
char box[256];
|
||||
char cbox[256];
|
||||
|
||||
static void
|
||||
hello(void)
|
||||
{
|
||||
fmtinstall('H', encodefmt);
|
||||
if((chs = auth_challenge("proto=apop role=server")) == nil){
|
||||
senderr("auth server not responding, try later");
|
||||
exits(nil);
|
||||
}
|
||||
|
||||
sendok("POP3 server ready %s", chs->chal);
|
||||
}
|
||||
|
||||
static int
|
||||
setuser(char *arg)
|
||||
{
|
||||
char *p;
|
||||
|
||||
strcpy(box, "/mail/box/");
|
||||
strecpy(box+strlen(box), box+sizeof box-7, arg);
|
||||
strcpy(cbox, box);
|
||||
cleanname(cbox);
|
||||
if(strcmp(cbox, box) != 0)
|
||||
return senderr("bad mailbox name");
|
||||
strcat(box, "/mbox");
|
||||
|
||||
strecpy(user, user+sizeof user, arg);
|
||||
if(p = strchr(user, '/'))
|
||||
*p = '\0';
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
usercmd(char *arg)
|
||||
{
|
||||
if(loggedin)
|
||||
return senderr("already authenticated");
|
||||
if(*arg == 0)
|
||||
return senderr("USER requires argument");
|
||||
if(setuser(arg) < 0)
|
||||
return -1;
|
||||
return sendok("");
|
||||
}
|
||||
|
||||
static void
|
||||
enableaddr(void)
|
||||
{
|
||||
int fd;
|
||||
char buf[64];
|
||||
|
||||
/* hide the peer IP address under a rock in the ratifier FS */
|
||||
if(peeraddr == 0 || *peeraddr == 0)
|
||||
return;
|
||||
|
||||
sprint(buf, "/mail/ratify/trusted/%s#32", peeraddr);
|
||||
|
||||
/*
|
||||
* if the address is already there and the user owns it,
|
||||
* remove it and recreate it to give him a new time quanta.
|
||||
*/
|
||||
if(access(buf, 0) >= 0 && remove(buf) < 0)
|
||||
return;
|
||||
|
||||
fd = create(buf, OREAD, 0666);
|
||||
if(fd >= 0){
|
||||
close(fd);
|
||||
// syslog(0, "pop3", "ratified %s", peeraddr);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
dologin(char *response)
|
||||
{
|
||||
AuthInfo *ai;
|
||||
static int tries;
|
||||
|
||||
chs->user = user;
|
||||
chs->resp = response;
|
||||
chs->nresp = strlen(response);
|
||||
if((ai = auth_response(chs)) == nil){
|
||||
if(tries++ >= 5){
|
||||
senderr("authentication failed: %r; server exiting");
|
||||
exits(nil);
|
||||
}
|
||||
return senderr("authentication failed");
|
||||
}
|
||||
|
||||
if(auth_chuid(ai, nil) < 0){
|
||||
senderr("chuid failed: %r; server exiting");
|
||||
exits(nil);
|
||||
}
|
||||
auth_freeAI(ai);
|
||||
auth_freechal(chs);
|
||||
chs = nil;
|
||||
|
||||
loggedin = 1;
|
||||
if(newns(user, 0) < 0){
|
||||
senderr("newns failed: %r; server exiting");
|
||||
exits(nil);
|
||||
}
|
||||
|
||||
enableaddr();
|
||||
if(readmbox(box) < 0)
|
||||
exits(nil);
|
||||
return sendok("mailbox is %s", box);
|
||||
}
|
||||
|
||||
static int
|
||||
passcmd(char *arg)
|
||||
{
|
||||
DigestState *s;
|
||||
uchar digest[MD5dlen];
|
||||
char response[2*MD5dlen+1];
|
||||
|
||||
if(passwordinclear==0 && didtls==0)
|
||||
return senderr("password in the clear disallowed");
|
||||
|
||||
/* use password to encode challenge */
|
||||
if((chs = auth_challenge("proto=apop role=server")) == nil)
|
||||
return senderr("couldn't get apop challenge");
|
||||
|
||||
// hash challenge with secret and convert to ascii
|
||||
s = md5((uchar*)chs->chal, chs->nchal, 0, 0);
|
||||
md5((uchar*)arg, strlen(arg), digest, s);
|
||||
snprint(response, sizeof response, "%.*H", MD5dlen, digest);
|
||||
return dologin(response);
|
||||
}
|
||||
|
||||
static int
|
||||
apopcmd(char *arg)
|
||||
{
|
||||
char *resp;
|
||||
|
||||
resp = nextarg(arg);
|
||||
if(setuser(arg) < 0)
|
||||
return -1;
|
||||
return dologin(resp);
|
||||
}
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue