1 /*
2  * Gophernicus - Copyright (c) 2009-2018 Kim Holviala <kimholviala@fastmail.com>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *     * Redistributions of source code must retain the above copyright
8  *       notice, this list of conditions and the following disclaimer.
9  *     * Redistributions in binary form must reproduce the above copyright
10  *       notice, this list of conditions and the following disclaimer in the
11  *       documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
14  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
15  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
16  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
17  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
20  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
22  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23  */
24 
25 #ifndef _GOPHERNICUS_H
26 #define _GOPHERNICUS_H
27 
28 
29 /*
30  * Ignore useless snprintf() format truncation warnings on GCC 7+
31  */
32 #if __GNUC__ >= 7
33 #pragma GCC diagnostic ignored "-Wformat-truncation"
34 #endif
35 
36 
37 /*
38  * Features
39  */
40 #undef  ENABLE_STRICT_RFC1436	/* Follow RFC1436 to the letter */
41 #undef  ENABLE_AUTOHIDING	/* Hide manually listed resources from generated menus */
42 #define ENABLE_HAPROXY1		/* Autodetect HAproxy/Stunnel proxy protocol v1 */
43 
44 
45 /*
46  * Platform configuration
47  */
48 
49 /* Defaults should fit standard POSIX systems */
50 #define HAVE_IPv4		/* IPv4 should work anywhere */
51 #define HAVE_IPv6		/* Requires modern POSIX */
52 #define HAVE_PASSWD		/* For systems with passwd-like userdb */
53 #define PASSWD_MIN_UID 100	/* Minimum allowed UID for ~userdirs */
54 #define HAVE_LOCALES		/* setlocale() and friends */
55 #define HAVE_SHMEM		/* Shared memory support */
56 #define HAVE_UNAME		/* uname() */
57 #define HAVE_POPEN		/* popen() */
58 #define HAVE_STRLCPY		/* strlcpy() from OpenBSD */
59 #undef  HAVE_SENDFILE		/* sendfile() in Linux & others */
60 /* #undef  HAVE_LIBWRAP		   autodetected, don't enable here */
61 
62 /* Linux */
63 #ifdef __linux
64 #undef  PASSWD_MIN_UID
65 #define PASSWD_MIN_UID 500
66 #define _FILE_OFFSET_BITS 64
67 #endif
68 
69 /* Embedded Linux with uClibc */
70 #ifdef __UCLIBC__
71 #undef HAVE_SHMEM
72 #undef HAVE_PASSWD
73 #endif
74 
75 /* Haiku */
76 #ifdef __HAIKU__
77 #undef HAVE_SHMEM
78 #undef HAVE_PASSWD
79 #endif
80 
81 /* OpenBSD */
82 #ifdef __OpenBSD__
83 #define HAVE_STRLCPY
84 #endif
85 
86 /* MacOS */
87 #if defined(__APPLE__)
88 #if __MAC_OS_X_VERSION_MIN_REQUIRED >= __MAC_10_10
89 #define HAVE_STRLCPY
90 #endif
91 #endif
92 
93 /* AIX */
94 #if defined(_AIX)
95 #define _LARGE_FILES 1
96 #endif
97 
98 /* Add other OS-specific defines here */
99 
100 /*
101  * Include headers
102  */
103 #include <stdio.h>
104 #include <stdlib.h>
105 #include <unistd.h>
106 #include <sys/types.h>
107 #include <sys/stat.h>
108 #include <dirent.h>
109 #include <string.h>
110 #include <libgen.h>
111 #include <time.h>
112 #include <syslog.h>
113 #include <errno.h>
114 #include <pwd.h>
115 #include <limits.h>
116 
117 #ifdef HAVE_SENDFILE
118 #include <sys/sendfile.h>
119 #include <fcntl.h>
120 #endif
121 
122 #ifdef HAVE_LOCALES
123 #include <locale.h>
124 #endif
125 
126 #ifdef HAVE_SHMEM
127 #include <sys/ipc.h>
128 #include <sys/shm.h>
129 #else
130 #define shm_state void
131 #endif
132 
133 #if defined(HAVE_IPv4) || defined(HAVE_IPv6)
134 #include <sys/socket.h>
135 #include <netinet/in.h>
136 #include <arpa/inet.h>
137 #endif
138 
139 #ifdef HAVE_UNAME
140 #include <sys/utsname.h>
141 #endif
142 
143 #if !defined(HAVE_STRLCPY)
144 size_t strlcpy(char *dst, const char *src, size_t siz);
145 size_t strlcat(char *dst, const char *src, size_t siz);
146 #endif
147 
148 #ifdef HAVE_LIBWRAP
149 #include <tcpd.h>
150 #endif
151 
152 /*
153  * Compile-time configuration
154  */
155 
156 /* Common stuff */
157 #define CRLF		"\r\n"
158 #define EMPTY		""
159 #define PARENT		".."
160 #define ROOT		"/"
161 
162 #define FALSE		0
163 #define TRUE		1
164 
165 #define QUIT		1
166 #define OK		0
167 #define ERROR		-1
168 
169 #define MATCH		0
170 #define WRAP_DENIED	0
171 
172 
173 /* Gopher filetypes */
174 #define TYPE_TEXT	'0'
175 #define TYPE_MENU	'1'
176 #define TYPE_ERROR	'3'
177 #define TYPE_GZIP	'5'
178 #define TYPE_QUERY	'7'
179 #define TYPE_BINARY	'9'
180 #define TYPE_GIF	'g'
181 #define TYPE_HTML	'h'
182 #define TYPE_INFO	'i'
183 #define TYPE_IMAGE	'I'
184 #define TYPE_MIME	'M'
185 #define TYPE_DOC	'd'
186 #define TYPE_TITLE	'!'
187 
188 /* Protocols */
189 #define PROTO_GOPHER	'g'
190 #define PROTO_HTTP	'h'
191 
192 /* Charsets */
193 #define AUTO		0
194 #define US_ASCII	1
195 #define ISO_8859_1	2
196 #define UTF_8		3
197 
198 /* HTTP protocol stuff for logging */
199 #define HTTP_OK		200
200 #define HTTP_404	404
201 #define HTTP_DATE	"%d/%b/%Y:%T %z"
202 #define HTTP_USERAGENT	"Unknown gopher client"
203 
204 /* Defaults for settings */
205 #define DEFAULT_HOST		"localhost"
206 #define DEFAULT_PORT		70
207 #define DEFAULT_TLS_PORT	0
208 #define DEFAULT_TYPE		TYPE_TEXT
209 #define DEFAULT_MAP		"gophermap"
210 #define DEFAULT_TAG		"gophertag"
211 #define DEFAULT_CGI		"/cgi-bin/"
212 #define DEFAULT_USERDIR		"public_gopher"
213 #define DEFAULT_WIDTH		76
214 #define DEFAULT_CHARSET		US_ASCII
215 #define MIN_WIDTH		33
216 #define MAX_WIDTH		200
217 #define UNKNOWN_ADDR		"unknown"
218 
219 /* Session defaults */
220 #define DEFAULT_SESSION_TIMEOUT		1800
221 #define DEFAULT_SESSION_MAX_KBYTES	4194304
222 #define DEFAULT_SESSION_MAX_HITS	4096
223 
224 /* Dummy values for gopher protocol */
225 #define DUMMY_SELECTOR	"null"
226 #define DUMMY_HOST	"null.host\t1"
227 
228 /* Safe $PATH for exec() */
229 #ifdef __HAIKU__
230 #define SAFE_PATH	"/boot/common/bin:/bin"
231 #else
232 #define SAFE_PATH	"/usr/bin:/bin"
233 #endif
234 
235 /* Special requests */
236 #define SERVER_STATUS	"/server-status"
237 #define CAPS_TXT	"/caps.txt"
238 
239 /* Error messages */
240 #define ERR_ACCESS	"Access denied!"
241 #define ERR_NOTFOUND	"File or directory not found!"
242 
243 #define ERROR_HOST	"error.host\t1"
244 #define ERROR_PREFIX	"Error: "
245 
246 /* Strings */
247 #define SERVER_SOFTWARE	"Gophernicus"
248 #define SERVER_SOFTWARE_FULL SERVER_SOFTWARE "/" VERSION " (%s)"
249 
250 #define HEADER_FORMAT	"[%s]"
251 #define FOOTER_FORMAT	"Gophered by Gophernicus/" VERSION " on %s"
252 
253 #define UNITS		"KB", "MB", "GB", "TB", "PB", NULL
254 #define DATE_FORMAT	"%Y-%b-%d %H:%M"	/* See man 3 strftime */
255 #define DATE_WIDTH	17
256 #define DATE_LOCALE 	"POSIX"
257 
258 #define USERDIR_FORMAT	"~%s", pwd->pw_name	/* See man 3 getpwent */
259 #define VHOST_FORMAT	"gopher://%s/"
260 
261 /* ISO-8859-1 to US-ASCII look-alike conversion table */
262 #define ASCII \
263 	"E?,f..++^%S<??Z?" \
264 	"?''\"\"*--~?s>??zY" \
265 	" !c_*Y|$\"C?<?-R-" \
266 	"??23'u?*,1?>????" \
267 	"AAAAAAACEEEEIIII" \
268 	"DNOOOOO*OUUUUYTB" \
269 	"aaaaaaaceeeeiiii" \
270 	"dnooooo/ouuuuyty"
271 
272 #define UNKNOWN '?'
273 
274 /* Sizes & maximums */
275 #define BUFSIZE		1024	/* Default size for string buffers */
276 #define MAX_HIDDEN	32	/* Maximum number of hidden files */
277 #define MAX_FILETYPES	128	/* Maximum number of suffix to filetype mappings */
278 #define MAX_FILTERS	16	/* Maximum number of file filters */
279 #define MAX_SDIRENT	1024	/* Maximum number of files per directory to handle */
280 #define MAX_REWRITE	32	/* Maximum number of selector rewrite options */
281 
282 /* Struct for file suffix -> gopher filetype mapping */
283 typedef struct {
284 	char suffix[15];
285 	char type;
286 } ftype;
287 
288 /* Struct for selector rewriting */
289 typedef struct {
290 	char match[BUFSIZE];
291 	char replace[BUFSIZE];
292 } srewrite;
293 
294 /* Struct for keeping the current options & state */
295 typedef struct {
296 
297 	/* Request */
298 	char req_selector[BUFSIZE];
299 	char req_realpath[BUFSIZE];
300 	char req_query_string[BUFSIZE];
301 	char req_search[BUFSIZE];
302 	char req_referrer[BUFSIZE];
303 	char req_local_addr[64];
304 	char req_remote_addr[64];
305 	char req_filetype;
306 	char req_protocol;
307 	off_t req_filesize;
308 
309 	/* Output */
310 	int out_width;
311 	int out_charset;
312 
313 	/* Settings */
314 	char server_description[64];
315 	char server_location[64];
316 	char server_platform[64];
317 	char server_admin[64];
318 	char server_root[256];
319 	char server_host_default[64];
320 	char server_host[64];
321 	int  server_port;
322 	int  server_tls_port;
323 
324 	char default_filetype;
325 	char map_file[64];
326 	char tag_file[64];
327 	char cgi_file[64];
328 	char user_dir[64];
329 	char log_file[256];
330 
331 	char hidden[MAX_HIDDEN][256];
332 	int hidden_count;
333 
334 	ftype filetype[MAX_FILETYPES];
335 	int filetype_count;
336 	char filter_dir[64];
337 
338 	srewrite rewrite[MAX_REWRITE];
339 	int rewrite_count;
340 
341 	/* Session */
342 	int session_timeout;
343 	int session_max_kbytes;
344 	int session_max_hits;
345 	int session_id;
346 
347 	/* Feature options */
348 	char opt_parent;
349 	char opt_header;
350 	char opt_footer;
351 	char opt_date;
352 	char opt_syslog;
353 	char opt_magic;
354 	char opt_iconv;
355 	char opt_vhost;
356 	char opt_query;
357 	char opt_caps;
358 	char opt_status;
359 	char opt_shm;
360 	char opt_root;
361 	char opt_proxy;
362 	char opt_exec;
363 	char opt_personal_spaces;
364 	char debug;
365 } state;
366 
367 /* Shared memory for session & accounting data */
368 #ifdef HAVE_SHMEM
369 
370 #define SHM_KEY		0xbeeb0008	/* Unique identifier + struct version */
371 #define SHM_MODE	0600		/* Access mode for the shared memory */
372 #define SHM_SESSIONS	256		/* Max amount of user sessions to track */
373 
374 typedef struct {
375 	long hits;
376 	long kbytes;
377 
378 	time_t req_atime;
379 	char req_selector[128];
380 	char req_remote_addr[64];
381 	char req_filetype;
382 	int session_id;
383 
384 	char server_host[64];
385 	int  server_port;
386 } shm_session;
387 
388 typedef struct {
389 	time_t start_time;
390 	long hits;
391 	long kbytes;
392 	char server_platform[64];
393 	char server_description[64];
394 	shm_session session[SHM_SESSIONS];
395 } shm_state;
396 
397 #endif
398 
399 /* Struct for directory sorting */
400 typedef struct {
401 	char	name[128];	/* Should be 256 but we're saving stack space */
402 	mode_t	mode;
403 	uid_t	uid;
404 	gid_t	gid;
405 	off_t	size;
406 	time_t	mtime;
407 } sdirent;
408 
409 
410 /* File suffix to gopher filetype mappings */
411 #define FILETYPES \
412 	"txt","0","pl","0","py","0","sh","0","tcl","0","c","0","cpp","0", "h","0","log","0", \
413 	"conf","0","php","0","php3","0", \
414 	"map","1","menu","1", \
415 	"hqx","4", \
416 	"Z","5","gz","5","tgz","5","tar","5","zip","5","bz2","5","rar","5","sea","5", \
417 	"q","7","qry","7", \
418 	"iso","9","so","9","o","9","rtf","9","ttf","9","bin","9", \
419 	"ics","c","ical","c", \
420 	"gif","g", \
421 	"html","h","htm","h","xhtml","h","css","h","swf","h","rdf","h","rss","h","xml","h", \
422 	"jpg","I","jpeg","I","png","I","bmp","I","svg","I","tif","I","tiff","I", \
423 	"ico","I","xbm","I","xpm","I","pcx","I", \
424 	"mbox","M", \
425 	"pdf","d","ps","d","doc","d","ppt","d","xls","d","xlsx","d","docx","d","pptx","d", \
426 	"mp3","s","wav","s","mid","s","wma","s","flac","s","ogg","s","aiff","s","aac","s", \
427 	"avi",";","mp4",";","mpg",";","mov",";","qt",";","asf",";","mpv",";","m4v",";","webm",";","ogv",";", \
428 	NULL, NULL
429 
430 /*
431  * Useful macros
432  */
433 #define strclear(str) str[0] = '\0';
434 #define sstrlcpy(dest, src) strlcpy(dest, src, sizeof(dest))
435 #define sstrlcat(dest, src) strlcat(dest, src, sizeof(dest))
436 #define sstrncmp(s1, s2) strncmp(s1, s2, sizeof(s2) - 1)
437 #define sstrncasecmp(s1, s2) strncasecmp(s1, s2, sizeof(s2) - 1)
438 #define sstrniconv(charset, out, in) strniconv(charset, out, in, sizeof(out))
439 #define max(a,b) (((a) > (b)) ? (a) : (b))
440 #define min(a,b) (((a) < (b)) ? (a) : (b))
441 
442 /*
443  * Include generated headers
444  */
445 #include "functions.h"
446 #include "files.h"
447 
448 #endif
449 
450 
451