diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/tools/Makefile | 34 | ||||
-rw-r--r-- | src/tools/README | 19 | ||||
-rw-r--r-- | src/tools/anopesmtp.c | 550 | ||||
-rw-r--r-- | src/tools/smtp.h | 94 |
4 files changed, 697 insertions, 0 deletions
diff --git a/src/tools/Makefile b/src/tools/Makefile new file mode 100644 index 000000000..54e3ca8e8 --- /dev/null +++ b/src/tools/Makefile @@ -0,0 +1,34 @@ +OBJS = anopesmpt.o +SRCS = anopesmpt.c + +INCLUDES = ../../include/services.h + +MAKEARGS = 'CFLAGS=${CFLAGS}' 'CC=${CC}' 'ANOPELIBS=${ANOPELIBS}' \ + 'LDFLAGS=${LDFLAGS}' 'BINDEST=${BINDEST}' 'INSTALL=${INSTALL}' \ + 'INCLUDEDIR=${INCLUDEDIR}' 'RM=${RM}' 'CP=${CP}' \ + 'TOUCH=${TOUCH}' 'SHELL=${SHELL}' 'DATDEST=${DATDEST}' \ + 'RUNGROUP=${RUNGROUP}' + +.c.o: + $(CC) $(CFLAGS) -I../include/ -c $< + +all: anopesmtp + +distclean: clean spotless + +anopesmpt: $(OBJS) + $(CC) $(CFLAGS) $(OBJS) $(ANOPELIBS) $(MLIBS) -o $@ $(LDFLAGS) + +$(OBJS): Makefile +anopesmpt.o: anopesmpt.c $(INCLUDES) + +clean: + rm -f *.o anopesmtp a.out + +spotless: clean + +install: anopesmtp + test -d ${BINDEST} || mkdir ${BINDEST} + $(INSTALL) anopesmtp $(BINDEST)/anopesmtp + +DUMMY: diff --git a/src/tools/README b/src/tools/README new file mode 100644 index 000000000..ccfc69129 --- /dev/null +++ b/src/tools/README @@ -0,0 +1,19 @@ +Anope SMTP Client + + - Provided with Anope is a simple SMTP client which can be used to replace programs like +SendMail in some cases. + + - To use the SMTP client find the line in your services.conf for the "SendMailPath", enter +the path to your services installation directory, followed by the "anopesmtp" and the IP address +of a valid SMTP server. It should look something like + +SendMailPath "/home/usersname/services/anopesmtp 194.97.50.135" + + - If you run into a problem you can compile a debug into the code by opening smtp.h and at the +bottom you should find "smtp_debug" change the 0 to a 1 and recompile the code. This should +generate a log file of what happened when it attempted to connect to the SMTP server. + + +Credits: +Orginally written by Dominick Meglio <codemastr@unrealircd.com> +Ported to *nix by Trystan Scott Lee <trystan@nomadirc.net> diff --git a/src/tools/anopesmtp.c b/src/tools/anopesmtp.c new file mode 100644 index 000000000..3b9eabe6c --- /dev/null +++ b/src/tools/anopesmtp.c @@ -0,0 +1,550 @@ +/* smtp stuff handler for win32. + * + * (C) 2003 Anope Team + * Contact us at info@anope.org + * + * Please read COPYING and README for furhter details. + * + * Based on the original code of Epona by Lara. + * Based on the original code of Services by Andy Church. + * + * Written by Dominick Meglio <codemastr@unrealircd.com> + * *nix port by Trystan Scott Lee <trystan@nomadirc.net> + * + */ + +#include "smtp.h" + +static FILE *logfile; +static int curday = 0; + +/*************************************************************************/ + +static int get_logname(char *name, int count, struct tm *tm) +{ + + char timestamp[32]; + + if (!tm) { + time_t t; + + time(&t); + tm = localtime(&t); + } + + strftime(timestamp, count, "%Y%m%d", tm); + snprintf(name, count, "logs/%s.%s", "anopesmtp", timestamp); + curday = tm->tm_yday; + + return 1; +} + +/*************************************************************************/ + +/* Close the log file. */ + +void close_log(void) +{ + if (!logfile) + return; + fclose(logfile); + logfile = NULL; +} + +/*************************************************************************/ + +static void remove_log(void) +{ + time_t t; + struct tm tm; + + char name[PATH_MAX]; + + time(&t); + t -= (60 * 60 * 24 * 30); + tm = *localtime(&t); + + if (!get_logname(name, sizeof(name), &tm)) + return; + unlink(name); +} + +/*************************************************************************/ + +static void checkday(void) +{ + time_t t; + struct tm tm; + + time(&t); + tm = *localtime(&t); + + if (curday != tm.tm_yday) { + close_log(); + remove_log(); + open_log(); + } +} + +/*************************************************************************/ + +/* Open the log file. Return -1 if the log file could not be opened, else + * return 0. */ + +int open_log(void) +{ + char name[PATH_MAX]; + + if (logfile) + return 0; + + if (!get_logname(name, sizeof(name), NULL)) + return 0; + logfile = fopen(name, "a"); + + if (logfile) + setbuf(logfile, NULL); + return logfile != NULL ? 0 : -1; +} + +/*************************************************************************/ + +/* Log stuff to the log file with a datestamp. Note that errno is + * preserved by this routine and log_perror(). + */ + +void alog(const char *fmt, ...) +{ + va_list args; + time_t t; + struct tm tm; + char buf[256]; + int errno_save = errno; + + if (!smtp_debug) { + return; + } + + checkday(); + + if (!fmt) { + return; + } + + va_start(args, fmt); + time(&t); + tm = *localtime(&t); + strftime(buf, sizeof(buf) - 1, "[%b %d %H:%M:%S %Y] ", &tm); + if (logfile && args) { + fputs(buf, logfile); + vfprintf(logfile, fmt, args); + fputc('\n', logfile); + } + va_end(args); + errno = errno_save; +} + +/*************************************************************************/ + +/* Remove a trailing \r\n */ +char *strip(char *buf) +{ + char *c; + if ((c = strchr(buf, '\n'))) + *c = 0; + if ((c = strchr(buf, '\r'))) + *c = 0; + return buf; +} + +/*************************************************************************/ + +/* Convert a trailing \n to \r\n + * The caller must free the allocated memory + */ +char *lftocrlf(char *buf) +{ + char *result = malloc(strlen(buf) + 2); + strip(buf); + strcpy(result, buf); + strcat(result, "\r\n"); + return result; +} + +/*************************************************************************/ + +/* Add a header to the list */ +void smtp_add_header(char *header) +{ + struct smtp_header *head = malloc(sizeof(struct smtp_header)); + + head->header = lftocrlf(header); + head->next = NULL; + + if (!mail.smtp_headers) { + mail.smtp_headers = head; + } + if (mail.smtp_headers_tail) { + mail.smtp_headers_tail->next = head; + } + mail.smtp_headers_tail = head; +} + +/*************************************************************************/ + +/* Is the buffer a header? */ +int smtp_is_header(char *buf) +{ + char *tmp = strchr(buf, ' '); + + if (!tmp) + return 0; + + if (*(tmp - 1) == ':') + return 1; + return 0; +} + +/*************************************************************************/ + +/* Parse a header into a name and value */ +void smtp_parse_header(char *buf, char **header, char **value) +{ + strip(buf); + + *header = strtok(buf, " "); + *value = strtok(NULL, ""); + if (*header) + (*header)[strlen(*header) - 1] = 0; +} + +/*************************************************************************/ + +/* Have we reached the end of input? */ +int smtp_is_end(char *buf) +{ + if (*buf == '.') + if (*(buf + 1) == '\r' || *(buf + 1) == '\n') + return 1; + + return 0; +} + +/*************************************************************************/ + +/* Set who the email is from */ +void smtp_set_from(char *from) +{ + mail.from = strdup(from); +} + +/*************************************************************************/ + +/* Set who the email is to */ +void smtp_set_to(char *to) +{ + char *c; + + if ((c = strrchr(to, '<')) && *(c + 1)) { + to = c + 1; + to[strlen(to) - 1] = 0; + } + mail.to = strdup(to); +} + +/*************************************************************************/ + +/* Add a line of body text */ +void smtp_add_body_line(char *line) +{ + struct smtp_body_line *body; + + body = malloc(sizeof(struct smtp_body_line)); + + body->line = lftocrlf(line); + body->next = NULL; + + if (!mail.smtp_body) + mail.smtp_body = body; + if (mail.smtp_body_tail) + mail.smtp_body_tail->next = body; + mail.smtp_body_tail = body; + +} + +/*************************************************************************/ + +/* Establish a connection to the SMTP server */ +int smtp_connect(char *host, unsigned short port) +{ + struct sockaddr_in addr; + + if ((mail.sock = socket(AF_INET, SOCK_STREAM, 0)) == SOCKET_ERROR) + return 0; + + if ((addr.sin_addr.s_addr = inet_addr(host)) == INADDR_NONE) { + struct hostent *hent; + if (!(hent = gethostbyname(host))) + return 0; + memcpy(&addr.sin_addr, hent->h_addr, hent->h_length); + } + addr.sin_family = AF_INET; + addr.sin_port = htons(port ? port : 25); + if (connect(mail.sock, (struct sockaddr *) &addr, sizeof(struct sockaddr_in)) == SOCKET_ERROR) { + ano_sockclose(mail.sock); + return 0; + } + + return 1; +} + +/*************************************************************************/ + +/* Send a line of text */ +int smtp_send(char *text) +{ + int result = ano_sockwrite(mail.sock, text, strlen(text)); + + alog("SMTP: sent %s",text); + + if (result == SOCKET_ERROR) + ano_sockclose(mail.sock); + + return result; +} + +/*************************************************************************/ + +/* Read a line of text */ +int smtp_read(char *buf, int len) +{ + int result; + + memset(buf, 0, len); + result = ano_sockread(mail.sock, buf, len); + + if (result == SOCKET_ERROR) + ano_sockclose(mail.sock); + + return result; +} + +/*************************************************************************/ + +/* Retrieve a response code */ +int smtp_get_code(char *text) +{ + char *tmp = strtok(text, " "); + + if (!tmp) + return 0; + + return atol(tmp); +} + +/*************************************************************************/ + +/* Send the email */ +int smtp_send_email() +{ + char buf[1024]; + struct smtp_header *head; + struct smtp_body_line *body; + int code; + int skip_done = 0; + + if (!smtp_read(buf, 1024)) { + alog("SMTP: error reading buffer"); + return 0; + } + + code = smtp_get_code(buf); + if (code != 220) { + alog("SMTP: error expected code 220 got %d",code); + return 0; + } + + if (!smtp_send("HELO anope\r\n")) { + alog("SMTP: error writting to socket"); + return 0; + } + + if (!smtp_read(buf, 1024)) { + alog("SMTP: error reading buffer"); + return 0; + } + + code = smtp_get_code(buf); + if (code != 250) { + alog("SMTP: error expected code 250 got %d",code); + return 0; + } + + strcpy(buf, "MAIL FROM: <"); + strcat(buf, mail.from); + strcat(buf, ">\r\n"); + + if (!smtp_send(buf)) { + alog("SMTP: error writting to socket"); + return 0; + } + + if (!smtp_read(buf, 1024)) { + alog("SMTP: error reading buffer"); + return 0; + } + + code = smtp_get_code(buf); + if (code != 250) + return 0; + + strcpy(buf, "RCPT TO: <"); + strcat(buf, mail.to); + strcat(buf, ">\r\n"); + + if (!smtp_send(buf)) { + alog("SMTP: error writting to socket"); + return 0; + } + + if (!smtp_read(buf, 1024)) { + alog("SMTP: error reading buffer"); + return 0; + } + + code = smtp_get_code(buf); + if (smtp_get_code(buf) != 250) { + alog("SMTP: error expected code 250 got %d",code); + return 0; + } + + if (!smtp_send("DATA\r\n")) { + alog("SMTP: error writting to socket"); + return 0; + } + + if (!smtp_read(buf, 1024)) { + alog("SMTP: error reading buffer"); + return 0; + } + + code = smtp_get_code(buf); + if (code != 354) { + alog("SMTP: error expected code 354 got %d",code); + return 0; + } + + for (head = mail.smtp_headers; head; head = head->next) { + if (!smtp_send(head->header)) { + alog("SMTP: error writting to socket"); + return 0; + } + } + + if (!smtp_send("\r\n")) { + alog("SMTP: error writting to socket"); + return 0; + } + + for (body = mail.smtp_body; body; body = body->next) { + if (skip_done) { + if (!smtp_send(body->line)) { + alog("SMTP: error writting to socket"); + return 0; + } + } else { + skip_done = 1; + } + } + + if (!smtp_send("\r\n.\r\n")) { + alog("SMTP: error writting to socket"); + return 0; + } + + return 1; +} + +/*************************************************************************/ + +void smtp_disconnect() +{ + smtp_send("QUIT\r\n"); + ano_sockclose(mail.sock); +} + +/*************************************************************************/ + +int main(int argc, char *argv[]) +{ + char buf[8192]; + struct smtp_body_line *b; + struct smtp_header *h; + int headers_done = 0; +/* Win32 stuff */ +#ifdef _WIN32 + WSADATA wsa; +#endif + char *server, *aport; + short port; + + if (argc == 1) + return 0; + + server = strtok(argv[1], ":"); + if ((aport = strtok(NULL, ""))) { + port = atoi(aport); + } else { + port = 25; + } + + if (!server) { + alog("No Server"); + return; + } else { + alog("SMTP: server %s port %d",server,port); + } + + memset(&mail, 0, sizeof(mail)); + +/* The WSAStartup function initiates use of WS2_32.DLL by a process. */ +/* guessing we can skip it under *nix */ +#ifdef _WIN32 + if (WSAStartup(MAKEWORD(1, 1), &wsa) != 0) + return 0; +#endif + + /* Read the message and parse it */ + while (fgets(buf, 8192, stdin)) { + if (smtp_is_header(buf) && !headers_done) { + char *header, *value; + smtp_add_header(buf); + smtp_parse_header(buf, &header, &value); + if (!strcasecmp(header, "from")) { + alog("SMTP: from: %s",value); + smtp_set_from(value); + } else if (!strcasecmp(header, "to")) { + alog("SMTP: to: %s",value); + smtp_set_to(value); + } else if (smtp_is_end(buf)) { + break; + } else { + headers_done = 1; + smtp_add_body_line(buf); + } + } else { + smtp_add_body_line(buf); + } + } + + if (!smtp_connect(server, port)) { + alog("SMTP: failed to connect to %s:%d",server, port); + return 0; + } + if (!smtp_send_email()) { + alog("SMTP: error during sending of mail"); + return 0; + } + smtp_disconnect(); + return 1; +} diff --git a/src/tools/smtp.h b/src/tools/smtp.h new file mode 100644 index 000000000..0dc0a0cbb --- /dev/null +++ b/src/tools/smtp.h @@ -0,0 +1,94 @@ +/* + * + * (C) 2003 Anope Team + * Contact us at info@anope.org + * + * Please read COPYING and README for furhter details. + * + * Based on the original code of Epona by Lara. + * Based on the original code of Services by Andy Church. + * + * + */ + +#ifndef SMTP_H +#define SMTP_H + +/*************************************************************************/ + +/* Some Linux boxes (or maybe glibc includes) require this for the + * prototype of strsignal(). */ +#define _GNU_SOURCE + +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <signal.h> +#include <time.h> +#include <errno.h> +#include <grp.h> +#include <limits.h> +#include <netdb.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <sys/socket.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <sys/time.h> +#include <fcntl.h> +#include <ctype.h> + +#ifdef _AIX +extern int strcasecmp(const char *, const char *); +extern int strncasecmp(const char *, const char *, size_t); +# if 0 /* These break on some AIX boxes (4.3.1 reported). */ +extern int socket(int, int, int); +extern int connect(int, struct sockaddr *, int); +# endif +#endif /* _AIX */ + + +/*************************************************************************/ + +#ifdef _WIN32 +#include <winsock.h> +typedef SOCKET ano_socket_t; +#define ano_sockclose(fd) closesocket(fd) +#define ano_sockread(fd, buf, len) recv(fd, buf, len, 0) +#define ano_sockwrite(fd, buf, len) send(fd, buf, len, 0) +#else +typedef int ano_socket_t; +#define ano_sockclose(fd) close(fd) +#define ano_sockread(fd, buf, len) read(fd, buf, len) +#define ano_sockwrite(fd, buf, len) write(fd, buf, len) +#define SOCKET_ERROR -1 +#endif + + +/* Data structures */ +struct smtp_header { + char *header; + struct smtp_header *next; +}; + +struct smtp_body_line { + char *line; + struct smtp_body_line *next; +}; + +struct smtp_message { + struct smtp_header *smtp_headers, *smtp_headers_tail; + struct smtp_body_line *smtp_body, *smtp_body_tail; + char *from; + char *to; + ano_socket_t sock; +}; + +struct smtp_message mail; + +/* set this to 1 if you want to get a log otherwise it runs silent */ +int smtp_debug = 0; + +#endif /* SMTP_H */ |