secret_driver.c 27.5 KB
Newer Older
1 2 3
/*
 * secret_driver.c: local driver for secret manipulation API
 *
4
 * Copyright (C) 2009-2016 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 23 24 25 26 27 28 29 30 31 32 33 34
 *
 * Red Hat Author: Miloslav Trmač <mitr@redhat.com>
 */

#include <config.h>

#include <dirent.h>
#include <fcntl.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>

#include "internal.h"
#include "base64.h"
#include "datatypes.h"
#include "driver.h"
35
#include "virlog.h"
36
#include "viralloc.h"
37 38
#include "secret_conf.h"
#include "secret_driver.h"
39
#include "virthread.h"
40
#include "viruuid.h"
41
#include "virerror.h"
E
Eric Blake 已提交
42
#include "virfile.h"
43
#include "configmake.h"
44
#include "virstring.h"
45
#include "viraccessapicheck.h"
46 47 48

#define VIR_FROM_THIS VIR_FROM_SECRET

49 50
VIR_LOG_INIT("secret.secret_driver");

51 52
enum { SECRET_MAX_XML_FILE = 10*1024*1024 };

53
/* Internal driver state */
54

J
John Ferlan 已提交
55 56 57 58
typedef struct _virSecretObj virSecretObj;
typedef virSecretObj *virSecretObjPtr;
struct _virSecretObj {
    virSecretObjPtr next;
59 60 61 62 63 64 65 66 67
    virSecretDefPtr def;
    unsigned char *value;       /* May be NULL */
    size_t value_size;
};

typedef struct _virSecretDriverState virSecretDriverState;
typedef virSecretDriverState *virSecretDriverStatePtr;
struct _virSecretDriverState {
    virMutex lock;
J
John Ferlan 已提交
68
    virSecretObj *secrets;
69 70 71
    char *directory;
};

72
static virSecretDriverStatePtr driver;
73 74

static void
75
secretDriverLock(void)
76 77 78 79 80
{
    virMutexLock(&driver->lock);
}

static void
81
secretDriverUnlock(void)
82 83 84 85
{
    virMutexUnlock(&driver->lock);
}

J
John Ferlan 已提交
86 87
static virSecretObjPtr
listUnlink(virSecretObjPtr *pptr)
88
{
J
John Ferlan 已提交
89
    virSecretObjPtr secret;
90 91 92 93 94 95 96

    secret = *pptr;
    *pptr = secret->next;
    return secret;
}

static void
J
John Ferlan 已提交
97 98
listInsert(virSecretObjPtr *pptr,
           virSecretObjPtr secret)
99 100 101 102 103 104
{
    secret->next = *pptr;
    *pptr = secret;
}

static void
J
John Ferlan 已提交
105
secretFree(virSecretObjPtr secret)
106 107 108 109 110 111 112 113 114 115 116 117
{
    if (secret == NULL)
        return;

    virSecretDefFree(secret->def);
    if (secret->value != NULL) {
        memset(secret->value, 0, secret->value_size);
        VIR_FREE(secret->value);
    }
    VIR_FREE(secret);
}

J
John Ferlan 已提交
118
static virSecretObjPtr
119
secretFindByUUID(const unsigned char *uuid)
120
{
J
John Ferlan 已提交
121
    virSecretObjPtr *pptr, s;
122 123 124

    for (pptr = &driver->secrets; *pptr != NULL; pptr = &s->next) {
        s = *pptr;
125
        if (memcmp(s->def->uuid, uuid, VIR_UUID_BUFLEN) == 0)
126
            return s;
127 128 129 130
    }
    return NULL;
}

J
John Ferlan 已提交
131
static virSecretObjPtr
132 133
secretFindByUsage(int usageType,
                  const char *usageID)
134
{
J
John Ferlan 已提交
135
    virSecretObjPtr *pptr, s;
136

137 138
    for (pptr = &driver->secrets; *pptr != NULL; pptr = &s->next) {
        s = *pptr;
139

140 141
        if (s->def->usage_type != usageType)
            continue;
142

143 144 145 146
        switch (usageType) {
        case VIR_SECRET_USAGE_TYPE_NONE:
            /* never match this */
            break;
147

148 149 150 151
        case VIR_SECRET_USAGE_TYPE_VOLUME:
            if (STREQ(s->def->usage.volume, usageID))
                return s;
            break;
S
Sage Weil 已提交
152 153 154 155 156

        case VIR_SECRET_USAGE_TYPE_CEPH:
            if (STREQ(s->def->usage.ceph, usageID))
                return s;
            break;
157 158 159 160 161

        case VIR_SECRET_USAGE_TYPE_ISCSI:
            if (STREQ(s->def->usage.target, usageID))
                return s;
            break;
162
        }
163
    }
164
    return NULL;
165 166
}

167
/* Permament secret storage */
168 169 170 171 172 173 174

/* Secrets are stored in virSecretDriverStatePtr->directory.  Each secret
   has virSecretDef stored as XML in "$basename.xml".  If a value of the
   secret is defined, it is stored as base64 (with no formatting) in
   "$basename.base64".  "$basename" is in both cases the base64-encoded UUID. */

static int
175 176
secretRewriteFile(int fd,
                  void *opaque)
177
{
178
    char *data = opaque;
179

180 181
    if (safewrite(fd, data, strlen(data)) < 0)
        return -1;
182

183
    return 0;
184 185 186
}

static char *
J
John Ferlan 已提交
187
secretComputePath(const virSecretObj *secret,
188
                  const char *suffix)
189
{
190 191
    char *ret;
    char uuidstr[VIR_UUID_STRING_BUFLEN];
192

193
    virUUIDFormat(secret->def->uuid, uuidstr);
194

195 196
    ignore_value(virAsprintf(&ret, "%s/%s%s", driver->directory,
                             uuidstr, suffix));
197 198 199 200
    return ret;
}

static char *
J
John Ferlan 已提交
201
secretXMLPath(const virSecretObj *secret)
202
{
203
    return secretComputePath(secret, ".xml");
204 205 206
}

static char *
J
John Ferlan 已提交
207
secretBase64Path(const virSecretObj *secret)
208
{
209
    return secretComputePath(secret, ".base64");
210 211 212
}

static int
213
secretEnsureDirectory(void)
214 215
{
    if (mkdir(driver->directory, S_IRWXU) < 0 && errno != EEXIST) {
216
        virReportSystemError(errno, _("cannot create '%s'"),
217 218 219 220 221 222 223
                             driver->directory);
        return -1;
    }
    return 0;
}

static int
J
John Ferlan 已提交
224
secretSaveDef(const virSecretObj *secret)
225 226 227 228
{
    char *filename = NULL, *xml = NULL;
    int ret = -1;

229
    if (secretEnsureDirectory() < 0)
230 231
        goto cleanup;

232
    if (!(filename = secretXMLPath(secret)))
233
        goto cleanup;
234 235

    if (!(xml = virSecretDefFormat(secret->def)))
236 237
        goto cleanup;

238 239
    if (virFileRewrite(filename, S_IRUSR | S_IWUSR,
                       secretRewriteFile, xml) < 0)
240 241 242 243
        goto cleanup;

    ret = 0;

244
 cleanup:
245 246 247 248 249 250
    VIR_FREE(xml);
    VIR_FREE(filename);
    return ret;
}

static int
J
John Ferlan 已提交
251
secretSaveValue(const virSecretObj *secret)
252 253 254 255 256 257 258
{
    char *filename = NULL, *base64 = NULL;
    int ret = -1;

    if (secret->value == NULL)
        return 0;

259
    if (secretEnsureDirectory() < 0)
260 261
        goto cleanup;

262
    if (!(filename = secretBase64Path(secret)))
263
        goto cleanup;
264

265 266 267
    base64_encode_alloc((const char *)secret->value, secret->value_size,
                        &base64);
    if (base64 == NULL) {
268
        virReportOOMError();
269 270 271
        goto cleanup;
    }

272 273
    if (virFileRewrite(filename, S_IRUSR | S_IWUSR,
                       secretRewriteFile, base64) < 0)
274 275 276 277
        goto cleanup;

    ret = 0;

278
 cleanup:
279 280 281 282 283 284
    VIR_FREE(base64);
    VIR_FREE(filename);
    return ret;
}

static int
J
John Ferlan 已提交
285
secretDeleteSaved(const virSecretObj *secret)
286 287 288 289
{
    char *xml_filename = NULL, *value_filename = NULL;
    int ret = -1;

290
    if (!(xml_filename = secretXMLPath(secret)))
291
        goto cleanup;
292 293

    if (!(value_filename = secretBase64Path(secret)))
294 295 296 297 298 299 300 301 302 303
        goto cleanup;

    if (unlink(xml_filename) < 0 && errno != ENOENT)
        goto cleanup;
    /* When the XML is missing, the rest may waste disk space, but the secret
       won't be loaded again, so we have succeeded already. */
    ret = 0;

    (void)unlink(value_filename);

304
 cleanup:
305 306 307 308 309 310
    VIR_FREE(value_filename);
    VIR_FREE(xml_filename);
    return ret;
}

static int
311
secretLoadValidateUUID(virSecretDefPtr def,
312 313
                       const char *xml_basename)
{
314
    char uuidstr[VIR_UUID_STRING_BUFLEN];
315

316
    virUUIDFormat(def->uuid, uuidstr);
317

318
    if (!virFileMatchesNameSuffix(xml_basename, uuidstr, ".xml")) {
319 320 321
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("<uuid> does not match secret file name '%s'"),
                       xml_basename);
322 323 324 325 326 327 328
        return -1;
    }

    return 0;
}

static int
J
John Ferlan 已提交
329
secretLoadValue(virSecretObjPtr secret)
330 331 332 333 334 335
{
    int ret = -1, fd = -1;
    struct stat st;
    char *filename = NULL, *contents = NULL, *value = NULL;
    size_t value_size;

336
    if (!(filename = secretBase64Path(secret)))
337 338
        goto cleanup;

339
    if ((fd = open(filename, O_RDONLY)) == -1) {
340 341 342 343
        if (errno == ENOENT) {
            ret = 0;
            goto cleanup;
        }
344
        virReportSystemError(errno, _("cannot open '%s'"), filename);
345 346
        goto cleanup;
    }
347

348
    if (fstat(fd, &st) < 0) {
349
        virReportSystemError(errno, _("cannot stat '%s'"), filename);
350 351
        goto cleanup;
    }
352

353
    if ((size_t)st.st_size != st.st_size) {
354 355
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("'%s' file does not fit in memory"), filename);
356 357 358
        goto cleanup;
    }

359
    if (VIR_ALLOC_N(contents, st.st_size) < 0)
360
        goto cleanup;
361

362
    if (saferead(fd, contents, st.st_size) != st.st_size) {
363
        virReportSystemError(errno, _("cannot read '%s'"), filename);
364 365
        goto cleanup;
    }
366

367
    VIR_FORCE_CLOSE(fd);
368 369

    if (!base64_decode_alloc(contents, st.st_size, &value, &value_size)) {
370 371
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("invalid base64 in '%s'"), filename);
372 373
        goto cleanup;
    }
374
    if (value == NULL)
375 376 377 378 379 380 381 382
        goto cleanup;

    secret->value = (unsigned char *)value;
    value = NULL;
    secret->value_size = value_size;

    ret = 0;

383
 cleanup:
384 385 386 387 388 389 390 391
    if (value != NULL) {
        memset(value, 0, value_size);
        VIR_FREE(value);
    }
    if (contents != NULL) {
        memset(contents, 0, st.st_size);
        VIR_FREE(contents);
    }
392
    VIR_FORCE_CLOSE(fd);
393 394 395 396
    VIR_FREE(filename);
    return ret;
}

J
John Ferlan 已提交
397
static virSecretObjPtr
398
secretLoad(const char *xml_basename)
399
{
400
    virSecretDefPtr def = NULL;
J
John Ferlan 已提交
401
    virSecretObjPtr secret = NULL, ret = NULL;
402 403 404
    char *xml_filename;

    if (virAsprintf(&xml_filename, "%s/%s", driver->directory,
405
                    xml_basename) < 0)
406
        goto cleanup;
407 408

    if (!(def = virSecretDefParseFile(xml_filename)))
409
        goto cleanup;
410

411 412
    VIR_FREE(xml_filename);

413
    if (secretLoadValidateUUID(def, xml_basename) < 0)
414 415
        goto cleanup;

416
    if (VIR_ALLOC(secret) < 0)
417 418 419 420
        goto cleanup;
    secret->def = def;
    def = NULL;

421
    if (secretLoadValue(secret) < 0)
422 423 424 425 426
        goto cleanup;

    ret = secret;
    secret = NULL;

427
 cleanup:
428 429 430 431 432 433 434
    secretFree(secret);
    virSecretDefFree(def);
    VIR_FREE(xml_filename);
    return ret;
}

static int
J
John Ferlan 已提交
435
loadSecrets(virSecretObjPtr *dest)
436 437 438
{
    DIR *dir = NULL;
    struct dirent *de;
J
John Ferlan 已提交
439
    virSecretObjPtr list = NULL;
440

441
    if (!(dir = opendir(driver->directory))) {
442 443
        if (errno == ENOENT)
            return 0;
444
        virReportSystemError(errno, _("cannot open '%s'"),
445
                             driver->directory);
446
        return -1;
447
    }
448

E
Eric Blake 已提交
449
    while (virDirRead(dir, &de, NULL) > 0) {
J
John Ferlan 已提交
450
        virSecretObjPtr secret;
451 452 453

        if (STREQ(de->d_name, ".") || STREQ(de->d_name, ".."))
            continue;
454

455 456 457
        if (!virFileHasSuffix(de->d_name, ".xml"))
            continue;

458
        if (!(secret = secretLoad(de->d_name))) {
459 460
            virErrorPtr err = virGetLastError();

461
            VIR_ERROR(_("Error reading secret: %s"),
462
                      err != NULL ? err->message: _("unknown error"));
463 464 465
            virResetError(err);
            continue;
        }
466

467 468
        listInsert(&list, secret);
    }
E
Eric Blake 已提交
469
    /* Ignore error reported by readdir, if any.  It's better to keep the
470 471 472
       secrets we managed to find. */

    while (list != NULL) {
J
John Ferlan 已提交
473
        virSecretObjPtr s;
474 475 476 477 478

        s = listUnlink(&list);
        listInsert(dest, s);
    }

479 480
    closedir(dir);
    return 0;
481 482
}

483
/* Driver functions */
484 485

static int
486
secretConnectNumOfSecrets(virConnectPtr conn)
487
{
488
    size_t i;
J
John Ferlan 已提交
489
    virSecretObjPtr secret;
490

491 492 493
    if (virConnectNumOfSecretsEnsureACL(conn) < 0)
        return -1;

494
    secretDriverLock();
495 496

    i = 0;
497 498 499 500 501
    for (secret = driver->secrets; secret != NULL; secret = secret->next) {
        if (virConnectNumOfSecretsCheckACL(conn,
                                           secret->def))
            i++;
    }
502

503
    secretDriverUnlock();
504 505 506 507
    return i;
}

static int
508 509 510
secretConnectListSecrets(virConnectPtr conn,
                         char **uuids,
                         int maxuuids)
511
{
512
    size_t i;
J
John Ferlan 已提交
513
    virSecretObjPtr secret;
514 515 516

    memset(uuids, 0, maxuuids * sizeof(*uuids));

517 518 519
    if (virConnectListSecretsEnsureACL(conn) < 0)
        return -1;

520
    secretDriverLock();
521 522 523

    i = 0;
    for (secret = driver->secrets; secret != NULL; secret = secret->next) {
524
        char *uuidstr;
525 526 527
        if (!virConnectListSecretsCheckACL(conn,
                                           secret->def))
            continue;
528 529
        if (i == maxuuids)
            break;
530
        if (VIR_ALLOC_N(uuidstr, VIR_UUID_STRING_BUFLEN) < 0)
531
            goto cleanup;
532 533
        virUUIDFormat(secret->def->uuid, uuidstr);
        uuids[i] = uuidstr;
534 535 536
        i++;
    }

537
    secretDriverUnlock();
538 539
    return i;

540
 cleanup:
541
    secretDriverUnlock();
542 543 544 545 546 547 548

    for (i = 0; i < maxuuids; i++)
        VIR_FREE(uuids[i]);

    return -1;
}

549 550 551 552 553 554 555 556 557 558
static const char *
secretUsageIDForDef(virSecretDefPtr def)
{
    switch (def->usage_type) {
    case VIR_SECRET_USAGE_TYPE_NONE:
        return "";

    case VIR_SECRET_USAGE_TYPE_VOLUME:
        return def->usage.volume;

S
Sage Weil 已提交
559 560 561
    case VIR_SECRET_USAGE_TYPE_CEPH:
        return def->usage.ceph;

562 563 564
    case VIR_SECRET_USAGE_TYPE_ISCSI:
        return def->usage.target;

565 566 567 568 569
    default:
        return NULL;
    }
}

O
Osier Yang 已提交
570 571
#define MATCH(FLAG) (flags & (FLAG))
static int
572 573
secretConnectListAllSecrets(virConnectPtr conn,
                            virSecretPtr **secrets,
574 575
                            unsigned int flags)
{
O
Osier Yang 已提交
576 577 578
    virSecretPtr *tmp_secrets = NULL;
    int nsecrets = 0;
    int ret_nsecrets = 0;
579
    virSecretObjPtr secret = NULL;
580
    size_t i = 0;
O
Osier Yang 已提交
581 582 583 584
    int ret = -1;

    virCheckFlags(VIR_CONNECT_LIST_SECRETS_FILTERS_ALL, -1);

585 586 587
    if (virConnectListAllSecretsEnsureACL(conn) < 0)
        return -1;

588
    secretDriverLock();
O
Osier Yang 已提交
589

590
    for (secret = driver->secrets; secret != NULL; secret = secret->next)
O
Osier Yang 已提交
591 592
        nsecrets++;

593 594
    if (secrets && VIR_ALLOC_N(tmp_secrets, nsecrets + 1) < 0)
        goto cleanup;
O
Osier Yang 已提交
595

596
    for (secret = driver->secrets; secret != NULL; secret = secret->next) {
597
        if (!virConnectListAllSecretsCheckACL(conn,
598
                                              secret->def))
599 600
            continue;

O
Osier Yang 已提交
601 602 603
        /* filter by whether it's ephemeral */
        if (MATCH(VIR_CONNECT_LIST_SECRETS_FILTERS_EPHEMERAL) &&
            !((MATCH(VIR_CONNECT_LIST_SECRETS_EPHEMERAL) &&
604
               secret->def->ephemeral) ||
O
Osier Yang 已提交
605
              (MATCH(VIR_CONNECT_LIST_SECRETS_NO_EPHEMERAL) &&
606
               !secret->def->ephemeral)))
O
Osier Yang 已提交
607 608 609 610 611
            continue;

        /* filter by whether it's private */
        if (MATCH(VIR_CONNECT_LIST_SECRETS_FILTERS_PRIVATE) &&
            !((MATCH(VIR_CONNECT_LIST_SECRETS_PRIVATE) &&
612
               secret->def->private) ||
O
Osier Yang 已提交
613
              (MATCH(VIR_CONNECT_LIST_SECRETS_NO_PRIVATE) &&
614
               !secret->def->private)))
O
Osier Yang 已提交
615 616 617
            continue;

        if (secrets) {
618 619
            if (!(tmp_secrets[ret_nsecrets] =
                  virGetSecret(conn,
620 621 622
                               secret->def->uuid,
                               secret->def->usage_type,
                               secretUsageIDForDef(secret->def))))
O
Osier Yang 已提交
623 624 625 626 627 628 629 630 631 632 633 634 635 636 637
                goto cleanup;
        }
        ret_nsecrets++;
    }

    if (tmp_secrets) {
        /* trim the array to the final size */
        ignore_value(VIR_REALLOC_N(tmp_secrets, ret_nsecrets + 1));
        *secrets = tmp_secrets;
        tmp_secrets = NULL;
    }

    ret = ret_nsecrets;

 cleanup:
638
    secretDriverUnlock();
O
Osier Yang 已提交
639
    if (tmp_secrets) {
640 641
        for (i = 0; i < ret_nsecrets; i ++)
            virObjectUnref(tmp_secrets[i]);
O
Osier Yang 已提交
642 643 644 645 646 647 648 649
    }
    VIR_FREE(tmp_secrets);

    return ret;
}
#undef MATCH


650
static virSecretPtr
651 652
secretLookupByUUID(virConnectPtr conn,
                   const unsigned char *uuid)
653 654
{
    virSecretPtr ret = NULL;
J
John Ferlan 已提交
655
    virSecretObjPtr secret;
656

657
    secretDriverLock();
658

659
    if (!(secret = secretFindByUUID(uuid))) {
660 661
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(uuid, uuidstr);
662 663
        virReportError(VIR_ERR_NO_SECRET,
                       _("no secret with matching uuid '%s'"), uuidstr);
664 665 666
        goto cleanup;
    }

667 668 669
    if (virSecretLookupByUUIDEnsureACL(conn, secret->def) < 0)
        goto cleanup;

670 671 672 673 674
    ret = virGetSecret(conn,
                       secret->def->uuid,
                       secret->def->usage_type,
                       secretUsageIDForDef(secret->def));

675
 cleanup:
676
    secretDriverUnlock();
677 678 679 680 681
    return ret;
}


static virSecretPtr
682 683 684
secretLookupByUsage(virConnectPtr conn,
                    int usageType,
                    const char *usageID)
685 686
{
    virSecretPtr ret = NULL;
J
John Ferlan 已提交
687
    virSecretObjPtr secret;
688

689
    secretDriverLock();
690

691
    if (!(secret = secretFindByUsage(usageType, usageID))) {
692 693
        virReportError(VIR_ERR_NO_SECRET,
                       _("no secret with matching usage '%s'"), usageID);
694 695 696
        goto cleanup;
    }

697 698 699
    if (virSecretLookupByUsageEnsureACL(conn, secret->def) < 0)
        goto cleanup;

700 701 702 703
    ret = virGetSecret(conn,
                       secret->def->uuid,
                       secret->def->usage_type,
                       secretUsageIDForDef(secret->def));
704

705
 cleanup:
706
    secretDriverUnlock();
707 708 709 710 711
    return ret;
}


static virSecretPtr
712 713
secretDefineXML(virConnectPtr conn,
                const char *xml,
714
                unsigned int flags)
715 716
{
    virSecretPtr ret = NULL;
J
John Ferlan 已提交
717
    virSecretObjPtr secret;
718 719
    virSecretDefPtr backup = NULL;
    virSecretDefPtr new_attrs;
720

721 722
    virCheckFlags(0, NULL);

723
    if (!(new_attrs = virSecretDefParseString(xml)))
724 725
        return NULL;

726
    secretDriverLock();
727

728 729 730
    if (virSecretDefineXMLEnsureACL(conn, new_attrs) < 0)
        goto cleanup;

731 732 733
    if (!(secret = secretFindByUUID(new_attrs->uuid))) {
        /* No existing secret with same UUID,
         * try look for matching usage instead */
734
        const char *usageID = secretUsageIDForDef(new_attrs);
735
        if ((secret = secretFindByUsage(new_attrs->usage_type, usageID))) {
736 737
            char uuidstr[VIR_UUID_STRING_BUFLEN];
            virUUIDFormat(secret->def->uuid, uuidstr);
738
            virReportError(VIR_ERR_INTERNAL_ERROR,
739 740
                           _("a secret with UUID %s already defined for "
                             "use with %s"),
741
                           uuidstr, usageID);
742 743
            goto cleanup;
        }
744

745
        /* No existing secret at all, create one */
746
        if (VIR_ALLOC(secret) < 0)
747
            goto cleanup;
748

749 750 751 752 753 754 755 756
        listInsert(&driver->secrets, secret);
        secret->def = new_attrs;
    } else {
        const char *newUsageID = secretUsageIDForDef(new_attrs);
        const char *oldUsageID = secretUsageIDForDef(secret->def);
        if (STRNEQ(oldUsageID, newUsageID)) {
            char uuidstr[VIR_UUID_STRING_BUFLEN];
            virUUIDFormat(secret->def->uuid, uuidstr);
757
            virReportError(VIR_ERR_INTERNAL_ERROR,
758 759
                           _("a secret with UUID %s is already defined "
                             "for use with %s"),
760
                           uuidstr, oldUsageID);
761 762 763 764
            goto cleanup;
        }

        if (secret->def->private && !new_attrs->private) {
765 766
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("cannot change private flag on existing secret"));
767 768 769 770 771 772
            goto cleanup;
        }

        /* Got an existing secret matches attrs, so reuse that */
        backup = secret->def;
        secret->def = new_attrs;
773 774 775
    }

    if (!new_attrs->ephemeral) {
776
        if (backup && backup->ephemeral) {
777
            if (secretSaveValue(secret) < 0)
778 779
                goto restore_backup;
        }
780
        if (secretSaveDef(secret) < 0) {
781
            if (backup && backup->ephemeral) {
782 783 784
                char *filename;

                /* Undo the secretSaveValue() above; ignore errors */
785
                filename = secretBase64Path(secret);
786 787 788 789 790 791
                if (filename != NULL)
                    (void)unlink(filename);
                VIR_FREE(filename);
            }
            goto restore_backup;
        }
792
    } else if (backup && !backup->ephemeral) {
793
        if (secretDeleteSaved(secret) < 0)
794 795
            goto restore_backup;
    }
796
    /* Saved successfully - drop old values */
797 798 799
    new_attrs = NULL;
    virSecretDefFree(backup);

800 801 802 803
    ret = virGetSecret(conn,
                       secret->def->uuid,
                       secret->def->usage_type,
                       secretUsageIDForDef(secret->def));
804 805
    goto cleanup;

806
 restore_backup:
807 808 809 810
    if (backup) {
        /* Error - restore previous state and free new attributes */
        secret->def = backup;
    } else {
811
        /* "secret" was added to the head of the list above */
812
        if (listUnlink(&driver->secrets) != secret)
813 814
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("list of secrets is inconsistent"));
815 816 817 818
        else
            secretFree(secret);
    }

819
 cleanup:
820
    virSecretDefFree(new_attrs);
821
    secretDriverUnlock();
822 823 824 825 826

    return ret;
}

static char *
827 828
secretGetXMLDesc(virSecretPtr obj,
                 unsigned int flags)
829 830
{
    char *ret = NULL;
J
John Ferlan 已提交
831
    virSecretObjPtr secret;
832

833 834
    virCheckFlags(0, NULL);

835
    secretDriverLock();
836

837
    if (!(secret = secretFindByUUID(obj->uuid))) {
838 839
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(obj->uuid, uuidstr);
840 841
        virReportError(VIR_ERR_NO_SECRET,
                       _("no secret with matching uuid '%s'"), uuidstr);
842 843 844
        goto cleanup;
    }

845 846 847
    if (virSecretGetXMLDescEnsureACL(obj->conn, secret->def) < 0)
        goto cleanup;

848
    ret = virSecretDefFormat(secret->def);
849

850
 cleanup:
851
    secretDriverUnlock();
852 853 854 855 856

    return ret;
}

static int
857 858 859 860
secretSetValue(virSecretPtr obj,
               const unsigned char *value,
               size_t value_size,
               unsigned int flags)
861 862 863 864
{
    int ret = -1;
    unsigned char *old_value, *new_value;
    size_t old_value_size;
J
John Ferlan 已提交
865
    virSecretObjPtr secret;
866

867 868
    virCheckFlags(0, -1);

869
    if (VIR_ALLOC_N(new_value, value_size) < 0)
870 871
        return -1;

872
    secretDriverLock();
873

874
    if (!(secret = secretFindByUUID(obj->uuid))) {
875 876
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(obj->uuid, uuidstr);
877 878
        virReportError(VIR_ERR_NO_SECRET,
                       _("no secret with matching uuid '%s'"), uuidstr);
879 880 881
        goto cleanup;
    }

882 883 884
    if (virSecretSetValueEnsureACL(obj->conn, secret->def) < 0)
        goto cleanup;

885 886 887 888 889 890 891
    old_value = secret->value;
    old_value_size = secret->value_size;

    memcpy(new_value, value, value_size);
    secret->value = new_value;
    secret->value_size = value_size;
    if (!secret->def->ephemeral) {
892
        if (secretSaveValue(secret) < 0)
893 894
            goto restore_backup;
    }
895
    /* Saved successfully - drop old value */
896 897 898 899 900 901 902 903 904
    if (old_value != NULL) {
        memset(old_value, 0, old_value_size);
        VIR_FREE(old_value);
    }
    new_value = NULL;

    ret = 0;
    goto cleanup;

905
 restore_backup:
906 907 908 909 910
    /* Error - restore previous state and free new value */
    secret->value = old_value;
    secret->value_size = old_value_size;
    memset(new_value, 0, value_size);

911
 cleanup:
912
    secretDriverUnlock();
913 914 915 916 917 918 919

    VIR_FREE(new_value);

    return ret;
}

static unsigned char *
920 921 922
secretGetValue(virSecretPtr obj,
               size_t *value_size,
               unsigned int flags,
923
               unsigned int internalFlags)
924 925
{
    unsigned char *ret = NULL;
J
John Ferlan 已提交
926
    virSecretObjPtr secret;
927

928 929
    virCheckFlags(0, NULL);

930
    secretDriverLock();
931

932
    if (!(secret = secretFindByUUID(obj->uuid))) {
933 934
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(obj->uuid, uuidstr);
935 936
        virReportError(VIR_ERR_NO_SECRET,
                       _("no secret with matching uuid '%s'"), uuidstr);
937 938
        goto cleanup;
    }
939

940 941 942
    if (virSecretGetValueEnsureACL(obj->conn, secret->def) < 0)
        goto cleanup;

943
    if (secret->value == NULL) {
944 945
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(obj->uuid, uuidstr);
946 947
        virReportError(VIR_ERR_NO_SECRET,
                       _("secret '%s' does not have a value"), uuidstr);
948 949 950
        goto cleanup;
    }

951
    if ((internalFlags & VIR_SECRET_GET_VALUE_INTERNAL_CALL) == 0 &&
952
        secret->def->private) {
953
        virReportError(VIR_ERR_INVALID_SECRET, "%s",
954
                       _("secret is private"));
955 956 957
        goto cleanup;
    }

958
    if (VIR_ALLOC_N(ret, secret->value_size) < 0)
959 960 961 962
        goto cleanup;
    memcpy(ret, secret->value, secret->value_size);
    *value_size = secret->value_size;

963
 cleanup:
964
    secretDriverUnlock();
965 966 967 968 969 970 971 972

    return ret;
}

static int
secretUndefine(virSecretPtr obj)
{
    int ret = -1;
J
John Ferlan 已提交
973
    virSecretObjPtr secret;
974

975
    secretDriverLock();
976

977
    if (!(secret = secretFindByUUID(obj->uuid))) {
978 979
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(obj->uuid, uuidstr);
980 981
        virReportError(VIR_ERR_NO_SECRET,
                       _("no secret with matching uuid '%s'"), uuidstr);
982 983 984
        goto cleanup;
    }

985 986 987
    if (virSecretUndefineEnsureACL(obj->conn, secret->def) < 0)
        goto cleanup;

988
    if (!secret->def->ephemeral &&
989
        secretDeleteSaved(secret) < 0)
990 991 992 993 994
        goto cleanup;

    if (driver->secrets == secret) {
        driver->secrets = secret->next;
    } else {
J
John Ferlan 已提交
995
        virSecretObjPtr tmp = driver->secrets;
996 997 998 999
        while (tmp && tmp->next != secret)
            tmp = tmp->next;
        if (tmp)
            tmp->next = secret->next;
1000 1001 1002 1003 1004
    }
    secretFree(secret);

    ret = 0;

1005
 cleanup:
1006
    secretDriverUnlock();
1007 1008 1009 1010 1011

    return ret;
}

static int
1012
secretStateCleanup(void)
1013
{
1014
    if (driver == NULL)
1015 1016
        return -1;

1017
    secretDriverLock();
1018

1019
    while (driver->secrets != NULL) {
J
John Ferlan 已提交
1020
        virSecretObjPtr s;
1021

1022
        s = listUnlink(&driver->secrets);
1023 1024
        secretFree(s);
    }
1025
    VIR_FREE(driver->directory);
1026

1027 1028 1029
    secretDriverUnlock();
    virMutexDestroy(&driver->lock);
    VIR_FREE(driver);
1030 1031 1032 1033 1034

    return 0;
}

static int
1035 1036 1037
secretStateInitialize(bool privileged,
                      virStateInhibitCallback callback ATTRIBUTE_UNUSED,
                      void *opaque ATTRIBUTE_UNUSED)
1038 1039 1040
{
    char *base = NULL;

1041
    if (VIR_ALLOC(driver) < 0)
1042 1043
        return -1;

1044 1045
    if (virMutexInit(&driver->lock) < 0) {
        VIR_FREE(driver);
1046 1047
        return -1;
    }
1048
    secretDriverLock();
1049 1050

    if (privileged) {
1051 1052
        if (VIR_STRDUP(base, SYSCONFDIR "/libvirt") < 0)
            goto error;
1053
    } else {
1054
        if (!(base = virGetUserConfigDirectory()))
1055 1056
            goto error;
    }
1057
    if (virAsprintf(&driver->directory, "%s/secrets", base) < 0)
1058
        goto error;
1059 1060
    VIR_FREE(base);

1061
    if (loadSecrets(&driver->secrets) < 0)
1062 1063
        goto error;

1064
    secretDriverUnlock();
1065 1066 1067 1068
    return 0;

 error:
    VIR_FREE(base);
1069
    secretDriverUnlock();
1070
    secretStateCleanup();
1071 1072 1073 1074
    return -1;
}

static int
1075
secretStateReload(void)
1076
{
J
John Ferlan 已提交
1077
    virSecretObjPtr new_secrets = NULL;
1078

1079
    if (!driver)
1080 1081
        return -1;

1082
    secretDriverLock();
1083

1084
    if (loadSecrets(&new_secrets) < 0)
1085 1086
        goto end;

1087 1088 1089
    /* Keep ephemeral secrets from current state.
     * Discard non-ephemeral secrets that were removed
     * by the secrets directory.  */
1090
    while (driver->secrets != NULL) {
J
John Ferlan 已提交
1091
        virSecretObjPtr s;
1092

1093
        s = listUnlink(&driver->secrets);
1094 1095 1096 1097 1098
        if (s->def->ephemeral)
            listInsert(&new_secrets, s);
        else
            secretFree(s);
    }
1099
    driver->secrets = new_secrets;
1100 1101

 end:
1102
    secretDriverUnlock();
1103 1104 1105 1106 1107
    return 0;
}

static virSecretDriver secretDriver = {
    .name = "secret",
1108 1109 1110
    .connectNumOfSecrets = secretConnectNumOfSecrets, /* 0.7.1 */
    .connectListSecrets = secretConnectListSecrets, /* 0.7.1 */
    .connectListAllSecrets = secretConnectListAllSecrets, /* 0.10.2 */
1111 1112 1113 1114 1115 1116 1117
    .secretLookupByUUID = secretLookupByUUID, /* 0.7.1 */
    .secretLookupByUsage = secretLookupByUsage, /* 0.7.1 */
    .secretDefineXML = secretDefineXML, /* 0.7.1 */
    .secretGetXMLDesc = secretGetXMLDesc, /* 0.7.1 */
    .secretSetValue = secretSetValue, /* 0.7.1 */
    .secretGetValue = secretGetValue, /* 0.7.1 */
    .secretUndefine = secretUndefine, /* 0.7.1 */
1118 1119 1120
};

static virStateDriver stateDriver = {
1121
    .name = "secret",
1122 1123 1124
    .stateInitialize = secretStateInitialize,
    .stateCleanup = secretStateCleanup,
    .stateReload = secretStateReload,
1125 1126 1127 1128 1129
};

int
secretRegister(void)
{
1130
    if (virSetSharedSecretDriver(&secretDriver) < 0)
1131 1132 1133
        return -1;
    if (virRegisterStateDriver(&stateDriver) < 0)
        return -1;
1134 1135
    return 0;
}