[apparmor] C based aa-exec
John Johansen
john.johansen at canonical.com
Thu Jul 11 22:53:05 UTC 2013
So this is a C based version of aa-exec to replace the perl version.
---
/*
* Copyright (C) 2013 Canonical Ltd.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
* License published by the Free Software Foundation.
*/
#define _GNU_SOURCE
#include <errno.h>
#include <getopt.h>
#include <libintl.h>
#include <locale.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/apparmor.h>
#define _(s) gettext(s)
#define aa_verbose(X...) \
do { \
if (opt_verbose) { \
fprintf(g_outfile, X); \
} \
} while (0)
#define aa_error(X, Y...) \
do { \
if (X) { \
fprintf(g_outfile, "aborting: " Y); \
exit(-1); \
} \
} while (0)
/* Internationalization support. Can be defined in Makefile */
#ifndef PACKAGE
#define PACKAGE "apparmor"
#endif
#ifndef LOCALEDIR
#define LOCALEDIR ""
#endif
const char *g_version = "3.0";
const char *g_copyright = "Copyright (C) 2013 Canonical Ltd.";
FILE *g_outfile;
char *g_progname;
int opt_immediate;
int opt_verbose;
char *opt_debug;
char *opt_file;
char *opt_profile;
char *opt_namespace;
const char *g_options =
"Options:\n"
"--------\n"
"-p PROFILE, --profile=PROFILE PROFILE to confine <prog> with\n"
"-n NAMESPACE, --namespace=NAMESPACE NAMESPACE to confine <prog> in\n"
"-f FILE, --file=FILE profile file to load\n"
"-i, --immediate change profile immediately instead of at exec\n"
"-v, --verbose show messages with stats\n"
"-d FILE, --debug=FILE dump verbose output to FILE\n"
"-h, --help display this help\n";
const char *short_options = "d:hp:n:f:iv";
struct option long_options[] = {
{"debug", 1, 0, 'd'},
{"help", 0, 0, 'h'},
{"profile", 1, 0, 'p'},
{"namespace", 1, 0, 'n'},
{"file", 1, 0, 'f'},
{"immediate", 0, 0, 'i'},
{"verbose", 0, 0, 'v'},
{"Version", 0, 0, 'V'},
{NULL, 0, 0, 0},
};
static void display_version(void)
{
printf("%s version %s\n%s\n", g_progname, g_version, g_copyright);
}
static void display_usage(void)
{
display_version();
printf("\nUsage: %s [options] [--] <prog> <args>\n\n%s", g_progname,
g_options);
}
static void process_args(int argc, char *argv[])
{
int c, o;
int count = 0;
while ((c = getopt_long(argc, argv, short_options, long_options, &o)) != -1) {
switch (c) {
case 0:
display_usage();
exit(0);
break;
case 'V':
display_version();
break;
case 'd':
opt_verbose = 1;
opt_debug = optarg;
break;
case 'h':
display_usage();
exit(0);
break;
case 'p':
opt_profile = optarg;
break;
case 'n':
opt_namespace = optarg;
break;
case 'f':
opt_file = optarg;
break;
case 'i':
opt_immediate = 1;
break;
case 'v':
opt_verbose = 1;
break;
default:
printf("Unknown option %c\n\n", c);
display_usage();
exit(0);
break;
}
count++;
}
}
int main(int argc, char *argv[])
{
int rc = 0;
char *profile = NULL;
/* name of executable, for error reporting and usage display */
g_progname = argv[0];
g_outfile = stderr;
setlocale(LC_MESSAGES, "");
bindtextdomain(PACKAGE, LOCALEDIR);
textdomain(PACKAGE);
process_args(argc, argv);
if (opt_debug) {
FILE *tmp = fopen(opt_debug, "w+");
aa_error(tmp == NULL, "could not open debug file %s\n", opt_debug);
aa_error(setvbuf(tmp, NULL, _IONBF, 0) != 0, "could not set debug file %s to unbuffered\n", opt_debug);
g_outfile = tmp;
}
if (opt_namespace || opt_profile) {
if (opt_namespace) {
rc = asprintf(&profile, ":%s:%s", opt_namespace, opt_profile ? opt_profile : "");
aa_error(rc == -1, "%s", strerror(errno));
} else if (opt_profile) {
rc = asprintf(&profile, "%s", opt_profile);
aa_error(rc == -1, "%s", strerror(errno));
}
if (opt_file) {
char *cmd;
rc = asprintf(&cmd, "apparmor_parser -r %s", opt_file);
aa_error(rc == -1, "%s", strerror(errno));
aa_verbose("%s\n", cmd);
rc = system(cmd);
aa_error(rc == -1, "could not load file %s", opt_file);
}
if (opt_immediate) {
aa_verbose("aa_change_profile(\"%s\")\n", profile);
rc = aa_change_profile(profile);
} else {
aa_verbose("aa_change_onexec(\"%s\")\n", profile);
rc = aa_change_onexec(profile);
}
if (rc == -1) {
if (errno == ENOENT || errno == EACCES)
aa_error(1, "\'%s\' does not exist", profile);
else if (errno == EINVAL)
aa_error(1, "AppArmor interface not available");
else
aa_error(1, "%s", strerror(errno));
}
}
aa_verbose("exec %s\n", argv[optind]);
(void)execvpe(argv[optind], &argv[optind], environ);
/* exec failed, kill outselves to flag parent */
rc = errno;
fprintf(g_outfile, "FAIL: exec to '%s' failed (%s)\n", argv[optind],
strerror(errno));
return rc;
}
More information about the AppArmor
mailing list