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.
Related
I found a way using a Terminal Command for that purpose:
xdg-open http://www.google.com
But how can I do it from my code?
Thanks.
I don't know C, but it seems like you just need to call said shell script via C. So after a quick google search (hint hint), you could probably call something along the lines of
system("xdg-open http://www.google.com");
Basically you just want a function that can execute a shell script
#include <stdlib.h>
int main()
{
char *URL;
URL = "xdg-open http://google.com";
system(URL);
return 0;
}
If the executable for Firefox (or Chrome, etc) is in your path, you can get away with:
system("firefox http://www.google.com");
If not, try:
system("C:\\Program Files\\Mozilla\\Firefox.exe http://www.google.com");
Easiest way is to include stdio.h and use the system() call to call xdv-open.
If you want to be able to change the url, try:
#include "stdio.h"
int main(int argc, char ** argv){
char url[128]; //you could make this bigger if you want
scanf("%s",url); // get the url from the console
char call[256];
strcpy(call, "xdg-open "); // web browser command
strcat(call, url); // append url
system(call);
return 0;
}
#include <stdlib.h>
int main()
{
char *URL;
URL = "chromium http://localhost/image/index.php";
system(URL);
return 0;
}
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.
In order to protect an application from begin used wrongly, I'm trying to check that its configuration files have correct permissions, so that the application can trust the content of the files not being modified by someone else.
I believe the following rules are corrects:
the file must not be writable by others
the file must be owned by a trusted user/group: root
or
the file must be owned by the effective user/group running the application (think of setuid program)
Here an example:
#include <stdio.h>
#include <unistd.h>
#include <sys/stat.h>
#include <string.h>
#include <errno.h>
static
int is_secure(const char *name)
{
struct stat st;
uid_t euid = geteuid();
gid_t egid = getegid();
if (stat(name, &st) != 0) {
int err = errno;
fprintf(stderr, "can't stat() '%s': %d (%s)\n", name, err, strerror(err));
return 0;
}
/* writable by other: unsecure */
if ((st.st_mode & S_IWOTH) != 0) {
return 0;
}
/* not owned by group root and not owned by effective group: unsecure */
if (st.st_gid != 0 && st.st_gid != egid) {
return 0;
}
/* not owned by user root and not owned by effective user: unsecure */
if (st.st_uid != 0 && st.st_uid != euid) {
return 0;
}
return 1;
}
int
main(int argc, char *argv[])
{
int i;
for(i = 1; i < argc; i++) {
printf("'%s' : %s\n", argv[i], is_secure(argv[i]) ? "sure" : "unsure");
}
return 0;
}
Since I'm not sure about my assumptions, can someone check if I leave some loophole in the file permissions check.
Update
sudo has a function for that: sudo_secure_path, it only check for one uid/gid, but it take care of checking for group write bit.
Regards.
Your rules and your code look correct to me, although you should be aware of the following security risks that could still affect your implementation.
An attacker with physical access to the machine or NFS/SMB access could mount the file system with a box that has root privileges, and then modify your file.
A vulnerability in another program being run as either the trusted user or root could allow that program to be exploited to modify your file.
All it would take to break your security check would be a careless user or sys-admin that messes up the privilege settings of the file. I've seen this happen during backups and copies to thumb drives, etc.
Also make sure the file is not executable. I can't think of an instance where this could be exploited on a config file, but the general rule with security is don't give any privileges that aren't required for the job.
As you can see these are not issues under control of your code. Therefore, you should make sure you client is aware of these risks before assuring them of the non-tamperability of the config file.
I believe you also want to check permissions on the directory.
A user would be able to mv another file belonging to the correct user to replace this one, if they are allowed to write to the directory.
Something like:
sudo touch foo.conf
sudo touch foo.conf-insecure-sample
mv -f foo.conf-insecure-sample foo.conf
I want to write to a random output, among which STD_OUTPUT_FILE can be. I want to use
WriteFile, but it does not seem to write anything.
HANDLE outH = GetStdHandle ( STD_OUTPUT_HANDLE );
WriteFile( outH,param, strlen ( param ), &written_b, NULL );
I solved it.
There was a error in redirecting the standard output in which when it should let it be as it was, it was doing something wrong. Do not know yet. I will update my answer.
Your code lacks any form of error-checking. This is common with code copied from a website or Stack Overflow answer, where the error-checking is often omitted for clarity and brevity. But any time you write code yourself, you absolutely must assume that it can fail and write the code to deal with that case. Here, you know it is failing and you still haven't gone back to add the error-checking code to see where that failure is occurring.
Let's add the error-checking code now, referring to the SDK documentation when necessary to see how the API functions you call handle error conditions:
static void ReportError(const TCHAR* errorMsg)
{
MessageBox(NULL, errorMsg, NULL, MB_OK | MB_ICONERROR);
}
int _tmain(int argc, TCHAR* argv[])
{
char param[] = "This is some output.";
DWORD written_b;
HANDLE outH = GetStdHandle(STD_OUTPUT_HANDLE);
if (!outH)
{
ReportError(TEXT("No standard handles associated with this app."));
}
else if (outH == INVALID_HANDLE_VALUE)
{
TCHAR errMsg[100];
wsprintf(errMsg, TEXT("GetStdHandle() failed with error code %lu"), GetLastError());
ReportError(errMsg);
}
else
{
if (!WriteFile(outH, param, strlen(param), &written_b, NULL))
{
TCHAR errMsg[100];
wsprintf(errMsg, TEXT("WriteFile() failed with error code %lu"), GetLastError());
ReportError(errMsg);
}
}
return 0;
}
Now, if something goes wrong, we'll not only know it but we'll know why.
And good thing, because when I run this code on my computer, it works just fine. The problem therefore lies elsewhere in your application in some of the code we haven't seen. The error-handling code will help flush it out.
To write to STDOUT using the calling window/console, you need to link the resulting executable to the console subsystem.
LINK.exe /EDIT /SUBSYSTEM:CONSOLE {your exe name here}
This works with the older VB6 environment, I'm assuming the same executable flags apply to Visual C as well.
I have to a do C program that uses the unix environment. I have already purchased the "Advancing Programming in the Unix Environment" book and it has helped out a lot so far. However, some of my questions have gone unanswered and I'm looking for some help.
I'm trying to write a program that can verify if the first and second arguments entered if a copy program exist. If the first argument does not exist, then an error message and exit must occur. If the second argument does exist, then an overwrite prompt must be displayed. I'm not exactly sure how to verify if a file already exists or not basically.
I have seen a few people saying that you can do (!-e) or something like that to verify the file existing/not existing.
If anyone could help me, I'd really appreciate it.
The access() function is designed to tell you if a file exists (or is readable, writeable or executable).
#include <unistd.h>
int result;
const char *filename = "/tmp/myfile";
result = access (filename, F_OK); // F_OK tests existence also (R_OK,W_OK,X_OK).
// for readable, writeable, executable
if ( result == 0 )
{
printf("%s exists!!\n",filename);
}
else
{
printf("ERROR: %s doesn't exist!\n",filename);
}
in your int main(int argc, char** argv) { block.
if (argc == 3) {
// then there were 3 arguments, the program name, and two parameters
} else if (argc == 2) {
// then prompt for the "second" argument, as the program name and one
// parameter exists
} else {
// just print out the usage, as we have a non-handled number of arguments
}
now if you want to verify that the file exists, that's different than verifying that the program argument exists. Basically attempt to open the file and read from it, but pay close attention to catching the integer error codes and checking them for errors. This will prevent your program from progressing into bits where those critical operations are assumed to have worked.
There is a common, yet misguided conception among new programmers when dealing with files in C. Basically, one really wants to make sure that a specific block of code works (the copying block in your case), so they check, check, and double-check conditions before the block is executed. Check if the file exists, check if it has correct permissions, check that it isn't a directory, etc. My recommendation is that you not do this.
Your copying block should be able to fail properly, just as properly as it should be able to succeed. If it fails, then typically you have all the information necessary to print out a meaningful error message. Should you check first and then act there will always be a small time gap between the check and action, and that time gap will eventually see the file removed or altered after the checks have passed, yet before it is read. Under such a scenario all of the pre-checking code failed to provide any benefit.
Code without benefit is just a nesting ground for future bugs and architectural problems. Don't waste your time writing code that has dubious (or no) benefit. When you suspect that some code you have written has little benefit, you need to restructure your code to put it in the right place. When you suspect that code someone else has written has little benefit, you need to first doubt your suspicions. It is trivially easy to not see the motivations behind a piece of code, and even more so when just starting out in a new language.
Good Luck!
--- code for the weary ---
#include <errorno.h>
#include <stdio.h>
#include <stdlib.h>
extern int errno;
int main(int argc, char** argv) {
// to hold our file descriptor
FILE *fp;
// reset any possible previously captured errors
errno = 0;
// open the file for reading
fp = fopen(argv[1], "r");
// check for an error condition
if ( fp == 0 && errno != 0 ) {
// print the error condition using the system error messages, with the
// additional message "Error occurred while opening file"
perror("Error occurred while opening file.\n");
// terminate the program with a non-successful status
exit(1);
}
}