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