Last active
April 1, 2020 14:51
-
-
Save mschmitt/fdac0d557cb42b5092bc63059bdfefb9 to your computer and use it in GitHub Desktop.
A wrapper for running apt-get and apt under sudo.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
# /usr/local/bin/packagemanagement is symlinked as /usr/local/bin/{apt,apt-get} | |
# and when called from sudo cleans the environment and refuses to accept | |
# configuration overrides and to directly install packages. | |
import sys | |
import os | |
import re | |
import syslog | |
import magic | |
syslog.openlog('packagemanagement-wrapper', logoption=syslog.LOG_PID, facility=syslog.LOG_INFO) | |
# Strip absolute path from my own name for later re-execution from $PATH | |
sys.argv[0] = os.path.basename(sys.argv[0]); | |
# If not running under sudo, don't make any checks but execute command as-is | |
if not os.getenv('SUDO_USER'): | |
os.environ['PATH']='/usr/sbin:/usr/bin:/sbin:/bin' | |
syslog.syslog(syslog.LOG_INFO, 'Skipping checks (non-sudo invocation): ' + ' '.join(sys.argv)) | |
syslog.closelog() | |
os.execvp(sys.argv[0], sys.argv) | |
# Arguments that, if detected, will lead to an error exit. | |
args_to_prohibit = [ | |
'^-o', '^--option', | |
'^-c', '^--config-file' | |
] | |
# Files that, if passed on the command line, will lead to an error exit | |
filetypes_to_prohibit = [ | |
'application/vnd.debian.binary-package' | |
] | |
# Force environment variables (removing /usr/local/bin from Path | |
# so I won't infinitely call myself from myself). | |
os.environ['PATH']='/usr/sbin:/usr/bin:/sbin:/bin' | |
os.environ['LESSSECURE']='1' # LESSSECURE makes less more secure | |
os.environ['PAGER']='less' # Force the pager program for apt changelog | |
# Explicitly unset APT_CONFIG, although reset_env in sudoers | |
# simultaneously takes care of it. | |
os.unsetenv('APT_CONFIG') | |
# Declaration of argument regex check | |
def is_prohibited_arg(want_arg): | |
# See if the passed arg is in the list of prohibited args | |
for prohibited_arg in args_to_prohibit: | |
prohibit_re = re.compile(prohibited_arg) | |
if prohibit_re.search(want_arg): | |
return 1 | |
return 0 | |
# Declaration of file type check | |
def is_prohibited_filetype(want_arg): | |
mimetype = magic.detect_from_filename(want_arg).mime_type | |
for prohibited_filetype in filetypes_to_prohibit: | |
if mimetype == prohibited_filetype: | |
return 1 | |
return 0 | |
# Check each argument: | |
for arg in sys.argv: | |
if is_prohibited_arg(arg): | |
print("Use of this argument is prohibited: " + arg) | |
syslog.syslog(syslog.LOG_NOTICE, | |
'Denying arg: ' + arg + ' - in: ' + ' '.join(sys.argv)) | |
exit(1) | |
if os.path.exists(arg) and is_prohibited_filetype(arg): | |
print("Use of this argument is prohibited: " + arg) | |
syslog.syslog(syslog.LOG_NOTICE, | |
'Denying file: ' + arg + ' - in: ' + ' '.join(sys.argv) + | |
' - cwd: ' + os.getcwd()) | |
exit(1) | |
# Still here -> execute command as-is. | |
syslog.syslog(syslog.LOG_INFO, 'Passing control to: ' + ' '.join(sys.argv)) | |
syslog.closelog() | |
os.execvp(sys.argv[0], sys.argv) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment