Home | History | Annotate | Download | only in common
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 /*
     22  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
     23  * Use is subject to license terms.
     24  *
     25  * private interfaces for auditd plugins and auditd.
     26  */
     27 
     28 #include <bsm/audit.h>
     29 #include <bsm/audit_record.h>
     30 #include <bsm/audit_uevents.h>
     31 #include <bsm/libbsm.h>
     32 #include <errno.h>
     33 #include <fcntl.h>
     34 #include <libintl.h>
     35 #include <pthread.h>
     36 #include <stdio.h>
     37 #include <stdlib.h>
     38 #include <string.h>
     39 #include <sys/file.h>
     40 #include <sys/stat.h>
     41 #include <sys/types.h>
     42 #include <syslog.h>
     43 #include <unistd.h>
     44 #include <wait.h>
     45 #include "audit_plugin.h"
     46 
     47 static char	auditwarn[] = "/etc/security/audit_warn";
     48 static pthread_mutex_t	syslog_lock;
     49 
     50 static void
     51 init_syslog_mutex()
     52 {
     53 	(void) pthread_mutex_init(&syslog_lock, NULL);
     54 }
     55 
     56 /*
     57  * audit_syslog() -- generate syslog messages from threads that use
     58  * different severity, facility code, and application names.
     59  *
     60  * syslog(3C) is thread safe, but the set openlog() / syslog() /
     61  * closelog() is not.
     62  *
     63  * Assumption:  the app_name and facility code are paired, i.e.,
     64  * if the facility code for this call is the same as for the
     65  * the previous, the app_name hasn't changed.
     66  */
     67 void
     68 __audit_syslog(
     69 	const char *app_name,
     70 	int flags,
     71 	int facility,
     72 	int severity,
     73 	const char *message)
     74 {
     75 	static pthread_once_t	once_control = PTHREAD_ONCE_INIT;
     76 	static int		logopen = 0;
     77 	static int		prev_facility = -1;
     78 
     79 	(void) pthread_once(&once_control, init_syslog_mutex);
     80 
     81 	(void) pthread_mutex_lock(&syslog_lock);
     82 	if (prev_facility != facility) {
     83 		if (logopen)
     84 			closelog();
     85 		openlog(app_name, flags, facility);
     86 		syslog(severity, "%s", message);
     87 		(void) pthread_mutex_unlock(&syslog_lock);
     88 	} else {
     89 		syslog(severity, "%s", message);
     90 		(void) pthread_mutex_unlock(&syslog_lock);
     91 	}
     92 }
     93 
     94 /*
     95  * __audit_dowarn - invoke the shell script auditwarn to notify the
     96  *	adminstrator about a given problem.
     97  * parameters -
     98  *	option - what the problem is
     99  *	text - when used with options soft and hard: which file was being
    100  *		   used when the filesystem filled up
    101  *	       when used with the plugin option:  error detail
    102  *	count - used with various options: how many times auditwarn has
    103  *		been called for this problem since it was last cleared.
    104  */
    105 void
    106 __audit_dowarn(char *option, char *text, int count)
    107 {
    108 	pid_t		pid;
    109 	int		st;
    110 	char		countstr[5];
    111 	char		warnstring[80];
    112 	char		empty[1] = "";
    113 
    114 	if ((pid = fork1()) == -1) {
    115 		__audit_syslog("auditd", LOG_PID | LOG_ODELAY | LOG_CONS,
    116 		    LOG_DAEMON, LOG_ALERT, gettext("audit_warn fork failed\n"));
    117 		return;
    118 	}
    119 	if (pid != 0) {
    120 		(void) waitpid(pid, &st, 0);
    121 		return;
    122 	}
    123 	(void) sprintf(countstr, "%d", count);
    124 	if (text == NULL)
    125 		text = empty;
    126 
    127 	if (strcmp(option, "soft") == 0 || strcmp(option, "hard") == 0)
    128 		(void) execl(auditwarn, auditwarn, option, text, 0);
    129 
    130 	else if (strcmp(option, "allhard") == 0 ||
    131 	    strcmp(option, "getacdir") == 0)
    132 		(void) execl(auditwarn, auditwarn, option, countstr, 0);
    133 	else if (strcmp(option, "plugin") == 0)
    134 		(void) execl(auditwarn, auditwarn, option, text, countstr, 0);
    135 	else
    136 		(void) execl(auditwarn, auditwarn, option, 0);
    137 	/*
    138 	 * (execl failed)
    139 	 */
    140 	if (strcmp(option, "soft") == 0)
    141 		(void) sprintf(warnstring,
    142 		    gettext("soft limit in %s.\n"), text);
    143 	else if (strcmp(option, "hard") == 0)
    144 		(void) sprintf(warnstring,
    145 		    gettext("hard limit in %s.\n"), text);
    146 	else if (strcmp(option, "allhard") == 0)
    147 		(void) sprintf(warnstring,
    148 		    gettext("All audit filesystems are full.\n"));
    149 	else if (strcmp(option, "getacmin") == 0)
    150 		(void) sprintf(warnstring,
    151 		    gettext("audit_control minfree error.\n"));
    152 	else if (strcmp(option, "getacdir") == 0)
    153 		(void) sprintf(warnstring,
    154 		    gettext("audit_control directory error.\n"));
    155 	else
    156 		(void) sprintf(warnstring,
    157 		    gettext("error %s.\n"), option);
    158 
    159 	__audit_syslog("auditd", LOG_PID | LOG_ODELAY | LOG_CONS, LOG_AUTH,
    160 	    LOG_ALERT, (const char *)warnstring);
    161 
    162 	exit(1);
    163 }
    164 
    165 /*
    166  * __audit_dowarn2 - invoke the shell script auditwarn to notify the
    167  *	adminstrator about a given problem.
    168  * parameters -
    169  *	option - what the problem is
    170  *	name - entity reporting the problem (ie, plugin name)
    171  *	error - error string
    172  *	text - when used with options soft and hard: which file was being
    173  *		   used when the filesystem filled up
    174  *	       when used with the plugin option:  error detail
    175  *	count - used with various options: how many times auditwarn has
    176  *		been called for this problem since it was last cleared.
    177  */
    178 void
    179 __audit_dowarn2(char *option, char *name, char *error, char *text, int count)
    180 {
    181 	pid_t		pid;
    182 	int		st;
    183 	char		countstr[5];
    184 	char		warnstring[80];
    185 	char		empty[4] = "...";
    186 	char		none[3] = "--";
    187 
    188 	if ((pid = fork()) == -1) {
    189 		__audit_syslog("auditd", LOG_PID | LOG_ODELAY | LOG_CONS,
    190 		    LOG_DAEMON, LOG_ALERT, gettext("audit_warn fork failed\n"));
    191 		return;
    192 	}
    193 	if (pid != 0) {
    194 		(void) waitpid(pid, &st, 0);
    195 		return;
    196 	}
    197 	(void) sprintf(countstr, "%d", count);
    198 	if ((text == NULL) || (*text == '\0'))
    199 		text = empty;
    200 	if ((name == NULL) || (*name == '\0'))
    201 		name = none;
    202 
    203 	(void) execl(auditwarn, auditwarn, option, name, error, text,
    204 	    countstr, 0);
    205 
    206 	/*
    207 	 * (execl failed)
    208 	 */
    209 	(void) sprintf(warnstring,
    210 	    gettext("audit_control plugin error: %s\n"), text);
    211 
    212 	__audit_syslog("auditd", LOG_PID | LOG_ODELAY | LOG_CONS, LOG_AUTH,
    213 	    LOG_ALERT, (const char *)warnstring);
    214 
    215 	exit(1);
    216 }
    217 
    218 /*
    219  * logpost - post the new audit log file name to audit_data.
    220  *
    221  * This is not re-entrant code; it is called from auditd.c when
    222  * audit_binfile.so is not running and from binfile after auditd
    223  * is done.
    224  */
    225 int
    226 __logpost(char *name)
    227 {
    228 	char	buffer[MAXPATHLEN];
    229 	char	empty[] = "";
    230 
    231 	static int	first = 1;
    232 	static char	auditdata[] = AUDITDATAFILE;
    233 	static int	audit_data_fd; /* file descriptor of audit_data */
    234 
    235 	if (first) {
    236 		first = 0;
    237 		/*
    238 		 * Open the audit_data file. Use O_APPEND so that the contents
    239 		 * are not destroyed if there is another auditd running.
    240 		 */
    241 		if ((audit_data_fd = open(auditdata,
    242 		    O_RDWR | O_APPEND | O_CREAT, 0660)) < 0) {
    243 			__audit_dowarn("tmpfile", "", 0);
    244 			return (1);
    245 		}
    246 	}
    247 	if (name == NULL)
    248 		name = empty;
    249 
    250 	(void) snprintf(buffer, sizeof (buffer), "%d:%s\n",
    251 	    (int)getpid(), name);
    252 
    253 	(void) ftruncate(audit_data_fd, (off_t)0);
    254 	(void) write(audit_data_fd, buffer, strlen(buffer));
    255 	(void) fsync(audit_data_fd);
    256 
    257 	return (0);
    258 }
    259 
    260 /*
    261  * debug use - open a file for auditd and its plugins for debug
    262  */
    263 FILE *
    264 __auditd_debug_file_open() {
    265 	static FILE	*fp = NULL;
    266 
    267 	if (fp != NULL)
    268 		return (fp);
    269 	if ((fp = fopen("/var/audit/dump", "aF")) == NULL)
    270 		(void) fprintf(stderr, "failed to open debug file:  %s\n",
    271 		    strerror(errno));
    272 
    273 	return (fp);
    274 }
    275