lib/agent/actions/lock/linux/prey-lock
#!/bin/sh
''':'
':'; python=$(command -v python)
':'; [ -z "$python" ] || [ -n "${python##*usr*}" ] && python="/usr/bin/python"
':'; exec "$python" "$0" "$@"
'''
#############################################
# Prey Linux Lock
# By Tomas Pollak - (c) 2010 Fork Ltd.
# http://preyproject.com
# GPLv3 License
#############################################
import os, sys, gtk, pango, base64
from gobject import timeout_add
from hashlib import md5
image_file = "/../lib/bg-lock.png"
def write(text):
print text
sys.stdout.flush()
class Lock:
def get_md5(self, string):
hashb64 = base64.b64encode(string.encode("utf-8"))
return md5(hashb64).hexdigest()
def hide_error(self):
self.label.hide()
return False # stops timeout from repeating
def enter_callback(self, widget, entry):
hashed_text = self.get_md5(entry.get_text())
# print hashed_text
if hashed_text != passwd:
write("Invalid password")
self.label.show()
timeout_add(3000, self.hide_error)
return True
else:
enable_XF86Switch()
print 'Correctomondo. PC Unlocked.'
# self.label.set_markup('<span foreground="green">Very good. Access granted.</span>');
# self.label.show()
os._exit(66)
def on_delete_event(self, widget, event):
return True
# self.window.set_keep_above(True)
def on_focus_change(self, widget, event):
print "Focus changed."
return True
def on_window_state_change(self, widget, event):
self.window.activate_focus()
print "Something happened."
return False
def on_key_press(self, widget, event):
keyname = gtk.gdk.keyval_name(event.keyval)
# print "Key %s (%d) was pressed" % (keyname, event.keyval)
if event.keyval > 65470 and event.keyval < 65481: # F1 through F12
print "Key %s (%d) was pressed" % (keyname, event.keyval)
# return True
if event.state & gtk.gdk.CONTROL_MASK:
print "Control was being held down"
# return True
if event.state & gtk.gdk.MOD1_MASK:
print "Alt was being held down"
# return True
if event.state & gtk.gdk.SHIFT_MASK:
print "Shift was being held down"
def scale_image(self, pixbuf, scale):
new_width = int(scale*pixbuf.get_width())
new_height = int(scale*pixbuf.get_height())
# print "Scaled image to: %s x %s" % (new_width, new_height)
return pixbuf.scale_simple(new_width, new_height, gtk.gdk.INTERP_BILINEAR)
def __init__(self):
# calculate number of screens
width = gtk.gdk.screen_width()
height = gtk.gdk.screen_height()
black = gtk.gdk.color_parse("black")
###################################
# black bg
###################################
self.bg_window = gtk.Window(gtk.WINDOW_POPUP)
self.bg_window.modify_bg(gtk.STATE_NORMAL, black)
self.bg_window.resize(width, height)
self.bg_window.set_deletable(False)
self.bg_window.show()
# monitors = self.bg_window.get_screen().get_n_monitors()
###################################
# window
###################################
self.window = gtk.Window(gtk.WINDOW_POPUP)
self.window.set_title("Prey Lock")
self.window.modify_bg(gtk.STATE_NORMAL, black)
# prevents window from being closed
self.window.connect("delete_event", self.on_delete_event)
# capture keypresses
self.window.connect("key_press_event", self.on_key_press)
self.window.stick()
self.window.set_deletable(False)
# self.window.set_focus_on_map(True)
self.window.set_decorated(False)
self.window.set_border_width(0)
self.window.set_keep_above(True)
self.window.set_resizable(False)
# self.window.fullscreen()
main_screen_width = self.window.get_screen().get_monitor_geometry(0).width
main_screen_height = self.window.get_screen().get_monitor_geometry(0).height
main_screen_middle = main_screen_width/2
# print "Main screen size: %s x %s" % (main_screen_width, main_screen_height)
# print "Main screen middle: %s" % main_screen_middle
vbox = gtk.VBox(False, 0)
vbox.set_size_request(main_screen_width, main_screen_height)
self.window.add(vbox)
# vbox.show()
###################################
# background color and image
###################################
image = gtk.Image()
script_path = sys.path[0]
bg_path = script_path + image_file
pixbuf = gtk.gdk.pixbuf_new_from_file(bg_path)
image_width = pixbuf.get_width()
image_height = pixbuf.get_height()
# print 'Image size: %s x %s' % (image_width, image_height)
scale = 1
input_font = 16
error_font = 11
if image_width > main_screen_width or image_height > main_screen_height:
scale = min(float(main_screen_width)/image_width, float(main_screen_height)/image_height)
pixbuf = scale_image(pixbuf, scale)
elif main_screen_width > 2000:
scale = 2
pixbuf = self.scale_image(pixbuf, scale)
input_font -= 2
error_font -= 1
image.set_from_pixbuf(pixbuf)
image.set_size_request(main_screen_width, main_screen_height)
image.show()
vbox.add(image)
###################################
# label
###################################
self.entry = gtk.Entry(max=0)
self.entry.set_max_length(40)
self.entry.set_inner_border(None)
self.entry.set_width_chars(20)
self.entry.set_visibility(False)
self.entry.set_has_frame(False)
self.entry.modify_base(gtk.STATE_NORMAL, gtk.gdk.color_parse("#FFFFFF"))
self.entry.modify_font(pango.FontDescription("sans " + str(input_font)))
self.entry.set_flags(gtk.CAN_FOCUS | gtk.HAS_FOCUS | gtk.HAS_GRAB | gtk.CAN_DEFAULT | gtk.SENSITIVE)
self.entry.connect("activate", self.enter_callback, self.entry)
# self.entry.show()
input_size = 140
padding_left = int(input_size*scale)
padding_top = 5*scale
# print 'Padding: left %s, top %s' % (padding_left, padding_top)
# if image was scaled down, calculate offset for positioning elements
if image_height > main_screen_height:
padding_top = 18 - int((image_height - main_screen_height)/8)
x_position = main_screen_middle-padding_left
y_position = -(main_screen_height/2)+padding_top
# print "Fixed position: %s, %s" % (x_position, y_position)
fixed = gtk.Fixed()
fixed.put(self.entry, x_position, y_position)
fixed.show()
vbox.pack_start(fixed, False, False, 0)
text = 'Invalid password. Access denied.'
self.label = gtk.Label()
self.label.set_markup('<span foreground="#b22222">'+text+'</span>');
self.label.modify_font(pango.FontDescription("sans " + str(error_font)))
# self.label.set_size_request(main_screen_width, 30)
fixed2 = gtk.Fixed()
# push label down a bit, and left a bit so it remains centered
fixed2.put(self.label, x_position + 20, y_position + (46 * scale))
vbox.pack_start(fixed2, False, False, 0)
###################################
# optional message
###################################
if msgtext != "":
self.label2 = gtk.Label()
self.label2.set_line_wrap(True)
self.label2.set_justify(gtk.JUSTIFY_CENTER)
self.label2.set_markup('<span foreground="#FFFFFF">'+msgtext+'</span>');
self.label2.modify_font(pango.FontDescription("sans " + str(error_font)))
label_width = self.label2.size_request()[0]
fixed3 = gtk.Fixed()
fixed3.put(self.label2, main_screen_width/2 - label_width/2, y_position + (100 * scale))
fixed3.show()
vbox.pack_start(fixed3, False, False, 0)
##############################################
disable_XF86Switch()
self.window.show_all()
# self.window.set_focus(self.entry)
gtk.gdk.keyboard_grab(fixed.window, True)
self.label.hide()
original_keycodes = []
def enable_XF86Switch():
import subprocess # need at least python 2.4
try:
for x,y,z in original_keycodes:
cmd = ['xmodmap', '-e', 'keycode %s=%s %s' % (x,y,z)]
subprocess.Popen(cmd)
except OSError, subprocess.CalledProcessError:
return
def disable_XF86Switch():
import subprocess # need at least python 2.4
import re
try:
cmd = ['xmodmap', '-pk']
# find all keys that allows switching to a VT
p = subprocess.Popen(cmd, stdout=subprocess.PIPE)
output, serror = p.communicate()
matched = []
# retrieve the keycode and its value from xmodmap output
for line in output.split('\n'):
if re.search('XF86Switch_VT', line):
items = line.split()
keycode = items[0]
keysym = items[1]
keysym2 = items[7]
keyname = items[2][1:-1]
matched.append((keycode, keyname))
original_keycodes.append((keycode, keysym, keysym2))
# disable all key that allow to switch to a VT
for k,v in matched:
cmd = ['xmodmap', '-e', 'keycode %s=%s' % (k,v)]
subprocess.Popen(cmd)
except IndexError:
print "Couldn't parse Xmodmap list."
except OSError, subprocess.CalledProcessError:
# print "Xmodmap not found"
# do nothing if xmodmap is not found or return an error
return
if __name__ == "__main__":
msgtext = ""
if len(sys.argv) < 2 or len(sys.argv[1]) != 32:
print "You need to pass an MD5 hexdigested string."
sys.exit(67)
else:
passwd = sys.argv[1]
if len(sys.argv) > 2:
msgtext = sys.argv[2]
write("Process PID: %d" % os.getpid())
lock = Lock()
gtk.main()