simplefiles

A lightweight C CGI web application for managing files.
git clone https://scm.kuandu.systems/git-raw/simplefiles.git
Log | Files | Refs | README | LICENSE

config.c (4971B)


      1 #include <ctype.h>
      2 #include <errno.h>
      3 #include <limits.h>
      4 #include <stdio.h>
      5 #include <stdlib.h>
      6 #include <string.h>
      7 
      8 #include "common.h"
      9 #include "config.h"
     10 
     11 static int
     12 build_config_path(char *path, size_t len)
     13 {
     14 	char repository_path[PATH_MAX];
     15 
     16 	if (build_repository_path(repository_path,
     17 		sizeof(repository_path),
     18 		storage_root(),
     19 		repository()) == -1)
     20 		return -1;
     21 
     22 	if (snprintf(path, len, "%s/%s", repository_path, CONFIG_FILENAME) >=
     23 	    (int) len)
     24 		return -1;
     25 
     26 	return 0;
     27 }
     28 
     29 static off_t
     30 config_value(const char *name, off_t default_value)
     31 {
     32 	char path[PATH_MAX];
     33 	char line[256];
     34 	FILE *fp;
     35 	size_t namelen;
     36 
     37 	if (build_config_path(path, sizeof(path)) == -1)
     38 		return default_value;
     39 
     40 	fp = fopen(path, "r");
     41 	if (fp == NULL)
     42 		return default_value;
     43 
     44 	namelen = strlen(name);
     45 
     46 	while (fgets(line, sizeof(line), fp) != NULL) {
     47 		char *p;
     48 		char *end;
     49 		char *value;
     50 		char *ep;
     51 		long long parsed;
     52 
     53 		/* Strip newline. */
     54 		line[strcspn(line, "\r\n")] = '\0';
     55 
     56 		/* Skip leading whitespace. */
     57 		p = line;
     58 		while (isspace((unsigned char) *p))
     59 			p++;
     60 
     61 		/* Ignore blank lines and comments. */
     62 		if (*p == '\0' || *p == '#')
     63 			continue;
     64 
     65 		/*
     66 		 * Match:
     67 		 *
     68 		 *     NAME=value
     69 		 *
     70 		 * and allow whitespace around the '='.
     71 		 */
     72 		if (strncmp(p, name, namelen) != 0)
     73 			continue;
     74 
     75 		end = p + namelen;
     76 
     77 		if (*end != '=' && !isspace((unsigned char) *end))
     78 			continue;
     79 
     80 		while (isspace((unsigned char) *end))
     81 			end++;
     82 
     83 		if (*end != '=')
     84 			continue;
     85 
     86 		end++;
     87 		while (isspace((unsigned char) *end))
     88 			end++;
     89 
     90 		value = end;
     91 
     92 		/* Trim trailing whitespace. */
     93 		end = value + strlen(value);
     94 		while (end > value &&
     95 		    isspace((unsigned char) end[-1]))
     96 			end--;
     97 		*end = '\0';
     98 
     99 		if (*value == '\0')
    100 			continue;
    101 
    102 		errno = 0;
    103 		parsed = strtoll(value, &ep, 10);
    104 
    105 		if (errno != 0 || ep == value || *ep != '\0')
    106 			continue;
    107 
    108 		if (parsed <= 0)
    109 			continue;
    110 
    111 		fclose(fp);
    112 		return (off_t) parsed;
    113 	}
    114 
    115 	fclose(fp);
    116 	return default_value;
    117 }
    118 
    119 static int
    120 config_string_file(const char *path,
    121     const char *name,
    122     char *value,
    123     size_t value_len)
    124 {
    125 	char line[256];
    126 	FILE *fp;
    127 	size_t namelen;
    128 
    129 	if (path == NULL || name == NULL ||
    130 	    value == NULL || value_len == 0)
    131 		return -1;
    132 
    133 	fp = fopen(path, "r");
    134 	if (fp == NULL)
    135 		return -1;
    136 
    137 	namelen = strlen(name);
    138 
    139 	while (fgets(line, sizeof(line), fp) != NULL) {
    140 		char *p;
    141 		char *end;
    142 		char *v;
    143 		size_t len;
    144 
    145 		line[strcspn(line, "\r\n")] = '\0';
    146 
    147 		p = line;
    148 		while (isspace((unsigned char) *p))
    149 			p++;
    150 
    151 		if (*p == '\0' || *p == '#')
    152 			continue;
    153 
    154 		if (strncmp(p, name, namelen) != 0)
    155 			continue;
    156 
    157 		end = p + namelen;
    158 
    159 		if (*end != '=' && !isspace((unsigned char) *end))
    160 			continue;
    161 		while (isspace((unsigned char) *end))
    162 			end++;
    163 
    164 		if (*end != '=')
    165 			continue;
    166 
    167 		end++;
    168 		while (isspace((unsigned char) *end))
    169 			end++;
    170 
    171 		v = end;
    172 
    173 		end = v + strlen(v);
    174 		while (end > v &&
    175 		    isspace((unsigned char) end[-1]))
    176 			end--;
    177 
    178 		*end = '\0';
    179 
    180 		if (*v == '\0')
    181 			continue;
    182 
    183 		len = strlen(v);
    184 
    185 		if (len >= value_len) {
    186 			fclose(fp);
    187 			return -1;
    188 		}
    189 		memcpy(value, v, len + 1);
    190 
    191 		fclose(fp);
    192 		return 0;
    193 	}
    194 
    195 	fclose(fp);
    196 	return -1;
    197 }
    198 
    199 static const char *
    200 global_config_filename(void)
    201 {
    202 	const char *path;
    203 
    204 	path = getenv("SIMPLEFILES_CONFIG");
    205 
    206 	if (path != NULL && *path != '\0')
    207 		return path;
    208 
    209 	return GLOBAL_CONFIG_FILENAME;
    210 }
    211 
    212 int
    213 global_config_string(const char *name,
    214     char *value,
    215     size_t value_len)
    216 {
    217 	return config_string_file(
    218 	    global_config_filename(),
    219 	    name,
    220 	    value,
    221 	    value_len);
    222 }
    223 
    224 int
    225 global_config_csrf_origin(char *origin,
    226     size_t origin_len)
    227 {
    228 	return global_config_string(
    229 	    "CSRF_ORIGIN",
    230 	    origin,
    231 	    origin_len);
    232 }
    233 
    234 const char *
    235 simplefiles_root(void)
    236 {
    237 	const char *root;
    238 
    239 	root = getenv("SIMPLEFILES_ROOT");
    240 	if (root != NULL && *root != '\0')
    241 		return root;
    242 
    243 	return SIMPLEFILES_ROOT_DEFAULT;
    244 }
    245 off_t
    246 config_max_upload(void)
    247 {
    248 	return config_value("MAX_UPLOAD", DEFAULT_MAX_UPLOAD);
    249 }
    250 off_t
    251 config_repo_quota(void)
    252 {
    253 	return config_value("QUOTA", DEFAULT_REPO_QUOTA);
    254 }
    255 
    256 int
    257 config_write_allowed(void)
    258 {
    259 	char path[PATH_MAX];
    260 	char value[16];
    261 	char admin[64];
    262 	const char *remote_user;
    263 
    264 	if (build_config_path(path, sizeof(path)) == -1)
    265 		return 0;
    266 
    267 	if (config_string_file(path,
    268 	    "READ_ONLY",
    269 	    value,
    270 	    sizeof(value)) == 0 &&
    271 	    strcmp(value, "1") == 0)
    272 		return 0;
    273 
    274 	if (config_string_file(path,
    275 	    "ADMIN_USER",
    276 	    admin,
    277 	    sizeof(admin)) == -1)
    278 		return 0;
    279 
    280 	remote_user = getenv("REMOTE_USER");
    281 
    282 	if (remote_user == NULL || *remote_user == '\0')
    283 		return 0;
    284 
    285 	return strcmp(remote_user, admin) == 0;
    286 }
    287 
    288 int
    289 config_access_allowed(void)
    290 {
    291 	char value[16];
    292 	const char *user;
    293 
    294 	user = getenv("REMOTE_USER");
    295 
    296 	/*
    297 	 * Authenticated users may read.
    298 	 */
    299 	if (user != NULL && *user != '\0')
    300 		return 1;
    301 
    302 	/* Anonymous read must be explicitly enabled. */
    303 	if (global_config_string("ANONYMOUS_READ",
    304 	    value, sizeof(value)) == 0 &&
    305 	    strcmp(value, "1") == 0)
    306 		return 1;
    307 
    308 	return 0;
    309 }