*/
#include <sys/types.h>
+#include <sys/wait.h>
+
#include <err.h>
#include <errno.h>
+#include <limits.h>
#include <pwd.h>
+#ifdef HAVE_READPASSPHRASE_H
+# include <readpassphrase.h>
+#else
+# include "readpassphrase.h"
+#endif
+#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <syslog.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 char doas_prompt[128];
static sig_atomic_t volatile caught_signal = 0;
-static int session_opened = 0;
-static int cred_established = 0;
static void
catchsig(int sig)
int ret;
if (!(rsp = calloc(nmsgs, sizeof(struct pam_response))))
- errx(1, "couldn't malloc pam_response");
+ err(1, "could not allocate pam_response");
for (i = 0; i < nmsgs; i++) {
switch (style = msgs[i]->msg_style) {
}
void
-pamcleanup(int ret)
+pamcleanup(int ret, int sess, int cred)
{
- if (session_opened != 0) {
+ if (sess) {
ret = pam_close_session(pamh, 0);
if (ret != PAM_SUCCESS)
errx(1, "pam_close_session: %s", pam_strerror(pamh, ret));
}
- if (cred_established != 0) {
+ if (cred) {
ret = pam_setcred(pamh, PAM_DELETE_CRED | PAM_SILENT);
if (ret != PAM_SUCCESS)
warn("pam_setcred(?, PAM_DELETE_CRED | PAM_SILENT): %s",
}
void
-watchsession(pid_t child)
+watchsession(pid_t child, int sess, int cred)
{
sigset_t sigs;
struct sigaction act, oldact;
- int status;
+ int status = 1;
/* block signals */
sigfillset(&sigs);
status = 1;
close:
- if (caught_signal) {
+ if (caught_signal && child != (pid_t)-1) {
fprintf(stderr, "\nSession terminated, killing shell\n");
kill(child, SIGTERM);
}
- pamcleanup(PAM_SUCCESS);
+ pamcleanup(PAM_SUCCESS, sess, cred);
if (caught_signal) {
- /* kill child */
- sleep(2);
- kill(child, SIGKILL);
- fprintf(stderr, " ...killed.\n");
+ if (child != (pid_t)-1) {
+ /* kill child */
+ sleep(2);
+ kill(child, SIGKILL);
+ fprintf(stderr, " ...killed.\n");
+ }
/* unblock cached signal and resend */
sigaction(SIGTERM, &oldact, NULL);
exit(status);
}
-int
-pamauth(const char *user, const char* ruser, int interactive, int nopass)
+void
+pamauth(const char *user, const char *myname, int interactive, int nopass, int persist)
{
static const struct pam_conv conv = {
.conv = pamconv,
};
const char *ttydev;
pid_t child;
- int ret;
+ int ret, sess = 0, cred = 0;
- if (!user || !ruser)
- return 0;
+#ifdef USE_TIMESTAMP
+ int fd = -1;
+ int valid = 0;
+#else
+ (void) persist;
+#endif
- ret = pam_start(PAM_SERVICE_NAME, ruser, &conv, &pamh);
+ if (!user || !myname)
+ errx(1, "Authorization failed");
+
+ ret = pam_start(PAM_SERVICE_NAME, myname, &conv, &pamh);
if (ret != PAM_SUCCESS)
errx(1, "pam_start(\"%s\", \"%s\", ?, ?): failed",
- PAM_SERVICE_NAME, ruser);
+ PAM_SERVICE_NAME, myname);
- ret = pam_set_item(pamh, PAM_RUSER, ruser);
+ ret = pam_set_item(pamh, PAM_RUSER, myname);
if (ret != PAM_SUCCESS)
warn("pam_set_item(?, PAM_RUSER, \"%s\"): %s",
- pam_strerror(pamh, ret), ruser);
+ pam_strerror(pamh, ret), myname);
if (isatty(0) && (ttydev = ttyname(0)) != NULL) {
if (strncmp(ttydev, "/dev/", 5) == 0)
ttydev, pam_strerror(pamh, ret));
}
+
+#ifdef USE_TIMESTAMP
+ if (persist)
+ fd = timestamp_open(&valid, 5 * 60);
+ if (fd != -1 && valid == 1)
+ nopass = 1;
+#endif
+
if (!nopass) {
if (!interactive)
errx(1, "Authorization required");
if (gethostname(host, sizeof(host)))
snprintf(host, sizeof(host), "?");
snprintf(doas_prompt, sizeof(doas_prompt),
- "\rdoas (%.32s@%.32s) password: ", ruser, host);
+ "\rdoas (%.32s@%.32s) password: ", myname, host);
/* authenticate */
ret = pam_authenticate(pamh, 0);
if (ret != PAM_SUCCESS) {
- pamcleanup(ret);
- return 0;
+ pamcleanup(ret, sess, cred);
+ syslog(LOG_AUTHPRIV | LOG_NOTICE, "failed auth for %s", myname);
+ errx(1, "Authorization failed");
}
}
+
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;
+ if (ret != PAM_SUCCESS) {
+ pamcleanup(ret, sess, cred);
+ syslog(LOG_AUTHPRIV | LOG_NOTICE, "failed auth for %s", myname);
+ errx(1, "Authorization failed");
+ }
/* set PAM_USER to the user we want to be */
ret = pam_set_item(pamh, PAM_USER, user);
if (ret != PAM_SUCCESS)
warn("pam_setcred(?, PAM_ESTABLISH_CRED): %s", pam_strerror(pamh, ret));
else
- cred_established = 1;
+ cred = 1;
/* open session */
ret = pam_open_session(pamh, 0);
if (ret != PAM_SUCCESS)
errx(1, "pam_open_session: %s", pam_strerror(pamh, ret));
- else
- session_opened = 1;
+ sess = 1;
if ((child = fork()) == -1) {
- pamcleanup(PAM_ABORT);
- errx(1, "fork");
+ pamcleanup(PAM_ABORT, sess, cred);
+ err(1, "fork");
}
/* return as child */
- if (child == 0)
- return 1;
-
- watchsession(child);
+ if (child == 0) {
+#ifdef USE_TIMESTAMP
+ if (fd != -1)
+ close(fd);
+#endif
+ return;
+ }
- return 0;
+#ifdef USE_TIMESTAMP
+ if (fd != -1) {
+ timestamp_set(fd, 5 * 60);
+ close(fd);
+ }
+#endif
+ watchsession(child, sess, cred);
}