1 /*- 2 * Copyright (c) 2012 The FreeBSD Foundation 3 * All rights reserved. 4 * 5 * This software was developed by Pawel Jakub Dawidek under sponsorship from 6 * the FreeBSD Foundation. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 */ 29 30 #include <config/config.h> 31 32 #include <sys/param.h> 33 #include <sys/stat.h> 34 35 #include <dirent.h> 36 #include <errno.h> 37 #include <fcntl.h> 38 #include <stdbool.h> 39 #include <stdint.h> 40 #include <stdlib.h> 41 #include <string.h> 42 #include <unistd.h> 43 44 #include <compat/compat.h> 45 #ifndef HAVE_STRLCPY 46 #include <compat/strlcpy.h> 47 #endif 48 #ifndef HAVE_FACCESSAT 49 #include "faccessat.h" 50 #endif 51 #ifndef HAVE_FSTATAT 52 #include "fstatat.h" 53 #endif 54 #ifndef HAVE_OPENAT 55 #include "openat.h" 56 #endif 57 #ifndef HAVE_UNLINKAT 58 #include "unlinkat.h" 59 #endif 60 61 #include "pjdlog.h" 62 #include "trail.h" 63 64 #define TRAIL_MAGIC 0x79a11 65 struct trail { 66 int tr_magic; 67 /* Path usually to /var/audit/dist/ directory. */ 68 char tr_dirname[PATH_MAX]; 69 /* Descriptor to td_dirname directory. */ 70 DIR *tr_dirfp; 71 /* Path to audit trail file. */ 72 char tr_filename[PATH_MAX]; 73 /* Descriptor to audit trail file. */ 74 int tr_filefd; 75 }; 76 77 #define HALF_LEN 14 78 79 bool 80 trail_is_not_terminated(const char *filename) 81 { 82 83 return (strcmp(filename + HALF_LEN, ".not_terminated") == 0); 84 } 85 86 bool 87 trail_is_crash_recovery(const char *filename) 88 { 89 90 return (strcmp(filename + HALF_LEN, ".crash_recovery") == 0); 91 } 92 93 struct trail * 94 trail_new(const char *dirname, bool create) 95 { 96 struct trail *trail; 97 98 trail = calloc(1, sizeof(*trail)); 99 100 if (strlcpy(trail->tr_dirname, dirname, sizeof(trail->tr_dirname)) >= 101 sizeof(trail->tr_dirname)) { 102 free(trail); 103 pjdlog_error("Directory name too long (\"%s\").", dirname); 104 errno = ENAMETOOLONG; 105 return (NULL); 106 } 107 trail->tr_dirfp = opendir(dirname); 108 if (trail->tr_dirfp == NULL) { 109 if (create && errno == ENOENT) { 110 if (mkdir(dirname, 0700) == -1) { 111 pjdlog_errno(LOG_ERR, 112 "Unable to create directory \"%s\"", 113 dirname); 114 free(trail); 115 return (NULL); 116 } 117 /* TODO: Set directory ownership. */ 118 } else { 119 pjdlog_errno(LOG_ERR, 120 "Unable to open directory \"%s\"", 121 dirname); 122 free(trail); 123 return (NULL); 124 } 125 trail->tr_dirfp = opendir(dirname); 126 if (trail->tr_dirfp == NULL) { 127 pjdlog_errno(LOG_ERR, 128 "Unable to open directory \"%s\"", 129 dirname); 130 free(trail); 131 return (NULL); 132 } 133 } 134 trail->tr_filefd = -1; 135 trail->tr_magic = TRAIL_MAGIC; 136 return (trail); 137 } 138 139 void 140 trail_free(struct trail *trail) 141 { 142 143 PJDLOG_ASSERT(trail->tr_magic == TRAIL_MAGIC); 144 145 if (trail->tr_filefd != -1) 146 trail_close(trail); 147 closedir(trail->tr_dirfp); 148 bzero(trail, sizeof(*trail)); 149 trail->tr_magic = 0; 150 trail->tr_filefd = -1; 151 free(trail); 152 } 153 154 static uint8_t 155 trail_type(DIR *dirfp, const char *filename) 156 { 157 struct stat sb; 158 int dfd; 159 160 PJDLOG_ASSERT(dirfp != NULL); 161 162 dfd = dirfd(dirfp); 163 PJDLOG_ASSERT(dfd >= 0); 164 if (fstatat(dfd, filename, &sb, AT_SYMLINK_NOFOLLOW) == -1) { 165 pjdlog_errno(LOG_ERR, "Unable to stat \"%s\"", filename); 166 return (DT_UNKNOWN); 167 } 168 return (IFTODT(sb.st_mode)); 169 } 170 171 /* 172 * Find trail file by first part of the name in case it was renamed. 173 * First part of the trail file name never changes, but trail file 174 * can be renamed when hosts are disconnected from .not_terminated 175 * to .[0-9]{14} or to .crash_recovery. 176 */ 177 static bool 178 trail_find(struct trail *trail) 179 { 180 struct dirent *dp; 181 182 PJDLOG_ASSERT(trail->tr_magic == TRAIL_MAGIC); 183 PJDLOG_ASSERT(trail_is_not_terminated(trail->tr_filename)); 184 185 rewinddir(trail->tr_dirfp); 186 while ((dp = readdir(trail->tr_dirfp)) != NULL) { 187 if (strncmp(dp->d_name, trail->tr_filename, HALF_LEN + 1) == 0) 188 break; 189 } 190 if (dp == NULL) 191 return (false); 192 PJDLOG_VERIFY(strlcpy(trail->tr_filename, dp->d_name, 193 sizeof(trail->tr_filename)) < sizeof(trail->tr_filename)); 194 return (true); 195 } 196 197 /* 198 * Open the given trail file and move pointer at the given offset, as this is 199 * where receiver finished the last time. 200 * If the file doesn't exist or the given offset is equal to the file size, 201 * move to the next trail file. 202 */ 203 void 204 trail_start(struct trail *trail, const char *filename, off_t offset) 205 { 206 struct stat sb; 207 int dfd, fd; 208 209 PJDLOG_ASSERT(trail->tr_magic == TRAIL_MAGIC); 210 211 PJDLOG_VERIFY(strlcpy(trail->tr_filename, filename, 212 sizeof(trail->tr_filename)) < sizeof(trail->tr_filename)); 213 trail->tr_filefd = -1; 214 215 if (trail->tr_filename[0] == '\0') { 216 PJDLOG_ASSERT(offset == 0); 217 trail_next(trail); 218 return; 219 } 220 221 dfd = dirfd(trail->tr_dirfp); 222 PJDLOG_ASSERT(dfd >= 0); 223 again: 224 fd = openat(dfd, trail->tr_filename, O_RDONLY); 225 if (fd == -1) { 226 if (errno == ENOENT && 227 trail_is_not_terminated(trail->tr_filename) && 228 trail_find(trail)) { 229 /* File was renamed. Retry with new name. */ 230 pjdlog_debug(1, 231 "Trail file was renamed since last connection to \"%s/%s\".", 232 trail->tr_dirname, trail->tr_filename); 233 goto again; 234 } else if (errno == ENOENT) { 235 /* File disappeared. */ 236 pjdlog_debug(1, "File \"%s/%s\" doesn't exist.", 237 trail->tr_dirname, trail->tr_filename); 238 } else { 239 pjdlog_errno(LOG_ERR, 240 "Unable to open file \"%s/%s\", skipping", 241 trail->tr_dirname, trail->tr_filename); 242 } 243 trail_next(trail); 244 return; 245 } 246 if (fstat(fd, &sb) == -1) { 247 pjdlog_errno(LOG_ERR, 248 "Unable to stat file \"%s/%s\", skipping", 249 trail->tr_dirname, trail->tr_filename); 250 close(fd); 251 trail_next(trail); 252 return; 253 } 254 if (!S_ISREG(sb.st_mode)) { 255 pjdlog_warning("File \"%s/%s\" is not a regular file, skipping.", 256 trail->tr_dirname, trail->tr_filename); 257 close(fd); 258 trail_next(trail); 259 return; 260 } 261 /* 262 * We continue sending requested file if: 263 * 1. It is not fully sent yet, or 264 * 2. It is fully sent, but is not terminated, so new data can be 265 * appended still, or 266 * 3. It is fully sent but file name has changed. 267 * 268 * Note that we are fine if our .not_terminated or .crash_recovery file 269 * is smaller than the one on the receiver side, as it is possible that 270 * more data was send to the receiver than was safely stored on disk. 271 * We accept .not_terminated only because auditdistd can start before 272 * auditd manage to rename it to .crash_recovery. 273 */ 274 if (offset < sb.st_size || 275 (offset >= sb.st_size && 276 trail_is_not_terminated(trail->tr_filename)) || 277 (offset >= sb.st_size && trail_is_not_terminated(filename) && 278 trail_is_crash_recovery(trail->tr_filename))) { 279 /* File was not fully send. Let's finish it. */ 280 if (lseek(fd, offset, SEEK_SET) == -1) { 281 pjdlog_errno(LOG_ERR, 282 "Unable to move to offset %jd within file \"%s/%s\", skipping", 283 (intmax_t)offset, trail->tr_dirname, 284 trail->tr_filename); 285 close(fd); 286 trail_next(trail); 287 return; 288 } 289 if (!trail_is_crash_recovery(trail->tr_filename)) { 290 pjdlog_debug(1, 291 "Restarting file \"%s/%s\" at offset %jd.", 292 trail->tr_dirname, trail->tr_filename, 293 (intmax_t)offset); 294 } 295 trail->tr_filefd = fd; 296 return; 297 } 298 close(fd); 299 if (offset > sb.st_size) { 300 pjdlog_warning("File \"%s/%s\" shrinked, removing it.", 301 trail->tr_dirname, trail->tr_filename); 302 } else { 303 pjdlog_debug(1, "File \"%s/%s\" is already sent, removing it.", 304 trail->tr_dirname, trail->tr_filename); 305 } 306 /* Entire file is already sent or it shirnked, we can remove it. */ 307 if (unlinkat(dfd, trail->tr_filename, 0) == -1) { 308 pjdlog_errno(LOG_WARNING, "Unable to remove file \"%s/%s\"", 309 trail->tr_dirname, trail->tr_filename); 310 } 311 trail_next(trail); 312 } 313 314 /* 315 * Set next file in the trail->tr_dirname directory and open it for reading. 316 */ 317 void 318 trail_next(struct trail *trail) 319 { 320 char curfile[PATH_MAX]; 321 struct dirent *dp; 322 int dfd; 323 324 PJDLOG_ASSERT(trail->tr_magic == TRAIL_MAGIC); 325 PJDLOG_ASSERT(trail->tr_filefd == -1); 326 327 again: 328 curfile[0] = '\0'; 329 330 rewinddir(trail->tr_dirfp); 331 while ((dp = readdir(trail->tr_dirfp)) != NULL) { 332 if (dp->d_name[0] < '0' || dp->d_name[0] > '9') 333 continue; 334 if (dp->d_type == DT_UNKNOWN) 335 dp->d_type = trail_type(trail->tr_dirfp, dp->d_name); 336 /* We are only interested in regular files, skip the rest. */ 337 if (dp->d_type != DT_REG) { 338 pjdlog_debug(1, 339 "File \"%s/%s\" is not a regular file, skipping.", 340 trail->tr_dirname, dp->d_name); 341 continue; 342 } 343 /* Skip all files "greater" than curfile. */ 344 if (curfile[0] != '\0' && strcmp(dp->d_name, curfile) > 0) 345 continue; 346 /* Skip all files "smaller" than the current trail_filename. */ 347 if (trail->tr_filename[0] != '\0' && 348 strcmp(dp->d_name, trail->tr_filename) <= 0) { 349 continue; 350 } 351 PJDLOG_VERIFY(strlcpy(curfile, dp->d_name, sizeof(curfile)) < 352 sizeof(curfile)); 353 } 354 if (curfile[0] == '\0') { 355 /* 356 * There are no new trail files, so we return. 357 * We don't clear trail_filename string, to know where to 358 * start when new file appears. 359 */ 360 PJDLOG_ASSERT(trail->tr_filefd == -1); 361 pjdlog_debug(1, "No new trail files."); 362 return; 363 } 364 dfd = dirfd(trail->tr_dirfp); 365 PJDLOG_ASSERT(dfd >= 0); 366 trail->tr_filefd = openat(dfd, curfile, O_RDONLY); 367 if (trail->tr_filefd == -1) { 368 if (errno == ENOENT && trail_is_not_terminated(curfile)) { 369 /* 370 * The .not_terminated file was most likely renamed. 371 * Keep trail->tr_filename as a starting point and 372 * search again. 373 */ 374 pjdlog_debug(1, 375 "Unable to open \"%s/%s\", most likely renamed in the meantime, retrying.", 376 trail->tr_dirname, curfile); 377 } else { 378 /* 379 * We were unable to open the file, but not because of 380 * the above. This shouldn't happen, but it did. 381 * We don't know why it happen, so the best we can do 382 * is to just skip this file - this is why we copy the 383 * name, so we can start and the next entry. 384 */ 385 PJDLOG_VERIFY(strlcpy(trail->tr_filename, curfile, 386 sizeof(trail->tr_filename)) < 387 sizeof(trail->tr_filename)); 388 pjdlog_errno(LOG_ERR, 389 "Unable to open file \"%s/%s\", skipping", 390 trail->tr_dirname, curfile); 391 } 392 goto again; 393 } 394 PJDLOG_VERIFY(strlcpy(trail->tr_filename, curfile, 395 sizeof(trail->tr_filename)) < sizeof(trail->tr_filename)); 396 pjdlog_debug(1, "Found next trail file: \"%s/%s\".", trail->tr_dirname, 397 trail->tr_filename); 398 } 399 400 /* 401 * Close current trial file. 402 */ 403 void 404 trail_close(struct trail *trail) 405 { 406 407 PJDLOG_ASSERT(trail->tr_magic == TRAIL_MAGIC); 408 PJDLOG_ASSERT(trail->tr_filefd >= 0); 409 PJDLOG_ASSERT(trail->tr_filename[0] != '\0'); 410 411 PJDLOG_VERIFY(close(trail->tr_filefd) == 0); 412 trail->tr_filefd = -1; 413 } 414 415 /* 416 * Reset trail state. Used when connection is disconnected and we will 417 * need to start over after reconnect. Trail needs to be already closed. 418 */ 419 void 420 trail_reset(struct trail *trail) 421 { 422 423 PJDLOG_ASSERT(trail->tr_magic == TRAIL_MAGIC); 424 PJDLOG_ASSERT(trail->tr_filefd == -1); 425 426 trail->tr_filename[0] = '\0'; 427 } 428 429 /* 430 * Unlink current trial file. 431 */ 432 void 433 trail_unlink(struct trail *trail, const char *filename) 434 { 435 int dfd; 436 437 PJDLOG_ASSERT(trail->tr_magic == TRAIL_MAGIC); 438 PJDLOG_ASSERT(filename != NULL); 439 PJDLOG_ASSERT(filename[0] != '\0'); 440 441 dfd = dirfd(trail->tr_dirfp); 442 PJDLOG_ASSERT(dfd >= 0); 443 444 if (unlinkat(dfd, filename, 0) == -1) { 445 pjdlog_errno(LOG_ERR, "Unable to remove \"%s/%s\"", 446 trail->tr_dirname, filename); 447 } else { 448 pjdlog_debug(1, "Trail file \"%s/%s\" removed.", 449 trail->tr_dirname, filename); 450 } 451 } 452 453 /* 454 * Return true if we should switch to next trail file. 455 * We don't switch if our file name ends with ".not_terminated" and it 456 * exists (ie. wasn't renamed). 457 */ 458 bool 459 trail_switch(struct trail *trail) 460 { 461 char filename[PATH_MAX]; 462 int fd; 463 464 PJDLOG_ASSERT(trail->tr_magic == TRAIL_MAGIC); 465 PJDLOG_ASSERT(trail->tr_filefd >= 0); 466 467 if (!trail_is_not_terminated(trail->tr_filename)) 468 return (true); 469 fd = dirfd(trail->tr_dirfp); 470 PJDLOG_ASSERT(fd >= 0); 471 if (faccessat(fd, trail->tr_filename, F_OK, 0) == 0) 472 return (false); 473 if (errno != ENOENT) { 474 pjdlog_errno(LOG_ERR, "Unable to access file \"%s/%s\"", 475 trail->tr_dirname, trail->tr_filename); 476 } 477 strlcpy(filename, trail->tr_filename, sizeof(filename)); 478 if (!trail_find(trail)) { 479 pjdlog_error("Trail file \"%s/%s\" disappeared.", 480 trail->tr_dirname, trail->tr_filename); 481 return (true); 482 } 483 pjdlog_debug(1, "Trail file \"%s/%s\" was renamed to \"%s/%s\".", 484 trail->tr_dirname, filename, trail->tr_dirname, 485 trail->tr_filename); 486 return (true); 487 } 488 489 const char * 490 trail_filename(const struct trail *trail) 491 { 492 493 PJDLOG_ASSERT(trail->tr_magic == TRAIL_MAGIC); 494 495 return (trail->tr_filename); 496 } 497 498 int 499 trail_filefd(const struct trail *trail) 500 { 501 502 PJDLOG_ASSERT(trail->tr_magic == TRAIL_MAGIC); 503 504 return (trail->tr_filefd); 505 } 506 507 int 508 trail_dirfd(const struct trail *trail) 509 { 510 511 PJDLOG_ASSERT(trail->tr_magic == TRAIL_MAGIC); 512 513 return (dirfd(trail->tr_dirfp)); 514 } 515 516 /* 517 * Find the last file in the directory opened under dirfp. 518 */ 519 void 520 trail_last(DIR *dirfp, char *filename, size_t filenamesize) 521 { 522 char curfile[PATH_MAX]; 523 struct dirent *dp; 524 525 PJDLOG_ASSERT(dirfp != NULL); 526 527 curfile[0] = '\0'; 528 529 rewinddir(dirfp); 530 while ((dp = readdir(dirfp)) != NULL) { 531 if (dp->d_name[0] < '0' || dp->d_name[0] > '9') 532 continue; 533 if (dp->d_type == DT_UNKNOWN) 534 dp->d_type = trail_type(dirfp, dp->d_name); 535 /* We are only interested in regular files, skip the rest. */ 536 if (dp->d_type != DT_REG) 537 continue; 538 /* Skip all files "greater" than curfile. */ 539 if (curfile[0] != '\0' && strcmp(dp->d_name, curfile) < 0) 540 continue; 541 PJDLOG_VERIFY(strlcpy(curfile, dp->d_name, sizeof(curfile)) < 542 sizeof(curfile)); 543 } 544 if (curfile[0] == '\0') { 545 /* 546 * There are no trail files, so we return. 547 */ 548 pjdlog_debug(1, "No trail files."); 549 bzero(filename, filenamesize); 550 return; 551 } 552 PJDLOG_VERIFY(strlcpy(filename, curfile, filenamesize) < filenamesize); 553 pjdlog_debug(1, "Found the most recent trail file: \"%s\".", filename); 554 } 555 556 /* 557 * Check if the given file name is a valid audit trail file name. 558 * Possible names: 559 * 20120106132657.20120106132805 560 * 20120106132657.not_terminated 561 * 20120106132657.crash_recovery 562 * If two names are given, check if the first name can be renamed 563 * to the second name. When renaming, first part of the name has 564 * to be identical and only the following renames are valid: 565 * 20120106132657.not_terminated -> 20120106132657.20120106132805 566 * 20120106132657.not_terminated -> 20120106132657.crash_recovery 567 */ 568 bool 569 trail_validate_name(const char *srcname, const char *dstname) 570 { 571 int i; 572 573 PJDLOG_ASSERT(srcname != NULL); 574 575 if (strlen(srcname) != 2 * HALF_LEN + 1) 576 return (false); 577 if (srcname[HALF_LEN] != '.') 578 return (false); 579 for (i = 0; i < HALF_LEN; i++) { 580 if (srcname[i] < '0' || srcname[i] > '9') 581 return (false); 582 } 583 for (i = HALF_LEN + 1; i < 2 * HALF_LEN - 1; i++) { 584 if (srcname[i] < '0' || srcname[i] > '9') 585 break; 586 } 587 if (i < 2 * HALF_LEN - 1 && 588 strcmp(srcname + HALF_LEN + 1, "not_terminated") != 0 && 589 strcmp(srcname + HALF_LEN + 1, "crash_recovery") != 0) { 590 return (false); 591 } 592 593 if (dstname == NULL) 594 return (true); 595 596 /* We tolarate if both names are identical. */ 597 if (strcmp(srcname, dstname) == 0) 598 return (true); 599 600 /* We can only rename not_terminated files. */ 601 if (strcmp(srcname + HALF_LEN + 1, "not_terminated") != 0) 602 return (false); 603 if (strlen(dstname) != 2 * HALF_LEN + 1) 604 return (false); 605 if (strncmp(srcname, dstname, HALF_LEN + 1) != 0) 606 return (false); 607 for (i = HALF_LEN + 1; i < 2 * HALF_LEN - 1; i++) { 608 if (dstname[i] < '0' || dstname[i] > '9') 609 break; 610 } 611 if (i < 2 * HALF_LEN - 1 && 612 strcmp(dstname + HALF_LEN + 1, "crash_recovery") != 0) { 613 return (false); 614 } 615 616 return (true); 617 } 618 619 int 620 trail_name_compare(const char *name0, const char *name1) 621 { 622 int ret; 623 624 ret = strcmp(name0, name1); 625 if (ret == 0) 626 return (TRAIL_IDENTICAL); 627 if (strncmp(name0, name1, HALF_LEN + 1) == 0) 628 return (TRAIL_RENAMED); 629 return (ret < 0 ? TRAIL_OLDER : TRAIL_NEWER); 630 } 631