]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/vnc/auth.c
vncv: pick an auth type that we support
[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 enum
8 {
9         VerLen  = 12
10 };
11
12 static char version33[VerLen+1] = "RFB 003.003\n";
13 static char version38[VerLen+1] = "RFB 003.008\n";
14 static int srvversion;
15
16 int
17 vncsrvhandshake(Vnc *v)
18 {
19         char msg[VerLen+1];
20
21         strecpy(msg, msg+sizeof msg, version33);
22         if(verbose)
23                 fprint(2, "server version: %s\n", msg);
24         vncwrbytes(v, msg, VerLen);
25         vncflush(v);
26
27         vncrdbytes(v, msg, VerLen);
28         if(verbose)
29                 fprint(2, "client version: %s\n", msg);
30         return 0;
31 }
32
33 int
34 vnchandshake(Vnc *v)
35 {
36         char msg[VerLen+1];
37
38         msg[VerLen] = 0;
39         vncrdbytes(v, msg, VerLen);
40         if(strncmp(msg, "RFB 003.", 8) != 0 ||
41            strncmp(msg, "RFB 003.007\n", VerLen) == 0){
42                 werrstr("bad rfb version \"%s\"", msg);
43                 return -1;
44         }
45         if(strncmp(msg, "RFB 003.008\n", VerLen) == 0)
46                 srvversion = 38;
47         else
48                 srvversion = 33;
49
50         if(verbose)
51                 fprint(2, "server version: %s\n", msg);
52         strcpy(msg, version38);
53         vncwrbytes(v, msg, VerLen);
54         vncflush(v);
55         return 0;
56 }
57
58 ulong
59 sectype38(Vnc *v)
60 {
61         ulong auth, type;
62         int i, ntypes;
63
64         ntypes = vncrdchar(v);
65         if(ntypes == 0){
66                 werrstr("no security types from server");
67                 return AFailed;
68         }
69
70         /* choose the "most secure" security type */
71         auth = AFailed;
72         for(i = 0; i < ntypes; i++){
73                 type = vncrdchar(v);
74                 if(verbose){
75                         fprint(2, "auth type %s\n",
76                                 type == AFailed ? "Invalid" :
77                                 type == ANoAuth ? "None" :
78                                 type == AVncAuth ? "VNC" : "Unknown");
79                 }
80                 if(type > auth && type <= AVncAuth)
81                         auth = type;
82         }
83         return auth;
84 }
85
86 int
87 vncauth(Vnc *v, char *keypattern)
88 {
89         char *reason;
90         uchar chal[VncChalLen];
91         ulong auth;
92
93         if(keypattern == nil)
94                 keypattern = "";
95
96         auth = srvversion == 38 ? sectype38(v) : vncrdlong(v);
97
98         switch(auth){
99         default:
100                 werrstr("unknown auth type 0x%lux", auth);
101                 if(verbose)
102                         fprint(2, "unknown auth type 0x%lux\n", auth);
103                 return -1;
104
105         case AFailed:
106         failed:
107                 reason = vncrdstring(v);
108                 werrstr("%s", reason);
109                 if(verbose)
110                         fprint(2, "auth failed: %s\n", reason);
111                 return -1;
112
113         case ANoAuth:
114                 if(srvversion == 38){
115                         vncwrchar(v, auth);
116                         vncflush(v);
117                 }
118                 if(verbose)
119                         fprint(2, "no auth needed\n");
120                 break;
121
122         case AVncAuth:
123                 if(srvversion == 38){
124                         vncwrchar(v, auth);
125                         vncflush(v);
126                 }
127
128                 vncrdbytes(v, chal, VncChalLen);
129                 if(auth_respond(chal, VncChalLen, nil, 0, chal, VncChalLen, auth_getkey,
130                         "proto=vnc role=client server=%s %s", serveraddr, keypattern) != VncChalLen){
131                         return -1;
132                 }
133                 vncwrbytes(v, chal, VncChalLen);
134                 vncflush(v);
135                 break;
136         }
137
138         /* in version 3.8 the auth status is always sent, in 3.3 only in AVncAuth */
139         if(srvversion == 38 || auth == AVncAuth){
140                 auth = vncrdlong(v); /* auth status */
141                 switch(auth){
142                 default:
143                         werrstr("unknown server response 0x%lux", auth);
144                         return -1;
145                 case VncAuthFailed:
146                         if (srvversion == 38)
147                                 goto failed;
148
149                         werrstr("server says authentication failed");
150                         return -1;
151                 case VncAuthTooMany:
152                         werrstr("server says too many tries");
153                         return -1;
154                 case VncAuthOK:
155                         break;
156                 }
157         }
158         return 0;
159 }
160
161 int
162 vncsrvauth(Vnc *v)
163 {
164         Chalstate *c;
165         AuthInfo *ai;
166
167         if((c = auth_challenge("proto=vnc role=server user=%q", getuser()))==nil)
168                 sysfatal("vncchal: %r");
169         if(c->nchal != VncChalLen)
170                 sysfatal("vncchal got %d bytes wanted %d", c->nchal, VncChalLen);
171         vncwrlong(v, AVncAuth);
172         vncwrbytes(v, c->chal, VncChalLen);
173         vncflush(v);
174
175         vncrdbytes(v, c->chal, VncChalLen);
176         c->resp = c->chal;
177         c->nresp = VncChalLen;
178         ai = auth_response(c);
179         auth_freechal(c);
180         if(ai == nil){
181                 fprint(2, "vnc auth failed: server factotum: %r\n");
182                 vncwrlong(v, VncAuthFailed);
183                 vncflush(v);
184                 return -1;
185         }
186         auth_freeAI(ai);
187         vncwrlong(v, VncAuthOK);
188         vncflush(v);
189
190         return 0;
191 }
192