/*
**
** Copyright (c) 2002,2003 Dave McMurtrie
** Copyright (c) 2004 Martin Blapp
**
** This file is part of pop3proxy, a descendant of Dave McMurtrie's pop3proxy.
**
** pop3proxy is free software; you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation; either version 2 of the License, or
** (at your option) any later version.
**
** pop3proxy is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with pop3proxy; if not, write to the Free Software
** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
**
**
** Facility:
**
** config.c
**
** Abstract:
**
** Routines for parsing a config file and setting global configuration
** options.
**
** Authors:
**
** Dave McMurtrie <davemcmurtrie@hotmail.com>
**
** RCS:
**
** $Source: /afs/pitt.edu/usr12/dgm/work/IMAP_Proxy/src/RCS/config.c,v $
** $Id: config.c,v 1.8 2003/10/23 06:18:58 dgm Exp $
**
** Modification History:
**
** $Log: config.c,v $
** Revision 1.8 2003/10/23 06:18:58 dgm
** Fixed bug in SetBooleanValue doing upcase of Value.
**
** Revision 1.7 2003/10/09 12:36:08 dgm
** Added the ability to set boolean configuration options.
**
** Revision 1.6 2003/05/20 18:42:04 dgm
** comment changes only.
**
** Revision 1.5 2003/05/06 12:10:37 dgm
** Applied patches by Ken Murchison to include additional config options
** for SSL support.
**
** Revision 1.4 2003/04/16 12:13:34 dgm
** Added commodore logo ascii-art comment at the end.
** Added support for syslog configuration options.
**
** Revision 1.3 2003/02/17 14:08:42 dgm
** added an fclose() that I forgot.
**
** Revision 1.2 2003/01/27 13:59:15 dgm
** Patch by Gary Mills <mills@cc.UManitoba.CA> to allow compilation
** using Sun's cc instead of gcc.
**
** Revision 1.1 2002/12/17 14:26:49 dgm
** Initial revision
**
**
*/
#define _REENTRANT
#define MAX_KEYWORD_LEN 128
#include <errno.h>
#include <string.h>
#include <strings.h>
#include <syslog.h>
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
#include "common.h"
#include "pop3proxy.h"
/*
* External globals
*/
extern ProxyConfig_Struct PC_Struct;
/*
* Internal prototypes
*/
static void SetStringValue( char *, char **, unsigned int );
static void SetNumericValue( char *, int *, unsigned int );
static void SetBooleanValue( char *, unsigned int *, unsigned int );
/*
* An array of Config_Structs will need to be allocated, one for
* every possible keyword/value combination (plus a NULL). Note that
* I declare an array of 100, meaning that there's a hard limit of 99
* possible config values right now. Currently, there are only 9 in use.
*/
struct Config_Struct
{
char Keyword[MAX_KEYWORD_LEN]; /* The configuration keyword */
void (*(SetFunction))(); /* ptr to function used to set the value */
void *StorageAddress; /* address to store the value */
};
struct Config_Struct ConfigTable[ 100 ];
/*
* Macro to populate the above ConfigTable
*/
#define ADD_TO_TABLE( KEYWORD, SETFUNCTION, STA, INDEX ) \
strncpy( ConfigTable[ INDEX ].Keyword, KEYWORD, MAX_KEYWORD_LEN -1 ); \
ConfigTable[ INDEX ].SetFunction = SETFUNCTION; \
ConfigTable[ INDEX ].StorageAddress = STA; \
INDEX++;
/*++
* Function: SetStringValue
*
* Purpose: Common routine to assign string values in the config
* options struct.
*
* Parameters: ptr to string from config file
* ptr to char ptr for dynamically allocated storage for string.
* int -- line of config file where the string was read from.
*
* Returns: nada -- exit()s on errors.
*
* Authors: Dave McMurtrie <davemcmurtrie@hotmail.com>
*
* Notes:
*--
*/
static void SetStringValue( char *String,
char **SavedString,
unsigned int linenum )
{
char *fn = "SetStringValue()";
unsigned int Size;
Size = strlen( String ) + 1;
/*
* Do some reasonable bounds checking before we malloc()
*/
if ( ( Size < 1 ) || ( Size > 4096 ) )
{
syslog( LOG_ERR, "%s: Length of string value at line %d of config file is not within size boundaries -- Exiting.", fn, linenum );
exit( 1 );
}
*SavedString = malloc( Size );
if ( ! *SavedString )
{
syslog( LOG_ERR, "%s: malloc() failed: %s -- Exiting.", fn,
strerror( errno ) );
exit( 1 );
}
memcpy( *SavedString, String, Size );
return;
}
/*++
* Function: SetNumericValue
*
* Purpose: Common routine to convert an ascii string to a numeric value
* and set a config value accordingly.
*
* Parameters: ptr to the string value to convert.
* ptr to int. (where to store the converted value)
* int -- line of config file where the string was read from.
*
* Returns: nada -- exit()s on failure.
*
* Authors: Dave McMurtrie <davemcmurtrie@hotmail.com>
*
* Notes:
*--
*/
static void SetNumericValue( char *StringValue,
int *Value,
unsigned int linenum )
{
char *fn = "SetNumericValue()";
/*
* Need to generalize this routine. atoi() seems to only set errno
* on Solaris, making this very platform specific.
*/
*Value = atoi( (const char *)StringValue );
if ( ( ! *Value ) &&
( errno == EINVAL ) )
{
syslog( LOG_ERR, "%s: numeric value specified at line %d of config file is invalid -- Exiting.", fn, linenum );
exit( 1 );
}
return;
}
/*++
* Function: SetBooleanValue
*
* Purpose: Common routine to assign true/false (or yes/no) values in
* the config options struct.
*
* Parameters: ptr to string value from configfile (yes, no, true, false)
* ptr to unsigned int -- where to store the boolean value (1/0)
* unsigned int -- Config file line number
*
* Returns: nada -- exit()s on errors.
*
* Authors: Dave McMurtrie <davemcmurtrie@hotmail.com>
*
* Notes: This function is not case sensitive.
* It will parse any of y, yes, true and store it as 1.
* It will parse any of n, no, false and store it as 0.
*
* Major note -- the Value passed into here will be upcased.
*--
*/
static void SetBooleanValue( char *Value,
unsigned int *StoredValue,
unsigned int linenum )
{
char *fn = "SetBooleanValue()";
char *CP;
/*
* Upcase for ease of comparison
*/
CP = Value;
while( *CP )
{
*CP = toupper( *CP );
CP++;
}
if ( ( ( Value[0] == 'Y' ) && ( Value[1] == '\0' ) ) ||
( ( Value[0] == 'Y' ) && ( Value[1] == 'E' ) && ( Value[2] == 'S' ) ) )
{
*StoredValue = 1;
return;
}
if ( ( ( Value[0] == 'N' ) && ( Value[1] == '\0' ) ) ||
( ( Value[0] == 'N' ) && ( Value[1] == 'O' ) ) )
{
*StoredValue = 0;
return;
}
if ( !strcmp( "TRUE", Value ) )
{
*StoredValue = 1;
return;
}
if ( !strcmp( "FALSE", Value ) )
{
*StoredValue = 0;
return;
}
syslog( LOG_WARNING, "%s: Invalid boolean value '%s' specified at line %d of config file. Defaulting to FALSE.", fn, Value, linenum );
*StoredValue = 0;
return;
}
/*++
* Function: SetConfigOptions
*
* Purpose: Set global configuration options by reading and parsing
* the configuration file.
*
* Parameters: char pointer to config filename path.
*
* Returns: nada. exit()s on any error.
*
* Authors: Dave McMurtrie <davemcmurtrie@hotmail.com>
*
* Notes: Sets values in global ProxyConfig_Struct PC_Struct.
*--
*/
extern void SetConfigOptions( char *ConfigFile )
{
FILE *FP;
char *fn = "SetConfigOptions()";
char Buffer[1024];
unsigned int LineNumber;
unsigned int index;
unsigned int i;
char *CP;
char *Keyword;
char *Value;
index = LineNumber = 0;
/*
* initialize the proxy config struct
*/
memset( &PC_Struct, 0, sizeof PC_Struct );
/*
* Build our config option table.
*/
ADD_TO_TABLE( "server_hostname", SetStringValue,
&PC_Struct.server_hostname, index );
ADD_TO_TABLE( "listen_port", SetNumericValue,
&PC_Struct.listen_port, index );
ADD_TO_TABLE( "server_port", SetNumericValue,
&PC_Struct.server_port, index );
ADD_TO_TABLE( "cache_size", SetNumericValue,
&PC_Struct.cache_size, index );
ADD_TO_TABLE( "cache_expiration_time", SetNumericValue,
&PC_Struct.cache_expiration_time, index );
ADD_TO_TABLE( "proc_username", SetStringValue,
&PC_Struct.proc_username, index );
ADD_TO_TABLE( "proc_groupname", SetStringValue,
&PC_Struct.proc_groupname, index );
ADD_TO_TABLE( "stat_filename", SetStringValue,
&PC_Struct.stat_filename, index );
ADD_TO_TABLE( "syslog_facility", SetStringValue,
&PC_Struct.syslog_facility, index );
ADD_TO_TABLE( "protocol_log_filename", SetStringValue,
&PC_Struct.protocol_log_filename, index );
ADD_TO_TABLE( "syslog_prioritymask", SetStringValue,
&PC_Struct.syslog_prioritymask, index );
ADD_TO_TABLE( "tls_ca_file", SetStringValue,
&PC_Struct.tls_ca_file, index );
ADD_TO_TABLE( "tls_ca_path", SetStringValue,
&PC_Struct.tls_ca_path, index );
ADD_TO_TABLE( "tls_cert_file", SetStringValue,
&PC_Struct.tls_cert_file, index );
ADD_TO_TABLE( "tls_key_file", SetStringValue,
&PC_Struct.tls_key_file, index );
ADD_TO_TABLE( "send_tcp_keepalives", SetBooleanValue,
&PC_Struct.send_tcp_keepalives, index );
ConfigTable[index].Keyword[0] = '\0';
FP = fopen( ConfigFile, "r" );
if ( !FP )
{
syslog(LOG_ERR, "%s: Unable to open config file '%s': %s -- Exiting",
fn, ConfigFile, strerror( errno ) );
exit( 1 );
}
for ( ;; )
{
if ( !fgets( Buffer, sizeof Buffer, FP ) )
break;
LineNumber++;
/*
* Nullify comments, and CRLFs
*/
CP = strchr( Buffer, '#' );
if ( CP ) *CP = 0;
CP = strchr( Buffer, '\n' );
if ( CP ) *CP = 0;
CP = strchr( Buffer, '\r' );
if ( CP ) *CP = 0;
/*
* Any line that started with a comment or CRLF, we'll
* skip.
*/
if ( !strlen( Buffer ) )
continue;
CP = strtok( Buffer, " " );
if ( !CP )
{
syslog(LOG_ERR, "%s: parse error reading config file at line %d. Exiting.", fn, LineNumber );
exit( 1 );
}
Keyword = CP;
CP = strtok( NULL, " " );
if ( !CP )
{
syslog(LOG_ERR, "%s: parse error reading config file at line %d. Exiting.", fn, LineNumber );
exit( 1 );
}
Value = CP;
for (i = 0; ConfigTable[i].Keyword[0] != '\0'; i++ )
{
if ( ! strcasecmp( (const char *)Keyword, ConfigTable[i].Keyword ) )
{
( ConfigTable[i].SetFunction )( Value,
ConfigTable[i].StorageAddress,
LineNumber );
break;
}
}
/*
* If we get here and we're at our NULL value at the end of our
* keyword array, we cycled through the entire array and never
* matched any keyword.
*/
if ( ! ConfigTable[i].Keyword )
{
syslog( LOG_ERR, "%s: unknown keyword '%s' found at line %d of config file -- Exiting.", fn, Keyword, LineNumber );
exit( 1 );
}
}
fclose( FP );
}
/*
* _________
* / |
* / |
* / ______|
* / / ________
* | | | /
* | | |_____/
* | | ______
* | | | \
* | | |______\
* \ \_______
* \ |
* \ |
* \_________|
*/
syntax highlighted by Code2HTML, v. 0.9.1