/* * Copyright (C) 2014-2024 Firejail Authors * * This file is part of firejail project * * 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "../include/etc_groups.h" #include "../include/common.h" #include #define MAX_BUF 4098 #define MAX_ARR 1024 char *arr[MAX_ARR] = {NULL}; int arr_cnt = 0; static int arr_tls_ca = 0; static int arr_x11 = 0; static int arr_games = 0; static char outbuf[256 * 1024]; static char *outptr; static int arg_replace = 0; static int arg_debug = 0; void outprintf(char* fmt, ...) { va_list args; va_start(args,fmt); outptr += vsprintf(outptr, fmt, args); va_end(args); } static int arr_check(const char *fname, char **pptr) { assert(fname); assert(pptr); while (*pptr != NULL) { if (strcmp(fname, *pptr) == 0) return 1; pptr++; } return 0; } static void arr_add(const char *fname) { assert(fname); assert(arr_cnt < MAX_ARR); int i; for (i = 0; i < arr_cnt; i++) if (strcmp(arr[i], fname) == 0) return; arr[arr_cnt] = strdup(fname); if (!arr[arr_cnt]) errExit("strdup"); arr_cnt++; } int arr_cmp(const void *p1, const void *p2) { char **ptr1 = (char **) p1; char **ptr2 = (char **) p2; return strcmp(*ptr1, *ptr2); } static void arr_sort(void) { qsort(&arr[0], arr_cnt, sizeof(char *), arr_cmp); } static void arr_clean(void) { int i; for (i = 0; i < arr_cnt; i++) { free(arr[i]); arr[i] = NULL; } arr_cnt = 0; arr_games = 0; arr_tls_ca = 0; arr_x11 = 0; } static char *arr_print(void) { char *last_line = outptr; outprintf("private-etc "); if (arr_games) outprintf("@games,"); if (arr_tls_ca) outprintf("@tls-ca,"); if (arr_x11) outprintf("@x11,"); int i; for (i = 0; i < arr_cnt; i++) outprintf("%s,", arr[i]); if (*(outptr - 1) == ' ' || *(outptr - 1) == ',') { outptr--; *outptr = '\0'; } outprintf("\n"); return last_line; } static void process_file(const char *fname) { assert(fname); FILE *fp = fopen(fname, "r"); if (!fp) { fprintf(stderr, "Error: cannot open %s file\n", fname); exit(1); } outptr = outbuf; *outptr = '\0'; arr_clean(); char line[MAX_BUF]; char orig_line[MAX_BUF]; int cnt = 0; int print = 0; while (fgets(line, MAX_BUF, fp)) { cnt++; if (strncmp(line, "private-etc", 11) != 0) { outprintf("%s", line); continue; } strcpy(orig_line,line); char *ptr = strchr(line, '\n'); if (ptr) *ptr = '\0'; ptr = line + 12; while (*ptr == ' ' || *ptr == '\t') ptr++; // check for blanks and tabs char *ptr2 = ptr; while (*ptr2 != '\0') { if (*ptr2 == ' ' || *ptr2 == '\t') { fprintf(stderr, "Error: invalid private-etc line %s:%d\n", fname, cnt); exit(1); } ptr2++; } ptr = strtok(ptr, ","); while (ptr) { if (arg_debug) printf("%s\n", ptr); if (arr_check(ptr, &etc_list[0])); else if (arr_check(ptr, &etc_group_sound[0])); else if (arr_check(ptr, &etc_group_network[0])); else if (strcmp(ptr, "@games") == 0) arr_games = 1; else if (strcmp(ptr, "@tls-ca") == 0) arr_tls_ca = 1; else if (strcmp(ptr, "@x11") == 0) arr_x11 = 1; else if (arr_check(ptr, &etc_group_games[0])) arr_games = 1; else if (arr_check(ptr, &etc_group_tls_ca[0])) arr_tls_ca = 1; else if (arr_check(ptr, &etc_group_x11[0])) arr_x11 = 1; else arr_add(ptr); ptr = strtok(NULL, ","); } arr_sort(); char *last_line = arr_print(); if (strcmp(last_line, orig_line) == 0) { fclose(fp); return; } printf("\n********************\nfile: %s\n\nold: %s\nnew: %s\n", fname, orig_line, last_line); print = 1; } fclose(fp); if (print && arg_replace) { fp = fopen(fname, "w"); if (!fp) { fprintf(stderr, "Error: cannot open profile file\n"); exit(1); } fprintf(fp, "%s", outbuf); fclose(fp); } } static const char *const usage_str = "usage: cleanup-etc [options] file.profile [file.profile]\n" "Group and clean private-etc entries in one or more profile files.\n" "Options:\n" " --debug - print debug messages\n" " -h, -?, --help - this help screen\n" " --replace - replace profile file\n"; static void usage(void) { puts(usage_str); } int main(int argc, char **argv) { if (argc < 2) { fprintf(stderr, "Error: invalid number of parameters\n"); usage(); return 1; } int i; for (i = 1; i < argc; i++) { if (strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "-?") == 0 || strcmp(argv[i], "--help") == 0) { usage(); return 0; } else if (strcmp(argv[i], "--debug") == 0) arg_debug = 1; else if (strcmp(argv[i], "--replace") == 0) arg_replace = 1; else if (*argv[i] == '-') { fprintf(stderr, "Error: invalid program option %s\n", argv[i]); return 1; } else break; } for (; i < argc; i++) process_file(argv[i]); return 0; }