xref: /plan9/sys/src/cmd/ip/telnetd.c (revision aef377881c258b55253e6d1b6004ee9da79af528)
17dd7cddfSDavid du Colombier #include <u.h>
27dd7cddfSDavid du Colombier #include <libc.h>
37dd7cddfSDavid du Colombier #include <bio.h>
47dd7cddfSDavid du Colombier #include <auth.h>
57dd7cddfSDavid du Colombier #include <libsec.h>
67dd7cddfSDavid du Colombier 
77dd7cddfSDavid du Colombier #include "../ip/telnet.h"
87dd7cddfSDavid du Colombier 
97dd7cddfSDavid du Colombier /*  console state (for consctl) */
107dd7cddfSDavid du Colombier typedef struct Consstate	Consstate;
117dd7cddfSDavid du Colombier struct Consstate{
127dd7cddfSDavid du Colombier 	int raw;
137dd7cddfSDavid du Colombier 	int hold;
147dd7cddfSDavid du Colombier };
157dd7cddfSDavid du Colombier Consstate *cons;
167dd7cddfSDavid du Colombier 
177dd7cddfSDavid du Colombier int notefd;		/* for sending notes to the child */
187dd7cddfSDavid du Colombier int noproto;		/* true if we shouldn't be using the telnet protocol */
197dd7cddfSDavid du Colombier int trusted;		/* true if we need not authenticate - current user
207dd7cddfSDavid du Colombier 				is ok */
217dd7cddfSDavid du Colombier int nonone = 1;		/* don't allow none logins */
229a747e4fSDavid du Colombier int noworldonly;	/* only noworld accounts */
239a747e4fSDavid du Colombier 
249a747e4fSDavid du Colombier enum
259a747e4fSDavid du Colombier {
269a747e4fSDavid du Colombier 	Maxpath=	256,
279a747e4fSDavid du Colombier 	Maxuser=	64,
289a747e4fSDavid du Colombier 	Maxvar=		32,
299a747e4fSDavid du Colombier };
307dd7cddfSDavid du Colombier 
317dd7cddfSDavid du Colombier /* input and output buffers for network connection */
327dd7cddfSDavid du Colombier Biobuf	netib;
337dd7cddfSDavid du Colombier Biobuf	childib;
349a747e4fSDavid du Colombier char	remotesys[Maxpath];	/* name of remote system */
357dd7cddfSDavid du Colombier 
367dd7cddfSDavid du Colombier int	alnum(int);
377dd7cddfSDavid du Colombier int	conssim(void);
387dd7cddfSDavid du Colombier int	fromchild(char*, int);
397dd7cddfSDavid du Colombier int	fromnet(char*, int);
407dd7cddfSDavid du Colombier int	termchange(Biobuf*, int);
417dd7cddfSDavid du Colombier int	termsub(Biobuf*, uchar*, int);
427dd7cddfSDavid du Colombier int	xlocchange(Biobuf*, int);
437dd7cddfSDavid du Colombier int	xlocsub(Biobuf*, uchar*, int);
447dd7cddfSDavid du Colombier int	challuser(char*);
457dd7cddfSDavid du Colombier int	noworldlogin(char*);
4674f16c81SDavid du Colombier void*	share(ulong);
477dd7cddfSDavid du Colombier int	doauth(char*);
487dd7cddfSDavid du Colombier 
497dd7cddfSDavid du Colombier #define TELNETLOG "telnet"
507dd7cddfSDavid du Colombier 
517dd7cddfSDavid du Colombier void
logit(char * fmt,...)527dd7cddfSDavid du Colombier logit(char *fmt, ...)
537dd7cddfSDavid du Colombier {
547dd7cddfSDavid du Colombier 	va_list arg;
559a747e4fSDavid du Colombier 	char buf[8192];
567dd7cddfSDavid du Colombier 
577dd7cddfSDavid du Colombier 	va_start(arg, fmt);
589a747e4fSDavid du Colombier 	vseprint(buf, buf + sizeof(buf) / sizeof(*buf), fmt, arg);
597dd7cddfSDavid du Colombier 	va_end(arg);
607dd7cddfSDavid du Colombier 	syslog(0, TELNETLOG, "(%s) %s", remotesys, buf);
617dd7cddfSDavid du Colombier }
627dd7cddfSDavid du Colombier 
637dd7cddfSDavid du Colombier void
getremote(char * dir)647dd7cddfSDavid du Colombier getremote(char *dir)
657dd7cddfSDavid du Colombier {
667dd7cddfSDavid du Colombier 	int fd, n;
679a747e4fSDavid du Colombier 	char remfile[Maxpath];
687dd7cddfSDavid du Colombier 
697dd7cddfSDavid du Colombier 	sprint(remfile, "%s/remote", dir);
707dd7cddfSDavid du Colombier 	fd = open(remfile, OREAD);
717dd7cddfSDavid du Colombier 	if(fd < 0)
727dd7cddfSDavid du Colombier 		strcpy(remotesys, "unknown2");
737dd7cddfSDavid du Colombier 	n = read(fd, remotesys, sizeof(remotesys)-1);
747dd7cddfSDavid du Colombier 	if(n>0)
757dd7cddfSDavid du Colombier 		remotesys[n-1] = 0;
767dd7cddfSDavid du Colombier 	else
777dd7cddfSDavid du Colombier 		strcpy(remotesys, remfile);
787dd7cddfSDavid du Colombier 	close(fd);
797dd7cddfSDavid du Colombier }
807dd7cddfSDavid du Colombier 
817dd7cddfSDavid du Colombier void
main(int argc,char * argv[])827dd7cddfSDavid du Colombier main(int argc, char *argv[])
837dd7cddfSDavid du Colombier {
847dd7cddfSDavid du Colombier 	char buf[1024];
857dd7cddfSDavid du Colombier 	int fd;
869a747e4fSDavid du Colombier 	char user[Maxuser];
877dd7cddfSDavid du Colombier 	int tries = 0;
887dd7cddfSDavid du Colombier 	int childpid;
897dd7cddfSDavid du Colombier 	int n, eofs;
907dd7cddfSDavid du Colombier 
917dd7cddfSDavid du Colombier 	memset(user, 0, sizeof(user));
927dd7cddfSDavid du Colombier 	ARGBEGIN {
937dd7cddfSDavid du Colombier 	case 'n':
947dd7cddfSDavid du Colombier 		opt[Echo].local = 1;
957dd7cddfSDavid du Colombier 		noproto = 1;
967dd7cddfSDavid du Colombier 		break;
977dd7cddfSDavid du Colombier 	case 'p':
987dd7cddfSDavid du Colombier 		noproto = 1;
997dd7cddfSDavid du Colombier 		break;
1007dd7cddfSDavid du Colombier 	case 'a':
1017dd7cddfSDavid du Colombier 		nonone = 0;
1027dd7cddfSDavid du Colombier 		break;
1037dd7cddfSDavid du Colombier 	case 't':
1047dd7cddfSDavid du Colombier 		trusted = 1;
1059a747e4fSDavid du Colombier 		strncpy(user, getuser(), sizeof(user)-1);
1067dd7cddfSDavid du Colombier 		break;
1077dd7cddfSDavid du Colombier 	case 'u':
1087dd7cddfSDavid du Colombier 		strncpy(user, ARGF(), sizeof(user)-1);
1097dd7cddfSDavid du Colombier 		break;
1107dd7cddfSDavid du Colombier 	case 'd':
1117dd7cddfSDavid du Colombier 		debug = 1;
1127dd7cddfSDavid du Colombier 		break;
1139a747e4fSDavid du Colombier 	case 'N':
1149a747e4fSDavid du Colombier 		noworldonly = 1;
1159a747e4fSDavid du Colombier 		break;
1167dd7cddfSDavid du Colombier 	} ARGEND
1177dd7cddfSDavid du Colombier 
1187dd7cddfSDavid du Colombier 	if(argc)
1197dd7cddfSDavid du Colombier 		getremote(argv[argc-1]);
1207dd7cddfSDavid du Colombier 	else
1217dd7cddfSDavid du Colombier 		strcpy(remotesys, "unknown");
1227dd7cddfSDavid du Colombier 
1237dd7cddfSDavid du Colombier 	/* options we need routines for */
1247dd7cddfSDavid du Colombier 	opt[Term].change = termchange;
1257dd7cddfSDavid du Colombier 	opt[Term].sub = termsub;
1267dd7cddfSDavid du Colombier 	opt[Xloc].sub = xlocsub;
1277dd7cddfSDavid du Colombier 
1287dd7cddfSDavid du Colombier 	/* setup default telnet options */
1297dd7cddfSDavid du Colombier 	if(!noproto){
1307dd7cddfSDavid du Colombier 		send3(1, Iac, Will, opt[Echo].code);
1317dd7cddfSDavid du Colombier 		send3(1, Iac, Do, opt[Term].code);
1327dd7cddfSDavid du Colombier 		send3(1, Iac, Do, opt[Xloc].code);
1337dd7cddfSDavid du Colombier 	}
1347dd7cddfSDavid du Colombier 
1357dd7cddfSDavid du Colombier 	/* shared data for console state */
1367dd7cddfSDavid du Colombier 	cons = share(sizeof(Consstate));
1377dd7cddfSDavid du Colombier 	if(cons == 0)
1387dd7cddfSDavid du Colombier 		fatal("shared memory", 0, 0);
1397dd7cddfSDavid du Colombier 
1407dd7cddfSDavid du Colombier 	/* authenticate and create new name space */
1417dd7cddfSDavid du Colombier 	Binit(&netib, 0, OREAD);
1427dd7cddfSDavid du Colombier 	if (!trusted){
1437dd7cddfSDavid du Colombier 		while(doauth(user) < 0)
1447dd7cddfSDavid du Colombier 			if(++tries == 5){
1459a747e4fSDavid du Colombier 				logit("failed as %s: %r", user);
1469a747e4fSDavid du Colombier 				print("authentication failure:%r\r\n");
1477dd7cddfSDavid du Colombier 				exits("authentication");
1487dd7cddfSDavid du Colombier 			}
1497dd7cddfSDavid du Colombier 	}
1507dd7cddfSDavid du Colombier 	logit("logged in as %s", user);
1517dd7cddfSDavid du Colombier 	putenv("service", "con");
1527dd7cddfSDavid du Colombier 
1537dd7cddfSDavid du Colombier 	/* simulate /dev/consctl and /dev/cons using pipes */
1547dd7cddfSDavid du Colombier 	fd = conssim();
1557dd7cddfSDavid du Colombier 	if(fd < 0)
1567dd7cddfSDavid du Colombier 		fatal("simulating", 0, 0);
1577dd7cddfSDavid du Colombier 	Binit(&childib, fd, OREAD);
1587dd7cddfSDavid du Colombier 
1597dd7cddfSDavid du Colombier 	/* start a shell in a different process group */
1607dd7cddfSDavid du Colombier 	switch(childpid = rfork(RFPROC|RFNAMEG|RFFDG|RFNOTEG)){
1617dd7cddfSDavid du Colombier 	case -1:
1627dd7cddfSDavid du Colombier 		fatal("fork", 0, 0);
1637dd7cddfSDavid du Colombier 	case 0:
1647dd7cddfSDavid du Colombier 		close(fd);
1657dd7cddfSDavid du Colombier 		fd = open("/dev/cons", OREAD);
1667dd7cddfSDavid du Colombier 		dup(fd, 0);
1677dd7cddfSDavid du Colombier 		close(fd);
1687dd7cddfSDavid du Colombier 		fd = open("/dev/cons", OWRITE);
1697dd7cddfSDavid du Colombier 		dup(fd, 1);
1707dd7cddfSDavid du Colombier 		dup(fd, 2);
1717dd7cddfSDavid du Colombier 		close(fd);
1727dd7cddfSDavid du Colombier 		segdetach(cons);
173f19e7b74SDavid du Colombier 		execl("/bin/rc", "rc", "-il", nil);
1747dd7cddfSDavid du Colombier 		fatal("/bin/rc", 0, 0);
1757dd7cddfSDavid du Colombier 	default:
1767dd7cddfSDavid du Colombier 		sprint(buf, "/proc/%d/notepg", childpid);
1777dd7cddfSDavid du Colombier 		notefd = open(buf, OWRITE);
1787dd7cddfSDavid du Colombier 		break;
1797dd7cddfSDavid du Colombier 	}
1807dd7cddfSDavid du Colombier 
1817dd7cddfSDavid du Colombier 	/* two processes to shuttle bytes twixt children and network */
1827dd7cddfSDavid du Colombier 	switch(fork()){
1837dd7cddfSDavid du Colombier 	case -1:
1847dd7cddfSDavid du Colombier 		fatal("fork", 0, 0);
1857dd7cddfSDavid du Colombier 	case 0:
1867dd7cddfSDavid du Colombier 		eofs = 0;
1877dd7cddfSDavid du Colombier 		for(;;){
1887dd7cddfSDavid du Colombier 			n = fromchild(buf, sizeof(buf));
1897dd7cddfSDavid du Colombier 			if(n <= 0){
1907dd7cddfSDavid du Colombier 				if(eofs++ > 2)
1917dd7cddfSDavid du Colombier 					break;
1927dd7cddfSDavid du Colombier 				continue;
1937dd7cddfSDavid du Colombier 			}
1947dd7cddfSDavid du Colombier 			eofs = 0;
1957dd7cddfSDavid du Colombier 			if(write(1, buf, n) != n)
1967dd7cddfSDavid du Colombier 				break;
1977dd7cddfSDavid du Colombier 		}
1987dd7cddfSDavid du Colombier 		break;
1997dd7cddfSDavid du Colombier 	default:
2007dd7cddfSDavid du Colombier 		while((n = fromnet(buf, sizeof(buf))) >= 0)
2017dd7cddfSDavid du Colombier 			if(write(fd, buf, n) != n)
2027dd7cddfSDavid du Colombier 				break;
2037dd7cddfSDavid du Colombier 		break;
2047dd7cddfSDavid du Colombier 	}
2057dd7cddfSDavid du Colombier 
2067dd7cddfSDavid du Colombier 	/* kill off all server processes */
2077dd7cddfSDavid du Colombier 	sprint(buf, "/proc/%d/notepg", getpid());
2087dd7cddfSDavid du Colombier 	fd = open(buf, OWRITE);
2097dd7cddfSDavid du Colombier 	write(fd, "die", 3);
2107dd7cddfSDavid du Colombier 	exits(0);
2117dd7cddfSDavid du Colombier }
2127dd7cddfSDavid du Colombier 
2137dd7cddfSDavid du Colombier void
prompt(char * p,char * b,int n,int raw)2147dd7cddfSDavid du Colombier prompt(char *p, char *b, int n, int raw)
2157dd7cddfSDavid du Colombier {
2167dd7cddfSDavid du Colombier 	char *e;
2177dd7cddfSDavid du Colombier 	int i;
2187dd7cddfSDavid du Colombier 	int echo;
2197dd7cddfSDavid du Colombier 
2207dd7cddfSDavid du Colombier 	echo = opt[Echo].local;
2217dd7cddfSDavid du Colombier 	if(raw)
2227dd7cddfSDavid du Colombier 		opt[Echo].local = 0;
2237dd7cddfSDavid du Colombier 	print("%s: ", p);
2247dd7cddfSDavid du Colombier 	for(e = b+n; b < e;){
2257dd7cddfSDavid du Colombier 		i = fromnet(b, e-b);
2267dd7cddfSDavid du Colombier 		if(i <= 0)
2277dd7cddfSDavid du Colombier 			exits("fromnet: hungup");
2287dd7cddfSDavid du Colombier 		b += i;
2297dd7cddfSDavid du Colombier 		if(*(b-1) == '\n' || *(b-1) == '\r'){
2307dd7cddfSDavid du Colombier 			*(b-1) = 0;
2317dd7cddfSDavid du Colombier 			break;
2327dd7cddfSDavid du Colombier 		}
2337dd7cddfSDavid du Colombier 	}
2347dd7cddfSDavid du Colombier 	if(raw)
2357dd7cddfSDavid du Colombier 		opt[Echo].local = echo;
2367dd7cddfSDavid du Colombier }
2377dd7cddfSDavid du Colombier 
2387dd7cddfSDavid du Colombier /*
2397dd7cddfSDavid du Colombier  *  challenge user
2407dd7cddfSDavid du Colombier  */
2417dd7cddfSDavid du Colombier int
challuser(char * user)2427dd7cddfSDavid du Colombier challuser(char *user)
2437dd7cddfSDavid du Colombier {
2449a747e4fSDavid du Colombier 	char nchall[64];
2459a747e4fSDavid du Colombier 	char response[64];
2469a747e4fSDavid du Colombier 	Chalstate *ch;
2479a747e4fSDavid du Colombier 	AuthInfo *ai;
2487dd7cddfSDavid du Colombier 
2497dd7cddfSDavid du Colombier 	if(strcmp(user, "none") == 0){
2507dd7cddfSDavid du Colombier 		if(nonone)
2517dd7cddfSDavid du Colombier 			return -1;
2529a747e4fSDavid du Colombier 		newns("none", nil);
2537dd7cddfSDavid du Colombier 		return 0;
2547dd7cddfSDavid du Colombier 	}
2559a747e4fSDavid du Colombier 	if((ch = auth_challenge("proto=p9cr role=server user=%q", user)) == nil)
2567dd7cddfSDavid du Colombier 		return -1;
2579a747e4fSDavid du Colombier 	snprint(nchall, sizeof nchall, "challenge: %s\r\nresponse", ch->chal);
2587dd7cddfSDavid du Colombier 	prompt(nchall, response, sizeof response, 0);
2599a747e4fSDavid du Colombier 	ch->resp = response;
2609a747e4fSDavid du Colombier 	ch->nresp = strlen(response);
2619a747e4fSDavid du Colombier 	ai = auth_response(ch);
2629a747e4fSDavid du Colombier 	auth_freechal(ch);
2633ff48bf5SDavid du Colombier 	if(ai == nil){
2643ff48bf5SDavid du Colombier 		rerrstr(response, sizeof response);
2653ff48bf5SDavid du Colombier 		print("!%s\n", response);
2667dd7cddfSDavid du Colombier 		return -1;
2673ff48bf5SDavid du Colombier 	}
2689a747e4fSDavid du Colombier 	if(auth_chuid(ai, nil) < 0)
2699a747e4fSDavid du Colombier 		return -1;
2707dd7cddfSDavid du Colombier 	return 0;
2717dd7cddfSDavid du Colombier }
2727dd7cddfSDavid du Colombier /*
2737dd7cddfSDavid du Colombier  *  use the in the clear apop password to change user id
2747dd7cddfSDavid du Colombier  */
2757dd7cddfSDavid du Colombier int
noworldlogin(char * user)2767dd7cddfSDavid du Colombier noworldlogin(char *user)
2777dd7cddfSDavid du Colombier {
2787dd7cddfSDavid du Colombier 	char password[256];
2797dd7cddfSDavid du Colombier 
2807dd7cddfSDavid du Colombier 	prompt("password", password, sizeof(password), 1);
2817dd7cddfSDavid du Colombier 	if(login(user, password, "/lib/namespace.noworld") < 0)
2827dd7cddfSDavid du Colombier 		return -1;
2839a747e4fSDavid du Colombier 	rfork(RFNOMNT);	/* sandbox */
2847dd7cddfSDavid du Colombier 	return 0;
2857dd7cddfSDavid du Colombier }
2867dd7cddfSDavid du Colombier 
2877dd7cddfSDavid du Colombier int
doauth(char * user)2887dd7cddfSDavid du Colombier doauth(char *user)
2897dd7cddfSDavid du Colombier {
2907dd7cddfSDavid du Colombier 	if(*user == 0)
2919a747e4fSDavid du Colombier 		prompt("user", user, Maxuser, 0);
2927dd7cddfSDavid du Colombier 	if(noworld(user))
2937dd7cddfSDavid du Colombier 		return noworldlogin(user);
2949a747e4fSDavid du Colombier 	if(noworldonly)
2959a747e4fSDavid du Colombier 		return -1;
2967dd7cddfSDavid du Colombier 	return challuser(user);
2977dd7cddfSDavid du Colombier 
2987dd7cddfSDavid du Colombier }
2997dd7cddfSDavid du Colombier 
3007dd7cddfSDavid du Colombier /*
3017dd7cddfSDavid du Colombier  *  Process some input from the child, add protocol if needed.  If
3027dd7cddfSDavid du Colombier  *  the input buffer goes empty, return.
3037dd7cddfSDavid du Colombier  */
3047dd7cddfSDavid du Colombier int
fromchild(char * bp,int len)3057dd7cddfSDavid du Colombier fromchild(char *bp, int len)
3067dd7cddfSDavid du Colombier {
3077dd7cddfSDavid du Colombier 	int c;
3087dd7cddfSDavid du Colombier 	char *start;
3097dd7cddfSDavid du Colombier 
3107dd7cddfSDavid du Colombier 	for(start = bp; bp-start < len-1; ){
3117dd7cddfSDavid du Colombier 		c = Bgetc(&childib);
3127dd7cddfSDavid du Colombier 		if(c < 0){
3137dd7cddfSDavid du Colombier 			if(bp == start)
3147dd7cddfSDavid du Colombier 				return -1;
3157dd7cddfSDavid du Colombier 			else
3167dd7cddfSDavid du Colombier 				break;
3177dd7cddfSDavid du Colombier 		}
3187dd7cddfSDavid du Colombier 		if(cons->raw == 0 && c == '\n')
3197dd7cddfSDavid du Colombier 			*bp++ = '\r';
3207dd7cddfSDavid du Colombier 		*bp++ = c;
3217dd7cddfSDavid du Colombier 		if(Bbuffered(&childib) == 0)
3227dd7cddfSDavid du Colombier 			break;
3237dd7cddfSDavid du Colombier 	}
3247dd7cddfSDavid du Colombier 	return bp-start;
3257dd7cddfSDavid du Colombier }
3267dd7cddfSDavid du Colombier 
3277dd7cddfSDavid du Colombier /*
3287dd7cddfSDavid du Colombier  *  Read from the network up to a '\n' or some other break.
3297dd7cddfSDavid du Colombier  *
3307dd7cddfSDavid du Colombier  *  If in binary mode, buffer characters but don't
3317dd7cddfSDavid du Colombier  *
3327dd7cddfSDavid du Colombier  *  The following characters are special:
3337dd7cddfSDavid du Colombier  *	'\r\n's and '\r's get turned into '\n's.
3347dd7cddfSDavid du Colombier  *	^H erases the last character buffered.
3357dd7cddfSDavid du Colombier  *	^U kills the whole line buffered.
3367dd7cddfSDavid du Colombier  *	^W erases the last word
337*aef37788SDavid du Colombier  *	^D causes a 0-length line to be returned.
3387dd7cddfSDavid du Colombier  *	Intr causes an "interrupt" note to be sent to the children.
3397dd7cddfSDavid du Colombier  */
3407dd7cddfSDavid du Colombier #define ECHO(c) { *ebp++ = (c); }
3417dd7cddfSDavid du Colombier int
fromnet(char * bp,int len)3427dd7cddfSDavid du Colombier fromnet(char *bp, int len)
3437dd7cddfSDavid du Colombier {
3447dd7cddfSDavid du Colombier 	int c;
3457dd7cddfSDavid du Colombier 	char echobuf[1024];
3467dd7cddfSDavid du Colombier 	char *ebp;
3477dd7cddfSDavid du Colombier 	char *start;
3487dd7cddfSDavid du Colombier 	static int crnl;
3497dd7cddfSDavid du Colombier 	static int doeof;
3507dd7cddfSDavid du Colombier 
3517dd7cddfSDavid du Colombier 
3527dd7cddfSDavid du Colombier 	/* simulate an EOF as a 0 length input */
3537dd7cddfSDavid du Colombier 	if(doeof){
3547dd7cddfSDavid du Colombier 		doeof = 0;
3557dd7cddfSDavid du Colombier 		return 0;
3567dd7cddfSDavid du Colombier 	}
3577dd7cddfSDavid du Colombier 
3587dd7cddfSDavid du Colombier 	for(ebp = echobuf,start = bp; bp-start < len && ebp-echobuf < sizeof(echobuf); ){
3597dd7cddfSDavid du Colombier 		c = Bgetc(&netib);
3607dd7cddfSDavid du Colombier 		if(c < 0){
3617dd7cddfSDavid du Colombier 			if(bp == start)
3627dd7cddfSDavid du Colombier 				return -1;
3637dd7cddfSDavid du Colombier 			else
3647dd7cddfSDavid du Colombier 				break;
3657dd7cddfSDavid du Colombier 		}
3667dd7cddfSDavid du Colombier 
3677dd7cddfSDavid du Colombier 		/* telnet protocol only */
3687dd7cddfSDavid du Colombier 		if(!noproto){
3697dd7cddfSDavid du Colombier 			/* protocol messages */
3707dd7cddfSDavid du Colombier 			switch(c){
3717dd7cddfSDavid du Colombier 			case Iac:
3727dd7cddfSDavid du Colombier 				crnl = 0;
3737dd7cddfSDavid du Colombier 				c = Bgetc(&netib);
3747dd7cddfSDavid du Colombier 				if(c == Iac)
3757dd7cddfSDavid du Colombier 					break;
3767dd7cddfSDavid du Colombier 				control(&netib, c);
3777dd7cddfSDavid du Colombier 				continue;
3787dd7cddfSDavid du Colombier 			}
3797dd7cddfSDavid du Colombier 
3807dd7cddfSDavid du Colombier 		}
3817dd7cddfSDavid du Colombier 
3827dd7cddfSDavid du Colombier 		/* \r\n or \n\r become \n  */
3837dd7cddfSDavid du Colombier 		if(c == '\r' || c == '\n'){
3847dd7cddfSDavid du Colombier 			if(crnl && crnl != c){
3857dd7cddfSDavid du Colombier 				crnl = 0;
3867dd7cddfSDavid du Colombier 				continue;
3877dd7cddfSDavid du Colombier 			}
3887dd7cddfSDavid du Colombier 			if(cons->raw == 0 && opt[Echo].local){
3897dd7cddfSDavid du Colombier 				ECHO('\r');
3907dd7cddfSDavid du Colombier 				ECHO('\n');
3917dd7cddfSDavid du Colombier 			}
3927dd7cddfSDavid du Colombier 			crnl = c;
3937dd7cddfSDavid du Colombier 			if(cons->raw == 0)
3947dd7cddfSDavid du Colombier 				*bp++ = '\n';
3957dd7cddfSDavid du Colombier 			else
3967dd7cddfSDavid du Colombier 				*bp++ = c;
3977dd7cddfSDavid du Colombier 			break;
3987dd7cddfSDavid du Colombier 		} else
3997dd7cddfSDavid du Colombier 			crnl = 0;
4007dd7cddfSDavid du Colombier 
4017dd7cddfSDavid du Colombier 		/* raw processing (each character terminates */
4027dd7cddfSDavid du Colombier 		if(cons->raw){
4037dd7cddfSDavid du Colombier 			*bp++ = c;
4047dd7cddfSDavid du Colombier 			break;
4057dd7cddfSDavid du Colombier 		}
4067dd7cddfSDavid du Colombier 
4077dd7cddfSDavid du Colombier 		/* in binary mode, there are no control characters */
4087dd7cddfSDavid du Colombier 		if(opt[Binary].local){
4097dd7cddfSDavid du Colombier 			if(opt[Echo].local)
4107dd7cddfSDavid du Colombier 				ECHO(c);
4117dd7cddfSDavid du Colombier 			*bp++ = c;
4127dd7cddfSDavid du Colombier 			continue;
4137dd7cddfSDavid du Colombier 		}
4147dd7cddfSDavid du Colombier 
4157dd7cddfSDavid du Colombier 		/* cooked processing */
4167dd7cddfSDavid du Colombier 		switch(c){
4177dd7cddfSDavid du Colombier 		case 0x00:
4187dd7cddfSDavid du Colombier 			if(noproto)		/* telnet ignores nulls */
4197dd7cddfSDavid du Colombier 				*bp++ = c;
4207dd7cddfSDavid du Colombier 			continue;
4217dd7cddfSDavid du Colombier 		case 0x04:
4227dd7cddfSDavid du Colombier 			if(bp != start)
4237dd7cddfSDavid du Colombier 				doeof = 1;
4247dd7cddfSDavid du Colombier 			goto out;
4257dd7cddfSDavid du Colombier 
4267dd7cddfSDavid du Colombier 		case 0x08:	/* ^H */
4277dd7cddfSDavid du Colombier 			if(start < bp)
4287dd7cddfSDavid du Colombier 				bp--;
4297dd7cddfSDavid du Colombier 			if(opt[Echo].local)
4307dd7cddfSDavid du Colombier 				ECHO(c);
4317dd7cddfSDavid du Colombier 			break;
4327dd7cddfSDavid du Colombier 
4337dd7cddfSDavid du Colombier 		case 0x15:	/* ^U */
4347dd7cddfSDavid du Colombier 			bp = start;
4357dd7cddfSDavid du Colombier 			if(opt[Echo].local){
4367dd7cddfSDavid du Colombier 				ECHO('^');
4377dd7cddfSDavid du Colombier 				ECHO('U');
4387dd7cddfSDavid du Colombier 				ECHO('\r');
4397dd7cddfSDavid du Colombier 				ECHO('\n');
4407dd7cddfSDavid du Colombier 			}
4417dd7cddfSDavid du Colombier 			break;
4427dd7cddfSDavid du Colombier 
4437dd7cddfSDavid du Colombier 		case 0x17:	/* ^W */
4447dd7cddfSDavid du Colombier 			if (opt[Echo].local) {
4457dd7cddfSDavid du Colombier 				while (--bp >= start && !alnum(*bp))
4467dd7cddfSDavid du Colombier 					ECHO('\b');
4477dd7cddfSDavid du Colombier 				while (bp >= start && alnum(*bp)) {
4487dd7cddfSDavid du Colombier 					ECHO('\b');
4497dd7cddfSDavid du Colombier 					bp--;
4507dd7cddfSDavid du Colombier 				}
4517dd7cddfSDavid du Colombier 				bp++;
4527dd7cddfSDavid du Colombier 			}
4537dd7cddfSDavid du Colombier 			break;
4547dd7cddfSDavid du Colombier 
4557dd7cddfSDavid du Colombier 		case 0x7f:	/* Del */
4567dd7cddfSDavid du Colombier 			write(notefd, "interrupt", 9);
45759cc4ca5SDavid du Colombier 			bp = start;
4587dd7cddfSDavid du Colombier 			break;
4597dd7cddfSDavid du Colombier 
4607dd7cddfSDavid du Colombier 		default:
4617dd7cddfSDavid du Colombier 			if(opt[Echo].local)
4627dd7cddfSDavid du Colombier 				ECHO(c);
4637dd7cddfSDavid du Colombier 			*bp++ = c;
4647dd7cddfSDavid du Colombier 		}
4657dd7cddfSDavid du Colombier 		if(ebp != echobuf)
4667dd7cddfSDavid du Colombier 			write(1, echobuf, ebp-echobuf);
4677dd7cddfSDavid du Colombier 		ebp = echobuf;
4687dd7cddfSDavid du Colombier 	}
4697dd7cddfSDavid du Colombier out:
4707dd7cddfSDavid du Colombier 	if(ebp != echobuf)
4717dd7cddfSDavid du Colombier 		write(1, echobuf, ebp-echobuf);
4727dd7cddfSDavid du Colombier 	return bp - start;
4737dd7cddfSDavid du Colombier }
4747dd7cddfSDavid du Colombier 
4757dd7cddfSDavid du Colombier int
termchange(Biobuf * bp,int cmd)4767dd7cddfSDavid du Colombier termchange(Biobuf *bp, int cmd)
4777dd7cddfSDavid du Colombier {
4787dd7cddfSDavid du Colombier 	char buf[8];
4797dd7cddfSDavid du Colombier 	char *p = buf;
4807dd7cddfSDavid du Colombier 
4817dd7cddfSDavid du Colombier 	if(cmd != Will)
4827dd7cddfSDavid du Colombier 		return 0;
4837dd7cddfSDavid du Colombier 
4847dd7cddfSDavid du Colombier 	/* ask other side to send term type info */
4857dd7cddfSDavid du Colombier 	*p++ = Iac;
4867dd7cddfSDavid du Colombier 	*p++ = Sb;
4877dd7cddfSDavid du Colombier 	*p++ = opt[Term].code;
4887dd7cddfSDavid du Colombier 	*p++ = 1;
4897dd7cddfSDavid du Colombier 	*p++ = Iac;
4907dd7cddfSDavid du Colombier 	*p++ = Se;
4917dd7cddfSDavid du Colombier 	return iwrite(Bfildes(bp), buf, p-buf);
4927dd7cddfSDavid du Colombier }
4937dd7cddfSDavid du Colombier 
4947dd7cddfSDavid du Colombier int
termsub(Biobuf * bp,uchar * sub,int n)4957dd7cddfSDavid du Colombier termsub(Biobuf *bp, uchar *sub, int n)
4967dd7cddfSDavid du Colombier {
4979a747e4fSDavid du Colombier 	char term[Maxvar];
4987dd7cddfSDavid du Colombier 
4997dd7cddfSDavid du Colombier 	USED(bp);
5007dd7cddfSDavid du Colombier 	if(n-- < 1 || sub[0] != 0)
5017dd7cddfSDavid du Colombier 		return 0;
5027dd7cddfSDavid du Colombier 	if(n >= sizeof term)
5037dd7cddfSDavid du Colombier 		n = sizeof term;
5047dd7cddfSDavid du Colombier 	strncpy(term, (char*)sub, n);
5057dd7cddfSDavid du Colombier 	putenv("TERM", term);
5067dd7cddfSDavid du Colombier 	return 0;
5077dd7cddfSDavid du Colombier }
5087dd7cddfSDavid du Colombier 
5097dd7cddfSDavid du Colombier int
xlocchange(Biobuf * bp,int cmd)5107dd7cddfSDavid du Colombier xlocchange(Biobuf *bp, int cmd)
5117dd7cddfSDavid du Colombier {
5127dd7cddfSDavid du Colombier 	char buf[8];
5137dd7cddfSDavid du Colombier 	char *p = buf;
5147dd7cddfSDavid du Colombier 
5157dd7cddfSDavid du Colombier 	if(cmd != Will)
5167dd7cddfSDavid du Colombier 		return 0;
5177dd7cddfSDavid du Colombier 
5187dd7cddfSDavid du Colombier 	/* ask other side to send x display info */
5197dd7cddfSDavid du Colombier 	*p++ = Iac;
5207dd7cddfSDavid du Colombier 	*p++ = Sb;
5217dd7cddfSDavid du Colombier 	*p++ = opt[Xloc].code;
5227dd7cddfSDavid du Colombier 	*p++ = 1;
5237dd7cddfSDavid du Colombier 	*p++ = Iac;
5247dd7cddfSDavid du Colombier 	*p++ = Se;
5257dd7cddfSDavid du Colombier 	return iwrite(Bfildes(bp), buf, p-buf);
5267dd7cddfSDavid du Colombier }
5277dd7cddfSDavid du Colombier 
5287dd7cddfSDavid du Colombier int
xlocsub(Biobuf * bp,uchar * sub,int n)5297dd7cddfSDavid du Colombier xlocsub(Biobuf *bp, uchar *sub, int n)
5307dd7cddfSDavid du Colombier {
5319a747e4fSDavid du Colombier 	char xloc[Maxvar];
5327dd7cddfSDavid du Colombier 
5337dd7cddfSDavid du Colombier 	USED(bp);
5347dd7cddfSDavid du Colombier 	if(n-- < 1 || sub[0] != 0)
5357dd7cddfSDavid du Colombier 		return 0;
5367dd7cddfSDavid du Colombier 	if(n >= sizeof xloc)
5377dd7cddfSDavid du Colombier 		n = sizeof xloc;
5387dd7cddfSDavid du Colombier 	strncpy(xloc, (char*)sub, n);
5397dd7cddfSDavid du Colombier 	putenv("DISPLAY", xloc);
5407dd7cddfSDavid du Colombier 	return 0;
5417dd7cddfSDavid du Colombier }
5427dd7cddfSDavid du Colombier 
5437dd7cddfSDavid du Colombier /*
5447dd7cddfSDavid du Colombier  *  create a shared segment.  Make is start 2 meg higher than the current
5457dd7cddfSDavid du Colombier  *  end of process memory.
5467dd7cddfSDavid du Colombier  */
5477dd7cddfSDavid du Colombier void*
share(ulong len)54874f16c81SDavid du Colombier share(ulong len)
5497dd7cddfSDavid du Colombier {
5507545821fSDavid du Colombier 	uchar *vastart;
5517dd7cddfSDavid du Colombier 
5527545821fSDavid du Colombier 	vastart = sbrk(0);
55374f16c81SDavid du Colombier 	if(vastart == (void*)-1)
55474f16c81SDavid du Colombier 		return 0;
5557545821fSDavid du Colombier 	vastart += 2*1024*1024;
5567dd7cddfSDavid du Colombier 
55774f16c81SDavid du Colombier 	if(segattach(0, "shared", vastart, len) == (void*)-1)
5587dd7cddfSDavid du Colombier 		return 0;
5597dd7cddfSDavid du Colombier 
5607545821fSDavid du Colombier 	return vastart;
5617dd7cddfSDavid du Colombier }
5627dd7cddfSDavid du Colombier 
5637dd7cddfSDavid du Colombier /*
5647dd7cddfSDavid du Colombier  *  bind a pipe onto consctl and keep reading it to
5657dd7cddfSDavid du Colombier  *  get changes to console state.
5667dd7cddfSDavid du Colombier  */
5677dd7cddfSDavid du Colombier int
conssim(void)5687dd7cddfSDavid du Colombier conssim(void)
5697dd7cddfSDavid du Colombier {
5707dd7cddfSDavid du Colombier 	int i, n;
5717dd7cddfSDavid du Colombier 	int fd;
5727dd7cddfSDavid du Colombier 	int tries;
5737dd7cddfSDavid du Colombier 	char buf[128];
5747dd7cddfSDavid du Colombier 	char *field[10];
5757dd7cddfSDavid du Colombier 
5767dd7cddfSDavid du Colombier 	/* a pipe to simulate the /dev/cons */
5777dd7cddfSDavid du Colombier 	if(bind("#|", "/mnt/cons/cons", MREPL) < 0)
5787dd7cddfSDavid du Colombier 		fatal("/dev/cons1", 0, 0);
5797dd7cddfSDavid du Colombier 	if(bind("/mnt/cons/cons/data1", "/dev/cons", MREPL) < 0)
5807dd7cddfSDavid du Colombier 		fatal("/dev/cons2", 0, 0);
5817dd7cddfSDavid du Colombier 
5827dd7cddfSDavid du Colombier 	/* a pipe to simulate consctl */
5837dd7cddfSDavid du Colombier 	if(bind("#|", "/mnt/cons/consctl", MBEFORE) < 0
5847dd7cddfSDavid du Colombier 	|| bind("/mnt/cons/consctl/data1", "/dev/consctl", MREPL) < 0)
5857dd7cddfSDavid du Colombier 		fatal("/dev/consctl", 0, 0);
5867dd7cddfSDavid du Colombier 
5877dd7cddfSDavid du Colombier 	/* a process to read /dev/consctl and set the state in cons */
5887dd7cddfSDavid du Colombier 	switch(fork()){
5897dd7cddfSDavid du Colombier 	case -1:
5907dd7cddfSDavid du Colombier 		fatal("forking", 0, 0);
5917dd7cddfSDavid du Colombier 	case 0:
5927dd7cddfSDavid du Colombier 		break;
5937dd7cddfSDavid du Colombier 	default:
5947dd7cddfSDavid du Colombier 		return open("/mnt/cons/cons/data", ORDWR);
5957dd7cddfSDavid du Colombier 	}
5967dd7cddfSDavid du Colombier 
5977dd7cddfSDavid du Colombier 	for(tries = 0; tries < 100; tries++){
5987dd7cddfSDavid du Colombier 		cons->raw = 0;
5997dd7cddfSDavid du Colombier 		cons->hold = 0;
6007dd7cddfSDavid du Colombier 		fd = open("/mnt/cons/consctl/data", OREAD);
6017dd7cddfSDavid du Colombier 		if(fd < 0)
6027dd7cddfSDavid du Colombier 			continue;
6037dd7cddfSDavid du Colombier 		tries = 0;
6047dd7cddfSDavid du Colombier 		for(;;){
6057dd7cddfSDavid du Colombier 			n = read(fd, buf, sizeof(buf)-1);
6067dd7cddfSDavid du Colombier 			if(n <= 0)
6077dd7cddfSDavid du Colombier 				break;
6087dd7cddfSDavid du Colombier 			buf[n] = 0;
6097dd7cddfSDavid du Colombier 			n = getfields(buf, field, 10, 1, " ");
6107dd7cddfSDavid du Colombier 			for(i = 0; i < n; i++){
6117dd7cddfSDavid du Colombier 				if(strcmp(field[i], "rawon") == 0) {
6127dd7cddfSDavid du Colombier 					if(debug) fprint(2, "raw = 1\n");
6137dd7cddfSDavid du Colombier 					cons->raw = 1;
6147dd7cddfSDavid du Colombier 				} else if(strcmp(field[i], "rawoff") == 0) {
6157dd7cddfSDavid du Colombier 					if(debug) fprint(2, "raw = 0\n");
6167dd7cddfSDavid du Colombier 					cons->raw = 0;
6177dd7cddfSDavid du Colombier 				} else if(strcmp(field[i], "holdon") == 0) {
6187dd7cddfSDavid du Colombier 					cons->hold = 1;
6197dd7cddfSDavid du Colombier 					if(debug) fprint(2, "raw = 1\n");
6207dd7cddfSDavid du Colombier 				} else if(strcmp(field[i], "holdoff") == 0) {
6217dd7cddfSDavid du Colombier 					cons->hold = 0;
6227dd7cddfSDavid du Colombier 					if(debug) fprint(2, "raw = 0\n");
6237dd7cddfSDavid du Colombier 				}
6247dd7cddfSDavid du Colombier 			}
6257dd7cddfSDavid du Colombier 		}
6267dd7cddfSDavid du Colombier 		close(fd);
6277dd7cddfSDavid du Colombier 	}
6287dd7cddfSDavid du Colombier 	exits(0);
6297dd7cddfSDavid du Colombier 	return -1;
6307dd7cddfSDavid du Colombier }
6317dd7cddfSDavid du Colombier 
6327dd7cddfSDavid du Colombier int
alnum(int c)6337dd7cddfSDavid du Colombier alnum(int c)
6347dd7cddfSDavid du Colombier {
6357dd7cddfSDavid du Colombier 	/*
6367dd7cddfSDavid du Colombier 	 * Hard to get absolutely right.  Use what we know about ASCII
6377dd7cddfSDavid du Colombier 	 * and assume anything above the Latin control characters is
6387dd7cddfSDavid du Colombier 	 * potentially an alphanumeric.
6397dd7cddfSDavid du Colombier 	 */
6407dd7cddfSDavid du Colombier 	if(c <= ' ')
6417dd7cddfSDavid du Colombier 		return 0;
6427dd7cddfSDavid du Colombier 	if(0x7F<=c && c<=0xA0)
6437dd7cddfSDavid du Colombier 		return 0;
6447dd7cddfSDavid du Colombier 	if(strchr("!\"#$%&'()*+,-./:;<=>?@`[\\]^{|}~", c))
6457dd7cddfSDavid du Colombier 		return 0;
6467dd7cddfSDavid du Colombier 	return 1;
6477dd7cddfSDavid du Colombier }
648