secret_driver.c 14.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
 *
 * Red Hat Author: Miloslav Trmač <mitr@redhat.com>
 */

#include <config.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"
34
#include "virlog.h"
35
#include "viralloc.h"
36
#include "secret_conf.h"
37
#include "virsecretobj.h"
38
#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 55 56 57 58

typedef struct _virSecretDriverState virSecretDriverState;
typedef virSecretDriverState *virSecretDriverStatePtr;
struct _virSecretDriverState {
    virMutex lock;
59
    virSecretObjListPtr secrets;
60
    char *configDir;
61 62
};

63
static virSecretDriverStatePtr driver;
64 65

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

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

J
John Ferlan 已提交
77

J
John Ferlan 已提交
78 79 80 81 82 83 84

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

85
    if (!(obj = virSecretObjListFindByUUID(driver->secrets, secret->uuid))) {
J
John Ferlan 已提交
86 87 88 89 90 91 92 93 94
        virUUIDFormat(secret->uuid, uuidstr);
        virReportError(VIR_ERR_NO_SECRET,
                       _("no secret with matching uuid '%s'"), uuidstr);
        return NULL;
    }
    return obj;
}


95
/* Permament secret storage */
96

97
/* Secrets are stored in virSecretDriverStatePtr->configDir.  Each secret
98 99 100 101 102
   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
103 104
secretRewriteFile(int fd,
                  void *opaque)
105
{
106
    char *data = opaque;
107

108 109
    if (safewrite(fd, data, strlen(data)) < 0)
        return -1;
110

111
    return 0;
112 113 114 115
}


static int
116
secretEnsureDirectory(void)
117
{
118
    if (mkdir(driver->configDir, S_IRWXU) < 0 && errno != EEXIST) {
119
        virReportSystemError(errno, _("cannot create '%s'"),
120
                             driver->configDir);
121 122 123 124 125 126
        return -1;
    }
    return 0;
}

static int
J
John Ferlan 已提交
127
secretSaveDef(const virSecretObj *secret)
128
{
129
    char *xml = NULL;
130 131
    int ret = -1;

132
    if (secretEnsureDirectory() < 0)
133 134
        goto cleanup;

135
    if (!(xml = virSecretDefFormat(secret->def)))
136 137
        goto cleanup;

138
    if (virFileRewrite(secret->configFile, S_IRUSR | S_IWUSR,
139
                       secretRewriteFile, xml) < 0)
140 141 142 143
        goto cleanup;

    ret = 0;

144
 cleanup:
145 146 147 148 149
    VIR_FREE(xml);
    return ret;
}

static int
J
John Ferlan 已提交
150
secretSaveValue(const virSecretObj *secret)
151
{
152
    char *base64 = NULL;
153 154 155 156 157
    int ret = -1;

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

158
    if (secretEnsureDirectory() < 0)
159 160 161 162 163
        goto cleanup;

    base64_encode_alloc((const char *)secret->value, secret->value_size,
                        &base64);
    if (base64 == NULL) {
164
        virReportOOMError();
165 166 167
        goto cleanup;
    }

168
    if (virFileRewrite(secret->base64File, S_IRUSR | S_IWUSR,
169
                       secretRewriteFile, base64) < 0)
170 171 172 173
        goto cleanup;

    ret = 0;

174
 cleanup:
175 176 177 178 179
    VIR_FREE(base64);
    return ret;
}

static int
J
John Ferlan 已提交
180
secretDeleteSaved(const virSecretObj *secret)
181
{
182
    if (unlink(secret->configFile) < 0 && errno != ENOENT)
183 184
        return -1;

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

189
    return 0;
190 191
}

192
/* Driver functions */
193 194

static int
195
secretConnectNumOfSecrets(virConnectPtr conn)
196
{
197 198 199
    if (virConnectNumOfSecretsEnsureACL(conn) < 0)
        return -1;

200 201 202
    return virSecretObjListNumOfSecrets(driver->secrets,
                                        virConnectNumOfSecretsCheckACL,
                                        conn);
203 204 205
}

static int
206 207 208
secretConnectListSecrets(virConnectPtr conn,
                         char **uuids,
                         int maxuuids)
209 210 211
{
    memset(uuids, 0, maxuuids * sizeof(*uuids));

212 213 214
    if (virConnectListSecretsEnsureACL(conn) < 0)
        return -1;

215 216
    return virSecretObjListGetUUIDs(driver->secrets, uuids, maxuuids,
                                    virConnectListSecretsCheckACL, conn);
217 218
}

219

O
Osier Yang 已提交
220
static int
221 222
secretConnectListAllSecrets(virConnectPtr conn,
                            virSecretPtr **secrets,
223 224
                            unsigned int flags)
{
O
Osier Yang 已提交
225 226
    virCheckFlags(VIR_CONNECT_LIST_SECRETS_FILTERS_ALL, -1);

227 228 229
    if (virConnectListAllSecretsEnsureACL(conn) < 0)
        return -1;

230 231 232
    return virSecretObjListExport(conn, driver->secrets, secrets,
                                  virConnectListAllSecretsCheckACL,
                                  flags);
O
Osier Yang 已提交
233 234 235
}


236
static virSecretPtr
237 238
secretLookupByUUID(virConnectPtr conn,
                   const unsigned char *uuid)
239 240
{
    virSecretPtr ret = NULL;
J
John Ferlan 已提交
241
    virSecretObjPtr secret;
242

243
    if (!(secret = virSecretObjListFindByUUID(driver->secrets, uuid))) {
244 245
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(uuid, uuidstr);
246 247
        virReportError(VIR_ERR_NO_SECRET,
                       _("no secret with matching uuid '%s'"), uuidstr);
248 249 250
        goto cleanup;
    }

251 252 253
    if (virSecretLookupByUUIDEnsureACL(conn, secret->def) < 0)
        goto cleanup;

254 255 256
    ret = virGetSecret(conn,
                       secret->def->uuid,
                       secret->def->usage_type,
257
                       virSecretUsageIDForDef(secret->def));
258

259
 cleanup:
260
    virSecretObjEndAPI(&secret);
261 262 263 264 265
    return ret;
}


static virSecretPtr
266 267 268
secretLookupByUsage(virConnectPtr conn,
                    int usageType,
                    const char *usageID)
269 270
{
    virSecretPtr ret = NULL;
J
John Ferlan 已提交
271
    virSecretObjPtr secret;
272

273 274
    if (!(secret = virSecretObjListFindByUsage(driver->secrets,
                                               usageType, usageID))) {
275 276
        virReportError(VIR_ERR_NO_SECRET,
                       _("no secret with matching usage '%s'"), usageID);
277 278 279
        goto cleanup;
    }

280 281 282
    if (virSecretLookupByUsageEnsureACL(conn, secret->def) < 0)
        goto cleanup;

283 284 285
    ret = virGetSecret(conn,
                       secret->def->uuid,
                       secret->def->usage_type,
286
                       virSecretUsageIDForDef(secret->def));
287

288
 cleanup:
289
    virSecretObjEndAPI(&secret);
290 291 292 293 294
    return ret;
}


static virSecretPtr
295 296
secretDefineXML(virConnectPtr conn,
                const char *xml,
297
                unsigned int flags)
298 299
{
    virSecretPtr ret = NULL;
J
John Ferlan 已提交
300
    virSecretObjPtr secret = NULL;
301 302
    virSecretDefPtr backup = NULL;
    virSecretDefPtr new_attrs;
303

304 305
    virCheckFlags(0, NULL);

306
    if (!(new_attrs = virSecretDefParseString(xml)))
307 308
        return NULL;

309 310 311
    if (virSecretDefineXMLEnsureACL(conn, new_attrs) < 0)
        goto cleanup;

312 313 314
    if (!(secret = virSecretObjListAdd(driver->secrets, new_attrs,
                                       driver->configDir, &backup)))
        goto cleanup;
315 316

    if (!new_attrs->ephemeral) {
317
        if (backup && backup->ephemeral) {
318
            if (secretSaveValue(secret) < 0)
319 320
                goto restore_backup;
        }
321
        if (secretSaveDef(secret) < 0) {
322
            if (backup && backup->ephemeral) {
323
                /* Undo the secretSaveValue() above; ignore errors */
324
                (void)unlink(secret->base64File);
325 326 327
            }
            goto restore_backup;
        }
328
    } else if (backup && !backup->ephemeral) {
329
        if (secretDeleteSaved(secret) < 0)
330 331
            goto restore_backup;
    }
332
    /* Saved successfully - drop old values */
333 334 335
    new_attrs = NULL;
    virSecretDefFree(backup);

336 337 338
    ret = virGetSecret(conn,
                       secret->def->uuid,
                       secret->def->usage_type,
339
                       virSecretUsageIDForDef(secret->def));
340 341
    goto cleanup;

342
 restore_backup:
343 344 345 346 347
    /* If we have a backup, then secret was defined before, so just restore
     * the backup. The current secret->def (new_attrs) will be handled below.
     * Otherwise, this is a new secret, thus remove it.
     */
    if (backup)
348
        secret->def = backup;
349 350
    else
        virSecretObjListRemove(driver->secrets, secret);
351

352
 cleanup:
353
    virSecretDefFree(new_attrs);
354
    virSecretObjEndAPI(&secret);
355 356 357 358 359

    return ret;
}

static char *
360 361
secretGetXMLDesc(virSecretPtr obj,
                 unsigned int flags)
362 363
{
    char *ret = NULL;
J
John Ferlan 已提交
364
    virSecretObjPtr secret;
365

366 367
    virCheckFlags(0, NULL);

J
John Ferlan 已提交
368
    if (!(secret = secretObjFromSecret(obj)))
369 370
        goto cleanup;

371 372 373
    if (virSecretGetXMLDescEnsureACL(obj->conn, secret->def) < 0)
        goto cleanup;

374
    ret = virSecretDefFormat(secret->def);
375

376
 cleanup:
377
    virSecretObjEndAPI(&secret);
378 379 380 381 382

    return ret;
}

static int
383 384 385 386
secretSetValue(virSecretPtr obj,
               const unsigned char *value,
               size_t value_size,
               unsigned int flags)
387 388 389 390
{
    int ret = -1;
    unsigned char *old_value, *new_value;
    size_t old_value_size;
J
John Ferlan 已提交
391
    virSecretObjPtr secret;
392

393 394
    virCheckFlags(0, -1);

395
    if (VIR_ALLOC_N(new_value, value_size) < 0)
396 397
        return -1;

J
John Ferlan 已提交
398
    if (!(secret = secretObjFromSecret(obj)))
399 400
        goto cleanup;

401 402 403
    if (virSecretSetValueEnsureACL(obj->conn, secret->def) < 0)
        goto cleanup;

404 405 406 407 408 409 410
    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) {
411
        if (secretSaveValue(secret) < 0)
412 413
            goto restore_backup;
    }
414
    /* Saved successfully - drop old value */
415 416 417 418 419 420 421 422 423
    if (old_value != NULL) {
        memset(old_value, 0, old_value_size);
        VIR_FREE(old_value);
    }
    new_value = NULL;

    ret = 0;
    goto cleanup;

424
 restore_backup:
425 426 427 428 429
    /* Error - restore previous state and free new value */
    secret->value = old_value;
    secret->value_size = old_value_size;
    memset(new_value, 0, value_size);

430
 cleanup:
431
    virSecretObjEndAPI(&secret);
432 433 434 435 436 437 438

    VIR_FREE(new_value);

    return ret;
}

static unsigned char *
439 440 441
secretGetValue(virSecretPtr obj,
               size_t *value_size,
               unsigned int flags,
442
               unsigned int internalFlags)
443 444
{
    unsigned char *ret = NULL;
J
John Ferlan 已提交
445
    virSecretObjPtr secret;
446

447 448
    virCheckFlags(0, NULL);

J
John Ferlan 已提交
449
    if (!(secret = secretObjFromSecret(obj)))
450
        goto cleanup;
451

452 453 454
    if (virSecretGetValueEnsureACL(obj->conn, secret->def) < 0)
        goto cleanup;

455
    if (secret->value == NULL) {
456 457
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(obj->uuid, uuidstr);
458 459
        virReportError(VIR_ERR_NO_SECRET,
                       _("secret '%s' does not have a value"), uuidstr);
460 461 462
        goto cleanup;
    }

463
    if ((internalFlags & VIR_SECRET_GET_VALUE_INTERNAL_CALL) == 0 &&
464
        secret->def->private) {
465
        virReportError(VIR_ERR_INVALID_SECRET, "%s",
466
                       _("secret is private"));
467 468 469
        goto cleanup;
    }

470
    if (VIR_ALLOC_N(ret, secret->value_size) < 0)
471 472 473 474
        goto cleanup;
    memcpy(ret, secret->value, secret->value_size);
    *value_size = secret->value_size;

475
 cleanup:
476
    virSecretObjEndAPI(&secret);
477 478 479 480 481 482 483 484

    return ret;
}

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

J
John Ferlan 已提交
487
    if (!(secret = secretObjFromSecret(obj)))
488 489
        goto cleanup;

490 491 492
    if (virSecretUndefineEnsureACL(obj->conn, secret->def) < 0)
        goto cleanup;

493
    if (!secret->def->ephemeral &&
494
        secretDeleteSaved(secret) < 0)
495 496
        goto cleanup;

497
    virSecretObjListRemove(driver->secrets, secret);
498 499 500

    ret = 0;

501
 cleanup:
502
    virSecretObjEndAPI(&secret);
503 504 505 506 507

    return ret;
}

static int
508
secretStateCleanup(void)
509
{
510
    if (!driver)
511 512
        return -1;

513
    secretDriverLock();
514

515
    virObjectUnref(driver->secrets);
516
    VIR_FREE(driver->configDir);
517

518 519 520
    secretDriverUnlock();
    virMutexDestroy(&driver->lock);
    VIR_FREE(driver);
521 522 523 524 525

    return 0;
}

static int
526 527 528
secretStateInitialize(bool privileged,
                      virStateInhibitCallback callback ATTRIBUTE_UNUSED,
                      void *opaque ATTRIBUTE_UNUSED)
529 530 531
{
    char *base = NULL;

532
    if (VIR_ALLOC(driver) < 0)
533 534
        return -1;

535 536
    if (virMutexInit(&driver->lock) < 0) {
        VIR_FREE(driver);
537 538
        return -1;
    }
539
    secretDriverLock();
540 541

    if (privileged) {
542 543
        if (VIR_STRDUP(base, SYSCONFDIR "/libvirt") < 0)
            goto error;
544
    } else {
545
        if (!(base = virGetUserConfigDirectory()))
546 547
            goto error;
    }
548
    if (virAsprintf(&driver->configDir, "%s/secrets", base) < 0)
549
        goto error;
550 551
    VIR_FREE(base);

552 553 554
    if (!(driver->secrets = virSecretObjListNew()))
        goto error;

555
    if (virSecretLoadAllConfigs(driver->secrets, driver->configDir) < 0)
556 557
        goto error;

558
    secretDriverUnlock();
559 560 561 562
    return 0;

 error:
    VIR_FREE(base);
563
    secretDriverUnlock();
564
    secretStateCleanup();
565 566 567 568
    return -1;
}

static int
569
secretStateReload(void)
570
{
571
    if (!driver)
572 573
        return -1;

574
    secretDriverLock();
575

576
    ignore_value(virSecretLoadAllConfigs(driver->secrets, driver->configDir));
577

578
    secretDriverUnlock();
579 580 581 582 583
    return 0;
}

static virSecretDriver secretDriver = {
    .name = "secret",
584 585 586
    .connectNumOfSecrets = secretConnectNumOfSecrets, /* 0.7.1 */
    .connectListSecrets = secretConnectListSecrets, /* 0.7.1 */
    .connectListAllSecrets = secretConnectListAllSecrets, /* 0.10.2 */
587 588 589 590 591 592 593
    .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 */
594 595 596
};

static virStateDriver stateDriver = {
597
    .name = "secret",
598 599 600
    .stateInitialize = secretStateInitialize,
    .stateCleanup = secretStateCleanup,
    .stateReload = secretStateReload,
601 602 603 604 605
};

int
secretRegister(void)
{
606
    if (virSetSharedSecretDriver(&secretDriver) < 0)
607 608 609
        return -1;
    if (virRegisterStateDriver(&stateDriver) < 0)
        return -1;
610 611
    return 0;
}