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