3
* virt-aa-helper: wrapper program used by AppArmor security driver.
4
* Copyright (C) 2009-2010 Canonical Ltd.
6
* See COPYING.LIB for the License of this software
9
* Jamie Strandboge <jamie@canonical.com>
21
#include <sys/types.h>
26
#include <sys/utsname.h>
33
#include "security_driver.h"
34
#include "security_apparmor.h"
35
#include "domain_conf.h"
41
static char *progname;
44
bool allowDiskFormatProbing;
45
char uuid[PROFILE_NAME_SIZE]; /* UUID of vm */
46
bool dryrun; /* dry run */
47
char cmd; /* 'c' create
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 */
62
vahDeinit(vahControl * ctl)
68
virCapabilitiesFree(ctl->caps);
72
VIR_FREE(ctl->newfile);
83
fprintf(stdout, "\n%s [options] [< def.xml]\n\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"
96
fprintf(stdout, "This command is intended to be used by libvirtd "
97
"and not used directly.\n");
102
vah_error(vahControl * ctl, int doexit, const char *str)
104
fprintf(stderr, _("%s: error: %s\n"), progname, str);
114
vah_warning(const char *str)
116
fprintf(stderr, _("%s: warning: %s\n"), progname, str);
120
vah_info(const char *str)
122
fprintf(stderr, _("%s:\n%s\n"), progname, str);
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
131
replace_string(char *orig, const size_t len, const char *oldstr,
138
if ((pos = strstr(orig, oldstr)) == NULL) {
139
vah_error(NULL, 0, "could not find replacement string");
143
if (VIR_ALLOC_N(tmp, len) < 0) {
144
vah_error(NULL, 0, "could not allocate memory for string");
149
idx = abs(pos - orig);
151
/* copy everything up to oldstr */
152
strncat(tmp, orig, idx);
154
/* add the replacement string */
155
if (strlen(tmp) + strlen(repstr) > len - 1) {
156
vah_error(NULL, 0, "not enough space in target buffer");
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");
168
strncat(tmp, orig + idx + strlen(oldstr),
169
strlen(orig) - (idx + strlen(oldstr)));
171
if (virStrcpy(orig, tmp, len) == NULL) {
172
vah_error(NULL, 0, "error replacing string");
182
* run an apparmor_parser command
185
parserCommand(const char *profile_name, const char cmd)
188
char profile[PATH_MAX];
192
if (strchr("arR", cmd) == NULL) {
193
vah_error(NULL, 0, "invalid flag");
197
snprintf(flag, 3, "-%c", cmd);
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");
205
if (!virFileExists(profile)) {
206
vah_error(NULL, 0, "profile does not exist");
209
const char * const argv[] = {
210
"/sbin/apparmor_parser", flag, profile, NULL
212
if ((ret = virRun(argv, &status)) != 0 ||
213
(WIFEXITED(status) && WEXITSTATUS(status) != 0)) {
215
vah_error(NULL, 0, "failed to run apparmor_parser");
217
} else if (cmd == 'R' && WIFEXITED(status) && WEXITSTATUS(status) == 234) {
218
vah_warning("unable to unload already unloaded profile (non-fatal)");
220
vah_error(NULL, 0, "apparmor_parser exited with error");
230
* Update the dynamic files
233
update_include_file(const char *include_file, const char *included_files,
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";
244
if (virFileExists(include_file)) {
245
flen = virFileReadAll(include_file, MAX_FILE_LEN, &existing);
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");
256
if (virAsprintf(&pcontent, "%s%s", warning, included_files) == -1) {
257
vah_error(NULL, 0, "could not allocate memory for profile");
262
plen = strlen(pcontent);
263
if (plen > MAX_FILE_LEN) {
264
vah_error(NULL, 0, "invalid length for new profile");
268
/* only update the disk profile if it is different */
269
if (flen > 0 && flen == plen && STREQLEN(existing, pcontent, plen)) {
275
if ((fd = open(include_file, O_CREAT | O_TRUNC | O_WRONLY, 0644)) == -1) {
276
vah_error(NULL, 0, "failed to create include file");
280
if (safewrite(fd, pcontent, plen) < 0) { /* don't write the '\0' */
282
vah_error(NULL, 0, "failed to write to profile");
286
if (close(fd) != 0) {
287
vah_error(NULL, 0, "failed to close or write to profile");
300
* Create a profile based on a template
303
create_profile(const char *profile, const char *profile_name,
304
const char *profile_files)
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}";
317
if (virFileExists(profile)) {
318
vah_error(NULL, 0, "profile exists");
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");
328
if (!virFileExists(template)) {
329
vah_error(NULL, 0, "template does not exist");
333
if ((tlen = virFileReadAll(template, MAX_FILE_LEN, &tcontent)) < 0) {
334
vah_error(NULL, 0, "failed to read AppArmor template");
338
if (strstr(tcontent, template_name) == NULL) {
339
vah_error(NULL, 0, "no replacement string in template");
343
if (strstr(tcontent, template_end) == NULL) {
344
vah_error(NULL, 0, "no replacement string in template");
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");
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);
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");
368
if (VIR_ALLOC_N(pcontent, plen) < 0) {
369
vah_error(NULL, 0, "could not allocate memory for profile");
373
strcpy(pcontent, tcontent);
375
if (replace_string(pcontent, plen, template_name, replace_name) < 0)
378
if (replace_string(pcontent, plen, template_end, replace_files) < 0)
382
if ((fd = open(profile, O_CREAT | O_EXCL | O_WRONLY, 0644)) == -1) {
383
vah_error(NULL, 0, "failed to create profile");
387
if (safewrite(fd, pcontent, plen - 1) < 0) { /* don't write the '\0' */
389
vah_error(NULL, 0, "failed to write to profile");
393
if (close(fd) != 0) {
394
vah_error(NULL, 0, "failed to close or write to profile");
402
VIR_FREE(replace_name);
403
VIR_FREE(replace_files);
411
* Load an existing profile
414
parserLoad(const char *profile_name)
416
return parserCommand(profile_name, 'a');
420
* Remove an existing profile
423
parserRemove(const char *profile_name)
425
return parserCommand(profile_name, 'R');
429
* Replace an existing profile
432
parserReplace(const char *profile_name)
434
return parserCommand(profile_name, 'r');
438
valid_uuid(const char *uuid)
440
unsigned char rawuuid[VIR_UUID_BUFLEN];
442
if (strlen(uuid) != PROFILE_NAME_SIZE - 1)
445
if (!STRPREFIX(uuid, AA_PREFIX))
448
if (virUUIDParse(uuid + strlen(AA_PREFIX), rawuuid) < 0)
455
valid_name(const char *name)
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 = " /[]*";
461
if (strlen(name) == 0 || strlen(name) > PATH_MAX - 1)
464
if (strcspn(name, bad) != strlen(name))
470
/* see if one of the strings in arr starts with str */
472
array_starts_with(const char *str, const char * const *arr, const long size)
475
for (i = 0; i < size; i++) {
476
if (strlen(str) < strlen(arr[i]))
479
if (STRPREFIX(str, arr[i]))
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.
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.
495
* RETURN: -1 on error, 0 if ok, 1 if blocked
498
valid_path(const char *path, const bool readonly)
502
const char * const restricted[] = {
520
/* these paths are ok for readonly, but not read/write */
521
const char * const restricted_rw[] = {
527
/* override the above with these */
528
const char * const override[] = {
529
"/sys/devices/pci" /* for hostdev pci devices */
532
if (path == NULL || strlen(path) > PATH_MAX - 1) {
533
vah_error(NULL, 0, "bad pathname");
537
/* Don't allow double quotes, since we use them to quote the filename
538
* and this will confuse the apparmor parser.
540
if (strchr(path, '"') != NULL)
543
/* Require an absolute path */
544
if (STRNEQLEN(path, "/", 1))
547
if (!virFileExists(path))
548
vah_warning("path does not exist, skipping file type checks");
550
if (stat(path, &sb) == -1)
553
switch (sb.st_mode & S_IFMT) {
568
opaths = sizeof(override)/sizeof *(override);
570
npaths = sizeof(restricted)/sizeof *(restricted);
571
if (array_starts_with(path, restricted, npaths) == 0 &&
572
array_starts_with(path, override, opaths) != 0)
575
npaths = sizeof(restricted_rw)/sizeof *(restricted_rw);
577
if (array_starts_with(path, restricted_rw, npaths) == 0)
584
/* Called from SAX on parsing errors in the XML. */
586
catchXMLError (void *ctx, const char *msg ATTRIBUTE_UNUSED, ...)
588
xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
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");
600
vah_error(NULL, 0, err_str);
608
* Parse the xml we received to fill in the following:
613
* These are suitable for setting up a virCapsPtr
616
caps_mockup(vahControl * ctl, const char *xmlStr)
619
xmlParserCtxtPtr pctxt = NULL;
620
xmlDocPtr xml = NULL;
621
xmlXPathContextPtr ctxt = NULL;
624
/* Set up a parser context so we can catch the details of XML errors. */
625
pctxt = xmlNewParserCtxt ();
626
if (!pctxt || !pctxt->sax)
628
pctxt->sax->error = catchXMLError;
630
xml = xmlCtxtReadDoc (pctxt, BAD_CAST xmlStr, "domain.xml", NULL,
631
XML_PARSE_NOENT | XML_PARSE_NONET |
632
XML_PARSE_NOWARNING);
634
if (virGetLastError() == NULL)
635
vah_error(NULL, 0, "failed to parse xml document");
639
if ((root = xmlDocGetRootElement(xml)) == NULL) {
640
vah_error(NULL, 0, "missing root element");
644
if (!xmlStrEqual(root->name, BAD_CAST "domain")) {
645
vah_error(NULL, 0, "incorrect root element");
649
if ((ctxt = xmlXPathNewContext(xml)) == NULL) {
650
vah_error(ctl, 0, "could not allocate memory");
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'");
660
ctl->arch = virXPathString("string(./os/type[1]/@arch)", ctxt);
662
/* The XML we are given should have an arch, but in case it doesn't,
663
* just use the host's arch.
665
struct utsname utsname;
667
/* Really, this never fails - look at the man-page. */
669
if ((ctl->arch = strdup(utsname.machine)) == NULL) {
670
vah_error(ctl, 0, "could not allocate memory");
674
if (STREQ(ctl->arch, "x86_64"))
682
xmlFreeParserCtxt (pctxt);
684
xmlXPathFreeContext(ctxt);
690
get_definition(vahControl * ctl, const char *xmlStr)
693
virCapsGuestPtr guest; /* this is freed when caps is freed */
696
* mock up some capabilities. We don't currently use these explicitly,
697
* but need them for virDomainDefParseString().
699
if (caps_mockup(ctl, xmlStr) != 0)
702
if ((ctl->caps = virCapabilitiesNew(ctl->arch, 1, 1)) == NULL) {
703
vah_error(ctl, 0, "could not allocate memory");
707
if ((guest = virCapabilitiesAddGuest(ctl->caps,
715
vah_error(ctl, 0, "could not allocate memory");
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");
726
if (!ctl->def->name) {
727
vah_error(ctl, 0, "could not find name in XML");
731
if (valid_name(ctl->def->name) != 0) {
732
vah_error(ctl, 0, "bad name");
743
vah_add_file(virBufferPtr buf, const char *path, const char *perms)
747
bool readonly = true;
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.
756
if (STRNEQLEN(path, "/", 1)) {
758
vah_warning(" skipped non-absolute path");
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");
769
if ((tmp = strdup(path)) == NULL)
772
if (strchr(perms, 'w') != NULL)
775
rc = valid_path(tmp, readonly);
778
vah_error(NULL, 0, path);
779
vah_error(NULL, 0, " skipped restricted file");
784
virBufferVSprintf(buf, " \"%s\" %s,\n", tmp, perms);
786
virBufferVSprintf(buf, " # don't audit writes to readonly files\n");
787
virBufferVSprintf(buf, " deny \"%s\" w,\n", tmp);
797
file_iterate_hostdev_cb(usbDevice *dev ATTRIBUTE_UNUSED,
798
const char *file, void *opaque)
800
virBufferPtr buf = opaque;
801
return vah_add_file(buf, file, "rw");
805
file_iterate_pci_cb(pciDevice *dev ATTRIBUTE_UNUSED,
806
const char *file, void *opaque)
808
virBufferPtr buf = opaque;
809
return vah_add_file(buf, file, "rw");
813
add_file_path(virDomainDiskDefPtr disk,
818
virBufferPtr buf = opaque;
823
ret = vah_add_file(buf, path, "r");
825
ret = vah_add_file(buf, path, "rw");
827
ret = vah_add_file(buf, path, "r");
838
get_files(vahControl * ctl)
840
virBuffer buf = VIR_BUFFER_INITIALIZER;
844
char uuidstr[VIR_UUID_STRING_BUFLEN];
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");
853
if (STRNEQ(uuid, ctl->uuid)) {
854
vah_error(ctl, 0, "given uuid does not match XML uuid");
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,
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)
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)
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,
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,
911
if (ctl->def->os.kernel)
912
if (vah_add_file(&buf, ctl->def->os.kernel, "r") != 0)
915
if (ctl->def->os.initrd)
916
if (vah_add_file(&buf, ctl->def->os.initrd, "r") != 0)
919
if (ctl->def->os.loader && ctl->def->os.loader)
920
if (vah_add_file(&buf, ctl->def->os.loader, "r") != 0)
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,
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);
940
rc = usbDeviceFileIterate(usb, file_iterate_hostdev_cb, &buf);
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);
957
rc = pciDeviceFileIterate(pci, file_iterate_pci_cb, &buf);
970
if (vah_add_file(&buf, ctl->newfile, "rw") != 0)
973
if (virBufferError(&buf)) {
974
virBufferFreeAndReset(&buf);
975
vah_error(NULL, 0, "failed to allocate file buffer");
980
ctl->files = virBufferContentAndReset(&buf);
988
vahParseArgv(vahControl * ctl, int argc, char **argv)
991
struct option opt[] = {
992
{"probing", 1, 0, 'p' },
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'},
1000
{"replace", 0, 0, 'r'},
1001
{"remove", 0, 0, 'R'},
1002
{"uuid", 1, 0, 'u'},
1006
while ((arg = getopt_long(argc, argv, "acdDhrRH:b:u:p:f:F:", opt,
1023
if ((ctl->newfile = strdup(optarg)) == NULL)
1024
vah_error(ctl, 1, "could not allocate memory for disk");
1025
ctl->append = arg == 'F';
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");
1045
if (STREQ(optarg, "1"))
1046
ctl->allowDiskFormatProbing = true;
1048
ctl->allowDiskFormatProbing = false;
1051
vah_error(ctl, 1, "unsupported option");
1055
if (strchr("acDrR", ctl->cmd) == NULL)
1056
vah_error(ctl, 1, "bad command");
1058
if (valid_uuid(ctl->uuid) != 0)
1059
vah_error(ctl, 1, "invalid UUID");
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");
1071
if (get_definition(ctl, xmlStr) != 0 || ctl->def == NULL) {
1073
vah_error(ctl, 1, "could not get VM definition");
1077
if (get_files(ctl) != 0)
1078
vah_error(ctl, 1, "invalid VM definition");
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
1092
main(int argc, char **argv)
1094
vahControl _ctl, *ctl = &_ctl;
1095
virBuffer buf = VIR_BUFFER_INITIALIZER;
1097
char profile[PATH_MAX];
1098
char include_file[PATH_MAX];
1100
/* clear the environment */
1102
if (setenv("PATH", "/sbin:/usr/sbin", 1) != 0) {
1103
vah_error(ctl, 1, "could not set PATH");
1105
if (setenv("IFS", " \t\n", 1) != 0) {
1106
vah_error(ctl, 1, "could not set IFS");
1109
if (!(progname = strrchr(argv[0], '/')))
1114
memset(ctl, 0, sizeof(vahControl));
1116
if (vahParseArgv(ctl, argc, argv) != 0)
1117
vah_error(ctl, 1, "could not parse arguments");
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");
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");
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);
1135
} else if (ctl->cmd == 'c' || ctl->cmd == 'r') {
1136
char *included_files = NULL;
1138
if (ctl->cmd == 'c' && virFileExists(profile))
1139
vah_error(ctl, 1, "profile exists");
1141
if (ctl->append && ctl->newfile) {
1142
if (vah_add_file(&buf, ctl->newfile, "rw") != 0)
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);
1152
virBufferVSprintf(&buf, "%s", ctl->files);
1155
if (virBufferError(&buf)) {
1156
virBufferFreeAndReset(&buf);
1157
vah_error(ctl, 1, "failed to allocate buffer");
1160
included_files = virBufferContentAndReset(&buf);
1162
/* (re)create the include file using included_files */
1164
vah_info(include_file);
1165
vah_info(included_files);
1167
} else if ((rc = update_include_file(include_file,
1173
/* create the profile from TEMPLATE */
1174
if (ctl->cmd == 'c') {
1176
if (virAsprintf(&tmp, " #include <libvirt/%s.files>\n",
1178
vah_error(ctl, 0, "could not allocate memory");
1184
vah_info(ctl->uuid);
1187
} else if ((rc = create_profile(profile, ctl->uuid, tmp)) != 0) {
1188
vah_error(ctl, 0, "could not create profile");
1189
unlink(include_file);
1194
if (rc == 0 && !ctl->dryrun) {
1195
if (ctl->cmd == 'c')
1196
rc = parserLoad(ctl->uuid);
1198
rc = parserReplace(ctl->uuid);
1202
unlink(include_file);
1203
if (ctl->cmd == 'c')
1208
VIR_FREE(included_files);
1212
exit(rc == 0 ? EXIT_SUCCESS : EXIT_FAILURE);