secret_driver.c 27.6 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
    char *configDir;
70 71
};

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
{
121
    virSecretObjPtr *pptr, secret;
122

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

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

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

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

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

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

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

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

167
/* Permament secret storage */
168

169
/* Secrets are stored in virSecretDriverStatePtr->configDir.  Each secret
170 171 172 173 174
   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
    ignore_value(virAsprintf(&ret, "%s/%s%s", driver->configDir,
196
                             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->configDir, S_IRWXU) < 0 && errno != EEXIST) {
216
        virReportSystemError(errno, _("cannot create '%s'"),
217
                             driver->configDir);
218 219 220 221 222 223
        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
                       const char *file)
313
{
314
    char uuidstr[VIR_UUID_STRING_BUFLEN];
315

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

318
    if (!virFileMatchesNameSuffix(file, uuidstr, ".xml")) {
319 320
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("<uuid> does not match secret file name '%s'"),
321
                       file);
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 399
secretLoad(const char *file,
           const char *path)
400
{
401
    virSecretDefPtr def = NULL;
J
John Ferlan 已提交
402
    virSecretObjPtr secret = NULL, ret = NULL;
403

404
    if (!(def = virSecretDefParseFile(path)))
405
        goto cleanup;
406

407
    if (secretLoadValidateUUID(def, file) < 0)
408 409
        goto cleanup;

410
    if (VIR_ALLOC(secret) < 0)
411 412 413 414
        goto cleanup;
    secret->def = def;
    def = NULL;

415
    if (secretLoadValue(secret) < 0)
416 417 418 419 420
        goto cleanup;

    ret = secret;
    secret = NULL;

421
 cleanup:
422 423 424 425 426 427
    secretFree(secret);
    virSecretDefFree(def);
    return ret;
}

static int
J
John Ferlan 已提交
428
loadSecrets(virSecretObjPtr *dest)
429 430 431
{
    DIR *dir = NULL;
    struct dirent *de;
J
John Ferlan 已提交
432
    virSecretObjPtr list = NULL;
433

434
    if (!(dir = opendir(driver->configDir))) {
435 436
        if (errno == ENOENT)
            return 0;
437
        virReportSystemError(errno, _("cannot open '%s'"),
438
                             driver->configDir);
439
        return -1;
440
    }
441

E
Eric Blake 已提交
442
    while (virDirRead(dir, &de, NULL) > 0) {
443
        char *path;
J
John Ferlan 已提交
444
        virSecretObjPtr secret;
445 446 447

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

449 450 451
        if (!virFileHasSuffix(de->d_name, ".xml"))
            continue;

452 453 454 455
        if (!(path = virFileBuildPath(driver->configDir, de->d_name, NULL)))
            continue;

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

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

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

    while (list != NULL) {
472
        virSecretObjPtr secret;
473

474 475
        secret = listUnlink(&list);
        listInsert(dest, secret);
476 477
    }

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

482
/* Driver functions */
483 484

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

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

493
    secretDriverLock();
494 495

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

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

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

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

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

519
    secretDriverLock();
520 521 522

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

536
    secretDriverUnlock();
537 538
    return i;

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

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

    return -1;
}

548 549 550 551 552 553 554 555 556 557
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 已提交
558 559 560
    case VIR_SECRET_USAGE_TYPE_CEPH:
        return def->usage.ceph;

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

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

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

    virCheckFlags(VIR_CONNECT_LIST_SECRETS_FILTERS_ALL, -1);

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

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

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

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

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

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

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

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

    return ret;
}
#undef MATCH


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

656
    secretDriverLock();
657

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

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

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

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


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

688
    secretDriverLock();
689

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

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

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

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


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

720 721
    virCheckFlags(0, NULL);

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

725
    secretDriverLock();
726

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

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

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

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

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

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

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

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

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

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

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

    return ret;
}

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

832 833
    virCheckFlags(0, NULL);

834
    secretDriverLock();
835

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

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

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

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

    return ret;
}

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

866 867
    virCheckFlags(0, -1);

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

871
    secretDriverLock();
872

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

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

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

    ret = 0;
    goto cleanup;

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

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

    VIR_FREE(new_value);

    return ret;
}

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

927 928
    virCheckFlags(0, NULL);

929
    secretDriverLock();
930

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

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

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

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

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

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

    return ret;
}

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

974
    secretDriverLock();
975

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

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

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

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

    ret = 0;

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

    return ret;
}

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

1016
    secretDriverLock();
1017

1018
    while (driver->secrets != NULL) {
1019
        virSecretObjPtr secret;
1020

1021 1022
        secret = listUnlink(&driver->secrets);
        secretFree(secret);
1023
    }
1024
    VIR_FREE(driver->configDir);
1025

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

    return 0;
}

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

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

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

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

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

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

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

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

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

1081
    secretDriverLock();
1082

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

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

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

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

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

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

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