2 * Copyright (c) 2006 Thorsten Kukuk <kukuk@thkukuk.de>
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, and the entire permission notice in its entirety,
9 * including the disclaimer of warranties.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. The name of the author may not be used to endorse or promote
14 * products derived from this software without specific prior
17 * ALTERNATIVELY, this product may be distributed under the terms of
18 * the GNU Public License, in which case the provisions of the GPL are
19 * required INSTEAD OF the above restrictions. (This clause is
20 * necessary due to a potential bad interaction between the GPL and
21 * the restrictions contained in a BSD-style copyright.)
23 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
24 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
27 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
28 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
29 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
31 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
33 * OF THE POSSIBILITY OF SUCH DAMAGE.
36 #if defined(HAVE_CONFIG_H)
50 #include <sys/types.h>
54 #define PAM_SM_ACCOUNT
55 #define PAM_SM_SESSION
56 #define PAM_SM_PASSWORD
58 #include <security/pam_modules.h>
59 #include <security/pam_modutil.h>
60 #include <security/pam_ext.h>
62 #define ENV_ITEM(n) { (n), #n }
67 ENV_ITEM(PAM_SERVICE),
75 call_exec (pam_handle_t *pamh, int argc, const char **argv)
81 const char *logfile = NULL;
85 pam_syslog (pamh, LOG_ERR,
86 "This module needs at least one argument");
87 return PAM_SERVICE_ERR;
90 for (optargc = 0; optargc < argc; optargc++)
92 if (argv[optargc][0] == '/') /* paths starts with / */
95 if (strcasecmp (argv[optargc], "debug") == 0)
97 else if (strncasecmp (argv[optargc], "log=", 4) == 0)
98 logfile = &argv[optargc][4];
99 else if (strcasecmp (argv[optargc], "seteuid") == 0)
101 else if (strcasecmp (argv[optargc], "quiet") == 0)
104 break; /* Unknown option, assume program to execute. */
108 if (optargc >= argc) {
109 pam_syslog (pamh, LOG_ERR, "No path given as argument");
110 return PAM_SERVICE_ERR;
115 return PAM_SYSTEM_ERR;
116 if (pid > 0) /* parent */
120 while ((retval = waitpid (pid, &status, 0)) == -1 &&
122 if (retval == (pid_t)-1)
124 pam_syslog (pamh, LOG_ERR, "waitpid returns with -1: %m");
125 return PAM_SYSTEM_ERR;
127 else if (status != 0)
129 if (WIFEXITED(status))
131 pam_syslog (pamh, LOG_ERR, "%s failed: exit code %d",
132 argv[optargc], WEXITSTATUS(status));
134 pam_error (pamh, _("%s failed: exit code %d"),
135 argv[optargc], WEXITSTATUS(status));
137 else if (WIFSIGNALED(status))
139 pam_syslog (pamh, LOG_ERR, "%s failed: caught signal %d%s",
140 argv[optargc], WTERMSIG(status),
141 WCOREDUMP(status) ? " (core dumped)" : "");
143 pam_error (pamh, _("%s failed: caught signal %d%s"),
144 argv[optargc], WTERMSIG(status),
145 WCOREDUMP(status) ? " (core dumped)" : "");
149 pam_syslog (pamh, LOG_ERR, "%s failed: unknown status 0x%x",
150 argv[optargc], status);
152 pam_error (pamh, _("%s failed: unknown status 0x%x"),
153 argv[optargc], status);
155 return PAM_SYSTEM_ERR;
164 for (i = 0; i < sysconf (_SC_OPEN_MAX); i++)
168 if ((i = open ("/dev/null", O_RDWR)) < 0)
171 pam_syslog (pamh, LOG_ERR, "open of /dev/null failed: %m");
174 /* New stdout and stderr. */
177 time_t tm = time (NULL);
180 if ((i = open (logfile, O_CREAT|O_APPEND|O_WRONLY,
181 S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)) == -1)
184 pam_syslog (pamh, LOG_ERR, "open of %s failed: %m",
188 if (asprintf (&buffer, "*** %s", ctime (&tm)) > 0)
190 pam_modutil_write (i, buffer, strlen (buffer));
198 pam_syslog (pamh, LOG_ERR, "dup failed: %m");
204 pam_syslog (pamh, LOG_ERR, "dup failed: %m");
209 if (setuid (geteuid ()) == -1)
212 pam_syslog (pamh, LOG_ERR, "setuid(%lu) failed: %m",
213 (unsigned long) geteuid ());
220 pam_syslog (pamh, LOG_ERR, "setsid failed: %m");
224 arggv = calloc (argc + 4, sizeof (char *));
228 for (i = 0; i < (argc - optargc); i++)
229 arggv[i] = strdup(argv[i+optargc]);
232 char **envlist, **tmp;
236 * Set up the child's environment list. It consists of the PAM
237 * environment, plus a few hand-picked PAM items.
239 envlist = pam_getenvlist(pamh);
240 for (envlen = 0; envlist[envlen] != NULL; ++envlen)
242 nitems = sizeof(env_items) / sizeof(*env_items);
243 tmp = realloc(envlist, (envlen + nitems + 1) * sizeof(*envlist));
247 pam_syslog (pamh, LOG_ERR, "realloc environment failed : %m");
251 for (i = 0; i < nitems; ++i)
256 if (pam_get_item(pamh, env_items[i].item, &item) != PAM_SUCCESS || item == NULL)
258 asprintf(&envstr, "%s=%s", env_items[i].name, (const char *)item);
262 pam_syslog (pamh, LOG_ERR, "prepare environment failed : %m");
265 envlist[envlen++] = envstr;
266 envlist[envlen] = NULL;
270 pam_syslog (pamh, LOG_DEBUG, "Calling %s ...", arggv[0]);
272 if (execve (arggv[0], arggv, envlist) == -1)
275 pam_syslog (pamh, LOG_ERR, "execve(%s,...) failed: %m",
281 exit (1); /* should never be reached. */
283 return PAM_SYSTEM_ERR; /* will never be reached. */
287 pam_sm_authenticate (pam_handle_t *pamh, int flags UNUSED,
288 int argc, const char **argv)
290 return call_exec (pamh, argc, argv);
294 pam_sm_setcred (pam_handle_t *pamh UNUSED, int flags UNUSED,
295 int argc UNUSED, const char **argv UNUSED)
300 /* password updating functions */
303 pam_sm_chauthtok(pam_handle_t *pamh, int flags,
304 int argc, const char **argv)
306 if (flags & PAM_PRELIM_CHECK)
308 return call_exec (pamh, argc, argv);
312 pam_sm_acct_mgmt(pam_handle_t *pamh, int flags UNUSED,
313 int argc, const char **argv)
315 return call_exec (pamh, argc, argv);
319 pam_sm_open_session(pam_handle_t *pamh, int flags UNUSED,
320 int argc, const char **argv)
322 return call_exec (pamh, argc, argv);
326 pam_sm_close_session(pam_handle_t *pamh, int flags UNUSED,
327 int argc, const char **argv)
329 return call_exec (pamh, argc, argv);
333 struct pam_module _pam_exec_modstruct = {
339 pam_sm_close_session,