xref: /plan9/sys/src/cmd/ip/imap4d/auth.c (revision 9a747e4fd48b9f4522c70c07e8f882a15030f964)
1 #include <u.h>
2 #include <libc.h>
3 #include <auth.h>
4 #include <libsec.h>
5 #include <bio.h>
6 #include "imap4d.h"
7 
8 /*
9  * hack to allow smtp forwarding.
10  * hide the peer IP address under a rock in the ratifier FS.
11  */
12 void
enableForwarding(void)13 enableForwarding(void)
14 {
15 	char buf[64], peer[64], *p;
16 	static ulong last;
17 	ulong now;
18 	int fd;
19 
20 	if(remote == nil)
21 		return;
22 
23 	now = time(0);
24 	if(now < last + 5*60)
25 		return;
26 	last = now;
27 
28 	fd = open("/srv/ratify", ORDWR);
29 	if(fd < 0)
30 		return;
31 	if(!mount(fd, -1, "/mail/ratify", MBEFORE, "")){
32 		close(fd);
33 		return;
34 	}
35 	close(fd);
36 
37 	strncpy(peer, remote, sizeof(peer));
38 	peer[sizeof(peer) - 1] = '\0';
39 	p = strchr(peer, '!');
40 	if(p != nil)
41 		*p = '\0';
42 
43 	snprint(buf, sizeof(buf), "/mail/ratify/trusted/%s#32", peer);
44 
45 	/*
46 	 * if the address is already there and the user owns it,
47 	 * remove it and recreate it to give him a new time quanta.
48 	 */
49 	if(access(buf, 0) >= 0 && remove(buf) < 0)
50 		return;
51 
52 	fd = create(buf, OREAD, 0666);
53 	if(fd >= 0)
54 		close(fd);
55 }
56 
57 void
setupuser(AuthInfo * ai)58 setupuser(AuthInfo *ai)
59 {
60 	Waitmsg *w;
61 	int pid;
62 
63 	if(ai){
64 		strecpy(username, username+sizeof username, ai->cuid);
65 
66 		if(auth_chuid(ai, nil) < 0)
67 			bye("user auth failed: %r");
68 		auth_freeAI(ai);
69 	}else
70 		strecpy(username, username+sizeof username, getuser());
71 
72 	if(newns(username, 0) < 0)
73 		bye("user login failed: %r");
74 
75 	/*
76 	 * hack to allow access to outgoing smtp forwarding
77 	 */
78 	enableForwarding();
79 
80 	snprint(mboxDir, MboxNameLen, "/mail/box/%s", username);
81 	if(myChdir(mboxDir) < 0)
82 		bye("can't open user's mailbox");
83 
84 	switch(pid = fork()){
85 	case -1:
86 		bye("can't initialize mail system");
87 		break;
88 	case 0:
89 		execl("/bin/upas/fs", "upas/fs", "-np", nil);
90 _exits("rob1");
91 		_exits(0);
92 		break;
93 	default:
94 		break;
95 	}
96 	if((w=wait()) == nil || w->pid != pid || w->msg[0] != '\0')
97 		bye("can't initialize mail system");
98 	free(w);
99 }
100 
101 static char*
authresp(void)102 authresp(void)
103 {
104 	char *s, *t;
105 	int n;
106 
107 	t = Brdline(&bin, '\n');
108 	n = Blinelen(&bin);
109 	if(n < 2)
110 		return nil;
111 	n--;
112 	if(t[n-1] == '\r')
113 		n--;
114 	t[n] = '\0';
115 	if(n == 0 || strcmp(t, "*") == 0)
116 		return nil;
117 
118 	s = binalloc(&parseBin, n + 1, 0);
119 	n = dec64((uchar*)s, n, t, n);
120 	s[n] = '\0';
121 	return s;
122 }
123 
124 /*
125  * rfc 2195 cram-md5 authentication
126  */
127 char*
cramauth(void)128 cramauth(void)
129 {
130 	AuthInfo *ai;
131 	Chalstate *cs;
132 	char *s, *t;
133 	int n;
134 
135 	if((cs = auth_challenge("proto=cram role=server")) == nil)
136 		return "couldn't get cram challenge";
137 
138 	n = cs->nchal;
139 	s = binalloc(&parseBin, n * 2, 0);
140 	n = enc64(s, n * 2, (uchar*)cs->chal, n);
141 	Bprint(&bout, "+ ");
142 	Bwrite(&bout, s, n);
143 	Bprint(&bout, "\r\n");
144 	if(Bflush(&bout) < 0)
145 		writeErr();
146 
147 	s = authresp();
148 	if(s == nil)
149 		return "client cancelled authentication";
150 
151 	t = strchr(s, ' ');
152 	if(t == nil)
153 		bye("bad auth response");
154 	*t++ = '\0';
155 	strncpy(username, s, UserNameLen);
156 	username[UserNameLen-1] = '\0';
157 
158 	cs->user = username;
159 	cs->resp = t;
160 	cs->nresp = strlen(t);
161 	if((ai = auth_response(cs)) == nil)
162 		return "login failed";
163 	auth_freechal(cs);
164 	setupuser(ai);
165 	return nil;
166 }
167 
168 AuthInfo*
passLogin(char * user,char * secret)169 passLogin(char *user, char *secret)
170 {
171 	AuthInfo *ai;
172 	Chalstate *cs;
173 	uchar digest[MD5dlen];
174 	char response[2*MD5dlen+1];
175 	int i;
176 
177 	if((cs = auth_challenge("proto=cram role=server")) == nil)
178 		return nil;
179 
180 	hmac_md5((uchar*)cs->chal, strlen(cs->chal),
181 		(uchar*)secret, strlen(secret), digest,
182 		nil);
183 	for(i = 0; i < MD5dlen; i++)
184 		snprint(response + 2*i, sizeof(response) - 2*i, "%2.2ux", digest[i]);
185 
186 	cs->user = user;
187 	cs->resp = response;
188 	cs->nresp = strlen(response);
189 	ai = auth_response(cs);
190 	auth_freechal(cs);
191 	return ai;
192 }
193