From 305087c48cab13786b7d43a72d91d9e54d11bf0f Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Tue, 3 May 2016 16:30:57 +0100 Subject: [PATCH] From: Brett Gordon This patch adds dwterm and dwgetty (dropped them from the ucp script as they are only relevant to COCO at this point) - Alan --- Applications/dw/Makefile.6809 | 2 +- Applications/dw/dwgetty.c | 355 +++++++++++++++++++++++ Applications/dw/dwterm.c | 510 ++++++++++++++++++++++++++++++++++ 3 files changed, 866 insertions(+), 1 deletion(-) create mode 100644 Applications/dw/dwgetty.c create mode 100644 Applications/dw/dwterm.c diff --git a/Applications/dw/Makefile.6809 b/Applications/dw/Makefile.6809 index eba8d484..e2f32505 100644 --- a/Applications/dw/Makefile.6809 +++ b/Applications/dw/Makefile.6809 @@ -15,7 +15,7 @@ CRT0 = ../../Library/libs/crt0_6809.o .SUFFIXES: .c .o -SRCS = dw.c +SRCS = dw.c dwgetty.c dwterm.c OBJS = $(SRCS:.c=.o) diff --git a/Applications/dw/dwgetty.c b/Applications/dw/dwgetty.c new file mode 100644 index 00000000..55cd048f --- /dev/null +++ b/Applications/dw/dwgetty.c @@ -0,0 +1,355 @@ +/* + A Very simple getty for starting a telnet session over Drivewire 4. + +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +/* for getty/login */ +#include +#include +#include +#include +#include +#include + + +int port; +int tries=3; +char *port_txt; +char *listenMsg="tcp listen "; +char *join="tcp join "; +char conn; +struct termios new; + +static void spawn_login(struct passwd *, const char *, const char *); +static pid_t getty(const char *, const char *, int); + +static struct utmp ut; + +char buff[128]; + +void doEcho( int f ) +{ + unsigned char e[3]={ 255, 253, 1 }; + write( f, e, 3 ); +} + +void dontEcho( int f ) +{ + unsigned char e[3]={ 255, 254, 1 }; + write( f, e, 3 ); +} + +void willEcho( int f ) +{ + unsigned char e[3]={ 255, 251, 1 }; + write( f, e, 3 ); +} + +void wontEcho( int f ) +{ + unsigned char e[3]={ 255, 252, 1 }; + write( f, e, 3 ); +} + +void getrply( int f ) +{ + unsigned char e[3]; + read( f, e, 3 ); +} + + +#define crlf() write(1, "\r\n", 2) + +void sigalarm(int sig) +{ + return; +} + +void putstr(char *str) +{ + write(1, str, strlen(str)); +} + +int showfile(char *fname) +{ + int fd, len; + char buf[80]; + + fd = open(fname, O_RDONLY); + if (fd >= 0) { + do { + len = read(fd, buf, 80); + write(1, buf, len); + } while (len > 0); + close(fd); + return 1; + } + return 0; +} + +static char *env[10]; +static int envn; + +static void envset(const char *a, const char *b) +{ + int al = strlen(a); + static char hptr[5]; + /* May unalign the memory pool but we don't care by this point */ + char *tp = sbrk(al + strlen(b) + 2); + if (tp == (char *) -1) { + putstr("out of memory.\n"); + return; + } + strcpy(tp, a); + tp[al] = '='; + strcpy(tp + al + 1, b); + env[envn++] = tp; +} + +static char *argp[] = { "sh", NULL }; + +static void spawn_login(struct passwd *pwd, const char *tty, const char *id) +{ + char *p, buf[50]; + /* utmp */ + ut.ut_type = USER_PROCESS; + ut.ut_pid = getpid(); + strncpy(ut.ut_line, tty+5, UT_LINESIZE); + strncpy(ut.ut_id, id, 2); + time(&ut.ut_time); + strncpy(ut.ut_user, pwd->pw_name, UT_NAMESIZE); + pututline(&ut); + endutent(); + + /* We don't care if initgroups fails - it only grants extra rights */ + initgroups(pwd->pw_name, pwd->pw_gid); + + /* But we do care if these fail! */ + if (setgid(pwd->pw_gid) == -1 || + setuid(pwd->pw_uid) == -1) + _exit(255); + signal(SIGINT, SIG_DFL); + + /* setup user environment variables */ + + envset("LOGNAME", pwd->pw_name); + envset("HOME", pwd->pw_dir); + envset("SHELL", pwd->pw_shell); + + /* home directory */ + + if (chdir(pwd->pw_dir)) + putstr("login: unable to change to home directory, using /\n"); + + /* show the motd file */ + + if (!showfile("/etc/motd")) + crlf(); + + /* and spawn the shell */ + + strcpy(buf, "-"); + if ((p = strrchr(pwd->pw_shell, '/')) != NULL) + strcat(buf, ++p); + else + strcat(buf, pwd->pw_shell); + + argp[0] = buf; + argp[1] = NULL; + + execve(pwd->pw_shell, (void *) argp, (void *) env); + putstr("login: can't execute shell\n"); + exit(1); +} + +/* + getpass.c implimented for TELNET +*/ + +#define EOF (-1) + +static int __getchar(int fd) +{ + static char ch; + return (read(fd, &ch, 1) == 1) ? ch : EOF; +} + +static char *_gets(int fd, char *buf, int len) +{ + int ch, i = 0; + + while (i < len) { + if ((ch = __getchar(fd)) == EOF && i == 0) + return NULL; + if (ch == '\n' || ch == '\r') + break; + buf[i++] = ch; + } + buf[i] = 0; + return buf; +} + +char *getpass(char *prompt) +{ + static char result[128]; + + /* display the prompt */ + write(1, prompt, strlen(prompt)); + + willEcho(1); + getrply(0); + /* read the input */ + if (_gets(0, result, sizeof(result) - 1) == NULL) + result[0] = 0; + wontEcho(1); + /* The newline isn't echoed as we have echo off, so we need to + output it as the end of the task */ + write(1, "\n", 1); + return result; +} + + + +/* + * Internal implementation of "getty" and "login" + */ +static pid_t getty(const char *ttyname, const char *id, int fdtty) +{ + struct passwd *pwd; + const char *pr; + char *p, buf[50], salt[3]; + char hn[64]; + gethostname(hn, sizeof(hn)); + + for (;;) { + close(0); + close(1); + close(2); + setpgrp(); + setpgid(0,0); + + /* here we are inside child's context of execution */ + envset("PATH", "/bin:/usr/bin"); + envset("CTTY", ttyname); + + /* make stdin, stdout and stderr point to fdtty */ + + dup(fdtty); + dup(fdtty); + dup(fdtty); + close(fdtty); + + /* display the /etc/issue file, if exists */ + showfile("/etc/issue"); + if (*hn) { + putstr(hn); + putstr(" "); + } + /* loop until a valid user name is entered + * and a shell is spawned */ + + for (;;) { + putstr("login: "); + while (read(0, buf, 20) < 0); /* EINTR might happens because of the alarm() call below */ + + if ((p = strchr(buf, '\n')) != NULL) + *p = '\0'; /* strip newline */ + + pwd = getpwnam(buf); + + if (pwd) { + if (pwd->pw_passwd[0] != '\0') { + p = getpass("Password: "); + salt[0] = pwd->pw_passwd[0]; + salt[1] = pwd->pw_passwd[1]; + salt[2] = '\0'; + pr = crypt(p, salt); + } else { + pr = ""; + } + if (strcmp(pr, pwd->pw_passwd) == 0) + spawn_login(pwd, ttyname, id); + } + if( !--tries ){ + putstr("\nToo Many Attempts\n\n"); + exit(1); + } + putstr("\nLogin incorrect\n\n"); + signal(SIGALRM, sigalarm); + alarm(2); + pause(); + } + } +} + + + +void pute( char *mess ) +{ + write( 2, mess, strlen(mess) ); +} + + +// dwgetty tty port +// dwgetty /dev/tty3 6809 +int main( int argc, char *argv[]) +{ + int f; + + + if( argc<3){ + pute("usage: dwgetty tty port\n" ); + exit(-1); + } + + port=atoi( argv[2] ); + port_txt=argv[2]; + + f=open( argv[1], O_RDWR ); + if( ! f ){ + pute("Cannot open device file\n" ); + exit(-1); + } + + tcgetattr( f, &new ); + new.c_iflag |= ICRNL; + new.c_iflag &= ~IGNCR; + // new.c_oflag |= OPOST | ONLCR; + // new.c_oflag &= ~ONLCR; + new.c_lflag &= ~ECHO; + tcsetattr( f, TCSANOW, &new ); + + int i; + int len; + + write(f,listenMsg,strlen(listenMsg) ); + write(f,port_txt,strlen(port_txt) ); + write(f,"\r",1); + + for( i=0; i<4; i++){ + len=read(f,buff,128); + } + conn=buff[0]; + + write(f, join, strlen(join) ); + write(f, &conn, 1 ); + write(f, "\r", 1 ); + len=read(f,buff,128); + + new.c_iflag |= IGNCR; + tcsetattr( f, TCSANOW, &new ); + char c[2]; + c[0]='0'; + c[1]=argv[1][strlen(argv[1])-1]; + getty( argv[1], c, f ); +} + + diff --git a/Applications/dw/dwterm.c b/Applications/dw/dwterm.c new file mode 100644 index 00000000..706a493e --- /dev/null +++ b/Applications/dw/dwterm.c @@ -0,0 +1,510 @@ +/* dwtelnet - Drivewire - raw Telnet + */ +#include +#include +#include +#include +#include +#include +#include + + +#define TESC 0x19 +#define ESC 0x1b + + +char ibuf[256]; +int opos=0; + +int flags; +struct termios prior,new; +struct termios lprior,lnew; +int fddw; +int para[4]={0,0,0,0}; +int no=0; +char colors[8]={ + '0', '2', '4', '6', + '1', '3', '5', '7' +}; + +int linemode=0; +int lecho=-1; +int pflag=0; +int hex=0; +int del=0; +int crnl=-1; +int fc=7; +int bc=0; +int inten=0; + + +void puterr( char *str ){ + write(2, str, strlen(str)); +} + +void putstr( char *str ){ + write(1, str, strlen(str)); +} + +int isnum( char c ){ + if( c>='0' && c<='9' ) return 1; + return 0; +} + +int tonum( char c ){ + return c-'0'; +} + +void out52( char c ){ + write(1, "\x1b", 1 ); + write(1,&c, 1 ); +} + +void out52n( char c, char n ){ + out52( c ); + write(1,&n, 1 ); +} + +void out52nn( char c, char n, char m){ + out52( c ); + write(1,&n,1); + write(1,&m,1); +} + + +char cconv( char c ){ + return colors[c]; +} + + +/* check for matching fore/background colors w/ intensity bit + we can't do intensity - so text disappears */ +void ckint(){ + if( (fc == bc) && inten ){ + fc = fc + 1 & 0x7 ; + out52n( 'b', fc ); + } +} + +/* Send a char to the console, processing for ANSI/TELNET chars */ +void charout( char c ){ + static char mode=0; + int i; + + switch( mode ){ + /* normal mode */ + case 0: + if( c == 255 ){ + mode=3; + return; + } + if( c != ESC ) write( 1, &c ,1 ); + else{ + mode=1; + } + return; + /* ESC detected */ + case 1: + if( c=='[' ){ + mode=2; + return; + } + return; + /* Multi-byte detected */ + case 2: + if( isnum(c) ){ + para[no]=para[no]*10+tonum(c); + return; + } + if( c == ';' ){ + no++; + return; + } + no++; + goto final; + /* Telnet IAC detected */ + case 3: + switch( c ){ + case 255: + write(1,&c,1); + mode=0; + return; + + case 251: + mode=5; + return; + case 252: + mode=6; + return; + case 253: + case 254: + if(hex) printf("<%x>",c); + mode=4; + return; + } + mode=0; + return; + /* send Telnet's WILLNOTs to server */ + case 4: + if( hex )printf("<%x>\n", c ); + write( fddw, "\xff\xfc",2); + write( fddw, &c, 1 ); + mode = 0; + return; + /* received a WILL */ + case 5: + if( c == 1 ){ + lecho = 0; + //write(fddw,"\xff\xfd",2); + //write(fddw, &c, 1 ); + mode = 0; + return; + } + write( fddw,"\xff\xfe",2); + write( fddw, &c, 1); + mode = 0; + return; + /* received a WONT */ + case 6: + if( hex ) printf("opt<%x>\n", c ); + if( c == 1 ) lecho = -1; + else{ + write( fddw, "\xff\xfe", 2 ); + write( fddw, &c, 1 ); + } + mode = 0; + return; + + } + /* and the trailing command */ + final: + // printf("DEBUG: %d %d %d %c\n", para[0], para[1], para[2], c); + switch( c ){ + case 'J': + if( para[0] == 2 ){ + out52( 'H' ); + out52( 'J' ); + break; + } + if( para[1] == 0 ){ + out52( 'J' ); + break; + } + case 'H': + case 'f': + if( para[0]==0 && para[1]==0 ){ + out52( 'H' ); + break; + } + if( para[0]==0 ) para[0]=1; + if( para[1]==0 ) para[1]=1; + out52nn( 'Y', para[0]+' ', para[1]+' '); + break; + case 'K': + if( para[0] == 0 ){ + out52( 'K'); + break; + } + case 'm': + for( i=0; i=30 && para[i]<=37 ){ + fc=cconv(para[i]-30); + out52n( 'b', fc ); + ckint(); + } + if( para[i]>=40 && para[i]<=47 ){ + bc=cconv(para[i]-40); + out52n( 'c', bc ); + ckint(); + } + if( para[i]==0 ){ + out52n( 'b', '4' ); + out52n( 'c', '0' ); + inten=0; + } + if( para[i]==1 ){ + inten=1; + ckint(); + } + } + break; + case 'C': + case 'D': + case 'A': + case 'B': + if( para[0]==0 ) para[0]=1; + for( i=0; i-1 ){ + switch( opt ){ + case 'p': + pflag=1; + break; + } + } + + + tcgetattr( 0, &lprior ); + + my_open( argc, argv ); + + flags = fcntl(0, F_GETFL, 0); + fcntl(0, F_SETFL, flags | O_NDELAY ); + + + tcgetattr( 0, &lnew ); + lnew.c_lflag &= ~ICANON; + lnew.c_lflag &= ~ECHO; + tcsetattr( 0, TCSANOW, &lnew ); + + printf("Use Cntl-A ? for help.\n"); + + while(1){ + char *pos=ibuf; + len=myread(); + while( len > 0 ){ + int ret = write( fddw, pos, len ); + if( ret < 0 ){ + if( errno == EAGAIN ){ + ret=0; + } + else { + close(fddw); + if( pflag ){ + my_open( argc, argv ); + continue; + } + else quit(); + } + } + len=len-ret; + pos+=ret; + } + len=read( fddw, ibuf, 127 ); + if( len < 0 ){ + if( errno != EAGAIN ){ + close(fddw); + if( pflag ){ + my_open( argc, argv ); + continue; + } + else quit(); + } + } + pos = ibuf; + while( len > 0){ + int ret = mywrite( pos, len ); + if( ret < 0 ){ + if( errno == EWOULDBLOCK ){ + ret=0; + } + else quit(); + } + len=len-ret; + pos+=ret; + } + } +} + + + -- 2.34.1