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