smtp.c (15772B)
1 /* 2 * Claws Mail -- a GTK based, lightweight, and fast e-mail client 3 * Copyright (C) 1999-2022 the Claws Mail team and Hiroyuki Yamamoto 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 3 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program. If not, see <http://www.gnu.org/licenses/>. 17 * 18 */ 19 20 #include <glib.h> 21 #ifdef ENABLE_NLS 22 #include <glib/gi18n.h> 23 #else 24 #define _(a) (a) 25 #define N_(a) (a) 26 #endif 27 #include <stdio.h> 28 #include <string.h> 29 30 #include "smtp.h" 31 #include "utils.h" 32 #include "log.h" 33 34 static void smtp_session_destroy(Session *session); 35 36 static gint smtp_auth(SMTPSession *session); 37 static gint smtp_starttls(SMTPSession *session); 38 static gint smtp_auth_oauth2(SMTPSession *session); 39 static gint smtp_auth_login(SMTPSession *session); 40 static gint smtp_auth_plain(SMTPSession *session); 41 42 static gint smtp_ehlo(SMTPSession *session); 43 static gint smtp_ehlo_recv(SMTPSession *session, const gchar *msg); 44 45 static gint smtp_helo(SMTPSession *session); 46 static gint smtp_rcpt(SMTPSession *session); 47 static gint smtp_data(SMTPSession *session); 48 static gint smtp_send_data(SMTPSession *session); 49 static gint smtp_make_ready(SMTPSession *session); 50 static gint smtp_eom(SMTPSession *session); 51 52 static gint smtp_session_recv_msg(Session *session, const gchar *msg); 53 static gint smtp_session_send_data_finished(Session *session, guint len); 54 55 56 Session *smtp_session_new(void *prefs_account) 57 { 58 SMTPSession *session; 59 60 session = g_new0(SMTPSession, 1); 61 62 session_init(SESSION(session), prefs_account, TRUE); 63 64 SESSION(session)->type = SESSION_SMTP; 65 66 SESSION(session)->recv_msg = smtp_session_recv_msg; 67 68 SESSION(session)->recv_data_finished = NULL; 69 SESSION(session)->send_data_finished = smtp_session_send_data_finished; 70 71 SESSION(session)->destroy = smtp_session_destroy; 72 73 session->state = SMTP_READY; 74 session->tls_init_done = FALSE; 75 76 session->hostname = NULL; 77 session->user = NULL; 78 session->pass = NULL; 79 80 session->from = NULL; 81 session->to_list = NULL; 82 session->cur_to = NULL; 83 84 session->send_data = NULL; 85 session->send_data_len = 0; 86 87 session->avail_auth_type = 0; 88 session->forced_auth_type = 0; 89 session->auth_type = 0; 90 session->esmtp_flags = 0; 91 92 session->error_val = SM_OK; 93 session->error_msg = NULL; 94 95 return SESSION(session); 96 } 97 98 static void smtp_session_destroy(Session *session) 99 { 100 SMTPSession *smtp_session = SMTP_SESSION(session); 101 102 g_free(smtp_session->hostname); 103 g_free(smtp_session->user); 104 g_free(smtp_session->pass); 105 g_free(smtp_session->from); 106 107 g_free(smtp_session->send_data); 108 109 g_free(smtp_session->error_msg); 110 } 111 112 gint smtp_from(SMTPSession *session) 113 { 114 gchar buf[MESSAGEBUFSIZE]; 115 gchar *mail_size = NULL; 116 117 cm_return_val_if_fail(session->from != NULL, SM_ERROR); 118 119 session->state = SMTP_FROM; 120 121 if (session->is_esmtp && (session->esmtp_flags & ESMTP_SIZE)!=0) 122 mail_size = g_strdup_printf(" SIZE=%d", session->send_data_len); 123 else 124 mail_size = g_strdup(""); 125 126 127 if (strchr(session->from, '<')) 128 g_snprintf(buf, sizeof(buf), "MAIL FROM:%s%s", session->from, 129 mail_size); 130 else 131 g_snprintf(buf, sizeof(buf), "MAIL FROM:<%s>%s", session->from, 132 mail_size); 133 134 g_free(mail_size); 135 136 if (session_send_msg(SESSION(session), buf) < 0) 137 return SM_ERROR; 138 log_print(LOG_PROTOCOL, "%sSMTP> %s\n", (session->is_esmtp?"E":""), buf); 139 140 return SM_OK; 141 } 142 143 static gint smtp_auth(SMTPSession *session) 144 { 145 146 cm_return_val_if_fail(session->user != NULL, SM_ERROR); 147 148 session->state = SMTP_AUTH; 149 if ((session->forced_auth_type == SMTPAUTH_LOGIN 150 || session->forced_auth_type == 0) 151 && 152 (session->avail_auth_type & SMTPAUTH_LOGIN) != 0) 153 smtp_auth_login(session); 154 else if ((session->forced_auth_type == SMTPAUTH_PLAIN 155 || session->forced_auth_type == 0) 156 && 157 (session->avail_auth_type & SMTPAUTH_PLAIN) != 0) 158 smtp_auth_plain(session); 159 160 else if ((session->forced_auth_type == SMTPAUTH_OAUTH2 161 || session->forced_auth_type == 0) 162 && 163 (session->avail_auth_type & SMTPAUTH_OAUTH2) != 0) 164 smtp_auth_oauth2(session); 165 166 else if (session->forced_auth_type == 0) { 167 log_warning(LOG_PROTOCOL, _("No SMTP AUTH method available\n")); 168 return SM_AUTHFAIL; 169 } else { 170 log_warning(LOG_PROTOCOL, _("Selected SMTP AUTH method not available\n")); 171 return SM_AUTHFAIL; 172 } 173 174 return SM_OK; 175 } 176 177 static gint smtp_auth_recv(SMTPSession *session, const gchar *msg) 178 { 179 switch (session->auth_type) { 180 case SMTPAUTH_LOGIN: 181 session->state = SMTP_AUTH_LOGIN_USER; 182 183 if (!strncmp(msg, "334 ", 4)) { 184 char *tmp; 185 tmp = g_base64_encode(session->user, strlen(session->user)); 186 if (session_send_msg(SESSION(session), tmp) < 0) { 187 free(tmp); 188 return SM_ERROR; 189 } 190 free(tmp); 191 log_print(LOG_PROTOCOL, "ESMTP> [USERID]\n"); 192 } else { 193 /* Server rejects AUTH */ 194 if (session_send_msg(SESSION(session), "*") < 0) 195 return SM_ERROR; 196 log_print(LOG_PROTOCOL, "ESMTP> *\n"); 197 } 198 break; 199 default: 200 /* stop smtp_auth when no correct authtype */ 201 if (session_send_msg(SESSION(session), "*") < 0) 202 return SM_ERROR; 203 log_print(LOG_PROTOCOL, "ESMTP> *\n"); 204 break; 205 } 206 207 return SM_OK; 208 } 209 210 static gint smtp_auth_login_user_recv(SMTPSession *session, const gchar *msg) 211 { 212 session->state = SMTP_AUTH_LOGIN_PASS; 213 214 gchar *tmp; 215 if (!strncmp(msg, "334 ", 4)) { 216 tmp = g_base64_encode(session->pass, strlen(session->pass)); 217 } else { 218 /* Server rejects AUTH */ 219 tmp = g_strdup("*"); 220 } 221 222 if (session_send_msg(SESSION(session), tmp) < 0) { 223 g_free(tmp); 224 return SM_ERROR; 225 } 226 g_free(tmp); 227 228 log_print(LOG_PROTOCOL, "ESMTP> [PASSWORD]\n"); 229 230 return SM_OK; 231 } 232 233 static gint smtp_ehlo(SMTPSession *session) 234 { 235 gchar buf[MESSAGEBUFSIZE]; 236 237 session->state = SMTP_EHLO; 238 239 session->avail_auth_type = 0; 240 241 g_snprintf(buf, sizeof(buf), "EHLO %s", 242 session->hostname ? session->hostname : get_domain_name()); 243 if (session_send_msg(SESSION(session), buf) < 0) 244 return SM_ERROR; 245 log_print(LOG_PROTOCOL, "ESMTP> %s\n", buf); 246 247 return SM_OK; 248 } 249 250 static gint smtp_ehlo_recv(SMTPSession *session, const gchar *msg) 251 { 252 if (strncmp(msg, "250", 3) == 0) { 253 const gchar *p = msg; 254 p += 3; 255 if (*p == '-' || *p == ' ') p++; 256 if (g_ascii_strncasecmp(p, "AUTH", 4) == 0) { 257 p += 5; 258 if (strcasestr(p, "PLAIN")) 259 session->avail_auth_type |= SMTPAUTH_PLAIN; 260 if (strcasestr(p, "LOGIN")) 261 session->avail_auth_type |= SMTPAUTH_LOGIN; 262 if (strcasestr(p, "XOAUTH2")) 263 session->avail_auth_type |= SMTPAUTH_OAUTH2; 264 } 265 if (g_ascii_strncasecmp(p, "SIZE", 4) == 0) { 266 p += 5; 267 session->max_message_size = atoi(p); 268 session->esmtp_flags |= ESMTP_SIZE; 269 } 270 if (g_ascii_strncasecmp(p, "STARTTLS", 8) == 0) { 271 p += 9; 272 session->avail_auth_type |= SMTPAUTH_TLS_AVAILABLE; 273 } 274 return SM_OK; 275 } else if ((msg[0] == '1' || msg[0] == '2' || msg[0] == '3') && 276 (msg[3] == ' ' || msg[3] == '\0')) 277 return SM_OK; 278 else if (msg[0] == '5' && msg[1] == '0' && 279 (msg[2] == '4' || msg[2] == '3' || msg[2] == '1')) 280 return SM_ERROR; 281 282 return SM_ERROR; 283 } 284 285 static gint smtp_starttls(SMTPSession *session) 286 { 287 session->state = SMTP_STARTTLS; 288 289 if (session_send_msg(SESSION(session), "STARTTLS") < 0) 290 return SM_ERROR; 291 log_print(LOG_PROTOCOL, "ESMTP> STARTTLS\n"); 292 293 return SM_OK; 294 } 295 296 static gint smtp_auth_plain(SMTPSession *session) 297 { 298 gchar buf[MESSAGEBUFSIZE], *b64buf, *out; 299 gint len; 300 301 session->state = SMTP_AUTH_PLAIN; 302 session->auth_type = SMTPAUTH_PLAIN; 303 304 memset(buf, 0, sizeof buf); 305 306 /* "\0user\0password" */ 307 len = sprintf(buf, "%c%s%c%s", '\0', session->user, '\0', session->pass); 308 b64buf = g_base64_encode(buf, len); 309 out = g_strconcat("AUTH PLAIN ", b64buf, NULL); 310 g_free(b64buf); 311 312 if (session_send_msg(SESSION(session), out) < 0) { 313 g_free(out); 314 return SM_ERROR; 315 } 316 317 g_free(out); 318 319 log_print(LOG_PROTOCOL, "ESMTP> [AUTH PLAIN]\n"); 320 321 return SM_OK; 322 } 323 324 static gint smtp_auth_oauth2(SMTPSession *session) 325 { 326 gchar buf[MESSAGEBUFSIZE], *b64buf, *out; 327 gint len; 328 329 session->state = SMTP_AUTH_OAUTH2; 330 session->auth_type = SMTPAUTH_OAUTH2; 331 332 memset(buf, 0, sizeof buf); 333 334 /* "user=" {User} "^Aauth=Bearer " {Access Token} "^A^A"*/ 335 /* session->pass contains the OAUTH2 Access Token*/ 336 len = sprintf(buf, "user=%s\1auth=Bearer %s\1\1", session->user, session->pass); 337 b64buf = g_base64_encode(buf, len); 338 out = g_strconcat("AUTH XOAUTH2 ", b64buf, NULL); 339 g_free(b64buf); 340 341 if (session_send_msg(SESSION(session), out) < 0) { 342 g_free(out); 343 return SM_ERROR; 344 } 345 346 g_free(out); 347 348 log_print(LOG_PROTOCOL, "ESMTP> [AUTH XOAUTH2]\n"); 349 350 return SM_OK; 351 } 352 353 static gint smtp_auth_login(SMTPSession *session) 354 { 355 session->state = SMTP_AUTH; 356 session->auth_type = SMTPAUTH_LOGIN; 357 358 if (session_send_msg(SESSION(session), "AUTH LOGIN") < 0) 359 return SM_ERROR; 360 log_print(LOG_PROTOCOL, "ESMTP> AUTH LOGIN\n"); 361 362 return SM_OK; 363 } 364 365 static gint smtp_helo(SMTPSession *session) 366 { 367 gchar buf[MESSAGEBUFSIZE]; 368 369 session->state = SMTP_HELO; 370 371 g_snprintf(buf, sizeof(buf), "HELO %s", 372 session->hostname ? session->hostname : get_domain_name()); 373 if (session_send_msg(SESSION(session), buf) < 0) 374 return SM_ERROR; 375 log_print(LOG_PROTOCOL, "SMTP> %s\n", buf); 376 377 return SM_OK; 378 } 379 380 static gint smtp_rcpt(SMTPSession *session) 381 { 382 gchar buf[MESSAGEBUFSIZE]; 383 gchar *to; 384 385 cm_return_val_if_fail(session->cur_to != NULL, SM_ERROR); 386 387 session->state = SMTP_RCPT; 388 389 to = (gchar *)session->cur_to->data; 390 391 if (strchr(to, '<')) 392 g_snprintf(buf, sizeof(buf), "RCPT TO:%s", to); 393 else 394 g_snprintf(buf, sizeof(buf), "RCPT TO:<%s>", to); 395 if (session_send_msg(SESSION(session), buf) < 0) 396 return SM_ERROR; 397 log_print(LOG_PROTOCOL, "SMTP> %s\n", buf); 398 399 session->cur_to = session->cur_to->next; 400 401 return SM_OK; 402 } 403 404 static gint smtp_data(SMTPSession *session) 405 { 406 session->state = SMTP_DATA; 407 408 if (session_send_msg(SESSION(session), "DATA") < 0) 409 return SM_ERROR; 410 log_print(LOG_PROTOCOL, "SMTP> DATA\n"); 411 412 return SM_OK; 413 } 414 415 static gint smtp_send_data(SMTPSession *session) 416 { 417 session->state = SMTP_SEND_DATA; 418 419 session_send_data(SESSION(session), session->send_data, 420 session->send_data_len); 421 422 return SM_OK; 423 } 424 425 static gint smtp_make_ready(SMTPSession *session) 426 { 427 session->state = SMTP_MAIL_SENT_OK; 428 429 return SM_OK; 430 } 431 432 gint smtp_quit(SMTPSession *session) 433 { 434 session->state = SMTP_QUIT; 435 436 session_send_msg(SESSION(session), "QUIT"); 437 log_print(LOG_PROTOCOL, "SMTP> QUIT\n"); 438 439 return SM_OK; 440 } 441 442 static gint smtp_eom(SMTPSession *session) 443 { 444 session->state = SMTP_EOM; 445 446 if (session_send_msg(SESSION(session), ".") < 0) 447 return SM_ERROR; 448 log_print(LOG_PROTOCOL, "SMTP> . (EOM)\n"); 449 450 return SM_OK; 451 } 452 453 static gint smtp_session_recv_msg(Session *session, const gchar *msg) 454 { 455 SMTPSession *smtp_session = SMTP_SESSION(session); 456 gboolean cont = FALSE; 457 gint ret = 0; 458 459 if (strlen(msg) < 4) { 460 log_warning(LOG_PROTOCOL, _("bad SMTP response\n")); 461 return -1; 462 } 463 464 switch (smtp_session->state) { 465 case SMTP_EHLO: 466 case SMTP_STARTTLS: 467 case SMTP_AUTH: 468 case SMTP_AUTH_PLAIN: 469 case SMTP_AUTH_LOGIN_USER: 470 case SMTP_AUTH_LOGIN_PASS: 471 case SMTP_AUTH_OAUTH2: 472 default: 473 log_print(LOG_PROTOCOL, "SMTP< %s\n", msg); 474 break; 475 } 476 477 /* ignore all multiline responses except for EHLO */ 478 if (msg[3] == '-' && smtp_session->state != SMTP_EHLO) 479 return session_recv_msg(session); 480 481 if (msg[0] == '5' && msg[1] == '0' && 482 (msg[2] == '4' || msg[2] == '3' || msg[2] == '1')) { 483 log_warning(LOG_PROTOCOL, _("error occurred on SMTP session\n")); 484 smtp_session->state = SMTP_ERROR; 485 smtp_session->error_val = SM_ERROR; 486 g_free(smtp_session->error_msg); 487 smtp_session->error_msg = g_strdup(msg); 488 return -1; 489 } 490 491 if (!strncmp(msg, "535", 3)) { 492 log_warning(LOG_PROTOCOL, _("error occurred on authentication\n")); 493 smtp_session->state = SMTP_ERROR; 494 smtp_session->error_val = SM_AUTHFAIL; 495 g_free(smtp_session->error_msg); 496 smtp_session->error_msg = g_strdup(msg); 497 return -1; 498 } 499 500 if (msg[0] != '1' && msg[0] != '2' && msg[0] != '3') { 501 log_warning(LOG_PROTOCOL, _("error occurred on SMTP session\n")); 502 smtp_session->state = SMTP_ERROR; 503 smtp_session->error_val = SM_ERROR; 504 g_free(smtp_session->error_msg); 505 smtp_session->error_msg = g_strdup(msg); 506 return -1; 507 } 508 509 if (msg[3] == '-') 510 cont = TRUE; 511 else if (msg[3] != ' ' && msg[3] != '\0') { 512 log_warning(LOG_PROTOCOL, _("bad SMTP response\n")); 513 smtp_session->state = SMTP_ERROR; 514 smtp_session->error_val = SM_UNRECOVERABLE; 515 return -1; 516 } 517 518 switch (smtp_session->state) { 519 case SMTP_READY: 520 if (strstr(msg, "ESMTP")) 521 smtp_session->is_esmtp = TRUE; 522 if (smtp_session->user || session->ssl_type != SSL_NONE || 523 smtp_session->is_esmtp) 524 ret = smtp_ehlo(smtp_session); 525 else 526 ret = smtp_helo(smtp_session); 527 break; 528 case SMTP_HELO: 529 ret = smtp_from(smtp_session); 530 break; 531 case SMTP_EHLO: 532 ret = smtp_ehlo_recv(smtp_session, msg); 533 if (cont == TRUE) 534 break; 535 if (smtp_session->max_message_size > 0 536 && smtp_session->max_message_size < 537 smtp_session->send_data_len) { 538 log_warning(LOG_PROTOCOL, _("Message is too big " 539 "(Maximum size is %s)\n"), 540 to_human_readable( 541 (goffset)(smtp_session->max_message_size))); 542 smtp_session->state = SMTP_ERROR; 543 smtp_session->error_val = SM_ERROR; 544 return -1; 545 } 546 if (session->ssl_type == SSL_STARTTLS && 547 smtp_session->tls_init_done == FALSE) { 548 ret = smtp_starttls(smtp_session); 549 break; 550 } 551 if (smtp_session->user) { 552 if (smtp_auth(smtp_session) != SM_OK) { 553 if (session->ssl_type == SSL_NONE 554 && smtp_session->tls_init_done == FALSE 555 && (smtp_session->avail_auth_type & SMTPAUTH_TLS_AVAILABLE)) 556 ret = smtp_starttls(smtp_session); 557 else 558 ret = smtp_from(smtp_session); 559 } 560 } else 561 ret = smtp_from(smtp_session); 562 break; 563 case SMTP_STARTTLS: 564 if (session_start_tls(session) < 0) { 565 log_warning(LOG_PROTOCOL, _("couldn't start STARTTLS session\n")); 566 smtp_session->state = SMTP_ERROR; 567 smtp_session->error_val = SM_ERROR; 568 return -1; 569 } 570 smtp_session->tls_init_done = TRUE; 571 ret = smtp_ehlo(smtp_session); 572 break; 573 case SMTP_AUTH: 574 ret = smtp_auth_recv(smtp_session, msg); 575 break; 576 case SMTP_AUTH_LOGIN_USER: 577 ret = smtp_auth_login_user_recv(smtp_session, msg); 578 break; 579 case SMTP_AUTH_PLAIN: 580 case SMTP_AUTH_LOGIN_PASS: 581 case SMTP_AUTH_OAUTH2: 582 case SMTP_FROM: 583 if (smtp_session->cur_to) 584 ret = smtp_rcpt(smtp_session); 585 break; 586 case SMTP_RCPT: 587 if (smtp_session->cur_to) 588 ret = smtp_rcpt(smtp_session); 589 else 590 ret = smtp_data(smtp_session); 591 break; 592 case SMTP_DATA: 593 ret = smtp_send_data(smtp_session); 594 break; 595 case SMTP_EOM: 596 smtp_make_ready(smtp_session); 597 break; 598 case SMTP_QUIT: 599 session_disconnect(session); 600 break; 601 case SMTP_ERROR: 602 default: 603 log_warning(LOG_PROTOCOL, _("error occurred on SMTP session\n")); 604 smtp_session->error_val = SM_ERROR; 605 return -1; 606 } 607 608 if (cont && ret == SM_OK) 609 return session_recv_msg(session); 610 611 if (ret != SM_OK) 612 smtp_session->error_val = SM_ERROR; 613 614 return ret == SM_OK ? 0 : -1; 615 } 616 617 static gint smtp_session_send_data_finished(Session *session, guint len) 618 { 619 return smtp_eom(SMTP_SESSION(session)); 620 }