summaryrefslogtreecommitdiffstats
path: root/secmds
diff options
context:
space:
mode:
Diffstat (limited to 'secmds')
-rw-r--r--secmds/Makefile.am40
-rw-r--r--secmds/findcon.cc245
-rw-r--r--secmds/indexcon.cc121
-rw-r--r--secmds/replcon.cc358
-rw-r--r--secmds/seinfo.c2337
-rw-r--r--secmds/sesearch.c1173
6 files changed, 4274 insertions, 0 deletions
diff --git a/secmds/Makefile.am b/secmds/Makefile.am
new file mode 100644
index 0000000..ddc88b1
--- /dev/null
+++ b/secmds/Makefile.am
@@ -0,0 +1,40 @@
+# various setools command line tools
+
+bin_PROGRAMS = seinfo sesearch findcon replcon indexcon
+
+# These are for indexcon so that it is usable on machines without setools
+STATICLIBS = ../libsefs/src/libsefs.a ../libapol/src/libapol.a ../libqpol/src/libqpol.a -lsqlite3
+
+AM_CFLAGS = @DEBUGCFLAGS@ @WARNCFLAGS@ @PROFILECFLAGS@ @SELINUX_CFLAGS@ \
+ @QPOL_CFLAGS@ @APOL_CFLAGS@
+AM_CXXFLAGS = @DEBUGCXXFLAGS@ @WARNCXXFLAGS@ @PROFILECFLAGS@ @SELINUX_CFLAGS@ \
+ @QPOL_CFLAGS@ @APOL_CFLAGS@ @SEFS_CFLAGS@
+AM_LDFLAGS = @DEBUGLDFLAGS@ @WARNLDFLAGS@ @PROFILELDFLAGS@
+
+LDADD = @SELINUX_LIB_FLAG@ @APOL_LIB_FLAG@ @QPOL_LIB_FLAG@
+DEPENDENCIES = $(top_builddir)/libapol/src/libapol.so $(top_builddir)/libqpol/src/libqpol.so
+
+seinfo_SOURCES = seinfo.c
+
+sesearch_SOURCES = sesearch.c
+
+indexcon_SOURCES = indexcon.cc
+indexcon_LDADD = @SELINUX_LIB_FLAG@ $(STATICLIBS)
+indexcon_DEPENDENCIES = $(DEPENDENCIES) $(top_builddir)/libsefs/src/libsefs.so
+
+findcon_SOURCES = findcon.cc
+findcon_LDADD = @SEFS_LIB_FLAG@ $(LDADD)
+findcon_DEPENDENCIES = $(DEPENDENCIES) $(top_builddir)/libsefs/src/libsefs.so
+
+replcon_SOURCES = replcon.cc
+replcon_LDADD = @SEFS_LIB_FLAG@ $(LDADD)
+replcon_DEPENDENCIES = $(DEPENDENCIES) $(top_builddir)/libsefs/src/libsefs.so
+
+$(top_builddir)/libapol/src/libapol.so:
+ $(MAKE) -C $(top_builddir)/libapol/src $(notdir $@)
+
+$(top_builddir)/libqpol/src/libqpol.so:
+ $(MAKE) -C $(top_builddir)/libqpol/src $(notdir $@)
+
+$(top_builddir)/libsefs/src/libsefs.so:
+ $(MAKE) -C $(top_builddir)/libsefs/src $(notdir $@)
diff --git a/secmds/findcon.cc b/secmds/findcon.cc
new file mode 100644
index 0000000..325c2f0
--- /dev/null
+++ b/secmds/findcon.cc
@@ -0,0 +1,245 @@
+/**
+ * @file
+ *
+ * Search a fclist (either the disk, a database generated by indexcon
+ * or apol, or a file_contexts file for entries that match a given
+ * SELinux file context.
+ *
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ *
+ * Copyright (C) 2003-2007 Tresys Technology, LLC
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <config.h>
+
+#include <sefs/db.hh>
+#include <sefs/fcfile.hh>
+#include <sefs/filesystem.hh>
+#include <sefs/entry.hh>
+#include <sefs/query.hh>
+
+using namespace std;
+
+#include <errno.h>
+#include <getopt.h>
+#include <iostream>
+#include <string>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#define COPYRIGHT_INFO "Copyright (C) 2003-2007 Tresys Technology, LLC"
+
+enum OPTIONS
+{
+ OPTION_CONTEXT = 256
+};
+
+static struct option const longopts[] = {
+ {"class", required_argument, NULL, 'c'},
+ {"type", required_argument, NULL, 't'},
+ {"user", required_argument, NULL, 'u'},
+ {"role", required_argument, NULL, 'r'},
+ {"mls-range", required_argument, NULL, 'm'},
+ {"path", required_argument, NULL, 'p'},
+ {"regex", no_argument, NULL, 'R'},
+ {"context", required_argument, NULL, OPTION_CONTEXT},
+ {"help", no_argument, NULL, 'h'},
+ {"version", no_argument, NULL, 'V'},
+ {NULL, 0, NULL, 0}
+};
+
+static void usage(const char *program_name, bool brief)
+{
+ cout << "Usage: " << program_name << " FCLIST [OPTIONS] [EXPRESSION]" << endl << endl;
+ if (brief)
+ {
+ cout << "\tTry " << program_name << " --help for more help." << endl << endl;
+ return;
+ }
+
+ cout << "Find files matching the given SELinux context." << endl << endl;
+
+ cout << "FCLIST is a directory name, a file_contexts file, or a database" << endl;
+ cout << "created by a previous run of indexcon." << endl;
+ cout << endl;
+
+ cout << "EXPRESSION:" << endl;
+ cout << " -t TYPE, --type=TYPE find contexts with type TYPE" << endl;
+ cout << " -u USER, --user=USER find contexts with user USER" << endl;
+ cout << " -r ROLE, --role=ROLE find contexts with role ROLE" << endl;
+ cout << " -m RANGE, --mls-range=RANGE find contexts with MLS range RANGE" << endl;
+ cout << " --context=CONTEXT partial or full context to find" << endl;
+ cout << " (overrides expression options above)" << endl;
+ cout << " -p PATH, --path=PATH find files in PATH" << endl;
+ cout << " -c CLASS, --class=CLASS find files of object class CLASS" << endl;
+ cout << endl;
+
+ cout << "OPTIONS:" << endl;
+ cout << " -R, --regex enable regular expressions" << endl;
+ cout << " -h, --help print this help text and exit" << endl;
+ cout << " -V, --version print version information and exit" << endl;
+ cout << endl;
+ cout << "If the fclist does not contain MLS ranges and -m was given," << endl;
+ cout << "then the search will return nothing." << endl;
+}
+
+static int print_entry(sefs_fclist * fclist, const sefs_entry * e, void *arg __attribute__ ((unused)))
+{
+ char *str = e->toString();
+ cout << str << endl;
+ free(str);
+ return 0;
+}
+
+int main(int argc, char *argv[])
+{
+ int optc;
+ sefs_query *query = new sefs_query();
+
+ apol_context_t *context = NULL;
+ try
+ {
+ while ((optc = getopt_long(argc, argv, "t:u:r:m:p:c:RhV", longopts, NULL)) != -1)
+ {
+ switch (optc)
+ {
+ case 't':
+ if (context == NULL)
+ {
+ query->type(optarg, false);
+ }
+ break;
+ case 'u':
+ if (context == NULL)
+ {
+ query->user(optarg);
+ }
+ break;
+ case 'r':
+ if (context == NULL)
+ {
+ query->role(optarg);
+ }
+ break;
+ case 'm':
+ if (context == NULL)
+ {
+ query->range(optarg, APOL_QUERY_EXACT);
+ }
+ break;
+ case OPTION_CONTEXT:
+ if ((context = apol_context_create_from_literal(optarg)) == NULL)
+ {
+ cerr << "Could not create a context." << endl;
+ throw runtime_error(strerror(errno));
+ }
+ break;
+ case 'p':
+ query->path(optarg);
+ break;
+ case 'c':
+ query->objectClass(optarg);
+ break;
+ case 'R':
+ query->regex(true);
+ break;
+ case 'h': // help
+ usage(argv[0], false);
+ exit(0);
+ case 'V': // version
+ cout << "findcon " << VERSION << endl << COPYRIGHT_INFO << endl;
+ exit(0);
+ default:
+ usage(argv[0], true);
+ exit(1);
+ }
+ }
+ if (context != NULL)
+ {
+ query->user(apol_context_get_user(context));
+ query->role(apol_context_get_role(context));
+ query->type(apol_context_get_type(context), false);
+ if (apol_context_get_range(context) != NULL)
+ {
+ char *r = apol_mls_range_render(NULL, apol_context_get_range(context));
+ query->range(r, APOL_QUERY_EXACT);
+ free(r);
+ }
+ else
+ {
+ query->range(NULL, APOL_QUERY_EXACT);
+ }
+ }
+ }
+ catch(...)
+ {
+ cerr << strerror(errno) << endl;
+ apol_context_destroy(&context);
+ delete query;
+ exit(-1);
+ }
+ apol_context_destroy(&context);
+
+ if (optind + 1 != argc)
+ {
+ usage(argv[0], 1);
+ delete query;
+ exit(-1);
+ }
+
+ // try to autodetect the type of thing being searched
+ struct stat sb;
+ if (stat(argv[optind], &sb) != 0)
+ {
+ cerr << "Could not open " << argv[optind] << ": " << strerror(errno) << endl;
+ delete query;
+ exit(-1);
+ }
+
+ sefs_fclist *fclist = NULL;
+ try
+ {
+ if (S_ISDIR(sb.st_mode))
+ {
+ fclist = new sefs_filesystem(argv[optind], NULL, NULL);
+ }
+ else if (sefs_db::isDB(argv[optind]))
+ {
+ fclist = new sefs_db(argv[optind], NULL, NULL);
+ }
+ else
+ {
+ fclist = new sefs_fcfile(argv[optind], NULL, NULL);
+ }
+
+ if (fclist->runQueryMap(query, print_entry, NULL) < 0)
+ {
+ throw runtime_error(strerror(errno));
+ }
+ }
+ catch(...)
+ {
+ delete query;
+ delete fclist;
+ exit(-1);
+ }
+
+ delete query;
+ delete fclist;
+ return 0;
+}
diff --git a/secmds/indexcon.cc b/secmds/indexcon.cc
new file mode 100644
index 0000000..dbbb4af
--- /dev/null
+++ b/secmds/indexcon.cc
@@ -0,0 +1,121 @@
+/**
+ * @file
+ *
+ * Command-line program that builds a libsefs database of file
+ * contexts.
+ *
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ *
+ * Copyright (C) 2003-2007 Tresys Technology, LLC
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * indexcon: a tool for indexing the security contexts of filesystem entities
+ */
+
+#include <config.h>
+
+#include <sefs/db.hh>
+#include <sefs/filesystem.hh>
+
+using namespace std;
+
+#include <iostream>
+#include <getopt.h>
+
+#define COPYRIGHT_INFO "Copyright (C) 2003-2007 Tresys Technology, LLC"
+
+static struct option const longopts[] = {
+ {"directory", required_argument, NULL, 'd'},
+ {"help", no_argument, NULL, 'h'},
+ {"version", no_argument, NULL, 'V'},
+ {NULL, 0, NULL, 0}
+};
+
+static void usage(const char *program_name, bool brief)
+{
+ cout << "Usage: " << program_name << " FILE [OPTIONS]" << endl << endl;
+ if (brief)
+ {
+ cout << "\tTry " << program_name << " --help for more help." << endl << endl;
+ return;
+ }
+ cout << "Index SELinux contexts on the filesystem." << endl;
+ cout << endl;
+ cout << " -d DIR, --directory=DIR start scanning at directory DIR (default \"/\")" << endl;
+ cout << " -h, --help print this help text and exit" << endl;
+ cout << " -V, --version print version information and exit" << endl;
+}
+
+int main(int argc, char *argv[])
+{
+ int optc;
+
+ char *outfilename = NULL, *dir = "/";
+
+ while ((optc = getopt_long(argc, argv, "d:hV", longopts, NULL)) != -1)
+ {
+ switch (optc)
+ {
+ case 'd': // starting directory
+ dir = optarg;
+ break;
+ case 'h':
+ usage(argv[0], false);
+ exit(0);
+ case 'V':
+ cout << "indexcon " << VERSION << endl << COPYRIGHT_INFO << endl;
+ exit(0);
+ default:
+ usage(argv[0], true);
+ exit(1);
+ }
+ }
+ if (argc - optind > 1 || argc - optind < 1)
+ {
+ usage(argv[0], true);
+ exit(1);
+ }
+ else
+ {
+ outfilename = argv[optind];
+ }
+
+ if (outfilename == NULL)
+ {
+ usage(argv[0], true);
+ exit(1);
+ }
+
+ sefs_filesystem *fs = NULL;
+ sefs_db *db = NULL;
+ try
+ {
+ fs = new sefs_filesystem(dir, NULL, NULL);
+ db = new sefs_db(fs, NULL, NULL);
+ db->save(outfilename);
+ }
+ catch(...)
+ {
+ delete fs;
+ delete db;
+ exit(2);
+ }
+
+ delete fs;
+ delete db;
+
+ return 0;
+}
diff --git a/secmds/replcon.cc b/secmds/replcon.cc
new file mode 100644
index 0000000..34f7c1a
--- /dev/null
+++ b/secmds/replcon.cc
@@ -0,0 +1,358 @@
+/**
+ * @file
+ *
+ * A tool for replacing file contexts in SELinux.
+ *
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ *
+ * Copyright (C) 2003-2007 Tresys Technology, LLC
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <config.h>
+
+#include <sefs/filesystem.hh>
+#include <sefs/query.hh>
+#include <selinux/selinux.h>
+#include <apol/util.h>
+
+using namespace std;
+
+#include <assert.h>
+#include <errno.h>
+#include <getopt.h>
+#include <iostream>
+#include <stdlib.h>
+
+#define COPYRIGHT_INFO "Copyright (C) 2003-2007 Tresys Technology, LLC"
+
+enum OPTIONS
+{
+ OPTION_CONTEXT = 256
+};
+
+static struct option const longopts[] = {
+ {"class", required_argument, NULL, 'c'},
+ {"type", required_argument, NULL, 't'},
+ {"user", required_argument, NULL, 'u'},
+ {"role", required_argument, NULL, 'r'},
+ {"mls-range", required_argument, NULL, 'm'},
+ {"path", required_argument, NULL, 'p'},
+ {"regex", no_argument, NULL, 'R'},
+ {"context", required_argument, NULL, OPTION_CONTEXT},
+ {"verbose", no_argument, NULL, 'v'},
+ {"help", no_argument, NULL, 'h'},
+ {"version", no_argument, NULL, 'V'},
+ {NULL, 0, NULL, 0}
+};
+
+extern int lsetfilecon_raw(const char *, security_context_t) __attribute__ ((weak));
+
+/**
+ * As that setools must work with older libselinux versions that may
+ * not have the _raw() functions, declare them as weak. If libselinux
+ * does indeed have the new functions then use them; otherwise
+ * fallback to the originals.
+ */
+static int replcon_lsetfilecon(const char *path, security_context_t context)
+{
+ if (lsetfilecon_raw != NULL)
+ {
+ return lsetfilecon_raw(path, context);
+ }
+ else
+ {
+ return lsetfilecon(path, context);
+ }
+}
+
+struct replcon_info
+{
+ bool verbose, mls;
+ apol_context_t *replcon;
+};
+
+static void usage(const char *program_name, bool brief)
+{
+ cout << "Usage: " << program_name << " NEW_CONTEXT DIR [OPTIONS] [EXPRESSION]" << endl << endl;
+ if (brief)
+ {
+ cout << "\tTry " << program_name << " --help for more help." << endl << endl;
+ return;
+ }
+
+ cout << "Replace SELinux file contexts for files matching a given context." << endl << endl;
+
+ cout << "REQUIRED ARGUMENTS :" << endl;
+ cout << " NEW_CONTEXT partial or full context to relabel" << endl;
+ cout << " DIR starting directory to replace" << endl;
+ cout << endl;
+ cout << "EXPRESSION:" << endl;
+ cout << " -t TYPE, --type=TYPE find contexts with type TYPE" << endl;
+ cout << " -u USER, --user=USER find contexts with user USER" << endl;
+ cout << " -r ROLE, --role=ROLE find contexts with role ROLE" << endl;
+ cout << " -m RANGE, --mls-range=RANGE find contexts with MLS range RANGE" << endl;
+ cout << " --context=CONTEXT partial or full context to find" << endl;
+ cout << " (overrides expression options above)" << endl;
+ cout << " -p PATH, --path=PATH find files in PATH" << endl;
+ cout << " -c CLASS, --class=CLASS find files of object class CLASS" << endl;
+ cout << endl;
+
+ cout << "OPTIONS:" << endl;
+ cout << " -R, --regex enable regular expressions" << endl;
+ cout << " -v, --verbose show context of matching files" << endl;
+ cout << " -h, --help print this help text and exit" << endl;
+ cout << " -V, --version print version information and exit" << endl;
+ cout << endl;
+ cout << "If the fclist does not contain MLS ranges and -m was given," << endl;
+ cout << "then the search will return nothing." << endl;
+ cout << endl;
+ cout << "NEW_CONTEXT is as a colon separated list of user, role, type, and MLS range" << endl;
+ cout << "such as follows: user_u:object_r:user_t:s0. If a field is not specified," << endl;
+ cout << "that portion of the context will not be replaced." << endl;
+ cout << "Examples:" << endl;
+ cout << " replcon ::type_t: ." << endl;
+ cout << " Replace all files and subdirectories in current directory with" << endl;
+ cout << " type type_t, recursing within the directory." << endl;
+ cout << " replcon -u user_u *:role_r:* ." << endl;
+ cout << " Replace files that contain user_u with role role_r." << endl;
+ cout << " replcon --context ::type_t:so :::s0:c0 /tmp" << endl;
+ cout << " Replace files with type type_t and level s0 in /tmp with MLS" << endl;
+ cout << " range s0:c0." << endl;
+}
+
+static int replace_entry(sefs_fclist * fclist, const sefs_entry * e, void *arg)
+{
+ struct replcon_info *r = static_cast < struct replcon_info *>(arg);
+ const apol_context_t *scon = e->context();
+ const char *user, *role, *type;
+ char *con_str = NULL;
+ size_t len = 0;
+
+ // determine what the new context should be
+ if ((user = apol_context_get_user(r->replcon)) == NULL)
+ {
+ user = apol_context_get_user(scon);
+ }
+ if ((role = apol_context_get_role(r->replcon)) == NULL)
+ {
+ role = apol_context_get_role(scon);
+ }
+ if ((type = apol_context_get_type(r->replcon)) == NULL)
+ {
+ type = apol_context_get_type(scon);
+ }
+ if (apol_str_appendf(&con_str, &len, "%s:%s:%s", user, role, type) < 0)
+ {
+ return -1;
+ }
+ if (r->mls)
+ {
+ const apol_mls_range_t *apol_range = NULL;
+ char *range = NULL;
+ if ((apol_range = apol_context_get_range(r->replcon)) == NULL)
+ {
+ apol_range = apol_context_get_range(scon);
+ }
+ if ((range = apol_mls_range_render(NULL, apol_range)) == NULL || apol_str_appendf(&con_str, &len, ":%s", range) < 0)
+ {
+ free(range);
+ free(con_str);
+ return -1;
+ }
+ free(range);
+ }
+
+ if (r->verbose)
+ {
+ char *lcon = NULL, *rcon = NULL;
+ if (r->mls)
+ {
+ lcon = apol_context_render(NULL, r->replcon);
+ rcon = apol_context_render(NULL, scon);
+ }
+ else
+ {
+ if (asprintf(&lcon, "%s:%s:%s",
+ apol_context_get_user(r->replcon),
+ apol_context_get_role(r->replcon), apol_context_get_type(r->replcon)) < 0)
+ {
+ lcon = NULL;
+ }
+ if (asprintf(&rcon, "%s:%s:%s",
+ apol_context_get_user(scon), apol_context_get_role(scon), apol_context_get_type(scon)) < 0)
+ {
+ rcon = NULL;
+ }
+ }
+ if (lcon == NULL || rcon == NULL)
+ {
+ free(lcon);
+ free(rcon);
+ return -1;
+ }
+ printf("%s: %s --> %s\n", e->path(), lcon, rcon);
+ free(lcon);
+ free(rcon);
+ }
+
+ // until there is a way to create a security_context_t from a
+ // char *, simply perform the implicit cast below
+ if (replcon_lsetfilecon(e->path(), con_str) != 0)
+ {
+ cerr << "Could not set context " << con_str << " for file " << e->path() << "." << endl;
+ free(con_str);
+ return -1;
+ }
+
+ free(con_str);
+ return 0;
+}
+
+int main(int argc, char *argv[])
+{
+ int optc;
+ struct replcon_info r;
+
+ r.verbose = false;
+ r.replcon = NULL;
+ sefs_query *query = new sefs_query();
+
+ apol_context_t *context = NULL;
+ try
+ {
+ while ((optc = getopt_long(argc, argv, "t:u:r:m:p:c:RvhV", longopts, NULL)) != -1)
+ {
+ switch (optc)
+ {
+ case 't':
+ if (context == NULL)
+ {
+ query->type(optarg, false);
+ }
+ break;
+ case 'u':
+ if (context == NULL)
+ {
+ query->user(optarg);
+ }
+ break;
+ case 'r':
+ if (context == NULL)
+ {
+ query->role(optarg);
+ }
+ break;
+ case 'm':
+ if (context == NULL)
+ {
+ query->range(optarg, APOL_QUERY_EXACT);
+ }
+ break;
+ case OPTION_CONTEXT:
+ if ((context = apol_context_create_from_literal(optarg)) == NULL)
+ {
+ cerr << "Could not create source context." << endl;
+ throw runtime_error(strerror(errno));
+ }
+ break;
+ case 'p':
+ query->path(optarg);
+ break;
+ case 'c':
+ query->objectClass(optarg);
+ break;
+ case 'R':
+ query->regex(true);
+ break;
+ case 'v':
+ r.verbose = true;
+ break;
+ case 'h': // help
+ usage(argv[0], false);
+ exit(0);
+ case 'V': // version
+ cout << "replcon " << VERSION << endl << COPYRIGHT_INFO << endl;
+ exit(0);
+ default:
+ usage(argv[0], true);
+ exit(1);
+ }
+ if (context != NULL)
+ {
+ query->user(apol_context_get_user(context));
+ query->role(apol_context_get_role(context));
+ query->type(apol_context_get_type(context), false);
+ if (apol_context_get_range(context) != NULL)
+ {
+ char *rng = apol_mls_range_render(NULL, apol_context_get_range(context));
+ query->range(rng, APOL_QUERY_EXACT);
+ free(rng);
+ }
+ else
+ {
+ query->range(NULL, APOL_QUERY_EXACT);
+ }
+ }
+ }
+ }
+ catch(bad_alloc)
+ {
+ cerr << strerror(errno) << endl;
+ apol_context_destroy(&context);
+ delete query;
+ exit(-1);
+ }
+ apol_context_destroy(&context);
+
+ if (optind + 2 != argc)
+ {
+ usage(argv[0], 1);
+ delete query;
+ exit(-1);
+ }
+
+ sefs_fclist *fclist = NULL;
+ try
+ {
+ fclist = new sefs_filesystem(argv[optind + 1], NULL, NULL);
+ r.mls = fclist->isMLS();
+
+ if ((r.replcon = apol_context_create_from_literal(argv[optind])) == NULL)
+ {
+ cerr << "Could not create replacement context." << endl;
+ throw runtime_error(strerror(errno));
+ }
+
+ if (fclist->runQueryMap(query, replace_entry, &r) < 0)
+ {
+ throw runtime_error(strerror(errno));
+ }
+ }
+ catch(...)
+ {
+ delete query;
+ delete fclist;
+ apol_context_destroy(&(r.replcon));
+ exit(-1);
+ }
+
+ delete query;
+ delete fclist;
+ apol_context_destroy(&(r.replcon));
+ return 0;
+}
diff --git a/secmds/seinfo.c b/secmds/seinfo.c
new file mode 100644
index 0000000..fdf23e9
--- /dev/null
+++ b/secmds/seinfo.c
@@ -0,0 +1,2337 @@
+/**
+ * @file
+ *
+ * Command line tool for looking at a SELinux policy
+ * and getting various component elements and statistics.
+ *
+ * @author Frank Mayer mayerf@tresys.com
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author David Windsor dwindsor@tresys.com
+ * @author Steve Lawrence slawrence@tresys.com
+ *
+ * Copyright (C) 2003-2008 Tresys Technology, LLC
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <config.h>
+
+/* libapol */
+#include <apol/policy.h>
+#include <apol/policy-query.h>
+#include <apol/render.h>
+#include <apol/util.h>
+#include <apol/vector.h>
+
+/* libqpol */
+#include <qpol/policy.h>
+#include <qpol/util.h>
+
+/* other */
+#include <errno.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <getopt.h>
+
+#define COPYRIGHT_INFO "Copyright (C) 2003-2007 Tresys Technology, LLC"
+
+/* placeholder for empty set in constraint statements */
+#define CONSTRAIN_NULL_SET "<empty set>"
+
+static char *policy_file = NULL;
+
+static void print_type_attrs(FILE * fp, const qpol_type_t * type_datum, const apol_policy_t * policydb, const int expand);
+static void print_attr_types(FILE * fp, const qpol_type_t * type_datum, const apol_policy_t * policydb, const int expand);
+static void print_user_roles(FILE * fp, const qpol_user_t * user_datum, const apol_policy_t * policydb, const int expand);
+static void print_role_types(FILE * fp, const qpol_role_t * role_datum, const apol_policy_t * policydb, const int expand);
+static void print_bool_state(FILE * fp, const qpol_bool_t * bool_datum, const apol_policy_t * policydb, const int expand);
+static void print_class_perms(FILE * fp, const qpol_class_t * class_datum, const apol_policy_t * policydb, const int expand);
+static void print_cat_sens(FILE * fp, const qpol_cat_t * cat_datum, const apol_policy_t * policydb, const int expand);
+static int qpol_cat_datum_compare(const void *datum1, const void *datum2, void *data);
+static int qpol_level_datum_compare(const void *datum1, const void *datum2, void *data);
+
+enum opt_values
+{
+ OPT_SENSITIVITY = 256, OPT_CATEGORY,
+ OPT_INITIALSID, OPT_FS_USE, OPT_GENFSCON,
+ OPT_NETIFCON, OPT_NODECON, OPT_PORTCON, OPT_PROTOCOL,
+ OPT_PERMISSIVE, OPT_POLCAP,
+ OPT_ALL, OPT_STATS, OPT_CONSTRAIN
+};
+
+static struct option const longopts[] = {
+ {"class", optional_argument, NULL, 'c'},
+ {"sensitivity", optional_argument, NULL, OPT_SENSITIVITY},
+ {"category", optional_argument, NULL, OPT_CATEGORY},
+ {"type", optional_argument, NULL, 't'},
+ {"attribute", optional_argument, NULL, 'a'},
+ {"role", optional_argument, NULL, 'r'},
+ {"user", optional_argument, NULL, 'u'},
+ {"bool", optional_argument, NULL, 'b'},
+ {"constrain", no_argument, NULL, OPT_CONSTRAIN},
+ {"initialsid", optional_argument, NULL, OPT_INITIALSID},
+ {"fs_use", optional_argument, NULL, OPT_FS_USE},
+ {"genfscon", optional_argument, NULL, OPT_GENFSCON},
+ {"netifcon", optional_argument, NULL, OPT_NETIFCON},
+ {"nodecon", optional_argument, NULL, OPT_NODECON},
+ {"permissive", optional_argument, NULL, OPT_PERMISSIVE},
+ {"polcap", optional_argument, NULL, OPT_POLCAP},
+ {"portcon", optional_argument, NULL, OPT_PORTCON},
+ {"protocol", required_argument, NULL, OPT_PROTOCOL},
+ {"stats", no_argument, NULL, OPT_STATS},
+ {"all", no_argument, NULL, OPT_ALL},
+ {"line-breaks", no_argument, NULL, 'l'},
+ {"expand", no_argument, NULL, 'x'},
+ {"help", no_argument, NULL, 'h'},
+ {"version", no_argument, NULL, 'V'},
+ {NULL, 0, NULL, 0}
+};
+
+/**
+ * Prints a message specifying program options and usage.
+ *
+ * @param program_name Name of the program
+ * @param brief Flag indicating whether brief usage
+ * information should be displayed
+ */
+void usage(const char *program_name, int brief)
+{
+ printf("Usage: %s [OPTIONS] [EXPRESSION] [POLICY ...]\n\n", program_name);
+ if (brief) {
+ printf("\tTry %s --help for more help.\n\n", program_name);
+ return;
+ }
+ printf("Print information about the components of a SELinux policy.\n\n");
+ printf("EXPRESSIONS:\n");
+ printf(" -c[NAME], --class[=NAME] print object classes\n");
+ printf(" --sensitivity[=NAME] print sensitivities\n");
+ printf(" --category[=NAME] print categories\n");
+ printf(" -t[NAME], --type[=NAME] print types (no aliases or attributes)\n");
+ printf(" -a[NAME], --attribute[=NAME] print type attributes\n");
+ printf(" -r[NAME], --role[=NAME] print roles\n");
+ printf(" -u[NAME], --user[=NAME] print users\n");
+ printf(" -b[NAME], --bool[=NAME] print conditional booleans\n");
+ printf(" --constrain print constrain statements\n");
+ printf(" --initialsid[=NAME] print initial SIDs\n");
+ printf(" --fs_use[=TYPE] print fs_use statements\n");
+ printf(" --genfscon[=TYPE] print genfscon statements\n");
+ printf(" --netifcon[=NAME] print netif contexts\n");
+ printf(" --nodecon[=ADDR] print node contexts\n");
+ printf(" --permissive print permissive types\n");
+ printf(" --polcap print policy capabilities\n");
+ printf(" --portcon[=PORT] print port contexts\n");
+ printf(" --protocol=PROTO specify a protocol for portcons\n");
+ printf(" --all print all of the above\n");
+ printf("OPTIONS:\n");
+ printf(" -x, --expand show more info for specified components\n");
+ printf(" --stats print useful policy statistics\n");
+ printf(" -l, --line-breaks print line breaks in constrain statements\n");
+ printf(" -h, --help print this help text and exit\n");
+ printf(" -V, --version print version information and exit\n");
+ printf("\n");
+ printf("For component options, if NAME is provided, then only show info for\n");
+ printf("NAME. Specifying a name is most useful when used with the -x option.\n");
+ printf("If no option is provided, display useful policy statistics (-s).\n");
+ printf("\n");
+ printf("The default source policy, or if that is unavailable the default binary\n");
+ printf("policy, will be opened if no policy is provided.\n\n");
+}
+
+/**
+ * Prints statistics regarding a policy's components.
+ *
+ * @param fp Reference to a file to which to print
+ * policy statistics
+ * @param policydb Reference to a policy
+ *
+ * @return 0 on success, < 0 on error.
+ */
+static int print_stats(FILE * fp, const apol_policy_t * policydb)
+{
+ int retval = -1;
+ unsigned int n_perms = 0;
+ qpol_iterator_t *iter = NULL;
+ apol_type_query_t *type_query = NULL;
+ apol_attr_query_t *attr_query = NULL;
+ apol_perm_query_t *perm_query = NULL;
+ apol_vector_t *perms = NULL, *v = NULL;
+ qpol_policy_t *q = apol_policy_get_qpol(policydb);
+ char *str = NULL;
+ size_t n_types = 0, n_attrs = 0;
+ size_t n_classes = 0, n_users = 0, n_roles = 0, n_bools = 0, n_conds = 0, n_levels = 0,
+ n_cats = 0, n_portcons = 0, n_netifcons = 0, n_nodecons = 0, n_fsuses = 0,
+ n_genfscons = 0, n_allows = 0, n_neverallows = 0, n_auditallows = 0, n_dontaudits = 0,
+ n_typetrans = 0, n_typechanges = 0, n_typemembers = 0, n_isids = 0, n_roleallows = 0,
+ n_roletrans = 0, n_rangetrans = 0, n_constr = 0, n_vtrans = 0, n_permissives = 0,
+ n_polcaps = 0;
+
+ assert(policydb != NULL);
+
+ fprintf(fp, "\nStatistics for policy file: %s\n", policy_file);
+
+ if (!(str = apol_policy_get_version_type_mls_str(policydb)))
+ goto cleanup;
+
+ fprintf(fp, "Policy Version & Type: ");
+ fprintf(fp, "%s\n", str);
+ free(str);
+
+ if (qpol_policy_get_class_iter(q, &iter))
+ goto cleanup;
+ if (qpol_iterator_get_size(iter, &n_classes))
+ goto cleanup;
+ qpol_iterator_destroy(&iter);
+
+ perm_query = apol_perm_query_create();
+ if (!perm_query)
+ goto cleanup;
+
+ /* Match all perms */
+ if (apol_perm_get_by_query(policydb, perm_query, &perms))
+ goto cleanup;
+
+ n_perms = apol_vector_get_size(perms);
+ apol_perm_query_destroy(&perm_query);
+ apol_vector_destroy(&perms);
+ fprintf(fp, "\n Classes: %7zd Permissions: %7d\n", n_classes, n_perms);
+
+ /* sensitivities/categories */
+ if (qpol_policy_get_level_iter(q, &iter))
+ goto cleanup;
+ if (qpol_iterator_get_size(iter, &n_levels))
+ goto cleanup;
+
+ qpol_iterator_destroy(&iter);
+ if (qpol_policy_get_cat_iter(q, &iter))
+ goto cleanup;
+ if (qpol_iterator_get_size(iter, &n_cats))
+ goto cleanup;
+ qpol_iterator_destroy(&iter);
+ fprintf(fp, " Sensitivities: %7zd Categories: %7zd\n", n_levels, n_cats);
+
+ /* types */
+ type_query = apol_type_query_create();
+ if (!type_query)
+ goto cleanup;
+ if (apol_type_get_by_query(policydb, type_query, &v) < 0)
+ goto cleanup;
+
+ n_types = apol_vector_get_size(v);
+ apol_type_query_destroy(&type_query);
+ apol_vector_destroy(&v);
+
+ attr_query = apol_attr_query_create();
+ if (!attr_query)
+ goto cleanup;
+ if (apol_attr_get_by_query(policydb, attr_query, &v) < 0)
+ goto cleanup;
+
+ n_attrs = apol_vector_get_size(v);
+ apol_attr_query_destroy(&attr_query);
+ apol_vector_destroy(&v);
+
+ fprintf(fp, " Types: %7zd Attributes: %7zd\n", n_types, n_attrs);
+ qpol_iterator_destroy(&iter);
+
+ /* users/roles */
+ if (qpol_policy_get_user_iter(q, &iter))
+ goto cleanup;
+ if (qpol_iterator_get_size(iter, &n_users))
+ goto cleanup;
+ qpol_iterator_destroy(&iter);
+ if (qpol_policy_get_role_iter(q, &iter))
+ goto cleanup;
+ if (qpol_iterator_get_size(iter, &n_roles))
+ goto cleanup;
+ qpol_iterator_destroy(&iter);
+ fprintf(fp, " Users: %7zd Roles: %7zd\n", n_users, n_roles);
+
+ /* booleans/cond. exprs. */
+ if (qpol_policy_get_bool_iter(q, &iter))
+ goto cleanup;
+ if (qpol_iterator_get_size(iter, &n_bools))
+ goto cleanup;
+ qpol_iterator_destroy(&iter);
+ if (qpol_policy_get_cond_iter(q, &iter))
+ goto cleanup;
+ if (qpol_iterator_get_size(iter, &n_conds))
+ goto cleanup;
+ qpol_iterator_destroy(&iter);
+ fprintf(fp, " Booleans: %7zd Cond. Expr.: %7zd\n", n_bools, n_conds);
+
+ /* allow/neverallow */
+ if (qpol_policy_get_avrule_iter(q, QPOL_RULE_ALLOW, &iter))
+ goto cleanup;
+ if (qpol_iterator_get_size(iter, &n_allows))
+ goto cleanup;
+ qpol_iterator_destroy(&iter);
+ if (qpol_policy_has_capability(q, QPOL_CAP_NEVERALLOW)) {
+ if (qpol_policy_get_avrule_iter(q, QPOL_RULE_NEVERALLOW, &iter))
+ goto cleanup;
+ if (qpol_iterator_get_size(iter, &n_neverallows))
+ goto cleanup;
+ } else {
+ n_neverallows = 0;
+ }
+ qpol_iterator_destroy(&iter);
+ fprintf(fp, " Allow: %7zd Neverallow: %7zd\n", n_allows, n_neverallows);
+
+ /* auditallow/dontaudit */
+ if (qpol_policy_get_avrule_iter(q, QPOL_RULE_AUDITALLOW, &iter))
+ goto cleanup;
+ if (qpol_iterator_get_size(iter, &n_auditallows))
+ goto cleanup;
+ qpol_iterator_destroy(&iter);
+ if (qpol_policy_get_avrule_iter(q, QPOL_RULE_DONTAUDIT, &iter))
+ goto cleanup;
+ if (qpol_iterator_get_size(iter, &n_dontaudits))
+ goto cleanup;
+ qpol_iterator_destroy(&iter);
+ fprintf(fp, " Auditallow: %7zd Dontaudit: %7zd\n", n_auditallows, n_dontaudits);
+
+ /* type_transition/type_change */
+ if (qpol_policy_get_terule_iter(q, QPOL_RULE_TYPE_TRANS, &iter))
+ goto cleanup;
+ if (qpol_iterator_get_size(iter, &n_typetrans))
+ goto cleanup;
+ qpol_iterator_destroy(&iter);
+ if (qpol_policy_get_terule_iter(q, QPOL_RULE_TYPE_CHANGE, &iter))
+ goto cleanup;
+ if (qpol_iterator_get_size(iter, &n_typechanges))
+ goto cleanup;
+ qpol_iterator_destroy(&iter);
+ fprintf(fp, " Type_trans: %7zd Type_change: %7zd\n", n_typetrans, n_typechanges);
+
+ /* type_member/role allow */
+ if (qpol_policy_get_terule_iter(q, QPOL_RULE_TYPE_MEMBER, &iter))
+ goto cleanup;
+ if (qpol_iterator_get_size(iter, &n_typemembers))
+ goto cleanup;
+ qpol_iterator_destroy(&iter);
+ if (qpol_policy_get_role_allow_iter(q, &iter))
+ goto cleanup;
+ if (qpol_iterator_get_size(iter, &n_roleallows))
+ goto cleanup;
+ qpol_iterator_destroy(&iter);
+ fprintf(fp, " Type_member: %7zd Role allow: %7zd\n", n_typemembers, n_roleallows);
+
+ /* role_trans/range_trans */
+ if (qpol_policy_get_role_trans_iter(q, &iter))
+ goto cleanup;
+ if (qpol_iterator_get_size(iter, &n_roletrans))
+ goto cleanup;
+ qpol_iterator_destroy(&iter);
+ if (qpol_policy_get_range_trans_iter(q, &iter))
+ goto cleanup;
+ if (qpol_iterator_get_size(iter, &n_rangetrans))
+ goto cleanup;
+ qpol_iterator_destroy(&iter);
+ fprintf(fp, " Role_trans: %7zd Range_trans: %7zd\n", n_roletrans, n_rangetrans);
+
+ /* constraints/validatetrans */
+ if (qpol_policy_get_constraint_iter(q, &iter))
+ goto cleanup;
+ if (qpol_iterator_get_size(iter, &n_constr))
+ goto cleanup;
+ qpol_iterator_destroy(&iter);
+ if (qpol_policy_get_validatetrans_iter(q, &iter))
+ goto cleanup;
+ if (qpol_iterator_get_size(iter, &n_vtrans))
+ goto cleanup;
+ qpol_iterator_destroy(&iter);
+ fprintf(fp, " Constraints: %7zd Validatetrans: %7zd\n", n_constr, n_vtrans);
+
+ /* isids/fs_use */
+ if (qpol_policy_get_isid_iter(q, &iter))
+ goto cleanup;
+ if (qpol_iterator_get_size(iter, &n_isids))
+ goto cleanup;
+ qpol_iterator_destroy(&iter);
+ if (qpol_policy_get_fs_use_iter(q, &iter))
+ goto cleanup;
+ if (qpol_iterator_get_size(iter, &n_fsuses))
+ goto cleanup;
+ qpol_iterator_destroy(&iter);
+ fprintf(fp, " Initial SIDs: %7zd Fs_use: %7zd\n", n_isids, n_fsuses);
+
+ /* genfscon/portcon */
+ if (qpol_policy_get_genfscon_iter(q, &iter))
+ goto cleanup;
+ if (qpol_iterator_get_size(iter, &n_genfscons))
+ goto cleanup;
+ qpol_iterator_destroy(&iter);
+ if (qpol_policy_get_portcon_iter(q, &iter))
+ goto cleanup;
+ if (qpol_iterator_get_size(iter, &n_portcons))
+ goto cleanup;
+ qpol_iterator_destroy(&iter);
+ fprintf(fp, " Genfscon: %7zd Portcon: %7zd\n", n_genfscons, n_portcons);
+
+ /* netifcon/nodecon */
+ if (qpol_policy_get_netifcon_iter(q, &iter))
+ goto cleanup;
+ if (qpol_iterator_get_size(iter, &n_netifcons))
+ goto cleanup;
+ qpol_iterator_destroy(&iter);
+ if (qpol_policy_get_nodecon_iter(q, &iter))
+ goto cleanup;
+ if (qpol_iterator_get_size(iter, &n_nodecons))
+ goto cleanup;
+ qpol_iterator_destroy(&iter);
+ fprintf(fp, " Netifcon: %7zd Nodecon: %7zd\n", n_netifcons, n_nodecons);
+
+ /* permissives/polcaps */
+ if (qpol_policy_get_permissive_iter(q, &iter))
+ goto cleanup;
+ if (qpol_iterator_get_size(iter, &n_permissives))
+ goto cleanup;
+ qpol_iterator_destroy(&iter);
+ if (qpol_policy_get_polcap_iter(q, &iter))
+ goto cleanup;
+ if (qpol_iterator_get_size(iter, &n_polcaps))
+ goto cleanup;
+ qpol_iterator_destroy(&iter);
+ fprintf(fp, " Permissives: %7zd Polcap: %7zd\n", n_permissives, n_polcaps);
+
+ fprintf(fp, "\n");
+
+ retval = 0;
+ cleanup:
+ qpol_iterator_destroy(&iter);
+ apol_type_query_destroy(&type_query);
+ apol_attr_query_destroy(&attr_query);
+ apol_perm_query_destroy(&perm_query);
+ apol_vector_destroy(&v);
+ apol_vector_destroy(&perms);
+ return retval;
+}
+
+/**
+ * Prints statistics regarding a policy's object classes.
+ * If this function is given a name, it will attempt to
+ * print statistics about a particular object class; otherwise
+ * the function prints statistics about all of the policy's object
+ * classes.
+ *
+ * @param fp Reference to a file to which to print statistics
+ * @param name Reference to an object class' name; if NULL,
+ * all object classes will be considered
+ * @param expand Flag indicating whether to print object class
+ * permissions
+ * @param policydb Reference to a policy
+ *
+ * @return 0 on success, < 0 on error.
+ */
+static int print_classes(FILE * fp, const char *name, int expand, const apol_policy_t * policydb)
+{
+ int retval = -1;
+ qpol_iterator_t *iter = NULL;
+ size_t n_classes = 0;
+ const qpol_class_t *class_datum = NULL;
+ qpol_policy_t *q = apol_policy_get_qpol(policydb);
+ if (name != NULL) {
+ if (qpol_policy_get_class_by_name(q, name, &class_datum))
+ goto cleanup;
+ print_class_perms(fp, class_datum, policydb, expand);
+ } else {
+ if (qpol_policy_get_class_iter(q, &iter))
+ goto cleanup;
+ if (qpol_iterator_get_size(iter, &n_classes))
+ goto cleanup;
+ fprintf(fp, "Object classes: %d\n", (int)n_classes);
+
+ for (; !qpol_iterator_end(iter); qpol_iterator_next(iter)) {
+ if (qpol_iterator_get_item(iter, (void **)&class_datum))
+ goto cleanup;
+ print_class_perms(fp, class_datum, policydb, expand);
+ }
+ qpol_iterator_destroy(&iter);
+ }
+
+ retval = 0;
+ cleanup:
+ qpol_iterator_destroy(&iter);
+ return retval;
+}
+
+/**
+ * Prints statistics regarding a policy's types.
+ * If this function is given a name, it will attempt to
+ * print statistics about a particular type; otherwise
+ * the function prints statistics about all of the policy's types.
+ *
+ * @param fp Reference to a file to which to print statistics
+ * @param name Reference to a type's name; if NULL,
+ * all object classes will be considered
+ * @param expand Flag indicating whether to print each type's attributes
+ * @param policydb Reference to a policy
+ *
+ * @return 0 on success, < 0 on error.
+ */
+static int print_types(FILE * fp, const char *name, int expand, const apol_policy_t * policydb)
+{
+ int retval = -1;
+ const qpol_type_t *type_datum = NULL;
+ qpol_iterator_t *iter = NULL;
+ apol_vector_t *type_vector = NULL;
+ qpol_policy_t *q = apol_policy_get_qpol(policydb);
+ size_t vector_sz;
+
+ if (name != NULL) {
+ if (qpol_policy_get_type_by_name(q, name, &type_datum))
+ goto cleanup;
+ }
+
+ /* Find the number of types in the policy */
+ if (apol_type_get_by_query(policydb, NULL, &type_vector))
+ goto cleanup;
+ vector_sz = apol_vector_get_size(type_vector);
+ apol_vector_destroy(&type_vector);
+
+ if (name == NULL) {
+ fprintf(fp, "\nTypes: %zd\n", vector_sz);
+ }
+
+ /* if name was provided, only print that name */
+ if (name != NULL) {
+ if (qpol_policy_get_type_by_name(q, name, &type_datum))
+ goto cleanup;
+ print_type_attrs(fp, type_datum, policydb, expand);
+ } else {
+ if (qpol_policy_get_type_iter(q, &iter))
+ goto cleanup;
+ /* Print all type names */
+ for (; !qpol_iterator_end(iter); qpol_iterator_next(iter)) {
+ if (qpol_iterator_get_item(iter, (void **)&type_datum))
+ goto cleanup;
+ print_type_attrs(fp, type_datum, policydb, expand);
+ }
+ }
+
+ retval = 0;
+ cleanup:
+ qpol_iterator_destroy(&iter);
+ return retval;
+}
+
+/**
+ * Prints statistics regarding a policy's attributes.
+ * If this function is given a name, it will attempt to
+ * print statistics about a particular attribute; otherwise
+ * the function prints statistics about all of the policy's
+ * attributes.
+ *
+ * @param fp Reference to a file to which to print statistics
+ * @param name Reference to an attribute's name; if NULL,
+ * all object classes will be considered
+ * @param expand Flag indicating whether to print each attribute's
+ * allowed types
+ * @param policydb Reference to a policy
+ *
+ * @return 0 on success, < 0 on error.
+ */
+static int print_attribs(FILE * fp, const char *name, int expand, const apol_policy_t * policydb)
+{
+ int retval = -1;
+ apol_attr_query_t *attr_query = NULL;
+ apol_vector_t *v = NULL;
+ const qpol_type_t *type_datum = NULL;
+ size_t n_attrs, i;
+
+ /* we are only printing information about 1 attribute */
+ if (name != NULL) {
+ attr_query = apol_attr_query_create();
+ if (!attr_query)
+ goto cleanup;
+ if (apol_attr_query_set_attr(policydb, attr_query, name))
+ goto cleanup;
+ if (apol_attr_get_by_query(policydb, attr_query, &v))
+ goto cleanup;
+ apol_attr_query_destroy(&attr_query);
+ if (apol_vector_get_size(v) == 0) {
+ apol_vector_destroy(&v);
+ ERR(policydb, "Provided attribute (%s) is not a valid attribute name.", name);
+ goto cleanup;
+ }
+
+ type_datum = apol_vector_get_element(v, (size_t) 0);
+ print_attr_types(fp, type_datum, policydb, expand);
+ } else {
+ attr_query = apol_attr_query_create();
+ if (!attr_query)
+ goto cleanup;
+ if (apol_attr_get_by_query(policydb, attr_query, &v))
+ goto cleanup;
+ apol_attr_query_destroy(&attr_query);
+ n_attrs = apol_vector_get_size(v);
+
+ fprintf(fp, "\nAttributes: %zd\n", n_attrs);
+ for (i = 0; i < n_attrs; i++) {
+ /* get qpol_type_t* item from vector */
+ type_datum = (qpol_type_t *) apol_vector_get_element(v, (size_t) i);
+ if (!type_datum)
+ goto cleanup;
+ print_attr_types(fp, type_datum, policydb, expand);
+ }
+ }
+ apol_vector_destroy(&v);
+
+ retval = 0;
+ cleanup:
+ apol_attr_query_destroy(&attr_query);
+ apol_vector_destroy(&v);
+ return retval;
+}
+
+/**
+ * Prints statistics regarding a policy's roles.
+ * If this function is given a name, it will attempt to
+ * print statistics about a particular role; otherwise
+ * the function prints statistics about all of the policy's roles.
+ *
+ * @param fp Reference to a file to which to print statistics
+ * @param name Reference to an role's name; if NULL,
+ * all roles will be considered
+ * @param expand Flag indicating whether to print valid users
+ * for each role
+ * @param policydb Reference to a policy
+ *
+ * @return 0 on success, < 0 on error.
+ */
+static int print_roles(FILE * fp, const char *name, int expand, const apol_policy_t * policydb)
+{
+ int retval = -1;
+ const qpol_role_t *role_datum = NULL;
+ qpol_iterator_t *iter = NULL;
+ qpol_policy_t *q = apol_policy_get_qpol(policydb);
+ size_t n_roles = 0;
+
+ if (name != NULL) {
+ if (qpol_policy_get_role_by_name(q, name, &role_datum))
+ goto cleanup;
+ print_role_types(fp, role_datum, policydb, expand);
+ } else {
+ if (qpol_policy_get_role_iter(q, &iter))
+ goto cleanup;
+ if (qpol_iterator_get_size(iter, &n_roles))
+ goto cleanup;
+ fprintf(fp, "\nRoles: %d\n", (int)n_roles);
+
+ for (; !qpol_iterator_end(iter); qpol_iterator_next(iter)) {
+ if (qpol_iterator_get_item(iter, (void **)&role_datum))
+ goto cleanup;
+ print_role_types(fp, role_datum, policydb, expand);
+ }
+ qpol_iterator_destroy(&iter);
+ }
+
+ retval = 0;
+ cleanup:
+ qpol_iterator_destroy(&iter);
+ return retval;
+}
+
+/**
+ * Prints statistics regarding a policy's booleans.
+ * If this function is given a name, it will attempt to
+ * print statistics about a particular boolean; otherwise
+ * the function prints statistics about all of the policy's booleans.
+ *
+ * @param fp Reference to a file to which to print statistics
+ * @param name Reference to a boolean's name; if NULL,
+ * all booleans will be considered
+ * @param expand Flag indicating whether to print each
+ * boolean's default state
+ * @param policydb Reference to a policy
+ *
+ * @return 0 on success, < 0 on error.
+ */
+static int print_booleans(FILE * fp, const char *name, int expand, const apol_policy_t * policydb)
+{
+ int retval = -1;
+ qpol_bool_t *bool_datum = NULL;
+ qpol_iterator_t *iter = NULL;
+ qpol_policy_t *q = apol_policy_get_qpol(policydb);
+ size_t n_bools = 0;
+
+ if (name != NULL) {
+ if (qpol_policy_get_bool_by_name(q, name, &bool_datum))
+ goto cleanup;
+ print_bool_state(fp, bool_datum, policydb, expand);
+ } else {
+ if (qpol_policy_get_bool_iter(q, &iter))
+ goto cleanup;
+ if (qpol_iterator_get_size(iter, &n_bools))
+ goto cleanup;
+ fprintf(fp, "\nConditional Booleans: %zd\n", n_bools);
+ for (; !qpol_iterator_end(iter); qpol_iterator_next(iter)) {
+ if (qpol_iterator_get_item(iter, (void **)&bool_datum))
+ goto cleanup;
+ print_bool_state(fp, bool_datum, policydb, expand);
+ }
+ qpol_iterator_destroy(&iter);
+ }
+
+ retval = 0;
+ cleanup:
+ qpol_iterator_destroy(&iter);
+ return retval;
+}
+
+/**
+ * Prints statistics regarding a policy's users.
+ * If this function is given a name, it will attempt to
+ * print statistics about a particular user; otherwise
+ * the function prints statistics about all of the policy's
+ * users.
+ *
+ * @param fp Reference to a file to which to print statistics
+ * @param name Reference to a user's name; if NULL,
+ * all users will be considered
+ * @param expand Flag indicating whether to print each user's
+ * roles
+ * @param policydb Reference to a policy
+ *
+ * @return 0 on success, < 0 on error.
+ */
+static int print_users(FILE * fp, const char *name, int expand, const apol_policy_t * policydb)
+{
+ int retval = -1;
+ qpol_iterator_t *iter = NULL;
+ const qpol_user_t *user_datum = NULL;
+ qpol_policy_t *q = apol_policy_get_qpol(policydb);
+ size_t n_users = 0;
+
+ if (name != NULL) {
+ if (qpol_policy_get_user_by_name(q, name, &user_datum))
+ goto cleanup;
+ print_user_roles(fp, user_datum, policydb, expand);
+ } else {
+ if (qpol_policy_get_user_iter(q, &iter))
+ goto cleanup;
+ if (qpol_iterator_get_size(iter, &n_users))
+ goto cleanup;
+ fprintf(fp, "\nUsers: %d\n", (int)n_users);
+
+ for (; !qpol_iterator_end(iter); qpol_iterator_next(iter)) {
+ if (qpol_iterator_get_item(iter, (void **)&user_datum))
+ goto cleanup;
+ print_user_roles(fp, user_datum, policydb, expand);
+ }
+ qpol_iterator_destroy(&iter);
+ }
+
+ retval = 0;
+ cleanup:
+ qpol_iterator_destroy(&iter);
+ return retval;
+}
+
+/**
+ * Prints statistics regarding a policy's MLS sensitivities.
+ * If this function is given a name, it will attempt to
+ * print statistics about a particular sensitivity; otherwise
+ * the function prints statistics about all of the policy's
+ * sensitivities.
+ *
+ * @param fp Reference to a file to which to print statistics
+ * @param name Reference to a sensitivity's name; if NULL,
+ * all sensitivities will be considered
+ * @param expand Flag indicating whether to print each
+ * sensitivity's categories
+ * @param policydb Reference to a policy
+ *
+ * @return 0 on success, < 0 on error.
+ */
+static int print_sens(FILE * fp, const char *name, int expand, const apol_policy_t * policydb)
+{
+ int retval = -1;
+ size_t i;
+ char *tmp = NULL;
+ const char *lvl_name = NULL;
+ apol_level_query_t *query = NULL;
+ apol_vector_t *v = NULL;
+ const qpol_level_t *level = NULL;
+ apol_mls_level_t *ap_mls_lvl = NULL;
+ qpol_policy_t *q = apol_policy_get_qpol(policydb);
+
+ query = apol_level_query_create();
+ if (!query) {
+ ERR(policydb, "%s", strerror(ENOMEM));
+ goto cleanup;
+ }
+ if (apol_level_query_set_sens(policydb, query, name))
+ goto cleanup;
+ if (apol_level_get_by_query(policydb, query, &v))
+ goto cleanup;
+
+ if (!name)
+ fprintf(fp, "\nSensitivities: %zd\n", apol_vector_get_size(v));
+ for (i = 0; i < apol_vector_get_size(v); i++) {
+ level = apol_vector_get_element(v, i);
+ if (qpol_level_get_name(q, level, &lvl_name))
+ goto cleanup;
+ fprintf(fp, " %s\n", lvl_name);
+ if (expand) {
+ ap_mls_lvl = (apol_mls_level_t *) apol_mls_level_create_from_qpol_level_datum(policydb, level);
+ tmp = apol_mls_level_render(policydb, ap_mls_lvl);
+ apol_mls_level_destroy(&ap_mls_lvl);
+ if (!tmp)
+ goto cleanup;
+ fprintf(fp, " level %s\n", tmp);
+ free(tmp);
+ }
+ }
+
+ if (name && !apol_vector_get_size(v)) {
+ ERR(policydb, "Provided sensitivity (%s) is not a valid sensitivity name.", name);
+ goto cleanup;
+ }
+
+ retval = 0;
+ cleanup:
+ apol_level_query_destroy(&query);
+ apol_vector_destroy(&v);
+ return retval;
+}
+
+/**
+ * Prints statistics regarding a policy's MLS categories.
+ * If this function is given a name, it will attempt to
+ * print statistics about a particular category; otherwise
+ * the function prints statistics about all of the policy's
+ * categories.
+ *
+ * @param fp Reference to a file to which to print statistics
+ * @param name Reference to a MLS category's name; if NULL,
+ * all categories will be considered
+ * @param expand Flag indicating whether to print each
+ * category's sensitivities
+ * @param policydb Reference to a policy
+ *
+ * @return 0 on success, < 0 on error.
+ */
+static int print_cats(FILE * fp, const char *name, int expand, const apol_policy_t * policydb)
+{
+ int retval = 0;
+ apol_cat_query_t *query = NULL;
+ apol_vector_t *v = NULL;
+ const qpol_cat_t *cat_datum = NULL;
+ size_t i, n_cats;
+
+ query = apol_cat_query_create();
+ if (!query) {
+ ERR(policydb, "%s", strerror(ENOMEM));
+ goto cleanup;
+ }
+ if (apol_cat_query_set_cat(policydb, query, name))
+ goto cleanup;
+ if (apol_cat_get_by_query(policydb, query, &v))
+ goto cleanup;
+ n_cats = apol_vector_get_size(v);
+ apol_vector_sort(v, &qpol_cat_datum_compare, (void *)policydb);
+
+ if (!name)
+ fprintf(fp, "Categories: %zd\n", n_cats);
+ for (i = 0; i < n_cats; i++) {
+ cat_datum = apol_vector_get_element(v, i);
+ if (!cat_datum)
+ goto cleanup;
+ print_cat_sens(fp, cat_datum, policydb, expand);
+
+ }
+
+ if (name && !n_cats) {
+ ERR(policydb, "Provided category (%s) is not a valid category name.", name);
+ goto cleanup;
+ }
+
+ retval = 0;
+ cleanup:
+ apol_cat_query_destroy(&query);
+ apol_vector_destroy(&v);
+ return retval;
+}
+
+/**
+ * Prints statistics regarding a policy's fs_use statements.
+ * If this function is given a name, it will attempt to
+ * print statistics about a particular filesystem; otherwise
+ * the function prints statistics about all of the policy's
+ * fs_use statements.
+ *
+ * @param fp Reference to a file to which to print statistics
+ * @param type Reference to the name of a file system type; if NULL,
+ * all file system types will be considered
+ * @param policydb Reference to a policy
+ *
+ * @return 0 on success, < 0 on error.
+ */
+static int print_fsuse(FILE * fp, const char *type, const apol_policy_t * policydb)
+{
+ int retval = -1;
+ char *tmp = NULL;
+ apol_fs_use_query_t *query = NULL;
+ apol_vector_t *v = NULL;
+ const qpol_fs_use_t *fs_use = NULL;
+ size_t i;
+
+ query = apol_fs_use_query_create();
+ if (!query) {
+ ERR(policydb, "%s", strerror(ENOMEM));
+ goto cleanup;
+ }
+ if (apol_fs_use_query_set_filesystem(policydb, query, type))
+ goto cleanup;
+ if (apol_fs_use_get_by_query(policydb, query, &v))
+ goto cleanup;
+
+ if (!type)
+ fprintf(fp, "\nFs_use: %zd\n", apol_vector_get_size(v));
+
+ for (i = 0; i < apol_vector_get_size(v); i++) {
+ fs_use = apol_vector_get_element(v, i);
+ tmp = apol_fs_use_render(policydb, fs_use);
+ if (!tmp)
+ goto cleanup;
+ fprintf(fp, " %s\n", tmp);
+ free(tmp);
+ }
+ if (type && !apol_vector_get_size(v))
+ ERR(policydb, "No fs_use statement for filesystem of type %s.", type);
+
+ retval = 0;
+ cleanup:
+ apol_fs_use_query_destroy(&query);
+ apol_vector_destroy(&v);
+ return retval;
+}
+
+/**
+ * Prints statistics regarding a policy's genfscons.
+ * If this function is given a name, it will attempt to
+ * print statistics about a particular genfscon; otherwise
+ * the function prints statistics about all of the policy's
+ * genfscons.
+ *
+ * @param fp Reference to a file to which to print statistics
+ * @param name Reference to a genfscon's type; if NULL,
+ * all genfscons will be considered
+ * @param policydb Reference to a policy
+ *
+ * @return 0 on success, < 0 on error.
+ */
+static int print_genfscon(FILE * fp, const char *type, const apol_policy_t * policydb)
+{
+ int retval = -1;
+ size_t i;
+ char *tmp = NULL;
+ apol_genfscon_query_t *query = NULL;
+ apol_vector_t *v = NULL;
+ qpol_genfscon_t *genfscon = NULL;
+
+ query = apol_genfscon_query_create();
+ if (!query) {
+ ERR(policydb, "%s", strerror(ENOMEM));
+ goto cleanup;
+ }
+
+ if (apol_genfscon_query_set_filesystem(policydb, query, type))
+ goto cleanup;
+ if (apol_genfscon_get_by_query(policydb, query, &v))
+ goto cleanup;
+
+ if (!type)
+ fprintf(fp, "\nGenfscon: %zd\n", apol_vector_get_size(v));
+
+ for (i = 0; i < apol_vector_get_size(v); i++) {
+ genfscon = (qpol_genfscon_t *) apol_vector_get_element(v, i);
+ tmp = apol_genfscon_render(policydb, genfscon);
+ if (!tmp)
+ goto cleanup;
+ fprintf(fp, " %s\n", tmp);
+ free(tmp);
+ }
+
+ if (type && !apol_vector_get_size(v))
+ ERR(policydb, "No genfscon statement for filesystem of type %s.", type);
+
+ retval = 0;
+ cleanup:
+ apol_genfscon_query_destroy(&query);
+ apol_vector_destroy(&v);
+
+ return retval;
+}
+
+/**
+ * Prints statistics regarding a policy's netifcons.
+ * If this function is given a name, it will attempt to
+ * print statistics about a particular netifcon; otherwise
+ * the function prints statistics about all of the policy's
+ * netifcons.
+ *
+ * @param fp Reference to a file to which to print statistics
+ * @param name Reference to a network interface's name; if NULL,
+ * all netifcons will be considered
+ * @param policydb Reference to a policy
+ *
+ * @return 0 on success, < 0 on error.
+ */
+static int print_netifcon(FILE * fp, const char *name, const apol_policy_t * policydb)
+{
+ int retval = -1;
+ char *tmp;
+ const qpol_netifcon_t *netifcon = NULL;
+ qpol_iterator_t *iter = NULL;
+ qpol_policy_t *q = apol_policy_get_qpol(policydb);
+ size_t n_netifcons = 0;
+
+ if (name != NULL) {
+ if (qpol_policy_get_netifcon_by_name(q, name, &netifcon))
+ goto cleanup;
+ tmp = apol_netifcon_render(policydb, netifcon);
+ if (!tmp)
+ goto cleanup;
+ fprintf(fp, " %s\n", tmp);
+ free(tmp);
+ } else {
+ if (qpol_policy_get_netifcon_iter(q, &iter))
+ goto cleanup;
+ if (qpol_iterator_get_size(iter, &n_netifcons))
+ goto cleanup;
+ fprintf(fp, "\nNetifcon: %zd\n", n_netifcons);
+
+ for (; !qpol_iterator_end(iter); qpol_iterator_next(iter)) {
+ if (qpol_iterator_get_item(iter, (void **)&netifcon))
+ goto cleanup;
+ tmp = apol_netifcon_render(policydb, netifcon);
+ if (!tmp)
+ goto cleanup;
+ fprintf(fp, " %s\n", tmp);
+ free(tmp);
+ }
+ qpol_iterator_destroy(&iter);
+ }
+
+ retval = 0;
+ cleanup:
+ qpol_iterator_destroy(&iter);
+ return retval;
+}
+
+/**
+ * Prints statistics regarding a policy's nodecons.
+ * If this function is given a name, it will attempt to
+ * print statistics about a particular nodecon; otherwise
+ * the function prints statistics about all of the policy's
+ * nodecons.
+ *
+ * @param fp Reference to a file to which to print statistics
+ * @param name Reference to a textually represented IP address;
+ * if NULL, all nodecons will be considered
+ * @param policydb Reference to a policy
+ *
+ * @return 0 on success, < 0 on error.
+ */
+static int print_nodecon(FILE * fp, const char *addr, const apol_policy_t * policydb)
+{
+ int retval = -1, protocol;
+ char *tmp = NULL;
+ uint32_t address[4] = { 0, 0, 0, 0 };
+ apol_nodecon_query_t *query = NULL;
+ apol_vector_t *v = NULL;
+ qpol_nodecon_t *nodecon = NULL;
+ size_t n_nodecons = 0, i;
+
+ query = apol_nodecon_query_create();
+ if (!query) {
+ ERR(policydb, "%s", strerror(ENOMEM));
+ goto cleanup;
+ }
+
+ /* address needs to be in a libapol-understandable format */
+ if (addr) {
+ protocol = apol_str_to_internal_ip(addr, address);
+ if (protocol < 0) {
+ ERR(policydb, "%s", "Unable to parse IP address");
+ goto cleanup;
+ }
+ if (apol_nodecon_query_set_addr(policydb, query, address, protocol))
+ goto cleanup;
+ if (apol_nodecon_query_set_protocol(policydb, query, protocol))
+ goto cleanup;
+ }
+
+ if (apol_nodecon_get_by_query(policydb, query, &v))
+ goto cleanup;
+
+ n_nodecons = apol_vector_get_size(v);
+
+ if (!addr) {
+ fprintf(fp, "Nodecon: %zd\n", n_nodecons);
+ } else if (!n_nodecons) {
+ ERR(policydb, "No matching nodecon for address %s.", addr);
+ retval = 1;
+ goto cleanup;
+ }
+
+ for (i = 0; i < n_nodecons; i++) {
+ nodecon = apol_vector_get_element(v, i);
+ tmp = apol_nodecon_render(policydb, nodecon);
+ if (!tmp)
+ goto cleanup;
+ fprintf(fp, " %s\n", tmp);
+ free(tmp);
+ }
+
+ retval = 0;
+ cleanup:
+ apol_nodecon_query_destroy(&query);
+ apol_vector_destroy(&v);
+ return retval;
+}
+
+/**
+ * Prints statistics regarding a policy's portcons.
+ * If this function is given a name, it will attempt to
+ * print statistics about a particular portcon; otherwise
+ * the function prints statistics about all of the policy's
+ * portcons.
+ *
+ * @param fp Reference to a file to which to print statistics
+ * @param num Reference to a port number; if NULL,
+ * all ports will be considered
+ * @param protocol Reference to the name of a ISO 7498-1
+ * transport layer protocol used to communicate over a port
+ * @param policydb Reference to a policy
+ *
+ * @return 0 on success, < 0 on error.
+ */
+static int print_portcon(FILE * fp, const char *num, const char *protocol, const apol_policy_t * policydb)
+{
+ int retval = -1;
+ const qpol_portcon_t *portcon = NULL;
+ qpol_iterator_t *iter = NULL;
+ uint16_t low_port, high_port;
+ uint8_t ocon_proto, proto = 0;
+ qpol_policy_t *q = apol_policy_get_qpol(policydb);
+ size_t n_portcons;
+ char *tmp = NULL;
+
+ if (protocol) {
+ if (!strcmp(protocol, "tcp"))
+ proto = IPPROTO_TCP;
+ else if (!strcmp(protocol, "udp"))
+ proto = IPPROTO_UDP;
+ else {
+ ERR(policydb, "Unable to get portcon by protocol: bad protocol %s.", protocol);
+ goto cleanup;
+ }
+ }
+ if (qpol_policy_get_portcon_iter(q, &iter))
+ goto cleanup;
+ if (qpol_iterator_get_size(iter, &n_portcons))
+ goto cleanup;
+ if (!num)
+ fprintf(fp, "\nPortcon: %zd\n", n_portcons);
+
+ for (; !qpol_iterator_end(iter); qpol_iterator_next(iter)) {
+ if (qpol_iterator_get_item(iter, (void **)&portcon))
+ goto cleanup;
+ if (qpol_portcon_get_low_port(q, portcon, &low_port))
+ goto cleanup;
+ if (qpol_portcon_get_high_port(q, portcon, &high_port))
+ goto cleanup;
+ if (qpol_portcon_get_protocol(q, portcon, &ocon_proto))
+ goto cleanup;
+ if (num) {
+ if (atoi(num) < low_port || atoi(num) > high_port)
+ continue;
+ }
+ if (protocol) {
+ if (ocon_proto != proto)
+ continue;
+ }
+ fprintf(fp, " %s\n", (tmp = apol_portcon_render(policydb, portcon)));
+ free(tmp);
+ tmp = NULL;
+ }
+
+ retval = 0;
+ cleanup:
+ qpol_iterator_destroy(&iter);
+ return retval;
+}
+
+/**
+ * Prints statistics regarding a policy's initial SIDs.
+ * If this function is given a name, it will attempt to
+ * print statistics about a particular initial SID; otherwise
+ * the function prints statistics about all of the policy's
+ * initial SIDs.
+ *
+ * @param fp Reference to a file to which to print statistics
+ * @param name Reference to a SID name; if NULL,
+ * all initial SIDs will be considered
+ * @param expand Flag indicating whether to print each
+ * initial SID's security context
+ * @param policydb Reference to a policy
+ *
+ * @return 0 on success, < 0 on error.
+ */
+static int print_isids(FILE * fp, const char *name, int expand, const apol_policy_t * policydb)
+{
+ int retval = -1;
+ apol_isid_query_t *query = NULL;
+ apol_vector_t *v = NULL;
+ const qpol_isid_t *isid = NULL;
+ const qpol_context_t *ctxt = NULL;
+ qpol_policy_t *q = apol_policy_get_qpol(policydb);
+ size_t i, n_isids = 0;
+ char *tmp = NULL;
+ const char *isid_name = NULL;
+
+ query = apol_isid_query_create();
+ if (!query) {
+ ERR(policydb, "%s", strerror(ENOMEM));
+ goto cleanup;
+ }
+ if (apol_isid_query_set_name(policydb, query, name))
+ goto cleanup;
+ if (apol_isid_get_by_query(policydb, query, &v))
+ goto cleanup;
+ n_isids = apol_vector_get_size(v);
+
+ if (!name)
+ fprintf(fp, "\nInitial SID: %zd\n", n_isids);
+
+ for (i = 0; i < n_isids; i++) {
+ isid = apol_vector_get_element(v, i);
+ if (qpol_isid_get_name(q, isid, &isid_name))
+ goto cleanup;
+ if (!expand) {
+ fprintf(fp, " %s\n", isid_name);
+ } else {
+ if (qpol_isid_get_context(q, isid, &ctxt))
+ goto cleanup;
+ tmp = apol_qpol_context_render(policydb, ctxt);
+ if (!tmp)
+ goto cleanup;
+ fprintf(fp, "%20s: %s\n", isid_name, tmp);
+ free(tmp);
+ }
+ }
+
+ if (name && !n_isids) {
+ ERR(policydb, "Provided initial SID name (%s) is not a valid name.", name);
+ goto cleanup;
+ }
+
+ retval = 0;
+ cleanup:
+ apol_isid_query_destroy(&query);
+ apol_vector_destroy(&v);
+ return retval;
+}
+
+/**
+ * Prints statistics regarding a policy's permissives.
+ * If this function is given a name, it will attempt to
+ * print statistics about a particular permissive; otherwise
+ * the function prints statistics about all of the policy's permissives.
+ *
+ * @param fp Reference to a file to which to print statistics
+ * @param name Reference to a permissives name; if NULL,
+ * all permissives will be considered
+ * @param expand Flag indicating whether to print each
+ * @param policydb Reference to a policy
+ *
+ * @return 0 on success, < 0 on error.
+ */
+static int print_permissives(FILE * fp, const char *name, int expand, const apol_policy_t * policydb)
+{
+ int retval = -1;
+ const char *tmp = NULL;
+ const qpol_permissive_t *permissive_datum = NULL;
+ qpol_iterator_t *iter = NULL;
+ qpol_policy_t *q = apol_policy_get_qpol(policydb);
+ size_t n_permissives = 0;
+
+ if (qpol_policy_get_permissive_iter(q, &iter))
+ goto cleanup;
+ if (qpol_iterator_get_size(iter, &n_permissives))
+ goto cleanup;
+ fprintf(fp, "\nPermissive Types: %zd\n", n_permissives);
+ for (; !qpol_iterator_end(iter); qpol_iterator_next(iter)) {
+ if (qpol_iterator_get_item(iter, (void **)&permissive_datum))
+ goto cleanup;
+ if (qpol_permissive_get_name(q, permissive_datum, &tmp))
+ goto cleanup;
+ if (!tmp)
+ goto cleanup;
+ fprintf(fp, " %s\n", tmp);
+ }
+
+ retval = 0;
+ cleanup:
+ qpol_iterator_destroy(&iter);
+ return retval;
+}
+
+/**
+ * Prints statistics regarding a policy's capabilities.
+ * If this function is given a name, it will attempt to
+ * print statistics about a particular capability; otherwise
+ * the function prints statistics about all of the policy's capabilities.
+ *
+ * @param fp Reference to a file to which to print statistics
+ * @param name Reference to a policy capability name; if NULL,
+ * all capabilities will be considered
+ * @param expand Flag indicating whether to print each
+ * @param policydb Reference to a policy
+ *
+ * @return 0 on success, < 0 on error.
+ */
+
+static int print_polcaps(FILE * fp, const char *name, int expand, const apol_policy_t * policydb)
+{
+ int retval = -1;
+ const char *tmp = NULL;
+ qpol_polcap_t *polcap_datum = NULL;
+ qpol_iterator_t *iter = NULL;
+ qpol_policy_t *q = apol_policy_get_qpol(policydb);
+ size_t n_polcaps = 0;
+
+ if (qpol_policy_get_polcap_iter(q, &iter))
+ goto cleanup;
+ if (qpol_iterator_get_size(iter, &n_polcaps))
+ goto cleanup;
+ fprintf(fp, "\nPolicy Capabilities: %zd\n", n_polcaps);
+ for (; !qpol_iterator_end(iter); qpol_iterator_next(iter)) {
+ if (qpol_iterator_get_item(iter, (void **)&polcap_datum))
+ goto cleanup;
+ if (qpol_polcap_get_name(q, polcap_datum, &tmp))
+ goto cleanup;
+ if (!tmp)
+ goto cleanup;
+ fprintf(fp, " %s\n", tmp);
+ }
+
+ retval = 0;
+ cleanup:
+ qpol_iterator_destroy(&iter);
+ return retval;
+}
+
+static const char *get_attr_string(int attr)
+{
+ const char *string = "";
+ switch (attr)
+ {
+ case QPOL_CEXPR_SYM_USER:
+ string = "u1";
+ break;
+ case QPOL_CEXPR_SYM_ROLE:
+ string = "r1";
+ break;
+ case QPOL_CEXPR_SYM_TYPE:
+ string = "t1";
+ break;
+
+ case QPOL_CEXPR_SYM_USER+QPOL_CEXPR_SYM_TARGET:
+ string = "u2";
+ break;
+ case QPOL_CEXPR_SYM_ROLE+QPOL_CEXPR_SYM_TARGET:
+ string = "r2";
+ break;
+ case QPOL_CEXPR_SYM_TYPE+QPOL_CEXPR_SYM_TARGET:
+ string = "t2";
+ break;
+
+ case QPOL_CEXPR_SYM_USER+QPOL_CEXPR_SYM_XTARGET:
+ string = "u3";
+ break;
+ case QPOL_CEXPR_SYM_ROLE+QPOL_CEXPR_SYM_XTARGET:
+ string = "r3";
+ break;
+ case QPOL_CEXPR_SYM_TYPE+QPOL_CEXPR_SYM_XTARGET:
+ string = "t3";
+ break;
+
+ case QPOL_CEXPR_SYM_L1L2:
+ string = "l1 l2";
+ break;
+ case QPOL_CEXPR_SYM_L1H2:
+ string = "l1 h2";
+ break;
+ case QPOL_CEXPR_SYM_H1L2:
+ string = "h1 l2";
+ break;
+ case QPOL_CEXPR_SYM_H1H2:
+ string = "h1 h2";
+ break;
+ case QPOL_CEXPR_SYM_L1H1:
+ string = "l1 h1";
+ break;
+ case QPOL_CEXPR_SYM_L2H2:
+ string = "l2 h2";
+ break;
+ }
+
+ return string;
+}
+
+static const char *get_op_string(int op)
+{
+ char *string = "";
+
+ switch (op)
+ {
+ case QPOL_CEXPR_OP_EQ:
+ string = "==";
+ break;
+ case QPOL_CEXPR_OP_NEQ:
+ string = "!=";
+ break;
+ case QPOL_CEXPR_OP_DOM:
+ string = "dom";
+ break;
+ case QPOL_CEXPR_OP_DOMBY:
+ string = "domby";
+ break;
+ case QPOL_CEXPR_OP_INCOMP:
+ string = "incomp";
+ break;
+ }
+
+ return string;
+}
+
+static int print_constraints(FILE * fp, int expand, const apol_policy_t * policydb, int linebreaks)
+{
+ int retval = -1;
+ const char *class_name = NULL;
+ char *constrain_type;
+ char *perm_list = "No Perms Extracted";
+ const qpol_constraint_expr_node_t *expr = NULL;
+ qpol_iterator_t *policy_iter = NULL; // Iterates over all constraints in a policy
+ qpol_iterator_t *perm_iter = NULL; // Iterates over permissions in a constraint
+ qpol_iterator_t *expr_iter = NULL; // Iterates over expression in a constraint
+ qpol_policy_t *q = apol_policy_get_qpol(policydb);
+ qpol_constraint_t *constraint = NULL;
+ const qpol_class_t *class;
+ size_t n_constraints = 0;
+ int expr_type = 0;
+ int sym_type = 0; // 'attr' in struct constraint_expr
+ int op = 0;
+
+ if (qpol_policy_get_constraint_iter(q, &policy_iter) != 0)
+ {
+ ERR (policydb, "%s", "Policy constraint iterator not accessible");
+ return retval;
+ }
+ if (qpol_iterator_get_size(policy_iter, &n_constraints) != 0)
+ {
+ ERR(policydb, "%s", "Policy size computation failed");
+ goto cleanup;
+ }
+
+ fprintf(fp, "\nConstraints: %zd\n", n_constraints);
+
+ // Iterate through constraints
+ for (; qpol_iterator_end(policy_iter) == 0; qpol_iterator_next(policy_iter))
+ {
+ constrain_type = "";
+ if (qpol_iterator_get_item(policy_iter, (void **)&constraint) != 0)
+ {
+ ERR(policydb, "%s", "Can't get constraint from iterator\n");
+ goto cleanup;
+ }
+
+ if (qpol_constraint_get_class(q, constraint, &class) != 0)
+ {
+ ERR(policydb, "%s", "Can't get class from constraint\n");
+ goto cleanup;
+ }
+
+ if (qpol_class_get_name(q, class, &class_name) != 0)
+ {
+ ERR(policydb, "%s", "Can't get class name from constraint\n");
+ goto cleanup;
+ }
+
+ // Get expression, we need to look into it.
+ if (qpol_constraint_get_expr_iter (q, constraint, &expr_iter) != 0)
+ {
+ ERR(policydb, "%s", "Can't get expression from constraint\n");
+ goto cleanup;
+ }
+ // Traverse the iterator to see if this is mlsconstrain
+ for (; qpol_iterator_end(expr_iter) == 0; qpol_iterator_next(expr_iter))
+ {
+ if (qpol_iterator_get_item(expr_iter, (void **)&expr) != 0)
+ {
+ ERR(policydb, "%s", "Can't get expression from iterator\n");
+ goto cleanup;
+ }
+
+ if (qpol_constraint_expr_node_get_sym_type(q, expr, &sym_type) != 0)
+ {
+ ERR(policydb, "%s", "Can't get sym_type from expression\n");
+ goto cleanup;
+ }
+
+ if (sym_type >= QPOL_CEXPR_SYM_L1L2)
+ {
+ constrain_type = "mls";
+ break;
+ }
+ }
+
+ // print permissions
+ fprintf (fp, "%sconstrain { %s } { ", constrain_type, class_name);
+
+ if (qpol_constraint_get_perm_iter (q, constraint, &perm_iter) != 0)
+ {
+ ERR(policydb, "%s", "Can't get permissions from constraint\n");
+ goto cleanup;
+ }
+
+ for (; qpol_iterator_end(perm_iter) == 0; qpol_iterator_next(perm_iter))
+ {
+ if (qpol_iterator_get_item(perm_iter, (void **)&perm_list) != 0)
+ {
+ ERR(policydb, "%s", "Can't get permissions from iterator\n");
+ goto cleanup;
+ }
+
+ fprintf (fp, "%s ", perm_list);
+ free (perm_list); // Strdup created the string.
+ }
+ fprintf (fp, " } ");
+
+ // dump RPN expressions
+ if (qpol_constraint_get_expr_iter (q, constraint, &expr_iter) != 0)
+ {
+ ERR(policydb, "%s", "Can't get expression from constraint\n");
+ goto cleanup;
+ }
+
+ fprintf (fp, "\n( ");
+ for (; qpol_iterator_end(expr_iter) == 0; qpol_iterator_next(expr_iter))
+ {
+ qpol_iterator_t *names_iter = NULL;
+
+ if (qpol_iterator_get_item(expr_iter, (void **)&expr) != 0)
+ {
+ ERR(policydb, "%s", "Can't get expression from iterator\n");
+ goto cleanup;
+ }
+
+ if (qpol_constraint_expr_node_get_op (q, expr, &op) != 0)
+ {
+ ERR(policydb, "%s", "Can't get op from expression\n");
+ goto cleanup;
+ }
+
+ if (qpol_constraint_expr_node_get_sym_type(q, expr, &sym_type) != 0)
+ {
+ ERR(policydb, "%s", "Can't get sym_type from expression\n");
+ goto cleanup;
+ }
+
+ if (qpol_constraint_expr_node_get_expr_type(q, expr, &expr_type) != 0)
+ {
+ ERR(policydb, "%s", "Can't get expr_type from expression\n");
+ goto cleanup;
+ }
+
+ if (linebreaks)
+ fprintf (fp, "\n\t");
+
+ if (expr_type == QPOL_CEXPR_TYPE_NOT)
+ {
+ fprintf (fp, " ! ");
+ }
+ if (expr_type == QPOL_CEXPR_TYPE_AND)
+ {
+ fprintf (fp, " && ");
+ }
+ if (expr_type == QPOL_CEXPR_TYPE_OR)
+ {
+ fprintf (fp, " || ");
+ }
+ if (expr_type == QPOL_CEXPR_TYPE_ATTR)
+ {
+ fprintf (fp, " %s ", get_attr_string(sym_type));
+ fprintf (fp, "%s ", get_attr_string(sym_type | QPOL_CEXPR_SYM_TARGET));
+ fprintf (fp, "%s ", get_op_string(op));
+ }
+ if (expr_type == QPOL_CEXPR_TYPE_NAMES)
+ {
+ size_t name_size=0;
+
+ fprintf (fp, " %s ", get_attr_string(sym_type));
+
+ if (qpol_constraint_expr_node_get_names_iter (q, expr, &names_iter) != 0)
+ {
+ ERR(policydb, "%s", "Can't get names iterator from expression\n");
+ goto cleanup;
+ }
+
+ if (qpol_iterator_get_size(names_iter, &name_size) != 0)
+ {
+ ERR(policydb, "%s", "Can't get size from names iterator\n");
+ goto cleanup;
+ }
+ if (name_size > 0)
+ {
+ if (name_size > 1)
+ fprintf (fp, "{ ");
+
+ for (; qpol_iterator_end(names_iter) == 0; qpol_iterator_next(names_iter))
+ {
+ char *lname = NULL;
+
+ if (qpol_iterator_get_item (names_iter, (void **)&lname) != 0)
+ {
+ ERR(policydb, "%s", "Can't get names from iterator\n");
+ goto cleanup;
+ }
+
+ fprintf (fp, "%s ", lname);
+ free (lname);
+
+ }
+ if (name_size > 1)
+ fprintf (fp, "} ");
+ } else {
+ fprintf (fp, "%s ", CONSTRAIN_NULL_SET);
+ }
+
+ fprintf (fp, "%s ", get_op_string(op));
+ }
+ }
+ if (linebreaks)
+ fprintf (fp, "\n);\n\n");
+ else
+ fprintf (fp, ");\n\n");
+ }
+
+ retval = 0;
+
+cleanup: // close and destroy iterators etc.
+ if (policy_iter != NULL) qpol_iterator_destroy(&policy_iter);
+ if (perm_iter != NULL) qpol_iterator_destroy(&perm_iter);
+ if (expr_iter != NULL) qpol_iterator_destroy(&expr_iter);
+
+ return retval;
+}
+
+
+int main(int argc, char **argv)
+{
+ int classes, types, attribs, roles, users, all, expand, stats, rt, optc, isids, bools, sens, cats, fsuse, genfs, netif,
+ node, port, permissives, polcaps, constrain, linebreaks;
+ apol_policy_t *policydb = NULL;
+ apol_policy_path_t *pol_path = NULL;
+ apol_vector_t *mod_paths = NULL;
+ apol_policy_path_type_e path_type = APOL_POLICY_PATH_TYPE_MONOLITHIC;
+
+ char *class_name, *type_name, *attrib_name, *role_name, *user_name, *isid_name, *bool_name, *sens_name, *cat_name,
+ *fsuse_type, *genfs_type, *netif_name, *node_addr, *permissive_name, *polcap_name, *port_num = NULL, *protocol = NULL;
+
+ class_name = type_name = attrib_name = role_name = user_name = isid_name = bool_name = sens_name = cat_name = fsuse_type =
+ genfs_type = netif_name = node_addr = port_num = permissive_name = polcap_name = NULL;
+ classes = types = attribs = roles = users = all = expand = stats = isids = bools = sens = cats = fsuse = genfs = netif =
+ node = port = permissives = polcaps = constrain = linebreaks = 0;
+ while ((optc = getopt_long(argc, argv, "c::t::a::r::u::b::lxhV", longopts, NULL)) != -1) {
+ switch (optc) {
+ case 0:
+ break;
+ case 'c': /* classes */
+ classes = 1;
+ if (optarg != 0)
+ class_name = optarg;
+ break;
+ case OPT_SENSITIVITY:
+ sens = 1;
+ if (optarg != 0)
+ sens_name = optarg;
+ break;
+ case OPT_CATEGORY:
+ cats = 1;
+ if (optarg != 0)
+ cat_name = optarg;
+ break;
+ case 't': /* types */
+ types = 1;
+ if (optarg != 0)
+ type_name = optarg;
+ break;
+ case 'a': /* attributes */
+ attribs = 1;
+ if (optarg != 0)
+ attrib_name = optarg;
+ break;
+ case 'r': /* roles */
+ roles = 1;
+ if (optarg != 0)
+ role_name = optarg;
+ break;
+ case 'u': /* users */
+ users = 1;
+ if (optarg != 0)
+ user_name = optarg;
+ break;
+ case 'b': /* conditional booleans */
+ bools = 1;
+ if (optarg != 0)
+ bool_name = optarg;
+ break;
+ case OPT_INITIALSID:
+ isids = 1;
+ if (optarg != 0)
+ isid_name = optarg;
+ break;
+ case OPT_FS_USE:
+ fsuse = 1;
+ if (optarg != 0)
+ fsuse_type = optarg;
+ break;
+ case OPT_GENFSCON:
+ genfs = 1;
+ if (optarg != 0)
+ genfs_type = optarg;
+ break;
+ case OPT_NETIFCON:
+ netif = 1;
+ if (optarg != 0)
+ netif_name = optarg;
+ break;
+ case OPT_NODECON:
+ node = 1;
+ if (optarg != 0)
+ node_addr = optarg;
+ break;
+ case OPT_PERMISSIVE:
+ permissives = 1;
+ if (optarg != 0)
+ permissive_name = optarg;
+ break;
+ case OPT_POLCAP:
+ polcaps = 1;
+ if (optarg != 0)
+ polcap_name = optarg;
+ break;
+ case OPT_PORTCON:
+ port = 1;
+ if (optarg != 0)
+ port_num = optarg;
+ break;
+ case OPT_PROTOCOL:
+ if (optarg != 0)
+ protocol = optarg;
+ break;
+ case OPT_ALL:
+ all = 1;
+ break;
+ case 'x': /* expand */
+ expand = 1;
+ break;
+ case 'l': /* Print line breaks in constraints */
+ linebreaks=1;
+ break;
+ case OPT_CONSTRAIN: /* Print constraints */
+ constrain=1;
+ break;
+ case OPT_STATS:
+ stats = 1;
+ break;
+ case 'h': /* help */
+ usage(argv[0], 0);
+ exit(0);
+ case 'V': /* version */
+ printf("seinfo %s\n%s\n", VERSION, COPYRIGHT_INFO);
+ exit(0);
+ default:
+ usage(argv[0], 1);
+ exit(1);
+ }
+ }
+
+ /* check for naked -l */
+ if (protocol && !(port || all)) {
+ fprintf(stderr, "The --protocol flag requires either --portcon or --ALL.\n");
+ exit(1);
+ }
+
+ /* if no options, then show stats */
+ if (classes + types + attribs + roles + users + isids + bools + sens + cats + fsuse + genfs + netif + node + port + permissives + polcaps + constrain + all < 1) {
+ stats = 1;
+ }
+
+ int policy_load_options = ((stats || all) ? 0 : QPOL_POLICY_OPTION_NO_RULES);
+
+ if (argc - optind < 1) {
+ rt = qpol_default_policy_find(&policy_file);
+ if (rt < 0) {
+ fprintf(stderr, "Default policy search failed: %s\n", strerror(errno));
+ exit(1);
+ } else if (rt != 0) {
+ fprintf(stderr, "No default policy found.\n");
+ exit(1);
+ }
+ policy_load_options |= QPOL_POLICY_OPTION_MATCH_SYSTEM;
+ } else {
+ policy_file = strdup(argv[optind]);
+ if (!policy_file) {
+ fprintf(stderr, "Out of memory\n");
+ exit(1);
+ }
+ optind++;
+ }
+
+ if (argc - optind > 0) {
+ path_type = APOL_POLICY_PATH_TYPE_MODULAR;
+ if (!(mod_paths = apol_vector_create(NULL))) {
+ ERR(policydb, "%s", strerror(ENOMEM));
+ free(policy_file);
+ exit(1);
+ }
+ for (; argc - optind; optind++) {
+ if (apol_vector_append(mod_paths, (void *)argv[optind])) {
+ ERR(policydb, "Error loading module %s", argv[optind]);
+ free(policy_file);
+ apol_vector_destroy(&mod_paths);
+ exit(1);
+ }
+ }
+ } else if (apol_file_is_policy_path_list(policy_file) > 0) {
+ pol_path = apol_policy_path_create_from_file(policy_file);
+ if (!pol_path) {
+ ERR(policydb, "%s", "invalid policy list");
+ free(policy_file);
+ exit(1);
+ }
+ }
+
+ if (!pol_path)
+ pol_path = apol_policy_path_create(path_type, policy_file, mod_paths);
+ if (!pol_path) {
+ ERR(policydb, "%s", strerror(ENOMEM));
+ free(policy_file);
+ apol_vector_destroy(&mod_paths);
+ exit(1);
+ }
+ apol_vector_destroy(&mod_paths);
+
+ policydb = apol_policy_create_from_policy_path(pol_path, policy_load_options, NULL, NULL);
+ if (!policydb) {
+ ERR(policydb, "%s", strerror(errno));
+ free(policy_file);
+ apol_policy_path_destroy(&pol_path);
+ exit(1);
+ }
+
+ /* display requested info */
+ if (stats || all)
+ print_stats(stdout, policydb);
+ if (classes || all)
+ print_classes(stdout, class_name, expand, policydb);
+ if (types || all)
+ print_types(stdout, type_name, expand, policydb);
+ if (attribs || all)
+ print_attribs(stdout, attrib_name, expand, policydb);
+ if (roles || all)
+ print_roles(stdout, role_name, expand, policydb);
+ if (users || all)
+ print_users(stdout, user_name, expand, policydb);
+ if (bools || all)
+ print_booleans(stdout, bool_name, expand, policydb);
+ if (sens || all)
+ print_sens(stdout, sens_name, expand, policydb);
+ if (cats || all)
+ print_cats(stdout, cat_name, expand, policydb);
+ if (fsuse || all)
+ print_fsuse(stdout, fsuse_type, policydb);
+ if (genfs || all)
+ print_genfscon(stdout, genfs_type, policydb);
+ if (netif || all)
+ print_netifcon(stdout, netif_name, policydb);
+ if (node || all)
+ print_nodecon(stdout, node_addr, policydb);
+ if (port || all)
+ print_portcon(stdout, port_num, protocol, policydb);
+ if (isids || all)
+ print_isids(stdout, isid_name, expand, policydb);
+ if (permissives || all)
+ print_permissives(stdout, permissive_name, expand, policydb);
+ if (polcaps || all)
+ print_polcaps(stdout, polcap_name, expand, policydb);
+ if (constrain || all)
+ print_constraints(stdout, expand, policydb, linebreaks);
+
+ apol_policy_destroy(&policydb);
+ apol_policy_path_destroy(&pol_path);
+ free(policy_file);
+ exit(0);
+}
+
+/**
+ * Prints a textual representation of a type, and possibly
+ * all of that type's attributes.
+ *
+ * @param fp Reference to a file to which to print type information
+ * @param type_datum Reference to sepol type_datum
+ * @param policydb Reference to a policy
+ * @param expand Flag indicating whether to print each type's
+ * attributes
+ */
+static void print_type_attrs(FILE * fp, const qpol_type_t * type_datum, const apol_policy_t * policydb, const int expand)
+{
+ qpol_iterator_t *iter = NULL;
+ unsigned char isattr, isalias;
+ const char *type_name = NULL, *attr_name = NULL;
+ const qpol_type_t *attr_datum = NULL;
+ qpol_policy_t *q = apol_policy_get_qpol(policydb);
+
+ if (qpol_type_get_name(q, type_datum, &type_name))
+ goto cleanup;
+ if (qpol_type_get_isattr(q, type_datum, &isattr))
+ goto cleanup;
+ if (qpol_type_get_isalias(q, type_datum, &isalias))
+ goto cleanup;
+
+ if (!isattr && !isalias) {
+ fprintf(fp, " %s\n", type_name);
+ if (expand) { /* Print this type's attributes */
+ if (qpol_type_get_attr_iter(q, type_datum, &iter))
+ goto cleanup;
+ for (; !qpol_iterator_end(iter); qpol_iterator_next(iter)) {
+ if (qpol_iterator_get_item(iter, (void **)&attr_datum))
+ goto cleanup;
+ if (qpol_type_get_name(q, attr_datum, &attr_name))
+ goto cleanup;
+ fprintf(fp, " %s\n", attr_name);
+ }
+ }
+ }
+
+ cleanup:
+ qpol_iterator_destroy(&iter);
+ return;
+}
+
+/**
+ * Prints a textual representation of an attribute, and possibly
+ * all of that attribute's types.
+ *
+ * @param fp Reference to a file to which to print attribute information
+ * @param type_datum Reference to sepol type_datum
+ * @param policydb Reference to a policy
+ * @param expand Flag indicating whether to print each attribute's
+ * types
+ */
+static void print_attr_types(FILE * fp, const qpol_type_t * type_datum, const apol_policy_t * policydb, const int expand)
+{
+ const qpol_type_t *attr_datum = NULL;
+ qpol_iterator_t *iter = NULL;
+ const char *attr_name = NULL, *type_name = NULL;
+ qpol_policy_t *q = apol_policy_get_qpol(policydb);
+ unsigned char isattr;
+
+ if (qpol_type_get_name(q, type_datum, &attr_name))
+ goto cleanup;
+ fprintf(fp, " %s\n", attr_name);
+
+ if (expand) {
+ /* get an iterator over all types this attribute has */
+ if (qpol_type_get_isattr(q, type_datum, &isattr))
+ goto cleanup;
+ if (isattr) { /* sanity check */
+ if (qpol_type_get_type_iter(q, type_datum, &iter))
+ goto cleanup;
+ for (; !qpol_iterator_end(iter); qpol_iterator_next(iter)) {
+ if (qpol_iterator_get_item(iter, (void **)&attr_datum))
+ goto cleanup;
+ if (qpol_type_get_name(q, attr_datum, &type_name))
+ goto cleanup;
+ fprintf(fp, " %s\n", type_name);
+ }
+ qpol_iterator_destroy(&iter);
+
+ } else /* this should never happen */
+ goto cleanup;
+
+ }
+
+ cleanup:
+ qpol_iterator_destroy(&iter);
+ return;
+}
+
+/**
+ * Prints a textual representation of a user, and possibly
+ * all of that user's roles.
+ *
+ * @param fp Reference to a file to which to print user information
+ * @param type_datum Reference to sepol type_datum
+ * @param policydb Reference to a policy
+ * @param expand Flag indicating whether to print each user's
+ * roles
+ */
+static void print_user_roles(FILE * fp, const qpol_user_t * user_datum, const apol_policy_t * policydb, const int expand)
+{
+ const qpol_role_t *role_datum = NULL;
+ qpol_iterator_t *iter = NULL;
+ const qpol_mls_range_t *range = NULL;
+ const qpol_mls_level_t *dflt_level = NULL;
+ apol_mls_level_t *ap_lvl = NULL;
+ apol_mls_range_t *ap_range = NULL;
+ qpol_policy_t *q = apol_policy_get_qpol(policydb);
+ char *tmp;
+ const char *user_name, *role_name;
+
+ if (qpol_user_get_name(q, user_datum, &user_name))
+ goto cleanup;
+ fprintf(fp, " %s\n", user_name);
+
+ if (expand) {
+ if (qpol_policy_has_capability(q, QPOL_CAP_MLS)) {
+ /* print default level */
+ if (qpol_user_get_dfltlevel(q, user_datum, &dflt_level))
+ goto cleanup;
+ ap_lvl = apol_mls_level_create_from_qpol_mls_level(policydb, dflt_level);
+ tmp = apol_mls_level_render(policydb, ap_lvl);
+ if (!tmp)
+ goto cleanup;
+ fprintf(fp, " default level: %s\n", tmp);
+ free(tmp);
+ /* print default range */
+ if (qpol_user_get_range(q, user_datum, &range))
+ goto cleanup;
+ ap_range = apol_mls_range_create_from_qpol_mls_range(policydb, range);
+ tmp = apol_mls_range_render(policydb, ap_range);
+ if (!tmp)
+ goto cleanup;
+ fprintf(fp, " range: %s\n", tmp);
+ free(tmp);
+ }
+
+ fprintf(fp, " roles:\n");
+ if (qpol_user_get_role_iter(q, user_datum, &iter))
+ goto cleanup;
+ for (; !qpol_iterator_end(iter); qpol_iterator_next(iter)) {
+ if (qpol_iterator_get_item(iter, (void **)&role_datum))
+ goto cleanup;
+ if (qpol_role_get_name(q, role_datum, &role_name))
+ goto cleanup;
+ fprintf(fp, " %s\n", role_name);
+ }
+ }
+
+ cleanup:
+ qpol_iterator_destroy(&iter);
+ apol_mls_level_destroy(&ap_lvl);
+ apol_mls_range_destroy(&ap_range);
+ return;
+}
+
+/**
+ * Prints a textual representation of a role, and possibly
+ * all of that role's types.
+ *
+ * @param fp Reference to a file to which to print role information
+ * @param type_datum Reference to sepol type_datum
+ * @param policydb Reference to a policy
+ * @param expand Flag indicating whether to print each role's
+ * types
+ */
+static void print_role_types(FILE * fp, const qpol_role_t * role_datum, const apol_policy_t * policydb, const int expand)
+{
+ const char *role_name = NULL, *type_name = NULL;
+ const qpol_role_t *dom_datum = NULL;
+ const qpol_type_t *type_datum = NULL;
+ qpol_iterator_t *iter = NULL;
+ qpol_policy_t *q = apol_policy_get_qpol(policydb);
+ size_t n_dom = 0, n_types = 0;
+
+ if (qpol_role_get_name(q, role_datum, &role_name))
+ goto cleanup;
+ fprintf(fp, " %s\n", role_name);
+
+ if (expand) {
+ if (qpol_role_get_dominate_iter(q, role_datum, &iter))
+ goto cleanup;
+ if (qpol_iterator_get_size(iter, &n_dom))
+ goto cleanup;
+ if ((int)n_dom > 0) {
+ fprintf(fp, " Dominated Roles:\n");
+ /* print dominated roles */
+ for (; !qpol_iterator_end(iter); qpol_iterator_next(iter)) {
+ if (qpol_iterator_get_item(iter, (void **)&dom_datum))
+ goto cleanup;
+ if (qpol_role_get_name(q, dom_datum, &role_name))
+ goto cleanup;
+ fprintf(fp, " %s\n", role_name);
+ }
+ }
+ qpol_iterator_destroy(&iter);
+
+ if (qpol_role_get_type_iter(q, role_datum, &iter))
+ goto cleanup;
+ if (qpol_iterator_get_size(iter, &n_types))
+ goto cleanup;
+ if ((int)n_types > 0) {
+ fprintf(fp, " Types:\n");
+ /* print types */
+ for (; !qpol_iterator_end(iter); qpol_iterator_next(iter)) {
+ if (qpol_iterator_get_item(iter, (void **)&type_datum))
+ goto cleanup;
+ if (qpol_type_get_name(q, type_datum, &type_name))
+ goto cleanup;
+ fprintf(fp, " %s\n", type_name);
+ }
+ }
+ }
+
+ cleanup:
+ qpol_iterator_destroy(&iter);
+ return;
+}
+
+/**
+ * Prints a textual representation of a boolean value, and possibly
+ * all of that boolean's initial state.
+ *
+ * @param fp Reference to a file to which to print boolean information
+ * @param type_datum Reference to sepol type_datum
+ * @param policydb Reference to a policy
+ * @param expand Flag indicating whether to print each boolean's
+ * initial state
+ */
+static void print_bool_state(FILE * fp, const qpol_bool_t * bool_datum, const apol_policy_t * policydb, const int expand)
+{
+ const char *bool_name = NULL;
+ qpol_policy_t *q = apol_policy_get_qpol(policydb);
+ int state;
+
+ if (qpol_bool_get_name(q, bool_datum, &bool_name))
+ return;
+ fprintf(fp, " %s", bool_name);
+
+ if (expand) {
+ if (qpol_bool_get_state(q, bool_datum, &state))
+ return;
+ fprintf(fp, ": %s", state ? "TRUE" : "FALSE");
+ }
+ fprintf(fp, "\n");
+}
+
+/**
+ * Prints a textual representation of an object class and possibly
+ * all of that object class' permissions.
+ *
+ * @param fp Reference to a file to which to print object class information
+ * @param type_datum Reference to sepol type_datum
+ * @param policydb Reference to a policy
+ * @param expand Flag indicating whether to print each object class'
+ * permissions
+ */
+static void print_class_perms(FILE * fp, const qpol_class_t * class_datum, const apol_policy_t * policydb, const int expand)
+{
+ const char *class_name = NULL, *perm_name = NULL;
+ qpol_iterator_t *iter = NULL;
+ const qpol_common_t *common_datum = NULL;
+ qpol_policy_t *q = apol_policy_get_qpol(policydb);
+
+ if (!class_datum)
+ goto cleanup;
+
+ if (qpol_class_get_name(q, class_datum, &class_name))
+ goto cleanup;
+ fprintf(fp, " %s\n", class_name);
+
+ if (expand) {
+ /* get commons for this class */
+ if (qpol_class_get_common(q, class_datum, &common_datum))
+ goto cleanup;
+ if (common_datum) {
+ if (qpol_common_get_perm_iter(q, common_datum, &iter))
+ goto cleanup;
+ /* print perms for the common */
+ for (; !qpol_iterator_end(iter); qpol_iterator_next(iter)) {
+ if (qpol_iterator_get_item(iter, (void **)&perm_name))
+ goto cleanup;
+ fprintf(fp, " %s\n", perm_name);
+ }
+ qpol_iterator_destroy(&iter);
+ }
+ /* print unique perms for this class */
+ if (qpol_class_get_perm_iter(q, class_datum, &iter))
+ goto cleanup;
+ for (; !qpol_iterator_end(iter); qpol_iterator_next(iter)) {
+ if (qpol_iterator_get_item(iter, (void **)&perm_name))
+ goto cleanup;
+ fprintf(fp, " %s\n", perm_name);
+ }
+ qpol_iterator_destroy(&iter);
+ }
+
+ cleanup:
+ qpol_iterator_destroy(&iter);
+ return;
+}
+
+/**
+ * Prints a textual representation of a MLS category and possibly
+ * all of that category's sensitivies.
+ *
+ * @param fp Reference to a file to which to print category information
+ * @param type_datum Reference to sepol type_datum
+ * @param policydb Reference to a policy
+ * @param expand Flag indicating whether to print each category's
+ * sensitivities
+ */
+static void print_cat_sens(FILE * fp, const qpol_cat_t * cat_datum, const apol_policy_t * policydb, const int expand)
+{
+ const char *cat_name, *lvl_name;
+ apol_level_query_t *query = NULL;
+ apol_vector_t *v = NULL;
+ const qpol_level_t *lvl_datum = NULL;
+ qpol_policy_t *q = apol_policy_get_qpol(policydb);
+ size_t i, n_sens = 0;
+
+ if (!fp || !cat_datum || !policydb)
+ goto cleanup;
+
+ /* get category name for apol query */
+ if (qpol_cat_get_name(q, cat_datum, &cat_name))
+ goto cleanup;
+
+ query = apol_level_query_create();
+ if (!query) {
+ ERR(policydb, "%s", strerror(ENOMEM));
+ goto cleanup;
+ }
+ if (apol_level_query_set_cat(policydb, query, cat_name))
+ goto cleanup;
+ if (apol_level_get_by_query(policydb, query, &v))
+ goto cleanup;
+ fprintf(fp, " %s\n", cat_name);
+
+ if (expand) {
+ fprintf(fp, " Sensitivities:\n");
+ apol_vector_sort(v, &qpol_level_datum_compare, (void *)policydb);
+ n_sens = apol_vector_get_size(v);
+ for (i = 0; i < n_sens; i++) {
+ lvl_datum = (qpol_level_t *) apol_vector_get_element(v, i);
+ if (!lvl_datum)
+ goto cleanup;
+ if (qpol_level_get_name(q, lvl_datum, &lvl_name))
+ goto cleanup;
+ fprintf(fp, " %s\n", lvl_name);
+ }
+ }
+
+ cleanup:
+ apol_level_query_destroy(&query);
+ apol_vector_destroy(&v);
+ return;
+}
+
+/**
+ * Compare two qpol_cat_datum_t objects.
+ * This function is meant to be passed to apol_vector_compare
+ * as the callback for performing comparisons.
+ *
+ * @param datum1 Reference to a qpol_type_datum_t object
+ * @param datum2 Reference to a qpol_type_datum_t object
+ * @param data Reference to a policy
+ * @return Greater than 0 if the first argument is less than the second argument,
+ * less than 0 if the first argument is greater than the second argument,
+ * 0 if the arguments are equal
+ */
+static int qpol_cat_datum_compare(const void *datum1, const void *datum2, void *data)
+{
+ const qpol_cat_t *cat_datum1 = NULL, *cat_datum2 = NULL;
+ apol_policy_t *policydb = NULL;
+ qpol_policy_t *q;
+ uint32_t val1, val2;
+
+ policydb = (apol_policy_t *) data;
+ q = apol_policy_get_qpol(policydb);
+ assert(policydb);
+
+ if (!datum1 || !datum2)
+ goto exit_err;
+ cat_datum1 = datum1;
+ cat_datum2 = datum2;
+
+ if (qpol_cat_get_value(q, cat_datum1, &val1))
+ goto exit_err;
+ if (qpol_cat_get_value(q, cat_datum2, &val2))
+ goto exit_err;
+
+ return (val1 > val2) ? 1 : ((val1 == val2) ? 0 : -1);
+
+ exit_err:
+ assert(0);
+ return 0;
+}
+
+/**
+ * Compare two qpol_level_datum_t objects.
+ * This function is meant to be passed to apol_vector_compare
+ * as the callback for performing comparisons.
+ *
+ * @param datum1 Reference to a qpol_level_datum_t object
+ * @param datum2 Reference to a qpol_level_datum_t object
+ * @param data Reference to a policy
+ * @return Greater than 0 if the first argument is less than the second argument,
+ * less than 0 if the first argument is greater than the second argument,
+ * 0 if the arguments are equal
+ */
+static int qpol_level_datum_compare(const void *datum1, const void *datum2, void *data)
+{
+ const qpol_level_t *lvl_datum1 = NULL, *lvl_datum2 = NULL;
+ apol_policy_t *policydb = NULL;
+ qpol_policy_t *q;
+ uint32_t val1, val2;
+
+ policydb = (apol_policy_t *) data;
+ assert(policydb);
+ q = apol_policy_get_qpol(policydb);
+
+ if (!datum1 || !datum2)
+ goto exit_err;
+ lvl_datum1 = datum1;
+ lvl_datum2 = datum2;
+
+ if (qpol_level_get_value(q, lvl_datum1, &val1))
+ goto exit_err;
+ if (qpol_level_get_value(q, lvl_datum2, &val2))
+ goto exit_err;
+
+ return (val1 > val2) ? 1 : ((val1 == val2) ? 0 : -1);
+
+ exit_err:
+ assert(0);
+ return 0;
+}
diff --git a/secmds/sesearch.c b/secmds/sesearch.c
new file mode 100644
index 0000000..ec0315f
--- /dev/null
+++ b/secmds/sesearch.c
@@ -0,0 +1,1173 @@
+/**
+ * @file
+ * Command line tool to search TE rules.
+ *
+ * @author Frank Mayer mayerf@tresys.com
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Paul Rosenfeld prosenfeld@tresys.com
+ *
+ * Copyright (C) 2003-2009 Tresys Technology, LLC
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <config.h>
+
+/* libapol */
+#include <apol/policy.h>
+#include <apol/policy-query.h>
+#include <apol/render.h>
+#include <apol/util.h>
+#include <apol/vector.h>
+
+/* libqpol*/
+#include <qpol/policy.h>
+#include <qpol/policy_extend.h>
+#include <qpol/syn_rule_query.h>
+#include <qpol/util.h>
+
+/* other */
+#include <errno.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+#include <getopt.h>
+#include <string.h>
+#include <stdbool.h>
+
+#define COPYRIGHT_INFO "Copyright (C) 2003-2009 Tresys Technology, LLC"
+
+static char *policy_file = NULL;
+
+enum opt_values
+{
+ RULE_NEVERALLOW = 256, RULE_AUDIT, RULE_AUDITALLOW, RULE_DONTAUDIT,
+ RULE_ROLE_ALLOW, RULE_ROLE_TRANS, RULE_RANGE_TRANS, RULE_ALL,
+ EXPR_ROLE_SOURCE, EXPR_ROLE_TARGET
+};
+
+static struct option const longopts[] = {
+ {"allow", no_argument, NULL, 'A'},
+ {"neverallow", no_argument, NULL, RULE_NEVERALLOW},
+ {"audit", no_argument, NULL, RULE_AUDIT},
+ {"auditallow", no_argument, NULL, RULE_AUDITALLOW},
+ {"dontaudit", no_argument, NULL, RULE_DONTAUDIT},
+ {"type", no_argument, NULL, 'T'},
+ {"role_allow", no_argument, NULL, RULE_ROLE_ALLOW},
+ {"role_trans", no_argument, NULL, RULE_ROLE_TRANS},
+ {"range_trans", no_argument, NULL, RULE_RANGE_TRANS},
+ {"all", no_argument, NULL, RULE_ALL},
+
+ {"source", required_argument, NULL, 's'},
+ {"target", required_argument, NULL, 't'},
+ {"role_source", required_argument, NULL, EXPR_ROLE_SOURCE},
+ {"role_target", required_argument, NULL, EXPR_ROLE_TARGET},
+ {"class", required_argument, NULL, 'c'},
+ {"perm", required_argument, NULL, 'p'},
+ {"bool", required_argument, NULL, 'b'},
+
+ {"direct", no_argument, NULL, 'd'},
+ {"regex", no_argument, NULL, 'R'},
+ {"linenum", no_argument, NULL, 'n'},
+ {"semantic", no_argument, NULL, 'S'},
+ {"show_cond", no_argument, NULL, 'C'},
+ {"help", no_argument, NULL, 'h'},
+ {"version", no_argument, NULL, 'V'},
+ {NULL, 0, NULL, 0}
+};
+
+typedef struct options
+{
+ char *src_name;
+ char *tgt_name;
+ char *src_role_name;
+ char *tgt_role_name;
+ char *class_name;
+ char *permlist;
+ char *bool_name;
+ apol_vector_t *class_vector;
+ bool all;
+ bool lineno;
+ bool semantic;
+ bool indirect;
+ bool allow;
+ bool nallow;
+ bool auditallow;
+ bool dontaudit;
+ bool type;
+ bool rtrans;
+ bool role_allow;
+ bool role_trans;
+ bool useregex;
+ bool show_cond;
+ apol_vector_t *perm_vector;
+} options_t;
+
+void usage(const char *program_name, int brief)
+{
+ printf("Usage: %s [OPTIONS] RULE_TYPE [RULE_TYPE ...] [EXPESSION] [POLICY ...]\n\n", program_name);
+ if (brief) {
+ printf("\tTry %s --help for more help.\n\n", program_name);
+ return;
+ }
+ printf("Search the rules in a SELinux policy.\n\n");
+ printf("RULE_TYPES:\n");
+ printf(" -A, --allow allow rules\n");
+ printf(" --neverallow neverallow rules\n");
+ printf(" --auditallow auditallow rules\n");
+ printf(" --dontaudit dontaudit rules\n");
+ printf(" -T, --type type_trans, type_member, and type_change\n");
+ printf(" --role_allow role allow rules\n");
+ printf(" --role_trans role_transition rules\n");
+ printf(" --range_trans range_transition rules\n");
+ printf(" --all all rules regardless of type, class, or perms\n");
+ printf("EXPRESSIONS:\n");
+ printf(" -s NAME, --source=NAME rules with type/attribute NAME as source\n");
+ printf(" -t NAME, --target=NAME rules with type/attribute NAME as target\n");
+ printf(" --role_source=NAME rules with role NAME as source\n");
+ printf(" --role_target=NAME rules with role NAME as target\n");
+ printf(" -c NAME, --class=NAME rules with class NAME as the object class\n");
+ printf(" -p P1[,P2,...], --perm=P1[,P2...]\n");
+ printf(" rules with the specified permission\n");
+ printf(" -b NAME, --bool=NAME conditional rules with NAME in the expression\n");
+ printf("OPTIONS:\n");
+ printf(" -d, --direct do not search for type's attributes\n");
+ printf(" -R, --regex use regular expression matching\n");
+ printf(" -n, --linenum show line number for each rule if available\n");
+ printf(" -S, --semantic search rules semantically instead of syntactically\n");
+ printf(" -C, --show_cond show conditional expression for conditional rules\n");
+ printf(" -h, --help print this help text and exit\n");
+ printf(" -V, --version print version information and exit\n");
+ printf("\n");
+ printf("If no expression is specified, then all rules are shown.\n");
+ printf("\n");
+ printf("The default source policy, or if that is unavailable the default binary\n");
+ printf("policy, will be opened if no policy is provided.\n\n");
+}
+
+static int perform_av_query(const apol_policy_t * policy, const options_t * opt, apol_vector_t ** v)
+{
+ apol_avrule_query_t *avq = NULL;
+ unsigned int rules = 0;
+ int error = 0;
+ char *tmp = NULL, *tok = NULL, *s = NULL;
+
+ if (!policy || !opt || !v) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (!opt->all && !opt->allow && !opt->nallow && !opt->auditallow && !opt->dontaudit) {
+ *v = NULL;
+ return 0; /* no search to do */
+ }
+
+ avq = apol_avrule_query_create();
+ if (!avq) {
+ ERR(policy, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ if (opt->allow || opt->all)
+ rules |= QPOL_RULE_ALLOW;
+ if (opt->nallow || opt->all) // Add this regardless of policy capabilities
+ rules |= QPOL_RULE_NEVERALLOW;
+ if (opt->auditallow || opt->all)
+ rules |= QPOL_RULE_AUDITALLOW;
+ if (opt->dontaudit || opt->all)
+ rules |= QPOL_RULE_DONTAUDIT;
+ if (rules != 0) // Setting rules = 0 means you want all the rules
+ apol_avrule_query_set_rules(policy, avq, rules);
+ apol_avrule_query_set_regex(policy, avq, opt->useregex);
+ if (opt->src_name)
+ apol_avrule_query_set_source(policy, avq, opt->src_name, opt->indirect);
+ if (opt->tgt_name)
+ apol_avrule_query_set_target(policy, avq, opt->tgt_name, opt->indirect);
+ if (opt->bool_name)
+ apol_avrule_query_set_bool(policy, avq, opt->bool_name);
+ if (opt->class_name) {
+ if (opt->class_vector == NULL) {
+ if (apol_avrule_query_append_class(policy, avq, opt->class_name)) {
+ error = errno;
+ goto err;
+ }
+ } else {
+ for (size_t i = 0; i < apol_vector_get_size(opt->class_vector); ++i) {
+ char *class_name;
+ class_name = apol_vector_get_element(opt->class_vector, i);
+ if (!class_name)
+ continue;
+ if (apol_avrule_query_append_class(policy, avq, class_name)) {
+ error = errno;
+ goto err;
+ }
+ }
+ }
+ }
+
+ if (opt->permlist) {
+ tmp = strdup(opt->permlist);
+ for (tok = strtok(tmp, ","); tok; tok = strtok(NULL, ",")) {
+ if (apol_avrule_query_append_perm(policy, avq, tok)) {
+ error = errno;
+ goto err;
+ }
+ if ((s = strdup(tok)) == NULL || apol_vector_append(opt->perm_vector, s) < 0) {
+ error = errno;
+ goto err;
+ }
+ s = NULL;
+ }
+ free(tmp);
+ }
+
+ if (!(opt->semantic) && qpol_policy_has_capability(apol_policy_get_qpol(policy), QPOL_CAP_SYN_RULES)) {
+ if (apol_syn_avrule_get_by_query(policy, avq, v)) {
+ error = errno;
+ goto err;
+ }
+ } else {
+ if (apol_avrule_get_by_query(policy, avq, v)) {
+ error = errno;
+ goto err;
+ }
+ }
+
+ apol_avrule_query_destroy(&avq);
+ return 0;
+
+ err:
+ apol_vector_destroy(v);
+ apol_avrule_query_destroy(&avq);
+ free(tmp);
+ free(s);
+ ERR(policy, "%s", strerror(error));
+ errno = error;
+ return -1;
+}
+
+static void print_syn_av_results(const apol_policy_t * policy, const options_t * opt, const apol_vector_t * v)
+{
+ qpol_policy_t *q = apol_policy_get_qpol(policy);
+ size_t i, num_rules = 0;
+ const apol_vector_t *syn_list = NULL;
+ const qpol_syn_avrule_t *rule = NULL;
+ char *tmp = NULL, *rule_str = NULL, *expr = NULL;
+ char enable_char = ' ', branch_char = ' ';
+ const qpol_cond_t *cond = NULL;
+ uint32_t enabled = 0, is_true = 0;
+ unsigned long lineno = 0;
+
+ if (!policy || !v)
+ return;
+
+ syn_list = v;
+ if (!(num_rules = apol_vector_get_size(syn_list)))
+ goto cleanup;
+
+ fprintf(stdout, "Found %zd syntactic av rules:\n", num_rules);
+
+ for (i = 0; i < num_rules; i++) {
+ rule = apol_vector_get_element(syn_list, i);
+ enable_char = branch_char = ' ';
+ if (opt->show_cond) {
+ if (qpol_syn_avrule_get_cond(q, rule, &cond))
+ goto cleanup;
+ if (cond) {
+ if (qpol_syn_avrule_get_is_enabled(q, rule, &enabled) < 0 || qpol_cond_eval(q, cond, &is_true) < 0)
+ goto cleanup;
+ tmp = apol_cond_expr_render(policy, cond);
+ enable_char = (enabled ? 'E' : 'D');
+ branch_char = ((is_true && enabled) || (!is_true && !enabled) ? 'T' : 'F');
+ asprintf(&expr, "[ %s ]", tmp);
+ free(tmp);
+ tmp = NULL;
+ if (!expr)
+ goto cleanup;
+ }
+ }
+ if (!(rule_str = apol_syn_avrule_render(policy, rule)))
+ goto cleanup;
+ if (opt->lineno) {
+ if (qpol_syn_avrule_get_lineno(q, rule, &lineno))
+ goto cleanup;
+ fprintf(stdout, "%c%c [%7lu] %s %s\n", enable_char, branch_char, lineno, rule_str, expr ? expr : "");
+ } else {
+ fprintf(stdout, "%c%c %s %s\n", enable_char, branch_char, rule_str, expr ? expr : "");
+ }
+ free(rule_str);
+ rule_str = NULL;
+ free(expr);
+ expr = NULL;
+ }
+
+ cleanup:
+ free(tmp);
+ free(rule_str);
+ free(expr);
+}
+
+static void print_av_results(const apol_policy_t * policy, const options_t * opt, const apol_vector_t * v)
+{
+ qpol_policy_t *q = apol_policy_get_qpol(policy);
+ size_t i, num_rules = 0;
+ const qpol_avrule_t *rule = NULL;
+ char *tmp = NULL, *rule_str = NULL, *expr = NULL;
+ char enable_char = ' ', branch_char = ' ';
+ qpol_iterator_t *iter = NULL;
+ const qpol_cond_t *cond = NULL;
+ uint32_t enabled = 0, list = 0;
+
+ if (!policy || !v)
+ return;
+
+ if (!(num_rules = apol_vector_get_size(v)))
+ return;
+
+ fprintf(stdout, "Found %zd semantic av rules:\n", num_rules);
+
+ for (i = 0; i < num_rules; i++) {
+ enable_char = branch_char = ' ';
+ if (!(rule = apol_vector_get_element(v, i)))
+ goto cleanup;
+ if (opt->show_cond) {
+ if (qpol_avrule_get_cond(q, rule, &cond))
+ goto cleanup;
+ if (qpol_avrule_get_is_enabled(q, rule, &enabled))
+ goto cleanup;
+ if (cond) {
+ if (qpol_avrule_get_which_list(q, rule, &list))
+ goto cleanup;
+ tmp = apol_cond_expr_render(policy, cond);
+ qpol_iterator_destroy(&iter);
+ enable_char = (enabled ? 'E' : 'D');
+ branch_char = (list ? 'T' : 'F');
+ asprintf(&expr, "[ %s ]", tmp);
+ free(tmp);
+ tmp = NULL;
+ if (!expr)
+ goto cleanup;
+ }
+ }
+ if (!(rule_str = apol_avrule_render(policy, rule)))
+ goto cleanup;
+ fprintf(stdout, "%c%c %s %s\n", enable_char, branch_char, rule_str, expr ? expr : "");
+ free(rule_str);
+ rule_str = NULL;
+ free(expr);
+ expr = NULL;
+ }
+
+ cleanup:
+ free(tmp);
+ free(rule_str);
+ free(expr);
+}
+
+static int perform_te_query(const apol_policy_t * policy, const options_t * opt, apol_vector_t ** v)
+{
+ apol_terule_query_t *teq = NULL;
+ unsigned int rules = 0;
+ int error = 0;
+
+ if (!policy || !opt || !v) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (opt->all || opt->type) {
+ rules = (QPOL_RULE_TYPE_TRANS | QPOL_RULE_TYPE_CHANGE | QPOL_RULE_TYPE_MEMBER);
+ } else {
+ *v = NULL;
+ return 0; /* no search to do */
+ }
+
+ teq = apol_terule_query_create();
+ if (!teq) {
+ ERR(policy, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ apol_terule_query_set_rules(policy, teq, rules);
+ apol_terule_query_set_regex(policy, teq, opt->useregex);
+ if (opt->src_name)
+ apol_terule_query_set_source(policy, teq, opt->src_name, opt->indirect);
+ if (opt->tgt_name)
+ apol_terule_query_set_target(policy, teq, opt->tgt_name, opt->indirect);
+ if (opt->bool_name)
+ apol_terule_query_set_bool(policy, teq, opt->bool_name);
+ if (opt->class_name) {
+ if (opt->class_vector == NULL) {
+ if (apol_terule_query_append_class(policy, teq, opt->class_name)) {
+ error = errno;
+ goto err;
+ }
+ } else {
+ for (size_t i = 0; i < apol_vector_get_size(opt->class_vector); ++i) {
+ char *class_name;
+ class_name = apol_vector_get_element(opt->class_vector, i);
+ if (!class_name)
+ continue;
+ if (apol_terule_query_append_class(policy, teq, class_name)) {
+ error = errno;
+ goto err;
+ }
+ }
+ }
+ }
+
+ if (!(opt->semantic) && qpol_policy_has_capability(apol_policy_get_qpol(policy), QPOL_CAP_SYN_RULES)) {
+ if (apol_syn_terule_get_by_query(policy, teq, v)) {
+ error = errno;
+ goto err;
+ }
+ } else {
+ if (apol_terule_get_by_query(policy, teq, v)) {
+ error = errno;
+ goto err;
+ }
+ }
+
+ apol_terule_query_destroy(&teq);
+ return 0;
+
+ err:
+ apol_vector_destroy(v);
+ apol_terule_query_destroy(&teq);
+ ERR(policy, "%s", strerror(error));
+ errno = error;
+ return -1;
+}
+
+static void print_syn_te_results(const apol_policy_t * policy, const options_t * opt, const apol_vector_t * v)
+{
+ qpol_policy_t *q = apol_policy_get_qpol(policy);
+ size_t i, num_rules = 0;
+ const apol_vector_t *syn_list = NULL;
+ const qpol_syn_terule_t *rule = NULL;
+ char *tmp = NULL, *rule_str = NULL, *expr = NULL;
+ char enable_char = ' ', branch_char = ' ';
+ const qpol_cond_t *cond = NULL;
+ uint32_t enabled = 0, is_true = 0;
+ unsigned long lineno = 0;
+
+ if (!policy || !v)
+ return;
+
+ syn_list = v;
+ if (!(num_rules = apol_vector_get_size(syn_list)))
+ goto cleanup;
+
+ fprintf(stdout, "Found %zd syntactic te rules:\n", num_rules);
+
+ for (i = 0; i < num_rules; i++) {
+ rule = apol_vector_get_element(syn_list, i);
+ enable_char = branch_char = ' ';
+ if (opt->show_cond) {
+ if (qpol_syn_terule_get_cond(q, rule, &cond))
+ goto cleanup;
+ if (cond) {
+ if (qpol_syn_terule_get_is_enabled(q, rule, &enabled) < 0 || qpol_cond_eval(q, cond, &is_true) < 0)
+ goto cleanup;
+ tmp = apol_cond_expr_render(policy, cond);
+ enable_char = (enabled ? 'E' : 'D');
+ branch_char = ((is_true && enabled) || (!is_true && !enabled) ? 'T' : 'F');
+ asprintf(&expr, "[ %s ]", tmp);
+ free(tmp);
+ tmp = NULL;
+ if (!expr)
+ break;
+ }
+ }
+ if (!(rule_str = apol_syn_terule_render(policy, rule)))
+ goto cleanup;
+ if (opt->lineno) {
+ if (qpol_syn_terule_get_lineno(q, rule, &lineno))
+ goto cleanup;
+ fprintf(stdout, "%c%c [%7lu] %s %s\n", enable_char, branch_char, lineno, rule_str, expr ? expr : "");
+ } else {
+ fprintf(stdout, "%c%c %s %s\n", enable_char, branch_char, rule_str, expr ? expr : "");
+ }
+ free(rule_str);
+ rule_str = NULL;
+ free(expr);
+ expr = NULL;
+ }
+
+ cleanup:
+ free(tmp);
+ free(rule_str);
+ free(expr);
+}
+
+static void print_te_results(const apol_policy_t * policy, const options_t * opt, const apol_vector_t * v)
+{
+ qpol_policy_t *q = apol_policy_get_qpol(policy);
+ size_t i, num_rules = 0;
+ const qpol_terule_t *rule = NULL;
+ char *tmp = NULL, *rule_str = NULL, *expr = NULL;
+ char enable_char = ' ', branch_char = ' ';
+ qpol_iterator_t *iter = NULL;
+ const qpol_cond_t *cond = NULL;
+ uint32_t enabled = 0, list = 0;
+
+ if (!policy || !v)
+ goto cleanup;
+
+ if (!(num_rules = apol_vector_get_size(v)))
+ goto cleanup;
+
+ fprintf(stdout, "Found %zd semantic te rules:\n", num_rules);
+
+ for (i = 0; i < num_rules; i++) {
+ enable_char = branch_char = ' ';
+ if (!(rule = apol_vector_get_element(v, i)))
+ goto cleanup;
+ if (opt->show_cond) {
+ if (qpol_terule_get_cond(q, rule, &cond))
+ goto cleanup;
+ if (qpol_terule_get_is_enabled(q, rule, &enabled))
+ goto cleanup;
+ if (cond) {
+ if (qpol_terule_get_which_list(q, rule, &list))
+ goto cleanup;
+ if (qpol_cond_get_expr_node_iter(q, cond, &iter))
+ goto cleanup;
+ tmp = apol_cond_expr_render(policy, cond);
+ qpol_iterator_destroy(&iter);
+ enable_char = (enabled ? 'E' : 'D');
+ branch_char = (list ? 'T' : 'F');
+ asprintf(&expr, "[ %s ]", tmp);
+ free(tmp);
+ tmp = NULL;
+ if (!expr)
+ goto cleanup;
+ }
+ }
+ if (!(rule_str = apol_terule_render(policy, rule)))
+ goto cleanup;
+ fprintf(stdout, "%c%c %s %s\n", enable_char, branch_char, rule_str, expr ? expr : "");
+ free(rule_str);
+ rule_str = NULL;
+ free(expr);
+ expr = NULL;
+ }
+
+ cleanup:
+ free(tmp);
+ free(rule_str);
+ free(expr);
+}
+
+static int perform_ra_query(const apol_policy_t * policy, const options_t * opt, apol_vector_t ** v)
+{
+ apol_role_allow_query_t *raq = NULL;
+ int error = 0;
+
+ if (!policy || !opt || !v) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (!opt->role_allow && !opt->all) {
+ *v = NULL;
+ return 0; /* no search to do */
+ }
+
+ raq = apol_role_allow_query_create();
+ if (!raq) {
+ ERR(policy, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ apol_role_allow_query_set_regex(policy, raq, opt->useregex);
+ if (opt->src_role_name) {
+ if (apol_role_allow_query_set_source(policy, raq, opt->src_role_name)) {
+ error = errno;
+ goto err;
+ }
+ }
+ if (opt->tgt_role_name)
+ if (apol_role_allow_query_set_target(policy, raq, opt->tgt_role_name)) {
+ error = errno;
+ goto err;
+ }
+
+ if (apol_role_allow_get_by_query(policy, raq, v)) {
+ error = errno;
+ goto err;
+ }
+
+ apol_role_allow_query_destroy(&raq);
+ return 0;
+
+ err:
+ apol_vector_destroy(v);
+ apol_role_allow_query_destroy(&raq);
+ ERR(policy, "%s", strerror(error));
+ errno = error;
+ return -1;
+}
+
+static void print_ra_results(const apol_policy_t * policy, const options_t * opt __attribute__ ((unused)), const apol_vector_t * v)
+{
+ size_t i, num_rules = 0;
+ const qpol_role_allow_t *rule = NULL;
+ char *tmp = NULL;
+
+ if (!policy || !v)
+ return;
+
+ if (!(num_rules = apol_vector_get_size(v)))
+ return;
+
+ fprintf(stdout, "Found %zd role allow rules:\n", num_rules);
+
+ for (i = 0; i < num_rules; i++) {
+ if (!(rule = apol_vector_get_element(v, i)))
+ break;
+ if (!(tmp = apol_role_allow_render(policy, rule)))
+ break;
+ fprintf(stdout, " %s\n", tmp);
+ free(tmp);
+ tmp = NULL;
+ }
+}
+
+static int perform_rt_query(const apol_policy_t * policy, const options_t * opt, apol_vector_t ** v)
+{
+ apol_role_trans_query_t *rtq = NULL;
+ int error = 0;
+
+ if (!policy || !opt || !v) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (!opt->role_trans && !opt->all) {
+ *v = NULL;
+ return 0; /* no search to do */
+ }
+
+ rtq = apol_role_trans_query_create();
+ if (!rtq) {
+ ERR(policy, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ apol_role_trans_query_set_regex(policy, rtq, opt->useregex);
+ if (opt->src_role_name) {
+ if (apol_role_trans_query_set_source(policy, rtq, opt->src_role_name)) {
+ error = errno;
+ goto err;
+ }
+ }
+ if (opt->tgt_name) {
+ if (apol_role_trans_query_set_target(policy, rtq, opt->tgt_name, opt->indirect)) {
+ error = errno;
+ goto err;
+ }
+ }
+
+ if (apol_role_trans_get_by_query(policy, rtq, v)) {
+ error = errno;
+ goto err;
+ }
+
+ apol_role_trans_query_destroy(&rtq);
+ return 0;
+
+ err:
+ apol_vector_destroy(v);
+ apol_role_trans_query_destroy(&rtq);
+ ERR(policy, "%s", strerror(error));
+ errno = error;
+ return -1;
+}
+
+static void print_rt_results(const apol_policy_t * policy, const options_t * opt __attribute__ ((unused)), const apol_vector_t * v)
+{
+ size_t i, num_rules = 0;
+ const qpol_role_trans_t *rule = NULL;
+ char *tmp = NULL;
+
+ if (!policy || !v)
+ return;
+
+ if (!(num_rules = apol_vector_get_size(v)))
+ return;
+
+ fprintf(stdout, "Found %zd role_transition rules:\n", num_rules);
+
+ for (i = 0; i < num_rules; i++) {
+ if (!(rule = apol_vector_get_element(v, i)))
+ break;
+ if (!(tmp = apol_role_trans_render(policy, rule)))
+ break;
+ fprintf(stdout, " %s\n", tmp);
+ free(tmp);
+ tmp = NULL;
+ }
+}
+
+static int perform_range_query(const apol_policy_t * policy, const options_t * opt, apol_vector_t ** v)
+{
+ apol_range_trans_query_t *rtq = NULL;
+ int error = 0;
+
+ if (!policy || !opt || !v) {
+ ERR(policy, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (!opt->rtrans && !opt->all) {
+ *v = NULL;
+ return 0; /* no search to do */
+ }
+
+ rtq = apol_range_trans_query_create();
+ if (!rtq) {
+ ERR(policy, "%s", strerror(ENOMEM));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ apol_range_trans_query_set_regex(policy, rtq, opt->useregex);
+ if (opt->src_name) {
+ if (apol_range_trans_query_set_source(policy, rtq, opt->src_name, opt->indirect)) {
+ error = errno;
+ goto err;
+ }
+ }
+ if (opt->tgt_name) {
+ if (apol_range_trans_query_set_target(policy, rtq, opt->tgt_name, opt->indirect)) {
+ error = errno;
+ goto err;
+ }
+ }
+ if (opt->class_name) {
+ if (opt->class_vector == NULL) {
+ if (apol_range_trans_query_append_class(policy, rtq, opt->class_name)) {
+ error = errno;
+ goto err;
+ }
+ } else {
+ for (size_t i = 0; i < apol_vector_get_size(opt->class_vector); ++i) {
+ char *class_name;
+ class_name = apol_vector_get_element(opt->class_vector, i);
+ if (!class_name)
+ continue;
+ if (apol_range_trans_query_append_class(policy, rtq, class_name)) {
+ error = errno;
+ goto err;
+ }
+ }
+ }
+ }
+
+ if (apol_range_trans_get_by_query(policy, rtq, v)) {
+ error = errno;
+ goto err;
+ }
+
+ apol_range_trans_query_destroy(&rtq);
+ return 0;
+
+ err:
+ apol_vector_destroy(v);
+ apol_range_trans_query_destroy(&rtq);
+ ERR(policy, "%s", strerror(error));
+ errno = error;
+ return -1;
+}
+
+static void print_range_results(const apol_policy_t * policy, const options_t * opt
+ __attribute__ ((unused)), const apol_vector_t * v)
+{
+ size_t i, num_rules = 0;
+ const qpol_range_trans_t *rule = NULL;
+ char *tmp = NULL;
+
+ if (!policy || !v)
+ return;
+
+ if (!(num_rules = apol_vector_get_size(v)))
+ return;
+
+ fprintf(stdout, "Found %zd range_transition rules:\n", num_rules);
+
+ for (i = 0; i < num_rules; i++) {
+ if (!(rule = apol_vector_get_element(v, i)))
+ break;
+ if (!(tmp = apol_range_trans_render(policy, rule)))
+ break;
+ fprintf(stdout, " %s\n", tmp);
+ free(tmp);
+ tmp = NULL;
+ }
+}
+
+int main(int argc, char **argv)
+{
+ options_t cmd_opts;
+ int optc, rt = -1;
+
+ apol_policy_t *policy = NULL;
+ apol_vector_t *v = NULL;
+ apol_policy_path_t *pol_path = NULL;
+ apol_vector_t *mod_paths = NULL;
+ apol_policy_path_type_e path_type = APOL_POLICY_PATH_TYPE_MONOLITHIC;
+
+ memset(&cmd_opts, 0, sizeof(cmd_opts));
+ cmd_opts.indirect = true;
+ while ((optc = getopt_long(argc, argv, "ATs:t:c:p:b:dRnSChV", longopts, NULL)) != -1) {
+ switch (optc) {
+ case 0:
+ break;
+ case 's': /* source */
+ if (optarg == 0) {
+ usage(argv[0], 1);
+ printf("Missing source type/attribute for -s (--source)\n");
+ exit(1);
+ }
+ cmd_opts.src_name = strdup(optarg);
+ if (!cmd_opts.src_name) {
+ fprintf(stderr, "%s\n", strerror(errno));
+ exit(1);
+ }
+ break;
+ case 't': /* target */
+ if (optarg == 0) {
+ usage(argv[0], 1);
+ printf("Missing target type/attribute for -t (--target)\n");
+ exit(1);
+ }
+ cmd_opts.tgt_name = strdup(optarg);
+ if (!cmd_opts.tgt_name) {
+ fprintf(stderr, "%s\n", strerror(errno));
+ exit(1);
+ }
+ break;
+ case EXPR_ROLE_SOURCE:
+ if (optarg == 0) {
+ usage(argv[0], 1);
+ printf("Missing source role for --role_source\n");
+ exit(1);
+ }
+ cmd_opts.src_role_name = strdup(optarg);
+ if (!cmd_opts.src_role_name) {
+ fprintf(stderr, "%s\n", strerror(errno));
+ exit(1);
+ }
+ break;
+ case EXPR_ROLE_TARGET:
+ if (optarg == 0) {
+ usage(argv[0], 1);
+ printf("Missing target role for --role_target\n");
+ exit(1);
+ }
+ cmd_opts.tgt_role_name = strdup(optarg);
+ if (!cmd_opts.tgt_role_name) {
+ fprintf(stderr, "%s\n", strerror(errno));
+ exit(1);
+ }
+ break;
+ case 'c': /* class */
+ if (optarg == 0) {
+ usage(argv[0], 1);
+ printf("Missing object class for -c (--class)\n");
+ exit(1);
+ }
+ cmd_opts.class_name = strdup(optarg);
+ if (!cmd_opts.class_name) {
+ fprintf(stderr, "%s\n", strerror(errno));
+ exit(1);
+ }
+ break;
+ case 'p': /* permission */
+ if (optarg == 0) {
+ usage(argv[0], 1);
+ printf("Missing permissions for -p (--perm)\n");
+ exit(1);
+ }
+ if ((cmd_opts.permlist = strdup(optarg)) == NULL
+ || (cmd_opts.perm_vector = apol_vector_create(free)) == NULL) {
+ fprintf(stderr, "%s\n", strerror(errno));
+ exit(1);
+ }
+ break;
+ case 'b':
+ if (optarg == 0) {
+ usage(argv[0], 1);
+ printf("Missing boolean for -b (--bool)\n");
+ exit(1);
+ }
+ cmd_opts.bool_name = strdup(optarg);
+ if (!cmd_opts.bool_name) {
+ fprintf(stderr, "%s\n", strerror(errno));
+ exit(1);
+ }
+ break;
+ case 'd': /* direct search */
+ cmd_opts.indirect = false;
+ break;
+ case 'R': /* use regex */
+ cmd_opts.useregex = true;
+ break;
+ case 'A': /* allow */
+ cmd_opts.allow = true;
+ break;
+ case RULE_NEVERALLOW: /* neverallow */
+ cmd_opts.nallow = true;
+ break;
+ case RULE_AUDIT: /* audit */
+ cmd_opts.auditallow = true;
+ cmd_opts.dontaudit = true;
+ fprintf(stderr, "Use of --audit is deprecated; use --auditallow and --dontaudit instead.\n");
+ break;
+ case RULE_AUDITALLOW:
+ cmd_opts.auditallow = true;
+ break;
+ case RULE_DONTAUDIT:
+ cmd_opts.dontaudit = true;
+ break;
+ case 'T': /* type */
+ cmd_opts.type = true;
+ break;
+ case RULE_ROLE_ALLOW:
+ cmd_opts.role_allow = true;
+ break;
+ case RULE_ROLE_TRANS:
+ cmd_opts.role_trans = true;
+ break;
+ case RULE_RANGE_TRANS: /* range transition */
+ cmd_opts.rtrans = true;
+ break;
+ case RULE_ALL: /* all */
+ cmd_opts.all = true;
+ break;
+ case 'n': /* lineno */
+ cmd_opts.lineno = true;
+ break;
+ case 'S': /* semantic */
+ cmd_opts.semantic = true;
+ break;
+ case 'C':
+ cmd_opts.show_cond = true;
+ break;
+ case 'h': /* help */
+ usage(argv[0], 0);
+ exit(0);
+ case 'V': /* version */
+ printf("sesearch %s\n%s\n", VERSION, COPYRIGHT_INFO);
+ exit(0);
+ default:
+ usage(argv[0], 1);
+ exit(1);
+ }
+ }
+
+ if (!(cmd_opts.allow || cmd_opts.nallow || cmd_opts.auditallow || cmd_opts.dontaudit || cmd_opts.role_allow ||
+ cmd_opts.type || cmd_opts.rtrans || cmd_opts.role_trans || cmd_opts.all)) {
+ usage(argv[0], 1);
+ fprintf(stderr, "One of --all, --allow, --neverallow, --auditallow, --dontaudit,\n"
+ "--range_trans, --type, --role_allow, or --role_trans must be specified.\n");
+ exit(1);
+ }
+
+ int pol_opt = 0;
+ if (!(cmd_opts.nallow || cmd_opts.all))
+ pol_opt |= QPOL_POLICY_OPTION_NO_NEVERALLOWS;
+
+ if (argc - optind < 1) {
+ rt = qpol_default_policy_find(&policy_file);
+ if (rt < 0) {
+ fprintf(stderr, "Default policy search failed: %s\n", strerror(errno));
+ exit(1);
+ } else if (rt != 0) {
+ fprintf(stderr, "No default policy found.\n");
+ exit(1);
+ }
+ pol_opt |= QPOL_POLICY_OPTION_MATCH_SYSTEM;
+ } else {
+ if ((policy_file = strdup(argv[optind])) == NULL) {
+ fprintf(stderr, "%s\n", strerror(errno));
+ exit(1);
+ }
+ optind++;
+ }
+
+ if (argc - optind > 0) {
+ path_type = APOL_POLICY_PATH_TYPE_MODULAR;
+ if (!(mod_paths = apol_vector_create(NULL))) {
+ ERR(policy, "%s", strerror(ENOMEM));
+ exit(1);
+ }
+ for (; argc - optind; optind++) {
+ if (apol_vector_append(mod_paths, (void *)argv[optind])) {
+ ERR(policy, "Error loading module %s", argv[optind]);
+ apol_vector_destroy(&mod_paths);
+ free(policy_file);
+ exit(1);
+ }
+ }
+ } else if (apol_file_is_policy_path_list(policy_file) > 0) {
+ pol_path = apol_policy_path_create_from_file(policy_file);
+ if (!pol_path) {
+ ERR(policy, "%s", "invalid policy list");
+ free(policy_file);
+ exit(1);
+ }
+ }
+
+ if (!pol_path)
+ pol_path = apol_policy_path_create(path_type, policy_file, mod_paths);
+ if (!pol_path) {
+ ERR(policy, "%s", strerror(ENOMEM));
+ free(policy_file);
+ apol_vector_destroy(&mod_paths);
+ exit(1);
+ }
+ free(policy_file);
+ apol_vector_destroy(&mod_paths);
+
+ policy = apol_policy_create_from_policy_path(pol_path, pol_opt, NULL, NULL);
+ if (!policy) {
+ ERR(policy, "%s", strerror(errno));
+ apol_policy_path_destroy(&pol_path);
+ exit(1);
+ }
+ /* handle regex for class name */
+ if (cmd_opts.useregex && cmd_opts.class_name != NULL) {
+ cmd_opts.class_vector = apol_vector_create(NULL);
+ apol_vector_t *qpol_matching_classes = NULL;
+ apol_class_query_t *regex_match_query = apol_class_query_create();
+ apol_class_query_set_regex(policy, regex_match_query, 1);
+ apol_class_query_set_class(policy, regex_match_query, cmd_opts.class_name);
+ if (apol_class_get_by_query(policy, regex_match_query, &qpol_matching_classes)) {
+ apol_class_query_destroy(&regex_match_query);
+ goto cleanup;
+ }
+ const qpol_class_t *class = NULL;
+ for (size_t i = 0; i < apol_vector_get_size(qpol_matching_classes); ++i) {
+ const char *class_name;
+ class = apol_vector_get_element(qpol_matching_classes, i);
+ if (!class)
+ break;
+ qpol_class_get_name(apol_policy_get_qpol(policy), class, &class_name);
+ apol_vector_append(cmd_opts.class_vector, (void *)class_name);
+ }
+ if (!apol_vector_get_size(qpol_matching_classes)) {
+ apol_vector_destroy(&qpol_matching_classes);
+ apol_class_query_destroy(&regex_match_query);
+ ERR(policy, "No classes match expression %s", cmd_opts.class_name);
+ goto cleanup;
+ }
+ apol_vector_destroy(&qpol_matching_classes);
+ apol_class_query_destroy(&regex_match_query);
+ }
+
+ if (!cmd_opts.semantic && qpol_policy_has_capability(apol_policy_get_qpol(policy), QPOL_CAP_SYN_RULES)) {
+ if (qpol_policy_build_syn_rule_table(apol_policy_get_qpol(policy))) {
+ apol_policy_destroy(&policy);
+ exit(1);
+ }
+ }
+
+ /* if syntactic rules are not available always do semantic search */
+ if (!qpol_policy_has_capability(apol_policy_get_qpol(policy), QPOL_CAP_SYN_RULES)) {
+ cmd_opts.semantic = 1;
+ }
+
+ /* supress line numbers if doing semantic search or not available */
+ if (cmd_opts.semantic || !qpol_policy_has_capability(apol_policy_get_qpol(policy), QPOL_CAP_LINE_NUMBERS)) {
+ cmd_opts.lineno = 0;
+ }
+
+ if (perform_av_query(policy, &cmd_opts, &v)) {
+ rt = 1;
+ goto cleanup;
+ }
+ if (v) {
+ if (!cmd_opts.semantic && qpol_policy_has_capability(apol_policy_get_qpol(policy), QPOL_CAP_SYN_RULES))
+ print_syn_av_results(policy, &cmd_opts, v);
+ else
+ print_av_results(policy, &cmd_opts, v);
+ fprintf(stdout, "\n");
+ }
+ apol_vector_destroy(&v);
+ if (perform_te_query(policy, &cmd_opts, &v)) {
+ rt = 1;
+ goto cleanup;
+ }
+ if (v) {
+ if (!cmd_opts.semantic && qpol_policy_has_capability(apol_policy_get_qpol(policy), QPOL_CAP_SYN_RULES))
+ print_syn_te_results(policy, &cmd_opts, v);
+ else
+ print_te_results(policy, &cmd_opts, v);
+ fprintf(stdout, "\n");
+ }
+ apol_vector_destroy(&v);
+ if (perform_ra_query(policy, &cmd_opts, &v)) {
+ rt = 1;
+ goto cleanup;
+ }
+ if (v) {
+ print_ra_results(policy, &cmd_opts, v);
+ fprintf(stdout, "\n");
+ }
+ apol_vector_destroy(&v);
+ if (perform_rt_query(policy, &cmd_opts, &v)) {
+ rt = 1;
+ goto cleanup;
+ }
+ if (v) {
+ print_rt_results(policy, &cmd_opts, v);
+ fprintf(stdout, "\n");
+ }
+ apol_vector_destroy(&v);
+ if (perform_range_query(policy, &cmd_opts, &v)) {
+ rt = 1;
+ goto cleanup;
+ }
+ if (v) {
+ print_range_results(policy, &cmd_opts, v);
+ fprintf(stdout, "\n");
+ }
+ apol_vector_destroy(&v);
+ rt = 0;
+ cleanup:
+ apol_policy_destroy(&policy);
+ apol_policy_path_destroy(&pol_path);
+ free(cmd_opts.src_name);
+ free(cmd_opts.tgt_name);
+ free(cmd_opts.class_name);
+ free(cmd_opts.permlist);
+ free(cmd_opts.bool_name);
+ free(cmd_opts.src_role_name);
+ free(cmd_opts.tgt_role_name);
+ apol_vector_destroy(&cmd_opts.perm_vector);
+ apol_vector_destroy(&cmd_opts.class_vector);
+ exit(rt);
+}