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 /* static int match __P((unsigned char *, int)); */ 45 static char *match __P((unsigned char *, int)); 46 static int mget __P((union VALUETYPE *, 47 unsigned char *, struct magic *, int)); 48 static int mcheck __P((union VALUETYPE *, struct magic *)); 49 static int mconvert __P((union VALUETYPE *, struct magic *)); 50 51 /* 52 * softmagic - lookup one file in database 53 * (already read from /etc/magic by apprentice.c). 54 * Passed the name and FILE * of one file to be typed. 55 */ 56 /*ARGSUSED1*/ /* nbytes passed for regularity, maybe need later */ 57 char * 58 softmagic(buf, nbytes) 59 unsigned char *buf; 60 int nbytes; 61 { 62 return (match(buf, nbytes)); 63 } 64 65 /* 66 * Go through the whole list, stopping if you find a match. Process all 67 * the continuations of that match before returning. 68 * 69 * We support multi-level continuations: 70 * 71 * At any time when processing a successful top-level match, there is a 72 * current continuation level; it represents the level of the last 73 * successfully matched continuation. 74 * 75 * Continuations above that level are skipped as, if we see one, it 76 * means that the continuation that controls them - i.e, the 77 * lower-level continuation preceding them - failed to match. 78 * 79 * Continuations below that level are processed as, if we see one, 80 * it means we've finished processing or skipping higher-level 81 * continuations under the control of a successful or unsuccessful 82 * lower-level continuation, and are now seeing the next lower-level 83 * continuation and should process it. The current continuation 84 * level reverts to the level of the one we're seeing. 85 * 86 * Continuations at the current level are processed as, if we see 87 * one, there's no lower-level continuation that may have failed. 88 * 89 * If a continuation matches, we bump the current continuation level 90 * so that higher-level continuations are processed. 91 */ 92 static char * 93 match(s, nbytes) 94 unsigned char *s; 95 int nbytes; 96 { 97 int magindex = 0; 98 union VALUETYPE p; 99 100 for (magindex = 0; magindex < nmagic; magindex++) { 101 /* if main entry matches, print it... */ 102 if (!mget(&p, s, &magic[magindex], nbytes) || 103 !mcheck(&p, &magic[magindex])) { 104 /* 105 * main entry didn't match, 106 * flush its continuations 107 */ 108 while (magindex < nmagic && 109 magic[magindex + 1].cont_level != 0) 110 magindex++; 111 continue; 112 } 113 114 return (magic[magindex].desc); 115 } 116 return 0; /* no match at all */ 117 } 118 119 120 /* 121 * Convert the byte order of the data we are looking at 122 */ 123 static int 124 mconvert(p, m) 125 union VALUETYPE *p; 126 struct magic *m; 127 { 128 switch (m->type) { 129 case BYTE: 130 case SHORT: 131 case LONG: 132 case DATE: 133 return 1; 134 case STRING: 135 { 136 char *ptr; 137 138 /* Null terminate and eat the return */ 139 p->s[sizeof(p->s) - 1] = '\0'; 140 if ((ptr = strchr(p->s, '\n')) != NULL) 141 *ptr = '\0'; 142 return 1; 143 } 144 case BESHORT: 145 p->h = (short)((p->hs[0]<<8)|(p->hs[1])); 146 return 1; 147 case BELONG: 148 case BEDATE: 149 p->l = (int32) 150 ((p->hl[0]<<24)|(p->hl[1]<<16)|(p->hl[2]<<8)|(p->hl[3])); 151 return 1; 152 case LESHORT: 153 p->h = (short)((p->hs[1]<<8)|(p->hs[0])); 154 return 1; 155 case LELONG: 156 case LEDATE: 157 p->l = (int32) 158 ((p->hl[3]<<24)|(p->hl[2]<<16)|(p->hl[1]<<8)|(p->hl[0])); 159 return 1; 160 default: 161 return 0; 162 } 163 } 164 165 166 static int 167 mget(p, s, m, nbytes) 168 union VALUETYPE* p; 169 unsigned char *s; 170 struct magic *m; 171 int nbytes; 172 { 173 int32 offset = m->offset; 174 175 if (offset + sizeof(union VALUETYPE) <= nbytes) 176 memcpy(p, s + offset, sizeof(union VALUETYPE)); 177 else { 178 /* 179 * the usefulness of padding with zeroes eludes me, it 180 * might even cause problems 181 */ 182 int32 have = nbytes - offset; 183 memset(p, 0, sizeof(union VALUETYPE)); 184 if (have > 0) 185 memcpy(p, s + offset, have); 186 } 187 188 if (!mconvert(p, m)) 189 return 0; 190 191 if (m->flag & INDIR) { 192 193 switch (m->in.type) { 194 case BYTE: 195 offset = p->b + m->in.offset; 196 break; 197 case SHORT: 198 offset = p->h + m->in.offset; 199 break; 200 case LONG: 201 offset = p->l + m->in.offset; 202 break; 203 } 204 205 if (offset + sizeof(union VALUETYPE) > nbytes) 206 return 0; 207 208 memcpy(p, s + offset, sizeof(union VALUETYPE)); 209 210 if (!mconvert(p, m)) 211 return 0; 212 } 213 return 1; 214 } 215 216 static int 217 mcheck(p, m) 218 union VALUETYPE* p; 219 struct magic *m; 220 { 221 register uint32 l = m->value.l; 222 register uint32 v; 223 int matched; 224 225 if ( (m->value.s[0] == 'x') && (m->value.s[1] == '\0') ) { 226 fprintf(stderr, "BOINK"); 227 return 1; 228 } 229 230 231 switch (m->type) { 232 case BYTE: 233 v = p->b; 234 break; 235 236 case SHORT: 237 case BESHORT: 238 case LESHORT: 239 v = p->h; 240 break; 241 242 case LONG: 243 case BELONG: 244 case LELONG: 245 case DATE: 246 case BEDATE: 247 case LEDATE: 248 v = p->l; 249 break; 250 251 case STRING: 252 l = 0; 253 /* What we want here is: 254 * v = strncmp(m->value.s, p->s, m->vallen); 255 * but ignoring any nulls. bcmp doesn't give -/+/0 256 * and isn't universally available anyway. 257 */ 258 v = 0; 259 { 260 register unsigned char *a = (unsigned char*)m->value.s; 261 register unsigned char *b = (unsigned char*)p->s; 262 register int len = m->vallen; 263 264 while (--len >= 0) 265 if ((v = *b++ - *a++) != '\0') 266 break; 267 } 268 break; 269 default: 270 return 0;/*NOTREACHED*/ 271 } 272 273 v = signextend(m, v) & m->mask; 274 275 switch (m->reln) { 276 case 'x': 277 if (debug) 278 (void) fprintf(stderr, "%u == *any* = 1\n", v); 279 matched = 1; 280 break; 281 282 case '!': 283 matched = v != l; 284 if (debug) 285 (void) fprintf(stderr, "%u != %u = %d\n", 286 v, l, matched); 287 break; 288 289 case '=': 290 matched = v == l; 291 if (debug) 292 (void) fprintf(stderr, "%u == %u = %d\n", 293 v, l, matched); 294 break; 295 296 case '>': 297 if (m->flag & UNSIGNED) { 298 matched = v > l; 299 if (debug) 300 (void) fprintf(stderr, "%u > %u = %d\n", 301 v, l, matched); 302 } 303 else { 304 matched = (int32) v > (int32) l; 305 if (debug) 306 (void) fprintf(stderr, "%d > %d = %d\n", 307 v, l, matched); 308 } 309 break; 310 311 case '<': 312 if (m->flag & UNSIGNED) { 313 matched = v < l; 314 if (debug) 315 (void) fprintf(stderr, "%u < %u = %d\n", 316 v, l, matched); 317 } 318 else { 319 matched = (int32) v < (int32) l; 320 if (debug) 321 (void) fprintf(stderr, "%d < %d = %d\n", 322 v, l, matched); 323 } 324 break; 325 326 case '&': 327 matched = (v & l) == l; 328 if (debug) 329 (void) fprintf(stderr, "((%x & %x) == %x) = %d\n", 330 v, l, l, matched); 331 break; 332 333 case '^': 334 matched = (v & l) != l; 335 if (debug) 336 (void) fprintf(stderr, "((%x & %x) != %x) = %d\n", 337 v, l, l, matched); 338 break; 339 340 default: 341 matched = 0; 342 break;/*NOTREACHED*/ 343 } 344 345 return matched; 346 } 347