Index: contrib/file/src/file.h =================================================================== --- contrib/file/src/file.h +++ contrib/file/src/file.h @@ -33,6 +33,17 @@ #ifndef __file_h__ #define __file_h__ +#if defined(__FreeBSD__) +#include +#if __FreeBSD_version >= 1100014 +#include +#define HAVE_CAPSICUM +#elif __FreeBSD_version >= 1000000 +#include +#define HAVE_CAPSICUM +#endif +#endif + #ifdef HAVE_CONFIG_H #include #endif @@ -439,7 +450,8 @@ protected void file_ms_free(struct magic_set *); protected int file_buffer(struct magic_set *, int, const char *, const void *, size_t); -protected int file_fsmagic(struct magic_set *, const char *, struct stat *); +protected int file_fsmagic(struct magic_set *, const char *, struct stat *, + int); protected int file_pipe2file(struct magic_set *, int, const void *, size_t); protected int file_vprintf(struct magic_set *, const char *, va_list) __attribute__((__format__(__printf__, 2, 0))); Index: contrib/file/src/file.c =================================================================== --- contrib/file/src/file.c +++ contrib/file/src/file.c @@ -87,6 +87,12 @@ nobuffer = 0, /* Do not buffer stdout */ nulsep = 0; /* Append '\0' to the separator */ +#ifdef HAVE_CAPSICUM + private int *ifds = NULL; + private int fcnt = 0; + private char **fnames = NULL; +#endif + private const char *separator = ":"; /* Default field separator */ private const struct option long_options[] = { #define OPT_HELP 1 @@ -148,8 +154,8 @@ #endif private void help(void); -private int unwrap(struct magic_set *, const char *); -private int process(struct magic_set *ms, const char *, int); +private int unwrap(struct magic_set * __unused, const char *, size_t *); +private int process(struct magic_set *ms, const char *, int, int); private struct magic_set *load(const char *, int); private void setparam(const char *); private void applyparam(magic_t); @@ -162,12 +168,15 @@ main(int argc, char *argv[]) { int c; - size_t i; + size_t i, wid = 0; int action = 0, didsomefiles = 0, errflg = 0; int flags = 0, e = 0; struct magic_set *magic = NULL; int longindex; const char *magicfile = NULL; /* where the magic is */ +#ifdef HAVE_CAPSICUM + cap_rights_t rights_ro; +#endif /* makes islower etc work for other langs */ #ifdef HAVE_SETLOCALE @@ -238,11 +247,15 @@ case 'f': if(action) usage(); +#ifdef HAVE_CAPSICUM + e |= unwrap(NULL, optarg, &wid); +#else if (magic == NULL) if ((magic = load(magicfile, flags)) == NULL) return 1; applyparam(magic); - e |= unwrap(magic, optarg); + e |= unwrap(magic, optarg, &wid); +#endif ++didsomefiles; break; case 'F': @@ -365,10 +378,24 @@ if (optind == argc) { if (!didsomefiles) usage(); +#ifdef HAVE_CAPSICUM + if (cap_enter() < 0 && errno != ENOSYS) { + (void)fprintf(stderr, "%s: Error: failed to enter " + "sandbox\n", progname); + return 1; + } + + /* Process file descriptions we opened earlier in unwrap_open */ + for (c = 0; c < fcnt; c++) { + e |= process(magic, fnames[c], wid, ifds[c]); + if(nobuffer) + (void)fflush(stdout); + } +#endif } else { - size_t j, wid, nw; - for (wid = 0, j = (size_t)optind; j < (size_t)argc; j++) { + size_t j, nw; + for (j = (size_t)optind; j < (size_t)argc; j++) { nw = file_mbswidth(argv[j]); if (nw > wid) wid = nw; @@ -380,11 +407,76 @@ if (bflag == 2) { bflag = optind >= argc - 1; } - for (; optind < argc; optind++) - e |= process(magic, argv[optind], wid); + +#ifdef HAVE_CAPSICUM + cap_rights_init(&rights_ro, CAP_READ, CAP_FSTAT, CAP_SEEK); + + ifds = realloc(ifds, sizeof(int) * (fcnt + argc)); + if (ifds == NULL) { + fprintf(stderr, "%s: failed to allocate memory: %s\n", + progname, strerror(errno)); + return 1; + } + + for (c = optind; c < argc; c++) { + if (strcmp(argv[c], "-") == 0) { + ifds[c + fcnt] = STDIN_FILENO; + continue; + } + if ((ifds[c + fcnt] = open(argv[c], + O_RDONLY | O_BINARY)) == -1) + (void)fprintf(stderr, "%s: cannot open `%s': " + "%s\n", progname, argv[c], strerror(errno)); + if (cap_rights_limit(ifds[c + fcnt], &rights_ro) < 0 && + errno != ENOSYS) { + (void)fprintf(stderr, "%s: cap_rights_limit() " + "failed, could not restrict capabilities\n", + progname); + return 1; + } + } + + if (cap_enter() < 0 && errno != ENOSYS) { + (void)fprintf(stderr, "%s: Error: failed to enter " + "sandbox\n", progname); + return 1; + } + + /* Process file descriptions we opened earlier in unwrap_open */ + for (c = 0; c < fcnt; c++) { + e |= process(magic, fnames[c], wid, ifds[c]); + if(nobuffer) + (void)fflush(stdout); + } + + /* Process files listed on the command line */ + for (; optind < argc; optind++) { + e |= process(magic, argv[optind], wid, + ifds[optind + fcnt]); + if(nobuffer) + (void)fflush(stdout); + } +#else + for (; optind < argc; optind++) { + e |= process(magic, argv[optind], wid, -1); + if(nobuffer) + (void)fflush(stdout); + } +#endif } out: +#ifdef HAVE_CAPSICUM + if (ifds != NULL) + free(ifds); + if (fnames != NULL) { + for (c = 0; c < fcnt; c++) + if (fnames[c] != NULL) + free(fnames[c]); + free(fnames); + } +#endif + if (magic) magic_close(magic); return e; @@ -448,18 +540,22 @@ * unwrap -- read a file of filenames, do each one. */ private int -unwrap(struct magic_set *ms, const char *fn) +unwrap(struct magic_set *ms __unused, const char *fn, size_t *wid) { FILE *f; ssize_t len; char *line = NULL; - size_t llen = 0; - int wid = 0, cwid; + size_t llen = 0, cwid, linecnt = 0; int e = 0; +#ifdef HAVE_CAPSICUM + cap_rights_t rights_ro; + + cap_rights_init(&rights_ro, CAP_READ, CAP_FSTAT, CAP_SEEK); +#endif if (strcmp("-", fn) == 0) { f = stdin; - wid = 1; + *wid = 1; } else { if ((f = fopen(fn, "r")) == NULL) { (void)fprintf(stderr, "%s: Cannot open `%s' (%s).\n", @@ -471,19 +567,54 @@ if (line[len - 1] == '\n') line[len - 1] = '\0'; cwid = file_mbswidth(line); - if (cwid > wid) - wid = cwid; + if (cwid > *wid) + *wid = cwid; + linecnt++; } rewind(f); } +#ifdef HAVE_CAPSICUM + ifds = realloc(ifds, sizeof(int) * (fcnt + linecnt)); + fnames = realloc(fnames, sizeof(char *) * (fcnt + linecnt)); + if (ifds == NULL || fnames == NULL) { + (void)fprintf(stderr, "%s: failed to allocate memory: %s\n", + progname, strerror(errno)); + exit(1); + } +#endif + while ((len = getline(&line, &llen, f)) > 0) { if (line[len - 1] == '\n') line[len - 1] = '\0'; - e |= process(ms, line, wid); +#ifdef HAVE_CAPSICUM + if (strcmp(line, "-") == 0) { + ifds[fcnt] = STDIN_FILENO; + } else if ((ifds[fcnt] = open(line, O_RDONLY)) == -1) { + (void)fprintf(stderr, "%s: Cannot open `%s' (%s).\n", + progname, line, strerror(errno)); + e = 1; + break; + } + if ((fnames[fcnt] = strdup(line)) == NULL) { + (void)fprintf(stderr, "%s: failed to allocate memory: " + "%s\n", progname, strerror(errno)); + exit(1); + } + if (cap_rights_limit(ifds[fcnt], &rights_ro) < 0 && + errno != ENOSYS) { + (void)fprintf(stderr, "%s: cap_rights_limit() " + "failed, could not restrict capabilities\n", + progname); + exit(1); + } + fcnt++; +#else + e |= process(ms, line, wid, -1); if(nobuffer) (void)fflush(stdout); +#endif } free(line); @@ -495,13 +626,14 @@ * Called for each input file on the command line (or in a list of files) */ private int -process(struct magic_set *ms, const char *inname, int wid) +process(struct magic_set *ms, const char *inname, int wid, int ifd) { const char *type, c = nulsep > 1 ? '\0' : '\n'; - int std_in = strcmp(inname, "-") == 0; + if (ifd == -1 && strcmp(inname, "-") == 0) + ifd = STDIN_FILENO; if (wid > 0 && !bflag) { - (void)printf("%s", std_in ? "/dev/stdin" : inname); + (void)printf("%s", ifd == STDIN_FILENO ? "/dev/stdin" : inname); if (nulsep) (void)putc('\0', stdout); if (nulsep < 2) { @@ -512,7 +644,10 @@ } } - type = magic_file(ms, std_in ? NULL : inname); + type = magic_file(ms, ifd == STDIN_FILENO ? NULL : inname, ifd); + + if (ifd > 0) + close(ifd); if (type == NULL) { (void)printf("ERROR: %s%c", magic_error(ms), c); Index: contrib/file/src/fsmagic.c =================================================================== --- contrib/file/src/fsmagic.c +++ contrib/file/src/fsmagic.c @@ -100,7 +100,7 @@ } protected int -file_fsmagic(struct magic_set *ms, const char *fn, struct stat *sb) +file_fsmagic(struct magic_set *ms, const char *fn, struct stat *sb, int fd) { int ret, did = 0; int mime = ms->flags & MAGIC_MIME; @@ -120,13 +120,16 @@ * Fstat is cheaper but fails for files you don't have read perms on. * On 4.2BSD and similar systems, use lstat() to identify symlinks. */ +#ifndef HAVE_CAPSICUM /* XXX: TODO: capsicumization breaks symlink check */ #ifdef S_IFLNK if ((ms->flags & MAGIC_SYMLINK) == 0) ret = lstat(fn, sb); else #endif - ret = stat(fn, sb); /* don't merge into if; see "ret =" above */ - + ret = stat(fn, sb); /* don't merge into if; see "ret =" above */ +#else /* ifndef HAVE_CAPSICUM */ + ret = fstat(fd, sb); +#endif /* ifndef HAVE_CAPSICUM */ #ifdef WIN32 { HANDLE hFile = CreateFile((LPCSTR)fn, 0, FILE_SHARE_DELETE | @@ -344,7 +347,7 @@ if ((ms->flags & MAGIC_SYMLINK) != 0) { const char *p; ms->flags &= MAGIC_SYMLINK; - p = magic_file(ms, buf); + p = magic_file(ms, buf, -1); ms->flags |= MAGIC_SYMLINK; if (p == NULL) return -1; Index: contrib/file/src/magic.h.in =================================================================== --- contrib/file/src/magic.h.in +++ contrib/file/src/magic.h.in @@ -92,7 +92,7 @@ void magic_close(magic_t); const char *magic_getpath(const char *, int); -const char *magic_file(magic_t, const char *); +const char *magic_file(magic_t, const char *, int); const char *magic_descriptor(magic_t, int); const char *magic_buffer(magic_t, const void *, size_t); Index: contrib/file/src/magic.c =================================================================== --- contrib/file/src/magic.c +++ contrib/file/src/magic.c @@ -392,11 +392,11 @@ * find type of named file */ public const char * -magic_file(struct magic_set *ms, const char *inname) +magic_file(struct magic_set *ms, const char *inname, int fd) { if (ms == NULL) return NULL; - return file_or_fd(ms, inname, STDIN_FILENO); + return file_or_fd(ms, inname, fd); } private const char * @@ -420,7 +420,7 @@ if ((buf = CAST(unsigned char *, malloc(ms->bytes_max + SLOP))) == NULL) return NULL; - switch (file_fsmagic(ms, inname, &sb)) { + switch (file_fsmagic(ms, inname, &sb, fd)) { case -1: /* error */ goto done; case 0: /* nothing found */ @@ -441,6 +441,24 @@ ispipe = 1; else pos = lseek(fd, (off_t)0, SEEK_CUR); +#ifdef HAVE_CAPSICUM + } else if (fd > 0 && fd != STDIN_FILENO) { + int flags = O_RDONLY|O_BINARY; + int okstat = fstat(fd, &sb) == 0; + + if (okstat && S_ISFIFO(sb.st_mode)) { +#ifdef O_NONBLOCK + flags |= O_NONBLOCK; +#endif + ispipe = 1; + } +#ifdef O_NONBLOCK + if ((flags = fcntl(fd, F_GETFL)) != -1) { + flags &= ~O_NONBLOCK; + (void)fcntl(fd, F_SETFL, flags); + } +#endif +#endif /* ifdef HAVE_CAPSICUM */ } else { int flags = O_RDONLY|O_BINARY; int okstat = stat(inname, &sb) == 0;