Deleted Added
sdiff udiff text old ( 106163 ) new ( 132451 )
full compact
1/*
2 * ntpd.c - main program for the fixed point NTP daemon
3 */
4
5#ifdef HAVE_CONFIG_H
6# include <config.h>
7#endif
8
9#include "ntp_machine.h"
10#include "ntpd.h"
11#include "ntp_io.h"
12#include "ntp_stdlib.h"
13
14#ifdef SIM
15#include "ntpsim.h"
16#endif
17
18#ifdef HAVE_UNISTD_H
19# include <unistd.h>
20#endif
21#ifdef HAVE_SYS_STAT_H
22# include <sys/stat.h>
23#endif
24#include <stdio.h>
25#ifndef SYS_WINNT
26# if !defined(VMS) /*wjm*/
27# ifdef HAVE_SYS_PARAM_H
28# include <sys/param.h>
29# endif
30# endif /* VMS */
31# ifdef HAVE_SYS_SIGNAL_H
32# include <sys/signal.h>
33# else
34# include <signal.h>
35# endif
36# ifdef HAVE_SYS_IOCTL_H
37# include <sys/ioctl.h>
38# endif /* HAVE_SYS_IOCTL_H */
39# ifdef HAVE_SYS_RESOURCE_H
40# include <sys/resource.h>
41# endif /* HAVE_SYS_RESOURCE_H */
42#else
43# include <signal.h>
44# include <process.h>
45# include <io.h>
46# include "../libntp/log.h"
47# include <clockstuff.h>
48# include <crtdbg.h>
49#endif /* SYS_WINNT */
50#if defined(HAVE_RTPRIO)
51# ifdef HAVE_SYS_RESOURCE_H
52# include <sys/resource.h>
53# endif
54# ifdef HAVE_SYS_LOCK_H
55# include <sys/lock.h>
56# endif
57# include <sys/rtprio.h>
58#else
59# ifdef HAVE_PLOCK
60# ifdef HAVE_SYS_LOCK_H
61# include <sys/lock.h>
62# endif
63# endif
64#endif
65#if defined(HAVE_SCHED_SETSCHEDULER)
66# ifdef HAVE_SCHED_H
67# include <sched.h>
68# else
69# ifdef HAVE_SYS_SCHED_H
70# include <sys/sched.h>
71# endif
72# endif
73#endif
74#if defined(HAVE_SYS_MMAN_H)
75# include <sys/mman.h>
76#endif
77
78#ifdef HAVE_TERMIOS_H
79# include <termios.h>
80#endif
81
82#ifdef SYS_DOMAINOS
83# include <apollo/base.h>
84#endif /* SYS_DOMAINOS */
85
86#include "recvbuff.h"
87#include "ntp_cmdargs.h"
88
89#if 0 /* HMS: I don't think we need this. 961223 */
90#ifdef LOCK_PROCESS
91# ifdef SYS_SOLARIS
92# include <sys/mman.h>
93# else
94# include <sys/lock.h>
95# endif
96#endif
97#endif
98
99#ifdef _AIX
100# include <ulimit.h>
101#endif /* _AIX */
102
103#ifdef SCO5_CLOCK
104# include <sys/ci/ciioctl.h>
105#endif
106
107#ifdef HAVE_CLOCKCTL
108# include <ctype.h>
109# include <grp.h>
110# include <pwd.h>
111#endif
112
113/*
114 * Signals we catch for debugging. If not debugging we ignore them.
115 */
116#define MOREDEBUGSIG SIGUSR1
117#define LESSDEBUGSIG SIGUSR2
118
119/*
120 * Signals which terminate us gracefully.
121 */
122#ifndef SYS_WINNT
123# define SIGDIE1 SIGHUP
124# define SIGDIE3 SIGQUIT
125# define SIGDIE2 SIGINT
126# define SIGDIE4 SIGTERM
127#endif /* SYS_WINNT */
128
129#if defined SYS_WINNT
130/* handles for various threads, process, and objects */
131HANDLE ResolverThreadHandle = NULL;
132/* variables used to inform the Service Control Manager of our current state */
133BOOL NoWinService = FALSE;
134SERVICE_STATUS ssStatus;
135SERVICE_STATUS_HANDLE sshStatusHandle;
136HANDLE WaitHandles[3] = { NULL, NULL, NULL };
137char szMsgPath[255];
138static BOOL WINAPI OnConsoleEvent(DWORD dwCtrlType);
139BOOL init_randfile();
140#endif /* SYS_WINNT */
141
142/*
143 * Scheduling priority we run at
144 */
145#define NTPD_PRIO (-12)
146
147int priority_done = 2; /* 0 - Set priority */
148 /* 1 - priority is OK where it is */
149 /* 2 - Don't set priority */
150 /* 1 and 2 are pretty much the same */
151
152/*
153 * Debugging flag
154 */
155volatile int debug;
156
157/*
158 * Set the processing not to be in the forground
159 */
160int forground_process = FALSE;
161
162/*
163 * No-fork flag. If set, we do not become a background daemon.
164 */
165int nofork;
166
167#ifdef HAVE_CLOCKCTL
168char *user = NULL; /* User to switch to */
169char *group = NULL; /* group to switch to */
170char *chrootdir = NULL; /* directory to chroot to */
171int sw_uid;
172int sw_gid;
173char *endp;
174struct group *gr;
175struct passwd *pw;
176#endif /* HAVE_CLOCKCTL */
177
178/*
179 * Initializing flag. All async routines watch this and only do their
180 * thing when it is clear.
181 */
182int initializing;
183
184/*
185 * Version declaration
186 */
187extern const char *Version;
188
189int was_alarmed;
190
191#ifdef DECL_SYSCALL
192/*
193 * We put this here, since the argument profile is syscall-specific
194 */
195extern int syscall P((int, ...));
196#endif /* DECL_SYSCALL */
197
198
199#ifdef SIGDIE2
200static RETSIGTYPE finish P((int));
201#endif /* SIGDIE2 */
202
203#ifdef DEBUG
204#ifndef SYS_WINNT
205static RETSIGTYPE moredebug P((int));
206static RETSIGTYPE lessdebug P((int));
207#endif
208#else /* not DEBUG */
209static RETSIGTYPE no_debug P((int));
210#endif /* not DEBUG */
211
212int ntpdmain P((int, char **));
213static void set_process_priority P((void));
214
215#ifdef SIM
216int
217main(
218 int argc,
219 char *argv[]
220 )
221{
222 return ntpsim(argc, argv);
223}
224#else /* SIM */
225#ifdef NO_MAIN_ALLOWED
226CALL(ntpd,"ntpd",ntpdmain);
227#else
228int
229main(
230 int argc,
231 char *argv[]
232 )
233{
234 return ntpdmain(argc, argv);
235}
236#endif
237#endif /* SIM */
238
239#ifdef _AIX
240/*
241 * OK. AIX is different than solaris in how it implements plock().
242 * If you do NOT adjust the stack limit, you will get the MAXIMUM
243 * stack size allocated and PINNED with you program. To check the
244 * value, use ulimit -a.
245 *
246 * To fix this, we create an automatic variable and set our stack limit
247 * to that PLUS 32KB of extra space (we need some headroom).
248 *
249 * This subroutine gets the stack address.
250 *
251 * Grover Davidson and Matt Ladendorf
252 *
253 */
254static char *
255get_aix_stack(void)
256{
257 char ch;
258 return (&ch);
259}
260
261/*
262 * Signal handler for SIGDANGER.
263 */
264static void
265catch_danger(int signo)
266{
267 msyslog(LOG_INFO, "ntpd: setpgid(): %m");
268 /* Make the system believe we'll free something, but don't do it! */
269 return;
270}
271#endif /* _AIX */
272
273/*
274 * Set the process priority
275 */
276static void
277set_process_priority(void)
278{
279
280#ifdef DEBUG
281 if (debug > 1)
282 msyslog(LOG_DEBUG, "set_process_priority: %s: priority_done is <%d>",
283 ((priority_done)
284 ? "Leave priority alone"
285 : "Attempt to set priority"
286 ),
287 priority_done);
288#endif /* DEBUG */
289
290#ifdef SYS_WINNT
291 priority_done += NT_set_process_priority();
292#endif
293
294#if defined(HAVE_SCHED_SETSCHEDULER)
295 if (!priority_done) {
296 extern int config_priority_override, config_priority;
297 int pmax, pmin;
298 struct sched_param sched;
299
300 pmax = sched_get_priority_max(SCHED_FIFO);
301 sched.sched_priority = pmax;
302 if ( config_priority_override ) {
303 pmin = sched_get_priority_min(SCHED_FIFO);
304 if ( config_priority > pmax )
305 sched.sched_priority = pmax;
306 else if ( config_priority < pmin )
307 sched.sched_priority = pmin;
308 else
309 sched.sched_priority = config_priority;
310 }
311 if ( sched_setscheduler(0, SCHED_FIFO, &sched) == -1 )
312 msyslog(LOG_ERR, "sched_setscheduler(): %m");
313 else
314 ++priority_done;
315 }
316#endif /* HAVE_SCHED_SETSCHEDULER */
317#if defined(HAVE_RTPRIO)
318# ifdef RTP_SET
319 if (!priority_done) {
320 struct rtprio srtp;
321
322 srtp.type = RTP_PRIO_REALTIME; /* was: RTP_PRIO_NORMAL */
323 srtp.prio = 0; /* 0 (hi) -> RTP_PRIO_MAX (31,lo) */
324
325 if (rtprio(RTP_SET, getpid(), &srtp) < 0)
326 msyslog(LOG_ERR, "rtprio() error: %m");
327 else
328 ++priority_done;
329 }
330# else /* not RTP_SET */
331 if (!priority_done) {
332 if (rtprio(0, 120) < 0)
333 msyslog(LOG_ERR, "rtprio() error: %m");
334 else
335 ++priority_done;
336 }
337# endif /* not RTP_SET */
338#endif /* HAVE_RTPRIO */
339#if defined(NTPD_PRIO) && NTPD_PRIO != 0
340# ifdef HAVE_ATT_NICE
341 if (!priority_done) {
342 errno = 0;
343 if (-1 == nice (NTPD_PRIO) && errno != 0)
344 msyslog(LOG_ERR, "nice() error: %m");
345 else
346 ++priority_done;
347 }
348# endif /* HAVE_ATT_NICE */
349# ifdef HAVE_BSD_NICE
350 if (!priority_done) {
351 if (-1 == setpriority(PRIO_PROCESS, 0, NTPD_PRIO))
352 msyslog(LOG_ERR, "setpriority() error: %m");
353 else
354 ++priority_done;
355 }
356# endif /* HAVE_BSD_NICE */
357#endif /* NTPD_PRIO && NTPD_PRIO != 0 */
358 if (!priority_done)
359 msyslog(LOG_ERR, "set_process_priority: No way found to improve our priority");
360}
361
362
363/*
364 * Main program. Initialize us, disconnect us from the tty if necessary,
365 * and loop waiting for I/O and/or timer expiries.
366 */
367int
368ntpdmain(
369 int argc,
370 char *argv[]
371 )
372{
373 l_fp now;
374 char *cp;
375 struct recvbuf *rbuflist;
376 struct recvbuf *rbuf;
377#ifdef _AIX /* HMS: ifdef SIGDANGER? */
378 struct sigaction sa;
379#endif
380
381 initializing = 1; /* mark that we are initializing */
382 debug = 0; /* no debugging by default */
383 nofork = 0; /* will fork by default */
384
385#ifdef HAVE_UMASK
386 {
387 mode_t uv;
388
389 uv = umask(0);
390 if(uv)
391 (void) umask(uv);
392 else
393 (void) umask(022);
394 }
395#endif
396
397#if defined(HAVE_GETUID) && !defined(MPE) /* MPE lacks the concept of root */
398 {
399 uid_t uid;
400
401 uid = getuid();
402 if (uid)
403 {
404 msyslog(LOG_ERR, "ntpd: must be run as root, not uid %ld", (long)uid);
405 exit(1);
406 }
407 }
408#endif
409
410#ifdef SYS_WINNT
411 /* Set the Event-ID message-file name. */
412 if (!GetModuleFileName(NULL, szMsgPath, sizeof(szMsgPath))) {
413 msyslog(LOG_ERR, "GetModuleFileName(PGM_EXE_FILE) failed: %m\n");
414 exit(1);
415 }
416 addSourceToRegistry("NTP", szMsgPath);
417#endif
418 getstartup(argc, argv); /* startup configuration, may set debug */
419
420 if (debug)
421 printf("%s\n", Version);
422
423 /*
424 * Initialize random generator and public key pair
425 */
426#ifdef SYS_WINNT
427 /* Initialize random file before OpenSSL checks */
428 if(!init_randfile())
429 msyslog(LOG_ERR, "Unable to initialize .rnd file\n");
430#endif
431 get_systime(&now);
432 SRANDOM((int)(now.l_i * now.l_uf));
433
434#if !defined(VMS)
435# ifndef NODETACH
436 /*
437 * Detach us from the terminal. May need an #ifndef GIZMO.
438 */
439# ifdef DEBUG
440 if (!debug && !nofork)
441# else /* DEBUG */
442 if (!nofork)
443# endif /* DEBUG */
444 {
445# ifndef SYS_WINNT
446# ifdef HAVE_DAEMON
447 daemon(0, 0);
448# else /* not HAVE_DAEMON */
449 if (fork()) /* HMS: What about a -1? */
450 exit(0);
451
452 {
453#if !defined(F_CLOSEM)
454 u_long s;
455 int max_fd;
456#endif /* not F_CLOSEM */
457
458#if defined(F_CLOSEM)
459 /*
460 * From 'Writing Reliable AIX Daemons,' SG24-4946-00,
461 * by Eric Agar (saves us from doing 32767 system
462 * calls)
463 */
464 if (fcntl(0, F_CLOSEM, 0) == -1)
465 msyslog(LOG_ERR, "ntpd: failed to close open files(): %m");
466#else /* not F_CLOSEM */
467
468# if defined(HAVE_SYSCONF) && defined(_SC_OPEN_MAX)
469 max_fd = sysconf(_SC_OPEN_MAX);
470# else /* HAVE_SYSCONF && _SC_OPEN_MAX */
471 max_fd = getdtablesize();
472# endif /* HAVE_SYSCONF && _SC_OPEN_MAX */
473 for (s = 0; s < max_fd; s++)
474 (void) close((int)s);
475#endif /* not F_CLOSEM */
476 (void) open("/", 0);
477 (void) dup2(0, 1);
478 (void) dup2(0, 2);
479#ifdef SYS_DOMAINOS
480 {
481 uid_$t puid;
482 status_$t st;
483
484 proc2_$who_am_i(&puid);
485 proc2_$make_server(&puid, &st);
486 }
487#endif /* SYS_DOMAINOS */
488#if defined(HAVE_SETPGID) || defined(HAVE_SETSID)
489# ifdef HAVE_SETSID
490 if (setsid() == (pid_t)-1)
491 msyslog(LOG_ERR, "ntpd: setsid(): %m");
492# else
493 if (setpgid(0, 0) == -1)
494 msyslog(LOG_ERR, "ntpd: setpgid(): %m");
495# endif
496#else /* HAVE_SETPGID || HAVE_SETSID */
497 {
498# if defined(TIOCNOTTY)
499 int fid;
500
501 fid = open("/dev/tty", 2);
502 if (fid >= 0)
503 {
504 (void) ioctl(fid, (u_long) TIOCNOTTY, (char *) 0);
505 (void) close(fid);
506 }
507# endif /* defined(TIOCNOTTY) */
508# ifdef HAVE_SETPGRP_0
509 (void) setpgrp();
510# else /* HAVE_SETPGRP_0 */
511 (void) setpgrp(0, getpid());
512# endif /* HAVE_SETPGRP_0 */
513 }
514#endif /* HAVE_SETPGID || HAVE_SETSID */
515#ifdef _AIX
516 /* Don't get killed by low-on-memory signal. */
517 sa.sa_handler = catch_danger;
518 sigemptyset(&sa.sa_mask);
519 sa.sa_flags = SA_RESTART;
520
521 (void) sigaction(SIGDANGER, &sa, NULL);
522#endif /* _AIX */
523 }
524# endif /* not HAVE_DAEMON */
525# else /* SYS_WINNT */
526
527 {
528 if (NoWinService == FALSE) {
529 SERVICE_TABLE_ENTRY dispatchTable[] = {
530 { TEXT("NetworkTimeProtocol"), (LPSERVICE_MAIN_FUNCTION)service_main },
531 { NULL, NULL }
532 };
533
534 /* daemonize */
535 if (!StartServiceCtrlDispatcher(dispatchTable))
536 {
537 msyslog(LOG_ERR, "StartServiceCtrlDispatcher: %m");
538 ExitProcess(2);
539 }
540 }
541 else {
542 service_main(argc, argv);
543 return 0;
544 }
545 }
546# endif /* SYS_WINNT */
547 }
548# endif /* NODETACH */
549# if defined(SYS_WINNT) && !defined(NODETACH)
550 else
551 service_main(argc, argv);
552 return 0; /* must return a value */
553} /* end main */
554
555/*
556 * If this runs as a service under NT, the main thread will block at
557 * StartServiceCtrlDispatcher() and another thread will be started by the
558 * Service Control Dispatcher which will begin execution at the routine
559 * specified in that call (viz. service_main)
560 */
561void
562service_main(
563 DWORD argc,
564 LPTSTR *argv
565 )
566{
567 char *cp;
568 struct recvbuf *rbuflist;
569 struct recvbuf *rbuf;
570
571 if(!debug && NoWinService == FALSE)
572 {
573 /* register our service control handler */
574 sshStatusHandle = RegisterServiceCtrlHandler( TEXT("NetworkTimeProtocol"),
575 (LPHANDLER_FUNCTION)service_ctrl);
576 if(sshStatusHandle == 0)
577 {
578 msyslog(LOG_ERR, "RegisterServiceCtrlHandler failed: %m");
579 return;
580 }
581
582 /* report pending status to Service Control Manager */
583 ssStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
584 ssStatus.dwCurrentState = SERVICE_START_PENDING;
585 ssStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
586 ssStatus.dwWin32ExitCode = NO_ERROR;
587 ssStatus.dwServiceSpecificExitCode = 0;
588 ssStatus.dwCheckPoint = 1;
589 ssStatus.dwWaitHint = 5000;
590 if (!SetServiceStatus(sshStatusHandle, &ssStatus))
591 {
592 msyslog(LOG_ERR, "SetServiceStatus: %m");
593 ssStatus.dwCurrentState = SERVICE_STOPPED;
594 SetServiceStatus(sshStatusHandle, &ssStatus);
595 return;
596 }
597
598 } /* debug */
599# endif /* defined(SYS_WINNT) && !defined(NODETACH) */
600#endif /* VMS */
601
602 /*
603 * Logging. This may actually work on the gizmo board. Find a name
604 * to log with by using the basename of argv[0]
605 */
606 cp = strrchr(argv[0], '/');
607 if (cp == 0)
608 cp = argv[0];
609 else
610 cp++;
611
612 debug = 0; /* will be immediately re-initialized 8-( */
613 getstartup(argc, argv); /* startup configuration, catch logfile this time */
614
615#if !defined(VMS)
616
617# ifndef LOG_DAEMON
618 openlog(cp, LOG_PID);
619# else /* LOG_DAEMON */
620
621# ifndef LOG_NTP
622# define LOG_NTP LOG_DAEMON
623# endif
624 openlog(cp, LOG_PID | LOG_NDELAY, LOG_NTP);
625# ifdef DEBUG
626 if (debug)
627 setlogmask(LOG_UPTO(LOG_DEBUG));
628 else
629# endif /* DEBUG */
630 setlogmask(LOG_UPTO(LOG_DEBUG)); /* @@@ was INFO */
631# endif /* LOG_DAEMON */
632#endif /* !SYS_WINNT && !VMS */
633
634 NLOG(NLOG_SYSINFO) /* conditional if clause for conditional syslog */
635 msyslog(LOG_NOTICE, "%s", Version);
636
637#ifdef SYS_WINNT
638 /* GMS 1/18/1997
639 * TODO: lock the process in memory using SetProcessWorkingSetSize() and VirtualLock() functions
640 *
641 process_handle = GetCurrentProcess();
642 if (SetProcessWorkingSetSize(process_handle, 2097152 , 4194304 ) == TRUE) {
643 if (VirtualLock(0 , 4194304) == FALSE)
644 msyslog(LOG_ERR, "VirtualLock() failed: %m");
645 } else {
646 msyslog(LOG_ERR, "SetProcessWorkingSetSize() failed: %m");
647 }
648 */
649#endif /* SYS_WINNT */
650
651#ifdef SCO5_CLOCK
652 /*
653 * SCO OpenServer's system clock offers much more precise timekeeping
654 * on the base CPU than the other CPUs (for multiprocessor systems),
655 * so we must lock to the base CPU.
656 */
657 {
658 int fd = open("/dev/at1", O_RDONLY);
659 if (fd >= 0) {
660 int zero = 0;
661 if (ioctl(fd, ACPU_LOCK, &zero) < 0)
662 msyslog(LOG_ERR, "cannot lock to base CPU: %m\n");
663 close( fd );
664 } /* else ...
665 * If we can't open the device, this probably just isn't
666 * a multiprocessor system, so we're A-OK.
667 */
668 }
669#endif
670
671#if defined(HAVE_MLOCKALL) && defined(MCL_CURRENT) && defined(MCL_FUTURE)
672# ifdef HAVE_SETRLIMIT
673 /*
674 * Set the stack limit to something smaller, so that we don't lock a lot
675 * of unused stack memory.
676 */
677 {
678 struct rlimit rl;
679
680 if (getrlimit(RLIMIT_STACK, &rl) != -1
681 && (rl.rlim_cur = 20 * 4096) < rl.rlim_max)
682 {
683 if (setrlimit(RLIMIT_STACK, &rl) == -1)
684 {
685 msyslog(LOG_ERR,
686 "Cannot adjust stack limit for mlockall: %m");
687 }
688 }
689 }
690# endif /* HAVE_SETRLIMIT */
691 /*
692 * lock the process into memory
693 */
694 if (mlockall(MCL_CURRENT|MCL_FUTURE) < 0)
695 msyslog(LOG_ERR, "mlockall(): %m");
696#else /* not (HAVE_MLOCKALL && MCL_CURRENT && MCL_FUTURE) */
697# ifdef HAVE_PLOCK
698# ifdef PROCLOCK
699# ifdef _AIX
700 /*
701 * set the stack limit for AIX for plock().
702 * see get_aix_stack for more info.
703 */
704 if (ulimit(SET_STACKLIM, (get_aix_stack() - 8*4096)) < 0)
705 {
706 msyslog(LOG_ERR,"Cannot adjust stack limit for plock on AIX: %m");
707 }
708# endif /* _AIX */
709 /*
710 * lock the process into memory
711 */
712 if (plock(PROCLOCK) < 0)
713 msyslog(LOG_ERR, "plock(PROCLOCK): %m");
714# else /* not PROCLOCK */
715# ifdef TXTLOCK
716 /*
717 * Lock text into ram
718 */
719 if (plock(TXTLOCK) < 0)
720 msyslog(LOG_ERR, "plock(TXTLOCK) error: %m");
721# else /* not TXTLOCK */
722 msyslog(LOG_ERR, "plock() - don't know what to lock!");
723# endif /* not TXTLOCK */
724# endif /* not PROCLOCK */
725# endif /* HAVE_PLOCK */
726#endif /* not (HAVE_MLOCKALL && MCL_CURRENT && MCL_FUTURE) */
727
728 /*
729 * Set up signals we pay attention to locally.
730 */
731#ifdef SIGDIE1
732 (void) signal_no_reset(SIGDIE1, finish);
733#endif /* SIGDIE1 */
734#ifdef SIGDIE2
735 (void) signal_no_reset(SIGDIE2, finish);
736#endif /* SIGDIE2 */
737#ifdef SIGDIE3
738 (void) signal_no_reset(SIGDIE3, finish);
739#endif /* SIGDIE3 */
740#ifdef SIGDIE4
741 (void) signal_no_reset(SIGDIE4, finish);
742#endif /* SIGDIE4 */
743
744#ifdef SIGBUS
745 (void) signal_no_reset(SIGBUS, finish);
746#endif /* SIGBUS */
747
748#if !defined(SYS_WINNT) && !defined(VMS)
749# ifdef DEBUG
750 (void) signal_no_reset(MOREDEBUGSIG, moredebug);
751 (void) signal_no_reset(LESSDEBUGSIG, lessdebug);
752# else
753 (void) signal_no_reset(MOREDEBUGSIG, no_debug);
754 (void) signal_no_reset(LESSDEBUGSIG, no_debug);
755# endif /* DEBUG */
756#endif /* !SYS_WINNT && !VMS */
757
758 /*
759 * Set up signals we should never pay attention to.
760 */
761#if defined SIGPIPE
762 (void) signal_no_reset(SIGPIPE, SIG_IGN);
763#endif /* SIGPIPE */
764
765#if defined SYS_WINNT
766 if (!SetConsoleCtrlHandler(OnConsoleEvent, TRUE)) {
767 msyslog(LOG_ERR, "Can't set console control handler: %m");
768 }
769#endif
770
771 /*
772 * Call the init_ routines to initialize the data structures.
773 */
774#if defined (HAVE_IO_COMPLETION_PORT)
775 init_io_completion_port();
776 init_winnt_time();
777#endif
778 init_auth();
779 init_util();
780 init_restrict();
781 init_mon();
782 init_timer();
783 init_lib();
784 init_random();
785 init_request();
786 init_control();
787 init_peer();
788#ifdef REFCLOCK
789 init_refclock();
790#endif
791 set_process_priority();
792 init_proto(); /* Call at high priority */
793 init_io();
794 init_loopfilter();
795 mon_start(MON_ON); /* monitor on by default now */
796 /* turn off in config if unwanted */
797
798 /*
799 * Get configuration. This (including argument list parsing) is
800 * done in a separate module since this will definitely be different
801 * for the gizmo board. While at it, save the host name for later
802 * along with the length. The crypto needs this.
803 */
804#ifdef DEBUG
805 debug = 0;
806#endif
807 getconfig(argc, argv);
808#ifdef OPENSSL
809 crypto_setup();
810#endif /* OPENSSL */
811 initializing = 0;
812
813#if defined(SYS_WINNT) && !defined(NODETACH)
814# if defined(DEBUG)
815 if(!debug)
816 {
817# endif
818 if (NoWinService == FALSE) {
819 /* report to the service control manager that the service is running */
820 ssStatus.dwCurrentState = SERVICE_RUNNING;
821 ssStatus.dwWin32ExitCode = NO_ERROR;
822 if (!SetServiceStatus(sshStatusHandle, &ssStatus))
823 {
824 msyslog(LOG_ERR, "SetServiceStatus: %m");
825 if (ResolverThreadHandle != NULL)
826 CloseHandle(ResolverThreadHandle);
827 ssStatus.dwCurrentState = SERVICE_STOPPED;
828 SetServiceStatus(sshStatusHandle, &ssStatus);
829 return;
830 }
831 }
832# if defined(DEBUG)
833 }
834# endif
835#endif
836
837#ifdef HAVE_CLOCKCTL
838 /*
839 * Drop super-user privileges and chroot now if the OS supports
840 * non root clock control (only NetBSD for now).
841 */
842 if (user != NULL) {
843 if (isdigit((unsigned char)*user)) {
844 sw_uid = (uid_t)strtoul(user, &endp, 0);
845 if (*endp != '\0')
846 goto getuser;
847 } else {
848getuser:
849 if ((pw = getpwnam(user)) != NULL) {
850 sw_uid = pw->pw_uid;
851 } else {
852 errno = 0;
853 msyslog(LOG_ERR, "Cannot find user `%s'", user);
854 exit (-1);
855 }
856 }
857 }
858 if (group != NULL) {
859 if (isdigit((unsigned char)*group)) {
860 sw_gid = (gid_t)strtoul(group, &endp, 0);
861 if (*endp != '\0')
862 goto getgroup;
863 } else {
864getgroup:
865 if ((gr = getgrnam(group)) != NULL) {
866 sw_gid = pw->pw_gid;
867 } else {
868 errno = 0;
869 msyslog(LOG_ERR, "Cannot find group `%s'", group);
870 exit (-1);
871 }
872 }
873 }
874 if (chrootdir && chroot(chrootdir)) {
875 msyslog(LOG_ERR, "Cannot chroot to `%s': %m", chrootdir);
876 exit (-1);
877 }
878 if (group && setgid(sw_gid)) {
879 msyslog(LOG_ERR, "Cannot setgid() to group `%s': %m", group);
880 exit (-1);
881 }
882 if (group && setegid(sw_gid)) {
883 msyslog(LOG_ERR, "Cannot setegid() to group `%s': %m", group);
884 exit (-1);
885 }
886 if (user && setuid(sw_uid)) {
887 msyslog(LOG_ERR, "Cannot setuid() to user `%s': %m", user);
888 exit (-1);
889 }
890 if (user && seteuid(sw_uid)) {
891 msyslog(LOG_ERR, "Cannot seteuid() to user `%s': %m", user);
892 exit (-1);
893 }
894#endif
895 /*
896 * Report that we're up to any trappers
897 */
898 report_event(EVNT_SYSRESTART, (struct peer *)0);
899
900 /*
901 * Use select() on all on all input fd's for unlimited
902 * time. select() will terminate on SIGALARM or on the
903 * reception of input. Using select() means we can't do
904 * robust signal handling and we get a potential race
905 * between checking for alarms and doing the select().
906 * Mostly harmless, I think.
907 */
908 /* On VMS, I suspect that select() can't be interrupted
909 * by a "signal" either, so I take the easy way out and
910 * have select() time out after one second.
911 * System clock updates really aren't time-critical,
912 * and - lacking a hardware reference clock - I have
913 * yet to learn about anything else that is.
914 */
915#if defined(HAVE_IO_COMPLETION_PORT)
916 WaitHandles[0] = CreateEvent(NULL, FALSE, FALSE, NULL); /* exit reques */
917 WaitHandles[1] = get_timer_handle();
918 WaitHandles[2] = get_io_event();
919
920 for (;;) {
921 DWORD Index = WaitForMultipleObjectsEx(sizeof(WaitHandles)/sizeof(WaitHandles[0]), WaitHandles, FALSE, 1000, TRUE);
922 switch (Index) {
923 case WAIT_OBJECT_0 + 0 : /* exit request */
924 exit(0);
925 break;
926
927 case WAIT_OBJECT_0 + 1 : /* timer */
928 timer();
929 break;
930
931 case WAIT_OBJECT_0 + 2 : /* Io event */
932# ifdef DEBUG
933 if ( debug > 3 )
934 {
935 printf( "IoEvent occurred\n" );
936 }
937# endif
938 break;
939
940 case WAIT_IO_COMPLETION : /* loop */
941 case WAIT_TIMEOUT :
942 break;
943 case WAIT_FAILED:
944 msyslog(LOG_ERR, "ntpdc: WaitForMultipleObjectsEx Failed: Error: %m");
945 break;
946
947 /* For now do nothing if not expected */
948 default:
949 break;
950
951 } /* switch */
952 rbuflist = getrecvbufs(); /* get received buffers */
953
954#else /* normal I/O */
955
956 was_alarmed = 0;
957 rbuflist = (struct recvbuf *)0;
958 for (;;)
959 {
960# if !defined(HAVE_SIGNALED_IO)
961 extern fd_set activefds;
962 extern int maxactivefd;
963
964 fd_set rdfdes;
965 int nfound;
966# elif defined(HAVE_SIGNALED_IO)
967 block_io_and_alarm();
968# endif
969
970 rbuflist = getrecvbufs(); /* get received buffers */
971 if (alarm_flag) /* alarmed? */
972 {
973 was_alarmed = 1;
974 alarm_flag = 0;
975 }
976
977 if (!was_alarmed && rbuflist == (struct recvbuf *)0)
978 {
979 /*
980 * Nothing to do. Wait for something.
981 */
982# ifndef HAVE_SIGNALED_IO
983 rdfdes = activefds;
984# if defined(VMS) || defined(SYS_VXWORKS)
985 /* make select() wake up after one second */
986 {
987 struct timeval t1;
988
989 t1.tv_sec = 1; t1.tv_usec = 0;
990 nfound = select(maxactivefd+1, &rdfdes, (fd_set *)0,
991 (fd_set *)0, &t1);
992 }
993# else
994 nfound = select(maxactivefd+1, &rdfdes, (fd_set *)0,
995 (fd_set *)0, (struct timeval *)0);
996# endif /* VMS */
997 if (nfound > 0)
998 {
999 l_fp ts;
1000
1001 get_systime(&ts);
1002
1003 (void)input_handler(&ts);
1004 }
1005 else if (nfound == -1 && errno != EINTR)
1006 msyslog(LOG_ERR, "select() error: %m");
1007# ifdef DEBUG
1008 else if (debug > 2)
1009 msyslog(LOG_DEBUG, "select(): nfound=%d, error: %m", nfound);
1010# endif /* DEBUG */
1011# else /* HAVE_SIGNALED_IO */
1012
1013 wait_for_signal();
1014# endif /* HAVE_SIGNALED_IO */
1015 if (alarm_flag) /* alarmed? */
1016 {
1017 was_alarmed = 1;
1018 alarm_flag = 0;
1019 }
1020 rbuflist = getrecvbufs(); /* get received buffers */
1021 }
1022# ifdef HAVE_SIGNALED_IO
1023 unblock_io_and_alarm();
1024# endif /* HAVE_SIGNALED_IO */
1025
1026 /*
1027 * Out here, signals are unblocked. Call timer routine
1028 * to process expiry.
1029 */
1030 if (was_alarmed)
1031 {
1032 timer();
1033 was_alarmed = 0;
1034 }
1035
1036#endif /* HAVE_IO_COMPLETION_PORT */
1037 /*
1038 * Call the data procedure to handle each received
1039 * packet.
1040 */
1041 while (rbuflist != (struct recvbuf *)0)
1042 {
1043 rbuf = rbuflist;
1044 rbuflist = rbuf->next;
1045 (rbuf->receiver)(rbuf);
1046 freerecvbuf(rbuf);
1047 }
1048#if defined DEBUG && defined SYS_WINNT
1049 if (debug > 4)
1050 printf("getrecvbufs: %ld handler interrupts, %ld frames\n",
1051 handler_calls, handler_pkts);
1052#endif
1053
1054 /*
1055 * Go around again
1056 */
1057 }
1058#ifndef SYS_WINNT
1059 exit(1); /* unreachable */
1060#endif
1061#ifndef SYS_WINNT
1062 return 1; /* DEC OSF cc braindamage */
1063#endif
1064}
1065
1066
1067#ifdef SIGDIE2
1068/*
1069 * finish - exit gracefully
1070 */
1071static RETSIGTYPE
1072finish(
1073 int sig
1074 )
1075{
1076
1077 msyslog(LOG_NOTICE, "ntpd exiting on signal %d", sig);
1078
1079 switch (sig)
1080 {
1081# ifdef SIGBUS
1082 case SIGBUS:
1083 printf("\nfinish(SIGBUS)\n");
1084 exit(0);
1085# endif
1086 case 0: /* Should never happen... */
1087 return;
1088 default:
1089 exit(0);
1090 }
1091}
1092#endif /* SIGDIE2 */
1093
1094
1095#ifdef DEBUG
1096#ifndef SYS_WINNT
1097/*
1098 * moredebug - increase debugging verbosity
1099 */
1100static RETSIGTYPE
1101moredebug(
1102 int sig
1103 )
1104{
1105 int saved_errno = errno;
1106
1107 if (debug < 255)
1108 {
1109 debug++;
1110 msyslog(LOG_DEBUG, "debug raised to %d", debug);
1111 }
1112 errno = saved_errno;
1113}
1114
1115/*
1116 * lessdebug - decrease debugging verbosity
1117 */
1118static RETSIGTYPE
1119lessdebug(
1120 int sig
1121 )
1122{
1123 int saved_errno = errno;
1124
1125 if (debug > 0)
1126 {
1127 debug--;
1128 msyslog(LOG_DEBUG, "debug lowered to %d", debug);
1129 }
1130 errno = saved_errno;
1131}
1132#endif
1133#else /* not DEBUG */
1134#ifndef SYS_WINNT/*
1135 * no_debug - We don't do the debug here.
1136 */
1137static RETSIGTYPE
1138no_debug(
1139 int sig
1140 )
1141{
1142 int saved_errno = errno;
1143
1144 msyslog(LOG_DEBUG, "ntpd not compiled for debugging (signal %d)", sig);
1145 errno = saved_errno;
1146}
1147#endif /* not SYS_WINNT */
1148#endif /* not DEBUG */
1149
1150#ifdef SYS_WINNT
1151/* service_ctrl - control handler for NTP service
1152 * signals the service_main routine of start/stop requests
1153 * from the control panel or other applications making
1154 * win32API calls
1155 */
1156void
1157service_ctrl(
1158 DWORD dwCtrlCode
1159 )
1160{
1161 DWORD dwState = SERVICE_RUNNING;
1162
1163 /* Handle the requested control code */
1164 switch(dwCtrlCode)
1165 {
1166 case SERVICE_CONTROL_PAUSE:
1167 /* see no reason to support this */
1168 break;
1169
1170 case SERVICE_CONTROL_CONTINUE:
1171 /* see no reason to support this */
1172 break;
1173
1174 case SERVICE_CONTROL_STOP:
1175 dwState = SERVICE_STOP_PENDING;
1176 /*
1177 * Report the status, specifying the checkpoint and waithint,
1178 * before setting the termination event.
1179 */
1180 ssStatus.dwCurrentState = dwState;
1181 ssStatus.dwWin32ExitCode = NO_ERROR;
1182 ssStatus.dwWaitHint = 3000;
1183 if (!SetServiceStatus(sshStatusHandle, &ssStatus))
1184 {
1185 msyslog(LOG_ERR, "SetServiceStatus: %m");
1186 }
1187 if (WaitHandles[0] != NULL) {
1188 SetEvent(WaitHandles[0]);
1189 }
1190 return;
1191
1192 case SERVICE_CONTROL_INTERROGATE:
1193 /* Update the service status */
1194 break;
1195
1196 default:
1197 /* invalid control code */
1198 break;
1199
1200 }
1201
1202 ssStatus.dwCurrentState = dwState;
1203 ssStatus.dwWin32ExitCode = NO_ERROR;
1204 if (!SetServiceStatus(sshStatusHandle, &ssStatus))
1205 {
1206 msyslog(LOG_ERR, "SetServiceStatus: %m");
1207 }
1208}
1209
1210static BOOL WINAPI
1211OnConsoleEvent(
1212 DWORD dwCtrlType
1213 )
1214{
1215 switch (dwCtrlType) {
1216 case CTRL_BREAK_EVENT :
1217 if (debug > 0) {
1218 debug <<= 1;
1219 }
1220 else {
1221 debug = 1;
1222 }
1223 if (debug > 8) {
1224 debug = 0;
1225 }
1226 printf("debug level %d\n", debug);
1227 break ;
1228
1229 case CTRL_C_EVENT :
1230 case CTRL_CLOSE_EVENT :
1231 case CTRL_SHUTDOWN_EVENT :
1232 if (WaitHandles[0] != NULL) {
1233 SetEvent(WaitHandles[0]);
1234 }
1235 break;
1236
1237 default :
1238 return FALSE;
1239
1240
1241 }
1242 return TRUE;;
1243}
1244
1245
1246/*
1247 * NT version of exit() - all calls to exit() should be routed to
1248 * this function.
1249 */
1250void
1251service_exit(
1252 int status
1253 )
1254{
1255 if (!debug) { /* did not become a service, simply exit */
1256 /* service mode, need to have the service_main routine
1257 * register with the service control manager that the
1258 * service has stopped running, before exiting
1259 */
1260 ssStatus.dwCurrentState = SERVICE_STOPPED;
1261 SetServiceStatus(sshStatusHandle, &ssStatus);
1262
1263 }
1264 uninit_io_completion_port();
1265 reset_winnt_time();
1266
1267# if defined _MSC_VER
1268 _CrtDumpMemoryLeaks();
1269# endif
1270#undef exit
1271 exit(status);
1272}
1273
1274#endif /* SYS_WINNT */