1 /*
2  * Copyright (C) 2013-2018 Nikos Mavrogiannopoulos
3  *
4  * This file is part of ocserv.
5  *
6  * ocserv is free software: you can redistribute it and/or modify it
7  * under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * ocserv is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 #include <config.h>
21 
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <unistd.h>
26 #include <sys/types.h>
27 #include <sys/select.h>
28 #include <sys/wait.h>
29 #include <sys/stat.h>
30 #include <fcntl.h>
31 #include <sys/socket.h>
32 #include <netdb.h>
33 #include <system.h>
34 #include <errno.h>
35 #include <sys/ioctl.h>
36 #include <sys/un.h>
37 #include <common.h>
38 #include <syslog.h>
39 #include <main.h>
40 #include <sec-mod.h>
41 #include <tlslib.h>
42 #include <ipc.pb-c.h>
43 #include <sec-mod-sup-config.h>
44 #include <sec-mod-resume.h>
45 #include <cloexec.h>
46 #include <assert.h>
47 
48 #include <gnutls/gnutls.h>
49 #include <gnutls/crypto.h>
50 #include <gnutls/abstract.h>
51 
52 #define MAINTAINANCE_TIME 310
53 
54 static int need_maintainance = 0;
55 static int need_reload = 0;
56 static int need_exit = 0;
57 
58 static void reload_server(sec_mod_st *sec);
59 
60 static int load_keys(sec_mod_st *sec, unsigned force);
61 
62 static
pin_callback(void * user,int attempt,const char * token_url,const char * token_label,unsigned int flags,char * pin,size_t pin_max)63 int pin_callback(void *user, int attempt, const char *token_url,
64 		 const char *token_label, unsigned int flags, char *pin,
65 		 size_t pin_max)
66 {
67 	struct pin_st *ps = user;
68 	int srk = 0;
69 	const char *p;
70 	unsigned len;
71 
72 	if (flags & GNUTLS_PIN_FINAL_TRY) {
73 		syslog(LOG_ERR,
74 		       "PIN callback: final try before locking; not attempting to unlock");
75 		return -1;
76 	}
77 
78 	if (flags & GNUTLS_PIN_WRONG) {
79 		syslog(LOG_ERR,
80 		       "PIN callback: wrong PIN was entered for '%s' (%s)",
81 		       token_label, token_url);
82 		return -1;
83 	}
84 
85 	if (ps->pin[0] == 0) {
86 		syslog(LOG_ERR,
87 		       "PIN required for '%s' but pin-file was not set",
88 		       token_label);
89 		return -1;
90 	}
91 
92 	if (strcmp(token_url, "SRK") == 0 || strcmp(token_label, "SRK") == 0) {
93 		srk = 1;
94 		p = ps->srk_pin;
95 	} else {
96 		p = ps->pin;
97 	}
98 
99 	if (srk != 0 && ps->srk_pin[0] == 0) {
100 		syslog(LOG_ERR,
101 		       "PIN required for '%s' but srk-pin-file was not set",
102 		       token_label);
103 		return -1;
104 	}
105 
106 	len = strlen(p);
107 	if (len > pin_max - 1) {
108 		syslog(LOG_ERR, "Too long PIN (%u chars)", len);
109 		return -1;
110 	}
111 
112 	memcpy(pin, p, len);
113 	pin[len] = 0;
114 
115 	return 0;
116 }
117 
118 static
load_pins(struct perm_cfg_st * config,struct pin_st * s)119 int load_pins(struct perm_cfg_st *config, struct pin_st *s)
120 {
121 	int fd, ret;
122 
123 	s->srk_pin[0] = 0;
124 	s->pin[0] = 0;
125 
126 	if (config->srk_pin_file != NULL) {
127 		fd = open(config->srk_pin_file, O_RDONLY);
128 		if (fd < 0) {
129 			syslog(LOG_ERR, "could not open SRK PIN file '%s'",
130 			       config->srk_pin_file);
131 			return -1;
132 		}
133 
134 		ret = read(fd, s->srk_pin, sizeof(s->srk_pin) - 1);
135 		close(fd);
136 		if (ret <= 1) {
137 			syslog(LOG_ERR, "could not read from PIN file '%s'",
138 			       config->srk_pin_file);
139 			return -1;
140 		}
141 
142 		if (s->srk_pin[ret - 1] == '\n' || s->srk_pin[ret - 1] == '\r')
143 			s->srk_pin[ret - 1] = 0;
144 		s->srk_pin[ret] = 0;
145 	}
146 
147 	if (config->pin_file != NULL) {
148 		fd = open(config->pin_file, O_RDONLY);
149 		if (fd < 0) {
150 			syslog(LOG_ERR, "could not open PIN file '%s'",
151 			       config->pin_file);
152 			return -1;
153 		}
154 
155 		ret = read(fd, s->pin, sizeof(s->pin) - 1);
156 		close(fd);
157 		if (ret <= 1) {
158 			syslog(LOG_ERR, "could not read from PIN file '%s'",
159 			       config->pin_file);
160 			return -1;
161 		}
162 
163 		if (s->pin[ret - 1] == '\n' || s->pin[ret - 1] == '\r')
164 			s->pin[ret - 1] = 0;
165 		s->pin[ret] = 0;
166 	}
167 
168 	if (config->key_pin != NULL) {
169 		strlcpy(s->pin, config->key_pin, sizeof(s->pin));
170 	}
171 
172 	if (config->srk_pin != NULL) {
173 		strlcpy(s->srk_pin, config->srk_pin, sizeof(s->srk_pin));
174 	}
175 
176 	return 0;
177 }
178 
handle_op(void * pool,int cfd,sec_mod_st * sec,uint8_t type,uint8_t * rep,size_t rep_size)179 static int handle_op(void *pool, int cfd, sec_mod_st * sec, uint8_t type, uint8_t * rep,
180 		     size_t rep_size)
181 {
182 	SecOpMsg msg = SEC_OP_MSG__INIT;
183 	int ret;
184 
185 	msg.data.data = rep;
186 	msg.data.len = rep_size;
187 
188 	ret = send_msg(pool, cfd, type, &msg,
189 		       (pack_size_func) sec_op_msg__get_packed_size,
190 		       (pack_func) sec_op_msg__pack);
191 	if (ret < 0) {
192 		seclog(sec, LOG_WARNING, "sec-mod error in sending reply");
193 	}
194 
195 	return 0;
196 }
197 
198 static
process_worker_packet(void * pool,int cfd,pid_t pid,sec_mod_st * sec,cmd_request_t cmd,uint8_t * buffer,size_t buffer_size)199 int process_worker_packet(void *pool, int cfd, pid_t pid, sec_mod_st *sec, cmd_request_t cmd,
200 		   uint8_t * buffer, size_t buffer_size)
201 {
202 	unsigned i;
203 	gnutls_datum_t data, out;
204 	int ret;
205 	SecOpMsg *op;
206 	vhost_cfg_st *vhost;
207 #if GNUTLS_VERSION_NUMBER >= 0x030600
208 	unsigned bits;
209 	SecGetPkMsg *pkm;
210 #endif
211 	PROTOBUF_ALLOCATOR(pa, pool);
212 
213 	seclog(sec, LOG_DEBUG, "cmd [size=%d] %s\n", (int)buffer_size,
214 	       cmd_request_to_str(cmd));
215 	data.data = buffer;
216 	data.size = buffer_size;
217 
218 	switch (cmd) {
219 #if GNUTLS_VERSION_NUMBER >= 0x030600
220 	case CMD_SEC_GET_PK:
221 		pkm = sec_get_pk_msg__unpack(&pa, data.size, data.data);
222 		if (pkm == NULL) {
223 			seclog(sec, LOG_INFO, "error unpacking sec get pk\n");
224 			return -1;
225 		}
226 
227 		vhost = find_vhost(sec->vconfig, pkm->vhost);
228 		/* check for static analyzer - find_vhost is always non-NULL */
229 		assert(vhost != NULL);
230 
231 		i = pkm->key_idx;
232 		if (i >= vhost->key_size) {
233 			seclog(sec, LOG_INFO,
234 			       "%sreceived out-of-bounds key index (%d); have %d keys", PREFIX_VHOST(vhost), i, vhost->key_size);
235 			return -1;
236 		}
237 
238 		pkm->pk = gnutls_privkey_get_pk_algorithm(vhost->key[i], &bits);
239 		pkm->bits = bits;
240 
241 		ret = send_msg(pool, cfd, CMD_SEC_GET_PK, pkm,
242 			       (pack_size_func) sec_get_pk_msg__get_packed_size,
243 			       (pack_func) sec_get_pk_msg__pack);
244 
245 		sec_get_pk_msg__free_unpacked(pkm, &pa);
246 
247 		if (ret < 0) {
248 			seclog(sec, LOG_INFO, "error sending reply: %s",
249 			       gnutls_strerror(ret));
250 			return -1;
251 		}
252 
253 		return ret;
254 
255 	case CMD_SEC_SIGN_DATA:
256 	case CMD_SEC_SIGN_HASH:
257 		op = sec_op_msg__unpack(&pa, data.size, data.data);
258 		if (op == NULL) {
259 			seclog(sec, LOG_INFO, "error unpacking sec op\n");
260 			return -1;
261 		}
262 
263 		vhost = find_vhost(sec->vconfig, op->vhost);
264 		assert(vhost != NULL);
265 
266 		i = op->key_idx;
267 		if (op->has_key_idx == 0 || i >= vhost->key_size) {
268 			seclog(sec, LOG_INFO,
269 			       "%sreceived out-of-bounds key index (%d); have %d keys", PREFIX_VHOST(vhost), i, vhost->key_size);
270 			return -1;
271 		}
272 
273 		data.data = op->data.data;
274 		data.size = op->data.len;
275 
276 		if (cmd == CMD_SEC_SIGN_DATA) {
277 			ret = gnutls_privkey_sign_data2(vhost->key[i], op->sig, 0, &data, &out);
278 		} else {
279 			ret = gnutls_privkey_sign_hash2(vhost->key[i], op->sig, 0, &data, &out);
280 		}
281 		sec_op_msg__free_unpacked(op, &pa);
282 
283 		if (ret < 0) {
284 			seclog(sec, LOG_INFO, "error in crypto operation: %s",
285 			       gnutls_strerror(ret));
286 			return -1;
287 		}
288 
289 		ret = handle_op(pool, cfd, sec, cmd, out.data, out.size);
290 		gnutls_free(out.data);
291 
292 		return ret;
293 #endif
294 	case CMD_SEC_SIGN:
295 	case CMD_SEC_DECRYPT:
296 		op = sec_op_msg__unpack(&pa, data.size, data.data);
297 		if (op == NULL) {
298 			seclog(sec, LOG_INFO, "error unpacking sec op\n");
299 			return -1;
300 		}
301 
302 		vhost = find_vhost(sec->vconfig, op->vhost);
303 		assert(vhost != NULL);
304 
305 		i = op->key_idx;
306 		if (op->has_key_idx == 0 || i >= vhost->key_size) {
307 			seclog(sec, LOG_INFO,
308 			       "%sreceived out-of-bounds key index (%d); have %d keys", PREFIX_VHOST(vhost), i, vhost->key_size);
309 			return -1;
310 		}
311 
312 		data.data = op->data.data;
313 		data.size = op->data.len;
314 
315 		if (cmd == CMD_SEC_DECRYPT) {
316 			ret =
317 			    gnutls_privkey_decrypt_data(vhost->key[i], 0, &data,
318 							&out);
319 		} else {
320 			ret =
321 			    gnutls_privkey_sign_hash(vhost->key[i], 0,
322 						     GNUTLS_PRIVKEY_SIGN_FLAG_TLS1_RSA,
323 						     &data, &out);
324 		}
325 		sec_op_msg__free_unpacked(op, &pa);
326 
327 		if (ret < 0) {
328 			seclog(sec, LOG_INFO, "error in crypto operation: %s",
329 			       gnutls_strerror(ret));
330 			return -1;
331 		}
332 
333 		ret = handle_op(pool, cfd, sec, cmd, out.data, out.size);
334 		gnutls_free(out.data);
335 
336 		return ret;
337 
338 	case CMD_SEC_CLI_STATS:{
339 			CliStatsMsg *tmsg;
340 
341 			tmsg = cli_stats_msg__unpack(&pa, data.size, data.data);
342 			if (tmsg == NULL) {
343 				seclog(sec, LOG_ERR, "error unpacking data");
344 				return -1;
345 			}
346 
347 			ret = handle_sec_auth_stats_cmd(sec, tmsg, pid);
348 			cli_stats_msg__free_unpacked(tmsg, &pa);
349 			return ret;
350 		}
351 		break;
352 
353 	case CMD_SEC_AUTH_INIT:{
354 			SecAuthInitMsg *auth_init;
355 
356 			auth_init =
357 			    sec_auth_init_msg__unpack(&pa, data.size,
358 						      data.data);
359 			if (auth_init == NULL) {
360 				seclog(sec, LOG_INFO, "error unpacking auth init\n");
361 				return -1;
362 			}
363 
364 			ret = handle_sec_auth_init(cfd, sec, auth_init, pid);
365 			sec_auth_init_msg__free_unpacked(auth_init, &pa);
366 			return ret;
367 		}
368 	case CMD_SEC_AUTH_CONT:{
369 			SecAuthContMsg *auth_cont;
370 
371 			auth_cont =
372 			    sec_auth_cont_msg__unpack(&pa, data.size,
373 						      data.data);
374 			if (auth_cont == NULL) {
375 				seclog(sec, LOG_INFO, "error unpacking auth cont\n");
376 				return -1;
377 			}
378 
379 			ret = handle_sec_auth_cont(cfd, sec, auth_cont);
380 			sec_auth_cont_msg__free_unpacked(auth_cont, &pa);
381 			return ret;
382 		}
383 	case RESUME_STORE_REQ:{
384 			SessionResumeStoreReqMsg *smsg;
385 
386 			smsg =
387 			    session_resume_store_req_msg__unpack(&pa, buffer_size,
388 								 buffer);
389 			if (smsg == NULL) {
390 				seclog(sec, LOG_ERR, "error unpacking data");
391 				return ERR_BAD_COMMAND;
392 			}
393 
394 			ret = handle_resume_store_req(sec, smsg);
395 
396 			/* zeroize the data */
397 			safe_memset(buffer, 0, buffer_size);
398 			safe_memset(smsg->session_data.data, 0, smsg->session_data.len);
399 
400 			session_resume_store_req_msg__free_unpacked(smsg, &pa);
401 
402 			if (ret < 0) {
403 				seclog(sec, LOG_DEBUG,
404 				      "could not store resumption data");
405 			}
406 		}
407 
408 		break;
409 
410 	case RESUME_DELETE_REQ:{
411 			SessionResumeFetchMsg *fmsg;
412 
413 			fmsg =
414 			    session_resume_fetch_msg__unpack(&pa, buffer_size,
415 							     buffer);
416 			if (fmsg == NULL) {
417 				seclog(sec, LOG_ERR, "error unpacking data");
418 				return ERR_BAD_COMMAND;
419 			}
420 
421 			ret = handle_resume_delete_req(sec, fmsg);
422 
423 			session_resume_fetch_msg__free_unpacked(fmsg, &pa);
424 
425 			if (ret < 0) {
426 				seclog(sec, LOG_DEBUG,
427 				      "could not delete resumption data.");
428 			}
429 		}
430 
431 		break;
432 	case RESUME_FETCH_REQ:{
433 			SessionResumeReplyMsg msg =
434 			    SESSION_RESUME_REPLY_MSG__INIT;
435 			SessionResumeFetchMsg *fmsg;
436 
437 			fmsg =
438 			    session_resume_fetch_msg__unpack(&pa, buffer_size,
439 							     buffer);
440 			if (fmsg == NULL) {
441 				seclog(sec, LOG_ERR, "error unpacking data");
442 				return ERR_BAD_COMMAND;
443 			}
444 
445 			ret = handle_resume_fetch_req(sec, fmsg, &msg);
446 
447 			session_resume_fetch_msg__free_unpacked(fmsg, &pa);
448 
449 			if (ret < 0) {
450 				msg.reply =
451 				    SESSION_RESUME_REPLY_MSG__RESUME__REP__FAILED;
452 				seclog(sec, LOG_DEBUG,
453 				      "could not fetch resumption data.");
454 			} else {
455 				msg.reply =
456 				    SESSION_RESUME_REPLY_MSG__RESUME__REP__OK;
457 			}
458 
459 			ret =
460 			    send_msg(pool, cfd, RESUME_FETCH_REP, &msg,
461 					       (pack_size_func)
462 					       session_resume_reply_msg__get_packed_size,
463 					       (pack_func)
464 					       session_resume_reply_msg__pack);
465 
466 			if (ret < 0) {
467 				seclog(sec, LOG_ERR,
468 				      "could not send reply cmd %d.",
469 				      (unsigned)cmd);
470 				return ERR_BAD_COMMAND;
471 			}
472 
473 		}
474 
475 		break;
476 
477 	default:
478 		seclog(sec, LOG_WARNING, "unknown type 0x%.2x", cmd);
479 		return -1;
480 	}
481 
482 	return 0;
483 }
484 
485 static
process_packet_from_main(void * pool,int fd,sec_mod_st * sec,cmd_request_t cmd,uint8_t * buffer,size_t buffer_size)486 int process_packet_from_main(void *pool, int fd, sec_mod_st * sec, cmd_request_t cmd,
487 		   uint8_t * buffer, size_t buffer_size)
488 {
489 	gnutls_datum_t data;
490 	int ret;
491 	PROTOBUF_ALLOCATOR(pa, pool);
492 
493 	seclog(sec, LOG_DEBUG, "cmd [size=%d] %s\n", (int)buffer_size,
494 	       cmd_request_to_str(cmd));
495 	data.data = buffer;
496 	data.size = buffer_size;
497 
498 	switch (cmd) {
499 	case CMD_SECM_RELOAD:
500 		reload_server(sec);
501 
502 		ret = send_msg(pool, fd, CMD_SECM_RELOAD_REPLY, NULL,
503 			       NULL, NULL);
504 		if (ret < 0) {
505 			seclog(sec, LOG_ERR, "could not send reload reply to main!\n");
506 			return ERR_BAD_COMMAND;
507 		}
508 		break;
509 	case CMD_SECM_LIST_COOKIES:
510 		handle_secm_list_cookies_reply(pool, fd, sec);
511 
512 		return 0;
513 	case CMD_SECM_BAN_IP_REPLY:{
514 		BanIpReplyMsg *msg = NULL;
515 
516 		msg =
517 		    ban_ip_reply_msg__unpack(&pa, data.size,
518 					     data.data);
519 		if (msg == NULL) {
520 			seclog(sec, LOG_INFO, "error unpacking auth ban ip reply\n");
521 			return ERR_BAD_COMMAND;
522 		}
523 
524 		handle_sec_auth_ban_ip_reply(sec, msg);
525 		ban_ip_reply_msg__free_unpacked(msg, &pa);
526 
527 		return 0;
528 	}
529 	case CMD_SECM_SESSION_OPEN:{
530 			SecmSessionOpenMsg *msg;
531 
532 			msg =
533 			    secm_session_open_msg__unpack(&pa, data.size,
534 						      data.data);
535 			if (msg == NULL) {
536 				seclog(sec, LOG_INFO, "error unpacking session open\n");
537 				return ERR_BAD_COMMAND;
538 			}
539 
540 			ret = handle_secm_session_open_cmd(sec, fd, msg);
541 			secm_session_open_msg__free_unpacked(msg, &pa);
542 
543 			return ret;
544 		}
545 	case CMD_SECM_SESSION_CLOSE:{
546 			SecmSessionCloseMsg *msg;
547 
548 			msg =
549 			    secm_session_close_msg__unpack(&pa, data.size,
550 						      data.data);
551 			if (msg == NULL) {
552 				seclog(sec, LOG_INFO, "error unpacking session close\n");
553 				return ERR_BAD_COMMAND;
554 			}
555 
556 			ret = handle_secm_session_close_cmd(sec, fd, msg);
557 			secm_session_close_msg__free_unpacked(msg, &pa);
558 
559 			return ret;
560 		}
561 	default:
562 		seclog(sec, LOG_WARNING, "unknown type 0x%.2x", cmd);
563 		return ERR_BAD_COMMAND;
564 	}
565 
566 	return 0;
567 }
568 
handle_alarm(int signo)569 static void handle_alarm(int signo)
570 {
571 	need_maintainance = 1;
572 }
573 
handle_sigterm(int signo)574 static void handle_sigterm(int signo)
575 {
576 	need_exit = 1;
577 }
578 
send_stats_to_main(sec_mod_st * sec)579 static void send_stats_to_main(sec_mod_st *sec)
580 {
581 	int ret;
582 	time_t now = time(0);
583 	SecmStatsMsg msg = SECM_STATS_MSG__INIT;
584 
585 	if (GETPCONFIG(sec)->stats_reset_time != 0 &&
586 	    now - sec->last_stats_reset > GETPCONFIG(sec)->stats_reset_time) {
587 		sec->auth_failures = 0;
588 		sec->avg_auth_time = 0;
589 		sec->max_auth_time = 0;
590 		sec->last_stats_reset = now;
591 	}
592 
593 	msg.secmod_client_entries = sec_mod_client_db_elems(sec);
594 	msg.secmod_tlsdb_entries = sec->tls_db.entries;
595 	msg.secmod_auth_failures = sec->auth_failures;
596 	msg.secmod_avg_auth_time = sec->avg_auth_time;
597 	msg.secmod_max_auth_time = sec->max_auth_time;
598 	/* we only report the number of failures since last call */
599 	sec->auth_failures = 0;
600 
601 	/* the following two are not resettable */
602 	msg.secmod_client_entries = sec_mod_client_db_elems(sec);
603 	msg.secmod_tlsdb_entries = sec->tls_db.entries;
604 
605 	ret = send_msg(sec, sec->cmd_fd, CMD_SECM_STATS, &msg,
606 			(pack_size_func) secm_stats_msg__get_packed_size,
607 			(pack_func) secm_stats_msg__pack);
608 	if (ret < 0) {
609 		seclog(sec, LOG_ERR, "error in sending statistics to main");
610 		return;
611 	}
612 
613 	return;
614 }
615 
reload_server(sec_mod_st * sec)616 static void reload_server(sec_mod_st *sec)
617 {
618 	vhost_cfg_st *vhost = NULL;
619 
620 	seclog(sec, LOG_DEBUG, "reloading configuration");
621 	reload_cfg_file(sec, sec->vconfig, 1);
622 	load_keys(sec, 0);
623 
624 	list_for_each(sec->vconfig, vhost, list) {
625 		sec_auth_init(vhost);
626 	}
627 	sup_config_init(sec);
628 
629 	need_reload = 0;
630 }
631 
check_other_work(sec_mod_st * sec)632 static void check_other_work(sec_mod_st *sec)
633 {
634 	vhost_cfg_st *vhost = NULL;
635 
636 	if (need_exit) {
637 		unsigned i;
638 
639 		list_for_each(sec->vconfig, vhost, list) {
640 			for (i = 0; i < vhost->key_size; i++) {
641 				gnutls_privkey_deinit(vhost->key[i]);
642 				vhost->key[i] = NULL;
643 			}
644 			vhost->key_size = 0;
645 		}
646 
647 		sec_mod_client_db_deinit(sec);
648 		tls_cache_deinit(&sec->tls_db);
649 		talloc_free(sec->config_pool);
650 		talloc_free(sec->sec_mod_pool);
651 		exit(0);
652 	}
653 
654 	if (need_reload) {
655 		reload_server(sec);
656 	}
657 
658 	if (need_maintainance) {
659 		seclog(sec, LOG_DEBUG, "performing maintenance");
660 		cleanup_client_entries(sec);
661 		expire_tls_sessions(sec);
662 		send_stats_to_main(sec);
663 		seclog(sec, LOG_DEBUG, "active sessions %d",
664 			sec_mod_client_db_elems(sec));
665 		alarm(MAINTAINANCE_TIME);
666 		need_maintainance = 0;
667 	}
668 }
669 
670 static
serve_request_main(sec_mod_st * sec,int fd,uint8_t * buffer,unsigned buffer_size)671 int serve_request_main(sec_mod_st *sec, int fd, uint8_t *buffer, unsigned buffer_size)
672 {
673 	int ret, e;
674 	uint8_t cmd;
675 	size_t length;
676 	void *pool = buffer;
677 
678 	/* read request */
679 	ret = recv_msg_headers(fd, &cmd, MAIN_SEC_MOD_TIMEOUT);
680 	if (ret < 0) {
681 		seclog(sec, LOG_ERR, "error receiving msg head from main");
682 		ret = ERR_BAD_COMMAND;
683 		goto leave;
684 	}
685 
686 	length = ret;
687 
688 	seclog(sec, LOG_DEBUG, "received request %s", cmd_request_to_str(cmd));
689 	if (cmd <= MIN_SECM_CMD || cmd >= MAX_SECM_CMD) {
690 		seclog(sec, LOG_ERR, "received invalid message from main of %u bytes (cmd: %u)\n",
691 		      (unsigned)length, (unsigned)cmd);
692 		return ERR_BAD_COMMAND;
693 	}
694 
695 	if (length > buffer_size) {
696 		seclog(sec, LOG_ERR, "received too big message (%d)", (int)length);
697 		ret = ERR_BAD_COMMAND;
698 		goto leave;
699 	}
700 
701 	/* read the body */
702 	ret = force_read_timeout(fd, buffer, length, MAIN_SEC_MOD_TIMEOUT);
703 	if (ret < 0) {
704 		e = errno;
705 		seclog(sec, LOG_ERR, "error receiving msg body of cmd %u with length %u: %s",
706 		       cmd, (unsigned)length, strerror(e));
707 		ret = ERR_BAD_COMMAND;
708 		goto leave;
709 	}
710 
711 	ret = process_packet_from_main(pool, fd, sec, cmd, buffer, ret);
712 	if (ret < 0) {
713 		seclog(sec, LOG_ERR, "error processing data for '%s' command (%d)", cmd_request_to_str(cmd), ret);
714 	}
715 
716  leave:
717 	return ret;
718 }
719 
720 static
serve_request_worker(sec_mod_st * sec,int cfd,pid_t pid,uint8_t * buffer,unsigned buffer_size)721 int serve_request_worker(sec_mod_st *sec, int cfd, pid_t pid, uint8_t *buffer, unsigned buffer_size)
722 {
723 	int ret, e;
724 	uint8_t cmd;
725 	size_t length;
726 	void *pool = buffer;
727 
728 	/* read request */
729 	ret = recv_msg_headers(cfd, &cmd, MAX_WAIT_SECS);
730 	if (ret < 0) {
731 		seclog(sec, LOG_DEBUG, "error receiving msg head from worker");
732 		goto leave;
733 	}
734 
735 	length = ret;
736 
737 	if (length > buffer_size) {
738 		seclog(sec, LOG_INFO, "too big message (%d)", (int)length);
739 		ret = -1;
740 		goto leave;
741 	}
742 
743 	/* read the body */
744 	ret = force_read_timeout(cfd, buffer, length, MAX_WAIT_SECS);
745 	if (ret < 0) {
746 		e = errno;
747 		seclog(sec, LOG_INFO, "error receiving msg body: %s",
748 		       strerror(e));
749 		ret = -1;
750 		goto leave;
751 	}
752 
753 	ret = process_worker_packet(pool, cfd, pid, sec, cmd, buffer, ret);
754 	if (ret < 0) {
755 		seclog(sec, LOG_DEBUG, "error processing '%s' command (%d)", cmd_request_to_str(cmd), ret);
756 	}
757 
758  leave:
759 	return ret;
760 }
761 
762 #define CHECK_LOOP_ERR(x) \
763 	if (force != 0) { GNUTLS_FATAL_ERR(x); } \
764 	else { if (ret < 0) { \
765 		seclog(sec, LOG_ERR, "could not reload key %s", vhost->perm_config.key[i]); \
766 		continue; } \
767 	}
768 
load_keys(sec_mod_st * sec,unsigned force)769 static int load_keys(sec_mod_st *sec, unsigned force)
770 {
771 	unsigned i, reload_file;
772 	int ret;
773 	vhost_cfg_st *vhost = NULL;
774 
775 	list_for_each_rev(sec->vconfig, vhost, list) {
776 		if (force == 0) {
777 			reload_file = 0;
778 
779 			for (i = 0; i < vhost->perm_config.key_size; i++) {
780 				if (need_file_reload(vhost->perm_config.key[i], vhost->cert_last_access) != 0) {
781 					reload_file = 1;
782 					break;
783 				}
784 			}
785 
786 			if (reload_file == 0)
787 				continue;
788 		}
789 
790 		vhost->cert_last_access = time(0);
791 
792 		ret = load_pins(GETPCONFIG(sec), &vhost->pins);
793 		if (ret < 0) {
794 			seclog(sec, LOG_ERR, "error loading PIN files");
795 			exit(1);
796 		}
797 
798 		/* Reminder: the number of private keys or their filenames cannot be changed on reload
799 		 */
800 		if (vhost->key == NULL) {
801 			vhost->key_size = vhost->perm_config.key_size;
802 			vhost->key = talloc_zero_size(sec, sizeof(*vhost->key) * vhost->perm_config.key_size);
803 			if (vhost->key == NULL) {
804 				seclog(sec, LOG_ERR, "error in memory allocation");
805 				exit(1);
806 			}
807 		}
808 
809 		/* read private keys */
810 		for (i = 0; i < vhost->key_size; i++) {
811 			gnutls_privkey_t p;
812 
813 			ret = gnutls_privkey_init(&p);
814 			CHECK_LOOP_ERR(ret);
815 
816 			/* load the private key */
817 			if (gnutls_url_is_supported(vhost->perm_config.key[i]) != 0) {
818 				gnutls_privkey_set_pin_function(p,
819 								pin_callback, &vhost->pins);
820 				ret =
821 				    gnutls_privkey_import_url(p,
822 							      vhost->perm_config.key[i], 0);
823 				CHECK_LOOP_ERR(ret);
824 			} else {
825 				gnutls_datum_t data;
826 				ret = gnutls_load_file(vhost->perm_config.key[i], &data);
827 				if (ret < 0) {
828 					seclog(sec, LOG_ERR, "error loading file '%s'",
829 					       vhost->perm_config.key[i]);
830 					CHECK_LOOP_ERR(ret);
831 				}
832 
833 				ret =
834 				    gnutls_privkey_import_x509_raw(p, &data,
835 								   GNUTLS_X509_FMT_PEM,
836 								   NULL, 0);
837 				if (ret == GNUTLS_E_DECRYPTION_FAILED && vhost->pins.pin[0]) {
838 					ret =
839 					    gnutls_privkey_import_x509_raw(p, &data,
840 									   GNUTLS_X509_FMT_PEM,
841 									   vhost->pins.pin, 0);
842 				}
843 				CHECK_LOOP_ERR(ret);
844 
845 				gnutls_free(data.data);
846 			}
847 
848 			if (vhost->key[i] != NULL) {
849 				gnutls_privkey_deinit(vhost->key[i]);
850 			}
851 			vhost->key[i] = p;
852 		}
853 		seclog(sec, LOG_DEBUG, "%sloaded %d keys\n", PREFIX_VHOST(vhost), vhost->key_size);
854 	}
855 	return 0;
856 }
857 
858 /* sec_mod_server:
859  * @config: server configuration
860  * @socket_file: the name of the socket
861  * @cmd_fd: socket to exchange commands with main
862  * @cmd_fd_sync: socket to received sync commands from main
863  *
864  * This is the main part of the security module.
865  * It creates the unix domain socket identified by @socket_file
866  * and then accepts connections from the workers to it. Then
867  * it serves commands requested on the server's private key.
868  *
869  * When the operation is decrypt the provided data are
870  * decrypted and sent back to worker. The sign operation
871  * signs the provided data.
872  *
873  * The security module's reply to the worker has the
874  * following format:
875  * byte[0-5]: length (uint32_t)
876  * byte[5-total]: data (signature or decrypted data)
877  *
878  * The reason for having this as a separate process
879  * is to avoid any bug on the workers to leak the key.
880  * It is not part of main because workers are spawned
881  * from main, and thus should be prevented from accessing
882  * parts the key in stack or heap that was not zeroized.
883  * Other than that it allows the main server to spawn
884  * clients fast without becoming a bottleneck due to private
885  * key operations.
886  */
sec_mod_server(void * main_pool,void * config_pool,struct list_head * vconfig,const char * socket_file,int cmd_fd,int cmd_fd_sync,size_t hmac_key_length,const uint8_t * hmac_key,const uint8_t instance_id)887 void sec_mod_server(void *main_pool, void *config_pool, struct list_head *vconfig,
888 		    const char *socket_file, int cmd_fd, int cmd_fd_sync,
889 		    size_t  hmac_key_length, const uint8_t * hmac_key,
890 			const uint8_t instance_id)
891 {
892 	struct sockaddr_un sa;
893 	socklen_t sa_len;
894 	int cfd, ret, e, n;
895 	unsigned buffer_size;
896 	uid_t uid;
897 	uint8_t *buffer;
898 	int sd;
899 	sec_mod_st *sec;
900 	void *sec_mod_pool;
901 	vhost_cfg_st *vhost = NULL;
902 	fd_set rd_set;
903 	pid_t pid;
904 #ifdef HAVE_PSELECT
905 	struct timespec ts;
906 #else
907 	struct timeval ts;
908 #endif
909 	sigset_t emptyset, blockset;
910 
911 #ifdef DEBUG_LEAKS
912 	talloc_enable_leak_report_full();
913 #endif
914 	sigemptyset(&blockset);
915 	sigemptyset(&emptyset);
916 	sigaddset(&blockset, SIGALRM);
917 	sigaddset(&blockset, SIGTERM);
918 	sigaddset(&blockset, SIGINT);
919 	sigaddset(&blockset, SIGHUP);
920 
921 	sec_mod_pool = talloc_init("sec-mod");
922 	if (sec_mod_pool == NULL) {
923 		seclog(sec, LOG_ERR, "error in memory allocation");
924 		exit(1);
925 	}
926 
927 	sec = talloc_zero(sec_mod_pool, sec_mod_st);
928 	if (sec == NULL) {
929 		seclog(sec, LOG_ERR, "error in memory allocation");
930 		exit(1);
931 	}
932 
933 	sec->vconfig = vconfig;
934 	sec->config_pool = config_pool;
935 	sec->sec_mod_pool = sec_mod_pool;
936 	memcpy((uint8_t*)sec->hmac_key, hmac_key, hmac_key_length);
937 	sec->sec_mod_instance_id = instance_id;
938 
939 	tls_cache_init(sec, &sec->tls_db);
940 	sup_config_init(sec);
941 
942 	memset(&sa, 0, sizeof(sa));
943 	sa.sun_family = AF_UNIX;
944 	strlcpy(sa.sun_path, socket_file, sizeof(sa.sun_path));
945 	(void)remove(socket_file);
946 
947 #define SOCKET_FILE sa.sun_path
948 
949 	/* we no longer need the main pool after this point. */
950 	talloc_free(main_pool);
951 
952 	ocsignal(SIGHUP, SIG_IGN);
953 	ocsignal(SIGINT, handle_sigterm);
954 	ocsignal(SIGTERM, handle_sigterm);
955 	ocsignal(SIGALRM, handle_alarm);
956 
957 	list_for_each(sec->vconfig, vhost, list) {
958 		sec_auth_init(vhost);
959 	}
960 
961 	sec->cmd_fd = cmd_fd;
962 	sec->cmd_fd_sync = cmd_fd_sync;
963 
964 	if (sec_mod_client_db_init(sec) == NULL) {
965 		seclog(sec, LOG_ERR, "error in client db initialization");
966 		exit(1);
967 	}
968 
969 	sd = socket(AF_UNIX, SOCK_STREAM, 0);
970 	if (sd == -1) {
971 		e = errno;
972 		seclog(sec, LOG_ERR, "could not create socket '%s': %s", SOCKET_FILE,
973 		       strerror(e));
974 		exit(1);
975 	}
976 	set_cloexec_flag(sd, 1);
977 
978 	umask(066);
979 	ret = bind(sd, (struct sockaddr *)&sa, SUN_LEN(&sa));
980 	if (ret == -1) {
981 		e = errno;
982 		seclog(sec, LOG_ERR, "could not bind socket '%s': %s", SOCKET_FILE,
983 		       strerror(e));
984 		exit(1);
985 	}
986 
987 	ret = chown(SOCKET_FILE, GETPCONFIG(sec)->uid, GETPCONFIG(sec)->gid);
988 	if (ret == -1) {
989 		e = errno;
990 		seclog(sec, LOG_INFO, "could not chown socket '%s': %s", SOCKET_FILE,
991 		       strerror(e));
992 	}
993 
994 	ret = listen(sd, 1024);
995 	if (ret == -1) {
996 		e = errno;
997 		seclog(sec, LOG_ERR, "could not listen to socket '%s': %s",
998 		       SOCKET_FILE, strerror(e));
999 		exit(1);
1000 	}
1001 
1002 	ret = load_keys(sec, 1);
1003 	if (ret < 0) {
1004 		seclog(sec, LOG_ERR, "error loading private key files");
1005 		exit(1);
1006 	}
1007 
1008 	sigprocmask(SIG_BLOCK, &blockset, &sig_default_set);
1009 	alarm(MAINTAINANCE_TIME);
1010 	seclog(sec, LOG_INFO, "sec-mod initialized (socket: %s)", SOCKET_FILE);
1011 
1012 
1013 	for (;;) {
1014 		check_other_work(sec);
1015 
1016 		FD_ZERO(&rd_set);
1017 		n = 0;
1018 
1019 		FD_SET(cmd_fd, &rd_set);
1020 		n = MAX(n, cmd_fd);
1021 
1022 		FD_SET(cmd_fd_sync, &rd_set);
1023 		n = MAX(n, cmd_fd_sync);
1024 
1025 		FD_SET(sd, &rd_set);
1026 		n = MAX(n, sd);
1027 
1028 #ifdef HAVE_PSELECT
1029 		ts.tv_nsec = 0;
1030 		ts.tv_sec = 120;
1031 		ret = pselect(n + 1, &rd_set, NULL, NULL, &ts, &emptyset);
1032 #else
1033 		ts.tv_usec = 0;
1034 		ts.tv_sec = 120;
1035 		sigprocmask(SIG_UNBLOCK, &blockset, NULL);
1036 		ret = select(n + 1, &rd_set, NULL, NULL, &ts);
1037 		sigprocmask(SIG_BLOCK, &blockset, NULL);
1038 #endif
1039 		if (ret == 0 || (ret == -1 && errno == EINTR))
1040 			continue;
1041 
1042 		if (ret < 0) {
1043 			e = errno;
1044 			seclog(sec, LOG_ERR, "Error in pselect(): %s",
1045 			       strerror(e));
1046 			exit(1);
1047 		}
1048 
1049 		/* we do a new allocation, to also use it as pool for the
1050 		 * parsers to use */
1051 		buffer_size = MAX_MSG_SIZE;
1052 		buffer = talloc_size(sec, buffer_size);
1053 		if (buffer == NULL) {
1054 			seclog(sec, LOG_ERR, "error in memory allocation");
1055 			exit(1);
1056 		}
1057 
1058 		/* we use two fds for communication with main. The synchronous is for
1059 		 * ping-pong communication which each request is answered immediated. The
1060 		 * async is for messages sent back and forth in no particular order */
1061 		if (FD_ISSET(cmd_fd_sync, &rd_set)) {
1062 			ret = serve_request_main(sec, cmd_fd_sync, buffer, buffer_size);
1063 			if (ret < 0 && ret == ERR_BAD_COMMAND) {
1064 				seclog(sec, LOG_ERR, "error processing sync command from main");
1065 				exit(1);
1066 			}
1067 		}
1068 
1069 		if (FD_ISSET(cmd_fd, &rd_set)) {
1070 			ret = serve_request_main(sec, cmd_fd, buffer, buffer_size);
1071 			if (ret < 0 && ret == ERR_BAD_COMMAND) {
1072 				seclog(sec, LOG_ERR, "error processing async command from main");
1073 				exit(1);
1074 			}
1075 		}
1076 
1077 		if (FD_ISSET(sd, &rd_set)) {
1078 			sa_len = sizeof(sa);
1079 			cfd = accept(sd, (struct sockaddr *)&sa, &sa_len);
1080 			if (cfd == -1) {
1081 				e = errno;
1082 				if (e != EINTR) {
1083 					seclog(sec, LOG_DEBUG,
1084 					       "sec-mod error accepting connection: %s",
1085 					       strerror(e));
1086 					goto cont;
1087 				}
1088 			}
1089 			set_cloexec_flag (cfd, 1);
1090 
1091 			/* do not allow unauthorized processes to issue commands
1092 			 */
1093 			ret = check_upeer_id("sec-mod", GETPCONFIG(sec)->debug, cfd,
1094 					     GETPCONFIG(sec)->uid, GETPCONFIG(sec)->gid,
1095 					     &uid, &pid);
1096 			if (ret < 0) {
1097 				seclog(sec, LOG_INFO, "rejected unauthorized connection");
1098 			} else {
1099 				memset(buffer, 0, buffer_size);
1100 				serve_request_worker(sec, cfd, pid, buffer, buffer_size);
1101 			}
1102 			close(cfd);
1103 		}
1104  cont:
1105 		talloc_free(buffer);
1106 #ifdef DEBUG_LEAKS
1107 		talloc_report_full(sec, stderr);
1108 #endif
1109 	}
1110 }
1111