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 2007 Sun Microsystems, Inc.  All rights reserved.
     23  * Use is subject to license terms.
     24  */
     25 #pragma ident	"%Z%%M%	%I%	%E% SMI"
     26 /*
     27  * get audit control info (replaces getacinfo.c)
     28  */
     29 
     30 #include <secdb.h>
     31 #include <stdio.h>
     32 #include <sys/types.h>
     33 #include <bsm/audit.h>
     34 #include <bsm/libbsm.h>
     35 #include <stdlib.h>
     36 #include <string.h>
     37 #include <synch.h>
     38 
     39 #define	REALLY_LONG_LINE 8192
     40 
     41 #define	FILE_AT_START 0	/* file pointer is at file start or file is closed */
     42 #define	FILE_MIDDLE 1	/* file pointer is not at file start */
     43 
     44 #define	LEN 360		/* arbitrary audit control entry length */
     45 
     46 #define	SUCCESS 0
     47 #define	EOF_WARN 1
     48 #define	REW_WARN 2
     49 #define	EOF_ERR -1
     50 #define	ERROR   -2
     51 #define	FORMAT_ERR -3
     52 #define	NO_CONTEXT -4
     53 
     54 /*
     55  * libbsm.h has opaque typedef:  typedef struct au_acinfo au_acinfo_t
     56  */
     57 struct au_acinfo {
     58 	char	*file;
     59 	FILE	*fp;
     60 	int	file_pointer;
     61 	int	once_read;
     62 };
     63 
     64 static char	*MINLABEL	= "minfree:";
     65 static char	*DIRLABEL	= "dir:";
     66 static char	*DEFFLGLABEL	= "flags:";
     67 static char	*NAFLGLABEL	= "naflags:";
     68 static char	*lib_label	= "plugin:";
     69 
     70 /*
     71  * get extended line, i.e., interpret trailing "\" and join to make
     72  * a single line.  Returns NULL on error or EOF, else returns its
     73  * input pointer.  A line containing only "\" and some blanks is valid.
     74  *
     75  * doesn't handle a comment line embedded in a series of continued lines.
     76  */
     77 
     78 static char *
     79 getlongline(char *line, int length, FILE *fp)
     80 {
     81 	int	keepgoing = 1;
     82 	int	partcount = 0;
     83 	char	*l, *b;
     84 	int	end = 0;
     85 
     86 	l = line;
     87 	while (keepgoing) {
     88 		if (fgets(l, length, fp) != NULL) {
     89 			partcount++;
     90 			end = strlen(l);
     91 			b = l + end - 2;	/* last char before \n */
     92 			*(b + 1) = '\0';	/* chop the \n */
     93 			keepgoing = 0;
     94 			while (b >= l) {
     95 				if (*b == '\\') {
     96 					keepgoing = 1;
     97 					l = b;
     98 					length -= (end - 1);
     99 					break;
    100 				} else if (*b != ' ')
    101 					break;
    102 				end--;
    103 				b--;
    104 			}
    105 		} else
    106 			keepgoing = 0;
    107 	}
    108 	if (partcount > 0)
    109 		return (line);
    110 	else
    111 		return (NULL);
    112 }
    113 
    114 /*
    115  * input a string of the form   attr: xxxxx{\n}
    116  * and return xxxxx with leading, internal, and trailing blanks removed
    117  */
    118 
    119 static int
    120 getvalue(char *out_buf, char *line, char *attr_name, int out_len)
    121 {
    122 	int	attr_length, value_length;
    123 	char	*bp, *cp;
    124 	int	retstat = SUCCESS;
    125 
    126 	attr_length = (int)strlen(attr_name);
    127 	value_length = (int)strlen(line);
    128 
    129 	if (strncmp(line, attr_name, attr_length) == 0) {
    130 		/*
    131 		 * allow zero or more blanks
    132 		 * between colon and rest of line
    133 		 */
    134 		value_length -= attr_length;
    135 
    136 		bp = line + attr_length;
    137 		while (*bp == ' ') {
    138 			value_length--;
    139 			attr_length++; /* offset to first non-blank */
    140 			bp++;
    141 		}
    142 		cp = bp;
    143 		while (*bp != '\0') {
    144 			if (*bp == ' ') {
    145 				bp++;
    146 				value_length--;
    147 			} else {
    148 				*cp++ = *bp++;
    149 			}
    150 		}
    151 		*cp = '\0';
    152 
    153 		if (value_length < 1) {
    154 			*out_buf = '\0';
    155 			return (retstat);
    156 		}
    157 		if ((retstat == SUCCESS) &&
    158 		    (strlcpy(out_buf, line + attr_length, out_len) >=
    159 		    out_len))
    160 			retstat = FORMAT_ERR;
    161 	} else
    162 		retstat = FORMAT_ERR;
    163 
    164 	return (retstat);
    165 }
    166 
    167 /*
    168  * getacval.c  -  get audit control info
    169  *
    170  *	_getacdir() - get audit control directories, one at a time
    171  *	_getacflg() - get audit control default audit flags
    172  *	_getacmin() - get audit control directory min. fill value
    173  *	_getacna()  - get audit control non-attrib audit flags
    174  *	_getacplug() - get audit control remote host and associated data
    175  *	_openac()  - open the audit control file
    176  *	_endac()    -  close the audit control file
    177  */
    178 
    179 /*
    180  * _getacdir() - get audit control directories, one at a time
    181  *
    182  * input: len  - size of dir buffer
    183  *
    184  * output: dir - directory string
    185  *
    186  * returns:	0 - entry read ok
    187  *		-1 - end of file
    188  *		-2 - error - can't open audit control file for read
    189  *		-3 - error - directory entry format error
    190  *		2 - directory search started from beginning again
    191  *
    192  * notes: It is the responsibility of the calling function to
    193  * 		check the status of the directory entry.
    194  */
    195 
    196 int
    197 _getacdir(au_acinfo_t *context, char *dir, int len)
    198 {
    199 	int	retstat = SUCCESS, gotone = 0;
    200 	char	*entry;
    201 
    202 	if (context == NULL)
    203 		return (NO_CONTEXT);
    204 
    205 	entry = malloc(REALLY_LONG_LINE);
    206 	if (entry == NULL)
    207 		return (ERROR);
    208 
    209 	if ((context->file_pointer != FILE_AT_START) &&
    210 	    (context->once_read == 1)) {
    211 		retstat = REW_WARN;
    212 		_rewindac(context);
    213 	} else {
    214 		context->once_read = 1;
    215 		context->file_pointer = FILE_AT_START;
    216 	}
    217 	if (retstat >= SUCCESS) do {
    218 		if (getlongline(entry, REALLY_LONG_LINE, context->fp) != NULL) {
    219 			if (*entry == 'd') {
    220 				retstat = getvalue(dir, entry, DIRLABEL, len);
    221 				if (retstat == SUCCESS) {
    222 					if (strlen(dir) == 0) {
    223 						retstat = FORMAT_ERR;
    224 					} else {
    225 						gotone = 1;
    226 					}
    227 				}
    228 			}
    229 		} else if ((feof(context->fp)) == 0) {
    230 			retstat = ERROR;
    231 		} else {
    232 			retstat = EOF_ERR;
    233 		}
    234 	} while (gotone == 0 && retstat >= SUCCESS);
    235 
    236 	free(entry);
    237 	return (retstat);
    238 }
    239 
    240 
    241 /*
    242  * _getacmin() - get audit control directory min. fill value
    243  *
    244  * output: min_val - percentage of directory fill allowed
    245  *
    246  * returns:	0 - entry read ok
    247  *		1 - end of file
    248  *		-2 - error; errno contains error number
    249  *		-3 - error - directory entry format error
    250  */
    251 
    252 int
    253 _getacmin(au_acinfo_t *context, int *min_val)
    254 {
    255 	int	retstat = SUCCESS, gotone = 0;
    256 
    257 	char	entry[LEN];
    258 	char	value[LEN];
    259 
    260 	if (context == NULL)
    261 		return (NO_CONTEXT);
    262 
    263 	_rewindac(context);
    264 
    265 	if (retstat == SUCCESS) do {
    266 		if (getlongline(entry, LEN, context->fp) != NULL) {
    267 			if (*entry == 'm') {
    268 				retstat = getvalue(value, entry, MINLABEL,
    269 				    5);	/* sb 2 digits, allow more */
    270 				if (retstat == SUCCESS) {
    271 					gotone = 1;
    272 					*min_val = (int)strtol(value, NULL, 10);
    273 					if ((*min_val == 0) && (errno != 0))
    274 						retstat = FORMAT_ERR;
    275 				}
    276 			}
    277 		} else if ((feof(context->fp)) == 0)
    278 			retstat = ERROR;
    279 		else
    280 			retstat = EOF_WARN;
    281 
    282 	} while (gotone == 0 && retstat == SUCCESS);
    283 
    284 	if (context->file_pointer == FILE_AT_START)
    285 		context->file_pointer = FILE_MIDDLE;
    286 	else
    287 		_rewindac(context);
    288 
    289 	return (retstat);
    290 }
    291 
    292 
    293 /*
    294  * _getacflg() - get audit control flags
    295  *
    296  * output: auditstring - character representation of system audit flags
    297  *
    298  * returns:	0 - entry read ok
    299  *		1 - end of file
    300  *		-2 - error - errno contains error number
    301  *		-3 - error - directory entry format error
    302  */
    303 
    304 int
    305 _getacflg(au_acinfo_t *context, char *auditstring, int len)
    306 {
    307 	int	retstat = SUCCESS, gotone = 0;
    308 	char	*entry;
    309 
    310 	if (context == NULL)
    311 		return (NO_CONTEXT);
    312 
    313 	entry = malloc(REALLY_LONG_LINE);
    314 	if (entry == NULL)
    315 		return (ERROR);
    316 
    317 	_rewindac(context);
    318 
    319 	if (retstat == SUCCESS) do {
    320 		if (getlongline(entry, REALLY_LONG_LINE, context->fp) != NULL) {
    321 			if (*entry == 'f') {
    322 				retstat = getvalue(auditstring, entry,
    323 				    DEFFLGLABEL, len);
    324 				if (retstat == SUCCESS)
    325 					gotone = 1;
    326 			}
    327 		} else if ((feof(context->fp)) == 0) {
    328 			retstat = ERROR;
    329 		} else {
    330 			retstat = EOF_WARN;
    331 		}
    332 	} while (gotone == 0 && retstat == SUCCESS);
    333 
    334 	if (context->file_pointer == FILE_AT_START)
    335 		context->file_pointer = FILE_MIDDLE;
    336 	else
    337 		_rewindac(context);
    338 
    339 	free(entry);
    340 	return (retstat);
    341 }
    342 
    343 
    344 /*
    345  * _getacna() - get audit flags for non-attributable (server) events
    346  *
    347  * output: auditstring - character representation of system audit flags
    348  *
    349  * returns:	0 - entry read ok
    350  *		1 - end of file
    351  *		-2 - error - errno contains error number
    352  *		-3 - error - directory entry format error
    353  */
    354 
    355 int
    356 _getacna(au_acinfo_t *context, char *auditstring, int len)
    357 {
    358 	int	retstat = SUCCESS, gotone = 0;
    359 	char	*entry;
    360 
    361 	entry = malloc(REALLY_LONG_LINE);
    362 	if (entry == NULL)
    363 		return (ERROR);
    364 
    365 	_rewindac(context);
    366 
    367 	if (retstat == SUCCESS) do {
    368 		if (getlongline(entry, REALLY_LONG_LINE, context->fp) != NULL) {
    369 			if (*entry == 'n') {
    370 				retstat = getvalue(auditstring, entry,
    371 				    NAFLGLABEL, len);
    372 				if (retstat == SUCCESS)
    373 					gotone = 1;
    374 			}
    375 		} else if ((feof(context->fp)) == 0) {
    376 			retstat = ERROR;
    377 		} else {
    378 			retstat = EOF_WARN;
    379 		}
    380 	/* end of if-do */
    381 	} while (gotone == 0 && retstat == SUCCESS);
    382 
    383 	if (context->file_pointer == FILE_AT_START)
    384 		context->file_pointer = FILE_MIDDLE;
    385 	else
    386 		_rewindac(context);
    387 
    388 	free(entry);
    389 	return (retstat);
    390 }
    391 
    392 /*
    393  * _getacplug() - get plugin parameter line
    394  *
    395  * As with _getacdir, the caller is responsible for checking the
    396  * validity of what's returned.
    397  *
    398  * outputs:	keyvalue list (call _kva_free(list_ptr) when you're done with
    399  *		it.)
    400  *
    401  * returns:	SUCCESS - entry read ok
    402  *		EOF_WARN - end of file
    403  *		REW_WARN - started over at the start of file
    404  *		ERROR - error - errno contains error number
    405  *		FORMAT_ERROR - fat finger failure
    406  */
    407 #define	MAX_ARG	256
    408 
    409 int
    410 _getacplug(au_acinfo_t *context, kva_t **kv_list)
    411 {
    412 	int	retstat = SUCCESS, got_one = 0;
    413 	char	entry[REALLY_LONG_LINE];
    414 	char	value[REALLY_LONG_LINE];
    415 
    416 	if (context == NULL)
    417 		return (NO_CONTEXT);
    418 
    419 	if (context->file_pointer != FILE_AT_START && context->once_read == 1) {
    420 		retstat = REW_WARN;
    421 		_rewindac(context);
    422 	} else {
    423 		context->once_read = 1;
    424 		context->file_pointer = FILE_AT_START;
    425 	}
    426 
    427 	if (retstat == SUCCESS) do {
    428 		if (getlongline(entry, REALLY_LONG_LINE, context->fp) != NULL) {
    429 			if (*entry == 'p') {
    430 				retstat = getvalue(value, entry, lib_label,
    431 				    REALLY_LONG_LINE);
    432 				if (retstat == SUCCESS)
    433 					got_one = 1;
    434 			}
    435 		} else if ((feof(context->fp)) == 0) {
    436 			retstat = ERROR;
    437 		} else {
    438 			retstat = EOF_WARN;
    439 		}
    440 		/* end of if-do */
    441 	} while ((got_one == 0) && (retstat == SUCCESS));
    442 
    443 	/* value contains a list of attribute/value pairs */
    444 	if (got_one) {
    445 		*kv_list = _str2kva(value, "=", ";");
    446 		if (*kv_list == NULL)
    447 			retstat = FORMAT_ERR;
    448 	} else {
    449 		retstat = EOF_WARN;
    450 		*kv_list = NULL;
    451 	}
    452 lib_exit:
    453 
    454 	return (retstat);
    455 }
    456 
    457 /* rewind the audit control file */
    458 void
    459 _rewindac(au_acinfo_t *context)
    460 {
    461 	rewind(context->fp);
    462 	context->file_pointer = FILE_AT_START;
    463 	context->once_read = 0;
    464 }
    465 
    466 /*
    467  * _openac() open either the audit_control file or an alternate.
    468  * A NULL input means use the real audit_control.
    469  */
    470 
    471 au_acinfo_t *
    472 _openac(char *filepath)
    473 {
    474 	au_acinfo_t	*context;
    475 
    476 	if (filepath == NULL)
    477 		filepath = AUDITCONTROLFILE;
    478 
    479 	context = malloc(sizeof (au_acinfo_t));
    480 	if (context == NULL)
    481 		return (NULL);
    482 
    483 	context->file = strdup(filepath);
    484 	if (filepath == NULL) {
    485 		free(context);
    486 		return (NULL);
    487 	}
    488 	context->fp = fopen(filepath, "rF");
    489 	if (context->fp == NULL) {
    490 		free(context->file);
    491 		free(context);
    492 		return (NULL);
    493 	}
    494 	context->file_pointer = FILE_AT_START;
    495 	context->once_read = 0;
    496 	return (context);
    497 }
    498 
    499 /* close the audit control file */
    500 void
    501 _endac(au_acinfo_t *context)
    502 {
    503 	if (context == NULL)
    504 		return;
    505 
    506 	if (context->fp != NULL)
    507 		(void) fclose(context->fp);
    508 
    509 	free(context->file);
    510 	free(context);
    511 }
    512