utils.c (3178B)
1 #include "utils.h" 2 3 #include <err.h> 4 #include <errno.h> 5 #include <limits.h> 6 #include <stdlib.h> 7 #include <string.h> 8 #include <sys/stat.h> 9 #include <sys/types.h> 10 11 #include "third_party/openbsd/strlcat.h" 12 #include "third_party/openbsd/strlcpy.h" 13 14 char* path_concat(char* out, size_t out_len, const char* p1, const char* p2) { 15 size_t p1_len = strlen(p1); 16 size_t p2_len = strlen(p2); 17 if (p1_len == 0) { 18 estrlcpy(out, p2, out_len); 19 return out; 20 } 21 if (p2_len == 0) { 22 estrlcpy(out, p1, out_len); 23 return out; 24 } 25 if (p1_len + p2_len + 2 > out_len) { 26 errx(1, "path truncated. p1: '%s' p2: '%s'", p1, p2); 27 } 28 if (snprintf(out, out_len, "%s/%s", p1, p2) < 0) { 29 err(1, "snprintf"); 30 } 31 return out; 32 } 33 34 int mkdirp(const char* path) { 35 char mut_path[PATH_MAX]; 36 estrlcpy(mut_path, path, sizeof(mut_path)); 37 38 for (char* p = mut_path + (mut_path[0] == '/'); *p; p++) { 39 if (*p != '/') { 40 continue; 41 } 42 *p = '\0'; 43 if (mkdir(mut_path, S_IRWXU | S_IRWXG | S_IRWXO) < 0 && errno != EEXIST) { 44 return -1; 45 } 46 *p = '/'; 47 } 48 if (mkdir(mut_path, S_IRWXU | S_IRWXG | S_IRWXO) < 0 && errno != EEXIST) { 49 return -1; 50 } 51 return 0; 52 } 53 54 void* ecalloc(size_t count, size_t size) { 55 void* ptr = calloc(count, size); 56 if (!ptr) { 57 err(1, "calloc"); 58 } 59 return ptr; 60 } 61 62 char* estrdup(const char* s) { 63 char* out_str = strdup(s); 64 if (!out_str) { 65 err(1, "strcpy"); 66 } 67 return out_str; 68 } 69 70 size_t estrlcpy(char* dst, const char* src, size_t dsize) { 71 size_t len = strlcpy(dst, src, dsize); 72 if (len >= dsize) { 73 errx(1, "string truncated: '%s'", src); 74 } 75 return len; 76 } 77 78 size_t estrlcat(char* dst, const char* src, size_t dsize) { 79 size_t len = strlcat(dst, src, dsize); 80 if (len >= dsize) { 81 errx(1, "string truncated: '%s'", src); 82 } 83 return len; 84 } 85 86 FILE* efopen(const char* filename, const char* flags) { 87 FILE* fp = fopen(filename, flags); 88 if (!fp) { 89 err(1, "fopen: '%s'", filename); 90 } 91 return fp; 92 } 93 94 void checkfileerror(FILE* fp, const char* name, char mode) { 95 if (mode == 'r' && ferror(fp)) { 96 errx(1, "read error: %s", name); 97 } else if (mode == 'w' && (fflush(fp) || ferror(fp))) { 98 errx(1, "write error: %s", name); 99 } 100 } 101 102 bool is_safe_repo_path(const char* path) { 103 if (path[0] == '/') { 104 return false; 105 } 106 107 const char* p = path; 108 while (*p) { 109 /* Locate the next path component, or end of path. */ 110 const char* start = p; 111 while (*p && *p != '/') { 112 p++; 113 } 114 115 /* Check for "..". */ 116 size_t len = p - start; 117 if (len == 2 && start[0] == '.' && start[1] == '.') { 118 return false; 119 } 120 121 /* Skip over the path delimiter. */ 122 if (*p) { 123 p++; 124 } 125 } 126 return true; 127 } 128 129 bool is_safe_url(const char* url) { 130 return strncmp(url, "http://", 7) == 0 || strncmp(url, "https://", 8) == 0 || 131 strncmp(url, "git://", 6) == 0; 132 } 133 134 bool is_safe_mailto(const char* email) { 135 /* A basic sanity check. We don't need a full RFC 5322 validator. We just 136 * want to prevent injection of HTML/JS. Disallow characters that are special 137 * in HTML or could be used to craft malicious URIs. */ 138 return strpbrk(email, "<>\"'\\\r\n") == NULL; 139 }