X-Git-Url: https://git.armaanb.net/?a=blobdiff_plain;f=pam.c;h=68294b275451c2e3ee9a88700b413114a261d748;hb=a1ab056bccfe66d4f03b96e3f83168a3732e56f4;hp=ec89d047dcc73bee6fe62ae991d11c82177d9af9;hpb=c05e559c4c473655da25d0fcae207aa3345b029b;p=opendoas.git diff --git a/pam.c b/pam.c index ec89d04..68294b2 100644 --- a/pam.c +++ b/pam.c @@ -14,32 +14,41 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "config.h" + #include +#include + #include #include +#include #include +#ifdef HAVE_READPASSPHRASE +# include +#else +# include "sys-readpassphrase.h" +#endif +#include #include #include #include +#include #include -#include -#include -#ifdef __linux__ -#include -#endif #include +#include "openbsd.h" #include "doas.h" -#include "includes.h" + +#ifndef HOST_NAME_MAX +#define HOST_NAME_MAX _POSIX_HOST_NAME_MAX +#endif #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) @@ -82,7 +91,7 @@ pamconv(int nmsgs, const struct pam_message **msgs, 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) { @@ -115,7 +124,7 @@ fail: for (i = 0; i < nmsgs; i++) { if (rsp[i].resp == NULL) continue; - switch (style = msgs[i]->msg_style) { + switch (msgs[i]->msg_style) { case PAM_PROMPT_ECHO_OFF: case PAM_PROMPT_ECHO_ON: explicit_bzero(rsp[i].resp, strlen(rsp[i].resp)); @@ -123,19 +132,20 @@ fail: } rsp[i].resp = NULL; } + free(rsp); return PAM_CONV_ERR; } 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", @@ -145,11 +155,11 @@ pamcleanup(int ret) } 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); @@ -191,18 +201,20 @@ watchsession(pid_t child) 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); @@ -214,8 +226,8 @@ close: 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, @@ -223,20 +235,27 @@ pamauth(const char *user, const char* ruser, int interactive, int nopass) }; const char *ttydev; pid_t child; - int ret; + int ret, sess = 0, cred = 0; + +#ifdef USE_TIMESTAMP + int fd = -1; + int valid = 0; +#else + (void) persist; +#endif - if (!user || !ruser) - return 0; + if (!user || !myname) + errx(1, "Authorization failed"); - ret = pam_start(PAM_SERVICE_NAME, ruser, &conv, &pamh); + 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) @@ -248,6 +267,14 @@ pamauth(const char *user, const char* ruser, int interactive, int nopass) 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"); @@ -257,23 +284,28 @@ pamauth(const char *user, const char* ruser, int interactive, int nopass) 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); @@ -281,29 +313,37 @@ pamauth(const char *user, const char* ruser, int interactive, int nopass) warn("pam_set_item(?, PAM_USER, \"%s\"): %s", user, pam_strerror(pamh, ret)); - ret = pam_setcred(pamh, PAM_ESTABLISH_CRED); + ret = pam_setcred(pamh, PAM_REINITIALIZE_CRED); if (ret != PAM_SUCCESS) - warn("pam_setcred(?, PAM_ESTABLISH_CRED): %s", pam_strerror(pamh, ret)); + warn("pam_setcred(?, PAM_REINITIALIZE_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); }