sediffx.c

Go to the documentation of this file.
00001 /**
00002  *  @file
00003  *  Main program for running sediffx in a GTK+ environment.
00004  *
00005  *  @author Jeremy A. Mowery jmowery@tresys.com
00006  *  @author Jason Tang jtang@tresys.com
00007  *  @author Brandon Whalen bwhalen@tresys.com
00008  *  @author Randy Wicks rwicks@tresys.com
00009  *
00010  *  Copyright (C) 2005-2007 Tresys Technology, LLC
00011  *
00012  *  This program is free software; you can redistribute it and/or modify
00013  *  it under the terms of the GNU General Public License as published by
00014  *  the Free Software Foundation; either version 2 of the License, or
00015  *  (at your option) any later version.
00016  *
00017  *  This program is distributed in the hope that it will be useful,
00018  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00019  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00020  *  GNU General Public License for more details.
00021  *
00022  *  You should have received a copy of the GNU General Public License
00023  *  along with this program; if not, write to the Free Software
00024  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00025  */
00026 
00027 #include <config.h>
00028 
00029 #include "sediffx.h"
00030 #include "toplevel.h"
00031 
00032 #include <errno.h>
00033 #include <getopt.h>
00034 #include <stdio.h>
00035 #include <stdlib.h>
00036 #include <glade/glade.h>
00037 #include <gtk/gtk.h>
00038 
00039 struct sediffx
00040 {
00041         apol_policy_path_t *paths[SEDIFFX_POLICY_NUM];
00042         apol_policy_t *policies[SEDIFFX_POLICY_NUM];
00043         toplevel_t *top;
00044         poldiff_t *poldiff;
00045         uint32_t flags;
00046 };
00047 
00048 static struct option const longopts[] = {
00049         {"run-diff", no_argument, NULL, 'd'},
00050         {"help", no_argument, NULL, 'h'},
00051         {"version", no_argument, NULL, 'V'},
00052         {NULL, 0, NULL, 0}
00053 };
00054 
00055 void sediffx_set_policy(sediffx_t * s, sediffx_policy_e which, apol_policy_t * policy, apol_policy_path_t * path)
00056 {
00057         poldiff_destroy(&s->poldiff);
00058         if (policy != NULL) {
00059                 apol_policy_destroy(&s->policies[which]);
00060                 s->policies[which] = policy;
00061                 if (path != s->paths[which]) {
00062                         apol_policy_path_destroy(&s->paths[which]);
00063                 }
00064                 s->paths[which] = path;
00065         } else {
00066                 apol_policy_destroy(&s->policies[which]);
00067                 apol_policy_path_destroy(&s->paths[which]);
00068         }
00069 }
00070 
00071 const apol_policy_path_t *sediffx_get_policy_path(sediffx_t * sediffx, const sediffx_policy_e which)
00072 {
00073         return sediffx->paths[which];
00074 }
00075 
00076 poldiff_t *sediffx_get_poldiff(sediffx_t * s, poldiff_handle_fn_t fn, void *arg)
00077 {
00078         if (s->poldiff != NULL) {
00079                 return s->poldiff;
00080         }
00081         if (s->policies[SEDIFFX_POLICY_ORIG] == NULL || s->policies[SEDIFFX_POLICY_MOD] == NULL) {
00082                 return NULL;
00083         }
00084         s->poldiff = poldiff_create(s->policies[SEDIFFX_POLICY_ORIG], s->policies[SEDIFFX_POLICY_MOD], fn, arg);
00085         if (s->poldiff != NULL) {
00086                 /* poldiff_create() took ownership of the policies */
00087                 s->policies[SEDIFFX_POLICY_ORIG] = NULL;
00088                 s->policies[SEDIFFX_POLICY_MOD] = NULL;
00089         }
00090         return s->poldiff;
00091 }
00092 
00093 void sediffx_set_poldiff_run_flags(sediffx_t * s, uint32_t flags)
00094 {
00095         s->flags = flags;
00096 }
00097 
00098 uint32_t sediffx_get_poldiff_run_flags(sediffx_t * s)
00099 {
00100         return s->flags;
00101 }
00102 
00103 static void print_version_info(void)
00104 {
00105         printf("sediffx %s\n%s\n", VERSION, COPYRIGHT_INFO);
00106 }
00107 
00108 static void usage(const char *program_name, int brief)
00109 {
00110         printf("Usage: %s [-d] [ORIGINAL_POLICY ; MODIFIED_POLICY]\n\n", program_name);
00111         if (brief) {
00112                 printf("\tTry %s --help for more help.\n\n", program_name);
00113                 return;
00114         }
00115         printf("Semantically differentiate two policies.  All supported policy elements\n");
00116         printf("are examined.  The following options are available:\n");
00117         printf("\n");
00118         printf("  -d, --diff-now   load policies and diff immediately\n");
00119         printf("  -h, --help       print this help text and exit\n");
00120         printf("  -V, --version    print version information and exit\n\n");
00121 }
00122 
00123 struct delayed_main_data
00124 {
00125         apol_policy_path_t *orig_path, *mod_path;
00126         int run_diff;
00127         toplevel_t *top;
00128 };
00129 
00130 /*
00131  * We don't want to do the heavy work of loading and displaying
00132  * the diff before the main loop has started because it will freeze
00133  * the gui for too long. To solve this, the function is called from an
00134  * idle callback set-up in main.
00135  */
00136 static gboolean delayed_main(gpointer data)
00137 {
00138         struct delayed_main_data *dmd = (struct delayed_main_data *)data;
00139         if (toplevel_open_policies(dmd->top, dmd->orig_path, dmd->mod_path) == 0 && dmd->run_diff) {
00140                 toplevel_run_diff(dmd->top);
00141         }
00142         return FALSE;
00143 }
00144 
00145 static void sediffx_destroy(sediffx_t ** sediffx)
00146 {
00147         if (sediffx != NULL && *sediffx != NULL) {
00148                 int i;
00149                 for (i = SEDIFFX_POLICY_ORIG; i < SEDIFFX_POLICY_NUM; i++) {
00150                         apol_policy_path_destroy(&((*sediffx)->paths[i]));
00151                         apol_policy_destroy(&((*sediffx)->policies[i]));
00152                 }
00153                 poldiff_destroy(&((*sediffx)->poldiff));
00154                 free(*sediffx);
00155                 *sediffx = NULL;
00156         }
00157 }
00158 
00159 static void sediffx_parse_command_line(int argc, char **argv, apol_policy_path_t ** orig_path, apol_policy_path_t ** mod_path,
00160                                        int *run_diff)
00161 {
00162         int optc;
00163         *orig_path = NULL;
00164         *mod_path = NULL;
00165         *run_diff = 0;
00166         while ((optc = getopt_long(argc, argv, "dhV", longopts, NULL)) != -1) {
00167                 switch (optc) {
00168                 case 0:
00169                         break;
00170                 case 'd':              /* run the diff only for gui */
00171                         *run_diff = 1;
00172                         break;
00173                 case 'h':              /* help */
00174                         usage(argv[0], 0);
00175                         exit(EXIT_SUCCESS);
00176                 case 'V':              /* version */
00177                         print_version_info();
00178                         exit(EXIT_SUCCESS);
00179                 default:
00180                         usage(argv[0], 1);
00181                         exit(EXIT_FAILURE);
00182                 }
00183         }
00184 
00185         if (argc - optind == 0) {
00186                 /* here we have found no missing arguments, but
00187                  * perhaps the user specified -d with no files */
00188                 if (*run_diff) {
00189                         usage(argv[0], 0);
00190                         exit(EXIT_FAILURE);
00191                 }
00192                 return;
00193         } else if (argc - optind == 1) {
00194                 usage(argv[0], 1);
00195                 exit(EXIT_FAILURE);
00196         }
00197         if (argc - optind == 2) {
00198                 /* sediffx with file names, old syntax */
00199                 if (strcmp(argv[optind], ";") == 0 || strcmp(argv[optind + 1], ";") == 0) {
00200                         usage(argv[0], 1);
00201                         exit(EXIT_FAILURE);
00202                 }
00203                 *orig_path = apol_policy_path_create(APOL_POLICY_PATH_TYPE_MONOLITHIC, argv[optind], NULL);
00204                 *mod_path = apol_policy_path_create(APOL_POLICY_PATH_TYPE_MONOLITHIC, argv[optind + 1], NULL);
00205                 if (*orig_path == NULL || *mod_path == NULL) {
00206                         ERR(NULL, "%s", strerror(errno));
00207                         exit(EXIT_FAILURE);
00208                 }
00209                 return;
00210         }
00211 
00212         /* module lists */
00213         char *orig_base_path = NULL;
00214         apol_vector_t *orig_module_paths = NULL;
00215         char *mod_base_path = NULL;
00216         apol_vector_t *mod_module_paths = NULL;
00217         apol_policy_path_type_e orig_path_type = APOL_POLICY_PATH_TYPE_MONOLITHIC;
00218         apol_policy_path_type_e mod_path_type = APOL_POLICY_PATH_TYPE_MONOLITHIC;
00219 
00220         orig_base_path = argv[optind++];
00221         if (!(orig_module_paths = apol_vector_create(NULL))) {
00222                 ERR(NULL, "%s", strerror(errno));
00223                 goto err;
00224         }
00225         for (; argc - optind; optind++) {
00226                 if (!strcmp(";", argv[optind])) {
00227                         optind++;
00228                         break;
00229                 }
00230                 if (apol_vector_append(orig_module_paths, (void *)argv[optind])) {
00231                         ERR(NULL, "Error loading module %s", argv[optind]);
00232                         goto err;
00233                 }
00234                 orig_path_type = APOL_POLICY_PATH_TYPE_MODULAR;
00235         }
00236         if (apol_file_is_policy_path_list(orig_base_path) > 0) {
00237                 *orig_path = apol_policy_path_create_from_file(orig_base_path);
00238                 if (*orig_path == NULL) {
00239                         ERR(NULL, "%s", "invalid policy list");
00240                         goto err;
00241                 }
00242         } else {
00243                 *orig_path = apol_policy_path_create(orig_path_type, orig_base_path, orig_module_paths);
00244                 if (*orig_path == NULL) {
00245                         ERR(NULL, "%s", strerror(errno));
00246                         goto err;
00247                 }
00248         }
00249         apol_vector_destroy(&orig_module_paths);
00250 
00251         if (argc - optind == 0) {
00252                 ERR(NULL, "%s", "Missing path to modified policy.");
00253                 goto err;
00254         }
00255 
00256         mod_base_path = argv[optind++];
00257         if (!(mod_module_paths = apol_vector_create(NULL))) {
00258                 ERR(NULL, "%s", strerror(errno));
00259                 goto err;
00260         }
00261         for (; argc - optind; optind++) {
00262                 if (apol_vector_append(mod_module_paths, (void *)argv[optind])) {
00263                         ERR(NULL, "Error loading module %s", argv[optind]);
00264                         goto err;
00265                 }
00266                 mod_path_type = APOL_POLICY_PATH_TYPE_MODULAR;
00267         }
00268         if (apol_file_is_policy_path_list(mod_base_path) > 0) {
00269                 *mod_path = apol_policy_path_create_from_file(mod_base_path);
00270                 if (*mod_path == NULL) {
00271                         ERR(NULL, "%s", "invalid policy list");
00272                         goto err;
00273                 }
00274         } else {
00275                 *mod_path = apol_policy_path_create(mod_path_type, mod_base_path, mod_module_paths);
00276                 if (*mod_path == NULL) {
00277                         ERR(NULL, "%s", strerror(errno));
00278                         goto err;
00279                 }
00280         }
00281         apol_vector_destroy(&mod_module_paths);
00282         return;
00283       err:
00284         apol_policy_path_destroy(orig_path);
00285         apol_policy_path_destroy(mod_path);
00286         apol_vector_destroy(&orig_module_paths);
00287         apol_vector_destroy(&mod_module_paths);
00288 }
00289 
00290 int main(int argc, char **argv)
00291 {
00292         sediffx_t *app;
00293         apol_policy_path_t *orig_path, *mod_path;
00294         int run_diff;
00295 
00296         if (!g_thread_supported())
00297                 g_thread_init(NULL);
00298 
00299         gtk_init(&argc, &argv);
00300         sediffx_parse_command_line(argc, argv, &orig_path, &mod_path, &run_diff);
00301         glade_init();
00302         if (!g_thread_supported())
00303                 g_thread_init(NULL);
00304         if ((app = calloc(1, sizeof(*app))) == NULL || (app->top = toplevel_create(app)) == NULL) {
00305                 ERR(NULL, "%s", strerror(errno));
00306                 sediffx_destroy(&app);
00307                 exit(EXIT_FAILURE);
00308         }
00309         if (orig_path != NULL && mod_path != NULL) {
00310                 struct delayed_main_data dmd = { orig_path, mod_path, run_diff, app->top };
00311                 g_idle_add(&delayed_main, &dmd);
00312         }
00313         gtk_main();
00314 
00315         sediffx_destroy(&app);
00316         exit(EXIT_SUCCESS);
00317 }