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

74
static virSecretDriverStatePtr driver;
75 76

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

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

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

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

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

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

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

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

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

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

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

144
        if (secret->def->usage_type != usageType)
145
            continue;
146

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

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

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

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

J
John Ferlan 已提交
171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186

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

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

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

    return secret;
}

187
/* Permament secret storage */
188

189
/* Secrets are stored in virSecretDriverStatePtr->configDir.  Each secret
190 191 192 193 194
   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
195 196
secretRewriteFile(int fd,
                  void *opaque)
197
{
198
    char *data = opaque;
199

200 201
    if (safewrite(fd, data, strlen(data)) < 0)
        return -1;
202

203
    return 0;
204 205 206 207
}


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

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

224
    if (secretEnsureDirectory() < 0)
225 226
        goto cleanup;

227
    if (!(xml = virSecretDefFormat(secret->def)))
228 229
        goto cleanup;

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

    ret = 0;

236
 cleanup:
237 238 239 240 241
    VIR_FREE(xml);
    return ret;
}

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

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

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

    base64_encode_alloc((const char *)secret->value, secret->value_size,
                        &base64);
    if (base64 == NULL) {
256
        virReportOOMError();
257 258 259
        goto cleanup;
    }

260
    if (virFileRewrite(secret->base64File, S_IRUSR | S_IWUSR,
261
                       secretRewriteFile, base64) < 0)
262 263 264 265
        goto cleanup;

    ret = 0;

266
 cleanup:
267 268 269 270 271
    VIR_FREE(base64);
    return ret;
}

static int
J
John Ferlan 已提交
272
secretDeleteSaved(const virSecretObj *secret)
273
{
274
    if (unlink(secret->configFile) < 0 && errno != ENOENT)
275 276
        return -1;

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

281
    return 0;
282 283 284
}

static int
285
secretLoadValidateUUID(virSecretDefPtr def,
286
                       const char *file)
287
{
288
    char uuidstr[VIR_UUID_STRING_BUFLEN];
289

290
    virUUIDFormat(def->uuid, uuidstr);
291

292
    if (!virFileMatchesNameSuffix(file, uuidstr, ".xml")) {
293 294
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("<uuid> does not match secret file name '%s'"),
295
                       file);
296 297 298 299 300 301 302
        return -1;
    }

    return 0;
}

static int
J
John Ferlan 已提交
303
secretLoadValue(virSecretObjPtr secret)
304 305 306
{
    int ret = -1, fd = -1;
    struct stat st;
307
    char *contents = NULL, *value = NULL;
308 309
    size_t value_size;

310
    if ((fd = open(secret->base64File, O_RDONLY)) == -1) {
311 312 313 314
        if (errno == ENOENT) {
            ret = 0;
            goto cleanup;
        }
315 316
        virReportSystemError(errno, _("cannot open '%s'"),
                             secret->base64File);
317 318
        goto cleanup;
    }
319

320
    if (fstat(fd, &st) < 0) {
321 322
        virReportSystemError(errno, _("cannot stat '%s'"),
                             secret->base64File);
323 324
        goto cleanup;
    }
325

326
    if ((size_t)st.st_size != st.st_size) {
327
        virReportError(VIR_ERR_INTERNAL_ERROR,
328 329
                       _("'%s' file does not fit in memory"),
                       secret->base64File);
330 331 332
        goto cleanup;
    }

333
    if (VIR_ALLOC_N(contents, st.st_size) < 0)
334
        goto cleanup;
335

336
    if (saferead(fd, contents, st.st_size) != st.st_size) {
337 338
        virReportSystemError(errno, _("cannot read '%s'"),
                             secret->base64File);
339 340
        goto cleanup;
    }
341

342
    VIR_FORCE_CLOSE(fd);
343 344

    if (!base64_decode_alloc(contents, st.st_size, &value, &value_size)) {
345
        virReportError(VIR_ERR_INTERNAL_ERROR,
346 347
                       _("invalid base64 in '%s'"),
                       secret->base64File);
348 349
        goto cleanup;
    }
350
    if (value == NULL)
351 352 353 354 355 356 357 358
        goto cleanup;

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

    ret = 0;

359
 cleanup:
360 361 362 363 364 365 366 367
    if (value != NULL) {
        memset(value, 0, value_size);
        VIR_FREE(value);
    }
    if (contents != NULL) {
        memset(contents, 0, st.st_size);
        VIR_FREE(contents);
    }
368
    VIR_FORCE_CLOSE(fd);
369 370 371
    return ret;
}

J
John Ferlan 已提交
372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391

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 已提交
392
static virSecretObjPtr
J
John Ferlan 已提交
393 394
secretLoad(virSecretObjPtr *list,
           const char *file,
395 396
           const char *path,
           const char *base64path)
397
{
398
    virSecretDefPtr def = NULL;
J
John Ferlan 已提交
399
    virSecretObjPtr secret = NULL, ret = NULL;
400

401
    if (!(def = virSecretDefParseFile(path)))
402
        goto cleanup;
403

404
    if (secretLoadValidateUUID(def, file) < 0)
405 406
        goto cleanup;

J
John Ferlan 已提交
407
    if (!(secret = secretAssignDef(list, def)))
408 409 410
        goto cleanup;
    def = NULL;

411 412 413
    if (VIR_STRDUP(secret->configFile, path) < 0)
        goto cleanup;

414 415 416
    if (VIR_STRDUP(secret->base64File, base64path) < 0)
        goto cleanup;

417
    if (secretLoadValue(secret) < 0)
418 419 420 421 422
        goto cleanup;

    ret = secret;
    secret = NULL;

423
 cleanup:
J
John Ferlan 已提交
424
    listUnlinkSecret(list, secret);
425 426 427 428 429 430
    secretFree(secret);
    virSecretDefFree(def);
    return ret;
}

static int
J
John Ferlan 已提交
431 432
secretLoadAllConfigs(virSecretObjPtr *dest,
                     const char *configDir)
433 434 435
{
    DIR *dir = NULL;
    struct dirent *de;
J
John Ferlan 已提交
436
    virSecretObjPtr list = NULL;
437

J
John Ferlan 已提交
438
    if (!(dir = opendir(configDir))) {
439 440
        if (errno == ENOENT)
            return 0;
J
John Ferlan 已提交
441
        virReportSystemError(errno, _("cannot open '%s'"), configDir);
442
        return -1;
443
    }
444

E
Eric Blake 已提交
445
    while (virDirRead(dir, &de, NULL) > 0) {
446
        char *path, *base64name, *base64path;
J
John Ferlan 已提交
447
        virSecretObjPtr secret;
448 449 450

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

452 453 454
        if (!virFileHasSuffix(de->d_name, ".xml"))
            continue;

J
John Ferlan 已提交
455
        if (!(path = virFileBuildPath(configDir, de->d_name, NULL)))
456 457
            continue;

458 459 460
        /* Copy the .xml file name, but use suffix ".base64" instead */
        if (VIR_STRDUP(base64name, de->d_name) < 0 ||
            !virFileStripSuffix(base64name, ".xml") ||
J
John Ferlan 已提交
461
            !(base64path = virFileBuildPath(configDir,
462 463 464 465 466 467 468
                                            base64name, ".base64"))) {
            VIR_FREE(path);
            VIR_FREE(base64name);
            continue;
        }
        VIR_FREE(base64name);

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

472
            VIR_ERROR(_("Error reading secret: %s"),
473
                      err != NULL ? err->message: _("unknown error"));
474
            virResetError(err);
475
            VIR_FREE(path);
476
            VIR_FREE(base64path);
477 478
            continue;
        }
479

480
        VIR_FREE(path);
481
        VIR_FREE(base64path);
482
    }
E
Eric Blake 已提交
483
    /* Ignore error reported by readdir, if any.  It's better to keep the
484 485 486
       secrets we managed to find. */

    while (list != NULL) {
487
        virSecretObjPtr secret;
488

489 490
        secret = listUnlink(&list);
        listInsert(dest, secret);
491 492
    }

493 494
    closedir(dir);
    return 0;
495 496
}

497
/* Driver functions */
498 499

static int
500
secretConnectNumOfSecrets(virConnectPtr conn)
501
{
502
    size_t i;
J
John Ferlan 已提交
503
    virSecretObjPtr secret;
504

505 506 507
    if (virConnectNumOfSecretsEnsureACL(conn) < 0)
        return -1;

508
    secretDriverLock();
509 510

    i = 0;
511 512 513 514 515
    for (secret = driver->secrets; secret != NULL; secret = secret->next) {
        if (virConnectNumOfSecretsCheckACL(conn,
                                           secret->def))
            i++;
    }
516

517
    secretDriverUnlock();
518 519 520 521
    return i;
}

static int
522 523 524
secretConnectListSecrets(virConnectPtr conn,
                         char **uuids,
                         int maxuuids)
525
{
526
    size_t i;
J
John Ferlan 已提交
527
    virSecretObjPtr secret;
528 529 530

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

531 532 533
    if (virConnectListSecretsEnsureACL(conn) < 0)
        return -1;

534
    secretDriverLock();
535 536 537

    i = 0;
    for (secret = driver->secrets; secret != NULL; secret = secret->next) {
538
        char *uuidstr;
539 540 541
        if (!virConnectListSecretsCheckACL(conn,
                                           secret->def))
            continue;
542 543
        if (i == maxuuids)
            break;
544
        if (VIR_ALLOC_N(uuidstr, VIR_UUID_STRING_BUFLEN) < 0)
545
            goto cleanup;
546 547
        virUUIDFormat(secret->def->uuid, uuidstr);
        uuids[i] = uuidstr;
548 549 550
        i++;
    }

551
    secretDriverUnlock();
552 553
    return i;

554
 cleanup:
555
    secretDriverUnlock();
556 557 558 559 560 561 562

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

    return -1;
}

563 564 565 566 567 568 569 570 571 572
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 已提交
573 574 575
    case VIR_SECRET_USAGE_TYPE_CEPH:
        return def->usage.ceph;

576 577 578
    case VIR_SECRET_USAGE_TYPE_ISCSI:
        return def->usage.target;

579 580 581 582 583
    default:
        return NULL;
    }
}

O
Osier Yang 已提交
584 585
#define MATCH(FLAG) (flags & (FLAG))
static int
586 587
secretConnectListAllSecrets(virConnectPtr conn,
                            virSecretPtr **secrets,
588 589
                            unsigned int flags)
{
O
Osier Yang 已提交
590 591 592
    virSecretPtr *tmp_secrets = NULL;
    int nsecrets = 0;
    int ret_nsecrets = 0;
593
    virSecretObjPtr secret = NULL;
594
    size_t i = 0;
O
Osier Yang 已提交
595 596 597 598
    int ret = -1;

    virCheckFlags(VIR_CONNECT_LIST_SECRETS_FILTERS_ALL, -1);

599 600 601
    if (virConnectListAllSecretsEnsureACL(conn) < 0)
        return -1;

602
    secretDriverLock();
O
Osier Yang 已提交
603

604
    for (secret = driver->secrets; secret != NULL; secret = secret->next)
O
Osier Yang 已提交
605 606
        nsecrets++;

607 608
    if (secrets && VIR_ALLOC_N(tmp_secrets, nsecrets + 1) < 0)
        goto cleanup;
O
Osier Yang 已提交
609

610
    for (secret = driver->secrets; secret != NULL; secret = secret->next) {
611
        if (!virConnectListAllSecretsCheckACL(conn,
612
                                              secret->def))
613 614
            continue;

O
Osier Yang 已提交
615 616 617
        /* filter by whether it's ephemeral */
        if (MATCH(VIR_CONNECT_LIST_SECRETS_FILTERS_EPHEMERAL) &&
            !((MATCH(VIR_CONNECT_LIST_SECRETS_EPHEMERAL) &&
618
               secret->def->ephemeral) ||
O
Osier Yang 已提交
619
              (MATCH(VIR_CONNECT_LIST_SECRETS_NO_EPHEMERAL) &&
620
               !secret->def->ephemeral)))
O
Osier Yang 已提交
621 622 623 624 625
            continue;

        /* filter by whether it's private */
        if (MATCH(VIR_CONNECT_LIST_SECRETS_FILTERS_PRIVATE) &&
            !((MATCH(VIR_CONNECT_LIST_SECRETS_PRIVATE) &&
626
               secret->def->private) ||
O
Osier Yang 已提交
627
              (MATCH(VIR_CONNECT_LIST_SECRETS_NO_PRIVATE) &&
628
               !secret->def->private)))
O
Osier Yang 已提交
629 630 631
            continue;

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

    return ret;
}
#undef MATCH


664
static virSecretPtr
665 666
secretLookupByUUID(virConnectPtr conn,
                   const unsigned char *uuid)
667 668
{
    virSecretPtr ret = NULL;
J
John Ferlan 已提交
669
    virSecretObjPtr secret;
670

671
    secretDriverLock();
672

673
    if (!(secret = secretFindByUUID(uuid))) {
674 675
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(uuid, uuidstr);
676 677
        virReportError(VIR_ERR_NO_SECRET,
                       _("no secret with matching uuid '%s'"), uuidstr);
678 679 680
        goto cleanup;
    }

681 682 683
    if (virSecretLookupByUUIDEnsureACL(conn, secret->def) < 0)
        goto cleanup;

684 685 686 687 688
    ret = virGetSecret(conn,
                       secret->def->uuid,
                       secret->def->usage_type,
                       secretUsageIDForDef(secret->def));

689
 cleanup:
690
    secretDriverUnlock();
691 692 693 694 695
    return ret;
}


static virSecretPtr
696 697 698
secretLookupByUsage(virConnectPtr conn,
                    int usageType,
                    const char *usageID)
699 700
{
    virSecretPtr ret = NULL;
J
John Ferlan 已提交
701
    virSecretObjPtr secret;
702

703
    secretDriverLock();
704

705
    if (!(secret = secretFindByUsage(usageType, usageID))) {
706 707
        virReportError(VIR_ERR_NO_SECRET,
                       _("no secret with matching usage '%s'"), usageID);
708 709 710
        goto cleanup;
    }

711 712 713
    if (virSecretLookupByUsageEnsureACL(conn, secret->def) < 0)
        goto cleanup;

714 715 716 717
    ret = virGetSecret(conn,
                       secret->def->uuid,
                       secret->def->usage_type,
                       secretUsageIDForDef(secret->def));
718

719
 cleanup:
720
    secretDriverUnlock();
721 722 723 724 725
    return ret;
}


static virSecretPtr
726 727
secretDefineXML(virConnectPtr conn,
                const char *xml,
728
                unsigned int flags)
729 730
{
    virSecretPtr ret = NULL;
J
John Ferlan 已提交
731
    virSecretObjPtr secret = NULL;
732 733
    virSecretDefPtr backup = NULL;
    virSecretDefPtr new_attrs;
734

735 736
    virCheckFlags(0, NULL);

737
    if (!(new_attrs = virSecretDefParseString(xml)))
738 739
        return NULL;

740
    secretDriverLock();
741

742 743 744
    if (virSecretDefineXMLEnsureACL(conn, new_attrs) < 0)
        goto cleanup;

745 746 747
    if (!(secret = secretFindByUUID(new_attrs->uuid))) {
        /* No existing secret with same UUID,
         * try look for matching usage instead */
748
        const char *usageID = secretUsageIDForDef(new_attrs);
749 750
        char uuidstr[VIR_UUID_STRING_BUFLEN];

751
        if ((secret = secretFindByUsage(new_attrs->usage_type, usageID))) {
752
            virUUIDFormat(secret->def->uuid, uuidstr);
753
            virReportError(VIR_ERR_INTERNAL_ERROR,
754 755
                           _("a secret with UUID %s already defined for "
                             "use with %s"),
756
                           uuidstr, usageID);
757 758
            goto cleanup;
        }
759

760
        /* No existing secret at all, create one */
J
John Ferlan 已提交
761
        if (!(secret = secretAssignDef(&driver->secrets, new_attrs)))
762
            goto cleanup;
763

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

        if (secret->def->private && !new_attrs->private) {
794 795
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("cannot change private flag on existing secret"));
796 797 798 799 800 801
            goto cleanup;
        }

        /* Got an existing secret matches attrs, so reuse that */
        backup = secret->def;
        secret->def = new_attrs;
802 803 804
    }

    if (!new_attrs->ephemeral) {
805
        if (backup && backup->ephemeral) {
806
            if (secretSaveValue(secret) < 0)
807 808
                goto restore_backup;
        }
809
        if (secretSaveDef(secret) < 0) {
810
            if (backup && backup->ephemeral) {
811
                /* Undo the secretSaveValue() above; ignore errors */
812
                (void)unlink(secret->base64File);
813 814 815
            }
            goto restore_backup;
        }
816
    } else if (backup && !backup->ephemeral) {
817
        if (secretDeleteSaved(secret) < 0)
818 819
            goto restore_backup;
    }
820
    /* Saved successfully - drop old values */
821 822 823
    new_attrs = NULL;
    virSecretDefFree(backup);

824 825 826 827
    ret = virGetSecret(conn,
                       secret->def->uuid,
                       secret->def->usage_type,
                       secretUsageIDForDef(secret->def));
828 829
    goto cleanup;

830
 restore_backup:
831 832 833 834
    if (backup) {
        /* Error - restore previous state and free new attributes */
        secret->def = backup;
    } else {
835
        /* "secret" was added to the head of the list above */
836
        if (listUnlink(&driver->secrets) != secret)
837 838
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("list of secrets is inconsistent"));
839 840 841 842
        else
            secretFree(secret);
    }

843
 cleanup:
844
    virSecretDefFree(new_attrs);
845
    secretDriverUnlock();
846 847 848 849 850

    return ret;
}

static char *
851 852
secretGetXMLDesc(virSecretPtr obj,
                 unsigned int flags)
853 854
{
    char *ret = NULL;
J
John Ferlan 已提交
855
    virSecretObjPtr secret;
856

857 858
    virCheckFlags(0, NULL);

859
    secretDriverLock();
860

861
    if (!(secret = secretFindByUUID(obj->uuid))) {
862 863
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(obj->uuid, uuidstr);
864 865
        virReportError(VIR_ERR_NO_SECRET,
                       _("no secret with matching uuid '%s'"), uuidstr);
866 867 868
        goto cleanup;
    }

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

872
    ret = virSecretDefFormat(secret->def);
873

874
 cleanup:
875
    secretDriverUnlock();
876 877 878 879 880

    return ret;
}

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

891 892
    virCheckFlags(0, -1);

893
    if (VIR_ALLOC_N(new_value, value_size) < 0)
894 895
        return -1;

896
    secretDriverLock();
897

898
    if (!(secret = secretFindByUUID(obj->uuid))) {
899 900
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(obj->uuid, uuidstr);
901 902
        virReportError(VIR_ERR_NO_SECRET,
                       _("no secret with matching uuid '%s'"), uuidstr);
903 904 905
        goto cleanup;
    }

906 907 908
    if (virSecretSetValueEnsureACL(obj->conn, secret->def) < 0)
        goto cleanup;

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

    ret = 0;
    goto cleanup;

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

935
 cleanup:
936
    secretDriverUnlock();
937 938 939 940 941 942 943

    VIR_FREE(new_value);

    return ret;
}

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

952 953
    virCheckFlags(0, NULL);

954
    secretDriverLock();
955

956
    if (!(secret = secretFindByUUID(obj->uuid))) {
957 958
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(obj->uuid, uuidstr);
959 960
        virReportError(VIR_ERR_NO_SECRET,
                       _("no secret with matching uuid '%s'"), uuidstr);
961 962
        goto cleanup;
    }
963

964 965 966
    if (virSecretGetValueEnsureACL(obj->conn, secret->def) < 0)
        goto cleanup;

967
    if (secret->value == NULL) {
968 969
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(obj->uuid, uuidstr);
970 971
        virReportError(VIR_ERR_NO_SECRET,
                       _("secret '%s' does not have a value"), uuidstr);
972 973 974
        goto cleanup;
    }

975
    if ((internalFlags & VIR_SECRET_GET_VALUE_INTERNAL_CALL) == 0 &&
976
        secret->def->private) {
977
        virReportError(VIR_ERR_INVALID_SECRET, "%s",
978
                       _("secret is private"));
979 980 981
        goto cleanup;
    }

982
    if (VIR_ALLOC_N(ret, secret->value_size) < 0)
983 984 985 986
        goto cleanup;
    memcpy(ret, secret->value, secret->value_size);
    *value_size = secret->value_size;

987
 cleanup:
988
    secretDriverUnlock();
989 990 991 992 993 994 995 996

    return ret;
}

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

999
    secretDriverLock();
1000

1001
    if (!(secret = secretFindByUUID(obj->uuid))) {
1002 1003
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(obj->uuid, uuidstr);
1004 1005
        virReportError(VIR_ERR_NO_SECRET,
                       _("no secret with matching uuid '%s'"), uuidstr);
1006 1007 1008
        goto cleanup;
    }

1009 1010 1011
    if (virSecretUndefineEnsureACL(obj->conn, secret->def) < 0)
        goto cleanup;

1012
    if (!secret->def->ephemeral &&
1013
        secretDeleteSaved(secret) < 0)
1014 1015
        goto cleanup;

J
John Ferlan 已提交
1016
    listUnlinkSecret(&driver->secrets, secret);
1017 1018 1019 1020
    secretFree(secret);

    ret = 0;

1021
 cleanup:
1022
    secretDriverUnlock();
1023 1024 1025 1026 1027

    return ret;
}

static int
1028
secretStateCleanup(void)
1029
{
1030
    if (driver == NULL)
1031 1032
        return -1;

1033
    secretDriverLock();
1034

1035
    while (driver->secrets != NULL) {
1036
        virSecretObjPtr secret;
1037

1038 1039
        secret = listUnlink(&driver->secrets);
        secretFree(secret);
1040
    }
1041
    VIR_FREE(driver->configDir);
1042

1043 1044 1045
    secretDriverUnlock();
    virMutexDestroy(&driver->lock);
    VIR_FREE(driver);
1046 1047 1048 1049 1050

    return 0;
}

static int
1051 1052 1053
secretStateInitialize(bool privileged,
                      virStateInhibitCallback callback ATTRIBUTE_UNUSED,
                      void *opaque ATTRIBUTE_UNUSED)
1054 1055 1056
{
    char *base = NULL;

1057
    if (VIR_ALLOC(driver) < 0)
1058 1059
        return -1;

1060 1061
    if (virMutexInit(&driver->lock) < 0) {
        VIR_FREE(driver);
1062 1063
        return -1;
    }
1064
    secretDriverLock();
1065 1066

    if (privileged) {
1067 1068
        if (VIR_STRDUP(base, SYSCONFDIR "/libvirt") < 0)
            goto error;
1069
    } else {
1070
        if (!(base = virGetUserConfigDirectory()))
1071 1072
            goto error;
    }
1073
    if (virAsprintf(&driver->configDir, "%s/secrets", base) < 0)
1074
        goto error;
1075 1076
    VIR_FREE(base);

J
John Ferlan 已提交
1077
    if (secretLoadAllConfigs(&driver->secrets, driver->configDir) < 0)
1078 1079
        goto error;

1080
    secretDriverUnlock();
1081 1082 1083 1084
    return 0;

 error:
    VIR_FREE(base);
1085
    secretDriverUnlock();
1086
    secretStateCleanup();
1087 1088 1089 1090
    return -1;
}

static int
1091
secretStateReload(void)
1092
{
J
John Ferlan 已提交
1093
    virSecretObjPtr new_secrets = NULL;
1094

1095
    if (!driver)
1096 1097
        return -1;

1098
    secretDriverLock();
1099

J
John Ferlan 已提交
1100
    if (secretLoadAllConfigs(&new_secrets, driver->configDir) < 0)
1101 1102
        goto end;

1103 1104
    /* Keep ephemeral secrets from current state.
     * Discard non-ephemeral secrets that were removed
1105
     * by the secrets configDir.  */
1106
    while (driver->secrets != NULL) {
1107
        virSecretObjPtr secret;
1108

1109 1110 1111
        secret = listUnlink(&driver->secrets);
        if (secret->def->ephemeral)
            listInsert(&new_secrets, secret);
1112
        else
1113
            secretFree(secret);
1114
    }
1115
    driver->secrets = new_secrets;
1116 1117

 end:
1118
    secretDriverUnlock();
1119 1120 1121 1122 1123
    return 0;
}

static virSecretDriver secretDriver = {
    .name = "secret",
1124 1125 1126
    .connectNumOfSecrets = secretConnectNumOfSecrets, /* 0.7.1 */
    .connectListSecrets = secretConnectListSecrets, /* 0.7.1 */
    .connectListAllSecrets = secretConnectListAllSecrets, /* 0.10.2 */
1127 1128 1129 1130 1131 1132 1133
    .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 */
1134 1135 1136
};

static virStateDriver stateDriver = {
1137
    .name = "secret",
1138 1139 1140
    .stateInitialize = secretStateInitialize,
    .stateCleanup = secretStateCleanup,
    .stateReload = secretStateReload,
1141 1142 1143 1144 1145
};

int
secretRegister(void)
{
1146
    if (virSetSharedSecretDriver(&secretDriver) < 0)
1147 1148 1149
        return -1;
    if (virRegisterStateDriver(&stateDriver) < 0)
        return -1;
1150 1151
    return 0;
}