1 /*
2 ** Zabbix
3 ** Copyright (C) 2001-2021 Zabbix SIA
4 **
5 ** This program is free software; you can redistribute it and/or modify
6 ** it under the terms of the GNU General Public License as published by
7 ** the Free Software Foundation; either version 2 of the License, or
8 ** (at your option) any later version.
9 **
10 ** This program is distributed in the hope that it will be useful,
11 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
12 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 ** GNU General Public License for more details.
14 **
15 ** You should have received a copy of the GNU General Public License
16 ** along with this program; if not, write to the Free Software
17 ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 **/
19
20 #include "common.h"
21
22 #include "threads.h"
23 #include "comms.h"
24 #include "cfg.h"
25 #include "log.h"
26 #include "zbxgetopt.h"
27 #include "zbxcrypto.h"
28
29 #ifndef _WINDOWS
30 # include "zbxnix.h"
31 #endif
32
33 const char *progname = NULL;
34 const char title_message[] = "zabbix_get";
35 const char syslog_app_name[] = "zabbix_get";
36 const char *usage_message[] = {
37 "-s host-name-or-IP", "[-p port-number]", "[-I IP-address]", "-k item-key", NULL,
38 #if defined(HAVE_GNUTLS) || defined(HAVE_OPENSSL)
39 "-s host-name-or-IP", "[-p port-number]", "[-I IP-address]", "--tls-connect cert", "--tls-ca-file CA-file",
40 "[--tls-crl-file CRL-file]", "[--tls-agent-cert-issuer cert-issuer]", "[--tls-agent-cert-subject cert-subject]",
41 "--tls-cert-file cert-file", "--tls-key-file key-file",
42 #if defined(HAVE_OPENSSL)
43 "[--tls-cipher13 cipher-string]",
44 #endif
45 #if defined(HAVE_GNUTLS) || defined(HAVE_OPENSSL)
46 "[--tls-cipher cipher-string]",
47 #endif
48 "-k item-key", NULL,
49 "-s host-name-or-IP", "[-p port-number]", "[-I IP-address]", "--tls-connect psk",
50 "--tls-psk-identity PSK-identity", "--tls-psk-file PSK-file",
51 #if defined(HAVE_OPENSSL)
52 "[--tls-cipher13 cipher-string]",
53 #endif
54 #if defined(HAVE_GNUTLS) || defined(HAVE_OPENSSL)
55 "[--tls-cipher cipher-string]",
56 #endif
57 "-k item-key", NULL,
58 #endif
59 "-h", NULL,
60 "-V", NULL,
61 NULL /* end of text */
62 };
63
64 unsigned char program_type = ZBX_PROGRAM_TYPE_GET;
65
66 const char *help_message[] = {
67 "Get data from Zabbix agent.",
68 "",
69 "General options:",
70 " -s --host host-name-or-IP Specify host name or IP address of a host",
71 " -p --port port-number Specify port number of agent running on the host",
72 " (default: " ZBX_DEFAULT_AGENT_PORT_STR ")",
73 " -I --source-address IP-address Specify source IP address",
74 "",
75 " -k --key item-key Specify key of the item to retrieve value for",
76 "",
77 " -h --help Display this help message",
78 " -V --version Display version number",
79 "",
80 "TLS connection options:",
81 #if defined(HAVE_GNUTLS) || defined(HAVE_OPENSSL)
82 " --tls-connect value How to connect to agent. Values:",
83 " unencrypted - connect without encryption",
84 " (default)",
85 " psk - connect using TLS and a pre-shared",
86 " key",
87 " cert - connect using TLS and a",
88 " certificate",
89 "",
90 " --tls-ca-file CA-file Full pathname of a file containing the top-level",
91 " CA(s) certificates for peer certificate",
92 " verification",
93 "",
94 " --tls-crl-file CRL-file Full pathname of a file containing revoked",
95 " certificates",
96 "",
97 " --tls-agent-cert-issuer cert-issuer Allowed agent certificate issuer",
98 "",
99 " --tls-agent-cert-subject cert-subject Allowed agent certificate subject",
100 "",
101 " --tls-cert-file cert-file Full pathname of a file containing the certificate",
102 " or certificate chain",
103 "",
104 " --tls-key-file key-file Full pathname of a file containing the private key",
105 "",
106 " --tls-psk-identity PSK-identity Unique, case sensitive string used to",
107 " identify the pre-shared key",
108 "",
109 " --tls-psk-file PSK-file Full pathname of a file containing the pre-shared",
110 " key",
111 #if defined(HAVE_OPENSSL)
112 "",
113 " --tls-cipher13 Cipher string for OpenSSL 1.1.1 or newer for",
114 " TLS 1.3. Override the default ciphersuite",
115 " selection criteria. This option is not available",
116 " if OpenSSL version is less than 1.1.1",
117 #endif
118 #if defined(HAVE_GNUTLS) || defined(HAVE_OPENSSL)
119 "",
120 " --tls-cipher GnuTLS priority string (for TLS 1.2 and up) or",
121 " OpenSSL cipher string (only for TLS 1.2).",
122 " Override the default ciphersuite selection",
123 " criteria",
124 #endif
125 #else
126 " Not available. This 'zabbix_get' was compiled without TLS support",
127 #endif
128 "",
129 "Example(s):",
130 " zabbix_get -s 127.0.0.1 -p " ZBX_DEFAULT_AGENT_PORT_STR " -k \"system.cpu.load[all,avg1]\"",
131 #if defined(HAVE_GNUTLS) || defined(HAVE_OPENSSL)
132 "",
133 " zabbix_get -s 127.0.0.1 -p " ZBX_DEFAULT_AGENT_PORT_STR " -k \"system.cpu.load[all,avg1]\" \\",
134 " --tls-connect cert --tls-ca-file /home/zabbix/zabbix_ca_file \\",
135 " --tls-agent-cert-issuer \\",
136 " \"CN=Signing CA,OU=IT operations,O=Example Corp,DC=example,DC=com\" \\",
137 " --tls-agent-cert-subject \\",
138 " \"CN=server1,OU=IT operations,O=Example Corp,DC=example,DC=com\" \\",
139 " --tls-cert-file /home/zabbix/zabbix_get.crt \\",
140 " --tls-key-file /home/zabbix/zabbix_get.key",
141 "",
142 " zabbix_get -s 127.0.0.1 -p " ZBX_DEFAULT_AGENT_PORT_STR " -k \"system.cpu.load[all,avg1]\" \\",
143 " --tls-connect psk --tls-psk-identity \"PSK ID Zabbix agentd\" \\",
144 " --tls-psk-file /home/zabbix/zabbix_agentd.psk",
145 #endif
146 NULL /* end of text */
147 };
148
149 /* TLS parameters */
150 unsigned int configured_tls_connect_mode = ZBX_TCP_SEC_UNENCRYPTED;
151 unsigned int configured_tls_accept_modes = ZBX_TCP_SEC_UNENCRYPTED; /* not used in zabbix_get, just for linking */
152 /* with tls.c */
153 char *CONFIG_TLS_CONNECT = NULL;
154 char *CONFIG_TLS_ACCEPT = NULL; /* not used in zabbix_get, just for linking with tls.c */
155 char *CONFIG_TLS_CA_FILE = NULL;
156 char *CONFIG_TLS_CRL_FILE = NULL;
157 char *CONFIG_TLS_SERVER_CERT_ISSUER = NULL;
158 char *CONFIG_TLS_SERVER_CERT_SUBJECT = NULL;
159 char *CONFIG_TLS_CERT_FILE = NULL;
160 char *CONFIG_TLS_KEY_FILE = NULL;
161 char *CONFIG_TLS_PSK_IDENTITY = NULL;
162 char *CONFIG_TLS_PSK_FILE = NULL;
163
164 char *CONFIG_TLS_CIPHER_CERT13 = NULL; /* not used in zabbix_get, just for linking with tls.c */
165 char *CONFIG_TLS_CIPHER_CERT = NULL; /* not used in zabbix_get, just for linking with tls.c */
166 char *CONFIG_TLS_CIPHER_PSK13 = NULL; /* not used in zabbix_get, just for linking with tls.c */
167 char *CONFIG_TLS_CIPHER_PSK = NULL; /* not used in zabbix_get, just for linking with tls.c */
168 char *CONFIG_TLS_CIPHER_ALL13 = NULL; /* not used in zabbix_get, just for linking with tls.c */
169 char *CONFIG_TLS_CIPHER_ALL = NULL; /* not used in zabbix_get, just for linking with tls.c */
170 char *CONFIG_TLS_CIPHER_CMD13 = NULL; /* parameter '--tls-cipher13' from zabbix_get command line */
171 char *CONFIG_TLS_CIPHER_CMD = NULL; /* parameter '--tls-cipher' from zabbix_get command line */
172
173 int CONFIG_PASSIVE_FORKS = 0; /* not used in zabbix_get, just for linking with tls.c */
174 int CONFIG_ACTIVE_FORKS = 0; /* not used in zabbix_get, just for linking with tls.c */
175
176 int CONFIG_TCP_MAX_BACKLOG_SIZE = SOMAXCONN;
177
178 /* COMMAND LINE OPTIONS */
179
180 /* long options */
181 struct zbx_option longopts[] =
182 {
183 {"host", 1, NULL, 's'},
184 {"port", 1, NULL, 'p'},
185 {"key", 1, NULL, 'k'},
186 {"source-address", 1, NULL, 'I'},
187 {"help", 0, NULL, 'h'},
188 {"version", 0, NULL, 'V'},
189 {"tls-connect", 1, NULL, '1'},
190 {"tls-ca-file", 1, NULL, '2'},
191 {"tls-crl-file", 1, NULL, '3'},
192 {"tls-agent-cert-issuer", 1, NULL, '4'},
193 {"tls-agent-cert-subject", 1, NULL, '5'},
194 {"tls-cert-file", 1, NULL, '6'},
195 {"tls-key-file", 1, NULL, '7'},
196 {"tls-psk-identity", 1, NULL, '8'},
197 {"tls-psk-file", 1, NULL, '9'},
198 {"tls-cipher13", 1, NULL, 'A'},
199 {"tls-cipher", 1, NULL, 'B'},
200 {NULL}
201 };
202
203 /* short options */
204 static char shortopts[] = "s:p:k:I:hV";
205
206 /* end of COMMAND LINE OPTIONS */
207
208 #if !defined(_WINDOWS)
209
210 /******************************************************************************
211 * *
212 * Function: get_signal_handler *
213 * *
214 * Purpose: process signals *
215 * *
216 * Parameters: sig - signal ID *
217 * *
218 * Return value: *
219 * *
220 * Comments: *
221 * *
222 ******************************************************************************/
get_signal_handler(int sig)223 static void get_signal_handler(int sig)
224 {
225 if (SIGPIPE == sig) /* this signal is raised when peer closes connection because of access restrictions */
226 return;
227
228 if (SIGALRM == sig)
229 zbx_error("Timeout while executing operation");
230
231 #if defined(HAVE_GNUTLS) || defined(HAVE_OPENSSL)
232 if (ZBX_TCP_SEC_UNENCRYPTED != configured_tls_connect_mode)
233 zbx_tls_free_on_signal();
234 #endif
235 exit(EXIT_FAILURE);
236 }
237
238 #endif /* not WINDOWS */
239
240 /******************************************************************************
241 * *
242 * Function: get_value *
243 * *
244 * Purpose: connect to Zabbix agent, receive and print value *
245 * *
246 * Parameters: host - server name or IP address *
247 * port - port number *
248 * key - item's key *
249 * *
250 ******************************************************************************/
get_value(const char * source_ip,const char * host,unsigned short port,const char * key)251 static int get_value(const char *source_ip, const char *host, unsigned short port, const char *key)
252 {
253 zbx_socket_t s;
254 int ret;
255 ssize_t bytes_received = -1;
256 char *tls_arg1, *tls_arg2;
257
258 switch (configured_tls_connect_mode)
259 {
260 case ZBX_TCP_SEC_UNENCRYPTED:
261 tls_arg1 = NULL;
262 tls_arg2 = NULL;
263 break;
264 #if defined(HAVE_GNUTLS) || defined(HAVE_OPENSSL)
265 case ZBX_TCP_SEC_TLS_CERT:
266 tls_arg1 = CONFIG_TLS_SERVER_CERT_ISSUER;
267 tls_arg2 = CONFIG_TLS_SERVER_CERT_SUBJECT;
268 break;
269 case ZBX_TCP_SEC_TLS_PSK:
270 tls_arg1 = CONFIG_TLS_PSK_IDENTITY;
271 tls_arg2 = NULL; /* zbx_tls_connect() will find PSK */
272 break;
273 #endif
274 default:
275 THIS_SHOULD_NEVER_HAPPEN;
276 return FAIL;
277 }
278
279 if (SUCCEED == (ret = zbx_tcp_connect(&s, source_ip, host, port, GET_SENDER_TIMEOUT,
280 configured_tls_connect_mode, tls_arg1, tls_arg2)))
281 {
282 if (SUCCEED == (ret = zbx_tcp_send(&s, key)))
283 {
284 if (0 < (bytes_received = zbx_tcp_recv_ext(&s, 0, 0)))
285 {
286 if (0 == strcmp(s.buffer, ZBX_NOTSUPPORTED) && sizeof(ZBX_NOTSUPPORTED) < s.read_bytes)
287 {
288 zbx_rtrim(s.buffer + sizeof(ZBX_NOTSUPPORTED), "\r\n");
289 printf("%s: %s\n", s.buffer, s.buffer + sizeof(ZBX_NOTSUPPORTED));
290 }
291 else
292 {
293 zbx_rtrim(s.buffer, "\r\n");
294 printf("%s\n", s.buffer);
295 }
296 }
297 else
298 {
299 if (0 == bytes_received)
300 zbx_error("Check access restrictions in Zabbix agent configuration");
301 ret = FAIL;
302 }
303 }
304
305 zbx_tcp_close(&s);
306
307 if (SUCCEED != ret && 0 != bytes_received)
308 {
309 zbx_error("Get value error: %s", zbx_socket_strerror());
310 zbx_error("Check access restrictions in Zabbix agent configuration");
311 }
312 }
313 else
314 zbx_error("Get value error: %s", zbx_socket_strerror());
315
316 return ret;
317 }
318
319 /******************************************************************************
320 * *
321 * Function: main *
322 * *
323 * Purpose: main function *
324 * *
325 * Parameters: *
326 * *
327 * Return value: *
328 * *
329 * Comments: *
330 * *
331 ******************************************************************************/
main(int argc,char ** argv)332 int main(int argc, char **argv)
333 {
334 int i, ret = SUCCEED;
335 char *host = NULL, *key = NULL, *source_ip = NULL, ch;
336 unsigned short opt_count[256] = {0}, port = ZBX_DEFAULT_AGENT_PORT;
337 #if defined(_WINDOWS)
338 char *error = NULL;
339 #endif
340
341 #if !defined(_WINDOWS) && (defined(HAVE_GNUTLS) || defined(HAVE_OPENSSL))
342 if (SUCCEED != zbx_coredump_disable())
343 {
344 zbx_error("cannot disable core dump, exiting...");
345 exit(EXIT_FAILURE);
346 }
347 #endif
348 progname = get_program_name(argv[0]);
349
350 /* parse the command-line */
351 while ((char)EOF != (ch = (char)zbx_getopt_long(argc, argv, shortopts, longopts, NULL)))
352 {
353 opt_count[(unsigned char)ch]++;
354
355 switch (ch)
356 {
357 case 'k':
358 if (NULL == key)
359 key = zbx_strdup(NULL, zbx_optarg);
360 break;
361 case 'p':
362 port = (unsigned short)atoi(zbx_optarg);
363 break;
364 case 's':
365 if (NULL == host)
366 host = zbx_strdup(NULL, zbx_optarg);
367 break;
368 case 'I':
369 if (NULL == source_ip)
370 source_ip = zbx_strdup(NULL, zbx_optarg);
371 break;
372 case 'h':
373 help();
374 exit(EXIT_SUCCESS);
375 break;
376 case 'V':
377 version();
378 exit(EXIT_SUCCESS);
379 break;
380 #if defined(HAVE_GNUTLS) || defined(HAVE_OPENSSL)
381 case '1':
382 CONFIG_TLS_CONNECT = zbx_strdup(CONFIG_TLS_CONNECT, zbx_optarg);
383 break;
384 case '2':
385 CONFIG_TLS_CA_FILE = zbx_strdup(CONFIG_TLS_CA_FILE, zbx_optarg);
386 break;
387 case '3':
388 CONFIG_TLS_CRL_FILE = zbx_strdup(CONFIG_TLS_CRL_FILE, zbx_optarg);
389 break;
390 case '4':
391 CONFIG_TLS_SERVER_CERT_ISSUER = zbx_strdup(CONFIG_TLS_SERVER_CERT_ISSUER, zbx_optarg);
392 break;
393 case '5':
394 CONFIG_TLS_SERVER_CERT_SUBJECT = zbx_strdup(CONFIG_TLS_SERVER_CERT_SUBJECT, zbx_optarg);
395 break;
396 case '6':
397 CONFIG_TLS_CERT_FILE = zbx_strdup(CONFIG_TLS_CERT_FILE, zbx_optarg);
398 break;
399 case '7':
400 CONFIG_TLS_KEY_FILE = zbx_strdup(CONFIG_TLS_KEY_FILE, zbx_optarg);
401 break;
402 case '8':
403 CONFIG_TLS_PSK_IDENTITY = zbx_strdup(CONFIG_TLS_PSK_IDENTITY, zbx_optarg);
404 break;
405 case '9':
406 CONFIG_TLS_PSK_FILE = zbx_strdup(CONFIG_TLS_PSK_FILE, zbx_optarg);
407 break;
408 case 'A':
409 #if defined(HAVE_OPENSSL)
410 CONFIG_TLS_CIPHER_CMD13 = zbx_strdup(CONFIG_TLS_CIPHER_CMD13, zbx_optarg);
411 #elif defined(HAVE_GNUTLS)
412 zbx_error("parameter \"--tls-cipher13\" can be used with OpenSSL 1.1.1 or newer."
413 " zabbix_get was compiled with GnuTLS");
414 exit(EXIT_FAILURE);
415 #endif
416 break;
417 case 'B':
418 CONFIG_TLS_CIPHER_CMD = zbx_strdup(CONFIG_TLS_CIPHER_CMD, zbx_optarg);
419 break;
420 #else
421 case '1':
422 case '2':
423 case '3':
424 case '4':
425 case '5':
426 case '6':
427 case '7':
428 case '8':
429 case '9':
430 case 'A':
431 case 'B':
432 zbx_error("TLS parameters cannot be used: 'zabbix_get' was compiled without TLS"
433 " support");
434 exit(EXIT_FAILURE);
435 break;
436 #endif
437 default:
438 usage();
439 exit(EXIT_FAILURE);
440 break;
441 }
442 }
443
444 #if defined(_WINDOWS)
445 if (SUCCEED != zbx_socket_start(&error))
446 {
447 zbx_error(error);
448 zbx_free(error);
449 exit(EXIT_FAILURE);
450 }
451 #endif
452
453 if (NULL == host || NULL == key)
454 {
455 usage();
456 ret = FAIL;
457 }
458
459 /* every option may be specified only once */
460
461 for (i = 0; NULL != longopts[i].name; i++)
462 {
463 ch = longopts[i].val;
464
465 if (1 < opt_count[(unsigned char)ch])
466 {
467 if (NULL == strchr(shortopts, ch))
468 zbx_error("option \"--%s\" specified multiple times", longopts[i].name);
469 else
470 zbx_error("option \"-%c\" or \"--%s\" specified multiple times", ch, longopts[i].name);
471
472 ret = FAIL;
473 }
474 }
475
476 if (FAIL == ret)
477 goto out;
478
479 /* Parameters which are not option values are invalid. The check relies on zbx_getopt_internal() which */
480 /* always permutes command line arguments regardless of POSIXLY_CORRECT environment variable. */
481 if (argc > zbx_optind)
482 {
483 for (i = zbx_optind; i < argc; i++)
484 zbx_error("invalid parameter \"%s\"", argv[i]);
485
486 ret = FAIL;
487 }
488
489 if (FAIL == ret)
490 {
491 printf("Try '%s --help' for more information.\n", progname);
492 goto out;
493 }
494
495 if (NULL != CONFIG_TLS_CONNECT || NULL != CONFIG_TLS_CA_FILE || NULL != CONFIG_TLS_CRL_FILE ||
496 NULL != CONFIG_TLS_SERVER_CERT_ISSUER || NULL != CONFIG_TLS_SERVER_CERT_SUBJECT ||
497 NULL != CONFIG_TLS_CERT_FILE || NULL != CONFIG_TLS_KEY_FILE ||
498 NULL != CONFIG_TLS_PSK_IDENTITY || NULL != CONFIG_TLS_PSK_FILE ||
499 NULL != CONFIG_TLS_CIPHER_CMD13 || NULL != CONFIG_TLS_CIPHER_CMD)
500 {
501 #if defined(HAVE_GNUTLS) || defined(HAVE_OPENSSL)
502 zbx_tls_validate_config();
503
504 if (ZBX_TCP_SEC_UNENCRYPTED != configured_tls_connect_mode)
505 {
506 #if defined(_WINDOWS)
507 zbx_tls_init_parent();
508 #endif
509 zbx_tls_init_child();
510 }
511 #endif
512 }
513 #if !defined(_WINDOWS)
514 signal(SIGINT, get_signal_handler);
515 signal(SIGQUIT, get_signal_handler);
516 signal(SIGTERM, get_signal_handler);
517 signal(SIGHUP, get_signal_handler);
518 signal(SIGALRM, get_signal_handler);
519 signal(SIGPIPE, get_signal_handler);
520 #endif
521 ret = get_value(source_ip, host, port, key);
522 out:
523 zbx_free(host);
524 zbx_free(key);
525 zbx_free(source_ip);
526 #if defined(HAVE_GNUTLS) || defined(HAVE_OPENSSL)
527 if (ZBX_TCP_SEC_UNENCRYPTED != configured_tls_connect_mode)
528 {
529 zbx_tls_free();
530 #if defined(_WINDOWS)
531 zbx_tls_library_deinit();
532 #endif
533 }
534 #endif
535 #if defined(_WINDOWS)
536 while (0 == WSACleanup())
537 ;
538 #endif
539
540 return SUCCEED == ret ? EXIT_SUCCESS : EXIT_FAILURE;
541 }
542