LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Programming (https://www.linuxquestions.org/questions/programming-9/)
-   -   Question compiling PAM module (C++ code) (https://www.linuxquestions.org/questions/programming-9/question-compiling-pam-module-c-code-911973/)

raevin 11-05-2011 12:36 AM

Question compiling PAM module (C++ code)
 
I wrote an authentication PAM module in C++, as I didn't want to deal with C for a few reasons, so I would prefer not having to re-write the entire module if possible.

I can compile the C++ code just fine, and have no issues running the ld command, but when I try to test the module using pamtester, I get an error message saying:
[quote]pamtester: Module is unknown[/code]

I dug into /var/log/auth.log (as faillog has no information), and found these entries:
Code:

Nov  5 01:22:41 localhost pamtester: PAM unable to dlopen(/lib/security/pam_zorpher.so): /lib/security/pam_zorpher.so
Nov  5 01:22:41 localhost pamtester: PAM adding faulty module: /lib/security/pam_zorpher.so

Here's the compile line I've used:
Code:

g++ -fPIC -fno-stack-protector -c client.cpp Socket.cpp ClientSocket.cpp random.cpp vc.cpp
sudo ld -x -lpam --shared -o /lib/security/pam_zorpher.so client.o

There's also been these lines in there, and I don't know where "_class_type_info" came from at all:
Code:

Nov  5 01:35:03 localhost pamtester: PAM unable to dlopen(/lib/security/pam_zorpher.so): /lib/security/pam_zorpher.so: undefined symbol: _ZTVN10__cxxabiv117__class_type_infoE
Nov  5 01:35:03 localhost pamtester: PAM adding faulty module: /lib/security/pam_zorpher.so

I know the module exists, but this doesn't make sense. I don't have issues compiling a C PAM module.

NevemTeve 11-05-2011 01:14 AM

I think eventually you will have to rewrite it in C.

johnsfine 11-05-2011 10:30 AM

I would start by using the ldd command to see what your .so file depends on.

I have no idea what rules and limits apply to PAM modules. But I doubt NevemTeve's answer (that you must code it in C) is correct.

Whatever call points your .so exports should be declared
extern "C"
otherwise, a client expecting a C .so can't use your C++ .so. But that doesn't require you to rewrite in C. A C++ function declared extern "C" is still a C++ function, it is just called using C calling and naming standards. This (extern C) is probably the important part of the answer, but I don't know enough about PAM modules to give you specifics.

It is possible you will need to link some C++ library code from .a files rather than .so files. I really don't know enough about PAM modules to give you any details about that.

NevemTeve 11-05-2011 10:55 AM

Basically, a C++ program can use a subrutin/plugin written in C, but it is not possible the other way around.

raevin 11-05-2011 11:42 AM

Well, I find this weird. I did the extern "C" option, and its not giving me any errors, and here's the revised command line I'm using to compile:
Code:

g++ -fPIC -shared -lpam client.cpp Socket.cpp ClientSocket.cpp vc.cpp -o pam_zorpher.so
I need to use -fPIC because of it being a shared library (If I don't make it shared I either get a lot of undefined symbol errors, or "relocation R_X86_64_32 against `.rodata' can not be used when making a shared object; recompile with -fPIC"). But, I still can't access the module. What I did now is run ldd on the module:
Quote:

$ sudo ldd /lib/security/pam_zorpher.so
Password:
linux-vdso.so.1 => (0x00007fff685ff000)
libpam.so.0 => /lib/libpam.so.0 (0x00007f64bcf6b000)
libstdc++.so.6 => /usr/lib/libstdc++.so.6 (0x00007f64bcc60000)
libm.so.6 => /lib/libm.so.6 (0x00007f64bc9dd000)
libgcc_s.so.1 => /usr/lib/libgcc_s.so.1 (0x00007f64bc7c7000)
libc.so.6 => /lib/libc.so.6 (0x00007f64bc440000)
libdl.so.2 => /lib/libdl.so.2 (0x00007f64bc23b000)
/lib/ld-linux-x86-64.so.2 (0x00007f64bd3a6000)
I don't see how I could be having this issue compiling on a 64-bit system. I did read that using classes could cause a problem when it comes to extern "C", but not sure if that's the issue...and my program heavily relies on classes.

Update

I typed up all the above before trying something else. It seemed I forgot to include a specific C++ source file along with the compiler line, which was because I didn't know that file was needed. The module loads fine now, and am able to test it. Thanks everyone for the help, and it seems that the extern "C" was a big help on this as well!

Nominal Animal 11-05-2011 03:57 PM

Please remember mention in your documentation that using your PAM module will break early userspace for systems where /usr is a separate mount point, and that it may break PAM-aware native C programs.

This is because your PAM module, unlike normal PAM modules, has a dependency on /usr/lib/libstdc++. Not only is it only available after /usr has been mounted, but it is known to (occasionally) have symbol collisions with perfectly valid C programs. Weird crashes may occur in innocent C programs using PAM, thanks to your PAM module.

Normal PAM modules only depend on libraries under /lib or /lib64 which are part of the root mount, and therefore available to early userspace. They have also minimal dependencies. Certain modules, like pam_ldap (and similar), do have dependencies outside /lib, but that is generally acceptable because the modules will never work before /usr has been mounted and network connections are available anyway. Password checking modules also often depend on external libraries, but they are obviously not critical during early userspace.

I also wonder what idiot has installed libgcc_s.so.1 under /usr/lib in your system, and not /lib or /lib64 where it belongs. Having it under /usr (or anywhere other than the root partition) will mean programs relying on it will not work during early userspace. Perhaps your distribution requires /usr to be a part of the root mount, and will fail if it is a separate mount point? (Funny but sad, if so.)

The early userspace I refer to here means the time during which init scripts are being run, but /usr has not been mounted yet. It is not that rare to for example mount /usr over the network. In fact, it is a very efficient solution if you have a lot of identical lightweight workstations (almost thin clients), good network infrastructure (GbE or better), and a powerful file server. (On many storage devices, I/O to small files is often slow unless already cached. Two thirds of files in my /usr/lib, /usr/bin, and /usr/sbin are under 16384 bytes. This means that /usr over NFS, with a good NFS server, is surprisingly snappy over GbE.)

For the above reasons, I think it is utterly inconsiderate (and, to be honest, stupid) to write a PAM library in C++. There is about zero chance of having it included in any major distribution. C++ is simply not a suitable language for PAM modules.

I apologise if my tone sounds harsh. It is just that there are repercussions to the choice of language (or, to be more specific, the library dependencies), which in the case of PAM modules are both complex and dangerous. In my opinion, certainly serious enough to override any personal preferences.


All times are GMT -5. The time now is 01:38 PM.