From: Vadim Antonov avg@postman.ncube.com
Subject: new telnetd (again)
Date: Thu, 17 Aug 1995 02:56:33 -0400 [thread overview]
Message-ID: <19950817065633.Y-mNCgupmIFHfvXmIgC_WglM2t2-QmCEc9bKGfsXm28@z> (raw)
The "more improved" line discipline plus the
plaintext-password authentication option for
those who does not have SecureNet keys or use
reasonable firewalls.
The plaintext password mode is turned on with -P
option (i.e. replace /rc/bin/service/tcp23 with
#!/bin/rc
exec /bin/aux/telnetd -P
Since there were many changes i appended the
complete source (/sys/src/cmd/service/telnetd.c):
--vadim
---CUT HERE---
#include <u.h>
#include <libc.h>
#include <bio.h>
#include <auth.h>
#include "../ip/telnet.h"
/* console state (for consctl) */
typedef struct Consstate Consstate;
struct Consstate{
int raw;
int hold;
int noecho;
int col;
int scol;
};
Consstate *cons;
int notefd; /* for sending notes to the child */
int noproto; /* true if we shouldn't be using the telnet protocol */
int trusted; /* true if we need not authenticate - current user
is ok */
int nonone; /* don't allow none logins */
int plaintext; /* use less secure plaintext passowrds */
/* input and output buffers for network connection */
Biobuf netib;
Biobuf childib;
char remotesys[2*NAMELEN]; /* name of remote system */
int alnum(int);
int conssim(void);
int fromchild(char*, int);
int fromnet(char*, int);
void rubout(char*, char*, char**);
int termchange(Biobuf*, int);
int termsub(Biobuf*, uchar*, int);
int xlocchange(Biobuf*, int);
int xlocsub(Biobuf*, uchar*, int);
int challuser(char*);
void* share(int);
#define TELNETLOG "telnet"
void
logit(char *fmt, ...)
{
char buf[8192], *s;
s = buf;
s = doprint(s, buf + sizeof(buf) / sizeof(*buf), fmt, &fmt + 1);
*s = 0;
syslog(0, TELNETLOG, "(%s) %s", remotesys, buf);
}
void
getremote(char *dir)
{
int fd, n;
char remfile[2*NAMELEN];
sprint(remfile, "%s/remote", dir);
fd = open(remfile, OREAD);
if(fd < 0)
strcpy(remotesys, "unknown2");
n = read(fd, remotesys, sizeof(remotesys)-1);
if(n>0)
remotesys[n-1] = 0;
else
strcpy(remotesys, remfile);
close(fd);
}
void
main(int argc, char *argv[])
{
char buf[1024];
int fd;
char user[NAMELEN];
int tries = 0;
int childpid;
int n;
memset(user, 0, sizeof(user));
ARGBEGIN {
case 'n':
opt[Echo].local = 1;
noproto = 1;
break;
case 'N':
nonone = 1;
break;
case 't':
trusted = 1;
strncpy(user, getuser(), NAMELEN-1);
break;
case 'u':
strncpy(user, ARGF(), sizeof(user)-1);
break;
case 'D':
debug = 1;
break;
case 'P':
plaintext = 1;
break;
} ARGEND
if(argc)
getremote(argv[argc-1]);
else
strcpy(remotesys, "unknown");
/* options we need routines for */
opt[Term].change = termchange;
opt[Term].sub = termsub;
opt[Xloc].sub = xlocsub;
/* setup default telnet options */
if(!noproto){
send3(1, Iac, Will, opt[Echo].code);
send3(1, Iac, Do, opt[Term].code);
send3(1, Iac, Do, opt[Xloc].code);
}
/* shared data for console state */
cons = share(sizeof(Consstate));
if(cons == 0)
fatal("shared memory", 0, 0);
cons->scol = -1;
/* authenticate and create new name space */
Binit(&netib, 0, OREAD);
if (!trusted){
while(challuser(user) < 0) {
if(++tries == 5){
logit("failed as %s", user);
print("authentication failure\r\n");
exits("authentication");
}
*user = 0;
}
}
logit("logged in as %s", user);
newns(user, 0);
putenv("service", "con");
/* simulate /dev/consctl and /dev/cons using pipes */
fd = conssim();
if(fd < 0)
fatal("simulating", 0, 0);
Binit(&childib, fd, OREAD);
/* start a shell in a different process group */
switch(childpid = rfork(RFPROC|RFNAMEG|RFFDG|RFNOTEG)){
case -1:
fatal("fork", 0, 0);
case 0:
fd = open("/dev/cons", OREAD);
dup(fd, 0);
close(fd);
fd = open("/dev/cons", OWRITE);
dup(fd, 1);
dup(fd, 2);
close(fd);
segdetach(cons);
execl("/bin/rc", "rc", "-il", 0);
fatal("/bin/rc", 0, 0);
default:
sprint(buf, "/proc/%d/notepg", childpid);
notefd = open(buf, OWRITE);
if(notefd < 0)
fatal(buf, 0, 0);
break;
}
/* two processes to shuttle bytes twixt children and network */
switch(fork()){
case -1:
fatal("fork", 0, 0);
case 0:
while((n = fromchild(buf, sizeof(buf))) >= 0)
if(write(1, buf, n) != n)
break;
break;
default:
while((n = fromnet(buf, sizeof(buf))) >= 0)
if(write(fd, buf, n) != n)
break;
break;
}
/* kill off all server processes */
sprint(buf, "/proc/%d/notepg", getpid());
fd = open(buf, OWRITE);
write(fd, "die", 3);
exits(0);
}
void
prompt(char *p, char *b, int n)
{
char *e;
int i;
print("%s: ", p);
for(e = b+n; b < e;){
i = fromnet(b, e-b);
if(i <= 0)
exits("fromnet: hungup");
b += i;
if(*(b-1) == '\n'){
*(b-1) = 0;
return;
}
}
}
/*
* challenge user
*/
int
challuser(char *user)
{
char nchall[NETCHLEN+32];
char response[NAMELEN];
Chalstate ch;
char key[DESKEYLEN];
if(*user == 0)
prompt("user", user, NAMELEN);
if(strcmp(user, "none") == 0){
if(nonone)
return -1;
return 0;
}
if(getchal(&ch, user) < 0)
return -1;
if(plaintext) {
cons->noecho = 1;
prompt("password", response, NAMELEN);
cons->noecho = 0;
print("\r\n");
passtokey(key, response);
strcpy(response, ch.chal);
netcrypt(key, response);
} else {
sprint(nchall, "challenge: %s\r\nresponse", ch.chal);
prompt(nchall, response, sizeof response);
}
if(chalreply(&ch, response) < 0)
return -1;
return 0;
}
/*
* Process some input from the child, add protocol if needed. If
* the input buffer goes empty, return.
*/
int
fromchild(char *bp, int len)
{
int c;
char *start;
for(start = bp; bp-start < len-1; ){
c = Bgetc(&childib);
if(c < 0){
if(bp == start)
return -1;
else
break;
}
if(cons->raw == 0) {
switch(c) {
case '\n':
*bp++ = '\r';
case '\r':
cons->col = 0;
break;
case '\b':
if(cons->col > 0)
cons->col--;
break;
case '\t':
cons->col = (cons->col + 8) & ~07;
break;
default:
cons->col++;
}
}
*bp++ = c;
if(Bbuffered(&childib) == 0)
break;
}
return bp-start;
}
/*
* Read from the network up to a '\n' or some other break.
*
* If in binary mode, buffer characters but don't
*
* The following characters are special:
* '\r\n's and '\r's get turned into '\n's.
* ^H erases the last character buffered.
* ^U kills the whole line buffered.
* ^W erases the last word
* ^D causes a 0-lenght line to be returned.
* Intr causes an "interrupt" note to be sent to the children.
*/
#define ECHO(c) { *ebp++ = (c); }
#define BACKSPACE() { ECHO('\b'); ECHO(' '); ECHO('\b'); }
int
fromnet(char *bp, int len)
{
int c;
char echobuf[1024];
char *ebp;
char *start;
static int crnl;
static int doeof;
/* simulate an EOF as a 0 length input */
if(doeof){
doeof = 0;
return 0;
}
for(ebp = echobuf,start = bp; bp-start < len && ebp-echobuf < sizeof(echobuf); ){
c = Bgetc(&netib);
if(c < 0){
if(bp == start)
return -1;
else
break;
}
/* telnet protocol only */
if(!noproto){
/* protocol messages */
switch(c){
case Iac:
crnl = 0;
c = Bgetc(&netib);
if(c == Iac)
break;
control(&netib, c);
continue;
case 0: /* telnet ignores nulls */
continue;
}
}
/* \r\n or \n\r become \n */
if(c == '\r' || c == '\n'){
if(crnl && crnl != c){
crnl = 0;
continue;
}
if(cons->raw == 0 && opt[Echo].local){
ECHO('\r');
ECHO('\n');
cons->col = 0;
cons->scol = -1;
}
crnl = c;
*bp++ = '\n';
break;
} else
crnl = 0;
/* raw processing (each character terminates */
if(cons->raw){
*bp++ = c;
break;
}
/* in binary mode, there are no control characters */
if(opt[Binary].local){
if(opt[Echo].local)
ECHO(c);
*bp++ = c;
continue;
}
/* cooked processing */
if(cons->scol == -1)
cons->scol = cons->col;
switch(c){
case 0x04:
if(bp != start)
doeof = 1;
goto out;
case 0x08: /* ^H */
if(start < bp) {
bp--;
if(opt[Echo].local)
rubout(bp, start, &ebp);
}
break;
case 0x15: /* ^U */
if(opt[Echo].local && cons->scol >= 0) {
while (cons->col > cons->scol) {
BACKSPACE();
cons->col--;
}
}
bp = start;
break;
case 0x17: /* ^W */
if (opt[Echo].local) {
while (bp > start && !alnum(bp[-1]))
rubout(--bp, start, &ebp);
while (bp > start && alnum(bp[-1])) {
bp--;
BACKSPACE();
cons->col--;
}
}
break;
case 0x7f: /* Del */
write(notefd, "interrupt", 9);
ECHO('\r');
ECHO('\n');
bp = start;
cons->col = 0;
cons->scol = -1;
break;
case 0x09: /* Tab */
if(opt[Echo].local) {
cons->col = (cons->col + 8) & ~7;
ECHO(c);
}
*bp++ = c;
break;
default:
if(opt[Echo].local) {
if( c >= ' ' ) {
ECHO(c);
cons->col++;
} else {
ECHO('^');
ECHO(0x40|c);
cons->col += 2;
}
}
*bp++ = c;
}
if(ebp != echobuf && !cons->noecho)
write(1, echobuf, ebp-echobuf);
ebp = echobuf;
}
out:
if(ebp != echobuf && !cons->noecho)
write(1, echobuf, ebp-echobuf);
return bp - start;
}
/*
* Rub out an echoed character
*/
void
rubout(char *bp, char *buf, char **pp)
{
char *ebp = *pp;
int col;
char *q;
if( *bp == '\t' ) { /* tough case */
col = cons->scol;
for(q = buf ; q < bp ; q++) {
if(*q == '\t')
col = (col + 8) & ~07;
else if(*q < ' ')
col += 2;
else
col++;
}
while(cons->col > col) {
BACKSPACE();
cons->col--;
}
*pp = ebp;
return;
} else if( *bp < ' ' ) {
cons->col--;
BACKSPACE();
}
cons->col--;
BACKSPACE();
*pp = ebp;
}
int
termchange(Biobuf *bp, int cmd)
{
char buf[8];
char *p = buf;
if(cmd != Will)
return 0;
/* ask other side to send term type info */
*p++ = Iac;
*p++ = Sb;
*p++ = opt[Term].code;
*p++ = 1;
*p++ = Iac;
*p++ = Se;
return iwrite(Bfildes(bp), buf, p-buf);
}
int
termsub(Biobuf *bp, uchar *sub, int n)
{
char term[NAMELEN];
USED(bp);
if(n-- < 1 || sub[0] != 0)
return 0;
if(n >= sizeof term)
n = sizeof term;
strncpy(term, (char*)sub, n);
putenv("TERM", term);
return 0;
}
int
xlocchange(Biobuf *bp, int cmd)
{
char buf[8];
char *p = buf;
if(cmd != Will)
return 0;
/* ask other side to send x display info */
*p++ = Iac;
*p++ = Sb;
*p++ = opt[Xloc].code;
*p++ = 1;
*p++ = Iac;
*p++ = Se;
return iwrite(Bfildes(bp), buf, p-buf);
}
int
xlocsub(Biobuf *bp, uchar *sub, int n)
{
char xloc[NAMELEN];
USED(bp);
if(n-- < 1 || sub[0] != 0)
return 0;
if(n >= sizeof xloc)
n = sizeof xloc;
strncpy(xloc, (char*)sub, n);
putenv("DISPLAY", xloc);
return 0;
}
/*
* create a shared segment. Make is start 2 meg higher than the current
* end of process memory.
*/
void*
share(int len)
{
ulong vastart;
vastart = ((ulong)sbrk(0)) + 2*1024*1024;
if(segattach(0, "shared", (void *)vastart, len) < 0)
return 0;
return (void*)vastart;
}
/*
* bind a pipe onto consctl and keep reading it to
* get changes to console state.
*/
int
conssim(void)
{
int i, n;
int fd;
int tries;
char buf[128];
char *field[10];
/* a pipe to simulate the /dev/cons */
if(bind("#|", "/mnt/cons/cons", MREPL) < 0
|| bind("/mnt/cons/cons/data1", "/dev/cons", MREPL) < 0)
fatal("/dev/cons", 0, 0);
/* a pipe to simulate consctl */
if(bind("#|", "/mnt/cons/consctl", MBEFORE) < 0
|| bind("/mnt/cons/consctl/data1", "/dev/consctl", MREPL) < 0)
fatal("/dev/consctl", 0, 0);
/* a process to read /dev/consctl and set the state in cons */
switch(fork()){
case -1:
fatal("forking", 0, 0);
case 0:
break;
default:
return open("/mnt/cons/cons/data", ORDWR);
}
setfields(" ");
for(tries = 0; tries < 100; tries++){
cons->raw = 0;
cons->hold = 0;
fd = open("/mnt/cons/consctl/data", OREAD);
if(fd < 0)
continue;
tries = 0;
for(;;){
n = read(fd, buf, sizeof(buf)-1);
if(n <= 0)
break;
buf[n] = 0;
n = getmfields(buf, field, 10);
for(i = 0; i < n; i++){
if(strcmp(field[i], "rawon") == 0)
cons->raw = 1;
else if(strcmp(field[i], "rawoff") == 0)
cons->raw = 0;
else if(strcmp(field[i], "holdon") == 0)
cons->hold = 1;
else if(strcmp(field[i], "holdoff") == 0)
cons->hold = 0;
}
}
close(fd);
}
exits(0);
return -1;
}
int
alnum(int c)
{
/*
* Hard to get absolutely right. Use what we know about ASCII
* and assume anything above the Latin control characters is
* potentially an alphanumeric.
*/
if(c <= ' ')
return 0;
if(0x7F<=c && c<=0xA0)
return 0;
if(strchr("!\"#$%&'()*+,-./:;<=>?@`[\\]^{|}~", c))
return 0;
return 1;
}
next reply other threads:[~1995-08-17 6:56 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
1995-08-17 6:56 Vadim [this message]
1995-08-17 23:59 Boyd
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=19950817065633.Y-mNCgupmIFHfvXmIgC_WglM2t2-QmCEc9bKGfsXm28@z \
--to=9fans@9fans.net \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).