/* # main: processing of command line options and start the main loop. # # Copyright (C) 2007-2011 Yves Rutschle # # 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. # # The full text for the General Public License is here: # http://www.gnu.org/licenses/gpl.html */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "common.h" const char* USAGE_STRING = "sslh " VERSION "\n" \ "usage:\n" \ "\tsslh [-v] [-i] [-V] [-f] [-n]\n" "\t[-t ] [-P ] -u -p [-p ...] \n" \ "%s\n\n" \ "-v: verbose\n" \ "-V: version\n" \ "-f: foreground\n" \ "-n: numeric output\n" \ "-t: timeout before connecting to SSH.\n" \ "-p: address and port to listen on.\n Can be used several times to bind to several addresses.\n" \ "--[ssh,ssl,...]: where to connect connections from corresponding protocol.\n" \ "-P: PID file. Default: /var/run/sslh.pid.\n" \ "-i: Run as a inetd service.\n" \ ""; void print_usage(void) { int i; char *prots = ""; for (i = 0; i < num_known_protocols; i++) asprintf(&prots, "%s\t[--%s ]\n", prots, protocols[i].description); fprintf(stderr, USAGE_STRING, prots); } void parse_cmdline(int argc, char* argv[]) { int c, affected = 0; struct option const_options[] = { { "inetd", no_argument, &inetd, 1 }, { "foreground", no_argument, &foreground, 1 }, { "verbose", no_argument, &verbose, 1 }, { "numeric", no_argument, &numeric, 1 }, { "user", required_argument, 0, 'u' }, { "pidfile", required_argument, 0, 'P' }, { "timeout", required_argument, 0, 't' }, { "listen", required_argument, 0, 'p' }, }; struct option all_options[ARRAY_SIZE(const_options) + num_known_protocols + 1]; struct addrinfo *addr, **a; memset(all_options, 0, sizeof(all_options)); memcpy(all_options, const_options, sizeof(const_options)); append_protocols(all_options, ARRAY_SIZE(const_options), protocols, num_known_protocols); while ((c = getopt_long_only(argc, argv, "t:T:p:VP:", all_options, NULL)) != -1) { if (c == 0) continue; if (c >= PROT_SHIFT) { affected++; protocols[c - PROT_SHIFT].affected = 1; resolve_name(&addr, optarg); protocols[c - PROT_SHIFT].saddr= *addr; continue; } switch (c) { case 't': probing_timeout = atoi(optarg); break; case 'p': /* find the end of the listen list */ for (a = &addr_listen; *a; a = &((*a)->ai_next)); /* append the specified addresses */ resolve_name(a, optarg); break; case 'V': printf("%s %s\n", server_type, VERSION); exit(0); case 'u': user_name = optarg; break; case 'P': pid_file = optarg; break; default: print_usage(); exit(2); } } if (!affected) { fprintf(stderr, "At least one target protocol must be specified.\n"); exit(2); } if (!addr_listen) { fprintf(stderr, "No listening address specified; use at least one -p option\n"); exit(1); } } int main(int argc, char *argv[]) { extern char *optarg; extern int optind; int res, num_addr_listen; int *listen_sockets; /* Init defaults */ pid_file = "/var/run/sslh.pid"; user_name = "nobody"; foreground = 0; parse_cmdline(argc, argv); if (inetd) { verbose = 0; start_shoveler(0); exit(0); } if (verbose) printsettings(); num_addr_listen = start_listen_sockets(&listen_sockets, addr_listen); if (!foreground) if (fork() > 0) exit(0); /* Detach */ setup_signals(); drop_privileges(user_name); /* New session -- become group leader */ if (getuid() == 0) { res = setsid(); CHECK_RES_DIE(res, "setsid: already process leader"); } write_pid_file(pid_file); /* Open syslog connection */ setup_syslog(argv[0]); main_loop(listen_sockets, num_addr_listen); return 0; }