#include <u.h>
#include <libc.h>
#include <auth.h>
#include <libsec.h>
#include <bio.h>
#include "imap4d.h"
/*
* hack to allow smtp forwarding.
* hide the peer IP address under a rock in the ratifier FS.
*/
void
enableForwarding(void)
{
char buf[64], peer[64], *p;
static ulong last;
ulong now;
int fd;
if(remote == nil)
return;
now = time(0);
if(now < last + 5*60)
return;
last = now;
fd = open("/srv/ratify", ORDWR);
if(fd < 0)
return;
if(!mount(fd, -1, "/mail/ratify", MBEFORE, "")){
close(fd);
return;
}
close(fd);
strncpy(peer, remote, sizeof(peer));
peer[sizeof(peer) - 1] = '\0';
p = strchr(peer, '!');
if(p != nil)
*p = '\0';
snprint(buf, sizeof(buf), "/mail/ratify/trusted/%s#32", peer);
/*
* 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);
}
void
setupuser(AuthInfo *ai)
{
Waitmsg *w;
int pid;
if(ai){
strecpy(username, username+sizeof username, ai->cuid);
if(auth_chuid(ai, nil) < 0)
bye("user auth failed: %r");
auth_freeAI(ai);
}else
strecpy(username, username+sizeof username, getuser());
if(newns(username, 0) < 0)
bye("user login failed: %r");
/*
* hack to allow access to outgoing smtp forwarding
*/
enableForwarding();
snprint(mboxDir, MboxNameLen, "/mail/box/%s", username);
if(myChdir(mboxDir) < 0)
bye("can't open user's mailbox");
switch(pid = fork()){
case -1:
bye("can't initialize mail system");
break;
case 0:
execl("/bin/upas/fs", "upas/fs", "-np", nil);
_exits("rob1");
_exits(0);
break;
default:
break;
}
if((w=wait()) == nil || w->pid != pid || w->msg[0] != '\0')
bye("can't initialize mail system");
free(w);
}
static char*
authresp(void)
{
char *s, *t;
int n;
t = Brdline(&bin, '\n');
n = Blinelen(&bin);
if(n < 2)
return nil;
n--;
if(t[n-1] == '\r')
n--;
t[n] = '\0';
if(n == 0 || strcmp(t, "*") == 0)
return nil;
s = binalloc(&parseBin, n + 1, 0);
n = dec64((uchar*)s, n, t, n);
s[n] = '\0';
return s;
}
/*
* rfc 2195 cram-md5 authentication
*/
char*
cramauth(void)
{
AuthInfo *ai;
Chalstate *cs;
char *s, *t;
int n;
if((cs = auth_challenge("proto=cram role=server")) == nil)
return "couldn't get cram challenge";
n = cs->nchal;
s = binalloc(&parseBin, n * 2, 0);
n = enc64(s, n * 2, (uchar*)cs->chal, n);
Bprint(&bout, "+ ");
Bwrite(&bout, s, n);
Bprint(&bout, "\r\n");
if(Bflush(&bout) < 0)
writeErr();
s = authresp();
if(s == nil)
return "client cancelled authentication";
t = strchr(s, ' ');
if(t == nil)
bye("bad auth response");
*t++ = '\0';
strncpy(username, s, UserNameLen);
username[UserNameLen-1] = '\0';
cs->user = username;
cs->resp = t;
cs->nresp = strlen(t);
if((ai = auth_response(cs)) == nil)
return "login failed";
auth_freechal(cs);
setupuser(ai);
return nil;
}
AuthInfo*
passLogin(char *user, char *secret)
{
AuthInfo *ai;
Chalstate *cs;
uchar digest[MD5dlen];
char response[2*MD5dlen+1];
int i;
if((cs = auth_challenge("proto=cram role=server")) == nil)
return nil;
hmac_md5((uchar*)cs->chal, strlen(cs->chal),
(uchar*)secret, strlen(secret), digest,
nil);
for(i = 0; i < MD5dlen; i++)
snprint(response + 2*i, sizeof(response) - 2*i, "%2.2ux", digest[i]);
cs->user = user;
cs->resp = response;
cs->nresp = strlen(response);
ai = auth_response(cs);
auth_freechal(cs);
return ai;
}
|