allbery@ncoast.UUCP (05/29/87)
This program lets a super-user enter commands or data on a terminal other than his own. Handy for logging people off -- just force ttyB4 logout instead of 'ps auxt' and 'kill -HUP'. Also more fun :-). It is known to run on 4.3 BSD; it will definitely run on 4.2 BSD; it may run on V7 or SIII or even S5 -- basically, if you have TIOCSTI, you can use this. I found this program in our public sources directory; it has no authorship in the comments, which means it probably belongs to ATT :-), but it's simple and short enough that it looks like it was done locally -- just way, way before my time. It was called 'type.c', but because it matches the function of a program in my old Alpha-Micro days called "force", I call it that here. The usage message thinks it's called "type", so you can call it that, too, if you want. Actually I don't care what you call it. ----------------------------cut here for force.c--------------------------- #include <sgtty.h> #include <sys/file.h> #include <stdio.h> #include <sys/param.h> #include <strings.h> /* * type - make the system think that a command was entered on * another user's terminal. * * type [-n] <terminal> <command> * * <terminal> is the line that the command should be entered on. * examples: "/dev/ttyj4" ; "ttyj4" ; "j4" * * <command> is the command that should be entered on that terminal. * examples: "logout" ; "jobs > /dev/console" * * a newline will be appended to <command> unless type is given a "-n" * option. * * type can only be used on the terminal you are on, unless you are the * superuser, in which case you can send commands to any terminal. */ static int fd; /* file descriptor for terminal line */ extern int wakeup(); /* routine to wakeup if open of terminal line hangs */ main(argc, argv, environ) int argc; char *argv[], *environ[]; { int flag_n; /* do not append newline to <command> */ if ( argc <= 1 ) { usage(); } if ( argv[1][0] == '-' ) { switch ( argv[1][1] ) { case 'n' : flag_n++; break; case '-' : break; default: usage(); break; } argc--, argv++; } if ( argc < 3 ) { usage(); } if ( index( argv[1], '/' ) == NULL ) { char terminal[MAXPATHLEN+1]; /* * since a full pathname was not given, assume the * file is in the "/dev" directory, and if only 2 * characters were given, assume that means a "tty". */ strcpy( terminal, "/dev/" ); if (strlen(argv[1]) == 2) strcat( terminal, "tty" ); argv[1] = strcat( terminal, argv[1] ); } /* * O_NDELAY does not work (?), so set a timer to * wake up if the open hangs. */ signal( SIGALRM, wakeup ); alarm( 30 ); if ( (fd = open(argv[1], O_WRONLY|O_NDELAY, 0)) < 0 ) { perror( "open" ); exit( 2 ); } else { char *cp = argv[2]; alarm( 0 ); while ( *cp != '\0' ) { send( *cp ); cp++; } if ( ! flag_n ) send( '\n' ); } } usage() { fprintf( stderr, "usage: type [-n] <terminal> <command>\n" ); exit( 1 ); } send( c ) char c; { register int status; status = ioctl( fd, TIOCSTI, &c ); if ( status != 0 ) { perror( "ioctl" ); exit( 3 ); } return status; } wakeup() { fprintf( stderr, "open hung\n" ); exit( 4 ); } -----------------------------------cut here-------------------------------- -- Brandon S. Allbery {decvax,cbatt,cbosgd}!cwruecmp!ncoast!allbery Tridelta Industries {ames,mit-eddie,talcott}!necntc!ncoast!allbery 7350 Corporate Blvd. necntc!ncoast!allbery@harvard.HARVARD.EDU Mentor, OH 44060 +01 216 255 1080 (also eddie.MIT.EDU)
allbery@ncoast.UUCP (06/02/87)
From: jjg@linus.UUCP (Jeff Glass) In article <8705291811.AA23508@ubvax.ub.com> allbery@ncoast.UUCP (Brandon S. Allbery) writes: [no, he doesn't; but I've commented on this before. ++bsa] > This program lets a super-user enter commands or data on a terminal other > than his own. Handy for logging people off -- just > force ttyB4 logout > instead of 'ps auxt' and 'kill -HUP'. Also more fun :-). It is known to > run on 4.3 BSD; it will definitely run on 4.2 BSD; it may run on V7 or SIII > or even S5 -- basically, if you have TIOCSTI, you can use this. > I found this program in our public sources directory; it has no authorship > in the comments, which means it probably belongs to ATT :-), but it's simple > and short enough that it looks like it was done locally -- just way, way > before my time. I wrote this program a while ago. Here's the latest version, which allows you to use '\' (e.g., '\037' and '\n') and '^' (e.g., '^S') escape sequences: ---------- cut here --------- #!/bin/sh sed 's/^X//' << 'END' > type.c X#include <sgtty.h> X#include <sys/file.h> X#include <stdio.h> X#include <sys/param.h> X#include <strings.h> X#include <ctype.h> X X/* X * Jeff Glass, The MITRE Corporation, 5/14/87 X * X * type - make the system think that a command was entered on X * another user's terminal. X * X * type [-n] <terminal> <command> ... X * X * <terminal> is the line that the command should be entered on. X * examples: "/dev/ttyj4" ; "ttyj4" ; "j4" X * X * <command> is the command that should be entered on that terminal. X * examples: "logout" ; "jobs > /dev/console" X * X * a newline will be appended to <command> unless type is given a "-n" X * option. a space will be appended after each command except the last. X * command can have '\nnn' and '\[tbnr]' and '^[SQC]' escapes in it. X * X * type can only be used on the terminal you are on, unless you are the X * superuser, in which case you can send commands to any terminal. X */ X Xstatic int fd; /* file descriptor for terminal line */ Xstatic char *name; /* argv[0] */ Xextern int wakeup(); /* routine to wakeup if open of terminal line hangs */ X Xmain(argc, argv, environ) Xint argc; Xchar *argv[], *environ[]; X{ X int flag_n; /* do not append newline to <command> */ X int opt; X extern int optind; X X name = argv[0]; X while ( (opt = getopt(argc,argv,"n")) != EOF ) { X switch ( opt ) { X case 'n' : X flag_n++; X break; X default: X usage(); X break; X } X } X if ( (optind+2) > argc ) { X usage(); X } X X if ( index( argv[optind], '/' ) == NULL ) { X char terminal[MAXPATHLEN+1]; X X /* X * since a full pathname was not given, assume the X * file is in the "/dev" directory, and if only 2 X * characters were given, assume that means a "tty". X */ X strcpy( terminal, "/dev/" ); X if (strlen(argv[optind]) == 2) X strcat( terminal, "tty" ); X argv[optind] = strcat( terminal, argv[optind] ); X } X X /* X * O_NDELAY does not work (?), so set a timer to X * wake up if the open hangs. X */ X X signal( SIGALRM, wakeup ); X alarm( 30 ); X X if ( (fd = open(argv[optind], O_RDONLY|O_NDELAY, 0)) < 0 ) { X perror( "open" ); X exit( 2 ); X } else { X int i; X X alarm( 0 ); X X for (i = optind+1; i < argc; i++) { X if (sendstr(argv[i]) != 0) X exit(3); X if (i != (argc-1)) X if (send(' ') != 0) X exit(3); X } X X if ( ! flag_n ) X if (send('\n')) X exit(3); X } X} X Xusage() X{ X fprintf( stderr, "%s: usage: %s [-n] <terminal> <command> ...\n", X name, X name ); X exit( 1 ); X} X Xsend( c ) Xchar c; X{ X register int status; X X if ( (status = ioctl(fd,TIOCSTI,&c)) != 0 ) X perror( "ioctl" ); X X return status; X} X X/* X * send a string to the terminal, but do some translation (such as '\012' X * or '\n' for newline, or '^S' for CTRL-S). X */ Xsendstr(cp) Xchar *cp; X{ X short ch, in_bslash, in_carat; X X ch = in_bslash = in_carat = 0; X X /* X * this is a FSM (don't laugh!), where the states are : X * in_bslash == 1 X * in_bslash > 1 X * in_carat == 1 X * in_bslash == 0 && in_carat == 0 X * X * whenever the FSM is in the state (in_bslash == 0 && in_carat == 0), X * it prints out the character held in ch. X */ X while (*cp != '\0' ) { X if (in_bslash) { X if (isascii(*cp) && isdigit(*cp)) { X ch = ch * 8 + *cp - '0'; X if (in_bslash < 3) X in_bslash++; X else X in_bslash = 0; X } else if (in_bslash == 1) { X switch (*cp) { X case 'b' : ch = '\b'; break; X case 'f' : ch = '\f'; break; X case 'n' : ch = '\n'; break; X case 'r' : ch = '\r'; break; X case 't' : ch = '\t'; break; X default : ch = *cp ; break; X } X in_bslash = 0; X } else { X /* X * this character terminated a '\nn', X * so back up cp so this character is X * seen again. X */ X cp--; X in_bslash = 0; X } X } else if (in_carat) { X if (*cp == '?') X ch = '\177'; X else X ch = *cp & 037; X in_carat = 0; X } else { X switch (*cp) { X case '\\' : X in_bslash = 1; X ch = 0; X break; X case '^' : X in_carat = 1; X break; X default : X ch = *cp; X break; X } X } /*else*/ X X if (!(in_bslash || in_carat)) X if (send(ch) != 0) X return 1; X cp++; X X } /*while*/ X X /* X * take care of anything left at the end of the string. X */ X if (in_bslash) { X if (send(ch) != 0) X return 1; X } else if (in_carat) { X if (send('^') != 0) X return 1; X } X X return 0; X} X Xwakeup() X{ X fprintf( stderr, "open hung\n" ); X exit( 4 ); X} END