Sti*_*y90 3 c numpy pam python-embedding python-2.7
我正在尝试用C语言编写一个演示PAM模块,该模块使用在C概念中嵌入Python来运行以python(2.7)编写的脚本,该脚本位于pam_sm_authenticate()函数内部,该函数以C文件(pam_auth.c)编写。
这是python脚本:test.py
import math
import numpy
def test_func():
a = "test"
return a
Run Code Online (Sandbox Code Playgroud)
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;
}
Run Code Online (Sandbox Code Playgroud)
C文件只是pam_permit.c的修改。使用gcc(gcc -shared -o pam_auth.so -fPIC pam_auth.c -I / usr / include / python2.7 -lpython2.7)编译C文件以获得一个.so文件(pam_auth.so)并放入在/ lib / security /文件夹中
我在/etc/pam.d中更改了'sudo'文件的PAM配置,如下所示:
#%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
Run Code Online (Sandbox Code Playgroud)
每当我使用命令“ sudo”时,“ auth required pam_auth.so”行就会强制系统使用我的模块进行身份验证。(对于exsudo 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)
Run Code Online (Sandbox Code Playgroud)
据我了解,它无法导入test.py文件中指定的numpy库。如何解决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;
}
Run Code Online (Sandbox Code Playgroud)
如果它可以在一般的python嵌入示例下工作,为什么它不能在基于PAM的嵌入示例(使用.so文件的地方)下工作?
PS:我出于特定原因导入numpy。不要问为什么我没有在python脚本中的任何地方使用过,因为这只是我要实现的演示脚本。此外,导入数学不会给出任何导入错误。我也收到SciPY的导入错误。
PPS:Numpy和Scipy软件包可在python脚本中完美运行,并安装在/usr/lib/python2.7/dist-packages/下。我正在使用Ubuntu 14.04。
请帮忙!!!!
我不知道您问题的答案,但我想知道为什么它没有更早失败。主机应用程序不知道使用libpython2.7.so.1需要使用您的PAM模块,因此必须以某种方式动态加载它,否则Py_Initialize()调用将因相同的错误而失败。
假设您说它不会失败,那么必须将其加载。但是,从您得到的错误中我们可以推断出它所包含的符号(例如PyExc_SystemError)对于随后加载的动态库不可见。这是默认的库时使用装载的dlopen() (见RTLD_LOCAL在男子3 dlopen的)。要覆盖它,必须将RTLD_GLOBAL传递给dlopen()。也许那是你的问题。
有关您的代码的其他注释:
对于每个pm_sm _...()调用,都调用Py_Initialise()将会很昂贵,并且可能会使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没有初始化。
我想您知道,这里所有让您用Python拧接PAM模块的样板都由pam-python提供-不需要C。由于您显然还是用Python编写了PAM模块,因此您已经承担了它带来的开销,但是却错过了它提供的功能(如记录未捕获的Python异常)。最重要的是,使用它意味着您可以完全避免使用C。您的PAM模块将被加载到保护机器安全的程序中,例如login,sudo和xdm / gdm3。避免使用C意味着也避免了C程序可能在Python中无法实现的大量安全漏洞-缓冲区溢出,未初始化的指针和访问释放的内存。由于您在此处发布的C代码中存在这些错误之一,因此避免它听起来是个好主意。