1 /* upsd.c - watches ups state files and answers queries
2
3 Copyright (C)
4 1999 Russell Kroll <rkroll@exploits.org>
5 2008 Arjen de Korte <adkorte-guest@alioth.debian.org>
6 2011 - 2012 Arnaud Quette <arnaud.quette.free.fr>
7 2019 Eaton (author: Arnaud Quette <ArnaudQuette@eaton.com>)
8
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 */
23
24 #include "upsd.h"
25 #include "upstype.h"
26 #include "conf.h"
27
28 #include "netcmds.h"
29 #include "upsconf.h"
30
31 #include <sys/un.h>
32 #include <sys/socket.h>
33 #include <netdb.h>
34 #include <signal.h>
35
36 #include "user.h"
37 #include "nut_ctype.h"
38 #include "nut_stdint.h"
39 #include "stype.h"
40 #include "netssl.h"
41 #include "sstate.h"
42 #include "desc.h"
43 #include "neterr.h"
44
45 #ifdef HAVE_WRAP
46 #include <tcpd.h>
47 int allow_severity = LOG_INFO;
48 int deny_severity = LOG_WARNING;
49 #endif /* HAVE_WRAP */
50
51 /* externally-visible settings and pointers */
52
53 upstype_t *firstups = NULL;
54
55 /* default 15 seconds before data is marked stale */
56 int maxage = 15;
57
58 /* default to 1h before cleaning up status tracking entries */
59 int tracking_delay = 3600;
60
61 /*
62 * Preloaded to ALLOW_NO_DEVICE from upsd.conf or environment variable
63 * (with higher prio for envvar); defaults to disabled for legacy compat.
64 */
65 int allow_no_device = 0;
66
67 /* preloaded to {OPEN_MAX} in main, can be overridden via upsd.conf */
68 nfds_t maxconn = 0;
69
70 /* preloaded to STATEPATH in main, can be overridden via upsd.conf */
71 char *statepath = NULL;
72
73 /* preloaded to DATADIR in main, can be overridden via upsd.conf */
74 char *datapath = NULL;
75
76 /* everything else */
77 static const char *progname;
78
79 nut_ctype_t *firstclient = NULL;
80 /* static nut_ctype_t *lastclient = NULL; */
81
82 /* default is to listen on all local interfaces */
83 static stype_t *firstaddr = NULL;
84
85 static int opt_af = AF_UNSPEC;
86
87 typedef enum {
88 DRIVER = 1,
89 CLIENT,
90 SERVER
91 } handler_type_t;
92
93 typedef struct {
94 handler_type_t type;
95 void *data;
96 } handler_t;
97
98
99 /* Commands and settings status tracking */
100
101 /* general enable/disable status info for commands and settings
102 * (disabled by default)
103 * Note that only client that requested it will have it enabled
104 * (see nut_ctype.h) */
105 static int tracking_enabled = 0;
106
107 /* Commands and settings status tracking structure */
108 typedef struct tracking_s {
109 char *id;
110 int status;
111 time_t request_time; /* for cleanup */
112 /* doubly linked list */
113 struct tracking_s *prev;
114 struct tracking_s *next;
115 } tracking_t;
116
117 static tracking_t *tracking_list = NULL;
118
119
120 /* pollfd */
121 static struct pollfd *fds = NULL;
122 static handler_t *handler = NULL;
123
124 /* pid file */
125 static char pidfn[SMALLBUF];
126
127 /* set by signal handlers */
128 static int reload_flag = 0, exit_flag = 0;
129
130 /* Minimalistic support for UUID v4 */
131 /* Ref: RFC 4122 https://tools.ietf.org/html/rfc4122#section-4.1.2 */
132 #define UUID4_BYTESIZE 16
133
134
inet_ntopW(struct sockaddr_storage * s)135 static const char *inet_ntopW (struct sockaddr_storage *s)
136 {
137 static char str[40];
138
139 switch (s->ss_family)
140 {
141 case AF_INET:
142 return inet_ntop (AF_INET, &(((struct sockaddr_in *)s)->sin_addr), str, 16);
143 case AF_INET6:
144 return inet_ntop (AF_INET6, &(((struct sockaddr_in6 *)s)->sin6_addr), str, 40);
145 default:
146 errno = EAFNOSUPPORT;
147 return NULL;
148 }
149 }
150
151 /* return a pointer to the named ups if possible */
get_ups_ptr(const char * name)152 upstype_t *get_ups_ptr(const char *name)
153 {
154 upstype_t *tmp;
155
156 if (!name) {
157 return NULL;
158 }
159
160 for (tmp = firstups; tmp; tmp = tmp->next) {
161 if (!strcasecmp(tmp->name, name)) {
162 return tmp;
163 }
164 }
165
166 return NULL;
167 }
168
169 /* mark the data stale if this is new, otherwise cleanup any remaining junk */
ups_data_stale(upstype_t * ups)170 static void ups_data_stale(upstype_t *ups)
171 {
172 /* don't complain again if it's already known to be stale */
173 if (ups->stale == 1) {
174 return;
175 }
176
177 ups->stale = 1;
178
179 upslogx(LOG_NOTICE, "Data for UPS [%s] is stale - check driver", ups->name);
180 }
181
182 /* mark the data ok if this is new, otherwise do nothing */
ups_data_ok(upstype_t * ups)183 static void ups_data_ok(upstype_t *ups)
184 {
185 if (ups->stale == 0) {
186 return;
187 }
188
189 ups->stale = 0;
190
191 upslogx(LOG_NOTICE, "UPS [%s] data is no longer stale", ups->name);
192 }
193
194 /* add another listening address */
listen_add(const char * addr,const char * port)195 void listen_add(const char *addr, const char *port)
196 {
197 stype_t *server;
198
199 /* don't change listening addresses on reload */
200 if (reload_flag) {
201 return;
202 }
203
204 /* grab some memory and add the info */
205 server = xcalloc(1, sizeof(*server));
206 server->addr = xstrdup(addr);
207 server->port = xstrdup(port);
208 server->sock_fd = -1;
209 server->next = firstaddr;
210
211 firstaddr = server;
212
213 upsdebugx(3, "listen_add: added %s:%s", server->addr, server->port);
214 }
215
216 /* create a listening socket for tcp connections */
setuptcp(stype_t * server)217 static void setuptcp(stype_t *server)
218 {
219 struct addrinfo hints, *res, *ai;
220 int v = 0, one = 1;
221
222 upsdebugx(3, "setuptcp: try to bind to %s port %s", server->addr, server->port);
223
224 memset(&hints, 0, sizeof(hints));
225 hints.ai_flags = AI_PASSIVE;
226 hints.ai_family = opt_af;
227 hints.ai_socktype = SOCK_STREAM;
228 hints.ai_protocol = IPPROTO_TCP;
229
230 if ((v = getaddrinfo(server->addr, server->port, &hints, &res)) != 0) {
231 if (v == EAI_SYSTEM) {
232 fatal_with_errno(EXIT_FAILURE, "getaddrinfo");
233 }
234
235 fatalx(EXIT_FAILURE, "getaddrinfo: %s", gai_strerror(v));
236 }
237
238 for (ai = res; ai; ai = ai->ai_next) {
239 int sock_fd;
240
241 if ((sock_fd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol)) < 0) {
242 upsdebug_with_errno(3, "setuptcp: socket");
243 continue;
244 }
245
246 if (setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, (void *)&one, sizeof(one)) != 0) {
247 fatal_with_errno(EXIT_FAILURE, "setuptcp: setsockopt");
248 }
249
250 if (bind(sock_fd, ai->ai_addr, ai->ai_addrlen) < 0) {
251 upsdebug_with_errno(3, "setuptcp: bind");
252 close(sock_fd);
253 continue;
254 }
255
256 if ((v = fcntl(sock_fd, F_GETFL, 0)) == -1) {
257 fatal_with_errno(EXIT_FAILURE, "setuptcp: fcntl(get)");
258 }
259
260 if (fcntl(sock_fd, F_SETFL, v | O_NDELAY) == -1) {
261 fatal_with_errno(EXIT_FAILURE, "setuptcp: fcntl(set)");
262 }
263
264 if (listen(sock_fd, 16) < 0) {
265 upsdebug_with_errno(3, "setuptcp: listen");
266 close(sock_fd);
267 continue;
268 }
269
270 server->sock_fd = sock_fd;
271 break;
272 }
273
274 freeaddrinfo(res);
275
276 /* leave up to the caller, server_load(), to fail silently if there is
277 * no other valid LISTEN interface */
278 if (server->sock_fd < 0) {
279 upslogx(LOG_ERR, "not listening on %s port %s", server->addr, server->port);
280 } else {
281 upslogx(LOG_INFO, "listening on %s port %s", server->addr, server->port);
282 }
283
284 return;
285 }
286
287 /* decrement the login counter for this ups */
declogins(const char * upsname)288 static void declogins(const char *upsname)
289 {
290 upstype_t *ups;
291
292 ups = get_ups_ptr(upsname);
293
294 if (!ups) {
295 upslogx(LOG_INFO, "Tried to decrement invalid ups name (%s)", upsname);
296 return;
297 }
298
299 ups->numlogins--;
300
301 if (ups->numlogins < 0) {
302 upslogx(LOG_ERR, "Programming error: UPS [%s] has numlogins=%d", ups->name, ups->numlogins);
303 }
304 }
305
306 /* disconnect a client connection and free all related memory */
client_disconnect(nut_ctype_t * client)307 static void client_disconnect(nut_ctype_t *client)
308 {
309 if (!client) {
310 return;
311 }
312
313 upsdebugx(2, "Disconnect from %s", client->addr);
314
315 shutdown(client->sock_fd, 2);
316 close(client->sock_fd);
317
318 if (client->loginups) {
319 declogins(client->loginups);
320 }
321
322 ssl_finish(client);
323
324 pconf_finish(&client->ctx);
325
326 if (client->prev) {
327 client->prev->next = client->next;
328 } else {
329 /* deleting first entry */
330 firstclient = client->next;
331 }
332
333 if (client->next) {
334 client->next->prev = client->prev;
335 } else {
336 /* deleting last entry */
337 /* lastclient = client->prev; */
338 }
339
340 free(client->addr);
341 free(client->loginups);
342 free(client->password);
343 free(client->username);
344 free(client);
345
346 return;
347 }
348
349 /* send the buffer <sendbuf> of length <sendlen> to host <dest>
350 * returns effectively a boolean: 0 = failed, 1 = sent ok
351 */
sendback(nut_ctype_t * client,const char * fmt,...)352 int sendback(nut_ctype_t *client, const char *fmt, ...)
353 {
354 ssize_t res;
355 size_t len;
356 char ans[NUT_NET_ANSWER_MAX+1];
357 va_list ap;
358
359 if (!client) {
360 return 0;
361 }
362
363 va_start(ap, fmt);
364 vsnprintf(ans, sizeof(ans), fmt, ap);
365 va_end(ap);
366
367 len = strlen(ans);
368
369 /* System write() and our ssl_write() have a loophole that they write a
370 * size_t amount of bytes and upon success return that in ssize_t value
371 */
372 assert(len < SSIZE_MAX);
373
374 #ifdef WITH_SSL
375 if (client->ssl) {
376 res = ssl_write(client, ans, len);
377 } else
378 #endif /* WITH_SSL */
379 {
380 res = write(client->sock_fd, ans, len);
381 }
382
383 upsdebugx(2, "write: [destfd=%d] [len=%zu] [%s]", client->sock_fd, len, str_rtrim(ans, '\n'));
384
385 if (res < 0 || len != (size_t)res) {
386 upslog_with_errno(LOG_NOTICE, "write() failed for %s", client->addr);
387 client->last_heard = 0;
388 return 0; /* failed */
389 }
390
391 return 1; /* OK */
392 }
393
394 /* just a simple wrapper for now */
send_err(nut_ctype_t * client,const char * errtype)395 int send_err(nut_ctype_t *client, const char *errtype)
396 {
397 if (!client) {
398 return -1;
399 }
400
401 upsdebugx(4, "Sending error [%s] to client %s", errtype, client->addr);
402
403 return sendback(client, "ERR %s\n", errtype);
404 }
405
406 /* disconnect anyone logged into this UPS */
kick_login_clients(const char * upsname)407 void kick_login_clients(const char *upsname)
408 {
409 nut_ctype_t *client, *cnext;
410
411 for (client = firstclient; client; client = cnext) {
412
413 cnext = client->next;
414
415 /* if it's not logged in, don't check it */
416 if (!client->loginups) {
417 continue;
418 }
419
420 if (!strcmp(client->loginups, upsname)) {
421 upslogx(LOG_INFO, "Kicking client %s (was on UPS [%s])\n", client->addr, upsname);
422 client_disconnect(client);
423 }
424 }
425 }
426
427 /* make sure a UPS is sane - connected, with fresh data */
ups_available(const upstype_t * ups,nut_ctype_t * client)428 int ups_available(const upstype_t *ups, nut_ctype_t *client)
429 {
430 if (ups->sock_fd < 0) {
431 send_err(client, NUT_ERR_DRIVER_NOT_CONNECTED);
432 return 0;
433 }
434
435 if (ups->stale) {
436 send_err(client, NUT_ERR_DATA_STALE);
437 return 0;
438 }
439
440 /* must be OK */
441 return 1;
442 }
443
444 /* check flags and access for an incoming command from the network */
check_command(int cmdnum,nut_ctype_t * client,size_t numarg,const char ** arg)445 static void check_command(int cmdnum, nut_ctype_t *client, size_t numarg,
446 const char **arg)
447 {
448 if (netcmds[cmdnum].flags & FLAG_USER) {
449 #ifdef HAVE_WRAP
450 struct request_info req;
451 #endif /* HAVE_WRAP */
452
453 if (!client->username) {
454 send_err(client, NUT_ERR_USERNAME_REQUIRED);
455 return;
456 }
457
458 if (!client->password) {
459 send_err(client, NUT_ERR_PASSWORD_REQUIRED);
460 return;
461 }
462
463 #ifdef HAVE_WRAP
464 request_init(&req, RQ_DAEMON, progname, RQ_FILE, client->sock_fd, RQ_USER, client->username, 0);
465 fromhost(&req);
466
467 if (!hosts_access(&req)) {
468 /* tcp-wrappers says access should be denied */
469 send_err(client, NUT_ERR_ACCESS_DENIED);
470 return;
471 }
472 #endif /* HAVE_WRAP */
473 }
474
475 /* looks good - call the command */
476 netcmds[cmdnum].func(client, (numarg < 2) ? 0 : (numarg - 1), (numarg > 1) ? &arg[1] : NULL);
477 }
478
479 /* parse requests from the network */
parse_net(nut_ctype_t * client)480 static void parse_net(nut_ctype_t *client)
481 {
482 int i;
483
484 /* shouldn't happen */
485 if (client->ctx.numargs < 1) {
486 send_err(client, NUT_ERR_UNKNOWN_COMMAND);
487 return;
488 }
489
490 for (i = 0; netcmds[i].name; i++) {
491 if (!strcasecmp(netcmds[i].name, client->ctx.arglist[0])) {
492 check_command(i, client, client->ctx.numargs, (const char **) client->ctx.arglist);
493 return;
494 }
495 }
496
497 /* fallthrough = not matched by any entry in netcmds */
498
499 send_err(client, NUT_ERR_UNKNOWN_COMMAND);
500 }
501
502 /* answer incoming tcp connections */
client_connect(stype_t * server)503 static void client_connect(stype_t *server)
504 {
505 struct sockaddr_storage csock;
506 #if defined(__hpux) && !defined(_XOPEN_SOURCE_EXTENDED)
507 int clen;
508 #else
509 socklen_t clen;
510 #endif
511 int fd;
512 nut_ctype_t *client;
513
514 clen = sizeof(csock);
515 fd = accept(server->sock_fd, (struct sockaddr *) &csock, &clen);
516
517 if (fd < 0) {
518 return;
519 }
520
521 client = xcalloc(1, sizeof(*client));
522
523 client->sock_fd = fd;
524
525 time(&client->last_heard);
526
527 client->addr = xstrdup(inet_ntopW(&csock));
528
529 client->tracking = 0;
530
531 pconf_init(&client->ctx, NULL);
532
533 if (firstclient) {
534 firstclient->prev = client;
535 client->next = firstclient;
536 }
537
538 firstclient = client;
539
540 /*
541 if (lastclient) {
542 client->prev = lastclient;
543 lastclient->next = client;
544 }
545
546 lastclient = client;
547 */
548 upsdebugx(2, "Connect from %s", client->addr);
549 }
550
551 /* read tcp messages and handle them */
client_readline(nut_ctype_t * client)552 static void client_readline(nut_ctype_t *client)
553 {
554 char buf[SMALLBUF];
555 int i;
556 ssize_t ret;
557
558 #ifdef WITH_SSL
559 if (client->ssl) {
560 ret = ssl_read(client, buf, sizeof(buf));
561 } else
562 #endif /* WITH_SSL */
563 {
564 ret = read(client->sock_fd, buf, sizeof(buf));
565 }
566
567 if (ret < 0) {
568 upsdebug_with_errno(2, "Disconnect %s (read failure)", client->addr);
569 client_disconnect(client);
570 return;
571 }
572
573 if (ret == 0) {
574 upsdebugx(2, "Disconnect %s (no data available)", client->addr);
575 client_disconnect(client);
576 return;
577 }
578
579 /* fragment handling code */
580 for (i = 0; i < ret; i++) {
581
582 /* add to the receive queue one by one */
583 switch (pconf_char(&client->ctx, buf[i]))
584 {
585 case 1:
586 time(&client->last_heard); /* command received */
587 parse_net(client);
588 continue;
589
590 case 0:
591 continue; /* haven't gotten a line yet */
592
593 default:
594 /* parse error */
595 upslogx(LOG_NOTICE, "Parse error on sock: %s", client->ctx.errmsg);
596 return;
597 }
598 }
599
600 return;
601 }
602
server_load(void)603 void server_load(void)
604 {
605 stype_t *server;
606
607 /* default behaviour if no LISTEN addres has been specified */
608 if (!firstaddr) {
609 if (opt_af != AF_INET) {
610 listen_add("::1", string_const(PORT));
611 }
612
613 if (opt_af != AF_INET6) {
614 listen_add("127.0.0.1", string_const(PORT));
615 }
616 }
617
618 for (server = firstaddr; server; server = server->next) {
619 setuptcp(server);
620 }
621
622 /* check if we have at least 1 valid LISTEN interface */
623 if (firstaddr->sock_fd < 0) {
624 fatalx(EXIT_FAILURE, "no listening interface available");
625 }
626 }
627
server_free(void)628 void server_free(void)
629 {
630 stype_t *server, *snext;
631
632 /* cleanup server fds */
633 for (server = firstaddr; server; server = snext) {
634 snext = server->next;
635
636 if (server->sock_fd != -1) {
637 close(server->sock_fd);
638 }
639
640 free(server->addr);
641 free(server->port);
642 free(server);
643 }
644
645 firstaddr = NULL;
646 }
647
client_free(void)648 static void client_free(void)
649 {
650 nut_ctype_t *client, *cnext;
651
652 /* cleanup client fds */
653 for (client = firstclient; client; client = cnext) {
654 cnext = client->next;
655 client_disconnect(client);
656 }
657 }
658
driver_free(void)659 static void driver_free(void)
660 {
661 upstype_t *ups, *unext;
662
663 for (ups = firstups; ups; ups = unext) {
664 unext = ups->next;
665
666 if (ups->sock_fd != -1) {
667 close(ups->sock_fd);
668 }
669
670 sstate_infofree(ups);
671 sstate_cmdfree(ups);
672
673 pconf_finish(&ups->sock_ctx);
674
675 free(ups->fn);
676 free(ups->name);
677 free(ups->desc);
678 free(ups);
679 }
680 }
681
upsd_cleanup(void)682 static void upsd_cleanup(void)
683 {
684 if (strlen(pidfn) > 0) {
685 unlink(pidfn);
686 }
687
688 /* dump everything */
689
690 user_flush();
691 desc_free();
692
693 server_free();
694 client_free();
695 driver_free();
696 tracking_free();
697
698 free(statepath);
699 free(datapath);
700 free(certfile);
701 free(certname);
702 free(certpasswd);
703
704 free(fds);
705 free(handler);
706 }
707
poll_reload(void)708 static void poll_reload(void)
709 {
710 long ret;
711
712 ret = sysconf(_SC_OPEN_MAX);
713
714 if ((intmax_t)ret < (intmax_t)maxconn) {
715 fatalx(EXIT_FAILURE,
716 "Your system limits the maximum number of connections to %ld\n"
717 "but you requested %jd. The server won't start until this\n"
718 "problem is resolved.\n", ret, (intmax_t)maxconn);
719 }
720
721 if (1 > maxconn) {
722 fatalx(EXIT_FAILURE,
723 "You requested %jd as maximum number of connections.\n"
724 "The server won't start until this problem is resolved.\n", (intmax_t)maxconn);
725 }
726
727 /* How many items can we stuff into the array? */
728 size_t maxalloc = SIZE_MAX / sizeof(void *);
729 if ((uintmax_t)maxalloc < (uintmax_t)maxconn) {
730 fatalx(EXIT_FAILURE,
731 "You requested %jd as maximum number of connections, but we can only allocate %zu.\n"
732 "The server won't start until this problem is resolved.\n", (intmax_t)maxconn, maxalloc);
733 }
734
735 /* The checks above effectively limit that maxconn is in size_t range */
736 fds = xrealloc(fds, (size_t)maxconn * sizeof(*fds));
737 handler = xrealloc(handler, (size_t)maxconn * sizeof(*handler));
738 }
739
740 /* instant command and setvar status tracking */
741
742 /* allocate a new status tracking entry */
tracking_add(const char * id)743 int tracking_add(const char *id)
744 {
745 tracking_t *item;
746
747 if ((!tracking_enabled) || (!id))
748 return 0;
749
750 item = xcalloc(1, sizeof(*item));
751
752 item->id = xstrdup(id);
753 item->status = STAT_PENDING;
754 time(&item->request_time);
755
756 if (tracking_list) {
757 tracking_list->prev = item;
758 item->next = tracking_list;
759 }
760
761 tracking_list = item;
762
763 return 1;
764 }
765
766 /* set status of a specific tracking entry */
tracking_set(const char * id,const char * value)767 int tracking_set(const char *id, const char *value)
768 {
769 tracking_t *item, *next_item;
770
771 /* sanity checks */
772 if ((!tracking_list) || (!id) || (!value))
773 return 0;
774
775 for (item = tracking_list; item; item = next_item) {
776
777 next_item = item->next;
778
779 if (!strcasecmp(item->id, id)) {
780 item->status = atoi(value);
781 return 1;
782 }
783 }
784
785 return 0; /* id not found! */
786 }
787
788 /* free a specific tracking entry */
tracking_del(const char * id)789 int tracking_del(const char *id)
790 {
791 tracking_t *item, *next_item;
792
793 /* sanity check */
794 if ((!tracking_list) || (!id))
795 return 0;
796
797 upsdebugx(3, "%s: deleting id %s", __func__, id);
798
799 for (item = tracking_list; item; item = next_item) {
800
801 next_item = item->next;
802
803 if (strcasecmp(item->id, id))
804 continue;
805
806 if (item->prev)
807 item->prev->next = item->next;
808 else
809 /* deleting first entry */
810 tracking_list = item->next;
811
812 if (item->next)
813 item->next->prev = item->prev;
814
815 free(item->id);
816 free(item);
817
818 return 1;
819
820 }
821
822 return 0; /* id not found! */
823 }
824
825 /* free all status tracking entries */
tracking_free(void)826 void tracking_free(void)
827 {
828 tracking_t *item, *next_item;
829
830 /* sanity check */
831 if (!tracking_list)
832 return;
833
834 upsdebugx(3, "%s", __func__);
835
836 for (item = tracking_list; item; item = next_item) {
837 next_item = item->next;
838 tracking_del(item->id);
839 }
840 }
841
842 /* cleanup status tracking entries according to their age and tracking_delay */
tracking_cleanup(void)843 void tracking_cleanup(void)
844 {
845 tracking_t *item, *next_item;
846 time_t now;
847
848 /* sanity check */
849 if (!tracking_list)
850 return;
851
852 time(&now);
853
854 upsdebugx(3, "%s", __func__);
855
856 for (item = tracking_list; item; item = next_item) {
857
858 next_item = item->next;
859
860 if (difftime(now, item->request_time) > tracking_delay) {
861 tracking_del(item->id);
862 }
863 }
864 }
865
866 /* get status of a specific tracking entry */
tracking_get(const char * id)867 char *tracking_get(const char *id)
868 {
869 tracking_t *item, *next_item;
870
871 /* sanity checks */
872 if ((!tracking_list) || (!id))
873 return "ERR UNKNOWN";
874
875 for (item = tracking_list; item; item = next_item) {
876
877 next_item = item->next;
878
879 if (strcasecmp(item->id, id))
880 continue;
881
882 switch (item->status)
883 {
884 case STAT_PENDING:
885 return "PENDING";
886 case STAT_HANDLED:
887 return "SUCCESS";
888 case STAT_UNKNOWN:
889 return "ERR UNKNOWN";
890 case STAT_INVALID:
891 return "ERR INVALID-ARGUMENT";
892 case STAT_FAILED:
893 return "ERR FAILED";
894 }
895 }
896
897 return "ERR UNKNOWN"; /* id not found! */
898 }
899
900 /* enable general status tracking (tracking_enabled) and return its value (1). */
tracking_enable(void)901 int tracking_enable(void)
902 {
903 tracking_enabled = 1;
904
905 return tracking_enabled;
906 }
907
908 /* disable general status tracking only if no client use it anymore.
909 * return the new value for tracking_enabled */
tracking_disable(void)910 int tracking_disable(void)
911 {
912 nut_ctype_t *client, *cnext;
913
914 for (client = firstclient; client; client = cnext) {
915 cnext = client->next;
916 if (client->tracking == 1)
917 return 1;
918 }
919 return 0;
920 }
921
922 /* return current general status of tracking (tracking_enabled). */
tracking_is_enabled(void)923 int tracking_is_enabled(void)
924 {
925 return tracking_enabled;
926 }
927
928 /* UUID v4 basic implementation
929 * Note: 'dest' must be at least `UUID4_LEN` long */
nut_uuid_v4(char * uuid_str)930 int nut_uuid_v4(char *uuid_str)
931 {
932 size_t i;
933 uint8_t nut_uuid[UUID4_BYTESIZE];
934
935 if (!uuid_str)
936 return 0;
937
938 for (i = 0; i < UUID4_BYTESIZE; i++)
939 nut_uuid[i] = (uint8_t)rand() + (uint8_t)rand();
940
941 /* set variant and version */
942 nut_uuid[6] = (nut_uuid[6] & 0x0F) | 0x40;
943 nut_uuid[8] = (nut_uuid[8] & 0x3F) | 0x80;
944
945 return snprintf(uuid_str, UUID4_LEN,
946 "%02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X",
947 nut_uuid[0], nut_uuid[1], nut_uuid[2], nut_uuid[3],
948 nut_uuid[4], nut_uuid[5], nut_uuid[6], nut_uuid[7],
949 nut_uuid[8], nut_uuid[9], nut_uuid[10], nut_uuid[11],
950 nut_uuid[12], nut_uuid[13], nut_uuid[14], nut_uuid[15]);
951 }
952
953 /* service requests and check on new data */
mainloop(void)954 static void mainloop(void)
955 {
956 int ret;
957 nfds_t i, nfds = 0;
958
959 upstype_t *ups;
960 nut_ctype_t *client, *cnext;
961 stype_t *server;
962 time_t now;
963
964 time(&now);
965
966 if (reload_flag) {
967 conf_reload();
968 poll_reload();
969 reload_flag = 0;
970 }
971
972 /* cleanup instcmd/setvar status tracking entries if needed */
973 tracking_cleanup();
974
975 /* scan through driver sockets */
976 for (ups = firstups; ups && (nfds < maxconn); ups = ups->next) {
977
978 /* see if we need to (re)connect to the socket */
979 if (ups->sock_fd < 0) {
980 ups->sock_fd = sstate_connect(ups);
981 continue;
982 }
983
984 /* throw some warnings if it's not feeding us data any more */
985 if (sstate_dead(ups, maxage)) {
986 ups_data_stale(ups);
987 } else {
988 ups_data_ok(ups);
989 }
990
991 fds[nfds].fd = ups->sock_fd;
992 fds[nfds].events = POLLIN;
993
994 handler[nfds].type = DRIVER;
995 handler[nfds].data = ups;
996
997 nfds++;
998 }
999
1000 /* scan through client sockets */
1001 for (client = firstclient; client; client = cnext) {
1002
1003 cnext = client->next;
1004
1005 if (difftime(now, client->last_heard) > 60) {
1006 /* shed clients after 1 minute of inactivity */
1007 /* FIXME: create an upsd.conf parameter (CLIENT_INACTIVITY_DELAY) */
1008 client_disconnect(client);
1009 continue;
1010 }
1011
1012 if (nfds >= maxconn) {
1013 /* ignore clients that we are unable to handle */
1014 continue;
1015 }
1016
1017 fds[nfds].fd = client->sock_fd;
1018 fds[nfds].events = POLLIN;
1019
1020 handler[nfds].type = CLIENT;
1021 handler[nfds].data = client;
1022
1023 nfds++;
1024 }
1025
1026 /* scan through server sockets */
1027 for (server = firstaddr; server && (nfds < maxconn); server = server->next) {
1028
1029 if (server->sock_fd < 0) {
1030 continue;
1031 }
1032
1033 fds[nfds].fd = server->sock_fd;
1034 fds[nfds].events = POLLIN;
1035
1036 handler[nfds].type = SERVER;
1037 handler[nfds].data = server;
1038
1039 nfds++;
1040 }
1041
1042 upsdebugx(2, "%s: polling %jd filedescriptors", __func__, (intmax_t)nfds);
1043
1044 ret = poll(fds, nfds, 2000);
1045
1046 if (ret == 0) {
1047 upsdebugx(2, "%s: no data available", __func__);
1048 return;
1049 }
1050
1051 if (ret < 0) {
1052 upslog_with_errno(LOG_ERR, "%s", __func__);
1053 return;
1054 }
1055
1056 for (i = 0; i < nfds; i++) {
1057
1058 if (fds[i].revents & (POLLHUP|POLLERR|POLLNVAL)) {
1059
1060 switch(handler[i].type)
1061 {
1062 case DRIVER:
1063 sstate_disconnect((upstype_t *)handler[i].data);
1064 break;
1065 case CLIENT:
1066 client_disconnect((nut_ctype_t *)handler[i].data);
1067 break;
1068 case SERVER:
1069 upsdebugx(2, "%s: server disconnected", __func__);
1070 break;
1071
1072 #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_COVERED_SWITCH_DEFAULT)
1073 # pragma GCC diagnostic push
1074 # pragma GCC diagnostic ignored "-Wcovered-switch-default"
1075 #endif
1076 /* All enum cases defined as of the time of coding
1077 * have been covered above. Handle later definitions,
1078 * memory corruptions and buggy inputs below...
1079 */
1080 default:
1081 upsdebugx(2, "%s: <unknown> disconnected", __func__);
1082 break;
1083 #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_COVERED_SWITCH_DEFAULT)
1084 # pragma GCC diagnostic pop
1085 #endif
1086
1087 }
1088
1089 continue;
1090 }
1091
1092 if (fds[i].revents & POLLIN) {
1093
1094 switch(handler[i].type)
1095 {
1096 case DRIVER:
1097 sstate_readline((upstype_t *)handler[i].data);
1098 break;
1099 case CLIENT:
1100 client_readline((nut_ctype_t *)handler[i].data);
1101 break;
1102 case SERVER:
1103 client_connect((stype_t *)handler[i].data);
1104 break;
1105
1106 #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_COVERED_SWITCH_DEFAULT)
1107 # pragma GCC diagnostic push
1108 # pragma GCC diagnostic ignored "-Wcovered-switch-default"
1109 #endif
1110 /* All enum cases defined as of the time of coding
1111 * have been covered above. Handle later definitions,
1112 * memory corruptions and buggy inputs below...
1113 */
1114 default:
1115 upsdebugx(2, "%s: <unknown> has data available", __func__);
1116 break;
1117 #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_COVERED_SWITCH_DEFAULT)
1118 # pragma GCC diagnostic pop
1119 #endif
1120 }
1121
1122 continue;
1123 }
1124 }
1125 }
1126
1127 static void help(const char *arg_progname)
1128 __attribute__((noreturn));
1129
help(const char * arg_progname)1130 static void help(const char *arg_progname)
1131 {
1132 printf("Network server for UPS data.\n\n");
1133 printf("usage: %s [OPTIONS]\n", arg_progname);
1134
1135 printf("\n");
1136 printf(" -c <command> send <command> via signal to background process\n");
1137 printf(" commands:\n");
1138 printf(" - reload: reread configuration files\n");
1139 printf(" - stop: stop process and exit\n");
1140 printf(" -D raise debugging level\n");
1141 printf(" -h display this help\n");
1142 printf(" -r <dir> chroots to <dir>\n");
1143 printf(" -q raise log level threshold\n");
1144 printf(" -u <user> switch to <user> (if started as root)\n");
1145 printf(" -V display the version of this software\n");
1146 printf(" -4 IPv4 only\n");
1147 printf(" -6 IPv6 only\n");
1148
1149 exit(EXIT_SUCCESS);
1150 }
1151
set_reload_flag(int sig)1152 static void set_reload_flag(int sig)
1153 {
1154 NUT_UNUSED_VARIABLE(sig);
1155 reload_flag = 1;
1156 }
1157
set_exit_flag(int sig)1158 static void set_exit_flag(int sig)
1159 {
1160 exit_flag = sig;
1161 }
1162
setup_signals(void)1163 static void setup_signals(void)
1164 {
1165 struct sigaction sa;
1166
1167 sigemptyset(&sa.sa_mask);
1168 sigaddset(&sa.sa_mask, SIGHUP);
1169 sa.sa_flags = 0;
1170
1171 /* basic signal setup to ignore SIGPIPE */
1172 #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_STRICT_PROTOTYPES)
1173 # pragma GCC diagnostic push
1174 # pragma GCC diagnostic ignored "-Wstrict-prototypes"
1175 #endif
1176 sa.sa_handler = SIG_IGN;
1177 #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_STRICT_PROTOTYPES)
1178 # pragma GCC diagnostic pop
1179 #endif
1180 sigaction(SIGPIPE, &sa, NULL);
1181
1182 /* handle shutdown signals */
1183 sa.sa_handler = set_exit_flag;
1184 sigaction(SIGINT, &sa, NULL);
1185 sigaction(SIGQUIT, &sa, NULL);
1186 sigaction(SIGTERM, &sa, NULL);
1187
1188 /* handle reloading */
1189 sa.sa_handler = set_reload_flag;
1190 sigaction(SIGHUP, &sa, NULL);
1191 }
1192
check_perms(const char * fn)1193 void check_perms(const char *fn)
1194 {
1195 int ret;
1196 struct stat st;
1197
1198 ret = stat(fn, &st);
1199
1200 if (ret != 0) {
1201 fatal_with_errno(EXIT_FAILURE, "stat %s", fn);
1202 }
1203
1204 /* include the x bit here in case we check a directory */
1205 if (st.st_mode & (S_IROTH | S_IXOTH)) {
1206 upslogx(LOG_WARNING, "%s is world readable", fn);
1207 }
1208 }
1209
main(int argc,char ** argv)1210 int main(int argc, char **argv)
1211 {
1212 int i, cmd = 0, cmdret = 0;
1213 char *chroot_path = NULL;
1214 const char *user = RUN_AS_USER;
1215 struct passwd *new_uid = NULL;
1216
1217 progname = xbasename(argv[0]);
1218
1219 /* yes, xstrdup - the conf handlers call free on this later */
1220 statepath = xstrdup(dflt_statepath());
1221 datapath = xstrdup(DATADIR);
1222
1223 /* set up some things for later */
1224 snprintf(pidfn, sizeof(pidfn), "%s/%s.pid", altpidpath(), progname);
1225
1226 printf("Network UPS Tools %s %s\n", progname, UPS_VERSION);
1227
1228 while ((i = getopt(argc, argv, "+h46p:qr:i:fu:Vc:D")) != -1) {
1229 switch (i) {
1230 case 'p':
1231 case 'i':
1232 fatalx(EXIT_FAILURE, "Specifying a listening addresses with '-i <address>' and '-p <port>'\n"
1233 "is deprecated. Use 'LISTEN <address> [<port>]' in 'upsd.conf' instead.\n"
1234 "See 'man 8 upsd.conf' for more information.");
1235 #ifndef HAVE___ATTRIBUTE__NORETURN
1236 exit(EXIT_FAILURE); /* Should not get here in practice, but compiler is afraid we can fall through */
1237 #endif
1238
1239 case 'q':
1240 nut_log_level++;
1241 break;
1242
1243 case 'r':
1244 chroot_path = optarg;
1245 break;
1246
1247 case 'u':
1248 user = optarg;
1249 break;
1250
1251 case 'V':
1252 /* do nothing - we already printed the banner */
1253 exit(EXIT_SUCCESS);
1254
1255 case 'c':
1256 if (!strncmp(optarg, "reload", strlen(optarg)))
1257 cmd = SIGCMD_RELOAD;
1258 if (!strncmp(optarg, "stop", strlen(optarg)))
1259 cmd = SIGCMD_STOP;
1260
1261 /* bad command given */
1262 if (cmd == 0)
1263 help(progname);
1264 break;
1265
1266 case 'D':
1267 nut_debug_level++;
1268 break;
1269
1270 case '4':
1271 opt_af = AF_INET;
1272 break;
1273
1274 case '6':
1275 opt_af = AF_INET6;
1276 break;
1277
1278 case 'h':
1279 default:
1280 help(progname);
1281 }
1282 }
1283
1284 if (cmd) {
1285 cmdret = sendsignalfn(pidfn, cmd);
1286 exit((cmdret == 0)?EXIT_SUCCESS:EXIT_FAILURE);
1287 }
1288
1289 /* otherwise, we are being asked to start.
1290 * so check if a previous instance is running by sending signal '0'
1291 * (Ie 'kill <pid> 0') */
1292 if (sendsignalfn(pidfn, 0) == 0) {
1293 printf("Fatal error: A previous upsd instance is already running!\n");
1294 printf("Either stop the previous instance first, or use the 'reload' command.\n");
1295 exit(EXIT_FAILURE);
1296 }
1297
1298 argc -= optind;
1299 argv += optind;
1300
1301 if (argc != 0) {
1302 help(progname);
1303 }
1304
1305 atexit(upsd_cleanup);
1306
1307 setup_signals();
1308
1309 open_syslog(progname);
1310
1311 /* send logging to the syslog pre-background for later use */
1312 syslogbit_set();
1313
1314 /* do this here, since getpwnam() might not work in the chroot */
1315 new_uid = get_user_pwent(user);
1316
1317 if (chroot_path) {
1318 chroot_start(chroot_path);
1319 }
1320
1321 /* default to system limit (may be overridden in upsd.conf) */
1322 /* FIXME: Check for overflows (and int size of nfds_t vs. long) - see get_max_pid_t() for example */
1323 maxconn = (nfds_t)sysconf(_SC_OPEN_MAX);
1324
1325 /* handle upsd.conf */
1326 load_upsdconf(0); /* 0 = initial */
1327
1328 { // scope
1329 /* As documented above, the ALLOW_NO_DEVICE can be provided via
1330 * envvars and then has higher priority than an upsd.conf setting
1331 */
1332 const char *envvar = getenv("ALLOW_NO_DEVICE");
1333 if ( envvar != NULL) {
1334 if ( (!strncasecmp("TRUE", envvar, 4)) || (!strncasecmp("YES", envvar, 3)) || (!strncasecmp("ON", envvar, 2)) || (!strncasecmp("1", envvar, 1)) ) {
1335 /* Admins of this server expressed a desire to serve
1336 * anything on the NUT protocol, even if nothing is
1337 * configured yet - tell the clients so, properly.
1338 */
1339 allow_no_device = 1;
1340 } else if ( (!strncasecmp("FALSE", envvar, 5)) || (!strncasecmp("NO", envvar, 2)) || (!strncasecmp("OFF", envvar, 3)) || (!strncasecmp("0", envvar, 1)) ) {
1341 /* Admins of this server expressed a desire to serve
1342 * anything on the NUT protocol, even if nothing is
1343 * configured yet - tell the clients so, properly.
1344 */
1345 allow_no_device = 0;
1346 }
1347 }
1348 } // scope
1349
1350 /* start server */
1351 server_load();
1352
1353 become_user(new_uid);
1354
1355 if (chdir(statepath)) {
1356 fatal_with_errno(EXIT_FAILURE, "Can't chdir to %s", statepath);
1357 }
1358
1359 /* check statepath perms */
1360 check_perms(statepath);
1361
1362 /* handle ups.conf */
1363 read_upsconf();
1364 upsconf_add(0); /* 0 = initial */
1365 poll_reload();
1366
1367 if (num_ups == 0) {
1368 if (allow_no_device) {
1369 upslogx(LOG_WARNING, "Normally at least one UPS must be defined in ups.conf, currently there are none (please configure the file and reload the service)");
1370 } else {
1371 fatalx(EXIT_FAILURE, "Fatal error: at least one UPS must be defined in ups.conf");
1372 }
1373 }
1374
1375 /* try to bring in the var/cmd descriptions */
1376 desc_load();
1377
1378 /* handle upsd.users */
1379 user_load();
1380
1381 if (!nut_debug_level) {
1382 background();
1383 writepid(pidfn);
1384 } else {
1385 memset(pidfn, 0, sizeof(pidfn));
1386 }
1387
1388 /* initialize SSL (keyfile must be readable by nut user) */
1389 ssl_init();
1390
1391 while (!exit_flag) {
1392 mainloop();
1393 }
1394
1395 ssl_cleanup();
1396
1397 upslogx(LOG_INFO, "Signal %d: exiting", exit_flag);
1398 return EXIT_SUCCESS;
1399 }
1400
1401