X-Git-Url: https://git.armaanb.net/?a=blobdiff_plain;f=pam.c;h=81483800655243219612ccbaf51b39b258b7018d;hb=b82ffa68a6436ce3f4c4b480bc9c12ac284b0d99;hp=6be44b70e2f517b4f1f1e969594e87935bd4ae5d;hpb=3df794793ea3db2a6a8abfeb46803b9c5b80502a;p=opendoas.git diff --git a/pam.c b/pam.c index 6be44b7..8148380 100644 --- a/pam.c +++ b/pam.c @@ -14,35 +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_H +#ifdef HAVE_READPASSPHRASE # include #else -# include "readpassphrase.h" +# include "sys-readpassphrase.h" #endif #include #include #include #include -#include +#include #include #include -#include "includes.h" +#include "openbsd.h" +#include "doas.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) @@ -85,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) { @@ -118,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)); @@ -126,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", @@ -148,7 +155,7 @@ pamcleanup(int ret) } void -watchsession(pid_t child) +watchsession(pid_t child, int sess, int cred) { sigset_t sigs; struct sigaction act, oldact; @@ -199,7 +206,7 @@ close: kill(child, SIGTERM); } - pamcleanup(PAM_SUCCESS); + pamcleanup(PAM_SUCCESS, sess, cred); if (caught_signal) { if (child != (pid_t)-1) { @@ -219,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, @@ -228,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) @@ -253,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"); @@ -262,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); @@ -290,25 +317,33 @@ pamauth(const char *user, const char* ruser, int interactive, int nopass) 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); }