Blame


1 aac8053c 2021-08-12 xhr /*
2 aac8053c 2021-08-12 xhr * Copyright (c) 2021 Matthias Schmidt <xhr@giessen.ccc.de>
3 aac8053c 2021-08-12 xhr *
4 aac8053c 2021-08-12 xhr * Permission to use, copy, modify, and distribute this software for any
5 aac8053c 2021-08-12 xhr * purpose with or without fee is hereby granted, provided that the above
6 aac8053c 2021-08-12 xhr * copyright notice and this permission notice appear in all copies.
7 aac8053c 2021-08-12 xhr *
8 aac8053c 2021-08-12 xhr * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 aac8053c 2021-08-12 xhr * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 aac8053c 2021-08-12 xhr * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 aac8053c 2021-08-12 xhr * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 aac8053c 2021-08-12 xhr * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 aac8053c 2021-08-12 xhr * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 aac8053c 2021-08-12 xhr * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 aac8053c 2021-08-12 xhr */
16 aac8053c 2021-08-12 xhr
17 cd8c0dcb 2021-08-11 xhr #include <ctype.h>
18 149a02ca 2021-08-10 xhr #include <limits.h>
19 8c443bed 2021-08-10 xhr #include <string.h>
20 8c443bed 2021-08-10 xhr
21 8c443bed 2021-08-10 xhr #include "log.h"
22 8c443bed 2021-08-10 xhr #include "twind.h"
23 8c443bed 2021-08-10 xhr
24 cd8c0dcb 2021-08-11 xhr char hex_to_int(char);
25 8de8cc9e 2021-08-11 xhr char* uridecode(const char *);
26 8c443bed 2021-08-10 xhr
27 cd8c0dcb 2021-08-11 xhr /*
28 cd8c0dcb 2021-08-11 xhr * The following two functions are from https://geekhideout.com/urlcode.shtml
29 cd8c0dcb 2021-08-11 xhr * and provided without license restrictions
30 cd8c0dcb 2021-08-11 xhr */
31 cd8c0dcb 2021-08-11 xhr char hex_to_int(char ch) {
32 cd8c0dcb 2021-08-11 xhr return isdigit(ch) ? ch - '0' : tolower(ch) - 'a' + 10;
33 cd8c0dcb 2021-08-11 xhr }
34 cd8c0dcb 2021-08-11 xhr
35 8de8cc9e 2021-08-11 xhr char *
36 8de8cc9e 2021-08-11 xhr uridecode(const char *request)
37 cd8c0dcb 2021-08-11 xhr {
38 8de8cc9e 2021-08-11 xhr char *temp = xmalloc(strlen(request) + 1);
39 8de8cc9e 2021-08-11 xhr const char *p;
40 8de8cc9e 2021-08-11 xhr char *pt;
41 cd8c0dcb 2021-08-11 xhr
42 c4e27397 2021-08-12 xhr memset(temp, 0, strlen(request)+1);
43 c4e27397 2021-08-12 xhr
44 cd8c0dcb 2021-08-11 xhr p = request;
45 cd8c0dcb 2021-08-11 xhr pt = temp;
46 cd8c0dcb 2021-08-11 xhr
47 cd8c0dcb 2021-08-11 xhr while (*p) {
48 cd8c0dcb 2021-08-11 xhr if (*p == '%') {
49 cd8c0dcb 2021-08-11 xhr if (p[1] && p[2]) {
50 cd8c0dcb 2021-08-11 xhr *pt++ = hex_to_int(p[1]) << 4 | hex_to_int(p[2]);
51 cd8c0dcb 2021-08-11 xhr p += 2;
52 cd8c0dcb 2021-08-11 xhr }
53 8aaf981a 2021-08-12 xhr } else if (*p == '+') {
54 cd8c0dcb 2021-08-11 xhr *pt++ = ' ';
55 cd8c0dcb 2021-08-11 xhr } else {
56 cd8c0dcb 2021-08-11 xhr *pt++ = *p;
57 cd8c0dcb 2021-08-11 xhr }
58 cd8c0dcb 2021-08-11 xhr p++;
59 cd8c0dcb 2021-08-11 xhr }
60 cd8c0dcb 2021-08-11 xhr *pt = '\0';
61 cd8c0dcb 2021-08-11 xhr
62 8de8cc9e 2021-08-11 xhr return temp;
63 cd8c0dcb 2021-08-11 xhr }
64 cd8c0dcb 2021-08-11 xhr
65 cd8c0dcb 2021-08-11 xhr int
66 06fbded9 2021-08-12 xhr get_path_from_request(char *request, char *finalpath)
67 8c443bed 2021-08-10 xhr {
68 be8b7633 2021-08-13 xhr char hostname[MAXREQLEN];
69 be8b7633 2021-08-13 xhr char localpath[MAXREQLEN];
70 be8b7633 2021-08-13 xhr char temp[MAXREQLEN];
71 8de8cc9e 2021-08-11 xhr char *p, *decoded_request;
72 06fbded9 2021-08-12 xhr int pos = 0, ret;
73 8c443bed 2021-08-10 xhr
74 8c443bed 2021-08-10 xhr memset(hostname, 0, sizeof(hostname));
75 8c443bed 2021-08-10 xhr memset(localpath, 0, sizeof(localpath));
76 06fbded9 2021-08-12 xhr memset(temp, 0, sizeof(temp));
77 8c443bed 2021-08-10 xhr
78 8c443bed 2021-08-10 xhr p = request;
79 8c443bed 2021-08-10 xhr
80 8c443bed 2021-08-10 xhr if ((p = strchr(request, '\r')) == NULL) {
81 8c443bed 2021-08-10 xhr log_info("\\r missing from request, abort processing");
82 8c443bed 2021-08-10 xhr return -1;
83 8c443bed 2021-08-10 xhr }
84 8c443bed 2021-08-10 xhr
85 8c443bed 2021-08-10 xhr *p = '\0'; /* Strip \r\n */
86 8c443bed 2021-08-10 xhr p = request;
87 8c443bed 2021-08-10 xhr
88 8c443bed 2021-08-10 xhr if (strncmp(p, "gemini://", 9) != 0) {
89 8c443bed 2021-08-10 xhr log_info("Gemini scheme missing, abort processing");
90 8c443bed 2021-08-10 xhr return -1;
91 8c443bed 2021-08-10 xhr }
92 8c443bed 2021-08-10 xhr memmove(request, p + 9, strlen(request) + 1 - 9);
93 8c443bed 2021-08-10 xhr
94 8de8cc9e 2021-08-11 xhr decoded_request = uridecode(request);
95 cd8c0dcb 2021-08-11 xhr
96 8c443bed 2021-08-10 xhr /* save hostname */
97 8de8cc9e 2021-08-11 xhr if ((p = strchr(decoded_request, '/')) != NULL)
98 0f5f93fa 2021-08-12 xhr snprintf(hostname, strlen(decoded_request) - strlen(p)+1, "%s",
99 0f5f93fa 2021-08-12 xhr decoded_request);
100 8c443bed 2021-08-10 xhr else
101 8de8cc9e 2021-08-11 xhr snprintf(hostname, strlen(decoded_request)+1, "%s", decoded_request);
102 8c443bed 2021-08-10 xhr
103 8c443bed 2021-08-10 xhr /* Strip possible port (e.g. :1965) from hostname */
104 8c443bed 2021-08-10 xhr if ((p = strrchr(hostname, ':')) != NULL) {
105 8c443bed 2021-08-10 xhr pos = strlen(hostname) - strlen(p);
106 8c443bed 2021-08-10 xhr if (pos < 0 || pos > _POSIX_HOST_NAME_MAX)
107 8c443bed 2021-08-10 xhr fatalx("pos while shorten hostname out of range");
108 8c443bed 2021-08-10 xhr hostname[pos] = '\0';
109 8c443bed 2021-08-10 xhr }
110 8c443bed 2021-08-10 xhr
111 8c443bed 2021-08-10 xhr /* Remove ../ for security reasons */
112 8de8cc9e 2021-08-11 xhr while ((p = strstr(decoded_request, "/..")) != NULL) {
113 8de8cc9e 2021-08-11 xhr memmove(decoded_request, p + 3, strlen(p) + 1 - 3);
114 8c443bed 2021-08-10 xhr }
115 8c443bed 2021-08-10 xhr
116 8de8cc9e 2021-08-11 xhr if ((p = strchr(decoded_request, '/')) != NULL) {
117 8c443bed 2021-08-10 xhr /* Save all after the first / in localpath */
118 8de8cc9e 2021-08-11 xhr snprintf(localpath, strlen(decoded_request), "%s", p+1);
119 8c443bed 2021-08-10 xhr if (strlen(localpath) == 0) {
120 8c443bed 2021-08-10 xhr /*
121 8c443bed 2021-08-10 xhr * If the request is 'example.com/', localpart will be empty. In this case
122 8c443bed 2021-08-10 xhr * write the default to it.
123 8c443bed 2021-08-10 xhr */
124 8c443bed 2021-08-10 xhr sprintf(localpath, "index.gmi");
125 8c443bed 2021-08-10 xhr }
126 8c443bed 2021-08-10 xhr } else {
127 8c443bed 2021-08-10 xhr /* There is no slash in the request, so assume index.gmi */
128 8c443bed 2021-08-10 xhr sprintf(localpath, "index.gmi");
129 8c443bed 2021-08-10 xhr }
130 8c443bed 2021-08-10 xhr
131 8c443bed 2021-08-10 xhr /*
132 8c443bed 2021-08-10 xhr *We do not need to take the base dir aka /var/db/gemini into account
133 6aeb6b11 2021-08-12 xhr * since we already chroot() to _PATH_TWIND_CHROOT .
134 8c443bed 2021-08-10 xhr *
135 8c443bed 2021-08-10 xhr * Here, a string truncation could happen. This can be implemented
136 8c443bed 2021-08-10 xhr * better! XXX FIXME
137 8c443bed 2021-08-10 xhr */
138 be8b7633 2021-08-13 xhr snprintf(finalpath, MAXREQLEN, "%s/%s", hostname, localpath);
139 06fbded9 2021-08-12 xhr
140 3452a3bd 2021-08-12 xhr /* Check if the wanted path exists and if it's a directory */
141 06fbded9 2021-08-12 xhr ret = check_gemini_file(finalpath);
142 06fbded9 2021-08-12 xhr if (ret < 0) {
143 06fbded9 2021-08-12 xhr log_debug("%s not found", finalpath);
144 2cbe7c1a 2021-08-20 xhr free(decoded_request);
145 06fbded9 2021-08-12 xhr return -2;
146 06fbded9 2021-08-12 xhr } else if (ret == 1) {
147 06fbded9 2021-08-12 xhr log_debug("%s is a directory", finalpath);
148 06fbded9 2021-08-12 xhr /* Auto append index.gmi if destination is a directory */
149 be8b7633 2021-08-13 xhr snprintf(temp, MAXREQLEN, "%s", finalpath);
150 be8b7633 2021-08-13 xhr snprintf(finalpath, MAXREQLEN, "%s/index.gmi", temp);
151 06fbded9 2021-08-12 xhr }
152 06fbded9 2021-08-12 xhr
153 0f5f93fa 2021-08-12 xhr log_debug("Got request for %s on server %s -> %s",
154 0f5f93fa 2021-08-12 xhr localpath, hostname, finalpath);
155 8c443bed 2021-08-10 xhr
156 8de8cc9e 2021-08-11 xhr /* decoded_request is no longer used, so it can be freed */
157 8de8cc9e 2021-08-11 xhr free(decoded_request);
158 8de8cc9e 2021-08-11 xhr
159 8c443bed 2021-08-10 xhr return 0;
160 8c443bed 2021-08-10 xhr }
161 8c443bed 2021-08-10 xhr