Last active
January 9, 2020 13:31
-
-
Save sebschrader/be6f599effd50f5e229eab52f0cde9ee to your computer and use it in GitHub Desktop.
PAM module that dumps the internal PAM state. Useful for debugging your own PAM modules without recompiling PAM.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <security/pam_appl.h> | |
#include <security/pam_modules.h> | |
struct handler { | |
int handler_type; | |
int (*func)(pam_handle_t *pamh, int flags, int argc, char **argv); | |
int actions[_PAM_RETURN_VALUES]; | |
/* set by authenticate, open_session, chauthtok(1st) | |
consumed by setcred, close_session, chauthtok(2nd) */ | |
int cached_retval; int *cached_retval_p; | |
int argc; | |
char **argv; | |
struct handler *next; | |
char *mod_name; | |
int stack_level; | |
int grantor; | |
}; | |
#define PAM_HT_MODULE 0 | |
#define PAM_HT_MUST_FAIL 1 | |
#define PAM_HT_SUBSTACK 2 | |
#define PAM_HT_SILENT_MODULE 3 | |
struct loaded_module { | |
char *name; | |
int type; /* PAM_STATIC_MOD or PAM_DYNAMIC_MOD */ | |
void *dl_handle; | |
}; | |
#define PAM_MT_DYNAMIC_MOD 0 | |
#define PAM_MT_STATIC_MOD 1 | |
#define PAM_MT_FAULTY_MOD 2 | |
struct handlers { | |
struct handler *authenticate; | |
struct handler *setcred; | |
struct handler *acct_mgmt; | |
struct handler *open_session; | |
struct handler *close_session; | |
struct handler *chauthtok; | |
}; | |
struct service { | |
struct loaded_module *module; /* Array of modules */ | |
int modules_allocated; | |
int modules_used; | |
int handlers_loaded; | |
struct handlers conf; /* the configured handlers */ | |
struct handlers other; /* the default handlers */ | |
}; | |
struct pam_data { | |
char *name; | |
void *data; | |
void (*cleanup)(pam_handle_t *pamh, void *data, int error_status); | |
struct pam_data *next; | |
}; | |
struct pam_environ { | |
int entries; /* the number of pointers available */ | |
int requested; /* the number of pointers used: * | |
* 1 <= requested <= entries */ | |
char **list; /* the environment storage (a list * | |
* of pointers to malloc() memory) */ | |
}; | |
#include <sys/time.h> | |
typedef enum { PAM_FALSE, PAM_TRUE } _pam_boolean; | |
struct _pam_fail_delay { | |
_pam_boolean set; | |
unsigned int delay; | |
time_t begin; | |
const void *delay_fn_ptr; | |
}; | |
/* initial state in substack */ | |
struct _pam_substack_state { | |
int impression; | |
int status; | |
}; | |
struct _pam_former_state { | |
/* this is known and set by _pam_dispatch() */ | |
int choice; /* which flavor of module function did we call? */ | |
/* state info for the _pam_dispatch_aux() function */ | |
int depth; /* how deep in the stack were we? */ | |
int impression; /* the impression at that time */ | |
int status; /* the status before returning incomplete */ | |
struct _pam_substack_state *substates; /* array of initial substack states */ | |
/* state info used by pam_get_user() function */ | |
int fail_user; | |
int want_user; | |
char *prompt; /* saved prompt information */ | |
/* state info for the pam_chauthtok() function */ | |
_pam_boolean update; | |
}; | |
struct pam_handle { | |
char *authtok; | |
unsigned caller_is; | |
struct pam_conv *pam_conversation; | |
char *oldauthtok; | |
char *prompt; /* for use by pam_get_user() */ | |
char *service_name; | |
char *user; | |
char *rhost; | |
char *ruser; | |
char *tty; | |
char *xdisplay; | |
char *authtok_type; /* PAM_AUTHTOK_TYPE */ | |
struct pam_data *data; | |
struct pam_environ *env; /* structure to maintain environment list */ | |
struct _pam_fail_delay fail_delay; /* helper function for easy delays */ | |
struct pam_xauth_data xauth; /* auth info for X display */ | |
struct service handlers; | |
struct _pam_former_state former; /* library state - support for | |
event driven applications */ | |
const char *mod_name; /* Name of the module currently executed */ | |
int mod_argc; /* Number of module arguments */ | |
char **mod_argv; /* module arguments */ | |
int choice; /* Which function we call from the module */ | |
#ifdef HAVE_LIBAUDIT | |
int audit_state; /* keep track of reported audit messages */ | |
#endif | |
}; | |
__attribute__((constructor)) static void init(void); | |
static FILE *log; | |
static void | |
init(void) | |
{ | |
log = fopen("/tmp/pam.log", "w"); | |
} | |
__attribute__((destructor)) static void fini(void); | |
static void | |
fini(void) | |
{ | |
fclose(log); | |
} | |
static void | |
dump_handler(const char *prefix, struct handler *handler) | |
{ | |
fprintf(log, "%s->handler_type: %d\n", prefix, handler->handler_type); | |
fprintf(log, "%s->func: %p\n", prefix, handler->func); | |
for (size_t i = 0; i < _PAM_RETURN_VALUES; i++) { | |
fprintf(log, "%s->actions[%zu]: %d\n", prefix, i, handler->actions[i]); | |
} | |
fprintf(log, "%s->cached_retval: %d\n", prefix, handler->cached_retval); | |
fprintf(log, "%s->cached_retval_p: %p\n", prefix, handler->cached_retval_p); | |
fprintf(log, "*%s->cached_retval_p: %i\n", prefix, *handler->cached_retval_p); | |
fprintf(log, "%s->argc: %d\n", prefix, handler->argc); | |
for (int i = 0; i < handler->argc; i++) { | |
fprintf(log, "%s->argv[%d]: %s\n", prefix, i, handler->argv[i]); | |
} | |
fprintf(log, "%s->mod_name: %s\n", prefix, handler->mod_name); | |
fprintf(log, "%s->stack_level: %d\n", prefix, handler->stack_level); | |
fprintf(log, "%s->grantor: %d\n", prefix, handler->grantor); | |
} | |
static void | |
dump_handlers(const char *prefix, struct handler *handler) | |
{ | |
char indexed[128] = {0}; | |
size_t prefixlen = strnlen(prefix, sizeof(indexed) - 1); | |
memcpy(indexed, prefix, prefixlen + 1); | |
char *index = indexed + prefixlen; | |
fprintf(log, "%s: %p\n", prefix, handler); | |
for (size_t i = 0; handler != NULL; handler = handler->next, i++) | |
{ | |
snprintf(index, sizeof(indexed) - prefixlen - 1, "[%zu]", i); | |
dump_handler(indexed, handler); | |
} | |
} | |
static void | |
dump_state(const char *prefix, pam_handle_t *pamh) | |
{ | |
char indexed[128] = {0}; | |
size_t prefixlen = strnlen(prefix, sizeof(indexed) - 1); | |
memcpy(indexed, prefix, prefixlen + 1); | |
char *index = indexed + prefixlen; | |
fprintf(log, "%s->authtok: %s\n", indexed, pamh->authtok); | |
fprintf(log, "%s->caller_is: %u\n", indexed, pamh->caller_is); | |
fprintf(log, "%s->pam_conversation: %p\n", indexed, pamh->pam_conversation); | |
fprintf(log, "%s->pam_conversation->conv: %p\n", indexed, pamh->pam_conversation->conv); | |
fprintf(log, "%s->pam_conversation->appdata_ptr: %p\n", indexed, pamh->pam_conversation->appdata_ptr); | |
fprintf(log, "%s->oldauthtok: %s\n", indexed, pamh->oldauthtok); | |
fprintf(log, "%s->prompt: %s\n", indexed, pamh->prompt); | |
fprintf(log, "%s->service_name: %s\n", indexed, pamh->service_name); | |
fprintf(log, "%s->user: %s\n", indexed, pamh->user); | |
fprintf(log, "%s->rhost: %s\n", indexed, pamh->rhost); | |
fprintf(log, "%s->ruser: %s\n", indexed, pamh->ruser); | |
fprintf(log, "%s->tty: %s\n", indexed, pamh->tty); | |
fprintf(log, "%s->xdisplay: %s\n", indexed, pamh->xdisplay); | |
fprintf(log, "%s->authtok_type: %s\n", indexed, pamh->authtok_type); | |
{ | |
size_t i = 0; | |
for (struct pam_data *data = pamh->data; data != NULL; data = data->next, i++) { | |
fprintf(log, "%s->data[%zu]: %p\n", indexed, i, data); | |
fprintf(log, "%s->data[%zu]->name: %s\n", indexed, i, data->name); | |
fprintf(log, "%s->data[%zu]->data: %p\n", indexed, i, data->data); | |
fprintf(log, "%s->data[%zu]->cleanup: %p\n", indexed, i, data->cleanup); | |
} | |
} | |
fprintf(log, "%s->env: %p\n", indexed, pamh->env); | |
fprintf(log, "%s->env->entries: %d\n", indexed, pamh->env->entries); | |
fprintf(log, "%s->env->requested: %d\n", indexed, pamh->env->requested); | |
for (int i = 0; i < pamh->env->requested; i++) | |
{ | |
fprintf(log, "%s->env->list[%d]: %s\n", indexed, i, pamh->env->list[i]); | |
} | |
fprintf(log, "%s->fail_delay.set: %i\n", indexed, pamh->fail_delay.set); | |
fprintf(log, "%s->fail_delay.delay: %u\n", indexed, pamh->fail_delay.delay); | |
fprintf(log, "%s->fail_delay.begin: %ld\n", indexed, pamh->fail_delay.begin); | |
fprintf(log, "%s->fail_delay.delay_fn_ptr: %p\n", indexed, pamh->fail_delay.delay_fn_ptr); | |
fprintf(log, "%s->xauth.namelen: %i\n", indexed, pamh->xauth.namelen); | |
fprintf(log, "%s->xauth.name: %s\n", indexed, pamh->xauth.name); | |
fprintf(log, "%s->xauth.datalen: %i\n", indexed, pamh->xauth.datalen); | |
fprintf(log, "%s->xauth.data: %s\n", indexed, pamh->xauth.data); | |
fprintf(log, "%s->xauth.data: %s\n", indexed, pamh->xauth.data); | |
for (int i = 0; i < pamh->handlers.modules_used; i++) | |
{ | |
fprintf(log, "%s->handlers.module[%d].name: %s\n", indexed, i, pamh->handlers.module[i].name); | |
fprintf(log, "%s->handlers.module[%d].type: %i\n", indexed, i, pamh->handlers.module[i].type); | |
fprintf(log, "%s->handlers.module[%d].dl_handle: %p\n", indexed, i, pamh->handlers.module[i].dl_handle); | |
} | |
fprintf(log, "%s->handlers.modules_allocated: %i\n", indexed, pamh->handlers.modules_allocated); | |
fprintf(log, "%s->handlers.modules_used: %d\n", indexed, pamh->handlers.modules_used); | |
fprintf(log, "%s->handlers.handlers_loaded: %i\n", indexed, pamh->handlers.handlers_loaded); | |
strncpy(index, "->handlers.conf.authenticate", sizeof(indexed) - prefixlen); | |
dump_handlers(indexed, pamh->handlers.conf.authenticate); | |
strncpy(index, "->handlers.conf.setcred", sizeof(indexed) - prefixlen); | |
dump_handlers(indexed, pamh->handlers.conf.authenticate); | |
strncpy(index, "->handlers.conf.acct_mgmt", sizeof(indexed) - prefixlen); | |
dump_handlers(indexed, pamh->handlers.conf.acct_mgmt); | |
strncpy(index, "->handlers.conf.open_session", sizeof(indexed) - prefixlen); | |
dump_handlers(indexed, pamh->handlers.conf.open_session); | |
strncpy(index, "->handlers.conf.close_session", sizeof(indexed) - prefixlen); | |
dump_handlers(indexed, pamh->handlers.conf.close_session); | |
strncpy(index, "->handlers.conf.chauthtok", sizeof(indexed) - prefixlen); | |
dump_handlers(indexed, pamh->handlers.conf.chauthtok); | |
fprintf(log, "%s->former.choice: %i\n", indexed, pamh->former.choice); | |
fprintf(log, "%s->former.depth: %i\n", indexed, pamh->former.depth); | |
fprintf(log, "%s->former.impression: %i\n", indexed, pamh->former.impression); | |
fprintf(log, "%s->former.status: %i\n", indexed, pamh->former.status); | |
for (int i = 0; i < pamh->former.depth; i++) | |
{ | |
fprintf(log, "%s->former.substates[%d].impression: %i\n", indexed, i, pamh->former.substates[i].impression); | |
fprintf(log, "%s->former.substates[%d].status: %i\n", indexed, i, pamh->former.substates[i].status); | |
} | |
fprintf(log, "%s->former.fail_user: %i\n", indexed, pamh->former.fail_user); | |
fprintf(log, "%s->former.want_user: %i\n", indexed, pamh->former.want_user); | |
fprintf(log, "%s->former.prompt: %s\n", indexed, pamh->former.prompt); | |
fprintf(log, "%s->former.update: %i\n", indexed, pamh->former.update); | |
fprintf(log, "%s->mod_name: %s\n", indexed, pamh->mod_name); | |
fprintf(log, "%s->mod_argc: %d\n", indexed, pamh->mod_argc); | |
for (int i = 0; i < pamh->mod_argc; i++) { | |
fprintf(log, "%s->mod_argv[%d]: %s\n", indexed, i, pamh->mod_argv[i]); | |
} | |
fprintf(log, "%s->choice: %i\n", indexed, pamh->choice); | |
#ifdef HAVE_LIBAUDIT | |
fprintf(log, "%s->audit_state: %i\n", indexed, pamh->audit_state); | |
#endif | |
} | |
static const char * | |
get_arg(int argc, const char *argv[], const char *name) | |
{ | |
size_t len = strlen(name); | |
for (int i = 0; i < argc; i++) | |
{ | |
if (strncmp(name, argv[i], len) == 0) { | |
return argv[i] + len; | |
} | |
} | |
return NULL; | |
} | |
PAM_EXTERN int | |
pam_sm_authenticate(pam_handle_t *pamh, int flags,int argc, const char **argv ) | |
{ | |
char prefix[128] = {0}; | |
snprintf(prefix, sizeof(prefix) - 1, "%s %s pamh", __func__, get_arg(argc, argv, "stage=")); | |
dump_state(prefix, pamh); | |
return PAM_IGNORE; | |
} | |
PAM_EXTERN int | |
pam_sm_setcred(pam_handle_t *pamh, int flags, int argc, const char **argv) | |
{ | |
char prefix[128] = {0}; | |
snprintf(prefix, sizeof(prefix) - 1, "%s %s pamh", __func__, get_arg(argc, argv, "stage=")); | |
dump_state(prefix, pamh); | |
return PAM_IGNORE; | |
} | |
PAM_EXTERN int | |
pam_sm_acct_mgmt(pam_handle_t *pamh, int flags, int argc, const char **argv) | |
{ | |
char prefix[128] = {0}; | |
snprintf(prefix, sizeof(prefix) - 1, "%s %s pamh", __func__, get_arg(argc, argv, "stage=")); | |
dump_state(prefix, pamh); | |
return PAM_IGNORE; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment