xref: /freebsd/contrib/openbsm/bin/auditdistd/subr.c (revision c6db8143eda5c775467145ac73e8ebec47afdd8f)
1 /*-
2  * Copyright (c) 2011-2012 Pawel Jakub Dawidek <pawel@dawidek.net>
3  * All rights reserved.
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  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  * $P4: //depot/projects/trustedbsd/openbsm/bin/auditdistd/subr.c#3 $
27  */
28 
29 #include <config/config.h>
30 
31 #ifdef HAVE_KQUEUE
32 #include <sys/types.h>
33 #include <sys/event.h>
34 #include <sys/time.h>
35 #endif
36 
37 #include <errno.h>
38 #include <stdarg.h>
39 #include <stdio.h>
40 #include <string.h>
41 #include <unistd.h>
42 
43 #ifndef HAVE_ARC4RANDOM
44 #include <openssl/rand.h>
45 #endif
46 
47 #ifndef HAVE_STRLCAT
48 #include <compat/strlcat.h>
49 #endif
50 
51 #include "auditdistd.h"
52 #include "pjdlog.h"
53 #include "subr.h"
54 
55 int
56 vsnprlcat(char *str, size_t size, const char *fmt, va_list ap)
57 {
58 	size_t len;
59 
60 	len = strlen(str);
61 	return (vsnprintf(str + len, size - len, fmt, ap));
62 }
63 
64 int
65 snprlcat(char *str, size_t size, const char *fmt, ...)
66 {
67 	va_list ap;
68 	int result;
69 
70 	va_start(ap, fmt);
71 	result = vsnprlcat(str, size, fmt, ap);
72 	va_end(ap);
73 	return (result);
74 }
75 
76 const char *
77 role2str(int role)
78 {
79 
80 	switch (role) {
81 	case ADIST_ROLE_SENDER:
82 		return ("sender");
83 	case ADIST_ROLE_RECEIVER:
84 		return ("receiver");
85 	}
86 	return ("unknown");
87 }
88 
89 const char *
90 adist_errstr(int error)
91 {
92 
93 	switch (error) {
94 	case ADIST_ERROR_WRONG_ORDER:
95 		return ("wrong operations order");
96 	case ADIST_ERROR_INVALID_NAME:
97 		return ("invalid trail file name");
98 	case ADIST_ERROR_OPEN_OLD:
99 		return ("attempt to open an old trail file");
100 	case ADIST_ERROR_CREATE:
101 		return ("creation of new trail file failed");
102 	case ADIST_ERROR_OPEN:
103 		return ("open of existing trail file failed");
104 	case ADIST_ERROR_READ:
105 		return ("read failed");
106 	case ADIST_ERROR_WRITE:
107 		return ("write failed");
108 	case ADIST_ERROR_RENAME:
109 		return ("rename of a trail file failed");
110 	default:
111 		return ("unknown error");
112 	}
113 }
114 
115 void
116 adreq_log(int loglevel, int debuglevel, int error, struct adreq *adreq,
117     const char *fmt, ...)
118 {
119 	char msg[1024];
120 	va_list ap;
121 
122 	va_start(ap, fmt);
123 	(void)vsnprintf(msg, sizeof(msg), fmt, ap);
124 	va_end(ap);
125 	(void)snprlcat(msg, sizeof(msg), "(seq=%ju) ",
126 	    (uintmax_t)adreq->adr_seq);
127 	switch (adreq->adr_cmd) {
128 	case ADIST_CMD_OPEN:
129 		(void)snprlcat(msg, sizeof(msg), "OPEN(%s)",
130 		    adreq->adr_data);
131 		break;
132 	case ADIST_CMD_APPEND:
133 		(void)snprlcat(msg, sizeof(msg), "APPEND(%ju)",
134 		    (uintmax_t)adreq->adr_datasize);
135 		break;
136 	case ADIST_CMD_CLOSE:
137 		(void)snprlcat(msg, sizeof(msg), "CLOSE(%s)",
138 		    adreq->adr_data);
139 		break;
140 	case ADIST_CMD_KEEPALIVE:
141 		(void)snprlcat(msg, sizeof(msg), "KEEPALIVE");
142 		break;
143 	case ADIST_CMD_ERROR:
144 		(void)snprlcat(msg, sizeof(msg), "ERROR");
145 		break;
146 	default:
147 		(void)snprlcat(msg, sizeof(msg), "UNKNOWN(%hhu)",
148 		    adreq->adr_cmd);
149 		break;
150 	}
151 	if (error != -1)
152 		(void)snprlcat(msg, sizeof(msg), ": %s", adist_errstr(error));
153 	(void)strlcat(msg, ".", sizeof(msg));
154 	pjdlog_common(loglevel, debuglevel, -1, "%s", msg);
155 }
156 
157 int
158 adist_random(unsigned char *buf, size_t size)
159 {
160 #ifdef HAVE_ARC4RANDOM_BUF
161 	arc4random_buf(buf, size);
162 	return (0);
163 #elif defined(HAVE_ARC4RANDOM)
164 	uint32_t val;
165 
166 	PJDLOG_ASSERT(size > 0);
167 	PJDLOG_ASSERT((size % sizeof(val)) == 0);
168 
169 	do {
170 		val = arc4random();
171 		bcopy(&val, buf, sizeof(val));
172 		buf += sizeof(val);
173 		size -= sizeof(val);
174 	} while (size > 0);
175 
176 	return (0);
177 #else
178 	if (RAND_bytes(buf, (int)size) == 0)
179 		return (-1);
180 	return (0);
181 #endif
182 }
183 
184 static int wait_for_dir_kq = -1;
185 static int wait_for_file_kq = -1;
186 
187 int
188 wait_for_dir_init(int fd)
189 {
190 #ifdef HAVE_KQUEUE
191 	struct kevent ev;
192 	int error, kq;
193 
194 	PJDLOG_ASSERT(wait_for_dir_kq == -1);
195 #endif
196 
197 	PJDLOG_ASSERT(fd != -1);
198 
199 #ifdef HAVE_KQUEUE
200 	kq = kqueue();
201 	if (kq == -1) {
202 		pjdlog_errno(LOG_WARNING, "kqueue() failed");
203 		return (-1);
204 	}
205 	EV_SET(&ev, fd, EVFILT_VNODE, EV_ADD | EV_ENABLE | EV_CLEAR,
206 	    NOTE_WRITE, 0, 0);
207 	if (kevent(kq, &ev, 1, NULL, 0, NULL) == -1) {
208 		error = errno;
209 		pjdlog_errno(LOG_WARNING, "kevent() failed");
210 		(void)close(kq);
211 		errno = error;
212 		return (-1);
213 	}
214 	wait_for_dir_kq = kq;
215 #endif
216 
217 	return (0);
218 }
219 
220 int
221 wait_for_file_init(int fd)
222 {
223 #ifdef HAVE_KQUEUE
224 	struct kevent ev[2];
225 	int error, kq;
226 #endif
227 
228 	PJDLOG_ASSERT(fd != -1);
229 
230 #ifdef HAVE_KQUEUE
231 	if (wait_for_file_kq != -1) {
232 		close(wait_for_file_kq);
233 		wait_for_file_kq = -1;
234 	}
235 
236 	kq = kqueue();
237 	if (kq == -1) {
238 		pjdlog_errno(LOG_WARNING, "kqueue() failed");
239 		return (-1);
240 	}
241 	EV_SET(&ev[0], fd, EVFILT_VNODE, EV_ADD | EV_ENABLE | EV_CLEAR,
242 	    NOTE_RENAME, 0, 0);
243 	EV_SET(&ev[1], fd, EVFILT_READ, EV_ADD | EV_ENABLE | EV_CLEAR,
244 	    0, 0, 0);
245 	if (kevent(kq, ev, 2, NULL, 0, NULL) == -1) {
246 		error = errno;
247 		pjdlog_errno(LOG_WARNING, "kevent() failed");
248 		(void)close(kq);
249 		errno = error;
250 		return (-1);
251 	}
252 	wait_for_file_kq = kq;
253 #endif
254 
255 	return (0);
256 }
257 
258 /*
259  * Wait for new file to appear in directory.
260  */
261 void
262 wait_for_dir(void)
263 {
264 #ifdef HAVE_KQUEUE
265 	struct kevent ev;
266 #endif
267 
268 	if (wait_for_dir_kq == -1) {
269 		sleep(1);
270 		return;
271 	}
272 
273 #ifdef HAVE_KQUEUE
274 	PJDLOG_ASSERT(wait_for_dir_kq != -1);
275 
276 	if (kevent(wait_for_dir_kq, NULL, 0, &ev, 1, NULL) == -1) {
277 		pjdlog_errno(LOG_WARNING, "kevent() failed");
278 		sleep(1);
279 	}
280 #endif
281 }
282 
283 /*
284  * Wait for file growth or rename.
285  */
286 void
287 wait_for_file(void)
288 {
289 #ifdef HAVE_KQUEUE
290 	struct kevent ev[2];
291 #endif
292 
293 	if (wait_for_file_kq == -1) {
294 		sleep(1);
295 		return;
296 	}
297 
298 #ifdef HAVE_KQUEUE
299 	PJDLOG_ASSERT(wait_for_file_kq != -1);
300 
301 	if (kevent(wait_for_file_kq, NULL, 0, ev, 2, NULL) == -1) {
302 		pjdlog_errno(LOG_WARNING, "kevent() failed");
303 		sleep(1);
304 	}
305 #endif
306 }
307