1 /* $OpenBSD: file.c,v 1.57 2015/12/24 11:45:34 jca Exp $ */ 2 3 /* 4 * Copyright (c) 2015 Nicholas Marriott <nicm@openbsd.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 15 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 16 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <sys/types.h> 20 #include <sys/ioctl.h> 21 #include <sys/mman.h> 22 #include <sys/socket.h> 23 #include <sys/queue.h> 24 #include <sys/uio.h> 25 #include <sys/wait.h> 26 27 #include <errno.h> 28 #include <imsg.h> 29 #include <libgen.h> 30 #include <getopt.h> 31 #include <fcntl.h> 32 #include <pwd.h> 33 #include <stdlib.h> 34 #include <time.h> 35 #include <unistd.h> 36 #include <limits.h> 37 38 #include "file.h" 39 #include "magic.h" 40 #include "xmalloc.h" 41 42 struct input_msg 43 { 44 int idx; 45 46 struct stat sb; 47 int error; 48 49 char link_path[PATH_MAX]; 50 int link_error; 51 int link_target; 52 }; 53 54 struct input_ack 55 { 56 int idx; 57 }; 58 59 struct input_file 60 { 61 struct magic *m; 62 struct input_msg *msg; 63 64 const char *path; 65 int fd; 66 67 void *base; 68 size_t size; 69 int mapped; 70 char *result; 71 }; 72 73 extern char *__progname; 74 75 __dead void usage(void); 76 77 static int prepare_message(struct input_msg *, int, const char *); 78 static void send_message(struct imsgbuf *, void *, size_t, int); 79 static int read_message(struct imsgbuf *, struct imsg *, pid_t); 80 81 static void read_link(struct input_msg *, const char *); 82 83 static __dead void child(int, pid_t, int, char **); 84 85 static void test_file(struct input_file *, size_t); 86 87 static int try_stat(struct input_file *); 88 static int try_empty(struct input_file *); 89 static int try_access(struct input_file *); 90 static int try_text(struct input_file *); 91 static int try_magic(struct input_file *); 92 static int try_unknown(struct input_file *); 93 94 static int bflag; 95 static int cflag; 96 static int iflag; 97 static int Lflag; 98 static int sflag; 99 static int Wflag; 100 101 static char *magicpath; 102 static FILE *magicfp; 103 104 static struct option longopts[] = { 105 { "brief", no_argument, NULL, 'b' }, 106 { "dereference", no_argument, NULL, 'L' }, 107 { "mime", no_argument, NULL, 'i' }, 108 { "mime-type", no_argument, NULL, 'i' }, 109 { NULL, 0, NULL, 0 } 110 }; 111 112 __dead void 113 usage(void) 114 { 115 fprintf(stderr, "usage: %s [-bchiLsW] file ...\n", __progname); 116 exit(1); 117 } 118 119 int 120 main(int argc, char **argv) 121 { 122 int opt, pair[2], fd, idx; 123 char *home; 124 struct passwd *pw; 125 struct imsgbuf ibuf; 126 struct imsg imsg; 127 struct input_msg msg; 128 struct input_ack *ack; 129 pid_t pid, parent; 130 131 tzset(); 132 133 for (;;) { 134 opt = getopt_long(argc, argv, "bchiLsW", longopts, NULL); 135 if (opt == -1) 136 break; 137 switch (opt) { 138 case 'b': 139 bflag = 1; 140 break; 141 case 'c': 142 cflag = 1; 143 break; 144 case 'h': 145 Lflag = 0; 146 break; 147 case 'i': 148 iflag = 1; 149 break; 150 case 'L': 151 Lflag = 1; 152 break; 153 case 's': 154 sflag = 1; 155 break; 156 case 'W': 157 Wflag = 1; 158 break; 159 default: 160 usage(); 161 } 162 } 163 argc -= optind; 164 argv += optind; 165 if (cflag) { 166 if (argc != 0) 167 usage(); 168 } else if (argc == 0) 169 usage(); 170 171 magicfp = NULL; 172 if (geteuid() != 0 && !issetugid()) { 173 home = getenv("HOME"); 174 if (home == NULL || *home == '\0') { 175 pw = getpwuid(getuid()); 176 if (pw != NULL) 177 home = pw->pw_dir; 178 else 179 home = NULL; 180 } 181 if (home != NULL) { 182 xasprintf(&magicpath, "%s/.magic", home); 183 magicfp = fopen(magicpath, "r"); 184 if (magicfp == NULL) 185 free(magicpath); 186 } 187 } 188 if (magicfp == NULL) { 189 magicpath = xstrdup("/etc/magic"); 190 magicfp = fopen(magicpath, "r"); 191 } 192 if (magicfp == NULL) 193 err(1, "%s", magicpath); 194 195 parent = getpid(); 196 if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pair) != 0) 197 err(1, "socketpair"); 198 switch (pid = fork()) { 199 case -1: 200 err(1, "fork"); 201 case 0: 202 close(pair[0]); 203 child(pair[1], parent, argc, argv); 204 } 205 close(pair[1]); 206 207 fclose(magicfp); 208 magicfp = NULL; 209 210 if (cflag) 211 goto wait_for_child; 212 213 imsg_init(&ibuf, pair[0]); 214 for (idx = 0; idx < argc; idx++) { 215 fd = prepare_message(&msg, idx, argv[idx]); 216 send_message(&ibuf, &msg, sizeof msg, fd); 217 218 if (read_message(&ibuf, &imsg, pid) == 0) 219 break; 220 if (imsg.hdr.len != IMSG_HEADER_SIZE + sizeof *ack) 221 errx(1, "message too small"); 222 ack = imsg.data; 223 if (ack->idx != idx) 224 errx(1, "index not expected"); 225 imsg_free(&imsg); 226 } 227 228 wait_for_child: 229 close(pair[0]); 230 while (wait(NULL) == -1 && errno != ECHILD) { 231 if (errno != EINTR) 232 err(1, "wait"); 233 } 234 _exit(0); /* let the child flush */ 235 } 236 237 static int 238 prepare_message(struct input_msg *msg, int idx, const char *path) 239 { 240 int fd, mode, error; 241 242 memset(msg, 0, sizeof *msg); 243 msg->idx = idx; 244 245 if (strcmp(path, "-") == 0) { 246 if (fstat(STDIN_FILENO, &msg->sb) == -1) { 247 msg->error = errno; 248 return (-1); 249 } 250 return (STDIN_FILENO); 251 } 252 253 if (Lflag) 254 error = stat(path, &msg->sb); 255 else 256 error = lstat(path, &msg->sb); 257 if (error == -1) { 258 msg->error = errno; 259 return (-1); 260 } 261 262 /* 263 * pledge(2) doesn't let us pass directory file descriptors around - 264 * but in fact we don't need them, so just don't open directories or 265 * symlinks (which could be to directories). 266 */ 267 mode = msg->sb.st_mode; 268 if (!S_ISDIR(mode) && !S_ISLNK(mode)) { 269 fd = open(path, O_RDONLY|O_NONBLOCK); 270 if (fd == -1 && (errno == ENFILE || errno == EMFILE)) 271 err(1, "open"); 272 } else 273 fd = -1; 274 if (S_ISLNK(mode)) 275 read_link(msg, path); 276 return (fd); 277 278 } 279 280 static void 281 send_message(struct imsgbuf *ibuf, void *msg, size_t msglen, int fd) 282 { 283 if (imsg_compose(ibuf, -1, -1, 0, fd, msg, msglen) != 1) 284 err(1, "imsg_compose"); 285 if (imsg_flush(ibuf) != 0) 286 err(1, "imsg_flush"); 287 } 288 289 static int 290 read_message(struct imsgbuf *ibuf, struct imsg *imsg, pid_t from) 291 { 292 int n; 293 294 while ((n = imsg_read(ibuf)) == -1 && errno == EAGAIN) 295 /* nothing */ ; 296 if (n == -1) 297 err(1, "imsg_read"); 298 if (n == 0) 299 return (0); 300 301 if ((n = imsg_get(ibuf, imsg)) == -1) 302 err(1, "imsg_get"); 303 if (n == 0) 304 return (0); 305 306 if ((pid_t)imsg->hdr.pid != from) 307 errx(1, "PIDs don't match"); 308 309 return (n); 310 311 } 312 313 static void 314 read_link(struct input_msg *msg, const char *path) 315 { 316 struct stat sb; 317 char lpath[PATH_MAX]; 318 char *copy, *root; 319 int used; 320 ssize_t size; 321 322 size = readlink(path, lpath, sizeof lpath - 1); 323 if (size == -1) { 324 msg->link_error = errno; 325 return; 326 } 327 lpath[size] = '\0'; 328 329 if (*lpath == '/') 330 strlcpy(msg->link_path, lpath, sizeof msg->link_path); 331 else { 332 copy = xstrdup(path); 333 334 root = dirname(copy); 335 if (*root == '\0' || strcmp(root, ".") == 0 || 336 strcmp (root, "/") == 0) 337 strlcpy(msg->link_path, lpath, sizeof msg->link_path); 338 else { 339 used = snprintf(msg->link_path, sizeof msg->link_path, 340 "%s/%s", root, lpath); 341 if (used < 0 || (size_t)used >= sizeof msg->link_path) { 342 msg->link_error = ENAMETOOLONG; 343 free(copy); 344 return; 345 } 346 } 347 348 free(copy); 349 } 350 351 if (!Lflag && stat(path, &sb) == -1) 352 msg->link_target = errno; 353 } 354 355 static __dead void 356 child(int fd, pid_t parent, int argc, char **argv) 357 { 358 struct passwd *pw; 359 struct magic *m; 360 struct imsgbuf ibuf; 361 struct imsg imsg; 362 struct input_msg *msg; 363 struct input_ack ack; 364 struct input_file inf; 365 int i, idx; 366 size_t len, width = 0; 367 368 if (pledge("stdio getpw recvfd id", NULL) == -1) 369 err(1, "pledge"); 370 371 if (geteuid() == 0) { 372 pw = getpwnam(FILE_USER); 373 if (pw == NULL) 374 errx(1, "unknown user %s", FILE_USER); 375 if (setgroups(1, &pw->pw_gid) != 0) 376 err(1, "setgroups"); 377 if (setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) != 0) 378 err(1, "setresgid"); 379 if (setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid) != 0) 380 err(1, "setresuid"); 381 } 382 383 if (pledge("stdio recvfd", NULL) == -1) 384 err(1, "pledge"); 385 386 m = magic_load(magicfp, magicpath, cflag || Wflag); 387 if (cflag) { 388 magic_dump(m); 389 exit(0); 390 } 391 392 for (i = 0; i < argc; i++) { 393 len = strlen(argv[i]) + 1; 394 if (len > width) 395 width = len; 396 } 397 398 imsg_init(&ibuf, fd); 399 for (;;) { 400 if (read_message(&ibuf, &imsg, parent) == 0) 401 break; 402 if (imsg.hdr.len != IMSG_HEADER_SIZE + sizeof *msg) 403 errx(1, "message too small"); 404 msg = imsg.data; 405 406 idx = msg->idx; 407 if (idx < 0 || idx >= argc) 408 errx(1, "index out of range"); 409 410 memset(&inf, 0, sizeof inf); 411 inf.m = m; 412 inf.msg = msg; 413 414 inf.path = argv[idx]; 415 inf.fd = imsg.fd; 416 417 test_file(&inf, width); 418 419 if (imsg.fd != -1) 420 close(imsg.fd); 421 imsg_free(&imsg); 422 423 ack.idx = idx; 424 send_message(&ibuf, &ack, sizeof ack, -1); 425 } 426 exit(0); 427 } 428 429 static void * 430 fill_buffer(int fd, size_t size, size_t *used) 431 { 432 static void *buffer; 433 ssize_t got; 434 size_t left; 435 void *next; 436 437 if (buffer == NULL) 438 buffer = xmalloc(FILE_READ_SIZE); 439 440 next = buffer; 441 left = size; 442 while (left != 0) { 443 got = read(fd, next, left); 444 if (got == -1) { 445 if (errno == EINTR) 446 continue; 447 return NULL; 448 } 449 if (got == 0) 450 break; 451 next = (char *)next + got; 452 left -= got; 453 } 454 *used = size - left; 455 return buffer; 456 } 457 458 static int 459 load_file(struct input_file *inf) 460 { 461 size_t used; 462 463 if (inf->msg->sb.st_size == 0 && S_ISREG(inf->msg->sb.st_mode)) 464 return (0); /* empty file */ 465 if (inf->msg->sb.st_size == 0 || inf->msg->sb.st_size > FILE_READ_SIZE) 466 inf->size = FILE_READ_SIZE; 467 else 468 inf->size = inf->msg->sb.st_size; 469 470 if (!S_ISREG(inf->msg->sb.st_mode)) 471 goto try_read; 472 473 inf->base = mmap(NULL, inf->size, PROT_READ, MAP_PRIVATE, inf->fd, 0); 474 if (inf->base == MAP_FAILED) 475 goto try_read; 476 inf->mapped = 1; 477 return (0); 478 479 try_read: 480 inf->base = fill_buffer(inf->fd, inf->size, &used); 481 if (inf->base == NULL) { 482 xasprintf(&inf->result, "cannot read '%s' (%s)", inf->path, 483 strerror(errno)); 484 return (1); 485 } 486 inf->size = used; 487 return (0); 488 } 489 490 static int 491 try_stat(struct input_file *inf) 492 { 493 if (inf->msg->error != 0) { 494 xasprintf(&inf->result, "cannot stat '%s' (%s)", inf->path, 495 strerror(inf->msg->error)); 496 return (1); 497 } 498 if (sflag || strcmp(inf->path, "-") == 0) { 499 switch (inf->msg->sb.st_mode & S_IFMT) { 500 case S_IFIFO: 501 if (strcmp(inf->path, "-") != 0) 502 break; 503 case S_IFBLK: 504 case S_IFCHR: 505 case S_IFREG: 506 return (0); 507 } 508 } 509 510 if (iflag && (inf->msg->sb.st_mode & S_IFMT) != S_IFREG) { 511 xasprintf(&inf->result, "application/x-not-regular-file"); 512 return (1); 513 } 514 515 switch (inf->msg->sb.st_mode & S_IFMT) { 516 case S_IFDIR: 517 xasprintf(&inf->result, "directory"); 518 return (1); 519 case S_IFLNK: 520 if (inf->msg->link_error != 0) { 521 xasprintf(&inf->result, "unreadable symlink '%s' (%s)", 522 inf->path, strerror(inf->msg->link_error)); 523 return (1); 524 } 525 if (inf->msg->link_target == ELOOP) 526 xasprintf(&inf->result, "symbolic link in a loop"); 527 else if (inf->msg->link_target != 0) { 528 xasprintf(&inf->result, "broken symbolic link to '%s'", 529 inf->msg->link_path); 530 } else { 531 xasprintf(&inf->result, "symbolic link to '%s'", 532 inf->msg->link_path); 533 } 534 return (1); 535 case S_IFSOCK: 536 xasprintf(&inf->result, "socket"); 537 return (1); 538 case S_IFBLK: 539 xasprintf(&inf->result, "block special (%ld/%ld)", 540 (long)major(inf->msg->sb.st_rdev), 541 (long)minor(inf->msg->sb.st_rdev)); 542 return (1); 543 case S_IFCHR: 544 xasprintf(&inf->result, "character special (%ld/%ld)", 545 (long)major(inf->msg->sb.st_rdev), 546 (long)minor(inf->msg->sb.st_rdev)); 547 return (1); 548 case S_IFIFO: 549 xasprintf(&inf->result, "fifo (named pipe)"); 550 return (1); 551 } 552 return (0); 553 } 554 555 static int 556 try_empty(struct input_file *inf) 557 { 558 if (inf->size != 0) 559 return (0); 560 561 if (iflag) 562 xasprintf(&inf->result, "application/x-empty"); 563 else 564 xasprintf(&inf->result, "empty"); 565 return (1); 566 } 567 568 static int 569 try_access(struct input_file *inf) 570 { 571 char tmp[256] = ""; 572 573 if (inf->msg->sb.st_size == 0 && S_ISREG(inf->msg->sb.st_mode)) 574 return (0); /* empty file */ 575 if (inf->fd != -1) 576 return (0); 577 578 if (inf->msg->sb.st_mode & (S_IWUSR|S_IWGRP|S_IWOTH)) 579 strlcat(tmp, "writable, ", sizeof tmp); 580 if (inf->msg->sb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) 581 strlcat(tmp, "executable, ", sizeof tmp); 582 if (S_ISREG(inf->msg->sb.st_mode)) 583 strlcat(tmp, "regular file, ", sizeof tmp); 584 strlcat(tmp, "no read permission", sizeof tmp); 585 586 inf->result = xstrdup(tmp); 587 return (1); 588 } 589 590 static int 591 try_text(struct input_file *inf) 592 { 593 const char *type, *s; 594 int flags; 595 596 flags = MAGIC_TEST_TEXT; 597 if (iflag) 598 flags |= MAGIC_TEST_MIME; 599 600 type = text_get_type(inf->base, inf->size); 601 if (type == NULL) 602 return (0); 603 604 s = magic_test(inf->m, inf->base, inf->size, flags); 605 if (s != NULL) { 606 inf->result = xstrdup(s); 607 return (1); 608 } 609 610 s = text_try_words(inf->base, inf->size, flags); 611 if (s != NULL) { 612 if (iflag) 613 inf->result = xstrdup(s); 614 else 615 xasprintf(&inf->result, "%s %s text", type, s); 616 return (1); 617 } 618 619 if (iflag) 620 inf->result = xstrdup("text/plain"); 621 else 622 xasprintf(&inf->result, "%s text", type); 623 return (1); 624 } 625 626 static int 627 try_magic(struct input_file *inf) 628 { 629 const char *s; 630 int flags; 631 632 flags = 0; 633 if (iflag) 634 flags |= MAGIC_TEST_MIME; 635 636 s = magic_test(inf->m, inf->base, inf->size, flags); 637 if (s != NULL) { 638 inf->result = xstrdup(s); 639 return (1); 640 } 641 return (0); 642 } 643 644 static int 645 try_unknown(struct input_file *inf) 646 { 647 if (iflag) 648 xasprintf(&inf->result, "application/x-not-regular-file"); 649 else 650 xasprintf(&inf->result, "data"); 651 return (1); 652 } 653 654 static void 655 test_file(struct input_file *inf, size_t width) 656 { 657 char *label; 658 int stop; 659 660 stop = 0; 661 if (!stop) 662 stop = try_stat(inf); 663 if (!stop) 664 stop = try_access(inf); 665 if (!stop) 666 stop = load_file(inf); 667 if (!stop) 668 stop = try_empty(inf); 669 if (!stop) 670 stop = try_magic(inf); 671 if (!stop) 672 stop = try_text(inf); 673 if (!stop) 674 stop = try_unknown(inf); 675 676 if (bflag) 677 printf("%s\n", inf->result); 678 else { 679 if (strcmp(inf->path, "-") == 0) 680 xasprintf(&label, "/dev/stdin:"); 681 else 682 xasprintf(&label, "%s:", inf->path); 683 printf("%-*s %s\n", (int)width, label, inf->result); 684 free(label); 685 } 686 free(inf->result); 687 688 if (inf->mapped && inf->base != NULL) 689 munmap(inf->base, inf->size); 690 } 691