#!/usr/bin/env python

import base64
from binascii import hexlify
import os
import socket
import sys
import threading
import traceback
import paramiko
import json
import time
import pwd
import grp

os.chdir(os.path.dirname(os.path.realpath(__file__)))
raw_config=open('data/config.json').read()
config = json.loads(raw_config)
host_key = paramiko.RSAKey(filename=config['key'])

if (config['log'] is not False):
    paramiko.util.log_to_file(config['log'])

class Server (paramiko.ServerInterface):
    def __init__(self):
        self.event = threading.Event()
        self.has_authenticated_before = False

    def check_channel_request(self, kind, chanid):
        if kind == 'session':
            return paramiko.OPEN_SUCCEEDED
        return paramiko.OPEN_FAILED_ADMINISTRATIVELY_PROHIBITED

    def check_auth_interactive(self, username, submethods):
        if self.has_authenticated_before:
            return paramiko.AUTH_FAILED
        else:
            self.has_authenticated_before = True
            return paramiko.InteractiveQuery('', config['banner'])

    def check_auth_password(self, username, password):
        time.sleep(3)
        return paramiko.AUTH_FAILED

    def check_auth_publickey(self, username, key):
        time.sleep(3)
        return paramiko.AUTH_FAILED

    def check_auth_interactive_response(self, responses):
        return paramiko.AUTH_FAILED

    def get_allowed_auths(self, username):
        return 'keyboard-interactive,publickey,password'

    def check_channel_shell_request(self, channel):
        self.event.set()
        return True

    def check_channel_pty_request(self, channel, term, width, height, pixelwidth,
                                  pixelheight, modes):
        return True

def incoming_connection(client):
    try:
        t = paramiko.Transport(client)

        # Try to load server moduli for gex
        try:
            t.load_server_moduli()
        except:
            print 'Failed to load moduli -- gex will be unsupported.'
            raise

        # Start the server & negotiate with the client
        server = Server()
        t.add_server_key(host_key)
        try:
            t.start_server(server=server)
        except paramiko.SSHException, x:
            print 'SSH negotiation failed.'
            try:
                t.close()
            except:
                pass
            return

        # Wait for auth
        t.accept(20)
        try:
            t.close()
        except:
            pass
        return

    except Exception, e:
        print 'Caught exception: ' + str(e.__class__) + ': ' + str(e)
        traceback.print_exc()
        try:
            t.close()
        except:
            pass
        return

# Bind to the port
try:
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    sock.bind(('', config['port']))
except Exception, e:
    print 'Could not bind to port: ' + str(e)
    traceback.print_exc()

# Drop privileges
os.setgroups([])
os.setgid(grp.getgrnam('nogroup').gr_gid)
os.setuid(pwd.getpwnam('nobody').pw_uid)

# Start listening for connections
server_listening = True
while server_listening:
    try:
        sock.listen(100)
        print 'Waiting for connection.'
        client, addr = sock.accept()

        print 'Client connected!'
        threading.Thread(target=incoming_connection, args=[client]).start()
    except Exception, e:
        print "Couldn't wait for connection: " + str(e)
        traceback.print_exc()

sock.close()

@@ -376,85 +376,400 @@
 %5D)%0A%0A
-if (config%5B'log'%5D is not False):%0A    paramiko.util.log_to_file(config%5B'log'%5D)
+# Set up logging%0Aparamiko.util.log_to_file('data/error_log')%0Alog_pipe = None%0Aif (config%5B'log'%5D is not False):%0A    log_pipe = open(config%5B'log'%5D, %22a%22)%0A%0Adef log_event(event_type, data = None):%0A    if (log_pipe is not None):%0A        try:%0A            log_pipe.write(str(int(time.time())) + %22%5Ct%22 + event_type + %22%5Ct%22 + str(data) + %22%5Cn%22)%0A            log_pipe.flush()%0A        except:%0A            pass
 %0A%0Acl
@@ -1262,16 +1262,49 @@
   else:%0A
+            log_event('a_inter')%0A
         
@@ -1463,24 +1463,136 @@
  password):%0A
+        log_event('a_password')%0A        log_event('username', username)%0A        log_event('password', password)%0A
         time
@@ -1689,16 +1689,44 @@
 , key):%0A
+        log_event('a_pkey')%0A
         
@@ -2912,9 +2912,9 @@
 ept(
-2
+6
 0)%0A 
@@ -3501,16 +3501,54 @@
 vileges%0A
+if os.getuid() == 0:%0A    try:%0A        
 os.setgr
@@ -3556,16 +3556,24 @@
 ups(%5B%5D)%0A
+        
 os.setgi
@@ -3606,16 +3606,24 @@
 gr_gid)%0A
+        
 os.setui
@@ -3654,16 +3654,75 @@
 .pw_uid)
+%0A    except:%0A        print(%22CAUTION: could not drop root!%22)
 %0A%0A# Star
@@ -4136,16 +4136,64 @@
 )%0A%0Asock.close()%0A
+if (log_pipe is not None):%0A    log_pipe.close()%0A

Add logging, fix exception for non-root use