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
231243730Srwatson	kq = kqueue();
232243730Srwatson	if (kq == -1) {
233243730Srwatson		pjdlog_errno(LOG_WARNING, "kqueue() failed");
234243730Srwatson		return (-1);
235243730Srwatson	}
236243730Srwatson	EV_SET(&ev[0], fd, EVFILT_VNODE, EV_ADD | EV_ENABLE | EV_CLEAR,
237243730Srwatson	    NOTE_RENAME, 0, 0);
238243730Srwatson	EV_SET(&ev[1], fd, EVFILT_READ, EV_ADD | EV_ENABLE | EV_CLEAR,
239243730Srwatson	    0, 0, 0);
240243730Srwatson	if (kevent(kq, ev, 2, NULL, 0, NULL) == -1) {
241243730Srwatson		error = errno;
242243730Srwatson		pjdlog_errno(LOG_WARNING, "kevent() failed");
243243730Srwatson		(void)close(kq);
244243730Srwatson		errno = error;
245243730Srwatson		return (-1);
246243730Srwatson	}
247243730Srwatson	wait_for_file_kq = kq;
248243730Srwatson#endif
249243730Srwatson
250243730Srwatson	return (0);
251243730Srwatson}
252243730Srwatson
253243730Srwatson/*
254243730Srwatson * Wait for new file to appear in directory.
255243730Srwatson */
256243730Srwatsonvoid
257243730Srwatsonwait_for_dir(void)
258243730Srwatson{
259243730Srwatson#ifdef HAVE_KQUEUE
260243730Srwatson	struct kevent ev;
261243730Srwatson#endif
262243730Srwatson
263243730Srwatson	if (wait_for_dir_kq == -1) {
264243730Srwatson		sleep(1);
265243730Srwatson		return;
266243730Srwatson	}
267243730Srwatson
268243730Srwatson#ifdef HAVE_KQUEUE
269243730Srwatson	PJDLOG_ASSERT(wait_for_dir_kq != -1);
270243730Srwatson
271243730Srwatson	if (kevent(wait_for_dir_kq, NULL, 0, &ev, 1, NULL) == -1) {
272243730Srwatson		pjdlog_errno(LOG_WARNING, "kevent() failed");
273243730Srwatson		sleep(1);
274243730Srwatson	}
275243730Srwatson#endif
276243730Srwatson}
277243730Srwatson
278243730Srwatson/*
279243730Srwatson * Wait for file growth or rename.
280243730Srwatson */
281243730Srwatsonvoid
282243730Srwatsonwait_for_file(void)
283243730Srwatson{
284243730Srwatson#ifdef HAVE_KQUEUE
285243730Srwatson	struct kevent ev[2];
286243730Srwatson#endif
287243730Srwatson
288243730Srwatson	if (wait_for_file_kq == -1) {
289243730Srwatson		sleep(1);
290243730Srwatson		return;
291243730Srwatson	}
292243730Srwatson
293243730Srwatson#ifdef HAVE_KQUEUE
294243730Srwatson	PJDLOG_ASSERT(wait_for_file_kq != -1);
295243730Srwatson
296243730Srwatson	if (kevent(wait_for_file_kq, NULL, 0, ev, 2, NULL) == -1) {
297243730Srwatson		pjdlog_errno(LOG_WARNING, "kevent() failed");
298243730Srwatson		sleep(1);
299243730Srwatson	}
300243730Srwatson#endif
301243730Srwatson}
302