From 21a03265ab2a001a3afadc1ffb73ef63c1fb7bdd Mon Sep 17 00:00:00 2001 From: Christoph Ruegge Date: Sun, 8 Mar 2020 02:16:06 +0100 Subject: [PATCH] Add some basic error logging --- src/helper.c | 46 ++++++++++++++++++++++++++++++++++++++++------ src/pam_gnupg.c | 29 ++++++++++++++++++++++++----- 2 files changed, 64 insertions(+), 11 deletions(-) diff --git a/src/helper.c b/src/helper.c index 8be5a85..b93bdce 100644 --- a/src/helper.c +++ b/src/helper.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -60,26 +61,42 @@ int main(int argc, char **argv) { } } + openlog("pam_gnupg_helper", 0, LOG_AUTHPRIV); + + errno = 0; struct passwd *pwd = getpwuid(getuid()); if (pwd == NULL) { + if (errno == 0) { + syslog(LOG_ERR, "getpwuid failed: User not found"); + } else { + syslog(LOG_ERR, "getpwuid failed: %m"); + } exit(EXIT_FAILURE); } int dirfd = open(pwd->pw_dir, O_RDONLY | O_DIRECTORY | O_CLOEXEC); if (dirfd < 0) { + syslog(LOG_ERR, "failed to open home directory: %m"); exit(EXIT_FAILURE); } int fd = openat(dirfd, ".pam-gnupg", O_RDONLY | O_CLOEXEC); if (fd < 0) { - exit(errno == ENOENT ? EXIT_SUCCESS : EXIT_FAILURE); + if (errno == ENOENT) { + exit(EXIT_SUCCESS); + } else { + syslog(LOG_ERR, "failed to open config file: %m"); + exit(EXIT_FAILURE); + } } FILE *f = fdopen(fd, "r"); if (f == NULL) { + syslog(LOG_ERR, "failed to fdopen config file: %m"); exit(EXIT_FAILURE); } char tok[MAX_PASSPHRASE_LEN + 1]; if (fgets(tok, MAX_PASSPHRASE_LEN + 1, stdin) == NULL) { + syslog(LOG_ERR, "failed to read passphrase: %m"); exit(EXIT_FAILURE); } @@ -94,21 +111,24 @@ int main(int argc, char **argv) { int pipefd[2]; if (pipe2(pipefd, O_CLOEXEC) < 0) { + syslog(LOG_ERR, "failed to open pipe: %m"); exit(EXIT_FAILURE); } FILE *p = fdopen(pipefd[1], "w"); if (p == NULL) { + syslog(LOG_ERR, "failed to fdopen pipe: %m"); exit(EXIT_FAILURE); } signal(SIGCHLD, SIG_DFL); pid_t pid = fork(); if (pid == -1) { + syslog(LOG_ERR, "fork failed: %m"); exit(EXIT_FAILURE); } else if (pid == 0) { if (dup2(pipefd[0], STDIN_FILENO) < 0) { - exit(EXIT_FAILURE); + exit(errno); } // gpg-connect-agent has an option --no-autostart, which *should* return // non-zero when the agent is not running. Unfortunately, the exit code is @@ -119,13 +139,13 @@ int main(int argc, char **argv) { cmd[1] = NULL; } execv(cmd[0], cmd); - exit(EXIT_FAILURE); + exit(errno); } close(pipefd[0]); signal(SIGPIPE, SIG_IGN); - bool finished = true; + int ret = EXIT_SUCCESS; for (; nextkeygrip(f); nextline(f)) { char keygrip[KEYGRIP_LEN + 1]; if (fscanf(f, "%" xstr(KEYGRIP_LEN) "[0-9A-Fa-f]", keygrip) < 1) { @@ -138,7 +158,8 @@ int main(int argc, char **argv) { *s = toupper(*s); } if (fprintf(p, "preset_passphrase %s -1 %s\n", keygrip, hextok) < 0) { - finished = false; + syslog(LOG_ERR, "failed to write to pipe: %m"); + ret = EXIT_FAILURE; break; } } @@ -147,5 +168,18 @@ int main(int argc, char **argv) { int status; waitpid(pid, &status, 0); - return (finished && WIFEXITED(status)) ? WEXITSTATUS(status) : EXIT_FAILURE; + if (WIFEXITED(status)) { + status = WEXITSTATUS(status); + if (status == EXIT_SUCCESS) { + return ret; + } + syslog(LOG_ERR, "child terminated with exit code %d", status); + return EXIT_FAILURE; + } else if (WIFSIGNALED(status)) { + syslog(LOG_ERR, "child killed by signal %d", WTERMSIG(status)); + return EXIT_FAILURE; + } else { + syslog(LOG_ERR, "child returned unknown status code %d", status); + return EXIT_FAILURE; + } } diff --git a/src/pam_gnupg.c b/src/pam_gnupg.c index bf65a56..85b4bb2 100644 --- a/src/pam_gnupg.c +++ b/src/pam_gnupg.c @@ -7,12 +7,14 @@ #include #include #include +#include #include #include #define PAM_SM_AUTH #define PAM_SM_SESSION +#include #include #include @@ -51,6 +53,7 @@ bool preset_passphrase(pam_handle_t *pamh, const char *tok, bool autostart) { struct passwd *pwd = pam_modutil_getpwnam(pamh, user); if (pwd == NULL) { + pam_syslog(pamh, LOG_ERR, "failed to get user info"); return false; } uid_t uid = pwd->pw_uid; @@ -58,6 +61,7 @@ bool preset_passphrase(pam_handle_t *pamh, const char *tok, bool autostart) { int pipefd[2]; if (pipe2(pipefd, O_CLOEXEC) < 0) { + pam_syslog(pamh, LOG_ERR, "failed to open pipe: %m"); return false; } @@ -81,14 +85,16 @@ bool preset_passphrase(pam_handle_t *pamh, const char *tok, bool autostart) { pid_t pid = fork(); if (pid < 0) { + pam_syslog(pamh, LOG_ERR, "failed to fork: %m"); close(pipefd[0]); close(pipefd[1]); ret = false; } else if (pid == 0) { - if (setregid(gid, gid) < 0 || setreuid(uid, uid) < 0) { - exit(EXIT_FAILURE); + // TODO what about supplementary groups? + if (setregid(gid, gid) < 0 ||setreuid(uid, uid) < 0) { + exit(errno); } // Unblock all signals. fork() clears pending signals in the child, so @@ -98,7 +104,7 @@ bool preset_passphrase(pam_handle_t *pamh, const char *tok, bool autostart) { sigprocmask(SIG_SETMASK, &emptyset, NULL); if (dup2(pipefd[0], STDIN_FILENO) < 0) { - exit(EXIT_FAILURE); + exit(errno); } int dev_null = open("/dev/null", O_WRONLY | O_CLOEXEC); if (dev_null != -1) { @@ -120,11 +126,12 @@ bool preset_passphrase(pam_handle_t *pamh, const char *tok, bool autostart) { } else { execv(cmd[0], cmd); } - exit(EXIT_FAILURE); + exit(errno); } else { if (pam_modutil_write(pipefd[1], tok, strlen(tok)) < 0) { + pam_syslog(pamh, LOG_ERR, "failed to write to pipe: %m"); ret = false; } // We close the read fd after writing in order to avoid SIGPIPE. Since @@ -135,7 +142,19 @@ bool preset_passphrase(pam_handle_t *pamh, const char *tok, bool autostart) { int status; while (waitpid(pid, &status, 0) < 0 && errno == EINTR) ; - ret = ret && WIFEXITED(status) && WEXITSTATUS(status) == EXIT_SUCCESS; + if (WIFEXITED(status)) { + status = WEXITSTATUS(status); + if (status != EXIT_SUCCESS) { + pam_syslog(pamh, LOG_ERR, "helper terminated with exit code %d", status); + ret = false; + } + } else if (WIFSIGNALED(status)) { + pam_syslog(pamh, LOG_ERR, "helper killed by signal %d", WTERMSIG(status)); + ret = false; + } else { + pam_syslog(pamh, LOG_ERR, "helper returned unknown status code %d", status); + ret = false; + } } free(env);