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

« back to all changes in this revision

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