1 typedef struct Opt Opt;
2
3 int debug;
4 #define DPRINT if(debug)fprint
5
6 enum
7 {
8 /* control characters */
9 Se= 240, /* end subnegotiation */
10 NOP= 241,
11 Mark= 242, /* data mark */
12 Break= 243,
13 Interrupt= 244,
14 Abort= 245, /* TENEX ^O */
15 AreYouThere= 246,
16 Erasechar= 247, /* erase last character */
17 Eraseline= 248, /* erase line */
18 GoAhead= 249, /* half duplex clear to send */
19 Sb= 250, /* start subnegotiation */
20 Will= 251,
21 Wont= 252,
22 Do= 253,
23 Dont= 254,
24 Iac= 255,
25
26 /* options */
27 Binary= 0,
28 Echo,
29 SGA,
30 Stat,
31 Timing,
32 Det,
33 Term,
34 EOR,
35 Uid,
36 Outmark,
37 Ttyloc,
38 M3270,
39 Padx3,
40 Window,
41 Speed,
42 Flow,
43 Line,
44 Xloc,
45 Extend,
46 };
47
48 struct Opt
49 {
50 char *name;
51 int code;
52 char noway;
53 int (*change)(Biobuf*, int); /* routine for status change */
54 int (*sub)(Biobuf*, uchar*, int n); /* routine for subnegotiation */
55 char remote; /* remote value */
56 char local; /* local value */
57 };
58
59 Opt opt[] =
60 {
61 [Binary] { "binary", 0, 0, },
62 [Echo] { "echo", 1, 0, },
63 [SGA] { "suppress Go Ahead", 3, 0, },
64 [Stat] { "status", 5, 1, },
65 [Timing] { "timing", 6, 1, },
66 [Det] { "det", 20, 1, },
67 [Term] { "terminal", 24, 0, },
68 [EOR] { "end of record", 25, 1, },
69 [Uid] { "uid", 26, 1, },
70 [Outmark] { "outmark", 27, 1, },
71 [Ttyloc] { "ttyloc", 28, 1, },
72 [M3270] { "3270 mode", 29, 1, },
73 [Padx3] { "pad x.3", 30, 1, },
74 [Window] { "window size", 31, 1, },
75 [Speed] { "speed", 32, 1, },
76 [Flow] { "flow control", 33, 1, },
77 [Line] { "line mode", 34, 1, },
78 [Xloc] { "X display loc", 35, 0, },
79 [Extend] { "Extended", 255, 1, },
80 };
81
82 int control(Biobuf*, int);
83 Opt* findopt(int);
84 int will(Biobuf*);
85 int wont(Biobuf*);
86 int doit(Biobuf*);
87 int dont(Biobuf*);
88 int sub(Biobuf*);
89 int send2(int, int, int);
90 int send3(int, int, int, int);
91 int sendnote(int, char*);
92 void fatal(char*, void*, void*);
93 char* syserr(void);
94 int wasintr(void);
95 long iread(int, void*, int);
96 long iwrite(int, void*, int);
97 void binit(Biobuf*, int);
98 void berase(Biobuf*);
99 void bkill(Biobuf*);
100
101 /*
102 * parse telnet control messages
103 */
104 int
control(Biobuf * bp,int c)105 control(Biobuf *bp, int c)
106 {
107 if(c < 0)
108 return -1;
109 switch(c){
110 case AreYouThere:
111 fprint(Bfildes(bp), "Plan 9 telnet, version 1\r\n");
112 break;
113 case Sb:
114 return sub(bp);
115 case Will:
116 return will(bp);
117 case Wont:
118 return wont(bp);
119 case Do:
120 return doit(bp);
121 case Dont:
122 return dont(bp);
123 case Se:
124 fprint(2, "telnet: SE without an SB\n");
125 break;
126 default:
127 break;
128 }
129 return 0;
130 }
131
132 Opt*
findopt(int c)133 findopt(int c)
134 {
135 Opt *o;
136
137 for(o = opt; o <= &opt[Extend]; o++)
138 if(o->code == c)
139 return o;
140 return 0;
141 }
142
143 int
will(Biobuf * bp)144 will(Biobuf *bp)
145 {
146 Opt *o;
147 int c;
148 int rv = 0;
149
150 c = Bgetc(bp);
151 if(c < 0)
152 return -1;
153 DPRINT(2, "will %d\n", c);
154 o = findopt(c);
155 if(o == 0){
156 send3(Bfildes(bp), Iac, Dont, c);
157 return 0;
158 }
159 if(o->noway)
160 send3(Bfildes(bp), Iac, Dont, c);
161 else if(o->remote == 0)
162 rv |= send3(Bfildes(bp), Iac, Do, c);
163 if(o->remote == 0){
164 if(o->change)
165 rv |= (*o->change)(bp, Will);
166 }
167 o->remote = 1;
168 return rv;
169 }
170
171 int
wont(Biobuf * bp)172 wont(Biobuf *bp)
173 {
174 Opt *o;
175 int c;
176 int rv = 0;
177
178 c = Bgetc(bp);
179 if(c < 0)
180 return -1;
181 DPRINT(2, "wont %d\n", c);
182 o = findopt(c);
183 if(o == 0)
184 return 0;
185 if(o->remote){
186 if(o->change)
187 rv |= (*o->change)(bp, Wont);
188 rv |= send3(Bfildes(bp), Iac, Dont, c);
189 }
190 o->remote = 0;
191 return rv;
192 }
193
194 int
doit(Biobuf * bp)195 doit(Biobuf *bp)
196 {
197 Opt *o;
198 int c;
199 int rv = 0;
200
201 c = Bgetc(bp);
202 if(c < 0)
203 return -1;
204 DPRINT(2, "do %d\n", c);
205 o = findopt(c);
206 if(o == 0 || o->noway){
207 send3(Bfildes(bp), Iac, Wont, c);
208 return 0;
209 }
210 if(o->noway)
211 return 0;
212 if(o->local == 0){
213 if(o->change)
214 rv |= (*o->change)(bp, Do);
215 rv |= send3(Bfildes(bp), Iac, Will, c);
216 }
217 o->local = 1;
218 return rv;
219 }
220
221 int
dont(Biobuf * bp)222 dont(Biobuf *bp)
223 {
224 Opt *o;
225 int c;
226 int rv = 0;
227
228 c = Bgetc(bp);
229 if(c < 0)
230 return -1;
231 DPRINT(2, "dont %d\n", c);
232 o = findopt(c);
233 if(o == 0)
234 return 0;
235 if(o->noway)
236 return 0;
237 if(o->local){
238 o->local = 0;
239 if(o->change)
240 rv |= (*o->change)(bp, Dont);
241 rv |= send3(Bfildes(bp), Iac, Wont, c);
242 }
243 o->local = 0;
244 return rv;
245 }
246
247 /* read in a subnegotiation message and pass it to a routine for that option */
248 int
sub(Biobuf * bp)249 sub(Biobuf *bp)
250 {
251 uchar subneg[128];
252 uchar *p;
253 Opt *o;
254 int c;
255
256 p = subneg;
257 for(;;){
258 c = Bgetc(bp);
259 if(c == Iac){
260 c = Bgetc(bp);
261 if(c == Se)
262 break;
263 if(p < &subneg[sizeof(subneg)])
264 *p++ = Iac;
265 }
266 if(c < 0)
267 return -1;
268 if(p < &subneg[sizeof(subneg)])
269 *p++ = c;
270 }
271 if(p == subneg)
272 return 0;
273 DPRINT(2, "sub %d %d n = %d\n", subneg[0], subneg[1], (int)(p - subneg - 1));
274 o = findopt(subneg[0]);
275 if(o == 0 || o->sub == 0)
276 return 0;
277 return (*o->sub)(bp, subneg+1, p - subneg - 1);
278 }
279
280 void
sendd(int c0,int c1)281 sendd(int c0, int c1)
282 {
283 char *t = 0;
284
285 switch(c0){
286 case Will:
287 t = "Will";
288 break;
289 case Wont:
290 t = "Wont";
291 break;
292 case Do:
293 t = "Do";
294 break;
295 case Dont:
296 t = "Dont";
297 break;
298 }
299 if(t)
300 DPRINT(2, "r %s %d\n", t, c1);
301 }
302
303 int
send2(int f,int c0,int c1)304 send2(int f, int c0, int c1)
305 {
306 uchar buf[2];
307
308 buf[0] = c0;
309 buf[1] = c1;
310 return iwrite(f, buf, 2) == 2 ? 0 : -1;
311 }
312
313 int
send3(int f,int c0,int c1,int c2)314 send3(int f, int c0, int c1, int c2)
315 {
316 uchar buf[3];
317
318 buf[0] = c0;
319 buf[1] = c1;
320 buf[2] = c2;
321 sendd(c1, c2);
322 return iwrite(f, buf, 3) == 3 ? 0 : -1;
323 }
324
325 int
sendnote(int pid,char * msg)326 sendnote(int pid, char *msg)
327 {
328 int fd;
329 char name[128];
330
331 sprint(name, "/proc/%d/note", pid);
332 fd = open(name, OWRITE);
333 if(fd < 0)
334 return -1;
335 if(write(fd, msg, strlen(msg))!=strlen(msg))
336 return -1;
337 return close(fd);
338 }
339
340 void
fatal(char * fmt,void * a0,void * a1)341 fatal(char *fmt, void *a0, void *a1)
342 {
343 char buf[128];
344
345 sprint(buf, fmt, a0, a1);
346 fprint(2, "%s: %s\n", argv0, buf);
347 exits(buf);
348 }
349
350 char*
syserr(void)351 syserr(void)
352 {
353 static char err[ERRMAX];
354
355 errstr(err, sizeof err);
356 return err;
357 }
358
359 int
wasintr(void)360 wasintr(void)
361 {
362 return strcmp(syserr(), "interrupted") == 0;
363 }
364
365 long
iread(int f,void * a,int n)366 iread(int f, void *a, int n)
367 {
368 long m;
369
370 for(;;){
371 m = read(f, a, n);
372 if(m >= 0 || !wasintr())
373 break;
374 }
375 return m;
376 }
377
378 long
iwrite(int f,void * a,int n)379 iwrite(int f, void *a, int n)
380 {
381 long m;
382
383 m = write(f, a, n);
384 if(m < 0 && wasintr())
385 return n;
386 return m;
387 }
388