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