Line data Source code
1 21 : int smtpstate_new(LOGGER log, CONNECTION* client, DATABASE* database, PATHPOOL* path_pool){
2 21 : CLIENT* client_data=(CLIENT*)client->aux_data;
3 21 : LISTENER* listener_data=(LISTENER*)client_data->listener->aux_data;
4 :
5 21 : if(!strncasecmp(client_data->recv_buffer, "ehlo ", 5)){
6 : #ifndef CMAIL_NO_TLS
7 18 : switch(client_data->listener->tls_mode){
8 : case TLS_ONLY:
9 1 : client_data->current_mail.protocol=(client_data->sasl_user.authenticated?"sesmtpa":"sesmtp");
10 1 : break;
11 : case TLS_NEGOTIATE:
12 17 : if(client->tls_mode==TLS_ONLY){
13 4 : client_data->current_mail.protocol=(client_data->sasl_user.authenticated?"esmtpsa":"esmtps");
14 4 : break;
15 : }
16 : case TLS_NONE:
17 13 : client_data->current_mail.protocol=(client_data->sasl_user.authenticated?"esmtpa":"esmtp");
18 13 : break;
19 : }
20 : #else
21 : client_data->current_mail.protocol=(client_data->sasl_user.authenticated?"esmtpa":"esmtp");
22 : #endif
23 :
24 18 : client_data->state=STATE_IDLE;
25 :
26 18 : client_send(log, client, "250-%s ahoyhoy\r\n", listener_data->announce_domain);
27 :
28 : //TODO hook plugins here
29 :
30 : //send hardcoded esmtp options
31 18 : client_send(log, client, "250-SIZE %d\r\n", listener_data->max_size);
32 18 : client_send(log, client, "250-8BITMIME\r\n"); //FIXME this might imply more processing than planned
33 18 : client_send(log, client, "250-SMTPUTF8\r\n"); //RFC 6531
34 18 : switch(listener_data->auth_offer){
35 : case AUTH_NONE:
36 10 : break;
37 : case AUTH_TLSONLY:
38 : #ifndef CMAIL_NO_TLS
39 8 : if(client->tls_mode!=TLS_ONLY){
40 4 : break;
41 : }
42 : #else
43 : break;
44 : #endif
45 : case AUTH_ANY:
46 4 : client_send(log, client, "250-AUTH PLAIN\r\n");
47 4 : break;
48 : }
49 : #ifndef CMAIL_NO_TLS
50 : //advertise only when possible
51 18 : if(client_data->listener->tls_mode==TLS_NEGOTIATE && client->tls_mode==TLS_NONE){
52 13 : client_send(log, client, "250-STARTTLS\r\n"); //RFC 3207
53 : }
54 : #endif
55 18 : client_send(log, client, "250 XYZZY\r\n"); //RFC 5321 2.2.2
56 18 : return 0;
57 : }
58 :
59 3 : if(!strncasecmp(client_data->recv_buffer, "helo ", 5)){
60 : #ifndef CMAIL_NO_TLS
61 2 : switch(client_data->listener->tls_mode){
62 : case TLS_ONLY:
63 0 : client_data->current_mail.protocol = (client_data->sasl_user.authenticated ? "ssmtpa":"ssmtp");
64 0 : break;
65 : case TLS_NEGOTIATE:
66 2 : if(client->tls_mode==TLS_ONLY){
67 1 : client_data->current_mail.protocol = (client_data->sasl_user.authenticated ? "smtpsa":"smtps");
68 1 : break;
69 : }
70 : case TLS_NONE:
71 1 : client_data->current_mail.protocol = (client_data->sasl_user.authenticated ? "smtpa":"smtp");
72 1 : break;
73 : }
74 : #else
75 : client_data->current_mail.protocol = (client_data->sasl_user.authenticated ? "smtpa":"smtp");
76 : #endif
77 :
78 2 : client_data->state=STATE_IDLE;
79 2 : logprintf(log, LOG_INFO, "Client negotiates smtp\n");
80 :
81 2 : client_send(log, client, "250 %s ahoyhoy\r\n", listener_data->announce_domain);
82 2 : return 0;
83 : }
84 :
85 1 : logprintf(log, LOG_INFO, "Command not recognized in state NEW: %s\n", client_data->recv_buffer);
86 1 : client_send(log, client, "500 Unknown command\r\n");
87 1 : return -1;
88 : }
89 :
90 14 : int smtpstate_auth(LOGGER log, CONNECTION* client, DATABASE* database, PATHPOOL* path_pool){
91 14 : CLIENT* client_data = (CLIENT*)client->aux_data;
92 14 : int status = SASL_ERROR_PROCESSING;
93 14 : char* method = NULL;
94 14 : char* parameter = NULL;
95 14 : char* challenge = NULL;
96 :
97 14 : if(client_data->sasl_context.method != SASL_INVALID && !strcmp(client_data->recv_buffer, "*")){
98 : //cancel authentication
99 1 : logprintf(log, LOG_INFO, "Client cancelled authentication\n");
100 1 : client_data->state=STATE_IDLE;
101 1 : sasl_cancel(&(client_data->sasl_context));
102 1 : client_send(log, client, "501 Authentication cancelled\r\n");
103 1 : return 0;
104 : }
105 13 : else if(client_data->sasl_context.method != SASL_INVALID){
106 2 : status = sasl_continue(log, &(client_data->sasl_context), client_data->recv_buffer, &challenge);
107 : }
108 11 : else if(!strncasecmp(client_data->recv_buffer, "auth ", 5)){
109 : //tokenize along spaces
110 11 : method = strtok(client_data->recv_buffer + 5, " ");
111 11 : if(method){
112 10 : parameter = strtok(NULL, " ");
113 10 : logprintf(log, LOG_DEBUG, "Beginning SASL with method %s parameter %s\n", method, parameter?parameter:"null");
114 10 : status = sasl_begin(log, &(client_data->sasl_context), &(client_data->sasl_user), method, parameter, &challenge);
115 : }
116 : else{
117 1 : logprintf(log, LOG_WARNING, "Client tried auth without supplying method\n");
118 1 : status = SASL_UNKNOWN_METHOD;
119 : }
120 : }
121 : else{
122 0 : logprintf(log, LOG_ERROR, "Invalid state (No negotiation but data) reached in AUTH, returning to IDLE\r\n");
123 0 : client_data->state=STATE_IDLE;
124 0 : client_send(log, client, "500 Invalid state\r\n");
125 0 : return -1;
126 : }
127 :
128 13 : switch(status){
129 : case SASL_OK:
130 0 : logprintf(log, LOG_ERROR, "Invalid state (SASL_OK) reached in AUTH, returning to IDLE\r\n");
131 : //FIXME might want to reset sasl_user here
132 0 : sasl_reset_ctx(&(client_data->sasl_context), false); //opting for security here, rather than freeing memory we do not own
133 0 : client_data->state = STATE_IDLE;
134 0 : client_send(log, client, "500 Invalid state\r\n");
135 0 : return -1;
136 : case SASL_ERROR_PROCESSING:
137 0 : logprintf(log, LOG_ERROR, "SASL processing error\r\n");
138 0 : sasl_reset_ctx(&(client_data->sasl_context), true);
139 0 : client_send(log, client, "454 Internal Error\r\n");
140 0 : client_data->state = STATE_IDLE;
141 0 : return 0;
142 : case SASL_ERROR_DATA:
143 2 : logprintf(log, LOG_ERROR, "SASL failed to parse data\r\n");
144 2 : sasl_reset_ctx(&(client_data->sasl_context), true);
145 2 : client_send(log, client, "501 Invalid data provided\r\n");
146 2 : client_data->state = STATE_IDLE;
147 2 : return -1;
148 : case SASL_UNKNOWN_METHOD:
149 3 : logprintf(log, LOG_WARNING, "Client tried unsupported authentication method: %s\n", client_data->recv_buffer + 5);
150 3 : client_data->state = STATE_IDLE;
151 3 : sasl_reset_ctx(&(client_data->sasl_context), false);
152 3 : client_send(log, client, "504 Unknown mechanism\r\n");
153 3 : return -1;
154 : case SASL_CONTINUE:
155 3 : logprintf(log, LOG_INFO, "Asking for SASL continuation\r\n");
156 3 : client_send(log, client, "334 %s\r\n", challenge ? challenge:"");
157 3 : return 0;
158 : case SASL_DATA_OK:
159 5 : sasl_reset_ctx(&(client_data->sasl_context), true);
160 5 : client_data->state = STATE_IDLE;
161 :
162 : //check auth data
163 5 : if(!challenge || auth_validate(log, database, client_data->sasl_user.authenticated, challenge, &(client_data->sasl_user.authorized)) < 0){
164 : //login failed
165 2 : sasl_reset_user(&(client_data->sasl_user), true);
166 2 : logprintf(log, LOG_INFO, "Client failed to authenticate\n");
167 2 : client_send(log, client, "535 Authentication failed\r\n");
168 :
169 : //increase the failscore
170 2 : return -1;
171 : }
172 :
173 3 : if(!client_data->sasl_user.authorized){
174 0 : sasl_reset_user(&(client_data->sasl_user), true);
175 0 : logprintf(log, LOG_ERROR, "Failed to allocate memory for authorized user\n");
176 0 : client_send(log, client, "454 Internal Error\r\n");
177 0 : return 0;
178 : }
179 :
180 3 : client_data->originating_route = route_query(log, database, client_data->sasl_user.authorized);
181 :
182 3 : logprintf(log, LOG_INFO, "Client authenticated as %s\n", client_data->sasl_user.authenticated);
183 3 : client_send(log, client, "235 Authenticated\r\n");
184 :
185 : //update the protocol version
186 : #ifndef CMAIL_NO_TLS
187 3 : switch(client_data->listener->tls_mode){
188 : case TLS_ONLY:
189 0 : client_data->current_mail.protocol = "sesmtpa";
190 0 : break;
191 : case TLS_NEGOTIATE:
192 3 : if(client->tls_mode == TLS_ONLY){
193 3 : client_data->current_mail.protocol = "esmtpsa";
194 3 : break;
195 : }
196 : case TLS_NONE:
197 0 : client_data->current_mail.protocol = "esmtpa";
198 0 : break;
199 : }
200 : #else
201 : client_data->current_mail.protocol = "esmtpa";
202 : #endif
203 :
204 : //decrease the failscore
205 3 : return 1;
206 : }
207 :
208 0 : logprintf(log, LOG_ERROR, "Invalid branch reached in AUTH\n");
209 0 : return -1;
210 : }
211 :
212 102 : int smtpstate_idle(LOGGER log, CONNECTION* client, DATABASE* database, PATHPOOL* path_pool){
213 102 : CLIENT* client_data = (CLIENT*)client->aux_data;
214 102 : LISTENER* listener_data = (LISTENER*)client_data->listener->aux_data;
215 :
216 102 : if(!strncasecmp(client_data->recv_buffer, "noop", 4)){
217 1 : logprintf(log, LOG_INFO, "Client noop\n");
218 1 : client_send(log, client, "250 OK\r\n");
219 1 : return 0;
220 : }
221 :
222 101 : if(!strncasecmp(client_data->recv_buffer, "rset", 4)){
223 29 : logprintf(log, LOG_INFO, "Client reset\n");
224 29 : mail_reset(&(client_data->current_mail));
225 29 : client_send(log, client, "250 Reset OK\r\n");
226 29 : return 0;
227 : }
228 :
229 : #ifndef CMAIL_NO_TLS
230 : //accept only when offered, reject when already negotiated
231 72 : if(!strncasecmp(client_data->recv_buffer, "starttls", 8)){
232 6 : if(client->tls_mode!=TLS_NONE){
233 1 : logprintf(log, LOG_WARNING, "Client with active TLS session tried to negotiate\n");
234 1 : client_send(log, client, "503 Already in TLS session\r\n");
235 1 : return 0;
236 : }
237 :
238 5 : if(client_data->listener->tls_mode!=TLS_NEGOTIATE){
239 0 : logprintf(log, LOG_WARNING, "Client tried to negotiate TLS with non-negotiable listener\n");
240 0 : client_send(log, client, "503 Not advertised\r\n");
241 :
242 : //increase the failscore
243 0 : return -1;
244 : }
245 :
246 5 : logprintf(log, LOG_INFO, "Client wants to negotiate TLS\n");
247 5 : mail_reset(&(client_data->current_mail));
248 5 : client_data->state=STATE_NEW;
249 :
250 5 : client_send(log, client, "220 Go ahead\r\n");
251 :
252 5 : client->tls_mode=TLS_NEGOTIATE;
253 :
254 : //this is somewhat dodgy and should probably be replaced by a proper conditional
255 5 : return tls_init_serverpeer(log, client, listener_data->tls_priorities, listener_data->tls_cert);
256 : }
257 : #endif
258 :
259 66 : if(!strncasecmp(client_data->recv_buffer, "auth ", 5)){
260 17 : switch(listener_data->auth_offer){
261 : case AUTH_NONE:
262 3 : logprintf(log, LOG_WARNING, "Client tried to auth on a non-auth listener\n");
263 3 : client_send(log, client, "503 Not advertised\r\n");
264 3 : return -1;
265 : case AUTH_TLSONLY:
266 : #ifndef CMAIL_NO_TLS
267 14 : if(client->tls_mode != TLS_ONLY){
268 : #endif
269 2 : logprintf(log, LOG_WARNING, "Non-TLS client tried to auth on auth-tlsonly listener\n");
270 2 : client_send(log, client, "504 Encryption required\r\n"); //FIXME 538 might be better, but is marked obsolete
271 2 : return -1;
272 : #ifndef CMAIL_NO_TLS
273 : }
274 : #endif
275 : case AUTH_ANY:
276 12 : if(client_data->sasl_user.authenticated){
277 1 : logprintf(log, LOG_WARNING, "Authenticated client tried to authenticate again\n");
278 1 : client_send(log, client, "503 Already authenticated\r\n");
279 1 : return -1;
280 : }
281 : //continue
282 11 : break;
283 : }
284 :
285 11 : client_data->state = STATE_AUTH;
286 11 : return smtpstate_auth(log, client, database, path_pool);
287 : }
288 :
289 49 : if(!strncasecmp(client_data->recv_buffer, "xyzzy", 5)){
290 1 : client_send(log, client, "250 Nothing happens\r\n");
291 1 : logprintf(log, LOG_INFO, "Client performs incantation\n");
292 : //Using this command for some debug output...
293 1 : logprintf(log, LOG_DEBUG, "Client protocol: %s\n", client_data->current_mail.protocol);
294 1 : logprintf(log, LOG_DEBUG, "Peer name %s, mail submitter %s, data_allocated %d\n", client_data->peer_name, client_data->current_mail.submitter, client_data->current_mail.data_allocated);
295 1 : logprintf(log, LOG_DEBUG, "AUTH Status %s, Authentication: %s, Authorization: %s\n", client_data->sasl_context.method!=SASL_INVALID?"active":"inactive", client_data->sasl_user.authenticated ? client_data->sasl_user.authenticated:"none", client_data->sasl_user.authorized ? client_data->sasl_user.authorized:"none");
296 1 : logprintf(log, LOG_DEBUG, "Originating router: %s (%s)\n", client_data->originating_route.router?client_data->originating_route.router:"none", client_data->originating_route.argument?client_data->originating_route.argument:"none");
297 : #ifndef CMAIL_NO_TLS
298 1 : logprintf(log, LOG_DEBUG, "TLS State: %s\n", tls_modestring(client->tls_mode));
299 : #endif
300 1 : logprintf(log, LOG_DEBUG, "Connection score: %d\n", client_data->connection_score);
301 1 : return 0;
302 : }
303 :
304 48 : if(!strncasecmp(client_data->recv_buffer, "quit", 4)){
305 3 : logprintf(log, LOG_INFO, "Client quit\n");
306 3 : client_send(log, client, "221 OK Bye\r\n");
307 3 : return client_close(client);
308 : }
309 :
310 : //this needs to be implemented as per RFC5321 3.3
311 45 : if(!strncasecmp(client_data->recv_buffer, "rcpt ", 5)){
312 1 : logprintf(log, LOG_INFO, "Client tried to use RCPT in IDLE\n");
313 1 : client_send(log, client, "503 Bad sequence of commands\r\n");
314 1 : return -1;
315 : }
316 :
317 44 : if(!strncasecmp(client_data->recv_buffer, "mail from:", 10)){
318 37 : if(listener_data->auth_require && !client_data->sasl_user.authenticated){
319 0 : logprintf(log, LOG_WARNING, "Client tried mail command without authentication on strict auth listener\n");
320 0 : client_send(log, client, "530 Authentication required\r\n");
321 0 : return -1;
322 : }
323 :
324 37 : logprintf(log, LOG_INFO, "Client initiates mail transaction\n");
325 : //extract reverse path and store it
326 37 : if(path_parse(log, client_data->recv_buffer + 10, &(client_data->current_mail.reverse_path)) < 0){
327 0 : client_send(log, client, "501 Path rejected\r\n");
328 0 : return -1;
329 : }
330 :
331 : //resolve reverse path
332 37 : switch(path_resolve(log, &(client_data->current_mail.reverse_path), database, client_data->sasl_user.authorized, true)){
333 : case 0:
334 : //reverse path contains either store or null router.
335 : //check origination routing data for action to take
336 37 : if(client_data->sasl_user.authenticated && client_data->sasl_user.authorized){
337 12 : if(!client_data->originating_route.router || !strcmp(client_data->originating_route.router, "reject")){
338 0 : client_send(log, client, "551 %s\r\n", client_data->originating_route.argument ? client_data->originating_route.argument:"User not allowed to use this path");
339 0 : path_reset(&(client_data->current_mail.reverse_path));
340 0 : return -1;
341 : }
342 12 : else if(!strcmp(client_data->originating_route.router, "any")){
343 : //accept anything
344 : }
345 0 : else if(!strcmp(client_data->originating_route.router, "defined")){
346 0 : if(!client_data->current_mail.reverse_path.route.router
347 0 : || !client_data->current_mail.reverse_path.route.argument
348 0 : || strcmp(client_data->current_mail.reverse_path.route.router, "store")
349 0 : || strcmp(client_data->current_mail.reverse_path.route.argument, client_data->sasl_user.authorized)){
350 : //no valid store router pointing back at the user, fail the reverse path
351 0 : client_send(log, client, "551 User not allowed to use this path\r\n");
352 0 : path_reset(&(client_data->current_mail.reverse_path));
353 0 : return -1;
354 : }
355 : else{
356 : //the path resolves back to the originating user, accept it
357 : }
358 : }
359 : }
360 : else{
361 : //filtering of local reverse paths for unauthenticated connections might take place here
362 : }
363 37 : break;
364 : case 1:
365 : //inbound reject router (should not be able to happen anymore)
366 0 : logprintf(log, LOG_ERROR, "Inbound reject router applied to reverse path, please notify the developers!\n");
367 0 : break;
368 : default:
369 : //resolution failed
370 0 : logprintf(log, LOG_INFO, "Failed to resolve reverse path\n");
371 0 : path_reset(&(client_data->current_mail.reverse_path));
372 0 : client_send(log, client, "451 Path rejected\r\n");
373 0 : return 0;
374 : }
375 :
376 : //TODO call plugins for spf, etc
377 :
378 37 : client_send(log, client, "250 OK\r\n");
379 37 : client_data->state = STATE_RECIPIENTS;
380 37 : return 0;
381 : }
382 :
383 7 : if(!strncasecmp(client_data->recv_buffer, "vrfy ", 5)
384 6 : || !strncasecmp(client_data->recv_buffer, "expn ", 5)){
385 2 : logprintf(log, LOG_WARNING, "Client tried to verify / expand an address, unsupported\n");
386 2 : client_send(log, client, "502 Not implemented\r\n");
387 2 : return -1;
388 : }
389 :
390 5 : logprintf(log, LOG_INFO, "Command not recognized in state IDLE: %s\n", client_data->recv_buffer);
391 5 : client_send(log, client, "500 Unknown command\r\n");
392 5 : return -1;
393 : }
394 :
395 89 : int smtpstate_recipients(LOGGER log, CONNECTION* client, DATABASE* database, PATHPOOL* path_pool){
396 89 : CLIENT* client_data = (CLIENT*)client->aux_data;
397 89 : LISTENER* listener_data = (LISTENER*)client_data->listener->aux_data;
398 : unsigned i;
399 : MAILPATH* current_path;
400 :
401 89 : if(!strncasecmp(client_data->recv_buffer, "rcpt to:", 8)){
402 : //get slot in forward_paths
403 83 : for(i = 0; i < SMTP_MAX_RECIPIENTS; i++){
404 83 : if(!client_data->current_mail.forward_paths[i]){
405 48 : break;
406 : }
407 : }
408 :
409 48 : if(i == SMTP_MAX_RECIPIENTS){
410 : //too many recipients, fail this one
411 0 : logprintf(log, LOG_INFO, "Mail exceeded recipient limit\n");
412 0 : client_send(log, client, "452 Too many recipients\r\n");
413 0 : return -1;
414 : }
415 :
416 : //get path from pool
417 48 : current_path = pathpool_get(log, path_pool);
418 48 : if(!current_path){
419 0 : logprintf(log, LOG_ERROR, "Failed to get path, failing recipient\n");
420 0 : client_send(log, client, "452 Recipients pool maxed out\r\n");
421 : //FIXME should state transition back to idle here?
422 0 : return -1;
423 : }
424 :
425 48 : if(path_parse(log, client_data->recv_buffer + 8, current_path) < 0){
426 3 : client_send(log, client, "501 Path rejected\r\n");
427 3 : pathpool_return(current_path);
428 3 : return -1;
429 : }
430 :
431 : //the last 2 parameters in this call _must_ be NULL/false to not trigger an invalid branch in this case
432 45 : switch(path_resolve(log, current_path, database, NULL, false)){
433 : case 0:
434 : //continue path handling
435 40 : break;
436 : case 1:
437 : //reject by router decision
438 5 : client_send(log, client, "551 %s\r\n", current_path->route.argument ? current_path->route.argument:"User does not accept mail");
439 5 : pathpool_return(current_path);
440 5 : return -1;
441 : default:
442 0 : client_send(log, client, "451 Path rejected\r\n");
443 0 : pathpool_return(current_path);
444 : //FIXME should state transition back to idle here?
445 : //client_data->state=STATE_IDLE;
446 : //mail_reset(&(client_data->current_mail));
447 0 : return 0;
448 : }
449 :
450 40 : if(!current_path->route.router){
451 : //path not local, accept only if authenticated
452 1 : if(!client_data->sasl_user.authenticated){
453 1 : client_send(log, client, "551 Unknown user\r\n");
454 1 : pathpool_return(current_path);
455 1 : return -1;
456 : }
457 : }
458 :
459 : //FIXME address deduplication?
460 : //TODO call plugins
461 :
462 39 : client_data->current_mail.forward_paths[i] = current_path;
463 39 : client_send(log, client, "250 Accepted\r\n");
464 :
465 : //decrease the failscore
466 39 : return 1;
467 : }
468 :
469 41 : if(!strncasecmp(client_data->recv_buffer, "quit", 4)){
470 1 : logprintf(log, LOG_INFO, "Client quit\n");
471 1 : client_send(log, client, "221 OK Bye\r\n");
472 1 : return client_close(client);
473 : }
474 :
475 40 : if(!strncasecmp(client_data->recv_buffer, "noop", 4)){
476 1 : logprintf(log, LOG_INFO, "Client noop\n");
477 1 : client_send(log, client, "250 OK\r\n");
478 1 : return 0;
479 : }
480 :
481 39 : if(!strncasecmp(client_data->recv_buffer, "rset", 4)){
482 4 : client_data->state = STATE_IDLE;
483 4 : mail_reset(&(client_data->current_mail));
484 4 : logprintf(log, LOG_INFO, "Client reset\n");
485 4 : client_send(log, client, "250 Reset OK\r\n");
486 4 : return 0;
487 : }
488 :
489 35 : if(!strncasecmp(client_data->recv_buffer, "auth", 4)){
490 1 : logprintf(log, LOG_INFO, "Client tried to use AUTH in RECIPIENTS\n");
491 1 : client_send(log, client, "503 Bad sequence of commands\r\n");
492 1 : return -1;
493 : }
494 :
495 34 : if(!strncasecmp(client_data->recv_buffer, "data", 4)){
496 : //reject command if no recipients
497 33 : if(!client_data->current_mail.forward_paths[0]){
498 2 : logprintf(log, LOG_INFO, "Data without recipients\n");
499 2 : client_send(log, client, "503 No valid recipients\r\n");
500 2 : return -1;
501 : }
502 31 : client_data->state = STATE_DATA;
503 :
504 : //write received: header
505 31 : if(mail_recvheader(log, &(client_data->current_mail), listener_data->announce_domain, listener_data->suppress_submitter) < 0){
506 0 : logprintf(log, LOG_WARNING, "Failed to write received header\n");
507 : }
508 :
509 31 : logprintf(log, LOG_INFO, "Client begins data transmission\n");
510 :
511 31 : client_send(log, client, "354 Go ahead\r\n");
512 31 : return 0;
513 : }
514 :
515 1 : logprintf(log, LOG_INFO, "Command not recognized in state RECIPIENTS: %s\n", client_data->recv_buffer);
516 1 : client_send(log, client, "500 Unknown command\r\n");
517 1 : return -1;
518 : }
519 :
520 102 : int smtpstate_data(LOGGER log, CONNECTION* client, DATABASE* database, PATHPOOL* path_pool){
521 102 : CLIENT* client_data = (CLIENT*)client->aux_data;
522 :
523 102 : if(client_data->recv_buffer[0] == '.'){
524 31 : if(client_data->recv_buffer[1]){
525 0 : logprintf(log, LOG_INFO, "Data line with leading dot, fixing\n");
526 : //skip leading dot
527 : //FIXME use return value (might indicate message too long)
528 0 : if(mail_line(log, &(client_data->current_mail), client_data->recv_buffer + 1) < 0){
529 0 : logprintf(log, LOG_WARNING, "Failed to store mail data line\n");
530 : }
531 0 : return 0;
532 : }
533 : else{
534 : //end of mail data signalled
535 : //check if mail was too big
536 31 : if(client_data->current_mail.data_max && client_data->current_mail.data_offset > client_data->current_mail.data_max){
537 0 : logprintf(log, LOG_WARNING, "End of mail, data section exceeded size limitation, rejecting\n");
538 0 : client_send(log, client, "552 Size limit exceeded\r\n");
539 : }
540 : //check for too many hops
541 31 : else if(client_data->current_mail.hop_count > CMAIL_MAX_HOPS){
542 0 : logprintf(log, LOG_WARNING, "Mail exceeded maximum hop count of %d", CMAIL_MAX_HOPS);
543 0 : client_send(log, client, "554 Too many hops\r\n");
544 : }
545 : else{
546 31 : logprintf(log, LOG_INFO, "End of mail data, routing\n");
547 :
548 : //TODO call plugins here
549 31 : if(!client_data->sasl_user.authenticated){
550 21 : switch(mail_route(log, &(client_data->current_mail), database)){
551 : case 250:
552 18 : logprintf(log, LOG_INFO, "Incoming mail accepted from %s\n", client_data->peer_name);
553 18 : client_send(log, client, "250 OK\r\n");
554 18 : break;
555 : case 400:
556 0 : logprintf(log, LOG_INFO, "Temporary routing failure, deferring message\n");
557 0 : client_send(log, client, "451 Temporary failure, please try again later. If the error persists, contact the administrator.\r\n");
558 0 : break;
559 : default:
560 3 : logprintf(log, LOG_WARNING, "Mail not routed, rejecting\n");
561 3 : client_send(log, client, "554 Rejected\r\n");
562 3 : break;
563 : }
564 : }
565 : else{
566 10 : switch(mail_originate(log, client_data->sasl_user.authorized, &(client_data->current_mail), client_data->originating_route, database)){
567 : case 250:
568 7 : logprintf(log, LOG_INFO, "Originating mail accepted for user %s (auth %s) from %s\n", client_data->sasl_user.authorized, client_data->sasl_user.authenticated, client_data->peer_name);
569 7 : client_send(log, client, "250 OK\r\n");
570 7 : break;
571 : case 400:
572 0 : logprintf(log, LOG_INFO, "Temporary routing failure, deferring message\n");
573 0 : client_send(log, client, "451 Temporary failure, please try again later. If the error persists, contact the administrator.\r\n");
574 0 : break;
575 : default:
576 3 : logprintf(log, LOG_WARNING, "Originated mail could not be routed, rejecting\n");
577 3 : client_send(log, client, "554 Rejected\r\n");
578 3 : break;
579 : }
580 : }
581 : }
582 31 : mail_reset(&(client_data->current_mail));
583 31 : client_data->state=STATE_IDLE;
584 : }
585 : }
586 : else{
587 : //detect end of header & count hops
588 71 : if(client_data->current_mail.header_offset == 0){
589 : //header end
590 43 : if(client_data->recv_buffer[0] == 0){
591 4 : client_data->current_mail.header_offset = client_data->current_mail.data_offset;
592 4 : logprintf(log, LOG_DEBUG, "End of header detected at %d\n", client_data->current_mail.header_offset);
593 : }
594 : //count Received: headers
595 39 : else if(!strncmp(client_data->recv_buffer, "Received: ", 10)){
596 0 : client_data->current_mail.hop_count++;
597 0 : logprintf(log, LOG_DEBUG, "Mail is now at %d hops\n", client_data->current_mail.hop_count);
598 : }
599 : }
600 :
601 : //FIXME use return value (might indicate message too long)
602 71 : if(mail_line(log, &(client_data->current_mail), client_data->recv_buffer) < 0){
603 0 : logprintf(log, LOG_WARNING, "Failed to store mail data line\n");
604 : }
605 71 : return 0;
606 : }
607 :
608 31 : return 0;
609 : }
|