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