ImportError и PyExc_SystemError при встраивании Python Script в C для модулей PAM (файлы.so)
Я пытаюсь написать демонстрационный модуль PAM на C, который использует концепцию Embedded Python in C для запуска скрипта, написанного на python (2.7), внутри функции pam_sm_authenticate(), которая написана в файле C (pam_auth.c).
Это скрипт Python: test.py
import math
import numpy
def test_func():
a = "test"
return a
Путь к test.py - /usr/lib/Python2.7/, поэтому я легко могу его импортировать.
Это файл C:
#define PAM_SM_AUTH
#define PAM_SM_ACCOUNT
#define PAM_SM_SESSION
#include <security/pam_modules.h>
#include <security/_pam_macros.h>
#include <security/pam_appl.h>
#include<python2.7/Python.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define NOBODY "nobody"
/*PAM Stuffs*/
PAM_EXTERN int pam_sm_authenticate(
pam_handle_t* pamh, int flags, int argc, const char** argv)
{
const char *user;
int retval;
user = NULL;
retval = pam_get_user(pamh, &user, NULL);
if(retval != PAM_SUCCESS)
{
fprintf(stderr, "%s", pam_strerror(pamh, retval));
// return (retval);
}
fprintf(stdout, "retval= %d user=%s\n", retval,user);
if (user == NULL || *user =='\0')
pam_set_item(pamh, PAM_USER, (const char*)NOBODY);
/* Python Wrapper */
// Set PYTHONPATH TO working directory
//int res = setenv("PYTHONPATH",".",1);
//fprintf(stdout, "%d", res);
PyObject *pName, *pModule, *pDict, *pFunc, *pValue, *pResult;
// Initialize the Python Interpreter
Py_Initialize();
// Build the name object
pName = PyString_FromString((char*)"test");
// Load the module object
pModule = PyImport_Import(pName);
// pDict is a borrowed reference
PyErr_Print();
pDict = PyModule_GetDict(pModule);
// pFunc is also a borrowed reference
pFunc = PyDict_GetItemString(pDict, (char*)"test_func");
if (PyCallable_Check(pFunc))
{
pValue=NULL;
PyErr_Print();
pResult=PyObject_CallObject(pFunc,pValue);
PyErr_Print();
}else
{
PyErr_Print();
}
printf("Result is %s\n",PyString_AsString(pResult));
// Clean up
Py_DECREF(pModule);
Py_DECREF(pName);/* */
// Finish the Python Interpreter
Py_Finalize();
return PAM_SUCCESS;
}
PAM_EXTERN int pam_sm_setcred(
pam_handle_t* pamh, int flags, int argc, const char** argv)
{
return PAM_SUCCESS;
}
PAM_EXTERN int pam_sm_acct_mgmt(
pam_handle_t* pamh, int flags, int argc, const char** argv)
{
return PAM_SUCCESS;
}
PAM_EXTERN int pam_sm_open_session(
pam_handle_t* pamh, int flags, int argc, const char** argv)
{
return PAM_SUCCESS;
}
PAM_EXTERN int pam_sm_close_session(
pam_handle_t* pamh, int flags, int argc, const char** argv)
{
return PAM_SUCCESS;
}
PAM_EXTERN int pam_sm_chauthtok(
pam_handle_t* pamh, int flags, int argc, const char** argv)
{
return PAM_SUCCESS;
}
C-файл является просто модификацией pam_permit.c. Файл C компилируется с использованием gcc ( gcc -shared -o pam_auth.so -fPIC pam_auth.c -I/usr/include/python2.7 -lpython2.7) для получения файла.so (pam_auth.so) и помещается внутри папки /lib/security/
Я изменил конфигурацию PAM файла 'sudo' в /etc/pam.d следующим образом:
#%PAM-1.0
auth required pam_env.so readenv=1 user_readenv=0
auth required pam_env.so readenv=1 envfile=/etc/default/locale user_readenv=0
#@include common-auth #this line is commented to make it use my pam module
auth required pam_auth.so
@include common-account
@include common-session-noninteractive
Строка "auth required pam_auth.so" заставляет систему использовать мой модуль для аутентификации каждый раз, когда я использую команду "sudo". (для ex- sudo nautilus)
Теперь проблема в следующем: эта строка в C-файле " pModule = PyImport_Import(pName); " выдает ошибку импорта, которая выводится PyErr_Print() следующим образом:
stitches@Andromida:~$ sudo nautilus
retval= 0 user=stitches
Traceback (most recent call last):
File "/usr/lib/python2.7/subho_auth.py", line 8, in <module>
import numpy
File "/usr/lib/python2.7/dist-packages/numpy/__init__.py", line 153, in <module>
from . import add_newdocs
File "/usr/lib/python2.7/dist-packages/numpy/add_newdocs.py", line 13, in <module>
from numpy.lib import add_newdoc
File "/usr/lib/python2.7/dist-packages/numpy/lib/__init__.py", line 8, in <module>
from .type_check import *
File "/usr/lib/python2.7/dist-packages/numpy/lib/type_check.py", line 11, in <module>
import numpy.core.numeric as _nx
File "/usr/lib/python2.7/dist-packages/numpy/core/__init__.py", line 6, in <module>
from . import multiarray
ImportError: /usr/lib/python2.7/dist-packages/numpy/core/multiarray.so: undefined symbol: PyExc_SystemError
Segmentation fault (core dumped)
Насколько я понимаю, он не может импортировать библиотеку numpy, как указано в файле test.py. Как решить эту проблему ImportError & PyExc_SystemError?
Скрипт Python работает как шарм, если я запускаю следующим образом:
#include <Python.h>
#include <stdlib.h>
#include <string.h>
int main()
{
// Set PYTHONPATH TO working directory
//int res = setenv("PYTHONPATH",".",1);
//fprintf(stdout, "%d", res);
PyObject *pName, *pModule, *pDict, *pFunc, *pValue, *pResult;
// Initialize the Python Interpreter
Py_Initialize();
// Build the name object
pName = PyString_FromString((char*)"test");
// Load the module object
pModule = PyImport_Import(pName);
// pDict is a borrowed reference
PyErr_Print();
pDict = PyModule_GetDict(pModule);
// pFunc is also a borrowed reference
pFunc = PyDict_GetItemString(pDict, (char*)"test_func");
if (PyCallable_Check(pFunc))
{
pValue=NULL;
PyErr_Print();
pResult=PyObject_CallObject(pFunc,pValue);
PyErr_Print();
}else
{
PyErr_Print();
}
printf("Result is %s\n",PyString_AsString(pResult));
// Clean up
Py_DECREF(pModule);
Py_DECREF(pName);/* */
// Finish the Python Interpreter
Py_Finalize();
return 0;
}
Если он работает в общих примерах встраивания python, почему он не работает в примерах встраивания на основе PAM (где используются файлы.so)?
PS: я импортирую NumPy по определенной причине. Не спрашивайте, почему я не использовал нигде в скрипте Python, поскольку это всего лишь демонстрационный скрипт того, чего я пытаюсь достичь. Кроме того, математика импорта не дает никакой ошибки импорта. Я получаю ошибку импорта для SciPY тоже.
PPS: пакеты Numpy и Scipy прекрасно работают в скриптах Python и устанавливаются в /usr/lib/python2.7/dist-packages/. Я использую Ubuntu 14.04.
Пожалуйста помоги!!!!
1 ответ
Я не знаю ответа на ваш вопрос, но мне интересно, почему он не потерпел неудачу раньше. Хост-приложение не знает, что ваш модуль PAM понадобится при использовании libpython2.7.so.1, так что каким-то образом он должен загружаться динамически, иначе вызов Py_Initialize() завершится с той же ошибкой.
Учитывая, что вы говорите, что там нет ошибок, он должен быть загружен. Однако из полученной ошибки мы можем вывести символы, которые она содержит (например, PyExc_SystemError), которые не видны динамически загружаемым библиотекам. Это значение по умолчанию, когда библиотеки загружаются с использованием dlopen () (см. RTLD_LOCAL в man 3 dlopen). Чтобы переопределить это, вы должны передать RTLD_GLOBAL в dlopen (). Может быть, это твоя проблема.
Другие комментарии о вашем коде:
Вызов Py_Initialise() для каждого вызова pm_sm_...() будет дорогостоящим и, возможно, неожиданным для модулей python. Это означает, что все данные, которые Python-модуль накопил за один вызов (например, голос или имя пользователя), будут отброшены при следующем вызове. Вам лучше загрузить libpython2.7.so.1 и инициализировать PAM один раз, а затем использовать функцию очистки pam_set_data(), чтобы выгрузить его, когда вы закончите.
В связанной с этим проблеме ваш модуль PAM не может использоваться из программ Python, потому что вы всегда вызываете Py_Initialise() (и я предполагаю, что соответствующий вызов Py_Finalize ()).
Если бы ваша программа не упала так, как она это сделала, она бы упала на строку printf("Result is %s\n",PyString_AsString(pResult)), потому что pResult не инициализирован.
Как я думаю, вы знаете, все шаблоны, которые у вас есть здесь, чтобы позволить вам использовать модули PAM в Python, предоставляются pam-python - C не требуется. Поскольку вы, очевидно, в любом случае пишете свой модуль PAM на Python, вы уже сталкиваетесь с накладными расходами, которые он несет, но упускаете возможности, которые он предоставляет, такие как регистрация необработанных исключений Python. И самое главное, его использование означает, что вы можете полностью избежать C. Ваш модуль PAM будет загружен в программы, обеспечивающие безопасность компьютера, такие как login, sudo и xdm / gdm3. Избегать C означает также избегать легионов ошибок безопасности, которые могут иметь C-программы, которые невозможны в Python - переполнение буфера, неинициализированные указатели и доступ к свободной памяти. Поскольку у вас есть одна из тех ошибок в вашем коде C, который вы разместили здесь, избегать его звучит как хорошая идея.