Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 12 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ To build, either use the build scripts or use these commands:

`gcc -fPIC -fno-stack-protector -c src/mypam.c`

`sudo ld -x --shared -o /lib/security/mypam.so mypam.o`
`ld -x --shared -lpam -o /tmp/pam_mypam.so mypam.o`

The first command builds the object file in the current directory and the second links it with PAM. Since it's a shared library, PAM can use it on the fly without having to restart.

Expand All @@ -23,21 +23,25 @@ OR

The test program is valid C, so it could be compiled using gcc or g++. I like g++ better because I'll probably want to extend it and I like C++ better.

The test program requires the service name and username as arguments.


Simple Usage
------------

The build scripts will take care of putting your module where it needs to be, `/lib/security`, so the next thing to do is edit config files.
The config files are located in `/etc/pam.d/`.
You can create a new PAM service dedicated by creating ``/etc/pam.d/mypam``.

The config files are located in `/etc/pam.d/` and the one I edited was `/etc/pam.d/common-auth`.
The test application tests auth and account functionality (although account isn't very interesting). The new file should :

The test application tests auth and account functionality (although account isn't very interesting). At the top of the pam file (or anywhere), put these lines:
auth sufficient /tmp/mypam.so
account sufficient /tmp/mypam.so

auth sufficient mypam.so
account sufficient mypam.so

I think the account part should technically go in `/etc/pam.d/common-account`, but I put mine in the same place so I'd remember to take them out later.
To run the test program, just do: `./pam_test mypam backdoor` and you should get some messages saying that you're authenticated!
Maybe this is how Sam Flynn 'hacked' his father's computer in TRON Legacy =D.

To run the test program, just do: `pam_test backdoor` and you should get some messages saying that you're authenticated! Maybe this is how Sam Flynn 'hacked' his father's computer in TRON Legacy =D.
On Ubuntu or Debian you can check `tail -f /var/log/auth.log` for errors.

Resources
=========
Expand Down
131 changes: 126 additions & 5 deletions src/mypam.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,32 +4,153 @@
#include <security/pam_appl.h>
#include <security/pam_modules.h>

/*
this function ripped from pam_unix/support.c

It does a PAM conversation.
*/
int converse(
pam_handle_t *pamh,
int nargs,
struct pam_message **message,
struct pam_response **response
){
int retval;
struct pam_conv *conv;

retval = pam_get_item(pamh, PAM_CONV, (const void **)&conv);
if (retval == PAM_SUCCESS) {
retval = conv->conv(
nargs,
( const struct pam_message ** ) message,
response,
conv->appdata_ptr
);
}
return retval;
}


/*
this function ripped from pam_unix/support.c

It initiated a PAM conversation for getting the password.
*/
int set_auth_tok(pam_handle_t *pamh, int flags) {

int retval;
char *p;

struct pam_message msg[1],*pmsg[1];
struct pam_response *resp;

/* set up conversation call */
pmsg[0] = &msg[0];
msg[0].msg_style = PAM_PROMPT_ECHO_OFF;
msg[0].msg = "Password: ";
resp = NULL;

if ((retval = converse( pamh, 1 , pmsg, &resp )) != PAM_SUCCESS)
return retval;

if (resp) {
if ((flags & PAM_DISALLOW_NULL_AUTHTOK ) && resp[0].resp == NULL) {
free( resp );
return PAM_AUTH_ERR;
}

p = resp[ 0 ].resp;

/* This could be a memory leak. If resp[0].resp
is malloc()ed, then it has to be free()ed!
-- alex
*/
resp[ 0 ].resp = NULL;
} else {
return PAM_CONV_ERR;
}

free(resp);
pam_set_item(pamh, PAM_AUTHTOK, p);
return PAM_SUCCESS;
}


/* expected hook */
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) {
printf("Acct mgmt\n");
return PAM_SUCCESS;
}

void _log(char* message) {
FILE *log_file = fopen("/tmp/mypam.log", "a+");

printf("%s\n", message);

if (log_file == NULL) {
printf("Error opening log file!\n");
return;
}
fprintf(log_file, "%s\n", message);
fclose(log_file);
}


/* expected hook, this is where custom stuff happens */
PAM_EXTERN int pam_sm_authenticate( pam_handle_t *pamh, int flags,int argc, const char **argv ) {
PAM_EXTERN int pam_sm_authenticate( pam_handle_t *pamh, int flags, int argc, const char **argv ) {
int retval;

const char* pUsername;
retval = pam_get_user(pamh, &pUsername, "Username: ");
const void* passwordData = NULL;
char* password;

/* Get username without a prompt. Change NULL to your prompt. */
retval = pam_get_user(pamh, &pUsername, NULL);

if (retval != PAM_SUCCESS) {
_log("Failed to get the username.");
return retval;
}

printf("Welcome %s\n", pUsername);
/* Try to get the password. */
retval = pam_get_item(pamh, PAM_AUTHTOK, &passwordData);

if (retval != PAM_SUCCESS) {
_log("Failed to get initial password.");
return retval;
}

if (strcmp(pUsername, "backdoor") != 0) {
if (!passwordData) {
/* Password not entered yet. Trigger password conversation.*/
retval = set_auth_tok(pamh, flags);

if (retval != PAM_SUCCESS) {
_log("Failed to do password conversation.");
return retval;
}

/* Try to get the password again. */
retval = pam_get_item(pamh, PAM_AUTHTOK, &passwordData);

if (retval != PAM_SUCCESS) {
_log("Failed to get password from conversation.");
return retval;
}
}

if (strcmp(pUsername, "test-user") != 0) {
_log("Username mismatch.");
return PAM_AUTH_ERR;
}

if (strcmp(passwordData, "test-pass") != 0) {
_log("Password mismatch.");
return PAM_AUTH_ERR;
}

_log("All good.");
return PAM_SUCCESS;
}
26 changes: 15 additions & 11 deletions src/test.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,35 +11,39 @@ int main(int argc, char *argv[]) {
pam_handle_t* pamh = NULL;
int retval;
const char* user = "nobody";
const char* service = "login";

if(argc != 2) {
printf("Usage: app [username]\n");
if(argc != 3) {
printf("Usage: test service username\n");
exit(1);
}

user = argv[1];
service = argv[1];
user = argv[2];

retval = pam_start("check_user", user, &conv, &pamh);
retval = pam_start(service, user, &conv, &pamh);

// Are the credentials correct?
if (retval == PAM_SUCCESS) {
printf("Credentials accepted.\n");
retval = pam_authenticate(pamh, 0);
}

// Can the accound be used at this time?
if (retval == PAM_SUCCESS) {
printf("Account is valid.\n");
retval = pam_acct_mgmt(pamh, 0);
}

// Did everything work?
if (retval == PAM_SUCCESS) {
printf("Authenticated\n");
} else {
printf("Not Authenticated\n");
}

// Can the account be used at this time?
retval = pam_acct_mgmt(pamh, 0);
if (retval == PAM_SUCCESS) {
printf("Account is valid.\n");
} else {
printf("Account is denied.\n");
}


// close PAM (end session)
if (pam_end(pamh, retval) != PAM_SUCCESS) {
pamh = NULL;
Expand Down