secret_driver.c 27.7 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
    char *configFile;
60 61 62 63 64 65 66 67 68
    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 已提交
69
    virSecretObj *secrets;
70
    char *configDir;
71 72
};

73
static virSecretDriverStatePtr driver;
74 75

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

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

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

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

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

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

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

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

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

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

139 140
    for (pptr = &driver->secrets; *pptr != NULL; pptr = &secret->next) {
        secret = *pptr;
141

142
        if (secret->def->usage_type != usageType)
143
            continue;
144

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

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

        case VIR_SECRET_USAGE_TYPE_CEPH:
156 157
            if (STREQ(secret->def->usage.ceph, usageID))
                return secret;
S
Sage Weil 已提交
158
            break;
159 160

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

169
/* Permament secret storage */
170

171
/* Secrets are stored in virSecretDriverStatePtr->configDir.  Each secret
172 173 174 175 176
   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
177 178
secretRewriteFile(int fd,
                  void *opaque)
179
{
180
    char *data = opaque;
181

182 183
    if (safewrite(fd, data, strlen(data)) < 0)
        return -1;
184

185
    return 0;
186 187 188
}

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

195
    virUUIDFormat(secret->def->uuid, uuidstr);
196

197
    ignore_value(virAsprintf(&ret, "%s/%s%s", driver->configDir,
198
                             uuidstr, suffix));
199 200 201 202 203
    return ret;
}


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

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

static int
J
John Ferlan 已提交
221
secretSaveDef(const virSecretObj *secret)
222
{
223
    char *xml = NULL;
224 225
    int ret = -1;

226
    if (secretEnsureDirectory() < 0)
227 228
        goto cleanup;

229
    if (!(xml = virSecretDefFormat(secret->def)))
230 231
        goto cleanup;

232
    if (virFileRewrite(secret->configFile, S_IRUSR | S_IWUSR,
233
                       secretRewriteFile, xml) < 0)
234 235 236 237
        goto cleanup;

    ret = 0;

238
 cleanup:
239 240 241 242 243
    VIR_FREE(xml);
    return ret;
}

static int
J
John Ferlan 已提交
244
secretSaveValue(const virSecretObj *secret)
245 246 247 248 249 250 251
{
    char *filename = NULL, *base64 = NULL;
    int ret = -1;

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

252
    if (secretEnsureDirectory() < 0)
253 254
        goto cleanup;

255
    if (!(filename = secretBase64Path(secret)))
256
        goto cleanup;
257

258 259 260
    base64_encode_alloc((const char *)secret->value, secret->value_size,
                        &base64);
    if (base64 == NULL) {
261
        virReportOOMError();
262 263 264
        goto cleanup;
    }

265 266
    if (virFileRewrite(filename, S_IRUSR | S_IWUSR,
                       secretRewriteFile, base64) < 0)
267 268 269 270
        goto cleanup;

    ret = 0;

271
 cleanup:
272 273 274 275 276 277
    VIR_FREE(base64);
    VIR_FREE(filename);
    return ret;
}

static int
J
John Ferlan 已提交
278
secretDeleteSaved(const virSecretObj *secret)
279
{
280
    char *value_filename = NULL;
281 282
    int ret = -1;

283
    if (!(value_filename = secretBase64Path(secret)))
284 285
        goto cleanup;

286
    if (unlink(secret->configFile) < 0 && errno != ENOENT)
287 288 289 290 291 292 293
        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);

294
 cleanup:
295 296 297 298 299
    VIR_FREE(value_filename);
    return ret;
}

static int
300
secretLoadValidateUUID(virSecretDefPtr def,
301
                       const char *file)
302
{
303
    char uuidstr[VIR_UUID_STRING_BUFLEN];
304

305
    virUUIDFormat(def->uuid, uuidstr);
306

307
    if (!virFileMatchesNameSuffix(file, uuidstr, ".xml")) {
308 309
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("<uuid> does not match secret file name '%s'"),
310
                       file);
311 312 313 314 315 316 317
        return -1;
    }

    return 0;
}

static int
J
John Ferlan 已提交
318
secretLoadValue(virSecretObjPtr secret)
319 320 321 322 323 324
{
    int ret = -1, fd = -1;
    struct stat st;
    char *filename = NULL, *contents = NULL, *value = NULL;
    size_t value_size;

325
    if (!(filename = secretBase64Path(secret)))
326 327
        goto cleanup;

328
    if ((fd = open(filename, O_RDONLY)) == -1) {
329 330 331 332
        if (errno == ENOENT) {
            ret = 0;
            goto cleanup;
        }
333
        virReportSystemError(errno, _("cannot open '%s'"), filename);
334 335
        goto cleanup;
    }
336

337
    if (fstat(fd, &st) < 0) {
338
        virReportSystemError(errno, _("cannot stat '%s'"), filename);
339 340
        goto cleanup;
    }
341

342
    if ((size_t)st.st_size != st.st_size) {
343 344
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("'%s' file does not fit in memory"), filename);
345 346 347
        goto cleanup;
    }

348
    if (VIR_ALLOC_N(contents, st.st_size) < 0)
349
        goto cleanup;
350

351
    if (saferead(fd, contents, st.st_size) != st.st_size) {
352
        virReportSystemError(errno, _("cannot read '%s'"), filename);
353 354
        goto cleanup;
    }
355

356
    VIR_FORCE_CLOSE(fd);
357 358

    if (!base64_decode_alloc(contents, st.st_size, &value, &value_size)) {
359 360
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("invalid base64 in '%s'"), filename);
361 362
        goto cleanup;
    }
363
    if (value == NULL)
364 365 366 367 368 369 370 371
        goto cleanup;

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

    ret = 0;

372
 cleanup:
373 374 375 376 377 378 379 380
    if (value != NULL) {
        memset(value, 0, value_size);
        VIR_FREE(value);
    }
    if (contents != NULL) {
        memset(contents, 0, st.st_size);
        VIR_FREE(contents);
    }
381
    VIR_FORCE_CLOSE(fd);
382 383 384 385
    VIR_FREE(filename);
    return ret;
}

J
John Ferlan 已提交
386
static virSecretObjPtr
387 388
secretLoad(const char *file,
           const char *path)
389
{
390
    virSecretDefPtr def = NULL;
J
John Ferlan 已提交
391
    virSecretObjPtr secret = NULL, ret = NULL;
392

393
    if (!(def = virSecretDefParseFile(path)))
394
        goto cleanup;
395

396
    if (secretLoadValidateUUID(def, file) < 0)
397 398
        goto cleanup;

399
    if (VIR_ALLOC(secret) < 0)
400 401 402 403
        goto cleanup;
    secret->def = def;
    def = NULL;

404 405 406
    if (VIR_STRDUP(secret->configFile, path) < 0)
        goto cleanup;

407
    if (secretLoadValue(secret) < 0)
408 409 410 411 412
        goto cleanup;

    ret = secret;
    secret = NULL;

413
 cleanup:
414 415 416 417 418 419
    secretFree(secret);
    virSecretDefFree(def);
    return ret;
}

static int
J
John Ferlan 已提交
420
loadSecrets(virSecretObjPtr *dest)
421 422 423
{
    DIR *dir = NULL;
    struct dirent *de;
J
John Ferlan 已提交
424
    virSecretObjPtr list = NULL;
425

426
    if (!(dir = opendir(driver->configDir))) {
427 428
        if (errno == ENOENT)
            return 0;
429
        virReportSystemError(errno, _("cannot open '%s'"),
430
                             driver->configDir);
431
        return -1;
432
    }
433

E
Eric Blake 已提交
434
    while (virDirRead(dir, &de, NULL) > 0) {
435
        char *path;
J
John Ferlan 已提交
436
        virSecretObjPtr secret;
437 438 439

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

441 442 443
        if (!virFileHasSuffix(de->d_name, ".xml"))
            continue;

444 445 446 447
        if (!(path = virFileBuildPath(driver->configDir, de->d_name, NULL)))
            continue;

        if (!(secret = secretLoad(de->d_name, path))) {
448 449
            virErrorPtr err = virGetLastError();

450
            VIR_ERROR(_("Error reading secret: %s"),
451
                      err != NULL ? err->message: _("unknown error"));
452
            virResetError(err);
453
            VIR_FREE(path);
454 455
            continue;
        }
456

457
        VIR_FREE(path);
458 459
        listInsert(&list, secret);
    }
E
Eric Blake 已提交
460
    /* Ignore error reported by readdir, if any.  It's better to keep the
461 462 463
       secrets we managed to find. */

    while (list != NULL) {
464
        virSecretObjPtr secret;
465

466 467
        secret = listUnlink(&list);
        listInsert(dest, secret);
468 469
    }

470 471
    closedir(dir);
    return 0;
472 473
}

474
/* Driver functions */
475 476

static int
477
secretConnectNumOfSecrets(virConnectPtr conn)
478
{
479
    size_t i;
J
John Ferlan 已提交
480
    virSecretObjPtr secret;
481

482 483 484
    if (virConnectNumOfSecretsEnsureACL(conn) < 0)
        return -1;

485
    secretDriverLock();
486 487

    i = 0;
488 489 490 491 492
    for (secret = driver->secrets; secret != NULL; secret = secret->next) {
        if (virConnectNumOfSecretsCheckACL(conn,
                                           secret->def))
            i++;
    }
493

494
    secretDriverUnlock();
495 496 497 498
    return i;
}

static int
499 500 501
secretConnectListSecrets(virConnectPtr conn,
                         char **uuids,
                         int maxuuids)
502
{
503
    size_t i;
J
John Ferlan 已提交
504
    virSecretObjPtr secret;
505 506 507

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

508 509 510
    if (virConnectListSecretsEnsureACL(conn) < 0)
        return -1;

511
    secretDriverLock();
512 513 514

    i = 0;
    for (secret = driver->secrets; secret != NULL; secret = secret->next) {
515
        char *uuidstr;
516 517 518
        if (!virConnectListSecretsCheckACL(conn,
                                           secret->def))
            continue;
519 520
        if (i == maxuuids)
            break;
521
        if (VIR_ALLOC_N(uuidstr, VIR_UUID_STRING_BUFLEN) < 0)
522
            goto cleanup;
523 524
        virUUIDFormat(secret->def->uuid, uuidstr);
        uuids[i] = uuidstr;
525 526 527
        i++;
    }

528
    secretDriverUnlock();
529 530
    return i;

531
 cleanup:
532
    secretDriverUnlock();
533 534 535 536 537 538 539

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

    return -1;
}

540 541 542 543 544 545 546 547 548 549
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 已提交
550 551 552
    case VIR_SECRET_USAGE_TYPE_CEPH:
        return def->usage.ceph;

553 554 555
    case VIR_SECRET_USAGE_TYPE_ISCSI:
        return def->usage.target;

556 557 558 559 560
    default:
        return NULL;
    }
}

O
Osier Yang 已提交
561 562
#define MATCH(FLAG) (flags & (FLAG))
static int
563 564
secretConnectListAllSecrets(virConnectPtr conn,
                            virSecretPtr **secrets,
565 566
                            unsigned int flags)
{
O
Osier Yang 已提交
567 568 569
    virSecretPtr *tmp_secrets = NULL;
    int nsecrets = 0;
    int ret_nsecrets = 0;
570
    virSecretObjPtr secret = NULL;
571
    size_t i = 0;
O
Osier Yang 已提交
572 573 574 575
    int ret = -1;

    virCheckFlags(VIR_CONNECT_LIST_SECRETS_FILTERS_ALL, -1);

576 577 578
    if (virConnectListAllSecretsEnsureACL(conn) < 0)
        return -1;

579
    secretDriverLock();
O
Osier Yang 已提交
580

581
    for (secret = driver->secrets; secret != NULL; secret = secret->next)
O
Osier Yang 已提交
582 583
        nsecrets++;

584 585
    if (secrets && VIR_ALLOC_N(tmp_secrets, nsecrets + 1) < 0)
        goto cleanup;
O
Osier Yang 已提交
586

587
    for (secret = driver->secrets; secret != NULL; secret = secret->next) {
588
        if (!virConnectListAllSecretsCheckACL(conn,
589
                                              secret->def))
590 591
            continue;

O
Osier Yang 已提交
592 593 594
        /* filter by whether it's ephemeral */
        if (MATCH(VIR_CONNECT_LIST_SECRETS_FILTERS_EPHEMERAL) &&
            !((MATCH(VIR_CONNECT_LIST_SECRETS_EPHEMERAL) &&
595
               secret->def->ephemeral) ||
O
Osier Yang 已提交
596
              (MATCH(VIR_CONNECT_LIST_SECRETS_NO_EPHEMERAL) &&
597
               !secret->def->ephemeral)))
O
Osier Yang 已提交
598 599 600 601 602
            continue;

        /* filter by whether it's private */
        if (MATCH(VIR_CONNECT_LIST_SECRETS_FILTERS_PRIVATE) &&
            !((MATCH(VIR_CONNECT_LIST_SECRETS_PRIVATE) &&
603
               secret->def->private) ||
O
Osier Yang 已提交
604
              (MATCH(VIR_CONNECT_LIST_SECRETS_NO_PRIVATE) &&
605
               !secret->def->private)))
O
Osier Yang 已提交
606 607 608
            continue;

        if (secrets) {
609 610
            if (!(tmp_secrets[ret_nsecrets] =
                  virGetSecret(conn,
611 612 613
                               secret->def->uuid,
                               secret->def->usage_type,
                               secretUsageIDForDef(secret->def))))
O
Osier Yang 已提交
614 615 616 617 618 619 620 621 622 623 624 625 626 627 628
                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:
629
    secretDriverUnlock();
O
Osier Yang 已提交
630
    if (tmp_secrets) {
631 632
        for (i = 0; i < ret_nsecrets; i ++)
            virObjectUnref(tmp_secrets[i]);
O
Osier Yang 已提交
633 634 635 636 637 638 639 640
    }
    VIR_FREE(tmp_secrets);

    return ret;
}
#undef MATCH


641
static virSecretPtr
642 643
secretLookupByUUID(virConnectPtr conn,
                   const unsigned char *uuid)
644 645
{
    virSecretPtr ret = NULL;
J
John Ferlan 已提交
646
    virSecretObjPtr secret;
647

648
    secretDriverLock();
649

650
    if (!(secret = secretFindByUUID(uuid))) {
651 652
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(uuid, uuidstr);
653 654
        virReportError(VIR_ERR_NO_SECRET,
                       _("no secret with matching uuid '%s'"), uuidstr);
655 656 657
        goto cleanup;
    }

658 659 660
    if (virSecretLookupByUUIDEnsureACL(conn, secret->def) < 0)
        goto cleanup;

661 662 663 664 665
    ret = virGetSecret(conn,
                       secret->def->uuid,
                       secret->def->usage_type,
                       secretUsageIDForDef(secret->def));

666
 cleanup:
667
    secretDriverUnlock();
668 669 670 671 672
    return ret;
}


static virSecretPtr
673 674 675
secretLookupByUsage(virConnectPtr conn,
                    int usageType,
                    const char *usageID)
676 677
{
    virSecretPtr ret = NULL;
J
John Ferlan 已提交
678
    virSecretObjPtr secret;
679

680
    secretDriverLock();
681

682
    if (!(secret = secretFindByUsage(usageType, usageID))) {
683 684
        virReportError(VIR_ERR_NO_SECRET,
                       _("no secret with matching usage '%s'"), usageID);
685 686 687
        goto cleanup;
    }

688 689 690
    if (virSecretLookupByUsageEnsureACL(conn, secret->def) < 0)
        goto cleanup;

691 692 693 694
    ret = virGetSecret(conn,
                       secret->def->uuid,
                       secret->def->usage_type,
                       secretUsageIDForDef(secret->def));
695

696
 cleanup:
697
    secretDriverUnlock();
698 699 700 701 702
    return ret;
}


static virSecretPtr
703 704
secretDefineXML(virConnectPtr conn,
                const char *xml,
705
                unsigned int flags)
706 707
{
    virSecretPtr ret = NULL;
J
John Ferlan 已提交
708
    virSecretObjPtr secret;
709 710
    virSecretDefPtr backup = NULL;
    virSecretDefPtr new_attrs;
711

712 713
    virCheckFlags(0, NULL);

714
    if (!(new_attrs = virSecretDefParseString(xml)))
715 716
        return NULL;

717
    secretDriverLock();
718

719 720 721
    if (virSecretDefineXMLEnsureACL(conn, new_attrs) < 0)
        goto cleanup;

722 723 724
    if (!(secret = secretFindByUUID(new_attrs->uuid))) {
        /* No existing secret with same UUID,
         * try look for matching usage instead */
725
        const char *usageID = secretUsageIDForDef(new_attrs);
726 727
        char uuidstr[VIR_UUID_STRING_BUFLEN];

728
        if ((secret = secretFindByUsage(new_attrs->usage_type, usageID))) {
729
            virUUIDFormat(secret->def->uuid, uuidstr);
730
            virReportError(VIR_ERR_INTERNAL_ERROR,
731 732
                           _("a secret with UUID %s already defined for "
                             "use with %s"),
733
                           uuidstr, usageID);
734 735
            goto cleanup;
        }
736

737
        /* No existing secret at all, create one */
738
        if (VIR_ALLOC(secret) < 0)
739
            goto cleanup;
740

741 742 743 744 745 746 747 748 749 750
        virUUIDFormat(secret->def->uuid, uuidstr);

        /* Generate configFile using driver->configDir,
         * the uuidstr, and .xml suffix */
        if (!(secret->configFile = virFileBuildPath(driver->configDir,
                                                    uuidstr, ".xml"))) {
            secretFree(secret);
            goto cleanup;
        }

751 752 753 754 755 756 757 758
        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);
759
            virReportError(VIR_ERR_INTERNAL_ERROR,
760 761
                           _("a secret with UUID %s is already defined "
                             "for use with %s"),
762
                           uuidstr, oldUsageID);
763 764 765 766
            goto cleanup;
        }

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

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

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

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

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

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

821
 cleanup:
822
    virSecretDefFree(new_attrs);
823
    secretDriverUnlock();
824 825 826 827 828

    return ret;
}

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

835 836
    virCheckFlags(0, NULL);

837
    secretDriverLock();
838

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

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

850
    ret = virSecretDefFormat(secret->def);
851

852
 cleanup:
853
    secretDriverUnlock();
854 855 856 857 858

    return ret;
}

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

869 870
    virCheckFlags(0, -1);

871
    if (VIR_ALLOC_N(new_value, value_size) < 0)
872 873
        return -1;

874
    secretDriverLock();
875

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

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

887 888 889 890 891 892 893
    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) {
894
        if (secretSaveValue(secret) < 0)
895 896
            goto restore_backup;
    }
897
    /* Saved successfully - drop old value */
898 899 900 901 902 903 904 905 906
    if (old_value != NULL) {
        memset(old_value, 0, old_value_size);
        VIR_FREE(old_value);
    }
    new_value = NULL;

    ret = 0;
    goto cleanup;

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

913
 cleanup:
914
    secretDriverUnlock();
915 916 917 918 919 920 921

    VIR_FREE(new_value);

    return ret;
}

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

930 931
    virCheckFlags(0, NULL);

932
    secretDriverLock();
933

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

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

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

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

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

965
 cleanup:
966
    secretDriverUnlock();
967 968 969 970 971 972 973 974

    return ret;
}

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

977
    secretDriverLock();
978

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

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

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

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

    ret = 0;

1007
 cleanup:
1008
    secretDriverUnlock();
1009 1010 1011 1012 1013

    return ret;
}

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

1019
    secretDriverLock();
1020

1021
    while (driver->secrets != NULL) {
1022
        virSecretObjPtr secret;
1023

1024 1025
        secret = listUnlink(&driver->secrets);
        secretFree(secret);
1026
    }
1027
    VIR_FREE(driver->configDir);
1028

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

    return 0;
}

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

1043
    if (VIR_ALLOC(driver) < 0)
1044 1045
        return -1;

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

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

1063
    if (loadSecrets(&driver->secrets) < 0)
1064 1065
        goto error;

1066
    secretDriverUnlock();
1067 1068 1069 1070
    return 0;

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

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

1081
    if (!driver)
1082 1083
        return -1;

1084
    secretDriverLock();
1085

1086
    if (loadSecrets(&new_secrets) < 0)
1087 1088
        goto end;

1089 1090
    /* Keep ephemeral secrets from current state.
     * Discard non-ephemeral secrets that were removed
1091
     * by the secrets configDir.  */
1092
    while (driver->secrets != NULL) {
1093
        virSecretObjPtr secret;
1094

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

 end:
1104
    secretDriverUnlock();
1105 1106 1107 1108 1109
    return 0;
}

static virSecretDriver secretDriver = {
    .name = "secret",
1110 1111 1112
    .connectNumOfSecrets = secretConnectNumOfSecrets, /* 0.7.1 */
    .connectListSecrets = secretConnectListSecrets, /* 0.7.1 */
    .connectListAllSecrets = secretConnectListAllSecrets, /* 0.10.2 */
1113 1114 1115 1116 1117 1118 1119
    .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 */
1120 1121 1122
};

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

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