virstorageencryption.c 11.3 KB
Newer Older
1
/*
2
 * virstorageencryption.c: volume encryption information
3
 *
4
 * Copyright (C) 2009-2014 Red Hat, Inc.
5 6 7 8 9 10 11 12 13 14 15 16
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
17
 * License along with this library.  If not, see
O
Osier Yang 已提交
18
 * <http://www.gnu.org/licenses/>.
19 20 21 22
 */

#include <config.h>

23 24 25
#include <fcntl.h>
#include <unistd.h>

26 27
#include "internal.h"

28
#include "virbuffer.h"
29
#include "viralloc.h"
30
#include "virstorageencryption.h"
31
#include "virxml.h"
32
#include "virerror.h"
33
#include "viruuid.h"
E
Eric Blake 已提交
34
#include "virfile.h"
J
John Ferlan 已提交
35
#include "virsecret.h"
36
#include "virstring.h"
37 38 39

#define VIR_FROM_THIS VIR_FROM_STORAGE

40
VIR_ENUM_IMPL(virStorageEncryptionSecret,
41 42 43
              VIR_STORAGE_ENCRYPTION_SECRET_TYPE_LAST,
              "passphrase",
);
44 45 46

VIR_ENUM_IMPL(virStorageEncryptionFormat,
              VIR_STORAGE_ENCRYPTION_FORMAT_LAST,
47 48
              "default", "qcow", "luks",
);
49

50 51 52 53 54 55 56 57 58 59 60
static void
virStorageEncryptionInfoDefFree(virStorageEncryptionInfoDefPtr def)
{
    VIR_FREE(def->cipher_name);
    VIR_FREE(def->cipher_mode);
    VIR_FREE(def->cipher_hash);
    VIR_FREE(def->ivgen_name);
    VIR_FREE(def->ivgen_hash);
}


61 62 63 64 65
static void
virStorageEncryptionSecretFree(virStorageEncryptionSecretPtr secret)
{
    if (!secret)
        return;
66
    virSecretLookupDefClear(&secret->seclookupdef);
67 68 69 70 71 72 73 74 75 76 77 78 79
    VIR_FREE(secret);
}

void
virStorageEncryptionFree(virStorageEncryptionPtr enc)
{
    size_t i;

    if (!enc)
        return;

    for (i = 0; i < enc->nsecrets; i++)
        virStorageEncryptionSecretFree(enc->secrets[i]);
80
    virStorageEncryptionInfoDefFree(&enc->encinfo);
81 82 83 84
    VIR_FREE(enc->secrets);
    VIR_FREE(enc);
}

85 86 87 88 89 90 91 92 93 94 95 96 97
static virStorageEncryptionSecretPtr
virStorageEncryptionSecretCopy(const virStorageEncryptionSecret *src)
{
    virStorageEncryptionSecretPtr ret;

    if (VIR_ALLOC(ret) < 0)
        return NULL;

    memcpy(ret, src, sizeof(*src));

    return ret;
}

98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114

static int
virStorageEncryptionInfoDefCopy(const virStorageEncryptionInfoDef *src,
                                virStorageEncryptionInfoDefPtr dst)
{
    dst->cipher_size = src->cipher_size;
    if (VIR_STRDUP(dst->cipher_name, src->cipher_name) < 0 ||
        VIR_STRDUP(dst->cipher_mode, src->cipher_mode) < 0 ||
        VIR_STRDUP(dst->cipher_hash, src->cipher_hash) < 0 ||
        VIR_STRDUP(dst->ivgen_name, src->ivgen_name) < 0 ||
        VIR_STRDUP(dst->ivgen_hash, src->ivgen_hash) < 0)
        return -1;

    return 0;
}


115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134
virStorageEncryptionPtr
virStorageEncryptionCopy(const virStorageEncryption *src)
{
    virStorageEncryptionPtr ret;
    size_t i;

    if (VIR_ALLOC(ret) < 0)
        return NULL;

    if (VIR_ALLOC_N(ret->secrets, src->nsecrets) < 0)
        goto error;

    ret->nsecrets = src->nsecrets;
    ret->format = src->format;

    for (i = 0; i < src->nsecrets; i++) {
        if (!(ret->secrets[i] = virStorageEncryptionSecretCopy(src->secrets[i])))
            goto error;
    }

135 136 137
    if (virStorageEncryptionInfoDefCopy(&src->encinfo, &ret->encinfo) < 0)
        goto error;

138 139 140 141 142 143 144
    return ret;

 error:
    virStorageEncryptionFree(ret);
    return NULL;
}

145
static virStorageEncryptionSecretPtr
146
virStorageEncryptionSecretParse(xmlXPathContextPtr ctxt,
147 148 149 150
                                xmlNodePtr node)
{
    xmlNodePtr old_node;
    virStorageEncryptionSecretPtr ret;
151
    char *type_str = NULL;
152
    char *uuidstr = NULL;
J
John Ferlan 已提交
153
    char *usagestr = NULL;
154

155
    if (VIR_ALLOC(ret) < 0)
156 157 158 159 160
        return NULL;

    old_node = ctxt->node;
    ctxt->node = node;

161
    if (!(type_str = virXPathString("string(./@type)", ctxt))) {
162 163
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("unknown volume encryption secret type"));
164 165
        goto cleanup;
    }
166 167

    if ((ret->type = virStorageEncryptionSecretTypeFromString(type_str)) < 0) {
168
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
169 170
                       _("unknown volume encryption secret type %s"),
                       type_str);
171 172 173
        goto cleanup;
    }

J
John Ferlan 已提交
174
    if (virSecretLookupParseSecret(node, &ret->seclookupdef) < 0)
175
        goto cleanup;
J
John Ferlan 已提交
176 177 178

    VIR_FREE(type_str);

179 180 181
    ctxt->node = old_node;
    return ret;

182
 cleanup:
183
    VIR_FREE(type_str);
184
    virStorageEncryptionSecretFree(ret);
185
    VIR_FREE(uuidstr);
J
John Ferlan 已提交
186
    VIR_FREE(usagestr);
187 188 189 190
    ctxt->node = old_node;
    return NULL;
}

191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245

static int
virStorageEncryptionInfoParseCipher(xmlNodePtr info_node,
                                    virStorageEncryptionInfoDefPtr info)
{
    int ret = -1;
    char *size_str = NULL;

    if (!(info->cipher_name = virXMLPropString(info_node, "name"))) {
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("cipher info missing 'name' attribute"));
        goto cleanup;
    }

    if ((size_str = virXMLPropString(info_node, "size")) &&
        virStrToLong_uip(size_str, NULL, 10, &info->cipher_size) < 0) {
        virReportError(VIR_ERR_XML_ERROR,
                       _("cannot parse cipher size: '%s'"),
                       size_str);
        goto cleanup;
    }

    if (!size_str) {
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("cipher info missing 'size' attribute"));
        goto cleanup;
    }

    info->cipher_mode = virXMLPropString(info_node, "mode");
    info->cipher_hash = virXMLPropString(info_node, "hash");

    ret = 0;

 cleanup:
    VIR_FREE(size_str);
    return ret;
}


static int
virStorageEncryptionInfoParseIvgen(xmlNodePtr info_node,
                                   virStorageEncryptionInfoDefPtr info)
{
    if (!(info->ivgen_name = virXMLPropString(info_node, "name"))) {
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("missing ivgen info name string"));
        return -1;
    }

    info->ivgen_hash = virXMLPropString(info_node, "hash");

    return 0;
}


246 247 248
virStorageEncryptionPtr
virStorageEncryptionParseNode(xmlNodePtr node,
                              xmlXPathContextPtr ctxt)
249
{
250
    xmlNodePtr saveNode = ctxt->node;
251
    xmlNodePtr *nodes = NULL;
252 253
    virStorageEncryptionPtr encdef = NULL;
    virStorageEncryptionPtr ret = NULL;
254 255
    char *format_str = NULL;
    int n;
256
    size_t i;
257

258 259
    ctxt->node = node;

260 261
    if (VIR_ALLOC(encdef) < 0)
        goto cleanup;
262

263
    if (!(format_str = virXPathString("string(./@format)", ctxt))) {
264 265
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("unknown volume encryption format"));
266 267
        goto cleanup;
    }
268

269
    if ((encdef->format =
270
         virStorageEncryptionFormatTypeFromString(format_str)) < 0) {
271
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
272 273
                       _("unknown volume encryption format type %s"),
                       format_str);
274 275 276
        goto cleanup;
    }

277
    if ((n = virXPathNodeSet("./secret", ctxt, &nodes)) < 0)
278
        goto cleanup;
279 280

    if (n > 0) {
281
        if (VIR_ALLOC_N(encdef->secrets, n) < 0)
282
            goto cleanup;
283
        encdef->nsecrets = n;
284 285

        for (i = 0; i < n; i++) {
286
            if (!(encdef->secrets[i] =
287 288 289
                  virStorageEncryptionSecretParse(ctxt, nodes[i])))
                goto cleanup;
        }
290 291
    }

292
    if (encdef->format == VIR_STORAGE_ENCRYPTION_FORMAT_LUKS) {
293 294 295
        xmlNodePtr tmpnode;

        if ((tmpnode = virXPathNode("./cipher[1]", ctxt))) {
296
            if (virStorageEncryptionInfoParseCipher(tmpnode, &encdef->encinfo) < 0)
297 298 299 300 301
                goto cleanup;
        }

        if ((tmpnode = virXPathNode("./ivgen[1]", ctxt))) {
            /* If no cipher node, then fail */
302
            if (!encdef->encinfo.cipher_name) {
303
                virReportError(VIR_ERR_XML_ERROR, "%s",
304
                               _("ivgen element found, but cipher is missing"));
305 306 307
                goto cleanup;
            }

308
            if (virStorageEncryptionInfoParseIvgen(tmpnode, &encdef->encinfo) < 0)
309 310 311 312
                goto cleanup;
        }
    }

313
    ret = g_steal_pointer(&encdef);
314

315
 cleanup:
316
    VIR_FREE(format_str);
317
    VIR_FREE(nodes);
318
    virStorageEncryptionFree(encdef);
319
    ctxt->node = saveNode;
320

321
    return ret;
322
}
323

324 325

static int
326
virStorageEncryptionSecretFormat(virBufferPtr buf,
327
                                 virStorageEncryptionSecretPtr secret)
328 329 330
{
    const char *type;

331
    if (!(type = virStorageEncryptionSecretTypeToString(secret->type))) {
332 333
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("unexpected volume encryption secret type"));
334 335 336
        return -1;
    }

J
John Ferlan 已提交
337 338
    virSecretLookupFormatSecret(buf, type, &secret->seclookupdef);

339 340 341
    return 0;
}

342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363

static void
virStorageEncryptionInfoDefFormat(virBufferPtr buf,
                                  const virStorageEncryptionInfoDef *enc)
{
    virBufferEscapeString(buf, "<cipher name='%s'", enc->cipher_name);
    virBufferAsprintf(buf, " size='%u'", enc->cipher_size);
    if (enc->cipher_mode)
        virBufferEscapeString(buf, " mode='%s'", enc->cipher_mode);
    if (enc->cipher_hash)
        virBufferEscapeString(buf, " hash='%s'", enc->cipher_hash);
    virBufferAddLit(buf, "/>\n");

    if (enc->ivgen_name) {
        virBufferEscapeString(buf, "<ivgen name='%s'", enc->ivgen_name);
        if (enc->ivgen_hash)
            virBufferEscapeString(buf, " hash='%s'", enc->ivgen_hash);
        virBufferAddLit(buf, "/>\n");
    }
}


364
int
365
virStorageEncryptionFormat(virBufferPtr buf,
366
                           virStorageEncryptionPtr enc)
367 368 369 370
{
    const char *format;
    size_t i;

371
    if (!(format = virStorageEncryptionFormatTypeToString(enc->format))) {
372 373
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("unexpected encryption format"));
374 375
        return -1;
    }
376
    virBufferAsprintf(buf, "<encryption format='%s'>\n", format);
377
    virBufferAdjustIndent(buf, 2);
378 379

    for (i = 0; i < enc->nsecrets; i++) {
380
        if (virStorageEncryptionSecretFormat(buf, enc->secrets[i]) < 0)
381 382 383
            return -1;
    }

384 385 386 387
    if (enc->format == VIR_STORAGE_ENCRYPTION_FORMAT_LUKS &&
        enc->encinfo.cipher_name)
        virStorageEncryptionInfoDefFormat(buf, &enc->encinfo);

388
    virBufferAdjustIndent(buf, -2);
389
    virBufferAddLit(buf, "</encryption>\n");
390 391 392

    return 0;
}
393 394

int
395
virStorageGenerateQcowPassphrase(unsigned char *dest)
396 397 398 399 400 401 402 403 404
{
    int fd;
    size_t i;

    /* A qcow passphrase is up to 16 bytes, with any data following a NUL
       ignored.  Prohibit control and non-ASCII characters to avoid possible
       unpleasant surprises with the qemu monitor input mechanism. */
    fd = open("/dev/urandom", O_RDONLY);
    if (fd < 0) {
405 406
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Cannot open /dev/urandom"));
407 408 409 410 411 412 413 414 415
        return -1;
    }
    i = 0;
    while (i < VIR_STORAGE_QCOW_PASSPHRASE_SIZE) {
        ssize_t r;

        while ((r = read(fd, dest + i, 1)) == -1 && errno == EINTR)
            ;
        if (r <= 0) {
416 417
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("Cannot read from /dev/urandom"));
418
            VIR_FORCE_CLOSE(fd);
419 420 421 422 423
            return -1;
        }
        if (dest[i] >= 0x20 && dest[i] <= 0x7E)
            i++; /* Got an acceptable character */
    }
424
    VIR_FORCE_CLOSE(fd);
425 426
    return 0;
}