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