static gint smtp_auth_login(SMTPSession *session) { session->state = SMTP_AUTH; session->auth_type = SMTPAUTH_LOGIN; if (session_send_msg(SESSION(session), SESSION_MSG_NORMAL, "AUTH LOGIN") < 0) return SM_ERROR; log_print(LOG_PROTOCOL, "ESMTP> AUTH LOGIN\n"); return SM_OK; }
static gint smtp_auth_cram_md5(SMTPSession *session) { session->state = SMTP_AUTH; session->auth_type = SMTPAUTH_CRAM_MD5; if (session_send_msg(SESSION(session), SESSION_MSG_NORMAL, "AUTH CRAM-MD5") < 0) return SM_ERROR; log_print(LOG_PROTOCOL, "ESMTP> AUTH CRAM-MD5\n"); return SM_OK; }
static gint sieve_auth_login(SieveSession *session) { session->state = SIEVE_AUTH; session->auth_type = SIEVEAUTH_LOGIN; if (session_send_msg(SESSION(session), SESSION_MSG_NORMAL, "Authenticate \"LOGIN\"") < 0) return SE_ERROR; log_print(LOG_PROTOCOL, "Sieve> Authenticate LOGIN\n"); return SE_OK; }
static gint sieve_auth_cram_md5(SieveSession *session) { session->state = SIEVE_AUTH; session->auth_type = SIEVEAUTH_CRAM_MD5; if (session_send_msg(SESSION(session), SESSION_MSG_NORMAL, "Authenticate \"CRAM-MD5\"") < 0) return SE_ERROR; log_print(LOG_PROTOCOL, "Sieve> Authenticate CRAM-MD5\n"); return SE_OK; }
static gint smtp_auth_plain(SMTPSession *session) { gchar buf[MESSAGEBUFSIZE]; /* * +1 +1 +1 * \0<user>\0<pass>\0 */ int b64len = (1 + strlen(session->user) + 1 + strlen(session->pass) + 1); gchar *b64buf = g_malloc(b64len); /* use the char *ptr to walk the base64 string with embedded \0 */ char *a = b64buf; int b64cnt = 0; session->state = SMTP_AUTH_PLAIN; session->auth_type = SMTPAUTH_PLAIN; memset(buf, 0, sizeof buf); /* * have to construct the string bit by bit. sprintf can't do it in one. * first field is null, so string is \0<user>\0<password> */ *a = 0; a++; g_snprintf (a, b64len - 1, "%s", session->user); b64cnt = strlen(session->user)+1; a += b64cnt; g_snprintf (a, b64len - b64cnt - 1, "%s", session->pass); b64cnt += strlen(session->pass) + 1; /* * reuse the char *ptr to offset into the textbuf to meld * the plaintext ESMTP message and the base64 string value */ strcpy(buf, "AUTH PLAIN "); a = buf + strlen(buf); base64_encode(a, b64buf, b64cnt); if (session_send_msg(SESSION(session), SESSION_MSG_NORMAL, buf) < 0) return SM_ERROR; log_print(LOG_PROTOCOL, "ESMTP> [AUTH PLAIN]\n"); g_free(b64buf); return SM_OK; }
static gint smtp_helo(SMTPSession *session) { gchar buf[MSGBUFSIZE]; session->state = SMTP_HELO; g_snprintf(buf, sizeof(buf), "HELO %s", session->hostname ? session->hostname : get_domain_name()); session_send_msg(SESSION(session), SESSION_MSG_NORMAL, buf); log_print("SMTP> %s\n", buf); return SM_OK; }
static void pop3_gen_send(Pop3Session *session, const gchar *format, ...) { gchar buf[POPBUFSIZE + 1]; va_list args; va_start(args, format); g_vsnprintf(buf, sizeof(buf) - 2, format, args); va_end(args); if (!g_ascii_strncasecmp(buf, "PASS ", 5)) log_print(LOG_PROTOCOL, "POP3> PASS ********\n"); else log_print(LOG_PROTOCOL, "POP3> %s\n", buf); session_send_msg(SESSION(session), SESSION_MSG_NORMAL, buf); }
static gint smtp_ehlo(SMTPSession *session) { gchar buf[MESSAGEBUFSIZE]; session->state = SMTP_EHLO; session->avail_auth_type = 0; g_snprintf(buf, sizeof(buf), "EHLO %s", session->hostname ? session->hostname : get_domain_name()); if (session_send_msg(SESSION(session), SESSION_MSG_NORMAL, buf) < 0) return SM_ERROR; log_print(LOG_PROTOCOL, "ESMTP> %s\n", buf); return SM_OK; }
static gint smtp_auth_login_user_recv(SMTPSession *session, const gchar *msg) { gchar buf[MSGBUFSIZE]; session->state = SMTP_AUTH_LOGIN_PASS; if (!strncmp(msg, "334 ", 4)) base64_encode(buf, session->pass, strlen(session->pass)); else /* Server rejects AUTH */ g_snprintf(buf, sizeof(buf), "*"); session_send_msg(SESSION(session), SESSION_MSG_NORMAL, buf); log_print("ESMTP> [PASSWORD]\n"); return SM_OK; }
static void sieve_queue_send(SieveSession *session, SieveState next_state, gchar *msg, sieve_session_data_cb_fn cb, gpointer data) { gboolean queue = FALSE; SieveCommand *cmd = g_new0(SieveCommand, 1); cmd->session = session; cmd->next_state = next_state; cmd->msg = msg; cmd->data = data; cmd->cb = cb; if (!session_is_connected(SESSION(session))) { log_print(LOG_PROTOCOL, "Sieve: connecting to %s:%hu\n", session->host, session->port); if (sieve_session_connect(session) < 0) { sieve_connect_finished(SESSION(session), FALSE); } queue = TRUE; } else if (session->state == SIEVE_RETRY_AUTH) { log_print(LOG_PROTOCOL, _("Sieve: retrying auth\n")); if (sieve_auth(session) == SE_AUTHFAIL) sieve_error(session, _("Auth method not available")); queue = TRUE; } else if (session->state != SIEVE_READY) { log_print(LOG_PROTOCOL, "Sieve: in state %d\n", session->state); queue = TRUE; } if (queue) { session->send_queue = g_slist_prepend(session->send_queue, cmd); } else { if (session->current_cmd) command_free(session->current_cmd); session->current_cmd = cmd; session->state = next_state; log_send(session, cmd); if (session_send_msg(SESSION(session), SESSION_SEND, cmd->msg) < 0) { /* error */ } } }
static gint smtp_rcpt(SMTPSession *session) { gchar buf[MSGBUFSIZE]; gchar *to; g_return_val_if_fail(session->cur_to != NULL, SM_ERROR); session->state = SMTP_RCPT; to = (gchar *)session->cur_to->data; if (strchr(to, '<')) g_snprintf(buf, sizeof(buf), "RCPT TO:%s", to); else g_snprintf(buf, sizeof(buf), "RCPT TO:<%s>", to); session_send_msg(SESSION(session), SESSION_MSG_NORMAL, buf); log_print("SMTP> %s\n", buf); session->cur_to = session->cur_to->next; return SM_OK; }
static gint smtp_auth_login_user_recv(SMTPSession *session, const gchar *msg) { gchar *tmp; session->state = SMTP_AUTH_LOGIN_PASS; if (!strncmp(msg, "334 ", 4)) { tmp = g_base64_encode(session->pass, strlen(session->pass)); } else { /* Server rejects AUTH */ tmp = g_strdup("*"); } if (session_send_msg(SESSION(session), SESSION_MSG_NORMAL, tmp) < 0) { g_free(tmp); return SM_ERROR; } g_free(tmp); log_print(LOG_PROTOCOL, "ESMTP> [PASSWORD]\n"); return SM_OK; }
static gint smtp_auth_recv(SMTPSession *session, const gchar *msg) { gchar buf[MSGBUFSIZE]; switch (session->auth_type) { case SMTPAUTH_LOGIN: session->state = SMTP_AUTH_LOGIN_USER; if (!strncmp(msg, "334 ", 4)) { base64_encode(buf, session->user, strlen(session->user)); session_send_msg(SESSION(session), SESSION_MSG_NORMAL, buf); log_print("ESMTP> [USERID]\n"); } else { /* Server rejects AUTH */ session_send_msg(SESSION(session), SESSION_MSG_NORMAL, "*"); log_print("ESMTP> *\n"); } break; case SMTPAUTH_CRAM_MD5: session->state = SMTP_AUTH_CRAM_MD5; if (!strncmp(msg, "334 ", 4)) { gchar *response; gchar *response64; gchar *challenge; gint challengelen; guchar hexdigest[33]; challenge = g_malloc(strlen(msg + 4) + 1); challengelen = base64_decode(challenge, msg + 4, -1); challenge[challengelen] = '\0'; log_print("ESMTP< [Decoded: %s]\n", challenge); g_snprintf(buf, sizeof(buf), "%s", session->pass); md5_hex_hmac(hexdigest, challenge, challengelen, buf, strlen(session->pass)); g_free(challenge); response = g_strdup_printf ("%s %s", session->user, hexdigest); log_print("ESMTP> [Encoded: %s]\n", response); response64 = g_malloc((strlen(response) + 3) * 2 + 1); base64_encode(response64, response, strlen(response)); g_free(response); session_send_msg(SESSION(session), SESSION_MSG_NORMAL, response64); log_print("ESMTP> %s\n", response64); g_free(response64); } else { /* Server rejects AUTH */ session_send_msg(SESSION(session), SESSION_MSG_NORMAL, "*"); log_print("ESMTP> *\n"); } break; case SMTPAUTH_DIGEST_MD5: default: /* stop smtp_auth when no correct authtype */ session_send_msg(SESSION(session), SESSION_MSG_NORMAL, "*"); log_print("ESMTP> *\n"); break; } return SM_OK; }
static gint sieve_session_recv_msg(Session *session, const gchar *msg) { SieveSession *sieve_session = SIEVE_SESSION(session); SieveResult result; gint ret = SE_OK; log_print(LOG_PROTOCOL, "Sieve< %s\n", msg); if (response_is_bye(msg)) { gchar *status; parse_response((gchar *)msg, &result); if (!result.description) status = g_strdup(_("Disconnected")); else if (g_str_has_prefix(result.description, "Disconnected")) status = g_strdup(result.description); else status = g_strdup_printf(_("Disconnected: %s"), result.description); sieve_session->error = SE_ERROR; sieve_error(sieve_session, status); sieve_session->state = SIEVE_DISCONNECTED; g_free(status); return -1; } switch (sieve_session->state) { case SIEVE_CAPABILITIES: if (response_is_ok(msg)) { /* capabilities list done */ #ifdef USE_GNUTLS if (sieve_session->tls_init_done == FALSE && sieve_session->config->tls_type != SIEVE_TLS_NO) { if (sieve_session->capability.starttls) { log_print(LOG_PROTOCOL, "Sieve> STARTTLS\n"); session_send_msg(session, SESSION_SEND, "STARTTLS"); sieve_session->state = SIEVE_STARTTLS; } else if (sieve_session->config->tls_type == SIEVE_TLS_YES) { log_warning(LOG_PROTOCOL, "Sieve: does not support STARTTLS\n"); sieve_session->state = SIEVE_ERROR; } else { log_warning(LOG_PROTOCOL, "Sieve: continuing without TLS\n"); sieve_session->state = SIEVE_READY; } break; } #endif /* authenticate after getting capabilities */ if (!sieve_session->authenticated) { ret = sieve_auth(sieve_session); } else { sieve_session->state = SIEVE_READY; sieve_connected(sieve_session, TRUE); } } else { /* got a capability */ gchar *cap_name, *cap_value; parse_split((gchar *)msg, &cap_name, &cap_value); sieve_got_capability(sieve_session, cap_name, cap_value); } break; case SIEVE_READY: if (!msg[0]) break; log_warning(LOG_PROTOCOL, _("unhandled message on Sieve session: %s\n"), msg); break; case SIEVE_STARTTLS: #ifdef USE_GNUTLS if (session_start_tls(session) < 0) { sieve_session->state = SIEVE_ERROR; sieve_session->error = SE_ERROR; sieve_error(sieve_session, _("TLS failed")); return -1; } sieve_session->tls_init_done = TRUE; sieve_session->state = SIEVE_CAPABILITIES; #endif break; case SIEVE_AUTH: ret = sieve_auth_recv(sieve_session, msg); break; case SIEVE_AUTH_LOGIN_USER: ret = sieve_auth_login_user_recv(sieve_session, msg); break; case SIEVE_AUTH_PLAIN: case SIEVE_AUTH_LOGIN_PASS: case SIEVE_AUTH_CRAM_MD5: if (response_is_no(msg)) { log_print(LOG_PROTOCOL, "Sieve auth failed\n"); session->state = SIEVE_RETRY_AUTH; ret = SE_AUTHFAIL; } else if (response_is_ok(msg)) { log_print(LOG_PROTOCOL, "Sieve auth completed\n"); sieve_error(sieve_session, ""); sieve_session->authenticated = TRUE; sieve_session->state = SIEVE_READY; sieve_connected(sieve_session, TRUE); } break; case SIEVE_NOOP: if (!response_is_ok(msg)) { sieve_session->state = SIEVE_ERROR; } sieve_session->state = SIEVE_READY; break; case SIEVE_LISTSCRIPTS: if (response_is_no(msg)) { /* got an error. probably not authenticated. */ command_cb(sieve_session->current_cmd, NULL); sieve_session->state = SIEVE_READY; } else if (response_is_ok(msg)) { /* end of list */ sieve_session->state = SIEVE_READY; sieve_session->error = SE_OK; command_cb(sieve_session->current_cmd, (gpointer)&(SieveScript){0}); } else { /* got a script name */ SieveScript script; gchar *script_status; parse_split((gchar *)msg, &script.name, &script_status); script.active = (script_status && strcasecmp(script_status, "active") == 0); command_cb(sieve_session->current_cmd, (gpointer)&script); } break; case SIEVE_RENAMESCRIPT: if (response_is_no(msg)) { /* error */ command_cb(sieve_session->current_cmd, NULL); } else if (response_is_ok(msg)) { command_cb(sieve_session->current_cmd, (void*)TRUE); } else { log_warning(LOG_PROTOCOL, _("error occurred on SIEVE session\n")); } sieve_session->state = SIEVE_READY; break; case SIEVE_SETACTIVE: parse_response((gchar *)msg, &result); if (result.success) { /* clear status possibly set when setting another * script active. TODO: give textual feedback */ sieve_error(sieve_session, ""); command_cb(sieve_session->current_cmd, NULL); } else if (result.description) { command_cb(sieve_session->current_cmd, result.description); } else { log_warning(LOG_PROTOCOL, _("error occurred on SIEVE session\n")); } if (result.has_octets) { return sieve_session_recv_chunk(sieve_session, result.octets); } else { sieve_session->state = SIEVE_READY; } break; case SIEVE_GETSCRIPT: if (response_is_no(msg)) { command_cb(sieve_session->current_cmd, (void *)-1); sieve_session->state = SIEVE_READY; } else { parse_response((gchar *)msg, &result); sieve_session->state = SIEVE_GETSCRIPT_DATA; return sieve_session_recv_chunk(sieve_session, result.octets); } break; case SIEVE_GETSCRIPT_DATA: if (!msg[0]) break; sieve_session->state = SIEVE_READY; if (response_is_ok(msg)) { command_cb(sieve_session->current_cmd, NULL); } else if (msg[0]) { log_warning(LOG_PROTOCOL, _("error occurred on SIEVE session\n")); } break; case SIEVE_PUTSCRIPT: if (!msg[0]) break; parse_response((gchar *)msg, &result); sieve_session_putscript_cb(sieve_session, &result); if (result.has_octets) { return sieve_session_recv_chunk(sieve_session, result.octets); } else { sieve_session->state = SIEVE_READY; } break; case SIEVE_DELETESCRIPT: parse_response((gchar *)msg, &result); if (!result.success) { command_cb(sieve_session->current_cmd, result.description); } else { command_cb(sieve_session->current_cmd, NULL); } sieve_session->state = SIEVE_READY; break; case SIEVE_ERROR: log_warning(LOG_PROTOCOL, _("error occurred on Sieve session. data: %s\n"), msg); sieve_session->error = SE_ERROR; break; case SIEVE_RETRY_AUTH: log_warning(LOG_PROTOCOL, _("unhandled message on Sieve session: %s\n"), msg); ret = sieve_auth(sieve_session); break; default: log_warning(LOG_PROTOCOL, _("unhandled message on Sieve session: %d\n"), sieve_session->state); sieve_session->error = SE_ERROR; return -1; } if (ret == SE_OK && sieve_session->state == SIEVE_READY) ret = sieve_pop_send_queue(sieve_session); if (ret == SE_OK) { return session_recv_msg(session); } else if (ret == SE_AUTHFAIL) { sieve_error(sieve_session, _("Auth failed")); sieve_session->state = SIEVE_ERROR; sieve_session->error = SE_ERROR; } return 0; }
static gint sieve_auth_recv(SieveSession *session, const gchar *msg) { gchar buf[MESSAGEBUFSIZE], *tmp; switch (session->auth_type) { case SIEVEAUTH_LOGIN: session->state = SIEVE_AUTH_LOGIN_USER; if (strstr(msg, "VXNlcm5hbWU6")) { tmp = g_base64_encode(session->user, strlen(session->user)); g_snprintf(buf, sizeof(buf), "\"%s\"", tmp); if (session_send_msg(SESSION(session), SESSION_MSG_NORMAL, buf) < 0) { g_free(tmp); return SE_ERROR; } g_free(tmp); log_print(LOG_PROTOCOL, "Sieve> [USERID]\n"); } else { /* Server rejects AUTH */ if (session_send_msg(SESSION(session), SESSION_MSG_NORMAL, "\"*\"") < 0) return SE_ERROR; log_print(LOG_PROTOCOL, "Sieve> *\n"); } break; case SIEVEAUTH_CRAM_MD5: session->state = SIEVE_AUTH_CRAM_MD5; if (msg[0] == '"') { gchar *response; gchar *response64; gchar *challenge, *tmp; gsize challengelen; guchar hexdigest[33]; tmp = g_base64_decode(msg + 1, &challengelen); challenge = g_strndup(tmp, challengelen); g_free(tmp); log_print(LOG_PROTOCOL, "Sieve< [Decoded: %s]\n", challenge); g_snprintf(buf, sizeof(buf), "%s", session->pass); md5_hex_hmac(hexdigest, challenge, challengelen, buf, strlen(session->pass)); g_free(challenge); response = g_strdup_printf ("%s %s", session->user, hexdigest); log_print(LOG_PROTOCOL, "Sieve> [Encoded: %s]\n", response); response64 = g_base64_encode(response, strlen(response)); g_free(response); response = g_strdup_printf("\"%s\"", response64); g_free(response64); if (session_send_msg(SESSION(session), SESSION_MSG_NORMAL, response) < 0) { g_free(response); return SE_ERROR; } log_print(LOG_PROTOCOL, "Sieve> %s\n", response); g_free(response); } else { /* Server rejects AUTH */ if (session_send_msg(SESSION(session), SESSION_MSG_NORMAL, "\"*\"") < 0) return SE_ERROR; log_print(LOG_PROTOCOL, "Sieve> *\n"); } break; default: /* stop sieve_auth when no correct authtype */ if (session_send_msg(SESSION(session), SESSION_MSG_NORMAL, "*") < 0) return SE_ERROR; log_print(LOG_PROTOCOL, "Sieve> *\n"); break; } return SE_OK; }
static gint smtp_auth_recv(SMTPSession *session, const gchar *msg) { gchar buf[MESSAGEBUFSIZE], *tmp; switch (session->auth_type) { case SMTPAUTH_LOGIN: session->state = SMTP_AUTH_LOGIN_USER; if (!strncmp(msg, "334 ", 4)) { tmp = g_base64_encode(session->user, strlen(session->user)); if (session_send_msg(SESSION(session), SESSION_MSG_NORMAL, tmp) < 0) { g_free(tmp); return SM_ERROR; } g_free(tmp); log_print(LOG_PROTOCOL, "ESMTP> [USERID]\n"); } else { /* Server rejects AUTH */ if (session_send_msg(SESSION(session), SESSION_MSG_NORMAL, "*") < 0) return SM_ERROR; log_print(LOG_PROTOCOL, "ESMTP> *\n"); } break; case SMTPAUTH_CRAM_MD5: session->state = SMTP_AUTH_CRAM_MD5; if (!strncmp(msg, "334 ", 4)) { gchar *response; gchar *response64; gchar *challenge; gsize challengelen; guchar hexdigest[33]; challenge = g_base64_decode_zero(msg + 4, &challengelen); log_print(LOG_PROTOCOL, "ESMTP< [Decoded: %s]\n", challenge); g_snprintf(buf, sizeof(buf), "%s", session->pass); md5_hex_hmac(hexdigest, challenge, challengelen, buf, strlen(session->pass)); g_free(challenge); response = g_strdup_printf ("%s %s", session->user, hexdigest); log_print(LOG_PROTOCOL, "ESMTP> [Encoded: %s]\n", response); response64 = g_base64_encode(response, strlen(response)); g_free(response); if (session_send_msg(SESSION(session), SESSION_MSG_NORMAL, response64) < 0) { g_free(response64); return SM_ERROR; } log_print(LOG_PROTOCOL, "ESMTP> %s\n", response64); g_free(response64); } else { /* Server rejects AUTH */ if (session_send_msg(SESSION(session), SESSION_MSG_NORMAL, "*") < 0) return SM_ERROR; log_print(LOG_PROTOCOL, "ESMTP> *\n"); } break; case SMTPAUTH_DIGEST_MD5: default: /* stop smtp_auth when no correct authtype */ if (session_send_msg(SESSION(session), SESSION_MSG_NORMAL, "*") < 0) return SM_ERROR; log_print(LOG_PROTOCOL, "ESMTP> *\n"); break; } return SM_OK; }