2 aac8053c 2021-08-12 xhr * Copyright (c) 2021 Matthias Schmidt <xhr@giessen.ccc.de>
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.
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.
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>
21 8c443bed 2021-08-10 xhr #include "log.h"
22 8c443bed 2021-08-10 xhr #include "twind.h"
24 cd8c0dcb 2021-08-11 xhr char hex_to_int(char);
25 8de8cc9e 2021-08-11 xhr char* uridecode(const char *);
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
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;
36 8de8cc9e 2021-08-11 xhr uridecode(const char *request)
38 8de8cc9e 2021-08-11 xhr char *temp = xmalloc(strlen(request) + 1);
39 8de8cc9e 2021-08-11 xhr const char *p;
42 c4e27397 2021-08-12 xhr memset(temp, 0, strlen(request)+1);
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]);
53 8aaf981a 2021-08-12 xhr } else if (*p == '+') {
66 06fbded9 2021-08-12 xhr get_path_from_request(char *request, char *finalpath)
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;
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));
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");
85 8c443bed 2021-08-10 xhr *p = '\0'; /* Strip \r\n */
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");
92 8c443bed 2021-08-10 xhr memmove(request, p + 9, strlen(request) + 1 - 9);
94 8de8cc9e 2021-08-11 xhr decoded_request = uridecode(request);
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);
101 8de8cc9e 2021-08-11 xhr snprintf(hostname, strlen(decoded_request)+1, "%s", decoded_request);
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';
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);
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) {
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.
124 8c443bed 2021-08-10 xhr sprintf(localpath, "index.gmi");
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");
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 .
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
138 be8b7633 2021-08-13 xhr snprintf(finalpath, MAXREQLEN, "%s/%s", hostname, localpath);
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);
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);
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);
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);