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 }