softmagic.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518
  1. /*
  2. * softmagic - interpret variable magic from /etc/magic
  3. *
  4. * Copyright (c) Ian F. Darwin, 1987.
  5. * Written by Ian F. Darwin.
  6. *
  7. * This software is not subject to any license of the American Telephone
  8. * and Telegraph Company or of the Regents of the University of California.
  9. *
  10. * Permission is granted to anyone to use this software for any purpose on
  11. * any computer system, and to alter it and redistribute it freely, subject
  12. * to the following restrictions:
  13. *
  14. * 1. The author is not responsible for the consequences of use of this
  15. * software, no matter how awful, even if they arise from flaws in it.
  16. *
  17. * 2. The origin of this software must not be misrepresented, either by
  18. * explicit claim or by omission. Since few users ever read sources,
  19. * credits must appear in the documentation.
  20. *
  21. * 3. Altered versions must be plainly marked as such, and must not be
  22. * misrepresented as being the original software. Since few users
  23. * ever read sources, credits must appear in the documentation.
  24. *
  25. * 4. This notice may not be removed or altered.
  26. */
  27. #include <stdio.h>
  28. #include <string.h>
  29. #include <stdlib.h>
  30. #include <time.h>
  31. #include <sys/types.h>
  32. #ifdef HAVE_CONFIG_H
  33. #include "config.h"
  34. #endif
  35. #include "file.h"
  36. #ifndef lint
  37. static char *moduleid =
  38. "@(#)$Id: softmagic.c,v 1.36 1998/02/15 23:18:53 christos Exp $";
  39. #endif /* lint */
  40. static int match __P((unsigned char *, int));
  41. static int mget __P((union VALUETYPE *,
  42. unsigned char *, struct magic *, int));
  43. static int mcheck __P((union VALUETYPE *, struct magic *));
  44. static int32 mprint __P((union VALUETYPE *, struct magic *));
  45. static void mdebug __P((int32, char *, int));
  46. static int mconvert __P((union VALUETYPE *, struct magic *));
  47. /*
  48. * softmagic - lookup one file in database
  49. * (already read from /etc/magic by apprentice.c).
  50. * Passed the name and FILE * of one file to be typed.
  51. */
  52. /*ARGSUSED1*/ /* nbytes passed for regularity, maybe need later */
  53. int
  54. softmagic(buf, nbytes)
  55. unsigned char *buf;
  56. int nbytes;
  57. {
  58. if (match(buf, nbytes))
  59. return 1;
  60. return 0;
  61. }
  62. /*
  63. * Go through the whole list, stopping if you find a match. Process all
  64. * the continuations of that match before returning.
  65. *
  66. * We support multi-level continuations:
  67. *
  68. * At any time when processing a successful top-level match, there is a
  69. * current continuation level; it represents the level of the last
  70. * successfully matched continuation.
  71. *
  72. * Continuations above that level are skipped as, if we see one, it
  73. * means that the continuation that controls them - i.e, the
  74. * lower-level continuation preceding them - failed to match.
  75. *
  76. * Continuations below that level are processed as, if we see one,
  77. * it means we've finished processing or skipping higher-level
  78. * continuations under the control of a successful or unsuccessful
  79. * lower-level continuation, and are now seeing the next lower-level
  80. * continuation and should process it. The current continuation
  81. * level reverts to the level of the one we're seeing.
  82. *
  83. * Continuations at the current level are processed as, if we see
  84. * one, there's no lower-level continuation that may have failed.
  85. *
  86. * If a continuation matches, we bump the current continuation level
  87. * so that higher-level continuations are processed.
  88. */
  89. static int
  90. match(s, nbytes)
  91. unsigned char *s;
  92. int nbytes;
  93. {
  94. int magindex = 0;
  95. int cont_level = 0;
  96. int need_separator = 0;
  97. union VALUETYPE p;
  98. static int32 *tmpoff = NULL;
  99. static size_t tmplen = 0;
  100. int32 oldoff = 0;
  101. if (tmpoff == NULL)
  102. if ((tmpoff = (int32 *) malloc(tmplen = 20)) == NULL)
  103. error("out of memory\n");
  104. for (magindex = 0; magindex < nmagic; magindex++) {
  105. /* if main entry matches, print it... */
  106. if (!mget(&p, s, &magic[magindex], nbytes) ||
  107. !mcheck(&p, &magic[magindex])) {
  108. /*
  109. * main entry didn't match,
  110. * flush its continuations
  111. */
  112. while (magindex < nmagic &&
  113. magic[magindex + 1].cont_level != 0)
  114. magindex++;
  115. continue;
  116. }
  117. tmpoff[cont_level] = mprint(&p, &magic[magindex]);
  118. /*
  119. * If we printed something, we'll need to print
  120. * a blank before we print something else.
  121. */
  122. if (magic[magindex].desc[0])
  123. need_separator = 1;
  124. /* and any continuations that match */
  125. if (++cont_level >= tmplen)
  126. if ((tmpoff = (int32 *) realloc(tmpoff,
  127. tmplen += 20)) == NULL)
  128. error("out of memory\n");
  129. while (magic[magindex+1].cont_level != 0 &&
  130. ++magindex < nmagic) {
  131. if (cont_level >= magic[magindex].cont_level) {
  132. if (cont_level > magic[magindex].cont_level) {
  133. /*
  134. * We're at the end of the level
  135. * "cont_level" continuations.
  136. */
  137. cont_level = magic[magindex].cont_level;
  138. }
  139. if (magic[magindex].flag & ADD) {
  140. oldoff=magic[magindex].offset;
  141. magic[magindex].offset += tmpoff[cont_level-1];
  142. }
  143. if (mget(&p, s, &magic[magindex], nbytes) &&
  144. mcheck(&p, &magic[magindex])) {
  145. /*
  146. * This continuation matched.
  147. * Print its message, with
  148. * a blank before it if
  149. * the previous item printed
  150. * and this item isn't empty.
  151. */
  152. /* space if previous printed */
  153. if (need_separator
  154. && (magic[magindex].nospflag == 0)
  155. && (magic[magindex].desc[0] != '\0')
  156. ) {
  157. (void) putchar(' ');
  158. need_separator = 0;
  159. }
  160. tmpoff[cont_level] = mprint(&p, &magic[magindex]);
  161. if (magic[magindex].desc[0])
  162. need_separator = 1;
  163. /*
  164. * If we see any continuations
  165. * at a higher level,
  166. * process them.
  167. */
  168. if (++cont_level >= tmplen)
  169. if ((tmpoff =
  170. (int32 *) realloc(tmpoff,
  171. tmplen += 20)) == NULL)
  172. error("out of memory\n");
  173. }
  174. if (magic[magindex].flag & ADD) {
  175. magic[magindex].offset = oldoff;
  176. }
  177. }
  178. }
  179. return 1; /* all through */
  180. }
  181. return 0; /* no match at all */
  182. }
  183. static int32
  184. mprint(p, m)
  185. union VALUETYPE *p;
  186. struct magic *m;
  187. {
  188. char *pp, *rt;
  189. uint32 v;
  190. time_t time;
  191. int32 t=0 ;
  192. switch (m->type) {
  193. case BYTE:
  194. v = p->b;
  195. v = signextend(m, v) & m->mask;
  196. (void) printf(m->desc, (unsigned char) v);
  197. t = m->offset + sizeof(char);
  198. break;
  199. case SHORT:
  200. case BESHORT:
  201. case LESHORT:
  202. v = p->h;
  203. v = signextend(m, v) & m->mask;
  204. (void) printf(m->desc, (unsigned short) v);
  205. t = m->offset + sizeof(short);
  206. break;
  207. case LONG:
  208. case BELONG:
  209. case LELONG:
  210. v = p->l;
  211. v = signextend(m, v) & m->mask;
  212. (void) printf(m->desc, (uint32) v);
  213. t = m->offset + sizeof(int32);
  214. break;
  215. case STRING:
  216. if (m->reln == '=') {
  217. (void) printf(m->desc, m->value.s);
  218. t = m->offset + strlen(m->value.s);
  219. }
  220. else {
  221. if (*m->value.s == '\0') {
  222. char *cp = strchr(p->s,'\n');
  223. if (cp)
  224. *cp = '\0';
  225. }
  226. (void) printf(m->desc, p->s);
  227. t = m->offset + strlen(p->s);
  228. }
  229. break;
  230. case DATE:
  231. case BEDATE:
  232. case LEDATE:
  233. time = p->l;
  234. pp = ctime(&time);
  235. if ((rt = strchr(pp, '\n')) != NULL)
  236. *rt = '\0';
  237. (void) printf(m->desc, pp);
  238. t = m->offset + sizeof(time_t);
  239. break;
  240. default:
  241. error("invalid m->type (%d) in mprint().\n", m->type);
  242. /*NOTREACHED*/
  243. }
  244. return(t);
  245. }
  246. /*
  247. * Convert the byte order of the data we are looking at
  248. */
  249. static int
  250. mconvert(p, m)
  251. union VALUETYPE *p;
  252. struct magic *m;
  253. {
  254. switch (m->type) {
  255. case BYTE:
  256. case SHORT:
  257. case LONG:
  258. case DATE:
  259. return 1;
  260. case STRING:
  261. {
  262. char *ptr;
  263. /* Null terminate and eat the return */
  264. p->s[sizeof(p->s) - 1] = '\0';
  265. if ((ptr = strchr(p->s, '\n')) != NULL)
  266. *ptr = '\0';
  267. return 1;
  268. }
  269. case BESHORT:
  270. p->h = (short)((p->hs[0]<<8)|(p->hs[1]));
  271. return 1;
  272. case BELONG:
  273. case BEDATE:
  274. p->l = (int32)
  275. ((p->hl[0]<<24)|(p->hl[1]<<16)|(p->hl[2]<<8)|(p->hl[3]));
  276. return 1;
  277. case LESHORT:
  278. p->h = (short)((p->hs[1]<<8)|(p->hs[0]));
  279. return 1;
  280. case LELONG:
  281. case LEDATE:
  282. p->l = (int32)
  283. ((p->hl[3]<<24)|(p->hl[2]<<16)|(p->hl[1]<<8)|(p->hl[0]));
  284. return 1;
  285. default:
  286. error("invalid type %d in mconvert().\n", m->type);
  287. return 0;
  288. }
  289. }
  290. static void
  291. mdebug(offset, str, len)
  292. int32 offset;
  293. char *str;
  294. int len;
  295. {
  296. (void) fprintf(stderr, "mget @%d: ", offset);
  297. showstr(stderr, (char *) str, len);
  298. (void) fputc('\n', stderr);
  299. (void) fputc('\n', stderr);
  300. }
  301. static int
  302. mget(p, s, m, nbytes)
  303. union VALUETYPE* p;
  304. unsigned char *s;
  305. struct magic *m;
  306. int nbytes;
  307. {
  308. int32 offset = m->offset;
  309. if (offset + sizeof(union VALUETYPE) <= nbytes)
  310. memcpy(p, s + offset, sizeof(union VALUETYPE));
  311. else {
  312. /*
  313. * the usefulness of padding with zeroes eludes me, it
  314. * might even cause problems
  315. */
  316. int32 have = nbytes - offset;
  317. memset(p, 0, sizeof(union VALUETYPE));
  318. if (have > 0)
  319. memcpy(p, s + offset, have);
  320. }
  321. if (debug) {
  322. mdebug(offset, (char *) p, sizeof(union VALUETYPE));
  323. mdump(m);
  324. }
  325. if (!mconvert(p, m))
  326. return 0;
  327. if (m->flag & INDIR) {
  328. switch (m->in.type) {
  329. case BYTE:
  330. offset = p->b + m->in.offset;
  331. break;
  332. case SHORT:
  333. offset = p->h + m->in.offset;
  334. break;
  335. case LONG:
  336. offset = p->l + m->in.offset;
  337. break;
  338. }
  339. if (offset + sizeof(union VALUETYPE) > nbytes)
  340. return 0;
  341. memcpy(p, s + offset, sizeof(union VALUETYPE));
  342. if (debug) {
  343. mdebug(offset, (char *) p, sizeof(union VALUETYPE));
  344. mdump(m);
  345. }
  346. if (!mconvert(p, m))
  347. return 0;
  348. }
  349. return 1;
  350. }
  351. static int
  352. mcheck(p, m)
  353. union VALUETYPE* p;
  354. struct magic *m;
  355. {
  356. register uint32 l = m->value.l;
  357. register uint32 v;
  358. int matched;
  359. if ( (m->value.s[0] == 'x') && (m->value.s[1] == '\0') ) {
  360. fprintf(stderr, "BOINK");
  361. return 1;
  362. }
  363. switch (m->type) {
  364. case BYTE:
  365. v = p->b;
  366. break;
  367. case SHORT:
  368. case BESHORT:
  369. case LESHORT:
  370. v = p->h;
  371. break;
  372. case LONG:
  373. case BELONG:
  374. case LELONG:
  375. case DATE:
  376. case BEDATE:
  377. case LEDATE:
  378. v = p->l;
  379. break;
  380. case STRING:
  381. l = 0;
  382. /* What we want here is:
  383. * v = strncmp(m->value.s, p->s, m->vallen);
  384. * but ignoring any nulls. bcmp doesn't give -/+/0
  385. * and isn't universally available anyway.
  386. */
  387. v = 0;
  388. {
  389. register unsigned char *a = (unsigned char*)m->value.s;
  390. register unsigned char *b = (unsigned char*)p->s;
  391. register int len = m->vallen;
  392. while (--len >= 0)
  393. if ((v = *b++ - *a++) != '\0')
  394. break;
  395. }
  396. break;
  397. default:
  398. error("invalid type %d in mcheck().\n", m->type);
  399. return 0;/*NOTREACHED*/
  400. }
  401. v = signextend(m, v) & m->mask;
  402. switch (m->reln) {
  403. case 'x':
  404. if (debug)
  405. (void) fprintf(stderr, "%u == *any* = 1\n", v);
  406. matched = 1;
  407. break;
  408. case '!':
  409. matched = v != l;
  410. if (debug)
  411. (void) fprintf(stderr, "%u != %u = %d\n",
  412. v, l, matched);
  413. break;
  414. case '=':
  415. matched = v == l;
  416. if (debug)
  417. (void) fprintf(stderr, "%u == %u = %d\n",
  418. v, l, matched);
  419. break;
  420. case '>':
  421. if (m->flag & UNSIGNED) {
  422. matched = v > l;
  423. if (debug)
  424. (void) fprintf(stderr, "%u > %u = %d\n",
  425. v, l, matched);
  426. }
  427. else {
  428. matched = (int32) v > (int32) l;
  429. if (debug)
  430. (void) fprintf(stderr, "%d > %d = %d\n",
  431. v, l, matched);
  432. }
  433. break;
  434. case '<':
  435. if (m->flag & UNSIGNED) {
  436. matched = v < l;
  437. if (debug)
  438. (void) fprintf(stderr, "%u < %u = %d\n",
  439. v, l, matched);
  440. }
  441. else {
  442. matched = (int32) v < (int32) l;
  443. if (debug)
  444. (void) fprintf(stderr, "%d < %d = %d\n",
  445. v, l, matched);
  446. }
  447. break;
  448. case '&':
  449. matched = (v & l) == l;
  450. if (debug)
  451. (void) fprintf(stderr, "((%x & %x) == %x) = %d\n",
  452. v, l, l, matched);
  453. break;
  454. case '^':
  455. matched = (v & l) != l;
  456. if (debug)
  457. (void) fprintf(stderr, "((%x & %x) != %x) = %d\n",
  458. v, l, l, matched);
  459. break;
  460. default:
  461. matched = 0;
  462. error("mcheck: can't happen: invalid relation %d.\n", m->reln);
  463. break;/*NOTREACHED*/
  464. }
  465. return matched;
  466. }