From c14d282c2a5fefbf7060d05b9d1910b359a1566f Mon Sep 17 00:00:00 2001 From: Thorsten Kukuk Date: Tue, 24 Jan 2006 16:02:11 +0000 Subject: CVS: Indicate any relevant BUGIDs here Relevant BUGIDs: Purpose of commit: new feature Commit summary: --------------- 2006-01-24 Thorsten Kukuk * configure.in: Add modules/pam_exec. * modules/Makefile.am: Add pam_exec subdirectory. * modules/pam_exec/README: New. * modules/pam_exec/Makefile.am: New. * modules/pam_exec/pam_exec.8: New. * modules/pam_exec/pam_exec.c: New. * modules/pam_exec/pam_exec.8.xml: New. * po/POTFILES.in: Add modules/pam_exec/pam_exec.c. * po/*.po: Merge new pam_exec strings. --- modules/Makefile.am | 2 +- modules/pam_exec/.cvsignore | 6 + modules/pam_exec/Makefile.am | 21 +++ modules/pam_exec/README | 29 ++++ modules/pam_exec/pam_exec.8 | 79 +++++++++++ modules/pam_exec/pam_exec.8.xml | 202 ++++++++++++++++++++++++++++ modules/pam_exec/pam_exec.c | 284 ++++++++++++++++++++++++++++++++++++++++ 7 files changed, 622 insertions(+), 1 deletion(-) create mode 100644 modules/pam_exec/.cvsignore create mode 100644 modules/pam_exec/Makefile.am create mode 100644 modules/pam_exec/README create mode 100644 modules/pam_exec/pam_exec.8 create mode 100644 modules/pam_exec/pam_exec.8.xml create mode 100644 modules/pam_exec/pam_exec.c (limited to 'modules') diff --git a/modules/Makefile.am b/modules/Makefile.am index a120a97e..a259d738 100644 --- a/modules/Makefile.am +++ b/modules/Makefile.am @@ -8,7 +8,7 @@ SUBDIRS = pam_access pam_cracklib pam_debug pam_deny pam_echo \ pam_motd pam_nologin pam_permit pam_pwdb pam_rhosts pam_rootok \ pam_securetty pam_selinux pam_shells pam_stress pam_succeed_if \ pam_tally pam_time pam_umask pam_unix pam_userdb pam_warn \ - pam_wheel pam_xauth + pam_wheel pam_xauth pam_exec CLEANFILES = *~ diff --git a/modules/pam_exec/.cvsignore b/modules/pam_exec/.cvsignore new file mode 100644 index 00000000..9fb98574 --- /dev/null +++ b/modules/pam_exec/.cvsignore @@ -0,0 +1,6 @@ +*.la +*.lo +.deps +.libs +Makefile +Makefile.in diff --git a/modules/pam_exec/Makefile.am b/modules/pam_exec/Makefile.am new file mode 100644 index 00000000..8310f3b6 --- /dev/null +++ b/modules/pam_exec/Makefile.am @@ -0,0 +1,21 @@ +# +# Copyright (c) 2006 Thorsten Kukuk +# + +CLEANFILES = *~ + +EXTRA_DIST = README $(MANS) + +man_MANS = pam_exec.8 + +securelibdir = $(SECUREDIR) +secureconfdir = $(SCONFIGDIR) + +AM_CFLAGS = -I$(top_srcdir)/libpam/include -I$(top_srcdir)/libpamc/include +AM_LDFLAGS = -no-undefined -avoid-version -module \ + -L$(top_builddir)/libpam -lpam +if HAVE_VERSIONING + AM_LDFLAGS += -Wl,--version-script=$(srcdir)/../modules.map +endif + +securelib_LTLIBRARIES = pam_exec.la diff --git a/modules/pam_exec/README b/modules/pam_exec/README new file mode 100644 index 00000000..8451ef03 --- /dev/null +++ b/modules/pam_exec/README @@ -0,0 +1,29 @@ + +pam_exec module: + Call + + +USAGE: + For the services you wish to run a program put the following + line in the config as the last line for that service: + + required pam_exec.so [options] /path/prog ... + + and pam_exec.so will run "/path/prog ...". + + +OPTIONS: + + debug print debug informations + + seteuid pam_exec.so will call setuid(seteuid()), so that + the program will run with the same rights as the + calling applications (effective user ID). The + default is that the program will be run with the + permissions of the calling user (real user ID). + + log= the output is appended to this file. + + +AUTHOR: + Thorsten Kukuk diff --git a/modules/pam_exec/pam_exec.8 b/modules/pam_exec/pam_exec.8 new file mode 100644 index 00000000..6ecd2dc9 --- /dev/null +++ b/modules/pam_exec/pam_exec.8 @@ -0,0 +1,79 @@ +.\" ** You probably do not want to edit this file directly ** +.\" It was generated using the DocBook XSL Stylesheets (version 1.69.1). +.\" Instead of manually editing it, you probably should edit the DocBook XML +.\" source for it and then use the DocBook XSL Stylesheets to regenerate it. +.TH "PAM_EXEC" "8" "01/24/2006" "Linux\-PAM Manual" "Linux\-PAM Manual" +.\" disable hyphenation +.nh +.\" disable justification (adjust text to left margin only) +.ad l +.SH "NAME" +pam_exec \- PAM module which calls an external command +.SH "SYNOPSIS" +.HP 12 +\fBpam_exec.so\fR [debug] [seteuid] [log=\fIfile\fR] \fIcommand\fR [\fI...\fR] +.SH "DESCRIPTION" +.PP +pam_exec is a PAM module that can be used to run an external command. +.SH "OPTIONS" +.PP +.TP +\fBdebug\fR +Print debug information. +.TP +\fBlog=\fR\fB\fIfile\fR\fR +The output of the command is appended to +\fIfile\fR +.TP +\fBseteuid\fR +Per default pam_exec.so will execute the external command with the real user ID of the calling process. Specifying this option means the command is run with the effective user ID. +.SH "MODULE SERVICES PROVIDED" +.PP +The services +\fBauth\fR, +\fBaccount\fR, +\fBpassword\fR +and +\fBsession\fR +are supported. +.SH "RETURN VALUES" +.PP +.TP +\fBPAM_SUCCESS\fR +The external command runs successfull. +.TP +\fBPAM_SERVICE_ERR\fR +No argument or a wrong number of arguments were given. +.TP +\fBPAM_SYSTEM_ERR\fR +A system error occured or the command to execute failed. +.TP +\fBPAM_IGNORE\fR +\fBpam_setcred\fR +was called, which does not execute the command. +.SH "EXAMPLES" +.PP +Add the following line to +\fI/etc/pam.d/passwd\fR +to rebuild the NIS database after each local password change: +.sp +.nf + passwd optional pam_exec.so seteuid make \-C /var/yp + +.fi +.sp +This will execute the command +.sp +.nf +make \-C /var/yp +.fi +.sp +with effective user ID. +.SH "SEE ALSO" +.PP +\fBpam.conf\fR(5), +\fBpam.d\fR(8), +\fBpam\fR(8) +.SH "AUTHOR" +.PP +pam_exec was written by Thorsten Kukuk . diff --git a/modules/pam_exec/pam_exec.8.xml b/modules/pam_exec/pam_exec.8.xml new file mode 100644 index 00000000..112f76cd --- /dev/null +++ b/modules/pam_exec/pam_exec.8.xml @@ -0,0 +1,202 @@ + + + + + + + pam_exec + 8 + Linux-PAM Manual + + + + pam_exec + PAM module which calls an external command + + + + + pam_exec.so + + debug + + + seteuid + + + log=file + + + command + + + ... + + + + + + + Description + + + pam_exec is a PAM module that can be used to run + an external command. + + + + + + + Options + + + + + + + + + + Print debug information. + + + + + + + + + + + The output of the command is appended to + file + + + + + + + + + + + Per default pam_exec.so will execute the external command + with the real user ID of the calling process. + Specifying this option means the command is run + with the effective user ID. + + + + + + + + + + + Module Services Provided + + The services , , + and are supported. + + + + + Return Values + + + + + + + + + + The external command runs successfull. + + + + + + + + + + + No argument or a wrong number of arguments were given. + + + + + + + + + + + A system error occured or the command to execute failed. + + + + + + + + + + + pam_setcred was called, which + does not execute the command. + + + + + + + + + + Examples + + Add the following line to /etc/pam.d/passwd to + rebuild the NIS database after each local password change: + + passwd optional pam_exec.so seteuid make -C /var/yp + + + This will execute the command + make -C /var/yp + with effective user ID. + + + + + See Also + + + pam.conf + 5 + , + + pam.d + 8 + , + + pam + 8 + + + + + + Author + + pam_exec was written by Thorsten Kukuk <kukuk@thkukuk.de>. + + + + + diff --git a/modules/pam_exec/pam_exec.c b/modules/pam_exec/pam_exec.c new file mode 100644 index 00000000..7bbaed21 --- /dev/null +++ b/modules/pam_exec/pam_exec.c @@ -0,0 +1,284 @@ +/* + * Copyright (c) 2006 Thorsten Kukuk + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, and the entire permission notice in its entirety, + * including the disclaimer of warranties. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * ALTERNATIVELY, this product may be distributed under the terms of + * the GNU Public License, in which case the provisions of the GPL are + * required INSTEAD OF the above restrictions. (This clause is + * necessary due to a potential bad interaction between the GPL and + * the restrictions contained in a BSD-style copyright.) + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#if defined(HAVE_CONFIG_H) +#include "config.h" +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#define PAM_SM_AUTH +#define PAM_SM_ACCOUNT +#define PAM_SM_SESSION +#define PAM_SM_PASSWORD + +#include +#include +#include + +static int +call_exec (pam_handle_t *pamh, int argc, const char **argv) +{ + int debug = 0; + int call_setuid = 0; + int optargc; + const char *logfile = NULL; + pid_t pid; + + if (argc < 1) { + pam_syslog (pamh, LOG_ERR, + "This module needs at least one argument"); + return PAM_SERVICE_ERR; + } + + for (optargc = 0; optargc < argc; optargc++) + { + if (argv[optargc][0] == '/') /* paths starts with / */ + break; + + if (strcasecmp (argv[optargc], "debug") == 0) + debug = 1; + else if (strncasecmp (argv[optargc], "log=", 4) == 0) + logfile = &argv[optargc][4]; + else if (strcasecmp (argv[optargc], "seteuid") == 0) + call_setuid = 1; + else + break; /* Unknown option, assume program to execute. */ + } + + + if (optargc >= argc) { + pam_syslog (pamh, LOG_ERR, "No path given as argument"); + return PAM_SERVICE_ERR; + } + + pid = fork(); + if (pid == -1) + return PAM_SYSTEM_ERR; + if (pid > 0) /* parent */ + { + int status = 0; + pid_t retval; + while ((retval = waitpid (pid, &status, 0)) == -1 && + errno == EINTR); + if (retval == (pid_t)-1) + { + pam_syslog (pamh, LOG_ERR, "waitpid returns with -1: %m"); + return PAM_SYSTEM_ERR; + } + else if (status != 0) + { + if (WIFEXITED(status)) + { + pam_syslog (pamh, LOG_ERR, "%s failed: exit code %d", + argv[optargc], WEXITSTATUS(status)); + pam_error (pamh, _("%s failed: exit code %d"), + argv[optargc], WEXITSTATUS(status)); + } + else if (WIFSIGNALED(status)) + { + pam_syslog (pamh, LOG_ERR, "%s failed: caught signal %d%s", + argv[optargc], WTERMSIG(status), + WCOREDUMP(status) ? " (core dumped)" : ""); + pam_error (pamh, _("%s failed: caught signal %d%s"), + argv[optargc], WTERMSIG(status), + WCOREDUMP(status) ? " (core dumped)" : ""); + } + else + { + pam_syslog (pamh, LOG_ERR, "%s failed: unknown status 0x%x", + argv[optargc], status); + pam_error (pamh, _("%s failed: unknown status 0x%x"), + argv[optargc], status); + } + return PAM_SYSTEM_ERR; + } + return PAM_SUCCESS; + } + else /* child */ + { + char **arggv; + int i; + + for (i = 0; i < sysconf (_SC_OPEN_MAX); i++) + close (i); + + /* New stdin. */ + if ((i = open ("/dev/null", O_RDWR)) < 0) + { + int err = errno; + pam_syslog (pamh, LOG_ERR, "open of /dev/null failed: %m"); + exit (err); + } + /* New stdout and stderr. */ + if (logfile) + { + time_t tm = time (NULL); + char *buffer = NULL; + + if ((i = open (logfile, O_CREAT|O_APPEND|O_WRONLY)) == -1) + { + int err = errno; + pam_syslog (pamh, LOG_ERR, "open of %s failed: %m", + logfile); + exit (err); + } + if (asprintf (&buffer, "*** %s", ctime (&tm)) > 0) + { + pam_modutil_write (i, buffer, strlen (buffer)); + free (buffer); + } + } + else + if (dup (i) == -1) + { + int err = errno; + pam_syslog (pamh, LOG_ERR, "dup failed: %m"); + exit (err); + } + if (dup (i) == -1) + { + int err = errno; + pam_syslog (pamh, LOG_ERR, "dup failed: %m"); + exit (err); + } + + if (call_setuid) + if (setuid (geteuid ()) == -1) + { + int err = errno; + pam_syslog (pamh, LOG_ERR, "setuid(%d) failed: %m", + geteuid ()); + exit (err); + } + + if (setsid () == -1) + { + int err = errno; + pam_syslog (pamh, LOG_ERR, "setsid failed: %m"); + exit (err); + } + + arggv = calloc (argc + 4, sizeof (char *)); + if (arggv == NULL) + exit (ENOMEM); + + for (i = 0; i < (argc - optargc); i++) + arggv[i] = argv[i+optargc]; + arggv[i] = NULL; + + if (debug) + pam_syslog (pamh, LOG_DEBUG, "Calling %s ...", arggv[0]); + + if (execv (arggv[0], arggv) == -1) + { + int err = errno; + pam_syslog (pamh, LOG_ERR, "execv(%s,...) failed: %m", + arggv[0]); + exit (err); + } + exit (1); /* should never be reached. */ + } + return PAM_SYSTEM_ERR; +} + +PAM_EXTERN int +pam_sm_authenticate (pam_handle_t *pamh, int flags UNUSED, + int argc, const char **argv) +{ + return call_exec (pamh, argc, argv); +} + +PAM_EXTERN int +pam_sm_setcred (pam_handle_t *pamh UNUSED, int flags UNUSED, + int argc UNUSED, const char **argv UNUSED) +{ + return PAM_IGNORE; +} + +/* password updating functions */ + +PAM_EXTERN int +pam_sm_chauthtok(pam_handle_t *pamh, int flags, + int argc, const char **argv) +{ + if (flags & PAM_PRELIM_CHECK) + return PAM_SUCCESS; + return call_exec (pamh, argc, argv); +} + +PAM_EXTERN int +pam_sm_acct_mgmt(pam_handle_t *pamh, int flags UNUSED, + int argc, const char **argv) +{ + return call_exec (pamh, argc, argv); +} + +PAM_EXTERN int +pam_sm_open_session(pam_handle_t *pamh, int flags UNUSED, + int argc, const char **argv) +{ + return call_exec (pamh, argc, argv); +} + +PAM_EXTERN int +pam_sm_close_session(pam_handle_t *pamh, int flags UNUSED, + int argc, const char **argv) +{ + return call_exec (pamh, argc, argv); +} + +#ifdef PAM_STATIC +struct pam_module _pam_exec_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 -- cgit v1.2.3