~ubuntu-branches/ubuntu/natty/libvirt/natty-security

« back to all changes in this revision

Viewing changes to .pc/9023-vah-require-uuid.patch/src/security/virt-aa-helper.c

  • Committer: Bazaar Package Importer
  • Author(s): Serge Hallyn
  • Date: 2011-02-23 09:05:46 UTC
  • mfrom: (1.2.8 upstream) (3.4.25 sid)
  • Revision ID: james.westby@ubuntu.com-20110223090546-4pwmrrt7h51hr3l3
Tags: 0.8.8-1ubuntu1
* Resynchronize and merge from Debian unstable. Remaining changes:
  - debian/patches:
    * 9000-delayed_iff_up_bridge.patch
    * 9001-dont_clobber_existing_bridges.patch
    * 9002-better_default_uri_virsh.patch
    * 9003-better-default-arch.patch
    * 9004-libvirtd-group-name.patch
    * 9005-increase-unix-socket-timeout.patch
    * 9006-default-config-test-case.patch
    * 9007-fix-daemon-conf-ftbfs.patch
    * 9011-move-ebtables-script.patch
    * 9014-skip-nodeinfotest.patch
    * 9020-lp545795.patch
    * 9021-fix-uint64_t.patch
  - debian/patches/series:
    * Disable qemu-disable-network.diff.patch
  - debian/control:
    * set ubuntu maintainer
    * Build-Depends:
      - swap libxen to libxen3, qemu to qemu-kvm, and open-iscsi to
        open-iscsi-utils in Build-Depends
      - remove virtualbox Build-Depends
      - add libxml2 and libapparmor-dev Build-Depends
    * convert Vcs-Git to Xs-Debian-Vcs-Git
    * libvirt-bin Depends: move netcat-openbsd, bridge-utils, dnsmasq-base
      (>= 2.46-1), and iptables from Recommends to Depends
    * libvirt-bin Recommends: move qemu to Suggests
    * libvirt-bin Suggests: add apparmor
    * libvirt0 Recommands: move lvm2 to Suggests
  - keep debian/libvirt-bin.apport
  - keep debian/libvirt-bin.cron.daily
  - debian/libvirt-bin.dirs:
    * add apparmor, cron.daily, and apport dirs
  - debian/libvirt-bin.examples:
    * add debian/libvirt-suspendonreboot
  - debian/libvirt-bin.install:
    * add /etc/apparmor.d files
    * add apport hook
  - debian/libvirt-bin.manpages:
    * add debian/libvirt-migrate-qemu-disks.1
  - debian/libvirt-bin.postinst:
    * replace libvirt groupname with libvirtd
    * add each admin user to libvirtd group
    * call apparmor_parser on usr.sbin.libvirtd and
      usr.lib.libvirt.virt-aa-helper
    * call 'libvirt-migrate-qemu-disks -a' after
      libvirt-bin has started if migrating from
      older than 0.8.3-1ubuntu1
  - debian/libvirt-bin.postrm:
    * replace libvirt groupname with libvirtd
    * remove usr.sbin.libvirtd and
      usr.lib.libvirt.virt-aa-helper
  - keep added files under debian/:
    * libvirt-bin.upstart
    * libvirt-migrate-qemu-disks
    * libvirt-migrate-qemu-disks.1
    * libvirt-suspendonreboot
    * apparmor profiles
  - debian/README.Debian:
    * add 'Apparmor Profile' section
    * add 'Disk migration' section
  - debian/rules:
    * don't build with vbox since virtualbox-ose is in universe
    * add --with-apparmor to DEB_CONFIGURE_EXTRA_FLAGS
    * set DEB_DH_INSTALLINIT_ARGS to '--upstart-only'
    * set DEB_MAKE_CHECK_TARGET to 'check'
    * remove unneeded binary-install/libvirt-bin:: and clean::
      sections (they only deal with sysvinit stuff)
    * add build/libvirt-bin:: section to install
      - apparmor files
      - apport hooks
      - libvirt-migrate-qemu-disks
* The following Ubuntu packaging changes occurred during the divergence
  between Debian and Ubuntu. These changes are not new, but included here
  for completeness: (0.8.5-0ubuntu1 - 0.8.5-0ubuntu5):
  - Have upstart job source /etc/default/libvirt-bin.  This is only a
    temporary fix until upstart provides proper default override support
    through /etc/init/libvirt-bin.override (or any other mechanism).
    (LP: 708172)
  - debian/apparmor/usr.sbin.libvirtd: use PUx instead of Ux for executables
    (LP: 573315)
  - Rebuild with python 2.7 as the python default.
  - debian/libvirt-bin.cron.daily: use shell globbing to enumerate xml files.
    Based on patch thanks to Henryk Plötz (LP: 655176)
* Dropped the following patches included/fixed upstream:
  - 9010-dont-disable-ipv6.patch
  - 9022-build-cleanup-declaration-of-xen-tests.patch
  - 9023-vah-require-uuid.patch
  - 9009-autodetect-nc-params.patch
    * rolled into Debian's
      Autodetect-if-the-remote-nc-command-supports-the-q-o.patch
* Updated the following patches:
  - 9011-move-ebtables-script.patch:
    * LOCALSTATEDIR is defined in configmake.h
  - 9000-9006: added DEP-3 tags
  - 9002-better_default_uri_virsh.patch: updated (context changed)
* New patches:
  - 9022-drop-booton-when-kernel-specified.patch (LP: #720426)
  - 9023-fix-lxc-console-hangup.patch (LP: #668369)
  - 9024-skip-broken-commandtest.patch
* debian/patches/series:
  - don't apply Disable-CHECKSUM-rule.patch: our iptables can do this
  - don't apply Debian-specific Debianize-libvirt-guests.patch

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
 
2
 
/*
3
 
 * virt-aa-helper: wrapper program used by AppArmor security driver.
4
 
 * Copyright (C) 2009-2010 Canonical Ltd.
5
 
 *
6
 
 * See COPYING.LIB for the License of this software
7
 
 *
8
 
 * Author:
9
 
 *   Jamie Strandboge <jamie@canonical.com>
10
 
 *
11
 
 */
12
 
 
13
 
#include <config.h>
14
 
 
15
 
#include <stdio.h>
16
 
#include <stdlib.h>
17
 
#include <string.h>
18
 
#include <stdarg.h>
19
 
#include <unistd.h>
20
 
#include <errno.h>
21
 
#include <sys/types.h>
22
 
#include <sys/stat.h>
23
 
#include <fcntl.h>
24
 
#include <getopt.h>
25
 
#include <stdbool.h>
26
 
#include <sys/utsname.h>
27
 
 
28
 
#include "internal.h"
29
 
#include "buf.h"
30
 
#include "util.h"
31
 
#include "memory.h"
32
 
 
33
 
#include "security_driver.h"
34
 
#include "security_apparmor.h"
35
 
#include "domain_conf.h"
36
 
#include "xml.h"
37
 
#include "uuid.h"
38
 
#include "hostusb.h"
39
 
#include "pci.h"
40
 
 
41
 
static char *progname;
42
 
 
43
 
typedef struct {
44
 
    bool allowDiskFormatProbing;
45
 
    char uuid[PROFILE_NAME_SIZE];       /* UUID of vm */
46
 
    bool dryrun;                /* dry run */
47
 
    char cmd;                   /* 'c'   create
48
 
                                 * 'a'   add (load)
49
 
                                 * 'r'   replace
50
 
                                 * 'R'   remove */
51
 
    char *files;                /* list of files */
52
 
    virDomainDefPtr def;        /* VM definition */
53
 
    virCapsPtr caps;            /* VM capabilities */
54
 
    char *hvm;                  /* type of hypervisor (eg hvm, xen) */
55
 
    char *arch;                 /* machine architecture */
56
 
    int bits;                   /* bits in the guest */
57
 
    char *newfile;              /* newly added file */
58
 
    bool append;                /* append to .files instead of rewrite */
59
 
} vahControl;
60
 
 
61
 
static int
62
 
vahDeinit(vahControl * ctl)
63
 
{
64
 
    if (ctl == NULL)
65
 
        return -1;
66
 
 
67
 
    VIR_FREE(ctl->def);
68
 
    virCapabilitiesFree(ctl->caps);
69
 
    VIR_FREE(ctl->files);
70
 
    VIR_FREE(ctl->hvm);
71
 
    VIR_FREE(ctl->arch);
72
 
    VIR_FREE(ctl->newfile);
73
 
 
74
 
    return 0;
75
 
}
76
 
 
77
 
/*
78
 
 * Print usage
79
 
 */
80
 
static void
81
 
vah_usage(void)
82
 
{
83
 
    fprintf(stdout, "\n%s [options] [< def.xml]\n\n"
84
 
            "  Options:\n"
85
 
            "    -a | --add                     load profile\n"
86
 
            "    -c | --create                  create profile from template\n"
87
 
            "    -D | --delete                  unload and delete profile\n"
88
 
            "    -f | --add-file <file>         add file to profile\n"
89
 
            "    -F | --append-file <file>      append file to profile\n"
90
 
            "    -r | --replace                 reload profile\n"
91
 
            "    -R | --remove                  unload profile\n"
92
 
            "    -h | --help                    this help\n"
93
 
            "    -u | --uuid <uuid>             uuid (profile name)\n"
94
 
            "\n", progname);
95
 
 
96
 
    fprintf(stdout, "This command is intended to be used by libvirtd "
97
 
            "and not used directly.\n");
98
 
    return;
99
 
}
100
 
 
101
 
static void
102
 
vah_error(vahControl * ctl, int doexit, const char *str)
103
 
{
104
 
    fprintf(stderr, _("%s: error: %s\n"), progname, str);
105
 
 
106
 
    if (doexit) {
107
 
        if (ctl != NULL)
108
 
            vahDeinit(ctl);
109
 
        exit(EXIT_FAILURE);
110
 
    }
111
 
}
112
 
 
113
 
static void
114
 
vah_warning(const char *str)
115
 
{
116
 
    fprintf(stderr, _("%s: warning: %s\n"), progname, str);
117
 
}
118
 
 
119
 
static void
120
 
vah_info(const char *str)
121
 
{
122
 
    fprintf(stderr, _("%s:\n%s\n"), progname, str);
123
 
}
124
 
 
125
 
/*
126
 
 * Replace @oldstr in @orig with @repstr
127
 
 * @len is number of bytes allocated for @orig. Assumes @orig, @oldstr and
128
 
 * @repstr are null terminated
129
 
 */
130
 
static int
131
 
replace_string(char *orig, const size_t len, const char *oldstr,
132
 
               const char *repstr)
133
 
{
134
 
    int idx;
135
 
    char *pos = NULL;
136
 
    char *tmp = NULL;
137
 
 
138
 
    if ((pos = strstr(orig, oldstr)) == NULL) {
139
 
        vah_error(NULL, 0, "could not find replacement string");
140
 
        return -1;
141
 
    }
142
 
 
143
 
    if (VIR_ALLOC_N(tmp, len) < 0) {
144
 
        vah_error(NULL, 0, "could not allocate memory for string");
145
 
        return -1;
146
 
    }
147
 
    tmp[0] = '\0';
148
 
 
149
 
    idx = abs(pos - orig);
150
 
 
151
 
    /* copy everything up to oldstr */
152
 
    strncat(tmp, orig, idx);
153
 
 
154
 
    /* add the replacement string */
155
 
    if (strlen(tmp) + strlen(repstr) > len - 1) {
156
 
        vah_error(NULL, 0, "not enough space in target buffer");
157
 
        VIR_FREE(tmp);
158
 
        return -1;
159
 
    }
160
 
    strcat(tmp, repstr);
161
 
 
162
 
    /* add everything after oldstr */
163
 
    if (strlen(tmp) + strlen(orig) - (idx + strlen(oldstr)) > len - 1) {
164
 
        vah_error(NULL, 0, "not enough space in target buffer");
165
 
        VIR_FREE(tmp);
166
 
        return -1;
167
 
    }
168
 
    strncat(tmp, orig + idx + strlen(oldstr),
169
 
            strlen(orig) - (idx + strlen(oldstr)));
170
 
 
171
 
    if (virStrcpy(orig, tmp, len) == NULL) {
172
 
        vah_error(NULL, 0, "error replacing string");
173
 
        VIR_FREE(tmp);
174
 
        return -1;
175
 
    }
176
 
    VIR_FREE(tmp);
177
 
 
178
 
    return 0;
179
 
}
180
 
 
181
 
/*
182
 
 * run an apparmor_parser command
183
 
 */
184
 
static int
185
 
parserCommand(const char *profile_name, const char cmd)
186
 
{
187
 
    char flag[3];
188
 
    char profile[PATH_MAX];
189
 
    int status;
190
 
    int ret;
191
 
 
192
 
    if (strchr("arR", cmd) == NULL) {
193
 
        vah_error(NULL, 0, "invalid flag");
194
 
        return -1;
195
 
    }
196
 
 
197
 
    snprintf(flag, 3, "-%c", cmd);
198
 
 
199
 
    if (snprintf(profile, PATH_MAX, "%s/%s",
200
 
                 APPARMOR_DIR "/libvirt", profile_name) > PATH_MAX - 1) {
201
 
        vah_error(NULL, 0, "profile name exceeds maximum length");
202
 
        return -1;
203
 
    }
204
 
 
205
 
    if (!virFileExists(profile)) {
206
 
        vah_error(NULL, 0, "profile does not exist");
207
 
        return -1;
208
 
    } else {
209
 
        const char * const argv[] = {
210
 
            "/sbin/apparmor_parser", flag, profile, NULL
211
 
        };
212
 
        if ((ret = virRun(argv, &status)) != 0 ||
213
 
            (WIFEXITED(status) && WEXITSTATUS(status) != 0)) {
214
 
            if (ret != 0) {
215
 
                vah_error(NULL, 0, "failed to run apparmor_parser");
216
 
                return -1;
217
 
            } else if (cmd == 'R' && WIFEXITED(status) && WEXITSTATUS(status) == 234) {
218
 
                vah_warning("unable to unload already unloaded profile (non-fatal)");
219
 
            } else {
220
 
                vah_error(NULL, 0, "apparmor_parser exited with error");
221
 
                return -1;
222
 
            }
223
 
        }
224
 
    }
225
 
 
226
 
    return 0;
227
 
}
228
 
 
229
 
/*
230
 
 * Update the dynamic files
231
 
 */
232
 
static int
233
 
update_include_file(const char *include_file, const char *included_files,
234
 
                    bool append)
235
 
{
236
 
    int rc = -1;
237
 
    int plen, flen;
238
 
    int fd;
239
 
    char *pcontent = NULL;
240
 
    char *existing = NULL;
241
 
    const char *warning =
242
 
         "# DO NOT EDIT THIS FILE DIRECTLY. IT IS MANAGED BY LIBVIRT.\n";
243
 
 
244
 
    if (virFileExists(include_file)) {
245
 
        flen = virFileReadAll(include_file, MAX_FILE_LEN, &existing);
246
 
        if (flen < 0)
247
 
            return rc;
248
 
    }
249
 
 
250
 
    if (append && virFileExists(include_file)) {
251
 
        if (virAsprintf(&pcontent, "%s%s", existing, included_files) == -1) {
252
 
            vah_error(NULL, 0, "could not allocate memory for profile");
253
 
            goto clean;
254
 
        }
255
 
    } else {
256
 
        if (virAsprintf(&pcontent, "%s%s", warning, included_files) == -1) {
257
 
            vah_error(NULL, 0, "could not allocate memory for profile");
258
 
            goto clean;
259
 
        }
260
 
    }
261
 
 
262
 
    plen = strlen(pcontent);
263
 
    if (plen > MAX_FILE_LEN) {
264
 
        vah_error(NULL, 0, "invalid length for new profile");
265
 
        goto clean;
266
 
    }
267
 
 
268
 
    /* only update the disk profile if it is different */
269
 
    if (flen > 0 && flen == plen && STREQLEN(existing, pcontent, plen)) {
270
 
        rc = 0;
271
 
        goto clean;
272
 
    }
273
 
 
274
 
    /* write the file */
275
 
    if ((fd = open(include_file, O_CREAT | O_TRUNC | O_WRONLY, 0644)) == -1) {
276
 
        vah_error(NULL, 0, "failed to create include file");
277
 
        goto clean;
278
 
    }
279
 
 
280
 
    if (safewrite(fd, pcontent, plen) < 0) { /* don't write the '\0' */
281
 
        close(fd);
282
 
        vah_error(NULL, 0, "failed to write to profile");
283
 
        goto clean;
284
 
    }
285
 
 
286
 
    if (close(fd) != 0) {
287
 
        vah_error(NULL, 0, "failed to close or write to profile");
288
 
        goto clean;
289
 
    }
290
 
    rc = 0;
291
 
 
292
 
  clean:
293
 
    VIR_FREE(pcontent);
294
 
    VIR_FREE(existing);
295
 
 
296
 
    return rc;
297
 
}
298
 
 
299
 
/*
300
 
 * Create a profile based on a template
301
 
 */
302
 
static int
303
 
create_profile(const char *profile, const char *profile_name,
304
 
               const char *profile_files)
305
 
{
306
 
    char template[PATH_MAX];
307
 
    char *tcontent = NULL;
308
 
    char *pcontent = NULL;
309
 
    char *replace_name = NULL;
310
 
    char *replace_files = NULL;
311
 
    const char *template_name = "\nprofile LIBVIRT_TEMPLATE";
312
 
    const char *template_end = "\n}";
313
 
    int tlen, plen;
314
 
    int fd;
315
 
    int rc = -1;
316
 
 
317
 
    if (virFileExists(profile)) {
318
 
        vah_error(NULL, 0, "profile exists");
319
 
        goto end;
320
 
    }
321
 
 
322
 
    if (snprintf(template, PATH_MAX, "%s/TEMPLATE",
323
 
                 APPARMOR_DIR "/libvirt") > PATH_MAX - 1) {
324
 
        vah_error(NULL, 0, "template name exceeds maximum length");
325
 
        goto end;
326
 
    }
327
 
 
328
 
    if (!virFileExists(template)) {
329
 
        vah_error(NULL, 0, "template does not exist");
330
 
        goto end;
331
 
    }
332
 
 
333
 
    if ((tlen = virFileReadAll(template, MAX_FILE_LEN, &tcontent)) < 0) {
334
 
        vah_error(NULL, 0, "failed to read AppArmor template");
335
 
        goto end;
336
 
    }
337
 
 
338
 
    if (strstr(tcontent, template_name) == NULL) {
339
 
        vah_error(NULL, 0, "no replacement string in template");
340
 
        goto clean_tcontent;
341
 
    }
342
 
 
343
 
    if (strstr(tcontent, template_end) == NULL) {
344
 
        vah_error(NULL, 0, "no replacement string in template");
345
 
        goto clean_tcontent;
346
 
    }
347
 
 
348
 
    /* '\nprofile <profile_name>\0' */
349
 
    if (virAsprintf(&replace_name, "\nprofile %s", profile_name) == -1) {
350
 
        vah_error(NULL, 0, "could not allocate memory for profile name");
351
 
        goto clean_tcontent;
352
 
    }
353
 
 
354
 
    /* '\n<profile_files>\n}\0' */
355
 
    if (virAsprintf(&replace_files, "\n%s\n}", profile_files) == -1) {
356
 
        vah_error(NULL, 0, "could not allocate memory for profile files");
357
 
        VIR_FREE(replace_name);
358
 
        goto clean_tcontent;
359
 
    }
360
 
 
361
 
    plen = tlen + strlen(replace_name) - strlen(template_name) +
362
 
           strlen(replace_files) - strlen(template_end) + 1;
363
 
    if (plen > MAX_FILE_LEN || plen < tlen) {
364
 
        vah_error(NULL, 0, "invalid length for new profile");
365
 
        goto clean_replace;
366
 
    }
367
 
 
368
 
    if (VIR_ALLOC_N(pcontent, plen) < 0) {
369
 
        vah_error(NULL, 0, "could not allocate memory for profile");
370
 
        goto clean_replace;
371
 
    }
372
 
    pcontent[0] = '\0';
373
 
    strcpy(pcontent, tcontent);
374
 
 
375
 
    if (replace_string(pcontent, plen, template_name, replace_name) < 0)
376
 
        goto clean_all;
377
 
 
378
 
    if (replace_string(pcontent, plen, template_end, replace_files) < 0)
379
 
        goto clean_all;
380
 
 
381
 
    /* write the file */
382
 
    if ((fd = open(profile, O_CREAT | O_EXCL | O_WRONLY, 0644)) == -1) {
383
 
        vah_error(NULL, 0, "failed to create profile");
384
 
        goto clean_all;
385
 
    }
386
 
 
387
 
    if (safewrite(fd, pcontent, plen - 1) < 0) { /* don't write the '\0' */
388
 
        close(fd);
389
 
        vah_error(NULL, 0, "failed to write to profile");
390
 
        goto clean_all;
391
 
    }
392
 
 
393
 
    if (close(fd) != 0) {
394
 
        vah_error(NULL, 0, "failed to close or write to profile");
395
 
        goto clean_all;
396
 
    }
397
 
    rc = 0;
398
 
 
399
 
  clean_all:
400
 
    VIR_FREE(pcontent);
401
 
  clean_replace:
402
 
    VIR_FREE(replace_name);
403
 
    VIR_FREE(replace_files);
404
 
  clean_tcontent:
405
 
    VIR_FREE(tcontent);
406
 
  end:
407
 
    return rc;
408
 
}
409
 
 
410
 
/*
411
 
 * Load an existing profile
412
 
 */
413
 
static int
414
 
parserLoad(const char *profile_name)
415
 
{
416
 
    return parserCommand(profile_name, 'a');
417
 
}
418
 
 
419
 
/*
420
 
 * Remove an existing profile
421
 
 */
422
 
static int
423
 
parserRemove(const char *profile_name)
424
 
{
425
 
    return parserCommand(profile_name, 'R');
426
 
}
427
 
 
428
 
/*
429
 
 * Replace an existing profile
430
 
 */
431
 
static int
432
 
parserReplace(const char *profile_name)
433
 
{
434
 
    return parserCommand(profile_name, 'r');
435
 
}
436
 
 
437
 
static int
438
 
valid_uuid(const char *uuid)
439
 
{
440
 
    unsigned char rawuuid[VIR_UUID_BUFLEN];
441
 
 
442
 
    if (strlen(uuid) != PROFILE_NAME_SIZE - 1)
443
 
        return -1;
444
 
 
445
 
    if (!STRPREFIX(uuid, AA_PREFIX))
446
 
        return -1;
447
 
 
448
 
    if (virUUIDParse(uuid + strlen(AA_PREFIX), rawuuid) < 0)
449
 
        return -1;
450
 
 
451
 
    return 0;
452
 
}
453
 
 
454
 
static int
455
 
valid_name(const char *name)
456
 
{
457
 
    /* just try to filter out any dangerous characters in the name that can be
458
 
     * used to subvert the profile */
459
 
    const char *bad = " /[]*";
460
 
 
461
 
    if (strlen(name) == 0 || strlen(name) > PATH_MAX - 1)
462
 
        return -1;
463
 
 
464
 
    if (strcspn(name, bad) != strlen(name))
465
 
        return -1;
466
 
 
467
 
    return 0;
468
 
}
469
 
 
470
 
/* see if one of the strings in arr starts with str */
471
 
static int
472
 
array_starts_with(const char *str, const char * const *arr, const long size)
473
 
{
474
 
    int i;
475
 
    for (i = 0; i < size; i++) {
476
 
        if (strlen(str) < strlen(arr[i]))
477
 
            continue;
478
 
 
479
 
        if (STRPREFIX(str, arr[i]))
480
 
            return 0;
481
 
    }
482
 
    return 1;
483
 
}
484
 
 
485
 
/*
486
 
 * Don't allow access to special files or restricted paths such as /bin, /sbin,
487
 
 * /usr/bin, /usr/sbin and /etc. This is in an effort to prevent read/write
488
 
 * access to system files which could be used to elevate privileges. This is a
489
 
 * safety measure in case libvirtd is under a restrictive profile and is
490
 
 * subverted and trying to escape confinement.
491
 
 *
492
 
 * Note that we cannot exclude block devices because they are valid devices.
493
 
 * The TEMPLATE file can be adjusted to explicitly disallow these if needed.
494
 
 *
495
 
 * RETURN: -1 on error, 0 if ok, 1 if blocked
496
 
 */
497
 
static int
498
 
valid_path(const char *path, const bool readonly)
499
 
{
500
 
    struct stat sb;
501
 
    int npaths, opaths;
502
 
    const char * const restricted[] = {
503
 
        "/bin/",
504
 
        "/etc/",
505
 
        "/lib",
506
 
        "/lost+found/",
507
 
        "/proc/",
508
 
        "/sbin/",
509
 
        "/selinux/",
510
 
        "/sys/",
511
 
        "/usr/bin/",
512
 
        "/usr/lib",
513
 
        "/usr/sbin/",
514
 
        "/usr/share/",
515
 
        "/usr/local/bin/",
516
 
        "/usr/local/etc/",
517
 
        "/usr/local/lib",
518
 
        "/usr/local/sbin/"
519
 
    };
520
 
    /* these paths are ok for readonly, but not read/write */
521
 
    const char * const restricted_rw[] = {
522
 
        "/boot/",
523
 
        "/vmlinuz",
524
 
        "/initrd",
525
 
        "/initrd.img"
526
 
    };
527
 
    /* override the above with these */
528
 
    const char * const override[] = {
529
 
        "/sys/devices/pci"      /* for hostdev pci devices */
530
 
    };
531
 
 
532
 
    if (path == NULL || strlen(path) > PATH_MAX - 1) {
533
 
        vah_error(NULL, 0, "bad pathname");
534
 
        return -1;
535
 
    }
536
 
 
537
 
    /* Don't allow double quotes, since we use them to quote the filename
538
 
     * and this will confuse the apparmor parser.
539
 
     */
540
 
    if (strchr(path, '"') != NULL)
541
 
        return 1;
542
 
 
543
 
    /* Require an absolute path */
544
 
    if (STRNEQLEN(path, "/", 1))
545
 
        return 1;
546
 
 
547
 
    if (!virFileExists(path))
548
 
        vah_warning("path does not exist, skipping file type checks");
549
 
    else {
550
 
        if (stat(path, &sb) == -1)
551
 
            return -1;
552
 
 
553
 
        switch (sb.st_mode & S_IFMT) {
554
 
            case S_IFDIR:
555
 
                return 1;
556
 
                break;
557
 
            case S_IFIFO:
558
 
                return 1;
559
 
                break;
560
 
            case S_IFSOCK:
561
 
                return 1;
562
 
                break;
563
 
            default:
564
 
                break;
565
 
        }
566
 
    }
567
 
 
568
 
    opaths = sizeof(override)/sizeof *(override);
569
 
 
570
 
    npaths = sizeof(restricted)/sizeof *(restricted);
571
 
    if (array_starts_with(path, restricted, npaths) == 0 &&
572
 
        array_starts_with(path, override, opaths) != 0)
573
 
            return 1;
574
 
 
575
 
    npaths = sizeof(restricted_rw)/sizeof *(restricted_rw);
576
 
    if (!readonly) {
577
 
        if (array_starts_with(path, restricted_rw, npaths) == 0)
578
 
            return 1;
579
 
    }
580
 
 
581
 
    return 0;
582
 
}
583
 
 
584
 
/* Called from SAX on parsing errors in the XML. */
585
 
static void
586
 
catchXMLError (void *ctx, const char *msg ATTRIBUTE_UNUSED, ...)
587
 
{
588
 
    xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
589
 
 
590
 
    if (ctxt) {
591
 
        if (virGetLastError() == NULL &&
592
 
            ctxt->lastError.level == XML_ERR_FATAL &&
593
 
            ctxt->lastError.message != NULL) {
594
 
                char *err_str = NULL;
595
 
                if (virAsprintf(&err_str, "XML error at line %d: %s",
596
 
                                ctxt->lastError.line,
597
 
                                ctxt->lastError.message) == -1)
598
 
                    vah_error(NULL, 0, "Could not get XML error");
599
 
                else {
600
 
                    vah_error(NULL, 0, err_str);
601
 
                    VIR_FREE(err_str);
602
 
                }
603
 
        }
604
 
    }
605
 
}
606
 
 
607
 
/*
608
 
 * Parse the xml we received to fill in the following:
609
 
 * ctl->hvm
610
 
 * ctl->arch
611
 
 * ctl->bits
612
 
 *
613
 
 * These are suitable for setting up a virCapsPtr
614
 
 */
615
 
static int
616
 
caps_mockup(vahControl * ctl, const char *xmlStr)
617
 
{
618
 
    int rc = -1;
619
 
    xmlParserCtxtPtr pctxt = NULL;
620
 
    xmlDocPtr xml = NULL;
621
 
    xmlXPathContextPtr ctxt = NULL;
622
 
    xmlNodePtr root;
623
 
 
624
 
    /* Set up a parser context so we can catch the details of XML errors. */
625
 
    pctxt = xmlNewParserCtxt ();
626
 
    if (!pctxt || !pctxt->sax)
627
 
        goto cleanup;
628
 
    pctxt->sax->error = catchXMLError;
629
 
 
630
 
    xml = xmlCtxtReadDoc (pctxt, BAD_CAST xmlStr, "domain.xml", NULL,
631
 
                          XML_PARSE_NOENT | XML_PARSE_NONET |
632
 
                          XML_PARSE_NOWARNING);
633
 
    if (!xml) {
634
 
        if (virGetLastError() == NULL)
635
 
            vah_error(NULL, 0, "failed to parse xml document");
636
 
        goto cleanup;
637
 
    }
638
 
 
639
 
    if ((root = xmlDocGetRootElement(xml)) == NULL) {
640
 
        vah_error(NULL, 0, "missing root element");
641
 
        goto cleanup;
642
 
    }
643
 
 
644
 
    if (!xmlStrEqual(root->name, BAD_CAST "domain")) {
645
 
        vah_error(NULL, 0, "incorrect root element");
646
 
        goto cleanup;
647
 
    }
648
 
 
649
 
    if ((ctxt = xmlXPathNewContext(xml)) == NULL) {
650
 
        vah_error(ctl, 0, "could not allocate memory");
651
 
        goto cleanup;
652
 
    }
653
 
    ctxt->node = root;
654
 
 
655
 
    ctl->hvm = virXPathString("string(./os/type[1])", ctxt);
656
 
    if (!ctl->hvm || STRNEQ(ctl->hvm, "hvm")) {
657
 
        vah_error(ctl, 0, "os.type is not 'hvm'");
658
 
        goto cleanup;
659
 
    }
660
 
    ctl->arch = virXPathString("string(./os/type[1]/@arch)", ctxt);
661
 
    if (!ctl->arch) {
662
 
        /* The XML we are given should have an arch, but in case it doesn't,
663
 
         * just use the host's arch.
664
 
         */
665
 
        struct utsname utsname;
666
 
 
667
 
        /* Really, this never fails - look at the man-page. */
668
 
        uname (&utsname);
669
 
        if ((ctl->arch = strdup(utsname.machine)) == NULL) {
670
 
            vah_error(ctl, 0, "could not allocate memory");
671
 
            goto cleanup;
672
 
        }
673
 
    }
674
 
    if (STREQ(ctl->arch, "x86_64"))
675
 
        ctl->bits = 64;
676
 
    else
677
 
        ctl->bits = 32;
678
 
 
679
 
    rc = 0;
680
 
 
681
 
  cleanup:
682
 
    xmlFreeParserCtxt (pctxt);
683
 
    xmlFreeDoc (xml);
684
 
    xmlXPathFreeContext(ctxt);
685
 
 
686
 
    return rc;
687
 
}
688
 
 
689
 
static int
690
 
get_definition(vahControl * ctl, const char *xmlStr)
691
 
{
692
 
    int rc = -1;
693
 
    virCapsGuestPtr guest;  /* this is freed when caps is freed */
694
 
 
695
 
    /*
696
 
     * mock up some capabilities. We don't currently use these explicitly,
697
 
     * but need them for virDomainDefParseString().
698
 
     */
699
 
    if (caps_mockup(ctl, xmlStr) != 0)
700
 
        goto exit;
701
 
 
702
 
    if ((ctl->caps = virCapabilitiesNew(ctl->arch, 1, 1)) == NULL) {
703
 
        vah_error(ctl, 0, "could not allocate memory");
704
 
        goto exit;
705
 
    }
706
 
 
707
 
    if ((guest = virCapabilitiesAddGuest(ctl->caps,
708
 
                                         ctl->hvm,
709
 
                                         ctl->arch,
710
 
                                         ctl->bits,
711
 
                                         NULL,
712
 
                                         NULL,
713
 
                                         0,
714
 
                                         NULL)) == NULL) {
715
 
        vah_error(ctl, 0, "could not allocate memory");
716
 
        goto exit;
717
 
    }
718
 
 
719
 
    ctl->def = virDomainDefParseString(ctl->caps, xmlStr,
720
 
                                       VIR_DOMAIN_XML_INACTIVE);
721
 
    if (ctl->def == NULL) {
722
 
        vah_error(ctl, 0, "could not parse XML");
723
 
        goto exit;
724
 
    }
725
 
 
726
 
    if (!ctl->def->name) {
727
 
        vah_error(ctl, 0, "could not find name in XML");
728
 
        goto exit;
729
 
    }
730
 
 
731
 
    if (valid_name(ctl->def->name) != 0) {
732
 
        vah_error(ctl, 0, "bad name");
733
 
        goto exit;
734
 
    }
735
 
 
736
 
    rc = 0;
737
 
 
738
 
  exit:
739
 
    return rc;
740
 
}
741
 
 
742
 
static int
743
 
vah_add_file(virBufferPtr buf, const char *path, const char *perms)
744
 
{
745
 
    char *tmp = NULL;
746
 
    int rc = -1;
747
 
    bool readonly = true;
748
 
 
749
 
    if (path == NULL)
750
 
        return rc;
751
 
 
752
 
    /* Skip files without an absolute path. Not having one confuses the
753
 
     * apparmor parser and this also ensures things like tcp consoles don't
754
 
     * get added to the profile.
755
 
     */
756
 
    if (STRNEQLEN(path, "/", 1)) {
757
 
        vah_warning(path);
758
 
        vah_warning("  skipped non-absolute path");
759
 
        return 0;
760
 
    }
761
 
 
762
 
    if (virFileExists(path)) {
763
 
        if ((tmp = realpath(path, NULL)) == NULL) {
764
 
            vah_error(NULL, 0, path);
765
 
            vah_error(NULL, 0, "  could not find realpath for disk");
766
 
            return rc;
767
 
        }
768
 
    } else
769
 
        if ((tmp = strdup(path)) == NULL)
770
 
            return rc;
771
 
 
772
 
    if (strchr(perms, 'w') != NULL)
773
 
        readonly = false;
774
 
 
775
 
    rc = valid_path(tmp, readonly);
776
 
    if (rc != 0) {
777
 
        if (rc > 0) {
778
 
            vah_error(NULL, 0, path);
779
 
            vah_error(NULL, 0, "  skipped restricted file");
780
 
        }
781
 
        goto clean;
782
 
    }
783
 
 
784
 
    virBufferVSprintf(buf, "  \"%s\" %s,\n", tmp, perms);
785
 
    if (readonly) {
786
 
        virBufferVSprintf(buf, "  # don't audit writes to readonly files\n");
787
 
        virBufferVSprintf(buf, "  deny \"%s\" w,\n", tmp);
788
 
    }
789
 
 
790
 
  clean:
791
 
    VIR_FREE(tmp);
792
 
 
793
 
    return rc;
794
 
}
795
 
 
796
 
static int
797
 
file_iterate_hostdev_cb(usbDevice *dev ATTRIBUTE_UNUSED,
798
 
                        const char *file, void *opaque)
799
 
{
800
 
    virBufferPtr buf = opaque;
801
 
    return vah_add_file(buf, file, "rw");
802
 
}
803
 
 
804
 
static int
805
 
file_iterate_pci_cb(pciDevice *dev ATTRIBUTE_UNUSED,
806
 
                        const char *file, void *opaque)
807
 
{
808
 
    virBufferPtr buf = opaque;
809
 
    return vah_add_file(buf, file, "rw");
810
 
}
811
 
 
812
 
static int
813
 
add_file_path(virDomainDiskDefPtr disk,
814
 
              const char *path,
815
 
              size_t depth,
816
 
              void *opaque)
817
 
{
818
 
    virBufferPtr buf = opaque;
819
 
    int ret;
820
 
 
821
 
    if (depth == 0) {
822
 
        if (disk->readonly)
823
 
            ret = vah_add_file(buf, path, "r");
824
 
        else
825
 
            ret = vah_add_file(buf, path, "rw");
826
 
    } else {
827
 
        ret = vah_add_file(buf, path, "r");
828
 
    }
829
 
 
830
 
    if (ret != 0)
831
 
        ret = -1;
832
 
 
833
 
    return ret;
834
 
}
835
 
 
836
 
 
837
 
static int
838
 
get_files(vahControl * ctl)
839
 
{
840
 
    virBuffer buf = VIR_BUFFER_INITIALIZER;
841
 
    int rc = -1;
842
 
    int i;
843
 
    char *uuid;
844
 
    char uuidstr[VIR_UUID_STRING_BUFLEN];
845
 
 
846
 
    /* verify uuid is same as what we were given on the command line */
847
 
    virUUIDFormat(ctl->def->uuid, uuidstr);
848
 
    if (virAsprintf(&uuid, "%s%s", AA_PREFIX, uuidstr) == -1) {
849
 
        vah_error(ctl, 0, "could not allocate memory");
850
 
        return rc;
851
 
    }
852
 
 
853
 
    if (STRNEQ(uuid, ctl->uuid)) {
854
 
        vah_error(ctl, 0, "given uuid does not match XML uuid");
855
 
        goto clean;
856
 
    }
857
 
 
858
 
    for (i = 0; i < ctl->def->ndisks; i++) {
859
 
        /* XXX passing ignoreOpenFailure = true to get back to the behavior
860
 
         * from before using virDomainDiskDefForeachPath. actually we should
861
 
         * be passing ignoreOpenFailure = false and handle open errors more
862
 
         * careful than just ignoring them */
863
 
        int ret = virDomainDiskDefForeachPath(ctl->def->disks[i],
864
 
                                              ctl->allowDiskFormatProbing,
865
 
                                              true,
866
 
                                              add_file_path,
867
 
                                              &buf);
868
 
        if (ret != 0)
869
 
            goto clean;
870
 
    }
871
 
 
872
 
    for (i = 0; i < ctl->def->nserials; i++)
873
 
        if (ctl->def->serials[i] &&
874
 
            (ctl->def->serials[i]->type == VIR_DOMAIN_CHR_TYPE_PTY ||
875
 
             ctl->def->serials[i]->type == VIR_DOMAIN_CHR_TYPE_DEV ||
876
 
             ctl->def->serials[i]->type == VIR_DOMAIN_CHR_TYPE_FILE ||
877
 
             ctl->def->serials[i]->type == VIR_DOMAIN_CHR_TYPE_PIPE) &&
878
 
            ctl->def->serials[i]->data.file.path)
879
 
            if (vah_add_file(&buf,
880
 
                             ctl->def->serials[i]->data.file.path, "rw") != 0)
881
 
                goto clean;
882
 
 
883
 
    if (ctl->def->console && ctl->def->console->data.file.path)
884
 
        if (vah_add_file(&buf, ctl->def->console->data.file.path, "rw") != 0)
885
 
            goto clean;
886
 
 
887
 
    for (i = 0 ; i < ctl->def->nparallels; i++)
888
 
        if (ctl->def->parallels[i] &&
889
 
            (ctl->def->parallels[i]->type == VIR_DOMAIN_CHR_TYPE_PTY ||
890
 
             ctl->def->parallels[i]->type == VIR_DOMAIN_CHR_TYPE_DEV ||
891
 
             ctl->def->parallels[i]->type == VIR_DOMAIN_CHR_TYPE_FILE ||
892
 
             ctl->def->parallels[i]->type == VIR_DOMAIN_CHR_TYPE_PIPE) &&
893
 
            ctl->def->parallels[i]->data.file.path)
894
 
            if (vah_add_file(&buf,
895
 
                             ctl->def->parallels[i]->data.file.path,
896
 
                             "rw") != 0)
897
 
                goto clean;
898
 
 
899
 
    for (i = 0 ; i < ctl->def->nchannels; i++)
900
 
        if (ctl->def->channels[i] &&
901
 
            (ctl->def->channels[i]->type == VIR_DOMAIN_CHR_TYPE_PTY ||
902
 
             ctl->def->channels[i]->type == VIR_DOMAIN_CHR_TYPE_DEV ||
903
 
             ctl->def->channels[i]->type == VIR_DOMAIN_CHR_TYPE_FILE ||
904
 
             ctl->def->channels[i]->type == VIR_DOMAIN_CHR_TYPE_PIPE) &&
905
 
            ctl->def->channels[i]->data.file.path)
906
 
            if (vah_add_file(&buf,
907
 
                             ctl->def->channels[i]->data.file.path,
908
 
                             "rw") != 0)
909
 
                goto clean;
910
 
 
911
 
    if (ctl->def->os.kernel)
912
 
        if (vah_add_file(&buf, ctl->def->os.kernel, "r") != 0)
913
 
            goto clean;
914
 
 
915
 
    if (ctl->def->os.initrd)
916
 
        if (vah_add_file(&buf, ctl->def->os.initrd, "r") != 0)
917
 
            goto clean;
918
 
 
919
 
    if (ctl->def->os.loader && ctl->def->os.loader)
920
 
        if (vah_add_file(&buf, ctl->def->os.loader, "r") != 0)
921
 
            goto clean;
922
 
 
923
 
    if (ctl->def->ngraphics == 1 &&
924
 
        ctl->def->graphics[0]->type == VIR_DOMAIN_GRAPHICS_TYPE_SDL)
925
 
        if (vah_add_file(&buf, ctl->def->graphics[0]->data.sdl.xauth,
926
 
                         "r") != 0)
927
 
            goto clean;
928
 
 
929
 
    for (i = 0; i < ctl->def->nhostdevs; i++)
930
 
        if (ctl->def->hostdevs[i]) {
931
 
            virDomainHostdevDefPtr dev = ctl->def->hostdevs[i];
932
 
            switch (dev->source.subsys.type) {
933
 
            case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB: {
934
 
                usbDevice *usb = usbGetDevice(dev->source.subsys.u.usb.bus,
935
 
                                              dev->source.subsys.u.usb.device);
936
 
 
937
 
                if (usb == NULL)
938
 
                    continue;
939
 
 
940
 
                rc = usbDeviceFileIterate(usb, file_iterate_hostdev_cb, &buf);
941
 
                usbFreeDevice(usb);
942
 
                if (rc != 0)
943
 
                    goto clean;
944
 
                break;
945
 
            }
946
 
 
947
 
            case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI: {
948
 
                pciDevice *pci = pciGetDevice(
949
 
                           dev->source.subsys.u.pci.domain,
950
 
                           dev->source.subsys.u.pci.bus,
951
 
                           dev->source.subsys.u.pci.slot,
952
 
                           dev->source.subsys.u.pci.function);
953
 
 
954
 
                if (pci == NULL)
955
 
                    continue;
956
 
 
957
 
                rc = pciDeviceFileIterate(pci, file_iterate_pci_cb, &buf);
958
 
                pciFreeDevice(pci);
959
 
 
960
 
                break;
961
 
            }
962
 
 
963
 
            default:
964
 
                rc = 0;
965
 
                break;
966
 
            } /* switch */
967
 
        }
968
 
 
969
 
    if (ctl->newfile)
970
 
        if (vah_add_file(&buf, ctl->newfile, "rw") != 0)
971
 
            goto clean;
972
 
 
973
 
    if (virBufferError(&buf)) {
974
 
        virBufferFreeAndReset(&buf);
975
 
        vah_error(NULL, 0, "failed to allocate file buffer");
976
 
        goto clean;
977
 
    }
978
 
 
979
 
    rc = 0;
980
 
    ctl->files = virBufferContentAndReset(&buf);
981
 
 
982
 
  clean:
983
 
    VIR_FREE(uuid);
984
 
    return rc;
985
 
}
986
 
 
987
 
static int
988
 
vahParseArgv(vahControl * ctl, int argc, char **argv)
989
 
{
990
 
    int arg, idx = 0;
991
 
    struct option opt[] = {
992
 
        {"probing", 1, 0, 'p' },
993
 
        {"add", 0, 0, 'a'},
994
 
        {"create", 0, 0, 'c'},
995
 
        {"dryrun", 0, 0, 'd'},
996
 
        {"delete", 0, 0, 'D'},
997
 
        {"add-file", 0, 0, 'f'},
998
 
        {"append-file", 0, 0, 'F'},
999
 
        {"help", 0, 0, 'h'},
1000
 
        {"replace", 0, 0, 'r'},
1001
 
        {"remove", 0, 0, 'R'},
1002
 
        {"uuid", 1, 0, 'u'},
1003
 
        {0, 0, 0, 0}
1004
 
    };
1005
 
 
1006
 
    while ((arg = getopt_long(argc, argv, "acdDhrRH:b:u:p:f:F:", opt,
1007
 
            &idx)) != -1) {
1008
 
        switch (arg) {
1009
 
            case 'a':
1010
 
                ctl->cmd = 'a';
1011
 
                break;
1012
 
            case 'c':
1013
 
                ctl->cmd = 'c';
1014
 
                break;
1015
 
            case 'd':
1016
 
                ctl->dryrun = true;
1017
 
                break;
1018
 
            case 'D':
1019
 
                ctl->cmd = 'D';
1020
 
                break;
1021
 
            case 'f':
1022
 
            case 'F':
1023
 
                if ((ctl->newfile = strdup(optarg)) == NULL)
1024
 
                    vah_error(ctl, 1, "could not allocate memory for disk");
1025
 
                ctl->append = arg == 'F';
1026
 
                break;
1027
 
            case 'h':
1028
 
                vah_usage();
1029
 
                exit(EXIT_SUCCESS);
1030
 
                break;
1031
 
            case 'r':
1032
 
                ctl->cmd = 'r';
1033
 
                break;
1034
 
            case 'R':
1035
 
                ctl->cmd = 'R';
1036
 
                break;
1037
 
            case 'u':
1038
 
                if (strlen(optarg) > PROFILE_NAME_SIZE - 1)
1039
 
                    vah_error(ctl, 1, "invalid UUID");
1040
 
                if (virStrcpy((char *) ctl->uuid, optarg,
1041
 
                    PROFILE_NAME_SIZE) == NULL)
1042
 
                    vah_error(ctl, 1, "error copying UUID");
1043
 
                break;
1044
 
            case 'p':
1045
 
                if (STREQ(optarg, "1"))
1046
 
                    ctl->allowDiskFormatProbing = true;
1047
 
                else
1048
 
                    ctl->allowDiskFormatProbing = false;
1049
 
                break;
1050
 
            default:
1051
 
                vah_error(ctl, 1, "unsupported option");
1052
 
                break;
1053
 
        }
1054
 
    }
1055
 
    if (strchr("acDrR", ctl->cmd) == NULL)
1056
 
        vah_error(ctl, 1, "bad command");
1057
 
 
1058
 
    if (valid_uuid(ctl->uuid) != 0)
1059
 
        vah_error(ctl, 1, "invalid UUID");
1060
 
 
1061
 
    if (!ctl->cmd) {
1062
 
        vah_usage();
1063
 
        exit(EXIT_FAILURE);
1064
 
    }
1065
 
 
1066
 
    if (ctl->cmd == 'c' || ctl->cmd == 'r') {
1067
 
        char *xmlStr = NULL;
1068
 
        if (virFileReadLimFD(STDIN_FILENO, MAX_FILE_LEN, &xmlStr) < 0)
1069
 
            vah_error(ctl, 1, "could not read xml file");
1070
 
 
1071
 
        if (get_definition(ctl, xmlStr) != 0 || ctl->def == NULL) {
1072
 
            VIR_FREE(xmlStr);
1073
 
            vah_error(ctl, 1, "could not get VM definition");
1074
 
        }
1075
 
        VIR_FREE(xmlStr);
1076
 
 
1077
 
        if (get_files(ctl) != 0)
1078
 
            vah_error(ctl, 1, "invalid VM definition");
1079
 
    }
1080
 
    return 0;
1081
 
}
1082
 
 
1083
 
 
1084
 
/*
1085
 
 * virt-aa-helper -c -u UUID < file.xml
1086
 
 * virt-aa-helper -r -u UUID [-f <file>] < file.xml
1087
 
 * virt-aa-helper -a -u UUID
1088
 
 * virt-aa-helper -R -u UUID
1089
 
 * virt-aa-helper -D -u UUID
1090
 
 */
1091
 
int
1092
 
main(int argc, char **argv)
1093
 
{
1094
 
    vahControl _ctl, *ctl = &_ctl;
1095
 
    virBuffer buf = VIR_BUFFER_INITIALIZER;
1096
 
    int rc = -1;
1097
 
    char profile[PATH_MAX];
1098
 
    char include_file[PATH_MAX];
1099
 
 
1100
 
    /* clear the environment */
1101
 
    environ = NULL;
1102
 
    if (setenv("PATH", "/sbin:/usr/sbin", 1) != 0) {
1103
 
        vah_error(ctl, 1, "could not set PATH");
1104
 
    }
1105
 
    if (setenv("IFS", " \t\n", 1) != 0) {
1106
 
        vah_error(ctl, 1, "could not set IFS");
1107
 
    }
1108
 
 
1109
 
    if (!(progname = strrchr(argv[0], '/')))
1110
 
        progname = argv[0];
1111
 
    else
1112
 
        progname++;
1113
 
 
1114
 
    memset(ctl, 0, sizeof(vahControl));
1115
 
 
1116
 
    if (vahParseArgv(ctl, argc, argv) != 0)
1117
 
        vah_error(ctl, 1, "could not parse arguments");
1118
 
 
1119
 
    if (snprintf(profile, PATH_MAX, "%s/%s",
1120
 
                 APPARMOR_DIR "/libvirt", ctl->uuid) > PATH_MAX - 1)
1121
 
        vah_error(ctl, 1, "profile name exceeds maximum length");
1122
 
 
1123
 
    if (snprintf(include_file, PATH_MAX, "%s/%s.files",
1124
 
                 APPARMOR_DIR "/libvirt", ctl->uuid) > PATH_MAX - 1)
1125
 
        vah_error(ctl, 1, "disk profile name exceeds maximum length");
1126
 
 
1127
 
    if (ctl->cmd == 'a')
1128
 
        rc = parserLoad(ctl->uuid);
1129
 
    else if (ctl->cmd == 'R' || ctl->cmd == 'D') {
1130
 
        rc = parserRemove(ctl->uuid);
1131
 
        if (ctl->cmd == 'D') {
1132
 
            unlink(include_file);
1133
 
            unlink(profile);
1134
 
        }
1135
 
    } else if (ctl->cmd == 'c' || ctl->cmd == 'r') {
1136
 
        char *included_files = NULL;
1137
 
 
1138
 
        if (ctl->cmd == 'c' && virFileExists(profile))
1139
 
            vah_error(ctl, 1, "profile exists");
1140
 
 
1141
 
        if (ctl->append && ctl->newfile) {
1142
 
            if (vah_add_file(&buf, ctl->newfile, "rw") != 0)
1143
 
                goto clean;
1144
 
        } else {
1145
 
            virBufferVSprintf(&buf, "  \"%s/log/libvirt/**/%s.log\" w,\n",
1146
 
                              LOCAL_STATE_DIR, ctl->def->name);
1147
 
            virBufferVSprintf(&buf, "  \"%s/lib/libvirt/**/%s.monitor\" rw,\n",
1148
 
                              LOCAL_STATE_DIR, ctl->def->name);
1149
 
            virBufferVSprintf(&buf, "  \"%s/run/libvirt/**/%s.pid\" rwk,\n",
1150
 
                              LOCAL_STATE_DIR, ctl->def->name);
1151
 
            if (ctl->files)
1152
 
                virBufferVSprintf(&buf, "%s", ctl->files);
1153
 
        }
1154
 
 
1155
 
        if (virBufferError(&buf)) {
1156
 
            virBufferFreeAndReset(&buf);
1157
 
            vah_error(ctl, 1, "failed to allocate buffer");
1158
 
        }
1159
 
 
1160
 
        included_files = virBufferContentAndReset(&buf);
1161
 
 
1162
 
        /* (re)create the include file using included_files */
1163
 
        if (ctl->dryrun) {
1164
 
            vah_info(include_file);
1165
 
            vah_info(included_files);
1166
 
            rc = 0;
1167
 
        } else if ((rc = update_include_file(include_file,
1168
 
                                             included_files,
1169
 
                                             ctl->append)) != 0)
1170
 
            goto clean;
1171
 
 
1172
 
 
1173
 
        /* create the profile from TEMPLATE */
1174
 
        if (ctl->cmd == 'c') {
1175
 
            char *tmp = NULL;
1176
 
            if (virAsprintf(&tmp, "  #include <libvirt/%s.files>\n",
1177
 
                            ctl->uuid) == -1) {
1178
 
                vah_error(ctl, 0, "could not allocate memory");
1179
 
                goto clean;
1180
 
            }
1181
 
 
1182
 
            if (ctl->dryrun) {
1183
 
                vah_info(profile);
1184
 
                vah_info(ctl->uuid);
1185
 
                vah_info(tmp);
1186
 
                rc = 0;
1187
 
            } else if ((rc = create_profile(profile, ctl->uuid, tmp)) != 0) {
1188
 
                vah_error(ctl, 0, "could not create profile");
1189
 
                unlink(include_file);
1190
 
            }
1191
 
            VIR_FREE(tmp);
1192
 
        }
1193
 
 
1194
 
        if (rc == 0 && !ctl->dryrun) {
1195
 
            if (ctl->cmd == 'c')
1196
 
                rc = parserLoad(ctl->uuid);
1197
 
            else
1198
 
                rc = parserReplace(ctl->uuid);
1199
 
 
1200
 
            /* cleanup */
1201
 
            if (rc != 0) {
1202
 
                unlink(include_file);
1203
 
                if (ctl->cmd == 'c')
1204
 
                    unlink(profile);
1205
 
            }
1206
 
        }
1207
 
      clean:
1208
 
        VIR_FREE(included_files);
1209
 
    }
1210
 
 
1211
 
    vahDeinit(ctl);
1212
 
    exit(rc == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
1213
 
}