]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/vnc/auth.c
fix utf and rune handling in preparation for 32bit runes
[plan9front.git] / sys / src / cmd / vnc / auth.c
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