/* WARNING: This file was generated by dkct. Changes you make here will be lost if dkct is run again! You should modify the original source and run dkct on it. Original source: rshdown.ctr */ /* Copyright (C) 2016-2017, Dirk Krause Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above opyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the author nor the names of contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** @file rshdown.c The rshdown module. */ #line 9 "rshdown.ctr" /* rshdown -s [-n _number_] [-l _port_] [-b] _address_ _port_ _file_ rshdown [-c _configfile_] Either send shutdown packages (-s option used) or run as daemon in background (no -s option) and wait for shutdown packages. Sending: -n _number_ Number of packages to send -l _port_ Local port number to use Default: Same as remote port -b Flag: Destination address is a broadcast address _address_ Destination address (hostname or IP address) _port_ Port number on destination host _file_ File containing data to send Daemon: -c _configfile_ Configuration file. */ #include "dk4conf.h" #include "dk4types.h" #include #if DK4_HAVE_UNISTD_H #ifndef UNISTD_H_INCLUDED #include #define UNISTD_H_INCLUDED 1 #endif #endif #if DK4_HAVE_STDLIB_H #ifndef STDLIB_H_INCLUDED #include #define STDLIB_H_INCLUDED 1 #endif #endif #if (DK4_CHAR_SIZE == 1) \ && (DK4_HAVE_SIGACTION || DK4_HAVE_SIGSET) \ && (DK4_HAVE_SETSID || DK4_HAVE_SETPGRP) #if DK4_HAVE_MATH_H #ifndef MATH_H_INCLUDED #include #define MATH_H_INCLUDED 1 #endif #endif #if DK4_HAVE_IO_H #ifndef IO_H_INCLUDED #include #define IO_H_INCLUDED 1 #endif #endif #if DK4_HAVE_FCNTL_H #ifndef FCNTL_H_INCLUDED #include #define FCNTL_H_INCLUDED 1 #endif #endif #if DK4_HAVE_STRING_H #ifndef STRING_H_INCLUDED #include #define STRING_H_INCLUDED 1 #endif #endif #if DK4_HAVE_SYS_TYPES_H #ifndef SYS_TYPES_H_INCLUDED #include #define SYS_TYPES_H_INCLUDED 1 #endif #endif #if DK4_HAVE_SIGNAL_H #ifndef SIGNAL_H_INCLUDED #include #define SIGNAL_H_INCLUDED 1 #endif #endif #if DK4_HAVE_SYSLOG_H #ifndef SYSLOG_H_INCLUDED #include #define SYSLOG_H_INCLUDED 1 #endif #endif #include "dk4mem.h" #include "dk4memrs.h" #include "dk4opt.h" #include "dk4mai8dus.h" #include "dk4mai8dii.h" #include "dk4fopt.h" #include "dk4fopc8.h" #include "dk4isadm.h" #include "dk4sock.h" #include "dk4inst.h" #include "dk4str8.h" #include "dk4mpl.h" #include "dk4dmt.h" #include "dk4vers.h" #line 131 "rshdown.ctr" #ifndef RSHDOWN_BUFFER_SIZE /** Buffer size, should not exceed UDP packet size. */ #define RSHDOWN_BUFFER_SIZE 1460 #endif /** Path name of data file. */ static char file_name[DK4_MAX_PATH]; /** Send and receive buffer. */ static char b1[RSHDOWN_BUFFER_SIZE]; /** Buffer for local secret from file in daemon. */ static char b2[sizeof(b1)]; /** Command to execute on packet arrival. */ static char cmd[1024]; /** Allowed sender peer as text. */ static char asender[1024]; /** Options used by the program. */ static dk4_option_t options[] = { /* 0 Configuration file. */ { { dkT('c'), dkT("config"), DK4_OPT_ARG_STRING }, { NULL }, 0 }, /* 1 Send data. */ { { dkT('s'), dkT("send"), DK4_OPT_ARG_NONE }, { NULL }, 0 }, /* 2 Destination address is a broadcast address. */ { { dkT('b'), dkT("broadcast"), DK4_OPT_ARG_NONE }, { NULL }, 0 }, /* 3 Number of packets to send. */ { { dkT('n'), dkT("number"), DK4_OPT_ARG_UNSIGNED}, { NULL }, 0 }, /* 4 Local port number. */ { { dkT('l'), dkT("local"), DK4_OPT_ARG_UNSIGNED}, { NULL }, 0}, /* 5 Help. */ { { dkT('\0'),dkT("help"), DK4_OPT_ARG_NONE}, { NULL }, 0}, /* 6 Version. */ { { dkT('\0'),dkT("version"), DK4_OPT_ARG_NONE}, { NULL }, 0}, /* 7 License */ { { dkT('\0'),dkT("license"), DK4_OPT_ARG_NONE}, { NULL }, 0} }; /** Help text. */ static const char * const help_text[] = { "", "Remote shutdown sender and recipient", "", "rshdown [-c config]", "rshdown -s [-n number] [-l port] [-b] host port file", "", "-c config\t\tConfiguration file for recipient (daemon).", "", "-s\t\t\tSend shutdown data packet.", "-n number\t\tSend packet multiple times.", "-l port\t\t\tLocal port to use for sending.", "-b\t\t\tPrepare socket for broadcast sending.", "host\t\t\tRemote host (recipient), host name or IP address.", "\t\t\tOption -b is required if you specify a broadcast", "\t\t\taddress like 255.255.255.255 or 192.0.2.255 here.", "port\t\t\tRemote port.", "file\t\t\tFile containing pre-shared secret (shutdown data).", "", "--help\t\t\tShow this help text.", "--version\t\tShow version number.", "--license\t\tShow license information.", "", NULL #line 234 "rshdown.ctr" }; /** License conditions text. */ static const char * const license_text[] = { "", "This software uses code from the following projects, either directly or as", "a library:", "", "dktools\t\tDirk Krause's tools and libraries.", "\t\tSee http://dktools.sourceforge.net/ for more information.", "", "DK tools and libraries license", "==============================", "Copyright (c) 2015-2016, Dirk Krause", "All rights reserved.", "", "Redistribution and use in source and binary forms, with or without", "modification, are permitted provided that the following conditions are met:", "", "* Redistributions of source code must retain the above copyright notice,", " this list of conditions and the following disclaimer.", "* Redistributions in binary form must reproduce the above copyright", " notice, this list of conditions and the following disclaimer in the", " documentation and/or other materials provided with the distribution.", "* Neither the name of the Dirk Krause nor the names of contributors may be", " used to endorse or promote products derived from this software without", " specific prior written permission.", "", "THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"", "AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE", "IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE", "ARE DISCLAIMED.", "", "IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,", "INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,", "BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,", "DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY", "OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING", "NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,", "EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.", "", NULL #line 280 "rshdown.ctr" }; /** Version information. */ static const char version_text[] = { DKT_VERSION_C8 }; /** Default configuration file name. */ static const char def_conf_name[] = { DK4_INST_DIR_ETC "/rshdown/rshdown.conf" }; /** PID file name. */ static const char pid_file_name[] = { DK4_INST_DIR_VAR "/run/rshdown.pid" }; /** Key names expected in configuration file. */ static const char * const key_names[] = { /* 0 */ "sender", /* 1 */ "sender port", /* 2 */ "receiver port", /* 3 */ "signal", /* 4 */ "command", /* 5 */ "file", /* 6 */ "debug", /* 7 */ "syslog facility", NULL #line 343 "rshdown.ctr" }; /** Signal names. */ static const char * const signal_names[] = { /* 0 */ "sighup", /* 1 */ "hup", /* 2 */ "sigint", /* 3 */ "int", /* 4 */ "sigquit", /* 5 */ "quit", /* 6 */ "sigill", /* 7 */ "ill", /* 8 */ "sigtrap", /* 9 */ "trap", /* 10 */ "sigabrt", /* 11 */ "abrt", /* 12 */ "sigiot", /* 13 */ "iot", /* 14 */ "sigbus", /* 15 */ "bus", /* 16 */ "sigfpe", /* 17 */ "fpe", /* 18 */ "sigkill", /* 19 */ "kill", /* 20 */ "sigusr1", /* 21 */ "usr1", /* 22 */ "sigsegv", /* 23 */ "segv", /* 24 */ "sigusr2", /* 25 */ "usr2", /* 26 */ "sigpipe", /* 27 */ "pipe", /* 28 */ "sigalrm", /* 29 */ "alrm", /* 30 */ "sigterm", /* 31 */ "term", /* 32 */ "sigstkflt", /* 33 */ "stkflt", /* 34 */ "sigcld", /* 35 */ "cld", /* 36 */ "sigchld", /* 37 */ "chld", /* 38 */ "sigcont", /* 39 */ "cont", /* 40 */ "sigstop", /* 41 */ "stop", /* 42 */ "sigtstp", /* 43 */ "tstp", /* 44 */ "sigttin", /* 45 */ "ttin", /* 46 */ "sigttou", /* 47 */ "ttou", /* 48 */ "sigurg", /* 49 */ "urg", /* 50 */ "sigxcpu", /* 51 */ "xcpu", /* 52 */ "sigxfsz", /* 53 */ "xfsz", /* 54 */ "sigvtalrm", /* 55 */ "vtalrm", /* 56 */ "sigprof", /* 57 */ "prof", /* 58 */ "sigwinch", /* 59 */ "winch", /* 60 */ "sigpoll", /* 61 */ "poll", /* 62 */ "sigio", /* 63 */ "io", /* 64 */ "sigpwr", /* 65 */ "pwr", /* 66 */ "sigsys", /* 67 */ "sys", NULL #line 453 "rshdown.ctr" }; /** Syslog facility names. */ static const char * const syslog_facility_names[] = { /* 0 */ "auth", /* 1 */ "authpriv", /* 2 */ "cron", /* 3 */ "daemon", /* 4 */ "ftp", /* 5 */ "kern", /* 6 */ "lpr", /* 7 */ "mail", /* 8 */ "news", /* 9 */ "security", /* 10 */ "syslog", /* 11 */ "user", /* 12 */ "uucp", /* 13 */ "local0", /* 14 */ "local1", /* 15 */ "local2", /* 16 */ "local3", /* 17 */ "local4", /* 18 */ "local5", /* 19 */ "local6", /* 20 */ "local7", NULL #line 483 "rshdown.ctr" }; /** Texts used by the program, not localized. */ static const char * const rshdown_kw[] = { /* 0 */ "rshdown", /* 1 */ ": ", /* 2 */ "ERROR: Failed to set broadcast mode on socket!\n", /* 3 */ "ERROR: Failed to bind local address!\n", /* 4 */ "ERROR: Failed to bind local address: \"", /* 5 */ "\"!\n", /* 6 */ "ERROR: Failed to create socket!\n", /* 7 */ "ERROR: Failed to find address for: \"", /* 8 */ "\"!\n", /* 9 */ "ERROR: Failed to bring socket subsystem up!\n", /* 10 */ "ERROR: 3 arguments required: host, port and file!\n", /* 11 */ "ERROR: Not a 16 bit unsigned integer: \"", /* 12 */ "\"!\n", /* 13 */ "ERROR: Port number 0 is not allowed!\n", /* 14 */ "ERROR: Failed to open data file:\n\"", /* 15 */ "\"!\n", /* 16 */ "ERROR: Failed to read data from file:\n\"", /* 17 */ "\"!\n", /* 18 */ "ERROR: Failed to install signal handlers!\n", /* 19 */ "ERROR: Failed to restore signal handlers!\n", /* 20 */ "ERROR: Failed to create child process!\n", /* 21 */ "Failed to detach from terminal!", /* 22 */ "Failed to create child process!", /* 23 */ "Failed to install signal handlers!", /* 24 */ "Failed to restore signal handlers!", /* 25 */ "Failed to bring socket subsystem up!", /* 26 */ "Failed to create UDP socket set!", /* 27 */ "ERROR: Local port number too large!\n", /* 28 */ "ERROR: Local port number must not be 0!\n", /* 29 */ "Failed to set allowed peer: \"", /* 30 */ "\"!", /* 31 */ "ERROR: Illegal signal name: \"", /* 32 */ "\"!\n", /* 33 */ "ERROR: Sender name too long:\n", /* 34 */ "\"!\n", /* 35 */ "ERROR: Sender name defined multiple times!\n", /* 36 */ "ERROR: Signal number must be positive!\n", /* 37 */ "ERROR: Command too long:\n\"", /* 38 */ "\"!\n", /* 39 */ "ERROR: Command defined multiple times!\n", /* 40 */ "ERROR: File name too long:\n\"", /* 41 */ "\"!\n", /* 42 */ "ERROR: File name defined multiple times!\n", /* 43 */ "ERROR: Unknown key in configuration file!\n", /* 44 */ "ERROR: Missing value on configuration line!\n", /* 45 */ "ERROR: No local port specified!\n", /* 46 */ "ERROR: Signal number or command required!\n", /* 47 */ "ERROR: No data file specified!\n", /* 48 */ "ERROR: Illegal syslog facility: \"", /* 49 */ "\"!\n", /* 50 */ "Service started.", /* 51 */ "Initiate shutdown.", /* 52 */ "Service finished.", /* 53 */ "Packet from \"", /* 54 */ "\" discarded, wrong sender address!", /* 55 */ "Packet from \"", /* 56 */ "\" discarded, wrong sender port!", /* 57 */ "Packet from \"", /* 58 */ "\" discarded, size mismatch!", /* 59 */ "Packet from \"", /* 60 */ "\" discarded, data mismatch!", /* 61 */ "Failed to execute command: \"", /* 62 */ "\"!", NULL #line 689 "rshdown.ctr" }; /** Number of options in the options array. */ static const size_t szoptions = sizeof(options)/sizeof(dk4_option_t); /** Number of bytes in buffer b1. */ static size_t szb1 = 0; /** Number of bytes in buffer b2. */ static size_t szb2 = 0; /** Exit status code. */ static int exval = EXIT_FAILURE; /** Options: Help (1), version (2), license (4). */ static int hvl = 0; /** Flag: Additional debug messages. */ static int debug = 0; #ifdef LOG_DAEMON /** Syslog facility. */ static int syslogf = LOG_AUTH; #else /** Syslog facility. */ static int syslogf = (3<<3); #endif /** Signal to send on arrival of shutdown data packet. */ static int signo = #ifdef SIGPWR SIGPWR #else #ifdef SIGTERM SIGTERM #else 15 #endif #endif ; #ifdef SIGPIPE /** Indicator: SIGPIPE signal received. */ static DK4_VOLATILE dk4_sig_atomic_t sig_had_pipe = 0; #endif /** Indicator: SIGINT signal received. */ static DK4_VOLATILE dk4_sig_atomic_t sig_had_int = 0; /** Indicator: SIGTERM signal received. */ static DK4_VOLATILE dk4_sig_atomic_t sig_had_term = 0; /** Remote port. */ static unsigned short rp = 0U; /** Local port. */ static unsigned short lp = 0U; /** Pass pointer through. Use of this function is recommended by CERT C coding standard to avoid optimizing out. @param ptr Pointer to pass through. @return The ptr argument. */ static DK4_VOLATILE dk4_sig_atomic_t * sig_pass_pointer(DK4_VOLATILE dk4_sig_atomic_t *ptr) { return ptr; } #ifdef SIGPIPE /** Handler for SIGPIPE signal. @param signo Signal number (always SIGPIPE, ignored). */ static void sig_handler_pipe(int signo) { *sig_pass_pointer(&sig_had_pipe) = 1; } #endif /** Handler for SIGINT signal. @param signo Signal number (always SIGINT, ignored). */ static void sig_handler_int(int signo) { *sig_pass_pointer(&sig_had_int) = 1; } /** Handler for SIGTERM signal. @param signo Signal number (always SIGTERM, ignored). */ static void sig_handler_term(int signo) { *sig_pass_pointer(&sig_had_term) = 1; } /** Read value from volatile atomic type. This function is necessary as some compilers mis-optimize direct access to volatile variables (at least if you believe one of the coding standards). @param ap Pointer to volatile atomic variable. @return Contents of the variable. */ static dk4_sig_atomic_t sig_read_atomic(DK4_VOLATILE dk4_sig_atomic_t *ap) { return (*ap); } /** Check whether we can continue or must abort due to signal. @param dopipe Flag: Check for SIGPIPE too. @return 1 if we can continue, 0 otherwise. */ static int can_continue(void) { int back = 1; if (0 != sig_read_atomic(&sig_had_term)) { back = 0; } if (0 != sig_read_atomic(&sig_had_int)) { back = 0; } return back; } /** Write log message to stderr, 1 component. @param i Text index in rshdown_kw array. */ static void log_1(size_t i) { fputs(rshdown_kw[0], stderr); fputs(rshdown_kw[1], stderr); fputs(rshdown_kw[i], stderr); fflush(stderr); } /** Write syslog message, 1 component. @param i Index of text in rshdown_kw array. */ static void syslog_1(size_t i) { #if DK4_HAVE_SYSLOG openlog(rshdown_kw[0], LOG_PID, syslogf); syslog(LOG_ERR, "%s", rshdown_kw[i]); closelog(); #endif } /** Write syslog message, 3 components. @param i1 Index of first component in rshdown_kw array. @param i2 Index of third component in rshdown_kw array. @param str Second component. */ static void syslog_3(size_t i1, size_t i2, const char *str) { #if DK4_HAVE_SYSLOG openlog(rshdown_kw[0], LOG_PID, syslogf); if (NULL != str) { syslog(LOG_ERR, "%s%s%s", rshdown_kw[i1], str, rshdown_kw[i2]); } else { syslog(LOG_ERR, "%s%s", rshdown_kw[i1], rshdown_kw[i2]); } closelog(); #endif } /** Write an additional debug message to syslog. @param i1 Index of first component in rshdown_kw array. @param i2 Index of third component in rshdown_kw array. @param sa Socket address, second component. */ static void syslog_debug(size_t i1, size_t i2, dk4_sockaddr_storage_t *sa) { #if DK4_HAVE_SYSLOG char buf[128]; /* Buffer for text respresentation of address */ int res; /* Operation result from conversion */ if (0 != debug) { res = dk4socket_c8_sockaddr_to_text(buf, sizeof(buf), sa, NULL); openlog(rshdown_kw[0], LOG_PID, syslogf); if (DK4_SOCKET_RESULT_SUCCESS == res) { syslog(LOG_DEBUG, "%s%s%s", rshdown_kw[i1], buf, rshdown_kw[i2]); } else { syslog(LOG_DEBUG, "%s%s", rshdown_kw[i1], rshdown_kw[i2]); } closelog(); } #endif } /** Write log message to stderr, 3 components. @param i1 Index of first component in rshdown_kw array. @param i2 Index of third component in rshdown_kw array. @param str Second component. */ static void log_3(size_t i1, size_t i2, const char *str) { fputs(rshdown_kw[0], stderr); fputs(rshdown_kw[1], stderr); fputs(rshdown_kw[i1], stderr); if (NULL != str) { fputs(str, stderr); } fputs(rshdown_kw[i2], stderr); fflush(stderr); } /** Send buffer over network. @param hn Remote host name or IP address as text. @param rp Remote port in host representation. @param lp Local port in host representation. @param sz Number of bytes in b1. */ static void send_network(const char *hn, size_t sz) { char adbuf[128]; /* Address as text */ dk4_sockaddr_storage_t array[2]; /* Address pair */ dk4_um_t num = (dk4_um_t)0UL; size_t szr = 0; /* Rem addr size */ size_t szl = 0; /* Loc addr size */ size_t lgt = 0; /* Length sent */ dk4_socket_t sock = INVALID_SOCKET; int res = 0; /* Operation result */ int ip4 = 0; /* IPv4 preferred */ int af = AF_UNSPEC; int pf = PF_UNSPEC; #line 995 "rshdown.ctr" if (DK4_SOCKET_RESULT_SUCCESS == dk4socket_up(NULL)) { if (options[2].found) { ip4 = 1; } #line 997 "rshdown.ctr" res = dk4socket_c8_udp_addresses_numeric(array, hn, rp, lp, ip4, NULL); if (DK4_SOCKET_RESULT_SUCCESS == res) { #line 999 "rshdown.ctr" szr = dk4socket_address_size(array); szl = dk4socket_address_size(&(array[1])); af = dk4socket_address_family(&(array[1])); pf = dk4socket_pf_for_af(af); if ((0 < szr) && (0 < szl) && (AF_UNSPEC != af) && (PF_UNSPEC != pf)) { sock = dk4socket_open(pf, SOCK_DGRAM, 0, NULL); if (INVALID_SOCKET != sock) { #line 1006 "rshdown.ctr" exval = EXIT_SUCCESS; (void)dk4socket_option_set_reuse(sock, 1, NULL); if (options[2].found) { #line 1009 "rshdown.ctr" res = dk4socket_option_set_broadcast(sock,1,NULL); if (DK4_SOCKET_RESULT_SUCCESS != res) { /* ERROR: Failed to set broadcast mode */ log_1(2); exval = EXIT_FAILURE; #line 1014 "rshdown.ctr" } } res = dk4socket_bind( sock, (struct sockaddr *)(&(array[1])), szl, NULL ); if (DK4_SOCKET_RESULT_SUCCESS == res) { #line 1020 "rshdown.ctr" if (0 != options[3].found) { num = options[3].val.u; } if ((dk4_um_t)0UL == num) { num = (dk4_um_t)1UL; } while ((0 != can_continue()) && ((dk4_um_t)0UL < num--)) { lgt = sz; #line 1024 "rshdown.ctr" res = dk4socket_sendto( sock, b1, &lgt, 0, (struct sockaddr *)(&(array[0])), szr, 0L, 0L, NULL ); if (DK4_SOCKET_RESULT_SUCCESS == res) { #line 1030 "rshdown.ctr" if (lgt != sz) { exval = EXIT_FAILURE; } } else { #line 1032 "rshdown.ctr" exval = EXIT_FAILURE; } } } else { #line 1036 "rshdown.ctr" /* ERROR: Failed to bind local address */ res = dk4socket_c8_addr_port_to_text( adbuf, sizeof(adbuf), af, (struct sockaddr *)(&(array[1])), szl, NULL ); if (DK4_SOCKET_RESULT_SUCCESS == res) { log_3(4, 5, adbuf); } else { log_1(3); } } (void)dk4socket_close(sock, NULL); } else { #line 1049 "rshdown.ctr" /* ERROR: Failed to open socket */ log_1(6); } } else { #line 1053 "rshdown.ctr" if (0 == szr) { #line 1054 "rshdown.ctr" log_3(7, 8, hn); } if (0 == szl) { #line 1057 "rshdown.ctr" log_3(7, 8, hn); } if (AF_UNSPEC == af) { #line 1060 "rshdown.ctr" log_3(7, 8, hn); } if (PF_UNSPEC == pf) { #line 1063 "rshdown.ctr" log_3(7, 8, hn); } } } else { #line 1067 "rshdown.ctr" /* ERROR: Failed to obtain addresses */ log_3(7, 8, hn); } (void)dk4socket_down(NULL); } else { #line 1072 "rshdown.ctr" /* ERROR: Failed to bring socket subsystem up */ log_1(9); } #line 1076 "rshdown.ctr" } /** Send shutdown data packet. @param filenames Command line arguments array, 0=remote host, 1=remote port, 2=filename. @param szfilenames Number of elements in filenames array. */ static void sender_with_signals(const char * const *filenames, size_t szfilenames) { FILE *fipo = NULL; /* Data file */ const char *ep = NULL; /* End of usefull data pointer */ size_t lgt = 0; /* Number of bytes in buffer */ int res = 0; /* Conversion or operation result */ #line 1094 "rshdown.ctr" if (3 == szfilenames) { #line 1095 "rshdown.ctr" res = dk4ma_input_c8_dec_ushort(&rp, filenames[1], &ep, 1, NULL); if (0 != res) { #line 1097 "rshdown.ctr" if (0 != rp) { #line 1098 "rshdown.ctr" lp = rp; if (0 != options[4].found) { #line 1100 "rshdown.ctr" if ((dk4_um_t)0UL < options[4].val.u) { #line 1101 "rshdown.ctr" if ((dk4_um_t)(USHRT_MAX) >= options[4].val.u) { lp = (unsigned short)(options[4].val.u); #line 1103 "rshdown.ctr" } else { #line 1104 "rshdown.ctr" lp = 0; /* ERROR: Local port number exceeds 16 bit unsigned range */ log_1(27); } } else { #line 1109 "rshdown.ctr" lp = 0; /* ERROR: Local port number 0 is not allowed */ log_1(28); } } if (0 != lp) { #line 1115 "rshdown.ctr" fipo = dk4fopen_c8(filenames[2], "rb", DK4_FOPEN_SC_IS_REGULAR, NULL); if (NULL != fipo) { #line 1117 "rshdown.ctr" lgt = fread(b1, 1, sizeof(b1), fipo); fclose(fipo); if (0 < lgt) { #line 1120 "rshdown.ctr" /* Send bytes over network */ send_network(filenames[0], lgt); /* Overwrite memory containing data packet */ if (0 == dk4mem_reset_secure(b1, sizeof(b1), NULL)) { exval = EXIT_FAILURE; #line 1125 "rshdown.ctr" } } else { #line 1127 "rshdown.ctr" /* ERROR: No data read from file */ log_3(16, 17, filenames[2]); } } else { #line 1131 "rshdown.ctr" /* ERROR: Failed to open data file */ log_3(14, 15, filenames[2]); } } else { #line 1135 "rshdown.ctr" } } else { #line 1137 "rshdown.ctr" /* ERROR: Remote port number 0 is not allowed */ log_1(13); } } else { #line 1141 "rshdown.ctr" /* ERROR: Not a 16 bit unsigned number */ log_3(11, 12, filenames[1]); } } else { #line 1145 "rshdown.ctr" /* ERROR: Three arguments required - host, port and file */ log_1(10); } #line 1149 "rshdown.ctr" } /** Send shutdown data packet. @param filenames Command line arguments array, 0=remote host, 1=remote port, 2=filename. @param szfilenames Number of elements in filenames array. */ static void sender(const char * const *filenames, size_t szfilenames) { #line 1163 "rshdown.ctr" #line 1164 "rshdown.ctr" #ifdef DK4_HAVE_SIGACTION #ifdef SIGPIPE struct sigaction opipe; struct sigaction npipe; #endif struct sigaction oint; struct sigaction nint; struct sigaction oterm; struct sigaction nterm; #else #ifdef SIGPIPE dk4_sig_handler_t *opipe = NULL; #endif dk4_sig_handler_t *oterm = NULL; dk4_sig_handler_t *oint = NULL; #endif #ifdef DK4_HAVE_SIGACTION #ifdef SIGPIPE int spipe = 0; #endif int sint = 0; int sterm = 0; int s_f_i = 0; int s_f_r = 0; #endif /* Set signal handlers */ #if DK4_HAVE_SIGACTION #ifdef SIGPIPE DK4_MEMRES(&npipe, sizeof(npipe)); npipe.sa_handler = sig_handler_pipe; npipe.sa_flags = 0; if (0 != sigemptyset(&npipe.sa_mask)) { s_f_i = 1; goto finished; } if (0 != sigaddset(&npipe.sa_mask, SIGPIPE)) { s_f_i = 1; goto finished; } if (0 != sigaction(SIGPIPE, &npipe, &opipe)) { s_f_i = 1; goto finished; } spipe = 1; #endif DK4_MEMRES(&nterm, sizeof(nterm)); nterm.sa_handler = sig_handler_term; nterm.sa_flags = 0; if (0 != sigemptyset(&nterm.sa_mask)) { s_f_i = 1; goto finished; } if (0 != sigaddset(&nterm.sa_mask, SIGTERM)) { s_f_i = 1; goto finished; } if (0 != sigaction(SIGTERM, &nterm, &oterm)) { s_f_i = 1; goto finished; } sterm = 1; DK4_MEMRES(&nint, sizeof(nint)); nint.sa_handler = sig_handler_int; nint.sa_flags = 0; if (0 != sigemptyset(&nint.sa_mask)) { s_f_i = 1; goto finished; } if (0 != sigaddset(&nint.sa_mask, SIGINT)) { s_f_i = 1; goto finished; } if (0 != sigaction(SIGINT, &nint, &oint)) { s_f_i = 1; goto finished; } sint = 1; #else #ifdef SIGPIPE opipe = sigset(SIGPIPE, sig_handler_pipe); #endif oint = sigset(SIGINT, sig_handler_int); oterm = sigset(SIGTERM, sig_handler_term); #endif /* Send the bytes. */ sender_with_signals(filenames, szfilenames); finished: /* Restore signal handlers */ #if DK4_HAVE_SIGACTION if (0 != s_f_i) { /* ERROR: Failed to install signal handlers */ log_1(18); exval = EXIT_FAILURE; } if (0 != sint) { if (0 != sigaction(SIGINT, &oint, NULL)) { s_f_r = 1; } } if (0 != sterm) { if (0 != sigaction(SIGTERM, &oterm, NULL)) { s_f_r = 1; } } #ifdef SIGPIPE if (0 != spipe) { if (0 != sigaction(SIGPIPE, &opipe, NULL)) { s_f_r = 1; } } #endif if (0 != s_f_r) { /* ERROR: Failed to restore signal handlers */ log_1(19); exval = EXIT_FAILURE; } #else if (NULL != oterm) { sigset(SIGTERM, oterm); } if (NULL != oint ) { sigset(SIGINT, oint ); } #ifdef SIGPIPE if (NULL != opipe) { sigset(SIGPIPE, opipe); } #endif #endif #line 1295 "rshdown.ctr" #line 1296 "rshdown.ctr" } /** Run service */ static void run_daemon_loop(void) { dk4_allowed_peer_t peer; /* Allowed remote address */ dk4_sockaddr_storage_t sa; /* Generic socket address */ fd_set rfds; /* Readable file descriptors */ dk4_socket_set_t *sset = NULL; /* Set of sockets to read data from */ struct sockaddr *soa = NULL; /* Minimum socket address */ struct sockaddr_in *so4 = NULL; /* IPv4 socket address */ #if DK4_HAVE_STRUCT_SOCKADDR_IN6 struct sockaddr_in6 *so6 = NULL; /* IPv6 socket address */ #endif size_t szsa = 0; /* Size of sa */ size_t i = 0; /* Traverse socket set */ dk4_socket_t smax = 0; /* Maximum socket fd number */ int cc = 1; /* Flag: Can continue */ int pused = 0; /* Flag: Peer used */ int res = 0; /* Operation result */ int ok = 0; /* Flag: Data packet matches file */ unsigned short frp = 0; /* Found remote port */ #line 1324 "rshdown.ctr" soa = (struct sockaddr *)(&sa); so4 = (struct sockaddr_in *)(&sa); #if DK4_HAVE_STRUCT_SOCKADDR_IN6 so6 = (struct sockaddr_in6 *)(&sa); #endif if (DK4_SOCKET_RESULT_SUCCESS == dk4socket_up(NULL)) { #line 1331 "rshdown.ctr" if (0 < strlen(asender)) { #line 1332 "rshdown.ctr" res = dk4socket_c8_get_allowed_peer(&peer, asender, NULL); if (DK4_SOCKET_RESULT_SUCCESS == res) { #line 1334 "rshdown.ctr" pused = 1; } else { #line 1336 "rshdown.ctr" cc = 0; /* SYSLOG ERROR: Invalid peer name */ syslog_3(29, 30, asender); } } if (1 == cc) { #line 1342 "rshdown.ctr" sset = dk4socket_set_udp_directly(lp, 0, 0, NULL); if (NULL != sset) { #line 1344 "rshdown.ctr" /* SYSLOG: Started */ #if DK4_HAVE_SYSLOG openlog(rshdown_kw[0], LOG_PID, syslogf); syslog(LOG_INFO, "%s", rshdown_kw[50]); closelog(); #endif do { if (0 != can_continue()) { FD_ZERO(&rfds); smax = -1; for (i = 0; i < sset->szUsed; i++) { #line 1356 "rshdown.ctr" FD_SET((sset->pSockets)[i],&rfds); if (smax < (sset->pSockets)[i]) { smax = (sset->pSockets)[i]; } } res = select((1+smax), &rfds, NULL, NULL, NULL); if (0 != can_continue()) { if (0 < res) { #line 1362 "rshdown.ctr" for (i = 0; ((1 == cc) && (i < sset->szUsed)); i++) { #line 1364 "rshdown.ctr" if (FD_ISSET((sset->pSockets)[i],&rfds)) { #line 1366 "rshdown.ctr" DK4_MEMRES(&sa, sizeof(sa)); szb2 = sizeof(b2); szsa = sizeof(sa); res = dk4socket_recvfrom( (sset->pSockets)[i], b2, &szb2, 0, (struct sockaddr *)(&sa), &szsa, 0L, 0L, NULL ); if (0 != can_continue()) { #line 1374 "rshdown.ctr" if (DK4_SOCKET_RESULT_SUCCESS == res) { #line 1375 "rshdown.ctr" if (0 < szb2) { #line 1376 "rshdown.ctr" ok = 1; if (0 != pused) { #line 1378 "rshdown.ctr" res = dk4socket_allowed_peer_compare(&peer, &sa, 1); if (0 != res) { #line 1380 "rshdown.ctr" ok = 0; /* SYSLOG DEBUG: Address mismatch */ syslog_debug(53, 54, &sa); } } if (0U != rp) { #line 1386 "rshdown.ctr" frp = 0; switch (soa->sa_family) { case AF_INET : { frp = dk4socket_ntohs(so4->sin_port); } break; #if DK4_HAVE_STRUCT_SOCKADDR_IN6 case AF_INET6 : { frp = dk4socket_ntohs(so6->sin6_port); } break; #endif } if (frp != rp) { #line 1398 "rshdown.ctr" ok = 0; /* SYSLOG DEBUG: Port mismatch */ syslog_debug(55, 56, &sa); } } if (0 != ok) { #line 1404 "rshdown.ctr" ok = 0; if (szb1 == szb2) { #line 1406 "rshdown.ctr" if (0 == DK4_MEMCMP(b1,b2,szb1)) { ok = 1; #line 1408 "rshdown.ctr" } else { #line 1409 "rshdown.ctr" /* SYSLOG DEBUG: Data mismatch */ syslog_debug(59, 60, &sa); } } else { #line 1413 "rshdown.ctr" /* SYSLOG DEBUG: Size mismatch */ syslog_debug(57, 58, &sa); } } if (0 != ok) { #line 1418 "rshdown.ctr" /* Shutdown */ /* SYSLOG: Initiating shutdown */ #if DK4_HAVE_SYSLOG openlog(rshdown_kw[0], LOG_PID, syslogf); syslog(LOG_INFO, "%s", rshdown_kw[51]); closelog(); #endif if (0 < strlen(cmd)) { #line 1426 "rshdown.ctr" if (0 != system(cmd)) { #if DK4_HAVE_SYSLOG openlog(rshdown_kw[0], LOG_PID, syslogf); syslog( LOG_ERR, "%s%s%s", rshdown_kw[61], cmd, rshdown_kw[62] ); closelog(); #endif } } else { #line 1438 "rshdown.ctr" if (0 < signo) { kill((pid_t)1, signo); } else { #ifdef SIGPWR kill((pid_t)1, SIGPWR); #else #ifdef SIGTERM kill((pid_t)1, SIGTERM); #else kill((pid_t)1, 15); #endif #endif } } cc = 0; } } else { #line 1455 "rshdown.ctr" } } else { #line 1457 "rshdown.ctr" } } else { #line 1459 "rshdown.ctr" cc = -1; } } else { #line 1462 "rshdown.ctr" } } } else { #line 1465 "rshdown.ctr" } } else { #line 1467 "rshdown.ctr" cc = -1; } } else { #line 1470 "rshdown.ctr" cc = -1; } } while (1 == cc); #line 1473 "rshdown.ctr" dk4socket_set_close(sset, NULL); /* SYSLOG: Finished */ #if DK4_HAVE_SYSLOG openlog(rshdown_kw[0], LOG_PID, syslogf); syslog(LOG_INFO, "%s", rshdown_kw[52]); closelog(); #endif } else { #line 1481 "rshdown.ctr" /* SYSLOG ERROR: Failed to create socket set */ syslog_1(26); } } else { #line 1485 "rshdown.ctr" } (void)dk4socket_down(NULL); } else { #line 1488 "rshdown.ctr" /* SYSLOG ERROR: Failed to bring socket subsystem up */ syslog_1(25); } #line 1492 "rshdown.ctr" } /** Set signal handlers and run service. */ static void run_daemon_with_signals(void) { #ifdef DK4_HAVE_SIGACTION #ifdef SIGPIPE struct sigaction opipe; struct sigaction npipe; #endif struct sigaction oint; struct sigaction nint; struct sigaction oterm; struct sigaction nterm; #else #ifdef SIGPIPE dk4_sig_handler_t *opipe = NULL; #endif dk4_sig_handler_t *oterm = NULL; dk4_sig_handler_t *oint = NULL; #endif #ifdef DK4_HAVE_SIGACTION #ifdef SIGPIPE int spipe = 0; #endif int sint = 0; int sterm = 0; int s_f_i = 0; int s_f_r = 0; #endif #line 1528 "rshdown.ctr" /* Set signal handlers */ #if DK4_HAVE_SIGACTION #ifdef SIGPIPE DK4_MEMRES(&npipe, sizeof(npipe)); npipe.sa_handler = sig_handler_pipe; npipe.sa_flags = 0; if (0 != sigemptyset(&npipe.sa_mask)) { s_f_i = 1; goto finished; } if (0 != sigaddset(&npipe.sa_mask, SIGPIPE)) { s_f_i = 1; goto finished; } if (0 != sigaction(SIGPIPE, &npipe, &opipe)) { s_f_i = 1; goto finished; } spipe = 1; #endif DK4_MEMRES(&nterm, sizeof(nterm)); nterm.sa_handler = sig_handler_term; nterm.sa_flags = 0; if (0 != sigemptyset(&nterm.sa_mask)) { s_f_i = 1; goto finished; } if (0 != sigaddset(&nterm.sa_mask, SIGTERM)) { s_f_i = 1; goto finished; } if (0 != sigaction(SIGTERM, &nterm, &oterm)) { s_f_i = 1; goto finished; } sterm = 1; DK4_MEMRES(&nint, sizeof(nint)); nint.sa_handler = sig_handler_int; nint.sa_flags = 0; if (0 != sigemptyset(&nint.sa_mask)) { s_f_i = 1; goto finished; } if (0 != sigaddset(&nint.sa_mask, SIGINT)) { s_f_i = 1; goto finished; } if (0 != sigaction(SIGINT, &nint, &oint)) { s_f_i = 1; goto finished; } sint = 1; #else #ifdef SIGPIPE opipe = sigset(SIGPIPE, sig_handler_pipe); #endif oint = sigset(SIGINT, sig_handler_int); oterm = sigset(SIGTERM, sig_handler_term); #endif run_daemon_loop(); finished: /* Restore signal handlers */ #if DK4_HAVE_SIGACTION if (0 != s_f_i) { /* ERROR: Failed to install signal handlers */ syslog_1(23); exval = EXIT_FAILURE; } if (0 != sint) { if (0 != sigaction(SIGINT, &oint, NULL)) { s_f_r = 1; } } if (0 != sterm) { if (0 != sigaction(SIGTERM, &oterm, NULL)) { s_f_r = 1; } } #ifdef SIGPIPE if (0 != spipe) { if (0 != sigaction(SIGPIPE, &opipe, NULL)) { s_f_r = 1; } } #endif if (0 != s_f_r) { /* ERROR: Failed to restore signal handlers */ syslog_1(24); exval = EXIT_FAILURE; } #else if (NULL != oterm) { sigset(SIGTERM, oterm); } if (NULL != oint ) { sigset(SIGINT, oint ); } #ifdef SIGPIPE if (NULL != opipe) { sigset(SIGPIPE, opipe); } #endif #endif #line 1631 "rshdown.ctr" } /** Retrieve port number from a configuration file line. @param dest Address of destination variable. @param pv String containing the port number. @param fn File name for diagnostics. @param lineno Line number for diagnostics. @param a0 Flag: Remote port, 0 allowed for arbitrary ports. @return 1 on success, 0 on error. */ static int set_port_number( unsigned short *dest, const char *pv, const char *fn, dk4_um_t lineno, int a0 ) { const char *ep = NULL; int back = 0; unsigned short us = 0U; if (0 != dk4ma_input_c8_dec_ushort(&us, pv, &ep, 1, NULL)) { if (0U != us) { *dest = us; back = 1; } else { if (0 != a0) { *dest = us; back = 1; } else { /* ERROR: Port number 0 not allowed! */ log_1(28); } } } else { /* ERROR: Not a 16 bit unsigned number! */ log_3(11, 12, pv); } return back; } /** Set the signal number. @param pv Text containing the number. @param fn File name for diagnostics. @param lineno Line number for diagnostics. @return 1 on success, 0 on error. */ static int set_signal_number(const char *pv, const char *fn, dk4_um_t lineno) { int back = 1; #line 1687 "rshdown.ctr" switch ( dk4str8_array_index(signal_names, pv, 0) ) { case 0 : case 1 : { #ifdef SIGHUP signo = SIGHUP; #else signo = 1; #endif } break; case 2 : case 3 : { #ifdef SIGINT signo = SIGINT; #else signo = 2; #endif } break; case 4 : case 5 : { #ifdef SIGQUIT signo = SIGQUIT; #else signo = 3; #endif } break; case 6 : case 7 : { #ifdef SIGILL signo = SIGILL; #else signo = 4; #endif } break; case 8 : case 9 : { #ifdef SIGTRAP signo = SIGTRAP; #else signo = 5; #endif } break; case 10 : case 11 : case 12 : case 13 : { #ifdef SIGABRT signo = SIGABRT; #else #ifdef SIGIOT signo = SIGIOT; #else signo = 6; #endif #endif } break; case 14 : case 15 : { #ifdef SIGBUS signo = SIGBUS; #else signo = 7; #endif } break; case 16 : case 17 : { #ifdef SIGFPE signo = SIGFPE; #else signo = 8; #endif } break; case 18 : case 19 : { #ifdef SIGKILL signo = SIGKILL; #else signo = 9; #endif } break; case 20 : case 21 : { #ifdef SIGUSR1 signo = SIGUSR1; #else signo = 10; #endif } break; case 22 : case 23 : { #ifdef SIGSEGV signo = SIGSEGV; #else signo = 11; #endif } break; case 24 : case 25 : { #ifdef SIGUSR2 signo = SIGUSR2; #else signo = 12; #endif } break; case 26 : case 27 : { #ifdef SIGPIPE signo = SIGPIPE; #else signo = 13; #endif } break; case 28 : case 29 : { #ifdef SIGALRM signo = SIGALRM; #else signo = 14; #endif } break; case 30 : case 31 : { #ifdef SIGTERM signo = SIGTERM; #else signo = 15; #endif } break; case 32 : case 33 : { #ifdef SIGSTKFLT signo = SIGSTKFLT; #else signo = 16; #endif } break; case 34 : case 35 : case 36 : case 37 : { #ifdef SIGCLD signo = SIGCLD; #else #ifdef SIGCHLD signo = SIGCHLD; #else signo = 17; #endif #endif } break; case 38 : case 39 : { #ifdef SIGCONT signo = SIGCONT; #else signo = 18; #endif } break; case 40 : case 41 : { #ifdef SIGSTOP signo = SIGSTOP; #else signo = 19; #endif } break; case 42 : case 43 : { #ifdef SIGTSTP signo = SIGTSTP; #else signo = 20; #endif } break; case 44 : case 45 : { #ifdef SIGTTIN signo = SIGTTIN; #else signo = 21; #endif } break; case 46 : case 47 : { #ifdef SIGTTOU signo = SIGTTOU; #else signo = 22; #endif } break; case 48 : case 49 : { #ifdef SIGURG signo = SIGURG; #else signo = 23; #endif } break; case 50 : case 51 : { #ifdef SIGXCPU signo = SIGXCPU; #else signo = 24; #endif } break; case 52 : case 53 : { #ifdef SIGXFSZ signo = SIGXFSZ; #else signo = 25; #endif } break; case 54 : case 55 : { #ifdef SIGVTALRM signo = SIGVTALRM; #else signo = 26; #endif } break; case 56 : case 57 : { #ifdef SIGPROF signo = SIGPROF; #else signo = 27; #endif } break; case 58 : case 59 : { #ifdef SIGWINCH signo = SIGWINCH; #else signo = 28; #endif } break; case 60 : case 61 : case 62 : case 63 : { #ifdef SIGPOLL signo = SIGPOLL; #else #ifdef SIGIO signo = SIGIO #else signo = 29; #endif #endif } break; case 64 : case 65 : { #ifdef SIGPWR signo = SIGPWR; #else signo = 30; #endif } break; case 66 : case 67 : { #ifdef SIGSYS signo = SIGSYS; #else signo = 31; #endif } break; default : { #line 1918 "rshdown.ctr" back = 0; /* ERROR: Illegal signal name */ log_3(31, 32, pv); } break; } #line 1923 "rshdown.ctr" return back; } /** Set syslog facility. @param pv Text representation of syslog facility. @return 1 on success, 0 on error. */ static int set_syslog_facility(const char *pv) { int back = 1; if (NULL != pv) { switch ( dk4str8_array_index(syslog_facility_names, pv, 0) ) { #ifdef LOG_AUTH case 0: { syslogf = LOG_AUTH; } break; #endif #ifdef LOG_AUTHPRIV case 1: { syslogf = LOG_AUTHPRIV; } break; #endif #ifdef LOG_CRON case 2: { syslogf = LOG_CRON; } break; #endif #ifdef LOG_DAEMON case 3: { syslogf = LOG_DAEMON; } break; #endif #ifdef LOG_FTP case 4: { syslogf = LOG_FTP; } break; #endif #ifdef LOG_KERN case 5: { syslogf = LOG_KERN; } break; #endif #ifdef LOG_LPR case 6: { syslogf = LOG_LPR; } break; #endif #ifdef LOG_MAIL case 7: { syslogf = LOG_MAIL; } break; #endif #ifdef LOG_NEWS case 8: { syslogf = LOG_NEWS; } break; #endif #ifdef LOG_AUTH case 9: { syslogf = LOG_AUTH; } break; #endif #ifdef LOG_SYSLOG case 10: { syslogf = LOG_SYSLOG; } break; #endif #ifdef LOG_USER case 11: { syslogf = LOG_USER; } break; #endif #ifdef LOG_UUCP case 12: { syslogf = LOG_UUCP; } break; #endif #ifdef LOG_LOCAL0 case 13: { syslogf = LOG_LOCAL0; } break; #endif #ifdef LOG_LOCAL1 case 14: { syslogf = LOG_LOCAL1; } break; #endif #ifdef LOG_LOCAL2 case 15: { syslogf = LOG_LOCAL2; } break; #endif #ifdef LOG_LOCAL3 case 16: { syslogf = LOG_LOCAL3; } break; #endif #ifdef LOG_LOCAL4 case 17: { syslogf = LOG_LOCAL4; } break; #endif #ifdef LOG_LOCAL5 case 18: { syslogf = LOG_LOCAL5; } break; #endif #ifdef LOG_LOCAL6 case 19: { syslogf = LOG_LOCAL6; } break; #endif #ifdef LOG_LOCAL7 case 20: { syslogf = LOG_LOCAL7; } break; #endif default: { back = 0; log_3(48, 49, pv); } break; } } return back; } /** Read configuration file. @return 1 on success, 0 on error. */ static int read_config_file(void) { FILE *fipo = NULL; /* Input file to process */ const char *fn = NULL; /* Input file name */ const char *ep = NULL; /* End pointer after number */ char *pk = NULL; /* Pointer to key string */ char *pv = NULL; /* Pointer to value string */ dk4_um_t lineno = (dk4_um_t)0UL; /* Current line number */ int back = 0; #line 2028 "rshdown.ctr" if (0 != options[0].found) { fn = options[0].val.t; } if (NULL == fn) { fn = def_conf_name; } fipo = dk4fopen_c8(fn, "r", DK4_FOPEN_SC_IS_REGULAR, NULL); if (NULL != fipo) { back = 1; while( fgets(b1, sizeof(b1), fipo) ) { lineno++; pk = dk4str8_start(b1, NULL); if (NULL != pk) { if ('#' != *pk) { pv = dk4str8_chr(pk, '='); if (NULL != pv) { *(pv++) = '\0'; pv = dk4str8_start(pv, NULL); if (NULL != pv) { dk4str8_normalize(pk, NULL); dk4str8_delnl(pv); switch ( dk4str8_array_index(key_names, pk, 0) ) { case 0: { /* sender address */ if (0 == strlen(asender)) { dk4str8_normalize(pv, NULL); if (0 == dk4str8_cpy_s(asender,sizeof(asender),pv,NULL)) { back = 0; #line 2051 "rshdown.ctr" /* ERROR: Sender name too long */ log_3(33, 34, pv); } } else { #line 2055 "rshdown.ctr" back = 0; /* ERROR: Redefinition of sender */ log_1(35); } } break; case 1: { /* sender port */ if (0 == set_port_number(&rp, pv, fn, lineno, 1)) { back = 0; #line 2063 "rshdown.ctr" } } break; case 2: { /* local port */ if (0 == set_port_number(&lp, pv, fn, lineno, 0)) { back = 0; #line 2068 "rshdown.ctr" } } break; case 3: { /* signal */ ep = NULL; if (0 != dk4ma_input_c8_dec_int(&signo, pv, &ep, 1, NULL)) { if (1 > signo) { back = 0; #line 2075 "rshdown.ctr" /* ERROR: Signal number must be positive */ log_1(36); } } else { dk4str8_normalize(pv, NULL); if (0 == set_signal_number(pv, fn, lineno)) { back = 0; #line 2082 "rshdown.ctr" } } } break; case 4: { /* command */ if (0 == strlen(cmd)) { if (0 == dk4str8_cpy_s(cmd, sizeof(cmd), pv, NULL)) { back = 0; /* ERROR: Command too long! */ log_3(37, 38, pv); } } else { #line 2093 "rshdown.ctr" back = 0; /* ERROR: Redefinition of command */ log_1(39); } } break; case 5: { /* file */ if (0 == strlen(file_name)) { if (0 == dk4str8_cpy_s(file_name,sizeof(file_name),pv,NULL)) { back = 0; /* ERROR: File name too long! */ log_3(40, 41, pv); } } else { #line 2107 "rshdown.ctr" back = 0; /* ERROR: Redefinition of file name */ log_1(42); } } break; case 6: { debug = ((dk4str8_is_on(pv)) ? 1 : 0); } break; case 7: { dk4str8_normalize(pv, NULL); if (0 == set_syslog_facility(pv)) { back = 0; } } break; default : { #line 2122 "rshdown.ctr" log_1(43); } break; } } else { #line 2126 "rshdown.ctr" back = 0; /* ERROR: Missing value */ log_1(44); } } else { #line 2131 "rshdown.ctr" back = 0; /* ERROR: Missing value */ log_1(44); } } } } fclose(fipo); if ((0 != back) && (0U == lp)) { back = 0; #line 2141 "rshdown.ctr" /* ERROR: Local port not specified */ log_1(45); } if (0 != back) { if ((0 == signo) && (0 == strlen(cmd))) { back = 0; #line 2147 "rshdown.ctr" /* ERROR: Signal or command required */ log_1(46); } } if (0 != back) { if (0 != strlen(file_name)) { fipo = dk4fopen_c8(file_name, "rb", DK4_FOPEN_SC_IS_REGULAR, NULL); if (NULL != fipo) { szb1 = fread(b1, 1, sizeof(b1), fipo); fclose(fipo); if (0 == szb1) { back = 0; #line 2159 "rshdown.ctr" /* ERROR: Failed to read data from file */ log_3(16, 17, file_name); } } else { #line 2163 "rshdown.ctr" back = 0; /* ERROR: Failed to open data file */ log_3(14, 15, file_name); } } else { #line 2168 "rshdown.ctr" back = 0; /* ERROR: No data file specified */ log_1(47); } } } else { #line 2174 "rshdown.ctr" } #line 2175 "rshdown.ctr" return back; } /** Daemon waiting for shutdown data packet. */ static void run_as_daemon(void) { pid_t cpid; #line 2188 "rshdown.ctr" /* Preparations before we start. */ DK4_MEMRES(cmd, sizeof(cmd)); DK4_MEMRES(asender, sizeof(asender)); DK4_MEMRES(file_name, sizeof(file_name)); if (read_config_file()) { #line 2194 "rshdown.ctr" if (0 != dk4dmt_parent_before_fork(rshdown_kw[0],pid_file_name,1,syslogf)) { cpid = fork(); if ((pid_t)0 == cpid) { /* in the child */ if (0 != dk4dmt_intermediate_before_fork(rshdown_kw[0], syslogf)) { cpid = fork(); if ((pid_t)0 == cpid) { /* in the child */ #line 2201 "rshdown.ctr" #line 2202 "rshdown.ctr" exval = EXIT_SUCCESS; if (dk4dmt_daemon_after_fork(rshdown_kw[0],pid_file_name,syslogf)) { run_daemon_with_signals(); } dk4dmt_daemon_end(rshdown_kw[0], pid_file_name, syslogf); if (0 == dk4mem_reset_secure(b1, sizeof(b1), NULL)) { exval = EXIT_FAILURE; } if (0 == dk4mem_reset_secure(b2, sizeof(b2), NULL)) { exval = EXIT_FAILURE; } #line 2214 "rshdown.ctr" #line 2215 "rshdown.ctr" } else { if ((pid_t)(-1) != cpid) { /* intermediate process */ exval = EXIT_SUCCESS; if (0 == dk4mem_reset_secure(b1, sizeof(b1), NULL)) { exval = EXIT_FAILURE; } if (0 == dk4mem_reset_secure(b2, sizeof(b2), NULL)) { exval = EXIT_FAILURE; } } else { /* error */ if (0 == dk4mem_reset_secure(b1, sizeof(b1), NULL)) { exval = EXIT_FAILURE; } if (0 == dk4mem_reset_secure(b2, sizeof(b2), NULL)) { exval = EXIT_FAILURE; } /* SYSLOG ERROR: Failed to create child process */ syslog_1(22); } } } else { if (0 == dk4mem_reset_secure(b1, sizeof(b1), NULL)) { exval = EXIT_FAILURE; } if (0 == dk4mem_reset_secure(b2, sizeof(b2), NULL)) { exval = EXIT_FAILURE; } /* SYSLOG ERROR: Failed to detach */ syslog_1(21); } } else { if ((pid_t)(-1) != cpid) { /* parent */ exval = EXIT_SUCCESS; } else { /* error */ /* ERROR: Failed to create child process */ log_1(20); } } } } if (0 == dk4mem_reset_secure(b1, sizeof(b1), NULL)) { exval = EXIT_FAILURE; } if (0 == dk4mem_reset_secure(b2, sizeof(b2), NULL)) { exval = EXIT_FAILURE; } #line 2262 "rshdown.ctr" } /** Show a text paragraph on standard output. @param txt Text to show. */ static void show_text(const char * const *txt) { if (NULL != txt) { while (NULL != *txt) { fputs(*(txt++), stdout); fputc('\n', stdout); } fflush(stdout); } } /** Handle --help, --version, --license options. */ static void run_hvl(void) { if (0 != (1 & hvl)) { show_text(help_text); } if (0 != (2 & hvl)) { fputs(version_text, stdout); fputc('\n', stdout); fflush(stdout); } if (0 != (4 & hvl)) { show_text(license_text); } } /** Program entry point. @param argc @param argv @return 0 on success, any other value indicates an error. */ int main(int argc, char *argv[]) { char *filenames[32]; size_t szfilenames = 32; /* Array size */ int res = 0; /* Operation result */ #line 2318 "rshdown.ctr" /* Process command line arguments. */ res = dk4opt_process_argv( options, szoptions, argc, argv, filenames, &szfilenames, 1, 1, NULL ); if (0 == res) { #line 2325 "rshdown.ctr" goto finished; } /* Check help, version, license. */ if (0 != options[5].found) { hvl |= 1; } if (0 != options[6].found) { hvl |= 2; } if (0 != options[7].found) { hvl |= 4; } if (0 != hvl) { run_hvl(); goto finished; } /* Either send data or run as daemon to receive data. */ if (0 != options[1].found) { #line 2341 "rshdown.ctr" sender((const char * const *)filenames, szfilenames); } else { #line 2343 "rshdown.ctr" run_as_daemon(); } finished: #line 2348 "rshdown.ctr" exit(exval); return exval; } #else /** Program entry point. @param argc @param argv @return 0 on success, any other value indicates an error. */ int main(int argc, char *argv[]) { fputs("rshdown: ERROR: Build requirements violation!\n", stderr); #if DK4_CHAR_SIZE > 1 fputs("Default character size is larger than 1!\n", stderr); #endif #if !((DK4_HAVE_SIGACTION) || (DK4_HAVE_SIGSET)) fputs("Neither sigaction() nor sigset() are available!\n", stderr); #endif #if !((DK4_HAVE_SETSID) || (DK4_HAVE_SETPGRP)) fputs("Neither setsid() nor setpgrp() are available!\n", stderr); #endif fflush(stderr); exit(EXIT_FAILURE); return EXIT_FAILURE; } #endif