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(EX_DATAERR); 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(EX_NOINPUT, "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(EX_OSERR, "calloc()"); 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(EX_CONFIG, "syntax error in authfile %s:%d", path, lineno); 135 /* NOTREACHED */ 136 } 137 138 SLIST_INSERT_HEAD(&authusers, au, next); 139 } 140 141 fclose(a); 142 } 143 144 /* 145 * XXX TODO 146 * Check for bad things[TM] 147 */ 148 void 149 parse_conf(const char *config_path) 150 { 151 char *word; 152 char *data; 153 FILE *conf; 154 char line[2048]; 155 int lineno = 0; 156 157 conf = fopen(config_path, "r"); 158 if (conf == NULL) { 159 /* Don't treat a non-existing config file as error */ 160 if (errno == ENOENT) 161 return; 162 errlog(EX_NOINPUT, "can not open config `%s'", config_path); 163 /* NOTREACHED */ 164 } 165 166 while (!feof(conf)) { 167 if (fgets(line, sizeof(line), conf) == NULL) 168 break; 169 lineno++; 170 171 chomp(line); 172 173 /* We hit a comment */ 174 if (strchr(line, '#')) 175 *strchr(line, '#') = 0; 176 177 data = line; 178 word = strsep(&data, EQS); 179 180 /* Ignore empty lines */ 181 if (word == NULL || *word == 0) 182 continue; 183 184 if (data != NULL && *data != 0) 185 data = strdup(data); 186 else 187 data = NULL; 188 189 if (strcmp(word, "SMARTHOST") == 0 && data != NULL) 190 config.smarthost = data; 191 else if (strcmp(word, "PORT") == 0 && data != NULL) 192 config.port = atoi(data); 193 else if (strcmp(word, "ALIASES") == 0 && data != NULL) 194 config.aliases = data; 195 else if (strcmp(word, "SPOOLDIR") == 0 && data != NULL) 196 config.spooldir = data; 197 else if (strcmp(word, "AUTHPATH") == 0 && data != NULL) 198 config.authpath= data; 199 else if (strcmp(word, "CERTFILE") == 0 && data != NULL) 200 config.certfile = data; 201 else if (strcmp(word, "MAILNAME") == 0 && data != NULL) 202 config.mailname = data; 203 else if (strcmp(word, "MASQUERADE") == 0 && data != NULL) { 204 char *user = NULL, *host = NULL; 205 if (strrchr(data, '@')) { 206 host = strrchr(data, '@'); 207 *host = 0; 208 host++; 209 user = data; 210 } else { 211 host = data; 212 } 213 if (host && *host == 0) 214 host = NULL; 215 if (user && *user == 0) 216 user = NULL; 217 config.masquerade_host = host; 218 config.masquerade_user = user; 219 } else if (strcmp(word, "STARTTLS") == 0 && data == NULL) 220 config.features |= STARTTLS; 221 else if (strcmp(word, "OPPORTUNISTIC_TLS") == 0 && data == NULL) 222 config.features |= TLS_OPP; 223 else if (strcmp(word, "SECURETRANSFER") == 0 && data == NULL) 224 config.features |= SECURETRANS; 225 else if (strcmp(word, "DEFER") == 0 && data == NULL) 226 config.features |= DEFER; 227 else if (strcmp(word, "INSECURE") == 0 && data == NULL) 228 config.features |= INSECURE; 229 else if (strcmp(word, "FULLBOUNCE") == 0 && data == NULL) 230 config.features |= FULLBOUNCE; 231 else if (strcmp(word, "NULLCLIENT") == 0 && data == NULL) 232 config.features |= NULLCLIENT; 233 else { 234 errlogx(EX_CONFIG, "syntax error in %s:%d", config_path, lineno); 235 /* NOTREACHED */ 236 } 237 } 238 239 if ((config.features & NULLCLIENT) && config.smarthost == NULL) { 240 errlogx(EX_CONFIG, "%s: NULLCLIENT requires SMARTHOST", config_path); 241 /* NOTREACHED */ 242 } 243 244 fclose(conf); 245 } 246