diff options
Diffstat (limited to 'pam_exec.c')
-rw-r--r-- | pam_exec.c | 214 |
1 files changed, 214 insertions, 0 deletions
diff --git a/pam_exec.c b/pam_exec.c new file mode 100644 index 0000000..6b887a3 --- /dev/null +++ b/pam_exec.c @@ -0,0 +1,214 @@ +/* pam_exec module */ + +/* + * Written by Guido Guenther <agx@sigxcpu.org> + * based on pam_warn by Andrew Morgan <morgan@linux.kernel.org> + */ + +#define _BSD_SOURCE + +#include <stdio.h> +#include <unistd.h> +#include <syslog.h> +#include <stdarg.h> +#include <string.h> +#include <stdlib.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/wait.h> + +/* + * here, we make a definition for the externally accessible function + * in this file (this definition is required for static a module + * but strongly encouraged generally) it is used to instruct the + * modules include file to define the function prototypes. + */ + +#define PAM_SM_AUTH +#define PAM_SM_PASSWORD + +#include <security/pam_modules.h> + + +static void _pam_log(int err, const char *format, ...) +{ + va_list args; + + va_start(args, format); + openlog("PAM-exec", LOG_CONS|LOG_PID, LOG_AUTH); + vsyslog(err, format, args); + va_end(args); + closelog(); +} + + +static int append_arg(pam_handle_t* pamh, int item, char* name, char* (*pargv[])) +{ + const char* value; + int i=0; + int ret; + + if((ret=pam_get_item(pamh, item, (const void **) &value)) != PAM_SUCCESS ) { + return ret; + } + if(value) { + while((*pargv)[i] != NULL) // skip to end of array + i++; + (*pargv)[i] = malloc(strlen(name)+strlen(value)+2); + if((*pargv)[i] == NULL ) { + return PAM_BUF_ERR; + } + sprintf((*pargv)[i], "%s=%s", name, value); + } + return PAM_SUCCESS; +} + + +static int do_exec(pam_handle_t *pamh, const char *function, int argc, const char* argv[]) +{ + int debug=0, ret=PAM_SUCCESS, i; + #define ARGS_MAX 9 + char **pass_argv; + pid_t child; + + pass_argv=calloc(ARGS_MAX, sizeof(char*)); + + for (i = 0; i < argc; i++) { + if (!strncmp (argv[i], "exec=", 5)) + pass_argv[0] = argv[i] + 5; + else if (!strcmp (argv[i], "debug")) + debug=1; + else + syslog (LOG_ERR, "illegal option %s", argv[i]); + } + if(!pass_argv[0]) { + _pam_log(LOG_ERR, "No executable given"); + return PAM_SYSTEM_ERR; + } else { + pass_argv[1] = function; + } + + if((ret=append_arg(pamh, PAM_USER, "user", &pass_argv)) != PAM_SUCCESS) { + goto out; + } + if((ret=append_arg(pamh, PAM_SERVICE, "service", &pass_argv)) != PAM_SUCCESS) { + goto out; + } + if((ret=append_arg(pamh, PAM_TTY, "tty", &pass_argv)) != PAM_SUCCESS) { + goto out; + } +#if 0 /* not good passing this on the commandline, we could put it in the environment */ + if((ret=append_arg(pamh, PAM_AUTHTOK, "passwd", &pass_argv)) != PAM_SUCCESS) { + goto out; + } +#endif + if((ret=append_arg(pamh, PAM_RUSER, "ruser", &pass_argv)) != PAM_SUCCESS) { + goto out; + } + if((ret=append_arg(pamh, PAM_RHOST, "rhost", &pass_argv)) != PAM_SUCCESS) { + goto out; + } + + if(debug) { + for(i=0; i < ARGS_MAX; i++) { + if(pass_argv[i] == NULL) + break; + _pam_log(LOG_DEBUG, "arg%d: %s", i, pass_argv[i]); + } + } + + if((child = fork()) == -1) { + _pam_log(LOG_ERR, "Cannot fork: %s", strerror(errno)); + ret=PAM_SYSTEM_ERR; + goto out; + } else { + if(!child) { + if(execve(pass_argv[0], pass_argv, NULL) == -1) + _pam_log(LOG_ERR, "Cannot execve: %s", strerror(errno)); + exit(1); + } else { + int status; + if(debug) + _pam_log(LOG_DEBUG, "Waiting for child: %d", child); + if(waitpid(child, &status, 0) != child) { + _pam_log(LOG_ERR, "Waitpid problem: %s", strerror(errno)); + } else { + _pam_log(LOG_DEBUG, "Child returnd with %d", WEXITSTATUS(status)); + } + + } + } +out: + for(i=2; i < ARGS_MAX; i++) { /* don't free argv[0] and function */ + if(pass_argv[i] != NULL) + free(pass_argv[i]); + else + break; + } + free(pass_argv); + + if(ret == PAM_SUCCESS) + ret=PAM_IGNORE; + return ret; +} + +/* --- authentication management functions (only) --- */ + +PAM_EXTERN +int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, + const char **argv) +{ + return do_exec(pamh, __FUNCTION__, argc, argv); +} + +PAM_EXTERN +int pam_sm_setcred(pam_handle_t *pamh, int flags, int argc, const char **argv) +{ + return do_exec(pamh, __FUNCTION__, argc, argv); +} + +/* password updating functions */ + +PAM_EXTERN +int pam_sm_chauthtok(pam_handle_t *pamh,int flags,int argc,const char **argv) +{ + return do_exec(pamh, __FUNCTION__, argc, argv); +} + +PAM_EXTERN int +pam_sm_acct_mgmt (pam_handle_t *pamh, int flags, int argc, const char **argv) +{ + return do_exec(pamh, __FUNCTION__, argc, argv); +} + +PAM_EXTERN int +pam_sm_open_session (pam_handle_t *pamh, int flags, int argc, + const char **argv) +{ + return do_exec(pamh, __FUNCTION__, argc, argv); +} + +PAM_EXTERN int +pam_sm_close_session (pam_handle_t *pamh, int flags, int argc, + const char **argv) +{ + return do_exec(pamh, __FUNCTION__, argc, argv); +} + +#ifdef PAM_STATIC + +/* static module data */ + +struct pam_module _pam_warn_modstruct = { + "pam_exec", + pam_sm_authenticate, + pam_sm_setcred, + pam_sm_acct_mgmt, + pam_sm_open_session, + pam_sm_close_session, + pam_sm_chauthtok, +}; + +#endif + +/* end of module definition */ |