funcs.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486
  1. /*
  2. * Copyright (c) Christos Zoulas 2003.
  3. * All Rights Reserved.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions
  7. * are met:
  8. * 1. Redistributions of source code must retain the above copyright
  9. * notice immediately at the beginning of the file, without modification,
  10. * this list of conditions, and the following disclaimer.
  11. * 2. Redistributions in binary form must reproduce the above copyright
  12. * notice, this list of conditions and the following disclaimer in the
  13. * documentation and/or other materials provided with the distribution.
  14. *
  15. * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  16. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  17. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  18. * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
  19. * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  20. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  21. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  22. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  23. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  24. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  25. * SUCH DAMAGE.
  26. */
  27. #include "file.h"
  28. #ifndef lint
  29. FILE_RCSID("@(#)$File: funcs.c,v 1.68 2014/02/18 11:09:31 kim Exp $")
  30. #endif /* lint */
  31. #include "magic.h"
  32. #include <stdarg.h>
  33. #include <stdlib.h>
  34. #include <string.h>
  35. #include <ctype.h>
  36. #if defined(HAVE_WCHAR_H)
  37. #include <wchar.h>
  38. #endif
  39. #if defined(HAVE_WCTYPE_H)
  40. #include <wctype.h>
  41. #endif
  42. #if defined(HAVE_LOCALE_H)
  43. #include <locale.h>
  44. #endif
  45. #ifndef SIZE_MAX
  46. # define SIZE_MAX ((size_t) -1)
  47. #endif
  48. #include "php.h"
  49. #include "main/php_network.h"
  50. #ifndef PREG_OFFSET_CAPTURE
  51. # define PREG_OFFSET_CAPTURE (1<<8)
  52. #endif
  53. extern public void convert_libmagic_pattern(zval *pattern, int options);
  54. protected int
  55. file_printf(struct magic_set *ms, const char *fmt, ...)
  56. {
  57. va_list ap;
  58. int len;
  59. char *buf = NULL, *newstr;
  60. va_start(ap, fmt);
  61. len = vspprintf(&buf, 0, fmt, ap);
  62. va_end(ap);
  63. if (ms->o.buf != NULL) {
  64. len = spprintf(&newstr, 0, "%s%s", ms->o.buf, (buf ? buf : ""));
  65. if (buf) {
  66. efree(buf);
  67. }
  68. efree(ms->o.buf);
  69. ms->o.buf = newstr;
  70. } else {
  71. ms->o.buf = buf;
  72. }
  73. return 0;
  74. }
  75. /*
  76. * error - print best error message possible
  77. */
  78. /*VARARGS*/
  79. private void
  80. file_error_core(struct magic_set *ms, int error, const char *f, va_list va,
  81. size_t lineno)
  82. {
  83. char *buf = NULL;
  84. /* Only the first error is ok */
  85. if (ms->event_flags & EVENT_HAD_ERR)
  86. return;
  87. if (lineno != 0) {
  88. efree(ms->o.buf);
  89. ms->o.buf = NULL;
  90. file_printf(ms, "line %" SIZE_T_FORMAT "u: ", lineno);
  91. }
  92. vspprintf(&buf, 0, f, va);
  93. va_end(va);
  94. if (error > 0) {
  95. file_printf(ms, "%s (%s)", (*buf ? buf : ""), strerror(error));
  96. } else if (*buf) {
  97. file_printf(ms, "%s", buf);
  98. }
  99. if (buf) {
  100. efree(buf);
  101. }
  102. ms->event_flags |= EVENT_HAD_ERR;
  103. ms->error = error;
  104. }
  105. /*VARARGS*/
  106. protected void
  107. file_error(struct magic_set *ms, int error, const char *f, ...)
  108. {
  109. va_list va;
  110. va_start(va, f);
  111. file_error_core(ms, error, f, va, 0);
  112. va_end(va);
  113. }
  114. /*
  115. * Print an error with magic line number.
  116. */
  117. /*VARARGS*/
  118. protected void
  119. file_magerror(struct magic_set *ms, const char *f, ...)
  120. {
  121. va_list va;
  122. va_start(va, f);
  123. file_error_core(ms, 0, f, va, ms->line);
  124. va_end(va);
  125. }
  126. protected void
  127. file_oomem(struct magic_set *ms, size_t len)
  128. {
  129. file_error(ms, errno, "cannot allocate %" SIZE_T_FORMAT "u bytes",
  130. len);
  131. }
  132. protected void
  133. file_badseek(struct magic_set *ms)
  134. {
  135. file_error(ms, errno, "error seeking");
  136. }
  137. protected void
  138. file_badread(struct magic_set *ms)
  139. {
  140. file_error(ms, errno, "error reading");
  141. }
  142. protected int
  143. file_buffer(struct magic_set *ms, php_stream *stream, const char *inname, const void *buf,
  144. size_t nb)
  145. {
  146. int m = 0, rv = 0, looks_text = 0;
  147. int mime = ms->flags & MAGIC_MIME;
  148. const unsigned char *ubuf = CAST(const unsigned char *, buf);
  149. unichar *u8buf = NULL;
  150. size_t ulen;
  151. const char *code = NULL;
  152. const char *code_mime = "binary";
  153. const char *type = "application/octet-stream";
  154. const char *def = "data";
  155. const char *ftype = NULL;
  156. if (nb == 0) {
  157. def = "empty";
  158. type = "application/x-empty";
  159. goto simple;
  160. } else if (nb == 1) {
  161. def = "very short file (no magic)";
  162. goto simple;
  163. }
  164. if ((ms->flags & MAGIC_NO_CHECK_ENCODING) == 0) {
  165. looks_text = file_encoding(ms, ubuf, nb, &u8buf, &ulen,
  166. &code, &code_mime, &ftype);
  167. }
  168. #ifdef __EMX__
  169. if ((ms->flags & MAGIC_NO_CHECK_APPTYPE) == 0 && inname) {
  170. switch (file_os2_apptype(ms, inname, buf, nb)) {
  171. case -1:
  172. return -1;
  173. case 0:
  174. break;
  175. default:
  176. return 1;
  177. }
  178. }
  179. #endif
  180. #if PHP_FILEINFO_UNCOMPRESS
  181. if ((ms->flags & MAGIC_NO_CHECK_COMPRESS) == 0)
  182. if ((m = file_zmagic(ms, stream, inname, ubuf, nb)) != 0) {
  183. if ((ms->flags & MAGIC_DEBUG) != 0)
  184. (void)fprintf(stderr, "zmagic %d\n", m);
  185. goto done_encoding;
  186. }
  187. #endif
  188. /* Check if we have a tar file */
  189. if ((ms->flags & MAGIC_NO_CHECK_TAR) == 0)
  190. if ((m = file_is_tar(ms, ubuf, nb)) != 0) {
  191. if ((ms->flags & MAGIC_DEBUG) != 0)
  192. (void)fprintf(stderr, "tar %d\n", m);
  193. goto done;
  194. }
  195. /* Check if we have a CDF file */
  196. if ((ms->flags & MAGIC_NO_CHECK_CDF) == 0) {
  197. php_socket_t fd;
  198. TSRMLS_FETCH();
  199. if (stream && SUCCESS == php_stream_cast(stream, PHP_STREAM_AS_FD, (void **)&fd, 0)) {
  200. if ((m = file_trycdf(ms, fd, ubuf, nb)) != 0) {
  201. if ((ms->flags & MAGIC_DEBUG) != 0)
  202. (void)fprintf(stderr, "cdf %d\n", m);
  203. goto done;
  204. }
  205. }
  206. }
  207. /* try soft magic tests */
  208. if ((ms->flags & MAGIC_NO_CHECK_SOFT) == 0)
  209. if ((m = file_softmagic(ms, ubuf, nb, 0, BINTEST,
  210. looks_text)) != 0) {
  211. if ((ms->flags & MAGIC_DEBUG) != 0)
  212. (void)fprintf(stderr, "softmagic %d\n", m);
  213. #ifdef BUILTIN_ELF
  214. if ((ms->flags & MAGIC_NO_CHECK_ELF) == 0 && m == 1 &&
  215. nb > 5 && fd != -1) {
  216. /*
  217. * We matched something in the file, so this
  218. * *might* be an ELF file, and the file is at
  219. * least 5 bytes long, so if it's an ELF file
  220. * it has at least one byte past the ELF magic
  221. * number - try extracting information from the
  222. * ELF headers that cannot easily * be
  223. * extracted with rules in the magic file.
  224. */
  225. if ((m = file_tryelf(ms, fd, ubuf, nb)) != 0)
  226. if ((ms->flags & MAGIC_DEBUG) != 0)
  227. (void)fprintf(stderr,
  228. "elf %d\n", m);
  229. }
  230. #endif
  231. goto done;
  232. }
  233. /* try text properties */
  234. if ((ms->flags & MAGIC_NO_CHECK_TEXT) == 0) {
  235. if ((m = file_ascmagic(ms, ubuf, nb, looks_text)) != 0) {
  236. if ((ms->flags & MAGIC_DEBUG) != 0)
  237. (void)fprintf(stderr, "ascmagic %d\n", m);
  238. goto done;
  239. }
  240. /* try to discover text encoding */
  241. if ((ms->flags & MAGIC_NO_CHECK_ENCODING) == 0) {
  242. if (looks_text == 0)
  243. if ((m = file_ascmagic_with_encoding( ms, ubuf,
  244. nb, u8buf, ulen, code, ftype, looks_text))
  245. != 0) {
  246. if ((ms->flags & MAGIC_DEBUG) != 0)
  247. (void)fprintf(stderr,
  248. "ascmagic/enc %d\n", m);
  249. goto done;
  250. }
  251. }
  252. }
  253. simple:
  254. /* give up */
  255. m = 1;
  256. if ((!mime || (mime & MAGIC_MIME_TYPE)) &&
  257. file_printf(ms, "%s", mime ? type : def) == -1) {
  258. rv = -1;
  259. }
  260. done:
  261. if ((ms->flags & MAGIC_MIME_ENCODING) != 0) {
  262. if (ms->flags & MAGIC_MIME_TYPE)
  263. if (file_printf(ms, "; charset=") == -1)
  264. rv = -1;
  265. if (file_printf(ms, "%s", code_mime) == -1)
  266. rv = -1;
  267. }
  268. done_encoding:
  269. free(u8buf);
  270. if (rv)
  271. return rv;
  272. return m;
  273. }
  274. protected int
  275. file_reset(struct magic_set *ms)
  276. {
  277. if (ms->mlist[0] == NULL) {
  278. file_error(ms, 0, "no magic files loaded");
  279. return -1;
  280. }
  281. if (ms->o.buf) {
  282. efree(ms->o.buf);
  283. ms->o.buf = NULL;
  284. }
  285. if (ms->o.pbuf) {
  286. efree(ms->o.pbuf);
  287. ms->o.pbuf = NULL;
  288. }
  289. ms->event_flags &= ~EVENT_HAD_ERR;
  290. ms->error = -1;
  291. return 0;
  292. }
  293. #define OCTALIFY(n, o) \
  294. /*LINTED*/ \
  295. (void)(*(n)++ = '\\', \
  296. *(n)++ = (((uint32_t)*(o) >> 6) & 3) + '0', \
  297. *(n)++ = (((uint32_t)*(o) >> 3) & 7) + '0', \
  298. *(n)++ = (((uint32_t)*(o) >> 0) & 7) + '0', \
  299. (o)++)
  300. protected const char *
  301. file_getbuffer(struct magic_set *ms)
  302. {
  303. char *op, *np;
  304. size_t psize, len;
  305. if (ms->event_flags & EVENT_HAD_ERR)
  306. return NULL;
  307. if (ms->flags & MAGIC_RAW)
  308. return ms->o.buf;
  309. if (ms->o.buf == NULL)
  310. return NULL;
  311. /* * 4 is for octal representation, + 1 is for NUL */
  312. len = strlen(ms->o.buf);
  313. if (len > (SIZE_MAX - 1) / 4) {
  314. return NULL;
  315. }
  316. psize = len * 4 + 1;
  317. if ((ms->o.pbuf = CAST(char *, erealloc(ms->o.pbuf, psize))) == NULL) {
  318. file_oomem(ms, psize);
  319. return NULL;
  320. }
  321. #if defined(HAVE_WCHAR_H) && defined(HAVE_MBRTOWC) && defined(HAVE_WCWIDTH)
  322. {
  323. mbstate_t state;
  324. wchar_t nextchar;
  325. int mb_conv = 1;
  326. size_t bytesconsumed;
  327. char *eop;
  328. (void)memset(&state, 0, sizeof(mbstate_t));
  329. np = ms->o.pbuf;
  330. op = ms->o.buf;
  331. eop = op + len;
  332. while (op < eop) {
  333. bytesconsumed = mbrtowc(&nextchar, op,
  334. (size_t)(eop - op), &state);
  335. if (bytesconsumed == (size_t)(-1) ||
  336. bytesconsumed == (size_t)(-2)) {
  337. mb_conv = 0;
  338. break;
  339. }
  340. if (iswprint(nextchar)) {
  341. (void)memcpy(np, op, bytesconsumed);
  342. op += bytesconsumed;
  343. np += bytesconsumed;
  344. } else {
  345. while (bytesconsumed-- > 0)
  346. OCTALIFY(np, op);
  347. }
  348. }
  349. *np = '\0';
  350. /* Parsing succeeded as a multi-byte sequence */
  351. if (mb_conv != 0)
  352. return ms->o.pbuf;
  353. }
  354. #endif
  355. for (np = ms->o.pbuf, op = ms->o.buf; *op;) {
  356. if (isprint((unsigned char)*op)) {
  357. *np++ = *op++;
  358. } else {
  359. OCTALIFY(np, op);
  360. }
  361. }
  362. *np = '\0';
  363. return ms->o.pbuf;
  364. }
  365. protected int
  366. file_check_mem(struct magic_set *ms, unsigned int level)
  367. {
  368. size_t len;
  369. if (level >= ms->c.len) {
  370. len = (ms->c.len = 20 + level) * sizeof(*ms->c.li);
  371. ms->c.li = CAST(struct level_info *, (ms->c.li == NULL) ?
  372. emalloc(len) :
  373. erealloc(ms->c.li, len));
  374. if (ms->c.li == NULL) {
  375. file_oomem(ms, len);
  376. return -1;
  377. }
  378. }
  379. ms->c.li[level].got_match = 0;
  380. #ifdef ENABLE_CONDITIONALS
  381. ms->c.li[level].last_match = 0;
  382. ms->c.li[level].last_cond = COND_NONE;
  383. #endif /* ENABLE_CONDITIONALS */
  384. return 0;
  385. }
  386. protected size_t
  387. file_printedlen(const struct magic_set *ms)
  388. {
  389. return ms->o.buf == NULL ? 0 : strlen(ms->o.buf);
  390. }
  391. file_replace(struct magic_set *ms, const char *pat, const char *rep)
  392. {
  393. zval *patt;
  394. int opts = 0;
  395. pcre_cache_entry *pce;
  396. char *res;
  397. zval *repl;
  398. int res_len, rep_cnt = 0;
  399. TSRMLS_FETCH();
  400. (void)setlocale(LC_CTYPE, "C");
  401. MAKE_STD_ZVAL(patt);
  402. ZVAL_STRINGL(patt, pat, strlen(pat), 0);
  403. opts |= PCRE_MULTILINE;
  404. convert_libmagic_pattern(patt, opts);
  405. if ((pce = pcre_get_compiled_regex_cache(Z_STRVAL_P(patt), Z_STRLEN_P(patt) TSRMLS_CC)) == NULL) {
  406. zval_dtor(patt);
  407. FREE_ZVAL(patt);
  408. rep_cnt = -1;
  409. goto out;
  410. }
  411. MAKE_STD_ZVAL(repl);
  412. ZVAL_STRINGL(repl, rep, strlen(rep), 0);
  413. res = php_pcre_replace_impl(pce, ms->o.buf, strlen(ms->o.buf), repl,
  414. 0, &res_len, -1, &rep_cnt TSRMLS_CC);
  415. FREE_ZVAL(repl);
  416. zval_dtor(patt);
  417. FREE_ZVAL(patt);
  418. if (NULL == res) {
  419. rep_cnt = -1;
  420. goto out;
  421. }
  422. strncpy(ms->o.buf, res, res_len);
  423. ms->o.buf[res_len] = '\0';
  424. efree(res);
  425. out:
  426. (void)setlocale(LC_CTYPE, "");
  427. return rep_cnt;
  428. }