Blame


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