LCOV - code coverage report
Current view: top level - cryptsetup - cryptsetup-generator.c (source / functions) Hit Total Coverage
Test: systemd_full.info Lines: 0 377 0.0 %
Date: 2019-08-23 13:36:53 Functions: 0 15 0.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 0 415 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 <sys/stat.h>
       6                 :            : #include <sys/types.h>
       7                 :            : 
       8                 :            : #include "alloc-util.h"
       9                 :            : #include "dropin.h"
      10                 :            : #include "escape.h"
      11                 :            : #include "fd-util.h"
      12                 :            : #include "fileio.h"
      13                 :            : #include "fstab-util.h"
      14                 :            : #include "generator.h"
      15                 :            : #include "hashmap.h"
      16                 :            : #include "id128-util.h"
      17                 :            : #include "log.h"
      18                 :            : #include "mkdir.h"
      19                 :            : #include "parse-util.h"
      20                 :            : #include "path-util.h"
      21                 :            : #include "proc-cmdline.h"
      22                 :            : #include "specifier.h"
      23                 :            : #include "string-util.h"
      24                 :            : #include "strv.h"
      25                 :            : #include "unit-name.h"
      26                 :            : #include "util.h"
      27                 :            : 
      28                 :            : typedef struct crypto_device {
      29                 :            :         char *uuid;
      30                 :            :         char *keyfile;
      31                 :            :         char *keydev;
      32                 :            :         char *name;
      33                 :            :         char *options;
      34                 :            :         bool create;
      35                 :            : } crypto_device;
      36                 :            : 
      37                 :            : static const char *arg_dest = NULL;
      38                 :            : static bool arg_enabled = true;
      39                 :            : static bool arg_read_crypttab = true;
      40                 :            : static bool arg_whitelist = false;
      41                 :            : static Hashmap *arg_disks = NULL;
      42                 :            : static char *arg_default_options = NULL;
      43                 :            : static char *arg_default_keyfile = NULL;
      44                 :            : 
      45                 :          0 : STATIC_DESTRUCTOR_REGISTER(arg_disks, hashmap_freep);
      46                 :          0 : STATIC_DESTRUCTOR_REGISTER(arg_default_options, freep);
      47                 :          0 : STATIC_DESTRUCTOR_REGISTER(arg_default_keyfile, freep);
      48                 :            : 
      49                 :          0 : static int split_keyspec(const char *keyspec, char **ret_keyfile, char **ret_keydev) {
      50                 :          0 :         _cleanup_free_ char *keyfile = NULL, *keydev = NULL;
      51                 :            :         const char *c;
      52                 :            : 
      53         [ #  # ]:          0 :         assert(ret_keyfile);
      54         [ #  # ]:          0 :         assert(ret_keydev);
      55                 :            : 
      56         [ #  # ]:          0 :         if (!keyspec) {
      57                 :          0 :                 *ret_keyfile = *ret_keydev = NULL;
      58                 :          0 :                 return 0;
      59                 :            :         }
      60                 :            : 
      61                 :          0 :         c = strrchr(keyspec, ':');
      62         [ #  # ]:          0 :         if (c) {
      63                 :          0 :                 keyfile = strndup(keyspec, c-keyspec);
      64                 :          0 :                 keydev = strdup(c + 1);
      65   [ #  #  #  # ]:          0 :                 if (!keyfile || !keydev)
      66                 :          0 :                         return log_oom();
      67                 :            :         } else {
      68                 :            :                 /* No keydev specified */
      69                 :          0 :                 keyfile = strdup(keyspec);
      70                 :          0 :                 keydev = NULL;
      71         [ #  # ]:          0 :                 if (!keyfile)
      72                 :          0 :                         return log_oom();
      73                 :            :         }
      74                 :            : 
      75                 :          0 :         *ret_keyfile = TAKE_PTR(keyfile);
      76                 :          0 :         *ret_keydev = TAKE_PTR(keydev);
      77                 :            : 
      78                 :          0 :         return 0;
      79                 :            : }
      80                 :            : 
      81                 :          0 : static int generate_keydev_mount(const char *name, const char *keydev, const char *keydev_timeout, bool canfail, char **unit, char **mount) {
      82                 :          0 :         _cleanup_free_ char *u = NULL, *what = NULL, *where = NULL, *name_escaped = NULL, *device_unit = NULL;
      83                 :          0 :         _cleanup_fclose_ FILE *f = NULL;
      84                 :            :         int r;
      85                 :            :         usec_t timeout_us;
      86                 :            : 
      87         [ #  # ]:          0 :         assert(name);
      88         [ #  # ]:          0 :         assert(keydev);
      89         [ #  # ]:          0 :         assert(unit);
      90         [ #  # ]:          0 :         assert(mount);
      91                 :            : 
      92                 :          0 :         r = mkdir_parents("/run/systemd/cryptsetup", 0755);
      93         [ #  # ]:          0 :         if (r < 0)
      94                 :          0 :                 return r;
      95                 :            : 
      96                 :          0 :         r = mkdir("/run/systemd/cryptsetup", 0700);
      97   [ #  #  #  # ]:          0 :         if (r < 0 && errno != EEXIST)
      98                 :          0 :                 return -errno;
      99                 :            : 
     100                 :          0 :         name_escaped = cescape(name);
     101         [ #  # ]:          0 :         if (!name_escaped)
     102                 :          0 :                 return -ENOMEM;
     103                 :            : 
     104                 :          0 :         where = strjoin("/run/systemd/cryptsetup/keydev-", name_escaped);
     105         [ #  # ]:          0 :         if (!where)
     106                 :          0 :                 return -ENOMEM;
     107                 :            : 
     108                 :          0 :         r = mkdir(where, 0700);
     109   [ #  #  #  # ]:          0 :         if (r < 0 && errno != EEXIST)
     110                 :          0 :                 return -errno;
     111                 :            : 
     112                 :          0 :         r = unit_name_from_path(where, ".mount", &u);
     113         [ #  # ]:          0 :         if (r < 0)
     114                 :          0 :                 return r;
     115                 :            : 
     116                 :          0 :         r = generator_open_unit_file(arg_dest, NULL, u, &f);
     117         [ #  # ]:          0 :         if (r < 0)
     118                 :          0 :                 return r;
     119                 :            : 
     120                 :          0 :         what = fstab_node_to_udev_node(keydev);
     121         [ #  # ]:          0 :         if (!what)
     122                 :          0 :                 return -ENOMEM;
     123                 :            : 
     124         [ #  # ]:          0 :         fprintf(f,
     125                 :            :                 "[Unit]\n"
     126                 :            :                 "DefaultDependencies=no\n\n"
     127                 :            :                 "[Mount]\n"
     128                 :            :                 "What=%s\n"
     129                 :            :                 "Where=%s\n"
     130                 :            :                 "Options=ro%s\n", what, where, canfail ? ",nofail" : "");
     131                 :            : 
     132         [ #  # ]:          0 :         if (keydev_timeout) {
     133                 :          0 :                 r = parse_sec_fix_0(keydev_timeout, &timeout_us);
     134         [ #  # ]:          0 :                 if (r >= 0) {
     135                 :          0 :                         r = unit_name_from_path(what, ".device", &device_unit);
     136         [ #  # ]:          0 :                         if (r < 0)
     137         [ #  # ]:          0 :                                 return log_error_errno(r, "Failed to generate unit name: %m");
     138                 :            : 
     139                 :          0 :                         r = write_drop_in_format(arg_dest, device_unit, 90, "device-timeout",
     140                 :            :                                 "# Automatically generated by systemd-cryptsetup-generator \n\n"
     141                 :            :                                 "[Unit]\nJobRunningTimeoutSec=%s", keydev_timeout);
     142         [ #  # ]:          0 :                         if (r < 0)
     143         [ #  # ]:          0 :                                 return log_error_errno(r, "Failed to write device drop-in: %m");
     144                 :            : 
     145                 :            :                 } else
     146         [ #  # ]:          0 :                         log_warning_errno(r, "Failed to parse %s, ignoring: %m", keydev_timeout);
     147                 :            : 
     148                 :            :         }
     149                 :            : 
     150                 :          0 :         r = fflush_and_check(f);
     151         [ #  # ]:          0 :         if (r < 0)
     152                 :          0 :                 return r;
     153                 :            : 
     154                 :          0 :         *unit = TAKE_PTR(u);
     155                 :          0 :         *mount = TAKE_PTR(where);
     156                 :            : 
     157                 :          0 :         return 0;
     158                 :            : }
     159                 :            : 
     160                 :          0 : static int print_dependencies(FILE *f, const char* device_path) {
     161                 :            :         int r;
     162                 :            : 
     163         [ #  # ]:          0 :         if (STR_IN_SET(device_path, "-", "none"))
     164                 :            :                 /* None, nothing to do */
     165                 :          0 :                 return 0;
     166                 :            : 
     167   [ #  #  #  #  :          0 :         if (PATH_IN_SET(device_path, "/dev/urandom", "/dev/random", "/dev/hw_random")) {
             #  #  #  # ]
     168                 :            :                 /* RNG device, add random dep */
     169                 :          0 :                 fputs("After=systemd-random-seed.service\n", f);
     170                 :          0 :                 return 0;
     171                 :            :         }
     172                 :            : 
     173                 :          0 :         _cleanup_free_ char *udev_node = fstab_node_to_udev_node(device_path);
     174         [ #  # ]:          0 :         if (!udev_node)
     175                 :          0 :                 return log_oom();
     176                 :            : 
     177         [ #  # ]:          0 :         if (path_equal(udev_node, "/dev/null"))
     178                 :          0 :                 return 0;
     179                 :            : 
     180         [ #  # ]:          0 :         if (path_startswith(udev_node, "/dev/")) {
     181                 :            :                 /* We are dealing with a block device, add dependency for correspoding unit */
     182         [ #  # ]:          0 :                 _cleanup_free_ char *unit = NULL;
     183                 :            : 
     184                 :          0 :                 r = unit_name_from_path(udev_node, ".device", &unit);
     185         [ #  # ]:          0 :                 if (r < 0)
     186         [ #  # ]:          0 :                         return log_error_errno(r, "Failed to generate unit name: %m");
     187                 :            : 
     188                 :          0 :                 fprintf(f, "After=%1$s\nRequires=%1$s\n", unit);
     189                 :            :         } else {
     190                 :            :                 /* Regular file, add mount dependency */
     191         [ #  # ]:          0 :                 _cleanup_free_ char *escaped_path = specifier_escape(device_path);
     192         [ #  # ]:          0 :                 if (!escaped_path)
     193                 :          0 :                         return log_oom();
     194                 :            : 
     195                 :          0 :                 fprintf(f, "RequiresMountsFor=%s\n", escaped_path);
     196                 :            :         }
     197                 :            : 
     198                 :          0 :         return 0;
     199                 :            : }
     200                 :            : 
     201                 :          0 : static int create_disk(
     202                 :            :                 const char *name,
     203                 :            :                 const char *device,
     204                 :            :                 const char *password,
     205                 :            :                 const char *keydev,
     206                 :            :                 const char *options) {
     207                 :            : 
     208                 :          0 :         _cleanup_free_ char *n = NULL, *d = NULL, *u = NULL, *e = NULL,
     209                 :          0 :                 *keydev_mount = NULL, *keyfile_timeout_value = NULL, *password_escaped = NULL,
     210                 :          0 :                 *filtered = NULL, *u_escaped = NULL, *filtered_escaped = NULL, *name_escaped = NULL, *header_path = NULL;
     211                 :          0 :         _cleanup_fclose_ FILE *f = NULL;
     212                 :            :         const char *dmname;
     213                 :            :         bool noauto, nofail, tmp, swap, netdev;
     214                 :            :         int r, detached_header, keyfile_can_timeout;
     215                 :            : 
     216         [ #  # ]:          0 :         assert(name);
     217         [ #  # ]:          0 :         assert(device);
     218                 :            : 
     219                 :          0 :         noauto = fstab_test_yes_no_option(options, "noauto\0" "auto\0");
     220                 :          0 :         nofail = fstab_test_yes_no_option(options, "nofail\0" "fail\0");
     221                 :          0 :         tmp = fstab_test_option(options, "tmp\0");
     222                 :          0 :         swap = fstab_test_option(options, "swap\0");
     223                 :          0 :         netdev = fstab_test_option(options, "_netdev\0");
     224                 :            : 
     225                 :          0 :         keyfile_can_timeout = fstab_filter_options(options, "keyfile-timeout\0", NULL, &keyfile_timeout_value, NULL);
     226         [ #  # ]:          0 :         if (keyfile_can_timeout < 0)
     227         [ #  # ]:          0 :                 return log_error_errno(keyfile_can_timeout, "Failed to parse keyfile-timeout= option value: %m");
     228                 :            : 
     229                 :          0 :         detached_header = fstab_filter_options(options, "header\0", NULL, &header_path, NULL);
     230         [ #  # ]:          0 :         if (detached_header < 0)
     231         [ #  # ]:          0 :                 return log_error_errno(detached_header, "Failed to parse header= option value: %m");
     232                 :            : 
     233   [ #  #  #  # ]:          0 :         if (tmp && swap)
     234         [ #  # ]:          0 :                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
     235                 :            :                                        "Device '%s' cannot be both 'tmp' and 'swap'. Ignoring.",
     236                 :            :                                        name);
     237                 :            : 
     238                 :          0 :         name_escaped = specifier_escape(name);
     239         [ #  # ]:          0 :         if (!name_escaped)
     240                 :          0 :                 return log_oom();
     241                 :            : 
     242                 :          0 :         e = unit_name_escape(name);
     243         [ #  # ]:          0 :         if (!e)
     244                 :          0 :                 return log_oom();
     245                 :            : 
     246                 :          0 :         u = fstab_node_to_udev_node(device);
     247         [ #  # ]:          0 :         if (!u)
     248                 :          0 :                 return log_oom();
     249                 :            : 
     250                 :          0 :         r = unit_name_build("systemd-cryptsetup", e, ".service", &n);
     251         [ #  # ]:          0 :         if (r < 0)
     252         [ #  # ]:          0 :                 return log_error_errno(r, "Failed to generate unit name: %m");
     253                 :            : 
     254                 :          0 :         u_escaped = specifier_escape(u);
     255         [ #  # ]:          0 :         if (!u_escaped)
     256                 :          0 :                 return log_oom();
     257                 :            : 
     258                 :          0 :         r = unit_name_from_path(u, ".device", &d);
     259         [ #  # ]:          0 :         if (r < 0)
     260         [ #  # ]:          0 :                 return log_error_errno(r, "Failed to generate unit name: %m");
     261                 :            : 
     262   [ #  #  #  # ]:          0 :         if (keydev && !password)
     263         [ #  # ]:          0 :                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
     264                 :            :                                        "Key device is specified, but path to the password file is missing.");
     265                 :            : 
     266                 :          0 :         r = generator_open_unit_file(arg_dest, NULL, n, &f);
     267         [ #  # ]:          0 :         if (r < 0)
     268                 :          0 :                 return r;
     269                 :            : 
     270         [ #  # ]:          0 :         fprintf(f,
     271                 :            :                 "[Unit]\n"
     272                 :            :                 "Description=Cryptography Setup for %%I\n"
     273                 :            :                 "Documentation=man:crypttab(5) man:systemd-cryptsetup-generator(8) man:systemd-cryptsetup@.service(8)\n"
     274                 :            :                 "SourcePath=/etc/crypttab\n"
     275                 :            :                 "DefaultDependencies=no\n"
     276                 :            :                 "Conflicts=umount.target\n"
     277                 :            :                 "IgnoreOnIsolate=true\n"
     278                 :            :                 "After=%s\n",
     279                 :            :                 netdev ? "remote-fs-pre.target" : "cryptsetup-pre.target");
     280                 :            : 
     281         [ #  # ]:          0 :         if (password) {
     282                 :          0 :                 password_escaped = specifier_escape(password);
     283         [ #  # ]:          0 :                 if (!password_escaped)
     284                 :          0 :                         return log_oom();
     285                 :            :         }
     286                 :            : 
     287         [ #  # ]:          0 :         if (keydev) {
     288   [ #  #  #  # ]:          0 :                 _cleanup_free_ char *unit = NULL, *p = NULL;
     289                 :            : 
     290                 :          0 :                 r = generate_keydev_mount(name, keydev, keyfile_timeout_value, keyfile_can_timeout > 0, &unit, &keydev_mount);
     291         [ #  # ]:          0 :                 if (r < 0)
     292         [ #  # ]:          0 :                         return log_error_errno(r, "Failed to generate keydev mount unit: %m");
     293                 :            : 
     294                 :          0 :                 p = path_join(keydev_mount, password_escaped);
     295         [ #  # ]:          0 :                 if (!p)
     296                 :          0 :                         return log_oom();
     297                 :            : 
     298                 :          0 :                 free_and_replace(password_escaped, p);
     299                 :            : 
     300                 :          0 :                 fprintf(f, "After=%s\n", unit);
     301         [ #  # ]:          0 :                 if (keyfile_can_timeout > 0)
     302                 :          0 :                         fprintf(f, "Wants=%s\n", unit);
     303                 :            :                 else
     304                 :          0 :                         fprintf(f, "Requires=%s\n", unit);
     305                 :            :         }
     306                 :            : 
     307         [ #  # ]:          0 :         if (!nofail)
     308         [ #  # ]:          0 :                 fprintf(f,
     309                 :            :                         "Before=%s\n",
     310                 :            :                         netdev ? "remote-cryptsetup.target" : "cryptsetup.target");
     311                 :            : 
     312   [ #  #  #  # ]:          0 :         if (password && !keydev) {
     313                 :          0 :                 r = print_dependencies(f, password);
     314         [ #  # ]:          0 :                 if (r < 0)
     315                 :          0 :                         return r;
     316                 :            :         }
     317                 :            : 
     318                 :            :         /* Check if a header option was specified */
     319         [ #  # ]:          0 :         if (detached_header > 0) {
     320                 :          0 :                 r = print_dependencies(f, header_path);
     321         [ #  # ]:          0 :                 if (r < 0)
     322                 :          0 :                         return r;
     323                 :            :         }
     324                 :            : 
     325         [ #  # ]:          0 :         if (path_startswith(u, "/dev/")) {
     326                 :          0 :                 fprintf(f,
     327                 :            :                         "BindsTo=%s\n"
     328                 :            :                         "After=%s\n"
     329                 :            :                         "Before=umount.target\n",
     330                 :            :                         d, d);
     331                 :            : 
     332         [ #  # ]:          0 :                 if (swap)
     333                 :          0 :                         fputs("Before=dev-mapper-%i.swap\n",
     334                 :            :                               f);
     335                 :            :         } else
     336                 :            :                 /* For loopback devices, add systemd-tmpfiles-setup-dev.service
     337                 :            :                    dependency to ensure that loopback support is available in
     338                 :            :                    the kernel (/dev/loop-control needs to exist) */
     339                 :          0 :                 fprintf(f,
     340                 :            :                         "RequiresMountsFor=%s\n"
     341                 :            :                         "Requires=systemd-tmpfiles-setup-dev.service\n"
     342                 :            :                         "After=systemd-tmpfiles-setup-dev.service\n",
     343                 :            :                         u_escaped);
     344                 :            : 
     345                 :          0 :         r = generator_write_timeouts(arg_dest, device, name, options, &filtered);
     346         [ #  # ]:          0 :         if (r < 0)
     347                 :          0 :                 return r;
     348                 :            : 
     349         [ #  # ]:          0 :         if (filtered) {
     350                 :          0 :                 filtered_escaped = specifier_escape(filtered);
     351         [ #  # ]:          0 :                 if (!filtered_escaped)
     352                 :          0 :                         return log_oom();
     353                 :            :         }
     354                 :            : 
     355                 :          0 :         fprintf(f,
     356                 :            :                 "\n[Service]\n"
     357                 :            :                 "Type=oneshot\n"
     358                 :            :                 "RemainAfterExit=yes\n"
     359                 :            :                 "TimeoutSec=0\n" /* the binary handles timeouts anyway */
     360                 :            :                 "KeyringMode=shared\n" /* make sure we can share cached keys among instances */
     361                 :            :                 "OOMScoreAdjust=500\n" /* unlocking can allocate a lot of memory if Argon2 is used */
     362                 :            :                 "ExecStart=" SYSTEMD_CRYPTSETUP_PATH " attach '%s' '%s' '%s' '%s'\n"
     363                 :            :                 "ExecStop=" SYSTEMD_CRYPTSETUP_PATH " detach '%s'\n",
     364                 :            :                 name_escaped, u_escaped, strempty(password_escaped), strempty(filtered_escaped),
     365                 :            :                 name_escaped);
     366                 :            : 
     367         [ #  # ]:          0 :         if (tmp)
     368                 :          0 :                 fprintf(f,
     369                 :            :                         "ExecStartPost=/sbin/mke2fs '/dev/mapper/%s'\n",
     370                 :            :                         name_escaped);
     371                 :            : 
     372         [ #  # ]:          0 :         if (swap)
     373                 :          0 :                 fprintf(f,
     374                 :            :                         "ExecStartPost=/sbin/mkswap '/dev/mapper/%s'\n",
     375                 :            :                         name_escaped);
     376                 :            : 
     377         [ #  # ]:          0 :         if (keydev)
     378                 :          0 :                 fprintf(f,
     379                 :            :                         "ExecStartPost=-" UMOUNT_PATH " %s\n\n",
     380                 :            :                         keydev_mount);
     381                 :            : 
     382                 :          0 :         r = fflush_and_check(f);
     383         [ #  # ]:          0 :         if (r < 0)
     384         [ #  # ]:          0 :                 return log_error_errno(r, "Failed to write unit file %s: %m", n);
     385                 :            : 
     386         [ #  # ]:          0 :         if (!noauto) {
     387   [ #  #  #  # ]:          0 :                 r = generator_add_symlink(arg_dest,
     388                 :            :                                           netdev ? "remote-cryptsetup.target" : "cryptsetup.target",
     389                 :            :                                           nofail ? "wants" : "requires", n);
     390         [ #  # ]:          0 :                 if (r < 0)
     391                 :          0 :                         return r;
     392                 :            :         }
     393                 :            : 
     394   [ #  #  #  #  :          0 :         dmname = strjoina("dev-mapper-", e, ".device");
          #  #  #  #  #  
                #  #  # ]
     395                 :          0 :         r = generator_add_symlink(arg_dest, dmname, "requires", n);
     396         [ #  # ]:          0 :         if (r < 0)
     397                 :          0 :                 return r;
     398                 :            : 
     399   [ #  #  #  # ]:          0 :         if (!noauto && !nofail) {
     400                 :          0 :                 r = write_drop_in(arg_dest, dmname, 90, "device-timeout",
     401                 :            :                                   "# Automatically generated by systemd-cryptsetup-generator \n\n"
     402                 :            :                                   "[Unit]\nJobTimeoutSec=0");
     403         [ #  # ]:          0 :                 if (r < 0)
     404         [ #  # ]:          0 :                         return log_error_errno(r, "Failed to write device drop-in: %m");
     405                 :            :         }
     406                 :            : 
     407                 :          0 :         return 0;
     408                 :            : }
     409                 :            : 
     410                 :          0 : static crypto_device* crypt_device_free(crypto_device *d) {
     411         [ #  # ]:          0 :         if (!d)
     412                 :          0 :                 return NULL;
     413                 :            : 
     414                 :          0 :         free(d->uuid);
     415                 :          0 :         free(d->keyfile);
     416                 :          0 :         free(d->keydev);
     417                 :          0 :         free(d->name);
     418                 :          0 :         free(d->options);
     419                 :          0 :         return mfree(d);
     420                 :            : }
     421                 :            : 
     422                 :          0 : static crypto_device *get_crypto_device(const char *uuid) {
     423                 :            :         int r;
     424                 :            :         crypto_device *d;
     425                 :            : 
     426         [ #  # ]:          0 :         assert(uuid);
     427                 :            : 
     428                 :          0 :         d = hashmap_get(arg_disks, uuid);
     429         [ #  # ]:          0 :         if (!d) {
     430                 :          0 :                 d = new0(struct crypto_device, 1);
     431         [ #  # ]:          0 :                 if (!d)
     432                 :          0 :                         return NULL;
     433                 :            : 
     434                 :          0 :                 d->uuid = strdup(uuid);
     435         [ #  # ]:          0 :                 if (!d->uuid)
     436                 :          0 :                         return mfree(d);
     437                 :            : 
     438                 :          0 :                 r = hashmap_put(arg_disks, d->uuid, d);
     439         [ #  # ]:          0 :                 if (r < 0) {
     440                 :          0 :                         free(d->uuid);
     441                 :          0 :                         return mfree(d);
     442                 :            :                 }
     443                 :            :         }
     444                 :            : 
     445                 :          0 :         return d;
     446                 :            : }
     447                 :            : 
     448                 :          0 : static int parse_proc_cmdline_item(const char *key, const char *value, void *data) {
     449                 :          0 :         _cleanup_free_ char *uuid = NULL, *uuid_value = NULL;
     450                 :            :         crypto_device *d;
     451                 :            :         int r;
     452                 :            : 
     453         [ #  # ]:          0 :         if (streq(key, "luks")) {
     454                 :            : 
     455         [ #  # ]:          0 :                 r = value ? parse_boolean(value) : 1;
     456         [ #  # ]:          0 :                 if (r < 0)
     457         [ #  # ]:          0 :                         log_warning("Failed to parse luks= kernel command line switch %s. Ignoring.", value);
     458                 :            :                 else
     459                 :          0 :                         arg_enabled = r;
     460                 :            : 
     461         [ #  # ]:          0 :         } else if (streq(key, "luks.crypttab")) {
     462                 :            : 
     463         [ #  # ]:          0 :                 r = value ? parse_boolean(value) : 1;
     464         [ #  # ]:          0 :                 if (r < 0)
     465         [ #  # ]:          0 :                         log_warning("Failed to parse luks.crypttab= kernel command line switch %s. Ignoring.", value);
     466                 :            :                 else
     467                 :          0 :                         arg_read_crypttab = r;
     468                 :            : 
     469         [ #  # ]:          0 :         } else if (streq(key, "luks.uuid")) {
     470                 :            : 
     471         [ #  # ]:          0 :                 if (proc_cmdline_value_missing(key, value))
     472                 :          0 :                         return 0;
     473                 :            : 
     474         [ #  # ]:          0 :                 d = get_crypto_device(startswith(value, "luks-") ? value+5 : value);
     475         [ #  # ]:          0 :                 if (!d)
     476                 :          0 :                         return log_oom();
     477                 :            : 
     478                 :          0 :                 d->create = arg_whitelist = true;
     479                 :            : 
     480         [ #  # ]:          0 :         } else if (streq(key, "luks.options")) {
     481                 :            : 
     482         [ #  # ]:          0 :                 if (proc_cmdline_value_missing(key, value))
     483                 :          0 :                         return 0;
     484                 :            : 
     485                 :          0 :                 r = sscanf(value, "%m[0-9a-fA-F-]=%ms", &uuid, &uuid_value);
     486         [ #  # ]:          0 :                 if (r == 2) {
     487                 :          0 :                         d = get_crypto_device(uuid);
     488         [ #  # ]:          0 :                         if (!d)
     489                 :          0 :                                 return log_oom();
     490                 :            : 
     491                 :          0 :                         free_and_replace(d->options, uuid_value);
     492         [ #  # ]:          0 :                 } else if (free_and_strdup(&arg_default_options, value) < 0)
     493                 :          0 :                         return log_oom();
     494                 :            : 
     495         [ #  # ]:          0 :         } else if (streq(key, "luks.key")) {
     496                 :            :                 size_t n;
     497   [ #  #  #  # ]:          0 :                 _cleanup_free_ char *keyfile = NULL, *keydev = NULL;
     498                 :            :                 const char *keyspec;
     499                 :            : 
     500         [ #  # ]:          0 :                 if (proc_cmdline_value_missing(key, value))
     501                 :          0 :                         return 0;
     502                 :            : 
     503                 :          0 :                 n = strspn(value, LETTERS DIGITS "-");
     504         [ #  # ]:          0 :                 if (value[n] != '=') {
     505         [ #  # ]:          0 :                         if (free_and_strdup(&arg_default_keyfile, value) < 0)
     506                 :          0 :                                  return log_oom();
     507                 :          0 :                         return 0;
     508                 :            :                 }
     509                 :            : 
     510                 :          0 :                 uuid = strndup(value, n);
     511         [ #  # ]:          0 :                 if (!uuid)
     512                 :          0 :                         return log_oom();
     513                 :            : 
     514         [ #  # ]:          0 :                 if (!id128_is_valid(uuid)) {
     515         [ #  # ]:          0 :                         log_warning("Failed to parse luks.key= kernel command line switch. UUID is invalid, ignoring.");
     516                 :          0 :                         return 0;
     517                 :            :                 }
     518                 :            : 
     519                 :          0 :                 d = get_crypto_device(uuid);
     520         [ #  # ]:          0 :                 if (!d)
     521                 :          0 :                         return log_oom();
     522                 :            : 
     523                 :          0 :                 keyspec = value + n + 1;
     524                 :          0 :                 r = split_keyspec(keyspec, &keyfile, &keydev);
     525         [ #  # ]:          0 :                 if (r < 0)
     526                 :          0 :                         return r;
     527                 :            : 
     528                 :          0 :                 free_and_replace(d->keyfile, keyfile);
     529                 :          0 :                 free_and_replace(d->keydev, keydev);
     530                 :            : 
     531         [ #  # ]:          0 :         } else if (streq(key, "luks.name")) {
     532                 :            : 
     533         [ #  # ]:          0 :                 if (proc_cmdline_value_missing(key, value))
     534                 :          0 :                         return 0;
     535                 :            : 
     536                 :          0 :                 r = sscanf(value, "%m[0-9a-fA-F-]=%ms", &uuid, &uuid_value);
     537         [ #  # ]:          0 :                 if (r == 2) {
     538                 :          0 :                         d = get_crypto_device(uuid);
     539         [ #  # ]:          0 :                         if (!d)
     540                 :          0 :                                 return log_oom();
     541                 :            : 
     542                 :          0 :                         d->create = arg_whitelist = true;
     543                 :            : 
     544                 :          0 :                         free_and_replace(d->name, uuid_value);
     545                 :            :                 } else
     546         [ #  # ]:          0 :                         log_warning("Failed to parse luks name switch %s. Ignoring.", value);
     547                 :            :         }
     548                 :            : 
     549                 :          0 :         return 0;
     550                 :            : }
     551                 :            : 
     552                 :          0 : static int add_crypttab_devices(void) {
     553                 :          0 :         _cleanup_fclose_ FILE *f = NULL;
     554                 :          0 :         unsigned crypttab_line = 0;
     555                 :            :         struct stat st;
     556                 :            :         int r;
     557                 :            : 
     558         [ #  # ]:          0 :         if (!arg_read_crypttab)
     559                 :          0 :                 return 0;
     560                 :            : 
     561                 :          0 :         r = fopen_unlocked("/etc/crypttab", "re", &f);
     562         [ #  # ]:          0 :         if (r < 0) {
     563         [ #  # ]:          0 :                 if (errno != ENOENT)
     564         [ #  # ]:          0 :                         log_error_errno(errno, "Failed to open /etc/crypttab: %m");
     565                 :          0 :                 return 0;
     566                 :            :         }
     567                 :            : 
     568         [ #  # ]:          0 :         if (fstat(fileno(f), &st) < 0) {
     569         [ #  # ]:          0 :                 log_error_errno(errno, "Failed to stat /etc/crypttab: %m");
     570                 :          0 :                 return 0;
     571                 :            :         }
     572                 :            : 
     573                 :          0 :         for (;;) {
     574   [ #  #  #  #  :          0 :                 _cleanup_free_ char *line = NULL, *name = NULL, *device = NULL, *keyspec = NULL, *options = NULL, *keyfile = NULL, *keydev = NULL;
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
             #  #  #  # ]
     575                 :          0 :                 crypto_device *d = NULL;
     576                 :            :                 char *l, *uuid;
     577                 :            :                 int k;
     578                 :            : 
     579                 :          0 :                 r = read_line(f, LONG_LINE_MAX, &line);
     580         [ #  # ]:          0 :                 if (r < 0)
     581         [ #  # ]:          0 :                         return log_error_errno(r, "Failed to read /etc/crypttab: %m");
     582         [ #  # ]:          0 :                 if (r == 0)
     583                 :          0 :                         break;
     584                 :            : 
     585                 :          0 :                 crypttab_line++;
     586                 :            : 
     587                 :          0 :                 l = strstrip(line);
     588   [ #  #  #  # ]:          0 :                 if (IN_SET(l[0], 0, '#'))
     589                 :          0 :                         continue;
     590                 :            : 
     591                 :          0 :                 k = sscanf(l, "%ms %ms %ms %ms", &name, &device, &keyspec, &options);
     592   [ #  #  #  # ]:          0 :                 if (k < 2 || k > 4) {
     593         [ #  # ]:          0 :                         log_error("Failed to parse /etc/crypttab:%u, ignoring.", crypttab_line);
     594                 :          0 :                         continue;
     595                 :            :                 }
     596                 :            : 
     597                 :          0 :                 uuid = startswith(device, "UUID=");
     598         [ #  # ]:          0 :                 if (!uuid)
     599                 :          0 :                         uuid = path_startswith(device, "/dev/disk/by-uuid/");
     600         [ #  # ]:          0 :                 if (!uuid)
     601                 :          0 :                         uuid = startswith(name, "luks-");
     602         [ #  # ]:          0 :                 if (uuid)
     603                 :          0 :                         d = hashmap_get(arg_disks, uuid);
     604                 :            : 
     605   [ #  #  #  # ]:          0 :                 if (arg_whitelist && !d) {
     606         [ #  # ]:          0 :                         log_info("Not creating device '%s' because it was not specified on the kernel command line.", name);
     607                 :          0 :                         continue;
     608                 :            :                 }
     609                 :            : 
     610                 :          0 :                 r = split_keyspec(keyspec, &keyfile, &keydev);
     611         [ #  # ]:          0 :                 if (r < 0)
     612                 :          0 :                         return r;
     613                 :            : 
     614   [ #  #  #  # ]:          0 :                 r = create_disk(name, device, keyfile, keydev, (d && d->options) ? d->options : options);
     615         [ #  # ]:          0 :                 if (r < 0)
     616                 :          0 :                         return r;
     617                 :            : 
     618         [ #  # ]:          0 :                 if (d)
     619                 :          0 :                         d->create = false;
     620                 :            :         }
     621                 :            : 
     622                 :          0 :         return 0;
     623                 :            : }
     624                 :            : 
     625                 :          0 : static int add_proc_cmdline_devices(void) {
     626                 :            :         int r;
     627                 :            :         Iterator i;
     628                 :            :         crypto_device *d;
     629                 :            : 
     630         [ #  # ]:          0 :         HASHMAP_FOREACH(d, arg_disks, i) {
     631                 :            :                 const char *options;
     632      [ #  #  # ]:          0 :                 _cleanup_free_ char *device = NULL;
     633                 :            : 
     634         [ #  # ]:          0 :                 if (!d->create)
     635                 :          0 :                         continue;
     636                 :            : 
     637         [ #  # ]:          0 :                 if (!d->name) {
     638                 :          0 :                         d->name = strjoin("luks-", d->uuid);
     639         [ #  # ]:          0 :                         if (!d->name)
     640                 :          0 :                                 return log_oom();
     641                 :            :                 }
     642                 :            : 
     643                 :          0 :                 device = strjoin("UUID=", d->uuid);
     644         [ #  # ]:          0 :                 if (!device)
     645                 :          0 :                         return log_oom();
     646                 :            : 
     647         [ #  # ]:          0 :                 if (d->options)
     648                 :          0 :                         options = d->options;
     649         [ #  # ]:          0 :                 else if (arg_default_options)
     650                 :          0 :                         options = arg_default_options;
     651                 :            :                 else
     652                 :          0 :                         options = "timeout=0";
     653                 :            : 
     654         [ #  # ]:          0 :                 r = create_disk(d->name, device, d->keyfile ?: arg_default_keyfile, d->keydev, options);
     655         [ #  # ]:          0 :                 if (r < 0)
     656                 :          0 :                         return r;
     657                 :            :         }
     658                 :            : 
     659                 :          0 :         return 0;
     660                 :            : }
     661                 :            : 
     662                 :          0 : DEFINE_PRIVATE_HASH_OPS_WITH_VALUE_DESTRUCTOR(crypt_device_hash_ops, char, string_hash_func, string_compare_func,
     663                 :            :                                               crypto_device, crypt_device_free);
     664                 :            : 
     665                 :          0 : static int run(const char *dest, const char *dest_early, const char *dest_late) {
     666                 :            :         int r;
     667                 :            : 
     668         [ #  # ]:          0 :         assert_se(arg_dest = dest);
     669                 :            : 
     670                 :          0 :         arg_disks = hashmap_new(&crypt_device_hash_ops);
     671         [ #  # ]:          0 :         if (!arg_disks)
     672                 :          0 :                 return log_oom();
     673                 :            : 
     674                 :          0 :         r = proc_cmdline_parse(parse_proc_cmdline_item, NULL, PROC_CMDLINE_STRIP_RD_PREFIX);
     675         [ #  # ]:          0 :         if (r < 0)
     676         [ #  # ]:          0 :                 return log_warning_errno(r, "Failed to parse kernel command line: %m");
     677                 :            : 
     678         [ #  # ]:          0 :         if (!arg_enabled)
     679                 :          0 :                 return 0;
     680                 :            : 
     681                 :          0 :         r = add_crypttab_devices();
     682         [ #  # ]:          0 :         if (r < 0)
     683                 :          0 :                 return r;
     684                 :            : 
     685                 :          0 :         r = add_proc_cmdline_devices();
     686         [ #  # ]:          0 :         if (r < 0)
     687                 :          0 :                 return r;
     688                 :            : 
     689                 :          0 :         return 0;
     690                 :            : }
     691                 :            : 
     692   [ #  #  #  #  :          0 : DEFINE_MAIN_GENERATOR_FUNCTION(run);
          #  #  #  #  #  
                #  #  # ]

Generated by: LCOV version 1.14