1243730Srwatson/*-
2243730Srwatson * Copyright (c) 2011-2012 Pawel Jakub Dawidek <pawel@dawidek.net>
3243730Srwatson * All rights reserved.
4243730Srwatson *
5243730Srwatson * Redistribution and use in source and binary forms, with or without
6243730Srwatson * modification, are permitted provided that the following conditions
7243730Srwatson * are met:
8243730Srwatson * 1. Redistributions of source code must retain the above copyright
9243730Srwatson *    notice, this list of conditions and the following disclaimer.
10243730Srwatson * 2. Redistributions in binary form must reproduce the above copyright
11243730Srwatson *    notice, this list of conditions and the following disclaimer in the
12243730Srwatson *    documentation and/or other materials provided with the distribution.
13243730Srwatson *
14243730Srwatson * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
15243730Srwatson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16243730Srwatson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17243730Srwatson * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
18243730Srwatson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19243730Srwatson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20243730Srwatson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21243730Srwatson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22243730Srwatson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23243730Srwatson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24243730Srwatson * SUCH DAMAGE.
25243730Srwatson *
26243734Srwatson * $P4: //depot/projects/trustedbsd/openbsm/bin/auditdistd/subr.c#3 $
27243730Srwatson */
28243730Srwatson
29243734Srwatson#include <config/config.h>
30243730Srwatson
31243730Srwatson#ifdef HAVE_KQUEUE
32243730Srwatson#include <sys/types.h>
33243730Srwatson#include <sys/event.h>
34243730Srwatson#include <sys/time.h>
35243730Srwatson#endif
36243730Srwatson
37243730Srwatson#include <errno.h>
38243730Srwatson#include <stdarg.h>
39243730Srwatson#include <stdio.h>
40243730Srwatson#include <string.h>
41243730Srwatson#include <unistd.h>
42243730Srwatson
43243730Srwatson#ifndef HAVE_ARC4RANDOM
44243730Srwatson#include <openssl/rand.h>
45243730Srwatson#endif
46243730Srwatson
47243730Srwatson#ifndef HAVE_STRLCAT
48243730Srwatson#include <compat/strlcat.h>
49243730Srwatson#endif
50243730Srwatson
51243730Srwatson#include "auditdistd.h"
52243734Srwatson#include "pjdlog.h"
53243730Srwatson#include "subr.h"
54243730Srwatson
55243730Srwatsonint
56243730Srwatsonvsnprlcat(char *str, size_t size, const char *fmt, va_list ap)
57243730Srwatson{
58243730Srwatson	size_t len;
59243730Srwatson
60243730Srwatson	len = strlen(str);
61243730Srwatson	return (vsnprintf(str + len, size - len, fmt, ap));
62243730Srwatson}
63243730Srwatson
64243730Srwatsonint
65243730Srwatsonsnprlcat(char *str, size_t size, const char *fmt, ...)
66243730Srwatson{
67243730Srwatson	va_list ap;
68243730Srwatson	int result;
69243730Srwatson
70243730Srwatson	va_start(ap, fmt);
71243730Srwatson	result = vsnprlcat(str, size, fmt, ap);
72243730Srwatson	va_end(ap);
73243730Srwatson	return (result);
74243730Srwatson}
75243730Srwatson
76243730Srwatsonconst char *
77243730Srwatsonrole2str(int role)
78243730Srwatson{
79243730Srwatson
80243730Srwatson	switch (role) {
81243730Srwatson	case ADIST_ROLE_SENDER:
82243730Srwatson		return ("sender");
83243730Srwatson	case ADIST_ROLE_RECEIVER:
84243730Srwatson		return ("receiver");
85243730Srwatson	}
86243730Srwatson	return ("unknown");
87243730Srwatson}
88243730Srwatson
89243730Srwatsonconst char *
90243730Srwatsonadist_errstr(int error)
91243730Srwatson{
92243730Srwatson
93243730Srwatson	switch (error) {
94243730Srwatson	case ADIST_ERROR_WRONG_ORDER:
95243730Srwatson		return ("wrong operations order");
96243730Srwatson	case ADIST_ERROR_INVALID_NAME:
97243730Srwatson		return ("invalid trail file name");
98243730Srwatson	case ADIST_ERROR_OPEN_OLD:
99243730Srwatson		return ("attempt to open an old trail file");
100243730Srwatson	case ADIST_ERROR_CREATE:
101243730Srwatson		return ("creation of new trail file failed");
102243730Srwatson	case ADIST_ERROR_OPEN:
103243730Srwatson		return ("open of existing trail file failed");
104243730Srwatson	case ADIST_ERROR_READ:
105243730Srwatson		return ("read failed");
106243730Srwatson	case ADIST_ERROR_WRITE:
107243730Srwatson		return ("write failed");
108243730Srwatson	case ADIST_ERROR_RENAME:
109243730Srwatson		return ("rename of a trail file failed");
110243730Srwatson	default:
111243730Srwatson		return ("unknown error");
112243730Srwatson	}
113243730Srwatson}
114243730Srwatson
115243730Srwatsonvoid
116243730Srwatsonadreq_log(int loglevel, int debuglevel, int error, struct adreq *adreq,
117243730Srwatson    const char *fmt, ...)
118243730Srwatson{
119243730Srwatson	char msg[1024];
120243730Srwatson	va_list ap;
121243730Srwatson
122243730Srwatson	va_start(ap, fmt);
123243730Srwatson	(void)vsnprintf(msg, sizeof(msg), fmt, ap);
124243730Srwatson	va_end(ap);
125243730Srwatson	(void)snprlcat(msg, sizeof(msg), "(seq=%ju) ",
126243730Srwatson	    (uintmax_t)adreq->adr_seq);
127243730Srwatson	switch (adreq->adr_cmd) {
128243730Srwatson	case ADIST_CMD_OPEN:
129243730Srwatson		(void)snprlcat(msg, sizeof(msg), "OPEN(%s)",
130243730Srwatson		    adreq->adr_data);
131243730Srwatson		break;
132243730Srwatson	case ADIST_CMD_APPEND:
133243730Srwatson		(void)snprlcat(msg, sizeof(msg), "APPEND(%ju)",
134243730Srwatson		    (uintmax_t)adreq->adr_datasize);
135243730Srwatson		break;
136243730Srwatson	case ADIST_CMD_CLOSE:
137243730Srwatson		(void)snprlcat(msg, sizeof(msg), "CLOSE(%s)",
138243730Srwatson		    adreq->adr_data);
139243730Srwatson		break;
140243730Srwatson	case ADIST_CMD_KEEPALIVE:
141243730Srwatson		(void)snprlcat(msg, sizeof(msg), "KEEPALIVE");
142243730Srwatson		break;
143243730Srwatson	case ADIST_CMD_ERROR:
144243730Srwatson		(void)snprlcat(msg, sizeof(msg), "ERROR");
145243730Srwatson		break;
146243730Srwatson	default:
147243730Srwatson		(void)snprlcat(msg, sizeof(msg), "UNKNOWN(%hhu)",
148243730Srwatson		    adreq->adr_cmd);
149243730Srwatson		break;
150243730Srwatson	}
151243730Srwatson	if (error != -1)
152243730Srwatson		(void)snprlcat(msg, sizeof(msg), ": %s", adist_errstr(error));
153243730Srwatson	(void)strlcat(msg, ".", sizeof(msg));
154243730Srwatson	pjdlog_common(loglevel, debuglevel, -1, "%s", msg);
155243730Srwatson}
156243730Srwatson
157243730Srwatsonint
158243730Srwatsonadist_random(unsigned char *buf, size_t size)
159243730Srwatson{
160243730Srwatson#ifdef HAVE_ARC4RANDOM_BUF
161243730Srwatson	arc4random_buf(buf, size);
162243730Srwatson	return (0);
163243730Srwatson#elif defined(HAVE_ARC4RANDOM)
164243730Srwatson	uint32_t val;
165243730Srwatson
166243730Srwatson	PJDLOG_ASSERT(size > 0);
167243730Srwatson	PJDLOG_ASSERT((size % sizeof(val)) == 0);
168243730Srwatson
169243730Srwatson	do {
170243730Srwatson		val = arc4random();
171243730Srwatson		bcopy(&val, buf, sizeof(val));
172243730Srwatson		buf += sizeof(val);
173243730Srwatson		size -= sizeof(val);
174243730Srwatson	} while (size > 0);
175243730Srwatson
176243730Srwatson	return (0);
177243730Srwatson#else
178243730Srwatson	if (RAND_bytes(buf, (int)size) == 0)
179243730Srwatson		return (-1);
180243730Srwatson	return (0);
181243730Srwatson#endif
182243730Srwatson}
183243730Srwatson
184243730Srwatsonstatic int wait_for_dir_kq = -1;
185243730Srwatsonstatic int wait_for_file_kq = -1;
186243730Srwatson
187243730Srwatsonint
188243730Srwatsonwait_for_dir_init(int fd)
189243730Srwatson{
190243730Srwatson#ifdef HAVE_KQUEUE
191243730Srwatson	struct kevent ev;
192243730Srwatson	int error, kq;
193243730Srwatson
194243730Srwatson	PJDLOG_ASSERT(wait_for_dir_kq == -1);
195243730Srwatson#endif
196243730Srwatson
197243730Srwatson	PJDLOG_ASSERT(fd != -1);
198243730Srwatson
199243730Srwatson#ifdef HAVE_KQUEUE
200243730Srwatson	kq = kqueue();
201243730Srwatson	if (kq == -1) {
202243730Srwatson		pjdlog_errno(LOG_WARNING, "kqueue() failed");
203243730Srwatson		return (-1);
204243730Srwatson	}
205243730Srwatson	EV_SET(&ev, fd, EVFILT_VNODE, EV_ADD | EV_ENABLE | EV_CLEAR,
206243730Srwatson	    NOTE_WRITE, 0, 0);
207243730Srwatson	if (kevent(kq, &ev, 1, NULL, 0, NULL) == -1) {
208243730Srwatson		error = errno;
209243730Srwatson		pjdlog_errno(LOG_WARNING, "kevent() failed");
210243730Srwatson		(void)close(kq);
211243730Srwatson		errno = error;
212243730Srwatson		return (-1);
213243730Srwatson	}
214243730Srwatson	wait_for_dir_kq = kq;
215243730Srwatson#endif
216243730Srwatson
217243730Srwatson	return (0);
218243730Srwatson}
219243730Srwatson
220243730Srwatsonint
221243730Srwatsonwait_for_file_init(int fd)
222243730Srwatson{
223243730Srwatson#ifdef HAVE_KQUEUE
224243730Srwatson	struct kevent ev[2];
225243730Srwatson	int error, kq;
226243730Srwatson#endif
227243730Srwatson
228243730Srwatson	PJDLOG_ASSERT(fd != -1);
229243730Srwatson
230243730Srwatson#ifdef HAVE_KQUEUE
231271844Spjd	if (wait_for_file_kq != -1) {
232271844Spjd		close(wait_for_file_kq);
233271844Spjd		wait_for_file_kq = -1;
234271844Spjd	}
235271844Spjd
236243730Srwatson	kq = kqueue();
237243730Srwatson	if (kq == -1) {
238243730Srwatson		pjdlog_errno(LOG_WARNING, "kqueue() failed");
239243730Srwatson		return (-1);
240243730Srwatson	}
241243730Srwatson	EV_SET(&ev[0], fd, EVFILT_VNODE, EV_ADD | EV_ENABLE | EV_CLEAR,
242243730Srwatson	    NOTE_RENAME, 0, 0);
243243730Srwatson	EV_SET(&ev[1], fd, EVFILT_READ, EV_ADD | EV_ENABLE | EV_CLEAR,
244243730Srwatson	    0, 0, 0);
245243730Srwatson	if (kevent(kq, ev, 2, NULL, 0, NULL) == -1) {
246243730Srwatson		error = errno;
247243730Srwatson		pjdlog_errno(LOG_WARNING, "kevent() failed");
248243730Srwatson		(void)close(kq);
249243730Srwatson		errno = error;
250243730Srwatson		return (-1);
251243730Srwatson	}
252243730Srwatson	wait_for_file_kq = kq;
253243730Srwatson#endif
254243730Srwatson
255243730Srwatson	return (0);
256243730Srwatson}
257243730Srwatson
258243730Srwatson/*
259243730Srwatson * Wait for new file to appear in directory.
260243730Srwatson */
261243730Srwatsonvoid
262243730Srwatsonwait_for_dir(void)
263243730Srwatson{
264243730Srwatson#ifdef HAVE_KQUEUE
265243730Srwatson	struct kevent ev;
266243730Srwatson#endif
267243730Srwatson
268243730Srwatson	if (wait_for_dir_kq == -1) {
269243730Srwatson		sleep(1);
270243730Srwatson		return;
271243730Srwatson	}
272243730Srwatson
273243730Srwatson#ifdef HAVE_KQUEUE
274243730Srwatson	PJDLOG_ASSERT(wait_for_dir_kq != -1);
275243730Srwatson
276243730Srwatson	if (kevent(wait_for_dir_kq, NULL, 0, &ev, 1, NULL) == -1) {
277243730Srwatson		pjdlog_errno(LOG_WARNING, "kevent() failed");
278243730Srwatson		sleep(1);
279243730Srwatson	}
280243730Srwatson#endif
281243730Srwatson}
282243730Srwatson
283243730Srwatson/*
284243730Srwatson * Wait for file growth or rename.
285243730Srwatson */
286243730Srwatsonvoid
287243730Srwatsonwait_for_file(void)
288243730Srwatson{
289243730Srwatson#ifdef HAVE_KQUEUE
290243730Srwatson	struct kevent ev[2];
291243730Srwatson#endif
292243730Srwatson
293243730Srwatson	if (wait_for_file_kq == -1) {
294243730Srwatson		sleep(1);
295243730Srwatson		return;
296243730Srwatson	}
297243730Srwatson
298243730Srwatson#ifdef HAVE_KQUEUE
299243730Srwatson	PJDLOG_ASSERT(wait_for_file_kq != -1);
300243730Srwatson
301243730Srwatson	if (kevent(wait_for_file_kq, NULL, 0, ev, 2, NULL) == -1) {
302243730Srwatson		pjdlog_errno(LOG_WARNING, "kevent() failed");
303243730Srwatson		sleep(1);
304243730Srwatson	}
305243730Srwatson#endif
306243730Srwatson}
307