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 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 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 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 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 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 146 vncauth(Vnc *v) 147 { 148 char pw[128], *reason; 149 uchar chal[VncChalLen]; 150 ulong auth; 151 char *p, *server; 152 153 auth = vncrdlong(v); 154 switch(auth){ 155 default: 156 werrstr("unknown auth type 0x%lux", auth); 157 if(verbose) 158 fprint(2, "unknown auth type 0x%lux", auth); 159 return -1; 160 161 case AFailed: 162 reason = vncrdstring(v); 163 werrstr("%s", reason); 164 if(verbose) 165 fprint(2, "auth failed: %s\n", reason); 166 return -1; 167 168 case ANoAuth: 169 if(verbose) 170 fprint(2, "no auth needed"); 171 break; 172 173 case AVncAuth: 174 vncrdbytes(v, chal, VncChalLen); 175 server = strdup(serveraddr); 176 p = strrchr(server, ':'); 177 if(p) 178 *p = 0; 179 if(auth_respond(chal, VncChalLen, nil, 0, chal, VncChalLen, auth_getkey, 180 "proto=vnc role=client server=%s", server) != VncChalLen){ 181 /* BUG This is for drawterm users who don't start their own factotums */ 182 readln("password: ", pw, sizeof(pw)); 183 vncencrypt(chal, VncChalLen, pw); 184 memset(pw, 0, sizeof pw); 185 } 186 free(server); 187 vncwrbytes(v, chal, VncChalLen); 188 vncflush(v); 189 190 auth = vncrdlong(v); 191 switch(auth){ 192 default: 193 werrstr("unknown server response 0x%lux", auth); 194 return -1; 195 case VncAuthFailed: 196 werrstr("server says authentication failed"); 197 return -1; 198 case VncAuthTooMany: 199 werrstr("server says too many tries"); 200 return -1; 201 case VncAuthOK: 202 break; 203 } 204 break; 205 } 206 return 0; 207 } 208 209 int 210 vncsrvauth(Vnc *v) 211 { 212 Chalstate *c; 213 AuthInfo *ai; 214 215 if((c = auth_challenge("proto=vnc role=server user=%q", getuser()))==nil) 216 sysfatal("vncchal: %r"); 217 if(c->nchal != VncChalLen) 218 sysfatal("vncchal got %d bytes wanted %d", c->nchal, VncChalLen); 219 vncwrlong(v, AVncAuth); 220 vncwrbytes(v, c->chal, VncChalLen); 221 vncflush(v); 222 223 vncrdbytes(v, c->chal, VncChalLen); 224 c->resp = c->chal; 225 c->nresp = VncChalLen; 226 ai = auth_response(c); 227 auth_freechal(c); 228 if(ai == nil){ 229 fprint(2, "vnc auth failed: server factotum: %r\n"); 230 vncwrlong(v, VncAuthFailed); 231 vncflush(v); 232 return -1; 233 } 234 auth_freeAI(ai); 235 vncwrlong(v, VncAuthOK); 236 vncflush(v); 237 238 return 0; 239 } 240 241