/*- * Copyright (c) 2002 Granch Ltd. All rigts reserved. * * All or some portions of this file are derived from material licensed * to the Grahcn Ltd. and are reproduced herein with the permission of * Granch Ltd. * * 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 the name of the author nor the names of any co-contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE GRANCH LTD. AND THEIR CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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. * * Author : Rashid N. Achilov E-Mail shelton@granch.ru * * @(#)parseconfig.c 0.97.3 (Granch Ltd.) 07/06/01 */ /*------------------------------------------------------------------------ Kaspersky Anti-Virus mail filter, based on libmilter API UNIX FreeBSD 4.6 version Configuration file parsing subroutine Call: void _KAV_milter_parse_config(char *cfgname); When error is occured, this subroutine will stop program! Max identifier length = 32 chars Max decimal value length - 9 valuable digits --------------------------------------------------------------------------*/ #include "kavmilter.h" #include "externals.h" #include "functions.h" void _KAV_milter_parse_config(char *cfgname) { short int i, chparm, nochparm; char *ids,*pos,*line,*buf,*bufx,*posix,*nafig,sig = 0; char **pts; int work,retcode = 0,bla; struct stat sb; // config_ent structures array, which describes parameters to parsing config // file at whole. Contains fields Name - parameter name (up to 32 chars), // Exit - processor's code, Valid - sing of validity parameter, HexMask - // to properly setup a bit-field parameter (contains a mask, which will OR'ed // with current signs byte, do not use to other types) and Which - address, // which subroutine should place parameter value (void pointer!). All string // variables should be (in structure) BEFORE all non-string (decimal, bool) // variables! struct config_ent paramConfig[] = { { "ProgramName", PROGNAME, NULL, NULL, &_KAV_milter_config.progname }, { "ProgramVersion", PROGVER, NULL, NULL, &_KAV_milter_config.progversion }, { "SendmailPipe", STDCHAR, NULL, NULL, &_KAV_milter_config.sendmail_pipe }, { "KAVPipe", STDCHAR, NULL, NULL, &_KAV_milter_config.KAV_pipe }, { "PIDFile", STDCHAR, NULL, NULL, &_KAV_milter_config.pidfile }, { "TempDirectory", STDCHAR, NULL, NULL, &_KAV_milter_config.temp_directory }, { "KAVTimeout", STDINT, NULL, NULL, &_KAV_milter_config.KAV_timeout }, { "SendmailTimeout", STDINT, NULL, NULL, &_KAV_milter_config.sendmail_timeout }, { "DebugLevel", STDINT, NULL, NULL, &_KAV_milter_config.debug_level }, { "DaemonMode", STDBOOL, NULL, 0x1, &_KAV_milter_config._idflags }, { "InfectedAction", INFPARAM, NULL, NULL, &_KAV_milter_config._idflags }, { "Null", NULL, NULL, NULL, NULL }, }; // Initial values to non-char parameters _KAV_milter_config.KAV_timeout = 0; _KAV_milter_config.sendmail_timeout = 0; _KAV_milter_config.debug_level = 0; // Detect quantity of parameters, quantity of string and non-string // parameters to memory allocation for(i = chparm = nochparm = 0; paramConfig[i].exit != NULL;i++) if (paramConfig[i].exit == STDCHAR) chparm++; else nochparm++; // Allocate memory to config file string variables and local area if ((_KAV_milter_config.progname = (char *) calloc((MAXLEN * (chparm + MANDFIELDS)), 1))==NULL) { fprintf(stderr,"malloc error, out of memory : %s\n",strerror(errno)); _KAV_milter_close(EX_TEMPFAIL); } // Allocation memory to all local and string-variables-config-file areas // Allocation done from 'ids' through 'nafig' and than all string-variables // (if any). for(i = 0, pts = &_KAV_milter_config.progversion, bufx = _KAV_milter_config.progname + MAXLEN; i < (chparm + MANDFIELDS - 1);i++, pts++, bufx += MAXLEN) *pts = bufx; _flags._alloc_config = OK; // Allocating workspace ids = (char *) malloc(MAXLEN + 2); nafig = ids + MAXLEN; // Open config file if ((work = open(cfgname,O_RDONLY)) > 0) { stat(cfgname,&sb); bufx = (char *) malloc(sb.st_size * 2); buf = bufx + sb.st_size; read(work,bufx,sb.st_size); // Fucked Feof()! close(work); // Now we drop lines with comment char at first position and strip spaces. // After this procedure in output buffer lies only name=value pairs, separa- // ted by '\n' char if ((bla = readconfig('#',bufx,buf,sb.st_size)) == ERR) { fprintf(stderr,"cannot read configuration file %s\n",cfgname); free(ids); _KAV_milter_close(EX_TEMPFAIL); } // Reading filtered buffer line-by-line. Now we search '\n' char and at each // loop round shift position on 1 greater than searched position. Loop stops // when length filtered buffer will be exhausted. for(line = buf;(line - buf) < bla;line = posix + 1,sig = NULL) { posix = strchr(line,'\n'); // Search '=' char and taking string BEFORE it as parameter name pos = strchr(line,'='); bzero(ids,32); strncpy(ids, line, pos - line); // Search in config file parameters array this parameter. Search stops when // parameter will be found or parameters quantity will be expired. When // search flag is on, search terminate immediately. for(i = 0;(i < (chparm + nochparm)) && (!sig);i++) if (!(strcmp(ids,paramConfig[i].name))) { switch(paramConfig[i].exit) { // Main loop. Switch by processor type. Processor type STDCHAR processed // string value through copying it to address from configParam[i].which // pointer. Length of copying string calculated as difference between // '\n' char and '=' char (and less to 1). Processor type STDINT processed // digital values in signed short int format (up to 32767) through storing // to address in paramConfig[i].which pointer a value, started from '=' // (greather to 1). case STDINT: if ((*(short *) paramConfig[i].which = b_atoi(pos + 1, SSMAX)) >= NO) sig = paramConfig[i].valid = OK; else paramConfig[i].valid = ERR; continue; case STDCHAR: strncpy(*((char **) paramConfig[i].which), pos + 1,posix - pos - 1); sig = paramConfig[i].valid = OK; continue; case STDBOOL: bzero(nafig,4); strncpy(nafig,pos+1,posix-pos-1); if (!strcasecmp(nafig,"YES")) *((char *) paramConfig[i].which) ^= paramConfig[i].hexmask; sig = paramConfig[i].valid = OK; continue; case INFPARAM: bzero(nafig,8); strncpy(nafig,pos+1,posix-pos-1); if (!strcasecmp(nafig,"reject")) *((char *) paramConfig[i].which) ^= 0x2; else *((char *) paramConfig[i].which) ^= 0x4; sig = paramConfig[i].valid = OK; continue; default: fprintf(stderr,"unknown processor exit code %d\n", paramConfig[i].exit); free(ids); _KAV_milter_close(EX_TEMPFAIL); } } } free(bufx); // Check on validity parameters processing for(i = 0;i < (chparm + nochparm);i++) { // Store mandatory fields, can missed in config file if (!(strcmp(paramConfig[i].name,"ProgramName"))) { strncpy(*((char **) paramConfig[i].which), kavfilter.xxfi_name,strlen(kavfilter.xxfi_name)); paramConfig[i].valid = OK; } if (!(strcmp(paramConfig[i].name,"ProgramVersion"))) { sprintf(*((char **) paramConfig[i].which), "%1d.%2d.%1d",VERSION_MAJOR,VERSION_MINOR,VERSION_PATCH); paramConfig[i].valid = OK; } // Checkout all parsed fields if (paramConfig[i].valid == NO) { fprintf(stderr, "parameter %s invalid: %s\n", paramConfig[i].name, (char *) paramConfig[i].which); retcode = ERR; } } // When errors in split config file were detected, stop processing if (retcode == ERR) { fprintf(stderr, "config file split error detected. %s aborted\n",progname); free(ids); _KAV_milter_close(EX_TEMPFAIL); } } // Specified configuration file didn't found else { fprintf(stderr,"opening file %s error: %s\n",cfgname,strerror(errno)); _KAV_milter_close(EX_TEMPFAIL); } // Free allocated workspace free(ids); }