/* * view_data.c - Part of AFD, an automatic file distribution program. * Copyright (c) 2007 - 2022 Holger Kiehl * * 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "afddefs.h" DESCR__S_M3 /* ** NAME ** view_data - calls a configured program to view data ** ** SYNOPSIS ** void view_data(char *fullname, char *file_name) ** ** DESCRIPTION ** ** RETURN VALUES ** ** AUTHOR ** H.Kiehl ** ** HISTORY ** 08.04.2007 H.Kiehl Created ** 04.09.2013 A.Maul Moved duplicate code to extra function ** add_default_afd_hex_print(). ** 12.09.2013 A.Maul The last filter is not terminated correctly. ** This could lead to a SIGSEGV. ** 29.04.2014 H.Kiehl When SUID bit is set we must release the ** effective UID and set the real user ID, in case ** we call some X program. ** */ DESCR__E_M3 #include #include /* strerror() */ #include /* realloc() */ #include #include #include #include /* seteuid() */ #include #include "ui_common_defs.h" /* External global variables. */ extern char font_name[], *p_work_dir; /* Local global variables. */ static int no_of_vdp; static struct view_process_list *vdpl; /* Local function prototypes. */ static void add_default_afd_hex_print(char *, char *); /*############################# view_data() #############################*/ void view_data(char *fullname, char *file_name) { int i, j; char afd_config_file[MAX_PATH_LENGTH]; (void)snprintf(afd_config_file, MAX_PATH_LENGTH, "%s%s%s", p_work_dir, ETC_DIR, AFD_CONFIG_FILE); if (eaccess(afd_config_file, F_OK) == 0) { int argcounter, fd, with_show_cmd; char *buffer, *ptr, *p_start, view_data_prog_def[VIEW_DATA_PROG_DEF_LENGTH + 2]; #ifdef HAVE_STATX struct statx stat_buf; #else struct stat stat_buf; #endif if ((fd = open(afd_config_file, O_RDONLY)) == -1) { (void)fprintf(stderr, "Failed to open() `%s' for reading : %s (%s %d)\n", afd_config_file, strerror(errno), __FILE__, __LINE__); exit(INCORRECT); } #ifdef HAVE_STATX if (statx(fd, "", AT_STATX_SYNC_AS_STAT | AT_EMPTY_PATH, STATX_SIZE, &stat_buf) == -1) #else if (fstat(fd, &stat_buf) == -1) #endif { (void)fprintf(stderr, "Failed to access `%s' : %s (%s %d)\n", afd_config_file, strerror(errno), __FILE__, __LINE__); exit(INCORRECT); } #ifdef HAVE_STATX if ((buffer = malloc(1 + stat_buf.stx_size + 1)) == NULL) #else if ((buffer = malloc(1 + stat_buf.st_size + 1)) == NULL) #endif { (void)fprintf(stderr, #if SIZEOF_OFF_T == 4 "Failed to malloc() %ld bytes : %s (%s %d)\n", #else "Failed to malloc() %lld bytes : %s (%s %d)\n", #endif #ifdef HAVE_STATX (pri_off_t)(1 + stat_buf.stx_size + 1), #else (pri_off_t)(1 + stat_buf.st_size + 1), #endif strerror(errno), __FILE__, __LINE__); exit(INCORRECT); } #ifdef HAVE_STATX if (read(fd, &buffer[1], stat_buf.stx_size) == -1) #else if (read(fd, &buffer[1], stat_buf.st_size) == -1) #endif { (void)fprintf(stderr, #if SIZEOF_OFF_T == 4 "Failed to read() %ld bytes from `%s' : %s (%s %d)\n", #else "Failed to read() %lld bytes from `%s' : %s (%s %d)\n", #endif #ifdef HAVE_STATX (pri_off_t)stat_buf.stx_size, afd_config_file, #else (pri_off_t)stat_buf.st_size, afd_config_file, #endif strerror(errno), __FILE__, __LINE__); exit(INCORRECT); } buffer[0] = '\n'; #ifdef HAVE_STATX buffer[stat_buf.stx_size + 1] = '\0'; #else buffer[stat_buf.st_size + 1] = '\0'; #endif (void)strcpy(&view_data_prog_def[1], VIEW_DATA_PROG_DEF); view_data_prog_def[0] = '\n'; if (no_of_vdp > 0) { for (i = 0; i < no_of_vdp; i++) { free(vdpl[i].progname); vdpl[i].progname = NULL; FREE_RT_ARRAY(vdpl[i].filter); vdpl[i].filter = NULL; free(vdpl[i].args); vdpl[i].args = NULL; } free(vdpl); } no_of_vdp = 0; vdpl = NULL; ptr = buffer; do { if ((ptr = posi(ptr, view_data_prog_def)) != NULL) { while ((*ptr == ' ') || (*ptr == '\t')) { ptr++; } /* Check if we wish to add show_cmd (--with-show_cmd). */ if ((*ptr == '-') && (*(ptr + 1) == '-') && (*(ptr + 2) == 'w') && (*(ptr + 3) == 'i') && (*(ptr + 4) == 't') && (*(ptr + 5) == 'h') && (*(ptr + 6) == '-') && (*(ptr + 7) == 's') && (*(ptr + 8) == 'h') && (*(ptr + 9) == 'o') && (*(ptr + 10) == 'w') && (*(ptr + 11) == '_') && (*(ptr + 12) == 'c') && (*(ptr + 13) == 'm') && (*(ptr + 14) == 'd') && ((*(ptr + 15) == ' ') || (*(ptr + 15) == '\t'))) { with_show_cmd = YES; ptr += 15; while ((*ptr == ' ') || (*ptr == '\t')) { ptr++; } } else { with_show_cmd = NO; } p_start = ptr; argcounter = 0; if (*ptr == '"') { ptr++; p_start = ptr; while ((*ptr != '"') && (*ptr != '\n') && (*ptr != '\0') && (*ptr != '\r')) { if ((*ptr == ' ') || (*ptr == '\t')) { argcounter++; } ptr++; } if (*ptr == '"') { *ptr = ' '; } } else { while ((*ptr != ' ') && (*ptr != '\t') && (*ptr != '\n') && (*ptr != '\r') && (*ptr != '\0')) { ptr++; } } if (ptr != p_start) { int length, max_length; if ((vdpl = realloc(vdpl, ((no_of_vdp + 1) * sizeof(struct view_process_list)))) == NULL) { (void)fprintf(stderr, "realloc() error : %s (%s %d)\n", strerror(errno), __FILE__, __LINE__); exit(INCORRECT); } length = ptr - p_start; if (with_show_cmd == YES) { int extra_length; char *p_arg, *p_read, *p_write, tmp_char; length += SHOW_CMD_LENGTH + 1 + WORK_DIR_ID_LENGTH + 1 + strlen(p_work_dir) + 1 + 2 + 1 + 2 + 1 + strlen(font_name) + 1 + 4 + MAX_PATH_LENGTH + 1 + strlen(file_name) + 1; if ((vdpl[no_of_vdp].progname = malloc(length + 1)) == NULL) { (void)fprintf(stderr, "Failed to malloc() %d bytes : %s (%s %d)\n", length + 1, strerror(errno), __FILE__, __LINE__); exit(INCORRECT); } extra_length = snprintf(vdpl[no_of_vdp].progname, length + 1, "%s %s %s -b -f %s \"", SHOW_CMD, WORK_DIR_ID, p_work_dir, font_name); if (extra_length > (length + 1)) { (void)fprintf(stderr, "Buffer to small %d > %d (%s %d)\n", extra_length, length + 1, __FILE__, __LINE__); exit(INCORRECT); } p_write = vdpl[no_of_vdp].progname + extra_length; extra_length = 0; tmp_char = *ptr; *ptr = '\0'; p_read = p_start; length = strlen(fullname); while (*p_read != '\0') { if ((*p_read == '%') && (*(p_read + 1) == 's') && ((extra_length + length) < MAX_PATH_LENGTH)) { (void)strcpy(p_write, fullname); p_read += 2; p_write += length; extra_length += length; } else { *p_write = *p_read; p_write++; p_read++; } } *ptr = tmp_char; /* If no %s is found, add fullname to the end. */ if (extra_length == 0) { *p_write = ' '; p_write++; (void)strcpy(p_write, fullname); p_write += length; } /* For show_cmd write as last parameter the file name. */ *p_write = ' '; p_write++; (void)strcpy(p_write, file_name); p_write += strlen(file_name); *p_write = '"'; p_write++; *p_write = '\0'; if ((vdpl[no_of_vdp].args = malloc(8 * sizeof(char *))) == NULL) { (void)fprintf(stderr, "malloc() error : %s (%s %d)\n", strerror(errno), __FILE__, __LINE__); exit(INCORRECT); } vdpl[no_of_vdp].args[0] = vdpl[no_of_vdp].progname; p_arg = vdpl[no_of_vdp].progname; p_arg += SHOW_CMD_LENGTH; *p_arg = '\0'; p_arg++; vdpl[no_of_vdp].args[1] = p_arg; p_arg += WORK_DIR_ID_LENGTH; *p_arg = '\0'; p_arg++; vdpl[no_of_vdp].args[2] = p_arg; while (*p_arg != ' ') { p_arg++; } *p_arg = '\0'; p_arg++; vdpl[no_of_vdp].args[3] = p_arg; p_arg += 2; *p_arg = '\0'; p_arg++; vdpl[no_of_vdp].args[4] = p_arg; p_arg += 2; *p_arg = '\0'; p_arg++; vdpl[no_of_vdp].args[5] = p_arg; while (*p_arg != ' ') { p_arg++; } *p_arg = '\0'; p_arg++; vdpl[no_of_vdp].args[6] = p_arg; vdpl[no_of_vdp].args[7] = NULL; } else { if ((vdpl[no_of_vdp].progname = malloc(length + 1)) == NULL) { (void)fprintf(stderr, "Failed to malloc() %d bytes : %s (%s %d)\n", length + 1, strerror(errno), __FILE__, __LINE__); exit(INCORRECT); } (void)strncpy(vdpl[no_of_vdp].progname, p_start, length); vdpl[no_of_vdp].progname[length] = '\0'; /* Cut out the args. */ if (argcounter > 0) { int filename_set = NO; char *p_arg; if ((vdpl[no_of_vdp].args = malloc((argcounter + 3) * sizeof(char *))) == NULL) { (void)fprintf(stderr, "malloc() error : %s (%s %d)\n", strerror(errno), __FILE__, __LINE__); exit(INCORRECT); } vdpl[no_of_vdp].args[0] = vdpl[no_of_vdp].progname; p_arg = vdpl[no_of_vdp].progname; for (i = 1; i < (argcounter + 1); i++) { while ((*p_arg != ' ') && (*p_arg != '\t')) { p_arg++; } *p_arg = '\0'; p_arg++; vdpl[no_of_vdp].args[i] = p_arg; if ((*p_arg == '%') && (*(p_arg + 1) == 's')) { filename_set = YES; vdpl[no_of_vdp].args[i] = fullname; } } while ((*p_arg != ' ') && (*p_arg != '\t') && (*p_arg != '\n') && (*p_arg != '\r') && (*p_arg != '\0')) { p_arg++; } if (*p_arg != '\0') { *p_arg = '\0'; } if (filename_set == NO) { vdpl[no_of_vdp].args[i] = fullname; i += 1; } vdpl[no_of_vdp].args[i] = NULL; } else { if ((vdpl[no_of_vdp].args = malloc(3 * sizeof(char *))) == NULL) { (void)fprintf(stderr, "malloc() error : %s (%s %d)\n", strerror(errno), __FILE__, __LINE__); exit(INCORRECT); } vdpl[no_of_vdp].args[0] = vdpl[no_of_vdp].progname; vdpl[no_of_vdp].args[1] = fullname; vdpl[no_of_vdp].args[2] = NULL; } } /* Cut out filters. */ while ((*ptr == ' ') || (*ptr == '\t')) { ptr++; } p_start = ptr; length = 0; max_length = 0; vdpl[no_of_vdp].no_of_filters = 0; while ((*ptr != '\n') && (*ptr != '\r') && (*ptr != '\0')) { if (*ptr == '|') { vdpl[no_of_vdp].no_of_filters++; if (length > max_length) { max_length = length; } length = 0; ptr++; } else { ptr++; length++; } } if (ptr != p_start) { vdpl[no_of_vdp].no_of_filters++; if (length > max_length) { max_length = length; } RT_ARRAY(vdpl[no_of_vdp].filter, vdpl[no_of_vdp].no_of_filters, max_length + 1, char); ptr = p_start; length = 0; max_length = 0; while ((*ptr != '\n') && (*ptr != '\r') && (*ptr != '\0')) { if (*ptr == '|') { vdpl[no_of_vdp].filter[max_length][length] = '\0'; length = 0; max_length++; ptr++; } else { vdpl[no_of_vdp].filter[max_length][length] = *ptr; ptr++; length++; } } vdpl[no_of_vdp].filter[max_length][length] = '\0'; } no_of_vdp++; } } } while (ptr != NULL); free(buffer); /* Add as default program afd_hex_print. */ add_default_afd_hex_print(fullname, file_name); if (close(fd) == -1) { (void)fprintf(stderr, "close() error : %s (%s %d)\n", strerror(errno), __FILE__, __LINE__); } } if (no_of_vdp == 0) { add_default_afd_hex_print(fullname, file_name); } for (i = 0; i < no_of_vdp; i++) { for (j = 0; j < vdpl[i].no_of_filters; j++) { if (pmatch(vdpl[i].filter[j], file_name, NULL) == 0) { uid_t euid, /* Effective user ID. */ ruid; /* Real user ID. */ if (i == (no_of_vdp - 1)) { (void)sprintf(vdpl[i].args[6], "\"%s %s %s\"", HEX_PRINT, fullname, file_name); } /* * SSH wants to look at .Xauthority and with setuid flag * set we cannot do that. So when we initialize X lets temporaly * disable it. After XtAppInitialize() we set it back. */ euid = geteuid(); ruid = getuid(); if (euid != ruid) { if (seteuid(ruid) == -1) { (void)fprintf(stderr, "Failed to seteuid() to %d : %s (%s %d)\n", ruid, strerror(errno), __FILE__, __LINE__); } } make_xprocess(vdpl[i].progname, vdpl[i].progname, vdpl[i].args, -1); if (euid != ruid) { if (seteuid(euid) == -1) { (void)fprintf(stderr, "Failed to seteuid() to %d : %s (%s %d)\n", euid, strerror(errno), __FILE__, __LINE__); } } return; } } } return; } /*+++++++++++++++++++++ add_default_afd_hex_print() +++++++++++++++++++++*/ static void add_default_afd_hex_print(char *fullname, char *file_name) { char *p_arg; /* Add as default program afd_hex_print. */ if ((vdpl = realloc(vdpl, ((no_of_vdp + 1) * sizeof(struct view_process_list)))) == NULL) { (void)fprintf(stderr, "realloc() error : %s (%s %d)\n", strerror(errno), __FILE__, __LINE__); exit(INCORRECT); } vdpl[no_of_vdp].no_of_filters = 1; RT_ARRAY(vdpl[no_of_vdp].filter, 1, 2, char); vdpl[no_of_vdp].filter[0][0] = '*'; vdpl[no_of_vdp].filter[0][1] = '\0'; if ((vdpl[no_of_vdp].progname = malloc(MAX_PATH_LENGTH)) == NULL) { (void)fprintf(stderr, "malloc() error : %s (%s %d)\n", strerror(errno), __FILE__, __LINE__); exit(INCORRECT); } (void)snprintf(vdpl[no_of_vdp].progname, MAX_PATH_LENGTH, "%s %s %s -b -f %s \"%s %s %s\"", SHOW_CMD, WORK_DIR_ID, p_work_dir, font_name, HEX_PRINT, fullname, file_name); if ((vdpl[no_of_vdp].args = malloc(8 * sizeof(char *))) == NULL) { (void)fprintf(stderr, "malloc() error : %s (%s %d)\n", strerror(errno), __FILE__, __LINE__); exit(INCORRECT); } vdpl[no_of_vdp].args[0] = vdpl[no_of_vdp].progname; p_arg = vdpl[no_of_vdp].progname; p_arg += SHOW_CMD_LENGTH; *p_arg = '\0'; p_arg++; vdpl[no_of_vdp].args[1] = p_arg; p_arg += WORK_DIR_ID_LENGTH; *p_arg = '\0'; p_arg++; vdpl[no_of_vdp].args[2] = p_arg; while (*p_arg != ' ') { p_arg++; } *p_arg = '\0'; p_arg++; vdpl[no_of_vdp].args[3] = p_arg; p_arg += 2; *p_arg = '\0'; p_arg++; vdpl[no_of_vdp].args[4] = p_arg; p_arg += 2; *p_arg = '\0'; p_arg++; vdpl[no_of_vdp].args[5] = p_arg; while (*p_arg != ' ') { p_arg++; } *p_arg = '\0'; p_arg++; vdpl[no_of_vdp].args[6] = p_arg; vdpl[no_of_vdp].args[7] = NULL; no_of_vdp++; return; }