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