xref: /plan9/sys/src/cmd/ip/imap4d/auth.c (revision 9a747e4fd48b9f4522c70c07e8f882a15030f964)
17dd7cddfSDavid du Colombier #include <u.h>
27dd7cddfSDavid du Colombier #include <libc.h>
37dd7cddfSDavid du Colombier #include <auth.h>
47dd7cddfSDavid du Colombier #include <libsec.h>
57dd7cddfSDavid du Colombier #include <bio.h>
67dd7cddfSDavid du Colombier #include "imap4d.h"
77dd7cddfSDavid du Colombier 
880ee5cbfSDavid du Colombier /*
980ee5cbfSDavid du Colombier  * hack to allow smtp forwarding.
1080ee5cbfSDavid du Colombier  * hide the peer IP address under a rock in the ratifier FS.
1180ee5cbfSDavid du Colombier  */
1280ee5cbfSDavid du Colombier void
enableForwarding(void)1380ee5cbfSDavid du Colombier enableForwarding(void)
1480ee5cbfSDavid du Colombier {
1580ee5cbfSDavid du Colombier 	char buf[64], peer[64], *p;
1680ee5cbfSDavid du Colombier 	static ulong last;
1780ee5cbfSDavid du Colombier 	ulong now;
1880ee5cbfSDavid du Colombier 	int fd;
1980ee5cbfSDavid du Colombier 
2080ee5cbfSDavid du Colombier 	if(remote == nil)
2180ee5cbfSDavid du Colombier 		return;
2280ee5cbfSDavid du Colombier 
2380ee5cbfSDavid du Colombier 	now = time(0);
2480ee5cbfSDavid du Colombier 	if(now < last + 5*60)
2580ee5cbfSDavid du Colombier 		return;
2680ee5cbfSDavid du Colombier 	last = now;
2780ee5cbfSDavid du Colombier 
2880ee5cbfSDavid du Colombier 	fd = open("/srv/ratify", ORDWR);
2980ee5cbfSDavid du Colombier 	if(fd < 0)
3080ee5cbfSDavid du Colombier 		return;
31*9a747e4fSDavid du Colombier 	if(!mount(fd, -1, "/mail/ratify", MBEFORE, "")){
3280ee5cbfSDavid du Colombier 		close(fd);
3380ee5cbfSDavid du Colombier 		return;
3480ee5cbfSDavid du Colombier 	}
3580ee5cbfSDavid du Colombier 	close(fd);
3680ee5cbfSDavid du Colombier 
3780ee5cbfSDavid du Colombier 	strncpy(peer, remote, sizeof(peer));
3880ee5cbfSDavid du Colombier 	peer[sizeof(peer) - 1] = '\0';
3980ee5cbfSDavid du Colombier 	p = strchr(peer, '!');
4080ee5cbfSDavid du Colombier 	if(p != nil)
4180ee5cbfSDavid du Colombier 		*p = '\0';
4280ee5cbfSDavid du Colombier 
4380ee5cbfSDavid du Colombier 	snprint(buf, sizeof(buf), "/mail/ratify/trusted/%s#32", peer);
4480ee5cbfSDavid du Colombier 
4580ee5cbfSDavid du Colombier 	/*
4680ee5cbfSDavid du Colombier 	 * if the address is already there and the user owns it,
4780ee5cbfSDavid du Colombier 	 * remove it and recreate it to give him a new time quanta.
4880ee5cbfSDavid du Colombier 	 */
4980ee5cbfSDavid du Colombier 	if(access(buf, 0) >= 0 && remove(buf) < 0)
5080ee5cbfSDavid du Colombier 		return;
5180ee5cbfSDavid du Colombier 
5280ee5cbfSDavid du Colombier 	fd = create(buf, OREAD, 0666);
5380ee5cbfSDavid du Colombier 	if(fd >= 0)
5480ee5cbfSDavid du Colombier 		close(fd);
5580ee5cbfSDavid du Colombier }
5680ee5cbfSDavid du Colombier 
577dd7cddfSDavid du Colombier void
setupuser(AuthInfo * ai)58*9a747e4fSDavid du Colombier setupuser(AuthInfo *ai)
597dd7cddfSDavid du Colombier {
60*9a747e4fSDavid du Colombier 	Waitmsg *w;
617dd7cddfSDavid du Colombier 	int pid;
627dd7cddfSDavid du Colombier 
63*9a747e4fSDavid du Colombier 	if(ai){
64*9a747e4fSDavid du Colombier 		strecpy(username, username+sizeof username, ai->cuid);
65*9a747e4fSDavid du Colombier 
66*9a747e4fSDavid du Colombier 		if(auth_chuid(ai, nil) < 0)
67*9a747e4fSDavid du Colombier 			bye("user auth failed: %r");
68*9a747e4fSDavid du Colombier 		auth_freeAI(ai);
69*9a747e4fSDavid du Colombier 	}else
70*9a747e4fSDavid du Colombier 		strecpy(username, username+sizeof username, getuser());
71*9a747e4fSDavid du Colombier 
727dd7cddfSDavid du Colombier 	if(newns(username, 0) < 0)
737dd7cddfSDavid du Colombier 		bye("user login failed: %r");
7480ee5cbfSDavid du Colombier 
7580ee5cbfSDavid du Colombier 	/*
7680ee5cbfSDavid du Colombier 	 * hack to allow access to outgoing smtp forwarding
7780ee5cbfSDavid du Colombier 	 */
7880ee5cbfSDavid du Colombier 	enableForwarding();
7980ee5cbfSDavid du Colombier 
80*9a747e4fSDavid du Colombier 	snprint(mboxDir, MboxNameLen, "/mail/box/%s", username);
817dd7cddfSDavid du Colombier 	if(myChdir(mboxDir) < 0)
827dd7cddfSDavid du Colombier 		bye("can't open user's mailbox");
837dd7cddfSDavid du Colombier 
847dd7cddfSDavid du Colombier 	switch(pid = fork()){
857dd7cddfSDavid du Colombier 	case -1:
867dd7cddfSDavid du Colombier 		bye("can't initialize mail system");
877dd7cddfSDavid du Colombier 		break;
887dd7cddfSDavid du Colombier 	case 0:
8959cc4ca5SDavid du Colombier 		execl("/bin/upas/fs", "upas/fs", "-np", nil);
90*9a747e4fSDavid du Colombier _exits("rob1");
917dd7cddfSDavid du Colombier 		_exits(0);
927dd7cddfSDavid du Colombier 		break;
937dd7cddfSDavid du Colombier 	default:
947dd7cddfSDavid du Colombier 		break;
957dd7cddfSDavid du Colombier 	}
96*9a747e4fSDavid du Colombier 	if((w=wait()) == nil || w->pid != pid || w->msg[0] != '\0')
977dd7cddfSDavid du Colombier 		bye("can't initialize mail system");
98*9a747e4fSDavid du Colombier 	free(w);
997dd7cddfSDavid du Colombier }
1007dd7cddfSDavid du Colombier 
1017dd7cddfSDavid du Colombier static char*
authresp(void)1027dd7cddfSDavid du Colombier authresp(void)
1037dd7cddfSDavid du Colombier {
1047dd7cddfSDavid du Colombier 	char *s, *t;
1057dd7cddfSDavid du Colombier 	int n;
1067dd7cddfSDavid du Colombier 
1077dd7cddfSDavid du Colombier 	t = Brdline(&bin, '\n');
1087dd7cddfSDavid du Colombier 	n = Blinelen(&bin);
1097dd7cddfSDavid du Colombier 	if(n < 2)
1107dd7cddfSDavid du Colombier 		return nil;
1117dd7cddfSDavid du Colombier 	n--;
1127dd7cddfSDavid du Colombier 	if(t[n-1] == '\r')
1137dd7cddfSDavid du Colombier 		n--;
1147dd7cddfSDavid du Colombier 	t[n] = '\0';
1157dd7cddfSDavid du Colombier 	if(n == 0 || strcmp(t, "*") == 0)
1167dd7cddfSDavid du Colombier 		return nil;
1177dd7cddfSDavid du Colombier 
11880ee5cbfSDavid du Colombier 	s = binalloc(&parseBin, n + 1, 0);
1197dd7cddfSDavid du Colombier 	n = dec64((uchar*)s, n, t, n);
1207dd7cddfSDavid du Colombier 	s[n] = '\0';
1217dd7cddfSDavid du Colombier 	return s;
1227dd7cddfSDavid du Colombier }
1237dd7cddfSDavid du Colombier 
1247dd7cddfSDavid du Colombier /*
1257dd7cddfSDavid du Colombier  * rfc 2195 cram-md5 authentication
1267dd7cddfSDavid du Colombier  */
1277dd7cddfSDavid du Colombier char*
cramauth(void)1287dd7cddfSDavid du Colombier cramauth(void)
1297dd7cddfSDavid du Colombier {
130*9a747e4fSDavid du Colombier 	AuthInfo *ai;
131*9a747e4fSDavid du Colombier 	Chalstate *cs;
1327dd7cddfSDavid du Colombier 	char *s, *t;
1337dd7cddfSDavid du Colombier 	int n;
1347dd7cddfSDavid du Colombier 
135*9a747e4fSDavid du Colombier 	if((cs = auth_challenge("proto=cram role=server")) == nil)
1367dd7cddfSDavid du Colombier 		return "couldn't get cram challenge";
1377dd7cddfSDavid du Colombier 
138*9a747e4fSDavid du Colombier 	n = cs->nchal;
13980ee5cbfSDavid du Colombier 	s = binalloc(&parseBin, n * 2, 0);
140*9a747e4fSDavid du Colombier 	n = enc64(s, n * 2, (uchar*)cs->chal, n);
1417dd7cddfSDavid du Colombier 	Bprint(&bout, "+ ");
1427dd7cddfSDavid du Colombier 	Bwrite(&bout, s, n);
1437dd7cddfSDavid du Colombier 	Bprint(&bout, "\r\n");
1447dd7cddfSDavid du Colombier 	if(Bflush(&bout) < 0)
1457dd7cddfSDavid du Colombier 		writeErr();
1467dd7cddfSDavid du Colombier 
1477dd7cddfSDavid du Colombier 	s = authresp();
1487dd7cddfSDavid du Colombier 	if(s == nil)
1497dd7cddfSDavid du Colombier 		return "client cancelled authentication";
1507dd7cddfSDavid du Colombier 
1517dd7cddfSDavid du Colombier 	t = strchr(s, ' ');
1527dd7cddfSDavid du Colombier 	if(t == nil)
1537dd7cddfSDavid du Colombier 		bye("bad auth response");
1547dd7cddfSDavid du Colombier 	*t++ = '\0';
155*9a747e4fSDavid du Colombier 	strncpy(username, s, UserNameLen);
156*9a747e4fSDavid du Colombier 	username[UserNameLen-1] = '\0';
1577dd7cddfSDavid du Colombier 
158*9a747e4fSDavid du Colombier 	cs->user = username;
159*9a747e4fSDavid du Colombier 	cs->resp = t;
160*9a747e4fSDavid du Colombier 	cs->nresp = strlen(t);
161*9a747e4fSDavid du Colombier 	if((ai = auth_response(cs)) == nil)
1627dd7cddfSDavid du Colombier 		return "login failed";
163*9a747e4fSDavid du Colombier 	auth_freechal(cs);
164*9a747e4fSDavid du Colombier 	setupuser(ai);
1657dd7cddfSDavid du Colombier 	return nil;
1667dd7cddfSDavid du Colombier }
1677dd7cddfSDavid du Colombier 
168*9a747e4fSDavid du Colombier AuthInfo*
passLogin(char * user,char * secret)169*9a747e4fSDavid du Colombier passLogin(char *user, char *secret)
1707dd7cddfSDavid du Colombier {
171*9a747e4fSDavid du Colombier 	AuthInfo *ai;
172*9a747e4fSDavid du Colombier 	Chalstate *cs;
1737dd7cddfSDavid du Colombier 	uchar digest[MD5dlen];
1747dd7cddfSDavid du Colombier 	char response[2*MD5dlen+1];
1757dd7cddfSDavid du Colombier 	int i;
1767dd7cddfSDavid du Colombier 
177*9a747e4fSDavid du Colombier 	if((cs = auth_challenge("proto=cram role=server")) == nil)
178*9a747e4fSDavid du Colombier 		return nil;
1797dd7cddfSDavid du Colombier 
180*9a747e4fSDavid du Colombier 	hmac_md5((uchar*)cs->chal, strlen(cs->chal),
1817dd7cddfSDavid du Colombier 		(uchar*)secret, strlen(secret), digest,
1827dd7cddfSDavid du Colombier 		nil);
1837dd7cddfSDavid du Colombier 	for(i = 0; i < MD5dlen; i++)
1847dd7cddfSDavid du Colombier 		snprint(response + 2*i, sizeof(response) - 2*i, "%2.2ux", digest[i]);
1857dd7cddfSDavid du Colombier 
186*9a747e4fSDavid du Colombier 	cs->user = user;
187*9a747e4fSDavid du Colombier 	cs->resp = response;
188*9a747e4fSDavid du Colombier 	cs->nresp = strlen(response);
189*9a747e4fSDavid du Colombier 	ai = auth_response(cs);
190*9a747e4fSDavid du Colombier 	auth_freechal(cs);
191*9a747e4fSDavid du Colombier 	return ai;
1927dd7cddfSDavid du Colombier }
193