1 /*
2  * Copyright (c) 2020 Omar Polo <op@omarpolo.com>
3  *
4  * Permission to use, copy, modify, and distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  */
16 
17 #ifndef GMID_H
18 #define GMID_H
19 
20 #include "config.h"
21 
22 #include <sys/socket.h>
23 #include <sys/types.h>
24 
25 #include <arpa/inet.h>
26 #include <netinet/in.h>
27 
28 #include <dirent.h>
29 #include <event.h>
30 #include <limits.h>
31 #include <netdb.h>
32 #include <signal.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <time.h>
36 #include <tls.h>
37 #include <unistd.h>
38 
39 #include <openssl/x509.h>
40 
41 #define GMID_STRING	"gmid " VERSION
42 #define GMID_VERSION	"gmid/" VERSION
43 
44 #define GEMINI_URL_LEN (1024+3)	/* URL max len + \r\n + \0 */
45 
46 #define SUCCESS		20
47 #define TEMP_REDIRECT	30
48 #define TEMP_FAILURE	40
49 #define CGI_ERROR	42
50 #define NOT_FOUND	51
51 #define PROXY_REFUSED	53
52 #define BAD_REQUEST	59
53 #define CLIENT_CERT_REQ	60
54 #define CERT_NOT_AUTH	61
55 
56 #define MAX_USERS	64
57 
58 /* maximum hostname and label length, +1 for the NUL-terminator */
59 #define DOMAIN_NAME_LEN	(253+1)
60 #define LABEL_LEN	(63+1)
61 
62 #define FCGI_MAX	32
63 #define PROC_MAX	16
64 
65 struct fcgi {
66 	int		 id;
67 	char		*path;
68 	char		*port;
69 	char		*prog;
70 	int		 fd;
71 	struct event	 e;
72 
73 	/* number of pending clients */
74 	int		 pending;
75 
76 #define FCGI_OFF	0
77 #define FCGI_INFLIGHT	1
78 #define FCGI_READY	2
79 	int		 s;
80 };
81 extern struct fcgi fcgi[FCGI_MAX];
82 
83 TAILQ_HEAD(lochead, location);
84 struct location {
85 	const char	*match;
86 	const char	*lang;
87 	const char	*default_mime;
88 	const char	*index;
89 	int		 auto_index; /* 0 auto, -1 off, 1 on */
90 	int		 block_code;
91 	const char	*block_fmt;
92 	int		 strip;
93 	X509_STORE	*reqca;
94 	int		 disable_log;
95 	int		 fcgi;
96 
97 	const char	*dir;
98 	int		 dirfd;
99 
100 	TAILQ_ENTRY(location) locations;
101 };
102 
103 TAILQ_HEAD(envhead, envlist);
104 struct envlist {
105 	char		*name;
106 	char		*value;
107 	TAILQ_ENTRY(envlist) envs;
108 };
109 
110 TAILQ_HEAD(aliashead, alist);
111 struct alist {
112 	char		*alias;
113 	TAILQ_ENTRY(alist) aliases;
114 };
115 
116 extern TAILQ_HEAD(vhosthead, vhost) hosts;
117 struct vhost {
118 	const char	*domain;
119 	const char	*cert;
120 	const char	*key;
121 	const char	*cgi;
122 	const char	*entrypoint;
123 
124 	TAILQ_ENTRY(vhost) vhosts;
125 
126 	/*
127 	 * the first location rule is always '*' and holds the default
128 	 * settings for the vhost, then follows the "real" location
129 	 * rules as specified in the configuration.
130 	 */
131 	struct lochead	 locations;
132 
133 	struct envhead	 env;
134 	struct envhead	 params;
135 	struct aliashead aliases;
136 };
137 
138 struct etm {			/* extension to mime */
139 	const char	*mime;
140 	const char	*ext;
141 };
142 
143 struct mime {
144 	struct etm	*t;
145 	size_t		len;
146 	size_t		cap;
147 };
148 
149 struct conf {
150 	/* from command line */
151 	int		 foreground;
152 	int		 verbose;
153 
154 	/* in the config */
155 	int		 port;
156 	int		 ipv6;
157 	uint32_t	 protos;
158 	struct mime	 mime;
159 	char		*chroot;
160 	char		*user;
161 	int		 prefork;
162 };
163 
164 extern const char *config_path;
165 extern struct conf conf;
166 
167 extern struct imsgbuf logibuf, exibuf, servibuf[PROC_MAX];
168 
169 extern int servpipes[PROC_MAX];
170 
171 struct iri {
172 	char		*schema;
173 	char		*host;
174 	char		*port;
175 	uint16_t	 port_no;
176 	char		*path;
177 	char		*query;
178 	char		*fragment;
179 };
180 
181 struct parser {
182 	char		*iri;
183 	struct iri	*parsed;
184 	const char	*err;
185 };
186 
187 struct mbuf {
188 	size_t			len;
189 	size_t			off;
190 	TAILQ_ENTRY(mbuf)	mbufs;
191 	char			data[];
192 };
193 TAILQ_HEAD(mbufhead, mbuf);
194 
195 typedef void (imsg_handlerfn)(struct imsgbuf*, struct imsg*, size_t);
196 
197 typedef void (*statefn)(int, short, void*);
198 
199 /*
200  * DFA: handle_handshake is the initial state, close_conn the final.
201  * Sometimes we have an enter_* function to handle the state switch.
202  *
203  * handle_handshake -> handle_open_conn
204  * handle_handshake -> close_conn		// on err
205  *
206  * handle_open_conn -> handle_cgi_reply		// via open_file/dir/...
207  * handle_open_conn -> send_fcgi_req		// via apply_fastcgi, IMSG_FCGI_FD
208  * handle_open_conn -> handle_dirlist		// ...same
209  * handle_open_conn -> send_file		// ...same
210  * handle_open_conn -> start_reply		// on error
211  *
212  * handle_cgi_reply -> handle_cgi	// after logging the CGI reply
213  * handle_cgi_reply -> start_reply	// on error
214  *
215  * handle_cgi -> close_conn
216  *
217  * send_fcgi_req -> copy_mbuf		// via handle_fcgi
218  * handle_fcgi -> close_all		// on error
219  * copy_mbuf -> close_conn		// on success/error
220  *
221  * handle_dirlist -> send_directory_listing
222  * handle_dirlist -> close_conn			// on error
223  *
224  * send_directory_listing -> close_conn
225  *
226  * send_file -> close_conn
227  */
228 struct client {
229 	int		 id;
230 	struct tls	*ctx;
231 	char		 req[GEMINI_URL_LEN];
232 	struct iri	 iri;
233 	char		 domain[DOMAIN_NAME_LEN];
234 
235 	/*
236 	 * start_reply uses this to know what function call after the
237 	 * reply.  It's also used as sentinel value in fastcgi to know
238 	 * if the server has closed the request.
239 	 */
240 	statefn		 next;
241 
242 	int		 code;
243 	const char	*meta;
244 	int		 fd, pfd;
245 	struct dirent	**dir;
246 	int		 dirlen, diroff;
247 	int		 fcgi;
248 
249 	/* big enough to store STATUS + SPACE + META + CRLF */
250 	char		 sbuf[1029];
251 	ssize_t		 len, off;
252 
253 	struct mbufhead	 mbufhead;
254 
255 	struct sockaddr_storage	 addr;
256 	struct vhost	*host;	/* host they're talking to */
257 	size_t		 loc;	/* location matched */
258 };
259 
260 extern struct client clients[MAX_USERS];
261 
262 struct cgireq {
263 	char		buf[GEMINI_URL_LEN];
264 
265 	size_t		iri_schema_off;
266 	size_t		iri_host_off;
267 	size_t		iri_port_off;
268 	size_t		iri_path_off;
269 	size_t		iri_query_off;
270 	size_t		iri_fragment_off;
271 	int		iri_portno;
272 
273 	char		spath[PATH_MAX+1];
274 	char		relpath[PATH_MAX+1];
275 	char		addr[NI_MAXHOST+1];
276 
277 	/* AFAIK there isn't an upper limit for these two fields. */
278 	char		subject[64+1];
279 	char		issuer[64+1];
280 
281 	char		hash[128+1];
282 	char		version[8];
283 	char		cipher[32];
284 	int		cipher_strength;
285 	time_t		notbefore;
286 	time_t		notafter;
287 
288 	size_t		host_off;
289 	size_t		loc_off;
290 };
291 
292 enum {
293 	FILE_EXISTS,
294 	FILE_EXECUTABLE,
295 	FILE_DIRECTORY,
296 	FILE_MISSING,
297 };
298 
299 enum imsg_type {
300 	IMSG_CGI_REQ,
301 	IMSG_CGI_RES,
302 	IMSG_FCGI_REQ,
303 	IMSG_FCGI_FD,
304 	IMSG_LOG,
305 	IMSG_LOG_REQUEST,
306 	IMSG_LOG_TYPE,
307 	IMSG_QUIT,
308 };
309 
310 /* gmid.c */
311 char		*data_dir(void);
312 void		 load_local_cert(const char*, const char*);
313 void		 load_vhosts(void);
314 int		 make_socket(int, int);
315 void		 setup_tls(void);
316 void		 init_config(void);
317 void		 free_config(void);
318 void		 drop_priv(void);
319 
320 void		 yyerror(const char*, ...);
321 void		 parse_conf(const char*);
322 int		 cmdline_symset(char *);
323 
324 /* log.c */
325 void		 fatal(const char*, ...)
326 	__attribute__((format (printf, 1, 2)))
327 	__attribute__((__noreturn__));
328 
329 #define LOG_ATTR_FMT __attribute__((format (printf, 2, 3)))
330 void		 log_err(struct client*, const char*, ...)	LOG_ATTR_FMT;
331 void		 log_warn(struct client*, const char*, ...)	LOG_ATTR_FMT;
332 void		 log_notice(struct client*, const char*, ...)	LOG_ATTR_FMT;
333 void		 log_info(struct client*, const char*, ...)	LOG_ATTR_FMT;
334 void		 log_debug(struct client*, const char*, ...)	LOG_ATTR_FMT;
335 void		 log_request(struct client*, char*, size_t);
336 int		 logger_main(int, struct imsgbuf*);
337 
338 /* mime.c */
339 void		 init_mime(struct mime*);
340 void		 add_mime(struct mime*, const char*, const char*);
341 void		 load_default_mime(struct mime*);
342 const char	*mime(struct vhost*, const char*);
343 
344 /* server.c */
345 extern int	shutting_down;
346 const char	*vhost_lang(struct vhost*, const char*);
347 const char	*vhost_default_mime(struct vhost*, const char*);
348 const char	*vhost_index(struct vhost*, const char*);
349 int		 vhost_auto_index(struct vhost*, const char*);
350 int		 vhost_block_return(struct vhost*, const char*, int*, const char**);
351 int		 vhost_fastcgi(struct vhost*, const char*);
352 int		 vhost_dirfd(struct vhost*, const char*, size_t*);
353 int		 vhost_strip(struct vhost*, const char*);
354 X509_STORE	*vhost_require_ca(struct vhost*, const char*);
355 int		 vhost_disable_log(struct vhost*, const char*);
356 
357 void		 mark_nonblock(int);
358 void		 start_reply(struct client*, int, const char*);
359 void		 close_conn(int, short, void*);
360 struct client	*try_client_by_id(int);
361 void		 loop(struct tls*, int, int, struct imsgbuf*);
362 
363 /* dirs.c */
364 int		 scandir_fd(int, struct dirent***, int(*)(const struct dirent*),
365 		    int(*)(const struct dirent**, const struct dirent**));
366 int		 select_non_dot(const struct dirent*);
367 int		 select_non_dotdot(const struct dirent*);
368 
369 /* ex.c */
370 int		 send_string(int, const char*);
371 int		 recv_string(int, char**);
372 int		 send_iri(int, struct iri*);
373 int		 recv_iri(int, struct iri*);
374 void		 free_recvd_iri(struct iri*);
375 int		 send_vhost(int, struct vhost*);
376 int		 recv_vhost(int, struct vhost**);
377 int		 send_time(int, time_t);
378 int		 recv_time(int, time_t*);
379 int		 send_fd(int, int);
380 int		 recv_fd(int);
381 int		 executor_main(struct imsgbuf*);
382 
383 /* fcgi.c */
384 void		 fcgi_close_backend(struct fcgi *);
385 void		 handle_fcgi(int, short, void*);
386 void		 send_fcgi_req(struct fcgi*, struct client*);
387 
388 /* sandbox.c */
389 void		 sandbox_server_process(void);
390 void		 sandbox_executor_process(void);
391 void		 sandbox_logger_process(void);
392 
393 /* utf8.c */
394 int		 valid_multibyte_utf8(struct parser*);
395 char		*utf8_nth(char*, size_t);
396 
397 /* iri.c */
398 int		 parse_iri(char*, struct iri*, const char**);
399 int		 trim_req_iri(char*, const char **);
400 int		 serialize_iri(struct iri*, char*, size_t);
401 char		*pct_decode_str(char *);
402 
403 /* puny.c */
404 int		 puny_decode(const char*, char*, size_t, const char**);
405 
406 /* utils.c */
407 void		 block_signals(void);
408 void		 unblock_signals(void);
409 int		 starts_with(const char*, const char*);
410 int		 ends_with(const char*, const char*);
411 ssize_t		 filesize(int);
412 char		*absolutify_path(const char*);
413 char		*xstrdup(const char*);
414 void		*xcalloc(size_t, size_t);
415 void		 gen_certificate(const char*, const char*, const char*);
416 X509_STORE	*load_ca(const char*);
417 int		 validate_against_ca(X509_STORE*, const uint8_t*, size_t);
418 void		 dispatch_imsg(struct imsgbuf*, imsg_handlerfn**, size_t);
419 
420 #endif
421