1 /**************************************************************************/
2 /* */
3 /* Copyright (c) Microsoft Corporation. All rights reserved. */
4 /* */
5 /* This software is licensed under the Microsoft Software License */
6 /* Terms for Microsoft Azure RTOS. Full text of the license can be */
7 /* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
8 /* and in the root directory of this software. */
9 /* */
10 /**************************************************************************/
11
12 /**************************************************************************/
13 /**************************************************************************/
14 /** */
15 /** */
16 /** NetX SMTP Client Component */
17 /** */
18 /** Simple Mail Transfer Protocol (SMTP) */
19 /** */
20 /**************************************************************************/
21 /**************************************************************************/
22
23
24 #define NX_SMTP_SOURCE_CODE
25
26
27 /* Force error checking to be disabled in this module. */
28
29 #ifndef NX_DISABLE_ERROR_CHECKING
30 #define NX_DISABLE_ERROR_CHECKING
31 #endif
32
33
34
35 #include "ctype.h"
36 #include "nx_api.h"
37 #include "nx_ip.h"
38 #include "nx_ipv4.h"
39 #include "nxd_smtp_client.h"
40 #ifdef FEATURE_NX_IPV6
41 #include "nx_ipv6.h"
42 #endif
43 #include "nx_tcp.h"
44
45 /* Necessary for threadx thread state macros. */
46 extern TX_THREAD *_tx_thread_current_ptr;
47 extern TX_THREAD _tx_timer_thread;
48 extern volatile ULONG _tx_thread_system_state;
49
50 #define NX_SMTP_BUFFER_SIZE 512
51 static CHAR _nx_smtp_buffer[NX_SMTP_BUFFER_SIZE];
52
53
54 /* Define internal SMTP Client functions. */
55
56 static VOID _nx_smtp_find_crlf(UCHAR *buffer, UINT length, UCHAR **CRLF, UINT reverse);
57 static UINT _nx_smtp_cmd_idle(NX_SMTP_CLIENT *client_ptr);
58 static UINT _nx_smtp_rsp_idle(NX_SMTP_CLIENT *client_ptr);
59 static UINT _nx_smtp_cmd_greeting(NX_SMTP_CLIENT *client_ptr);
60 static UINT _nx_smtp_rsp_greeting(NX_SMTP_CLIENT *client_ptr);
61 static UINT _nx_smtp_cmd_ehlo(NX_SMTP_CLIENT *client_ptr);
62 static UINT _nx_smtp_rsp_ehlo(NX_SMTP_CLIENT *client_ptr);
63 static UINT _nx_smtp_cmd_helo(NX_SMTP_CLIENT *client_ptr);
64 static UINT _nx_smtp_rsp_helo(NX_SMTP_CLIENT *client_ptr);
65 static UINT _nx_smtp_cmd_mail(NX_SMTP_CLIENT *client_ptr);
66 static UINT _nx_smtp_rsp_mail(NX_SMTP_CLIENT *client_ptr);
67 static UINT _nx_smtp_cmd_rcpt(NX_SMTP_CLIENT *client_ptr);
68 static UINT _nx_smtp_rsp_rcpt(NX_SMTP_CLIENT *client_ptr);
69 static UINT _nx_smtp_cmd_data(NX_SMTP_CLIENT *client_ptr);
70 static UINT _nx_smtp_rsp_data(NX_SMTP_CLIENT *client_ptr);
71 static UINT _nx_smtp_cmd_message(NX_SMTP_CLIENT *client_ptr);
72 static UINT _nx_smtp_rsp_message(NX_SMTP_CLIENT *client_ptr);
73 static UINT _nx_smtp_cmd_rset(NX_SMTP_CLIENT *client_ptr);
74 static UINT _nx_smtp_rsp_rset(NX_SMTP_CLIENT *client_ptr);
75 static UINT _nx_smtp_cmd_quit(NX_SMTP_CLIENT *client_ptr);
76 static UINT _nx_smtp_rsp_quit(NX_SMTP_CLIENT *client_ptr);
77 static UINT _nx_smtp_cmd_noop(NX_SMTP_CLIENT *client_ptr);
78 static UINT _nx_smtp_rsp_noop(NX_SMTP_CLIENT *client_ptr);
79 static UINT _nx_smtp_cmd_auth(NX_SMTP_CLIENT *client_ptr);
80 static UINT _nx_smtp_rsp_auth(NX_SMTP_CLIENT *client_ptr);
81 static UINT _nx_smtp_cmd_auth_challenge(NX_SMTP_CLIENT *client_ptr);
82 static UINT _nx_smtp_rsp_auth_challenge(NX_SMTP_CLIENT *client_ptr);
83 static UINT _nx_smtp_rsp_hello_command(NX_SMTP_CLIENT* client_ptr);
84 static UINT _nx_smtp_utility_read_server_code(NX_SMTP_CLIENT *client_ptr, ULONG timeout, UINT receive_all_lines);
85 static UINT _nx_smtp_utility_send_to_server(NX_SMTP_CLIENT *client_ptr, CHAR *buffer_ptr, UINT buffer_length, ULONG timeout);
86 static UINT _nx_smtp_utility_authentication_challenge(NX_SMTP_CLIENT *client_ptr, UCHAR *buffer_ptr, UINT length);
87 static UINT _nx_smtp_client_process(NX_SMTP_CLIENT *client_ptr);
88 static UINT _nx_smtp_utility_send_header_to_server(NX_SMTP_CLIENT *client_ptr, ULONG timeout) ;
89 static VOID _nx_smtp_utility_parse_server_services(NX_SMTP_CLIENT *client_ptr);
90 static UINT _nx_smtp_parse_250_response(UCHAR *buffer_ptr, UINT buffer_length, UINT *is_last_code);
91 static UINT _nx_smtp_parse_response(NX_SMTP_CLIENT *client_ptr, UCHAR *buffer, UINT arguement_index,
92 UINT buffer_length, UCHAR *arguement, UINT arguement_length,
93 UINT include_crlf);
94
95 static NX_SMTP_CLIENT_STATES protocol_states[] =
96 {
97 {_nx_smtp_cmd_idle , _nx_smtp_rsp_idle},
98 {_nx_smtp_cmd_greeting , _nx_smtp_rsp_greeting},
99 {_nx_smtp_cmd_ehlo , _nx_smtp_rsp_ehlo},
100 {_nx_smtp_cmd_helo , _nx_smtp_rsp_helo},
101 {_nx_smtp_cmd_mail , _nx_smtp_rsp_mail},
102 {_nx_smtp_cmd_rcpt , _nx_smtp_rsp_rcpt},
103 {_nx_smtp_cmd_data , _nx_smtp_rsp_data},
104 {_nx_smtp_cmd_message , _nx_smtp_rsp_message},
105 {_nx_smtp_cmd_rset , _nx_smtp_rsp_rset},
106 {_nx_smtp_cmd_quit , _nx_smtp_rsp_quit},
107 {_nx_smtp_cmd_noop , _nx_smtp_rsp_noop},
108 {_nx_smtp_cmd_auth , _nx_smtp_rsp_auth},
109 {_nx_smtp_cmd_auth_challenge , _nx_smtp_rsp_auth_challenge},
110 };
111
112
113
114
115 /**************************************************************************/
116 /* */
117 /* FUNCTION RELEASE */
118 /* */
119 /* _nxde_smtp_client_create PORTABLE C */
120 /* 6.1 */
121 /* AUTHOR */
122 /* */
123 /* Yuxin Zhou, Microsoft Corporation */
124 /* */
125 /* DESCRIPTION */
126 /* */
127 /* This function performs error checking on the client create service. */
128 /* */
129 /* Note: The string lengths of username,password,from_address and */
130 /* client_domain are limited by internal buffer size. */
131 /* */
132 /* INPUT */
133 /* */
134 /* */
135 /* client_ptr Pointer to SMTP Client instance */
136 /* ip_ptr Pointer to IP instance */
137 /* packet_pool_ptr Pointer to client packet pool */
138 /* username Pointer to username */
139 /* password Pointer to password */
140 /* from_address Pointer to Client email address */
141 /* client_domain Pointer to client domain */
142 /* authentication_type SMTP authentication type */
143 /* server_address Pointer to server address */
144 /* server_port SMTP server TCP port */
145 /* */
146 /* OUTPUT */
147 /* */
148 /* NX_PTR_ERROR Invalid pointer parameter */
149 /* NX_SMTP_INVALID_PARAM Invalid non pointer input */
150 /* status Actual completion status */
151 /* */
152 /* CALLS */
153 /* */
154 /* _nxd_smtp_client_create Actual SMTP client create service */
155 /* */
156 /* CALLED BY */
157 /* */
158 /* Application Code */
159 /* */
160 /* RELEASE HISTORY */
161 /* */
162 /* DATE NAME DESCRIPTION */
163 /* */
164 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
165 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
166 /* resulting in version 6.1 */
167 /* */
168 /**************************************************************************/
_nxde_smtp_client_create(NX_SMTP_CLIENT * client_ptr,NX_IP * ip_ptr,NX_PACKET_POOL * client_packet_pool_ptr,CHAR * username,CHAR * password,CHAR * from_address,CHAR * client_domain,UINT authentication_type,NXD_ADDRESS * server_address,UINT port)169 UINT _nxde_smtp_client_create(NX_SMTP_CLIENT *client_ptr, NX_IP *ip_ptr, NX_PACKET_POOL *client_packet_pool_ptr,
170 CHAR *username, CHAR *password, CHAR *from_address,
171 CHAR *client_domain, UINT authentication_type,
172 NXD_ADDRESS *server_address, UINT port)
173 {
174
175 UINT status;
176
177
178 if ((ip_ptr == NX_NULL) || (client_ptr == NX_NULL) || (client_packet_pool_ptr == NX_NULL) ||
179 (from_address == NX_NULL) || (username == NX_NULL) || (password == NX_NULL) ||
180 (client_domain == NX_NULL) || (server_address == NX_NULL))
181 {
182
183 /* Return error status. */
184 return(NX_PTR_ERROR);
185 }
186
187 /* Check for invalid non pointer input. */
188 if (ip_ptr -> nx_ip_id != NX_IP_ID)
189 {
190
191 return NX_SMTP_INVALID_PARAM;
192 }
193
194
195 /* Make sure the IP version is set correctly. */
196 if((server_address -> nxd_ip_version != NX_IP_VERSION_V4) &&
197 (server_address -> nxd_ip_version != NX_IP_VERSION_V6))
198 {
199 return(NX_IP_ADDRESS_ERROR);
200 }
201
202 /* Call the actual client create service. */
203 status = _nxd_smtp_client_create(client_ptr, ip_ptr, client_packet_pool_ptr, username, password,
204 from_address, client_domain, authentication_type,
205 server_address, port);
206
207 /* Return completion status. */
208 return(status);
209 }
210
211
212 /**************************************************************************/
213 /* */
214 /* FUNCTION RELEASE */
215 /* */
216 /* _nxd_smtp_client_create PORTABLE C */
217 /* 6.1 */
218 /* AUTHOR */
219 /* */
220 /* Yuxin Zhou, Microsoft Corporation */
221 /* */
222 /* DESCRIPTION */
223 /* */
224 /* This function creates a SMTP client instance for sending mail to an */
225 /* SMTP Server over IPv4 or IPv6 networks. It also creates the TCP */
226 /* socket for making connections with the SMTP server, sets the */
227 /* server IP address and port, and sets the Client username and SMTP */
228 /* address (from address) used in all SMTP mail transmissions. */
229 /* */
230 /* Note: The string lengths of username,password,from_address and */
231 /* client_domain are limited by internal buffer size. */
232 /* */
233 /* INPUT */
234 /* */
235 /* client_ptr Pointer to SMTP Client instance */
236 /* ip_ptr Pointer to IP instance */
237 /* packet_pool_ptr Pointer to client packet pool */
238 /* username Pointer to username */
239 /* password Pointer to password */
240 /* from_address Pointer to Client email address */
241 /* client_domain Pointer to client domain */
242 /* authentication_type SMTP authentication type */
243 /* server_address Pointer to server address */
244 /* server_port SMTP server TCP port */
245 /* */
246 /* OUTPUT */
247 /* */
248 /* NX_SUCCESS Successful completion status */
249 /* status Actual completion status */
250 /* */
251 /* CALLED BY */
252 /* */
253 /* Application Code */
254 /* */
255 /* CALLS */
256 /* */
257 /* memset Clear area of memory */
258 /* memcpy Copy data to area of memory */
259 /* nx_tcp_socket_create Create a NetX TCP socket */
260 /* */
261 /* RELEASE HISTORY */
262 /* */
263 /* DATE NAME DESCRIPTION */
264 /* */
265 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
266 /* 09-30-2020 Yuxin Zhou Modified comment(s), and */
267 /* verified memcpy use cases, */
268 /* resulting in version 6.1 */
269 /* */
270 /**************************************************************************/
_nxd_smtp_client_create(NX_SMTP_CLIENT * client_ptr,NX_IP * ip_ptr,NX_PACKET_POOL * client_packet_pool_ptr,CHAR * username,CHAR * password,CHAR * from_address,CHAR * client_domain,UINT authentication_type,NXD_ADDRESS * server_address,UINT port)271 UINT _nxd_smtp_client_create(NX_SMTP_CLIENT *client_ptr, NX_IP *ip_ptr, NX_PACKET_POOL *client_packet_pool_ptr,
272 CHAR *username, CHAR *password, CHAR *from_address,
273 CHAR *client_domain, UINT authentication_type,
274 NXD_ADDRESS *server_address, UINT port)
275 {
276
277 UINT status = NX_SUCCESS;
278 UINT str_length;
279 NX_SMTP_CLIENT_MAIL *mail_ptr;
280
281
282 /* Initialize client as not ready for SMTP yet. */
283 client_ptr -> nx_smtp_client_init_status = NX_FALSE;
284
285 mail_ptr = &client_ptr -> nx_smtp_client_mail;
286
287 /* Clear the Client and session memory. */
288 memset(client_ptr, 0, sizeof(NX_SMTP_CLIENT));
289
290 /* Configure client with input parameters. */
291 status = _nx_utility_string_length_check(username, &str_length, NX_SMTP_CLIENT_MAX_USERNAME);
292 if (status)
293 {
294 return(status);
295 }
296
297 memcpy(client_ptr -> nx_smtp_username, username, str_length); /* Use case of memcpy is verified. */
298
299 status = _nx_utility_string_length_check(password, &str_length, NX_SMTP_CLIENT_MAX_PASSWORD);
300 if (status)
301 {
302 return(status);
303 }
304
305 memcpy(client_ptr -> nx_smtp_password, password, str_length); /* Use case of memcpy is verified. */
306
307 status = _nx_utility_string_length_check(client_domain, &str_length, NX_SMTP_CLIENT_MAX_USERNAME);
308 if (status)
309 {
310 return(status);
311 }
312
313 memcpy(client_ptr -> nx_smtp_client_domain, client_domain, str_length); /* Use case of memcpy is verified. */
314
315 /* Set the mail server IP address and port number. */
316
317 #ifdef FEATURE_NX_IPV6
318 client_ptr -> nx_smtp_server_address.nxd_ip_version = server_address -> nxd_ip_version;
319 client_ptr -> nx_smtp_server_address.nxd_ip_address.v6[0] = server_address -> nxd_ip_address.v6[0] ;
320 client_ptr -> nx_smtp_server_address.nxd_ip_address.v6[1] = server_address -> nxd_ip_address.v6[1] ;
321 client_ptr -> nx_smtp_server_address.nxd_ip_address.v6[2] = server_address -> nxd_ip_address.v6[2] ;
322 client_ptr -> nx_smtp_server_address.nxd_ip_address.v6[3] = server_address -> nxd_ip_address.v6[3] ;
323 #else
324
325 client_ptr -> nx_smtp_server_address.nxd_ip_version = server_address -> nxd_ip_version;
326 client_ptr -> nx_smtp_server_address.nxd_ip_address.v4 = server_address -> nxd_ip_address.v4;
327 #endif
328 client_ptr -> nx_smtp_server_port = (port & 0xFFFF);
329
330 /* Set up the "from" address. */
331 mail_ptr -> nx_smtp_client_mail_from_address = from_address;
332
333 /* Check if authentication type is specified. */
334 if ((authentication_type != NX_SMTP_CLIENT_AUTH_PLAIN) &&
335 (authentication_type != NX_SMTP_CLIENT_AUTH_LOGIN) &&
336 (authentication_type != NX_SMTP_CLIENT_AUTH_NONE))
337 {
338
339 /* No. Set the default authentication type. */
340 authentication_type = NX_SMTP_CLIENT_AUTH_PLAIN;
341 }
342
343 client_ptr -> nx_smtp_client_authentication_type = authentication_type;
344
345 /* Configure client IP options. */
346 client_ptr -> nx_smtp_client_ip_ptr = ip_ptr;
347 client_ptr -> nx_smtp_client_packet_pool_ptr = client_packet_pool_ptr;
348
349 /* Set the Client ID to indicate the SMTP client thread is ready. */
350 client_ptr -> nx_smtp_client_id = NX_SMTP_CLIENT_ID;
351
352 /* Create a tcp socket to send/receive SMTP data. */
353 status = nx_tcp_socket_create(client_ptr -> nx_smtp_client_ip_ptr,
354 &client_ptr -> nx_smtp_client_socket, "SMTP Client socket",
355 NX_IP_NORMAL, NX_FRAGMENT_OKAY, NX_IP_TIME_TO_LIVE,
356 NX_SMTP_CLIENT_TCP_WINDOW_SIZE,
357 NX_NULL, NX_NULL);
358
359 /* Check for error. */
360 if (status != NX_SUCCESS)
361 {
362
363 /* Return error status. */
364 return(status);
365 }
366
367 /* Initialize client as ready for conducting an SMTP session. */
368 client_ptr -> nx_smtp_client_init_status = NX_TRUE;
369
370 return(status);
371 }
372
373
374 /**************************************************************************/
375 /* */
376 /* FUNCTION RELEASE */
377 /* */
378 /* _nxe_smtp_client_delete PORTABLE C */
379 /* 6.1 */
380 /* AUTHOR */
381 /* */
382 /* Yuxin Zhou, Microsoft Corporation */
383 /* */
384 /* DESCRIPTION */
385 /* */
386 /* This function checks for errors on the client delete service. */
387 /* */
388 /* INPUT */
389 /* */
390 /* client_ptr Pointer to client struct */
391 /* */
392 /* OUTPUT */
393 /* */
394 /* NX_PTR_ERROR Invalid pointer parameter */
395 /* status Actual completion status */
396 /* */
397 /* CALLS */
398 /* */
399 /* _nx_smtp_client_delete Actual SMTP client delete service */
400 /* */
401 /* CALLED BY */
402 /* */
403 /* Application Code */
404 /* */
405 /* RELEASE HISTORY */
406 /* */
407 /* DATE NAME DESCRIPTION */
408 /* */
409 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
410 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
411 /* resulting in version 6.1 */
412 /* */
413 /**************************************************************************/
_nxe_smtp_client_delete(NX_SMTP_CLIENT * client_ptr)414 UINT _nxe_smtp_client_delete(NX_SMTP_CLIENT *client_ptr)
415 {
416
417 UINT status;
418
419
420 /* Check for the validity of input parameter. */
421 if ((client_ptr == NX_NULL) || (client_ptr -> nx_smtp_client_id != NX_SMTP_CLIENT_ID))
422 {
423
424 /* Return error status. */
425 return(NX_PTR_ERROR);
426 }
427
428 /* Call the actual client create service. */
429 status = _nx_smtp_client_delete(client_ptr);
430
431 /* Return completion status. */
432 return(status);
433 }
434
435
436 /**************************************************************************/
437 /* */
438 /* FUNCTION RELEASE */
439 /* */
440 /* _nx_smtp_client_delete PORTABLE C */
441 /* 6.1 */
442 /* AUTHOR */
443 /* */
444 /* Yuxin Zhou, Microsoft Corporation */
445 /* */
446 /* DESCRIPTION */
447 /* */
448 /* This function deletes a previously created SMTP client and releases */
449 /* all client resources (sockets, packet pools). */
450 /* */
451 /* INPUT */
452 /* */
453 /* client_ptr Pointer to SMTP Client instance */
454 /* */
455 /* OUTPUT */
456 /* */
457 /* NX_SUCCESS Successful completion status */
458 /* status Actual completion status */
459 /* */
460 /* CALLS */
461 /* */
462 /* _nx_smtp_session_delete Delete the SMTP Client session */
463 /* */
464 /* CALLED BY */
465 /* */
466 /* Application Code */
467 /* */
468 /* RELEASE HISTORY */
469 /* */
470 /* DATE NAME DESCRIPTION */
471 /* */
472 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
473 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
474 /* resulting in version 6.1 */
475 /* */
476 /**************************************************************************/
_nx_smtp_client_delete(NX_SMTP_CLIENT * client_ptr)477 UINT _nx_smtp_client_delete(NX_SMTP_CLIENT *client_ptr)
478 {
479
480 UINT status;
481
482
483 if ((client_ptr -> nx_smtp_client_socket).nx_tcp_socket_state == NX_TCP_ESTABLISHED)
484 {
485
486 nx_tcp_socket_disconnect(&client_ptr -> nx_smtp_client_socket, NX_SMTP_CLIENT_DISCONNECT_TIMEOUT);
487
488 nx_tcp_client_socket_unbind(&client_ptr -> nx_smtp_client_socket);
489 }
490
491 status = nx_tcp_socket_delete(&(client_ptr -> nx_smtp_client_socket));
492
493 /* Check status. */
494 if (status)
495 {
496 return status;
497 }
498
499 /* Clear client memory. */
500 memset(client_ptr, 0, sizeof(NX_SMTP_CLIENT));
501
502 /* Return success status. */
503 return(NX_SUCCESS);
504 }
505
506
507
508 /**************************************************************************/
509 /* */
510 /* FUNCTION RELEASE */
511 /* */
512 /* _nxe_smtp_mail_send PORTABLE C */
513 /* 6.1 */
514 /* AUTHOR */
515 /* */
516 /* Yuxin Zhou, Microsoft Corporation */
517 /* */
518 /* DESCRIPTION */
519 /* */
520 /* This function checks for errors on the mail send service. */
521 /* */
522 /* Note: The string lengths of recipient_address and subject are */
523 /* limited by internal buffer size. */
524 /* */
525 /* INPUT */
526 /* */
527 /* client_ptr Pointer to Client instance */
528 /* recipient_address Pointer to recipient (To) address */
529 /* priority Mail send priority level */
530 /* subject Pointer to mail subject text */
531 /* mail_body Pointer to mail message text */
532 /* mail_body_length Size of mail message text */
533 /* */
534 /* OUTPUT */
535 /* */
536 /* NX_PTR_ERROR Invalid pointer parameter */
537 /* status Actual completion status */
538 /* */
539 /* CALLS */
540 /* */
541 /* _nx_smtp_mail_send Actual SMTP mail send service */
542 /* */
543 /* CALLED BY */
544 /* */
545 /* Application Code */
546 /* */
547 /* RELEASE HISTORY */
548 /* */
549 /* DATE NAME DESCRIPTION */
550 /* */
551 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
552 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
553 /* resulting in version 6.1 */
554 /* */
555 /**************************************************************************/
_nxe_smtp_mail_send(NX_SMTP_CLIENT * client_ptr,CHAR * recipient_address,UINT priority,CHAR * subject,CHAR * mail_body,UINT mail_body_length)556 UINT _nxe_smtp_mail_send(NX_SMTP_CLIENT *client_ptr, CHAR *recipient_address, UINT priority,
557 CHAR *subject, CHAR *mail_body, UINT mail_body_length)
558 {
559
560 UINT status;
561
562
563 /* Check for invalid pointer input. */
564 if((client_ptr == NX_NULL) || (recipient_address == NX_NULL) ||
565 (mail_body == NX_NULL) || (subject == NX_NULL))
566
567 {
568 return NX_PTR_ERROR;
569 }
570
571 if (mail_body_length == 0)
572 {
573 return NX_SMTP_INVALID_PARAM;
574 }
575
576 /* Check if this function is called from the appropriate thread. */
577 NX_THREADS_ONLY_CALLER_CHECKING
578
579 status = _nx_smtp_mail_send(client_ptr, recipient_address, priority,
580 subject, mail_body, mail_body_length);
581
582 return status;
583 }
584
585 /**************************************************************************/
586 /* */
587 /* FUNCTION RELEASE */
588 /* */
589 /* _nx_smtp_mail_send PORTABLE C */
590 /* 6.1 */
591 /* AUTHOR */
592 /* */
593 /* Yuxin Zhou, Microsoft Corporation */
594 /* */
595 /* DESCRIPTION */
596 /* */
597 /* This function creates and sends an SMTP mail item with the input */
598 /* parameters for a previously created SMTP Client. It supports IPv4 */
599 /* and IPv6 connections. */
600 /* */
601 /* Before calling this service, the SMTP application must initialize */
602 /* the SMTP Client (nx_smtp_client_init). Thereafter it need not */
603 /* reinitialize the SMTP Client to send subsequent mail items. */
604 /* */
605 /* This service assumes the syntax of the from_address is correct. */
606 /* */
607 /* Note: The string lengths of recipient_address and subject are */
608 /* limited by internal buffer size. */
609 /* */
610 /* INPUT */
611 /* */
612 /* client_ptr Pointer to Client instance */
613 /* recipient_address Pointer to recipient (To) address */
614 /* priority Mail send priority level */
615 /* subject Pointer to mail subject text */
616 /* mail_body Pointer to mail message text */
617 /* mail_body_length Size of mail message text */
618 /* */
619 /* OUTPUT */
620 /* */
621 /* NX_SUCCESS Success completion status */
622 /* status Actual completion status */
623 /* */
624 /* CALLS */
625 /* */
626 /* memset Clear data in memory */
627 /* _nx_smtp_client_process Conducts SMTP session for */
628 /* transmitting mail message */
629 /* */
630 /* CALLED BY */
631 /* */
632 /* Application Code */
633 /* */
634 /* RELEASE HISTORY */
635 /* */
636 /* DATE NAME DESCRIPTION */
637 /* */
638 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
639 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
640 /* resulting in version 6.1 */
641 /* */
642 /**************************************************************************/
_nx_smtp_mail_send(NX_SMTP_CLIENT * client_ptr,CHAR * recipient_address,UINT priority,CHAR * subject,CHAR * mail_body,UINT mail_body_length)643 UINT _nx_smtp_mail_send(NX_SMTP_CLIENT *client_ptr,
644 CHAR *recipient_address,
645 UINT priority, CHAR *subject,
646 CHAR *mail_body, UINT mail_body_length)
647 {
648
649 UINT status;
650 NX_SMTP_CLIENT_MAIL *mail_ptr;
651
652
653 client_ptr -> nx_smtp_client_mute = NX_FALSE;
654
655 /* Verify Client is properly set up and ready to conduct an SMTP session. */
656 if (client_ptr -> nx_smtp_client_init_status != NX_TRUE)
657 {
658 return NX_SMTP_CLIENT_NOT_INTIALIZED;
659 }
660
661 /* Initialize the Client to idle. */
662 client_ptr -> nx_smtp_client_cmd_state = NX_SMTP_CLIENT_STATE_IDLE;
663 client_ptr -> nx_smtp_client_rsp_state = NX_SMTP_CLIENT_STATE_IDLE;
664
665
666 /* Set local variables for convenience. */
667 mail_ptr = &client_ptr -> nx_smtp_client_mail;
668
669 /* Did we get a valid priority type? */
670 if ((priority != NX_SMTP_MAIL_PRIORITY_LOW) &&
671 (priority != NX_SMTP_MAIL_PRIORITY_NORMAL) &&
672 (priority != NX_SMTP_MAIL_PRIORITY_HIGH))
673 {
674
675 /* No, default priority to normal. */
676 mail_ptr -> nx_smtp_client_mail_priority = NX_SMTP_MAIL_PRIORITY_NORMAL;
677 }
678 else
679 {
680
681 /* Yes, apply it to the session priority. */
682 mail_ptr -> nx_smtp_client_mail_priority = priority;
683 }
684 mail_ptr -> nx_smtp_client_mail_subject = subject;
685 mail_ptr -> nx_smtp_client_mail_body = mail_body;
686 mail_ptr -> nx_smtp_client_mail_body_length = mail_body_length;
687 mail_ptr -> nx_smtp_client_mail_recipient_address = recipient_address;
688
689 /* Mark mail item as unsent */
690 client_ptr -> nx_smtp_client_mail_status = NX_SUCCESS;
691
692 /* Set up the recipient. */
693
694 /* Set up a local pointer to the session for convenience. */
695
696 /* Set session members to initial values. */
697 client_ptr -> nx_smtp_client_authentication_state = NX_SMTP_NOT_AUTHENTICATED;
698 client_ptr -> nx_smtp_client_reply_code_status = 0;
699
700 /* Start this session by setting the state to the first step in SMTP Protocol, greeting. */
701 client_ptr -> nx_smtp_client_cmd_state = NX_SMTP_CLIENT_STATE_GREETING;
702 client_ptr -> nx_smtp_client_rsp_state = NX_SMTP_CLIENT_STATE_GREETING;
703
704 status = _nx_smtp_client_process(client_ptr);
705
706 /* Return success status. */
707 return(status);
708
709 }
710
711 /**************************************************************************/
712 /* */
713 /* FUNCTION RELEASE */
714 /* */
715 /* _nx_smtp_client_process PORTABLE C */
716 /* 6.1 */
717 /* AUTHOR */
718 /* */
719 /* Yuxin Zhou, Microsoft Corporation */
720 /* */
721 /* DESCRIPTION */
722 /* */
723 /* This function executes the SMTP client state machine to transmit a */
724 /* previously created mail item to an SMTP server. For more details, */
725 /* See nx_smtp_mail_send. */
726 /* */
727 /* INPUT */
728 /* */
729 /* client_ptr Pointer to SMTP Client instance */
730 /* */
731 /* OUTPUT */
732 /* */
733 /* NX_SUCCESS Success completion status */
734 /* status Actual completion status */
735 /* */
736 /* CALLS */
737 /* nx_tcp_client_socket_bind Bind NetX TCP socket to local port */
738 /* nx_tcp_client_socket_unbind Release port from NetX TCP socket */
739 /* nx_tcp_client_socket_connect Connect to a TCP server socket */
740 /* nx_tcp_client_socket_disconnect Disconnect from TCP server socket */
741 /* */
742 /* CALLED BY */
743 /* */
744 /* Application Code */
745 /* */
746 /* RELEASE HISTORY */
747 /* */
748 /* DATE NAME DESCRIPTION */
749 /* */
750 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
751 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
752 /* resulting in version 6.1 */
753 /* */
754 /**************************************************************************/
_nx_smtp_client_process(NX_SMTP_CLIENT * client_ptr)755 static UINT _nx_smtp_client_process(NX_SMTP_CLIENT *client_ptr)
756 {
757
758 UINT status;
759 UINT close_connection = NX_FALSE;
760
761
762 /* Initialize completion status to successful outcome. */
763 status = NX_SUCCESS;
764
765 /* Run the SMTP protocol state machine till session terminates. */
766 while (status == NX_SUCCESS)
767 {
768
769 /* Check if we are starting a mail transaction. */
770 if (client_ptr -> nx_smtp_client_cmd_state == NX_SMTP_CLIENT_STATE_GREETING)
771 {
772
773 /* We are so we need to set up a connection. Bind the socket to client port. */
774 status = nx_tcp_client_socket_bind(&client_ptr -> nx_smtp_client_socket, NX_ANY_PORT, 100);
775
776 /* Check for error. */
777 if (status != NX_SUCCESS)
778 {
779
780 /* Reset the Client to idle. The caller must resend the email. */
781 client_ptr -> nx_smtp_client_cmd_state = NX_SMTP_CLIENT_STATE_IDLE;
782 client_ptr -> nx_smtp_client_rsp_state = NX_SMTP_CLIENT_STATE_IDLE;
783
784 return status;
785 }
786
787 /* Connect to the SMTP server using our tcp socket. */
788 status = nxd_tcp_client_socket_connect(&client_ptr -> nx_smtp_client_socket,
789 &client_ptr -> nx_smtp_server_address,
790 client_ptr -> nx_smtp_server_port,
791 NX_SMTP_CLIENT_CONNECTION_TIMEOUT);
792
793 /* Check for error. */
794 if (status != NX_SUCCESS)
795 {
796
797 nx_tcp_client_socket_unbind(&client_ptr -> nx_smtp_client_socket);
798
799 /* Reset the Client to idle. The caller must resend the email.*/
800 client_ptr -> nx_smtp_client_cmd_state = NX_SMTP_CLIENT_STATE_IDLE;
801 client_ptr -> nx_smtp_client_rsp_state = NX_SMTP_CLIENT_STATE_IDLE;
802 return status;
803 }
804
805 /* Successful connection set up. Now let the Client task process the GREETING command. */
806 }
807
808 /* Is the next command waiting the outcome of the previous reply handler? */
809 if ((client_ptr -> nx_smtp_client_cmd_state == NX_SMTP_CLIENT_STATE_AWAITING_REPLY) &&
810 /* Do not advance the state if the client is in mute. */
811 (!client_ptr -> nx_smtp_client_mute))
812 {
813
814 /* Yes, update the session state to the next command to send. */
815 client_ptr -> nx_smtp_client_cmd_state = client_ptr -> nx_smtp_client_rsp_state;
816 }
817
818 if (!client_ptr -> nx_smtp_client_mute)
819 {
820
821 /* Execute the next command in the SMTP state machine. */
822 status = (*protocol_states[client_ptr -> nx_smtp_client_cmd_state].cmd)(client_ptr);
823
824 /* Check for internal error state in the SMTP state machine. */
825 if (status != NX_SUCCESS)
826 {
827
828 /* This is likely an internal error and we need to break off the connection, reset the Client state
829 to an idle state. */
830
831 /* Set the status to close the connection down. */
832 close_connection = NX_TRUE;
833 }
834 }
835
836 /* Reset server reply to null. */
837 client_ptr -> nx_smtp_client_reply_code_status = 0;
838
839 /* Wait for a response unless we are closing the connection, or have
840 encountered an internal error (packet allocation error for example). */
841 if (close_connection == NX_FALSE)
842 {
843
844 /* Awaiting the server reply to the command just sent. */
845 status = (*protocol_states[client_ptr -> nx_smtp_client_rsp_state].rsp)(client_ptr);
846
847 /* Check for internal error state in the SMTP state machine. */
848 if (status != NX_SUCCESS)
849 {
850
851 /* This is an internal error or invalid server reply of some kind. Just shut down the
852 connection, notify the host application and set the Client to idle. */
853
854 /* Set the status to close the connection down. */
855 close_connection = NX_TRUE;
856 }
857
858 /* Are we at the end of the Client state (received a reply to our QUIT message to the server)? */
859 else if (client_ptr -> nx_smtp_client_rsp_state == NX_SMTP_CLIENT_STATE_COMPLETED_NORMALLY)
860 {
861
862 /* Yes, time to close it down and return to an idle state. */
863 close_connection = NX_TRUE;
864 }
865 /* else keep the connection open... */
866 }
867
868 /* Check again if we need to break down the connection. */
869 if (close_connection == NX_TRUE)
870 {
871
872 UINT timeout = 0;
873
874 /* We do. Depending on the reason for closing the connection, set the timeout. If we experienced
875 an internal error, e.g. packet allocation error, we probably won't be able to send
876 a fin or rst packet anyway, so set the timeout to zero and close down the connection.
877
878 RFC 2821 Section 3.9: if client must abort processing due to internal conditions or socket reset,
879 it should handle as error code 451 from the server which is to abort processing immediately.
880 */
881 if (status != NX_SUCCESS)
882 {
883 timeout = NX_NO_WAIT;
884 }
885 else
886 {
887 timeout = NX_SMTP_CLIENT_DISCONNECT_TIMEOUT;
888 }
889
890 /* Disconnect client socket from server. */
891 nx_tcp_socket_disconnect(&client_ptr -> nx_smtp_client_socket, timeout);
892
893 /* Unbind the port from client socket. */
894 nx_tcp_client_socket_unbind(&client_ptr -> nx_smtp_client_socket);
895
896 /* Indicate the Client is idle. */
897 client_ptr -> nx_smtp_client_cmd_state = NX_SMTP_CLIENT_STATE_IDLE;
898 client_ptr -> nx_smtp_client_rsp_state = NX_SMTP_CLIENT_STATE_IDLE;
899
900 /* Did the session terminate normally (e.g. no internal errors)? */
901 if (status == NX_SUCCESS)
902 {
903
904 /* Yes, so set the mail transmit status as the completion status. */
905 status = client_ptr -> nx_smtp_client_mail_status;
906 }
907
908 return status;
909 }
910
911 /* Clear the abort status. */
912 close_connection = NX_FALSE;
913 }
914
915 return status;
916 }
917
918
919 /**************************************************************************/
920 /* */
921 /* FUNCTION RELEASE */
922 /* */
923 /* _nx_smtp_cmd_greeting PORTABLE C */
924 /* 6.1 */
925 /* AUTHOR */
926 /* */
927 /* Yuxin Zhou, Microsoft Corporation */
928 /* */
929 /* DESCRIPTION */
930 /* */
931 /* This is the start of the SMTP Client process for sending an mail */
932 /* item. It sets the client state to send a greeting command to the */
933 /* server. */
934 /* */
935 /* INPUT */
936 /* */
937 /* session_ptr SMTP Session for sending mail */
938 /* */
939 /* OUTPUT */
940 /* */
941 /* NX_SUCCESS Successful completion status */
942 /* */
943 /* CALLS */
944 /* */
945 /* None */
946 /* */
947 /* CALLED BY */
948 /* */
949 /* _nx_smtp_client_process Runs the SMTP state machine */
950 /* */
951 /* RELEASE HISTORY */
952 /* */
953 /* DATE NAME DESCRIPTION */
954 /* */
955 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
956 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
957 /* resulting in version 6.1 */
958 /* */
959 /**************************************************************************/
_nx_smtp_cmd_greeting(NX_SMTP_CLIENT * client_ptr)960 UINT _nx_smtp_cmd_greeting(NX_SMTP_CLIENT *client_ptr)
961 {
962
963
964 /* Set session state to wait on the outcome of the greeting response handler. */
965 client_ptr -> nx_smtp_client_cmd_state = NX_SMTP_CLIENT_STATE_AWAITING_REPLY;
966
967 /* Return successful session status. */
968 return(NX_SUCCESS);
969 }
970
971 /**************************************************************************/
972 /* */
973 /* FUNCTION RELEASE */
974 /* */
975 /* _nx_smtp_cmd_idle PORTABLE C */
976 /* 6.1 */
977 /* AUTHOR */
978 /* */
979 /* Yuxin Zhou, Microsoft Corporation */
980 /* */
981 /* DESCRIPTION */
982 /* */
983 /* Execute the idle state of the SMTP Client (do nothing while waiting */
984 /* for the next send mail request. */
985 /* */
986 /* INPUT */
987 /* */
988 /* session_ptr SMTP Session for sending mail */
989 /* */
990 /* OUTPUT */
991 /* */
992 /* NX_SUCCESS Successful completion status */
993 /* */
994 /* CALLS */
995 /* */
996 /* None */
997 /* */
998 /* CALLED BY */
999 /* */
1000 /* _nx_smtp_client_process Runs the SMTP state machine */
1001 /* */
1002 /* RELEASE HISTORY */
1003 /* */
1004 /* DATE NAME DESCRIPTION */
1005 /* */
1006 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
1007 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
1008 /* resulting in version 6.1 */
1009 /* */
1010 /**************************************************************************/
_nx_smtp_cmd_idle(NX_SMTP_CLIENT * client_ptr)1011 UINT _nx_smtp_cmd_idle(NX_SMTP_CLIENT *client_ptr)
1012 {
1013
1014 client_ptr -> nx_smtp_client_cmd_state = NX_SMTP_CLIENT_STATE_IDLE;
1015
1016 /* Return successful session status. */
1017 return(NX_SUCCESS);
1018 }
1019
1020 /**************************************************************************/
1021 /* */
1022 /* FUNCTION RELEASE */
1023 /* */
1024 /* _nx_smtp_rsp_idle PORTABLE C */
1025 /* 6.1 */
1026 /* AUTHOR */
1027 /* */
1028 /* Yuxin Zhou, Microsoft Corporation */
1029 /* */
1030 /* DESCRIPTION */
1031 /* */
1032 /* Execute the idle state of the SMTP Client (waiting for the next */
1033 /* send mail request). The state machine has a 'response' state for */
1034 /* every command state, so this is the response handler for the idle */
1035 /* state. */
1036 /* */
1037 /* INPUT */
1038 /* */
1039 /* session_ptr SMTP Session for sending mail */
1040 /* */
1041 /* OUTPUT */
1042 /* */
1043 /* NX_SUCCESS Successful completion status */
1044 /* */
1045 /* CALLS */
1046 /* */
1047 /* None */
1048 /* */
1049 /* CALLED BY */
1050 /* */
1051 /* _nx_smtp_client_process Runs the SMTP state machine */
1052 /* */
1053 /* RELEASE HISTORY */
1054 /* */
1055 /* DATE NAME DESCRIPTION */
1056 /* */
1057 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
1058 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
1059 /* resulting in version 6.1 */
1060 /* */
1061 /**************************************************************************/
_nx_smtp_rsp_idle(NX_SMTP_CLIENT * client_ptr)1062 UINT _nx_smtp_rsp_idle(NX_SMTP_CLIENT *client_ptr)
1063 {
1064
1065 client_ptr -> nx_smtp_client_rsp_state = NX_SMTP_CLIENT_STATE_IDLE;
1066
1067 /* Return successful session status. */
1068 return(NX_SUCCESS);
1069 }
1070
1071 /**************************************************************************/
1072 /* */
1073 /* FUNCTION RELEASE */
1074 /* */
1075 /* _nx_smtp_rsp_greeting PORTABLE C */
1076 /* 6.1 */
1077 /* AUTHOR */
1078 /* */
1079 /* Yuxin Zhou, Microsoft Corporation */
1080 /* */
1081 /* DESCRIPTION */
1082 /* */
1083 /* This handles the server's response to the client greeting and set */
1084 /* the next session state and next command to send to the server. */
1085 /* */
1086 /* INPUT */
1087 /* */
1088 /* session_ptr Session to send mail to SMTP Server */
1089 /* */
1090 /* OUTPUT */
1091 /* */
1092 /* NX_SUCCESS Successful completion status */
1093 /* status Actual completion status */
1094 /* */
1095 /* CALLS */
1096 /* */
1097 /* _nx_smtp_utility_read_server_code */
1098 /* Extracts the server reply code and */
1099 /* stores reply text to session buffer */
1100 /* */
1101 /* CALLED BY */
1102 /* */
1103 /* _nx_smtp_client_process Runs the SMTP state machine */
1104 /* */
1105 /* RELEASE HISTORY */
1106 /* */
1107 /* DATE NAME DESCRIPTION */
1108 /* */
1109 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
1110 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
1111 /* resulting in version 6.1 */
1112 /* */
1113 /**************************************************************************/
_nx_smtp_rsp_greeting(NX_SMTP_CLIENT * client_ptr)1114 UINT _nx_smtp_rsp_greeting(NX_SMTP_CLIENT *client_ptr)
1115 {
1116
1117 UINT status;
1118
1119
1120 /* Get the server greeting message. */
1121 status = _nx_smtp_utility_read_server_code(client_ptr, NX_SMTP_GREETING_TIMEOUT, NX_TRUE);
1122
1123 /* Check for error. */
1124 if (status != NX_SUCCESS)
1125 {
1126
1127 /* Return error status. */
1128 return (status);
1129 }
1130
1131 /* Process based on the reply protocol code from server. */
1132 if (client_ptr -> nx_smtp_client_reply_code_status == NX_SMTP_CODE_GREETING_OK)
1133 {
1134
1135 /* Yes, set session state to next state, EHLO. */
1136 client_ptr -> nx_smtp_client_rsp_state = NX_SMTP_CLIENT_STATE_EHLO;
1137 }
1138 else
1139 {
1140
1141 /* All other codes. */
1142
1143 /* Server did not accept the greeting, exit session gracefully. */
1144 client_ptr -> nx_smtp_client_rsp_state = NX_SMTP_CLIENT_STATE_QUIT;
1145
1146 /* Indicate mail cannot be sent. */
1147 client_ptr -> nx_smtp_client_mail_status = NX_SMTP_GREET_REPLY_ERROR;
1148
1149
1150 }
1151
1152 if (client_ptr -> nx_smtp_server_packet)
1153 {
1154 nx_packet_release(client_ptr -> nx_smtp_server_packet);
1155 }
1156 /* Return successful session state. */
1157 return(NX_SUCCESS);
1158 }
1159
1160
1161 /**************************************************************************/
1162 /* */
1163 /* FUNCTION RELEASE */
1164 /* */
1165 /* _nx_smtp_cmd_helo PORTABLE C */
1166 /* 6.1 */
1167 /* AUTHOR */
1168 /* */
1169 /* Yuxin Zhou, Microsoft Corporation */
1170 /* */
1171 /* DESCRIPTION */
1172 /* */
1173 /* Create the HELO command text and send to the SMTP server. */
1174 /* */
1175 /* INPUT */
1176 /* */
1177 /* session_ptr SMTP Session for sending mail */
1178 /* */
1179 /* OUTPUT */
1180 /* */
1181 /* NX_SUCCESS Successful completion status */
1182 /* status Actual completion status. */
1183 /* */
1184 /* CALLS */
1185 /* */
1186 /* _nx_smtp_utility_send_to_server Sends data to server */
1187 /* memcpy Copy data to area of memory */
1188 /* */
1189 /* CALLED BY */
1190 /* */
1191 /* _nx_smtp_client_process Runs the SMTP state machine */
1192 /* */
1193 /* RELEASE HISTORY */
1194 /* */
1195 /* DATE NAME DESCRIPTION */
1196 /* */
1197 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
1198 /* 09-30-2020 Yuxin Zhou Modified comment(s), and */
1199 /* verified memcpy use cases, */
1200 /* resulting in version 6.1 */
1201 /* */
1202 /**************************************************************************/
_nx_smtp_cmd_helo(NX_SMTP_CLIENT * client_ptr)1203 UINT _nx_smtp_cmd_helo(NX_SMTP_CLIENT *client_ptr)
1204 {
1205
1206 UINT status;
1207 UINT index;
1208 UINT domain_length;
1209
1210
1211 memset(&_nx_smtp_buffer[0], 0, NX_SMTP_BUFFER_SIZE);
1212
1213 if (_nx_utility_string_length_check(client_ptr -> nx_smtp_client_domain, &domain_length, NX_SMTP_CLIENT_MAX_USERNAME))
1214 {
1215 return(NX_SIZE_ERROR);
1216 }
1217
1218 if (NX_SMTP_BUFFER_SIZE < (sizeof(NX_SMTP_COMMAND_HELO) + domain_length + sizeof(NX_SMTP_LINE_TERMINATOR) - 1))
1219 {
1220
1221 /* Buffer size too small. */
1222 return(NX_SMTP_INTERNAL_ERROR);
1223 }
1224
1225 /* Format the HELO command. */
1226 memcpy(&_nx_smtp_buffer[0], NX_SMTP_COMMAND_HELO, sizeof(NX_SMTP_COMMAND_HELO) - 1); /* Use case of memcpy is verified. */
1227 index = sizeof(NX_SMTP_COMMAND_HELO) - 1;
1228
1229 _nx_smtp_buffer[index++] = ' ';
1230
1231 memcpy(&_nx_smtp_buffer[index], client_ptr -> nx_smtp_client_domain, domain_length); /* Use case of memcpy is verified. */
1232 index += domain_length;
1233 memcpy(&_nx_smtp_buffer[index], NX_SMTP_LINE_TERMINATOR, sizeof(NX_SMTP_LINE_TERMINATOR) - 1); /* Use case of memcpy is verified. */
1234 index += sizeof(NX_SMTP_LINE_TERMINATOR) - 1;
1235
1236 /* Send the HELO command. */
1237 status = _nx_smtp_utility_send_to_server(client_ptr, _nx_smtp_buffer, index, NX_SMTP_CLIENT_SEND_TIMEOUT);
1238
1239 /* Check for error. */
1240 if (status != NX_SUCCESS)
1241 {
1242
1243 return status;
1244 }
1245
1246 /* Set session state to wait next response from server. */
1247 client_ptr -> nx_smtp_client_cmd_state = NX_SMTP_CLIENT_STATE_AWAITING_REPLY;
1248
1249 /* Return normal session status. */
1250 return NX_SUCCESS;
1251 }
1252
1253
1254 /**************************************************************************/
1255 /* */
1256 /* FUNCTION RELEASE */
1257 /* */
1258 /* _nx_smtp_rsp_helo PORTABLE C */
1259 /* 6.1 */
1260 /* AUTHOR */
1261 /* */
1262 /* Yuxin Zhou, Microsoft Corporation */
1263 /* */
1264 /* DESCRIPTION */
1265 /* */
1266 /* This function handles the server reply to the HELO command and set */
1267 /* the next session state and next command to send to the server. This*/
1268 /* is the GREETING state where we do not initiate the greeting. */
1269 /* Instead we wait for the server's 'greeting' message. */
1270 /* */
1271 /* INPUT */
1272 /* */
1273 /* session_ptr Session to send mail to SMTP Server */
1274 /* */
1275 /* OUTPUT */
1276 /* */
1277 /* NX_SUCCESS Successful completion status */
1278 /* status Actual completion status */
1279 /* */
1280 /* CALLS */
1281 /* _nx_smtp_parse_response Parse specified argument from buffer */
1282 /* _nx_smtp_rsp_hello_command Handle HELO/EHLO reply from Server */
1283 /* nx_packet_release Release NetX receive packet */
1284 /* memset Clear specified area of memory */
1285 /* */
1286 /* CALLED BY */
1287 /* */
1288 /* _nx_smtp_client_process Runs the SMTP state machine */
1289 /* */
1290 /* RELEASE HISTORY */
1291 /* */
1292 /* DATE NAME DESCRIPTION */
1293 /* */
1294 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
1295 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
1296 /* resulting in version 6.1 */
1297 /* */
1298 /**************************************************************************/
_nx_smtp_rsp_helo(NX_SMTP_CLIENT * client_ptr)1299 UINT _nx_smtp_rsp_helo(NX_SMTP_CLIENT *client_ptr)
1300 {
1301
1302 UINT status;
1303
1304 /* Get the server response to the EHLO command. */
1305 status = _nx_smtp_utility_read_server_code(client_ptr, NX_SMTP_ENVELOPE_TIMEOUT, NX_TRUE);
1306
1307 /* Check for error. */
1308 if (status != NX_SUCCESS)
1309 {
1310
1311 /* This is either no packet received or an invalid server response. */
1312
1313 /* Return error status. */
1314 return status;
1315 }
1316
1317 /* Update session with specific services offered, if any, by server. */
1318 _nx_smtp_utility_parse_server_services(client_ptr);
1319
1320 /* We are done with the packet now. */
1321 nx_packet_release(client_ptr -> nx_smtp_server_packet);
1322
1323 /* if server rejected hello, set the session state to terminate */
1324 if (client_ptr -> nx_smtp_client_rsp_state == NX_SMTP_CLIENT_STATE_QUIT)
1325 {
1326
1327 /* Return successful session status to execute QUIT command. */
1328 return NX_SUCCESS;
1329 }
1330
1331 /* Handle the server reply code first. */
1332 _nx_smtp_rsp_hello_command(client_ptr);
1333
1334 /* if server rejected hello, set the session state to terminate */
1335 if (client_ptr -> nx_smtp_client_rsp_state == NX_SMTP_CLIENT_STATE_QUIT)
1336 {
1337
1338 /* Return successful session status to execute QUIT command. */
1339 return NX_SUCCESS;
1340 }
1341
1342 /* Server accepted the HELO command. Continue the SMTP session. */
1343
1344 /* Return successful completion status. */
1345 return NX_SUCCESS;
1346 }
1347
1348
1349 /**************************************************************************/
1350 /* */
1351 /* FUNCTION RELEASE */
1352 /* */
1353 /* _nx_smtp_cmd_ehlo PORTABLE C */
1354 /* 6.1 */
1355 /* AUTHOR */
1356 /* */
1357 /* Yuxin Zhou, Microsoft Corporation */
1358 /* */
1359 /* DESCRIPTION */
1360 /* */
1361 /* This function creates the EHLO command and sends it to the server. */
1362 /* */
1363 /* INPUT */
1364 /* */
1365 /* session_ptr SMTP Session for sending mail */
1366 /* */
1367 /* OUTPUT */
1368 /* */
1369 /* NX_SUCCESS Successful completion status */
1370 /* status Actual completion status */
1371 /* */
1372 /* CALLS */
1373 /* */
1374 /* _nx_smtp_utility_send_to_server Send data to server */
1375 /* memcpy Copy data to area of memory */
1376 /* */
1377 /* CALLED BY */
1378 /* */
1379 /* _nx_smtp_client_process Runs the SMTP state machine */
1380 /* */
1381 /* RELEASE HISTORY */
1382 /* */
1383 /* DATE NAME DESCRIPTION */
1384 /* */
1385 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
1386 /* 09-30-2020 Yuxin Zhou Modified comment(s), and */
1387 /* verified memcpy use cases, */
1388 /* resulting in version 6.1 */
1389 /* */
1390 /**************************************************************************/
_nx_smtp_cmd_ehlo(NX_SMTP_CLIENT * client_ptr)1391 UINT _nx_smtp_cmd_ehlo(NX_SMTP_CLIENT *client_ptr)
1392 {
1393
1394 UINT status;
1395 UINT index;
1396 UINT domain_length;
1397
1398
1399 memset(&_nx_smtp_buffer[0], 0, NX_SMTP_BUFFER_SIZE);
1400
1401 if (_nx_utility_string_length_check(client_ptr -> nx_smtp_client_domain, &domain_length, NX_SMTP_CLIENT_MAX_USERNAME))
1402 {
1403 return(NX_SIZE_ERROR);
1404 }
1405
1406 if (NX_SMTP_BUFFER_SIZE < (sizeof(NX_SMTP_COMMAND_EHLO) + domain_length + sizeof(NX_SMTP_LINE_TERMINATOR) - 1))
1407 {
1408
1409 /* Buffer size too small. */
1410 return(NX_SMTP_INTERNAL_ERROR);
1411 }
1412
1413 /* Format the EHLO command. */
1414 memcpy(&_nx_smtp_buffer[0], NX_SMTP_COMMAND_EHLO, sizeof(NX_SMTP_COMMAND_EHLO) - 1); /* Use case of memcpy is verified. */
1415 index = sizeof(NX_SMTP_COMMAND_EHLO) - 1;
1416
1417 _nx_smtp_buffer[index++] = ' ';
1418 memcpy(&_nx_smtp_buffer[index], client_ptr -> nx_smtp_client_domain, domain_length); /* Use case of memcpy is verified. */
1419 index += domain_length;
1420 memcpy(&_nx_smtp_buffer[index], NX_SMTP_LINE_TERMINATOR, sizeof(NX_SMTP_LINE_TERMINATOR) - 1); /* Use case of memcpy is verified. */
1421 index += sizeof(NX_SMTP_LINE_TERMINATOR) - 1;
1422
1423 /* Send the EHLO command. */
1424 status = _nx_smtp_utility_send_to_server(client_ptr, _nx_smtp_buffer, index, NX_SMTP_CLIENT_SEND_TIMEOUT);
1425
1426 /* Check for error. */
1427 if (status != NX_SUCCESS)
1428 {
1429
1430 return status;
1431 }
1432
1433 /* Set session state to wait on the outcome of the EHLO response handler. */
1434 client_ptr -> nx_smtp_client_cmd_state = NX_SMTP_CLIENT_STATE_AWAITING_REPLY;
1435
1436 /* Return normal session status. */
1437 return NX_SUCCESS;
1438 }
1439
1440
1441
1442 /**************************************************************************/
1443 /* */
1444 /* FUNCTION RELEASE */
1445 /* */
1446 /* _nx_smtp_rsp_ehlo PORTABLE C */
1447 /* 6.1 */
1448 /* AUTHOR */
1449 /* */
1450 /* Yuxin Zhou, Microsoft Corporation */
1451 /* */
1452 /* DESCRIPTION */
1453 /* */
1454 /* This handles the server reply to the EHLO command and determines the*/
1455 /* next session state and next command to send to the server. */
1456 /* */
1457 /* INPUT */
1458 /* */
1459 /* session_ptr SMTP Session for sending mail */
1460 /* */
1461 /* OUTPUT */
1462 /* */
1463 /* NX_SUCCESS Successful completion status */
1464 /* status Actual completion status */
1465 /* */
1466 /* CALLS */
1467 /* */
1468 /* _nx_smtp_utility_parse_server_services Parser for extracting server */
1469 /* services and reply code */
1470 /* _nx_smtp_utility_read_server_code Parse the server replies */
1471 /* code and text */
1472 /* _nx_smtp_rsp_hello_command Server HELO/EHLO reply */
1473 /* handler */
1474 /* */
1475 /* CALLED BY */
1476 /* */
1477 /* _nx_smtp_client_process Runs the SMTP state machine */
1478 /* */
1479 /* RELEASE HISTORY */
1480 /* */
1481 /* DATE NAME DESCRIPTION */
1482 /* */
1483 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
1484 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
1485 /* resulting in version 6.1 */
1486 /* */
1487 /**************************************************************************/
_nx_smtp_rsp_ehlo(NX_SMTP_CLIENT * client_ptr)1488 UINT _nx_smtp_rsp_ehlo(NX_SMTP_CLIENT *client_ptr)
1489 {
1490
1491 UINT status;
1492
1493
1494 /* Get the server response to the EHLO command. */
1495 status = _nx_smtp_utility_read_server_code(client_ptr, NX_SMTP_ENVELOPE_TIMEOUT, NX_TRUE);
1496
1497 /* Check for error. */
1498 if (status != NX_SUCCESS)
1499 {
1500
1501 /* This is either no packet received or an invalid server response. */
1502
1503 /* Return error status. */
1504 return status;
1505 }
1506
1507 /* Update session with specific services offered, if any, by server. */
1508 _nx_smtp_utility_parse_server_services(client_ptr);
1509
1510 /* We are done with the packet now. */
1511 nx_packet_release(client_ptr -> nx_smtp_server_packet);
1512
1513 if (client_ptr -> nx_smtp_client_mute)
1514 {
1515 /* We expect another response packet from the server...
1516 keep the same state, don't send anything. */
1517 return NX_SUCCESS;
1518 }
1519
1520 /* Handle the server reply code first. */
1521 _nx_smtp_rsp_hello_command(client_ptr);
1522
1523 /* if server rejected hello, set the session state to terminate */
1524 if (client_ptr -> nx_smtp_client_rsp_state == NX_SMTP_CLIENT_STATE_QUIT)
1525 {
1526
1527 /* Return successful session status to execute QUIT command. */
1528 return NX_SUCCESS;
1529 }
1530
1531 /* Determine if we go to authenticatio next (otherwise we go to the MAIL state). */
1532 if (client_ptr -> nx_smtp_client_authentication_type != NX_SMTP_CLIENT_AUTH_NONE)
1533 {
1534
1535 /* Yes, set session to the AUTH state before going on to MAIL. */
1536 client_ptr -> nx_smtp_client_rsp_state = NX_SMTP_CLIENT_STATE_AUTH;
1537 }
1538
1539 /* Return successful completion status. */
1540 return NX_SUCCESS;
1541 }
1542
1543
1544 /**************************************************************************/
1545 /* */
1546 /* FUNCTION RELEASE */
1547 /* */
1548 /* _nx_smtp_rsp_hello_command PORTABLE C */
1549 /* 6.1 */
1550 /* AUTHOR */
1551 /* */
1552 /* Yuxin Zhou, Microsoft Corporation */
1553 /* */
1554 /* DESCRIPTION */
1555 /* */
1556 /* This function handles the server response to HELO and EHLO commands */
1557 /* common to both command states. If server accepts the EHLO/HELO */
1558 /* command, proceed with the session */
1559 /* */
1560 /* INPUT */
1561 /* */
1562 /* session_ptr Session to send mail to SMTP Server */
1563 /* */
1564 /* OUTPUT */
1565 /* */
1566 /* NX_SUCCESS Successful completion status */
1567 /* */
1568 /* CALLS */
1569 /* */
1570 /* None */
1571 /* */
1572 /* CALLED BY */
1573 /* Session server EHLO reply handler */
1574 /* _nx_smtp_rsp_ehlo Session server HELO reply handler */
1575 /* _nx_smtp_rsp_helo */
1576 /* */
1577 /* RELEASE HISTORY */
1578 /* */
1579 /* DATE NAME DESCRIPTION */
1580 /* */
1581 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
1582 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
1583 /* resulting in version 6.1 */
1584 /* */
1585 /**************************************************************************/
_nx_smtp_rsp_hello_command(NX_SMTP_CLIENT * client_ptr)1586 UINT _nx_smtp_rsp_hello_command(NX_SMTP_CLIENT* client_ptr)
1587 {
1588
1589 UINT first_digit_server_reply;
1590
1591 first_digit_server_reply = client_ptr -> nx_smtp_client_reply_code_status/ 100;
1592
1593 /* Process the server reply starting with the first digit. */
1594 if (first_digit_server_reply == 2)
1595 {
1596
1597
1598 /* Did server accept the EHLO/HELO command? */
1599 if (client_ptr -> nx_smtp_client_reply_code_status == NX_SMTP_CODE_OK_TO_CONTINUE)
1600 {
1601
1602 /* Set session to the next state (MAIL). */
1603 client_ptr -> nx_smtp_client_rsp_state = NX_SMTP_CLIENT_STATE_MAIL;
1604
1605 /* Return successful session status. */
1606 return NX_SUCCESS;
1607 }
1608 }
1609
1610 /* If we are here, an error occurred. Indicate mail cannot be sent. */
1611 client_ptr -> nx_smtp_client_mail_status = NX_SMTP_HELLO_REPLY_ERROR;
1612
1613 /* Set session state to QUIT. */
1614 client_ptr -> nx_smtp_client_rsp_state = NX_SMTP_CLIENT_STATE_QUIT;
1615
1616 /* Return successful session status. */
1617 return NX_SUCCESS;
1618 }
1619
1620
1621
1622 /**************************************************************************/
1623 /* */
1624 /* FUNCTION RELEASE */
1625 /* */
1626 /* _nx_smtp_cmd_auth PORTABLE C */
1627 /* 6.1 */
1628 /* AUTHOR */
1629 /* */
1630 /* Yuxin Zhou, Microsoft Corporation */
1631 /* */
1632 /* DESCRIPTION */
1633 /* */
1634 /* This function creates the text of the SMTP AUTH command text and */
1635 /* sends it to the SMTP server. If the session is already */
1636 /* authenticated, this function proceeds to the MAIL state (next stage */
1637 /* of the SMTP protocol) instead. */
1638 /* */
1639 /* INPUT */
1640 /* */
1641 /* session_ptr Session to send mail to SMTP Server */
1642 /* */
1643 /* OUTPUT */
1644 /* */
1645 /* NX_SUCCESS Successful completion status */
1646 /* status Actual completion status */
1647 /* */
1648 /* CALLS */
1649 /* */
1650 /* _nx_smtp_cmd_mail Send MAIL command to server */
1651 /* _nx_smtp_utility_send_to_server Send data to server */
1652 /* memset Clear area of memory */
1653 /* memcpy Copy data to area of memory */
1654 /* */
1655 /* CALLED BY */
1656 /* */
1657 /* _nx_smtp_client_process Runs the SMTP session */
1658 /* */
1659 /* RELEASE HISTORY */
1660 /* */
1661 /* DATE NAME DESCRIPTION */
1662 /* */
1663 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
1664 /* 09-30-2020 Yuxin Zhou Modified comment(s), and */
1665 /* verified memcpy use cases, */
1666 /* resulting in version 6.1 */
1667 /* */
1668 /**************************************************************************/
_nx_smtp_cmd_auth(NX_SMTP_CLIENT * client_ptr)1669 UINT _nx_smtp_cmd_auth(NX_SMTP_CLIENT *client_ptr)
1670 {
1671
1672 UINT status = NX_SUCCESS;
1673 UINT index;
1674
1675 memset(&_nx_smtp_buffer[0], 0, NX_SMTP_BUFFER_SIZE);
1676
1677 /* Is session already successfully authenticated? */
1678 if (client_ptr -> nx_smtp_client_authentication_state == NX_SMTP_AUTHENTICATION_SUCCEEDED)
1679 {
1680
1681 /* Yes, server will reject any authentication command; skip to MAIL state. */
1682 client_ptr -> nx_smtp_client_cmd_state = NX_SMTP_CLIENT_STATE_MAIL;
1683 client_ptr -> nx_smtp_client_rsp_state = NX_SMTP_CLIENT_STATE_MAIL;
1684
1685 /* Call the session MAIL service. */
1686 _nx_smtp_cmd_mail(client_ptr);
1687
1688 /* Return successful session status. */
1689 return NX_SUCCESS;
1690 }
1691
1692 /* Mark the session authentication as in progress. */
1693 client_ptr -> nx_smtp_client_authentication_state = NX_SMTP_AUTHENTICATION_IN_PROGRESS;
1694
1695 /* Set the authentication prompt depending on the Client authentication type. */
1696 if (client_ptr -> nx_smtp_client_authentication_type == NX_SMTP_CLIENT_AUTH_LOGIN)
1697 {
1698
1699 memcpy(&_nx_smtp_buffer[0], NX_SMTP_CLIENT_AUTH_LOGIN_TEXT, sizeof(NX_SMTP_CLIENT_AUTH_LOGIN_TEXT) - 1); /* Use case of memcpy is verified. */
1700 index = sizeof(NX_SMTP_CLIENT_AUTH_LOGIN_TEXT) - 1;
1701 }
1702 else if (client_ptr -> nx_smtp_client_authentication_type == NX_SMTP_CLIENT_AUTH_CRAM_MD5)
1703 {
1704
1705 memcpy(&_nx_smtp_buffer[0], NX_SMTP_CLIENT_AUTH_CRAM_MD5_TEXT, sizeof(NX_SMTP_CLIENT_AUTH_CRAM_MD5_TEXT) - 1); /* Use case of memcpy is verified. */
1706 index = sizeof(NX_SMTP_CLIENT_AUTH_CRAM_MD5_TEXT) - 1;
1707 }
1708 else
1709 {
1710
1711 memcpy(&_nx_smtp_buffer[0], NX_SMTP_CLIENT_AUTH_PLAIN_TEXT, sizeof(NX_SMTP_CLIENT_AUTH_PLAIN_TEXT) - 1); /* Use case of memcpy is verified. */
1712 index = sizeof(NX_SMTP_CLIENT_AUTH_PLAIN_TEXT) - 1;
1713 }
1714
1715 memcpy(&_nx_smtp_buffer[index], NX_SMTP_LINE_TERMINATOR, sizeof(NX_SMTP_LINE_TERMINATOR) - 1); /* Use case of memcpy is verified. */
1716 index += sizeof(NX_SMTP_LINE_TERMINATOR) - 1;
1717
1718 /* Send the AUTH command to the server. */
1719 status = _nx_smtp_utility_send_to_server(client_ptr, _nx_smtp_buffer, index, NX_SMTP_CLIENT_SEND_TIMEOUT);
1720
1721 /* Check for error. */
1722 if (status != NX_SUCCESS)
1723 {
1724
1725 return status;
1726 }
1727
1728 /* Set session state to wait on the outcome of the EHLO response handler. */
1729 client_ptr -> nx_smtp_client_cmd_state = NX_SMTP_CLIENT_STATE_AWAITING_REPLY;
1730
1731 /* Return normal session status. */
1732 return NX_SUCCESS;
1733 }
1734
1735
1736 /**************************************************************************/
1737 /* */
1738 /* FUNCTION RELEASE */
1739 /* */
1740 /* _nx_smtp_rsp_auth PORTABLE C */
1741 /* 6.1.5 */
1742 /* AUTHOR */
1743 /* */
1744 /* Yuxin Zhou, Microsoft Corporation */
1745 /* */
1746 /* DESCRIPTION */
1747 /* */
1748 /* This function handles the server reply to the AUTH command and set */
1749 /* determine the next session state and next command to send to the */
1750 /* server. */
1751 /* */
1752 /* During the authentication process, it attempts to find a match for */
1753 /* the server authentication type and decodes each server */
1754 /* authentication challenge (e.g. USERNAME, PASSWORD). It then sets the*/
1755 /* session authentication state depending on server acceptance of its */
1756 /* replies to its challenges. */
1757 /* */
1758 /* INPUT */
1759 /* */
1760 /* session_ptr SMTP Session for sending mail */
1761 /* */
1762 /* OUTPUT */
1763 /* */
1764 /* NX_SUCCESS Successful completion status */
1765 /* status Actual completion status */
1766 /* */
1767 /* CALLS */
1768 /* */
1769 /* _nx_smtp_utility_read_server_code Parser for server reply */
1770 /* _nx_smtp_utility_authentication_challenge */
1771 /* Respond to server */
1772 /* authentication challenge*/
1773 /* _nx_smtp_rsp_auth When called by itself,respond */
1774 /* to server authentication */
1775 /* challenge */
1776 /* _nx_smtp_utility_send_to_server Send data to server */
1777 /* nx_packet_release Release NetX receive packet */
1778 /* */
1779 /* CALLED BY */
1780 /* */
1781 /* _nx_smtp_client_process Runs the SMTP state machine */
1782 /* */
1783 /* RELEASE HISTORY */
1784 /* */
1785 /* DATE NAME DESCRIPTION */
1786 /* */
1787 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
1788 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
1789 /* resulting in version 6.1 */
1790 /* 03-02-2021 Yuxin Zhou Modified comment(s), */
1791 /* fixed compiler warnings, */
1792 /* resulting in version 6.1.5 */
1793 /* */
1794 /**************************************************************************/
_nx_smtp_rsp_auth(NX_SMTP_CLIENT * client_ptr)1795 UINT _nx_smtp_rsp_auth(NX_SMTP_CLIENT *client_ptr)
1796 {
1797
1798 UINT status;
1799 UINT server_reply_first_digit;
1800 UCHAR *carriage_return_linefeed_ptr = NX_NULL;
1801 UINT auth_length;
1802
1803
1804 /* Get the server response to the AUTH command. */
1805 status = _nx_smtp_utility_read_server_code(client_ptr, NX_SMTP_ENVELOPE_TIMEOUT, NX_TRUE);
1806
1807 /* Check for error. */
1808 if (status != NX_SUCCESS)
1809 {
1810
1811 /* This is an server response or no packet received. */
1812
1813 /* Return error status. */
1814 return(status);
1815 }
1816
1817 /* Use the first digit to group possible server replies. */
1818 server_reply_first_digit = client_ptr -> nx_smtp_client_reply_code_status / 100;
1819
1820 /* Process the reply code from server. */
1821 if (server_reply_first_digit == 2)
1822 {
1823
1824 if (client_ptr -> nx_smtp_client_reply_code_status == NX_SMTP_CODE_AUTHENTICATION_SUCCESSFUL)
1825 {
1826
1827 /* Advance to the MAIL state. */
1828 client_ptr -> nx_smtp_client_rsp_state = NX_SMTP_CLIENT_STATE_MAIL;
1829
1830 /* Mark the session as authenticated successfully. */
1831 client_ptr -> nx_smtp_client_authentication_state = NX_SMTP_AUTHENTICATION_SUCCEEDED;
1832 }
1833 else
1834 {
1835
1836 /* The server returns a 2xx code. Determine if it is an error code. */
1837 if ((client_ptr -> nx_smtp_client_reply_code_status == NX_SMTP_CODE_CANNOT_VERIFY_RECIPIENT) ||
1838 (client_ptr -> nx_smtp_client_reply_code_status == NX_SMTP_CODE_ACKNOWLEDGE_QUIT))
1839 {
1840
1841 /* It is. Abort. */
1842 client_ptr -> nx_smtp_client_rsp_state = NX_SMTP_CLIENT_STATE_QUIT;
1843
1844 /* Indicate mail cannot be sent. */
1845 client_ptr -> nx_smtp_client_mail_status = NX_SMTP_AUTH_REPLY_ERROR;
1846 }
1847 else
1848 {
1849 /* It is not the code expected. Discard and keep the SMTP Client in the same state. */
1850 }
1851
1852 /* We are done with the packet now. */
1853 nx_packet_release(client_ptr -> nx_smtp_server_packet);
1854
1855 return NX_SUCCESS;
1856 }
1857 }
1858 else if (server_reply_first_digit == 3)
1859 {
1860
1861 /* Check if the server accepted our authentication type. */
1862 if (client_ptr -> nx_smtp_client_reply_code_status != NX_SMTP_CODE_AUTHENTICATION_TYPE_ACCEPTED)
1863 {
1864
1865 /* It did not. Or we may be out of synch with the SMTP Server, if we get a
1866 354 message for example. Abort the mail session. */
1867 client_ptr -> nx_smtp_client_rsp_state = NX_SMTP_CLIENT_STATE_QUIT;
1868
1869 /* Indicate mail cannot be sent. */
1870 client_ptr -> nx_smtp_client_mail_status = NX_SMTP_AUTH_REPLY_ERROR;
1871
1872 /* We are done with the packet now. */
1873 nx_packet_release(client_ptr -> nx_smtp_server_packet);
1874
1875 return NX_SUCCESS;
1876 }
1877 /* Authentication in progress. */
1878
1879 }
1880 else
1881 {
1882
1883 /* Set session to the QUIT state. */
1884 client_ptr -> nx_smtp_client_rsp_state = NX_SMTP_CLIENT_STATE_QUIT;
1885
1886 /* Indicate mail cannot be sent. */
1887 client_ptr -> nx_smtp_client_mail_status = NX_SMTP_AUTH_REPLY_ERROR;
1888
1889 /* We are done with the packet now. */
1890 nx_packet_release(client_ptr -> nx_smtp_server_packet);
1891
1892 return NX_SUCCESS;
1893 }
1894
1895 /* Is authentication in progress? */
1896 if (client_ptr -> nx_smtp_client_authentication_state != NX_SMTP_AUTHENTICATION_SUCCEEDED)
1897 {
1898
1899 /* Set allowed authentication string length. */
1900 auth_length = client_ptr -> nx_smtp_server_packet -> nx_packet_length;
1901
1902 /* Find the end (e.g. CRLF) of the server reply. */
1903 _nx_smtp_find_crlf(client_ptr -> nx_smtp_server_packet -> nx_packet_prepend_ptr,
1904 auth_length, &carriage_return_linefeed_ptr, NX_FALSE);
1905
1906 /* Check for invalid server reply (e.g. missing CRLF). */
1907 if (carriage_return_linefeed_ptr== NX_NULL)
1908 {
1909
1910 client_ptr -> nx_smtp_client_rsp_state = NX_SMTP_CLIENT_STATE_QUIT;
1911
1912 /* Indicate mail cannot be sent. */
1913 client_ptr -> nx_smtp_client_mail_status = NX_SMTP_SERVER_ERROR_REPLY;
1914
1915 /* We are done with the packet now. */
1916 nx_packet_release(client_ptr -> nx_smtp_server_packet);
1917
1918 /* Return completion status. */
1919 return NX_SUCCESS;
1920 }
1921
1922 /* Yes, process (decode) the server's challenge. */
1923 status = _nx_smtp_utility_authentication_challenge(client_ptr, client_ptr -> nx_smtp_server_packet -> nx_packet_prepend_ptr,
1924 (UINT)(carriage_return_linefeed_ptr - client_ptr -> nx_smtp_server_packet -> nx_packet_prepend_ptr));
1925
1926 /* Did the session successfully handle server challenge? */
1927 if (status == NX_SUCCESS)
1928 {
1929
1930 /* Yes, set session to respond to the next server challenge. */
1931 client_ptr -> nx_smtp_client_rsp_state = NX_SMTP_CLIENT_STATE_AUTH_CHALLENGE;
1932 }
1933 /* Did the session have problems parsing the server challenge? */
1934 else
1935 {
1936
1937 client_ptr -> nx_smtp_client_rsp_state = NX_SMTP_CLIENT_STATE_QUIT;
1938
1939 /* Indicate mail cannot be sent. */
1940 client_ptr -> nx_smtp_client_mail_status = NX_SMTP_AUTH_REPLY_ERROR;
1941
1942 nx_packet_release(client_ptr -> nx_smtp_server_packet);
1943
1944 /* Return completion status. */
1945 return NX_SUCCESS;
1946 }
1947 }
1948
1949 /* We are done with the packet now. */
1950 nx_packet_release(client_ptr -> nx_smtp_server_packet);
1951
1952 /* Return successful status. */
1953 return NX_SUCCESS;
1954 }
1955
1956 /**************************************************************************/
1957 /* */
1958 /* FUNCTION RELEASE */
1959 /* */
1960 /* _nx_smtp_cmd_auth_challenge PORTABLE C */
1961 /* 6.1.6 */
1962 /* AUTHOR */
1963 /* */
1964 /* Yuxin Zhou, Microsoft Corporation */
1965 /* */
1966 /* DESCRIPTION */
1967 /* */
1968 /* This function creates a reply to the server authentication challenge*/
1969 /* It determines which challenge the server sent (e.g Username, */
1970 /* Password) and encodes the session response using base64 encryption. */
1971 /* */
1972 /* INPUT */
1973 /* */
1974 /* session_ptr SMTP Session for sending mail */
1975 /* */
1976 /* OUTPUT */
1977 /* */
1978 /* NX_SUCCESS Successful completion status */
1979 /* */
1980 /* CALLS */
1981 /* */
1982 /* _nx_smtp_utility_send_to_server Send data to server */
1983 /* _nx_utility_base64_encode Base64 encode specified text */
1984 /* memcpy Copy data to area of memory */
1985 /* */
1986 /* CALLED BY */
1987 /* */
1988 /* _nx_smtp_client_process Runs the SMTP session */
1989 /* */
1990 /* RELEASE HISTORY */
1991 /* */
1992 /* DATE NAME DESCRIPTION */
1993 /* */
1994 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
1995 /* 09-30-2020 Yuxin Zhou Modified comment(s), improved */
1996 /* buffer length verification, */
1997 /* verified memcpy use cases, */
1998 /* resulting in version 6.1 */
1999 /* 04-02-2021 Yuxin Zhou Modified comment(s), and */
2000 /* improved the logic of */
2001 /* parsing base64, */
2002 /* resulting in version 6.1.6 */
2003 /* */
2004 /**************************************************************************/
_nx_smtp_cmd_auth_challenge(NX_SMTP_CLIENT * client_ptr)2005 UINT _nx_smtp_cmd_auth_challenge(NX_SMTP_CLIENT *client_ptr)
2006 {
2007
2008 UINT status;
2009 UINT index;
2010 UCHAR auth_reply_encoded[NX_SMTP_CLIENT_AUTH_CHALLENGE_ENCODED_SIZE + 1];
2011 UINT auth_reply_encoded_size;
2012 UINT length;
2013 UINT password_length;
2014
2015 /* Initialize the encoded reply to NULL. */
2016 memset(auth_reply_encoded, 0, sizeof(auth_reply_encoded));
2017
2018 /* Verify string length. */
2019 if (_nx_utility_string_length_check(client_ptr -> nx_smtp_password, &password_length, NX_SMTP_CLIENT_MAX_PASSWORD))
2020 {
2021 return(NX_SIZE_ERROR);
2022 }
2023
2024 /* Did the server send us the Username prompt? */
2025 if (client_ptr -> nx_smtp_client_authentication_reply == NX_SMTP_CLIENT_REPLY_TO_USERNAME_PROMPT)
2026 {
2027 if (_nx_utility_string_length_check(client_ptr -> nx_smtp_username, &length, NX_SMTP_CLIENT_MAX_USERNAME))
2028 {
2029 return(NX_SIZE_ERROR);
2030 }
2031
2032
2033 if (client_ptr -> nx_smtp_client_authentication_type == NX_SMTP_CLIENT_AUTH_PLAIN)
2034 {
2035
2036 UCHAR plain_auth_buffer[NX_SMTP_CLIENT_AUTH_CHALLENGE_SIZE];
2037
2038 if (NX_SMTP_CLIENT_AUTH_CHALLENGE_SIZE < (length + 1 + length + 1 + password_length))
2039 {
2040
2041 /* Buffer size too small. */
2042 return(NX_SMTP_INTERNAL_ERROR);
2043 }
2044
2045 memset(&plain_auth_buffer[0], 0, NX_SMTP_CLIENT_AUTH_CHALLENGE_SIZE);
2046
2047 /* Process the client name as per AUTH PLAIN syntax: authorization-id\0authentication-id\0password. */
2048 memcpy(&plain_auth_buffer[0], client_ptr -> nx_smtp_username, length); /* Use case of memcpy is verified. */
2049 length++;
2050 memcpy(&plain_auth_buffer[length], client_ptr -> nx_smtp_username, length); /* Use case of memcpy is verified. */
2051 length += length;
2052 memcpy(&plain_auth_buffer[length], client_ptr -> nx_smtp_password, password_length); /* Use case of memcpy is verified. */
2053 length += password_length;
2054
2055 /* Now encode the combined client username/password. */
2056 _nx_utility_base64_encode(&plain_auth_buffer[0], length, auth_reply_encoded, sizeof(auth_reply_encoded), &auth_reply_encoded_size);
2057
2058 }
2059 else
2060 {
2061
2062 /* Just encode the client username. */
2063 _nx_utility_base64_encode((UCHAR *)client_ptr -> nx_smtp_username, length, auth_reply_encoded, sizeof(auth_reply_encoded), &auth_reply_encoded_size);
2064 }
2065
2066 }
2067 /* Or did the server send us the Password prompt? */
2068 else if (client_ptr -> nx_smtp_client_authentication_reply == NX_SMTP_CLIENT_REPLY_TO_PASSWORD_PROMPT)
2069 {
2070
2071 /* Encode the client password. */
2072 _nx_utility_base64_encode((UCHAR *)client_ptr -> nx_smtp_password, password_length, auth_reply_encoded, sizeof(auth_reply_encoded), &auth_reply_encoded_size);
2073 }
2074
2075 else
2076 {
2077
2078 /* Unknown prompt: Send the '*' to terminate the authentication process. */
2079 memcpy(auth_reply_encoded, NX_SMTP_CANCEL_AUTHENTICATION, sizeof(NX_SMTP_CANCEL_AUTHENTICATION)); /* Use case of memcpy is verified. */
2080 auth_reply_encoded_size = sizeof(NX_SMTP_CANCEL_AUTHENTICATION) - 1;
2081 }
2082
2083 if (sizeof(_nx_smtp_buffer) < (auth_reply_encoded_size + sizeof(NX_SMTP_LINE_TERMINATOR) - 1))
2084 {
2085
2086 /* Buffer size too small. */
2087 return(NX_SMTP_INTERNAL_ERROR);
2088 }
2089
2090 /* Format the encoded response. */
2091 memcpy(&_nx_smtp_buffer[0],auth_reply_encoded, auth_reply_encoded_size); /* Use case of memcpy is verified. */
2092 index = auth_reply_encoded_size;
2093 memcpy(&_nx_smtp_buffer[index], NX_SMTP_LINE_TERMINATOR, sizeof(NX_SMTP_LINE_TERMINATOR) - 1); /* Use case of memcpy is verified. */
2094 index += sizeof(NX_SMTP_LINE_TERMINATOR) - 1;
2095
2096 /* Send the response back to the server. */
2097 status = _nx_smtp_utility_send_to_server(client_ptr, _nx_smtp_buffer, index, NX_SMTP_CLIENT_SEND_TIMEOUT);
2098
2099 /* Check for successful. */
2100 if (status == NX_SUCCESS)
2101 {
2102
2103 /* Set session state to wait on the outcome of the AUTH challenge handler. */
2104 client_ptr -> nx_smtp_client_cmd_state = NX_SMTP_CLIENT_STATE_AWAITING_REPLY;
2105 }
2106
2107 /* Return completion status. */
2108 return status;
2109 }
2110
2111
2112 /**************************************************************************/
2113 /* */
2114 /* FUNCTION RELEASE */
2115 /* */
2116 /* _nx_smtp_rsp_auth_challenge PORTABLE C */
2117 /* 6.1 */
2118 /* AUTHOR */
2119 /* */
2120 /* Yuxin Zhou, Microsoft Corporation */
2121 /* */
2122 /* DESCRIPTION */
2123 /* */
2124 /* This receives the server's response to the AUTH challenge sent by */
2125 /* the session previously and actually just calls the same session */
2126 /* AUTH server reply handler again. */
2127 /* */
2128 /* INPUT */
2129 /* */
2130 /* session_ptr SMTP Session for sending mail */
2131 /* */
2132 /* OUTPUT */
2133 /* */
2134 /* status Actual completion status */
2135 /* */
2136 /* CALLS */
2137 /* */
2138 /* _nx_smtp_rsp_auth AUTH server reply handler */
2139 /* */
2140 /* CALLED BY */
2141 /* */
2142 /* _nx_smtp_client_process Runs the SMTP state machine */
2143 /* */
2144 /* RELEASE HISTORY */
2145 /* */
2146 /* DATE NAME DESCRIPTION */
2147 /* */
2148 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
2149 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
2150 /* resulting in version 6.1 */
2151 /* */
2152 /**************************************************************************/
_nx_smtp_rsp_auth_challenge(NX_SMTP_CLIENT * client_ptr)2153 UINT _nx_smtp_rsp_auth_challenge(NX_SMTP_CLIENT *client_ptr)
2154 {
2155
2156 UINT status;
2157
2158
2159 /* Run the session AUTH server reply handler directly. */
2160 status = _nx_smtp_rsp_auth(client_ptr);
2161
2162 /* Return completion status. */
2163 return status;
2164 }
2165
2166
2167 /**************************************************************************/
2168 /* */
2169 /* FUNCTION RELEASE */
2170 /* */
2171 /* _nx_smtp_cmd_mail PORTABLE C */
2172 /* 6.1 */
2173 /* AUTHOR */
2174 /* */
2175 /* Yuxin Zhou, Microsoft Corporation */
2176 /* */
2177 /* DESCRIPTION */
2178 /* */
2179 /* This function creates the MAIL command and sets the Client state to */
2180 /* send it to the SMTP server. */
2181 /* */
2182 /* INPUT */
2183 /* */
2184 /* session_ptr SMTP Session for sending mail */
2185 /* */
2186 /* OUTPUT */
2187 /* */
2188 /* NX_SUCCESS Successful completion status */
2189 /* status Actual completion status */
2190 /* memcpy Copy data to area of memory */
2191 /* */
2192 /* CALLS */
2193 /* */
2194 /* _nx_smtp_utility_send_to_server Send data to server */
2195 /* */
2196 /* CALLED BY */
2197 /* */
2198 /* _nx_smtp_client_process Runs the SMTP state machine */
2199 /* */
2200 /* RELEASE HISTORY */
2201 /* */
2202 /* DATE NAME DESCRIPTION */
2203 /* */
2204 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
2205 /* 09-30-2020 Yuxin Zhou Modified comment(s), and */
2206 /* verified memcpy use cases, */
2207 /* resulting in version 6.1 */
2208 /* */
2209 /**************************************************************************/
_nx_smtp_cmd_mail(NX_SMTP_CLIENT * client_ptr)2210 UINT _nx_smtp_cmd_mail(NX_SMTP_CLIENT *client_ptr)
2211 {
2212
2213 UINT index;
2214 UINT status;
2215 UINT mail_from_length;
2216 NX_SMTP_CLIENT_MAIL *mail_ptr = &client_ptr -> nx_smtp_client_mail;
2217
2218
2219 memset(_nx_smtp_buffer, 0, NX_SMTP_BUFFER_SIZE);
2220
2221 if (_nx_utility_string_length_check(mail_ptr -> nx_smtp_client_mail_from_address, &mail_from_length, NX_SMTP_BUFFER_SIZE))
2222 {
2223 return(NX_SIZE_ERROR);
2224 }
2225
2226 /* Check if authentication status still left as 'in progress'. */
2227 if (client_ptr -> nx_smtp_client_authentication_state == NX_SMTP_AUTHENTICATION_IN_PROGRESS)
2228 {
2229
2230 /* For some reason, authentication did not complete. Reset status here. */
2231 client_ptr -> nx_smtp_client_authentication_state = NX_SMTP_NOT_AUTHENTICATED;
2232 }
2233
2234 /* Validate message size. */
2235 if((sizeof(NX_SMTP_COMMAND_MAIL) + mail_from_length +
2236 sizeof(NX_SMTP_LINE_TERMINATOR) + 2) > NX_SMTP_BUFFER_SIZE)
2237 {
2238 /* Message size exceeds buffer size. */
2239 return(NX_SMTP_INTERNAL_ERROR);
2240 }
2241
2242 /* Create the command text. */
2243 memcpy(&_nx_smtp_buffer[0], NX_SMTP_COMMAND_MAIL, sizeof(NX_SMTP_COMMAND_MAIL) - 1); /* Use case of memcpy is verified. */
2244 index = sizeof(NX_SMTP_COMMAND_MAIL) - 1;
2245
2246 _nx_smtp_buffer[index++] = ':';
2247 _nx_smtp_buffer[index++] = '<';
2248 memcpy(&_nx_smtp_buffer[index], mail_ptr -> nx_smtp_client_mail_from_address, mail_from_length); /* Use case of memcpy is verified. */
2249 index += mail_from_length;
2250 _nx_smtp_buffer[index++] = '>';
2251
2252 _nx_smtp_buffer[index++] = ' ';
2253 memcpy(&_nx_smtp_buffer[index], NX_SMTP_LINE_TERMINATOR, sizeof(NX_SMTP_LINE_TERMINATOR) - 1); /* Use case of memcpy is verified. */
2254 index += sizeof(NX_SMTP_LINE_TERMINATOR) - 1;
2255
2256 /* Send the session command we constructed above. */
2257 status = _nx_smtp_utility_send_to_server(client_ptr, _nx_smtp_buffer, index, NX_SMTP_CLIENT_SEND_TIMEOUT);
2258
2259 /* Check for error. */
2260 if (status != NX_SUCCESS)
2261 {
2262
2263 /* Return error status.*/
2264 return status;
2265 }
2266
2267 /* Set session state to wait on the outcome of the MAIL response handler. */
2268 client_ptr -> nx_smtp_client_cmd_state = NX_SMTP_CLIENT_STATE_AWAITING_REPLY;
2269
2270 /* Return successful session status. */
2271 return(NX_SUCCESS);
2272 }
2273
2274
2275 /**************************************************************************/
2276 /* */
2277 /* FUNCTION RELEASE */
2278 /* */
2279 /* _nx_smtp_rsp_mail PORTABLE C */
2280 /* 6.1 */
2281 /* AUTHOR */
2282 /* */
2283 /* Yuxin Zhou, Microsoft Corporation */
2284 /* */
2285 /* DESCRIPTION */
2286 /* */
2287 /* This receives the server's response to the MAIL command; it */
2288 /* extracts the server reply code and reply text and store both to the */
2289 /* Client session. It will also set the next SMTP command to send to */
2290 /* the server. */
2291 /* */
2292 /* INPUT */
2293 /* */
2294 /* session_ptr SMTP Session for sending mail */
2295 /* */
2296 /* OUTPUT */
2297 /* */
2298 /* NX_SUCCESS Successful completion status */
2299 /* status Actual completion status */
2300 /* */
2301 /* CALLS */
2302 /* */
2303 /* _nx_smtp_utility_read_server_code Parse the server reply */
2304 /* */
2305 /* CALLED BY */
2306 /* */
2307 /* _nx_smtp_client_process Runs the SMTP state machine */
2308 /* */
2309 /* RELEASE HISTORY */
2310 /* */
2311 /* DATE NAME DESCRIPTION */
2312 /* */
2313 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
2314 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
2315 /* resulting in version 6.1 */
2316 /* */
2317 /**************************************************************************/
_nx_smtp_rsp_mail(NX_SMTP_CLIENT * client_ptr)2318 UINT _nx_smtp_rsp_mail(NX_SMTP_CLIENT *client_ptr)
2319 {
2320
2321 UINT status;
2322
2323 /* Get the server response to the MAIL command. */
2324 status = _nx_smtp_utility_read_server_code(client_ptr, NX_SMTP_ENVELOPE_TIMEOUT, NX_TRUE);
2325
2326 /* Check for error. */
2327 if (status != NX_SUCCESS)
2328 {
2329
2330 /* This is an invalid line or corrupted transmission from the server. */
2331
2332 /* Return error status. */
2333 return(status);
2334 }
2335
2336 /* Did server accept the MAIL command? */
2337 if (client_ptr -> nx_smtp_client_reply_code_status == NX_SMTP_CODE_OK_TO_CONTINUE)
2338 {
2339
2340 /* Yes, set the session to the RCPT state. */
2341 client_ptr -> nx_smtp_client_rsp_state = NX_SMTP_CLIENT_STATE_RCPT;
2342 }
2343 else
2344 {
2345
2346 /* Set session state to QUIT. */
2347 client_ptr -> nx_smtp_client_rsp_state = NX_SMTP_CLIENT_STATE_QUIT;
2348
2349 /* Indicate mail cannot be sent. */
2350 client_ptr -> nx_smtp_client_mail_status = NX_SMTP_MAIL_REPLY_ERROR;
2351 }
2352
2353 /* We are done with the packet now. */
2354 nx_packet_release(client_ptr -> nx_smtp_server_packet);
2355
2356 /* Return successful session status. */
2357 return(NX_SUCCESS);
2358 }
2359
2360
2361 /**************************************************************************/
2362 /* */
2363 /* FUNCTION RELEASE */
2364 /* */
2365 /* _nx_smtp_cmd_rcpt PORTABLE C */
2366 /* 6.1 */
2367 /* AUTHOR */
2368 /* */
2369 /* Yuxin Zhou, Microsoft Corporation */
2370 /* */
2371 /* DESCRIPTION */
2372 /* */
2373 /* This function creates the RCPT command and sets the Client state to */
2374 /* send it to the SMTP server. */
2375 /* */
2376 /* INPUT */
2377 /* */
2378 /* session_ptr SMTP Session for sending mail */
2379 /* */
2380 /* OUTPUT */
2381 /* */
2382 /* NX_SUCCESS Successful completion status */
2383 /* status Actual completion status */
2384 /* */
2385 /* CALLS */
2386 /* */
2387 /* _nx_smtp_utility_send_to_server Send data to server */
2388 /* memcpy Copy data to area of memory */
2389 /* */
2390 /* CALLED BY */
2391 /* */
2392 /* _nx_smtp_client_process Runs the SMTP state machine */
2393 /* */
2394 /* RELEASE HISTORY */
2395 /* */
2396 /* DATE NAME DESCRIPTION */
2397 /* */
2398 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
2399 /* 09-30-2020 Yuxin Zhou Modified comment(s), and */
2400 /* verified memcpy use cases, */
2401 /* resulting in version 6.1 */
2402 /* */
2403 /**************************************************************************/
_nx_smtp_cmd_rcpt(NX_SMTP_CLIENT * client_ptr)2404 UINT _nx_smtp_cmd_rcpt(NX_SMTP_CLIENT *client_ptr)
2405 {
2406
2407 UINT status;
2408 UINT index;
2409 UINT recipient_length;
2410 NX_SMTP_CLIENT_MAIL *mail_ptr;
2411
2412
2413 mail_ptr = &(client_ptr -> nx_smtp_client_mail);
2414
2415 if (_nx_utility_string_length_check(mail_ptr -> nx_smtp_client_mail_recipient_address, &recipient_length, NX_SMTP_BUFFER_SIZE))
2416 {
2417 return(NX_SIZE_ERROR);
2418 }
2419
2420 memset(_nx_smtp_buffer, 0, NX_SMTP_BUFFER_SIZE);
2421
2422 /* Validate message size. */
2423 if((sizeof(NX_SMTP_COMMAND_RCPT) + recipient_length +
2424 sizeof(NX_SMTP_LINE_TERMINATOR) + 2) > NX_SMTP_BUFFER_SIZE)
2425 {
2426 /* Message size exceeds buffer size. */
2427 return(NX_SMTP_INTERNAL_ERROR);
2428 }
2429
2430 /* Create the command text. */
2431 memcpy(&_nx_smtp_buffer[0], NX_SMTP_COMMAND_RCPT, sizeof(NX_SMTP_COMMAND_RCPT) - 1); /* Use case of memcpy is verified. */
2432 index = sizeof(NX_SMTP_COMMAND_RCPT) - 1;
2433
2434 _nx_smtp_buffer[index++] = ':';
2435 _nx_smtp_buffer[index++] = '<';
2436 memcpy(&_nx_smtp_buffer[index], mail_ptr -> nx_smtp_client_mail_recipient_address, /* Use case of memcpy is verified. */
2437 recipient_length);
2438 index += recipient_length;
2439 _nx_smtp_buffer[index++] = '>';
2440 _nx_smtp_buffer[index++] = ' ';
2441 memcpy(&_nx_smtp_buffer[index], NX_SMTP_LINE_TERMINATOR, sizeof(NX_SMTP_LINE_TERMINATOR) - 1); /* Use case of memcpy is verified. */
2442 index += sizeof(NX_SMTP_LINE_TERMINATOR) - 1;
2443
2444 /* Send the RCPT command. */
2445 status = _nx_smtp_utility_send_to_server(client_ptr, _nx_smtp_buffer, index, NX_SMTP_CLIENT_SEND_TIMEOUT);
2446
2447 /* Check for error. */
2448 if (status != NX_SUCCESS)
2449 {
2450
2451 return status;
2452 }
2453
2454 /* Set session state to wait next response from server. */
2455 client_ptr -> nx_smtp_client_cmd_state = NX_SMTP_CLIENT_STATE_AWAITING_REPLY;
2456
2457 /* Return normal session status. */
2458 return NX_SUCCESS;
2459 }
2460
2461
2462 /**************************************************************************/
2463 /* */
2464 /* FUNCTION RELEASE */
2465 /* */
2466 /* _nx_smtp_rsp_rcpt PORTABLE C */
2467 /* 6.1 */
2468 /* AUTHOR */
2469 /* */
2470 /* Yuxin Zhou, Microsoft Corporation */
2471 /* */
2472 /* DESCRIPTION */
2473 /* */
2474 /* This service handles the server's response to the RCPT command and */
2475 /* set the next session state and next command to send to the server. */
2476 /* */
2477 /* INPUT */
2478 /* */
2479 /* session_ptr SMTP Session for sending mail */
2480 /* */
2481 /* OUTPUT */
2482 /* */
2483 /* NX_SUCCESS Successful completion status */
2484 /* status Actual completion status */
2485 /* */
2486 /* CALLS */
2487 /* */
2488 /* _nx_smtp_utility_read_server_code Parse the server reply */
2489 /* */
2490 /* CALLED BY */
2491 /* */
2492 /* _nx_smtp_client_process Runs the SMTP state machine */
2493 /* */
2494 /* RELEASE HISTORY */
2495 /* */
2496 /* DATE NAME DESCRIPTION */
2497 /* */
2498 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
2499 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
2500 /* resulting in version 6.1 */
2501 /* */
2502 /**************************************************************************/
_nx_smtp_rsp_rcpt(NX_SMTP_CLIENT * client_ptr)2503 UINT _nx_smtp_rsp_rcpt(NX_SMTP_CLIENT *client_ptr)
2504 {
2505
2506 UINT status;
2507
2508
2509 /* Get server response to RCPT command. */
2510 status = _nx_smtp_utility_read_server_code(client_ptr, NX_SMTP_ENVELOPE_TIMEOUT, NX_TRUE);
2511
2512 /* Check for error. */
2513 if (status != NX_SUCCESS)
2514 {
2515
2516 /* Return error status. */
2517 return(status);
2518 }
2519
2520 /* Did server accept RCPT command? */
2521 if (client_ptr -> nx_smtp_client_reply_code_status != NX_SMTP_CODE_OK_TO_CONTINUE)
2522 {
2523 /* NO, Set session state to QUIT. */
2524 client_ptr -> nx_smtp_client_rsp_state = NX_SMTP_CLIENT_STATE_QUIT;
2525
2526 /* Indicate mail cannot be sent. */
2527 client_ptr -> nx_smtp_client_mail_status = NX_SMTP_RCPT_REPLY_ERROR;
2528 }
2529 else
2530 {
2531
2532 /* Ok for server to send the mail message */
2533 client_ptr -> nx_smtp_client_rsp_state = NX_SMTP_CLIENT_STATE_DATA;
2534 }
2535
2536 /* We are done with the packet now. */
2537 nx_packet_release(client_ptr -> nx_smtp_server_packet);
2538
2539 /* Return successful session status. */
2540 return NX_SUCCESS;
2541 }
2542
2543
2544 /**************************************************************************/
2545 /* */
2546 /* FUNCTION RELEASE */
2547 /* */
2548 /* _nx_smtp_cmd_data PORTABLE C */
2549 /* 6.1 */
2550 /* AUTHOR */
2551 /* */
2552 /* Yuxin Zhou, Microsoft Corporation */
2553 /* */
2554 /* DESCRIPTION */
2555 /* */
2556 /* This function sets the DATA command text, verifies the mail to send */
2557 /* has a valid recipient and sends it to the SMTP server. */
2558 /* */
2559 /* INPUT */
2560 /* */
2561 /* session_ptr SMTP Session for sending mail */
2562 /* */
2563 /* OUTPUT */
2564 /* */
2565 /* NX_SUCCESS Successful completion status */
2566 /* status Actual completion status */
2567 /* */
2568 /* CALLS */
2569 /* */
2570 /* _nx_smtp_utility_send_to_server Send SMTP commend to server */
2571 /* memcpy Copy data to area of memory */
2572 /* */
2573 /* CALLED BY */
2574 /* */
2575 /* _nx_smtp_client_process Runs the SMTP state machine */
2576 /* */
2577 /* RELEASE HISTORY */
2578 /* */
2579 /* DATE NAME DESCRIPTION */
2580 /* */
2581 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
2582 /* 09-30-2020 Yuxin Zhou Modified comment(s), and */
2583 /* verified memcpy use cases, */
2584 /* resulting in version 6.1 */
2585 /* */
2586 /**************************************************************************/
_nx_smtp_cmd_data(NX_SMTP_CLIENT * client_ptr)2587 UINT _nx_smtp_cmd_data(NX_SMTP_CLIENT *client_ptr)
2588 {
2589
2590 UINT status;
2591 UINT index;
2592
2593
2594 memset(_nx_smtp_buffer, 0, NX_SMTP_BUFFER_SIZE);
2595
2596 /* Format the DATA command. */
2597 memcpy(&_nx_smtp_buffer[0], NX_SMTP_COMMAND_DATA, sizeof(NX_SMTP_COMMAND_DATA) - 1); /* Use case of memcpy is verified. */
2598 index = sizeof(NX_SMTP_COMMAND_DATA) - 1;
2599 memcpy(&_nx_smtp_buffer[index], NX_SMTP_LINE_TERMINATOR, sizeof(NX_SMTP_LINE_TERMINATOR) - 1); /* Use case of memcpy is verified. */
2600 index += sizeof(NX_SMTP_LINE_TERMINATOR) - 1;
2601
2602 /* Send the DATA command. */
2603 status = _nx_smtp_utility_send_to_server(client_ptr, _nx_smtp_buffer, index, NX_SMTP_CLIENT_SEND_TIMEOUT);
2604
2605 /* Check for error. */
2606 if (status != NX_SUCCESS)
2607 {
2608
2609 return status;
2610 }
2611
2612 /* Set session state to wait next response from server. */
2613 client_ptr -> nx_smtp_client_cmd_state = NX_SMTP_CLIENT_STATE_AWAITING_REPLY;
2614
2615 /* Return normal session status. */
2616 return NX_SUCCESS;
2617 }
2618
2619
2620 /**************************************************************************/
2621 /* */
2622 /* FUNCTION RELEASE */
2623 /* */
2624 /* _nx_smtp_rsp_data PORTABLE C */
2625 /* 6.1 */
2626 /* AUTHOR */
2627 /* */
2628 /* Yuxin Zhou, Microsoft Corporation */
2629 /* */
2630 /* DESCRIPTION */
2631 /* */
2632 /* This function handles the server reply to the DATA command and set */
2633 /* the next SMTP Client command to send to the server. */
2634 /* */
2635 /* INPUT */
2636 /* */
2637 /* session_ptr SMTP Session for sending mail */
2638 /* */
2639 /* OUTPUT */
2640 /* */
2641 /* NX_SUCCESS Successful completion status */
2642 /* status Actual completion status */
2643 /* */
2644 /* CALLS */
2645 /* */
2646 /* _nx_smtp_utility_read_server_code Parse the server reply */
2647 /* */
2648 /* CALLED BY */
2649 /* */
2650 /* _nx_smtp_client_process Runs the SMTP state machine */
2651 /* */
2652 /* RELEASE HISTORY */
2653 /* */
2654 /* DATE NAME DESCRIPTION */
2655 /* */
2656 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
2657 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
2658 /* resulting in version 6.1 */
2659 /* */
2660 /**************************************************************************/
_nx_smtp_rsp_data(NX_SMTP_CLIENT * client_ptr)2661 UINT _nx_smtp_rsp_data(NX_SMTP_CLIENT *client_ptr)
2662 {
2663
2664 UINT status;
2665
2666
2667 /* Get the response to DATA command. */
2668 status = _nx_smtp_utility_read_server_code(client_ptr, NX_SMTP_ENVELOPE_TIMEOUT, NX_TRUE);
2669
2670 /* Check for errors. */
2671 if (status != NX_SUCCESS)
2672 {
2673
2674 /* Return error status. */
2675 return (status);
2676 }
2677
2678 if (client_ptr -> nx_smtp_client_reply_code_status == NX_SMTP_CODE_SEND_MAIL_INPUT)
2679 {
2680
2681 /* Yes, set session state to next step. */
2682 client_ptr -> nx_smtp_client_rsp_state = NX_SMTP_CLIENT_STATE_MESSAGE;
2683 }
2684 else
2685 {
2686
2687 /* No, any other 3xy code in inappropriate. Quit the session. */
2688 client_ptr -> nx_smtp_client_rsp_state = NX_SMTP_CLIENT_STATE_QUIT;
2689
2690 /* Indicate mail cannot be sent. */
2691 client_ptr -> nx_smtp_client_mail_status = NX_SMTP_DATA_REPLY_ERROR;
2692 }
2693
2694 /* We are done with the packet now. */
2695 nx_packet_release(client_ptr -> nx_smtp_server_packet);
2696
2697 /* Return successful session status. */
2698 return NX_SUCCESS;
2699 }
2700
2701
2702 /**************************************************************************/
2703 /* */
2704 /* FUNCTION RELEASE */
2705 /* */
2706 /* _nx_smtp_cmd_message PORTABLE C */
2707 /* 6.1 */
2708 /* AUTHOR */
2709 /* */
2710 /* Yuxin Zhou, Microsoft Corporation */
2711 /* */
2712 /* DESCRIPTION */
2713 /* */
2714 /* This function handles the mail message text handling for message */
2715 /* text. It attempts to fit as much of each message into each packet */
2716 /* as possible. */
2717 /* */
2718 /* INPUT */
2719 /* */
2720 /* session_ptr Session for sending mail */
2721 /* */
2722 /* OUTPUT */
2723 /* */
2724 /* NX_SUCCESS Successful completion status */
2725 /* NX_NOT_ENABLED IPv6 not enabled */
2726 /* status Actual completion status */
2727 /* */
2728 /* CALLS */
2729 /* */
2730 /* _nx_smtp_utility_send_to_server Send data to server */
2731 /* */
2732 /* CALLED BY */
2733 /* */
2734 /* _nx_smtp_client_process Runs the SMTP state machine */
2735 /* */
2736 /* RELEASE HISTORY */
2737 /* */
2738 /* DATE NAME DESCRIPTION */
2739 /* */
2740 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
2741 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
2742 /* resulting in version 6.1 */
2743 /* */
2744 /**************************************************************************/
_nx_smtp_cmd_message(NX_SMTP_CLIENT * client_ptr)2745 UINT _nx_smtp_cmd_message(NX_SMTP_CLIENT *client_ptr)
2746 {
2747
2748 UINT status;
2749 ULONG data_left_to_transmit;
2750 ULONG packet_payload;
2751 CHAR *data_to_send;
2752 NX_PACKET_POOL *pool_ptr;
2753 NX_SMTP_CLIENT_MAIL *mail_ptr;
2754
2755
2756 /* Set local variable for convenience. */
2757 mail_ptr = &client_ptr -> nx_smtp_client_mail;
2758
2759 /* Set session state to wait next response from server. */
2760 client_ptr -> nx_smtp_client_cmd_state = NX_SMTP_CLIENT_STATE_AWAITING_REPLY;
2761
2762 pool_ptr = client_ptr -> nx_smtp_client_packet_pool_ptr;
2763
2764 /* Compute packet payload after IP and TCP headers are subtracted. */
2765 if (client_ptr -> nx_smtp_server_address.nxd_ip_version == NX_IP_VERSION_V4)
2766 {
2767
2768 #ifndef NX_DISABLE_IPV4
2769 packet_payload = pool_ptr -> nx_packet_pool_payload_size - sizeof(NX_TCP_HEADER) - sizeof(NX_IPV4_HEADER);
2770 #else
2771 return NX_NOT_ENABLED;
2772 #endif /* NX_DISABLE_IPV4 */
2773 }
2774 else
2775 {
2776 #ifdef FEATURE_NX_IPV6
2777 packet_payload = pool_ptr -> nx_packet_pool_payload_size - sizeof(NX_TCP_HEADER) - sizeof(NX_IPV6_HEADER);
2778 #else
2779 return NX_NOT_ENABLED;
2780 #endif
2781 }
2782
2783
2784 /* Send the Mail header */
2785 status = _nx_smtp_utility_send_header_to_server(client_ptr, NX_SMTP_CLIENT_SEND_TIMEOUT);
2786 if(status)
2787 return(status);
2788
2789 /* Set up local variable of size of mail message. */
2790 data_left_to_transmit = mail_ptr -> nx_smtp_client_mail_body_length;
2791
2792 /* Set a local pointer to (rest of) mail message to send. */
2793 data_to_send = mail_ptr -> nx_smtp_client_mail_body;
2794
2795 /* Send the next chunk of mail text buffer till nothing is left. */
2796 while(data_left_to_transmit)
2797 {
2798
2799 /* Check if remaining mail text will fit in a packet.*/
2800 if (packet_payload >= data_left_to_transmit)
2801 {
2802
2803 /* Yes, send it off! This will load the specified data into an packet from the SMTP client packet pool. */
2804 status = _nx_smtp_utility_send_to_server(client_ptr, data_to_send, data_left_to_transmit,
2805 NX_SMTP_CLIENT_SEND_TIMEOUT);
2806
2807 /* Check for error. */
2808 if (status != NX_SUCCESS)
2809 {
2810
2811 /* Return error status. */
2812 return status;
2813 }
2814
2815 break;
2816 }
2817
2818 /* No, break up mail message into multiple packets. */
2819 else
2820 {
2821
2822 /* Fill up the packet with as much data as it will hold and send it off! */
2823 status = _nx_smtp_utility_send_to_server(client_ptr, data_to_send, packet_payload,
2824 NX_SMTP_CLIENT_SEND_TIMEOUT);
2825
2826 /* Check for error. */
2827 if (status != NX_SUCCESS)
2828 {
2829
2830 /* Return error status. */
2831 return status;
2832 }
2833
2834 /* Update pointer to remainder of message to send, update how much is left to send. */
2835 data_left_to_transmit -= packet_payload;
2836 data_to_send += packet_payload;
2837 }
2838 }
2839
2840 /* Send end of message (EOM) to server or it will handle subsequent commands as message text. */
2841 status = _nx_smtp_utility_send_to_server(client_ptr, NX_SMTP_EOM, sizeof(NX_SMTP_EOM) - 1, NX_SMTP_CLIENT_SEND_TIMEOUT);
2842
2843 /* Return normal session status. */
2844 return status;
2845 }
2846
2847
2848 /**************************************************************************/
2849 /* */
2850 /* FUNCTION RELEASE */
2851 /* */
2852 /* _nx_smtp_rsp_message PORTABLE C */
2853 /* 6.1 */
2854 /* AUTHOR */
2855 /* */
2856 /* Yuxin Zhou, Microsoft Corporation */
2857 /* */
2858 /* DESCRIPTION */
2859 /* */
2860 /* This receives the server's response to sending it mail message data.*/
2861 /* It extracts the server reply code and reply text and store both to */
2862 /* the Client session. It then sets the next session state, sets up */
2863 /* the next command to send to the server. */
2864 /* */
2865 /* If the server accepts the mail message, this function determines if */
2866 /* if there is more session mail to transact, and if so sets the next */
2867 /* Client mail. */
2868 /* */
2869 /* INPUT */
2870 /* */
2871 /* session_ptr Session for sending mail */
2872 /* */
2873 /* OUTPUT */
2874 /* */
2875 /* NX_SUCCESS Successful completion status */
2876 /* status Actual completion status */
2877 /* */
2878 /* CALLS */
2879 /* */
2880 /* _nx_smtp_utility_read_server_code Parse the server reply code */
2881 /* */
2882 /* CALLED BY */
2883 /* */
2884 /* _nx_smtp_client_process Runs the SMTP state machine */
2885 /* */
2886 /* RELEASE HISTORY */
2887 /* */
2888 /* DATE NAME DESCRIPTION */
2889 /* */
2890 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
2891 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
2892 /* resulting in version 6.1 */
2893 /* */
2894 /**************************************************************************/
_nx_smtp_rsp_message(NX_SMTP_CLIENT * client_ptr)2895 UINT _nx_smtp_rsp_message(NX_SMTP_CLIENT *client_ptr)
2896 {
2897
2898 UINT status;
2899
2900
2901 /* Get the server reply to receiving session mail message data. */
2902 status = _nx_smtp_utility_read_server_code(client_ptr, NX_SMTP_MESSAGE_TIMEOUT, NX_TRUE);
2903
2904 /* Check for error. */
2905 if (status != NX_SUCCESS)
2906 {
2907
2908 /* Return the error status. */
2909 return(status);
2910 }
2911
2912 /* Process server reply code by first digit. */
2913 if (client_ptr -> nx_smtp_client_reply_code_status == NX_SMTP_CODE_OK_TO_CONTINUE)
2914 {
2915
2916 /* Message accepted by server. Mark the Client mail as sent. */
2917 client_ptr -> nx_smtp_client_mail_status = NX_SUCCESS;
2918 }
2919 else
2920 {
2921
2922 /* Indicate mail cannot be sent. */
2923 client_ptr -> nx_smtp_client_mail_status = NX_SMTP_MESSAGE_REPLY_ERROR;
2924 }
2925
2926 /* We're done with this session */
2927 client_ptr -> nx_smtp_client_rsp_state = NX_SMTP_CLIENT_STATE_QUIT;
2928
2929 /* We are done with the packet now. */
2930 nx_packet_release(client_ptr -> nx_smtp_server_packet);
2931
2932 /* Return successful session status. */
2933 return(NX_SUCCESS);
2934 }
2935
2936
2937 /**************************************************************************/
2938 /* */
2939 /* FUNCTION RELEASE */
2940 /* */
2941 /* _nx_smtp_cmd_quit PORTABLE C */
2942 /* 6.1 */
2943 /* AUTHOR */
2944 /* */
2945 /* Yuxin Zhou, Microsoft Corporation */
2946 /* */
2947 /* DESCRIPTION */
2948 /* */
2949 /* This function creates the QUIT command text and and sends the Quit */
2950 /* command to the SMTP server. */
2951 /* */
2952 /* INPUT */
2953 /* */
2954 /* session_ptr SMTP Session for sending mail */
2955 /* */
2956 /* OUTPUT */
2957 /* */
2958 /* NX_SUCCESS Successful completion status */
2959 /* status Actual completion status */
2960 /* */
2961 /* CALLS */
2962 /* */
2963 /* _nx_smtp_utility_send_to_server Send data to server */
2964 /* memcpy Copy data to area of memory */
2965 /* */
2966 /* CALLED BY */
2967 /* */
2968 /* _nx_smtp_client_process Runs the SMTP state machine */
2969 /* */
2970 /* RELEASE HISTORY */
2971 /* */
2972 /* DATE NAME DESCRIPTION */
2973 /* */
2974 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
2975 /* 09-30-2020 Yuxin Zhou Modified comment(s), and */
2976 /* verified memcpy use cases, */
2977 /* resulting in version 6.1 */
2978 /* */
2979 /**************************************************************************/
_nx_smtp_cmd_quit(NX_SMTP_CLIENT * client_ptr)2980 UINT _nx_smtp_cmd_quit(NX_SMTP_CLIENT *client_ptr)
2981 {
2982
2983 UINT status;
2984 UINT index;
2985
2986
2987 memset(_nx_smtp_buffer, 0, NX_SMTP_BUFFER_SIZE);
2988
2989 /* Format the QUIT command. */
2990 memcpy(&_nx_smtp_buffer[0], NX_SMTP_COMMAND_QUIT, sizeof(NX_SMTP_COMMAND_QUIT) - 1); /* Use case of memcpy is verified. */
2991 index = sizeof(NX_SMTP_COMMAND_QUIT) - 1;
2992 memcpy(&_nx_smtp_buffer[index], NX_SMTP_LINE_TERMINATOR, sizeof(NX_SMTP_LINE_TERMINATOR)); /* Use case of memcpy is verified. */
2993 index += sizeof(NX_SMTP_LINE_TERMINATOR) - 1;
2994
2995 /* Send the QUIT command. */
2996 status = _nx_smtp_utility_send_to_server(client_ptr, _nx_smtp_buffer, index, NX_SMTP_CLIENT_SEND_TIMEOUT);
2997
2998 /* Check for error. */
2999 if (status != NX_SUCCESS)
3000 {
3001
3002 /* Return error status. */
3003 return status;
3004 }
3005
3006 /* Set session state to wait on the outcome of the EHLO response handler. */
3007 client_ptr -> nx_smtp_client_cmd_state = NX_SMTP_CLIENT_STATE_AWAITING_REPLY;
3008
3009 /* Return normal session status. */
3010 return NX_SUCCESS;
3011 }
3012
3013
3014 /**************************************************************************/
3015 /* */
3016 /* FUNCTION RELEASE */
3017 /* */
3018 /* _nx_smtp_rsp_quit PORTABLE C */
3019 /* 6.1 */
3020 /* AUTHOR */
3021 /* */
3022 /* Yuxin Zhou, Microsoft Corporation */
3023 /* */
3024 /* DESCRIPTION */
3025 /* */
3026 /* This function handles the server reply to the SMTP QUIT command and */
3027 /* sets the session state to the session has terminated normally. */
3028 /* */
3029 /* INPUT */
3030 /* */
3031 /* session_ptr SMTP Session for sending mail */
3032 /* */
3033 /* OUTPUT */
3034 /* */
3035 /* NX_SUCCESS Successful completion status */
3036 /* status Actual completion status */
3037 /* */
3038 /* CALLS */
3039 /* */
3040 /* _nx_smtp_utility_read_server_code Parse the server reply */
3041 /* */
3042 /* CALLED BY */
3043 /* */
3044 /* _nx_smtp_client_process Runs the SMTP state machine */
3045 /* */
3046 /* RELEASE HISTORY */
3047 /* */
3048 /* DATE NAME DESCRIPTION */
3049 /* */
3050 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
3051 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
3052 /* resulting in version 6.1 */
3053 /* */
3054 /**************************************************************************/
_nx_smtp_rsp_quit(NX_SMTP_CLIENT * client_ptr)3055 UINT _nx_smtp_rsp_quit(NX_SMTP_CLIENT *client_ptr)
3056 {
3057
3058 UINT status;
3059
3060
3061 /* Get server response to QUIT command. */
3062 status = _nx_smtp_utility_read_server_code(client_ptr, NX_SMTP_ENVELOPE_TIMEOUT, NX_TRUE);
3063
3064 /* Check for error status. */
3065 if (status != NX_SUCCESS)
3066 {
3067
3068 /* Return the error status. */
3069 return(status);
3070 }
3071
3072 /* Set the session state to normal termination. Normal is when the SMTP Client can
3073 receive SMTP server replies and regardless if mail can be sent, can at least
3074 terminate the session with the Quit command and normal TCP socket disconnect. */
3075 client_ptr -> nx_smtp_client_rsp_state = NX_SMTP_CLIENT_STATE_COMPLETED_NORMALLY;
3076
3077 /* We are done with the packet now. */
3078 nx_packet_release(client_ptr -> nx_smtp_server_packet);
3079
3080 /* Return successful session status. */
3081 return NX_SUCCESS;
3082 }
3083
3084
3085 /**************************************************************************/
3086 /* */
3087 /* FUNCTION RELEASE */
3088 /* */
3089 /* _nx_smtp_cmd_rset PORTABLE C */
3090 /* 6.1 */
3091 /* AUTHOR */
3092 /* */
3093 /* Yuxin Zhou, Microsoft Corporation */
3094 /* */
3095 /* DESCRIPTION */
3096 /* */
3097 /* This functions creates the RSET command for the Client task to send */
3098 /* it to the SMTP server. */
3099 /* */
3100 /* INPUT */
3101 /* */
3102 /* session_ptr SMTP Session for sending mail */
3103 /* */
3104 /* OUTPUT */
3105 /* */
3106 /* NX_SUCCESS Successful completion status */
3107 /* */
3108 /* CALLS */
3109 /* */
3110 /* _nx_smtp_utility_send_to_server Send data to server */
3111 /* memcpy Copy data to area of memory */
3112 /* */
3113 /* CALLED BY */
3114 /* */
3115 /* _nx_smtp_client_process Runs the SMTP state machine */
3116 /* */
3117 /* RELEASE HISTORY */
3118 /* */
3119 /* DATE NAME DESCRIPTION */
3120 /* */
3121 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
3122 /* 09-30-2020 Yuxin Zhou Modified comment(s), and */
3123 /* verified memcpy use cases, */
3124 /* resulting in version 6.1 */
3125 /* */
3126 /**************************************************************************/
_nx_smtp_cmd_rset(NX_SMTP_CLIENT * client_ptr)3127 UINT _nx_smtp_cmd_rset(NX_SMTP_CLIENT *client_ptr)
3128 {
3129
3130 ULONG timeout;
3131 UINT status;
3132 UINT index;
3133
3134
3135 memset(_nx_smtp_buffer, 0, NX_SMTP_BUFFER_SIZE);
3136
3137 /* Get TCP send timeout. */
3138 timeout = NX_SMTP_ENVELOPE_TIMEOUT;
3139
3140 /* Format the RSET command. */
3141 memcpy(&_nx_smtp_buffer[0], NX_SMTP_COMMAND_RSET, sizeof(NX_SMTP_COMMAND_RSET) - 1); /* Use case of memcpy is verified. */
3142 index = sizeof(NX_SMTP_COMMAND_RSET) - 1;
3143 memcpy(&_nx_smtp_buffer[index], NX_SMTP_LINE_TERMINATOR, sizeof(NX_SMTP_LINE_TERMINATOR) - 1); /* Use case of memcpy is verified. */
3144 index += sizeof( NX_SMTP_LINE_TERMINATOR) - 1;
3145
3146 /* Send the RSET command. */
3147 status = _nx_smtp_utility_send_to_server(client_ptr, _nx_smtp_buffer, index, timeout);
3148
3149 /* Check for error. */
3150 if (status != NX_SUCCESS)
3151 {
3152
3153 return status;
3154 }
3155
3156 /* Set session state to wait on the outcome of the EHLO response handler. */
3157 client_ptr -> nx_smtp_client_cmd_state = NX_SMTP_CLIENT_STATE_AWAITING_REPLY;
3158
3159 /* Return normal session status. */
3160 return NX_SUCCESS;
3161 }
3162
3163
3164 /**************************************************************************/
3165 /* */
3166 /* FUNCTION RELEASE */
3167 /* */
3168 /* _nx_smtp_rsp_rset PORTABLE C */
3169 /* 6.1 */
3170 /* AUTHOR */
3171 /* */
3172 /* Yuxin Zhou, Microsoft Corporation */
3173 /* */
3174 /* DESCRIPTION */
3175 /* */
3176 /* This function handles the RSET server reply. */
3177 /* */
3178 /* Resetting an SMTP session means clearing the Client mail transaction*/
3179 /* including recipients and mail text. */
3180 /* */
3181 /* INPUT */
3182 /* */
3183 /* session_ptr SMTP Session for sending mail */
3184 /* */
3185 /* OUTPUT */
3186 /* */
3187 /* NX_SUCCESS Successful completion status */
3188 /* status Actual completion status */
3189 /* */
3190 /* CALLS */
3191 /* */
3192 /* _nx_smtp_utility_read_server_code Parse the server reply */
3193 /* */
3194 /* CALLED BY */
3195 /* */
3196 /* _nx_smtp_client_process Runs the SMTP state machine */
3197 /* */
3198 /* RELEASE HISTORY */
3199 /* */
3200 /* DATE NAME DESCRIPTION */
3201 /* */
3202 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
3203 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
3204 /* resulting in version 6.1 */
3205 /* */
3206 /**************************************************************************/
_nx_smtp_rsp_rset(NX_SMTP_CLIENT * client_ptr)3207 UINT _nx_smtp_rsp_rset(NX_SMTP_CLIENT *client_ptr)
3208 {
3209
3210 UINT status;
3211
3212
3213 /* Get server response to RSET command. */
3214 status = _nx_smtp_utility_read_server_code(client_ptr, NX_SMTP_ENVELOPE_TIMEOUT, NX_TRUE);
3215
3216 /* Check for error. */
3217 if (status != NX_SUCCESS)
3218 {
3219
3220 /* Return error status. */
3221 return(status);
3222 }
3223
3224 /* Did the session receive the 250 OK from the server? */
3225 if (client_ptr -> nx_smtp_client_reply_code_status != NX_SMTP_CODE_OK_TO_CONTINUE)
3226 {
3227
3228 /* Yes, set the session state to QUIT. */
3229 client_ptr -> nx_smtp_client_rsp_state = NX_SMTP_CLIENT_STATE_QUIT;
3230 /* Indicate mail cannot be sent. */
3231 client_ptr -> nx_smtp_client_mail_status = NX_SMTP_SERVER_ERROR_CODE_RECEIVED;
3232 }
3233 else
3234 {
3235
3236 /* Yes, session accepted the RSET command with the 250 code.
3237 Reset session state back to MAIL. */
3238 client_ptr -> nx_smtp_client_rsp_state = NX_SMTP_CLIENT_STATE_MAIL;
3239
3240 }
3241
3242 /* Return successful session status. */
3243 return NX_SUCCESS;
3244 }
3245
3246
3247 /**************************************************************************/
3248 /* */
3249 /* FUNCTION RELEASE */
3250 /* */
3251 /* _nx_smtp_cmd_noop PORTABLE C */
3252 /* 6.1 */
3253 /* AUTHOR */
3254 /* */
3255 /* Yuxin Zhou, Microsoft Corporation */
3256 /* */
3257 /* DESCRIPTION */
3258 /* */
3259 /* This function creates the SMTP NOOP command text and sends it to the*/
3260 /* SMTP server. */
3261 /* */
3262 /* INPUT */
3263 /* */
3264 /* session_ptr SMTP Session for sending mail */
3265 /* */
3266 /* OUTPUT */
3267 /* */
3268 /* NX_SUCCESS Successful completion status */
3269 /* */
3270 /* CALLS */
3271 /* */
3272 /* _nx_smtp_utility_send_to_server Send data to server */
3273 /* memcpy Copy data to area of memory */
3274 /* */
3275 /* CALLED BY */
3276 /* */
3277 /* _nx_smtp_client_process Runs the SMTP state machine */
3278 /* */
3279 /* RELEASE HISTORY */
3280 /* */
3281 /* DATE NAME DESCRIPTION */
3282 /* */
3283 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
3284 /* 09-30-2020 Yuxin Zhou Modified comment(s), and */
3285 /* verified memcpy use cases, */
3286 /* resulting in version 6.1 */
3287 /* */
3288 /**************************************************************************/
_nx_smtp_cmd_noop(NX_SMTP_CLIENT * client_ptr)3289 UINT _nx_smtp_cmd_noop(NX_SMTP_CLIENT *client_ptr)
3290 {
3291
3292 UINT status;
3293 UINT index;
3294
3295
3296 memset(_nx_smtp_buffer, 0, NX_SMTP_BUFFER_SIZE);
3297
3298 /* Format the NOOP command. */
3299 memcpy(&_nx_smtp_buffer[0], NX_SMTP_COMMAND_NOOP, sizeof(NX_SMTP_COMMAND_NOOP) - 1); /* Use case of memcpy is verified. */
3300 index = sizeof(NX_SMTP_COMMAND_NOOP) - 1;
3301 memcpy(&_nx_smtp_buffer[index], NX_SMTP_LINE_TERMINATOR, sizeof(NX_SMTP_LINE_TERMINATOR) - 1); /* Use case of memcpy is verified. */
3302 index += sizeof(NX_SMTP_LINE_TERMINATOR) - 1;
3303
3304 /* Send the NOOP command. */
3305 status = _nx_smtp_utility_send_to_server(client_ptr, _nx_smtp_buffer, index, NX_SMTP_CLIENT_SEND_TIMEOUT);
3306
3307 /* Check for error. */
3308 if (status != NX_SUCCESS)
3309 {
3310
3311 return status;
3312 }
3313
3314 /* Set session state to wait on the outcome of the EHLO response handler. */
3315 client_ptr -> nx_smtp_client_cmd_state = NX_SMTP_CLIENT_STATE_AWAITING_REPLY;
3316
3317 /* Return normal session status. */
3318 return NX_SUCCESS;
3319 }
3320
3321
3322
3323 /**************************************************************************/
3324 /* */
3325 /* FUNCTION RELEASE */
3326 /* */
3327 /* _nx_smtp_rsp_noop PORTABLE C */
3328 /* 6.1 */
3329 /* AUTHOR */
3330 /* */
3331 /* Yuxin Zhou, Microsoft Corporation */
3332 /* */
3333 /* DESCRIPTION */
3334 /* */
3335 /* This function handles the NOOP server reply. It will not */
3336 /* automatically advance the session state like most other SMTP client */
3337 /* commands. However, an indication of server problems will set the */
3338 /* session state to QUIT. */
3339 /* */
3340 /* INPUT */
3341 /* */
3342 /* session_ptr TCP connection to send mail */
3343 /* */
3344 /* OUTPUT */
3345 /* */
3346 /* NX_SUCCESS Successful completion status */
3347 /* status Actual completion status */
3348 /* */
3349 /* CALLS */
3350 /* */
3351 /* _nx_smtp_utility_read_server_code Parse the server reply */
3352 /* */
3353 /* CALLED BY */
3354 /* */
3355 /* _nx_smtp_client_process Runs the SMTP state machine */
3356 /* */
3357 /* RELEASE HISTORY */
3358 /* */
3359 /* DATE NAME DESCRIPTION */
3360 /* */
3361 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
3362 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
3363 /* resulting in version 6.1 */
3364 /* */
3365 /**************************************************************************/
_nx_smtp_rsp_noop(NX_SMTP_CLIENT * client_ptr)3366 UINT _nx_smtp_rsp_noop(NX_SMTP_CLIENT *client_ptr)
3367 {
3368
3369 UINT status;
3370 UINT first_digit_server_reply;
3371
3372
3373 /* Get the response for NOOP command. */
3374 status = _nx_smtp_utility_read_server_code(client_ptr, NX_SMTP_ENVELOPE_TIMEOUT, NX_TRUE);
3375
3376 /* Check for error. */
3377 if (status != NX_SUCCESS)
3378 {
3379
3380 /* Return the error status. */
3381 return(status);
3382 }
3383
3384 /* Get category of server reply from the first digit. */
3385 first_digit_server_reply = client_ptr -> nx_smtp_client_reply_code_status / 100;
3386
3387 /* Is the server experiencing problems forcing the session to abort? */
3388 if (first_digit_server_reply == 4)
3389 {
3390
3391 /* Yes, set the session state to quit. */
3392 client_ptr -> nx_smtp_client_rsp_state = NX_SMTP_CLIENT_STATE_QUIT;
3393
3394 /* Indicate mail cannot be sent. */
3395 client_ptr -> nx_smtp_client_mail_status = NX_SMTP_SERVER_ERROR_CODE_RECEIVED;
3396 }
3397
3398 /* Return successful session status. */
3399 return NX_SUCCESS;
3400 }
3401
3402 /**************************************************************************/
3403 /* */
3404 /* FUNCTION RELEASE */
3405 /* */
3406 /* _nx_smtp_utility_read_server_code PORTABLE C */
3407 /* 6.1 */
3408 /* AUTHOR */
3409 /* */
3410 /* Yuxin Zhou, Microsoft Corporation */
3411 /* */
3412 /* DESCRIPTION */
3413 /* */
3414 /* This function parses the 3 digit SMTP server code and stores the */
3415 /* text of the server reply if there is any to the session buffer. */
3416 /* Its use is intended primarily for session server reply handlers. */
3417 /* */
3418 /* INPUT */
3419 /* */
3420 /* session_ptr Session to send mail to SMTP Server */
3421 /* timeout Timeout on receiving server reply */
3422 /* receive_all_lines Indicates if SMTP Client should expect*/
3423 /* one packet or multiple packets e.g. */
3424 /* a multi packet server reply. */
3425 /* */
3426 /* OUTPUT */
3427 /* */
3428 /* NX_SUCCESS Successful completion status */
3429 /* status Actual completion status */
3430 /* */
3431 /* CALLS */
3432 /* */
3433 /* _nx_smtp_parse_response Parse an argument from text */
3434 /* nx_tcp_socket_receive Receive data over TCP socket */
3435 /* nx_packet_release Release packet to packet pool */
3436 /* memset Clear specified area of memory */
3437 /* */
3438 /* CALLED BY */
3439 /* */
3440 /* Session server reply handlers Handle server replies to SMTP */
3441 /* commands in the session */
3442 /* */
3443 /* RELEASE HISTORY */
3444 /* */
3445 /* DATE NAME DESCRIPTION */
3446 /* */
3447 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
3448 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
3449 /* resulting in version 6.1 */
3450 /* */
3451 /**************************************************************************/
_nx_smtp_utility_read_server_code(NX_SMTP_CLIENT * client_ptr,ULONG timeout,UINT receive_all_lines)3452 UINT _nx_smtp_utility_read_server_code(NX_SMTP_CLIENT *client_ptr, ULONG timeout, UINT receive_all_lines)
3453 {
3454
3455 UINT status;
3456 NX_PACKET *packet_ptr;
3457 UCHAR server_code[NX_SMTP_SERVER_REPLY_CODE_SIZE + 1];
3458 UCHAR *work_ptr;
3459 UINT buffer_length;
3460
3461 NX_PARAMETER_NOT_USED(receive_all_lines);
3462
3463 /* Initialize argument to NULL. */
3464 memset(server_code, 0, NX_SMTP_SERVER_REPLY_CODE_SIZE + 1);
3465
3466 /* Process all packets received as part of server reply. A server response may
3467 have several 'lines' in it e.g. 250-EHLO\r\n250-AUTH LOGIN\r\n250 HELP,
3468 and this may be spread over multiple packets. */
3469
3470 /* Wait to receive the next packet. */
3471 status = nx_tcp_socket_receive(&(client_ptr -> nx_smtp_client_socket), &packet_ptr, timeout);
3472
3473 /* Check for errors. */
3474 if (status != NX_SUCCESS)
3475 {
3476
3477 /* Set session state to QUIT. */
3478 client_ptr -> nx_smtp_client_rsp_state = NX_SMTP_CLIENT_STATE_QUIT;
3479
3480 /* Return error status. */
3481 return status;
3482 }
3483
3484 #ifndef NX_DISABLE_PACKET_CHAIN
3485 if (packet_ptr -> nx_packet_next)
3486 {
3487
3488 /* Chained packet is not supported. */
3489 nx_packet_release(packet_ptr);
3490
3491 /* Set session state to QUIT. */
3492 client_ptr -> nx_smtp_client_rsp_state = NX_SMTP_CLIENT_STATE_QUIT;
3493
3494 /* Indicate mail cannot be sent. */
3495 client_ptr -> nx_smtp_client_mail_status = NX_SMTP_SERVER_ERROR_REPLY;
3496
3497 /* While there was an error with the packet, the SMTP Client is ok. So just return
3498 completion status and we quit the session. */
3499 return NX_SUCCESS;
3500 }
3501 #endif /* NX_DISABLE_PACKET_CHAIN */
3502
3503 /* Save the location of the server response buffer. */
3504 client_ptr -> nx_smtp_server_packet = packet_ptr;
3505
3506 work_ptr = client_ptr -> nx_smtp_server_packet -> nx_packet_prepend_ptr;
3507 buffer_length = client_ptr -> nx_smtp_server_packet -> nx_packet_length;
3508
3509 /* Yes, parse the server code. Note that with SMTP protocol, the server reply
3510 may be multiple lines/packets. To determine if we have the end of the reply
3511 we look for the command code followed by a space (not a hyphen). */
3512 status = _nx_smtp_parse_response(client_ptr, work_ptr, 1, buffer_length, &server_code[0],
3513 NX_SMTP_SERVER_REPLY_CODE_SIZE, NX_FALSE);
3514
3515 /* Was a server reply code found in the first line? */
3516 if (status != NX_SUCCESS)
3517 {
3518
3519 /* No, it wasn't. */
3520 nx_packet_release(packet_ptr);
3521
3522 /* Set session state to QUIT. */
3523 client_ptr -> nx_smtp_client_rsp_state = NX_SMTP_CLIENT_STATE_QUIT;
3524
3525 /* Indicate mail cannot be sent. */
3526 client_ptr -> nx_smtp_client_mail_status = NX_SMTP_SERVER_ERROR_REPLY;
3527
3528 /* While there was an error with the packet, the SMTP Client is ok. So just return
3529 completion status and we quit the session. */
3530 return NX_SUCCESS;
3531 }
3532
3533 /* Convert server code from text to unsigned int and store to session. */
3534 client_ptr -> nx_smtp_client_reply_code_status = strtoul((const char *)server_code, NULL, 10);
3535
3536 /* Return completion status. */
3537 return (NX_SUCCESS);
3538 }
3539
3540 /**************************************************************************/
3541 /* */
3542 /* FUNCTION RELEASE */
3543 /* */
3544 /* _nx_smtp_utility_send_to_server PORTABLE C */
3545 /* 6.1 */
3546 /* AUTHOR */
3547 /* */
3548 /* Yuxin Zhou, Microsoft Corporation */
3549 /* */
3550 /* DESCRIPTION */
3551 /* */
3552 /* This function compiles the message/command to send the SMTP server. */
3553 /* It returns a non success status if packet allocation fails or an */
3554 /* error results from creating the SMTP command packet. */
3555 /* */
3556 /* INPUT */
3557 /* */
3558 /* session_ptr Session to send mail to SMTP Server */
3559 /* buffer_ptr Pointer to buffer for to send */
3560 /* buffer_length Size of buffer */
3561 /* timeout Timeout for sending data out */
3562 /* */
3563 /* OUTPUT */
3564 /* */
3565 /* NX_SUCCESS Successful completion */
3566 /* status Actual completion status */
3567 /* */
3568 /* CALLS */
3569 /* */
3570 /* nx_packet_allocate Allocate packet from specified pool */
3571 /* nx_packet_data_append Appends buffer to packet data */
3572 /* nx_packet_release Releases send packet back to pool */
3573 /* nx_tcp_socket_send Sends packet out over TCP socket */
3574 /* */
3575 /* CALLED BY */
3576 /* */
3577 /* _nx_smtp_session_run Runs the SMTP state machine */
3578 /* Session server reply handlers Handle server reply so SMTP command */
3579 /* Session SMTP command services Send SMTP commands to server */
3580 /* */
3581 /* RELEASE HISTORY */
3582 /* */
3583 /* DATE NAME DESCRIPTION */
3584 /* */
3585 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
3586 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
3587 /* resulting in version 6.1 */
3588 /* */
3589 /**************************************************************************/
_nx_smtp_utility_send_to_server(NX_SMTP_CLIENT * client_ptr,CHAR * buffer_ptr,UINT buffer_length,ULONG timeout)3590 UINT _nx_smtp_utility_send_to_server(NX_SMTP_CLIENT *client_ptr, CHAR *buffer_ptr, UINT buffer_length, ULONG timeout)
3591 {
3592
3593 UINT status;
3594 NX_PACKET *packet_ptr;
3595 UINT packet_type;
3596
3597
3598 if (client_ptr -> nx_smtp_server_address.nxd_ip_version == NX_IP_VERSION_V6)
3599 packet_type = NX_IPv6_TCP_PACKET;
3600 else
3601 packet_type = NX_IPv4_TCP_PACKET;
3602
3603 /* Allocate a packet. */
3604 status = nx_packet_allocate(client_ptr -> nx_smtp_client_packet_pool_ptr,
3605 &packet_ptr, packet_type, NX_SMTP_CLIENT_PACKET_TIMEOUT);
3606
3607 /* Check for error. */
3608 if (status != NX_SUCCESS)
3609 {
3610
3611 /* Abort the session. If we cannot allocate a packet we cannot send a QUIT message. */
3612 client_ptr -> nx_smtp_client_cmd_state = NX_SMTP_CLIENT_STATE_IDLE;
3613 client_ptr -> nx_smtp_client_rsp_state = NX_SMTP_CLIENT_STATE_IDLE;
3614
3615 client_ptr -> nx_smtp_client_mail_status = NX_SMTP_PACKET_ALLOCATE_ERROR;
3616
3617 /* Return error status. */
3618 return(status);
3619 }
3620
3621 /* Add message to packet data. */
3622 status = nx_packet_data_append(packet_ptr, buffer_ptr, buffer_length,
3623 client_ptr -> nx_smtp_client_packet_pool_ptr,
3624 NX_SMTP_CLIENT_PACKET_TIMEOUT);
3625 /* Check for error. */
3626 if (status != NX_SUCCESS)
3627 {
3628
3629 /* Release the packet. */
3630 nx_packet_release(packet_ptr);
3631
3632 /* Abort further processing. This error is most likely a packet allocate. */
3633 client_ptr -> nx_smtp_client_rsp_state = NX_SMTP_CLIENT_STATE_IDLE;
3634 client_ptr -> nx_smtp_client_cmd_state = NX_SMTP_CLIENT_STATE_IDLE;
3635
3636 client_ptr -> nx_smtp_client_mail_status = NX_SMTP_INTERNAL_ERROR;
3637
3638 /* Return error status. */
3639 return(status);
3640 }
3641
3642 /* Send the packet out. */
3643 status = nx_tcp_socket_send(&client_ptr -> nx_smtp_client_socket, packet_ptr, timeout);
3644
3645 /* Check for error. */
3646 if (status != NX_SUCCESS)
3647 {
3648
3649 /* Release the packet. */
3650 nx_packet_release(packet_ptr);
3651
3652 /* Abort further processing. If we are unable to send, we won't be able to send a quit message either. */
3653 client_ptr -> nx_smtp_client_rsp_state = NX_SMTP_CLIENT_STATE_IDLE;
3654 client_ptr -> nx_smtp_client_cmd_state = NX_SMTP_CLIENT_STATE_IDLE;
3655
3656 /* Return error status. */
3657 return(status);
3658 }
3659
3660 /* Return successful session status. */
3661 return(NX_SUCCESS);
3662 }
3663
3664
3665
3666 /**************************************************************************/
3667 /* */
3668 /* FUNCTION RELEASE */
3669 /* */
3670 /* _nx_smtp_utility_send_to_server PORTABLE C */
3671 /* 6.1 */
3672 /* AUTHOR */
3673 /* */
3674 /* Yuxin Zhou, Microsoft Corporation */
3675 /* */
3676 /* DESCRIPTION */
3677 /* */
3678 /* This function compiles the message/command to send the SMTP server. */
3679 /* It returns a non success status if packet allocation fails or an */
3680 /* error results from creating the SMTP command packet. */
3681 /* */
3682 /* INPUT */
3683 /* */
3684 /* session_ptr Session to send mail to SMTP Server */
3685 /* buffer_ptr Pointer to buffer for to send */
3686 /* buffer_length Size of buffer */
3687 /* timeout Timeout for sending data out */
3688 /* */
3689 /* OUTPUT */
3690 /* */
3691 /* NX_SUCCESS Successful completion */
3692 /* status Actual completion status */
3693 /* */
3694 /* CALLS */
3695 /* */
3696 /* nx_packet_allocate Allocate packet from specified pool */
3697 /* nx_packet_data_append Appends buffer to packet data */
3698 /* nx_packet_release Releases send packet back to pool */
3699 /* nx_tcp_socket_send Sends packet out over TCP socket */
3700 /* */
3701 /* CALLED BY */
3702 /* */
3703 /* _nx_smtp_session_run Runs the SMTP state machine */
3704 /* Session server reply handlers Handle server reply so SMTP command */
3705 /* Session SMTP command services Send SMTP commands to server */
3706 /* */
3707 /* RELEASE HISTORY */
3708 /* */
3709 /* DATE NAME DESCRIPTION */
3710 /* */
3711 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
3712 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
3713 /* resulting in version 6.1 */
3714 /* */
3715 /**************************************************************************/
_nx_smtp_utility_send_header_to_server(NX_SMTP_CLIENT * client_ptr,ULONG timeout)3716 UINT _nx_smtp_utility_send_header_to_server(NX_SMTP_CLIENT *client_ptr, ULONG timeout)
3717 {
3718
3719 UINT status;
3720 NX_PACKET *packet_ptr = NX_NULL;
3721 UINT packet_type;
3722 NX_SMTP_CLIENT_MAIL *mail_ptr;
3723 NX_PACKET_POOL *pool_ptr;
3724 UINT recipient_length;
3725 UINT mail_from_length;
3726 UINT subject_length;
3727
3728
3729 mail_ptr = &client_ptr -> nx_smtp_client_mail;
3730
3731 if (client_ptr -> nx_smtp_server_address.nxd_ip_version == NX_IP_VERSION_V6)
3732 packet_type = NX_IPv6_TCP_PACKET;
3733 else
3734 packet_type = NX_IPv4_TCP_PACKET;
3735
3736 /* Verify string length. */
3737 if (_nx_utility_string_length_check(mail_ptr -> nx_smtp_client_mail_recipient_address, &recipient_length, NX_SMTP_BUFFER_SIZE))
3738 {
3739 return(NX_SIZE_ERROR);
3740 }
3741
3742 if (_nx_utility_string_length_check(mail_ptr -> nx_smtp_client_mail_from_address, &mail_from_length, NX_SMTP_BUFFER_SIZE))
3743 {
3744 return(NX_SIZE_ERROR);
3745 }
3746
3747 if (_nx_utility_string_length_check(mail_ptr -> nx_smtp_client_mail_subject, &subject_length, NX_SMTP_BUFFER_SIZE))
3748 {
3749 return(NX_SIZE_ERROR);
3750 }
3751
3752
3753 pool_ptr = client_ptr -> nx_smtp_client_packet_pool_ptr;
3754
3755 /* Allocate a packet. */
3756 status = nx_packet_allocate(pool_ptr, &packet_ptr, packet_type, NX_SMTP_CLIENT_PACKET_TIMEOUT);
3757
3758 /* Check for error. */
3759 if (status == NX_SUCCESS)
3760 {
3761 if (/* Add "To: <recipient_address> CRLF" */
3762 (nx_packet_data_append(packet_ptr, NX_SMTP_TO_STRING, sizeof(NX_SMTP_TO_STRING) - 1,
3763 pool_ptr, NX_SMTP_CLIENT_PACKET_TIMEOUT) == NX_SUCCESS) &&
3764 (nx_packet_data_append(packet_ptr, mail_ptr -> nx_smtp_client_mail_recipient_address,
3765 recipient_length,
3766 pool_ptr, NX_SMTP_CLIENT_PACKET_TIMEOUT) == NX_SUCCESS) &&
3767 (nx_packet_data_append(packet_ptr, NX_SMTP_LINE_TERMINATOR, sizeof(NX_SMTP_LINE_TERMINATOR) - 1,
3768 pool_ptr, NX_SMTP_CLIENT_PACKET_TIMEOUT) == NX_SUCCESS) &&
3769 /* Add "From: <from_address> CRLF" */
3770 (nx_packet_data_append(packet_ptr, NX_SMTP_FROM_STRING, sizeof(NX_SMTP_FROM_STRING) - 1,
3771 pool_ptr, NX_SMTP_CLIENT_PACKET_TIMEOUT) == NX_SUCCESS) &&
3772 (nx_packet_data_append(packet_ptr, mail_ptr -> nx_smtp_client_mail_from_address,
3773 mail_from_length,
3774 pool_ptr, NX_SMTP_CLIENT_PACKET_TIMEOUT) == NX_SUCCESS) &&
3775 (nx_packet_data_append(packet_ptr, NX_SMTP_LINE_TERMINATOR, sizeof(NX_SMTP_LINE_TERMINATOR) - 1,
3776 pool_ptr, NX_SMTP_CLIENT_PACKET_TIMEOUT) == NX_SUCCESS) &&
3777 /* Add "Subject: Subject_line CRLF" */
3778 (nx_packet_data_append(packet_ptr, NX_SMTP_SUBJECT_STRING, sizeof(NX_SMTP_SUBJECT_STRING) - 1,
3779 pool_ptr, NX_SMTP_CLIENT_PACKET_TIMEOUT) == NX_SUCCESS) &&
3780 (nx_packet_data_append(packet_ptr, mail_ptr -> nx_smtp_client_mail_subject,
3781 subject_length,
3782 pool_ptr, NX_SMTP_CLIENT_PACKET_TIMEOUT) == NX_SUCCESS) &&
3783 (nx_packet_data_append(packet_ptr, NX_SMTP_LINE_TERMINATOR, sizeof(NX_SMTP_LINE_TERMINATOR) - 1,
3784 pool_ptr, NX_SMTP_CLIENT_PACKET_TIMEOUT) == NX_SUCCESS) &&
3785 /* Add the rest of the mail header components. */
3786 (nx_packet_data_append(packet_ptr, NX_SMTP_MAIL_HEADER_COMPONENTS, sizeof(NX_SMTP_MAIL_HEADER_COMPONENTS) - 1,
3787 pool_ptr, NX_SMTP_CLIENT_PACKET_TIMEOUT) == NX_SUCCESS))
3788 {
3789 /* Send the packet out. */
3790 status = nx_tcp_socket_send(&client_ptr -> nx_smtp_client_socket, packet_ptr, timeout);
3791
3792 if(status)
3793 {
3794 /* Send failed. */
3795 status = NX_SMTP_INTERNAL_ERROR;
3796 }
3797 }
3798 else
3799 {
3800 /* One of the Mail header components failed to be appended. */
3801 status = NX_SMTP_INTERNAL_ERROR;
3802 }
3803 }
3804
3805 if(status)
3806 {
3807
3808 /* Abort the session. If we cannot allocate a packet we cannot send a QUIT message. */
3809 client_ptr -> nx_smtp_client_cmd_state = NX_SMTP_CLIENT_STATE_IDLE;
3810 client_ptr -> nx_smtp_client_rsp_state = NX_SMTP_CLIENT_STATE_IDLE;
3811
3812 client_ptr -> nx_smtp_client_mail_status = NX_SMTP_INTERNAL_ERROR;
3813
3814 if(packet_ptr)
3815 {
3816 /* Release the packet. */
3817 nx_packet_release(packet_ptr);
3818 }
3819 }
3820
3821
3822 /* Return successful session status. */
3823 return(NX_SUCCESS);
3824 }
3825
3826
3827 /**************************************************************************/
3828 /* */
3829 /* FUNCTION RELEASE */
3830 /* */
3831 /* _nx_smtp_utility_authentication_challenge PORTABLE C */
3832 /* 6.1.6 */
3833 /* AUTHOR */
3834 /* */
3835 /* Yuxin Zhou, Microsoft Corporation */
3836 /* */
3837 /* DESCRIPTION */
3838 /* */
3839 /* This function handles parsing and decoding the server challenge, */
3840 /* and setting up the client response to the challenge. It does not */
3841 /* alter the session state or determine the next session command. */
3842 /* */
3843 /* INPUT */
3844 /* */
3845 /* session_ptr Session to send mail to SMTP Server */
3846 /* server_challenge Buffer containing server challenge */
3847 /* length Size of server challenge buffer */
3848 /* */
3849 /* OUTPUT */
3850 /* */
3851 /* NX_SUCCESS Successful completion status */
3852 /* NX_SMTP_PARAM_ERROR Server parsing (parameter) error */
3853 /* */
3854 /* CALLS */
3855 /* */
3856 /* _nx_smtp_parse_response Parses argument from buffer text */
3857 /* _nx_utility_base64_decode Decodes base64 text */
3858 /* memset Clears specified area of memory */
3859 /* memcmp Compares data between areas of memory */
3860 /* */
3861 /* CALLED BY */
3862 /* */
3863 /* _nx_smtp_rsp_auth AUTH server reply handler */
3864 /* */
3865 /* RELEASE HISTORY */
3866 /* */
3867 /* DATE NAME DESCRIPTION */
3868 /* */
3869 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
3870 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
3871 /* resulting in version 6.1 */
3872 /* 04-02-2021 Yuxin Zhou Modified comment(s), and */
3873 /* improved the logic of */
3874 /* parsing base64, */
3875 /* resulting in version 6.1.6 */
3876 /* */
3877 /**************************************************************************/
_nx_smtp_utility_authentication_challenge(NX_SMTP_CLIENT * client_ptr,UCHAR * server_challenge,UINT length)3878 UINT _nx_smtp_utility_authentication_challenge(NX_SMTP_CLIENT *client_ptr, UCHAR *server_challenge, UINT length)
3879 {
3880
3881 UCHAR encrypted_server_prompt[NX_SMTP_SERVER_CHALLENGE_MAX_STRING + 1];
3882 UCHAR decoded_server_prompt[NX_SMTP_SERVER_CHALLENGE_MAX_STRING + 1];
3883 UINT encrypted_server_prompt_size;
3884 UINT decoded_server_prompt_size;
3885
3886 if (client_ptr -> nx_smtp_client_authentication_type == NX_SMTP_CLIENT_AUTH_PLAIN)
3887 {
3888 /* Set the session to reply to a username challenge. */
3889 client_ptr -> nx_smtp_client_authentication_reply = NX_SMTP_CLIENT_REPLY_TO_USERNAME_PROMPT;
3890
3891 /* Return successful session status. */
3892 return NX_SUCCESS;
3893 }
3894
3895 /* Clear buffers for storing encrypted and decoded server challenges. */
3896 memset(encrypted_server_prompt, 0, NX_SMTP_SERVER_CHALLENGE_MAX_STRING + 1);
3897 memset(decoded_server_prompt, 0, NX_SMTP_SERVER_CHALLENGE_MAX_STRING + 1);
3898
3899 /* Parse the 2nd argument for the server challenge we need to decode. */
3900 _nx_smtp_parse_response(client_ptr, &server_challenge[0], 2, length, &encrypted_server_prompt[0],
3901 NX_SMTP_SERVER_CHALLENGE_MAX_STRING, NX_FALSE);
3902
3903 /* Was a valid argument parsed? */
3904 if (*encrypted_server_prompt == NX_NULL)
3905 {
3906
3907 /* No , unable to parse server prompt. */
3908
3909 /* Return error status. */
3910 return NX_SMTP_INVALID_SERVER_REPLY;
3911 }
3912
3913 /* Calculate the name length. */
3914 if (_nx_utility_string_length_check((CHAR *)encrypted_server_prompt, &encrypted_server_prompt_size, NX_SMTP_SERVER_CHALLENGE_MAX_STRING))
3915 {
3916 return NX_SMTP_INVALID_SERVER_REPLY;
3917 }
3918
3919 /* Decode the parsed server challenge. */
3920 _nx_utility_base64_decode(encrypted_server_prompt, encrypted_server_prompt_size, decoded_server_prompt, sizeof(decoded_server_prompt), &decoded_server_prompt_size);
3921
3922 /* Is this a username prompt? */
3923 if ((decoded_server_prompt_size == 9) &&
3924 ((decoded_server_prompt[0] == 'U') || (decoded_server_prompt[0] == 'u')) &&
3925 ((decoded_server_prompt[1] == 'S') || (decoded_server_prompt[1] == 's')) &&
3926 ((decoded_server_prompt[2] == 'E') || (decoded_server_prompt[2] == 'e')) &&
3927 ((decoded_server_prompt[3] == 'R') || (decoded_server_prompt[3] == 'r')) &&
3928 ((decoded_server_prompt[4] == 'N') || (decoded_server_prompt[4] == 'n')) &&
3929 ((decoded_server_prompt[5] == 'A') || (decoded_server_prompt[5] == 'a')) &&
3930 ((decoded_server_prompt[6] == 'M') || (decoded_server_prompt[6] == 'm')) &&
3931 ((decoded_server_prompt[7] == 'E') || (decoded_server_prompt[7] == 'e')) &&
3932 (decoded_server_prompt[8] == ':'))
3933 {
3934
3935 /* Yes, set the session to reply to a username challenge. */
3936 client_ptr -> nx_smtp_client_authentication_reply = NX_SMTP_CLIENT_REPLY_TO_USERNAME_PROMPT;
3937 }
3938 /* Is this a password prompt? */
3939 else if ((decoded_server_prompt_size == 9) &&
3940 ((decoded_server_prompt[0] == 'P') || (decoded_server_prompt[0] == 'p')) &&
3941 ((decoded_server_prompt[1] == 'A') || (decoded_server_prompt[1] == 'a')) &&
3942 ((decoded_server_prompt[2] == 'S') || (decoded_server_prompt[2] == 's')) &&
3943 ((decoded_server_prompt[3] == 'S') || (decoded_server_prompt[3] == 's')) &&
3944 ((decoded_server_prompt[4] == 'W') || (decoded_server_prompt[4] == 'w')) &&
3945 ((decoded_server_prompt[5] == 'O') || (decoded_server_prompt[5] == 'o')) &&
3946 ((decoded_server_prompt[6] == 'R') || (decoded_server_prompt[6] == 'r')) &&
3947 ((decoded_server_prompt[7] == 'D') || (decoded_server_prompt[7] == 'd')) &&
3948 (decoded_server_prompt[8] == ':'))
3949 {
3950
3951 /* Yes, set the session to reply to a password challenge. */
3952 client_ptr -> nx_smtp_client_authentication_reply = NX_SMTP_CLIENT_REPLY_TO_PASSWORD_PROMPT;
3953 }
3954 else
3955 {
3956
3957 /* Indicate invalid authentication from server. */
3958 return NX_SMTP_CLIENT_REPLY_TO_UNKNOWN_PROMPT;
3959 }
3960
3961 /* Return successful session status. */
3962 return NX_SUCCESS;
3963 }
3964
3965
3966 /**************************************************************************/
3967 /* */
3968 /* FUNCTION RELEASE */
3969 /* */
3970 /* _nx_smtp_utility_parse_server_services PORTABLE C */
3971 /* 6.1.6 */
3972 /* AUTHOR */
3973 /* */
3974 /* Yuxin Zhou, Microsoft Corporation */
3975 /* */
3976 /* DESCRIPTION */
3977 /* */
3978 /* This function checks for the AUTH option in the server response. If */
3979 /* authentication is offered, it attempts to find a match between */
3980 /* authentication options offered by the server and the client */
3981 /* authentication type. If no match between client and server is found,*/
3982 /* or no authentication is listed in the server response, it sets the */
3983 /* client authentication type to PLAIN. */
3984 /* */
3985 /* INPUT */
3986 /* */
3987 /* session_ptr Session to send mail to SMTP Server */
3988 /* */
3989 /* OUTPUT */
3990 /* */
3991 /* None */
3992 /* */
3993 /* CALLS */
3994 /* */
3995 /* strstr Search for a string within a string */
3996 /* */
3997 /* CALLED BY */
3998 /* */
3999 /* _nx_smtp_rsp_ehlo EHLO server reply handler */
4000 /* */
4001 /* RELEASE HISTORY */
4002 /* */
4003 /* DATE NAME DESCRIPTION */
4004 /* */
4005 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
4006 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
4007 /* resulting in version 6.1 */
4008 /* 04-02-2021 Yuxin Zhou Modified comment(s), */
4009 /* improved boundary check, */
4010 /* resulting in version 6.1.6 */
4011 /* */
4012 /**************************************************************************/
_nx_smtp_utility_parse_server_services(NX_SMTP_CLIENT * client_ptr)4013 VOID _nx_smtp_utility_parse_server_services(NX_SMTP_CLIENT *client_ptr)
4014 {
4015
4016 UINT plain_option = NX_FALSE;
4017 UINT login_option = NX_FALSE;
4018 UCHAR *work_ptr;
4019 UCHAR *temp_ptr;
4020 ULONG length, new_length;
4021 UINT i;
4022 UINT found = NX_FALSE;
4023
4024
4025 /* Does the server list an authentication type, and does the client want authentication? */
4026
4027 /* Set local variable for convenience. */
4028 length = client_ptr -> nx_smtp_server_packet -> nx_packet_length;
4029
4030 /* Find the location of the AUTH command. */
4031 work_ptr = client_ptr -> nx_smtp_server_packet -> nx_packet_prepend_ptr;
4032
4033 /* Check length. */
4034 if (length <= 4)
4035 {
4036 return;
4037 }
4038
4039 for (i = 0; i < length - 4; i++)
4040 {
4041 if (
4042 ((*work_ptr == 'A') || (*work_ptr == 'a')) &&
4043 ((*(work_ptr + 1) == 'U') || (*(work_ptr + 1) == 'u')) &&
4044 ((*(work_ptr + 2) == 'T') || (*(work_ptr + 2) == 't')) &&
4045 ((*(work_ptr + 3) == 'H') || (*(work_ptr + 3) == 'h'))
4046 )
4047 {
4048
4049 found = NX_TRUE;
4050 work_ptr += 4;
4051 break;
4052 }
4053
4054 work_ptr++;
4055 }
4056
4057 /* Check if this packet has the AUTH keyword. */
4058 if (!found )
4059 {
4060
4061 /* It does not. So leave the Client authentication type as is. */
4062 return;
4063 }
4064
4065 /* Check if the client prefers no authentication. */
4066 if (found && (client_ptr -> nx_smtp_client_authentication_type == NX_SMTP_CLIENT_AUTH_NONE))
4067 {
4068
4069 /* There is an AUTH keyword but the client prefers not to authenticate. */
4070 return;
4071 }
4072
4073 /* Save the location where the search stopped. */
4074 temp_ptr = work_ptr;
4075
4076 found = NX_FALSE;
4077 new_length = length - (ULONG)(temp_ptr - client_ptr -> nx_smtp_server_packet -> nx_packet_prepend_ptr);
4078
4079 /* Check length. */
4080 if (new_length < 5)
4081 {
4082 return;
4083 }
4084 else
4085 {
4086 new_length -= 5;
4087 }
4088
4089 /* Search for supported authentication types. */
4090 for (i = 0; i < new_length; i++)
4091 {
4092 if (
4093 ((*work_ptr == 'L') || (*work_ptr == 'l')) &&
4094 ((*(work_ptr + 1) == 'O') || (*(work_ptr + 1) == 'o')) &&
4095 ((*(work_ptr + 2) == 'G') || (*(work_ptr + 2) == 'g')) &&
4096 ((*(work_ptr + 3) == 'I') || (*(work_ptr + 3) == 'i')) &&
4097 ((*(work_ptr + 4) == 'N') || (*(work_ptr + 4) == 'n'))
4098 )
4099 {
4100 found = NX_TRUE;
4101 break;
4102 }
4103
4104 work_ptr++;
4105 }
4106
4107 /* Is there a LOGIN option offered? */
4108 if (found)
4109 {
4110 /* Yes, set the login option flag. */
4111 login_option = NX_TRUE;
4112 }
4113
4114 found = NX_FALSE;
4115
4116 /* Restore the location for a new search. */
4117 work_ptr = temp_ptr;
4118
4119 for (i = 0; i < new_length; i++)
4120 {
4121 if (
4122 ((*work_ptr == 'P') || (*work_ptr == 'p')) &&
4123 ((*(work_ptr + 1) == 'L') || (*(work_ptr + 1) == 'l')) &&
4124 ((*(work_ptr + 2) == 'A') || (*(work_ptr + 2) == 'a')) &&
4125 ((*(work_ptr + 3) == 'I') || (*(work_ptr + 3) == 'i')) &&
4126 ((*(work_ptr + 4) == 'N') || (*(work_ptr + 4) == 'n'))
4127 )
4128 {
4129 found = NX_TRUE;
4130 break;
4131 }
4132
4133 work_ptr++;
4134 }
4135
4136 /* Is there a PLAIN option offered? */
4137 if (found)
4138 {
4139 /* Yes, set the plain option flag. */
4140 plain_option = NX_TRUE;
4141 }
4142
4143 /* Compare Server list of authentication types to client preferred authentication type. */
4144
4145 /* Handle the case of the client prefers LOGIN authentication. */
4146 if (client_ptr -> nx_smtp_client_authentication_type == NX_SMTP_CLIENT_AUTH_LOGIN)
4147 {
4148
4149 /* Yes; Check if server supports offers LOGIN authentication. */
4150 if (login_option)
4151 {
4152
4153 return;
4154 }
4155 else
4156 {
4157 /* Switch client to plain authentication. */
4158 client_ptr -> nx_smtp_client_authentication_type = NX_SMTP_CLIENT_AUTH_PLAIN;
4159
4160 return;
4161 }
4162 }
4163
4164 /* Check if server listed PLAIN authentication. */
4165 if (plain_option && (client_ptr -> nx_smtp_client_authentication_type == NX_SMTP_CLIENT_AUTH_PLAIN))
4166 {
4167 /* Yes, and there's a match, we're done here. */
4168 return;
4169 }
4170
4171 /* If we are here, the server offers LOGIN authentication but the Client preference is something else. */
4172 if (login_option)
4173 {
4174
4175 /* Switch client to LOGIN authentication. */
4176 client_ptr -> nx_smtp_client_authentication_type = NX_SMTP_CLIENT_AUTH_LOGIN;
4177
4178 return;
4179 }
4180
4181 /* Handle the case of no matches between server/client. Assume the server requires authentication
4182 and set Client type to plain. */
4183 client_ptr -> nx_smtp_client_authentication_type = NX_SMTP_CLIENT_AUTH_PLAIN;
4184
4185 /* Return. */
4186 return;
4187
4188 }
4189
4190 /**************************************************************************/
4191 /* */
4192 /* FUNCTION RELEASE */
4193 /* */
4194 /* _nx_smtp_parse_response PORTABLE C */
4195 /* 6.1.6 */
4196 /* AUTHOR */
4197 /* */
4198 /* Yuxin Zhou, Microsoft Corporation */
4199 /* */
4200 /* DESCRIPTION */
4201 /* */
4202 /* This function parses the argument specified by the argument index */
4203 /* from the supplied buffer. The first argument is at index 1. */
4204 /* If the specified argument can't be found the argument pointer at NULL.*/
4205 /* */
4206 /* Carriage return/line feeds can be treated as word word separator if */
4207 /* specified by the crlf_are_word_breaks parameter. For OK TO CONTINUE */
4208 /* messages (250), this function searches the whole message for the last */
4209 /* occurance of the server code e.g. code followed by a space. */
4210 /* */
4211 /* Carriage return/line feeds are removed if found on the end of the */
4212 /* parsed argument. */
4213 /* */
4214 /* INPUT */
4215 /* */
4216 /* client_ptr Pointer to client instance */
4217 /* buffer Pointer to buffer to parse */
4218 /* argument_index Identify which argument to parse */
4219 /* buffer_length Size of buffer to parse */
4220 /* argument Argument to parse from buffer */
4221 /* argument_length Size of argument buffer */
4222 /* crlf_are_word_breaks Treat \r\n's as word breaks */
4223 /* */
4224 /* OUTPUT */
4225 /* */
4226 /* NX_SUCCESS Successfully parsed reply code or */
4227 /* authentication challenge */
4228 /* NX_SMTP_INVALID_PARAM Invalid input */
4229 /* */
4230 /* CALLS */
4231 /* */
4232 /* toupper Convert chars to upper case */
4233 /* */
4234 /* CALLED BY */
4235 /* */
4236 /* Application Code */
4237 /* */
4238 /* RELEASE HISTORY */
4239 /* */
4240 /* DATE NAME DESCRIPTION */
4241 /* */
4242 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
4243 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
4244 /* resulting in version 6.1 */
4245 /* 04-02-2021 Yuxin Zhou Modified comment(s), */
4246 /* improved boundary check, */
4247 /* resulting in version 6.1.6 */
4248 /* */
4249 /**************************************************************************/
_nx_smtp_parse_response(NX_SMTP_CLIENT * client_ptr,UCHAR * buffer,UINT argument_index,UINT buffer_length,UCHAR * argument,UINT argument_length,UINT crlf_are_word_breaks)4250 UINT _nx_smtp_parse_response(NX_SMTP_CLIENT *client_ptr, UCHAR *buffer, UINT argument_index,
4251 UINT buffer_length, UCHAR *argument,
4252 UINT argument_length, UINT crlf_are_word_breaks)
4253 {
4254
4255
4256 UINT i = 0;
4257 UINT j = 0;
4258 UINT argument_char_count = 0;
4259 UCHAR *work_ptr;
4260 UINT is_last_code;
4261
4262
4263 /* Check for invalid input parameters. */
4264 if ((buffer == NX_NULL) || (buffer_length == 0) || (argument_index == 0))
4265 {
4266
4267 return NX_SMTP_INVALID_PARAM;
4268 }
4269
4270 work_ptr = argument;
4271
4272 /* Is this the first word?
4273 The first word is the reply code, not an SMTP command parameter */
4274 if (argument_index == 1)
4275 {
4276
4277 /* Yes, search each character up to the end of the buffer for
4278 the first separator. */
4279 while (i < buffer_length)
4280 {
4281
4282 /* Have we reached a word break? */
4283 if (
4284 (argument[0] != 0) &&
4285 ((*buffer == ' ') || (*buffer == '-'))
4286 )
4287 {
4288 /* Yes, this marks the end of the first argument (word). */
4289 break;
4290 }
4291
4292 /* Are we starting a number? */
4293 else if ((*buffer >= 0x30) && (*buffer <= 0x39))
4294 {
4295
4296 if (work_ptr >= argument + argument_length)
4297 {
4298 return(NX_SMTP_INTERNAL_ERROR);
4299 }
4300
4301 /* Yes, copy to buffer. */
4302 *work_ptr = *buffer;
4303 work_ptr++;
4304 }
4305 else
4306 {
4307 /* Not a number. make sure the argument buffer is reset */
4308 memset(&argument[0], 0, argument_length);
4309 work_ptr = argument;
4310 }
4311
4312 /* Get the next character in the buffer. */
4313 buffer++;
4314 i++;
4315 }
4316 }
4317 else
4318 {
4319 /* No, we're not parsing the first argument. This is a special case for parsing
4320 the server authentication challenge, not just the reply code. */
4321
4322 /* Mark the start of the argument at the separator after
4323 the end of the previous argument. */
4324 while ((j < argument_index) && (i < buffer_length))
4325 {
4326
4327 /* Keep track of the number of separators in the buffer */
4328 /* OD0A marks the end of a line usually in SMTP */
4329
4330 /* Did we hit a line terminator? */
4331 if ((*buffer == 0x0D) && (*(buffer + 1) == 0x0A))
4332 {
4333
4334 /* Yes, Update the count of separators. */
4335 j++;
4336
4337 /* Are line terminators as word breaks? */
4338 if (crlf_are_word_breaks == NX_FALSE)
4339 {
4340
4341 /* No, this is the end of the search buffer.
4342 Argument not parsed from buffer, return error. */
4343 return NX_SMTP_INVALID_SERVER_REPLY;
4344 }
4345
4346 /* Get the next character after '\n' byte in the buffer. */
4347 i++;
4348 buffer++;
4349 }
4350 /* Did we hit a space or a dash in the first argument? */
4351 else if ((*buffer == ' ') || ((*buffer == '-') && (j == 0)))
4352 {
4353
4354 /* Yes; these are counted as separators (note that dashes found in arguments
4355 after the first argument are NOT considered separators. */
4356 j++;
4357 }
4358 else
4359 {
4360
4361 /* No, is this the argument to parse? */
4362 if (j == (argument_index - 1))
4363 {
4364 /* Yes; did we go past the argument size limit before the next word break? */
4365 if (argument_char_count >= argument_length)
4366 {
4367
4368 /* Yes, unable to finish parsing this buffer. Return error. */
4369 return NX_SMTP_INVALID_SERVER_REPLY;
4370 }
4371
4372 /* No, copy the next character into the argument. */
4373 argument_char_count++;
4374
4375 /* Convert to uppercase if the caller requests. */
4376 *argument++ = *buffer;
4377 }
4378 }
4379
4380 /* Get the next character in the buffer. */
4381 buffer++;
4382 i++;
4383 }
4384 }
4385
4386 /* Determine if this is the last 250 in the message (e.g. followed by a space, not hyphen) */
4387 work_ptr = buffer - 3;
4388
4389 if ((*work_ptr == '2') && (*(work_ptr + 1) == '5') && (*(work_ptr + 2) == '0') && (*(work_ptr + 3) == '-'))
4390 {
4391
4392 UINT status;
4393
4394 /* Parse the rest of the buffer to see if this packet contains the last 250 code. */
4395 status = _nx_smtp_parse_250_response(buffer, buffer_length - i, &is_last_code);
4396 if (status)
4397 {
4398 /* Error with parsing response. */
4399 return status;
4400 }
4401
4402 /* Did we parse the whole 250 response? */
4403 if (is_last_code != NX_TRUE)
4404 {
4405 /* NO, so we are waiting for another 250 packet. */
4406 client_ptr -> nx_smtp_client_mute = NX_TRUE;
4407 }
4408 else
4409 {
4410
4411 /* YES, so we are NOT waiting for a packet with the last 250 code. */
4412 client_ptr -> nx_smtp_client_mute = NX_FALSE;
4413 }
4414 }
4415 else if ((*work_ptr == '2') && (*(work_ptr + 1) == '5') && (*(work_ptr + 2) == '0') && (*(work_ptr + 3) == ' '))
4416 {
4417 client_ptr -> nx_smtp_client_mute = NX_FALSE;
4418 }
4419
4420 return NX_SUCCESS;
4421 }
4422
4423 /**************************************************************************/
4424 /* */
4425 /* FUNCTION RELEASE */
4426 /* */
4427 /* _nx_smtp_parse_250_response PORTABLE C */
4428 /* 6.1 */
4429 /* AUTHOR */
4430 /* */
4431 /* Yuxin Zhou, Microsoft Corporation */
4432 /* */
4433 /* DESCRIPTION */
4434 /* */
4435 /* This function is called to search the rest of the message for the last*/
4436 /* instance of the server code 250. The first 250 has been found but */
4437 /* followed by a hyphen, indicating more 250's in the message. */
4438 /* */
4439 /* INPUT */
4440 /* */
4441 /* buffer_ptr Pointer to buffer to parse */
4442 /* buffer_length Size of buffer to parse */
4443 /* is_last_code Indicate if last 250 found */
4444 /* */
4445 /* OUTPUT */
4446 /* */
4447 /* NX_SUCCESS Successfully parsed last code */
4448 /* */
4449 /* */
4450 /* CALLED BY */
4451 /* */
4452 /* _nx_smtp_parse_response Parse (any) code in server message */
4453 /* */
4454 /* RELEASE HISTORY */
4455 /* */
4456 /* DATE NAME DESCRIPTION */
4457 /* */
4458 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
4459 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
4460 /* resulting in version 6.1 */
4461 /* */
4462 /**************************************************************************/
_nx_smtp_parse_250_response(UCHAR * buffer_ptr,UINT buffer_length,UINT * is_last_code)4463 UINT _nx_smtp_parse_250_response(UCHAR *buffer_ptr, UINT buffer_length, UINT *is_last_code)
4464 {
4465
4466 *is_last_code = NX_FALSE;
4467
4468 /* Are there more 250 codes in this buffer? Advance the buffer
4469 pointer and search for a 250 followed by a space. */
4470
4471 while (buffer_length > 3)
4472 {
4473 /* Find next 250[sp] in the buffer */
4474 if ((*buffer_ptr == '2') &&
4475 (*(buffer_ptr + 1) == '5') &&
4476 (*(buffer_ptr + 2) == '0') &&
4477 (*(buffer_ptr + 3) == ' '))
4478 {
4479 *is_last_code = NX_TRUE;
4480 break;
4481 }
4482 else
4483 {
4484 buffer_ptr++;
4485 buffer_length--;
4486 }
4487 }
4488
4489 return NX_SUCCESS;
4490 }
4491
4492 /**************************************************************************/
4493 /* */
4494 /* FUNCTION RELEASE */
4495 /* */
4496 /* _nx_smtp_find_crlf PORTABLE C */
4497 /* 6.1 */
4498 /* AUTHOR */
4499 /* */
4500 /* Yuxin Zhou, Microsoft Corporation */
4501 /* */
4502 /* DESCRIPTION */
4503 /* */
4504 /* This function returns a pointer to the first carriage return/line */
4505 /* feed (CRLF) sequence found in the buffer. If no CRLF is found within */
4506 /* length specified, the CRLF pointer is left at NULL. If specified the */
4507 /* search can start at the end of the buffer and work backwards to the */
4508 /* first CRLF found. */
4509 /* */
4510 /* INPUT */
4511 /* */
4512 /* buffer Pointer to buffer to search */
4513 /* length Size of buffer to search */
4514 /* CRLF Pointer to CRLF found in buffer */
4515 /* in_reverse Search buffer in reverse direction */
4516 /* */
4517 /* OUTPUT */
4518 /* */
4519 /* None */
4520 /* */
4521 /* CALLS */
4522 /* */
4523 /* None */
4524 /* */
4525 /* CALLED BY */
4526 /* */
4527 /* Application Code */
4528 /* */
4529 /* RELEASE HISTORY */
4530 /* */
4531 /* DATE NAME DESCRIPTION */
4532 /* */
4533 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
4534 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
4535 /* resulting in version 6.1 */
4536 /* */
4537 /**************************************************************************/
_nx_smtp_find_crlf(UCHAR * buffer,UINT length,UCHAR ** CRLF,UINT in_reverse)4538 VOID _nx_smtp_find_crlf(UCHAR *buffer, UINT length, UCHAR **CRLF, UINT in_reverse)
4539 {
4540
4541 UINT i = 0;
4542
4543 *CRLF = NULL;
4544
4545 if ((buffer == NX_NULL) || (length == 0))
4546 {
4547 return;
4548 }
4549
4550
4551 /* Search for CRLF from end to start of buffer (reverse) */
4552 if (in_reverse == NX_TRUE)
4553 {
4554
4555 /* Move pointer out to the end of the buffer. */
4556 buffer += length - 1;
4557
4558 while (i < length - 1)
4559 {
4560 if (*(buffer - 1) == 0x0D && *buffer == 0x0A)
4561 {
4562 /* Set the location of CRLF sequence. */
4563 *CRLF = buffer - 1;
4564 break;
4565 }
4566
4567 /* Move the pointer back one. */
4568 buffer--;
4569
4570 /* Keep track how many bytes we've gone. */
4571 i++;
4572 }
4573 }
4574 /* Search for CRLF starting at the beginning of the buffer */
4575 else
4576 {
4577 while( i < length - 1)
4578 {
4579 if (*buffer == 0x0D && *(buffer + 1) == 0x0A)
4580 {
4581 /* Set the location of CRLF sequence. */
4582 *CRLF = buffer;
4583
4584 break;
4585 }
4586 i++;
4587 buffer++;
4588 }
4589 }
4590
4591 return ;
4592 }
4593