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
#include "secret_conf.h"
38
#include "virsecretobj.h"
39
#include "secret_driver.h"
40
#include "virthread.h"
41
#include "viruuid.h"
42
#include "virerror.h"
E
Eric Blake 已提交
43
#include "virfile.h"
44
#include "configmake.h"
45
#include "virstring.h"
46
#include "viraccessapicheck.h"
47 48 49

#define VIR_FROM_THIS VIR_FROM_SECRET

50 51
VIR_LOG_INIT("secret.secret_driver");

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

54
/* Internal driver state */
55 56 57 58 59

typedef struct _virSecretDriverState virSecretDriverState;
typedef virSecretDriverState *virSecretDriverStatePtr;
struct _virSecretDriverState {
    virMutex lock;
J
John Ferlan 已提交
60
    virSecretObj *secrets;
61
    char *configDir;
62 63
};

64
static virSecretDriverStatePtr driver;
65 66

static void
67
secretDriverLock(void)
68 69 70 71 72
{
    virMutexLock(&driver->lock);
}

static void
73
secretDriverUnlock(void)
74 75 76 77
{
    virMutexUnlock(&driver->lock);
}

J
John Ferlan 已提交
78 79
static virSecretObjPtr
listUnlink(virSecretObjPtr *pptr)
80
{
J
John Ferlan 已提交
81
    virSecretObjPtr secret;
82 83 84 85 86 87 88

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

static void
J
John Ferlan 已提交
89 90
listInsert(virSecretObjPtr *pptr,
           virSecretObjPtr secret)
91 92 93 94 95 96
{
    secret->next = *pptr;
    *pptr = secret;
}

static void
J
John Ferlan 已提交
97
secretFree(virSecretObjPtr secret)
98 99 100 101 102 103 104 105 106
{
    if (secret == NULL)
        return;

    virSecretDefFree(secret->def);
    if (secret->value != NULL) {
        memset(secret->value, 0, secret->value_size);
        VIR_FREE(secret->value);
    }
107
    VIR_FREE(secret->configFile);
108
    VIR_FREE(secret->base64File);
109 110 111
    VIR_FREE(secret);
}

J
John Ferlan 已提交
112
static virSecretObjPtr
113
secretFindByUUID(const unsigned char *uuid)
114
{
115
    virSecretObjPtr *pptr, secret;
116

117 118 119 120
    for (pptr = &driver->secrets; *pptr != NULL; pptr = &secret->next) {
        secret = *pptr;
        if (memcmp(secret->def->uuid, uuid, VIR_UUID_BUFLEN) == 0)
            return secret;
121 122 123 124
    }
    return NULL;
}

J
John Ferlan 已提交
125
static virSecretObjPtr
126 127
secretFindByUsage(int usageType,
                  const char *usageID)
128
{
129
    virSecretObjPtr *pptr, secret;
130

131 132
    for (pptr = &driver->secrets; *pptr != NULL; pptr = &secret->next) {
        secret = *pptr;
133

134
        if (secret->def->usage_type != usageType)
135
            continue;
136

137 138 139 140
        switch (usageType) {
        case VIR_SECRET_USAGE_TYPE_NONE:
            /* never match this */
            break;
141

142
        case VIR_SECRET_USAGE_TYPE_VOLUME:
143 144
            if (STREQ(secret->def->usage.volume, usageID))
                return secret;
145
            break;
S
Sage Weil 已提交
146 147

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

        case VIR_SECRET_USAGE_TYPE_ISCSI:
153 154
            if (STREQ(secret->def->usage.target, usageID))
                return secret;
155
            break;
156
        }
157
    }
158
    return NULL;
159 160
}

J
John Ferlan 已提交
161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176

static virSecretObjPtr
secretAssignDef(virSecretObjPtr *list,
                virSecretDefPtr def)
{
    virSecretObjPtr secret;

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

    listInsert(list, secret);
    secret->def = def;

    return secret;
}

J
John Ferlan 已提交
177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193

static virSecretObjPtr
secretObjFromSecret(virSecretPtr secret)
{
    virSecretObjPtr obj;
    char uuidstr[VIR_UUID_STRING_BUFLEN];

    if (!(obj = secretFindByUUID(secret->uuid))) {
        virUUIDFormat(secret->uuid, uuidstr);
        virReportError(VIR_ERR_NO_SECRET,
                       _("no secret with matching uuid '%s'"), uuidstr);
        return NULL;
    }
    return obj;
}


194
/* Permament secret storage */
195

196
/* Secrets are stored in virSecretDriverStatePtr->configDir.  Each secret
197 198 199 200 201
   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
202 203
secretRewriteFile(int fd,
                  void *opaque)
204
{
205
    char *data = opaque;
206

207 208
    if (safewrite(fd, data, strlen(data)) < 0)
        return -1;
209

210
    return 0;
211 212 213 214
}


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

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

231
    if (secretEnsureDirectory() < 0)
232 233
        goto cleanup;

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

237
    if (virFileRewrite(secret->configFile, S_IRUSR | S_IWUSR,
238
                       secretRewriteFile, xml) < 0)
239 240 241 242
        goto cleanup;

    ret = 0;

243
 cleanup:
244 245 246 247 248
    VIR_FREE(xml);
    return ret;
}

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

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

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

    base64_encode_alloc((const char *)secret->value, secret->value_size,
                        &base64);
    if (base64 == NULL) {
263
        virReportOOMError();
264 265 266
        goto cleanup;
    }

267
    if (virFileRewrite(secret->base64File, S_IRUSR | S_IWUSR,
268
                       secretRewriteFile, base64) < 0)
269 270 271 272
        goto cleanup;

    ret = 0;

273
 cleanup:
274 275 276 277 278
    VIR_FREE(base64);
    return ret;
}

static int
J
John Ferlan 已提交
279
secretDeleteSaved(const virSecretObj *secret)
280
{
281
    if (unlink(secret->configFile) < 0 && errno != ENOENT)
282 283
        return -1;

284 285
    /* When the XML is missing, the rest may waste disk space, but the secret
       won't be loaded again, so we have succeeded already. */
286
    (void)unlink(secret->base64File);
287

288
    return 0;
289 290 291
}

static int
292
secretLoadValidateUUID(virSecretDefPtr def,
293
                       const char *file)
294
{
295
    char uuidstr[VIR_UUID_STRING_BUFLEN];
296

297
    virUUIDFormat(def->uuid, uuidstr);
298

299
    if (!virFileMatchesNameSuffix(file, uuidstr, ".xml")) {
300 301
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("<uuid> does not match secret file name '%s'"),
302
                       file);
303 304 305 306 307 308 309
        return -1;
    }

    return 0;
}

static int
J
John Ferlan 已提交
310
secretLoadValue(virSecretObjPtr secret)
311 312 313
{
    int ret = -1, fd = -1;
    struct stat st;
314
    char *contents = NULL, *value = NULL;
315 316
    size_t value_size;

317
    if ((fd = open(secret->base64File, O_RDONLY)) == -1) {
318 319 320 321
        if (errno == ENOENT) {
            ret = 0;
            goto cleanup;
        }
322 323
        virReportSystemError(errno, _("cannot open '%s'"),
                             secret->base64File);
324 325
        goto cleanup;
    }
326

327
    if (fstat(fd, &st) < 0) {
328 329
        virReportSystemError(errno, _("cannot stat '%s'"),
                             secret->base64File);
330 331
        goto cleanup;
    }
332

333
    if ((size_t)st.st_size != st.st_size) {
334
        virReportError(VIR_ERR_INTERNAL_ERROR,
335 336
                       _("'%s' file does not fit in memory"),
                       secret->base64File);
337 338 339
        goto cleanup;
    }

340
    if (VIR_ALLOC_N(contents, st.st_size) < 0)
341
        goto cleanup;
342

343
    if (saferead(fd, contents, st.st_size) != st.st_size) {
344 345
        virReportSystemError(errno, _("cannot read '%s'"),
                             secret->base64File);
346 347
        goto cleanup;
    }
348

349
    VIR_FORCE_CLOSE(fd);
350 351

    if (!base64_decode_alloc(contents, st.st_size, &value, &value_size)) {
352
        virReportError(VIR_ERR_INTERNAL_ERROR,
353 354
                       _("invalid base64 in '%s'"),
                       secret->base64File);
355 356
        goto cleanup;
    }
357
    if (value == NULL)
358 359 360 361 362 363 364 365
        goto cleanup;

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

    ret = 0;

366
 cleanup:
367 368 369 370 371 372 373 374
    if (value != NULL) {
        memset(value, 0, value_size);
        VIR_FREE(value);
    }
    if (contents != NULL) {
        memset(contents, 0, st.st_size);
        VIR_FREE(contents);
    }
375
    VIR_FORCE_CLOSE(fd);
376 377 378
    return ret;
}

J
John Ferlan 已提交
379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398

static void
listUnlinkSecret(virSecretObjPtr *pptr,
                 virSecretObjPtr secret)
{
    if (!secret)
        return;

    if (*pptr == secret) {
        *pptr = secret->next;
    } else {
        virSecretObjPtr tmp = *pptr;
        while (tmp && tmp->next != secret)
            tmp = tmp->next;
        if (tmp)
            tmp->next = secret->next;
    }
}


J
John Ferlan 已提交
399
static virSecretObjPtr
J
John Ferlan 已提交
400 401
secretLoad(virSecretObjPtr *list,
           const char *file,
402 403
           const char *path,
           const char *base64path)
404
{
405
    virSecretDefPtr def = NULL;
J
John Ferlan 已提交
406
    virSecretObjPtr secret = NULL, ret = NULL;
407

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

411
    if (secretLoadValidateUUID(def, file) < 0)
412 413
        goto cleanup;

J
John Ferlan 已提交
414
    if (!(secret = secretAssignDef(list, def)))
415 416 417
        goto cleanup;
    def = NULL;

418 419 420
    if (VIR_STRDUP(secret->configFile, path) < 0)
        goto cleanup;

421 422 423
    if (VIR_STRDUP(secret->base64File, base64path) < 0)
        goto cleanup;

424
    if (secretLoadValue(secret) < 0)
425 426 427 428 429
        goto cleanup;

    ret = secret;
    secret = NULL;

430
 cleanup:
J
John Ferlan 已提交
431
    listUnlinkSecret(list, secret);
432 433 434 435 436 437
    secretFree(secret);
    virSecretDefFree(def);
    return ret;
}

static int
J
John Ferlan 已提交
438 439
secretLoadAllConfigs(virSecretObjPtr *dest,
                     const char *configDir)
440 441 442
{
    DIR *dir = NULL;
    struct dirent *de;
J
John Ferlan 已提交
443
    virSecretObjPtr list = NULL;
444

J
John Ferlan 已提交
445
    if (!(dir = opendir(configDir))) {
446 447
        if (errno == ENOENT)
            return 0;
J
John Ferlan 已提交
448
        virReportSystemError(errno, _("cannot open '%s'"), configDir);
449
        return -1;
450
    }
451

E
Eric Blake 已提交
452
    while (virDirRead(dir, &de, NULL) > 0) {
453
        char *path, *base64name, *base64path;
J
John Ferlan 已提交
454
        virSecretObjPtr secret;
455 456 457

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

459 460 461
        if (!virFileHasSuffix(de->d_name, ".xml"))
            continue;

J
John Ferlan 已提交
462
        if (!(path = virFileBuildPath(configDir, de->d_name, NULL)))
463 464
            continue;

465 466 467
        /* Copy the .xml file name, but use suffix ".base64" instead */
        if (VIR_STRDUP(base64name, de->d_name) < 0 ||
            !virFileStripSuffix(base64name, ".xml") ||
J
John Ferlan 已提交
468
            !(base64path = virFileBuildPath(configDir,
469 470 471 472 473 474 475
                                            base64name, ".base64"))) {
            VIR_FREE(path);
            VIR_FREE(base64name);
            continue;
        }
        VIR_FREE(base64name);

J
John Ferlan 已提交
476
        if (!(secret = secretLoad(&list, de->d_name, path, base64path))) {
477 478
            virErrorPtr err = virGetLastError();

479
            VIR_ERROR(_("Error reading secret: %s"),
480
                      err != NULL ? err->message: _("unknown error"));
481
            virResetError(err);
482
            VIR_FREE(path);
483
            VIR_FREE(base64path);
484 485
            continue;
        }
486

487
        VIR_FREE(path);
488
        VIR_FREE(base64path);
489
    }
E
Eric Blake 已提交
490
    /* Ignore error reported by readdir, if any.  It's better to keep the
491 492 493
       secrets we managed to find. */

    while (list != NULL) {
494
        virSecretObjPtr secret;
495

496 497
        secret = listUnlink(&list);
        listInsert(dest, secret);
498 499
    }

500 501
    closedir(dir);
    return 0;
502 503
}

504
/* Driver functions */
505 506

static int
507
secretConnectNumOfSecrets(virConnectPtr conn)
508
{
509
    size_t i;
J
John Ferlan 已提交
510
    virSecretObjPtr secret;
511

512 513 514
    if (virConnectNumOfSecretsEnsureACL(conn) < 0)
        return -1;

515
    secretDriverLock();
516 517

    i = 0;
518 519 520 521 522
    for (secret = driver->secrets; secret != NULL; secret = secret->next) {
        if (virConnectNumOfSecretsCheckACL(conn,
                                           secret->def))
            i++;
    }
523

524
    secretDriverUnlock();
525 526 527 528
    return i;
}

static int
529 530 531
secretConnectListSecrets(virConnectPtr conn,
                         char **uuids,
                         int maxuuids)
532
{
533
    size_t i;
J
John Ferlan 已提交
534
    virSecretObjPtr secret;
535 536 537

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

538 539 540
    if (virConnectListSecretsEnsureACL(conn) < 0)
        return -1;

541
    secretDriverLock();
542 543 544

    i = 0;
    for (secret = driver->secrets; secret != NULL; secret = secret->next) {
545
        char *uuidstr;
546 547 548
        if (!virConnectListSecretsCheckACL(conn,
                                           secret->def))
            continue;
549 550
        if (i == maxuuids)
            break;
551
        if (VIR_ALLOC_N(uuidstr, VIR_UUID_STRING_BUFLEN) < 0)
552
            goto cleanup;
553 554
        virUUIDFormat(secret->def->uuid, uuidstr);
        uuids[i] = uuidstr;
555 556 557
        i++;
    }

558
    secretDriverUnlock();
559 560
    return i;

561
 cleanup:
562
    secretDriverUnlock();
563 564 565 566 567 568 569

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

    return -1;
}

570 571 572 573 574 575 576 577 578 579
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 已提交
580 581 582
    case VIR_SECRET_USAGE_TYPE_CEPH:
        return def->usage.ceph;

583 584 585
    case VIR_SECRET_USAGE_TYPE_ISCSI:
        return def->usage.target;

586 587 588 589 590
    default:
        return NULL;
    }
}

O
Osier Yang 已提交
591 592
#define MATCH(FLAG) (flags & (FLAG))
static int
593 594
secretConnectListAllSecrets(virConnectPtr conn,
                            virSecretPtr **secrets,
595 596
                            unsigned int flags)
{
O
Osier Yang 已提交
597 598 599
    virSecretPtr *tmp_secrets = NULL;
    int nsecrets = 0;
    int ret_nsecrets = 0;
600
    virSecretObjPtr secret = NULL;
601
    size_t i = 0;
O
Osier Yang 已提交
602 603 604 605
    int ret = -1;

    virCheckFlags(VIR_CONNECT_LIST_SECRETS_FILTERS_ALL, -1);

606 607 608
    if (virConnectListAllSecretsEnsureACL(conn) < 0)
        return -1;

609
    secretDriverLock();
O
Osier Yang 已提交
610

611
    for (secret = driver->secrets; secret != NULL; secret = secret->next)
O
Osier Yang 已提交
612 613
        nsecrets++;

614 615
    if (secrets && VIR_ALLOC_N(tmp_secrets, nsecrets + 1) < 0)
        goto cleanup;
O
Osier Yang 已提交
616

617
    for (secret = driver->secrets; secret != NULL; secret = secret->next) {
618
        if (!virConnectListAllSecretsCheckACL(conn,
619
                                              secret->def))
620 621
            continue;

O
Osier Yang 已提交
622 623 624
        /* filter by whether it's ephemeral */
        if (MATCH(VIR_CONNECT_LIST_SECRETS_FILTERS_EPHEMERAL) &&
            !((MATCH(VIR_CONNECT_LIST_SECRETS_EPHEMERAL) &&
625
               secret->def->ephemeral) ||
O
Osier Yang 已提交
626
              (MATCH(VIR_CONNECT_LIST_SECRETS_NO_EPHEMERAL) &&
627
               !secret->def->ephemeral)))
O
Osier Yang 已提交
628 629 630 631 632
            continue;

        /* filter by whether it's private */
        if (MATCH(VIR_CONNECT_LIST_SECRETS_FILTERS_PRIVATE) &&
            !((MATCH(VIR_CONNECT_LIST_SECRETS_PRIVATE) &&
633
               secret->def->private) ||
O
Osier Yang 已提交
634
              (MATCH(VIR_CONNECT_LIST_SECRETS_NO_PRIVATE) &&
635
               !secret->def->private)))
O
Osier Yang 已提交
636 637 638
            continue;

        if (secrets) {
639 640
            if (!(tmp_secrets[ret_nsecrets] =
                  virGetSecret(conn,
641 642 643
                               secret->def->uuid,
                               secret->def->usage_type,
                               secretUsageIDForDef(secret->def))))
O
Osier Yang 已提交
644 645 646 647 648 649 650 651 652 653 654 655 656 657 658
                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:
659
    secretDriverUnlock();
O
Osier Yang 已提交
660
    if (tmp_secrets) {
661 662
        for (i = 0; i < ret_nsecrets; i ++)
            virObjectUnref(tmp_secrets[i]);
O
Osier Yang 已提交
663 664 665 666 667 668 669 670
    }
    VIR_FREE(tmp_secrets);

    return ret;
}
#undef MATCH


671
static virSecretPtr
672 673
secretLookupByUUID(virConnectPtr conn,
                   const unsigned char *uuid)
674 675
{
    virSecretPtr ret = NULL;
J
John Ferlan 已提交
676
    virSecretObjPtr secret;
677

678
    secretDriverLock();
679

680
    if (!(secret = secretFindByUUID(uuid))) {
681 682
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(uuid, uuidstr);
683 684
        virReportError(VIR_ERR_NO_SECRET,
                       _("no secret with matching uuid '%s'"), uuidstr);
685 686 687
        goto cleanup;
    }

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

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

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


static virSecretPtr
703 704 705
secretLookupByUsage(virConnectPtr conn,
                    int usageType,
                    const char *usageID)
706 707
{
    virSecretPtr ret = NULL;
J
John Ferlan 已提交
708
    virSecretObjPtr secret;
709

710
    secretDriverLock();
711

712
    if (!(secret = secretFindByUsage(usageType, usageID))) {
713 714
        virReportError(VIR_ERR_NO_SECRET,
                       _("no secret with matching usage '%s'"), usageID);
715 716 717
        goto cleanup;
    }

718 719 720
    if (virSecretLookupByUsageEnsureACL(conn, secret->def) < 0)
        goto cleanup;

721 722 723 724
    ret = virGetSecret(conn,
                       secret->def->uuid,
                       secret->def->usage_type,
                       secretUsageIDForDef(secret->def));
725

726
 cleanup:
727
    secretDriverUnlock();
728 729 730 731 732
    return ret;
}


static virSecretPtr
733 734
secretDefineXML(virConnectPtr conn,
                const char *xml,
735
                unsigned int flags)
736 737
{
    virSecretPtr ret = NULL;
J
John Ferlan 已提交
738
    virSecretObjPtr secret = NULL;
739 740
    virSecretDefPtr backup = NULL;
    virSecretDefPtr new_attrs;
741

742 743
    virCheckFlags(0, NULL);

744
    if (!(new_attrs = virSecretDefParseString(xml)))
745 746
        return NULL;

747
    secretDriverLock();
748

749 750 751
    if (virSecretDefineXMLEnsureACL(conn, new_attrs) < 0)
        goto cleanup;

752 753 754
    if (!(secret = secretFindByUUID(new_attrs->uuid))) {
        /* No existing secret with same UUID,
         * try look for matching usage instead */
755
        const char *usageID = secretUsageIDForDef(new_attrs);
756 757
        char uuidstr[VIR_UUID_STRING_BUFLEN];

758
        if ((secret = secretFindByUsage(new_attrs->usage_type, usageID))) {
759
            virUUIDFormat(secret->def->uuid, uuidstr);
760
            virReportError(VIR_ERR_INTERNAL_ERROR,
761 762
                           _("a secret with UUID %s already defined for "
                             "use with %s"),
763
                           uuidstr, usageID);
764 765
            goto cleanup;
        }
766

767
        /* No existing secret at all, create one */
J
John Ferlan 已提交
768
        if (!(secret = secretAssignDef(&driver->secrets, new_attrs)))
769
            goto cleanup;
770

771 772 773 774 775 776 777 778 779
        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;
        }
780 781 782 783 784 785 786
        /* Generate base64File using driver->configDir,
         * the uuidstr, and .base64 suffix */
        if (!(secret->base64File = virFileBuildPath(driver->configDir,
                                                    uuidstr, ".base64"))) {
            secretFree(secret);
            goto cleanup;
        }
787 788 789 790 791 792
    } 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);
793
            virReportError(VIR_ERR_INTERNAL_ERROR,
794 795
                           _("a secret with UUID %s is already defined "
                             "for use with %s"),
796
                           uuidstr, oldUsageID);
797 798 799 800
            goto cleanup;
        }

        if (secret->def->private && !new_attrs->private) {
801 802
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("cannot change private flag on existing secret"));
803 804 805 806 807 808
            goto cleanup;
        }

        /* Got an existing secret matches attrs, so reuse that */
        backup = secret->def;
        secret->def = new_attrs;
809 810 811
    }

    if (!new_attrs->ephemeral) {
812
        if (backup && backup->ephemeral) {
813
            if (secretSaveValue(secret) < 0)
814 815
                goto restore_backup;
        }
816
        if (secretSaveDef(secret) < 0) {
817
            if (backup && backup->ephemeral) {
818
                /* Undo the secretSaveValue() above; ignore errors */
819
                (void)unlink(secret->base64File);
820 821 822
            }
            goto restore_backup;
        }
823
    } else if (backup && !backup->ephemeral) {
824
        if (secretDeleteSaved(secret) < 0)
825 826
            goto restore_backup;
    }
827
    /* Saved successfully - drop old values */
828 829 830
    new_attrs = NULL;
    virSecretDefFree(backup);

831 832 833 834
    ret = virGetSecret(conn,
                       secret->def->uuid,
                       secret->def->usage_type,
                       secretUsageIDForDef(secret->def));
835 836
    goto cleanup;

837
 restore_backup:
838 839 840 841
    if (backup) {
        /* Error - restore previous state and free new attributes */
        secret->def = backup;
    } else {
842
        /* "secret" was added to the head of the list above */
843
        if (listUnlink(&driver->secrets) != secret)
844 845
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("list of secrets is inconsistent"));
846 847 848 849
        else
            secretFree(secret);
    }

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

    return ret;
}

static char *
858 859
secretGetXMLDesc(virSecretPtr obj,
                 unsigned int flags)
860 861
{
    char *ret = NULL;
J
John Ferlan 已提交
862
    virSecretObjPtr secret;
863

864 865
    virCheckFlags(0, NULL);

866
    secretDriverLock();
867

J
John Ferlan 已提交
868
    if (!(secret = secretObjFromSecret(obj)))
869 870
        goto cleanup;

871 872 873
    if (virSecretGetXMLDescEnsureACL(obj->conn, secret->def) < 0)
        goto cleanup;

874
    ret = virSecretDefFormat(secret->def);
875

876
 cleanup:
877
    secretDriverUnlock();
878 879 880 881 882

    return ret;
}

static int
883 884 885 886
secretSetValue(virSecretPtr obj,
               const unsigned char *value,
               size_t value_size,
               unsigned int flags)
887 888 889 890
{
    int ret = -1;
    unsigned char *old_value, *new_value;
    size_t old_value_size;
J
John Ferlan 已提交
891
    virSecretObjPtr secret;
892

893 894
    virCheckFlags(0, -1);

895
    if (VIR_ALLOC_N(new_value, value_size) < 0)
896 897
        return -1;

898
    secretDriverLock();
899

J
John Ferlan 已提交
900
    if (!(secret = secretObjFromSecret(obj)))
901 902
        goto cleanup;

903 904 905
    if (virSecretSetValueEnsureACL(obj->conn, secret->def) < 0)
        goto cleanup;

906 907 908 909 910 911 912
    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) {
913
        if (secretSaveValue(secret) < 0)
914 915
            goto restore_backup;
    }
916
    /* Saved successfully - drop old value */
917 918 919 920 921 922 923 924 925
    if (old_value != NULL) {
        memset(old_value, 0, old_value_size);
        VIR_FREE(old_value);
    }
    new_value = NULL;

    ret = 0;
    goto cleanup;

926
 restore_backup:
927 928 929 930 931
    /* Error - restore previous state and free new value */
    secret->value = old_value;
    secret->value_size = old_value_size;
    memset(new_value, 0, value_size);

932
 cleanup:
933
    secretDriverUnlock();
934 935 936 937 938 939 940

    VIR_FREE(new_value);

    return ret;
}

static unsigned char *
941 942 943
secretGetValue(virSecretPtr obj,
               size_t *value_size,
               unsigned int flags,
944
               unsigned int internalFlags)
945 946
{
    unsigned char *ret = NULL;
J
John Ferlan 已提交
947
    virSecretObjPtr secret;
948

949 950
    virCheckFlags(0, NULL);

951
    secretDriverLock();
952

J
John Ferlan 已提交
953
    if (!(secret = secretObjFromSecret(obj)))
954
        goto cleanup;
955

956 957 958
    if (virSecretGetValueEnsureACL(obj->conn, secret->def) < 0)
        goto cleanup;

959
    if (secret->value == NULL) {
960 961
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(obj->uuid, uuidstr);
962 963
        virReportError(VIR_ERR_NO_SECRET,
                       _("secret '%s' does not have a value"), uuidstr);
964 965 966
        goto cleanup;
    }

967
    if ((internalFlags & VIR_SECRET_GET_VALUE_INTERNAL_CALL) == 0 &&
968
        secret->def->private) {
969
        virReportError(VIR_ERR_INVALID_SECRET, "%s",
970
                       _("secret is private"));
971 972 973
        goto cleanup;
    }

974
    if (VIR_ALLOC_N(ret, secret->value_size) < 0)
975 976 977 978
        goto cleanup;
    memcpy(ret, secret->value, secret->value_size);
    *value_size = secret->value_size;

979
 cleanup:
980
    secretDriverUnlock();
981 982 983 984 985 986 987 988

    return ret;
}

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

991
    secretDriverLock();
992

J
John Ferlan 已提交
993
    if (!(secret = secretObjFromSecret(obj)))
994 995
        goto cleanup;

996 997 998
    if (virSecretUndefineEnsureACL(obj->conn, secret->def) < 0)
        goto cleanup;

999
    if (!secret->def->ephemeral &&
1000
        secretDeleteSaved(secret) < 0)
1001 1002
        goto cleanup;

J
John Ferlan 已提交
1003
    listUnlinkSecret(&driver->secrets, secret);
1004 1005 1006 1007
    secretFree(secret);

    ret = 0;

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

    return ret;
}

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

1020
    secretDriverLock();
1021

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

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

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

    return 0;
}

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

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

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

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

J
John Ferlan 已提交
1064
    if (secretLoadAllConfigs(&driver->secrets, driver->configDir) < 0)
1065 1066
        goto error;

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

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

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

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

1085
    secretDriverLock();
1086

J
John Ferlan 已提交
1087
    if (secretLoadAllConfigs(&new_secrets, driver->configDir) < 0)
1088 1089
        goto end;

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

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

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

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

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

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