softmagic.c 11 KB

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