X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Fask-password.c;h=596c8e08f07a767b9907250a2cfa9148a6a65a23;hp=22dda974c5fac62e33c172cb11aaf98e804dd127;hb=867b3b7d6b88ba4d07ec7c830576d4ac2f7dd226;hpb=ad6ab0af1ed38e342aeeae1c5f7c1503fab11935 diff --git a/src/ask-password.c b/src/ask-password.c index 22dda974c..596c8e08f 100644 --- a/src/ask-password.c +++ b/src/ask-password.c @@ -33,70 +33,25 @@ #include #include #include +#include #include "log.h" #include "macro.h" #include "util.h" +#include "ask-password-api.h" static const char *arg_icon = NULL; static const char *arg_message = NULL; static bool arg_use_tty = true; static usec_t arg_timeout = 60 * USEC_PER_SEC; -static int create_socket(char **name) { - int fd; - union { - struct sockaddr sa; - struct sockaddr_un un; - } sa; - int one = 1, r; - char *c; - - assert(name); - - if ((fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0)) < 0) { - log_error("socket() failed: %m"); - return -errno; - } - - zero(sa); - sa.un.sun_family = AF_UNIX; - snprintf(sa.un.sun_path+1, sizeof(sa.un.sun_path)-1, "/org/freedesktop/systemd1/ask-password/%llu", random_ull()); - - if (bind(fd, &sa.sa, sizeof(sa_family_t) + 1 + strlen(sa.un.sun_path+1)) < 0) { - r = -errno; - log_error("bind() failed: %m"); - goto fail; - } - - if (setsockopt(fd, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one)) < 0) { - r = -errno; - log_error("SO_PASSCRED failed: %m"); - goto fail; - } - - if (!(c = strdup(sa.un.sun_path+1))) { - r = -ENOMEM; - log_error("Out of memory"); - goto fail; - } - - *name = c; - return fd; - -fail: - close_nointr_nofail(fd); - - return r; -} - static int help(void) { printf("%s [OPTIONS...] MESSAGE\n\n" "Query the user for a system passphrase, via the TTY or an UI agent.\n\n" " -h --help Show this help\n" " --icon=NAME Icon name\n" - " --timeout=USEC Timeout in usec\n" + " --timeout=SEC Timeout in sec\n" " --no-tty Ask question via agent even on TTY\n", program_invocation_short_name); @@ -165,293 +120,9 @@ static int parse_argv(int argc, char *argv[]) { return 1; } -static int ask_agent(void) { - char temp[] = "/dev/.systemd/ask-password/tmp.XXXXXX"; - char final[sizeof(temp)] = ""; - int fd = -1, r; - FILE *f = NULL; - char *socket_name = NULL; - int socket_fd, signal_fd; - sigset_t mask; - usec_t not_after; - - if ((fd = mkostemp(temp, O_CLOEXEC|O_CREAT|O_WRONLY)) < 0) { - log_error("Failed to create password file: %m"); - r = -errno; - goto finish; - } - - fchmod(fd, 0644); - - if (!(f = fdopen(fd, "w"))) { - log_error("Failed to allocate FILE: %m"); - r = -errno; - goto finish; - } - - fd = -1; - - assert_se(sigemptyset(&mask) == 0); - sigset_add_many(&mask, SIGINT, SIGTERM, -1); - assert_se(sigprocmask(SIG_SETMASK, &mask, NULL) == 0); - - if ((signal_fd = signalfd(-1, &mask, SFD_NONBLOCK|SFD_CLOEXEC)) < 0) { - log_error("signalfd(): %m"); - r = -errno; - goto finish; - } - - if ((socket_fd = create_socket(&socket_name)) < 0) { - r = socket_fd; - goto finish; - } - - not_after = now(CLOCK_MONOTONIC) + arg_timeout; - - fprintf(f, - "[Ask]\n" - "Socket=%s\n" - "NotAfter=%llu\n", - socket_name, - (unsigned long long) not_after); - - if (arg_message) - fprintf(f, "Message=%s\n", arg_message); - - if (arg_icon) - fprintf(f, "Icon=%s\n", arg_icon); - - fflush(f); - - if (ferror(f)) { - log_error("Failed to write query file: %m"); - r = -errno; - goto finish; - } - - memcpy(final, temp, sizeof(temp)); - - final[sizeof(final)-11] = 'a'; - final[sizeof(final)-10] = 's'; - final[sizeof(final)-9] = 'k'; - - if (rename(temp, final) < 0) { - log_error("Failed to rename query file: %m"); - r = -errno; - goto finish; - } - - for (;;) { - enum { - FD_SOCKET, - FD_SIGNAL, - _FD_MAX - }; - - char passphrase[LINE_MAX+1]; - struct msghdr msghdr; - struct iovec iovec; - struct ucred *ucred; - union { - struct cmsghdr cmsghdr; - uint8_t buf[CMSG_SPACE(sizeof(struct ucred))]; - } control; - ssize_t n; - struct pollfd pollfd[_FD_MAX]; - int k; - - zero(pollfd); - pollfd[FD_SOCKET].fd = socket_fd; - pollfd[FD_SOCKET].events = POLLIN; - pollfd[FD_SIGNAL].fd = signal_fd; - pollfd[FD_SIGNAL].events = POLLIN; - - if ((k = poll(pollfd, 2, arg_timeout/USEC_PER_MSEC)) < 0) { - - if (errno == EINTR) - continue; - - log_error("poll() failed: %m"); - r = -errno; - goto finish; - } - - if (k <= 0) { - log_notice("Timed out"); - r = -ETIME; - goto finish; - } - - if (pollfd[FD_SIGNAL].revents & POLLIN) - break; - - if (pollfd[FD_SOCKET].revents != POLLIN) { - log_error("Unexpected poll() event."); - r = -EIO; - goto finish; - } - - zero(iovec); - iovec.iov_base = passphrase; - iovec.iov_len = sizeof(passphrase)-1; - - zero(control); - zero(msghdr); - msghdr.msg_iov = &iovec; - msghdr.msg_iovlen = 1; - msghdr.msg_control = &control; - msghdr.msg_controllen = sizeof(control); - - if ((n = recvmsg(socket_fd, &msghdr, 0)) < 0) { - - if (errno == EAGAIN || - errno == EINTR) - continue; - - log_error("recvmsg() failed: %m"); - r = -errno; - goto finish; - } - - if (n <= 0) { - log_error("Message too short"); - continue; - } - - if (msghdr.msg_controllen < CMSG_LEN(sizeof(struct ucred)) || - control.cmsghdr.cmsg_level != SOL_SOCKET || - control.cmsghdr.cmsg_type != SCM_CREDENTIALS || - control.cmsghdr.cmsg_len != CMSG_LEN(sizeof(struct ucred))) { - log_warning("Received message without credentials. Ignoring."); - continue; - } - - ucred = (struct ucred*) CMSG_DATA(&control.cmsghdr); - if (ucred->uid != 0) { - log_warning("Got request from unprivileged user. Ignoring."); - continue; - } - - if (passphrase[0] == '+') { - passphrase[n] = 0; - fputs(passphrase+1, stdout); - fflush(stdout); - } else if (passphrase[0] == '-') { - r = -ECANCELED; - goto finish; - } else { - log_error("Invalid packet"); - continue; - } - - break; - } - - r = 0; - -finish: - if (fd >= 0) - close_nointr_nofail(fd); - - if (socket_fd >= 0) - close_nointr_nofail(socket_fd); - - if (f) - fclose(f); - - unlink(temp); - - if (final[0]) - unlink(final); - - return r; -} - -static int ask_tty(void) { - struct termios old_termios, new_termios; - char passphrase[LINE_MAX]; - FILE *ttyf; - - if (!(ttyf = fopen("/dev/tty", "w"))) { - log_error("Failed to open /dev/tty: %m"); - return -errno; - } - - fputs("\x1B[1m", ttyf); - fprintf(ttyf, "%s: ", arg_message); - fputs("\x1B[0m", ttyf); - fflush(ttyf); - - if (tcgetattr(STDIN_FILENO, &old_termios) >= 0) { - - new_termios = old_termios; - - new_termios.c_lflag &= ~(ICANON|ECHO); - new_termios.c_cc[VMIN] = 1; - new_termios.c_cc[VTIME] = 0; - - if (tcsetattr(STDIN_FILENO, TCSADRAIN, &new_termios) >= 0) { - size_t p = 0; - int r = 0; - - for (;;) { - size_t k; - char c; - - k = fread(&c, 1, 1, stdin); - - if (k <= 0) { - r = -EIO; - break; - } - - if (c == '\n') - break; - else if (c == '\b' || c == 127) { - if (p > 0) { - p--; - fputs("\b \b", ttyf); - } - } else { - passphrase[p++] = c; - fputc('*', ttyf); - } - - fflush(ttyf); - } - - fputc('\n', ttyf); - fclose(ttyf); - tcsetattr(STDIN_FILENO, TCSADRAIN, &old_termios); - - if (r < 0) - return -EIO; - - passphrase[p] = 0; - - fputs(passphrase, stdout); - fflush(stdout); - return 0; - } - - } - - fclose(ttyf); - - if (!fgets(passphrase, sizeof(passphrase), stdin)) { - log_error("Failed to read password."); - return -EIO; - } - - truncate_nl(passphrase); - fputs(passphrase, stdout); - fflush(stdout); - - return 0; -} - int main(int argc, char *argv[]) { int r; + char *password = NULL; log_parse_environment(); log_open(); @@ -460,10 +131,17 @@ int main(int argc, char *argv[]) { goto finish; if (arg_use_tty && isatty(STDIN_FILENO)) - r = ask_tty(); + r = ask_password_tty(arg_message, now(CLOCK_MONOTONIC) + arg_timeout, NULL, &password); else - r = ask_agent(); + r = ask_password_agent(arg_message, arg_icon, now(CLOCK_MONOTONIC) + arg_timeout, &password); + + if (r >= 0) { + fputs(password, stdout); + fflush(stdout); + } finish: + free(password); + return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; }