9fans - fans of the OS Plan 9 from Bell Labs
 help / color / mirror / Atom feed
* new telnetd (again)
@ 1995-08-17  6:56 Vadim
  0 siblings, 0 replies; 2+ messages in thread
From: Vadim @ 1995-08-17  6:56 UTC (permalink / 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;
}






^ permalink raw reply	[flat|nested] 2+ messages in thread

* new telnetd (again)
@ 1995-08-17 23:59 Boyd
  0 siblings, 0 replies; 2+ messages in thread
From: Boyd @ 1995-08-17 23:59 UTC (permalink / raw)


    From:	avg@postman.ncube.com (Vadim Antonov)
    
    The "more improved" line discipline plus the

one message i'm worried about it, the next it happens...






^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~1995-08-17 23:59 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
1995-08-17  6:56 new telnetd (again) Vadim
1995-08-17 23:59 Boyd

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).