OpenDNSSEC-enforcer  1.4.5
daemon.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2008-2009 Nominet UK. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  * notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  * notice, this list of conditions and the following disclaimer in the
11  * documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
14  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
15  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
17  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
19  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
21  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
22  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
23  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  *
25  */
26 
27 /*
28  * daemon.c code needed to get a daemon up and running
29  *
30  * edit the DAEMONCONFIG and cmlParse function
31  * in daemon_util.[c|h] to add options specific
32  * to your app
33  *
34  * gcc -o daemon daemon_util.c daemon.c
35  *
36  * Most of this is based on stuff I have seen in NSD
37  */
38 
39 #include "config.h"
40 
41 #include <sys/types.h>
42 #include <sys/param.h>
43 #include <syslog.h>
44 #include <stdarg.h>
45 #include <errno.h>
46 #include <unistd.h>
47 #include <fcntl.h>
48 #include <stdlib.h>
49 #include <string.h>
50 #include <signal.h>
51 
52 #include "daemon.h"
53 #include "daemon_util.h"
54 #include "privdrop.h"
55 
56 #include "ksm/ksm.h"
57 #include "ksm/dbsmsg.h"
58 #include "ksm/dbsdef.h"
59 #include "ksm/kmemsg.h"
60 #include "ksm/kmedef.h"
61 #include "ksm/message.h"
62 #include "ksm/string_util.h"
63 
64 #ifndef MAXPATHLEN
65 # define MAXPATHLEN 4096
66 #endif
67 
68 extern int server_init(DAEMONCONFIG *config);
69 extern void server_main(DAEMONCONFIG *config);
70 
72 
73 void
74 sig_handler (int sig)
75 {
76  switch (sig) {
77  case SIGCHLD:
78  return;
79  case SIGHUP:
80  return;
81  case SIGALRM:
82  break;
83  case SIGILL:
84  break;
85  case SIGUSR1:
86  break;
87  case SIGINT:
88  config.term = 2;
89  break;
90  case SIGTERM:
91  config.term = 1;
92  break;
93  default:
94  break;
95  }
96 }
97 
99 
100 void
102 {
103  /* Only unlink pidfile if its our pidfile */
104  if (daemon_our_pidfile) {
105  unlink(config.pidfile);
106  }
107 }
108 
109 int
110 main(int argc, char *argv[]){
111  int fd;
112  struct sigaction action;
113  const char* program; /* Temporary for program name */
114 
115  config.debug = false;
116  config.once = false;
117 
118  config.pidfile = NULL;
119  config.program = NULL;
120  config.host = NULL;
121  config.port = NULL;
122  config.user = (unsigned char *)calloc(MAX_USER_LENGTH, sizeof(char));
123  config.password = (unsigned char *)calloc(MAX_PASSWORD_LENGTH, sizeof(char));
124  config.schema = (unsigned char *)calloc(MAX_SCHEMA_LENGTH, sizeof(char));
125  config.DSSubmitCmd = (char *)calloc(MAXPATHLEN + 1024, sizeof(char));
126  config.policy = NULL;
127 
128  if (config.user == NULL || config.password == NULL || config.schema == NULL) {
129  log_msg(&config, LOG_ERR, "Malloc for config struct failed");
130  exit(1);
131  }
132  config.term = 0;
133 
134  /* Lets set up the logging first */
135  /* The program name is the last component of the program file name */
136  if ((program = strrchr(argv[0], '/'))) { /* EQUALS */
137  ++program; /* Point to character after last "/" */
138  }
139  else {
140  program = argv[0]; /* No slash, so use string given */
141  }
142  config.program = program;
144 
145  log_init(config.log_user, config.program);
146 
147  /* useful message */
148  log_msg(&config, LOG_INFO, "%s starting...", PACKAGE_NAME);
149 
150 #ifdef ENFORCER_TIMESHIFT
151  if (getenv("ENFORCER_TIMESHIFT")) {
152  log_msg(&config, LOG_INFO, "Timeshift mode detected, running once only!");
153  fprintf(stderr, "WARNING: Timeshift mode detected, running once only!\n");
154  config.once = true;
155  config.debug = true;
156  }
157 #endif /* ENFORCER_TIMESHIFT */
158 
159  /* Process command line */
160  cmdlParse(&config, &argc, argv);
161  if(config.debug) log_msg(&config, LOG_INFO, "%s DEBUG ON.", PACKAGE_NAME);
162 
163  /* If we dont debug then fork */
164  if(!config.debug){
165  /* Fork */
166  switch ((config.pid = fork())) {
167  case 0:
168  break;
169  case -1:
170  log_msg(&config, LOG_ERR, "fork failed: %s", strerror(errno));
171  unlink(config.pidfile);
172  exit(1);
173  default:
174  fprintf(stdout, "OpenDNSSEC ods-enforcerd started (version %s), pid %d\n", PACKAGE_VERSION, (int) config.pid);
175  log_msg(&config, LOG_INFO, "%s Parent exiting...", PACKAGE_NAME);
176  exit(0);
177  }
178 
179  /* Detach ourselves... */
180  if (setsid() == -1) {
181  log_msg(&config, LOG_ERR, "setsid() failed: %s", strerror(errno));
182  exit(1);
183  }
184 
185  if ((fd = open("/dev/null", O_RDWR, 0)) != -1) {
186  (void)dup2(fd, STDIN_FILENO);
187  (void)dup2(fd, STDOUT_FILENO);
188  (void)dup2(fd, STDERR_FILENO);
189  if (fd > 2)
190  (void)close(fd);
191  }
192  log_msg(&config, LOG_INFO, "%s forked OK...", PACKAGE_NAME);
193  } else {
194  log_msg(&config, LOG_INFO, "%s in debug mode - not forking...", PACKAGE_NAME);
195  }
196 
197  action.sa_handler = sig_handler;
198  sigfillset(&action.sa_mask);
199  action.sa_flags = 0;
200  sigaction(SIGTERM, &action, NULL);
201  sigaction(SIGHUP, &action, NULL);
202  sigaction(SIGINT, &action, NULL);
203  sigaction(SIGILL, &action, NULL);
204  sigaction(SIGUSR1, &action, NULL);
205  sigaction(SIGALRM, &action, NULL);
206  sigaction(SIGCHLD, &action, NULL);
207  action.sa_handler = SIG_IGN;
208  sigaction(SIGPIPE, &action, NULL);
209 
210  /* Get perms that we will be dropping to */
211  if (getPermsForDrop(&config) != 0) {
212  exit(1);
213  }
214 
215  /* Run the server specific code. You need to provide this function somewhere
216  this sets our pidfile */
217  if (server_init(&config) != 0) {
218  exit(1);
219  }
220 
221  /* make the directory for the pidfile if required; do this before we drop
222  privs */
223  if (createPidDir(&config) != 0) {
224  exit(1);
225  }
226 
227  /*
228  * Drop permissions.
229  * This function exits if something goes wrong
230  */
231  privdrop(config.username, config.groupname, NULL);
232 
233  config.uid = geteuid();
234  config.gid = getegid();
235  config.pid = getpid();
236 
237  atexit(exit_function);
238 
239  log_msg(&config, LOG_NOTICE, "%s started (version %s), pid %d", PACKAGE_NAME, PACKAGE_VERSION,
240  (int) config.pid);
241 
242  MsgInit();
245 
246  /* Do something. You need to provide this function somewhere */
247  server_main(&config);
248 
249  /* Free stuff here (exit from sigs pass through) */
250  MsgRundown();
251  if (config.host) free(config.host);
252  if (config.port) free(config.port);
253  free(config.user);
254  free(config.password);
255  free(config.schema);
256  free(config.DSSubmitCmd);
257 
258  StrFree(config.username);
259  StrFree(config.groupname);
260 #if 0
261  StrFree(config.chrootdir);
262 #endif
263 
264  exit(0);
265 
266 }
267