Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sudo-project
GitHub Repository: sudo-project/sudo
Path: blob/main/lib/iolog/regress/iolog_path/check_iolog_path.c
1532 views
1
/*
2
* SPDX-License-Identifier: ISC
3
*
4
* Copyright (c) 2011-2013 Todd C. Miller <[email protected]>
5
*
6
* Permission to use, copy, modify, and distribute this software for any
7
* purpose with or without fee is hereby granted, provided that the above
8
* copyright notice and this permission notice appear in all copies.
9
*
10
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17
*/
18
19
#include <config.h>
20
21
#include <stdio.h>
22
#include <stdlib.h>
23
#include <string.h>
24
#include <limits.h>
25
#include <time.h>
26
#include <unistd.h>
27
28
#define SUDO_ERROR_WRAP 0
29
30
#include <sudo_compat.h>
31
#include <sudo_util.h>
32
#include <sudo_fatal.h>
33
#include <sudo_iolog.h>
34
35
static struct iolog_escape_data {
36
char sessid[7];
37
char *user;
38
char *group;
39
char *runas_user;
40
char *runas_group;
41
char *host;
42
char *command;
43
} escape_data;
44
45
sudo_dso_public int main(int argc, char *argv[]);
46
47
sudo_noreturn static void
48
usage(void)
49
{
50
fprintf(stderr, "usage: %s datafile\n", getprogname());
51
exit(EXIT_FAILURE);
52
}
53
54
static void
55
reset_escape_data(struct iolog_escape_data *data)
56
{
57
free(data->user);
58
free(data->group);
59
free(data->runas_user);
60
free(data->runas_group);
61
free(data->host);
62
free(data->command);
63
memset(data, 0, sizeof(*data));
64
}
65
66
static size_t
67
fill_seq(char *restrict str, size_t strsize, void *restrict unused)
68
{
69
int len;
70
71
/* Path is of the form /var/log/sudo-io/00/00/01. */
72
len = snprintf(str, strsize, "%c%c/%c%c/%c%c", escape_data.sessid[0],
73
escape_data.sessid[1], escape_data.sessid[2], escape_data.sessid[3],
74
escape_data.sessid[4], escape_data.sessid[5]);
75
if (len < 0)
76
return strsize; /* handle non-standard snprintf() */
77
return (size_t)len;
78
}
79
80
static size_t
81
fill_user(char *restrict str, size_t strsize, void * restrict unused)
82
{
83
return strlcpy(str, escape_data.user, strsize);
84
}
85
86
static size_t
87
fill_group(char *restrict str, size_t strsize, void * restrict unused)
88
{
89
return strlcpy(str, escape_data.group, strsize);
90
}
91
92
static size_t
93
fill_runas_user(char * restrict str, size_t strsize, void * restrict unused)
94
{
95
return strlcpy(str, escape_data.runas_user, strsize);
96
}
97
98
static size_t
99
fill_runas_group(char * restrict str, size_t strsize, void *restrict unused)
100
{
101
return strlcpy(str, escape_data.runas_group, strsize);
102
}
103
104
static size_t
105
fill_hostname(char *restrict str, size_t strsize, void * restrict unused)
106
{
107
return strlcpy(str, escape_data.host, strsize);
108
}
109
110
static size_t
111
fill_command(char * restrict str, size_t strsize, void * restrict unused)
112
{
113
return strlcpy(str, escape_data.command, strsize);
114
}
115
116
/* Note: "seq" must be first in the list. */
117
static struct iolog_path_escape path_escapes[] = {
118
{ "seq", fill_seq },
119
{ "user", fill_user },
120
{ "group", fill_group },
121
{ "runas_user", fill_runas_user },
122
{ "runas_group", fill_runas_group },
123
{ "hostname", fill_hostname },
124
{ "command", fill_command },
125
{ NULL, NULL }
126
};
127
128
static int
129
do_check(char *dir_in, char *file_in, char *tdir_out, char *tfile_out)
130
{
131
char dir[PATH_MAX], dir_out[PATH_MAX] = "";
132
char file[PATH_MAX], file_out[PATH_MAX] = "";
133
int error = 0;
134
struct tm tm;
135
time_t now;
136
size_t len;
137
138
/*
139
* Expand any strftime(3) escapes
140
* XXX - want to pass tm to expand_iolog_path
141
*/
142
time(&now);
143
if (localtime_r(&now, &tm) == NULL)
144
sudo_fatal("localtime_r");
145
if (tdir_out[0] != '\0') {
146
len = strftime(dir_out, sizeof(dir_out), tdir_out, &tm);
147
if (len == 0 || dir_out[sizeof(dir_out) - 1] != '\0')
148
sudo_fatalx("dir_out: strftime overflow");
149
}
150
if (tfile_out[0] != '\0') {
151
len = strftime(file_out, sizeof(file_out), tfile_out, &tm);
152
if (len == 0 || file_out[sizeof(file_out) - 1] != '\0')
153
sudo_fatalx("file_out: strftime overflow");
154
}
155
156
if (!expand_iolog_path(dir_in, dir, sizeof(dir), &path_escapes[1], NULL))
157
sudo_fatalx("unable to expand I/O log dir");
158
if (!expand_iolog_path(file_in, file, sizeof(file), &path_escapes[0], dir))
159
sudo_fatalx("unable to expand I/O log file");
160
161
if (strcmp(dir, dir_out) != 0) {
162
sudo_warnx("%s: expected %s, got %s", dir_in, dir_out, dir);
163
error = 1;
164
}
165
if (strcmp(file, file_out) != 0) {
166
sudo_warnx("%s: expected %s, got %s", file_in, file_out, file);
167
error = 1;
168
}
169
170
return error;
171
}
172
173
#define MAX_STATE 12
174
175
int
176
main(int argc, char *argv[])
177
{
178
size_t len;
179
FILE *fp;
180
char line[2048];
181
char *file_in = NULL, *file_out = NULL;
182
char *dir_in = NULL, *dir_out = NULL;
183
int ch, state = 0, errors = 0, ntests = 0;
184
185
initprogname(argc > 0 ? argv[0] : "check_iolog_path");
186
187
while ((ch = getopt(argc, argv, "v")) != -1) {
188
switch (ch) {
189
case 'v':
190
/* ignore */
191
break;
192
default:
193
fprintf(stderr, "usage: %s [-v] data\n", getprogname());
194
return EXIT_FAILURE;
195
}
196
}
197
argc -= optind;
198
argv += optind;
199
200
if (argc != 1)
201
usage();
202
203
fp = fopen(argv[0], "r");
204
if (fp == NULL)
205
sudo_fatalx("unable to open %s", argv[0]);
206
207
/*
208
* Input consists of 12 lines:
209
* sequence number
210
* user name
211
* user gid
212
* runas user name
213
* runas gid
214
* hostname [short form]
215
* command
216
* dir [with escapes]
217
* file [with escapes]
218
* expanded dir
219
* expanded file
220
* empty line
221
*/
222
while (fgets(line, sizeof(line), fp) != NULL) {
223
len = strcspn(line, "\n");
224
line[len] = '\0';
225
226
switch (state) {
227
case 0:
228
strlcpy(escape_data.sessid, line, sizeof(escape_data.sessid));
229
break;
230
case 1:
231
if ((escape_data.user = strdup(line)) == NULL)
232
sudo_fatal(NULL);
233
break;
234
case 2:
235
if ((escape_data.group = strdup(line)) == NULL)
236
sudo_fatal(NULL);
237
break;
238
case 3:
239
if ((escape_data.runas_user = strdup(line)) == NULL)
240
sudo_fatal(NULL);
241
break;
242
case 4:
243
if ((escape_data.runas_group = strdup(line)) == NULL)
244
sudo_fatal(NULL);
245
break;
246
case 5:
247
if ((escape_data.host = strdup(line)) == NULL)
248
sudo_fatal(NULL);
249
break;
250
case 6:
251
if ((escape_data.command = strdup(line)) == NULL)
252
sudo_fatal(NULL);
253
break;
254
case 7:
255
free(dir_in);
256
if ((dir_in = strdup(line)) == NULL)
257
sudo_fatal(NULL);
258
break;
259
case 8:
260
free(file_in);
261
if ((file_in = strdup(line)) == NULL)
262
sudo_fatal(NULL);
263
break;
264
case 9:
265
free(dir_out);
266
if ((dir_out = strdup(line)) == NULL)
267
sudo_fatal(NULL);
268
break;
269
case 10:
270
free(file_out);
271
if ((file_out = strdup(line)) == NULL)
272
sudo_fatal(NULL);
273
break;
274
case 11:
275
errors += do_check(dir_in, file_in, dir_out, file_out);
276
ntests++;
277
reset_escape_data(&escape_data);
278
break;
279
default:
280
sudo_fatalx("internal error, invalid state %d", state);
281
}
282
state = (state + 1) % MAX_STATE;
283
}
284
free(dir_in);
285
free(dir_out);
286
free(file_in);
287
free(file_out);
288
289
if (ntests != 0) {
290
printf("iolog_path: %d test%s run, %d errors, %d%% success rate\n",
291
ntests, ntests == 1 ? "" : "s", errors,
292
(ntests - errors) * 100 / ntests);
293
}
294
295
return errors;
296
}
297
298