aboutsummaryrefslogtreecommitdiff
path: root/pam_exec.c
diff options
context:
space:
mode:
Diffstat (limited to 'pam_exec.c')
-rw-r--r--pam_exec.c214
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 */