~ubuntu-branches/ubuntu/trusty/maradns/trusty-proposed

« back to all changes in this revision

Viewing changes to deadwood-3.2.05/tools/duende.c

  • Committer: Package Import Robot
  • Author(s): Dariusz Dwornikowski
  • Date: 2014-02-16 19:36:04 UTC
  • mfrom: (1.2.11) (21.1.11 experimental)
  • Revision ID: package-import@ubuntu.com-20140216193604-xtmcopn9pilzszae
Tags: 2.0.09-1
* New maintainer (Closes: #739084)
* New upstream release to unstable
* Several security bugs (Closes: #739755)
   - security bugfix for CVE-2011-5055, CVE-2011-5056, CVE-2012-0024,
   CVE-2012-1570
   - security bugfix agains blind spoofing attack (no CVE number)
   - security bugfix for packet of death attack (no CVE number)
* Bump standards to 3.9.5
* Updated d/postinst to no longer modify conffiles (Closes: #710903)
* Init script fixed (Closes: #709826)
* --reinstall no longer kills the process (Closes: #701657)
* Updated old d/changelog entries, added information when the CVEs were
  fixed: 2.0.06-1, 2.0.04-1, 1.4.11-1, 1.2.12.06-1, 1.2.12.05-1, 1.0.28-1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Copyright (c) 2003-2008 Sam Trenholme
 
2
 *
 
3
 * TERMS
 
4
 *
 
5
 * Redistribution and use in source and binary forms, with or without
 
6
 * modification, are permitted provided that the following conditions
 
7
 * are met:
 
8
 *
 
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 'as is' with no guarantees of correctness or
 
16
 * fitness for purpose.
 
17
 */
 
18
 
 
19
/* I would like to thank D. Richard Felker III for his invaluable help
 
20
   with debugging how the pipes are set up here */
 
21
 
 
22
/* This program is a helper application which does the following:
 
23
 
 
24
   It starts the maradns process
 
25
 
 
26
   It syslog()s maradns' output via a chroot'd unprivledged child process
 
27
 
 
28
   If maradns exits with a code of 8, this means that she was given a
 
29
   HUP signal.  Restart the MaraDNS process
 
30
 
 
31
   If this process gets a HUP signal, restart the MaraDNS process
 
32
 
 
33
 */
 
34
 
 
35
#include <signal.h>
 
36
#include <stdio.h>
 
37
#include <stdlib.h>
 
38
#include <syslog.h>
 
39
#include <sys/time.h>
 
40
#include <sys/types.h>
 
41
#include <sys/wait.h>
 
42
#include <unistd.h>
 
43
 
 
44
/* The UID that the Duende logging process uses.  CHANGE THE DUENDE MAN
 
45
   PAGE IF YOU CHANGE THIS VALUE (same general process as changing the
 
46
   mararc man page; the source file for the duende man page is duende.ej) */
 
47
#define DUENDE_LOGGER_UID 66
 
48
 
 
49
/* The directory that Duende runs in.  This directory has to exist for
 
50
   Duende to be able to run.  Again, IF YOU CHANGE THIS, CHANGE THE
 
51
   DUENDE MAN PAGE */
 
52
#define DUENDE_CHROOT_DIR "/etc/maradns/logger"
 
53
 
 
54
int got_hup_signal = 0;
 
55
int got_term_signal = 0;
 
56
 
 
57
/* If we get a HUP signal set the flag so we can restart the MaraDNS child
 
58
   process */
 
59
void handle_hup() {
 
60
    got_hup_signal = 1;
 
61
    return;
 
62
    }
 
63
 
 
64
void handle_term() {
 
65
    got_term_signal = 1;
 
66
    return;
 
67
    }
 
68
 
 
69
/* Helper process which syslogs stuff from either MaraDNS' stdout or stderr. */
 
70
 
 
71
void log_helper(char *name,int stdout_fd) {
 
72
    char out_buf[1024];
 
73
 
 
74
    /* We can't use our signal handlers because fgets is blocking */
 
75
    signal(SIGTERM,SIG_DFL);
 
76
    signal(SIGHUP,SIG_DFL);
 
77
 
 
78
    /* Open up the sys log */
 
79
    openlog(name,0,LOG_DAEMON);
 
80
 
 
81
    /* Drop all privileges */
 
82
    if(chdir(DUENDE_CHROOT_DIR) != 0) {
 
83
       syslog(LOG_ALERT,"Can not enter chroot directory %s",DUENDE_CHROOT_DIR);
 
84
        syslog(LOG_ALERT,"%s","We can not log daemon output");
 
85
        printf("Fatal error logging; read syslog\n");
 
86
        printf("%s directory required to exist\n",DUENDE_CHROOT_DIR);
 
87
        exit(1);
 
88
        }
 
89
    if(setuid(DUENDE_LOGGER_UID) != 0) {
 
90
        syslog(LOG_ALERT,"%s%d","Can not change UID to ",DUENDE_LOGGER_UID);
 
91
        syslog(LOG_ALERT,"%s","We can not log daemon output");
 
92
        printf("Fatal error logging; read syslog\n");
 
93
        exit(1);
 
94
        }
 
95
 
 
96
    /* Log both stdout and stderr */
 
97
    dup2(stdout_fd,0);
 
98
    for(;;) {
 
99
        if(fgets(out_buf,1020,stdin) == out_buf)
 
100
#ifdef __FreeBSD__
 
101
            /* FreeBSD doesn't log daemon.info messages by default; while
 
102
             * this can be changed by editing /etc/syslog.conf, it *is*
 
103
             * an issue that can cause confusion */
 
104
            syslog(LOG_ALERT,"%s",out_buf);
 
105
#else /* __FreeBSD__ */
 
106
            syslog(LOG_INFO,"%s",out_buf);
 
107
#endif /* __FreeBSD__ */
 
108
        }
 
109
 
 
110
    syslog(LOG_ALERT,"log_helper process terminating");
 
111
    exit(0);
 
112
 
 
113
    }
 
114
 
 
115
 
 
116
/* If a child exits, see if the child exited with a code of 8 or received
 
117
   a HUP signal.  In either of these cases, restart the child daemon and the
 
118
   (if needed) logger process).  Otherwise, exit */
 
119
 
 
120
void handle_child_exited(int exit_status, pid_t alive, pid_t exited) {
 
121
        if(WIFEXITED(exit_status)) { /* Exit with exit code */
 
122
            if(WEXITSTATUS(exit_status) != 8) { /* Anything but HUP */
 
123
                kill(alive,SIGTERM);
 
124
                syslog(LOG_ALERT,"Child exited with status %d",exit_status);
 
125
                exit(WEXITSTATUS(exit_status));
 
126
                }
 
127
            }
 
128
        if(WIFSIGNALED(exit_status)) { /* Got signal */
 
129
            if(WTERMSIG(exit_status) != SIGHUP) {
 
130
                syslog(LOG_ALERT,"Child got signal %d",exit_status);
 
131
                kill(alive,SIGTERM);
 
132
                exit(1);
 
133
                }
 
134
            }
 
135
       /* If you somehow stop the child daemon, we go bye bye */
 
136
       if(WIFSTOPPED(exit_status)) {
 
137
            syslog(LOG_ALERT,"Child stopped");
 
138
            kill(exited,SIGTERM);
 
139
            kill(alive,SIGTERM);
 
140
            exit(2);
 
141
            }
 
142
        /* Clean up the system logging */
 
143
        syslog(LOG_ALERT,"Cleaning up system logging");
 
144
        kill(alive,SIGTERM);
 
145
    }
 
146
 
 
147
/* The main process forks off the child.  Right now, I will just have
 
148
   it fork off the MaraDNS process, hardwired as /usr/sbin/maradns,
 
149
   directing her standard output to
 
150
   /dev/null.  The revision of this file will correctly handle Mara's
 
151
   output
 
152
 */
 
153
 
 
154
int main(int argc, char **argv) {
 
155
    int exit_status;
 
156
    pid_t pid, log_pid;
 
157
    int stream1[2]; /* Used for piping */
 
158
    int exec_argv_offset = 1; /* Also used to determine PID writing */
 
159
    if(argv[0] == NULL || argv[1] == NULL) {
 
160
        printf("Usage: duende (--pid=/path/to/file) [program] [arguments]\n");
 
161
        exit(1);
 
162
        }
 
163
    if(!strncasecmp(argv[1],"--pid=",6)) {
 
164
        if(argv[2] == NULL) {
 
165
            printf(
 
166
                "Usage: duende (--pid=/path/to/file) [program] [arguments]\n");
 
167
            exit(1);
 
168
            }
 
169
        exec_argv_offset = 2;
 
170
        }
 
171
 
 
172
    /* Let children know that duende is running */
 
173
    if(setenv("DUENDE_IS_RUNNING","1",0) != 0) {
 
174
        printf("FATAL: Unable to set environment variable\n");
 
175
        exit(1);
 
176
        }
 
177
 
 
178
    /* The parent immediately exits */
 
179
    if(fork() != 0)
 
180
        exit(0);
 
181
 
 
182
    /* The child becomes a full-fledged daemon */
 
183
    setpgid(0,0); /* No longer visible in 'ps' without the 'auxw' argument */
 
184
 
 
185
    /* Write our PID to a file if the user so desires us to */
 
186
    if(exec_argv_offset == 2) {
 
187
        FILE *fp_pid = fopen(argv[1] + 6,"w");
 
188
        if(!fp_pid) {
 
189
            syslog(LOG_ALERT,"Fatal writing, to PID file, error\n");
 
190
            exit(1);
 
191
            }
 
192
        unsigned int local_pid = getpid();
 
193
        fprintf(fp_pid,"%u",local_pid);
 
194
        fclose(fp_pid);
 
195
        }
 
196
 
 
197
    /* Sysadmins expect HUP to reload, so we set that up */
 
198
    signal(SIGHUP,handle_hup);
 
199
    signal(SIGTERM,handle_term);
 
200
    signal(SIGINT,handle_term);
 
201
 
 
202
    pid = 0; log_pid = 0;
 
203
 
 
204
    for(;;) {
 
205
        if(pipe(stream1) != 0) {
 
206
            syslog(LOG_ALERT,"Fatal pipe error");
 
207
            exit(3);
 
208
            }
 
209
        pid = fork();
 
210
        if(pid == -1) {
 
211
            syslog(LOG_ALERT,"Fatal pid error");
 
212
            exit(1);
 
213
            }
 
214
        if(pid == 0) { /* Child; this one execs maradns */
 
215
            close(stream1[0]);
 
216
            /* Dup the standard output */
 
217
            if(dup2(stream1[1],1) != 1) {
 
218
                syslog(LOG_ALERT,"Fatal dup2 error 1");
 
219
                exit(4);
 
220
                }
 
221
            /* And the standard error */
 
222
            if(dup2(stream1[1],2) != 2) {
 
223
                syslog(LOG_ALERT,"Fatal dup2 error 2");
 
224
                exit(5);
 
225
                }
 
226
            argv[0] = argv[exec_argv_offset];
 
227
            execvp(argv[exec_argv_offset],argv + exec_argv_offset);
 
228
            /* OK, not found */
 
229
            printf("duende: %s: Command can't run, terminating\n",argv[exec_argv_offset]);
 
230
            syslog(LOG_ALERT,"Command can't run, terminating\n");
 
231
            exit(1);
 
232
            }
 
233
 
 
234
        /* Parent */
 
235
        close(stream1[1]);
 
236
        log_pid = fork();
 
237
        if(log_pid == 0) { /* Child to syslog all of MaraDNS' output */
 
238
            argv[0] = "duende-log-helper";
 
239
            log_helper(argv[exec_argv_offset],stream1[0]);
 
240
            syslog(LOG_ALERT,"log_helper finished, terminating\n");
 
241
            exit(1);
 
242
            }
 
243
        for(;;) {
 
244
            /* If we got a HUP signal, send it to the child */
 
245
            if(got_hup_signal == 1) {
 
246
                kill(pid,SIGHUP);
 
247
                got_hup_signal = 0;
 
248
                }
 
249
            /* If we got a TERM or INT signal, send it to the children
 
250
               then exit ourselves */
 
251
            else if(got_term_signal == 1) {
 
252
                /* XXX: make sure term really stops the children */
 
253
                kill(pid,SIGTERM);
 
254
                kill(log_pid,SIGTERM);
 
255
                syslog(LOG_ALERT,"got term signal, terminating\n");
 
256
                exit(0);
 
257
                }
 
258
            sleep(1);
 
259
            if(waitpid(pid,&exit_status,WNOHANG) == pid) { /* If child ended */
 
260
                handle_child_exited(exit_status,log_pid,pid);
 
261
                close(stream1[0]);
 
262
                break; /* Out of the inner loop; re-start Mara */
 
263
                }
 
264
            /* If logger terminated */
 
265
            if(waitpid(log_pid,&exit_status,WNOHANG) == log_pid) {
 
266
                handle_child_exited(exit_status,pid,log_pid);
 
267
                close(stream1[0]);
 
268
                break; /* Out of the inner loop; re-start Mara */
 
269
                }
 
270
            }
 
271
        }
 
272
    }
 
273