secret_driver.c 14.5 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
#include "secret_event.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;
60
    virSecretObjListPtr secrets;
61
    char *configDir;
62 63 64

    /* Immutable pointer, self-locking APIs */
    virObjectEventStatePtr secretEventState;
65 66
};

67
static virSecretDriverStatePtr driver;
68 69

static void
70
secretDriverLock(void)
71 72 73 74
{
    virMutexLock(&driver->lock);
}

75

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

J
John Ferlan 已提交
82

J
John Ferlan 已提交
83 84 85 86 87 88
static virSecretObjPtr
secretObjFromSecret(virSecretPtr secret)
{
    virSecretObjPtr obj;
    char uuidstr[VIR_UUID_STRING_BUFLEN];

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


99
/* Driver functions */
100 101

static int
102
secretConnectNumOfSecrets(virConnectPtr conn)
103
{
104 105 106
    if (virConnectNumOfSecretsEnsureACL(conn) < 0)
        return -1;

107 108 109
    return virSecretObjListNumOfSecrets(driver->secrets,
                                        virConnectNumOfSecretsCheckACL,
                                        conn);
110 111
}

112

113
static int
114 115 116
secretConnectListSecrets(virConnectPtr conn,
                         char **uuids,
                         int maxuuids)
117 118 119
{
    memset(uuids, 0, maxuuids * sizeof(*uuids));

120 121 122
    if (virConnectListSecretsEnsureACL(conn) < 0)
        return -1;

123 124
    return virSecretObjListGetUUIDs(driver->secrets, uuids, maxuuids,
                                    virConnectListSecretsCheckACL, conn);
125 126
}

127

O
Osier Yang 已提交
128
static int
129 130
secretConnectListAllSecrets(virConnectPtr conn,
                            virSecretPtr **secrets,
131 132
                            unsigned int flags)
{
O
Osier Yang 已提交
133 134
    virCheckFlags(VIR_CONNECT_LIST_SECRETS_FILTERS_ALL, -1);

135 136 137
    if (virConnectListAllSecretsEnsureACL(conn) < 0)
        return -1;

138 139 140
    return virSecretObjListExport(conn, driver->secrets, secrets,
                                  virConnectListAllSecretsCheckACL,
                                  flags);
O
Osier Yang 已提交
141 142 143
}


144
static virSecretPtr
145 146
secretLookupByUUID(virConnectPtr conn,
                   const unsigned char *uuid)
147 148
{
    virSecretPtr ret = NULL;
149
    virSecretObjPtr obj;
150
    virSecretDefPtr def;
151

152
    if (!(obj = virSecretObjListFindByUUID(driver->secrets, uuid))) {
153 154
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(uuid, uuidstr);
155 156
        virReportError(VIR_ERR_NO_SECRET,
                       _("no secret with matching uuid '%s'"), uuidstr);
157 158 159
        goto cleanup;
    }

160
    def = virSecretObjGetDef(obj);
161
    if (virSecretLookupByUUIDEnsureACL(conn, def) < 0)
162 163
        goto cleanup;

164
    ret = virGetSecret(conn,
165 166
                       def->uuid,
                       def->usage_type,
167
                       def->usage_id);
168

169
 cleanup:
170
    virSecretObjEndAPI(&obj);
171 172 173 174 175
    return ret;
}


static virSecretPtr
176 177 178
secretLookupByUsage(virConnectPtr conn,
                    int usageType,
                    const char *usageID)
179 180
{
    virSecretPtr ret = NULL;
181
    virSecretObjPtr obj;
182
    virSecretDefPtr def;
183

184 185
    if (!(obj = virSecretObjListFindByUsage(driver->secrets,
                                            usageType, usageID))) {
186 187
        virReportError(VIR_ERR_NO_SECRET,
                       _("no secret with matching usage '%s'"), usageID);
188 189 190
        goto cleanup;
    }

191
    def = virSecretObjGetDef(obj);
192
    if (virSecretLookupByUsageEnsureACL(conn, def) < 0)
193 194
        goto cleanup;

195
    ret = virGetSecret(conn,
196 197
                       def->uuid,
                       def->usage_type,
198
                       def->usage_id);
199

200
 cleanup:
201
    virSecretObjEndAPI(&obj);
202 203 204 205 206
    return ret;
}


static virSecretPtr
207 208
secretDefineXML(virConnectPtr conn,
                const char *xml,
209
                unsigned int flags)
210 211
{
    virSecretPtr ret = NULL;
212
    virSecretObjPtr obj = NULL;
213
    virSecretDefPtr backup = NULL;
214
    virSecretDefPtr def;
215
    virObjectEventPtr event = NULL;
216

217 218
    virCheckFlags(0, NULL);

219
    if (!(def = virSecretDefParseString(xml)))
220 221
        return NULL;

222
    if (virSecretDefineXMLEnsureACL(conn, def) < 0)
223 224
        goto cleanup;

225 226
    if (!(obj = virSecretObjListAdd(driver->secrets, def,
                                    driver->configDir, &backup)))
227
        goto cleanup;
228

229
    if (!def->isephemeral) {
230
        if (backup && backup->isephemeral) {
231
            if (virSecretObjSaveData(obj) < 0)
232 233
                goto restore_backup;
        }
234

235
        if (virSecretObjSaveConfig(obj) < 0) {
236
            if (backup && backup->isephemeral) {
237
                /* Undo the virSecretObjSaveData() above; ignore errors */
238
                virSecretObjDeleteData(obj);
239 240 241
            }
            goto restore_backup;
        }
242
    } else if (backup && !backup->isephemeral) {
243
        if (virSecretObjDeleteConfig(obj) < 0)
244
            goto restore_backup;
245

246
        virSecretObjDeleteData(obj);
247
    }
248
    /* Saved successfully - drop old values */
249 250
    virSecretDefFree(backup);

251 252 253
    event = virSecretEventLifecycleNew(def->uuid,
                                       def->usage_type,
                                       def->usage_id,
254 255 256
                                       VIR_SECRET_EVENT_DEFINED,
                                       0);

257
    ret = virGetSecret(conn,
258 259 260 261
                       def->uuid,
                       def->usage_type,
                       def->usage_id);
    def = NULL;
262 263
    goto cleanup;

264
 restore_backup:
265
    /* If we have a backup, then secret was defined before, so just restore
266
     * the backup. The current def will be handled below.
267 268 269
     * Otherwise, this is a new secret, thus remove it.
     */
    if (backup)
270
        virSecretObjSetDef(obj, backup);
271
    else
272
        virSecretObjListRemove(driver->secrets, obj);
273

274
 cleanup:
275 276
    virSecretDefFree(def);
    virSecretObjEndAPI(&obj);
277 278
    if (event)
        virObjectEventStateQueue(driver->secretEventState, event);
279 280 281 282

    return ret;
}

283

284
static char *
285
secretGetXMLDesc(virSecretPtr secret,
286
                 unsigned int flags)
287 288
{
    char *ret = NULL;
289
    virSecretObjPtr obj;
290
    virSecretDefPtr def;
291

292 293
    virCheckFlags(0, NULL);

294
    if (!(obj = secretObjFromSecret(secret)))
295 296
        goto cleanup;

297 298
    def = virSecretObjGetDef(obj);
    if (virSecretGetXMLDescEnsureACL(secret->conn, def) < 0)
299 300
        goto cleanup;

301
    ret = virSecretDefFormat(def);
302

303
 cleanup:
304
    virSecretObjEndAPI(&obj);
305 306 307 308

    return ret;
}

309

310
static int
311
secretSetValue(virSecretPtr secret,
312 313 314
               const unsigned char *value,
               size_t value_size,
               unsigned int flags)
315 316
{
    int ret = -1;
317
    virSecretObjPtr obj;
318
    virSecretDefPtr def;
319
    virObjectEventPtr event = NULL;
320

321 322
    virCheckFlags(0, -1);

323
    if (!(obj = secretObjFromSecret(secret)))
324 325
        goto cleanup;

326 327
    def = virSecretObjGetDef(obj);
    if (virSecretSetValueEnsureACL(secret->conn, def) < 0)
328 329
        goto cleanup;

330
    if (virSecretObjSetValue(obj, value, value_size) < 0)
331
        goto cleanup;
332

333 334 335
    event = virSecretEventValueChangedNew(def->uuid,
                                          def->usage_type,
                                          def->usage_id);
336 337
    ret = 0;

338
 cleanup:
339
    virSecretObjEndAPI(&obj);
340 341
    if (event)
        virObjectEventStateQueue(driver->secretEventState, event);
342 343 344 345

    return ret;
}

346

347
static unsigned char *
348
secretGetValue(virSecretPtr secret,
349 350
               size_t *value_size,
               unsigned int flags,
351
               unsigned int internalFlags)
352 353
{
    unsigned char *ret = NULL;
354
    virSecretObjPtr obj;
355
    virSecretDefPtr def;
356

357 358
    virCheckFlags(0, NULL);

359
    if (!(obj = secretObjFromSecret(secret)))
360
        goto cleanup;
361

362 363
    def = virSecretObjGetDef(obj);
    if (virSecretGetValueEnsureACL(secret->conn, def) < 0)
364 365
        goto cleanup;

366
    if ((internalFlags & VIR_SECRET_GET_VALUE_INTERNAL_CALL) == 0 &&
367
        def->isprivate) {
368
        virReportError(VIR_ERR_INVALID_SECRET, "%s",
369
                       _("secret is private"));
370 371 372
        goto cleanup;
    }

373
    if (!(ret = virSecretObjGetValue(obj)))
374
        goto cleanup;
375

376
    *value_size = virSecretObjGetValueSize(obj);
377

378
 cleanup:
379
    virSecretObjEndAPI(&obj);
380 381 382 383

    return ret;
}

384

385
static int
386
secretUndefine(virSecretPtr secret)
387 388
{
    int ret = -1;
389
    virSecretObjPtr obj;
390
    virSecretDefPtr def;
391
    virObjectEventPtr event = NULL;
392

393
    if (!(obj = secretObjFromSecret(secret)))
394 395
        goto cleanup;

396 397
    def = virSecretObjGetDef(obj);
    if (virSecretUndefineEnsureACL(secret->conn, def) < 0)
398 399
        goto cleanup;

400
    if (virSecretObjDeleteConfig(obj) < 0)
401 402
        goto cleanup;

403 404 405 406 407 408
    event = virSecretEventLifecycleNew(def->uuid,
                                       def->usage_type,
                                       def->usage_id,
                                       VIR_SECRET_EVENT_UNDEFINED,
                                       0);

409
    virSecretObjDeleteData(obj);
410

411
    virSecretObjListRemove(driver->secrets, obj);
412 413 414

    ret = 0;

415
 cleanup:
416
    virSecretObjEndAPI(&obj);
417 418
    if (event)
        virObjectEventStateQueue(driver->secretEventState, event);
419 420 421 422

    return ret;
}

423

424
static int
425
secretStateCleanup(void)
426
{
427
    if (!driver)
428 429
        return -1;

430
    secretDriverLock();
431

432
    virObjectUnref(driver->secrets);
433
    VIR_FREE(driver->configDir);
434

435 436
    virObjectUnref(driver->secretEventState);

437 438 439
    secretDriverUnlock();
    virMutexDestroy(&driver->lock);
    VIR_FREE(driver);
440 441 442 443

    return 0;
}

444

445
static int
446 447 448
secretStateInitialize(bool privileged,
                      virStateInhibitCallback callback ATTRIBUTE_UNUSED,
                      void *opaque ATTRIBUTE_UNUSED)
449 450 451
{
    char *base = NULL;

452
    if (VIR_ALLOC(driver) < 0)
453 454
        return -1;

455 456
    if (virMutexInit(&driver->lock) < 0) {
        VIR_FREE(driver);
457 458
        return -1;
    }
459
    secretDriverLock();
460

461 462
    driver->secretEventState = virObjectEventStateNew();

463
    if (privileged) {
464 465
        if (VIR_STRDUP(base, SYSCONFDIR "/libvirt") < 0)
            goto error;
466
    } else {
467
        if (!(base = virGetUserConfigDirectory()))
468 469
            goto error;
    }
470
    if (virAsprintf(&driver->configDir, "%s/secrets", base) < 0)
471
        goto error;
472 473
    VIR_FREE(base);

474 475 476 477 478 479
    if (virFileMakePathWithMode(driver->configDir, S_IRWXU) < 0) {
        virReportSystemError(errno, _("cannot create config directory '%s'"),
                             driver->configDir);
        goto error;
    }

480 481 482
    if (!(driver->secrets = virSecretObjListNew()))
        goto error;

483
    if (virSecretLoadAllConfigs(driver->secrets, driver->configDir) < 0)
484 485
        goto error;

486
    secretDriverUnlock();
487 488 489 490
    return 0;

 error:
    VIR_FREE(base);
491
    secretDriverUnlock();
492
    secretStateCleanup();
493 494 495
    return -1;
}

496

497
static int
498
secretStateReload(void)
499
{
500
    if (!driver)
501 502
        return -1;

503
    secretDriverLock();
504

505
    ignore_value(virSecretLoadAllConfigs(driver->secrets, driver->configDir));
506

507
    secretDriverUnlock();
508 509 510
    return 0;
}

511

512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532
static int
secretConnectSecretEventRegisterAny(virConnectPtr conn,
                                    virSecretPtr secret,
                                    int eventID,
                                    virConnectSecretEventGenericCallback callback,
                                    void *opaque,
                                    virFreeCallback freecb)
{
    int callbackID = -1;

    if (virConnectSecretEventRegisterAnyEnsureACL(conn) < 0)
        goto cleanup;

    if (virSecretEventStateRegisterID(conn, driver->secretEventState,
                                      secret, eventID, callback,
                                      opaque, freecb, &callbackID) < 0)
        callbackID = -1;
 cleanup:
    return callbackID;
}

533

534 535 536 537 538 539 540 541 542 543 544
static int
secretConnectSecretEventDeregisterAny(virConnectPtr conn,
                                      int callbackID)
{
    int ret = -1;

    if (virConnectSecretEventDeregisterAnyEnsureACL(conn) < 0)
        goto cleanup;

    if (virObjectEventStateDeregisterID(conn,
                                        driver->secretEventState,
545
                                        callbackID, true) < 0)
546 547 548 549 550 551 552 553 554
        goto cleanup;

    ret = 0;

 cleanup:
    return ret;
}


555 556
static virSecretDriver secretDriver = {
    .name = "secret",
557 558 559
    .connectNumOfSecrets = secretConnectNumOfSecrets, /* 0.7.1 */
    .connectListSecrets = secretConnectListSecrets, /* 0.7.1 */
    .connectListAllSecrets = secretConnectListAllSecrets, /* 0.10.2 */
560 561 562 563 564 565 566
    .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 */
567 568
    .connectSecretEventRegisterAny = secretConnectSecretEventRegisterAny, /* 3.0.0 */
    .connectSecretEventDeregisterAny = secretConnectSecretEventDeregisterAny, /* 3.0.0 */
569 570 571
};

static virStateDriver stateDriver = {
572
    .name = "secret",
573 574 575
    .stateInitialize = secretStateInitialize,
    .stateCleanup = secretStateCleanup,
    .stateReload = secretStateReload,
576 577
};

578

579 580 581
int
secretRegister(void)
{
582
    if (virSetSharedSecretDriver(&secretDriver) < 0)
583 584 585
        return -1;
    if (virRegisterStateDriver(&stateDriver) < 0)
        return -1;
586 587
    return 0;
}