1 /*
2 Copyright (C) 2008-2021, Dirk Krause
3 SPDX-License-Identifier: BSD-3-Clause
4 */
5
6 /*
7 WARNING: This file was generated by the dkct program (see
8 http://dktools.sourceforge.net/ for details).
9 Changes you make here will be lost if dkct is run again!
10 You should modify the original source and run dkct on it.
11 Original source: rshdown.ctr
12 */
13
14 /** @file rshdown.c The rshdown module.
15 */
16
17
18 /*
19 Copyright (c) 2008-2020, Dirk Krause
20 All rights reserved.
21
22 Redistribution and use in source and binary forms, with or without
23 modification, are permitted provided that the following conditions are met:
24
25 1. Redistributions of source code must retain the above copyright notice,
26 this list of conditions and the following disclaimer.
27 2. Redistributions in binary form must reproduce the above copyright
28 notice, this list of conditions and the following disclaimer in the
29 documentation and/or other materials provided with the distribution.
30 3. Neither the name of the copyright holder nor the names of its
31 contributors may be used to endorse or promote products derived from
32 this software without specific prior written permission.
33
34 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
35 ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
36 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
37 A PARTICULAR PURPOSE ARE DISCLAIMED.
38 IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
39 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
40 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
41 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
42 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
43 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
44 OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
45 SUCH DAMAGE.
46 */
47
48 #include "dk4conf.h"
49
50 #if DK4_ON_WINDOWS
51
52 /*
53 Windows service on Windows systems
54 ==================================
55 */
56
57 #include "rshdown.h"
58
59 #include <windows.h>
60 #include <winbase.h>
61 #include <process.h>
62 #include <stdio.h>
63 #include <stddef.h>
64 #include <stdlib.h>
65 #include <conio.h>
66
67 #include "rshdownm.h"
68
69
70
71
72
73
74 /** Typedef necessary for sizeof() operator.
75 */
76 typedef struct sockaddr_in SOIN;
77
78 /** Size of Internet socket address.
79 */
80 #define SZ_SOIN (sizeof(SOIN))
81
82
83
84 /** Service name.
85 */
86 static WCHAR service_name[] = { L"RshDown" };
87
88
89
90 /** Text constants used by program.
91 */
92 static WCHAR *n[] = {
93 /* 0 */ L"sender", /* sender of the packet */
94 /* 1 */ L"file", /* file to compare data packet */
95 /* 2 */ L"port", /* local port to listen */
96 /* 3 */ L"Software\\RshDown", /* registry key */
97 /* 4 */ L"SeShutdownPrivilege", /* shutdown privilege
98 / 5 */ L"Power supply failure!", /* message for shutdown */
99 NULL
100 };
101
102
103
104 /** Service status.
105 */
106 SERVICE_STATUS st;
107
108
109 /** Service status handle.
110 */
111 SERVICE_STATUS_HANDLE hSt;
112
113
114
115 /** Event: Service must stop.
116 */
117 static volatile HANDLE hEventMustStop = NULL;
118
119
120
121 /** Event: Service did stop.
122 */
123 static volatile HANDLE hEventDidStop = NULL;
124
125
126
127 /** Buffer for datagram from file (local copy of shared secret).
128 */
129 static char filebuffer[RSHDOWN_DATA_BUFFER_SIZE];
130
131
132
133 /** Buffer for datagram from network.
134 */
135 static char netbuffer[RSHDOWN_DATA_BUFFER_SIZE];
136
137
138
139 /** Number of bytes used in file buffer.
140 */
141 static size_t u_filebuffer = 0;
142
143
144
145 /** Log one syslog event.
146 @param t Message type.
147 @param e Event ID.
148 @param s1 Additional string 1.
149 @param s2 Additional string 2
150 */
151 static
152 void
log_event(WORD t,DWORD e,WCHAR * s1,WCHAR * s2)153 log_event(WORD t, DWORD e, WCHAR *s1, WCHAR *s2)
154 {
155 HANDLE hEventLog;
156 WCHAR *msgs[16];
157 int i;
158 hEventLog = RegisterEventSourceW(NULL, service_name);
159 if(hEventLog != NULL) {
160 for(i = 0; i < 16; i++) msgs[i] = NULL;
161 i = 0;
162 if(s1) {
163 msgs[0] = s1; i = 1;
164 if(s2) {
165 msgs[1] = s2; i = 2;
166 }
167 }
168 ReportEventW(
169 hEventLog, /* hEventLog */
170 t, /* wType */
171 CAT_RSHDOWN, /* wCategoy */
172 e, /* dwEventID */
173 NULL, /* lpUserSid */
174 (WORD)i, /* wNumStrings */
175 (DWORD)0, /* dwDataSize */
176 ((i > 0) ? msgs : NULL), /* lpStrings */
177 NULL /* lpRawData */
178 );
179 DeregisterEventSource(hEventLog);
180 }
181 }
182
183
184
185 /** Callback function for service events.
186 @param ctrl_code Event code.
187 */
188 VOID
189 CALLBACK
service_ctrl_handler(IN DWORD ctrl_code)190 service_ctrl_handler(IN DWORD ctrl_code)
191 {
192 int i;
193 DWORD res;
194 int success = 0;
195
196 st.dwWaitHint = 0; st.dwCheckPoint = 0;
197 switch(ctrl_code) {
198 case SERVICE_CONTROL_SHUTDOWN:
199 case SERVICE_CONTROL_STOP:
200 {
201 st.dwCurrentState = SERVICE_STOP_PENDING;
202 st.dwWaitHint = RSHDOWN_STOP_WAIT_HINT;
203 if((hEventMustStop != NULL) && (hEventDidStop != NULL)) {
204 SetEvent(hEventMustStop);
205 for(i = 0; i < RSHDOWN_MAX_ATTEMPTS_TO_STOP; i++) {
206 res =
207 WaitForSingleObjectEx(hEventDidStop, RSHDOWN_STOP_SLEEP_TIME, FALSE);
208 switch(res) {
209 case WAIT_OBJECT_0: {
210 i = RSHDOWN_MAX_ATTEMPTS_TO_STOP;
211 success = 1;
212 } break;
213 default: {
214 SetServiceStatus(hSt, &st);
215 st.dwCheckPoint++;
216 } break;
217 }
218 }
219 if(!success) {
220 log_event(EVENTLOG_ERROR_TYPE,MSG_BG_THREAD_NOT_RESPONDING,NULL,NULL);
221 }
222 } else {
223 log_event(EVENTLOG_ERROR_TYPE,MSG_ALREADY_STOPPED,NULL,NULL);
224 }
225 st.dwCurrentState = SERVICE_STOPPED;
226 st.dwWaitHint = 0;
227 CloseHandle(hEventMustStop); hEventMustStop = 0;
228 CloseHandle(hEventDidStop); hEventDidStop = 0;
229 } break;
230 }
231 SetServiceStatus(hSt, &st);
232 }
233
234
235
236 /** Initialize Internet socket address.
237 @param s Internet socket address.
238 */
239 static
240 void
initializeSOIN(SOIN * s)241 initializeSOIN(SOIN *s)
242 {
243 memset((void *)s, 0, SZ_SOIN);
244 s->sin_family = AF_INET;
245 s->sin_addr.s_addr = htonl(INADDR_ANY);
246 s->sin_port = htons(0);
247 }
248
249
250
251 /** Get string from registry.
252 @param b Result buffer.
253 @param sz Size of \a b in WCHAR.
254 @param hk Registry key.
255 @param k Entry name (key).
256 @return TRUE on success, FALSE on error.
257 */
258 static
259 BOOL
regWstring(WCHAR * b,size_t sz,HKEY hk,WCHAR * k)260 regWstring(WCHAR *b, size_t /* WCHAR */ sz, HKEY hk, WCHAR *k)
261 {
262 BOOL back = FALSE;
263 LONG res;
264 DWORD dwType;
265 DWORD dwSz;
266 dwType = REG_SZ; dwSz = (DWORD)(sz * sizeof(WCHAR));
267 res = RegQueryValueExW(hk, k, NULL, &dwType, (LPBYTE)b, &dwSz);
268 if(res == ERROR_SUCCESS) {
269 if(dwType == REG_SZ) {
270 if(dwSz > 0) {
271 back = TRUE;
272 dwSz = dwSz / sizeof(WCHAR);
273 b[(dwSz < sz) ? dwSz : (sz - 1)] = L'\0';
274 }
275 }
276 }
277 return back;
278 }
279
280
281
282 /** Convert dotted decimal notation to IP address.
283 @param hn Host name (IP address in dotted decimal notation).
284 @return IP4 address in _host_ byte order on success, 0UL on error.
285 */
286 static
287 unsigned long
dotted_string_to_ip(char * hn)288 dotted_string_to_ip (char *hn)
289 {
290 unsigned long back = 0UL;
291 unsigned long u1, u2, u3, u4, u;
292 int ende, state; char *ptr;
293
294 if(hn) {
295 state = 0;
296 u = u1 = u2 = u3 = u4 = 0UL;
297 ptr = hn; ende = 0;
298 while(!ende) {
299 if(*ptr) {
300 if(isascii((unsigned char)(*ptr)) && isdigit((unsigned char)(*ptr))) {
301 u = 0UL;
302 switch(*ptr) {
303 case '0': u = 0UL; break;
304 case '1': u = 1UL; break;
305 case '2': u = 2UL; break;
306 case '3': u = 3UL; break;
307 case '4': u = 4UL; break;
308 case '5': u = 5UL; break;
309 case '6': u = 6UL; break;
310 case '7': u = 7UL; break;
311 case '8': u = 8UL; break;
312 case '9': u = 9UL; break;
313 }
314 switch(state) {
315 case 0: u1 = 10UL * u1 + u; break;
316 case 1: u2 = 10UL * u2 + u; break;
317 case 2: u3 = 10UL * u3 + u; break;
318 case 3: u4 = 10UL * u4 + u; break;
319 }
320 } else {
321 if(*ptr == '.') {
322 state++;
323 if(state >= 4) {
324 ende = 1;
325 }
326 }
327 }
328 ptr++;
329 } else {
330 ende = 1;
331 }
332 }
333 }
334 u1 = u1 << 24; u1 = u1 & 0xFF000000UL;
335 u2 = u2 << 16; u2 = u2 & 0x00FF0000UL;
336 u3 = u3 << 8; u3 = u3 & 0x0000FF00UL;
337 u4 = u4 & 0x000000FFUL;
338 back = u1 | u2 | u3 | u4;
339 return back;
340 }
341
342
343
344 /** Set IP address in socket address.
345 @param sin Internet socket address.
346 @param str String containing host name or IP address.
347 @return 1 on success, 0 on error.
348 */
349 static
350 int
set_ip_address(struct sockaddr_in * sin,char * str)351 set_ip_address(struct sockaddr_in *sin, char *str)
352 {
353 int back = 0;
354
355 sin->sin_addr.s_addr = htonl(dotted_string_to_ip(str));
356 if(sin->sin_addr.s_addr) {
357 back = 1;
358 } else {
359 struct hostent *hp; unsigned long *lp;
360 hp = gethostbyname(str);
361 if(hp) {
362 if(hp->h_addr_list) {
363 if(hp->h_length) {
364 lp = (unsigned long*)(*(hp->h_addr_list));
365 if(lp) {
366 sin->sin_addr.s_addr = *lp;
367 back = 1;
368 }
369 }
370 }
371 }
372 }
373 return back;
374 }
375
376
377
378 /** Set remote address.
379 @param rw Remote socket address or address:port text.
380 @param s Host name of remote host.
381 @return TRUE on success, FALSE on error.
382 */
383 static
384 BOOL
setRemote(SOIN * rw,WCHAR * s)385 setRemote(SOIN *rw, WCHAR *s)
386 {
387 BOOL back = FALSE;
388 WCHAR *ptr; char *cptr;
389 unsigned u; unsigned short us;
390
391 ptr = wcsrchr(s, L':');
392 if(ptr) {
393 *(ptr++) = L'\0';
394 if(swscanf(ptr, L"%u", &u) == 1) {
395 us = (unsigned short)u;
396 rw->sin_port = htons(us);
397 if(wcslen(s) < sizeof(netbuffer)) {
398 ptr = s;
399 cptr = netbuffer;
400 while(*ptr) {
401 *(cptr++) = (char)(*(ptr++));
402 } *cptr = '\0';
403 if(set_ip_address(rw, netbuffer)) {
404 back = TRUE;
405 } else {
406 log_event(EVENTLOG_ERROR_TYPE,MSG_HOST_NOT_FOUND,s,NULL);
407 }
408 } else {
409 log_event(EVENTLOG_ERROR_TYPE,MSG_HOST_NAME_TOO_LONG,s,NULL);
410 }
411 } else {
412 log_event(EVENTLOG_ERROR_TYPE,MSG_NOT_A_NUMBER,ptr,NULL);
413 }
414 } else {
415 log_event(EVENTLOG_ERROR_TYPE,MSG_NOT_HOST_AND_PORT,s,NULL);
416 }
417 return back;
418 }
419
420
421
422 /** Get configuration from registry entries.
423 @param rw Remote address.
424 @param rf Socket address.
425 @param la Local address.
426 @return TRUE on success, FALSE on error.
427 */
428 static
429 BOOL
setupFromRegistry(SOIN * rw,SOIN * rf,SOIN * la)430 setupFromRegistry(SOIN *rw, SOIN *rf, SOIN *la)
431 {
432 BOOL back = FALSE;
433 HKEY hk;
434 DWORD dwDisp;
435 LONG res;
436 unsigned u;
437 WCHAR rb[RSHDOWN_BUFFER_SIZE];
438 FILE *fipo;
439
440 initializeSOIN(rw);
441 initializeSOIN(rf);
442 initializeSOIN(la);
443 res = RegCreateKeyExW(
444 HKEY_LOCAL_MACHINE, n[3], 0, NULL, REG_OPTION_NON_VOLATILE,
445 KEY_READ, NULL, &hk, &dwDisp
446 );
447 if(res == ERROR_SUCCESS) {
448 if(regWstring(rb, SIZEOF(rb,WCHAR), hk, n[0])) {
449 if(setRemote(rw, rb)) {
450 if(regWstring(rb, SIZEOF(rb,WCHAR), hk, n[2])) {
451 if(swscanf(rb, L"%u", &u) == 1) {
452 la->sin_port = htons((unsigned short)u);
453 if(regWstring(rb, SIZEOF(rb,WCHAR), hk, n[1])) {
454 fipo = _wfopen(rb, L"rb");
455 if(fipo) {
456 u_filebuffer = fread(filebuffer, 1, sizeof(filebuffer), fipo);
457 if(u_filebuffer > 0) {
458 back = TRUE;
459 } else {
460 log_event(EVENTLOG_ERROR_TYPE,MSG_FILE_EMPTY,rb,NULL);
461 }
462 fclose(fipo);
463 } else {
464 log_event(EVENTLOG_ERROR_TYPE,MSG_FOPEN_FAILED,rb,NULL);
465 }
466 } else {
467 log_event(EVENTLOG_ERROR_TYPE,MSG_FILE_NOT_SPECIFIED,NULL,NULL);
468 }
469 } else {
470 log_event(EVENTLOG_ERROR_TYPE,MSG_NOT_A_NUMBER,rb,NULL);
471 }
472 } else {
473 log_event(EVENTLOG_ERROR_TYPE,MSG_NO_LOCAL_PORT,NULL,NULL);
474 }
475 } else {
476 }
477 } else {
478 log_event(EVENTLOG_ERROR_TYPE,MSG_NO_SENDER,NULL,NULL);
479 }
480 RegCloseKey(hk);
481 } else {
482 log_event(EVENTLOG_ERROR_TYPE,MSG_REGKEY_FAILED,NULL,NULL);
483 }
484 return back;
485 }
486
487
488
489 /** Service function, run in a separated thread.
490 @param dataforthread Data for the thread.
491 */
492 static
493 void
494 __cdecl
thread_function(void * dataforthread)495 thread_function(void *dataforthread)
496 {
497 unsigned char can_continue = 0x01; /* flag, can continue */
498 unsigned char must_shutdown = 0x00; /* flag whether or not to shut down */
499 WORD version_requested;
500 WSADATA wsa_data;
501 struct sockaddr_in rw; /* remote wanted */
502 struct sockaddr_in rf; /* remote found */
503 struct sockaddr_in la; /* local address */
504 int chars_in_netbuffer;
505 SOCKET sock;
506 FD_SET rfds, wfds, efds;
507 struct timeval to;
508 int lgt;
509 int err;
510 LONG res;
511 HANDLE current_proc; /* the current process */
512 HANDLE proc_token; /* process token */
513 TOKEN_PRIVILEGES ns; /* new state of token privileges */
514 LUID myluid; /* lookup restult for SE_SHUTDOWN_NAME */
515
516
517
518 version_requested = MAKEWORD(2,2);
519 err = WSAStartup(version_requested, &wsa_data);
520 if(err == 0) {
521 if(setupFromRegistry(&rw, &rf, &la)) {
522 sock = socket(AF_INET, SOCK_DGRAM, 0);
523 if(sock != INVALID_SOCKET) {
524 if(bind(sock, (struct sockaddr *)(&la), SZ_SOIN) == 0) {
525 can_continue = 0x01;
526 log_event(EVENTLOG_SUCCESS, MSG_STARTED, NULL, NULL);
527 while(can_continue) {
528 FD_ZERO(&rfds); FD_ZERO(&wfds); FD_ZERO(&efds);
529 FD_SET(sock, &rfds); FD_SET(sock, &efds);
530 to.tv_sec = 2;
531 to.tv_usec = 0;
532 err = select(((int)sock + 1), &rfds, &wfds, &efds, &to);
533 if((err != SOCKET_ERROR) && (err > 0)) {
534
535 if((FD_ISSET(sock, &rfds)) || (FD_ISSET(sock, &efds))) {
536 memcpy((void *)(&rf), (void *)(&rw), SZ_SOIN);
537 lgt = SZ_SOIN;
538 chars_in_netbuffer = recvfrom(
539 sock, netbuffer, sizeof(netbuffer),
540 0, (struct sockaddr *)(&rf), &lgt
541 );
542 if(chars_in_netbuffer != SOCKET_ERROR) {
543
544 if(rf.sin_addr.s_addr = rw.sin_addr.s_addr) {
545 if(rf.sin_port == rw.sin_port) {
546 if(chars_in_netbuffer == u_filebuffer) {
547 if(memcmp(
548 (void *)netbuffer, (void *)filebuffer, u_filebuffer
549 ) == 0)
550 {
551 can_continue = 0x00;
552 must_shutdown = 0x01;
553
554 } else {
555 }
556 } else {
557 }
558 } else {
559 }
560 } else {
561 }
562 }
563 }
564 } else {
565 }
566 if(can_continue) {
567 res = WaitForSingleObjectEx(hEventMustStop, 0, FALSE);
568 switch(res) {
569 case WAIT_OBJECT_0: {
570 can_continue = 0x00;
571 } break;
572 }
573 }
574 }
575 log_event(EVENTLOG_SUCCESS,MSG_GOING_DOWN,NULL,NULL);
576 } else {
577 log_event(EVENTLOG_ERROR_TYPE,MSG_BIND_FAILED,NULL,NULL);
578 }
579 closesocket(sock);
580 } else {
581 log_event(EVENTLOG_ERROR_TYPE,MSG_SOCKET_FAILED,NULL,NULL);
582 }
583 }
584 WSACleanup();
585 } else {
586 log_event(EVENTLOG_ERROR_TYPE,MSG_WINSOCK_FAILED,NULL,NULL);
587 }
588 if(must_shutdown) {
589 /* ACTION: Start shutdown */
590 current_proc = GetCurrentProcess();
591 if(current_proc != (HANDLE)0) {
592 LookupPrivilegeValueW(NULL, n[4], &myluid);
593 if(
594 OpenProcessToken(
595 current_proc, (TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY),&proc_token
596 )
597 ) {
598 ns.PrivilegeCount = 1;
599 ns.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
600 ns.Privileges[0].Luid.HighPart = myluid.HighPart;
601 ns.Privileges[0].Luid.LowPart = myluid.LowPart;
602 if(AdjustTokenPrivileges(proc_token, FALSE, &ns, 0, NULL, NULL)) {
603 } else {
604 /* ERROR: Failed to obtain shutdown privilege */
605 log_event(EVENTLOG_ERROR_TYPE,MSG_PRIVILEGE_FAILED,NULL,NULL);
606 }
607 CloseHandle(proc_token);
608 } else {
609 /* ERROR: Failed to access current process token */
610 log_event(EVENTLOG_ERROR_TYPE,MSG_PROCESS_TOKEN,NULL,NULL);
611 }
612 } else {
613 /* ERROR: Failed to obtain handle for current process */
614 log_event(EVENTLOG_ERROR_TYPE,MSG_PROCESS_HANDLE,NULL,NULL);
615 }
616 if(InitiateSystemShutdownExW(
617 NULL,
618 n[5],
619 15,
620 TRUE,
621 FALSE,
622 (SHTDN_REASON_MAJOR_POWER | SHTDN_REASON_MINOR_ENVIRONMENT)
623 ))
624 {
625 /* Shutdown initiated successfully */
626 log_event(EVENTLOG_SUCCESS, MSG_SHUTDOWN_INITIALIZED, NULL, NULL);
627 } else {
628 /* ERROR: Failed to initiate shutdown */
629 log_event(EVENTLOG_ERROR_TYPE,MSG_SHUTDOWN_FAILED,NULL,NULL);
630 }
631 }
632
633
634 SetEvent(hEventDidStop);
635 _endthread();
636 }
637
638
639
640 /** The service function registers the service control handler
641 and runs the service function in a separate thread.
642 @param argc Number of command line arguments.
643 @param argv Command line arguments array.
644 */
645 VOID
646 CALLBACK
service_function(DWORD argc,LPTSTR * argv)647 service_function(DWORD argc, LPTSTR *argv)
648 {
649 uintptr_t thread_id;
650 memset((void *)(&st), 0, sizeof(SERVICE_STATUS));
651 st.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
652 st.dwCurrentState = SERVICE_START_PENDING;
653 st.dwControlsAccepted =
654 SERVICE_ACCEPT_SHUTDOWN | SERVICE_ACCEPT_STOP;
655 st.dwWin32ExitCode = 0;
656 st.dwServiceSpecificExitCode = 0;
657 st.dwCheckPoint = 0;
658 st.dwWaitHint = 0;
659 hSt = RegisterServiceCtrlHandlerW(service_name, service_ctrl_handler);
660 if(hSt != (SERVICE_STATUS_HANDLE)0) {
661 st.dwCurrentState = SERVICE_STOPPED;
662 hEventMustStop = CreateEventW(NULL, TRUE, FALSE, NULL);
663 if(hEventMustStop != NULL) {
664 hEventDidStop = CreateEventW(NULL, TRUE, FALSE, NULL);
665 if(hEventDidStop != NULL) {
666 ResetEvent(hEventMustStop);
667 ResetEvent(hEventDidStop);
668 thread_id = _beginthread(thread_function, 0, NULL);
669 if(thread_id != -1L) {
670 st.dwCurrentState = SERVICE_RUNNING;
671 } else {
672 CloseHandle(hEventDidStop); hEventDidStop = NULL;
673 CloseHandle(hEventMustStop); hEventMustStop = NULL;
674 }
675 } else {
676 CloseHandle(hEventMustStop); hEventMustStop = NULL;
677 }
678 } else {
679 }
680 SetServiceStatus(hSt, &st);
681 }
682 }
683
684
685
686 /** Service dispatch table.
687 */
688 static SERVICE_TABLE_ENTRY dispatch_table[] = {
689 { service_name, service_function },
690 { NULL, NULL }
691 };
692
693
694
695 /** The main() function of the rshdown program (Windows).
696 @param argc Number of command line arguments.
697 @param argv Command line arguments array.
698 @return 0 on success, any other value indicates an error.
699 */
wmain(int argc,WCHAR * argv[])700 int wmain(int argc, WCHAR *argv[])
701 {
702 if(StartServiceCtrlDispatcherW(dispatch_table) == 0) {
703 fprintf(stderr, "ERROR: This program is a Windows service\n");
704 fprintf(stderr, "and can not be run on the command line!\n");
705 fflush(stderr);
706 }
707 exit(0); return 0;
708 }
709
710
711 #else
712 /* defined(_WIN32) || defined(WIN32) || defined(_WIN64) || defined(WIN64) */
713
714
715
716 /*
717 Daemon on POSIX systems.
718 ========================
719 */
720
721 /*
722 rshdown -s [-n _number_] [-l _port_] [-b] _address_ _port_ _file_
723 rshdown [-c _configfile_]
724
725 Either send shutdown packages (-s option used)
726 or run as daemon in background (no -s option)
727 and wait for shutdown packages.
728
729 Sending:
730
731 -n _number_ Number of packages to send
732
733 -l _port_ Local port number to use
734 Default: Same as remote port
735
736 -b Flag: Destination address is a broadcast address
737
738 _address_ Destination address (hostname or IP address)
739
740 _port_ Port number on destination host
741
742 _file_ File containing data to send
743
744 Daemon:
745
746 -c _configfile_ Configuration file.
747
748 */
749
750
751 #include <libdk4base/dk4types.h>
752
753
754 #include <stdio.h>
755
756 #if DK4_HAVE_UNISTD_H
757 #ifndef UNISTD_H_INCLUDED
758 #include <unistd.h>
759 #define UNISTD_H_INCLUDED 1
760 #endif
761 #endif
762
763 #if DK4_HAVE_STDLIB_H
764 #ifndef STDLIB_H_INCLUDED
765 #include <stdlib.h>
766 #define STDLIB_H_INCLUDED 1
767 #endif
768 #endif
769
770 #if (DK4_CHAR_SIZE == 1) \
771 && (DK4_HAVE_SIGACTION || DK4_HAVE_SIGSET) \
772 && (DK4_HAVE_SETSID || DK4_HAVE_SETPGRP)
773
774 #if DK4_HAVE_MATH_H
775 #ifndef MATH_H_INCLUDED
776 #if DK4_ON_WINDOWS
777 #ifndef _USE_MATH_DEFINES
778 #define _USE_MATH_DEFINES 1
779 #endif
780 #endif
781 #include <math.h>
782 #define MATH_H_INCLUDED 1
783 #endif
784 #endif
785
786 #if DK4_HAVE_IO_H
787 #ifndef IO_H_INCLUDED
788 #include <io.h>
789 #define IO_H_INCLUDED 1
790 #endif
791 #endif
792
793 #if DK4_HAVE_FCNTL_H
794 #ifndef FCNTL_H_INCLUDED
795 #include <fcntl.h>
796 #define FCNTL_H_INCLUDED 1
797 #endif
798 #endif
799
800 #if DK4_HAVE_STRING_H
801 #ifndef STRING_H_INCLUDED
802 #include <string.h>
803 #define STRING_H_INCLUDED 1
804 #endif
805 #endif
806
807 #if DK4_HAVE_SYS_TYPES_H
808 #ifndef SYS_TYPES_H_INCLUDED
809 #include <sys/types.h>
810 #define SYS_TYPES_H_INCLUDED 1
811 #endif
812 #endif
813
814 #if DK4_HAVE_SIGNAL_H
815 #ifndef SIGNAL_H_INCLUDED
816 #include <signal.h>
817 #define SIGNAL_H_INCLUDED 1
818 #endif
819 #endif
820
821 #if DK4_HAVE_SYSLOG_H
822 #ifndef SYSLOG_H_INCLUDED
823 #include <syslog.h>
824 #define SYSLOG_H_INCLUDED 1
825 #endif
826 #endif
827
828 #if DK4_HAVE_SYSEXITS_H
829 #ifndef SYSEXITS_H_INCLUDED
830 #include <sysexits.h>
831 #define SYSEXITS_H_INCLUDED 1
832 #endif
833 #endif
834
835 #include <libdk4base/dk4mem.h>
836 #include <libdk4base/dk4memrs.h>
837 #include <libdk4c/dk4opt.h>
838 #include <libdk4maio8d/dk4mai8dus.h>
839 #include <libdk4maio8d/dk4mai8dii.h>
840 #include <libdk4c/dk4fopt.h>
841 #include <libdk4c/dk4fopc8.h>
842 #include <libdk4c/dk4isadm.h>
843 #include <libdk4sock/dk4sock.h>
844 #include <libdk4c/dk4inst.h>
845 #include <libdk4base/dk4str8.h>
846 #include <libdk4base/dk4mpl.h>
847 #include <libdk4c/dk4dmt.h>
848 #include <libdk4base/dk4vers.h>
849 #include <libdk4base/dk4unused.h>
850
851
852
853
854
855
856
857 #ifndef RSHDOWN_BUFFER_SIZE
858 /** Buffer size, should not exceed UDP packet size.
859 */
860 #define RSHDOWN_BUFFER_SIZE 1460
861 #endif
862
863
864
865 /** Path name of data file.
866 */
867 static char file_name[DK4_MAX_PATH];
868
869
870
871 /** Send and receive buffer.
872 */
873 static char b1[RSHDOWN_BUFFER_SIZE];
874
875
876 /** Buffer for local secret from file in daemon.
877 */
878 static char b2[sizeof(b1)];
879
880
881 /** Command to execute on packet arrival.
882 */
883 static char cmd[1024];
884
885
886 /** Allowed sender peer as text.
887 */
888 static char asender[1024];
889
890
891 /** Options used by the program.
892 */
893 static dk4_option_t options[] = {
894
895 /* 0 Configuration file.
896 */
897 { { dkT('c'), dkT("config"), DK4_OPT_ARG_STRING }, { NULL }, 0 },
898
899 /* 1 Send data.
900 */
901 { { dkT('s'), dkT("send"), DK4_OPT_ARG_NONE }, { NULL }, 0 },
902
903 /* 2 Destination address is a broadcast address.
904 */
905 { { dkT('b'), dkT("broadcast"), DK4_OPT_ARG_NONE }, { NULL }, 0 },
906
907 /* 3 Number of packets to send.
908 */
909 { { dkT('n'), dkT("number"), DK4_OPT_ARG_UNSIGNED}, { NULL }, 0 },
910
911 /* 4 Local port number.
912 */
913 { { dkT('l'), dkT("local"), DK4_OPT_ARG_UNSIGNED}, { NULL }, 0},
914
915 /* 5 Help.
916 */
917 { { dkT('\0'),dkT("help"), DK4_OPT_ARG_NONE}, { NULL }, 0},
918
919 /* 6 Version.
920 */
921 { { dkT('\0'),dkT("version"), DK4_OPT_ARG_NONE}, { NULL }, 0},
922
923 /* 7 License
924 */
925 { { dkT('\0'),dkT("license"), DK4_OPT_ARG_NONE}, { NULL }, 0}
926 };
927
928
929
930 /** Help text.
931 */
932 static const char * const help_text[] = {
933 "",
934 "Remote shutdown sender and recipient",
935 "",
936 "rshdown [-c config]",
937 "rshdown -s [-n number] [-l port] [-b] host port file",
938 "",
939 "-c config\t\tConfiguration file for recipient (daemon).",
940 "",
941 "-s\t\t\tSend shutdown data packet.",
942 "-n number\t\tSend packet multiple times.",
943 "-l port\t\t\tLocal port to use for sending.",
944 "-b\t\t\tPrepare socket for broadcast sending.",
945 "host\t\t\tRemote host (recipient), host name or IP address.",
946 "\t\t\tOption -b is required if you specify a broadcast",
947 "\t\t\taddress like 255.255.255.255 or 192.0.2.255 here.",
948 "port\t\t\tRemote port.",
949 "file\t\t\tFile containing pre-shared secret (shutdown data).",
950 "",
951 "--help\t\t\tShow this help text.",
952 "--version\t\tShow version number.",
953 "--license\t\tShow license information.",
954 "",
955 NULL
956
957 };
958
959
960
961 /** License conditions text.
962 */
963 static const char * const license_text[] = {
964 "",
965 "This software uses code from the following projects, either directly or as",
966 "a library:",
967 "",
968 "dktools\t\tDirk Krause's tools and libraries.",
969 "\t\tSee http://sourceforge.net/p/dktools/wiki/Home/",
970 "\t\tfor more information.",
971 "",
972 "DK tools and libraries license",
973 "==============================",
974 "Copyright (c) 2015-2016, Dirk Krause",
975 "All rights reserved.",
976 "",
977 "Redistribution and use in source and binary forms, with or without",
978 "modification, are permitted provided that the following conditions are met:",
979 "",
980 "1. Redistributions of source code must retain the above copyright notice,",
981 " this list of conditions and the following disclaimer.",
982 "2. Redistributions in binary form must reproduce the above copyright",
983 " notice, this list of conditions and the following disclaimer in the",
984 " documentation and/or other materials provided with the distribution.",
985 "3. Neither the name of the copyright holder nor the names of its",
986 " contributors may be used to endorse or promote products derived from",
987 " this software without specific prior written permission.",
988 "",
989 "THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS",
990 "``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT",
991 "LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR",
992 "A PARTICULAR PURPOSE ARE DISCLAIMED.",
993 "IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY",
994 "DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES",
995 "(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR",
996 "SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER",
997 "CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT",
998 "LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY",
999 "OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF",
1000 "SUCH DAMAGE.",
1001 "",
1002 NULL
1003
1004 };
1005
1006
1007
1008 /** Version information.
1009 */
1010 static const char version_text[] = { DKT_VERSION_C8 };
1011
1012
1013
1014 /** Default configuration file name.
1015 */
1016 static const char def_conf_name[] = {
1017 DK4_INST_DIR_ETC "/rshdown/rshdown.conf"
1018 };
1019
1020
1021
1022 /** PID file name.
1023 */
1024 static const char pid_file_name[] = {
1025 DK4_INST_DIR_SYSTEMD_RUN "/rshdown/rshdown.pid"
1026 };
1027
1028
1029
1030 /** Key names expected in configuration file.
1031 */
1032 static const char * const key_names[] = {
1033 /* 0 */
1034 "sender",
1035
1036 /* 1 */
1037 "sender port",
1038
1039 /* 2 */
1040 "receiver port",
1041
1042 /* 3 */
1043 "signal",
1044
1045 /* 4 */
1046 "command",
1047
1048 /* 5 */
1049 "file",
1050
1051 /* 6 */
1052 "debug",
1053
1054 /* 7 */
1055 "syslog facility",
1056
1057 NULL
1058
1059 };
1060
1061
1062
1063 /** Signal names.
1064 */
1065 static const char * const signal_names[] = {
1066 /* 0 */
1067 "sighup",
1068
1069 /* 1 */
1070 "hup",
1071
1072 /* 2 */
1073 "sigint",
1074
1075 /* 3 */
1076 "int",
1077
1078 /* 4 */
1079 "sigquit",
1080
1081 /* 5 */
1082 "quit",
1083
1084 /* 6 */
1085 "sigill",
1086
1087 /* 7 */
1088 "ill",
1089
1090 /* 8 */
1091 "sigtrap",
1092
1093 /* 9 */
1094 "trap",
1095
1096 /* 10 */
1097 "sigabrt",
1098
1099 /* 11 */
1100 "abrt",
1101
1102 /* 12 */
1103 "sigiot",
1104
1105 /* 13 */
1106 "iot",
1107
1108 /* 14 */
1109 "sigbus",
1110
1111 /* 15 */
1112 "bus",
1113
1114 /* 16 */
1115 "sigfpe",
1116
1117 /* 17 */
1118 "fpe",
1119
1120 /* 18 */
1121 "sigkill",
1122
1123 /* 19 */
1124 "kill",
1125
1126 /* 20 */
1127 "sigusr1",
1128
1129 /* 21 */
1130 "usr1",
1131
1132 /* 22 */
1133 "sigsegv",
1134
1135 /* 23 */
1136 "segv",
1137
1138 /* 24 */
1139 "sigusr2",
1140
1141 /* 25 */
1142 "usr2",
1143
1144 /* 26 */
1145 "sigpipe",
1146
1147 /* 27 */
1148 "pipe",
1149
1150 /* 28 */
1151 "sigalrm",
1152
1153 /* 29 */
1154 "alrm",
1155
1156 /* 30 */
1157 "sigterm",
1158
1159 /* 31 */
1160 "term",
1161
1162 /* 32 */
1163 "sigstkflt",
1164
1165 /* 33 */
1166 "stkflt",
1167
1168 /* 34 */
1169 "sigcld",
1170
1171 /* 35 */
1172 "cld",
1173
1174 /* 36 */
1175 "sigchld",
1176
1177 /* 37 */
1178 "chld",
1179
1180 /* 38 */
1181 "sigcont",
1182
1183 /* 39 */
1184 "cont",
1185
1186 /* 40 */
1187 "sigstop",
1188
1189 /* 41 */
1190 "stop",
1191
1192 /* 42 */
1193 "sigtstp",
1194
1195 /* 43 */
1196 "tstp",
1197
1198 /* 44 */
1199 "sigttin",
1200
1201 /* 45 */
1202 "ttin",
1203
1204 /* 46 */
1205 "sigttou",
1206
1207 /* 47 */
1208 "ttou",
1209
1210 /* 48 */
1211 "sigurg",
1212
1213 /* 49 */
1214 "urg",
1215
1216 /* 50 */
1217 "sigxcpu",
1218
1219 /* 51 */
1220 "xcpu",
1221
1222 /* 52 */
1223 "sigxfsz",
1224
1225 /* 53 */
1226 "xfsz",
1227
1228 /* 54 */
1229 "sigvtalrm",
1230
1231 /* 55 */
1232 "vtalrm",
1233
1234 /* 56 */
1235 "sigprof",
1236
1237 /* 57 */
1238 "prof",
1239
1240 /* 58 */
1241 "sigwinch",
1242
1243 /* 59 */
1244 "winch",
1245
1246 /* 60 */
1247 "sigpoll",
1248
1249 /* 61 */
1250 "poll",
1251
1252 /* 62 */
1253 "sigio",
1254
1255 /* 63 */
1256 "io",
1257
1258 /* 64 */
1259 "sigpwr",
1260
1261 /* 65 */
1262 "pwr",
1263
1264 /* 66 */
1265 "sigsys",
1266
1267 /* 67 */
1268 "sys",
1269
1270 NULL
1271
1272 };
1273
1274
1275
1276 /** Syslog facility names.
1277 */
1278 static const char * const syslog_facility_names[] = {
1279 /* 0 */
1280 "auth",
1281
1282 /* 1 */
1283 "authpriv",
1284
1285 /* 2 */
1286 "cron",
1287
1288 /* 3 */
1289 "daemon",
1290
1291 /* 4 */
1292 "ftp",
1293
1294 /* 5 */
1295 "kern",
1296
1297 /* 6 */
1298 "lpr",
1299
1300 /* 7 */
1301 "mail",
1302
1303 /* 8 */
1304 "news",
1305
1306 /* 9 */
1307 "security",
1308
1309 /* 10 */
1310 "syslog",
1311
1312 /* 11 */
1313 "user",
1314
1315 /* 12 */
1316 "uucp",
1317
1318 /* 13 */
1319 "local0",
1320
1321 /* 14 */
1322 "local1",
1323
1324 /* 15 */
1325 "local2",
1326
1327 /* 16 */
1328 "local3",
1329
1330 /* 17 */
1331 "local4",
1332
1333 /* 18 */
1334 "local5",
1335
1336 /* 19 */
1337 "local6",
1338
1339 /* 20 */
1340 "local7",
1341
1342 NULL
1343
1344 };
1345
1346
1347 /** Texts used by the program, not localized.
1348 */
1349 static const char * const rshdown_kw[] = {
1350 /* 0 */
1351 "rshdown",
1352
1353 /* 1 */
1354 ": ",
1355
1356 /* 2 */
1357 "ERROR: Failed to set broadcast mode on socket!\n",
1358
1359 /* 3 */
1360 "ERROR: Failed to bind local address!\n",
1361
1362 /* 4 */
1363 "ERROR: Failed to bind local address: \"",
1364
1365 /* 5 */
1366 "\"!\n",
1367
1368 /* 6 */
1369 "ERROR: Failed to create socket!\n",
1370
1371 /* 7 */
1372 "ERROR: Failed to find address for: \"",
1373
1374 /* 8 */
1375 "\"!\n",
1376
1377 /* 9 */
1378 "ERROR: Failed to bring socket subsystem up!\n",
1379
1380 /* 10 */
1381 "ERROR: 3 arguments required: host, port and file!\n",
1382
1383 /* 11 */
1384 "ERROR: Not a 16 bit unsigned integer: \"",
1385
1386 /* 12 */
1387 "\"!\n",
1388
1389 /* 13 */
1390 "ERROR: Port number 0 is not allowed!\n",
1391
1392 /* 14 */
1393 "ERROR: Failed to open data file:\n\"",
1394
1395 /* 15 */
1396 "\"!\n",
1397
1398 /* 16 */
1399 "ERROR: Failed to read data from file:\n\"",
1400
1401 /* 17 */
1402 "\"!\n",
1403
1404 /* 18 */
1405 "ERROR: Failed to install signal handlers!\n",
1406
1407 /* 19 */
1408 "ERROR: Failed to restore signal handlers!\n",
1409
1410 /* 20 */
1411 "ERROR: Failed to create child process!\n",
1412
1413 /* 21 */
1414 "Failed to detach from terminal!",
1415
1416 /* 22 */
1417 "Failed to create child process!",
1418
1419 /* 23 */
1420 "Failed to install signal handlers!",
1421
1422 /* 24 */
1423 "Failed to restore signal handlers!",
1424
1425 /* 25 */
1426 "Failed to bring socket subsystem up!",
1427
1428 /* 26 */
1429 "Failed to create UDP socket set!",
1430
1431 /* 27 */
1432 "ERROR: Local port number too large!\n",
1433
1434 /* 28 */
1435 "ERROR: Local port number must not be 0!\n",
1436
1437 /* 29 */
1438 "Failed to set allowed peer: \"",
1439
1440 /* 30 */
1441 "\"!",
1442
1443 /* 31 */
1444 "ERROR: Illegal signal name: \"",
1445
1446 /* 32 */
1447 "\"!\n",
1448
1449 /* 33 */
1450 "ERROR: Sender name too long:\n",
1451
1452 /* 34 */
1453 "\"!\n",
1454
1455 /* 35 */
1456 "ERROR: Sender name defined multiple times!\n",
1457
1458 /* 36 */
1459 "ERROR: Signal number must be positive!\n",
1460
1461 /* 37 */
1462 "ERROR: Command too long:\n\"",
1463
1464 /* 38 */
1465 "\"!\n",
1466
1467 /* 39 */
1468 "ERROR: Command defined multiple times!\n",
1469
1470 /* 40 */
1471 "ERROR: File name too long:\n\"",
1472
1473 /* 41 */
1474 "\"!\n",
1475
1476 /* 42 */
1477 "ERROR: File name defined multiple times!\n",
1478
1479 /* 43 */
1480 "ERROR: Unknown key in configuration file!\n",
1481
1482 /* 44 */
1483 "ERROR: Missing value on configuration line!\n",
1484
1485 /* 45 */
1486 "ERROR: No local port specified!\n",
1487
1488 /* 46 */
1489 "ERROR: Signal number or command required!\n",
1490
1491 /* 47 */
1492 "ERROR: No data file specified!\n",
1493
1494 /* 48 */
1495 "ERROR: Illegal syslog facility: \"",
1496
1497 /* 49 */
1498 "\"!\n",
1499
1500 /* 50 */
1501 "Service started.",
1502
1503 /* 51 */
1504 "Initiate shutdown.",
1505
1506 /* 52 */
1507 "Service finished.",
1508
1509 /* 53 */
1510 "Packet from \"",
1511
1512 /* 54 */
1513 "\" discarded, wrong sender address!",
1514
1515 /* 55 */
1516 "Packet from \"",
1517
1518 /* 56 */
1519 "\" discarded, wrong sender port!",
1520
1521 /* 57 */
1522 "Packet from \"",
1523
1524 /* 58 */
1525 "\" discarded, size mismatch!",
1526
1527 /* 59 */
1528 "Packet from \"",
1529
1530 /* 60 */
1531 "\" discarded, data mismatch!",
1532
1533 /* 61 */
1534 "Failed to execute command: \"",
1535
1536 /* 62 */
1537 "\"!",
1538
1539 NULL
1540
1541 };
1542
1543
1544 /** Information for daemon tool functions.
1545 */
1546 static dk4dmt_t dmt;
1547
1548
1549 /** Number of options in the options array.
1550 */
1551 static const size_t szoptions = sizeof(options)/sizeof(dk4_option_t);
1552
1553
1554
1555 /** Number of bytes in buffer b1.
1556 */
1557 static size_t szb1 = 0;
1558
1559
1560
1561 /** Number of bytes in buffer b2.
1562 */
1563 static size_t szb2 = 0;
1564
1565
1566
1567 /** Exit status code.
1568 */
1569 static int exval = EXIT_FAILURE;
1570
1571
1572
1573 /** Options: Help (1), version (2), license (4).
1574 */
1575 static int hvl = 0;
1576
1577
1578
1579 /** Flag: Additional debug messages.
1580 */
1581 static int debug = 0;
1582
1583
1584
1585 #ifdef LOG_DAEMON
1586 /** Syslog facility.
1587 */
1588 static int syslogf = LOG_AUTH;
1589 #else
1590 /** Syslog facility.
1591 */
1592 static int syslogf = (3<<3);
1593 #endif
1594
1595
1596
1597 /** Signal to send on arrival of shutdown data packet.
1598 */
1599 static int signo =
1600 #ifdef SIGPWR
1601 SIGPWR
1602 #else
1603 #ifdef SIGTERM
1604 SIGTERM
1605 #else
1606 15
1607 #endif
1608 #endif
1609 ;
1610
1611
1612
1613 #ifdef SIGPIPE
1614 /** Indicator: SIGPIPE signal received.
1615 */
1616 static
1617 DK4_VOLATILE
1618 dk4_sig_atomic_t sig_had_pipe = 0;
1619 #endif
1620
1621
1622 /** Indicator: SIGINT signal received.
1623 */
1624 static
1625 DK4_VOLATILE
1626 dk4_sig_atomic_t sig_had_int = 0;
1627
1628
1629 /** Indicator: SIGTERM signal received.
1630 */
1631 static
1632 DK4_VOLATILE
1633 dk4_sig_atomic_t sig_had_term = 0;
1634
1635
1636
1637 /** Remote port.
1638 */
1639 static unsigned short rp = 0U;
1640
1641
1642
1643 /** Local port.
1644 */
1645 static unsigned short lp = 0U;
1646
1647
1648 /** Pass pointer through.
1649 Use of this function is recommended by CERT C coding standard
1650 to avoid optimizing out.
1651 @param ptr Pointer to pass through.
1652 @return The ptr argument.
1653 */
1654 static
1655 DK4_VOLATILE
1656 dk4_sig_atomic_t *
sig_pass_pointer(DK4_VOLATILE dk4_sig_atomic_t * ptr)1657 sig_pass_pointer(DK4_VOLATILE dk4_sig_atomic_t *ptr)
1658 {
1659 return ptr;
1660 }
1661
1662
1663 #ifdef SIGPIPE
1664 /** Handler for SIGPIPE signal.
1665 @param signo Signal number (always SIGPIPE, ignored).
1666 */
1667 static
1668 void
sig_handler_pipe(int DK4_ARG_UNUSED (signo))1669 sig_handler_pipe(int DK4_ARG_UNUSED(signo) )
1670 {
1671 DK4_UNUSED_ARG(signo)
1672 *sig_pass_pointer(&sig_had_pipe) = 1;
1673 }
1674 #endif
1675
1676
1677 /** Handler for SIGINT signal.
1678 @param signo Signal number (always SIGINT, ignored).
1679 */
1680 static
1681 void
sig_handler_int(int DK4_ARG_UNUSED (signo))1682 sig_handler_int(int DK4_ARG_UNUSED(signo) )
1683 {
1684 DK4_UNUSED_ARG(signo)
1685 *sig_pass_pointer(&sig_had_int) = 1;
1686 }
1687
1688
1689 /** Handler for SIGTERM signal.
1690 @param signo Signal number (always SIGTERM, ignored).
1691 */
1692 static
1693 void
sig_handler_term(int DK4_ARG_UNUSED (signo))1694 sig_handler_term(int DK4_ARG_UNUSED(signo) )
1695 {
1696 DK4_UNUSED_ARG(signo)
1697 *sig_pass_pointer(&sig_had_term) = 1;
1698 }
1699
1700
1701 /** Read value from volatile atomic type.
1702 This function is necessary as some compilers mis-optimize
1703 direct access to volatile variables (at least if you believe
1704 one of the coding standards).
1705 @param ap Pointer to volatile atomic variable.
1706 @return Contents of the variable.
1707 */
1708 static
1709 dk4_sig_atomic_t
sig_read_atomic(DK4_VOLATILE dk4_sig_atomic_t * ap)1710 sig_read_atomic(DK4_VOLATILE dk4_sig_atomic_t *ap)
1711 {
1712 return (*ap);
1713 }
1714
1715
1716 /** Check whether we can continue or must abort due to signal.
1717 @param dopipe Flag: Check for SIGPIPE too.
1718 @return 1 if we can continue, 0 otherwise.
1719 */
1720 static
1721 int
can_continue(void)1722 can_continue(void)
1723 {
1724 int back = 1;
1725 if (0 != sig_read_atomic(&sig_had_term)) { back = 0; }
1726 if (0 != sig_read_atomic(&sig_had_int)) { back = 0; }
1727 return back;
1728 }
1729
1730
1731
1732 /** Write log message to stderr, 1 component.
1733 @param i Text index in rshdown_kw array.
1734 */
1735 static
1736 void
log_1(size_t i)1737 log_1(size_t i)
1738 {
1739 fputs(rshdown_kw[0], stderr);
1740 fputs(rshdown_kw[1], stderr);
1741 fputs(rshdown_kw[i], stderr);
1742 fflush(stderr);
1743 }
1744
1745
1746
1747 /** Write syslog message, 1 component.
1748 @param i Index of text in rshdown_kw array.
1749 */
1750 static
1751 void
syslog_1(size_t i)1752 syslog_1(size_t i)
1753 {
1754 #if DK4_HAVE_SYSLOG
1755 openlog(rshdown_kw[0], LOG_PID, syslogf);
1756 syslog(LOG_ERR, "%s", rshdown_kw[i]);
1757 closelog();
1758 #endif
1759 }
1760
1761
1762
1763 /** Write syslog message, 3 components.
1764 @param i1 Index of first component in rshdown_kw array.
1765 @param i2 Index of third component in rshdown_kw array.
1766 @param str Second component.
1767 */
1768 static
1769 void
syslog_3(size_t i1,size_t i2,const char * str)1770 syslog_3(size_t i1, size_t i2, const char *str)
1771 {
1772 #if DK4_HAVE_SYSLOG
1773 openlog(rshdown_kw[0], LOG_PID, syslogf);
1774 if (NULL != str) {
1775 syslog(LOG_ERR, "%s%s%s", rshdown_kw[i1], str, rshdown_kw[i2]);
1776 } else {
1777 syslog(LOG_ERR, "%s%s", rshdown_kw[i1], rshdown_kw[i2]);
1778 }
1779 closelog();
1780 #endif
1781 }
1782
1783
1784
1785 /** Write an additional debug message to syslog.
1786 @param i1 Index of first component in rshdown_kw array.
1787 @param i2 Index of third component in rshdown_kw array.
1788 @param sa Socket address, second component.
1789 */
1790 static
1791 void
syslog_debug(size_t i1,size_t i2,dk4_sockaddr_storage_t * sa)1792 syslog_debug(size_t i1, size_t i2, dk4_sockaddr_storage_t *sa)
1793 {
1794 #if DK4_HAVE_SYSLOG
1795 char buf[128]; /* Buffer for text respresentation of address */
1796 int res; /* Operation result from conversion */
1797
1798 if (0 != debug) {
1799 res = dk4socket_c8_sockaddr_to_text(buf, sizeof(buf), sa, NULL);
1800 openlog(rshdown_kw[0], LOG_PID, syslogf);
1801 if (DK4_SOCKET_RESULT_SUCCESS == res) {
1802 syslog(LOG_DEBUG, "%s%s%s", rshdown_kw[i1], buf, rshdown_kw[i2]);
1803 } else {
1804 syslog(LOG_DEBUG, "%s%s", rshdown_kw[i1], rshdown_kw[i2]);
1805 }
1806 closelog();
1807 }
1808 #endif
1809 }
1810
1811
1812
1813 /** Write log message to stderr, 3 components.
1814 @param i1 Index of first component in rshdown_kw array.
1815 @param i2 Index of third component in rshdown_kw array.
1816 @param str Second component.
1817 */
1818 static
1819 void
log_3(size_t i1,size_t i2,const char * str)1820 log_3(size_t i1, size_t i2, const char *str)
1821 {
1822 fputs(rshdown_kw[0], stderr);
1823 fputs(rshdown_kw[1], stderr);
1824 fputs(rshdown_kw[i1], stderr);
1825 if (NULL != str) { fputs(str, stderr); }
1826 fputs(rshdown_kw[i2], stderr);
1827 fflush(stderr);
1828 }
1829
1830
1831
1832 /** Send buffer over network.
1833 @param hn Remote host name or IP address as text.
1834 @param rp Remote port in host representation.
1835 @param lp Local port in host representation.
1836 @param sz Number of bytes in b1.
1837 */
1838 static
1839 void
send_network(const char * hn,size_t sz)1840 send_network(const char *hn, size_t sz)
1841 {
1842 char adbuf[128]; /* Address as text */
1843 dk4_sockaddr_storage_t array[2]; /* Address pair */
1844 dk4_um_t num = (dk4_um_t)0UL;
1845 size_t szr = 0; /* Rem addr size */
1846 size_t szl = 0; /* Loc addr size */
1847 size_t lgt = 0; /* Length sent */
1848 dk4_socket_t sock = INVALID_SOCKET;
1849 int res = 0; /* Operation result */
1850 int ip4 = 0; /* IPv4 preferred */
1851 int af = AF_UNSPEC;
1852 int pf = PF_UNSPEC;
1853
1854 if (DK4_SOCKET_RESULT_SUCCESS == dk4socket_up(NULL)) {
1855 if (options[2].found) { ip4 = 1; }
1856 res = dk4socket_c8_udp_addresses_numeric(array, hn, rp, lp, ip4, NULL);
1857 if (DK4_SOCKET_RESULT_SUCCESS == res) {
1858 szr = dk4socket_address_size(array);
1859 szl = dk4socket_address_size(&(array[1]));
1860 af = dk4socket_address_family(&(array[1]));
1861 pf = dk4socket_pf_for_af(af);
1862 if ((0 < szr) && (0 < szl) && (AF_UNSPEC != af) && (PF_UNSPEC != pf)) {
1863 sock = dk4socket_open(pf, SOCK_DGRAM, 0, NULL);
1864 if (INVALID_SOCKET != sock) {
1865 exval = EXIT_SUCCESS;
1866 (void)dk4socket_option_set_reuse(sock, 1, NULL);
1867 if (options[2].found) {
1868 res = dk4socket_option_set_broadcast(sock,1,NULL);
1869 if (DK4_SOCKET_RESULT_SUCCESS != res) {
1870 /* ERROR: Failed to set broadcast mode */
1871 log_1(2);
1872 exval = EXIT_FAILURE;
1873 }
1874 }
1875 res = dk4socket_bind(
1876 sock, (struct sockaddr *)(&(array[1])), szl, NULL
1877 );
1878 if (DK4_SOCKET_RESULT_SUCCESS == res) {
1879 if (0 != options[3].found) { num = options[3].val.u; }
1880 if ((dk4_um_t)0UL == num) { num = (dk4_um_t)1UL; }
1881 while ((0 != can_continue()) && ((dk4_um_t)0UL < num--)) {
1882 lgt = sz;
1883 res = dk4socket_sendto(
1884 sock, b1, &lgt, 0,
1885 (struct sockaddr *)(&(array[0])), szr,
1886 0L, 0L, NULL
1887 );
1888 if (DK4_SOCKET_RESULT_SUCCESS == res) {
1889 if (lgt != sz) { exval = EXIT_FAILURE; }
1890 } else {
1891 exval = EXIT_FAILURE;
1892 }
1893 }
1894 } else {
1895 /* ERROR: Failed to bind local address */
1896 res = dk4socket_c8_addr_port_to_text(
1897 adbuf, sizeof(adbuf),
1898 af, (struct sockaddr *)(&(array[1])), szl, NULL
1899 );
1900 if (DK4_SOCKET_RESULT_SUCCESS == res) {
1901 log_3(4, 5, adbuf);
1902 } else {
1903 log_1(3);
1904 }
1905 }
1906 (void)dk4socket_close(sock, NULL);
1907 } else {
1908 /* ERROR: Failed to open socket */
1909 log_1(6);
1910 }
1911 } else {
1912 if (0 == szr) {
1913 log_3(7, 8, hn);
1914 }
1915 if (0 == szl) {
1916 log_3(7, 8, hn);
1917 }
1918 if (AF_UNSPEC == af) {
1919 log_3(7, 8, hn);
1920 }
1921 if (PF_UNSPEC == pf) {
1922 log_3(7, 8, hn);
1923 }
1924 }
1925 } else {
1926 /* ERROR: Failed to obtain addresses */
1927 log_3(7, 8, hn);
1928 }
1929 (void)dk4socket_down(NULL);
1930 } else {
1931 /* ERROR: Failed to bring socket subsystem up */
1932 log_1(9);
1933 }
1934
1935 }
1936
1937
1938
1939 /** Send shutdown data packet.
1940 @param filenames Command line arguments array,
1941 0=remote host, 1=remote port, 2=filename.
1942 @param szfilenames Number of elements in filenames array.
1943 */
1944 static
1945 void
sender_with_signals(const char * const * filenames,size_t szfilenames)1946 sender_with_signals(const char * const *filenames, size_t szfilenames)
1947 {
1948 FILE *fipo = NULL; /* Data file */
1949 const char *ep = NULL; /* End of usefull data pointer */
1950 size_t lgt = 0; /* Number of bytes in buffer */
1951 int res = 0; /* Conversion or operation result */
1952
1953 if (3 == szfilenames) {
1954 res = dk4ma_input_c8_dec_ushort(&rp, filenames[1], &ep, 1, NULL);
1955 if (0 != res) {
1956 if (0 != rp) {
1957 lp = rp;
1958 if (0 != options[4].found) {
1959 if ((dk4_um_t)0UL < options[4].val.u) {
1960 if ((dk4_um_t)(USHRT_MAX) >= options[4].val.u) {
1961 lp = (unsigned short)(options[4].val.u);
1962 } else {
1963 lp = 0;
1964 /* ERROR: Local port number exceeds 16 bit unsigned range */
1965 log_1(27);
1966 }
1967 } else {
1968 lp = 0;
1969 /* ERROR: Local port number 0 is not allowed */
1970 log_1(28);
1971 }
1972 }
1973 if (0 != lp) {
1974 fipo = dk4fopen_c8(filenames[2], "rb", DK4_FOPEN_SC_IS_REGULAR, NULL);
1975 if (NULL != fipo) {
1976 lgt = fread(b1, 1, sizeof(b1), fipo);
1977 fclose(fipo);
1978 if (0 < lgt) {
1979 /* Send bytes over network */
1980 send_network(filenames[0], lgt);
1981 /* Overwrite memory containing data packet */
1982 if (0 == dk4mem_reset_secure(b1, sizeof(b1), NULL)) {
1983 exval = EXIT_FAILURE;
1984 }
1985 } else {
1986 /* ERROR: No data read from file */
1987 log_3(16, 17, filenames[2]);
1988 }
1989 } else {
1990 /* ERROR: Failed to open data file */
1991 log_3(14, 15, filenames[2]);
1992 }
1993 } else {
1994 }
1995 } else {
1996 /* ERROR: Remote port number 0 is not allowed */
1997 log_1(13);
1998 }
1999 } else {
2000 /* ERROR: Not a 16 bit unsigned number */
2001 log_3(11, 12, filenames[1]);
2002 }
2003 } else {
2004 /* ERROR: Three arguments required - host, port and file */
2005 log_1(10);
2006 }
2007
2008 }
2009
2010
2011
2012 /** Send shutdown data packet.
2013 @param filenames Command line arguments array,
2014 0=remote host, 1=remote port, 2=filename.
2015 @param szfilenames Number of elements in filenames array.
2016 */
2017 static
2018 void
sender(const char * const * filenames,size_t szfilenames)2019 sender(const char * const *filenames, size_t szfilenames)
2020 {
2021
2022
2023 #ifdef DK4_HAVE_SIGACTION
2024 #ifdef SIGPIPE
2025 struct sigaction opipe;
2026 struct sigaction npipe;
2027 #endif
2028 struct sigaction oint;
2029 struct sigaction nint;
2030 struct sigaction oterm;
2031 struct sigaction nterm;
2032 #else
2033 #ifdef SIGPIPE
2034 dk4_sig_handler_t *opipe = NULL;
2035 #endif
2036 dk4_sig_handler_t *oterm = NULL;
2037 dk4_sig_handler_t *oint = NULL;
2038 #endif
2039 #ifdef DK4_HAVE_SIGACTION
2040 #ifdef SIGPIPE
2041 int spipe = 0;
2042 #endif
2043 int sint = 0;
2044 int sterm = 0;
2045 int s_f_i = 0;
2046 int s_f_r = 0;
2047 #endif
2048
2049 /* Set signal handlers
2050 */
2051 #if DK4_HAVE_SIGACTION
2052 #ifdef SIGPIPE
2053 DK4_MEMRES(&npipe, sizeof(npipe));
2054 npipe.sa_handler = sig_handler_pipe;
2055 npipe.sa_flags = 0;
2056 if (0 != sigemptyset(&npipe.sa_mask)) {
2057 s_f_i = 1;
2058 goto finished;
2059 }
2060 if (0 != sigaddset(&npipe.sa_mask, SIGPIPE)) {
2061 s_f_i = 1;
2062 goto finished;
2063 }
2064 if (0 != sigaction(SIGPIPE, &npipe, &opipe)) {
2065 s_f_i = 1;
2066 goto finished;
2067 }
2068 spipe = 1;
2069 #endif
2070 DK4_MEMRES(&nterm, sizeof(nterm));
2071 nterm.sa_handler = sig_handler_term;
2072 nterm.sa_flags = 0;
2073 if (0 != sigemptyset(&nterm.sa_mask)) {
2074 s_f_i = 1;
2075 goto finished;
2076 }
2077 if (0 != sigaddset(&nterm.sa_mask, SIGTERM)) {
2078 s_f_i = 1;
2079 goto finished;
2080 }
2081 if (0 != sigaction(SIGTERM, &nterm, &oterm)) {
2082 s_f_i = 1;
2083 goto finished;
2084 }
2085 sterm = 1;
2086 DK4_MEMRES(&nint, sizeof(nint));
2087 nint.sa_handler = sig_handler_int;
2088 nint.sa_flags = 0;
2089 if (0 != sigemptyset(&nint.sa_mask)) {
2090 s_f_i = 1;
2091 goto finished;
2092 }
2093 if (0 != sigaddset(&nint.sa_mask, SIGINT)) {
2094 s_f_i = 1;
2095 goto finished;
2096 }
2097 if (0 != sigaction(SIGINT, &nint, &oint)) {
2098 s_f_i = 1;
2099 goto finished;
2100 }
2101 sint = 1;
2102 #else
2103 #ifdef SIGPIPE
2104 opipe = sigset(SIGPIPE, sig_handler_pipe);
2105 #endif
2106 oint = sigset(SIGINT, sig_handler_int);
2107 oterm = sigset(SIGTERM, sig_handler_term);
2108 #endif
2109
2110 /* Send the bytes.
2111 */
2112 sender_with_signals(filenames, szfilenames);
2113
2114 finished:
2115
2116 /* Restore signal handlers
2117 */
2118 #if DK4_HAVE_SIGACTION
2119 if (0 != s_f_i) {
2120 /* ERROR: Failed to install signal handlers */
2121 log_1(18);
2122 exval = EXIT_FAILURE;
2123 }
2124 if (0 != sint) {
2125 if (0 != sigaction(SIGINT, &oint, NULL)) {
2126 s_f_r = 1;
2127 }
2128 }
2129 if (0 != sterm) {
2130 if (0 != sigaction(SIGTERM, &oterm, NULL)) {
2131 s_f_r = 1;
2132 }
2133 }
2134 #ifdef SIGPIPE
2135 if (0 != spipe) {
2136 if (0 != sigaction(SIGPIPE, &opipe, NULL)) {
2137 s_f_r = 1;
2138 }
2139 }
2140 #endif
2141 if (0 != s_f_r) {
2142 /* ERROR: Failed to restore signal handlers */
2143 log_1(19);
2144 exval = EXIT_FAILURE;
2145 }
2146 #else
2147 if (NULL != oterm) { sigset(SIGTERM, oterm); }
2148 if (NULL != oint ) { sigset(SIGINT, oint ); }
2149 #ifdef SIGPIPE
2150 if (NULL != opipe) { sigset(SIGPIPE, opipe); }
2151 #endif
2152 #endif
2153
2154
2155 }
2156
2157
2158
2159 /** Run service
2160 */
2161 static
2162 void
run_daemon_loop(void)2163 run_daemon_loop(void)
2164 {
2165 dk4_allowed_peer_t peer; /* Allowed remote address */
2166 dk4_sockaddr_storage_t sa; /* Generic socket address */
2167 fd_set rfds; /* Readable file descriptors */
2168 dk4_socket_set_t *sset = NULL; /* Set of sockets to read data from */
2169 struct sockaddr *soa = NULL; /* Minimum socket address */
2170 struct sockaddr_in *so4 = NULL; /* IPv4 socket address */
2171 #if DK4_HAVE_STRUCT_SOCKADDR_IN6
2172 struct sockaddr_in6 *so6 = NULL; /* IPv6 socket address */
2173 #endif
2174 size_t szsa = 0; /* Size of sa */
2175 size_t i = 0; /* Traverse socket set */
2176 dk4_socket_t smax = 0; /* Maximum socket fd number */
2177 int cc = 1; /* Flag: Can continue */
2178 int pused = 0; /* Flag: Peer used */
2179 int res = 0; /* Operation result */
2180 int ok = 0; /* Flag: Data packet matches file */
2181 unsigned short frp = 0; /* Found remote port */
2182
2183 soa = (struct sockaddr *)(&sa);
2184 so4 = (struct sockaddr_in *)(&sa);
2185 #if DK4_HAVE_STRUCT_SOCKADDR_IN6
2186 so6 = (struct sockaddr_in6 *)(&sa);
2187 #endif
2188 if (DK4_SOCKET_RESULT_SUCCESS == dk4socket_up(NULL)) {
2189
2190 if (0 < strlen(asender)) {
2191 res = dk4socket_c8_get_allowed_peer(&peer, asender, NULL);
2192 if (DK4_SOCKET_RESULT_SUCCESS == res) {
2193 pused = 1;
2194 } else {
2195 cc = 0;
2196 /* SYSLOG ERROR: Invalid peer name */
2197 syslog_3(29, 30, asender);
2198 }
2199 }
2200 if (1 == cc) {
2201 sset = dk4socket_set_udp_directly(lp, 0, 0, NULL);
2202 if (NULL != sset) {
2203 /* SYSLOG: Started */
2204 #if DK4_HAVE_SYSLOG
2205 openlog(rshdown_kw[0], LOG_PID, syslogf);
2206 syslog(LOG_INFO, "%s", rshdown_kw[50]);
2207 closelog();
2208 #endif
2209 do {
2210 if (0 != can_continue()) {
2211 FD_ZERO(&rfds);
2212 smax = -1;
2213 for (i = 0; i < sset->szUsed; i++) {
2214
2215 FD_SET((sset->pSockets)[i],&rfds);
2216 if (smax < (sset->pSockets)[i]) { smax = (sset->pSockets)[i]; }
2217 }
2218 res = select((1+smax), &rfds, NULL, NULL, NULL);
2219 if (0 != can_continue()) {
2220 if (0 < res) {
2221 for (i = 0; ((1 == cc) && (i < sset->szUsed)); i++) {
2222
2223 if (FD_ISSET((sset->pSockets)[i],&rfds)) {
2224
2225 DK4_MEMRES(&sa, sizeof(sa));
2226 szb2 = sizeof(b2);
2227 szsa = sizeof(sa);
2228 res = dk4socket_recvfrom(
2229 (sset->pSockets)[i], b2, &szb2, 0,
2230 (struct sockaddr *)(&sa), &szsa, 0L, 0L, NULL
2231 );
2232 if (0 != can_continue()) {
2233 if (DK4_SOCKET_RESULT_SUCCESS == res) {
2234 if (0 < szb2) {
2235 ok = 1;
2236 if (0 != pused) {
2237 res = dk4socket_allowed_peer_compare(&peer, &sa, 1);
2238 if (0 != res) {
2239 ok = 0;
2240 /* SYSLOG DEBUG: Address mismatch */
2241 syslog_debug(53, 54, &sa);
2242 }
2243 }
2244 if (0U != rp) {
2245 frp = 0;
2246 switch (soa->sa_family) {
2247 case AF_INET : {
2248 frp = dk4socket_ntohs(so4->sin_port);
2249 } break;
2250 #if DK4_HAVE_STRUCT_SOCKADDR_IN6
2251 case AF_INET6 : {
2252 frp = dk4socket_ntohs(so6->sin6_port);
2253 } break;
2254 #endif
2255 }
2256 if (frp != rp) {
2257 ok = 0;
2258 /* SYSLOG DEBUG: Port mismatch */
2259 syslog_debug(55, 56, &sa);
2260 }
2261 }
2262 if (0 != ok) {
2263 ok = 0;
2264 if (szb1 == szb2) {
2265 if (0 == DK4_MEMCMP(b1,b2,szb1)) {
2266 ok = 1;
2267 } else {
2268 /* SYSLOG DEBUG: Data mismatch */
2269 syslog_debug(59, 60, &sa);
2270 }
2271 } else {
2272 /* SYSLOG DEBUG: Size mismatch */
2273 syslog_debug(57, 58, &sa);
2274 }
2275 }
2276 if (0 != ok) {
2277 /* Shutdown */
2278 /* SYSLOG: Initiating shutdown */
2279 #if DK4_HAVE_SYSLOG
2280 openlog(rshdown_kw[0], LOG_PID, syslogf);
2281 syslog(LOG_INFO, "%s", rshdown_kw[51]);
2282 closelog();
2283 #endif
2284 if (0 < strlen(cmd)) {
2285 if (0 != system(cmd)) {
2286 #if DK4_HAVE_SYSLOG
2287
2288 openlog(rshdown_kw[0], LOG_PID, syslogf);
2289 syslog(
2290 LOG_ERR, "%s%s%s",
2291 rshdown_kw[61], cmd, rshdown_kw[62]
2292 );
2293 closelog();
2294 #endif
2295 }
2296 } else {
2297 if (0 < signo) {
2298 kill((pid_t)1, signo);
2299 } else {
2300 #ifdef SIGPWR
2301 kill((pid_t)1, SIGPWR);
2302 #else
2303 #ifdef SIGTERM
2304 kill((pid_t)1, SIGTERM);
2305 #else
2306 kill((pid_t)1, 15);
2307 #endif
2308 #endif
2309 }
2310 }
2311 cc = 0;
2312 }
2313 } else {
2314 }
2315 } else {
2316 }
2317 } else {
2318 cc = -1;
2319 }
2320 } else {
2321 }
2322 }
2323 } else {
2324 }
2325 } else {
2326 cc = -1;
2327 }
2328 } else {
2329 cc = -1;
2330 }
2331 } while (1 == cc);
2332 dk4socket_set_close(sset, NULL);
2333 /* SYSLOG: Finished */
2334 #if DK4_HAVE_SYSLOG
2335 openlog(rshdown_kw[0], LOG_PID, syslogf);
2336 syslog(LOG_INFO, "%s", rshdown_kw[52]);
2337 closelog();
2338 #endif
2339 } else {
2340 /* SYSLOG ERROR: Failed to create socket set */
2341 syslog_1(26);
2342 }
2343 } else {
2344 }
2345 (void)dk4socket_down(NULL);
2346 } else {
2347 /* SYSLOG ERROR: Failed to bring socket subsystem up */
2348 syslog_1(25);
2349 }
2350
2351 }
2352
2353
2354
2355 /** Set signal handlers and run service.
2356 */
2357 static
2358 void
run_daemon_with_signals(void)2359 run_daemon_with_signals(void)
2360 {
2361 #ifdef DK4_HAVE_SIGACTION
2362 #ifdef SIGPIPE
2363 struct sigaction opipe;
2364 struct sigaction npipe;
2365 #endif
2366 struct sigaction oint;
2367 struct sigaction nint;
2368 struct sigaction oterm;
2369 struct sigaction nterm;
2370 #else
2371 #ifdef SIGPIPE
2372 dk4_sig_handler_t *opipe = NULL;
2373 #endif
2374 dk4_sig_handler_t *oterm = NULL;
2375 dk4_sig_handler_t *oint = NULL;
2376 #endif
2377 #ifdef DK4_HAVE_SIGACTION
2378 #ifdef SIGPIPE
2379 int spipe = 0;
2380 #endif
2381 int sint = 0;
2382 int sterm = 0;
2383 int s_f_i = 0;
2384 int s_f_r = 0;
2385 #endif
2386
2387 /* Set signal handlers
2388 */
2389 #if DK4_HAVE_SIGACTION
2390 #ifdef SIGPIPE
2391 DK4_MEMRES(&npipe, sizeof(npipe));
2392 npipe.sa_handler = sig_handler_pipe;
2393 npipe.sa_flags = 0;
2394 if (0 != sigemptyset(&npipe.sa_mask)) {
2395 s_f_i = 1;
2396 goto finished;
2397 }
2398 if (0 != sigaddset(&npipe.sa_mask, SIGPIPE)) {
2399 s_f_i = 1;
2400 goto finished;
2401 }
2402 if (0 != sigaction(SIGPIPE, &npipe, &opipe)) {
2403 s_f_i = 1;
2404 goto finished;
2405 }
2406 spipe = 1;
2407 #endif
2408 DK4_MEMRES(&nterm, sizeof(nterm));
2409 nterm.sa_handler = sig_handler_term;
2410 nterm.sa_flags = 0;
2411 if (0 != sigemptyset(&nterm.sa_mask)) {
2412 s_f_i = 1;
2413 goto finished;
2414 }
2415 if (0 != sigaddset(&nterm.sa_mask, SIGTERM)) {
2416 s_f_i = 1;
2417 goto finished;
2418 }
2419 if (0 != sigaction(SIGTERM, &nterm, &oterm)) {
2420 s_f_i = 1;
2421 goto finished;
2422 }
2423 sterm = 1;
2424 DK4_MEMRES(&nint, sizeof(nint));
2425 nint.sa_handler = sig_handler_int;
2426 nint.sa_flags = 0;
2427 if (0 != sigemptyset(&nint.sa_mask)) {
2428 s_f_i = 1;
2429 goto finished;
2430 }
2431 if (0 != sigaddset(&nint.sa_mask, SIGINT)) {
2432 s_f_i = 1;
2433 goto finished;
2434 }
2435 if (0 != sigaction(SIGINT, &nint, &oint)) {
2436 s_f_i = 1;
2437 goto finished;
2438 }
2439 sint = 1;
2440 #else
2441 #ifdef SIGPIPE
2442 opipe = sigset(SIGPIPE, sig_handler_pipe);
2443 #endif
2444 oint = sigset(SIGINT, sig_handler_int);
2445 oterm = sigset(SIGTERM, sig_handler_term);
2446 #endif
2447
2448 run_daemon_loop();
2449
2450 finished:
2451
2452 /* Restore signal handlers
2453 */
2454 #if DK4_HAVE_SIGACTION
2455 if (0 != s_f_i) {
2456 /* ERROR: Failed to install signal handlers */
2457 syslog_1(23);
2458 dk4dmt_error_sysfct(&dmt);
2459 }
2460 if (0 != sint) {
2461 if (0 != sigaction(SIGINT, &oint, NULL)) {
2462 s_f_r = 1;
2463 }
2464 }
2465 if (0 != sterm) {
2466 if (0 != sigaction(SIGTERM, &oterm, NULL)) {
2467 s_f_r = 1;
2468 }
2469 }
2470 #ifdef SIGPIPE
2471 if (0 != spipe) {
2472 if (0 != sigaction(SIGPIPE, &opipe, NULL)) {
2473 s_f_r = 1;
2474 }
2475 }
2476 #endif
2477 if (0 != s_f_r) {
2478 /* ERROR: Failed to restore signal handlers */
2479 syslog_1(24);
2480 dk4dmt_error_sysfct(&dmt);
2481 }
2482 #else
2483 if (NULL != oterm) { sigset(SIGTERM, oterm); }
2484 if (NULL != oint ) { sigset(SIGINT, oint ); }
2485 #ifdef SIGPIPE
2486 if (NULL != opipe) { sigset(SIGPIPE, opipe); }
2487 #endif
2488 #endif
2489
2490 }
2491
2492
2493
2494 /** Retrieve port number from a configuration file line.
2495 @param dest Address of destination variable.
2496 @param pv String containing the port number.
2497 @param a0 Flag: Remote port, 0 allowed for arbitrary ports.
2498 @return 1 on success, 0 on error.
2499 */
2500 static
2501 int
set_port_number(unsigned short * dest,const char * pv,int a0)2502 set_port_number(
2503 unsigned short *dest,
2504 const char *pv,
2505 int a0
2506 )
2507 {
2508 const char *ep = NULL;
2509 int back = 0;
2510 unsigned short us = 0U;
2511
2512 if (0 != dk4ma_input_c8_dec_ushort(&us, pv, &ep, 1, NULL)) {
2513 if (0U != us) {
2514 *dest = us;
2515 back = 1;
2516 } else {
2517 if (0 != a0) {
2518 *dest = us;
2519 back = 1;
2520 } else {
2521 /* ERROR: Port number 0 not allowed! */
2522 log_1(28);
2523 }
2524 }
2525 } else {
2526 /* ERROR: Not a 16 bit unsigned number! */
2527 log_3(11, 12, pv);
2528 }
2529 return back;
2530 }
2531
2532
2533
2534 /** Set the signal number.
2535 @param pv Text containing the number.
2536 @return 1 on success, 0 on error.
2537 */
2538 static
2539 int
set_signal_number(const char * pv)2540 set_signal_number(const char *pv)
2541 {
2542 int back = 1;
2543
2544 switch ( dk4str8_array_index(signal_names, pv, 0) ) {
2545 case 0 : case 1 : {
2546 #ifdef SIGHUP
2547 signo = SIGHUP;
2548 #else
2549 signo = 1;
2550 #endif
2551 } break;
2552 case 2 : case 3 : {
2553 #ifdef SIGINT
2554 signo = SIGINT;
2555 #else
2556 signo = 2;
2557 #endif
2558 } break;
2559 case 4 : case 5 : {
2560 #ifdef SIGQUIT
2561 signo = SIGQUIT;
2562 #else
2563 signo = 3;
2564 #endif
2565 } break;
2566 case 6 : case 7 : {
2567 #ifdef SIGILL
2568 signo = SIGILL;
2569 #else
2570 signo = 4;
2571 #endif
2572 } break;
2573 case 8 : case 9 : {
2574 #ifdef SIGTRAP
2575 signo = SIGTRAP;
2576 #else
2577 signo = 5;
2578 #endif
2579 } break;
2580 case 10 : case 11 : case 12 : case 13 : {
2581 #ifdef SIGABRT
2582 signo = SIGABRT;
2583 #else
2584 #ifdef SIGIOT
2585 signo = SIGIOT;
2586 #else
2587 signo = 6;
2588 #endif
2589 #endif
2590 } break;
2591 case 14 : case 15 : {
2592 #ifdef SIGBUS
2593 signo = SIGBUS;
2594 #else
2595 signo = 7;
2596 #endif
2597 } break;
2598 case 16 : case 17 : {
2599 #ifdef SIGFPE
2600 signo = SIGFPE;
2601 #else
2602 signo = 8;
2603 #endif
2604 } break;
2605 case 18 : case 19 : {
2606 #ifdef SIGKILL
2607 signo = SIGKILL;
2608 #else
2609 signo = 9;
2610 #endif
2611 } break;
2612 case 20 : case 21 : {
2613 #ifdef SIGUSR1
2614 signo = SIGUSR1;
2615 #else
2616 signo = 10;
2617 #endif
2618 } break;
2619 case 22 : case 23 : {
2620 #ifdef SIGSEGV
2621 signo = SIGSEGV;
2622 #else
2623 signo = 11;
2624 #endif
2625 } break;
2626 case 24 : case 25 : {
2627 #ifdef SIGUSR2
2628 signo = SIGUSR2;
2629 #else
2630 signo = 12;
2631 #endif
2632 } break;
2633 case 26 : case 27 : {
2634 #ifdef SIGPIPE
2635 signo = SIGPIPE;
2636 #else
2637 signo = 13;
2638 #endif
2639 } break;
2640 case 28 : case 29 : {
2641 #ifdef SIGALRM
2642 signo = SIGALRM;
2643 #else
2644 signo = 14;
2645 #endif
2646 } break;
2647 case 30 : case 31 : {
2648 #ifdef SIGTERM
2649 signo = SIGTERM;
2650 #else
2651 signo = 15;
2652 #endif
2653 } break;
2654 case 32 : case 33 : {
2655 #ifdef SIGSTKFLT
2656 signo = SIGSTKFLT;
2657 #else
2658 signo = 16;
2659 #endif
2660 } break;
2661 case 34 : case 35 : case 36 : case 37 : {
2662 #ifdef SIGCLD
2663 signo = SIGCLD;
2664 #else
2665 #ifdef SIGCHLD
2666 signo = SIGCHLD;
2667 #else
2668 signo = 17;
2669 #endif
2670 #endif
2671 } break;
2672 case 38 : case 39 : {
2673 #ifdef SIGCONT
2674 signo = SIGCONT;
2675 #else
2676 signo = 18;
2677 #endif
2678 } break;
2679 case 40 : case 41 : {
2680 #ifdef SIGSTOP
2681 signo = SIGSTOP;
2682 #else
2683 signo = 19;
2684 #endif
2685 } break;
2686 case 42 : case 43 : {
2687 #ifdef SIGTSTP
2688 signo = SIGTSTP;
2689 #else
2690 signo = 20;
2691 #endif
2692 } break;
2693 case 44 : case 45 : {
2694 #ifdef SIGTTIN
2695 signo = SIGTTIN;
2696 #else
2697 signo = 21;
2698 #endif
2699 } break;
2700 case 46 : case 47 : {
2701 #ifdef SIGTTOU
2702 signo = SIGTTOU;
2703 #else
2704 signo = 22;
2705 #endif
2706 } break;
2707 case 48 : case 49 : {
2708 #ifdef SIGURG
2709 signo = SIGURG;
2710 #else
2711 signo = 23;
2712 #endif
2713 } break;
2714 case 50 : case 51 : {
2715 #ifdef SIGXCPU
2716 signo = SIGXCPU;
2717 #else
2718 signo = 24;
2719 #endif
2720 } break;
2721 case 52 : case 53 : {
2722 #ifdef SIGXFSZ
2723 signo = SIGXFSZ;
2724 #else
2725 signo = 25;
2726 #endif
2727 } break;
2728 case 54 : case 55 : {
2729 #ifdef SIGVTALRM
2730 signo = SIGVTALRM;
2731 #else
2732 signo = 26;
2733 #endif
2734 } break;
2735 case 56 : case 57 : {
2736 #ifdef SIGPROF
2737 signo = SIGPROF;
2738 #else
2739 signo = 27;
2740 #endif
2741 } break;
2742 case 58 : case 59 : {
2743 #ifdef SIGWINCH
2744 signo = SIGWINCH;
2745 #else
2746 signo = 28;
2747 #endif
2748 } break;
2749 case 60 : case 61 : case 62 : case 63 : {
2750 #ifdef SIGPOLL
2751 signo = SIGPOLL;
2752 #else
2753 #ifdef SIGIO
2754 signo = SIGIO
2755 #else
2756 signo = 29;
2757 #endif
2758 #endif
2759 } break;
2760 case 64 : case 65 : {
2761 #ifdef SIGPWR
2762 signo = SIGPWR;
2763 #else
2764 signo = 30;
2765 #endif
2766 } break;
2767 case 66 : case 67 : {
2768 #ifdef SIGSYS
2769 signo = SIGSYS;
2770 #else
2771 signo = 31;
2772 #endif
2773 } break;
2774 default : {
2775 back = 0;
2776 /* ERROR: Illegal signal name */
2777 log_3(31, 32, pv);
2778 } break;
2779 }
2780 return back;
2781 }
2782
2783
2784
2785 /** Set syslog facility.
2786 @param pv Text representation of syslog facility.
2787 @return 1 on success, 0 on error.
2788 */
2789 static
2790 int
set_syslog_facility(const char * pv)2791 set_syslog_facility(const char *pv)
2792 {
2793 int back = 1;
2794 if (NULL != pv) {
2795 switch ( dk4str8_array_index(syslog_facility_names, pv, 0) ) {
2796 #ifdef LOG_AUTH
2797 case 0: { syslogf = LOG_AUTH; } break;
2798 #endif
2799 #ifdef LOG_AUTHPRIV
2800 case 1: { syslogf = LOG_AUTHPRIV; } break;
2801 #endif
2802 #ifdef LOG_CRON
2803 case 2: { syslogf = LOG_CRON; } break;
2804 #endif
2805 #ifdef LOG_DAEMON
2806 case 3: { syslogf = LOG_DAEMON; } break;
2807 #endif
2808 #ifdef LOG_FTP
2809 case 4: { syslogf = LOG_FTP; } break;
2810 #endif
2811 #ifdef LOG_KERN
2812 case 5: { syslogf = LOG_KERN; } break;
2813 #endif
2814 #ifdef LOG_LPR
2815 case 6: { syslogf = LOG_LPR; } break;
2816 #endif
2817 #ifdef LOG_MAIL
2818 case 7: { syslogf = LOG_MAIL; } break;
2819 #endif
2820 #ifdef LOG_NEWS
2821 case 8: { syslogf = LOG_NEWS; } break;
2822 #endif
2823 #ifdef LOG_AUTH
2824 case 9: { syslogf = LOG_AUTH; } break;
2825 #endif
2826 #ifdef LOG_SYSLOG
2827 case 10: { syslogf = LOG_SYSLOG; } break;
2828 #endif
2829 #ifdef LOG_USER
2830 case 11: { syslogf = LOG_USER; } break;
2831 #endif
2832 #ifdef LOG_UUCP
2833 case 12: { syslogf = LOG_UUCP; } break;
2834 #endif
2835 #ifdef LOG_LOCAL0
2836 case 13: { syslogf = LOG_LOCAL0; } break;
2837 #endif
2838 #ifdef LOG_LOCAL1
2839 case 14: { syslogf = LOG_LOCAL1; } break;
2840 #endif
2841 #ifdef LOG_LOCAL2
2842 case 15: { syslogf = LOG_LOCAL2; } break;
2843 #endif
2844 #ifdef LOG_LOCAL3
2845 case 16: { syslogf = LOG_LOCAL3; } break;
2846 #endif
2847 #ifdef LOG_LOCAL4
2848 case 17: { syslogf = LOG_LOCAL4; } break;
2849 #endif
2850 #ifdef LOG_LOCAL5
2851 case 18: { syslogf = LOG_LOCAL5; } break;
2852 #endif
2853 #ifdef LOG_LOCAL6
2854 case 19: { syslogf = LOG_LOCAL6; } break;
2855 #endif
2856 #ifdef LOG_LOCAL7
2857 case 20: { syslogf = LOG_LOCAL7; } break;
2858 #endif
2859 default: {
2860 back = 0;
2861 log_3(48, 49, pv);
2862 } break;
2863 }
2864 }
2865 return back;
2866 }
2867
2868
2869
2870 /** Read configuration file.
2871 @return 1 on success, 0 on error.
2872 */
2873 static
2874 int
read_config_file(void)2875 read_config_file(void)
2876 {
2877 FILE *fipo = NULL; /* Input file to process */
2878 const char *fn = NULL; /* Input file name */
2879 const char *ep = NULL; /* End pointer after number */
2880 char *pk = NULL; /* Pointer to key string */
2881 char *pv = NULL; /* Pointer to value string */
2882 dk4_um_t lineno = (dk4_um_t)0UL; /* Current line number */
2883 int back = 0;
2884
2885 if (0 != options[0].found) { fn = options[0].val.t; }
2886 if (NULL == fn) { fn = def_conf_name; }
2887 fipo = dk4fopen_c8(fn, "r", DK4_FOPEN_SC_IS_REGULAR, NULL);
2888 if (NULL != fipo) {
2889 back = 1;
2890 while( fgets(b1, sizeof(b1), fipo) ) {
2891 lineno++;
2892 pk = dk4str8_start(b1, NULL);
2893 if (NULL != pk) {
2894 if ('#' != *pk) {
2895 pv = dk4str8_chr(pk, '=');
2896 if (NULL != pv) {
2897 *(pv++) = '\0';
2898 pv = dk4str8_start(pv, NULL);
2899 if (NULL != pv) {
2900 dk4str8_normalize(pk, NULL);
2901 dk4str8_delnl(pv);
2902 switch ( dk4str8_array_index(key_names, pk, 0) ) {
2903 case 0: { /* sender address */
2904 if (0 == strlen(asender)) {
2905 dk4str8_normalize(pv, NULL);
2906 if (0 == dk4str8_cpy_s(asender,sizeof(asender),pv,NULL)) {
2907 back = 0;
2908 /* ERROR: Sender name too long */
2909 log_3(33, 34, pv);
2910 }
2911 } else {
2912 back = 0;
2913 /* ERROR: Redefinition of sender */
2914 log_1(35);
2915 }
2916 } break;
2917 case 1: { /* sender port */
2918 if (0 == set_port_number(&rp, pv, 1)) {
2919 back = 0;
2920 }
2921 } break;
2922 case 2: { /* local port */
2923 if (0 == set_port_number(&lp, pv, 0)) {
2924 back = 0;
2925 }
2926 } break;
2927 case 3: { /* signal */
2928 ep = NULL;
2929 if (0 != dk4ma_input_c8_dec_int(&signo, pv, &ep, 1, NULL)) {
2930 if (1 > signo) {
2931 back = 0;
2932 /* ERROR: Signal number must be positive */
2933 log_1(36);
2934 }
2935 } else {
2936 dk4str8_normalize(pv, NULL);
2937 if (0 == set_signal_number(pv)) {
2938 back = 0;
2939 }
2940 }
2941 } break;
2942 case 4: { /* command */
2943 if (0 == strlen(cmd)) {
2944 if (0 == dk4str8_cpy_s(cmd, sizeof(cmd), pv, NULL)) {
2945 back = 0;
2946 /* ERROR: Command too long! */
2947 log_3(37, 38, pv);
2948 }
2949 } else {
2950 back = 0;
2951 /* ERROR: Redefinition of command */
2952 log_1(39);
2953 }
2954 } break;
2955 case 5: { /* file */
2956 if (0 == strlen(file_name)) {
2957 if (0 == dk4str8_cpy_s(file_name,sizeof(file_name),pv,NULL))
2958 {
2959 back = 0;
2960 /* ERROR: File name too long! */
2961 log_3(40, 41, pv);
2962 }
2963 } else {
2964 back = 0;
2965 /* ERROR: Redefinition of file name */
2966 log_1(42);
2967 }
2968 } break;
2969 case 6: {
2970 debug = ((dk4str8_is_on(pv)) ? 1 : 0);
2971 } break;
2972 case 7: {
2973 dk4str8_normalize(pv, NULL);
2974 if (0 == set_syslog_facility(pv)) {
2975 back = 0;
2976 }
2977 } break;
2978 default : {
2979 log_1(43);
2980 } break;
2981 }
2982 } else {
2983 back = 0;
2984 /* ERROR: Missing value */
2985 log_1(44);
2986 }
2987 } else {
2988 back = 0;
2989 /* ERROR: Missing value */
2990 log_1(44);
2991 }
2992 }
2993 }
2994 }
2995 fclose(fipo);
2996 if ((0 != back) && (0U == lp)) {
2997 back = 0;
2998 /* ERROR: Local port not specified */
2999 log_1(45);
3000 }
3001 if (0 != back) {
3002 if ((0 == signo) && (0 == strlen(cmd))) {
3003 back = 0;
3004 /* ERROR: Signal or command required */
3005 log_1(46);
3006 }
3007 }
3008 if (0 != back) {
3009 if (0 != strlen(file_name)) {
3010 fipo = dk4fopen_c8(file_name, "rb", DK4_FOPEN_SC_IS_REGULAR, NULL);
3011 if (NULL != fipo) {
3012 szb1 = fread(b1, 1, sizeof(b1), fipo);
3013 fclose(fipo);
3014 if (0 == szb1) {
3015 back = 0;
3016 /* ERROR: Failed to read data from file */
3017 log_3(16, 17, file_name);
3018 }
3019 } else {
3020 back = 0;
3021 /* ERROR: Failed to open data file */
3022 log_3(14, 15, file_name);
3023 }
3024 } else {
3025 back = 0;
3026 /* ERROR: No data file specified */
3027 log_1(47);
3028 }
3029 }
3030 } else {
3031 }
3032 return back;
3033 }
3034
3035
3036 /** Daemon waiting for shutdown data packet.
3037 */
3038 static
3039 void
run_as_daemon(void)3040 run_as_daemon(void)
3041 {
3042 pid_t cpid;
3043
3044 dk4dmt_init(&dmt);
3045
3046 /* Preparations before we start.
3047 */
3048 DK4_MEMRES(cmd, sizeof(cmd));
3049 DK4_MEMRES(asender, sizeof(asender));
3050 DK4_MEMRES(file_name, sizeof(file_name));
3051 if (read_config_file()) {
3052 dk4dmt_set_program(&dmt, rshdown_kw[0]);
3053 dk4dmt_set_pidfile(&dmt, pid_file_name);
3054 dk4dmt_set_syslog_feature(&dmt, syslogf);
3055 if (0 != dk4dmt_parent_before_fork(&dmt)) {
3056 cpid = fork();
3057 if ((pid_t)0 == cpid) { /* in the child */
3058 if (0 != dk4dmt_intermediate_before_fork(&dmt)) {
3059 cpid = fork();
3060 if ((pid_t)0 == cpid) { /* in the child */
3061
3062
3063 dk4dmt_success(&dmt);
3064 if (0 != dk4dmt_daemon_start(&dmt)) {
3065 run_daemon_with_signals();
3066 }
3067 dk4dmt_daemon_end(&dmt);
3068 if (0 == dk4mem_reset_secure(b1, sizeof(b1), NULL)) {
3069 dk4dmt_error_sysfct(&dmt);
3070 }
3071 if (0 == dk4mem_reset_secure(b2, sizeof(b2), NULL)) {
3072 dk4dmt_error_sysfct(&dmt);
3073 }
3074
3075
3076 } else {
3077 if ((pid_t)(-1) != cpid) { /* intermediate process */
3078 dk4dmt_success(&dmt);
3079 if (0 == dk4mem_reset_secure(b1, sizeof(b1), NULL)) {
3080 dk4dmt_error_sysfct(&dmt);
3081 }
3082 if (0 == dk4mem_reset_secure(b2, sizeof(b2), NULL)) {
3083 dk4dmt_error_sysfct(&dmt);
3084 }
3085 dk4dmt_intermediate_after_fork(&dmt);
3086 } else { /* error */
3087 if (0 == dk4mem_reset_secure(b1, sizeof(b1), NULL)) {
3088 dk4dmt_error_sysfct(&dmt);
3089 }
3090 if (0 == dk4mem_reset_secure(b2, sizeof(b2), NULL)) {
3091 dk4dmt_error_sysfct(&dmt);
3092 }
3093 /* SYSLOG ERROR: Failed to create child process */
3094 syslog_1(22);
3095 dk4dmt_intermediate_fork_failed(&dmt);
3096 }
3097 }
3098 } else {
3099 if (0 == dk4mem_reset_secure(b1, sizeof(b1), NULL)) {
3100 dk4dmt_error_sysfct(&dmt);
3101 }
3102 if (0 == dk4mem_reset_secure(b2, sizeof(b2), NULL)) {
3103 dk4dmt_error_sysfct(&dmt);
3104 }
3105 /* SYSLOG ERROR: Failed to detach */
3106 syslog_1(21);
3107 }
3108 } else {
3109 if ((pid_t)(-1) != cpid) { /* parent */
3110 dk4dmt_parent_after_fork(&dmt);
3111 } else { /* error */
3112 /* ERROR: Failed to create child process */
3113 dk4dmt_parent_fork_failed(&dmt);
3114 log_1(20);
3115 }
3116 }
3117 }
3118 }
3119 else {
3120 dk4dmt_error_config(&dmt);
3121 }
3122 if (0 == dk4mem_reset_secure(b1, sizeof(b1), NULL)) {
3123 dk4dmt_error_sysfct(&dmt);
3124 }
3125 if (0 == dk4mem_reset_secure(b2, sizeof(b2), NULL)) {
3126 dk4dmt_error_sysfct(&dmt);
3127 }
3128 exval = dk4dmt_get_exit_status(&dmt);
3129
3130 }
3131
3132
3133
3134 /** Show a text paragraph on standard output.
3135 @param txt Text to show.
3136 */
3137 static
3138 void
show_text(const char * const * txt)3139 show_text(const char * const *txt)
3140 {
3141 if (NULL != txt) {
3142 while (NULL != *txt) {
3143 fputs(*(txt++), stdout);
3144 fputc('\n', stdout);
3145 }
3146 fflush(stdout);
3147 }
3148 }
3149
3150
3151
3152 /** Handle --help, --version, --license options.
3153 */
3154 static
3155 void
run_hvl(void)3156 run_hvl(void)
3157 {
3158 if (0 != (1 & hvl)) {
3159 show_text(help_text);
3160 }
3161 if (0 != (2 & hvl)) {
3162 fputs(version_text, stdout);
3163 fputc('\n', stdout);
3164 fflush(stdout);
3165 }
3166 if (0 != (4 & hvl)) {
3167 show_text(license_text);
3168 }
3169 }
3170
3171
3172
3173 /** Program entry point.
3174 @param argc
3175 @param argv
3176 @return 0 on success, any other value indicates an error.
3177 */
3178 int
main(int argc,char * argv[])3179 main(int argc, char *argv[])
3180 {
3181 char *filenames[32];
3182 size_t szfilenames = 32; /* Array size */
3183 int res = 0; /* Operation result */
3184
3185
3186 /* Process command line arguments.
3187 */
3188 res = dk4opt_process_argv(
3189 options, szoptions, argc, argv, filenames, &szfilenames, 1, 1, NULL
3190 );
3191 if (0 == res) {
3192 goto finished;
3193 }
3194
3195 /* Check help, version, license.
3196 */
3197 if (0 != options[5].found) { hvl |= 1; }
3198 if (0 != options[6].found) { hvl |= 2; }
3199 if (0 != options[7].found) { hvl |= 4; }
3200 if (0 != hvl) {
3201 run_hvl();
3202 goto finished;
3203 }
3204
3205 /* Either send data or run as daemon to receive data.
3206 */
3207 if (0 != options[1].found) {
3208 sender((const char * const *)filenames, szfilenames);
3209 } else {
3210 run_as_daemon();
3211 }
3212
3213 finished:
3214
3215 exit(exval); return exval;
3216 }
3217
3218
3219 #else
3220
3221
3222 /** Program entry point.
3223 @param argc
3224 @param argv
3225 @return 0 on success, any other value indicates an error.
3226 */
3227 int
main(int argc,char * argv[])3228 main(int argc, char *argv[])
3229 {
3230 fputs("rshdown: ERROR: Build requirements violation!\n", stderr);
3231 #if DK4_CHAR_SIZE > 1
3232 fputs("Default character size is larger than 1!\n", stderr);
3233 #endif
3234 #if !((DK4_HAVE_SIGACTION) || (DK4_HAVE_SIGSET))
3235 fputs("Neither sigaction() nor sigset() are available!\n", stderr);
3236 #endif
3237 #if !((DK4_HAVE_SETSID) || (DK4_HAVE_SETPGRP))
3238 fputs("Neither setsid() nor setpgrp() are available!\n", stderr);
3239 #endif
3240 fflush(stderr);
3241 exit(EXIT_FAILURE); return EXIT_FAILURE;
3242 }
3243
3244 #endif
3245
3246
3247 #endif
3248 /* defined(_WIN32) || defined(WIN32) || defined(_WIN64) || defined(WIN64) */
3249
3250
3251 /* vim: set ai sw=4 ts=4 : */
3252
3253