How to lock own console when idle?

Newbie here, have looked using search engine and can find nothing revelant to my problem..

Using Linux

Here, I want to create a unix daemon (using C) that run to check user idle time, then if the idle time match the timeout, that console will be locked automatically
(user need to enter password to unlock it, and the password is determined in C code and not using real user password).

Here's the C code

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>

#define PSW_PATH "/home/abuzaid/Script/CSiSop/modul3/wajib/pkey"
#define LOG_PATH "/home/abuzaid/Script/CSiSop/modul3/wajib/log"
#define TIME_PATH "/home/abuzaid/Script/CSiSop/modul3/wajib/time"
#define SCRIPT_PATH "/home/abuzaid/Script/CSiSop/modul3/wajib/lockscript.sh"
#define PASS_PATH "/home/abuzaid/Script/CSiSop/modul3/wajib/checkpass.sh"
#define PASSWORD "well"

void check_file(char argv[10]) {
	FILE *idleTime;
    FILE *myLog;
	char time[10];
	if((idleTime = fopen(TIME_PATH, "r")) == NULL)
		exit(EXIT_FAILURE);
	if((fscanf(idleTime, "%s", time)) == -1) {
		if((myLog = fopen(LOG_PATH, "a")) == NULL)
			exit(EXIT_FAILURE);
		fprintf(myLog, "Error reading!\n");
		fclose(myLog);
	}
	fclose(idleTime);
	if((myLog = fopen(LOG_PATH, "a")) == NULL)
		exit(EXIT_FAILURE);
	fprintf(myLog, "%s vs %s\n", time, argv);
	fclose(myLog);
	
	if((strcmp(time, argv)) == 0) { //THIS PART IS GONNA USED TO LOCK THE CONSOLE
		if((myLog = fopen(LOG_PATH, "a")) == NULL)
			exit(EXIT_FAILURE);
		fprintf(myLog, "DO IT NOW\n"); 
		fclose(myLog);
	}
	printf("\ntes");
}

void daemonTask(char argv[10]) {
	FILE *myLog;
	while(1) {
	
		int status;
		int rV = 0;
		pid_t pid;
		pid = fork();
		switch(pid) {
			case -1:
				if((myLog = fopen(LOG_PATH, "a")) == NULL)
					exit(EXIT_FAILURE);
				fprintf(myLog, "MasyaAllah gagal membuat proses untuk exec\n");
				fclose(myLog);
				exit(EXIT_FAILURE);
				break;
			case 0:
				rV = execl(SCRIPT_PATH, SCRIPT_PATH, 0, (char *) 0);
				if(rV == -1) {
					if((myLog = fopen(LOG_PATH, "a")) == NULL)
						exit(EXIT_FAILURE);
					fprintf(myLog, "MasyaAllah anak gagal melakukan exec\n");
					fclose(myLog);
				}
				_exit(1);
				break;
			default:
				wait(&status);
				kill(pid, SIGKILL);
		}	
		
		check_file(argv);
		
		sleep (10);
	}
}

int main(int argc, char *argv[]) {
	FILE *myLog;
	pid_t pid,
		  sid;
	char *time = argv[1];
	
	pid = fork();
	if(pid < 0) {
		exit(EXIT_FAILURE);		
	}
	if(pid > 0) {
		exit(EXIT_SUCCESS);	
	}
	umask(0);

	sid = setsid();
	if(sid < 0) {
		if((myLog = fopen(LOG_PATH, "w")) == NULL)
				exit(EXIT_FAILURE);
		fprintf(myLog, "MasyaAllah SID gagal didapatkan.\n");
		fclose(myLog);
		exit(EXIT_FAILURE);	
	}
	else {
		if((myLog = fopen(LOG_PATH, "w")) == NULL)
				exit(EXIT_FAILURE);
		fprintf(myLog, "Alhamdulillah daemon mulai dengan SID %d.\n", sid);
		fclose(myLog);
	}

	
	if((chdir("/")) < 0) {
		if((myLog = fopen(LOG_PATH, "w")) == NULL)
				exit(EXIT_FAILURE);
		fprintf(myLog, "MasyaAllah gagal pindahkan working directory.\n");
		fclose(myLog);	
		exit(EXIT_FAILURE);
	}
	

	daemonTask(time);
	
	exit(EXIT_SUCCESS);
}

and I want to do console locking mechanism in that bold part (strcmp ...)

I've tried to use printf and scanf and didn't work..
use exec to call shell script to read user input, just same.. won't work

is there any idea?

thx before.

develop_5889

Use the command lock

Using Lock? how come?

can't find that function on unix standar lib.

The command lock can do the job, but it can be killed!

Could someone give example on using the lock command to lock the cosole? :slight_smile: haven't found out how..

To lock >> press ctrl+s
To unlock>>press ctrl+q

No password required

Sorry, i need to use password to let user to open the console..

is there any possibility other than using vlock??

Hemmm..pening2!

Why do you want lock the console of the idle user? Isn't it better if you log him out of the session! Kill him I say! :wink:

I like your idea of a program. As is, I use "screen", which has an "idle timeout". But I do like the idea of forcing this on users of idle TTYs. Vlock doesn't really work on non-vc's (Linux consoles), but I bet you can take the source and adapt it to your program. It might be, in the end, a function to add to the user's shell. You could hack the MAILCHECK command feature, which looks at a file to see if it should print "You have new mail". (Does anyone use standard UNIX mailboxes these days?) Or you could modify the behavior of TMOUT:

A final hack would be using PROMPT_COMMAND to run a program after each time the prompt is printed. This command could be a program that locks if it's been X minutes since the last time the message was printed. Seems to me this would be a bit "heavy" on the system.

Here, 'bout this problem, my friend had solved it with different approach. What do you think of his idea?

Here's the code with a little mod.

void check_idle() {
    struct stat stbuf;
    stat(myTty, &stbuf);
    char out[100];;
    char time_now[100];
    time_t now,*mod_time;
    memset( out, '\0', sizeof( time_now) );
    now = time( NULL );
    mod_time = &stbuf.st_mtime;
    if(last_modif != *mod_time) {
        last_modif=*mod_time;
        idle_time=0;
    }
    else idle_time++;
}

void alarm_handler()
{
    char psswd[20] = "develop5889";
    char usr_input[20];
    
    check_idle();
    if(idle_time == input_idle) {
        kill(parent, SIGSTOP);
        system("clear");    
        printf("\n\tTERMINAL LOCKED, PLEASE ENTER PASSWORD, THEN TAP [ENTER] TWICE\n");
        while (1) {
            usr_input[0] = '\0';
            fflush(stdin);
            scanf("%s", usr_input);
            
            if(strcmp(usr_input, psswd) == 0) 
                break;   
            
            printf("\n\tWRONG PASSWORD, PLEASE ENTER CORRECT PASSWORD\n");
        }
        kill(parent, SIGCONT);
    }
    alarm(1);
}

void run_daemon()
{
    pid_t pid, sid;
    pid = fork();
    if (pid < 0) {
        exit(EXIT_FAILURE);
    } 
    if (pid > 0) {
        exit(EXIT_SUCCESS);
    }

    umask(0);
        
    sid = setsid();
    if (sid < 0) {
        exit(EXIT_FAILURE);
    }
    
    if ((chdir("/")) < 0) {
        exit(EXIT_FAILURE);
    }
    
    signal(SIGALRM, alarm_handler);
    signal(SIGTERM, kill_handler);
    alarm(1);
   
    while(1) {
        sleep(1);
    }
}

int main(int argc, char *argv[]) {
    if((input_idle = atoi(argv[1])) == 0) {
        exit(EXIT_FAILURE);
    }

    parent = getppid();
    myTty=ttyname(STDOUT_FILENO);
    
    run_daemon();
}

Nice program! A couple of bugs:

system("clear");

Probably a bad idea to do inside a signal handler. Also, why, other than to annoy the user. If it's to hide what the user was doing, I doubt this will prevent the terminal's scroll-back from working.

    if(idle_time == input_idle) {

You really need greater-than-or-equal to here. You cannot guarantee that the signal handler will be invoked every second. Oh, and that reminds me:

while(1) sleep(1);

You just need sleep() here. In the C library and system calls, sleep does not take an argument, as it does with perl and the shell.

And last, but definitely not least: an attacker could crash the program by entering more than 20 characters into the password prompt. You Using scanf() and strcmp() here are really bad ideas. You should use fgets() and strncmp() to ensure that at most N characters are read into the stream.

There are other improvements to be made, such as turning off echo on the input stream so that typed characters are not displayed, and such as using PAM or the getent() calls to verify the user's own password (otherwise EVERY user could figure this out). If you do install it as-is, turn off the read bit on the executable. Otherwise, one could get the password with:

strings  your-program-path

Nice feedback from otheus..

That's still a prototype of program, i don't even know the next step i'll take to it :stuck_out_tongue:

FYI, when we run that daemon, if user is prompted to enter password, any input that user type don't show on screen (don't know why)

And, is that "getent()" used to call "real" user password??

It might be because it hasn't actually grabbed the console from the parent process, which is still trying to read characters itself. You might find that entering the password doesn't work. I've seen that when a background process got forked off and tried to read input. You ended up seeing every second character on the command line.

It gets the encrypted version of whatever is accessible through /etc/nsswitch.conf, so normally, yes. To compare, you have to encrypt the inputted password in the same fashion and then compare with what getent() returned. With Linux, you should go through PAM, but I realize that's a lot of work for something like this. However, it would be more secure.

just a tiny correction: sleep does take an argument, which is number of seconds to sleep
On my SysV box
/usr/include/unistd.h:extern unsigned sleep(unsigned);

Ah, okay, I was smoking something in my teens. Or maybe thinking of Kernel programming?? Anyway, in Linux, the man pages specifically states:

 sleep() may be implemented using SIGALRM; mixing calls to alarm() and sleep() is a bad idea.

So develop_5889, don't use the alarm()/sigtrap routines -- just use sleep(). And actually, it makes more sense to call sleep() with the configured idle-time minus the amount of time that the TTY has been idle.