new upstream 2.8.0

This commit is contained in:
lagertonne 2022-06-29 12:37:36 +02:00
parent fc7f4b43c1
commit b2b0c9995a
836 changed files with 137090 additions and 30018 deletions

View file

@ -1,5 +1,10 @@
# Network UPS Tools: server
# Make sure out-of-dir dependencies exist (especially when dev-building parts):
$(top_builddir)/common/libcommon.la \
$(top_builddir)/common/libparseconf.la: dummy
@cd $(@D) && $(MAKE) $(AM_MAKEFLAGS) $(@F)
# Avoid per-target CFLAGS, because this will prevent re-use of object
# files. In any case, CFLAGS are only -I options, so there is no harm,
# but only add them if we really use the target.
@ -10,7 +15,7 @@ endif
if WITH_SSL
AM_CFLAGS += $(LIBSSL_CFLAGS)
endif
LDADD = ../common/libcommon.la ../common/libparseconf.la $(NETLIBS)
LDADD = $(top_builddir)/common/libcommon.la $(top_builddir)/common/libparseconf.la $(NETLIBS)
if WITH_WRAP
LDADD += $(LIBWRAP_LIBS)
endif
@ -28,3 +33,12 @@ upsd_SOURCES = upsd.c user.c conf.c netssl.c sstate.c desc.c \
upstype.h user-data.h user.h
sockdebug_SOURCES = sockdebug.c
dummy:
MAINTAINERCLEANFILES = Makefile.in .dirstamp
# NOTE: Do not clean ".deps" in SUBDIRS of the main project,
# the root Makefile.am takes care of that!
#clean-local:
# rm -rf $(builddir)/.deps

View file

@ -1,7 +1,7 @@
# Makefile.in generated by automake 1.14.1 from Makefile.am.
# Makefile.in generated by automake 1.16.3 from Makefile.am.
# @configure_input@
# Copyright (C) 1994-2013 Free Software Foundation, Inc.
# Copyright (C) 1994-2020 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@ -17,7 +17,17 @@
# Network UPS Tools: server
VPATH = @srcdir@
am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
am__is_gnu_make = { \
if test -z '$(MAKELEVEL)'; then \
false; \
elif test -n '$(MAKE_HOST)'; then \
true; \
elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
true; \
else \
false; \
fi; \
}
am__make_running_with_option = \
case $${target_option-} in \
?) ;; \
@ -88,19 +98,24 @@ target_triplet = @target@
sbin_PROGRAMS = upsd$(EXEEXT)
EXTRA_PROGRAMS = sockdebug$(EXEEXT)
subdir = server
DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
$(top_srcdir)/depcomp
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/m4/ax_compare_version.m4 \
am__aclocal_m4_deps = $(top_srcdir)/m4/ax_c___attribute__.m4 \
$(top_srcdir)/m4/ax_c_pragmas.m4 \
$(top_srcdir)/m4/ax_check_compile_flag.m4 \
$(top_srcdir)/m4/ax_compare_version.m4 \
$(top_srcdir)/m4/ax_run_or_link_ifelse.m4 \
$(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
$(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
$(top_srcdir)/m4/lt~obsolete.m4 \
$(top_srcdir)/m4/nut_arg_with.m4 \
$(top_srcdir)/m4/nut_check_asciidoc.m4 \
$(top_srcdir)/m4/nut_check_cppcheck.m4 \
$(top_srcdir)/m4/nut_check_headers_windows.m4 \
$(top_srcdir)/m4/nut_check_libavahi.m4 \
$(top_srcdir)/m4/nut_check_libfreeipmi.m4 \
$(top_srcdir)/m4/nut_check_libgd.m4 \
$(top_srcdir)/m4/nut_check_libltdl.m4 \
$(top_srcdir)/m4/nut_check_libmodbus.m4 \
$(top_srcdir)/m4/nut_check_libneon.m4 \
$(top_srcdir)/m4/nut_check_libnetsnmp.m4 \
$(top_srcdir)/m4/nut_check_libnss.m4 \
@ -109,11 +124,17 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/ax_compare_version.m4 \
$(top_srcdir)/m4/nut_check_libusb.m4 \
$(top_srcdir)/m4/nut_check_libwrap.m4 \
$(top_srcdir)/m4/nut_check_os.m4 \
$(top_srcdir)/m4/nut_check_pkgconfig.m4 \
$(top_srcdir)/m4/nut_check_python.m4 \
$(top_srcdir)/m4/nut_compiler_family.m4 \
$(top_srcdir)/m4/nut_func_getnameinfo_argtypes.m4 \
$(top_srcdir)/m4/nut_report_feature.m4 \
$(top_srcdir)/m4/nut_stash_warnings.m4 \
$(top_srcdir)/m4/nut_type_socklen_t.m4 \
$(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4)
DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
mkinstalldirs = $(install_sh) -d
CONFIG_HEADER = $(top_builddir)/include/config.h
CONFIG_CLEAN_FILES =
@ -126,8 +147,8 @@ sockdebug_LDADD = $(LDADD)
am__DEPENDENCIES_1 =
@WITH_WRAP_TRUE@am__DEPENDENCIES_2 = $(am__DEPENDENCIES_1)
@WITH_SSL_TRUE@am__DEPENDENCIES_3 = $(am__DEPENDENCIES_1)
sockdebug_DEPENDENCIES = ../common/libcommon.la \
../common/libparseconf.la $(am__DEPENDENCIES_1) \
sockdebug_DEPENDENCIES = $(top_builddir)/common/libcommon.la \
$(top_builddir)/common/libparseconf.la $(am__DEPENDENCIES_1) \
$(am__DEPENDENCIES_2) $(am__DEPENDENCIES_3)
AM_V_lt = $(am__v_lt_@AM_V@)
am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
@ -139,9 +160,9 @@ am_upsd_OBJECTS = upsd.$(OBJEXT) user.$(OBJEXT) conf.$(OBJEXT) \
netuser.$(OBJEXT) netset.$(OBJEXT) netinstcmd.$(OBJEXT)
upsd_OBJECTS = $(am_upsd_OBJECTS)
upsd_LDADD = $(LDADD)
upsd_DEPENDENCIES = ../common/libcommon.la ../common/libparseconf.la \
$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_2) \
$(am__DEPENDENCIES_3)
upsd_DEPENDENCIES = $(top_builddir)/common/libcommon.la \
$(top_builddir)/common/libparseconf.la $(am__DEPENDENCIES_1) \
$(am__DEPENDENCIES_2) $(am__DEPENDENCIES_3)
AM_V_P = $(am__v_P_@AM_V@)
am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
am__v_P_0 = false
@ -156,7 +177,13 @@ am__v_at_0 = @
am__v_at_1 =
DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/include
depcomp = $(SHELL) $(top_srcdir)/depcomp
am__depfiles_maybe = depfiles
am__maybe_remake_depfiles = depfiles
am__depfiles_remade = ./$(DEPDIR)/conf.Po ./$(DEPDIR)/desc.Po \
./$(DEPDIR)/netget.Po ./$(DEPDIR)/netinstcmd.Po \
./$(DEPDIR)/netlist.Po ./$(DEPDIR)/netmisc.Po \
./$(DEPDIR)/netset.Po ./$(DEPDIR)/netssl.Po \
./$(DEPDIR)/netuser.Po ./$(DEPDIR)/sockdebug.Po \
./$(DEPDIR)/sstate.Po ./$(DEPDIR)/upsd.Po ./$(DEPDIR)/user.Po
am__mv = mv -f
COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
@ -202,6 +229,7 @@ am__define_uniq_tagged_files = \
done | $(am__uniquify_input)`
ETAGS = etags
CTAGS = ctags
am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
A2X = @A2X@
ACLOCAL = @ACLOCAL@
@ -210,6 +238,7 @@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
AR = @AR@
ASCIIDOC = @ASCIIDOC@
ASPELL = @ASPELL@
AUGPARSE = @AUGPARSE@
AUTOCONF = @AUTOCONF@
AUTOHEADER = @AUTOHEADER@
AUTOMAKE = @AUTOMAKE@
@ -220,6 +249,7 @@ CCDEPMODE = @CCDEPMODE@
CFLAGS = @CFLAGS@
CONFPATH = @CONFPATH@
CPP = @CPP@
CPPCHECK = @CPPCHECK@
CPPFLAGS = @CPPFLAGS@
CPPUNIT_CFLAGS = @CPPUNIT_CFLAGS@
CPPUNIT_LIBS = @CPPUNIT_LIBS@
@ -233,6 +263,7 @@ DEFS = @DEFS@
DEPDIR = @DEPDIR@
DLLTOOL = @DLLTOOL@
DOC_BUILD_LIST = @DOC_BUILD_LIST@
DOC_CHECK_LIST = @DOC_CHECK_LIST@
DRIVER_BUILD_LIST = @DRIVER_BUILD_LIST@
DRIVER_INSTALL_TARGET = @DRIVER_INSTALL_TARGET@
DRIVER_MAN_LIST = @DRIVER_MAN_LIST@
@ -245,6 +276,7 @@ ECHO_T = @ECHO_T@
EGREP = @EGREP@
EXEEXT = @EXEEXT@
FGREP = @FGREP@
GDLIB_CONFIG = @GDLIB_CONFIG@
GREP = @GREP@
INSTALL = @INSTALL@
INSTALL_DATA = @INSTALL_DATA@
@ -262,6 +294,8 @@ LIBIPMI_CFLAGS = @LIBIPMI_CFLAGS@
LIBIPMI_LIBS = @LIBIPMI_LIBS@
LIBLTDL_CFLAGS = @LIBLTDL_CFLAGS@
LIBLTDL_LIBS = @LIBLTDL_LIBS@
LIBMODBUS_CFLAGS = @LIBMODBUS_CFLAGS@
LIBMODBUS_LIBS = @LIBMODBUS_LIBS@
LIBNEON_CFLAGS = @LIBNEON_CFLAGS@
LIBNEON_LIBS = @LIBNEON_LIBS@
LIBNETSNMP_CFLAGS = @LIBNETSNMP_CFLAGS@
@ -272,21 +306,29 @@ LIBPOWERMAN_LIBS = @LIBPOWERMAN_LIBS@
LIBS = @LIBS@
LIBSSL_CFLAGS = @LIBSSL_CFLAGS@
LIBSSL_LIBS = @LIBSSL_LIBS@
LIBSSL_REQUIRES = @LIBSSL_REQUIRES@
LIBTOOL = @LIBTOOL@
LIBTOOL_DEPS = @LIBTOOL_DEPS@
LIBUSB_CFLAGS = @LIBUSB_CFLAGS@
LIBUSB_CONFIG = @LIBUSB_CONFIG@
LIBUSB_LIBS = @LIBUSB_LIBS@
LIBWRAP_CFLAGS = @LIBWRAP_CFLAGS@
LIBWRAP_LIBS = @LIBWRAP_LIBS@
LIPO = @LIPO@
LN_S = @LN_S@
LN_S_R = @LN_S_R@
LTLIBOBJS = @LTLIBOBJS@
LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
MAINT = @MAINT@
MAKEINFO = @MAKEINFO@
MANIFEST_TOOL = @MANIFEST_TOOL@
MKDIR_P = @MKDIR_P@
NETLIBS = @NETLIBS@
NET_SNMP_CONFIG = @NET_SNMP_CONFIG@
NM = @NM@
NMEDIT = @NMEDIT@
NUT_DATADIR = @NUT_DATADIR@
NUT_LIBEXECDIR = @NUT_LIBEXECDIR@
NUT_NETVERSION = @NUT_NETVERSION@
OBJDUMP = @OBJDUMP@
OBJEXT = @OBJEXT@
@ -306,6 +348,9 @@ PKG_CONFIG = @PKG_CONFIG@
PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
PORT = @PORT@
PYTHON = @PYTHON@
PYTHON2 = @PYTHON2@
PYTHON3 = @PYTHON3@
RANLIB = @RANLIB@
RUN_AS_GROUP = @RUN_AS_GROUP@
RUN_AS_USER = @RUN_AS_USER@
@ -319,6 +364,7 @@ STATEPATH = @STATEPATH@
STRIP = @STRIP@
SUN_LIBUSB = @SUN_LIBUSB@
TREE_VERSION = @TREE_VERSION@
VALGRIND = @VALGRIND@
VERSION = @VERSION@
WORDS_BIGENDIAN = @WORDS_BIGENDIAN@
XMLLINT = @XMLLINT@
@ -336,6 +382,7 @@ am__leading_dot = @am__leading_dot@
am__quote = @am__quote@
am__tar = @am__tar@
am__untar = @am__untar@
auglensdir = @auglensdir@
bindir = @bindir@
build = @build@
build_alias = @build_alias@
@ -349,6 +396,9 @@ datarootdir = @datarootdir@
devddir = @devddir@
docdir = @docdir@
driverexecdir = @driverexecdir@
dummy_PKG_CONFIG = @dummy_PKG_CONFIG@
dummy_PKG_CONFIG_CFLAGS = @dummy_PKG_CONFIG_CFLAGS@
dummy_PKG_CONFIG_LIBS = @dummy_PKG_CONFIG_LIBS@
dvidir = @dvidir@
exec_prefix = @exec_prefix@
host = @host@
@ -374,12 +424,14 @@ pkgconfigdir = @pkgconfigdir@
prefix = @prefix@
program_transform_name = @program_transform_name@
psdir = @psdir@
runstatedir = @runstatedir@
sbindir = @sbindir@
sharedstatedir = @sharedstatedir@
srcdir = @srcdir@
sysconfdir = @sysconfdir@
systemdsystemshutdowndir = @systemdsystemshutdowndir@
systemdshutdowndir = @systemdshutdowndir@
systemdsystemunitdir = @systemdsystemunitdir@
systemdtmpfilesdir = @systemdtmpfilesdir@
target = @target@
target_alias = @target_alias@
target_cpu = @target_cpu@
@ -394,7 +446,8 @@ udevdir = @udevdir@
# files. In any case, CFLAGS are only -I options, so there is no harm,
# but only add them if we really use the target.
AM_CFLAGS = -I$(top_srcdir)/include $(am__append_1) $(am__append_2)
LDADD = ../common/libcommon.la ../common/libparseconf.la $(NETLIBS) \
LDADD = $(top_builddir)/common/libcommon.la \
$(top_builddir)/common/libparseconf.la $(NETLIBS) \
$(am__append_3) $(am__append_4)
upsd_SOURCES = upsd.c user.c conf.c netssl.c sstate.c desc.c \
netget.c netmisc.c netlist.c netuser.c netset.c netinstcmd.c \
@ -403,6 +456,7 @@ upsd_SOURCES = upsd.c user.c conf.c netssl.c sstate.c desc.c \
upstype.h user-data.h user.h
sockdebug_SOURCES = sockdebug.c
MAINTAINERCLEANFILES = Makefile.in .dirstamp
all: all-am
.SUFFIXES:
@ -419,14 +473,13 @@ $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__confi
echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu server/Makefile'; \
$(am__cd) $(top_srcdir) && \
$(AUTOMAKE) --gnu server/Makefile
.PRECIOUS: Makefile
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
@case '$?' in \
*config.status*) \
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
*) \
echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
esac;
$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
@ -501,19 +554,25 @@ mostlyclean-compile:
distclean-compile:
-rm -f *.tab.c
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/conf.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/desc.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/netget.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/netinstcmd.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/netlist.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/netmisc.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/netset.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/netssl.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/netuser.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sockdebug.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sstate.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/upsd.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/user.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/conf.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/desc.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/netget.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/netinstcmd.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/netlist.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/netmisc.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/netset.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/netssl.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/netuser.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sockdebug.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sstate.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/upsd.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/user.Po@am__quote@ # am--include-marker
$(am__depfiles_remade):
@$(MKDIR_P) $(@D)
@echo '# dummy' >$@-t && $(am__mv) $@-t $@
am--depfiles: $(am__depfiles_remade)
.c.o:
@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\
@ -597,7 +656,10 @@ cscopelist-am: $(am__tagged_files)
distclean-tags:
-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
distdir: $(DISTFILES)
distdir: $(BUILT_SOURCES)
$(MAKE) $(AM_MAKEFLAGS) distdir-am
distdir-am: $(DISTFILES)
@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
list='$(DISTFILES)'; \
@ -664,13 +726,26 @@ distclean-generic:
maintainer-clean-generic:
@echo "This command is intended for maintainers to use"
@echo "it deletes files that may require special tools to rebuild."
-test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
clean: clean-am
clean-am: clean-generic clean-libtool clean-sbinPROGRAMS \
mostlyclean-am
distclean: distclean-am
-rm -rf ./$(DEPDIR)
-rm -f ./$(DEPDIR)/conf.Po
-rm -f ./$(DEPDIR)/desc.Po
-rm -f ./$(DEPDIR)/netget.Po
-rm -f ./$(DEPDIR)/netinstcmd.Po
-rm -f ./$(DEPDIR)/netlist.Po
-rm -f ./$(DEPDIR)/netmisc.Po
-rm -f ./$(DEPDIR)/netset.Po
-rm -f ./$(DEPDIR)/netssl.Po
-rm -f ./$(DEPDIR)/netuser.Po
-rm -f ./$(DEPDIR)/sockdebug.Po
-rm -f ./$(DEPDIR)/sstate.Po
-rm -f ./$(DEPDIR)/upsd.Po
-rm -f ./$(DEPDIR)/user.Po
-rm -f Makefile
distclean-am: clean-am distclean-compile distclean-generic \
distclean-tags
@ -716,7 +791,19 @@ install-ps-am:
installcheck-am:
maintainer-clean: maintainer-clean-am
-rm -rf ./$(DEPDIR)
-rm -f ./$(DEPDIR)/conf.Po
-rm -f ./$(DEPDIR)/desc.Po
-rm -f ./$(DEPDIR)/netget.Po
-rm -f ./$(DEPDIR)/netinstcmd.Po
-rm -f ./$(DEPDIR)/netlist.Po
-rm -f ./$(DEPDIR)/netmisc.Po
-rm -f ./$(DEPDIR)/netset.Po
-rm -f ./$(DEPDIR)/netssl.Po
-rm -f ./$(DEPDIR)/netuser.Po
-rm -f ./$(DEPDIR)/sockdebug.Po
-rm -f ./$(DEPDIR)/sstate.Po
-rm -f ./$(DEPDIR)/upsd.Po
-rm -f ./$(DEPDIR)/user.Po
-rm -f Makefile
maintainer-clean-am: distclean-am maintainer-clean-generic
@ -737,9 +824,9 @@ uninstall-am: uninstall-sbinPROGRAMS
.MAKE: install-am install-strip
.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \
clean-libtool clean-sbinPROGRAMS cscopelist-am ctags ctags-am \
distclean distclean-compile distclean-generic \
.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \
clean-generic clean-libtool clean-sbinPROGRAMS cscopelist-am \
ctags ctags-am distclean distclean-compile distclean-generic \
distclean-libtool distclean-tags distdir dvi dvi-am html \
html-am info info-am install install-am install-data \
install-data-am install-dvi install-dvi-am install-exec \
@ -751,6 +838,20 @@ uninstall-am: uninstall-sbinPROGRAMS
mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
tags tags-am uninstall uninstall-am uninstall-sbinPROGRAMS
.PRECIOUS: Makefile
# Make sure out-of-dir dependencies exist (especially when dev-building parts):
$(top_builddir)/common/libcommon.la \
$(top_builddir)/common/libparseconf.la: dummy
@cd $(@D) && $(MAKE) $(AM_MAKEFLAGS) $(@F)
dummy:
# NOTE: Do not clean ".deps" in SUBDIRS of the main project,
# the root Makefile.am takes care of that!
#clean-local:
# rm -rf $(builddir)/.deps
# Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.

View file

@ -23,9 +23,19 @@
#include "sstate.h"
#include "user.h"
#include "netssl.h"
#include "nut_stdint.h"
#include <ctype.h>
ups_t *upstable = NULL;
int num_ups = 0;
static ups_t *upstable = NULL;
int num_ups = 0;
/* Users can pass a -D[...] option to enable debugging.
* For the service tracing purposes, also the upsd.conf
* can define a debug_min value in the global section,
* to set the minimal debug level (CLI provided value less
* than that would not have effect, can only have more).
*/
int nut_debug_level_global = -1;
/* add another UPS for monitoring from ups.conf */
static void ups_create(const char *fn, const char *name, const char *desc)
@ -110,25 +120,91 @@ static void ups_update(const char *fn, const char *name, const char *desc)
/* always set this on reload */
temp->retain = 1;
}
}
/* returns 1 if "arg" was usable as a boolean value, 0 if not
* saves converted meaning of "arg" into referenced "result"
*/
static int parse_boolean(char *arg, int *result)
{
if ( (!strcasecmp(arg, "true")) || (!strcasecmp(arg, "on")) || (!strcasecmp(arg, "yes")) || (!strcasecmp(arg, "1"))) {
*result = 1;
return 1;
}
if ( (!strcasecmp(arg, "false")) || (!strcasecmp(arg, "off")) || (!strcasecmp(arg, "no")) || (!strcasecmp(arg, "0"))) {
*result = 0;
return 1;
}
return 0;
}
/* return 1 if usable, 0 if not */
static int parse_upsd_conf_args(int numargs, char **arg)
static int parse_upsd_conf_args(size_t numargs, char **arg)
{
/* everything below here uses up through arg[1] */
if (numargs < 2)
return 0;
/* DEBUG_MIN (NUM) */
/* debug_min (NUM) also acceptable, to be on par with ups.conf */
if (!strcasecmp(arg[0], "DEBUG_MIN")) {
int lvl = -1; // typeof common/common.c: int nut_debug_level
if ( str_to_int (arg[1], &lvl, 10) && lvl >= 0 ) {
nut_debug_level_global = lvl;
} else {
upslogx(LOG_INFO, "DEBUG_MIN has non numeric or negative value in upsd.conf");
}
return 1;
}
/* MAXAGE <seconds> */
if (!strcmp(arg[0], "MAXAGE")) {
maxage = atoi(arg[1]);
return 1;
if (isdigit((size_t)arg[1][0])) {
maxage = atoi(arg[1]);
return 1;
}
else {
upslogx(LOG_ERR, "MAXAGE has non numeric value (%s)!", arg[1]);
return 0;
}
}
/* TRACKINGDELAY <seconds> */
if (!strcmp(arg[0], "TRACKINGDELAY")) {
if (isdigit((size_t)arg[1][0])) {
tracking_delay = atoi(arg[1]);
return 1;
}
else {
upslogx(LOG_ERR, "TRACKINGDELAY has non numeric value (%s)!", arg[1]);
return 0;
}
}
/* ALLOW_NO_DEVICE <seconds> */
if (!strcmp(arg[0], "ALLOW_NO_DEVICE")) {
if (isdigit((size_t)arg[1][0])) {
allow_no_device = (atoi(arg[1]) != 0); /* non-zero arg is true here */
return 1;
}
if (parse_boolean(arg[1], &allow_no_device))
return 1;
upslogx(LOG_ERR, "ALLOW_NO_DEVICE has non numeric and non boolean value (%s)!", arg[1]);
return 0;
}
/* MAXCONN <connections> */
if (!strcmp(arg[0], "MAXCONN")) {
maxconn = atoi(arg[1]);
return 1;
if (isdigit((size_t)arg[1][0])) {
/* FIXME: Check for overflows (and int size of nfds_t vs. long) - see get_max_pid_t() for example */
maxconn = (nfds_t)atol(arg[1]);
return 1;
}
else {
upslogx(LOG_ERR, "MAXCONN has non numeric value (%s)!", arg[1]);
return 0;
}
}
/* STATEPATH <dir> */
@ -162,12 +238,29 @@ static int parse_upsd_conf_args(int numargs, char **arg)
#ifdef WITH_CLIENT_CERTIFICATE_VALIDATION
/* CERTREQUEST (0 | 1 | 2) */
if (!strcmp(arg[0], "CERTREQUEST")) {
certrequest = atoi(arg[1]);
return 1;
if (isdigit((size_t)arg[1][0])) {
certrequest = atoi(arg[1]);
return 1;
}
else {
upslogx(LOG_ERR, "CERTREQUEST has non numeric value (%s)!", arg[1]);
return 0;
}
}
#endif /* WITH_CLIENT_CERTIFICATE_VALIDATION */
#endif /* WITH_OPENSSL | WITH_NSS */
#if defined(WITH_OPENSSL) || defined(WITH_NSS)
/* DISABLE_WEAK_SSL <bool> */
if (!strcmp(arg[0], "DISABLE_WEAK_SSL")) {
if (parse_boolean(arg[1], &disable_weak_ssl))
return 1;
upslogx(LOG_ERR, "DISABLE_WEAK_SSL has non boolean value (%s)!", arg[1]);
return 0;
}
#endif /* WITH_OPENSSL | WITH_NSS */
/* ACCEPT <aclname> [<aclname>...] */
if (!strcmp(arg[0], "ACCEPT")) {
upslogx(LOG_WARNING, "ACCEPT in upsd.conf is no longer supported - switch to LISTEN");
@ -198,7 +291,7 @@ static int parse_upsd_conf_args(int numargs, char **arg)
upslogx(LOG_WARNING, "ACL in upsd.conf is no longer supported - switch to LISTEN");
return 1;
}
#ifdef WITH_NSS
/* CERTIDENT <name> <passwd> */
if (!strcmp(arg[0], "CERTIDENT")) {
@ -241,6 +334,13 @@ void load_upsdconf(int reloading)
return;
}
if (reloading) {
/* if upsd.conf added or changed
* (or commented away) the debug_min
* setting, detect that */
nut_debug_level_global = -1;
}
while (pconf_file_next(&ctx)) {
if (pconf_parse_error(&ctx)) {
upslogx(LOG_ERR, "Parse error: %s:%d: %s",
@ -255,11 +355,11 @@ void load_upsdconf(int reloading)
unsigned int i;
char errmsg[SMALLBUF];
snprintf(errmsg, sizeof(errmsg),
snprintf(errmsg, sizeof(errmsg),
"upsd.conf: invalid directive");
for (i = 0; i < ctx.numargs; i++)
snprintfcat(errmsg, sizeof(errmsg), " %s",
snprintfcat(errmsg, sizeof(errmsg), " %s",
ctx.arglist[i]);
upslogx(LOG_WARNING, "%s", errmsg);
@ -267,7 +367,16 @@ void load_upsdconf(int reloading)
}
pconf_finish(&ctx);
if (reloading) {
if (nut_debug_level_global > -1) {
upslogx(LOG_INFO,
"Applying debug_min=%d from upsd.conf",
nut_debug_level_global);
nut_debug_level = nut_debug_level_global;
}
}
pconf_finish(&ctx);
}
/* callback during parsing of ups.conf */
@ -331,7 +440,7 @@ void upsconf_add(int reloading)
/* don't accept an entry that's missing items */
if ((!tmp->driver) || (!tmp->port)) {
upslogx(LOG_WARNING, "Warning: ignoring incomplete configuration for UPS [%s]\n",
upslogx(LOG_WARNING, "Warning: ignoring incomplete configuration for UPS [%s]\n",
tmp->upsname);
} else {
snprintf(statefn, sizeof(statefn), "%s-%s",
@ -404,7 +513,7 @@ static void delete_ups(upstype_t *target)
/* shouldn't happen */
upslogx(LOG_ERR, "delete_ups: UPS not found");
}
}
/* see if we can open a file */
static int check_file(const char *fn)

View file

@ -3,6 +3,7 @@
Copyright (C)
2001 Russell Kroll <rkroll@exploits.org>
2008 Arjen de Korte <adkorte-guest@alioth.debian.org>
2020 Jim Klimov <jimklimov@gmail.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -19,6 +20,9 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef NUT_CONF_H_SEEN
#define NUT_CONF_H_SEEN 1
#ifdef __cplusplus
/* *INDENT-OFF* */
extern "C" {
@ -47,6 +51,7 @@ void delete_acls(void);
void delete_access(void);
extern int num_ups;
extern int nut_debug_level_global;
#ifdef __cplusplus
/* *INDENT-OFF* */
@ -54,3 +59,4 @@ extern int num_ups;
/* *INDENT-ON* */
#endif
#endif /* NUT_CONF_H_SEEN */

View file

@ -17,6 +17,8 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "config.h" /* must be the first header */
#include <string.h>
#include "common.h"

View file

@ -1,3 +1,28 @@
/* desc.h - variable/command description handling for upsd
Copyright (C)
2003 Russell Kroll <rkroll@exploits.org>
2005 Arnaud Quette <arnaud.quette@free.fr>
2013 Emilien Kia <kiae.dev@gmail.com>
2020 Jim Klimov <jimklimov@gmail.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef NUT_DESC_H_SEEN
#define NUT_DESC_H_SEEN 1
#ifdef __cplusplus
/* *INDENT-OFF* */
@ -16,3 +41,4 @@ const char *desc_get_var(const char *name);
/* *INDENT-ON* */
#endif
#endif /* NUT_DESC_H_SEEN */

View file

@ -1,6 +1,11 @@
/* netcmds.h - upsd support structure details
Copyright (C) 2001 Russell Kroll <rkroll@exploits.org>
2005 Arnaud Quette <arnaud.quette@free.fr>
2007 Peter Selinger <selinger@users.sourceforge.net>
2010 Arjen de Korte <adkorte-guest@alioth.debian.org>
2012 Emilien Kia <kiae.dev@gmail.com>
2020 Jim Klimov <jimklimov@gmail.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -17,6 +22,9 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef NUT_NETCMDS_H_SEEN
#define NUT_NETCMDS_H_SEEN 1
#include "nut_ctype.h"
#include "netssl.h"
@ -35,13 +43,14 @@ extern "C" {
/* *INDENT-ON* */
#endif
struct {
static struct {
const char *name;
void (*func)(nut_ctype_t *client, int numargs, const char **arg);
void (*func)(nut_ctype_t *client, size_t numargs, const char **arg);
int flags;
} netcmds[] = {
{ "VER", net_ver, 0 },
{ "NETVER", net_netver, 0 },
{ "PROTVER", net_netver, 0 }, /* aliased since NUT 2.8.0 */
{ "HELP", net_help, 0 },
{ "STARTTLS", net_starttls, 0 },
@ -53,6 +62,10 @@ struct {
{ "LOGIN", net_login, FLAG_USER },
{ "LOGOUT", net_logout, 0 },
/* NOTE: Protocol in NUT 2.8.0 allows to handle
* master/primary to rename/alias the routine.
*/
{ "PRIMARY", net_primary, FLAG_USER },
{ "MASTER", net_master, FLAG_USER },
{ "FSD", net_fsd, FLAG_USER },
@ -60,7 +73,7 @@ struct {
{ "SET", net_set, FLAG_USER },
{ "INSTCMD", net_instcmd, FLAG_USER },
{ NULL, (void(*)())(NULL), 0 }
{ NULL, (void(*)(struct nut_ctype_s *, size_t, const char **))(NULL), 0 }
};
#ifdef __cplusplus
@ -69,3 +82,4 @@ struct {
/* *INDENT-ON* */
#endif
#endif /* NUT_NETCMDS_H_SEEN */

View file

@ -1,3 +1,35 @@
/* neterr.h - network error definitions for NUT
Copyright (C)
2003 Russell Kroll <rkroll@exploits.org>
2005 Arnaud Quette <arnaud.quette@free.fr>
2013 Emilien Kia <kiae.dev@gmail.com>
2020 Jim Klimov <jimklimov@gmail.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef NUT_NETERR_H_SEEN
#define NUT_NETERR_H_SEEN 1
#ifdef __cplusplus
/* *INDENT-OFF* */
extern "C" {
/* *INDENT-ON* */
#endif
/* network error definitions for consistency */
#define NUT_ERR_ACCESS_DENIED "ACCESS-DENIED"
@ -33,3 +65,11 @@
#define NUT_ERR_UNKNOWN_INSTCMD "UNKNOWN-INSTCMD"
#define NUT_ERR_MISSING_ARGUMENT "MISSING-ARGUMENT"
#define NUT_ERR_INVALID_VALUE "INVALID-VALUE"
#ifdef __cplusplus
/* *INDENT-OFF* */
}
/* *INDENT-ON* */
#endif
#endif /* NUT_NETERR_H_SEEN */

View file

@ -109,7 +109,7 @@ static void get_cmddesc(nut_ctype_t *client, const char *upsname, const char *cm
if (desc)
sendback(client, "CMDDESC %s %s \"%s\"\n", upsname, cmd, desc);
else
sendback(client, "CMDDESC %s %s \"Description unavailable\"\n",
sendback(client, "CMDDESC %s %s \"Description unavailable\"\n",
upsname, cmd);
}
@ -142,38 +142,36 @@ static void get_type(nut_ctype_t *client, const char *upsname, const char *var)
snprintfcat(buf, sizeof(buf), " RW");
if (node->enum_list) {
sendback(client, "%s ENUM\n", buf);
return;
snprintfcat(buf, sizeof(buf), " ENUM");
}
if (node->range_list) {
sendback(client, "%s RANGE\n", buf);
return;
snprintfcat(buf, sizeof(buf), " RANGE");
}
if (node->flags & ST_FLAG_STRING) {
sendback(client, "%s STRING:%d\n", buf, node->aux);
sendback(client, "%s STRING:%ld\n", buf, node->aux);
return;
}
/* Any variable that is not string | range | enum is just a simple
* numeric value */
sendback(client, "TYPE %s %s NUMBER\n", upsname, var);
}
sendback(client, "%s NUMBER\n", buf);
}
static void get_var_server(nut_ctype_t *client, const char *upsname, const char *var)
{
if (!strcasecmp(var, "server.info")) {
sendback(client, "VAR %s server.info "
"\"Network UPS Tools upsd %s - "
"http://www.networkupstools.org/\"\n",
"http://www.networkupstools.org/\"\n",
upsname, UPS_VERSION);
return;
}
if (!strcasecmp(var, "server.version")) {
sendback(client, "VAR %s server.version \"%s\"\n",
sendback(client, "VAR %s server.version \"%s\"\n",
upsname, UPS_VERSION);
return;
}
@ -216,8 +214,27 @@ static void get_var(nut_ctype_t *client, const char *upsname, const char *var)
sendback(client, "VAR %s %s \"%s\"\n", upsname, var, val);
}
void net_get(nut_ctype_t *client, int numarg, const char **arg)
void net_get(nut_ctype_t *client, size_t numarg, const char **arg)
{
if (numarg < 1) {
send_err(client, NUT_ERR_INVALID_ARGUMENT);
return;
}
/* GET TRACKING [ID] */
if (!strcasecmp(arg[0], "TRACKING")) {
if (numarg < 2) {
sendback(client, "%s\n", (client->tracking) ? "ON" : "OFF");
}
else {
if (client->tracking)
sendback(client, "%s\n", tracking_get(arg[1]));
else
send_err(client, NUT_ERR_FEATURE_NOT_CONFIGURED);
}
return;
}
if (numarg < 2) {
send_err(client, NUT_ERR_INVALID_ARGUMENT);
return;

View file

@ -1,10 +1,37 @@
/* netget.h - GET handlers for upsd
Copyright (C)
2003 Russell Kroll <rkroll@exploits.org>
2005 Arnaud Quette <arnaud.quette@free.fr>
2007 Peter Selinger <selinger@users.sourceforge.net>
2013 Emilien Kia <kiae.dev@gmail.com>
2020 Jim Klimov <jimklimov@gmail.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef NUT_NETGET_H_SEEN
#define NUT_NETGET_H_SEEN 1
#ifdef __cplusplus
/* *INDENT-OFF* */
extern "C" {
/* *INDENT-ON* */
#endif
void net_get(nut_ctype_t *client, int numarg, const char **arg);
void net_get(nut_ctype_t *client, size_t numarg, const char **arg);
#ifdef __cplusplus
/* *INDENT-OFF* */
@ -12,3 +39,4 @@ void net_get(nut_ctype_t *client, int numarg, const char **arg);
/* *INDENT-ON* */
#endif
#endif /* NUT_NETGET_H_SEEN */

View file

@ -28,10 +28,10 @@
#include "netinstcmd.h"
static void send_instcmd(nut_ctype_t *client, const char *upsname,
const char *cmdname, const char *value)
static void send_instcmd(nut_ctype_t *client, const char *upsname,
const char *cmdname, const char *value, const char *tracking_id)
{
int found;
int found, have_tracking_id = 0;
upstype_t *ups;
const cmdlist_t *ctmp;
char sockcmd[SMALLBUF], esc[SMALLBUF];
@ -70,20 +70,30 @@ static void send_instcmd(nut_ctype_t *client, const char *upsname,
return;
}
/* Format the base command */
snprintf(sockcmd, sizeof(sockcmd), "INSTCMD %s", cmdname);
/* see if the user has also passed a value for this command */
if (value != NULL) {
upslogx(LOG_INFO, "Instant command: %s@%s did %s with value \"%s\" on %s",
client->username, client->addr, cmdname, value, ups->name);
if (value != NULL)
snprintfcat(sockcmd, sizeof(sockcmd), " %s", pconf_encode(value, esc, sizeof(esc)));
snprintf(sockcmd, sizeof(sockcmd), "INSTCMD %s %s\n",
cmdname, pconf_encode(value, esc, sizeof(esc)));
/* see if the user want execution tracking for this command */
if (tracking_id && *tracking_id) {
snprintfcat(sockcmd, sizeof(sockcmd), " TRACKING %s", tracking_id);
/* Add an entry in the tracking structure */
tracking_add(tracking_id);
have_tracking_id = 1;
}
else {
upslogx(LOG_INFO, "Instant command: %s@%s did %s on %s",
client->username, client->addr, cmdname, ups->name);
snprintf(sockcmd, sizeof(sockcmd), "INSTCMD %s\n", cmdname);
}
/* add EOL */
snprintfcat(sockcmd, sizeof(sockcmd), "\n");
upslogx(LOG_INFO, "Instant command: %s@%s did %s%s%s on %s (tracking ID: %s)",
client->username, client->addr, cmdname,
(value != NULL)?" with value ":"",
(value != NULL)?value:"",
ups->name,
(have_tracking_id) ? tracking_id : "disabled");
if (!sstate_sendline(ups, sockcmd)) {
upslogx(LOG_INFO, "Set command send failed");
@ -91,18 +101,38 @@ static void send_instcmd(nut_ctype_t *client, const char *upsname,
return;
}
/* FIXME: need to retrieve the cookie number */
sendback(client, "OK\n");
/* return the result, possibly including tracking_id */
if (have_tracking_id)
sendback(client, "OK TRACKING %s\n", tracking_id);
else
sendback(client, "OK\n");
}
void net_instcmd(nut_ctype_t *client, int numarg, const char **arg)
void net_instcmd(nut_ctype_t *client, size_t numarg, const char **arg)
{
const char *devname = NULL;
const char *cmdname = NULL;
const char *cmdparam = NULL;
char tracking_id[UUID4_LEN] = "";
if (numarg < 2) {
send_err(client, NUT_ERR_INVALID_ARGUMENT);
return;
}
/* INSTCMD <ups> <cmdname> [<extra>]*/
send_instcmd(client, arg[0], arg[1], (numarg == 3)?arg[2]:NULL);
/* INSTCMD <ups> <cmdname> [cmdparam] */
/* Check arguments */
devname = arg[0];
cmdname = arg[1];
if (numarg == 3)
cmdparam = arg[2];
if (client->tracking) {
/* Generate a tracking ID, if client requested status tracking */
nut_uuid_v4(tracking_id);
}
send_instcmd(client, devname, cmdname, cmdparam, tracking_id);
return;
}

View file

@ -1,10 +1,37 @@
/* netinstcmd.h - network instand command definitions for NUT
Copyright (C)
2003 Russell Kroll <rkroll@exploits.org>
2005 Arnaud Quette <arnaud.quette@free.fr>
2007 Peter Selinger <selinger@users.sourceforge.net>
2013 Emilien Kia <kiae.dev@gmail.com>
2020 Jim Klimov <jimklimov@gmail.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef NUT_NETINSTCMD_H_SEEN
#define NUT_NETINSTCMD_H_SEEN 1
#ifdef __cplusplus
/* *INDENT-OFF* */
extern "C" {
/* *INDENT-ON* */
#endif
void net_instcmd(nut_ctype_t *client, int numarg, const char **arg);
void net_instcmd(nut_ctype_t *client, size_t numarg, const char **arg);
#ifdef __cplusplus
/* *INDENT-OFF* */
@ -12,3 +39,4 @@ void net_instcmd(nut_ctype_t *client, int numarg, const char **arg);
/* *INDENT-ON* */
#endif
#endif /* NUT_NETINSTCMD_H_SEEN */

View file

@ -52,7 +52,7 @@ static int tree_dump(st_tree_t *node, nut_ctype_t *client, const char *ups,
if (node->flags & ST_FLAG_RW) {
ret = sendback(client, "RW %s %s \"%s\"\n",
ups, node->var, node->val);
} else {
ret = 1; /* dummy */
}
@ -240,7 +240,7 @@ static void list_ups(nut_ctype_t *client)
pconf_encode(utmp->desc, esc, sizeof(esc));
ret = sendback(client, "UPS %s \"%s\"\n",
utmp->name, esc);
} else {
ret = sendback(client, "UPS %s \"Description unavailable\"\n",
utmp->name);
@ -253,7 +253,7 @@ static void list_ups(nut_ctype_t *client)
}
sendback(client, "END LIST UPS\n");
}
}
static void list_clients(nut_ctype_t *client, const char *upsname)
{
@ -285,7 +285,7 @@ static void list_clients(nut_ctype_t *client, const char *upsname)
sendback(client, "END LIST CLIENT %s\n", upsname);
}
void net_list(nut_ctype_t *client, int numarg, const char **arg)
void net_list(nut_ctype_t *client, size_t numarg, const char **arg)
{
if (numarg < 1) {
send_err(client, NUT_ERR_INVALID_ARGUMENT);

View file

@ -1,10 +1,37 @@
/* netlist.h - LIST handlers for upsd
Copyright (C)
2003 Russell Kroll <rkroll@exploits.org>
2005 Arnaud Quette <arnaud.quette@free.fr>
2007 Peter Selinger <selinger@users.sourceforge.net>
2013 Emilien Kia <kiae.dev@gmail.com>
2020 Jim Klimov <jimklimov@gmail.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef NUT_NETLIST_H_SEEN
#define NUT_NETLIST_H_SEEN 1
#ifdef __cplusplus
/* *INDENT-OFF* */
extern "C" {
/* *INDENT-ON* */
#endif
void net_list(nut_ctype_t *client, int numarg, const char **arg);
void net_list(nut_ctype_t *client, size_t numarg, const char **arg);
#ifdef __cplusplus
/* *INDENT-OFF* */
@ -12,3 +39,4 @@ void net_list(nut_ctype_t *client, int numarg, const char **arg);
/* *INDENT-ON* */
#endif
#endif /* NUT_NETLIST_H_SEEN */

View file

@ -22,15 +22,16 @@
#include "common.h"
#include "upsd.h"
#include "sstate.h"
#include "sstate.h"
#include "state.h"
#include "user.h" /* for user_checkaction */
#include "neterr.h"
#include "netmisc.h"
void net_ver(nut_ctype_t *client, int numarg, const char **arg)
void net_ver(nut_ctype_t *client, size_t numarg, const char **arg)
{
NUT_UNUSED_VARIABLE(arg);
if (numarg != 0) {
send_err(client, NUT_ERR_INVALID_ARGUMENT);
return;
@ -40,8 +41,9 @@ void net_ver(nut_ctype_t *client, int numarg, const char **arg)
UPS_VERSION);
}
void net_netver(nut_ctype_t *client, int numarg, const char **arg)
void net_netver(nut_ctype_t *client, size_t numarg, const char **arg)
{
NUT_UNUSED_VARIABLE(arg);
if (numarg != 0) {
send_err(client, NUT_ERR_INVALID_ARGUMENT);
return;
@ -50,8 +52,9 @@ void net_netver(nut_ctype_t *client, int numarg, const char **arg)
sendback(client, "%s\n", NUT_NETVERSION);
}
void net_help(nut_ctype_t *client, int numarg, const char **arg)
void net_help(nut_ctype_t *client, size_t numarg, const char **arg)
{
NUT_UNUSED_VARIABLE(arg);
if (numarg != 0) {
send_err(client, NUT_ERR_INVALID_ARGUMENT);
return;
@ -61,7 +64,7 @@ void net_help(nut_ctype_t *client, int numarg, const char **arg)
" USERNAME PASSWORD STARTTLS\n");
}
void net_fsd(nut_ctype_t *client, int numarg, const char **arg)
void net_fsd(nut_ctype_t *client, size_t numarg, const char **arg)
{
upstype_t *ups;
@ -77,13 +80,13 @@ void net_fsd(nut_ctype_t *client, int numarg, const char **arg)
return;
}
/* make sure this user is allowed to do FSD */
/* make sure this user is allowed to do FSD */
if (!user_checkaction(client->username, client->password, "FSD")) {
send_err(client, NUT_ERR_ACCESS_DENIED);
return;
}
upslogx(LOG_INFO, "Client %s@%s set FSD on UPS [%s]",
upslogx(LOG_INFO, "Client %s@%s set FSD on UPS [%s]",
client->username, client->addr, ups->name);
ups->fsd = 1;

View file

@ -1,13 +1,40 @@
/* netmisc.h - miscellaneous network handlers for upsd (VER, HELP, FSD)
Copyright (C)
2003 Russell Kroll <rkroll@exploits.org>
2007 Peter Selinger <selinger@users.sourceforge.net>
2012 Arnaud Quette <arnaud.quette.free.fr>
2013 Emilien Kia <kiae.dev@gmail.com>
2020 Jim Klimov <jimklimov@gmail.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef NUT_NETMISC_H_SEEN
#define NUT_NETMISC_H_SEEN 1
#ifdef __cplusplus
/* *INDENT-OFF* */
extern "C" {
/* *INDENT-ON* */
#endif
void net_ver(nut_ctype_t *client, int numarg, const char **arg);
void net_netver(nut_ctype_t *client, int numarg, const char **arg);
void net_help(nut_ctype_t *client, int numarg, const char **arg);
void net_fsd(nut_ctype_t *client, int numarg, const char **arg);
void net_ver(nut_ctype_t *client, size_t numarg, const char **arg);
void net_netver(nut_ctype_t *client, size_t numarg, const char **arg);
void net_help(nut_ctype_t *client, size_t numarg, const char **arg);
void net_fsd(nut_ctype_t *client, size_t numarg, const char **arg);
#ifdef __cplusplus
/* *INDENT-OFF* */
@ -15,3 +42,4 @@ void net_fsd(nut_ctype_t *client, int numarg, const char **arg);
/* *INDENT-ON* */
#endif
#endif /* NUT_NETMISC_H_SEEN */

View file

@ -28,13 +28,14 @@
#include "netset.h"
static void set_var(nut_ctype_t *client, const char *upsname, const char *var,
const char *newval)
const char *newval, const char *tracking_id)
{
upstype_t *ups;
const char *val;
const enum_t *etmp;
const range_t *rtmp;
char cmd[SMALLBUF], esc[SMALLBUF];
int have_tracking_id = 0;
ups = get_ups_ptr(upsname);
@ -68,7 +69,7 @@ static void set_var(nut_ctype_t *client, const char *upsname, const char *var,
/* see if the new value is allowed for this variable */
if (sstate_getflags(ups, var) & ST_FLAG_STRING) {
int aux;
long aux;
aux = sstate_getaux(ups, var);
@ -81,6 +82,10 @@ static void set_var(nut_ctype_t *client, const char *upsname, const char *var,
return;
}
/* FIXME? Should this cast to "long"?
* An int-size string is quite a lot already,
* even on architectures with a moderate INTMAX
*/
if (aux < (int) strlen(newval)) {
send_err(client, NUT_ERR_TOO_LONG);
return;
@ -134,31 +139,92 @@ static void set_var(nut_ctype_t *client, const char *upsname, const char *var,
/* must be OK now */
upslogx(LOG_INFO, "Set variable: %s@%s set %s on %s to %s",
client->username, client->addr, var, ups->name, newval);
snprintf(cmd, sizeof(cmd), "SET %s \"%s\"\n",
snprintf(cmd, sizeof(cmd), "SET %s \"%s\"",
var, pconf_encode(newval, esc, sizeof(esc)));
/* see if the user want execution tracking for this command */
if (tracking_id && *tracking_id) {
snprintfcat(cmd, sizeof(cmd), " TRACKING %s", tracking_id);
/* Add an entry in the tracking structure */
tracking_add(tracking_id);
have_tracking_id = 1;
}
/* add EOL */
snprintfcat(cmd, sizeof(cmd), "\n");
upslogx(LOG_INFO, "Set variable: %s@%s set %s on %s to %s (tracking ID: %s)",
client->username, client->addr, var, ups->name, newval,
(have_tracking_id) ? tracking_id : "disabled");
if (!sstate_sendline(ups, cmd)) {
upslogx(LOG_INFO, "Set command send failed");
send_err(client, NUT_ERR_SET_FAILED);
return;
}
sendback(client, "OK\n");
/* return the result, possibly including tracking_id */
if (have_tracking_id)
sendback(client, "OK TRACKING %s\n", tracking_id);
else
sendback(client, "OK\n");
}
void net_set(nut_ctype_t *client, int numarg, const char **arg)
void net_set(nut_ctype_t *client, size_t numarg, const char **arg)
{
if (numarg < 4) {
char tracking_id[UUID4_LEN] = "";
/* Base verification, to ensure that we have at least the SET parameter */
if (numarg < 2) {
send_err(client, NUT_ERR_INVALID_ARGUMENT);
return;
}
/* SET VAR UPS VARNAME VALUE */
if (!strcasecmp(arg[0], "VAR")) {
set_var(client, arg[1], arg[2], arg[3]);
if (numarg < 4) {
send_err(client, NUT_ERR_INVALID_ARGUMENT);
return;
}
if (client->tracking) {
/* Generate a tracking ID, if client requested status tracking */
nut_uuid_v4(tracking_id);
}
set_var(client, arg[1], arg[2], arg[3], tracking_id);
return;
}
/* SET TRACKING VALUE */
if (!strcasecmp(arg[0], "TRACKING")) {
if (!strcasecmp(arg[1], "ON")) {
/* general enablement along with for this client */
client->tracking = tracking_enable();
}
else if (!strcasecmp(arg[1], "OFF")) {
/* disable status tracking for this client first */
client->tracking = 0;
/* then only disable the general one if no other clients use it!
* Note: don't call tracking_free() since we want info to
* persist, and tracking_cleanup() takes care of cleaning */
if (tracking_disable()) {
upsdebugx(2, "%s: TRACKING disabled for one client, more remain.", __func__);
} else {
upsdebugx(2, "%s: TRACKING disabled for last client.", __func__);
}
}
else {
send_err(client, NUT_ERR_INVALID_ARGUMENT);
return;
}
upsdebugx(1, "%s: TRACKING general %s, client %s.", __func__,
tracking_is_enabled() ? "enabled" : "disabled",
client->tracking ? "enabled" : "disabled");
sendback(client, "OK\n");
return;
}

View file

@ -1,10 +1,37 @@
/* netset.h - SET handler for upsd
Copyright (C)
2003 Russell Kroll <rkroll@exploits.org>
2005 Arnaud Quette <arnaud.quette@free.fr>
2007 Peter Selinger <selinger@users.sourceforge.net>
2013 Emilien Kia <kiae.dev@gmail.com>
2020 Jim Klimov <jimklimov@gmail.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef NUT_NETSET_H_SEEN
#define NUT_NETSET_H_SEEN 1
#ifdef __cplusplus
/* *INDENT-OFF* */
extern "C" {
/* *INDENT-ON* */
#endif
void net_set(nut_ctype_t *client, int numarg, const char **arg);
void net_set(nut_ctype_t *client, size_t numarg, const char **arg);
#ifdef __cplusplus
/* *INDENT-OFF* */
@ -12,3 +39,4 @@ void net_set(nut_ctype_t *client, int numarg, const char **arg);
/* *INDENT-ON* */
#endif
#endif /* NUT_NETSET_H_SEEN */

View file

@ -30,21 +30,35 @@
#include "upsd.h"
#include "neterr.h"
#include "netssl.h"
#include "nut_stdint.h"
#ifdef WITH_NSS
#include <pk11pub.h>
#include <prinit.h>
#include <private/pprio.h>
#if defined(NSS_VMAJOR) && (NSS_VMAJOR > 3 || (NSS_VMAJOR == 3 && defined(NSS_VMINOR) && NSS_VMINOR >= 39))
#include <keyhi.h>
#include <keythi.h>
#else
#include <key.h>
#include <keyt.h>
#endif /* NSS before 3.39 */
#include <secerr.h>
#include <sslerr.h>
#include <sslproto.h>
#endif /* WITH_NSS */
char *certfile = NULL;
char *certname = NULL;
char *certpasswd = NULL;
/* Warning: in this release of NUT, this feature is disabled by default
* in order to retain compatibility with "least surprise" for earlier
* existing deployments. Over time it can become enabled by default.
* See upsd.conf option DISABLE_WEAK_SSL to toggle this in-vivo.
*/
int disable_weak_ssl = 0;
#ifdef WITH_CLIENT_CERTIFICATE_VALIDATION
int certrequest = 0;
#endif /* WITH_CLIENT_CERTIFICATE_VALIDATION */
@ -54,20 +68,32 @@ static int ssl_initialized = 0;
#ifndef WITH_SSL
/* stubs for non-ssl compiles */
void net_starttls(nut_ctype_t *client, int numarg, const char **arg)
void net_starttls(nut_ctype_t *client, size_t numarg, const char **arg)
{
NUT_UNUSED_VARIABLE(client);
NUT_UNUSED_VARIABLE(numarg);
NUT_UNUSED_VARIABLE(arg);
send_err(client, NUT_ERR_FEATURE_NOT_SUPPORTED);
return;
}
int ssl_write(nut_ctype_t *client, const char *buf, size_t buflen)
ssize_t ssl_write(nut_ctype_t *client, const char *buf, size_t buflen)
{
NUT_UNUSED_VARIABLE(client);
NUT_UNUSED_VARIABLE(buf);
NUT_UNUSED_VARIABLE(buflen);
upslogx(LOG_ERR, "ssl_write called but SSL wasn't compiled in");
return -1;
}
int ssl_read(nut_ctype_t *client, char *buf, size_t buflen)
ssize_t ssl_read(nut_ctype_t *client, char *buf, size_t buflen)
{
NUT_UNUSED_VARIABLE(client);
NUT_UNUSED_VARIABLE(buf);
NUT_UNUSED_VARIABLE(buflen);
upslogx(LOG_ERR, "ssl_read called but SSL wasn't compiled in");
return -1;
}
@ -96,7 +122,7 @@ static SSL_CTX *ssl_ctx = NULL;
static void ssl_debug(void)
{
int e;
unsigned long e;
char errmsg[SMALLBUF];
while ((e = ERR_get_error()) != 0) {
@ -105,32 +131,36 @@ static void ssl_debug(void)
}
}
static int ssl_error(SSL *ssl, int ret)
static int ssl_error(SSL *ssl, ssize_t ret)
{
int e;
e = SSL_get_error(ssl, ret);
if (ret >= INT_MAX) {
upslogx(LOG_ERR, "ssl_error() ret=%zd would not fit in an int", ret);
return -1;
}
e = SSL_get_error(ssl, (int)ret);
switch (e)
{
case SSL_ERROR_WANT_READ:
upsdebugx(1, "ssl_error() ret=%d SSL_ERROR_WANT_READ", ret);
upsdebugx(1, "ssl_error() ret=%zd SSL_ERROR_WANT_READ", ret);
break;
case SSL_ERROR_WANT_WRITE:
upsdebugx(1, "ssl_error() ret=%d SSL_ERROR_WANT_WRITE", ret);
upsdebugx(1, "ssl_error() ret=%zd SSL_ERROR_WANT_WRITE", ret);
break;
case SSL_ERROR_SYSCALL:
if (ret == 0 && ERR_peek_error() == 0) {
upsdebugx(1, "ssl_error() EOF from client");
} else {
upsdebugx(1, "ssl_error() ret=%d SSL_ERROR_SYSCALL", ret);
upsdebugx(1, "ssl_error() ret=%zd SSL_ERROR_SYSCALL", ret);
}
break;
default:
upsdebugx(1, "ssl_error() ret=%d SSL_ERROR %d", ret, e);
upsdebugx(1, "ssl_error() ret=%zd SSL_ERROR %d", ret, e);
ssl_debug();
}
@ -142,9 +172,11 @@ static int ssl_error(SSL *ssl, int ret)
static CERTCertificate *cert;
static SECKEYPrivateKey *privKey;
static char *nss_password_callback(PK11SlotInfo *slot, PRBool retry,
static char *nss_password_callback(PK11SlotInfo *slot, PRBool retry,
void *arg)
{
NUT_UNUSED_VARIABLE(arg);
if (retry) {
/* Force not inted to retrieve password many times. */
return NULL;
@ -165,12 +197,14 @@ static void nss_error(const char* text)
}
}
static int ssl_error(PRFileDesc *ssl, int ret)
static int ssl_error(PRFileDesc *ssl, ssize_t ret)
{
char buffer[256];
PRInt32 length;
PRErrorCode e;
NUT_UNUSED_VARIABLE(ssl);
NUT_UNUSED_VARIABLE(ret);
e = PR_GetError();
length = PR_GetErrorText(buffer);
if (length > 0 && length < 256) {
@ -195,13 +229,15 @@ static SECStatus AuthCertificate(CERTCertDBHandle *arg, PRFileDesc *fd,
static SECStatus BadCertHandler(nut_ctype_t *arg, PRFileDesc *fd)
{
NUT_UNUSED_VARIABLE(fd);
upslogx(LOG_WARNING, "Certificate validation failed for %s",
(arg&&arg->addr)?arg->addr:"<unnamed>");
#ifdef WITH_CLIENT_CERTIFICATE_VALIDATION
/* BadCertHandler is called when the NSS certificate validation is failed.
* If the certificate verification (user conf) is mandatory, reject authentication
* else accept it.
*/
*/
return certrequest==NETSSL_CERTREQ_REQUIRE?SECFailure:SECSuccess;
#else /* WITH_CLIENT_CERTIFICATE_VALIDATION */
/* Always accept clients. */
@ -211,6 +247,8 @@ static SECStatus BadCertHandler(nut_ctype_t *arg, PRFileDesc *fd)
static void HandshakeCallback(PRFileDesc *fd, nut_ctype_t *client_data)
{
NUT_UNUSED_VARIABLE(fd);
upslogx(LOG_INFO, "SSL handshake done successfully with client %s",
client_data->addr);
}
@ -218,7 +256,7 @@ static void HandshakeCallback(PRFileDesc *fd, nut_ctype_t *client_data)
#endif /* WITH_OPENSSL | WITH_NSS */
void net_starttls(nut_ctype_t *client, int numarg, const char **arg)
void net_starttls(nut_ctype_t *client, size_t numarg, const char **arg)
{
#ifdef WITH_OPENSSL
int ret;
@ -226,7 +264,10 @@ void net_starttls(nut_ctype_t *client, int numarg, const char **arg)
SECStatus status;
PRFileDesc *socket;
#endif /* WITH_OPENSSL | WITH_NSS */
NUT_UNUSED_VARIABLE(numarg);
NUT_UNUSED_VARIABLE(arg);
if (client->ssl) {
send_err(client, NUT_ERR_ALREADY_SSL_MODE);
return;
@ -238,22 +279,23 @@ void net_starttls(nut_ctype_t *client, int numarg, const char **arg)
send_err(client, NUT_ERR_FEATURE_NOT_CONFIGURED);
return;
}
#ifdef WITH_OPENSSL
if (!ssl_ctx) {
#ifdef WITH_OPENSSL
if (!ssl_ctx)
#elif defined(WITH_NSS) /* WITH_OPENSSL */
if (!NSS_IsInitialized()) {
if (!NSS_IsInitialized())
#endif /* WITH_OPENSSL | WITH_NSS */
{
send_err(client, NUT_ERR_FEATURE_NOT_CONFIGURED);
ssl_initialized = 0;
return;
}
if (!sendback(client, "OK STARTTLS\n")) {
return;
}
#ifdef WITH_OPENSSL
#ifdef WITH_OPENSSL
client->ssl = SSL_new(ssl_ctx);
@ -268,15 +310,15 @@ void net_starttls(nut_ctype_t *client, int numarg, const char **arg)
ssl_debug();
return;
}
ret = SSL_accept(client->ssl);
switch (ret)
{
case 1:
client->ssl_connected = 1;
upsdebugx(3, "SSL connected");
upsdebugx(3, "SSL connected (%s)", SSL_get_version(client->ssl));
break;
case 0:
upslog_with_errno(LOG_ERR, "SSL_accept do not accept handshake.");
ssl_error(client->ssl, ret);
@ -286,7 +328,7 @@ void net_starttls(nut_ctype_t *client, int numarg, const char **arg)
ssl_error(client->ssl, ret);
break;
}
#elif defined(WITH_NSS) /* WITH_OPENSSL */
socket = PR_ImportTCPSocket(client->sock_fd);
@ -302,13 +344,13 @@ void net_starttls(nut_ctype_t *client, int numarg, const char **arg)
nss_error("net_starttls / SSL_ImportFD");
return;
}
if (SSL_SetPKCS11PinArg(client->ssl, client) == -1){
upslogx(LOG_ERR, "Can not inialize SSL connection");
nss_error("net_starttls / SSL_SetPKCS11PinArg");
return;
}
/* Note cast to SSLAuthCertificate to prevent warning due to
* bad function prototype in NSS.
*/
@ -318,21 +360,21 @@ void net_starttls(nut_ctype_t *client, int numarg, const char **arg)
nss_error("net_starttls / SSL_AuthCertificateHook");
return;
}
status = SSL_BadCertHook(client->ssl, (SSLBadCertHandler)BadCertHandler, client);
if (status != SECSuccess) {
upslogx(LOG_ERR, "Can not inialize SSL connection");
nss_error("net_starttls / SSL_BadCertHook");
return;
}
status = SSL_HandshakeCallback(client->ssl, (SSLHandshakeCallback)HandshakeCallback, client);
if (status != SECSuccess) {
upslogx(LOG_ERR, "Can not inialize SSL connection");
nss_error("net_starttls / SSL_HandshakeCallback");
return;
}
status = SSL_ConfigSecureServer(client->ssl, cert, privKey, NSS_FindCertKEAType(cert));
if (status != SECSuccess) {
upslogx(LOG_ERR, "Can not inialize SSL connection");
@ -370,35 +412,53 @@ void ssl_init(void)
{
#ifdef WITH_NSS
SECStatus status;
#elif defined(WITH_OPENSSL)
#if OPENSSL_VERSION_NUMBER >= 0x10000000L
const SSL_METHOD *ssl_method;
#else
SSL_METHOD *ssl_method;
#if defined(NSS_VMAJOR) && (NSS_VMAJOR > 3 || (NSS_VMAJOR == 3 && defined(NSS_VMINOR) && NSS_VMINOR >= 14))
SSLVersionRange range;
#endif
#endif /* WITH_NSS|WITH_OPENSSL */
#endif /* WITH_NSS */
if (!certfile) {
return;
}
check_perms(certfile);
if (!disable_weak_ssl)
upslogx(LOG_WARNING, "Warning: DISABLE_WEAK_SSL is not enabled. Please consider enabling to improve network security.");
#ifdef WITH_OPENSSL
#if OPENSSL_VERSION_NUMBER < 0x10100000L
SSL_load_error_strings();
SSL_library_init();
if ((ssl_method = TLSv1_server_method()) == NULL) {
ssl_debug();
fatalx(EXIT_FAILURE, "TLSv1_server_method failed");
}
ssl_ctx = SSL_CTX_new(SSLv23_server_method());
#else
ssl_ctx = SSL_CTX_new(TLS_server_method());
#endif
if ((ssl_ctx = SSL_CTX_new(ssl_method)) == NULL) {
if (!ssl_ctx) {
ssl_debug();
fatalx(EXIT_FAILURE, "SSL_CTX_new failed");
}
SSL_CTX_set_options(ssl_ctx, SSL_OP_CIPHER_SERVER_PREFERENCE);
#if OPENSSL_VERSION_NUMBER < 0x10100000L
/* set minimum protocol TLSv1 */
SSL_CTX_set_options(ssl_ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3);
if (disable_weak_ssl) {
#if defined(SSL_OP_NO_TLSv1_2)
SSL_CTX_set_options(ssl_ctx, SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1);
#elif defined(SSL_OP_NO_TLSv1_1)
SSL_CTX_set_options(ssl_ctx, SSL_OP_NO_TLSv1);
#endif
}
#else
if (SSL_CTX_set_min_proto_version(ssl_ctx, disable_weak_ssl ? TLS1_2_VERSION : TLS1_VERSION) != 1) {
ssl_debug();
fatalx(EXIT_FAILURE, "SSL_CTX_set_min_proto_version(TLS1_VERSION)");
}
#endif
if (SSL_CTX_use_certificate_chain_file(ssl_ctx, certfile) != 1) {
ssl_debug();
fatalx(EXIT_FAILURE, "SSL_CTX_use_certificate_chain_file(%s) failed", certfile);
@ -422,7 +482,7 @@ void ssl_init(void)
SSL_CTX_set_verify(ssl_ctx, SSL_VERIFY_NONE, NULL);
ssl_initialized = 1;
#elif defined(WITH_NSS) /* WITH_OPENSSL */
if (!certname || certname[0]==0 ) {
@ -431,9 +491,9 @@ void ssl_init(void)
}
PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
PK11_SetPasswordFunc(nss_password_callback);
if (certfile)
/* Note: this call can generate memory leaks not resolvable
* by any release function.
@ -444,10 +504,10 @@ void ssl_init(void)
status = NSS_NoDB_Init(NULL);
if (status != SECSuccess) {
upslogx(LOG_ERR, "Can not initialize SSL context");
nss_error("upscli_init / NSS_[NoDB]_Init");
nss_error("upscli_init / NSS_[NoDB]_Init");
return;
}
status = NSS_SetDomesticPolicy();
if (status != SECSuccess) {
upslogx(LOG_ERR, "Can not initialize SSL policy");
@ -462,18 +522,57 @@ void ssl_init(void)
nss_error("upscli_init / SSL_ConfigServerSessionIDCache");
return;
}
status = SSL_OptionSetDefault(SSL_ENABLE_SSL3, PR_TRUE);
if (status != SECSuccess) {
upslogx(LOG_ERR, "Can not enable SSLv3");
nss_error("upscli_init / SSL_OptionSetDefault(SSL_ENABLE_SSL3)");
return;
}
status = SSL_OptionSetDefault(SSL_ENABLE_TLS, PR_TRUE);
if (status != SECSuccess) {
upslogx(LOG_ERR, "Can not enable TLSv1");
nss_error("upscli_init / SSL_OptionSetDefault(SSL_ENABLE_TLS)");
return;
if (!disable_weak_ssl) {
status = SSL_OptionSetDefault(SSL_ENABLE_SSL3, PR_TRUE);
if (status != SECSuccess) {
upslogx(LOG_ERR, "Can not enable SSLv3");
nss_error("upscli_init / SSL_OptionSetDefault(SSL_ENABLE_SSL3)");
return;
}
status = SSL_OptionSetDefault(SSL_ENABLE_TLS, PR_TRUE);
if (status != SECSuccess) {
upslogx(LOG_ERR, "Can not enable TLSv1");
nss_error("upscli_init / SSL_OptionSetDefault(SSL_ENABLE_TLS)");
return;
}
} else {
#if defined(NSS_VMAJOR) && (NSS_VMAJOR > 3 || (NSS_VMAJOR == 3 && defined(NSS_VMINOR) && NSS_VMINOR >= 14))
status = SSL_VersionRangeGetSupported(ssl_variant_stream, &range);
if (status != SECSuccess) {
upslogx(LOG_ERR, "Can not get versions supported");
nss_error("upscli_init / SSL_VersionRangeGetSupported");
return;
}
range.min = SSL_LIBRARY_VERSION_TLS_1_1;
#ifdef SSL_LIBRARY_VERSION_TLS_1_2
range.min = SSL_LIBRARY_VERSION_TLS_1_2;
#endif
status = SSL_VersionRangeSetDefault(ssl_variant_stream, &range);
if (status != SECSuccess) {
upslogx(LOG_ERR, "Can not set versions supported");
nss_error("upscli_init / SSL_VersionRangeSetDefault");
return;
}
/* Disable old/weak ciphers */
SSL_CipherPrefSetDefault(TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA, PR_FALSE);
SSL_CipherPrefSetDefault(TLS_RSA_WITH_3DES_EDE_CBC_SHA, PR_FALSE);
SSL_CipherPrefSetDefault(TLS_RSA_WITH_RC4_128_SHA, PR_FALSE);
SSL_CipherPrefSetDefault(TLS_RSA_WITH_RC4_128_MD5, PR_FALSE);
#else
status = SSL_OptionSetDefault(SSL_ENABLE_SSL3, PR_FALSE);
if (status != SECSuccess) {
upslogx(LOG_ERR, "Can not disable SSLv3");
nss_error("upscli_init / SSL_OptionSetDefault(SSL_DISABLE_SSL3)");
return;
}
status = SSL_OptionSetDefault(SSL_ENABLE_TLS, PR_TRUE);
if (status != SECSuccess) {
upslogx(LOG_ERR, "Can not enable TLSv1");
nss_error("upscli_init / SSL_OptionSetDefault(SSL_ENABLE_TLS)");
return;
}
#endif
}
#ifdef WITH_CLIENT_CERTIFICATE_VALIDATION
@ -483,7 +582,7 @@ void ssl_init(void)
return;
}
if (certrequest == NETSSL_CERTREQ_REQUEST ||
if (certrequest == NETSSL_CERTREQ_REQUEST ||
certrequest == NETSSL_CERTREQ_REQUIRE ) {
status = SSL_OptionSetDefault(SSL_REQUEST_CERTIFICATE, PR_TRUE);
if (status != SECSuccess) {
@ -502,39 +601,59 @@ void ssl_init(void)
}
}
#endif /* WITH_CLIENT_CERTIFICATE_VALIDATION */
cert = PK11_FindCertFromNickname(certname, NULL);
if(cert==NULL) {
upslogx(LOG_ERR, "Can not find server certificate");
nss_error("upscli_init / PK11_FindCertFromNickname");
return;
}
privKey = PK11_FindKeyByAnyCert(cert, NULL);
if(privKey==NULL){
upslogx(LOG_ERR, "Can not find private key associate to server certificate");
nss_error("upscli_init / PK11_FindKeyByAnyCert");
return;
}
ssl_initialized = 1;
#else /* WITH_OPENSSL | WITH_NSS */
upslogx(LOG_ERR, "ssl_init called but SSL wasn't compiled in");
#endif /* WITH_OPENSSL | WITH_NSS */
}
int ssl_read(nut_ctype_t *client, char *buf, size_t buflen)
#if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP_BESIDEFUNC) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS_BESIDEFUNC) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE_BESIDEFUNC) )
# pragma GCC diagnostic push
#endif
#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS_BESIDEFUNC
# pragma GCC diagnostic ignored "-Wtype-limits"
#endif
#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE_BESIDEFUNC
# pragma GCC diagnostic ignored "-Wtautological-constant-out-of-range-compare"
#endif
ssize_t ssl_read(nut_ctype_t *client, char *buf, size_t buflen)
{
int ret;
ssize_t ret = -1;
if (!client->ssl_connected) {
return -1;
}
#ifdef WITH_OPENSSL
ret = SSL_read(client->ssl, buf, buflen);
/* SSL_* routines deal with int type for return and buflen
* We might need to window our I/O if we exceed 2GB (in
* 32-bit builds)... Not likely to exceed in 64-bit builds,
* but smaller systems with 16-bits might be endangered :)
*/
assert(buflen <= INT_MAX);
int iret = SSL_read(client->ssl, buf, (int)buflen);
assert(iret <= SSIZE_MAX);
ret = (ssize_t)iret;
#elif defined(WITH_NSS) /* WITH_OPENSSL */
ret = PR_Read(client->ssl, buf, buflen);
/* PR_* routines deal in PRInt32 type
* We might need to window our I/O if we exceed 2GB :) */
assert(buflen <= PR_INT32_MAX);
ret = PR_Read(client->ssl, buf, (PRInt32)buflen);
#endif /* WITH_OPENSSL | WITH_NSS */
if (ret < 1) {
@ -545,24 +664,38 @@ int ssl_read(nut_ctype_t *client, char *buf, size_t buflen)
return ret;
}
int ssl_write(nut_ctype_t *client, const char *buf, size_t buflen)
ssize_t ssl_write(nut_ctype_t *client, const char *buf, size_t buflen)
{
int ret;
ssize_t ret = -1;
if (!client->ssl_connected) {
return -1;
}
#ifdef WITH_OPENSSL
ret = SSL_write(client->ssl, buf, buflen);
/* SSL_* routines deal with int type for return and buflen
* We might need to window our I/O if we exceed 2GB (in
* 32-bit builds)... Not likely to exceed in 64-bit builds,
* but smaller systems with 16-bits might be endangered :)
*/
assert(buflen <= INT_MAX);
int iret = SSL_write(client->ssl, buf, (int)buflen);
assert(iret <= SSIZE_MAX);
ret = (ssize_t)iret;
#elif defined(WITH_NSS) /* WITH_OPENSSL */
ret = PR_Write(client->ssl, buf, buflen);
/* PR_* routines deal in PRInt32 type
* We might need to window our I/O if we exceed 2GB :) */
assert(buflen <= PR_INT32_MAX);
ret = PR_Write(client->ssl, buf, (PRInt32)buflen);
#endif /* WITH_OPENSSL | WITH_NSS */
upsdebugx(5, "ssl_write ret=%d", ret);
upsdebugx(5, "ssl_write ret=%zd", ret);
return ret;
}
#if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP_BESIDEFUNC) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS_BESIDEFUNC) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE_BESIDEFUNC) )
# pragma GCC diagnostic pop
#endif
void ssl_finish(nut_ctype_t *client)
{

View file

@ -17,8 +17,8 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef NETSSL_H_SEEN
#define NETSSL_H_SEEN 1
#ifndef NUT_NETSSL_H_SEEN
#define NUT_NETSSL_H_SEEN 1
#include "nut_ctype.h"
@ -31,6 +31,7 @@ extern "C" {
extern char *certfile;
extern char *certname;
extern char *certpasswd;
extern int disable_weak_ssl;
#ifdef WITH_CLIENT_CERTIFICATE_VALIDATION
extern int certrequest;
#endif /* WITH_CLIENT_CERTIFICATE_VALIDATION */
@ -48,10 +49,10 @@ void ssl_init(void);
void ssl_finish(nut_ctype_t *client);
void ssl_cleanup(void);
int ssl_read(nut_ctype_t *client, char *buf, size_t buflen);
int ssl_write(nut_ctype_t *client, const char *buf, size_t buflen);
ssize_t ssl_read(nut_ctype_t *client, char *buf, size_t buflen);
ssize_t ssl_write(nut_ctype_t *client, const char *buf, size_t buflen);
void net_starttls(nut_ctype_t *client, int numarg, const char **arg);
void net_starttls(nut_ctype_t *client, size_t numarg, const char **arg);
#ifdef __cplusplus
/* *INDENT-OFF* */
@ -59,4 +60,4 @@ void net_starttls(nut_ctype_t *client, int numarg, const char **arg);
/* *INDENT-ON* */
#endif
#endif /* NETSSL_H_SEEN */
#endif /* NUT_NETSSL_H_SEEN */

View file

@ -1,4 +1,4 @@
/* netuser.c - LOGIN/LOGOUT/USERNAME/PASSWORD/MASTER handlers for upsd
/* netuser.c - LOGIN/LOGOUT/USERNAME/PASSWORD/MASTER[PRIMARY] handlers for upsd
Copyright (C) 2003 Russell Kroll <rkroll@exploits.org>
@ -28,7 +28,7 @@
#include "netuser.h"
/* LOGIN <ups> */
void net_login(nut_ctype_t *client, int numarg, const char **arg)
void net_login(nut_ctype_t *client, size_t numarg, const char **arg)
{
upstype_t *ups;
@ -53,6 +53,8 @@ void net_login(nut_ctype_t *client, int numarg, const char **arg)
/* make sure this is a valid user */
if (!user_checkaction(client->username, client->password, "LOGIN")) {
upsdebugx(3, "%s: not a valid user: %s",
__func__, client->username);
send_err(client, NUT_ERR_ACCESS_DENIED);
return;
}
@ -65,8 +67,9 @@ void net_login(nut_ctype_t *client, int numarg, const char **arg)
sendback(client, "OK\n");
}
void net_logout(nut_ctype_t *client, int numarg, const char **arg)
void net_logout(nut_ctype_t *client, size_t numarg, const char **arg)
{
NUT_UNUSED_VARIABLE(arg);
if (numarg != 0) {
send_err(client, NUT_ERR_INVALID_ARGUMENT);
return;
@ -82,35 +85,64 @@ void net_logout(nut_ctype_t *client, int numarg, const char **arg)
client->last_heard = 0;
}
/* MASTER <upsname> */
void net_master(nut_ctype_t *client, int numarg, const char **arg)
/* NOTE: Protocol updated since NUT 2.8.0 to handle master/primary
* and API bumped, to rename/alias the routine.
*/
static int do_net_primary(nut_ctype_t *client, size_t numarg, const char **arg)
{
upstype_t *ups;
if (numarg != 1) {
send_err(client, NUT_ERR_INVALID_ARGUMENT);
return;
return -1;
}
ups = get_ups_ptr(arg[0]);
if (!ups) {
send_err(client, NUT_ERR_UNKNOWN_UPS);
return;
return -1;
}
/* make sure this user is allowed to do MASTER */
if (!user_checkaction(client->username, client->password, "MASTER")) {
/* make sure this user is allowed to do PRIMARY or MASTER */
if (!user_checkaction(client->username, client->password, "PRIMARY")
&& !user_checkaction(client->username, client->password, "MASTER")
) {
send_err(client, NUT_ERR_ACCESS_DENIED);
return;
return -1;
}
/* this is just an access level check */
sendback(client, "OK MASTER-GRANTED\n");
/* sendback() will be worded by caller below */
return 0;
}
/* MASTER <upsname> (deprecated) */
void net_master(nut_ctype_t *client, size_t numarg, const char **arg) {
/* Allow existing binaries linked against this file to still work */
upsdebugx(1,
"WARNING: Client %s@%s "
"requested MASTER level for device %s - "
"which is deprecated in favor of PRIMARY "
"since NUT 2.8.0",
client->username, client->addr,
(numarg > 0) ? arg[0] : "<null>");
if (0 == do_net_primary(client, numarg, arg)) {
sendback(client, "OK MASTER-GRANTED\n");
}
}
/* PRIMARY <upsname> (since NUT 2.8.0) */
void net_primary(nut_ctype_t *client, size_t numarg, const char **arg)
{
if (0 == do_net_primary(client, numarg, arg)) {
sendback(client, "OK PRIMARY-GRANTED\n");
}
}
/* USERNAME <username> */
void net_username(nut_ctype_t *client, int numarg, const char **arg)
void net_username(nut_ctype_t *client, size_t numarg, const char **arg)
{
if (numarg != 1) {
send_err(client, NUT_ERR_INVALID_ARGUMENT);
@ -130,7 +162,7 @@ void net_username(nut_ctype_t *client, int numarg, const char **arg)
}
/* PASSWORD <password> */
void net_password(nut_ctype_t *client, int numarg, const char **arg)
void net_password(nut_ctype_t *client, size_t numarg, const char **arg)
{
if (numarg != 1) {
send_err(client, NUT_ERR_INVALID_ARGUMENT);

View file

@ -1,14 +1,48 @@
/* netuser.c - LOGIN/LOGOUT/USERNAME/PASSWORD/MASTER[PRIMARY] handlers for upsd
Copyright (C)
2003 Russell Kroll <rkroll@exploits.org>
2005 Arnaud Quette <arnaud.quette@free.fr>
2007 Peter Selinger <selinger@users.sourceforge.net>
2013 Emilien Kia <kiae.dev@gmail.com>
2020-2021 Jim Klimov <jimklimov@gmail.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef NUT_NETUSER_H_SEEN
#define NUT_NETUSER_H_SEEN 1
#ifdef __cplusplus
/* *INDENT-OFF* */
extern "C" {
/* *INDENT-ON* */
#endif
void net_login(nut_ctype_t *client, int numarg, const char **arg);
void net_logout(nut_ctype_t *client, int numarg, const char **arg);
void net_master(nut_ctype_t *client, int numarg, const char **arg);
void net_username(nut_ctype_t *client, int numarg, const char **arg);
void net_password(nut_ctype_t *client, int numarg, const char **arg);
void net_login(nut_ctype_t *client, size_t numarg, const char **arg);
void net_logout(nut_ctype_t *client, size_t numarg, const char **arg);
/* NOTE: Since NUT 2.8.0 we handle master as alias for primary
* Header keyword kept for building older consumers, but
* the implementation will warn that it is deprecated.
*/
void net_master(nut_ctype_t *client, size_t numarg, const char **arg);
void net_primary(nut_ctype_t *client, size_t numarg, const char **arg);
void net_username(nut_ctype_t *client, size_t numarg, const char **arg);
void net_password(nut_ctype_t *client, size_t numarg, const char **arg);
#ifdef __cplusplus
/* *INDENT-OFF* */
@ -16,3 +50,4 @@ void net_password(nut_ctype_t *client, int numarg, const char **arg);
/* *INDENT-ON* */
#endif
#endif /* NUT_NETUSER_H_SEEN */

View file

@ -4,6 +4,8 @@
2002 Russell Kroll <rkroll@exploits.org>
2008 Arjen de Korte <adkorte-guest@alioth.debian.org>
2011 Arnaud Quette <arnaud.quette@free.fr>
2013 Emilien Kia <kiae.dev@gmail.com>
2020 Jim Klimov <jimklimov@gmail.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -37,6 +39,12 @@
#include "parseconf.h"
#ifdef __cplusplus
/* *INDENT-OFF* */
extern "C" {
/* *INDENT-ON* */
#endif
/* client structure */
typedef struct nut_ctype_s {
char *addr;
@ -45,6 +53,9 @@ typedef struct nut_ctype_s {
char *loginups;
char *password;
char *username;
/* per client status info for commands and settings
* (disabled by default) */
int tracking;
#ifdef WITH_OPENSSL
SSL *ssl;
@ -62,4 +73,10 @@ typedef struct nut_ctype_s {
struct nut_ctype_s *next;
} nut_ctype_t;
#ifdef __cplusplus
/* *INDENT-OFF* */
}
/* *INDENT-ON* */
#endif
#endif /* NUT_CTYPE_H_SEEN */

View file

@ -21,7 +21,7 @@
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/un.h>
#include <sys/un.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/socket.h>
@ -31,11 +31,11 @@
PCONF_CTX_t sock_ctx;
static void sock_arg(int numarg, char **arg)
static void sock_arg(size_t numarg, char **arg)
{
int i;
size_t i;
printf("numarg=%d : ", numarg);
printf("numarg=%zu : ", numarg);
for (i = 0; i < numarg; i++)
printf("[%s] ", arg[i]);
@ -48,6 +48,8 @@ static int socket_connect(const char *sockfn)
int ret, fd;
struct sockaddr_un sa;
check_unix_socket_filename(sockfn);
memset(&sa, '\0', sizeof(sa));
sa.sun_family = AF_UNIX;
snprintf(sa.sun_path, sizeof(sa.sun_path), "%s", sockfn);
@ -98,7 +100,7 @@ static void read_sock(int fd)
}
if (ret < 0) {
perror("read sockfd");
perror("read sockfd");
exit(EXIT_FAILURE);
}

View file

@ -25,7 +25,9 @@
#include "timehead.h"
#include "sstate.h"
#include "upsd.h"
#include "upstype.h"
#include "nut_stdint.h"
#include <fcntl.h>
#include <stdio.h>
@ -33,9 +35,9 @@
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/un.h>
static int parse_args(upstype_t *ups, int numargs, char **arg)
static int parse_args(upstype_t *ups, size_t numargs, char **arg)
{
if (numargs < 1)
return 0;
@ -104,48 +106,63 @@ static int parse_args(upstype_t *ups, int numargs, char **arg)
return 1;
}
/* ADDRANGE <varname> <minvalue> <maxvalue> */
if (!strcasecmp(arg[0], "ADDRANGE")) {
state_addrange(ups->inforoot, arg[1], atoi(arg[2]), atoi(arg[3]));
return 1;
}
/* DELENUM <varname> <enumval> */
if (!strcasecmp(arg[0], "DELENUM")) {
state_delenum(ups->inforoot, arg[1], arg[2]);
return 1;
}
/* DELRANGE <varname> <minvalue> <maxvalue> */
if (!strcasecmp(arg[0], "DELRANGE")) {
state_delrange(ups->inforoot, arg[1], atoi(arg[2]), atoi(arg[3]));
return 1;
}
/* SETAUX <varname> <auxval> */
if (!strcasecmp(arg[0], "SETAUX")) {
state_setaux(ups->inforoot, arg[1], arg[2]);
return 1;
}
/* TRACKING <id> <status> */
if (!strcasecmp(arg[0], "TRACKING")) {
tracking_set(arg[1], arg[2]);
upsdebugx(1, "TRACKING: ID %s status %s", arg[1], arg[2]);
/* log actual result of instcmd / setvar */
if (strncmp(arg[2], "PENDING", 7) != 0) {
upslogx(LOG_INFO, "tracking ID: %s\tresult: %s", arg[1], tracking_get(arg[1]));
}
return 1;
}
if (numargs < 4)
return 0;
/* ADDRANGE <varname> <minvalue> <maxvalue> */
if (!strcasecmp(arg[0], "ADDRANGE")) {
state_addrange(ups->inforoot, arg[1], atoi(arg[2]), atoi(arg[3]));
return 1;
}
/* DELRANGE <varname> <minvalue> <maxvalue> */
if (!strcasecmp(arg[0], "DELRANGE")) {
state_delrange(ups->inforoot, arg[1], atoi(arg[2]), atoi(arg[3]));
return 1;
}
return 0;
}
/* nothing fancy - just make the driver say something back to us */
static void sendping(upstype_t *ups)
{
int ret;
ssize_t ret;
const char *cmd = "PING\n";
size_t cmdlen = strlen(cmd);
if ((!ups) || (ups->sock_fd < 0)) {
return;
}
upsdebugx(3, "Pinging UPS [%s]", ups->name);
ret = write(ups->sock_fd, cmd, cmdlen);
ret = write(ups->sock_fd, cmd, strlen(cmd));
if (ret != (int)strlen(cmd)) {
if ((ret < 1) || (ret != (ssize_t)cmdlen)) {
upslog_with_errno(LOG_NOTICE, "Send ping to UPS [%s] failed", ups->name);
sstate_disconnect(ups);
return;
@ -158,10 +175,14 @@ static void sendping(upstype_t *ups)
int sstate_connect(upstype_t *ups)
{
int ret, fd;
int fd;
const char *dumpcmd = "DUMPALL\n";
size_t dumpcmdlen = strlen(dumpcmd);
ssize_t ret;
struct sockaddr_un sa;
check_unix_socket_filename(ups->fn);
memset(&sa, '\0', sizeof(sa));
sa.sun_family = AF_UNIX;
snprintf(sa.sun_path, sizeof(sa.sun_path), "%s", ups->fn);
@ -186,7 +207,7 @@ int sstate_connect(upstype_t *ups)
return -1;
ups->last_connfail = now;
upslog_with_errno(LOG_ERR, "Can't connect to UPS [%s] (%s)",
upslog_with_errno(LOG_ERR, "Can't connect to UPS [%s] (%s)",
ups->name, ups->fn);
return -1;
@ -209,9 +230,9 @@ int sstate_connect(upstype_t *ups)
}
/* get a dump started so we have a fresh set of data */
ret = write(fd, dumpcmd, strlen(dumpcmd));
ret = write(fd, dumpcmd, dumpcmdlen);
if (ret != (int)strlen(dumpcmd)) {
if ((ret < 1) || (ret != (ssize_t)dumpcmdlen)) {
upslog_with_errno(LOG_ERR, "Initial write to UPS [%s] failed", ups->name);
close(fd);
return -1;
@ -250,7 +271,7 @@ void sstate_disconnect(upstype_t *ups)
void sstate_readline(upstype_t *ups)
{
int i, ret;
ssize_t i, ret;
char buf[SMALLBUF];
if ((!ups) || (ups->sock_fd < 0)) {
@ -280,7 +301,7 @@ void sstate_readline(upstype_t *ups)
case 1:
/* set the 'last heard' time to now for later staleness checks */
if (parse_args(ups, ups->sock_ctx.numargs, ups->sock_ctx.arglist)) {
time(&ups->last_heard);
time(&ups->last_heard);
}
continue;
@ -303,12 +324,12 @@ const char *sstate_getinfo(const upstype_t *ups, const char *var)
int sstate_getflags(const upstype_t *ups, const char *var)
{
return state_getflags(ups->inforoot, var);
}
}
int sstate_getaux(const upstype_t *ups, const char *var)
long sstate_getaux(const upstype_t *ups, const char *var)
{
return state_getaux(ups->inforoot, var);
}
}
const enum_t *sstate_getenumlist(const upstype_t *ups, const char *var)
{
@ -325,7 +346,7 @@ const cmdlist_t *sstate_getcmdlist(const upstype_t *ups)
return ups->cmdlist;
}
int sstate_dead(upstype_t *ups, int maxage)
int sstate_dead(upstype_t *ups, int arg_maxage)
{
time_t now;
double elapsed;
@ -347,12 +368,12 @@ int sstate_dead(upstype_t *ups, int maxage)
elapsed = difftime(now, ups->last_heard);
/* somewhere beyond a third of the maximum time - prod it to make it talk */
if ((elapsed > (maxage / 3)) && (difftime(now, ups->last_ping) > (maxage / 3)))
if ((elapsed > (arg_maxage / 3)) && (difftime(now, ups->last_ping) > (arg_maxage / 3)))
sendping(ups);
if (elapsed > maxage) {
if (elapsed > arg_maxage) {
upsdebugx(3, "sstate_dead: didn't hear from driver for UPS [%s] for %g seconds (max %d)",
ups->name, elapsed, maxage);
ups->name, elapsed, arg_maxage);
return 1; /* dead */
}
@ -376,16 +397,24 @@ void sstate_cmdfree(upstype_t *ups)
int sstate_sendline(upstype_t *ups, const char *buf)
{
int ret;
ssize_t ret;
size_t buflen;
if ((!ups) ||(ups->sock_fd < 0)) {
return 0; /* failed */
}
ret = write(ups->sock_fd, buf, strlen(buf));
buflen = strlen(buf);
if (buflen >= SSIZE_MAX) {
/* Can't compare buflen to ret... */
upslog_with_errno(LOG_NOTICE, "Send ping to UPS [%s] failed: buffered message too large", ups->name);
return 0; /* failed */
}
if (ret == (int)strlen(buf)) {
return 1;
ret = write(ups->sock_fd, buf, buflen);
if (ret == (ssize_t)buflen) {
return 1;
}
upslog_with_errno(LOG_NOTICE, "Send to UPS [%s] failed", ups->name);

View file

@ -20,8 +20,8 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef SSTATE_H_SEEN
#define SSTATE_H_SEEN
#ifndef NUT_SSTATE_H_SEEN
#define NUT_SSTATE_H_SEEN 1
#include "state.h"
#include "upstype.h"
@ -40,7 +40,7 @@ void sstate_disconnect(upstype_t *ups);
void sstate_readline(upstype_t *ups);
const char *sstate_getinfo(const upstype_t *ups, const char *var);
int sstate_getflags(const upstype_t *ups, const char *var);
int sstate_getaux(const upstype_t *ups, const char *var);
long sstate_getaux(const upstype_t *ups, const char *var);
const enum_t *sstate_getenumlist(const upstype_t *ups, const char *var);
const range_t *sstate_getrangelist(const upstype_t *ups, const char *var);
const cmdlist_t *sstate_getcmdlist(const upstype_t *ups);
@ -59,4 +59,4 @@ const st_tree_t *sstate_getnode(const upstype_t *ups, const char *varname);
/* *INDENT-ON* */
#endif
#endif /* SSTATE_H_SEEN */
#endif /* NUT_SSTATE_H_SEEN */

View file

@ -18,8 +18,8 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef STYPE_H_SEEN
#define STYPE_H_SEEN 1
#ifndef NUT_STYPE_H_SEEN
#define NUT_STYPE_H_SEEN 1
#include <netdb.h>
@ -50,4 +50,4 @@ typedef struct stype_s {
/* *INDENT-ON* */
#endif
#endif /* STYPE_H_SEEN */
#endif /* NUT_STYPE_H_SEEN */

View file

@ -1,9 +1,10 @@
/* upsd.c - watches ups state files and answers queries
/* upsd.c - watches ups state files and answers queries
Copyright (C)
1999 Russell Kroll <rkroll@exploits.org>
2008 Arjen de Korte <adkorte-guest@alioth.debian.org>
2011 - 2012 Arnaud Quette <arnaud.quette.free.fr>
2019 Eaton (author: Arnaud Quette <ArnaudQuette@eaton.com>)
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -20,6 +21,8 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "config.h" /* must be the first header */
#include "upsd.h"
#include "upstype.h"
#include "conf.h"
@ -30,10 +33,17 @@
#include <sys/un.h>
#include <sys/socket.h>
#include <netdb.h>
#include <poll.h>
#ifdef HAVE_SYS_SIGNAL_H
#include <sys/signal.h>
#endif
#ifdef HAVE_SIGNAL_H
#include <signal.h>
#endif
#include "user.h"
#include "nut_ctype.h"
#include "nut_stdint.h"
#include "stype.h"
#include "netssl.h"
#include "sstate.h"
@ -46,29 +56,38 @@ int allow_severity = LOG_INFO;
int deny_severity = LOG_WARNING;
#endif /* HAVE_WRAP */
/* externally-visible settings and pointers */
/* externally-visible settings and pointers */
upstype_t *firstups = NULL;
upstype_t *firstups = NULL;
/* default 15 seconds before data is marked stale */
int maxage = 15;
/* default 15 seconds before data is marked stale */
int maxage = 15;
/* preloaded to {OPEN_MAX} in main, can be overridden via upsd.conf */
int maxconn = 0;
/* default to 1h before cleaning up status tracking entries */
int tracking_delay = 3600;
/* preloaded to STATEPATH in main, can be overridden via upsd.conf */
char *statepath = NULL;
/*
* Preloaded to ALLOW_NO_DEVICE from upsd.conf or environment variable
* (with higher prio for envvar); defaults to disabled for legacy compat.
*/
int allow_no_device = 0;
/* preloaded to DATADIR in main, can be overridden via upsd.conf */
char *datapath = NULL;
/* preloaded to {OPEN_MAX} in main, can be overridden via upsd.conf */
nfds_t maxconn = 0;
/* everything else */
const char *progname;
/* preloaded to STATEPATH in main, can be overridden via upsd.conf */
char *statepath = NULL;
/* preloaded to DATADIR in main, can be overridden via upsd.conf */
char *datapath = NULL;
/* everything else */
static const char *progname;
nut_ctype_t *firstclient = NULL;
/* static nut_ctype_t *lastclient = NULL; */
/* default is to listen on all local interfaces */
/* default is to listen on all local interfaces */
static stype_t *firstaddr = NULL;
static int opt_af = AF_UNSPEC;
@ -84,6 +103,28 @@ typedef struct {
void *data;
} handler_t;
/* Commands and settings status tracking */
/* general enable/disable status info for commands and settings
* (disabled by default)
* Note that only client that requested it will have it enabled
* (see nut_ctype.h) */
static int tracking_enabled = 0;
/* Commands and settings status tracking structure */
typedef struct tracking_s {
char *id;
int status;
time_t request_time; /* for cleanup */
/* doubly linked list */
struct tracking_s *prev;
struct tracking_s *next;
} tracking_t;
static tracking_t *tracking_list = NULL;
/* pollfd */
static struct pollfd *fds = NULL;
static handler_t *handler = NULL;
@ -94,6 +135,11 @@ static char pidfn[SMALLBUF];
/* set by signal handlers */
static int reload_flag = 0, exit_flag = 0;
/* Minimalistic support for UUID v4 */
/* Ref: RFC 4122 https://tools.ietf.org/html/rfc4122#section-4.1.2 */
#define UUID4_BYTESIZE 16
static const char *inet_ntopW (struct sockaddr_storage *s)
{
static char str[40];
@ -204,7 +250,7 @@ static void setuptcp(stype_t *server)
upsdebug_with_errno(3, "setuptcp: socket");
continue;
}
if (setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, (void *)&one, sizeof(one)) != 0) {
fatal_with_errno(EXIT_FAILURE, "setuptcp: setsockopt");
}
@ -308,12 +354,15 @@ static void client_disconnect(nut_ctype_t *client)
return;
}
/* send the buffer <sendbuf> of length <sendlen> to host <dest> */
/* send the buffer <sendbuf> of length <sendlen> to host <dest>
* returns effectively a boolean: 0 = failed, 1 = sent ok
*/
int sendback(nut_ctype_t *client, const char *fmt, ...)
{
int res, len;
char ans[NUT_NET_ANSWER_MAX+1];
va_list ap;
ssize_t res;
size_t len;
char ans[NUT_NET_ANSWER_MAX+1];
va_list ap;
if (!client) {
return 0;
@ -325,18 +374,23 @@ int sendback(nut_ctype_t *client, const char *fmt, ...)
len = strlen(ans);
/* System write() and our ssl_write() have a loophole that they write a
* size_t amount of bytes and upon success return that in ssize_t value
*/
assert(len < SSIZE_MAX);
#ifdef WITH_SSL
if (client->ssl) {
res = ssl_write(client, ans, len);
} else
} else
#endif /* WITH_SSL */
{
res = write(client->sock_fd, ans, len);
}
upsdebugx(2, "write: [destfd=%d] [len=%d] [%s]", client->sock_fd, len, str_rtrim(ans, '\n'));
upsdebugx(2, "write: [destfd=%d] [len=%zu] [%s]", client->sock_fd, len, str_rtrim(ans, '\n'));
if (len != res) {
if (res < 0 || len != (size_t)res) {
upslog_with_errno(LOG_NOTICE, "write() failed for %s", client->addr);
client->last_heard = 0;
return 0; /* failed */
@ -396,20 +450,25 @@ int ups_available(const upstype_t *ups, nut_ctype_t *client)
}
/* check flags and access for an incoming command from the network */
static void check_command(int cmdnum, nut_ctype_t *client, int numarg,
static void check_command(int cmdnum, nut_ctype_t *client, size_t numarg,
const char **arg)
{
upsdebugx(6, "Entering %s: %s", __func__, numarg > 0 ? arg[0] : "<>");
if (netcmds[cmdnum].flags & FLAG_USER) {
/* command requires previous authentication */
#ifdef HAVE_WRAP
struct request_info req;
#endif /* HAVE_WRAP */
if (!client->username) {
upsdebugx(1, "%s: client not logged in yet", __func__);
send_err(client, NUT_ERR_USERNAME_REQUIRED);
return;
}
if (!client->password) {
upsdebugx(1, "%s: client not logged in yet", __func__);
send_err(client, NUT_ERR_PASSWORD_REQUIRED);
return;
}
@ -419,15 +478,20 @@ static void check_command(int cmdnum, nut_ctype_t *client, int numarg,
fromhost(&req);
if (!hosts_access(&req)) {
/* tcp-wrappers says access should be denied */
upsdebugx(1,
"%s: while authenticating %s found that "
"tcp-wrappers says access should be denied",
__func__, client->username);
send_err(client, NUT_ERR_ACCESS_DENIED);
return;
}
#endif /* HAVE_WRAP */
}
upsdebugx(6, "%s: Calling command handler for %s", __func__, numarg > 0 ? arg[0] : "<>");
/* looks good - call the command */
netcmds[cmdnum].func(client, numarg - 1, &arg[1]);
netcmds[cmdnum].func(client, (numarg < 2) ? 0 : (numarg - 1), (numarg > 1) ? &arg[1] : NULL);
}
/* parse requests from the network */
@ -457,7 +521,7 @@ static void parse_net(nut_ctype_t *client)
static void client_connect(stype_t *server)
{
struct sockaddr_storage csock;
#if defined(__hpux) && !defined(_XOPEN_SOURCE_EXTENDED)
#if defined(__hpux) && !defined(_XOPEN_SOURCE_EXTENDED)
int clen;
#else
socklen_t clen;
@ -480,6 +544,8 @@ static void client_connect(stype_t *server)
client->addr = xstrdup(inet_ntopW(&csock));
client->tracking = 0;
pconf_init(&client->ctx, NULL);
if (firstclient) {
@ -504,12 +570,13 @@ static void client_connect(stype_t *server)
static void client_readline(nut_ctype_t *client)
{
char buf[SMALLBUF];
int i, ret;
int i;
ssize_t ret;
#ifdef WITH_SSL
if (client->ssl) {
ret = ssl_read(client, buf, sizeof(buf));
} else
} else
#endif /* WITH_SSL */
{
ret = read(client->sock_fd, buf, sizeof(buf));
@ -569,7 +636,7 @@ void server_load(void)
for (server = firstaddr; server; server = server->next) {
setuptcp(server);
}
/* check if we have at least 1 valid LISTEN interface */
if (firstaddr->sock_fd < 0) {
fatalx(EXIT_FAILURE, "no listening interface available");
@ -607,11 +674,14 @@ static void client_free(void)
}
}
void driver_free(void)
static void driver_free(void)
{
upstype_t *ups, *unext;
for (ups = firstups; ups; ups = unext) {
upsdebugx(1, "%s: forgetting UPS [%s] (FD %d)",
__func__, ups->name, ups->sock_fd);
unext = ups->next;
if (ups->sock_fd != -1) {
@ -640,10 +710,11 @@ static void upsd_cleanup(void)
user_flush();
desc_free();
server_free();
client_free();
driver_free();
tracking_free();
free(statepath);
free(datapath);
@ -655,27 +726,256 @@ static void upsd_cleanup(void)
free(handler);
}
void poll_reload(void)
static void poll_reload(void)
{
int ret;
long ret;
ret = sysconf(_SC_OPEN_MAX);
if (ret < maxconn) {
if ((intmax_t)ret < (intmax_t)maxconn) {
fatalx(EXIT_FAILURE,
"Your system limits the maximum number of connections to %d\n"
"but you requested %d. The server won't start until this\n"
"problem is resolved.\n", ret, maxconn);
"Your system limits the maximum number of connections to %ld\n"
"but you requested %jd. The server won't start until this\n"
"problem is resolved.\n", ret, (intmax_t)maxconn);
}
fds = xrealloc(fds, maxconn * sizeof(*fds));
handler = xrealloc(handler, maxconn * sizeof(*handler));
if (1 > maxconn) {
fatalx(EXIT_FAILURE,
"You requested %jd as maximum number of connections.\n"
"The server won't start until this problem is resolved.\n", (intmax_t)maxconn);
}
/* How many items can we stuff into the array? */
size_t maxalloc = SIZE_MAX / sizeof(void *);
if ((uintmax_t)maxalloc < (uintmax_t)maxconn) {
fatalx(EXIT_FAILURE,
"You requested %jd as maximum number of connections, but we can only allocate %zu.\n"
"The server won't start until this problem is resolved.\n", (intmax_t)maxconn, maxalloc);
}
/* The checks above effectively limit that maxconn is in size_t range */
fds = xrealloc(fds, (size_t)maxconn * sizeof(*fds));
handler = xrealloc(handler, (size_t)maxconn * sizeof(*handler));
}
/* instant command and setvar status tracking */
/* allocate a new status tracking entry */
int tracking_add(const char *id)
{
tracking_t *item;
if ((!tracking_enabled) || (!id))
return 0;
item = xcalloc(1, sizeof(*item));
item->id = xstrdup(id);
item->status = STAT_PENDING;
time(&item->request_time);
if (tracking_list) {
tracking_list->prev = item;
item->next = tracking_list;
}
tracking_list = item;
return 1;
}
/* set status of a specific tracking entry */
int tracking_set(const char *id, const char *value)
{
tracking_t *item, *next_item;
/* sanity checks */
if ((!tracking_list) || (!id) || (!value))
return 0;
for (item = tracking_list; item; item = next_item) {
next_item = item->next;
if (!strcasecmp(item->id, id)) {
item->status = atoi(value);
return 1;
}
}
return 0; /* id not found! */
}
/* free a specific tracking entry */
int tracking_del(const char *id)
{
tracking_t *item, *next_item;
/* sanity check */
if ((!tracking_list) || (!id))
return 0;
upsdebugx(3, "%s: deleting id %s", __func__, id);
for (item = tracking_list; item; item = next_item) {
next_item = item->next;
if (strcasecmp(item->id, id))
continue;
if (item->prev)
item->prev->next = item->next;
else
/* deleting first entry */
tracking_list = item->next;
if (item->next)
item->next->prev = item->prev;
free(item->id);
free(item);
return 1;
}
return 0; /* id not found! */
}
/* free all status tracking entries */
void tracking_free(void)
{
tracking_t *item, *next_item;
/* sanity check */
if (!tracking_list)
return;
upsdebugx(3, "%s", __func__);
for (item = tracking_list; item; item = next_item) {
next_item = item->next;
tracking_del(item->id);
}
}
/* cleanup status tracking entries according to their age and tracking_delay */
void tracking_cleanup(void)
{
tracking_t *item, *next_item;
time_t now;
/* sanity check */
if (!tracking_list)
return;
time(&now);
upsdebugx(3, "%s", __func__);
for (item = tracking_list; item; item = next_item) {
next_item = item->next;
if (difftime(now, item->request_time) > tracking_delay) {
tracking_del(item->id);
}
}
}
/* get status of a specific tracking entry */
char *tracking_get(const char *id)
{
tracking_t *item, *next_item;
/* sanity checks */
if ((!tracking_list) || (!id))
return "ERR UNKNOWN";
for (item = tracking_list; item; item = next_item) {
next_item = item->next;
if (strcasecmp(item->id, id))
continue;
switch (item->status)
{
case STAT_PENDING:
return "PENDING";
case STAT_HANDLED:
return "SUCCESS";
case STAT_UNKNOWN:
return "ERR UNKNOWN";
case STAT_INVALID:
return "ERR INVALID-ARGUMENT";
case STAT_FAILED:
return "ERR FAILED";
}
}
return "ERR UNKNOWN"; /* id not found! */
}
/* enable general status tracking (tracking_enabled) and return its value (1). */
int tracking_enable(void)
{
tracking_enabled = 1;
return tracking_enabled;
}
/* disable general status tracking only if no client use it anymore.
* return the new value for tracking_enabled */
int tracking_disable(void)
{
nut_ctype_t *client, *cnext;
for (client = firstclient; client; client = cnext) {
cnext = client->next;
if (client->tracking == 1)
return 1;
}
return 0;
}
/* return current general status of tracking (tracking_enabled). */
int tracking_is_enabled(void)
{
return tracking_enabled;
}
/* UUID v4 basic implementation
* Note: 'dest' must be at least `UUID4_LEN` long */
int nut_uuid_v4(char *uuid_str)
{
size_t i;
uint8_t nut_uuid[UUID4_BYTESIZE];
if (!uuid_str)
return 0;
for (i = 0; i < UUID4_BYTESIZE; i++)
nut_uuid[i] = (uint8_t)rand() + (uint8_t)rand();
/* set variant and version */
nut_uuid[6] = (nut_uuid[6] & 0x0F) | 0x40;
nut_uuid[8] = (nut_uuid[8] & 0x3F) | 0x80;
return snprintf(uuid_str, UUID4_LEN,
"%02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X",
nut_uuid[0], nut_uuid[1], nut_uuid[2], nut_uuid[3],
nut_uuid[4], nut_uuid[5], nut_uuid[6], nut_uuid[7],
nut_uuid[8], nut_uuid[9], nut_uuid[10], nut_uuid[11],
nut_uuid[12], nut_uuid[13], nut_uuid[14], nut_uuid[15]);
}
/* service requests and check on new data */
static void mainloop(void)
{
int i, ret, nfds = 0;
int ret;
nfds_t i, nfds = 0;
upstype_t *ups;
nut_ctype_t *client, *cnext;
@ -690,12 +990,19 @@ static void mainloop(void)
reload_flag = 0;
}
/* cleanup instcmd/setvar status tracking entries if needed */
tracking_cleanup();
/* scan through driver sockets */
for (ups = firstups; ups && (nfds < maxconn); ups = ups->next) {
/* see if we need to (re)connect to the socket */
if (ups->sock_fd < 0) {
upsdebugx(1, "%s: UPS [%s] is not currently connected",
__func__, ups->name);
ups->sock_fd = sstate_connect(ups);
upsdebugx(1, "%s: UPS [%s] is now connected as FD %d",
__func__, ups->name, ups->sock_fd);
continue;
}
@ -722,6 +1029,7 @@ static void mainloop(void)
if (difftime(now, client->last_heard) > 60) {
/* shed clients after 1 minute of inactivity */
/* FIXME: create an upsd.conf parameter (CLIENT_INACTIVITY_DELAY) */
client_disconnect(client);
continue;
}
@ -756,7 +1064,7 @@ static void mainloop(void)
nfds++;
}
upsdebugx(2, "%s: polling %d filedescriptors", __func__, nfds);
upsdebugx(2, "%s: polling %jd filedescriptors", __func__, (intmax_t)nfds);
ret = poll(fds, nfds, 2000);
@ -785,9 +1093,36 @@ static void mainloop(void)
case SERVER:
upsdebugx(2, "%s: server disconnected", __func__);
break;
#if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_COVERED_SWITCH_DEFAULT) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE) )
# pragma GCC diagnostic push
#endif
#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_COVERED_SWITCH_DEFAULT
# pragma GCC diagnostic ignored "-Wcovered-switch-default"
#endif
#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE
# pragma GCC diagnostic ignored "-Wunreachable-code"
#endif
/* Older CLANG (e.g. clang-3.4) seems to not support the GCC pragmas above */
#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wcovered-switch-default"
#pragma clang diagnostic ignored "-Wunreachable-code"
#endif
/* All enum cases defined as of the time of coding
* have been covered above. Handle later definitions,
* memory corruptions and buggy inputs below...
*/
default:
upsdebugx(2, "%s: <unknown> disconnected", __func__);
break;
#ifdef __clang__
#pragma clang diagnostic pop
#endif
#if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_COVERED_SWITCH_DEFAULT) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE) )
# pragma GCC diagnostic pop
#endif
}
continue;
@ -806,9 +1141,35 @@ static void mainloop(void)
case SERVER:
client_connect((stype_t *)handler[i].data);
break;
#if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_COVERED_SWITCH_DEFAULT) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE) )
# pragma GCC diagnostic push
#endif
#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_COVERED_SWITCH_DEFAULT
# pragma GCC diagnostic ignored "-Wcovered-switch-default"
#endif
#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE
# pragma GCC diagnostic ignored "-Wunreachable-code"
#endif
/* Older CLANG (e.g. clang-3.4) seems to not support the GCC pragmas above */
#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wcovered-switch-default"
#pragma clang diagnostic ignored "-Wunreachable-code"
#endif
/* All enum cases defined as of the time of coding
* have been covered above. Handle later definitions,
* memory corruptions and buggy inputs below...
*/
default:
upsdebugx(2, "%s: <unknown> has data available", __func__);
break;
#ifdef __clang__
#pragma clang diagnostic pop
#endif
#if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_COVERED_SWITCH_DEFAULT) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE) )
# pragma GCC diagnostic pop
#endif
}
continue;
@ -816,17 +1177,24 @@ static void mainloop(void)
}
}
static void help(const char *progname)
static void help(const char *arg_progname)
__attribute__((noreturn));
static void help(const char *arg_progname)
{
printf("Network server for UPS data.\n\n");
printf("usage: %s [OPTIONS]\n", progname);
printf("usage: %s [OPTIONS]\n", arg_progname);
printf("\n");
printf(" -c <command> send <command> via signal to background process\n");
printf(" commands:\n");
printf(" - reload: reread configuration files\n");
printf(" - stop: stop process and exit\n");
printf(" -D raise debugging level\n");
printf(" -P <pid> send the signal above to specified PID (bypassing PID file)\n");
printf(" -D raise debugging level (and stay foreground by default)\n");
printf(" -F stay foregrounded even if no debugging is enabled\n");
printf(" -FF stay foregrounded and still save the PID file\n");
printf(" -B stay backgrounded even if debugging is bumped\n");
printf(" -h display this help\n");
printf(" -r <dir> chroots to <dir>\n");
printf(" -q raise log level threshold\n");
@ -840,6 +1208,7 @@ static void help(const char *progname)
static void set_reload_flag(int sig)
{
NUT_UNUSED_VARIABLE(sig);
reload_flag = 1;
}
@ -857,7 +1226,14 @@ static void setup_signals(void)
sa.sa_flags = 0;
/* basic signal setup to ignore SIGPIPE */
#if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_STRICT_PROTOTYPES)
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wstrict-prototypes"
#endif
sa.sa_handler = SIG_IGN;
#if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_STRICT_PROTOTYPES)
# pragma GCC diagnostic pop
#endif
sigaction(SIGPIPE, &sa, NULL);
/* handle shutdown signals */
@ -890,10 +1266,11 @@ void check_perms(const char *fn)
int main(int argc, char **argv)
{
int i, cmd = 0;
int i, cmd = 0, cmdret = 0, foreground = -1;
char *chroot_path = NULL;
const char *user = RUN_AS_USER;
struct passwd *new_uid = NULL;
pid_t oldpid = -1;
progname = xbasename(argv[0]);
@ -906,25 +1283,29 @@ int main(int argc, char **argv)
printf("Network UPS Tools %s %s\n", progname, UPS_VERSION);
while ((i = getopt(argc, argv, "+h46p:qr:i:fu:Vc:D")) != -1) {
while ((i = getopt(argc, argv, "+h46p:qr:i:fu:Vc:P:DFB")) != -1) {
switch (i) {
case 'h':
help(progname);
break;
case 'p':
case 'i':
fatalx(EXIT_FAILURE, "Specifying a listening addresses with '-i <address>' and '-p <port>'\n"
"is deprecated. Use 'LISTEN <address> [<port>]' in 'upsd.conf' instead.\n"
"See 'man 8 upsd.conf' for more information.");
#ifndef HAVE___ATTRIBUTE__NORETURN
exit(EXIT_FAILURE); /* Should not get here in practice, but compiler is afraid we can fall through */
#endif
case 'q':
nut_log_level++;
break;
case 'r':
chroot_path = optarg;
break;
case 'u':
user = optarg;
break;
case 'V':
/* do nothing - we already printed the banner */
exit(EXIT_SUCCESS);
@ -940,9 +1321,25 @@ int main(int argc, char **argv)
help(progname);
break;
case 'P':
if ((oldpid = parsepid(optarg)) < 0)
help(progname);
break;
case 'D':
nut_debug_level++;
break;
case 'F':
if (foreground > 0) {
/* specified twice to save PID file anyway */
foreground = 2;
} else {
foreground = 1;
}
break;
case 'B':
foreground = 0;
break;
case '4':
opt_af = AF_INET;
@ -952,24 +1349,56 @@ int main(int argc, char **argv)
opt_af = AF_INET6;
break;
case 'h':
default:
help(progname);
break;
}
}
if (foreground < 0) {
if (nut_debug_level > 0) {
foreground = 1;
} else {
foreground = 0;
}
}
if (cmd) {
sendsignalfn(pidfn, cmd);
exit(EXIT_SUCCESS);
if (oldpid < 0) {
cmdret = sendsignalfn(pidfn, cmd);
} else {
cmdret = sendsignalpid(oldpid, cmd);
}
exit((cmdret == 0)?EXIT_SUCCESS:EXIT_FAILURE);
}
/* otherwise, we are being asked to start.
* so check if a previous instance is running by sending signal '0'
* (Ie 'kill <pid> 0') */
if (sendsignalfn(pidfn, 0) == 0) {
if (oldpid < 0) {
cmdret = sendsignalfn(pidfn, 0);
} else {
cmdret = sendsignalpid(oldpid, 0);
}
switch (cmdret) {
case 0:
printf("Fatal error: A previous upsd instance is already running!\n");
printf("Either stop the previous instance first, or use the 'reload' command.\n");
exit(EXIT_FAILURE);
case -3:
case -2:
upslogx(LOG_WARNING, "Could not %s PID file '%s' "
"to see if previous upsd instance is "
"already running!\n",
(cmdret == -3 ? "find" : "parse"),
pidfn);
break;
case -1:
default:
/* Just failed to send signal, no competitor running */
break;
}
argc -= optind;
@ -995,12 +1424,43 @@ int main(int argc, char **argv)
chroot_start(chroot_path);
}
/* default to system limit (may be overridden in upsd.conf */
maxconn = sysconf(_SC_OPEN_MAX);
/* default to system limit (may be overridden in upsd.conf) */
/* FIXME: Check for overflows (and int size of nfds_t vs. long) - see get_max_pid_t() for example */
maxconn = (nfds_t)sysconf(_SC_OPEN_MAX);
/* handle upsd.conf */
load_upsdconf(0); /* 0 = initial */
/* CLI debug level can not be smaller than debug_min specified
* in upsd.conf. Note that non-zero debug_min does not impact
* foreground running mode.
*/
if (nut_debug_level_global > nut_debug_level)
nut_debug_level = nut_debug_level_global;
upsdebugx(1, "debug level is '%d'", nut_debug_level);
{ /* scope */
/* As documented above, the ALLOW_NO_DEVICE can be provided via
* envvars and then has higher priority than an upsd.conf setting
*/
const char *envvar = getenv("ALLOW_NO_DEVICE");
if ( envvar != NULL) {
if ( (!strncasecmp("TRUE", envvar, 4)) || (!strncasecmp("YES", envvar, 3)) || (!strncasecmp("ON", envvar, 2)) || (!strncasecmp("1", envvar, 1)) ) {
/* Admins of this server expressed a desire to serve
* anything on the NUT protocol, even if nothing is
* configured yet - tell the clients so, properly.
*/
allow_no_device = 1;
} else if ( (!strncasecmp("FALSE", envvar, 5)) || (!strncasecmp("NO", envvar, 2)) || (!strncasecmp("OFF", envvar, 3)) || (!strncasecmp("0", envvar, 1)) ) {
/* Admins of this server expressed a desire to serve
* anything on the NUT protocol, even if nothing is
* configured yet - tell the clients so, properly.
*/
allow_no_device = 0;
}
}
} /* scope */
/* start server */
server_load();
@ -1019,7 +1479,11 @@ int main(int argc, char **argv)
poll_reload();
if (num_ups == 0) {
fatalx(EXIT_FAILURE, "Fatal error: at least one UPS must be defined in ups.conf");
if (allow_no_device) {
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)");
} else {
fatalx(EXIT_FAILURE, "Fatal error: at least one UPS must be defined in ups.conf");
}
}
/* try to bring in the var/cmd descriptions */
@ -1028,11 +1492,17 @@ int main(int argc, char **argv)
/* handle upsd.users */
user_load();
if (!nut_debug_level) {
if (!foreground) {
background();
writepid(pidfn);
} else {
memset(pidfn, 0, sizeof(pidfn));
if (foreground == 2) {
upslogx(LOG_WARNING, "Running as foreground process, but saving a PID file anyway");
writepid(pidfn);
} else {
upslogx(LOG_WARNING, "Running as foreground process, not saving a PID file");
memset(pidfn, 0, sizeof(pidfn));
}
}
/* initialize SSL (keyfile must be readable by nut user) */

View file

@ -38,6 +38,7 @@
#include "timehead.h"
#include <sys/file.h>
#include <poll.h> /* nfds_t */
#include "parseconf.h"
#include "nut_ctype.h"
@ -68,9 +69,30 @@ void server_free(void);
void check_perms(const char *fn);
/* declarations from upsd.c */
/* return values for instcmd / setvar status tracking,
* mapped on drivers/upshandler.h, apart from STAT_PENDING (initial state) */
enum {
STAT_PENDING = -1, /* not yet completed */
STAT_HANDLED = 0, /* completed successfully (NUT_SUCCESS or "OK") */
STAT_UNKNOWN, /* unspecified error (NUT_ERR_UNKNOWN) */
STAT_INVALID, /* invalid command/setvar (NUT_ERR_INVALID_ARGUMENT) */
STAT_FAILED /* command/setvar failed (NUT_ERR_INSTCMD_FAILED / NUT_ERR_SET_FAILED) */
};
extern int maxage, maxconn;
/* Commands and settings status tracking functions */
int tracking_add(const char *id);
int tracking_set(const char *id, const char *value);
int tracking_del(const char *id);
void tracking_free(void);
void tracking_cleanup(void);
char *tracking_get(const char *id);
int tracking_enable(void);
int tracking_disable(void);
int tracking_is_enabled(void);
/* declarations from upsd.c */
extern int maxage, tracking_delay, allow_no_device;
extern nfds_t maxconn;
extern char *statepath, *datapath;
extern upstype_t *firstups;
extern nut_ctype_t *firstclient;
@ -91,6 +113,10 @@ extern nut_ctype_t *firstclient;
#define shutdown_how 2
#endif
/* UUID v4 generation function
* Note: 'dest' must be at least `UUID4_LEN` long */
int nut_uuid_v4(char *uuid_str);
#ifdef __cplusplus
/* *INDENT-OFF* */
}

View file

@ -19,8 +19,8 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef UPSTYPE_H_SEEN
#define UPSTYPE_H_SEEN 1
#ifndef NUT_UPSTYPE_H_SEEN
#define NUT_UPSTYPE_H_SEEN 1
#include "parseconf.h"
@ -51,7 +51,7 @@ typedef struct upstype_s {
int fsd; /* forced shutdown in effect? */
int retain;
struct upstype_s *next;
} upstype_t;
@ -64,4 +64,4 @@ extern upstype_t *firstups;
/* *INDENT-ON* */
#endif
#endif /* UPSTYPE_H_SEEN */
#endif /* NUT_UPSTYPE_H_SEEN */

View file

@ -1,6 +1,11 @@
/* user-data.h - structures for user.c
Copyright (C) 2001 Russell Kroll <rkroll@exploits.org>
2005 Arnaud Quette <arnaud.quette@free.fr>
2007 Peter Selinger <selinger@users.sourceforge.net>
2008 Arjen de Korte <adkorte-guest@alioth.debian.org>
2013 Emilien Kia <kiae.dev@gmail.com>
2020 Jim Klimov <jimklimov@gmail.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -17,6 +22,9 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef NUT_USERDATA_H_SEEN
#define NUT_USERDATA_H_SEEN 1
#ifdef __cplusplus
/* *INDENT-OFF* */
extern "C" {
@ -47,3 +55,4 @@ typedef struct {
/* *INDENT-ON* */
#endif
#endif /* NUT_USERDATA_H_SEEN */

View file

@ -17,6 +17,8 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "config.h" /* must be the first header */
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
@ -28,9 +30,9 @@
#include "user.h"
#include "user-data.h"
ulist_t *users = NULL;
static ulist_t *users = NULL;
static ulist_t *curr_user;
static ulist_t *curr_user;
/* create a new user entry */
static void user_add(const char *un)
@ -57,7 +59,7 @@ static void user_add(const char *un)
if (last) {
last->next = tmp;
} else {
users = tmp;
users = tmp;
}
/* remember who we're working on */
@ -78,7 +80,7 @@ static void user_password(const char *pw)
}
if (curr_user->password) {
fprintf(stderr, "Ignoring duplicate password for %s\n",
fprintf(stderr, "Ignoring duplicate password for %s\n",
curr_user->username);
return;
}
@ -317,19 +319,20 @@ int user_checkaction(const char *un, const char *pw, const char *action)
return 0; /* fail */
}
/* handle "upsmon master" and "upsmon slave" for nicer configurations */
/* handle "upsmon primary" and "upsmon secondary" for nicer configurations */
/* FIXME: Protocol update needed to handle master/primary alias (in action and in protocol) */
static void set_upsmon_type(char *type)
{
/* master: login, master, fsd */
if (!strcasecmp(type, "master")) {
/* primary: login, master, fsd */
if (!strcasecmp(type, "master") || !strcasecmp(type, "primary")) {
user_add_action("login");
user_add_action("master");
user_add_action("master"); /* Note: this is linked to "MASTER" API command permission */
user_add_action("fsd");
return;
}
/* slave: just login */
if (!strcasecmp(type, "slave")) {
/* secondary: just login */
if (!strcasecmp(type, "slave") || !strcasecmp(type, "secondary")) {
user_add_action("login");
return;
}
@ -370,9 +373,9 @@ static void parse_var(char *var, char *val)
}
/* parse first var+val pair, then flip through remaining vals */
static void parse_rest(char *var, char *fval, char **arg, int next, int left)
static void parse_rest(char *var, char *fval, char **arg, size_t next, size_t left)
{
int i;
size_t i;
/* no globals supported yet, so there's no sense in continuing */
if (!curr_user) {
@ -390,7 +393,7 @@ static void parse_rest(char *var, char *fval, char **arg, int next, int left)
}
}
static void user_parse_arg(int numargs, char **arg)
static void user_parse_arg(size_t numargs, char **arg)
{
char *ep;
@ -414,7 +417,7 @@ static void user_parse_arg(int numargs, char **arg)
/* 0 1 2 ... */
/* foo=bar <rest1> <rest2> ... */
parse_rest(arg[0], ep+1, arg, 1, numargs - 1);
parse_rest(arg[0], ep+1, arg, 1, (numargs < 2) ? 0 : (numargs - 1));
return;
}
@ -447,8 +450,8 @@ static void user_parse_arg(int numargs, char **arg)
/* foo = bar <rest1> <rest2> ... */
/* parse first var/val, plus subsequent values (if any) */
parse_rest(arg[0], arg[2], arg, 3, numargs - 3);
parse_rest(arg[0], arg[2], arg, 3, (numargs < 4) ? 0 : (numargs - 3));
return;
}

View file

@ -1,6 +1,11 @@
/* user.c - supporting elements of user handling functions for upsd
Copyright (C) 2001 Russell Kroll <rkroll@exploits.org>
2005 Arnaud Quette <arnaud.quette@free.fr>
2007 Peter Selinger <selinger@users.sourceforge.net>
2008 Arjen de Korte <adkorte-guest@alioth.debian.org>
2013 Emilien Kia <kiae.dev@gmail.com>
2020 Jim Klimov <jimklimov@gmail.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -17,6 +22,9 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef NUT_USER_H_SEEN
#define NUT_USER_H_SEEN 1
#ifdef __cplusplus
/* *INDENT-OFF* */
extern "C" {
@ -39,3 +47,4 @@ void check_perms(const char *fn);
/* *INDENT-ON* */
#endif
#endif /* NUT_USER_H_SEEN */