"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 };