LCOV - code coverage report
Current view: top level - shared - ask-password-api.c (source / functions) Hit Total Coverage
Test: main_coverage.info Lines: 0 439 0.0 %
Date: 2019-08-22 15:41:25 Functions: 0 11 0.0 %

          Line data    Source code
       1             : /* SPDX-License-Identifier: LGPL-2.1+ */
       2             : 
       3             : #include <errno.h>
       4             : #include <fcntl.h>
       5             : #include <inttypes.h>
       6             : #include <limits.h>
       7             : #include <poll.h>
       8             : #include <signal.h>
       9             : #include <stdbool.h>
      10             : #include <stddef.h>
      11             : #include <stdint.h>
      12             : #include <stdio.h>
      13             : #include <stdlib.h>
      14             : #include <string.h>
      15             : #include <sys/inotify.h>
      16             : #include <sys/signalfd.h>
      17             : #include <sys/socket.h>
      18             : #include <sys/stat.h>
      19             : #include <sys/time.h>
      20             : #include <sys/uio.h>
      21             : #include <sys/un.h>
      22             : #include <termios.h>
      23             : #include <unistd.h>
      24             : 
      25             : #include "alloc-util.h"
      26             : #include "ask-password-api.h"
      27             : #include "fd-util.h"
      28             : #include "fileio.h"
      29             : #include "format-util.h"
      30             : #include "fs-util.h"
      31             : #include "io-util.h"
      32             : #include "log.h"
      33             : #include "macro.h"
      34             : #include "memory-util.h"
      35             : #include "missing.h"
      36             : #include "mkdir.h"
      37             : #include "process-util.h"
      38             : #include "random-util.h"
      39             : #include "signal-util.h"
      40             : #include "socket-util.h"
      41             : #include "string-util.h"
      42             : #include "strv.h"
      43             : #include "terminal-util.h"
      44             : #include "time-util.h"
      45             : #include "tmpfile-util.h"
      46             : #include "umask-util.h"
      47             : #include "utf8.h"
      48             : 
      49             : #define KEYRING_TIMEOUT_USEC ((5 * USEC_PER_MINUTE) / 2)
      50             : 
      51           0 : static int lookup_key(const char *keyname, key_serial_t *ret) {
      52             :         key_serial_t serial;
      53             : 
      54           0 :         assert(keyname);
      55           0 :         assert(ret);
      56             : 
      57           0 :         serial = request_key("user", keyname, NULL, 0);
      58           0 :         if (serial == -1)
      59           0 :                 return negative_errno();
      60             : 
      61           0 :         *ret = serial;
      62           0 :         return 0;
      63             : }
      64             : 
      65           0 : static int retrieve_key(key_serial_t serial, char ***ret) {
      66           0 :         size_t nfinal, m = 100;
      67             :         char **l;
      68           0 :         _cleanup_(erase_and_freep) char *pfinal = NULL;
      69             : 
      70           0 :         assert(ret);
      71             : 
      72           0 :         for (;;) {
      73           0 :                 _cleanup_(erase_and_freep) char *p = NULL;
      74             :                 long n;
      75             : 
      76           0 :                 p = new(char, m);
      77           0 :                 if (!p)
      78           0 :                         return -ENOMEM;
      79             : 
      80           0 :                 n = keyctl(KEYCTL_READ, (unsigned long) serial, (unsigned long) p, (unsigned long) m, 0);
      81           0 :                 if (n < 0)
      82           0 :                         return -errno;
      83           0 :                 if ((size_t) n < m) {
      84           0 :                         nfinal = (size_t) n;
      85           0 :                         pfinal = TAKE_PTR(p);
      86           0 :                         break;
      87             :                 }
      88             : 
      89           0 :                 if (m > LONG_MAX / 2) /* overflow check */
      90           0 :                         return -ENOMEM;
      91           0 :                 m *= 2;
      92             :         }
      93             : 
      94           0 :         l = strv_parse_nulstr(pfinal, nfinal);
      95           0 :         if (!l)
      96           0 :                 return -ENOMEM;
      97             : 
      98           0 :         *ret = l;
      99           0 :         return 0;
     100             : }
     101             : 
     102           0 : static int add_to_keyring(const char *keyname, AskPasswordFlags flags, char **passwords) {
     103           0 :         _cleanup_strv_free_erase_ char **l = NULL;
     104           0 :         _cleanup_(erase_and_freep) char *p = NULL;
     105             :         key_serial_t serial;
     106             :         size_t n;
     107             :         int r;
     108             : 
     109           0 :         assert(keyname);
     110           0 :         assert(passwords);
     111             : 
     112           0 :         if (!(flags & ASK_PASSWORD_PUSH_CACHE))
     113           0 :                 return 0;
     114             : 
     115           0 :         r = lookup_key(keyname, &serial);
     116           0 :         if (r >= 0) {
     117           0 :                 r = retrieve_key(serial, &l);
     118           0 :                 if (r < 0)
     119           0 :                         return r;
     120           0 :         } else if (r != -ENOKEY)
     121           0 :                 return r;
     122             : 
     123           0 :         r = strv_extend_strv(&l, passwords, true);
     124           0 :         if (r <= 0)
     125           0 :                 return r;
     126             : 
     127           0 :         r = strv_make_nulstr(l, &p, &n);
     128           0 :         if (r < 0)
     129           0 :                 return r;
     130             : 
     131           0 :         serial = add_key("user", keyname, p, n, KEY_SPEC_USER_KEYRING);
     132           0 :         if (serial == -1)
     133           0 :                 return -errno;
     134             : 
     135           0 :         if (keyctl(KEYCTL_SET_TIMEOUT,
     136             :                    (unsigned long) serial,
     137           0 :                    (unsigned long) DIV_ROUND_UP(KEYRING_TIMEOUT_USEC, USEC_PER_SEC), 0, 0) < 0)
     138           0 :                 log_debug_errno(errno, "Failed to adjust timeout: %m");
     139             : 
     140             :         /* Tell everyone to check the keyring */
     141           0 :         (void) touch("/run/systemd/ask-password");
     142             : 
     143           0 :         log_debug("Added key to keyring as %" PRIi32 ".", serial);
     144             : 
     145           0 :         return 1;
     146             : }
     147             : 
     148           0 : static int add_to_keyring_and_log(const char *keyname, AskPasswordFlags flags, char **passwords) {
     149             :         int r;
     150             : 
     151           0 :         assert(keyname);
     152           0 :         assert(passwords);
     153             : 
     154           0 :         r = add_to_keyring(keyname, flags, passwords);
     155           0 :         if (r < 0)
     156           0 :                 return log_debug_errno(r, "Failed to add password to keyring: %m");
     157             : 
     158           0 :         return 0;
     159             : }
     160             : 
     161           0 : static int ask_password_keyring(const char *keyname, AskPasswordFlags flags, char ***ret) {
     162             : 
     163             :         key_serial_t serial;
     164             :         int r;
     165             : 
     166           0 :         assert(keyname);
     167           0 :         assert(ret);
     168             : 
     169           0 :         if (!(flags & ASK_PASSWORD_ACCEPT_CACHED))
     170           0 :                 return -EUNATCH;
     171             : 
     172           0 :         r = lookup_key(keyname, &serial);
     173           0 :         if (r == -ENOSYS) /* when retrieving the distinction doesn't matter */
     174           0 :                 return -ENOKEY;
     175           0 :         if (r < 0)
     176           0 :                 return r;
     177             : 
     178           0 :         return retrieve_key(serial, ret);
     179             : }
     180             : 
     181           0 : static int backspace_chars(int ttyfd, size_t p) {
     182           0 :         if (ttyfd < 0)
     183           0 :                 return 0;
     184             : 
     185           0 :         _cleanup_free_ char *buf = malloc_multiply(3, p);
     186           0 :         if (!buf)
     187           0 :                 return log_oom();
     188             : 
     189           0 :         for (size_t i = 0; i < p; i++)
     190           0 :                 memcpy(buf + 3 * i, "\b \b", 3);
     191             : 
     192           0 :         return loop_write(ttyfd, buf, 3*p, false);
     193             : }
     194             : 
     195           0 : static int backspace_string(int ttyfd, const char *str) {
     196           0 :         assert(str);
     197             : 
     198             :         /* Backspaces through enough characters to entirely undo printing of the specified string. */
     199             : 
     200           0 :         if (ttyfd < 0)
     201           0 :                 return 0;
     202             : 
     203           0 :         size_t m = utf8_n_codepoints(str);
     204           0 :         if (m == (size_t) -1)
     205           0 :                 m = strlen(str); /* Not a valid UTF-8 string? If so, let's backspace the number of bytes
     206             :                                   * output. Most likely this happened because we are not in an UTF-8 locale,
     207             :                                   * and in that case that is the correct thing to do. And even if it's not,
     208             :                                   * terminals tend to stop backspacing at the leftmost column, hence
     209             :                                   * backspacing too much should be mostly OK. */
     210             : 
     211           0 :         return backspace_chars(ttyfd, m);
     212             : }
     213             : 
     214           0 : int ask_password_tty(
     215             :                 int ttyfd,
     216             :                 const char *message,
     217             :                 const char *keyname,
     218             :                 usec_t until,
     219             :                 AskPasswordFlags flags,
     220             :                 const char *flag_file,
     221             :                 char ***ret) {
     222             : 
     223             :         enum {
     224             :                 POLL_TTY,
     225             :                 POLL_INOTIFY,
     226             :                 _POLL_MAX,
     227             :         };
     228             : 
     229           0 :         bool reset_tty = false, dirty = false, use_color = false;
     230           0 :         _cleanup_close_ int cttyfd = -1, notify = -1;
     231             :         struct termios old_termios, new_termios;
     232           0 :         char passphrase[LINE_MAX + 1] = {}, *x;
     233           0 :         _cleanup_strv_free_erase_ char **l = NULL;
     234             :         struct pollfd pollfd[_POLL_MAX];
     235           0 :         size_t p = 0, codepoint = 0;
     236             :         int r;
     237             : 
     238           0 :         assert(ret);
     239             : 
     240           0 :         if (flags & ASK_PASSWORD_NO_TTY)
     241           0 :                 return -EUNATCH;
     242             : 
     243           0 :         if (!message)
     244           0 :                 message = "Password:";
     245             : 
     246           0 :         if (flag_file || ((flags & ASK_PASSWORD_ACCEPT_CACHED) && keyname)) {
     247           0 :                 notify = inotify_init1(IN_CLOEXEC|IN_NONBLOCK);
     248           0 :                 if (notify < 0)
     249           0 :                         return -errno;
     250             :         }
     251           0 :         if (flag_file) {
     252           0 :                 if (inotify_add_watch(notify, flag_file, IN_ATTRIB /* for the link count */) < 0)
     253           0 :                         return -errno;
     254             :         }
     255           0 :         if ((flags & ASK_PASSWORD_ACCEPT_CACHED) && keyname) {
     256           0 :                 r = ask_password_keyring(keyname, flags, ret);
     257           0 :                 if (r >= 0)
     258           0 :                         return 0;
     259           0 :                 else if (r != -ENOKEY)
     260           0 :                         return r;
     261             : 
     262           0 :                 if (inotify_add_watch(notify, "/run/systemd/ask-password", IN_ATTRIB /* for mtime */) < 0)
     263           0 :                         return -errno;
     264             :         }
     265             : 
     266             :         /* If the caller didn't specify a TTY, then use the controlling tty, if we can. */
     267           0 :         if (ttyfd < 0)
     268           0 :                 ttyfd = cttyfd = open("/dev/tty", O_RDWR|O_NOCTTY|O_CLOEXEC);
     269             : 
     270           0 :         if (ttyfd >= 0) {
     271           0 :                 if (tcgetattr(ttyfd, &old_termios) < 0)
     272           0 :                         return -errno;
     273             : 
     274           0 :                 if (flags & ASK_PASSWORD_CONSOLE_COLOR)
     275           0 :                         use_color = dev_console_colors_enabled();
     276             :                 else
     277           0 :                         use_color = colors_enabled();
     278             : 
     279           0 :                 if (use_color)
     280           0 :                         (void) loop_write(ttyfd, ANSI_HIGHLIGHT, STRLEN(ANSI_HIGHLIGHT), false);
     281             : 
     282           0 :                 (void) loop_write(ttyfd, message, strlen(message), false);
     283           0 :                 (void) loop_write(ttyfd, " ", 1, false);
     284             : 
     285           0 :                 if (use_color)
     286           0 :                         (void) loop_write(ttyfd, ANSI_NORMAL, STRLEN(ANSI_NORMAL), false);
     287             : 
     288           0 :                 new_termios = old_termios;
     289           0 :                 new_termios.c_lflag &= ~(ICANON|ECHO);
     290           0 :                 new_termios.c_cc[VMIN] = 1;
     291           0 :                 new_termios.c_cc[VTIME] = 0;
     292             : 
     293           0 :                 if (tcsetattr(ttyfd, TCSADRAIN, &new_termios) < 0) {
     294           0 :                         r = -errno;
     295           0 :                         goto finish;
     296             :                 }
     297             : 
     298           0 :                 reset_tty = true;
     299             :         }
     300             : 
     301           0 :         pollfd[POLL_TTY] = (struct pollfd) {
     302           0 :                 .fd = ttyfd >= 0 ? ttyfd : STDIN_FILENO,
     303             :                 .events = POLLIN,
     304             :         };
     305           0 :         pollfd[POLL_INOTIFY] = (struct pollfd) {
     306             :                 .fd = notify,
     307             :                 .events = POLLIN,
     308             :         };
     309             : 
     310           0 :         for (;;) {
     311           0 :                 _cleanup_(erase_char) char c;
     312           0 :                 int sleep_for = -1, k;
     313             :                 ssize_t n;
     314             : 
     315           0 :                 if (until > 0) {
     316             :                         usec_t y;
     317             : 
     318           0 :                         y = now(CLOCK_MONOTONIC);
     319             : 
     320           0 :                         if (y > until) {
     321           0 :                                 r = -ETIME;
     322           0 :                                 goto finish;
     323             :                         }
     324             : 
     325           0 :                         sleep_for = (int) DIV_ROUND_UP(until - y, USEC_PER_MSEC);
     326             :                 }
     327             : 
     328           0 :                 if (flag_file)
     329           0 :                         if (access(flag_file, F_OK) < 0) {
     330           0 :                                 r = -errno;
     331           0 :                                 goto finish;
     332             :                         }
     333             : 
     334           0 :                 k = poll(pollfd, notify >= 0 ? 2 : 1, sleep_for);
     335           0 :                 if (k < 0) {
     336           0 :                         if (errno == EINTR)
     337           0 :                                 continue;
     338             : 
     339           0 :                         r = -errno;
     340           0 :                         goto finish;
     341           0 :                 } else if (k == 0) {
     342           0 :                         r = -ETIME;
     343           0 :                         goto finish;
     344             :                 }
     345             : 
     346           0 :                 if (notify >= 0 && pollfd[POLL_INOTIFY].revents != 0 && keyname) {
     347           0 :                         (void) flush_fd(notify);
     348             : 
     349           0 :                         r = ask_password_keyring(keyname, flags, ret);
     350           0 :                         if (r >= 0) {
     351           0 :                                 r = 0;
     352           0 :                                 goto finish;
     353           0 :                         } else if (r != -ENOKEY)
     354           0 :                                 goto finish;
     355             :                 }
     356             : 
     357           0 :                 if (pollfd[POLL_TTY].revents == 0)
     358           0 :                         continue;
     359             : 
     360           0 :                 n = read(ttyfd >= 0 ? ttyfd : STDIN_FILENO, &c, 1);
     361           0 :                 if (n < 0) {
     362           0 :                         if (IN_SET(errno, EINTR, EAGAIN))
     363           0 :                                 continue;
     364             : 
     365           0 :                         r = -errno;
     366           0 :                         goto finish;
     367             : 
     368             :                 }
     369             : 
     370             :                 /* We treat EOF, newline and NUL byte all as valid end markers */
     371           0 :                 if (n == 0 || c == '\n' || c == 0)
     372             :                         break;
     373             : 
     374           0 :                 if (c == 21) { /* C-u */
     375             : 
     376           0 :                         if (!(flags & ASK_PASSWORD_SILENT))
     377           0 :                                 (void) backspace_string(ttyfd, passphrase);
     378             : 
     379           0 :                         explicit_bzero_safe(passphrase, sizeof(passphrase));
     380           0 :                         p = codepoint = 0;
     381             : 
     382           0 :                 } else if (IN_SET(c, '\b', 127)) {
     383             : 
     384           0 :                         if (p > 0) {
     385             :                                 size_t q;
     386             : 
     387           0 :                                 if (!(flags & ASK_PASSWORD_SILENT))
     388           0 :                                         (void) backspace_chars(ttyfd, 1);
     389             : 
     390             :                                 /* Remove a full UTF-8 codepoint from the end. For that, figure out where the
     391             :                                  * last one begins */
     392           0 :                                 q = 0;
     393           0 :                                 for (;;) {
     394             :                                         size_t z;
     395             : 
     396           0 :                                         z = utf8_encoded_valid_unichar(passphrase + q, (size_t) -1);
     397           0 :                                         if (z == 0) {
     398           0 :                                                 q = (size_t) -1; /* Invalid UTF8! */
     399           0 :                                                 break;
     400             :                                         }
     401             : 
     402           0 :                                         if (q + z >= p) /* This one brings us over the edge */
     403           0 :                                                 break;
     404             : 
     405           0 :                                         q += z;
     406             :                                 }
     407             : 
     408           0 :                                 p = codepoint = q == (size_t) -1 ? p - 1 : q;
     409           0 :                                 explicit_bzero_safe(passphrase + p, sizeof(passphrase) - p);
     410             : 
     411           0 :                         } else if (!dirty && !(flags & ASK_PASSWORD_SILENT)) {
     412             : 
     413           0 :                                 flags |= ASK_PASSWORD_SILENT;
     414             : 
     415             :                                 /* There are two ways to enter silent mode. Either by pressing backspace as
     416             :                                  * first key (and only as first key), or ... */
     417             : 
     418           0 :                                 if (ttyfd >= 0)
     419           0 :                                         (void) loop_write(ttyfd, "(no echo) ", 10, false);
     420             : 
     421           0 :                         } else if (ttyfd >= 0)
     422           0 :                                 (void) loop_write(ttyfd, "\a", 1, false);
     423             : 
     424           0 :                 } else if (c == '\t' && !(flags & ASK_PASSWORD_SILENT)) {
     425             : 
     426           0 :                         (void) backspace_string(ttyfd, passphrase);
     427           0 :                         flags |= ASK_PASSWORD_SILENT;
     428             : 
     429             :                         /* ... or by pressing TAB at any time. */
     430             : 
     431           0 :                         if (ttyfd >= 0)
     432           0 :                                 (void) loop_write(ttyfd, "(no echo) ", 10, false);
     433             : 
     434           0 :                 } else if (p >= sizeof(passphrase)-1) {
     435             : 
     436             :                         /* Reached the size limit */
     437           0 :                         if (ttyfd >= 0)
     438           0 :                                 (void) loop_write(ttyfd, "\a", 1, false);
     439             : 
     440             :                 } else {
     441           0 :                         passphrase[p++] = c;
     442             : 
     443           0 :                         if (!(flags & ASK_PASSWORD_SILENT) && ttyfd >= 0) {
     444             :                                 /* Check if we got a complete UTF-8 character now. If so, let's output one '*'. */
     445           0 :                                 n = utf8_encoded_valid_unichar(passphrase + codepoint, (size_t) -1);
     446           0 :                                 if (n >= 0) {
     447           0 :                                         if (flags & ASK_PASSWORD_ECHO)
     448           0 :                                                 (void) loop_write(ttyfd, passphrase + codepoint, n, false);
     449             :                                         else
     450           0 :                                                 (void) loop_write(ttyfd, "*", 1, false);
     451           0 :                                         codepoint = p;
     452             :                                 }
     453             :                         }
     454             : 
     455           0 :                         dirty = true;
     456             :                 }
     457             :         }
     458             : 
     459           0 :         x = strndup(passphrase, p);
     460           0 :         explicit_bzero_safe(passphrase, sizeof(passphrase));
     461           0 :         if (!x) {
     462           0 :                 r = -ENOMEM;
     463           0 :                 goto finish;
     464             :         }
     465             : 
     466           0 :         r = strv_consume(&l, x);
     467           0 :         if (r < 0)
     468           0 :                 goto finish;
     469             : 
     470           0 :         if (keyname)
     471           0 :                 (void) add_to_keyring_and_log(keyname, flags, l);
     472             : 
     473           0 :         *ret = TAKE_PTR(l);
     474           0 :         r = 0;
     475             : 
     476           0 : finish:
     477           0 :         if (ttyfd >= 0 && reset_tty) {
     478           0 :                 (void) loop_write(ttyfd, "\n", 1, false);
     479           0 :                 (void) tcsetattr(ttyfd, TCSADRAIN, &old_termios);
     480             :         }
     481             : 
     482           0 :         return r;
     483             : }
     484             : 
     485           0 : static int create_socket(char **ret) {
     486           0 :         _cleanup_free_ char *path = NULL;
     487           0 :         union sockaddr_union sa = {};
     488           0 :         _cleanup_close_ int fd = -1;
     489             :         int salen, r;
     490             : 
     491           0 :         assert(ret);
     492             : 
     493           0 :         fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
     494           0 :         if (fd < 0)
     495           0 :                 return -errno;
     496             : 
     497           0 :         if (asprintf(&path, "/run/systemd/ask-password/sck.%" PRIx64, random_u64()) < 0)
     498           0 :                 return -ENOMEM;
     499             : 
     500           0 :         salen = sockaddr_un_set_path(&sa.un, path);
     501           0 :         if (salen < 0)
     502           0 :                 return salen;
     503             : 
     504           0 :         RUN_WITH_UMASK(0177) {
     505           0 :                 if (bind(fd, &sa.sa, salen) < 0)
     506           0 :                         return -errno;
     507             :         }
     508             : 
     509           0 :         r = setsockopt_int(fd, SOL_SOCKET, SO_PASSCRED, true);
     510           0 :         if (r < 0)
     511           0 :                 return r;
     512             : 
     513           0 :         *ret = TAKE_PTR(path);
     514           0 :         return TAKE_FD(fd);
     515             : }
     516             : 
     517           0 : int ask_password_agent(
     518             :                 const char *message,
     519             :                 const char *icon,
     520             :                 const char *id,
     521             :                 const char *keyname,
     522             :                 usec_t until,
     523             :                 AskPasswordFlags flags,
     524             :                 char ***ret) {
     525             : 
     526             :         enum {
     527             :                 FD_SOCKET,
     528             :                 FD_SIGNAL,
     529             :                 FD_INOTIFY,
     530             :                 _FD_MAX
     531             :         };
     532             : 
     533           0 :         _cleanup_close_ int socket_fd = -1, signal_fd = -1, notify = -1, fd = -1;
     534           0 :         char temp[] = "/run/systemd/ask-password/tmp.XXXXXX";
     535           0 :         char final[sizeof(temp)] = "";
     536           0 :         _cleanup_free_ char *socket_name = NULL;
     537           0 :         _cleanup_strv_free_erase_ char **l = NULL;
     538           0 :         _cleanup_fclose_ FILE *f = NULL;
     539             :         struct pollfd pollfd[_FD_MAX];
     540             :         sigset_t mask, oldmask;
     541             :         int r;
     542             : 
     543           0 :         assert(ret);
     544             : 
     545           0 :         if (flags & ASK_PASSWORD_NO_AGENT)
     546           0 :                 return -EUNATCH;
     547             : 
     548           0 :         assert_se(sigemptyset(&mask) >= 0);
     549           0 :         assert_se(sigset_add_many(&mask, SIGINT, SIGTERM, -1) >= 0);
     550           0 :         assert_se(sigprocmask(SIG_BLOCK, &mask, &oldmask) >= 0);
     551             : 
     552           0 :         (void) mkdir_p_label("/run/systemd/ask-password", 0755);
     553             : 
     554           0 :         if ((flags & ASK_PASSWORD_ACCEPT_CACHED) && keyname) {
     555           0 :                 r = ask_password_keyring(keyname, flags, ret);
     556           0 :                 if (r >= 0) {
     557           0 :                         r = 0;
     558           0 :                         goto finish;
     559           0 :                 } else if (r != -ENOKEY)
     560           0 :                         goto finish;
     561             : 
     562           0 :                 notify = inotify_init1(IN_CLOEXEC | IN_NONBLOCK);
     563           0 :                 if (notify < 0) {
     564           0 :                         r = -errno;
     565           0 :                         goto finish;
     566             :                 }
     567           0 :                 if (inotify_add_watch(notify, "/run/systemd/ask-password", IN_ATTRIB /* for mtime */) < 0) {
     568           0 :                         r = -errno;
     569           0 :                         goto finish;
     570             :                 }
     571             :         }
     572             : 
     573           0 :         fd = mkostemp_safe(temp);
     574           0 :         if (fd < 0) {
     575           0 :                 r = fd;
     576           0 :                 goto finish;
     577             :         }
     578             : 
     579           0 :         (void) fchmod(fd, 0644);
     580             : 
     581           0 :         f = fdopen(fd, "w");
     582           0 :         if (!f) {
     583           0 :                 r = -errno;
     584           0 :                 goto finish;
     585             :         }
     586             : 
     587           0 :         fd = -1;
     588             : 
     589           0 :         signal_fd = signalfd(-1, &mask, SFD_NONBLOCK|SFD_CLOEXEC);
     590           0 :         if (signal_fd < 0) {
     591           0 :                 r = -errno;
     592           0 :                 goto finish;
     593             :         }
     594             : 
     595           0 :         socket_fd = create_socket(&socket_name);
     596           0 :         if (socket_fd < 0) {
     597           0 :                 r = socket_fd;
     598           0 :                 goto finish;
     599             :         }
     600             : 
     601           0 :         fprintf(f,
     602             :                 "[Ask]\n"
     603             :                 "PID="PID_FMT"\n"
     604             :                 "Socket=%s\n"
     605             :                 "AcceptCached=%i\n"
     606             :                 "Echo=%i\n"
     607             :                 "NotAfter="USEC_FMT"\n",
     608             :                 getpid_cached(),
     609             :                 socket_name,
     610           0 :                 (flags & ASK_PASSWORD_ACCEPT_CACHED) ? 1 : 0,
     611           0 :                 (flags & ASK_PASSWORD_ECHO) ? 1 : 0,
     612             :                 until);
     613             : 
     614           0 :         if (message)
     615           0 :                 fprintf(f, "Message=%s\n", message);
     616             : 
     617           0 :         if (icon)
     618           0 :                 fprintf(f, "Icon=%s\n", icon);
     619             : 
     620           0 :         if (id)
     621           0 :                 fprintf(f, "Id=%s\n", id);
     622             : 
     623           0 :         r = fflush_and_check(f);
     624           0 :         if (r < 0)
     625           0 :                 goto finish;
     626             : 
     627           0 :         memcpy(final, temp, sizeof(temp));
     628             : 
     629           0 :         final[sizeof(final)-11] = 'a';
     630           0 :         final[sizeof(final)-10] = 's';
     631           0 :         final[sizeof(final)-9] = 'k';
     632             : 
     633           0 :         if (rename(temp, final) < 0) {
     634           0 :                 r = -errno;
     635           0 :                 goto finish;
     636             :         }
     637             : 
     638           0 :         zero(pollfd);
     639           0 :         pollfd[FD_SOCKET].fd = socket_fd;
     640           0 :         pollfd[FD_SOCKET].events = POLLIN;
     641           0 :         pollfd[FD_SIGNAL].fd = signal_fd;
     642           0 :         pollfd[FD_SIGNAL].events = POLLIN;
     643           0 :         pollfd[FD_INOTIFY].fd = notify;
     644           0 :         pollfd[FD_INOTIFY].events = POLLIN;
     645             : 
     646           0 :         for (;;) {
     647             :                 char passphrase[LINE_MAX+1];
     648             :                 struct msghdr msghdr;
     649             :                 struct iovec iovec;
     650             :                 struct ucred *ucred;
     651             :                 union {
     652             :                         struct cmsghdr cmsghdr;
     653             :                         uint8_t buf[CMSG_SPACE(sizeof(struct ucred))];
     654             :                 } control;
     655             :                 ssize_t n;
     656             :                 int k;
     657             :                 usec_t t;
     658             : 
     659           0 :                 t = now(CLOCK_MONOTONIC);
     660             : 
     661           0 :                 if (until > 0 && until <= t) {
     662           0 :                         r = -ETIME;
     663           0 :                         goto finish;
     664             :                 }
     665             : 
     666           0 :                 k = poll(pollfd, notify >= 0 ? _FD_MAX : _FD_MAX - 1, until > 0 ? (int) ((until-t)/USEC_PER_MSEC) : -1);
     667           0 :                 if (k < 0) {
     668           0 :                         if (errno == EINTR)
     669           0 :                                 continue;
     670             : 
     671           0 :                         r = -errno;
     672           0 :                         goto finish;
     673             :                 }
     674             : 
     675           0 :                 if (k <= 0) {
     676           0 :                         r = -ETIME;
     677           0 :                         goto finish;
     678             :                 }
     679             : 
     680           0 :                 if (pollfd[FD_SIGNAL].revents & POLLIN) {
     681           0 :                         r = -EINTR;
     682           0 :                         goto finish;
     683             :                 }
     684             : 
     685           0 :                 if (notify >= 0 && pollfd[FD_INOTIFY].revents != 0) {
     686           0 :                         (void) flush_fd(notify);
     687             : 
     688           0 :                         r = ask_password_keyring(keyname, flags, ret);
     689           0 :                         if (r >= 0) {
     690           0 :                                 r = 0;
     691           0 :                                 goto finish;
     692           0 :                         } else if (r != -ENOKEY)
     693           0 :                                 goto finish;
     694             :                 }
     695             : 
     696           0 :                 if (pollfd[FD_SOCKET].revents == 0)
     697           0 :                         continue;
     698             : 
     699           0 :                 if (pollfd[FD_SOCKET].revents != POLLIN) {
     700           0 :                         r = -EIO;
     701           0 :                         goto finish;
     702             :                 }
     703             : 
     704           0 :                 iovec = IOVEC_MAKE(passphrase, sizeof(passphrase));
     705             : 
     706           0 :                 zero(control);
     707           0 :                 zero(msghdr);
     708           0 :                 msghdr.msg_iov = &iovec;
     709           0 :                 msghdr.msg_iovlen = 1;
     710           0 :                 msghdr.msg_control = &control;
     711           0 :                 msghdr.msg_controllen = sizeof(control);
     712             : 
     713           0 :                 n = recvmsg(socket_fd, &msghdr, 0);
     714           0 :                 if (n < 0) {
     715           0 :                         if (IN_SET(errno, EAGAIN, EINTR))
     716           0 :                                 continue;
     717             : 
     718           0 :                         r = -errno;
     719           0 :                         goto finish;
     720             :                 }
     721             : 
     722           0 :                 cmsg_close_all(&msghdr);
     723             : 
     724           0 :                 if (n <= 0) {
     725           0 :                         log_debug("Message too short");
     726           0 :                         continue;
     727             :                 }
     728             : 
     729           0 :                 if (msghdr.msg_controllen < CMSG_LEN(sizeof(struct ucred)) ||
     730           0 :                     control.cmsghdr.cmsg_level != SOL_SOCKET ||
     731           0 :                     control.cmsghdr.cmsg_type != SCM_CREDENTIALS ||
     732           0 :                     control.cmsghdr.cmsg_len != CMSG_LEN(sizeof(struct ucred))) {
     733           0 :                         log_debug("Received message without credentials. Ignoring.");
     734           0 :                         continue;
     735             :                 }
     736             : 
     737           0 :                 ucred = (struct ucred*) CMSG_DATA(&control.cmsghdr);
     738           0 :                 if (ucred->uid != 0) {
     739           0 :                         log_debug("Got request from unprivileged user. Ignoring.");
     740           0 :                         continue;
     741             :                 }
     742             : 
     743           0 :                 if (passphrase[0] == '+') {
     744             :                         /* An empty message refers to the empty password */
     745           0 :                         if (n == 1)
     746           0 :                                 l = strv_new("");
     747             :                         else
     748           0 :                                 l = strv_parse_nulstr(passphrase+1, n-1);
     749           0 :                         explicit_bzero_safe(passphrase, n);
     750           0 :                         if (!l) {
     751           0 :                                 r = -ENOMEM;
     752           0 :                                 goto finish;
     753             :                         }
     754             : 
     755           0 :                         if (strv_isempty(l)) {
     756           0 :                                 l = strv_free(l);
     757           0 :                                 log_debug("Invalid packet");
     758           0 :                                 continue;
     759             :                         }
     760             : 
     761           0 :                         break;
     762             :                 }
     763             : 
     764           0 :                 if (passphrase[0] == '-') {
     765           0 :                         r = -ECANCELED;
     766           0 :                         goto finish;
     767             :                 }
     768             : 
     769           0 :                 log_debug("Invalid packet");
     770             :         }
     771             : 
     772           0 :         if (keyname)
     773           0 :                 (void) add_to_keyring_and_log(keyname, flags, l);
     774             : 
     775           0 :         *ret = TAKE_PTR(l);
     776           0 :         r = 0;
     777             : 
     778           0 : finish:
     779           0 :         if (socket_name)
     780           0 :                 (void) unlink(socket_name);
     781             : 
     782           0 :         (void) unlink(temp);
     783             : 
     784           0 :         if (final[0])
     785           0 :                 (void) unlink(final);
     786             : 
     787           0 :         assert_se(sigprocmask(SIG_SETMASK, &oldmask, NULL) == 0);
     788           0 :         return r;
     789             : }
     790             : 
     791           0 : int ask_password_auto(
     792             :                 const char *message,
     793             :                 const char *icon,
     794             :                 const char *id,
     795             :                 const char *keyname,
     796             :                 usec_t until,
     797             :                 AskPasswordFlags flags,
     798             :                 char ***ret) {
     799             : 
     800             :         int r;
     801             : 
     802           0 :         assert(ret);
     803             : 
     804           0 :         if ((flags & ASK_PASSWORD_ACCEPT_CACHED) &&
     805           0 :             keyname &&
     806           0 :             ((flags & ASK_PASSWORD_NO_TTY) || !isatty(STDIN_FILENO)) &&
     807           0 :             (flags & ASK_PASSWORD_NO_AGENT)) {
     808           0 :                 r = ask_password_keyring(keyname, flags, ret);
     809           0 :                 if (r != -ENOKEY)
     810           0 :                         return r;
     811             :         }
     812             : 
     813           0 :         if (!(flags & ASK_PASSWORD_NO_TTY) && isatty(STDIN_FILENO))
     814           0 :                 return ask_password_tty(-1, message, keyname, until, flags, NULL, ret);
     815             : 
     816           0 :         if (!(flags & ASK_PASSWORD_NO_AGENT))
     817           0 :                 return ask_password_agent(message, icon, id, keyname, until, flags, ret);
     818             : 
     819           0 :         return -EUNATCH;
     820             : }

Generated by: LCOV version 1.14