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