xref: /plan9/sys/src/cmd/vnc/auth.c (revision 5e4924093ecb86f7174bf23023955abc83fb6962)
1 #include "vnc.h"
2 #include <libsec.h>
3 #include <auth.h>
4 
5 char *serveraddr;
6 
7 /*
8  * Encrypt n bytes using the password
9  * as key, padded with zeros to 8 bytes.
10  */
11 enum
12 {
13 	VerLen	= 12
14 };
15 
16 static char version[VerLen+1] = "RFB 003.003\n";
17 
18 static uchar tab[256];
19 
20 /* VNC reverses the bits of each byte before using as a des key */
21 static void
mktab(void)22 mktab(void)
23 {
24 	int i, j, k;
25 	static int once;
26 
27 	if(once)
28 		return;
29 	once = 1;
30 
31 	for(i=0; i<256; i++){
32 		j=i;
33 		tab[i] = 0;
34 		for(k=0; k<8; k++){
35 			tab[i] = (tab[i]<<1) | (j&1);
36 			j >>= 1;
37 		}
38 	}
39 }
40 
41 static void
vncencrypt(uchar * buf,int n,char * pw)42 vncencrypt(uchar *buf, int n, char *pw)
43 {
44 	uchar *p;
45 	uchar key[9];
46 	DESstate s;
47 
48 	mktab();
49 	memset(key, 0, sizeof key);
50 	strncpy((char*)key, pw, 8);
51 	for(p=key; *p; p++)
52 		*p = tab[*p];
53 
54 	setupDESstate(&s, key, nil);
55 	desECBencrypt(buf, n, &s);
56 }
57 
58 static int
readln(char * prompt,char * line,int len)59 readln(char *prompt, char *line, int len)
60 {
61 	char *p;
62 	int fd, ctl, n, nr;
63 
64 	fd = open("/dev/cons", ORDWR);
65 	if(fd < 0)
66 		sysfatal("couldn't open cons");
67 	ctl = open("/dev/consctl", OWRITE);
68 	if(ctl < 0)
69 		sysfatal("couldn't open consctl");
70 	write(ctl, "rawon", 5);
71 	fprint(fd, "%s", prompt);
72 	nr = 0;
73 	p = line;
74 	for(;;){
75 		n = read(fd, p, 1);
76 		if(n < 0){
77 			close(fd);
78 			close(ctl);
79 			return -1;
80 		}
81 		if(n == 0 || *p == '\n' || *p == '\r'){
82 			*p = '\0';
83 			write(fd, "\n", 1);
84 			close(fd);
85 			close(ctl);
86 			return nr;
87 		}
88 		if(*p == '\b'){
89 			if(nr > 0){
90 				nr--;
91 				p--;
92 			}
93 		}else if(*p == 21){		/* cntrl-u */
94 			fprint(fd, "\n%s", prompt);
95 			nr = 0;
96 			p = line;
97 		}else{
98 			nr++;
99 			p++;
100 		}
101 		if(nr == len){
102 			fprint(fd, "line too long; try again\n%s", prompt);
103 			nr = 0;
104 			p = line;
105 		}
106 	}
107 }
108 
109 int
vncsrvhandshake(Vnc * v)110 vncsrvhandshake(Vnc *v)
111 {
112 	char msg[VerLen+1];
113 
114 	strecpy(msg, msg+sizeof msg, version);
115 	if(verbose)
116 		fprint(2, "server version: %s", msg);
117 	vncwrbytes(v, msg, VerLen);
118 	vncflush(v);
119 
120 	vncrdbytes(v, msg, VerLen);
121 	if(verbose)
122 		fprint(2, "client version: %s", msg);
123 	return 0;
124 }
125 
126 int
vnchandshake(Vnc * v)127 vnchandshake(Vnc *v)
128 {
129 	char msg[VerLen+1];
130 
131 	msg[VerLen] = 0;
132 	vncrdbytes(v, msg, VerLen);
133 	if(strncmp(msg, "RFB ", 4) != 0){
134 		werrstr("bad rfb version \"%s\"", msg);
135 		return -1;
136 	}
137 	if(verbose)
138 		fprint(2, "server version: %s", msg);
139 	strcpy(msg, version);
140 	vncwrbytes(v, msg, VerLen);
141 	vncflush(v);
142 	return 0;
143 }
144 
145 int
vncauth(Vnc * v,char * keypattern)146 vncauth(Vnc *v, char *keypattern)
147 {
148 	char pw[128], *reason;
149 	uchar chal[VncChalLen];
150 	ulong auth;
151 	char *p, *server;
152 
153 	if(keypattern == nil)
154 		keypattern = "";
155 	auth = vncrdlong(v);
156 	switch(auth){
157 	default:
158 		werrstr("unknown auth type 0x%lux", auth);
159 		if(verbose)
160 			fprint(2, "unknown auth type 0x%lux", auth);
161 		return -1;
162 
163 	case AFailed:
164 		reason = vncrdstring(v);
165 		werrstr("%s", reason);
166 		if(verbose)
167 			fprint(2, "auth failed: %s\n", reason);
168 		return -1;
169 
170 	case ANoAuth:
171 		if(verbose)
172 			fprint(2, "no auth needed");
173 		break;
174 
175 	case AVncAuth:
176 		vncrdbytes(v, chal, VncChalLen);
177 		server = strdup(serveraddr);
178 		p = strrchr(server, ':');
179 		if(p)
180 			*p = 0;
181 		if(auth_respond(chal, VncChalLen, nil, 0, chal, VncChalLen, auth_getkey,
182 			"proto=vnc role=client server=%s %s", server, keypattern) != VncChalLen){
183 			/* BUG This is for drawterm users who don't start their own factotums */
184 			readln("password: ", pw, sizeof(pw));
185 			vncencrypt(chal, VncChalLen, pw);
186 			memset(pw, 0, sizeof pw);
187 		}
188 		free(server);
189 		vncwrbytes(v, chal, VncChalLen);
190 		vncflush(v);
191 
192 		auth = vncrdlong(v);
193 		switch(auth){
194 		default:
195 			werrstr("unknown server response 0x%lux", auth);
196 			return -1;
197 		case VncAuthFailed:
198 			werrstr("server says authentication failed");
199 			return -1;
200 		case VncAuthTooMany:
201 			werrstr("server says too many tries");
202 			return -1;
203 		case VncAuthOK:
204 			break;
205 		}
206 		break;
207 	}
208 	return 0;
209 }
210 
211 int
vncsrvauth(Vnc * v)212 vncsrvauth(Vnc *v)
213 {
214 	Chalstate *c;
215 	AuthInfo *ai;
216 
217 	if((c = auth_challenge("proto=vnc role=server user=%q", getuser()))==nil)
218 		sysfatal("vncchal: %r");
219 	if(c->nchal != VncChalLen)
220 		sysfatal("vncchal got %d bytes wanted %d", c->nchal, VncChalLen);
221 	vncwrlong(v, AVncAuth);
222 	vncwrbytes(v, c->chal, VncChalLen);
223 	vncflush(v);
224 
225 	vncrdbytes(v, c->chal, VncChalLen);
226 	c->resp = c->chal;
227 	c->nresp = VncChalLen;
228 	ai = auth_response(c);
229 	auth_freechal(c);
230 	if(ai == nil){
231 		fprint(2, "vnc auth failed: server factotum: %r\n");
232 		vncwrlong(v, VncAuthFailed);
233 		vncflush(v);
234 		return -1;
235 	}
236 	auth_freeAI(ai);
237 	vncwrlong(v, VncAuthOK);
238 	vncflush(v);
239 
240 	return 0;
241 }
242 
243