"""Support for asynchronously authenticating using PAM.
"""
from __future__ import nested_scopes
import PAM
from twisted.internet import reactor
from twisted.internet import threads, defer
import sys, time, getpass, threading, os
def pamAuthenticateThread(service, user, conv):
def _conv(p, items):
try:
d = conv(items)
except:
import traceback
traceback.print_exc()
return
ev = threading.Event()
def cb(r):
ev.r = (1, r)
ev.set()
def eb(e):
ev.r = (0, e)
ev.set()
reactor.callFromThread(d.addCallbacks, cb, eb)
ev.wait()
done = ev.r
if done[0]:
return done[1]
else:
raise done[1].type, done[1].value
pam = PAM.pam()
pam.start(service, user, _conv)
gid = os.getegid()
uid = os.geteuid()
os.setegid(0)
os.seteuid(0)
try:
pam.authenticate() pam.acct_mgmt()
except:
os.setegid(gid)
os.seteuid(uid)
raise
else:
os.setegid(gid)
os.seteuid(uid)
return 1
def defConv(items):
resp = []
for i in range(len(items)):
message, kind = items[i]
if kind == 1: p = getpass.getpass(message)
resp.append((p, 0))
elif kind == 2: p = raw_input(message)
resp.append((p, 0))
elif kind in (3,4):
print message
resp.append(("", 0))
else:
return defer.fail('foo')
d = defer.succeed(resp)
return d
def pamAuthenticate(service, user, conv):
return threads.deferToThread(pamAuthenticateThread, service, user, conv)