]> git.proxmox.com Git - mirror_corosync-qdevice.git/blob - qdevices/corosync-qnetd.c
qnetd: Don't alloc host_addr
[mirror_corosync-qdevice.git] / qdevices / corosync-qnetd.c
1 /*
2 * Copyright (c) 2015-2020 Red Hat, Inc.
3 *
4 * All rights reserved.
5 *
6 * Author: Jan Friesse (jfriesse@redhat.com)
7 *
8 * This software licensed under BSD license, the text of which follows:
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions are met:
12 *
13 * - Redistributions of source code must retain the above copyright notice,
14 * this list of conditions and the following disclaimer.
15 * - Redistributions in binary form must reproduce the above copyright notice,
16 * this list of conditions and the following disclaimer in the documentation
17 * and/or other materials provided with the distribution.
18 * - Neither the name of the Red Hat, Inc. nor the names of its
19 * contributors may be used to endorse or promote products derived from this
20 * software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
26 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
32 * THE POSSIBILITY OF SUCH DAMAGE.
33 */
34
35 #include <err.h>
36 #include <errno.h>
37 #include <getopt.h>
38 #include <limits.h>
39 #include <signal.h>
40 #include <unistd.h>
41
42 #include "qnet-config.h"
43
44 #include "dynar.h"
45 #include "dynar-str.h"
46 #include "dynar-getopt-lex.h"
47 #include "log.h"
48 #include "nss-sock.h"
49 #include "pr-poll-array.h"
50 #include "qnetd-advanced-settings.h"
51 #include "qnetd-algorithm.h"
52 #include "qnetd-instance.h"
53 #include "qnetd-ipc.h"
54 #include "qnetd-client-net.h"
55 #include "qnetd-client-msg-received.h"
56 #include "utils.h"
57 #include "msg.h"
58
59 #ifdef HAVE_LIBSYSTEMD
60 #include <systemd/sd-daemon.h>
61 #endif
62
63 /*
64 * This is global variable used for comunication with main loop and signal (calls close)
65 */
66 struct qnetd_instance *global_instance;
67
68 enum tlv_decision_algorithm_type
69 qnetd_static_supported_decision_algorithms[QNETD_STATIC_SUPPORTED_DECISION_ALGORITHMS_SIZE] = {
70 TLV_DECISION_ALGORITHM_TYPE_TEST,
71 TLV_DECISION_ALGORITHM_TYPE_FFSPLIT,
72 TLV_DECISION_ALGORITHM_TYPE_2NODELMS,
73 TLV_DECISION_ALGORITHM_TYPE_LMS,
74 };
75
76 static void
77 qnetd_err_nss(void)
78 {
79
80 log_nss(LOG_CRIT, "NSS error");
81
82 exit(EXIT_FAILURE);
83 }
84
85 static void
86 qnetd_warn_nss(void)
87 {
88
89 log_nss(LOG_WARNING, "NSS warning");
90 }
91
92 static int
93 server_socket_poll_loop_read_cb(PRFileDesc *prfd, const PRPollDesc *pd, void *user_data1, void *user_data2)
94 {
95 struct qnetd_instance *instance = (struct qnetd_instance *)user_data1;
96
97 qnetd_client_net_accept(instance);
98
99 return (0);
100 }
101
102 static int
103 server_socket_poll_loop_err_cb(PRFileDesc *prfd, short revents, const PRPollDesc *pd,
104 void *user_data1, void *user_data2)
105 {
106
107 if (revents != POLLNVAL) {
108 /*
109 * Poll ERR on listening socket is fatal error.
110 * POLL_NVAL is used as a signal to quit poll loop.
111 */
112 log(LOG_CRIT, "POLL_ERR (%u) on listening socket", revents);
113 } else {
114 log(LOG_DEBUG, "Listening socket is closed");
115 }
116
117 return (-1);
118 }
119
120 static void
121 signal_int_handler(int sig)
122 {
123
124 log(LOG_DEBUG, "SIGINT received - closing server IPC socket");
125
126 qnetd_ipc_close(global_instance);
127 }
128
129 static void
130 signal_term_handler(int sig)
131 {
132
133 log(LOG_DEBUG, "SIGTERM received - closing server IPC socket");
134
135 qnetd_ipc_close(global_instance);
136 }
137
138 static void
139 signal_handlers_register(void)
140 {
141 struct sigaction act;
142
143 act.sa_handler = signal_int_handler;
144 sigemptyset(&act.sa_mask);
145 act.sa_flags = SA_RESTART;
146
147 sigaction(SIGINT, &act, NULL);
148
149 act.sa_handler = signal_term_handler;
150 sigemptyset(&act.sa_mask);
151 act.sa_flags = SA_RESTART;
152
153 sigaction(SIGTERM, &act, NULL);
154 }
155
156 static int
157 qnetd_run_main_loop(struct qnetd_instance *instance)
158 {
159 int poll_res;
160
161 while ((poll_res = pr_poll_loop_exec(&instance->main_poll_loop)) == 0) {
162 }
163
164 if (poll_res == -2) {
165 log(LOG_CRIT, "pr_poll_loop_exec returned -2 - internal error");
166 return (-1);
167 } else if (poll_res == -3) {
168 log_nss(LOG_CRIT, "pr_poll_loop_exec returned -3 - PR_Poll error");
169 return (-1);
170 }
171
172 return (qnetd_ipc_is_closed(instance) ? 0 : -1);
173 }
174
175 static void
176 usage(void)
177 {
178
179 printf("usage: %s [-46dfhv] [-l listen_addr] [-p listen_port] [-s tls]\n", QNETD_PROGRAM_NAME);
180 printf("%14s[-c client_cert_required] [-m max_clients] [-S option=value[,option2=value2,...]]\n", "");
181 }
182
183 static void
184 display_version(void)
185 {
186 enum msg_type *supported_messages;
187 size_t no_supported_messages;
188 size_t zi;
189
190 msg_get_supported_messages(&supported_messages, &no_supported_messages);
191 printf("Corosync Qdevice Network Daemon, version '%s'\n\n", VERSION);
192 printf("Supported algorithms: ");
193 for (zi = 0; zi < QNETD_STATIC_SUPPORTED_DECISION_ALGORITHMS_SIZE; zi++) {
194 if (zi != 0) {
195 printf(", ");
196 }
197 printf("%s (%u)",
198 tlv_decision_algorithm_type_to_str(qnetd_static_supported_decision_algorithms[zi]),
199 qnetd_static_supported_decision_algorithms[zi]);
200 }
201 printf("\n");
202 printf("Supported message types: ");
203 for (zi = 0; zi < no_supported_messages; zi++) {
204 if (zi != 0) {
205 printf(", ");
206 }
207 printf("%s (%u)", msg_type_to_str(supported_messages[zi]), supported_messages[zi]);
208 }
209 printf("\n");
210 }
211
212 static void
213 cli_parse_long_opt(struct qnetd_advanced_settings *advanced_settings, const char *long_opt)
214 {
215 struct dynar_getopt_lex lex;
216 struct dynar dynar_long_opt;
217 const char *opt;
218 const char *val;
219 int res;
220
221 dynar_init(&dynar_long_opt, strlen(long_opt) + 1);
222 if (dynar_str_cpy(&dynar_long_opt, long_opt) != 0) {
223 errx(EXIT_FAILURE, "Can't alloc memory for long option");
224 }
225
226 dynar_getopt_lex_init(&lex, &dynar_long_opt);
227
228 while (dynar_getopt_lex_token_next(&lex) == 0 && strcmp(dynar_data(&lex.option), "") != 0) {
229 opt = dynar_data(&lex.option);
230 val = dynar_data(&lex.value);
231
232 res = qnetd_advanced_settings_set(advanced_settings, opt, val);
233 switch (res) {
234 case -1:
235 errx(EXIT_FAILURE, "Unknown option '%s'", opt);
236 break;
237 case -2:
238 errx(EXIT_FAILURE, "Invalid value '%s' for option '%s'", val, opt);
239 break;
240 case -3:
241 warnx("Option '%s' is deprecated and has no effect anymore", opt);
242 break;
243 }
244 }
245
246 dynar_getopt_lex_destroy(&lex);
247 dynar_destroy(&dynar_long_opt);
248 }
249
250 static void
251 cli_parse(int argc, char * const argv[], char **host_addr, uint16_t *host_port, int *foreground,
252 int *debug_log, int *bump_log_priority, enum tlv_tls_supported *tls_supported,
253 int *client_cert_required, size_t *max_clients, PRIntn *address_family,
254 struct qnetd_advanced_settings *advanced_settings)
255 {
256 int ch;
257 long long int tmpll;
258
259 *host_addr = NULL;
260 *host_port = QNETD_DEFAULT_HOST_PORT;
261 *foreground = 0;
262 *debug_log = 0;
263 *bump_log_priority = 0;
264 *tls_supported = QNETD_DEFAULT_TLS_SUPPORTED;
265 *client_cert_required = QNETD_DEFAULT_TLS_CLIENT_CERT_REQUIRED;
266 *max_clients = QNETD_DEFAULT_MAX_CLIENTS;
267 *address_family = PR_AF_UNSPEC;
268
269 while ((ch = getopt(argc, argv, "46dfhvc:l:m:p:S:s:")) != -1) {
270 switch (ch) {
271 case '4':
272 *address_family = PR_AF_INET;
273 break;
274 case '6':
275 *address_family = PR_AF_INET6;
276 break;
277 case 'f':
278 *foreground = 1;
279 break;
280 case 'd':
281 if (*debug_log) {
282 *bump_log_priority = 1;
283 }
284 *debug_log = 1;
285 break;
286 case 'c':
287 if ((*client_cert_required = utils_parse_bool_str(optarg)) == -1) {
288 errx(EXIT_FAILURE, "client_cert_required should be on/yes/1, off/no/0");
289 }
290 break;
291 case 'l':
292 *host_addr = optarg;
293 break;
294 case 'm':
295 if (utils_strtonum(optarg, 0, LLONG_MAX, &tmpll) == -1) {
296 errx(EXIT_FAILURE, "max clients value %s is invalid", optarg);
297 }
298
299 *max_clients = (size_t)tmpll;
300 break;
301 case 'p':
302 if (utils_strtonum(optarg, 1, UINT16_MAX, &tmpll) == -1) {
303 errx(EXIT_FAILURE, "host port must be in range 1-%u", UINT16_MAX);
304 }
305
306 *host_port = tmpll;
307 break;
308 case 'S':
309 cli_parse_long_opt(advanced_settings, optarg);
310 break;
311 case 's':
312 if (strcasecmp(optarg, "on") == 0) {
313 *tls_supported = QNETD_DEFAULT_TLS_SUPPORTED;
314 } else if (strcasecmp(optarg, "off") == 0) {
315 *tls_supported = TLV_TLS_UNSUPPORTED;
316 } else if (strcasecmp(optarg, "req") == 0) {
317 *tls_supported = TLV_TLS_REQUIRED;
318 } else {
319 errx(EXIT_FAILURE, "tls must be one of on, off, req");
320 }
321 break;
322 case 'v':
323 display_version();
324 exit(EXIT_FAILURE);
325 break;
326 case 'h':
327 case '?':
328 usage();
329 exit(EXIT_FAILURE);
330 break;
331 }
332 }
333 }
334
335 int
336 main(int argc, char * const argv[])
337 {
338 struct qnetd_instance instance;
339 struct qnetd_advanced_settings advanced_settings;
340 char *host_addr;
341 uint16_t host_port;
342 int foreground;
343 int debug_log;
344 int bump_log_priority;
345 enum tlv_tls_supported tls_supported;
346 int client_cert_required;
347 size_t max_clients;
348 PRIntn address_family;
349 int lock_file;
350 int another_instance_running;
351 int log_target;
352 int main_loop_res;
353
354 if (qnetd_advanced_settings_init(&advanced_settings) != 0) {
355 errx(EXIT_FAILURE, "Can't alloc memory for advanced settings");
356 }
357
358 cli_parse(argc, argv, &host_addr, &host_port, &foreground, &debug_log, &bump_log_priority,
359 &tls_supported, &client_cert_required, &max_clients, &address_family, &advanced_settings);
360
361 log_target = LOG_TARGET_SYSLOG;
362 if (foreground) {
363 log_target |= LOG_TARGET_STDERR;
364 }
365
366 if (log_init(QNETD_PROGRAM_NAME, log_target, LOG_DAEMON) == -1) {
367 errx(EXIT_FAILURE, "Can't initialize logging");
368 }
369
370 log_set_debug(debug_log);
371 log_set_priority_bump(bump_log_priority);
372
373 /*
374 * Check that it's possible to open NSS dir if needed
375 */
376 if (nss_sock_check_db_dir((tls_supported != TLV_TLS_UNSUPPORTED ?
377 advanced_settings.nss_db_dir : NULL)) != 0) {
378 log_err(LOG_ERR, "Can't open NSS DB directory");
379
380 return (EXIT_FAILURE);
381 }
382
383 /*
384 * Daemonize
385 */
386 if (!foreground) {
387 utils_tty_detach();
388 }
389
390 if ((lock_file = utils_flock(advanced_settings.lock_file, getpid(),
391 &another_instance_running)) == -1) {
392 if (another_instance_running) {
393 log(LOG_ERR, "Another instance is running");
394 } else {
395 log_err(LOG_ERR, "Can't acquire lock");
396 }
397
398 return (EXIT_FAILURE);
399 }
400
401 log(LOG_DEBUG, "Initializing nss");
402 if (nss_sock_init_nss((tls_supported != TLV_TLS_UNSUPPORTED ?
403 advanced_settings.nss_db_dir : NULL)) != 0) {
404 qnetd_err_nss();
405 }
406
407 if (SSL_ConfigServerSessionIDCache(0, 0, 0, NULL) != SECSuccess) {
408 qnetd_err_nss();
409 }
410
411 if (qnetd_instance_init(&instance, tls_supported, client_cert_required,
412 max_clients, &advanced_settings) == -1) {
413 log(LOG_ERR, "Can't initialize qnetd");
414 return (EXIT_FAILURE);
415 }
416 instance.host_addr = host_addr;
417 instance.host_port = host_port;
418
419 if (tls_supported != TLV_TLS_UNSUPPORTED && qnetd_instance_init_certs(&instance) == -1) {
420 qnetd_err_nss();
421 }
422
423 log(LOG_DEBUG, "Initializing local socket");
424 if (qnetd_ipc_init(&instance) != 0) {
425 return (EXIT_FAILURE);
426 }
427
428 log(LOG_DEBUG, "Creating listening socket");
429 instance.server.socket = nss_sock_create_listen_socket(instance.host_addr,
430 instance.host_port, address_family);
431 if (instance.server.socket == NULL) {
432 qnetd_err_nss();
433 }
434
435 if (nss_sock_set_non_blocking(instance.server.socket) != 0) {
436 qnetd_err_nss();
437 }
438
439 if (PR_Listen(instance.server.socket, instance.advanced_settings->listen_backlog) !=
440 PR_SUCCESS) {
441 qnetd_err_nss();
442 }
443
444 if (pr_poll_loop_add_prfd(&instance.main_poll_loop, instance.server.socket, POLLIN,
445 NULL,
446 server_socket_poll_loop_read_cb,
447 NULL,
448 server_socket_poll_loop_err_cb,
449 &instance, NULL) != 0) {
450 log(LOG_ERR, "Can't add server socket to main poll loop");
451
452 return (EXIT_FAILURE);
453 }
454
455 global_instance = &instance;
456 signal_handlers_register();
457
458 log(LOG_DEBUG, "Registering algorithms");
459 if (qnetd_algorithm_register_all() != 0) {
460 return (EXIT_FAILURE);
461 }
462
463 log(LOG_DEBUG, "QNetd ready to provide service");
464
465 #ifdef HAVE_LIBSYSTEMD
466 sd_notify(0, "READY=1");
467 #endif
468
469 log(LOG_DEBUG, "Running QNetd main loop");
470 main_loop_res = qnetd_run_main_loop(&instance);
471
472 /*
473 * Cleanup
474 */
475 log(LOG_DEBUG, "Destroying qnetd ipc");
476 qnetd_ipc_destroy(&instance);
477
478 log(LOG_DEBUG, "Closing server socket");
479 if (PR_Close(instance.server.socket) != PR_SUCCESS) {
480 qnetd_warn_nss();
481 }
482
483 CERT_DestroyCertificate(instance.server.cert);
484 SECKEY_DestroyPrivateKey(instance.server.private_key);
485
486 SSL_ClearSessionCache();
487
488 SSL_ShutdownServerSessionIDCache();
489
490 qnetd_instance_destroy(&instance);
491
492 qnetd_advanced_settings_destroy(&advanced_settings);
493
494 if (NSS_Shutdown() != SECSuccess) {
495 qnetd_warn_nss();
496 }
497
498 if (PR_Cleanup() != PR_SUCCESS) {
499 qnetd_warn_nss();
500 }
501
502 log(LOG_DEBUG, "Closing log");
503 log_close();
504
505 return (main_loop_res == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
506 }