00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include "seaudit_internal.h"
00026
00027 #include <seaudit/report.h>
00028
00029 #include <apol/util.h>
00030 #include <libxml/xmlreader.h>
00031
00032 #include <assert.h>
00033 #include <errno.h>
00034 #include <stdio.h>
00035 #include <stdlib.h>
00036 #include <string.h>
00037 #include <unistd.h>
00038
00039 #define CONFIG_FILE "seaudit-report.conf"
00040 #define STYLESHEET_FILE "seaudit-report.css"
00041 #define LINE_MAX 1024
00042
00043 struct seaudit_report
00044 {
00045
00046 seaudit_report_format_e format;
00047
00048 char *config;
00049
00050 char *stylesheet;
00051
00052 int use_stylesheet;
00053
00054 int malformed;
00055
00056 seaudit_model_t *model;
00057 };
00058
00059 static const char *seaudit_report_node_names[] = {
00060 "seaudit-report",
00061 "standard-section",
00062 "custom-section",
00063 "view",
00064 NULL
00065 };
00066
00067 static const char *seaudit_standard_section_names[] = {
00068 "PolicyLoads",
00069 "EnforcementToggles",
00070 "PolicyBooleans",
00071 "Statistics",
00072 "AllowListing",
00073 "DenyListing",
00074 NULL
00075 };
00076
00077 seaudit_report_t *seaudit_report_create(seaudit_model_t * model)
00078 {
00079 seaudit_report_t *r = calloc(1, sizeof(*r));
00080 if (r == NULL) {
00081 return NULL;
00082 }
00083 r->model = model;
00084 return r;
00085 }
00086
00087 void seaudit_report_destroy(seaudit_report_t ** report)
00088 {
00089 if (report == NULL || *report == NULL) {
00090 return;
00091 }
00092 free((*report)->config);
00093 free((*report)->stylesheet);
00094 free(*report);
00095 *report = NULL;
00096 }
00097
00098 int seaudit_report_set_format(const seaudit_log_t * log, seaudit_report_t * report, seaudit_report_format_e format)
00099 {
00100 if (report == NULL) {
00101 ERR(log, "%s", strerror(EINVAL));
00102 errno = EINVAL;
00103 return -1;
00104 }
00105 report->format = format;
00106 return 0;
00107 }
00108
00109
00110
00111
00112 static int report_set_default_configuration(const seaudit_log_t * log, seaudit_report_t * report)
00113 {
00114 char *config_dir = apol_file_find(CONFIG_FILE);
00115 int error;
00116
00117 if (config_dir == NULL) {
00118 error = errno;
00119 ERR(log, "%s", "Could not find default configuration file.");
00120 errno = error;
00121 return -1;
00122 }
00123 if (asprintf(&report->config, "%s/%s", config_dir, CONFIG_FILE) < 0) {
00124 error = errno;
00125 report->config = NULL;
00126 free(config_dir);
00127 ERR(log, "%s", strerror(error));
00128 errno = error;
00129 return -1;
00130 }
00131 free(config_dir);
00132
00133
00134 if (access(report->config, R_OK) != 0) {
00135 error = errno;
00136 ERR(log, "Could not read default config file %s.", report->config);
00137 errno = error;
00138 return -1;
00139 }
00140 return 0;
00141 }
00142
00143 int seaudit_report_set_configuration(const seaudit_log_t * log, seaudit_report_t * report, const char *file)
00144 {
00145 if (report == NULL) {
00146 ERR(log, "%s", strerror(EINVAL));
00147 errno = EINVAL;
00148 return -1;
00149 }
00150 free(report->config);
00151 report->config = NULL;
00152 if (file == NULL) {
00153 return report_set_default_configuration(log, report);
00154 } else {
00155 if ((report->config = strdup(file)) == NULL) {
00156 int error = errno;
00157 ERR(log, "%s", strerror(error));
00158 errno = error;
00159 return -1;
00160 }
00161 return 0;
00162 }
00163 }
00164
00165
00166
00167
00168 static int report_set_default_stylesheet(const seaudit_log_t * log, seaudit_report_t * report)
00169 {
00170 char *dir = apol_file_find(STYLESHEET_FILE);
00171 int error;
00172 if (dir == NULL) {
00173 error = errno;
00174 ERR(log, "%s", "Could not find default stylesheet.");
00175 errno = error;
00176 return -1;
00177 }
00178
00179 if (asprintf(&report->stylesheet, "%s/%s", dir, STYLESHEET_FILE) < 0) {
00180 error = errno;
00181 report->stylesheet = NULL;
00182 free(dir);
00183 ERR(log, "%s", strerror(error));
00184 errno = error;
00185 return -1;
00186 }
00187 free(dir);
00188
00189 return 0;
00190 }
00191
00192 int seaudit_report_set_stylesheet(const seaudit_log_t * log, seaudit_report_t * report, const char *file, const int use_stylesheet)
00193 {
00194 if (report == NULL) {
00195 ERR(log, "%s", strerror(EINVAL));
00196 errno = EINVAL;
00197 return -1;
00198 }
00199 free(report->stylesheet);
00200 report->stylesheet = NULL;
00201 report->use_stylesheet = use_stylesheet;
00202 if (file == NULL) {
00203 return report_set_default_stylesheet(log, report);
00204 } else {
00205 if ((report->stylesheet = strdup(file)) == NULL) {
00206 return -1;
00207 int error = errno;
00208 ERR(log, "%s", strerror(error));
00209 errno = error;
00210 return -1;
00211 }
00212 return 0;
00213 }
00214 }
00215
00216 int seaudit_report_set_malformed(const seaudit_log_t * log, seaudit_report_t * report, const int do_malformed)
00217 {
00218 if (report == NULL) {
00219 ERR(log, "%s", strerror(EINVAL));
00220 errno = EINVAL;
00221 return -1;
00222 }
00223 report->malformed = do_malformed;
00224 return 0;
00225 }
00226
00227
00228
00229
00230
00231
00232 static int report_import_html_stylesheet(const seaudit_log_t * log, const seaudit_report_t * report, FILE * outfile)
00233 {
00234 char line[LINE_MAX], *line_ptr = NULL;
00235 FILE *fp;
00236
00237 if (report->use_stylesheet) {
00238 fp = fopen(report->stylesheet, "r");
00239 if (fp == NULL) {
00240 WARN(log, "Cannot open stylesheet file %s.", report->stylesheet);
00241 return 1;
00242 }
00243 fprintf(outfile, "<style type=\"text/css\">\n");
00244
00245 while (fgets(line, LINE_MAX, fp) != NULL) {
00246 free(line_ptr);
00247 line_ptr = NULL;
00248 if ((line_ptr = strdup(line)) == NULL) {
00249 int error = errno;
00250 free(line_ptr);
00251 fclose(fp);
00252 ERR(log, "%s", strerror(error));
00253 errno = error;
00254 return -1;
00255 }
00256 apol_str_trim(line_ptr);
00257 if (line_ptr[0] == '#' || apol_str_is_only_white_space(line_ptr))
00258 continue;
00259 fprintf(outfile, "%s\n", line_ptr);
00260 }
00261 fprintf(outfile, "</style>\n");
00262 fclose(fp);
00263 free(line_ptr);
00264 }
00265 return 0;
00266 }
00267
00268 static int report_print_header(const seaudit_log_t * log, const seaudit_report_t * report, FILE * outfile)
00269 {
00270 time_t ltime;
00271
00272 time(<ime);
00273 if (report->format == SEAUDIT_REPORT_FORMAT_HTML) {
00274 fprintf(outfile, "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 3.2 Final//EN\">\n");
00275 fprintf(outfile, "<html>\n<head>\n");
00276 if (report_import_html_stylesheet(log, report, outfile) < 0) {
00277 return -1;
00278 }
00279 fprintf(outfile, "<title>seaudit-report</title>\n</head>\n");
00280 fprintf(outfile, "<body>\n");
00281 fprintf(outfile, "<b class=\"report_date\"># Report generated by seaudit-report on %s</b><br>\n", ctime(<ime));
00282 } else {
00283 fprintf(outfile, "# Begin\n\n");
00284 fprintf(outfile, "# Report generated by seaudit-report on %s\n", ctime(<ime));
00285 }
00286 return 0;
00287 }
00288
00289 static int report_print_footer(const seaudit_report_t * report, FILE * outfile)
00290 {
00291 if (report->format == SEAUDIT_REPORT_FORMAT_HTML) {
00292 fprintf(outfile, "</body>\n</html>\n");
00293 } else {
00294 fprintf(outfile, "# End\n");
00295 }
00296 return 0;
00297 }
00298
00299 static int report_is_valid_node_name(const char *name)
00300 {
00301 size_t i;
00302 for (i = 0; seaudit_report_node_names[i] != NULL; i++)
00303 if (strcmp(seaudit_report_node_names[i], name) == 0)
00304 return 1;
00305 return 0;
00306 }
00307
00308 static int report_is_valid_section_name(const char *name)
00309 {
00310 size_t i;
00311 for (i = 0; seaudit_standard_section_names[i] != NULL; i++)
00312 if (strcmp(seaudit_standard_section_names[i], name) == 0)
00313 return 1;
00314 return 0;
00315 }
00316
00317 static int report_parse_seaudit_report(const seaudit_log_t * log, const seaudit_report_t * report __attribute__ ((unused)),
00318 xmlTextReaderPtr reader, xmlChar ** id_value
00319 __attribute__ ((unused)), xmlChar ** title_value)
00320 {
00321 int rt, error;
00322 xmlChar *name = NULL;
00323
00324 if (xmlTextReaderNodeType(reader) == 1 && xmlTextReaderAttributeCount(reader) > 0) {
00325
00326 rt = xmlTextReaderMoveToNextAttribute(reader);
00327 while (rt > 0) {
00328 name = xmlTextReaderName(reader);
00329 if (name == NULL) {
00330 error = errno;
00331 ERR(log, "%s", "Attribute name unavailable.");
00332 errno = error;
00333 return -1;
00334 }
00335 if (strcmp((char *)name, "title") == 0) {
00336 *title_value = xmlTextReaderValue(reader);
00337 }
00338
00339 xmlFree(name);
00340 rt = xmlTextReaderMoveToNextAttribute(reader);
00341 }
00342 if (rt < 0) {
00343 error = errno;
00344 ERR(log, "%s", "Error parsing attribute for seaudit-report node.");
00345 errno = error;
00346 return -1;
00347 }
00348 }
00349 return 0;
00350 }
00351
00352 static int report_parse_standard_attribs(const seaudit_log_t * log, const seaudit_report_t * report __attribute__ ((unused)),
00353 xmlTextReaderPtr reader, xmlChar ** id_value, xmlChar ** title_value)
00354 {
00355 int rt, error;
00356 xmlChar *name = NULL;
00357
00358 if (xmlTextReaderNodeType(reader) == 1 && xmlTextReaderAttributeCount(reader) > 0) {
00359
00360 rt = xmlTextReaderMoveToNextAttribute(reader);
00361 while (rt > 0) {
00362 name = xmlTextReaderName(reader);
00363 if (name == NULL) {
00364 error = errno;
00365 ERR(log, "%s", "Attribute name unavailable.");
00366 errno = error;
00367 return -1;
00368 }
00369 if (strcmp((char *)name, "id") == 0) {
00370 *id_value = xmlTextReaderValue(reader);
00371 } else if (strcmp((char *)name, "title") == 0) {
00372 *title_value = xmlTextReaderValue(reader);
00373 }
00374 xmlFree(name);
00375 rt = xmlTextReaderMoveToNextAttribute(reader);
00376 }
00377 if (rt < 0) {
00378 error = errno;
00379 ERR(log, "%s", "Error parsing attribute for standard-section node.");
00380 errno = error;
00381 return -1;
00382 }
00383 }
00384 return 0;
00385 }
00386
00387 static int report_parse_custom_attribs(const seaudit_log_t * log, const seaudit_report_t * report __attribute__ ((unused)),
00388 xmlTextReaderPtr reader, xmlChar ** title_value)
00389 {
00390 int rt, error;
00391 xmlChar *name = NULL;
00392
00393 if (xmlTextReaderNodeType(reader) == 1 && xmlTextReaderAttributeCount(reader) > 0) {
00394
00395 rt = xmlTextReaderMoveToNextAttribute(reader);
00396 while (rt > 0) {
00397 name = xmlTextReaderName(reader);
00398 if (name == NULL) {
00399 error = errno;
00400 ERR(log, "%s", "Attribute name unavailable.");
00401 errno = error;
00402 return -1;
00403 }
00404 if (strcmp((char *)name, "title") == 0) {
00405 *title_value = xmlTextReaderValue(reader);
00406 }
00407
00408 xmlFree(name);
00409 rt = xmlTextReaderMoveToNextAttribute(reader);
00410 }
00411 if (rt < 0) {
00412 error = errno;
00413 ERR(log, "%s", "Error parsing attribute for custom-section node.");
00414 errno = error;
00415 return -1;
00416 }
00417 }
00418 return 0;
00419 }
00420
00421
00422
00423
00424
00425 static seaudit_filter_t *report_enforce_toggle_filter_create(const seaudit_log_t * log, const seaudit_report_t * report
00426 __attribute__ ((unused)))
00427 {
00428 seaudit_filter_t *filter = NULL;
00429 apol_vector_t *type_v = NULL, *class_v;
00430 int retval = -1, error = 0;
00431 char *tgt_type = "security_t";
00432 char *obj_class = "security";
00433
00434 if ((filter = seaudit_filter_create(NULL)) == NULL) {
00435 error = errno;
00436 ERR(log, "%s", strerror(error));
00437 goto cleanup;
00438 }
00439 if ((type_v = apol_vector_create_with_capacity(1, NULL)) == NULL ||
00440 apol_vector_append(type_v, tgt_type) < 0 || seaudit_filter_set_target_type(filter, type_v) < 0) {
00441 error = errno;
00442 ERR(log, "%s", strerror(error));
00443 goto cleanup;
00444 }
00445 if ((class_v = apol_vector_create_with_capacity(1, NULL)) == NULL ||
00446 apol_vector_append(class_v, obj_class) < 0 || seaudit_filter_set_target_class(filter, class_v) < 0) {
00447 error = errno;
00448 ERR(log, "%s", strerror(error));
00449 goto cleanup;
00450 }
00451 retval = 0;
00452 cleanup:
00453 apol_vector_destroy(&type_v);
00454 apol_vector_destroy(&class_v);
00455 if (retval != 0) {
00456 seaudit_filter_destroy(&filter);
00457 errno = error;
00458 return NULL;
00459 }
00460 return filter;
00461 }
00462
00463 static int report_print_enforce_toggles(const seaudit_log_t * log, const seaudit_report_t * report, FILE * outfile)
00464 {
00465 seaudit_filter_t *filter = NULL;
00466 seaudit_model_t *dup_model = NULL;
00467 size_t i, j, num_setenforce = 0;
00468 apol_vector_t *v = NULL;
00469 seaudit_message_t *msg;
00470 seaudit_avc_message_t *avc;
00471 seaudit_message_type_e type;
00472 char *s;
00473 char *perm = "setenforce";
00474 int retval = -1, error = 0;
00475
00476 if ((filter = report_enforce_toggle_filter_create(log, report)) == NULL) {
00477 error = errno;
00478 goto cleanup;
00479 }
00480 if ((dup_model = seaudit_model_create_from_model(report->model)) == NULL ||
00481 seaudit_model_append_filter(dup_model, filter) < 0) {
00482 error = errno;
00483 ERR(log, "%s", strerror(error));
00484 goto cleanup;
00485 }
00486 filter = NULL;
00487
00488
00489 v = seaudit_model_get_messages(log, dup_model);
00490 for (i = 0; i < apol_vector_get_size(v); i++) {
00491 msg = apol_vector_get_element(v, i);
00492 avc = seaudit_message_get_data(msg, &type);
00493 if (type != SEAUDIT_MESSAGE_TYPE_AVC || avc->msg == SEAUDIT_AVC_DENIED)
00494 continue;
00495 if (apol_vector_get_index(avc->perms, perm, apol_str_strcmp, NULL, &j) == 0) {
00496
00497 num_setenforce++;
00498 }
00499 }
00500
00501
00502
00503 if (report->format == SEAUDIT_REPORT_FORMAT_HTML)
00504 fprintf(outfile,
00505 "<font class=\"message_count_label\">Number of messages:</font> <b class=\"message_count\">%zd</b><br>\n<br>\n",
00506 num_setenforce);
00507 else
00508 fprintf(outfile, "Number of messages: %zd\n\n", num_setenforce);
00509
00510 for (i = 0; i < apol_vector_get_size(v); i++) {
00511 msg = apol_vector_get_element(v, i);
00512 avc = seaudit_message_get_data(msg, &type);
00513 if (type != SEAUDIT_MESSAGE_TYPE_AVC ||
00514 avc->msg == SEAUDIT_AVC_DENIED || apol_vector_get_index(avc->perms, perm, apol_str_strcmp, NULL, &j) < 0) {
00515 continue;
00516 }
00517 if (report->format == SEAUDIT_REPORT_FORMAT_HTML) {
00518 s = seaudit_message_to_string_html(msg);
00519 } else {
00520 s = seaudit_message_to_string(msg);
00521 }
00522 if (s == NULL) {
00523 error = errno;
00524 ERR(log, "%s", strerror(error));
00525 goto cleanup;
00526 }
00527 fputs(s, outfile);
00528 fputc('\n', outfile);
00529 free(s);
00530 }
00531 retval = 0;
00532 cleanup:
00533 apol_vector_destroy(&v);
00534 seaudit_filter_destroy(&filter);
00535 seaudit_model_destroy(&dup_model);
00536 if (error != 0) {
00537 errno = error;
00538 }
00539 return retval;
00540 }
00541
00542 static int report_print_policy_booleans(const seaudit_log_t * log, const seaudit_report_t * report, FILE * outfile)
00543 {
00544 size_t i, num = seaudit_model_get_num_bools(log, report->model);
00545 apol_vector_t *v = seaudit_model_get_messages(log, report->model);
00546 seaudit_message_t *m;
00547 seaudit_message_type_e type;
00548 char *s;
00549 if (report->format == SEAUDIT_REPORT_FORMAT_HTML)
00550 fprintf(outfile,
00551 "<font class=\"message_count_label\">Number of messages:</font> <b class=\"message_count\">%zd</b><br>\n<br>\n",
00552 num);
00553 else
00554 fprintf(outfile, "Number of messages: %zd\n\n", num);
00555
00556 for (i = 0; i < apol_vector_get_size(v); i++) {
00557 m = apol_vector_get_element(v, i);
00558 seaudit_message_get_data(m, &type);
00559 if (type == SEAUDIT_MESSAGE_TYPE_BOOL) {
00560 if (report->format == SEAUDIT_REPORT_FORMAT_HTML) {
00561 s = seaudit_message_to_string_html(m);
00562 } else {
00563 s = seaudit_message_to_string(m);
00564 }
00565 if (s == NULL) {
00566 int error = errno;
00567 apol_vector_destroy(&v);
00568 ERR(log, "%s", strerror(error));
00569 errno = error;
00570 return -1;
00571 }
00572 fputs(s, outfile);
00573 fputc('\n', outfile);
00574 free(s);
00575 }
00576 }
00577 apol_vector_destroy(&v);
00578 return 0;
00579 }
00580
00581 static int report_print_policy_loads(const seaudit_log_t * log, const seaudit_report_t * report, FILE * outfile)
00582 {
00583 size_t i, num = seaudit_model_get_num_loads(log, report->model);
00584 apol_vector_t *v = seaudit_model_get_messages(log, report->model);
00585 seaudit_message_t *m;
00586 seaudit_message_type_e type;
00587 char *s;
00588 if (report->format == SEAUDIT_REPORT_FORMAT_HTML)
00589 fprintf(outfile,
00590 "<font class=\"message_count_label\">Number of messages:</font> <b class=\"message_count\">%zd</b><br>\n<br>\n",
00591 num);
00592 else
00593 fprintf(outfile, "Number of messages: %zd\n\n", num);
00594
00595 for (i = 0; i < apol_vector_get_size(v); i++) {
00596 m = apol_vector_get_element(v, i);
00597 seaudit_message_get_data(m, &type);
00598 if (type == SEAUDIT_MESSAGE_TYPE_LOAD) {
00599 if (report->format == SEAUDIT_REPORT_FORMAT_HTML) {
00600 s = seaudit_message_to_string_html(m);
00601 } else {
00602 s = seaudit_message_to_string(m);
00603 }
00604 if (s == NULL) {
00605 int error = errno;
00606 apol_vector_destroy(&v);
00607 ERR(log, "%s", strerror(error));
00608 errno = error;
00609 return -1;
00610 }
00611 fputs(s, outfile);
00612 fputc('\n', outfile);
00613 free(s);
00614 }
00615 }
00616 apol_vector_destroy(&v);
00617 return 0;
00618 }
00619
00620 static int report_print_avc_listing(const seaudit_log_t * log, const seaudit_report_t * report, seaudit_avc_message_type_e avc_type,
00621 FILE * outfile)
00622 {
00623 size_t i, num;
00624 apol_vector_t *v = seaudit_model_get_messages(log, report->model);
00625 seaudit_message_t *m;
00626 seaudit_avc_message_t *avc;
00627 seaudit_message_type_e type;
00628 char *s;
00629 if (avc_type == SEAUDIT_AVC_GRANTED) {
00630 num = seaudit_model_get_num_allows(log, report->model);
00631 } else {
00632 num = seaudit_model_get_num_denies(log, report->model);
00633 }
00634 if (report->format == SEAUDIT_REPORT_FORMAT_HTML)
00635 fprintf(outfile,
00636 "<font class=\"message_count_label\">Number of messages:</font> <b class=\"message_count\">%zd</b><br>\n<br>\n",
00637 num);
00638 else
00639 fprintf(outfile, "Number of messages: %zd\n\n", num);
00640
00641 for (i = 0; i < apol_vector_get_size(v); i++) {
00642 m = apol_vector_get_element(v, i);
00643 avc = seaudit_message_get_data(m, &type);
00644 if (type == SEAUDIT_MESSAGE_TYPE_AVC && avc->msg == avc_type) {
00645 if (report->format == SEAUDIT_REPORT_FORMAT_HTML) {
00646 s = seaudit_message_to_string_html(m);
00647 } else {
00648 s = seaudit_message_to_string(m);
00649 }
00650 if (s == NULL) {
00651 int error = errno;
00652 apol_vector_destroy(&v);
00653 ERR(log, "%s", strerror(error));
00654 errno = error;
00655 return -1;
00656 }
00657 fputs(s, outfile);
00658 fputc('\n', outfile);
00659 free(s);
00660 }
00661 }
00662 apol_vector_destroy(&v);
00663 return 0;
00664 }
00665
00666 static int report_print_stats(const seaudit_log_t * log, const seaudit_report_t * report, FILE * outfile)
00667 {
00668 apol_vector_t *v = seaudit_model_get_messages(log, report->model);
00669 size_t num_messages = apol_vector_get_size(v);
00670 apol_vector_destroy(&v);
00671 if (report->format == SEAUDIT_REPORT_FORMAT_HTML) {
00672 fprintf(outfile,
00673 "<font class=\"stats_label\">Number of total messages:</font> <b class=\"stats_count\">%zd</b><br>\n",
00674 num_messages);
00675 fprintf(outfile,
00676 "<font class=\"stats_label\">Number of policy load messages:</font> <b class=\"stats_count\">%zd</b><br>\n",
00677 seaudit_model_get_num_loads(log, report->model));
00678 fprintf(outfile,
00679 "<font class=\"stats_label\">Number of policy boolean messages:</font> <b class=\"stats_count\">%zd</b><br>\n",
00680 seaudit_model_get_num_bools(log, report->model));
00681 fprintf(outfile,
00682 "<font class=\"stats_label\">Number of allow messages:</font> <b class=\"stats_count\">%zd</b><br>\n",
00683 seaudit_model_get_num_allows(log, report->model));
00684 fprintf(outfile,
00685 "<font class=\"stats_label\">Number of denied messages:</font> <b class=\"stats_count\">%zd</b><br>\n",
00686 seaudit_model_get_num_denies(log, report->model));
00687 } else {
00688 fprintf(outfile, "Number of total messages: %zd\n", num_messages);
00689 fprintf(outfile, "Number of policy load messages: %zd\n", seaudit_model_get_num_loads(log, report->model));
00690 fprintf(outfile, "Number of policy boolean messages: %zd\n", seaudit_model_get_num_bools(log, report->model));
00691 fprintf(outfile, "Number of allow messages: %zd\n", seaudit_model_get_num_allows(log, report->model));
00692 fprintf(outfile, "Number of denied messages: %zd\n", seaudit_model_get_num_denies(log, report->model));
00693 }
00694 return 0;
00695 }
00696
00697 static int report_print_standard_section(const seaudit_log_t * log, const seaudit_report_t * report,
00698 xmlChar * id, xmlChar * title, FILE * outfile)
00699 {
00700 size_t sz, len, i;
00701 int rt = 0;
00702
00703 if (!report_is_valid_section_name((char *)id)) {
00704 ERR(log, "%s", "Invalid standard section ID.");
00705 errno = EINVAL;
00706 return -1;
00707 }
00708 sz = strlen((char *)id);
00709 if (title != NULL) {
00710 if (report->format == SEAUDIT_REPORT_FORMAT_HTML) {
00711 fprintf(outfile, "<h2 class=\"standard_section_title\"><u>%s</h2></u>\n", title);
00712 } else {
00713 fprintf(outfile, "%s\n", title);
00714 len = strlen((char *)title);
00715 for (i = 0; i < len; i++) {
00716 fprintf(outfile, "-");
00717 }
00718 fprintf(outfile, "\n");
00719 }
00720 }
00721 if (strncasecmp((char *)id, "PolicyLoads", sz) == 0) {
00722 rt = report_print_policy_loads(log, report, outfile);
00723 } else if (strncasecmp((char *)id, "EnforcementToggles", sz) == 0) {
00724 rt = report_print_enforce_toggles(log, report, outfile);
00725 } else if (strncasecmp((char *)id, "PolicyBooleans", sz) == 0) {
00726 rt = report_print_policy_booleans(log, report, outfile);
00727 } else if (strncasecmp((char *)id, "AllowListing", sz) == 0) {
00728 rt = report_print_avc_listing(log, report, SEAUDIT_AVC_GRANTED, outfile);
00729 } else if (strncasecmp((char *)id, "DenyListing", sz) == 0) {
00730 rt = report_print_avc_listing(log, report, SEAUDIT_AVC_DENIED, outfile);
00731 } else if (strncasecmp((char *)id, "Statistics", sz) == 0) {
00732 rt = report_print_stats(log, report, outfile);
00733 }
00734 if (rt < 0) {
00735 return rt;
00736 }
00737
00738 if (report->format == SEAUDIT_REPORT_FORMAT_HTML)
00739 fprintf(outfile, "<br>\n");
00740 else
00741 fprintf(outfile, "\n");
00742
00743 return 0;
00744 }
00745
00746 static int report_print_loaded_view(const seaudit_log_t * log, const seaudit_report_t * report, xmlChar * view_filePath,
00747 FILE * outfile)
00748 {
00749 size_t i, filters_added = 0;
00750 apol_vector_t *loaded_filters = NULL;
00751 seaudit_model_t *dup_model = NULL;
00752 seaudit_filter_t *filter;
00753 seaudit_message_t *msg;
00754 char *s;
00755 apol_vector_t *v = NULL;
00756 int retval = -1, error = 0;
00757
00758 if ((loaded_filters = seaudit_filter_create_from_file((char *)view_filePath)) == NULL) {
00759 error = errno;
00760 ERR(log, "Error parsing file %s.", view_filePath);
00761 goto cleanup;
00762 }
00763 if ((dup_model = seaudit_model_create_from_model(report->model)) == NULL) {
00764 error = errno;
00765 ERR(log, "%s", strerror(error));
00766 goto cleanup;
00767 }
00768 for (i = 0; i < apol_vector_get_size(loaded_filters); i++, filters_added++) {
00769 filter = apol_vector_get_element(loaded_filters, i);
00770 if (seaudit_model_append_filter(dup_model, filter) < 0) {
00771 error = errno;
00772 ERR(log, "%s", strerror(error));
00773 goto cleanup;
00774 }
00775 }
00776 if ((v = seaudit_model_get_messages(log, dup_model)) == NULL) {
00777 error = errno;
00778 ERR(log, "%s", strerror(error));
00779 goto cleanup;
00780 }
00781 if (report->format == SEAUDIT_REPORT_FORMAT_HTML) {
00782 fprintf(outfile, "View file: %s<br>\n", view_filePath);
00783 fprintf(outfile,
00784 "<font class=\"message_count_label\">Number of messages:</font> <b class=\"message_count\">%zd</b><br>\n<br>\n",
00785 apol_vector_get_size(v));
00786 } else {
00787 fprintf(outfile, "View file: %s\n", view_filePath);
00788 fprintf(outfile, "Number of messages: %zd\n\n", apol_vector_get_size(v));
00789 }
00790
00791 for (i = 0; i < apol_vector_get_size(v); i++) {
00792 msg = apol_vector_get_element(v, i);
00793 if (report->format == SEAUDIT_REPORT_FORMAT_HTML) {
00794 s = seaudit_message_to_string_html(msg);
00795 } else {
00796 s = seaudit_message_to_string(msg);
00797 }
00798 if (s == NULL) {
00799 error = errno;
00800 ERR(log, "%s", strerror(error));
00801 goto cleanup;
00802 }
00803 fputs(s, outfile);
00804 fputc('\n', outfile);
00805 free(s);
00806 }
00807 retval = 0;
00808 cleanup:
00809
00810
00811 if (loaded_filters != NULL) {
00812 for (i = filters_added; i < apol_vector_get_size(loaded_filters); i++) {
00813 filter = apol_vector_get_element(loaded_filters, i);
00814 seaudit_filter_destroy(&filter);
00815 }
00816 apol_vector_destroy(&loaded_filters);
00817 }
00818 seaudit_model_destroy(&dup_model);
00819 apol_vector_destroy(&v);
00820 if (error != 0) {
00821 errno = error;
00822 }
00823 return retval;
00824 }
00825
00826 static int report_print_custom_section(const seaudit_log_t * log, const seaudit_report_t * report,
00827 xmlTextReaderPtr reader, xmlChar * title, FILE * outfile)
00828 {
00829 size_t len, i;
00830 int rt, error = 0, retval = -1, end_of_element = 0;
00831 xmlChar *view_filePath = NULL, *name = NULL;
00832
00833 if (title != NULL) {
00834 if (report->format == SEAUDIT_REPORT_FORMAT_HTML) {
00835 fprintf(outfile, "<h2 class=\"custom_section_title\"><u>%s</h2></u>\n", title);
00836 } else {
00837 fprintf(outfile, "%s\n", title);
00838 len = strlen((char *)title);
00839 for (i = 0; i < len; i++) {
00840 fprintf(outfile, "-");
00841 }
00842 fprintf(outfile, "\n");
00843 }
00844 }
00845
00846
00847
00848 rt = xmlTextReaderRead(reader);
00849 while (rt == 1) {
00850
00851 name = xmlTextReaderName(reader);
00852 if (name == NULL) {
00853 error = errno;
00854 ERR(log, "%s", "Unavailable node name within.");
00855 goto cleanup;
00856 }
00857
00858
00859 if (strcmp((char *)name, "custom-section") == 0 && xmlTextReaderNodeType(reader) == 15) {
00860 xmlFree(name);
00861 end_of_element = 1;
00862 break;
00863 }
00864 if (strcmp((char *)name, "view") == 0 && xmlTextReaderNodeType(reader) == 1 && xmlTextReaderHasAttributes(reader)) {
00865 view_filePath = xmlTextReaderGetAttribute(reader, (const xmlChar *)"file");
00866 if (view_filePath == NULL) {
00867 error = errno;
00868 ERR(log, "%s", "Error getting file attribute for view node.");
00869 goto cleanup;
00870 }
00871 if (report_print_loaded_view(log, report, view_filePath, outfile) < 0) {
00872 error = errno;
00873 goto cleanup;
00874 }
00875 xmlFree(view_filePath);
00876 }
00877 xmlFree(name);
00878 rt = xmlTextReaderRead(reader);
00879 }
00880 if (!end_of_element && rt != 0) {
00881 error = EIO;
00882 ERR(log, "Error parsing config file %s. (rt:%d)", report->config, rt);
00883 goto cleanup;
00884 }
00885
00886 if (!end_of_element) {
00887 error = EIO;
00888 ERR(log, "%s", "Encountered end of file before finding end of element for custom-section node.");
00889 goto cleanup;;
00890 }
00891 if (report->format == SEAUDIT_REPORT_FORMAT_HTML)
00892 fprintf(outfile, "<br>\n");
00893 else
00894 fprintf(outfile, "\n");
00895
00896 return 0;
00897 cleanup:
00898 if (view_filePath)
00899 xmlFree(view_filePath);
00900 if (name)
00901 xmlFree(name);
00902 if (error != 0) {
00903 errno = error;
00904 }
00905 return retval;
00906 }
00907
00908 static int report_process_xmlNode(const seaudit_log_t * log, const seaudit_report_t * report, xmlTextReaderPtr reader,
00909 FILE * outfile)
00910 {
00911 xmlChar *name = NULL, *id_attr = NULL, *title_attr = NULL;
00912 int retval = -1, error = 0;
00913
00914 if ((name = xmlTextReaderName(reader)) == NULL) {
00915 error = errno;
00916 ERR(log, "%s", "Unavailable node name.");
00917 goto cleanup;
00918 }
00919
00920 if (!report_is_valid_node_name((char *)name)) {
00921 retval = 0;
00922 goto cleanup;
00923 }
00924
00925 if (strcmp((char *)name, "seaudit-report") == 0 && xmlTextReaderNodeType(reader) == 1) {
00926 if (report_parse_seaudit_report(log, report, reader, &id_attr, &title_attr) < 0) {
00927 error = errno;
00928 goto cleanup;
00929 }
00930 if (report->format == SEAUDIT_REPORT_FORMAT_HTML) {
00931 fprintf(outfile, "<h1 class=\"report_title\">Title: %s</h1>\n", title_attr);
00932 } else {
00933 fprintf(outfile, "Title: %s\n", title_attr);
00934 }
00935 } else if (strcmp((char *)name, "standard-section") == 0 && xmlTextReaderNodeType(reader) == 1) {
00936 if (report_parse_standard_attribs(log, report, reader, &id_attr, &title_attr) < 0) {
00937 error = errno;
00938 goto cleanup;
00939 }
00940 if (id_attr == NULL) {
00941 ERR(log, "%s", "Missing required id attribute for standard section node.");
00942 error = EIO;
00943 goto cleanup;
00944 }
00945
00946 if (report_print_standard_section(log, report, id_attr, title_attr, outfile) < 0) {
00947 error = errno;
00948 goto cleanup;
00949 }
00950 } else if (strcmp((char *)name, "custom-section") == 0 && xmlTextReaderNodeType(reader) == 1) {
00951 if (report_parse_custom_attribs(log, report, reader, &title_attr) < 0) {
00952 error = errno;
00953 goto cleanup;
00954 }
00955
00956 if (report_print_custom_section(log, report, reader, title_attr, outfile) < 0) {
00957 error = errno;
00958 goto cleanup;
00959 }
00960 }
00961
00962 retval = 0;
00963 cleanup:
00964 xmlFree(name);
00965 xmlFree(id_attr);
00966 xmlFree(title_attr);
00967 if (retval < 0) {
00968 errno = error;
00969 }
00970 return retval;
00971 }
00972
00973 static int report_print_malformed(const seaudit_log_t * log, const seaudit_report_t * report, FILE * outfile)
00974 {
00975 size_t i, len;
00976 apol_vector_t *v = seaudit_model_get_malformed_messages(log, report->model);
00977 if (v == NULL) {
00978 return -1;
00979 }
00980 if (report->format == SEAUDIT_REPORT_FORMAT_HTML) {
00981 fprintf(outfile, "<b><u>Malformed messages</b></u>\n");
00982 fprintf(outfile, "<br>\n<br>\n");
00983 } else {
00984 fprintf(outfile, "Malformed messages\n");
00985 len = strlen("Malformed messages\n");
00986 for (i = 0; i < len; i++) {
00987 fprintf(outfile, "-");
00988 }
00989 fprintf(outfile, "\n");
00990 }
00991 for (i = 0; i < apol_vector_get_size(v); i++) {
00992 char *malformed_msg;
00993 malformed_msg = apol_vector_get_element(v, i);
00994 if (report->format == SEAUDIT_REPORT_FORMAT_HTML)
00995 fprintf(outfile, "%s<br>\n", malformed_msg);
00996 else
00997 fprintf(outfile, "%s\n", malformed_msg);
00998 }
00999 fprintf(outfile, "\n");
01000 apol_vector_destroy(&v);
01001 return 0;
01002 }
01003
01004 int seaudit_report_write(const seaudit_log_t * log, const seaudit_report_t * report, const char *out_file)
01005 {
01006 xmlTextReaderPtr reader;
01007 FILE *outfile = NULL;
01008 int rt, retval = -1, error = 0;
01009
01010
01011 if (out_file == NULL) {
01012 outfile = stdout;
01013 } else {
01014 if ((outfile = fopen(out_file, "w+")) == NULL) {
01015 error = errno;
01016 ERR(log, "Could not open %s for writing.", out_file);
01017 goto cleanup;
01018 }
01019 }
01020
01021
01022 if (report_print_header(log, report, outfile) < 0) {
01023 error = errno;
01024 goto cleanup;
01025 }
01026
01027
01028 reader = xmlNewTextReaderFilename(report->config);
01029 if (reader == NULL) {
01030 error = errno;
01031 ERR(log, "Unable to open config file (%s).", report->config);
01032 goto cleanup;
01033 }
01034 rt = xmlTextReaderRead(reader);
01035 while (rt == 1) {
01036 report_process_xmlNode(log, report, reader, outfile);
01037 rt = xmlTextReaderRead(reader);
01038 }
01039 error = errno;
01040 xmlFreeTextReader(reader);
01041 if (rt != 0) {
01042 ERR(log, "Failed to parse config file %s.", report->config);
01043 goto cleanup;
01044 }
01045 if (report->malformed && report_print_malformed(log, report, outfile) < 0) {
01046 error = errno;
01047 goto cleanup;
01048 }
01049 report_print_footer(report, outfile);
01050
01051 retval = 0;
01052 cleanup:
01053 if (outfile != NULL) {
01054 fclose(outfile);
01055 }
01056 if (retval < 0) {
01057 errno = error;
01058 }
01059 return retval;
01060 }