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