/* ** ** Copyright (C) 1993 Swedish University Network (SUNET) ** ** ** This program is developed by UDAC, Uppsala University by commission ** of the Swedish University Network (SUNET). ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation; either version 2 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITTNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ** ** ** Martin.Wendel@its.uu.se ** Torbjorn.Wictorin@its.uu.se ** ** ITS ** P.O. Box 887 ** S-751 08 Uppsala ** Sweden ** */ #include "emil.h" #ifdef SMTP #define RTYPE(r) ((r) / 100) #define RCLASS(r) (((r) / 10) % 10) #include #include #include #include #ifdef NAMED_BIND #ifdef HAVE_RES_SEARCH #include #include #endif #endif #define SMTPBUF 1024 #define smtpout out_fd #ifndef INADDR_NONE # define INADDR_NONE 0xffffffff #endif #ifndef SMTPHOSTNAME #define SMTPHOSTNAME "nohost.nodomain" #endif FILE *smtpin; extern FILE *out_fd; static char outbuf[SMTPBUF], inbuf[SMTPBUF]; #endif #ifdef NAMED_BIND #ifdef HAVE_RES_SEARCH extern int h_errno; #endif #endif void make_connection(char *ahost, FILE **in, FILE **out, int usemx) { #ifdef SMTP register struct hostent *h = (struct hostent *)NULL; struct sockaddr_in server; int sock = 0; int sockt = 0; int i; char *p, *t; char *host; #ifdef USE_MX #ifdef HAVE_RES_SEARCH struct mxlist *list; #endif #endif t = NULL; #ifdef NAMED_BIND #ifdef HAVE_RES_SEARCH _res.options &= (~RES_DNSRCH & 0xffff); list = NULL; #endif #endif host = ahost; errno = h_errno = 0; if (*host == '[') { unsigned long i = INADDR_NONE; p = host + 1; if ((t = index(host, ']')) != NULL) { *t = '\0'; i = inet_addr(p); *t = ']'; } if (t == NULL || i == INADDR_NONE) { /* Invalid server spec */ fprintf(stderr, "Emil: Unknown host %s\n", host); exit(EX_NOHOST); } server.sin_addr.s_addr = i; } lookup: errno = 0; if (t == NULL) { #ifdef USE_MX #ifdef HAVE_RES_SEARCH if (usemx) /* Look for MX */ { list = (struct mxlist *)get_mx(host); usemx = 0; } if (list != NULL) { host = list->host; list = list->next; } #endif #endif if ((h = (struct hostent *)gethostbyname(host)) == NULL) { #ifdef USE_MX #ifdef HAVE_RES_SEARCH if (list != NULL) goto lookup; #endif #endif if (errno == ETIMEDOUT || h_errno == TRY_AGAIN) exit (EX_TEMPFAIL); if (errno == ECONNREFUSED) exit(EX_TEMPFAIL); /* Failed */ fprintf(stderr, "Emil: Host lookup failed.\n"); fprintf(stderr, "Emil: Unknown host %s\n", host); exit(EX_NOHOST); } else bcopy((char *)h->h_addr, (char *)&server.sin_addr, h->h_length); } i = 0; again: if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) { fprintf(stderr, "Emil: Unable to create socket\n"); exit(EX_TEMPFAIL); } server.sin_family = AF_INET; server.sin_port = htons(25); errno = 0; if (connect(sock,(struct sockaddr *)&server, sizeof server) < 0) { close(sock); #ifdef NAMED_BIND #ifdef HAVE_RES_SEARCH if (h && h->h_addr_list[i]) { bcopy(h->h_addr_list[i++], (char *)&server.sin_addr, h->h_length); goto again; } if (list != NULL) goto lookup; #endif #endif switch(errno) { case EISCONN: case ETIMEDOUT: case EINPROGRESS: case EALREADY: case EADDRINUSE: case EHOSTDOWN: case ENETDOWN: case ENETRESET: case ENOBUFS: case ECONNREFUSED: case ECONNRESET: case EHOSTUNREACH: case ENETUNREACH: case EPERM: exit (EX_TEMPFAIL); default: { fprintf(stderr, "Emil: Unable to connect to %s\n", host); exit(EX_TEMPFAIL); } } } *out = fdopen(sock, "a"); if ((sockt = dup(sock)) == -1) { fprintf(stderr, "Emil dup(socket) failed.\n"); exit(EX_OSERR); } *in = fdopen(sockt, "r"); if (smtpout == NULL || smtpin == NULL) { close(sock); fprintf(stderr, "Emil: smtp open failed.\n"); exit(EX_TEMPFAIL); } } void smtp_open(char *host) { int r; #if defined(HAVE_RES_SEARCH) && defined(USE_MX) make_connection(host, &smtpin, &smtpout, 1); #else make_connection(host, &smtpin, &smtpout, 0); #endif if ((r = smtp_get()) < 0 || RTYPE(r) != 2) { fprintf(stderr, "Emil: %s greeted us with %d\n", host, r); exit(EX_TEMPFAIL); } if (hostname == NULL) hostname = NEWSTR(SMTPHOSTNAME); sprintf(outbuf, "HELO %s\r\n", hostname); if (fputs(outbuf, smtpout) == EOF) { fprintf(stderr, "Emil: smtp error on write\n"); exit(EX_TEMPFAIL); } fflush(smtpout); #ifdef DEBUG if (edebug) fprintf(stderr, "SMTP write: %s", outbuf); #endif if ((r = smtp_get()) < 0 || RTYPE(r) != 2) { fprintf(stderr, "Emil: %s said %d\n", host, r); exit(EX_TEMPFAIL); } sprintf(outbuf, "MAIL FROM: <%s>\r\n", sender); if (fputs(outbuf, smtpout) == EOF) { fprintf(stderr, "Emil: smtp error on write\n"); exit(EX_TEMPFAIL); } fflush(smtpout); #ifdef DEBUG if (edebug) fprintf(stderr, "SMTP write: %s", outbuf); #endif r = smtp_get(); if (r != 250) { fprintf(stderr, "Emil: sender %s not accepted by %s", sender, host); exit(EX_NOUSER); } sprintf(outbuf, "RCPT TO: <%s>\r\n", recipient); if (fputs(outbuf, smtpout) == EOF) { fprintf(stderr, "Emil: smtp error on write\n"); exit(EX_TEMPFAIL); } fflush(smtpout); #ifdef DEBUG if (edebug) fprintf(stderr, "SMTP write: %s", outbuf); #endif r = smtp_get(); if (r != 250) { fprintf(stderr, "Emil: recipient %s not accepted by %s\n", recipient, host); exit(EX_NOUSER); } sprintf(outbuf, "DATA\r\n"); if (fputs(outbuf, smtpout) == EOF) { fprintf(stderr, "Emil: smtp error on write\n"); exit(EX_TEMPFAIL); } fflush(smtpout); #ifdef DEBUG if (edebug) fprintf(stderr, "SMTP write: DATA\r\n"); #endif r = smtp_get(); if (r != 250 && r != 354) { fprintf(stderr, "Emil: data transfer to %s failed\n", host); exit(EX_NOUSER); } #endif } void smtp_close(char *host) { int r; sprintf(outbuf, "\r\n.\r\n"); fputs(outbuf, smtpout); fflush(smtpout); #ifdef DEBUG if (edebug) fprintf(stderr, "SMTP write: .\r\n"); #endif r = smtp_get(); if (r != 250) { fprintf(stderr, "Emil: %s said %d after data transer completed\n", host, r); exit(EX_TEMPFAIL); } sprintf(outbuf, "QUIT\r\n"); #ifdef DEBUG if (edebug) fprintf(stderr, "SMTP write: QUIT\r\n"); #endif fputs(outbuf, smtpout); fflush(smtpout); r = smtp_get(); } int smtp_get() { int i; for(;;) { if ((fgets(inbuf, SMTPBUF, smtpin)) == NULL) { fprintf(stderr, "Emil SMTP: Error on read.\n"); exit(EX_TEMPFAIL); } #ifdef DEBUG if (edebug) fprintf(stderr, "SMTP read:%s:", inbuf); #endif if (inbuf[0] == '4' || inbuf[0] == '5') { /* Serious error */ exit(EX_NOUSER); } i = atoi(inbuf); if (inbuf[3] == '-') continue; if (i < 100) continue; return(i); } }