mod_mime_magic.c revision 443f96ac390c06ca4fa763d3bfcfbc8f757bd756
360a4be4266d6a72be99dfd252623dc0527f5b84Pavel Březina/* ====================================================================
360a4be4266d6a72be99dfd252623dc0527f5b84Pavel Březina * The Apache Software License, Version 1.1
360a4be4266d6a72be99dfd252623dc0527f5b84Pavel Březina * Copyright (c) 2000 The Apache Software Foundation. All rights
360a4be4266d6a72be99dfd252623dc0527f5b84Pavel Březina * Redistribution and use in source and binary forms, with or without
360a4be4266d6a72be99dfd252623dc0527f5b84Pavel Březina * modification, are permitted provided that the following conditions
360a4be4266d6a72be99dfd252623dc0527f5b84Pavel Březina * 1. Redistributions of source code must retain the above copyright
360a4be4266d6a72be99dfd252623dc0527f5b84Pavel Březina * notice, this list of conditions and the following disclaimer.
360a4be4266d6a72be99dfd252623dc0527f5b84Pavel Březina * 2. Redistributions in binary form must reproduce the above copyright
360a4be4266d6a72be99dfd252623dc0527f5b84Pavel Březina * notice, this list of conditions and the following disclaimer in
360a4be4266d6a72be99dfd252623dc0527f5b84Pavel Březina * the documentation and/or other materials provided with the
360a4be4266d6a72be99dfd252623dc0527f5b84Pavel Březina * distribution.
360a4be4266d6a72be99dfd252623dc0527f5b84Pavel Březina * 3. The end-user documentation included with the redistribution,
360a4be4266d6a72be99dfd252623dc0527f5b84Pavel Březina * if any, must include the following acknowledgment:
360a4be4266d6a72be99dfd252623dc0527f5b84Pavel Březina * "This product includes software developed by the
360a4be4266d6a72be99dfd252623dc0527f5b84Pavel Březina * Apache Software Foundation (http://www.apache.org/)."
360a4be4266d6a72be99dfd252623dc0527f5b84Pavel Březina * Alternately, this acknowledgment may appear in the software itself,
360a4be4266d6a72be99dfd252623dc0527f5b84Pavel Březina * if and wherever such third-party acknowledgments normally appear.
360a4be4266d6a72be99dfd252623dc0527f5b84Pavel Březina * 4. The names "Apache" and "Apache Software Foundation" must
360a4be4266d6a72be99dfd252623dc0527f5b84Pavel Březina * not be used to endorse or promote products derived from this
360a4be4266d6a72be99dfd252623dc0527f5b84Pavel Březina * software without prior written permission. For written
360a4be4266d6a72be99dfd252623dc0527f5b84Pavel Březina * permission, please contact apache@apache.org.
50c9d542e8bf641412debaa82a4dcf67ddb72258Lukas Slebodnik * 5. Products derived from this software may not be called "Apache",
360a4be4266d6a72be99dfd252623dc0527f5b84Pavel Březina * nor may "Apache" appear in their name, without prior written
360a4be4266d6a72be99dfd252623dc0527f5b84Pavel Březina * permission of the Apache Software Foundation.
360a4be4266d6a72be99dfd252623dc0527f5b84Pavel Březina * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
bbc34d5a6e84d6c337bd89a22d33e365eb466226Pavel Březina * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
28ebfa4373d1e7ce45b5d70a3619df1c074a661ePavel Březina * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
3a5ea81007bd38ce511c37f65cc45d4b6b95ec44Pavel Březina * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
641d684ee88c6540a4cf1d74d258614f615699fePavel Březina * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
641d684ee88c6540a4cf1d74d258614f615699fePavel Březina * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
bbc34d5a6e84d6c337bd89a22d33e365eb466226Pavel Březina * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
c4d4fe1603420fe8f3d256a3a446974699563ff3Petr Cech * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
c4d4fe1603420fe8f3d256a3a446974699563ff3Petr Cech * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
c4d4fe1603420fe8f3d256a3a446974699563ff3Petr Cech * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
c4d4fe1603420fe8f3d256a3a446974699563ff3Petr Cech * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
c4d4fe1603420fe8f3d256a3a446974699563ff3Petr Cech * SUCH DAMAGE.
c4d4fe1603420fe8f3d256a3a446974699563ff3Petr Cech * ====================================================================
c4d4fe1603420fe8f3d256a3a446974699563ff3Petr Cech * This software consists of voluntary contributions made by many
c4d4fe1603420fe8f3d256a3a446974699563ff3Petr Cech * individuals on behalf of the Apache Software Foundation. For more
fd04b25eaa5cd105da4122854d8bc1e702760e60Jakub Hrozek * information on the Apache Software Foundation, please see
360a4be4266d6a72be99dfd252623dc0527f5b84Pavel Březina * Portions of this software are based upon public domain software
4e5e846de22407f825fe3b4040d79606818a2419Jakub Hrozek * originally written at the National Center for Supercomputing Applications,
4e5e846de22407f825fe3b4040d79606818a2419Jakub Hrozek * University of Illinois, Urbana-Champaign.
4e5e846de22407f825fe3b4040d79606818a2419Jakub Hrozek * mod_mime_magic: MIME type lookup via file magic numbers
4e5e846de22407f825fe3b4040d79606818a2419Jakub Hrozek * Copyright (c) 1996-1997 Cisco Systems, Inc.
360a4be4266d6a72be99dfd252623dc0527f5b84Pavel Březina * This software was submitted by Cisco Systems to the Apache Software Foundation in July
3688374991afb34bbaf2b7843683fc13dd77879dPavel Březina * 1997. Future revisions and derivatives of this source code must
3688374991afb34bbaf2b7843683fc13dd77879dPavel Březina * acknowledge Cisco Systems as the original contributor of this module.
3688374991afb34bbaf2b7843683fc13dd77879dPavel Březina * All other licensing and usage conditions are those of the Apache Software Foundation.
3688374991afb34bbaf2b7843683fc13dd77879dPavel Březina * Some of this code is derived from the free version of the file command
3688374991afb34bbaf2b7843683fc13dd77879dPavel Březina * originally posted to comp.sources.unix. Copyright info for that program
3688374991afb34bbaf2b7843683fc13dd77879dPavel Březina * is included below as required.
3688374991afb34bbaf2b7843683fc13dd77879dPavel Březina * ---------------------------------------------------------------------------
3688374991afb34bbaf2b7843683fc13dd77879dPavel Březina * - Copyright (c) Ian F. Darwin, 1987. Written by Ian F. Darwin.
3688374991afb34bbaf2b7843683fc13dd77879dPavel Březina * This software is not subject to any license of the American Telephone and
3688374991afb34bbaf2b7843683fc13dd77879dPavel Březina * Telegraph Company or of the Regents of the University of California.
3688374991afb34bbaf2b7843683fc13dd77879dPavel Březina * Permission is granted to anyone to use this software for any purpose on any
3688374991afb34bbaf2b7843683fc13dd77879dPavel Březina * computer system, and to alter it and redistribute it freely, subject to
3688374991afb34bbaf2b7843683fc13dd77879dPavel Březina * the following restrictions:
3688374991afb34bbaf2b7843683fc13dd77879dPavel Březina * 1. The author is not responsible for the consequences of use of this
3688374991afb34bbaf2b7843683fc13dd77879dPavel Březina * software, no matter how awful, even if they arise from flaws in it.
3688374991afb34bbaf2b7843683fc13dd77879dPavel Březina * 2. The origin of this software must not be misrepresented, either by
360a4be4266d6a72be99dfd252623dc0527f5b84Pavel Březina * explicit claim or by omission. Since few users ever read sources, credits
360a4be4266d6a72be99dfd252623dc0527f5b84Pavel Březina * must appear in the documentation.
360a4be4266d6a72be99dfd252623dc0527f5b84Pavel Březina * 3. Altered versions must be plainly marked as such, and must not be
360a4be4266d6a72be99dfd252623dc0527f5b84Pavel Březina * misrepresented as being the original software. Since few users ever read
360a4be4266d6a72be99dfd252623dc0527f5b84Pavel Březina * sources, credits must appear in the documentation.
e87b2a6e94c1066b3044fe683825ff5b4f8716c2Pavel Březina * 4. This notice may not be removed or altered.
360a4be4266d6a72be99dfd252623dc0527f5b84Pavel Březina * -------------------------------------------------------------------------
5928fcbb57b92bfd18ad15aaaf4a5e1ab8dabe61Petr Cech * For compliance with Mr Darwin's terms: this has been very significantly
5928fcbb57b92bfd18ad15aaaf4a5e1ab8dabe61Petr Cech * modified from the free "file" command.
c4d4fe1603420fe8f3d256a3a446974699563ff3Petr Cech * - all-in-one file for compilation convenience when moving from one
c4d4fe1603420fe8f3d256a3a446974699563ff3Petr Cech * version of Apache to the next.
5928fcbb57b92bfd18ad15aaaf4a5e1ab8dabe61Petr Cech * - Memory allocation is done through the Apache API's apr_pool_t structure.
5928fcbb57b92bfd18ad15aaaf4a5e1ab8dabe61Petr Cech * - All functions have had necessary Apache API request or server
360a4be4266d6a72be99dfd252623dc0527f5b84Pavel Březina * structures passed to them where necessary to call other Apache API
360a4be4266d6a72be99dfd252623dc0527f5b84Pavel Březina * routines. (i.e. usually for logging, files, or memory allocation in
360a4be4266d6a72be99dfd252623dc0527f5b84Pavel Březina * itself or a called function.)
360a4be4266d6a72be99dfd252623dc0527f5b84Pavel Březina * - struct magic has been converted from an array to a single-ended linked
360a4be4266d6a72be99dfd252623dc0527f5b84Pavel Březina * list because it only grows one record at a time, it's only accessed
360a4be4266d6a72be99dfd252623dc0527f5b84Pavel Březina * sequentially, and the Apache API has no equivalent of realloc().
360a4be4266d6a72be99dfd252623dc0527f5b84Pavel Březina * - Functions have been changed to get their parameters from the server
360a4be4266d6a72be99dfd252623dc0527f5b84Pavel Březina * configuration instead of globals. (It should be reentrant now but has
360a4be4266d6a72be99dfd252623dc0527f5b84Pavel Březina * not been tested in a threaded environment.)
360a4be4266d6a72be99dfd252623dc0527f5b84Pavel Březina * - Places where it used to print results to stdout now saves them in a
360a4be4266d6a72be99dfd252623dc0527f5b84Pavel Březina * list where they're used to set the MIME type in the Apache request
360a4be4266d6a72be99dfd252623dc0527f5b84Pavel Březina * - Command-line flags have been removed since they will never be used here.
360a4be4266d6a72be99dfd252623dc0527f5b84Pavel Březina * Ian Kluft <ikluft@cisco.com>
360a4be4266d6a72be99dfd252623dc0527f5b84Pavel Březina * Engineering Information Framework
360a4be4266d6a72be99dfd252623dc0527f5b84Pavel Březina * Central Engineering
54ed1b1214dbf9da1f481e8d193c81ce4312516bPavel Březina * Cisco Systems, Inc.
360a4be4266d6a72be99dfd252623dc0527f5b84Pavel Březina * San Jose, CA, USA
360a4be4266d6a72be99dfd252623dc0527f5b84Pavel Březina * Initial installation July/August 1996
360a4be4266d6a72be99dfd252623dc0527f5b84Pavel Březina * Misc bug fixes May 1997
360a4be4266d6a72be99dfd252623dc0527f5b84Pavel Březina * Submission to Apache Software Foundation July 1997
3a5ea81007bd38ce511c37f65cc45d4b6b95ec44Pavel Březina * data structures and related constants
641d684ee88c6540a4cf1d74d258614f615699fePavel Březina#define MIME_BINARY_UNKNOWN "application/octet-stream"
e87b2a6e94c1066b3044fe683825ff5b4f8716c2Pavel Březina/* HOWMANY must be at least 4096 to make gzip -dcq work */
641d684ee88c6540a4cf1d74d258614f615699fePavel Březina/* SMALL_HOWMANY limits how much work we do to figure out text files */
641d684ee88c6540a4cf1d74d258614f615699fePavel Březina#define MAXDESC 50 /* max leng of text description */
641d684ee88c6540a4cf1d74d258614f615699fePavel Březina#define MAXstring 64 /* max leng of "string" types */
71965bb18407ff45ada9e47cb6def086e48663c6Pavel Březina#define UNSIGNED 2 /* comparison is unsigned */
c4d4fe1603420fe8f3d256a3a446974699563ff3Petr Cech unsigned char reln; /* relation (0=eq, '>'=gt, etc) */
3688374991afb34bbaf2b7843683fc13dd77879dPavel Březina unsigned char b;
c4d4fe1603420fe8f3d256a3a446974699563ff3Petr Cech unsigned short h;
c4d4fe1603420fe8f3d256a3a446974699563ff3Petr Cech unsigned long l;
df9e9a1f9b7dc255eb62c390163c25917b08f5a2Lukas Slebodnik unsigned char hs[2]; /* 2 bytes of a fixed-endian "short" */
3688374991afb34bbaf2b7843683fc13dd77879dPavel Březina unsigned char hl[4]; /* 2 bytes of a fixed-endian "long" */
3688374991afb34bbaf2b7843683fc13dd77879dPavel Březina unsigned long mask; /* mask before comparison with value */
c4d4fe1603420fe8f3d256a3a446974699563ff3Petr Cech /* NOTE: this string is suspected of overrunning - find it! */
c4d4fe1603420fe8f3d256a3a446974699563ff3Petr Cech * data structures for tar file recognition
c4d4fe1603420fe8f3d256a3a446974699563ff3Petr Cech * --------------------------------------------------------------------------
3688374991afb34bbaf2b7843683fc13dd77879dPavel Březina * Header file for public domain tar (tape archive) program.
3688374991afb34bbaf2b7843683fc13dd77879dPavel Březina * @(#)tar.h 1.20 86/10/29 Public Domain. Created 25 August 1985 by John
3688374991afb34bbaf2b7843683fc13dd77879dPavel Březina * Gilmore, ihnp4!hoptoad!gnu.
3688374991afb34bbaf2b7843683fc13dd77879dPavel Březina * Header block on tape.
3688374991afb34bbaf2b7843683fc13dd77879dPavel Březina * I'm going to use traditional DP naming conventions here. A "block" is a big
3688374991afb34bbaf2b7843683fc13dd77879dPavel Březina * chunk of stuff that we do I/O on. A "record" is a piece of info that we
3688374991afb34bbaf2b7843683fc13dd77879dPavel Březina * care about. Typically many "record"s fit into a "block".
3688374991afb34bbaf2b7843683fc13dd77879dPavel Březina/* The magic field is filled with this if uname and gname are valid. */
3688374991afb34bbaf2b7843683fc13dd77879dPavel Březina#define TMAGIC "ustar " /* 7 chars and a null */
3688374991afb34bbaf2b7843683fc13dd77879dPavel Březina * file-function prototypes
3688374991afb34bbaf2b7843683fc13dd77879dPavel Březinastatic int ascmagic(request_rec *, unsigned char *, int);
3688374991afb34bbaf2b7843683fc13dd77879dPavel Březinastatic int is_tar(unsigned char *, int);
3688374991afb34bbaf2b7843683fc13dd77879dPavel Březinastatic int softmagic(request_rec *, unsigned char *, int);
3688374991afb34bbaf2b7843683fc13dd77879dPavel Březinastatic void tryit(request_rec *, unsigned char *, int, int);
3688374991afb34bbaf2b7843683fc13dd77879dPavel Březinastatic int zmagic(request_rec *, unsigned char *, int);
3688374991afb34bbaf2b7843683fc13dd77879dPavel Březinastatic int getvalue(server_rec *, struct magic *, char **);
3688374991afb34bbaf2b7843683fc13dd77879dPavel Březinastatic int hextoint(int);
3688374991afb34bbaf2b7843683fc13dd77879dPavel Březinastatic char *getstr(server_rec *, char *, char *, int, int *);
3688374991afb34bbaf2b7843683fc13dd77879dPavel Březinastatic int parse(server_rec *, apr_pool_t *p, char *, int);
3688374991afb34bbaf2b7843683fc13dd77879dPavel Březinastatic int match(request_rec *, unsigned char *, int);
3688374991afb34bbaf2b7843683fc13dd77879dPavel Březinastatic int mget(request_rec *, union VALUETYPE *, unsigned char *,
3688374991afb34bbaf2b7843683fc13dd77879dPavel Březina struct magic *, int);
3688374991afb34bbaf2b7843683fc13dd77879dPavel Březinastatic int mcheck(request_rec *, union VALUETYPE *, struct magic *);
3688374991afb34bbaf2b7843683fc13dd77879dPavel Březinastatic void mprint(request_rec *, union VALUETYPE *, struct magic *);
3688374991afb34bbaf2b7843683fc13dd77879dPavel Březina unsigned char **, int);
3688374991afb34bbaf2b7843683fc13dd77879dPavel Březinastatic long from_oct(int, char *);
3688374991afb34bbaf2b7843683fc13dd77879dPavel Březinastatic int fsmagic(request_rec *r, const char *fn);
3688374991afb34bbaf2b7843683fc13dd77879dPavel Březina * includes for ASCII substring recognition formerly "names.h" in file
df9e9a1f9b7dc255eb62c390163c25917b08f5a2Lukas Slebodnik * Original notes: names and types used by ascmagic in file(1). These tokens are
3688374991afb34bbaf2b7843683fc13dd77879dPavel Březina * here because they can appear anywhere in the first HOWMANY bytes, while
3688374991afb34bbaf2b7843683fc13dd77879dPavel Březina * tokens in /etc/magic must appear at fixed offsets into the file. Don't
3688374991afb34bbaf2b7843683fc13dd77879dPavel Březina * make HOWMANY too high unless you have a very fast CPU.
3688374991afb34bbaf2b7843683fc13dd77879dPavel Březina/* these types are used to index the apr_table_t 'types': keep em in sync! */
3688374991afb34bbaf2b7843683fc13dd77879dPavel Březina/* HTML inserted in first because this is a web server module now */
3688374991afb34bbaf2b7843683fc13dd77879dPavel Březinastatic char *types[] =
3688374991afb34bbaf2b7843683fc13dd77879dPavel Březina "application/binary", /* "can't happen error on names.h/types", */
3688374991afb34bbaf2b7843683fc13dd77879dPavel Březinastatic struct names {
3688374991afb34bbaf2b7843683fc13dd77879dPavel Březina /* These must be sorted by eye for optimal hit rate */
3688374991afb34bbaf2b7843683fc13dd77879dPavel Březina /* Add to this list only after substantial meditation */
3688374991afb34bbaf2b7843683fc13dd77879dPavel Březina }, /* must precede "The", "the", etc. */
4e5e846de22407f825fe3b4040d79606818a2419Jakub Hrozek * Too many files of text have these words in them. Find another way to
360a4be4266d6a72be99dfd252623dc0527f5b84Pavel Březina * recognize Fortrash.
4e5e846de22407f825fe3b4040d79606818a2419Jakub Hrozek#endif /* NOTDEF */
e87b2a6e94c1066b3044fe683825ff5b4f8716c2Pavel Březina#define NNAMES ((sizeof(names)/sizeof(struct names)) - 1)
e87b2a6e94c1066b3044fe683825ff5b4f8716c2Pavel Březina * Result String List (RSL)
e87b2a6e94c1066b3044fe683825ff5b4f8716c2Pavel Březina * The file(1) command prints its output. Instead, we store the various
e87b2a6e94c1066b3044fe683825ff5b4f8716c2Pavel Březina * "printed" strings in a list (allocating memory as we go) and concatenate
e87b2a6e94c1066b3044fe683825ff5b4f8716c2Pavel Březina * them at the end when we finally know how much space they'll need.
e87b2a6e94c1066b3044fe683825ff5b4f8716c2Pavel Březinatypedef struct magic_rsl_s {
e87b2a6e94c1066b3044fe683825ff5b4f8716c2Pavel Březina struct magic_rsl_s *next; /* pointer to next fragment */
e87b2a6e94c1066b3044fe683825ff5b4f8716c2Pavel Březina * Apache module configuration structures
3688374991afb34bbaf2b7843683fc13dd77879dPavel Březina/* per-server info */
e87b2a6e94c1066b3044fe683825ff5b4f8716c2Pavel Březinatypedef struct {
e87b2a6e94c1066b3044fe683825ff5b4f8716c2Pavel Březina const char *magicfile; /* where magic be found */
e87b2a6e94c1066b3044fe683825ff5b4f8716c2Pavel Březina struct magic *magic; /* head of magic config list */
e87b2a6e94c1066b3044fe683825ff5b4f8716c2Pavel Březina/* per-request info */
e87b2a6e94c1066b3044fe683825ff5b4f8716c2Pavel Březinatypedef struct {
e87b2a6e94c1066b3044fe683825ff5b4f8716c2Pavel Březina unsigned suf_recursion; /* recursion depth in suffix check */
3688374991afb34bbaf2b7843683fc13dd77879dPavel Březina * configuration functions - called by Apache API routines
e87b2a6e94c1066b3044fe683825ff5b4f8716c2Pavel Březinastatic void *create_magic_server_config(apr_pool_t *p, server_rec *d)
e87b2a6e94c1066b3044fe683825ff5b4f8716c2Pavel Březina /* allocate the config - use pcalloc because it needs to be zeroed */
e87b2a6e94c1066b3044fe683825ff5b4f8716c2Pavel Březina return apr_pcalloc(p, sizeof(magic_server_config_rec));
e87b2a6e94c1066b3044fe683825ff5b4f8716c2Pavel Březinastatic void *merge_magic_server_config(apr_pool_t *p, void *basev, void *addv)
e87b2a6e94c1066b3044fe683825ff5b4f8716c2Pavel Březina magic_server_config_rec *base = (magic_server_config_rec *) basev;
e87b2a6e94c1066b3044fe683825ff5b4f8716c2Pavel Březina magic_server_config_rec *add = (magic_server_config_rec *) addv;
e87b2a6e94c1066b3044fe683825ff5b4f8716c2Pavel Březina magic_server_config_rec *new = (magic_server_config_rec *)
e87b2a6e94c1066b3044fe683825ff5b4f8716c2Pavel Březina apr_palloc(p, sizeof(magic_server_config_rec));
e87b2a6e94c1066b3044fe683825ff5b4f8716c2Pavel Březina new->magicfile = add->magicfile ? add->magicfile : base->magicfile;
360a4be4266d6a72be99dfd252623dc0527f5b84Pavel Březinastatic const char *set_magicfile(cmd_parms *cmd, void *dummy, const char *arg)
360a4be4266d6a72be99dfd252623dc0527f5b84Pavel Březina magic_server_config_rec *conf = (magic_server_config_rec *)
360a4be4266d6a72be99dfd252623dc0527f5b84Pavel Březina ap_get_module_config(cmd->server->module_config,
360a4be4266d6a72be99dfd252623dc0527f5b84Pavel Březina return MODNAME ": server structure not allocated";
360a4be4266d6a72be99dfd252623dc0527f5b84Pavel Březina * configuration file commands - exported to Apache API
3688374991afb34bbaf2b7843683fc13dd77879dPavel Březina AP_INIT_TAKE1("MimeMagicFile", set_magicfile, NULL, RSRC_CONF,
3688374991afb34bbaf2b7843683fc13dd77879dPavel Březina "Path to MIME Magic file (in file(1) format)"),
360a4be4266d6a72be99dfd252623dc0527f5b84Pavel Březina * RSL (result string list) processing routines
3688374991afb34bbaf2b7843683fc13dd77879dPavel Březina * These collect strings that would have been printed in fragments by file(1)
3688374991afb34bbaf2b7843683fc13dd77879dPavel Březina * into a list of magic_rsl structures with the strings. When complete,
360a4be4266d6a72be99dfd252623dc0527f5b84Pavel Březina * they're concatenated together to become the MIME content and encoding
360a4be4266d6a72be99dfd252623dc0527f5b84Pavel Březina * return value conventions for these functions: functions which return int:
54ed1b1214dbf9da1f481e8d193c81ce4312516bPavel Březina * failure = -1, other = result functions which return pointers: failure = 0,
360a4be4266d6a72be99dfd252623dc0527f5b84Pavel Březina * other = result
360a4be4266d6a72be99dfd252623dc0527f5b84Pavel Březina/* allocate a per-request structure and put it in the request record */
360a4be4266d6a72be99dfd252623dc0527f5b84Pavel Březinastatic magic_req_rec *magic_set_config(request_rec *r)
3688374991afb34bbaf2b7843683fc13dd77879dPavel Březina magic_req_rec *req_dat = (magic_req_rec *) apr_palloc(r->pool,
360a4be4266d6a72be99dfd252623dc0527f5b84Pavel Březina req_dat->head = req_dat->tail = (magic_rsl *) NULL;
360a4be4266d6a72be99dfd252623dc0527f5b84Pavel Březina ap_set_module_config(r->request_config, &mime_magic_module, req_dat);
360a4be4266d6a72be99dfd252623dc0527f5b84Pavel Březina/* add a string to the result string list for this request */
3688374991afb34bbaf2b7843683fc13dd77879dPavel Březina/* it is the responsibility of the caller to allocate "str" */
360a4be4266d6a72be99dfd252623dc0527f5b84Pavel Březinastatic int magic_rsl_add(request_rec *r, char *str)
360a4be4266d6a72be99dfd252623dc0527f5b84Pavel Březina ap_get_module_config(r->request_config, &mime_magic_module);
360a4be4266d6a72be99dfd252623dc0527f5b84Pavel Březina /* make sure we have a list to put it in */
360a4be4266d6a72be99dfd252623dc0527f5b84Pavel Březina ap_log_rerror(APLOG_MARK, APLOG_NOERRNO | APLOG_ERR, APR_EINVAL, r,
3688374991afb34bbaf2b7843683fc13dd77879dPavel Březina MODNAME ": request config should not be NULL");
3688374991afb34bbaf2b7843683fc13dd77879dPavel Březina /* failure */
360a4be4266d6a72be99dfd252623dc0527f5b84Pavel Březina /* allocate the list entry */
360a4be4266d6a72be99dfd252623dc0527f5b84Pavel Březina rsl = (magic_rsl *) apr_palloc(r->pool, sizeof(magic_rsl));
54ed1b1214dbf9da1f481e8d193c81ce4312516bPavel Březina /* fill it */
360a4be4266d6a72be99dfd252623dc0527f5b84Pavel Březina /* append to the list */
3688374991afb34bbaf2b7843683fc13dd77879dPavel Březina /* success */
360a4be4266d6a72be99dfd252623dc0527f5b84Pavel Březina/* RSL hook for puts-type functions */
360a4be4266d6a72be99dfd252623dc0527f5b84Pavel Březinastatic int magic_rsl_puts(request_rec *r, char *str)
360a4be4266d6a72be99dfd252623dc0527f5b84Pavel Březina/* RSL hook for printf-type functions */
360a4be4266d6a72be99dfd252623dc0527f5b84Pavel Březinastatic int magic_rsl_printf(request_rec *r, char *str,...)
3688374991afb34bbaf2b7843683fc13dd77879dPavel Březina /* assemble the string into the buffer */
28ebfa4373d1e7ce45b5d70a3619df1c074a661ePavel Březina /* add the buffer to the list */
28ebfa4373d1e7ce45b5d70a3619df1c074a661ePavel Březina/* RSL hook for putchar-type functions */
28ebfa4373d1e7ce45b5d70a3619df1c074a661ePavel Březinastatic int magic_rsl_putchar(request_rec *r, char c)
28ebfa4373d1e7ce45b5d70a3619df1c074a661ePavel Březina /* high overhead for 1 char - just hope they don't do this much */
28ebfa4373d1e7ce45b5d70a3619df1c074a661ePavel Březina/* allocate and copy a contiguous string from a result string list */
28ebfa4373d1e7ce45b5d70a3619df1c074a661ePavel Březinastatic char *rsl_strdup(request_rec *r, int start_frag, int start_pos, int len)
3688374991afb34bbaf2b7843683fc13dd77879dPavel Březina int cur_frag, /* current fragment number/counter */
28ebfa4373d1e7ce45b5d70a3619df1c074a661ePavel Březina cur_pos, /* current position within fragment */
28ebfa4373d1e7ce45b5d70a3619df1c074a661ePavel Březina ap_get_module_config(r->request_config, &mime_magic_module);
28ebfa4373d1e7ce45b5d70a3619df1c074a661ePavel Březina /* allocate the result string */
28ebfa4373d1e7ce45b5d70a3619df1c074a661ePavel Březina result = (char *) apr_palloc(r->pool, len + 1);
28ebfa4373d1e7ce45b5d70a3619df1c074a661ePavel Březina /* loop through and collect the string */
28ebfa4373d1e7ce45b5d70a3619df1c074a661ePavel Březina /* loop to the first fragment */
28ebfa4373d1e7ce45b5d70a3619df1c074a661ePavel Březina /* loop through and collect chars */
28ebfa4373d1e7ce45b5d70a3619df1c074a661ePavel Březina for (cur_pos = (cur_frag == start_frag) ? start_pos : 0;
3688374991afb34bbaf2b7843683fc13dd77879dPavel Březina /* clean up and return */
28ebfa4373d1e7ce45b5d70a3619df1c074a661ePavel Březina ap_log_rerror(APLOG_MARK, APLOG_NOERRNO | APLOG_DEBUG, 0, r,
28ebfa4373d1e7ce45b5d70a3619df1c074a661ePavel Březina MODNAME ": rsl_strdup() %d chars: %s", res_pos - 1, result);
28ebfa4373d1e7ce45b5d70a3619df1c074a661ePavel Březina/* states for the state-machine algorithm in magic_rsl_to_request() */
3688374991afb34bbaf2b7843683fc13dd77879dPavel Březinatypedef enum {
3688374991afb34bbaf2b7843683fc13dd77879dPavel Březina rsl_leading_space, rsl_type, rsl_subtype, rsl_separator, rsl_encoding
28ebfa4373d1e7ce45b5d70a3619df1c074a661ePavel Březina/* process the RSL and set the MIME info in the request record */
28ebfa4373d1e7ce45b5d70a3619df1c074a661ePavel Březinastatic int magic_rsl_to_request(request_rec *r)
28ebfa4373d1e7ce45b5d70a3619df1c074a661ePavel Březina int cur_frag, /* current fragment number/counter */
28ebfa4373d1e7ce45b5d70a3619df1c074a661ePavel Březina cur_pos, /* current position within fragment */
3688374991afb34bbaf2b7843683fc13dd77879dPavel Březina type_frag, /* content type starting point: fragment */
3688374991afb34bbaf2b7843683fc13dd77879dPavel Březina type_pos, /* content type starting point: position */
3688374991afb34bbaf2b7843683fc13dd77879dPavel Březina encoding_frag, /* content encoding starting point: fragment */
28ebfa4373d1e7ce45b5d70a3619df1c074a661ePavel Březina encoding_pos, /* content encoding starting point: position */
28ebfa4373d1e7ce45b5d70a3619df1c074a661ePavel Březina ap_get_module_config(r->request_config, &mime_magic_module);
3688374991afb34bbaf2b7843683fc13dd77879dPavel Březina /* check if we have a result */
3688374991afb34bbaf2b7843683fc13dd77879dPavel Březina /* empty - no match, we defer to other Apache modules */
28ebfa4373d1e7ce45b5d70a3619df1c074a661ePavel Březina /* start searching for the type and encoding */
28ebfa4373d1e7ce45b5d70a3619df1c074a661ePavel Březina encoding_frag = encoding_pos = encoding_len = 0;
28ebfa4373d1e7ce45b5d70a3619df1c074a661ePavel Březina /* loop through the characters in the fragment */
28ebfa4373d1e7ce45b5d70a3619df1c074a661ePavel Březina for (cur_pos = 0; frag->str[cur_pos]; cur_pos++) {
28ebfa4373d1e7ce45b5d70a3619df1c074a661ePavel Březina /* process whitespace actions for each state */
28ebfa4373d1e7ce45b5d70a3619df1c074a661ePavel Březina /* eat whitespace in this state */
3688374991afb34bbaf2b7843683fc13dd77879dPavel Březina /* whitespace: type has no slash! */
28ebfa4373d1e7ce45b5d70a3619df1c074a661ePavel Březina /* whitespace: end of MIME type */
28ebfa4373d1e7ce45b5d70a3619df1c074a661ePavel Březina /* eat whitespace in this state */
28ebfa4373d1e7ce45b5d70a3619df1c074a661ePavel Březina /* whitespace: end of MIME encoding */
28ebfa4373d1e7ce45b5d70a3619df1c074a661ePavel Březina /* we're done */
28ebfa4373d1e7ce45b5d70a3619df1c074a661ePavel Březina /* should not be possible */
28ebfa4373d1e7ce45b5d70a3619df1c074a661ePavel Březina /* abandon malfunctioning module */
28ebfa4373d1e7ce45b5d70a3619df1c074a661ePavel Březina ap_log_rerror(APLOG_MARK, APLOG_NOERRNO | APLOG_ERR, 0, r,
3688374991afb34bbaf2b7843683fc13dd77879dPavel Březina /* NOTREACHED */
3688374991afb34bbaf2b7843683fc13dd77879dPavel Březina /* copy the char and go to rsl_subtype state */
28ebfa4373d1e7ce45b5d70a3619df1c074a661ePavel Březina /* process non-space actions for each state */
28ebfa4373d1e7ce45b5d70a3619df1c074a661ePavel Březina /* non-space: begin MIME type */
28ebfa4373d1e7ce45b5d70a3619df1c074a661ePavel Březina /* non-space: adds to type */
3a5ea81007bd38ce511c37f65cc45d4b6b95ec44Pavel Březina /* non-space: begin MIME encoding */
3a5ea81007bd38ce511c37f65cc45d4b6b95ec44Pavel Březina /* non-space: adds to encoding */
3a5ea81007bd38ce511c37f65cc45d4b6b95ec44Pavel Březina /* should not be possible */
3a5ea81007bd38ce511c37f65cc45d4b6b95ec44Pavel Březina /* abandon malfunctioning module */
3688374991afb34bbaf2b7843683fc13dd77879dPavel Březina ap_log_rerror(APLOG_MARK, APLOG_NOERRNO | APLOG_ERR, 0, r,
3a5ea81007bd38ce511c37f65cc45d4b6b95ec44Pavel Březina /* NOTREACHED */
3a5ea81007bd38ce511c37f65cc45d4b6b95ec44Pavel Březina /* NOTREACHED */
3a5ea81007bd38ce511c37f65cc45d4b6b95ec44Pavel Březina /* if we ended prior to state rsl_subtype, we had incomplete info */
3a5ea81007bd38ce511c37f65cc45d4b6b95ec44Pavel Březina if (state != rsl_subtype && state != rsl_separator &&
3a5ea81007bd38ce511c37f65cc45d4b6b95ec44Pavel Březina /* defer to other modules */
3688374991afb34bbaf2b7843683fc13dd77879dPavel Březina /* save the info in the request record */
3a5ea81007bd38ce511c37f65cc45d4b6b95ec44Pavel Březina if (state == rsl_subtype || state == rsl_encoding ||
3a5ea81007bd38ce511c37f65cc45d4b6b95ec44Pavel Březina tmp = rsl_strdup(r, type_frag, type_pos, type_len);
3a5ea81007bd38ce511c37f65cc45d4b6b95ec44Pavel Březina /* XXX: this could be done at config time I'm sure... but I'm
3a5ea81007bd38ce511c37f65cc45d4b6b95ec44Pavel Březina * confused by all this magic_rsl stuff. -djg */
3688374991afb34bbaf2b7843683fc13dd77879dPavel Březina /* XXX: this could be done at config time I'm sure... but I'm
3688374991afb34bbaf2b7843683fc13dd77879dPavel Březina * confused by all this magic_rsl stuff. -djg */
3a5ea81007bd38ce511c37f65cc45d4b6b95ec44Pavel Březina /* detect memory allocation errors */
3a5ea81007bd38ce511c37f65cc45d4b6b95ec44Pavel Březina (state == rsl_encoding && !r->content_encoding)) {
3a5ea81007bd38ce511c37f65cc45d4b6b95ec44Pavel Březina /* success! */
3a5ea81007bd38ce511c37f65cc45d4b6b95ec44Pavel Březina * magic_process - process input file r Apache API request record
3688374991afb34bbaf2b7843683fc13dd77879dPavel Březina * (formerly called "process" in file command, prefix added for clarity) Opens
3688374991afb34bbaf2b7843683fc13dd77879dPavel Březina * the file and reads a fixed-size buffer to begin processing the contents.
3a5ea81007bd38ce511c37f65cc45d4b6b95ec44Pavel Březina unsigned char buf[HOWMANY + 1]; /* one extra for terminating '\0' */
3a5ea81007bd38ce511c37f65cc45d4b6b95ec44Pavel Březina int nbytes = 0; /* number of bytes read from a datafile */
3a5ea81007bd38ce511c37f65cc45d4b6b95ec44Pavel Březina * first try judging the file based on its filesystem status
3688374991afb34bbaf2b7843683fc13dd77879dPavel Březina /* fatal error, bail out */
3a5ea81007bd38ce511c37f65cc45d4b6b95ec44Pavel Březina if (apr_open(&fd, r->filename, APR_READ, APR_OS_DEFAULT, r->pool) != APR_SUCCESS) {
3a5ea81007bd38ce511c37f65cc45d4b6b95ec44Pavel Březina /* We can't open it, but we were able to stat it. */
3a5ea81007bd38ce511c37f65cc45d4b6b95ec44Pavel Březina /* let some other handler decide what the problem is */
3688374991afb34bbaf2b7843683fc13dd77879dPavel Březina * try looking at the first HOWMANY bytes
3688374991afb34bbaf2b7843683fc13dd77879dPavel Březina if ((result = apr_read(fd, (char *) buf, &nbytes)) != APR_SUCCESS) {
3688374991afb34bbaf2b7843683fc13dd77879dPavel Březina ap_log_rerror(APLOG_MARK, APLOG_ERR, result, r,
3a5ea81007bd38ce511c37f65cc45d4b6b95ec44Pavel Březinastatic void tryit(request_rec *r, unsigned char *buf, int nb, int checkzmagic)
3a5ea81007bd38ce511c37f65cc45d4b6b95ec44Pavel Březina * Try compression stuff
3a5ea81007bd38ce511c37f65cc45d4b6b95ec44Pavel Březina * try tests in /etc/magic (or surrogate magic file)
3a5ea81007bd38ce511c37f65cc45d4b6b95ec44Pavel Březina * try known keywords, check for ascii-ness too.
641d684ee88c6540a4cf1d74d258614f615699fePavel Březina * abandon hope, all ye who remain here
641d684ee88c6540a4cf1d74d258614f615699fePavel Březina#define EATAB {while (apr_isspace((unsigned char) *l)) ++l;}
641d684ee88c6540a4cf1d74d258614f615699fePavel Březina * apprentice - load configuration from the magic file r
3688374991afb34bbaf2b7843683fc13dd77879dPavel Březina * API request record
641d684ee88c6540a4cf1d74d258614f615699fePavel Březinastatic int apprentice(server_rec *s, apr_pool_t *p)
641d684ee88c6540a4cf1d74d258614f615699fePavel Březina magic_server_config_rec *conf = (magic_server_config_rec *)
641d684ee88c6540a4cf1d74d258614f615699fePavel Březina ap_get_module_config(s->module_config, &mime_magic_module);
641d684ee88c6540a4cf1d74d258614f615699fePavel Březina const char *fname = ap_server_root_relative(p, conf->magicfile);
3688374991afb34bbaf2b7843683fc13dd77879dPavel Březina result = apr_open(&f, fname, APR_READ | APR_BUFFERED, APR_OS_DEFAULT, p);
641d684ee88c6540a4cf1d74d258614f615699fePavel Březina ap_log_error(APLOG_MARK, APLOG_ERR, result, s,
641d684ee88c6540a4cf1d74d258614f615699fePavel Březina /* set up the magic list (empty) */
e87b2a6e94c1066b3044fe683825ff5b4f8716c2Pavel Březina /* parse it */
e87b2a6e94c1066b3044fe683825ff5b4f8716c2Pavel Březina for (lineno = 1; apr_fgets(line, BUFSIZ, f) == APR_SUCCESS; lineno++) {
e87b2a6e94c1066b3044fe683825ff5b4f8716c2Pavel Březina /* delete newline */
e87b2a6e94c1066b3044fe683825ff5b4f8716c2Pavel Březina /* skip leading whitespace */
e87b2a6e94c1066b3044fe683825ff5b4f8716c2Pavel Březina while (line[ws_offset] && apr_isspace(line[ws_offset])) {
e87b2a6e94c1066b3044fe683825ff5b4f8716c2Pavel Březina /* skip blank lines */
e87b2a6e94c1066b3044fe683825ff5b4f8716c2Pavel Březina /* comment, do not parse */
e87b2a6e94c1066b3044fe683825ff5b4f8716c2Pavel Březina /* if we get here, we're going to use it so count it */
e87b2a6e94c1066b3044fe683825ff5b4f8716c2Pavel Březina /* parse it */
e87b2a6e94c1066b3044fe683825ff5b4f8716c2Pavel Březina if (parse(s, p, line + ws_offset, lineno) != 0)
e87b2a6e94c1066b3044fe683825ff5b4f8716c2Pavel Březina ap_log_error(APLOG_MARK, APLOG_NOERRNO | APLOG_DEBUG, 0, s,
28ebfa4373d1e7ce45b5d70a3619df1c074a661ePavel Březina MODNAME ": apprentice conf=%x file=%s m=%s m->next=%s last=%s",
e87b2a6e94c1066b3044fe683825ff5b4f8716c2Pavel Březina (conf->magic && conf->magic->next) ? "set" : "NULL",
e87b2a6e94c1066b3044fe683825ff5b4f8716c2Pavel Březina ap_log_error(APLOG_MARK, APLOG_NOERRNO | APLOG_DEBUG, 0, s,
e87b2a6e94c1066b3044fe683825ff5b4f8716c2Pavel Březina MODNAME ": apprentice read %d lines, %d rules, %d errors",
3688374991afb34bbaf2b7843683fc13dd77879dPavel Březina ap_log_error(APLOG_MARK, APLOG_NOERRNO | APLOG_DEBUG, 0, s,
e87b2a6e94c1066b3044fe683825ff5b4f8716c2Pavel Březina if (apr_isprint((((unsigned long) m) >> 24) & 255) &&
e87b2a6e94c1066b3044fe683825ff5b4f8716c2Pavel Březina apr_isprint((((unsigned long) m) >> 16) & 255) &&
e87b2a6e94c1066b3044fe683825ff5b4f8716c2Pavel Březina apr_isprint((((unsigned long) m) >> 8) & 255) &&
641d684ee88c6540a4cf1d74d258614f615699fePavel Březina ap_log_error(APLOG_MARK, APLOG_NOERRNO | APLOG_DEBUG, 0, s,
641d684ee88c6540a4cf1d74d258614f615699fePavel Březina "m=\"%c%c%c%c\" line=%d",
3688374991afb34bbaf2b7843683fc13dd77879dPavel Březina ((unsigned long) m) & 255,
641d684ee88c6540a4cf1d74d258614f615699fePavel Březina * extend the sign bit if the comparison is to be signed
3688374991afb34bbaf2b7843683fc13dd77879dPavel Březinastatic unsigned long signextend(server_rec *s, struct magic *m, unsigned long v)
641d684ee88c6540a4cf1d74d258614f615699fePavel Březina switch (m->type) {
641d684ee88c6540a4cf1d74d258614f615699fePavel Březina * Do not remove the casts below. They are vital. When later
641d684ee88c6540a4cf1d74d258614f615699fePavel Březina * compared with the data, the sign extension must have happened.
641d684ee88c6540a4cf1d74d258614f615699fePavel Březina v = (char) v;
3688374991afb34bbaf2b7843683fc13dd77879dPavel Březina v = (short) v;
3688374991afb34bbaf2b7843683fc13dd77879dPavel Březina v = (long) v;
3688374991afb34bbaf2b7843683fc13dd77879dPavel Březina ap_log_error(APLOG_MARK, APLOG_NOERRNO | APLOG_ERR, 0, s,
641d684ee88c6540a4cf1d74d258614f615699fePavel Březina MODNAME ": can't happen: m->type=%d", m->type);
641d684ee88c6540a4cf1d74d258614f615699fePavel Březina * parse one line from magic file, put into magic[index++] if valid
641d684ee88c6540a4cf1d74d258614f615699fePavel Březinastatic int parse(server_rec *serv, apr_pool_t *p, char *l, int lineno)
3688374991afb34bbaf2b7843683fc13dd77879dPavel Březina magic_server_config_rec *conf = (magic_server_config_rec *)
641d684ee88c6540a4cf1d74d258614f615699fePavel Březina ap_get_module_config(serv->module_config, &mime_magic_module);
3688374991afb34bbaf2b7843683fc13dd77879dPavel Březina /* allocate magic structure entry */
3688374991afb34bbaf2b7843683fc13dd77879dPavel Březina m = (struct magic *) apr_pcalloc(p, sizeof(struct magic));
641d684ee88c6540a4cf1d74d258614f615699fePavel Březina /* append to linked list */
641d684ee88c6540a4cf1d74d258614f615699fePavel Březina /* set values in magic structure */
3688374991afb34bbaf2b7843683fc13dd77879dPavel Březina while (*l == '>') {
3688374991afb34bbaf2b7843683fc13dd77879dPavel Březina ++l; /* step over */
641d684ee88c6540a4cf1d74d258614f615699fePavel Březina ++l; /* step over */
641d684ee88c6540a4cf1d74d258614f615699fePavel Březina /* get offset, then skip over it */
3688374991afb34bbaf2b7843683fc13dd77879dPavel Březina if (l == t) {
641d684ee88c6540a4cf1d74d258614f615699fePavel Březina ap_log_error(APLOG_MARK, APLOG_NOERRNO | APLOG_ERR, 0, serv,
71965bb18407ff45ada9e47cb6def086e48663c6Pavel Březina * read [.lbs][+-]nnnnn)
71965bb18407ff45ada9e47cb6def086e48663c6Pavel Březina if (*l == '.') {
71965bb18407ff45ada9e47cb6def086e48663c6Pavel Březina switch (*++l) {
71965bb18407ff45ada9e47cb6def086e48663c6Pavel Březina ap_log_error(APLOG_MARK, APLOG_NOERRNO | APLOG_ERR, 0, serv,
71965bb18407ff45ada9e47cb6def086e48663c6Pavel Březina MODNAME ": indirect offset type %c invalid", *l);
71965bb18407ff45ada9e47cb6def086e48663c6Pavel Březina if (apr_isdigit((unsigned char) *l)) {
71965bb18407ff45ada9e47cb6def086e48663c6Pavel Březina if (*s == '-')
71965bb18407ff45ada9e47cb6def086e48663c6Pavel Březina if (*t++ != ')') {
71965bb18407ff45ada9e47cb6def086e48663c6Pavel Březina ap_log_error(APLOG_MARK, APLOG_NOERRNO | APLOG_ERR, 0, serv,
71965bb18407ff45ada9e47cb6def086e48663c6Pavel Březina while (apr_isdigit((unsigned char) *l))
71965bb18407ff45ada9e47cb6def086e48663c6Pavel Březina if (*l == 'u') {
71965bb18407ff45ada9e47cb6def086e48663c6Pavel Březina /* get type, skip it */
71965bb18407ff45ada9e47cb6def086e48663c6Pavel Březina else if (strncmp(l, "string", NSTRING) == 0) {
3688374991afb34bbaf2b7843683fc13dd77879dPavel Březina else if (strncmp(l, "beshort", NBESHORT) == 0) {
3688374991afb34bbaf2b7843683fc13dd77879dPavel Březina else if (strncmp(l, "belong", NBELONG) == 0) {
71965bb18407ff45ada9e47cb6def086e48663c6Pavel Březina else if (strncmp(l, "bedate", NBEDATE) == 0) {
71965bb18407ff45ada9e47cb6def086e48663c6Pavel Březina else if (strncmp(l, "leshort", NLESHORT) == 0) {
71965bb18407ff45ada9e47cb6def086e48663c6Pavel Březina else if (strncmp(l, "lelong", NLELONG) == 0) {
71965bb18407ff45ada9e47cb6def086e48663c6Pavel Březina else if (strncmp(l, "ledate", NLEDATE) == 0) {
71965bb18407ff45ada9e47cb6def086e48663c6Pavel Březina ap_log_error(APLOG_MARK, APLOG_NOERRNO | APLOG_ERR, 0, serv,
71965bb18407ff45ada9e47cb6def086e48663c6Pavel Březina /* New-style anding: "0 byte&0x80 =0x80 dynamically linked" */
71965bb18407ff45ada9e47cb6def086e48663c6Pavel Březina if (*l == '&') {
3688374991afb34bbaf2b7843683fc13dd77879dPavel Březina m->mask = signextend(serv, m, strtol(l, &l, 0));
71965bb18407ff45ada9e47cb6def086e48663c6Pavel Březina switch (*l) {
71965bb18407ff45ada9e47cb6def086e48663c6Pavel Březina /* Old-style anding: "0 byte &0x80 dynamically linked" */
71965bb18407ff45ada9e47cb6def086e48663c6Pavel Březina /* FALL THROUGH */
3688374991afb34bbaf2b7843683fc13dd77879dPavel Březina if (*l == 'x' && apr_isspace((unsigned char) l[1])) {
fd04b25eaa5cd105da4122854d8bc1e702760e60Jakub Hrozek * now get last part - the description
da79bee1472a06b89be2df903fb0bd8ce600c610Petr Cech if (l[0] == '\b') {
da79bee1472a06b89be2df903fb0bd8ce600c610Petr Cech ap_log_error(APLOG_MARK, APLOG_NOERRNO | APLOG_DEBUG, 0, serv,
da79bee1472a06b89be2df903fb0bd8ce600c610Petr Cech MODNAME ": parse line=%d m=%x next=%x cont=%d desc=%s",
da79bee1472a06b89be2df903fb0bd8ce600c610Petr Cech#endif /* MIME_MAGIC_DEBUG */
da79bee1472a06b89be2df903fb0bd8ce600c610Petr Cech * Read a numeric value from a pointer, into the value union of a magic
da79bee1472a06b89be2df903fb0bd8ce600c610Petr Cech * pointer, according to the magic type. Update the string pointer to point
da79bee1472a06b89be2df903fb0bd8ce600c610Petr Cech * just after the number read. Return 0 for success, non-zero for failure.
da79bee1472a06b89be2df903fb0bd8ce600c610Petr Cechstatic int getvalue(server_rec *s, struct magic *m, char **p)
da79bee1472a06b89be2df903fb0bd8ce600c610Petr Cech *p = getstr(s, *p, m->value.s, sizeof(m->value.s), &slen);
da79bee1472a06b89be2df903fb0bd8ce600c610Petr Cech * Convert a string containing C character escapes. Stop at an unescaped
da79bee1472a06b89be2df903fb0bd8ce600c610Petr Cech * space or tab. Copy the converted version to "p", returning its length in
da79bee1472a06b89be2df903fb0bd8ce600c610Petr Cech * *slen. Return updated scan pointer as function result.
da79bee1472a06b89be2df903fb0bd8ce600c610Petr Cechstatic char *getstr(server_rec *serv, register char *s, register char *p,
a6a5a08a357d2adbb653b81bacc602ca3543c4c4Petr Cech register int c;
a6a5a08a357d2adbb653b81bacc602ca3543c4c4Petr Cech register int val;
a6a5a08a357d2adbb653b81bacc602ca3543c4c4Petr Cech while ((c = *s++) != '\0') {
a6a5a08a357d2adbb653b81bacc602ca3543c4c4Petr Cech if (apr_isspace((unsigned char) c))
a6a5a08a357d2adbb653b81bacc602ca3543c4c4Petr Cech ap_log_error(APLOG_MARK, APLOG_NOERRNO | APLOG_ERR, 0, serv,
a6a5a08a357d2adbb653b81bacc602ca3543c4c4Petr Cech if (c == '\\') {
a6a5a08a357d2adbb653b81bacc602ca3543c4c4Petr Cech switch (c = *s++) {
a6a5a08a357d2adbb653b81bacc602ca3543c4c4Petr Cech *p++ = (char) c;
a6a5a08a357d2adbb653b81bacc602ca3543c4c4Petr Cech *p++ = '\n';
a6a5a08a357d2adbb653b81bacc602ca3543c4c4Petr Cech *p++ = '\r';
a6a5a08a357d2adbb653b81bacc602ca3543c4c4Petr Cech *p++ = '\b';
a6a5a08a357d2adbb653b81bacc602ca3543c4c4Petr Cech *p++ = '\t';
a6a5a08a357d2adbb653b81bacc602ca3543c4c4Petr Cech *p++ = '\f';
a6a5a08a357d2adbb653b81bacc602ca3543c4c4Petr Cech *p++ = '\v';
a6a5a08a357d2adbb653b81bacc602ca3543c4c4Petr Cech /* \ and up to 3 octal digits */
a6a5a08a357d2adbb653b81bacc602ca3543c4c4Petr Cech c = *s++; /* try for 2 */
fd04b25eaa5cd105da4122854d8bc1e702760e60Jakub Hrozek c = *s++; /* try for 3 */
fd04b25eaa5cd105da4122854d8bc1e702760e60Jakub Hrozek *p++ = (char) val;
fd04b25eaa5cd105da4122854d8bc1e702760e60Jakub Hrozek /* \x and up to 3 hex digits */
fd04b25eaa5cd105da4122854d8bc1e702760e60Jakub Hrozek if (c >= 0) {
fd04b25eaa5cd105da4122854d8bc1e702760e60Jakub Hrozek if (c >= 0) {
fd04b25eaa5cd105da4122854d8bc1e702760e60Jakub Hrozek if (c >= 0) {
fd04b25eaa5cd105da4122854d8bc1e702760e60Jakub Hrozek *p++ = (char) val;
fd04b25eaa5cd105da4122854d8bc1e702760e60Jakub Hrozek *p++ = (char) c;
fd04b25eaa5cd105da4122854d8bc1e702760e60Jakub Hrozek/* Single hex char to int; -1 if not a hex char. */
fd04b25eaa5cd105da4122854d8bc1e702760e60Jakub Hrozekstatic int hextoint(int c)
fd04b25eaa5cd105da4122854d8bc1e702760e60Jakub Hrozek if (apr_isdigit((unsigned char) c))
fd04b25eaa5cd105da4122854d8bc1e702760e60Jakub Hrozek return c - '0';
fd04b25eaa5cd105da4122854d8bc1e702760e60Jakub Hrozek * return DONE to indicate it's been handled
fd04b25eaa5cd105da4122854d8bc1e702760e60Jakub Hrozek * return OK to indicate it's a regular file still needing handling
fd04b25eaa5cd105da4122854d8bc1e702760e60Jakub Hrozek * other returns indicate a failure of some sort
fd04b25eaa5cd105da4122854d8bc1e702760e60Jakub Hrozekstatic int fsmagic(request_rec *r, const char *fn)
fd04b25eaa5cd105da4122854d8bc1e702760e60Jakub Hrozek * (void) magic_rsl_printf(r,"character special (%d/%d)",
fd04b25eaa5cd105da4122854d8bc1e702760e60Jakub Hrozek * major(sb->st_rdev), minor(sb->st_rdev));
fd04b25eaa5cd105da4122854d8bc1e702760e60Jakub Hrozek * (void) magic_rsl_printf(r,"block special (%d/%d)",
fd04b25eaa5cd105da4122854d8bc1e702760e60Jakub Hrozek * major(sb->st_rdev), minor(sb->st_rdev));
fd04b25eaa5cd105da4122854d8bc1e702760e60Jakub Hrozek /* TODO add code to handle V7 MUX and Blit MUX files */
fd04b25eaa5cd105da4122854d8bc1e702760e60Jakub Hrozek * magic_rsl_puts(r,"fifo (named pipe)");
fd04b25eaa5cd105da4122854d8bc1e702760e60Jakub Hrozek /* We used stat(), the only possible reason for this is that the
fd04b25eaa5cd105da4122854d8bc1e702760e60Jakub Hrozek * symlink is broken.
fd04b25eaa5cd105da4122854d8bc1e702760e60Jakub Hrozek ap_log_rerror(APLOG_MARK, APLOG_NOERRNO | APLOG_ERR, 0, r,
fd04b25eaa5cd105da4122854d8bc1e702760e60Jakub Hrozek ap_log_rerror(APLOG_MARK, APLOG_NOERRNO | APLOG_ERR, 0, r,
fd04b25eaa5cd105da4122854d8bc1e702760e60Jakub Hrozek MODNAME ": invalid mode 0%o.", (unsigned int)r->finfo.protection);
fd04b25eaa5cd105da4122854d8bc1e702760e60Jakub Hrozek * regular file, check next possibility
fe6dd669d1e8606862879127f92c177bb7fdc1bdPetr Cech * softmagic - lookup one file in database (already read from /etc/magic by
fe6dd669d1e8606862879127f92c177bb7fdc1bdPetr Cech * apprentice.c). Passed the name and FILE * of one file to be typed.
fe6dd669d1e8606862879127f92c177bb7fdc1bdPetr Cech /* ARGSUSED1 *//* nbytes passed for regularity, maybe need later */
fe6dd669d1e8606862879127f92c177bb7fdc1bdPetr Cechstatic int softmagic(request_rec *r, unsigned char *buf, int nbytes)
fe6dd669d1e8606862879127f92c177bb7fdc1bdPetr Cech * Go through the whole list, stopping if you find a match. Process all the
fe6dd669d1e8606862879127f92c177bb7fdc1bdPetr Cech * continuations of that match before returning.
fe6dd669d1e8606862879127f92c177bb7fdc1bdPetr Cech * We support multi-level continuations:
fe6dd669d1e8606862879127f92c177bb7fdc1bdPetr Cech * At any time when processing a successful top-level match, there is a current
fe6dd669d1e8606862879127f92c177bb7fdc1bdPetr Cech * continuation level; it represents the level of the last successfully
fe6dd669d1e8606862879127f92c177bb7fdc1bdPetr Cech * matched continuation.
fe6dd669d1e8606862879127f92c177bb7fdc1bdPetr Cech * Continuations above that level are skipped as, if we see one, it means that
fe6dd669d1e8606862879127f92c177bb7fdc1bdPetr Cech * the continuation that controls them - i.e, the lower-level continuation
fe6dd669d1e8606862879127f92c177bb7fdc1bdPetr Cech * preceding them - failed to match.
fe6dd669d1e8606862879127f92c177bb7fdc1bdPetr Cech * Continuations below that level are processed as, if we see one, it means
fe6dd669d1e8606862879127f92c177bb7fdc1bdPetr Cech * we've finished processing or skipping higher-level continuations under the
fe6dd669d1e8606862879127f92c177bb7fdc1bdPetr Cech * control of a successful or unsuccessful lower-level continuation, and are
fe6dd669d1e8606862879127f92c177bb7fdc1bdPetr Cech * now seeing the next lower-level continuation and should process it. The
fe6dd669d1e8606862879127f92c177bb7fdc1bdPetr Cech * current continuation level reverts to the level of the one we're seeing.
fe6dd669d1e8606862879127f92c177bb7fdc1bdPetr Cech * Continuations at the current level are processed as, if we see one, there's
fe6dd669d1e8606862879127f92c177bb7fdc1bdPetr Cech * no lower-level continuation that may have failed.
fe6dd669d1e8606862879127f92c177bb7fdc1bdPetr Cech * If a continuation matches, we bump the current continuation level so that
fe6dd669d1e8606862879127f92c177bb7fdc1bdPetr Cech * higher-level continuations are processed.
fe6dd669d1e8606862879127f92c177bb7fdc1bdPetr Cechstatic int match(request_rec *r, unsigned char *s, int nbytes)
16212bbb2aaa55d0587515e72c0018479ae51be9Petr Cech magic_server_config_rec *conf = (magic_server_config_rec *)
16212bbb2aaa55d0587515e72c0018479ae51be9Petr Cech ap_get_module_config(r->server->module_config, &mime_magic_module);
16212bbb2aaa55d0587515e72c0018479ae51be9Petr Cech ap_log_rerror(APLOG_MARK, APLOG_NOERRNO | APLOG_DEBUG, 0, r,
16212bbb2aaa55d0587515e72c0018479ae51be9Petr Cech MODNAME ": match conf=%x file=%s m=%s m->next=%s last=%s",
16212bbb2aaa55d0587515e72c0018479ae51be9Petr Cech (conf->magic && conf->magic->next) ? "set" : "NULL",
16212bbb2aaa55d0587515e72c0018479ae51be9Petr Cech if (apr_isprint((((unsigned long) m) >> 24) & 255) &&
16212bbb2aaa55d0587515e72c0018479ae51be9Petr Cech ap_log_rerror(APLOG_MARK, APLOG_NOERRNO | APLOG_DEBUG, 0, r,
16212bbb2aaa55d0587515e72c0018479ae51be9Petr Cech "m=\"%c%c%c%c\"",
16212bbb2aaa55d0587515e72c0018479ae51be9Petr Cech ((unsigned long) m) & 255);
16212bbb2aaa55d0587515e72c0018479ae51be9Petr Cech ap_log_rerror(APLOG_MARK, APLOG_NOERRNO | APLOG_DEBUG, 0, r,
16212bbb2aaa55d0587515e72c0018479ae51be9Petr Cech /* check if main entry matches */
16212bbb2aaa55d0587515e72c0018479ae51be9Petr Cech !mcheck(r, &p, m)) {
16212bbb2aaa55d0587515e72c0018479ae51be9Petr Cech * main entry didn't match, flush its continuations
16212bbb2aaa55d0587515e72c0018479ae51be9Petr Cech ap_log_rerror(APLOG_MARK, APLOG_NOERRNO | APLOG_DEBUG, 0, r,
16212bbb2aaa55d0587515e72c0018479ae51be9Petr Cech MODNAME ": line=%d mc=%x mc->next=%x cont=%d desc=%s",
16212bbb2aaa55d0587515e72c0018479ae51be9Petr Cech * this trick allows us to keep *m in sync when the continue
fd04b25eaa5cd105da4122854d8bc1e702760e60Jakub Hrozek * advances the pointer
fd04b25eaa5cd105da4122854d8bc1e702760e60Jakub Hrozek /* if we get here, the main entry rule was a match */
fd04b25eaa5cd105da4122854d8bc1e702760e60Jakub Hrozek /* this will be the last run through the loop */
fd04b25eaa5cd105da4122854d8bc1e702760e60Jakub Hrozek ap_log_rerror(APLOG_MARK, APLOG_NOERRNO | APLOG_DEBUG, 0, r,
fd04b25eaa5cd105da4122854d8bc1e702760e60Jakub Hrozek /* print the match */
fd04b25eaa5cd105da4122854d8bc1e702760e60Jakub Hrozek * If we printed something, we'll need to print a blank before we
fd04b25eaa5cd105da4122854d8bc1e702760e60Jakub Hrozek * print something else.
fd04b25eaa5cd105da4122854d8bc1e702760e60Jakub Hrozek /* and any continuations that match */
fd04b25eaa5cd105da4122854d8bc1e702760e60Jakub Hrozek * while (m && m->next && m->next->cont_level != 0 && ( m = m->next
fd04b25eaa5cd105da4122854d8bc1e702760e60Jakub Hrozek while (m && (m->cont_level != 0)) {
fd04b25eaa5cd105da4122854d8bc1e702760e60Jakub Hrozek ap_log_rerror(APLOG_MARK, APLOG_NOERRNO | APLOG_DEBUG, 0, r,
fd04b25eaa5cd105da4122854d8bc1e702760e60Jakub Hrozek * We're at the end of the level "cont_level"
fd04b25eaa5cd105da4122854d8bc1e702760e60Jakub Hrozek * continuations.
fd04b25eaa5cd105da4122854d8bc1e702760e60Jakub Hrozek * This continuation matched. Print its message, with a
fd04b25eaa5cd105da4122854d8bc1e702760e60Jakub Hrozek * blank before it if the previous item printed and this
fd04b25eaa5cd105da4122854d8bc1e702760e60Jakub Hrozek * item isn't empty.
fd04b25eaa5cd105da4122854d8bc1e702760e60Jakub Hrozek /* space if previous printed */
360a4be4266d6a72be99dfd252623dc0527f5b84Pavel Březina * If we see any continuations at a higher level, process
54ed1b1214dbf9da1f481e8d193c81ce4312516bPavel Březina /* move to next continuation record */
e87b2a6e94c1066b3044fe683825ff5b4f8716c2Pavel Březina ap_log_rerror(APLOG_MARK, APLOG_NOERRNO | APLOG_DEBUG, 0, r,
3a5ea81007bd38ce511c37f65cc45d4b6b95ec44Pavel Březina MODNAME ": matched after %d rules", rule_counter);
28ebfa4373d1e7ce45b5d70a3619df1c074a661ePavel Březina ap_log_rerror(APLOG_MARK, APLOG_NOERRNO | APLOG_DEBUG, 0, r,
28ebfa4373d1e7ce45b5d70a3619df1c074a661ePavel Březina MODNAME ": failed after %d rules", rule_counter);
28ebfa4373d1e7ce45b5d70a3619df1c074a661ePavel Březina return 0; /* no match at all */
3a5ea81007bd38ce511c37f65cc45d4b6b95ec44Pavel Březinastatic void mprint(request_rec *r, union VALUETYPE *p, struct magic *m)
3a5ea81007bd38ce511c37f65cc45d4b6b95ec44Pavel Březina unsigned long v;
3a5ea81007bd38ce511c37f65cc45d4b6b95ec44Pavel Březina switch (m->type) {
71965bb18407ff45ada9e47cb6def086e48663c6Pavel Březina (void) magic_rsl_printf(r, m->desc, m->value.s);
fd04b25eaa5cd105da4122854d8bc1e702760e60Jakub Hrozek /* XXX: not multithread safe */
360a4be4266d6a72be99dfd252623dc0527f5b84Pavel Březina ap_log_rerror(APLOG_MARK, APLOG_NOERRNO | APLOG_ERR, 0, r,
360a4be4266d6a72be99dfd252623dc0527f5b84Pavel Březina MODNAME ": invalid m->type (%d) in mprint().",
360a4be4266d6a72be99dfd252623dc0527f5b84Pavel Březina (void) magic_rsl_printf(r, m->desc, (unsigned long) v);
360a4be4266d6a72be99dfd252623dc0527f5b84Pavel Březina * Convert the byte order of the data we are looking at
360a4be4266d6a72be99dfd252623dc0527f5b84Pavel Březinastatic int mconvert(request_rec *r, union VALUETYPE *p, struct magic *m)
360a4be4266d6a72be99dfd252623dc0527f5b84Pavel Březina switch (m->type) {
case BESHORT:
case BELONG:
case BEDATE:
case LESHORT:
case LELONG:
case LEDATE:
if (!mconvert(r, p, m))
case BYTE:
case SHORT:
case LONG:
if (!mconvert(r, p, m))
register unsigned long l = m->value.l;
int matched;
switch (m->type) {
case BYTE:
case SHORT:
case BESHORT:
case LESHORT:
case LONG:
case BELONG:
case LELONG:
case DATE:
case BEDATE:
case LEDATE:
case STRING:
* What we want here is: v = strncmp(m->value.s, p->s, m->vallen);
register unsigned char *a = (unsigned char *) m->value.s;
while (--len >= 0)
switch (m->reln) {
#if MIME_MAGIC_DEBUG
matched = v != l;
#if MIME_MAGIC_DEBUG
matched = v == l;
#if MIME_MAGIC_DEBUG
matched = v > l;
#if MIME_MAGIC_DEBUG
matched = (long) v > (long) l;
#if MIME_MAGIC_DEBUG
matched = v < l;
#if MIME_MAGIC_DEBUG
matched = (long) v < (long) l;
#if MIME_MAGIC_DEBUG
matched = (v & l) == l;
#if MIME_MAGIC_DEBUG
matched = (v & l) != l;
#if MIME_MAGIC_DEBUG
matched = 0;
m->reln);
return matched;
int has_escapes = 0;
char *token;
register struct names *p;
int small_nbytes;
/* look for tokens from names.h - this is expensive!, so we'll limit
if (has_escapes)
if (has_escapes) {
char *magic;
int maglen;
int silent;
} compr[] = {
unsigned char *newbuf;
int newsize;
for (i = 0; i < ncompr; i++) {
if (i == ncompr)
struct uncompress_parms {
request_rec *r;
int method;
char **env;
if (script_in) {
return (rc);
unsigned char **newch, int n)
parm.r = r;
* @(#)list.c 1.18 9/23/86 Public Domain - gnu $Id: mod_mime_magic.c,v 1.7
sum = 0;
for (i = sizeof(union record); --i >= 0;) {
register long value;
where++;
if (--digs <= 0)
value = 0;
--digs;
return value;
char *sub_filename;
#if MIME_MAGIC_DEBUG
suffix_pos--;
result = 0;
#if MIME_MAGIC_DEBUG
#if MIME_MAGIC_DEBUG
r->content_encoding =
r->content_language =
return result;
int result;
server_rec *s;
#if MIME_MAGIC_DEBUG
#if MIME_MAGIC_DEBUG
prevm = 0;
prevm = m;
int result;
return DECLINED;
if (r->content_type) {
return DECLINED;
return DECLINED;
if (!magic_set_config(r)) {
return HTTP_INTERNAL_SERVER_ERROR;
return result;
return magic_rsl_to_request(r);
static void register_hooks(void)