/* Authors: Frank Mayer and Karl MacMillan * * Copyright (C) 2003,2004,2005 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, version 2. */ /* * dismod.c * * Test program to the contents of a binary policy in text * form. * * dismod binary_mod_file */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if __BYTE_ORDER == __LITTLE_ENDIAN #define le32_to_cpu(x) (x) #else #define le32_to_cpu(x) bswap_32(x) #endif #define DISPLAY_AVBLOCK_COND_AVTAB 0 #define DISPLAY_AVBLOCK_UNCOND_AVTAB 1 #define DISPLAY_AVBLOCK_ROLE_TYPE_NODE 2 /* unused? */ #define DISPLAY_AVBLOCK_ROLE_TRANS 3 #define DISPLAY_AVBLOCK_ROLE_ALLOW 4 #define DISPLAY_AVBLOCK_REQUIRES 5 #define DISPLAY_AVBLOCK_DECLARES 6 #define DISPLAY_AVBLOCK_FILENAME_TRANS 7 static policydb_t policydb; extern unsigned int ss_initialized; int policyvers = MOD_POLICYDB_VERSION_BASE; static const char *symbol_labels[9] = { "commons", "classes", "roles ", "types ", "users ", "bools ", "levels ", "cats ", "attribs" }; void usage(const char *progname) { printf("usage: %s binary_pol_file\n\n", progname); exit(1); } static void render_access_mask(uint32_t mask, uint32_t class, policydb_t * p, FILE * fp) { char *perm; fprintf(fp, "{"); perm = sepol_av_to_string(p, class, mask); if (perm) fprintf(fp, "%s ", perm); fprintf(fp, "}"); } static void render_access_bitmap(ebitmap_t * map, uint32_t class, policydb_t * p, FILE * fp) { unsigned int i; char *perm; fprintf(fp, "{"); for (i = ebitmap_startbit(map); i < ebitmap_length(map); i++) { if (ebitmap_get_bit(map, i)) { perm = sepol_av_to_string(p, class, 1 << i); if (perm) fprintf(fp, " %s", perm); } } fprintf(fp, " }"); } static void display_id(policydb_t * p, FILE * fp, uint32_t symbol_type, uint32_t symbol_value, const char *prefix) { char *id = p->sym_val_to_name[symbol_type][symbol_value]; scope_datum_t *scope = (scope_datum_t *) hashtab_search(p->scope[symbol_type].table, id); assert(scope != NULL); if (scope->scope == SCOPE_REQ) { fprintf(fp, " [%s%s]", prefix, id); } else { fprintf(fp, " %s%s", prefix, id); } } int display_type_set(type_set_t * set, uint32_t flags, policydb_t * policy, FILE * fp) { unsigned int i, num_types; if (set->flags & TYPE_STAR) { fprintf(fp, " * "); return 0; } else if (set->flags & TYPE_COMP) { fprintf(fp, " ~"); } num_types = 0; if (flags & RULE_SELF) { num_types++; } for (i = ebitmap_startbit(&set->types); i < ebitmap_length(&set->types); i++) { if (!ebitmap_get_bit(&set->types, i)) continue; num_types++; if (num_types > 1) break; } if (num_types <= 1) { for (i = ebitmap_startbit(&set->negset); i < ebitmap_length(&set->negset); i++) { if (!ebitmap_get_bit(&set->negset, i)) continue; num_types++; if (num_types > 1) break; } } if (num_types > 1) fprintf(fp, "{"); for (i = ebitmap_startbit(&set->types); i < ebitmap_length(&set->types); i++) { if (!ebitmap_get_bit(&set->types, i)) continue; display_id(policy, fp, SYM_TYPES, i, ""); } for (i = ebitmap_startbit(&set->negset); i < ebitmap_length(&set->negset); i++) { if (!ebitmap_get_bit(&set->negset, i)) continue; display_id(policy, fp, SYM_TYPES, i, "-"); } if (flags & RULE_SELF) { fprintf(fp, " self"); } if (num_types > 1) fprintf(fp, " }"); return 0; } int display_mod_role_set(role_set_t * roles, policydb_t * p, FILE * fp) { unsigned int i, num = 0; if (roles->flags & ROLE_STAR) { fprintf(fp, " * "); return 0; } else if (roles->flags & ROLE_COMP) { fprintf(fp, " ~"); } for (i = ebitmap_startbit(&roles->roles); i < ebitmap_length(&roles->roles); i++) { if (!ebitmap_get_bit(&roles->roles, i)) continue; num++; if (num > 1) { fprintf(fp, "{"); break; } } for (i = ebitmap_startbit(&roles->roles); i < ebitmap_length(&roles->roles); i++) { if (ebitmap_get_bit(&roles->roles, i)) display_id(p, fp, SYM_ROLES, i, ""); } if (num > 1) fprintf(fp, " }"); return 0; } int display_avrule(avrule_t * avrule, policydb_t * policy, FILE * fp) { class_perm_node_t *cur; int num_classes; if (avrule == NULL) { fprintf(fp, " \n"); return 0; } if (avrule->specified & AVRULE_AV) { if (avrule->specified & AVRULE_ALLOWED) { fprintf(fp, " allow"); } if (avrule->specified & AVRULE_AUDITALLOW) { fprintf(fp, " auditallow "); } if (avrule->specified & AVRULE_DONTAUDIT) { fprintf(fp, " dontaudit"); } } else if (avrule->specified & AVRULE_TYPE) { if (avrule->specified & AVRULE_TRANSITION) { fprintf(fp, " type_transition"); } if (avrule->specified & AVRULE_MEMBER) { fprintf(fp, " type_member"); } if (avrule->specified & AVRULE_CHANGE) { fprintf(fp, " type_change"); } } else if (avrule->specified & AVRULE_NEVERALLOW) { fprintf(fp, " neverallow"); } else { fprintf(fp, " ERROR: no valid rule type specified\n"); return -1; } if (display_type_set(&avrule->stypes, 0, policy, fp)) return -1; if (display_type_set(&avrule->ttypes, avrule->flags, policy, fp)) return -1; fprintf(fp, " :"); cur = avrule->perms; num_classes = 0; while (cur) { num_classes++; if (num_classes > 1) break; cur = cur->next; } if (num_classes > 1) fprintf(fp, " {"); cur = avrule->perms; while (cur) { display_id(policy, fp, SYM_CLASSES, cur->class - 1, ""); cur = cur->next; } if (num_classes > 1) fprintf(fp, " }"); fprintf(fp, " "); if (avrule->specified & (AVRULE_AV | AVRULE_NEVERALLOW)) { render_access_mask(avrule->perms->data, avrule->perms->class, policy, fp); } else if (avrule->specified & AVRULE_TYPE) { display_id(policy, fp, SYM_TYPES, avrule->perms->data - 1, ""); } fprintf(fp, ";\n"); return 0; } int display_type_callback(hashtab_key_t key, hashtab_datum_t datum, void *data) { type_datum_t *type; FILE *fp; unsigned int i, first_attrib = 1; type = (type_datum_t *) datum; fp = (FILE *) data; if (type->primary) { display_id(&policydb, fp, SYM_TYPES, type->s.value - 1, ""); fprintf(fp, " [%d]: ", type->s.value); } else { /* as that aliases have no value of their own and that * they can never be required by a module, use this * alternative way of displaying a name */ fprintf(fp, " %s [%d]: ", (char *)key, type->s.value); } if (type->flavor == TYPE_ATTRIB) { fprintf(fp, "attribute for types"); for (i = ebitmap_startbit(&type->types); i < ebitmap_length(&type->types); i++) { if (!ebitmap_get_bit(&type->types, i)) continue; if (first_attrib) { first_attrib = 0; } else { fprintf(fp, ","); } display_id(&policydb, fp, SYM_TYPES, i, ""); } } else if (type->primary) { fprintf(fp, "type"); } else { fprintf(fp, "alias for type"); display_id(&policydb, fp, SYM_TYPES, type->s.value - 1, ""); } fprintf(fp, " flags:%x\n", type->flags); return 0; } int display_types(policydb_t * p, FILE * fp) { if (hashtab_map(p->p_types.table, display_type_callback, fp)) return -1; return 0; } int display_users(policydb_t * p, FILE * fp) { unsigned int i, j; ebitmap_t *bitmap; for (i = 0; i < p->p_users.nprim; i++) { display_id(p, fp, SYM_USERS, i, ""); fprintf(fp, ":"); bitmap = &(p->user_val_to_struct[i]->roles.roles); for (j = ebitmap_startbit(bitmap); j < ebitmap_length(bitmap); j++) { if (ebitmap_get_bit(bitmap, j)) { display_id(p, fp, SYM_ROLES, j, ""); } } fprintf(fp, "\n"); } return 0; } int display_bools(policydb_t * p, FILE * fp) { unsigned int i; for (i = 0; i < p->p_bools.nprim; i++) { display_id(p, fp, SYM_BOOLS, i, ""); fprintf(fp, " : %d\n", p->bool_val_to_struct[i]->state); } return 0; } void display_expr(policydb_t * p, cond_expr_t * exp, FILE * fp) { cond_expr_t *cur; for (cur = exp; cur != NULL; cur = cur->next) { switch (cur->expr_type) { case COND_BOOL: fprintf(fp, "%s ", p->p_bool_val_to_name[cur->bool - 1]); break; case COND_NOT: fprintf(fp, "! "); break; case COND_OR: fprintf(fp, "|| "); break; case COND_AND: fprintf(fp, "&& "); break; case COND_XOR: fprintf(fp, "^ "); break; case COND_EQ: fprintf(fp, "== "); break; case COND_NEQ: fprintf(fp, "!= "); break; default: fprintf(fp, "error!"); break; } } } void display_policycon(FILE * fp) { /* There was an attempt to implement this at one time. Look through * git history to find it. */ fprintf(fp, "Sorry, not implemented\n"); } void display_initial_sids(policydb_t * p, FILE * fp) { ocontext_t *cur; char *user, *role, *type; fprintf(fp, "Initial SIDs:\n"); for (cur = p->ocontexts[OCON_ISID]; cur != NULL; cur = cur->next) { user = p->p_user_val_to_name[cur->context[0].user - 1]; role = p->p_role_val_to_name[cur->context[0].role - 1]; type = p->p_type_val_to_name[cur->context[0].type - 1]; fprintf(fp, "\t%s: sid %d, context %s:%s:%s\n", cur->u.name, cur->sid[0], user, role, type); } #if 0 fprintf(fp, "Policy Initial SIDs:\n"); for (cur = p->ocontexts[OCON_POLICYISID]; cur != NULL; cur = cur->next) { user = p->p_user_val_to_name[cur->context[0].user - 1]; role = p->p_role_val_to_name[cur->context[0].role - 1]; type = p->p_type_val_to_name[cur->context[0].type - 1]; fprintf(fp, "\t%s: sid %d, context %s:%s:%s\n", cur->u.name, cur->sid[0], user, role, type); } #endif } void display_class_set(ebitmap_t *classes, policydb_t *p, FILE *fp) { unsigned int i, num = 0; for (i = ebitmap_startbit(classes); i < ebitmap_length(classes); i++) { if (!ebitmap_get_bit(classes, i)) continue; num++; if (num > 1) { fprintf(fp, "{"); break; } } for (i = ebitmap_startbit(classes); i < ebitmap_length(classes); i++) { if (ebitmap_get_bit(classes, i)) display_id(p, fp, SYM_CLASSES, i, ""); } if (num > 1) fprintf(fp, " }"); } void display_role_trans(role_trans_rule_t * tr, policydb_t * p, FILE * fp) { for (; tr; tr = tr->next) { fprintf(fp, "role transition "); display_mod_role_set(&tr->roles, p, fp); display_type_set(&tr->types, 0, p, fp); fprintf(fp, " :"); display_class_set(&tr->classes, p, fp); display_id(p, fp, SYM_ROLES, tr->new_role - 1, ""); fprintf(fp, "\n"); } } void display_role_allow(role_allow_rule_t * ra, policydb_t * p, FILE * fp) { for (; ra; ra = ra->next) { fprintf(fp, "role allow "); display_mod_role_set(&ra->roles, p, fp); display_mod_role_set(&ra->new_roles, p, fp); fprintf(fp, "\n"); } } static void display_filename_trans(filename_trans_rule_t * tr, policydb_t * p, FILE * fp) { fprintf(fp, "filename transition"); for (; tr; tr = tr->next) { display_type_set(&tr->stypes, 0, p, fp); display_type_set(&tr->ttypes, 0, p, fp); display_id(p, fp, SYM_CLASSES, tr->tclass - 1, ":"); display_id(p, fp, SYM_TYPES, tr->otype - 1, ""); fprintf(fp, " %s\n", tr->name); } } int role_display_callback(hashtab_key_t key __attribute__((unused)), hashtab_datum_t datum, void *data) { role_datum_t *role; FILE *fp; role = (role_datum_t *) datum; fp = (FILE *) data; fprintf(fp, "role:"); display_id(&policydb, fp, SYM_ROLES, role->s.value - 1, ""); fprintf(fp, " types: "); display_type_set(&role->types, 0, &policydb, fp); fprintf(fp, "\n"); return 0; } static int display_scope_index(scope_index_t * indices, policydb_t * p, FILE * out_fp) { unsigned int i; for (i = 0; i < SYM_NUM; i++) { unsigned int any_found = 0, j; fprintf(out_fp, "%s:", symbol_labels[i]); for (j = ebitmap_startbit(&indices->scope[i]); j < ebitmap_length(&indices->scope[i]); j++) { if (ebitmap_get_bit(&indices->scope[i], j)) { any_found = 1; fprintf(out_fp, " %s", p->sym_val_to_name[i][j]); if (i == SYM_CLASSES) { if (j < indices->class_perms_len) { render_access_bitmap(indices-> class_perms_map + j, j + 1, p, out_fp); } else { fprintf(out_fp, ""); } } } } if (!any_found) { fprintf(out_fp, " "); } fprintf(out_fp, "\n"); } return 0; } #if 0 int display_cond_expressions(policydb_t * p, FILE * fp) { cond_node_t *cur; cond_av_list_t *av_cur; for (cur = p->cond_list; cur != NULL; cur = cur->next) { fprintf(fp, "expression: "); display_expr(p, cur->expr, fp); fprintf(fp, "current state: %d\n", cur->cur_state); fprintf(fp, "True list:\n"); for (av_cur = cur->true_list; av_cur != NULL; av_cur = av_cur->next) { fprintf(fp, "\t"); render_av_rule(&av_cur->node->key, &av_cur->node->datum, RENDER_CONDITIONAL, p, fp); } fprintf(fp, "False list:\n"); for (av_cur = cur->false_list; av_cur != NULL; av_cur = av_cur->next) { fprintf(fp, "\t"); render_av_rule(&av_cur->node->key, &av_cur->node->datum, RENDER_CONDITIONAL, p, fp); } } return 0; } int change_bool(char *name, int state, policydb_t * p, FILE * fp) { cond_bool_datum_t *bool; bool = hashtab_search(p->p_bools.table, name); if (bool == NULL) { fprintf(fp, "Could not find bool %s\n", name); return -1; } bool->state = state; evaluate_conds(p); return 0; } #endif int display_avdecl(avrule_decl_t * decl, int field, policydb_t * policy, FILE * out_fp) { fprintf(out_fp, "decl %u:%s\n", decl->decl_id, (decl->enabled ? " [enabled]" : "")); switch (field) { case DISPLAY_AVBLOCK_COND_AVTAB:{ cond_list_t *cond = decl->cond_list; avrule_t *avrule; while (cond) { fprintf(out_fp, "expression: "); display_expr(&policydb, cond->expr, out_fp); fprintf(out_fp, "current state: %d\n", cond->cur_state); fprintf(out_fp, "True list:\n"); avrule = cond->avtrue_list; while (avrule) { display_avrule(avrule, &policydb, out_fp); avrule = avrule->next; } fprintf(out_fp, "False list:\n"); avrule = cond->avfalse_list; while (avrule) { display_avrule(avrule, &policydb, out_fp); avrule = avrule->next; } cond = cond->next; } break; } case DISPLAY_AVBLOCK_UNCOND_AVTAB:{ avrule_t *avrule = decl->avrules; if (avrule == NULL) { fprintf(out_fp, " \n"); } while (avrule != NULL) { if (display_avrule(avrule, policy, out_fp)) return -1; avrule = avrule->next; } break; } case DISPLAY_AVBLOCK_ROLE_TYPE_NODE:{ /* role_type_node */ break; } case DISPLAY_AVBLOCK_ROLE_TRANS:{ display_role_trans(decl->role_tr_rules, policy, out_fp); break; } case DISPLAY_AVBLOCK_ROLE_ALLOW:{ display_role_allow(decl->role_allow_rules, policy, out_fp); break; } case DISPLAY_AVBLOCK_REQUIRES:{ if (display_scope_index (&decl->required, policy, out_fp)) { return -1; } break; } case DISPLAY_AVBLOCK_DECLARES:{ if (display_scope_index (&decl->declared, policy, out_fp)) { return -1; } break; } case DISPLAY_AVBLOCK_FILENAME_TRANS: display_filename_trans(decl->filename_trans_rules, policy, out_fp); break; default:{ assert(0); } } return 0; /* should never get here */ } int display_avblock(int field, policydb_t * policy, FILE * out_fp) { avrule_block_t *block = policydb.global; while (block != NULL) { fprintf(out_fp, "--- begin avrule block ---\n"); avrule_decl_t *decl = block->branch_list; while (decl != NULL) { if (display_avdecl(decl, field, policy, out_fp)) { return -1; } decl = decl->next; } block = block->next; } return 0; } int display_handle_unknown(policydb_t * p, FILE * out_fp) { if (p->handle_unknown == ALLOW_UNKNOWN) fprintf(out_fp, "Allow unknown classes and perms\n"); else if (p->handle_unknown == DENY_UNKNOWN) fprintf(out_fp, "Deny unknown classes and perms\n"); else if (p->handle_unknown == REJECT_UNKNOWN) fprintf(out_fp, "Reject unknown classes and perms\n"); return 0; } static int read_policy(char *filename, policydb_t * policy) { FILE *in_fp; struct policy_file f; int retval; uint32_t buf[1]; if ((in_fp = fopen(filename, "rb")) == NULL) { fprintf(stderr, "Can't open '%s': %s\n", filename, strerror(errno)); exit(1); } policy_file_init(&f); f.type = PF_USE_STDIO; f.fp = in_fp; /* peek at the first byte. if they are indicative of a package use the package reader, otherwise use the normal policy reader */ if (fread(buf, sizeof(uint32_t), 1, in_fp) != 1) { fprintf(stderr, "Could not read from policy.\n"); exit(1); } rewind(in_fp); if (le32_to_cpu(buf[0]) == SEPOL_MODULE_PACKAGE_MAGIC) { sepol_module_package_t *package; if (sepol_module_package_create(&package)) { fprintf(stderr, "%s: Out of memory!\n", __FUNCTION__); exit(1); } package->policy = (sepol_policydb_t *) policy; package->file_contexts = NULL; retval = sepol_module_package_read(package, (sepol_policy_file_t *) & f, 1); free(package->file_contexts); } else { if (policydb_init(policy)) { fprintf(stderr, "%s: Out of memory!\n", __FUNCTION__); exit(1); } retval = policydb_read(policy, &f, 1); } fclose(in_fp); return retval; } static void link_module(policydb_t * base, FILE * out_fp) { char module_name[80] = { 0 }; int ret; policydb_t module, *mods = &module; if (base->policy_type != POLICY_BASE) { printf("Can only link if initial file was a base policy.\n"); return; } printf("\nModule filename: "); fgets(module_name, sizeof(module_name), stdin); module_name[strlen(module_name) - 1] = '\0'; /* remove LF */ if (module_name[0] == '\0') { return; } /* read the binary policy */ fprintf(out_fp, "Reading module...\n"); if (read_policy(module_name, mods)) { fprintf(stderr, "%s: error(s) encountered while loading policy\n", module_name); exit(1); } if (module.policy_type != POLICY_MOD) { fprintf(stderr, "This file is not a loadable policy module.\n"); exit(1); } if (policydb_index_classes(&module) || policydb_index_others(NULL, &module, 0)) { fprintf(stderr, "Could not index module.\n"); exit(1); } ret = link_modules(NULL, base, &mods, 1, 0); if (ret != 0) { printf("Link failed (error %d)\n", ret); printf("(You will probably need to restart dismod.)\n"); } policydb_destroy(&module); return; } static void display_policycaps(policydb_t * p, FILE * fp) { ebitmap_node_t *node; const char *capname; char buf[64]; unsigned int i; fprintf(fp, "policy capabilities:\n"); ebitmap_for_each_bit(&p->policycaps, node, i) { if (ebitmap_node_get_bit(node, i)) { capname = sepol_polcap_getname(i); if (capname == NULL) { snprintf(buf, sizeof(buf), "unknown (%d)", i); capname = buf; } fprintf(fp, "\t%s\n", capname); } } } int menu(void) { printf("\nSelect a command:\n"); printf("1) display unconditional AVTAB\n"); printf("2) display conditional AVTAB\n"); printf("3) display users\n"); printf("4) display bools\n"); printf("5) display roles\n"); printf("6) display types, attributes, and aliases\n"); printf("7) display role transitions\n"); printf("8) display role allows\n"); printf("9) Display policycon\n"); printf("0) Display initial SIDs\n"); printf("\n"); printf("a) Display avrule requirements\n"); printf("b) Display avrule declarations\n"); printf("c) Display policy capabilities\n"); printf("l) Link in a module\n"); printf("u) Display the unknown handling setting\n"); printf("F) Display filename_trans rules\n"); printf("\n"); printf("f) set output file\n"); printf("m) display menu\n"); printf("q) quit\n"); return 0; } int main(int argc, char **argv) { FILE *out_fp = stdout; char ans[81], OutfileName[121]; if (argc != 2) usage(argv[0]); /* read the binary policy */ fprintf(out_fp, "Reading policy...\n"); if (policydb_init(&policydb)) { fprintf(stderr, "%s: Out of memory!\n", __FUNCTION__); exit(1); } if (read_policy(argv[1], &policydb)) { fprintf(stderr, "%s: error(s) encountered while loading policy\n", argv[0]); exit(1); } if (policydb.policy_type != POLICY_BASE && policydb.policy_type != POLICY_MOD) { fprintf(stderr, "This file is neither a base nor loadable policy module.\n"); exit(1); } if (policydb_index_classes(&policydb)) { fprintf(stderr, "Error indexing classes\n"); exit(1); } if (policydb_index_others(NULL, &policydb, 1)) { fprintf(stderr, "Error indexing others\n"); exit(1); } if (policydb.policy_type == POLICY_BASE) { printf("Binary base policy file loaded.\n\n"); } else { printf("Binary policy module file loaded.\n"); printf("Module name: %s\n", policydb.name); printf("Module version: %s\n", policydb.version); printf("\n"); } menu(); for (;;) { printf("\nCommand (\'m\' for menu): "); fgets(ans, sizeof(ans), stdin); switch (ans[0]) { case '1': fprintf(out_fp, "unconditional avtab:\n"); display_avblock(DISPLAY_AVBLOCK_UNCOND_AVTAB, &policydb, out_fp); break; case '2': fprintf(out_fp, "conditional avtab:\n"); display_avblock(DISPLAY_AVBLOCK_COND_AVTAB, &policydb, out_fp); break; case '3': display_users(&policydb, out_fp); break; case '4': display_bools(&policydb, out_fp); break; case '5': if (hashtab_map (policydb.p_roles.table, role_display_callback, out_fp)) exit(1); break; case '6': if (display_types(&policydb, out_fp)) { fprintf(stderr, "Error displaying types\n"); exit(1); } break; case '7': fprintf(out_fp, "role transitions:\n"); display_avblock(DISPLAY_AVBLOCK_ROLE_TRANS, &policydb, out_fp); break; case '8': fprintf(out_fp, "role allows:\n"); display_avblock(DISPLAY_AVBLOCK_ROLE_ALLOW, &policydb, out_fp); break; case '9': display_policycon(out_fp); break; case '0': display_initial_sids(&policydb, out_fp); break; case 'a': fprintf(out_fp, "avrule block requirements:\n"); display_avblock(DISPLAY_AVBLOCK_REQUIRES, &policydb, out_fp); break; case 'b': fprintf(out_fp, "avrule block declarations:\n"); display_avblock(DISPLAY_AVBLOCK_DECLARES, &policydb, out_fp); break; case 'c': display_policycaps(&policydb, out_fp); break; case 'u': case 'U': display_handle_unknown(&policydb, out_fp); break; case 'f': printf ("\nFilename for output ( for screen output): "); fgets(OutfileName, sizeof(OutfileName), stdin); OutfileName[strlen(OutfileName) - 1] = '\0'; /* fix_string (remove LF) */ if (strlen(OutfileName) == 0) out_fp = stdout; else if ((out_fp = fopen(OutfileName, "w")) == NULL) { fprintf(stderr, "Cannot open output file %s\n", OutfileName); out_fp = stdout; } if (out_fp != stdout) printf("\nOutput to file: %s\n", OutfileName); break; case 'F': fprintf(out_fp, "filename_trans rules:\n"); display_avblock(DISPLAY_AVBLOCK_FILENAME_TRANS, &policydb, out_fp); break; case 'l': link_module(&policydb, out_fp); break; case 'q': policydb_destroy(&policydb); exit(0); break; case 'm': menu(); break; default: printf("\nInvalid choice\n"); menu(); break; } } exit(EXIT_SUCCESS); }