/* Copyright (C) 2016-2020, Dirk Krause SPDX-License-Identifier: BSD-3-Clause */ /* WARNING: This file was generated by the dkct program (see http://dktools.sourceforge.net/ for details). 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 */ /** @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 #if DK4_ON_WINDOWS #ifndef _USE_MATH_DEFINES #define _USE_MATH_DEFINES 1 #endif #endif #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 #if DK4_HAVE_SYSEXITS_H #ifndef SYSEXITS_H_INCLUDED #include #define SYSEXITS_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" #include "dk4unused.h" #line 144 "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 247 "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://sourceforge.net/p/dktools/wiki/Home/", "\t\tfor 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:", "", "1. Redistributions of source code must retain the above copyright notice,", " this list of conditions and the following disclaimer.", "2. 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.", "3. Neither the name of the copyright holder nor the names of its", " 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 HOLDER 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 294 "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_SYSTEMD_RUN "/rshdown/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 357 "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 467 "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 497 "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 703 "rshdown.ctr" }; /** Information for daemon tool functions. */ static dk4dmt_t dmt; /** 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 DK4_ARG_UNUSED(signo) ) { DK4_UNUSED_ARG(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 DK4_ARG_UNUSED(signo) ) { DK4_UNUSED_ARG(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 DK4_ARG_UNUSED(signo) ) { DK4_UNUSED_ARG(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 1016 "rshdown.ctr" if (DK4_SOCKET_RESULT_SUCCESS == dk4socket_up(NULL)) { if (options[2].found) { ip4 = 1; } #line 1018 "rshdown.ctr" res = dk4socket_c8_udp_addresses_numeric(array, hn, rp, lp, ip4, NULL); if (DK4_SOCKET_RESULT_SUCCESS == res) { #line 1020 "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 1027 "rshdown.ctr" exval = EXIT_SUCCESS; (void)dk4socket_option_set_reuse(sock, 1, NULL); if (options[2].found) { #line 1030 "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 1035 "rshdown.ctr" } } res = dk4socket_bind( sock, (struct sockaddr *)(&(array[1])), szl, NULL ); if (DK4_SOCKET_RESULT_SUCCESS == res) { #line 1041 "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 1045 "rshdown.ctr" res = dk4socket_sendto( sock, b1, &lgt, 0, (struct sockaddr *)(&(array[0])), szr, 0L, 0L, NULL ); if (DK4_SOCKET_RESULT_SUCCESS == res) { #line 1051 "rshdown.ctr" if (lgt != sz) { exval = EXIT_FAILURE; } } else { #line 1053 "rshdown.ctr" exval = EXIT_FAILURE; } } } else { #line 1057 "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 1070 "rshdown.ctr" /* ERROR: Failed to open socket */ log_1(6); } } else { #line 1074 "rshdown.ctr" if (0 == szr) { #line 1075 "rshdown.ctr" log_3(7, 8, hn); } if (0 == szl) { #line 1078 "rshdown.ctr" log_3(7, 8, hn); } if (AF_UNSPEC == af) { #line 1081 "rshdown.ctr" log_3(7, 8, hn); } if (PF_UNSPEC == pf) { #line 1084 "rshdown.ctr" log_3(7, 8, hn); } } } else { #line 1088 "rshdown.ctr" /* ERROR: Failed to obtain addresses */ log_3(7, 8, hn); } (void)dk4socket_down(NULL); } else { #line 1093 "rshdown.ctr" /* ERROR: Failed to bring socket subsystem up */ log_1(9); } #line 1097 "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 1115 "rshdown.ctr" if (3 == szfilenames) { #line 1116 "rshdown.ctr" res = dk4ma_input_c8_dec_ushort(&rp, filenames[1], &ep, 1, NULL); if (0 != res) { #line 1118 "rshdown.ctr" if (0 != rp) { #line 1119 "rshdown.ctr" lp = rp; if (0 != options[4].found) { #line 1121 "rshdown.ctr" if ((dk4_um_t)0UL < options[4].val.u) { #line 1122 "rshdown.ctr" if ((dk4_um_t)(USHRT_MAX) >= options[4].val.u) { lp = (unsigned short)(options[4].val.u); #line 1124 "rshdown.ctr" } else { #line 1125 "rshdown.ctr" lp = 0; /* ERROR: Local port number exceeds 16 bit unsigned range */ log_1(27); } } else { #line 1130 "rshdown.ctr" lp = 0; /* ERROR: Local port number 0 is not allowed */ log_1(28); } } if (0 != lp) { #line 1136 "rshdown.ctr" fipo = dk4fopen_c8(filenames[2], "rb", DK4_FOPEN_SC_IS_REGULAR, NULL); if (NULL != fipo) { #line 1138 "rshdown.ctr" lgt = fread(b1, 1, sizeof(b1), fipo); fclose(fipo); if (0 < lgt) { #line 1141 "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 1146 "rshdown.ctr" } } else { #line 1148 "rshdown.ctr" /* ERROR: No data read from file */ log_3(16, 17, filenames[2]); } } else { #line 1152 "rshdown.ctr" /* ERROR: Failed to open data file */ log_3(14, 15, filenames[2]); } } else { #line 1156 "rshdown.ctr" } } else { #line 1158 "rshdown.ctr" /* ERROR: Remote port number 0 is not allowed */ log_1(13); } } else { #line 1162 "rshdown.ctr" /* ERROR: Not a 16 bit unsigned number */ log_3(11, 12, filenames[1]); } } else { #line 1166 "rshdown.ctr" /* ERROR: Three arguments required - host, port and file */ log_1(10); } #line 1170 "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 1184 "rshdown.ctr" #line 1185 "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 1316 "rshdown.ctr" #line 1317 "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 1345 "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 1352 "rshdown.ctr" if (0 < strlen(asender)) { #line 1353 "rshdown.ctr" res = dk4socket_c8_get_allowed_peer(&peer, asender, NULL); if (DK4_SOCKET_RESULT_SUCCESS == res) { #line 1355 "rshdown.ctr" pused = 1; } else { #line 1357 "rshdown.ctr" cc = 0; /* SYSLOG ERROR: Invalid peer name */ syslog_3(29, 30, asender); } } if (1 == cc) { #line 1363 "rshdown.ctr" sset = dk4socket_set_udp_directly(lp, 0, 0, NULL); if (NULL != sset) { #line 1365 "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 1377 "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 1383 "rshdown.ctr" for (i = 0; ((1 == cc) && (i < sset->szUsed)); i++) { #line 1385 "rshdown.ctr" if (FD_ISSET((sset->pSockets)[i],&rfds)) { #line 1387 "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 1395 "rshdown.ctr" if (DK4_SOCKET_RESULT_SUCCESS == res) { #line 1396 "rshdown.ctr" if (0 < szb2) { #line 1397 "rshdown.ctr" ok = 1; if (0 != pused) { #line 1399 "rshdown.ctr" res = dk4socket_allowed_peer_compare(&peer, &sa, 1); if (0 != res) { #line 1401 "rshdown.ctr" ok = 0; /* SYSLOG DEBUG: Address mismatch */ syslog_debug(53, 54, &sa); } } if (0U != rp) { #line 1407 "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 1419 "rshdown.ctr" ok = 0; /* SYSLOG DEBUG: Port mismatch */ syslog_debug(55, 56, &sa); } } if (0 != ok) { #line 1425 "rshdown.ctr" ok = 0; if (szb1 == szb2) { #line 1427 "rshdown.ctr" if (0 == DK4_MEMCMP(b1,b2,szb1)) { ok = 1; #line 1429 "rshdown.ctr" } else { #line 1430 "rshdown.ctr" /* SYSLOG DEBUG: Data mismatch */ syslog_debug(59, 60, &sa); } } else { #line 1434 "rshdown.ctr" /* SYSLOG DEBUG: Size mismatch */ syslog_debug(57, 58, &sa); } } if (0 != ok) { #line 1439 "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 1447 "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 1459 "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 1476 "rshdown.ctr" } } else { #line 1478 "rshdown.ctr" } } else { #line 1480 "rshdown.ctr" cc = -1; } } else { #line 1483 "rshdown.ctr" } } } else { #line 1486 "rshdown.ctr" } } else { #line 1488 "rshdown.ctr" cc = -1; } } else { #line 1491 "rshdown.ctr" cc = -1; } } while (1 == cc); #line 1494 "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 1502 "rshdown.ctr" /* SYSLOG ERROR: Failed to create socket set */ syslog_1(26); } } else { #line 1506 "rshdown.ctr" } (void)dk4socket_down(NULL); } else { #line 1509 "rshdown.ctr" /* SYSLOG ERROR: Failed to bring socket subsystem up */ syslog_1(25); } #line 1513 "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 1549 "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); dk4dmt_error_sysfct(&dmt); } 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); dk4dmt_error_sysfct(&dmt); } #else if (NULL != oterm) { sigset(SIGTERM, oterm); } if (NULL != oint ) { sigset(SIGINT, oint ); } #ifdef SIGPIPE if (NULL != opipe) { sigset(SIGPIPE, opipe); } #endif #endif #line 1652 "rshdown.ctr" } /** Retrieve port number from a configuration file line. @param dest Address of destination variable. @param pv String containing the port number. @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, 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. @return 1 on success, 0 on error. */ static int set_signal_number(const char *pv) { int back = 1; #line 1706 "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 1937 "rshdown.ctr" back = 0; /* ERROR: Illegal signal name */ log_3(31, 32, pv); } break; } #line 1942 "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 2047 "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 2070 "rshdown.ctr" /* ERROR: Sender name too long */ log_3(33, 34, pv); } } else { #line 2074 "rshdown.ctr" back = 0; /* ERROR: Redefinition of sender */ log_1(35); } } break; case 1: { /* sender port */ if (0 == set_port_number(&rp, pv, 1)) { back = 0; #line 2082 "rshdown.ctr" } } break; case 2: { /* local port */ if (0 == set_port_number(&lp, pv, 0)) { back = 0; #line 2087 "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 2094 "rshdown.ctr" /* ERROR: Signal number must be positive */ log_1(36); } } else { dk4str8_normalize(pv, NULL); if (0 == set_signal_number(pv)) { back = 0; #line 2101 "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 2112 "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 2126 "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 2141 "rshdown.ctr" log_1(43); } break; } } else { #line 2145 "rshdown.ctr" back = 0; /* ERROR: Missing value */ log_1(44); } } else { #line 2150 "rshdown.ctr" back = 0; /* ERROR: Missing value */ log_1(44); } } } } fclose(fipo); if ((0 != back) && (0U == lp)) { back = 0; #line 2160 "rshdown.ctr" /* ERROR: Local port not specified */ log_1(45); } if (0 != back) { if ((0 == signo) && (0 == strlen(cmd))) { back = 0; #line 2166 "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 2178 "rshdown.ctr" /* ERROR: Failed to read data from file */ log_3(16, 17, file_name); } } else { #line 2182 "rshdown.ctr" back = 0; /* ERROR: Failed to open data file */ log_3(14, 15, file_name); } } else { #line 2187 "rshdown.ctr" back = 0; /* ERROR: No data file specified */ log_1(47); } } } else { #line 2193 "rshdown.ctr" } #line 2194 "rshdown.ctr" return back; } /** Daemon waiting for shutdown data packet. */ static void run_as_daemon(void) { pid_t cpid; dk4dmt_init(&dmt); #line 2208 "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 2214 "rshdown.ctr" dk4dmt_set_program(&dmt, rshdown_kw[0]); dk4dmt_set_pidfile(&dmt, pid_file_name); dk4dmt_set_syslog_feature(&dmt, syslogf); if (0 != dk4dmt_parent_before_fork(&dmt)) { cpid = fork(); if ((pid_t)0 == cpid) { /* in the child */ if (0 != dk4dmt_intermediate_before_fork(&dmt)) { cpid = fork(); if ((pid_t)0 == cpid) { /* in the child */ #line 2224 "rshdown.ctr" #line 2225 "rshdown.ctr" dk4dmt_success(&dmt); if (0 != dk4dmt_daemon_start(&dmt)) { run_daemon_with_signals(); } dk4dmt_daemon_end(&dmt); if (0 == dk4mem_reset_secure(b1, sizeof(b1), NULL)) { dk4dmt_error_sysfct(&dmt); } if (0 == dk4mem_reset_secure(b2, sizeof(b2), NULL)) { dk4dmt_error_sysfct(&dmt); } #line 2237 "rshdown.ctr" #line 2238 "rshdown.ctr" } else { if ((pid_t)(-1) != cpid) { /* intermediate process */ dk4dmt_success(&dmt); if (0 == dk4mem_reset_secure(b1, sizeof(b1), NULL)) { dk4dmt_error_sysfct(&dmt); } if (0 == dk4mem_reset_secure(b2, sizeof(b2), NULL)) { dk4dmt_error_sysfct(&dmt); } dk4dmt_intermediate_after_fork(&dmt); } else { /* error */ if (0 == dk4mem_reset_secure(b1, sizeof(b1), NULL)) { dk4dmt_error_sysfct(&dmt); } if (0 == dk4mem_reset_secure(b2, sizeof(b2), NULL)) { dk4dmt_error_sysfct(&dmt); } /* SYSLOG ERROR: Failed to create child process */ syslog_1(22); dk4dmt_intermediate_fork_failed(&dmt); } } } else { if (0 == dk4mem_reset_secure(b1, sizeof(b1), NULL)) { dk4dmt_error_sysfct(&dmt); } if (0 == dk4mem_reset_secure(b2, sizeof(b2), NULL)) { dk4dmt_error_sysfct(&dmt); } /* SYSLOG ERROR: Failed to detach */ syslog_1(21); } } else { if ((pid_t)(-1) != cpid) { /* parent */ dk4dmt_parent_after_fork(&dmt); } else { /* error */ /* ERROR: Failed to create child process */ dk4dmt_parent_fork_failed(&dmt); log_1(20); } } } } else { dk4dmt_error_config(&dmt); } if (0 == dk4mem_reset_secure(b1, sizeof(b1), NULL)) { dk4dmt_error_sysfct(&dmt); } if (0 == dk4mem_reset_secure(b2, sizeof(b2), NULL)) { dk4dmt_error_sysfct(&dmt); } exval = dk4dmt_get_exit_status(&dmt); #line 2292 "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 2348 "rshdown.ctr" /* Process command line arguments. */ res = dk4opt_process_argv( options, szoptions, argc, argv, filenames, &szfilenames, 1, 1, NULL ); if (0 == res) { #line 2354 "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 2370 "rshdown.ctr" sender((const char * const *)filenames, szfilenames); } else { #line 2372 "rshdown.ctr" run_as_daemon(); } finished: #line 2377 "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