libconfig patch for including files (fwd)

Matthew Hodgson matthew at mxtelecom.com
Mon Apr 26 04:44:36 EDT 2004


This seemed to disappear into the void first time, so i'll try resending
it from pine rather than thunderbird...

---------- Forwarded message ----------
Date: Thu, 22 Apr 2004 11:31:56 +0100
From: Matthew Hodgson <matthew at mxtelecom.com>
To: info-cyrus at lists.andrew.cmu.edu
Subject: libconfig patch for including files

Hi,

I have a slightly strange requirement for being able to include additional
config files in my /etc/imapd.conf.  The motivation is not because a ~60 line
imapd.conf needs abstraction to be manageable, but because includes allow
sensitive information such as plaintext MySQL passwords to reside in a
standalone file, allowing the rest of the config to be checked into a
relatively public CVS repository.  The desired effect is to go from:

sasl_sql_user: cyrus
sasl_sql_passwd: secret

to

sasl_sql_user: cyrus
include: /etc/imapd-passwd.conf

where

% cat /etc/imapd-passwd.conf
# we keep this in here to prevent it from getting checked into CVS.

sasl_sql_passwd: secret


To this end, i've shuffled the libconfig code around slightly; patch against
CVS head attached for constructive abuse, and the hope that someone else might
find it useful.

cheers,

Matthew.

-- 
______________________________________________________________
Matthew Hodgson   matthew at mxtelecom.com   Tel: +44 845 6667778
                 Systems Analyst, MX Telecom Ltd.
-------------- next part --------------
Index: libconfig.c
===================================================================
RCS file: /cvs/src/cyrus/lib/libconfig.c,v
retrieving revision 1.7
diff -u -r1.7 libconfig.c
--- libconfig.c	29 Dec 2003 20:22:55 -0000	1.7
+++ libconfig.c	22 Apr 2004 10:04:28 -0000
@@ -79,6 +79,9 @@
 extern void fatal(const char *fatal_message, int fatal_code)
    __attribute__ ((noreturn));
 
+/* prototype to allow for sane function ordering */
+void config_read_file(const char *filename);
+
 const char *config_getstring(enum imapopt opt)
 {
     assert(opt > IMAPOPT_ZERO && opt < IMAPOPT_LAST);
@@ -149,6 +152,98 @@
 
 void config_read(const char *alt_config)
 {
+    enum opttype opt = IMAPOPT_ZERO;
+    char buf[4096];
+    char *p;
+
+    /* xxx this is leaked, this may be able to be better in 2.2 (cyrus_done) */
+    if(alt_config) config_filename = xstrdup(alt_config);
+    else config_filename = xstrdup(CONFIG_FILENAME);
+
+    if(!construct_hash_table(&confighash, CONFIGHASHSIZE, 1)) {
+	fatal("could not construct configuration hash table", EC_CONFIG);
+    }
+
+    config_read_file(config_filename);
+
+    /* Check configdirectory config option */
+    if (!config_dir) {
+	fatal("configdirectory option not specified in configuration file",
+	      EC_CONFIG);
+    }
+
+    /* Scan options to see if we need to replace {configdirectory} */
+    /* xxx need to scan overflow options as well! */
+    for(opt = IMAPOPT_ZERO; opt < IMAPOPT_LAST; opt++) {
+	if(!imapopts[opt].val.s ||
+	   imapopts[opt].t != OPT_STRING ||
+	   opt == IMAPOPT_CONFIGDIRECTORY) {
+	    /* Skip options that have a NULL value, aren't strings, or
+	     * are the configdirectory option */
+	    continue;
+	}
+	
+	/* We use some magic numbers here,
+	 * 17 is the length of "{configdirectory}",
+	 * 16 is one less than that length, so that the replacement string
+	 *    that is malloced has room for the '\0' */
+	if(!strncasecmp(imapopts[opt].val.s,"{configdirectory}",17)) {
+	    const char *str = imapopts[opt].val.s;
+	    char *newstring =
+		xmalloc(strlen(config_dir) + strlen(str) - 16);
+	    char *freeme = NULL;
+	    
+	    /* we need to replace this string, will we need to free
+	     * the current value?  -- only if we've actually seen it in
+	     * the config file. */
+	    if(imapopts[opt].seen)
+		freeme = (char *)str;
+
+	    /* Build replacement string from configdirectory option */
+	    strcpy(newstring, config_dir);
+	    strcat(newstring, str + 17);
+
+	    imapopts[opt].val.s = newstring;
+
+	    if(freeme) free(freeme);
+	}
+    }
+
+    /* Look up default partition */
+    config_defpartition = config_getstring(IMAPOPT_DEFAULTPARTITION);
+    for (p = (char *)config_defpartition; *p; p++) {
+	if (!isalnum((unsigned char) *p))
+	  fatal("defaultpartition option contains non-alphanumeric character",
+		EC_CONFIG);
+	if (isupper((unsigned char) *p)) *p = tolower((unsigned char) *p);
+    }
+    if ((config_need_data & CONFIG_NEED_PARTITION_DATA) &&
+	(!config_defpartition || !config_partitiondir(config_defpartition))) {
+	snprintf(buf, sizeof(buf),
+		"partition-%s option not specified in configuration file",
+		config_defpartition);
+	fatal(buf, EC_CONFIG);
+    }
+
+    /* look up mailbox hashing */
+    config_hashimapspool = config_getswitch(IMAPOPT_HASHIMAPSPOOL);
+
+    /* are we supporting virtual domains?  */
+    config_virtdomains = config_getenum(IMAPOPT_VIRTDOMAINS);
+    config_defdomain = config_getstring(IMAPOPT_DEFAULTDOMAIN);
+
+    /* look up the hostname we should present to the user */
+    config_servername = config_getstring(IMAPOPT_SERVERNAME);
+    if (!config_servername) {
+	config_servername = xmalloc(sizeof(char) * 256);
+	gethostname((char *) config_servername, 256);
+    }
+
+    config_mupdate_server = config_getstring(IMAPOPT_MUPDATE_SERVER);
+}
+
+void config_read_file(const char *filename)
+{
     FILE *infile;
     enum opttype opt = IMAPOPT_ZERO;
     int lineno = 0;
@@ -157,24 +252,16 @@
     int service_specific;
     int idlen = (config_ident ? strlen(config_ident) : 0);
 
-    if(!construct_hash_table(&confighash, CONFIGHASHSIZE, 1)) {
-	fatal("could not construct configuration hash table", EC_CONFIG);
-    }
-
-    /* xxx this is leaked, this may be able to be better in 2.2 (cyrus_done) */
-    if(alt_config) config_filename = xstrdup(alt_config);
-    else config_filename = xstrdup(CONFIG_FILENAME);
-
     /* read in config file */
-    infile = fopen(config_filename, "r");
+    infile = fopen(filename, "r");
     if (!infile) {
 	strlcpy(buf, CYRUS_PATH, sizeof(buf));
-	strlcat(buf, config_filename, sizeof(buf));
+	strlcat(buf, filename, sizeof(buf));
 	infile = fopen(buf, "r");
     }
     if (!infile) {
 	snprintf(buf, sizeof(buf), "can't open configuration file %s: %s",
-		 config_filename, error_message(errno));
+		 filename, error_message(errno));
 	fatal(buf, EC_CONFIG);
     }
     
@@ -194,8 +281,8 @@
 	}
 	if (*p != ':') {
 	    snprintf(errbuf, sizeof(errbuf),
-		    "invalid option name on line %d of configuration file",
-		    lineno);
+		    "invalid option name on line %d of configuration file %s",
+		    lineno, filename);
 	    fatal(errbuf, EC_CONFIG);
 	}
 	*p++ = '\0';
@@ -216,6 +303,15 @@
 	
 	srvkey = NULL;
 
+	/* Look for an include statement */
+	if (!strcasecmp(key, "include")) {
+	    char *inc_filename;
+	    inc_filename = xstrdup(p);
+	    config_read_file(inc_filename);
+	    free(inc_filename);
+	    continue;		
+	}
+
 	/* Find if there is a <service>_ prefix */
 	if(config_ident && !strncasecmp(key, config_ident, idlen) 
 	   && key[idlen] == '_') {
@@ -387,79 +483,4 @@
 	}
     }
     fclose(infile);
-
-    /* Check configdirectory config option */
-    if (!config_dir) {
-	fatal("configdirectory option not specified in configuration file",
-	      EC_CONFIG);
-    }
-
-    /* Scan options to see if we need to replace {configdirectory} */
-    /* xxx need to scan overflow options as well! */
-    for(opt = IMAPOPT_ZERO; opt < IMAPOPT_LAST; opt++) {
-	if(!imapopts[opt].val.s ||
-	   imapopts[opt].t != OPT_STRING ||
-	   opt == IMAPOPT_CONFIGDIRECTORY) {
-	    /* Skip options that have a NULL value, aren't strings, or
-	     * are the configdirectory option */
-	    continue;
-	}
-	
-	/* We use some magic numbers here,
-	 * 17 is the length of "{configdirectory}",
-	 * 16 is one less than that length, so that the replacement string
-	 *    that is malloced has room for the '\0' */
-	if(!strncasecmp(imapopts[opt].val.s,"{configdirectory}",17)) {
-	    const char *str = imapopts[opt].val.s;
-	    char *newstring =
-		xmalloc(strlen(config_dir) + strlen(str) - 16);
-	    char *freeme = NULL;
-	    
-	    /* we need to replace this string, will we need to free
-	     * the current value?  -- only if we've actually seen it in
-	     * the config file. */
-	    if(imapopts[opt].seen)
-		freeme = (char *)str;
-
-	    /* Build replacement string from configdirectory option */
-	    strcpy(newstring, config_dir);
-	    strcat(newstring, str + 17);
-
-	    imapopts[opt].val.s = newstring;
-
-	    if(freeme) free(freeme);
-	}
-    }
-
-    /* Look up default partition */
-    config_defpartition = config_getstring(IMAPOPT_DEFAULTPARTITION);
-    for (p = (char *)config_defpartition; *p; p++) {
-	if (!isalnum((unsigned char) *p))
-	  fatal("defaultpartition option contains non-alphanumeric character",
-		EC_CONFIG);
-	if (isupper((unsigned char) *p)) *p = tolower((unsigned char) *p);
-    }
-    if ((config_need_data & CONFIG_NEED_PARTITION_DATA) &&
-	(!config_defpartition || !config_partitiondir(config_defpartition))) {
-	snprintf(buf, sizeof(buf),
-		"partition-%s option not specified in configuration file",
-		config_defpartition);
-	fatal(buf, EC_CONFIG);
-    }
-
-    /* look up mailbox hashing */
-    config_hashimapspool = config_getswitch(IMAPOPT_HASHIMAPSPOOL);
-
-    /* are we supporting virtual domains?  */
-    config_virtdomains = config_getenum(IMAPOPT_VIRTDOMAINS);
-    config_defdomain = config_getstring(IMAPOPT_DEFAULTDOMAIN);
-
-    /* look up the hostname we should present to the user */
-    config_servername = config_getstring(IMAPOPT_SERVERNAME);
-    if (!config_servername) {
-	config_servername = xmalloc(sizeof(char) * 256);
-	gethostname((char *) config_servername, 256);
-    }
-
-    config_mupdate_server = config_getstring(IMAPOPT_MUPDATE_SERVER);
 }


More information about the Info-cyrus mailing list