masqmail

diff src/conf.c @ 392:c5fd796ea06e

Heavy refactoring in parts of conf.c. init_conf() parse_boolean() parse_list_file() Re-arrangement of code. parse_address_glob_list() Removed unneccessary parameter. parse_list() parse_interface(): Use strtok()/strchr() instead of doing is all by hand. Removed limitation of fixed size buffer. eat_comments() Use a state machine. eat_line_trailing() eat_spaces() read_lval() Better structured code. read_conf() read_route() Removed magic numbers. Made all list type in the config files accept pathname entries, except for `permanent_routes' and `query_routes.' for which this is impossible.
author markus schnalke <meillo@marmaro.de>
date Sat, 18 Feb 2012 18:07:55 +0100
parents a408411ff8df
children 5e728dd64c1b
line diff
     1.1 --- a/src/conf.c	Sat Feb 18 17:53:04 2012 +0100
     1.2 +++ b/src/conf.c	Sat Feb 18 18:07:55 2012 +0100
     1.3 @@ -31,23 +31,21 @@
     1.4  	struct passwd *passwd;
     1.5  	struct group *group;
     1.6  
     1.7 +	if (!(passwd = getpwnam(DEF_MAIL_USER))) {
     1.8 +		fprintf(stderr, "user %s not found! (terminating)\n",
     1.9 +				DEF_MAIL_USER);
    1.10 +		exit(1);
    1.11 +	}
    1.12 +	if (!(group = getgrnam(DEF_MAIL_GROUP))) {
    1.13 +		fprintf(stderr, "group %s not found! (terminating)\n",
    1.14 +				DEF_MAIL_GROUP);
    1.15 +		exit(1);
    1.16 +	}
    1.17  	memset(&conf, 0, sizeof(masqmail_conf));
    1.18 -
    1.19  	conf.orig_uid = getuid();
    1.20  	conf.orig_gid = getgid();
    1.21 -
    1.22 -	if ((passwd = getpwnam(DEF_MAIL_USER)))
    1.23 -		conf.mail_uid = passwd->pw_uid;
    1.24 -	else {
    1.25 -		fprintf(stderr, "user %s not found! (terminating)\n", DEF_MAIL_USER);
    1.26 -		exit(1);
    1.27 -	}
    1.28 -	if ((group = getgrnam(DEF_MAIL_GROUP)))
    1.29 -		conf.mail_gid = group->gr_gid;
    1.30 -	else {
    1.31 -		fprintf(stderr, "group %s not found! (terminating)\n", DEF_MAIL_GROUP);
    1.32 -		exit(1);
    1.33 -	}
    1.34 +	conf.mail_uid = passwd->pw_uid;
    1.35 +	conf.mail_gid = group->gr_gid;
    1.36  }
    1.37  
    1.38  static gchar *true_strings[] = {
    1.39 @@ -64,96 +62,83 @@
    1.40  	gchar **str;
    1.41  
    1.42  	DEBUG(9) fprintf(stderr, "parse_boolean: %s\n", rval);
    1.43 -
    1.44 -	str = true_strings;
    1.45 -	while (*str) {
    1.46 -		if (strncasecmp(*str, rval, strlen(*str)) == 0)
    1.47 +	for (str = true_strings; *str; str++) {
    1.48 +		if (strncasecmp(*str, rval, strlen(*str))==0) {
    1.49  			return TRUE;
    1.50 -		str++;
    1.51 +		}
    1.52  	}
    1.53 -
    1.54 -	str = false_strings;
    1.55 -	while (*str) {
    1.56 -		if (strncasecmp(*str, rval, strlen(*str)) == 0)
    1.57 +	for (str = false_strings; *str; str++) {
    1.58 +		if (strncasecmp(*str, rval, strlen(*str))==0) {
    1.59  			return FALSE;
    1.60 -		str++;
    1.61 +		}
    1.62  	}
    1.63 -
    1.64  	fprintf(stderr, "cannot parse value '%s'\n", rval);
    1.65  	exit(1);
    1.66  }
    1.67  
    1.68 -/* make a list from each line in a file */
    1.69 +/*
    1.70 +** make a list from the lines of a file
    1.71 +*/
    1.72  static GList*
    1.73 -parse_list_file(gchar *fname)
    1.74 +parse_list_file(const gchar *fname)
    1.75  {
    1.76  	GList *list = NULL;
    1.77  	FILE *fptr;
    1.78 +	gchar buf[256];
    1.79  
    1.80 -	if ((fptr = fopen(fname, "rt")) == NULL) {
    1.81 -		logwrite(LOG_ALERT, "could not open %s for reading: %s\n", fname, strerror(errno));
    1.82 +	if (!(fptr = fopen(fname, "rt"))) {
    1.83 +		logwrite(LOG_ALERT, "could not open %s for reading: %s\n",
    1.84 +				fname, strerror(errno));
    1.85  		exit(1);
    1.86  	}
    1.87 -
    1.88 -	gchar buf[256];
    1.89 -
    1.90 -	while (!feof(fptr)) {
    1.91 -		fgets(buf, 255, fptr);
    1.92 -		if (buf[0] && (buf[0] != '#') && (buf[0] != '\n')) {
    1.93 -			g_strchomp(buf);
    1.94 -			DEBUG(9) fprintf(stderr,"parse_list_file: item = %s\n", buf);
    1.95 -			list = g_list_append(list, g_strdup(buf));
    1.96 +	while (!fgets(buf, sizeof buf, fptr)) {
    1.97 +		g_strstrip(buf);
    1.98 +		if (!*buf || *buf == '#') {
    1.99 +			continue;
   1.100  		}
   1.101 +		DEBUG(9) fprintf(stderr, "parse_list_file: item = %s\n", buf);
   1.102 +		list = g_list_append(list, g_strdup(buf));
   1.103  	}
   1.104  	fclose(fptr);
   1.105  
   1.106  	return list;
   1.107  }
   1.108  
   1.109 -/* given a semicolon separated string, this function makes a GList out of it. */
   1.110 -GList*
   1.111 +/*
   1.112 +** given a semicolon separated string, this function makes a GList out of it.
   1.113 +*/
   1.114 +static GList*
   1.115  parse_list(gchar *line, gboolean read_file)
   1.116  {
   1.117  	GList *list = NULL;
   1.118 -	gchar buf[256];
   1.119 -	gchar *p, *q;
   1.120 +	gchar *tok;
   1.121  
   1.122 -	DEBUG(9) fprintf(stderr, "parsing list %s, file?:%d\n", line, read_file);
   1.123 -
   1.124 -	p = line;
   1.125 -	while (*p != '\0') {
   1.126 -		q = buf;
   1.127 -
   1.128 -		while (*p && (*p != ';') && (q < buf + 255))
   1.129 -			*(q++) = *(p++);
   1.130 -		*q = '\0';
   1.131 -
   1.132 -		if ((buf[0] == '/') && (read_file))
   1.133 +	DEBUG(9) fprintf(stderr, "parsing list %s, file?:%d\n",
   1.134 +			line, read_file);
   1.135 +	for (tok = strtok(strdup(line), ";"); tok; tok = strtok(NULL, ";")) {
   1.136 +		DEBUG(9) fprintf(stderr, "item = %s\n", tok);
   1.137 +		if (read_file && *tok == '/') {
   1.138  			/* item is a filename, include its contents */
   1.139 -			list = g_list_concat(list, parse_list_file(buf));
   1.140 -		else
   1.141 +			list = g_list_concat(list, parse_list_file(tok));
   1.142 +		} else {
   1.143  			/* just a normal item */
   1.144 -			list = g_list_append(list, g_strdup(buf));
   1.145 -
   1.146 -		DEBUG(9) fprintf(stderr, "item = %s\n", buf);
   1.147 -
   1.148 -		if (*p)
   1.149 -			p++;
   1.150 +			list = g_list_append(list, g_strdup(tok));
   1.151 +		}
   1.152  	}
   1.153  	return list;
   1.154  }
   1.155  
   1.156  /*
   1.157  **  Split the addrs at '@' into local_part and domain. Without an '@'
   1.158 -**  everything is local_part. Create address structs, which are put into a
   1.159 -**  list and returned.  This funktion is used for lists of addrs containing
   1.160 -**  globbing chars (* and ?).  We don't need valid RFC821 addresses here,
   1.161 -**  just patterns to match against.
   1.162 +**  everything is local_part. Create and return a list of address structs.
   1.163 +**  This funktion is used for lists of addrs containing globbing chars
   1.164 +**  (* and ?).  We don't need valid RFC821 addresses here, just patterns
   1.165 +**  to match against.
   1.166  */
   1.167  static GList*
   1.168 -parse_address_glob_list(gchar *line, gboolean read_file)
   1.169 +parse_address_glob_list(gchar *line)
   1.170  {
   1.171 -	GList *plain_list = parse_list(line, read_file);
   1.172 +	GList *plain_list = parse_list(line, TRUE);
   1.173  	GList *node;
   1.174  	GList *list = NULL;
   1.175  
   1.176 @@ -181,7 +166,8 @@
   1.177  			addr->domain = "*";
   1.178  		}
   1.179  		list = g_list_append(list, addr);
   1.180 -		DEBUG(6) debugf("parse_address_glob_list: read pattern `%s' `%s'\n",
   1.181 +		DEBUG(6) debugf("parse_address_glob_list: "
   1.182 +				"read pattern `%s' `%s'\n",
   1.183  		                addr->local_part, addr->domain);
   1.184  		g_free(item);
   1.185  	}
   1.186 @@ -195,20 +181,20 @@
   1.187  	GList *list;
   1.188  	GList *list_node;
   1.189  	GList *res_list = NULL;
   1.190 +	gchar *item;
   1.191  
   1.192 -	list = parse_list(line, FALSE);
   1.193 +	list = parse_list(line, TRUE);
   1.194  	if (!list) {
   1.195  		return NULL;
   1.196  	}
   1.197 -
   1.198  	foreach(list, list_node) {
   1.199 -		gchar *item = (gchar *) (list_node->data);
   1.200 -		if (strcmp(item, "byname") == 0) {
   1.201 +		item = (gchar *) list_node->data;
   1.202 +		if (strcmp(item, "byname")==0) {
   1.203  			res_list = g_list_append(res_list, resolve_byname);
   1.204  #ifdef ENABLE_RESOLVER
   1.205 -		} else if (strcmp(item, "dns_a") == 0) {
   1.206 +		} else if (strcmp(item, "dns_a")==0) {
   1.207  			res_list = g_list_append(res_list, resolve_dns_a);
   1.208 -		} else if (strcmp(item, "dns_mx") == 0) {
   1.209 +		} else if (strcmp(item, "dns_mx")==0) {
   1.210  			res_list = g_list_append(res_list, resolve_dns_mx);
   1.211  #endif
   1.212  		} else {
   1.213 @@ -224,28 +210,17 @@
   1.214  static interface*
   1.215  parse_interface(gchar *line, gint def_port)
   1.216  {
   1.217 -	gchar buf[256];
   1.218 -	gchar *p, *q;
   1.219 -	interface *iface;
   1.220 +	gchar *cp;
   1.221 +	interface *iface = g_malloc(sizeof(interface));
   1.222  
   1.223  	DEBUG(9) fprintf(stderr, "parse_interface: %s\n", line);
   1.224 -
   1.225 -	p = line;
   1.226 -	q = buf;
   1.227 -	while ((*p != '\0') && (*p != ':') && (q < buf + 255))
   1.228 -		*(q++) = *(p++);
   1.229 -	*q = '\0';
   1.230 -
   1.231 -	iface = g_malloc(sizeof(interface));
   1.232 -	iface->address = g_strdup(buf);
   1.233 -
   1.234 -	if (*p) {
   1.235 -		p++;
   1.236 -		iface->port = atoi(p);
   1.237 -	} else
   1.238 -		iface->port = def_port;
   1.239 -	DEBUG(9) fprintf(stderr,"rval=%s, address:port=%s:%i\n",line, iface->address, iface->port);
   1.240 -
   1.241 +	if ((cp = strchr(line, ':'))) {
   1.242 +		*cp = '\0';
   1.243 +	}
   1.244 +	iface->address = g_strdup(line);
   1.245 +	iface->port = (cp) ? atoi(++cp) : def_port;
   1.246 +	DEBUG(9) fprintf(stderr,"found: address:port=%s:%u\n",
   1.247 +			iface->address, iface->port);
   1.248  	return iface;
   1.249  }
   1.250  
   1.251 @@ -253,30 +228,48 @@
   1.252  eat_comments(FILE *in)
   1.253  {
   1.254  	gint c;
   1.255 +	int incomment = 0;
   1.256  
   1.257 -	for (c = fgetc(in); (c == '#' || isspace(c)) && c != EOF;
   1.258 -		 c = fgetc(in)) {
   1.259 -		if (c == '#') {
   1.260 -			gint c;
   1.261 -			for (c = fgetc(in); (c != '\n') && (c != EOF); c = fgetc(in));
   1.262 +	while ((c = fgetc(in)) != EOF) {
   1.263 +		if (incomment) {
   1.264 +			/* eat until end of line */
   1.265 +			if (c == '\n') {
   1.266 +				incomment = 0;
   1.267 +				continue;
   1.268 +			} else {
   1.269 +				continue;
   1.270 +			}
   1.271 +		} else {
   1.272 +			/* eat whitespace and watch for comments */
   1.273 +			if (isspace(c)) {
   1.274 +				continue;
   1.275 +			} else if (c == '#') {
   1.276 +				incomment = 1;
   1.277 +				continue;
   1.278 +			} else {
   1.279 +				/* found something (that's not our business) */
   1.280 +				ungetc(c, in);
   1.281 +				return TRUE;
   1.282 +			}
   1.283  		}
   1.284  	}
   1.285 -	if (c == EOF)
   1.286 -		return FALSE;
   1.287 -	ungetc(c, in);
   1.288 -	return TRUE;
   1.289 +	return FALSE;
   1.290  }
   1.291  
   1.292 -/* after parsing, eat trailing character until LF */
   1.293 +/*
   1.294 +** after parsing, eat trailing characters until and including the Newline
   1.295 +*/
   1.296  static gboolean
   1.297  eat_line_trailing(FILE *in)
   1.298  {
   1.299  	gint c;
   1.300  
   1.301 -	for (c = fgetc(in); c != EOF && c != '\n'; c = fgetc(in));
   1.302 -	if (c == EOF)
   1.303 -		return FALSE;
   1.304 -	return TRUE;
   1.305 +	while ((c = fgetc(in)) != EOF) {
   1.306 +		if (c == '\n') {
   1.307 +			return TRUE;
   1.308 +		}
   1.309 +	}
   1.310 +	return FALSE;
   1.311  }
   1.312  
   1.313  static gboolean
   1.314 @@ -284,13 +277,13 @@
   1.315  {
   1.316  	gint c;
   1.317  
   1.318 -	for (c = fgetc(in); c != EOF && isspace(c); c = fgetc(in)) {
   1.319 -		/* empty */
   1.320 +	while ((c = fgetc(in)) != EOF) {
   1.321 +		if (!isspace(c)) {
   1.322 +			ungetc(c, in);
   1.323 +			return TRUE;
   1.324 +		}
   1.325  	}
   1.326 -	if (c == EOF)
   1.327 -		return FALSE;
   1.328 -	ungetc(c, in);
   1.329 -	return TRUE;
   1.330 +	return FALSE;
   1.331  }
   1.332  
   1.333  static gboolean
   1.334 @@ -300,34 +293,31 @@
   1.335  	gchar *ptr = buf;
   1.336  
   1.337  	DEBUG(9) fprintf(stderr, "read_lval()\n");
   1.338 -
   1.339 -	if (!eat_spaces(in))
   1.340 +	if (!eat_spaces(in)) {
   1.341  		return FALSE;
   1.342 +	}
   1.343  
   1.344  	c = fgetc(in);
   1.345  	DEBUG(9) fprintf(stderr, "read_lval() 2\n");
   1.346 -	while ((isalnum(c) || c == '_' || c == '-' || c == '.')
   1.347 -	       && (ptr < buf + size - 1)
   1.348 -	       && (c != EOF)) {
   1.349 -		*ptr = c;
   1.350 -		ptr++;
   1.351 -		c = fgetc(in);
   1.352 +	while (1) {
   1.353 +		if ((c = fgetc(in)) == EOF) {
   1.354 +			fprintf(stderr, "unexpected EOF after %s\n", buf);
   1.355 +			return FALSE;
   1.356 +		}
   1.357 +		if (ptr >= buf+size-1) {
   1.358 +			fprintf(stderr, "lval too long\n");
   1.359 +			break;
   1.360 +		}
   1.361 +		if (!isalnum(c) && c != '_' && c != '-' && c != '.') {
   1.362 +			break;
   1.363 +		}
   1.364 +		*ptr++ = c;
   1.365  	}
   1.366  	*ptr = '\0';
   1.367  	ungetc(c, in);
   1.368 -
   1.369 -	if (c == EOF) {
   1.370 -		fprintf(stderr, "unexpected EOF after %s\n", buf);
   1.371 -		return FALSE;
   1.372 -	} else if (ptr >= buf + size - 1) {
   1.373 -		fprintf(stderr, "lval too long\n");
   1.374 -	}
   1.375 -
   1.376  	eat_spaces(in);
   1.377 -
   1.378  	DEBUG(9) fprintf(stderr, "lval = %s\n", buf);
   1.379 -
   1.380 -	return buf[0] != '\0';
   1.381 +	return *buf != '\0';
   1.382  }
   1.383  
   1.384  static gboolean
   1.385 @@ -337,9 +327,9 @@
   1.386  	gchar *ptr = buf;
   1.387  
   1.388  	DEBUG(9) fprintf(stderr, "read_rval()\n");
   1.389 -
   1.390 -	if (!eat_spaces(in))
   1.391 +	if (!eat_spaces(in)) {
   1.392  		return FALSE;
   1.393 +	}
   1.394  
   1.395  	c = fgetc(in);
   1.396  	if (c != '\"') {
   1.397 @@ -426,7 +416,7 @@
   1.398  	}
   1.399  
   1.400  	gchar lval[256], rval[2048];
   1.401 -	while (read_statement(in, lval, 256, rval, 2048)) {
   1.402 +	while (read_statement(in, lval, sizeof lval, rval, sizeof rval)) {
   1.403  		DEBUG(9) fprintf(stderr,"read_conf(): lval=%s\n", lval);
   1.404  		if (strcmp(lval, "debug_level") == 0)
   1.405  			conf.debug_level = atoi(rval);
   1.406 @@ -459,7 +449,7 @@
   1.407  				fclose(fptr);
   1.408  			}
   1.409  		} else if (strcmp(lval, "local_hosts") == 0)
   1.410 -			conf.local_hosts = parse_list(rval, FALSE);
   1.411 +			conf.local_hosts = parse_list(rval, TRUE);
   1.412  		else if (strcmp(lval, "local_addresses") == 0)
   1.413  			conf.local_addresses = parse_list(rval, TRUE);
   1.414  		else if (strcmp(lval, "not_local_addresses") == 0)
   1.415 @@ -494,7 +484,7 @@
   1.416  			conf.pipe_fromhack = parse_boolean(rval);
   1.417  		} else if (strcmp(lval, "listen_addresses") == 0) {
   1.418  			GList *node;
   1.419 -			GList *tmp_list = parse_list(rval, FALSE);
   1.420 +			GList *tmp_list = parse_list(rval, TRUE);
   1.421  
   1.422  			conf.listen_addresses = NULL;
   1.423  			foreach(tmp_list, node) {
   1.424 @@ -517,7 +507,7 @@
   1.425  		else if (strcmp(lval, "warnmsg_file") == 0)
   1.426  			conf.warnmsg_file = g_strdup(rval);
   1.427  		else if (strcmp(lval, "warn_intervals") == 0)
   1.428 -			conf.warn_intervals = parse_list(rval, FALSE);
   1.429 +			conf.warn_intervals = parse_list(rval, TRUE);
   1.430  		else if (strcmp(lval, "max_defer_time") == 0) {
   1.431  			gint ival = time_interval(rval);
   1.432  			if (ival < 0)
   1.433 @@ -553,7 +543,7 @@
   1.434  		conf.mbox_default = g_strdup("mbox");
   1.435  
   1.436  	if (conf.warn_intervals == NULL)
   1.437 -		conf.warn_intervals = parse_list("1h;4h;8h;1d;2d;3d", FALSE);
   1.438 +		conf.warn_intervals = parse_list("1h;4h;8h;1d;2d;3d", TRUE);
   1.439  
   1.440  	if (!conf.local_hosts) {
   1.441  		char *shortname = strdup(conf.host_name);
   1.442 @@ -561,9 +551,10 @@
   1.443  		if (p) {
   1.444  			*p = '\0';
   1.445  		}
   1.446 -		/* we don't care if shortname and conf.host_name are the same */
   1.447 -		char *local_hosts_str = g_strdup_printf("localhost;%s;%s", shortname, conf.host_name);
   1.448 -		conf.local_hosts = parse_list(local_hosts_str, FALSE);
   1.449 +		/* don't care if shortname and conf.host_name are the same */
   1.450 +		char *local_hosts_str = g_strdup_printf("localhost;%s;%s",
   1.451 +				shortname, conf.host_name);
   1.452 +		conf.local_hosts = parse_list(local_hosts_str, TRUE);
   1.453  		free(shortname);
   1.454  		free(local_hosts_str);
   1.455  	}
   1.456 @@ -599,7 +590,7 @@
   1.457  	}
   1.458  
   1.459  	gchar lval[256], rval[2048];
   1.460 -	while (read_statement(in, lval, 256, rval, 2048)) {
   1.461 +	while (read_statement(in, lval, sizeof lval, rval, sizeof rval)) {
   1.462  		if (strcmp(lval, "mail_host") == 0)
   1.463  			route->mail_host = parse_interface(rval, 25);
   1.464  		else if (strcmp(lval, "helo_name") == 0)
   1.465 @@ -616,13 +607,13 @@
   1.466  			route->do_pipelining = parse_boolean(rval);
   1.467  
   1.468  		else if (strcmp(lval, "allowed_senders") == 0)
   1.469 -			route->allowed_senders = parse_address_glob_list(rval, TRUE);
   1.470 +			route->allowed_senders = parse_address_glob_list(rval);
   1.471  		else if (strcmp(lval, "denied_senders") == 0)
   1.472 -			route->denied_senders = parse_address_glob_list(rval, TRUE);
   1.473 +			route->denied_senders = parse_address_glob_list(rval);
   1.474  		else if (strcmp(lval, "allowed_recipients") == 0)
   1.475 -			route->allowed_recipients = parse_address_glob_list(rval, TRUE);
   1.476 +			route->allowed_recipients = parse_address_glob_list(rval);
   1.477  		else if (strcmp(lval, "denied_recipients") == 0)
   1.478 -			route->denied_recipients = parse_address_glob_list(rval, TRUE);
   1.479 +			route->denied_recipients = parse_address_glob_list(rval);
   1.480  
   1.481  		else if (strcmp(lval, "set_h_from_domain") == 0)
   1.482  			route->set_h_from_domain = g_strdup(rval);