2015-04-26 4 views
2

Я пытаюсь написать демо-модуль PAM на C, который использует Embedding Python в концепции C для запуска скрипта, написанного на языке python (2.7) , внутри функции pam_sm_authenticate(), которая написана в файле C (pam_auth.c).ImportError и PyExc_SystemError при встраивании скрипта Python в C для модулей PAM (файлы .so)

Это питон скрипт: 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/безопасности/

Я изменил конфигурацию 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 

линия "требуется авторизация pam_auth.so" заставляет система для использования моего модуля для аутентификации каждый раз, когда я использую команду «sudo». (Для экс- Sudo наутилуса)

Теперь проблема: Эта строка в C файл "pModule = PyImport_Import (PNAME);" выдает ошибку импорта, который напечатан на PyErr_Print() следующим образом:

[email protected]:~$ 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?

Сценарий питон работает как шарм, если я бегу следующим образом:

#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; 
} 

Если он работает под общим питона вложения примеров, почему он не работает в РАМ на основе внедрения примеров (где используются .so файлы)?

PS: Я импортирую numpy по определенной причине. Не спрашивайте, почему я нигде не использовал сценарий python, поскольку это всего лишь демонстрационный сценарий того, что я пытаюсь достичь. Более того, импортная математика не дает никакой ошибки импорта. Я также получаю ошибку импорта для SciPY.

PPS: Пакеты Numpy и Scipy отлично работают в сценариях python и устанавливаются под /usr/lib/python2.7/dist-packages/. Я использую ubuntu 14.04.

Пожалуйста, помогите !!!!

ответ

4

Я не знаю ответа на ваш вопрос, но мне интересно, почему это не провалилось раньше. Хост-приложение не знает, что ваш модуль PAM потребуется с помощью libpython2.7.so.1, поэтому каким-то образом это должно быть загружено динамически, иначе вызов Py_Initialize() завершится с той же ошибкой.

Поскольку вы говорите, что это не подведет, оно должно быть загружено. Однако из полученной ошибки мы можем выводить содержащиеся в ней символы (например, PyExc_SystemError), не отображаются в динамических библиотеках, впоследствии загруженных.Это значение по умолчанию, когда библиотеки загружаются с использованием dlopen() (см. RTLD_LOCAL в человек 3 dlopen). Чтобы отменить его, вы должны пройти RTLD_GLOBAL до dlopen(). Возможно, это твоя проблема.

Другие комментарии о коде:

  • Вызывающие Py_Initialise() для каждого pm_sm _...() вызов будет дорогим и, возможно, удивительно питон модулей. Это означает, что все данные, которые модуль python, накопленный в течение одного вызова (например, голос или имя пользователя), будут отброшены при следующем вызове. Вам лучше загружать libpython2.7.so.1 и инициализировать PAM один раз, а затем использовать функцию очистки pam_set_data(), чтобы выгрузить его, когда вы закончите.

  • В связи с этим вопрос, ваш модуль PAM не может использоваться из программ Python, потому что вы всегда вызывать Py_Initialise() (и я полагаю, совпадающую вызов Py_Finalize()).

  • Если программа не упал над местом, где это произошло, он упал бы более на линии Е («Результат% s \ п», PyString_AsString (pResult)) потому pResult не инициализирован.

  • Как я думаю, вы знаете, что все шаблоны, которые у вас есть, чтобы вы могли нажимать модули PAM на Python, предоставлены pam-python - не требуется C. Поскольку вы, очевидно, пишете свой PAM-модуль на Python, вы уже сталкиваетесь с накладными расходами, которые он несет, но упускают из функций, которые он предоставляет, например, при регистрации неперехваченных исключений Python. И самое главное, использование этого означает, что вы можете полностью избежать C. Ваш модуль PAM будет загружен в программы, которые защищают безопасность машины - такие программы, как login, sudo и xdm/gdm3. Избегание C-средств также позволяет избежать легионов ошибок безопасности, которые могут иметь программы C, которые невозможны в Python - переполнение буфера, неинициализированные указатели и доступ к свободной памяти. Поскольку у вас есть одна из этих ошибок в вашем коде C, который вы разместили здесь, избегая этого, это звучит неплохо.

+1

Спасибо за подробный подход. Я добавил заголовок #include и dlopen ("libpython2.7.so.1", RTLD_LAZY | RTLD_GLOBAL); перед Py_Initialize(), и это сработало! Я согласен с вами относительно pam-python. Однако я не могу явно «импортировать» файлы python в PAM-скрипте, написанном на python. Например: Внутри примера pam_permit.py, я не могу написать в явной форме - «тест импорта», чтобы импортировать test.py (путь /usr/lib/Python2.7)like это: тест импорта Защиту pam_sm_authenticate (pamh, flags, argv): /* обязательные строки в соответствии с примерами pam-python */ return pamh.PAM_SUCCESS Любые предложения? – StitchesGuy90

+0

«импорт» работает в pam-python - см. Пример pam_nologin.py. Вы не говорите, какое сообщение об ошибке «import test» дает, но я полагаю, что он не может его найти. Попробуйте: «import sys; sys.path.append (« direct/test.py/ives/in »)« –

+0

Я попробую, как вы сказали выше. Я сообщу вам об этом в случае каких-либо ошибок. Благодаря! – StitchesGuy90