Help with PAM and ctypes
Lenard Lindstrom
len-l at telus.net
Mon Jun 11 18:01:36 EDT 2007
Chris AtLee wrote:
> 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
>
[snip some code]
>
> 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)()
The memory allocated to r is garbage collected immediately after my_conv
returns. You need to allocate it explicitly using C's calloc or such.
This assumes pam_start will free the memory for you.
addr = calloc(sizeof(pam_response), nMessages)
addr is the memory address as a Python integer.
> pResponse.contents = cast(r, POINTER(pam_response))
pResponse.contents changes the actual value of pResponse, a value on the
stack. You want to change the value of the pointer pResponse points to:
pResponse[0] = cast(addr, POINTER(pam_response))
The cast creates a POINTER(pam_reponse) instance with value addr.
> 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
>
If you are going to do any serious ctypes coding consider joining the
ctypes mailing list at sourceforge.net .
--
Lenard Lindstrom
<len-l at telus.net>
More information about the Python-list
mailing list