问题描述
我想用C编写的演示PAM模块,它采用Python嵌入在C概念来运行Python编写的(2.7)的脚本,里面的pam_sm_authenticate()函数,这是写在C文件(pam_auth.c )。
I'm trying to write a demo PAM module in C, which uses Embedding Python in C concept to run a script written in python (2.7), inside pam_sm_authenticate() function, which is written in C file (pam_auth.c).
这是Python脚本:test.py
This is the python script: test.py
import math
import numpy
def test_func():
a = "test"
return a
有关test.py的路径/usr/lib/Python2.7/这样我就可以轻松地将其导入。
The path for test.py is /usr/lib/Python2.7/ so that I can easily import it.
这是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目录内/安全/
The C-file is just a modification of pam_permit.c. The C file is compiled using gcc ( gcc -shared -o pam_auth.so -fPIC pam_auth.c -I/usr/include/python2.7 -lpython2.7 ) to obtain an .so file (pam_auth.so) and is put inside the folder /lib/security/
我改变了'须藤'文件中的PAM配置/etc/pam.d中如下:
I changed the PAM configuration of 'sudo' file in /etc/pam.d as follows:
#%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需要身份验证强制系统使用我的模块我用命令命令验证每次。 (为前须藤鹦鹉螺)
The line "auth required pam_auth.so" forces the system to use my module for authentication everytime I use the command "sudo". (for ex- sudo nautilus)
现在的问题是:
;这条线在C文件pModule = PyImport_Import(PNAME),如下所示给出了一个导入错误,这是由PyErr_Print()打印的:
Now the problem is:This line in C file " pModule = PyImport_Import(pName); " gives an import error, which is printed by PyErr_Print() as follows:
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)
根据我可以理解,但没有按test.py文件中指定导入numpy的图书馆。如何解决导入错误和放这个问题; PyExc_SystemError?
As per I can understand,it fails to import numpy library as specified in test.py file. How to solve this problem of ImportError & PyExc_SystemError?
Python脚本工作方式的魅力,如果我运行如下:
The python script works as charm if I run in as follows:
#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;
}
如果它工作在一般蟒蛇嵌入的例子,为什么它在基于PAM嵌入的例子不工作(其中.so文件被使用)?
If it works under general python embedding examples, why its not working in PAM-based embedding examples (where .so files are used)?
PS:我导入numpy的特定原因。不要问我为什么还没有在python脚本的任何地方作为这仅仅是我想要达到一个演示脚本。此外,进口数学不给任何导入错误。我得到的进口错误SciPy的了。
PS: I'm importing numpy for a particular reason. Don't ask why I've not used in anywhere in python script as this is just a demo script of what I'm trying to achieve. Moreover, import math doesn't give any import error. I get import error for SciPY too.
PPS:numpy的和SciPy的包完美的作品在Python脚本和下/usr/lib/python2.7/dist-packages/安装。我使用Ubuntu 14.04。
PPS: Numpy and Scipy packages works perfect in python scripts and is installed under /usr/lib/python2.7/dist-packages/. I'm using ubuntu 14.04.
请帮助!
推荐答案
我不知道回答你的问题,但我想知道为什么没有更早失败。主机应用程序不知道你的PAM模块将使用libpython2.7.so.1需要,所以在某种程度上必须被动态加载,否则Py_Initialize()调用将失败,并同样的错误。
I don't know the answer to your question, but I am wondering why it didn't fail earlier. The host application does not know your PAM module will be needed using libpython2.7.so.1, so somehow that must being loaded dynamically otherwise the Py_Initialize() call would fail with the same error.
由于你说它不会失败有它必须被加载。但是从错误中你得到我们可以推断出它包含的符号(如 PyExc_SystemError 的)不是随后加载动态库可见。这是默认的库时使用装载的的dlopen()的(见的 RTLD_LOCAL 的中的男子3的dlopen 的)。要覆盖它,你必须通过的 RTLD_GLOBAL 导入的的dlopen()的。也许这就是你的问题。
Given you say it doesn't fail there it must be loaded. However from the error you are getting we can deduce the symbols it contains (such as PyExc_SystemError) are not visible to dynamic libraries subsequently loaded. This is the default when libraries are loaded using dlopen() (see RTLD_LOCAL in man 3 dlopen). To override it, you must pass RTLD_GLOBAL to dlopen(). Maybe that's your problem.
你的code。其他的评论:
Other comments about your code:
-
调用Py_Initialise()每个pm_sm _...()调用将是昂贵的,可能令人惊讶的Python模块。这意味着Python模块积累的一个呼叫中的所有数据(如说语音或用户名)下一个调用时将被丢弃。你最好装libpython2.7.so.1和初始化PAM一次,然后使用pam_set_data的清理功能()来卸载它,当你做。
Calling Py_Initialise() for each pm_sm_...() call is going to be expensive and possibly surprising to the python modules. It means all data the python module accumulated within one call (like say voice or the user name) will be discarded when the next call is made. You are better off loading libpython2.7.so.1 and initialising PAM once, then using the cleanup function of pam_set_data() to unload it when you are done.
在一个相关的问题,您的PAM模块是不是从Python程序使用,因为你总是调用的 Py_Initialise()的(我presume匹配调用的 Py_Finalize ()的)。
In a related issue, your PAM module isn't usable from Python programs because you always call Py_Initialise() (and I presume the matching call to Py_Finalize()).
如果你的程序没有超过它在哪里倒下,就已经下跌了就行的的printf(结果为%s \\ n,PyString_AsString(presult)),因为 presult 的未初始化。
If you program hadn't fallen over where it did, it would have fallen over on the line printf("Result is %s\n",PyString_AsString(pResult)) because pResult isn't initialised.
当我想你知道,你在这里的样板,让你拧在Python PAM模块是通过的 - 没有C需要。既然你显然用Python编写的PAM模块,无论如何,你已经接触到它即被但它提供了诸如记录未捕获的Python的异常功能丢失了开销。而最重要的是,使用它意味着你可以避开时完全是。您的PAM模块将被加载到守卫机器的安全程序 - 像登录,须藤和XDM / gdm3程序。避免C表示还避免安全漏洞C程序可以有在Python是不可能的军团 - 缓冲区溢出,未初始化的指针和访问free'ed内存。既然你有这些错误的一个在你的C code您张贴在这里,以避免这听起来像一个好主意。
As I think you know, all the boilerplate you have here to let you wring PAM modules in Python is provided by pam-python - no C required. Since you are evidently writing your PAM module in Python anyway, you are already exposed to the overheads it incurs but are missing out on the features it provides like logging uncaught Python exceptions. And most importantly, using it means you can avoid C entirely. Your PAM module will be loaded into programs that guard the security of the machine - programs like login, sudo, and xdm/gdm3. Avoiding C means also avoiding the legions of security bugs C programs can have that are impossible in Python - buffer overruns, uninitialised pointers and accessing free'ed memory. Since you have one of those bugs in your the C code you posted here, avoiding it sounds like a good idea.
这篇关于导入错误和PyExc_SystemError而在C中嵌入的Python脚本的PAM模块(.so文件)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!