comparison src/context.cpp @ 90:962a1f8f1d9f stable-5-4

add verify statement to verify addresses with better mx host
author carl
date Sun, 18 Sep 2005 10:19:58 -0700
parents 7245c45cef7a
children ca46fafc6621
comparison
equal deleted inserted replaced
89:946fc1bcfb2c 90:962a1f8f1d9f
5 http://www.fsf.org/licenses/gpl.txt 5 http://www.fsf.org/licenses/gpl.txt
6 6
7 */ 7 */
8 8
9 #include "includes.h" 9 #include "includes.h"
10
11 // needed for socket io
12 #include <sys/ioctl.h>
13 #include <net/if.h>
14 #include <arpa/inet.h>
15 #include <netinet/in.h>
16 #include <netinet/tcp.h>
17 #include <netdb.h>
18 #include <sys/socket.h>
19 #include <sys/un.h>
10 20
11 static char* context_version="$Id$"; 21 static char* context_version="$Id$";
12 22
13 char *token_black; 23 char *token_black;
14 char *token_content; 24 char *token_content;
38 char *token_semi; 48 char *token_semi;
39 char *token_soft; 49 char *token_soft;
40 char *token_substitute; 50 char *token_substitute;
41 char *token_tld; 51 char *token_tld;
42 char *token_unknown; 52 char *token_unknown;
53 char *token_verify;
43 char *token_white; 54 char *token_white;
44 55
45 string_set all_strings; // owns all the strings, only modified by the config loader thread 56 char *token_myhostname;
46 const int maxlen = 1000; 57 char myhostname[HOST_NAME_MAX+1];
58
59 verify_map verifiers;
60 string_set all_strings; // owns all the strings, only modified by the config loader thread
61 const int maxlen = 1000; // used for snprintf buffers
62 const int maxage = 120; // smtp verify sockets older than this are ancient
63 extern int NULL_SOCKET;
64 extern time_t ERROR_SOCKET_TIME; // number of seconds between attempts to open a socket an smtp host for address verification
65
66
67 int SMTP::writer() {
68 // log("writer() sees buffer with %s", buffer);
69 // log("writer() sees error %d", (int)error);
70 int rs = 0;
71 if (!error) {
72 int len = strlen(buffer);
73 while (rs < len) {
74 int ws = write(fd, buffer+rs, len-rs);
75 if (ws > 0) {
76 rs += ws;
77 }
78 else {
79 // peer closed the socket!
80 rs = 0;
81 error = true;
82 break;
83 }
84 }
85 }
86 return rs;
87 }
88
89
90 int SMTP::reader() {
91 // read some bytes terminated by lf or end of buffer.
92 // we may have a multi line response or part thereof in the buffer.
93 // log("reader() sees error %d", (int)error);
94 if (error) return 0;
95 int len = maxlen-1; // room for null terminator
96 while (pending < len) {
97 int ws = read(fd, buffer+pending, len-pending);
98 if (ws > 0) {
99 pending += ws;
100 if (buffer[pending-1] == '\n') break;
101 }
102 else {
103 // peer closed the socket!
104 pending = 0;
105 error = true;
106 break;
107 }
108 }
109 buffer[pending] = '\0';
110 // log("reader() sees buffer with %s", buffer);
111 return pending;
112 }
113
114
115 int SMTP::read_line() {
116 char *lf = strchr(buffer, '\n');
117 if (!lf) {
118 reader(); // get a lf
119 lf = strchr(buffer, '\n');
120 if (!lf) lf = buffer + pending - 1;
121 }
122 return (lf-buffer)+1; // number of bytes in this line
123 }
124
125
126 int SMTP::flush_line(int r) {
127 if (pending > r) memmove(buffer, buffer+r, pending-r);
128 pending -= r;
129 }
130
131
132 int SMTP::read_response() {
133 pending = 0;
134 buffer[pending] = '\0';
135 while (true) {
136 int r = read_line();
137 // log("read_response() sees line with %s", buffer);
138 // log("read_response() sees line length %d", r);
139 if (r == 0) return 0; // failed to read any bytes
140 if ((r > 4) && (buffer[3] == '-')) {
141 flush_line(r);
142 continue;
143 }
144 return atoi(buffer);
145 }
146 return 0;
147 }
148
149
150 int SMTP::cmd(char *c) {
151 if (c) {
152 init();
153 append(c);
154 }
155 append("\r\n");
156 writer();
157 return read_response();
158 }
159
160
161 int SMTP::helo() {
162 if (read_response() != 220) return 0;
163 init();
164 append("HELO ");
165 append(token_myhostname);
166 return cmd(NULL);
167 }
168
169
170 int SMTP::rset() {
171 return cmd("RSET");
172 }
173
174
175 int SMTP::from(char *f) {
176 init();
177 append("MAIL FROM:<");
178 append(f);
179 append(">");
180 return cmd(NULL);
181 }
182
183
184 int SMTP::rcpt(char *t) {
185 init();
186 append("RCPT TO:<");
187 append(t);
188 append(">");
189 return cmd(NULL);
190 }
191
192
193 int SMTP::quit() {
194 int rc = cmd("QUIT");
195 shutdown(fd, SHUT_RDWR);
196 close(fd);
197 return rc;
198 }
199
200
201 // void SMTP::log(char *m, int v) {
202 // char buf[maxlen];
203 // snprintf(buf, maxlen, m, v);
204 // my_syslog(buf);
205 // }
206 //
207 //
208 // void SMTP::log(char *m, char *v) {
209 // char buf[maxlen];
210 // snprintf(buf, maxlen, m, v);
211 // my_syslog(buf);
212 // }
213 //
214 //
215 VERIFY::VERIFY(char *h) {
216 host = h;
217 last_err = 0;
218 pthread_mutex_init(&mutex, 0);
219 }
220
221
222 void VERIFY::closer() {
223 bool ok = true;
224 while (ok) {
225 int fd = 0;
226 pthread_mutex_lock(&mutex);
227 if (sockets.empty()) {
228 ok = false;
229 }
230 else {
231 time_t t = times.front();
232 time_t now = time(NULL);
233 if ((now - t) > maxage) {
234 // this socket is ancient, remove it
235 fd = sockets.front();
236 times.pop_front();
237 sockets.pop_front();
238 }
239 else {
240 ok = false;
241 }
242 }
243 pthread_mutex_unlock(&mutex);
244 if (fd) {
245 SMTP s(fd);
246 s.quit(); // closes the fd
247 // s.log("closer() closes ancient %d", fd);
248 }
249 }
250 }
251
252
253 int VERIFY::get_socket() {
254 int sock = NULL_SOCKET;
255 pthread_mutex_lock(&mutex);
256 if (!sockets.empty()) {
257 sock = sockets.front();
258 times.pop_front();
259 sockets.pop_front();
260 // SMTP::log("get_socket() %d from cache", sock);
261 }
262 pthread_mutex_unlock(&mutex);
263
264 if (sock == NULL_SOCKET) {
265 time_t now = time(NULL);
266 if ((now - last_err) > ERROR_SOCKET_TIME) {
267 // nothing recent, maybe this time it will work
268 hostent *h = gethostbyname(host);
269 if (h) {
270 sockaddr_in server;
271 server.sin_family = h->h_addrtype;
272 server.sin_port = htons(25);
273 memcpy(&server.sin_addr, h->h_addr_list[0], h->h_length);
274 sock = socket(PF_INET, SOCK_STREAM, 0);
275 if (sock != NULL_SOCKET) {
276 bool rc = (connect(sock, (sockaddr *)&server, sizeof(server)) == 0);
277 if (!rc) {
278 shutdown(sock, SHUT_RDWR);
279 close(sock);
280 sock = NULL_SOCKET;
281 last_err = now;
282 }
283 }
284 else last_err = now;
285 }
286 else last_err = now;
287 }
288 if (sock != NULL_SOCKET) {
289 SMTP s(sock);
290 if (s.helo() != 250) {
291 put_socket(sock, true);
292 sock = NULL_SOCKET;
293 }
294 }
295 }
296 return sock;
297 }
298
299
300 void VERIFY::put_socket(int fd, bool err) {
301 if (err) {
302 // SMTP::log("put_socket() %d with error, close it", fd);
303 shutdown(fd, SHUT_RDWR);
304 close(fd);
305 last_err = time(NULL);
306 }
307 else {
308 // SMTP::log("put_socket() %d", fd);
309 pthread_mutex_lock(&mutex);
310 time_t now = time(NULL);
311 times.push_back(now);
312 sockets.push_back(fd);
313 pthread_mutex_unlock(&mutex);
314 }
315 }
316
317
318 bool VERIFY::ok(char *from, char *to) {
319 if (host == token_myhostname) return true;
320 int fd = get_socket();
321 if (fd == NULL_SOCKET) return true; // cannot verify right now, we have socket errors
322 SMTP s(fd);
323 s.rset();
324 int rc;
325 rc = s.from(from);
326 // s.log("verify::ok from sees %d", rc);
327 if (rc != 250) {
328 put_socket(fd, s.err());
329 return (rc >= 500) ? false : true;
330 }
331 rc = s.rcpt(to);
332 // s.log("verify::ok rcpt sees %d", rc);
333 put_socket(fd, s.err());
334 return (rc >= 500) ? false : true;
335 }
336
47 337
48 DNSBL::DNSBL(char *n, char *s, char *m) { 338 DNSBL::DNSBL(char *n, char *s, char *m) {
49 name = n; 339 name = n;
50 suffix = s; 340 suffix = s;
51 message = m; 341 message = m;
153 443
154 444
155 CONTEXT::CONTEXT(CONTEXTP parent_, char *name_) { 445 CONTEXT::CONTEXT(CONTEXTP parent_, char *name_) {
156 parent = parent_; 446 parent = parent_;
157 name = name_; 447 name = name_;
448 verify_host = NULL;
158 env_from_default = (parent) ? token_inherit : token_unknown; 449 env_from_default = (parent) ? token_inherit : token_unknown;
159 content_filtering = (parent) ? parent->content_filtering : false; 450 content_filtering = (parent) ? parent->content_filtering : false;
160 content_suffix = NULL; 451 content_suffix = NULL;
161 content_message = NULL; 452 content_message = NULL;
162 host_limit = (parent) ? parent->host_limit : 0; 453 host_limit = (parent) ? parent->host_limit : 0;
198 else x = to; 489 else x = to;
199 if (*x == '\0') return true; // always allow covering addresses with no domain name, eg abuse@ 490 if (*x == '\0') return true; // always allow covering addresses with no domain name, eg abuse@
200 string_set::iterator i = env_to.find(x); 491 string_set::iterator i = env_to.find(x);
201 if (i != env_to.end()) return true; 492 if (i != env_to.end()) return true;
202 return false; 493 return false;
494 }
495
496
497 VERIFYP CONTEXT::find_verify(char *to) {
498 if (verify_host && (verify_host != token_myhostname) && cover_env_to(to)) {
499 verify_map::iterator i = verifiers.find(verify_host);
500 if (i == verifiers.end()) {
501 if (debug_syslog) {
502 char buf[maxlen];
503 snprintf(buf, maxlen, "cannot find struc for %s", verify_host);
504 my_syslog(buf);
505 }
506 return NULL;
507 }
508 VERIFYP v = (*i).second;
509
510 return v;
511 }
512 else if (parent) return parent->find_verify(to);
513 else return NULL;
203 } 514 }
204 515
205 516
206 char *CONTEXT::find_from(char *from) { 517 char *CONTEXT::find_from(char *from) {
207 char *rc = token_inherit; 518 char *rc = token_inherit;
387 for (string_set::iterator i=env_to.begin(); i!=env_to.end(); i++) { 698 for (string_set::iterator i=env_to.begin(); i!=env_to.end(); i++) {
388 printf("%s %s; \n", indent, *i); 699 printf("%s %s; \n", indent, *i);
389 } 700 }
390 printf("%s }; \n", indent); 701 printf("%s }; \n", indent);
391 702
703 if (verify_host) {
704 printf("%s verify %s; \n", indent, verify_host);
705 }
706
392 for (context_map::iterator i=children.begin(); i!=children.end(); i++) { 707 for (context_map::iterator i=children.begin(); i!=children.end(); i++) {
393 CONTEXTP c = (*i).second; 708 CONTEXTP c = (*i).second;
394 c->dump(level+1); 709 c->dump(level+1);
395 } 710 }
396 711
680 } 995 }
681 996
682 997
683 //////////////////////////////////////////////// 998 ////////////////////////////////////////////////
684 // 999 //
1000 bool parse_verify(TOKEN &tok, CONFIG &dc, CONTEXT &me);
1001 bool parse_verify(TOKEN &tok, CONFIG &dc, CONTEXT &me) {
1002 char *host = tok.next();
1003 if (!tsa(tok, token_semi)) return false;
1004 me.set_verify(host);
1005 add_verify_host(host);
1006 }
1007
1008
1009 ////////////////////////////////////////////////
1010 //
685 bool parse_envfrom(TOKEN &tok, CONFIG &dc, CONTEXT &me); 1011 bool parse_envfrom(TOKEN &tok, CONFIG &dc, CONTEXT &me);
686 bool parse_envfrom(TOKEN &tok, CONFIG &dc, CONTEXT &me) { 1012 bool parse_envfrom(TOKEN &tok, CONFIG &dc, CONTEXT &me) {
687 char *st = tok.next(); 1013 char *st = tok.next();
688 if ((st == token_black) || (st == token_white) || (st == token_unknown) || (st == token_inherit)) { 1014 if ((st == token_black) || (st == token_white) || (st == token_unknown) || (st == token_inherit)) {
689 me.set_from_default(st); 1015 me.set_from_default(st);
780 if (!parse_content(tok, dc, *con)) return false; 1106 if (!parse_content(tok, dc, *con)) return false;
781 } 1107 }
782 else if (have == token_envto) { 1108 else if (have == token_envto) {
783 if (!parse_envto(tok, dc, *con)) return false; 1109 if (!parse_envto(tok, dc, *con)) return false;
784 } 1110 }
1111 else if (have == token_verify) {
1112 if (!parse_verify(tok, dc, *con)) return false;
1113 }
785 else if (have == token_envfrom) { 1114 else if (have == token_envfrom) {
786 if (!parse_envfrom(tok, dc, *con)) return false; 1115 if (!parse_envfrom(tok, dc, *con)) return false;
787 } 1116 }
788 else if (have == token_context) { 1117 else if (have == token_context) {
789 if (!parse_context(tok, dc, con)) return false; 1118 if (!parse_context(tok, dc, con)) return false;
821 tok.token_error(token_context, have); 1150 tok.token_error(token_context, have);
822 return false; 1151 return false;
823 } 1152 }
824 } 1153 }
825 return (dc.default_context) ? true : false; 1154 return (dc.default_context) ? true : false;
1155 }
1156
1157
1158 ////////////////////////////////////////////////
1159 // setup a new smtp verify host
1160 //
1161 void add_verify_host(char *host) {
1162 verify_map::iterator i = verifiers.find(host);
1163 if (i == verifiers.end()) {
1164 VERIFYP v = new VERIFY(host);
1165 verifiers[host] = v;
1166 }
1167 }
1168
1169
1170 ////////////////////////////////////////////////
1171 // thread to check for verify hosts with old sockets that we can close
1172 //
1173 void* verify_closer(void *arg) {
1174 while (true) {
1175 sleep(maxage);
1176 for (verify_map::iterator i=verifiers.begin(); i!=verifiers.end(); i++) {
1177 VERIFYP v = (*i).second;
1178 v->closer();
1179 }
1180 }
1181 return NULL;
826 } 1182 }
827 1183
828 1184
829 //////////////////////////////////////////////// 1185 ////////////////////////////////////////////////
830 // init the tokens 1186 // init the tokens
858 token_semi = register_string(";"); 1214 token_semi = register_string(";");
859 token_soft = register_string("soft"); 1215 token_soft = register_string("soft");
860 token_substitute = register_string("substitute"); 1216 token_substitute = register_string("substitute");
861 token_tld = register_string("tld"); 1217 token_tld = register_string("tld");
862 token_unknown = register_string("unknown"); 1218 token_unknown = register_string("unknown");
1219 token_verify = register_string("verify");
863 token_white = register_string("white"); 1220 token_white = register_string("white");
864 } 1221
1222 if (gethostname(myhostname, HOST_NAME_MAX+1) != 0) {
1223 strncpy(myhostname, "localhost", HOST_NAME_MAX+1);
1224 }
1225 myhostname[HOST_NAME_MAX] = '\0'; // ensure null termination
1226 token_myhostname = register_string(myhostname);
1227 }