Imported Upstream version 2.4.3
[platform/upstream/audit.git] / src / auditd-dispatch.c
1 /* auditd-dispatch.c -- 
2  * Copyright 2005-07,2013 Red Hat Inc., Durham, North Carolina.
3  * All Rights Reserved.
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  *
19  * Authors:
20  *   Steve Grubb <sgrubb@redhat.com>
21  *   Junji Kanemaru <junji.kanemaru@linuon.com>
22  */
23
24 #include "config.h"
25 #include <unistd.h>
26 #include <sys/uio.h>
27 #include <fcntl.h>
28 #include <signal.h>
29 #include <errno.h>
30 #include <string.h>
31 #include <stdlib.h>
32
33 #include "libaudit.h"
34 #include "private.h"
35 #include "auditd-dispatch.h"
36
37 /* This is the communications channel between auditd & the dispatcher */
38 static int disp_pipe[2] = {-1, -1};
39 static pid_t pid = 0;
40 static int n_errs = 0;
41 #define REPORT_LIMIT 10
42
43 int dispatcher_pid(void)
44 {
45         return pid;
46 }
47
48 void dispatcher_reaped(void)
49 {
50         audit_msg(LOG_INFO, "dispatcher %d reaped\n", pid);
51         pid = 0;
52         shutdown_dispatcher();
53 }
54
55 /* set_flags: to set flags to file desc */
56 static int set_flags(int fn, int flags)
57 {
58         int fl;
59
60         if ((fl = fcntl(fn, F_GETFL, 0)) < 0) {
61                 audit_msg(LOG_ERR, "fcntl failed. Cannot get flags (%s)\n", 
62                         strerror(errno));
63                 return fl;
64         }
65
66         fl |= flags;
67
68         return fcntl(fn, F_SETFL, fl);
69 }
70
71 /* This function returns 1 on error & 0 on success */
72 int init_dispatcher(const struct daemon_conf *config)
73 {
74         struct sigaction sa;
75
76         if (config->dispatcher == NULL) 
77                 return 0;
78
79         if (socketpair(AF_UNIX, SOCK_STREAM, 0, disp_pipe)) {
80                 audit_msg(LOG_ERR, "Failed creating disp_pipe");
81                 return 1;
82         }
83
84         /* Make both disp_pipe non-blocking */
85         if (config->qos == QOS_NON_BLOCKING) {
86                 if (set_flags(disp_pipe[0], O_NONBLOCK) < 0 ||
87                         set_flags(disp_pipe[1], O_NONBLOCK) < 0) {
88                         audit_msg(LOG_ERR, "Failed to set O_NONBLOCK flag");
89                         return 1;
90                 }
91         }
92
93         // do the fork
94         pid = fork();
95         switch(pid) {
96                 case 0: // child
97                         dup2(disp_pipe[0], 0);
98                         close(disp_pipe[0]);
99                         close(disp_pipe[1]);
100                         sigfillset (&sa.sa_mask);
101                         sigprocmask (SIG_UNBLOCK, &sa.sa_mask, 0);
102                         setsid();
103                         execl(config->dispatcher, config->dispatcher, NULL);
104                         audit_msg(LOG_ERR, "exec() failed");
105                         exit(1);
106                         break;
107                 case -1:        // error
108                         return 1;
109                         break;
110                 default:        // parent
111                         close(disp_pipe[0]);
112                         disp_pipe[0] = -1;
113                         /* Avoid leaking this */
114                         if (fcntl(disp_pipe[1], F_SETFD, FD_CLOEXEC) < 0) {
115                                 audit_msg(LOG_ERR,
116                                         "Failed to set FD_CLOEXEC flag");
117                                 return 1;
118                         }
119                         audit_msg(LOG_INFO, "Started dispatcher: %s pid: %u",
120                                         config->dispatcher, pid);
121                         break;
122         }
123
124         return 0;
125 }
126
127 void shutdown_dispatcher(void)
128 {
129         // kill child
130         if (pid)
131                 kill(pid, SIGTERM);
132         // wait for term
133         // if not in time, send sigkill
134         pid = 0;
135
136         // cleanup comm pipe
137         if (disp_pipe[0] >= 0) {
138                 close(disp_pipe[0]);
139                 disp_pipe[0] = -1;
140         }
141         if (disp_pipe[1] >= 0) {
142                 close(disp_pipe[1]);
143                 disp_pipe[1] = -1;
144         }
145 }
146
147 void reconfigure_dispatcher(const struct daemon_conf *config)
148 {
149         // signal child or start it so it can see if config changed
150         if (pid)
151                 kill(pid, SIGHUP);
152         else
153                 init_dispatcher(config);
154 }
155
156 /* Returns -1 on err, 0 on success, and 1 if eagain occurred and not an err */
157 int dispatch_event(const struct audit_reply *rep, int is_err)
158 {
159         int rc, count = 0;
160         struct iovec vec[2];
161         struct audit_dispatcher_header hdr;
162
163         if (disp_pipe[1] == -1)
164                 return 0;
165
166         // Don't send reconfig or rotate as they are purely internal to daemon
167         if (rep->type == AUDIT_DAEMON_RECONFIG ||
168                                         rep->type == AUDIT_DAEMON_ROTATE)
169                 return 0;
170
171         hdr.ver = AUDISP_PROTOCOL_VER; /* Hard-coded to current protocol */
172         hdr.hlen = sizeof(struct audit_dispatcher_header);
173         hdr.type = rep->type;
174         hdr.size = rep->len;
175
176         vec[0].iov_base = (void*)&hdr;
177         vec[0].iov_len = sizeof(hdr);
178         vec[1].iov_base = (void*)rep->message;
179         vec[1].iov_len = rep->len;
180
181         do {
182                 rc = writev(disp_pipe[1], vec, 2);
183         } while (rc < 0 && errno == EAGAIN && count++ < 8);
184
185         // close pipe if no child or peer has been lost
186         if (rc <= 0) {
187                 if (errno == EPIPE) {
188                         shutdown_dispatcher();
189                         n_errs = 0;
190                 } else if (errno == EAGAIN && !is_err) {
191                         return 1;
192                 } else {
193                         if (n_errs <= REPORT_LIMIT) {
194                                 audit_msg(LOG_ERR, 
195                                         "dispatch err (%s) event lost",
196                                         errno == EAGAIN ? "pipe full" :
197                                         strerror(errno));
198                                 n_errs++;
199                         }
200                         if (n_errs == REPORT_LIMIT) {
201                                 audit_msg(LOG_ERR, 
202                                         "dispatch error reporting limit"
203                                         " reached - ending report"
204                                         " notification.");
205                                 n_errs++;
206                         }
207                         return -1;
208                 }
209         } else
210                 n_errs = 0;
211         return 0;
212 }
213