xref: /freebsd/contrib/dma/conf.c (revision 3bdf775801b218aa5a89564839405b122f4b233e)
1 /*
2  * Copyright (c) 2008 The DragonFly Project.  All rights reserved.
3  *
4  * This code is derived from software contributed to The DragonFly Project
5  * by Matthias Schmidt <matthias@dragonflybsd.org>, University of Marburg,
6  * Germany.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in
16  *    the documentation and/or other materials provided with the
17  *    distribution.
18  * 3. Neither the name of The DragonFly Project nor the names of its
19  *    contributors may be used to endorse or promote products derived
20  *    from this software without specific, prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
26  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
27  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
28  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
30  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
31  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
32  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33  * SUCH DAMAGE.
34  */
35 
36 #include <err.h>
37 #include <errno.h>
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <syslog.h>
42 #include <stdarg.h>
43 
44 #include "dma.h"
45 
46 #define DP	": \t"
47 #define EQS	" \t"
48 
49 
50 /*
51  * Remove trailing \n's
52  */
53 void
54 trim_line(char *line)
55 {
56 	size_t linelen;
57 	char *p;
58 
59 	if ((p = strchr(line, '\n')))
60 		*p = (char)0;
61 
62 	/* Escape leading dot in every case */
63 	linelen = strlen(line);
64 	if (line[0] == '.') {
65 		if ((linelen + 2) > 1000) {
66 			syslog(LOG_CRIT, "Cannot escape leading dot.  Buffer overflow");
67 			exit(1);
68 		}
69 		memmove((line + 1), line, (linelen + 1));
70 		line[0] = '.';
71 	}
72 }
73 
74 static void
75 chomp(char *str)
76 {
77 	size_t len = strlen(str);
78 
79 	if (len == 0)
80 		return;
81 	if (str[len - 1] == '\n')
82 		str[len - 1] = 0;
83 }
84 
85 /*
86  * Read the SMTP authentication config file
87  *
88  * file format is:
89  * user|host:password
90  *
91  * A line starting with # is treated as comment and ignored.
92  */
93 void
94 parse_authfile(const char *path)
95 {
96 	char line[2048];
97 	struct authuser *au;
98 	FILE *a;
99 	char *data;
100 	int lineno = 0;
101 
102 	a = fopen(path, "r");
103 	if (a == NULL) {
104 		errlog(1, "can not open auth file `%s'", path);
105 		/* NOTREACHED */
106 	}
107 
108 	while (!feof(a)) {
109 		if (fgets(line, sizeof(line), a) == NULL)
110 			break;
111 		lineno++;
112 
113 		chomp(line);
114 
115 		/* We hit a comment */
116 		if (*line == '#')
117 			continue;
118 		/* Ignore empty lines */
119 		if (*line == 0)
120 			continue;
121 
122 		au = calloc(1, sizeof(*au));
123 		if (au == NULL)
124 			errlog(1, "calloc failed");
125 
126 		data = strdup(line);
127 		au->login = strsep(&data, "|");
128 		au->host = strsep(&data, DP);
129 		au->password = data;
130 
131 		if (au->login == NULL ||
132 		    au->host == NULL ||
133 		    au->password == NULL) {
134 			errlogx(1, "syntax error in authfile %s:%d",
135 				path, lineno);
136 			/* NOTREACHED */
137 		}
138 
139 		SLIST_INSERT_HEAD(&authusers, au, next);
140 	}
141 
142 	fclose(a);
143 }
144 
145 /*
146  * XXX TODO
147  * Check for bad things[TM]
148  */
149 void
150 parse_conf(const char *config_path)
151 {
152 	char *word;
153 	char *data;
154 	FILE *conf;
155 	char line[2048];
156 	int lineno = 0;
157 
158 	conf = fopen(config_path, "r");
159 	if (conf == NULL) {
160 		/* Don't treat a non-existing config file as error */
161 		if (errno == ENOENT)
162 			return;
163 		errlog(1, "can not open config `%s'", config_path);
164 		/* NOTREACHED */
165 	}
166 
167 	while (!feof(conf)) {
168 		if (fgets(line, sizeof(line), conf) == NULL)
169 			break;
170 		lineno++;
171 
172 		chomp(line);
173 
174 		/* We hit a comment */
175 		if (strchr(line, '#'))
176 			*strchr(line, '#') = 0;
177 
178 		data = line;
179 		word = strsep(&data, EQS);
180 
181 		/* Ignore empty lines */
182 		if (word == NULL || *word == 0)
183 			continue;
184 
185 		if (data != NULL && *data != 0)
186 			data = strdup(data);
187 		else
188 			data = NULL;
189 
190 		if (strcmp(word, "SMARTHOST") == 0 && data != NULL)
191 			config.smarthost = data;
192 		else if (strcmp(word, "PORT") == 0 && data != NULL)
193 			config.port = atoi(data);
194 		else if (strcmp(word, "ALIASES") == 0 && data != NULL)
195 			config.aliases = data;
196 		else if (strcmp(word, "SPOOLDIR") == 0 && data != NULL)
197 			config.spooldir = data;
198 		else if (strcmp(word, "AUTHPATH") == 0 && data != NULL)
199 			config.authpath= data;
200 		else if (strcmp(word, "CERTFILE") == 0 && data != NULL)
201 			config.certfile = data;
202 		else if (strcmp(word, "MAILNAME") == 0 && data != NULL)
203 			config.mailname = data;
204 		else if (strcmp(word, "MASQUERADE") == 0 && data != NULL) {
205 			char *user = NULL, *host = NULL;
206 			if (strrchr(data, '@')) {
207 				host = strrchr(data, '@');
208 				*host = 0;
209 				host++;
210 				user = data;
211 			} else {
212 				host = data;
213 			}
214  			if (host && *host == 0)
215 				host = NULL;
216                         if (user && *user == 0)
217                                 user = NULL;
218 			config.masquerade_host = host;
219 			config.masquerade_user = user;
220 		} else if (strcmp(word, "STARTTLS") == 0 && data == NULL)
221 			config.features |= STARTTLS;
222 		else if (strcmp(word, "OPPORTUNISTIC_TLS") == 0 && data == NULL)
223 			config.features |= TLS_OPP;
224 		else if (strcmp(word, "SECURETRANSFER") == 0 && data == NULL)
225 			config.features |= SECURETRANS;
226 		else if (strcmp(word, "DEFER") == 0 && data == NULL)
227 			config.features |= DEFER;
228 		else if (strcmp(word, "INSECURE") == 0 && data == NULL)
229 			config.features |= INSECURE;
230 		else if (strcmp(word, "FULLBOUNCE") == 0 && data == NULL)
231 			config.features |= FULLBOUNCE;
232 		else if (strcmp(word, "NULLCLIENT") == 0 && data == NULL)
233 			config.features |= NULLCLIENT;
234 		else {
235 			errlogx(1, "syntax error in %s:%d", config_path, lineno);
236 			/* NOTREACHED */
237 		}
238 	}
239 
240 	if ((config.features & NULLCLIENT) && config.smarthost == NULL) {
241 		errlogx(1, "%s: NULLCLIENT requires SMARTHOST", config_path);
242 		/* NOTREACHED */
243 	}
244 
245 	fclose(conf);
246 }
247