LCOV - code coverage report
Current view: top level - shared - ask-password-api.c (source / functions) Hit Total Coverage
Test: systemd_full.info Lines: 0 439 0.0 %
Date: 2019-08-23 13:36:53 Functions: 0 11 0.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 0 371 0.0 %

           Branch data     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