Skip to content

Instantly share code, notes, and snippets.

@ionelmc
Last active December 19, 2015 00:49
Show Gist options
  • Select an option

  • Save ionelmc/5871575 to your computer and use it in GitHub Desktop.

Select an option

Save ionelmc/5871575 to your computer and use it in GitHub Desktop.
from __future__ import print_function
from logging import getLogger
logger = getLogger(__name__)
import thread
import threading
import traceback
import socket
import struct
import sys
import os
SO_PEERCRED = 17
def cry(message):
try:
logger.warning(message)
print(message, file=_stderr)
except:
pass
class SuspiciousClient(Exception):
pass
class Manhole(threading.Thread):
def __init__(self):
super(Manhole, self).__init__()
self.daemon = True
self.name = "Manhole"
def run(self):
try:
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
pid = os.getpid()
name = "/tmp/manhole-%s" % pid
if os.path.exists(name):
os.unlink(name)
sock.bind(name)
sock.listen(0)
cry("ManholeUDS@: "+name)
while True:
client, _ = sock.accept()
try:
self.handle_connection(client)
except IOError:
pass # yes I'm sure !
except Exception: #pylint: disable=W0703
cry(traceback.format_exc())
finally:
del client
finally:
os.unlink(name)
@staticmethod
def handle_connection(client):
client.settimeout(None)
pid, uid, gid = struct.unpack('3i', client.getsockopt(
socket.SOL_SOCKET, SO_PEERCRED, struct.calcsize('3i')
))
euid = os.geteuid()
if uid not in (0, euid):
raise SuspiciousClient(
"Can't accept client with UID:%s (GID:%s and PID:%s). "
"It doesn't match the current EUID:%s or ROOT." % (
uid, gid, pid, euid
))
cry("Accepted connection %s from pid:%s uid:%s gid:%s" % (client, pid, uid, gid))
client.setsockopt(socket.SOL_SOCKET, socket.SO_SNDBUF, 0)
client.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF, 0)
backup = []
try:
client_fd = client.fileno()
for mode, names in (
('w', ('stderr', '__stderr__', 'stdout', '__stdout__')),
('r', ('stdin', '__stdin__'))
):
for name in names:
backup.append((name, getattr(sys, name)))
setattr(sys, name, os.fdopen(client_fd, mode, 0))
run_repl()
cry("DONE. Cleaning up.")
finally:
old_interval = sys.getcheckinterval()
sys.setcheckinterval(2147483647)
junk = [client] # keep the old file objects alive for a bit
for name, fh in backup:
junk.append(getattr(sys, name))
setattr(sys, name, fh)
del backup
for fh in junk:
try:
fh.close()
except IOError:
pass
del fh
del junk
sys.setcheckinterval(old_interval)
_inst_lock = thread.allocate_lock()
_stderr = _inst = None
def run_repl():
#import IPython
#IPython.embed()
dump_stactraces()
import code
code.InteractiveConsole(locals=globals()).interact()
def install():
global _stderr, _inst #pylint: disable=W0603
with _inst_lock:
_stderr = sys.__stderr__
if not _inst:
_inst = Manhole()
_inst.start()
def dump_stactraces():
code = []
for thread_id, stack in sys._current_frames().items(): #pylint: disable=W0212
code.append("\n######### ProcessID=%s, ThreadID=%s #########" % (
os.getpid(), thread_id
))
for filename, lineno, name, line in traceback.extract_stack(stack):
code.append('File: "%s", line %d, in %s' % (filename, lineno, name))
if line:
code.append(" %s" % (line.strip()))
code.append("#############################################\n\n")
print('\n'.join(code), file=sys.stderr)
if __name__ == '__main__':
from logging import basicConfig, DEBUG
basicConfig(level=DEBUG)
install()
print()
import time
while 1:
print('Main', end='')
time.sleep(2)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment