aboutsummaryrefslogtreecommitdiffstats
path: root/smtpc.c
diff options
context:
space:
mode:
Diffstat (limited to 'smtpc.c')
-rw-r--r--smtpc.c457
1 files changed, 0 insertions, 457 deletions
diff --git a/smtpc.c b/smtpc.c
deleted file mode 100644
index deb99c63..00000000
--- a/smtpc.c
+++ /dev/null
@@ -1,457 +0,0 @@
-/* $OpenBSD: smtpc.c,v 1.10 2019/09/21 09:04:08 semarie Exp $ */
-
-/*
- * Copyright (c) 2018 Eric Faurot <eric@openbsd.org>
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <sys/types.h>
-#include <sys/socket.h>
-
-#include <event.h>
-#include <limits.h>
-#include <netdb.h>
-#include <pwd.h>
-#include <resolv.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <syslog.h>
-#include <unistd.h>
-
-#include <openssl/ssl.h>
-
-#include "smtp.h"
-#include "ssl.h"
-#include "log.h"
-
-static void parse_server(char *);
-static void parse_message(FILE *);
-static void resume(void);
-
-static int verbose = 1;
-static int done = 0;
-static int noaction = 0;
-static struct addrinfo *res0, *ai;
-static struct smtp_params params;
-static struct smtp_mail mail;
-static const char *servname = NULL;
-
-static SSL_CTX *ssl_ctx;
-
-static void
-usage(void)
-{
- extern char *__progname;
-
- fprintf(stderr,
- "usage: %s [-Chnv] [-F from] [-H helo] [-s server] [-S name] rcpt ...\n",
- __progname);
- exit(1);
-}
-
-int
-main(int argc, char **argv)
-{
- char hostname[256];
- int ch, i;
- char *server = "localhost";
- struct passwd *pw;
-
- log_init(1, 0);
-
- if (gethostname(hostname, sizeof(hostname)) == -1)
- fatal("gethostname");
-
- if ((pw = getpwuid(getuid())) == NULL)
- fatal("getpwuid");
-
- memset(&params, 0, sizeof(params));
-
- params.linemax = 16392;
- params.ibufmax = 65536;
- params.obufmax = 65536;
- params.timeout = 100000;
- params.helo = hostname;
-
- params.tls_verify = 1;
-
- memset(&mail, 0, sizeof(mail));
- mail.from = pw->pw_name;
-
- while ((ch = getopt(argc, argv, "CF:H:S:hns:v")) != -1) {
- switch (ch) {
- case 'C':
- params.tls_verify = 0;
- break;
- case 'F':
- mail.from = optarg;
- break;
- case 'H':
- params.helo = optarg;
- break;
- case 'S':
- servname = optarg;
- break;
- case 'h':
- usage();
- break;
- case 'n':
- noaction = 1;
- break;
- case 's':
- server = optarg;
- break;
- case 'v':
- verbose++;
- break;
- default:
- usage();
- }
- }
-
- log_setverbose(verbose);
-
- argc -= optind;
- argv += optind;
-
- if (argc) {
- mail.rcpt = calloc(argc, sizeof(*mail.rcpt));
- if (mail.rcpt == NULL)
- fatal("calloc");
- for (i = 0; i < argc; i++)
- mail.rcpt[i].to = argv[i];
- mail.rcptcount = argc;
- }
-
- ssl_init();
- event_init();
-
- ssl_ctx = ssl_ctx_create(NULL, NULL, 0, NULL);
- if (!SSL_CTX_load_verify_locations(ssl_ctx,
- X509_get_default_cert_file(), NULL))
- fatal("SSL_CTX_load_verify_locations");
- if (!SSL_CTX_set_ssl_version(ssl_ctx, SSLv23_client_method()))
- fatal("SSL_CTX_set_ssl_version");
- SSL_CTX_set_verify(ssl_ctx, SSL_VERIFY_NONE , NULL);
-
- if (pledge("stdio inet dns tmppath", NULL) == -1)
- fatal("pledge");
-
- if (!noaction)
- parse_message(stdin);
-
- if (pledge("stdio inet dns", NULL) == -1)
- fatal("pledge");
-
- parse_server(server);
-
- if (pledge("stdio inet", NULL) == -1)
- fatal("pledge");
-
- resume();
-
- log_debug("done...");
-
- return 0;
-}
-
-static void
-parse_server(char *server)
-{
- struct addrinfo hints;
- char *scheme, *creds, *host, *port, *p, *c;
- int error;
-
- creds = NULL;
- host = NULL;
- port = NULL;
- scheme = server;
-
- p = strstr(server, "://");
- if (p) {
- *p = '\0';
- p += 3;
- /* check for credentials */
- c = strchr(p, '@');
- if (c) {
- creds = p;
- *c = '\0';
- host = c + 1;
- } else
- host = p;
- } else {
- /* Assume a simple server name */
- scheme = "smtp";
- host = server;
- }
-
- if (host[0] == '[') {
- /* IPV6 address? */
- p = strchr(host, ']');
- if (p) {
- if (p[1] == ':' || p[1] == '\0') {
- *p++ = '\0'; /* remove ']' */
- host++; /* skip '[' */
- if (*p == ':')
- port = p + 1;
- }
- }
- }
- else {
- port = strchr(host, ':');
- if (port)
- *port++ = '\0';
- }
-
- if (port && port[0] == '\0')
- port = NULL;
-
- if (creds) {
- p = strchr(creds, ':');
- if (p == NULL)
- fatalx("invalid credentials");
- *p = '\0';
-
- params.auth_user = creds;
- params.auth_pass = p + 1;
- }
- params.tls_req = TLS_YES;
-
- if (!strcmp(scheme, "lmtp")) {
- params.lmtp = 1;
- }
- else if (!strcmp(scheme, "lmtp+tls")) {
- params.lmtp = 1;
- params.tls_req = TLS_FORCE;
- }
- else if (!strcmp(scheme, "lmtp+notls")) {
- params.lmtp = 1;
- params.tls_req = TLS_NO;
- }
- else if (!strcmp(scheme, "smtps")) {
- params.tls_req = TLS_SMTPS;
- if (port == NULL)
- port = "smtps";
- }
- else if (!strcmp(scheme, "smtp")) {
- }
- else if (!strcmp(scheme, "smtp+tls")) {
- params.tls_req = TLS_FORCE;
- }
- else if (!strcmp(scheme, "smtp+notls")) {
- params.tls_req = TLS_NO;
- }
- else
- fatalx("invalid url scheme %s", scheme);
-
- if (port == NULL)
- port = "smtp";
-
- if (servname == NULL)
- servname = host;
-
- memset(&hints, 0, sizeof(hints));
- hints.ai_family = AF_UNSPEC;
- hints.ai_socktype = SOCK_STREAM;
- error = getaddrinfo(host, port, &hints, &res0);
- if (error)
- fatalx("%s: %s", host, gai_strerror(error));
- ai = res0;
-}
-
-void
-parse_message(FILE *ifp)
-{
- char *line = NULL;
- size_t linesz = 0;
- ssize_t len;
-
- if ((mail.fp = tmpfile()) == NULL)
- fatal("tmpfile");
-
- for (;;) {
- if ((len = getline(&line, &linesz, ifp)) == -1) {
- if (feof(ifp))
- break;
- fatal("getline");
- }
-
- if (len >= 2 && line[len - 2] == '\r' && line[len - 1] == '\n')
- line[--len - 1] = '\n';
-
- if (fwrite(line, 1, len, mail.fp) != len)
- fatal("fwrite");
-
- if (line[len - 1] != '\n' && fputc('\n', mail.fp) == EOF)
- fatal("fputc");
- }
-
- fclose(ifp);
- rewind(mail.fp);
-}
-
-void
-resume(void)
-{
- static int started = 0;
- char host[256];
- char serv[16];
-
- if (done) {
- event_loopexit(NULL);
- return;
- }
-
- if (ai == NULL)
- fatalx("no more host");
-
- getnameinfo(ai->ai_addr, ai->ai_addr->sa_len,
- host, sizeof(host), serv, sizeof(serv),
- NI_NUMERICHOST | NI_NUMERICSERV);
- log_debug("trying host %s port %s...", host, serv);
-
- params.dst = ai->ai_addr;
- if (smtp_connect(&params, NULL) == NULL)
- fatal("smtp_connect");
-
- if (started == 0) {
- started = 1;
- event_loop(0);
- }
-}
-
-void
-log_trace(int lvl, const char *emsg, ...)
-{
- va_list ap;
-
- if (verbose > lvl) {
- va_start(ap, emsg);
- vlog(LOG_DEBUG, emsg, ap);
- va_end(ap);
- }
-}
-
-void
-smtp_verify_server_cert(void *tag, struct smtp_client *proto, void *ctx)
-{
- SSL *ssl = ctx;
- X509 *cert;
- long res;
- int match;
-
- if ((cert = SSL_get_peer_certificate(ssl))) {
- (void)ssl_check_name(cert, servname, &match);
- X509_free(cert);
- res = SSL_get_verify_result(ssl);
- if (res == X509_V_OK) {
- if (match) {
- log_debug("valid certificate");
- smtp_cert_verified(proto, CERT_OK);
- }
- else {
- log_debug("certificate does not match hostname");
- smtp_cert_verified(proto, CERT_INVALID);
- }
- return;
- }
- log_debug("certificate validation error %ld", res);
- }
- else
- log_debug("no certificate provided");
-
- smtp_cert_verified(proto, CERT_INVALID);
-}
-
-void
-smtp_require_tls(void *tag, struct smtp_client *proto)
-{
- SSL *ssl = NULL;
-
- if ((ssl = SSL_new(ssl_ctx)) == NULL)
- fatal("SSL_new");
- smtp_set_tls(proto, ssl);
-}
-
-void
-smtp_ready(void *tag, struct smtp_client *proto)
-{
- log_debug("connection ready...");
-
- if (done || noaction)
- smtp_quit(proto);
- else
- smtp_sendmail(proto, &mail);
-}
-
-void
-smtp_failed(void *tag, struct smtp_client *proto, int failure, const char *detail)
-{
- switch (failure) {
- case FAIL_INTERNAL:
- log_warnx("internal error: %s", detail);
- break;
- case FAIL_CONN:
- log_warnx("connection error: %s", detail);
- break;
- case FAIL_PROTO:
- log_warnx("protocol error: %s", detail);
- break;
- case FAIL_IMPL:
- log_warnx("missing feature: %s", detail);
- break;
- case FAIL_RESP:
- log_warnx("rejected by server: %s", detail);
- break;
- default:
- fatalx("unknown failure %d: %s", failure, detail);
- }
-}
-
-void
-smtp_status(void *tag, struct smtp_client *proto, struct smtp_status *status)
-{
- log_info("%s: %s: %s", status->rcpt->to, status->cmd, status->status);
-}
-
-void
-smtp_done(void *tag, struct smtp_client *proto, struct smtp_mail *mail)
-{
- int i;
-
- log_debug("mail done...");
-
- if (noaction)
- return;
-
- for (i = 0; i < mail->rcptcount; i++)
- if (!mail->rcpt[i].done)
- return;
-
- done = 1;
-}
-
-void
-smtp_closed(void *tag, struct smtp_client *proto)
-{
- log_debug("connection closed...");
-
- ai = ai->ai_next;
- if (noaction && ai == NULL)
- done = 1;
-
- resume();
-}