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