2 * Copyright (c) 2006, 2008 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>
61 #include <security/_pam_macros.h>
63 #define ENV_ITEM(n) { (n), #n }
68 ENV_ITEM(PAM_SERVICE),
77 call_exec (const char *pam_type, pam_handle_t *pamh,
78 int argc, const char **argv)
83 int expose_authtok = 0;
85 const char *logfile = NULL;
86 const char *authtok = NULL;
91 pam_syslog (pamh, LOG_ERR,
92 "This module needs at least one argument");
93 return PAM_SERVICE_ERR;
96 for (optargc = 0; optargc < argc; optargc++)
98 if (argv[optargc][0] == '/') /* paths starts with / */
101 if (strcasecmp (argv[optargc], "debug") == 0)
103 else if (strncasecmp (argv[optargc], "log=", 4) == 0)
104 logfile = &argv[optargc][4];
105 else if (strcasecmp (argv[optargc], "seteuid") == 0)
107 else if (strcasecmp (argv[optargc], "quiet") == 0)
109 else if (strcasecmp (argv[optargc], "expose_authtok") == 0)
112 break; /* Unknown option, assume program to execute. */
115 if (expose_authtok == 1)
117 if (strcmp (pam_type, "auth") != 0)
119 pam_syslog (pamh, LOG_ERR,
120 "expose_authtok not supported for type %s", pam_type);
125 const void *void_pass;
128 retval = pam_get_item (pamh, PAM_AUTHTOK, &void_pass);
129 if (retval != PAM_SUCCESS)
132 pam_syslog (pamh, LOG_DEBUG,
133 "pam_get_item (PAM_AUTHTOK) failed, return %d",
137 else if (void_pass == NULL)
141 retval = pam_prompt (pamh, PAM_PROMPT_ECHO_OFF,
142 &resp, _("Password: "));
144 if (retval != PAM_SUCCESS)
147 if (retval == PAM_CONV_AGAIN)
148 retval = PAM_INCOMPLETE;
152 pam_set_item (pamh, PAM_AUTHTOK, resp);
153 authtok = strdupa (resp);
161 pam_syslog (pamh, LOG_ERR, "Could not create pipe: %m");
162 return PAM_SYSTEM_ERR;
167 if (optargc >= argc) {
168 pam_syslog (pamh, LOG_ERR, "No path given as argument");
169 return PAM_SERVICE_ERR;
174 return PAM_SYSTEM_ERR;
175 if (pid > 0) /* parent */
180 if (expose_authtok) /* send the password to the child */
183 { /* send the password to the child */
185 pam_syslog (pamh, LOG_DEBUG, "send password to child");
186 if (write(fds[1], authtok, strlen(authtok)+1) == -1)
187 pam_syslog (pamh, LOG_ERR,
188 "sending password to child failed: %m");
193 if (write(fds[1], "", 1) == -1) /* blank password */
194 pam_syslog (pamh, LOG_ERR,
195 "sending password to child failed: %m");
197 close(fds[0]); /* close here to avoid possible SIGPIPE above */
201 while ((retval = waitpid (pid, &status, 0)) == -1 &&
203 if (retval == (pid_t)-1)
205 pam_syslog (pamh, LOG_ERR, "waitpid returns with -1: %m");
206 return PAM_SYSTEM_ERR;
208 else if (status != 0)
210 if (WIFEXITED(status))
212 pam_syslog (pamh, LOG_ERR, "%s failed: exit code %d",
213 argv[optargc], WEXITSTATUS(status));
215 pam_error (pamh, _("%s failed: exit code %d"),
216 argv[optargc], WEXITSTATUS(status));
218 else if (WIFSIGNALED(status))
220 pam_syslog (pamh, LOG_ERR, "%s failed: caught signal %d%s",
221 argv[optargc], WTERMSIG(status),
222 WCOREDUMP(status) ? " (core dumped)" : "");
224 pam_error (pamh, _("%s failed: caught signal %d%s"),
225 argv[optargc], WTERMSIG(status),
226 WCOREDUMP(status) ? " (core dumped)" : "");
230 pam_syslog (pamh, LOG_ERR, "%s failed: unknown status 0x%x",
231 argv[optargc], status);
233 pam_error (pamh, _("%s failed: unknown status 0x%x"),
234 argv[optargc], status);
236 return PAM_SYSTEM_ERR;
244 char **envlist, **tmp;
250 /* reopen stdin as pipe */
251 if (dup2(fds[0], STDIN_FILENO) == -1)
254 pam_syslog (pamh, LOG_ERR, "dup2 of STDIN failed: %m");
258 for (i = 0; i < sysconf (_SC_OPEN_MAX); i++)
260 if (i != STDIN_FILENO)
266 for (i = 0; i < sysconf (_SC_OPEN_MAX); i++)
270 if ((i = open ("/dev/null", O_RDWR)) < 0)
273 pam_syslog (pamh, LOG_ERR, "open of /dev/null failed: %m");
278 /* New stdout and stderr. */
281 time_t tm = time (NULL);
284 if ((i = open (logfile, O_CREAT|O_APPEND|O_WRONLY,
285 S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)) == -1)
288 pam_syslog (pamh, LOG_ERR, "open of %s failed: %m",
292 if (asprintf (&buffer, "*** %s", ctime (&tm)) > 0)
294 pam_modutil_write (i, buffer, strlen (buffer));
300 /* New stdout/stderr. */
301 if ((i = open ("/dev/null", O_RDWR)) < 0)
304 pam_syslog (pamh, LOG_ERR, "open of /dev/null failed: %m");
312 pam_syslog (pamh, LOG_ERR, "dup failed: %m");
317 if (setuid (geteuid ()) == -1)
320 pam_syslog (pamh, LOG_ERR, "setuid(%lu) failed: %m",
321 (unsigned long) geteuid ());
328 pam_syslog (pamh, LOG_ERR, "setsid failed: %m");
332 arggv = calloc (argc + 4, sizeof (char *));
336 for (i = 0; i < (argc - optargc); i++)
337 arggv[i] = strdup(argv[i+optargc]);
341 * Set up the child's environment list. It consists of the PAM
342 * environment, plus a few hand-picked PAM items.
344 envlist = pam_getenvlist(pamh);
345 for (envlen = 0; envlist[envlen] != NULL; ++envlen)
347 nitems = sizeof(env_items) / sizeof(*env_items);
348 /* + 2 because of PAM_TYPE and NULL entry */
349 tmp = realloc(envlist, (envlen + nitems + 2) * sizeof(*envlist));
353 pam_syslog (pamh, LOG_ERR, "realloc environment failed: %m");
357 for (i = 0; i < nitems; ++i)
361 if (pam_get_item(pamh, env_items[i].item, &item) != PAM_SUCCESS || item == NULL)
363 if (asprintf(&envstr, "%s=%s", env_items[i].name, (const char *)item) < 0)
366 pam_syslog (pamh, LOG_ERR, "prepare environment failed: %m");
369 envlist[envlen++] = envstr;
370 envlist[envlen] = NULL;
373 if (asprintf(&envstr, "PAM_TYPE=%s", pam_type) < 0)
376 pam_syslog (pamh, LOG_ERR, "prepare environment failed: %m");
379 envlist[envlen++] = envstr;
380 envlist[envlen] = NULL;
383 pam_syslog (pamh, LOG_DEBUG, "Calling %s ...", arggv[0]);
385 execve (arggv[0], arggv, envlist);
387 pam_syslog (pamh, LOG_ERR, "execve(%s,...) failed: %m", arggv[0]);
391 return PAM_SYSTEM_ERR; /* will never be reached. */
395 pam_sm_authenticate (pam_handle_t *pamh, int flags UNUSED,
396 int argc, const char **argv)
398 return call_exec ("auth", pamh, argc, argv);
402 pam_sm_setcred (pam_handle_t *pamh UNUSED, int flags UNUSED,
403 int argc UNUSED, const char **argv UNUSED)
408 /* password updating functions */
411 pam_sm_chauthtok(pam_handle_t *pamh, int flags,
412 int argc, const char **argv)
414 if (flags & PAM_PRELIM_CHECK)
416 return call_exec ("password", pamh, argc, argv);
420 pam_sm_acct_mgmt(pam_handle_t *pamh, int flags UNUSED,
421 int argc, const char **argv)
423 return call_exec ("account", pamh, argc, argv);
427 pam_sm_open_session(pam_handle_t *pamh, int flags UNUSED,
428 int argc, const char **argv)
430 return call_exec ("open_session", pamh, argc, argv);
434 pam_sm_close_session(pam_handle_t *pamh, int flags UNUSED,
435 int argc, const char **argv)
437 return call_exec ("close_session", pamh, argc, argv);
441 struct pam_module _pam_exec_modstruct = {
447 pam_sm_close_session,