diff options
Diffstat (limited to 'protocols/protocol.cc')
-rw-r--r-- | protocols/protocol.cc | 155 |
1 files changed, 155 insertions, 0 deletions
diff --git a/protocols/protocol.cc b/protocols/protocol.cc new file mode 100644 index 0000000..4545dd8 --- /dev/null +++ b/protocols/protocol.cc @@ -0,0 +1,155 @@ +// nullmailer -- a simple relay-only MTA +// Copyright (C) 2017 Bruce Guenter <bruce@untroubled.org> +// +// 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 FITNESS 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// You can contact me at <bruce@untroubled.org>. There is also a mailing list +// available to discuss this package. To subscribe, send an email to +// <nullmailer-subscribe@lists.untroubled.org>. + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> +#include "connect.h" +#include "errcodes.h" +#include "list.h" +#include "mystring/mystring.h" +#include "protocol.h" +#include "cli++/cli++.h" + +const char* user = 0; +const char* pass = 0; +int port = 0; +int auth_method = AUTH_DETECT; +int use_tls = 0; +int use_starttls = 0; +const char* remote = 0; +const char* source = 0; +const char* cli_help_suffix = ""; +const char* cli_args_usage = "< options 3< mail-file"; +const int cli_args_min = 0; +const int cli_args_max = 0; +cli_option cli_options[] = { + { 0, "host", cli_option::string, 0, &remote, + "Set the hostname for the remote", 0 }, + { 'p', "port", cli_option::integer, 0, &port, + "Set the port number on the remote host to connect to", 0 }, + { 0, "user", cli_option::string, 0, &user, + "Set the user name for authentication", 0 }, + { 0, "pass", cli_option::string, 0, &pass, + "Set the password for authentication", 0 }, + { 0, "auth-login", cli_option::flag, AUTH_LOGIN, &auth_method, + "Use AUTH LOGIN instead of auto-detecting in SMTP", 0 }, + { 0, "source", cli_option::string, 0, &source, + "Source address for connections", 0 }, +#ifdef HAVE_TLS + { 0, "tls", cli_option::flag, 1, &use_tls, + "Connect using TLS (on an alternate port by default)", 0 }, + { 0, "ssl", cli_option::flag, 1, &use_tls, + "Alias for --tls", 0 }, + { 0, "starttls", cli_option::flag, 1, &use_starttls, + "Use STARTTLS command", 0 }, + { 0, "x509certfile", cli_option::string, 0, &tls_x509certfile, + "Client certificate file", 0 }, + { 0, "x509keyfile", cli_option::string, 0, &tls_x509keyfile, + "Client certificate private key file", "the same file as --x509certfile" }, + { 0, "x509cafile", cli_option::string, 0, &tls_x509cafile, + "Certificate authority trust file", DEFAULT_CA_FILE }, + { 0, "x509crlfile", cli_option::string, 0, &tls_x509crlfile, + "Certificate revocation list file", 0 }, + { 0, "x509fmtder", cli_option::flag, true, &tls_x509derfmt, + "X.509 files are in DER format", "PEM format" }, + { 0, "insecure", cli_option::flag, true, &tls_insecure, + "Don't abort if server certificate fails validation", 0 }, + { 0, "tls-anon-auth", cli_option::flag, true, &tls_anon_auth, + "Use TLS anonymous authentication - needs --insecure option", 0 }, +#endif + {0, 0, cli_option::flag, 0, 0, 0, 0} +}; + +void protocol_fail(int e, const char* msg) +{ + fout << msg << endl; + ferr << cli_program << ": Failed: " << msg << endl; + exit(e); +} + +void protocol_succ(const char* msg) +{ + fout << msg << endl; + ferr << cli_program << ": Succeeded: " << msg << endl; + exit(0); +} + +static void plain_send(fdibuf& in, int fd) +{ + fdibuf netin(fd); + fdobuf netout(fd); + if (!netin || !netout) + protocol_fail(ERR_MSG_TEMPFAIL, "Error allocating I/O buffers"); + if (use_starttls) { + protocol_starttls(netin, netout); + tls_send(in, fd); + } + else + protocol_send(in, netin, netout); +} + +static void parse_option(mystring line) +{ + if (line[0] != '-') + line = "--" + line; + const char* arg = strdup(line.c_str()); + if (arg == NULL) + exit(ERR_CONFIG); + const char* args[3] = { argv0, arg, NULL }; + if (cli_parse_args(2, (char**)args) != 2) + exit(ERR_CONFIG); +} + +static void parse_options(void) +{ + mystring line; + while (fin.getline(line, '\n')) { + if (line.length() == 0) + return; + parse_option(line); + } + if (!fin.eof()) + exit(ERR_CONFIG); +} + +int cli_main(int, char*[]) +{ + parse_options(); + if (remote == 0) + protocol_fail(ERR_USAGE, "Remote host not set"); + if (port == 0) + port = use_tls ? default_tls_port : default_port; + if (port < 0) + protocol_fail(ERR_USAGE, "Invalid value for port"); + if (use_tls || use_starttls) + tls_init(remote); + fdibuf in(3, true); + protocol_prep(in); + int fd = tcpconnect(remote, port, source); + if(fd < 0) + protocol_fail(-fd, "Connect failed"); + if (use_tls) + tls_send(in, fd); + else + plain_send(in, fd); + return 0; +} |