[comp.lang.c] Catching ^C and ^Z

deen@utopia.rutgers.edu (Cinnamon Raisin) (09/05/90)

Hi boys and girls,

	I am trying to write a quick programme to lock a terminal(TTY)
	when I leave it.  Essentially I want to capture all the 
	interrupts that can be sent from the keyboard, such as
	SIG_INT,SIG_QUIT and so on.  The only reasonable thing I've 
	found that lets me do this is ioctl().

	Essentially I need to get all the characters from the keyboard
	in the RAW mode, sos I can process them myself.  How can I do
	this.  The unix ref is a bit hazy on the topic and the mann page
	makes no mention of the RAW mode.

		I know I need to capture the current mode, 
		push my mode onto the system
		deal with the passwords and junk from keyboard
		and restore the captured mode.

	The following is a short programme I wrote to test this out, 
	but it dumps on me, and I don't know why.


------------

#include <stdio.h>
#include <sys/ioctl.h>
#include <sgtty.h>
char TMP;			/* to hold keyboard entry */
struct sgttyb *TTY;		/* From unix ref	  */

int main(void)
{
  ioctl(0,TIOCGETP,TTY);	/* Get current status	  */
  TTY->sg_flags = RAW | ECHO;   /* Unprocessed and echoed */
  ioctl(0,TIOCSETN,TTY);	/* to the screen	  */
  while(1 == 1) {TMP = getchar();} 
  exit(0);
}

------------

	Do I have the calling parameters typed wrongly or somethin?

					...Tanx in Advanz...

					-Z Raisin
-- 
---
"May The Prezent Tenz Be With You."
-The Super Amazin Cinnamon Raisin
 deen@police.rutgers.edu

brnstnd@kramden.acf.nyu.edu (Dan Bernstein) (09/05/90)

In article <Sep.4.20.08.17.1990.1216@utopia.rutgers.edu> deen@utopia.rutgers.edu (Cinnamon Raisin) writes:
> 	I am trying to write a quick programme to lock a terminal(TTY)
> 	when I leave it.  Essentially I want to capture all the 
> 	interrupts that can be sent from the keyboard, such as
> 	SIG_INT,SIG_QUIT and so on.  The only reasonable thing I've 
> 	found that lets me do this is ioctl().

A public-domain ``lock'' appears in the pty package. It should answer
all your questions. Watch c.s.unix.

---Dan

weisen@eniac.seas.upenn.edu (Neil Weisenfeld) (09/05/90)

In article <Sep.4.20.08.17.1990.1216@utopia.rutgers.edu>, deen@utopia (Cinnamon Raisin) writes:
>
>Hi boys and girls,
>
>	I am trying to write a quick programme to lock a terminal(TTY)
>	when I leave it.  Essentially I want to capture all the 
>	interrupts that can be sent from the keyboard, such as
>	SIG_INT,SIG_QUIT and so on.  The only reasonable thing I've 
>	found that lets me do this is ioctl().
[stuff deleted]

I remember doing this a while ago.  What UNIX are you running?  Under BSD,
you should be able to do something like:
	signal(SIGINT,SIG_IGN);
	signal(SIGQUIT,SIG_IGN);
to IGNore the signals.  Using SIG_DFL should return them to their default
handlers.  You can also substitute a pointer to a handler of your own.  Take
a look at signal(3) and sigvec(2).

Neil

_____________________________________________________________________________
( ) _     ( )   Neil Weisenfeld                            | 3900 Chestnut St.
( )(_)_   ( )   Computer Science and Engineering           | Apt. 233
( )  (_)_ ( )   School of Engineering and Applied Science  | Philadelphia, PA
( )    (_)( )   University of Pennsylvania		   |	        19104
(_)       (_)   Class of 1991                              |
-----------------------------------------------------------------------------
--
_____________________________________________________________________________
( ) _     ( )   Neil Weisenfeld                            | 3900 Chestnut St.
( )(_)_   ( )   Computer Science and Engineering           | Apt. 233
( )  (_)_ ( )   School of Engineering and Applied Science  | Philadelphia, PA

gaynor@sparky.rutgers.edu (Silver) (09/05/90)

deen@utopia.rutgers.edu:
> [I wanna write a lockscreen.]

weisen@eniac.seas.upenn.edu:
> Under BSD, you should be able to do something like:
>        signal(SIGINT,SIG_IGN);
>        signal(SIGQUIT,SIG_IGN);
> to IGNore the signals.

SunOS signal(3):
> SIGKILL   9    kill (cannot be caught, blocked, or ignored)
> SIGSTOP   17   stop (cannot be caught, blocked, or ignored)

Therein lies the incentive to capture the characters before a shell can see
them.

Regards, [Ag]

nts0302@dsacg3.dsac.dla.mil (Bob Fisher) (09/05/90)

From article <Sep.4.20.08.17.1990.1216@utopia.rutgers.edu>, by deen@utopia.rutgers.edu (Cinnamon Raisin):
> 
> 	I am trying to write a quick programme to lock a terminal(TTY)
> 	when I leave it.  Essentially I want to capture all the 
> 	interrupts that can be sent from the keyboard, such as
> 	SIG_INT,SIG_QUIT and so on.  The only reasonable thing I've 
> 	found that lets me do this is ioctl().

Here's a quickie that we use on our BSD systems.  I know this isn't the
right group to post to, but it's small.  It's based on a book on Unix
security - Pat Woods, I think.


#include <stdio.h>
#include <signal.h>
main ()
{
static char rcsid[]="$Header: termlock.c,v 1.2 89/02/13 15:29:12 root Exp $";
char         passbuf[20], *passwd, *getpass ();
int      validentry = 0;
if(strcmp(ttyname(0), "/dev/console") == 0)
	{
	printf("\nYOU CAN'T LOCK THE CONSOLE\n\n");
	return(0);
	}
printf("\n\nThis process enables you to lock your terminal without\n");
printf("logging out.  A password provided by you will be required\n");
printf("to re-activate this terminal.  Don't forget it.\n\n");
while ( ! validentry )
	{
	strcpy (passbuf, getpass ("Enter password: "));
	if ( strlen (passbuf) < 4 )
		printf ("Please enter at least four characters\n");
	else
		validentry = 1;
	}
signal (SIGINT, SIG_IGN);
signal (SIGQUIT, SIG_IGN);
signal (SIGSTOP, SIG_IGN);
signal (SIGTSTP, SIG_IGN);
printf ("\n\n\n\n\n\n\n");
printf ("\t\t********************************************\n");
printf ("\t\t*                                          *\n");
printf ("\t\t*                                          *\n");
printf ("\t\t*                                          *\n");
printf ("\t\t*             TERMINAL LOCKED !!!          *\n");
printf ("\t\t*                                          *\n");
printf ("\t\t*                                          *\n");
printf ("\t\t*                                          *\n");
printf ("\t\t********************************************\n");
printf ("\n\n\n\n\n\n\n");
validentry = 0;
while ( ! validentry )
	{
        passwd = getpass ("Enter password: ");
        if ( strcmp (passwd, passbuf) != 0 )
		{
		printf ("Bad password, try again.\n");
		}
	else
	validentry = 1;
	}
system("clear");
return(0);
}

-- 
Bob Fisher
US Defense Logistics Agency Systems Automation Center
DSAC-TSX, Box 1605, Columbus, OH 43216-5002     614-238-9071 (AV 850-9071)
bfisher@dsac.dla.mil		osu-cis!dsacg1!bfisher

vu0310@bingvaxu.cc.binghamton.edu (R. Kym Horsell) (09/05/90)

In article <Sep.4.20.08.17.1990.1216@utopia.rutgers.edu> deen@utopia.rutgers.edu (Cinnamon Raisin) writes:
\\\
>#include <stdio.h>
>#include <sys/ioctl.h>
>#include <sgtty.h>
>char TMP;			/* to hold keyboard entry */
>struct sgttyb *TTY;		/* From unix ref	  */
>
>int main(void)
>{
>  ioctl(0,TIOCGETP,TTY);	/* Get current status	  */
>  TTY->sg_flags = RAW | ECHO;   /* Unprocessed and echoed */
>  ioctl(0,TIOCSETN,TTY);	/* to the screen	  */
>  while(1 == 1) {TMP = getchar();} 
>  exit(0);

A small problem here -- where's the storage for the ioctl buffer?
You have only defined the _pointer_ to that storage area.

What you need is
...
struct sgttyb buffer;
...
ioctl(...,&buffer);
...

And then _maybe_... There are a few conflicting standards
for controlling terminals these days (oh, for the good old
(simple) days of sgtty)! You may want to look up the
``termio'' stuff in your documentation.

-Kym Horsell
======

P.S. Be careful not to lock up your terminal >:-)

dcm@toysrus.uucp (dcm) (09/05/90)

In article <Sep.5.01.20.23.1990.18603@sparky.rutgers.edu> gaynor@sparky.rutgers.edu (Silver) writes:
>deen@utopia.rutgers.edu:
>
>SunOS signal(3):
>> SIGKILL   9    kill (cannot be caught, blocked, or ignored)
>> SIGSTOP   17   stop (cannot be caught, blocked, or ignored)
>
>Therein lies the incentive to capture the characters before a shell can see
>them.


	Exactly what characters are you talking about?  At least on the
	various Un*ces I've been on, *all* keyboard generated signals are
	catchable.   Signal(SIG_IGN) has always done the job for me...

	Why complicate things with ioctls?
--------
	Craig Miller, contractor @ IBM AWD, Austin  (I don't speak for IBM)
	UUCP: ..!uunet!cs.utexas.edu!ibmaus!auschs!toysrus.austin.ibm.com!dcm

	"Just because it works doesn't means it's right, stupid!"
	"You should never install code you do not understand."
	"If you knowningly install broken code, you should be shot.  Period."
	"Programmers have to be accountable for their code."

sarima@tdatirv.UUCP (Stanley Friesen) (09/05/90)

In article <Sep.5.01.20.23.1990.18603@sparky.rutgers.edu> gaynor@sparky.rutgers.edu (Silver) writes:
>weisen@eniac.seas.upenn.edu:
>> Under BSD, you should be able to do something like:
>>        signal(SIGINT,SIG_IGN);
>>        signal(SIGQUIT,SIG_IGN);
>> to IGNore the signals.
 
>SunOS signal(3):
>> SIGKILL   9    kill (cannot be caught, blocked, or ignored)
>> SIGSTOP   17   stop (cannot be caught, blocked, or ignored)
 
>Therein lies the incentive to capture the characters before a shell can see
>them.

Except that this is totally irrelevant.  SIGKILL and SIGSTOP *cannot* be
generated by any keystroke sequence on a terminal!  They may *only* be generated
by software means, such as kill(1) or kill(2).  In addition only the owner of
the process and the superuser are allowed to do this, so they do *not* effect
the security of a lock program.
---------------------------------
uunet!tdatirv!sarima				(Stanley Friesen)
						(Teradata Corporation)
-
-
-
-
-
-

karl@haddock.ima.isc.com (Karl Heuer) (09/06/90)

>>>[deen@utopia.rutgers.edu wants to lock the terminal]
>>[weisen@eniac.seas.upenn.edu suggests using signal() instead of ioctl()]
>[gaynor@sparky.rutgers.edu notes that SIGKILL/SIGSTOP can't be trapped]

Irrelevant, since those signals can't be generated from the keyboard.

Karl W. Z. Heuer (karl@kelp.ima.isc.com or ima!kelp!karl), The Walking Lint

will@kfw.COM (Will Crowder) (09/06/90)

In article <Sep.4.20.08.17.1990.1216@utopia.rutgers.edu> deen@utopia.rutgers.edu (Cinnamon Raisin) writes:
>
>Hi boys and girls,
>[I want a lockscreen program]
>	The following is a short programme I wrote to test this out, 
>	but it dumps on me, and I don't know why.
>
>
>------------
>
>#include <stdio.h>
>#include <sys/ioctl.h>
>#include <sgtty.h>
>char TMP;			/* to hold keyboard entry */
>struct sgttyb *TTY;		/* From unix ref	  */
>
>int main(void)
>{
>  ioctl(0,TIOCGETP,TTY);	/* Get current status	  */
>  TTY->sg_flags = RAW | ECHO;   /* Unprocessed and echoed */
>  ioctl(0,TIOCSETN,TTY);	/* to the screen	  */
>  while(1 == 1) {TMP = getchar();} 
>  exit(0);
>}

You're calling ioctl() with a pointer to garbage, namely, TTY.  This
ioctl() wants a pointer to the structure to be read from/filled in,
but this structure must be defined somewhere.  Change

struct sgttyb *TTY;

to

struct sgttyb TTY;

and change both of your ioctl() calls to use &TTY instead of just TTY,
and things should be happy.  Oh, and for complete portability and
correctness, cast the &TTY to a char * or caddr_t or whatever your particular
ioctl() wants.  (man ioctl)  Oh, and yeah, you don't need that TMP variable.
Just call getchar() or whatever.  C will throw away the return value.
If you want lint to be quiet about it, say (void) getchar().

Will

P.S.  The 1 == 1 in your while statement is unnecessary.  Use while (1)
      or for (;;).  The latter is considered by many to be superior, because
      many older compilers generate better code for it.  (The reason for
      that is too lengthy to go into in this article.)

brnstnd@kramden.acf.nyu.edu (Dan Bernstein) (09/06/90)

In article <3367@awdprime.UUCP> dcm@toysrus.austin.ibm.com (Craig Miller) writes:
  [ about a ``lock'' program ]
> 	Why complicate things with ioctls?

You have to do something so that the user's keystrokes don't show up on
the screen; you may as well go all the way and basically turn off the
tty device driver. (To do this portably, use curses.)

---Dan

campbell@redsox.bsw.com (Larry Campbell) (09/06/90)

AARGGH!  What is this cruft doing in comp.lang.c??  This has *nothing* to do
with C, and *everything* to do with whatever crummy operating system you're
running on.
-- 
Larry Campbell                          The Boston Software Works, Inc.
campbell@redsox.bsw.com                 120 Fulton Street
wjh12!redsox!campbell                   Boston, MA 02109

lars@spectrum.CMC.COM (Lars Poulsen) (09/07/90)

In article <Sep.4.20.08.17.1990.1216@utopia.rutgers.edu> deen@utopia.rutgers.edu (Cinnamon Raisin) writes:
>	The following is a short programme I wrote to test this out, 
>	but it dumps on me, and I don't know why.
>------------
>
>#include <stdio.h>
>#include <sys/ioctl.h>
>#include <sgtty.h>
>char TMP;			/* to hold keyboard entry */
>struct sgttyb *TTY;		/* From unix ref	  */
>
>int main(void)
>{
>  ioctl(0,TIOCGETP,TTY);	/* Get current status	  */
>  TTY->sg_flags = RAW | ECHO;   /* Unprocessed and echoed */
>  ioctl(0,TIOCSETN,TTY);	/* to the screen	  */
>  while(1 == 1) {TMP = getchar();} 
>  exit(0);
>}

The ioctl() functions move data between internal places in the system
and a structure of type "struct sgttyb" in your program. You have
created a variable to hold a pointer to such a structure, but you have
never created a structure to actually hold the data, and your pointer
has never been initialized.

The following changes should cure the problem:
	struct sgttyb TTY;
	  ioctl(0,TIOCGETP,&TTY);	/* Get current status	  */


-- 
/ Lars Poulsen, SMTS Software Engineer
  CMC Rockwell  lars@CMC.COM

gansevle@cs.utwente.nl (Fred Gansevles) (09/07/90)

In article <Sep.4.20.08.17.1990.1216@utopia.rutgers.edu>,
deen@utopia.rutgers.edu (Cinnamon Raisin) writes:
|>
|>Hi boys and girls,
|>
|>	I am trying to write a quick programme to lock a terminal(TTY)
|>	[ stuff deleted ]
|>
|>------------
|>
|>#include <stdio.h>
|>#include <sys/ioctl.h>
|>#include <sgtty.h>
|>char TMP;			/* to hold keyboard entry */
|>struct sgttyb *TTY;		/* From unix ref	  */
  struct sgttyb TTY;
|>
|>int main(void)
|>{
|>  ioctl(0,TIOCGETP,TTY);	/* Get current status	  */
    ioctl(0,TIOCGETP,&TTY);     /* ioctl fills the pointer you pass */
|>  TTY->sg_flags = RAW | ECHO;   /* Unprocessed and echoed */
    TTY.sg_flags = RAW | ECHO;
|>  ioctl(0,TIOCSETN,TTY);	/* to the screen	  */
    ioctl(0,TIOCSETN,&TTY) 
|>  while(1 == 1) {TMP = getchar();} 
|>  exit(0);
|>}
|>
|>------------
|>
|>	Do I have the calling parameters typed wrongly or somethin?
                                               ^^^^^^^ YES.

This should do the trick.

Fred.         
________________________________________________________________________

Fred Gansevles              gansevle@cs.utwente.nl        

INF Laboratory
University Twente
Enschede
The Netherlands
_________________________________________________________________________

dhesi%cirrusl@oliveb.ATC.olivetti.com (Rahul Dhesi) (09/08/90)

>SIGKILL and SIGSTOP *cannot* be
>generated by any keystroke sequence on a terminal!

Just in case there was any doubt, let's rephrase this:

     SIGKILL and SIGSTOP cannot be generated by any keystroke
     sequence *that is given special treatment by the tty driver*.

This will forestall somebody piping up with "What about the keystroke
sequence 'k' 'i' 'l' 'l' blank dash '9'?"
--
Rahul Dhesi <dhesi%cirrusl@oliveb.ATC.olivetti.com>
UUCP:  oliveb!cirrusl!dhesi

mat@mole-end.UUCP (Mark A Terribile) (09/08/90)

> > [I wanna write a lockscreen.]
 
> weisen@eniac.seas.upenn.edu:
> > Under BSD, you should be able to do something like:
> >        signal(SIGINT,SIG_IGN);
> >        signal(SIGQUIT,SIG_IGN);
> > to IGNore the signals.
 
> SunOS signal(3):
> > SIGKILL   9    kill (cannot be caught, blocked, or ignored)
> > SIGSTOP   17   stop (cannot be caught, blocked, or ignored)
 
> Therein lies the incentive to capture the characters before a shell can see
> them.

Well, if you are under SunOS you already have a very nice lockscreen, at
least in all the windowing environments.

BUT

^C does NOT generate a SIGKILL, it generates a SIGINT (or does SunOS still
call it a SIGDEL ?)  That certainly CAN be caught or ignored.  To prevent
being SIGSTOPped, you read the terminal modes ( ioctl() ) to determine the
present stop character, SET the stop character to NUL (thereby disabling
the feature) and RESTORE the stop character before you go away.

This is really a Unix/Berzerkelix/SunOS question, you know ...
-- 

 (This man's opinions are his own.)
 From mole-end				Mark Terribile

weisen@eniac.seas.upenn.edu (Neil Weisenfeld) (09/10/90)

In article <439@mole-end.UUCP>, mat@mole-end (Mark A Terribile) writes:
>> > [I wanna write a lockscreen.]
> 
>> weisen@eniac.seas.upenn.edu:
>> > Under BSD, you should be able to do something like:
>> >        signal(SIGINT,SIG_IGN);
>> >        signal(SIGQUIT,SIG_IGN);
>> > to IGNore the signals.
> 
>> SunOS signal(3):
>> > SIGKILL   9    kill (cannot be caught, blocked, or ignored)
>> > SIGSTOP   17   stop (cannot be caught, blocked, or ignored)
> 
>> Therein lies the incentive to capture the characters before a shell can see
>> them.
>
[stuff deleted about ^C not generating SIGINT and ^Z not generating SIGSTOP]

How does my name keep ending up at the top of a message with a whole
bunch of leading >>>>'s?  What happened to the names of the people who
actually wrote that stuff?  The only part of this mess that was written
by me is the part about SIGINT and SIGQUIT.  Also, according to the
man page for SIGNAL(3), SIGSTOP is not generated from the keyboard,
SIGTSTP is!

Neil


P.S. -- Please stop misquoting me:  The text after the SunOS signal(3) is NOT
WHAT I PUT THERE...arrrgh!

--
_____________________________________________________________________________
( ) _     ( )   Neil Weisenfeld                            | 3900 Chestnut St.
( )(_)_   ( )   Computer Science and Engineering           | Apt. 233
( )  (_)_ ( )   School of Engineering and Applied Science  | Philadelphia, PA