You need to sign in or sign up before continuing.
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 75
{
    virMutexLock(&driver->lock);
}

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

J
John Ferlan 已提交
81

J
John Ferlan 已提交
82 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
}

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

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

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

126

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

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

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


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

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

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

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

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


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

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

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

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

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


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

216 217
    virCheckFlags(0, NULL);

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

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

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

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

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

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

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

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

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

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

    return ret;
}

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

290 291
    virCheckFlags(0, NULL);

292
    if (!(obj = secretObjFromSecret(secret)))
293 294
        goto cleanup;

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

299
    ret = virSecretDefFormat(def);
300

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

    return ret;
}

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

318 319
    virCheckFlags(0, -1);

320
    if (!(obj = secretObjFromSecret(secret)))
321 322
        goto cleanup;

323 324
    def = virSecretObjGetDef(obj);
    if (virSecretSetValueEnsureACL(secret->conn, def) < 0)
325 326
        goto cleanup;

327
    if (virSecretObjSetValue(obj, value, value_size) < 0)
328
        goto cleanup;
329

330 331 332
    event = virSecretEventValueChangedNew(def->uuid,
                                          def->usage_type,
                                          def->usage_id);
333 334
    ret = 0;

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

    return ret;
}

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

353 354
    virCheckFlags(0, NULL);

355
    if (!(obj = secretObjFromSecret(secret)))
356
        goto cleanup;
357

358 359
    def = virSecretObjGetDef(obj);
    if (virSecretGetValueEnsureACL(secret->conn, def) < 0)
360 361
        goto cleanup;

362
    if ((internalFlags & VIR_SECRET_GET_VALUE_INTERNAL_CALL) == 0 &&
363
        def->isprivate) {
364
        virReportError(VIR_ERR_INVALID_SECRET, "%s",
365
                       _("secret is private"));
366 367 368
        goto cleanup;
    }

369
    if (!(ret = virSecretObjGetValue(obj)))
370
        goto cleanup;
371

372
    *value_size = virSecretObjGetValueSize(obj);
373

374
 cleanup:
375
    virSecretObjEndAPI(&obj);
376 377 378 379 380

    return ret;
}

static int
381
secretUndefine(virSecretPtr secret)
382 383
{
    int ret = -1;
384
    virSecretObjPtr obj;
385
    virSecretDefPtr def;
386
    virObjectEventPtr event = NULL;
387

388
    if (!(obj = secretObjFromSecret(secret)))
389 390
        goto cleanup;

391 392
    def = virSecretObjGetDef(obj);
    if (virSecretUndefineEnsureACL(secret->conn, def) < 0)
393 394
        goto cleanup;

395
    if (virSecretObjDeleteConfig(obj) < 0)
396 397
        goto cleanup;

398 399 400 401 402 403
    event = virSecretEventLifecycleNew(def->uuid,
                                       def->usage_type,
                                       def->usage_id,
                                       VIR_SECRET_EVENT_UNDEFINED,
                                       0);

404
    virSecretObjDeleteData(obj);
405

406
    virSecretObjListRemove(driver->secrets, obj);
407 408 409

    ret = 0;

410
 cleanup:
411
    virSecretObjEndAPI(&obj);
412 413
    if (event)
        virObjectEventStateQueue(driver->secretEventState, event);
414 415 416 417 418

    return ret;
}

static int
419
secretStateCleanup(void)
420
{
421
    if (!driver)
422 423
        return -1;

424
    secretDriverLock();
425

426
    virObjectUnref(driver->secrets);
427
    VIR_FREE(driver->configDir);
428

429 430
    virObjectUnref(driver->secretEventState);

431 432 433
    secretDriverUnlock();
    virMutexDestroy(&driver->lock);
    VIR_FREE(driver);
434 435 436 437 438

    return 0;
}

static int
439 440 441
secretStateInitialize(bool privileged,
                      virStateInhibitCallback callback ATTRIBUTE_UNUSED,
                      void *opaque ATTRIBUTE_UNUSED)
442 443 444
{
    char *base = NULL;

445
    if (VIR_ALLOC(driver) < 0)
446 447
        return -1;

448 449
    if (virMutexInit(&driver->lock) < 0) {
        VIR_FREE(driver);
450 451
        return -1;
    }
452
    secretDriverLock();
453

454 455
    driver->secretEventState = virObjectEventStateNew();

456
    if (privileged) {
457 458
        if (VIR_STRDUP(base, SYSCONFDIR "/libvirt") < 0)
            goto error;
459
    } else {
460
        if (!(base = virGetUserConfigDirectory()))
461 462
            goto error;
    }
463
    if (virAsprintf(&driver->configDir, "%s/secrets", base) < 0)
464
        goto error;
465 466
    VIR_FREE(base);

467 468 469 470 471 472
    if (virFileMakePathWithMode(driver->configDir, S_IRWXU) < 0) {
        virReportSystemError(errno, _("cannot create config directory '%s'"),
                             driver->configDir);
        goto error;
    }

473 474 475
    if (!(driver->secrets = virSecretObjListNew()))
        goto error;

476
    if (virSecretLoadAllConfigs(driver->secrets, driver->configDir) < 0)
477 478
        goto error;

479
    secretDriverUnlock();
480 481 482 483
    return 0;

 error:
    VIR_FREE(base);
484
    secretDriverUnlock();
485
    secretStateCleanup();
486 487 488 489
    return -1;
}

static int
490
secretStateReload(void)
491
{
492
    if (!driver)
493 494
        return -1;

495
    secretDriverLock();
496

497
    ignore_value(virSecretLoadAllConfigs(driver->secrets, driver->configDir));
498

499
    secretDriverUnlock();
500 501 502
    return 0;
}

503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544
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;
}

static int
secretConnectSecretEventDeregisterAny(virConnectPtr conn,
                                      int callbackID)
{
    int ret = -1;

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

    if (virObjectEventStateDeregisterID(conn,
                                        driver->secretEventState,
                                        callbackID) < 0)
        goto cleanup;

    ret = 0;

 cleanup:
    return ret;
}


545 546
static virSecretDriver secretDriver = {
    .name = "secret",
547 548 549
    .connectNumOfSecrets = secretConnectNumOfSecrets, /* 0.7.1 */
    .connectListSecrets = secretConnectListSecrets, /* 0.7.1 */
    .connectListAllSecrets = secretConnectListAllSecrets, /* 0.10.2 */
550 551 552 553 554 555 556
    .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 */
557 558
    .connectSecretEventRegisterAny = secretConnectSecretEventRegisterAny, /* 3.0.0 */
    .connectSecretEventDeregisterAny = secretConnectSecretEventDeregisterAny, /* 3.0.0 */
559 560 561
};

static virStateDriver stateDriver = {
562
    .name = "secret",
563 564 565
    .stateInitialize = secretStateInitialize,
    .stateCleanup = secretStateCleanup,
    .stateReload = secretStateReload,
566 567 568 569 570
};

int
secretRegister(void)
{
571
    if (virSetSharedSecretDriver(&secretDriver) < 0)
572 573 574
        return -1;
    if (virRegisterStateDriver(&stateDriver) < 0)
        return -1;
575 576
    return 0;
}