PAM for SMTP Authentication
リビジョン | f7b01492de3be20c4b379b376213bacad48e92e8 (tree) |
---|---|
日時 | 2011-09-14 09:26:27 |
作者 | Taizo ITO <taizo.ito@hde....> |
コミッター | Taizo ITO |
Within NAT environment, a smtp greeting message cannot be received correctly
@@ -369,7 +369,9 @@ smtp_auth(config_t *cfg) { | ||
369 | 369 | struct iovec iov[5]; |
370 | 370 | char *c; |
371 | 371 | int rc; |
372 | + int readBytes = 0; | |
372 | 373 | char rbuf[RESP_LEN]; |
374 | + char sockbuf[RESP_LEN]; | |
373 | 375 | int auth = 0; |
374 | 376 | int avail_auth_type = 0; |
375 | 377 | char *tbuf; |
@@ -465,9 +467,14 @@ smtp_auth(config_t *cfg) { | ||
465 | 467 | } |
466 | 468 | } |
467 | 469 | } |
468 | - addr.sin_addr.s_addr = *((int *)he->h_addr_list[0]); | |
469 | 470 | s = socket(PF_INET, SOCK_STREAM, 0); |
470 | 471 | |
472 | + addr.sin_family = AF_INET; | |
473 | + addr.sin_port = htons(cfg->port); | |
474 | + addr.sin_addr.s_addr = *((int *)he->h_addr_list[0]); | |
475 | + addr.sin_addr = *((struct in_addr *)he->h_addr); | |
476 | + memset(&(addr.sin_zero),'\0',8); | |
477 | + | |
471 | 478 | if(cfg->conn_timeout > 0) { |
472 | 479 | set_timeout(cfg->conn_timeout); |
473 | 480 | } |
@@ -505,7 +512,15 @@ smtp_auth(config_t *cfg) { | ||
505 | 512 | if(cfg->timeout > 0) { |
506 | 513 | set_timeout(cfg->timeout); |
507 | 514 | } |
508 | - rc = socket_read(smtp->sock, rbuf, sizeof(rbuf)); | |
515 | + | |
516 | + ////////////////////////////////// | |
517 | + //usleep(3000000); | |
518 | + memset(rbuf,0x00,sizeof(rbuf)); | |
519 | + memset(rbuf,0x00,sizeof(sockbuf)); | |
520 | + rc = socket_read(smtp->sock, sockbuf, sizeof(rbuf)-1); | |
521 | +#ifdef DEBUG | |
522 | + log_debug(DEBUG_1, "smtp_auth: read count: %d", rc); | |
523 | +#endif | |
509 | 524 | if(cfg->timeout > 0) { |
510 | 525 | set_timeout(0); |
511 | 526 | } |
@@ -519,11 +534,51 @@ smtp_auth(config_t *cfg) { | ||
519 | 534 | strcpy(smtp->error_message, msgbuf); |
520 | 535 | goto bail; |
521 | 536 | } |
522 | - rbuf[rc] = '\0'; | |
537 | + readBytes += rc; | |
538 | +#ifdef DEBUG | |
539 | + log_debug(DEBUG_1, "smtp_auth: 1st 220 response total read count %d", readBytes); | |
540 | +#endif | |
541 | + sockbuf[rc+1] = '\0'; | |
542 | + rbuf[readBytes+1] = '\0'; | |
543 | + strcat(rbuf, sockbuf); | |
544 | + c = strpbrk(rbuf, SMTP_NEWLINE); | |
545 | + if(c == NULL) { | |
546 | +#ifdef DEBUG | |
547 | + log_debug(DEBUG_1, "smtp_auth: 220 response is not terminated. try to read again. now: %s", rbuf); | |
548 | +#endif | |
549 | + rc = socket_read(smtp->sock, sockbuf, sizeof(sockbuf)-1); | |
550 | +#ifdef DEBUG | |
551 | + log_debug(DEBUG_1, "smtp_auth: read count: %d", rc); | |
552 | +#endif | |
553 | + if(cfg->timeout > 0) { | |
554 | + set_timeout(0); | |
555 | + } | |
556 | + if(rc == -1) { | |
557 | +#ifdef DEBUG | |
558 | + log_debug(DEBUG_1, "smtp_auth: read (banner): %m"); | |
559 | +#endif | |
560 | + smtp->error = 1; | |
561 | + strcpy(msgbuf, RESP_SYNCERROR); | |
562 | + smtp->error_message = malloc(strlen(msgbuf) + 1); | |
563 | + strcpy(smtp->error_message, msgbuf); | |
564 | + goto bail; | |
565 | + } | |
566 | + readBytes += rc; | |
567 | +#ifdef DEBUG | |
568 | + log_debug(DEBUG_1, "smtp_auth: 220 response total read count %d", readBytes); | |
569 | +#endif | |
570 | + sockbuf[rc+1] = '\0'; | |
571 | + rbuf[readBytes+1] = '\0'; | |
572 | + strcat(rbuf, sockbuf); | |
573 | + } | |
523 | 574 | c = strpbrk(rbuf, SMTP_NEWLINE); |
524 | - if(c != NULL) { | |
525 | - *c = '\0'; | |
575 | + if (c != NULL) { | |
576 | +#ifdef DEBUG | |
577 | + log_debug(DEBUG_1, "smtp_auth: 220 response is terminated. total read count: %d, now: %s", readBytes, rbuf); | |
578 | +#endif | |
579 | + rbuf[readBytes+1] = '\0'; | |
526 | 580 | } |
581 | + ////////////////////////////////// | |
527 | 582 | |
528 | 583 | if(strncmp(rbuf, "220 ", sizeof("220 ")-1)) { |
529 | 584 | #ifdef DEBUG |
@@ -575,14 +630,17 @@ smtp_auth(config_t *cfg) { | ||
575 | 630 | if(cfg->timeout > 0) { |
576 | 631 | set_timeout(cfg->timeout); |
577 | 632 | } |
633 | + | |
634 | + memset(rbuf,0x00,sizeof(rbuf)); | |
578 | 635 | rc = socket_read(smtp->sock, rbuf, sizeof(rbuf)); |
579 | 636 | if(cfg->timeout > 0) { |
580 | 637 | set_timeout(0); |
581 | 638 | } |
582 | - if(rc == -1) { | |
583 | 639 | #ifdef DEBUG |
584 | - log_debug(DEBUG_1, "smtp_auth: read (response): %m"); | |
640 | + log_debug(DEBUG_1, "smtp_auth: read (response): %m"); | |
641 | + log_debug(DEBUG_1, "smtp_auth: read (response): %s", rbuf); | |
585 | 642 | #endif |
643 | + if(rc == -1) { | |
586 | 644 | smtp->error = 1; |
587 | 645 | strcpy(msgbuf, RESP_IERROR); |
588 | 646 | smtp->error_message = malloc(strlen(msgbuf) + 1); |
@@ -0,0 +1,1435 @@ | ||
1 | +/* | |
2 | + * smtpauth.c | |
3 | + * $Id: smtpauth.c,v 1.14 2009/06/12 08:55:50 taizo Exp $ | |
4 | + * Copyright (C) 2009 HDE, Inc. | |
5 | + * | |
6 | + * This program is free software; you can redistribute it and/or modify | |
7 | + * it under the terms of the GNU General Public License as published by | |
8 | + * the Free Software Foundation; either version 2, or (at your option) | |
9 | + * any later version. | |
10 | + * | |
11 | + * This program is distributed in the hope that it will be useful, | |
12 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 | + * GNU General Public License for more details. | |
15 | + * | |
16 | + * You should have received a copy of the GNU General Public License | |
17 | + * along with GNU Emacs; see the file COPYING. If not, write to | |
18 | + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | |
19 | + */ | |
20 | + | |
21 | +#define _GNU_SOURCE | |
22 | +#include <stdio.h> | |
23 | +#include <stdlib.h> | |
24 | +#include <string.h> | |
25 | +#include <unistd.h> | |
26 | +#include <ctype.h> | |
27 | +#include <assert.h> | |
28 | +#include <errno.h> | |
29 | +#include <time.h> | |
30 | +#include <sys/types.h> | |
31 | +#include <sys/socket.h> | |
32 | +#include <sys/utsname.h> | |
33 | +#include <netinet/in.h> | |
34 | +#include <arpa/inet.h> | |
35 | +#include <netdb.h> | |
36 | +#include <sys/ioctl.h> | |
37 | +#include <net/if.h> | |
38 | + | |
39 | +#include "smtpauth.h" | |
40 | +#include "pam_smtpauth.h" | |
41 | + | |
42 | +#ifdef USE_SSL | |
43 | +#include <openssl/err.h> | |
44 | +#include <openssl/md5.h> | |
45 | +#else | |
46 | +#include "global.h" | |
47 | +#include "md5.h" | |
48 | +#endif | |
49 | + | |
50 | +#define SMTP_EHLO_CMD "EHLO " /* ESMTP ehlo command */ | |
51 | +#define SMTP_AUTH_CMD "AUTH " /* ESMTP auth command */ | |
52 | +#define SMTP_QUIT_CMD "QUIT" /* ESMTP quit command */ | |
53 | +#define SMTP_NEWLINE "\r\n" /* ESMTP newline */ | |
54 | + | |
55 | +#define RESP_LEN 1000 | |
56 | +#define RESP_IERROR "internal error" | |
57 | +#define RESP_UNAVAILABLE "remote authentication server is currently unavailable" | |
58 | +#define RESP_UNEXPECTED "unexpected response from remote authentication server" | |
59 | +#define RESP_SYNCERROR "error synchronizing with remote authentication server" | |
60 | +#define RESP_CREDERROR "remote authentication server rejected your credentials" | |
61 | + | |
62 | +#define AUTH_NG 0 | |
63 | +#define AUTH_OK 1 | |
64 | + | |
65 | +#define AUTH_PLAIN 1 << 0 | |
66 | +#define AUTH_LOGIN 1 << 1 | |
67 | +#define AUTH_CRAM_MD5 1 << 2 | |
68 | +#define AUTH_DIGEST_MD5 1 << 3 | |
69 | + | |
70 | +#define DIGEST_MD5_REALM_LEN 256 | |
71 | +#define DIGEST_MD5_NONCE_LEN 64 | |
72 | +#define DIGEST_MD5_CNONCE_LEN 33 | |
73 | +#define DIGEST_MD5_QOP_LEN 64 | |
74 | +#define DIGEST_MD5_URI_LEN 261 | |
75 | + | |
76 | +extern void base64_encode(char *out, const char *in, int inlen); | |
77 | +extern int base64_decode(char *out, const char *in, int inlen); | |
78 | +extern int retry_writev(socket_t *sock, struct iovec *iov, int iovcnt); | |
79 | +extern int socket_read(socket_t *sock, char *buf, size_t len); | |
80 | +extern int socket_close(socket_t *sock); | |
81 | +extern void socket_perror(const char *func, socket_t *sock, int ret); | |
82 | +extern void set_timeout(int timeout); | |
83 | + | |
84 | +void md5_hex_hmac(char *hexdigest, unsigned char *text, unsigned int text_len, unsigned char *key, unsigned int key_len); | |
85 | +void hmac_md5(unsigned char *text, unsigned int text_len, unsigned char *key, unsigned int key_len, unsigned char *digest); | |
86 | +int start_tls(smtp_t *smtp, config_t *cfg); | |
87 | + | |
88 | +int smtp_quit(socket_t *sock, config_t *cfg); | |
89 | +int auth_plain(socket_t *sock, config_t *cfg); | |
90 | +int auth_login(socket_t *sock, config_t *cfg); | |
91 | +int auth_cram_md5(socket_t *sock, config_t *cfg); | |
92 | +int auth_digest_md5(socket_t *sock, config_t *cfg); | |
93 | + | |
94 | +config_t global; | |
95 | +param_t params; | |
96 | + | |
97 | +static void | |
98 | +bin2hex(char *out, const unsigned char *in, int in_len) { | |
99 | + static const char hex[17] = "0123456789abcdef"; | |
100 | + int cnt; | |
101 | + | |
102 | + for(cnt=0; cnt<in_len; cnt++) { | |
103 | + out[cnt * 2] = hex[in[cnt] >> 4]; | |
104 | + out[(cnt * 2) + 1] = hex[in[cnt]&0x0F]; | |
105 | + } | |
106 | +} | |
107 | + | |
108 | +void | |
109 | +make_digest(char *md5str, unsigned char *digest) { | |
110 | + bin2hex(md5str, digest, 16); | |
111 | + md5str[32] = '\0'; | |
112 | +} | |
113 | + | |
114 | +void | |
115 | +md5_hex_hmac(char *hexdigest, unsigned char *text, unsigned int text_len, unsigned char *key, unsigned int key_len) { | |
116 | + | |
117 | + unsigned char digest[16]; | |
118 | + int cnt; | |
119 | + | |
120 | + hmac_md5(text, text_len, key, key_len, digest); | |
121 | + for(cnt=0; cnt<16; cnt++) { | |
122 | + sprintf(hexdigest + 2 * cnt, "%02x", digest[cnt]); | |
123 | + } | |
124 | +} | |
125 | + | |
126 | + | |
127 | +void | |
128 | +hmac_md5(unsigned char *text, unsigned int text_len, unsigned char *key, unsigned int key_len, unsigned char *digest) { | |
129 | + | |
130 | + MD5_CTX context; | |
131 | + unsigned char k_ipad[64]; | |
132 | + unsigned char k_opad[64]; | |
133 | + int cnt; | |
134 | + | |
135 | + memset(k_ipad, 0, sizeof(k_ipad)); | |
136 | + memset(k_opad, 0, sizeof(k_opad)); | |
137 | + if(key_len > 64) { | |
138 | + MD5_CTX tctx; | |
139 | + | |
140 | +#ifdef USE_SSL | |
141 | + MD5_Init(&tctx); | |
142 | + MD5_Update(&tctx, key, key_len); | |
143 | + MD5_Final(k_ipad, &tctx); | |
144 | + MD5_Final(k_opad, &tctx); | |
145 | +#else | |
146 | + MD5Init(&tctx); | |
147 | + MD5Update(&tctx, key, key_len); | |
148 | + MD5Final(k_ipad, &tctx); | |
149 | + MD5Final(k_opad, &tctx); | |
150 | +#endif | |
151 | + } else { | |
152 | + memcpy(k_ipad, key, key_len); | |
153 | + memcpy(k_opad, key, key_len); | |
154 | + } | |
155 | + | |
156 | + for(cnt=0; cnt<64; cnt++) { | |
157 | + k_ipad[cnt] ^= 0x36; | |
158 | + k_opad[cnt] ^= 0x5c; | |
159 | + } | |
160 | + | |
161 | +#ifdef USE_SSL | |
162 | + MD5_Init(&context); | |
163 | + MD5_Update(&context, k_ipad, 64); | |
164 | + MD5_Update(&context, text, text_len); | |
165 | + MD5_Final(digest, &context); | |
166 | + | |
167 | + MD5_Init(&context); | |
168 | + MD5_Update(&context, k_opad, 64); | |
169 | + MD5_Update(&context, digest, 16); | |
170 | + MD5_Final(digest, &context); | |
171 | +#else | |
172 | + MD5Init(&context); | |
173 | + MD5Update(&context, k_ipad, 64); | |
174 | + MD5Update(&context, text, text_len); | |
175 | + MD5Final(digest, &context); | |
176 | + | |
177 | + MD5Init(&context); | |
178 | + MD5Update(&context, k_opad, 64); | |
179 | + MD5Update(&context, digest, 16); | |
180 | + MD5Final(digest, &context); | |
181 | +#endif | |
182 | +} | |
183 | + | |
184 | + | |
185 | +int | |
186 | +extract_token(const char *str, const char *token, char *value, int len) { | |
187 | + | |
188 | + char *p = NULL, *q = NULL; | |
189 | + | |
190 | + memset(value,0x00,sizeof(char)*len); | |
191 | + if((p = strstr(str, token)) != NULL) { | |
192 | + p += strlen(token); | |
193 | + if(*p == '\"') { | |
194 | + if((q = strchr(p + 1, '\"')) == NULL) | |
195 | + return -1; | |
196 | + strncpy(value, p + 1, q - p - 1 >= len ? len - 1 : q - p - 1); | |
197 | + | |
198 | + } else { | |
199 | + if((q = strchr(p, ',')) == NULL) | |
200 | + q += strlen(p); | |
201 | + strncpy(value, p, q - p >= len ? len - 1 : q - p); | |
202 | + } | |
203 | + } | |
204 | +#ifdef DEBUG | |
205 | + log_debug(DEBUG_9, "extract_token: str=%s", str); | |
206 | +#endif | |
207 | + | |
208 | + return 0; | |
209 | +} | |
210 | + | |
211 | +void | |
212 | +digest_md5(char *response, unsigned char *text, unsigned int text_len, const char *login, const char *passwd) { | |
213 | + | |
214 | + char realm[DIGEST_MD5_REALM_LEN]; | |
215 | + char nonce[DIGEST_MD5_NONCE_LEN]; | |
216 | + char qop[DIGEST_MD5_QOP_LEN]; | |
217 | + char uri[DIGEST_MD5_URI_LEN]; | |
218 | + char cnonce[DIGEST_MD5_CNONCE_LEN]; | |
219 | + | |
220 | + unsigned char random[16]; | |
221 | + | |
222 | + MD5_CTX ctx; | |
223 | + unsigned char digest[16]; | |
224 | + char hexA1[33], hexA2[33], resp[33]; | |
225 | + | |
226 | + | |
227 | +#ifdef DEBUG | |
228 | + log_debug(DEBUG_9, "digest_md5: text=%s", text); | |
229 | +#endif | |
230 | + | |
231 | + extract_token((const char *)text, "nonce=", nonce, DIGEST_MD5_NONCE_LEN); | |
232 | + extract_token((const char *)text, "realm=", realm, DIGEST_MD5_REALM_LEN); | |
233 | + extract_token((const char *)text, "qop=", qop, DIGEST_MD5_QOP_LEN); | |
234 | + | |
235 | + srand(time(NULL)); | |
236 | + snprintf((char *)random, sizeof(random), "%ld", (long int)rand()); | |
237 | + bin2hex(cnonce, random, 8); | |
238 | + cnonce[16] = '\0'; | |
239 | + | |
240 | + sprintf(uri, "smtp/%s", realm); | |
241 | +#ifdef DEBUG | |
242 | + log_debug(DEBUG_9, "digest_md5: realm=%s", realm); | |
243 | + log_debug(DEBUG_9, "digest_md5: nonce=%s", nonce); | |
244 | + log_debug(DEBUG_9, "digest_md5: qop=%s", qop); | |
245 | + log_debug(DEBUG_9, "digest_md5: cnonce=%s", cnonce); | |
246 | + log_debug(DEBUG_9, "digest_md5: uri=%s", uri); | |
247 | +#endif | |
248 | + | |
249 | + /* A1 */ | |
250 | +#ifdef USE_SSL | |
251 | + MD5_Init(&ctx); | |
252 | + MD5_Update(&ctx, login, strlen(login)); | |
253 | + MD5_Update(&ctx, ":", 1); | |
254 | + MD5_Update(&ctx, realm, strlen(realm)); | |
255 | + MD5_Update(&ctx, ":", 1); | |
256 | + MD5_Update(&ctx, passwd, strlen(passwd)); | |
257 | + MD5_Final(digest, &ctx); | |
258 | +#else | |
259 | + MD5Init(&ctx); | |
260 | + MD5Update(&ctx, login, strlen(login)); | |
261 | + MD5Update(&ctx, ":", 1); | |
262 | + MD5Update(&ctx, realm, strlen(realm)); | |
263 | + MD5Update(&ctx, ":", 1); | |
264 | + MD5Update(&ctx, passwd, strlen(passwd)); | |
265 | + MD5Final(digest, &ctx); | |
266 | +#endif | |
267 | + | |
268 | +#ifdef USE_SSL | |
269 | + MD5_Init(&ctx); | |
270 | + MD5_Update(&ctx, digest, 16); | |
271 | + MD5_Update(&ctx, ":", 1); | |
272 | + MD5_Update(&ctx, nonce, strlen(nonce)); | |
273 | + MD5_Update(&ctx, ":", 1); | |
274 | + MD5_Update(&ctx, cnonce, strlen(cnonce)); | |
275 | + MD5_Final(digest, &ctx); | |
276 | +#else | |
277 | + MD5Init(&ctx); | |
278 | + MD5Update(&ctx, digest, 16); | |
279 | + MD5Update(&ctx, ":", 1); | |
280 | + MD5Update(&ctx, nonce, strlen(nonce)); | |
281 | + MD5Update(&ctx, ":", 1); | |
282 | + MD5Update(&ctx, cnonce, strlen(cnonce)); | |
283 | + MD5Final(digest, &ctx); | |
284 | +#endif | |
285 | + make_digest(hexA1, digest); | |
286 | + | |
287 | +#ifdef DEBUG | |
288 | + log_debug(DEBUG_9, "digest_md5: A1=%s", hexA1); | |
289 | +#endif | |
290 | + | |
291 | + /* A2 */ | |
292 | +#ifdef USE_SSL | |
293 | + MD5_Init(&ctx); | |
294 | + MD5_Update(&ctx, "AUTHENTICATE:", sizeof("AUTHENTICATE:") - 1); | |
295 | + MD5_Update(&ctx, uri, strlen(uri)); | |
296 | + if(!strcmp(qop, "auth-int")) { | |
297 | + MD5_Update(&ctx, ":00000000000000000000000000000000", sizeof(":00000000000000000000000000000000") - 1); | |
298 | + } | |
299 | + MD5_Final(digest, &ctx); | |
300 | +#else | |
301 | + MD5Init(&ctx); | |
302 | + MD5Update(&ctx, "AUTHENTICATE:", sizeof("AUTHENTICATE:") - 1); | |
303 | + MD5Update(&ctx, uri, strlen(uri)); | |
304 | + if(!strcmp(qop, "auth-int")) { | |
305 | + MD5Update(&ctx, ":00000000000000000000000000000000", sizeof(":00000000000000000000000000000000") - 1); | |
306 | + } | |
307 | + MD5Final(digest, &ctx); | |
308 | +#endif | |
309 | + make_digest(hexA2, digest); | |
310 | + | |
311 | +#ifdef DEBUG | |
312 | + log_debug(DEBUG_9, "digest_md5: A2=%s", hexA2); | |
313 | +#endif | |
314 | + | |
315 | + /* response */ | |
316 | +#ifdef USE_SSL | |
317 | + MD5_Init(&ctx); | |
318 | + MD5_Update(&ctx, hexA1, 32); | |
319 | + MD5_Update(&ctx, ":", 1); | |
320 | + MD5_Update(&ctx, nonce, strlen(nonce)); | |
321 | + MD5_Update(&ctx, ":00000001:", sizeof(":00000001:") - 1); | |
322 | + MD5_Update(&ctx, cnonce, strlen(cnonce)); | |
323 | + MD5_Update(&ctx, ":", 1); | |
324 | + MD5_Update(&ctx, qop, strlen(qop)); | |
325 | + MD5_Update(&ctx, ":", 1); | |
326 | + MD5_Update(&ctx, hexA2, 32); | |
327 | + MD5_Final(digest, &ctx); | |
328 | +#else | |
329 | + MD5Init(&ctx); | |
330 | + MD5Update(&ctx, hexA1, 32); | |
331 | + MD5Update(&ctx, ":", 1); | |
332 | + MD5Update(&ctx, nonce, strlen(nonce)); | |
333 | + MD5Update(&ctx, ":00000001:", sizeof(":00000001:") - 1); | |
334 | + MD5Update(&ctx, cnonce, strlen(cnonce)); | |
335 | + MD5Update(&ctx, ":", 1); | |
336 | + MD5Update(&ctx, qop, strlen(qop)); | |
337 | + MD5Update(&ctx, ":", 1); | |
338 | + MD5Update(&ctx, hexA2, 32); | |
339 | + MD5Final(digest, &ctx); | |
340 | +#endif | |
341 | + | |
342 | + make_digest(resp, digest); | |
343 | + | |
344 | +#ifdef DEBUG | |
345 | + log_debug(DEBUG_9, "digest_md5: resp=%s", resp); | |
346 | +#endif | |
347 | + | |
348 | + sprintf(response, "charset=utf-8,username=\"%s\",realm=\"%s\",nonce=\"%s\"," | |
349 | + "nc=00000001,cnonce=\"%s\",digest-uri=\"%s\",qop=%s," | |
350 | + "response=%s", | |
351 | + login, realm, nonce, cnonce, uri, qop, resp); | |
352 | + | |
353 | +#ifdef DEBUG | |
354 | + log_debug(DEBUG_9, "digest_md5: response:%s", response); | |
355 | + log_debug(DEBUG_9, "digest_md5: text:%s", text); | |
356 | +#endif | |
357 | +} | |
358 | + | |
359 | + | |
360 | +smtp_t * | |
361 | +smtp_auth(config_t *cfg) { | |
362 | + | |
363 | + int s; | |
364 | + struct sockaddr_in addr; | |
365 | + struct hostent *he; | |
366 | + smtp_t *smtp = NULL; | |
367 | + char msgbuf[256]; | |
368 | + | |
369 | + struct iovec iov[5]; | |
370 | + char *c; | |
371 | + int rc; | |
372 | + char rbuf[RESP_LEN]; | |
373 | + int auth = 0; | |
374 | + int avail_auth_type = 0; | |
375 | + char *tbuf; | |
376 | + struct utsname h_name[1]; | |
377 | + char *myhostname; | |
378 | + | |
379 | + int n; | |
380 | + struct sockaddr_in taddr; | |
381 | + int sd; | |
382 | + struct ifconf ifconf; | |
383 | + struct ifreq *ifr, ifreq; | |
384 | + unsigned char *ifptr; | |
385 | + int iflen; | |
386 | +#ifdef USE_SSL | |
387 | + int use_ssl; | |
388 | +#endif | |
389 | + | |
390 | + if(!cfg->password) { | |
391 | + if(!global.password) { | |
392 | + global.password = getpass("Password:"); | |
393 | + if(!global.password) { | |
394 | + return 0; | |
395 | + } | |
396 | + if(!*global.password) { | |
397 | + global.password = NULL; | |
398 | + goto bail; | |
399 | + } | |
400 | + global.password = strdup(global.password); | |
401 | + } | |
402 | + cfg->password = strdup(global.password); | |
403 | + } | |
404 | + | |
405 | + assert(cfg->username != NULL); | |
406 | + assert(cfg->password != NULL); | |
407 | + | |
408 | + smtp = calloc(1, sizeof(smtp_t)); | |
409 | + smtp->sock = calloc(1, sizeof(socket_t)); | |
410 | + smtp->buf = calloc(1, sizeof(buffer_t)); | |
411 | + smtp->buf->sock = smtp->sock; | |
412 | + smtp->sock->fd = -1; | |
413 | + smtp->error = 0; | |
414 | + | |
415 | + /* open connection to SMTP server */ | |
416 | + memset(&addr, 0, sizeof(addr)); | |
417 | + addr.sin_port = htons(cfg->port); | |
418 | + addr.sin_family = AF_INET; | |
419 | + he = gethostbyname(cfg->host); | |
420 | + if(!he) { | |
421 | + smtp->error = 1; | |
422 | + strcpy(msgbuf, "Error: resolving hostname "); | |
423 | + strcat(msgbuf, cfg->host); | |
424 | + smtp->error_message = malloc(strlen(msgbuf) + 1); | |
425 | + strcpy(smtp->error_message, msgbuf); | |
426 | + goto bail; | |
427 | + } | |
428 | + | |
429 | + if((sd = socket(PF_INET, SOCK_DGRAM, 0)) != -1) { | |
430 | + bzero(&ifconf, sizeof(struct ifconf)); | |
431 | + bzero(&ifreq, sizeof(struct ifreq)); | |
432 | + iflen = 10 * sizeof(struct ifreq); | |
433 | + ifptr = malloc(iflen); | |
434 | + ifconf.ifc_len = iflen; | |
435 | + ifconf.ifc_ifcu.ifcu_req = (struct ifreq *)ifptr; | |
436 | + if(ioctl(sd, SIOCGIFCONF, &ifconf) != -1) { | |
437 | + for(iflen=sizeof(struct ifreq); iflen<=ifconf.ifc_len; iflen+=sizeof(struct ifreq)) { | |
438 | + ifr = (struct ifreq *)ifptr; | |
439 | + strcpy(ifreq.ifr_ifrn.ifrn_name, ifr->ifr_name); | |
440 | + if(ioctl(sd, SIOCGIFADDR, &ifreq) != -1) { | |
441 | + n = 0; | |
442 | + while(he->h_addr_list[n]) { | |
443 | + if(he->h_addrtype == AF_INET) { | |
444 | + memset((char*)&taddr, 0, sizeof(taddr)); | |
445 | + memcpy((char*)&taddr.sin_addr, he->h_addr_list[n], he->h_length); | |
446 | +#ifdef DEBUG | |
447 | + log_debug(DEBUG_5, "smtp_auth: my ip: %s", | |
448 | + inet_ntoa(((struct sockaddr_in *)&ifreq.ifr_addr)->sin_addr)); | |
449 | + log_debug(DEBUG_5, "smtp_auth: smtp ip: %s", | |
450 | + inet_ntoa(taddr.sin_addr)); | |
451 | +#endif | |
452 | + if(((struct sockaddr_in *)&ifreq.ifr_addr)->sin_addr.s_addr == taddr.sin_addr.s_addr) { | |
453 | + smtp->error = 1; | |
454 | + strcpy(msgbuf, "Error: this host is specified. "); | |
455 | + strcat(msgbuf, inet_ntoa(taddr.sin_addr)); | |
456 | + smtp->error_message = malloc(strlen(msgbuf) + 1); | |
457 | + strcpy(smtp->error_message, msgbuf); | |
458 | + goto bail; | |
459 | + } | |
460 | + } | |
461 | + n++; | |
462 | + } | |
463 | + } | |
464 | + ifptr += sizeof(struct ifreq); | |
465 | + } | |
466 | + } | |
467 | + } | |
468 | + addr.sin_addr.s_addr = *((int *)he->h_addr_list[0]); | |
469 | + s = socket(PF_INET, SOCK_STREAM, 0); | |
470 | + | |
471 | + if(cfg->conn_timeout > 0) { | |
472 | + set_timeout(cfg->conn_timeout); | |
473 | + } | |
474 | + if(connect(s, (struct sockaddr *) &addr, sizeof(addr))) { | |
475 | +#ifdef DEBUG | |
476 | + log_debug(DEBUG_1, "smtp_auth: connection error = %s",strerror(errno)); | |
477 | +#endif | |
478 | + smtp->error = 1; | |
479 | + strcpy(msgbuf, "Error: connecting to "); | |
480 | + strcat(msgbuf, inet_ntoa(addr.sin_addr)); | |
481 | + smtp->error_message = malloc(strlen(msgbuf) + 1); | |
482 | + strcpy(smtp->error_message, msgbuf); | |
483 | + goto bail; | |
484 | + } | |
485 | + smtp->sock->fd = s; | |
486 | + if(cfg->conn_timeout > 0) { | |
487 | + set_timeout(0); | |
488 | + } | |
489 | + | |
490 | +#ifdef USE_SSL | |
491 | + use_ssl = 0; | |
492 | + if(cfg->use_smtps) { | |
493 | + if(start_tls(smtp, cfg)) { | |
494 | + smtp->error = 1; | |
495 | + strcpy(msgbuf, "Error: start_tls"); | |
496 | + smtp->error_message = malloc(strlen(msgbuf) + 1); | |
497 | + strcpy(smtp->error_message, msgbuf); | |
498 | + goto bail; | |
499 | + } | |
500 | + use_ssl = 1; | |
501 | + } | |
502 | +#endif | |
503 | + | |
504 | + /* TCP connection to the remote SMTP server */ | |
505 | + if(cfg->timeout > 0) { | |
506 | + set_timeout(cfg->timeout); | |
507 | + } | |
508 | + usleep(2000000); | |
509 | + rc = socket_read(smtp->sock, rbuf, sizeof(rbuf)); | |
510 | + if(cfg->timeout > 0) { | |
511 | + set_timeout(0); | |
512 | + } | |
513 | + if(rc == -1) { | |
514 | +#ifdef DEBUG | |
515 | + log_debug(DEBUG_1, "smtp_auth: read (banner): %m"); | |
516 | +#endif | |
517 | + smtp->error = 1; | |
518 | + strcpy(msgbuf, RESP_SYNCERROR); | |
519 | + smtp->error_message = malloc(strlen(msgbuf) + 1); | |
520 | + strcpy(smtp->error_message, msgbuf); | |
521 | + goto bail; | |
522 | + } | |
523 | + rbuf[rc] = '\0'; | |
524 | + c = strpbrk(rbuf, SMTP_NEWLINE); | |
525 | + if(c != NULL) { | |
526 | + *c = '\0'; | |
527 | + } | |
528 | + | |
529 | + if(strncmp(rbuf, "220 ", sizeof("220 ")-1)) { | |
530 | +#ifdef DEBUG | |
531 | + log_debug(DEBUG_1, "smtp_auth: unexpected response during initial handshake: %s", rbuf); | |
532 | +#endif | |
533 | + smtp->error = 1; | |
534 | + strcpy(msgbuf, RESP_UNEXPECTED); | |
535 | + smtp->error_message = malloc(strlen(msgbuf) + 1); | |
536 | + strcpy(smtp->error_message, msgbuf); | |
537 | + goto bail; | |
538 | + } | |
539 | + | |
540 | + if((uname(h_name)) < 0){ | |
541 | + myhostname = "localhost.localdomain"; | |
542 | + } else { | |
543 | + myhostname = h_name->nodename; | |
544 | + } | |
545 | + | |
546 | + iov[0].iov_base = SMTP_EHLO_CMD; | |
547 | + iov[0].iov_len = sizeof(SMTP_EHLO_CMD) - 1; | |
548 | + iov[1].iov_base = myhostname; | |
549 | + iov[1].iov_len = strlen(myhostname); | |
550 | + iov[2].iov_base = SMTP_NEWLINE; | |
551 | + iov[2].iov_len = sizeof(SMTP_NEWLINE) - 1; | |
552 | + | |
553 | +#ifdef DEBUG | |
554 | + log_debug(DEBUG_9, "smtp_auth: sending %s%s", SMTP_EHLO_CMD, myhostname); | |
555 | +#endif | |
556 | + if(cfg->timeout > 0) { | |
557 | + set_timeout(cfg->timeout); | |
558 | + } | |
559 | + rc = retry_writev(smtp->sock, iov, 3); | |
560 | + memset(iov, 0, sizeof(iov)); | |
561 | + if(cfg->timeout > 0) { | |
562 | + set_timeout(0); | |
563 | + } | |
564 | + if(rc == -1) { | |
565 | +#ifdef DEBUG | |
566 | + log_debug(DEBUG_1, "smtp_auth: writev: %m"); | |
567 | +#endif | |
568 | + smtp->error = 1; | |
569 | + strcpy(msgbuf, RESP_IERROR); | |
570 | + smtp->error_message = malloc(strlen(msgbuf) + 1); | |
571 | + strcpy(smtp->error_message, msgbuf); | |
572 | + goto bail; | |
573 | + } | |
574 | + | |
575 | + /* read and parse the EHLO response */ | |
576 | + if(cfg->timeout > 0) { | |
577 | + set_timeout(cfg->timeout); | |
578 | + } | |
579 | + rc = socket_read(smtp->sock, rbuf, sizeof(rbuf)); | |
580 | + if(cfg->timeout > 0) { | |
581 | + set_timeout(0); | |
582 | + } | |
583 | + if(rc == -1) { | |
584 | +#ifdef DEBUG | |
585 | + log_debug(DEBUG_1, "smtp_auth: read (response): %m"); | |
586 | +#endif | |
587 | + smtp->error = 1; | |
588 | + strcpy(msgbuf, RESP_IERROR); | |
589 | + smtp->error_message = malloc(strlen(msgbuf) + 1); | |
590 | + strcpy(smtp->error_message, msgbuf); | |
591 | + goto bail; | |
592 | + } | |
593 | + | |
594 | + if((tbuf = strstr(rbuf, "250-STARTTLS"))) { | |
595 | +#ifdef DEBUG | |
596 | + log_debug(DEBUG_1, "smtp_auth: STARTTLS not supported."); | |
597 | +#endif | |
598 | + } | |
599 | + | |
600 | + if((tbuf = strstr(rbuf, "250-AUTH"))) { | |
601 | + if(strncmp(tbuf, "250", sizeof("250")-1) == 0) { | |
602 | + char *p = tbuf; | |
603 | + p += 3; | |
604 | + if(*p == '-' || *p == ' ') p++; | |
605 | + if(strncasecmp(p, "AUTH", sizeof("AUTH")-1) == 0) { | |
606 | + p += 5; | |
607 | + if(strcasestr(p, "PLAIN")) | |
608 | + avail_auth_type |= AUTH_PLAIN; | |
609 | + if(strcasestr(p, "LOGIN")) | |
610 | + avail_auth_type |= AUTH_LOGIN; | |
611 | + if(strcasestr(p, "CRAM-MD5")) | |
612 | + avail_auth_type |= AUTH_CRAM_MD5; | |
613 | + if(strcasestr(p, "DIGEST-MD5")) | |
614 | + avail_auth_type |= AUTH_DIGEST_MD5; | |
615 | + } | |
616 | + } | |
617 | + } | |
618 | + | |
619 | + if(avail_auth_type == 0) { | |
620 | +#ifdef DEBUG | |
621 | + log_debug(DEBUG_1, "smtp_auth: smtp authentication is not implemented: %s", rbuf); | |
622 | +#endif | |
623 | + smtp->error = 1; | |
624 | + strcpy(msgbuf, RESP_UNEXPECTED); | |
625 | + smtp->error_message = malloc(strlen(msgbuf) + 1); | |
626 | + strcpy(smtp->error_message, msgbuf); | |
627 | + goto bail; | |
628 | + } | |
629 | +#ifdef DEBUG | |
630 | + log_debug(DEBUG_1, "smtp_auth: auth_type=%d", avail_auth_type); | |
631 | +#endif | |
632 | + | |
633 | + /* build the AUTH command */ | |
634 | + if(avail_auth_type & AUTH_CRAM_MD5) { | |
635 | + auth = auth_cram_md5(smtp->sock,&global); | |
636 | + } | |
637 | + else if((avail_auth_type & AUTH_LOGIN) != 0) { | |
638 | + auth = auth_login(smtp->sock,&global); | |
639 | + } | |
640 | + else if((avail_auth_type & AUTH_PLAIN) != 0) { | |
641 | + auth = auth_plain(smtp->sock,&global); | |
642 | + } | |
643 | + else if((avail_auth_type & AUTH_DIGEST_MD5) != 0) { | |
644 | + auth = auth_digest_md5(smtp->sock,&global); | |
645 | + } | |
646 | + else { | |
647 | +#ifdef DEBUG | |
648 | + log_debug(DEBUG_1, "smtp_auth: smtp authentication is not implemented: %s", rbuf); | |
649 | +#endif | |
650 | + smtp->error = 1; | |
651 | + strcpy(msgbuf, RESP_UNEXPECTED); | |
652 | + smtp->error_message = malloc(strlen(msgbuf) + 1); | |
653 | + strcpy(smtp->error_message, msgbuf); | |
654 | + goto bail; | |
655 | + } | |
656 | + | |
657 | +#ifdef DEBUG | |
658 | + log_debug(DEBUG_5, "smtp_auth: auth=%d", auth); | |
659 | +#endif | |
660 | + if(auth == 0) { | |
661 | +#ifdef DEBUG | |
662 | + log_debug(DEBUG_1, "smtp_auth: rejected=%s", global.username); | |
663 | +#endif | |
664 | + smtp->error = 2; | |
665 | + strcpy(msgbuf, RESP_CREDERROR); | |
666 | + smtp->error_message = malloc(strlen(msgbuf) + 1); | |
667 | + strcpy(smtp->error_message, msgbuf); | |
668 | + goto bail; | |
669 | + } | |
670 | + | |
671 | + smtp_quit(smtp->sock,&global); | |
672 | + return smtp; | |
673 | + | |
674 | + bail: | |
675 | + smtp_quit(smtp->sock,&global); | |
676 | + if(smtp->error == 1) | |
677 | + return smtp; | |
678 | + else if(smtp->error == 2) | |
679 | + return smtp; | |
680 | + return smtp; | |
681 | +} | |
682 | + | |
683 | + | |
684 | +int | |
685 | +smtp_quit(socket_t *sock, config_t *cfg) { | |
686 | + | |
687 | + struct iovec iov[3]; | |
688 | + int rc; | |
689 | + | |
690 | + iov[0].iov_base = SMTP_QUIT_CMD; | |
691 | + iov[0].iov_len = sizeof(SMTP_QUIT_CMD) - 1; | |
692 | + iov[1].iov_base = SMTP_NEWLINE; | |
693 | + iov[1].iov_len = sizeof(SMTP_NEWLINE) - 1; | |
694 | + | |
695 | +#ifdef DEBUG | |
696 | + log_debug(DEBUG_9, "smtp_quit: sending %s", SMTP_QUIT_CMD); | |
697 | +#endif | |
698 | + if(cfg->timeout > 0) { | |
699 | + set_timeout(cfg->timeout); | |
700 | + } | |
701 | + rc = retry_writev(sock, iov, 2); | |
702 | + memset(iov, 0, sizeof(iov)); | |
703 | + if(cfg->timeout > 0) { | |
704 | + set_timeout(0); | |
705 | + } | |
706 | + if(rc == -1) { | |
707 | +#ifdef DEBUG | |
708 | + log_debug(DEBUG_1, "smtp_quit: quit writev: %m"); | |
709 | +#endif | |
710 | + } | |
711 | + (void)socket_close(sock); | |
712 | + return 1; | |
713 | +} | |
714 | + | |
715 | + | |
716 | +int | |
717 | +auth_cram_md5(socket_t *sock, config_t *cfg) { | |
718 | + | |
719 | + struct iovec iov[3]; | |
720 | + int rc; | |
721 | + char rbuf[RESP_LEN]; | |
722 | + char buf[RESP_LEN]; | |
723 | + | |
724 | +#ifdef DEBUG | |
725 | + log_debug(DEBUG_1, "auth_cram_md5: AUTH CRAM-MD5"); | |
726 | +#endif | |
727 | + iov[0].iov_base = SMTP_AUTH_CMD; | |
728 | + iov[0].iov_len = sizeof(SMTP_AUTH_CMD) - 1; | |
729 | + iov[1].iov_base = "CRAM-MD5"; | |
730 | + iov[1].iov_len = strlen("CRAM-MD5"); | |
731 | + iov[2].iov_base = SMTP_NEWLINE; | |
732 | + iov[2].iov_len = sizeof(SMTP_NEWLINE) - 1; | |
733 | + | |
734 | +#ifdef DEBUG | |
735 | + log_debug(DEBUG_9, "auth_cram_md5: sending %s%s", SMTP_AUTH_CMD,"CRAM-MD5"); | |
736 | +#endif | |
737 | + if(cfg->timeout > 0) { | |
738 | + set_timeout(cfg->timeout); | |
739 | + } | |
740 | + rc = retry_writev(sock, iov, 3); | |
741 | + memset(iov, 0, sizeof(iov)); | |
742 | + if(cfg->timeout > 0) { | |
743 | + set_timeout(0); | |
744 | + } | |
745 | + if(rc == -1) { | |
746 | +#ifdef DEBUG | |
747 | + log_debug(DEBUG_1, "auth_cram_md5: cram-md5 writev: %m"); | |
748 | +#endif | |
749 | + return AUTH_NG; | |
750 | + } | |
751 | + | |
752 | + if(cfg->timeout > 0) { | |
753 | + set_timeout(cfg->timeout); | |
754 | + } | |
755 | + rc = socket_read(sock, rbuf, sizeof(rbuf)); | |
756 | + if(cfg->timeout > 0) { | |
757 | + set_timeout(0); | |
758 | + } | |
759 | + if(rc == -1) { | |
760 | +#ifdef DEBUG | |
761 | + log_debug(DEBUG_1, "auth_cram_md5: read (response): %m"); | |
762 | +#endif | |
763 | + return AUTH_NG; | |
764 | + } | |
765 | + | |
766 | +#ifdef DEBUG | |
767 | + log_debug(DEBUG_5, "auth_cram_md5: read (response): %s",rbuf); | |
768 | +#endif | |
769 | + if(strncmp(rbuf, "334 ", sizeof("334 ")-1) == 0) { | |
770 | + char *response; | |
771 | + char *response64; | |
772 | + unsigned char *challenge; | |
773 | + int challengelen; | |
774 | + unsigned char hexdigest[33]; | |
775 | + | |
776 | + challenge = malloc(strlen(rbuf + 4) + 1); | |
777 | + challengelen = base64_decode((char *)challenge, rbuf + 4, -1); | |
778 | + challenge[challengelen] = '\0'; | |
779 | +#ifdef DEBUG | |
780 | + log_debug(DEBUG_9, "auth_cram_md5: challenge=%s", challenge); | |
781 | +#endif | |
782 | + | |
783 | + snprintf(buf, sizeof(buf), "%s", cfg->password); | |
784 | + md5_hex_hmac((char *)hexdigest, challenge, challengelen, (unsigned char*)buf, strlen(cfg->password)); | |
785 | + free(challenge); | |
786 | + | |
787 | + response = malloc(sizeof(char)*128); | |
788 | + sprintf(response, "%s %s", cfg->username, hexdigest); | |
789 | + response64 = malloc((strlen(response) + 3) * 2 + 1); | |
790 | + base64_encode(response64, response, strlen(response)); | |
791 | + free(response); | |
792 | + | |
793 | + iov[0].iov_base = response64; | |
794 | + iov[0].iov_len = strlen(response64); | |
795 | + iov[1].iov_base = SMTP_NEWLINE; | |
796 | + iov[1].iov_len = sizeof(SMTP_NEWLINE) - 1; | |
797 | + | |
798 | +#ifdef DEBUG | |
799 | + log_debug(DEBUG_9, "auth_cram_md5: sending %s", response64); | |
800 | +#endif | |
801 | + if(cfg->timeout > 0) { | |
802 | + set_timeout(cfg->timeout); | |
803 | + } | |
804 | + rc = retry_writev(sock, iov, 2); | |
805 | + memset(iov, 0, sizeof(iov)); | |
806 | + if(cfg->timeout > 0) { | |
807 | + set_timeout(0); | |
808 | + } | |
809 | + if(rc == -1) { | |
810 | +#ifdef DEBUG | |
811 | + log_debug(DEBUG_1, "auth_cram_md5: cram-md5 writev: %m"); | |
812 | +#endif | |
813 | + return AUTH_NG; | |
814 | + } | |
815 | + | |
816 | + if(cfg->timeout > 0) { | |
817 | + set_timeout(cfg->timeout); | |
818 | + } | |
819 | + rc = socket_read(sock, rbuf, sizeof(rbuf)); | |
820 | + if(cfg->timeout > 0) { | |
821 | + set_timeout(0); | |
822 | + } | |
823 | + if(rc == -1) { | |
824 | +#ifdef DEBUG | |
825 | + log_debug(DEBUG_1, "auth_cram_md5: read (response): %m"); | |
826 | +#endif | |
827 | + return AUTH_NG; | |
828 | + } | |
829 | + | |
830 | +#ifdef DEBUG | |
831 | + log_debug(DEBUG_5, "auth_cram_md5: read (response): %s",rbuf); | |
832 | +#endif | |
833 | + if(strncmp(rbuf, "235 ", sizeof("235 ")-1) != 0) { | |
834 | +#ifdef DEBUG | |
835 | + log_debug(DEBUG_1, "auth_cram_md5: auth failure."); | |
836 | +#endif | |
837 | + return AUTH_NG; | |
838 | + } | |
839 | + free(response64); | |
840 | + } else { | |
841 | +#ifdef DEBUG | |
842 | + log_debug(DEBUG_1, "auth_cram_md5: it seems cram-md5 mech is not implemented."); | |
843 | +#endif | |
844 | + return AUTH_NG; | |
845 | + } | |
846 | + return AUTH_OK; | |
847 | +} | |
848 | + | |
849 | + | |
850 | +int | |
851 | +auth_login(socket_t *sock, config_t *cfg) { | |
852 | + | |
853 | + struct iovec iov[3]; | |
854 | + int rc; | |
855 | + char rbuf[RESP_LEN]; | |
856 | + //char buf[RESP_LEN]; | |
857 | + char *buf; | |
858 | + | |
859 | +#ifdef DEBUG | |
860 | + log_debug(DEBUG_1, "auth_login: AUTH LOGIN"); | |
861 | +#endif | |
862 | + iov[0].iov_base = SMTP_AUTH_CMD; | |
863 | + iov[0].iov_len = sizeof(SMTP_AUTH_CMD) - 1; | |
864 | + iov[1].iov_base = "LOGIN"; | |
865 | + iov[1].iov_len = strlen("LOGIN"); | |
866 | + iov[2].iov_base = SMTP_NEWLINE; | |
867 | + iov[2].iov_len = sizeof(SMTP_NEWLINE) - 1; | |
868 | + | |
869 | +#ifdef DEBUG | |
870 | + log_debug(DEBUG_9, "auth_login: sending %s%s", SMTP_AUTH_CMD,"LOGIN"); | |
871 | +#endif | |
872 | + if(cfg->timeout > 0) { | |
873 | + set_timeout(cfg->timeout); | |
874 | + } | |
875 | + rc = retry_writev(sock, iov, 3); | |
876 | + memset(iov, 0, sizeof(iov)); | |
877 | + if(cfg->timeout > 0) { | |
878 | + set_timeout(0); | |
879 | + } | |
880 | + if(rc == -1) { | |
881 | +#ifdef DEBUG | |
882 | + log_debug(DEBUG_1, "auth_login: login writev: %m"); | |
883 | +#endif | |
884 | + return AUTH_NG; | |
885 | + } | |
886 | + | |
887 | + if(cfg->timeout > 0) { | |
888 | + set_timeout(cfg->timeout); | |
889 | + } | |
890 | + rc = socket_read(sock, rbuf, sizeof(rbuf)); | |
891 | + if(cfg->timeout > 0) { | |
892 | + set_timeout(0); | |
893 | + } | |
894 | + if(rc == -1) { | |
895 | +#ifdef DEBUG | |
896 | + log_debug(DEBUG_1, "auth_login: read (response): %m"); | |
897 | +#endif | |
898 | + return AUTH_NG; | |
899 | + } | |
900 | + | |
901 | +#ifdef DEBUG | |
902 | + log_debug(DEBUG_5, "auth_login: read (response): %s",rbuf); | |
903 | +#endif | |
904 | + if(strncmp(rbuf, "334 ", sizeof("334 ")-1) == 0) { | |
905 | + buf = malloc(sizeof(char)*128); | |
906 | + base64_encode(buf, cfg->username, strlen(cfg->username)); | |
907 | + | |
908 | + iov[0].iov_base = buf; | |
909 | + iov[0].iov_len = strlen(buf); | |
910 | + iov[1].iov_base = SMTP_NEWLINE; | |
911 | + iov[1].iov_len = sizeof(SMTP_NEWLINE) - 1; | |
912 | + | |
913 | +#ifdef DEBUG | |
914 | + log_debug(DEBUG_9, "auth_login: sending %s", buf); | |
915 | +#endif | |
916 | + if(cfg->timeout > 0) { | |
917 | + set_timeout(cfg->timeout); | |
918 | + } | |
919 | + rc = retry_writev(sock, iov, 2); | |
920 | + memset(iov, 0, sizeof(iov)); | |
921 | + if(cfg->timeout > 0) { | |
922 | + set_timeout(0); | |
923 | + } | |
924 | + if(rc == -1) { | |
925 | +#ifdef DEBUG | |
926 | + log_debug(DEBUG_1, "auth_login: login writev: %m"); | |
927 | +#endif | |
928 | + return AUTH_NG; | |
929 | + } | |
930 | + | |
931 | + if(cfg->timeout > 0) { | |
932 | + set_timeout(cfg->timeout); | |
933 | + } | |
934 | + rc = socket_read(sock, rbuf, sizeof(rbuf)); | |
935 | + if(cfg->timeout > 0) { | |
936 | + set_timeout(0); | |
937 | + } | |
938 | + if(rc == -1) { | |
939 | +#ifdef DEBUG | |
940 | + log_debug(DEBUG_1, "auth_login: read (response): %m"); | |
941 | +#endif | |
942 | + return AUTH_NG; | |
943 | + } | |
944 | + | |
945 | +#ifdef DEBUG | |
946 | + log_debug(DEBUG_5, "auth_login: read (response): %s",rbuf); | |
947 | +#endif | |
948 | + if(strncmp(rbuf, "334 ", sizeof("334 ")-1) == 0) { | |
949 | + buf = malloc(sizeof(char)*128); | |
950 | + base64_encode(buf, cfg->password, strlen(cfg->password)); | |
951 | + | |
952 | + iov[0].iov_base = buf; | |
953 | + iov[0].iov_len = strlen(buf); | |
954 | + iov[1].iov_base = SMTP_NEWLINE; | |
955 | + iov[1].iov_len = sizeof(SMTP_NEWLINE) - 1; | |
956 | + | |
957 | +#ifdef DEBUG | |
958 | + log_debug(DEBUG_9, "auth_login: sending %s", buf); | |
959 | +#endif | |
960 | + if(cfg->timeout > 0) { | |
961 | + set_timeout(cfg->timeout); | |
962 | + } | |
963 | + rc = retry_writev(sock, iov, 2); | |
964 | + memset(iov, 0, sizeof(iov)); | |
965 | + if(cfg->timeout > 0) { | |
966 | + set_timeout(0); | |
967 | + } | |
968 | + if(rc == -1) { | |
969 | +#ifdef DEBUG | |
970 | + log_debug(DEBUG_1, "auth_login: login writev: %m"); | |
971 | +#endif | |
972 | + return AUTH_NG; | |
973 | + } | |
974 | + | |
975 | + if(cfg->timeout > 0) { | |
976 | + set_timeout(cfg->timeout); | |
977 | + } | |
978 | + rc = socket_read(sock, rbuf, sizeof(rbuf)); | |
979 | + if(cfg->timeout > 0) { | |
980 | + set_timeout(0); | |
981 | + } | |
982 | + if(rc == -1) { | |
983 | +#ifdef DEBUG | |
984 | + log_debug(DEBUG_1, "auth_login: read (response): %m"); | |
985 | +#endif | |
986 | + return AUTH_NG; | |
987 | + } | |
988 | + | |
989 | +#ifdef DEBUG | |
990 | + log_debug(DEBUG_5, "auth_login: read (response): %s",rbuf); | |
991 | +#endif | |
992 | + if(strncmp(rbuf, "235 ", sizeof("235 ")-1) != 0) { | |
993 | +#ifdef DEBUG | |
994 | + log_debug(DEBUG_1, "auth_login: auth failure."); | |
995 | +#endif | |
996 | + return AUTH_NG; | |
997 | + } | |
998 | + } else { | |
999 | +#ifdef DEBUG | |
1000 | + log_debug(DEBUG_1, "auth_login: it seems login mech is not implemented."); | |
1001 | +#endif | |
1002 | + return AUTH_NG; | |
1003 | + } | |
1004 | + } else { | |
1005 | +#ifdef DEBUG | |
1006 | + log_debug(DEBUG_1, "auth_login: it seems login mech is not implemented."); | |
1007 | +#endif | |
1008 | + return AUTH_NG; | |
1009 | + } | |
1010 | + return AUTH_OK; | |
1011 | +} | |
1012 | + | |
1013 | + | |
1014 | +int | |
1015 | +auth_plain(socket_t *sock, config_t *cfg) { | |
1016 | + | |
1017 | + struct iovec iov[3]; | |
1018 | + int rc; | |
1019 | + char rbuf[RESP_LEN]; | |
1020 | + //char buf[RESP_LEN]; | |
1021 | + char *buf; | |
1022 | + int cnt, len; | |
1023 | + char phrase[512]; | |
1024 | + | |
1025 | +#ifdef DEBUG | |
1026 | + log_debug(DEBUG_1, "auth_plain: AUTH PLAIN"); | |
1027 | +#endif | |
1028 | + sprintf(phrase,"%s^%s^%s", cfg->username, cfg->username, cfg->password); | |
1029 | + len = strlen(phrase); | |
1030 | + for(cnt=len-1; cnt>=0; cnt--) { | |
1031 | + if(phrase[cnt] == '^') { | |
1032 | + phrase[cnt] = '\0'; | |
1033 | + } | |
1034 | + } | |
1035 | + buf = malloc(sizeof(char)*128); | |
1036 | + base64_encode(buf, phrase, len); | |
1037 | + | |
1038 | + iov[0].iov_base = SMTP_AUTH_CMD; | |
1039 | + iov[0].iov_len = sizeof(SMTP_AUTH_CMD) - 1; | |
1040 | + iov[1].iov_base = "PLAIN "; | |
1041 | + iov[1].iov_len = strlen("PLAIN "); | |
1042 | + iov[2].iov_base = buf; | |
1043 | + iov[2].iov_len = strlen(buf); | |
1044 | + iov[3].iov_base = SMTP_NEWLINE; | |
1045 | + iov[3].iov_len = sizeof(SMTP_NEWLINE) - 1; | |
1046 | + | |
1047 | +#ifdef DEBUG | |
1048 | + log_debug(DEBUG_9, "auth_plain: sending %s%s %s", SMTP_AUTH_CMD,"PLAIN",buf); | |
1049 | +#endif | |
1050 | + if(cfg->timeout > 0) { | |
1051 | + set_timeout(cfg->timeout); | |
1052 | + } | |
1053 | + rc = retry_writev(sock, iov, 4); | |
1054 | + memset(iov, 0, sizeof(iov)); | |
1055 | + free(buf); | |
1056 | + if(cfg->timeout > 0) { | |
1057 | + set_timeout(0); | |
1058 | + } | |
1059 | + if(rc == -1) { | |
1060 | +#ifdef DEBUG | |
1061 | + log_debug(DEBUG_1, "auth_plain: plain writev: %m"); | |
1062 | +#endif | |
1063 | + return AUTH_NG; | |
1064 | + } | |
1065 | + | |
1066 | + if(cfg->timeout > 0) { | |
1067 | + set_timeout(cfg->timeout); | |
1068 | + } | |
1069 | + rc = socket_read(sock, rbuf, sizeof(rbuf)); | |
1070 | + if(cfg->timeout > 0) { | |
1071 | + set_timeout(0); | |
1072 | + } | |
1073 | + if(rc == -1) { | |
1074 | +#ifdef DEBUG | |
1075 | + log_debug(DEBUG_1, "auth_plain: read (response): %m"); | |
1076 | +#endif | |
1077 | + return AUTH_NG; | |
1078 | + } | |
1079 | + | |
1080 | +#ifdef DEBUG | |
1081 | + log_debug(DEBUG_5, "auth_plain: read (response): %s",rbuf); | |
1082 | +#endif | |
1083 | + | |
1084 | + if(strncmp(rbuf, "235 ", sizeof("235 ")-1) != 0) { | |
1085 | +#ifdef DEBUG | |
1086 | + log_debug(DEBUG_1, "auth_plain: auth failure."); | |
1087 | +#endif | |
1088 | + return AUTH_NG; | |
1089 | + } | |
1090 | + return AUTH_OK; | |
1091 | +} | |
1092 | + | |
1093 | + | |
1094 | +int | |
1095 | +auth_digest_md5(socket_t *sock, config_t *cfg) { | |
1096 | + | |
1097 | + struct iovec iov[3]; | |
1098 | + int rc; | |
1099 | + char rbuf[RESP_LEN]; | |
1100 | + char *buf; | |
1101 | + | |
1102 | +#ifdef DEBUG | |
1103 | + log_debug(DEBUG_1, "auth_digest_md5: AUTH DIGEST-MD5"); | |
1104 | +#endif | |
1105 | + | |
1106 | + iov[0].iov_base = SMTP_AUTH_CMD; | |
1107 | + iov[0].iov_len = sizeof(SMTP_AUTH_CMD) - 1; | |
1108 | + iov[1].iov_base = "DIGEST-MD5"; | |
1109 | + iov[1].iov_len = strlen("DIGEST-MD5"); | |
1110 | + iov[2].iov_base = SMTP_NEWLINE; | |
1111 | + iov[2].iov_len = sizeof(SMTP_NEWLINE) - 1; | |
1112 | + | |
1113 | +#ifdef DEBUG | |
1114 | + log_debug(DEBUG_9, "auth_digest_md5: sending %s%s", SMTP_AUTH_CMD,"DIGEST-MD5"); | |
1115 | +#endif | |
1116 | + if(cfg->timeout > 0) { | |
1117 | + set_timeout(cfg->timeout); | |
1118 | + } | |
1119 | + rc = retry_writev(sock, iov, 3); | |
1120 | + memset(iov, 0, sizeof(iov)); | |
1121 | + if(cfg->timeout > 0) { | |
1122 | + set_timeout(0); | |
1123 | + } | |
1124 | + if(rc == -1) { | |
1125 | +#ifdef DEBUG | |
1126 | + log_debug(DEBUG_1, "auth_digest_md5: digest-md5 writev: %m"); | |
1127 | +#endif | |
1128 | + return AUTH_NG; | |
1129 | + } | |
1130 | + | |
1131 | + if(cfg->timeout > 0) { | |
1132 | + set_timeout(cfg->timeout); | |
1133 | + } | |
1134 | + rc = socket_read(sock, rbuf, sizeof(rbuf)); | |
1135 | + if(cfg->timeout > 0) { | |
1136 | + set_timeout(0); | |
1137 | + } | |
1138 | + if(rc == -1) { | |
1139 | +#ifdef DEBUG | |
1140 | + log_debug(DEBUG_1, "auth_digest_md5: read (response): %m"); | |
1141 | +#endif | |
1142 | + return AUTH_NG; | |
1143 | + } | |
1144 | + | |
1145 | +#ifdef DEBUG | |
1146 | + log_debug(DEBUG_5, "auth_digest_md5: read (response): %s",rbuf); | |
1147 | +#endif | |
1148 | + if(strncmp(rbuf, "334 ", sizeof("334 ")-1) == 0) { | |
1149 | + char *response; | |
1150 | + char *response64; | |
1151 | + char *challenge; | |
1152 | + int challengelen; | |
1153 | + unsigned char hexdigest[256]; | |
1154 | + | |
1155 | + challenge = malloc(strlen(rbuf + 4) + 1); | |
1156 | + challengelen = base64_decode(challenge, rbuf + 4, -1); | |
1157 | + challenge[challengelen] = '\0'; | |
1158 | +#ifdef DEBUG | |
1159 | + log_debug(DEBUG_9, "auth_digest_md5: challenge=%s", challenge); | |
1160 | +#endif | |
1161 | + | |
1162 | + digest_md5((char *)hexdigest, (unsigned char*)challenge, challengelen, cfg->username, cfg->password); | |
1163 | +#ifdef DEBUG | |
1164 | + log_debug(DEBUG_9, "auth_digest_md5: hexdigest=%s", hexdigest); | |
1165 | +#endif | |
1166 | + | |
1167 | + response = malloc(sizeof(char)*256); | |
1168 | + snprintf(response, 256, "%s", hexdigest); | |
1169 | +#ifdef DEBUG | |
1170 | + log_debug(DEBUG_9, "auth_digest_md5: response=%s", response); | |
1171 | +#endif | |
1172 | + response64 = malloc((strlen(response) + 3) * 2 + 1); | |
1173 | + base64_encode(response64, response, strlen(response)); | |
1174 | + free(response); | |
1175 | +#ifdef DEBUG | |
1176 | + log_debug(DEBUG_9, "auth_digest_md5: response64=%s", response64); | |
1177 | +#endif | |
1178 | + | |
1179 | + iov[0].iov_base = response64; | |
1180 | + iov[0].iov_len = strlen(response64); | |
1181 | + iov[1].iov_base = SMTP_NEWLINE; | |
1182 | + iov[1].iov_len = sizeof(SMTP_NEWLINE) - 1; | |
1183 | + | |
1184 | +#ifdef DEBUG | |
1185 | + log_debug(DEBUG_9, "auth_digest_md5: sending %s", response64); | |
1186 | +#endif | |
1187 | + if(cfg->timeout > 0) { | |
1188 | + set_timeout(cfg->timeout); | |
1189 | + } | |
1190 | + rc = retry_writev(sock, iov, 2); | |
1191 | + memset(iov, 0, sizeof(iov)); | |
1192 | + if(cfg->timeout > 0) { | |
1193 | + set_timeout(0); | |
1194 | + } | |
1195 | + if(rc == -1) { | |
1196 | +#ifdef DEBUG | |
1197 | + log_debug(DEBUG_1, "auth_digest_md5: digest-md5 writev: %m"); | |
1198 | +#endif | |
1199 | + return AUTH_NG; | |
1200 | + } | |
1201 | + | |
1202 | + if(cfg->timeout > 0) { | |
1203 | + set_timeout(cfg->timeout); | |
1204 | + } | |
1205 | + rc = socket_read(sock, rbuf, sizeof(rbuf)); | |
1206 | + if(cfg->timeout > 0) { | |
1207 | + set_timeout(0); | |
1208 | + } | |
1209 | + if(rc == -1) { | |
1210 | +#ifdef DEBUG | |
1211 | + log_debug(DEBUG_1, "auth_digest_md5: read (response): %m"); | |
1212 | +#endif | |
1213 | + return AUTH_NG; | |
1214 | + } | |
1215 | + | |
1216 | +#ifdef DEBUG | |
1217 | + log_debug(DEBUG_5, "auth_digest_md5: read (response): %s",rbuf); | |
1218 | +#endif | |
1219 | + if(strncmp(rbuf, "334 ", sizeof("334 ")-1) == 0) { | |
1220 | + int buflen; | |
1221 | + | |
1222 | + buf = malloc(strlen(rbuf + 4) + 1); | |
1223 | + buflen = base64_decode(buf, rbuf + 4, -1); | |
1224 | + buf[buflen] = '\0'; | |
1225 | + | |
1226 | + iov[0].iov_base = buf; | |
1227 | + iov[0].iov_len = strlen(buf); | |
1228 | + iov[1].iov_base = SMTP_NEWLINE; | |
1229 | + iov[1].iov_len = sizeof(SMTP_NEWLINE) - 1; | |
1230 | + | |
1231 | +#ifdef DEBUG | |
1232 | + log_debug(DEBUG_9, "auth_digest_md5: sending %s", buf); | |
1233 | +#endif | |
1234 | + if(cfg->timeout > 0) { | |
1235 | + set_timeout(cfg->timeout); | |
1236 | + } | |
1237 | + rc = retry_writev(sock, iov, 2); | |
1238 | + memset(iov, 0, sizeof(iov)); | |
1239 | + if(cfg->timeout > 0) { | |
1240 | + set_timeout(0); | |
1241 | + } | |
1242 | + if(rc == -1) { | |
1243 | +#ifdef DEBUG | |
1244 | + log_debug(DEBUG_1, "auth_digest_md5: digest-md5 writev: %m"); | |
1245 | +#endif | |
1246 | + return AUTH_NG; | |
1247 | + } | |
1248 | + | |
1249 | + if(cfg->timeout > 0) { | |
1250 | + set_timeout(cfg->timeout); | |
1251 | + } | |
1252 | + rc = socket_read(sock, rbuf, sizeof(rbuf)); | |
1253 | + if(cfg->timeout > 0) { | |
1254 | + set_timeout(0); | |
1255 | + } | |
1256 | + if(rc == -1) { | |
1257 | +#ifdef DEBUG | |
1258 | + log_debug(DEBUG_1, "auth_digest_md5: read (response): %m"); | |
1259 | +#endif | |
1260 | + return AUTH_NG; | |
1261 | + } | |
1262 | + | |
1263 | +#ifdef DEBUG | |
1264 | + log_debug(DEBUG_5, "auth_digest_md5: read (response): %s",rbuf); | |
1265 | +#endif | |
1266 | + if(strncmp(rbuf, "235 ", sizeof("235 ")-1) != 0) { | |
1267 | +#ifdef DEBUG | |
1268 | + log_debug(DEBUG_1, "auth_digest_md5: auth failure."); | |
1269 | +#endif | |
1270 | + return AUTH_NG; | |
1271 | + } | |
1272 | + } else { | |
1273 | +#ifdef DEBUG | |
1274 | + log_debug(DEBUG_1, "auth_digest_md5: it seems digest-md5 mech is not implemented."); | |
1275 | +#endif | |
1276 | + return AUTH_NG; | |
1277 | + } | |
1278 | + free(response64); | |
1279 | + } else { | |
1280 | +#ifdef DEBUG | |
1281 | + log_debug(DEBUG_1, "auth_digest_md5: it seems digest-md5 mech is not implemented."); | |
1282 | +#endif | |
1283 | + return AUTH_NG; | |
1284 | + } | |
1285 | + return AUTH_OK; | |
1286 | +} | |
1287 | + | |
1288 | +#ifdef USE_SSL | |
1289 | +SSL_CTX *SSLContext = 0; | |
1290 | + | |
1291 | +#ifdef VERYIFY_CERT | |
1292 | +static int | |
1293 | +verify_cert(SSL *ssl) { | |
1294 | + | |
1295 | + X509 *cert; | |
1296 | + int err; | |
1297 | + char buf[256]; | |
1298 | + int ret = -1; | |
1299 | + BIO *bio; | |
1300 | + | |
1301 | + cert = SSL_get_peer_certificate(ssl); | |
1302 | + if(!cert) { | |
1303 | +#ifdef DEBUG | |
1304 | + log_debug(DEBUG_1, "verify_cert: Error: no server certificate."); | |
1305 | +#endif | |
1306 | + return -1; | |
1307 | + } | |
1308 | + | |
1309 | + err = SSL_get_verify_result(ssl); | |
1310 | + if(err == X509_V_OK) { | |
1311 | + return 0; | |
1312 | + } | |
1313 | + | |
1314 | +#ifdef DEBUG | |
1315 | + log_debug(DEBUG_1, "verify_cert: Error: can't verify certificate: %s (%d).", X509_verify_cert_error_string(err), err); | |
1316 | +#endif | |
1317 | + X509_NAME_oneline(X509_get_subject_name(cert), buf, sizeof(buf)); | |
1318 | + fprintf(stderr,"\nSubject: %s\n", buf); | |
1319 | + X509_NAME_oneline(X509_get_issuer_name(cert), buf, sizeof(buf)); | |
1320 | + fprintf(stderr,"Issuer: %s\n", buf); | |
1321 | + bio = BIO_new(BIO_s_mem()); | |
1322 | + ASN1_TIME_print(bio, X509_get_notBefore(cert)); | |
1323 | + memset(buf, 0, sizeof(buf)); | |
1324 | + BIO_read(bio, buf, sizeof(buf) - 1); | |
1325 | + fprintf(stderr,"Valid from: %s\n", buf); | |
1326 | + ASN1_TIME_print(bio, X509_get_notAfter(cert)); | |
1327 | + memset(buf, 0, sizeof(buf)); | |
1328 | + BIO_read(bio, buf, sizeof(buf) - 1); | |
1329 | + BIO_free(bio); | |
1330 | + fprintf(stderr," to: %s\n", buf); | |
1331 | + | |
1332 | + fprintf(stderr, | |
1333 | + "\nThere is no way to verify this certificate.\n" | |
1334 | + " It is possible that a hostile attacker has replaced the server certificate.\n" | |
1335 | + " Continue at your own risk!\n" | |
1336 | + "\nAccept this certificate anyway? [no]: "); | |
1337 | + if(fgets(buf, sizeof(buf), stdin) && (buf[0] == 'y' || buf[0] == 'Y')) { | |
1338 | + ret = 0; | |
1339 | + fprintf(stderr, "\nFine, but don't say I didn't warn you!\n\n"); | |
1340 | + } | |
1341 | + return ret; | |
1342 | +} | |
1343 | +#endif | |
1344 | + | |
1345 | +static int | |
1346 | +init_ssl(config_t *conf) { | |
1347 | + | |
1348 | + SSL_METHOD *method; | |
1349 | + int options = 0; | |
1350 | + | |
1351 | + if(!conf->certfile) { | |
1352 | +#ifdef DEBUG | |
1353 | + log_debug(DEBUG_1, "init_ssl: Error: SSLCertificateFile not defined."); | |
1354 | +#endif | |
1355 | + return -1; | |
1356 | + } | |
1357 | + SSL_load_error_strings(); | |
1358 | + SSL_library_init(); | |
1359 | + if(conf->use_tlsv1 && !conf->use_sslv2 && !conf->use_sslv3) | |
1360 | + method = TLSv1_client_method(); | |
1361 | + else | |
1362 | + method = SSLv23_client_method(); | |
1363 | + | |
1364 | + SSLContext = SSL_CTX_new(method); | |
1365 | + | |
1366 | + if(access(conf->certfile, F_OK)) { | |
1367 | + if(errno != ENOENT) { | |
1368 | +#ifdef DEBUG | |
1369 | + log_debug(DEBUG_1, "init_ssl: Error: SSLCertificateFile is not accessible."); | |
1370 | +#endif | |
1371 | + return -1; | |
1372 | + } | |
1373 | +#ifdef DEBUG | |
1374 | + log_debug(DEBUG_1, "init_ssl: Warning: SSLCertificateFile doesn't exist, can't verify server certificates."); | |
1375 | +#endif | |
1376 | + } else if(!SSL_CTX_load_verify_locations(SSLContext, conf->certfile, NULL)) { | |
1377 | +#ifdef DEBUG | |
1378 | + log_debug(DEBUG_1, "init_ssl: Error: SSL_CTX_load_verify_locations: %s.",ERR_error_string(ERR_get_error(), 0)); | |
1379 | +#endif | |
1380 | + SSL_CTX_free(SSLContext); | |
1381 | + return -1; | |
1382 | + } | |
1383 | + | |
1384 | + if(!conf->use_sslv2) { | |
1385 | + options |= SSL_OP_NO_SSLv2; | |
1386 | + } | |
1387 | + if(!conf->use_sslv3) { | |
1388 | + options |= SSL_OP_NO_SSLv3; | |
1389 | + } | |
1390 | + if(!conf->use_tlsv1) { | |
1391 | + options |= SSL_OP_NO_TLSv1; | |
1392 | + } | |
1393 | + | |
1394 | + SSL_CTX_set_options(SSLContext, options); | |
1395 | + | |
1396 | + /* we check the result of the verification after SSL_connect() */ | |
1397 | + SSL_CTX_set_verify(SSLContext, SSL_VERIFY_NONE, 0); | |
1398 | + return 0; | |
1399 | +} | |
1400 | + | |
1401 | +int | |
1402 | +start_tls(smtp_t *smtp, config_t *cfg) { | |
1403 | + | |
1404 | + int ret; | |
1405 | + /* initialize SSL */ | |
1406 | + if(init_ssl(cfg)) { | |
1407 | +#ifdef DEBUG | |
1408 | + log_debug(DEBUG_1, "start_tls: failed to initialize ssl session."); | |
1409 | +#endif | |
1410 | + return 1; | |
1411 | + } | |
1412 | + | |
1413 | + smtp->sock->ssl = SSL_new(SSLContext); | |
1414 | + SSL_set_fd(smtp->sock->ssl, smtp->sock->fd); | |
1415 | + if((ret = SSL_connect(smtp->sock->ssl)) <= 0) { | |
1416 | + socket_perror("connect", smtp->sock, ret); | |
1417 | +#ifdef DEBUG | |
1418 | + log_debug(DEBUG_1, "start_tls: failed to connect ssl session."); | |
1419 | +#endif | |
1420 | + return 1; | |
1421 | + } | |
1422 | +#ifdef VERIFY_CERT | |
1423 | + /* verify the server certificate */ | |
1424 | + if(verify_cert(smtp->sock->ssl)) { | |
1425 | + return 1; | |
1426 | + } | |
1427 | +#endif | |
1428 | + smtp->sock->use_ssl = 1; | |
1429 | +#ifdef DEBUG | |
1430 | + log_debug(DEBUG_1, "start_tls: SSL support enabled."); | |
1431 | +#endif | |
1432 | + return 0; | |
1433 | +} | |
1434 | +#endif | |
1435 | + |