• R/O
  • HTTP
  • SSH
  • HTTPS

pam_smtpauth: コミット

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

変更サマリ

差分

--- a/src/smtpauth.c
+++ b/src/smtpauth.c
@@ -369,7 +369,9 @@ smtp_auth(config_t *cfg) {
369369 struct iovec iov[5];
370370 char *c;
371371 int rc;
372+ int readBytes = 0;
372373 char rbuf[RESP_LEN];
374+ char sockbuf[RESP_LEN];
373375 int auth = 0;
374376 int avail_auth_type = 0;
375377 char *tbuf;
@@ -465,9 +467,14 @@ smtp_auth(config_t *cfg) {
465467 }
466468 }
467469 }
468- addr.sin_addr.s_addr = *((int *)he->h_addr_list[0]);
469470 s = socket(PF_INET, SOCK_STREAM, 0);
470471
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+
471478 if(cfg->conn_timeout > 0) {
472479 set_timeout(cfg->conn_timeout);
473480 }
@@ -505,7 +512,15 @@ smtp_auth(config_t *cfg) {
505512 if(cfg->timeout > 0) {
506513 set_timeout(cfg->timeout);
507514 }
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
509524 if(cfg->timeout > 0) {
510525 set_timeout(0);
511526 }
@@ -519,11 +534,51 @@ smtp_auth(config_t *cfg) {
519534 strcpy(smtp->error_message, msgbuf);
520535 goto bail;
521536 }
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+ }
523574 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';
526580 }
581+ //////////////////////////////////
527582
528583 if(strncmp(rbuf, "220 ", sizeof("220 ")-1)) {
529584 #ifdef DEBUG
@@ -575,14 +630,17 @@ smtp_auth(config_t *cfg) {
575630 if(cfg->timeout > 0) {
576631 set_timeout(cfg->timeout);
577632 }
633+
634+ memset(rbuf,0x00,sizeof(rbuf));
578635 rc = socket_read(smtp->sock, rbuf, sizeof(rbuf));
579636 if(cfg->timeout > 0) {
580637 set_timeout(0);
581638 }
582- if(rc == -1) {
583639 #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);
585642 #endif
643+ if(rc == -1) {
586644 smtp->error = 1;
587645 strcpy(msgbuf, RESP_IERROR);
588646 smtp->error_message = malloc(strlen(msgbuf) + 1);
--- /dev/null
+++ b/src/smtpauth.c.usleep
@@ -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+
旧リポジトリブラウザで表示