App-PerlXLock
view release on metacpan or search on metacpan
lib/App/PerlXLock.pm view on Meta::CPAN
use strict;
use warnings;
use base 'Exporter';
our @EXPORT = qw(main_loop);
BEGIN {
use constant PLOCK_PASSWORD => $ENV{PLOCK_PASSWORD};
}
sub detect_x11 {
my $pkg = `pkg-config --cflags --libs x11`;
if($? != 0){
die "Could not detect x11 using pkg-config (perhaps you are missing libx11)";
}
return $pkg;
}
use App::PerlXLock::Inline C => Config => LIBS => detect_x11();
use App::PerlXLock::Inline C => "DATA";
my @buffer;
my @windows;
my @screens;
sub lock_all {
my $d = shift();
for ( 0 .. screen_count($d) - 1 ) {
push( @screens, $_ );
push( @windows, open_lock( $d, $_ ) );
}
}
sub has_shadow {
-e "/etc/shadow";
}
sub shadow_readable {
-r "/etc/shadow";
}
sub password_accessible {
PLOCK_PASSWORD || ( has_shadow() && shadow_readable() );
}
sub check_event {
my $ev = read_event( $_[0] );
$ev > 0 ? push( @buffer, chr($ev) ) : undef;
}
sub check_password {
my $pw = shift;
defined( PLOCK_PASSWORD ) && return(PLOCK_PASSWORD eq $pw);
check_unix_password($pw) == 0;
}
sub main_loop {
my $d = open_connection();
lock_all($d);
grab_keyboard( $d, 0 );
my $locked = 1;
while ($locked) {
check_event($d);
if ( $buffer[-1] && $buffer[-1] eq "\n" ) {
pop(@buffer);
if ( password_accessible() ) {
for my $n ( 0 .. $#buffer ) {
if ( check_password( join( "", @buffer[ $n .. $#buffer ] ) ) ) {
$locked = 0;
}
}
}
else {
$locked = 0;
}
@buffer = ();
}
}
unlock_all($d);
ungrab_keyboard($d);
close_connection($d);
}
sub unlock_all {
my $d = shift;
destroy_window( $d, $_ ) for (@windows);
}
unless ( PLOCK_PASSWORD ) {
has_shadow()
|| print "/etc/shadow does not exist. Xlock is not password protected.\n";
shadow_readable
|| print "No permissions to read /etc/shadow. Xlock is not password protected.\n";
}
1;
__DATA__
__C__
#include <X11/Xlib.h>
#include <X11/X.h>
#include <X11/keysym.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <shadow.h>
#include <crypt.h>
SV *open_connection(){
Display *display;
SV *d_sv;
SV *d_sv_ref;
display = XOpenDisplay(NULL);
if (display == NULL){
croak("Could not open X display connection.");
}
d_sv = newSViv((IV)display);
d_sv_ref = newRV_noinc(d_sv);
return d_sv_ref;
}
void close_connection(SV* display){
XCloseDisplay((Display *)SvIV(SvRV(display)));
}
void destroy_window(SV *display, int window){
XDestroyWindow((Display *)SvIV(SvRV(display)), window);
}
int screen_count(SV *display){
return XScreenCount((Display *)SvIV(SvRV(display)));
}
int close_window(SV *display, int window){
( run in 1.658 second using v1.01-cache-2.11-cpan-a49fcb8fa48 )