pam-python-1.0.2/0000755000215700017510000000000011741446577012533 5ustar rstuartitpam-python-1.0.2/src/0000755000215700017510000000000011741446574013317 5ustar rstuartitpam-python-1.0.2/src/test.py0000644000215700017510000004661511741431270014647 0ustar rstuartit#!/usr/bin/python -W default # # This is the test script for libpython-pam. There aren't many stones # left unturned. # # Best run from the Makefile using the target 'test'. To run manually: # sudo ln -s $PWD/test-pam_python.pam /etc/pam.d # python test.py # sudo rm /etc/pam.d/test-pam_python.pam # import warnings; warnings.simplefilter('default') import os import sys TEST_PAM_MODULE = "test-pam_python.pam" TEST_PAM_USER = "root" # # A Fairly straight forward test harness. # def pam_sm_end(pamh): return test(pam_sm_end, pamh, None, None) def pam_sm_authenticate(pamh, flags, argv): return test(pam_sm_authenticate, pamh, flags, argv) def pam_sm_setcred(pamh, flags, argv): return test(pam_sm_setcred, pamh, flags, argv) def pam_sm_acct_mgmt(pamh, flags, argv): return test(pam_sm_acct_mgmt, pamh, flags, argv) def pam_sm_open_session(pamh, flags, argv): return test(pam_sm_open_session, pamh, flags, argv) def pam_sm_close_session(pamh, flags, argv): return test(pam_sm_close_session, pamh, flags, argv) def pam_sm_chauthtok(pamh, flags, argv): return test(pam_sm_chauthtok, pamh, flags, argv) def test(who, pamh, flags, argv): import test if not hasattr(test, "test_function"):# only true if not called via "main" return pamh.PAM_SUCCESS # normally happens only if run by ctest test_function = globals()[test.test_function.__name__] return test_function(test.test_results, who, pamh, flags, argv) def run_test(caller): import test test_name = caller.__name__[4:] sys.stdout.write("Testing " + test_name + " ") sys.stdout.flush() test.test_results = [] test.test_function = globals()["test_" + test_name] caller(test.test_results) sys.stdout.write("OK\n") def pam_conv(auth, query_list, userData): return query_list # # Verify the results match. # def assert_results(expected_results, results): for i in range(min(len(expected_results), len(results))): assert expected_results[i] == results[i], (i, expected_results[i], results[i]) if len(expected_results) < len(results): assert len(expected_results) == len(results), (i, results[len(expected_results)]) else: assert len(expected_results) == len(results), (i, expected_results[len(results)]) # # Test all the calls happen. # def test_basic_calls(results, who, pamh, flags, argv): results.append((who.func_name, flags, argv)) return pamh.PAM_SUCCESS def run_basic_calls(results): pam = PAM.pam() pam.start(TEST_PAM_MODULE, TEST_PAM_USER, pam_conv) pam.authenticate(0) pam.acct_mgmt() pam.chauthtok() pam.open_session() pam.close_session() del pam me = os.path.join(os.getcwd(), __file__) expected_results = [ (pam_sm_authenticate.func_name, 0, [me]), (pam_sm_acct_mgmt.func_name, 0, [me, 'arg1', 'arg2']), (pam_sm_chauthtok.func_name, 16384, [me]), (pam_sm_chauthtok.func_name, 8192, [me]), (pam_sm_open_session.func_name, 0, [me]), (pam_sm_close_session.func_name, 0, [me]), (pam_sm_end.func_name, None, None)] assert_results(expected_results, results) # # Test all the constants are defined. # PAM_CONSTANTS = { # # Constants defined in _pam_types.h. The item constants are omitted. # "PAM_SUCCESS": 0, "PAM_OPEN_ERR": 1, "PAM_SYMBOL_ERR": 2, "PAM_SERVICE_ERR": 3, "PAM_SYSTEM_ERR": 4, "PAM_BUF_ERR": 5, "PAM_PERM_DENIED": 6, "PAM_AUTH_ERR": 7, "PAM_CRED_INSUFFICIENT": 8, "PAM_AUTHINFO_UNAVAIL": 9, "PAM_USER_UNKNOWN": 10, "PAM_MAXTRIES": 11, "PAM_NEW_AUTHTOK_REQD": 12, "PAM_ACCT_EXPIRED": 13, "PAM_SESSION_ERR": 14, "PAM_CRED_UNAVAIL": 15, "PAM_CRED_EXPIRED": 16, "PAM_CRED_ERR": 17, "PAM_NO_MODULE_DATA": 18, "PAM_CONV_ERR": 19, "PAM_AUTHTOK_ERR": 20, "PAM_AUTHTOK_RECOVER_ERR": 21, "PAM_AUTHTOK_RECOVERY_ERR": 21, "PAM_AUTHTOK_LOCK_BUSY": 22, "PAM_AUTHTOK_DISABLE_AGING": 23, "PAM_TRY_AGAIN": 24, "PAM_IGNORE": 25, "PAM_ABORT": 26, "PAM_AUTHTOK_EXPIRED": 27, "PAM_MODULE_UNKNOWN": 28, "PAM_BAD_ITEM": 29, "PAM_CONV_AGAIN": 30, "PAM_INCOMPLETE": 31, "PAM_SERVICE": 1, "PAM_USER": 2, "PAM_TTY": 3, "PAM_RHOST": 4, "PAM_CONV": 5, "PAM_AUTHTOK": 6, "PAM_OLDAUTHTOK": 7, "PAM_RUSER": 8, "PAM_USER_PROMPT": 9, "PAM_FAIL_DELAY": 10, "PAM_XDISPLAY": 11, "PAM_XAUTHDATA": 12, "PAM_AUTHTOK_TYPE": 13, "PAM_SILENT": 0x8000, "PAM_DISALLOW_NULL_AUTHTOK": 0x0001, "PAM_ESTABLISH_CRED": 0x0002, "PAM_DELETE_CRED": 0x0004, "PAM_REINITIALIZE_CRED": 0x0008, "PAM_REFRESH_CRED": 0x0010, "PAM_CHANGE_EXPIRED_AUTHTOK": 0x0020, "PAM_DATA_SILENT": 0x40000000, "PAM_PROMPT_ECHO_OFF": 1, "PAM_PROMPT_ECHO_ON": 2, "PAM_ERROR_MSG": 3, "PAM_TEXT_INFO": 4, "PAM_RADIO_TYPE": 5, "PAM_BINARY_PROMPT": 7, "PAM_MAX_NUM_MSG": 32, "PAM_MAX_MSG_SIZE": 512, "PAM_MAX_RESP_SIZE": 512, "_PAM_RETURN_VALUES": 32, # # Constants defined in pam_modules.h. The item constants are omitted. # "PAM_PRELIM_CHECK": 0x4000, "PAM_UPDATE_AUTHTOK": 0x2000, "PAM_DATA_REPLACE": 0x20000000, } def test_constants(results, who, pamh, flags, argv): results.append(who.func_name) if who != pam_sm_authenticate: return pamh.PAM_SUCCESS pam_constants = dict([ (var, getattr(pamh,var)) for var in dir(pamh) if var.startswith("PAM_") or var.startswith("_PAM_")]) results.append(pam_constants) try: pamh.PAM_SUCCESS = 1 results.append("Opps, pamh.PAM_SUCCESS = 1 worked!") except StandardError, e: results.append("except: %s" % e) return pamh.PAM_SUCCESS def run_constants(results): pam = PAM.pam() pam.start(TEST_PAM_MODULE, TEST_PAM_USER, pam_conv) pam.authenticate(0) pam.close_session() del pam assert results[0] == pam_sm_authenticate.func_name, (results[0], pam_sm_authenticate.func_name) assert results[2] == "except: attribute 'PAM_SUCCESS' of 'PamHandle_type' objects is not writable", results[2] assert results[3] == pam_sm_close_session.func_name, (results[3], pam_sm_close_session.func_name) assert results[4] == pam_sm_end.func_name, (results[4], pam_sm_end.func_name) consts = results[1] for var in PAM_CONSTANTS.keys(): assert consts.has_key(var), var assert consts[var] == PAM_CONSTANTS[var], (var, consts[var], PAM_CONSTANTS[var]) for var in consts.keys(): assert PAM_CONSTANTS.has_key(var), var assert PAM_CONSTANTS[var] == consts[var], (var, PAM_CONSTANTS[var], consts[var]) assert len(results) == 5, len(results) # # Test the environment calls. # def test_environment(results, who, pamh, flags, argv): results.append(who.func_name) if who != pam_sm_acct_mgmt: return pamh.PAM_SUCCESS def test_exception(func): try: func() return str(None) except Exception, e: return e.__class__.__name__ + ": " + str(e) # # A few things to test here. First that PamEnv_as_mapping works. # results.append(len(pamh.env)) results.append(pamh.env["x1"]) pamh.env["yy"] = "y" results.append(pamh.env["yy"]) pamh.env["yy"] = "z" results.append(pamh.env["yy"]) def t(): pamh.env["yy"] = 1 results.append(test_exception(t)) del pamh.env["yy"] results.append(test_exception(lambda: pamh.env["yy"])) results.append(test_exception(lambda: pamh.env[1])) results.append(test_exception(lambda: pamh.env['a='])) results.append(test_exception(lambda: pamh.env[''])) # # Now the dict functions. # pamh.env["xx"] = "x" results.append("not in" in pamh.env) results.append("xx" in pamh.env) results.append(pamh.env.has_key("not in")) results.append(pamh.env.has_key("xx")) results.append(test_exception(lambda: pamh.env.__getitem__("not in"))) results.append(pamh.env.get("not in")) results.append(pamh.env.get("not in", "default")) results.append(pamh.env.get("xx")) results.append(pamh.env.get("xx", "default")) del pamh.env["x1"] results.append(pamh.env.items()) results.append(pamh.env.keys()) results.append(pamh.env.values()) return pamh.PAM_SUCCESS def run_environment(results): pam = PAM.pam() pam.start(TEST_PAM_MODULE, TEST_PAM_USER, pam_conv) pam.authenticate(0) pam.putenv("x1=1") pam.putenv("x2=2") pam.putenv("x3=3") pam.acct_mgmt() pam.close_session() del pam expected_results = [ pam_sm_authenticate.func_name, pam_sm_acct_mgmt.func_name, 3, '1', 'y', 'z', 'TypeError: PAM environment value must be a string', "KeyError: 'yy'", 'TypeError: PAM environment key must be a string', "ValueError: PAM environment key can't contain '='", "ValueError: PAM environment key mustn't be 0 length", False, True, False, True, "KeyError: 'not in'", None, 'default', 'x', 'x', [('x2', '2'), ('x3', '3'), ('xx', 'x')], ['x2', 'x3', 'xx'], ['2', '3', 'x'], pam_sm_close_session.func_name, pam_sm_end.func_name] assert_results(expected_results, results) # # Test strerror(). # def test_strerror(results, who, pamh, flags, argv): results.append(who.func_name) if who != pam_sm_authenticate: return pamh.PAM_SUCCESS results.extend([(e, pamh.strerror(e).lower()) for e in (0, 1, 30, 31)]) return pamh.PAM_SUCCESS def run_strerror(results): pam = PAM.pam() pam.start(TEST_PAM_MODULE, TEST_PAM_USER, pam_conv) pam.authenticate(0) del pam expected_results = [ pam_sm_authenticate.func_name, ( 0, 'success'), ( 1, 'failed to load module'), (30, 'conversation is waiting for event'), (31, 'application needs to call libpam again'), pam_sm_end.func_name] assert_results(expected_results, results) # # Test items. # def test_items(results, who, pamh, flags, argv): results.append(who.func_name) if not who in (pam_sm_open_session, pam_sm_close_session): return pamh.PAM_SUCCESS items = { "authtok": "authtok-module", "authtok_type": "authtok_type-module", "oldauthtok": "oldauthtok-module", "rhost": "rhost-module", "ruser": "ruser-module", "tty": "tty-module", "user_prompt": "user_prompt-module", "user": "user-module", "xdisplay": "xdisplay-module", } keys = items.keys() keys.sort() for key in keys: results.append((key, getattr(pamh, key))) value = items[key] if value != None: setattr(pamh, key, value) try: setattr(pamh, "tty", 1) results.append("%r = %r" % (key, value)) except StandardError, e: results.append("except: %s" % e) results.append(pamh.get_user("a prompt")) return pamh.PAM_SUCCESS def run_items(results): pam = PAM.pam() pam.start(TEST_PAM_MODULE, TEST_PAM_USER, pam_conv) pam.authenticate(0) items = { 2: "user", 3: "tty", 4: "rhost", 8: "ruser", 9: "user_prompt", 11: "xdisplay", 13: "authtok_type"} items_list = items.keys() items_list.sort() for item in items_list: pam.set_item(item, items[item]) pam.open_session() pam.close_session() del pam expected_results = [ pam_sm_authenticate.func_name, pam_sm_open_session.func_name, ('authtok', None), ('authtok_type', 'authtok_type'), ('oldauthtok', None), ('rhost', 'rhost'), ('ruser', 'ruser'), ('tty', 'tty'), ('user', 'user'), ('user_prompt', 'user_prompt'), ('xdisplay', 'xdisplay'), 'except: PAM item PAM_TTY must be set to a string', 'user-module', pam_sm_close_session.func_name, ('authtok', 'authtok-module'), ('authtok_type', 'authtok_type-module'), ('oldauthtok', 'oldauthtok-module'), ('rhost', 'rhost-module'), ('ruser', 'ruser-module'), ('tty', 'tty-module'), ('user', 'user-module'), ('user_prompt', 'user_prompt-module'), ('xdisplay', 'xdisplay-module'), 'except: PAM item PAM_TTY must be set to a string', 'user-module', pam_sm_end.func_name] assert_results(expected_results, results) # # Test the xauthdata item. # def test_xauthdata(results, who, pamh, flags, argv): results.append(who.func_name) if not who in (pam_sm_open_session, pam_sm_close_session): return pamh.PAM_SUCCESS xauthdata0 = pamh.XAuthData("name-module", "data-module") pamh.xauthdata = xauthdata0 xauthdata1 = pamh.xauthdata results.append('name=%r, data=%r' % (xauthdata1.name, xauthdata1.data)) try: xauthdata2 = pamh.XAuthData(None, "x") results.append('pamh.XAuthData(%r, %r)' % (xauthdata2.name, xauthdata2.data)) except TypeError, e: results.append('except: %s' % e) try: xauthdata2 = pamh.XAuthData("x", 1) results.append('pamh.XAuthData(%r, %r)' % (xauthdata2.name, xauthdata2.data)) except TypeError, e: results.append('except: %s' % e) class XA: pass XA.name = "name-XA" XA.data = "data-XA" pamh.xauthdata = XA xauthdata2 = pamh.xauthdata results.append('name=%r, data=%r' % (xauthdata2.name, xauthdata2.data)) xa = XA() xa.name = "name-xa" xa.data = "data-xa" pamh.xauthdata = xa xauthdata4 = pamh.xauthdata results.append('name=%r, data=%r' % (xauthdata4.name, xauthdata4.data)) return pamh.PAM_SUCCESS def run_xauthdata(results): pam = PAM.pam() pam.start(TEST_PAM_MODULE, TEST_PAM_USER, pam_conv) pam.authenticate(0) # # The PAM module doesn't support XAUTHDATA, so check what we can from the # module only. # pam.open_session() pam.close_session() del pam expected_results = [ pam_sm_authenticate.func_name, pam_sm_open_session.func_name, ("name='name-module', data='data-module'"), 'except: XAuthData() argument 1 must be string, not None', 'except: XAuthData() argument 2 must be string, not int', ("name='name-XA', data='data-XA'"), ("name='name-xa', data='data-xa'"), pam_sm_close_session.func_name, ("name='name-module', data='data-module'"), 'except: XAuthData() argument 1 must be string, not None', 'except: XAuthData() argument 2 must be string, not int', ("name='name-XA', data='data-XA'"), ("name='name-xa', data='data-xa'"), pam_sm_end.func_name] assert_results(expected_results, results) # # Test having no pam_sm_end. # def test_no_sm_end(results, who, pamh, flags, argv): results.append(who.func_name) global pam_sm_end del pam_sm_end return pamh.PAM_SUCCESS def run_no_sm_end(results): pam = PAM.pam() pam.start(TEST_PAM_MODULE, TEST_PAM_USER, pam_conv) pam.authenticate(0) del pam expected_results = [pam_sm_authenticate.func_name] assert_results(expected_results, results) # # Test the conversation mechanism. # def test_conv(results, who, pamh, flags, argv): results.append(who.func_name) if who == pam_sm_end: return # # We must get rid of all references to pamh.Response objects. This instance # of the test.py module is running inside of libpam_python. That shared # library will be unloaded soon. Should a pamh.Response instance be # dealloc'ed after it is unloaded the now non-existant dealloc function will # be called, and a SIGSEGV will result. Normally instances would not leak, # but with the trickery we are performing with fake import's here they will # leak via the results variable unless we take special action. # def conv(convs): responses = pamh.conversation(convs) if type(responses) != type(()): return (responses.resp, responses.resp_retcode) return [(r.resp, r.resp_retcode) for r in responses] if who == pam_sm_authenticate: convs = [ pamh.Message(pamh.PAM_PROMPT_ECHO_OFF, "Prompt_echo_off"), pamh.Message(pamh.PAM_PROMPT_ECHO_ON, "Prompt_echo_on"), pamh.Message(pamh.PAM_ERROR_MSG, "Error_msg"), pamh.Message(pamh.PAM_TEXT_INFO, "Text_info")] if who == pam_sm_acct_mgmt: convs = pamh.Message(pamh.PAM_PROMPT_ECHO_OFF, "single") results.append(conv(convs)) return pamh.PAM_SUCCESS def run_conv(results): pam = PAM.pam() pam.start(TEST_PAM_MODULE, TEST_PAM_USER, pam_conv) pam.authenticate(0) pam.acct_mgmt() del pam expected_results = [ pam_sm_authenticate.func_name, [('Prompt_echo_off', 1), ('Prompt_echo_on', 2), ('Error_msg', 3), ('Text_info', 4)], pam_sm_acct_mgmt.func_name, ('single', 1), pam_sm_end.func_name] assert_results(expected_results, results) # # Test pam error returns. # def test_pamerr(results, who, pamh, flags, argv): return results[-1] def run_pamerr(results): pam = PAM.pam() pam.start(TEST_PAM_MODULE, TEST_PAM_USER, pam_conv) for err in range(0, PAM._PAM_RETURN_VALUES): results.append(err) try: pam.authenticate(0) except PAM.error, e: results[-1] = -e.args[1] del pam expected_results = [-r for r in range(PAM._PAM_RETURN_VALUES)] expected_results[25] = -6 assert_results(expected_results, results) # # Test fail_delay. # def test_fail_delay(results, who, pamh, flags, argv): pamh.fail_delay(10) return pamh.PAM_SUCCESS def run_fail_delay(results): pam = PAM.pam() pam.start(TEST_PAM_MODULE, TEST_PAM_USER, pam_conv) pam.authenticate(0) del pam # # Test raising an exception. # def test_exceptions(results, who, pamh, flags, argv): if who != pam_sm_end: return pamh.PAM_SUCCESS # # Here we have use of a backdoor put into pam_python.c specifically # for testing raising exceptions. Oddly, normally PAM should never # return anything other than PAM_SUCCESS to anything pam_python.c # calls. # debug_magic = 0x4567abcd results.append(pamh._PAM_RETURN_VALUES) for err in range(pamh._PAM_RETURN_VALUES): try: pamh.strerror(debug_magic + err) results.append(err) except pamh.exception, e: results.append((-e.pam_result,)) return pamh.PAM_SUCCESS def run_exceptions(results): pam = PAM.pam() pam.start(TEST_PAM_MODULE, TEST_PAM_USER, pam_conv) pam.authenticate(0) del pam expected_results = [results[0], 0] expected_results += [(-r,) for r in range(1, results[0])] assert_results(expected_results, results) # # Test absent entry point. # def test_absent(results, who, pamh, flags, argv): results.append(who.func_name) if who != pam_sm_authenticate: return pamh.PAM_SUCCESS global pam_sm_acct_mgmt; del pam_sm_acct_mgmt global pam_sm_setcred; del pam_sm_setcred global pam_sm_open_session; del pam_sm_open_session global pam_sm_close_session; del pam_sm_close_session global pam_sm_chauthtok; del pam_sm_chauthtok return pamh.PAM_SUCCESS def run_absent(results): pam = PAM.pam() pam.start(TEST_PAM_MODULE, TEST_PAM_USER, pam_conv) pam.authenticate(0) funcs = ( pam.acct_mgmt, pam.setcred, pam.open_session, pam.close_session, pam.chauthtok ) for func in funcs: try: func(0) exception = None except Exception, e: exception = e results.append((exception.__class__.__name__, str(exception))) del pam expected_results = [ 'pam_sm_authenticate', ('error', "('Symbol not found', 2)"), ('error', "('Symbol not found', 2)"), ('error', "('Symbol not found', 2)"), ('error', "('Symbol not found', 2)"), ('error', "('Symbol not found', 2)"), ] assert_results(expected_results, results) # # Entry point. # def main(argv): run_test(run_basic_calls) run_test(run_constants) run_test(run_environment) run_test(run_strerror) run_test(run_items) run_test(run_xauthdata) run_test(run_no_sm_end) run_test(run_conv) run_test(run_pamerr) run_test(run_fail_delay) run_test(run_exceptions) run_test(run_absent) # # If run from Python run the test suite. Otherwse we are being used # as a real PAM module presumable from ctest, so just make every call # return success. # if __name__ == "__main__": import PAM main(sys.argv) pam-python-1.0.2/src/test-pam_python.pam.in0000644000215700017510000000031410725216273017544 0ustar rstuartitauth required $PWD/pam_python.so $PWD/test.py account required $PWD/pam_python.so $PWD/test.py arg1 arg2 password required $PWD/pam_python.so $PWD/test.py session required $PWD/pam_python.so $PWD/test.py pam-python-1.0.2/src/setup.py0000755000215700017510000000304311741446255015030 0ustar rstuartit#!/usr/bin/python -W default import warnings; warnings.simplefilter('default') try: from setuptools import setup, Extension except ImportError: from distutils.core import setup, Extension import sys import os long_description = """\ Embeds the Python interpreter into PAM \ so PAM modules can be written in Python""" classifiers = [ "Development Status :: 4 - Beta", "Intended Audience :: Developers", "License :: OSI Approved :: EPL", "Natural Language :: English", "Operating System :: Unix", "Programming Language :: C", "Programming Language :: Python", "Topic :: Software Development :: Libraries :: Python Modules", "Topic :: System :: Systems Administration :: Authentication/Directory"] if not os.environ.has_key("Py_DEBUG"): Py_DEBUG = [] else: Py_DEBUG = [('Py_DEBUG',1)] libpython_so = ('libpython%d.%d.so.1') % sys.version_info[:2] ext_modules = [ Extension( "pam_python", sources=["pam_python.c"], include_dirs = [], library_dirs=[], define_macros=[('LIBPYTHON_SO','"'+libpython_so+'"')] + Py_DEBUG, libraries=["pam","python%d.%d" % sys.version_info[:2]], ), ] setup( name="pam_python", version="1.0.2", description="Enabled PAM Modules to be written in Python", keywords="pam,embed,authentication,security", platforms="Unix", long_description=long_description, author="Russell Stuart", author_email="russell-pampython@stuart.id.au", url="http://www.stuart.id.au/russell/files/pam_python", license="EPL", classifiers=classifiers, ext_modules=ext_modules, ) pam-python-1.0.2/src/ctest.c0000644000215700017510000000665211432174221014576 0ustar rstuartit/* * Best compiled & run using the Makefile target "test". To compile and run * manually: * gcc -O0 -g -Wall -o test -lpam test.c * sudo ln -s $PWD/test-pam_python.pam /etc/pam.d * ./ctest * sudo rm /etc/pam.d/test-pam_python.pam */ #define _GNU_SOURCE #include #include #include #include #include #include struct walk_info { int libpam_python_seen; int python_seen; }; static int conv( int num_msg, const struct pam_message** msg, struct pam_response** resp, void *appdata_ptr) { int i; appdata_ptr = appdata_ptr; *resp = malloc(num_msg * sizeof(**resp)); for (i = 0; i < num_msg; i += 1) { (*resp)[i].resp = strdup((*msg)[i].msg); (*resp)[i].resp_retcode = (*msg)[i].msg_style; } return 0; } static void call_pam( int* exit_status, const char* who, pam_handle_t* pamh, int (*func)(pam_handle_t*, int)) { int pam_result = (*func)(pamh, 0); if (pam_result == PAM_SUCCESS) return; fprintf( stderr, "%s failed: %d %s\n", who, pam_result, pam_strerror(pamh, pam_result)); *exit_status = 1; } static int dl_walk(struct dl_phdr_info* info, size_t size, void* data) { struct walk_info* walk_info = data; size = size; if (strstr(info->dlpi_name, "/pam_python.so") != 0) walk_info->libpam_python_seen = 1; if (strstr(info->dlpi_name, "/libpython") != 0) walk_info->python_seen = 1; return 0; } static void walk_dlls(struct walk_info* walk_info) { walk_info->libpam_python_seen = 0; walk_info->python_seen = 0; dl_iterate_phdr(dl_walk, walk_info); } int main(int argc, char **argv) { int exit_status; struct pam_conv convstruct; pam_handle_t* pamh; struct walk_info walk_info_before; struct walk_info walk_info_after; argc = argc; argv = argv; if (access("/etc/pam.d/test-pam_python.pam", 0) != 0) { fprintf( stderr, "**WARNING**\n" " This test requires ./test-pam_python.pam configuration to be\n" " available to PAM But it doesn't appear to be in /etc/pam.d.\n" ); } printf("Testing calls from C"); fflush(stdout); convstruct.conv = conv; convstruct.appdata_ptr = 0; if (pam_start("test-pam_python.pam", "", &convstruct, &pamh) == -1) { fprintf(stderr, "pam_start failed\n"); exit(1); } exit_status = 0; call_pam(&exit_status, "pam_authenticate", pamh, pam_authenticate); call_pam(&exit_status, "pam_chauthtok", pamh, pam_chauthtok); call_pam(&exit_status, "pam_acct_mgmt", pamh, pam_acct_mgmt); call_pam(&exit_status, "pam_open_session", pamh, pam_open_session); call_pam(&exit_status, "pam_close_session", pamh, pam_close_session); walk_dlls(&walk_info_before); call_pam(&exit_status, "pam_end", pamh, pam_end); if (exit_status == 0) printf(" OK\n"); walk_dlls(&walk_info_after); printf("Testing dll load/unload "); if (!walk_info_before.libpam_python_seen) { fprintf(stderr, "It looks like pam_python.so wasn't loaded!\n"); exit_status = 1; } else if (!walk_info_before.python_seen) { fprintf(stderr, "It looks like libpythonX.Y.so wasn't loaded!\n"); exit_status = 1; } else if (walk_info_after.libpam_python_seen) { fprintf(stderr, "pam_python.so wasn't unloaded.\n"); exit_status = 1; } else if (walk_info_after.python_seen) { fprintf(stderr, "libpythonX.Y.so wasn't uloaded.\n"); exit_status = 1; } else printf("OK\n"); return exit_status; } pam-python-1.0.2/src/Makefile0000644000215700017510000000257111737231754014761 0ustar rstuartitall: ctest pam_python.so test-pam_python.pam WARNINGS=-Wall -Wextra -Wundef -Wshadow -Wpointer-arith -Wbad-function-cast -Wsign-compare -Waggregate-return -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations -Werror #WARNINGS=-Wunreachable-code # Gcc 4.1 .. 4.4 are too buggy to make this useful pam_python.so: pam_python.c setup.py Makefile @rm -f "$@" @[ ! -e build -o build/lib.*/$@ -nt setup.py -a build/lib.*/$@ -nt Makefile ] || rm -r build CFLAGS="$(WARNINGS)" ./setup.py build @#CFLAGS="-O0 $(WARNINGS)" ./setup.py build --debug @#CFLAGS="-O0 $(WARNINGS)" Py_DEBUG=1 ./setup.py build --debug ln -sf build/lib.*/$@ . .PHONY: install install-lib install: install-lib install-lib: mkdir -p $(DESTDIR)/lib/security cp build/lib.*/pam_python.so $(DESTDIR)/lib/security .PHONY: clean clean: rm -rf build ctest pam_python.so test-pam_python.pam test.pyc core s=$$([ $$(id -u) = 0 ] || echo sudo); $$s rm -f /etc/pam.d/test-pam_python.pam .PHONY: ctest ctest: ctest.c Makefile gcc -O0 $(WARNINGS) -g -o $@ ctest.c -lpam test-pam_python.pam: test-pam_python.pam.in Makefile sed "s,\\\$$PWD,$$(pwd),g" "$@.in" >"$@.tmp" mv $@.tmp $@ /etc/pam.d/test-pam_python.pam: test-pam_python.pam s=$$([ $$(id -u) = 0 ] || echo sudo); $$s ln -sf $$(pwd)/test-pam_python.pam /etc/pam.d .PHONY: test test: pam_python.so ctest /etc/pam.d/test-pam_python.pam python test.py ./ctest pam-python-1.0.2/src/pam_python.c0000644000215700017510000021677211741446574015660 0ustar rstuartit/* * Copyright (c) 2007,2009,2010,2011,2012 Russell Stuart * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ #define PAM_SM_AUTH #define PAM_SM_ACCOUNT #define PAM_SM_SESSION #define PAM_SM_PASSWORD #include #include #undef _POSIX_C_SOURCE #include #include #include #include #include #ifndef MODULE_NAME #define MODULE_NAME "libpam_python" #endif #ifndef DEFAULT_SECURITY_DIR #define DEFAULT_SECURITY_DIR "/lib/security/" #endif #define PAMHANDLE_NAME "PamHandle" #define PAMHANDLEEXCEPTION_NAME "PamException" #define arr_size(x) (sizeof(x) / sizeof(*(x))) const char libpam_python_version[] = "1.0.2"; const char libpam_python_date[] = "2012-04-12"; /* * The python interpreter's shared library. */ static char libpython_so[] = LIBPYTHON_SO; /* * Initialise Python. How this should be done changed between versions. */ static void initialise_python(void) { #if PY_MAJOR_VERSION*100 + PY_MINOR_VERSION >= 204 Py_InitializeEx(0); #else size_t signum; struct sigaction oldsigaction[NSIG]; for (signum = 0; signum < arr_size(oldsigaction); signum += 1) sigaction(signum, 0, &oldsigaction[signum]); Py_Initialize(); for (signum = 0; signum < arr_size(oldsigaction); signum += 1) sigaction(signum, &oldsigaction[signum], 0); #endif } /* * The Py_XDECREF macro gives warnings. This function doesn't. */ static void py_xdecref(PyObject* object) { Py_XDECREF(object); } /* * Generic traverse function for heap objects. */ static int generic_traverse(PyObject* self, visitproc visitor, void* arg) { PyMemberDef* member; int member_visible; PyObject* object; int py_result; PyObject** slot; member = self->ob_type->tp_members; if (member == 0) return 0; /* * Loop for python visible and python non-visible members. */ for (member_visible = 0; member_visible < 2; member_visible += 1) { for (; member->name != 0; member += 1) { if (member->type != T_OBJECT && member->type != T_OBJECT_EX) continue; slot = (PyObject**)((char*)self + member->offset); object = *slot; if (object == 0) continue; py_result = visitor(object, arg); if (py_result != 0) return py_result; } member += 1; } return 0; } /* * Clear all slots in the object. */ static void clear_slot(PyObject** slot) { PyObject* object; object = *slot; if (object != 0) { *slot = 0; Py_DECREF(object); } } static int generic_clear(PyObject* self) { PyMemberDef* member; int member_visible; member = self->ob_type->tp_members; if (member == 0) return 0; /* * Loop for python visible and python non-visible members. */ for (member_visible = 0; member_visible < 2; member_visible += 1) { for (; member->name != 0; member += 1) { if (member->type != T_OBJECT && member->type != T_OBJECT_EX) continue; clear_slot((PyObject**)((char*)self + member->offset)); } member += 1; } return 0; } /* * A dealloc for all our objects. */ static void generic_dealloc(PyObject* self) { PyTypeObject* type = self->ob_type; if (PyObject_IS_GC(self)) PyObject_GC_UnTrack(self); if (type->tp_clear != 0) type->tp_clear(self); type->tp_free(self); } /* * The PamHandleObject - the object passed to all the python module's entry * points. */ typedef struct { PyObject_HEAD /* The Python Object Header */ void* dlhandle; /* dlopen() handle */ PyObject* env; /* pamh.env */ PyObject* exception; /* pamh.exception */ char* libpam_version; /* pamh.libpam_version */ PyTypeObject* message; /* pamh.Message */ PyObject* module; /* The Python Pam Module */ pam_handle_t* pamh; /* The pam handle */ PyObject* print_exception;/* traceback.print_exception */ int py_initialized; /* True if Py_initialize() called */ PyTypeObject* response; /* pamh.Response */ PyObject* syslogFile; /* A (the) SyslogFile instance */ PyTypeObject* xauthdata; /* pamh.XAuthData */ } PamHandleObject; /* * Forward declarations. */ static int call_python_handler( PyObject** result, PamHandleObject* pamHandle, PyObject* handler_function, const char* handler_name, int flags, int argc, const char** argv); /* * The SyslogfileObject. It emulates a Python file object (in that it has * a write method). It prints to stuff passed to write() on syslog. */ #define SYSLOGFILE_NAME "SyslogFile" typedef struct { PyObject_HEAD /* The Python Object Header */ char* buffer; /* Line buffer */ int size; /* Size of the buffer in bytes */ } SyslogFileObject; /* * Clear the SyslogFileObject for the garbage collector. */ static int SyslogFile_clear(PyObject* self) { SyslogFileObject* syslogFile = (SyslogFileObject*)self; PyMem_Free(syslogFile->buffer); syslogFile->buffer = 0; syslogFile->size = 0; return generic_clear(self); } /* * Emulate python's file.write(), but write to syslog. */ static PyObject* SyslogFile_write( PyObject* self, PyObject* args, PyObject* kwds) { SyslogFileObject* syslogFile = (SyslogFileObject*)self; const char* c; const char* data = 0; int len; const char* newline; PyObject* result = 0; static char* kwlist[] = {"data", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwds, "s:write", kwlist, &data)) goto error_exit; if (syslogFile->buffer == 0) len = 0; else len = strlen(syslogFile->buffer); len += strlen(data) + 1; if (len > syslogFile->size) { const int new_size = len * 2; syslogFile->buffer = PyMem_Realloc(syslogFile->buffer, new_size); if (syslogFile->buffer == 0) { syslogFile->size = 0; goto error_exit; } if (syslogFile->size == 0) syslogFile->buffer[0] = '\0'; syslogFile->size = new_size; } strcat(syslogFile->buffer, data); for (c = syslogFile->buffer; *c != '\0'; c = newline + 1) { newline = strchr(c, '\n'); if (newline == 0) break; syslog(LOG_AUTHPRIV|LOG_ERR, "%.*s", (int)(newline - c), c); } if (c != syslogFile->buffer) strcpy(syslogFile->buffer, c); result = Py_None; Py_INCREF(result); error_exit: return result; } /* * Emulate python's file.flush(), but write to syslog. */ static void SyslogFile_flush(PyObject* self) { SyslogFileObject* syslogFile = (SyslogFileObject*)self; if (syslogFile->buffer != 0 && syslogFile->buffer[0] != '\0') { syslog(LOG_AUTHPRIV|LOG_ERR, "%s", syslogFile->buffer); syslogFile->buffer[0] = '\0'; } } static PyMethodDef SyslogFile_Methods[] = { { "write", (PyCFunction)SyslogFile_write, METH_VARARGS|METH_KEYWORDS, 0 }, {0,0,0,0} /* Sentinal */ }; /* * Open syslog. */ static void syslog_open(const char* module_path) { openlog(module_path, LOG_CONS|LOG_PID, LOG_AUTHPRIV); } /* * Close syslog. */ static void syslog_close(void) { closelog(); } /* * Type to translate a Python Exception to a PAM error. */ static int syslog_python2pam(PyObject* exception_type) { if (exception_type == PyExc_MemoryError) return PAM_BUF_ERR; return PAM_SERVICE_ERR; } /* * Return the modules filename. */ static const char* get_module_path(PamHandleObject* pamHandle) { const char* result = PyModule_GetFilename(pamHandle->module); if (result != 0) return result; return MODULE_NAME; } /* * Print an exception to syslog. */ static int syslog_path_exception(const char* module_path, const char* errormsg) { PyObject* message = 0; PyObject* name = 0; PyObject* ptype = 0; PyObject* ptraceback = 0; PyObject* pvalue = 0; int pam_result = 0; PyObject* stype = 0; const char* str_name = 0; const char* str_message = 0; PyErr_Fetch(&ptype, &pvalue, &ptraceback); /* * We don't have a PamHandleObject, so we can't print a full traceback. * Just print the exception in some recognisable form, hopefully. */ syslog_open(module_path); if (PyClass_Check(ptype)) stype = PyObject_GetAttrString(ptype, "__name__"); else { stype = ptype; Py_INCREF(stype); } if (stype != 0) { name = PyObject_Str(stype); if (name != 0) str_name = PyString_AsString(name); } if (pvalue != 0) { message = PyObject_Str(pvalue); if (message != 0) str_message = PyString_AsString(message); } if (errormsg != 0 && str_name != 0 && str_message != 0) { syslog( LOG_AUTHPRIV|LOG_ERR, "%s - %s: %s", errormsg, str_name, str_message); } else if (str_name != 0 && str_message != 0) syslog(LOG_AUTHPRIV|LOG_ERR, "%s: %s", str_name, str_message); else if (errormsg != 0 && str_name != 0) syslog(LOG_AUTHPRIV|LOG_ERR, "%s - %s", errormsg, str_name); else if (errormsg != 0 && str_message != 0) syslog(LOG_AUTHPRIV|LOG_ERR, "%s - %s", errormsg, str_message); else if (errormsg != 0) syslog(LOG_AUTHPRIV|LOG_ERR, "%s", errormsg); else if (str_name != 0) syslog(LOG_AUTHPRIV|LOG_ERR, "%s", str_name); else if (str_message != 0) syslog(LOG_AUTHPRIV|LOG_ERR, "%s", str_message); pam_result = syslog_python2pam(ptype); py_xdecref(message); py_xdecref(name); py_xdecref(ptraceback); py_xdecref(ptype); py_xdecref(pvalue); py_xdecref(stype); syslog_close(); return pam_result; } /* * Print an exception to syslog, once we are initialised. */ static int syslog_exception(PamHandleObject* pamHandle, const char* errormsg) { return syslog_path_exception(get_module_path(pamHandle), errormsg); } /* * Print an message to syslog. */ static int syslog_path_vmessage( const char* module_path, const char* message, va_list ap) { syslog_open(module_path); vsyslog(LOG_AUTHPRIV|LOG_ERR, message, ap); syslog_close(); return PAM_SERVICE_ERR; } /* * Print an message to syslog. */ static int syslog_path_message( const char* module_path, const char* message, ...) { va_list ap; int result; va_start(ap, message); result = syslog_path_vmessage(module_path, message, ap); va_end(ap); return result; } /* * Print an message to syslog, once we are initialised. */ static int syslog_message(PamHandleObject* pamHandle, const char* message, ...) { va_list ap; int result; va_start(ap, message); result = syslog_path_vmessage(get_module_path(pamHandle), message, ap); va_end(ap); return result; } /* * Print a traceback to syslog. */ static int syslog_path_traceback( const char* module_path, PamHandleObject* pamHandle) { PyObject* args = 0; PyObject* ptraceback = 0; PyObject* ptype = 0; PyObject* pvalue = 0; PyObject* py_resultobj = 0; int pam_result; PyErr_Fetch(&ptype, &pvalue, &ptraceback); /* * If there isn't a traceback just log the exception. */ if (ptraceback == 0) { PyErr_Restore(ptype, pvalue, ptraceback); return syslog_path_exception(module_path, 0); } /* * Bit messy, this. The easiest way to print a traceback is to use * the traceback module, writing through a dummy file that actually * outputs to syslog. */ syslog_open(module_path); if (ptype == 0) { ptype = Py_None; Py_INCREF(ptype); } if (pvalue == 0) { pvalue = Py_None; Py_INCREF(pvalue); } args = Py_BuildValue( "OOOOO", ptype, pvalue, ptraceback, Py_None, pamHandle->syslogFile); if (args != 0) { py_resultobj = PyEval_CallObject(pamHandle->print_exception, args); if (py_resultobj != 0) SyslogFile_flush(pamHandle->syslogFile); } pam_result = syslog_python2pam(ptype); py_xdecref(args); py_xdecref(ptraceback); py_xdecref(ptype); py_xdecref(pvalue); py_xdecref(py_resultobj); syslog_close(); return pam_result; } /* * Print an message to syslog, once we are initialised. */ static int syslog_traceback(PamHandleObject* pamHandle) { return syslog_path_traceback(get_module_path(pamHandle), pamHandle); } /* * The PamMessage object - used in conversations. */ #define PAMMESSAGE_NAME "Message" typedef struct { PyObject_HEAD /* The Python Object header */ int msg_style; /* struct pam_message.msg_style */ PyObject* msg; /* struct pam_message.msg */ } PamMessageObject; static char PamMessage_doc[] = MODULE_NAME "." PAMHANDLE_NAME "." PAMMESSAGE_NAME "(msg_style, msg)\n" " Constructs an immutable object that can be passed to\n" " " MODULE_NAME "." PAMHANDLE_NAME ".conversation(). The parameters are\n" " assigned to readonly members of the same name. msg_style determines what\n" " is done (eg prompt for input, write a message), and msg is the prompt or\n" " message."; static PyMemberDef PamMessage_members[] = { { "msg_style", T_INT, offsetof(PamMessageObject, msg_style), READONLY, "What to do with the msg member, eg display it or use as a prompt.", }, { "msg", T_OBJECT_EX, offsetof(PamMessageObject, msg), READONLY, "The text to display to the user", }, {0,0,0,0,0}, /* End of Python visible members */ {0,0,0,0,0} /* Sentinal */ }; static PyObject* PamMessage_new( PyTypeObject* type, PyObject* args, PyObject* kwds) { int err; PyObject* msg = 0; int msg_style = 0; PamMessageObject* pamMessage = 0; PyObject* self = 0; static char* kwlist[] = {"msg_style", "msg", 0}; err = PyArg_ParseTupleAndKeywords( args, kwds, "iO!:Message", kwlist, &msg_style, &PyString_Type, &msg); if (!err) goto error_exit; pamMessage = (PamMessageObject*)type->tp_alloc(type, 0); if (pamMessage == 0) goto error_exit; pamMessage->msg_style = msg_style; pamMessage->msg = msg; Py_INCREF(pamMessage->msg); self = (PyObject*)pamMessage; pamMessage = 0; error_exit: py_xdecref((PyObject*)pamMessage); return self; } /* * The PamResponse object - used in conversations. */ #define PAMRESPONSE_NAME "Response" typedef struct { PyObject_HEAD /* The Python Object header */ PyObject* resp; /* struct pam_response.resp */ int resp_retcode; /* struct pam_response.resp_retcode */ } PamResponseObject; static char PamResponse_doc[] = MODULE_NAME "." PAMHANDLE_NAME "." PAMRESPONSE_NAME "(resp, resp_retcode)\n" " Constructs an immutable object that is returned by\n" " " MODULE_NAME "." PAMHANDLE_NAME ".conversation(). The parameters are\n" " assigned to readonly members of the same name. resp is the response from\n" " the user (if one was asked for), and resp_retcode says what it means."; static PyMemberDef PamResponse_members[] = { { "resp", T_OBJECT_EX, offsetof(PamResponseObject, resp), READONLY, "The response from the user.", }, { "resp_retcode", T_INT, offsetof(PamResponseObject, resp_retcode), READONLY, "The type of response.", }, {0,0,0,0,0}, /* End of Python visible members */ {0,0,0,0,0} /* Sentinal */ }; static PyObject* PamResponse_new( PyTypeObject* type, PyObject* args, PyObject* kwds) { int err; PyObject* resp = 0; int resp_retcode = 0; PamResponseObject* pamResponse = 0; PyObject* self = 0; static char* kwlist[] = {"resp", "resp_retcode", 0}; err = PyArg_ParseTupleAndKeywords( args, kwds, "Oi:Response", kwlist, &resp, &resp_retcode); if (!err) goto error_exit; if (resp != Py_None && !PyString_Check(resp)) { PyErr_SetString(PyExc_TypeError, "resp must be a string or None"); goto error_exit; } pamResponse = (PamResponseObject*)type->tp_alloc(type, 0); if (pamResponse == 0) goto error_exit; pamResponse->resp_retcode = resp_retcode; pamResponse->resp = resp; Py_INCREF(pamResponse->resp); self = (PyObject*)pamResponse; pamResponse = 0; error_exit: py_xdecref((PyObject*)pamResponse); return self; } /* * The PamXAuthData object - used by PAM_XAUTHDATA item. */ #define PAMXAUTHDATA_NAME "XAuthData" typedef struct { PyObject_HEAD /* The Python Object header */ PyObject* name; /* struct pam_xauth_data.name */ PyObject* data; /* struct pam_xauth_data.data */ } PamXAuthDataObject; static char PamXAuthData_doc[] = MODULE_NAME "." PAMHANDLE_NAME "." PAMXAUTHDATA_NAME "(name, data)\n" " Constructs an immutable object is returned by and can be passed to\n" " the " MODULE_NAME ".xauthdata property. The parameters are\n" " assigned to readonly members of the same name."; static PyMemberDef PamXAuthData_members[] = { { "data", T_OBJECT_EX, offsetof(PamXAuthDataObject, data), READONLY, "The value of the data item. A string or None.", }, { "name", T_OBJECT_EX, offsetof(PamXAuthDataObject, name), READONLY, "The name of the data item. A string or None.", }, {0,0,0,0,0}, /* End of Python visible members */ {0,0,0,0,0} /* Sentinal */ }; static PyObject* PamXAuthData_new( PyTypeObject* type, PyObject* args, PyObject* kwds) { int err; PyObject* name = 0; PyObject* data = 0; PamXAuthDataObject* pamXAuthData = 0; PyObject* self = 0; static char* kwlist[] = {"name", "data", 0}; err = PyArg_ParseTupleAndKeywords( args, kwds, "SS:XAuthData", kwlist, &name, &data); if (!err) goto error_exit; pamXAuthData = (PamXAuthDataObject*)type->tp_alloc(type, 0); if (pamXAuthData == 0) goto error_exit; pamXAuthData->name = name; Py_INCREF(pamXAuthData->name); pamXAuthData->data = data; Py_INCREF(pamXAuthData->data); self = (PyObject*)pamXAuthData; pamXAuthData = 0; error_exit: py_xdecref((PyObject*)pamXAuthData); return self; } /* * Check a PAM return value. If the function failed raise an exception * and return -1. */ static int check_pam_result(PamHandleObject* pamHandle, int pam_result) { if (pam_result == PAM_SUCCESS) return 0; if (!PyErr_Occurred()) { PyObject* ptype; PyObject* pvalue; PyObject* ptraceback; PyObject* error_code = 0; const char* error_string = pam_strerror(pamHandle->pamh, pam_result); PyErr_SetString(pamHandle->exception, error_string); PyErr_Fetch(&ptype, &pvalue, &ptraceback); PyErr_NormalizeException(&ptype, &pvalue, &ptraceback); error_code = PyInt_FromLong(pam_result); if (error_code != NULL) PyObject_SetAttrString(pvalue, "pam_result", error_code); PyErr_Restore(ptype, pvalue, ptraceback); py_xdecref(error_code); } return -1; } /* * Python getters / setters are used to manipulate PAM's items. */ static PyObject* PamHandle_get_item(PyObject* self, int item_type) { PamHandleObject* pamHandle = (PamHandleObject*)self; const char* value; PyObject* result = 0; int pam_result; pam_result = pam_get_item(pamHandle->pamh, item_type, (const void**)&value); if (check_pam_result(pamHandle, pam_result) == -1) goto error_exit; if (value != 0) result = PyString_FromString(value); else { result = Py_None; Py_INCREF(result); } error_exit: return result; } static int PamHandle_set_item( PyObject* self, int item_type, char* item_name, PyObject* pyValue) { PamHandleObject* pamHandle = (PamHandleObject*)self; int pam_result; int result = -1; char* value; char error_message[64]; if (pyValue == Py_None) value = 0; else { value = PyString_AsString(pyValue); if (value == 0) { snprintf( error_message, sizeof(error_message), "PAM item %s must be set to a string", item_name); PyErr_SetString(PyExc_TypeError, error_message); goto error_exit; } value = strdup(value); if (value == 0) { PyErr_NoMemory(); goto error_exit; } } pam_result = pam_set_item(pamHandle->pamh, item_type, value); if (pam_result == PAM_SUCCESS) value = 0; result = check_pam_result(pamHandle, pam_result); error_exit: if (value != 0) free(value); return result; } /* * The PAM Environment Object & its iterator. */ #define PAMENV_NAME "PamEnv" typedef struct { PyObject_HEAD /* The Python Object header */ PamHandleObject* pamHandle; /* The PamHandle that owns us */ PyTypeObject* pamEnvIter_type;/* A class for our iterators */ } PamEnvObject; static PyMemberDef PamEnv_Members[] = { {0,0,0,0,0}, /* End of Python visible members */ { "Iter", T_OBJECT_EX, offsetof(PamEnvObject, pamEnvIter_type), READONLY, "Iterator class for " PAMENV_NAME }, {0,0,0,0,0} /* Sentinel */ }; #define PAMENVITER_NAME "PamEnvIter" typedef struct { PyObject_HEAD PamEnvObject* env; /* The PamEnvObject we are iterating */ int pos; /* Nest position to return */ PyObject* (*get_entry)(const char* entry); /* What to return */ } PamEnvIterObject; static PyMemberDef PamEnvIter_Members[] = { {0,0,0,0,0}, /* End of Python visible members */ { "env", T_OBJECT_EX, offsetof(PamEnvIterObject, env), READONLY, "Dictionary to iterate" }, {0,0,0,0,0} /* Sentinel */ }; /* * Create a new iterator for a PamEnv. */ static PyObject* PamEnvIter_create( PamEnvObject* pamEnv, PyObject* (*get_entry)(const char* entry)) { PyTypeObject* type = pamEnv->pamEnvIter_type; PamEnvIterObject* pamEnvIter; PyObject* result = 0; pamEnvIter = (PamEnvIterObject*)type->tp_alloc(type, 0); if (pamEnvIter == 0) goto error_exit; pamEnvIter->env = pamEnv; Py_INCREF(pamEnvIter->env); pamEnvIter->get_entry = get_entry; pamEnvIter->pos = 0; result = (PyObject*)pamEnvIter; Py_INCREF(result); error_exit: py_xdecref((PyObject*)pamEnvIter); return result; } /* * Return the next object in the iteration. */ static PyObject* PamEnvIter_iternext(PyObject* self) { PamEnvIterObject* pamEnvIter = (PamEnvIterObject*)self; char** env; int i; PyObject* result; if (pamEnvIter->env == 0) goto error_exit; env = pam_getenvlist(pamEnvIter->env->pamHandle->pamh); if (env == 0) goto error_exit; for (i = 0; env[i] != 0 && i < pamEnvIter->pos; i += 1) continue; if (env[i] == 0) goto error_exit; result = pamEnvIter->get_entry(env[i]); if (result == 0) goto error_exit; pamEnvIter->pos += 1; return result; error_exit: clear_slot((PyObject**)&pamEnvIter->env); return 0; } /* * Return a python object for the key part. */ static PyObject* PamEnvIter_key_entry(const char* entry) { const char* equals; equals = strchr(entry, '='); if (equals == 0) return PyString_FromString(entry); return PyString_FromStringAndSize(entry, equals - entry); } /* * Return a python object for the value part. */ static PyObject* PamEnvIter_value_entry(const char* entry) { const char* equals; equals = strchr(entry, '='); if (equals == 0) return PyString_FromString(""); return PyString_FromString(equals + 1); } /* * Return a python object entire item. */ static PyObject* PamEnvIter_item_entry(const char* entry) { PyObject* key = 0; PyObject* result = 0; PyObject* tuple = 0; PyObject* value = 0; key = PamEnvIter_key_entry(entry); if (key == 0) goto error_exit; value = PamEnvIter_value_entry(entry); if (key == 0) goto error_exit; tuple = PyTuple_New(2); if (tuple == 0) goto error_exit; if (PyTuple_SetItem(tuple, 0, key) == -1) goto error_exit; key = 0; /* was stolen */ if (PyTuple_SetItem(tuple, 1, value) == -1) goto error_exit; value = 0; /* was stolen */ result = tuple; tuple = 0; error_exit: py_xdecref(key); py_xdecref(tuple); py_xdecref(value); return result; } /* * Create an iterator. */ static PyObject* PamEnv_iter(PyObject* self) { PamEnvObject* pamEnv = (PamEnvObject*)self; return PamEnvIter_create(pamEnv, PamEnvIter_key_entry); } /* * Get the value of a environment key. */ static const char* PamEnv_getkey(PyObject* key) { const char* result; if (!PyString_Check(key)) { PyErr_SetString(PyExc_TypeError, "PAM environment key must be a string"); return 0; } result = PyString_AS_STRING(key); if (*result == '\0') { PyErr_SetString( PyExc_ValueError, "PAM environment key mustn't be 0 length"); return 0; } if (strchr(result, '=') != 0) { PyErr_SetString(PyExc_ValueError, "PAM environment key can't contain '='"); return 0; } return result; } /* * Return the length. */ static Py_ssize_t PamEnv_mp_length(PyObject* self) { PamEnvObject* pamEnv = (PamEnvObject*)self; char** env; int length; env = pam_getenvlist(pamEnv->pamHandle->pamh); if (env == 0) return 0; for (length = 0; env[length] != 0; length += 1) continue; return length; } /* * Lookup a key returning its value. */ static PyObject* PamEnv_mp_subscript(PyObject* self, PyObject* key) { PamEnvObject* pamEnv = (PamEnvObject*)self; PyObject* result = 0; const char* key_str; const char* value; key_str = PamEnv_getkey(key); if (key_str == 0) goto error_exit; value = pam_getenv(pamEnv->pamHandle->pamh, key_str); if (value == 0) { PyErr_SetString(PyExc_KeyError, key_str); goto error_exit; } result = PyString_FromString(value); error_exit: return result; } /* * Assign a value to a key, or delete it. */ static int PamEnv_mp_assign(PyObject* self, PyObject* key, PyObject* value) { PamEnvObject* pamEnv = (PamEnvObject*)self; char* value_str = 0; int result = -1; const char* key_str; int pam_result; key_str = PamEnv_getkey(key); if (key_str == 0) goto error_exit; if (value == 0) value_str = (char*)key_str; else { if (!PyString_Check(value)) { PyErr_SetString( PyExc_TypeError, "PAM environment value must be a string"); goto error_exit; } value_str = malloc(PyString_Size(key) + 1 + PyString_Size(value) + 1); if (value_str == 0) { PyErr_NoMemory(); goto error_exit; } strcat(strcat(strcpy(value_str, key_str), "="), PyString_AS_STRING(value)); } pam_result = pam_putenv(pamEnv->pamHandle->pamh, value_str); if (pam_result == PAM_BAD_ITEM) { PyErr_SetString(PyExc_KeyError, key_str); goto error_exit; } if (check_pam_result(pamEnv->pamHandle, pam_result) == -1) goto error_exit; value_str = 0; result = 0; error_exit: if (value_str != key_str && value_str != 0) free(value_str); return result; } static PyMappingMethods PamEnv_as_mapping = { PamEnv_mp_length, /* mp_length */ PamEnv_mp_subscript, /* mp_subscript */ PamEnv_mp_assign, /* mp_ass_subscript */ }; /* * Check if a key is in the environment. */ static PyObject* PamEnv_has_key( PyObject* self, PyObject* args, PyObject* kwds) { PamEnvObject* pamEnv = (PamEnvObject*)self; PyObject* key; PyObject* result = 0; const char* key_str; const char* value_str; static char* kwlist[] = {"key", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwds, "O:has_key", kwlist, &key)) goto error_exit; key_str = PamEnv_getkey(key); if (key_str == 0) goto error_exit; value_str = pam_getenv(pamEnv->pamHandle->pamh, key_str); result = value_str != 0 ? Py_True : Py_False; Py_INCREF(result); error_exit: return result; } /* * Lookup a key and return its value, throwing KeyError if the key * doesn't exist. */ static PyObject* PamEnv_getitem( PyObject* self, PyObject* args, PyObject* kwds) { PyObject* result = 0; PyObject* key; static char* kwlist[] = {"key", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwds, "O:__getitem__", kwlist, &key)) goto error_exit; result = PamEnv_mp_subscript(self, key); error_exit: return result; } /* * Lookup a key and return its value, returning None or a default if it * doesn't exist. */ static PyObject* PamEnv_get( PyObject* self, PyObject* args, PyObject* kwds) { int err; PamEnvObject* pamEnv = (PamEnvObject*)self; PyObject* default_value = 0; PyObject* result = 0; PyObject* key; const char* key_str; const char* value_str; static char* kwlist[] = {"key", "default", NULL}; err = PyArg_ParseTupleAndKeywords( args, kwds, "O|O:get", kwlist, &key, &default_value); if (!err) goto error_exit; key_str = PamEnv_getkey(key); if (key_str == 0) goto error_exit; value_str = pam_getenv(pamEnv->pamHandle->pamh, key_str); if (value_str != 0) result = PyString_FromString(value_str); else { result = default_value != 0 ? default_value : Py_None; Py_INCREF(result); } error_exit: return result; } /* * Return all objects in the environment as a sequence. */ static PyObject* PamEnv_as_sequence( PyObject* self, PyObject* (*get_entry)(const char* entry)) { PamEnvObject* pamEnv = (PamEnvObject*)self; PyObject* list = 0; PyObject* result = 0; PyObject* entry = 0; char** env; int i; int length; env = pam_getenvlist(pamEnv->pamHandle->pamh); if (env == 0) length = 0; else { for (length = 0; env[length] != 0; length += 1) continue; } list = PyList_New(length); if (list == 0) goto error_exit; for (i = 0; env[i] != 0; i += 1) { entry = get_entry(env[i]); if (entry == 0) goto error_exit; if (PyList_SetItem(list, i, entry) == -1) goto error_exit; entry = 0; /* was stolen */ } result = list; list = 0; error_exit: py_xdecref(list); py_xdecref(entry); return result; } /* * Return all (key, value) pairs. */ static PyObject* PamEnv_items( PyObject* self, PyObject* args, PyObject* kwds) { static char* kwlist[] = {NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwds, ":items", kwlist)) return 0; return PamEnv_as_sequence(self, PamEnvIter_item_entry); } /* * An iterator for all (key, value) pairs. */ static PyObject* PamEnv_iteritems( PyObject* self, PyObject* args, PyObject* kwds) { PamEnvObject* pamEnv = (PamEnvObject*)self; static char* kwlist[] = {NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwds, ":iteritems", kwlist)) return 0; return PamEnvIter_create(pamEnv, PamEnvIter_item_entry); } /* * An iterator for the keys. */ static PyObject* PamEnv_iterkeys( PyObject* self, PyObject* args, PyObject* kwds) { PamEnvObject* pamEnv = (PamEnvObject*)self; static char* kwlist[] = {NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwds, ":iterkeys", kwlist)) return 0; return PamEnvIter_create(pamEnv, PamEnvIter_key_entry); } /* * An iterator for the values. */ static PyObject* PamEnv_itervalues( PyObject* self, PyObject* args, PyObject* kwds) { PamEnvObject* pamEnv = (PamEnvObject*)self; static char* kwlist[] = {NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwds, ":itervalues", kwlist)) return 0; return PamEnvIter_create(pamEnv, PamEnvIter_value_entry); } /* * Return all keys. */ static PyObject* PamEnv_keys( PyObject* self, PyObject* args, PyObject* kwds) { static char* kwlist[] = {NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwds, ":keys", kwlist)) return 0; return PamEnv_as_sequence(self, PamEnvIter_key_entry); } /* * Return all (key, value) pairs. */ static PyObject* PamEnv_values( PyObject* self, PyObject* args, PyObject* kwds) { static char* kwlist[] = {NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwds, ":values", kwlist)) return 0; return PamEnv_as_sequence(self, PamEnvIter_value_entry); } static PyMethodDef PamEnv_Methods[] = { {"__contains__", (PyCFunction)PamEnv_has_key,METH_VARARGS|METH_KEYWORDS, 0}, {"__getitem__", (PyCFunction)PamEnv_getitem,METH_VARARGS|METH_KEYWORDS, 0}, {"get", (PyCFunction)PamEnv_get, METH_VARARGS|METH_KEYWORDS, 0}, {"has_key", (PyCFunction)PamEnv_has_key,METH_VARARGS|METH_KEYWORDS, 0}, {"items", (PyCFunction)PamEnv_items, METH_VARARGS|METH_KEYWORDS, 0}, {"iteritems", (PyCFunction)PamEnv_iteritems,METH_VARARGS|METH_KEYWORDS, 0}, {"iterkeys", (PyCFunction)PamEnv_iterkeys,METH_VARARGS|METH_KEYWORDS, 0}, {"itervalues", (PyCFunction)PamEnv_itervalues,METH_VARARGS|METH_KEYWORDS, 0}, {"keys", (PyCFunction)PamEnv_keys, METH_VARARGS|METH_KEYWORDS, 0}, {"values", (PyCFunction)PamEnv_values, METH_VARARGS|METH_KEYWORDS, 0}, {0,0,0,0} /* Sentinel */ }; /* * Python Getter's for the constants. */ #define DECLARE_CONSTANT_GET_VALUE(x, v) \ static PyObject* PamHandle_Constant_ ## x(PyObject* object, void* closure) { \ object = object; \ closure = closure; \ return PyLong_FromLong(v); \ } #define DECLARE_CONSTANT_GET(x) \ static PyObject* PamHandle_Constant_ ## x(PyObject* object, void* closure) { \ object = object; \ closure = closure; \ return PyLong_FromLong(x); \ } #ifdef HAVE_PAM_FAIL_DELAY DECLARE_CONSTANT_GET_VALUE(HAVE_PAM_FAIL_DELAY, 1) #else DECLARE_CONSTANT_GET_VALUE(HAVE_PAM_FAIL_DELAY, 0) #endif DECLARE_CONSTANT_GET(PAM_ABORT) DECLARE_CONSTANT_GET(PAM_ACCT_EXPIRED) DECLARE_CONSTANT_GET(PAM_AUTH_ERR) DECLARE_CONSTANT_GET(PAM_AUTHINFO_UNAVAIL) DECLARE_CONSTANT_GET(PAM_AUTHTOK) DECLARE_CONSTANT_GET(PAM_AUTHTOK_DISABLE_AGING) DECLARE_CONSTANT_GET(PAM_AUTHTOK_ERR) DECLARE_CONSTANT_GET(PAM_AUTHTOK_EXPIRED) DECLARE_CONSTANT_GET(PAM_AUTHTOK_LOCK_BUSY) DECLARE_CONSTANT_GET(PAM_AUTHTOK_RECOVER_ERR) #ifdef PAM_AUTHTOK_RECOVERY_ERR DECLARE_CONSTANT_GET(PAM_AUTHTOK_RECOVERY_ERR) #endif #ifdef PAM_AUTHTOK_TYPE DECLARE_CONSTANT_GET(PAM_AUTHTOK_TYPE) #endif DECLARE_CONSTANT_GET(PAM_BAD_ITEM) DECLARE_CONSTANT_GET(PAM_BINARY_PROMPT) DECLARE_CONSTANT_GET(PAM_BUF_ERR) DECLARE_CONSTANT_GET(PAM_CHANGE_EXPIRED_AUTHTOK) DECLARE_CONSTANT_GET(PAM_CONV) DECLARE_CONSTANT_GET(PAM_CONV_AGAIN) DECLARE_CONSTANT_GET(PAM_CONV_ERR) DECLARE_CONSTANT_GET(PAM_CRED_ERR) DECLARE_CONSTANT_GET(PAM_CRED_EXPIRED) DECLARE_CONSTANT_GET(PAM_CRED_INSUFFICIENT) DECLARE_CONSTANT_GET(PAM_CRED_UNAVAIL) DECLARE_CONSTANT_GET(PAM_DATA_REPLACE) DECLARE_CONSTANT_GET(PAM_DATA_SILENT) DECLARE_CONSTANT_GET(PAM_DELETE_CRED) DECLARE_CONSTANT_GET(PAM_DISALLOW_NULL_AUTHTOK) DECLARE_CONSTANT_GET(PAM_ERROR_MSG) DECLARE_CONSTANT_GET(PAM_ESTABLISH_CRED) DECLARE_CONSTANT_GET(PAM_FAIL_DELAY) DECLARE_CONSTANT_GET(PAM_IGNORE) DECLARE_CONSTANT_GET(PAM_INCOMPLETE) DECLARE_CONSTANT_GET(PAM_MAX_MSG_SIZE) DECLARE_CONSTANT_GET(PAM_MAX_NUM_MSG) DECLARE_CONSTANT_GET(PAM_MAX_RESP_SIZE) DECLARE_CONSTANT_GET(PAM_MAXTRIES) DECLARE_CONSTANT_GET(PAM_MODULE_UNKNOWN) DECLARE_CONSTANT_GET(PAM_NEW_AUTHTOK_REQD) DECLARE_CONSTANT_GET(PAM_NO_MODULE_DATA) DECLARE_CONSTANT_GET(PAM_OLDAUTHTOK) DECLARE_CONSTANT_GET(PAM_OPEN_ERR) DECLARE_CONSTANT_GET(PAM_PERM_DENIED) DECLARE_CONSTANT_GET(PAM_PRELIM_CHECK) DECLARE_CONSTANT_GET(PAM_PROMPT_ECHO_OFF) DECLARE_CONSTANT_GET(PAM_PROMPT_ECHO_ON) DECLARE_CONSTANT_GET(PAM_RADIO_TYPE) DECLARE_CONSTANT_GET(PAM_REFRESH_CRED) DECLARE_CONSTANT_GET(PAM_REINITIALIZE_CRED) DECLARE_CONSTANT_GET(_PAM_RETURN_VALUES) DECLARE_CONSTANT_GET(PAM_RHOST) DECLARE_CONSTANT_GET(PAM_RUSER) DECLARE_CONSTANT_GET(PAM_SERVICE) DECLARE_CONSTANT_GET(PAM_SERVICE_ERR) DECLARE_CONSTANT_GET(PAM_SESSION_ERR) DECLARE_CONSTANT_GET(PAM_SILENT) DECLARE_CONSTANT_GET(PAM_SUCCESS) DECLARE_CONSTANT_GET(PAM_SYMBOL_ERR) DECLARE_CONSTANT_GET(PAM_SYSTEM_ERR) DECLARE_CONSTANT_GET(PAM_TEXT_INFO) DECLARE_CONSTANT_GET(PAM_TRY_AGAIN) DECLARE_CONSTANT_GET(PAM_TTY) DECLARE_CONSTANT_GET(PAM_UPDATE_AUTHTOK) DECLARE_CONSTANT_GET(PAM_USER) DECLARE_CONSTANT_GET(PAM_USER_PROMPT) DECLARE_CONSTANT_GET(PAM_USER_UNKNOWN) #ifdef PAM_XAUTHDATA DECLARE_CONSTANT_GET(PAM_XAUTHDATA) #endif #ifdef PAM_XDISPLAY DECLARE_CONSTANT_GET(PAM_XDISPLAY) #endif #define CONSTANT_GETSET(x) {#x, PamHandle_Constant_ ## x, 0, 0, 0} #define MAKE_GETSET_ITEM(t) \ static PyObject* PamHandle_get_##t(PyObject* self, void* closure) \ { \ closure = closure; \ return PamHandle_get_item(self, PAM_##t); \ } \ static int PamHandle_set_##t(PyObject* self, PyObject* pyValue, void* closure) \ { \ closure = closure; \ return PamHandle_set_item(self, PAM_##t, "PAM_" #t, pyValue); \ } MAKE_GETSET_ITEM(AUTHTOK) #ifdef PAM_AUTHTOK_TYPE MAKE_GETSET_ITEM(AUTHTOK_TYPE) #endif MAKE_GETSET_ITEM(OLDAUTHTOK) MAKE_GETSET_ITEM(RHOST) MAKE_GETSET_ITEM(RUSER) MAKE_GETSET_ITEM(SERVICE) MAKE_GETSET_ITEM(TTY) MAKE_GETSET_ITEM(USER) MAKE_GETSET_ITEM(USER_PROMPT) #ifdef PAM_XDISPLAY MAKE_GETSET_ITEM(XDISPLAY) #endif #ifdef PAM_XAUTHDATA /* * The PAM_XAUTHDATA item doesn't take strings like the rest of them. * It wants a pam_xauth_data structure. */ static PyObject* PamHandle_get_XAUTHDATA(PyObject* self, void* closure) { PamHandleObject* pamHandle = (PamHandleObject*)self; PyObject* newargs = 0; PyObject* result = 0; int pam_result; struct pam_xauth_data* xauth_data = 0; closure = closure; pam_result = pam_get_item( pamHandle->pamh, PAM_XAUTHDATA, (const void**)&xauth_data); if (check_pam_result(pamHandle, pam_result) == -1) goto error_exit; if (xauth_data == 0) { result = Py_None; Py_INCREF(result); } else { newargs = Py_BuildValue( "s#s#", xauth_data->name, xauth_data->namelen, xauth_data->data, xauth_data->datalen); if (newargs == 0) goto error_exit; result = pamHandle->xauthdata->tp_new(pamHandle->xauthdata, newargs, 0); if (result == 0) goto error_exit; } error_exit: py_xdecref(newargs); return result; } static int PamHandle_set_XAUTHDATA( PyObject* self, PyObject* pyValue, void* closure) { PamHandleObject* pamHandle = (PamHandleObject*)self; PyObject* name = 0; PyObject* data = 0; int result = -1; const char* data_str; const char* name_str; int pam_result; struct pam_xauth_data xauth_data; closure = closure; xauth_data.name = 0; xauth_data.data = 0; /* * Get the name. */ name = PyObject_GetAttrString(pyValue, "name"); if (name == 0) goto error_exit; name_str = PyString_AsString(name); if (name_str == 0) { PyErr_SetString(PyExc_TypeError, "xauthdata.name must be a string"); goto error_exit; } xauth_data.name = strdup(name_str); if (xauth_data.name == 0) { PyErr_NoMemory(); goto error_exit; } xauth_data.namelen = PyString_GET_SIZE(name); /* * Get the data. */ data = PyObject_GetAttrString(pyValue, "data"); if (data == 0) goto error_exit; data_str = PyString_AsString(data); if (data_str == 0) { PyErr_SetString(PyExc_TypeError, "xauthdata.data must be a string"); goto error_exit; } xauth_data.data = strdup(data_str); if (xauth_data.data == 0) { PyErr_NoMemory(); goto error_exit; } xauth_data.datalen = PyString_GET_SIZE(data); /* * Set the item. If that worked PAM will have swallowed the strings inside * of it, so we must not free them. */ pam_result = pam_set_item(pamHandle->pamh, PAM_XAUTHDATA, &xauth_data); if (pam_result == PAM_SUCCESS) { xauth_data.name = 0; xauth_data.data = 0; } result = check_pam_result(pamHandle, pam_result); error_exit: py_xdecref(data); py_xdecref(name); if (xauth_data.name != 0) free(xauth_data.name); if (xauth_data.data != 0) free(xauth_data.data); return result; } #endif /* * Getters and setters. */ static PyGetSetDef PamHandle_Getset[] = { /* * Items. */ {"authtok", PamHandle_get_AUTHTOK, PamHandle_set_AUTHTOK, "Authentication token", 0}, #ifdef PAM_AUTHTOK_TYPE {"authtok_type",PamHandle_get_AUTHTOK_TYPE,PamHandle_set_AUTHTOK_TYPE,"XXX in the \"New XXX password:\" prompt", 0}, #endif {"oldauthtok", PamHandle_get_OLDAUTHTOK, PamHandle_set_OLDAUTHTOK, "Old authentication token", 0}, {"rhost", PamHandle_get_RHOST, PamHandle_set_RHOST, "Requesting host name", 0}, {"ruser", PamHandle_get_RUSER, PamHandle_set_RUSER, "Requesting user name", 0}, {"service", PamHandle_get_SERVICE, PamHandle_set_SERVICE, "Service (pam stack) name", 0}, {"tty", PamHandle_get_TTY, PamHandle_set_TTY, "Terminal name", 0}, {"user", PamHandle_get_USER, PamHandle_set_USER, "Authorized user name", 0}, {"user_prompt", PamHandle_get_USER_PROMPT, PamHandle_set_USER_PROMPT, "Prompt asking for users name", 0}, #ifdef PAM_XAUTHDATA {"xauthdata", PamHandle_get_XAUTHDATA, PamHandle_set_XAUTHDATA, "The name of the X display ($DISPLAY)", 0}, #endif #ifdef PAM_XDISPLAY {"xdisplay", PamHandle_get_XDISPLAY, PamHandle_set_XDISPLAY, "The name of the X display ($DISPLAY)", 0}, #endif /* * Constants. */ CONSTANT_GETSET(HAVE_PAM_FAIL_DELAY), CONSTANT_GETSET(PAM_ABORT), CONSTANT_GETSET(PAM_ACCT_EXPIRED), CONSTANT_GETSET(PAM_AUTH_ERR), CONSTANT_GETSET(PAM_AUTHINFO_UNAVAIL), CONSTANT_GETSET(PAM_AUTHTOK), CONSTANT_GETSET(PAM_AUTHTOK_DISABLE_AGING), CONSTANT_GETSET(PAM_AUTHTOK_ERR), CONSTANT_GETSET(PAM_AUTHTOK_EXPIRED), CONSTANT_GETSET(PAM_AUTHTOK_LOCK_BUSY), CONSTANT_GETSET(PAM_AUTHTOK_RECOVER_ERR), #ifdef PAM_AUTHTOK_RECOVERY_ERR CONSTANT_GETSET(PAM_AUTHTOK_RECOVERY_ERR), #endif #ifdef PAM_AUTHTOK_TYPE CONSTANT_GETSET(PAM_AUTHTOK_TYPE), #endif CONSTANT_GETSET(PAM_BAD_ITEM), CONSTANT_GETSET(PAM_BINARY_PROMPT), CONSTANT_GETSET(PAM_BUF_ERR), CONSTANT_GETSET(PAM_CHANGE_EXPIRED_AUTHTOK), CONSTANT_GETSET(PAM_CONV), CONSTANT_GETSET(PAM_CONV_AGAIN), CONSTANT_GETSET(PAM_CONV_ERR), CONSTANT_GETSET(PAM_CRED_ERR), CONSTANT_GETSET(PAM_CRED_EXPIRED), CONSTANT_GETSET(PAM_CRED_INSUFFICIENT), CONSTANT_GETSET(PAM_CRED_UNAVAIL), CONSTANT_GETSET(PAM_DATA_REPLACE), CONSTANT_GETSET(PAM_DATA_SILENT), CONSTANT_GETSET(PAM_DELETE_CRED), CONSTANT_GETSET(PAM_DISALLOW_NULL_AUTHTOK), CONSTANT_GETSET(PAM_ERROR_MSG), CONSTANT_GETSET(PAM_ESTABLISH_CRED), CONSTANT_GETSET(PAM_FAIL_DELAY), CONSTANT_GETSET(PAM_IGNORE), CONSTANT_GETSET(PAM_INCOMPLETE), CONSTANT_GETSET(PAM_MAX_MSG_SIZE), CONSTANT_GETSET(PAM_MAX_NUM_MSG), CONSTANT_GETSET(PAM_MAX_RESP_SIZE), CONSTANT_GETSET(PAM_MAXTRIES), CONSTANT_GETSET(PAM_MODULE_UNKNOWN), CONSTANT_GETSET(PAM_NEW_AUTHTOK_REQD), CONSTANT_GETSET(PAM_NO_MODULE_DATA), CONSTANT_GETSET(PAM_OLDAUTHTOK), CONSTANT_GETSET(PAM_OPEN_ERR), CONSTANT_GETSET(PAM_PERM_DENIED), CONSTANT_GETSET(PAM_PRELIM_CHECK), CONSTANT_GETSET(PAM_PROMPT_ECHO_OFF), CONSTANT_GETSET(PAM_PROMPT_ECHO_ON), CONSTANT_GETSET(PAM_RADIO_TYPE), CONSTANT_GETSET(PAM_REFRESH_CRED), CONSTANT_GETSET(PAM_REINITIALIZE_CRED), CONSTANT_GETSET(_PAM_RETURN_VALUES), CONSTANT_GETSET(PAM_RHOST), CONSTANT_GETSET(PAM_RUSER), CONSTANT_GETSET(PAM_SERVICE), CONSTANT_GETSET(PAM_SERVICE_ERR), CONSTANT_GETSET(PAM_SESSION_ERR), CONSTANT_GETSET(PAM_SILENT), CONSTANT_GETSET(PAM_SUCCESS), CONSTANT_GETSET(PAM_SYMBOL_ERR), CONSTANT_GETSET(PAM_SYSTEM_ERR), CONSTANT_GETSET(PAM_TEXT_INFO), CONSTANT_GETSET(PAM_TRY_AGAIN), CONSTANT_GETSET(PAM_TTY), CONSTANT_GETSET(PAM_UPDATE_AUTHTOK), CONSTANT_GETSET(PAM_USER), CONSTANT_GETSET(PAM_USER_PROMPT), CONSTANT_GETSET(PAM_USER_UNKNOWN), CONSTANT_GETSET(PAM_XAUTHDATA), #ifdef PAM_XDISPLAY CONSTANT_GETSET(PAM_XDISPLAY), #endif {0,0,0,0,0} /* Sentinel */ }; /* * Convert a PamHandleObject.Message style object to a pam_message structure. */ static int PamHandle_conversation_2message( struct pam_message* message, PyObject* object) { PyObject* msg = 0; PyObject* msg_style = 0; int result = -1; msg_style = PyObject_GetAttrString(object, "msg_style"); if (msg_style == 0) goto error_exit; if (!PyInt_Check(msg_style) && !PyLong_Check(msg_style)) { PyErr_SetString(PyExc_TypeError, "message.msg_style must be an int"); goto error_exit; } message->msg_style = PyInt_AsLong(msg_style); msg = PyObject_GetAttrString(object, "msg"); if (msg == 0) goto error_exit; message->msg = PyString_AsString(msg); if (message->msg == 0) { PyErr_SetString(PyExc_TypeError, "message.msg must be a string"); goto error_exit; } result = 0; error_exit: py_xdecref(msg); py_xdecref(msg_style); return result; } /* * Convert a pam_response structure to a PamHandleObject.Response object. */ static PyObject* PamHandle_conversation_2response( PamHandleObject* pamHandle, struct pam_response* pam_response) { PyObject* newargs; PyObject* result = 0; newargs = Py_BuildValue("si", pam_response->resp, pam_response->resp_retcode); if (newargs == 0) goto error_exit; result = pamHandle->response->tp_new(pamHandle->response, newargs, 0); if (result == 0) goto error_exit; error_exit: py_xdecref(newargs); return result; } /* * Run a PAM "conversation". */ static PyObject* PamHandle_conversation( PyObject* self, PyObject* args, PyObject* kwds) { int err; PamHandleObject* pamHandle = (PamHandleObject*)self; PyObject* prompts = 0; PyObject* result_tuple = 0; struct pam_message* message_array = 0; struct pam_message** message_vector = 0; struct pam_response* response_array = 0; PyObject* result = 0; PyObject* response = 0; const struct pam_conv*conv; int prompt_count; int i; int pam_result; int prompts_is_sequence; int py_result; static char* kwlist[] = {"prompts", NULL}; err = PyArg_ParseTupleAndKeywords( args, kwds, "O:conversation", kwlist, &prompts); if (!err) goto error_exit; pam_result = pam_get_item(pamHandle->pamh, PAM_CONV, (const void**)&conv); if (check_pam_result(pamHandle, pam_result) == -1) goto error_exit; prompts_is_sequence = PySequence_Check(prompts); if (!prompts_is_sequence) prompt_count = 1; else { prompt_count = PySequence_Size(prompts); if (prompt_count == 0) { result = prompts; Py_INCREF(result); goto error_exit; } } message_array = PyMem_Malloc(prompt_count * sizeof(*message_array)); if (message_array == 0) { PyErr_NoMemory(); goto error_exit; } if (!prompts_is_sequence) { py_result = PamHandle_conversation_2message(message_array, prompts); if (py_result == -1) goto error_exit; } else { for (i = 0; i < prompt_count; i += 1) { PyObject* message = PySequence_ITEM(prompts, i); if (message == 0) goto error_exit; py_result = PamHandle_conversation_2message(&message_array[i], message); Py_DECREF(message); if (py_result == -1) goto error_exit; } } message_vector = PyMem_Malloc(prompt_count * sizeof(*message_vector)); if (message_vector == 0) { PyErr_NoMemory(); goto error_exit; } for (i = 0; i < prompt_count; i += 1) message_vector[i] = &message_array[i]; pam_result = conv->conv( prompt_count, (const struct pam_message**)message_vector, &response_array, conv->appdata_ptr); if (check_pam_result(pamHandle, pam_result) == -1) goto error_exit; if (!prompts_is_sequence) result = PamHandle_conversation_2response(pamHandle, response_array); else { result_tuple = PyTuple_New(prompt_count); if (result_tuple == 0) goto error_exit; for (i = 0; i < prompt_count; i += 1) { response = PamHandle_conversation_2response( pamHandle, &response_array[i]); if (response == 0) goto error_exit; if (PyTuple_SetItem(result_tuple, i, response) == -1) goto error_exit; response = 0; /* was stolen */ } result = result_tuple; result_tuple = 0; } error_exit: py_xdecref(response); py_xdecref(result_tuple); PyMem_Free(message_array); PyMem_Free(message_vector); if (response_array != 0) free(response_array); return result; } /* * Set the fail delay. */ static PyObject* PamHandle_fail_delay( PyObject* self, PyObject* args, PyObject* kwds) { int err; PamHandleObject* pamHandle = (PamHandleObject*)self; int micro_sec = 0; int pam_result; PyObject* result = 0; static char* kwlist[] = {"micro_sec", NULL}; err = PyArg_ParseTupleAndKeywords( args, kwds, "i:fail_delay", kwlist, µ_sec); if (!err) goto error_exit; pam_result = pam_fail_delay(pamHandle->pamh, micro_sec); if (check_pam_result(pamHandle, pam_result) == -1) goto error_exit; result = Py_None; Py_INCREF(result); error_exit: return result; } /* * Get the user's name, promping if it isn't known. */ static PyObject* PamHandle_get_user( PyObject* self, PyObject* args, PyObject* kwds) { PamHandleObject* pamHandle = (PamHandleObject*)self; char* prompt = 0; PyObject* result = 0; int pam_result; const char* user = 0; static char* kwlist[] = {"prompt", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwds, "|z:get_user", kwlist, &prompt)) goto error_exit; pam_result = pam_get_user(pamHandle->pamh, &user, prompt); if (check_pam_result(pamHandle, pam_result) == -1) goto error_exit; if (user != 0) result = PyString_FromString(user); else { result = Py_None; Py_INCREF(result); } if (result == 0) goto error_exit; error_exit: return result; } /* * Set a PAM environment variable. */ static PyObject* PamHandle_strerror( PyObject* self, PyObject* args, PyObject* kwds) { PamHandleObject* pamHandle = (PamHandleObject*)self; const char* err; int errnum; PyObject* result = 0; const int debug_magic = 0x4567abcd; static char* kwlist[] = {"errnum", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwds, "i:strerror", kwlist, &errnum)) goto error_exit; /* * A kludge so we can test exceptions. */ if (errnum >= debug_magic && errnum < debug_magic + _PAM_RETURN_VALUES) { if (check_pam_result(pamHandle, errnum - debug_magic) == -1) goto error_exit; } err = pam_strerror(pamHandle->pamh, errnum); if (err == 0) { result = Py_None; Py_INCREF(result); } else { result = PyString_FromString(err); if (result == 0) goto error_exit; } error_exit: return result; } static PyMethodDef PamHandle_Methods[] = { { "conversation", (PyCFunction)PamHandle_conversation, METH_VARARGS|METH_KEYWORDS, MODULE_NAME "." PAMHANDLE_NAME "." "conversation(prompts)\n" " Ask the application to issue the prompts to the user and return the\n" " users responses. The 'prompts' can be one, or a list of\n" " " MODULE_NAME "." PAMHANDLE_NAME "." PAMMESSAGE_NAME " objects. The return value is one,\n" " or an array of " MODULE_NAME "." PAMHANDLE_NAME "." PAMRESPONSE_NAME " objects." }, { "fail_delay", (PyCFunction)PamHandle_fail_delay, METH_VARARGS|METH_KEYWORDS, MODULE_NAME "." PAMHANDLE_NAME "." "fail_delay(micro_sec)\n" " Sets the amount of time a failed authenticate attempt should delay for\n" " in micro seconds. This amount reset to 0 after every authenticate\n" " attempt." }, { "get_user", (PyCFunction)PamHandle_get_user, METH_VARARGS|METH_KEYWORDS, MODULE_NAME "." PAMHANDLE_NAME "." "getuser([prompt])\n" " If " PAMHANDLE_NAME ".user isn't None return it, otherwise ask the\n" " application to display the string 'prompt' and enter the user name. The\n" " user name (a string) is returned. It will be None if it isn't known." }, { "strerror", (PyCFunction)PamHandle_strerror, METH_VARARGS|METH_KEYWORDS, MODULE_NAME "." PAMHANDLE_NAME "." "strerror(errnum)\n" " Return a string describing the pam error errnum." }, {0,0,0,0} /* Sentinel */ }; static PyMemberDef PamHandle_Members[] = { { "env", T_OBJECT_EX, offsetof(PamHandleObject, env), READONLY, "The PAM environment mapping." }, { "exception", T_OBJECT_EX, offsetof(PamHandleObject, exception), READONLY, "Exception raised when a call to PAM fails." }, { "libpam_version", T_STRING, offsetof(PamHandleObject, libpam_version), READONLY, "The runtime PAM version." }, { "Message", T_OBJECT, offsetof(PamHandleObject, message), READONLY, "Message class that can be passed to " MODULE_NAME "." PAMHANDLE_NAME ".conversation()" }, { "module", T_OBJECT, offsetof(PamHandleObject, module), READONLY, "The user module (ie you!)" }, { "pamh", T_LONG, offsetof(PamHandleObject, pamh), READONLY, "The PAM handle." }, { "py_initialized", T_INT, offsetof(PamHandleObject, py_initialized), READONLY, "True if Py_Initialize was called." }, { "Response", T_OBJECT, offsetof(PamHandleObject, response), READONLY, "Response class returned by " MODULE_NAME "." PAMHANDLE_NAME ".conversation()" }, { "XAuthData", T_OBJECT, offsetof(PamHandleObject, xauthdata), READONLY, "XAuthData class used by " MODULE_NAME "." PAMHANDLE_NAME ".xauthdata" }, {0,0,0,0,0}, /* End of Python visible members */ { "syslogFile", T_OBJECT, offsetof(PamHandleObject, syslogFile), READONLY, "File like object that writes to syslog" }, {0,0,0,0,0} /* Sentinal */ }; static char PamHandle_Doc[] = MODULE_NAME "." PAMHANDLE_NAME "\n" " A an instance of this class makes the PAM API available to the Python\n" " module. It is the first argument to every method PAM calls in the module."; static int pypam_initialize_count = 0; static void cleanup_pamHandle(pam_handle_t* pamh, void* data, int error_status) { PamHandleObject* pamHandle = (PamHandleObject*)data; void* dlhandle = pamHandle->dlhandle; PyObject* py_resultobj = 0; PyObject* handler_function = 0; int py_initialized; static const char* handler_name = "pam_sm_end"; pamh = pamh; error_status = error_status; handler_function = PyObject_GetAttrString(pamHandle->module, (char*)handler_name); if (handler_function == 0) PyErr_Restore(0, 0, 0); else { call_python_handler( &py_resultobj, pamHandle, handler_function, handler_name, 0, 0, 0); } py_xdecref(py_resultobj); py_xdecref(handler_function); py_initialized = pamHandle->py_initialized; Py_DECREF(pamHandle); if (py_initialized) { pypam_initialize_count -= 1; if (pypam_initialize_count == 0) Py_Finalize(); } dlclose(dlhandle); } /* * Find the module, and load it if we haven't see it before. Returns * PAM_SUCCESS if it worked, the PAM error code otherwise. */ static int load_user_module( PyObject** user_module, PamHandleObject* pamHandle, const char* module_path) { PyObject* builtins = 0; PyObject* module_dict = 0; FILE* module_fp = 0; char* user_module_name = 0; PyObject* py_resultobj = 0; char* dot; int pam_result; int py_result; /* * Open the file. */ module_fp = fopen(module_path, "r"); if (module_fp == 0) { syslog_path_message( module_path, "Can not open module: %s", strerror(errno)); pam_result = PAM_OPEN_ERR; goto error_exit; } /* * Create the new module. */ user_module_name = strrchr(module_path, '/'); if (user_module_name == 0) user_module_name = strdup(module_path); else user_module_name = strdup(user_module_name + 1); if (user_module_name == 0) { syslog_path_message(MODULE_NAME, "out of memory"); pam_result = PAM_BUF_ERR; goto error_exit; } dot = strrchr(user_module_name, '.'); if (dot != 0 || strcmp(dot, ".py") == 0) *dot = '\0'; *user_module = PyModule_New(user_module_name); if (*user_module == 0) { pam_result = syslog_path_exception( module_path, "PyModule_New(pamh.module.__file__) failed"); goto error_exit; } py_result = PyModule_AddStringConstant(*user_module, "__file__", (char*)module_path); if (py_result == -1) { pam_result = syslog_path_exception( module_path, "PyModule_AddStringConstant(pamh.module, '__file__', module_path) failed"); goto error_exit; } /* * Add __builtins__. */ if (!PyObject_HasAttrString(*user_module , "__builtins__")) { builtins = PyEval_GetBuiltins(); Py_INCREF(builtins); /* is stolen */ if (PyModule_AddObject(*user_module, "__builtins__", builtins) == -1) { pam_result = syslog_path_exception( module_path, "PyModule_AddObject(pamh.module, '__builtins__', builtins) failed"); goto error_exit; } builtins = 0; /* was borrowed */ } /* * Call it. */ module_dict = PyModule_GetDict(*user_module); py_resultobj = PyRun_FileExFlags( module_fp, module_path, Py_file_input, module_dict, module_dict, 1, 0); module_fp = 0; /* it was closed */ module_dict = 0; /* was borrowed */ /* * If that didn't work there was an exception. Errk! */ if (py_resultobj == 0) { pam_result = syslog_path_traceback(module_path, pamHandle); goto error_exit; } pam_result = PAM_SUCCESS; error_exit: py_xdecref(builtins); py_xdecref(module_dict); if (module_fp != 0) fclose(module_fp); if (user_module_name != 0) free(user_module_name); py_xdecref(py_resultobj); return pam_result; } /* * Create a new Python type on the heap. This differs from creating a static * type in non-obvious ways. */ static PyTypeObject* newHeapType( PyObject* module, /* Module declaring type (required) */ const char* name, /* tp_name (required) */ int basicsize, /* tp_basicsize (required) */ char* doc, /* tp_doc (optional) */ inquiry clear, /* tp_clear (optional) */ struct PyMethodDef* methods, /* tp_methods (optional) */ struct PyMemberDef* members, /* tp_members (optional) */ struct PyGetSetDef* getset, /* tp_getset (optional) */ newfunc new /* tp_new (optional) */ ) { PyObject* pyName = 0; PyTypeObject* result = 0; PyTypeObject* type = 0; pyName = PyString_FromString(name); if (pyName == 0) goto error_exit; type = (PyTypeObject*)PyType_Type.tp_alloc(&PyType_Type, 0); if (type == 0) goto error_exit; type->tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HEAPTYPE|Py_TPFLAGS_HAVE_GC; type->tp_basicsize = basicsize; type->tp_dealloc = generic_dealloc; if (doc != 0) { char *doc_string = PyMem_Malloc(strlen(doc)+1); if (doc_string == 0) { PyErr_NoMemory(); goto error_exit; } strcpy(doc_string, doc); type->tp_doc = doc_string; } type->tp_traverse = generic_traverse; type->tp_clear = clear != 0 ? clear : generic_clear; type->tp_methods = methods; type->tp_members = members; type->tp_getset = getset; type->tp_name = PyString_AsString(pyName); ((PyHeapTypeObject*)type)->ht_name = pyName; pyName = 0; PyType_Ready(type); type->tp_new = new; if (PyDict_SetItemString(type->tp_dict, "__module__", module) == -1) goto error_exit; result = type; type = 0; error_exit: py_xdecref(pyName); py_xdecref((PyObject*)type); return result; } /* * Create a type and return an instance of that type. The newly created * type object is discarded. */ static PyObject* newSingletonObject( PyObject* module, /* Module declaring type (required) */ const char* name, /* tp_name (required) */ int basicsize, /* tp_basicsize (required) */ char* doc, /* tp_doc (optional) */ inquiry clear, /* tp_clear (optional) */ struct PyMethodDef* methods, /* tp_methods (optional) */ struct PyMemberDef* members, /* tp_members (optional) */ struct PyGetSetDef* getset /* tp_getset (optional) */ ) { PyObject* result = 0; PyTypeObject* type = 0; type = newHeapType( module, name, basicsize, doc, clear, methods, members, getset, 0); if (type != 0) result = type->tp_alloc(type, 0); py_xdecref((PyObject*)type); return result; } /* * Find the PamHandle object used by the pamh instance, creating one if it * doesn't exist. Returns a pam_result, which will be PAM_SUCCESS if it * works. */ static int get_pamHandle( PamHandleObject** result, pam_handle_t* pamh, const char** argv) { void* dlhandle = 0; int do_initialize; char* module_dir; char* module_path = 0; char* module_data_name = 0; PyObject* user_module = 0; PamEnvObject* pamEnv = 0; PamHandleObject* pamHandle = 0; PyObject* pamHandle_module = 0; SyslogFileObject* syslogFile = 0; PyObject* tracebackModule = 0; int pam_result; /* * Figure out where the module lives. */ if (argv == 0 || argv[0] == 0) { syslog_path_message(MODULE_NAME, "python module name not supplied"); pam_result = PAM_MODULE_UNKNOWN; goto error_exit; } if (argv[0][0] == '/') module_dir = ""; else module_dir = DEFAULT_SECURITY_DIR; module_path = malloc(strlen(module_dir) + strlen(argv[0]) + 1); if (module_path == 0) { syslog_path_message(MODULE_NAME, "out of memory"); pam_result = PAM_BUF_ERR; goto error_exit; } strcat(strcpy(module_path, module_dir), argv[0]); /* * See if we already exist. */ module_data_name = malloc(strlen(MODULE_NAME) + 1 + strlen(module_path) + 1); if (module_data_name == 0) { syslog_path_message(MODULE_NAME, "out of memory"); pam_result = PAM_BUF_ERR; goto error_exit; } strcat(strcat(strcpy(module_data_name, MODULE_NAME), "."), module_path); pam_result = pam_get_data(pamh, module_data_name, (void*)result); if (pam_result == PAM_SUCCESS) { (*result)->pamh = pamh; Py_INCREF(*result); goto error_exit; } /* * Initialize Python if required. */ dlhandle = dlopen(libpython_so, RTLD_NOW|RTLD_GLOBAL); if (dlhandle == 0) { pam_result = syslog_path_message( module_path, "Can't load python library %s: %s", libpython_so, strerror(errno)); goto error_exit; } do_initialize = pypam_initialize_count > 0 || !Py_IsInitialized(); if (do_initialize) { if (pypam_initialize_count == 0) initialise_python(); pypam_initialize_count += 1; } /* * Create a throw away module because heap types need one, apparently. */ pamHandle_module = PyModule_New((char*)module_data_name); if (pamHandle_module == 0) { pam_result = syslog_path_exception( module_path, "PyModule_New(module_data_name) failed"); goto error_exit; } /* * Create the type we use for our object. */ pamHandle = (PamHandleObject*)newSingletonObject( pamHandle_module, /* __module__ */ PAMHANDLE_NAME "_type", /* tp_name */ sizeof(PamHandleObject), /* tp_basicsize */ PamHandle_Doc, /* tp_doc */ 0, /* tp_clear */ PamHandle_Methods, /* tp_methods */ PamHandle_Members, /* tp_members */ PamHandle_Getset); /* tp_getset */ if (pamHandle == 0) { pam_result = syslog_path_exception(module_path, "Can't create pamh Object"); goto error_exit; } if (PyObject_IS_GC((PyObject*)pamHandle)) PyObject_GC_UnTrack(pamHandle); /* No refs are visible to python */ pamHandle->dlhandle = dlhandle; dlhandle = 0; pamHandle->libpam_version = __STRING(__LINUX_PAM__) "." __STRING(__LINUX_PAM_MINOR__); pamHandle->pamh = pamh; pamHandle->py_initialized = do_initialize; pamHandle->exception = PyErr_NewException( PAMHANDLE_NAME "." PAMHANDLEEXCEPTION_NAME, PyExc_StandardError, NULL); if (pamHandle->exception == NULL) goto error_exit; /* * Create the object we use to handle the PAM environment. */ pamEnv = (PamEnvObject*)newSingletonObject( pamHandle_module, /* __module__ */ PAMENV_NAME "_type", /* tp_name */ sizeof(PamEnvObject), /* tp_basicsize */ 0, /* tp_doc */ 0, /* tp_clear */ PamEnv_Methods, /* tp_methods */ PamEnv_Members, /* tp_members */ 0); /* tp_getset */ if (pamEnv == 0) { pam_result = syslog_path_exception(module_path, "Can't create pamh.env"); goto error_exit; } pamEnv->ob_type->tp_as_mapping = &PamEnv_as_mapping; pamEnv->ob_type->tp_iter = PamEnv_iter; pamEnv->pamHandle = pamHandle; pamEnv->pamEnvIter_type = newHeapType( pamHandle_module, /* __module__ */ PAMENVITER_NAME "_type", /* tp_name */ sizeof(PamEnvIterObject), /* tp_basicsize */ 0, /* tp_doc */ 0, /* tp_clear */ 0, /* tp_methods */ PamEnvIter_Members, /* tp_members */ 0, /* tp_getset */ 0); /* tp_new */ if (pamEnv->pamEnvIter_type == 0) goto error_exit; if (PyObject_IS_GC((PyObject*)pamEnv->pamEnvIter_type)) { /* * No refs are visible to python. */ PyObject_GC_UnTrack(pamEnv->pamEnvIter_type); } pamEnv->pamEnvIter_type->tp_iter = PyObject_SelfIter; pamEnv->pamEnvIter_type->tp_iternext = PamEnvIter_iternext; pamHandle->env = (PyObject*)pamEnv; pamEnv = 0; /* * Create the type for the PamMessageObject. */ pamHandle->message = newHeapType( pamHandle_module, /* __module__ */ PAMMESSAGE_NAME "_type", /* tp_name */ sizeof(PamMessageObject), /* tp_basicsize */ PamMessage_doc, /* tp_doc */ 0, /* tp_clear */ 0, /* tp_methods */ PamMessage_members, /* tp_members */ 0, /* tp_getset */ PamMessage_new); /* tp_new */ if (pamHandle->message == 0) { pam_result = syslog_path_exception( module_path, "Can't create pamh.Message"); goto error_exit; } /* * Create the type for the PamResponseObject. */ pamHandle->response = newHeapType( pamHandle_module, /* __module__ */ PAMRESPONSE_NAME "_type", /* tp_name */ sizeof(PamResponseObject), /* tp_basicsize */ PamResponse_doc, /* tp_doc */ 0, /* tp_clear */ 0, /* tp_methods */ PamResponse_members, /* tp_members */ 0, /* tp_getset */ PamResponse_new); /* tp_new */ if (pamHandle->response == 0) { pam_result = syslog_path_exception( module_path, "Can't create pamh.Response"); goto error_exit; } /* * Create the Syslogfile Type & Object. */ syslogFile = (SyslogFileObject*)newSingletonObject( pamHandle_module, /* __module__ */ SYSLOGFILE_NAME "_type", /* tp_name */ sizeof(SyslogFileObject), /* tp_basicsize */ 0, /* tp_doc */ SyslogFile_clear, /* tp_clear */ SyslogFile_Methods, /* tp_methods */ 0, /* tp_members */ 0); /* tp_getset */ if (syslogFile == 0) { pam_result = syslog_path_exception( module_path, "Can't create pamh.syslogFile"); goto error_exit; } syslogFile->buffer = 0; syslogFile->size = 0; pamHandle->syslogFile = (PyObject*)syslogFile; syslogFile = 0; /* * The traceback object. */ tracebackModule = PyImport_ImportModule("traceback"); if (tracebackModule == 0) { pam_result = syslog_path_exception( module_path, "PyImport_ImportModule('traceback') failed"); goto error_exit; } pamHandle->print_exception = PyObject_GetAttrString(tracebackModule, "print_exception"); if (pamHandle->print_exception == 0) { pam_result = syslog_path_exception( module_path, "PyObject_GetAttrString(traceback, 'print_exception') failed"); goto error_exit; } Py_INCREF(pamHandle->print_exception); /* Borrowed reference */ /* * Create the type for the PamXAuthDataObject. */ pamHandle->xauthdata = newHeapType( pamHandle_module, /* __module__ */ PAMXAUTHDATA_NAME "_type", /* tp_name */ sizeof(PamXAuthDataObject), /* tp_basicsize */ PamXAuthData_doc, /* tp_doc */ 0, /* tp_clear */ 0, /* tp_methods */ PamXAuthData_members, /* tp_members */ 0, /* tp_getset */ PamXAuthData_new); /* tp_new */ if (pamHandle->xauthdata == 0) { pam_result = syslog_path_exception( module_path, "Can't create pamh.XAuthData"); goto error_exit; } /* * Now we have error reporting set up import the module. */ pam_result = load_user_module(&user_module, pamHandle, module_path); if (pam_result != PAM_SUCCESS) goto error_exit; pamHandle->module = user_module; Py_INCREF(pamHandle->module); /* * That worked. Save a reference to it. */ Py_INCREF(pamHandle); pam_set_data(pamh, module_data_name, pamHandle, cleanup_pamHandle); *result = pamHandle; pamHandle = 0; error_exit: if (module_path != 0) free(module_path); if (module_data_name != 0) free(module_data_name); py_xdecref(user_module); py_xdecref((PyObject*)pamEnv); py_xdecref((PyObject*)pamHandle); py_xdecref(pamHandle_module); py_xdecref((PyObject*)syslogFile); py_xdecref(tracebackModule); return pam_result; } /* * Call the python handler. */ static int call_python_handler( PyObject** result, PamHandleObject* pamHandle, PyObject* handler_function, const char* handler_name, int flags, int argc, const char** argv) { PyObject* arg_object = 0; PyObject* argv_object = 0; PyObject* flags_object = 0; PyObject* handler_args = 0; PyObject* py_resultobj = 0; int i; int pam_result; if (!PyCallable_Check(handler_function)) { pam_result = syslog_message(pamHandle, "%s isn't a function.", handler_name); goto error_exit; } /* * Set up the arguments for the python function. If we aren't passed * argv then this is pam_sm_end() and it is only given pamh. */ if (argv == 0) handler_args = Py_BuildValue("(O)", pamHandle); else { flags_object = PyInt_FromLong(flags); if (flags_object == 0) { pam_result = syslog_exception(pamHandle, "PyInt_FromLong(flags) failed"); goto error_exit; } argv_object = PyList_New(argc); if (argv_object == 0) { pam_result = syslog_exception(pamHandle, "PyList_New(argc) failed"); goto error_exit; } for (i = 0; i < argc; i += 1) { arg_object = PyString_FromString(argv[i]); if (arg_object == 0) { pam_result = syslog_exception( pamHandle, "PyString_FromString(argv[i]) failed"); goto error_exit; } PyList_SET_ITEM(argv_object, i, arg_object); arg_object = 0; /* It was pinched by SET_ITEM */ } handler_args = Py_BuildValue("OOO", pamHandle, flags_object, argv_object); } if (handler_args == 0) { pam_result = syslog_exception( pamHandle, "handler_args = Py_BuildValue(...) failed"); goto error_exit; } /* * Call the Python handler function. */ py_resultobj = PyEval_CallObject(handler_function, handler_args); /* * Did it throw an exception? */ if (py_resultobj == 0) { pam_result = syslog_traceback(pamHandle); goto error_exit; } *result = py_resultobj; py_resultobj = 0; pam_result = PAM_SUCCESS; error_exit: py_xdecref(arg_object); py_xdecref(argv_object); py_xdecref(flags_object); py_xdecref(handler_args); py_xdecref(py_resultobj); return pam_result; } /* * Calls the Python method that will handle PAM's request to the module. */ static int call_handler( const char* handler_name, pam_handle_t* pamh, int flags, int argc, const char** argv) { PyObject* handler_function = 0; PamHandleObject* pamHandle = 0; PyObject* py_resultobj = 0; int pam_result; /* * Initialise Python, and get a copy of our object. */ pam_result = get_pamHandle(&pamHandle, pamh, argv); if (pam_result != PAM_SUCCESS) goto error_exit; /* * See if the function we have to call has been defined. */ handler_function = PyObject_GetAttrString(pamHandle->module, (char*)handler_name); if (handler_function == 0) { syslog_message(pamHandle, "%s() isn't defined.", handler_name); pam_result = PAM_SYMBOL_ERR; goto error_exit; } pam_result = call_python_handler( &py_resultobj, pamHandle, handler_function, handler_name, flags, argc, argv); if (pam_result != PAM_SUCCESS) goto error_exit; /* * It must return an integer. */ if (!PyInt_Check(py_resultobj) && !PyLong_Check(py_resultobj)) { pam_result = syslog_message( pamHandle, "%s() did not return an integer.", handler_name); goto error_exit; } pam_result = PyInt_AsLong(py_resultobj); error_exit: py_xdecref(handler_function); py_xdecref((PyObject*)pamHandle); py_xdecref(py_resultobj); return pam_result; } PAM_EXTERN int pam_sm_authenticate( pam_handle_t* pamh, int flags, int argc, const char** argv) { return call_handler("pam_sm_authenticate", pamh, flags, argc, argv); } PAM_EXTERN int pam_sm_setcred( pam_handle_t* pamh, int flags, int argc, const char** argv) { return call_handler("pam_sm_setcred", pamh, flags, argc, argv); } PAM_EXTERN int pam_sm_acct_mgmt( pam_handle_t* pamh, int flags, int argc, const char** argv) { return call_handler("pam_sm_acct_mgmt", pamh, flags, argc, argv); } PAM_EXTERN int pam_sm_open_session( pam_handle_t* pamh, int flags, int argc, const char** argv) { return call_handler("pam_sm_open_session", pamh, flags, argc, argv); } PAM_EXTERN int pam_sm_close_session( pam_handle_t* pamh, int flags, int argc, const char** argv) { return call_handler("pam_sm_close_session", pamh, flags, argc, argv); } PAM_EXTERN int pam_sm_chauthtok( pam_handle_t* pamh, int flags, int argc, const char** argv) { return call_handler("pam_sm_chauthtok", pamh, flags, argc, argv); } pam-python-1.0.2/doc/0000755000215700017510000000000011741446574013275 5ustar rstuartitpam-python-1.0.2/doc/html/0000755000215700017510000000000011741446577014244 5ustar rstuartitpam-python-1.0.2/doc/html/searchindex.js0000644000215700017510000001223311741446577017100 0ustar rstuartitSearch.setIndex({objects:{"":{pam_sm_close_session:[0,0,1,""],tty:[0,1,1,""],authtok_type:[0,1,1,""],PAM_BUF_ERR:[0,1,1,""],libpam_version:[0,1,1,""],pam_sm_authenticate:[0,0,1,""],rhost:[0,1,1,""],py_initialized:[0,1,1,""],pam_sm_setcred:[0,0,1,""],xdisplay:[0,1,1,""],authtok:[0,1,1,""],service:[0,1,1,""],pam_sm_acct_mgmt:[0,0,1,""],PAM_MODULE_UNKNOWN:[0,1,1,""],pam_sm_open_session:[0,0,1,""],PAM_SYMBOL_ERR:[0,1,1,""],env:[0,1,1,""],oldauthtok:[0,1,1,""],PAM_SERVICE_ERR:[0,1,1,""],"__builtins__":[0,1,1,""],"__file__":[0,1,1,""],user:[0,1,1,""],pamh:[0,1,1,""],user_prompt:[0,1,1,""],pam_sm_end:[0,0,1,""],exception:[0,1,1,""],PAM_OPEN_ERR:[0,1,1,""],pam_sm_chauthtok:[0,0,1,""],ruser:[0,1,1,""],xauthdata:[0,1,1,""]},PamHandle:{strerror:[0,2,1,""],Response:[0,2,1,""],conversation:[0,2,1,""],fail_delay:[0,2,1,""],get_user:[0,2,1,""],XAuthData:[0,2,1,""],Message:[0,2,1,""]}},terms:{all:0,code:0,global:0,pam_getenv:0,secondli:0,stumbl:0,follow:0,millisecond:0,privat:0,doom:0,pam_messag:0,program:0,those:0,pam_authtok:0,introduc:0,sourc:0,everi:0,risk:0,pam_get_data:0,account:0,failur:0,syntax:0,oldauthtok:0,administr:0,ret_cod:0,list:0,iter:0,"try":0,item:0,stderr:0,refer:0,pam_success:0,pam_tti:0,jump:0,syslog:0,design:0,pass:0,minimis:0,section:0,invok:0,access:0,pam_user_prompt:0,version:0,"new":0,method:0,gener:0,never:0,here:0,debugg:0,address:0,path:0,safer:0,becom:0,valu:0,wait:0,invis:0,pam_sm_authent:0,convers:0,current:0,prior:0,aka:0,configur:0,regardless:0,modul:0,api:0,heurist:0,instal:0,unit:0,from:0,describ:0,would:0,memori:0,pam_sm_close_sess:0,two:0,next:0,few:0,live:0,call:0,msg:0,type:0,tell:0,more:0,sort:0,flag:0,known:0,hold:0,must:0,none:0,work:0,strerror:0,remain:0,can:0,pam_xauth_data:0,learn:0,pam_strerror:0,def:0,control:0,prompt:0,give:0,xdisplai:0,share:0,py_fin:0,want:0,string:0,delai:0,end:0,secur:0,pam_module_unknown:0,anoth:0,default_us:0,how:0,env:0,map:0,log_authpriv:0,referenc:0,after:0,befor:0,mai:0,data:0,alloc:0,bind:0,correspond:0,caus:0,environ:0,allow:0,finalis:0,tty:0,enter:0,becaus:0,paramet:0,shorter:0,easier:0,non:0,messag:0,"return":0,thei:0,python:0,safe:0,auth:0,pam_sm_:0,pam_get_us:0,nor:0,introduct:0,name:0,pam_open_err:0,authent:0,mysteri:0,trap:0,each:0,debug:0,mean:0,compil:0,wasn:0,pam_chauthtok:0,happen:0,variabl:0,pam_close_sess:0,space:0,goe:0,open:0,rel:0,print:0,authtok_typ:0,"__builtins__":0,given:0,argv:0,reason:0,pam_conv:0,ask:0,thrown:0,could:0,traceback:0,initialis:0,thing:0,length:0,isn:0,imposs:0,first:0,oper:0,directli:0,pam_xdisplai:0,done:0,rhost:0,blank:0,facil:0,differ:0,pam_fail_delai:0,interact:0,system:0,construct:0,pam_symbol_err:0,pam_oldauthtok:0,"final":0,option:0,namespac:0,copi:0,incur:0,nobodi:0,than:0,wide:0,provid:0,structur:0,cite:0,sai:0,arg:0,argument:0,corrupt:0,have:0,requisit:0,"null":0,packag:0,imagin:0,equival:0,destroi:0,also:0,ideal:0,which:0,noth:0,pam_permit:0,pam_set_item:0,importantli:0,distribut:0,normal:0,object:0,most:0,pam_sm_open_sess:0,breakpoint:0,"class":0,don:0,doe:0,inde:0,pam_setcr:0,xauthdata:0,sigsegv:0,random:0,pam_get_item:0,session:0,penalti:0,absolut:0,onli:0,writer:0,should:0,local:0,pam_sm_end:0,"__file__":0,stop:0,get_us:0,requir:0,emb:0,pam_servic:0,bad:0,contain:0,where:0,valid:0,set:0,see:0,result:0,respons:0,fail:0,best:0,pam_sm_acct_mgmt:0,pypam:0,someth:0,pam_sm_setcr:0,written:0,won:0,"import":0,across:0,kei:0,isol:0,job:0,pamh:0,pam_:0,last:0,foreign:0,etc:0,instanc:0,mani:0,login:0,pdb:0,load:0,point:0,pampython:0,pam_start:0,suppli:0,guid:0,assum:0,duplic:0,creat:0,three:0,destructor:0,interpret:0,"abstract":0,execfil:0,pam_python:0,ani:0,present:0,"case":0,pam_buf_err:0,servic:0,defin:0,"while":0,abov:0,error:0,exist:0,pam_accept:0,pamhandl:0,them:0,itself:0,conf:0,sever:0,develop:0,standarderror:0,author:0,perform:0,suggest:0,make:0,same:0,member:0,handl:0,document:0,pam:0,conflict:0,backtrac:0,hand:0,rais:0,user:0,chang:0,lib:0,scenario:0,firstli:0,entri:0,exampl:0,thi:0,programm:0,usual:0,just:0,resp:0,obtain:0,rest:0,via:0,struct:0,expos:0,except:0,add:0,pam_end:0,applic:0,read:0,big:0,pam_acct_mgmt:0,pam_result:0,password:0,pam_service_err:0,like:0,manual:0,integ:0,singl:0,decis:0,pam_getenvlist:0,right:0,often:0,msg_style:0,pam_respons:0,"export":0,unless:0,librari:0,authtok:0,leak:0,avoid:0,subclass:0,larg:0,pam_putenv:0,either:0,encourag:0,who:0,run:0,inspect:0,immut:0,"throw":0,py_initi:0,actual:0,pam_sm_chauthtok:0,stuart:0,routin:0,own:0,primarili:0,automat:0,pam_authent:0,storag:0,your:0,log:0,wai:0,aren:0,support:0,avail:0,start:0,pam_rhost:0,interfac:0,includ:0,"var":0,pam_us:0,"function":0,errnum:0,newer:0,bug:0,possibl:0,"default":0,maximum:0,until:0,ruser:0,otherwis:0,problem:0,gone:0,constant:0,user_prompt:0,pam_open_sess:0,"int":0,dure:0,doesn:0,repres:0,diagnost:0,implement:0,file:0,russel:0,check:0,fail_delai:0,when:0,libpam_vers:0,other:0,test:0,you:0,pam_set_data:0,sequenc:0,pam_rus:0,pam_xauthdata:0,pam_authtok_typ:0,longer:0,unload:0,directori:0,descript:0,rule:0,write:0,ignor:0,potenti:0,time:0},objtypes:{"0":"py:function","1":"py:data","2":"py:method"},titles:["pam_python"],objnames:{"0":["py","function","Python function"],"1":["py","data","Python data"],"2":["py","method","Python method"]},filenames:["pam_python"]})pam-python-1.0.2/doc/html/objects.inv0000644000215700017510000000123111741446577016410 0ustar rstuartit# Sphinx inventory version 2 # Project: pam_python # Version: 1.0.2 # The remainder of this file is compressed using zlib. xÚ•TËnÛ0¼ë+4Ç8@¯¹ù¡"F#Ûpê>N-®%"IKÃê×—Œ¤:‘¹ÙÔÌrfv¹ Ž®®¹¬s‹ì^Ð#ˆ|ö5×´%ºÃFÉ»[ñå&_À¬É%ƒË[ÆxÚãóuøù2 •L@¬úòmzðRPk³JɯI·|ÝÍˬU쉺›•¥bÎß׋µ@MÕ¼¥ôgú©ìh á·µ{ù$å=Áf>E£-<&3€ÎÈÙ™ QÆŠÓZ*‹¼²—hTŒ° æ*äJfìÊþÄE·×™¸í%Ã…¶:žÊ\æ2 ±-©„²@,Xëåø>ÝŸœ|‘–¿ÇŸeˆ]@1ŠôuØ z&Øiˆ@ÿÏÝEÆ(-xûˆ2/Éâðû}¤¸àÇp|3Z›ií }Ä!! Óø~${¬‰³÷¨;Â%GNÿ ,M¹¬LŽˆ¾0nµ ‰mLvçwFˆšâö¤CŸÂ™WØ”ªBÒÖ-&˜ ãQnW‡Ç‚6ß7Û_›´;”ù‰Wpµ]zŽßJIsûô§\lFä99÷=X­¤+P‚%ö4H-ö?×Ë"A+!GÇri ‰BO\@võv¢\ðNºÖt«›$T!Ú¨VcÚÜ€Lyrp©@c| ]ÿžûV­2e°¶»b“Ъqå7¯æ ¶ár½„rlÐ:û Index — pam_python 1.0.2 documentation pam-python-1.0.2/doc/html/_static/0000755000215700017510000000000011741446577015672 5ustar rstuartitpam-python-1.0.2/doc/html/_static/doctools.js0000644000215700017510000001527011653777212020056 0ustar rstuartit/* * doctools.js * ~~~~~~~~~~~ * * Sphinx JavaScript utilities for all documentation. * * :copyright: Copyright 2007-2011 by the Sphinx team, see AUTHORS. * :license: BSD, see LICENSE for details. * */ /** * select a different prefix for underscore */ $u = _.noConflict(); /** * make the code below compatible with browsers without * an installed firebug like debugger if (!window.console || !console.firebug) { var names = ["log", "debug", "info", "warn", "error", "assert", "dir", "dirxml", "group", "groupEnd", "time", "timeEnd", "count", "trace", "profile", "profileEnd"]; window.console = {}; for (var i = 0; i < names.length; ++i) window.console[names[i]] = function() {}; } */ /** * small helper function to urldecode strings */ jQuery.urldecode = function(x) { return decodeURIComponent(x).replace(/\+/g, ' '); } /** * small helper function to urlencode strings */ jQuery.urlencode = encodeURIComponent; /** * This function returns the parsed url parameters of the * current request. Multiple values per key are supported, * it will always return arrays of strings for the value parts. */ jQuery.getQueryParameters = function(s) { if (typeof s == 'undefined') s = document.location.search; var parts = s.substr(s.indexOf('?') + 1).split('&'); var result = {}; for (var i = 0; i < parts.length; i++) { var tmp = parts[i].split('=', 2); var key = jQuery.urldecode(tmp[0]); var value = jQuery.urldecode(tmp[1]); if (key in result) result[key].push(value); else result[key] = [value]; } return result; }; /** * small function to check if an array contains * a given item. */ jQuery.contains = function(arr, item) { for (var i = 0; i < arr.length; i++) { if (arr[i] == item) return true; } return false; }; /** * highlight a given string on a jquery object by wrapping it in * span elements with the given class name. */ jQuery.fn.highlightText = function(text, className) { function highlight(node) { if (node.nodeType == 3) { var val = node.nodeValue; var pos = val.toLowerCase().indexOf(text); if (pos >= 0 && !jQuery(node.parentNode).hasClass(className)) { var span = document.createElement("span"); span.className = className; span.appendChild(document.createTextNode(val.substr(pos, text.length))); node.parentNode.insertBefore(span, node.parentNode.insertBefore( document.createTextNode(val.substr(pos + text.length)), node.nextSibling)); node.nodeValue = val.substr(0, pos); } } else if (!jQuery(node).is("button, select, textarea")) { jQuery.each(node.childNodes, function() { highlight(this); }); } } return this.each(function() { highlight(this); }); }; /** * Small JavaScript module for the documentation. */ var Documentation = { init : function() { this.fixFirefoxAnchorBug(); this.highlightSearchWords(); this.initIndexTable(); }, /** * i18n support */ TRANSLATIONS : {}, PLURAL_EXPR : function(n) { return n == 1 ? 0 : 1; }, LOCALE : 'unknown', // gettext and ngettext don't access this so that the functions // can safely bound to a different name (_ = Documentation.gettext) gettext : function(string) { var translated = Documentation.TRANSLATIONS[string]; if (typeof translated == 'undefined') return string; return (typeof translated == 'string') ? translated : translated[0]; }, ngettext : function(singular, plural, n) { var translated = Documentation.TRANSLATIONS[singular]; if (typeof translated == 'undefined') return (n == 1) ? singular : plural; return translated[Documentation.PLURALEXPR(n)]; }, addTranslations : function(catalog) { for (var key in catalog.messages) this.TRANSLATIONS[key] = catalog.messages[key]; this.PLURAL_EXPR = new Function('n', 'return +(' + catalog.plural_expr + ')'); this.LOCALE = catalog.locale; }, /** * add context elements like header anchor links */ addContextElements : function() { $('div[id] > :header:first').each(function() { $('\u00B6'). attr('href', '#' + this.id). attr('title', _('Permalink to this headline')). appendTo(this); }); $('dt[id]').each(function() { $('\u00B6'). attr('href', '#' + this.id). attr('title', _('Permalink to this definition')). appendTo(this); }); }, /** * workaround a firefox stupidity */ fixFirefoxAnchorBug : function() { if (document.location.hash && $.browser.mozilla) window.setTimeout(function() { document.location.href += ''; }, 10); }, /** * highlight the search words provided in the url in the text */ highlightSearchWords : function() { var params = $.getQueryParameters(); var terms = (params.highlight) ? params.highlight[0].split(/\s+/) : []; if (terms.length) { var body = $('div.body'); window.setTimeout(function() { $.each(terms, function() { body.highlightText(this.toLowerCase(), 'highlighted'); }); }, 10); $('') .appendTo($('#searchbox')); } }, /** * init the domain index toggle buttons */ initIndexTable : function() { var togglers = $('img.toggler').click(function() { var src = $(this).attr('src'); var idnum = $(this).attr('id').substr(7); $('tr.cg-' + idnum).toggle(); if (src.substr(-9) == 'minus.png') $(this).attr('src', src.substr(0, src.length-9) + 'plus.png'); else $(this).attr('src', src.substr(0, src.length-8) + 'minus.png'); }).css('display', ''); if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) { togglers.click(); } }, /** * helper function to hide the search marks again */ hideSearchWords : function() { $('#searchbox .highlight-link').fadeOut(300); $('span.highlighted').removeClass('highlighted'); }, /** * make the url absolute */ makeURL : function(relativeURL) { return DOCUMENTATION_OPTIONS.URL_ROOT + '/' + relativeURL; }, /** * get the current relative url */ getCurrentURL : function() { var path = document.location.pathname; var parts = path.split(/\//); $.each(DOCUMENTATION_OPTIONS.URL_ROOT.split(/\//), function() { if (this == '..') parts.pop(); }); var url = parts.join('/'); return path.substring(url.lastIndexOf('/') + 1, path.length - 1); } }; // quick alias for translations _ = Documentation.gettext; $(document).ready(function() { Documentation.init(); }); pam-python-1.0.2/doc/html/_static/down-pressed.png0000644000215700017510000000056011644410761020777 0ustar rstuartit‰PNG  IHDRóÿasRGB®ÎébKGDùC» pHYs × ×B(›xtIMEÚ -vF#ðIDAT8ËÍÒ!OAàïÚJ, ++@ I v¢bÿ@Wñ7F’ HNâ±ú# ‚4¡8Ì6¹4×6Tñ’MvvÞ¼7³»êœûöDs¿‡aóxâ1†U îq‚;<¦ˆÏ E¸Â-f)âºj%ßpˆo4xFà78G…>æ)â-ƒ ž ¡ÂEYm4%7YTk-¾–Q¶a–"NWAo-y†eqÒá¾,)â ÓÒYÓÑú´ptŽÐå½\hóq´Îím˜sÔz¦ìG]ÄNñ‡Òa…‡röçß¶¨s^lã vh\î2Ù%ðâßãŽ0EeRvØIEND®B`‚pam-python-1.0.2/doc/html/_static/comment-bright.png0000644000215700017510000000665411644410761021316 0ustar rstuartit‰PNG  IHDRóÿa OiCCPPhotoshop ICC profilexÚSgTSé=÷ÞôBKˆ€”KoR RB‹€‘&*! Jˆ!¡ÙQÁEEÈ ˆŽŽ€ŒQ, Š Øä!¢Žƒ£ˆŠÊûá{£kÖ¼÷æÍþµ×>ç¬ó³ÏÀ –H3Q5€ ©BàƒÇÄÆáä.@ $p³d!sý#ø~<<+"À¾xÓ ÀM›À0‡ÿêB™\€„Àt‘8K€@zŽB¦@F€˜&S `ËcbãP-`'æÓ€ø™{[”! ‘ eˆDh;¬ÏVŠEX0fKÄ9Ø-0IWfH°·ÀÎ ² 0Qˆ…){`È##x„™FòW<ñ+®ç*x™²<¹$9E[-qWW.(ÎI+6aaš@.Ây™24àóÌ ‘àƒóýxήÎÎ6޶_-ê¿ÿ"bbãþåÏ«p@át~Ñþ,/³€;€mþ¢%îh^  u÷‹f²@µ éÚWópø~<ß5°j>{‘-¨]cöK'XtÀâ÷ò»oÁÔ(€hƒáÏwÿï?ýG %€fI’q^D$.Tʳ?ÇD *°AôÁ,ÀÁÜÁ ü`6„B$ÄÂBB d€r`)¬‚B(†Í°*`/Ô@4ÀQh†“p.ÂU¸=púažÁ(¼ AÈa!ÚˆbŠX#Ž™…ø!ÁH‹$ ɈQ"K‘5H1RŠT UHò=r9‡\Fº‘;È2‚ü†¼G1”²Q=Ô µC¹¨7„F¢ Ðdt1š ›Ðr´=Œ6¡çЫhÚ>CÇ0Àè3Äl0.ÆÃB±8, “c˱"¬ «Æ°V¬»‰õcϱwEÀ 6wB aAHXLXNØH¨ $4Ú 7 „QÂ'"“¨K´&ºùÄb21‡XH,#Ö/{ˆCÄ7$‰C2'¹I±¤TÒÒFÒnR#é,©›4H#“ÉÚdk²9”, +È…ääÃä3ää!ò[ b@q¤øSâ(RÊjJåå4åe˜2AU£šRݨ¡T5ZB­¡¶R¯Q‡¨4uš9̓IK¥­¢•Óhh÷i¯ètºÝ•N—ÐWÒËéGè—èôw †ƒÇˆg(›gw¯˜L¦Ó‹ÇT071ë˜ç™™oUX*¶*|‘Ê •J•&•*/T©ª¦ªÞª UóUËT©^S}®FU3Sã© Ô–«UªPëSSg©;¨‡ªg¨oT?¤~Yý‰YÃLÃOC¤Q ±_ã¼Æ c³x,!k «†u5Ä&±ÍÙ|v*»˜ý»‹=ª©¡9C3J3W³Ró”f?ã˜qøœtN ç(§—ó~ŠÞï)â)¦4L¹1e\kª–—–X«H«Q«Gë½6®í§¦½E»YûAÇJ'\'GgÎçSÙSݧ §M=:õ®.ªk¥¡»Dw¿n§î˜ž¾^€žLo§Þy½çú}/ýTýmú§õG X³ $Û Î<Å5qo</ÇÛñQC]Ã@C¥a•a—á„‘¹Ñ<£ÕFFŒiÆ\ã$ãmÆmÆ£&&!&KMêMîšRM¹¦)¦;L;LÇÍÌÍ¢ÍÖ™5›=1×2ç›ç›×›ß·`ZxZ,¶¨¶¸eI²äZ¦Yî¶¼n…Z9Y¥XUZ]³F­­%Ö»­»§§¹N“N«žÖgðñ¶É¶©·°åØÛ®¶m¶}agbg·Å®Ã“}º}ý= ‡Ù«Z~s´r:V:ޚΜî?}Åô–é/gXÏÏØ3ã¶Ë)ÄiS›ÓGgg¹sƒóˆ‹‰K‚Ë.—>.›ÆÝȽäJtõq]ázÒõ›³›Âí¨Û¯î6îiî‡ÜŸÌ4Ÿ)žY3sÐÃÈCàQåÑ? Ÿ•0k߬~OCOgµç#/c/‘W­×°·¥wª÷aï>ö>rŸã>ã<7Þ2ÞY_Ì7À·È·ËOÃož_…ßC#ÿdÿzÿѧ€%g‰A[ûøz|!¿Ž?:Ûeö²ÙíAŒ ¹AA‚­‚åÁ­!hÈì­!÷ç˜Î‘Îi…P~èÖÐaæa‹Ã~ '…‡…W†?ŽpˆXÑ1—5wÑÜCsßDúD–DÞ›g1O9¯-J5*>ª.j<Ú7º4º?Æ.fYÌÕXXIlK9.*®6nl¾ßüíó‡ââ ã{˜/È]py¡ÎÂô…§©.,:–@LˆN8”ðA*¨Œ%òw%Ž yÂÂg"/Ñ6шØC\*NòH*Mz’쑼5y$Å3¥,幄'©¼L LÝ›:žšv m2=:½1ƒ’‘qBª!M“¶gêgæfvˬe…²þÅn‹·/•Ék³¬Y- ¶B¦èTZ(×*²geWf¿Í‰Ê9–«ž+Íí̳ÊÛ7œïŸÿíÂá’¶¥†KW-X潬j9²‰Š®Û—Ø(Üxå‡oÊ¿™Ü”´©«Ä¹dÏfÒféæÞ-ž[–ª—æ—n ÙÚ´ ßV´íõöEÛ/—Í(Û»ƒ¶C¹£¿<¸¼e§ÉÎÍ;?T¤TôTúT6îÒݵa×ønÑî{¼ö4ìÕÛ[¼÷ý>ɾÛUUMÕfÕeûIû³÷?®‰ªéø–ûm]­NmqíÇÒý#¶×¹ÔÕÒ=TRÖ+ëGǾþïw- 6 UœÆâ#pDyäé÷ ß÷ :ÚvŒ{¬áÓvg/jBšòšF›Sšû[b[ºOÌ>ÑÖêÞzüGÛœ499â?rýéü§CÏdÏ&žþ¢þË®/~øÕë×Îјѡ—ò—“¿m|¥ýêÀë¯ÛÆÂƾÉx31^ôVûíÁwÜwï£ßOä| (ÿhù±õSЧû“““ÿ˜óüc3-ÛbKGDÿÿÿ ½§“ pHYs  šœtIMEÚ 6 B©\<ÞIDAT8Ë…’Kh]e…¿½ÿs1mAÛÄÚ`j‚Ïh[-ˆE(FEŠÁaAœ! bI« àÈ*–BX‘"Ø4)NŠõUR‚Zˆ¹­!’×Mhj“›ssÎùÿíà–¨àãmØ‹Å^‹-\ggßÏ ÷ßì]o|ÑÑÒ¬[3±¶4§Á§6»”û©òèø¯×>zd‘¿ ]½#Œ»î8ÙþüáÇOݺ±t{5·uIÍXN!I=@Vf¾®Ÿ=v×ÀÞþ1ûº}e>;ØÉö×fvìénøvËÍÅxaÉHrÏʪJ’¦Fȹ`œÈðDò¹WZ®]ÀžSíýŸø%S)ÌWAÌœb¹ |0K=âSo7D†~\~qâÍ-ïÀËŸ\ùaóMÅ“Z,S'*æô™‘È} óF`—†ÎNnzæ674¸öËUÈ 0) { var start = document.cookie.indexOf('sortBy='); if (start != -1) { start = start + 7; var end = document.cookie.indexOf(";", start); if (end == -1) { end = document.cookie.length; by = unescape(document.cookie.substring(start, end)); } } } setComparator(); } /** * Show a comment div. */ function show(id) { $('#ao' + id).hide(); $('#ah' + id).show(); var context = $.extend({id: id}, opts); var popup = $(renderTemplate(popupTemplate, context)).hide(); popup.find('textarea[name="proposal"]').hide(); popup.find('a.by' + by).addClass('sel'); var form = popup.find('#cf' + id); form.submit(function(event) { event.preventDefault(); addComment(form); }); $('#s' + id).after(popup); popup.slideDown('fast', function() { getComments(id); }); } /** * Hide a comment div. */ function hide(id) { $('#ah' + id).hide(); $('#ao' + id).show(); var div = $('#sc' + id); div.slideUp('fast', function() { div.remove(); }); } /** * Perform an ajax request to get comments for a node * and insert the comments into the comments tree. */ function getComments(id) { $.ajax({ type: 'GET', url: opts.getCommentsURL, data: {node: id}, success: function(data, textStatus, request) { var ul = $('#cl' + id); var speed = 100; $('#cf' + id) .find('textarea[name="proposal"]') .data('source', data.source); if (data.comments.length === 0) { ul.html('
  • No comments yet.
  • '); ul.data('empty', true); } else { // If there are comments, sort them and put them in the list. var comments = sortComments(data.comments); speed = data.comments.length * 100; appendComments(comments, ul); ul.data('empty', false); } $('#cn' + id).slideUp(speed + 200); ul.slideDown(speed); }, error: function(request, textStatus, error) { showError('Oops, there was a problem retrieving the comments.'); }, dataType: 'json' }); } /** * Add a comment via ajax and insert the comment into the comment tree. */ function addComment(form) { var node_id = form.find('input[name="node"]').val(); var parent_id = form.find('input[name="parent"]').val(); var text = form.find('textarea[name="comment"]').val(); var proposal = form.find('textarea[name="proposal"]').val(); if (text == '') { showError('Please enter a comment.'); return; } // Disable the form that is being submitted. form.find('textarea,input').attr('disabled', 'disabled'); // Send the comment to the server. $.ajax({ type: "POST", url: opts.addCommentURL, dataType: 'json', data: { node: node_id, parent: parent_id, text: text, proposal: proposal }, success: function(data, textStatus, error) { // Reset the form. if (node_id) { hideProposeChange(node_id); } form.find('textarea') .val('') .add(form.find('input')) .removeAttr('disabled'); var ul = $('#cl' + (node_id || parent_id)); if (ul.data('empty')) { $(ul).empty(); ul.data('empty', false); } insertComment(data.comment); var ao = $('#ao' + node_id); ao.find('img').attr({'src': opts.commentBrightImage}); if (node_id) { // if this was a "root" comment, remove the commenting box // (the user can get it back by reopening the comment popup) $('#ca' + node_id).slideUp(); } }, error: function(request, textStatus, error) { form.find('textarea,input').removeAttr('disabled'); showError('Oops, there was a problem adding the comment.'); } }); } /** * Recursively append comments to the main comment list and children * lists, creating the comment tree. */ function appendComments(comments, ul) { $.each(comments, function() { var div = createCommentDiv(this); ul.append($(document.createElement('li')).html(div)); appendComments(this.children, div.find('ul.comment-children')); // To avoid stagnating data, don't store the comments children in data. this.children = null; div.data('comment', this); }); } /** * After adding a new comment, it must be inserted in the correct * location in the comment tree. */ function insertComment(comment) { var div = createCommentDiv(comment); // To avoid stagnating data, don't store the comments children in data. comment.children = null; div.data('comment', comment); var ul = $('#cl' + (comment.node || comment.parent)); var siblings = getChildren(ul); var li = $(document.createElement('li')); li.hide(); // Determine where in the parents children list to insert this comment. for(i=0; i < siblings.length; i++) { if (comp(comment, siblings[i]) <= 0) { $('#cd' + siblings[i].id) .parent() .before(li.html(div)); li.slideDown('fast'); return; } } // If we get here, this comment rates lower than all the others, // or it is the only comment in the list. ul.append(li.html(div)); li.slideDown('fast'); } function acceptComment(id) { $.ajax({ type: 'POST', url: opts.acceptCommentURL, data: {id: id}, success: function(data, textStatus, request) { $('#cm' + id).fadeOut('fast'); $('#cd' + id).removeClass('moderate'); }, error: function(request, textStatus, error) { showError('Oops, there was a problem accepting the comment.'); } }); } function deleteComment(id) { $.ajax({ type: 'POST', url: opts.deleteCommentURL, data: {id: id}, success: function(data, textStatus, request) { var div = $('#cd' + id); if (data == 'delete') { // Moderator mode: remove the comment and all children immediately div.slideUp('fast', function() { div.remove(); }); return; } // User mode: only mark the comment as deleted div .find('span.user-id:first') .text('[deleted]').end() .find('div.comment-text:first') .text('[deleted]').end() .find('#cm' + id + ', #dc' + id + ', #ac' + id + ', #rc' + id + ', #sp' + id + ', #hp' + id + ', #cr' + id + ', #rl' + id) .remove(); var comment = div.data('comment'); comment.username = '[deleted]'; comment.text = '[deleted]'; div.data('comment', comment); }, error: function(request, textStatus, error) { showError('Oops, there was a problem deleting the comment.'); } }); } function showProposal(id) { $('#sp' + id).hide(); $('#hp' + id).show(); $('#pr' + id).slideDown('fast'); } function hideProposal(id) { $('#hp' + id).hide(); $('#sp' + id).show(); $('#pr' + id).slideUp('fast'); } function showProposeChange(id) { $('#pc' + id).hide(); $('#hc' + id).show(); var textarea = $('#pt' + id); textarea.val(textarea.data('source')); $.fn.autogrow.resize(textarea[0]); textarea.slideDown('fast'); } function hideProposeChange(id) { $('#hc' + id).hide(); $('#pc' + id).show(); var textarea = $('#pt' + id); textarea.val('').removeAttr('disabled'); textarea.slideUp('fast'); } function toggleCommentMarkupBox(id) { $('#mb' + id).toggle(); } /** Handle when the user clicks on a sort by link. */ function handleReSort(link) { var classes = link.attr('class').split(/\s+/); for (var i=0; iThank you! Your comment will show up ' + 'once it is has been approved by a moderator.'); } // Prettify the comment rating. comment.pretty_rating = comment.rating + ' point' + (comment.rating == 1 ? '' : 's'); // Make a class (for displaying not yet moderated comments differently) comment.css_class = comment.displayed ? '' : ' moderate'; // Create a div for this comment. var context = $.extend({}, opts, comment); var div = $(renderTemplate(commentTemplate, context)); // If the user has voted on this comment, highlight the correct arrow. if (comment.vote) { var direction = (comment.vote == 1) ? 'u' : 'd'; div.find('#' + direction + 'v' + comment.id).hide(); div.find('#' + direction + 'u' + comment.id).show(); } if (opts.moderator || comment.text != '[deleted]') { div.find('a.reply').show(); if (comment.proposal_diff) div.find('#sp' + comment.id).show(); if (opts.moderator && !comment.displayed) div.find('#cm' + comment.id).show(); if (opts.moderator || (opts.username == comment.username)) div.find('#dc' + comment.id).show(); } return div; } /** * A simple template renderer. Placeholders such as <%id%> are replaced * by context['id'] with items being escaped. Placeholders such as <#id#> * are not escaped. */ function renderTemplate(template, context) { var esc = $(document.createElement('div')); function handle(ph, escape) { var cur = context; $.each(ph.split('.'), function() { cur = cur[this]; }); return escape ? esc.text(cur || "").html() : cur; } return template.replace(/<([%#])([\w\.]*)\1>/g, function() { return handle(arguments[2], arguments[1] == '%' ? true : false); }); } /** Flash an error message briefly. */ function showError(message) { $(document.createElement('div')).attr({'class': 'popup-error'}) .append($(document.createElement('div')) .attr({'class': 'error-message'}).text(message)) .appendTo('body') .fadeIn("slow") .delay(2000) .fadeOut("slow"); } /** Add a link the user uses to open the comments popup. */ $.fn.comment = function() { return this.each(function() { var id = $(this).attr('id').substring(1); var count = COMMENT_METADATA[id]; var title = count + ' comment' + (count == 1 ? '' : 's'); var image = count > 0 ? opts.commentBrightImage : opts.commentImage; var addcls = count == 0 ? ' nocomment' : ''; $(this) .append( $(document.createElement('a')).attr({ href: '#', 'class': 'sphinx-comment-open' + addcls, id: 'ao' + id }) .append($(document.createElement('img')).attr({ src: image, alt: 'comment', title: title })) .click(function(event) { event.preventDefault(); show($(this).attr('id').substring(2)); }) ) .append( $(document.createElement('a')).attr({ href: '#', 'class': 'sphinx-comment-close hidden', id: 'ah' + id }) .append($(document.createElement('img')).attr({ src: opts.closeCommentImage, alt: 'close', title: 'close' })) .click(function(event) { event.preventDefault(); hide($(this).attr('id').substring(2)); }) ); }); }; var opts = { processVoteURL: '/_process_vote', addCommentURL: '/_add_comment', getCommentsURL: '/_get_comments', acceptCommentURL: '/_accept_comment', deleteCommentURL: '/_delete_comment', commentImage: '/static/_static/comment.png', closeCommentImage: '/static/_static/comment-close.png', loadingImage: '/static/_static/ajax-loader.gif', commentBrightImage: '/static/_static/comment-bright.png', upArrow: '/static/_static/up.png', downArrow: '/static/_static/down.png', upArrowPressed: '/static/_static/up-pressed.png', downArrowPressed: '/static/_static/down-pressed.png', voting: false, moderator: false }; if (typeof COMMENT_OPTIONS != "undefined") { opts = jQuery.extend(opts, COMMENT_OPTIONS); } var popupTemplate = '\
    \

    \ Sort by:\ best rated\ newest\ oldest\

    \
    Comments
    \
    \ loading comments...
    \
      \
      \

      Add a comment\ (markup):

      \
      \ reStructured text markup: *emph*, **strong**, \ ``code``, \ code blocks: :: and an indented block after blank line
      \
      \ \

      \ \ Propose a change ▹\ \ \ Propose a change ▿\ \

      \ \ \ \ \
      \
      \
      '; var commentTemplate = '\
      \
      \
      \ \ \ \ \ \ \
      \
      \ \ \ \ \ \ \
      \
      \
      \

      \ <%username%>\ <%pretty_rating%>\ <%time.delta%>\

      \
      <#text#>
      \

      \ \ reply ▿\ proposal ▹\ proposal ▿\ \ \

      \
      \
      <#proposal_diff#>\
              
      \
        \
        \
        \
        \ '; var replyTemplate = '\
      • \
        \
        \ \ \ \ \ \
        \
        \
      • '; $(document).ready(function() { init(); }); })(jQuery); $(document).ready(function() { // add comment anchors for all paragraphs that are commentable $('.sphinx-has-comment').comment(); // highlight search words in search results $("div.context").each(function() { var params = $.getQueryParameters(); var terms = (params.q) ? params.q[0].split(/\s+/) : []; var result = $(this); $.each(terms, function() { result.highlightText(this.toLowerCase(), 'highlighted'); }); }); // directly open comment window if requested var anchor = document.location.hash; if (anchor.substring(0, 9) == '#comment-') { $('#ao' + anchor.substring(9)).click(); document.location.hash = '#s' + anchor.substring(9); } }); pam-python-1.0.2/doc/html/_static/file.png0000644000215700017510000000061011644410761017300 0ustar rstuartit‰PNG  IHDRóÿabKGDÿÿÿ ½§“ pHYs  šœtIMEÕ  )¶TIDAT8Ë­‘±JÄ@†¿Ir('[ "&xØÙYZ ‚Xø0‚!i|†_@±Ô÷•t§ÓDÄæÏ] ¹#¹Äxÿjv˜ùç› Y–ÐN‡ažE‘i«(ŠÌÄÉ™yž£µ@D¦£&±ˆ`Û6®ë–P¦Zk’$)5%"ôz½Ê.NñA#Aœba‘`Vsø¾_3ñc°,«™àä2m¼Ýñþjó [kŸìlv¹y|!IÕ´ðþyô;ÀðvÈé "Œß®°—a©?ŸAúðÄ7Œ`ô˜ñÇc^énôk?¸²Bg}»TЙ¹D#ÁÑÞ "R¹D1÷£çyüEŽRê*ŽãÝ6MJ©3þK_U«t8F~ÇIEND®B`‚pam-python-1.0.2/doc/html/_static/down.png0000644000215700017510000000055311644410761017336 0ustar rstuartit‰PNG  IHDRóÿasRGB®ÎébKGDùC» pHYs × ×B(›xtIMEÚ"ÅíU{ëIDAT8ËÍÒ¡NCAÐóÚJ, ++@ ™4>‡¨â/ÐUü’¤^,†~T&Ô3M^^^ÛPÅM6ÙÙ¹sïÌî*¥ôí‰RJ¿‡a)e¼GñÃ*ƒœàñ¹¡èW¸Å<"®«Fò ‡øFgÜã78G…>q ƒ†ÁOI¨p‘«‰:s“õAÕjñ5GÙ†yDœ®ƒ^+y†U:ép_%G§@D|ašÕ­O“£s„Æ(ïy¡M,"â¨Íím˜sÔx:÷£.b§@D|`–V˜åÙŸÛ²”²ÜÆìиÜe²KàÅ¿Ç/êG!‚ ™IEND®B`‚pam-python-1.0.2/doc/html/_static/searchtools.js0000644000215700017510000003725311741446577020570 0ustar rstuartit/* * searchtools.js_t * ~~~~~~~~~~~~~~~~ * * Sphinx JavaScript utilties for the full-text search. * * :copyright: Copyright 2007-2011 by the Sphinx team, see AUTHORS. * :license: BSD, see LICENSE for details. * */ /** * helper function to return a node containing the * search summary for a given text. keywords is a list * of stemmed words, hlwords is the list of normal, unstemmed * words. the first one is used to find the occurance, the * latter for highlighting it. */ jQuery.makeSearchSummary = function(text, keywords, hlwords) { var textLower = text.toLowerCase(); var start = 0; $.each(keywords, function() { var i = textLower.indexOf(this.toLowerCase()); if (i > -1) start = i; }); start = Math.max(start - 120, 0); var excerpt = ((start > 0) ? '...' : '') + $.trim(text.substr(start, 240)) + ((start + 240 - text.length) ? '...' : ''); var rv = $('
        ').text(excerpt); $.each(hlwords, function() { rv = rv.highlightText(this, 'highlighted'); }); return rv; } /** * Porter Stemmer */ var Stemmer = function() { var step2list = { ational: 'ate', tional: 'tion', enci: 'ence', anci: 'ance', izer: 'ize', bli: 'ble', alli: 'al', entli: 'ent', eli: 'e', ousli: 'ous', ization: 'ize', ation: 'ate', ator: 'ate', alism: 'al', iveness: 'ive', fulness: 'ful', ousness: 'ous', aliti: 'al', iviti: 'ive', biliti: 'ble', logi: 'log' }; var step3list = { icate: 'ic', ative: '', alize: 'al', iciti: 'ic', ical: 'ic', ful: '', ness: '' }; var c = "[^aeiou]"; // consonant var v = "[aeiouy]"; // vowel var C = c + "[^aeiouy]*"; // consonant sequence var V = v + "[aeiou]*"; // vowel sequence var mgr0 = "^(" + C + ")?" + V + C; // [C]VC... is m>0 var meq1 = "^(" + C + ")?" + V + C + "(" + V + ")?$"; // [C]VC[V] is m=1 var mgr1 = "^(" + C + ")?" + V + C + V + C; // [C]VCVC... is m>1 var s_v = "^(" + C + ")?" + v; // vowel in stem this.stemWord = function (w) { var stem; var suffix; var firstch; var origword = w; if (w.length < 3) return w; var re; var re2; var re3; var re4; firstch = w.substr(0,1); if (firstch == "y") w = firstch.toUpperCase() + w.substr(1); // Step 1a re = /^(.+?)(ss|i)es$/; re2 = /^(.+?)([^s])s$/; if (re.test(w)) w = w.replace(re,"$1$2"); else if (re2.test(w)) w = w.replace(re2,"$1$2"); // Step 1b re = /^(.+?)eed$/; re2 = /^(.+?)(ed|ing)$/; if (re.test(w)) { var fp = re.exec(w); re = new RegExp(mgr0); if (re.test(fp[1])) { re = /.$/; w = w.replace(re,""); } } else if (re2.test(w)) { var fp = re2.exec(w); stem = fp[1]; re2 = new RegExp(s_v); if (re2.test(stem)) { w = stem; re2 = /(at|bl|iz)$/; re3 = new RegExp("([^aeiouylsz])\\1$"); re4 = new RegExp("^" + C + v + "[^aeiouwxy]$"); if (re2.test(w)) w = w + "e"; else if (re3.test(w)) { re = /.$/; w = w.replace(re,""); } else if (re4.test(w)) w = w + "e"; } } // Step 1c re = /^(.+?)y$/; if (re.test(w)) { var fp = re.exec(w); stem = fp[1]; re = new RegExp(s_v); if (re.test(stem)) w = stem + "i"; } // Step 2 re = /^(.+?)(ational|tional|enci|anci|izer|bli|alli|entli|eli|ousli|ization|ation|ator|alism|iveness|fulness|ousness|aliti|iviti|biliti|logi)$/; if (re.test(w)) { var fp = re.exec(w); stem = fp[1]; suffix = fp[2]; re = new RegExp(mgr0); if (re.test(stem)) w = stem + step2list[suffix]; } // Step 3 re = /^(.+?)(icate|ative|alize|iciti|ical|ful|ness)$/; if (re.test(w)) { var fp = re.exec(w); stem = fp[1]; suffix = fp[2]; re = new RegExp(mgr0); if (re.test(stem)) w = stem + step3list[suffix]; } // Step 4 re = /^(.+?)(al|ance|ence|er|ic|able|ible|ant|ement|ment|ent|ou|ism|ate|iti|ous|ive|ize)$/; re2 = /^(.+?)(s|t)(ion)$/; if (re.test(w)) { var fp = re.exec(w); stem = fp[1]; re = new RegExp(mgr1); if (re.test(stem)) w = stem; } else if (re2.test(w)) { var fp = re2.exec(w); stem = fp[1] + fp[2]; re2 = new RegExp(mgr1); if (re2.test(stem)) w = stem; } // Step 5 re = /^(.+?)e$/; if (re.test(w)) { var fp = re.exec(w); stem = fp[1]; re = new RegExp(mgr1); re2 = new RegExp(meq1); re3 = new RegExp("^" + C + v + "[^aeiouwxy]$"); if (re.test(stem) || (re2.test(stem) && !(re3.test(stem)))) w = stem; } re = /ll$/; re2 = new RegExp(mgr1); if (re.test(w) && re2.test(w)) { re = /.$/; w = w.replace(re,""); } // and turn initial Y back to y if (firstch == "y") w = firstch.toLowerCase() + w.substr(1); return w; } } /** * Search Module */ var Search = { _index : null, _queued_query : null, _pulse_status : -1, init : function() { var params = $.getQueryParameters(); if (params.q) { var query = params.q[0]; $('input[name="q"]')[0].value = query; this.performSearch(query); } }, loadIndex : function(url) { $.ajax({type: "GET", url: url, data: null, success: null, dataType: "script", cache: true}); }, setIndex : function(index) { var q; this._index = index; if ((q = this._queued_query) !== null) { this._queued_query = null; Search.query(q); } }, hasIndex : function() { return this._index !== null; }, deferQuery : function(query) { this._queued_query = query; }, stopPulse : function() { this._pulse_status = 0; }, startPulse : function() { if (this._pulse_status >= 0) return; function pulse() { Search._pulse_status = (Search._pulse_status + 1) % 4; var dotString = ''; for (var i = 0; i < Search._pulse_status; i++) dotString += '.'; Search.dots.text(dotString); if (Search._pulse_status > -1) window.setTimeout(pulse, 500); }; pulse(); }, /** * perform a search for something */ performSearch : function(query) { // create the required interface elements this.out = $('#search-results'); this.title = $('

        ' + _('Searching') + '

        ').appendTo(this.out); this.dots = $('').appendTo(this.title); this.status = $('

        ').appendTo(this.out); this.output = $('