try to authenticate with CRAM-MD5
[claws.git] / src / esmtp.c
1 /*
2  * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3  * Copyright (C) 1999-2002 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 2 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, write to the Free Software
17  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18  */
19
20 #include <glib.h>
21 #include <stdio.h>
22 #include <string.h>
23
24 #include "esmtp.h"
25 #include "smtp.h"
26 #include "socket.h"
27 #include "utils.h"
28 #include "md5.h"
29 #include "base64.h"
30
31 #define MSGBUFSIZE      8192
32
33 static gint verbose = 1;
34 static gchar esmtp_response[MSGBUFSIZE];
35
36 gint esmtp_ehlo(SockInfo *sock, const gchar *hostname)
37 {
38         smtp_auth_methods[0] = smtp_auth_methods[1] = smtp_auth_methods[2] = smtp_auth_methods[3] = FALSE;
39         sock_printf(sock, "EHLO %s\r\n", hostname);
40         if (verbose)
41                 log_print("ESMTP> EHLO %s\n", hostname);
42
43         return esmtp_ok(sock);
44 }
45
46 gint esmtp_starttls(SockInfo *sock)
47 {
48         sock_printf(sock, "STARTTLS\r\n");
49         if (verbose)
50                 log_print("ESMTP> STARTTLS\n");
51
52         return esmtp_ok(sock);
53 }
54
55 gint esmtp_auth_cram_md5(SockInfo *sock)
56 {
57         sock_printf(sock, "AUTH CRAM-MD5\r\n");
58         if (verbose)
59                 log_print("ESMTP> AUTH CRAM-MD5\n");
60
61         return esmtp_ok(sock);
62 }
63
64 gint esmtp_auth_login(SockInfo *sock)
65 {
66         sock_printf(sock, "AUTH LOGIN\r\n");
67         if (verbose)
68                 log_print("ESMTP> AUTH LOGIN\n");
69
70         return esmtp_ok(sock);
71 }
72
73 gint esmtp_auth(SockInfo *sock, SMTPAuthType authtype,
74                 const gchar *userid, const gchar *passwd)
75 {
76         gchar buf[MSGBUFSIZE];
77         guchar hexdigest[33];
78         gchar *challenge, *response, *response64;
79         gint challengelen;
80
81         switch (authtype) {
82         case SMTPAUTH_LOGIN:
83                 if (!strncmp(esmtp_response, "334 ", 4))
84                         to64frombits(buf, userid, strlen(userid));
85                 else
86                         /* Server rejects AUTH */
87                         g_snprintf(buf, sizeof(buf), "*");
88
89                 sock_printf(sock, "%s\r\n", buf);
90                 if (verbose) log_print("ESMTP> USERID\n");
91
92                 esmtp_ok(sock); /* to read the answer from the server */
93
94                 if (!strncmp(esmtp_response, "334 ", 4))
95                         to64frombits(buf, passwd, strlen(passwd));
96                 else
97                         /* Server rejects AUTH */
98                         g_snprintf(buf, sizeof(buf), "*");
99
100                 sock_printf(sock, "%s\r\n", buf);
101                 if (verbose) log_print("ESMTP> PASSWORD\n");
102                 break;
103         case SMTPAUTH_CRAM_MD5:
104                 if (!strncmp(esmtp_response, "334 ", 4)) {
105                         /* remove 334 from esmtp_response */
106                         gchar *p = esmtp_response + 4;
107
108                         challenge = g_malloc(strlen(p) + 1);
109                         challengelen = from64tobits(challenge, p);
110                         challenge[challengelen] = '\0';
111                         if (verbose)
112                                 log_print("ESMTP< [Decoded: %s]\n", challenge);
113
114                         g_snprintf(buf, sizeof(buf), "%s", passwd);
115                         md5_hex_hmac(hexdigest, challenge, challengelen,
116                                      buf, strlen(passwd));
117                         g_free(challenge);
118
119                         response = g_strdup_printf("%s %s", userid, hexdigest);
120                         if (verbose)
121                                 log_print("ESMTP> [Encoded: %s]\n", response);
122
123                         response64 = g_malloc((strlen(response) + 3) * 2 + 1);
124                         to64frombits(response64, response, strlen(response));
125                         g_free(response);
126
127                         sock_printf(sock, "%s\r\n", response64);
128                         if (verbose) log_print("ESMTP> %s\n", response64);
129                         g_free(response64);
130                 } else {
131                         /* Server rejects AUTH */
132                         g_snprintf(buf, sizeof(buf), "*");
133                         sock_printf(sock, "%s\r\n", buf);
134                         if (verbose)
135                                 log_print("ESMTP> %s\n",buf);
136                 }
137                 break;
138         case SMTPAUTH_DIGEST_MD5:
139         default:
140                 /* stop esmtp_auth when no correct authtype */
141                 g_snprintf(buf, sizeof(buf), "*");
142                 sock_printf(sock, "%s\r\n", buf);
143                 if (verbose) log_print("ESMTP> %s\n", buf);
144                 break;
145         }
146
147         return esmtp_ok(sock);
148 }
149
150 gint esmtp_ok(SockInfo *sock)
151 {
152         while (sock_gets(sock, esmtp_response, sizeof(esmtp_response) - 1)
153                != -1) {
154                 if (strlen(esmtp_response) < 4)
155                         return SM_ERROR;
156                 strretchomp(esmtp_response);
157
158                 if (verbose)
159                         log_print("ESMTP< %s\n", esmtp_response);
160
161                 if (strncasecmp("250-AUTH", esmtp_response, 8) == 0) {
162                         smtp_auth_methods[SMTPAUTH_LOGIN]      = (strstr(esmtp_response, " LOGIN") != NULL); 
163                         smtp_auth_methods[SMTPAUTH_CRAM_MD5]   = (strstr(esmtp_response, " CRAM-MD5") != NULL);
164                         smtp_auth_methods[SMTPAUTH_DIGEST_MD5] = FALSE; /* not implemented yet */
165                 }
166
167                 if ((esmtp_response[0] == '1' || esmtp_response[0] == '2' ||
168                      esmtp_response[0] == '3') && esmtp_response[3] == ' ')
169                         return SM_OK;
170                 else if (esmtp_response[3] != '-')
171                         return SM_ERROR;
172                 else if (esmtp_response[0] == '5' &&
173                          esmtp_response[1] == '0' &&
174                          (esmtp_response[2] == '4' ||
175                           esmtp_response[2] == '3' ||
176                           esmtp_response[2] == '1'))
177                         return SM_ERROR;
178         }
179
180         return SM_UNRECOVERABLE;
181 }