subr.c revision 243730
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#1 $
27 */
28
29#include "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 <pjdlog.h>
52
53#include "auditdistd.h"
54#include "subr.h"
55
56int
57vsnprlcat(char *str, size_t size, const char *fmt, va_list ap)
58{
59	size_t len;
60
61	len = strlen(str);
62	return (vsnprintf(str + len, size - len, fmt, ap));
63}
64
65int
66snprlcat(char *str, size_t size, const char *fmt, ...)
67{
68	va_list ap;
69	int result;
70
71	va_start(ap, fmt);
72	result = vsnprlcat(str, size, fmt, ap);
73	va_end(ap);
74	return (result);
75}
76
77const char *
78role2str(int role)
79{
80
81	switch (role) {
82	case ADIST_ROLE_SENDER:
83		return ("sender");
84	case ADIST_ROLE_RECEIVER:
85		return ("receiver");
86	}
87	return ("unknown");
88}
89
90const char *
91adist_errstr(int error)
92{
93
94	switch (error) {
95	case ADIST_ERROR_WRONG_ORDER:
96		return ("wrong operations order");
97	case ADIST_ERROR_INVALID_NAME:
98		return ("invalid trail file name");
99	case ADIST_ERROR_OPEN_OLD:
100		return ("attempt to open an old trail file");
101	case ADIST_ERROR_CREATE:
102		return ("creation of new trail file failed");
103	case ADIST_ERROR_OPEN:
104		return ("open of existing trail file failed");
105	case ADIST_ERROR_READ:
106		return ("read failed");
107	case ADIST_ERROR_WRITE:
108		return ("write failed");
109	case ADIST_ERROR_RENAME:
110		return ("rename of a trail file failed");
111	default:
112		return ("unknown error");
113	}
114}
115
116void
117adreq_log(int loglevel, int debuglevel, int error, struct adreq *adreq,
118    const char *fmt, ...)
119{
120	char msg[1024];
121	va_list ap;
122
123	va_start(ap, fmt);
124	(void)vsnprintf(msg, sizeof(msg), fmt, ap);
125	va_end(ap);
126	(void)snprlcat(msg, sizeof(msg), "(seq=%ju) ",
127	    (uintmax_t)adreq->adr_seq);
128	switch (adreq->adr_cmd) {
129	case ADIST_CMD_OPEN:
130		(void)snprlcat(msg, sizeof(msg), "OPEN(%s)",
131		    adreq->adr_data);
132		break;
133	case ADIST_CMD_APPEND:
134		(void)snprlcat(msg, sizeof(msg), "APPEND(%ju)",
135		    (uintmax_t)adreq->adr_datasize);
136		break;
137	case ADIST_CMD_CLOSE:
138		(void)snprlcat(msg, sizeof(msg), "CLOSE(%s)",
139		    adreq->adr_data);
140		break;
141	case ADIST_CMD_KEEPALIVE:
142		(void)snprlcat(msg, sizeof(msg), "KEEPALIVE");
143		break;
144	case ADIST_CMD_ERROR:
145		(void)snprlcat(msg, sizeof(msg), "ERROR");
146		break;
147	default:
148		(void)snprlcat(msg, sizeof(msg), "UNKNOWN(%hhu)",
149		    adreq->adr_cmd);
150		break;
151	}
152	if (error != -1)
153		(void)snprlcat(msg, sizeof(msg), ": %s", adist_errstr(error));
154	(void)strlcat(msg, ".", sizeof(msg));
155	pjdlog_common(loglevel, debuglevel, -1, "%s", msg);
156}
157
158int
159adist_random(unsigned char *buf, size_t size)
160{
161#ifdef HAVE_ARC4RANDOM_BUF
162	arc4random_buf(buf, size);
163	return (0);
164#elif defined(HAVE_ARC4RANDOM)
165	uint32_t val;
166
167	PJDLOG_ASSERT(size > 0);
168	PJDLOG_ASSERT((size % sizeof(val)) == 0);
169
170	do {
171		val = arc4random();
172		bcopy(&val, buf, sizeof(val));
173		buf += sizeof(val);
174		size -= sizeof(val);
175	} while (size > 0);
176
177	return (0);
178#else
179	if (RAND_bytes(buf, (int)size) == 0)
180		return (-1);
181	return (0);
182#endif
183}
184
185static int wait_for_dir_kq = -1;
186static int wait_for_file_kq = -1;
187
188int
189wait_for_dir_init(int fd)
190{
191#ifdef HAVE_KQUEUE
192	struct kevent ev;
193	int error, kq;
194
195	PJDLOG_ASSERT(wait_for_dir_kq == -1);
196#endif
197
198	PJDLOG_ASSERT(fd != -1);
199
200#ifdef HAVE_KQUEUE
201	kq = kqueue();
202	if (kq == -1) {
203		pjdlog_errno(LOG_WARNING, "kqueue() failed");
204		return (-1);
205	}
206	EV_SET(&ev, fd, EVFILT_VNODE, EV_ADD | EV_ENABLE | EV_CLEAR,
207	    NOTE_WRITE, 0, 0);
208	if (kevent(kq, &ev, 1, NULL, 0, NULL) == -1) {
209		error = errno;
210		pjdlog_errno(LOG_WARNING, "kevent() failed");
211		(void)close(kq);
212		errno = error;
213		return (-1);
214	}
215	wait_for_dir_kq = kq;
216#endif
217
218	return (0);
219}
220
221int
222wait_for_file_init(int fd)
223{
224#ifdef HAVE_KQUEUE
225	struct kevent ev[2];
226	int error, kq;
227#endif
228
229	PJDLOG_ASSERT(fd != -1);
230
231#ifdef HAVE_KQUEUE
232	kq = kqueue();
233	if (kq == -1) {
234		pjdlog_errno(LOG_WARNING, "kqueue() failed");
235		return (-1);
236	}
237	EV_SET(&ev[0], fd, EVFILT_VNODE, EV_ADD | EV_ENABLE | EV_CLEAR,
238	    NOTE_RENAME, 0, 0);
239	EV_SET(&ev[1], fd, EVFILT_READ, EV_ADD | EV_ENABLE | EV_CLEAR,
240	    0, 0, 0);
241	if (kevent(kq, ev, 2, NULL, 0, NULL) == -1) {
242		error = errno;
243		pjdlog_errno(LOG_WARNING, "kevent() failed");
244		(void)close(kq);
245		errno = error;
246		return (-1);
247	}
248	wait_for_file_kq = kq;
249#endif
250
251	return (0);
252}
253
254/*
255 * Wait for new file to appear in directory.
256 */
257void
258wait_for_dir(void)
259{
260#ifdef HAVE_KQUEUE
261	struct kevent ev;
262#endif
263
264	if (wait_for_dir_kq == -1) {
265		sleep(1);
266		return;
267	}
268
269#ifdef HAVE_KQUEUE
270	PJDLOG_ASSERT(wait_for_dir_kq != -1);
271
272	if (kevent(wait_for_dir_kq, NULL, 0, &ev, 1, NULL) == -1) {
273		pjdlog_errno(LOG_WARNING, "kevent() failed");
274		sleep(1);
275	}
276#endif
277}
278
279/*
280 * Wait for file growth or rename.
281 */
282void
283wait_for_file(void)
284{
285#ifdef HAVE_KQUEUE
286	struct kevent ev[2];
287#endif
288
289	if (wait_for_file_kq == -1) {
290		sleep(1);
291		return;
292	}
293
294#ifdef HAVE_KQUEUE
295	PJDLOG_ASSERT(wait_for_file_kq != -1);
296
297	if (kevent(wait_for_file_kq, NULL, 0, ev, 2, NULL) == -1) {
298		pjdlog_errno(LOG_WARNING, "kevent() failed");
299		sleep(1);
300	}
301#endif
302}
303