/* $CoreSDI: audconf.c,v 1.14 2001/08/15 00:59:40 claudio Exp $ */ /* * Copyright (c) 2000, 2001, Core SDI S.A., Argentina * All rights reserved * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither name of the Core SDI S.A. nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * Auditd configuration functions * Author: Claudio Castiglia */ #include #include #ifndef __linux__ #include #endif #include #include #include #include #include #include #include #include #include "sysdep.h" #include "packet.h" #include "resource.h" #include "modtypes.h" #include "modules.h" #include "audit.h" #include "audconf.h" #include "log.h" #define WHITE_SPACE " \r\n\t" #define YES(arg) (!strcasecmp(arg, "yes")) #define NO(arg) (!strcasecmp(arg, "no")) /* * Misc. name-code struct */ struct namecode { char *name; int code; }; /* * Auditd Options List */ struct namecode auditd_options[] = { { "LogSession", AOC_LOG_SESSION }, { "LogDebugInfo", AOC_LOG_DEBUG }, { "QuietMode", AOC_LOG_QUIET }, { "Port", AOC_PORT }, { "ListenAddress", AOC_ADDRESS }, { "ModulesPath", AOC_MODULES_PATH }, { "SyslogFacility", AOC_SYSLOG_FACILITY }, { "Timeout", AOC_TIMEOUT }, { "CommandTimeout", AOC_COMMAND_TIMEOUT }, { "AuthModule", AOC_AUTH_MODULE }, { "IaModule", AOC_IA_MODULE }, { "ResModule", AOC_RESOURCE_MODULE }, { NULL, 0 } }; /* * Allowed Auditd Syslog Facility Options */ struct namecode auditd_sysfac_options[] = { { "AUTH", LOG_AUTH }, { "AUTHPRIV", LOG_AUTHPRIV }, { "DAEMON", LOG_DAEMON }, { "USER", LOG_USER }, { NULL, 0 } }; /* * Add module_name into auth/ia list * list == 0: auth list * list != 0: ia list * Return 0 on success and -1 on error */ int auditd_add_modulename(AUDITD_OPTIONS *options, int list, const char *module_name) { char ***dst; char **p; char *d; int *n; if (list) { dst = &options->ia_list; n = &options->ia_modules; } else { dst = &options->auth_list; n = &options->auth_modules; } if ( (d = strdup(module_name)) == NULL) return (-1); if ( (p = (char **) realloc(*dst, sizeof(char *) * (*n)+1)) == NULL) { free(d); return (-1); } p[*n] = d; *dst = p; (*n)++; return (0); } /* * Release auditd options dynamic memory */ void auditd_release_options(AUDITD_OPTIONS *options) { if (options->auth_list != NULL) { while (options->auth_modules--) free(options->auth_list[options->auth_modules]); free(options->auth_list); options->auth_list = NULL; } if (options->ia_list != NULL) { while (options->ia_modules--) free(options->ia_list[options->ia_modules]); free(options->ia_list); options->ia_list = NULL; } } /* * Set default auditd options */ void auditd_set_default_options(AUDITD_OPTIONS *options) { options->flags = LOGF_ERROR; options->sysfac = DEFAULT_FACILITY; options->timeout = DEFAULT_TIMEOUT; options->command_timeout = DEFAULT_COMMAND_TIMEOUT; options->auth_modules = 0; options->ia_modules = 0; options->auth_list = NULL; options->ia_list = NULL; bzero(&options->addr, sizeof(options->addr)); options->addr.sin_family = AF_INET; options->addr.sin_port = htons(DEFAULT_AUDIT_PORT); options->addr.sin_addr.s_addr = htonl(DEFAULT_ADDRESS); strlcpy(options->pidfile, AUDITD_PID_FILE, sizeof(options->pidfile)); strlcpy(options->confile, DEFAULT_CONFIG_FILE, sizeof(options->confile)); strlcpy(options->modpath, DEFAULT_MODULES_PATH, sizeof(options->modpath)); strlcpy(options->resmodule, DEFAULT_RESOURCES_MODULE, sizeof(options->resmodule)); } /* * auditd_set_option: * Set user auditd option, return 0 on success and -1 on fail */ int auditd_set_option(AUDITD_OPTIONS *options, AUDITD_OPTIONS_CODES code, char *value) { unsigned long int i; char *err; if (value == NULL) return (-1); switch (code) { case AOC_LOG_SESSION: if (YES(value)) options->flags |= LOGF_SESSION; else if (NO(value)) options->flags &= ~LOGF_SESSION; else break; return (0); case AOC_LOG_DEBUG: if (YES(value)) options->flags |= LOGF_DEBUG; else if (NO(value)) options->flags &= ~LOGF_DEBUG; else break; return (0); case AOC_LOG_VERBOSE: if (YES(value)) options->flags |= LOGF_STDERR; else if (NO(value)) options->flags &= ~LOGF_STDERR; else break; return (0); case AOC_LOG_QUIET: if (YES(value)) options->flags |= LOGF_NOLOG; else if (NO(value)) options->flags &= ~LOGF_NOLOG; else break; return (0); case AOC_SYSLOG_FACILITY: for (i = 0; auditd_sysfac_options[i].name; i++) if (!strcasecmp(auditd_sysfac_options[i].name, value)) { options->sysfac = auditd_sysfac_options[i].code; return (0);; } if (auditd_sysfac_options[i].name == NULL) break; return (0); case AOC_PORT: i = strtoul(value, &err, 0); if (*err != '\0' || i > 65535) break; options->addr.sin_port = htons((u_int16_t) i); return (0); case AOC_ADDRESS: switch(inet_pton(options->addr.sin_family, value, &options->addr.sin_addr.s_addr)) { case 1: break; case 0: errno = EAFNOSUPPORT; default: return (-1); } return (0); case AOC_CONFIG_FILE: return ((realpath(value, options->confile) == NULL) ? -1 : 0); case AOC_MODULES_PATH: return ((realpath(value, options->modpath) == NULL) ? -1 : 0); case AOC_TIMEOUT: i = strtoul(value, &err, 0); if (*err != '\0') break; options->timeout = i; return (0); case AOC_COMMAND_TIMEOUT: i = strtoul(value, &err, 0); if (*err != '\0') break; options->command_timeout = i; return (0); case AOC_AUTH_MODULE: return (auditd_add_modulename(options, 0, value)); case AOC_IA_MODULE: return (auditd_add_modulename(options, 1, value)); case AOC_RESOURCE_MODULE: strlcpy(options->resmodule, value, sizeof(options->resmodule)); return (0); default: break; } errno = EINVAL; return (-1); } /* * auditd_load_configuration(): * Open, parse configuration file, and configure auditd. */ int auditd_load_configuration(AUDITD_OPTIONS *options) { char buf[128]; char *pc; char *pn; int line; int errors; int i; FILE *f; AUDITD_OPTIONS o; o = *options; o.auth_modules = 0; o.ia_modules = 0; o.auth_list = NULL; o.ia_list = NULL; if (o.confile[0] != '\0') { if ( (f = fopen(o.confile, "r")) == NULL) { log_err("Can't open '%s': %s", o.confile, strerror(errno)); return (-1); } line = 0; errors = 0; while (fgets(buf, sizeof(buf), f) != NULL) { line++; pc = buf + strspn(buf, WHITE_SPACE); if (*pc == '\0' || *pc == '\n' || *pc == '#') continue; pn = pc; if (strsep(&pn, WHITE_SPACE) == NULL) continue; pn += strspn(buf, WHITE_SPACE); if (pn[( i = strlen(pn) - 1)] == '\n') pn[i] = '\0'; for (i = 0; auditd_options[i].name != NULL; i++) if (!strcasecmp(auditd_options[i].name, pc)) { if (auditd_set_option(&o, auditd_options[i].code, pn) < 0) { errors++; log_err("%s: Invalid \"%s\" " "argument on line %d.", options->confile, pn, line); } break; } if (auditd_options[i].name == NULL) { errors++; log_err("%s: Invalid \"%s\" " "option on line %d.", o.confile, pc, line); } } fclose(f); if (errors) { log_err("%s: Found %d errors.", o.confile, errors); auditd_release_options(&o); return (-1); } else { auditd_release_options(options); *options = o; } set_modules_path(options->modpath); } return (0); }