diff options
author | Thorsten Kukuk <kukuk@thkukuk.de> | 2006-01-24 16:02:11 +0000 |
---|---|---|
committer | Thorsten Kukuk <kukuk@thkukuk.de> | 2006-01-24 16:02:11 +0000 |
commit | c14d282c2a5fefbf7060d05b9d1910b359a1566f (patch) | |
tree | 8f6b2a2f2d2d4ac3462bf95487e9fde2d973e454 /modules | |
parent | fe200c2c6b75da02f6367c1d63d40b2304ed71d4 (diff) | |
download | pam-c14d282c2a5fefbf7060d05b9d1910b359a1566f.tar.gz pam-c14d282c2a5fefbf7060d05b9d1910b359a1566f.tar.bz2 pam-c14d282c2a5fefbf7060d05b9d1910b359a1566f.zip |
CVS: Indicate any relevant BUGIDs here
Relevant BUGIDs:
Purpose of commit: new feature
Commit summary:
---------------
2006-01-24 Thorsten Kukuk <kukuk@thkukuk.de>
* 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.
Diffstat (limited to 'modules')
-rw-r--r-- | modules/Makefile.am | 2 | ||||
-rw-r--r-- | modules/pam_exec/.cvsignore | 6 | ||||
-rw-r--r-- | modules/pam_exec/Makefile.am | 21 | ||||
-rw-r--r-- | modules/pam_exec/README | 29 | ||||
-rw-r--r-- | modules/pam_exec/pam_exec.8 | 79 | ||||
-rw-r--r-- | modules/pam_exec/pam_exec.8.xml | 202 | ||||
-rw-r--r-- | modules/pam_exec/pam_exec.c | 284 |
7 files changed, 622 insertions, 1 deletions
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 <kukuk@suse.de> +# + +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 <prog> <arguments> + + +USAGE: + For the services you wish to run a program put the following + line in the config as the last line for that service: + + <type> 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=<file> the output is appended to this file. + + +AUTHOR: + Thorsten Kukuk <kukuk@thkukuk.de> 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 <kukuk@thkukuk.de>. 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 @@ +<?xml version="1.0" encoding='UTF-8'?> +<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN" + "http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd"> + +<refentry id="pam_exec"> + + <refmeta> + <refentrytitle>pam_exec</refentrytitle> + <manvolnum>8</manvolnum> + <refmiscinfo class="sectdesc">Linux-PAM Manual</refmiscinfo> + </refmeta> + + <refnamediv> + <refname>pam_exec</refname> + <refpurpose>PAM module which calls an external command</refpurpose> + </refnamediv> + + <refsynopsisdiv> + <cmdsynopsis id="pam_exec-cmdsynopsis"> + <command>pam_exec.so</command> + <arg choice="opt"> + debug + </arg> + <arg choice="opt"> + seteuid + </arg> + <arg choice="opt"> + log=<replaceable>file</replaceable> + </arg> + <arg choice="plain"> + <replaceable>command</replaceable> + </arg> + <arg choice="opt"> + <replaceable>...</replaceable> + </arg> + </cmdsynopsis> + </refsynopsisdiv> + + <refsect1 id="pam_exec-description"> + + <title>Description</title> + + <para> + pam_exec is a PAM module that can be used to run + an external command. + </para> + + </refsect1> + + <refsect1 id="pam_exec-options"> + + <title>Options</title> + <para> + <variablelist> + + <varlistentry> + <term> + <option>debug</option> + </term> + <listitem> + <para> + Print debug information. + </para> + </listitem> + </varlistentry> + + <varlistentry> + <term> + <option>log=<replaceable>file</replaceable></option> + </term> + <listitem> + <para> + The output of the command is appended to + <filename>file</filename> + </para> + </listitem> + </varlistentry> + + <varlistentry> + <term> + <option>seteuid</option> + </term> + <listitem> + <para> + 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. + </para> + </listitem> + </varlistentry> + + </variablelist> + + </para> + </refsect1> + + <refsect1 id="pam_exec-services"> + <title>Module Services Provided</title> + <para> + The services <option>auth</option>, <option>account</option>, + <option>password</option> and <option>session</option> are supported. + </para> + </refsect1> + + <refsect1 id='pam_exec-return_values'> + <title>Return Values</title> + <para> + <variablelist> + + <varlistentry> + <term> + <option>PAM_SUCCESS</option> + </term> + <listitem> + <para> + The external command runs successfull. + </para> + </listitem> + </varlistentry> + + <varlistentry> + <term> + <option>PAM_SERVICE_ERR</option> + </term> + <listitem> + <para> + No argument or a wrong number of arguments were given. + </para> + </listitem> + </varlistentry> + + <varlistentry> + <term> + <option>PAM_SYSTEM_ERR</option> + </term> + <listitem> + <para> + A system error occured or the command to execute failed. + </para> + </listitem> + </varlistentry> + + <varlistentry> + <term> + <option>PAM_IGNORE</option> + </term> + <listitem> + <para> + <function>pam_setcred</function> was called, which + does not execute the command. + </para> + </listitem> + </varlistentry> + + </variablelist> + </para> + </refsect1> + + <refsect1 id='pam_exec-examples'> + <title>Examples</title> + <para> + Add the following line to <filename>/etc/pam.d/passwd</filename> to + rebuild the NIS database after each local password change: + <programlisting> + passwd optional pam_exec.so seteuid make -C /var/yp + </programlisting> + + This will execute the command + <programlisting>make -C /var/yp</programlisting> + with effective user ID. + </para> + </refsect1> + + <refsect1 id='pam_exec-see_also'> + <title>See Also</title> + <para> + <citerefentry> + <refentrytitle>pam.conf</refentrytitle> + <manvolnum>5</manvolnum> + </citerefentry>, + <citerefentry> + <refentrytitle>pam.d</refentrytitle> + <manvolnum>8</manvolnum> + </citerefentry>, + <citerefentry> + <refentrytitle>pam</refentrytitle> + <manvolnum>8</manvolnum> + </citerefentry> + </para> + </refsect1> + + <refsect1 id='pam_exec-author'> + <title>Author</title> + <para> + pam_exec was written by Thorsten Kukuk <kukuk@thkukuk.de>. + </para> + </refsect1> + +</refentry> +<!-- vim: sw=2 +--> 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 <kukuk@thkukuk.de> + * + * 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 <time.h> +#include <errno.h> +#include <fcntl.h> +#include <stdio.h> +#include <string.h> +#include <syslog.h> +#include <unistd.h> +#include <stdlib.h> +#include <sys/wait.h> +#include <sys/stat.h> +#include <sys/types.h> + + +#define PAM_SM_AUTH +#define PAM_SM_ACCOUNT +#define PAM_SM_SESSION +#define PAM_SM_PASSWORD + +#include <security/pam_modules.h> +#include <security/pam_modutil.h> +#include <security/pam_ext.h> + +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 |