/* pam_exec module */ /* * Written by Guido Guenther * based on pam_warn by Andrew Morgan */ #define _BSD_SOURCE #include #include #include #include #include #include #include #include #include /* * 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 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; char *args=NULL; #define ARGS_MAX 9 char **pass_argv; char **pass_env; pid_t child; pass_argv=calloc(ARGS_MAX, sizeof(char*)); pass_env=calloc(2, sizeof(char*)); for (i = 0; i < argc; i++) { if (!strncmp (argv[i], "exec=", 5)) pass_argv[0] = argv[i] + 5; else if (!strncmp (argv[i], "args=", 5)) args = argv[i] + 5; else if (!strcmp (argv[i], "debug")) debug=1; else _pam_log(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(args) pass_argv[2] = args; } 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((ret=append_arg(pamh, PAM_AUTHTOK, "PASSWD", &pass_env)) != PAM_SUCCESS) { goto out; } 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, pass_env) == -1) { _pam_log(LOG_ERR, "Cannot execve: %s", strerror(errno)); exit(1); } else exit(0); /* we never get here */ } 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: if(!args) i=2; /* don't free argv[0] and function */ else i=3; /* don't free argv[0], function and args */ for(; i < ARGS_MAX; i++) { if(pass_argv[i] != NULL) free(pass_argv[i]); else break; } free(pass_argv); if(pass_env[0]) free(pass_env[0]); free(pass_env); 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 */