xref: /plan9/sys/src/cmd/ip/imap4d/auth.c (revision 59cc4ca53493a3c6d2349fe2b7f7c40f7dce7294)
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 void
9 setupuser(void)
10 {
11 	Waitmsg w;
12 	int pid;
13 
14 	if(newns(username, 0) < 0)
15 		bye("user login failed: %r");
16 	snprint(mboxDir, 3 * NAMELEN, "/mail/box/%s", username);
17 	if(myChdir(mboxDir) < 0)
18 		bye("can't open user's mailbox");
19 
20 	switch(pid = fork()){
21 	case -1:
22 		bye("can't initialize mail system");
23 		break;
24 	case 0:
25 		execl("/bin/upas/fs", "upas/fs", "-np", nil);
26 		_exits(0);
27 		break;
28 	default:
29 		break;
30 	}
31 	if(wait(&w) != pid || w.msg[0] != '\0')
32 		bye("can't initialize mail system");
33 }
34 
35 void
36 initchal(Chalstate *ch)
37 {
38 	ch->afd = -1;
39 	ch->asfd = -1;
40 }
41 
42 void
43 closechal(Chalstate *ch)
44 {
45 	if(ch->afd >= 0)
46 		close(ch->afd);
47 	if(ch->asfd >= 0)
48 		close(ch->asfd);
49 	ch->afd = -1;
50 	ch->asfd = -1;
51 }
52 
53 static char*
54 authresp(void)
55 {
56 	char *s, *t;
57 	int n;
58 
59 	t = Brdline(&bin, '\n');
60 	n = Blinelen(&bin);
61 	if(n < 2)
62 		return nil;
63 	n--;
64 	if(t[n-1] == '\r')
65 		n--;
66 	t[n] = '\0';
67 	if(n == 0 || strcmp(t, "*") == 0)
68 		return nil;
69 
70 	s = canAlloc(&parseCan, n + 1, 0);
71 	n = dec64((uchar*)s, n, t, n);
72 	s[n] = '\0';
73 	return s;
74 }
75 
76 /*
77  * rfc 2195 cram-md5 authentication
78  */
79 char*
80 cramauth(void)
81 {
82 	Cramchalstate acs;
83 	char *s, *t;
84 	int n;
85 
86 	if(cramchal(&acs) < 0)
87 		return "couldn't get cram challenge";
88 
89 	n = strlen(acs.chal);
90 	s = canAlloc(&parseCan, n * 2, 0);
91 	n = enc64(s, n * 2, (uchar*)acs.chal, n);
92 	Bprint(&bout, "+ ");
93 	Bwrite(&bout, s, n);
94 	Bprint(&bout, "\r\n");
95 	if(Bflush(&bout) < 0)
96 		writeErr();
97 
98 	s = authresp();
99 	if(s == nil)
100 		return "client cancelled authentication";
101 
102 	t = strchr(s, ' ');
103 	if(t == nil)
104 		bye("bad auth response");
105 	*t++ = '\0';
106 	strncpy(username, s, NAMELEN);
107 	username[NAMELEN-1] = '\0';
108 
109 	if(cramreply(&acs, username, t) < 0)
110 		return "login failed";
111 
112 	setupuser();
113 
114 	return nil;
115 }
116 
117 static char*
118 cramLogin(char *user, char *secret)
119 {
120 	Cramchalstate acs;
121 	uchar digest[MD5dlen];
122 	char response[2*MD5dlen+1];
123 	int i;
124 
125 	if(cramchal(&acs) < 0)
126 		return "couldn't get cram challenge";
127 
128 	hmac_md5((uchar*)acs.chal, strlen(acs.chal),
129 		(uchar*)secret, strlen(secret), digest,
130 		nil);
131 	for(i = 0; i < MD5dlen; i++)
132 		snprint(response + 2*i, sizeof(response) - 2*i, "%2.2ux", digest[i]);
133 
134 	if(cramreply(&acs, user, response) < 0)
135 		return "login failed";
136 
137 	return nil;
138 }
139 
140 int
141 passCheck(char *user, char *pass)
142 {
143 	return cramLogin(user, pass) == nil;
144 }
145 
146 
147 #define USER		"VXNlcg=="
148 #define PASSWORD	"UGFzc3dvcmQ="
149 
150 char*
151 loginauth(void)
152 {
153 	Chalstate ch;
154 	char *s, *u;
155 
156 	Bprint(&bout, "+ %s\r\n", USER);
157 	if(Bflush(&bout) < 0)
158 		writeErr();
159 
160 	u = authresp();
161 	if(u == nil || getchal(&ch, u) < 0)
162 		return "login failed";
163 	Bprint(&bout, "* ok [ALERT] encrypt challenge, %s, as a password\r\n", ch.chal);
164 	Bprint(&bout, "+ %s\r\n", PASSWORD);
165 	if(Bflush(&bout) < 0)
166 		writeErr();
167 
168 	s = authresp();
169 	if(s == nil || chalreply(&ch, s) < 0)
170 		return "login failed";
171 
172 	strncpy(username, u, NAMELEN);
173 	username[NAMELEN-1] = '\0';
174 
175 	setupuser();
176 	return nil;
177 }
178