Check-in [5ea7bc0001]
Overview
Comment:Added compile-time support for a fake chroot mode instead of using a real chroot (this may change into a runtime option one day)
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1:5ea7bc000130190bc06ffe49d09549bfe879bc36
User & Date: rkeene on 2016-08-17 16:21:30
Other Links: manifest | tags
Context
2016-08-17
16:22
Filed 1.18 check-in: a78878e047 user: rkeene tags: trunk, 1.18
16:21
Added compile-time support for a fake chroot mode instead of using a real chroot (this may change into a runtime option one day) check-in: 5ea7bc0001 user: rkeene tags: trunk
2016-08-09
16:51
Disabled -Werror, it is a bad idea for releases to include check-in: 1a822c0ca5 user: rkeene tags: trunk
Changes

Modified README from [d62e07fe87] to [8ec76224c9].

    67     67   	This is an internal option and should only be used during development.
    68     68   
    69     69      4. Differing HTTP semantics (CFLAGS, -DFILED_NONBLOCK_HTTP=1)
    70     70   	It is possible that some HTTP clients may not process the HTTP stream
    71     71   	being delivered if they cannot write to the HTTP stream itself.  This
    72     72   	has not been observed yet, but it is possible.  If these semantics are
    73     73   	needed (and they should not be) then they can be enabled with this
    74         -	flag at the cost of performance
           74  +	flag at the cost of performance.
           75  +
           76  +   5. Differing chroot() semantics (CFLAGS, -DFILED_FAKE_CHROOT=1)
           77  +        In some cases it is desirable to mangle paths with a path prefix
           78  +        rather than call chroot() at startup.  This is less secure and slower
           79  +        and should be generally avoided -- however it may be necessary to do.
           80  +        In these cases the executable may be compiled with the
           81  +        FILED_FAKE_CHROOT C preprocessor macro defined and instead of calling
           82  +        chroot() all HTTP requests will have the root suffix specified as the
           83  +        argument to the "-r" or "--root" option prepended to them.
    75     84   
    76         -   5. MIME Types (MIMETYPES)
    77         -	For single-file convience "filed" compiles the mapping of file
           85  +   6. MIME Types (MIMETYPES)
           86  +	For single-file convenience "filed" compiles the mapping of file
    78     87   	extensions (the string in the filename following its last dot ("."))
    79     88   	into the executable.  This mapping comes from a file in the format of
    80     89   		type1   type1_extension1 type1_extension2...
    81     90   		type2   type2_extension1 type2_extension2...
    82     91   		...
    83     92   	However it may not be desirable to include this mapping, or it may be
    84     93   	desirable to use your own mapping rather than the default one.  This

Modified filed.c from [7391155930] to [e20f1f0a83].

   115    115   	attr = attr;
   116    116   }
   117    117   #endif
   118    118   
   119    119   /* Configuration options that work threads need to be aware of */
   120    120   struct filed_options {
   121    121   	int vhosts_enabled;
          122  +	const char *fake_newroot;
   122    123   };
   123    124   
   124    125   /* Arguments for worker threads */
   125    126   struct filed_worker_thread_args {
   126    127   	int fd;
   127    128   	struct filed_options options;
   128    129   };
................................................................................
   862    863   		(unsigned long long) time(NULL),
   863    864   		(unsigned long long) random(),
   864    865   		(unsigned long long) random(),
   865    866   		(unsigned long long) random(),
   866    867   		(unsigned long long) random()
   867    868   	);
   868    869   }
          870  +
          871  +#ifdef FILED_FAKE_CHROOT
          872  +/* Translate a path into a fake chroot path */
          873  +static const char *filed_path_translate(const char *path, struct filed_options *options) {
          874  +	static __thread char pathBuffer[8192];
          875  +	int snprintf_ret;
          876  +
          877  +	/* If no alternative root is specified, return the unadorned path */
          878  +	if (!options->fake_newroot) {
          879  +		return(path);
          880  +	}
          881  +
          882  +	/* Verify that this request will not go outside of the specified root */
          883  +	if (strstr(path, "/../") != NULL || path[0] != '/') {
          884  +		filed_log_msg_debug("Unable to translate path \"%s\", contains invalid characters", path);
          885  +
          886  +		return(options->fake_newroot);
          887  +	}
          888  +
          889  +	/* Create the new path into our local (TLS) static buffer */
          890  +	snprintf_ret = snprintf(pathBuffer, sizeof(pathBuffer), "%s/%s", options->fake_newroot, path);
          891  +	if (snprintf_ret < 0 || ((unsigned int) snprintf_ret) >= sizeof(pathBuffer)) {
          892  +		filed_log_msg_debug("Unable to translate path \"%s\", will not fit into new buffer", path);
          893  +
          894  +		return(options->fake_newroot);
          895  +	}
          896  +
          897  +	filed_log_msg_debug("Translating path \"%s\" into \"%s\"", path, pathBuffer);
          898  +
          899  +	/* Return the new path */
          900  +	return(pathBuffer);
          901  +}
          902  +
          903  +static void filed_path_translate_set_root(const char *var, struct filed_options *options, const char *val) {
          904  +	options->fake_newroot = strdup(val);
          905  +
          906  +	return;
          907  +
          908  +	/* var is only used in the macro -- discard it here */
          909  +	var = var;
          910  +}
          911  +#else
          912  +#define filed_path_translate(path, options) path
          913  +#define filed_path_translate_set_root(var, options, val) var = strdup(val)
          914  +#endif
   869    915   
   870    916   /* Open a file and return file information */
   871         -static struct filed_fileinfo *filed_open_file(const char *path, struct filed_fileinfo *buffer) {
          917  +static struct filed_fileinfo *filed_open_file(const char *path, struct filed_fileinfo *buffer, struct filed_options *options) {
   872    918   	struct filed_fileinfo *cache;
   873    919   	unsigned int cache_idx;
   874    920   	off_t len;
   875    921   	int fd;
   876    922   
   877    923   	if (filed_fileinfo_fdcache_size != 0) {
   878    924   		cache_idx = filed_hash((const unsigned char *) path, filed_fileinfo_fdcache_size);
................................................................................
   890    936   		cache->path[0] = '\0';
   891    937   		cache->fd = -1;
   892    938   	}
   893    939   
   894    940   	if (strcmp(path, cache->path) != 0) {
   895    941   		filed_log_msg_debug("Cache miss for idx: %lu: OLD \"%s\", NEW \"%s\"", (unsigned long) cache_idx, cache->path, path);
   896    942   
   897         -		fd = open(path, O_RDONLY | O_LARGEFILE);
          943  +		fd = open(filed_path_translate(path, options), O_RDONLY | O_LARGEFILE);
   898    944   		if (fd < 0) {
   899    945   			if (filed_fileinfo_fdcache_size != 0) {
   900    946   				pthread_mutex_unlock(&cache->mutex);
   901    947   			}
   902    948   
   903    949   			return(NULL);
   904    950   		}
................................................................................
   941    987   		memcpy(buffer->etag, cache->etag, sizeof(buffer->etag));
   942    988   		buffer->lastmod = buffer->lastmod_b + (cache->lastmod - cache->lastmod_b);
   943    989   
   944    990   		pthread_mutex_unlock(&cache->mutex);
   945    991   	}
   946    992   
   947    993   	return(buffer);
          994  +
          995  +	/* options is only used if fake chroot is enabled, confuse the compiler */
          996  +	options = options;
   948    997   }
   949    998   
   950    999   /* Process an HTTP request and return the path requested */
   951   1000   static struct filed_http_request *filed_get_http_request(FILE *fp, struct filed_http_request *buffer_st, struct filed_options *options) {
   952   1001   	char *method, *path;
   953   1002   	char *buffer, *workbuffer, *workbuffer_next;
   954   1003   	char *fgets_ret;
................................................................................
  1235   1284   	/* If the requested path is a directory, redirect to index page */
  1236   1285   	if (request->type == FILED_REQUEST_TYPE_DIRECTORY) {
  1237   1286   		filed_redirect_index(fp, date_current, path, log);
  1238   1287   
  1239   1288   		return(FILED_CONNECTION_CLOSE);
  1240   1289   	}
  1241   1290   
  1242         -	fileinfo = filed_open_file(path, &request->fileinfo);
         1291  +	fileinfo = filed_open_file(path, &request->fileinfo, options);
  1243   1292   	if (fileinfo == NULL) {
  1244   1293   		filed_error_page(fp, date_current, 404, request->method, "open_failed", log);
  1245   1294   
  1246   1295   		return(FILED_CONNECTION_CLOSE);
  1247   1296   	}
  1248   1297   
  1249   1298   	if (request->headers.range.present) {
................................................................................
  1679   1728   
  1680   1729   	return(0);
  1681   1730   }
  1682   1731   
  1683   1732   /* Run process */
  1684   1733   int main(int argc, char **argv) {
  1685   1734   	struct option options[12];
  1686         -	struct filed_options thread_options;
         1735  +	struct filed_options thread_options = {0};
  1687   1736   	const char *bind_addr = BIND_ADDR, *newroot = NULL, *log_file = LOG_FILE;
  1688   1737   	FILE *log_fp;
  1689   1738   	uid_t user = 0;
  1690   1739   	int port = PORT, thread_count = THREAD_COUNT;
  1691   1740   	int cache_size = CACHE_SIZE;
  1692   1741   	int init_ret, chroot_ret, setuid_ret, lookup_ret, chdir_ret;
  1693   1742   	int setuid_enabled = 0, daemon_enabled = 0;
  1694   1743   	int ch;
  1695   1744   	int fd;
  1696   1745   
  1697         -	/* Set default values */
  1698         -	thread_options.vhosts_enabled = 0;
  1699         -
  1700   1746   	/* Process arguments */
  1701   1747   	filed_getopt_long_setopt(&options[0], "port", required_argument, 'p');
  1702   1748   	filed_getopt_long_setopt(&options[1], "threads", required_argument, 't');
  1703   1749   	filed_getopt_long_setopt(&options[2], "cache", required_argument, 'c');
  1704   1750   	filed_getopt_long_setopt(&options[3], "bind", required_argument, 'b');
  1705   1751   	filed_getopt_long_setopt(&options[4], "user", required_argument, 'u');
  1706   1752   	filed_getopt_long_setopt(&options[5], "root", required_argument, 'r');
................................................................................
  1730   1776   				if (lookup_ret != 0) {
  1731   1777   					filed_print_help(stderr, 0, "Invalid username specified");
  1732   1778   
  1733   1779   					return(1);
  1734   1780   				}
  1735   1781   				break;
  1736   1782   			case 'r':
  1737         -				newroot = strdup(optarg);
         1783  +				filed_path_translate_set_root(newroot, &thread_options, optarg);
  1738   1784   				break;
  1739   1785   			case 'l':
  1740   1786   				log_file = strdup(optarg);
  1741   1787   				break;
  1742   1788   			case 'd':
  1743   1789   				daemon_enabled = 1;
  1744   1790   				break;