mirror of
https://github.com/paradoxxxzero/butterfly.git
synced 2026-05-26 07:08:08 +00:00
Don't import pam if not necessary + pep8
This commit is contained in:
113
butterfly/pam.py
113
butterfly/pam.py
@@ -20,92 +20,102 @@ a user against the Pluggable Authentication Modules (PAM) on the system.
|
||||
Implemented using ctypes, so no compilation is necessary.
|
||||
'''
|
||||
|
||||
import sys
|
||||
import os
|
||||
|
||||
from ctypes import CDLL, POINTER, Structure, CFUNCTYPE, cast, byref, sizeof
|
||||
from ctypes import c_void_p, c_size_t, c_char_p, c_char, c_int
|
||||
from ctypes import memmove
|
||||
import sys
|
||||
from ctypes import (
|
||||
CDLL, CFUNCTYPE, POINTER, Structure, byref, c_char_p, c_int, c_size_t,
|
||||
c_void_p)
|
||||
from ctypes.util import find_library
|
||||
|
||||
|
||||
class PamHandle(Structure):
|
||||
"""wrapper class for pam_handle_t pointer"""
|
||||
_fields_ = [ ("handle", c_void_p) ]
|
||||
_fields_ = [("handle", c_void_p)]
|
||||
|
||||
def __init__(self):
|
||||
Structure.__init__(self)
|
||||
self.handle = 0
|
||||
|
||||
|
||||
class PamMessage(Structure):
|
||||
"""wrapper class for pam_message structure"""
|
||||
_fields_ = [ ("msg_style", c_int), ("msg", c_char_p) ]
|
||||
_fields_ = [("msg_style", c_int), ("msg", c_char_p)]
|
||||
|
||||
def __repr__(self):
|
||||
return "<PamMessage %i '%s'>" % (self.msg_style, self.msg)
|
||||
|
||||
|
||||
class PamResponse(Structure):
|
||||
"""wrapper class for pam_response structure"""
|
||||
_fields_ = [ ("resp", c_char_p), ("resp_retcode", c_int) ]
|
||||
_fields_ = [("resp", c_char_p), ("resp_retcode", c_int)]
|
||||
|
||||
def __repr__(self):
|
||||
return "<PamResponse %i '%s'>" % (self.resp_retcode, self.resp)
|
||||
|
||||
conv_func = CFUNCTYPE(c_int, c_int, POINTER(POINTER(PamMessage)), POINTER(POINTER(PamResponse)), c_void_p)
|
||||
|
||||
conv_func = CFUNCTYPE(
|
||||
c_int, c_int, POINTER(POINTER(PamMessage)),
|
||||
POINTER(POINTER(PamResponse)), c_void_p)
|
||||
|
||||
|
||||
class PamConv(Structure):
|
||||
"""wrapper class for pam_conv structure"""
|
||||
_fields_ = [ ("conv", conv_func), ("appdata_ptr", c_void_p) ]
|
||||
_fields_ = [("conv", conv_func), ("appdata_ptr", c_void_p)]
|
||||
|
||||
|
||||
# Various constants
|
||||
PAM_PROMPT_ECHO_OFF = 1
|
||||
PAM_PROMPT_ECHO_ON = 2
|
||||
PAM_ERROR_MSG = 3
|
||||
PAM_TEXT_INFO = 4
|
||||
PAM_REINITIALIZE_CRED = 8
|
||||
PAM_PROMPT_ECHO_OFF = 1
|
||||
PAM_PROMPT_ECHO_ON = 2
|
||||
PAM_ERROR_MSG = 3
|
||||
PAM_TEXT_INFO = 4
|
||||
PAM_REINITIALIZE_CRED = 8
|
||||
|
||||
libc = CDLL(find_library("c"))
|
||||
libpam = CDLL(find_library("pam"))
|
||||
libpam_misc = CDLL(find_library("pam_misc"))
|
||||
libc = CDLL(find_library("c"))
|
||||
libpam = CDLL(find_library("pam"))
|
||||
libpam_misc = CDLL(find_library("pam_misc"))
|
||||
|
||||
calloc = libc.calloc
|
||||
calloc.restype = c_void_p
|
||||
calloc.argtypes = [c_size_t, c_size_t]
|
||||
calloc = libc.calloc
|
||||
calloc.restype = c_void_p
|
||||
calloc.argtypes = [c_size_t, c_size_t]
|
||||
|
||||
pam_end = libpam.pam_end
|
||||
pam_end.restype = c_int
|
||||
pam_end.argtypes = [PamHandle, c_int]
|
||||
pam_end = libpam.pam_end
|
||||
pam_end.restype = c_int
|
||||
pam_end.argtypes = [PamHandle, c_int]
|
||||
|
||||
pam_start = libpam.pam_start
|
||||
pam_start.restype = c_int
|
||||
pam_start.argtypes = [c_char_p, c_char_p, POINTER(PamConv), POINTER(PamHandle)]
|
||||
pam_start = libpam.pam_start
|
||||
pam_start.restype = c_int
|
||||
pam_start.argtypes = [c_char_p, c_char_p, POINTER(PamConv), POINTER(PamHandle)]
|
||||
|
||||
pam_setcred = libpam.pam_setcred
|
||||
pam_setcred.restype = c_int
|
||||
pam_setcred.argtypes = [PamHandle, c_int]
|
||||
pam_setcred = libpam.pam_setcred
|
||||
pam_setcred.restype = c_int
|
||||
pam_setcred.argtypes = [PamHandle, c_int]
|
||||
|
||||
pam_strerror = libpam.pam_strerror
|
||||
pam_strerror.restype = c_char_p
|
||||
pam_strerror.argtypes = [PamHandle, c_int]
|
||||
pam_strerror = libpam.pam_strerror
|
||||
pam_strerror.restype = c_char_p
|
||||
pam_strerror.argtypes = [PamHandle, c_int]
|
||||
|
||||
pam_authenticate = libpam.pam_authenticate
|
||||
pam_authenticate.restype = c_int
|
||||
pam_authenticate = libpam.pam_authenticate
|
||||
pam_authenticate.restype = c_int
|
||||
pam_authenticate.argtypes = [PamHandle, c_int]
|
||||
|
||||
misc_conv = libpam_misc.misc_conv
|
||||
misc_conv = libpam_misc.misc_conv
|
||||
|
||||
|
||||
class PAM():
|
||||
code = 0
|
||||
code = 0
|
||||
reason = None
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def authenticate(self, username, service='login', encoding='utf-8', resetcreds=True):
|
||||
def authenticate(
|
||||
self, username,
|
||||
service='login', encoding='utf-8', resetcreds=True):
|
||||
"""PAM authentication through standard input for the given service.
|
||||
Returns True for success, or False for failure.
|
||||
self.code (integer) and self.reason (string) are always stored and may
|
||||
be referenced for the reason why authentication failed. 0/'Success' will
|
||||
be stored for success.
|
||||
self.code (integer) and self.reason (string) are always stored
|
||||
and may be referenced for the reason why authentication failed.
|
||||
0/'Success' will be stored for success.
|
||||
Python3 expects bytes() for ctypes inputs. This function will make
|
||||
necessary conversions using the supplied encoding.
|
||||
Inputs:
|
||||
@@ -118,13 +128,15 @@ class PAM():
|
||||
|
||||
# python3 ctypes prefers bytes
|
||||
if sys.version_info >= (3,):
|
||||
if isinstance(username, str): username = username.encode(encoding)
|
||||
if isinstance(service, str): service = service.encode(encoding)
|
||||
if isinstance(username, str):
|
||||
username = username.encode(encoding)
|
||||
if isinstance(service, str):
|
||||
service = service.encode(encoding)
|
||||
else:
|
||||
if isinstance(username, unicode):
|
||||
username = username.encode(encoding)
|
||||
if isinstance(service, unicode):
|
||||
service = service.encode(encoding)
|
||||
service = service.encode(encoding)
|
||||
|
||||
if b'\x00' in username or b'\x00' in service:
|
||||
self.code = 4 # PAM_SYSTEM_ERR in Linux-PAM
|
||||
@@ -132,12 +144,13 @@ class PAM():
|
||||
return False
|
||||
|
||||
handle = PamHandle()
|
||||
conv = PamConv(conv_func(misc_conv), 0)
|
||||
conv = PamConv(conv_func(misc_conv), 0)
|
||||
retval = pam_start(service, username, byref(conv), byref(handle))
|
||||
|
||||
if retval != 0:
|
||||
# This is not an authentication error, something has gone wrong starting up PAM
|
||||
self.code = retval
|
||||
# This is not an authentication error,
|
||||
# something has gone wrong starting up PAM
|
||||
self.code = retval
|
||||
self.reason = "pam_start() failed"
|
||||
return False
|
||||
|
||||
@@ -145,10 +158,10 @@ class PAM():
|
||||
auth_success = retval == 0
|
||||
|
||||
if auth_success and resetcreds:
|
||||
retval = pam_setcred(handle, PAM_REINITIALIZE_CRED);
|
||||
retval = pam_setcred(handle, PAM_REINITIALIZE_CRED)
|
||||
|
||||
# store information to inform the caller why we failed
|
||||
self.code = retval
|
||||
self.code = retval
|
||||
self.reason = pam_strerror(handle, retval)
|
||||
if sys.version_info >= (3,):
|
||||
self.reason = self.reason.decode(encoding)
|
||||
@@ -157,6 +170,7 @@ class PAM():
|
||||
|
||||
return auth_success
|
||||
|
||||
|
||||
def login_prompt(username, profile, env):
|
||||
pam = PAM()
|
||||
|
||||
@@ -170,6 +184,7 @@ def login_prompt(username, profile, env):
|
||||
os.execvpe(su, [su, '-l', username], env)
|
||||
return success
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
if login_prompt(sys.argv[1], sys.argv[2], os.environ):
|
||||
exit(0)
|
||||
|
||||
@@ -31,7 +31,7 @@ import tornado.process
|
||||
import tornado.web
|
||||
import tornado.websocket
|
||||
from logging import getLogger
|
||||
from butterfly import pam, utils, __version__
|
||||
from butterfly import utils, __version__
|
||||
|
||||
log = getLogger('butterfly')
|
||||
ioloop = tornado.ioloop.IOLoop.instance()
|
||||
@@ -95,10 +95,10 @@ class Terminal(object):
|
||||
version=__version__,
|
||||
opts=tornado.options.options,
|
||||
uri=self.uri,
|
||||
colors=utils.ansi_colors)
|
||||
.decode('utf-8')
|
||||
.replace('\r', '')
|
||||
.replace('\n', '\r\n'))
|
||||
colors=utils.ansi_colors
|
||||
).decode('utf-8')
|
||||
.replace('\r', '')
|
||||
.replace('\n', '\r\n'))
|
||||
self.send(motd)
|
||||
|
||||
log.info('Forking pty for user %r' % self.user)
|
||||
|
||||
Reference in New Issue
Block a user