Path: blob/main/lib/iolog/regress/iolog_path/check_iolog_path.c
1532 views
/*1* SPDX-License-Identifier: ISC2*3* Copyright (c) 2011-2013 Todd C. Miller <[email protected]>4*5* Permission to use, copy, modify, and distribute this software for any6* purpose with or without fee is hereby granted, provided that the above7* copyright notice and this permission notice appear in all copies.8*9* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES10* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF11* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR12* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES13* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN14* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF15* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.16*/1718#include <config.h>1920#include <stdio.h>21#include <stdlib.h>22#include <string.h>23#include <limits.h>24#include <time.h>25#include <unistd.h>2627#define SUDO_ERROR_WRAP 02829#include <sudo_compat.h>30#include <sudo_util.h>31#include <sudo_fatal.h>32#include <sudo_iolog.h>3334static struct iolog_escape_data {35char sessid[7];36char *user;37char *group;38char *runas_user;39char *runas_group;40char *host;41char *command;42} escape_data;4344sudo_dso_public int main(int argc, char *argv[]);4546sudo_noreturn static void47usage(void)48{49fprintf(stderr, "usage: %s datafile\n", getprogname());50exit(EXIT_FAILURE);51}5253static void54reset_escape_data(struct iolog_escape_data *data)55{56free(data->user);57free(data->group);58free(data->runas_user);59free(data->runas_group);60free(data->host);61free(data->command);62memset(data, 0, sizeof(*data));63}6465static size_t66fill_seq(char *restrict str, size_t strsize, void *restrict unused)67{68int len;6970/* Path is of the form /var/log/sudo-io/00/00/01. */71len = snprintf(str, strsize, "%c%c/%c%c/%c%c", escape_data.sessid[0],72escape_data.sessid[1], escape_data.sessid[2], escape_data.sessid[3],73escape_data.sessid[4], escape_data.sessid[5]);74if (len < 0)75return strsize; /* handle non-standard snprintf() */76return (size_t)len;77}7879static size_t80fill_user(char *restrict str, size_t strsize, void * restrict unused)81{82return strlcpy(str, escape_data.user, strsize);83}8485static size_t86fill_group(char *restrict str, size_t strsize, void * restrict unused)87{88return strlcpy(str, escape_data.group, strsize);89}9091static size_t92fill_runas_user(char * restrict str, size_t strsize, void * restrict unused)93{94return strlcpy(str, escape_data.runas_user, strsize);95}9697static size_t98fill_runas_group(char * restrict str, size_t strsize, void *restrict unused)99{100return strlcpy(str, escape_data.runas_group, strsize);101}102103static size_t104fill_hostname(char *restrict str, size_t strsize, void * restrict unused)105{106return strlcpy(str, escape_data.host, strsize);107}108109static size_t110fill_command(char * restrict str, size_t strsize, void * restrict unused)111{112return strlcpy(str, escape_data.command, strsize);113}114115/* Note: "seq" must be first in the list. */116static struct iolog_path_escape path_escapes[] = {117{ "seq", fill_seq },118{ "user", fill_user },119{ "group", fill_group },120{ "runas_user", fill_runas_user },121{ "runas_group", fill_runas_group },122{ "hostname", fill_hostname },123{ "command", fill_command },124{ NULL, NULL }125};126127static int128do_check(char *dir_in, char *file_in, char *tdir_out, char *tfile_out)129{130char dir[PATH_MAX], dir_out[PATH_MAX] = "";131char file[PATH_MAX], file_out[PATH_MAX] = "";132int error = 0;133struct tm tm;134time_t now;135size_t len;136137/*138* Expand any strftime(3) escapes139* XXX - want to pass tm to expand_iolog_path140*/141time(&now);142if (localtime_r(&now, &tm) == NULL)143sudo_fatal("localtime_r");144if (tdir_out[0] != '\0') {145len = strftime(dir_out, sizeof(dir_out), tdir_out, &tm);146if (len == 0 || dir_out[sizeof(dir_out) - 1] != '\0')147sudo_fatalx("dir_out: strftime overflow");148}149if (tfile_out[0] != '\0') {150len = strftime(file_out, sizeof(file_out), tfile_out, &tm);151if (len == 0 || file_out[sizeof(file_out) - 1] != '\0')152sudo_fatalx("file_out: strftime overflow");153}154155if (!expand_iolog_path(dir_in, dir, sizeof(dir), &path_escapes[1], NULL))156sudo_fatalx("unable to expand I/O log dir");157if (!expand_iolog_path(file_in, file, sizeof(file), &path_escapes[0], dir))158sudo_fatalx("unable to expand I/O log file");159160if (strcmp(dir, dir_out) != 0) {161sudo_warnx("%s: expected %s, got %s", dir_in, dir_out, dir);162error = 1;163}164if (strcmp(file, file_out) != 0) {165sudo_warnx("%s: expected %s, got %s", file_in, file_out, file);166error = 1;167}168169return error;170}171172#define MAX_STATE 12173174int175main(int argc, char *argv[])176{177size_t len;178FILE *fp;179char line[2048];180char *file_in = NULL, *file_out = NULL;181char *dir_in = NULL, *dir_out = NULL;182int ch, state = 0, errors = 0, ntests = 0;183184initprogname(argc > 0 ? argv[0] : "check_iolog_path");185186while ((ch = getopt(argc, argv, "v")) != -1) {187switch (ch) {188case 'v':189/* ignore */190break;191default:192fprintf(stderr, "usage: %s [-v] data\n", getprogname());193return EXIT_FAILURE;194}195}196argc -= optind;197argv += optind;198199if (argc != 1)200usage();201202fp = fopen(argv[0], "r");203if (fp == NULL)204sudo_fatalx("unable to open %s", argv[0]);205206/*207* Input consists of 12 lines:208* sequence number209* user name210* user gid211* runas user name212* runas gid213* hostname [short form]214* command215* dir [with escapes]216* file [with escapes]217* expanded dir218* expanded file219* empty line220*/221while (fgets(line, sizeof(line), fp) != NULL) {222len = strcspn(line, "\n");223line[len] = '\0';224225switch (state) {226case 0:227strlcpy(escape_data.sessid, line, sizeof(escape_data.sessid));228break;229case 1:230if ((escape_data.user = strdup(line)) == NULL)231sudo_fatal(NULL);232break;233case 2:234if ((escape_data.group = strdup(line)) == NULL)235sudo_fatal(NULL);236break;237case 3:238if ((escape_data.runas_user = strdup(line)) == NULL)239sudo_fatal(NULL);240break;241case 4:242if ((escape_data.runas_group = strdup(line)) == NULL)243sudo_fatal(NULL);244break;245case 5:246if ((escape_data.host = strdup(line)) == NULL)247sudo_fatal(NULL);248break;249case 6:250if ((escape_data.command = strdup(line)) == NULL)251sudo_fatal(NULL);252break;253case 7:254free(dir_in);255if ((dir_in = strdup(line)) == NULL)256sudo_fatal(NULL);257break;258case 8:259free(file_in);260if ((file_in = strdup(line)) == NULL)261sudo_fatal(NULL);262break;263case 9:264free(dir_out);265if ((dir_out = strdup(line)) == NULL)266sudo_fatal(NULL);267break;268case 10:269free(file_out);270if ((file_out = strdup(line)) == NULL)271sudo_fatal(NULL);272break;273case 11:274errors += do_check(dir_in, file_in, dir_out, file_out);275ntests++;276reset_escape_data(&escape_data);277break;278default:279sudo_fatalx("internal error, invalid state %d", state);280}281state = (state + 1) % MAX_STATE;282}283free(dir_in);284free(dir_out);285free(file_in);286free(file_out);287288if (ntests != 0) {289printf("iolog_path: %d test%s run, %d errors, %d%% success rate\n",290ntests, ntests == 1 ? "" : "s", errors,291(ntests - errors) * 100 / ntests);292}293294return errors;295}296297298