common.c (3734B)
1 #include <ctype.h> 2 #include <errno.h> 3 #include <fcntl.h> 4 #include <limits.h> 5 #include <stdio.h> 6 #include <stdlib.h> 7 #include <string.h> 8 #include <sys/file.h> 9 #include <unistd.h> 10 11 #include "common.h" 12 #include "config.h" 13 #include "html.h" 14 15 #define REPOSITORY_MAXLEN 255 16 17 static int 18 repository_from_script_name(const char *script_name, 19 char *repository, 20 size_t len); 21 22 static int valid_repository(const char *); 23 24 int 25 build_repository_path(char *path, 26 size_t len, 27 const char *storage_root, 28 const char *repository) 29 { 30 if (snprintf(path, 31 len, 32 "%s/%s", 33 storage_root, 34 repository) >= (int) len) 35 return -1; 36 37 return 0; 38 } 39 40 int 41 build_storage_path(char *path, 42 size_t len, 43 const char *storage_root, 44 const char *repository, 45 const char *filename) 46 { 47 if (snprintf(path, len, 48 "%s/%s/%s", 49 storage_root, 50 repository, 51 filename) >= (int) len) 52 return -1; 53 54 return 0; 55 } 56 57 const char * 58 storage_root(void) 59 { 60 const char *root; 61 62 root = getenv("STORAGE_ROOT"); 63 if (root != NULL) 64 return root; 65 66 return DEFAULT_STORAGE_ROOT; 67 } 68 69 const char * 70 repository_lock_dir(void) 71 { 72 const char *dir; 73 74 dir = getenv("REPOSITORY_LOCK_DIR"); 75 if (dir != NULL && *dir != '\0') 76 return dir; 77 78 return DEFAULT_REPOSITORY_LOCK_DIR; 79 } 80 81 int 82 repository_lock(const char *repo) 83 { 84 char path[PATH_MAX]; 85 int fd; 86 87 if (repo == NULL || !valid_repository(repo)) 88 return -1; 89 90 if (snprintf(path, sizeof(path), "%s/%s", 91 repository_lock_dir(), repo) >= (int) sizeof(path)) 92 return -1; 93 94 fd = open(path, O_RDWR | O_CREAT | O_CLOEXEC | O_NOFOLLOW, 0600); 95 if (fd == -1) 96 return -1; 97 98 if (flock(fd, LOCK_EX) == -1) { 99 close(fd); 100 return -1; 101 } 102 return fd; 103 } 104 105 void 106 repository_unlock(int fd) 107 { 108 if (fd != -1) { 109 flock(fd, LOCK_UN); 110 close(fd); 111 } 112 } 113 114 const char * 115 repository(void) 116 { 117 static char repository[REPOSITORY_MAXLEN + 1]; 118 119 if (repository_from_script_name( 120 getenv("SCRIPT_NAME"), 121 repository, 122 sizeof(repository)) == -1) 123 return DEFAULT_REPOSITORY; 124 125 if (!valid_repository(repository)) 126 return DEFAULT_REPOSITORY; 127 128 return repository; 129 } 130 131 int 132 valid_repository(const char *repository) 133 { 134 const unsigned char *p; 135 136 if (repository == NULL || *repository == '\0') 137 return 0; 138 139 for (p = (const unsigned char *) repository; *p != '\0'; p++) { 140 if (!isalnum(*p) && 141 *p != '_' && 142 *p != '-') 143 return 0; 144 } 145 146 return 1; 147 } 148 149 static int 150 repository_from_script_name(const char *script_name, 151 char *repository, 152 size_t len) 153 { 154 const char *start; 155 const char *end; 156 size_t namelen; 157 158 if (script_name == NULL) 159 return -1; 160 161 if (script_name[0] != '/') 162 return -1; 163 164 start = script_name + 1; 165 if (*start == '\0') 166 return -1; 167 168 end = strchr(start, '/'); 169 if (end == NULL) 170 return -1; 171 172 namelen = (size_t) (end - start); 173 if (namelen == 0) 174 return -1; 175 176 if (namelen >= len) 177 return -1; 178 179 memcpy(repository, start, namelen); 180 repository[namelen] = '\0'; 181 182 return 0; 183 } 184 185 int 186 valid_filename(const char *filename) 187 { 188 const unsigned char *p; 189 190 if (filename == NULL || *filename == '\0') 191 return 0; 192 193 if (strcmp(filename, CONFIG_FILENAME) == 0) 194 return 0; 195 196 if (strncmp(filename, ".upload-", 8) == 0) 197 return 0; 198 199 if (strcmp(filename, ".") == 0 || 200 strcmp(filename, "..") == 0) 201 return 0; 202 203 for (p = (const unsigned char *) filename; *p != '\0'; p++) { 204 if (*p == '/' || 205 *p == '\\' || 206 *p == '"' || 207 *p == '\r' || 208 *p == '\n') 209 return 0; 210 211 if (iscntrl(*p)) 212 return 0; 213 } 214 215 return 1; 216 } 217 218 int 219 check_csrf_origin(void) 220 { 221 const char *origin; 222 char expected[CSRF_ORIGIN_MAX]; 223 224 if (global_config_csrf_origin( 225 expected, sizeof(expected)) == -1) 226 return -2; 227 228 origin = getenv("HTTP_ORIGIN"); 229 230 if (origin == NULL) 231 return -1; 232 233 if (strcmp(origin, expected) != 0) 234 return -1; 235 236 return 0; 237 }