2 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3 * Copyright (C) 1999,2000 Hiroyuki Yamamoto
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.
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.
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.
31 #define MSGBUFSIZE 8192
33 static gint verbose = 1;
34 static gchar esmtp_response[MSGBUFSIZE];
38 ** taken from the file rfc2104.txt
40 void hmac_md5(guchar *text, gint text_len, guchar *key, gint key_len,
44 guchar k_ipad[65]; /* inner padding -
47 guchar k_opad[65]; /* outer padding -
53 /* if key is longer than 64 bytes reset it to key=MD5(key) */
58 MD5Update(&tctx, key, key_len);
66 * the HMAC_MD5 transform looks like:
68 * MD5(K XOR opad, MD5(K XOR ipad, text))
70 * where K is an n byte key
71 * ipad is the byte 0x36 repeated 64 times
72 * opad is the byte 0x5c repeated 64 times
73 * and text is the data being protected
76 /* start out by storing key in pads */
77 bzero(k_ipad, sizeof k_ipad);
78 bzero(k_opad, sizeof k_opad);
79 bcopy(key, k_ipad, key_len);
80 bcopy(key, k_opad, key_len);
82 /* XOR key with ipad and opad values */
83 for (i = 0; i < 64; i++) {
91 MD5Init(&context); /* init context for 1st
93 MD5Update(&context, k_ipad, 64); /* start with inner pad */
94 MD5Update(&context, text, text_len); /* then text of datagram */
95 MD5Final(digest, &context); /* finish up 1st pass */
100 MD5Init(&context); /* init context for 2nd
102 MD5Update(&context, k_opad, 64); /* start with outer pad */
103 MD5Update(&context, digest, 16); /* then results of 1st
105 MD5Final(digest, &context); /* finish up 2nd pass */
108 void md5_hex_hmac(gchar *hexdigest, guchar *text, gint text_len,
109 guchar *key, gint key_len)
114 hmac_md5(text, text_len, key, key_len, digest);
115 for(i = 0; i < 16; i++)
116 sprintf(hexdigest + 2 * i, "%02x", digest[i]);
119 gint esmtp_auth_cram_md5(gint sock)
121 gchar buf[MSGBUFSIZE];
123 g_snprintf(buf, sizeof(buf), "AUTH CRAM-MD5");
124 sock_printf(sock, "%s\r\n", buf);
127 log_print("ESMTP> %s\n", buf);
129 return esmtp_ok(sock);
132 gint esmtp_auth_login(gint sock)
134 gchar buf[MSGBUFSIZE];
136 g_snprintf(buf, sizeof(buf), "AUTH LOGIN");
137 sock_printf(sock, "%s\r\n", buf);
140 log_print("ESMTP> %s\n", buf);
142 return esmtp_ok(sock);
145 gint esmtp_auth(gint sock, SMTPAuthType authtype,
146 const gchar *userid, const gchar *passwd,
147 gboolean use_smtp_auth)
149 gchar buf[MSGBUFSIZE];
150 guchar hexdigest[33];
151 gchar *challenge, *response, *response64;
153 //const gchar delimiters[]=" ";
158 if (!strncmp(esmtp_response, "334 ", 4))
159 to64frombits(buf, userid, strlen(userid));
161 /* Server rejects AUTH */
162 g_snprintf(buf, sizeof(buf), "*");
164 sock_printf(sock, "%s\r\n", buf);
165 if (verbose) log_print("ESMTP> USERID\n");
167 esmtp_ok(sock); /* to read the answer from the server */
169 if (!strncmp(esmtp_response, "334 ", 4))
170 to64frombits(buf, passwd, strlen(passwd));
172 /* Server rejects AUTH */
173 g_snprintf(buf, sizeof(buf), "*");
175 sock_printf(sock, "%s\r\n", buf);
176 if (verbose) log_print("ESMTP> PASSWORD\n");
178 case SMTPAUTH_CRAM_MD5:
179 if (!strncmp(esmtp_response, "334 ", 4)) {
180 /* remove 334 from esmtp_response */
181 g_snprintf(buf, sizeof(buf), "%s",esmtp_response);
182 token = strtok(buf, " ");
183 token = strtok(NULL, " ");
184 challenge = g_malloc(strlen(token)+1);
185 challengelen = from64tobits(challenge,token);
187 log_print("ESMTP< Decoded: %s\n", challenge);
189 g_snprintf(buf, sizeof(buf), "%s", passwd);
190 md5_hex_hmac(hexdigest, challenge, challengelen,
191 buf, strlen(passwd));
193 response = g_strdup_printf("%s %s", userid, hexdigest);
195 log_print("ESMTP> Encoded %s\n",response);
197 response64 = g_malloc((strlen(response) + 3) * 2 + 1);
198 to64frombits(response64, response, strlen(response));
201 sock_printf(sock, "%s\r\n", response64);
202 if (verbose) log_print("ESMTP> %s\n", response64);
205 /* Server rejects AUTH */
206 g_snprintf(buf, sizeof(buf), "*");
207 sock_printf(sock, "%s\r\n", buf);
209 log_print("ESMTP> %s\n",buf);
212 case SMTPAUTH_DIGEST_MD5:
214 /* stop esmtp_auth when no correct authtype */
215 g_snprintf(buf, sizeof(buf), "*");
216 sock_printf(sock, "%s\r\n", buf);
217 if (verbose) log_print("ESMTP> %s\n", buf);
221 return esmtp_ok(sock);
224 gint esmtp_ok(gint sock)
226 while (sock_read(sock, esmtp_response, sizeof(esmtp_response) - 1)
228 if (strlen(esmtp_response) < 4)
230 strretchomp(esmtp_response);
233 log_print("ESMTP< %s\n", esmtp_response);
235 if ((esmtp_response[0] == '1' || esmtp_response[0] == '2' ||
236 esmtp_response[0] == '3') && esmtp_response[3] == ' ')
238 else if (esmtp_response[3] != '-')
240 else if (esmtp_response[0] == '5' &&
241 esmtp_response[1] == '0' &&
242 (esmtp_response[3] == '4' ||
243 esmtp_response[3] == '3' ||
244 esmtp_response[3] == '1'))
248 return SM_UNRECOVERABLE;