// nullmailer -- a simple relay-only MTA // Copyright (C) 2018 Bruce Guenter // // 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 . There is also a mailing list // available to discuss this package. To subscribe, send an email to // . #include #include #include #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; }