static char sccsid
[] = "@(#)telnetd.c 4.3 (Berkeley) %G%";
* Stripped-down telnet server.
#define INFINITY 10000000
#define swab(x) ((((x) >> 8) | ((x) << 8)) & 0xffff)
char doopt
[] = { IAC
, DO
, '%', 'c', 0 };
char dont
[] = { IAC
, DONT
, '%', 'c', 0 };
char will
[] = { IAC
, WILL
, '%', 'c', 0 };
char wont
[] = { IAC
, WONT
, '%', 'c', 0 };
* I/O data buffers, pointers, and counters.
char ptyibuf
[BUFSIZ
], *ptyip
= ptyibuf
;
char ptyobuf
[BUFSIZ
], *pfrontp
= ptyobuf
, *pbackp
= ptyobuf
;
char netibuf
[BUFSIZ
], *netip
= netibuf
;
{ IAC
, DO
, TELOPT_ECHO
, '\r', '\n' },
*nfrontp
= netobuf
+ 5, *nbackp
= netobuf
;
char line
[] = "/dev/ptyp0";
struct sockaddr_in sin
= { AF_INET
, swab(IPPORT_TELNET
) };
int options
= SO_ACCEPTCONN
;
* Debugging hooks. Turned on with a SIGTERM.
* Successive SIGTERM's toggle the switch.
char logfile
[80] = "/tmp/teldebugx";
if (argc
> 0 && !strcmp(argv
[0], "-d"))
if ((s
= socket(SOCK_STREAM
, 0, &sin
, options
)) < 0) {
printf("Out of processes\n");
while (wait3(status
, WNOHANG
, 0) > 0)
* Get a pty, scan input lines.
for (i
= 0; i
< 16; i
++) {
cp
[strlen("/dev/ptyp")] = "0123456789abcdef"[i
];
printf("All network ports in use.\n");
logfile
[strlen("/tmp/teldebug")] = "0123456789abcdef"[i
];
cp
[strlen("/dev/")] = 't';
b
.sg_flags
= ECHO
|CRMOD
|XTABS
|ANYP
;
execl("/bin/login", "telnet-login", 0);
* Main loop. Select from pty and network, and
* hand data to telnet receiver finite state machine.
signal(SIGTSTP
, SIG_IGN
);
sigset(SIGCHLD
, cleanup
);
int ibits
= 0, obits
= 0;
* Never look for input if there's still
* stuff in the corresponding output buffer
fprintf(log
, "select: ibits=%d, obits=%d\n",
select(32, &ibits
, &obits
, INFINITY
);
fprintf(log
, "ibits=%d, obits=%d\n", ibits
, obits
);
if (ibits
== 0 && obits
== 0) {
* Something to read from the network...
ncc
= read(f
, netibuf
, BUFSIZ
);
fprintf(log
, "read %d from net\n", ncc
);
if (ncc
< 0 && errno
== EWOULDBLOCK
)
* Something to read from the pty...
pcc
= read(p
, ptyibuf
, BUFSIZ
);
fprintf(log
, "read %d from pty\n", pcc
);
if (pcc
< 0 && errno
== EWOULDBLOCK
)
if ((&netobuf
[BUFSIZ
] - nfrontp
) < 2)
c
= *ptyip
++ & 0377, pcc
--;
if ((obits
& (1 << f
)) && (nfrontp
- nbackp
) > 0)
if ((obits
& (1 << p
)) && (pfrontp
- pbackp
) > 0)
#define TS_DATA 0 /* base state */
#define TS_IAC 1 /* look for double IAC's */
#define TS_CR 2 /* CR-LF ->'s CR */
#define TS_BEGINNEG 3 /* throw away begin's... */
#define TS_ENDNEG 4 /* ...end's (suboption negotiation) */
#define TS_WILL 5 /* will option negotiation */
#define TS_WONT 6 /* wont " */
#define TS_DO 7 /* do " */
#define TS_DONT 8 /* dont " */
static int state
= TS_DATA
;
if ((&ptyobuf
[BUFSIZ
] - pfrontp
) < 2)
c
= *netip
++ & 0377, ncc
--;
if (!myopts
[TELOPT_BINARY
] && c
== '\r')
* Send the process on the pty side an
* interrupt. Do this with a NULL or
* interrupt char; depending on the tty mode.
ptyflush(); /* half-hearted */
ioctl(pty
, TIOCGETP
, &b
);
* Check for urgent data...
* Begin option subnegotiation...
state
= TS_WILL
+ (c
- WILL
);
state
= c
== SE
? TS_DATA
: TS_BEGINNEG
;
sprintf(nfrontp
, wont
, c
);
nfrontp
+= sizeof(wont
) - 2;
printf("netser: panic state=%d\n", state
);
sprintf(nfrontp
, fmt
, option
);
nfrontp
+= sizeof(dont
) - 2;
sprintf(nfrontp
, fmt
, option
);
nfrontp
+= sizeof(doopt
) - 2;
sprintf(nfrontp
, fmt
, option
);
nfrontp
+= sizeof(doopt
) - 2;
ioctl(pty
, TIOCGETP
, &b
);
ioctl(pty
, TIOCSETP
, &b
);
* Send interrupt to process on other side of pty.
* If it is in raw mode, just write NULL;
* otherwise, write intr char.
ptyflush(); /* half-hearted */
ioctl(pty
, TIOCGETP
, &b
);
*pfrontp
++ = ioctl(pty
, TIOCGETC
, &tchars
) < 0 ?
if ((n
= pfrontp
- pbackp
) > 0)
n
= write(pty
, pbackp
, n
);
if (n
< 0 && errno
== EWOULDBLOCK
)
pbackp
= pfrontp
= ptyobuf
;
if ((n
= nfrontp
- nbackp
) > 0)
n
= write(net
, nbackp
, n
);
if (n
< 0 && errno
== EWOULDBLOCK
)
nbackp
= nfrontp
= netobuf
;
fprintf(log
, "log stopped\n");
if ((log
= fopen(logfile
, "a")) != NULL
) {
fprintf(log
, "log started on /dev/pty%c\n",
logfile
[strlen("/tmp/teldebug")]);
fprintf(log
, "net=%d, pty=%d\n", net
, pty
);
ioctl(net
, SIOCDONE
, &how
);
char wtmpf
[] = "/usr/adm/wtmp";
char utmp
[] = "/etc/utmp";
#define SCPYN(a, b) strncpy(a, b, sizeof(a))
#define SCMPN(a, b) strncmp(a, b, sizeof(a))
while(read(f
, (char *)&wtmp
, sizeof(wtmp
)) == sizeof(wtmp
)) {
if (SCMPN(wtmp
.ut_line
, line
+5) || wtmp
.ut_name
[0]==0)
lseek(f
, -(long)sizeof(wtmp
), 1);
write(f
, (char *)&wtmp
, sizeof(wtmp
));
SCPYN(wtmp
.ut_line
, line
+5);
write(f
, (char *)&wtmp
, sizeof(wtmp
));
line
[strlen("/dev/")] = 'p';