secret_conf.c 8.9 KB
Newer Older
1 2 3
/*
 * secret_conf.c: internal <secret> XML handling
 *
P
Phil Petty 已提交
4
 * Copyright (C) 2009, 2011 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
 *
 * Red Hat Author: Miloslav Trmač <mitr@redhat.com>
 */

#include <config.h>

#include "internal.h"
26
#include "virbuffer.h"
27
#include "datatypes.h"
28
#include "virlog.h"
29
#include "viralloc.h"
30
#include "secret_conf.h"
31
#include "virerror.h"
32
#include "virutil.h"
33
#include "virxml.h"
34
#include "viruuid.h"
35 36 37

#define VIR_FROM_THIS VIR_FROM_SECRET

S
Sage Weil 已提交
38
VIR_ENUM_IMPL(virSecretUsageType, VIR_SECRET_USAGE_TYPE_LAST,
39
              "none", "volume", "ceph", "iscsi")
40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55

void
virSecretDefFree(virSecretDefPtr def)
{
    if (def == NULL)
        return;

    VIR_FREE(def->description);
    switch (def->usage_type) {
    case VIR_SECRET_USAGE_TYPE_NONE:
        break;

    case VIR_SECRET_USAGE_TYPE_VOLUME:
        VIR_FREE(def->usage.volume);
        break;

S
Sage Weil 已提交
56 57
    case VIR_SECRET_USAGE_TYPE_CEPH:
        VIR_FREE(def->usage.ceph);
E
Eric Blake 已提交
58
        break;
S
Sage Weil 已提交
59

60 61 62 63
    case VIR_SECRET_USAGE_TYPE_ISCSI:
        VIR_FREE(def->usage.target);
        break;

64 65 66 67 68 69 70 71
    default:
        VIR_ERROR(_("unexpected secret usage type %d"), def->usage_type);
        break;
    }
    VIR_FREE(def);
}

static int
72
virSecretDefParseUsage(xmlXPathContextPtr ctxt,
73 74 75 76 77
                       virSecretDefPtr def)
{
    char *type_str;
    int type;

78
    type_str = virXPathString("string(./usage/@type)", ctxt);
79
    if (type_str == NULL) {
80 81
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("unknown secret usage type"));
82 83 84 85
        return -1;
    }
    type = virSecretUsageTypeTypeFromString(type_str);
    if (type < 0) {
86 87
        virReportError(VIR_ERR_XML_ERROR,
                       _("unknown secret usage type %s"), type_str);
88 89 90 91 92 93 94 95 96 97
        VIR_FREE(type_str);
        return -1;
    }
    VIR_FREE(type_str);
    def->usage_type = type;
    switch (def->usage_type) {
    case VIR_SECRET_USAGE_TYPE_NONE:
        break;

    case VIR_SECRET_USAGE_TYPE_VOLUME:
98
        def->usage.volume = virXPathString("string(./usage/volume)", ctxt);
99
        if (!def->usage.volume) {
100 101
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("volume usage specified, but volume path is missing"));
102 103
            return -1;
        }
104 105
        break;

S
Sage Weil 已提交
106 107 108
    case VIR_SECRET_USAGE_TYPE_CEPH:
        def->usage.ceph = virXPathString("string(./usage/name)", ctxt);
        if (!def->usage.ceph) {
109 110
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("Ceph usage specified, but name is missing"));
S
Sage Weil 已提交
111 112 113 114
            return -1;
        }
        break;

115 116 117 118 119 120 121 122 123
    case VIR_SECRET_USAGE_TYPE_ISCSI:
        def->usage.target = virXPathString("string(./usage/target)", ctxt);
        if (!def->usage.target) {
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("iSCSI usage specified, but target is missing"));
            return -1;
        }
        break;

124
    default:
125 126 127
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected secret usage type %d"),
                       def->usage_type);
128 129 130 131 132 133
        return -1;
    }
    return 0;
}

static virSecretDefPtr
134
secretXMLParseNode(xmlDocPtr xml, xmlNodePtr root)
135 136 137 138
{
    xmlXPathContextPtr ctxt = NULL;
    virSecretDefPtr def = NULL, ret = NULL;
    char *prop = NULL;
139
    char *uuidstr = NULL;
140 141

    if (!xmlStrEqual(root->name, BAD_CAST "secret")) {
142 143 144 145
        virReportError(VIR_ERR_XML_ERROR,
                       _("unexpected root element <%s>, "
                         "expecting <secret>"),
                       root->name);
146 147 148 149 150
        goto cleanup;
    }

    ctxt = xmlXPathNewContext(xml);
    if (ctxt == NULL) {
151
        virReportOOMError();
152 153 154 155 156
        goto cleanup;
    }
    ctxt->node = root;

    if (VIR_ALLOC(def) < 0) {
157
        virReportOOMError();
158 159 160
        goto cleanup;
    }

161
    prop = virXPathString("string(./@ephemeral)", ctxt);
162 163
    if (prop != NULL) {
        if (STREQ(prop, "yes"))
164
            def->ephemeral = true;
165
        else if (STREQ(prop, "no"))
166
            def->ephemeral = false;
167
        else {
168 169
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("invalid value of 'ephemeral'"));
170 171 172 173 174
            goto cleanup;
        }
        VIR_FREE(prop);
    }

175
    prop = virXPathString("string(./@private)", ctxt);
176 177 178 179 180 181
    if (prop != NULL) {
        if (STREQ(prop, "yes"))
            def->private = 1;
        else if (STREQ(prop, "no"))
            def->private = 0;
        else {
182 183
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("invalid value of 'private'"));
184 185 186 187 188
            goto cleanup;
        }
        VIR_FREE(prop);
    }

189
    uuidstr = virXPathString("string(./uuid)", ctxt);
190 191
    if (!uuidstr) {
        if (virUUIDGenerate(def->uuid)) {
192 193
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("Failed to generate UUID"));
194 195 196 197
            goto cleanup;
        }
    } else {
        if (virUUIDParse(uuidstr, def->uuid) < 0) {
198 199
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("malformed uuid element"));
200 201 202 203 204
            goto cleanup;
        }
        VIR_FREE(uuidstr);
    }

205 206
    def->description = virXPathString("string(./description)", ctxt);
    if (virXPathNode("./usage", ctxt) != NULL
207
        && virSecretDefParseUsage(ctxt, def) < 0)
208 209 210 211 212 213
        goto cleanup;
    ret = def;
    def = NULL;

 cleanup:
    VIR_FREE(prop);
P
Phil Petty 已提交
214
    VIR_FREE(uuidstr);
215 216 217 218 219 220
    virSecretDefFree(def);
    xmlXPathFreeContext(ctxt);
    return ret;
}

static virSecretDefPtr
J
Jiri Denemark 已提交
221 222
virSecretDefParse(const char *xmlStr,
                  const char *filename)
223
{
J
Jiri Denemark 已提交
224
    xmlDocPtr xml;
225 226
    virSecretDefPtr ret = NULL;

227
    if ((xml = virXMLParse(filename, xmlStr, _("(definition_of_secret)")))) {
J
Jiri Denemark 已提交
228 229
        ret = secretXMLParseNode(xml, xmlDocGetRootElement(xml));
        xmlFreeDoc(xml);
230 231 232 233 234 235
    }

    return ret;
}

virSecretDefPtr
236
virSecretDefParseString(const char *xmlStr)
237
{
238
    return virSecretDefParse(xmlStr, NULL);
239 240 241
}

virSecretDefPtr
242
virSecretDefParseFile(const char *filename)
243
{
244
    return virSecretDefParse(NULL, filename);
245 246 247
}

static int
248
virSecretDefFormatUsage(virBufferPtr buf,
249 250 251 252 253 254
                        const virSecretDefPtr def)
{
    const char *type;

    type = virSecretUsageTypeTypeToString(def->usage_type);
    if (type == NULL) {
255 256 257
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected secret usage type %d"),
                       def->usage_type);
258 259
        return -1;
    }
260
    virBufferAsprintf(buf, "  <usage type='%s'>\n", type);
261 262 263 264 265 266 267 268 269 270
    switch (def->usage_type) {
    case VIR_SECRET_USAGE_TYPE_NONE:
        break;

    case VIR_SECRET_USAGE_TYPE_VOLUME:
        if (def->usage.volume != NULL)
            virBufferEscapeString(buf, "    <volume>%s</volume>\n",
                                  def->usage.volume);
        break;

S
Sage Weil 已提交
271 272 273 274 275 276 277
    case VIR_SECRET_USAGE_TYPE_CEPH:
        if (def->usage.ceph != NULL) {
            virBufferEscapeString(buf, "    <name>%s</name>\n",
                                  def->usage.ceph);
        }
        break;

278 279 280 281 282 283 284
    case VIR_SECRET_USAGE_TYPE_ISCSI:
        if (def->usage.target != NULL) {
            virBufferEscapeString(buf, "    <target>%s</target>\n",
                                  def->usage.target);
        }
        break;

285
    default:
286 287 288
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected secret usage type %d"),
                       def->usage_type);
289 290 291 292 293 294 295 296
        return -1;
    }
    virBufferAddLit(buf, "  </usage>\n");

    return 0;
}

char *
297
virSecretDefFormat(const virSecretDefPtr def)
298 299
{
    virBuffer buf = VIR_BUFFER_INITIALIZER;
300 301
    unsigned char *uuid;
    char uuidstr[VIR_UUID_STRING_BUFLEN];
302

303
    virBufferAsprintf(&buf, "<secret ephemeral='%s' private='%s'>\n",
304 305
                      def->ephemeral ? "yes" : "no",
                      def->private ? "yes" : "no");
306 307 308 309

    uuid = def->uuid;
    virUUIDFormat(uuid, uuidstr);
    virBufferEscapeString(&buf, "  <uuid>%s</uuid>\n", uuidstr);
310 311 312 313
    if (def->description != NULL)
        virBufferEscapeString(&buf, "  <description>%s</description>\n",
                              def->description);
    if (def->usage_type != VIR_SECRET_USAGE_TYPE_NONE &&
314
        virSecretDefFormatUsage(&buf, def) < 0)
315 316 317 318 319 320 321 322 323
        goto error;
    virBufferAddLit(&buf, "</secret>\n");

    if (virBufferError(&buf))
        goto no_memory;

    return virBufferContentAndReset(&buf);

 no_memory:
324
    virReportOOMError();
325
 error:
326
    virBufferFreeAndReset(&buf);
327 328
    return NULL;
}