The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/geom/eli/g_eli_ctl.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * Copyright (c) 2005-2011 Pawel Jakub Dawidek <pawel@dawidek.net>
    3  * All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer.
   10  * 2. Redistributions in binary form must reproduce the above copyright
   11  *    notice, this list of conditions and the following disclaimer in the
   12  *    documentation and/or other materials provided with the distribution.
   13  *
   14  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
   15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
   18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   24  * SUCH DAMAGE.
   25  */
   26 
   27 #include <sys/cdefs.h>
   28 __FBSDID("$FreeBSD: releng/10.0/sys/geom/eli/g_eli_ctl.c 257718 2013-11-05 19:58:40Z delphij $");
   29 
   30 #include <sys/param.h>
   31 #include <sys/systm.h>
   32 #include <sys/kernel.h>
   33 #include <sys/module.h>
   34 #include <sys/lock.h>
   35 #include <sys/mutex.h>
   36 #include <sys/bio.h>
   37 #include <sys/sysctl.h>
   38 #include <sys/malloc.h>
   39 #include <sys/kthread.h>
   40 #include <sys/proc.h>
   41 #include <sys/sched.h>
   42 #include <sys/uio.h>
   43 
   44 #include <vm/uma.h>
   45 
   46 #include <geom/geom.h>
   47 #include <geom/eli/g_eli.h>
   48 
   49 
   50 MALLOC_DECLARE(M_ELI);
   51 
   52 
   53 static void
   54 g_eli_ctl_attach(struct gctl_req *req, struct g_class *mp)
   55 {
   56         struct g_eli_metadata md;
   57         struct g_provider *pp;
   58         const char *name;
   59         u_char *key, mkey[G_ELI_DATAIVKEYLEN];
   60         int *nargs, *detach, *readonly;
   61         int keysize, error;
   62         u_int nkey;
   63 
   64         g_topology_assert();
   65 
   66         nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
   67         if (nargs == NULL) {
   68                 gctl_error(req, "No '%s' argument.", "nargs");
   69                 return;
   70         }
   71         if (*nargs != 1) {
   72                 gctl_error(req, "Invalid number of arguments.");
   73                 return;
   74         }
   75 
   76         detach = gctl_get_paraml(req, "detach", sizeof(*detach));
   77         if (detach == NULL) {
   78                 gctl_error(req, "No '%s' argument.", "detach");
   79                 return;
   80         }
   81 
   82         readonly = gctl_get_paraml(req, "readonly", sizeof(*readonly));
   83         if (readonly == NULL) {
   84                 gctl_error(req, "No '%s' argument.", "readonly");
   85                 return;
   86         }
   87 
   88         name = gctl_get_asciiparam(req, "arg0");
   89         if (name == NULL) {
   90                 gctl_error(req, "No 'arg%u' argument.", 0);
   91                 return;
   92         }
   93         if (strncmp(name, "/dev/", strlen("/dev/")) == 0)
   94                 name += strlen("/dev/");
   95         pp = g_provider_by_name(name);
   96         if (pp == NULL) {
   97                 gctl_error(req, "Provider %s is invalid.", name);
   98                 return;
   99         }
  100         error = g_eli_read_metadata(mp, pp, &md);
  101         if (error != 0) {
  102                 gctl_error(req, "Cannot read metadata from %s (error=%d).",
  103                     name, error);
  104                 return;
  105         }
  106         if (md.md_keys == 0x00) {
  107                 bzero(&md, sizeof(md));
  108                 gctl_error(req, "No valid keys on %s.", pp->name);
  109                 return;
  110         }
  111 
  112         key = gctl_get_param(req, "key", &keysize);
  113         if (key == NULL || keysize != G_ELI_USERKEYLEN) {
  114                 bzero(&md, sizeof(md));
  115                 gctl_error(req, "No '%s' argument.", "key");
  116                 return;
  117         }
  118 
  119         error = g_eli_mkey_decrypt(&md, key, mkey, &nkey);
  120         bzero(key, keysize);
  121         if (error == -1) {
  122                 bzero(&md, sizeof(md));
  123                 gctl_error(req, "Wrong key for %s.", pp->name);
  124                 return;
  125         } else if (error > 0) {
  126                 bzero(&md, sizeof(md));
  127                 gctl_error(req, "Cannot decrypt Master Key for %s (error=%d).",
  128                     pp->name, error);
  129                 return;
  130         }
  131         G_ELI_DEBUG(1, "Using Master Key %u for %s.", nkey, pp->name);
  132 
  133         if (*detach && *readonly) {
  134                 bzero(&md, sizeof(md));
  135                 gctl_error(req, "Options -d and -r are mutually exclusive.");
  136                 return;
  137         }
  138         if (*detach)
  139                 md.md_flags |= G_ELI_FLAG_WO_DETACH;
  140         if (*readonly)
  141                 md.md_flags |= G_ELI_FLAG_RO;
  142         g_eli_create(req, mp, pp, &md, mkey, nkey);
  143         bzero(mkey, sizeof(mkey));
  144         bzero(&md, sizeof(md));
  145 }
  146 
  147 static struct g_eli_softc *
  148 g_eli_find_device(struct g_class *mp, const char *prov)
  149 {
  150         struct g_eli_softc *sc;
  151         struct g_geom *gp;
  152         struct g_provider *pp;
  153         struct g_consumer *cp;
  154 
  155         if (strncmp(prov, "/dev/", strlen("/dev/")) == 0)
  156                 prov += strlen("/dev/");
  157         LIST_FOREACH(gp, &mp->geom, geom) {
  158                 sc = gp->softc;
  159                 if (sc == NULL)
  160                         continue;
  161                 pp = LIST_FIRST(&gp->provider);
  162                 if (pp != NULL && strcmp(pp->name, prov) == 0)
  163                         return (sc);
  164                 cp = LIST_FIRST(&gp->consumer);
  165                 if (cp != NULL && cp->provider != NULL &&
  166                     strcmp(cp->provider->name, prov) == 0) {
  167                         return (sc);
  168                 }
  169         }
  170         return (NULL);
  171 }
  172 
  173 static void
  174 g_eli_ctl_detach(struct gctl_req *req, struct g_class *mp)
  175 {
  176         struct g_eli_softc *sc;
  177         int *force, *last, *nargs, error;
  178         const char *prov;
  179         char param[16];
  180         int i;
  181 
  182         g_topology_assert();
  183 
  184         nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
  185         if (nargs == NULL) {
  186                 gctl_error(req, "No '%s' argument.", "nargs");
  187                 return;
  188         }
  189         if (*nargs <= 0) {
  190                 gctl_error(req, "Missing device(s).");
  191                 return;
  192         }
  193         force = gctl_get_paraml(req, "force", sizeof(*force));
  194         if (force == NULL) {
  195                 gctl_error(req, "No '%s' argument.", "force");
  196                 return;
  197         }
  198         last = gctl_get_paraml(req, "last", sizeof(*last));
  199         if (last == NULL) {
  200                 gctl_error(req, "No '%s' argument.", "last");
  201                 return;
  202         }
  203 
  204         for (i = 0; i < *nargs; i++) {
  205                 snprintf(param, sizeof(param), "arg%d", i);
  206                 prov = gctl_get_asciiparam(req, param);
  207                 if (prov == NULL) {
  208                         gctl_error(req, "No 'arg%d' argument.", i);
  209                         return;
  210                 }
  211                 sc = g_eli_find_device(mp, prov);
  212                 if (sc == NULL) {
  213                         gctl_error(req, "No such device: %s.", prov);
  214                         return;
  215                 }
  216                 if (*last) {
  217                         sc->sc_flags |= G_ELI_FLAG_RW_DETACH;
  218                         sc->sc_geom->access = g_eli_access;
  219                 } else {
  220                         error = g_eli_destroy(sc, *force ? TRUE : FALSE);
  221                         if (error != 0) {
  222                                 gctl_error(req,
  223                                     "Cannot destroy device %s (error=%d).",
  224                                     sc->sc_name, error);
  225                                 return;
  226                         }
  227                 }
  228         }
  229 }
  230 
  231 static void
  232 g_eli_ctl_onetime(struct gctl_req *req, struct g_class *mp)
  233 {
  234         struct g_eli_metadata md;
  235         struct g_provider *pp;
  236         const char *name;
  237         intmax_t *keylen, *sectorsize;
  238         u_char mkey[G_ELI_DATAIVKEYLEN];
  239         int *nargs, *detach;
  240 
  241         g_topology_assert();
  242         bzero(&md, sizeof(md));
  243 
  244         nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
  245         if (nargs == NULL) {
  246                 gctl_error(req, "No '%s' argument.", "nargs");
  247                 return;
  248         }
  249         if (*nargs != 1) {
  250                 gctl_error(req, "Invalid number of arguments.");
  251                 return;
  252         }
  253 
  254         detach = gctl_get_paraml(req, "detach", sizeof(*detach));
  255         if (detach == NULL) {
  256                 gctl_error(req, "No '%s' argument.", "detach");
  257                 return;
  258         }
  259 
  260         strlcpy(md.md_magic, G_ELI_MAGIC, sizeof(md.md_magic));
  261         md.md_version = G_ELI_VERSION;
  262         md.md_flags |= G_ELI_FLAG_ONETIME;
  263         if (*detach)
  264                 md.md_flags |= G_ELI_FLAG_WO_DETACH;
  265 
  266         md.md_ealgo = CRYPTO_ALGORITHM_MIN - 1;
  267         name = gctl_get_asciiparam(req, "aalgo");
  268         if (name == NULL) {
  269                 gctl_error(req, "No '%s' argument.", "aalgo");
  270                 return;
  271         }
  272         if (*name != '\0') {
  273                 md.md_aalgo = g_eli_str2aalgo(name);
  274                 if (md.md_aalgo >= CRYPTO_ALGORITHM_MIN &&
  275                     md.md_aalgo <= CRYPTO_ALGORITHM_MAX) {
  276                         md.md_flags |= G_ELI_FLAG_AUTH;
  277                 } else {
  278                         /*
  279                          * For backward compatibility, check if the -a option
  280                          * was used to provide encryption algorithm.
  281                          */
  282                         md.md_ealgo = g_eli_str2ealgo(name);
  283                         if (md.md_ealgo < CRYPTO_ALGORITHM_MIN ||
  284                             md.md_ealgo > CRYPTO_ALGORITHM_MAX) {
  285                                 gctl_error(req,
  286                                     "Invalid authentication algorithm.");
  287                                 return;
  288                         } else {
  289                                 gctl_error(req, "warning: The -e option, not "
  290                                     "the -a option is now used to specify "
  291                                     "encryption algorithm to use.");
  292                         }
  293                 }
  294         }
  295 
  296         if (md.md_ealgo < CRYPTO_ALGORITHM_MIN ||
  297             md.md_ealgo > CRYPTO_ALGORITHM_MAX) {
  298                 name = gctl_get_asciiparam(req, "ealgo");
  299                 if (name == NULL) {
  300                         gctl_error(req, "No '%s' argument.", "ealgo");
  301                         return;
  302                 }
  303                 md.md_ealgo = g_eli_str2ealgo(name);
  304                 if (md.md_ealgo < CRYPTO_ALGORITHM_MIN ||
  305                     md.md_ealgo > CRYPTO_ALGORITHM_MAX) {
  306                         gctl_error(req, "Invalid encryption algorithm.");
  307                         return;
  308                 }
  309         }
  310 
  311         keylen = gctl_get_paraml(req, "keylen", sizeof(*keylen));
  312         if (keylen == NULL) {
  313                 gctl_error(req, "No '%s' argument.", "keylen");
  314                 return;
  315         }
  316         md.md_keylen = g_eli_keylen(md.md_ealgo, *keylen);
  317         if (md.md_keylen == 0) {
  318                 gctl_error(req, "Invalid '%s' argument.", "keylen");
  319                 return;
  320         }
  321 
  322         /* Not important here. */
  323         md.md_provsize = 0;
  324         /* Not important here. */
  325         bzero(md.md_salt, sizeof(md.md_salt));
  326 
  327         md.md_keys = 0x01;
  328         arc4rand(mkey, sizeof(mkey), 0);
  329 
  330         /* Not important here. */
  331         bzero(md.md_hash, sizeof(md.md_hash));
  332 
  333         name = gctl_get_asciiparam(req, "arg0");
  334         if (name == NULL) {
  335                 gctl_error(req, "No 'arg%u' argument.", 0);
  336                 return;
  337         }
  338         if (strncmp(name, "/dev/", strlen("/dev/")) == 0)
  339                 name += strlen("/dev/");
  340         pp = g_provider_by_name(name);
  341         if (pp == NULL) {
  342                 gctl_error(req, "Provider %s is invalid.", name);
  343                 return;
  344         }
  345 
  346         sectorsize = gctl_get_paraml(req, "sectorsize", sizeof(*sectorsize));
  347         if (sectorsize == NULL) {
  348                 gctl_error(req, "No '%s' argument.", "sectorsize");
  349                 return;
  350         }
  351         if (*sectorsize == 0)
  352                 md.md_sectorsize = pp->sectorsize;
  353         else {
  354                 if (*sectorsize < 0 || (*sectorsize % pp->sectorsize) != 0) {
  355                         gctl_error(req, "Invalid sector size.");
  356                         return;
  357                 }
  358                 if (*sectorsize > PAGE_SIZE) {
  359                         gctl_error(req, "warning: Using sectorsize bigger than "
  360                             "the page size!");
  361                 }
  362                 md.md_sectorsize = *sectorsize;
  363         }
  364 
  365         g_eli_create(req, mp, pp, &md, mkey, -1);
  366         bzero(mkey, sizeof(mkey));
  367         bzero(&md, sizeof(md));
  368 }
  369 
  370 static void
  371 g_eli_ctl_configure(struct gctl_req *req, struct g_class *mp)
  372 {
  373         struct g_eli_softc *sc;
  374         struct g_eli_metadata md;
  375         struct g_provider *pp;
  376         struct g_consumer *cp;
  377         char param[16];
  378         const char *prov;
  379         u_char *sector;
  380         int *nargs, *boot, *noboot;
  381         int error;
  382         u_int i;
  383 
  384         g_topology_assert();
  385 
  386         nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
  387         if (nargs == NULL) {
  388                 gctl_error(req, "No '%s' argument.", "nargs");
  389                 return;
  390         }
  391         if (*nargs <= 0) {
  392                 gctl_error(req, "Missing device(s).");
  393                 return;
  394         }
  395 
  396         boot = gctl_get_paraml(req, "boot", sizeof(*boot));
  397         if (boot == NULL) {
  398                 gctl_error(req, "No '%s' argument.", "boot");
  399                 return;
  400         }
  401         noboot = gctl_get_paraml(req, "noboot", sizeof(*noboot));
  402         if (noboot == NULL) {
  403                 gctl_error(req, "No '%s' argument.", "noboot");
  404                 return;
  405         }
  406         if (*boot && *noboot) {
  407                 gctl_error(req, "Options -b and -B are mutually exclusive.");
  408                 return;
  409         }
  410         if (!*boot && !*noboot) {
  411                 gctl_error(req, "No option given.");
  412                 return;
  413         }
  414 
  415         for (i = 0; i < *nargs; i++) {
  416                 snprintf(param, sizeof(param), "arg%d", i);
  417                 prov = gctl_get_asciiparam(req, param);
  418                 if (prov == NULL) {
  419                         gctl_error(req, "No 'arg%d' argument.", i);
  420                         return;
  421                 }
  422                 sc = g_eli_find_device(mp, prov);
  423                 if (sc == NULL) {
  424                         /*
  425                          * We ignore not attached providers, userland part will
  426                          * take care of them.
  427                          */
  428                         G_ELI_DEBUG(1, "Skipping configuration of not attached "
  429                             "provider %s.", prov);
  430                         continue;
  431                 }
  432                 if (*boot && (sc->sc_flags & G_ELI_FLAG_BOOT)) {
  433                         G_ELI_DEBUG(1, "BOOT flag already configured for %s.",
  434                             prov);
  435                         continue;
  436                 } else if (!*boot && !(sc->sc_flags & G_ELI_FLAG_BOOT)) {
  437                         G_ELI_DEBUG(1, "BOOT flag not configured for %s.",
  438                             prov);
  439                         continue;
  440                 }
  441                 if (sc->sc_flags & G_ELI_FLAG_RO) {
  442                         gctl_error(req, "Cannot change configuration of "
  443                             "read-only provider %s.", prov);
  444                         continue;
  445                 }
  446                 cp = LIST_FIRST(&sc->sc_geom->consumer);
  447                 pp = cp->provider;
  448                 error = g_eli_read_metadata(mp, pp, &md);
  449                 if (error != 0) {
  450                         gctl_error(req,
  451                             "Cannot read metadata from %s (error=%d).",
  452                             prov, error);
  453                         continue;
  454                 }
  455 
  456                 if (*boot) {
  457                         md.md_flags |= G_ELI_FLAG_BOOT;
  458                         sc->sc_flags |= G_ELI_FLAG_BOOT;
  459                 } else {
  460                         md.md_flags &= ~G_ELI_FLAG_BOOT;
  461                         sc->sc_flags &= ~G_ELI_FLAG_BOOT;
  462                 }
  463 
  464                 sector = malloc(pp->sectorsize, M_ELI, M_WAITOK | M_ZERO);
  465                 eli_metadata_encode(&md, sector);
  466                 error = g_write_data(cp, pp->mediasize - pp->sectorsize, sector,
  467                     pp->sectorsize);
  468                 if (error != 0) {
  469                         gctl_error(req,
  470                             "Cannot store metadata on %s (error=%d).",
  471                             prov, error);
  472                 }
  473                 bzero(&md, sizeof(md));
  474                 bzero(sector, pp->sectorsize);
  475                 free(sector, M_ELI);
  476         }
  477 }
  478 
  479 static void
  480 g_eli_ctl_setkey(struct gctl_req *req, struct g_class *mp)
  481 {
  482         struct g_eli_softc *sc;
  483         struct g_eli_metadata md;
  484         struct g_provider *pp;
  485         struct g_consumer *cp;
  486         const char *name;
  487         u_char *key, *mkeydst, *sector;
  488         intmax_t *valp;
  489         int keysize, nkey, error;
  490 
  491         g_topology_assert();
  492 
  493         name = gctl_get_asciiparam(req, "arg0");
  494         if (name == NULL) {
  495                 gctl_error(req, "No 'arg%u' argument.", 0);
  496                 return;
  497         }
  498         sc = g_eli_find_device(mp, name);
  499         if (sc == NULL) {
  500                 gctl_error(req, "Provider %s is invalid.", name);
  501                 return;
  502         }
  503         if (sc->sc_flags & G_ELI_FLAG_RO) {
  504                 gctl_error(req, "Cannot change keys for read-only provider.");
  505                 return;
  506         }
  507         cp = LIST_FIRST(&sc->sc_geom->consumer);
  508         pp = cp->provider;
  509 
  510         error = g_eli_read_metadata(mp, pp, &md);
  511         if (error != 0) {
  512                 gctl_error(req, "Cannot read metadata from %s (error=%d).",
  513                     name, error);
  514                 return;
  515         }
  516 
  517         valp = gctl_get_paraml(req, "keyno", sizeof(*valp));
  518         if (valp == NULL) {
  519                 gctl_error(req, "No '%s' argument.", "keyno");
  520                 return;
  521         }
  522         if (*valp != -1)
  523                 nkey = *valp;
  524         else
  525                 nkey = sc->sc_nkey;
  526         if (nkey < 0 || nkey >= G_ELI_MAXMKEYS) {
  527                 gctl_error(req, "Invalid '%s' argument.", "keyno");
  528                 return;
  529         }
  530 
  531         valp = gctl_get_paraml(req, "iterations", sizeof(*valp));
  532         if (valp == NULL) {
  533                 gctl_error(req, "No '%s' argument.", "iterations");
  534                 return;
  535         }
  536         /* Check if iterations number should and can be changed. */
  537         if (*valp != -1) {
  538                 if (bitcount32(md.md_keys) != 1) {
  539                         gctl_error(req, "To be able to use '-i' option, only "
  540                             "one key can be defined.");
  541                         return;
  542                 }
  543                 if (md.md_keys != (1 << nkey)) {
  544                         gctl_error(req, "Only already defined key can be "
  545                             "changed when '-i' option is used.");
  546                         return;
  547                 }
  548                 md.md_iterations = *valp;
  549         }
  550 
  551         key = gctl_get_param(req, "key", &keysize);
  552         if (key == NULL || keysize != G_ELI_USERKEYLEN) {
  553                 bzero(&md, sizeof(md));
  554                 gctl_error(req, "No '%s' argument.", "key");
  555                 return;
  556         }
  557 
  558         mkeydst = md.md_mkeys + nkey * G_ELI_MKEYLEN;
  559         md.md_keys |= (1 << nkey);
  560 
  561         bcopy(sc->sc_mkey, mkeydst, sizeof(sc->sc_mkey));
  562 
  563         /* Encrypt Master Key with the new key. */
  564         error = g_eli_mkey_encrypt(md.md_ealgo, key, md.md_keylen, mkeydst);
  565         bzero(key, keysize);
  566         if (error != 0) {
  567                 bzero(&md, sizeof(md));
  568                 gctl_error(req, "Cannot encrypt Master Key (error=%d).", error);
  569                 return;
  570         }
  571 
  572         sector = malloc(pp->sectorsize, M_ELI, M_WAITOK | M_ZERO);
  573         /* Store metadata with fresh key. */
  574         eli_metadata_encode(&md, sector);
  575         bzero(&md, sizeof(md));
  576         error = g_write_data(cp, pp->mediasize - pp->sectorsize, sector,
  577             pp->sectorsize);
  578         bzero(sector, pp->sectorsize);
  579         free(sector, M_ELI);
  580         if (error != 0) {
  581                 gctl_error(req, "Cannot store metadata on %s (error=%d).",
  582                     pp->name, error);
  583                 return;
  584         }
  585         G_ELI_DEBUG(1, "Key %u changed on %s.", nkey, pp->name);
  586 }
  587 
  588 static void
  589 g_eli_ctl_delkey(struct gctl_req *req, struct g_class *mp)
  590 {
  591         struct g_eli_softc *sc;
  592         struct g_eli_metadata md;
  593         struct g_provider *pp;
  594         struct g_consumer *cp;
  595         const char *name;
  596         u_char *mkeydst, *sector;
  597         intmax_t *valp;
  598         size_t keysize;
  599         int error, nkey, *all, *force;
  600         u_int i;
  601 
  602         g_topology_assert();
  603 
  604         nkey = 0;       /* fixes causeless gcc warning */
  605 
  606         name = gctl_get_asciiparam(req, "arg0");
  607         if (name == NULL) {
  608                 gctl_error(req, "No 'arg%u' argument.", 0);
  609                 return;
  610         }
  611         sc = g_eli_find_device(mp, name);
  612         if (sc == NULL) {
  613                 gctl_error(req, "Provider %s is invalid.", name);
  614                 return;
  615         }
  616         if (sc->sc_flags & G_ELI_FLAG_RO) {
  617                 gctl_error(req, "Cannot delete keys for read-only provider.");
  618                 return;
  619         }
  620         cp = LIST_FIRST(&sc->sc_geom->consumer);
  621         pp = cp->provider;
  622 
  623         error = g_eli_read_metadata(mp, pp, &md);
  624         if (error != 0) {
  625                 gctl_error(req, "Cannot read metadata from %s (error=%d).",
  626                     name, error);
  627                 return;
  628         }
  629 
  630         all = gctl_get_paraml(req, "all", sizeof(*all));
  631         if (all == NULL) {
  632                 gctl_error(req, "No '%s' argument.", "all");
  633                 return;
  634         }
  635 
  636         if (*all) {
  637                 mkeydst = md.md_mkeys;
  638                 keysize = sizeof(md.md_mkeys);
  639         } else {
  640                 force = gctl_get_paraml(req, "force", sizeof(*force));
  641                 if (force == NULL) {
  642                         gctl_error(req, "No '%s' argument.", "force");
  643                         return;
  644                 }
  645 
  646                 valp = gctl_get_paraml(req, "keyno", sizeof(*valp));
  647                 if (valp == NULL) {
  648                         gctl_error(req, "No '%s' argument.", "keyno");
  649                         return;
  650                 }
  651                 if (*valp != -1)
  652                         nkey = *valp;
  653                 else
  654                         nkey = sc->sc_nkey;
  655                 if (nkey < 0 || nkey >= G_ELI_MAXMKEYS) {
  656                         gctl_error(req, "Invalid '%s' argument.", "keyno");
  657                         return;
  658                 }
  659                 if (!(md.md_keys & (1 << nkey)) && !*force) {
  660                         gctl_error(req, "Master Key %u is not set.", nkey);
  661                         return;
  662                 }
  663                 md.md_keys &= ~(1 << nkey);
  664                 if (md.md_keys == 0 && !*force) {
  665                         gctl_error(req, "This is the last Master Key. Use '-f' "
  666                             "flag if you really want to remove it.");
  667                         return;
  668                 }
  669                 mkeydst = md.md_mkeys + nkey * G_ELI_MKEYLEN;
  670                 keysize = G_ELI_MKEYLEN;
  671         }
  672 
  673         sector = malloc(pp->sectorsize, M_ELI, M_WAITOK | M_ZERO);
  674         for (i = 0; i <= g_eli_overwrites; i++) {
  675                 if (i == g_eli_overwrites)
  676                         bzero(mkeydst, keysize);
  677                 else
  678                         arc4rand(mkeydst, keysize, 0);
  679                 /* Store metadata with destroyed key. */
  680                 eli_metadata_encode(&md, sector);
  681                 error = g_write_data(cp, pp->mediasize - pp->sectorsize, sector,
  682                     pp->sectorsize);
  683                 if (error != 0) {
  684                         G_ELI_DEBUG(0, "Cannot store metadata on %s "
  685                             "(error=%d).", pp->name, error);
  686                 }
  687                 /*
  688                  * Flush write cache so we don't overwrite data N times in cache
  689                  * and only once on disk.
  690                  */
  691                 (void)g_io_flush(cp);
  692         }
  693         bzero(&md, sizeof(md));
  694         bzero(sector, pp->sectorsize);
  695         free(sector, M_ELI);
  696         if (*all)
  697                 G_ELI_DEBUG(1, "All keys removed from %s.", pp->name);
  698         else
  699                 G_ELI_DEBUG(1, "Key %d removed from %s.", nkey, pp->name);
  700 }
  701 
  702 static void
  703 g_eli_suspend_one(struct g_eli_softc *sc, struct gctl_req *req)
  704 {
  705         struct g_eli_worker *wr;
  706 
  707         g_topology_assert();
  708 
  709         KASSERT(sc != NULL, ("NULL sc"));
  710 
  711         if (sc->sc_flags & G_ELI_FLAG_ONETIME) {
  712                 gctl_error(req,
  713                     "Device %s is using one-time key, suspend not supported.",
  714                     sc->sc_name);
  715                 return;
  716         }
  717 
  718         mtx_lock(&sc->sc_queue_mtx);
  719         if (sc->sc_flags & G_ELI_FLAG_SUSPEND) {
  720                 mtx_unlock(&sc->sc_queue_mtx);
  721                 gctl_error(req, "Device %s already suspended.",
  722                     sc->sc_name);
  723                 return;
  724         }
  725         sc->sc_flags |= G_ELI_FLAG_SUSPEND;
  726         wakeup(sc);
  727         for (;;) {
  728                 LIST_FOREACH(wr, &sc->sc_workers, w_next) {
  729                         if (wr->w_active)
  730                                 break;
  731                 }
  732                 if (wr == NULL)
  733                         break;
  734                 /* Not all threads suspended. */
  735                 msleep(&sc->sc_workers, &sc->sc_queue_mtx, PRIBIO,
  736                     "geli:suspend", 0);
  737         }
  738         /*
  739          * Clear sensitive data on suspend, they will be recovered on resume.
  740          */
  741         bzero(sc->sc_mkey, sizeof(sc->sc_mkey));
  742         g_eli_key_destroy(sc);
  743         bzero(sc->sc_akey, sizeof(sc->sc_akey));
  744         bzero(&sc->sc_akeyctx, sizeof(sc->sc_akeyctx));
  745         bzero(sc->sc_ivkey, sizeof(sc->sc_ivkey));
  746         bzero(&sc->sc_ivctx, sizeof(sc->sc_ivctx));
  747         mtx_unlock(&sc->sc_queue_mtx);
  748         G_ELI_DEBUG(0, "Device %s has been suspended.", sc->sc_name);
  749 }
  750 
  751 static void
  752 g_eli_ctl_suspend(struct gctl_req *req, struct g_class *mp)
  753 {
  754         struct g_eli_softc *sc;
  755         int *all, *nargs;
  756 
  757         g_topology_assert();
  758 
  759         nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
  760         if (nargs == NULL) {
  761                 gctl_error(req, "No '%s' argument.", "nargs");
  762                 return;
  763         }
  764         all = gctl_get_paraml(req, "all", sizeof(*all));
  765         if (all == NULL) {
  766                 gctl_error(req, "No '%s' argument.", "all");
  767                 return;
  768         }
  769         if (!*all && *nargs == 0) {
  770                 gctl_error(req, "Too few arguments.");
  771                 return;
  772         }
  773 
  774         if (*all) {
  775                 struct g_geom *gp, *gp2;
  776 
  777                 LIST_FOREACH_SAFE(gp, &mp->geom, geom, gp2) {
  778                         sc = gp->softc;
  779                         if (sc->sc_flags & G_ELI_FLAG_ONETIME) {
  780                                 G_ELI_DEBUG(0,
  781                                     "Device %s is using one-time key, suspend not supported, skipping.",
  782                                     sc->sc_name);
  783                                 continue;
  784                         }
  785                         g_eli_suspend_one(sc, req);
  786                 }
  787         } else {
  788                 const char *prov;
  789                 char param[16];
  790                 int i;
  791 
  792                 for (i = 0; i < *nargs; i++) {
  793                         snprintf(param, sizeof(param), "arg%d", i);
  794                         prov = gctl_get_asciiparam(req, param);
  795                         if (prov == NULL) {
  796                                 G_ELI_DEBUG(0, "No 'arg%d' argument.", i);
  797                                 continue;
  798                         }
  799 
  800                         sc = g_eli_find_device(mp, prov);
  801                         if (sc == NULL) {
  802                                 G_ELI_DEBUG(0, "No such provider: %s.", prov);
  803                                 continue;
  804                         }
  805                         g_eli_suspend_one(sc, req);
  806                 }
  807         }
  808 }
  809 
  810 static void
  811 g_eli_ctl_resume(struct gctl_req *req, struct g_class *mp)
  812 {
  813         struct g_eli_metadata md;
  814         struct g_eli_softc *sc;
  815         struct g_provider *pp;
  816         struct g_consumer *cp;
  817         const char *name;
  818         u_char *key, mkey[G_ELI_DATAIVKEYLEN];
  819         int *nargs, keysize, error;
  820         u_int nkey;
  821 
  822         g_topology_assert();
  823 
  824         nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
  825         if (nargs == NULL) {
  826                 gctl_error(req, "No '%s' argument.", "nargs");
  827                 return;
  828         }
  829         if (*nargs != 1) {
  830                 gctl_error(req, "Invalid number of arguments.");
  831                 return;
  832         }
  833 
  834         name = gctl_get_asciiparam(req, "arg0");
  835         if (name == NULL) {
  836                 gctl_error(req, "No 'arg%u' argument.", 0);
  837                 return;
  838         }
  839         sc = g_eli_find_device(mp, name);
  840         if (sc == NULL) {
  841                 gctl_error(req, "Provider %s is invalid.", name);
  842                 return;
  843         }
  844         cp = LIST_FIRST(&sc->sc_geom->consumer);
  845         pp = cp->provider;
  846         error = g_eli_read_metadata(mp, pp, &md);
  847         if (error != 0) {
  848                 gctl_error(req, "Cannot read metadata from %s (error=%d).",
  849                     name, error);
  850                 return;
  851         }
  852         if (md.md_keys == 0x00) {
  853                 bzero(&md, sizeof(md));
  854                 gctl_error(req, "No valid keys on %s.", pp->name);
  855                 return;
  856         }
  857 
  858         key = gctl_get_param(req, "key", &keysize);
  859         if (key == NULL || keysize != G_ELI_USERKEYLEN) {
  860                 bzero(&md, sizeof(md));
  861                 gctl_error(req, "No '%s' argument.", "key");
  862                 return;
  863         }
  864 
  865         error = g_eli_mkey_decrypt(&md, key, mkey, &nkey);
  866         bzero(key, keysize);
  867         if (error == -1) {
  868                 bzero(&md, sizeof(md));
  869                 gctl_error(req, "Wrong key for %s.", pp->name);
  870                 return;
  871         } else if (error > 0) {
  872                 bzero(&md, sizeof(md));
  873                 gctl_error(req, "Cannot decrypt Master Key for %s (error=%d).",
  874                     pp->name, error);
  875                 return;
  876         }
  877         G_ELI_DEBUG(1, "Using Master Key %u for %s.", nkey, pp->name);
  878 
  879         mtx_lock(&sc->sc_queue_mtx);
  880         if (!(sc->sc_flags & G_ELI_FLAG_SUSPEND))
  881                 gctl_error(req, "Device %s is not suspended.", name);
  882         else {
  883                 /* Restore sc_mkey, sc_ekeys, sc_akey and sc_ivkey. */
  884                 g_eli_mkey_propagate(sc, mkey);
  885                 sc->sc_flags &= ~G_ELI_FLAG_SUSPEND;
  886                 G_ELI_DEBUG(1, "Resumed %s.", pp->name);
  887                 wakeup(sc);
  888         }
  889         mtx_unlock(&sc->sc_queue_mtx);
  890         bzero(mkey, sizeof(mkey));
  891         bzero(&md, sizeof(md));
  892 }
  893 
  894 static int
  895 g_eli_kill_one(struct g_eli_softc *sc)
  896 {
  897         struct g_provider *pp;
  898         struct g_consumer *cp;
  899         int error = 0;
  900 
  901         g_topology_assert();
  902 
  903         if (sc == NULL)
  904                 return (ENOENT);
  905 
  906         pp = LIST_FIRST(&sc->sc_geom->provider);
  907         g_error_provider(pp, ENXIO);
  908 
  909         cp = LIST_FIRST(&sc->sc_geom->consumer);
  910         pp = cp->provider;
  911 
  912         if (sc->sc_flags & G_ELI_FLAG_RO) {
  913                 G_ELI_DEBUG(0, "WARNING: Metadata won't be erased on read-only "
  914                     "provider: %s.", pp->name);
  915         } else {
  916                 u_char *sector;
  917                 u_int i;
  918                 int err;
  919 
  920                 sector = malloc(pp->sectorsize, M_ELI, M_WAITOK);
  921                 for (i = 0; i <= g_eli_overwrites; i++) {
  922                         if (i == g_eli_overwrites)
  923                                 bzero(sector, pp->sectorsize);
  924                         else
  925                                 arc4rand(sector, pp->sectorsize, 0);
  926                         err = g_write_data(cp, pp->mediasize - pp->sectorsize,
  927                             sector, pp->sectorsize);
  928                         if (err != 0) {
  929                                 G_ELI_DEBUG(0, "Cannot erase metadata on %s "
  930                                     "(error=%d).", pp->name, err);
  931                                 if (error == 0)
  932                                         error = err;
  933                         }
  934                         /*
  935                          * Flush write cache so we don't overwrite data N times
  936                          * in cache and only once on disk.
  937                          */
  938                         (void)g_io_flush(cp);
  939                 }
  940                 free(sector, M_ELI);
  941         }
  942         if (error == 0)
  943                 G_ELI_DEBUG(0, "%s has been killed.", pp->name);
  944         g_eli_destroy(sc, TRUE);
  945         return (error);
  946 }
  947 
  948 static void
  949 g_eli_ctl_kill(struct gctl_req *req, struct g_class *mp)
  950 {
  951         int *all, *nargs;
  952         int error;
  953 
  954         g_topology_assert();
  955 
  956         nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
  957         if (nargs == NULL) {
  958                 gctl_error(req, "No '%s' argument.", "nargs");
  959                 return;
  960         }
  961         all = gctl_get_paraml(req, "all", sizeof(*all));
  962         if (all == NULL) {
  963                 gctl_error(req, "No '%s' argument.", "all");
  964                 return;
  965         }
  966         if (!*all && *nargs == 0) {
  967                 gctl_error(req, "Too few arguments.");
  968                 return;
  969         }
  970 
  971         if (*all) {
  972                 struct g_geom *gp, *gp2;
  973 
  974                 LIST_FOREACH_SAFE(gp, &mp->geom, geom, gp2) {
  975                         error = g_eli_kill_one(gp->softc);
  976                         if (error != 0)
  977                                 gctl_error(req, "Not fully done.");
  978                 }
  979         } else {
  980                 struct g_eli_softc *sc;
  981                 const char *prov;
  982                 char param[16];
  983                 int i;
  984 
  985                 for (i = 0; i < *nargs; i++) {
  986                         snprintf(param, sizeof(param), "arg%d", i);
  987                         prov = gctl_get_asciiparam(req, param);
  988                         if (prov == NULL) {
  989                                 G_ELI_DEBUG(0, "No 'arg%d' argument.", i);
  990                                 continue;
  991                         }
  992 
  993                         sc = g_eli_find_device(mp, prov);
  994                         if (sc == NULL) {
  995                                 G_ELI_DEBUG(0, "No such provider: %s.", prov);
  996                                 continue;
  997                         }
  998                         error = g_eli_kill_one(sc);
  999                         if (error != 0)
 1000                                 gctl_error(req, "Not fully done.");
 1001                 }
 1002         }
 1003 }
 1004 
 1005 void
 1006 g_eli_config(struct gctl_req *req, struct g_class *mp, const char *verb)
 1007 {
 1008         uint32_t *version;
 1009 
 1010         g_topology_assert();
 1011 
 1012         version = gctl_get_paraml(req, "version", sizeof(*version));
 1013         if (version == NULL) {
 1014                 gctl_error(req, "No '%s' argument.", "version");
 1015                 return;
 1016         }
 1017         while (*version != G_ELI_VERSION) {
 1018                 if (G_ELI_VERSION == G_ELI_VERSION_06 &&
 1019                     *version == G_ELI_VERSION_05) {
 1020                         /* Compatible. */
 1021                         break;
 1022                 }
 1023                 if (G_ELI_VERSION == G_ELI_VERSION_07 &&
 1024                     (*version == G_ELI_VERSION_05 ||
 1025                      *version == G_ELI_VERSION_06)) {
 1026                         /* Compatible. */
 1027                         break;
 1028                 }
 1029                 gctl_error(req, "Userland and kernel parts are out of sync.");
 1030                 return;
 1031         }
 1032 
 1033         if (strcmp(verb, "attach") == 0)
 1034                 g_eli_ctl_attach(req, mp);
 1035         else if (strcmp(verb, "detach") == 0 || strcmp(verb, "stop") == 0)
 1036                 g_eli_ctl_detach(req, mp);
 1037         else if (strcmp(verb, "onetime") == 0)
 1038                 g_eli_ctl_onetime(req, mp);
 1039         else if (strcmp(verb, "configure") == 0)
 1040                 g_eli_ctl_configure(req, mp);
 1041         else if (strcmp(verb, "setkey") == 0)
 1042                 g_eli_ctl_setkey(req, mp);
 1043         else if (strcmp(verb, "delkey") == 0)
 1044                 g_eli_ctl_delkey(req, mp);
 1045         else if (strcmp(verb, "suspend") == 0)
 1046                 g_eli_ctl_suspend(req, mp);
 1047         else if (strcmp(verb, "resume") == 0)
 1048                 g_eli_ctl_resume(req, mp);
 1049         else if (strcmp(verb, "kill") == 0)
 1050                 g_eli_ctl_kill(req, mp);
 1051         else
 1052                 gctl_error(req, "Unknown verb.");
 1053 }

Cache object: f579c060488304f71709f4da814585ce


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.