~ubuntu-branches/ubuntu/wily/netkit-telnet-ssl/wily-proposed

« back to all changes in this revision

Viewing changes to .pc/500-implement_ssl.diff/telnetd/utility.c

  • Committer: Package Import Robot
  • Author(s): Mats Erik Andersson
  • Date: 2015-04-27 23:20:22 UTC
  • mfrom: (7.1.2 sid)
  • Revision ID: package-import@ubuntu.com-20150427232022-c2f04nl1gr4qyqom
Tags: 0.17.40+0.2-1
* Bring in package changes from experimental to unstable.
* Update to source version 0.17-40 of netkit-telnet.
  + debian/rules: Define and use the variable LDDEFS.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (c) 1989 Regents of the University of California.
 
3
 * All rights reserved.
 
4
 *
 
5
 * Redistribution and use in source and binary forms, with or without
 
6
 * modification, are permitted provided that the following conditions
 
7
 * are met:
 
8
 * 1. Redistributions of source code must retain the above copyright
 
9
 *    notice, this list of conditions and the following disclaimer.
 
10
 * 2. Redistributions in binary form must reproduce the above copyright
 
11
 *    notice, this list of conditions and the following disclaimer in the
 
12
 *    documentation and/or other materials provided with the distribution.
 
13
 * 3. All advertising materials mentioning features or use of this software
 
14
 *    must display the following acknowledgement:
 
15
 *      This product includes software developed by the University of
 
16
 *      California, Berkeley and its contributors.
 
17
 * 4. Neither the name of the University nor the names of its contributors
 
18
 *    may be used to endorse or promote products derived from this software
 
19
 *    without specific prior written permission.
 
20
 *
 
21
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 
22
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 
23
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 
24
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 
25
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 
26
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 
27
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 
28
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 
29
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 
30
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 
31
 * SUCH DAMAGE.
 
32
 */
 
33
 
 
34
/*
 
35
 * From: @(#)utility.c  5.8 (Berkeley) 3/22/91
 
36
 */
 
37
char util_rcsid[] = 
 
38
  "$Id: utility.c,v 1.11 1999/12/12 14:59:45 dholland Exp $";
 
39
 
 
40
#define PRINTOPTIONS
 
41
 
 
42
#include <stdarg.h>
 
43
#include <sys/utsname.h>
 
44
#include <sys/time.h>
 
45
 
 
46
#ifdef AUTHENTICATE
 
47
#include <libtelnet/auth.h>
 
48
#endif
 
49
 
 
50
#include "telnetd.h"
 
51
 
 
52
struct buflist {
 
53
        struct buflist *next;
 
54
        char *buf;
 
55
        size_t len;
 
56
};
 
57
 
 
58
static struct buflist head = { next: &head, buf: 0, len: 0 };
 
59
static struct buflist *tail = &head;
 
60
static size_t skip;
 
61
static int trailing;
 
62
static size_t listlen;
 
63
static int doclear;
 
64
static struct buflist *urg;
 
65
 
 
66
/*
 
67
 * ttloop
 
68
 *
 
69
 *      A small subroutine to flush the network output buffer, get some data
 
70
 * from the network, and pass it through the telnet state machine.  We
 
71
 * also flush the pty input buffer (by dropping its data) if it becomes
 
72
 * too full.
 
73
 */
 
74
 
 
75
void
 
76
ttloop(void)
 
77
{
 
78
 
 
79
    DIAG(TD_REPORT, netoprintf("td: ttloop\r\n"););
 
80
                     
 
81
    netflush();
 
82
    ncc = read(net, netibuf, sizeof(netibuf));
 
83
    if (ncc < 0) {
 
84
        syslog(LOG_INFO, "ttloop: read: %m\n");
 
85
        exit(1);
 
86
    } else if (ncc == 0) {
 
87
        syslog(LOG_INFO, "ttloop: peer died: EOF\n");
 
88
        exit(1);
 
89
    }
 
90
    DIAG(TD_REPORT, netoprintf("td: ttloop read %d chars\r\n", ncc););
 
91
    netip = netibuf;
 
92
    telrcv();                   /* state machine */
 
93
    if (ncc > 0) {
 
94
        pfrontp = pbackp = ptyobuf;
 
95
        telrcv();
 
96
    }
 
97
}  /* end of ttloop */
 
98
 
 
99
/*
 
100
 * Check a descriptor to see if out of band data exists on it.
 
101
 */
 
102
int stilloob(int s)             /* socket number */
 
103
{
 
104
    static struct timeval timeout = { 0, 0 };
 
105
    fd_set      excepts;
 
106
    int value;
 
107
 
 
108
    do {
 
109
        FD_ZERO(&excepts);
 
110
        FD_SET(s, &excepts);
 
111
        value = select(s+1, (fd_set *)0, (fd_set *)0, &excepts, &timeout);
 
112
    } while ((value == -1) && (errno == EINTR));
 
113
 
 
114
    if (value < 0) {
 
115
        fatalperror(pty, "select");
 
116
    }
 
117
    if (FD_ISSET(s, &excepts)) {
 
118
        return 1;
 
119
    } else {
 
120
        return 0;
 
121
    }
 
122
}
 
123
 
 
124
void    ptyflush(void)
 
125
{
 
126
        int n;
 
127
 
 
128
        if ((n = pfrontp - pbackp) > 0) {
 
129
                DIAG((TD_REPORT | TD_PTYDATA),
 
130
                     netoprintf("td: ptyflush %d chars\r\n", n););
 
131
                DIAG(TD_PTYDATA, printdata("pd", pbackp, n));
 
132
                n = write(pty, pbackp, n);
 
133
        }
 
134
        if (n < 0) {
 
135
                if (errno == EWOULDBLOCK || errno == EINTR)
 
136
                        return;
 
137
                cleanup(0);
 
138
        }
 
139
        pbackp += n;
 
140
        if (pbackp == pfrontp)
 
141
                pbackp = pfrontp = ptyobuf;
 
142
}
 
143
 
 
144
/*
 
145
 * nextitem()
 
146
 *
 
147
 *      Return the address of the next "item" in the TELNET data
 
148
 * stream.  This will be the address of the next character if
 
149
 * the current address is a user data character, or it will
 
150
 * be the address of the character following the TELNET command
 
151
 * if the current address is a TELNET IAC ("I Am a Command")
 
152
 * character.
 
153
 */
 
154
static
 
155
const char *
 
156
nextitem(
 
157
        const unsigned char *current, const unsigned char *end,
 
158
        const unsigned char *next, const unsigned char *nextend
 
159
) {
 
160
        if (*current++ != IAC) {
 
161
                while (current < end && *current++ != IAC)
 
162
                        ;
 
163
                goto out;
 
164
        }
 
165
 
 
166
        if (current >= end) {
 
167
                current = next;
 
168
                if (!current) {
 
169
                        return 0;
 
170
                }
 
171
                end = nextend;
 
172
                next = 0;
 
173
        }
 
174
 
 
175
        switch (*current++) {
 
176
        case DO:
 
177
        case DONT:
 
178
        case WILL:
 
179
        case WONT:
 
180
                current++;
 
181
                break;
 
182
        case SB:                /* loop forever looking for the SE */
 
183
                for (;;) {
 
184
                        int iac;
 
185
 
 
186
                        while (iac = 0, current < end) {
 
187
                                if (*current++ == IAC) {
 
188
                                        if (current >= end) {
 
189
                                                iac = 1;
 
190
                                                break;
 
191
                                        }
 
192
iac:
 
193
                                        if (*current++ == SE) {
 
194
                                                goto out;
 
195
                                        }
 
196
                                }
 
197
                        }
 
198
 
 
199
                        current = next;
 
200
                        if (!current) {
 
201
                                return 0;
 
202
                        }
 
203
                        end = nextend;
 
204
                        next = 0;
 
205
                        if (iac) {
 
206
                                goto iac;
 
207
                        }
 
208
                }
 
209
        }
 
210
 
 
211
out:
 
212
        return next ? next + (current - end) : current;
 
213
}  /* end of nextitem */
 
214
 
 
215
 
 
216
/*
 
217
 * netclear()
 
218
 *
 
219
 *      We are about to do a TELNET SYNCH operation.  Clear
 
220
 * the path to the network.
 
221
 *
 
222
 *      Things are a bit tricky since we may have sent the first
 
223
 * byte or so of a previous TELNET command into the network.
 
224
 * So, we have to scan the network buffer from the beginning
 
225
 * until we are up to where we want to be.
 
226
 *
 
227
 *      A side effect of what we do, just to keep things
 
228
 * simple, is to clear the urgent data pointer.  The principal
 
229
 * caller should be setting the urgent data pointer AFTER calling
 
230
 * us in any case.
 
231
 */
 
232
void netclear(void)
 
233
{
 
234
        doclear++;
 
235
        netflush();
 
236
        doclear--;
 
237
}  /* end of netclear */
 
238
 
 
239
static void
 
240
netwritebuf(void)
 
241
{
 
242
        struct iovec *vector;
 
243
        struct iovec *v;
 
244
        struct buflist *lp;
 
245
        ssize_t n;
 
246
        size_t len;
 
247
        int ltrailing = trailing;
 
248
 
 
249
        vector = malloc(listlen * sizeof(struct iovec));
 
250
        if (!vector) {
 
251
                return;
 
252
        }
 
253
 
 
254
        len = listlen - (doclear & ltrailing);
 
255
        v = vector;
 
256
        lp = head.next;
 
257
        while (lp != &head) {
 
258
                if (lp == urg) {
 
259
                        len = v - vector;
 
260
                        if (!len) {
 
261
                                n = send(net, lp->buf, 1, MSG_OOB);
 
262
                                if (n > 0) {
 
263
                                        urg = 0;
 
264
                                }
 
265
                                goto epi;
 
266
                        }
 
267
                        break;
 
268
                }
 
269
                v->iov_base = lp->buf;
 
270
                v->iov_len = lp->len;
 
271
                v++;
 
272
                lp = lp->next;
 
273
        }
 
274
 
 
275
        vector->iov_base = (char *)vector->iov_base + skip;
 
276
        vector->iov_len -= skip;
 
277
 
 
278
        n = writev(net, vector, len);
 
279
 
 
280
epi:
 
281
        free(vector);
 
282
 
 
283
        if (n < 0) {
 
284
                if (errno != EWOULDBLOCK && errno != EINTR)
 
285
                        cleanup(0);
 
286
                return;
 
287
        }
 
288
 
 
289
        len = n + skip;
 
290
 
 
291
        lp = head.next;
 
292
        while (lp->len <= len) {
 
293
                if (lp == tail && ltrailing) {
 
294
                        break;
 
295
                }
 
296
 
 
297
                len -= lp->len;
 
298
 
 
299
                head.next = lp->next;
 
300
                listlen--;
 
301
                free(lp->buf);
 
302
                free(lp);
 
303
 
 
304
                lp = head.next;
 
305
                if (lp == &head) {
 
306
                        tail = &head;
 
307
                        break;
 
308
                }
 
309
        }
 
310
 
 
311
        skip = len;
 
312
}
 
313
 
 
314
/*
 
315
 *  netflush
 
316
 *             Send as much data as possible to the network,
 
317
 *     handling requests for urgent data.
 
318
 */
 
319
void
 
320
netflush(void)
 
321
{
 
322
        if (fflush(netfile)) {
 
323
                /* out of memory? */
 
324
                cleanup(0);
 
325
        }
 
326
        if (listlen) {
 
327
                netwritebuf();
 
328
        }
 
329
}
 
330
 
 
331
 
 
332
/*
 
333
 * miscellaneous functions doing a variety of little jobs follow ...
 
334
 */
 
335
 
 
336
 
 
337
void
 
338
fatal(int f, const char *msg)
 
339
{
 
340
        char buf[BUFSIZ];
 
341
 
 
342
        (void) snprintf(buf, sizeof(buf), "telnetd: %s.\r\n", msg);
 
343
#if     defined(ENCRYPT)
 
344
        if (encrypt_output) {
 
345
                /*
 
346
                 * Better turn off encryption first....
 
347
                 * Hope it flushes...
 
348
                 */
 
349
                encrypt_send_end();
 
350
                netflush();
 
351
        }
 
352
#endif
 
353
        (void) write(f, buf, (int)strlen(buf));
 
354
        sleep(1);       /*XXX*/
 
355
        exit(1);
 
356
}
 
357
 
 
358
void
 
359
fatalperror(int f, const char *msg)
 
360
{
 
361
        char buf[BUFSIZ];
 
362
        snprintf(buf, sizeof(buf), "%s: %s\r\n", msg, strerror(errno));
 
363
        fatal(f, buf);
 
364
}
 
365
 
 
366
char *editedhost;
 
367
struct utsname kerninfo;
 
368
 
 
369
void
 
370
edithost(const char *pat, const char *host)
 
371
{
 
372
        char *res;
 
373
 
 
374
        uname(&kerninfo);
 
375
 
 
376
        if (!pat)
 
377
                pat = "";
 
378
 
 
379
        res = realloc(editedhost, strlen(pat) + strlen(host) + 1);
 
380
        if (!res) {
 
381
                if (editedhost) {
 
382
                        free(editedhost);
 
383
                        editedhost = 0;
 
384
                }
 
385
                fprintf(stderr, "edithost: Out of memory\n");
 
386
                return;
 
387
        }
 
388
        editedhost = res;
 
389
 
 
390
        while (*pat) {
 
391
                switch (*pat) {
 
392
 
 
393
                case '#':
 
394
                        if (*host)
 
395
                                host++;
 
396
                        break;
 
397
 
 
398
                case '@':
 
399
                        if (*host)
 
400
                                *res++ = *host++;
 
401
                        break;
 
402
 
 
403
                default:
 
404
                        *res++ = *pat;
 
405
                        break;
 
406
                }
 
407
                pat++;
 
408
        }
 
409
        if (*host)
 
410
                (void) strcpy(res, host);
 
411
        else
 
412
                *res = '\0';
 
413
}
 
414
 
 
415
static char *putlocation;
 
416
 
 
417
static 
 
418
void
 
419
putstr(const char *s)
 
420
{
 
421
    while (*s) putchr(*s++);
 
422
}
 
423
 
 
424
void putchr(int cc)
 
425
{
 
426
        *putlocation++ = cc;
 
427
}
 
428
 
 
429
static char fmtstr[] = { "%H:%M on %A, %d %B %Y" };
 
430
 
 
431
void putf(const char *cp, char *where)
 
432
{
 
433
        char *slash;
 
434
        time_t t;
 
435
        char db[100];
 
436
 
 
437
        if (where)
 
438
        putlocation = where;
 
439
 
 
440
        while (*cp) {
 
441
                if (*cp != '%') {
 
442
                        putchr(*cp++);
 
443
                        continue;
 
444
                }
 
445
                switch (*++cp) {
 
446
 
 
447
                case 't':
 
448
                        slash = strrchr(line, '/');
 
449
                        if (slash == NULL)
 
450
                                putstr(line);
 
451
                        else
 
452
                                putstr(slash+1);
 
453
                        break;
 
454
 
 
455
                case 'h':
 
456
                        if (editedhost) {
 
457
                                putstr(editedhost);
 
458
                        }
 
459
                        break;
 
460
 
 
461
                case 'd':
 
462
                        (void)time(&t);
 
463
                        (void)strftime(db, sizeof(db), fmtstr, localtime(&t));
 
464
                        putstr(db);
 
465
                        break;
 
466
 
 
467
                case '%':
 
468
                        putchr('%');
 
469
                        break;
 
470
 
 
471
                case 'D':
 
472
                        {
 
473
                                char    buff[128];
 
474
 
 
475
                                if (getdomainname(buff,sizeof(buff)) < 0
 
476
                                        || buff[0] == '\0'
 
477
                                        || strcmp(buff, "(none)") == 0)
 
478
                                        break;
 
479
                                putstr(buff);
 
480
                        }
 
481
                        break;
 
482
 
 
483
                case 'i':
 
484
                        {
 
485
                                char buff[3];
 
486
                                FILE *fp;
 
487
                                int p, c;
 
488
 
 
489
                                if ((fp = fopen(ISSUE_FILE, "r")) == NULL)
 
490
                                        break;
 
491
                                p = '\n';
 
492
                                while ((c = fgetc(fp)) != EOF) {
 
493
                                        if (p == '\n' && c == '#') {
 
494
                                                do {
 
495
                                                        c = fgetc(fp);
 
496
                                                } while (c != EOF && c != '\n');
 
497
                                                continue;
 
498
                                        } else if (c == '%') {
 
499
                                                buff[0] = c;
 
500
                                                c = fgetc(fp);
 
501
                                                if (c == EOF) break;
 
502
                                                buff[1] = c;
 
503
                                                buff[2] = '\0';
 
504
                                                putf(buff, NULL);
 
505
                                        } else {
 
506
                                                if (c == '\n') putchr('\r');
 
507
                                                putchr(c);
 
508
                                                p = c;
 
509
                                        }
 
510
                                };
 
511
                                (void) fclose(fp);
 
512
                        }
 
513
                        return; /* ignore remainder of the banner string */
 
514
                        /*NOTREACHED*/
 
515
 
 
516
                case 's':
 
517
                        putstr(kerninfo.sysname);
 
518
                        break;
 
519
 
 
520
                case 'm':
 
521
                        putstr(kerninfo.machine);
 
522
                        break;
 
523
 
 
524
                case 'r':
 
525
                        putstr(kerninfo.release);
 
526
                        break;
 
527
 
 
528
                case 'v':
 
529
#ifdef __linux__
 
530
                        putstr(kerninfo.version);
 
531
#else
 
532
                        puts(kerninfo.version);
 
533
#endif
 
534
                        break;
 
535
                }
 
536
                cp++;
 
537
        }
 
538
}
 
539
 
 
540
#ifdef DIAGNOSTICS
 
541
/*
 
542
 * Print telnet options and commands in plain text, if possible.
 
543
 */
 
544
void
 
545
printoption(const char *fmt, int option)
 
546
{
 
547
        if (TELOPT_OK(option))
 
548
                netoprintf("%s %s\r\n", fmt, TELOPT(option));
 
549
        else if (TELCMD_OK(option))
 
550
                netoprintf("%s %s\r\n", fmt, TELCMD(option));
 
551
        else
 
552
                netoprintf("%s %d\r\n", fmt, option);
 
553
}
 
554
 
 
555
/* direction: '<' or '>' */
 
556
/* pointer: where suboption data sits */
 
557
/* length: length of suboption data */
 
558
void
 
559
printsub(char direction, unsigned char *pointer, int length)
 
560
{
 
561
    register int i = -1;
 
562
#ifdef AUTHENTICATE
 
563
    char buf[512];
 
564
#endif
 
565
 
 
566
        if (!(diagnostic & TD_OPTIONS))
 
567
                return;
 
568
 
 
569
        if (direction) {
 
570
            netoprintf("td: %s suboption ",
 
571
                       direction == '<' ? "recv" : "send");
 
572
            if (length >= 3) {
 
573
                register int j;
 
574
 
 
575
                i = pointer[length-2];
 
576
                j = pointer[length-1];
 
577
 
 
578
                if (i != IAC || j != SE) {
 
579
                    netoprintf("(terminated by ");
 
580
                    if (TELOPT_OK(i))
 
581
                        netoprintf("%s ", TELOPT(i));
 
582
                    else if (TELCMD_OK(i))
 
583
                        netoprintf("%s ", TELCMD(i));
 
584
                    else
 
585
                        netoprintf("%d ", i);
 
586
                    if (TELOPT_OK(j))
 
587
                        netoprintf("%s", TELOPT(j));
 
588
                    else if (TELCMD_OK(j))
 
589
                        netoprintf("%s", TELCMD(j));
 
590
                    else
 
591
                        netoprintf("%d", j);
 
592
                    netoprintf(", not IAC SE!) ");
 
593
                }
 
594
            }
 
595
            length -= 2;
 
596
        }
 
597
        if (length < 1) {
 
598
            netoprintf("(Empty suboption???)");
 
599
            return;
 
600
        }
 
601
        switch (pointer[0]) {
 
602
        case TELOPT_TTYPE:
 
603
            netoprintf("TERMINAL-TYPE ");
 
604
            switch (pointer[1]) {
 
605
            case TELQUAL_IS:
 
606
                netoprintf("IS \"%.*s\"", length-2, (char *)pointer+2);
 
607
                break;
 
608
            case TELQUAL_SEND:
 
609
                netoprintf("SEND");
 
610
                break;
 
611
            default:
 
612
                netoprintf("- unknown qualifier %d (0x%x).",
 
613
                                pointer[1], pointer[1]);
 
614
            }
 
615
            break;
 
616
        case TELOPT_TSPEED:
 
617
            netoprintf("TERMINAL-SPEED");
 
618
            if (length < 2) {
 
619
                netoprintf(" (empty suboption???)");
 
620
                break;
 
621
            }
 
622
            switch (pointer[1]) {
 
623
            case TELQUAL_IS:
 
624
                netoprintf(" IS %.*s", length-2, (char *)pointer+2);
 
625
                break;
 
626
            default:
 
627
                if (pointer[1] == 1)
 
628
                    netoprintf(" SEND");
 
629
                else
 
630
                    netoprintf(" %d (unknown)", pointer[1]);
 
631
                for (i = 2; i < length; i++) {
 
632
                    netoprintf(" ?%d?", pointer[i]);
 
633
                }
 
634
                break;
 
635
            }
 
636
            break;
 
637
 
 
638
        case TELOPT_LFLOW:
 
639
            netoprintf("TOGGLE-FLOW-CONTROL");
 
640
            if (length < 2) {
 
641
                netoprintf(" (empty suboption???)");
 
642
                break;
 
643
            }
 
644
            switch (pointer[1]) {
 
645
            case 0:
 
646
                netoprintf(" OFF"); break;
 
647
            case 1:
 
648
                netoprintf(" ON"); break;
 
649
            default:
 
650
                netoprintf(" %d (unknown)", pointer[1]);
 
651
            }
 
652
            for (i = 2; i < length; i++) {
 
653
                netoprintf(" ?%d?", pointer[i]);
 
654
            }
 
655
            break;
 
656
 
 
657
        case TELOPT_NAWS:
 
658
            netoprintf("NAWS");
 
659
            if (length < 2) {
 
660
                netoprintf(" (empty suboption???)");
 
661
                break;
 
662
            }
 
663
            if (length == 2) {
 
664
                netoprintf(" ?%d?", pointer[1]);
 
665
                break;
 
666
            }
 
667
            netoprintf(" %d %d (%d)",
 
668
                pointer[1], pointer[2],
 
669
                (int)((((unsigned int)pointer[1])<<8)|((unsigned int)pointer[2])));
 
670
            if (length == 4) {
 
671
                netoprintf(" ?%d?", pointer[3]);
 
672
                break;
 
673
            }
 
674
            netoprintf(" %d %d (%d)",
 
675
                pointer[3], pointer[4],
 
676
                (int)((((unsigned int)pointer[3])<<8)|((unsigned int)pointer[4])));
 
677
            for (i = 5; i < length; i++) {
 
678
                netoprintf(" ?%d?", pointer[i]);
 
679
            }
 
680
            break;
 
681
 
 
682
        case TELOPT_LINEMODE:
 
683
            netoprintf("LINEMODE ");
 
684
            if (length < 2) {
 
685
                netoprintf(" (empty suboption???)");
 
686
                break;
 
687
            }
 
688
            switch (pointer[1]) {
 
689
            case WILL:
 
690
                netoprintf("WILL ");
 
691
                goto common;
 
692
            case WONT:
 
693
                netoprintf("WONT ");
 
694
                goto common;
 
695
            case DO:
 
696
                netoprintf("DO ");
 
697
                goto common;
 
698
            case DONT:
 
699
                netoprintf("DONT ");
 
700
            common:
 
701
                if (length < 3) {
 
702
                    netoprintf("(no option???)");
 
703
                    break;
 
704
                }
 
705
                switch (pointer[2]) {
 
706
                case LM_FORWARDMASK:
 
707
                    netoprintf("Forward Mask");
 
708
                    for (i = 3; i < length; i++) {
 
709
                        netoprintf(" %x", pointer[i]);
 
710
                    }
 
711
                    break;
 
712
                default:
 
713
                    netoprintf("%d (unknown)", pointer[2]);
 
714
                    for (i = 3; i < length; i++) {
 
715
                        netoprintf(" %d", pointer[i]);
 
716
                    }
 
717
                    break;
 
718
                }
 
719
                break;
 
720
                
 
721
            case LM_SLC:
 
722
                netoprintf("SLC");
 
723
                for (i = 2; i < length - 2; i += 3) {
 
724
                    if (SLC_NAME_OK(pointer[i+SLC_FUNC]))
 
725
                        netoprintf(" %s", SLC_NAME(pointer[i+SLC_FUNC]));
 
726
                    else
 
727
                        netoprintf(" %d", pointer[i+SLC_FUNC]);
 
728
                    switch (pointer[i+SLC_FLAGS]&SLC_LEVELBITS) {
 
729
                    case SLC_NOSUPPORT:
 
730
                        netoprintf(" NOSUPPORT"); break;
 
731
                    case SLC_CANTCHANGE:
 
732
                        netoprintf(" CANTCHANGE"); break;
 
733
                    case SLC_VARIABLE:
 
734
                        netoprintf(" VARIABLE"); break;
 
735
                    case SLC_DEFAULT:
 
736
                        netoprintf(" DEFAULT"); break;
 
737
                    }
 
738
                    netoprintf("%s%s%s",
 
739
                        pointer[i+SLC_FLAGS]&SLC_ACK ? "|ACK" : "",
 
740
                        pointer[i+SLC_FLAGS]&SLC_FLUSHIN ? "|FLUSHIN" : "",
 
741
                        pointer[i+SLC_FLAGS]&SLC_FLUSHOUT ? "|FLUSHOUT" : "");
 
742
                    if (pointer[i+SLC_FLAGS]& ~(SLC_ACK|SLC_FLUSHIN|
 
743
                                                SLC_FLUSHOUT| SLC_LEVELBITS)) {
 
744
                        netoprintf("(0x%x)", pointer[i+SLC_FLAGS]);
 
745
                    }
 
746
                    netoprintf(" %d;", pointer[i+SLC_VALUE]);
 
747
                    if ((pointer[i+SLC_VALUE] == IAC) &&
 
748
                        (pointer[i+SLC_VALUE+1] == IAC))
 
749
                                i++;
 
750
                }
 
751
                for (; i < length; i++) {
 
752
                    netoprintf(" ?%d?", pointer[i]);
 
753
                }
 
754
                break;
 
755
 
 
756
            case LM_MODE:
 
757
                netoprintf("MODE ");
 
758
                if (length < 3) {
 
759
                    netoprintf("(no mode???)");
 
760
                    break;
 
761
                }
 
762
                {
 
763
                    char tbuf[32];
 
764
                    snprintf(tbuf, sizeof(tbuf), "%s%s%s%s%s",
 
765
                        pointer[2]&MODE_EDIT ? "|EDIT" : "",
 
766
                        pointer[2]&MODE_TRAPSIG ? "|TRAPSIG" : "",
 
767
                        pointer[2]&MODE_SOFT_TAB ? "|SOFT_TAB" : "",
 
768
                        pointer[2]&MODE_LIT_ECHO ? "|LIT_ECHO" : "",
 
769
                        pointer[2]&MODE_ACK ? "|ACK" : "");
 
770
                    netoprintf("%s", tbuf[1] ? &tbuf[1] : "0");
 
771
                }
 
772
                if (pointer[2]&~(MODE_EDIT|MODE_TRAPSIG|MODE_ACK)) {
 
773
                    netoprintf(" (0x%x)", pointer[2]);
 
774
                }
 
775
                for (i = 3; i < length; i++) {
 
776
                    netoprintf(" ?0x%x?", pointer[i]);
 
777
                }
 
778
                break;
 
779
            default:
 
780
                netoprintf("%d (unknown)", pointer[1]);
 
781
                for (i = 2; i < length; i++) {
 
782
                    netoprintf(" %d", pointer[i]);
 
783
                }
 
784
            }
 
785
            break;
 
786
 
 
787
        case TELOPT_STATUS: {
 
788
            const char *cp;
 
789
            register int j, k;
 
790
 
 
791
            netoprintf("STATUS");
 
792
 
 
793
            switch (pointer[1]) {
 
794
            default:
 
795
                if (pointer[1] == TELQUAL_SEND)
 
796
                    netoprintf(" SEND");
 
797
                else
 
798
                    netoprintf(" %d (unknown)", pointer[1]);
 
799
                for (i = 2; i < length; i++) {
 
800
                    netoprintf(" ?%d?", pointer[i]);
 
801
                }
 
802
                break;
 
803
            case TELQUAL_IS:
 
804
                netoprintf(" IS\r\n");
 
805
 
 
806
                for (i = 2; i < length; i++) {
 
807
                    switch(pointer[i]) {
 
808
                    case DO:    cp = "DO"; goto common2;
 
809
                    case DONT:  cp = "DONT"; goto common2;
 
810
                    case WILL:  cp = "WILL"; goto common2;
 
811
                    case WONT:  cp = "WONT"; goto common2;
 
812
                    common2:
 
813
                        i++;
 
814
                        if (TELOPT_OK((int)pointer[i]))
 
815
                            netoprintf(" %s %s", cp, TELOPT(pointer[i]));
 
816
                        else
 
817
                            netoprintf(" %s %d", cp, pointer[i]);
 
818
 
 
819
                        netoprintf("\r\n");
 
820
                        break;
 
821
 
 
822
                    case SB:
 
823
                        netoprintf(" SB ");
 
824
                        i++;
 
825
                        j = k = i;
 
826
                        while (j < length) {
 
827
                            if (pointer[j] == SE) {
 
828
                                if (j+1 == length)
 
829
                                    break;
 
830
                                if (pointer[j+1] == SE)
 
831
                                    j++;
 
832
                                else
 
833
                                    break;
 
834
                            }
 
835
                            pointer[k++] = pointer[j++];
 
836
                        }
 
837
                        printsub(0, &pointer[i], k - i);
 
838
                        if (i < length) {
 
839
                            netoprintf(" SE");
 
840
                            i = j;
 
841
                        } else
 
842
                            i = j - 1;
 
843
 
 
844
                        netoprintf("\r\n");
 
845
 
 
846
                        break;
 
847
                                
 
848
                    default:
 
849
                        netoprintf(" %d", pointer[i]);
 
850
                        break;
 
851
                    }
 
852
                }
 
853
                break;
 
854
            }
 
855
            break;
 
856
          }
 
857
 
 
858
        case TELOPT_XDISPLOC:
 
859
            netoprintf("X-DISPLAY-LOCATION ");
 
860
            switch (pointer[1]) {
 
861
            case TELQUAL_IS:
 
862
                netoprintf("IS \"%.*s\"", length-2, (char *)pointer+2);
 
863
                break;
 
864
            case TELQUAL_SEND:
 
865
                netoprintf("SEND");
 
866
                break;
 
867
            default:
 
868
                netoprintf("- unknown qualifier %d (0x%x).",
 
869
                                pointer[1], pointer[1]);
 
870
            }
 
871
            break;
 
872
 
 
873
        case TELOPT_ENVIRON:
 
874
            netoprintf("ENVIRON ");
 
875
            switch (pointer[1]) {
 
876
            case TELQUAL_IS:
 
877
                netoprintf("IS ");
 
878
                goto env_common;
 
879
            case TELQUAL_SEND:
 
880
                netoprintf("SEND ");
 
881
                goto env_common;
 
882
            case TELQUAL_INFO:
 
883
                netoprintf("INFO ");
 
884
            env_common:
 
885
                {
 
886
                    register int noquote = 2;
 
887
                    for (i = 2; i < length; i++ ) {
 
888
                        switch (pointer[i]) {
 
889
                        case ENV_VAR:
 
890
                            if (pointer[1] == TELQUAL_SEND)
 
891
                                goto def_case;
 
892
                            netoprintf("\" VAR " + noquote);
 
893
                            noquote = 2;
 
894
                            break;
 
895
 
 
896
                        case ENV_VALUE:
 
897
                            netoprintf("\" VALUE " + noquote);
 
898
                            noquote = 2;
 
899
                            break;
 
900
 
 
901
                        case ENV_ESC:
 
902
                            netoprintf("\" ESC " + noquote);
 
903
                            noquote = 2;
 
904
                            break;
 
905
 
 
906
                        default:
 
907
                        def_case:
 
908
                            if (isprint(pointer[i]) && pointer[i] != '"') {
 
909
                                if (noquote) {
 
910
                                    netoprintf("\"");
 
911
                                    noquote = 0;
 
912
                                }
 
913
                                netoprintf("%c", pointer[i]);
 
914
                            } else {
 
915
                                netoprintf("\" %03o " + noquote,
 
916
                                                        pointer[i]);
 
917
                                noquote = 2;
 
918
                            }
 
919
                            break;
 
920
                        }
 
921
                    }
 
922
                    if (!noquote)
 
923
                        netoprintf("\"");
 
924
                    break;
 
925
                }
 
926
            }
 
927
            break;
 
928
 
 
929
#if     defined(AUTHENTICATE)
 
930
        case TELOPT_AUTHENTICATION:
 
931
            netoprintf("AUTHENTICATION");
 
932
        
 
933
            if (length < 2) {
 
934
                netoprintf(" (empty suboption???)");
 
935
                break;
 
936
            }
 
937
            switch (pointer[1]) {
 
938
            case TELQUAL_REPLY:
 
939
            case TELQUAL_IS:
 
940
                netoprintf(" %s ", (pointer[1] == TELQUAL_IS) ?
 
941
                                                        "IS" : "REPLY");
 
942
                if (AUTHTYPE_NAME_OK(pointer[2]))
 
943
                    netoprintf("%s ", AUTHTYPE_NAME(pointer[2]));
 
944
                else
 
945
                    netoprintf("%d ", pointer[2]);
 
946
                if (length < 3) {
 
947
                    netoprintf("(partial suboption???)");
 
948
                    break;
 
949
                }
 
950
                netoprintf("%s|%s",
 
951
                        ((pointer[3] & AUTH_WHO_MASK) == AUTH_WHO_CLIENT) ?
 
952
                        "CLIENT" : "SERVER",
 
953
                        ((pointer[3] & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) ?
 
954
                        "MUTUAL" : "ONE-WAY");
 
955
 
 
956
                auth_printsub(&pointer[1], length - 1, buf, sizeof(buf));
 
957
                netoprintf("%s", buf);
 
958
                break;
 
959
 
 
960
            case TELQUAL_SEND:
 
961
                i = 2;
 
962
                netoprintf(" SEND ");
 
963
                while (i < length) {
 
964
                    if (AUTHTYPE_NAME_OK(pointer[i]))
 
965
                        netoprintf("%s ", AUTHTYPE_NAME(pointer[i]));
 
966
                    else
 
967
                        netoprintf("%d ", pointer[i]);
 
968
                    if (++i >= length) {
 
969
                        netoprintf("(partial suboption???)");
 
970
                        break;
 
971
                    }
 
972
                    netoprintf("%s|%s ",
 
973
                        ((pointer[i] & AUTH_WHO_MASK) == AUTH_WHO_CLIENT) ?
 
974
                                                        "CLIENT" : "SERVER",
 
975
                        ((pointer[i] & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) ?
 
976
                                                        "MUTUAL" : "ONE-WAY");
 
977
                    ++i;
 
978
                }
 
979
                break;
 
980
 
 
981
            case TELQUAL_NAME:
 
982
                i = 2;
 
983
                netoprintf(" NAME \"");
 
984
                /*
 
985
                 * Was:
 
986
                 *    while (i < length)
 
987
                 *       *nfrontp += pointer[i++];
 
988
                 *    *nfrontp += '"';
 
989
                 *
 
990
                 * but I'm pretty sure that's wrong...
 
991
                 */
 
992
                while (i < length)
 
993
                    netoprintf("%c", pointer[i++]);
 
994
                netoprintf("\"");
 
995
                break;
 
996
 
 
997
            default:
 
998
                    for (i = 2; i < length; i++) {
 
999
                        netoprintf(" ?%d?", pointer[i]);
 
1000
                    }
 
1001
                    break;
 
1002
            }
 
1003
            break;
 
1004
#endif
 
1005
 
 
1006
#if     defined(ENCRYPT)
 
1007
        case TELOPT_ENCRYPT:
 
1008
            netoprintf("ENCRYPT");
 
1009
            if (length < 2) {
 
1010
                netoprintf(" (empty suboption???)");
 
1011
                break;
 
1012
            }
 
1013
            switch (pointer[1]) {
 
1014
            case ENCRYPT_START:
 
1015
                netoprintf(" START");
 
1016
                break;
 
1017
 
 
1018
            case ENCRYPT_END:
 
1019
                netoprintf(" END");
 
1020
                break;
 
1021
 
 
1022
            case ENCRYPT_REQSTART:
 
1023
                netoprintf(" REQUEST-START");
 
1024
                break;
 
1025
 
 
1026
            case ENCRYPT_REQEND:
 
1027
                netoprintf(" REQUEST-END");
 
1028
                break;
 
1029
 
 
1030
            case ENCRYPT_IS:
 
1031
            case ENCRYPT_REPLY:
 
1032
                netoprintf(" %s ", (pointer[1] == ENCRYPT_IS) ?
 
1033
                                                        "IS" : "REPLY");
 
1034
                if (length < 3) {
 
1035
                    netoprintf(" (partial suboption???)");
 
1036
                    break;
 
1037
                }
 
1038
                if (ENCTYPE_NAME_OK(pointer[2]))
 
1039
                    netoprintf("%s ", ENCTYPE_NAME(pointer[2]));
 
1040
                else
 
1041
                    netoprintf(" %d (unknown)", pointer[2]);
 
1042
 
 
1043
                encrypt_printsub(&pointer[1], length - 1, buf, sizeof(buf));
 
1044
                netoprintf("%s", buf);
 
1045
                break;
 
1046
 
 
1047
            case ENCRYPT_SUPPORT:
 
1048
                i = 2;
 
1049
                netoprintf(" SUPPORT ");
 
1050
                while (i < length) {
 
1051
                    if (ENCTYPE_NAME_OK(pointer[i]))
 
1052
                        netoprintf("%s ", ENCTYPE_NAME(pointer[i]));
 
1053
                    else
 
1054
                        netoprintf("%d ", pointer[i]);
 
1055
                    i++;
 
1056
                }
 
1057
                break;
 
1058
 
 
1059
            case ENCRYPT_ENC_KEYID:
 
1060
                netoprintf(" ENC_KEYID", pointer[1]);
 
1061
                goto encommon;
 
1062
 
 
1063
            case ENCRYPT_DEC_KEYID:
 
1064
                netoprintf(" DEC_KEYID", pointer[1]);
 
1065
                goto encommon;
 
1066
 
 
1067
            default:
 
1068
                netoprintf(" %d (unknown)", pointer[1]);
 
1069
            encommon:
 
1070
                for (i = 2; i < length; i++) {
 
1071
                    netoprintf(" %d", pointer[i]);
 
1072
                }
 
1073
                break;
 
1074
            }
 
1075
            break;
 
1076
#endif
 
1077
 
 
1078
        default:
 
1079
            if (TELOPT_OK(pointer[0]))
 
1080
                netoprintf("%s (unknown)", TELOPT(pointer[0]));
 
1081
            else
 
1082
                netoprintf("%d (unknown)", pointer[i]);
 
1083
            for (i = 1; i < length; i++) {
 
1084
                netoprintf(" %d", pointer[i]);
 
1085
            }
 
1086
            break;
 
1087
        }
 
1088
        netoprintf("\r\n");
 
1089
}
 
1090
 
 
1091
/*
 
1092
 * Dump a data buffer in hex and ascii to the output data stream.
 
1093
 */
 
1094
void
 
1095
printdata(const char *tag, const char *ptr, int cnt)
 
1096
{
 
1097
        register int i;
 
1098
        char xbuf[30];
 
1099
 
 
1100
        while (cnt) {
 
1101
                /* add a line of output */
 
1102
                netoprintf("%s: ", tag);
 
1103
                for (i = 0; i < 20 && cnt; i++) {
 
1104
                        netoprintf("%02x", *ptr);
 
1105
                        if (isprint(*ptr)) {
 
1106
                                xbuf[i] = *ptr;
 
1107
                        } else {
 
1108
                                xbuf[i] = '.';
 
1109
                        }
 
1110
                        if (i % 2) { 
 
1111
                                netoprintf(" ");
 
1112
                        }
 
1113
                        cnt--;
 
1114
                        ptr++;
 
1115
                }
 
1116
                xbuf[i] = '\0';
 
1117
                netoprintf(" %s\r\n", xbuf );
 
1118
        } 
 
1119
}
 
1120
#endif /* DIAGNOSTICS */
 
1121
 
 
1122
static struct buflist *
 
1123
addbuf(const char *buf, size_t len)
 
1124
{
 
1125
        struct buflist *bufl;
 
1126
 
 
1127
        bufl = malloc(sizeof(struct buflist));
 
1128
        if (!bufl) {
 
1129
                return 0;
 
1130
        }
 
1131
        bufl->next = tail->next;
 
1132
        bufl->buf = malloc(len);
 
1133
        if (!bufl->buf) {
 
1134
                free(bufl);
 
1135
                return 0;
 
1136
        }
 
1137
        bufl->len = len;
 
1138
 
 
1139
        tail = tail->next = bufl;
 
1140
        listlen++;
 
1141
 
 
1142
        memcpy(bufl->buf, buf, len);
 
1143
        return bufl;
 
1144
}
 
1145
 
 
1146
static ssize_t
 
1147
netwrite(void *cookie, const char *buf, size_t len)
 
1148
{
 
1149
        size_t ret;
 
1150
        const char *const end = buf + len;
 
1151
        int ltrailing = trailing;
 
1152
        int ldoclear = doclear;
 
1153
 
 
1154
#define wewant(p)       ((*p&0xff) == IAC) && \
 
1155
                                ((*(p+1)&0xff) != EC) && ((*(p+1)&0xff) != EL)
 
1156
 
 
1157
        ret = 0;
 
1158
 
 
1159
        if (ltrailing) {
 
1160
                const char *p;
 
1161
                size_t l;
 
1162
                size_t m = tail->len;
 
1163
 
 
1164
                p = nextitem(tail->buf, tail->buf + tail->len, buf, end);
 
1165
                ltrailing = !p;
 
1166
                if (ltrailing) {
 
1167
                        p = end;
 
1168
                }
 
1169
 
 
1170
                l = p - buf;
 
1171
                tail->len += l;
 
1172
                tail->buf = realloc(tail->buf, tail->len);
 
1173
                if (!tail->buf) {
 
1174
                        return -1;
 
1175
                }
 
1176
 
 
1177
                memcpy(tail->buf + m, buf, l);
 
1178
                buf += l;
 
1179
                len -= l;
 
1180
                ret += l;
 
1181
                trailing = ltrailing;
 
1182
        }
 
1183
 
 
1184
        if (ldoclear) {
 
1185
                struct buflist *lpprev;
 
1186
 
 
1187
                skip = 0;
 
1188
                lpprev = &head;
 
1189
                for (;;) {
 
1190
                        struct buflist *lp;
 
1191
 
 
1192
                        lp = lpprev->next;
 
1193
 
 
1194
                        if (lp == &head) {
 
1195
                                tail = lpprev;
 
1196
                                break;
 
1197
                        }
 
1198
 
 
1199
                        if (lp == tail && ltrailing) {
 
1200
                                break;
 
1201
                        }
 
1202
 
 
1203
                        if (!wewant(lp->buf)) {
 
1204
                                lpprev->next = lp->next;
 
1205
                                listlen--;
 
1206
                                free(lp->buf);
 
1207
                                free(lp);
 
1208
                        } else {
 
1209
                                lpprev = lp;
 
1210
                        }
 
1211
                }
 
1212
        }
 
1213
 
 
1214
        while (len) {
 
1215
                const char *p;
 
1216
                size_t l;
 
1217
 
 
1218
                p = nextitem(buf, end, 0, 0);
 
1219
                ltrailing = !p;
 
1220
                if (ltrailing) {
 
1221
                        p = end;
 
1222
                } else if (ldoclear) {
 
1223
                        if (!wewant(buf)) {
 
1224
                                l = p - buf;
 
1225
                                goto cont;
 
1226
                        }
 
1227
                }
 
1228
 
 
1229
                l = p - buf;
 
1230
                if (!addbuf(buf, l)) {
 
1231
                        return ret ? ret : -1;
 
1232
                }
 
1233
                trailing = ltrailing;
 
1234
 
 
1235
cont:
 
1236
                buf += l;
 
1237
                len -= l;
 
1238
                ret += l;
 
1239
        }
 
1240
 
 
1241
        netwritebuf();
 
1242
        return ret;
 
1243
}
 
1244
 
 
1245
void
 
1246
netopen() {
 
1247
        static const cookie_io_functions_t funcs = {
 
1248
                read: 0, write: netwrite, seek: 0, close: 0
 
1249
        };
 
1250
 
 
1251
        netfile = fopencookie(0, "w", funcs);
 
1252
}
 
1253
 
 
1254
extern int not42;
 
1255
void
 
1256
sendurg(const char *buf, size_t len) {
 
1257
        if (!not42) {
 
1258
                fwrite(buf, 1, len, netfile);
 
1259
                return;
 
1260
        }
 
1261
 
 
1262
        urg = addbuf(buf, len);
 
1263
}
 
1264
 
 
1265
size_t
 
1266
netbuflen(int flush) {
 
1267
        if (flush) {
 
1268
                netflush();
 
1269
        }
 
1270
        return listlen != 1 ? listlen : tail->len - skip;
 
1271
}