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, 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 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