Allow geli to operate on read-only providers.

Initial patch from:	vd
MFC after:		2 weeks
This commit is contained in:
Pawel Jakub Dawidek 2006-08-09 18:11:14 +00:00
parent edd5ce3102
commit 850590166f
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=161127
5 changed files with 74 additions and 28 deletions

View File

@ -64,7 +64,7 @@ utility:
.Cm init
.Nm
.Cm attach
.Op Fl dpv
.Op Fl dprv
.Op Fl k Ar keyfile
.Ar prov
.Nm
@ -288,6 +288,8 @@ Probably a better choice is the
option for the
.Cm detach
subcommand.
.It Fl r
Attach read-only provider. It will not be opened for writting.
.It Fl k Ar keyfile
Specifies a file which contains part of the key.
For more information see the description of the

View File

@ -1,5 +1,5 @@
/*-
* Copyright (c) 2004 Pawel Jakub Dawidek <pjd@FreeBSD.org>
* Copyright (c) 2004-2006 Pawel Jakub Dawidek <pjd@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -78,7 +78,7 @@ static void eli_dump(struct gctl_req *req);
*
* init [-bhPv] [-a aalgo] [-e ealgo] [-i iterations] [-l keylen] [-K newkeyfile] prov
* label - alias for 'init'
* attach [-dpv] [-k keyfile] prov
* attach [-dprv] [-k keyfile] prov
* detach [-fl] prov ...
* stop - alias for 'detach'
* onetime [-d] [-a aalgo] [-e ealgo] [-l keylen] prov ...
@ -124,9 +124,10 @@ struct g_command class_commands[] = {
{ 'd', "detach", NULL, G_TYPE_NONE },
{ 'k', "keyfile", keyfile, G_TYPE_STRING },
{ 'p', "nopassphrase", NULL, G_TYPE_NONE },
{ 'r', "readonly", NULL, G_TYPE_NONE },
G_OPT_SENTINEL
},
"[-dpv] [-k keyfile] prov"
"[-dprv] [-k keyfile] prov"
},
{ "detach", 0, NULL,
{

View File

@ -455,6 +455,10 @@ g_eli_access(struct g_provider *pp, int dr, int dw, int de)
sc = gp->softc;
if (dw > 0) {
if (sc->sc_flags & G_ELI_FLAG_RO) {
/* Deny write attempts. */
return (EROFS);
}
/* Someone is opening us for write, we need to remember that. */
sc->sc_flags |= G_ELI_FLAG_WOPEN;
return (0);
@ -495,19 +499,19 @@ g_eli_create(struct gctl_req *req, struct g_class *mp, struct g_provider *bpp,
gp->start = g_eli_start;
/*
* Spoiling cannot happen actually, because we keep provider open for
* writing all the time.
* writing all the time or provider is read-only.
*/
gp->spoiled = g_eli_orphan_spoil_assert;
gp->orphan = g_eli_orphan;
gp->dumpconf = g_eli_dumpconf;
/*
* If detach-on-last-close feature is not enabled, we can simply use
* g_std_access().
* If detach-on-last-close feature is not enabled and we don't operate
* on read-only provider, we can simply use g_std_access().
*/
if (md->md_flags & G_ELI_FLAG_WO_DETACH)
if (md->md_flags & (G_ELI_FLAG_WO_DETACH | G_ELI_FLAG_RO))
gp->access = g_eli_access;
else
gp->access = g_std_access;
gp->dumpconf = g_eli_dumpconf;
sc->sc_crypto = G_ELI_CRYPTO_SW;
sc->sc_flags = md->md_flags;
@ -578,8 +582,13 @@ g_eli_create(struct gctl_req *req, struct g_class *mp, struct g_provider *bpp,
* Keep provider open all the time, so we can run critical tasks,
* like Master Keys deletion, without wondering if we can open
* provider or not.
* We don't open provider for writing only when user requested read-only
* access.
*/
error = g_access(cp, 1, 1, 1);
if (sc->sc_flags & G_ELI_FLAG_RO)
error = g_access(cp, 1, 0, 1);
else
error = g_access(cp, 1, 1, 1);
if (error != 0) {
if (req != NULL) {
gctl_error(req, "Cannot access %s (error=%d).",
@ -997,6 +1006,7 @@ g_eli_dumpconf(struct sbuf *sb, const char *indent, struct g_geom *gp,
ADD_FLAG(G_ELI_FLAG_AUTH, "AUTH");
ADD_FLAG(G_ELI_FLAG_WOPEN, "W-OPEN");
ADD_FLAG(G_ELI_FLAG_DESTROY, "DESTROY");
ADD_FLAG(G_ELI_FLAG_RO, "READ-ONLY");
#undef ADD_FLAG
}
sbuf_printf(sb, "</Flags>\n");

View File

@ -59,6 +59,7 @@
*/
#define G_ELI_VERSION 1
/* ON DISK FLAGS. */
/* Use random, onetime keys. */
#define G_ELI_FLAG_ONETIME 0x00000001
/* Ask for the passphrase from the kernel, before mounting root. */
@ -69,6 +70,9 @@
#define G_ELI_FLAG_RW_DETACH 0x00000008
/* Provide data authentication. */
#define G_ELI_FLAG_AUTH 0x00000010
/* Provider is read-only, we should deny all write attempts. */
#define G_ELI_FLAG_RO 0x00000020
/* RUNTIME FLAGS. */
/* Provider was open for writing. */
#define G_ELI_FLAG_WOPEN 0x00010000
/* Destroy device. */

View File

@ -57,7 +57,7 @@ g_eli_ctl_attach(struct gctl_req *req, struct g_class *mp)
struct g_provider *pp;
const char *name;
u_char *key, mkey[G_ELI_DATAIVKEYLEN];
int *nargs, *detach;
int *nargs, *detach, *readonly;
int keysize, error;
u_int nkey;
@ -79,6 +79,12 @@ g_eli_ctl_attach(struct gctl_req *req, struct g_class *mp)
return;
}
readonly = gctl_get_paraml(req, "readonly", sizeof(*readonly));
if (readonly == NULL) {
gctl_error(req, "No '%s' argument.", "readonly");
return;
}
name = gctl_get_asciiparam(req, "arg0");
if (name == NULL) {
gctl_error(req, "No 'arg%u' argument.", 0);
@ -124,8 +130,16 @@ g_eli_ctl_attach(struct gctl_req *req, struct g_class *mp)
}
G_ELI_DEBUG(1, "Using Master Key %u for %s.", nkey, pp->name);
if (*detach && *readonly) {
bzero(&md, sizeof(md));
gctl_error(req, "Options -d and -r are mutually exclusive.",
pp->name, error);
return;
}
if (*detach)
md.md_flags |= G_ELI_FLAG_WO_DETACH;
if (*readonly)
md.md_flags |= G_ELI_FLAG_RO;
g_eli_create(req, mp, pp, &md, mkey, nkey);
bzero(mkey, sizeof(mkey));
bzero(&md, sizeof(md));
@ -374,6 +388,10 @@ g_eli_ctl_setkey(struct gctl_req *req, struct g_class *mp)
gctl_error(req, "Provider %s is invalid.", name);
return;
}
if (sc->sc_flags & G_ELI_FLAG_RO) {
gctl_error(req, "Cannot change keys for read-only provider.");
return;
}
cp = LIST_FIRST(&sc->sc_geom->consumer);
pp = cp->provider;
@ -483,6 +501,10 @@ g_eli_ctl_delkey(struct gctl_req *req, struct g_class *mp)
gctl_error(req, "Provider %s is invalid.", name);
return;
}
if (sc->sc_flags & G_ELI_FLAG_RO) {
gctl_error(req, "Cannot delete keys for read-only provider.");
return;
}
cp = LIST_FIRST(&sc->sc_geom->consumer);
pp = cp->provider;
@ -565,9 +587,7 @@ g_eli_kill_one(struct g_eli_softc *sc)
{
struct g_provider *pp;
struct g_consumer *cp;
u_char *sector;
int err, error = 0;
u_int i;
int error = 0;
g_topology_assert();
@ -580,22 +600,31 @@ g_eli_kill_one(struct g_eli_softc *sc)
cp = LIST_FIRST(&sc->sc_geom->consumer);
pp = cp->provider;
sector = malloc(pp->sectorsize, M_ELI, M_WAITOK);
for (i = 0; i <= g_eli_overwrites; i++) {
if (i == g_eli_overwrites)
bzero(sector, pp->sectorsize);
else
arc4rand(sector, pp->sectorsize, 0);
err = g_write_data(cp, pp->mediasize - pp->sectorsize, sector,
pp->sectorsize);
if (err != 0) {
G_ELI_DEBUG(0, "Cannot erase metadata on %s "
"(error=%d).", pp->name, err);
if (error == 0)
error = err;
if (sc->sc_flags & G_ELI_FLAG_RO) {
G_ELI_DEBUG(0, "WARNING: Metadata won't be erased on read-only "
"provider: %s.", pp->name);
} else {
u_char *sector;
u_int i;
int err;
sector = malloc(pp->sectorsize, M_ELI, M_WAITOK);
for (i = 0; i <= g_eli_overwrites; i++) {
if (i == g_eli_overwrites)
bzero(sector, pp->sectorsize);
else
arc4rand(sector, pp->sectorsize, 0);
err = g_write_data(cp, pp->mediasize - pp->sectorsize,
sector, pp->sectorsize);
if (err != 0) {
G_ELI_DEBUG(0, "Cannot erase metadata on %s "
"(error=%d).", pp->name, err);
if (error == 0)
error = err;
}
}
free(sector, M_ELI);
}
free(sector, M_ELI);
if (error == 0)
G_ELI_DEBUG(0, "%s has been killed.", pp->name);
g_eli_destroy(sc, 1);