I am writing a custom PAM module.
I have written a shared object (.so) file as required for Linux-PAM. What this .so file does, is call embedded Python to open up my facial recognition and , depending on the outcome, will return PAM_SUCCESS or PAM_AUTH_ERR
In the /etc/pam.d/sudo file I have told PAM that the file resides in (/home/berns/2020-ca326-cberns-fileencryption-with-opencv/PAM/pam_authnew.so). This is okay as , when sudo is typed, I can see my own personal error statement being printed saying it could not load the Python file.
The issue I have is, the facial recognition code resides in a total different directory from where the .so file resides. (../code/facial). I have used a chdir command in my C code, but it does'nt seem to change the directory back to where the Python facial files reside to provide success or not.
Is there something I'm missing ?
C code given below:
#define PAM_SM_AUTH
#define PAM_SM_ACCOUNT
#define PAM_SM_SESSION
#define GetCurrentDir getcwd
#include <dlfcn.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <security/pam_appl.h>
#include <security/pam_modules.h>
#include </usr/include/python3.6m/Python.h>
int main(int argc, char** argv){
}
PAM_EXTERN int pam_sm_authenticate( pam_handle_t *pamh, int flags,int argc, const char **argv ){
char *result;
chdir("../code/facial"); // this changes it to the correct directory to execute
//dlopen("/usr/lib/x86_64-linux-gnu/libpython3.6m.so",RTLD_LAZY | RTLD_GLOBAL);
Py_Initialize(); // Starts python interpreter
PyRun_SimpleString("import os\nimport sys\nsys.path.append(os.getcwd())"); // lets python know where we are
PyObject *mymod, *func1, *ret1;
mymod = PyImport_ImportModule("pam_detect"); // This is the .py
if (mymod != NULL){ // check if the file file was loaded
func1 = PyObject_GetAttrString(mymod, "detect"); // hel is the function name in the file you declared earlier
ret1 = PyObject_CallObject(func1, NULL); // Null because the function doesnt take an argument.
result = PyUnicode_AsUTF8(ret1);
//printf("%s\n", result);
if (strcmp(result, "success") == 0){
Py_Finalize();
return PAM_SUCCESS;
}
else{
Py_Finalize();
return PAM_AUTH_ERR;
}
}
else{
printf("Error: can't find file!\n");
}
Py_Finalize();
return 0;
}
Error response from the terminal below
Is this due to child processes not changing the directories outside of their own running space ?
Also worth noting if I compile the C code WITHOUT making it a .so , I can load up the Python files perfectly and recognise my face.
Related
I am trying to embed python script into c++ project.
Below is what I have tried so far.
#include<iostream>
#include <Python.h>
int
main()
{
Py_Initialize();
PyObject* sysPath = PySys_GetObject("path");
PyObject* modPath = PyBytes_FromString("C:\\Users\\naal\\Documents\\Visual Studio 2017\\Projects\\Project1\pyscripts");
int result = PyList_Insert(sysPath,0, modPath);
PyObject *pModule = PyImport_ImportModule("myscript2");
printf("%p\n", pModule);
return 0;
}
below is the python script "myscript2.py"
def find_me():
print("hey you found me")
The problem is, the main module is not able to find the python script i.e object pyModule is always NULL, no matter how I change python script path.
What am I doing wrong ?
I ended up implementing this in another way.
#include<iostream>
#include <Python.h>
int main() {
std::string location = "C:\\Users\\myscript.py";
const char* file_location = location.c_str(); FILE* file_pointer;
Py_Initialize();
file_pointer = _Py_fopen(file_location, "r");
PyRun_SimpleFile(file_pointer, file_location);
Py_Finalize();
return 1;
}
The above seemed to work. I still don't know why the SYSPATH idea originially mentioned in the question didn't work.
I'm trying to create an instance of Game, pass it into the main namespace of the test.py as the variable game, then call game.add(e) to run the C++ function that will add Entity e into the std::vector. However, this code produces the error:
unbound method Boost.Python.function object must be called with Game instance as first argument (got Entity instance instead)
(Some context: I'm trying to let Python create instances that will be kept in a container for C++ to run through every tick and update. I thought I had it working a few weeks ago but I came back to it and apparently it wasn't working - I know, source control.)
#include <vector>
class Entity{
public:
Entity(){}
Entity(float x, float y){}
};
class Game{
public:
Game();
void add(Entity* entity);
private:
std::vector<Entity*> objects_;
};
Game::Game(){
}
void Game::add(Entity* entity){
objects_.push_back(entity);
}
main.cpp:
#include <iostream>
#include <boost/python.hpp>
#include "Game.h"
#include "Entity.h"
using namespace boost::python;
BOOST_PYTHON_MODULE(sfgame){
class_<Game>("Game")
.def("add", &Game::add)
;
class_<Entity>("Entity", init<float, float>())
;
}
int main(){
PyImport_AppendInittab("sfgame", &initsfgame);
Py_Initialize();
object main_module = import("__main__");
object main_namespace = main_module.attr("__dict__");
import("sfgame");
Game* game = new Game();
try{
main_namespace["game"] = ptr(game);
exec_file("test.py", main_namespace);
}
catch (const boost::python::error_already_set &){
PyObject *ptype, *pvalue, *ptraceback;
PyErr_Fetch(&ptype, &pvalue, &ptraceback);
std::string error;
error = boost::python::extract<std::string>(pvalue);
std::cout << error << std::endl;
}
delete game;
system("PAUSE");
return 0;
}
test.py:
from sfgame import *
e = Entity(5,5)
game.add(e)
You would receive that error if you set the variable name in the main namespace to Game, as it would be the same as the class name.
However, the code posted is correct. You must have compiled the .pyd file using the variable Game, realised your error, then changed it to game and compiled the C++ file to test it without recompiling the .pyd file so the error remained.
I have write a python script that load a dll writed in c++ .
Script is :
from ctypes import *
mydll = cdll.LoadLibrary('C:\\Users\\gpiscite\\Documents\\Project\\DllXPython\\Debug\\DllXPython.dll')
mydll
mydll.fnDllXPython(956, c_char_p("c_char_p"), c_void_p(0), "std::string")
The c++ code is compiled in VisualStudio as a DLL and it is:
// DllXPython.cpp : Defines the exported functions for the DLL application.
//
#include "stdafx.h"
#include <cstdlib>
#include <string>
#include "DllXPython.h"
// This is an example of an exported variable
DLLXPYTHON_API int nDllXPython=0;
// This is an example of an exported function.
DLLXPYTHON_API int fnDllXPython(int aInt, char* apChar, void* apVoid, std::string aString)
//DLLXPYTHON_API PyObject * fnDllXPython(PyObject *self, PyObject *args)
{
return 0;
}
I had attached debug on python process and i saw thad the exception was raised on return 0 execution . The exception raised is:
Debug Assertion Failed! ..... _BLOCK_TYPE_IS_VALID(pHead->nBlockUse) ....
Any idea ? Thanks.
"std::string" is not a std::string. It is merely a char*
I've been messing around with the Python/C API and have this code:
#include <Python.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[]) {
//Initialize Python
Py_Initialize();
//Run file
FILE *fp = fopen("Test.py", "r");
PyRun_SimpleFile(fp,"Test.py");
fclose(fp);
//Run Python code
PyRun_SimpleString("print(__NAME__)");
PyRun_SimpleString("print(__DESC__)");
PyRun_SimpleString("print(__SKIN__)");
PyRun_SimpleString("onEnable()");
//Finalize Python
Py_Finalize();
return EXIT_SUCCESS;
}
Test.py contains this:
__NAME__ = "Frank"
__DESC__ = "I am a test script"
__SKIN__ = "random image"
def onEnable():
print("In Func")
As you would expect, compiling and running the c program results in this:
Frank
I am a test script
random image
In Func
However, I need a way to get the python strings from interpreter, stick them in C strings and then print them, rather than using PyRun_SimpleString("print(blah)").
For example:
char *__NAME__;
__NAME__ = Py_GetObject("__NAME__")
Is this possible?
Thanks for your help.
You need to use PyString_AsString. I think it goes something like this:
PyObject* module = PyImport_AddModule("__main__");
PyObject* o = PyObject_GetAttrString(module , "__NAME__");
if (PyString_Check(o))
{
const char* name = PyString_AsString(o);
// don't delete or modify "name"!
}
Py_DECREF(o);
I have from a third party a DLL delivered together with his .lib and .h files (let's say the files are: "test.dll", "test.lib" and "test.h")
This delivered DLL contains some functions that I should access them from a Python script.
For this, I must build an extension (.pyd) using SWIG and MSVC2010.
(I copy the third party files into the MSVC project's directory)
To have an overview about "test.h" file, this is how it looks like (for simplicity, I put only one function, "CreateFile()", which returns a file handle):
/* File : test.h */
#if !defined ( TEST_H )
#define TEST_H
#if defined ( _MSC_VER )
#pragma warning( disable: 4103)
#pragma pack( push, 8)
#elif defined ( __BORLANDC__ )
#pragma option push -a8
#pragma nopushoptwarn
#pragma nopackwarning
#endif
#include <wtypes.h>
/*----------------------------------------------------------------------------
| BL API
-----------------------------------------------------------------------------*/
#if defined ( DLL_EXPORTS )
#define BLAPI( ret) ret __stdcall
#else
#define BLAPI( ret) __declspec( dllimport) ret __stdcall
#endif
/*----------------------------------------------------------------------------
| API
-----------------------------------------------------------------------------*/
#if defined ( __cplusplus )
extern "C" {
#endif
BLAPI( HANDLE) CreateFile( LPCTSTR lpFileName, DWORD dwDesiredAccess);
#if defined ( __cplusplus )
}
#endif
/*----------------------------------------------------------------------------
|
-----------------------------------------------------------------------------*/
#if defined ( _MSC_VER )
#pragma pack( pop)
#elif defined ( __BORLANDC__ )
#pragma option pop
#pragma nopushoptwarn
#pragma nopackwarning
#endif
#endif // TEST_H
I intend to make a class to wrap those third party functions (implemented in "test.dll" library). The "myInterface.h" file looks like this:
/* File : myInterface.h */
#include <windows.h>
#include "test.h" // <--- third party header
class myInterfaceClass {
public:
myInterfaceClass() {
}
virtual ~myInterfaceClass() {
};
HANDLE hFile;
BOOL errorCode;
BOOL OpenFile( LPCTSTR lpFileName ); // <-- function wrapper
};
...and the implementation of the class, I put it into "myInterface.cxx" file:
/* File : myInterface.cxx */
#include "myInterface.h"
#include "test.h" // <--- third party header
#include <windows.h>
BOOL myInterfaceClass::OpenFile( LPCTSTR lpFileName )
{
errorCode = TRUE;
// open file
hFile = CreateFile(lpFileName, GENERIC_READ); // <--- third party function call
errorCode = ( INVALID_HANDLE_VALUE == hFile);
return errorCode;
}
To use SWIG, I must add into the MSVC project the following SWIG interface file .i:
/* File : myInterface.i */
%module myInterface
%{
#include "myInterface.h"
#include "test.h"
%}
/* Let's just grab the original header file here */
%include "myInterface.h"
%include "test.h"
In the MSVC project, in the "Properties" of this .i file, I put on "Custom Build Tool" -> "Command Line", the following:
echo PYTHON_INCLUDE: %PYTHON_INCLUDE%
echo PYTHON_LIB: %PYTHON_LIB%
rem
rem WARNING!: Use quotes (" ") on path names to avoid errors !
rem
echo on
echo.
echo. "%(FullPath)"
echo.
"%SWIG_PATH%\swig.exe" -c++ -python -I%SWIG_PATH%\lib -Itest "%(FullPath)"
OK!
When I try to build the PYD extension, I've got this error:
Error 1 error : Syntax error in input(1). D:\ADXWorkZone\testSwig\test.h 33 1 myInterface
...but there is nothing wrong with "test.h" file. I use the same file (without any modifications) to implement the same C++ wrapper class as a classic DLL and it works well.
Project specs:
Properties -> C/C++ -> General -> Additional Include Directories: $(PYTHON_INCLUDE)
Properties -> Linker -> General -> Output File: _myInterface.pyd
Properties -> Linker -> Input -> Additional Dependencies: $(PYTHON_LIB);test.lib
Could anyone help me, please?
Any idea will be appreciated!
Thank you!
Try adding the following before your other %includes in your interface file.
%include <windows.i>
SWIG doesn't recurse into nested includes, and this provides definitions such as BOOL and _declspec that otherwise confuse SWIG.