]> git.armaanb.net Git - opendoas.git/commitdiff
rename doas_pam.c to pam.c
authorDuncaen <mail@duncano.de>
Fri, 24 Jun 2016 14:50:17 +0000 (16:50 +0200)
committerDuncaen <mail@duncano.de>
Fri, 24 Jun 2016 14:55:50 +0000 (16:55 +0200)
configure
doas_pam.c [deleted file]
pam.c [new file with mode: 0644]

index c5981a58b295a2aecae4482f0fb31c93584176bd..1bb827fc8e11cd5f2ef713f5ad152c9ecb10b4d4 100755 (executable)
--- a/configure
+++ b/configure
@@ -284,7 +284,7 @@ int main(void) {
 }'
 [ -z "$have_bsd_auth_h" ] && \
        check_func "pam_appl_h" "$src" && {
-               printf 'SRCS     +=     doas_pam.c\n' >>$CONFIG_MK
+               printf 'SRCS     +=     pam.c\n' >>$CONFIG_MK
                printf 'LDFLAGS  +=     -lpam\n' >>$CONFIG_MK
        }
 
diff --git a/doas_pam.c b/doas_pam.c
deleted file mode 100644 (file)
index 4f2731d..0000000
+++ /dev/null
@@ -1,289 +0,0 @@
-/*
- * Copyright (c) 2015 Nathan Holstein <nathan.holstein@gmail.com>
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <sys/types.h>
-#include <err.h>
-#include <errno.h>
-#include <pwd.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <sys/wait.h>
-#include <signal.h>
-#ifdef __linux__
-#include <limits.h>
-#endif
-
-#include <security/pam_appl.h>
-
-#include "doas.h"
-#include "includes.h"
-
-#define PAM_SERVICE_NAME "doas"
-
-static pam_handle_t *pamh = NULL;
-static sig_atomic_t volatile caught_signal = 0;
-static char doas_prompt[128];
-
-static void
-catchsig(int sig)
-{
-       caught_signal = sig;
-}
-
-static char *
-prompt(const char *msg, int echo_on, int *pam)
-{
-       const char *prompt;
-       char *ret, buf[PAM_MAX_RESP_SIZE];
-       int flags = RPP_REQUIRE_TTY | (echo_on ? RPP_ECHO_ON : RPP_ECHO_OFF);
-
-       /* overwrite default prompt if it matches "Password:[ ]" */
-       if (strncmp(msg,"Password:", 9) == 0 &&
-           (msg[9] == '\0' || (msg[9] == ' ' && msg[10] == '\0')))
-               prompt = doas_prompt;
-       else
-               prompt = msg;
-
-       ret = readpassphrase(prompt, buf, sizeof(buf), flags);
-       if (!ret)
-               *pam = PAM_CONV_ERR;
-       else if (!(ret = strdup(ret)))
-               *pam = PAM_BUF_ERR;
-
-       explicit_bzero(buf, sizeof(buf));
-       return ret;
-}
-
-static int
-doas_pam_conv(int nmsgs, const struct pam_message **msgs,
-               struct pam_response **rsps, __UNUSED void *ptr)
-{
-       struct pam_response *rsp;
-       int i, style;
-       int ret = PAM_SUCCESS;
-
-       if (!(rsp = calloc(nmsgs, sizeof(struct pam_response))))
-               errx(1, "couldn't malloc pam_response");
-
-       for (i = 0; i < nmsgs; i++) {
-               switch (style = msgs[i]->msg_style) {
-               case PAM_PROMPT_ECHO_OFF:
-               case PAM_PROMPT_ECHO_ON:
-                       rsp[i].resp = prompt(msgs[i]->msg, style == PAM_PROMPT_ECHO_ON, &ret);
-                       if (ret != PAM_SUCCESS)
-                               goto fail;
-                       break;
-
-               case PAM_ERROR_MSG:
-               case PAM_TEXT_INFO:
-                       if (fprintf(style == PAM_ERROR_MSG ? stderr : stdout,
-                           "%s\n", msgs[i]->msg) < 0)
-                               goto fail;
-                       break;
-
-               default:
-                       errx(1, "invalid PAM msg_style %d", style);
-               }
-       }
-
-       *rsps = rsp;
-       rsp = NULL;
-
-       return PAM_SUCCESS;
-
-fail:
-       /* overwrite and free response buffers */
-       for (i = 0; i < nmsgs; i++) {
-               if (rsp[i].resp == NULL)
-                       continue;
-               switch (style = msgs[i]->msg_style) {
-               case PAM_PROMPT_ECHO_OFF:
-               case PAM_PROMPT_ECHO_ON:
-                       explicit_bzero(rsp[i].resp, strlen(rsp[i].resp));
-                       free(rsp[i].resp);
-               }
-               rsp[i].resp = NULL;
-       }
-
-       return PAM_CONV_ERR;
-}
-
-int
-doas_pam(const char *user, const char* ruser, int interactive, int nopass)
-{
-       static const struct pam_conv conv = {
-               .conv = doas_pam_conv,
-               .appdata_ptr = NULL,
-       };
-       const char *ttydev, *tty;
-       pid_t child;
-       int ret;
-
-       if (!user || !ruser)
-               return 0;
-
-       /* pam needs the real root */
-       if(setuid(0))
-               errx(1, "setuid");
-
-       ret = pam_start(PAM_SERVICE_NAME, ruser, &conv, &pamh);
-       if (ret != PAM_SUCCESS)
-               errx(1, "pam_start(\"%s\", \"%s\", ?, ?): failed\n",
-                   PAM_SERVICE_NAME, ruser);
-
-       ret = pam_set_item(pamh, PAM_RUSER, ruser);
-       if (ret != PAM_SUCCESS)
-               warn("pam_set_item(?, PAM_RUSER, \"%s\"): %s\n",
-                   pam_strerror(pamh, ret), ruser);
-
-       if (isatty(0) && (ttydev = ttyname(0)) != NULL) {
-               if (strncmp(ttydev, "/dev/", 5))
-                       tty = ttydev + 5;
-               else
-                       tty = ttydev;
-
-               ret = pam_set_item(pamh, PAM_TTY, tty);
-               if (ret != PAM_SUCCESS)
-                       warn("pam_set_item(?, PAM_TTY, \"%s\"): %s\n",
-                           tty, pam_strerror(pamh, ret));
-       }
-
-       if (!nopass) {
-               if (!interactive)
-                       errx(1, "Authorization required");
-
-               /* doas style prompt for pam */
-               char host[HOST_NAME_MAX + 1];
-               if (gethostname(host, sizeof(host)))
-                       snprintf(host, sizeof(host), "?");
-               snprintf(doas_prompt, sizeof(doas_prompt),
-                   "\rdoas (%.32s@%.32s) password: ", ruser, host);
-
-               /* authenticate */
-               ret = pam_authenticate(pamh, 0);
-               if (ret != PAM_SUCCESS) {
-                       pam_end(pamh, ret);
-                       return 0;
-               }
-       }
-
-       ret = pam_acct_mgmt(pamh, 0);
-       if (ret == PAM_NEW_AUTHTOK_REQD)
-               ret = pam_chauthtok(pamh, PAM_CHANGE_EXPIRED_AUTHTOK);
-
-       /* account not vaild or changing the auth token failed */
-       if (ret != PAM_SUCCESS)
-               return 0;
-
-       ret = pam_set_item(pamh, PAM_USER, user);
-       if (ret != PAM_SUCCESS)
-               warn("pam_set_item(?, PAM_USER, \"%s\"): %s\n", user,
-                   pam_strerror(pamh, ret));
-
-       ret = pam_setcred(pamh, PAM_ESTABLISH_CRED);
-       if (ret != PAM_SUCCESS)
-               warn("pam_setcred(?, PAM_ESTABLISH_CRED): %s\n", pam_strerror(pamh, ret));
-
-       /* open session */
-       ret = pam_open_session(pamh, 0);
-       if (ret != PAM_SUCCESS)
-               errx(1, "pam_open_session(): %s\n", pam_strerror(pamh, ret));
-
-       if ((child = fork()) == -1) {
-               pam_close_session(pamh, 0);
-               pam_end(pamh, PAM_ABORT);
-               errx(1, "fork()");
-       }
-
-       /* return as child */
-       if (child == 0) {
-               return 1;
-       }
-
-       /* parent watches for signals and closes session */
-       sigset_t sigs;
-       struct sigaction act, oldact;
-       int status;
-
-       /* block signals */
-       sigfillset(&sigs);
-       if (sigprocmask(SIG_BLOCK, &sigs, NULL)) {
-               warn("failed to block signals");
-               caught_signal = 1;
-       }
-
-       /* setup signal handler */
-       act.sa_handler = catchsig;
-       sigemptyset(&act.sa_mask);
-       act.sa_flags = 0;
-
-       /* unblock SIGTERM and SIGALRM to catch them */
-       sigemptyset(&sigs);
-       if (sigaddset(&sigs, SIGTERM) ||
-           sigaddset(&sigs, SIGALRM) ||
-           sigaction(SIGTERM, &act, &oldact) ||
-           sigprocmask(SIG_UNBLOCK, &sigs, NULL)) {
-               warn("failed to set signal handler");
-               caught_signal = 1;
-       }
-
-       if (!caught_signal) {
-               /* wait for child to be terminated */
-               if (waitpid(child, &status, 0) != -1) {
-                       if (WIFSIGNALED(status)) {
-                               fprintf(stderr, "%s%s\n", strsignal(WTERMSIG(status)),
-                                   WCOREDUMP(status) ? " (core dumped)" : "");
-                               status = WTERMSIG(status) + 128;
-                       } else {
-                               status = WEXITSTATUS(status);
-                       }
-               }
-               else if (caught_signal)
-                       status = caught_signal + 128;
-               else
-                       status = 1;
-       }
-
-       if (caught_signal) {
-               fprintf(stderr, "\nSession terminated, killing shell\n");
-               kill(child, SIGTERM);
-       }
-
-       /* close session */
-       ret = pam_close_session(pamh, 0);
-       if (ret != PAM_SUCCESS)
-               errx(1, "pam_close_session(): %s\n", pam_strerror(pamh, ret));
-
-       pam_end(pamh, PAM_SUCCESS);
-
-       if (caught_signal) {
-               /* kill child */
-               sleep(2);
-               kill(child, SIGKILL);
-               fprintf(stderr, " ...killed.\n");
-
-               /* unblock cached signal and resend */
-               sigaction(SIGTERM, &oldact, NULL);
-               if (caught_signal != SIGTERM)
-                       caught_signal = SIGKILL;
-               kill(getpid(), caught_signal);
-       }
-
-       exit(status);
-       return 0;
-}
diff --git a/pam.c b/pam.c
new file mode 100644 (file)
index 0000000..4f2731d
--- /dev/null
+++ b/pam.c
@@ -0,0 +1,289 @@
+/*
+ * Copyright (c) 2015 Nathan Holstein <nathan.holstein@gmail.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+#include <err.h>
+#include <errno.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/wait.h>
+#include <signal.h>
+#ifdef __linux__
+#include <limits.h>
+#endif
+
+#include <security/pam_appl.h>
+
+#include "doas.h"
+#include "includes.h"
+
+#define PAM_SERVICE_NAME "doas"
+
+static pam_handle_t *pamh = NULL;
+static sig_atomic_t volatile caught_signal = 0;
+static char doas_prompt[128];
+
+static void
+catchsig(int sig)
+{
+       caught_signal = sig;
+}
+
+static char *
+prompt(const char *msg, int echo_on, int *pam)
+{
+       const char *prompt;
+       char *ret, buf[PAM_MAX_RESP_SIZE];
+       int flags = RPP_REQUIRE_TTY | (echo_on ? RPP_ECHO_ON : RPP_ECHO_OFF);
+
+       /* overwrite default prompt if it matches "Password:[ ]" */
+       if (strncmp(msg,"Password:", 9) == 0 &&
+           (msg[9] == '\0' || (msg[9] == ' ' && msg[10] == '\0')))
+               prompt = doas_prompt;
+       else
+               prompt = msg;
+
+       ret = readpassphrase(prompt, buf, sizeof(buf), flags);
+       if (!ret)
+               *pam = PAM_CONV_ERR;
+       else if (!(ret = strdup(ret)))
+               *pam = PAM_BUF_ERR;
+
+       explicit_bzero(buf, sizeof(buf));
+       return ret;
+}
+
+static int
+doas_pam_conv(int nmsgs, const struct pam_message **msgs,
+               struct pam_response **rsps, __UNUSED void *ptr)
+{
+       struct pam_response *rsp;
+       int i, style;
+       int ret = PAM_SUCCESS;
+
+       if (!(rsp = calloc(nmsgs, sizeof(struct pam_response))))
+               errx(1, "couldn't malloc pam_response");
+
+       for (i = 0; i < nmsgs; i++) {
+               switch (style = msgs[i]->msg_style) {
+               case PAM_PROMPT_ECHO_OFF:
+               case PAM_PROMPT_ECHO_ON:
+                       rsp[i].resp = prompt(msgs[i]->msg, style == PAM_PROMPT_ECHO_ON, &ret);
+                       if (ret != PAM_SUCCESS)
+                               goto fail;
+                       break;
+
+               case PAM_ERROR_MSG:
+               case PAM_TEXT_INFO:
+                       if (fprintf(style == PAM_ERROR_MSG ? stderr : stdout,
+                           "%s\n", msgs[i]->msg) < 0)
+                               goto fail;
+                       break;
+
+               default:
+                       errx(1, "invalid PAM msg_style %d", style);
+               }
+       }
+
+       *rsps = rsp;
+       rsp = NULL;
+
+       return PAM_SUCCESS;
+
+fail:
+       /* overwrite and free response buffers */
+       for (i = 0; i < nmsgs; i++) {
+               if (rsp[i].resp == NULL)
+                       continue;
+               switch (style = msgs[i]->msg_style) {
+               case PAM_PROMPT_ECHO_OFF:
+               case PAM_PROMPT_ECHO_ON:
+                       explicit_bzero(rsp[i].resp, strlen(rsp[i].resp));
+                       free(rsp[i].resp);
+               }
+               rsp[i].resp = NULL;
+       }
+
+       return PAM_CONV_ERR;
+}
+
+int
+doas_pam(const char *user, const char* ruser, int interactive, int nopass)
+{
+       static const struct pam_conv conv = {
+               .conv = doas_pam_conv,
+               .appdata_ptr = NULL,
+       };
+       const char *ttydev, *tty;
+       pid_t child;
+       int ret;
+
+       if (!user || !ruser)
+               return 0;
+
+       /* pam needs the real root */
+       if(setuid(0))
+               errx(1, "setuid");
+
+       ret = pam_start(PAM_SERVICE_NAME, ruser, &conv, &pamh);
+       if (ret != PAM_SUCCESS)
+               errx(1, "pam_start(\"%s\", \"%s\", ?, ?): failed\n",
+                   PAM_SERVICE_NAME, ruser);
+
+       ret = pam_set_item(pamh, PAM_RUSER, ruser);
+       if (ret != PAM_SUCCESS)
+               warn("pam_set_item(?, PAM_RUSER, \"%s\"): %s\n",
+                   pam_strerror(pamh, ret), ruser);
+
+       if (isatty(0) && (ttydev = ttyname(0)) != NULL) {
+               if (strncmp(ttydev, "/dev/", 5))
+                       tty = ttydev + 5;
+               else
+                       tty = ttydev;
+
+               ret = pam_set_item(pamh, PAM_TTY, tty);
+               if (ret != PAM_SUCCESS)
+                       warn("pam_set_item(?, PAM_TTY, \"%s\"): %s\n",
+                           tty, pam_strerror(pamh, ret));
+       }
+
+       if (!nopass) {
+               if (!interactive)
+                       errx(1, "Authorization required");
+
+               /* doas style prompt for pam */
+               char host[HOST_NAME_MAX + 1];
+               if (gethostname(host, sizeof(host)))
+                       snprintf(host, sizeof(host), "?");
+               snprintf(doas_prompt, sizeof(doas_prompt),
+                   "\rdoas (%.32s@%.32s) password: ", ruser, host);
+
+               /* authenticate */
+               ret = pam_authenticate(pamh, 0);
+               if (ret != PAM_SUCCESS) {
+                       pam_end(pamh, ret);
+                       return 0;
+               }
+       }
+
+       ret = pam_acct_mgmt(pamh, 0);
+       if (ret == PAM_NEW_AUTHTOK_REQD)
+               ret = pam_chauthtok(pamh, PAM_CHANGE_EXPIRED_AUTHTOK);
+
+       /* account not vaild or changing the auth token failed */
+       if (ret != PAM_SUCCESS)
+               return 0;
+
+       ret = pam_set_item(pamh, PAM_USER, user);
+       if (ret != PAM_SUCCESS)
+               warn("pam_set_item(?, PAM_USER, \"%s\"): %s\n", user,
+                   pam_strerror(pamh, ret));
+
+       ret = pam_setcred(pamh, PAM_ESTABLISH_CRED);
+       if (ret != PAM_SUCCESS)
+               warn("pam_setcred(?, PAM_ESTABLISH_CRED): %s\n", pam_strerror(pamh, ret));
+
+       /* open session */
+       ret = pam_open_session(pamh, 0);
+       if (ret != PAM_SUCCESS)
+               errx(1, "pam_open_session(): %s\n", pam_strerror(pamh, ret));
+
+       if ((child = fork()) == -1) {
+               pam_close_session(pamh, 0);
+               pam_end(pamh, PAM_ABORT);
+               errx(1, "fork()");
+       }
+
+       /* return as child */
+       if (child == 0) {
+               return 1;
+       }
+
+       /* parent watches for signals and closes session */
+       sigset_t sigs;
+       struct sigaction act, oldact;
+       int status;
+
+       /* block signals */
+       sigfillset(&sigs);
+       if (sigprocmask(SIG_BLOCK, &sigs, NULL)) {
+               warn("failed to block signals");
+               caught_signal = 1;
+       }
+
+       /* setup signal handler */
+       act.sa_handler = catchsig;
+       sigemptyset(&act.sa_mask);
+       act.sa_flags = 0;
+
+       /* unblock SIGTERM and SIGALRM to catch them */
+       sigemptyset(&sigs);
+       if (sigaddset(&sigs, SIGTERM) ||
+           sigaddset(&sigs, SIGALRM) ||
+           sigaction(SIGTERM, &act, &oldact) ||
+           sigprocmask(SIG_UNBLOCK, &sigs, NULL)) {
+               warn("failed to set signal handler");
+               caught_signal = 1;
+       }
+
+       if (!caught_signal) {
+               /* wait for child to be terminated */
+               if (waitpid(child, &status, 0) != -1) {
+                       if (WIFSIGNALED(status)) {
+                               fprintf(stderr, "%s%s\n", strsignal(WTERMSIG(status)),
+                                   WCOREDUMP(status) ? " (core dumped)" : "");
+                               status = WTERMSIG(status) + 128;
+                       } else {
+                               status = WEXITSTATUS(status);
+                       }
+               }
+               else if (caught_signal)
+                       status = caught_signal + 128;
+               else
+                       status = 1;
+       }
+
+       if (caught_signal) {
+               fprintf(stderr, "\nSession terminated, killing shell\n");
+               kill(child, SIGTERM);
+       }
+
+       /* close session */
+       ret = pam_close_session(pamh, 0);
+       if (ret != PAM_SUCCESS)
+               errx(1, "pam_close_session(): %s\n", pam_strerror(pamh, ret));
+
+       pam_end(pamh, PAM_SUCCESS);
+
+       if (caught_signal) {
+               /* kill child */
+               sleep(2);
+               kill(child, SIGKILL);
+               fprintf(stderr, " ...killed.\n");
+
+               /* unblock cached signal and resend */
+               sigaction(SIGTERM, &oldact, NULL);
+               if (caught_signal != SIGTERM)
+                       caught_signal = SIGKILL;
+               kill(getpid(), caught_signal);
+       }
+
+       exit(status);
+       return 0;
+}