How to mock the pam_handle struct - c

Background
I am developing a module using the PAM specification and I would like to test one of the pam functions (specifically pam_sm_authenticate) to make sure that the helper functions that I have implement play nice with the specification.
The pam_sm_[authenticate, acct_mgmt...etc.] series functions all take the same parameters.
int pam_sm_acct_mgmt(pam_handle_t *pamh, int flags, int argc, const char **argv)
I am having trouble mocking struct pam_handle, but need to as this structure will contain information vital to authenticating users.
Using PAM header information from the internet (pam_appl.h and pam_private.h) I have attempted to use the structure directly as pam_handle_t normalPamh; and populate it myself, but when I try to I get the following error:
error: aggregate 'pam_handle_t normalPamh' has incomplete type and cannot be defined
I would really like to test my module to make sure that I haven't done anything that will cause segmentation faults and that I'm using memory within reasonable limits, but I am having trouble doing so because I can't mock this structure.
Question
How do I mock the pam_handle_t struct?

It sounds like, the headers you're referring to declare the pam-handle type along the lines of:
typedef struct pam_handle pam_handle_t;
However the actual definition of the struct pam_handle is NOT part of the headers you describe. To mock it, you would need to specify the actual structure before writing any code that code accessing the struct pam_handle members (whatever they are). I.E:
In your interface definitions, you "post-pone" the structure definition, by using handle only:
int pam_sm_acct_mgmt(pam_handle_t *pamh, int flags, int argc, const char **argv);
In your test code, where you modify handle-members for testing purposes, you have to define it, e.g.
#include "interface_to_be_tested.h"
// declare the pam_handle
struct pam_handle
{
// provide definition of struct-members here
};
...
// Test code here
Update: The structure seems to be defined in libpam/pam_private.h, so including that file in your test-code ought to be sufficient. Note the header is "private", so your actual implementation should of course NOT use this.
Hope that helps!

I found some open source software that does exactly what I need it to.
It's called pamtester and it compiles on a number of *nix systems.
Once it's installed you can run it like:
pamtester -v -I user=test01#test.com -I rhost=192.168.2.150 dovecot test01#test.com "authenticate(PAM_ESTABLISH_CRED)"
It will take care of everything else that is needed to establish user credentials.
I wanted to use it in automated testing through C, so I wrapped a lot of the calls in a bash script where I could specify input I wanted to change like user and ruser.
The problem is passwords need to be entered when the program asks for it. I solved this using popen in my C source.
Here is an example of what I did for reference. It's not perfect, but for anyone else that might run into a similar situation this might serve as a starting point.
int testPamSmAuthenticate(char * username, char * hostname, char * password) {
//--------------------------------------
// declarations
//--------------------------------------
char testCommand[512];
char passwordPromptResponse[128];
char resultLine[3];
FILE * testFile;
//--------------------------------------
// declarations
//--------------------------------------
sprintf(testCommand, "%s %s %s", PAM_TEST_SCRIPT_PATH, username, hostname);
sprintf(passwordPromptResponse, "%s\n", password);
//--------------------------------------
// run the command and enter a password
//--------------------------------------
if (!(testFile = popen(testCommand, "w"))){
return(1);
}
fputs(passwordPromptResponse, testFile);
pclose(testFile);
//--------------------------------------
// get the output of the command from
// the text file written by bash
//--------------------------------------
testFile = fopen(PAM_TEST_RESULT_PATH, "r");
while (fgets(resultLine, sizeof(resultLine), testFile)) {
printf("%s", resultLine);
}
fclose(testFile);
//--------------------------------------
// evaulate and return a code
// 1 == authentication good
// 0 == authentication bad
//--------------------------------------
if (strchr(resultLine, '0')) {
printf("Authentication successful!\n");
return(1);
}
printf("Authentication failed!\n");
return(0);
}
More information about the use of this program is available by downloading the source and reading it's README file.

Related

Build new binary from C program

I'm working on a C program, it's a custom shell that asks the user to set different options (IP, port, ...) and then allow the user to build a binary based on these informations. I was wondering what is the best way to build a new binary from within an existing program ?
EDIT: My question may have been a bit unclear. The new compiled binary is a simple TCP client that will connect to the specified IP and Port. I don't want this new binary to be dependant of a config file. How can i build this from my existing C program ? Should i write the IP and Port to a .c file and then compile it using system("/bin/gcc ...") ?
I think you are describing code generation and programmatically compiling a new executable. There are many ways to do what you have described. Here is a very simple (and very rough draft of a) set of steps to code gen, and compile:
1) Use printf, fgets calls from existing program to prompt user for a specific set of input values
2) Convert command line numeric input values if necessary. (Using atoi(), or strtod() for example)
3) Open a file for write, (eg FILE *fp = fopen(filespec, "w");)
4) Using fputs(), send a series of lines to the file comprised of a C source file, including values from steps 1&2 from the user input.
eg. fputs("#include _some file_", fp); (and other header files as needed)
eg, fputs("int main(int argc, char *argv[]) {", fp);
fputs(...) (all of the rest of your lines to make up the complete user defined code.)
fputs("return 0; }", fp);
5) close the file: fclose(fp);
6) Construct a gcc command line compile string to be used on command line on the file you just created.
7) Using popen() (If available) or system() or if using Windows, something like this to send a command to the OS, to execute gcc (or other compiler) on the command line to create your executable.
If you have ready code in C all the options (like ip or other parameters write to the another file for example userdata.c
#include "userdata.h"
unsigned char IP[4] = {212,34,56,78};
const char IPstring[] = "212.34.56.78";
const char DNSIPstring[] = "4.4.4.4";
const char defaultGatewayIPstring[] = "212.34.56.1";
/* etc etc */
and userdata.h
#ifndef USERTATA_H
#define USERTATA_H
extern unsigned char IP[];
extern const char IPstring[];
extern const char DNSIPstring[];
extern const char defaultGatewayIPstring[];
/* etc etc */
#endif
In your main program files just include the .h file. Do not forget to compile and link the .c file as well :)

C Unit Testing - Mock (In Check Framework)

I'm trying to "mock" some things in my unit testing of a C project.
I am using the Check framework for testing and I have a function that reads from a file on disk to verify the contents.
My function is:
#include "verifier.h"
#include <stdio.h>
int verify_content(char *path, char *verify_string) {
File *fptr
fptr = fopen(path, "r")
// Do verification
return 0
and my test is
START_TEST (verify_content_test)
{
char *test_path = "test_path";
char *test_string = "unique_string_content_here";
ck_assert_str_eq(verify_content(test_path, test_string), 0);
}
END_TEST
However, I don't want this to read from disk, because that would be slow, and I'd have to have multiple static files just for testing against.
Is there a way to "mock"/"fake" the fopen?
I'm still new to C development and super new to unit testing in C so if I should approach this problem differently, please point me in the right direction.
You can write your own fopen() and put anything you like into it. Link this module with all other modules that need the mocked version.
The function will only be linked from the standard library if there are unresolved references. Providing your own implementation resolves all references and so the standard version will not be used.
With GCC you also have another alternative: use the linker's --wrap option. For example --wrap=fopen will change all references of fopen() into __wrap_fopen() and change the defined symbols of fopen() into __real_fopen(). This way you can "intercept" the call and massage it to you liking:
FILE* __wrap_fopen(const char* filename, const char* mode) {
/* Do anthing you want, including changing arguments or not calling __real_fopen() at all. */
FILE* result = __real_fopen(filename, mode);
/* Do anthing you want, including changing the result. */
return result;
}

Simple PAM example

I want to develop an authentication module using PAM, but I'm having trouble getting a simple example working.
For starters, I would like to do a simple SSH login system where if the user enters the username backdoor, then the user will be logged in without a password (just like in TRON Legacy).
I tried using this guide as a template, but I can't get it to work. Here is my code so far:
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_authenticate( pam_handle_t *pamh, int flags,int argc, const char **argv ) {
int retval;
printf("I'm here");
const char* pUsername;
retval = pam_get_user(pamh, &pUsername, "Username: ");
if (retval != PAM_SUCCESS) {
return retval;
}
if (strcmp(pUsername, "backdoor") != 0) {
return PAM_AUTH_ERR;
}
return PAM_SUCCESS;
}
When I log in with the name backdoor, I get permission denied. I've tried creating the user account, but I still get prompted for the password.
When I log in with a valid user, I see the "I'm here" printout. Is there a better way to debug something like this or is it mostly trial and error?
EDIT:
I added this to my /etc/pam.d/sshd after #include common-auth:
auth sufficient mypam.so
This comes after 2 other .so files, but I'm pretty sure it's getting executed every time.
I have not modified pam.conf (there isn't anything there). I figured that starting with SSH would be easiest because I don't have to log out each time.
EDIT:
I finally got it working. Here's the result:
https://github.com/beatgammit/simple-pam
It's open-source, so if you're interested, take a look!
First off, sufficient will still fail if a previous required module has failed. Since you say you have put your sufficient line beneath the include of common-auth you may be seeing a failure because some required module in common-auth has denied access already. Plus you have have sshd getting in the way.
I'd get all this stuff out of the way so you know your test is really a test of your pam module and not some further interaction with other things. I'd start with a simple test program like the one here with /etc/pam.d/check_user listing your module instead of pam_unix.

Traversing file system according to a given root place by using threads by using C for unix

I wanna traverse inside the file system by using threads and processes.My program has to assume the first parameter is either given as "-p" which offers a multi-process application or "-t" which runs in a multi-threaded way. The second parameter is the
pathname of a file or directory. If my program gets the path of a file, it should print out the size of the file in bytes. If my program gets the path of a directory, it should, in the same way, print out the directory name, then process all the entries in the
directory except the directory itself and the parent directory. If my program is given a directory, it must display the entire hierarchy rooted at the specified directory. I wrote something but I got stuck in.I can not improve my code.Please help me.
My code is as following:
include
include
include
include
include
include
include
int funcThread(DIR *D);
int main(int argc, char * argv[])
{
pthread_t thread[100];
DIR *dirPointer;
struct stat object_file;
struct dirent *object_dir;
int counter;
if(opendir(argv[1])==NULL)
{
printf("\n\nERROR !\n\n Please enter -p or -t \n\n");
return 0;
}
if((dirPointer=opendir(argv[1]))=="-t")
{
if ((object_dir = opendir(argv[2])) == NULL)
{
printf("\n\nERROR !\n\nPlease enter the third argument\n\n");
return 0;.
}
else
{
counter=0;
while ((object_dir = readdir(object_dir)) != NULL)
{
pthread_create(&thread[counter],NULL,funcThread,(void *) object_dir);
counter++;
}
}
}
return 0;
}
int funcThread(DIR *dPtr)
{
DIR *ptr;
struct stat oFile;
struct dirent *oDir;
int num;
if(ptr=readdir(dPtr)==NULL)
rewinddir(ptr);
if(S_ISDIR(oFile.st_mode))
{
ptr=readdir(dPtr);
printf("\t%s\n",ptr);
return funcThread(ptr);
}
else
{
while(ptr=readdir(dPtr)!=NULL)
{
printf("\n%s\n",oDir->d_name);
stat(oDir->d_name,&oFile);
printf("\n%f\n",oFile.st_size);
}
rewinddir(ptr);
}
}
This line:
if((dirPointer=opendir(argv[1]))=="-t")
dirPointer is a pointer DIR* so how can it be equal to a literal string pointer?
I spotted a few errors:
Why are you using opendir() to check your arguments? You should use something like strcmp for that.
You're passing struct dirent* to funcThread() but funcThread() takes a DIR*.
You're using oFile on funcThread() before you initialize it (by calling stat()).
What is the purpose of calling rewinddir()? I guess you're blindly trying to get readdir() to work with a struct dirent*.
You're using oDir but it's never initialized.
You're calling printf() from multiple threads with no means to synchronize the output so it would be completelly out of order or garbled.
I suggest you read and understand the documentation of all those functions before using them (google "posix function_name") and get familiar with the basics of C. And before bringing threads into the equation try to get it working on a single threaded program. Also you won't see an improvement in performance by using that many threads unless you have close to that many cores, it will actually decrease performance and increase resource usage.
if(ptr=readdir(dPtr)==NULL){}
The = operator has lower precedence than ==
[this error is repeated several times]

How can I write commands to the vxworks shell with a c program

If I wanted to run a shell command in linux with a c program, I would use
system("ls");
Is there a way I can accomplish this in Wind River vxworks?
I found the below example but I'm wondering do I need to include vxworks header files for this to work? I assume I do, but how do I figure out which one?
Example:
// This function runs a shell command and captures the output to the
// specified file
//
extern int consoleFd;
typedef unsigned int (*UINTFUNCPTR) ();
extern "C" int shellToFile(char * shellCmd, char * outputFile)
{
int rtn;
int STDFd;
int outFileFd;
outFileFd = creat( outputFile, O_RDWR);
printf("creat returned %x as a file desc\n",outFileFd);
if (outFileFd != -1)
{
STDFd=ioGlobalStdGet(STD_OUT);
ioGlobalStdSet(STD_OUT,outFileFd);
rtn=execute(shellCmd);
if (rtn !=0)
printf("execute returned %d \n",outFileFd);
ioGlobalStdSet(STD_OUT,STDFd);
}
close(outFileFd);
return (rtn);
}
I found the code segment below worked for me. For some reason changing the globalStdOut didn't work. Also the execute function did not work for me. But my setting the specific task out to my file, I was able to obtain the data I needed.
/* This function directs the output from the devs command into a new file*/
int devsToFile(const char * outputFile)
{
int stdTaskFd;
int outputFileFd;
outputFileFd = creat( outputFile, O_RDWR);
if (outputFileFd != ERROR)
{
stdTaskFd = ioTaskStdGet(0,1);
ioTaskStdSet(0,1,outputFileFd);
devs();
ioTaskStdSet(0,1,stdTaskFd);
close(outputFileFd);
return (OK);
}
else
return (ERROR);
}
If this is a target/kernel shell (i.e. running on the target itself), then remember that all the shell commands are simply translated to function calls.
Thus "ls" really is a call to ls(), which I believe is declared in dirLib.h
I think that the ExecCmd function is what you are looking for.
http://www.dholloway.com/vxworks/6.5/man/cat2/ExecCmd.shtml
As ever, read the documentation. ioLib.h is required for most of the functions used in that example, and stdio.h of course for printf().
As to the general question of whether you need to include any particular headers for any code to compile, you do need to declare all symbols used, and generally that means including appropriate headers. The compiler will soon tell you about any undefined symbols, either by warning or error (in C89/90 undefined functions are not an error, just a bad idea).

Resources