[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