]> CyberLeo.Net >> Repos - FreeBSD/releng/10.1.git/blob - contrib/file/src/magic.c
Update base system file(1) to 5.22 to address multiple denial of
[FreeBSD/releng/10.1.git] / contrib / file / src / magic.c
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
28 #ifdef WIN32
29 #include <windows.h>
30 #include <shlwapi.h>
31 #endif
32
33 #include "file.h"
34
35 #ifndef lint
36 FILE_RCSID("@(#)$File: magic.c,v 1.91 2014/12/16 23:18:40 christos Exp $")
37 #endif  /* lint */
38
39 #include "magic.h"
40
41 #include <stdlib.h>
42 #include <unistd.h>
43 #include <string.h>
44 #ifdef QUICK
45 #include <sys/mman.h>
46 #endif
47 #ifdef HAVE_LIMITS_H
48 #include <limits.h>     /* for PIPE_BUF */
49 #endif
50
51 #if defined(HAVE_UTIMES)
52 # include <sys/time.h>
53 #elif defined(HAVE_UTIME)
54 # if defined(HAVE_SYS_UTIME_H)
55 #  include <sys/utime.h>
56 # elif defined(HAVE_UTIME_H)
57 #  include <utime.h>
58 # endif
59 #endif
60
61 #ifdef HAVE_UNISTD_H
62 #include <unistd.h>     /* for read() */
63 #endif
64
65 #ifndef PIPE_BUF
66 /* Get the PIPE_BUF from pathconf */
67 #ifdef _PC_PIPE_BUF
68 #define PIPE_BUF pathconf(".", _PC_PIPE_BUF)
69 #else
70 #define PIPE_BUF 512
71 #endif
72 #endif
73
74 private void close_and_restore(const struct magic_set *, const char *, int,
75     const struct stat *);
76 private int unreadable_info(struct magic_set *, mode_t, const char *);
77 private const char* get_default_magic(void);
78 #ifndef COMPILE_ONLY
79 private const char *file_or_fd(struct magic_set *, const char *, int);
80 #endif
81
82 #ifndef STDIN_FILENO
83 #define STDIN_FILENO    0
84 #endif
85
86 private const char *
87 get_default_magic(void)
88 {
89         static const char hmagic[] = "/.magic/magic.mgc";
90         static char *default_magic;
91         char *home, *hmagicpath;
92
93 #ifndef WIN32
94         struct stat st;
95
96         if (default_magic) {
97                 free(default_magic);
98                 default_magic = NULL;
99         }
100         if ((home = getenv("HOME")) == NULL)
101                 return MAGIC;
102
103         if (asprintf(&hmagicpath, "%s/.magic.mgc", home) < 0)
104                 return MAGIC;
105         if (stat(hmagicpath, &st) == -1) {
106                 free(hmagicpath);
107                 if (asprintf(&hmagicpath, "%s/.magic", home) < 0)
108                         return MAGIC;
109                 if (stat(hmagicpath, &st) == -1)
110                         goto out;
111                 if (S_ISDIR(st.st_mode)) {
112                         free(hmagicpath);
113                         if (asprintf(&hmagicpath, "%s/%s", home, hmagic) < 0)
114                                 return MAGIC;
115                         if (access(hmagicpath, R_OK) == -1)
116                                 goto out;
117                 }
118         }
119
120         if (asprintf(&default_magic, "%s:%s", hmagicpath, MAGIC) < 0)
121                 goto out;
122         free(hmagicpath);
123         return default_magic;
124 out:
125         default_magic = NULL;
126         free(hmagicpath);
127         return MAGIC;
128 #else
129         char *hmagicp;
130         char *tmppath = NULL;
131         LPTSTR dllpath;
132         hmagicpath = NULL;
133
134 #define APPENDPATH() \
135         do { \
136                 if (tmppath && access(tmppath, R_OK) != -1) { \
137                         if (hmagicpath == NULL) \
138                                 hmagicpath = tmppath; \
139                         else { \
140                                 if (asprintf(&hmagicp, "%s%c%s", hmagicpath, \
141                                     PATHSEP, tmppath) >= 0) { \
142                                         free(hmagicpath); \
143                                         hmagicpath = hmagicp; \
144                                 } \
145                                 free(tmppath); \
146                         } \
147                         tmppath = NULL; \
148                 } \
149         } while (/*CONSTCOND*/0)
150                                 
151         if (default_magic) {
152                 free(default_magic);
153                 default_magic = NULL;
154         }
155
156         /* First, try to get user-specific magic file */
157         if ((home = getenv("LOCALAPPDATA")) == NULL) {
158                 if ((home = getenv("USERPROFILE")) != NULL)
159                         if (asprintf(&tmppath,
160                             "%s/Local Settings/Application Data%s", home,
161                             hmagic) < 0)
162                                 tmppath = NULL;
163         } else {
164                 if (asprintf(&tmppath, "%s%s", home, hmagic) < 0)
165                         tmppath = NULL;
166         }
167
168         APPENDPATH();
169
170         /* Second, try to get a magic file from Common Files */
171         if ((home = getenv("COMMONPROGRAMFILES")) != NULL) {
172                 if (asprintf(&tmppath, "%s%s", home, hmagic) >= 0)
173                         APPENDPATH();
174         }
175
176         /* Third, try to get magic file relative to dll location */
177         dllpath = malloc(sizeof(*dllpath) * (MAX_PATH + 1));
178         dllpath[MAX_PATH] = 0;  /* just in case long path gets truncated and not null terminated */
179         if (GetModuleFileNameA(NULL, dllpath, MAX_PATH)){
180                 PathRemoveFileSpecA(dllpath);
181                 if (strlen(dllpath) > 3 &&
182                     stricmp(&dllpath[strlen(dllpath) - 3], "bin") == 0) {
183                         if (asprintf(&tmppath,
184                             "%s/../share/misc/magic.mgc", dllpath) >= 0)
185                                 APPENDPATH();
186                 } else {
187                         if (asprintf(&tmppath,
188                             "%s/share/misc/magic.mgc", dllpath) >= 0)
189                                 APPENDPATH();
190                         else if (asprintf(&tmppath,
191                             "%s/magic.mgc", dllpath) >= 0)
192                                 APPENDPATH();
193                 }
194         }
195
196         /* Don't put MAGIC constant - it likely points to a file within MSys
197         tree */
198         default_magic = hmagicpath;
199         return default_magic;
200 #endif
201 }
202
203 public const char *
204 magic_getpath(const char *magicfile, int action)
205 {
206         if (magicfile != NULL)
207                 return magicfile;
208
209         magicfile = getenv("MAGIC");
210         if (magicfile != NULL)
211                 return magicfile;
212
213         return action == FILE_LOAD ? get_default_magic() : MAGIC;
214 }
215
216 public struct magic_set *
217 magic_open(int flags)
218 {
219         return file_ms_alloc(flags);
220 }
221
222 private int
223 unreadable_info(struct magic_set *ms, mode_t md, const char *file)
224 {
225         if (file) {
226                 /* We cannot open it, but we were able to stat it. */
227                 if (access(file, W_OK) == 0)
228                         if (file_printf(ms, "writable, ") == -1)
229                                 return -1;
230                 if (access(file, X_OK) == 0)
231                         if (file_printf(ms, "executable, ") == -1)
232                                 return -1;
233         }
234         if (S_ISREG(md))
235                 if (file_printf(ms, "regular file, ") == -1)
236                         return -1;
237         if (file_printf(ms, "no read permission") == -1)
238                 return -1;
239         return 0;
240 }
241
242 public void
243 magic_close(struct magic_set *ms)
244 {
245         if (ms == NULL)
246                 return;
247         file_ms_free(ms);
248 }
249
250 /*
251  * load a magic file
252  */
253 public int
254 magic_load(struct magic_set *ms, const char *magicfile)
255 {
256         if (ms == NULL)
257                 return -1;
258         return file_apprentice(ms, magicfile, FILE_LOAD);
259 }
260
261 #ifndef COMPILE_ONLY
262 /*
263  * Install a set of compiled magic buffers.
264  */
265 public int
266 magic_load_buffers(struct magic_set *ms, void **bufs, size_t *sizes,
267     size_t nbufs)
268 {
269         if (ms == NULL)
270                 return -1;
271         return buffer_apprentice(ms, (struct magic **)bufs, sizes, nbufs);
272 }
273 #endif
274
275 public int
276 magic_compile(struct magic_set *ms, const char *magicfile)
277 {
278         if (ms == NULL)
279                 return -1;
280         return file_apprentice(ms, magicfile, FILE_COMPILE);
281 }
282
283 public int
284 magic_check(struct magic_set *ms, const char *magicfile)
285 {
286         if (ms == NULL)
287                 return -1;
288         return file_apprentice(ms, magicfile, FILE_CHECK);
289 }
290
291 public int
292 magic_list(struct magic_set *ms, const char *magicfile)
293 {
294         if (ms == NULL)
295                 return -1;
296         return file_apprentice(ms, magicfile, FILE_LIST);
297 }
298
299 private void
300 close_and_restore(const struct magic_set *ms, const char *name, int fd,
301     const struct stat *sb)
302 {
303         if (fd == STDIN_FILENO || name == NULL)
304                 return;
305         (void) close(fd);
306
307         if ((ms->flags & MAGIC_PRESERVE_ATIME) != 0) {
308                 /*
309                  * Try to restore access, modification times if read it.
310                  * This is really *bad* because it will modify the status
311                  * time of the file... And of course this will affect
312                  * backup programs
313                  */
314 #ifdef HAVE_UTIMES
315                 struct timeval  utsbuf[2];
316                 (void)memset(utsbuf, 0, sizeof(utsbuf));
317                 utsbuf[0].tv_sec = sb->st_atime;
318                 utsbuf[1].tv_sec = sb->st_mtime;
319
320                 (void) utimes(name, utsbuf); /* don't care if loses */
321 #elif defined(HAVE_UTIME_H) || defined(HAVE_SYS_UTIME_H)
322                 struct utimbuf  utbuf;
323
324                 (void)memset(&utbuf, 0, sizeof(utbuf));
325                 utbuf.actime = sb->st_atime;
326                 utbuf.modtime = sb->st_mtime;
327                 (void) utime(name, &utbuf); /* don't care if loses */
328 #endif
329         }
330 }
331
332 #ifndef COMPILE_ONLY
333
334 /*
335  * find type of descriptor
336  */
337 public const char *
338 magic_descriptor(struct magic_set *ms, int fd)
339 {
340         if (ms == NULL)
341                 return NULL;
342         return file_or_fd(ms, NULL, fd);
343 }
344
345 /*
346  * find type of named file
347  */
348 public const char *
349 magic_file(struct magic_set *ms, const char *inname)
350 {
351         if (ms == NULL)
352                 return NULL;
353         return file_or_fd(ms, inname, STDIN_FILENO);
354 }
355
356 private const char *
357 file_or_fd(struct magic_set *ms, const char *inname, int fd)
358 {
359         int     rv = -1;
360         unsigned char *buf;
361         struct stat     sb;
362         ssize_t nbytes = 0;     /* number of bytes read from a datafile */
363         int     ispipe = 0;
364         off_t   pos = (off_t)-1;
365
366         if (file_reset(ms) == -1)
367                 goto out;
368
369         /*
370          * one extra for terminating '\0', and
371          * some overlapping space for matches near EOF
372          */
373 #define SLOP (1 + sizeof(union VALUETYPE))
374         if ((buf = CAST(unsigned char *, malloc(HOWMANY + SLOP))) == NULL)
375                 return NULL;
376
377         switch (file_fsmagic(ms, inname, &sb)) {
378         case -1:                /* error */
379                 goto done;
380         case 0:                 /* nothing found */
381                 break;
382         default:                /* matched it and printed type */
383                 rv = 0;
384                 goto done;
385         }
386
387 #ifdef WIN32
388         /* Place stdin in binary mode, so EOF (Ctrl+Z) doesn't stop early. */
389         if (fd == STDIN_FILENO)
390                 _setmode(STDIN_FILENO, O_BINARY);
391 #endif
392
393         if (inname == NULL) {
394                 if (fstat(fd, &sb) == 0 && S_ISFIFO(sb.st_mode))
395                         ispipe = 1;
396                 else
397                         pos = lseek(fd, (off_t)0, SEEK_CUR);
398         } else {
399                 int flags = O_RDONLY|O_BINARY;
400                 int okstat = stat(inname, &sb) == 0;
401
402                 if (okstat && S_ISFIFO(sb.st_mode)) {
403 #ifdef O_NONBLOCK
404                         flags |= O_NONBLOCK;
405 #endif
406                         ispipe = 1;
407                 }
408
409                 errno = 0;
410                 if ((fd = open(inname, flags)) < 0) {
411 #ifdef WIN32
412                         /*
413                          * Can't stat, can't open.  It may have been opened in
414                          * fsmagic, so if the user doesn't have read permission,
415                          * allow it to say so; otherwise an error was probably
416                          * displayed in fsmagic.
417                          */
418                         if (!okstat && errno == EACCES) {
419                                 sb.st_mode = S_IFBLK;
420                                 okstat = 1;
421                         }
422 #endif
423                         if (okstat &&
424                             unreadable_info(ms, sb.st_mode, inname) == -1)
425                                 goto done;
426                         rv = 0;
427                         goto done;
428                 }
429 #ifdef O_NONBLOCK
430                 if ((flags = fcntl(fd, F_GETFL)) != -1) {
431                         flags &= ~O_NONBLOCK;
432                         (void)fcntl(fd, F_SETFL, flags);
433                 }
434 #endif
435         }
436
437         /*
438          * try looking at the first HOWMANY bytes
439          */
440         if (ispipe) {
441                 ssize_t r = 0;
442
443                 while ((r = sread(fd, (void *)&buf[nbytes],
444                     (size_t)(HOWMANY - nbytes), 1)) > 0) {
445                         nbytes += r;
446                         if (r < PIPE_BUF) break;
447                 }
448
449                 if (nbytes == 0) {
450                         /* We can not read it, but we were able to stat it. */
451                         if (unreadable_info(ms, sb.st_mode, inname) == -1)
452                                 goto done;
453                         rv = 0;
454                         goto done;
455                 }
456
457         } else {
458                 /* Windows refuses to read from a big console buffer. */
459                 size_t howmany =
460 #if defined(WIN32) && HOWMANY > 8 * 1024
461                                 _isatty(fd) ? 8 * 1024 :
462 #endif
463                                 HOWMANY;
464                 if ((nbytes = read(fd, (char *)buf, howmany)) == -1) {
465                         if (inname == NULL && fd != STDIN_FILENO)
466                                 file_error(ms, errno, "cannot read fd %d", fd);
467                         else
468                                 file_error(ms, errno, "cannot read `%s'",
469                                     inname == NULL ? "/dev/stdin" : inname);
470                         goto done;
471                 }
472         }
473
474         (void)memset(buf + nbytes, 0, SLOP); /* NUL terminate */
475         if (file_buffer(ms, fd, inname, buf, (size_t)nbytes) == -1)
476                 goto done;
477         rv = 0;
478 done:
479         free(buf);
480         if (pos != (off_t)-1)
481                 (void)lseek(fd, pos, SEEK_SET);
482         close_and_restore(ms, inname, fd, &sb);
483 out:
484         return rv == 0 ? file_getbuffer(ms) : NULL;
485 }
486
487
488 public const char *
489 magic_buffer(struct magic_set *ms, const void *buf, size_t nb)
490 {
491         if (ms == NULL)
492                 return NULL;
493         if (file_reset(ms) == -1)
494                 return NULL;
495         /*
496          * The main work is done here!
497          * We have the file name and/or the data buffer to be identified.
498          */
499         if (file_buffer(ms, -1, NULL, buf, nb) == -1) {
500                 return NULL;
501         }
502         return file_getbuffer(ms);
503 }
504 #endif
505
506 public const char *
507 magic_error(struct magic_set *ms)
508 {
509         if (ms == NULL)
510                 return "Magic database is not open";
511         return (ms->event_flags & EVENT_HAD_ERR) ? ms->o.buf : NULL;
512 }
513
514 public int
515 magic_errno(struct magic_set *ms)
516 {
517         if (ms == NULL)
518                 return EINVAL;
519         return (ms->event_flags & EVENT_HAD_ERR) ? ms->error : 0;
520 }
521
522 public int
523 magic_setflags(struct magic_set *ms, int flags)
524 {
525         if (ms == NULL)
526                 return -1;
527 #if !defined(HAVE_UTIME) && !defined(HAVE_UTIMES)
528         if (flags & MAGIC_PRESERVE_ATIME)
529                 return -1;
530 #endif
531         ms->flags = flags;
532         return 0;
533 }
534
535 public int
536 magic_version(void)
537 {
538         return MAGIC_VERSION;
539 }
540
541 public int
542 magic_setparam(struct magic_set *ms, int param, const void *val)
543 {
544         switch (param) {
545         case MAGIC_PARAM_INDIR_MAX:
546                 ms->indir_max = *(const size_t *)val;
547                 return 0;
548         case MAGIC_PARAM_NAME_MAX:
549                 ms->name_max = *(const size_t *)val;
550                 return 0;
551         case MAGIC_PARAM_ELF_PHNUM_MAX:
552                 ms->elf_phnum_max = *(const size_t *)val;
553                 return 0;
554         case MAGIC_PARAM_ELF_SHNUM_MAX:
555                 ms->elf_shnum_max = *(const size_t *)val;
556                 return 0;
557         case MAGIC_PARAM_ELF_NOTES_MAX:
558                 ms->elf_notes_max = *(const size_t *)val;
559                 return 0;
560         default:
561                 errno = EINVAL;
562                 return -1;
563         }
564 }
565
566 public int
567 magic_getparam(struct magic_set *ms, int param, void *val)
568 {
569         switch (param) {
570         case MAGIC_PARAM_INDIR_MAX:
571                 *(size_t *)val = ms->indir_max;
572                 return 0;
573         case MAGIC_PARAM_NAME_MAX:
574                 *(size_t *)val = ms->name_max;
575                 return 0;
576         case MAGIC_PARAM_ELF_PHNUM_MAX:
577                 *(size_t *)val = ms->elf_phnum_max;
578                 return 0;
579         case MAGIC_PARAM_ELF_SHNUM_MAX:
580                 *(size_t *)val = ms->elf_shnum_max;
581                 return 0;
582         case MAGIC_PARAM_ELF_NOTES_MAX:
583                 *(size_t *)val = ms->elf_notes_max;
584                 return 0;
585         default:
586                 errno = EINVAL;
587                 return -1;
588         }
589 }