opendoas

A portable version of the OpenBSD `doas` command
git clone https://pi.duncano.de/git/opendoas.git
Log | Files | Refs | README | LICENSE

commit 67372a74fe974ba799bb209a111eb7c2e9bc1203
parent 5c60366f659313e46a5b22ad27f50a3ba3ab8f15
Author: Nathan Holstein <nathan.holstein@gmail.com>
Date:   Thu,  6 Aug 2015 00:40:10 -0400

Implement PAM authentication.

This now lets us check for a password. This still needs some error
checking logic within pam_conv(). The current state could fail an IO
operation but still return PAM_SUCCESS.

Diffstat:
libopenbsd/auth_userokay.c | 101+++++++++++++++++++++++++++++++++++++++++++++----------------------------------
1 file changed, 57 insertions(+), 44 deletions(-)

diff --git a/libopenbsd/auth_userokay.c b/libopenbsd/auth_userokay.c @@ -15,11 +15,13 @@ */ #include <sys/types.h> +#include <err.h> #include <errno.h> #include <pwd.h> #include <readpassphrase.h> #include <stdio.h> #include <stdlib.h> +#include <string.h> #include <security/pam_appl.h> @@ -29,67 +31,78 @@ #define __UNUSED __attribute__ ((unused)) -static int -pam_conv(__UNUSED int huh, __UNUSED const struct pam_message **msg, - __UNUSED struct pam_response **rsp, __UNUSED void *ptr) +static char * +pam_prompt(const char *msg, int echo_on) { - return 0; + char buf[PAM_MAX_RESP_SIZE]; + int flags = RPP_REQUIRE_TTY | (echo_on ? RPP_ECHO_ON : RPP_ECHO_OFF); + char *ret = readpassphrase(msg, buf, sizeof(buf), flags); + if (ret) + ret = strdup(ret); + explicit_bzero(buf, sizeof(buf)); + return ret; } -static struct pam_conv conv = { - .conv = pam_conv, - .appdata_ptr = NULL, -}; - static int -check_pam(const char *user) +pam_conv(int nmsgs, const struct pam_message **msgs, + struct pam_response **rsps, __UNUSED void *ptr) { - fprintf(stderr, "check_pam(%s)\n", user); - - int ret; - pam_handle_t *pamh = NULL; - - ret = pam_start(PAM_SERVICE, user, &conv, &pamh); - if (ret != 0) { - fprintf(stderr, "pam_start(\"%s\", \"%s\", ?, ?): failed\n", - PAM_SERVICE, user); - return -1; - } - - if ((ret = pam_close_session(pamh, 0)) != 0) { - fprintf(stderr, "pam_close_session(): %s\n", pam_strerror(pamh, ret)); - return -1; + int i, style; + struct pam_response *rsp; + + if (!(rsp = calloc(nmsgs, sizeof(struct pam_response)))) + errx(1, "couldn't malloc pam_response"); + *rsps = rsp; + + 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 = pam_prompt(msgs[i]->msg, + style == PAM_PROMPT_ECHO_ON); + break; + + case PAM_ERROR_MSG: + case PAM_TEXT_INFO: + fprintf(style == PAM_ERROR_MSG ? stderr : stdout, + "%s\n", msgs[i]->msg); + break; + + default: + errx(1, "invalid PAM msg_style %d", style); + } } - return 0; + return PAM_SUCCESS; } int auth_userokay(char *name, char *style, char *type, char *password) { + static const struct pam_conv conv = { + .conv = pam_conv, + .appdata_ptr = NULL, + }; + + int ret, auth; + pam_handle_t *pamh = NULL; + if (!name) return 0; - if (style || type || password) { - fprintf(stderr, "auth_userokay(name, NULL, NULL, NULL)!\n"); - exit(1); - } + if (style || type || password) + errx(1, "auth_userokay(name, NULL, NULL, NULL)!\n"); - int ret = check_pam(name); - if (ret != 0) { - fprintf(stderr, "PAM authentication failed\n"); - return 0; - } + ret = pam_start(PAM_SERVICE, name, &conv, &pamh); + if (ret != PAM_SUCCESS) + errx(1, "pam_start(\"%s\", \"%s\", ?, ?): failed\n", + PAM_SERVICE, name); - /* - char passbuf[256]; - if (readpassphrase("Password: ", passbuf, sizeof(passbuf), - RPP_REQUIRE_TTY) == NULL) - return 0; + auth = pam_authenticate(pamh, 0); - explicit_bzero(passbuf, sizeof(passbuf)); - */ + ret = pam_close_session(pamh, 0); + if (ret != PAM_SUCCESS) + errx(1, "pam_close_session(): %s\n", pam_strerror(pamh, ret)); - fprintf(stderr, "failing auth check for %s\n", name); - return 0; + return auth == PAM_SUCCESS; }