diff options
author | Lorry Tar Creator <lorry-tar-importer@baserock.org> | 2015-01-02 20:23:27 +0000 |
---|---|---|
committer | <> | 2015-02-03 17:27:18 +0000 |
commit | 670c2bbcffe873a2b8589ed140c12e7923ef20c0 (patch) | |
tree | 41044880e826d60621a2d636ed71283de5e0e291 /src | |
parent | 3b49db406667ee7189b9ea69b9d9e0bdcc43c5b7 (diff) | |
download | file-670c2bbcffe873a2b8589ed140c12e7923ef20c0.tar.gz |
Imported from /home/lorry/working-area/delta_file/file-5.22.tar.gz.file-5.22
Diffstat (limited to 'src')
-rw-r--r-- | src/Makefile.in | 284 | ||||
-rw-r--r-- | src/apprentice.c | 817 | ||||
-rw-r--r-- | src/ascmagic.c | 8 | ||||
-rw-r--r-- | src/cdf.c | 198 | ||||
-rw-r--r-- | src/cdf.h | 29 | ||||
-rw-r--r-- | src/cdf_time.c | 9 | ||||
-rw-r--r-- | src/compress.c | 60 | ||||
-rw-r--r-- | src/elfclass.h | 34 | ||||
-rw-r--r-- | src/encoding.c | 15 | ||||
-rw-r--r-- | src/file.c | 80 | ||||
-rw-r--r-- | src/file.h | 84 | ||||
-rw-r--r-- | src/file_opts.h | 8 | ||||
-rw-r--r-- | src/fmtcheck.c | 234 | ||||
-rw-r--r-- | src/fsmagic.c | 60 | ||||
-rw-r--r-- | src/funcs.c | 181 | ||||
-rw-r--r-- | src/getline.c | 18 | ||||
-rw-r--r-- | src/magic.c | 140 | ||||
-rw-r--r-- | src/magic.h | 14 | ||||
-rw-r--r-- | src/magic.h.in | 12 | ||||
-rw-r--r-- | src/pread.c | 17 | ||||
-rw-r--r-- | src/print.c | 22 | ||||
-rw-r--r-- | src/readcdf.c | 314 | ||||
-rw-r--r-- | src/readelf.c | 755 | ||||
-rw-r--r-- | src/readelf.h | 48 | ||||
-rw-r--r-- | src/softmagic.c | 695 | ||||
-rw-r--r-- | src/strcasestr.c | 84 | ||||
-rw-r--r-- | src/vasprintf.c | 23 |
27 files changed, 2996 insertions, 1247 deletions
diff --git a/src/Makefile.in b/src/Makefile.in index 5761964..41cb9f5 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -1,9 +1,8 @@ -# Makefile.in generated by automake 1.11.1 from Makefile.am. +# Makefile.in generated by automake 1.14 from Makefile.am. # @configure_input@ -# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, -# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, -# Inc. +# Copyright (C) 1994-2013 Free Software Foundation, Inc. + # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. @@ -18,6 +17,51 @@ VPATH = @srcdir@ +am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ @@ -37,16 +81,15 @@ build_triplet = @build@ host_triplet = @host@ bin_PROGRAMS = file$(EXEEXT) subdir = src -DIST_COMMON = $(include_HEADERS) $(srcdir)/Makefile.am \ - $(srcdir)/Makefile.in asctime_r.c asprintf.c ctime_r.c \ - getline.c getopt_long.c pread.c strlcat.c strlcpy.c \ - vasprintf.c +DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am ctime_r.c \ + vasprintf.c asctime_r.c asprintf.c strcasestr.c pread.c \ + getline.c strlcpy.c strlcat.c fmtcheck.c getopt_long.c \ + $(top_srcdir)/depcomp $(include_HEADERS) ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ - $(top_srcdir)/m4/visibility.m4 $(top_srcdir)/acinclude.m4 \ - $(top_srcdir)/configure.ac + $(top_srcdir)/acinclude.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d @@ -74,6 +117,12 @@ am__nobase_list = $(am__nobase_strip_setup); \ am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__uninstall_files_from_dir = { \ + test -z "$$files" \ + || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ + || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ + $(am__cd) "$$dir" && rm -f $$files; }; \ + } am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(bindir)" \ "$(DESTDIR)$(includedir)" LTLIBRARIES = $(lib_LTLIBRARIES) @@ -84,9 +133,10 @@ am_libmagic_la_OBJECTS = magic.lo apprentice.lo softmagic.lo \ print.lo fsmagic.lo funcs.lo apptype.lo cdf.lo cdf_time.lo \ readcdf.lo libmagic_la_OBJECTS = $(am_libmagic_la_OBJECTS) -AM_V_lt = $(am__v_lt_$(V)) -am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY)) +AM_V_lt = $(am__v_lt_@AM_V@) +am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent +am__v_lt_1 = libmagic_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(libmagic_la_LDFLAGS) $(LDFLAGS) -o $@ @@ -94,6 +144,18 @@ PROGRAMS = $(bin_PROGRAMS) am_file_OBJECTS = file.$(OBJEXT) file_OBJECTS = $(am_file_OBJECTS) file_DEPENDENCIES = libmagic.la +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles @@ -104,25 +166,43 @@ LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) -AM_V_CC = $(am__v_CC_$(V)) -am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY)) -am__v_CC_0 = @echo " CC " $@; -AM_V_at = $(am__v_at_$(V)) -am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) -am__v_at_0 = @ +AM_V_CC = $(am__v_CC_@AM_V@) +am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) +am__v_CC_0 = @echo " CC " $@; +am__v_CC_1 = CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ -AM_V_CCLD = $(am__v_CCLD_$(V)) -am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY)) -am__v_CCLD_0 = @echo " CCLD " $@; -AM_V_GEN = $(am__v_GEN_$(V)) -am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) -am__v_GEN_0 = @echo " GEN " $@; +AM_V_CCLD = $(am__v_CCLD_@AM_V@) +am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) +am__v_CCLD_0 = @echo " CCLD " $@; +am__v_CCLD_1 = SOURCES = $(libmagic_la_SOURCES) $(file_SOURCES) DIST_SOURCES = $(libmagic_la_SOURCES) $(file_SOURCES) +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac HEADERS = $(include_HEADERS) +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) @@ -144,6 +224,7 @@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ @@ -168,6 +249,7 @@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ MINGW = @MINGW@ MKDIR_P = @MKDIR_P@ NM = @NM@ @@ -195,6 +277,7 @@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ @@ -228,7 +311,6 @@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ -lt_ECHO = @lt_ECHO@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ @@ -299,9 +381,9 @@ $(top_srcdir)/configure: $(am__configure_deps) $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): + install-libLTLIBRARIES: $(lib_LTLIBRARIES) @$(NORMAL_INSTALL) - test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)" @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ list2=; for p in $$list; do \ if test -f $$p; then \ @@ -309,6 +391,8 @@ install-libLTLIBRARIES: $(lib_LTLIBRARIES) else :; fi; \ done; \ test -z "$$list2" || { \ + echo " $(MKDIR_P) '$(DESTDIR)$(libdir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(libdir)" || exit 1; \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ } @@ -324,24 +408,32 @@ uninstall-libLTLIBRARIES: clean-libLTLIBRARIES: -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) - @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ - dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ - test "$$dir" != "$$p" || dir=.; \ - echo "rm -f \"$${dir}/so_locations\""; \ - rm -f "$${dir}/so_locations"; \ - done -libmagic.la: $(libmagic_la_OBJECTS) $(libmagic_la_DEPENDENCIES) + @list='$(lib_LTLIBRARIES)'; \ + locs=`for p in $$list; do echo $$p; done | \ + sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ + sort -u`; \ + test -z "$$locs" || { \ + echo rm -f $${locs}; \ + rm -f $${locs}; \ + } + +libmagic.la: $(libmagic_la_OBJECTS) $(libmagic_la_DEPENDENCIES) $(EXTRA_libmagic_la_DEPENDENCIES) $(AM_V_CCLD)$(libmagic_la_LINK) -rpath $(libdir) $(libmagic_la_OBJECTS) $(libmagic_la_LIBADD) $(LIBS) install-binPROGRAMS: $(bin_PROGRAMS) @$(NORMAL_INSTALL) - test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)" @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(bindir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(bindir)" || exit 1; \ + fi; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ - while read p p1; do if test -f $$p || test -f $$p1; \ - then echo "$$p"; echo "$$p"; else :; fi; \ + while read p p1; do if test -f $$p \ + || test -f $$p1 \ + ; then echo "$$p"; echo "$$p"; else :; fi; \ done | \ - sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \ + sed -e 'p;s,.*/,,;n;h' \ + -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ @@ -362,7 +454,8 @@ uninstall-binPROGRAMS: @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ - -e 's/$$/$(EXEEXT)/' `; \ + -e 's/$$/$(EXEEXT)/' \ + `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(bindir)" && rm -f $$files @@ -375,7 +468,8 @@ clean-binPROGRAMS: list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list -file$(EXEEXT): $(file_OBJECTS) $(file_DEPENDENCIES) + +file$(EXEEXT): $(file_OBJECTS) $(file_DEPENDENCIES) $(EXTRA_file_DEPENDENCIES) @rm -f file$(EXEEXT) $(AM_V_CCLD)$(LINK) $(file_OBJECTS) $(file_LDADD) $(LIBS) @@ -388,9 +482,11 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/asctime_r.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/asprintf.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/ctime_r.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/fmtcheck.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/getline.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/getopt_long.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/pread.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/strcasestr.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/strlcat.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/strlcpy.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/vasprintf.Plo@am__quote@ @@ -415,28 +511,25 @@ distclean-compile: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po -@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(COMPILE) -c -o $@ $< +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po -@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\ @am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo -@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo @@ -445,8 +538,11 @@ clean-libtool: -rm -rf .libs _libs install-includeHEADERS: $(include_HEADERS) @$(NORMAL_INSTALL) - test -z "$(includedir)" || $(MKDIR_P) "$(DESTDIR)$(includedir)" @list='$(include_HEADERS)'; test -n "$(includedir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(includedir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(includedir)" || exit 1; \ + fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ @@ -460,30 +556,17 @@ uninstall-includeHEADERS: @$(NORMAL_UNINSTALL) @list='$(include_HEADERS)'; test -n "$(includedir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ - test -n "$$files" || exit 0; \ - echo " ( cd '$(DESTDIR)$(includedir)' && rm -f" $$files ")"; \ - cd "$(DESTDIR)$(includedir)" && rm -f $$files - -ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) - list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ - unique=`for i in $$list; do \ - if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ - done | \ - $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ - END { if (nonempty) { for (i in files) print i; }; }'`; \ - mkid -fID $$unique -tags: TAGS - -TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ - $(TAGS_FILES) $(LISP) + dir='$(DESTDIR)$(includedir)'; $(am__uninstall_files_from_dir) + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-am +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ - list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ - unique=`for i in $$list; do \ - if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ - done | \ - $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ - END { if (nonempty) { for (i in files) print i; }; }'`; \ + $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ @@ -495,15 +578,11 @@ TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $$unique; \ fi; \ fi -ctags: CTAGS -CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ - $(TAGS_FILES) $(LISP) - list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ - unique=`for i in $$list; do \ - if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ - done | \ - $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ - END { if (nonempty) { for (i in files) print i; }; }'`; \ +ctags: ctags-am + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique @@ -512,6 +591,21 @@ GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" +cscopelist: cscopelist-am + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags @@ -567,10 +661,15 @@ install-am: all-am installcheck: installcheck-am install-strip: - $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ - install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ - `test -z '$(STRIP)' || \ - echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi mostlyclean-generic: clean-generic: @@ -658,20 +757,21 @@ uninstall-am: uninstall-binPROGRAMS uninstall-includeHEADERS \ .MAKE: all check install install-am install-strip -.PHONY: CTAGS GTAGS all all-am check check-am clean clean-binPROGRAMS \ - clean-generic clean-libLTLIBRARIES clean-libtool ctags \ - distclean distclean-compile distclean-generic \ - distclean-libtool distclean-tags distdir dvi dvi-am html \ - html-am info info-am install install-am install-binPROGRAMS \ - install-data install-data-am install-dvi install-dvi-am \ - install-exec install-exec-am install-html install-html-am \ +.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean \ + clean-binPROGRAMS clean-generic clean-libLTLIBRARIES \ + clean-libtool cscopelist-am ctags ctags-am distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-binPROGRAMS install-data \ + install-data-am install-dvi install-dvi-am install-exec \ + install-exec-am install-html install-html-am \ install-includeHEADERS install-info install-info-am \ install-libLTLIBRARIES install-man install-pdf install-pdf-am \ install-ps install-ps-am install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ - tags uninstall uninstall-am uninstall-binPROGRAMS \ + tags tags-am uninstall uninstall-am uninstall-binPROGRAMS \ uninstall-includeHEADERS uninstall-libLTLIBRARIES diff --git a/src/apprentice.c b/src/apprentice.c index cd45bdc..47b4c87 100644 --- a/src/apprentice.c +++ b/src/apprentice.c @@ -32,7 +32,7 @@ #include "file.h" #ifndef lint -FILE_RCSID("@(#)$File: apprentice.c,v 1.190 2013/02/17 22:29:40 christos Exp $") +FILE_RCSID("@(#)$File: apprentice.c,v 1.229 2015/01/01 17:07:34 christos Exp $") #endif /* lint */ #include "magic.h" @@ -40,6 +40,9 @@ FILE_RCSID("@(#)$File: apprentice.c,v 1.190 2013/02/17 22:29:40 christos Exp $") #ifdef HAVE_UNISTD_H #include <unistd.h> #endif +#ifdef HAVE_STDDEF_H +#include <stddef.h> +#endif #include <string.h> #include <assert.h> #include <ctype.h> @@ -48,6 +51,15 @@ FILE_RCSID("@(#)$File: apprentice.c,v 1.190 2013/02/17 22:29:40 christos Exp $") #include <sys/mman.h> #endif #include <dirent.h> +#if defined(HAVE_LIMITS_H) +#include <limits.h> +#endif + +#ifndef SSIZE_MAX +#define MAXMAGIC_SIZE ((ssize_t)0x7fffffff) +#else +#define MAXMAGIC_SIZE SSIZE_MAX +#endif #define EATAB {while (isascii((unsigned char) *l) && \ isspace((unsigned char) *l)) ++l;} @@ -74,15 +86,26 @@ FILE_RCSID("@(#)$File: apprentice.c,v 1.190 2013/02/17 22:29:40 christos Exp $") #define ALLOC_CHUNK (size_t)10 #define ALLOC_INCR (size_t)200 +#define MAP_TYPE_MMAP 0 +#define MAP_TYPE_MALLOC 1 +#define MAP_TYPE_USER 2 + struct magic_entry { struct magic *mp; uint32_t cont_count; uint32_t max_count; }; +struct magic_entry_set { + struct magic_entry *me; + uint32_t count; + uint32_t max; +}; + struct magic_map { void *p; size_t len; + int type; struct magic *magic[MAGIC_SETS]; uint32_t nmagic[MAGIC_SETS]; }; @@ -113,7 +136,10 @@ private uint16_t swap2(uint16_t); private uint32_t swap4(uint32_t); private uint64_t swap8(uint64_t); private char *mkdbname(struct magic_set *, const char *, int); +private struct magic_map *apprentice_buf(struct magic_set *, struct magic *, + size_t); private struct magic_map *apprentice_map(struct magic_set *, const char *); +private int check_buffer(struct magic_set *, struct magic_map *, const char *); private void apprentice_unmap(struct magic_map *); private int apprentice_compile(struct magic_set *, struct magic_map *, const char *); @@ -125,7 +151,6 @@ private int parse_strength(struct magic_set *, struct magic_entry *, const char private int parse_apple(struct magic_set *, struct magic_entry *, const char *); -private size_t maxmagic[MAGIC_SETS] = { 0 }; private size_t magicsize = sizeof(struct magic); private const char usg_hdr[] = "cont\toffset\ttype\topcode\tmask\tvalue\tdesc"; @@ -196,7 +221,7 @@ static const struct type_tbl_s type_tbl[] = { { XX("invalid"), FILE_INVALID, FILE_FMT_NONE }, { XX("byte"), FILE_BYTE, FILE_FMT_NUM }, { XX("short"), FILE_SHORT, FILE_FMT_NUM }, - { XX("default"), FILE_DEFAULT, FILE_FMT_STR }, + { XX("default"), FILE_DEFAULT, FILE_FMT_NONE }, { XX("long"), FILE_LONG, FILE_FMT_NUM }, { XX("string"), FILE_STRING, FILE_FMT_STR }, { XX("date"), FILE_DATE, FILE_FMT_STR }, @@ -240,6 +265,7 @@ static const struct type_tbl_s type_tbl[] = { { XX("beqwdate"), FILE_BEQWDATE, FILE_FMT_STR }, { XX("name"), FILE_NAME, FILE_FMT_NONE }, { XX("use"), FILE_USE, FILE_FMT_NONE }, + { XX("clear"), FILE_CLEAR, FILE_FMT_NONE }, { XX_NULL, FILE_INVALID, FILE_FMT_NONE }, }; @@ -378,10 +404,11 @@ add_mlist(struct mlist *mlp, struct magic_map *map, size_t idx) { struct mlist *ml; + mlp->map = idx == 0 ? map : NULL; if ((ml = CAST(struct mlist *, malloc(sizeof(*ml)))) == NULL) return -1; - ml->map = idx == 0 ? map : NULL; + ml->map = NULL; ml->magic = map->magic[idx]; ml->nmagic = map->nmagic[idx]; @@ -398,9 +425,11 @@ add_mlist(struct mlist *mlp, struct magic_map *map, size_t idx) private int apprentice_1(struct magic_set *ms, const char *fn, int action) { - struct mlist *ml; struct magic_map *map; +#ifndef COMPILE_ONLY + struct mlist *ml; size_t i; +#endif if (magicsize != FILE_MAGICSIZE) { file_error(ms, 0, "magic element size %lu != %lu", @@ -429,20 +458,27 @@ apprentice_1(struct magic_set *ms, const char *fn, int action) for (i = 0; i < MAGIC_SETS; i++) { if (add_mlist(ms->mlist[i], map, i) == -1) { file_oomem(ms, sizeof(*ml)); - apprentice_unmap(map); - return -1; + goto fail; } } if (action == FILE_LIST) { for (i = 0; i < MAGIC_SETS; i++) { - printf("Set %zu:\nBinary patterns:\n", i); + printf("Set %" SIZE_T_FORMAT "u:\nBinary patterns:\n", + i); apprentice_list(ms->mlist[i], BINTEST); printf("Text patterns:\n"); apprentice_list(ms->mlist[i], TEXTTEST); } } - + return 0; +fail: + for (i = 0; i < MAGIC_SETS; i++) { + mlist_free(ms->mlist[i]); + ms->mlist[i] = NULL; + } + return -1; +#else return 0; #endif /* COMPILE_ONLY */ } @@ -488,6 +524,11 @@ file_ms_alloc(int flags) ms->mlist[i] = NULL; ms->file = "unknown"; ms->line = 0; + ms->indir_max = FILE_INDIR_MAX; + ms->name_max = FILE_NAME_MAX; + ms->elf_shnum_max = FILE_ELF_SHNUM_MAX; + ms->elf_phnum_max = FILE_ELF_PHNUM_MAX; + ms->elf_notes_max = FILE_ELF_NOTES_MAX; return ms; free: free(ms); @@ -499,14 +540,22 @@ apprentice_unmap(struct magic_map *map) { if (map == NULL) return; - if (map->p == NULL) - return; + + switch (map->type) { #ifdef QUICK - if (map->len) - (void)munmap(map->p, map->len); - else + case MAP_TYPE_MMAP: + if (map->p) + (void)munmap(map->p, map->len); + break; #endif + case MAP_TYPE_MALLOC: free(map->p); + break; + case MAP_TYPE_USER: + break; + default: + abort(); + } free(map); } @@ -524,21 +573,70 @@ mlist_alloc(void) private void mlist_free(struct mlist *mlist) { - struct mlist *ml; + struct mlist *ml, *next; if (mlist == NULL) return; - for (ml = mlist->next; ml != mlist;) { - struct mlist *next = ml->next; + ml = mlist->next; + for (ml = mlist->next; (next = ml->next) != NULL; ml = next) { if (ml->map) apprentice_unmap(ml->map); free(ml); - ml = next; + if (ml == mlist) + break; } - free(ml); } +#ifndef COMPILE_ONLY +/* void **bufs: an array of compiled magic files */ +protected int +buffer_apprentice(struct magic_set *ms, struct magic **bufs, + size_t *sizes, size_t nbufs) +{ + size_t i, j; + struct mlist *ml; + struct magic_map *map; + + if (nbufs == 0) + return -1; + + if (ms->mlist[0] != NULL) + file_reset(ms); + + init_file_tables(); + + for (i = 0; i < MAGIC_SETS; i++) { + mlist_free(ms->mlist[i]); + if ((ms->mlist[i] = mlist_alloc()) == NULL) { + file_oomem(ms, sizeof(*ms->mlist[i])); + goto fail; + } + } + + for (i = 0; i < nbufs; i++) { + map = apprentice_buf(ms, bufs[i], sizes[i]); + if (map == NULL) + goto fail; + + for (j = 0; j < MAGIC_SETS; j++) { + if (add_mlist(ms->mlist[j], map, j) == -1) { + file_oomem(ms, sizeof(*ml)); + goto fail; + } + } + } + + return 0; +fail: + for (i = 0; i < MAGIC_SETS; i++) { + mlist_free(ms->mlist[i]); + ms->mlist[i] = NULL; + } + return -1; +} +#endif + /* const char *fn: list of magic files and directories */ protected int file_apprentice(struct magic_set *ms, const char *fn, int action) @@ -547,6 +645,9 @@ file_apprentice(struct magic_set *ms, const char *fn, int action) int file_err, errs = -1; size_t i; + if (ms->mlist[0] != NULL) + file_reset(ms); + if ((fn = magic_getpath(fn, action)) == NULL) return -1; @@ -561,11 +662,9 @@ file_apprentice(struct magic_set *ms, const char *fn, int action) mlist_free(ms->mlist[i]); if ((ms->mlist[i] = mlist_alloc()) == NULL) { file_oomem(ms, sizeof(*ms->mlist[i])); - if (i != 0) { - --i; - do - mlist_free(ms->mlist[i]); - while (i != 0); + while (i-- > 0) { + mlist_free(ms->mlist[i]); + ms->mlist[i] = NULL; } free(mfn); return -1; @@ -595,6 +694,10 @@ file_apprentice(struct magic_set *ms, const char *fn, int action) return -1; } +#if 0 + /* + * Always leave the database loaded + */ if (action == FILE_LOAD) return 0; @@ -602,8 +705,10 @@ file_apprentice(struct magic_set *ms, const char *fn, int action) mlist_free(ms->mlist[i]); ms->mlist[i] = NULL; } +#endif switch (action) { + case FILE_LOAD: case FILE_COMPILE: case FILE_CHECK: case FILE_LIST: @@ -615,13 +720,62 @@ file_apprentice(struct magic_set *ms, const char *fn, int action) } /* + * Compute the real length of a magic expression, for the purposes + * of determining how "strong" a magic expression is (approximating + * how specific its matches are): + * - magic characters count 0 unless escaped. + * - [] expressions count 1 + * - {} expressions count 0 + * - regular characters or escaped magic characters count 1 + * - 0 length expressions count as one + */ +private size_t +nonmagic(const char *str) +{ + const char *p; + size_t rv = 0; + + for (p = str; *p; p++) + switch (*p) { + case '\\': /* Escaped anything counts 1 */ + if (!*++p) + p--; + rv++; + continue; + case '?': /* Magic characters count 0 */ + case '*': + case '.': + case '+': + case '^': + case '$': + continue; + case '[': /* Bracketed expressions count 1 the ']' */ + while (*p && *p != ']') + p++; + p--; + continue; + case '{': /* Braced expressions count 0 */ + while (*p && *p != '}') + p++; + if (!*p) + p--; + continue; + default: /* Anything else counts 1 */ + rv++; + continue; + } + + return rv == 0 ? 1 : rv; /* Return at least 1 */ +} + +/* * Get weight of this magic entry, for sorting purposes. */ private size_t apprentice_magic_strength(const struct magic *m) { #define MULT 10 - size_t val = 2 * MULT; /* baseline strength */ + size_t v, val = 2 * MULT; /* baseline strength */ switch (m->type) { case FILE_DEFAULT: /* make sure this sorts last */ @@ -657,10 +811,14 @@ apprentice_magic_strength(const struct magic *m) break; case FILE_SEARCH: - case FILE_REGEX: val += m->vallen * MAX(MULT / m->vallen, 1); break; + case FILE_REGEX: + v = nonmagic(m->value.s); + val += v * MAX(MULT / v, 1); + break; + case FILE_DATE: case FILE_LEDATE: case FILE_BEDATE: @@ -699,7 +857,6 @@ apprentice_magic_strength(const struct magic *m) break; default: - val = 0; (void)fprintf(stderr, "Bad type %d\n", m->type); abort(); } @@ -896,24 +1053,24 @@ set_test_type(struct magic *mstart, struct magic *m) private int addentry(struct magic_set *ms, struct magic_entry *me, - struct magic_entry **mentry, uint32_t *mentrycount) + struct magic_entry_set *mset) { size_t i = me->mp->type == FILE_NAME ? 1 : 0; - if (mentrycount[i] == maxmagic[i]) { + if (mset[i].count == mset[i].max) { struct magic_entry *mp; - maxmagic[i] += ALLOC_INCR; + mset[i].max += ALLOC_INCR; if ((mp = CAST(struct magic_entry *, - realloc(mentry[i], sizeof(*mp) * maxmagic[i]))) == + realloc(mset[i].me, sizeof(*mp) * mset[i].max))) == NULL) { - file_oomem(ms, sizeof(*mp) * maxmagic[i]); + file_oomem(ms, sizeof(*mp) * mset[i].max); return -1; } - (void)memset(&mp[mentrycount[i]], 0, sizeof(*mp) * + (void)memset(&mp[mset[i].count], 0, sizeof(*mp) * ALLOC_INCR); - mentry[i] = mp; + mset[i].me = mp; } - mentry[i][mentrycount[i]++] = *me; + mset[i].me[mset[i].count++] = *me; memset(me, 0, sizeof(*me)); return 0; } @@ -923,7 +1080,7 @@ addentry(struct magic_set *ms, struct magic_entry *me, */ private void load_1(struct magic_set *ms, int action, const char *fn, int *errs, - struct magic_entry **mentry, uint32_t *mentrycount) + struct magic_entry_set *mset) { size_t lineno = 0, llen = 0; char *line = NULL; @@ -990,7 +1147,7 @@ load_1(struct magic_set *ms, int action, const char *fn, int *errs, case 0: continue; case 1: - (void)addentry(ms, &me, mentry, mentrycount); + (void)addentry(ms, &me, mset); goto again; default: (*errs)++; @@ -999,7 +1156,7 @@ load_1(struct magic_set *ms, int action, const char *fn, int *errs, } } if (me.mp) - (void)addentry(ms, &me, mentry, mentrycount); + (void)addentry(ms, &me, mset); free(line); (void)fclose(f); } @@ -1110,19 +1267,21 @@ private struct magic_map * apprentice_load(struct magic_set *ms, const char *fn, int action) { int errs = 0; - struct magic_entry *mentry[MAGIC_SETS] = { NULL }; - uint32_t mentrycount[MAGIC_SETS] = { 0 }; uint32_t i, j; size_t files = 0, maxfiles = 0; char **filearr = NULL, *mfn; struct stat st; struct magic_map *map; + struct magic_entry_set mset[MAGIC_SETS]; DIR *dir; struct dirent *d; + memset(mset, 0, sizeof(mset)); ms->flags |= MAGIC_CHECK; /* Enable checks for parsed files */ - if ((map = CAST(struct magic_map *, calloc(1, sizeof(*map)))) == NULL) { + + if ((map = CAST(struct magic_map *, calloc(1, sizeof(*map)))) == NULL) + { file_oomem(ms, sizeof(*map)); return NULL; } @@ -1168,36 +1327,35 @@ apprentice_load(struct magic_set *ms, const char *fn, int action) closedir(dir); qsort(filearr, files, sizeof(*filearr), cmpstrp); for (i = 0; i < files; i++) { - load_1(ms, action, filearr[i], &errs, mentry, - mentrycount); + load_1(ms, action, filearr[i], &errs, mset); free(filearr[i]); } free(filearr); } else - load_1(ms, action, fn, &errs, mentry, mentrycount); + load_1(ms, action, fn, &errs, mset); if (errs) goto out; for (j = 0; j < MAGIC_SETS; j++) { /* Set types of tests */ - for (i = 0; i < mentrycount[j]; ) { - if (mentry[j][i].mp->cont_level != 0) { + for (i = 0; i < mset[j].count; ) { + if (mset[j].me[i].mp->cont_level != 0) { i++; continue; } - i = set_text_binary(ms, mentry[j], mentrycount[j], i); + i = set_text_binary(ms, mset[j].me, mset[j].count, i); } - qsort(mentry[j], mentrycount[j], sizeof(*mentry[j]), + qsort(mset[j].me, mset[j].count, sizeof(*mset[j].me), apprentice_sort); /* * Make sure that any level 0 "default" line is last * (if one exists). */ - set_last_default(ms, mentry[j], mentrycount[j]); + set_last_default(ms, mset[j].me, mset[j].count); /* coalesce per file arrays into a single one */ - if (coalesce_entries(ms, mentry[j], mentrycount[j], + if (coalesce_entries(ms, mset[j].me, mset[j].count, &map->magic[j], &map->nmagic[j]) == -1) { errs++; goto out; @@ -1206,14 +1364,10 @@ apprentice_load(struct magic_set *ms, const char *fn, int action) out: for (j = 0; j < MAGIC_SETS; j++) - magic_entry_free(mentry[j], mentrycount[j]); + magic_entry_free(mset[j].me, mset[j].count); if (errs) { - for (j = 0; j < MAGIC_SETS; j++) { - if (map->magic[j]) - free(map->magic[j]); - } - free(map); + apprentice_unmap(map); return NULL; } return map; @@ -1233,7 +1387,7 @@ file_signextend(struct magic_set *ms, struct magic *m, uint64_t v) * the sign extension must have happened. */ case FILE_BYTE: - v = (char) v; + v = (signed char) v; break; case FILE_SHORT: case FILE_BESHORT: @@ -1284,6 +1438,7 @@ file_signextend(struct magic_set *ms, struct magic *m, uint64_t v) case FILE_INDIRECT: case FILE_NAME: case FILE_USE: + case FILE_CLEAR: break; default: if (ms->flags & MAGIC_CHECK) @@ -1301,7 +1456,8 @@ string_modifier_check(struct magic_set *ms, struct magic *m) if ((ms->flags & MAGIC_CHECK) == 0) return 0; - if (m->type != FILE_PSTRING && (m->str_flags & PSTRING_LEN) != 0) { + if ((m->type != FILE_REGEX || (m->str_flags & REGEX_LINE_COUNT) == 0) && + (m->type != FILE_PSTRING && (m->str_flags & PSTRING_LEN) != 0)) { file_magwarn(ms, "'/BHhLl' modifiers are only allowed for pascal strings\n"); return -1; @@ -1449,6 +1605,145 @@ check_cond(struct magic_set *ms, int cond, uint32_t cont_level) } #endif /* ENABLE_CONDITIONALS */ +private int +parse_indirect_modifier(struct magic_set *ms, struct magic *m, const char **lp) +{ + const char *l = *lp; + + while (!isspace((unsigned char)*++l)) + switch (*l) { + case CHAR_INDIRECT_RELATIVE: + m->str_flags |= INDIRECT_RELATIVE; + break; + default: + if (ms->flags & MAGIC_CHECK) + file_magwarn(ms, "indirect modifier `%c' " + "invalid", *l); + *lp = l; + return -1; + } + *lp = l; + return 0; +} + +private void +parse_op_modifier(struct magic_set *ms, struct magic *m, const char **lp, + int op) +{ + const char *l = *lp; + char *t; + uint64_t val; + + ++l; + m->mask_op |= op; + val = (uint64_t)strtoull(l, &t, 0); + l = t; + m->num_mask = file_signextend(ms, m, val); + eatsize(&l); + *lp = l; +} + +private int +parse_string_modifier(struct magic_set *ms, struct magic *m, const char **lp) +{ + const char *l = *lp; + char *t; + int have_range = 0; + + while (!isspace((unsigned char)*++l)) { + switch (*l) { + case '0': case '1': case '2': + case '3': case '4': case '5': + case '6': case '7': case '8': + case '9': + if (have_range && (ms->flags & MAGIC_CHECK)) + file_magwarn(ms, "multiple ranges"); + have_range = 1; + m->str_range = CAST(uint32_t, strtoul(l, &t, 0)); + if (m->str_range == 0) + file_magwarn(ms, "zero range"); + l = t - 1; + break; + case CHAR_COMPACT_WHITESPACE: + m->str_flags |= STRING_COMPACT_WHITESPACE; + break; + case CHAR_COMPACT_OPTIONAL_WHITESPACE: + m->str_flags |= STRING_COMPACT_OPTIONAL_WHITESPACE; + break; + case CHAR_IGNORE_LOWERCASE: + m->str_flags |= STRING_IGNORE_LOWERCASE; + break; + case CHAR_IGNORE_UPPERCASE: + m->str_flags |= STRING_IGNORE_UPPERCASE; + break; + case CHAR_REGEX_OFFSET_START: + m->str_flags |= REGEX_OFFSET_START; + break; + case CHAR_BINTEST: + m->str_flags |= STRING_BINTEST; + break; + case CHAR_TEXTTEST: + m->str_flags |= STRING_TEXTTEST; + break; + case CHAR_TRIM: + m->str_flags |= STRING_TRIM; + break; + case CHAR_PSTRING_1_LE: +#define SET_LENGTH(a) m->str_flags = (m->str_flags & ~PSTRING_LEN) | (a) + if (m->type != FILE_PSTRING) + goto bad; + SET_LENGTH(PSTRING_1_LE); + break; + case CHAR_PSTRING_2_BE: + if (m->type != FILE_PSTRING) + goto bad; + SET_LENGTH(PSTRING_2_BE); + break; + case CHAR_PSTRING_2_LE: + if (m->type != FILE_PSTRING) + goto bad; + SET_LENGTH(PSTRING_2_LE); + break; + case CHAR_PSTRING_4_BE: + if (m->type != FILE_PSTRING) + goto bad; + SET_LENGTH(PSTRING_4_BE); + break; + case CHAR_PSTRING_4_LE: + switch (m->type) { + case FILE_PSTRING: + case FILE_REGEX: + break; + default: + goto bad; + } + SET_LENGTH(PSTRING_4_LE); + break; + case CHAR_PSTRING_LENGTH_INCLUDES_ITSELF: + if (m->type != FILE_PSTRING) + goto bad; + m->str_flags |= PSTRING_LENGTH_INCLUDES_ITSELF; + break; + default: + bad: + if (ms->flags & MAGIC_CHECK) + file_magwarn(ms, "string modifier `%c' " + "invalid", *l); + goto out; + } + /* allow multiple '/' for readability */ + if (l[1] == '/' && !isspace((unsigned char)l[2])) + l++; + } + if (string_modifier_check(ms, m) == -1) + goto out; + *lp = l; + return 0; +out: + *lp = l; + return -1; +} + /* * parse one line from magic file, put into magic[index++] if valid */ @@ -1667,7 +1962,7 @@ parse(struct magic_set *ms, struct magic_entry *me, const char *line, */ m->type = get_standard_integer_type(l, &l); } - // It's unsigned. + /* It's unsigned. */ if (m->type != FILE_INVALID) m->flag |= UNSIGNED; } else { @@ -1718,113 +2013,27 @@ parse(struct magic_set *ms, struct magic_entry *me, const char *line, m->str_range = 0; m->str_flags = m->type == FILE_PSTRING ? PSTRING_1_LE : 0; if ((op = get_op(*l)) != -1) { - if (!IS_STRING(m->type)) { - uint64_t val; - ++l; - m->mask_op |= op; - val = (uint64_t)strtoull(l, &t, 0); - l = t; - m->num_mask = file_signextend(ms, m, val); - eatsize(&l); - } - else if (op == FILE_OPDIVIDE) { - int have_range = 0; - while (!isspace((unsigned char)*++l)) { - switch (*l) { - case '0': case '1': case '2': - case '3': case '4': case '5': - case '6': case '7': case '8': - case '9': - if (have_range && - (ms->flags & MAGIC_CHECK)) - file_magwarn(ms, - "multiple ranges"); - have_range = 1; - m->str_range = CAST(uint32_t, - strtoul(l, &t, 0)); - if (m->str_range == 0) - file_magwarn(ms, - "zero range"); - l = t - 1; - break; - case CHAR_COMPACT_WHITESPACE: - m->str_flags |= - STRING_COMPACT_WHITESPACE; - break; - case CHAR_COMPACT_OPTIONAL_WHITESPACE: - m->str_flags |= - STRING_COMPACT_OPTIONAL_WHITESPACE; - break; - case CHAR_IGNORE_LOWERCASE: - m->str_flags |= STRING_IGNORE_LOWERCASE; - break; - case CHAR_IGNORE_UPPERCASE: - m->str_flags |= STRING_IGNORE_UPPERCASE; - break; - case CHAR_REGEX_OFFSET_START: - m->str_flags |= REGEX_OFFSET_START; - break; - case CHAR_BINTEST: - m->str_flags |= STRING_BINTEST; - break; - case CHAR_TEXTTEST: - m->str_flags |= STRING_TEXTTEST; - break; - case CHAR_TRIM: - m->str_flags |= STRING_TRIM; - break; - case CHAR_PSTRING_1_LE: - if (m->type != FILE_PSTRING) - goto bad; - m->str_flags = (m->str_flags & ~PSTRING_LEN) | PSTRING_1_LE; - break; - case CHAR_PSTRING_2_BE: - if (m->type != FILE_PSTRING) - goto bad; - m->str_flags = (m->str_flags & ~PSTRING_LEN) | PSTRING_2_BE; - break; - case CHAR_PSTRING_2_LE: - if (m->type != FILE_PSTRING) - goto bad; - m->str_flags = (m->str_flags & ~PSTRING_LEN) | PSTRING_2_LE; - break; - case CHAR_PSTRING_4_BE: - if (m->type != FILE_PSTRING) - goto bad; - m->str_flags = (m->str_flags & ~PSTRING_LEN) | PSTRING_4_BE; - break; - case CHAR_PSTRING_4_LE: - if (m->type != FILE_PSTRING) - goto bad; - m->str_flags = (m->str_flags & ~PSTRING_LEN) | PSTRING_4_LE; - break; - case CHAR_PSTRING_LENGTH_INCLUDES_ITSELF: - if (m->type != FILE_PSTRING) - goto bad; - m->str_flags |= PSTRING_LENGTH_INCLUDES_ITSELF; - break; - default: - bad: - if (ms->flags & MAGIC_CHECK) - file_magwarn(ms, - "string extension `%c' " - "invalid", *l); - return -1; - } - /* allow multiple '/' for readability */ - if (l[1] == '/' && - !isspace((unsigned char)l[2])) - l++; + if (IS_STRING(m->type)) { + int r; + + if (op != FILE_OPDIVIDE) { + if (ms->flags & MAGIC_CHECK) + file_magwarn(ms, + "invalid string/indirect op: " + "`%c'", *t); + return -1; } - if (string_modifier_check(ms, m) == -1) + + if (m->type == FILE_INDIRECT) + r = parse_indirect_modifier(ms, m, &l); + else + r = parse_string_modifier(ms, m, &l); + if (r == -1) return -1; - } - else { - if (ms->flags & MAGIC_CHECK) - file_magwarn(ms, "invalid string op: %c", *t); - return -1; - } + } else + parse_op_modifier(ms, m, &l, op); } + /* * We used to set mask to all 1's here, instead let's just not do * anything if mask = 0 (unless you have a better idea) @@ -1936,6 +2145,11 @@ parse_strength(struct magic_set *ms, struct magic_entry *me, const char *line) m->factor_op, m->factor); return -1; } + if (m->type == FILE_NAME) { + file_magwarn(ms, "%s: Strength setting is not supported in " + "\"name\" magic entries", m->value.s); + return -1; + } EATAB; switch (*l) { case FILE_FACTOR_OP_NONE: @@ -1972,39 +2186,70 @@ out: return -1; } -/* - * Parse an Apple CREATOR/TYPE annotation from magic file and put it into - * magic[index - 1] - */ private int -parse_apple(struct magic_set *ms, struct magic_entry *me, const char *line) +goodchar(unsigned char x, const char *extra) +{ + return (isascii(x) && isalnum(x)) || strchr(extra, x); +} + +private int +parse_extra(struct magic_set *ms, struct magic_entry *me, const char *line, + off_t off, size_t len, const char *name, const char *extra, int nt) { size_t i; const char *l = line; struct magic *m = &me->mp[me->cont_count == 0 ? 0 : me->cont_count - 1]; + char *buf = (char *)m + off; - if (m->apple[0] != '\0') { - file_magwarn(ms, "Current entry already has a APPLE type " - "`%.8s', new type `%s'", m->mimetype, l); + if (buf[0] != '\0') { + len = nt ? strlen(buf) : len; + file_magwarn(ms, "Current entry already has a %s type " + "`%.*s', new type `%s'", name, (int)len, buf, l); return -1; } + if (*m->desc == '\0') { + file_magwarn(ms, "Current entry does not yet have a " + "description for adding a %s type", name); + return -1; + } + EATAB; - for (i = 0; *l && ((isascii((unsigned char)*l) && - isalnum((unsigned char)*l)) || strchr("-+/.", *l)) && - i < sizeof(m->apple); m->apple[i++] = *l++) + for (i = 0; *l && i < len && goodchar(*l, extra); buf[i++] = *l++) continue; - if (i == sizeof(m->apple) && *l) { - /* We don't need to NUL terminate here, printing handles it */ + + if (i == len && *l) { + if (nt) + buf[len - 1] = '\0'; if (ms->flags & MAGIC_CHECK) - file_magwarn(ms, "APPLE type `%s' truncated %" - SIZE_T_FORMAT "u", line, i); + file_magwarn(ms, "%s type `%s' truncated %" + SIZE_T_FORMAT "u", name, line, i); + } else { + if (!isspace((unsigned char)*l) && !goodchar(*l, extra)) + file_magwarn(ms, "%s type `%s' has bad char '%c'", + name, line, *l); + if (nt) + buf[i] = '\0'; } if (i > 0) return 0; - else - return -1; + + file_magerror(ms, "Bad magic entry '%s'", line); + return -1; +} + +/* + * Parse an Apple CREATOR/TYPE annotation from magic file and put it into + * magic[index - 1] + */ +private int +parse_apple(struct magic_set *ms, struct magic_entry *me, const char *line) +{ + struct magic *m = &me->mp[0]; + + return parse_extra(ms, me, line, offsetof(struct magic, apple), + sizeof(m->apple), "APPLE", "!+-./", 0); } /* @@ -2014,49 +2259,50 @@ parse_apple(struct magic_set *ms, struct magic_entry *me, const char *line) private int parse_mime(struct magic_set *ms, struct magic_entry *me, const char *line) { - size_t i; - const char *l = line; - struct magic *m = &me->mp[me->cont_count == 0 ? 0 : me->cont_count - 1]; - - if (m->mimetype[0] != '\0') { - file_magwarn(ms, "Current entry already has a MIME type `%s'," - " new type `%s'", m->mimetype, l); - return -1; - } - - EATAB; - for (i = 0; *l && ((isascii((unsigned char)*l) && - isalnum((unsigned char)*l)) || strchr("-+/.", *l)) && - i < sizeof(m->mimetype); m->mimetype[i++] = *l++) - continue; - if (i == sizeof(m->mimetype)) { - m->mimetype[sizeof(m->mimetype) - 1] = '\0'; - if (ms->flags & MAGIC_CHECK) - file_magwarn(ms, "MIME type `%s' truncated %" - SIZE_T_FORMAT "u", m->mimetype, i); - } else - m->mimetype[i] = '\0'; + struct magic *m = &me->mp[0]; - if (i > 0) - return 0; - else - return -1; + return parse_extra(ms, me, line, offsetof(struct magic, mimetype), + sizeof(m->mimetype), "MIME", "+-/.", 1); } private int check_format_type(const char *ptr, int type) { - int quad = 0; + int quad = 0, h; if (*ptr == '\0') { /* Missing format string; bad */ return -1; } - switch (type) { + switch (file_formats[type]) { case FILE_FMT_QUAD: quad = 1; /*FALLTHROUGH*/ case FILE_FMT_NUM: + if (quad == 0) { + switch (type) { + case FILE_BYTE: + h = 2; + break; + case FILE_SHORT: + case FILE_BESHORT: + case FILE_LESHORT: + h = 1; + break; + case FILE_LONG: + case FILE_BELONG: + case FILE_LELONG: + case FILE_MELONG: + case FILE_LEID3: + case FILE_BEID3: + case FILE_INDIRECT: + h = 0; + break; + default: + abort(); + } + } else + h = 0; if (*ptr == '-') ptr++; if (*ptr == '.') @@ -2073,45 +2319,67 @@ check_format_type(const char *ptr, int type) } switch (*ptr++) { +#ifdef STRICT_FORMAT /* "long" formats are int formats for us */ + /* so don't accept the 'l' modifier */ case 'l': switch (*ptr++) { case 'i': case 'd': case 'u': + case 'o': case 'x': case 'X': - return 0; + return h != 0 ? -1 : 0; default: return -1; } + /* + * Don't accept h and hh modifiers. They make writing + * magic entries more complicated, for very little benefit + */ case 'h': + if (h-- <= 0) + return -1; switch (*ptr++) { case 'h': + if (h-- <= 0) + return -1; switch (*ptr++) { case 'i': case 'd': case 'u': + case 'o': case 'x': case 'X': return 0; default: return -1; } + case 'i': case 'd': - return 0; + case 'u': + case 'o': + case 'x': + case 'X': + return h != 0 ? -1 : 0; default: return -1; } - - case 'i': +#endif case 'c': + return h != 2 ? -1 : 0; + case 'i': case 'd': case 'u': + case 'o': case 'x': case 'X': +#ifdef STRICT_FORMAT + return h != 0 ? -1 : 0; +#else return 0; - +#endif default: return -1; } @@ -2198,7 +2466,7 @@ check_format(struct magic_set *ms, struct magic *m) } ptr++; - if (check_format_type(ptr, file_formats[m->type]) == -1) { + if (check_format_type(ptr, m->type) == -1) { /* * TODO: this error message is unhelpful if the format * string is not one character long @@ -2245,6 +2513,16 @@ getvalue(struct magic_set *ms, struct magic *m, const char **p, int action) m->value.s); return -1; } + if (m->type == FILE_REGEX) { + file_regex_t rx; + int rc = file_regcomp(&rx, m->value.s, REG_EXTENDED); + if (rc) { + if (ms->flags & MAGIC_CHECK) + file_regerror(&rx, rc, ms); + } + file_regfree(&rx); + return rc ? -1 : 0; + } return 0; case FILE_FLOAT: case FILE_BEFLOAT: @@ -2545,6 +2823,28 @@ eatsize(const char **p) } /* + * handle a buffer containing a compiled file. + */ +private struct magic_map * +apprentice_buf(struct magic_set *ms, struct magic *buf, size_t len) +{ + struct magic_map *map; + + if ((map = CAST(struct magic_map *, calloc(1, sizeof(*map)))) == NULL) { + file_oomem(ms, sizeof(*map)); + return NULL; + } + map->len = len; + map->p = buf; + map->type = MAP_TYPE_USER; + if (check_buffer(ms, map, "buffer") != 0) { + apprentice_unmap(map); + return NULL; + } + return map; +} + +/* * handle a compiled file. */ @@ -2553,12 +2853,8 @@ apprentice_map(struct magic_set *ms, const char *fn) { int fd; struct stat st; - uint32_t *ptr; - uint32_t version, entries, nentries; - int needsbyteswap; char *dbname = NULL; struct magic_map *map; - size_t i; fd = -1; if ((map = CAST(struct magic_map *, calloc(1, sizeof(*map)))) == NULL) { @@ -2577,8 +2873,9 @@ apprentice_map(struct magic_set *ms, const char *fn) file_error(ms, errno, "cannot stat `%s'", dbname); goto error; } - if (st.st_size < 8) { - file_error(ms, 0, "file `%s' is too small", dbname); + if (st.st_size < 8 || st.st_size > MAXMAGIC_SIZE) { + file_error(ms, 0, "file `%s' is too %s", dbname, + st.st_size < 8 ? "small" : "large"); goto error; } @@ -2589,6 +2886,7 @@ apprentice_map(struct magic_set *ms, const char *fn) file_error(ms, errno, "cannot map `%s'", dbname); goto error; } + map->type = MAP_TYPE_MMAP; #else if ((map->p = CAST(void *, malloc(map->len))) == NULL) { file_oomem(ms, map->len); @@ -2598,16 +2896,39 @@ apprentice_map(struct magic_set *ms, const char *fn) file_badread(ms); goto error; } - map->len = 0; + map->type = MAP_TYPE_MALLOC; #define RET 1 #endif (void)close(fd); fd = -1; + + if (check_buffer(ms, map, dbname) != 0) + goto error; + + free(dbname); + return map; + +error: + if (fd != -1) + (void)close(fd); + apprentice_unmap(map); + free(dbname); + return NULL; +} + +private int +check_buffer(struct magic_set *ms, struct magic_map *map, const char *dbname) +{ + uint32_t *ptr; + uint32_t entries, nentries; + uint32_t version; + int i, needsbyteswap; + ptr = CAST(uint32_t *, map->p); if (*ptr != MAGICNO) { if (swap4(*ptr) != MAGICNO) { file_error(ms, 0, "bad magic in `%s'", dbname); - goto error; + return -1; } needsbyteswap = 1; } else @@ -2620,14 +2941,14 @@ apprentice_map(struct magic_set *ms, const char *fn) file_error(ms, 0, "File %s supports only version %d magic " "files. `%s' is version %d", VERSION, VERSIONNO, dbname, version); - goto error; + return -1; } - entries = (uint32_t)(st.st_size / sizeof(struct magic)); - if ((off_t)(entries * sizeof(struct magic)) != st.st_size) { - file_error(ms, 0, "Size of `%s' %llu is not a multiple of %zu", - dbname, (unsigned long long)st.st_size, - sizeof(struct magic)); - goto error; + entries = (uint32_t)(map->len / sizeof(struct magic)); + if ((entries * sizeof(struct magic)) != map->len) { + file_error(ms, 0, "Size of `%s' %" SIZE_T_FORMAT "u is not " + "a multiple of %" SIZE_T_FORMAT "u", + dbname, map->len, sizeof(struct magic)); + return -1; } map->magic[0] = CAST(struct magic *, map->p) + 1; nentries = 0; @@ -2643,26 +2964,14 @@ apprentice_map(struct magic_set *ms, const char *fn) if (entries != nentries + 1) { file_error(ms, 0, "Inconsistent entries in `%s' %u != %u", dbname, entries, nentries + 1); - goto error; + return -1; } if (needsbyteswap) for (i = 0; i < MAGIC_SETS; i++) byteswap(map->magic[i], map->nmagic[i]); - free(dbname); - return map; - -error: - if (fd != -1) - (void)close(fd); - apprentice_unmap(map); - free(dbname); - return NULL; + return 0; } -private const uint32_t ar[] = { - MAGICNO, VERSIONNO -}; - /* * handle an mmaped file. */ @@ -2676,6 +2985,10 @@ apprentice_compile(struct magic_set *ms, struct magic_map *map, const char *fn) char *dbname; int rv = -1; uint32_t i; + union { + struct magic m; + uint32_t h[2 + MAGIC_SETS]; + } hdr; dbname = mkdbname(ms, fn, 1); @@ -2687,24 +3000,16 @@ apprentice_compile(struct magic_set *ms, struct magic_map *map, const char *fn) file_error(ms, errno, "cannot open `%s'", dbname); goto out; } + memset(&hdr, 0, sizeof(hdr)); + hdr.h[0] = MAGICNO; + hdr.h[1] = VERSIONNO; + memcpy(hdr.h + 2, map->nmagic, nm); - if (write(fd, ar, sizeof(ar)) != (ssize_t)sizeof(ar)) { - file_error(ms, errno, "error writing `%s'", dbname); - goto out; - } - - if (write(fd, map->nmagic, nm) != (ssize_t)nm) { + if (write(fd, &hdr, sizeof(hdr)) != (ssize_t)sizeof(hdr)) { file_error(ms, errno, "error writing `%s'", dbname); goto out; } - assert(nm + sizeof(ar) < m); - - if (lseek(fd, (off_t)m, SEEK_SET) != (off_t)m) { - file_error(ms, errno, "error seeking `%s'", dbname); - goto out; - } - for (i = 0; i < MAGIC_SETS; i++) { len = m * map->nmagic[i]; if (write(fd, map->magic[i], len) != (ssize_t)len) { diff --git a/src/ascmagic.c b/src/ascmagic.c index 000c9de..78a6dbb 100644 --- a/src/ascmagic.c +++ b/src/ascmagic.c @@ -35,7 +35,7 @@ #include "file.h" #ifndef lint -FILE_RCSID("@(#)$File: ascmagic.c,v 1.85 2012/08/09 16:33:15 christos Exp $") +FILE_RCSID("@(#)$File: ascmagic.c,v 1.91 2014/11/28 02:46:39 christos Exp $") #endif /* lint */ #include "magic.h" @@ -72,7 +72,7 @@ file_ascmagic(struct magic_set *ms, const unsigned char *buf, size_t nbytes, int text) { unichar *ubuf = NULL; - size_t ulen; + size_t ulen = 0; int rv = 1; const char *code = NULL; @@ -147,7 +147,8 @@ file_ascmagic_with_encoding(struct magic_set *ms, const unsigned char *buf, == NULL) goto done; if ((rv = file_softmagic(ms, utf8_buf, - (size_t)(utf8_end - utf8_buf), TEXTTEST, text)) == 0) + (size_t)(utf8_end - utf8_buf), 0, NULL, + TEXTTEST, text)) == 0) rv = -1; } @@ -211,6 +212,7 @@ file_ascmagic_with_encoding(struct magic_set *ms, const unsigned char *buf, case 0: if (file_printf(ms, ", ") == -1) goto done; + break; case -1: goto done; default: @@ -35,7 +35,7 @@ #include "file.h" #ifndef lint -FILE_RCSID("@(#)$File: cdf.c,v 1.52 2013/02/18 15:40:59 christos Exp $") +FILE_RCSID("@(#)$File: cdf.c,v 1.69 2014/12/04 15:56:46 christos Exp $") #endif #include <assert.h> @@ -73,6 +73,8 @@ static union { #define CDF_TOLE8(x) ((uint64_t)(NEED_SWAP ? _cdf_tole8(x) : (uint64_t)(x))) #define CDF_TOLE4(x) ((uint32_t)(NEED_SWAP ? _cdf_tole4(x) : (uint32_t)(x))) #define CDF_TOLE2(x) ((uint16_t)(NEED_SWAP ? _cdf_tole2(x) : (uint16_t)(x))) +#define CDF_TOLE(x) (sizeof(x) == 2 ? CDF_TOLE2(x) : (sizeof(x) == 4 ? \ + CDF_TOLE4(x) : CDF_TOLE8(x))) #define CDF_GETUINT32(x, y) cdf_getuint32(x, y) @@ -267,13 +269,15 @@ cdf_check_stream_offset(const cdf_stream_t *sst, const cdf_header_t *h, { const char *b = (const char *)sst->sst_tab; const char *e = ((const char *)p) + tail; + size_t ss = sst->sst_dirlen < h->h_min_size_standard_stream ? + CDF_SHORT_SEC_SIZE(h) : CDF_SEC_SIZE(h); (void)&line; - if (e >= b && (size_t)(e - b) <= CDF_SEC_SIZE(h) * sst->sst_len) + if (e >= b && (size_t)(e - b) <= ss * sst->sst_len) return 0; DPRINTF(("%d: offset begin %p < end %p || %" SIZE_T_FORMAT "u" " > %" SIZE_T_FORMAT "u [%" SIZE_T_FORMAT "u %" SIZE_T_FORMAT "u]\n", line, b, e, (size_t)(e - b), - CDF_SEC_SIZE(h) * sst->sst_len, CDF_SEC_SIZE(h), sst->sst_len)); + ss * sst->sst_len, ss, sst->sst_len)); errno = EFTYPE; return -1; } @@ -296,8 +300,6 @@ cdf_read(const cdf_info_t *info, off_t off, void *buf, size_t len) if (info->i_fd == -1) return -1; - return -1; - if (pread(info->i_fd, buf, len, off) != (ssize_t)len) return -1; @@ -354,10 +356,10 @@ cdf_read_short_sector(const cdf_stream_t *sst, void *buf, size_t offs, size_t ss = CDF_SHORT_SEC_SIZE(h); size_t pos = CDF_SHORT_SEC_POS(h, id); assert(ss == len); - if (pos > CDF_SEC_SIZE(h) * sst->sst_len) { + if (pos + len > CDF_SEC_SIZE(h) * sst->sst_len) { DPRINTF(("Out of bounds read %" SIZE_T_FORMAT "u > %" SIZE_T_FORMAT "u\n", - pos, CDF_SEC_SIZE(h) * sst->sst_len)); + pos + len, CDF_SEC_SIZE(h) * sst->sst_len)); return -1; } (void)memcpy(((char *)buf) + offs, @@ -457,9 +459,16 @@ size_t cdf_count_chain(const cdf_sat_t *sat, cdf_secid_t sid, size_t size) { size_t i, j; - cdf_secid_t maxsector = (cdf_secid_t)(sat->sat_len * size); + cdf_secid_t maxsector = (cdf_secid_t)((sat->sat_len * size) + / sizeof(maxsector)); DPRINTF(("Chain:")); + if (sid == CDF_SECID_END_OF_CHAIN) { + /* 0-length chain. */ + DPRINTF((" empty\n")); + return 0; + } + for (j = i = 0; sid >= 0; i++, j++) { DPRINTF((" %d", sid)); if (j >= CDF_LOOP_LIMIT) { @@ -467,13 +476,18 @@ cdf_count_chain(const cdf_sat_t *sat, cdf_secid_t sid, size_t size) errno = EFTYPE; return (size_t)-1; } - if (sid > maxsector) { - DPRINTF(("Sector %d > %d\n", sid, maxsector)); + if (sid >= maxsector) { + DPRINTF(("Sector %d >= %d\n", sid, maxsector)); errno = EFTYPE; return (size_t)-1; } sid = CDF_TOLE4((uint32_t)sat->sat_tab[sid]); } + if (i == 0) { + DPRINTF((" none, sid: %d\n", sid)); + return (size_t)-1; + + } DPRINTF(("\n")); return i; } @@ -677,11 +691,13 @@ out: int cdf_read_short_stream(const cdf_info_t *info, const cdf_header_t *h, - const cdf_sat_t *sat, const cdf_dir_t *dir, cdf_stream_t *scn) + const cdf_sat_t *sat, const cdf_dir_t *dir, cdf_stream_t *scn, + const cdf_directory_t **root) { size_t i; const cdf_directory_t *d; + *root = NULL; for (i = 0; i < dir->dir_len; i++) if (dir->dir_tab[i].d_type == CDF_DIR_TYPE_ROOT_STORAGE) break; @@ -690,6 +706,7 @@ cdf_read_short_stream(const cdf_info_t *info, const cdf_header_t *h, if (i == dir->dir_len) goto out; d = &dir->dir_tab[i]; + *root = d; /* If the it is not there, just fake it; some docs don't have it */ if (d->d_stream_first_sector < 0) @@ -718,18 +735,27 @@ cdf_read_summary_info(const cdf_info_t *info, const cdf_header_t *h, const cdf_sat_t *sat, const cdf_sat_t *ssat, const cdf_stream_t *sst, const cdf_dir_t *dir, cdf_stream_t *scn) { + return cdf_read_user_stream(info, h, sat, ssat, sst, dir, + "\05SummaryInformation", scn); +} + +int +cdf_read_user_stream(const cdf_info_t *info, const cdf_header_t *h, + const cdf_sat_t *sat, const cdf_sat_t *ssat, const cdf_stream_t *sst, + const cdf_dir_t *dir, const char *name, cdf_stream_t *scn) +{ size_t i; const cdf_directory_t *d; - static const char name[] = "\05SummaryInformation"; + size_t name_len = strlen(name) + 1; for (i = dir->dir_len; i > 0; i--) if (dir->dir_tab[i - 1].d_type == CDF_DIR_TYPE_USER_STREAM && - cdf_namecmp(name, dir->dir_tab[i - 1].d_name, sizeof(name)) + cdf_namecmp(name, dir->dir_tab[i - 1].d_name, name_len) == 0) break; if (i == 0) { - DPRINTF(("Cannot find summary information section\n")); + DPRINTF(("Cannot find user stream `%s'\n", name)); errno = ESRCH; return -1; } @@ -798,10 +824,19 @@ cdf_read_property_info(const cdf_stream_t *sst, const cdf_header_t *h, if (cdf_check_stream_offset(sst, h, e, 0, __LINE__) == -1) goto out; for (i = 0; i < sh.sh_properties; i++) { - size_t ofs = CDF_GETUINT32(p, (i << 1) + 1); + size_t tail = (i << 1) + 1; + size_t ofs; + if (cdf_check_stream_offset(sst, h, p, tail * sizeof(uint32_t), + __LINE__) == -1) + goto out; + ofs = CDF_GETUINT32(p, tail); q = (const uint8_t *)(const void *) ((const char *)(const void *)p + ofs - 2 * sizeof(uint32_t)); + if (q < p) { + DPRINTF(("Wrapped around %p < %p\n", q, p)); + goto out; + } if (q > e) { DPRINTF(("Ran of the end %p > %p\n", q, e)); goto out; @@ -812,6 +847,10 @@ cdf_read_property_info(const cdf_stream_t *sst, const cdf_header_t *h, i, inp[i].pi_id, inp[i].pi_type, q - p, offs)); if (inp[i].pi_type & CDF_VECTOR) { nelements = CDF_GETUINT32(q, 1); + if (nelements == 0) { + DPRINTF(("CDF_VECTOR with nelements == 0\n")); + goto out; + } o = 2; } else { nelements = 1; @@ -886,7 +925,9 @@ cdf_read_property_info(const cdf_stream_t *sst, const cdf_header_t *h, } DPRINTF(("nelements = %" SIZE_T_FORMAT "u\n", nelements)); - for (j = 0; j < nelements; j++, i++) { + for (j = 0; j < nelements && i < sh.sh_properties; + j++, i++) + { uint32_t l = CDF_GETUINT32(q, o); inp[i].pi_str.s_len = l; inp[i].pi_str.s_buf = (const char *) @@ -931,7 +972,7 @@ int cdf_unpack_summary_info(const cdf_stream_t *sst, const cdf_header_t *h, cdf_summary_info_header_t *ssi, cdf_property_info_t **info, size_t *count) { - size_t i, maxcount; + size_t maxcount; const cdf_summary_info_header_t *si = CAST(const cdf_summary_info_header_t *, sst->sst_tab); const cdf_section_declaration_t *sd = @@ -946,25 +987,65 @@ cdf_unpack_summary_info(const cdf_stream_t *sst, const cdf_header_t *h, ssi->si_os = CDF_TOLE2(si->si_os); ssi->si_class = si->si_class; cdf_swap_class(&ssi->si_class); - ssi->si_count = CDF_TOLE2(si->si_count); + ssi->si_count = CDF_TOLE4(si->si_count); *count = 0; maxcount = 0; *info = NULL; - for (i = 0; i < CDF_TOLE4(si->si_count); i++) { - if (i >= CDF_LOOP_LIMIT) { - DPRINTF(("Unpack summary info loop limit")); - errno = EFTYPE; - return -1; - } - if (cdf_read_property_info(sst, h, CDF_TOLE4(sd->sd_offset), - info, count, &maxcount) == -1) { - return -1; - } - } + if (cdf_read_property_info(sst, h, CDF_TOLE4(sd->sd_offset), info, + count, &maxcount) == -1) + return -1; return 0; } +#define extract_catalog_field(f, l) \ + memcpy(&ce[i].f, b + (l), sizeof(ce[i].f)); \ + ce[i].f = CDF_TOLE(ce[i].f) + +int +cdf_unpack_catalog(const cdf_header_t *h, const cdf_stream_t *sst, + cdf_catalog_t **cat) +{ + size_t ss = sst->sst_dirlen < h->h_min_size_standard_stream ? + CDF_SHORT_SEC_SIZE(h) : CDF_SEC_SIZE(h); + const char *b = CAST(const char *, sst->sst_tab); + const char *eb = b + ss * sst->sst_len; + size_t nr, i, k; + cdf_catalog_entry_t *ce; + uint16_t reclen; + const uint16_t *np; + + for (nr = 0; b < eb; nr++) { + memcpy(&reclen, b, sizeof(reclen)); + reclen = CDF_TOLE2(reclen); + if (reclen == 0) + break; + b += reclen; + } + *cat = CAST(cdf_catalog_t *, + malloc(sizeof(cdf_catalog_t) + nr * sizeof(*ce))); + (*cat)->cat_num = nr; + ce = (*cat)->cat_e; + b = CAST(const char *, sst->sst_tab); + for (i = 0; i < nr; i++) { + extract_catalog_field(ce_namlen, 0); + extract_catalog_field(ce_num, 2); + extract_catalog_field(ce_timestamp, 6); + reclen = ce[i].ce_namlen; + ce[i].ce_namlen = + sizeof(ce[i].ce_name) / sizeof(ce[i].ce_name[0]) - 1; + if (ce[i].ce_namlen > reclen - 14) + ce[i].ce_namlen = reclen - 14; + np = CAST(const uint16_t *, (b + 16)); + for (k = 0; k < ce[i].ce_namlen; k++) { + ce[i].ce_name[k] = np[k]; + CDF_TOLE2(ce[i].ce_name[k]); + } + ce[i].ce_name[ce[i].ce_namlen] = 0; + b += reclen; + } + return 0; +} int cdf_print_classid(char *buf, size_t buflen, const cdf_classid_t *id) @@ -1048,6 +1129,15 @@ cdf_print_elapsed_time(char *buf, size_t bufsiz, cdf_timestamp_t ts) return len; } +char * +cdf_u16tos8(char *buf, size_t len, const uint16_t *p) +{ + size_t i; + for (i = 0; i < len && p[i]; i++) + buf[i] = (char)p[i]; + buf[i] = '\0'; + return buf; +} #ifdef CDF_DEBUG void @@ -1073,7 +1163,7 @@ cdf_dump_header(const cdf_header_t *h) for (i = 0; i < __arraycount(h->h_master_sat); i++) { if (h->h_master_sat[i] == CDF_SECID_FREE) break; - (void)fprintf(stderr, "%35.35s[%.3zu] = %d\n", + (void)fprintf(stderr, "%35.35s[%.3" SIZE_T_FORMAT "u] = %d\n", "master_sat", i, h->h_master_sat[i]); } } @@ -1140,6 +1230,7 @@ cdf_dump_dir(const cdf_info_t *info, const cdf_header_t *h, "user stream", "lockbytes", "property", "root storage" }; for (i = 0; i < dir->dir_len; i++) { + char buf[26]; d = &dir->dir_tab[i]; for (j = 0; j < sizeof(name); j++) name[j] = (char)CDF_TOLE2(d->d_name[j]); @@ -1155,9 +1246,10 @@ cdf_dump_dir(const cdf_info_t *info, const cdf_header_t *h, (void)fprintf(stderr, "Right child: %d\n", d->d_right_child); (void)fprintf(stderr, "Flags: 0x%x\n", d->d_flags); cdf_timestamp_to_timespec(&ts, d->d_created); - (void)fprintf(stderr, "Created %s", cdf_ctime(&ts.tv_sec)); + (void)fprintf(stderr, "Created %s", cdf_ctime(&ts.tv_sec, buf)); cdf_timestamp_to_timespec(&ts, d->d_modified); - (void)fprintf(stderr, "Modified %s", cdf_ctime(&ts.tv_sec)); + (void)fprintf(stderr, "Modified %s", + cdf_ctime(&ts.tv_sec, buf)); (void)fprintf(stderr, "Stream %d\n", d->d_stream_first_sector); (void)fprintf(stderr, "Size %d\n", d->d_size); switch (d->d_type) { @@ -1235,9 +1327,10 @@ cdf_dump_property_info(const cdf_property_info_t *info, size_t count) cdf_print_elapsed_time(buf, sizeof(buf), tp); (void)fprintf(stderr, "timestamp %s\n", buf); } else { + char buf[26]; cdf_timestamp_to_timespec(&ts, tp); (void)fprintf(stderr, "timestamp %s", - cdf_ctime(&ts.tv_sec)); + cdf_ctime(&ts.tv_sec, buf)); } break; case CDF_CLIPBOARD: @@ -1265,7 +1358,7 @@ cdf_dump_summary_info(const cdf_header_t *h, const cdf_stream_t *sst) return; (void)fprintf(stderr, "Endian: %x\n", ssi.si_byte_order); (void)fprintf(stderr, "Os Version %d.%d\n", ssi.si_os_version & 0xff, - ssi.si_os_version >> 8); + ssi.si_os_version >> 8); (void)fprintf(stderr, "Os %d\n", ssi.si_os); cdf_print_classid(buf, sizeof(buf), &ssi.si_class); (void)fprintf(stderr, "Class %s\n", buf); @@ -1274,6 +1367,27 @@ cdf_dump_summary_info(const cdf_header_t *h, const cdf_stream_t *sst) free(info); } + +void +cdf_dump_catalog(const cdf_header_t *h, const cdf_stream_t *sst) +{ + cdf_catalog_t *cat; + cdf_unpack_catalog(h, sst, &cat); + const cdf_catalog_entry_t *ce = cat->cat_e; + struct timespec ts; + char tbuf[64], sbuf[256]; + size_t i; + + printf("Catalog:\n"); + for (i = 0; i < cat->cat_num; i++) { + cdf_timestamp_to_timespec(&ts, ce[i].ce_timestamp); + printf("\t%d %s %s", ce[i].ce_num, + cdf_u16tos8(sbuf, ce[i].ce_namlen, ce[i].ce_name), + cdf_ctime(&ts.tv_sec, tbuf)); + } + free(cat); +} + #endif #ifdef TEST @@ -1286,6 +1400,7 @@ main(int argc, char *argv[]) cdf_stream_t sst, scn; cdf_dir_t dir; cdf_info_t info; + const cdf_directory_t *root; if (argc < 2) { (void)fprintf(stderr, "Usage: %s <filename>\n", getprogname()); @@ -1319,7 +1434,8 @@ main(int argc, char *argv[]) if (cdf_read_dir(&info, &h, &sat, &dir) == -1) err(1, "Cannot read dir"); - if (cdf_read_short_stream(&info, &h, &sat, &dir, &sst) == -1) + if (cdf_read_short_stream(&info, &h, &sat, &dir, &sst, &root) + == -1) err(1, "Cannot read short stream"); #ifdef CDF_DEBUG cdf_dump_stream(&h, &sst); @@ -1332,9 +1448,17 @@ main(int argc, char *argv[]) if (cdf_read_summary_info(&info, &h, &sat, &ssat, &sst, &dir, &scn) == -1) - err(1, "Cannot read summary info"); + warn("Cannot read summary info"); +#ifdef CDF_DEBUG + else + cdf_dump_summary_info(&h, &scn); +#endif + if (cdf_read_catalog(&info, &h, &sat, &ssat, &sst, &dir, + &scn) == -1) + warn("Cannot read catalog"); #ifdef CDF_DEBUG - cdf_dump_summary_info(&h, &scn); + else + cdf_dump_catalog(&h, &scn); #endif (void)close(info.i_fd); @@ -267,6 +267,19 @@ typedef struct { size_t i_len; } cdf_info_t; + +typedef struct { + uint16_t ce_namlen; + uint32_t ce_num; + uint64_t ce_timestamp; + uint16_t ce_name[256]; +} cdf_catalog_entry_t; + +typedef struct { + size_t cat_num; + cdf_catalog_entry_t cat_e[0]; +} cdf_catalog_t; + struct timespec; int cdf_timestamp_to_timespec(struct timespec *, cdf_timestamp_t); int cdf_timespec_to_timestamp(cdf_timestamp_t *, const struct timespec *); @@ -294,14 +307,26 @@ int cdf_read_dir(const cdf_info_t *, const cdf_header_t *, const cdf_sat_t *, int cdf_read_ssat(const cdf_info_t *, const cdf_header_t *, const cdf_sat_t *, cdf_sat_t *); int cdf_read_short_stream(const cdf_info_t *, const cdf_header_t *, - const cdf_sat_t *, const cdf_dir_t *, cdf_stream_t *); + const cdf_sat_t *, const cdf_dir_t *, cdf_stream_t *, + const cdf_directory_t **); int cdf_read_property_info(const cdf_stream_t *, const cdf_header_t *, uint32_t, cdf_property_info_t **, size_t *, size_t *); +int cdf_read_user_stream(const cdf_info_t *, const cdf_header_t *, + const cdf_sat_t *, const cdf_sat_t *, const cdf_stream_t *, + const cdf_dir_t *, const char *, cdf_stream_t *); +#define cdf_read_catalog(info, header, sat, ssat, stream, dir, scn) \ + cdf_read_user_stream(info, header, sat, ssat, stream, dir, "Catalog", \ + scn) +#define cdf_read_encrypted_package(info, header, sat, ssat, stream, dir, scn) \ + cdf_read_user_stream(info, header, sat, ssat, stream, dir, \ + "EncryptedPackage", scn) int cdf_read_summary_info(const cdf_info_t *, const cdf_header_t *, const cdf_sat_t *, const cdf_sat_t *, const cdf_stream_t *, const cdf_dir_t *, cdf_stream_t *); int cdf_unpack_summary_info(const cdf_stream_t *, const cdf_header_t *, cdf_summary_info_header_t *, cdf_property_info_t **, size_t *); +int cdf_unpack_catalog(const cdf_header_t *, const cdf_stream_t *, + cdf_catalog_t **); int cdf_print_classid(char *, size_t, const cdf_classid_t *); int cdf_print_property_name(char *, size_t, uint32_t); int cdf_print_elapsed_time(char *, size_t, cdf_timestamp_t); @@ -309,6 +334,7 @@ uint16_t cdf_tole2(uint16_t); uint32_t cdf_tole4(uint32_t); uint64_t cdf_tole8(uint64_t); char *cdf_ctime(const time_t *, char *); +char *cdf_u16tos8(char *, size_t, const uint16_t *); #ifdef CDF_DEBUG void cdf_dump_header(const cdf_header_t *); @@ -319,6 +345,7 @@ void cdf_dump_dir(const cdf_info_t *, const cdf_header_t *, const cdf_sat_t *, const cdf_sat_t *, const cdf_stream_t *, const cdf_dir_t *); void cdf_dump_property_info(const cdf_property_info_t *, size_t); void cdf_dump_summary_info(const cdf_header_t *, const cdf_stream_t *); +void cdf_dump_catalog(const cdf_header_t *, const cdf_stream_t *); #endif diff --git a/src/cdf_time.c b/src/cdf_time.c index 674e1a4..1e572de 100644 --- a/src/cdf_time.c +++ b/src/cdf_time.c @@ -27,7 +27,7 @@ #include "file.h" #ifndef lint -FILE_RCSID("@(#)$File: cdf_time.c,v 1.12 2012/05/15 17:14:36 christos Exp $") +FILE_RCSID("@(#)$File: cdf_time.c,v 1.15 2014/05/14 23:15:42 christos Exp $") #endif #include <time.h> @@ -117,7 +117,7 @@ cdf_timestamp_to_timespec(struct timespec *ts, cdf_timestamp_t t) tm.tm_hour = (int)(t % 24); t /= 24; - // XXX: Approx + /* XXX: Approx */ tm.tm_year = (int)(CDF_BASE_YEAR + (t / 365)); rdays = cdf_getdays(tm.tm_year); @@ -171,12 +171,13 @@ cdf_ctime(const time_t *sec, char *buf) char *ptr = ctime_r(sec, buf); if (ptr != NULL) return buf; - (void)snprintf(buf, 26, "*Bad* 0x%16.16llx\n", (long long)*sec); + (void)snprintf(buf, 26, "*Bad* 0x%16.16" INT64_T_FORMAT "x\n", + (long long)*sec); return buf; } -#ifdef TEST +#ifdef TEST_TIME int main(int argc, char *argv[]) { diff --git a/src/compress.c b/src/compress.c index 084970b..e968bb4 100644 --- a/src/compress.c +++ b/src/compress.c @@ -35,7 +35,7 @@ #include "file.h" #ifndef lint -FILE_RCSID("@(#)$File: compress.c,v 1.70 2012/11/07 17:54:48 christos Exp $") +FILE_RCSID("@(#)$File: compress.c,v 1.77 2014/12/12 16:33:01 christos Exp $") #endif #include "magic.h" @@ -45,7 +45,8 @@ FILE_RCSID("@(#)$File: compress.c,v 1.70 2012/11/07 17:54:48 christos Exp $") #endif #include <string.h> #include <errno.h> -#ifndef __MINGW32__ +#include <signal.h> +#if !defined(__MINGW32__) && !defined(WIN32) #include <sys/ioctl.h> #endif #ifdef HAVE_SYS_WAIT_H @@ -80,6 +81,7 @@ private const struct { { "LZIP", 4, { "lzip", "-cdq", NULL }, 1 }, { "\3757zXZ\0",6,{ "xz", "-cd", NULL }, 1 }, /* XZ Utils */ { "LRZI", 4, { "lrzip", "-dqo-", NULL }, 1 }, /* LRZIP */ + { "\004\"M\030", 4, { "lz4", "-cd", NULL }, 1 }, /* LZ4 */ }; #define NODATA ((size_t)~0) @@ -102,10 +104,12 @@ file_zmagic(struct magic_set *ms, int fd, const char *name, size_t i, nsz; int rv = 0; int mime = ms->flags & MAGIC_MIME; + sig_t osigpipe; if ((ms->flags & MAGIC_COMPRESS) == 0) return 0; + osigpipe = signal(SIGPIPE, SIG_IGN); for (i = 0; i < ncompr; i++) { if (nbytes < compr[i].maglen) continue; @@ -121,19 +125,18 @@ file_zmagic(struct magic_set *ms, int fd, const char *name, if (file_printf(ms, mime ? " compressed-encoding=" : " (") == -1) goto error; + if (file_buffer(ms, -1, NULL, buf, nbytes) == -1) + goto error; + if (!mime && file_printf(ms, ")") == -1) + goto error; } - if ((mime == 0 || mime & MAGIC_MIME_ENCODING) && - file_buffer(ms, -1, NULL, buf, nbytes) == -1) - goto error; - - if (!mime && file_printf(ms, ")") == -1) - goto error; rv = 1; break; } } error: + (void)signal(SIGPIPE, osigpipe); free(newbuf); ms->flags |= MAGIC_COMPRESS; return rv; @@ -378,6 +381,7 @@ uncompressbuf(struct magic_set *ms, int fd, size_t method, const unsigned char *old, unsigned char **newch, size_t n) { int fdin[2], fdout[2]; + int status; ssize_t r; pid_t pid; @@ -460,7 +464,17 @@ uncompressbuf(struct magic_set *ms, int fd, size_t method, /*NOTREACHED*/ default: /* parent */ - break; + if (wait(&status) == -1) { +#ifdef DEBUG + (void)fprintf(stderr, + "Wait failed (%s)\n", + strerror(errno)); +#endif + exit(1); + } + exit(WIFEXITED(status) ? + WEXITSTATUS(status) : 1); + /*NOTREACHED*/ } (void) close(fdin[1]); fdin[1] = -1; @@ -471,7 +485,7 @@ uncompressbuf(struct magic_set *ms, int fd, size_t method, (void)fprintf(stderr, "Malloc failed (%s)\n", strerror(errno)); #endif - n = 0; + n = NODATA; goto err; } if ((r = sread(fdout[0], *newch, HOWMANY, 0)) <= 0) { @@ -480,8 +494,8 @@ uncompressbuf(struct magic_set *ms, int fd, size_t method, strerror(errno)); #endif free(*newch); - n = 0; - newch[0] = '\0'; + n = NODATA; + *newch = NULL; goto err; } else { n = r; @@ -492,12 +506,24 @@ err: if (fdin[1] != -1) (void) close(fdin[1]); (void) close(fdout[0]); -#ifdef WNOHANG - while (waitpid(pid, NULL, WNOHANG) != -1) - continue; -#else - (void)wait(NULL); + if (wait(&status) == -1) { +#ifdef DEBUG + (void)fprintf(stderr, "Wait failed (%s)\n", + strerror(errno)); #endif + n = NODATA; + } else if (!WIFEXITED(status)) { +#ifdef DEBUG + (void)fprintf(stderr, "Child not exited (0x%x)\n", + status); +#endif + } else if (WEXITSTATUS(status) != 0) { +#ifdef DEBUG + (void)fprintf(stderr, "Child exited (0x%d)\n", + WEXITSTATUS(status)); +#endif + } + (void) close(fdin[0]); return n; diff --git a/src/elfclass.h b/src/elfclass.h index 010958a..5360b0b 100644 --- a/src/elfclass.h +++ b/src/elfclass.h @@ -32,39 +32,51 @@ swap = (u.c[sizeof(int32_t) - 1] + 1) != elfhdr.e_ident[EI_DATA]; type = elf_getu16(swap, elfhdr.e_type); + notecount = ms->elf_notes_max; switch (type) { #ifdef ELFCORE case ET_CORE: + phnum = elf_getu16(swap, elfhdr.e_phnum); + if (phnum > ms->elf_phnum_max) + return toomany(ms, "program headers", phnum); flags |= FLAGS_IS_CORE; if (dophn_core(ms, clazz, swap, fd, - (off_t)elf_getu(swap, elfhdr.e_phoff), - elf_getu16(swap, elfhdr.e_phnum), + (off_t)elf_getu(swap, elfhdr.e_phoff), phnum, (size_t)elf_getu16(swap, elfhdr.e_phentsize), - fsize, &flags) == -1) + fsize, &flags, ¬ecount) == -1) return -1; break; #endif case ET_EXEC: case ET_DYN: + phnum = elf_getu16(swap, elfhdr.e_phnum); + if (phnum > ms->elf_phnum_max) + return toomany(ms, "program", phnum); + shnum = elf_getu16(swap, elfhdr.e_shnum); + if (shnum > ms->elf_shnum_max) + return toomany(ms, "section", shnum); if (dophn_exec(ms, clazz, swap, fd, - (off_t)elf_getu(swap, elfhdr.e_phoff), - elf_getu16(swap, elfhdr.e_phnum), + (off_t)elf_getu(swap, elfhdr.e_phoff), phnum, (size_t)elf_getu16(swap, elfhdr.e_phentsize), - fsize, &flags, elf_getu16(swap, elfhdr.e_shnum)) - == -1) + fsize, shnum, &flags, ¬ecount) == -1) return -1; /*FALLTHROUGH*/ case ET_REL: + shnum = elf_getu16(swap, elfhdr.e_shnum); + if (shnum > ms->elf_shnum_max) + return toomany(ms, "section headers", shnum); if (doshn(ms, clazz, swap, fd, - (off_t)elf_getu(swap, elfhdr.e_shoff), - elf_getu16(swap, elfhdr.e_shnum), + (off_t)elf_getu(swap, elfhdr.e_shoff), shnum, (size_t)elf_getu16(swap, elfhdr.e_shentsize), - fsize, &flags, elf_getu16(swap, elfhdr.e_machine), - (int)elf_getu16(swap, elfhdr.e_shstrndx)) == -1) + fsize, elf_getu16(swap, elfhdr.e_machine), + (int)elf_getu16(swap, elfhdr.e_shstrndx), + &flags, ¬ecount) == -1) return -1; break; default: break; } + if (notecount == 0) + return toomany(ms, "notes", ms->elf_notes_max); return 1; diff --git a/src/encoding.c b/src/encoding.c index dee57a6..c1b23cc 100644 --- a/src/encoding.c +++ b/src/encoding.c @@ -35,7 +35,7 @@ #include "file.h" #ifndef lint -FILE_RCSID("@(#)$File: encoding.c,v 1.7 2012/01/24 19:02:02 christos Exp $") +FILE_RCSID("@(#)$File: encoding.c,v 1.10 2014/09/11 12:08:52 christos Exp $") #endif /* lint */ #include "magic.h" @@ -72,13 +72,17 @@ file_encoding(struct magic_set *ms, const unsigned char *buf, size_t nbytes, uni unsigned char *nbuf = NULL; *type = "text"; - mlen = (nbytes + 1) * sizeof(nbuf[0]); - if ((nbuf = CAST(unsigned char *, calloc((size_t)1, mlen))) == NULL) { + *ulen = 0; + *code = "unknown"; + *code_mime = "binary"; + + mlen = (nbytes + 1) * sizeof((*ubuf)[0]); + if ((*ubuf = CAST(unichar *, calloc((size_t)1, mlen))) == NULL) { file_oomem(ms, mlen); goto done; } - mlen = (nbytes + 1) * sizeof((*ubuf)[0]); - if ((*ubuf = CAST(unichar *, calloc((size_t)1, mlen))) == NULL) { + mlen = (nbytes + 1) * sizeof(nbuf[0]); + if ((nbuf = CAST(unsigned char *, calloc((size_t)1, mlen))) == NULL) { file_oomem(ms, mlen); goto done; } @@ -93,7 +97,6 @@ file_encoding(struct magic_set *ms, const unsigned char *buf, size_t nbytes, uni *code_mime = "utf-8"; } else if (file_looks_utf8(buf, nbytes, *ubuf, ulen) > 1) { DPRINTF(("utf8 %" SIZE_T_FORMAT "u\n", *ulen)); - *code = "UTF-8 Unicode (with BOM)"; *code = "UTF-8 Unicode"; *code_mime = "utf-8"; } else if ((ucs_type = looks_ucs16(buf, nbytes, *ubuf, ulen)) != 0) { @@ -32,7 +32,7 @@ #include "file.h" #ifndef lint -FILE_RCSID("@(#)$File: file.c,v 1.149 2013/01/07 18:20:19 christos Exp $") +FILE_RCSID("@(#)$File: file.c,v 1.160 2014/12/16 23:18:40 christos Exp $") #endif /* lint */ #include "magic.h" @@ -54,9 +54,6 @@ FILE_RCSID("@(#)$File: file.c,v 1.149 2013/01/07 18:20:19 christos Exp $") #ifdef HAVE_UNISTD_H #include <unistd.h> /* for read() */ #endif -#ifdef HAVE_LOCALE_H -#include <locale.h> -#endif #ifdef HAVE_WCHAR_H #include <wchar.h> #endif @@ -71,9 +68,9 @@ int getopt_long(int argc, char * const *argv, const char *optstring, const struc #endif #ifdef S_IFLNK -#define FILE_FLAGS "-bchikLlNnprsvz0" +#define FILE_FLAGS "-bcEhikLlNnprsvz0" #else -#define FILE_FLAGS "-bciklNnprsvz0" +#define FILE_FLAGS "-bcEiklNnprsvz0" #endif # define USAGE \ @@ -101,7 +98,7 @@ private const struct option long_options[] = { #undef OPT_LONGONLY {0, 0, NULL, 0} }; -#define OPTSTRING "bcCde:f:F:hiklLm:nNprsvz0" +#define OPTSTRING "bcCde:Ef:F:hiklLm:nNpP:rsvz0" private const struct { const char *name; @@ -119,6 +116,18 @@ private const struct { { "tokens", MAGIC_NO_CHECK_TOKENS }, /* OBSOLETE: ignored for backwards compatibility */ }; +private struct { + const char *name; + int tag; + size_t value; +} pm[] = { + { "indir", MAGIC_PARAM_INDIR_MAX, 0 }, + { "name", MAGIC_PARAM_NAME_MAX, 0 }, + { "elf_phnum", MAGIC_PARAM_ELF_PHNUM_MAX, 0 }, + { "elf_shnum", MAGIC_PARAM_ELF_SHNUM_MAX, 0 }, + { "elf_notes", MAGIC_PARAM_ELF_NOTES_MAX, 0 }, +}; + private char *progname; /* used throughout */ private void usage(void); @@ -128,6 +137,8 @@ private void help(void); private int unwrap(struct magic_set *, const char *); private int process(struct magic_set *ms, const char *, int); private struct magic_set *load(const char *, int); +private void setparam(const char *); +private void applyparam(magic_t); /* @@ -145,7 +156,9 @@ main(int argc, char *argv[]) const char *magicfile = NULL; /* where the magic is */ /* makes islower etc work for other langs */ +#ifdef HAVE_SETLOCALE (void)setlocale(LC_CTYPE, ""); +#endif #ifdef __EMX__ /* sh-like wildcard expansion! Shouldn't hurt at least ... */ @@ -194,6 +207,9 @@ main(int argc, char *argv[]) case 'd': flags |= MAGIC_DEBUG|MAGIC_CHECK; break; + case 'E': + flags |= MAGIC_ERROR; + break; case 'e': for (i = 0; i < sizeof(nv) / sizeof(nv[0]); i++) if (strcmp(nv[i].name, optarg) == 0) @@ -240,9 +256,13 @@ main(int argc, char *argv[]) flags |= MAGIC_PRESERVE_ATIME; break; #endif + case 'P': + setparam(optarg); + break; case 'r': flags |= MAGIC_RAW; break; + break; case 's': flags |= MAGIC_DEVICES; break; @@ -295,6 +315,8 @@ main(int argc, char *argv[]) strerror(errno)); return 1; } + + switch(action) { case FILE_CHECK: c = magic_check(magic, magicfile); @@ -318,7 +340,7 @@ main(int argc, char *argv[]) if (magic == NULL) if ((magic = load(magicfile, flags)) == NULL) return 1; - break; + applyparam(magic); } if (optind == argc) { @@ -348,6 +370,41 @@ main(int argc, char *argv[]) return e; } +private void +applyparam(magic_t magic) +{ + size_t i; + + for (i = 0; i < __arraycount(pm); i++) { + if (pm[i].value == 0) + continue; + if (magic_setparam(magic, pm[i].tag, &pm[i].value) == -1) { + (void)fprintf(stderr, "%s: Can't set %s %s\n", progname, + pm[i].name, strerror(errno)); + exit(1); + } + } +} + +private void +setparam(const char *p) +{ + size_t i; + char *s; + + if ((s = strchr(p, '=')) == NULL) + goto badparm; + + for (i = 0; i < __arraycount(pm); i++) { + if (strncmp(p, pm[i].name, s - p) != 0) + continue; + pm[i].value = atoi(s + 1); + return; + } +badparm: + (void)fprintf(stderr, "%s: Unknown param %s\n", progname, p); + exit(1); +} private struct magic_set * /*ARGSUSED*/ @@ -465,8 +522,11 @@ file_mbswidth(const char *s) * is always right */ width++; - } else - width += wcwidth(nextchar); + } else { + int w = wcwidth(nextchar); + if (w > 0) + width += w; + } s += bytesconsumed, n -= bytesconsumed; } @@ -27,7 +27,7 @@ */ /* * file.h - definitions for file(1) program - * @(#)$File: file.h,v 1.144 2013/02/18 15:40:59 christos Exp $ + * @(#)$File: file.h,v 1.164 2015/01/01 17:07:34 christos Exp $ */ #ifndef __file_h__ @@ -64,7 +64,9 @@ #include <regex.h> #include <time.h> #include <sys/types.h> +#ifndef WIN32 #include <sys/param.h> +#endif /* Do this here and now, because struct stat gets re-defined on solaris */ #include <sys/stat.h> #include <stdarg.h> @@ -83,7 +85,7 @@ #define private static -#if HAVE_VISIBILITY +#if HAVE_VISIBILITY && !defined(WIN32) #define public __attribute__ ((__visibility__("default"))) #ifndef protected #define protected __attribute__ ((__visibility__("hidden"))) @@ -133,7 +135,7 @@ #define MAXstring 64 /* max len of "string" types */ #define MAGICNO 0xF11E041C -#define VERSIONNO 10 +#define VERSIONNO 12 #define FILE_MAGICSIZE 248 #define FILE_LOAD 0 @@ -222,7 +224,8 @@ struct magic { #define FILE_BEQWDATE 44 #define FILE_NAME 45 #define FILE_USE 46 -#define FILE_NAMES_SIZE 47 /* size of array to contain all names */ +#define FILE_CLEAR 47 +#define FILE_NAMES_SIZE 48 /* size of array to contain all names */ #define IS_STRING(t) \ ((t) == FILE_STRING || \ @@ -231,9 +234,9 @@ struct magic { (t) == FILE_LESTRING16 || \ (t) == FILE_REGEX || \ (t) == FILE_SEARCH || \ + (t) == FILE_INDIRECT || \ (t) == FILE_NAME || \ - (t) == FILE_USE || \ - (t) == FILE_DEFAULT) + (t) == FILE_USE) #define FILE_FMT_NONE 0 #define FILE_FMT_NUM 1 /* "cduxXi" */ @@ -321,6 +324,7 @@ struct magic { #define PSTRING_2_LE BIT(9) #define PSTRING_4_BE BIT(10) #define PSTRING_4_LE BIT(11) +#define REGEX_LINE_COUNT BIT(11) #define PSTRING_LEN \ (PSTRING_1_BE|PSTRING_2_LE|PSTRING_2_BE|PSTRING_4_LE|PSTRING_4_BE) #define PSTRING_LENGTH_INCLUDES_ITSELF BIT(12) @@ -343,6 +347,8 @@ struct magic { #define STRING_IGNORE_CASE (STRING_IGNORE_LOWERCASE|STRING_IGNORE_UPPERCASE) #define STRING_DEFAULT_RANGE 100 +#define INDIRECT_RELATIVE BIT(0) +#define CHAR_INDIRECT_RELATIVE 'r' /* list of magic entries */ struct mlist { @@ -400,6 +406,16 @@ struct magic_set { /* FIXME: Make the string dynamically allocated so that e.g. strings matched in files can be longer than MAXstring */ union VALUETYPE ms_value; /* either number or string */ + uint16_t indir_max; + uint16_t name_max; + uint16_t elf_shnum_max; + uint16_t elf_phnum_max; + uint16_t elf_notes_max; +#define FILE_INDIR_MAX 15 +#define FILE_NAME_MAX 30 +#define FILE_ELF_SHNUM_MAX 32768 +#define FILE_ELF_PHNUM_MAX 128 +#define FILE_ELF_NOTES_MAX 256 }; /* Type for Unicode characters */ @@ -415,7 +431,8 @@ 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_pipe2file(struct magic_set *, int, const void *, size_t); -protected int file_vprintf(struct magic_set *, const char *, va_list); +protected int file_vprintf(struct magic_set *, const char *, va_list) + __attribute__((__format__(__printf__, 2, 0))); protected size_t file_printedlen(const struct magic_set *); protected int file_replace(struct magic_set *, const char *, const char *); protected int file_printf(struct magic_set *, const char *, ...) @@ -438,8 +455,10 @@ protected int file_encoding(struct magic_set *, const unsigned char *, size_t, unichar **, size_t *, const char **, const char **, const char **); protected int file_is_tar(struct magic_set *, const unsigned char *, size_t); protected int file_softmagic(struct magic_set *, const unsigned char *, size_t, - int, int); + uint16_t, uint16_t *, int, int); protected int file_apprentice(struct magic_set *, const char *, int); +protected int buffer_apprentice(struct magic_set *, struct magic **, + size_t *, size_t); protected int file_magicfind(struct magic_set *, const char *, struct mlist *); protected uint64_t file_signextend(struct magic_set *, struct magic *, uint64_t); @@ -462,11 +481,43 @@ protected int file_looks_utf8(const unsigned char *, size_t, unichar *, size_t *); protected size_t file_pstring_length_size(const struct magic *); protected size_t file_pstring_get_length(const struct magic *, const char *); +protected char * file_printable(char *, size_t, const char *); #ifdef __EMX__ protected int file_os2_apptype(struct magic_set *, const char *, const void *, size_t); #endif /* __EMX__ */ +#if defined(HAVE_LOCALE_H) +#include <locale.h> +#endif +#if defined(HAVE_XLOCALE_H) +#include <xlocale.h> +#endif + +typedef struct { + const char *pat; +#if defined(HAVE_NEWLOCALE) && defined(HAVE_USELOCALE) && defined(HAVE_FREELOCALE) +#define USE_C_LOCALE + locale_t old_lc_ctype; + locale_t c_lc_ctype; +#endif + int rc; + regex_t rx; +} file_regex_t; + +protected int file_regcomp(file_regex_t *, const char *, int); +protected int file_regexec(file_regex_t *, const char *, size_t, regmatch_t *, + int); +protected void file_regfree(file_regex_t *); +protected void file_regerror(file_regex_t *, int, struct magic_set *); + +typedef struct { + char *buf; + uint32_t offset; +} file_pushbuf_t; + +protected file_pushbuf_t *file_push_buffer(struct magic_set *); +protected char *file_pop_buffer(struct magic_set *, file_pushbuf_t *); #ifndef COMPILE_ONLY extern const char *file_names[]; @@ -491,18 +542,21 @@ ssize_t pread(int, void *, size_t, off_t); int vasprintf(char **, const char *, va_list); #endif #ifndef HAVE_ASPRINTF -int asprintf(char **ptr, const char *format_string, ...); +int asprintf(char **, const char *, ...); #endif #ifndef HAVE_STRLCPY -size_t strlcpy(char *dst, const char *src, size_t siz); +size_t strlcpy(char *, const char *, size_t); #endif #ifndef HAVE_STRLCAT -size_t strlcat(char *dst, const char *src, size_t siz); +size_t strlcat(char *, const char *, size_t); +#endif +#ifndef HAVE_STRCASESTR +char *strcasestr(const char *, const char *); #endif #ifndef HAVE_GETLINE -ssize_t getline(char **dst, size_t *len, FILE *fp); -ssize_t getdelim(char **dst, size_t *len, int delimiter, FILE *fp); +ssize_t getline(char **, size_t *, FILE *); +ssize_t getdelim(char **, size_t *, int, FILE *); #endif #ifndef HAVE_CTIME_R char *ctime_r(const time_t *, char *); @@ -510,6 +564,10 @@ char *ctime_r(const time_t *, char *); #ifndef HAVE_ASCTIME_R char *asctime_r(const struct tm *, char *); #endif +#ifndef HAVE_FMTCHECK +const char *fmtcheck(const char *, const char *) + __attribute__((__format_arg__(2))); +#endif #if defined(HAVE_MMAP) && defined(HAVE_SYS_MMAN_H) && !defined(QUICK) #define QUICK diff --git a/src/file_opts.h b/src/file_opts.h index 60096ca..3286ac6 100644 --- a/src/file_opts.h +++ b/src/file_opts.h @@ -32,8 +32,8 @@ OPT_LONGONLY("apple", 0, " output the Apple CREATOR/TYPE\n") OPT_LONGONLY("mime-type", 0, " output the MIME type\n") OPT_LONGONLY("mime-encoding", 0, " output the MIME encoding\n") OPT('k', "keep-going", 0, " don't stop at the first match\n") -#ifdef S_IFLNK OPT('l', "list", 0, " list magic strength\n") +#ifdef S_IFLNK OPT('L', "dereference", 0, " follow symlinks (default)\n") OPT('h', "no-dereference", 0, " don't follow symlinks\n") #endif @@ -43,6 +43,12 @@ OPT('0', "print0", 0, " terminate filenames with ASCII NUL\n") #if defined(HAVE_UTIME) || defined(HAVE_UTIMES) OPT('p', "preserve-date", 0, " preserve access times on files\n") #endif +OPT('P', "parameter", 0, " set file engine parameter limits\n" + " indir 15 recursion limit for indirection\n" + " name 30 use limit for name/use magic\n" + " elf_notes 256 max ELF notes processed\n" + " elf_phnum 128 max ELF prog sections processed\n" + " elf_shnum 32768 max ELF sections processed\n") OPT('r', "raw", 0, " don't translate unprintable chars to \\ooo\n") OPT('s', "special-files", 0, " treat special (block/char devices) files as\n" " ordinary ones\n") diff --git a/src/fmtcheck.c b/src/fmtcheck.c new file mode 100644 index 0000000..0fc7038 --- /dev/null +++ b/src/fmtcheck.c @@ -0,0 +1,234 @@ +/* $NetBSD: fmtcheck.c,v 1.8 2008/04/28 20:22:59 martin Exp $ */ + +/*- + * Copyright (c) 2000 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code was contributed to The NetBSD Foundation by Allen Briggs. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "file.h" + +#include <stdio.h> +#include <string.h> +#include <ctype.h> + +enum __e_fmtcheck_types { + FMTCHECK_START, + FMTCHECK_SHORT, + FMTCHECK_INT, + FMTCHECK_LONG, + FMTCHECK_QUAD, + FMTCHECK_SHORTPOINTER, + FMTCHECK_INTPOINTER, + FMTCHECK_LONGPOINTER, + FMTCHECK_QUADPOINTER, + FMTCHECK_DOUBLE, + FMTCHECK_LONGDOUBLE, + FMTCHECK_STRING, + FMTCHECK_WIDTH, + FMTCHECK_PRECISION, + FMTCHECK_DONE, + FMTCHECK_UNKNOWN +}; +typedef enum __e_fmtcheck_types EFT; + +#define RETURN(pf,f,r) do { \ + *(pf) = (f); \ + return r; \ + } /*NOTREACHED*/ /*CONSTCOND*/ while (0) + +static EFT +get_next_format_from_precision(const char **pf) +{ + int sh, lg, quad, longdouble; + const char *f; + + sh = lg = quad = longdouble = 0; + + f = *pf; + switch (*f) { + case 'h': + f++; + sh = 1; + break; + case 'l': + f++; + if (!*f) RETURN(pf,f,FMTCHECK_UNKNOWN); + if (*f == 'l') { + f++; + quad = 1; + } else { + lg = 1; + } + break; + case 'q': + f++; + quad = 1; + break; + case 'L': + f++; + longdouble = 1; + break; + default: + break; + } + if (!*f) RETURN(pf,f,FMTCHECK_UNKNOWN); + if (strchr("diouxX", *f)) { + if (longdouble) + RETURN(pf,f,FMTCHECK_UNKNOWN); + if (lg) + RETURN(pf,f,FMTCHECK_LONG); + if (quad) + RETURN(pf,f,FMTCHECK_QUAD); + RETURN(pf,f,FMTCHECK_INT); + } + if (*f == 'n') { + if (longdouble) + RETURN(pf,f,FMTCHECK_UNKNOWN); + if (sh) + RETURN(pf,f,FMTCHECK_SHORTPOINTER); + if (lg) + RETURN(pf,f,FMTCHECK_LONGPOINTER); + if (quad) + RETURN(pf,f,FMTCHECK_QUADPOINTER); + RETURN(pf,f,FMTCHECK_INTPOINTER); + } + if (strchr("DOU", *f)) { + if (sh + lg + quad + longdouble) + RETURN(pf,f,FMTCHECK_UNKNOWN); + RETURN(pf,f,FMTCHECK_LONG); + } + if (strchr("eEfg", *f)) { + if (longdouble) + RETURN(pf,f,FMTCHECK_LONGDOUBLE); + if (sh + lg + quad) + RETURN(pf,f,FMTCHECK_UNKNOWN); + RETURN(pf,f,FMTCHECK_DOUBLE); + } + if (*f == 'c') { + if (sh + lg + quad + longdouble) + RETURN(pf,f,FMTCHECK_UNKNOWN); + RETURN(pf,f,FMTCHECK_INT); + } + if (*f == 's') { + if (sh + lg + quad + longdouble) + RETURN(pf,f,FMTCHECK_UNKNOWN); + RETURN(pf,f,FMTCHECK_STRING); + } + if (*f == 'p') { + if (sh + lg + quad + longdouble) + RETURN(pf,f,FMTCHECK_UNKNOWN); + RETURN(pf,f,FMTCHECK_LONG); + } + RETURN(pf,f,FMTCHECK_UNKNOWN); + /*NOTREACHED*/ +} + +static EFT +get_next_format_from_width(const char **pf) +{ + const char *f; + + f = *pf; + if (*f == '.') { + f++; + if (*f == '*') { + RETURN(pf,f,FMTCHECK_PRECISION); + } + /* eat any precision (empty is allowed) */ + while (isdigit((unsigned char)*f)) f++; + if (!*f) RETURN(pf,f,FMTCHECK_UNKNOWN); + } + RETURN(pf,f,get_next_format_from_precision(pf)); + /*NOTREACHED*/ +} + +static EFT +get_next_format(const char **pf, EFT eft) +{ + int infmt; + const char *f; + + if (eft == FMTCHECK_WIDTH) { + (*pf)++; + return get_next_format_from_width(pf); + } else if (eft == FMTCHECK_PRECISION) { + (*pf)++; + return get_next_format_from_precision(pf); + } + + f = *pf; + infmt = 0; + while (!infmt) { + f = strchr(f, '%'); + if (f == NULL) + RETURN(pf,f,FMTCHECK_DONE); + f++; + if (!*f) + RETURN(pf,f,FMTCHECK_UNKNOWN); + if (*f != '%') + infmt = 1; + else + f++; + } + + /* Eat any of the flags */ + while (*f && (strchr("#0- +", *f))) + f++; + + if (*f == '*') { + RETURN(pf,f,FMTCHECK_WIDTH); + } + /* eat any width */ + while (isdigit((unsigned char)*f)) f++; + if (!*f) { + RETURN(pf,f,FMTCHECK_UNKNOWN); + } + + RETURN(pf,f,get_next_format_from_width(pf)); + /*NOTREACHED*/ +} + +const char * +fmtcheck(const char *f1, const char *f2) +{ + const char *f1p, *f2p; + EFT f1t, f2t; + + if (!f1) return f2; + + f1p = f1; + f1t = FMTCHECK_START; + f2p = f2; + f2t = FMTCHECK_START; + while ((f1t = get_next_format(&f1p, f1t)) != FMTCHECK_DONE) { + if (f1t == FMTCHECK_UNKNOWN) + return f2; + f2t = get_next_format(&f2p, f2t); + if (f1t != f2t) + return f2; + } + return f1; +} diff --git a/src/fsmagic.c b/src/fsmagic.c index dd4f0a0..1e8fd74 100644 --- a/src/fsmagic.c +++ b/src/fsmagic.c @@ -32,7 +32,7 @@ #include "file.h" #ifndef lint -FILE_RCSID("@(#)$File: fsmagic.c,v 1.66 2013/01/11 19:46:55 christos Exp $") +FILE_RCSID("@(#)$File: fsmagic.c,v 1.75 2014/12/04 15:56:46 christos Exp $") #endif /* lint */ #include "magic.h" @@ -53,7 +53,11 @@ FILE_RCSID("@(#)$File: fsmagic.c,v 1.66 2013/01/11 19:46:55 christos Exp $") #ifdef major /* Might be defined in sys/types.h. */ # define HAVE_MAJOR #endif - +#ifdef WIN32 +# define WIN32_LEAN_AND_MEAN +# include <windows.h> +#endif + #ifndef HAVE_MAJOR # define major(dev) (((dev) >> 8) & 0xff) # define minor(dev) ((dev) & 0xff) @@ -71,10 +75,10 @@ bad_link(struct magic_set *ms, int err, char *buf) else if (!mime) { if (ms->flags & MAGIC_ERROR) { file_error(ms, err, - "broken symbolic link to `%s'", buf); + "broken symbolic link to %s", buf); return -1; } - if (file_printf(ms, "broken symbolic link to `%s'", buf) == -1) + if (file_printf(ms, "broken symbolic link to %s", buf) == -1) return -1; } return 1; @@ -123,6 +127,35 @@ file_fsmagic(struct magic_set *ms, const char *fn, struct stat *sb) #endif ret = stat(fn, sb); /* don't merge into if; see "ret =" above */ +#ifdef WIN32 + { + HANDLE hFile = CreateFile((LPCSTR)fn, 0, FILE_SHARE_DELETE | + FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, + NULL); + if (hFile != INVALID_HANDLE_VALUE) { + /* + * Stat failed, but we can still open it - assume it's + * a block device, if nothing else. + */ + if (ret) { + sb->st_mode = S_IFBLK; + ret = 0; + } + switch (GetFileType(hFile)) { + case FILE_TYPE_CHAR: + sb->st_mode |= S_IFCHR; + sb->st_mode &= ~S_IFREG; + break; + case FILE_TYPE_PIPE: + sb->st_mode |= S_IFIFO; + sb->st_mode &= ~S_IFREG; + break; + } + CloseHandle(hFile); + } + } +#endif + if (ret) { if (ms->flags & MAGIC_ERROR) { file_error(ms, errno, "cannot stat `%s'", fn); @@ -131,8 +164,7 @@ file_fsmagic(struct magic_set *ms, const char *fn, struct stat *sb) if (file_printf(ms, "cannot open `%s' (%s)", fn, strerror(errno)) == -1) return -1; - ms->event_flags |= EVENT_HAD_ERR; - return -1; + return 0; } ret = 1; @@ -169,13 +201,15 @@ file_fsmagic(struct magic_set *ms, const char *fn, struct stat *sb) * like ordinary files. Otherwise, just report that they * are block special files and go on to the next file. */ - if ((ms->flags & MAGIC_DEVICES) != 0) + if ((ms->flags & MAGIC_DEVICES) != 0) { + ret = 0; break; + } if (mime) { if (handle_mime(ms, mime, "chardevice") == -1) return -1; } else { -#ifdef HAVE_STAT_ST_RDEV +#ifdef HAVE_STRUCT_STAT_ST_RDEV # ifdef dv_unit if (file_printf(ms, "%scharacter special (%d/%d/%d)", COMMA, major(sb->st_rdev), dv_unit(sb->st_rdev), @@ -201,13 +235,15 @@ file_fsmagic(struct magic_set *ms, const char *fn, struct stat *sb) * like ordinary files. Otherwise, just report that they * are block special files and go on to the next file. */ - if ((ms->flags & MAGIC_DEVICES) != 0) + if ((ms->flags & MAGIC_DEVICES) != 0) { + ret = 0; break; + } if (mime) { if (handle_mime(ms, mime, "blockdevice") == -1) return -1; } else { -#ifdef HAVE_STAT_ST_RDEV +#ifdef HAVE_STRUCT_STAT_ST_RDEV # ifdef dv_unit if (file_printf(ms, "%sblock special (%d/%d/%d)", COMMA, major(sb->st_rdev), dv_unit(sb->st_rdev), @@ -316,7 +352,7 @@ file_fsmagic(struct magic_set *ms, const char *fn, struct stat *sb) if (mime) { if (handle_mime(ms, mime, "symlink") == -1) return -1; - } else if (file_printf(ms, "%ssymbolic link to `%s'", + } else if (file_printf(ms, "%ssymbolic link to %s", COMMA, buf) == -1) return -1; } @@ -363,7 +399,7 @@ file_fsmagic(struct magic_set *ms, const char *fn, struct stat *sb) /*NOTREACHED*/ } - if (!mime && did) { + if (!mime && did && ret == 0) { if (file_printf(ms, " ") == -1) return -1; } diff --git a/src/funcs.c b/src/funcs.c index 7fc0e5c..a60ccaa 100644 --- a/src/funcs.c +++ b/src/funcs.c @@ -27,10 +27,11 @@ #include "file.h" #ifndef lint -FILE_RCSID("@(#)$File: funcs.c,v 1.61 2012/10/30 23:11:51 christos Exp $") +FILE_RCSID("@(#)$File: funcs.c,v 1.79 2014/12/16 20:52:49 christos Exp $") #endif /* lint */ #include "magic.h" +#include <assert.h> #include <stdarg.h> #include <stdlib.h> #include <string.h> @@ -58,6 +59,8 @@ file_vprintf(struct magic_set *ms, const char *fmt, va_list ap) int len; char *buf, *newstr; + if (ms->event_flags & EVENT_HAD_ERR) + return 0; len = vasprintf(&buf, fmt, ap); if (len < 0) goto out; @@ -93,6 +96,7 @@ file_printf(struct magic_set *ms, const char *fmt, ...) * error - print best error message possible */ /*VARARGS*/ +__attribute__((__format__(__printf__, 3, 0))) private void file_error_core(struct magic_set *ms, int error, const char *f, va_list va, size_t lineno) @@ -166,27 +170,22 @@ file_buffer(struct magic_set *ms, int fd, const char *inname __attribute__ ((unu size_t ulen; const char *code = NULL; const char *code_mime = "binary"; - const char *type = NULL; - - + const char *type = "application/octet-stream"; + const char *def = "data"; + const char *ftype = NULL; if (nb == 0) { - if ((!mime || (mime & MAGIC_MIME_TYPE)) && - file_printf(ms, mime ? "application/x-empty" : - "empty") == -1) - return -1; - return 1; + def = "empty"; + type = "application/x-empty"; + goto simple; } else if (nb == 1) { - if ((!mime || (mime & MAGIC_MIME_TYPE)) && - file_printf(ms, mime ? "application/octet-stream" : - "very short file (no magic)") == -1) - return -1; - return 1; + def = "very short file (no magic)"; + goto simple; } if ((ms->flags & MAGIC_NO_CHECK_ENCODING) == 0) { looks_text = file_encoding(ms, ubuf, nb, &u8buf, &ulen, - &code, &code_mime, &type); + &code, &code_mime, &ftype); } #ifdef __EMX__ @@ -207,7 +206,7 @@ file_buffer(struct magic_set *ms, int fd, const char *inname __attribute__ ((unu if ((m = file_zmagic(ms, fd, inname, ubuf, nb)) != 0) { if ((ms->flags & MAGIC_DEBUG) != 0) (void)fprintf(stderr, "zmagic %d\n", m); - goto done; + goto done_encoding; } #endif /* Check if we have a tar file */ @@ -228,7 +227,7 @@ file_buffer(struct magic_set *ms, int fd, const char *inname __attribute__ ((unu /* try soft magic tests */ if ((ms->flags & MAGIC_NO_CHECK_SOFT) == 0) - if ((m = file_softmagic(ms, ubuf, nb, BINTEST, + if ((m = file_softmagic(ms, ubuf, nb, 0, NULL, BINTEST, looks_text)) != 0) { if ((ms->flags & MAGIC_DEBUG) != 0) (void)fprintf(stderr, "softmagic %d\n", m); @@ -261,25 +260,13 @@ file_buffer(struct magic_set *ms, int fd, const char *inname __attribute__ ((unu (void)fprintf(stderr, "ascmagic %d\n", m); goto done; } - - /* try to discover text encoding */ - if ((ms->flags & MAGIC_NO_CHECK_ENCODING) == 0) { - if (looks_text == 0) - if ((m = file_ascmagic_with_encoding( ms, ubuf, - nb, u8buf, ulen, code, type, looks_text)) - != 0) { - if ((ms->flags & MAGIC_DEBUG) != 0) - (void)fprintf(stderr, - "ascmagic/enc %d\n", m); - goto done; - } - } } +simple: /* give up */ m = 1; if ((!mime || (mime & MAGIC_MIME_TYPE)) && - file_printf(ms, mime ? "application/octet-stream" : "data") == -1) { + file_printf(ms, "%s", mime ? type : def) == -1) { rv = -1; } done: @@ -290,6 +277,9 @@ file_buffer(struct magic_set *ms, int fd, const char *inname __attribute__ ((unu if (file_printf(ms, "%s", code_mime) == -1) rv = -1; } +#if HAVE_FORK + done_encoding: +#endif free(u8buf); if (rv) return rv; @@ -436,26 +426,133 @@ file_printedlen(const struct magic_set *ms) protected int file_replace(struct magic_set *ms, const char *pat, const char *rep) { - regex_t rx; - int rc; + file_regex_t rx; + int rc, rv = -1; - rc = regcomp(&rx, pat, REG_EXTENDED); + rc = file_regcomp(&rx, pat, REG_EXTENDED); if (rc) { - char errmsg[512]; - (void)regerror(rc, &rx, errmsg, sizeof(errmsg)); - file_magerror(ms, "regex error %d, (%s)", rc, errmsg); - return -1; + file_regerror(&rx, rc, ms); } else { regmatch_t rm; int nm = 0; - while (regexec(&rx, ms->o.buf, 1, &rm, 0) == 0) { + while (file_regexec(&rx, ms->o.buf, 1, &rm, 0) == 0) { ms->o.buf[rm.rm_so] = '\0'; if (file_printf(ms, "%s%s", rep, rm.rm_eo != 0 ? ms->o.buf + rm.rm_eo : "") == -1) - return -1; + goto out; nm++; } - regfree(&rx); - return nm; + rv = nm; + } +out: + file_regfree(&rx); + return rv; +} + +protected int +file_regcomp(file_regex_t *rx, const char *pat, int flags) +{ +#ifdef USE_C_LOCALE + rx->c_lc_ctype = newlocale(LC_CTYPE_MASK, "C", 0); + assert(rx->c_lc_ctype != NULL); + rx->old_lc_ctype = uselocale(rx->c_lc_ctype); + assert(rx->old_lc_ctype != NULL); +#endif + rx->pat = pat; + + return rx->rc = regcomp(&rx->rx, pat, flags); +} + +protected int +file_regexec(file_regex_t *rx, const char *str, size_t nmatch, + regmatch_t* pmatch, int eflags) +{ + assert(rx->rc == 0); + return regexec(&rx->rx, str, nmatch, pmatch, eflags); +} + +protected void +file_regfree(file_regex_t *rx) +{ + if (rx->rc == 0) + regfree(&rx->rx); +#ifdef USE_C_LOCALE + (void)uselocale(rx->old_lc_ctype); + freelocale(rx->c_lc_ctype); +#endif +} + +protected void +file_regerror(file_regex_t *rx, int rc, struct magic_set *ms) +{ + char errmsg[512]; + + (void)regerror(rc, &rx->rx, errmsg, sizeof(errmsg)); + file_magerror(ms, "regex error %d for `%s', (%s)", rc, rx->pat, + errmsg); +} + +protected file_pushbuf_t * +file_push_buffer(struct magic_set *ms) +{ + file_pushbuf_t *pb; + + if (ms->event_flags & EVENT_HAD_ERR) + return NULL; + + if ((pb = (CAST(file_pushbuf_t *, malloc(sizeof(*pb))))) == NULL) + return NULL; + + pb->buf = ms->o.buf; + pb->offset = ms->offset; + + ms->o.buf = NULL; + ms->offset = 0; + + return pb; +} + +protected char * +file_pop_buffer(struct magic_set *ms, file_pushbuf_t *pb) +{ + char *rbuf; + + if (ms->event_flags & EVENT_HAD_ERR) { + free(pb->buf); + free(pb); + return NULL; + } + + rbuf = ms->o.buf; + + ms->o.buf = pb->buf; + ms->offset = pb->offset; + + free(pb); + return rbuf; +} + +/* + * convert string to ascii printable format. + */ +protected char * +file_printable(char *buf, size_t bufsiz, const char *str) +{ + char *ptr, *eptr; + const unsigned char *s = (const unsigned char *)str; + + for (ptr = buf, eptr = ptr + bufsiz - 1; ptr < eptr && *s; s++) { + if (isprint(*s)) { + *ptr++ = *s; + continue; + } + if (ptr >= eptr - 3) + break; + *ptr++ = '\\'; + *ptr++ = ((*s >> 6) & 7) + '0'; + *ptr++ = ((*s >> 3) & 7) + '0'; + *ptr++ = ((*s >> 0) & 7) + '0'; } + *ptr = '\0'; + return buf; } diff --git a/src/getline.c b/src/getline.c index 99cd150..b00de01 100644 --- a/src/getline.c +++ b/src/getline.c @@ -1,4 +1,4 @@ -/* $NetBSD: fgetln.c,v 1.9 2008/04/29 06:53:03 martin Exp $ */ +/* $NetBSD: getline.c,v 1.2 2014/09/16 17:23:50 christos Exp $ */ /*- * Copyright (c) 2011 The NetBSD Foundation, Inc. @@ -52,10 +52,14 @@ getdelim(char **buf, size_t *bufsiz, int delimiter, FILE *fp) for (ptr = *buf, eptr = *buf + *bufsiz;;) { int c = fgetc(fp); if (c == -1) { - if (feof(fp)) - return ptr == *buf ? -1 : ptr - *buf; - else - return -1; + if (feof(fp)) { + ssize_t diff = (ssize_t)(ptr - *buf); + if (diff != 0) { + *ptr = '\0'; + return diff; + } + } + return -1; } *ptr++ = c; if (c == delimiter) { @@ -76,7 +80,7 @@ getdelim(char **buf, size_t *bufsiz, int delimiter, FILE *fp) } } -ssize_t +public ssize_t getline(char **buf, size_t *bufsiz, FILE *fp) { return getdelim(buf, bufsiz, '\n', fp); @@ -93,7 +97,7 @@ main(int argc, char *argv[]) size_t n = 0; while ((len = getline(&p, &n, stdin)) != -1) - (void)printf("%zd %s", len, p); + (void)printf("%" SIZE_T_FORMAT "d %s", len, p); free(p); return 0; } diff --git a/src/magic.c b/src/magic.c index bc382e8..d16f8c6 100644 --- a/src/magic.c +++ b/src/magic.c @@ -33,7 +33,7 @@ #include "file.h" #ifndef lint -FILE_RCSID("@(#)$File: magic.c,v 1.78 2013/01/07 18:20:19 christos Exp $") +FILE_RCSID("@(#)$File: magic.c,v 1.91 2014/12/16 23:18:40 christos Exp $") #endif /* lint */ #include "magic.h" @@ -126,8 +126,10 @@ out: free(hmagicpath); return MAGIC; #else - char *hmagicp = hmagicpath; + char *hmagicp; char *tmppath = NULL; + LPTSTR dllpath; + hmagicpath = NULL; #define APPENDPATH() \ do { \ @@ -172,7 +174,7 @@ out: } /* Third, try to get magic file relative to dll location */ - LPTSTR dllpath = malloc(sizeof(*dllpath) * (MAX_PATH + 1)); + dllpath = malloc(sizeof(*dllpath) * (MAX_PATH + 1)); dllpath[MAX_PATH] = 0; /* just in case long path gets truncated and not null terminated */ if (GetModuleFileNameA(NULL, dllpath, MAX_PATH)){ PathRemoveFileSpecA(dllpath); @@ -220,13 +222,15 @@ magic_open(int flags) private int unreadable_info(struct magic_set *ms, mode_t md, const char *file) { - /* We cannot open it, but we were able to stat it. */ - if (access(file, W_OK) == 0) - if (file_printf(ms, "writable, ") == -1) - return -1; - if (access(file, X_OK) == 0) - if (file_printf(ms, "executable, ") == -1) - return -1; + if (file) { + /* We cannot open it, but we were able to stat it. */ + if (access(file, W_OK) == 0) + if (file_printf(ms, "writable, ") == -1) + return -1; + if (access(file, X_OK) == 0) + if (file_printf(ms, "executable, ") == -1) + return -1; + } if (S_ISREG(md)) if (file_printf(ms, "regular file, ") == -1) return -1; @@ -254,6 +258,20 @@ magic_load(struct magic_set *ms, const char *magicfile) return file_apprentice(ms, magicfile, FILE_LOAD); } +#ifndef COMPILE_ONLY +/* + * Install a set of compiled magic buffers. + */ +public int +magic_load_buffers(struct magic_set *ms, void **bufs, size_t *sizes, + size_t nbufs) +{ + if (ms == NULL) + return -1; + return buffer_apprentice(ms, (struct magic **)bufs, sizes, nbufs); +} +#endif + public int magic_compile(struct magic_set *ms, const char *magicfile) { @@ -282,7 +300,7 @@ private void close_and_restore(const struct magic_set *ms, const char *name, int fd, const struct stat *sb) { - if (fd == STDIN_FILENO) + if (fd == STDIN_FILENO || name == NULL) return; (void) close(fd); @@ -343,6 +361,10 @@ file_or_fd(struct magic_set *ms, const char *inname, int fd) struct stat sb; ssize_t nbytes = 0; /* number of bytes read from a datafile */ int ispipe = 0; + off_t pos = (off_t)-1; + + if (file_reset(ms) == -1) + goto out; /* * one extra for terminating '\0', and @@ -352,9 +374,6 @@ file_or_fd(struct magic_set *ms, const char *inname, int fd) if ((buf = CAST(unsigned char *, malloc(HOWMANY + SLOP))) == NULL) return NULL; - if (file_reset(ms) == -1) - goto done; - switch (file_fsmagic(ms, inname, &sb)) { case -1: /* error */ goto done; @@ -365,13 +384,22 @@ file_or_fd(struct magic_set *ms, const char *inname, int fd) goto done; } +#ifdef WIN32 + /* Place stdin in binary mode, so EOF (Ctrl+Z) doesn't stop early. */ + if (fd == STDIN_FILENO) + _setmode(STDIN_FILENO, O_BINARY); +#endif + if (inname == NULL) { if (fstat(fd, &sb) == 0 && S_ISFIFO(sb.st_mode)) ispipe = 1; + else + pos = lseek(fd, (off_t)0, SEEK_CUR); } else { int flags = O_RDONLY|O_BINARY; + int okstat = stat(inname, &sb) == 0; - if (stat(inname, &sb) == 0 && S_ISFIFO(sb.st_mode)) { + if (okstat && S_ISFIFO(sb.st_mode)) { #ifdef O_NONBLOCK flags |= O_NONBLOCK; #endif @@ -380,7 +408,20 @@ file_or_fd(struct magic_set *ms, const char *inname, int fd) errno = 0; if ((fd = open(inname, flags)) < 0) { - if (unreadable_info(ms, sb.st_mode, inname) == -1) +#ifdef WIN32 + /* + * Can't stat, can't open. It may have been opened in + * fsmagic, so if the user doesn't have read permission, + * allow it to say so; otherwise an error was probably + * displayed in fsmagic. + */ + if (!okstat && errno == EACCES) { + sb.st_mode = S_IFBLK; + okstat = 1; + } +#endif + if (okstat && + unreadable_info(ms, sb.st_mode, inname) == -1) goto done; rv = 0; goto done; @@ -414,8 +455,18 @@ file_or_fd(struct magic_set *ms, const char *inname, int fd) } } else { - if ((nbytes = read(fd, (char *)buf, HOWMANY)) == -1) { - file_error(ms, errno, "cannot read `%s'", inname); + /* Windows refuses to read from a big console buffer. */ + size_t howmany = +#if defined(WIN32) && HOWMANY > 8 * 1024 + _isatty(fd) ? 8 * 1024 : +#endif + HOWMANY; + if ((nbytes = read(fd, (char *)buf, howmany)) == -1) { + if (inname == NULL && fd != STDIN_FILENO) + file_error(ms, errno, "cannot read fd %d", fd); + else + file_error(ms, errno, "cannot read `%s'", + inname == NULL ? "/dev/stdin" : inname); goto done; } } @@ -426,7 +477,10 @@ file_or_fd(struct magic_set *ms, const char *inname, int fd) rv = 0; done: free(buf); + if (pos != (off_t)-1) + (void)lseek(fd, pos, SEEK_SET); close_and_restore(ms, inname, fd, &sb); +out: return rv == 0 ? file_getbuffer(ms) : NULL; } @@ -483,3 +537,53 @@ magic_version(void) { return MAGIC_VERSION; } + +public int +magic_setparam(struct magic_set *ms, int param, const void *val) +{ + switch (param) { + case MAGIC_PARAM_INDIR_MAX: + ms->indir_max = *(const size_t *)val; + return 0; + case MAGIC_PARAM_NAME_MAX: + ms->name_max = *(const size_t *)val; + return 0; + case MAGIC_PARAM_ELF_PHNUM_MAX: + ms->elf_phnum_max = *(const size_t *)val; + return 0; + case MAGIC_PARAM_ELF_SHNUM_MAX: + ms->elf_shnum_max = *(const size_t *)val; + return 0; + case MAGIC_PARAM_ELF_NOTES_MAX: + ms->elf_notes_max = *(const size_t *)val; + return 0; + default: + errno = EINVAL; + return -1; + } +} + +public int +magic_getparam(struct magic_set *ms, int param, void *val) +{ + switch (param) { + case MAGIC_PARAM_INDIR_MAX: + *(size_t *)val = ms->indir_max; + return 0; + case MAGIC_PARAM_NAME_MAX: + *(size_t *)val = ms->name_max; + return 0; + case MAGIC_PARAM_ELF_PHNUM_MAX: + *(size_t *)val = ms->elf_phnum_max; + return 0; + case MAGIC_PARAM_ELF_SHNUM_MAX: + *(size_t *)val = ms->elf_shnum_max; + return 0; + case MAGIC_PARAM_ELF_NOTES_MAX: + *(size_t *)val = ms->elf_notes_max; + return 0; + default: + errno = EINVAL; + return -1; + } +} diff --git a/src/magic.h b/src/magic.h index 59561de..721712f 100644 --- a/src/magic.h +++ b/src/magic.h @@ -65,6 +65,7 @@ MAGIC_NO_CHECK_CDF | \ MAGIC_NO_CHECK_TOKENS | \ MAGIC_NO_CHECK_ENCODING | \ + 0 \ ) /* Defined for backwards compatibility (renamed) */ @@ -74,7 +75,7 @@ #define MAGIC_NO_CHECK_FORTRAN 0x000000 /* Don't check ascii/fortran */ #define MAGIC_NO_CHECK_TROFF 0x000000 /* Don't check ascii/troff */ -#define MAGIC_VERSION 513 /* This implementation */ +#define MAGIC_VERSION 521 /* This implementation */ #ifdef __cplusplus @@ -95,11 +96,22 @@ int magic_setflags(magic_t, int); int magic_version(void); int magic_load(magic_t, const char *); +int magic_load_buffers(magic_t, void **, size_t *, size_t); + int magic_compile(magic_t, const char *); int magic_check(magic_t, const char *); int magic_list(magic_t, const char *); int magic_errno(magic_t); +#define MAGIC_PARAM_INDIR_MAX 0 +#define MAGIC_PARAM_NAME_MAX 1 +#define MAGIC_PARAM_ELF_PHNUM_MAX 2 +#define MAGIC_PARAM_ELF_SHNUM_MAX 3 +#define MAGIC_PARAM_ELF_NOTES_MAX 4 + +int magic_setparam(magic_t, int, const void *); +int magic_getparam(magic_t, int, void *); + #ifdef __cplusplus }; #endif diff --git a/src/magic.h.in b/src/magic.h.in index bb3bfe8..0d4c5ce 100644 --- a/src/magic.h.in +++ b/src/magic.h.in @@ -65,6 +65,7 @@ MAGIC_NO_CHECK_CDF | \ MAGIC_NO_CHECK_TOKENS | \ MAGIC_NO_CHECK_ENCODING | \ + 0 \ ) /* Defined for backwards compatibility (renamed) */ @@ -95,11 +96,22 @@ int magic_setflags(magic_t, int); int magic_version(void); int magic_load(magic_t, const char *); +int magic_load_buffers(magic_t, void **, size_t *, size_t); + int magic_compile(magic_t, const char *); int magic_check(magic_t, const char *); int magic_list(magic_t, const char *); int magic_errno(magic_t); +#define MAGIC_PARAM_INDIR_MAX 0 +#define MAGIC_PARAM_NAME_MAX 1 +#define MAGIC_PARAM_ELF_PHNUM_MAX 2 +#define MAGIC_PARAM_ELF_SHNUM_MAX 3 +#define MAGIC_PARAM_ELF_NOTES_MAX 4 + +int magic_setparam(magic_t, int, const void *); +int magic_getparam(magic_t, int, void *); + #ifdef __cplusplus }; #endif diff --git a/src/pread.c b/src/pread.c index 80498f7..72d3a6b 100644 --- a/src/pread.c +++ b/src/pread.c @@ -1,14 +1,23 @@ #include "file.h" #ifndef lint -FILE_RCSID("@(#)$File: pread.c,v 1.1 2013/02/18 15:40:59 christos Exp $") +FILE_RCSID("@(#)$File: pread.c,v 1.3 2014/09/15 19:11:25 christos Exp $") #endif /* lint */ #include <fcntl.h> #include <unistd.h> ssize_t -pread(int fd, void *buf, ssize_t len, off_t off) { - if (lseek(fd, off, SEEK_SET) == (off_t)-1) +pread(int fd, void *buf, size_t len, off_t off) { + off_t old; + ssize_t rv; + + if ((old = lseek(fd, off, SEEK_SET)) == -1) + return -1; + + if ((rv = read(fd, buf, len)) == -1) + return -1; + + if (lseek(fd, old, SEEK_SET) == -1) return -1; - return read(fd, buf, len); + return rv; } diff --git a/src/print.c b/src/print.c index 245bb98..fa81798 100644 --- a/src/print.c +++ b/src/print.c @@ -32,7 +32,7 @@ #include "file.h" #ifndef lint -FILE_RCSID("@(#)$File: print.c,v 1.75 2012/10/30 23:11:51 christos Exp $") +FILE_RCSID("@(#)$File: print.c,v 1.76 2013/02/26 18:25:00 christos Exp $") #endif /* lint */ #include <string.h> @@ -59,20 +59,19 @@ file_mdump(struct magic *m) if (m->flag & INDIR) { (void) fprintf(stderr, "(%s,", - /* Note: type is unsigned */ - (m->in_type < file_nnames) ? - file_names[m->in_type] : "*bad*"); + /* Note: type is unsigned */ + (m->in_type < file_nnames) ? file_names[m->in_type] : + "*bad in_type*"); if (m->in_op & FILE_OPINVERSE) (void) fputc('~', stderr); (void) fprintf(stderr, "%c%u),", - ((size_t)(m->in_op & FILE_OPS_MASK) < - SZOF(optyp)) ? - optyp[m->in_op & FILE_OPS_MASK] : '?', - m->in_offset); + ((size_t)(m->in_op & FILE_OPS_MASK) < + SZOF(optyp)) ? optyp[m->in_op & FILE_OPS_MASK] : '?', + m->in_offset); } (void) fprintf(stderr, " %s%s", (m->flag & UNSIGNED) ? "u" : "", - /* Note: type is unsigned */ - (m->type < file_nnames) ? file_names[m->type] : "*bad*"); + /* Note: type is unsigned */ + (m->type < file_nnames) ? file_names[m->type] : "*bad type"); if (m->mask_op & FILE_OPINVERSE) (void) fputc('~', stderr); @@ -135,6 +134,7 @@ file_mdump(struct magic *m) case FILE_MELONG: case FILE_BESHORT: case FILE_BELONG: + case FILE_INDIRECT: (void) fprintf(stderr, "%d", m->value.l); break; case FILE_BEQUAD: @@ -200,7 +200,7 @@ file_mdump(struct magic *m) (void) fprintf(stderr, "'%s'", m->value.s); break; default: - (void) fputs("*bad*", stderr); + (void) fprintf(stderr, "*bad type %d*", m->type); break; } } diff --git a/src/readcdf.c b/src/readcdf.c index 2034208..635a926 100644 --- a/src/readcdf.c +++ b/src/readcdf.c @@ -26,9 +26,10 @@ #include "file.h" #ifndef lint -FILE_RCSID("@(#)$File: readcdf.c,v 1.33 2012/06/20 21:52:36 christos Exp $") +FILE_RCSID("@(#)$File: readcdf.c,v 1.49 2014/12/04 15:56:46 christos Exp $") #endif +#include <assert.h> #include <stdlib.h> #include <unistd.h> #include <string.h> @@ -40,9 +41,92 @@ FILE_RCSID("@(#)$File: readcdf.c,v 1.33 2012/06/20 21:52:36 christos Exp $") #define NOTMIME(ms) (((ms)->flags & MAGIC_MIME) == 0) +static const struct nv { + const char *pattern; + const char *mime; +} app2mime[] = { + { "Word", "msword", }, + { "Excel", "vnd.ms-excel", }, + { "Powerpoint", "vnd.ms-powerpoint", }, + { "Crystal Reports", "x-rpt", }, + { "Advanced Installer", "vnd.ms-msi", }, + { "InstallShield", "vnd.ms-msi", }, + { "Microsoft Patch Compiler", "vnd.ms-msi", }, + { "NAnt", "vnd.ms-msi", }, + { "Windows Installer", "vnd.ms-msi", }, + { NULL, NULL, }, +}, name2mime[] = { + { "WordDocument", "msword", }, + { "PowerPoint", "vnd.ms-powerpoint", }, + { "DigitalSignature", "vnd.ms-msi", }, + { NULL, NULL, }, +}, name2desc[] = { + { "WordDocument", "Microsoft Office Word",}, + { "PowerPoint", "Microsoft PowerPoint", }, + { "DigitalSignature", "Microsoft Installer", }, + { NULL, NULL, }, +}; + +static const struct cv { + uint64_t clsid[2]; + const char *mime; +} clsid2mime[] = { + { + { 0x00000000000c1084ULL, 0x46000000000000c0ULL }, + "x-msi", + }, + { { 0, 0 }, + NULL, + }, +}, clsid2desc[] = { + { + { 0x00000000000c1084ULL, 0x46000000000000c0ULL }, + "MSI Installer", + }, + { { 0, 0 }, + NULL, + }, +}; + +private const char * +cdf_clsid_to_mime(const uint64_t clsid[2], const struct cv *cv) +{ + size_t i; + for (i = 0; cv[i].mime != NULL; i++) { + if (clsid[0] == cv[i].clsid[0] && clsid[1] == cv[i].clsid[1]) + return cv[i].mime; + } + return NULL; +} + +private const char * +cdf_app_to_mime(const char *vbuf, const struct nv *nv) +{ + size_t i; + const char *rv = NULL; +#ifdef USE_C_LOCALE + locale_t old_lc_ctype, c_lc_ctype; + + c_lc_ctype = newlocale(LC_CTYPE_MASK, "C", 0); + assert(c_lc_ctype != NULL); + old_lc_ctype = uselocale(c_lc_ctype); + assert(old_lc_ctype != NULL); +#endif + for (i = 0; nv[i].pattern != NULL; i++) + if (strcasestr(vbuf, nv[i].pattern) != NULL) { + rv = nv[i].mime; + break; + } +#ifdef USE_C_LOCALE + (void)uselocale(old_lc_ctype); + freelocale(c_lc_ctype); +#endif + return rv; +} + private int cdf_file_property_info(struct magic_set *ms, const cdf_property_info_t *info, - size_t count) + size_t count, const cdf_directory_t *root_storage) { size_t i; cdf_timestamp_t tp; @@ -52,6 +136,10 @@ cdf_file_property_info(struct magic_set *ms, const cdf_property_info_t *info, const char *s; int len; + if (!NOTMIME(ms) && root_storage) + str = cdf_clsid_to_mime(root_storage->d_storage_uuid, + clsid2mime); + for (i = 0; i < count; i++) { cdf_print_property_name(buf, sizeof(buf), info[i].pi_id); switch (info[i].pi_type) { @@ -92,12 +180,11 @@ cdf_file_property_info(struct magic_set *ms, const cdf_property_info_t *info, if (info[i].pi_type == CDF_LENGTH32_WSTRING) k++; s = info[i].pi_str.s_buf; - for (j = 0; j < sizeof(vbuf) && len--; - j++, s += k) { + for (j = 0; j < sizeof(vbuf) && len--; s += k) { if (*s == '\0') break; if (isprint((unsigned char)*s)) - vbuf[j] = *s; + vbuf[j++] = *s; } if (j == sizeof(vbuf)) --j; @@ -108,19 +195,11 @@ cdf_file_property_info(struct magic_set *ms, const cdf_property_info_t *info, buf, vbuf) == -1) return -1; } - } else if (info[i].pi_id == - CDF_PROPERTY_NAME_OF_APPLICATION) { - if (strstr(vbuf, "Word")) - str = "msword"; - else if (strstr(vbuf, "Excel")) - str = "vnd.ms-excel"; - else if (strstr(vbuf, "Powerpoint")) - str = "vnd.ms-powerpoint"; - else if (strstr(vbuf, - "Crystal Reports")) - str = "x-rpt"; - } - } + } else if (str == NULL && info[i].pi_id == + CDF_PROPERTY_NAME_OF_APPLICATION) { + str = cdf_app_to_mime(vbuf, app2mime); + } + } break; case CDF_FILETIME: tp = info[i].pi_tp; @@ -136,8 +215,9 @@ cdf_file_property_info(struct magic_set *ms, const cdf_property_info_t *info, char *c, *ec; cdf_timestamp_to_timespec(&ts, tp); c = cdf_ctime(&ts.tv_sec, tbuf); - if ((ec = strchr(c, '\n')) != NULL) - *ec = '\0'; + if (c != NULL && + (ec = strchr(c, '\n')) != NULL) + *ec = '\0'; if (NOTMIME(ms) && file_printf(ms, ", %s: %s", buf, c) == -1) @@ -161,9 +241,40 @@ cdf_file_property_info(struct magic_set *ms, const cdf_property_info_t *info, } private int -cdf_file_summary_info(struct magic_set *ms, const cdf_header_t *h, +cdf_file_catalog(struct magic_set *ms, const cdf_header_t *h, const cdf_stream_t *sst) { + cdf_catalog_t *cat; + size_t i; + char buf[256]; + cdf_catalog_entry_t *ce; + + if (NOTMIME(ms)) { + if (file_printf(ms, "Microsoft Thumbs.db [") == -1) + return -1; + if (cdf_unpack_catalog(h, sst, &cat) == -1) + return -1; + ce = cat->cat_e; + /* skip first entry since it has a , or paren */ + for (i = 1; i < cat->cat_num; i++) + if (file_printf(ms, "%s%s", + cdf_u16tos8(buf, ce[i].ce_namlen, ce[i].ce_name), + i == cat->cat_num - 1 ? "]" : ", ") == -1) { + free(cat); + return -1; + } + free(cat); + } else { + if (file_printf(ms, "application/CDFV2") == -1) + return -1; + } + return 1; +} + +private int +cdf_file_summary_info(struct magic_set *ms, const cdf_header_t *h, + const cdf_stream_t *sst, const cdf_directory_t *root_storage) +{ cdf_summary_info_header_t si; cdf_property_info_t *info; size_t count; @@ -173,6 +284,8 @@ cdf_file_summary_info(struct magic_set *ms, const cdf_header_t *h, return -1; if (NOTMIME(ms)) { + const char *str; + if (file_printf(ms, "Composite Document File V2 Document") == -1) return -1; @@ -200,14 +313,36 @@ cdf_file_summary_info(struct magic_set *ms, const cdf_header_t *h, return -2; break; } - } + if (root_storage) { + str = cdf_clsid_to_mime(root_storage->d_storage_uuid, + clsid2desc); + if (str) { + if (file_printf(ms, ", %s", str) == -1) + return -2; + } + } + } - m = cdf_file_property_info(ms, info, count); + m = cdf_file_property_info(ms, info, count, root_storage); free(info); return m == -1 ? -2 : m; } +#ifdef notdef +private char * +format_clsid(char *buf, size_t len, const uint64_t uuid[2]) { + snprintf(buf, len, "%.8" PRIx64 "-%.4" PRIx64 "-%.4" PRIx64 "-%.4" + PRIx64 "-%.12" PRIx64, + (uuid[0] >> 32) & (uint64_t)0x000000000ffffffffULL, + (uuid[0] >> 16) & (uint64_t)0x0000000000000ffffULL, + (uuid[0] >> 0) & (uint64_t)0x0000000000000ffffULL, + (uuid[1] >> 48) & (uint64_t)0x0000000000000ffffULL, + (uuid[1] >> 0) & (uint64_t)0x0000fffffffffffffULL); + return buf; +} +#endif + protected int file_trycdf(struct magic_set *ms, int fd, const unsigned char *buf, size_t nbytes) @@ -220,6 +355,7 @@ file_trycdf(struct magic_set *ms, int fd, const unsigned char *buf, int i; const char *expn = ""; const char *corrupt = "corrupt: "; + const cdf_directory_t *root_storage; info.i_fd = fd; info.i_buf = buf; @@ -253,19 +389,71 @@ file_trycdf(struct magic_set *ms, int fd, const unsigned char *buf, goto out2; } - if ((i = cdf_read_short_stream(&info, &h, &sat, &dir, &sst)) == -1) { + if ((i = cdf_read_short_stream(&info, &h, &sat, &dir, &sst, + &root_storage)) == -1) { expn = "Cannot read short stream"; goto out3; } #ifdef CDF_DEBUG cdf_dump_dir(&info, &h, &sat, &ssat, &sst, &dir); #endif +#ifdef notdef + if (root_storage) { + if (NOTMIME(ms)) { + char clsbuf[128]; + if (file_printf(ms, "CLSID %s, ", + format_clsid(clsbuf, sizeof(clsbuf), + root_storage->d_storage_uuid)) == -1) + return -1; + } + } +#endif + + if ((i = cdf_read_user_stream(&info, &h, &sat, &ssat, &sst, &dir, + "FileHeader", &scn)) != -1) { +#define HWP5_SIGNATURE "HWP Document File" + if (scn.sst_dirlen >= sizeof(HWP5_SIGNATURE) - 1 + && memcmp(scn.sst_tab, HWP5_SIGNATURE, + sizeof(HWP5_SIGNATURE) - 1) == 0) { + if (NOTMIME(ms)) { + if (file_printf(ms, + "Hangul (Korean) Word Processor File 5.x") == -1) + return -1; + } else { + if (file_printf(ms, "application/x-hwp") == -1) + return -1; + } + i = 1; + goto out5; + } else { + free(scn.sst_tab); + scn.sst_tab = NULL; + scn.sst_len = 0; + scn.sst_dirlen = 0; + } + } if ((i = cdf_read_summary_info(&info, &h, &sat, &ssat, &sst, &dir, &scn)) == -1) { if (errno == ESRCH) { - corrupt = expn; - expn = "No summary info"; + if ((i = cdf_read_catalog(&info, &h, &sat, &ssat, &sst, + &dir, &scn)) == -1) { + corrupt = expn; + if ((i = cdf_read_encrypted_package(&info, &h, + &sat, &ssat, &sst, &dir, &scn)) == -1) + expn = "No summary info"; + else { + expn = "Encrypted"; + i = -1; + } + goto out4; + } +#ifdef CDF_DEBUG + cdf_dump_catalog(&h, &scn); +#endif + if ((i = cdf_file_catalog(ms, &h, &scn)) + < 0) + expn = "Can't expand catalog"; } else { expn = "Cannot read summary info"; } @@ -274,30 +462,37 @@ file_trycdf(struct magic_set *ms, int fd, const unsigned char *buf, #ifdef CDF_DEBUG cdf_dump_summary_info(&h, &scn); #endif - if ((i = cdf_file_summary_info(ms, &h, &scn)) < 0) - expn = "Can't expand summary_info"; + if ((i = cdf_file_summary_info(ms, &h, &scn, root_storage)) < 0) + expn = "Can't expand summary_info"; + if (i == 0) { - const char *str = "vnd.ms-office"; + const char *str = NULL; cdf_directory_t *d; char name[__arraycount(d->d_name)]; size_t j, k; - for (j = 0; j < dir.dir_len; j++) { - d = &dir.dir_tab[j]; - for (k = 0; k < sizeof(name); k++) - name[k] = (char)cdf_tole2(d->d_name[k]); - if (strstr(name, "WordDocument") != 0) { - str = "msword"; - break; - } - if (strstr(name, "PowerPoint") != 0) { - str = "vnd.ms-powerpoint"; - break; - } + + for (j = 0; str == NULL && j < dir.dir_len; j++) { + d = &dir.dir_tab[j]; + for (k = 0; k < sizeof(name); k++) + name[k] = (char)cdf_tole2(d->d_name[k]); + str = cdf_app_to_mime(name, + NOTMIME(ms) ? name2desc : name2mime); + } + if (NOTMIME(ms)) { + if (str != NULL) { + if (file_printf(ms, "%s", str) == -1) + return -1; + i = 1; + } + } else { + if (str == NULL) + str = "vnd.ms-office"; + if (file_printf(ms, "application/%s", str) == -1) + return -1; + i = 1; } - if (file_printf(ms, "application/%s", str) == -1) - return -1; - i = 1; } +out5: free(scn.sst_tab); out4: free(sst.sst_tab); @@ -308,21 +503,20 @@ out2: out1: free(sat.sat_tab); out0: - if (i != 1) { - if (i == -1) { - if (NOTMIME(ms)) { - if (file_printf(ms, - "Composite Document File V2 Document") == -1) - return -1; - if (*expn) - if (file_printf(ms, ", %s%s", corrupt, expn) == -1) - return -1; - } else { - if (file_printf(ms, "application/CDFV2-corrupt") == -1) - return -1; - } - } - i = 1; - } + if (i == -1) { + if (NOTMIME(ms)) { + if (file_printf(ms, + "Composite Document File V2 Document") == -1) + return -1; + if (*expn) + if (file_printf(ms, ", %s%s", corrupt, expn) == -1) + return -1; + } else { + if (file_printf(ms, "application/CDFV2-%s", + *corrupt ? "corrupt" : "encrypted") == -1) + return -1; + } + i = 1; + } return i; } diff --git a/src/readelf.c b/src/readelf.c index 398056f..d159620 100644 --- a/src/readelf.c +++ b/src/readelf.c @@ -27,7 +27,7 @@ #include "file.h" #ifndef lint -FILE_RCSID("@(#)$File: readelf.c,v 1.96 2013/02/22 01:35:49 christos Exp $") +FILE_RCSID("@(#)$File: readelf.c,v 1.117 2014/12/16 23:29:42 christos Exp $") #endif #ifdef BUILTIN_ELF @@ -43,14 +43,14 @@ FILE_RCSID("@(#)$File: readelf.c,v 1.96 2013/02/22 01:35:49 christos Exp $") #ifdef ELFCORE private int dophn_core(struct magic_set *, int, int, int, off_t, int, size_t, - off_t, int *); + off_t, int *, uint16_t *); #endif private int dophn_exec(struct magic_set *, int, int, int, off_t, int, size_t, - off_t, int *, int); + off_t, int, int *, uint16_t *); private int doshn(struct magic_set *, int, int, int, off_t, int, size_t, - off_t, int *, int, int); + off_t, int, int, int *, uint16_t *); private size_t donote(struct magic_set *, void *, size_t, size_t, int, - int, size_t, int *); + int, size_t, int *, uint16_t *); #define ELF_ALIGN(a) ((((a) + align - 1) / align) * align) @@ -58,9 +58,20 @@ private size_t donote(struct magic_set *, void *, size_t, size_t, int, private uint16_t getu16(int, uint16_t); private uint32_t getu32(int, uint32_t); -#ifndef USE_ARRAY_FOR_64BIT_TYPES private uint64_t getu64(int, uint64_t); -#endif + +#define MAX_PHNUM 128 +#define MAX_SHNUM 32768 +#define SIZE_UNKNOWN ((off_t)-1) + +private int +toomany(struct magic_set *ms, const char *name, uint16_t num) +{ + if (file_printf(ms, ", too many %s (%u)", name, num + ) == -1) + return -1; + return 0; +} private uint16_t getu16(int swap, uint16_t value) @@ -102,7 +113,6 @@ getu32(int swap, uint32_t value) return value; } -#ifndef USE_ARRAY_FOR_64BIT_TYPES private uint64_t getu64(int swap, uint64_t value) { @@ -127,19 +137,10 @@ getu64(int swap, uint64_t value) } else return value; } -#endif #define elf_getu16(swap, value) getu16(swap, value) #define elf_getu32(swap, value) getu32(swap, value) -#ifdef USE_ARRAY_FOR_64BIT_TYPES -# define elf_getu64(swap, array) \ - ((swap ? ((uint64_t)elf_getu32(swap, array[0])) << 32 \ - : elf_getu32(swap, array[0])) + \ - (swap ? elf_getu32(swap, array[1]) : \ - ((uint64_t)elf_getu32(swap, array[1]) << 32))) -#else -# define elf_getu64(swap, value) getu64(swap, value) -#endif +#define elf_getu64(swap, value) getu64(swap, value) #define xsh_addr (clazz == ELFCLASS32 \ ? (void *)&sh32 \ @@ -292,15 +293,19 @@ private const char os_style_names[][8] = { "NetBSD", }; -#define FLAGS_DID_CORE 0x01 -#define FLAGS_DID_NOTE 0x02 -#define FLAGS_DID_BUILD_ID 0x04 -#define FLAGS_DID_CORE_STYLE 0x08 -#define FLAGS_IS_CORE 0x10 +#define FLAGS_DID_CORE 0x001 +#define FLAGS_DID_OS_NOTE 0x002 +#define FLAGS_DID_BUILD_ID 0x004 +#define FLAGS_DID_CORE_STYLE 0x008 +#define FLAGS_DID_NETBSD_PAX 0x010 +#define FLAGS_DID_NETBSD_MARCH 0x020 +#define FLAGS_DID_NETBSD_CMODEL 0x040 +#define FLAGS_DID_NETBSD_UNKNOWN 0x080 +#define FLAGS_IS_CORE 0x100 private int dophn_core(struct magic_set *ms, int clazz, int swap, int fd, off_t off, - int num, size_t size, off_t fsize, int *flags) + int num, size_t size, off_t fsize, int *flags, uint16_t *notecount) { Elf32_Phdr ph32; Elf64_Phdr ph64; @@ -318,13 +323,13 @@ dophn_core(struct magic_set *ms, int clazz, int swap, int fd, off_t off, * Loop through all the program headers. */ for ( ; num; num--) { - if (pread(fd, xph_addr, xph_sizeof, off) == -1) { + if (pread(fd, xph_addr, xph_sizeof, off) < (ssize_t)xph_sizeof) { file_badread(ms); return -1; } off += size; - if (xph_offset > fsize) { + if (fsize != SIZE_UNKNOWN && xph_offset > fsize) { /* Perhaps warn here */ continue; } @@ -346,7 +351,7 @@ dophn_core(struct magic_set *ms, int clazz, int swap, int fd, off_t off, if (offset >= (size_t)bufsize) break; offset = donote(ms, nbuf, offset, (size_t)bufsize, - clazz, swap, 4, flags); + clazz, swap, 4, flags, notecount); if (offset == 0) break; @@ -356,271 +361,285 @@ dophn_core(struct magic_set *ms, int clazz, int swap, int fd, off_t off, } #endif -private size_t -donote(struct magic_set *ms, void *vbuf, size_t offset, size_t size, - int clazz, int swap, size_t align, int *flags) +static void +do_note_netbsd_version(struct magic_set *ms, int swap, void *v) { - Elf32_Nhdr nh32; - Elf64_Nhdr nh64; - size_t noff, doff; -#ifdef ELFCORE - int os_style = -1; -#endif - uint32_t namesz, descsz; - unsigned char *nbuf = CAST(unsigned char *, vbuf); - - (void)memcpy(xnh_addr, &nbuf[offset], xnh_sizeof); - offset += xnh_sizeof; - - namesz = xnh_namesz; - descsz = xnh_descsz; - if ((namesz == 0) && (descsz == 0)) { - /* - * We're out of note headers. - */ - return (offset >= size) ? offset : size; - } - - if (namesz & 0x80000000) { - (void)file_printf(ms, ", bad note name size 0x%lx", - (unsigned long)namesz); - return offset; - } + uint32_t desc; + (void)memcpy(&desc, v, sizeof(desc)); + desc = elf_getu32(swap, desc); - if (descsz & 0x80000000) { - (void)file_printf(ms, ", bad note description size 0x%lx", - (unsigned long)descsz); - return offset; + if (file_printf(ms, ", for NetBSD") == -1) + return; + /* + * The version number used to be stuck as 199905, and was thus + * basically content-free. Newer versions of NetBSD have fixed + * this and now use the encoding of __NetBSD_Version__: + * + * MMmmrrpp00 + * + * M = major version + * m = minor version + * r = release ["",A-Z,Z[A-Z] but numeric] + * p = patchlevel + */ + if (desc > 100000000U) { + uint32_t ver_patch = (desc / 100) % 100; + uint32_t ver_rel = (desc / 10000) % 100; + uint32_t ver_min = (desc / 1000000) % 100; + uint32_t ver_maj = desc / 100000000; + + if (file_printf(ms, " %u.%u", ver_maj, ver_min) == -1) + return; + if (ver_rel == 0 && ver_patch != 0) { + if (file_printf(ms, ".%u", ver_patch) == -1) + return; + } else if (ver_rel != 0) { + while (ver_rel > 26) { + if (file_printf(ms, "Z") == -1) + return; + ver_rel -= 26; + } + if (file_printf(ms, "%c", 'A' + ver_rel - 1) + == -1) + return; + } } +} +static void +do_note_freebsd_version(struct magic_set *ms, int swap, void *v) +{ + uint32_t desc; - noff = offset; - doff = ELF_ALIGN(offset + namesz); + (void)memcpy(&desc, v, sizeof(desc)); + desc = elf_getu32(swap, desc); + if (file_printf(ms, ", for FreeBSD") == -1) + return; - if (offset + namesz > size) { - /* - * We're past the end of the buffer. - */ - return doff; + /* + * Contents is __FreeBSD_version, whose relation to OS + * versions is defined by a huge table in the Porter's + * Handbook. This is the general scheme: + * + * Releases: + * Mmp000 (before 4.10) + * Mmi0p0 (before 5.0) + * Mmm0p0 + * + * Development branches: + * Mmpxxx (before 4.6) + * Mmp1xx (before 4.10) + * Mmi1xx (before 5.0) + * M000xx (pre-M.0) + * Mmm1xx + * + * M = major version + * m = minor version + * i = minor version increment (491000 -> 4.10) + * p = patchlevel + * x = revision + * + * The first release of FreeBSD to use ELF by default + * was version 3.0. + */ + if (desc == 460002) { + if (file_printf(ms, " 4.6.2") == -1) + return; + } else if (desc < 460100) { + if (file_printf(ms, " %d.%d", desc / 100000, + desc / 10000 % 10) == -1) + return; + if (desc / 1000 % 10 > 0) + if (file_printf(ms, ".%d", desc / 1000 % 10) == -1) + return; + if ((desc % 1000 > 0) || (desc % 100000 == 0)) + if (file_printf(ms, " (%d)", desc) == -1) + return; + } else if (desc < 500000) { + if (file_printf(ms, " %d.%d", desc / 100000, + desc / 10000 % 10 + desc / 1000 % 10) == -1) + return; + if (desc / 100 % 10 > 0) { + if (file_printf(ms, " (%d)", desc) == -1) + return; + } else if (desc / 10 % 10 > 0) { + if (file_printf(ms, ".%d", desc / 10 % 10) == -1) + return; + } + } else { + if (file_printf(ms, " %d.%d", desc / 100000, + desc / 1000 % 100) == -1) + return; + if ((desc / 100 % 10 > 0) || + (desc % 100000 / 100 == 0)) { + if (file_printf(ms, " (%d)", desc) == -1) + return; + } else if (desc / 10 % 10 > 0) { + if (file_printf(ms, ".%d", desc / 10 % 10) == -1) + return; + } } +} - offset = ELF_ALIGN(doff + descsz); - if (doff + descsz > size) { - /* - * We're past the end of the buffer. - */ - return (offset >= size) ? offset : size; +private int +do_bid_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type, + int swap __attribute__((__unused__)), uint32_t namesz, uint32_t descsz, + size_t noff, size_t doff, int *flags) +{ + if (namesz == 4 && strcmp((char *)&nbuf[noff], "GNU") == 0 && + type == NT_GNU_BUILD_ID && (descsz == 16 || descsz == 20)) { + uint8_t desc[20]; + uint32_t i; + *flags |= FLAGS_DID_BUILD_ID; + if (file_printf(ms, ", BuildID[%s]=", descsz == 16 ? "md5/uuid" : + "sha1") == -1) + return 1; + (void)memcpy(desc, &nbuf[doff], descsz); + for (i = 0; i < descsz; i++) + if (file_printf(ms, "%02x", desc[i]) == -1) + return 1; + return 1; } + return 0; +} - if ((*flags & (FLAGS_DID_NOTE|FLAGS_DID_BUILD_ID)) == - (FLAGS_DID_NOTE|FLAGS_DID_BUILD_ID)) - goto core; - +private int +do_os_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type, + int swap, uint32_t namesz, uint32_t descsz, + size_t noff, size_t doff, int *flags) +{ if (namesz == 5 && strcmp((char *)&nbuf[noff], "SuSE") == 0 && - xnh_type == NT_GNU_VERSION && descsz == 2) { + type == NT_GNU_VERSION && descsz == 2) { + *flags |= FLAGS_DID_OS_NOTE; file_printf(ms, ", for SuSE %d.%d", nbuf[doff], nbuf[doff + 1]); + return 1; } + if (namesz == 4 && strcmp((char *)&nbuf[noff], "GNU") == 0 && - xnh_type == NT_GNU_VERSION && descsz == 16) { + type == NT_GNU_VERSION && descsz == 16) { uint32_t desc[4]; (void)memcpy(desc, &nbuf[doff], sizeof(desc)); + *flags |= FLAGS_DID_OS_NOTE; if (file_printf(ms, ", for GNU/") == -1) - return size; + return 1; switch (elf_getu32(swap, desc[0])) { case GNU_OS_LINUX: if (file_printf(ms, "Linux") == -1) - return size; + return 1; break; case GNU_OS_HURD: if (file_printf(ms, "Hurd") == -1) - return size; + return 1; break; case GNU_OS_SOLARIS: if (file_printf(ms, "Solaris") == -1) - return size; + return 1; break; case GNU_OS_KFREEBSD: if (file_printf(ms, "kFreeBSD") == -1) - return size; + return 1; break; case GNU_OS_KNETBSD: if (file_printf(ms, "kNetBSD") == -1) - return size; + return 1; break; default: if (file_printf(ms, "<unknown>") == -1) - return size; + return 1; } if (file_printf(ms, " %d.%d.%d", elf_getu32(swap, desc[1]), elf_getu32(swap, desc[2]), elf_getu32(swap, desc[3])) == -1) - return size; - *flags |= FLAGS_DID_NOTE; - return size; + return 1; + return 1; } - if (namesz == 4 && strcmp((char *)&nbuf[noff], "GNU") == 0 && - xnh_type == NT_GNU_BUILD_ID && (descsz == 16 || descsz == 20)) { - uint8_t desc[20]; - uint32_t i; - if (file_printf(ms, ", BuildID[%s]=", descsz == 16 ? "md5/uuid" : - "sha1") == -1) - return size; - (void)memcpy(desc, &nbuf[doff], descsz); - for (i = 0; i < descsz; i++) - if (file_printf(ms, "%02x", desc[i]) == -1) - return size; - *flags |= FLAGS_DID_BUILD_ID; - } - - if (namesz == 7 && strcmp((char *)&nbuf[noff], "NetBSD") == 0 && - xnh_type == NT_NETBSD_VERSION && descsz == 4) { - uint32_t desc; - (void)memcpy(&desc, &nbuf[doff], sizeof(desc)); - desc = elf_getu32(swap, desc); - - if (file_printf(ms, ", for NetBSD") == -1) - return size; - /* - * The version number used to be stuck as 199905, and was thus - * basically content-free. Newer versions of NetBSD have fixed - * this and now use the encoding of __NetBSD_Version__: - * - * MMmmrrpp00 - * - * M = major version - * m = minor version - * r = release ["",A-Z,Z[A-Z] but numeric] - * p = patchlevel - */ - if (desc > 100000000U) { - uint32_t ver_patch = (desc / 100) % 100; - uint32_t ver_rel = (desc / 10000) % 100; - uint32_t ver_min = (desc / 1000000) % 100; - uint32_t ver_maj = desc / 100000000; - - if (file_printf(ms, " %u.%u", ver_maj, ver_min) == -1) - return size; - if (ver_rel == 0 && ver_patch != 0) { - if (file_printf(ms, ".%u", ver_patch) == -1) - return size; - } else if (ver_rel != 0) { - while (ver_rel > 26) { - if (file_printf(ms, "Z") == -1) - return size; - ver_rel -= 26; - } - if (file_printf(ms, "%c", 'A' + ver_rel - 1) - == -1) - return size; - } + if (namesz == 7 && strcmp((char *)&nbuf[noff], "NetBSD") == 0) { + if (type == NT_NETBSD_VERSION && descsz == 4) { + *flags |= FLAGS_DID_OS_NOTE; + do_note_netbsd_version(ms, swap, &nbuf[doff]); + return 1; } - *flags |= FLAGS_DID_NOTE; - return size; } - if (namesz == 8 && strcmp((char *)&nbuf[noff], "FreeBSD") == 0 && - xnh_type == NT_FREEBSD_VERSION && descsz == 4) { - uint32_t desc; - (void)memcpy(&desc, &nbuf[doff], sizeof(desc)); - desc = elf_getu32(swap, desc); - if (file_printf(ms, ", for FreeBSD") == -1) - return size; - - /* - * Contents is __FreeBSD_version, whose relation to OS - * versions is defined by a huge table in the Porter's - * Handbook. This is the general scheme: - * - * Releases: - * Mmp000 (before 4.10) - * Mmi0p0 (before 5.0) - * Mmm0p0 - * - * Development branches: - * Mmpxxx (before 4.6) - * Mmp1xx (before 4.10) - * Mmi1xx (before 5.0) - * M000xx (pre-M.0) - * Mmm1xx - * - * M = major version - * m = minor version - * i = minor version increment (491000 -> 4.10) - * p = patchlevel - * x = revision - * - * The first release of FreeBSD to use ELF by default - * was version 3.0. - */ - if (desc == 460002) { - if (file_printf(ms, " 4.6.2") == -1) - return size; - } else if (desc < 460100) { - if (file_printf(ms, " %d.%d", desc / 100000, - desc / 10000 % 10) == -1) - return size; - if (desc / 1000 % 10 > 0) - if (file_printf(ms, ".%d", desc / 1000 % 10) - == -1) - return size; - if ((desc % 1000 > 0) || (desc % 100000 == 0)) - if (file_printf(ms, " (%d)", desc) == -1) - return size; - } else if (desc < 500000) { - if (file_printf(ms, " %d.%d", desc / 100000, - desc / 10000 % 10 + desc / 1000 % 10) == -1) - return size; - if (desc / 100 % 10 > 0) { - if (file_printf(ms, " (%d)", desc) == -1) - return size; - } else if (desc / 10 % 10 > 0) { - if (file_printf(ms, ".%d", desc / 10 % 10) - == -1) - return size; - } - } else { - if (file_printf(ms, " %d.%d", desc / 100000, - desc / 1000 % 100) == -1) - return size; - if ((desc / 100 % 10 > 0) || - (desc % 100000 / 100 == 0)) { - if (file_printf(ms, " (%d)", desc) == -1) - return size; - } else if (desc / 10 % 10 > 0) { - if (file_printf(ms, ".%d", desc / 10 % 10) - == -1) - return size; - } + if (namesz == 8 && strcmp((char *)&nbuf[noff], "FreeBSD") == 0) { + if (type == NT_FREEBSD_VERSION && descsz == 4) { + *flags |= FLAGS_DID_OS_NOTE; + do_note_freebsd_version(ms, swap, &nbuf[doff]); + return 1; } - *flags |= FLAGS_DID_NOTE; - return size; } if (namesz == 8 && strcmp((char *)&nbuf[noff], "OpenBSD") == 0 && - xnh_type == NT_OPENBSD_VERSION && descsz == 4) { + type == NT_OPENBSD_VERSION && descsz == 4) { + *flags |= FLAGS_DID_OS_NOTE; if (file_printf(ms, ", for OpenBSD") == -1) - return size; + return 1; /* Content of note is always 0 */ - *flags |= FLAGS_DID_NOTE; - return size; + return 1; } if (namesz == 10 && strcmp((char *)&nbuf[noff], "DragonFly") == 0 && - xnh_type == NT_DRAGONFLY_VERSION && descsz == 4) { + type == NT_DRAGONFLY_VERSION && descsz == 4) { uint32_t desc; + *flags |= FLAGS_DID_OS_NOTE; if (file_printf(ms, ", for DragonFly") == -1) - return size; + return 1; (void)memcpy(&desc, &nbuf[doff], sizeof(desc)); desc = elf_getu32(swap, desc); if (file_printf(ms, " %d.%d.%d", desc / 100000, desc / 10000 % 10, desc % 10000) == -1) - return size; - *flags |= FLAGS_DID_NOTE; - return size; + return 1; + return 1; + } + return 0; +} + +private int +do_pax_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type, + int swap, uint32_t namesz, uint32_t descsz, + size_t noff, size_t doff, int *flags) +{ + if (namesz == 4 && strcmp((char *)&nbuf[noff], "PaX") == 0 && + type == NT_NETBSD_PAX && descsz == 4) { + static const char *pax[] = { + "+mprotect", + "-mprotect", + "+segvguard", + "-segvguard", + "+ASLR", + "-ASLR", + }; + uint32_t desc; + size_t i; + int did = 0; + + *flags |= FLAGS_DID_NETBSD_PAX; + (void)memcpy(&desc, &nbuf[doff], sizeof(desc)); + desc = elf_getu32(swap, desc); + + if (desc && file_printf(ms, ", PaX: ") == -1) + return 1; + + for (i = 0; i < __arraycount(pax); i++) { + if (((1 << i) & desc) == 0) + continue; + if (file_printf(ms, "%s%s", did++ ? "," : "", + pax[i]) == -1) + return 1; + } + return 1; } + return 0; +} -core: +private int +do_core_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type, + int swap, uint32_t namesz, uint32_t descsz, + size_t noff, size_t doff, int *flags, size_t size, int clazz) +{ +#ifdef ELFCORE + int os_style = -1; /* * Sigh. The 2.0.36 kernel in Debian 2.1, at * least, doesn't correctly implement name @@ -649,20 +668,17 @@ core: os_style = OS_STYLE_NETBSD; } -#ifdef ELFCORE - if ((*flags & FLAGS_DID_CORE) != 0) - return size; - if (os_style != -1 && (*flags & FLAGS_DID_CORE_STYLE) == 0) { if (file_printf(ms, ", %s-style", os_style_names[os_style]) == -1) - return size; + return 1; *flags |= FLAGS_DID_CORE_STYLE; } switch (os_style) { case OS_STYLE_NETBSD: - if (xnh_type == NT_NETBSD_CORE_PROCINFO) { + if (type == NT_NETBSD_CORE_PROCINFO) { + char sbuf[512]; uint32_t signo; /* * Extract the program name. It is at @@ -670,8 +686,9 @@ core: * including the terminating NUL. */ if (file_printf(ms, ", from '%.31s'", - &nbuf[doff + 0x7c]) == -1) - return size; + file_printable(sbuf, sizeof(sbuf), + (const char *)&nbuf[doff + 0x7c])) == -1) + return 1; /* * Extract the signal number. It is at @@ -681,14 +698,14 @@ core: sizeof(signo)); if (file_printf(ms, " (signal %u)", elf_getu32(swap, signo)) == -1) - return size; + return 1; *flags |= FLAGS_DID_CORE; - return size; + return 1; } break; default: - if (xnh_type == NT_PRPSINFO && *flags & FLAGS_IS_CORE) { + if (type == NT_PRPSINFO && *flags & FLAGS_IS_CORE) { size_t i, j; unsigned char c; /* @@ -756,7 +773,7 @@ core: * Try next offsets, in case this match is * in the middle of a string. */ - for (k = i + 1 ; k < NOFFSETS ; k++) { + for (k = i + 1 ; k < NOFFSETS; k++) { size_t no; int adjust = 1; if (prpsoffsets(k) >= prpsoffsets(i)) @@ -781,9 +798,9 @@ core: cp--; if (file_printf(ms, ", from '%.*s'", (int)(cp - cname), cname) == -1) - return size; + return 1; *flags |= FLAGS_DID_CORE; - return size; + return 1; tryanother: ; @@ -792,6 +809,129 @@ core: break; } #endif + return 0; +} + +private size_t +donote(struct magic_set *ms, void *vbuf, size_t offset, size_t size, + int clazz, int swap, size_t align, int *flags, uint16_t *notecount) +{ + Elf32_Nhdr nh32; + Elf64_Nhdr nh64; + size_t noff, doff; + uint32_t namesz, descsz; + unsigned char *nbuf = CAST(unsigned char *, vbuf); + + if (*notecount == 0) + return 0; + --*notecount; + + if (xnh_sizeof + offset > size) { + /* + * We're out of note headers. + */ + return xnh_sizeof + offset; + } + + (void)memcpy(xnh_addr, &nbuf[offset], xnh_sizeof); + offset += xnh_sizeof; + + namesz = xnh_namesz; + descsz = xnh_descsz; + if ((namesz == 0) && (descsz == 0)) { + /* + * We're out of note headers. + */ + return (offset >= size) ? offset : size; + } + + if (namesz & 0x80000000) { + (void)file_printf(ms, ", bad note name size 0x%lx", + (unsigned long)namesz); + return 0; + } + + if (descsz & 0x80000000) { + (void)file_printf(ms, ", bad note description size 0x%lx", + (unsigned long)descsz); + return 0; + } + + noff = offset; + doff = ELF_ALIGN(offset + namesz); + + if (offset + namesz > size) { + /* + * We're past the end of the buffer. + */ + return doff; + } + + offset = ELF_ALIGN(doff + descsz); + if (doff + descsz > size) { + /* + * We're past the end of the buffer. + */ + return (offset >= size) ? offset : size; + } + + if ((*flags & FLAGS_DID_OS_NOTE) == 0) { + if (do_os_note(ms, nbuf, xnh_type, swap, + namesz, descsz, noff, doff, flags)) + return size; + } + + if ((*flags & FLAGS_DID_BUILD_ID) == 0) { + if (do_bid_note(ms, nbuf, xnh_type, swap, + namesz, descsz, noff, doff, flags)) + return size; + } + + if ((*flags & FLAGS_DID_NETBSD_PAX) == 0) { + if (do_pax_note(ms, nbuf, xnh_type, swap, + namesz, descsz, noff, doff, flags)) + return size; + } + + if ((*flags & FLAGS_DID_CORE) == 0) { + if (do_core_note(ms, nbuf, xnh_type, swap, + namesz, descsz, noff, doff, flags, size, clazz)) + return size; + } + + if (namesz == 7 && strcmp((char *)&nbuf[noff], "NetBSD") == 0) { + if (descsz > 100) + descsz = 100; + switch (xnh_type) { + case NT_NETBSD_VERSION: + return size; + case NT_NETBSD_MARCH: + if (*flags & FLAGS_DID_NETBSD_MARCH) + return size; + *flags |= FLAGS_DID_NETBSD_MARCH; + if (file_printf(ms, ", compiled for: %.*s", + (int)descsz, (const char *)&nbuf[doff]) == -1) + return size; + break; + case NT_NETBSD_CMODEL: + if (*flags & FLAGS_DID_NETBSD_CMODEL) + return size; + *flags |= FLAGS_DID_NETBSD_CMODEL; + if (file_printf(ms, ", compiler model: %.*s", + (int)descsz, (const char *)&nbuf[doff]) == -1) + return size; + break; + default: + if (*flags & FLAGS_DID_NETBSD_UNKNOWN) + return size; + *flags |= FLAGS_DID_NETBSD_UNKNOWN; + if (file_printf(ms, ", note=%u", xnh_type) == -1) + return size; + break; + } + return size; + } + return offset; } @@ -847,16 +987,19 @@ static const cap_desc_t cap_desc_386[] = { private int doshn(struct magic_set *ms, int clazz, int swap, int fd, off_t off, int num, - size_t size, off_t fsize, int *flags, int mach, int strtab) + size_t size, off_t fsize, int mach, int strtab, int *flags, + uint16_t *notecount) { Elf32_Shdr sh32; Elf64_Shdr sh64; int stripped = 1; + size_t nbadcap = 0; void *nbuf; off_t noff, coff, name_off; uint64_t cap_hw1 = 0; /* SunOS 5.x hardware capabilites */ uint64_t cap_sf1 = 0; /* SunOS 5.x software capabilites */ char name[50]; + ssize_t namesize; if (size != xsh_sizeof) { if (file_printf(ms, ", corrupted section header size") == -1) @@ -865,7 +1008,7 @@ doshn(struct magic_set *ms, int clazz, int swap, int fd, off_t off, int num, } /* Read offset of name section to be able to read section names later */ - if (pread(fd, xsh_addr, xsh_sizeof, off + size * strtab) == -1) { + if (pread(fd, xsh_addr, xsh_sizeof, off + size * strtab) < (ssize_t)xsh_sizeof) { file_badread(ms); return -1; } @@ -873,15 +1016,15 @@ doshn(struct magic_set *ms, int clazz, int swap, int fd, off_t off, int num, for ( ; num; num--) { /* Read the name of this section. */ - if (pread(fd, name, sizeof(name), name_off + xsh_name) == -1) { + if ((namesize = pread(fd, name, sizeof(name) - 1, name_off + xsh_name)) == -1) { file_badread(ms); return -1; } - name[sizeof(name) - 1] = '\0'; + name[namesize] = '\0'; if (strcmp(name, ".debug_info") == 0) stripped = 0; - if (pread(fd, xsh_addr, xsh_sizeof, off) == -1) { + if (pread(fd, xsh_addr, xsh_sizeof, off) < (ssize_t)xsh_sizeof) { file_badread(ms); return -1; } @@ -896,7 +1039,7 @@ doshn(struct magic_set *ms, int clazz, int swap, int fd, off_t off, int num, stripped = 0; break; default: - if (xsh_offset > fsize) { + if (fsize != SIZE_UNKNOWN && xsh_offset > fsize) { /* Perhaps warn here */ continue; } @@ -911,7 +1054,7 @@ doshn(struct magic_set *ms, int clazz, int swap, int fd, off_t off, int num, " for note"); return -1; } - if (pread(fd, nbuf, xsh_size, xsh_offset) == -1) { + if (pread(fd, nbuf, xsh_size, xsh_offset) < (ssize_t)xsh_size) { file_badread(ms); free(nbuf); return -1; @@ -922,7 +1065,7 @@ doshn(struct magic_set *ms, int clazz, int swap, int fd, off_t off, int num, if (noff >= (off_t)xsh_size) break; noff = donote(ms, nbuf, (size_t)noff, - xsh_size, clazz, swap, 4, flags); + xsh_size, clazz, swap, 4, flags, notecount); if (noff == 0) break; } @@ -940,6 +1083,8 @@ doshn(struct magic_set *ms, int clazz, int swap, int fd, off_t off, int num, goto skip; } + if (nbadcap > 5) + break; if (lseek(fd, xsh_offset, SEEK_SET) == (off_t)-1) { file_badseek(ms); return -1; @@ -957,6 +1102,36 @@ doshn(struct magic_set *ms, int clazz, int swap, int fd, off_t off, int num, file_badread(ms); return -1; } + if (cbuf[0] == 'A') { +#ifdef notyet + char *p = cbuf + 1; + uint32_t len, tag; + memcpy(&len, p, sizeof(len)); + p += 4; + len = getu32(swap, len); + if (memcmp("gnu", p, 3) != 0) { + if (file_printf(ms, + ", unknown capability %.3s", p) + == -1) + return -1; + break; + } + p += strlen(p) + 1; + tag = *p++; + memcpy(&len, p, sizeof(len)); + p += 4; + len = getu32(swap, len); + if (tag != 1) { + if (file_printf(ms, ", unknown gnu" + " capability tag %d", tag) + == -1) + return -1; + break; + } + // gnu attributes +#endif + break; + } (void)memcpy(xcap_addr, cbuf, xcap_sizeof); switch (xcap_tag) { case CA_SUNW_NULL: @@ -975,6 +1150,8 @@ doshn(struct magic_set *ms, int clazz, int swap, int fd, off_t off, int num, (unsigned long long)xcap_tag, (unsigned long long)xcap_val) == -1) return -1; + if (nbadcap++ > 2) + coff = xsh_size; break; } } @@ -1055,13 +1232,15 @@ doshn(struct magic_set *ms, int clazz, int swap, int fd, off_t off, int num, */ private int dophn_exec(struct magic_set *ms, int clazz, int swap, int fd, off_t off, - int num, size_t size, off_t fsize, int *flags, int sh_num) + int num, size_t size, off_t fsize, int sh_num, int *flags, + uint16_t *notecount) { Elf32_Phdr ph32; Elf64_Phdr ph64; const char *linking_style = "statically"; - const char *shared_libraries = ""; + const char *interp = ""; unsigned char nbuf[BUFSIZ]; + char ibuf[BUFSIZ]; ssize_t bufsize; size_t offset, align, len; @@ -1072,23 +1251,43 @@ dophn_exec(struct magic_set *ms, int clazz, int swap, int fd, off_t off, } for ( ; num; num--) { - if (pread(fd, xph_addr, xph_sizeof, off) == -1) { + if (pread(fd, xph_addr, xph_sizeof, off) < (ssize_t)xph_sizeof) { file_badread(ms); return -1; } off += size; + bufsize = 0; + align = 4; /* Things we can determine before we seek */ switch (xph_type) { case PT_DYNAMIC: linking_style = "dynamically"; break; + case PT_NOTE: + if (sh_num) /* Did this through section headers */ + continue; + if (((align = xph_align) & 0x80000000UL) != 0 || + align < 4) { + if (file_printf(ms, + ", invalid note alignment 0x%lx", + (unsigned long)align) == -1) + return -1; + align = 4; + } + /*FALLTHROUGH*/ case PT_INTERP: - shared_libraries = " (uses shared libs)"; + len = xph_filesz < sizeof(nbuf) ? xph_filesz + : sizeof(nbuf); + bufsize = pread(fd, nbuf, len, xph_offset); + if (bufsize == -1) { + file_badread(ms); + return -1; + } break; default: - if (xph_offset > fsize) { + if (fsize != SIZE_UNKNOWN && xph_offset > fsize) { /* Maybe warn here? */ continue; } @@ -1097,34 +1296,25 @@ dophn_exec(struct magic_set *ms, int clazz, int swap, int fd, off_t off, /* Things we can determine when we seek */ switch (xph_type) { + case PT_INTERP: + if (bufsize && nbuf[0]) { + nbuf[bufsize - 1] = '\0'; + interp = (const char *)nbuf; + } else + interp = "*empty*"; + break; case PT_NOTE: - if ((align = xph_align) & 0x80000000UL) { - if (file_printf(ms, - ", invalid note alignment 0x%lx", - (unsigned long)align) == -1) - return -1; - align = 4; - } - if (sh_num) - break; /* * This is a PT_NOTE section; loop through all the notes * in the section. */ - len = xph_filesz < sizeof(nbuf) ? xph_filesz - : sizeof(nbuf); - bufsize = pread(fd, nbuf, len, xph_offset); - if (bufsize == -1) { - file_badread(ms); - return -1; - } offset = 0; for (;;) { if (offset >= (size_t)bufsize) break; offset = donote(ms, nbuf, offset, (size_t)bufsize, clazz, swap, align, - flags); + flags, notecount); if (offset == 0) break; } @@ -1133,9 +1323,13 @@ dophn_exec(struct magic_set *ms, int clazz, int swap, int fd, off_t off, break; } } - if (file_printf(ms, ", %s linked%s", linking_style, shared_libraries) + if (file_printf(ms, ", %s linked", linking_style) == -1) - return -1; + return -1; + if (interp[0]) + if (file_printf(ms, ", interpreter %s", + file_printable(ibuf, sizeof(ibuf), interp)) == -1) + return -1; return 0; } @@ -1155,7 +1349,7 @@ file_tryelf(struct magic_set *ms, int fd, const unsigned char *buf, int flags = 0; Elf32_Ehdr elf32hdr; Elf64_Ehdr elf64hdr; - uint16_t type; + uint16_t type, phnum, shnum, notecount; if (ms->flags & (MAGIC_MIME|MAGIC_APPLE)) return 0; @@ -1181,7 +1375,10 @@ file_tryelf(struct magic_set *ms, int fd, const unsigned char *buf, file_badread(ms); return -1; } - fsize = st.st_size; + if (S_ISREG(st.st_mode) || st.st_size != 0) + fsize = st.st_size; + else + fsize = SIZE_UNKNOWN; clazz = buf[EI_CLASS]; diff --git a/src/readelf.h b/src/readelf.h index 4308e6a..732b20c 100644 --- a/src/readelf.h +++ b/src/readelf.h @@ -44,17 +44,9 @@ typedef uint16_t Elf32_Half; typedef uint32_t Elf32_Word; typedef uint8_t Elf32_Char; -#if SIZEOF_LONG_LONG != 8 -#define USE_ARRAY_FOR_64BIT_TYPES -typedef uint32_t Elf64_Addr[2]; -typedef uint32_t Elf64_Off[2]; -typedef uint32_t Elf64_Xword[2]; -#else -#undef USE_ARRAY_FOR_64BIT_TYPES typedef uint64_t Elf64_Addr; typedef uint64_t Elf64_Off; typedef uint64_t Elf64_Xword; -#endif typedef uint16_t Elf64_Half; typedef uint32_t Elf64_Word; typedef uint8_t Elf64_Char; @@ -263,6 +255,46 @@ typedef struct { */ #define NT_GNU_BUILD_ID 3 +/* + * NetBSD-specific note type: PaX. + * There should be 1 NOTE per executable. + * name: PaX\0 + * namesz: 4 + * desc: + * word[0]: capability bitmask + * descsz: 4 + */ +#define NT_NETBSD_PAX 3 +#define NT_NETBSD_PAX_MPROTECT 0x01 /* Force enable Mprotect */ +#define NT_NETBSD_PAX_NOMPROTECT 0x02 /* Force disable Mprotect */ +#define NT_NETBSD_PAX_GUARD 0x04 /* Force enable Segvguard */ +#define NT_NETBSD_PAX_NOGUARD 0x08 /* Force disable Servguard */ +#define NT_NETBSD_PAX_ASLR 0x10 /* Force enable ASLR */ +#define NT_NETBSD_PAX_NOASLR 0x20 /* Force disable ASLR */ + +/* + * NetBSD-specific note type: MACHINE_ARCH. + * There should be 1 NOTE per executable. + * name: NetBSD\0 + * namesz: 7 + * desc: string + * descsz: variable + */ +#define NT_NETBSD_MARCH 5 + +/* + * NetBSD-specific note type: COMPILER MODEL. + * There should be 1 NOTE per executable. + * name: NetBSD\0 + * namesz: 7 + * desc: string + * descsz: variable + */ +#define NT_NETBSD_CMODEL 6 + +#if !defined(ELFSIZE) && defined(ARCH_ELFSIZE) +#define ELFSIZE ARCH_ELFSIZE +#endif /* SunOS 5.x hardware/software capabilities */ typedef struct { Elf32_Word c_tag; diff --git a/src/softmagic.c b/src/softmagic.c index 038a1ff..5e277e3 100644 --- a/src/softmagic.c +++ b/src/softmagic.c @@ -32,26 +32,28 @@ #include "file.h" #ifndef lint -FILE_RCSID("@(#)$File: softmagic.c,v 1.159 2013/02/17 22:28:27 christos Exp $") +FILE_RCSID("@(#)$File: softmagic.c,v 1.206 2015/01/01 17:07:34 christos Exp $") #endif /* lint */ #include "magic.h" +#include <assert.h> #include <string.h> #include <ctype.h> #include <stdlib.h> #include <time.h> - private int match(struct magic_set *, struct magic *, uint32_t, - const unsigned char *, size_t, size_t, int, int, int, int *); + const unsigned char *, size_t, size_t, int, int, int, uint16_t, + uint16_t *, int *, int *, int *); private int mget(struct magic_set *, const unsigned char *, - struct magic *, size_t, size_t, unsigned int, int, int, int, int *); + struct magic *, size_t, size_t, unsigned int, int, int, int, uint16_t, + uint16_t *, int *, int *, int *); private int magiccheck(struct magic_set *, struct magic *); private int32_t mprint(struct magic_set *, struct magic *); private int32_t moffset(struct magic_set *, struct magic *); private void mdebug(uint32_t, const char *, size_t); private int mcopy(struct magic_set *, union VALUETYPE *, int, int, - const unsigned char *, uint32_t, size_t, size_t); + const unsigned char *, uint32_t, size_t, struct magic *); private int mconvert(struct magic_set *, struct magic *, int); private int print_sep(struct magic_set *, int); private int handle_annotation(struct magic_set *, struct magic *); @@ -60,6 +62,8 @@ private void cvt_16(union VALUETYPE *, const struct magic *); private void cvt_32(union VALUETYPE *, const struct magic *); private void cvt_64(union VALUETYPE *, const struct magic *); +#define OFFSET_OOB(n, o, i) ((n) < (o) || (i) > ((n) - (o))) + /* * softmagic - lookup one file in parsed, in-memory copy of database * Passed the name and FILE * of one file to be typed. @@ -67,18 +71,45 @@ private void cvt_64(union VALUETYPE *, const struct magic *); /*ARGSUSED1*/ /* nbytes passed for regularity, maybe need later */ protected int file_softmagic(struct magic_set *ms, const unsigned char *buf, size_t nbytes, - int mode, int text) + uint16_t indir_level, uint16_t *name_count, int mode, int text) { struct mlist *ml; - int rv; + int rv, printed_something = 0, need_separator = 0; + uint16_t nc; + + if (name_count == NULL) { + nc = 0; + name_count = &nc; + } + for (ml = ms->mlist[0]->next; ml != ms->mlist[0]; ml = ml->next) if ((rv = match(ms, ml->magic, ml->nmagic, buf, nbytes, 0, mode, - text, 0, NULL)) != 0) + text, 0, indir_level, name_count, + &printed_something, &need_separator, NULL)) != 0) return rv; return 0; } +#define FILE_FMTDEBUG +#ifdef FILE_FMTDEBUG +#define F(a, b, c) file_fmtcheck((a), (b), (c), __FILE__, __LINE__) + +private const char * __attribute__((__format_arg__(3))) +file_fmtcheck(struct magic_set *ms, const struct magic *m, const char *def, + const char *file, size_t line) +{ + const char *ptr = fmtcheck(m->desc, def); + if (ptr == def) + file_magerror(ms, + "%s, %" SIZE_T_FORMAT "u: format `%s' does not match" + " with `%s'", file, line, m->desc, def); + return ptr; +} +#else +#define F(a, b, c) fmtcheck((b)->desc, (c)) +#endif + /* * Go through the whole list, stopping if you find a match. Process all * the continuations of that match before returning. @@ -109,14 +140,13 @@ file_softmagic(struct magic_set *ms, const unsigned char *buf, size_t nbytes, private int match(struct magic_set *ms, struct magic *magic, uint32_t nmagic, const unsigned char *s, size_t nbytes, size_t offset, int mode, int text, - int flip, int *returnval) + int flip, uint16_t indir_level, uint16_t *name_count, + int *printed_something, int *need_separator, int *returnval) { uint32_t magindex = 0; unsigned int cont_level = 0; - int need_separator = 0; int returnvalv = 0, e; /* if a match is found it is set to 1*/ int firstline = 1; /* a flag to print X\n X\n- X */ - int printed_something = 0; int print = (ms->flags & (MAGIC_MIME|MAGIC_APPLE)) == 0; if (returnval == NULL) @@ -131,8 +161,9 @@ match(struct magic_set *ms, struct magic *magic, uint32_t nmagic, if (m->type != FILE_NAME) if ((IS_STRING(m->type) && - ((text && (m->str_flags & (STRING_BINTEST | STRING_TEXTTEST)) == STRING_BINTEST) || - (!text && (m->str_flags & (STRING_TEXTTEST | STRING_BINTEST)) == STRING_TEXTTEST))) || +#define FLT (STRING_BINTEST | STRING_TEXTTEST) + ((text && (m->str_flags & FLT) == STRING_BINTEST) || + (!text && (m->str_flags & FLT) == STRING_TEXTTEST))) || (m->flag & mode) != mode) { /* Skip sub-tests */ while (magindex + 1 < nmagic && @@ -147,7 +178,8 @@ match(struct magic_set *ms, struct magic *magic, uint32_t nmagic, /* if main entry matches, print it... */ switch (mget(ms, s, m, nbytes, offset, cont_level, mode, text, - flip, returnval)) { + flip, indir_level, name_count, + printed_something, need_separator, returnval)) { case -1: return -1; case 0: @@ -181,6 +213,8 @@ match(struct magic_set *ms, struct magic *magic, uint32_t nmagic, } if ((e = handle_annotation(ms, m)) != 0) { + *need_separator = 1; + *printed_something = 1; *returnval = 1; return e; } @@ -189,8 +223,8 @@ match(struct magic_set *ms, struct magic *magic, uint32_t nmagic, * a blank before we print something else. */ if (*m->desc) { - need_separator = 1; - printed_something = 1; + *need_separator = 1; + *printed_something = 1; if (print_sep(ms, firstline) == -1) return -1; } @@ -205,9 +239,9 @@ match(struct magic_set *ms, struct magic *magic, uint32_t nmagic, if (file_check_mem(ms, ++cont_level) == -1) return -1; - while (magic[magindex+1].cont_level != 0 && - ++magindex < nmagic) { - m = &magic[magindex]; + while (magindex + 1 < nmagic && + magic[magindex + 1].cont_level != 0) { + m = &magic[++magindex]; ms->line = m->lineno; /* for messages */ if (cont_level < m->cont_level) @@ -233,7 +267,8 @@ match(struct magic_set *ms, struct magic *magic, uint32_t nmagic, } #endif switch (mget(ms, s, m, nbytes, offset, cont_level, mode, - text, flip, returnval)) { + text, flip, indir_level, name_count, + printed_something, need_separator, returnval)) { case -1: return -1; case 0: @@ -260,13 +295,16 @@ match(struct magic_set *ms, struct magic *magic, uint32_t nmagic, #ifdef ENABLE_CONDITIONALS ms->c.li[cont_level].last_match = 1; #endif - if (m->type != FILE_DEFAULT) - ms->c.li[cont_level].got_match = 1; - else if (ms->c.li[cont_level].got_match) { + if (m->type == FILE_CLEAR) ms->c.li[cont_level].got_match = 0; - break; - } + else if (ms->c.li[cont_level].got_match) { + if (m->type == FILE_DEFAULT) + break; + } else + ms->c.li[cont_level].got_match = 1; if ((e = handle_annotation(ms, m)) != 0) { + *need_separator = 1; + *printed_something = 1; *returnval = 1; return e; } @@ -275,8 +313,8 @@ match(struct magic_set *ms, struct magic *magic, uint32_t nmagic, * make sure that we have a separator first. */ if (*m->desc) { - if (!printed_something) { - printed_something = 1; + if (!*printed_something) { + *printed_something = 1; if (print_sep(ms, firstline) == -1) return -1; @@ -289,13 +327,13 @@ match(struct magic_set *ms, struct magic *magic, uint32_t nmagic, * this item isn't empty. */ /* space if previous printed */ - if (need_separator + if (*need_separator && ((m->flag & NOSPACE) == 0) && *m->desc) { if (print && file_printf(ms, " ") == -1) return -1; - need_separator = 0; + *need_separator = 0; } if (print && mprint(ms, m) == -1) return -1; @@ -303,7 +341,7 @@ match(struct magic_set *ms, struct magic *magic, uint32_t nmagic, ms->c.li[cont_level].off = moffset(ms, m); if (*m->desc) - need_separator = 1; + *need_separator = 1; /* * If we see any continuations @@ -315,12 +353,12 @@ match(struct magic_set *ms, struct magic *magic, uint32_t nmagic, break; } } - if (printed_something) { + if (*printed_something) { firstline = 0; if (print) *returnval = 1; } - if ((ms->flags & MAGIC_CONTINUE) == 0 && printed_something) { + if ((ms->flags & MAGIC_CONTINUE) == 0 && *printed_something) { return *returnval; /* don't keep searching */ } } @@ -330,23 +368,21 @@ match(struct magic_set *ms, struct magic *magic, uint32_t nmagic, private int check_fmt(struct magic_set *ms, struct magic *m) { - regex_t rx; - int rc; + file_regex_t rx; + int rc, rv = -1; if (strchr(m->desc, '%') == NULL) return 0; - rc = regcomp(&rx, "%[-0-9\\.]*s", REG_EXTENDED|REG_NOSUB); + rc = file_regcomp(&rx, "%[-0-9\\.]*s", REG_EXTENDED|REG_NOSUB); if (rc) { - char errmsg[512]; - (void)regerror(rc, &rx, errmsg, sizeof(errmsg)); - file_magerror(ms, "regex error %d, (%s)", rc, errmsg); - return -1; + file_regerror(&rx, rc, ms); } else { - rc = regexec(&rx, m->desc, 0, 0, 0); - regfree(&rx); - return !rc; + rc = file_regexec(&rx, m->desc, 0, 0, 0); + rv = !rc; } + file_regfree(&rx); + return rv; } #ifndef HAVE_STRNDUP @@ -375,7 +411,7 @@ mprint(struct magic_set *ms, struct magic *m) float vf; double vd; int64_t t = 0; - char buf[128], tbuf[26]; + char buf[128], tbuf[26], sbuf[512]; union VALUETYPE *p = &ms->ms_value; switch (m->type) { @@ -385,13 +421,14 @@ mprint(struct magic_set *ms, struct magic *m) case -1: return -1; case 1: - (void)snprintf(buf, sizeof(buf), "%c", + (void)snprintf(buf, sizeof(buf), "%d", (unsigned char)v); - if (file_printf(ms, m->desc, buf) == -1) + if (file_printf(ms, F(ms, m, "%s"), buf) == -1) return -1; break; default: - if (file_printf(ms, m->desc, (unsigned char) v) == -1) + if (file_printf(ms, F(ms, m, "%d"), + (unsigned char) v) == -1) return -1; break; } @@ -406,14 +443,14 @@ mprint(struct magic_set *ms, struct magic *m) case -1: return -1; case 1: - (void)snprintf(buf, sizeof(buf), "%hu", + (void)snprintf(buf, sizeof(buf), "%u", (unsigned short)v); - if (file_printf(ms, m->desc, buf) == -1) + if (file_printf(ms, F(ms, m, "%s"), buf) == -1) return -1; break; default: - if ( - file_printf(ms, m->desc, (unsigned short) v) == -1) + if (file_printf(ms, F(ms, m, "%u"), + (unsigned short) v) == -1) return -1; break; } @@ -429,12 +466,12 @@ mprint(struct magic_set *ms, struct magic *m) case -1: return -1; case 1: - (void)snprintf(buf, sizeof(buf), "%u", (uint32_t)v); - if (file_printf(ms, m->desc, buf) == -1) + (void)snprintf(buf, sizeof(buf), "%u", (uint32_t) v); + if (file_printf(ms, F(ms, m, "%s"), buf) == -1) return -1; break; default: - if (file_printf(ms, m->desc, (uint32_t) v) == -1) + if (file_printf(ms, F(ms, m, "%u"), (uint32_t) v) == -1) return -1; break; } @@ -445,8 +482,21 @@ mprint(struct magic_set *ms, struct magic *m) case FILE_BEQUAD: case FILE_LEQUAD: v = file_signextend(ms, m, p->q); - if (file_printf(ms, m->desc, (uint64_t) v) == -1) + switch (check_fmt(ms, m)) { + case -1: return -1; + case 1: + (void)snprintf(buf, sizeof(buf), "%" INT64_T_FORMAT "u", + (unsigned long long)v); + if (file_printf(ms, F(ms, m, "%s"), buf) == -1) + return -1; + break; + default: + if (file_printf(ms, F(ms, m, "%" INT64_T_FORMAT "u"), + (unsigned long long) v) == -1) + return -1; + break; + } t = ms->offset + sizeof(int64_t); break; @@ -455,7 +505,9 @@ mprint(struct magic_set *ms, struct magic *m) case FILE_BESTRING16: case FILE_LESTRING16: if (m->reln == '=' || m->reln == '!') { - if (file_printf(ms, m->desc, m->value.s) == -1) + if (file_printf(ms, F(ms, m, "%s"), + file_printable(sbuf, sizeof(sbuf), m->value.s)) + == -1) return -1; t = ms->offset + m->vallen; } @@ -481,7 +533,8 @@ mprint(struct magic_set *ms, struct magic *m) *++last = '\0'; } - if (file_printf(ms, m->desc, str) == -1) + if (file_printf(ms, F(ms, m, "%s"), + file_printable(sbuf, sizeof(sbuf), str)) == -1) return -1; if (m->type == FILE_PSTRING) @@ -493,8 +546,8 @@ mprint(struct magic_set *ms, struct magic *m) case FILE_BEDATE: case FILE_LEDATE: case FILE_MEDATE: - if (file_printf(ms, m->desc, file_fmttime(p->l, FILE_T_LOCAL, - tbuf)) == -1) + if (file_printf(ms, F(ms, m, "%s"), + file_fmttime(p->l + m->num_mask, FILE_T_LOCAL, tbuf)) == -1) return -1; t = ms->offset + sizeof(uint32_t); break; @@ -503,7 +556,8 @@ mprint(struct magic_set *ms, struct magic *m) case FILE_BELDATE: case FILE_LELDATE: case FILE_MELDATE: - if (file_printf(ms, m->desc, file_fmttime(p->l, 0, tbuf)) == -1) + if (file_printf(ms, F(ms, m, "%s"), + file_fmttime(p->l + m->num_mask, 0, tbuf)) == -1) return -1; t = ms->offset + sizeof(uint32_t); break; @@ -511,8 +565,8 @@ mprint(struct magic_set *ms, struct magic *m) case FILE_QDATE: case FILE_BEQDATE: case FILE_LEQDATE: - if (file_printf(ms, m->desc, file_fmttime(p->q, FILE_T_LOCAL, - tbuf)) == -1) + if (file_printf(ms, F(ms, m, "%s"), + file_fmttime(p->q + m->num_mask, FILE_T_LOCAL, tbuf)) == -1) return -1; t = ms->offset + sizeof(uint64_t); break; @@ -520,7 +574,8 @@ mprint(struct magic_set *ms, struct magic *m) case FILE_QLDATE: case FILE_BEQLDATE: case FILE_LEQLDATE: - if (file_printf(ms, m->desc, file_fmttime(p->q, 0, tbuf)) == -1) + if (file_printf(ms, F(ms, m, "%s"), + file_fmttime(p->q + m->num_mask, 0, tbuf)) == -1) return -1; t = ms->offset + sizeof(uint64_t); break; @@ -528,8 +583,8 @@ mprint(struct magic_set *ms, struct magic *m) case FILE_QWDATE: case FILE_BEQWDATE: case FILE_LEQWDATE: - if (file_printf(ms, m->desc, file_fmttime(p->q, FILE_T_WINDOWS, - tbuf)) == -1) + if (file_printf(ms, F(ms, m, "%s"), + file_fmttime(p->q + m->num_mask, FILE_T_WINDOWS, tbuf)) == -1) return -1; t = ms->offset + sizeof(uint64_t); break; @@ -543,11 +598,11 @@ mprint(struct magic_set *ms, struct magic *m) return -1; case 1: (void)snprintf(buf, sizeof(buf), "%g", vf); - if (file_printf(ms, m->desc, buf) == -1) + if (file_printf(ms, F(ms, m, "%s"), buf) == -1) return -1; break; default: - if (file_printf(ms, m->desc, vf) == -1) + if (file_printf(ms, F(ms, m, "%g"), vf) == -1) return -1; break; } @@ -563,11 +618,11 @@ mprint(struct magic_set *ms, struct magic *m) return -1; case 1: (void)snprintf(buf, sizeof(buf), "%g", vd); - if (file_printf(ms, m->desc, buf) == -1) + if (file_printf(ms, F(ms, m, "%s"), buf) == -1) return -1; break; default: - if (file_printf(ms, m->desc, vd) == -1) + if (file_printf(ms, F(ms, m, "%g"), vd) == -1) return -1; break; } @@ -583,7 +638,8 @@ mprint(struct magic_set *ms, struct magic *m) file_oomem(ms, ms->search.rm_len); return -1; } - rval = file_printf(ms, m->desc, cp); + rval = file_printf(ms, F(ms, m, "%s"), + file_printable(sbuf, sizeof(sbuf), cp)); free(cp); if (rval == -1) @@ -597,7 +653,8 @@ mprint(struct magic_set *ms, struct magic *m) } case FILE_SEARCH: - if (file_printf(ms, m->desc, m->value.s) == -1) + if (file_printf(ms, F(ms, m, "%s"), + file_printable(sbuf, sizeof(sbuf), m->value.s)) == -1) return -1; if ((m->str_flags & REGEX_OFFSET_START)) t = ms->search.offset; @@ -606,7 +663,8 @@ mprint(struct magic_set *ms, struct magic *m) break; case FILE_DEFAULT: - if (file_printf(ms, m->desc, m->value.s) == -1) + case FILE_CLEAR: + if (file_printf(ms, "%s", m->desc) == -1) return -1; t = ms->offset; break; @@ -710,9 +768,8 @@ moffset(struct magic_set *ms, struct magic *m) else return CAST(int32_t, (ms->search.offset + m->vallen)); + case FILE_CLEAR: case FILE_DEFAULT: - return ms->offset; - case FILE_INDIRECT: return ms->offset; @@ -864,8 +921,9 @@ private int mconvert(struct magic_set *ms, struct magic *m, int flip) { union VALUETYPE *p = &ms->ms_value; + uint8_t type; - switch (cvt_flip(m->type, flip)) { + switch (type = cvt_flip(m->type, flip)) { case FILE_BYTE: cvt_8(p, m); return 1; @@ -891,10 +949,21 @@ mconvert(struct magic_set *ms, struct magic *m, int flip) return 1; } case FILE_PSTRING: { - char *ptr1 = p->s, *ptr2 = ptr1 + file_pstring_length_size(m); + size_t sz = file_pstring_length_size(m); + char *ptr1 = p->s, *ptr2 = ptr1 + sz; size_t len = file_pstring_get_length(m, ptr1); - if (len >= sizeof(p->s)) - len = sizeof(p->s) - 1; + sz = sizeof(p->s) - sz; /* maximum length of string */ + if (len >= sz) { + /* + * The size of the pascal string length (sz) + * is 1, 2, or 4. We need at least 1 byte for NUL + * termination, but we've already truncated the + * string by p->s, so we need to deduct sz. + * Because we can use one of the bytes of the length + * after we shifted as NUL termination. + */ + len = sz; + } while (len--) *ptr1++ = *ptr2++; *ptr1 = '\0'; @@ -909,7 +978,8 @@ mconvert(struct magic_set *ms, struct magic *m, int flip) case FILE_BELDATE: p->l = (int32_t) ((p->hl[0]<<24)|(p->hl[1]<<16)|(p->hl[2]<<8)|(p->hl[3])); - cvt_32(p, m); + if (type == FILE_BELONG) + cvt_32(p, m); return 1; case FILE_BEQUAD: case FILE_BEQDATE: @@ -920,7 +990,8 @@ mconvert(struct magic_set *ms, struct magic *m, int flip) ((uint64_t)p->hq[2]<<40)|((uint64_t)p->hq[3]<<32)| ((uint64_t)p->hq[4]<<24)|((uint64_t)p->hq[5]<<16)| ((uint64_t)p->hq[6]<<8)|((uint64_t)p->hq[7])); - cvt_64(p, m); + if (type == FILE_BEQUAD) + cvt_64(p, m); return 1; case FILE_LESHORT: p->h = (short)((p->hs[1]<<8)|(p->hs[0])); @@ -931,7 +1002,8 @@ mconvert(struct magic_set *ms, struct magic *m, int flip) case FILE_LELDATE: p->l = (int32_t) ((p->hl[3]<<24)|(p->hl[2]<<16)|(p->hl[1]<<8)|(p->hl[0])); - cvt_32(p, m); + if (type == FILE_LELONG) + cvt_32(p, m); return 1; case FILE_LEQUAD: case FILE_LEQDATE: @@ -942,14 +1014,16 @@ mconvert(struct magic_set *ms, struct magic *m, int flip) ((uint64_t)p->hq[5]<<40)|((uint64_t)p->hq[4]<<32)| ((uint64_t)p->hq[3]<<24)|((uint64_t)p->hq[2]<<16)| ((uint64_t)p->hq[1]<<8)|((uint64_t)p->hq[0])); - cvt_64(p, m); + if (type == FILE_LEQUAD) + cvt_64(p, m); return 1; case FILE_MELONG: case FILE_MEDATE: case FILE_MELDATE: p->l = (int32_t) ((p->hl[1]<<24)|(p->hl[0]<<16)|(p->hl[3]<<8)|(p->hl[2])); - cvt_32(p, m); + if (type == FILE_MELONG) + cvt_32(p, m); return 1; case FILE_FLOAT: cvt_float(p, m); @@ -984,6 +1058,7 @@ mconvert(struct magic_set *ms, struct magic *m, int flip) case FILE_REGEX: case FILE_SEARCH: case FILE_DEFAULT: + case FILE_CLEAR: case FILE_NAME: case FILE_USE: return 1; @@ -997,7 +1072,7 @@ mconvert(struct magic_set *ms, struct magic *m, int flip) private void mdebug(uint32_t offset, const char *str, size_t len) { - (void) fprintf(stderr, "mget/%zu @%d: ", len, offset); + (void) fprintf(stderr, "mget/%" SIZE_T_FORMAT "u @%d: ", len, offset); file_showstr(stderr, str, len); (void) fputc('\n', stderr); (void) fputc('\n', stderr); @@ -1005,7 +1080,7 @@ mdebug(uint32_t offset, const char *str, size_t len) private int mcopy(struct magic_set *ms, union VALUETYPE *p, int type, int indir, - const unsigned char *s, uint32_t offset, size_t nbytes, size_t linecnt) + const unsigned char *s, uint32_t offset, size_t nbytes, struct magic *m) { /* * Note: FILE_SEARCH and FILE_REGEX do not actually copy @@ -1025,15 +1100,29 @@ mcopy(struct magic_set *ms, union VALUETYPE *p, int type, int indir, const char *last; /* end of search region */ const char *buf; /* start of search region */ const char *end; - size_t lines; + size_t lines, linecnt, bytecnt; if (s == NULL) { ms->search.s_len = 0; ms->search.s = NULL; return 0; } + + if (m->str_flags & REGEX_LINE_COUNT) { + linecnt = m->str_range; + bytecnt = linecnt * 80; + } else { + linecnt = 0; + bytecnt = m->str_range; + } + + if (bytecnt == 0) + bytecnt = 8192; + if (bytecnt > nbytes) + bytecnt = nbytes; + buf = RCAST(const char *, s) + offset; - end = last = RCAST(const char *, s) + nbytes; + end = last = RCAST(const char *, s) + bytecnt; /* mget() guarantees buf <= last */ for (lines = linecnt, b = buf; lines && b < end && ((b = CAST(const char *, @@ -1046,7 +1135,7 @@ mcopy(struct magic_set *ms, union VALUETYPE *p, int type, int indir, b++; } if (lines) - last = RCAST(const char *, s) + nbytes; + last = RCAST(const char *, s) + bytecnt; ms->search.s = buf; ms->search.s_len = last - buf; @@ -1065,11 +1154,8 @@ mcopy(struct magic_set *ms, union VALUETYPE *p, int type, int indir, src++; /* check that offset is within range */ - if (offset >= nbytes) { - file_magerror(ms, "invalid offset %u in mcopy()", - offset); - return -1; - } + if (offset >= nbytes) + break; for (/*EMPTY*/; src < esrc; src += 2, dst++) { if (dst < edst) *dst = *src; @@ -1116,23 +1202,39 @@ mcopy(struct magic_set *ms, union VALUETYPE *p, int type, int indir, private int mget(struct magic_set *ms, const unsigned char *s, struct magic *m, size_t nbytes, size_t o, unsigned int cont_level, int mode, int text, - int flip, int *returnval) + int flip, uint16_t indir_level, uint16_t *name_count, + int *printed_something, int *need_separator, int *returnval) { uint32_t offset = ms->offset; - uint32_t count = m->str_range; - int rv; - char *sbuf, *rbuf; + uint32_t lhs; + file_pushbuf_t *pb; + int rv, oneed_separator, in_type; + char *rbuf; union VALUETYPE *p = &ms->ms_value; struct mlist ml; + if (indir_level >= ms->indir_max) { + file_error(ms, 0, "indirect recursion nesting (%hu) exceeded", + indir_level); + return -1; + } + + if (*name_count >= ms->name_max) { + file_error(ms, 0, "name use count (%hu) exceeded", + *name_count); + return -1; + } + if (mcopy(ms, p, m->type, m->flag & INDIR, s, (uint32_t)(offset + o), - (uint32_t)nbytes, count) == -1) + (uint32_t)nbytes, m) == -1) return -1; if ((ms->flags & MAGIC_DEBUG) != 0) { - fprintf(stderr, "mget(type=%d, flag=%x, offset=%u, o=%zu, " - "nbytes=%zu, count=%u)\n", m->type, m->flag, offset, o, - nbytes, count); + fprintf(stderr, "mget(type=%d, flag=%x, offset=%u, o=%" + SIZE_T_FORMAT "u, " "nbytes=%" SIZE_T_FORMAT + "u, il=%hu, nc=%hu)\n", + m->type, m->flag, offset, o, nbytes, + indir_level, *name_count); mdebug(offset, (char *)(void *)p, sizeof(union VALUETYPE)); #ifndef COMPILE_ONLY file_mdump(m); @@ -1178,9 +1280,9 @@ mget(struct magic_set *ms, const unsigned char *s, struct magic *m, if ((ms->flags & MAGIC_DEBUG) != 0) fprintf(stderr, "indirect offs=%u\n", off); } - switch (cvt_flip(m->in_type, flip)) { + switch (in_type = cvt_flip(m->in_type, flip)) { case FILE_BYTE: - if (nbytes < (offset + 1)) + if (OFFSET_OOB(nbytes, offset, 1)) return 0; if (off) { switch (m->in_op & FILE_OPS_MASK) { @@ -1215,111 +1317,79 @@ mget(struct magic_set *ms, const unsigned char *s, struct magic *m, offset = ~offset; break; case FILE_BESHORT: - if (nbytes < (offset + 2)) + if (OFFSET_OOB(nbytes, offset, 2)) return 0; + lhs = (p->hs[0] << 8) | p->hs[1]; if (off) { switch (m->in_op & FILE_OPS_MASK) { case FILE_OPAND: - offset = (short)((p->hs[0]<<8)| - (p->hs[1])) & - off; + offset = lhs & off; break; case FILE_OPOR: - offset = (short)((p->hs[0]<<8)| - (p->hs[1])) | - off; + offset = lhs | off; break; case FILE_OPXOR: - offset = (short)((p->hs[0]<<8)| - (p->hs[1])) ^ - off; + offset = lhs ^ off; break; case FILE_OPADD: - offset = (short)((p->hs[0]<<8)| - (p->hs[1])) + - off; + offset = lhs + off; break; case FILE_OPMINUS: - offset = (short)((p->hs[0]<<8)| - (p->hs[1])) - - off; + offset = lhs - off; break; case FILE_OPMULTIPLY: - offset = (short)((p->hs[0]<<8)| - (p->hs[1])) * - off; + offset = lhs * off; break; case FILE_OPDIVIDE: - offset = (short)((p->hs[0]<<8)| - (p->hs[1])) / - off; + offset = lhs / off; break; case FILE_OPMODULO: - offset = (short)((p->hs[0]<<8)| - (p->hs[1])) % - off; + offset = lhs % off; break; } } else - offset = (short)((p->hs[0]<<8)| - (p->hs[1])); + offset = lhs; if (m->in_op & FILE_OPINVERSE) offset = ~offset; break; case FILE_LESHORT: - if (nbytes < (offset + 2)) + if (OFFSET_OOB(nbytes, offset, 2)) return 0; + lhs = (p->hs[1] << 8) | p->hs[0]; if (off) { switch (m->in_op & FILE_OPS_MASK) { case FILE_OPAND: - offset = (short)((p->hs[1]<<8)| - (p->hs[0])) & - off; + offset = lhs & off; break; case FILE_OPOR: - offset = (short)((p->hs[1]<<8)| - (p->hs[0])) | - off; + offset = lhs | off; break; case FILE_OPXOR: - offset = (short)((p->hs[1]<<8)| - (p->hs[0])) ^ - off; + offset = lhs ^ off; break; case FILE_OPADD: - offset = (short)((p->hs[1]<<8)| - (p->hs[0])) + - off; + offset = lhs + off; break; case FILE_OPMINUS: - offset = (short)((p->hs[1]<<8)| - (p->hs[0])) - - off; + offset = lhs - off; break; case FILE_OPMULTIPLY: - offset = (short)((p->hs[1]<<8)| - (p->hs[0])) * - off; + offset = lhs * off; break; case FILE_OPDIVIDE: - offset = (short)((p->hs[1]<<8)| - (p->hs[0])) / - off; + offset = lhs / off; break; case FILE_OPMODULO: - offset = (short)((p->hs[1]<<8)| - (p->hs[0])) % - off; + offset = lhs % off; break; } } else - offset = (short)((p->hs[1]<<8)| - (p->hs[0])); + offset = lhs; if (m->in_op & FILE_OPINVERSE) offset = ~offset; break; case FILE_SHORT: - if (nbytes < (offset + 2)) + if (OFFSET_OOB(nbytes, offset, 2)) return 0; if (off) { switch (m->in_op & FILE_OPS_MASK) { @@ -1356,218 +1426,119 @@ mget(struct magic_set *ms, const unsigned char *s, struct magic *m, break; case FILE_BELONG: case FILE_BEID3: - if (nbytes < (offset + 4)) + if (OFFSET_OOB(nbytes, offset, 4)) return 0; + lhs = (p->hl[0] << 24) | (p->hl[1] << 16) | + (p->hl[2] << 8) | p->hl[3]; if (off) { switch (m->in_op & FILE_OPS_MASK) { case FILE_OPAND: - offset = (int32_t)((p->hl[0]<<24)| - (p->hl[1]<<16)| - (p->hl[2]<<8)| - (p->hl[3])) & - off; + offset = lhs & off; break; case FILE_OPOR: - offset = (int32_t)((p->hl[0]<<24)| - (p->hl[1]<<16)| - (p->hl[2]<<8)| - (p->hl[3])) | - off; + offset = lhs | off; break; case FILE_OPXOR: - offset = (int32_t)((p->hl[0]<<24)| - (p->hl[1]<<16)| - (p->hl[2]<<8)| - (p->hl[3])) ^ - off; + offset = lhs ^ off; break; case FILE_OPADD: - offset = (int32_t)((p->hl[0]<<24)| - (p->hl[1]<<16)| - (p->hl[2]<<8)| - (p->hl[3])) + - off; + offset = lhs + off; break; case FILE_OPMINUS: - offset = (int32_t)((p->hl[0]<<24)| - (p->hl[1]<<16)| - (p->hl[2]<<8)| - (p->hl[3])) - - off; + offset = lhs - off; break; case FILE_OPMULTIPLY: - offset = (int32_t)((p->hl[0]<<24)| - (p->hl[1]<<16)| - (p->hl[2]<<8)| - (p->hl[3])) * - off; + offset = lhs * off; break; case FILE_OPDIVIDE: - offset = (int32_t)((p->hl[0]<<24)| - (p->hl[1]<<16)| - (p->hl[2]<<8)| - (p->hl[3])) / - off; + offset = lhs / off; break; case FILE_OPMODULO: - offset = (int32_t)((p->hl[0]<<24)| - (p->hl[1]<<16)| - (p->hl[2]<<8)| - (p->hl[3])) % - off; + offset = lhs % off; break; } } else - offset = (int32_t)((p->hl[0]<<24)| - (p->hl[1]<<16)| - (p->hl[2]<<8)| - (p->hl[3])); + offset = lhs; if (m->in_op & FILE_OPINVERSE) offset = ~offset; break; case FILE_LELONG: case FILE_LEID3: - if (nbytes < (offset + 4)) + if (OFFSET_OOB(nbytes, offset, 4)) return 0; + lhs = (p->hl[3] << 24) | (p->hl[2] << 16) | + (p->hl[1] << 8) | p->hl[0]; if (off) { switch (m->in_op & FILE_OPS_MASK) { case FILE_OPAND: - offset = (int32_t)((p->hl[3]<<24)| - (p->hl[2]<<16)| - (p->hl[1]<<8)| - (p->hl[0])) & - off; + offset = lhs & off; break; case FILE_OPOR: - offset = (int32_t)((p->hl[3]<<24)| - (p->hl[2]<<16)| - (p->hl[1]<<8)| - (p->hl[0])) | - off; + offset = lhs | off; break; case FILE_OPXOR: - offset = (int32_t)((p->hl[3]<<24)| - (p->hl[2]<<16)| - (p->hl[1]<<8)| - (p->hl[0])) ^ - off; + offset = lhs ^ off; break; case FILE_OPADD: - offset = (int32_t)((p->hl[3]<<24)| - (p->hl[2]<<16)| - (p->hl[1]<<8)| - (p->hl[0])) + - off; + offset = lhs + off; break; case FILE_OPMINUS: - offset = (int32_t)((p->hl[3]<<24)| - (p->hl[2]<<16)| - (p->hl[1]<<8)| - (p->hl[0])) - - off; + offset = lhs - off; break; case FILE_OPMULTIPLY: - offset = (int32_t)((p->hl[3]<<24)| - (p->hl[2]<<16)| - (p->hl[1]<<8)| - (p->hl[0])) * - off; + offset = lhs * off; break; case FILE_OPDIVIDE: - offset = (int32_t)((p->hl[3]<<24)| - (p->hl[2]<<16)| - (p->hl[1]<<8)| - (p->hl[0])) / - off; + offset = lhs / off; break; case FILE_OPMODULO: - offset = (int32_t)((p->hl[3]<<24)| - (p->hl[2]<<16)| - (p->hl[1]<<8)| - (p->hl[0])) % - off; + offset = lhs % off; break; } } else - offset = (int32_t)((p->hl[3]<<24)| - (p->hl[2]<<16)| - (p->hl[1]<<8)| - (p->hl[0])); + offset = lhs; if (m->in_op & FILE_OPINVERSE) offset = ~offset; break; case FILE_MELONG: - if (nbytes < (offset + 4)) + if (OFFSET_OOB(nbytes, offset, 4)) return 0; + lhs = (p->hl[1] << 24) | (p->hl[0] << 16) | + (p->hl[3] << 8) | p->hl[2]; if (off) { switch (m->in_op & FILE_OPS_MASK) { case FILE_OPAND: - offset = (int32_t)((p->hl[1]<<24)| - (p->hl[0]<<16)| - (p->hl[3]<<8)| - (p->hl[2])) & - off; + offset = lhs & off; break; case FILE_OPOR: - offset = (int32_t)((p->hl[1]<<24)| - (p->hl[0]<<16)| - (p->hl[3]<<8)| - (p->hl[2])) | - off; + offset = lhs | off; break; case FILE_OPXOR: - offset = (int32_t)((p->hl[1]<<24)| - (p->hl[0]<<16)| - (p->hl[3]<<8)| - (p->hl[2])) ^ - off; + offset = lhs ^ off; break; case FILE_OPADD: - offset = (int32_t)((p->hl[1]<<24)| - (p->hl[0]<<16)| - (p->hl[3]<<8)| - (p->hl[2])) + - off; + offset = lhs + off; break; case FILE_OPMINUS: - offset = (int32_t)((p->hl[1]<<24)| - (p->hl[0]<<16)| - (p->hl[3]<<8)| - (p->hl[2])) - - off; + offset = lhs - off; break; case FILE_OPMULTIPLY: - offset = (int32_t)((p->hl[1]<<24)| - (p->hl[0]<<16)| - (p->hl[3]<<8)| - (p->hl[2])) * - off; + offset = lhs * off; break; case FILE_OPDIVIDE: - offset = (int32_t)((p->hl[1]<<24)| - (p->hl[0]<<16)| - (p->hl[3]<<8)| - (p->hl[2])) / - off; + offset = lhs / off; break; case FILE_OPMODULO: - offset = (int32_t)((p->hl[1]<<24)| - (p->hl[0]<<16)| - (p->hl[3]<<8)| - (p->hl[2])) % - off; + offset = lhs % off; break; } } else - offset = (int32_t)((p->hl[1]<<24)| - (p->hl[0]<<16)| - (p->hl[3]<<8)| - (p->hl[2])); + offset = lhs; if (m->in_op & FILE_OPINVERSE) offset = ~offset; break; case FILE_LONG: - if (nbytes < (offset + 4)) + if (OFFSET_OOB(nbytes, offset, 4)) return 0; if (off) { switch (m->in_op & FILE_OPS_MASK) { @@ -1601,9 +1572,11 @@ mget(struct magic_set *ms, const unsigned char *s, struct magic *m, if (m->in_op & FILE_OPINVERSE) offset = ~offset; break; + default: + break; } - switch (cvt_flip(m->in_type, flip)) { + switch (in_type) { case FILE_LEID3: case FILE_BEID3: offset = ((((offset >> 0) & 0x7f) << 0) | @@ -1617,10 +1590,16 @@ mget(struct magic_set *ms, const unsigned char *s, struct magic *m, if (m->flag & INDIROFFADD) { offset += ms->c.li[cont_level-1].off; + if (offset == 0) { + if ((ms->flags & MAGIC_DEBUG) != 0) + fprintf(stderr, + "indirect *zero* offset\n"); + return 0; + } if ((ms->flags & MAGIC_DEBUG) != 0) fprintf(stderr, "indirect +offs=%u\n", offset); } - if (mcopy(ms, p, m->type, 0, s, offset, nbytes, count) == -1) + if (mcopy(ms, p, m->type, 0, s, offset, nbytes, m) == -1) return -1; ms->offset = offset; @@ -1636,14 +1615,14 @@ mget(struct magic_set *ms, const unsigned char *s, struct magic *m, /* Verify we have enough data to match magic type */ switch (m->type) { case FILE_BYTE: - if (nbytes < (offset + 1)) /* should alway be true */ + if (OFFSET_OOB(nbytes, offset, 1)) return 0; break; case FILE_SHORT: case FILE_BESHORT: case FILE_LESHORT: - if (nbytes < (offset + 2)) + if (OFFSET_OOB(nbytes, offset, 2)) return 0; break; @@ -1662,21 +1641,21 @@ mget(struct magic_set *ms, const unsigned char *s, struct magic *m, case FILE_FLOAT: case FILE_BEFLOAT: case FILE_LEFLOAT: - if (nbytes < (offset + 4)) + if (OFFSET_OOB(nbytes, offset, 4)) return 0; break; case FILE_DOUBLE: case FILE_BEDOUBLE: case FILE_LEDOUBLE: - if (nbytes < (offset + 8)) + if (OFFSET_OOB(nbytes, offset, 8)) return 0; break; case FILE_STRING: case FILE_PSTRING: case FILE_SEARCH: - if (nbytes < (offset + m->vallen)) + if (OFFSET_OOB(nbytes, offset, m->vallen)) return 0; break; @@ -1686,49 +1665,70 @@ mget(struct magic_set *ms, const unsigned char *s, struct magic *m, break; case FILE_INDIRECT: + if (m->str_flags & INDIRECT_RELATIVE) + offset += o; + if (offset == 0) + return 0; + if (nbytes < offset) return 0; - sbuf = ms->o.buf; - ms->o.buf = NULL; - ms->offset = 0; + + if ((pb = file_push_buffer(ms)) == NULL) + return -1; + rv = file_softmagic(ms, s + offset, nbytes - offset, - BINTEST, text); + indir_level + 1, name_count, BINTEST, text); + if ((ms->flags & MAGIC_DEBUG) != 0) fprintf(stderr, "indirect @offs=%u[%d]\n", offset, rv); + + rbuf = file_pop_buffer(ms, pb); + if (rbuf == NULL && ms->event_flags & EVENT_HAD_ERR) + return -1; + if (rv == 1) { - rbuf = ms->o.buf; - ms->o.buf = sbuf; if ((ms->flags & (MAGIC_MIME|MAGIC_APPLE)) == 0 && - file_printf(ms, m->desc, offset) == -1) + file_printf(ms, F(ms, m, "%u"), offset) == -1) { + free(rbuf); return -1; - if (file_printf(ms, "%s", rbuf) == -1) + } + if (file_printf(ms, "%s", rbuf) == -1) { + free(rbuf); return -1; - free(rbuf); - } else - ms->o.buf = sbuf; + } + } + free(rbuf); return rv; case FILE_USE: if (nbytes < offset) return 0; - sbuf = m->value.s; - if (*sbuf == '^') { - sbuf++; - flip = 1; - } else - flip = 0; - if (file_magicfind(ms, sbuf, &ml) == -1) { - file_error(ms, 0, "cannot find entry `%s'", sbuf); + rbuf = m->value.s; + if (*rbuf == '^') { + rbuf++; + flip = !flip; + } + if (file_magicfind(ms, rbuf, &ml) == -1) { + file_error(ms, 0, "cannot find entry `%s'", rbuf); return -1; } - return match(ms, ml.magic, ml.nmagic, s, nbytes, offset, - mode, text, flip, returnval); + (*name_count)++; + oneed_separator = *need_separator; + if (m->flag & NOSPACE) + *need_separator = 0; + rv = match(ms, ml.magic, ml.nmagic, s, nbytes, offset + o, + mode, text, flip, indir_level, name_count, + printed_something, need_separator, returnval); + if (rv != 1) + *need_separator = oneed_separator; + return rv; case FILE_NAME: if (file_printf(ms, "%s", m->desc) == -1) return -1; return 1; case FILE_DEFAULT: /* nothing to check */ + case FILE_CLEAR: default: break; } @@ -1890,7 +1890,6 @@ magiccheck(struct magic_set *ms, struct magic *m) break; default: - matched = 0; file_magerror(ms, "cannot happen with float: invalid relation `%c'", m->reln); return -1; @@ -1924,13 +1923,13 @@ magiccheck(struct magic_set *ms, struct magic *m) break; default: - matched = 0; file_magerror(ms, "cannot happen with double: invalid relation `%c'", m->reln); return -1; } return matched; case FILE_DEFAULT: + case FILE_CLEAR: l = 0; v = 0; break; @@ -1962,7 +1961,8 @@ magiccheck(struct magic_set *ms, struct magic *m) if (slen + idx > ms->search.s_len) break; - v = file_strncmp(m->value.s, ms->search.s + idx, slen, m->str_flags); + v = file_strncmp(m->value.s, ms->search.s + idx, slen, + m->str_flags); if (v == 0) { /* found match */ ms->search.offset += idx; break; @@ -1972,37 +1972,49 @@ magiccheck(struct magic_set *ms, struct magic *m) } case FILE_REGEX: { int rc; - regex_t rx; - char errmsg[512]; + file_regex_t rx; + const char *search; if (ms->search.s == NULL) return 0; l = 0; - rc = regcomp(&rx, m->value.s, + rc = file_regcomp(&rx, m->value.s, REG_EXTENDED|REG_NEWLINE| ((m->str_flags & STRING_IGNORE_CASE) ? REG_ICASE : 0)); if (rc) { - (void)regerror(rc, &rx, errmsg, sizeof(errmsg)); - file_magerror(ms, "regex error %d, (%s)", - rc, errmsg); + file_regerror(&rx, rc, ms); v = (uint64_t)-1; - } - else { + } else { regmatch_t pmatch[1]; + size_t slen = ms->search.s_len; #ifndef REG_STARTEND #define REG_STARTEND 0 - size_t l = ms->search.s_len - 1; - char c = ms->search.s[l]; - ((char *)(intptr_t)ms->search.s)[l] = '\0'; + char *copy; + if (slen != 0) { + copy = malloc(slen); + if (copy == NULL) { + file_error(ms, errno, + "can't allocate %" SIZE_T_FORMAT "u bytes", + slen); + return -1; + } + memcpy(copy, ms->search.s, slen); + copy[--slen] = '\0'; + search = copy; + } else { + search = ms->search.s; + copy = NULL; + } #else + search = ms->search.s; pmatch[0].rm_so = 0; - pmatch[0].rm_eo = ms->search.s_len; + pmatch[0].rm_eo = slen; #endif - rc = regexec(&rx, (const char *)ms->search.s, + rc = file_regexec(&rx, (const char *)search, 1, pmatch, REG_STARTEND); #if REG_STARTEND == 0 - ((char *)(intptr_t)ms->search.s)[l] = c; + free(copy); #endif switch (rc) { case 0: @@ -2018,14 +2030,12 @@ magiccheck(struct magic_set *ms, struct magic *m) break; default: - (void)regerror(rc, &rx, errmsg, sizeof(errmsg)); - file_magerror(ms, "regexec error %d, (%s)", - rc, errmsg); + file_regerror(&rx, rc, ms); v = (uint64_t)-1; break; } - regfree(&rx); } + file_regfree(&rx); if (v == (uint64_t)-1) return -1; break; @@ -2122,7 +2132,6 @@ magiccheck(struct magic_set *ms, struct magic *m) break; default: - matched = 0; file_magerror(ms, "cannot happen: invalid relation `%c'", m->reln); return -1; diff --git a/src/strcasestr.c b/src/strcasestr.c new file mode 100644 index 0000000..3db407f --- /dev/null +++ b/src/strcasestr.c @@ -0,0 +1,84 @@ +/* $NetBSD: strcasestr.c,v 1.3 2005/11/29 03:12:00 christos Exp $ */ + +/*- + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Chris Torek. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +__RCSID("$NetBSD: strcasestr.c,v 1.3 2005/11/29 03:12:00 christos Exp $"); +__RCSID("$NetBSD: strncasecmp.c,v 1.2 2007/06/04 18:19:27 christos Exp $"); +#endif /* LIBC_SCCS and not lint */ + +#include "file.h" + +#include <assert.h> +#include <ctype.h> +#include <string.h> + +static int +_strncasecmp(const char *s1, const char *s2, size_t n) +{ + if (n != 0) { + const unsigned char *us1 = (const unsigned char *)s1, + *us2 = (const unsigned char *)s2; + + do { + if (tolower(*us1) != tolower(*us2++)) + return tolower(*us1) - tolower(*--us2); + if (*us1++ == '\0') + break; + } while (--n != 0); + } + return 0; +} + +/* + * Find the first occurrence of find in s, ignore case. + */ +char * +strcasestr(const char *s, const char *find) +{ + char c, sc; + size_t len; + + if ((c = *find++) != 0) { + c = tolower((unsigned char)c); + len = strlen(find); + do { + do { + if ((sc = *s++) == 0) + return (NULL); + } while ((char)tolower((unsigned char)sc) != c); + } while (_strncasecmp(s, find, len) != 0); + s--; + } + return (char *)(intptr_t)(s); +} diff --git a/src/vasprintf.c b/src/vasprintf.c index 648dda4..7a18bed 100644 --- a/src/vasprintf.c +++ b/src/vasprintf.c @@ -108,7 +108,7 @@ you use strange formats. #include "file.h" #ifndef lint -FILE_RCSID("@(#)$File: vasprintf.c,v 1.10 2012/08/09 16:40:04 christos Exp $") +FILE_RCSID("@(#)$File: vasprintf.c,v 1.13 2014/12/04 15:56:46 christos Exp $") #endif /* lint */ #include <assert.h> @@ -559,7 +559,7 @@ static int dispatch(xprintf_struct *s) */ static int core(xprintf_struct *s) { - size_t len, save_len; + size_t save_len; char *dummy_base; /* basic checks */ @@ -584,8 +584,7 @@ static int core(xprintf_struct *s) for (;;) { /* up to end of source string */ if (*(s->src_string) == 0) { - *(s->dest_string) = 0; /* final 0 */ - len = s->real_len + 1; + *(s->dest_string) = '\0'; /* final NUL */ break; } @@ -594,15 +593,13 @@ static int core(xprintf_struct *s) /* up to end of dest string */ if (s->real_len >= s->maxlen) { - (s->buffer_base)[s->maxlen] = 0; /* final 0 */ - len = s->maxlen + 1; + (s->buffer_base)[s->maxlen] = '\0'; /* final NUL */ break; } } /* for (v)asnprintf */ dummy_base = s->buffer_base; - save_len = 0; /* just to avoid a compiler warning */ dummy_base = s->buffer_base + s->real_len; save_len = s->real_len; @@ -636,11 +633,15 @@ int vasprintf(char **ptr, const char *format_string, va_list vargs) #ifdef va_copy va_copy (s.vargs, vargs); #else -#ifdef __va_copy +# ifdef __va_copy __va_copy (s.vargs, vargs); -#else - memcpy (&s.vargs, vargs, sizeof (va_list)); -#endif /* __va_copy */ +# else +# ifdef WIN32 + s.vargs = vargs; +# else + memcpy (&s.vargs, &vargs, sizeof (s.va_args)); +# endif /* WIN32 */ +# endif /* __va_copy */ #endif /* va_copy */ s.maxlen = (size_t)INT_MAX; |