secret_driver.c 13.3 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
static int
96
secretEnsureDirectory(void)
97
{
98
    if (mkdir(driver->configDir, S_IRWXU) < 0 && errno != EEXIST) {
99
        virReportSystemError(errno, _("cannot create '%s'"),
100
                             driver->configDir);
101 102 103 104 105
        return -1;
    }
    return 0;
}

106
/* Driver functions */
107 108

static int
109
secretConnectNumOfSecrets(virConnectPtr conn)
110
{
111 112 113
    if (virConnectNumOfSecretsEnsureACL(conn) < 0)
        return -1;

114 115 116
    return virSecretObjListNumOfSecrets(driver->secrets,
                                        virConnectNumOfSecretsCheckACL,
                                        conn);
117 118 119
}

static int
120 121 122
secretConnectListSecrets(virConnectPtr conn,
                         char **uuids,
                         int maxuuids)
123 124 125
{
    memset(uuids, 0, maxuuids * sizeof(*uuids));

126 127 128
    if (virConnectListSecretsEnsureACL(conn) < 0)
        return -1;

129 130
    return virSecretObjListGetUUIDs(driver->secrets, uuids, maxuuids,
                                    virConnectListSecretsCheckACL, conn);
131 132
}

133

O
Osier Yang 已提交
134
static int
135 136
secretConnectListAllSecrets(virConnectPtr conn,
                            virSecretPtr **secrets,
137 138
                            unsigned int flags)
{
O
Osier Yang 已提交
139 140
    virCheckFlags(VIR_CONNECT_LIST_SECRETS_FILTERS_ALL, -1);

141 142 143
    if (virConnectListAllSecretsEnsureACL(conn) < 0)
        return -1;

144 145 146
    return virSecretObjListExport(conn, driver->secrets, secrets,
                                  virConnectListAllSecretsCheckACL,
                                  flags);
O
Osier Yang 已提交
147 148 149
}


150
static virSecretPtr
151 152
secretLookupByUUID(virConnectPtr conn,
                   const unsigned char *uuid)
153 154
{
    virSecretPtr ret = NULL;
J
John Ferlan 已提交
155
    virSecretObjPtr secret;
156
    virSecretDefPtr def;
157

158
    if (!(secret = virSecretObjListFindByUUID(driver->secrets, uuid))) {
159 160
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(uuid, uuidstr);
161 162
        virReportError(VIR_ERR_NO_SECRET,
                       _("no secret with matching uuid '%s'"), uuidstr);
163 164 165
        goto cleanup;
    }

166 167
    def = virSecretObjGetDef(secret);
    if (virSecretLookupByUUIDEnsureACL(conn, def) < 0)
168 169
        goto cleanup;

170
    ret = virGetSecret(conn,
171 172 173
                       def->uuid,
                       def->usage_type,
                       virSecretUsageIDForDef(def));
174

175
 cleanup:
176
    virSecretObjEndAPI(&secret);
177 178 179 180 181
    return ret;
}


static virSecretPtr
182 183 184
secretLookupByUsage(virConnectPtr conn,
                    int usageType,
                    const char *usageID)
185 186
{
    virSecretPtr ret = NULL;
J
John Ferlan 已提交
187
    virSecretObjPtr secret;
188
    virSecretDefPtr def;
189

190 191
    if (!(secret = virSecretObjListFindByUsage(driver->secrets,
                                               usageType, usageID))) {
192 193
        virReportError(VIR_ERR_NO_SECRET,
                       _("no secret with matching usage '%s'"), usageID);
194 195 196
        goto cleanup;
    }

197 198
    def = virSecretObjGetDef(secret);
    if (virSecretLookupByUsageEnsureACL(conn, def) < 0)
199 200
        goto cleanup;

201
    ret = virGetSecret(conn,
202 203 204
                       def->uuid,
                       def->usage_type,
                       virSecretUsageIDForDef(def));
205

206
 cleanup:
207
    virSecretObjEndAPI(&secret);
208 209 210 211 212
    return ret;
}


static virSecretPtr
213 214
secretDefineXML(virConnectPtr conn,
                const char *xml,
215
                unsigned int flags)
216 217
{
    virSecretPtr ret = NULL;
J
John Ferlan 已提交
218
    virSecretObjPtr secret = NULL;
219 220
    virSecretDefPtr backup = NULL;
    virSecretDefPtr new_attrs;
221

222 223
    virCheckFlags(0, NULL);

224
    if (!(new_attrs = virSecretDefParseString(xml)))
225 226
        return NULL;

227 228 229
    if (virSecretDefineXMLEnsureACL(conn, new_attrs) < 0)
        goto cleanup;

230 231 232
    if (!(secret = virSecretObjListAdd(driver->secrets, new_attrs,
                                       driver->configDir, &backup)))
        goto cleanup;
233 234

    if (!new_attrs->ephemeral) {
235 236 237
        if (secretEnsureDirectory() < 0)
            goto cleanup;

238
        if (backup && backup->ephemeral) {
239
            if (virSecretObjSaveData(secret) < 0)
240 241
                goto restore_backup;
        }
242 243

        if (virSecretObjSaveConfig(secret) < 0) {
244
            if (backup && backup->ephemeral) {
245 246
                /* Undo the virSecretObjSaveData() above; ignore errors */
                virSecretObjDeleteData(secret);
247 248 249
            }
            goto restore_backup;
        }
250
    } else if (backup && !backup->ephemeral) {
251
        if (virSecretObjDeleteConfig(secret) < 0)
252
            goto restore_backup;
253 254

        virSecretObjDeleteData(secret);
255
    }
256
    /* Saved successfully - drop old values */
257 258
    virSecretDefFree(backup);

259
    ret = virGetSecret(conn,
260 261 262 263
                       new_attrs->uuid,
                       new_attrs->usage_type,
                       virSecretUsageIDForDef(new_attrs));
    new_attrs = NULL;
264 265
    goto cleanup;

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

276
 cleanup:
277
    virSecretDefFree(new_attrs);
278
    virSecretObjEndAPI(&secret);
279 280 281 282 283

    return ret;
}

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

291 292
    virCheckFlags(0, NULL);

J
John Ferlan 已提交
293
    if (!(secret = secretObjFromSecret(obj)))
294 295
        goto cleanup;

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

300
    ret = virSecretDefFormat(def);
301

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

    return ret;
}

static int
309 310 311 312
secretSetValue(virSecretPtr obj,
               const unsigned char *value,
               size_t value_size,
               unsigned int flags)
313 314 315 316
{
    int ret = -1;
    unsigned char *old_value, *new_value;
    size_t old_value_size;
J
John Ferlan 已提交
317
    virSecretObjPtr secret;
318
    virSecretDefPtr def;
319

320 321
    virCheckFlags(0, -1);

322
    if (VIR_ALLOC_N(new_value, value_size) < 0)
323 324
        return -1;

J
John Ferlan 已提交
325
    if (!(secret = secretObjFromSecret(obj)))
326 327
        goto cleanup;

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

332 333 334 335 336 337
    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;
338
    if (!def->ephemeral) {
339 340 341 342
        if (secretEnsureDirectory() < 0)
            goto cleanup;

        if (virSecretObjSaveData(secret) < 0)
343 344
            goto restore_backup;
    }
345
    /* Saved successfully - drop old value */
346 347 348 349 350 351 352 353 354
    if (old_value != NULL) {
        memset(old_value, 0, old_value_size);
        VIR_FREE(old_value);
    }
    new_value = NULL;

    ret = 0;
    goto cleanup;

355
 restore_backup:
356 357 358 359 360
    /* Error - restore previous state and free new value */
    secret->value = old_value;
    secret->value_size = old_value_size;
    memset(new_value, 0, value_size);

361
 cleanup:
362
    virSecretObjEndAPI(&secret);
363 364 365 366 367 368 369

    VIR_FREE(new_value);

    return ret;
}

static unsigned char *
370 371 372
secretGetValue(virSecretPtr obj,
               size_t *value_size,
               unsigned int flags,
373
               unsigned int internalFlags)
374 375
{
    unsigned char *ret = NULL;
J
John Ferlan 已提交
376
    virSecretObjPtr secret;
377
    virSecretDefPtr def;
378

379 380
    virCheckFlags(0, NULL);

J
John Ferlan 已提交
381
    if (!(secret = secretObjFromSecret(obj)))
382
        goto cleanup;
383

384 385
    def = virSecretObjGetDef(secret);
    if (virSecretGetValueEnsureACL(obj->conn, def) < 0)
386 387
        goto cleanup;

388
    if (secret->value == NULL) {
389 390
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(obj->uuid, uuidstr);
391 392
        virReportError(VIR_ERR_NO_SECRET,
                       _("secret '%s' does not have a value"), uuidstr);
393 394 395
        goto cleanup;
    }

396
    if ((internalFlags & VIR_SECRET_GET_VALUE_INTERNAL_CALL) == 0 &&
397
        def->private) {
398
        virReportError(VIR_ERR_INVALID_SECRET, "%s",
399
                       _("secret is private"));
400 401 402
        goto cleanup;
    }

403
    if (VIR_ALLOC_N(ret, secret->value_size) < 0)
404 405 406 407
        goto cleanup;
    memcpy(ret, secret->value, secret->value_size);
    *value_size = secret->value_size;

408
 cleanup:
409
    virSecretObjEndAPI(&secret);
410 411 412 413 414 415 416 417

    return ret;
}

static int
secretUndefine(virSecretPtr obj)
{
    int ret = -1;
J
John Ferlan 已提交
418
    virSecretObjPtr secret;
419
    virSecretDefPtr def;
420

J
John Ferlan 已提交
421
    if (!(secret = secretObjFromSecret(obj)))
422 423
        goto cleanup;

424 425
    def = virSecretObjGetDef(secret);
    if (virSecretUndefineEnsureACL(obj->conn, def) < 0)
426 427
        goto cleanup;

428
    if (virSecretObjDeleteConfig(secret) < 0)
429 430
        goto cleanup;

431 432
    virSecretObjDeleteData(secret);

433
    virSecretObjListRemove(driver->secrets, secret);
434 435 436

    ret = 0;

437
 cleanup:
438
    virSecretObjEndAPI(&secret);
439 440 441 442 443

    return ret;
}

static int
444
secretStateCleanup(void)
445
{
446
    if (!driver)
447 448
        return -1;

449
    secretDriverLock();
450

451
    virObjectUnref(driver->secrets);
452
    VIR_FREE(driver->configDir);
453

454 455 456
    secretDriverUnlock();
    virMutexDestroy(&driver->lock);
    VIR_FREE(driver);
457 458 459 460 461

    return 0;
}

static int
462 463 464
secretStateInitialize(bool privileged,
                      virStateInhibitCallback callback ATTRIBUTE_UNUSED,
                      void *opaque ATTRIBUTE_UNUSED)
465 466 467
{
    char *base = NULL;

468
    if (VIR_ALLOC(driver) < 0)
469 470
        return -1;

471 472
    if (virMutexInit(&driver->lock) < 0) {
        VIR_FREE(driver);
473 474
        return -1;
    }
475
    secretDriverLock();
476 477

    if (privileged) {
478 479
        if (VIR_STRDUP(base, SYSCONFDIR "/libvirt") < 0)
            goto error;
480
    } else {
481
        if (!(base = virGetUserConfigDirectory()))
482 483
            goto error;
    }
484
    if (virAsprintf(&driver->configDir, "%s/secrets", base) < 0)
485
        goto error;
486 487
    VIR_FREE(base);

488 489 490
    if (!(driver->secrets = virSecretObjListNew()))
        goto error;

491
    if (virSecretLoadAllConfigs(driver->secrets, driver->configDir) < 0)
492 493
        goto error;

494
    secretDriverUnlock();
495 496 497 498
    return 0;

 error:
    VIR_FREE(base);
499
    secretDriverUnlock();
500
    secretStateCleanup();
501 502 503 504
    return -1;
}

static int
505
secretStateReload(void)
506
{
507
    if (!driver)
508 509
        return -1;

510
    secretDriverLock();
511

512
    ignore_value(virSecretLoadAllConfigs(driver->secrets, driver->configDir));
513

514
    secretDriverUnlock();
515 516 517 518 519
    return 0;
}

static virSecretDriver secretDriver = {
    .name = "secret",
520 521 522
    .connectNumOfSecrets = secretConnectNumOfSecrets, /* 0.7.1 */
    .connectListSecrets = secretConnectListSecrets, /* 0.7.1 */
    .connectListAllSecrets = secretConnectListAllSecrets, /* 0.10.2 */
523 524 525 526 527 528 529
    .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 */
530 531 532
};

static virStateDriver stateDriver = {
533
    .name = "secret",
534 535 536
    .stateInitialize = secretStateInitialize,
    .stateCleanup = secretStateCleanup,
    .stateReload = secretStateReload,
537 538 539 540 541
};

int
secretRegister(void)
{
542
    if (virSetSharedSecretDriver(&secretDriver) < 0)
543 544 545
        return -1;
    if (virRegisterStateDriver(&stateDriver) < 0)
        return -1;
546 547
    return 0;
}