forked from hephaest0s/usbkill
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathusbkill.py
155 lines (122 loc) · 5.54 KB
/
usbkill.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# Contact: [email protected] - 8764 EF6F D5C1 7838 8D10 E061 CF84 9CE5 42D0 B12B
import re
import subprocess
import os, sys, signal
from time import time, sleep
# We compile this function beforehand for efficiency.
DEVICE_RE = re.compile(".+ID\s(?P<id>\w+:\w+)")
help_message = "usbkill is a simple program with one goal: quickly shutdown the computer when a usb is inserted or removed.\nIt logs to /var/log/usbkill/kills.log\nYou can configure a whitelist of usb ids that are acceptable to insert and the remove.\nThe usb id can be found by running the command 'lsusb'.\nSettings can be changed in /etc/usbkill/settings\n\nIn order to be able to shutdown the computer, this program needs to run as root.\n"
def log(msg):
logfile = " /var/log/usbkill/usbkill.log"
# Empty line to separate log enties
os.system("echo '' >> " + logfile)
# Log the message that needed to be logged:
os.system("echo '" + str(time) + " " + msg + "' >> " + logfile)
# Log current usb state:
os.system("echo 'Current state:' >> " + logfile)
os.system("lsusb >> " + logfile)
def kill_computer():
# Log what is happening:
log("Detected usb change. Dumping lsusb and killing computer...")
# Sync the filesystem so that the recent log entry does not get lost.
os.system("sync")
# This function will poweroff your computer immediately
os.system("poweroff -f")
def lsusb():
# A python version of the command 'lsusb' that returns a list of connected usbids
df = subprocess.check_output("lsusb", shell=True).decode('utf-8')
devices = []
for line in df.split('\n'):
if line:
info = DEVICE_RE.match(line)
if info:
dinfo = info.groupdict()
devices.append(dinfo['id'])
return devices
def settings_template(filename):
if not os.path.isfile(filename):
# Pre-populate the settings file if it does not exist yet
f = open(filename, 'w')
f.write("# whitelist command lists the usb ids that you want whitelisted\n")
f.write("# find the correct usbid for your trusted usb using the command 'lsusb'\n")
f.write("# usbid looks something line 0123:9abc\n")
f.write("# Be warned! other parties can copy your trusted usbid to another usb device!\n")
f.write("# use whitelist command and single space separation as follows:\n")
f.write("# whitelist usbid1 usbid2 etc\n")
f.write("whitelist \n\n")
f.write("# allow for a certain amount of sleep time between checks, e.g. 0.5 seconds:\n")
f.write("sleep 0.5\n")
f.close()
def load_settings(filename='/etc/usbkill/settings'):
# read all lines of settings file
f = open(filename, 'r')
lines = f.readlines()
f.close()
# Find the only two supported settings
devices = None
sleep_time = None
for line in lines:
if line[:10] == "whitelist ":
devices = line.replace("\n","").replace(" "," ").split(" ")[1:]
if line[:6] == "sleep ":
sleep_time = float(line.replace("\n","").replace(" "," ").split(" ").pop())
assert not None in [devices, sleep_time], "Please set the 'sleep' and 'whitelist' parameters in '/etc/usbkill/settings' !"
assert sleep_time > 0.0, "Please allow for positive non-zero 'sleep' delay between usb checks!"
return devices, sleep_time
def loop():
# Main loop that checks every 'sleep_time' seconds if computer should be killed.
# Allows only whitelisted usb devices to connect!
# Allows no usb device that wat present during program start to disconnect!
start_devices = lsusb()
whitelisted_devices, sleep_time = load_settings()
acceptable_devices = set(start_devices + whitelisted_devices)
# Write to logs that loop is starting:
log("Started patrolling the usb ports every ", sleep_time, " seconds.")
# Main loop
while True:
# List the current usb devices
current_devices = lsusb()
# Check that all current devices are in the set of acceptable devices
for device in current_devices:
if device not in acceptable_devices:
kill_computer()
# Check that all start devices are still present in current devices
for device in start_devices:
if device not in current_devices:
kill_computer()
sleep(sleep_time)
def exit_handler(signum, frame):
print("\nExiting because exit signal was received\n")
log("Exiting because exit signal was received")
sys.exit(0)
if __name__=="__main__":
# Check arguments
args = sys.argv[1:]
if '-h' in args or '--help' in args:
sys.exit(help_message)
elif len(args) > 0:
sys.exit("\nArgument not understood. Can only understand -h\n")
# Check if program is run as root, else exit.
# Root is needed to power off the computer.
if not os.geteuid() == 0:
sys.exit("\nThis program needs to run as root.\n")
# Make sure there is a logging folder
if not os.path.isdir("/var/log/usbkill/"):
os.system("mkdir /var/log/usbkill/")
# Make sure settings file is available
settings_template(filename)
# Register handlers for clean exit of loop
for sig in [signal.SIGINT, signal.SIGTERM, signal.SIGQUIT, ]:
signal.signal(sig, exit_handler)
# Start main loop
loop()