C
chris.atlee
Hello,
I've been trying to write a PAM module using ctypes. In the
conversation
function (my_conv in the script below), you're passed in a
pam_response**
pointer. You're supposed to allocate an array of pam_response's and
set
the pointer's value to the new array. Then you fill in the array with
appropriate data.
I can't seem to get it working in python...The authenticate function
always
returns PAM_AUTHTOK_RECOVER_ERR (21), which I think means the response
doesn't
make any sense.
I've tried saving the response array outside of my_conv to make sure
it
doesn't get garbage collected, but that doesn't seem to help.
Any pointers would be appreciated!
Cheers,
Chris
from ctypes import *
libpam = CDLL("libpam.so")
class pam_handle(Structure):
_fields_ = [
("handle", c_void_p)
]
def __init__(self):
self.handle = 0
class pam_message(Structure):
_fields_ = [
("msg_style", c_int),
("msg", c_char_p),
]
def __repr__(self):
return "<pam_message %i '%s'>" % (self.msg_style, self.msg)
class pam_response(Structure):
_fields_ = [
("resp", c_char_p),
("resp_retcode", c_int),
]
def __repr__(self):
return "<pam_response %i '%s'>" % (self.resp_retcode,
self.resp)
conv_func = CFUNCTYPE(c_int,
c_int, POINTER(POINTER(pam_message)),
POINTER(POINTER(pam_response)), c_void_p)
class pam_conv(Structure):
_fields_ = [
("conv", conv_func),
("appdata_ptr", c_void_p)
]
pam_start = libpam.pam_start
pam_start.restype = c_int
pam_start.argtypes = [c_char_p, c_char_p, POINTER(pam_conv),
POINTER(pam_handle)]
pam_authenticate = libpam.pam_authenticate
pam_authenticate.restype = c_int
pam_authenticate.argtypes = [pam_handle, c_int]
if __name__ == "__main__":
import getpass, os, sys
@conv_func
def my_conv(nMessages, messages, pResponse, appData):
# Create an array of nMessages response objects
# Does r get GC'ed after we're all done?
r = (pam_response * nMessages)()
pResponse.contents = cast(r, POINTER(pam_response))
for i in range(nMessages):
if messages.contents.msg == "Password: ":
p = getpass.getpass()
pResponse.contents[0].resp_retcode = 0
pResponse.contents[0].resp = p
return 0
handle = pam_handle()
c = pam_conv(my_conv, 0)
retval = pam_start("login", os.getlogin(), pointer(c),
pointer(handle))
if retval != 0:
print "Couldn't start pam session"
sys.exit(-1)
retval = pam_authenticate(handle, 0)
if retval == 21:
print "Authentication information cannot be recovered"
sys.exit(-1)
print retval
I've been trying to write a PAM module using ctypes. In the
conversation
function (my_conv in the script below), you're passed in a
pam_response**
pointer. You're supposed to allocate an array of pam_response's and
set
the pointer's value to the new array. Then you fill in the array with
appropriate data.
I can't seem to get it working in python...The authenticate function
always
returns PAM_AUTHTOK_RECOVER_ERR (21), which I think means the response
doesn't
make any sense.
I've tried saving the response array outside of my_conv to make sure
it
doesn't get garbage collected, but that doesn't seem to help.
Any pointers would be appreciated!
Cheers,
Chris
from ctypes import *
libpam = CDLL("libpam.so")
class pam_handle(Structure):
_fields_ = [
("handle", c_void_p)
]
def __init__(self):
self.handle = 0
class pam_message(Structure):
_fields_ = [
("msg_style", c_int),
("msg", c_char_p),
]
def __repr__(self):
return "<pam_message %i '%s'>" % (self.msg_style, self.msg)
class pam_response(Structure):
_fields_ = [
("resp", c_char_p),
("resp_retcode", c_int),
]
def __repr__(self):
return "<pam_response %i '%s'>" % (self.resp_retcode,
self.resp)
conv_func = CFUNCTYPE(c_int,
c_int, POINTER(POINTER(pam_message)),
POINTER(POINTER(pam_response)), c_void_p)
class pam_conv(Structure):
_fields_ = [
("conv", conv_func),
("appdata_ptr", c_void_p)
]
pam_start = libpam.pam_start
pam_start.restype = c_int
pam_start.argtypes = [c_char_p, c_char_p, POINTER(pam_conv),
POINTER(pam_handle)]
pam_authenticate = libpam.pam_authenticate
pam_authenticate.restype = c_int
pam_authenticate.argtypes = [pam_handle, c_int]
if __name__ == "__main__":
import getpass, os, sys
@conv_func
def my_conv(nMessages, messages, pResponse, appData):
# Create an array of nMessages response objects
# Does r get GC'ed after we're all done?
r = (pam_response * nMessages)()
pResponse.contents = cast(r, POINTER(pam_response))
for i in range(nMessages):
if messages.contents.msg == "Password: ":
p = getpass.getpass()
pResponse.contents[0].resp_retcode = 0
pResponse.contents[0].resp = p
return 0
handle = pam_handle()
c = pam_conv(my_conv, 0)
retval = pam_start("login", os.getlogin(), pointer(c),
pointer(handle))
if retval != 0:
print "Couldn't start pam session"
sys.exit(-1)
retval = pam_authenticate(handle, 0)
if retval == 21:
print "Authentication information cannot be recovered"
sys.exit(-1)
print retval