"Fossies" - the Fresh Open Source Software Archive 
Member "sudo-1.9.11p3/plugins/sudoers/audit.c" (12 Jun 2022, 12167 Bytes) of package /linux/misc/sudo-1.9.11p3.tar.gz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "audit.c" see the
Fossies "Dox" file reference documentation and the last
Fossies "Diffs" side-by-side code changes report:
1.9.10_vs_1.9.11rc1.
1 /*
2 * SPDX-License-Identifier: ISC
3 *
4 * Copyright (c) 2009-2015, 2019-2020 Todd C. Miller <Todd.Miller@sudo.ws>
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 /*
20 * This is an open source non-commercial project. Dear PVS-Studio, please check it.
21 * PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
22 */
23
24 #include <config.h>
25
26 #include <sys/wait.h>
27 #include <stdarg.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31
32 #include "sudoers.h"
33 #ifdef SUDOERS_LOG_CLIENT
34 # include "log_client.h"
35 #endif
36
37 #ifdef HAVE_BSM_AUDIT
38 # include "bsm_audit.h"
39 #endif
40 #ifdef HAVE_LINUX_AUDIT
41 # include "linux_audit.h"
42 #endif
43 #ifdef HAVE_SOLARIS_AUDIT
44 # include "solaris_audit.h"
45 #endif
46
47 #ifdef SUDOERS_LOG_CLIENT
48 static struct log_details audit_details;
49 #endif
50 char *audit_msg = NULL;
51
52 /* sudoers_audit is declared at the end of this file. */
53 extern sudo_dso_public struct audit_plugin sudoers_audit;
54
55 static int
56 audit_success(char *const argv[])
57 {
58 int rc = 0;
59 debug_decl(audit_success, SUDOERS_DEBUG_AUDIT);
60
61 if (argv != NULL) {
62 #ifdef HAVE_BSM_AUDIT
63 if (bsm_audit_success(argv) == -1)
64 rc = -1;
65 #endif
66 #ifdef HAVE_LINUX_AUDIT
67 if (linux_audit_command(argv, 1) == -1)
68 rc = -1;
69 #endif
70 #ifdef HAVE_SOLARIS_AUDIT
71 if (solaris_audit_success(argv) == -1)
72 rc = -1;
73 #endif
74 }
75
76 debug_return_int(rc);
77 }
78
79 static int
80 audit_failure_int(char *const argv[], const char *message)
81 {
82 int ret = 0;
83 debug_decl(audit_failure_int, SUDOERS_DEBUG_AUDIT);
84
85 #if defined(HAVE_BSM_AUDIT) || defined(HAVE_LINUX_AUDIT)
86 if (def_log_denied && argv != NULL) {
87 #ifdef HAVE_BSM_AUDIT
88 if (bsm_audit_failure(argv, message) == -1)
89 ret = -1;
90 #endif
91 #ifdef HAVE_LINUX_AUDIT
92 if (linux_audit_command(argv, 0) == -1)
93 ret = -1;
94 #endif
95 #ifdef HAVE_SOLARIS_AUDIT
96 if (solaris_audit_failure(argv, message) == -1)
97 ret = -1;
98 #endif
99 }
100 #endif /* HAVE_BSM_AUDIT || HAVE_LINUX_AUDIT */
101
102 debug_return_int(ret);
103 }
104
105 int
106 vaudit_failure(char *const argv[], char const *const fmt, va_list ap)
107 {
108 int oldlocale, ret;
109 char *message;
110 debug_decl(vaudit_failure, SUDOERS_DEBUG_AUDIT);
111
112 /* Audit messages should be in the sudoers locale. */
113 sudoers_setlocale(SUDOERS_LOCALE_SUDOERS, &oldlocale);
114
115 if ((ret = vasprintf(&message, _(fmt), ap)) == -1)
116 sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
117
118 if (ret != -1) {
119 /* Set audit_msg for audit plugins. */
120 free(audit_msg);
121 audit_msg = message;
122
123 ret = audit_failure_int(argv, audit_msg);
124 }
125
126 sudoers_setlocale(oldlocale, NULL);
127
128 debug_return_int(ret);
129 }
130
131 int
132 audit_failure(char *const argv[], char const *const fmt, ...)
133 {
134 va_list ap;
135 int ret;
136 debug_decl(audit_failure, SUDOERS_DEBUG_AUDIT);
137
138 va_start(ap, fmt);
139 ret = vaudit_failure(argv, fmt, ap);
140 va_end(ap);
141
142 debug_return_int(ret);
143 }
144
145 static int
146 sudoers_audit_open(unsigned int version, sudo_conv_t conversation,
147 sudo_printf_t plugin_printf, char * const settings[],
148 char * const user_info[], int submit_optind, char * const submit_argv[],
149 char * const submit_envp[], char * const plugin_options[],
150 const char **errstr)
151 {
152 struct sudo_conf_debug_file_list debug_files = TAILQ_HEAD_INITIALIZER(debug_files);
153 struct sudoers_open_info info;
154 const char *cp, *plugin_path = NULL;
155 char * const *cur;
156 int ret;
157 debug_decl(sudoers_audit_open, SUDOERS_DEBUG_PLUGIN);
158
159 sudo_conv = conversation;
160 sudo_printf = plugin_printf;
161 if (sudoers_audit.event_alloc != NULL)
162 plugin_event_alloc = sudoers_audit.event_alloc;
163
164 bindtextdomain("sudoers", LOCALEDIR);
165
166 /* Initialize the debug subsystem. */
167 for (cur = settings; (cp = *cur) != NULL; cur++) {
168 if (strncmp(cp, "debug_flags=", sizeof("debug_flags=") - 1) == 0) {
169 cp += sizeof("debug_flags=") - 1;
170 if (!sudoers_debug_parse_flags(&debug_files, cp))
171 debug_return_int(-1);
172 continue;
173 }
174 if (strncmp(cp, "plugin_path=", sizeof("plugin_path=") - 1) == 0) {
175 plugin_path = cp + sizeof("plugin_path=") - 1;
176 continue;
177 }
178 }
179 if (!sudoers_debug_register(plugin_path, &debug_files))
180 debug_return_int(-1);
181
182 /* Call the sudoers init function. */
183 info.settings = settings;
184 info.user_info = user_info;
185 info.plugin_args = plugin_options;
186 ret = sudoers_init(&info, log_parse_error, submit_envp);
187
188 if (ret == true) {
189 /* Unset close function if we don't need it to avoid extra process. */
190 #ifdef SUDOERS_LOG_CLIENT
191 if (client_closure == NULL)
192 #endif
193 sudoers_audit.close = NULL;
194 } else {
195 /* The audit functions set audit_msg on failure. */
196 if (audit_msg != NULL)
197 *errstr = audit_msg;
198 }
199
200 debug_return_int(ret);
201 }
202
203 static void
204 audit_to_eventlog(struct eventlog *evlog, char * const command_info[],
205 char * const run_argv[], char * const run_envp[], const char *uuid_str)
206 {
207 char * const *cur;
208 debug_decl(audit_to_eventlog, SUDOERS_DEBUG_PLUGIN);
209
210 /* Fill in evlog from sudoers Defaults, run_argv and run_envp. */
211 sudoers_to_eventlog(evlog, run_argv, run_envp, uuid_str);
212
213 /* Update iolog and execution environment from command_info[]. */
214 if (command_info != NULL) {
215 for (cur = command_info; *cur != NULL; cur++) {
216 switch (**cur) {
217 case 'c':
218 if (strncmp(*cur, "command=", sizeof("command=") - 1) == 0) {
219 evlog->command = *cur + sizeof("command=") - 1;
220 continue;
221 }
222 if (strncmp(*cur, "chroot=", sizeof("chroot=") - 1) == 0) {
223 evlog->runchroot = *cur + sizeof("chroot=") - 1;
224 continue;
225 }
226 break;
227 case 'i':
228 if (strncmp(*cur, "iolog_path=", sizeof("iolog_path=") - 1) == 0) {
229 evlog->iolog_path = *cur + sizeof("iolog_path=") - 1;
230 evlog->iolog_file = sudo_basename(evlog->iolog_path);
231 continue;
232 }
233 break;
234 case 'r':
235 if (strncmp(*cur, "runcwd=", sizeof("runcwd=") - 1) == 0) {
236 evlog->runcwd = *cur + sizeof("runcwd=") - 1;
237 continue;
238 }
239 break;
240 }
241 }
242 }
243
244 debug_return;
245 }
246
247 #ifdef SUDOERS_LOG_CLIENT
248 static bool
249 log_server_accept(struct eventlog *evlog)
250 {
251 struct timespec now;
252 bool ret = false;
253 debug_decl(log_server_accept, SUDOERS_DEBUG_PLUGIN);
254
255 if (SLIST_EMPTY(&def_log_servers))
256 debug_return_bool(true);
257
258 if (client_closure != NULL && ISSET(sudo_mode, MODE_POLICY_INTERCEPTED)) {
259 /* Older servers don't support multiple commands per session. */
260 if (!client_closure->subcommands)
261 debug_return_bool(true);
262 } else {
263 /* Only send accept event to log server if I/O log plugin did not. */
264 if (def_log_input || def_log_output)
265 debug_return_bool(true);
266 }
267
268 if (sudo_gettime_real(&now) == -1) {
269 sudo_warn("%s", U_("unable to get time of day"));
270 goto done;
271 }
272
273 if (client_closure != NULL) {
274 /* Use existing client closure. */
275 if (fmt_accept_message(client_closure, evlog)) {
276 if (client_closure->write_ev->add(client_closure->write_ev,
277 &client_closure->log_details->server_timeout) == -1) {
278 sudo_warn("%s", U_("unable to add event to queue"));
279 goto done;
280 }
281 ret = true;
282 }
283 } else {
284 if (!init_log_details(&audit_details, evlog))
285 goto done;
286
287 /* Open connection to log server, send hello and accept messages. */
288 client_closure = log_server_open(&audit_details, &now, false,
289 SEND_ACCEPT, NULL);
290 if (client_closure != NULL)
291 ret = true;
292 }
293
294 done:
295 debug_return_bool(ret);
296 }
297
298 static void
299 log_server_exit(int status_type, int status)
300 {
301 debug_decl(log_server_exit, SUDOERS_DEBUG_PLUGIN);
302
303 if (client_closure != NULL) {
304 int exit_status = 0, error = 0;
305
306 if (status_type == SUDO_PLUGIN_WAIT_STATUS) {
307 if (WIFEXITED(status))
308 exit_status = WEXITSTATUS(status);
309 else
310 exit_status = WTERMSIG(status) | 128;
311 } else {
312 /* Must be errno. */
313 error = status;
314 }
315 log_server_close(client_closure, exit_status, error);
316 client_closure = NULL;
317 free(audit_details.evlog);
318 audit_details.evlog = NULL;
319 }
320
321 debug_return;
322 }
323 #else
324 static bool
325 log_server_accept(struct eventlog *evlog)
326 {
327 return true;
328 }
329
330 static void
331 log_server_exit(int status_type, int status)
332 {
333 return;
334 }
335 #endif /* SUDOERS_LOG_CLIENT */
336
337 static int
338 sudoers_audit_accept(const char *plugin_name, unsigned int plugin_type,
339 char * const command_info[], char * const run_argv[],
340 char * const run_envp[], const char **errstr)
341 {
342 const char *uuid_str = NULL;
343 struct eventlog evlog;
344 int ret = true;
345 debug_decl(sudoers_audit_accept, SUDOERS_DEBUG_PLUGIN);
346
347 /* Only log the accept event from the sudo front-end */
348 if (plugin_type != SUDO_FRONT_END)
349 debug_return_int(true);
350
351 if (!def_log_allowed)
352 debug_return_int(true);
353
354 if (audit_success(run_argv) != 0 && !def_ignore_audit_errors)
355 ret = false;
356
357 if (!ISSET(sudo_mode, MODE_POLICY_INTERCEPTED))
358 uuid_str = sudo_user.uuid_str;
359
360 audit_to_eventlog(&evlog, command_info, run_argv, run_envp, uuid_str);
361 if (!log_allowed(&evlog) && !def_ignore_logfile_errors)
362 ret = false;
363
364 if (!log_server_accept(&evlog)) {
365 if (!def_ignore_logfile_errors)
366 ret = false;
367 }
368
369 debug_return_int(ret);
370 }
371
372 static int
373 sudoers_audit_reject(const char *plugin_name, unsigned int plugin_type,
374 const char *message, char * const command_info[], const char **errstr)
375 {
376 struct eventlog evlog;
377 int ret = true;
378 debug_decl(sudoers_audit_reject, SUDOERS_DEBUG_PLUGIN);
379
380 /* Skip reject events that sudoers generated itself. */
381 if (strncmp(plugin_name, "sudoers_", 8) == 0)
382 debug_return_int(true);
383
384 if (!def_log_denied)
385 debug_return_int(true);
386
387 if (audit_failure_int(NewArgv, message) != 0) {
388 if (!def_ignore_audit_errors)
389 ret = false;
390 }
391
392 audit_to_eventlog(&evlog, command_info, NewArgv, env_get(), NULL);
393 if (!eventlog_reject(&evlog, 0, message, NULL, NULL))
394 ret = false;
395
396 if (!log_server_reject(&evlog, message))
397 ret = false;
398
399 debug_return_int(ret);
400 }
401
402 static int
403 sudoers_audit_error(const char *plugin_name, unsigned int plugin_type,
404 const char *message, char * const command_info[], const char **errstr)
405 {
406 struct eventlog evlog;
407 struct timespec now;
408 int ret = true;
409 debug_decl(sudoers_audit_error, SUDOERS_DEBUG_PLUGIN);
410
411 /* Skip error events that sudoers generated itself. */
412 if (strncmp(plugin_name, "sudoers_", 8) == 0)
413 debug_return_int(true);
414
415 if (audit_failure_int(NewArgv, message) != 0) {
416 if (!def_ignore_audit_errors)
417 ret = false;
418 }
419
420 if (sudo_gettime_real(&now)) {
421 sudo_warn("%s", U_("unable to get time of day"));
422 debug_return_bool(false);
423 }
424
425 audit_to_eventlog(&evlog, command_info, NewArgv, env_get(), NULL);
426 if (!eventlog_alert(&evlog, 0, &now, message, NULL))
427 ret = false;
428
429 if (!log_server_alert(&evlog, &now, message, NULL))
430 ret = false;
431
432 debug_return_int(ret);
433 }
434
435 void
436 sudoers_audit_close(int status_type, int status)
437 {
438 log_server_exit(status_type, status);
439 }
440
441 static int
442 sudoers_audit_version(int verbose)
443 {
444 debug_decl(sudoers_audit_version, SUDOERS_DEBUG_PLUGIN);
445
446 sudo_printf(SUDO_CONV_INFO_MSG, "Sudoers audit plugin version %s\n",
447 PACKAGE_VERSION);
448
449 debug_return_int(true);
450 }
451
452 sudo_dso_public struct audit_plugin sudoers_audit = {
453 SUDO_AUDIT_PLUGIN,
454 SUDO_API_VERSION,
455 sudoers_audit_open,
456 sudoers_audit_close,
457 sudoers_audit_accept,
458 sudoers_audit_reject,
459 sudoers_audit_error,
460 sudoers_audit_version,
461 NULL, /* register_hooks */
462 NULL, /* deregister_hooks */
463 NULL /* event_alloc() filled in by sudo */
464 };