19a747e4fSDavid du Colombier #include "vnc.h"
29a747e4fSDavid du Colombier #include <libsec.h>
39a747e4fSDavid du Colombier #include <auth.h>
49a747e4fSDavid du Colombier
5b7b24591SDavid du Colombier char *serveraddr;
6b7b24591SDavid du Colombier
79a747e4fSDavid du Colombier /*
89a747e4fSDavid du Colombier * Encrypt n bytes using the password
99a747e4fSDavid du Colombier * as key, padded with zeros to 8 bytes.
109a747e4fSDavid du Colombier */
119a747e4fSDavid du Colombier enum
129a747e4fSDavid du Colombier {
139a747e4fSDavid du Colombier VerLen = 12
149a747e4fSDavid du Colombier };
159a747e4fSDavid du Colombier
169a747e4fSDavid du Colombier static char version[VerLen+1] = "RFB 003.003\n";
179a747e4fSDavid du Colombier
189a747e4fSDavid du Colombier static uchar tab[256];
199a747e4fSDavid du Colombier
209a747e4fSDavid du Colombier /* VNC reverses the bits of each byte before using as a des key */
219a747e4fSDavid du Colombier static void
mktab(void)229a747e4fSDavid du Colombier mktab(void)
239a747e4fSDavid du Colombier {
249a747e4fSDavid du Colombier int i, j, k;
259a747e4fSDavid du Colombier static int once;
269a747e4fSDavid du Colombier
279a747e4fSDavid du Colombier if(once)
289a747e4fSDavid du Colombier return;
299a747e4fSDavid du Colombier once = 1;
309a747e4fSDavid du Colombier
319a747e4fSDavid du Colombier for(i=0; i<256; i++){
329a747e4fSDavid du Colombier j=i;
339a747e4fSDavid du Colombier tab[i] = 0;
349a747e4fSDavid du Colombier for(k=0; k<8; k++){
359a747e4fSDavid du Colombier tab[i] = (tab[i]<<1) | (j&1);
369a747e4fSDavid du Colombier j >>= 1;
379a747e4fSDavid du Colombier }
389a747e4fSDavid du Colombier }
399a747e4fSDavid du Colombier }
409a747e4fSDavid du Colombier
419a747e4fSDavid du Colombier static void
vncencrypt(uchar * buf,int n,char * pw)429a747e4fSDavid du Colombier vncencrypt(uchar *buf, int n, char *pw)
439a747e4fSDavid du Colombier {
449a747e4fSDavid du Colombier uchar *p;
459a747e4fSDavid du Colombier uchar key[9];
469a747e4fSDavid du Colombier DESstate s;
479a747e4fSDavid du Colombier
489a747e4fSDavid du Colombier mktab();
499a747e4fSDavid du Colombier memset(key, 0, sizeof key);
509a747e4fSDavid du Colombier strncpy((char*)key, pw, 8);
519a747e4fSDavid du Colombier for(p=key; *p; p++)
529a747e4fSDavid du Colombier *p = tab[*p];
539a747e4fSDavid du Colombier
549a747e4fSDavid du Colombier setupDESstate(&s, key, nil);
559a747e4fSDavid du Colombier desECBencrypt(buf, n, &s);
569a747e4fSDavid du Colombier }
579a747e4fSDavid du Colombier
589a747e4fSDavid du Colombier static int
readln(char * prompt,char * line,int len)599a747e4fSDavid du Colombier readln(char *prompt, char *line, int len)
609a747e4fSDavid du Colombier {
619a747e4fSDavid du Colombier char *p;
629a747e4fSDavid du Colombier int fd, ctl, n, nr;
639a747e4fSDavid du Colombier
649a747e4fSDavid du Colombier fd = open("/dev/cons", ORDWR);
659a747e4fSDavid du Colombier if(fd < 0)
669a747e4fSDavid du Colombier sysfatal("couldn't open cons");
679a747e4fSDavid du Colombier ctl = open("/dev/consctl", OWRITE);
689a747e4fSDavid du Colombier if(ctl < 0)
699a747e4fSDavid du Colombier sysfatal("couldn't open consctl");
709a747e4fSDavid du Colombier write(ctl, "rawon", 5);
719a747e4fSDavid du Colombier fprint(fd, "%s", prompt);
729a747e4fSDavid du Colombier nr = 0;
739a747e4fSDavid du Colombier p = line;
749a747e4fSDavid du Colombier for(;;){
759a747e4fSDavid du Colombier n = read(fd, p, 1);
769a747e4fSDavid du Colombier if(n < 0){
779a747e4fSDavid du Colombier close(fd);
789a747e4fSDavid du Colombier close(ctl);
799a747e4fSDavid du Colombier return -1;
809a747e4fSDavid du Colombier }
819a747e4fSDavid du Colombier if(n == 0 || *p == '\n' || *p == '\r'){
829a747e4fSDavid du Colombier *p = '\0';
839a747e4fSDavid du Colombier write(fd, "\n", 1);
849a747e4fSDavid du Colombier close(fd);
859a747e4fSDavid du Colombier close(ctl);
869a747e4fSDavid du Colombier return nr;
879a747e4fSDavid du Colombier }
889a747e4fSDavid du Colombier if(*p == '\b'){
899a747e4fSDavid du Colombier if(nr > 0){
909a747e4fSDavid du Colombier nr--;
919a747e4fSDavid du Colombier p--;
929a747e4fSDavid du Colombier }
939a747e4fSDavid du Colombier }else if(*p == 21){ /* cntrl-u */
949a747e4fSDavid du Colombier fprint(fd, "\n%s", prompt);
959a747e4fSDavid du Colombier nr = 0;
969a747e4fSDavid du Colombier p = line;
979a747e4fSDavid du Colombier }else{
989a747e4fSDavid du Colombier nr++;
999a747e4fSDavid du Colombier p++;
1009a747e4fSDavid du Colombier }
1019a747e4fSDavid du Colombier if(nr == len){
1029a747e4fSDavid du Colombier fprint(fd, "line too long; try again\n%s", prompt);
1039a747e4fSDavid du Colombier nr = 0;
1049a747e4fSDavid du Colombier p = line;
1059a747e4fSDavid du Colombier }
1069a747e4fSDavid du Colombier }
1079a747e4fSDavid du Colombier }
1089a747e4fSDavid du Colombier
1099a747e4fSDavid du Colombier int
vncsrvhandshake(Vnc * v)110f8e525acSDavid du Colombier vncsrvhandshake(Vnc *v)
1119a747e4fSDavid du Colombier {
1129a747e4fSDavid du Colombier char msg[VerLen+1];
1139a747e4fSDavid du Colombier
114f8e525acSDavid du Colombier strecpy(msg, msg+sizeof msg, version);
1159a747e4fSDavid du Colombier if(verbose)
116f8e525acSDavid du Colombier fprint(2, "server version: %s", msg);
1179a747e4fSDavid du Colombier vncwrbytes(v, msg, VerLen);
1189a747e4fSDavid du Colombier vncflush(v);
1199a747e4fSDavid du Colombier
1209a747e4fSDavid du Colombier vncrdbytes(v, msg, VerLen);
1219a747e4fSDavid du Colombier if(verbose)
1229a747e4fSDavid du Colombier fprint(2, "client version: %s", msg);
1239a747e4fSDavid du Colombier return 0;
1249a747e4fSDavid du Colombier }
1259a747e4fSDavid du Colombier
1269a747e4fSDavid du Colombier int
vnchandshake(Vnc * v)1279a747e4fSDavid du Colombier vnchandshake(Vnc *v)
1289a747e4fSDavid du Colombier {
1299a747e4fSDavid du Colombier char msg[VerLen+1];
1309a747e4fSDavid du Colombier
131f8e525acSDavid du Colombier msg[VerLen] = 0;
1329a747e4fSDavid du Colombier vncrdbytes(v, msg, VerLen);
133d9306527SDavid du Colombier if(strncmp(msg, "RFB ", 4) != 0){
1349a747e4fSDavid du Colombier werrstr("bad rfb version \"%s\"", msg);
1359a747e4fSDavid du Colombier return -1;
1369a747e4fSDavid du Colombier }
1379a747e4fSDavid du Colombier if(verbose)
138f8e525acSDavid du Colombier fprint(2, "server version: %s", msg);
1399a747e4fSDavid du Colombier strcpy(msg, version);
1409a747e4fSDavid du Colombier vncwrbytes(v, msg, VerLen);
1419a747e4fSDavid du Colombier vncflush(v);
1429a747e4fSDavid du Colombier return 0;
1439a747e4fSDavid du Colombier }
1449a747e4fSDavid du Colombier
1459a747e4fSDavid du Colombier int
vncauth(Vnc * v,char * keypattern)146*5e492409SDavid du Colombier vncauth(Vnc *v, char *keypattern)
1479a747e4fSDavid du Colombier {
1489a747e4fSDavid du Colombier char pw[128], *reason;
1499a747e4fSDavid du Colombier uchar chal[VncChalLen];
1509a747e4fSDavid du Colombier ulong auth;
151d9306527SDavid du Colombier char *p, *server;
1529a747e4fSDavid du Colombier
153*5e492409SDavid du Colombier if(keypattern == nil)
154*5e492409SDavid du Colombier keypattern = "";
1559a747e4fSDavid du Colombier auth = vncrdlong(v);
1569a747e4fSDavid du Colombier switch(auth){
1579a747e4fSDavid du Colombier default:
1589a747e4fSDavid du Colombier werrstr("unknown auth type 0x%lux", auth);
1599a747e4fSDavid du Colombier if(verbose)
1609a747e4fSDavid du Colombier fprint(2, "unknown auth type 0x%lux", auth);
1619a747e4fSDavid du Colombier return -1;
1629a747e4fSDavid du Colombier
1639a747e4fSDavid du Colombier case AFailed:
1649a747e4fSDavid du Colombier reason = vncrdstring(v);
1659a747e4fSDavid du Colombier werrstr("%s", reason);
1669a747e4fSDavid du Colombier if(verbose)
1679a747e4fSDavid du Colombier fprint(2, "auth failed: %s\n", reason);
1689a747e4fSDavid du Colombier return -1;
1699a747e4fSDavid du Colombier
1709a747e4fSDavid du Colombier case ANoAuth:
1719a747e4fSDavid du Colombier if(verbose)
1729a747e4fSDavid du Colombier fprint(2, "no auth needed");
1739a747e4fSDavid du Colombier break;
1749a747e4fSDavid du Colombier
1759a747e4fSDavid du Colombier case AVncAuth:
1769a747e4fSDavid du Colombier vncrdbytes(v, chal, VncChalLen);
177d9306527SDavid du Colombier server = strdup(serveraddr);
178d9306527SDavid du Colombier p = strrchr(server, ':');
179d9306527SDavid du Colombier if(p)
180d9306527SDavid du Colombier *p = 0;
181b7b24591SDavid du Colombier if(auth_respond(chal, VncChalLen, nil, 0, chal, VncChalLen, auth_getkey,
182*5e492409SDavid du Colombier "proto=vnc role=client server=%s %s", server, keypattern) != VncChalLen){
183f8e525acSDavid du Colombier /* BUG This is for drawterm users who don't start their own factotums */
1849a747e4fSDavid du Colombier readln("password: ", pw, sizeof(pw));
1859a747e4fSDavid du Colombier vncencrypt(chal, VncChalLen, pw);
1869a747e4fSDavid du Colombier memset(pw, 0, sizeof pw);
187b7b24591SDavid du Colombier }
188d9306527SDavid du Colombier free(server);
1899a747e4fSDavid du Colombier vncwrbytes(v, chal, VncChalLen);
1909a747e4fSDavid du Colombier vncflush(v);
1919a747e4fSDavid du Colombier
1929a747e4fSDavid du Colombier auth = vncrdlong(v);
1939a747e4fSDavid du Colombier switch(auth){
1949a747e4fSDavid du Colombier default:
195f8e525acSDavid du Colombier werrstr("unknown server response 0x%lux", auth);
1969a747e4fSDavid du Colombier return -1;
1979a747e4fSDavid du Colombier case VncAuthFailed:
198f8e525acSDavid du Colombier werrstr("server says authentication failed");
1999a747e4fSDavid du Colombier return -1;
2009a747e4fSDavid du Colombier case VncAuthTooMany:
201f8e525acSDavid du Colombier werrstr("server says too many tries");
2029a747e4fSDavid du Colombier return -1;
2039a747e4fSDavid du Colombier case VncAuthOK:
2049a747e4fSDavid du Colombier break;
2059a747e4fSDavid du Colombier }
2069a747e4fSDavid du Colombier break;
2079a747e4fSDavid du Colombier }
2089a747e4fSDavid du Colombier return 0;
2099a747e4fSDavid du Colombier }
2109a747e4fSDavid du Colombier
2119a747e4fSDavid du Colombier int
vncsrvauth(Vnc * v)212f8e525acSDavid du Colombier vncsrvauth(Vnc *v)
2139a747e4fSDavid du Colombier {
2149a747e4fSDavid du Colombier Chalstate *c;
215f8e525acSDavid du Colombier AuthInfo *ai;
2169a747e4fSDavid du Colombier
217f8e525acSDavid du Colombier if((c = auth_challenge("proto=vnc role=server user=%q", getuser()))==nil)
218f8e525acSDavid du Colombier sysfatal("vncchal: %r");
219f8e525acSDavid du Colombier if(c->nchal != VncChalLen)
220f8e525acSDavid du Colombier sysfatal("vncchal got %d bytes wanted %d", c->nchal, VncChalLen);
2219a747e4fSDavid du Colombier vncwrlong(v, AVncAuth);
2229a747e4fSDavid du Colombier vncwrbytes(v, c->chal, VncChalLen);
2239a747e4fSDavid du Colombier vncflush(v);
2249a747e4fSDavid du Colombier
2259a747e4fSDavid du Colombier vncrdbytes(v, c->chal, VncChalLen);
2269a747e4fSDavid du Colombier c->resp = c->chal;
2279a747e4fSDavid du Colombier c->nresp = VncChalLen;
2289a747e4fSDavid du Colombier ai = auth_response(c);
2299a747e4fSDavid du Colombier auth_freechal(c);
2309a747e4fSDavid du Colombier if(ai == nil){
231f8e525acSDavid du Colombier fprint(2, "vnc auth failed: server factotum: %r\n");
232f8e525acSDavid du Colombier vncwrlong(v, VncAuthFailed);
233f8e525acSDavid du Colombier vncflush(v);
2349a747e4fSDavid du Colombier return -1;
2359a747e4fSDavid du Colombier }
2369a747e4fSDavid du Colombier auth_freeAI(ai);
2379a747e4fSDavid du Colombier vncwrlong(v, VncAuthOK);
2389a747e4fSDavid du Colombier vncflush(v);
2399a747e4fSDavid du Colombier
2409a747e4fSDavid du Colombier return 0;
2419a747e4fSDavid du Colombier }
2429a747e4fSDavid du Colombier
243