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