Help with PAM and ctypes

Chris AtLee chris.atlee at gmail.com
Thu Jun 7 08:28:41 EDT 2007


Sorry for the repeat post...I'm not sure if my first post (on May
30th) went through or
not.

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[i].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




More information about the Python-list mailing list