From 9290a4b8a0d30f2b718b242f8c8e8967d31ebab5 Mon Sep 17 00:00:00 2001 From: MrIron Date: Fri, 9 Jan 2026 14:08:56 +0100 Subject: [PATCH 1/3] - Completed TLS implementation (based on initial implementation prepared by Compy) - Re-done authentication mechanism in mod.cservice. - Added sasl and fingeprint authentication support to mod.cservice. - Added network configuration support in gnuworld core, utilised by sasl authentication. --- ChangeLog | 36 + Makefile.in | 95 ++- aclocal.m4 | 992 +++++++++++++++++++++- bin/GNUWorld.example.conf | 14 + bin/cservice.example.conf | 7 + bin/server_command_map | 1 + configure | 109 +++ configure.ac | 30 + doc/cservice.sql | 18 +- doc/cservice.update.sql | 40 + include/Channel.h | 3 + include/Network.h | 27 + include/defs.h.in | 3 + include/events.h | 4 + include/gnuworld_config.h | 7 + include/iClient.h | 48 +- include/server.h | 21 + libgnuworld/Connection.cc | 32 +- libgnuworld/Connection.h | 99 ++- libgnuworld/ConnectionManager.cc | 258 +++++- libgnuworld/ConnectionManager.h | 19 +- libgnuworld/misc.cc | 35 + libgnuworld/misc.h | 7 + libircu/Makefile.am | 1 + libircu/msg_B.cc | 4 + libircu/msg_CF.cc | 92 ++ libircu/msg_CM.cc | 7 + libircu/msg_M.cc | 4 + libircu/msg_N.cc | 11 + libltdl/Makefile.in | 24 +- libltdl/aclocal.m4 | 992 +++++++++++++++++++++- mod.ccontrol/CLEARCHANCommand.cc | 4 +- mod.ccontrol/WHOISCommand.cc | 28 +- mod.ccontrol/ccontrol.cc | 5 + mod.cloner/cloner.cc | 6 + mod.cservice/CERTCommand.cc | 250 ++++++ mod.cservice/CHANINFOCommand.cc | 31 +- mod.cservice/CLEARMODECommand.cc | 2 +- mod.cservice/HELLOCommand.cc | 14 +- mod.cservice/LOGINCommand.cc | 199 +---- mod.cservice/Makefile.am | 4 + mod.cservice/NEWPASSCommand.cc | 13 + mod.cservice/SETCommand.cc | 73 ++ mod.cservice/constants.h | 2 +- mod.cservice/cservice.cc | 1354 ++++++++++++++++++++++++------ mod.cservice/cservice.h | 124 ++- mod.cservice/cserviceCommands.h | 1 + mod.cservice/cservice_config.h | 21 +- mod.cservice/cservice_confvars.h | 2 + mod.cservice/cservice_crypt.cc | 345 ++++++++ mod.cservice/cservice_crypt.h | 92 ++ mod.cservice/responses.h | 16 +- mod.cservice/sqlUser.cc | 22 +- mod.cservice/sqlUser.h | 18 +- mod.dronescan/FAKECommand.cc | 1 + mod.gnutest/gnutest.cc | 1 + mod.nickserv/nickserv.cc | 1 + mod.scanner/wingateModule.cc | 2 +- mod.snoop/snoop.cc | 1 + src/Channel.cc | 2 + src/Network.cc | 8 + src/client.cc | 9 +- src/iClient.cc | 12 +- src/main.cc | 3 +- src/server.cc | 85 +- src/server_connection.cc | 2 +- 66 files changed, 5215 insertions(+), 578 deletions(-) create mode 100755 libircu/msg_CF.cc create mode 100644 mod.cservice/CERTCommand.cc create mode 100644 mod.cservice/cservice_crypt.cc create mode 100644 mod.cservice/cservice_crypt.h diff --git a/ChangeLog b/ChangeLog index e5d031f5..f35434c1 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,41 @@ // $Id: ChangeLog,v 1.173 2010/04/10 18:56:06 danielaustin Exp $ // +2026-01-09 MrIron + * Major update: TLS support (based on Compy's initial implementation), SASL/SCRAM authentication, fingerprint features, and expanded user/channel modes. + * configure.ac: + - Added default libssl detection and configuration for TLS features. + * bin/server_command_map, include/Network.h, include/events.h, libircu/Makefile.am, libircu/msg_CF.cc (new), src/Network.cc: + - Implemented new CF network command (network configuration) to hold network-wide configuration variables, necessary for the SASL implementation. + * src/main.cc, src/server.cc, src/client.cc, src/Channel.cc, src/Network.cc, src/iClient.cc, libgnuworld/Connection.cc, Connection.h, ConnectionManager.cc, ConnectionManager.h, misc.cc, misc.h, + include/Channel.h, include/Network.h, include/defs.h.in, include/events.h, include/gnuworld_config.h, include/iClient.h, include/server.h: + - Added TLS support (configurable, with certificate/key loading, TLS-only channel/user modes). + - Added new channel and user modes for TLS implementation. + - Updated connection logic, mode parsing, and display for TLS. + - Added TLS fingerprint field to iClient and related constructors. + - Updated for new TLS, fingerprint, and mode features. + * mod.cservice/cservice_crypt.cc, mod.cservice/cservice_crypt.h (new files): + - Implemented SCRAM-SHA-256 password hashing and authentication helpers. + - Added base64 helpers, PBKDF2, HMAC, and nonce generation. + * mod.cservice/CERTCommand.cc (new file): + - Added certificate management and fingerprint registration commands. + * mod.cservice/CHANINFOCommand.cc, CLEARMODECommand.cc, HELLOCommand.cc, LOGINCommand.cc, NEWPASSCommand.cc, SETCommand.cc, constants.h, cservice.cc, cservice.h, cserviceCommands.h, cservice_config.h, cservice_confvars.h, responses.h, sqlUser.cc, sqlUser.h: + - Added SASL/SCRAM authentication, fingerprint management, new user flags (certonly, autohide, etc.), and expanded command set. + - Improved error handling, logging, and configuration options. + * mod.dronescan/FAKECommand.cc, mod.gnutest/gnutest.cc, mod.nickserv/nickserv.cc, mod.snoop/snoop.cc: + - Updated iClient instantiation to include TLS fingerprint field. + * mod.scanner/wingateModule.cc: + - Updated Connect() to accept TLS flag. + * mod.ccontrol/CLEARCHANCommand.cc, WHOISCommand.cc, ccontrol.cc: + - Minor updates for compatibility with new TLS and fingerprint features. + * mod.cloner/cloner.cc: + - Minor update for compatibility. + * libircu/msg_B.cc, msg_CM.cc, msg_M.cc, msg_N.cc: + - Implemented TLS user and channel modes and fingerprint parsing. + * bin/GNUWorld.example.conf, bin/cservice.example.conf: + - Updated example configs for new TLS and authentication options. + * doc/cservice.sql, doc/cservice.update.sql: + - Updated schema for SCRAM, fingerprint, and new flags. + 2025-10-17 MrIron * src/main.cc: * include/server.h: diff --git a/Makefile.in b/Makefile.in index ccc09957..81bc9cf1 100644 --- a/Makefile.in +++ b/Makefile.in @@ -251,8 +251,7 @@ ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_boost_base.m4 \ $(top_srcdir)/m4/ax_boost_thread.m4 \ $(top_srcdir)/m4/ax_cxx_compile_stdcxx.m4 \ - $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltargz.m4 \ - $(top_srcdir)/m4/ltdl.m4 $(top_srcdir)/m4/ltoptions.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)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ @@ -562,15 +561,16 @@ libcloner_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \ @COND_MODCLONER_TRUE@am_libcloner_la_rpath = -rpath $(libdir) @COND_MODCSERVICE_TRUE@libcservice_la_DEPENDENCIES = libgnuworldDB.la am__libcservice_la_SOURCES_DIST = mod.cservice/banMatcher.cc \ - mod.cservice/cservice.cc mod.cservice/networkData.cc \ - mod.cservice/sqlChannel.cc mod.cservice/sqlUser.cc \ - mod.cservice/sqlLevel.cc mod.cservice/sqlBan.cc \ - mod.cservice/sqlPendingChannel.cc \ + mod.cservice/cservice.cc mod.cservice/cservice_crypt.cc \ + mod.cservice/networkData.cc mod.cservice/sqlChannel.cc \ + mod.cservice/sqlUser.cc mod.cservice/sqlLevel.cc \ + mod.cservice/sqlBan.cc mod.cservice/sqlPendingChannel.cc \ mod.cservice/sqlPendingTraffic.cc mod.cservice/csGline.cc \ mod.cservice/ACCESSCommand.cc \ mod.cservice/ADDCOMMENTCommand.cc \ mod.cservice/ADDUSERCommand.cc mod.cservice/BANCommand.cc \ - mod.cservice/BANLISTCommand.cc mod.cservice/CHANINFOCommand.cc \ + mod.cservice/BANLISTCommand.cc mod.cservice/CERTCommand.cc \ + mod.cservice/CHANINFOCommand.cc \ mod.cservice/CLEARMODECommand.cc mod.cservice/DEOPCommand.cc \ mod.cservice/DEVOICECommand.cc mod.cservice/FORCECommand.cc \ mod.cservice/HELPCommand.cc mod.cservice/HELLOCommand.cc \ @@ -602,6 +602,7 @@ am__libcservice_la_SOURCES_DIST = mod.cservice/banMatcher.cc \ mod.cservice/MODECommand.cc @COND_MODCSERVICE_TRUE@am_libcservice_la_OBJECTS = mod.cservice/libcservice_la-banMatcher.lo \ @COND_MODCSERVICE_TRUE@ mod.cservice/libcservice_la-cservice.lo \ +@COND_MODCSERVICE_TRUE@ mod.cservice/libcservice_la-cservice_crypt.lo \ @COND_MODCSERVICE_TRUE@ mod.cservice/libcservice_la-networkData.lo \ @COND_MODCSERVICE_TRUE@ mod.cservice/libcservice_la-sqlChannel.lo \ @COND_MODCSERVICE_TRUE@ mod.cservice/libcservice_la-sqlUser.lo \ @@ -615,6 +616,7 @@ am__libcservice_la_SOURCES_DIST = mod.cservice/banMatcher.cc \ @COND_MODCSERVICE_TRUE@ mod.cservice/libcservice_la-ADDUSERCommand.lo \ @COND_MODCSERVICE_TRUE@ mod.cservice/libcservice_la-BANCommand.lo \ @COND_MODCSERVICE_TRUE@ mod.cservice/libcservice_la-BANLISTCommand.lo \ +@COND_MODCSERVICE_TRUE@ mod.cservice/libcservice_la-CERTCommand.lo \ @COND_MODCSERVICE_TRUE@ mod.cservice/libcservice_la-CHANINFOCommand.lo \ @COND_MODCSERVICE_TRUE@ mod.cservice/libcservice_la-CLEARMODECommand.lo \ @COND_MODCSERVICE_TRUE@ mod.cservice/libcservice_la-DEOPCommand.lo \ @@ -775,19 +777,20 @@ libgnuworldcore_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(libgnuworldcore_la_LDFLAGS) $(LDFLAGS) -o $@ libircu_la_LIBADD = am_libircu_la_OBJECTS = libircu/la-msg_AC.lo libircu/la-msg_AD.lo \ - libircu/la-msg_B.lo libircu/la-msg_C.lo libircu/la-msg_CM.lo \ - libircu/la-msg_D.lo libircu/la-msg_DS.lo libircu/la-msg_EA.lo \ - libircu/la-msg_EB.lo libircu/la-msg_G.lo libircu/la-msg_GL.lo \ - libircu/la-msg_I.lo libircu/la-msg_J.lo libircu/la-msg_JU.lo \ - libircu/la-msg_K.lo libircu/la-msg_L.lo libircu/la-msg_M351.lo \ - libircu/la-msg_M391.lo libircu/la-msg_M.lo libircu/la-msg_N.lo \ - libircu/la-msg_NOOP.lo libircu/la-msg_O.lo \ - libircu/la-msg_PA.lo libircu/la-msg_P.lo libircu/la-msg_Q.lo \ - libircu/la-msg_R.lo libircu/la-msg_RI.lo libircu/la-msg_RO.lo \ - libircu/la-msg_S.lo libircu/la-msg_Server.lo \ - libircu/la-msg_SQ.lo libircu/la-msg_T.lo libircu/la-msg_V.lo \ - libircu/la-msg_WA.lo libircu/la-msg_W.lo libircu/la-msg_XQ.lo \ - libircu/la-msg_XR.lo libircu/la-msg_Y.lo + libircu/la-msg_B.lo libircu/la-msg_C.lo libircu/la-msg_CF.lo \ + libircu/la-msg_CM.lo libircu/la-msg_D.lo libircu/la-msg_DS.lo \ + libircu/la-msg_EA.lo libircu/la-msg_EB.lo libircu/la-msg_G.lo \ + libircu/la-msg_GL.lo libircu/la-msg_I.lo libircu/la-msg_J.lo \ + libircu/la-msg_JU.lo libircu/la-msg_K.lo libircu/la-msg_L.lo \ + libircu/la-msg_M351.lo libircu/la-msg_M391.lo \ + libircu/la-msg_M.lo libircu/la-msg_N.lo libircu/la-msg_NOOP.lo \ + libircu/la-msg_O.lo libircu/la-msg_PA.lo libircu/la-msg_P.lo \ + libircu/la-msg_Q.lo libircu/la-msg_R.lo libircu/la-msg_RI.lo \ + libircu/la-msg_RO.lo libircu/la-msg_S.lo \ + libircu/la-msg_Server.lo libircu/la-msg_SQ.lo \ + libircu/la-msg_T.lo libircu/la-msg_V.lo libircu/la-msg_WA.lo \ + libircu/la-msg_W.lo libircu/la-msg_XQ.lo libircu/la-msg_XR.lo \ + libircu/la-msg_Y.lo libircu_la_OBJECTS = $(am_libircu_la_OBJECTS) libircu_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(libircu_la_CXXFLAGS) \ @@ -1011,8 +1014,9 @@ am__depfiles_remade = db/$(DEPDIR)/libgnuworldDB_la-gnuworldDB.Plo \ libgnuworld/$(DEPDIR)/la-threadworker.Plo \ libircu/$(DEPDIR)/la-msg_AC.Plo \ libircu/$(DEPDIR)/la-msg_AD.Plo libircu/$(DEPDIR)/la-msg_B.Plo \ - libircu/$(DEPDIR)/la-msg_C.Plo libircu/$(DEPDIR)/la-msg_CM.Plo \ - libircu/$(DEPDIR)/la-msg_D.Plo libircu/$(DEPDIR)/la-msg_DS.Plo \ + libircu/$(DEPDIR)/la-msg_C.Plo libircu/$(DEPDIR)/la-msg_CF.Plo \ + libircu/$(DEPDIR)/la-msg_CM.Plo libircu/$(DEPDIR)/la-msg_D.Plo \ + libircu/$(DEPDIR)/la-msg_DS.Plo \ libircu/$(DEPDIR)/la-msg_EA.Plo \ libircu/$(DEPDIR)/la-msg_EB.Plo libircu/$(DEPDIR)/la-msg_G.Plo \ libircu/$(DEPDIR)/la-msg_GL.Plo libircu/$(DEPDIR)/la-msg_I.Plo \ @@ -1121,6 +1125,7 @@ am__depfiles_remade = db/$(DEPDIR)/libgnuworldDB_la-gnuworldDB.Plo \ mod.cservice/$(DEPDIR)/libcservice_la-ADDUSERCommand.Plo \ mod.cservice/$(DEPDIR)/libcservice_la-BANCommand.Plo \ mod.cservice/$(DEPDIR)/libcservice_la-BANLISTCommand.Plo \ + mod.cservice/$(DEPDIR)/libcservice_la-CERTCommand.Plo \ mod.cservice/$(DEPDIR)/libcservice_la-CHANINFOCommand.Plo \ mod.cservice/$(DEPDIR)/libcservice_la-CLEARMODECommand.Plo \ mod.cservice/$(DEPDIR)/libcservice_la-DEOPCommand.Plo \ @@ -1176,6 +1181,7 @@ am__depfiles_remade = db/$(DEPDIR)/libgnuworldDB_la-gnuworldDB.Plo \ mod.cservice/$(DEPDIR)/libcservice_la-banMatcher.Plo \ mod.cservice/$(DEPDIR)/libcservice_la-csGline.Plo \ mod.cservice/$(DEPDIR)/libcservice_la-cservice.Plo \ + mod.cservice/$(DEPDIR)/libcservice_la-cservice_crypt.Plo \ mod.cservice/$(DEPDIR)/libcservice_la-networkData.Plo \ mod.cservice/$(DEPDIR)/libcservice_la-sqlBan.Plo \ mod.cservice/$(DEPDIR)/libcservice_la-sqlChannel.Plo \ @@ -1700,8 +1706,8 @@ EXTRA_DIST = bin/ccontrol.example.conf bin/chanfix.example.conf \ libgnuworld/threadworker.h libgnuworld/misc.h \ libgnuworld/MTrie.h libgnuworld/MTrie.cc libgnuworld/Signal.h \ libgnuworld/StringTokenizer.h libgnuworld/xparameters.h \ - libgnuworld/logger.h libgnuworld/notifier.h \ - libgnuworld/prometheus.h libgnuworld/pushover.h \ + libnotifier/logger.h libnotifier/notifier.h \ + libnotifier/prometheus.h libnotifier/pushover.h \ $(am__append_6) $(am__append_8) $(am__append_10) \ $(am__append_12) $(am__append_14) $(am__append_16) \ $(am__append_18) $(am__append_20) $(am__append_22) \ @@ -1751,6 +1757,7 @@ libircu_la_SOURCES = \ libircu/msg_AD.cc \ libircu/msg_B.cc \ libircu/msg_C.cc \ + libircu/msg_CF.cc \ libircu/msg_CM.cc \ libircu/msg_D.cc \ libircu/msg_DS.cc \ @@ -1985,6 +1992,7 @@ gnuworld_LDADD = libgnuworld.la libgnuworldcore.la $(LIBLTDL) @COND_MODCSERVICE_TRUE@libcservice_la_SOURCES = \ @COND_MODCSERVICE_TRUE@ mod.cservice/banMatcher.cc \ @COND_MODCSERVICE_TRUE@ mod.cservice/cservice.cc \ +@COND_MODCSERVICE_TRUE@ mod.cservice/cservice_crypt.cc \ @COND_MODCSERVICE_TRUE@ mod.cservice/networkData.cc \ @COND_MODCSERVICE_TRUE@ mod.cservice/sqlChannel.cc \ @COND_MODCSERVICE_TRUE@ mod.cservice/sqlUser.cc \ @@ -1998,6 +2006,7 @@ gnuworld_LDADD = libgnuworld.la libgnuworldcore.la $(LIBLTDL) @COND_MODCSERVICE_TRUE@ mod.cservice/ADDUSERCommand.cc \ @COND_MODCSERVICE_TRUE@ mod.cservice/BANCommand.cc \ @COND_MODCSERVICE_TRUE@ mod.cservice/BANLISTCommand.cc \ +@COND_MODCSERVICE_TRUE@ mod.cservice/CERTCommand.cc \ @COND_MODCSERVICE_TRUE@ mod.cservice/CHANINFOCommand.cc \ @COND_MODCSERVICE_TRUE@ mod.cservice/CLEARMODECommand.cc \ @COND_MODCSERVICE_TRUE@ mod.cservice/DEOPCommand.cc \ @@ -2753,6 +2762,9 @@ mod.cservice/libcservice_la-banMatcher.lo: \ mod.cservice/$(DEPDIR)/$(am__dirstamp) mod.cservice/libcservice_la-cservice.lo: mod.cservice/$(am__dirstamp) \ mod.cservice/$(DEPDIR)/$(am__dirstamp) +mod.cservice/libcservice_la-cservice_crypt.lo: \ + mod.cservice/$(am__dirstamp) \ + mod.cservice/$(DEPDIR)/$(am__dirstamp) mod.cservice/libcservice_la-networkData.lo: \ mod.cservice/$(am__dirstamp) \ mod.cservice/$(DEPDIR)/$(am__dirstamp) @@ -2788,6 +2800,9 @@ mod.cservice/libcservice_la-BANCommand.lo: \ mod.cservice/libcservice_la-BANLISTCommand.lo: \ mod.cservice/$(am__dirstamp) \ mod.cservice/$(DEPDIR)/$(am__dirstamp) +mod.cservice/libcservice_la-CERTCommand.lo: \ + mod.cservice/$(am__dirstamp) \ + mod.cservice/$(DEPDIR)/$(am__dirstamp) mod.cservice/libcservice_la-CHANINFOCommand.lo: \ mod.cservice/$(am__dirstamp) \ mod.cservice/$(DEPDIR)/$(am__dirstamp) @@ -3140,6 +3155,8 @@ libircu/la-msg_B.lo: libircu/$(am__dirstamp) \ libircu/$(DEPDIR)/$(am__dirstamp) libircu/la-msg_C.lo: libircu/$(am__dirstamp) \ libircu/$(DEPDIR)/$(am__dirstamp) +libircu/la-msg_CF.lo: libircu/$(am__dirstamp) \ + libircu/$(DEPDIR)/$(am__dirstamp) libircu/la-msg_CM.lo: libircu/$(am__dirstamp) \ libircu/$(DEPDIR)/$(am__dirstamp) libircu/la-msg_D.lo: libircu/$(am__dirstamp) \ @@ -3470,6 +3487,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@libircu/$(DEPDIR)/la-msg_AD.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@libircu/$(DEPDIR)/la-msg_B.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@libircu/$(DEPDIR)/la-msg_C.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@libircu/$(DEPDIR)/la-msg_CF.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@libircu/$(DEPDIR)/la-msg_CM.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@libircu/$(DEPDIR)/la-msg_D.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@libircu/$(DEPDIR)/la-msg_DS.Plo@am__quote@ # am--include-marker @@ -3592,6 +3610,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@mod.cservice/$(DEPDIR)/libcservice_la-ADDUSERCommand.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@mod.cservice/$(DEPDIR)/libcservice_la-BANCommand.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@mod.cservice/$(DEPDIR)/libcservice_la-BANLISTCommand.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@mod.cservice/$(DEPDIR)/libcservice_la-CERTCommand.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@mod.cservice/$(DEPDIR)/libcservice_la-CHANINFOCommand.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@mod.cservice/$(DEPDIR)/libcservice_la-CLEARMODECommand.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@mod.cservice/$(DEPDIR)/libcservice_la-DEOPCommand.Plo@am__quote@ # am--include-marker @@ -3647,6 +3666,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@mod.cservice/$(DEPDIR)/libcservice_la-banMatcher.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@mod.cservice/$(DEPDIR)/libcservice_la-csGline.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@mod.cservice/$(DEPDIR)/libcservice_la-cservice.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@mod.cservice/$(DEPDIR)/libcservice_la-cservice_crypt.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@mod.cservice/$(DEPDIR)/libcservice_la-networkData.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@mod.cservice/$(DEPDIR)/libcservice_la-sqlBan.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@mod.cservice/$(DEPDIR)/libcservice_la-sqlChannel.Plo@am__quote@ # am--include-marker @@ -4719,6 +4739,13 @@ mod.cservice/libcservice_la-cservice.lo: mod.cservice/cservice.cc @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcservice_la_CXXFLAGS) $(CXXFLAGS) -c -o mod.cservice/libcservice_la-cservice.lo `test -f 'mod.cservice/cservice.cc' || echo '$(srcdir)/'`mod.cservice/cservice.cc +mod.cservice/libcservice_la-cservice_crypt.lo: mod.cservice/cservice_crypt.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcservice_la_CXXFLAGS) $(CXXFLAGS) -MT mod.cservice/libcservice_la-cservice_crypt.lo -MD -MP -MF mod.cservice/$(DEPDIR)/libcservice_la-cservice_crypt.Tpo -c -o mod.cservice/libcservice_la-cservice_crypt.lo `test -f 'mod.cservice/cservice_crypt.cc' || echo '$(srcdir)/'`mod.cservice/cservice_crypt.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) mod.cservice/$(DEPDIR)/libcservice_la-cservice_crypt.Tpo mod.cservice/$(DEPDIR)/libcservice_la-cservice_crypt.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='mod.cservice/cservice_crypt.cc' object='mod.cservice/libcservice_la-cservice_crypt.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcservice_la_CXXFLAGS) $(CXXFLAGS) -c -o mod.cservice/libcservice_la-cservice_crypt.lo `test -f 'mod.cservice/cservice_crypt.cc' || echo '$(srcdir)/'`mod.cservice/cservice_crypt.cc + mod.cservice/libcservice_la-networkData.lo: mod.cservice/networkData.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcservice_la_CXXFLAGS) $(CXXFLAGS) -MT mod.cservice/libcservice_la-networkData.lo -MD -MP -MF mod.cservice/$(DEPDIR)/libcservice_la-networkData.Tpo -c -o mod.cservice/libcservice_la-networkData.lo `test -f 'mod.cservice/networkData.cc' || echo '$(srcdir)/'`mod.cservice/networkData.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) mod.cservice/$(DEPDIR)/libcservice_la-networkData.Tpo mod.cservice/$(DEPDIR)/libcservice_la-networkData.Plo @@ -4810,6 +4837,13 @@ mod.cservice/libcservice_la-BANLISTCommand.lo: mod.cservice/BANLISTCommand.cc @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcservice_la_CXXFLAGS) $(CXXFLAGS) -c -o mod.cservice/libcservice_la-BANLISTCommand.lo `test -f 'mod.cservice/BANLISTCommand.cc' || echo '$(srcdir)/'`mod.cservice/BANLISTCommand.cc +mod.cservice/libcservice_la-CERTCommand.lo: mod.cservice/CERTCommand.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcservice_la_CXXFLAGS) $(CXXFLAGS) -MT mod.cservice/libcservice_la-CERTCommand.lo -MD -MP -MF mod.cservice/$(DEPDIR)/libcservice_la-CERTCommand.Tpo -c -o mod.cservice/libcservice_la-CERTCommand.lo `test -f 'mod.cservice/CERTCommand.cc' || echo '$(srcdir)/'`mod.cservice/CERTCommand.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) mod.cservice/$(DEPDIR)/libcservice_la-CERTCommand.Tpo mod.cservice/$(DEPDIR)/libcservice_la-CERTCommand.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='mod.cservice/CERTCommand.cc' object='mod.cservice/libcservice_la-CERTCommand.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcservice_la_CXXFLAGS) $(CXXFLAGS) -c -o mod.cservice/libcservice_la-CERTCommand.lo `test -f 'mod.cservice/CERTCommand.cc' || echo '$(srcdir)/'`mod.cservice/CERTCommand.cc + mod.cservice/libcservice_la-CHANINFOCommand.lo: mod.cservice/CHANINFOCommand.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcservice_la_CXXFLAGS) $(CXXFLAGS) -MT mod.cservice/libcservice_la-CHANINFOCommand.lo -MD -MP -MF mod.cservice/$(DEPDIR)/libcservice_la-CHANINFOCommand.Tpo -c -o mod.cservice/libcservice_la-CHANINFOCommand.lo `test -f 'mod.cservice/CHANINFOCommand.cc' || echo '$(srcdir)/'`mod.cservice/CHANINFOCommand.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) mod.cservice/$(DEPDIR)/libcservice_la-CHANINFOCommand.Tpo mod.cservice/$(DEPDIR)/libcservice_la-CHANINFOCommand.Plo @@ -5587,6 +5621,13 @@ libircu/la-msg_C.lo: libircu/msg_C.cc @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libircu_la_CXXFLAGS) $(CXXFLAGS) -c -o libircu/la-msg_C.lo `test -f 'libircu/msg_C.cc' || echo '$(srcdir)/'`libircu/msg_C.cc +libircu/la-msg_CF.lo: libircu/msg_CF.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libircu_la_CXXFLAGS) $(CXXFLAGS) -MT libircu/la-msg_CF.lo -MD -MP -MF libircu/$(DEPDIR)/la-msg_CF.Tpo -c -o libircu/la-msg_CF.lo `test -f 'libircu/msg_CF.cc' || echo '$(srcdir)/'`libircu/msg_CF.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) libircu/$(DEPDIR)/la-msg_CF.Tpo libircu/$(DEPDIR)/la-msg_CF.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='libircu/msg_CF.cc' object='libircu/la-msg_CF.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libircu_la_CXXFLAGS) $(CXXFLAGS) -c -o libircu/la-msg_CF.lo `test -f 'libircu/msg_CF.cc' || echo '$(srcdir)/'`libircu/msg_CF.cc + libircu/la-msg_CM.lo: libircu/msg_CM.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libircu_la_CXXFLAGS) $(CXXFLAGS) -MT libircu/la-msg_CM.lo -MD -MP -MF libircu/$(DEPDIR)/la-msg_CM.Tpo -c -o libircu/la-msg_CM.lo `test -f 'libircu/msg_CM.cc' || echo '$(srcdir)/'`libircu/msg_CM.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) libircu/$(DEPDIR)/la-msg_CM.Tpo libircu/$(DEPDIR)/la-msg_CM.Plo @@ -6634,6 +6675,7 @@ distclean: distclean-recursive -rm -f libircu/$(DEPDIR)/la-msg_AD.Plo -rm -f libircu/$(DEPDIR)/la-msg_B.Plo -rm -f libircu/$(DEPDIR)/la-msg_C.Plo + -rm -f libircu/$(DEPDIR)/la-msg_CF.Plo -rm -f libircu/$(DEPDIR)/la-msg_CM.Plo -rm -f libircu/$(DEPDIR)/la-msg_D.Plo -rm -f libircu/$(DEPDIR)/la-msg_DS.Plo @@ -6756,6 +6798,7 @@ distclean: distclean-recursive -rm -f mod.cservice/$(DEPDIR)/libcservice_la-ADDUSERCommand.Plo -rm -f mod.cservice/$(DEPDIR)/libcservice_la-BANCommand.Plo -rm -f mod.cservice/$(DEPDIR)/libcservice_la-BANLISTCommand.Plo + -rm -f mod.cservice/$(DEPDIR)/libcservice_la-CERTCommand.Plo -rm -f mod.cservice/$(DEPDIR)/libcservice_la-CHANINFOCommand.Plo -rm -f mod.cservice/$(DEPDIR)/libcservice_la-CLEARMODECommand.Plo -rm -f mod.cservice/$(DEPDIR)/libcservice_la-DEOPCommand.Plo @@ -6811,6 +6854,7 @@ distclean: distclean-recursive -rm -f mod.cservice/$(DEPDIR)/libcservice_la-banMatcher.Plo -rm -f mod.cservice/$(DEPDIR)/libcservice_la-csGline.Plo -rm -f mod.cservice/$(DEPDIR)/libcservice_la-cservice.Plo + -rm -f mod.cservice/$(DEPDIR)/libcservice_la-cservice_crypt.Plo -rm -f mod.cservice/$(DEPDIR)/libcservice_la-networkData.Plo -rm -f mod.cservice/$(DEPDIR)/libcservice_la-sqlBan.Plo -rm -f mod.cservice/$(DEPDIR)/libcservice_la-sqlChannel.Plo @@ -7008,6 +7052,7 @@ maintainer-clean: maintainer-clean-recursive -rm -f libircu/$(DEPDIR)/la-msg_AD.Plo -rm -f libircu/$(DEPDIR)/la-msg_B.Plo -rm -f libircu/$(DEPDIR)/la-msg_C.Plo + -rm -f libircu/$(DEPDIR)/la-msg_CF.Plo -rm -f libircu/$(DEPDIR)/la-msg_CM.Plo -rm -f libircu/$(DEPDIR)/la-msg_D.Plo -rm -f libircu/$(DEPDIR)/la-msg_DS.Plo @@ -7130,6 +7175,7 @@ maintainer-clean: maintainer-clean-recursive -rm -f mod.cservice/$(DEPDIR)/libcservice_la-ADDUSERCommand.Plo -rm -f mod.cservice/$(DEPDIR)/libcservice_la-BANCommand.Plo -rm -f mod.cservice/$(DEPDIR)/libcservice_la-BANLISTCommand.Plo + -rm -f mod.cservice/$(DEPDIR)/libcservice_la-CERTCommand.Plo -rm -f mod.cservice/$(DEPDIR)/libcservice_la-CHANINFOCommand.Plo -rm -f mod.cservice/$(DEPDIR)/libcservice_la-CLEARMODECommand.Plo -rm -f mod.cservice/$(DEPDIR)/libcservice_la-DEOPCommand.Plo @@ -7185,6 +7231,7 @@ maintainer-clean: maintainer-clean-recursive -rm -f mod.cservice/$(DEPDIR)/libcservice_la-banMatcher.Plo -rm -f mod.cservice/$(DEPDIR)/libcservice_la-csGline.Plo -rm -f mod.cservice/$(DEPDIR)/libcservice_la-cservice.Plo + -rm -f mod.cservice/$(DEPDIR)/libcservice_la-cservice_crypt.Plo -rm -f mod.cservice/$(DEPDIR)/libcservice_la-networkData.Plo -rm -f mod.cservice/$(DEPDIR)/libcservice_la-sqlBan.Plo -rm -f mod.cservice/$(DEPDIR)/libcservice_la-sqlChannel.Plo diff --git a/aclocal.m4 b/aclocal.m4 index 7a1f9181..c1224da9 100644 --- a/aclocal.m4 +++ b/aclocal.m4 @@ -20,6 +20,996 @@ You have another version of autoconf. It may work, but is not guaranteed to. If you have problems, you may need to regenerate the build system entirely. To do so, use the procedure documented by the package, typically 'autoreconf'.])]) +# Portability macros for glibc argz. -*- Autoconf -*- +# +# Copyright (C) 2004-2007, 2011-2019, 2021-2024 Free Software +# Foundation, Inc. +# Written by Gary V. Vaughan +# +# This file is free software; the Free Software Foundation gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. + +# serial 2 ltargz.m4 + +AC_DEFUN([LT_FUNC_ARGZ], [ +dnl Required for use of '$SED' in Cygwin configuration. +AC_REQUIRE([AC_PROG_SED])dnl +AC_CHECK_HEADERS([argz.h], [], [], [AC_INCLUDES_DEFAULT]) + +AC_CHECK_TYPES([error_t], + [], + [AC_DEFINE([error_t], [int], + [Define to a type to use for 'error_t' if it is not otherwise available.]) + AC_DEFINE([__error_t_defined], [1], [Define so that glibc/gnulib argp.h + does not typedef error_t.])], + [#if defined(HAVE_ARGZ_H) +# include +#endif]) + +LT_ARGZ_H= +AC_CHECK_FUNCS([argz_add argz_append argz_count argz_create_sep argz_insert \ + argz_next argz_stringify], [], [LT_ARGZ_H=lt__argz.h; AC_LIBOBJ([lt__argz])]) + +dnl if have system argz functions, allow forced use of +dnl libltdl-supplied implementation (and default to do so +dnl on "known bad" systems). Could use a runtime check, but +dnl (a) detecting malloc issues is notoriously unreliable +dnl (b) only known system that declares argz functions, +dnl provides them, yet they are broken, is cygwin +dnl releases prior to 16-Mar-2007 (1.5.24 and earlier) +dnl So, it's more straightforward simply to special case +dnl this for known bad systems. +AS_IF([test -z "$LT_ARGZ_H"], + [AC_CACHE_CHECK( + [if argz actually works], + [lt_cv_sys_argz_works], + [[case $host_os in #( + *cygwin*) + lt_cv_sys_argz_works=no + if test no != "$cross_compiling"; then + lt_cv_sys_argz_works="guessing no" + else + lt_sed_extract_leading_digits='s/^\([0-9\.]*\).*/\1/' + save_IFS=$IFS + IFS=-. + set x `uname -r | $SED -e "$lt_sed_extract_leading_digits"` + IFS=$save_IFS + lt_os_major=${2-0} + lt_os_minor=${3-0} + lt_os_micro=${4-0} + if test 1 -lt "$lt_os_major" \ + || { test 1 -eq "$lt_os_major" \ + && { test 5 -lt "$lt_os_minor" \ + || { test 5 -eq "$lt_os_minor" \ + && test 24 -lt "$lt_os_micro"; }; }; }; then + lt_cv_sys_argz_works=yes + fi + fi + ;; #( + *) lt_cv_sys_argz_works=yes ;; + esac]]) + AS_IF([test yes = "$lt_cv_sys_argz_works"], + [AC_DEFINE([HAVE_WORKING_ARGZ], 1, + [This value is set to 1 to indicate that the system argz facility works])], + [LT_ARGZ_H=lt__argz.h + AC_LIBOBJ([lt__argz])])]) + +AC_SUBST([LT_ARGZ_H]) +]) + +# ltdl.m4 - Configure ltdl for the target system. -*-Autoconf-*- +# +# Copyright (C) 1999-2008, 2011-2019, 2021-2024 Free Software +# Foundation, Inc. +# Written by Thomas Tanner, 1999 +# +# This file is free software; the Free Software Foundation gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. + +# serial 24 LTDL_INIT + +# LT_CONFIG_LTDL_DIR(DIRECTORY, [LTDL-MODE]) +# ------------------------------------------ +# DIRECTORY contains the libltdl sources. It is okay to call this +# function multiple times, as long as the same DIRECTORY is always given. +AC_DEFUN([LT_CONFIG_LTDL_DIR], +[AC_BEFORE([$0], [LTDL_INIT]) +_$0($*) +])# LT_CONFIG_LTDL_DIR + +# We break this out into a separate macro, so that we can call it safely +# internally without being caught accidentally by the sed scan in libtoolize. +m4_defun([_LT_CONFIG_LTDL_DIR], +[dnl remove trailing slashes +m4_pushdef([_ARG_DIR], m4_bpatsubst([$1], [/*$])) +m4_case(_LTDL_DIR, + [], [dnl only set lt_ltdl_dir if _ARG_DIR is not simply '.' + m4_if(_ARG_DIR, [.], + [], + [m4_define([_LTDL_DIR], _ARG_DIR) + _LT_SHELL_INIT([lt_ltdl_dir=']_ARG_DIR['])])], + [m4_if(_ARG_DIR, _LTDL_DIR, + [], + [m4_fatal([multiple libltdl directories: ']_LTDL_DIR[', ']_ARG_DIR['])])]) +m4_popdef([_ARG_DIR]) +])# _LT_CONFIG_LTDL_DIR + +# Initialise: +m4_define([_LTDL_DIR], []) + + +# _LT_BUILD_PREFIX +# ---------------- +# If Autoconf is new enough, expand to '$(top_build_prefix)', otherwise +# to '$(top_builddir)/'. +m4_define([_LT_BUILD_PREFIX], +[m4_ifdef([AC_AUTOCONF_VERSION], + [m4_if(m4_version_compare(m4_defn([AC_AUTOCONF_VERSION]), [2.62]), + [-1], [m4_ifdef([_AC_HAVE_TOP_BUILD_PREFIX], + [$(top_build_prefix)], + [$(top_builddir)/])], + [$(top_build_prefix)])], + [$(top_builddir)/])[]dnl +]) + + +# LTDL_CONVENIENCE +# ---------------- +# sets LIBLTDL to the link flags for the libltdl convenience library and +# LTDLINCL to the include flags for the libltdl header and adds +# --enable-ltdl-convenience to the configure arguments. Note that +# AC_CONFIG_SUBDIRS is not called here. LIBLTDL will be prefixed with +# '$(top_build_prefix)' if available, otherwise with '$(top_builddir)/', +# and LTDLINCL will be prefixed with '$(top_srcdir)/' (note the single +# quotes!). If your package is not flat and you're not using automake, +# define top_build_prefix, top_builddir, and top_srcdir appropriately +# in your Makefiles. +AC_DEFUN([LTDL_CONVENIENCE], +[AC_BEFORE([$0], [LTDL_INIT])dnl +dnl Although the argument is deprecated and no longer documented, +dnl LTDL_CONVENIENCE used to take a DIRECTORY orgument, if we have one +dnl here make sure it is the same as any other declaration of libltdl's +dnl location! This also ensures lt_ltdl_dir is set when configure.ac is +dnl not yet using an explicit LT_CONFIG_LTDL_DIR. +m4_ifval([$1], [_LT_CONFIG_LTDL_DIR([$1])])dnl +_$0() +])# LTDL_CONVENIENCE + +# AC_LIBLTDL_CONVENIENCE accepted a directory argument in older libtools, +# now we have LT_CONFIG_LTDL_DIR: +AU_DEFUN([AC_LIBLTDL_CONVENIENCE], +[_LT_CONFIG_LTDL_DIR([m4_default([$1], [libltdl])]) +_LTDL_CONVENIENCE]) + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBLTDL_CONVENIENCE], []) + + +# _LTDL_CONVENIENCE +# ----------------- +# Code shared by LTDL_CONVENIENCE and LTDL_INIT([convenience]). +m4_defun([_LTDL_CONVENIENCE], +[case $enable_ltdl_convenience in + no) AC_MSG_ERROR([this package needs a convenience libltdl]) ;; + "") enable_ltdl_convenience=yes + ac_configure_args="$ac_configure_args --enable-ltdl-convenience" ;; +esac +LIBLTDL='_LT_BUILD_PREFIX'"${lt_ltdl_dir+$lt_ltdl_dir/}libltdlc.la" +LTDLDEPS=$LIBLTDL +LTDLINCL='-I$(top_srcdir)'"${lt_ltdl_dir+/$lt_ltdl_dir}" + +AC_SUBST([LIBLTDL]) +AC_SUBST([LTDLDEPS]) +AC_SUBST([LTDLINCL]) + +# For backwards non-gettext consistent compatibility... +INCLTDL=$LTDLINCL +AC_SUBST([INCLTDL]) +])# _LTDL_CONVENIENCE + + +# LTDL_INSTALLABLE +# ---------------- +# sets LIBLTDL to the link flags for the libltdl installable library +# and LTDLINCL to the include flags for the libltdl header and adds +# --enable-ltdl-install to the configure arguments. Note that +# AC_CONFIG_SUBDIRS is not called from here. If an installed libltdl +# is not found, LIBLTDL will be prefixed with '$(top_build_prefix)' if +# available, otherwise with '$(top_builddir)/', and LTDLINCL will be +# prefixed with '$(top_srcdir)/' (note the single quotes!). If your +# package is not flat and you're not using automake, define top_build_prefix, +# top_builddir, and top_srcdir appropriately in your Makefiles. +# In the future, this macro may have to be called after LT_INIT. +AC_DEFUN([LTDL_INSTALLABLE], +[AC_BEFORE([$0], [LTDL_INIT])dnl +dnl Although the argument is deprecated and no longer documented, +dnl LTDL_INSTALLABLE used to take a DIRECTORY orgument, if we have one +dnl here make sure it is the same as any other declaration of libltdl's +dnl location! This also ensures lt_ltdl_dir is set when configure.ac is +dnl not yet using an explicit LT_CONFIG_LTDL_DIR. +m4_ifval([$1], [_LT_CONFIG_LTDL_DIR([$1])])dnl +_$0() +])# LTDL_INSTALLABLE + +# AC_LIBLTDL_INSTALLABLE accepted a directory argument in older libtools, +# now we have LT_CONFIG_LTDL_DIR: +AU_DEFUN([AC_LIBLTDL_INSTALLABLE], +[_LT_CONFIG_LTDL_DIR([m4_default([$1], [libltdl])]) +_LTDL_INSTALLABLE]) + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBLTDL_INSTALLABLE], []) + + +# _LTDL_INSTALLABLE +# ----------------- +# Code shared by LTDL_INSTALLABLE and LTDL_INIT([installable]). +m4_defun([_LTDL_INSTALLABLE], +[if test -f "$prefix/lib/libltdl.la"; then + lt_save_LDFLAGS=$LDFLAGS + LDFLAGS="-L$prefix/lib $LDFLAGS" + AC_CHECK_LIB([ltdl], [lt_dlinit], [lt_lib_ltdl=yes]) + LDFLAGS=$lt_save_LDFLAGS + if test yes = "${lt_lib_ltdl-no}"; then + if test yes != "$enable_ltdl_install"; then + # Don't overwrite $prefix/lib/libltdl.la without --enable-ltdl-install + AC_MSG_WARN([not overwriting libltdl at $prefix, force with '--enable-ltdl-install']) + enable_ltdl_install=no + fi + elif test no = "$enable_ltdl_install"; then + AC_MSG_WARN([libltdl not installed, but installation disabled]) + fi +fi + +# If configure.ac declared an installable ltdl, and the user didn't override +# with --disable-ltdl-install, we will install the shipped libltdl. +case $enable_ltdl_install in + no) ac_configure_args="$ac_configure_args --enable-ltdl-install=no" + LIBLTDL=-lltdl + LTDLDEPS= + LTDLINCL= + ;; + *) enable_ltdl_install=yes + ac_configure_args="$ac_configure_args --enable-ltdl-install" + LIBLTDL='_LT_BUILD_PREFIX'"${lt_ltdl_dir+$lt_ltdl_dir/}libltdl.la" + LTDLDEPS=$LIBLTDL + LTDLINCL='-I$(top_srcdir)'"${lt_ltdl_dir+/$lt_ltdl_dir}" + ;; +esac + +AC_SUBST([LIBLTDL]) +AC_SUBST([LTDLDEPS]) +AC_SUBST([LTDLINCL]) + +# For backwards non-gettext consistent compatibility... +INCLTDL=$LTDLINCL +AC_SUBST([INCLTDL]) +])# LTDL_INSTALLABLE + + +# _LTDL_MODE_DISPATCH +# ------------------- +m4_define([_LTDL_MODE_DISPATCH], +[dnl If _LTDL_DIR is '.', then we are configuring libltdl itself: +m4_if(_LTDL_DIR, [], + [], + dnl if _LTDL_MODE was not set already, the default value is 'subproject': + [m4_case(m4_default(_LTDL_MODE, [subproject]), + [subproject], [AC_CONFIG_SUBDIRS(_LTDL_DIR) + _LT_SHELL_INIT([lt_dlopen_dir=$lt_ltdl_dir])], + [nonrecursive], [_LT_SHELL_INIT([lt_dlopen_dir=$lt_ltdl_dir; lt_libobj_prefix=$lt_ltdl_dir/])], + [recursive], [], + [m4_fatal([unknown libltdl mode: ]_LTDL_MODE)])])dnl +dnl Be careful not to expand twice: +m4_define([$0], []) +])# _LTDL_MODE_DISPATCH + + +# _LT_LIBOBJ(MODULE_NAME) +# ----------------------- +# Like AC_LIBOBJ, except that MODULE_NAME goes into _LT_LIBOBJS instead +# of into LIBOBJS. +AC_DEFUN([_LT_LIBOBJ], [ + m4_pattern_allow([^_LT_LIBOBJS$]) + _LT_LIBOBJS="$_LT_LIBOBJS $1.$ac_objext" +])# _LT_LIBOBJS + + +# LTDL_INIT([OPTIONS]) +# -------------------- +# Clients of libltdl can use this macro to allow the installer to +# choose between a shipped copy of the ltdl sources or a preinstalled +# version of the library. If the shipped ltdl sources are not in a +# subdirectory named libltdl, the directory name must be given by +# LT_CONFIG_LTDL_DIR. +AC_DEFUN([LTDL_INIT], +[dnl Parse OPTIONS +_LT_SET_OPTIONS([$0], [$1]) + +dnl We need to keep our own list of libobjs separate from our parent project, +dnl and the easiest way to do that is redefine the AC_LIBOBJs macro while +dnl we look for our own LIBOBJs. +m4_pushdef([AC_LIBOBJ], m4_defn([_LT_LIBOBJ])) +m4_pushdef([AC_LIBSOURCES]) + +dnl If not otherwise defined, default to the 1.5.x compatible subproject mode: +m4_if(_LTDL_MODE, [], + [m4_define([_LTDL_MODE], m4_default([$2], [subproject])) + m4_if([-1], [m4_bregexp(_LTDL_MODE, [\(subproject\|\(non\)?recursive\)])], + [m4_fatal([unknown libltdl mode: ]_LTDL_MODE)])]) + +AC_ARG_WITH([included_ltdl], + [AS_HELP_STRING([--with-included-ltdl], + [use the GNU ltdl sources included here])]) + +if test yes != "$with_included_ltdl"; then + # We are not being forced to use the included libltdl sources, so + # decide whether there is a useful installed version we can use. + AC_CHECK_HEADER([ltdl.h], + [AC_CHECK_DECL([lt_dlinterface_register], + [AC_CHECK_LIB([ltdl], [lt_dladvise_preload], + [with_included_ltdl=no], + [with_included_ltdl=yes])], + [with_included_ltdl=yes], + [AC_INCLUDES_DEFAULT + #include ])], + [with_included_ltdl=yes], + [AC_INCLUDES_DEFAULT] + ) +fi + +dnl If neither LT_CONFIG_LTDL_DIR, LTDL_CONVENIENCE nor LTDL_INSTALLABLE +dnl was called yet, then for old times' sake, we assume libltdl is in an +dnl eponymous directory: +AC_PROVIDE_IFELSE([LT_CONFIG_LTDL_DIR], [], [_LT_CONFIG_LTDL_DIR([libltdl])]) + +AC_ARG_WITH([ltdl_include], + [AS_HELP_STRING([--with-ltdl-include=DIR], + [use the ltdl headers installed in DIR])]) + +if test -n "$with_ltdl_include"; then + if test -f "$with_ltdl_include/ltdl.h"; then : + else + AC_MSG_ERROR([invalid ltdl include directory: '$with_ltdl_include']) + fi +else + with_ltdl_include=no +fi + +AC_ARG_WITH([ltdl_lib], + [AS_HELP_STRING([--with-ltdl-lib=DIR], + [use the libltdl.la installed in DIR])]) + +if test -n "$with_ltdl_lib"; then + if test -f "$with_ltdl_lib/libltdl.la"; then : + else + AC_MSG_ERROR([invalid ltdl library directory: '$with_ltdl_lib']) + fi +else + with_ltdl_lib=no +fi + +case ,$with_included_ltdl,$with_ltdl_include,$with_ltdl_lib, in + ,yes,no,no,) + m4_case(m4_default(_LTDL_TYPE, [convenience]), + [convenience], [_LTDL_CONVENIENCE], + [installable], [_LTDL_INSTALLABLE], + [m4_fatal([unknown libltdl build type: ]_LTDL_TYPE)]) + ;; + ,no,no,no,) + # If the included ltdl is not to be used, then use the + # preinstalled libltdl we found. + AC_DEFINE([HAVE_LTDL], [1], + [Define this if a modern libltdl is already installed]) + LIBLTDL=-lltdl + LTDLDEPS= + LTDLINCL= + ;; + ,no*,no,*) + AC_MSG_ERROR(['--with-ltdl-include' and '--with-ltdl-lib' options must be used together]) + ;; + *) with_included_ltdl=no + LIBLTDL="-L$with_ltdl_lib -lltdl" + LTDLDEPS= + LTDLINCL=-I$with_ltdl_include + ;; +esac +INCLTDL=$LTDLINCL + +# Report our decision... +AC_MSG_CHECKING([where to find libltdl headers]) +AC_MSG_RESULT([$LTDLINCL]) +AC_MSG_CHECKING([where to find libltdl library]) +AC_MSG_RESULT([$LIBLTDL]) + +_LTDL_SETUP + +dnl restore autoconf definition. +m4_popdef([AC_LIBOBJ]) +m4_popdef([AC_LIBSOURCES]) + +AC_CONFIG_COMMANDS_PRE([ + _ltdl_libobjs= + _ltdl_ltlibobjs= + if test -n "$_LT_LIBOBJS"; then + # Remove the extension. + _lt_sed_drop_objext='s/\.o$//;s/\.obj$//' + for i in `for i in $_LT_LIBOBJS; do echo "$i"; done | $SED "$_lt_sed_drop_objext" | sort -u`; do + _ltdl_libobjs="$_ltdl_libobjs $lt_libobj_prefix$i.$ac_objext" + _ltdl_ltlibobjs="$_ltdl_ltlibobjs $lt_libobj_prefix$i.lo" + done + fi + AC_SUBST([ltdl_LIBOBJS], [$_ltdl_libobjs]) + AC_SUBST([ltdl_LTLIBOBJS], [$_ltdl_ltlibobjs]) +]) + +# Only expand once: +m4_define([LTDL_INIT]) +])# LTDL_INIT + +# Old names: +AU_DEFUN([AC_LIB_LTDL], [LTDL_INIT($@)]) +AU_DEFUN([AC_WITH_LTDL], [LTDL_INIT($@)]) +AU_DEFUN([LT_WITH_LTDL], [LTDL_INIT($@)]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIB_LTDL], []) +dnl AC_DEFUN([AC_WITH_LTDL], []) +dnl AC_DEFUN([LT_WITH_LTDL], []) + + +# _LTDL_SETUP +# ----------- +# Perform all the checks necessary for compilation of the ltdl objects +# -- including compiler checks and header checks. This is a public +# interface mainly for the benefit of libltdl's own configure.ac, most +# other users should call LTDL_INIT instead. +AC_DEFUN([_LTDL_SETUP], +[AC_REQUIRE([AC_PROG_CC])dnl +AC_REQUIRE([LT_SYS_MODULE_EXT])dnl +AC_REQUIRE([LT_SYS_MODULE_PATH])dnl +AC_REQUIRE([LT_SYS_DLSEARCH_PATH])dnl +AC_REQUIRE([LT_LIB_DLLOAD])dnl +AC_REQUIRE([LT_SYS_SYMBOL_USCORE])dnl +AC_REQUIRE([LT_FUNC_DLSYM_USCORE])dnl +AC_REQUIRE([LT_SYS_DLOPEN_DEPLIBS])dnl +AC_REQUIRE([LT_FUNC_ARGZ])dnl + +m4_require([_LT_CHECK_OBJDIR])dnl +m4_require([_LT_HEADER_DLFCN])dnl +m4_require([_LT_CHECK_DLPREOPEN])dnl +m4_require([_LT_DECL_SED])dnl + +dnl Don't require this, or it will be expanded earlier than the code +dnl that sets the variables it relies on: +_LT_ENABLE_INSTALL + +dnl _LTDL_MODE specific code must be called at least once: +_LTDL_MODE_DISPATCH + +# In order that ltdl.c can compile, find out the first AC_CONFIG_HEADERS +# the user used. This is so that ltdl.h can pick up the parent projects +# config.h file, The first file in AC_CONFIG_HEADERS must contain the +# definitions required by ltdl.c. +# FIXME: Remove use of undocumented AC_LIST_HEADERS (2.59 compatibility). +AC_CONFIG_COMMANDS_PRE([dnl +m4_pattern_allow([^LT_CONFIG_H$])dnl +m4_ifset([AH_HEADER], + [LT_CONFIG_H=AH_HEADER], + [m4_ifset([AC_LIST_HEADERS], + [LT_CONFIG_H=`echo "AC_LIST_HEADERS" | $SED 's|^[[ ]]*||;s|[[ :]].*$||'`], + [])])]) +AC_SUBST([LT_CONFIG_H]) + +AC_CHECK_HEADERS([unistd.h dl.h sys/dl.h dld.h mach-o/dyld.h dirent.h], + [], [], [AC_INCLUDES_DEFAULT]) + +AC_CHECK_FUNCS([closedir opendir readdir], [], [AC_LIBOBJ([lt__dirent])]) +AC_CHECK_FUNCS([strlcat strlcpy], [], [AC_LIBOBJ([lt__strl])]) + +m4_pattern_allow([LT_LIBEXT])dnl +AC_DEFINE_UNQUOTED([LT_LIBEXT],["$libext"],[The archive extension]) + +name= +eval "lt_libprefix=\"$libname_spec\"" +m4_pattern_allow([LT_LIBPREFIX])dnl +AC_DEFINE_UNQUOTED([LT_LIBPREFIX],["$lt_libprefix"],[The archive prefix]) + +name=ltdl +eval "LTDLOPEN=\"$libname_spec\"" +AC_SUBST([LTDLOPEN]) +])# _LTDL_SETUP + + +# _LT_ENABLE_INSTALL +# ------------------ +m4_define([_LT_ENABLE_INSTALL], +[AC_ARG_ENABLE([ltdl-install], + [AS_HELP_STRING([--enable-ltdl-install], [install libltdl])]) + +case ,$enable_ltdl_install,$enable_ltdl_convenience in + *yes*) ;; + *) enable_ltdl_convenience=yes ;; +esac + +m4_ifdef([AM_CONDITIONAL], +[AM_CONDITIONAL(INSTALL_LTDL, test no != "${enable_ltdl_install-no}") + AM_CONDITIONAL(CONVENIENCE_LTDL, test no != "${enable_ltdl_convenience-no}") + AM_CONDITIONAL(LTARGZH_EXISTS, test -n "$LT_ARGZ_H")]) +])# _LT_ENABLE_INSTALL + + +# LT_SYS_DLOPEN_DEPLIBS +# --------------------- +AC_DEFUN([LT_SYS_DLOPEN_DEPLIBS], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +AC_CACHE_CHECK([whether deplibs are loaded by dlopen], + [lt_cv_sys_dlopen_deplibs], + [# PORTME does your system automatically load deplibs for dlopen? + # or its logical equivalent (e.g. shl_load for HP-UX < 11) + # For now, we just catch OSes we know something about -- in the + # future, we'll try test this programmatically. + lt_cv_sys_dlopen_deplibs=unknown + case $host_os in + aix3*|aix4.1.*|aix4.2.*) + # Unknown whether this is true for these versions of AIX, but + # we want this 'case' here to explicitly catch those versions. + lt_cv_sys_dlopen_deplibs=unknown + ;; + aix[[4-9]]*) + lt_cv_sys_dlopen_deplibs=yes + ;; + amigaos*) + case $host_cpu in + powerpc) + lt_cv_sys_dlopen_deplibs=no + ;; + esac + ;; + darwin*) + # Assuming the user has installed a libdl from somewhere, this is true + # If you are looking for one http://www.opendarwin.org/projects/dlcompat + lt_cv_sys_dlopen_deplibs=yes + ;; + freebsd* | dragonfly* | midnightbsd*) + lt_cv_sys_dlopen_deplibs=yes + ;; + gnu* | linux* | k*bsd*-gnu | kopensolaris*-gnu) + # GNU and its variants, using gnu ld.so (Glibc) + lt_cv_sys_dlopen_deplibs=yes + ;; + hpux10*|hpux11*) + lt_cv_sys_dlopen_deplibs=yes + ;; + interix*) + lt_cv_sys_dlopen_deplibs=yes + ;; + irix[[12345]]*|irix6.[[01]]*) + # Catch all versions of IRIX before 6.2, and indicate that we don't + # know how it worked for any of those versions. + lt_cv_sys_dlopen_deplibs=unknown + ;; + irix*) + # The case above catches anything before 6.2, and it's known that + # at 6.2 and later dlopen does load deplibs. + lt_cv_sys_dlopen_deplibs=yes + ;; + *-mlibc) + lt_cv_sys_dlopen_deplibs=yes + ;; + netbsd* | netbsdelf*-gnu) + lt_cv_sys_dlopen_deplibs=yes + ;; + openbsd*) + lt_cv_sys_dlopen_deplibs=yes + ;; + osf[[1234]]*) + # dlopen did load deplibs (at least at 4.x), but until the 5.x series, + # it did *not* use an RPATH in a shared library to find objects the + # library depends on, so we explicitly say 'no'. + lt_cv_sys_dlopen_deplibs=no + ;; + osf5.0|osf5.0a|osf5.1) + # dlopen *does* load deplibs and with the right loader patch applied + # it even uses RPATH in a shared library to search for shared objects + # that the library depends on, but there's no easy way to know if that + # patch is installed. Since this is the case, all we can really + # say is unknown -- it depends on the patch being installed. If + # it is, this changes to 'yes'. Without it, it would be 'no'. + lt_cv_sys_dlopen_deplibs=unknown + ;; + osf*) + # the two cases above should catch all versions of osf <= 5.1. Read + # the comments above for what we know about them. + # At > 5.1, deplibs are loaded *and* any RPATH in a shared library + # is used to find them so we can finally say 'yes'. + lt_cv_sys_dlopen_deplibs=yes + ;; + qnx*) + lt_cv_sys_dlopen_deplibs=yes + ;; + solaris*) + lt_cv_sys_dlopen_deplibs=yes + ;; + sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + libltdl_cv_sys_dlopen_deplibs=yes + ;; + esac + ]) +if test yes != "$lt_cv_sys_dlopen_deplibs"; then + AC_DEFINE([LTDL_DLOPEN_DEPLIBS], [1], + [Define if the OS needs help to load dependent libraries for dlopen().]) +fi +])# LT_SYS_DLOPEN_DEPLIBS + +# Old name: +AU_ALIAS([AC_LTDL_SYS_DLOPEN_DEPLIBS], [LT_SYS_DLOPEN_DEPLIBS]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LTDL_SYS_DLOPEN_DEPLIBS], []) + + +# LT_SYS_MODULE_EXT +# ----------------- +AC_DEFUN([LT_SYS_MODULE_EXT], +[m4_require([_LT_SYS_DYNAMIC_LINKER])dnl +AC_CACHE_CHECK([what extension is used for runtime loadable modules], + [libltdl_cv_shlibext], +[ +module=yes +eval libltdl_cv_shlibext=$shrext_cmds +module=no +eval libltdl_cv_shrext=$shrext_cmds + ]) +if test -n "$libltdl_cv_shlibext"; then + m4_pattern_allow([LT_MODULE_EXT])dnl + AC_DEFINE_UNQUOTED([LT_MODULE_EXT], ["$libltdl_cv_shlibext"], + [Define to the extension used for runtime loadable modules, say, ".so".]) +fi +if test "$libltdl_cv_shrext" != "$libltdl_cv_shlibext"; then + m4_pattern_allow([LT_SHARED_EXT])dnl + AC_DEFINE_UNQUOTED([LT_SHARED_EXT], ["$libltdl_cv_shrext"], + [Define to the shared library suffix, say, ".dylib".]) +fi +if test -n "$shared_archive_member_spec"; then + m4_pattern_allow([LT_SHARED_LIB_MEMBER])dnl + AC_DEFINE_UNQUOTED([LT_SHARED_LIB_MEMBER], ["($shared_archive_member_spec.o)"], + [Define to the shared archive member specification, say "(shr.o)".]) +fi +])# LT_SYS_MODULE_EXT + +# Old name: +AU_ALIAS([AC_LTDL_SHLIBEXT], [LT_SYS_MODULE_EXT]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LTDL_SHLIBEXT], []) + + +# LT_SYS_MODULE_PATH +# ------------------ +AC_DEFUN([LT_SYS_MODULE_PATH], +[m4_require([_LT_SYS_DYNAMIC_LINKER])dnl +AC_CACHE_CHECK([what variable specifies run-time module search path], + [lt_cv_module_path_var], [lt_cv_module_path_var=$shlibpath_var]) +if test -n "$lt_cv_module_path_var"; then + m4_pattern_allow([LT_MODULE_PATH_VAR])dnl + AC_DEFINE_UNQUOTED([LT_MODULE_PATH_VAR], ["$lt_cv_module_path_var"], + [Define to the name of the environment variable that determines the run-time module search path.]) +fi +])# LT_SYS_MODULE_PATH + +# Old name: +AU_ALIAS([AC_LTDL_SHLIBPATH], [LT_SYS_MODULE_PATH]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LTDL_SHLIBPATH], []) + + +# LT_SYS_DLSEARCH_PATH +# -------------------- +AC_DEFUN([LT_SYS_DLSEARCH_PATH], +[m4_require([_LT_SYS_DYNAMIC_LINKER])dnl +AC_CACHE_CHECK([for the default library search path], + [lt_cv_sys_dlsearch_path], + [lt_cv_sys_dlsearch_path=$sys_lib_dlsearch_path_spec]) +if test -n "$lt_cv_sys_dlsearch_path"; then + sys_dlsearch_path= + for dir in $lt_cv_sys_dlsearch_path; do + if test -z "$sys_dlsearch_path"; then + sys_dlsearch_path=$dir + else + sys_dlsearch_path=$sys_dlsearch_path$PATH_SEPARATOR$dir + fi + done + m4_pattern_allow([LT_DLSEARCH_PATH])dnl + AC_DEFINE_UNQUOTED([LT_DLSEARCH_PATH], ["$sys_dlsearch_path"], + [Define to the system default library search path.]) +fi +])# LT_SYS_DLSEARCH_PATH + +# Old name: +AU_ALIAS([AC_LTDL_SYSSEARCHPATH], [LT_SYS_DLSEARCH_PATH]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LTDL_SYSSEARCHPATH], []) + + +# _LT_CHECK_DLPREOPEN +# ------------------- +m4_defun([_LT_CHECK_DLPREOPEN], +[m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl +AC_CACHE_CHECK([whether libtool supports -dlopen/-dlpreopen], + [libltdl_cv_preloaded_symbols], + [if test -n "$lt_cv_sys_global_symbol_pipe"; then + libltdl_cv_preloaded_symbols=yes + else + libltdl_cv_preloaded_symbols=no + fi + ]) +if test yes = "$libltdl_cv_preloaded_symbols"; then + AC_DEFINE([HAVE_PRELOADED_SYMBOLS], [1], + [Define if libtool can extract symbol lists from object files.]) +fi +])# _LT_CHECK_DLPREOPEN + + +# LT_LIB_DLLOAD +# ------------- +AC_DEFUN([LT_LIB_DLLOAD], +[m4_pattern_allow([^LT_DLLOADERS$]) +LT_DLLOADERS= +AC_SUBST([LT_DLLOADERS]) + +AC_LANG_PUSH([C]) +lt_dlload_save_LIBS=$LIBS + +LIBADD_DLOPEN= +AC_SEARCH_LIBS([dlopen], [dl], + [AC_DEFINE([HAVE_LIBDL], [1], + [Define if you have the libdl library or equivalent.]) + if test "$ac_cv_search_dlopen" != "none required"; then + LIBADD_DLOPEN=-ldl + fi + libltdl_cv_lib_dl_dlopen=yes + LT_DLLOADERS="$LT_DLLOADERS ${lt_dlopen_dir+$lt_dlopen_dir/}dlopen.la"], + [AC_LINK_IFELSE([AC_LANG_PROGRAM([[#if HAVE_DLFCN_H +# include +#endif + ]], [[dlopen(0, 0);]])], + [AC_DEFINE([HAVE_LIBDL], [1], + [Define if you have the libdl library or equivalent.]) + libltdl_cv_func_dlopen=yes + LT_DLLOADERS="$LT_DLLOADERS ${lt_dlopen_dir+$lt_dlopen_dir/}dlopen.la"], + [AC_CHECK_LIB([svld], [dlopen], + [AC_DEFINE([HAVE_LIBDL], [1], + [Define if you have the libdl library or equivalent.]) + LIBADD_DLOPEN=-lsvld libltdl_cv_func_dlopen=yes + LT_DLLOADERS="$LT_DLLOADERS ${lt_dlopen_dir+$lt_dlopen_dir/}dlopen.la"])])]) +if test yes = "$libltdl_cv_func_dlopen" || test yes = "$libltdl_cv_lib_dl_dlopen" +then + lt_save_LIBS=$LIBS + LIBS="$LIBS $LIBADD_DLOPEN" + AC_CHECK_FUNCS([dlerror]) + LIBS=$lt_save_LIBS +fi +AC_SUBST([LIBADD_DLOPEN]) + +LIBADD_SHL_LOAD= +AC_CHECK_FUNC([shl_load], + [AC_DEFINE([HAVE_SHL_LOAD], [1], + [Define if you have the shl_load function.]) + LT_DLLOADERS="$LT_DLLOADERS ${lt_dlopen_dir+$lt_dlopen_dir/}shl_load.la"], + [AC_CHECK_LIB([dld], [shl_load], + [AC_DEFINE([HAVE_SHL_LOAD], [1], + [Define if you have the shl_load function.]) + LT_DLLOADERS="$LT_DLLOADERS ${lt_dlopen_dir+$lt_dlopen_dir/}shl_load.la" + LIBADD_SHL_LOAD=-ldld])]) +AC_SUBST([LIBADD_SHL_LOAD]) + +case $host_os in +darwin[[1567]].*) +# We only want this for pre-Mac OS X 10.4. + AC_CHECK_FUNC([_dyld_func_lookup], + [AC_DEFINE([HAVE_DYLD], [1], + [Define if you have the _dyld_func_lookup function.]) + LT_DLLOADERS="$LT_DLLOADERS ${lt_dlopen_dir+$lt_dlopen_dir/}dyld.la"]) + ;; +beos*) + LT_DLLOADERS="$LT_DLLOADERS ${lt_dlopen_dir+$lt_dlopen_dir/}load_add_on.la" + ;; +cygwin* | mingw* | windows* | pw32*) + AC_CHECK_DECLS([cygwin_conv_path], [], [], [[#include ]]) + LT_DLLOADERS="$LT_DLLOADERS ${lt_dlopen_dir+$lt_dlopen_dir/}loadlibrary.la" + ;; +esac + +AC_CHECK_LIB([dld], [dld_link], + [AC_DEFINE([HAVE_DLD], [1], + [Define if you have the GNU dld library.]) + LT_DLLOADERS="$LT_DLLOADERS ${lt_dlopen_dir+$lt_dlopen_dir/}dld_link.la"]) +AC_SUBST([LIBADD_DLD_LINK]) + +m4_pattern_allow([^LT_DLPREOPEN$]) +LT_DLPREOPEN= +if test -n "$LT_DLLOADERS" +then + for lt_loader in $LT_DLLOADERS; do + LT_DLPREOPEN="$LT_DLPREOPEN-dlpreopen $lt_loader " + done + AC_DEFINE([HAVE_LIBDLLOADER], [1], + [Define if libdlloader will be built on this platform]) +fi +AC_SUBST([LT_DLPREOPEN]) + +dnl This isn't used anymore, but set it for backwards compatibility +LIBADD_DL="$LIBADD_DLOPEN $LIBADD_SHL_LOAD" +AC_SUBST([LIBADD_DL]) + +LIBS=$lt_dlload_save_LIBS +AC_LANG_POP +])# LT_LIB_DLLOAD + +# Old name: +AU_ALIAS([AC_LTDL_DLLIB], [LT_LIB_DLLOAD]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LTDL_DLLIB], []) + + +# LT_SYS_SYMBOL_USCORE +# -------------------- +# does the compiler prefix global symbols with an underscore? +AC_DEFUN([LT_SYS_SYMBOL_USCORE], +[m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl +AC_CACHE_CHECK([for _ prefix in compiled symbols], + [lt_cv_sys_symbol_underscore], + [lt_cv_sys_symbol_underscore=no + cat > conftest.$ac_ext <<_LT_EOF +void nm_test_func(){} +int main(void){nm_test_func;return 0;} +_LT_EOF + if AC_TRY_EVAL(ac_compile); then + # Now try to grab the symbols. + ac_nlist=conftest.nm + if AC_TRY_EVAL(NM conftest.$ac_objext \| $lt_cv_sys_global_symbol_pipe \> $ac_nlist) && test -s "$ac_nlist"; then + # See whether the symbols have a leading underscore. + if grep '^. _nm_test_func' "$ac_nlist" >/dev/null; then + lt_cv_sys_symbol_underscore=yes + else + if grep '^. nm_test_func ' "$ac_nlist" >/dev/null; then + : + else + echo "configure: cannot find nm_test_func in $ac_nlist" >&AS_MESSAGE_LOG_FD + fi + fi + else + echo "configure: cannot run $lt_cv_sys_global_symbol_pipe" >&AS_MESSAGE_LOG_FD + fi + else + echo "configure: failed program was:" >&AS_MESSAGE_LOG_FD + cat conftest.c >&AS_MESSAGE_LOG_FD + fi + rm -rf conftest* + ]) + sys_symbol_underscore=$lt_cv_sys_symbol_underscore + AC_SUBST([sys_symbol_underscore]) +])# LT_SYS_SYMBOL_USCORE + +# Old name: +AU_ALIAS([AC_LTDL_SYMBOL_USCORE], [LT_SYS_SYMBOL_USCORE]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LTDL_SYMBOL_USCORE], []) + + +# LT_FUNC_DLSYM_USCORE +# -------------------- +AC_DEFUN([LT_FUNC_DLSYM_USCORE], +[AC_REQUIRE([_LT_COMPILER_PIC])dnl for lt_prog_compiler_wl +AC_REQUIRE([LT_SYS_SYMBOL_USCORE])dnl for lt_cv_sys_symbol_underscore +AC_REQUIRE([LT_SYS_MODULE_EXT])dnl for libltdl_cv_shlibext +if test yes = "$lt_cv_sys_symbol_underscore"; then + if test yes = "$libltdl_cv_func_dlopen" || test yes = "$libltdl_cv_lib_dl_dlopen"; then + AC_CACHE_CHECK([whether we have to add an underscore for dlsym], + [libltdl_cv_need_uscore], + [libltdl_cv_need_uscore=unknown + dlsym_uscore_save_LIBS=$LIBS + LIBS="$LIBS $LIBADD_DLOPEN" + libname=conftmod # stay within 8.3 filename limits! + cat >$libname.$ac_ext <<_LT_EOF +[#line $LINENO "configure" +#include "confdefs.h" +/* When -fvisibility=hidden is used, assume the code has been annotated + correspondingly for the symbols needed. */ +#if defined __GNUC__ && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)) +int fnord () __attribute__((visibility("default"))); +#endif +int fnord () { return 42; }] +_LT_EOF + + # ltfn_module_cmds module_cmds + # Execute tilde-delimited MODULE_CMDS with environment primed for + # $module_cmds or $archive_cmds type content. + ltfn_module_cmds () + {( # subshell avoids polluting parent global environment + module_cmds_save_ifs=$IFS; IFS='~' + for cmd in @S|@1; do + IFS=$module_cmds_save_ifs + libobjs=$libname.$ac_objext; lib=$libname$libltdl_cv_shlibext + rpath=/not-exists; soname=$libname$libltdl_cv_shlibext; output_objdir=. + major=; versuffix=; verstring=; deplibs= + ECHO=echo; wl=$lt_prog_compiler_wl; allow_undefined_flag= + eval $cmd + done + IFS=$module_cmds_save_ifs + )} + + # Compile a loadable module using libtool macro expansion results. + $CC $pic_flag -c $libname.$ac_ext + ltfn_module_cmds "${module_cmds:-$archive_cmds}" + + # Try to fetch fnord with dlsym(). + libltdl_dlunknown=0; libltdl_dlnouscore=1; libltdl_dluscore=2 + cat >conftest.$ac_ext <<_LT_EOF +[#line $LINENO "configure" +#include "confdefs.h" +#if HAVE_DLFCN_H +#include +#endif +#include +#ifndef RTLD_GLOBAL +# ifdef DL_GLOBAL +# define RTLD_GLOBAL DL_GLOBAL +# else +# define RTLD_GLOBAL 0 +# endif +#endif +#ifndef RTLD_NOW +# ifdef DL_NOW +# define RTLD_NOW DL_NOW +# else +# define RTLD_NOW 0 +# endif +#endif +int main (void) { + void *handle = dlopen ("`pwd`/$libname$libltdl_cv_shlibext", RTLD_GLOBAL|RTLD_NOW); + int status = $libltdl_dlunknown; + if (handle) { + if (dlsym (handle, "fnord")) + status = $libltdl_dlnouscore; + else { + if (dlsym (handle, "_fnord")) + status = $libltdl_dluscore; + else + puts (dlerror ()); + } + dlclose (handle); + } else + puts (dlerror ()); + return status; +}] +_LT_EOF + if AC_TRY_EVAL(ac_link) && test -s "conftest$ac_exeext" 2>/dev/null; then + (./conftest; exit; ) >&AS_MESSAGE_LOG_FD 2>/dev/null + libltdl_status=$? + case x$libltdl_status in + x$libltdl_dlnouscore) libltdl_cv_need_uscore=no ;; + x$libltdl_dluscore) libltdl_cv_need_uscore=yes ;; + x*) libltdl_cv_need_uscore=unknown ;; + esac + fi + rm -rf conftest* $libname* + LIBS=$dlsym_uscore_save_LIBS + ]) + fi +fi + +if test yes = "$libltdl_cv_need_uscore"; then + AC_DEFINE([NEED_USCORE], [1], + [Define if dlsym() requires a leading underscore in symbol names.]) +fi +])# LT_FUNC_DLSYM_USCORE + +# Old name: +AU_ALIAS([AC_LTDL_DLSYM_USCORE], [LT_FUNC_DLSYM_USCORE]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LTDL_DLSYM_USCORE], []) + # pkg.m4 - Macros to locate and use pkg-config. -*- Autoconf -*- # serial 12 (pkg-config-0.29.2) @@ -1751,8 +2741,6 @@ m4_include([m4/ax_boost_base.m4]) m4_include([m4/ax_boost_thread.m4]) m4_include([m4/ax_cxx_compile_stdcxx.m4]) m4_include([m4/libtool.m4]) -m4_include([m4/ltargz.m4]) -m4_include([m4/ltdl.m4]) m4_include([m4/ltoptions.m4]) m4_include([m4/ltsugar.m4]) m4_include([m4/ltversion.m4]) diff --git a/bin/GNUWorld.example.conf b/bin/GNUWorld.example.conf index 9d5c3845..ee1f00d5 100644 --- a/bin/GNUWorld.example.conf +++ b/bin/GNUWorld.example.conf @@ -9,6 +9,20 @@ name = services.undernet.org description = UnderNet Services numeric = 51 +# Enable TLS connections to the uplink IRC server +# This will require openssl libraries to be installed on the GNUWorld +# host server +tls = yes + +# A valid file path to the private key file for GNUWorld +# Required if tls is enabled +tlsKeyFile = gnuworld.key + +# A valid file path to the public key file for GNUWorld that will +# be exchanged with the uplink. +# Required if tls is enabled +tlsCertFile = gnuworld.cert + # Set this variable to yes if you want the server to attempt # to auto_reconnect when a connection is terminated, set # to no otherwise. diff --git a/bin/cservice.example.conf b/bin/cservice.example.conf index b4b7ff0d..0a73ff2b 100644 --- a/bin/cservice.example.conf +++ b/bin/cservice.example.conf @@ -393,6 +393,13 @@ log_to_admin_console = 1 # chanfix servername to send and receive Oplist/Score requests/answers chanfix_servername = gnuworld6.undernet.org +# Maximum number of fingerprints per user + +max_fingerprints = 10 + +# Timeout for a SASL authentication session (in seconds) +sasl_timeout = 30 + # # Optional settings to enable Pushover notifications. # To use this, you need to create an application on Pushover diff --git a/bin/server_command_map b/bin/server_command_map index 6d3cb4b6..9103bd0f 100644 --- a/bin/server_command_map +++ b/bin/server_command_map @@ -10,6 +10,7 @@ libircu msg_AC AC libircu msg_AD AD libircu msg_B B libircu msg_C C +libircu msg_CF CF libircu msg_CM CM libircu msg_D D libircu msg_NOOP DE diff --git a/configure b/configure index 28957857..2ea2a4f2 100755 --- a/configure +++ b/configure @@ -891,6 +891,9 @@ with_pgconfig with_log4cplus with_log4cplus_lib with_log4cplus_include +with_libssl +with_libssl_lib +with_libssl_include with_extra_includes with_extra_libraries with_boost @@ -1595,6 +1598,11 @@ Optional Packages: Specify location to find liblog4cplus.so --with-log4cplus-include=LOG4CPLUSINCLUDEDIR Specify location to find logger.h + --with-libssl Enable OpenSSL (default) + --with-libssl-lib=LIBSSLLIBDIR + Specify location to find libssl.so + --with-libssl-include=SSLINCLUDEDIR + Specify location to find ssl.h --with-extra-includes=INCLUDESDIR Specify location to find additional include files --with-extra-libraries=LIBRARYDIR @@ -21669,6 +21677,107 @@ fi +# Check whether --with-libssl was given. +if test ${with_libssl+y} +then : + withval=$with_libssl; check_libssl=$withval +else case e in #( + e) check_libssl=yes ;; +esac +fi + + + +# Check whether --with-libssl-lib was given. +if test ${with_libssl_lib+y} +then : + withval=$with_libssl_lib; SSL_LIB=$withval +else case e in #( + e) SSL_LIB="/usr/lib" ;; +esac +fi + + + +# Check whether --with-libssl-include was given. +if test ${with_libssl_include+y} +then : + withval=$with_libssl_include; SSL_INCLUDE=$withval +else case e in #( + e) SSL_INCLUDE="/usr/include" ;; +esac +fi + + +if test "x$check_libssl" != "xno"; then + LDFLAGS="${LDFLAGS} -L${SSL_LIB} -lssl -lcrypto" + CXXFLAGS="${CXXFLAGS} -I${SSL_INCLUDE} -L${SSL_LIB}" + as_ac_File=`printf "%s\n" "ac_cv_file_"$SSL_LIB/libssl.so"" | sed "$as_sed_sh"` +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for \"$SSL_LIB/libssl.so\"" >&5 +printf %s "checking for \"$SSL_LIB/libssl.so\"... " >&6; } +if eval test \${$as_ac_File+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) test "$cross_compiling" = yes && + as_fn_error $? "cannot check for file existence when cross compiling" "$LINENO" 5 +if test -r ""$SSL_LIB/libssl.so""; then + eval "$as_ac_File=yes" +else + eval "$as_ac_File=no" +fi ;; +esac +fi +eval ac_res=\$$as_ac_File + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +printf "%s\n" "$ac_res" >&6; } +if eval test \"x\$"$as_ac_File"\" = x"yes" +then : + +else case e in #( + e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: Unable to find libssl.so, please use --with-libssl-lib to specify the path" >&5 +printf "%s\n" "$as_me: WARNING: Unable to find libssl.so, please use --with-libssl-lib to specify the path" >&2;} ;; +esac +fi + + as_ac_File=`printf "%s\n" "ac_cv_file_"$SSL_INCLUDE/openssl/ssl.h"" | sed "$as_sed_sh"` +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for \"$SSL_INCLUDE/openssl/ssl.h\"" >&5 +printf %s "checking for \"$SSL_INCLUDE/openssl/ssl.h\"... " >&6; } +if eval test \${$as_ac_File+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) test "$cross_compiling" = yes && + as_fn_error $? "cannot check for file existence when cross compiling" "$LINENO" 5 +if test -r ""$SSL_INCLUDE/openssl/ssl.h""; then + eval "$as_ac_File=yes" +else + eval "$as_ac_File=no" +fi ;; +esac +fi +eval ac_res=\$$as_ac_File + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +printf "%s\n" "$ac_res" >&6; } +if eval test \"x\$"$as_ac_File"\" = x"yes" +then : + +else case e in #( + e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: Unable to find ssl.h, please use --with-libssl-include to specify the path" >&5 +printf "%s\n" "$as_me: WARNING: Unable to find ssl.h, please use --with-libssl-include to specify the path" >&2;} ;; +esac +fi + + +printf "%s\n" "#define HAVE_LIBSSL /**/" >>confdefs.h + +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: OpenSSL support disabled (--without-libssl)" >&5 +printf "%s\n" "$as_me: WARNING: OpenSSL support disabled (--without-libssl)" >&2;} +fi + + + # Check whether --with-extra-includes was given. if test ${with_extra_includes+y} then : diff --git a/configure.ac b/configure.ac index b23a6ed3..fa58f995 100644 --- a/configure.ac +++ b/configure.ac @@ -267,6 +267,36 @@ if test "x$check_log4cplus" != "x" ; then CXXFLAGS="${CXXFLAGS} -I${LOG4CPLUS_INCLUDE}" fi +dnl Enable OpenSSL if required + +dnl Enable OpenSSL by default unless --without-libssl is specified +AC_ARG_WITH([libssl], + AS_HELP_STRING([--with-libssl],[Enable OpenSSL (default)]), + [check_libssl=$withval], + [check_libssl=yes]) + +AC_ARG_WITH([libssl-lib], + AS_HELP_STRING([--with-libssl-lib=LIBSSLLIBDIR],[Specify location to find libssl.so]), + [SSL_LIB=$withval], + [SSL_LIB="/usr/lib"]) + +AC_ARG_WITH([libssl-include], + AS_HELP_STRING([--with-libssl-include=SSLINCLUDEDIR],[Specify location to find ssl.h]), + [SSL_INCLUDE=$withval], + [SSL_INCLUDE="/usr/include"]) + +if test "x$check_libssl" != "xno"; then + LDFLAGS="${LDFLAGS} -L${SSL_LIB} -lssl -lcrypto" + CXXFLAGS="${CXXFLAGS} -I${SSL_INCLUDE} -L${SSL_LIB}" + AC_CHECK_FILE("$SSL_LIB/libssl.so",, + [AC_MSG_WARN([Unable to find libssl.so, please use --with-libssl-lib to specify the path])]) + AC_CHECK_FILE("$SSL_INCLUDE/openssl/ssl.h",, + [AC_MSG_WARN([Unable to find ssl.h, please use --with-libssl-include to specify the path])]) + AC_DEFINE([HAVE_LIBSSL], [], [Using LIBSSL]) +else + AC_MSG_WARN([OpenSSL support disabled (--without-libssl)]) +fi + dnl Allow selection of additional includes and libraries paths dnl just in case! diff --git a/doc/cservice.sql b/doc/cservice.sql index f6b0267e..28b93fbb 100644 --- a/doc/cservice.sql +++ b/doc/cservice.sql @@ -3,6 +3,9 @@ -- Channel service DB SQL file for PostgreSQL. -- ChangeLog: +-- 2026-01-09: MrIron +-- Added column for scram records. +-- Added table for TLS fingerprints. -- 2025-04-01: Empus -- Added ident column to user_sec_history table -- Added deleted column to user_sec_history table @@ -221,7 +224,7 @@ CREATE TABLE users ( language_id INT4 CONSTRAINT language_channel_id_ref REFERENCES languages (id), public_key TEXT, post_forms int4 DEFAULT 0 NOT NULL, - flags INT2 NOT NULL DEFAULT '0', + flags INT4 NOT NULL DEFAULT '0', -- 0x00 01 -- Suspended globally. -- 0x00 02 -- Logged in (Depricated). -- 0x00 04 -- Invisible. @@ -241,6 +244,7 @@ CREATE TABLE users ( signup_ts INT4, signup_ip VARCHAR(15), maxlogins INT4 DEFAULT 1, + scram_record TEXT, totp_key VARCHAR(60) DEFAULT '', PRIMARY KEY ( id ) ) ; @@ -250,6 +254,16 @@ CREATE INDEX users_email_idx ON users( lower(email) ); CREATE INDEX users_signup_ts_idx ON users( signup_ts ); CREATE INDEX users_signup_ip_idx ON users( signup_ip ); +-- This table used to store TLS fingerprints. + +CREATE TABLE users_fingerprints ( + user_id INT4 NOT NULL REFERENCES users(id) ON DELETE CASCADE, + fingerprint VARCHAR(128) NOT NULL UNIQUE, + added_ts BIGINT NOT NULL, + added_by VARCHAR(128) NOT NULL, + note TEXT +); + -- This table used to store the "Last Seen" informatation previously -- routinely updated in the users table. CREATE TABLE users_lastseen ( @@ -1104,4 +1118,4 @@ CREATE TABLE default_msgs ( content text NOT NULL ); -CREATE INDEX default_msgs_idx ON default_msgs(type); \ No newline at end of file +CREATE INDEX default_msgs_idx ON default_msgs(type); diff --git a/doc/cservice.update.sql b/doc/cservice.update.sql index b2b8fbcc..e9d2a60c 100644 --- a/doc/cservice.update.sql +++ b/doc/cservice.update.sql @@ -99,3 +99,43 @@ $$ LANGUAGE sql STABLE; -- 2025-04-17: Empus -- Added deleted column to languages table ALTER TABLE languages ADD COLUMN deleted INT2 DEFAULT 0; + +-- 2026-01-09: MrIron +-- Added new users_fingerprints table +-- Added new translations and help entries for certauth +-- Added column for scram records. +-- Changed flags column to INT4 to allow for more flags. +-- Added new translations for AUTOHIDE setting. +CREATE TABLE users_fingerprints ( + user_id INT4 CONSTRAINT fingerprints_users_id_ref REFERENCES users ( id ), + fingerprint VARCHAR( 128 ), + added_ts BIGINT NOT NULL, + added_by VARCHAR( 128 ), + note TEXT, + PRIMARY KEY (user_id) +); + +ALTER TABLE users + ADD COLUMN scram_record TEXT; + +ALTER TABLE users + ALTER COLUMN flags TYPE INT4; + +INSERT INTO translations (language_id, response_id, text, last_updated) VALUES(1, 197, 'Your AUTOHIDE setting is now ON.', 31337); +INSERT INTO translations (language_id, response_id, text, last_updated) VALUES(1, 198, 'Your AUTOHIDE setting is now OFF.', 31337); +INSERT INTO translations (language_id, response_id, text, last_updated) VALUES(1, 195, 'Your CERTONLY setting is now ON.', 31337); +INSERT INTO translations (language_id, response_id, text, last_updated) VALUES(1, 196, 'Your CERTONLY setting is now OFF.', 31337); +INSERT INTO translations (language_id, response_id, text, last_updated) VALUES(1, 197, 'Your AUTOHIDE setting is now ON.', 31337); +INSERT INTO translations (language_id, response_id, text, last_updated) VALUES(1, 198, 'Your AUTOHIDE setting is now OFF.', 31337); +INSERT INTO translations (language_id, response_id, text, last_updated) VALUES(1, 225, 'You currently don''t have any fingerprints added to your account. For more information, use ''/msg X help cert''', 31337); +INSERT INTO translations (language_id, response_id, text, last_updated) VALUES(1, 226, 'No fingerprints found.', 31337); +INSERT INTO translations (language_id, response_id, text, last_updated) VALUES(1, 227, 'Your current fingerprint is: %s', 31337); +INSERT INTO translations (language_id, response_id, text, last_updated) VALUES(1, 228, 'You already have %d fingerprints added to your username.', 31337); +INSERT INTO translations (language_id, response_id, text, last_updated) VALUES(1, 229, 'Invalid fingerprint.', 31337); +INSERT INTO translations (language_id, response_id, text, last_updated) VALUES(1, 230, 'That fingerprint is already added to a username.', 31337); +INSERT INTO translations (language_id, response_id, text, last_updated) VALUES(1, 231, 'Successfully added ''%s'' to your username.', 31337); +INSERT INTO translations (language_id, response_id, text, last_updated) VALUES(1, 232, 'Successfully removed ''%s'' from your username.', 31337); +INSERT INTO translations (language_id, response_id, text, last_updated) VALUES(1, 233, 'You cannot remove that fingerprint unless you disable CERTONLY or add another fingerprint.', 31337); +INSERT INTO translations (language_id, response_id, text, last_updated) VALUES(1, 234, 'That fingerprint was not found on your username.', 31337); + +INSERT INTO help VALUES ('CERT', '1', E'/msg X cert [fingerprint] [note]\nThis command allows you to add, remove and list TLS fingerprints added to your username.\nBy connecting to Undernet using TLS and a certificate, you may login to X without using a password if the certificate''s fingerprint has been added to your username.\nTo login to X with a fingerprint, use ''/msg X@channels.undernet.org login [TOTP token]''.\nUsing CERT ADD or REM without specifying a fingerprint will add or remove the fingerprint you are currently connected with (if any).\nA specified fingerprint must be in a SHA-256 format (i.e. AB:CD:12:ED:34 ...).\nWhen having a fingerprint added to your account, you may deactivate password login on IRC using ''SET CERTONLY ON/OFF''. You will still be able to login to the website with your password.'); diff --git a/include/Channel.h b/include/Channel.h index cccfb24a..4e7d4a94 100644 --- a/include/Channel.h +++ b/include/Channel.h @@ -129,6 +129,9 @@ class Channel /// Bit representing channel mode +U static const modeType MODE_U ; + /// Bit representing channel mode +Z + static const modeType MODE_Z ; + /// Type used to store number of clients in channel typedef userListType::size_type size_type ; diff --git a/include/Network.h b/include/Network.h index abd29828..4108d5e4 100644 --- a/include/Network.h +++ b/include/Network.h @@ -29,6 +29,7 @@ #include #include #include +#include #include @@ -141,6 +142,12 @@ class xNetwork */ typedef std::map< unsigned int, iServer* > serverMapType ; + /** + * The type used to store Network configuration pairs (CF), + * keyed by the configuration key. + */ + typedef std::map< std::string, std::pair< std::string, time_t > > netConfMapType ; + public: /** @@ -205,6 +212,20 @@ class xNetwork */ virtual bool addChannel( Channel* ) ; + /** + * Add a new netconf variable to the network table. + */ + virtual void addNetConf( const std::string& key, + const std::string& value, + time_t timestamp ) + { netConfMap[ key ] = std::make_pair( value, timestamp ) ; } + + /** + * Find a netconf variable by key. + * Returns std::nullopt if not found. + */ + virtual std::optional< std::pair< std::string, time_t > > findNetConf( const std::string& key ) const ; + /* * All nickname based searches are case insensitive. */ @@ -972,6 +993,12 @@ class xNetwork */ serverMapType serverMap ; + /** + * This structure holds all network configuration pairs + * bursted on the network (CF). + */ + netConfMapType netConfMap ; + /** * This variable is used backwards calls to the main server. */ diff --git a/include/defs.h.in b/include/defs.h.in index 5a12477c..e5367842 100644 --- a/include/defs.h.in +++ b/include/defs.h.in @@ -100,6 +100,9 @@ /* Define to 1 if you have the 'socket' library (-lsocket). */ #undef HAVE_LIBSOCKET +/* Using LIBSSL */ +#undef HAVE_LIBSSL + /* Define this if a modern libltdl is already installed */ #undef HAVE_LTDL diff --git a/include/events.h b/include/events.h index 41304e9a..d6979005 100644 --- a/include/events.h +++ b/include/events.h @@ -59,6 +59,7 @@ enum EVT_RAW, EVT_XQUERY, EVT_XREPLY, + EVT_NETCONF, // EVT_NOOP must always be last EVT_NOOP @@ -127,6 +128,9 @@ typedef int channelEventType ; * 1) iServer* source * 2) string* - routing * 3) string* - command + * EVT_NETCONF + * 1) iServer* source + * 2) string* - key * * Channel Events * -------------- diff --git a/include/gnuworld_config.h b/include/gnuworld_config.h index 9c86bda3..f40486d1 100755 --- a/include/gnuworld_config.h +++ b/include/gnuworld_config.h @@ -81,6 +81,13 @@ */ #define TOPIC_TRACK +/** + * NO_FINGERPRINT_BURST + * Disable this if gnuworld is linked to a hub that doesn't support fingerprint burst. + * This should only be enabled when the uplink is running ircu with tls support. + */ +#define NO_FINGERPRINT_BURST + /** * USE_THREAD * Set this to enable mutexes on shared objects. Relevant for running diff --git a/include/iClient.h b/include/iClient.h index 1c407723..e5a301c0 100644 --- a/include/iClient.h +++ b/include/iClient.h @@ -97,6 +97,9 @@ class iClient : public NetworkTarget /** MODE_FAKE is true if this user is a fake client. */ static constexpr modeType MODE_FAKE = 0x0200 ; + /** MODE_TLS is true if this user is using TLS. */ + static constexpr modeType MODE_TLS = 0x0400 ; + /** * Define a type to be used for storing the * iClient's account's flags. @@ -106,6 +109,9 @@ class iClient : public NetworkTarget static constexpr flagType X_TOTP_REQ_IPR = 0x002 ; static constexpr flagType X_GLOBAL_SUSPEND = 0x004 ; static constexpr flagType X_FRAUD = 0x008 ; + static constexpr flagType X_CERTONLY = 0x010 ; + static constexpr flagType X_CERT_DISABLE_TOTP = 0x020 ; + static constexpr flagType X_WEB_DISABLE_TOTP = 0x040 ; /// Iterator for channels this user is on. typedef channelListType::iterator channelIterator ; @@ -131,6 +137,7 @@ class iClient : public NetworkTarget const std::string& _account, const unsigned int _account_id, const flagType _account_flags, + const std::string& _tls_fingerprint, const std::string& _description, const time_t& _nick_ts ) ; @@ -151,6 +158,7 @@ class iClient : public NetworkTarget const std::string& _account, const unsigned int _account_id, const flagType _account_flags, + const std::string& _tls_fingerprint, const std::string& _setHost, const std::string& _fakeHost, const std::string& _description, @@ -213,6 +221,19 @@ class iClient : public NetworkTarget inline const std::string getRealNickUserHost() const { return (nickName + '!' + userName + '@' + realInsecureHost) ; } + /** + * Retrieve client's TLS fingerprint. + * Will return empty if the client is not using TLS. + */ + inline const std::string& getTlsFingerprint() const + { return tlsFingerprint ; } + + /** + * Returns true if the client has a fingerprint. + */ + inline bool hasTlsFingerprint() const + { return !tlsFingerprint.empty() ; } + /** * Retrieve client's 'real-name' field. */ @@ -309,6 +330,15 @@ class iClient : public NetworkTarget account_flags |= newFlag ; } + /** + * Set the TLS fingerprint for this iClient. + */ + inline void setTlsFingerprint( const std::string& _tls_fingerprint ) + { + if( ! isModeZ() ) { return ; } + tlsFingerprint = _tls_fingerprint ; + } + #ifdef ASUKA /** * Retrieve the iClient's sethost. @@ -498,6 +528,13 @@ class iClient : public NetworkTarget inline bool isModeG() const { return getMode( MODE_G ) ; } + /** + * Return true if this client has the +z mode set, + * indicating that the client is using TLS. False otherwise. + */ + inline bool isModeZ() const + { return getMode( MODE_TLS ) ; } + /** * Return true if this iClient is a fake, false otherwise. */ @@ -573,6 +610,12 @@ class iClient : public NetworkTarget inline void setModeR() { setMode( MODE_REGISTERED ) ; } + /** + * Set mode +z for this user. + */ + inline void setModeZ() + { setMode( MODE_TLS ) ; } + /** * Designate this iClient as a fake. */ @@ -766,7 +809,10 @@ class iClient : public NetworkTarget unsigned int account_id ; /** The flags of this client's account. */ - unsigned short int account_flags; + unsigned short int account_flags ; + + /** The TLS fingerprint of this client. */ + std::string tlsFingerprint ; #ifdef ASUKA /** diff --git a/include/server.h b/include/server.h index 19d99b7d..76d33078 100644 --- a/include/server.h +++ b/include/server.h @@ -1294,6 +1294,12 @@ class xServer : public ConnectionManager, */ long Version ; + /** + * Whether or not TLS encrypted connections are enabled (and required) + * for the server uplink + */ + bool tlsEnabled ; + /** * This variable is true when this server is bursting. */ @@ -1522,6 +1528,16 @@ class xServer : public ConnectionManager, */ std::string simFileName ; + /** + * The path to the TLS key file + */ + std::string tlsKeyFile ; + + /** + * The path to the TLS cert file + */ + std::string tlsCertFile ; + /** * True if autoreconnect is enabled, false otherwise. */ @@ -1543,6 +1559,11 @@ class xServer : public ConnectionManager, bool loadCommandHandlers() ; + /** + * This method initializes all of the TLS contexts + */ + bool initTls() ; + /** * Load an individual command handler from a file (fileName), * and associate that handler with the network message diff --git a/libgnuworld/Connection.cc b/libgnuworld/Connection.cc index 4ef47654..bbc057f5 100755 --- a/libgnuworld/Connection.cc +++ b/libgnuworld/Connection.cc @@ -34,31 +34,28 @@ namespace gnuworld { -// Allocate these static variables in class Connection -const Connection::flagType Connection::F_PENDING = 0x01 ; -const Connection::flagType Connection::F_CONNECTED = 0x02 ; -const Connection::flagType Connection::F_INCOMING = 0x04 ; -const Connection::flagType Connection::F_LISTEN = 0x08 ; -const Connection::flagType Connection::F_FILE = 0x10 ; -const Connection::flagType Connection::F_FLUSH = 0x20 ; - using std::string ; // Simply initialize the object Connection::Connection( const string& _hostname, const unsigned short int _remotePort, - const char _delimiter ) + const char _delimiter, + bool _tlsEnabled ) : hostname( _hostname ), localPort( 0 ), remotePort( _remotePort ), inputBuffer( _delimiter ), outputBuffer( _delimiter ), + tlsEnabled( _tlsEnabled ), IP( string() ), sockFD( -1 ), flags( F_PENDING ), connectTime( 0 ), bytesRead( 0 ), bytesWritten( 0 ) +#ifdef HAVE_LIBSSL + , tlsState( nullptr ) +#endif { memset( &addr, 0, sizeof( struct sockaddr_in ) ) ; } @@ -68,15 +65,28 @@ Connection::Connection( const char _delimiter ) remotePort( 0 ), inputBuffer( _delimiter ), outputBuffer( _delimiter ), + tlsEnabled( false ), sockFD( -1 ), - flags( F_PENDING ) + flags( F_PENDING ), + connectTime( 0 ), + bytesRead( 0 ), + bytesWritten( 0 ) +#ifdef HAVE_LIBSSL + , tlsState( nullptr ) +#endif { memset( &addr, 0, sizeof( struct sockaddr_in ) ) ; } Connection::~Connection() { -/* No work to be done, no heap space allocated */ +#ifdef HAVE_LIBSSL +if( tlsState ) + { + SSL_free( tlsState ) ; + tlsState = nullptr ; + } +#endif } void Connection::Write( const string& writeMe ) diff --git a/libgnuworld/Connection.h b/libgnuworld/Connection.h index 103b18ff..fa01955a 100755 --- a/libgnuworld/Connection.h +++ b/libgnuworld/Connection.h @@ -35,6 +35,13 @@ #include "Buffer.h" #include "ELog.h" +#include "defs.h" + +#ifdef HAVE_LIBSSL +#include +#include +#include +#endif namespace gnuworld { @@ -102,13 +109,13 @@ class Connection * This flag is true if the connection is currently fully * connected. */ - static const flagType F_CONNECTED ; + static constexpr flagType F_CONNECTED = 0x01 ; /** * This flag is true if the connection is still pending, * not yet complete. */ - static const flagType F_PENDING ; + static constexpr flagType F_PENDING = 0x02 ; /** * This flag is true if this Connection represents a @@ -117,7 +124,7 @@ class Connection * The F_INCOMING flag exists throughout the life ot * the Connection. */ - static const flagType F_INCOMING ; + static constexpr flagType F_INCOMING = 0x04 ; /** * This flag is true if this Connection represents a @@ -125,20 +132,36 @@ class Connection * This flag exists for the life of this connection. * A listening Connection is never connected. */ - static const flagType F_LISTEN ; + static constexpr flagType F_LISTEN = 0x08 ; /** * This flag is true when the Connection represents a * connection to a file, rather than a network connection. */ - static const flagType F_FILE ; + static constexpr flagType F_FILE = 0x10 ; /** * This flag will be set if the next write is to flush all * data from the output buffer. * The flag will be reset after the send(). */ - static const flagType F_FLUSH ; + static constexpr flagType F_FLUSH = 0x20 ; + + /** + * This flag will be set upon initiating a TLS connection. + * The flag will be reset after the handshake is completed. + */ + static constexpr flagType F_TLS_HANDSHAKING = 0x40 ; + + /** + * This flag will be set upon shutting down a TLS connection. + */ + static constexpr flagType F_TLS_SHUTTING_DOWN = 0x80 ; + + /** + * This flags a TLS connection as having a fatal error, i.e. ssl_shutdown() will not be called. + */ + static constexpr flagType F_TLS_FATAL_ERROR = 0x100 ; /** * Append a string to the Connection's output buffer. @@ -207,6 +230,19 @@ class Connection inline bool isFlush() const { return (flags & F_FLUSH) ; } + /** + * Return true if the negotiating TLS flag is set, indicating that + * the TLS handshake has not completed. + */ + inline bool isNegotiatingTLS() const + { return (flags & F_TLS_HANDSHAKING) ; } + + /** + * Return true if the TLS connection has initiating shutdown. + */ + inline bool isShuttingDownTLS() const + { return (flags & F_TLS_SHUTTING_DOWN) ; } + /** * Return the total number of bytes read from this * Connection. @@ -242,6 +278,12 @@ class Connection */ inline size_t getInputBufferSize() const { return inputBuffer.size() ; } + + /** + * Return whether or not this connection has TLS enabled + */ + inline bool isTLS() const + { return tlsEnabled ; } /** * Set the F_FLUSH flag to true. @@ -261,6 +303,7 @@ class Connection << ", localPort: " << con.getLocalPort() << ", remotePort: " << con.getRemotePort() << ", sockFD: " << con.getSockFD() + << ", TLS: " << (con.isTLS() ? "yes" : "no") << ", state: " << (con.isConnected() ? "connected" : "pending") ; if( con.isIncoming() ) @@ -285,6 +328,7 @@ class Connection << ", localPort: " << con.getLocalPort() << ", remotePort: " << con.getRemotePort() << ", sockFD: " << con.getSockFD() + << ", TLS: " << (con.isTLS() ? "yes" : "no") << ", state: " << (con.isConnected() ? "connected" : "pending") ; if( con.isIncoming() ) @@ -306,7 +350,8 @@ class Connection */ Connection( const std::string& host, const unsigned short int remotePort, - const char delimiter ) ; + const char delimiter, + bool tlsEnabled ) ; /** * Create a new instance of this class, set all variables @@ -358,6 +403,24 @@ class Connection inline void setFile() { setFlag( F_FILE ) ; } + /** + * Mark that this Connection as pending TLS negotiation. + */ + inline void setNegotiatingTLS() + { setFlag( F_TLS_HANDSHAKING ) ; } + + /** + * Mark that this Connection as pending TLS negotiation. + */ + inline void clrNegotiatingTLS() + { removeFlag( F_TLS_HANDSHAKING ) ; } + + /** + * Mark that this Connection as pending TLS negotiation. + */ + inline void setShuttingDownTLS() + { setFlag( F_TLS_SHUTTING_DOWN ) ; } + /** * Set this connection's local port number */ @@ -414,6 +477,17 @@ class Connection */ inline time_t getAbsTimeout() const { return absTimeout ; } + +#ifdef HAVE_LIBSSL + /** + * Return the current TLS state for this connection + */ + inline SSL* getTlsState() const + { return tlsState ; } + + inline void setTlsState( SSL* newState ) + { tlsState = newState ; } +#endif /** * The remote hostname of this connection @@ -441,6 +515,11 @@ class Connection */ Buffer outputBuffer ; + /** + * Whether or not this connection is encrypted + */ + bool tlsEnabled ; + /** * The remote IP of this connection * This variable is empty() if this Connection is a listener @@ -484,6 +563,12 @@ class Connection */ size_t bytesWritten ; +#ifdef HAVE_LIBSSL + /** + * The current OpenSSL TLS state for this connection + */ + SSL* tlsState ; +#endif } ; } // namespace gnuworld diff --git a/libgnuworld/ConnectionManager.cc b/libgnuworld/ConnectionManager.cc index 62ed33e1..85397302 100755 --- a/libgnuworld/ConnectionManager.cc +++ b/libgnuworld/ConnectionManager.cc @@ -86,7 +86,7 @@ eraseMap.clear() ; for( handlerMapIterator handlerItr = handlerMap.begin() ; handlerItr != handlerMap.end() ; ++handlerItr ) { - for( connectionMapIterator connectionItr = + for( connectionMapIterator connectionItr = handlerItr->second.begin() ; connectionItr != handlerItr->second.end() ; ++connectionItr ) @@ -109,7 +109,8 @@ handlerMap.clear() ; Connection* ConnectionManager::Connect( ConnectionHandler* hPtr, const string& host, - const unsigned short int remotePort ) + const unsigned short int remotePort, + bool tlsEnabled = false ) { // Handler must be valid assert( hPtr != 0 ) ; @@ -128,7 +129,7 @@ if( host.empty() ) // Allocate a new Connection object Connection* newConnection = new (nothrow) - Connection( host, remotePort, delimiter ) ; + Connection( host, remotePort, delimiter, tlsEnabled ) ; assert( newConnection != 0 ) ; // Set the absolute time for this Connection's timeout to occur @@ -184,6 +185,22 @@ addr->sin_addr.s_addr = inet_addr( newConnection->getIP().c_str() ) ; // Update the new Connection object newConnection->setSockFD( sockFD ) ; +#ifdef HAVE_LIBSSL +if (tlsEnabled) { + SSL* state = SSL_new(sslCtx); + if (!state) { + elog << "Connect> Could not create SSL session" << endl; + return 0; + } + newConnection->setTlsState(state); + newConnection->setNegotiatingTLS(); + SSL_set_fd(state, sockFD); + BIO_set_nbio(SSL_get_rbio(state), 1); + BIO_set_nbio(SSL_get_wbio(state), 1); + SSL_set_connect_state(state); +} +#endif + // Attempt to initiate the connect. // The socket is non-blocking, so a failure is expected // In the case of a UDP socket, this call to ::connect() will just @@ -551,6 +568,24 @@ elog << "ConnectionManager::Disconnect> Scheduling connection " // to Poll() scheduleErasure( hPtr, connectionItr ) ; +// Flush buffer. +cPtr->Flush() ; + +#ifdef HAVE_LIBSSL +// Attempt to shutdown TLS connection. +if( cPtr->isTLS() && !cPtr->isNegotiatingTLS() && !cPtr->hasFlag( Connection::F_TLS_FATAL_ERROR ) ) + { + // Flag the connections as shutting down. + cPtr->setShuttingDownTLS() ; + + int res = SSL_shutdown( cPtr->getTlsState() ) ; + if( res > 0 ) + { + elog << "ConnectionManager::Disconnect> TLS connection gracefully shut down." << endl ; + } + } +#endif + // Connection located and scheduled for erasure, return success return true ; } @@ -868,6 +903,24 @@ for( eraseMapIterator eraseItr = eraseMap.begin(), // << *connectionPtr // << endl ; +#ifdef HAVE_LIBSSL + // Attempt to shutdown TLS connection if not already closed. + if( connectionPtr->isTLS() && !connectionPtr->isNegotiatingTLS() && !connectionPtr->hasFlag( Connection::F_TLS_FATAL_ERROR )) + { + int res = SSL_shutdown( connectionPtr->getTlsState() ) ; + if( res > 0 ) + { + elog << "ConnectionManager::Poll> TLS connection gracefully shut down." << endl ; + } + else + { + elog << "ConnectionManager::Poll> TLS failed to shut down gracefully (" << res << "): " + << ERR_error_string( ERR_get_error(), nullptr ) + << endl ; + } + } +#endif + // Close the Connection's socket (file) descriptor closeSocket( connectionPtr->getSockFD() ) ; @@ -891,11 +944,11 @@ for( handlerMapIterator handlerItr = handlerMap.begin() ; handlerItr != handlerMap.end() ; ++handlerItr ) { // From SGI STL website: - // Map has the important property that inserting a new element - // into a map does not invalidate iterators that point to + // Map has the important property that inserting a new element + // into a map does not invalidate iterators that point to // existing elements. Erasing an element from a map also does - // not invalidate any iterators, except, of course, for iterators - // that actually point to the element that is being erased. + // not invalidate any iterators, except, of course, for iterators + // that actually point to the element that is being erased. if( handlerItr->second.empty() ) { // The connectionMap for this handler is empty @@ -1010,6 +1063,17 @@ ::close( fd ) ; bool ConnectionManager::handleRead( ConnectionHandler* hPtr, Connection* cPtr ) { +// Don't allow reads if the connection is shutting down. +if( cPtr->isTLS() && cPtr->isShuttingDownTLS() ) + return true ; + +#ifdef HAVE_LIBSSL +// Don't allow reads until TLS handshake is complete +if( cPtr->isTLS() && cPtr->isNegotiatingTLS() ) + { + return negotiateTLS( hPtr, cPtr ) ; + } +#endif // protected member, no error checking // Attempt the read from the socket @@ -1026,8 +1090,40 @@ if( cPtr->isFile() ) else { // Network connection - readResult = ::recv( cPtr->getSockFD(), inputBuffer, - inputBufferSize, 0 ) ; + if( cPtr->isTLS() ) + { +#ifdef HAVE_LIBSSL + readResult = SSL_read( cPtr->getTlsState(), inputBuffer, inputBufferSize ) ; + if( readResult <= 0 ) + { + int err = SSL_get_error( cPtr->getTlsState(), readResult ) ; + switch( err ) + { + case SSL_ERROR_WANT_READ: + case SSL_ERROR_WANT_WRITE: + // Not ready - try again later + return true ; + + case SSL_ERROR_ZERO_RETURN: + // Clean shutdown + hPtr->OnDisconnect( cPtr ) ; + return false ; + + default: + elog << "ConnectionManager::handleRead> TLS read error: " + << ERR_error_string( ERR_get_error(), nullptr ) << endl ; + cPtr->setFlag( Connection::F_TLS_FATAL_ERROR ) ; + hPtr->OnDisconnect( cPtr ) ; + return false ; + } + } +#endif + } + else + { + readResult = ::recv( cPtr->getSockFD(), inputBuffer, + inputBufferSize, 0 ) ; + } } if( EAGAIN == errno ) @@ -1082,6 +1178,18 @@ return true ; bool ConnectionManager::handleWrite( ConnectionHandler* hPtr, Connection* cPtr ) { +// Don't allow reads if the connection is shutting down. +if( cPtr->isTLS() && cPtr->isShuttingDownTLS() ) + return true ; + +#ifdef HAVE_LIBSSL +// Don't allow writes until TLS handshake is complete +if( cPtr->isTLS() && cPtr->isNegotiatingTLS() ) + { + return negotiateTLS( hPtr, cPtr ) ; + } +#endif + // protected member, no error checking // Attempt the write to the socket @@ -1099,7 +1207,6 @@ if( cPtr->isFile() ) { // Just ignore writes to the file cPtr->outputBuffer.clear() ; - return true ; } @@ -1109,16 +1216,45 @@ if( cPtr->isFlush() ) } errno = 0 ; -int writeResult = ::send( cPtr->getSockFD(), - cPtr->outputBuffer.data(), - cPtr->outputBuffer.size(), - 0 ) ; +int writeResult = 0 ; +if ( !cPtr->isTLS() ) { + writeResult = ::send( cPtr->getSockFD(), + cPtr->outputBuffer.data(), + cPtr->outputBuffer.size(), + 0 ) ; +} else { +#ifdef HAVE_LIBSSL + writeResult = SSL_write( cPtr->getTlsState(), + cPtr->outputBuffer.data(), + cPtr->outputBuffer.size() ) ; + if( writeResult < 0 ) + { + int err = SSL_get_error( cPtr->getTlsState(), writeResult) ; + switch( err ) + { + case SSL_ERROR_WANT_READ: + case SSL_ERROR_WANT_WRITE: + return true ; /* Retry when the socket is ready. */ + case SSL_ERROR_ZERO_RETURN: + // Clean shutdown + hPtr->OnDisconnect( cPtr ) ; + return false ; + default: + elog << "ConnectionManager::handleWrite> TLS write error: " + << ERR_error_string( ERR_get_error(), nullptr ) << endl ; + cPtr->setFlag( Connection::F_TLS_FATAL_ERROR ) ; + hPtr->OnDisconnect( cPtr ) ; + return false ; + } + } +#endif +} if( (ENOBUFS == errno) || (EWOULDBLOCK == errno) || (EAGAIN == errno) ) { // Nonblocking type error // Ignore it for now - elog << "ConnectionManager::handleWrite> errno: " + elog << "ConnectionManager::handleWrite> errno: (" << errno << ") " << strerror( errno ) << endl ; return true ; @@ -1159,6 +1295,12 @@ bool ConnectionManager::handleFlush( ConnectionHandler* hPtr, { // protected member, no error checking +#ifdef HAVE_LIBSSL +// This function returns false if TLS handshake negotiations are not completed. +if( !negotiateTLS( hPtr, cPtr ) ) + return false ; +#endif + // Make sure the Connection's F_FLUSH flag is cleared, so do it first cPtr->removeFlag( Connection::F_FLUSH ) ; @@ -1197,10 +1339,40 @@ if( ::fcntl( cPtr->getSockFD(), F_SETFL, flags ) < 0 ) while( !cPtr->outputBuffer.empty() ) { errno = 0 ; - int writeResult = ::send( cPtr->getSockFD(), - cPtr->outputBuffer.data(), - cPtr->outputBuffer.size(), - 0 ) ; + int writeResult = 0 ; + if( !cPtr->isTLS()) + writeResult = ::send( cPtr->getSockFD(), + cPtr->outputBuffer.data(), + cPtr->outputBuffer.size(), + 0 ) ; + #ifdef HAVE_LIBSSL + else + { + writeResult = SSL_write( cPtr->getTlsState(), + cPtr->outputBuffer.data(), + cPtr->outputBuffer.size() ) ; + if( writeResult < 0 ) + { + int err = SSL_get_error( cPtr->getTlsState(), writeResult ) ; + + switch( err ) + { + case SSL_ERROR_WANT_READ: + case SSL_ERROR_WANT_WRITE: + return true ; // Retry when the socket is ready. + case SSL_ERROR_ZERO_RETURN: + // Clean shutdown + hPtr->OnDisconnect( cPtr ) ; + return false ; + default: + elog << "ConnectionManager::HandleFlush> Fatal TLS error encountered." << endl ; + cPtr->setFlag( Connection::F_TLS_FATAL_ERROR ) ; + hPtr->OnDisconnect( cPtr ) ; + return false ; + } + } + } + #endif if( (ENOBUFS == errno) || (EWOULDBLOCK == errno) || (EAGAIN == errno) ) { @@ -1677,7 +1849,7 @@ if( fd < 0 ) // Create a new Connection object to represent this open file Connection* newConnect = new (std::nothrow) - Connection( fileName, fd, delimiter ) ; + Connection( fileName, fd, delimiter, false ) ; assert( newConnect != 0 ) ; // Set the Connection's state @@ -1733,4 +1905,50 @@ if( hItr == handlerMap.end() ) return hItr->second.size() ; } +#ifdef HAVE_LIBSSL +bool ConnectionManager::negotiateTLS( ConnectionHandler* hPtr, Connection* cPtr ) +{ +/* Return true if negotiations are completed. */ +if( !cPtr->isNegotiatingTLS() ) + return true ; + +if( ::time( 0 ) > ( cPtr->connectTime + 5 ) ) + { + elog << "ConnectionManager::negotiateTLS> TLS handshake timed out" << endl ; + hPtr->OnDisconnect( cPtr ) ; + return false ; + } + +int res = SSL_connect( cPtr->getTlsState() ) ; +if( res == 1 ) + { + elog << "ConnectionManager::negotiateTLS> TLS handshake completed successfully." << endl ; + cPtr->clrNegotiatingTLS() ; + return true ; + } + +int err = SSL_get_error( cPtr->getTlsState(), res ) ; +switch( err ) + { + case SSL_ERROR_WANT_READ: + case SSL_ERROR_WANT_WRITE: + // This is normal for non-blocking - return true to continue in next poll + return true ; + + case SSL_ERROR_ZERO_RETURN: + // Clean shutdown + elog << "ConnectionManager::negotiateTLS> TLS connection closed cleanly" << endl ; + hPtr->OnDisconnect( cPtr ) ; + return false ; + + default: + // Fatal error + elog << "ConnectionManager::negotiateTLS> TLS handshake failed: " + << ERR_error_string( ERR_get_error(), nullptr ) << endl ; + cPtr->setFlag( Connection::F_TLS_FATAL_ERROR ) ; + hPtr->OnDisconnect( cPtr ) ; + return false ; + } +} +#endif } // namespace gnuworld diff --git a/libgnuworld/ConnectionManager.h b/libgnuworld/ConnectionManager.h index aa280edb..c9987b55 100755 --- a/libgnuworld/ConnectionManager.h +++ b/libgnuworld/ConnectionManager.h @@ -37,6 +37,12 @@ #include "Connection.h" #include "ConnectionHandler.h" +#ifdef HAVE_LIBSSL +#include +#include +#include +#endif + namespace gnuworld { @@ -188,7 +194,8 @@ class ConnectionManager virtual Connection* Connect( ConnectionHandler*, const std::string& host, - const unsigned short int remotePort ) ; + const unsigned short int remotePort, + bool tlsEnabled ) ; /** * Connect to a file instead of a network host. This method @@ -334,6 +341,13 @@ class ConnectionManager */ char* inputBuffer ; +#ifdef HAVE_LIBSSL + /** + * The OpenSSL context for TLS connections + */ + SSL_CTX* sslCtx ; +#endif + /** * Open a socket. * Return -1 on error @@ -421,6 +435,9 @@ class ConnectionManager */ virtual bool disconnectAll( ConnectionHandler* ) ; +#ifdef HAVE_LIBSSL + virtual bool negotiateTLS( ConnectionHandler*, Connection* ) ; +#endif } ; } // namespace gnuworld diff --git a/libgnuworld/misc.cc b/libgnuworld/misc.cc index 19f30eb4..7dbca1be 100644 --- a/libgnuworld/misc.cc +++ b/libgnuworld/misc.cc @@ -34,6 +34,7 @@ #include #include #include +#include #include "misc.h" #include "StringTokenizer.h" @@ -693,6 +694,40 @@ getrusage( RUSAGE_SELF, &usage ) ; return usage.ru_maxrss ; } +// Converts "12asb23b..." to "12:AS:B2:3B..." +std::string compactToCanonical( const std::string& fingerprint ) +{ +std::string result ; +for( size_t i = 0 ; i < fingerprint.size() ; ++i ) + { + result += std::toupper( fingerprint[ i ] ) ; + if( ( i + 1 ) % 2 == 0 && i + 1 < fingerprint.size() ) + result += ':' ; +} +return result ; +} + +// Converts "12:AS:B2:3B..." back to "12asb23b..." +std::string canonicalToCompact( const std::string& fingerprint ) +{ +std::string result ; +for( char c : fingerprint ) + if( c != ':' ) + result += std::tolower( c ) ; +return result ; +} + +// SHA-256 fingerprint format: 32-byte hash in uppercase hex, separated by colons +bool isValidSHA256Fingerprint( const std::string& fingerprint ) +{ +const std::regex fingerprintRegex( "^([A-F0-9]{2}:){31}[A-F0-9]{2}$" ) ; + +if( fingerprint.length() != 95 ) + return false ; + +return std::regex_match( fingerprint, fingerprintRegex ) ; +} + /* Returns the CPU time used by gnuworld in seconds. */ double getCPUTime() { struct rusage usage ; diff --git a/libgnuworld/misc.h b/libgnuworld/misc.h index 737543e1..6a18c2c4 100755 --- a/libgnuworld/misc.h +++ b/libgnuworld/misc.h @@ -245,6 +245,13 @@ void stripModes( std::string& , const std::string& ) ; /* Returns the memory usage of gnuworld in KB. */ size_t getMemoryUsage() ; +std::string compactToCanonical( const std::string& ) ; + +// Converts "12:AS:B2:3B..." back to "12asb23b..." +std::string canonicalToCompact( const std::string& ) ; + +bool isValidSHA256Fingerprint( const std::string& ) ; + /* Returns the CPU time used by gnuworld in seconds. */ double getCPUTime() ; diff --git a/libircu/Makefile.am b/libircu/Makefile.am index 091fe040..99f70c42 100644 --- a/libircu/Makefile.am +++ b/libircu/Makefile.am @@ -7,6 +7,7 @@ libircu_la_SOURCES = \ libircu/msg_AD.cc \ libircu/msg_B.cc \ libircu/msg_C.cc \ + libircu/msg_CF.cc \ libircu/msg_CM.cc \ libircu/msg_D.cc \ libircu/msg_DS.cc \ diff --git a/libircu/msg_B.cc b/libircu/msg_B.cc index be757f18..2360152b 100644 --- a/libircu/msg_B.cc +++ b/libircu/msg_B.cc @@ -237,6 +237,10 @@ if( '+' == Param[ whichToken ][ 0 ] ) modeVector.push_back( make_pair( true, Channel::MODE_MNOREG ) ) ; break ; + case 'Z': + modeVector.push_back( make_pair( + true, Channel::MODE_Z ) ) ; + break ; case 'l': theServer->OnChannelModeL( theChan, true, 0, diff --git a/libircu/msg_CF.cc b/libircu/msg_CF.cc new file mode 100755 index 00000000..aa2cc091 --- /dev/null +++ b/libircu/msg_CF.cc @@ -0,0 +1,92 @@ +/** + * msg_CF.cc + * + * 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. + * + */ + + #include + #include + + #include "gnuworld_config.h" + #include "ServerCommandHandler.h" + #include "server.h" + #include "xparameters.h" + #include "Channel.h" + #include "Network.h" + #include "iClient.h" + #include "ELog.h" + + namespace gnuworld + { + + CREATE_HANDLER(msg_CF) + + /** + * CONFIGURATION message handler. + * + * This message is used to propagate network configuration + * source CF : + */ + bool msg_CF::Execute( const xParameters& Param ) + { + if( Param.size() < 3 ) + { + elog << "msg_CF> Invalid number of parameters" + << std::endl ; + return false ; + } + + iServer* sourceServer = Network->findServer( Param[ 0 ] ) ; + if( NULL == sourceServer ) + { + elog << "msg_CF> Unable to find source server: " + << Param[ 0 ] << std::endl ; + return false ; + } + +time_t timestamp = atoi( Param[ 1 ] ) ; +std::string key( Param[ 2 ] ) ; +std::string value( Param.assemble( 3 ) ) ; + +auto netConf = Network->findNetConf( key ) ; +if( netConf && netConf->second > timestamp ) + { + // This should never happen. + elog << "msg_CF> Netconf variable already exists and is newer: " + << key + << " (timestamp on file: " << netConf->second << ", timestamp on network: " << timestamp << ")" + << std::endl ; + return false ; + } + + Network->addNetConf( key, value, timestamp ) ; + + elog << "msg_CF> Adding netconf variable: " + << key + << " (value: " << value << ")" + << " (timestamp: " << timestamp << ")" + << std::endl ; + + // Post event to listening clients + theServer->PostEvent( EVT_NETCONF, static_cast< void* >( sourceServer ), + static_cast< void* >( &key ) ) ; + + // Return success + return true ; + } + + } // namespace gnuworld diff --git a/libircu/msg_CM.cc b/libircu/msg_CM.cc index d19e02ea..92d4c83e 100644 --- a/libircu/msg_CM.cc +++ b/libircu/msg_CM.cc @@ -196,6 +196,13 @@ for( std::string::size_type i = 0 ; i < Modes.size() ; i++ ) false, Channel::MODE_MNOREG ) ) ; // elog << tmpChan->getName() // << "msg_CM> Doing CLEAR_MNOREG" +// << endl; + break ; + case 'Z': + modeVector.push_back( make_pair( + false, Channel::MODE_Z ) ) ; +// elog << tmpChan->getName() +// << "msg_CM> Doing CLEAR_Z" // << endl; break ; case 'k': diff --git a/libircu/msg_M.cc b/libircu/msg_M.cc index 7f78b122..a4ab6488 100644 --- a/libircu/msg_M.cc +++ b/libircu/msg_M.cc @@ -232,6 +232,10 @@ for( const char* modePtr = Param[ 2 ] ; *modePtr ; ++modePtr ) modeVector.push_back( make_pair(polarity, Channel::MODE_MNOREG)); break; + case 'Z': + modeVector.push_back( + make_pair(polarity, Channel::MODE_Z)); + break; // Channel mode l only has an argument if // it is being added, but not removed case 'l': diff --git a/libircu/msg_N.cc b/libircu/msg_N.cc index fd94dbb9..cd0ba7bb 100644 --- a/libircu/msg_N.cc +++ b/libircu/msg_N.cc @@ -162,6 +162,7 @@ unsigned int account_id = 0 ; unsigned short int account_flags = 0; string sethost ; string fakehost ; +string tlsFingerprint ; xParameters::size_type currentArgIndex = 6 ; @@ -190,6 +191,11 @@ if( '+' == params[ currentArgIndex ][ 0 ] ) case 'f': fakehost = params[ currentArgIndex++ ] ; break ; +#ifndef NO_FINGERPRINT_BURST + case 'z': + tlsFingerprint = params[ currentArgIndex++ ] ; + break ; +#endif default: break ; } // switch( *modePtr ) } // for() @@ -229,6 +235,10 @@ if( !account.empty() ) } // if( 3 == st.size() ) } // if( !account.empty() ) +/* Set the fingerprint to empty if it is empty. */ +if( tlsFingerprint == "_" ) + tlsFingerprint.clear() ; + /* * -3 * -2 @@ -250,6 +260,7 @@ iClient* newClient = new (std::nothrow) iClient( account, // account account_id, // account id account_flags, // account flags + tlsFingerprint, // TLS fingerprint sethost, // asuka sethost fakehost, // srvx fakehost description, // real name / infoline diff --git a/libltdl/Makefile.in b/libltdl/Makefile.in index 5b34f616..d038af0c 100644 --- a/libltdl/Makefile.in +++ b/libltdl/Makefile.in @@ -100,7 +100,6 @@ host_triplet = @host@ subdir = . ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/../m4/libtool.m4 \ - $(top_srcdir)/../m4/ltargz.m4 $(top_srcdir)/../m4/ltdl.m4 \ $(top_srcdir)/../m4/ltoptions.m4 \ $(top_srcdir)/../m4/ltsugar.m4 \ $(top_srcdir)/../m4/ltversion.m4 \ @@ -112,7 +111,7 @@ DIST_COMMON = $(srcdir)/Makefile.am $(top_srcdir)/configure \ $(am__ltdlinclude_HEADERS_DIST) $(am__DIST_COMMON) am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ configure.lineno config.status.lineno -mkinstalldirs = $(install_sh) -d +mkinstalldirs = $(SHELL) $(top_srcdir)/../mkinstalldirs CONFIG_HEADER = config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = @@ -296,18 +295,15 @@ am__define_uniq_tagged_files = \ done | $(am__uniquify_input)` AM_RECURSIVE_TARGETS = cscope am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/config-h.in \ - $(top_srcdir)/../compile \ - $(top_srcdir)/../config.guess \ - $(top_srcdir)/../config.sub \ - $(top_srcdir)/../depcomp \ - $(top_srcdir)/../install-sh \ - $(top_srcdir)/../ltmain.sh \ - $(top_srcdir)/../missing ../compile \ - ../config.guess ../config.sub \ - ../depcomp ../install-sh \ - ../ltmain.sh \ - ../missing COPYING.LIB \ - README lt__argz.c lt__dirent.c lt__strl.c + $(top_srcdir)/../compile $(top_srcdir)/../config.guess \ + $(top_srcdir)/../config.sub $(top_srcdir)/../depcomp \ + $(top_srcdir)/../install-sh $(top_srcdir)/../ltmain.sh \ + $(top_srcdir)/../missing $(top_srcdir)/../mkinstalldirs \ + ../AUTHORS ../COPYING ../ChangeLog ../INSTALL ../NEWS \ + ../README ../TODO ../ar-lib ../compile ../config.guess \ + ../config.sub ../depcomp ../install-sh ../ltconfig \ + ../ltmain.sh ../missing ../mkinstalldirs COPYING.LIB README \ + lt__argz.c lt__dirent.c lt__strl.c DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) distdir = $(PACKAGE)-$(VERSION) top_distdir = $(distdir) diff --git a/libltdl/aclocal.m4 b/libltdl/aclocal.m4 index c6c322f5..3b421f5c 100644 --- a/libltdl/aclocal.m4 +++ b/libltdl/aclocal.m4 @@ -20,6 +20,996 @@ You have another version of autoconf. It may work, but is not guaranteed to. If you have problems, you may need to regenerate the build system entirely. To do so, use the procedure documented by the package, typically 'autoreconf'.])]) +# Portability macros for glibc argz. -*- Autoconf -*- +# +# Copyright (C) 2004-2007, 2011-2019, 2021-2024 Free Software +# Foundation, Inc. +# Written by Gary V. Vaughan +# +# This file is free software; the Free Software Foundation gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. + +# serial 2 ltargz.m4 + +AC_DEFUN([LT_FUNC_ARGZ], [ +dnl Required for use of '$SED' in Cygwin configuration. +AC_REQUIRE([AC_PROG_SED])dnl +AC_CHECK_HEADERS([argz.h], [], [], [AC_INCLUDES_DEFAULT]) + +AC_CHECK_TYPES([error_t], + [], + [AC_DEFINE([error_t], [int], + [Define to a type to use for 'error_t' if it is not otherwise available.]) + AC_DEFINE([__error_t_defined], [1], [Define so that glibc/gnulib argp.h + does not typedef error_t.])], + [#if defined(HAVE_ARGZ_H) +# include +#endif]) + +LT_ARGZ_H= +AC_CHECK_FUNCS([argz_add argz_append argz_count argz_create_sep argz_insert \ + argz_next argz_stringify], [], [LT_ARGZ_H=lt__argz.h; AC_LIBOBJ([lt__argz])]) + +dnl if have system argz functions, allow forced use of +dnl libltdl-supplied implementation (and default to do so +dnl on "known bad" systems). Could use a runtime check, but +dnl (a) detecting malloc issues is notoriously unreliable +dnl (b) only known system that declares argz functions, +dnl provides them, yet they are broken, is cygwin +dnl releases prior to 16-Mar-2007 (1.5.24 and earlier) +dnl So, it's more straightforward simply to special case +dnl this for known bad systems. +AS_IF([test -z "$LT_ARGZ_H"], + [AC_CACHE_CHECK( + [if argz actually works], + [lt_cv_sys_argz_works], + [[case $host_os in #( + *cygwin*) + lt_cv_sys_argz_works=no + if test no != "$cross_compiling"; then + lt_cv_sys_argz_works="guessing no" + else + lt_sed_extract_leading_digits='s/^\([0-9\.]*\).*/\1/' + save_IFS=$IFS + IFS=-. + set x `uname -r | $SED -e "$lt_sed_extract_leading_digits"` + IFS=$save_IFS + lt_os_major=${2-0} + lt_os_minor=${3-0} + lt_os_micro=${4-0} + if test 1 -lt "$lt_os_major" \ + || { test 1 -eq "$lt_os_major" \ + && { test 5 -lt "$lt_os_minor" \ + || { test 5 -eq "$lt_os_minor" \ + && test 24 -lt "$lt_os_micro"; }; }; }; then + lt_cv_sys_argz_works=yes + fi + fi + ;; #( + *) lt_cv_sys_argz_works=yes ;; + esac]]) + AS_IF([test yes = "$lt_cv_sys_argz_works"], + [AC_DEFINE([HAVE_WORKING_ARGZ], 1, + [This value is set to 1 to indicate that the system argz facility works])], + [LT_ARGZ_H=lt__argz.h + AC_LIBOBJ([lt__argz])])]) + +AC_SUBST([LT_ARGZ_H]) +]) + +# ltdl.m4 - Configure ltdl for the target system. -*-Autoconf-*- +# +# Copyright (C) 1999-2008, 2011-2019, 2021-2024 Free Software +# Foundation, Inc. +# Written by Thomas Tanner, 1999 +# +# This file is free software; the Free Software Foundation gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. + +# serial 24 LTDL_INIT + +# LT_CONFIG_LTDL_DIR(DIRECTORY, [LTDL-MODE]) +# ------------------------------------------ +# DIRECTORY contains the libltdl sources. It is okay to call this +# function multiple times, as long as the same DIRECTORY is always given. +AC_DEFUN([LT_CONFIG_LTDL_DIR], +[AC_BEFORE([$0], [LTDL_INIT]) +_$0($*) +])# LT_CONFIG_LTDL_DIR + +# We break this out into a separate macro, so that we can call it safely +# internally without being caught accidentally by the sed scan in libtoolize. +m4_defun([_LT_CONFIG_LTDL_DIR], +[dnl remove trailing slashes +m4_pushdef([_ARG_DIR], m4_bpatsubst([$1], [/*$])) +m4_case(_LTDL_DIR, + [], [dnl only set lt_ltdl_dir if _ARG_DIR is not simply '.' + m4_if(_ARG_DIR, [.], + [], + [m4_define([_LTDL_DIR], _ARG_DIR) + _LT_SHELL_INIT([lt_ltdl_dir=']_ARG_DIR['])])], + [m4_if(_ARG_DIR, _LTDL_DIR, + [], + [m4_fatal([multiple libltdl directories: ']_LTDL_DIR[', ']_ARG_DIR['])])]) +m4_popdef([_ARG_DIR]) +])# _LT_CONFIG_LTDL_DIR + +# Initialise: +m4_define([_LTDL_DIR], []) + + +# _LT_BUILD_PREFIX +# ---------------- +# If Autoconf is new enough, expand to '$(top_build_prefix)', otherwise +# to '$(top_builddir)/'. +m4_define([_LT_BUILD_PREFIX], +[m4_ifdef([AC_AUTOCONF_VERSION], + [m4_if(m4_version_compare(m4_defn([AC_AUTOCONF_VERSION]), [2.62]), + [-1], [m4_ifdef([_AC_HAVE_TOP_BUILD_PREFIX], + [$(top_build_prefix)], + [$(top_builddir)/])], + [$(top_build_prefix)])], + [$(top_builddir)/])[]dnl +]) + + +# LTDL_CONVENIENCE +# ---------------- +# sets LIBLTDL to the link flags for the libltdl convenience library and +# LTDLINCL to the include flags for the libltdl header and adds +# --enable-ltdl-convenience to the configure arguments. Note that +# AC_CONFIG_SUBDIRS is not called here. LIBLTDL will be prefixed with +# '$(top_build_prefix)' if available, otherwise with '$(top_builddir)/', +# and LTDLINCL will be prefixed with '$(top_srcdir)/' (note the single +# quotes!). If your package is not flat and you're not using automake, +# define top_build_prefix, top_builddir, and top_srcdir appropriately +# in your Makefiles. +AC_DEFUN([LTDL_CONVENIENCE], +[AC_BEFORE([$0], [LTDL_INIT])dnl +dnl Although the argument is deprecated and no longer documented, +dnl LTDL_CONVENIENCE used to take a DIRECTORY orgument, if we have one +dnl here make sure it is the same as any other declaration of libltdl's +dnl location! This also ensures lt_ltdl_dir is set when configure.ac is +dnl not yet using an explicit LT_CONFIG_LTDL_DIR. +m4_ifval([$1], [_LT_CONFIG_LTDL_DIR([$1])])dnl +_$0() +])# LTDL_CONVENIENCE + +# AC_LIBLTDL_CONVENIENCE accepted a directory argument in older libtools, +# now we have LT_CONFIG_LTDL_DIR: +AU_DEFUN([AC_LIBLTDL_CONVENIENCE], +[_LT_CONFIG_LTDL_DIR([m4_default([$1], [libltdl])]) +_LTDL_CONVENIENCE]) + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBLTDL_CONVENIENCE], []) + + +# _LTDL_CONVENIENCE +# ----------------- +# Code shared by LTDL_CONVENIENCE and LTDL_INIT([convenience]). +m4_defun([_LTDL_CONVENIENCE], +[case $enable_ltdl_convenience in + no) AC_MSG_ERROR([this package needs a convenience libltdl]) ;; + "") enable_ltdl_convenience=yes + ac_configure_args="$ac_configure_args --enable-ltdl-convenience" ;; +esac +LIBLTDL='_LT_BUILD_PREFIX'"${lt_ltdl_dir+$lt_ltdl_dir/}libltdlc.la" +LTDLDEPS=$LIBLTDL +LTDLINCL='-I$(top_srcdir)'"${lt_ltdl_dir+/$lt_ltdl_dir}" + +AC_SUBST([LIBLTDL]) +AC_SUBST([LTDLDEPS]) +AC_SUBST([LTDLINCL]) + +# For backwards non-gettext consistent compatibility... +INCLTDL=$LTDLINCL +AC_SUBST([INCLTDL]) +])# _LTDL_CONVENIENCE + + +# LTDL_INSTALLABLE +# ---------------- +# sets LIBLTDL to the link flags for the libltdl installable library +# and LTDLINCL to the include flags for the libltdl header and adds +# --enable-ltdl-install to the configure arguments. Note that +# AC_CONFIG_SUBDIRS is not called from here. If an installed libltdl +# is not found, LIBLTDL will be prefixed with '$(top_build_prefix)' if +# available, otherwise with '$(top_builddir)/', and LTDLINCL will be +# prefixed with '$(top_srcdir)/' (note the single quotes!). If your +# package is not flat and you're not using automake, define top_build_prefix, +# top_builddir, and top_srcdir appropriately in your Makefiles. +# In the future, this macro may have to be called after LT_INIT. +AC_DEFUN([LTDL_INSTALLABLE], +[AC_BEFORE([$0], [LTDL_INIT])dnl +dnl Although the argument is deprecated and no longer documented, +dnl LTDL_INSTALLABLE used to take a DIRECTORY orgument, if we have one +dnl here make sure it is the same as any other declaration of libltdl's +dnl location! This also ensures lt_ltdl_dir is set when configure.ac is +dnl not yet using an explicit LT_CONFIG_LTDL_DIR. +m4_ifval([$1], [_LT_CONFIG_LTDL_DIR([$1])])dnl +_$0() +])# LTDL_INSTALLABLE + +# AC_LIBLTDL_INSTALLABLE accepted a directory argument in older libtools, +# now we have LT_CONFIG_LTDL_DIR: +AU_DEFUN([AC_LIBLTDL_INSTALLABLE], +[_LT_CONFIG_LTDL_DIR([m4_default([$1], [libltdl])]) +_LTDL_INSTALLABLE]) + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBLTDL_INSTALLABLE], []) + + +# _LTDL_INSTALLABLE +# ----------------- +# Code shared by LTDL_INSTALLABLE and LTDL_INIT([installable]). +m4_defun([_LTDL_INSTALLABLE], +[if test -f "$prefix/lib/libltdl.la"; then + lt_save_LDFLAGS=$LDFLAGS + LDFLAGS="-L$prefix/lib $LDFLAGS" + AC_CHECK_LIB([ltdl], [lt_dlinit], [lt_lib_ltdl=yes]) + LDFLAGS=$lt_save_LDFLAGS + if test yes = "${lt_lib_ltdl-no}"; then + if test yes != "$enable_ltdl_install"; then + # Don't overwrite $prefix/lib/libltdl.la without --enable-ltdl-install + AC_MSG_WARN([not overwriting libltdl at $prefix, force with '--enable-ltdl-install']) + enable_ltdl_install=no + fi + elif test no = "$enable_ltdl_install"; then + AC_MSG_WARN([libltdl not installed, but installation disabled]) + fi +fi + +# If configure.ac declared an installable ltdl, and the user didn't override +# with --disable-ltdl-install, we will install the shipped libltdl. +case $enable_ltdl_install in + no) ac_configure_args="$ac_configure_args --enable-ltdl-install=no" + LIBLTDL=-lltdl + LTDLDEPS= + LTDLINCL= + ;; + *) enable_ltdl_install=yes + ac_configure_args="$ac_configure_args --enable-ltdl-install" + LIBLTDL='_LT_BUILD_PREFIX'"${lt_ltdl_dir+$lt_ltdl_dir/}libltdl.la" + LTDLDEPS=$LIBLTDL + LTDLINCL='-I$(top_srcdir)'"${lt_ltdl_dir+/$lt_ltdl_dir}" + ;; +esac + +AC_SUBST([LIBLTDL]) +AC_SUBST([LTDLDEPS]) +AC_SUBST([LTDLINCL]) + +# For backwards non-gettext consistent compatibility... +INCLTDL=$LTDLINCL +AC_SUBST([INCLTDL]) +])# LTDL_INSTALLABLE + + +# _LTDL_MODE_DISPATCH +# ------------------- +m4_define([_LTDL_MODE_DISPATCH], +[dnl If _LTDL_DIR is '.', then we are configuring libltdl itself: +m4_if(_LTDL_DIR, [], + [], + dnl if _LTDL_MODE was not set already, the default value is 'subproject': + [m4_case(m4_default(_LTDL_MODE, [subproject]), + [subproject], [AC_CONFIG_SUBDIRS(_LTDL_DIR) + _LT_SHELL_INIT([lt_dlopen_dir=$lt_ltdl_dir])], + [nonrecursive], [_LT_SHELL_INIT([lt_dlopen_dir=$lt_ltdl_dir; lt_libobj_prefix=$lt_ltdl_dir/])], + [recursive], [], + [m4_fatal([unknown libltdl mode: ]_LTDL_MODE)])])dnl +dnl Be careful not to expand twice: +m4_define([$0], []) +])# _LTDL_MODE_DISPATCH + + +# _LT_LIBOBJ(MODULE_NAME) +# ----------------------- +# Like AC_LIBOBJ, except that MODULE_NAME goes into _LT_LIBOBJS instead +# of into LIBOBJS. +AC_DEFUN([_LT_LIBOBJ], [ + m4_pattern_allow([^_LT_LIBOBJS$]) + _LT_LIBOBJS="$_LT_LIBOBJS $1.$ac_objext" +])# _LT_LIBOBJS + + +# LTDL_INIT([OPTIONS]) +# -------------------- +# Clients of libltdl can use this macro to allow the installer to +# choose between a shipped copy of the ltdl sources or a preinstalled +# version of the library. If the shipped ltdl sources are not in a +# subdirectory named libltdl, the directory name must be given by +# LT_CONFIG_LTDL_DIR. +AC_DEFUN([LTDL_INIT], +[dnl Parse OPTIONS +_LT_SET_OPTIONS([$0], [$1]) + +dnl We need to keep our own list of libobjs separate from our parent project, +dnl and the easiest way to do that is redefine the AC_LIBOBJs macro while +dnl we look for our own LIBOBJs. +m4_pushdef([AC_LIBOBJ], m4_defn([_LT_LIBOBJ])) +m4_pushdef([AC_LIBSOURCES]) + +dnl If not otherwise defined, default to the 1.5.x compatible subproject mode: +m4_if(_LTDL_MODE, [], + [m4_define([_LTDL_MODE], m4_default([$2], [subproject])) + m4_if([-1], [m4_bregexp(_LTDL_MODE, [\(subproject\|\(non\)?recursive\)])], + [m4_fatal([unknown libltdl mode: ]_LTDL_MODE)])]) + +AC_ARG_WITH([included_ltdl], + [AS_HELP_STRING([--with-included-ltdl], + [use the GNU ltdl sources included here])]) + +if test yes != "$with_included_ltdl"; then + # We are not being forced to use the included libltdl sources, so + # decide whether there is a useful installed version we can use. + AC_CHECK_HEADER([ltdl.h], + [AC_CHECK_DECL([lt_dlinterface_register], + [AC_CHECK_LIB([ltdl], [lt_dladvise_preload], + [with_included_ltdl=no], + [with_included_ltdl=yes])], + [with_included_ltdl=yes], + [AC_INCLUDES_DEFAULT + #include ])], + [with_included_ltdl=yes], + [AC_INCLUDES_DEFAULT] + ) +fi + +dnl If neither LT_CONFIG_LTDL_DIR, LTDL_CONVENIENCE nor LTDL_INSTALLABLE +dnl was called yet, then for old times' sake, we assume libltdl is in an +dnl eponymous directory: +AC_PROVIDE_IFELSE([LT_CONFIG_LTDL_DIR], [], [_LT_CONFIG_LTDL_DIR([libltdl])]) + +AC_ARG_WITH([ltdl_include], + [AS_HELP_STRING([--with-ltdl-include=DIR], + [use the ltdl headers installed in DIR])]) + +if test -n "$with_ltdl_include"; then + if test -f "$with_ltdl_include/ltdl.h"; then : + else + AC_MSG_ERROR([invalid ltdl include directory: '$with_ltdl_include']) + fi +else + with_ltdl_include=no +fi + +AC_ARG_WITH([ltdl_lib], + [AS_HELP_STRING([--with-ltdl-lib=DIR], + [use the libltdl.la installed in DIR])]) + +if test -n "$with_ltdl_lib"; then + if test -f "$with_ltdl_lib/libltdl.la"; then : + else + AC_MSG_ERROR([invalid ltdl library directory: '$with_ltdl_lib']) + fi +else + with_ltdl_lib=no +fi + +case ,$with_included_ltdl,$with_ltdl_include,$with_ltdl_lib, in + ,yes,no,no,) + m4_case(m4_default(_LTDL_TYPE, [convenience]), + [convenience], [_LTDL_CONVENIENCE], + [installable], [_LTDL_INSTALLABLE], + [m4_fatal([unknown libltdl build type: ]_LTDL_TYPE)]) + ;; + ,no,no,no,) + # If the included ltdl is not to be used, then use the + # preinstalled libltdl we found. + AC_DEFINE([HAVE_LTDL], [1], + [Define this if a modern libltdl is already installed]) + LIBLTDL=-lltdl + LTDLDEPS= + LTDLINCL= + ;; + ,no*,no,*) + AC_MSG_ERROR(['--with-ltdl-include' and '--with-ltdl-lib' options must be used together]) + ;; + *) with_included_ltdl=no + LIBLTDL="-L$with_ltdl_lib -lltdl" + LTDLDEPS= + LTDLINCL=-I$with_ltdl_include + ;; +esac +INCLTDL=$LTDLINCL + +# Report our decision... +AC_MSG_CHECKING([where to find libltdl headers]) +AC_MSG_RESULT([$LTDLINCL]) +AC_MSG_CHECKING([where to find libltdl library]) +AC_MSG_RESULT([$LIBLTDL]) + +_LTDL_SETUP + +dnl restore autoconf definition. +m4_popdef([AC_LIBOBJ]) +m4_popdef([AC_LIBSOURCES]) + +AC_CONFIG_COMMANDS_PRE([ + _ltdl_libobjs= + _ltdl_ltlibobjs= + if test -n "$_LT_LIBOBJS"; then + # Remove the extension. + _lt_sed_drop_objext='s/\.o$//;s/\.obj$//' + for i in `for i in $_LT_LIBOBJS; do echo "$i"; done | $SED "$_lt_sed_drop_objext" | sort -u`; do + _ltdl_libobjs="$_ltdl_libobjs $lt_libobj_prefix$i.$ac_objext" + _ltdl_ltlibobjs="$_ltdl_ltlibobjs $lt_libobj_prefix$i.lo" + done + fi + AC_SUBST([ltdl_LIBOBJS], [$_ltdl_libobjs]) + AC_SUBST([ltdl_LTLIBOBJS], [$_ltdl_ltlibobjs]) +]) + +# Only expand once: +m4_define([LTDL_INIT]) +])# LTDL_INIT + +# Old names: +AU_DEFUN([AC_LIB_LTDL], [LTDL_INIT($@)]) +AU_DEFUN([AC_WITH_LTDL], [LTDL_INIT($@)]) +AU_DEFUN([LT_WITH_LTDL], [LTDL_INIT($@)]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIB_LTDL], []) +dnl AC_DEFUN([AC_WITH_LTDL], []) +dnl AC_DEFUN([LT_WITH_LTDL], []) + + +# _LTDL_SETUP +# ----------- +# Perform all the checks necessary for compilation of the ltdl objects +# -- including compiler checks and header checks. This is a public +# interface mainly for the benefit of libltdl's own configure.ac, most +# other users should call LTDL_INIT instead. +AC_DEFUN([_LTDL_SETUP], +[AC_REQUIRE([AC_PROG_CC])dnl +AC_REQUIRE([LT_SYS_MODULE_EXT])dnl +AC_REQUIRE([LT_SYS_MODULE_PATH])dnl +AC_REQUIRE([LT_SYS_DLSEARCH_PATH])dnl +AC_REQUIRE([LT_LIB_DLLOAD])dnl +AC_REQUIRE([LT_SYS_SYMBOL_USCORE])dnl +AC_REQUIRE([LT_FUNC_DLSYM_USCORE])dnl +AC_REQUIRE([LT_SYS_DLOPEN_DEPLIBS])dnl +AC_REQUIRE([LT_FUNC_ARGZ])dnl + +m4_require([_LT_CHECK_OBJDIR])dnl +m4_require([_LT_HEADER_DLFCN])dnl +m4_require([_LT_CHECK_DLPREOPEN])dnl +m4_require([_LT_DECL_SED])dnl + +dnl Don't require this, or it will be expanded earlier than the code +dnl that sets the variables it relies on: +_LT_ENABLE_INSTALL + +dnl _LTDL_MODE specific code must be called at least once: +_LTDL_MODE_DISPATCH + +# In order that ltdl.c can compile, find out the first AC_CONFIG_HEADERS +# the user used. This is so that ltdl.h can pick up the parent projects +# config.h file, The first file in AC_CONFIG_HEADERS must contain the +# definitions required by ltdl.c. +# FIXME: Remove use of undocumented AC_LIST_HEADERS (2.59 compatibility). +AC_CONFIG_COMMANDS_PRE([dnl +m4_pattern_allow([^LT_CONFIG_H$])dnl +m4_ifset([AH_HEADER], + [LT_CONFIG_H=AH_HEADER], + [m4_ifset([AC_LIST_HEADERS], + [LT_CONFIG_H=`echo "AC_LIST_HEADERS" | $SED 's|^[[ ]]*||;s|[[ :]].*$||'`], + [])])]) +AC_SUBST([LT_CONFIG_H]) + +AC_CHECK_HEADERS([unistd.h dl.h sys/dl.h dld.h mach-o/dyld.h dirent.h], + [], [], [AC_INCLUDES_DEFAULT]) + +AC_CHECK_FUNCS([closedir opendir readdir], [], [AC_LIBOBJ([lt__dirent])]) +AC_CHECK_FUNCS([strlcat strlcpy], [], [AC_LIBOBJ([lt__strl])]) + +m4_pattern_allow([LT_LIBEXT])dnl +AC_DEFINE_UNQUOTED([LT_LIBEXT],["$libext"],[The archive extension]) + +name= +eval "lt_libprefix=\"$libname_spec\"" +m4_pattern_allow([LT_LIBPREFIX])dnl +AC_DEFINE_UNQUOTED([LT_LIBPREFIX],["$lt_libprefix"],[The archive prefix]) + +name=ltdl +eval "LTDLOPEN=\"$libname_spec\"" +AC_SUBST([LTDLOPEN]) +])# _LTDL_SETUP + + +# _LT_ENABLE_INSTALL +# ------------------ +m4_define([_LT_ENABLE_INSTALL], +[AC_ARG_ENABLE([ltdl-install], + [AS_HELP_STRING([--enable-ltdl-install], [install libltdl])]) + +case ,$enable_ltdl_install,$enable_ltdl_convenience in + *yes*) ;; + *) enable_ltdl_convenience=yes ;; +esac + +m4_ifdef([AM_CONDITIONAL], +[AM_CONDITIONAL(INSTALL_LTDL, test no != "${enable_ltdl_install-no}") + AM_CONDITIONAL(CONVENIENCE_LTDL, test no != "${enable_ltdl_convenience-no}") + AM_CONDITIONAL(LTARGZH_EXISTS, test -n "$LT_ARGZ_H")]) +])# _LT_ENABLE_INSTALL + + +# LT_SYS_DLOPEN_DEPLIBS +# --------------------- +AC_DEFUN([LT_SYS_DLOPEN_DEPLIBS], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +AC_CACHE_CHECK([whether deplibs are loaded by dlopen], + [lt_cv_sys_dlopen_deplibs], + [# PORTME does your system automatically load deplibs for dlopen? + # or its logical equivalent (e.g. shl_load for HP-UX < 11) + # For now, we just catch OSes we know something about -- in the + # future, we'll try test this programmatically. + lt_cv_sys_dlopen_deplibs=unknown + case $host_os in + aix3*|aix4.1.*|aix4.2.*) + # Unknown whether this is true for these versions of AIX, but + # we want this 'case' here to explicitly catch those versions. + lt_cv_sys_dlopen_deplibs=unknown + ;; + aix[[4-9]]*) + lt_cv_sys_dlopen_deplibs=yes + ;; + amigaos*) + case $host_cpu in + powerpc) + lt_cv_sys_dlopen_deplibs=no + ;; + esac + ;; + darwin*) + # Assuming the user has installed a libdl from somewhere, this is true + # If you are looking for one http://www.opendarwin.org/projects/dlcompat + lt_cv_sys_dlopen_deplibs=yes + ;; + freebsd* | dragonfly* | midnightbsd*) + lt_cv_sys_dlopen_deplibs=yes + ;; + gnu* | linux* | k*bsd*-gnu | kopensolaris*-gnu) + # GNU and its variants, using gnu ld.so (Glibc) + lt_cv_sys_dlopen_deplibs=yes + ;; + hpux10*|hpux11*) + lt_cv_sys_dlopen_deplibs=yes + ;; + interix*) + lt_cv_sys_dlopen_deplibs=yes + ;; + irix[[12345]]*|irix6.[[01]]*) + # Catch all versions of IRIX before 6.2, and indicate that we don't + # know how it worked for any of those versions. + lt_cv_sys_dlopen_deplibs=unknown + ;; + irix*) + # The case above catches anything before 6.2, and it's known that + # at 6.2 and later dlopen does load deplibs. + lt_cv_sys_dlopen_deplibs=yes + ;; + *-mlibc) + lt_cv_sys_dlopen_deplibs=yes + ;; + netbsd* | netbsdelf*-gnu) + lt_cv_sys_dlopen_deplibs=yes + ;; + openbsd*) + lt_cv_sys_dlopen_deplibs=yes + ;; + osf[[1234]]*) + # dlopen did load deplibs (at least at 4.x), but until the 5.x series, + # it did *not* use an RPATH in a shared library to find objects the + # library depends on, so we explicitly say 'no'. + lt_cv_sys_dlopen_deplibs=no + ;; + osf5.0|osf5.0a|osf5.1) + # dlopen *does* load deplibs and with the right loader patch applied + # it even uses RPATH in a shared library to search for shared objects + # that the library depends on, but there's no easy way to know if that + # patch is installed. Since this is the case, all we can really + # say is unknown -- it depends on the patch being installed. If + # it is, this changes to 'yes'. Without it, it would be 'no'. + lt_cv_sys_dlopen_deplibs=unknown + ;; + osf*) + # the two cases above should catch all versions of osf <= 5.1. Read + # the comments above for what we know about them. + # At > 5.1, deplibs are loaded *and* any RPATH in a shared library + # is used to find them so we can finally say 'yes'. + lt_cv_sys_dlopen_deplibs=yes + ;; + qnx*) + lt_cv_sys_dlopen_deplibs=yes + ;; + solaris*) + lt_cv_sys_dlopen_deplibs=yes + ;; + sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + libltdl_cv_sys_dlopen_deplibs=yes + ;; + esac + ]) +if test yes != "$lt_cv_sys_dlopen_deplibs"; then + AC_DEFINE([LTDL_DLOPEN_DEPLIBS], [1], + [Define if the OS needs help to load dependent libraries for dlopen().]) +fi +])# LT_SYS_DLOPEN_DEPLIBS + +# Old name: +AU_ALIAS([AC_LTDL_SYS_DLOPEN_DEPLIBS], [LT_SYS_DLOPEN_DEPLIBS]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LTDL_SYS_DLOPEN_DEPLIBS], []) + + +# LT_SYS_MODULE_EXT +# ----------------- +AC_DEFUN([LT_SYS_MODULE_EXT], +[m4_require([_LT_SYS_DYNAMIC_LINKER])dnl +AC_CACHE_CHECK([what extension is used for runtime loadable modules], + [libltdl_cv_shlibext], +[ +module=yes +eval libltdl_cv_shlibext=$shrext_cmds +module=no +eval libltdl_cv_shrext=$shrext_cmds + ]) +if test -n "$libltdl_cv_shlibext"; then + m4_pattern_allow([LT_MODULE_EXT])dnl + AC_DEFINE_UNQUOTED([LT_MODULE_EXT], ["$libltdl_cv_shlibext"], + [Define to the extension used for runtime loadable modules, say, ".so".]) +fi +if test "$libltdl_cv_shrext" != "$libltdl_cv_shlibext"; then + m4_pattern_allow([LT_SHARED_EXT])dnl + AC_DEFINE_UNQUOTED([LT_SHARED_EXT], ["$libltdl_cv_shrext"], + [Define to the shared library suffix, say, ".dylib".]) +fi +if test -n "$shared_archive_member_spec"; then + m4_pattern_allow([LT_SHARED_LIB_MEMBER])dnl + AC_DEFINE_UNQUOTED([LT_SHARED_LIB_MEMBER], ["($shared_archive_member_spec.o)"], + [Define to the shared archive member specification, say "(shr.o)".]) +fi +])# LT_SYS_MODULE_EXT + +# Old name: +AU_ALIAS([AC_LTDL_SHLIBEXT], [LT_SYS_MODULE_EXT]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LTDL_SHLIBEXT], []) + + +# LT_SYS_MODULE_PATH +# ------------------ +AC_DEFUN([LT_SYS_MODULE_PATH], +[m4_require([_LT_SYS_DYNAMIC_LINKER])dnl +AC_CACHE_CHECK([what variable specifies run-time module search path], + [lt_cv_module_path_var], [lt_cv_module_path_var=$shlibpath_var]) +if test -n "$lt_cv_module_path_var"; then + m4_pattern_allow([LT_MODULE_PATH_VAR])dnl + AC_DEFINE_UNQUOTED([LT_MODULE_PATH_VAR], ["$lt_cv_module_path_var"], + [Define to the name of the environment variable that determines the run-time module search path.]) +fi +])# LT_SYS_MODULE_PATH + +# Old name: +AU_ALIAS([AC_LTDL_SHLIBPATH], [LT_SYS_MODULE_PATH]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LTDL_SHLIBPATH], []) + + +# LT_SYS_DLSEARCH_PATH +# -------------------- +AC_DEFUN([LT_SYS_DLSEARCH_PATH], +[m4_require([_LT_SYS_DYNAMIC_LINKER])dnl +AC_CACHE_CHECK([for the default library search path], + [lt_cv_sys_dlsearch_path], + [lt_cv_sys_dlsearch_path=$sys_lib_dlsearch_path_spec]) +if test -n "$lt_cv_sys_dlsearch_path"; then + sys_dlsearch_path= + for dir in $lt_cv_sys_dlsearch_path; do + if test -z "$sys_dlsearch_path"; then + sys_dlsearch_path=$dir + else + sys_dlsearch_path=$sys_dlsearch_path$PATH_SEPARATOR$dir + fi + done + m4_pattern_allow([LT_DLSEARCH_PATH])dnl + AC_DEFINE_UNQUOTED([LT_DLSEARCH_PATH], ["$sys_dlsearch_path"], + [Define to the system default library search path.]) +fi +])# LT_SYS_DLSEARCH_PATH + +# Old name: +AU_ALIAS([AC_LTDL_SYSSEARCHPATH], [LT_SYS_DLSEARCH_PATH]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LTDL_SYSSEARCHPATH], []) + + +# _LT_CHECK_DLPREOPEN +# ------------------- +m4_defun([_LT_CHECK_DLPREOPEN], +[m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl +AC_CACHE_CHECK([whether libtool supports -dlopen/-dlpreopen], + [libltdl_cv_preloaded_symbols], + [if test -n "$lt_cv_sys_global_symbol_pipe"; then + libltdl_cv_preloaded_symbols=yes + else + libltdl_cv_preloaded_symbols=no + fi + ]) +if test yes = "$libltdl_cv_preloaded_symbols"; then + AC_DEFINE([HAVE_PRELOADED_SYMBOLS], [1], + [Define if libtool can extract symbol lists from object files.]) +fi +])# _LT_CHECK_DLPREOPEN + + +# LT_LIB_DLLOAD +# ------------- +AC_DEFUN([LT_LIB_DLLOAD], +[m4_pattern_allow([^LT_DLLOADERS$]) +LT_DLLOADERS= +AC_SUBST([LT_DLLOADERS]) + +AC_LANG_PUSH([C]) +lt_dlload_save_LIBS=$LIBS + +LIBADD_DLOPEN= +AC_SEARCH_LIBS([dlopen], [dl], + [AC_DEFINE([HAVE_LIBDL], [1], + [Define if you have the libdl library or equivalent.]) + if test "$ac_cv_search_dlopen" != "none required"; then + LIBADD_DLOPEN=-ldl + fi + libltdl_cv_lib_dl_dlopen=yes + LT_DLLOADERS="$LT_DLLOADERS ${lt_dlopen_dir+$lt_dlopen_dir/}dlopen.la"], + [AC_LINK_IFELSE([AC_LANG_PROGRAM([[#if HAVE_DLFCN_H +# include +#endif + ]], [[dlopen(0, 0);]])], + [AC_DEFINE([HAVE_LIBDL], [1], + [Define if you have the libdl library or equivalent.]) + libltdl_cv_func_dlopen=yes + LT_DLLOADERS="$LT_DLLOADERS ${lt_dlopen_dir+$lt_dlopen_dir/}dlopen.la"], + [AC_CHECK_LIB([svld], [dlopen], + [AC_DEFINE([HAVE_LIBDL], [1], + [Define if you have the libdl library or equivalent.]) + LIBADD_DLOPEN=-lsvld libltdl_cv_func_dlopen=yes + LT_DLLOADERS="$LT_DLLOADERS ${lt_dlopen_dir+$lt_dlopen_dir/}dlopen.la"])])]) +if test yes = "$libltdl_cv_func_dlopen" || test yes = "$libltdl_cv_lib_dl_dlopen" +then + lt_save_LIBS=$LIBS + LIBS="$LIBS $LIBADD_DLOPEN" + AC_CHECK_FUNCS([dlerror]) + LIBS=$lt_save_LIBS +fi +AC_SUBST([LIBADD_DLOPEN]) + +LIBADD_SHL_LOAD= +AC_CHECK_FUNC([shl_load], + [AC_DEFINE([HAVE_SHL_LOAD], [1], + [Define if you have the shl_load function.]) + LT_DLLOADERS="$LT_DLLOADERS ${lt_dlopen_dir+$lt_dlopen_dir/}shl_load.la"], + [AC_CHECK_LIB([dld], [shl_load], + [AC_DEFINE([HAVE_SHL_LOAD], [1], + [Define if you have the shl_load function.]) + LT_DLLOADERS="$LT_DLLOADERS ${lt_dlopen_dir+$lt_dlopen_dir/}shl_load.la" + LIBADD_SHL_LOAD=-ldld])]) +AC_SUBST([LIBADD_SHL_LOAD]) + +case $host_os in +darwin[[1567]].*) +# We only want this for pre-Mac OS X 10.4. + AC_CHECK_FUNC([_dyld_func_lookup], + [AC_DEFINE([HAVE_DYLD], [1], + [Define if you have the _dyld_func_lookup function.]) + LT_DLLOADERS="$LT_DLLOADERS ${lt_dlopen_dir+$lt_dlopen_dir/}dyld.la"]) + ;; +beos*) + LT_DLLOADERS="$LT_DLLOADERS ${lt_dlopen_dir+$lt_dlopen_dir/}load_add_on.la" + ;; +cygwin* | mingw* | windows* | pw32*) + AC_CHECK_DECLS([cygwin_conv_path], [], [], [[#include ]]) + LT_DLLOADERS="$LT_DLLOADERS ${lt_dlopen_dir+$lt_dlopen_dir/}loadlibrary.la" + ;; +esac + +AC_CHECK_LIB([dld], [dld_link], + [AC_DEFINE([HAVE_DLD], [1], + [Define if you have the GNU dld library.]) + LT_DLLOADERS="$LT_DLLOADERS ${lt_dlopen_dir+$lt_dlopen_dir/}dld_link.la"]) +AC_SUBST([LIBADD_DLD_LINK]) + +m4_pattern_allow([^LT_DLPREOPEN$]) +LT_DLPREOPEN= +if test -n "$LT_DLLOADERS" +then + for lt_loader in $LT_DLLOADERS; do + LT_DLPREOPEN="$LT_DLPREOPEN-dlpreopen $lt_loader " + done + AC_DEFINE([HAVE_LIBDLLOADER], [1], + [Define if libdlloader will be built on this platform]) +fi +AC_SUBST([LT_DLPREOPEN]) + +dnl This isn't used anymore, but set it for backwards compatibility +LIBADD_DL="$LIBADD_DLOPEN $LIBADD_SHL_LOAD" +AC_SUBST([LIBADD_DL]) + +LIBS=$lt_dlload_save_LIBS +AC_LANG_POP +])# LT_LIB_DLLOAD + +# Old name: +AU_ALIAS([AC_LTDL_DLLIB], [LT_LIB_DLLOAD]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LTDL_DLLIB], []) + + +# LT_SYS_SYMBOL_USCORE +# -------------------- +# does the compiler prefix global symbols with an underscore? +AC_DEFUN([LT_SYS_SYMBOL_USCORE], +[m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl +AC_CACHE_CHECK([for _ prefix in compiled symbols], + [lt_cv_sys_symbol_underscore], + [lt_cv_sys_symbol_underscore=no + cat > conftest.$ac_ext <<_LT_EOF +void nm_test_func(){} +int main(void){nm_test_func;return 0;} +_LT_EOF + if AC_TRY_EVAL(ac_compile); then + # Now try to grab the symbols. + ac_nlist=conftest.nm + if AC_TRY_EVAL(NM conftest.$ac_objext \| $lt_cv_sys_global_symbol_pipe \> $ac_nlist) && test -s "$ac_nlist"; then + # See whether the symbols have a leading underscore. + if grep '^. _nm_test_func' "$ac_nlist" >/dev/null; then + lt_cv_sys_symbol_underscore=yes + else + if grep '^. nm_test_func ' "$ac_nlist" >/dev/null; then + : + else + echo "configure: cannot find nm_test_func in $ac_nlist" >&AS_MESSAGE_LOG_FD + fi + fi + else + echo "configure: cannot run $lt_cv_sys_global_symbol_pipe" >&AS_MESSAGE_LOG_FD + fi + else + echo "configure: failed program was:" >&AS_MESSAGE_LOG_FD + cat conftest.c >&AS_MESSAGE_LOG_FD + fi + rm -rf conftest* + ]) + sys_symbol_underscore=$lt_cv_sys_symbol_underscore + AC_SUBST([sys_symbol_underscore]) +])# LT_SYS_SYMBOL_USCORE + +# Old name: +AU_ALIAS([AC_LTDL_SYMBOL_USCORE], [LT_SYS_SYMBOL_USCORE]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LTDL_SYMBOL_USCORE], []) + + +# LT_FUNC_DLSYM_USCORE +# -------------------- +AC_DEFUN([LT_FUNC_DLSYM_USCORE], +[AC_REQUIRE([_LT_COMPILER_PIC])dnl for lt_prog_compiler_wl +AC_REQUIRE([LT_SYS_SYMBOL_USCORE])dnl for lt_cv_sys_symbol_underscore +AC_REQUIRE([LT_SYS_MODULE_EXT])dnl for libltdl_cv_shlibext +if test yes = "$lt_cv_sys_symbol_underscore"; then + if test yes = "$libltdl_cv_func_dlopen" || test yes = "$libltdl_cv_lib_dl_dlopen"; then + AC_CACHE_CHECK([whether we have to add an underscore for dlsym], + [libltdl_cv_need_uscore], + [libltdl_cv_need_uscore=unknown + dlsym_uscore_save_LIBS=$LIBS + LIBS="$LIBS $LIBADD_DLOPEN" + libname=conftmod # stay within 8.3 filename limits! + cat >$libname.$ac_ext <<_LT_EOF +[#line $LINENO "configure" +#include "confdefs.h" +/* When -fvisibility=hidden is used, assume the code has been annotated + correspondingly for the symbols needed. */ +#if defined __GNUC__ && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)) +int fnord () __attribute__((visibility("default"))); +#endif +int fnord () { return 42; }] +_LT_EOF + + # ltfn_module_cmds module_cmds + # Execute tilde-delimited MODULE_CMDS with environment primed for + # $module_cmds or $archive_cmds type content. + ltfn_module_cmds () + {( # subshell avoids polluting parent global environment + module_cmds_save_ifs=$IFS; IFS='~' + for cmd in @S|@1; do + IFS=$module_cmds_save_ifs + libobjs=$libname.$ac_objext; lib=$libname$libltdl_cv_shlibext + rpath=/not-exists; soname=$libname$libltdl_cv_shlibext; output_objdir=. + major=; versuffix=; verstring=; deplibs= + ECHO=echo; wl=$lt_prog_compiler_wl; allow_undefined_flag= + eval $cmd + done + IFS=$module_cmds_save_ifs + )} + + # Compile a loadable module using libtool macro expansion results. + $CC $pic_flag -c $libname.$ac_ext + ltfn_module_cmds "${module_cmds:-$archive_cmds}" + + # Try to fetch fnord with dlsym(). + libltdl_dlunknown=0; libltdl_dlnouscore=1; libltdl_dluscore=2 + cat >conftest.$ac_ext <<_LT_EOF +[#line $LINENO "configure" +#include "confdefs.h" +#if HAVE_DLFCN_H +#include +#endif +#include +#ifndef RTLD_GLOBAL +# ifdef DL_GLOBAL +# define RTLD_GLOBAL DL_GLOBAL +# else +# define RTLD_GLOBAL 0 +# endif +#endif +#ifndef RTLD_NOW +# ifdef DL_NOW +# define RTLD_NOW DL_NOW +# else +# define RTLD_NOW 0 +# endif +#endif +int main (void) { + void *handle = dlopen ("`pwd`/$libname$libltdl_cv_shlibext", RTLD_GLOBAL|RTLD_NOW); + int status = $libltdl_dlunknown; + if (handle) { + if (dlsym (handle, "fnord")) + status = $libltdl_dlnouscore; + else { + if (dlsym (handle, "_fnord")) + status = $libltdl_dluscore; + else + puts (dlerror ()); + } + dlclose (handle); + } else + puts (dlerror ()); + return status; +}] +_LT_EOF + if AC_TRY_EVAL(ac_link) && test -s "conftest$ac_exeext" 2>/dev/null; then + (./conftest; exit; ) >&AS_MESSAGE_LOG_FD 2>/dev/null + libltdl_status=$? + case x$libltdl_status in + x$libltdl_dlnouscore) libltdl_cv_need_uscore=no ;; + x$libltdl_dluscore) libltdl_cv_need_uscore=yes ;; + x*) libltdl_cv_need_uscore=unknown ;; + esac + fi + rm -rf conftest* $libname* + LIBS=$dlsym_uscore_save_LIBS + ]) + fi +fi + +if test yes = "$libltdl_cv_need_uscore"; then + AC_DEFINE([NEED_USCORE], [1], + [Define if dlsym() requires a leading underscore in symbol names.]) +fi +])# LT_FUNC_DLSYM_USCORE + +# Old name: +AU_ALIAS([AC_LTDL_DLSYM_USCORE], [LT_FUNC_DLSYM_USCORE]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LTDL_DLSYM_USCORE], []) + # Copyright (C) 2002-2024 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation @@ -1306,8 +2296,6 @@ AC_SUBST(am__xargs_n) ]) m4_include([../m4/libtool.m4]) -m4_include([../m4/ltargz.m4]) -m4_include([../m4/ltdl.m4]) m4_include([../m4/ltoptions.m4]) m4_include([../m4/ltsugar.m4]) m4_include([../m4/ltversion.m4]) diff --git a/mod.ccontrol/CLEARCHANCommand.cc b/mod.ccontrol/CLEARCHANCommand.cc index 8a8fc1d3..46b855f8 100644 --- a/mod.ccontrol/CLEARCHANCommand.cc +++ b/mod.ccontrol/CLEARCHANCommand.cc @@ -88,9 +88,9 @@ if(Chan) //Check if the user specified the modes, if not assume he ment all of the modes if(st.size() == 2) - doModes = "obklimrD"; + doModes = "obklimrDZ"; else if(!strcasecmp(string_upper(st[ 2 ]),"ALL")) - doModes = "obklimnsptrDCc"; + doModes = "obklimnsptrDCcuMZ"; else if(!strcasecmp(string_upper(st [ 2]),"-d")) Desynch = true; else diff --git a/mod.ccontrol/WHOISCommand.cc b/mod.ccontrol/WHOISCommand.cc index 62061f64..b3662ce4 100644 --- a/mod.ccontrol/WHOISCommand.cc +++ b/mod.ccontrol/WHOISCommand.cc @@ -99,14 +99,26 @@ bot->Notice(theClient, "%s has been connected for %s [since %ld]", if (Target->isModeR()) { string accountFlags; + if( Target->getAccountFlag( iClient::X_TOTP_REQ_IPR ) || Target->getAccountFlag(iClient::X_TOTP_ENABLED ) ) + { + accountFlags += ( Target->getAccountFlag( iClient::X_TOTP_REQ_IPR ) ) ? "TOTP_REQ_IPR " : "TOTP "; + + // Check for disabled methods + std::string disabled; + if( Target->getAccountFlag( iClient::X_WEB_DISABLE_TOTP ) ) + disabled += ( disabled.empty() ? "WEB" : ",WEB" ) ; + if( Target->getAccountFlag( iClient::X_CERT_DISABLE_TOTP ) ) + disabled += ( disabled.empty() ? "CERT" : ",CERT" ) ; + if( !disabled.empty() ) + accountFlags += "(DISABLE=" + disabled + ") "; + } + if(Target->getAccountFlag(iClient::X_GLOBAL_SUSPEND)) accountFlags += "SUSPENDED "; - if(Target->getAccountFlag(iClient::X_TOTP_ENABLED)) - accountFlags += "TOTP "; - if(Target->getAccountFlag(iClient::X_TOTP_REQ_IPR)) - accountFlags += "TOTP_REQ_IPR "; if(Target->getAccountFlag(iClient::X_FRAUD)) accountFlags += "FRAUD "; + if(Target->getAccountFlag(iClient::X_CERTONLY)) + accountFlags += "CERTONLY "; /* client is authed - show it here */ bot->Notice(theClient, "%s is authed as [%s]", @@ -123,6 +135,14 @@ bot->Notice( theClient, "Numeric: %s, UserModes: %s, Server Numeric: %s (%s)", targetServer->getName().c_str() ) ; +if( Target->isModeZ() ) + { + bot->Notice( theClient, "%s is connected using TLS", + st[ 1 ].c_str()) ; + if( Target->hasTlsFingerprint() ) + bot->Notice( theClient, " Fingerprint: %s", compactToCanonical( Target->getTlsFingerprint() ).c_str() ) ; + } + if( Target->isOper() ) { bot->Notice( theClient, "%s is an IRCoperator", diff --git a/mod.ccontrol/ccontrol.cc b/mod.ccontrol/ccontrol.cc index f11d025a..10132580 100644 --- a/mod.ccontrol/ccontrol.cc +++ b/mod.ccontrol/ccontrol.cc @@ -950,6 +950,9 @@ for(glineIterator GLptr = rnGlineList.begin(); GLptr != rnGlineList.end(); ++GLp rnGlineList.clear(); +// Deallocate the database handle +delete SQLDb; SQLDb = 0; + } // Register a command handler @@ -6242,6 +6245,7 @@ void ccontrol::announce(iClient* theClient, const string& text) string(), 0, 0, + string(), "Announcement Service.", ::time( 0 ) ) ; assert( newClient != 0 ); @@ -7417,6 +7421,7 @@ iClient* newClient = new (std::nothrow) iClient( string(), 0, 0, + string(), fullname, ::time( 0 ) ) ; assert( newClient != 0 ); diff --git a/mod.cloner/cloner.cc b/mod.cloner/cloner.cc index f895b972..d5f9d5de 100644 --- a/mod.cloner/cloner.cc +++ b/mod.cloner/cloner.cc @@ -868,6 +868,11 @@ if( theChan->getMode( Channel::MODE_R ) && !theClone->getMode( iClient::MODE_REGISTERED ) ) return 0 ; +/* Chanmode +Z? */ +if( theChan->getMode( Channel::MODE_Z ) + && !theClone->getMode( iClient::MODE_TLS ) ) + return 0 ; + /* Banned? */ if( banMatch( theChan, theClone ) ) return 0 ; @@ -1038,6 +1043,7 @@ iClient* newClient = new iClient( account, account_id, 0, + string(), cloneDescription, ::time( nullptr ) ) ; assert( newClient != nullptr ) ; diff --git a/mod.cservice/CERTCommand.cc b/mod.cservice/CERTCommand.cc new file mode 100644 index 00000000..9e73b808 --- /dev/null +++ b/mod.cservice/CERTCommand.cc @@ -0,0 +1,250 @@ +/** + * CERTCommand.cc + * + * 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. + * + */ + +#include +#include "cservice.h" +#include "StringTokenizer.h" +#include "ELog.h" +#include "responses.h" + +namespace gnuworld +{ + +bool CERTCommand::Exec( iClient* [[maybe_unused]] theClient, const string& [[maybe_unused]] Message ) +{ +#ifdef NEW_IRCU_FEATURES + +bot->incStat("COMMANDS.CERT"); + +sqlUser* theUser = bot->isAuthed( theClient, true ) ; +if( !theUser ) + { + return false ; + } + +StringTokenizer st( Message ) ; +if( st.size() < 2 ) + { + Usage( theClient ) ; + return true ; + } + +string Command = string_upper( st[ 1 ] ) ; +if( ( Command != "ADD" ) && ( Command != "REM" ) && ( Command != "LIST" ) ) + { + Usage( theClient ) ; + return true ; + } + +if( Command == "LIST" ) + { + bot->Notice( theClient, "+-------------------------------------------------------------------------------------------------+------------------------------------------+--------------+--------------------+" ) ; + bot->Notice( theClient, "| %-95s | %-40s | %-12s | %-18s |", "TLS Fingerprint", "Added By", "Last Updated", "Note" ) ; + bot->Notice( theClient, "+-------------------------------------------------------------------------------------------------+------------------------------------------+--------------+--------------------+" ) ; + + std::stringstream theQuery ; + theQuery << "SELECT fingerprint, added_by, added_ts, note FROM users_fingerprints WHERE user_id = " + << theClient->getAccountID() + << " ORDER BY added_ts" ; + + if( !bot->SQLDb->Exec( theQuery, true ) ) + { + LOGSQL_ERROR( bot->SQLDb ) ; + return false ; + } + + if( bot->SQLDb->Tuples() > 0 ) + { + for( unsigned int i = 0 ; i < bot->SQLDb->Tuples() ; i++ ) + bot->Notice( theClient, "| %-95s | %-40s | %-12s | %-18s |", + compactToCanonical( bot->SQLDb->GetValue( i, 0 ) ).c_str(), + bot->SQLDb->GetValue( i, 1 ).c_str(), + prettyTime( std::stoul( bot->SQLDb->GetValue( i, 2 ) ), false ).c_str(), + bot->SQLDb->GetValue( i, 3 ).c_str() ) ; + bot->Notice( theClient, "+-------------------------------------------------------------------------------------------------+------------------------------------------+--------------+--------------------+" ) ; + bot->Notice( theClient, "Done listing %d fingerprint%s.", + bot->SQLDb->Tuples(), bot->SQLDb->Tuples() > 1 ? "s" : "" ) ; + } + else + { + bot->Notice( theClient, bot->getResponse( theUser, language::no_fingerprints_found ) ) ; + } + + if( theClient->hasTlsFingerprint() ) + { + bot->Notice( theClient, bot->getResponse( theUser, language::your_fingerprint_is ).c_str(), + compactToCanonical( theClient->getTlsFingerprint() ).c_str() ) ; + } + + return true ; + } + +if( Command == "ADD" ) + { + /* Check whether this user already has reached the limit of fingerprints. */ + if( bot->hasFP( theUser) > bot->getConfmaxFingerprints() ) + { + bot->Notice( theClient, bot->getResponse( theUser, language::max_fingerprints ).c_str(), bot->getConfmaxFingerprints() ) ; + return true ; + } + + string fingerPrint, note ; + + /* No param provided. Use current fingerprint, if any. */ + if( st.size() < 3 ) + { + if( theClient->hasTlsFingerprint() ) + fingerPrint = theClient->getTlsFingerprint() ; + else + { + Usage( theClient ) ; + return true ; + } + } + /* We have one param. */ + else if( st.size() == 3 ) + { + /* Is the param a fingerprint? */ + if( isValidSHA256Fingerprint( st[ 2 ] ) ) + fingerPrint = canonicalToCompact( st[ 2 ] ) ; + /* If it is not a fingerprint, we treat it as a note if (and only if) the user has a fingerprint. */ + else if( theClient->hasTlsFingerprint() ) + note = st[ 2 ] ; + /* If the param is not a fingerprint and the user does not have a fingerprint, fail. */ + else + { + bot->Notice( theClient, bot->getResponse( theUser, language::invalid_fingerprint ).c_str() ) ; + return true ; + } + } + /* We have either two params, or a note consisting of several words. */ + else if( st.size() > 3 ) + { + /* Is the first word a fingerprint? */ + if( isValidSHA256Fingerprint( st[ 2 ] ) ) + { + fingerPrint = canonicalToCompact( st[ 2 ] ) ; + note = st.assemble( 3 ) ; + } + /* If it is not a fingerprint, we treat it as a note if (and only if) the user has a fingerprint. */ + else if( theClient->hasTlsFingerprint() ) + note = st.assemble( 2 ) ; + /* If the first word is not a fingerprint and the user does not have a fingerprint, fail. */ + else + { + bot->Notice( theClient, bot->getResponse( theUser, language::invalid_fingerprint ).c_str() ) ; + return true ; + } + } + + /* Add to cache. This will return false if the fingerprint already exists. */ + auto result = bot->addFP( canonicalToCompact( fingerPrint ), theClient->getAccountID() ) ; + if( !result.second ) + { + bot->Notice( theClient, bot->getResponse( theUser, language::fingerprint_already_exists ).c_str() ) ; + return true ; + } + + /* Add to SQL. */ + std::stringstream theQuery ; + theQuery << "INSERT INTO users_fingerprints (user_id, fingerprint, added_ts, added_by, note) VALUES (" + << theClient->getAccountID() << ", '" + << fingerPrint + << "', date_part('epoch', CURRENT_TIMESTAMP)::int, '" + << theClient->getRealNickUserHost() << "', '" + << note << "')" + << std::endl ; + + if( !bot->SQLDb->Exec( theQuery, true ) ) + { + LOGSQL_ERROR( bot->SQLDb ) ; + return false ; + } + + bot->Notice( theClient, bot->getResponse( theUser, language::fingerprint_added ).c_str(), + compactToCanonical( fingerPrint ).c_str() ) ; + + return true ; + } + +if( Command == "REM" ) + { + string fingerPrint ; + + /* No fingerprint been provided. Use current, if any. */ + if( st.size() < 3 ) + { + if( theClient->hasTlsFingerprint() ) + fingerPrint = theClient->getTlsFingerprint() ; + else + { + Usage( theClient ) ; + return true ; + } + } + else + { + if( !isValidSHA256Fingerprint( st[ 2 ] ) ) + { + bot->Notice( theClient, bot->getResponse( theUser, language::invalid_fingerprint ).c_str() ) ; + return true ; + } + + fingerPrint = canonicalToCompact( st[ 2 ] ) ; + } + + /* Don't remove last fingerprint if CERTONLY is ON. */ + if( bot->hasFP( theUser) == 1 && theUser->getFlag( sqlUser::F_CERTONLY ) ) + { + bot->Notice( theClient, bot->getResponse( theUser, language::fingerprint_norem_certonly ).c_str() ) ; + return true ; + } + + if( !bot->checkFP( fingerPrint, theClient->getAccountID() ) ) + { + bot->Notice( theClient, bot->getResponse( theUser, language::fingerprint_not_found ).c_str() ) ; + return true ; + } + + /* Remove from SQL. */ + std::stringstream theQuery ; + theQuery << "DELETE FROM users_fingerprints WHERE fingerprint ='" + << fingerPrint << "'" + << std::endl ; + + if( !bot->SQLDb->Exec( theQuery, true ) ) + { + LOGSQL_ERROR( bot->SQLDb ) ; + return false ; + } + /* Remove from cache. */ + bot->removeFP( fingerPrint ) ; + + bot->Notice( theClient, bot->getResponse( theUser, language::fingerprint_removed ).c_str(), + compactToCanonical( fingerPrint ).c_str() ) ; + + return true ; + } + +#endif // NEW_IRCU_FEATURES +return true ; +} + +} // namespace gnuworld. diff --git a/mod.cservice/CHANINFOCommand.cc b/mod.cservice/CHANINFOCommand.cc index 2b4f06b7..26e09ab0 100644 --- a/mod.cservice/CHANINFOCommand.cc +++ b/mod.cservice/CHANINFOCommand.cc @@ -141,7 +141,7 @@ if( string::npos == st[ 1 ].find_first_of( '#' ) ) /* build up a flag string */ string flagsSet; - if (theUser->getFlag(sqlUser::F_GLOBAL_SUSPEND)) + if (theUser->getFlag(sqlUser::F_GLOBAL_SUSPEND)) flagsSet += "SUSPEND "; if (theUser->getFlag(sqlUser::F_INVIS)) flagsSet += "INVISIBLE "; @@ -169,10 +169,20 @@ if( string::npos == st[ 1 ].find_first_of( '#' ) ) if (adminAccess || (tmpUser == theUser)) { - if (theUser->getFlag(sqlUser::F_TOTP_REQ_IPR)) - flagsSet += "TOTP_REQ_IPR "; - else if (theUser->getFlag(sqlUser::F_TOTP_ENABLED)) - flagsSet += "TOTP "; + if (theUser->getFlag(sqlUser::F_TOTP_REQ_IPR) || theUser->getFlag(sqlUser::F_TOTP_ENABLED)) + { + flagsSet += (theUser->getFlag(sqlUser::F_TOTP_REQ_IPR)) ? "TOTP_REQ_IPR " : "TOTP "; + + // Check for disabled methods + std::string disabled; + if (theUser->getFlag(sqlUser::F_WEB_DISABLE_TOTP)) + disabled += (disabled.empty() ? "WEB" : ",WEB"); + if (theUser->getFlag(sqlUser::F_CERT_DISABLE_TOTP)) + disabled += (disabled.empty() ? "CERT" : ",CERT"); + + if (!disabled.empty()) + flagsSet += "(DISABLE=" + disabled + ") "; + } } /* flags with variables */ if (langString.size() > 0) @@ -180,13 +190,16 @@ if( string::npos == st[ 1 ].find_first_of( '#' ) ) /* flags with variables for admins (or self-viewing) only */ if (adminAccess || (tmpUser == theUser)) { + if (theUser->getFlag(sqlUser::F_AUTOHIDE)) + flagsSet += "AUTOHIDE "; + int maxLogins = theUser->getMaxLogins(); stringstream ss; ss << maxLogins; // << ends ; if (maxLogins > 1) flagsSet += "MAXLOGINS=" + ss.str() + " "; - + stringstream autoInviteQuery; autoInviteQuery << "SELECT channel_id from levels" @@ -404,10 +417,10 @@ if( string::npos == st[ 1 ].find_first_of( '#' ) ) bot->Notice(theClient, "Last Hostmask: %s", theUser->getLastHostMask().c_str()); //Show ip only to admins - if(adminAccess > 0) + if(adminAccess > 0) { bot->Notice(theClient, "Last IP: %s", - theUser->getLastIP().c_str()); + theUser->getLastIP().c_str()); } } @@ -694,7 +707,7 @@ if( !theChan ) if (bot->SQLDb->Tuples() > 0) comCount = atoi(bot->SQLDb->GetValue(0,0)); } - + // output additional information if user is admin, supporter, or applicant) if (showsupplist) { diff --git a/mod.cservice/CLEARMODECommand.cc b/mod.cservice/CLEARMODECommand.cc index 4eae2167..647a3f42 100644 --- a/mod.cservice/CLEARMODECommand.cc +++ b/mod.cservice/CLEARMODECommand.cc @@ -100,7 +100,7 @@ if(!tmpChan) return false; } -bot->ClearMode( tmpChan, string( "mstnipklrDcC" ), false ) ; +bot->ClearMode( tmpChan, string( "mstnipklrDcCuMZ" ), false ) ; bot->Notice(theClient, bot->getResponse(theUser, diff --git a/mod.cservice/HELLOCommand.cc b/mod.cservice/HELLOCommand.cc index 9393544b..583a25d9 100644 --- a/mod.cservice/HELLOCommand.cc +++ b/mod.cservice/HELLOCommand.cc @@ -180,12 +180,24 @@ string cryptpass = bot->CryptPass(plainpass); string updatedBy = "HELLO used by: "; updatedBy += theClient->getNickUserHost().c_str(); -newUser = new (std::nothrow) sqlUser(bot->SQLDb); +newUser = new (std::nothrow) sqlUser(bot); newUser->setUserName(escapeSQLChars(st[1].c_str())); newUser->setEmail(escapeSQLChars(st[2])); newUser->setPassword(cryptpass.c_str()); newUser->setLastUpdatedBy(updatedBy); newUser->setFlag(sqlUser::F_INVIS); + +string err ; +auto recOpt = make_scram_sha256_record( plainpass, &err ) ; +if( !recOpt ) + { + LOG( ERROR, "[SCRAM] Record generation error: {}", err ) ; + } +else + { + std::string scram_record = *recOpt ; + newUser->setScramRecord( scram_record ) ; + } newUser->Insert(); bot->Notice(theClient, "I generated this password for you: \002%s\002", diff --git a/mod.cservice/LOGINCommand.cc b/mod.cservice/LOGINCommand.cc index e397893d..640bfb68 100644 --- a/mod.cservice/LOGINCommand.cc +++ b/mod.cservice/LOGINCommand.cc @@ -37,16 +37,11 @@ namespace gnuworld { -using std::string ; -using std::endl ; -using std::ends ; -using std::stringstream ; -using namespace gnuworld; bool LOGINCommand::Exec( iClient* theClient, const string& Message ) { StringTokenizer st( Message ) ; -if( st.size() < 3 ) +if( st.size() < 2 ) { Usage(theClient); return true; @@ -65,181 +60,25 @@ if (tmpUser) tmpUser->getUserName().c_str()); return false; } -unsigned int maxFailedLogins = bot->getConfigVar("MAX_FAILED_LOGINS")->asInt(); -unsigned int failedLogins = bot->getFailedLogins(theClient); -if ((maxFailedLogins > 0) && (failedLogins >= maxFailedLogins)) -{ - /* exceeded maximum failed logins */ - bot->Notice(theClient, - bot->getResponse(tmpUser, - language::max_failed_logins, - string("AUTHENTICATION FAILED as %s (Exceeded maximum login failures for this session)")).c_str(), - st[1].c_str()); - return false; -} - -sqlUser* theUser; -int auth_res = bot->authenticateUser(st[1],st.assemble(2),theClient,&theUser); -unsigned int loginTime = bot->getUplink()->getStartTime() + bot->getConfloginDelay(); -unsigned int max_failed_logins = bot->getConfigVar("FAILED_LOGINS")->asInt(); -unsigned int failed_login_rate = bot->getConfigVar("FAILED_LOGINS_RATE")->asInt(); -string clientList; - -switch(auth_res) - { - case cservice::TOO_EARLY_TOLOGIN: - bot->Notice(theClient, "AUTHENTICATION FAILED as %s (Unable " - "to login during reconnection, please try again in " - "%i seconds)", - st[1].c_str(), (loginTime - bot->currentTime())); - return false; - break; - case cservice::AUTH_FAILED: - bot->setFailedLogins(theClient, failedLogins+1); - bot->Notice(theClient, "AUTHENTICATION FAILED as %s", st[1].c_str()); - return false; - break; - case cservice::AUTH_UNKNOWN_USER: - bot->setFailedLogins(theClient, failedLogins+1); - bot->Notice(theClient, - bot->getResponse(tmpUser, - language::not_registered, - string("AUTHENTICATION FAILED as %s")).c_str(), - st[1].c_str()); - return false; - break; - case cservice::AUTH_SUSPENDED_USER: - bot->setFailedLogins(theClient, failedLogins+1); - bot->Notice(theClient, "AUTHENTICATION FAILED as %s (Suspended)", - st[1].c_str()); - return false; - break; - case cservice::AUTH_NO_TOKEN: - bot->setFailedLogins(theClient, failedLogins+1); - bot->Notice(theClient,"AUTHENTICATION FAILED as %s (Missing TOTP token)",st[1].c_str()); - return false; - break; - case cservice::AUTH_INVALID_PASS: - if (failed_login_rate==0) - failed_login_rate = 900; - bot->setFailedLogins(theClient, failedLogins+1); - bot->Notice(theClient, - bot->getResponse(theUser, - language::auth_failed, - string("AUTHENTICATION FAILED as %s")).c_str(), - theUser->getUserName().c_str()); - /* increment failed logins counter */ - theUser->incFailedLogins(); - if ((max_failed_logins > 0) && (theUser->getFailedLogins() > max_failed_logins) && - (theUser->getLastFailedLoginTS() < (time(NULL) - failed_login_rate))) - { - /* we have exceeded our maximum - alert relay channel */ - /* work out a checksum for the password. Yes, I could have - * just used a checksum of the original password, but this - * means it's harder to 'fool' the check digit with a real - * password - create MD5 from original salt stored */ - unsigned char checksum; - md5 hash; - md5Digest digest; - - if (theUser->getPassword().size() < 9) - { - checksum = 0; - } else { - string salt = theUser->getPassword().substr(0, 8); - string guess = salt + st.assemble(2); - - hash.update( (const unsigned char *)guess.c_str(), guess.size() ); - hash.report( digest ); - - checksum = 0; - for (size_t i = 0; i < MD5_DIGEST_LENGTH; i++) - { - /* add ascii value to check digit */ - checksum += digest[i]; - } - } - - theUser->setLastFailedLoginTS(time(NULL)); - bot->logPrivAdminMessage("%d failed logins for %s (last attempt by %s, checksum %d).", - theUser->getFailedLogins(), - theUser->getUserName().c_str(), - theClient->getRealNickUserHost().c_str(), - checksum); - } - return false; - break; - case cservice::AUTH_ERROR: - bot->Notice(theClient,"AUTHENTICATION FAILED as %s due to an error, please contact CService represetitive",st[1].c_str()); - return false; - break; - case cservice::AUTH_INVALID_TOKEN: - bot->setFailedLogins(theClient, failedLogins+1); - bot->Notice(theClient, - bot->getResponse(theUser, - language::auth_failed_token, - string("AUTHENTICATION FAILED as %s (Invalid Token)")).c_str(), - theUser->getUserName().c_str()); - /* increment failed logins counter */ - theUser->incFailedLogins(); - return false; - break; - case cservice::AUTH_FAILED_IPR: - bot->setFailedLogins(theClient, failedLogins+1); - bot->Notice(theClient, "AUTHENTICATION FAILED as %s (IPR)", - st[1].c_str()); - /* notify the relay channel */ - bot->logAdminMessage("%s (%s) failed IPR check.", - theClient->getNickName().c_str(), - st[1].c_str()); - /* increment failed logins counter */ - theUser->incFailedLogins(); - if ((max_failed_logins > 0) && (theUser->getFailedLogins() > max_failed_logins) && - (theUser->getLastFailedLoginTS() < (time(NULL) - failed_login_rate))) - { - /* we have exceeded our maximum - alert relay channel */ - theUser->setLastFailedLoginTS(time(NULL)); - bot->logPrivAdminMessage("%d failed logins for %s (last attempt by %s).", - theUser->getFailedLogins(), - theUser->getUserName().c_str(), - theClient->getRealNickUserHost().c_str()); - } - return false; - break; - case cservice::AUTH_ML_EXCEEDED: - bot->setFailedLogins(theClient, failedLogins+1); - bot->Notice(theClient, "AUTHENTICATION FAILED as %s (Maximum " - "concurrent logins exceeded).", - theUser->getUserName().c_str()); - - for( sqlUser::networkClientListType::iterator ptr = theUser->networkClientList.begin() ; - ptr != theUser->networkClientList.end() ; ) - { - clientList += (*ptr)->getNickUserHost(); - ++ptr; - if (ptr != theUser->networkClientList.end()) - { - clientList += ", "; - } - } // for() - - bot->Notice(theClient, "Current Sessions: %s", clientList.c_str()); - return false; - break; - case cservice::AUTH_SUCCEEDED: - break; - default: - //Should never get here! - LOG_MSG( ERROR, "Response {auth_res} while authenticating!") - .with( "client", theClient ) - .logStructured() ; - bot->Notice(theClient,"AUTHENTICATION FAILED as %s (due to an error)\n",st[1].c_str()); - return false; - break; - } - -return bot->doCommonAuth(theClient, theUser->getUserName()); +cservice::AuthStruct auth = { + AuthType::LOGIN, // auth type + cservice::AUTH_ERROR, // result (placeholder) + st[ 1 ], // username + st.assemble( 2 ), // password/token + theClient->getUserName(), // ident + xIP( theClient->getIP() ).GetNumericIP(), // ip + theClient->getTlsFingerprint(), // tls fingerprint + nullptr, // sqlUser (placeholder) + theClient, // iClient + {} // no sasl +} ; + +cservice::AuthResult auth_res = bot->authenticateUser( auth ) ; +auth.result = auth_res ; +bot->processAuthentication( auth ) ; + +return true; } } // namespace gnuworld. diff --git a/mod.cservice/Makefile.am b/mod.cservice/Makefile.am index 54782798..587e0fdc 100755 --- a/mod.cservice/Makefile.am +++ b/mod.cservice/Makefile.am @@ -11,6 +11,7 @@ libcservice_la_CXXFLAGS = -I$(top_srcdir)/db -I${top_srcdir}/include \ libcservice_la_SOURCES = \ mod.cservice/banMatcher.cc \ mod.cservice/cservice.cc \ + mod.cservice/cservice_crypt.cc \ mod.cservice/networkData.cc \ mod.cservice/sqlChannel.cc \ mod.cservice/sqlUser.cc \ @@ -24,6 +25,7 @@ libcservice_la_SOURCES = \ mod.cservice/ADDUSERCommand.cc \ mod.cservice/BANCommand.cc \ mod.cservice/BANLISTCommand.cc \ + mod.cservice/CERTCommand.cc \ mod.cservice/CHANINFOCommand.cc \ mod.cservice/CLEARMODECommand.cc \ mod.cservice/DEOPCommand.cc \ @@ -82,6 +84,8 @@ EXTRA_DIST += \ mod.cservice/constants.h \ mod.cservice/cserviceCommands.h \ mod.cservice/cservice_config.h \ + mod.cservice/cservice_confvars.h \ + mod.cservice/cservice_crypt.h \ mod.cservice/cservice.h \ mod.cservice/levels.h \ mod.cservice/networkData.h \ diff --git a/mod.cservice/NEWPASSCommand.cc b/mod.cservice/NEWPASSCommand.cc index df1cb38f..c27bcbef 100644 --- a/mod.cservice/NEWPASSCommand.cc +++ b/mod.cservice/NEWPASSCommand.cc @@ -139,6 +139,19 @@ output << ends; // Prepend the md5 hash to the salt string finalPassword = salt + output.str().c_str(); tmpUser->setPassword(finalPassword); +std::string err ; +// elog << "Generating SCRAM record for user " << theUser->getUserName() << " and password: [" << st.assemble( 0, pass_end ) << "]\n" ; +auto recOpt = make_scram_sha256_record( st.assemble( 1 ), &err ) ; + +if( !recOpt ) + { + LOG( ERROR, "SCRAM generation error: {}", err ) ; + } +else + { + std::string scram_record = *recOpt ; + tmpUser->setScramRecord( scram_record ) ; + } if( tmpUser->commit(theClient) ) { diff --git a/mod.cservice/SETCommand.cc b/mod.cservice/SETCommand.cc index 7f4bdd6e..767c2e07 100644 --- a/mod.cservice/SETCommand.cc +++ b/mod.cservice/SETCommand.cc @@ -147,6 +147,79 @@ if( st[1][0] != '#' ) // Didn't find a hash? return true; } +#ifdef NEW_IRCU_FEATURES + if (option == "AUTOHIDE") + { + if (value == "ON") + { + theUser->setFlag(sqlUser::F_AUTOHIDE); + theUser->commit(theClient); + bot->Notice(theClient, + bot->getResponse(theUser, + language::autohide_on, + string("Your AUTOHIDE setting is now ON."))); + return true; + } + + if (value == "OFF") + { + theUser->removeFlag(sqlUser::F_AUTOHIDE); + theUser->commit(theClient); + bot->Notice(theClient, + bot->getResponse(theUser, + language::autohide_off, + string("Your AUTOHIDE setting is now OFF."))); + return true; + } + + bot->Notice(theClient, + bot->getResponse(theUser, + language::set_cmd_syntax_on_off, + string("value of %s must be ON or OFF")).c_str(), + option.c_str()); + return true; + } + + if (option == "CERTONLY") + { + if (value == "ON") + { + if (!bot->hasFP(theUser)) + { + bot->Notice(theClient, + bot->getResponse(theUser, + language::no_fingerprints_registered, + string("You currently don't have any fingerprints added to your account. For more information, use '/msg X help fingerprint'"))); + return true; + } + theUser->setFlag(sqlUser::F_CERTONLY); + theUser->commit(theClient); + bot->Notice(theClient, + bot->getResponse(theUser, + language::certonly_on, + string("Your CERTONLY setting is now ON."))); + return true; + } + + if (value == "OFF") + { + theUser->removeFlag(sqlUser::F_CERTONLY); + theUser->commit(theClient); + bot->Notice(theClient, + bot->getResponse(theUser, + language::certonly_off, + string("Your CERTONLY setting is now OFF."))); + return true; + } + + bot->Notice(theClient, + bot->getResponse(theUser, + language::set_cmd_syntax_on_off, + string("value of %s must be ON or OFF")).c_str(), + option.c_str()); + return true; + } +#endif #ifdef USE_NOTES if (option == "NONOTES") { diff --git a/mod.cservice/constants.h b/mod.cservice/constants.h index d63e2da3..623fc9b1 100644 --- a/mod.cservice/constants.h +++ b/mod.cservice/constants.h @@ -38,7 +38,7 @@ namespace sql * articles of data. */ const std::string channel_fields = "id,name,flags,mass_deop_pro,flood_pro,url,channels.description,comment,keywords,registered_ts,channel_ts,channel_mode,userflags,channels.last_updated,limit_offset,limit_period,limit_grace,limit_max,max_bans,no_take,welcome,limit_joinmax,limit_joinsecs,limit_joinperiod,limit_joinmode"; - const std::string user_fields = "users.id,users.user_name,users.password,users.url,users.language_id,users.flags,users.last_updated_by,users.last_updated,users.signup_ts,users.email,users.maxlogins,users.verificationdata,users.totp_key"; + const std::string user_fields = "users.id,users.user_name,users.password,users.url,users.language_id,users.flags,users.last_updated_by,users.last_updated,users.signup_ts,users.email,users.maxlogins,users.verificationdata,users.totp_key,users.scram_record"; const std::string level_fields = "channel_id,user_id,access,flags,suspend_expires,suspend_level,suspend_by,added,added_by,last_Modif,last_Modif_By,last_Updated,suspend_reason"; const std::string ban_fields = "id,channel_id,banmask,set_by,set_ts,level,expires,reason,last_updated"; } diff --git a/mod.cservice/cservice.cc b/mod.cservice/cservice.cc index 14bb738d..cf35fd55 100644 --- a/mod.cservice/cservice.cc +++ b/mod.cservice/cservice.cc @@ -179,7 +179,7 @@ MyUplink->RegisterEvent( EVT_XQUERY, this ); MyUplink->RegisterEvent( EVT_XREPLY, this ); MyUplink->RegisterEvent( EVT_GLINE , this ); MyUplink->RegisterEvent( EVT_REMGLINE , this ); - +MyUplink->RegisterEvent( EVT_NETBREAK, this ); xClient::OnAttach() ; } @@ -218,7 +218,9 @@ RegisterCommand(new SHOWIGNORECommand(this, "SHOWIGNORE", "", 3)); RegisterCommand(new SUPPORTCommand(this, "SUPPORT", "#channel ", 15)); RegisterCommand(new NOTECommand(this, "NOTE", "send , read all, erase ", 10)); RegisterCommand(new NOTECommand(this, "NOTES", "send , read all, erase ", 10)); - +#ifdef NEW_IRCU_FEATURES +RegisterCommand(new CERTCommand(this, "CERT", " [fingerprint] [note]", 10)); +#endif RegisterCommand(new OPCommand(this, "OP", "<#channel> [nick] [nick] ..", 3)); RegisterCommand(new DEOPCommand(this, "DEOP", "<#channel> [nick] [nick] ..", 3)); RegisterCommand(new VOICECommand(this, "VOICE", "<#channel> [nick] [nick] ..", 3)); @@ -404,6 +406,9 @@ preloadLevelsCache(); /* Preload any user accounts we want to */ preloadUserCache(); +/* Preload fingerprints */ +preloadFingerprintCache(); + /* Load the glines from db */ loadGlines(); @@ -434,6 +439,8 @@ for( commandMapType::iterator ptr = commandMap.begin() ; } commandMap.clear() ; +saslRequests.clear() ; +fingerprintMap.clear() ; } void cservice::BurstChannels() @@ -516,7 +523,35 @@ void cservice::BurstChannels() void cservice::OnConnect() { -// TODO: I changed this from return 0 +#ifdef NEW_IRCU_FEATURES +auto saslServer = Network->findNetConf( "sasl.server" ) ; +if( !saslServer || saslServer->first != MyUplink->getName() ) + { + MyUplink->Write( "%s CF %d sasl.server :%s", + getCharYY().c_str(), + time(nullptr), + MyUplink->getName().c_str() ) ; + } + +auto saslMechanisms = Network->findNetConf( "sasl.mechanisms" ) ; +if( !saslMechanisms || saslMechanisms->first != saslMechsAdvertiseList() ) + { + MyUplink->Write( "%s CF %d sasl.mechanisms :%s", + getCharYY().c_str(), + time(nullptr), + saslMechsAdvertiseList().c_str() ) ; + } + +auto netSaslTimeout = Network->findNetConf( "sasl.timeout" ) ; +if( !netSaslTimeout || std::stoul( netSaslTimeout->first ) != saslTimeout ) + { + MyUplink->Write( "%s CF %d sasl.timeout :%d", + getCharYY().c_str(), + time(nullptr), + saslTimeout ) ; + } +#endif // NEW_IRCU_FEATURES + xClient::OnConnect() ; } @@ -1931,6 +1966,30 @@ bool cservice::hasIPR( sqlUser* theUser ) return true; } +unsigned int cservice::hasFP( sqlUser* theUser ) +{ +stringstream theQuery ; +theQuery << "SELECT COUNT(*) FROM " + << "users_fingerprints WHERE user_id = " + << theUser->getID() + << endl ; +#ifdef LOG_SQL +elog << "cservice::hasFP::sqlQuery> " + << theQuery.str() + << endl ; +#endif + +if( !SQLDb->Exec(theQuery, true ) ) + { + elog << "cservice::hasFP> SQL Error: " + << SQLDb->ErrorMessage() + << endl; + return 0 ; + } + +return SQLDb->Tuples() ; +} + /** * Check a user against IP restrictions */ @@ -3000,6 +3059,7 @@ void cservice::processDBUpdates() updateUsers(); updateLevels(); updateBans(); + updateFingerprints(); LOG( INFO, "[DB-UPDATE]: Complete."); } @@ -3310,6 +3370,39 @@ void cservice::updateUsers() lastUserRefresh = atoi(SQLDb->GetValue(0,"db_unixtime").c_str()); } +/* + * Check the fingerpritns table to see if there have been any updates since we last looked. + */ +void cservice::updateFingerprints() +{ +const std::string theQuery = "SELECT fingerprint,user_id FROM users_fingerprints" ; + +#ifdef LOG_SQL +elog << "*** [CMaster::updateFingerprints]: sqlQuery: " + << theQuery + << endl ; +#endif + +if( !SQLDb->Exec(theQuery, true ) ) + { + elog << "*** [CMaster::updateFingerprints]: SQL error: " + << SQLDb->ErrorMessage() + << endl ; + return; + } + +if( SQLDb->Tuples() <= 0 ) + { + return ; + } + +fingerprintMap.clear() ; +for( unsigned int i = 0 ; i < SQLDb->Tuples() ; i++ ) + fingerprintMap.emplace( SQLDb->GetValue( i, 0 ), std::stoul( SQLDb->GetValue( i, 1 ) ) ) ; + +LOG(INFO, "[DB-UPDATE]: Refreshed fingerprint(s)." ) ; +} + void cservice::updateBans() { /* Todo */ @@ -4911,12 +5004,25 @@ void cservice::OnEvent( const eventType& theEvent, { switch( theEvent ) { + case EVT_NETBREAK: + { + iServer* theServer = static_cast< iServer* >( data1 ) ; + saslRequests.erase( + std::remove_if( + saslRequests.begin(), + saslRequests.end(), + [&]( const SaslRequest& req ) { return req.theServer == theServer ; } + ), + saslRequests.end() + ) ; + break ; + } case EVT_XQUERY: { iServer* theServer = static_cast< iServer* >( data1 ); const char* Routing = reinterpret_cast< char* >( data2 ); const char* Message = reinterpret_cast< char* >( data3 ); - //elog << "CSERVICE.CC XQUERY: " << theServer->getName() << " " << Routing << " " << Message << endl; + // elog << "CSERVICE.CC XQUERY: " << theServer->getName() << " " << Routing << " " << Message << endl; //As it is possible to run multiple GNUWorld clients on one server, first parameter should be a nickname. //If it ain't us, ignore the message, the message is probably meant for another client here. StringTokenizer st( Message ) ; @@ -4935,6 +5041,10 @@ switch( theEvent ) { doXQIsCheck(theServer, Routing, Command, Message); } + if (Command == "SASL") + { + doXQSASL(theServer, Routing, Message); + } break; } case EVT_XREPLY: @@ -7599,6 +7709,29 @@ void cservice::preloadUserCache() << endl; } +void cservice::preloadFingerprintCache() +{ + stringstream theQuery; + theQuery << "SELECT fingerprint,user_id FROM users_fingerprints" + << endl; + + elog << "*** [CMaster::preloadFingerprintCache]: Loading TLS fingerprints : " + << endl; + + if( SQLDb->Exec(theQuery, true ) ) + { + for (unsigned int i = 0 ; i < SQLDb->Tuples(); i++) + { + fingerprintMap.emplace(SQLDb->GetValue(i,0), std::stoul(SQLDb->GetValue(i,1))); + } + } + + elog << "*** [CMaster::preloadFingerprintCache]: Done. Loaded " + << SQLDb->Tuples() + << " fingerprints." + << endl; +} + void cservice::incStat(const string& name) { statsMapType::iterator ptr = statsMap.find( name ); @@ -7881,6 +8014,26 @@ void cservice::doCoderStats(iClient* theClient) } userDBTOTPIPRTotal = atoi(SQLDb->GetValue(0,0)); + int userDBFPTotal = 0; + theQuery.str(""); + theQuery << "SELECT COUNT(*) FROM users,users_fingerprints WHERE " + << "users.id = users_fingerprints.user_id" + << endl; +#ifdef LOG_SQL + elog << "cservice::doCoderStats::sqlQuery> " + << theQuery.str().c_str() + << endl; +#endif + + if( !SQLDb->Exec(theQuery, true ) ) + { + elog << "cservice::doCoderStats> SQL Error: " + << SQLDb->ErrorMessage() + << endl; + return; + } + userDBFPTotal = atoi(SQLDb->GetValue(0,0)); + float userTotal = userCacheHits + userHits; float userEf = userCacheHits ? ((float)userCacheHits / userTotal * 100) : 0; @@ -7953,6 +8106,7 @@ void cservice::doCoderStats(iClient* theClient) Notice(theClient, "--- Total users in DB with IPR: %i (in cache: %i (%.2f%% of total))", userDBIPRTotal, iprCount, cacheIPRTotal); float cacheIPRTOTPTotal = ((float)ipr_totp_Count / (float)sqlUserCache.size()) * 100; Notice(theClient, "--- Total users in DB with TOTP&IPR: %i (in cache: %i (%.2f%% of total))", userDBTOTPIPRTotal, ipr_totp_Count, cacheIPRTOTPTotal); + Notice(theClient, "--- Total users in DB with TLS: %i (fingerprints in cache %i)", userDBFPTotal, fingerprintMap.size()); float authTotal = ((float)authCount / (float)Network->clientList_size()) * 100; Notice(theClient, "--- Total Auth'd : %i (%.2f%% of total)", @@ -8216,143 +8370,915 @@ else } } -int cservice::authenticateUser(const string& username, const string& password, const string& ip, const string& ident,unsigned int& ipr_ts,sqlUser** suser) +cservice::AuthResult cservice::authenticateUser( AuthStruct& auth ) { +unsigned int ipr_ts ; +bool certAuth = false ; // Set to true if the client has a certificate matching the username + +/* 1: Check loginDelay. */ unsigned int useLoginDelay = getConfigVar("USE_LOGIN_DELAY")->asInt(); unsigned int loginTime = getUplink()->getStartTime() + loginDelay; if ( (useLoginDelay == 1) && (loginTime >= (unsigned int)currentTime()) ) - { - return TOO_EARLY_TOLOGIN; - } -/* - * Find the user record, confirm authorisation and attach the record - * to this client. - */ -if(username[0] == '#') - { - return AUTH_FAILED; - } + { + return TOO_EARLY_TOLOGIN ; + } -// TODO: Force a refresh of the user's info from the db -*suser = getUserRecord(username); +/* 2: Check whether this iClient has exceeded the maximum number of failed login attempts. */ +if( auth.theClient ) + { + unsigned int maxFailedLogins = getConfigVar("MAX_FAILED_LOGINS")->asInt() ; + unsigned int failedLogins = getFailedLogins( auth.theClient ) ; + if( ( maxFailedLogins > 0 ) && ( failedLogins >= maxFailedLogins ) ) + return AUTH_FAIL_EXCEEDED ; + } -sqlUser* theUser = *suser; +/* 3: Check that the username exists. */ +// TODO: Force a refresh of the user's info from the db +sqlUser* theUser = getUserRecord( auth.username ) ; if( !theUser ) - { - return AUTH_UNKNOWN_USER; - } + { + return AUTH_UNKNOWN_USER ; + } -if (theUser->getFlag(sqlUser::F_GLOBAL_SUSPEND)) - { - return AUTH_SUSPENDED_USER; - } -StringTokenizer st (password); -int pass_end = st.size(); +auth.theUser = theUser ; + +/* 4: Check whether the username is glbobally suspended. */ +if( theUser->getFlag( sqlUser::F_GLOBAL_SUSPEND ) ) + { + return AUTH_SUSPENDED_USER ; + } + +/** + * 5: If the client has a fingerprint, we check whether it matches the username. + * If it does, we take that into account when parsing the password string to look for + * the TOTP token (if any). If there is no match, we treat the password string as a + * regular login. + * + * If the client is authenticating with EXTERNAL, the auth fails if the fingerprint does not match the username. + * + */ +if( !auth.fingerprint.empty() ) + { + auto it = fingerprintMap.find( auth.fingerprint ) ; + if( it != fingerprintMap.end() && it->second == theUser->getID() ) + certAuth = true ; + } + +if( auth.sasl == SaslMechanism::EXTERNAL && !certAuth ) + { + return AUTH_INVALID_FINGERPRINT ; + } + +/* 6: If CERTONLY is set for this user, the auth fails if we did not get a fingerprint match. */ +if( theUser->getFlag( sqlUser::F_CERTONLY ) && !certAuth ) + { + return AUTH_CERTONLY ; + } + +/** + * 7: Check whether a TOTP token has been provided. + * TOTP is not required for fingerprint authentication if F_CERT_DISABLE_TOTP is set. + */ +StringTokenizer st( auth.password ) ; +StringTokenizer::size_type pass_end = st.size() ; #ifdef TOTP_AUTH_ENABLED -bool totp_enabled = false; -if(totpAuthEnabled && theUser->getFlag(sqlUser::F_TOTP_ENABLED)) { - if(st.size() == 1 ) { - return AUTH_NO_TOKEN; - } - pass_end = st.size()-1; - totp_enabled = true; -} +bool totp_enabled = false ; + +if( totpAuthEnabled && theUser->getFlag( sqlUser::F_TOTP_ENABLED ) ) + { + /* If the user has a certificate matching the username or we are using SCRAM, the password is the TOTP token. */ + if( ( certAuth && !theUser->getFlag( sqlUser::F_CERT_DISABLE_TOTP ) ) + || auth.sasl == SaslMechanism::SCRAM_SHA_256 ) + { + if( st.size() < 1 ) + return AUTH_NO_TOKEN ; + + pass_end = st.size() - 1 ; + totp_enabled = true ; + } + /* If the user does not have a certificate matching the username and we are not using SCRAM, the second part of the password is the TOTP token. */ + else if( !certAuth && auth.sasl != SaslMechanism::SCRAM_SHA_256 ) + { + if( st.size() < 2 ) + return AUTH_NO_TOKEN ; + + pass_end = st.size() - 1 ; + totp_enabled = true ; + } + } #endif -/* - * Check if this is a privileged user, if so check against IP restrictions +/** + * 8: IPR + * Check if this is a privileged user, if so check against IP restrictions. */ -if (needIPRcheck(theUser)) -{ - /* ok, they have "*" access (excluding alumni's) */ - if (!checkIPR(ip, theUser, ipr_ts)) +if( needIPRcheck( theUser ) ) { - return AUTH_FAILED_IPR; + /* ok, they have "*" access (excluding alumni's) */ + if( !checkIPR( auth.ip, theUser, ipr_ts ) ) + return AUTH_FAILED_IPR ; } -} /* - * Check password, if its wrong, bye bye. + * 9: Check password. + * Password will not be checked for EXTERNAL or SCRAM or when a matching certificate is provided. */ -if (!isPasswordRight(theUser, st.assemble(0,pass_end))) - { - return AUTH_INVALID_PASS; - } +if( !certAuth && auth.sasl != SaslMechanism::SCRAM_SHA_256 + && auth.sasl != SaslMechanism::EXTERNAL + && !isPasswordRight( theUser, st.assemble( 0, pass_end ) ) ) + { + return AUTH_INVALID_PASS ; + } + +/* + * Compute SCRAM RECORD if it does not exist. + */ +#ifdef HAVE_LIBSSL +if( !certAuth && auth.sasl != SaslMechanism::SCRAM_SHA_256 + && auth.sasl != SaslMechanism::EXTERNAL + && theUser->getScramRecord().empty() ) + { + std::string err ; + auto recOpt = make_scram_sha256_record( st.assemble( 0, pass_end ), &err ) ; + + if( !recOpt ) + { + LOG( ERROR, "[SCRAM] Record generation error: {}", err ) ; + } + else + { + std::string scram_record = *recOpt ; + theUser->setScramRecord( scram_record ) ; + if( auth.theClient ) + theUser->commit( auth.theClient ) ; + else + theUser->commit( auth.ident + "@" + auth.ip ) ; + } + } +#endif // HAVE_LIBSSL + +/* 10: Check TOTP token. */ #ifdef TOTP_AUTH_ENABLED -if(totp_enabled) { - char* key; - size_t len; - int res = oath_base32_decode(theUser->getTotpKey().c_str(),theUser->getTotpKey().size(),&key,&len); - if(res != OATH_OK) { - return AUTH_ERROR; - } - res=oath_totp_validate(key,len,time(NULL),30,0,1,st[st.size()-1].c_str()); - free(key); - if(res < 0 ) { - return AUTH_INVALID_TOKEN; +if( totp_enabled ) + { + char* key ; + size_t len ; + int res = oath_base32_decode( theUser->getTotpKey().c_str(), theUser->getTotpKey().size(), &key, &len ) ; + if( res != OATH_OK ) + return AUTH_ERROR ; + + res = oath_totp_validate( key, len, time(NULL), 30, 0, 1, st[ pass_end ].c_str() ) ; + free( key ) ; + if( res < 0 ) + return AUTH_INVALID_TOKEN; + } +#endif + +/* 12: Don't exceed MAXLOGINS. */ +bool iploginallow = false ; +string clip = fixToCIDR64( auth.ip.c_str() ) ; +if( theUser->networkClientList.size() + 1 > theUser->getMaxLogins() ) + { + /* They have exceeded their maxlogins setting, but check if they + * are allowed to login from the same IP - only applies if their + * maxlogins is set to ONE. + */ + uint32_t iplogins = getConfigVar("LOGINS_FROM_SAME_IP")->asInt() ; + uint32_t iploginident = getConfigVar("LOGINS_FROM_SAME_IP_AND_IDENT")->asInt() ; + if( ( theUser->getMaxLogins() == 1 ) && ( iplogins > 1 ) ) + { + /* ok, we're using the multi-logins feature (0=disabled) */ + if( theUser->networkClientList.size() + 1 <= iplogins ) + { + /* Check their IP from previous session against + * current IP. If it matches, allow the login. + * As this only applies if their maxlogin is 1, we + * know there is only 1 entry in their clientlist. + */ + if( clip == ( xIP( theUser->networkClientList.front()->getIP()).GetNumericIP( true ) ) ) + { + if( iploginident == 1 ) + { + /* need to check ident here */ + string oldident = theUser->networkClientList.front()->getUserName() ; + if( ( oldident[0] =='~' ) || ( oldident == auth.ident ) ) + { + /* idents match (or they are unidented) - allow this login */ + iploginallow = true ; + } + } + else + { + /* don't need to check ident, this login is allowed */ + iploginallow = true ; + } + } + } } + + if( !iploginallow ) + return AUTH_ML_EXCEEDED; + } + +/* Success. */ +if( auth.theClient ) + setIPRts( auth.theClient, ipr_ts ) ; + +return AUTH_SUCCEEDED ; } -#endif -/* - * Don't exceed MAXLOGINS. +/* This function is called after authenticateUser() to process the authentication. */ +bool cservice::processAuthentication( AuthStruct auth, std::string* Message ) +{ +/* Get background variables. */ +unsigned int loginTime = getUplink()->getStartTime() + loginDelay ; +unsigned int max_failed_logins = getConfigVar("FAILED_LOGINS")->asInt() ; +unsigned int failed_login_rate = getConfigVar("FAILED_LOGINS_RATE")->asInt() ; + +/* Fetch client info. */ +string clientMask ; +if( auth.theClient ) + clientMask = auth.theClient->getRealNickUserHost() ; +else + clientMask = auth.ident + "@" + auth.ip ; + +string authResponse ; +bool setFailedLogin = false ; + +switch( auth.result ) + { + case cservice::TOO_EARLY_TOLOGIN: + authResponse = TokenStringsParams( "AUTHENTICATION FAILED as %s (Unable to login during reconnection, please try again in %i seconds)", + auth.username.c_str(), ( loginTime - currentTime() ) ) ; + break ; + case cservice::AUTH_FAILED: + authResponse = TokenStringsParams( getResponse( NULL, language::auth_failed, + string("AUTHENTICATION FAILED as %s") ).c_str(), + auth.username.c_str() ) ; + setFailedLogin = true ; + break ; + case cservice::AUTH_UNKNOWN_USER: + authResponse = TokenStringsParams( getResponse( NULL, language::not_registered, + string("AUTHENTICATION FAILED as %s") ).c_str(), + auth.username.c_str() ) ; + setFailedLogin = true ; + break ; + case cservice::AUTH_SUSPENDED_USER: + authResponse = TokenStringsParams( "AUTHENTICATION FAILED as %s (Suspended)", + auth.username.c_str() ) ; + setFailedLogin = true ; + break ; + case cservice::AUTH_NO_TOKEN: + authResponse = TokenStringsParams( "AUTHENTICATION FAILED as %s (Missing TOTP token)", + auth.username.c_str() ) ; + setFailedLogin = true ; + break ; + case cservice::AUTH_INVALID_PASS: + if( failed_login_rate == 0 ) + failed_login_rate = 900 ; + authResponse = TokenStringsParams( getResponse( NULL, language::auth_failed, + string("AUTHENTICATION FAILED as %s") ).c_str(), + auth.username.c_str() ) ; + + if( ( max_failed_logins > 0 ) && ( auth.theUser->getFailedLogins() > max_failed_logins ) && + ( auth.theUser->getLastFailedLoginTS() < ( time(NULL) - failed_login_rate ) ) ) + { + /* we have exceeded our maximum - alert relay channel */ + /* work out a checksum for the password. Yes, I could have + * just used a checksum of the original password, but this + * means it's harder to 'fool' the check digit with a real + * password - create MD5 from original salt stored */ + unsigned char checksum ; + md5 hash ; + md5Digest digest ; + + if( auth.theUser->getPassword().size() < 9 ) + checksum = 0 ; + else + { + string salt = auth.theUser->getPassword().substr( 0, 8 ) ; + string guess = salt + auth.password ; + + hash.update( (const unsigned char *)guess.c_str(), guess.size() ) ; + hash.report( digest ) ; + + checksum = 0 ; + for( size_t i = 0; i < MD5_DIGEST_LENGTH; i++ ) + { + /* add ascii value to check digit */ + checksum += digest[ i ] ; + } + } + + auth.theUser->setLastFailedLoginTS( time(NULL) ) ; + logPrivAdminMessage("%d failed logins for %s (last attempt by %s%s, checksum %d).", + auth.theUser->getFailedLogins(), + auth.theUser->getUserName().c_str(), + clientMask.c_str(), + auth.type == AuthType::XQUERY ? " (LoC)" : "", + checksum ) ; + } + setFailedLogin = true ; + break ; + case cservice::AUTH_INVALID_FINGERPRINT: + authResponse = TokenStringsParams( "AUTHENTICATION FAILED as %s (Invalid fingerprint)", + auth.username.c_str() ) ; + setFailedLogin = true ; + break ; + case cservice::AUTH_ERROR: + authResponse = TokenStringsParams( "AUTHENTICATION FAILED as %s due to an error. Please contact a CService representative", + auth.username.c_str() ) ; + break ; + case cservice::AUTH_INVALID_TOKEN: + authResponse = TokenStringsParams( getResponse( NULL, language::auth_failed_token, + string("AUTHENTICATION FAILED as %s") ).c_str(), + auth.username.c_str() ) ; + + setFailedLogin = true ; + break ; + case cservice::AUTH_FAILED_IPR: + authResponse = TokenStringsParams("AUTHENTICATION FAILED as %s (IPR)", + auth.username.c_str() ) ; + + /* notify the relay channel */ + logAdminMessage( "%s (%s) failed IPR check.", + clientMask.c_str(), + auth.username.c_str() ) ; + + if( ( max_failed_logins > 0 ) && ( auth.theUser->getFailedLogins() > max_failed_logins ) && + ( auth.theUser->getLastFailedLoginTS() < ( time(NULL) - failed_login_rate ) ) ) + { + /* we have exceeded our maximum - alert relay channel */ + auth.theUser->setLastFailedLoginTS( time(NULL) ) ; + logPrivAdminMessage( "%d failed logins for %s (last attempt by %s).", + auth.theUser->getFailedLogins(), + auth.theUser->getUserName().c_str(), + clientMask.c_str() ) ; + } + setFailedLogin = true ; + break ; + case cservice::AUTH_CERTONLY: + authResponse = TokenStringsParams( "AUTHENTICATION FAILED as %s (Password login disabled and fingerprint mismatch)", + auth.username.c_str() ) ; + setFailedLogin = true ; + break ; + case cservice::AUTH_ML_EXCEEDED: + authResponse = TokenStringsParams( "AUTHENTICATION FAILED as %s (Maximum concurrent logins exceeded)", + auth.theUser->getUserName().c_str() ) ; + + /* Do not list the sessions for XQUERY logins. */ + if( auth.theClient ) + { + string clientList ; + for( sqlUser::networkClientListType::iterator ptr = auth.theUser->networkClientList.begin() ; + ptr != auth.theUser->networkClientList.end() ; ) + { + clientList += (*ptr)->getNickUserHost() ; + ++ptr ; + if( ptr != auth.theUser->networkClientList.end() ) + clientList += ", " ; + } // for() + + Notice( auth.theClient, "Current Sessions: %s", clientList.c_str() ) ; + } + setFailedLogin = true ; + break ; + case cservice::AUTH_FAIL_EXCEEDED: + authResponse = TokenStringsParams( getResponse( NULL, language::max_failed_logins, + string("AUTHENTICATION FAILED as %s (Exceeded maximum login failures for this session)") ).c_str(), + auth.username.c_str() ) ; + setFailedLogin = true ; + break ; + case cservice::AUTH_SUCCEEDED: + break ; + default: + //Should never get here! + elog << "Response " << auth.result << " while authenticating!" << endl ; + authResponse = TokenStringsParams( "AUTHENTICATION FAILED as %s (due to an error)", + auth.username.c_str() ) ; + break ; + } + +if( setFailedLogin ) + { + if( auth.theClient ) + { + unsigned int failedLogins = getFailedLogins( auth.theClient ) ; + setFailedLogins( auth.theClient, failedLogins + 1 ) ; + } + + if( auth.theUser ) + auth.theUser->incFailedLogins() ; + } + +/* Send response only if it fails. If it succeeds, the message is sent from doCommonAuth() */ +if( auth.theClient ) + { + if( auth.result == AUTH_SUCCEEDED ) + { + doCommonAuth( auth.theClient, auth.theUser->getUserName() ) ; + return true ; + } + else + { + Notice( auth.theClient, authResponse ) ; + return false ; + } + } +/** + * If theClient is nullptr, it means that the authentication is done by SASL/XQUERY and auth will + * occurr when the client is introduced to the network. */ +else + { + *Message = authResponse ; + } -bool iploginallow = false; -//unsigned long clip = xIP(ip.c_str(),false).GetLongIP(); -//string clip = xIP(xIP(ip.c_str(),false).GetLongIP()).GetNumericIP(); -string clip = fixToCIDR64(ip.c_str()); -if(theUser->networkClientList.size() + 1 > theUser->getMaxLogins()) { - /* They have exceeded their maxlogins setting, but check if they - are allowed to login from the same IP - only applies if their - maxlogins is set to ONE */ - uint32_t iplogins = getConfigVar("LOGINS_FROM_SAME_IP")->asInt(); - uint32_t iploginident = getConfigVar("LOGINS_FROM_SAME_IP_AND_IDENT")->asInt(); - if ((theUser->getMaxLogins() == 1) && (iplogins > 1)) - { - /* ok, we're using the multi-logins feature (0=disabled) */ - if (theUser->networkClientList.size() + 1 <= iplogins) - { - /* Check their IP from previous session against - current IP. If it matches, allow the login. - As this only applies if their maxlogin is 1, we - know there is only 1 entry in their clientlist */ - if (clip == (xIP(theUser->networkClientList.front()->getIP()).GetNumericIP(true))) //->getIP() - { - if (iploginident==1) - { - /* need to check ident here */ - string oldident = theUser->networkClientList.front()->getUserName(); - if ((oldident[0]=='~') || (oldident==ident)) - { - /* idents match (or they are unidented) - allow this login */ - iploginallow = true; - } - } else { - /* don't need to check ident, this login is allowed */ - iploginallow = true; - } - } - } - } - if (!iploginallow) - { - return AUTH_ML_EXCEEDED; - } +return ( auth.result == AUTH_SUCCEEDED ) ; } -return AUTH_SUCCEEDED; + +bool cservice::parseSaslMechanism( const std::string& in, cservice::SaslMechanism& out ) +{ + std::string up = string_upper( in ) ; +#define X(NAME, NAME_STR) if( up == NAME_STR ) { out = cservice::SaslMechanism::NAME ; return true ; } + CSERVICE_SASL_MECH_LIST +#undef X + return false ; } -int cservice::authenticateUser(const string& username, const string& password, iClient* theClient,sqlUser** theUser) { - unsigned int ipr_ts; - const string ip = xIP(theClient->getIP()).GetNumericIP(); - int res = authenticateUser(username,password, ip, theClient->getUserName(),ipr_ts,theUser); - if(res == AUTH_SUCCEEDED) - { - setIPRts(theClient, ipr_ts); +std::string cservice::saslMechanismToString( cservice::SaslMechanism mech ) +{ +#define X(NAME, NAME_STR) if( mech == cservice::SaslMechanism::NAME ) return NAME_STR ; + CSERVICE_SASL_MECH_LIST +#undef X + return "" ; +} + +std::string cservice::saslMechsAdvertiseList() +{ +// std::string out = "MECHS " ; + string out ; + bool first = true ; +#define X(NAME, NAME_STR) \ + do { if( !first ) out += "," ; first = false ; out += string_lower( NAME_STR ) ; } while(0); + CSERVICE_SASL_MECH_LIST +#undef X + return out ; +} + +bool cservice::doXQSASL( iServer* theServer, const string& Routing, const string& Message ) +{ + elog << "cservice::doXQSASL: Routing: " << Routing << " Message: " << Message << "\n" ; + +#ifdef HAVE_LIBSSL + StringTokenizer st( Message ) ; + if( st.size() < 2 ) + { + elog << "Received empty SASL message... Ignoring." << endl; + return false ; + } + + // Delete timed out requests. + auto it = saslRequests.begin() ; + while( it != saslRequests.end() ) + { + if( currentTime() - it->last_ts > saslTimeout ) + it = saslRequests.erase(it) ; + else + ++it ; + } + + // Check if we have an existing entry with this routing and server + it = std::find_if( + saslRequests.begin(), + saslRequests.end(), + [&]( const SaslRequest& req ) + { return req.routing == Routing && req.theServer == theServer ; } + ) ; + + /* Found existing challenge. */ + if( it != saslRequests.end() ) + { + elog << "Found matching SASL request for Routing: " << Routing << "\n" ; + string authMessage = st[ 1 ] ; + + it->last_ts = currentTime() ; + + // If the message is 400 bytes long we add it to the struct and wait for the next message. + if( authMessage.size() == 400 ) + { + it->credentials += authMessage ; + return true ; + } + + if( authMessage != "+" ) + it->credentials += authMessage ; + + if( it->mechanism == SaslMechanism::PLAIN ) + { + auto bufferOpt = b64decode( it->credentials, nullptr, true ) ; + if( !bufferOpt ) + { + elog << "[PLAIN] Failed to decode credentials: " << it->credentials << endl ; + incStat("SASL." + saslMechanismToString( it->mechanism ) + ".ERROR" ) ; + doXResponse( theServer, Routing, "Invalid credentials", true ) ; + saslRequests.erase( it ) ; + return false ; + } + + string decodedString = std::string( reinterpret_cast< char* >( bufferOpt->data() ), bufferOpt->size() ) ; + size_t p1 = decodedString.find( '\0' ) ; + size_t p2 = decodedString.find( '\0', p1 + 1 ) ; + + if( p1 == std::string::npos || p2 == std::string::npos || p1 == 0 ) + { + elog << "[PLAIN] Invalid PLAIN format in decoded credentials: " << decodedString << endl ; + incStat("SASL." + saslMechanismToString( it->mechanism ) + ".ERROR" ) ; + doXResponse( theServer, Routing, "Invalid credentials", true ) ; + saslRequests.erase( it ) ; + return false ; + } + + it->username = decodedString.substr( p1 + 1, p2 - ( p1 + 1 ) ) ; + it->password = decodedString.substr( p2 + 1 ) ; + + if( it->username.empty() || it->password.empty() ) + { + elog << "[PLAIN] Empty username or password in credentials" << endl ; + incStat("SASL." + saslMechanismToString( it->mechanism ) + ".ERROR" ) ; + doXResponse( theServer, Routing, "Invalid credentials", true ) ; + saslRequests.erase( it ) ; + return false ; + } + } + else if( it->mechanism == SaslMechanism::EXTERNAL ) + { + // A client certificate has to be provided. + if( it->fingerprint.empty() ) + { + incStat("SASL." + saslMechanismToString( it->mechanism ) + ".FAILED" ) ; + doXResponse( theServer, Routing, "Client certificate required for SASL EXTERNAL authentication", true ) ; + saslRequests.erase( it ) ; + return false ; + } + + // We only support EXTERNAL if a username has been provided. + if( it->credentials.empty() ) + { + incStat("SASL." + saslMechanismToString( it->mechanism ) + ".FAILED" ) ; + doXResponse( theServer, Routing, "Username required for SASL EXTERNAL authentication", true ) ; + saslRequests.erase( it ) ; + return false ; + } + + auto bufferOpt = b64decode( it->credentials, nullptr, true ) ; + if( !bufferOpt ) + { + elog << "[EXTERNAL] Failed to decode username: " << it->credentials << endl ; + incStat("SASL." + saslMechanismToString( it->mechanism ) + ".ERROR" ) ; + doXResponse( theServer, Routing, "Invalid username", true ) ; + saslRequests.erase( it ) ; + return false ; + } + + string decodedString = std::string( reinterpret_cast< char* >( bufferOpt->data() ), bufferOpt->size() ) ; + StringTokenizer st2( decodedString ) ; + + // Validate that we have at least a username + if( st2.size() < 1 || st2[ 0 ].empty() ) + { + elog << "[EXTERNAL] Invalid username in decoded credentials" << endl ; + incStat("SASL." + saslMechanismToString( it->mechanism ) + ".ERROR" ) ; + doXResponse( theServer, Routing, "Invalid username", true ) ; + saslRequests.erase( it ) ; + return false ; + } + + it->username = st2[ 0 ] ; + if( st2.size() > 1 ) + it->password = st2[ 1 ] ; + } + else if( it->mechanism == SaslMechanism::SCRAM_SHA_256 ) + { + if( it->state == SaslState::INITIAL ) + { + auto bufferOpt = b64decode( it->credentials, nullptr, true ) ; + if( !bufferOpt ) + { + elog << "[SCRAM] Failed to decode client first message: " << it->credentials << endl ; + incStat("SASL." + saslMechanismToString( it->mechanism ) + ".ERROR" ) ; + doXResponse( theServer, Routing, "Invalid credentials", true ) ; + saslRequests.erase( it ) ; + return false ; + } + + string decodedString = std::string( reinterpret_cast< char* >( bufferOpt->data() ), bufferOpt->size() ) ; + if( decodedString.find("n,,") != 0 ) + { + elog << "[SCRAM] Invalid client first message: " << decodedString << endl ; + incStat("SASL." + saslMechanismToString( it->mechanism ) + ".ERROR" ) ; + doXResponse( theServer, Routing, "Invalid credentials", true ) ; + saslRequests.erase( it ) ; + return false ; + } + + it->client_first = decodedString.substr( 3 ) ; // remove 'n,,' + StringTokenizer st2( it->client_first, ',' ) ; + for( size_t i = 0 ; i < st2.size() ; ++i ) + { + if( st2[ i ].rfind( "n=", 0 ) == 0 ) + { + StringTokenizer st3( st2[ i ].substr( 2 ) ) ; + it->username = st3[ 0 ] ; + if( st3.size() > 1 ) + it->password = st3[ 1 ] ; + } + else if( st2[ i ].rfind( "r=", 0 ) == 0 ) + it->client_nonce = st2[ i ].substr( 2 ) ; + } + + if( it->username.empty() || it->client_nonce.empty() ) + { + elog << "[SCRAM] Missing username or client nonce in authentication: " << decodedString << endl ; + incStat("SASL." + saslMechanismToString( it->mechanism ) + ".ERROR" ) ; + doXResponse( theServer, Routing, "Invalid credentials", true ) ; + saslRequests.erase( it ) ; + return false ; + } + + sqlUser* theUser = getUserRecord( it->username ) ; + if( !theUser || theUser->getScramRecord().empty() ) + { + incStat("SASL." + saslMechanismToString( it->mechanism ) + ".FAILED" ) ; + doXResponse( theServer, Routing, "AUTHENTICATION FAILED as " + it->username, true ) ; + saslRequests.erase( it ) ; + return false ; + } + + it->username = theUser->getUserName() ; + + auto nonceOpt = generateRandomNonce() ; + if( !nonceOpt ) + { + elog << "[SCRAM] Failed to generate server nonce." << endl ; + incStat("SASL." + saslMechanismToString( it->mechanism ) + ".ERROR" ) ; + doXResponse( theServer, Routing, "Internal error", true ) ; + saslRequests.erase( it ) ; + return false ; + } + it->server_nonce = *nonceOpt ; + std::string combinedNonce = it->client_nonce + it->server_nonce ; + + std::string err ; + auto parse_opt = parse_scram_sha256_record( theUser->getScramRecord(), &err ) ; + if( !parse_opt ) + { + incStat("SASL." + saslMechanismToString( it->mechanism ) + ".ERROR" ) ; + LOG( ERROR, "[SCRAM] Record parse error: {}", err ) ; + doXResponse( theServer, Routing, "Internal error", true ) ; + return false ; + } + it->scram = *parse_opt ; + + /*elog << "Iterations: " << it->scram.iterations << endl; + elog << "Salt (base64): " << b64encode(it->scram.salt.data(), it->scram.salt.size()) << endl; + elog << "StoredKey (base64): " << b64encode(it->scram.storedKey.data(), it->scram.storedKey.size()) << endl; + elog << "ServerKey (base64): " << b64encode(it->scram.serverKey.data(), it->scram.serverKey.size()) << endl; + elog << "StoredKey (hex): "; + for (auto c : it->scram.storedKey) elog << std::hex << (int)c << " "; + elog << std::dec << "\n"; + elog << "ServerKey (hex): "; + for (auto c : it->scram.serverKey) elog << std::hex << (int)c << " "; + elog << std::dec << "\n";*/ + + it->server_first = "r=" + combinedNonce + ",s=" + b64encode( it->scram.salt.data(), it->scram.salt.size() ) + ",i=" + std::to_string( it->scram.iterations ) ; + std::string serverFirst_b64 = b64encode( reinterpret_cast< const unsigned char* >( it->server_first.data() ), it->server_first.size() ) ; + MyUplink->XReply( theServer, Routing, "SASL " + serverFirst_b64 ) ; + it->state = SaslState::SERVER_FIRST ; + it->credentials.clear() ; + return true ; + } + else if( it->state == SaslState::SERVER_FIRST ) + { + auto bufferOpt = b64decode( it->credentials, nullptr, true ) ; + if( !bufferOpt ) + { + elog << "[SCRAM] Failed to decode client final message: " << it->credentials << endl ; + incStat("SASL." + saslMechanismToString( it->mechanism ) + ".ERROR" ) ; + doXResponse( theServer, Routing, "Invalid credentials", true ) ; + saslRequests.erase( it ) ; + return false ; + } + + string decodedString = std::string( reinterpret_cast< char* >( bufferOpt->data() ), bufferOpt->size() ) ; + if( decodedString.find("n,,") == 0 ) + decodedString = decodedString.substr( 3 ) ; + + size_t p_pos = decodedString.rfind( ",p=" ) ; + if( p_pos == std::string::npos ) + { + elog << "[SCRAM] Missing ,p= in client final message: " << decodedString << endl ; + incStat("SASL." + saslMechanismToString( it->mechanism ) + ".ERROR" ) ; + doXResponse( theServer, Routing, "Invalid credentials", true ) ; + saslRequests.erase( it ) ; + return false ; + } + it->client_final = decodedString.substr(0, p_pos) ; // up to but not including ",p=" + + std::string cbind_input, nonce, proof ; + StringTokenizer st( decodedString, ',' ) ; + for( size_t i = 0 ; i < st.size() ; ++i ) + { + if( st[i].rfind("c=", 0 ) == 0 ) + cbind_input = st[i].substr( 2 ) ; + else if( st[i].rfind("r=", 0 ) == 0 ) + nonce = st[i].substr( 2 ) ; + else if( st[i].rfind("p=", 0 ) == 0 ) + proof = st[i].substr( 2 ) ; + } + + if( cbind_input.empty() || nonce.empty() || proof.empty() ) + { + elog << "[SCRAM] Missing c=, r= or p= in client final message: " << decodedString << endl ; + incStat("SASL." + saslMechanismToString( it->mechanism ) + ".ERROR" ) ; + doXResponse( theServer, Routing, "Invalid credentials", true ) ; + saslRequests.erase( it ) ; + return false ; + } + + if( nonce != it->client_nonce + it->server_nonce ) + { + elog << "[SCRAM] nonce match failed: " << decodedString << endl ; + incStat("SASL." + saslMechanismToString( it->mechanism ) + ".FAILED" ) ; + doXResponse( theServer, Routing, "AUTHENTICATION FAILED as " + it->username, true ) ; + saslRequests.erase( it ) ; + return false ; + } + + std::string auth_message = it->client_first + "," + it->server_first + "," + it->client_final ; + bool valid = validate_scram_sha256_proof( + it->scram.storedKey, + auth_message, + proof + ) ; + + if( !valid ) + { + elog << "[SCRAM] Proof validation failed for user " << it->username << endl ; + incStat("SASL." + saslMechanismToString( it->mechanism ) + ".FAILED" ) ; + doXResponse( theServer, Routing, "AUTHENTICATION FAILED as " + it->username, true ) ; + saslRequests.erase( it ) ; + return false ; + } + + std::string server_signature = compute_server_signature( it->scram.serverKey, auth_message ) ; + std::string server_final = "v=" + server_signature ; + std::string server_final_b64 = b64encode( reinterpret_cast< const unsigned char* >( server_final.data() ), server_final.size() ) ; + MyUplink->XReply( theServer, Routing, "SASL " + server_final_b64 ) ; + it->state = SaslState::COMPLETE ; + return true ; // Waiting for the + to complete the authentication + } + else if( it->state == SaslState::COMPLETE ) + { + /* Pass through to authentication. */ + } + else + { + elog << "[SCRAM] Invalid state in authentication." << endl ; + incStat("SASL." + saslMechanismToString( it->mechanism ) + ".ERROR" ) ; + doXResponse( theServer, Routing, "An error occurred", true ) ; + saslRequests.erase( it ) ; + return false ; + } + } + + AuthStruct auth = { + AuthType::XQUERY, + AUTH_ERROR, // result (placeholder) + it->username, // username + it->password, // password/token + it->ident, // ident (empty for LoC) + it->ip, // ip + it->fingerprint, // tls fingerprint + nullptr, // sqlUser (placeholder) + it->theClient, // iClient (nullptr for LoC) + it->mechanism + } ; + + if( it->mechanism == SaslMechanism::SCRAM_SHA_256 ) + elog << "Authenticating with SCRAM" << endl; + else + elog << "Authenticating with username " << it->username << " and password " << mask(it->password) << endl ; + + AuthResult auth_res = authenticateUser( auth ) ; + auth.result = auth_res ; + + /* Process result. */ + if( auth_res == AUTH_SUCCEEDED ) + { + incStat("SASL." + saslMechanismToString( it->mechanism ) + ".SUCCESS" ) ; + if( !auth.theClient ) + doXResponse( theServer, Routing, auth.theUser->getUserName() + ":" + + std::to_string( auth.theUser->getID() ) + ":" + + std::to_string( makeAccountFlags( auth.theUser ) ) + + (auth.theUser->getFlag( sqlUser::F_AUTOHIDE ) ? " +x" : "") ) ; + else + { + doCommonAuth( auth.theClient, auth.theUser->getUserName() ) ; + doXResponse( theServer, Routing, string() ) ; + } + + elog << "cservice::doXQSASL: " + << "Succesful auth for " + << it->username + << endl ; + + saslRequests.erase( it ) ; + return true; + } + + /* The authentication failed. Process and send correct message. */ + string AuthResponse ; + processAuthentication( auth, &AuthResponse ) ; + + /* Send response. */ + doXResponse( theServer, Routing, AuthResponse, true ) ; + + incStat("SASL." + saslMechanismToString( it->mechanism ) + ".FAILED" ) ; + + saslRequests.erase( it ) ; + return false ; + } + // It is the initial message consisting of the mechanism. + else + { + // Did we receive a numeric? + iClient* tmpClient = Network->findClient( st[ 1 ] ) ; + string IP ; + string fingerprint ; + string authMessage ; + if( tmpClient ) + { + if( st.size() < 3 ) + { + elog << "Bogus SASL message with numeric" << endl ; + doXResponse( theServer, Routing, "An error has occurred", true ) ; + return false ; + } + + IP = xIP( tmpClient->getIP() ).GetNumericIP() ; + fingerprint = tmpClient->getTlsFingerprint().empty() ? "_" : tmpClient->getTlsFingerprint() ; + authMessage = string_upper( st[ 2 ] ) ; + } + else + { + if( st.size() < 4 ) + { + elog << "Bogus SASL message without numeric" << endl ; + doXResponse( theServer, Routing, "An error has occurred", true ) ; + return false ; + } + + IP = st[ 1 ] ; + fingerprint = st[ 2 ] ; + authMessage = string_upper( st[ 3 ] ) ; + } + + SaslMechanism mech ; + if( !parseSaslMechanism( authMessage, mech ) ) + { + LOG( ERROR, "Received invalid SASL mechanism: {}", authMessage ) ; + doXResponse( theServer, Routing, "An error has occurred", true ) ; + return false ; + } + + if( mech == SaslMechanism::EXTERNAL && fingerprint == "_" ) + { + incStat("SASL." + saslMechanismToString( mech ) + ".FAILED" ) ; + doXResponse( theServer, Routing, "No TLS fingerprint provided", true ) ; + return false ; + } + + // Valid mechanism - store in cache for further use. + elog << "Received valid SASL mechanism: " << authMessage << " from IP: " << IP << endl; + SaslRequest newRequest ; + newRequest.theClient = tmpClient ; + newRequest.routing = Routing ; + newRequest.theServer = theServer ; + newRequest.ip = IP ; + newRequest.added_ts = currentTime() ; + newRequest.last_ts = currentTime() ; + newRequest.fingerprint = fingerprint == "_" ? "" : fingerprint ; + newRequest.mechanism = mech ; + newRequest.ident = tmpClient ? tmpClient->getUserName() : "" ; + + saslRequests.push_back( newRequest ) ; + + MyUplink->XReply( theServer, Routing, "SASL +" ) ; } - return res; +#endif // HAVE_LIBSSL + return true; } bool cservice::doXQLogin(iServer* theServer, const string& Routing, const string& Message) @@ -8364,12 +9290,9 @@ bool cservice::doXQLogin(iServer* theServer, const string& Routing, const string StringTokenizer st( Message ); string username; string password; - string ip = string(); - string hostname = string(); - string ident = string(); - sqlUser* theUser; - unsigned int ipr_ts; - string AuthResponse = string(); + string ip; + string hostname; + string ident; if (st[0] == "LOGIN") { @@ -8402,155 +9325,47 @@ bool cservice::doXQLogin(iServer* theServer, const string& Routing, const string ident = st[3]; LOG( TRACE, "XQ-LOGIN2: LOGIN2 {} {} {} {} {}", ip, hostname, ident, username, mask(password) ) ; } - int auth_res = authenticateUser(username,password,ip,ident,ipr_ts,&theUser); - unsigned int loginTime = getUplink()->getStartTime() + loginDelay; - unsigned int max_failed_logins = getConfigVar("FAILED_LOGINS")->asInt(); - unsigned int failed_login_rate = getConfigVar("FAILED_LOGINS_RATE")->asInt(); - switch(auth_res) - { - case TOO_EARLY_TOLOGIN: - AuthResponse = TokenStringsParams("AUTHENTICATION FAILED as %s (Unable " - "to login during reconnection, please try again in " - "%i seconds)", - username.c_str(), (loginTime - currentTime())); - doXResponse(theServer, Routing, AuthResponse,true); - LOG( DEBUG, "Auth res = TOO_EARLY_TOLOGIN" ) ; - break; - case AUTH_FAILED: - AuthResponse = TokenStringsParams("AUTHENTICATION FAILED as %s (Erroneus username)", username.c_str()); - doXResponse(theServer, Routing, AuthResponse, true); - LOG( DEBUG, "Auth res = AUTH_FAILED" ) ; - break; - case AUTH_UNKNOWN_USER: - AuthResponse = TokenStringsParams("AUTHENTICATION FAILED as %s", username.c_str()); - doXResponse(theServer, Routing, AuthResponse, true); - LOG( DEBUG, "Auth res = AUTH_UNKNOWN_USER" ) ; - break; - case AUTH_SUSPENDED_USER: - AuthResponse = TokenStringsParams("AUTHENTICATION FAILED as %s (Suspended)", theUser->getUserName().c_str()); - doXResponse(theServer, Routing, AuthResponse, true); - LOG( DEBUG, "Auth res = AUTH_SUSPENDED_USER" ) ; - break; - case AUTH_NO_TOKEN: - theUser->incFailedLogins(); - AuthResponse = TokenStringsParams("AUTHENTICATION FAILED as %s (Missing TOTP token)", theUser->getUserName().c_str()); - doXResponse(theServer, Routing, AuthResponse, true); - LOG( DEBUG, "Auth res = AUTH_NO_TOKEN" ) ; - break; - case AUTH_INVALID_PASS: - if (failed_login_rate==0) - failed_login_rate = 900; - AuthResponse = TokenStringsParams(getResponse(theUser, - language::auth_failed, - string("AUTHENTICATION FAILED as %s")).c_str(), - theUser->getUserName().c_str()); - doXResponse(theServer, Routing, AuthResponse, true); // <- this will be removed! - LOG( DEBUG, "Auth res = AUTH_INVALID_PASS" ) ; - /* increment failed logins counter */ - theUser->incFailedLogins(); - if ((max_failed_logins > 0) && (theUser->getFailedLogins() > max_failed_logins) && - (theUser->getLastFailedLoginTS() < (time(NULL) - failed_login_rate))) - { - /* we have exceeded our maximum - alert relay channel */ - /* work out a checksum for the password. Yes, I could have - * just used a checksum of the original password, but this - * means it's harder to 'fool' the check digit with a real - * password - create MD5 from original salt stored */ - unsigned char checksum; - md5 hash; - md5Digest digest; - - if (theUser->getPassword().size() < 9) - { - checksum = 0; - } else { - string salt = theUser->getPassword().substr(0, 8); - string guess = salt + st.assemble(2); - - hash.update( (const unsigned char *)guess.c_str(), guess.size() ); - hash.report( digest ); - - checksum = 0; - for (size_t i = 0; i < MD5_DIGEST_LENGTH; i++) - { - /* add ascii value to check digit */ - checksum += digest[i]; - } - } - theUser->setLastFailedLoginTS(time(NULL)); - logPrivAdminMessage("%d failed logins for %s (last attempt by %s@%s (LoC), checksum %d).", - theUser->getFailedLogins(), - theUser->getUserName().c_str(), - ident.c_str(), - ip.c_str(), - checksum); - } - break; - case AUTH_ERROR: - AuthResponse = TokenStringsParams("AUTHENTICATION FAILED as %s due to an error, please contact CService represetitive", username.c_str()); - doXResponse(theServer, Routing, AuthResponse, true); - LOG( DEBUG, "Auth res = AUTH_ERROR" ) ; - break; - case AUTH_INVALID_TOKEN: - theUser->incFailedLogins(); - AuthResponse = TokenStringsParams(getResponse(theUser, - language::auth_failed_token, - string("AUTHENTICATION FAILED as %s (Invalid Token)")).c_str(), - theUser->getUserName().c_str()); - doXResponse(theServer, Routing, AuthResponse, true); - LOG( DEBUG, "Auth res = AUTH_INVALID_TOKEN" ) ; - break; - case AUTH_FAILED_IPR: - /* increment failed logins counter */ - theUser->incFailedLogins(); - AuthResponse = TokenStringsParams("AUTHENTICATION FAILED as %s (IPR)", theUser->getUserName().c_str()); - /* notify the relay channel */ - logAdminMessage("%s@%s (%s) failed IPR check.", - ident.c_str(), - ip.c_str(), - theUser->getUserName().c_str()); - if ((max_failed_logins > 0) && (theUser->getFailedLogins() > max_failed_logins) && - (theUser->getLastFailedLoginTS() < (time(NULL) - failed_login_rate))) - { - /* we have exceeded our maximum - alert relay channel */ - theUser->setLastFailedLoginTS(time(NULL)); - logPrivAdminMessage("%d failed logins for %s (last attempt by %s@%s).", - theUser->getFailedLogins(), - theUser->getUserName().c_str(), - ident.c_str(), ip.c_str()); - } - doXResponse(theServer, Routing, AuthResponse, true); - LOG( DEBUG, "Auth res = AUTH_FAILED_IPR" ) ; - break; - case AUTH_ML_EXCEEDED: - /* increment failed logins counter */ - theUser->incFailedLogins(); - AuthResponse = TokenStringsParams("AUTHENTICATION FAILED as %s (Maximum " - "concurrent logins exceeded).", - theUser->getUserName().c_str()); - doXResponse(theServer, Routing, AuthResponse, true); - LOG( DEBUG, "Auth res = AUTH_ML_EXCEEDED" ) ; - break; - case AUTH_SUCCEEDED: - doXResponse(theServer, Routing, theUser->getUserName() + ":" + std::to_string(theUser->getID()) + ":" + std::to_string(makeAccountFlags(theUser))); - LOG_MSG( DEBUG, "Succesful auth for {user_name}" ) - .with( "user", theUser ) - .logStructured() ; - incStat("CORE.LOC.SUCCESS"); - return true; - break; - default: - //Should never get here! - LOG( ERROR, "Response {} while authenticating!", auth_res ) ; - AuthResponse = TokenStringsParams("AUTHENTICATION FAILED as %s (due to an error)\n", username.c_str()); - doXResponse(theServer, Routing, AuthResponse, true); - break; + AuthStruct auth = { + AuthType::XQUERY, // auth type + AUTH_ERROR, // result (placeholder) + username, // username + password, // password/token + ident, // ident + ip, // ip + string(), // tls fingerprint + nullptr, // sqlUser (placeholder) + nullptr, // iClient (not in use for LoC) + SaslMechanism::NO_SASL + } ; + + AuthResult auth_res = authenticateUser( auth ) ; + auth.result = auth_res ; + + /* Process result. */ + if( auth_res == AUTH_SUCCEEDED ) + { + incStat( "LOC." + st[0] + ".SUCCESS" ) ; + doXResponse(theServer, Routing, auth.theUser->getUserName() + ":" + + std::to_string(auth.theUser->getID()) + ":" + + std::to_string(makeAccountFlags(auth.theUser)) + + (auth.theUser->getFlag( sqlUser::F_AUTOHIDE ) ? " +x" : "") ) ; + elog << "cservice::doXQLogin: " + << "Succesful auth for " + << username + << endl; + return true; } -LOG( DEBUG, "XQ-LOGIN: FAILED login for {}", username ) ; -incStat("CORE.LOC.FAILED"); -return true; + /* The authentication failed. Process and send correct message. */ + string AuthResponse; + processAuthentication(auth, &AuthResponse); + + /* Send response. */ + doXResponse(theServer, Routing, AuthResponse, true); + incStat( "LOC." + st[0] + ".FAILED" ) ; + + return true; } void cservice::doXQToAllServices(const string& Routing, const string& Message) @@ -9128,6 +9943,11 @@ bool cservice::doCommonAuth(iClient* theClient, string username) if (!LoC) this->MyUplink->UserLogin(theClient, theUser->getUserName(), theUser->getID(), makeAccountFlags(theUser), this); +#ifdef NEW_IRCU_FEATURES + /* Set remote +x if user has AUTOHIDE set */ + if (theUser->getFlag(sqlUser::F_AUTOHIDE) && !theClient->isModeX()) + MyUplink->Write("%s OM %s :+x", getCharYY().c_str(), theClient->getCharYYXXX().c_str()); +#endif /* * If the user account has been suspended, make sure they don't get * auto-opped. @@ -9141,7 +9961,7 @@ bool cservice::doCommonAuth(iClient* theClient, string username) return true; } - + /* * Check they aren't banned < 75 in any chan. */ @@ -9796,7 +10616,7 @@ const iClient::flagType newFlags = makeAccountFlags( theUser ) ; if( theClient->getAccountFlags() == newFlags ) return ; -#ifdef USE_AC_XFLAGS +#ifdef NEW_IRCU_FEATURES MyUplink->Write( "%s AC %s %s %u %u", getCharYY().c_str(), theClient->getCharYYXXX().c_str(), theClient->getAccount().c_str(), theClient->getAccountID(), newFlags ) ; diff --git a/mod.cservice/cservice.h b/mod.cservice/cservice.h index 5f2e508a..12c1c29a 100644 --- a/mod.cservice/cservice.h +++ b/mod.cservice/cservice.h @@ -41,6 +41,7 @@ #include "EConfig.h" #include "cservice_config.h" #include "cservice_confvars.h" +#include "cservice_crypt.h" #include "cserviceCommands.h" #include "sqlChannel.h" #include "sqlUser.h" @@ -53,7 +54,7 @@ #include "prometheus.h" #ifdef USE_THREAD -#include "threadworker.h" + #include "threadworker.h" #endif namespace gnuworld @@ -62,6 +63,11 @@ using std::string ; using std::vector ; using std::map ; +enum class AuthType { + LOGIN, + XQUERY +} ; + /* * Class for the configuration variables extracted from the database. * An attempted conversion to a number is stored in 'int_value' for @@ -90,6 +96,62 @@ class Command; class cservice : public xClient { +private: + /* + * Declare SASL mechanisms once using an X-macro list. Each entry: + * X(EnumName, CanonicalName) + * CanonicalName may be any consistent casing; helpers will convert as needed. + */ +#define CSERVICE_SASL_MECH_LIST \ + X( PLAIN, "PLAIN" ) \ + X( SCRAM_SHA_256, "SCRAM-SHA-256" ) \ + X( EXTERNAL, "EXTERNAL" ) + + enum class SaslMechanism { + NO_SASL, +#define X(NAME, NAME_STR) NAME, + CSERVICE_SASL_MECH_LIST +#undef X + } ; + + enum class SaslState { + INITIAL, // Waiting for the first client message + CLIENT_FIRST, // Received client-first-message (SCRAM step 1) + SERVER_FIRST, // Sent server-first-message, waiting for client-final-message (SCRAM step 2) + CLIENT_FINAL, // Received client-final-message (SCRAM step 3) + COMPLETE, // Authentication complete (success or failure) + FAILED // Authentication failed + } ; + + struct SaslRequest { + iServer* theServer ; + iClient* theClient = nullptr ; + time_t added_ts ; + time_t last_ts ; + string routing ; + string ip ; + string ident ; + string fingerprint ; + string username ; + string password ; + SaslMechanism mechanism ; + string credentials ; + string client_nonce ; + string server_nonce ; + string client_first ; + string server_first ; + string client_final ; + SaslState state = SaslState::INITIAL ; + #ifdef HAVE_LIBSSL + ScramParsed scram ; + #endif + } ; + + std::vector< SaslRequest > saslRequests ; + static bool parseSaslMechanism( const std::string&, SaslMechanism& ) ; + static std::string saslMechanismToString( cservice::SaslMechanism ) ; + static std::string saslMechsAdvertiseList() ; + protected: /* Configfile */ @@ -187,6 +249,9 @@ class cservice : public xClient // Accesslevel cache, key is pair(userid, chanid). typedef map < std::pair , sqlLevel* > sqlLevelHashType ; + // Fingerprints. Key is fingerprint, value is userID. + typedef map< string, unsigned int > fpMapType ; + // Cache of user records. sqlUserHashType sqlUserCache; @@ -199,6 +264,9 @@ class cservice : public xClient // Cache of Level records. sqlLevelHashType sqlLevelCache; + // Cache of TLS fingerprints. + fpMapType fingerprintMap; + /* Pushover object. */ std::shared_ptr< PushoverClient > pushover ; @@ -339,15 +407,19 @@ class cservice : public xClient /* XQ handlers. */ bool doXQLogin(iServer* , const string&, const string&); bool doXQIsCheck(iServer*, const string&, const string&, const string&); + bool doXQSASL(iServer* , const string&, const string&); /** * Array of sqlUser flags and the corresponding accountFlags. */ - static constexpr std::array< std::pair< sqlUser::flagType, iClient::flagType >, 4 > flagMap = { { + static constexpr std::array< std::pair< sqlUser::flagType, iClient::flagType >, 7 > flagMap = { { { sqlUser::F_TOTP_ENABLED, iClient::X_TOTP_ENABLED }, { sqlUser::F_TOTP_REQ_IPR, iClient::X_TOTP_REQ_IPR }, { sqlUser::F_GLOBAL_SUSPEND, iClient::X_GLOBAL_SUSPEND }, - { sqlUser::F_FRAUD, iClient::X_FRAUD } + { sqlUser::F_FRAUD, iClient::X_FRAUD }, + { sqlUser::F_CERTONLY, iClient::X_CERTONLY }, + { sqlUser::F_CERT_DISABLE_TOTP, iClient::X_CERT_DISABLE_TOTP }, + { sqlUser::F_WEB_DISABLE_TOTP, iClient::X_WEB_DISABLE_TOTP } } } ; /** @@ -369,7 +441,7 @@ class cservice : public xClient CONFIG_VAR_LIST #undef CONFIG_VAR - enum { + enum AuthResult { AUTH_SUCCEEDED, AUTH_FAILED, TOO_EARLY_TOLOGIN, @@ -377,10 +449,13 @@ class cservice : public xClient AUTH_SUSPENDED_USER, AUTH_NO_TOKEN, AUTH_INVALID_PASS, + AUTH_INVALID_FINGERPRINT, AUTH_ERROR, AUTH_INVALID_TOKEN, AUTH_FAILED_IPR, - AUTH_ML_EXCEEDED + AUTH_CERTONLY, + AUTH_ML_EXCEEDED, + AUTH_FAIL_EXCEEDED }; cservice(const string& args); @@ -480,6 +555,26 @@ class cservice : public xClient /* Returns what access a user has in the coder channel */ short getCoderAccessLevel( sqlUser* ); + /* Checks if a user has an existing TLS fingerprint for it's username + * Returns the COUNT(*) + */ + unsigned int hasFP( sqlUser* ); + + /* Returns true if the fingerprint exists and matches the user_id. */ + bool checkFP( const string& fingerprint, unsigned int userId ) + { + auto it = fingerprintMap.find( fingerprint ) ; + return ( it != fingerprintMap.end() && it->second == userId ) ; + } + + /* Adds a fingerprint to cache. */ + auto addFP( const string& fingerprint, unsigned int userId ) + { return fingerprintMap.emplace( fingerprint, userId ) ; } + + /* Removes a fingerprint from cache. */ + void removeFP( const string& fingerprint ) + { fingerprintMap.erase( fingerprint ) ; } + /* Fetch a user record from cache only. */ inline std::optional< sqlUser* > getCachedUserRecord( const string& user_name ) { @@ -575,8 +670,21 @@ class cservice : public xClient unsigned int getOutputTotal(const iClient* theClient); bool hasOutputFlooded(iClient*); - int authenticateUser(const string& username, const string& password, const string& ip, const string& ident,unsigned int&, sqlUser**); - int authenticateUser(const string& username, const string& password, iClient*, sqlUser**); + using AuthStruct = struct { + AuthType type ; + unsigned int result ; + std::string username ; + std::string password ; + std::string ident ; + std::string ip ; + std::string fingerprint ; + sqlUser* theUser ; + iClient* theClient ; + SaslMechanism sasl ; + } ; + + AuthResult authenticateUser( AuthStruct& ) ; + bool processAuthentication( AuthStruct, std::string* Message = nullptr ) ; void doXQToAllServices(const string&, const string&); @@ -833,11 +941,13 @@ class cservice : public xClient void preloadChannelCache(); void preloadLevelsCache(); void preloadUserCache(); + void preloadFingerprintCache(); bool loadGlines(); void updateChannels(); void updateUsers(); + void updateFingerprints(); void updateUserLevels(sqlUser* ); void updateLevels(int channelId = 0); vector getChannelManager(int channelId); diff --git a/mod.cservice/cserviceCommands.h b/mod.cservice/cserviceCommands.h index 4d468fb1..8831e1c1 100644 --- a/mod.cservice/cserviceCommands.h +++ b/mod.cservice/cserviceCommands.h @@ -106,6 +106,7 @@ DECLARE_COMMAND( VERIFY ) DECLARE_COMMAND( RANDOM ) DECLARE_COMMAND( SUPPORT ) DECLARE_COMMAND( NOTE ) +DECLARE_COMMAND( CERT ) // Channel user level commands. diff --git a/mod.cservice/cservice_config.h b/mod.cservice/cservice_config.h index 8146afdb..c89ab5ec 100644 --- a/mod.cservice/cservice_config.h +++ b/mod.cservice/cservice_config.h @@ -123,10 +123,27 @@ #undef GLINE_ON_FLOODPRO /* - * Enable this to send new AC messages upon changes of sqlUser flags. + * Enable this to enable the following features currently not released in ircu: + * - Send new AC messages upon changes of sqlUser flags. + * - TLS connections + * - SASL authentication + * - Network config + * - Autohide hostmask (+x) * All servers on the network must run the appropriate version of ircu * in order not to get protocol violation messages. */ -#undef USE_AC_XFLAGS +#undef NEW_IRCU_FEATURES + +/** + * Define the number of iterations for the SCRAM record generation. + * Must not exceed 4096. + */ +#define CRYPT_ITERATIONS 4096 + +/** + * Define the length of the salt for the SCRAM record generation. + * Must be in the range of 12 to 64 bytes. + */ +#define CRYPT_SALT_LEN 16 #endif // __CSERVICE_CONFIG_H diff --git a/mod.cservice/cservice_confvars.h b/mod.cservice/cservice_confvars.h index b1890554..0a7f330b 100644 --- a/mod.cservice/cservice_confvars.h +++ b/mod.cservice/cservice_confvars.h @@ -81,6 +81,8 @@ CONFIG_VAR( unsigned int, preloadUserDays, "preload_user_days") \ CONFIG_VAR( unsigned int, partIdleChan, "part_idle_chan") \ CONFIG_VAR( unsigned int, connectRetry, "connection_retry_total") \ + CONFIG_VAR( unsigned int, saslTimeout, "sasl_timeout") \ + CONFIG_VAR( unsigned int, maxFingerprints, "max_fingerprints") \ CONFIG_VAR( unsigned int, logVerbosity, "log_verbosity") \ CONFIG_VAR( unsigned int, chanVerbosity, "chan_verbosity") \ CONFIG_VAR( unsigned int, consoleVerbosity, "console_verbosity") \ diff --git a/mod.cservice/cservice_crypt.cc b/mod.cservice/cservice_crypt.cc new file mode 100644 index 00000000..b5fc6990 --- /dev/null +++ b/mod.cservice/cservice_crypt.cc @@ -0,0 +1,345 @@ +/** + * cservice_crypt.cc + * Author: MrIron + * + * 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. + * + */ + +#include "cservice_crypt.h" +#ifdef HAVE_LIBSSL + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cservice_config.h" +#include "ELog.h" + +namespace gnuworld +{ + +/** + * Write an error if `err` is non-null, then return std::nullopt. + */ +template +static std::optional fail( std::string_view msg, std::string* err ) +{ + if( err ) *err = std::string( msg ) ; + return std::nullopt ; +} + +/** + * Base64-encode a byte array. + */ +std::string b64encode( const unsigned char* data, size_t len ) +{ + std::string out ; + out.resize( 4 * ( ( len + 2 ) / 3 ) ) ; + int n = EVP_EncodeBlock( reinterpret_cast< unsigned char* >( &out[ 0 ] ), data, (int)len ) ; + if( n < 0 ) return {} ; + out.resize( (size_t)n ) ; + return out ; +} + +/** + * Base64-decode a string to a byte vector. + */ +std::optional< std::vector< unsigned char > > +b64decode( std::string_view b64, std::string* err, bool validatePrintable ) +{ + if( b64.size() % 4 != 0 ) return fail< std::vector< unsigned char > >( "bad base64 length", err ) ; + + // Validate that the input contains only valid base64 characters + for( char c : b64 ) { + if( !std::isalnum( c ) && c != '+' && c != '/' && c != '=' ) { + return fail< std::vector< unsigned char > >( "invalid base64 character", err ) ; + } + } + + std::vector< unsigned char > out ; + out.resize( 3 * ( b64.size() / 4 ) ) ; + + int n = EVP_DecodeBlock( out.data(), + reinterpret_cast< const unsigned char* >( b64.data() ), + (int)b64.size() ) ; + if( n < 0 ) return fail< std::vector< unsigned char > >( "bad base64", err ) ; + + // Compute real length by subtracting '=' padding (0,1,2) + size_t pad = 0 ; + if( !b64.empty() && b64.back() == '=' ) + { + pad++ ; + if( b64.size() >= 2 && b64[ b64.size() - 2 ] == '=' ) pad++ ; + } + size_t real_len = (size_t)n - pad ; + if( real_len > out.size() ) return fail< std::vector< unsigned char > >( "base64 overflow", err ) ; + out.resize( real_len ) ; + + // Optionally validate that decoded data contains only printable ASCII characters and null bytes + if( validatePrintable ) { + for( size_t i = 0 ; i < real_len ; ++i ) { + if( out[ i ] != 0 && ( out[ i ] < 32 || out[ i ] > 126 ) ) { + return fail< std::vector< unsigned char > >( "decoded data contains non-printable characters", err ) ; + } + } + } + + return out ; +} + +/** + * PBKDF2-HMAC-SHA256 key derivation. + */ +static inline std::optional< std::array< unsigned char, 32 > > +pbkdf2_sha256( std::string_view password, + const unsigned char* salt, size_t salt_len, + int iterations, + std::string* err ) +{ + std::array< unsigned char, 32 > out{} ; + if( !PKCS5_PBKDF2_HMAC( password.data(), (int)password.size(), + salt, (int)salt_len, iterations, + EVP_sha256(), (int)out.size(), out.data() ) ) + return fail< std::array< unsigned char, 32 > >( "PBKDF2 failed", err ) ; + return out ; +} + +/** + * SHA256 hash. + */ +static inline std::optional< std::array< unsigned char, 32 > > +sha256( const unsigned char* data, size_t len, std::string* err ) +{ + std::array< unsigned char, 32 > out{} ; + unsigned int outlen = 0 ; + EVP_MD_CTX* ctx = EVP_MD_CTX_new() ; + if( !ctx ) return fail< std::array< unsigned char, 32 > >( "EVP_MD_CTX_new failed", err ) ; + if( EVP_DigestInit_ex( ctx, EVP_sha256(), nullptr ) != 1 + || EVP_DigestUpdate( ctx, data, len ) != 1 + || EVP_DigestFinal_ex( ctx, out.data(), &outlen ) != 1 ) + { + EVP_MD_CTX_free( ctx ) ; + return fail< std::array< unsigned char, 32 > >( "SHA256 failed", err ) ; + } + EVP_MD_CTX_free( ctx ) ; + return out ; +} + +/** + * HMAC-SHA256. + */ +static inline std::optional< std::array< unsigned char, 32 > > +hmac_sha256( const unsigned char* key, size_t key_len, + const unsigned char* msg, size_t msg_len, + std::string* err ) +{ + std::array< unsigned char, 32 > out{} ; + unsigned int outlen = 0 ; + if( !HMAC( EVP_sha256(), key, (int)key_len, msg, msg_len, out.data(), &outlen ) ) + return fail< std::array< unsigned char, 32 > >( "HMAC failed", err ) ; + return out ; +} + +/** + * Parse a SCRAM-SHA-256 record string into its components. + */ +std::optional< ScramParsed > +parse_scram_sha256_record( const std::string& rec, std::string* err ) +{ + constexpr const char* kPrefix = "SCRAM-SHA-256$" ; + if( rec.rfind( kPrefix, 0 ) != 0 ) + return fail< ScramParsed >( "bad prefix", err ) ; + + std::string_view rest( rec ) ; + rest.remove_prefix( std::char_traits< char >::length( kPrefix ) ) ; + + // iterations + auto pos1 = rest.find( ':' ) ; + if( pos1 == std::string_view::npos ) return fail< ScramParsed >( "bad record (no ':')", err ) ; + int iterations = 0 ; + { + auto it_str = rest.substr( 0, pos1 ) ; + auto first = it_str.data() ; + auto last = it_str.data() + it_str.size() ; + auto res = std::from_chars( first, last, iterations ) ; + if( res.ec != std::errc() || res.ptr != last ) + return fail< ScramParsed >( "bad iterations", err ) ; + } + rest.remove_prefix( pos1 + 1 ) ; + + // salt_b64 + auto pos2 = rest.find( '$' ) ; + if( pos2 == std::string_view::npos ) return fail< ScramParsed >( "bad record (no '$')", err ) ; + auto salt_b64 = rest.substr( 0, pos2 ) ; + rest.remove_prefix( pos2 + 1 ) ; + + // stored_b64 : server_b64 + auto pos3 = rest.find( ':' ) ; + if( pos3 == std::string_view::npos ) return fail< ScramParsed >( "bad record (no second ':')", err ) ; + auto stored_b64 = rest.substr( 0, pos3 ) ; + auto server_b64 = rest.substr( pos3 + 1 ) ; + + auto saltOpt = b64decode( salt_b64, err ) ; + if( !saltOpt ) return std::nullopt ; + auto storedOpt = b64decode( stored_b64, err ) ; + if( !storedOpt ) return std::nullopt ; + auto serverOpt = b64decode( server_b64, err ) ; + if( !serverOpt ) return std::nullopt ; + + if( storedOpt->size() != 32 ) return fail< ScramParsed >( "storedKey wrong size", err ) ; + if( serverOpt->size() != 32 ) return fail< ScramParsed >( "serverKey wrong size", err ) ; + + ScramParsed out { + iterations, + std::move( *saltOpt ), + std::move( *storedOpt ), + std::move( *serverOpt ) + } ; + return out ; +} + +/** + * Create a SCRAM-SHA-256 record string from a plaintext password. + */ +std::optional< std::string > +make_scram_sha256_record( std::string_view password, std::string* err ) +{ + if( CRYPT_ITERATIONS < 4096 ) + return fail< std::string >( "iterations too low", err ) ; + if( CRYPT_SALT_LEN < 12 || CRYPT_SALT_LEN > 64 ) + return fail< std::string >( "salt_len out of range", err ) ; + + std::vector< unsigned char > salt( CRYPT_SALT_LEN ) ; + if( RAND_bytes( salt.data(), (int)salt.size() ) != 1 ) + return fail< std::string >( "RAND_bytes failed", err ) ; + + auto saltedOpt = pbkdf2_sha256( password, salt.data(), salt.size(), CRYPT_ITERATIONS, err ) ; + if( !saltedOpt ) return std::nullopt ; + auto& salted = *saltedOpt ; + + static const unsigned char ck[] = "Client Key" ; + auto clientKeyOpt = hmac_sha256( salted.data(), salted.size(), ck, sizeof( ck ) - 1, err ) ; + if( !clientKeyOpt ) return std::nullopt ; + auto& clientKey = *clientKeyOpt ; + + auto storedKeyOpt = sha256( clientKey.data(), clientKey.size(), err ) ; + if( !storedKeyOpt ) return std::nullopt ; + auto& storedKey = *storedKeyOpt ; + + static const unsigned char sk[] = "Server Key" ; + auto serverKeyOpt = hmac_sha256( salted.data(), salted.size(), sk, sizeof( sk ) - 1, err ) ; + if( !serverKeyOpt ) return std::nullopt ; + auto& serverKey = *serverKeyOpt ; + + std::string rec ; + rec.reserve( 64 + CRYPT_SALT_LEN ) ; + rec += "SCRAM-SHA-256$" ; + rec += std::to_string( CRYPT_ITERATIONS ) ; + rec += ":" ; + rec += b64encode( salt.data(), salt.size() ) ; + rec += "$" ; + rec += b64encode( storedKey.data(), storedKey.size() ) ; + rec += ":" ; + rec += b64encode( serverKey.data(), serverKey.size() ) ; + + OPENSSL_cleanse( salted.data(), salted.size() ) ; + OPENSSL_cleanse( clientKey.data(), clientKey.size() ) ; + + return rec ; +} + +/** + * Generate a random nonce for SCRAM authentication. + */ +std::optional< std::string > generateRandomNonce( size_t length, std::string* err ) +{ + std::vector< unsigned char > buf( length ) ; + if( RAND_bytes( buf.data(), (int)length ) != 1 ) + return fail< std::string >( "RAND_bytes failed in generateRandomNonce", err ) ; + // Use base64 for nonce encoding, remove any trailing '=' + std::string nonce = b64encode( buf.data(), buf.size() ) ; + nonce.erase( std::remove( nonce.begin(), nonce.end(), '=' ), nonce.end() ) ; + return nonce ; +} + +/** + * Validate a SCRAM-SHA-256 client proof. + */ +bool validate_scram_sha256_proof( + const std::vector< unsigned char >& storedKey, + const std::string& authMessage, + const std::string& clientProof_b64 +) +{ + auto proofOpt = b64decode( clientProof_b64 ) ; + if( !proofOpt || proofOpt->size() != storedKey.size() ) + { + elog << "[SCRAM] Proof decode failed or wrong size\n" ; + return false ; + } + const std::vector< unsigned char >& clientProof = *proofOpt ; + + unsigned int siglen = 0 ; + unsigned char clientSignature[ SHA256_DIGEST_LENGTH ] ; + HMAC( EVP_sha256(), + storedKey.data(), storedKey.size(), + reinterpret_cast< const unsigned char* >( authMessage.data() ), authMessage.size(), + clientSignature, &siglen ) ; + + std::vector< unsigned char > clientKey( clientProof.size() ) ; + for( size_t i = 0 ; i < clientProof.size() ; ++i ) + clientKey[ i ] = clientProof[ i ] ^ clientSignature[ i ] ; + + unsigned char computedStoredKey[ SHA256_DIGEST_LENGTH ] ; + SHA256( clientKey.data(), clientKey.size(), computedStoredKey ) ; + + bool result = std::memcmp( computedStoredKey, storedKey.data(), SHA256_DIGEST_LENGTH ) == 0 ; + return result ; +} + +/** + * Compute the SCRAM server signature. + */ +std::string compute_server_signature( + const std::vector< unsigned char >& serverKey, + const std::string& authMessage +) +{ + unsigned int siglen = 0 ; + unsigned char serverSignature[ SHA256_DIGEST_LENGTH ] ; + HMAC( EVP_sha256(), + serverKey.data(), serverKey.size(), + reinterpret_cast< const unsigned char* >( authMessage.data() ), authMessage.size(), + serverSignature, &siglen ) ; + return b64encode( serverSignature, siglen ) ; +} + +} // namespace gnuworld + +#endif // HAVE_LIBSSL diff --git a/mod.cservice/cservice_crypt.h b/mod.cservice/cservice_crypt.h new file mode 100644 index 00000000..56ebbea5 --- /dev/null +++ b/mod.cservice/cservice_crypt.h @@ -0,0 +1,92 @@ +/** + * cservice_crypt.h + * Author: MrIron + * + * 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. + * + */ + +#include "defs.h" +#ifdef HAVE_LIBSSL + +#pragma once + +#include +#include +#include + +namespace gnuworld { + +/** + * Parsed SCRAM-SHA-256 record. + */ +struct ScramParsed { + int iterations ; + std::vector< unsigned char > salt ; // variable length, typically 16 + std::vector< unsigned char > storedKey ; // 32 bytes + std::vector< unsigned char > serverKey ; // 32 bytes +} ; + +/** + * Create a SCRAM-SHA-256 record string from a plaintext password. + * Format: "SCRAM-SHA-256$:$:" + * Returns std::nullopt on failure; writes error text into err if provided. + */ +std::optional< std::string > make_scram_sha256_record( std::string_view password, std::string* err = nullptr ) ; + +/** + * Parse a SCRAM-SHA-256 record string into its components. + * Returns std::nullopt on parse error; writes error text into err if provided. + */ +std::optional< ScramParsed > parse_scram_sha256_record( const std::string& record, std::string* err = nullptr ) ; + +/** + * Generate a random nonce for SCRAM authentication. + * Returns std::nullopt on failure; writes error text into err if provided. + */ +std::optional< std::string > generateRandomNonce( size_t length = 18, std::string* err = nullptr ) ; + +/** + * Base64-encode a byte array. + */ +std::string b64encode( const unsigned char* data, size_t len ) ; + +/** + * Base64-decode a byte array. + */ +std::optional< std::vector< unsigned char > > +b64decode( std::string_view b64, std::string* err = nullptr, bool validatePrintable = false ) ; + +/** + * Validate a SCRAM-SHA-256 client proof. + */ +bool validate_scram_sha256_proof( + const std::vector< unsigned char >& storedKey, + const std::string& authMessage, + const std::string& clientProof_b64 +) ; + +/** + * Compute the SCRAM server signature. + */ +std::string compute_server_signature( + const std::vector< unsigned char >& serverKey, + const std::string& authMessage +) ; + +} // namespace + +#endif // HAVE_LIBSSL diff --git a/mod.cservice/responses.h b/mod.cservice/responses.h index 109097ce..8c8f00fd 100644 --- a/mod.cservice/responses.h +++ b/mod.cservice/responses.h @@ -230,7 +230,10 @@ namespace gnuworld const int reason_must = 192; const int susp_reason = 193; const int unsusp_reason = 194; - + const int certonly_on = 195; + const int certonly_off = 196; + const int autohide_on = 197; + const int autohide_off = 198; // Allow for merge of other features const int welcome_max_len = 205; @@ -256,6 +259,17 @@ namespace gnuworld const int mode_wrongkey = 223; const int mode_keylength = 224; + const int no_fingerprints_registered = 225; + const int no_fingerprints_found = 226; + const int your_fingerprint_is = 227; + const int max_fingerprints = 228; + const int invalid_fingerprint = 229; + const int fingerprint_already_exists = 230; + const int fingerprint_added = 231; + const int fingerprint_removed = 232; + const int fingerprint_norem_certonly = 233; + const int fingerprint_not_found = 234; + const int greeting = 9998; const int motd = 9999; } diff --git a/mod.cservice/sqlUser.cc b/mod.cservice/sqlUser.cc index 597964b7..63623906 100644 --- a/mod.cservice/sqlUser.cc +++ b/mod.cservice/sqlUser.cc @@ -68,6 +68,7 @@ sqlUser::sqlUser(cservice* _bot) notes_sent(0), failed_logins(0), failed_login_ts(0), + scram_record(), logger(_bot->getLogger()), SQLDb(_bot->SQLDb) { @@ -171,22 +172,25 @@ verifdata = SQLDb->GetValue(row, 11); failed_logins = 0; failed_login_ts = 0; totp_key = SQLDb->GetValue(row, 12); +scram_record = SQLDb->GetValue(row, 13); /* Fetch the "Last Seen" time from the users_lastseen table. */ } bool sqlUser::commit(iClient* who) { +if(who) + return commit(who->getNickUserHost()); +else + return commit("Marvin, the paranoid android."); +} + +bool sqlUser::commit(std::string last_updated_by) +{ /* * Build an SQL statement to commit the transient data in this storage class * back into the database. */ -if(who) -{ - last_updated_by = who->getNickUserHost(); -} else { - last_updated_by = "Marvin, the paranoid android."; -} static const char* queryHeader = "UPDATE users "; static const char* queryCondition = "WHERE id = "; @@ -199,7 +203,8 @@ queryString << queryHeader << "maxlogins = " << maxlogins << ", " << "last_updated = date_part('epoch', CURRENT_TIMESTAMP)::int, " << "last_updated_by = '" << escapeSQLChars(last_updated_by) << "', " - << "totp_key = '" << escapeSQLChars(totp_key) << "' " + << "totp_key = '" << escapeSQLChars(totp_key) << "', " + << "scram_record = '" << escapeSQLChars(scram_record) << "' " << queryCondition << id << ends; @@ -424,7 +429,7 @@ bool sqlUser::Insert() */ static const char* queryHeader = "INSERT INTO users " "(user_name,password,language_id,flags,last_updated_by,last_" - "updated,post_forms,signup_ts,email) VALUES ('"; + "updated,post_forms,signup_ts,email,scram_record) VALUES ('"; stringstream queryString; queryString << queryHeader @@ -439,6 +444,7 @@ queryString << queryHeader << "(date_part('epoch', CURRENT_TIMESTAMP)::int + 432000)," << "date_part('epoch', CURRENT_TIMESTAMP)::int,'" << escapeSQLChars(email) + << "','" << escapeSQLChars(scram_record) << "')" << ends; diff --git a/mod.cservice/sqlUser.h b/mod.cservice/sqlUser.h index 19cf36a0..448aedb3 100644 --- a/mod.cservice/sqlUser.h +++ b/mod.cservice/sqlUser.h @@ -42,7 +42,7 @@ class sqlUser sqlUser(cservice*) ; virtual ~sqlUser() ; - typedef unsigned short int flagType ; + typedef unsigned int flagType ; static constexpr flagType F_GLOBAL_SUSPEND = 0x01 ; static constexpr flagType F_LOGGEDIN = 0x02 ; // Deprecated static constexpr flagType F_INVIS = 0x04 ; @@ -55,7 +55,10 @@ class sqlUser static constexpr flagType F_NOADDUSER = 0x200 ; static constexpr flagType F_TOTP_ENABLED = 0x400 ; static constexpr flagType F_TOTP_REQ_IPR = 0x800 ; - + static constexpr flagType F_CERTONLY = 0x1000 ; + static constexpr flagType F_CERT_DISABLE_TOTP = 0x2000 ; + static constexpr flagType F_WEB_DISABLE_TOTP = 0x4000 ; + static constexpr flagType F_AUTOHIDE = 0x8000 ; /* * User 'Event' Flags, used in the userlog table. */ @@ -152,6 +155,9 @@ class sqlUser inline const std::string& getTotpKey() const { return totp_key ; } + inline const std::string& getScramRecord() const + { return scram_record ; } + /* * Methods to set data atrributes. */ @@ -220,12 +226,17 @@ class sqlUser inline void setTotpKey( const std::string& _totp_key ) { totp_key = _totp_key ; } + + inline void setScramRecord( const std::string& _scram_record ) + { scram_record = _scram_record ; } + /* * Method to perform a SQL 'UPDATE' and commit changes to this * object back to the database. */ - bool commit(iClient* who); + bool commit(iClient*); + bool commit(std::string); bool commitLastSeen(); bool commitLastSeenWithoutMask(); time_t getLastSeen(); @@ -269,6 +280,7 @@ class sqlUser unsigned int failed_logins; unsigned int failed_login_ts; std::string totp_key; + std::string scram_record; Logger* logger; dbHandle* SQLDb; diff --git a/mod.dronescan/FAKECommand.cc b/mod.dronescan/FAKECommand.cc index ac36cb08..2430ae04 100644 --- a/mod.dronescan/FAKECommand.cc +++ b/mod.dronescan/FAKECommand.cc @@ -78,6 +78,7 @@ void FAKECommand::Exec( const iClient *theClient, const string& Message, const s string(), 0, 0, + string(), theFake->getRealName(), ::time(0) ); diff --git a/mod.gnutest/gnutest.cc b/mod.gnutest/gnutest.cc index a21a2168..2cb6890e 100644 --- a/mod.gnutest/gnutest.cc +++ b/mod.gnutest/gnutest.cc @@ -867,6 +867,7 @@ iClient* newClient = new (std::nothrow) iClient( string(), // account 0, // account_id 0, // account_flags + string(), // tls fingerprint "test spawn client, moo", // description 31337 // connect time ) ; diff --git a/mod.nickserv/nickserv.cc b/mod.nickserv/nickserv.cc index ec3ba11e..c14dddbe 100644 --- a/mod.nickserv/nickserv.cc +++ b/mod.nickserv/nickserv.cc @@ -607,6 +607,7 @@ for( vector::iterator itr = jupeQueue.begin(); string(), 0, 0, + string(), "Juped Nick", ::time( 0 ) ); diff --git a/mod.scanner/wingateModule.cc b/mod.scanner/wingateModule.cc index 8ef45d31..c701d208 100644 --- a/mod.scanner/wingateModule.cc +++ b/mod.scanner/wingateModule.cc @@ -66,7 +66,7 @@ wingateModule::~wingateModule() void wingateModule::CheckIP( const string& ip ) { -cm->Connect( this, ip, 23 ) ; +cm->Connect( this, ip, 23, false ) ; } void wingateModule::OnConnect( Connection* ) diff --git a/mod.snoop/snoop.cc b/mod.snoop/snoop.cc index fb766919..055cb094 100644 --- a/mod.snoop/snoop.cc +++ b/mod.snoop/snoop.cc @@ -197,6 +197,7 @@ iClient* newClient = new (std::nothrow) iClient( string(), // account 0, // account_id 0, // account_flags + string(), // tls fingerprint realname, 31337 // connect time ) ; diff --git a/src/Channel.cc b/src/Channel.cc index 1f1bee5d..cb79ec3e 100644 --- a/src/Channel.cc +++ b/src/Channel.cc @@ -59,6 +59,7 @@ const Channel::modeType Channel::MODE_C = 0x02000 ; const Channel::modeType Channel::MODE_CTCP = 0x04000 ; const Channel::modeType Channel::MODE_PART = 0x08000 ; const Channel::modeType Channel::MODE_MNOREG = 0x10000 ; +const Channel::modeType Channel::MODE_Z = 0x20000 ; Channel::Channel( const string& _name, const time_t& _creationTime ) @@ -500,6 +501,7 @@ if( modes & MODE_C ) modeString += 'c'; if( modes & MODE_CTCP ) modeString += 'C'; if( modes & MODE_PART ) modeString += 'u'; if( modes & MODE_MNOREG ) modeString += 'M'; +if( modes & MODE_Z ) modeString += 'Z'; if( modes & MODE_K ) { diff --git a/src/Network.cc b/src/Network.cc index 336d4b11..dee7e9cf 100644 --- a/src/Network.cc +++ b/src/Network.cc @@ -174,6 +174,14 @@ return channelMap.insert( theChan ) ).second ; } +std::optional< std::pair< std::string, time_t > > xNetwork::findNetConf( const std::string& key ) const +{ +auto it = netConfMap.find( key ) ; +if( it != netConfMap.end() ) + return it->second; +return std::nullopt; +} + iClient* xNetwork::findClient( const unsigned int& intYYXXX ) const { numericMapType::const_iterator ptr = numericMap.find( intYYXXX ) ; diff --git a/src/client.cc b/src/client.cc index ee4334b2..f033a8f2 100644 --- a/src/client.cc +++ b/src/client.cc @@ -122,6 +122,7 @@ if( mode & iClient::MODE_SERVICES ) Mode += 'k' ; if( mode & iClient::MODE_OPER ) Mode += 'o' ; if( mode & iClient::MODE_WALLOPS ) Mode += 'w' ; if( mode & iClient::MODE_INVISIBLE ) Mode += 'i' ; +if( mode & iClient::MODE_TLS ) Mode += 'z' ; return Mode ; } @@ -153,6 +154,7 @@ for( ; ptr != end ; ++ptr ) case 'o': mode |= iClient::MODE_OPER ; break; case 'w': mode |= iClient::MODE_WALLOPS ; break; case 'i': mode |= iClient::MODE_INVISIBLE ; break; + case 'z': mode |= iClient::MODE_TLS ; break; default: elog << "xClient::Mode> Unknown mode: " @@ -2667,11 +2669,16 @@ for( string::size_type modePos = 0 ; modePos < modes.size() ; ++modePos ) modeVector.push_back(make_pair(false, Channel::MODE_PART)); break; - case 'M': // mode to prevent part messages + case 'M': // mode to moderate for non-authed users theChan->removeMode(Channel::MODE_MNOREG); modeVector.push_back(make_pair(false, Channel::MODE_MNOREG)); break; + case 'Z': // TLS only? + theChan->removeMode(Channel::MODE_Z); + modeVector.push_back(make_pair(false, + Channel::MODE_Z)); + break; case 'A': // Apass for oplevels if (theChan->getMode(Channel::MODE_A)) { diff --git a/src/iClient.cc b/src/iClient.cc index 7af8ec13..310cb345 100644 --- a/src/iClient.cc +++ b/src/iClient.cc @@ -55,6 +55,7 @@ iClient::iClient( const unsigned int& /* _uplink */, const string& _account, const unsigned int _account_id, const flagType _account_flags, + const string& _tls_fingerprint, const string& _description, const time_t& _nick_ts ) : NetworkTarget( _yyxxx ), @@ -69,7 +70,8 @@ iClient::iClient( const unsigned int& /* _uplink */, mode( 0 ), account( _account ), account_id( _account_id ), - account_flags( _account_flags ) + account_flags( _account_flags ), + tlsFingerprint( _tls_fingerprint ) { setModes( _mode ) ; customDataMap = 0 ; @@ -87,6 +89,7 @@ iClient::iClient( const unsigned int& /* _uplink */, const string& _account, const unsigned int _account_id, const flagType _account_flags, + const string& _tls_fingerprint, const string& _setHost, const string& _fakeHost, const string& _description, @@ -103,7 +106,8 @@ iClient::iClient( const unsigned int& /* _uplink */, mode( 0 ), account( _account ), account_id( _account_id ), - account_flags( _account_flags ) + account_flags( _account_flags ), + tlsFingerprint( _tls_fingerprint ) #ifdef ASUKA ,setHost( _setHost ) #endif @@ -161,6 +165,9 @@ for( string::size_type i = 0 ; i < newModes.size() ; i++ ) case 'g': setModeG() ; break ; + case 'z': + setModeZ() ; + break ; case 'r': case 'R': setModeR() ; @@ -221,6 +228,7 @@ if( isModeK() ) retMe += 'k' ; if( isModeR() ) retMe += 'r' ; if( isModeX() ) retMe += 'x' ; if( isModeG() ) retMe += 'g' ; +if( isModeZ() ) retMe += 'z' ; return retMe ; } diff --git a/src/main.cc b/src/main.cc index 3a42ebca..ddc0742a 100644 --- a/src/main.cc +++ b/src/main.cc @@ -249,6 +249,7 @@ xServer::xServer( bool verbose_arg, bool doDebug_arg, bool logSocket_arg, const std::string& configFileName_arg, const std::string& simFileName_arg ) : eventList( EVT_NOOP ), + tlsEnabled( false ), verbose( verbose_arg ), doDebug( doDebug_arg ), logSocket( logSocket_arg ), @@ -310,7 +311,7 @@ while( keepRunning ) << "... " << endl ; - serverConnection = Connect( this, UplinkName, Port ) ; + serverConnection = Connect( this, UplinkName, Port, tlsEnabled ) ; } } // if( NULL == serverConnection ) diff --git a/src/server.cc b/src/server.cc index d802097e..476c2a5e 100644 --- a/src/server.cc +++ b/src/server.cc @@ -264,9 +264,70 @@ glineUpdateInterval = static_cast< time_t >( atoi( pingUpdateInterval = static_cast< time_t >( atoi( conf.Require( "pingupdateinterval" )->second.c_str() ) ) ; +// Check TLS configuration settings +#ifdef HAVE_LIBSSL +EConfig::const_iterator tlsItr = conf.Find( "tls" ) ; +if ( tlsItr == conf.end() || tlsItr->second != "yes" ) +{ + tlsEnabled = false ; +} else { + tlsEnabled = true ; + + // If TLS is enabled, parse the other configuration options + tlsKeyFile = conf.Require( "tlsKeyFile" )->second ; + tlsCertFile = conf.Require( "tlsCertFile" )->second ; + + if (!initTls()) { + elog << "TLS initialization error. Exiting." << endl; + ::exit(1); + } +} +#endif return true ; } +/** + * This function is only called if TLS is enabled in config. We exit if gnuworld + * is not compiled with TLS support. + */ +#ifdef HAVE_LIBSSL +bool xServer::initTls() +{ + elog << "xServer::initTls - Spinning up TLS" << endl; + SSL_library_init(); + SSL_load_error_strings(); + sslCtx = SSL_CTX_new(TLS_method()); + + SSL_CTX_set_min_proto_version(sslCtx, TLS1_2_VERSION); // Allow TLS 1.2 and above + SSL_CTX_set_max_proto_version(sslCtx, TLS1_3_VERSION); // Allow up to TLS 1.3 + SSL_CTX_set_verify(sslCtx, SSL_VERIFY_NONE, NULL); + + int res = SSL_CTX_use_certificate_chain_file(sslCtx, tlsCertFile.c_str()); + if (res != 1) { + elog << "xServer::initTls - Could not load certificate file" << endl; + SSL_CTX_free(sslCtx); + return false; + } + + res = SSL_CTX_use_PrivateKey_file(sslCtx, tlsKeyFile.c_str(), SSL_FILETYPE_PEM); + if (res != 1) { + elog << "xServer::initTls - Could not load key file" << endl; + SSL_CTX_free(sslCtx); + return false; + } + + res = SSL_CTX_check_private_key(sslCtx); + if (res != 1) { + elog << "xServer::initTls - Private key validation failed" << endl; + SSL_CTX_free(sslCtx); + return false; + } + + SSL_CTX_set_cipher_list(sslCtx, SSL_DEFAULT_CIPHER_LIST); + return true; +} +#endif + bool xServer::loadCommandHandlers() { std::ifstream commandMapFile( commandMapFileName.c_str() ) ; @@ -953,6 +1014,7 @@ iClient* theIClient = new (std::nothrow) iClient( 0, string(), string(), + string(), Client->getDescription(), ::time( 0 ) ) ; assert( theIClient != 0 ) ; @@ -1805,6 +1867,12 @@ if( !chanModes.empty() && else theChan->removeMode(Channel::MODE_MNOREG); break; + case 'Z': + if (plus) + theChan->setMode(Channel::MODE_Z); + else + theChan->removeMode(Channel::MODE_Z); + break; // TODO: Finish with polarity // TODO: Add in support for modes b,v,o @@ -1951,8 +2019,12 @@ s << theClient->getCharYY() << " N " << hopCount << " 31337 " << theClient->getUserName() << ' ' << theClient->getHostName() << ' ' - << theClient->getModes() << ' ' - << "AAAAAA " + << theClient->getModes() << ' ' ; + +if( theClient->getMode( iClient::MODE_TLS ) ) + s << "_ " ; + +s << "AAAAAA " << theClient->getCharYYXXX() << " :" << theClient->getDescription() ; Write( s ) ; @@ -2138,6 +2210,10 @@ if( theChan->getMode( Channel::MODE_MNOREG ) ) { modeVector.push_back( make_pair( false, Channel::MODE_MNOREG ) ) ; } +if( theChan->getMode( Channel::MODE_Z ) ) + { + modeVector.push_back( make_pair( false, Channel::MODE_Z ) ) ; + } if( theChan->getMode( Channel::MODE_L ) ) { OnChannelModeL( theChan, false, 0, 0 ) ; @@ -2303,6 +2379,7 @@ chanModes[ 'c' ] = Channel::MODE_C ; chanModes[ 'C' ] = Channel::MODE_CTCP ; chanModes[ 'u' ] = Channel::MODE_PART ; chanModes[ 'M' ] = Channel::MODE_MNOREG ; +chanModes[ 'Z' ] = Channel::MODE_Z ; // This vector is used for argument-less types that can be passed // to OnChannelMode() @@ -2379,6 +2456,7 @@ for( ; tokenIndex < st.size() ; ) case 'u': case 'M': case 'D': + case 'Z': // elog << "xServer::Mode> General mode: " // << theChar // << ", polarity: " @@ -3370,6 +3448,9 @@ for( string::const_iterator ptr = st[ 0 ].begin() ; ptr != st[ 0 ].end() ; case 'M': theChan->setMode( Channel::MODE_MNOREG ) ; break; + case 'Z': + theChan->setMode( Channel::MODE_Z ) ; + break; case 'k': { if( argPos >= st.size() ) diff --git a/src/server_connection.cc b/src/server_connection.cc index 0f3a0c0c..6186f879 100644 --- a/src/server_connection.cc +++ b/src/server_connection.cc @@ -50,7 +50,6 @@ //#include "events.h" //#include "ip.h" -#include "misc.h" #include "server.h" #include "Network.h" //#include "iServer.h" @@ -64,6 +63,7 @@ //#include "ServerTimerHandlers.h" //#include "LoadClientTimerHandler.h" //#include "UnloadClientTimerHandler.h" +#include "misc.h" #include "ConnectionManager.h" #include "ConnectionHandler.h" #include "Connection.h" From 5082f57f0824a54874fbbeb5797ce764f009aec5 Mon Sep 17 00:00:00 2001 From: MrIron Date: Fri, 9 Jan 2026 14:30:49 +0100 Subject: [PATCH 2/3] Update autotools. Added missing language fields. --- Makefile.in | 5 +- aclocal.m4 | 992 +------------------------------------ doc/cservice.update.sql | 8 +- libltdl/Makefile.in | 24 +- libltdl/aclocal.m4 | 992 +------------------------------------ libltdl/configure | 0 mod.cservice/SETCommand.cc | 2 +- 7 files changed, 26 insertions(+), 1997 deletions(-) mode change 100755 => 100644 libltdl/configure diff --git a/Makefile.in b/Makefile.in index 81bc9cf1..f8b2560e 100644 --- a/Makefile.in +++ b/Makefile.in @@ -153,6 +153,8 @@ bin_PROGRAMS = gnuworld$(EXEEXT) @COND_MODCSERVICE_TRUE@ mod.cservice/constants.h \ @COND_MODCSERVICE_TRUE@ mod.cservice/cserviceCommands.h \ @COND_MODCSERVICE_TRUE@ mod.cservice/cservice_config.h \ +@COND_MODCSERVICE_TRUE@ mod.cservice/cservice_confvars.h \ +@COND_MODCSERVICE_TRUE@ mod.cservice/cservice_crypt.h \ @COND_MODCSERVICE_TRUE@ mod.cservice/cservice.h \ @COND_MODCSERVICE_TRUE@ mod.cservice/levels.h \ @COND_MODCSERVICE_TRUE@ mod.cservice/networkData.h \ @@ -251,7 +253,8 @@ ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_boost_base.m4 \ $(top_srcdir)/m4/ax_boost_thread.m4 \ $(top_srcdir)/m4/ax_cxx_compile_stdcxx.m4 \ - $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ + $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltargz.m4 \ + $(top_srcdir)/m4/ltdl.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ diff --git a/aclocal.m4 b/aclocal.m4 index c1224da9..7a1f9181 100644 --- a/aclocal.m4 +++ b/aclocal.m4 @@ -20,996 +20,6 @@ You have another version of autoconf. It may work, but is not guaranteed to. If you have problems, you may need to regenerate the build system entirely. To do so, use the procedure documented by the package, typically 'autoreconf'.])]) -# Portability macros for glibc argz. -*- Autoconf -*- -# -# Copyright (C) 2004-2007, 2011-2019, 2021-2024 Free Software -# Foundation, Inc. -# Written by Gary V. Vaughan -# -# This file is free software; the Free Software Foundation gives -# unlimited permission to copy and/or distribute it, with or without -# modifications, as long as this notice is preserved. - -# serial 2 ltargz.m4 - -AC_DEFUN([LT_FUNC_ARGZ], [ -dnl Required for use of '$SED' in Cygwin configuration. -AC_REQUIRE([AC_PROG_SED])dnl -AC_CHECK_HEADERS([argz.h], [], [], [AC_INCLUDES_DEFAULT]) - -AC_CHECK_TYPES([error_t], - [], - [AC_DEFINE([error_t], [int], - [Define to a type to use for 'error_t' if it is not otherwise available.]) - AC_DEFINE([__error_t_defined], [1], [Define so that glibc/gnulib argp.h - does not typedef error_t.])], - [#if defined(HAVE_ARGZ_H) -# include -#endif]) - -LT_ARGZ_H= -AC_CHECK_FUNCS([argz_add argz_append argz_count argz_create_sep argz_insert \ - argz_next argz_stringify], [], [LT_ARGZ_H=lt__argz.h; AC_LIBOBJ([lt__argz])]) - -dnl if have system argz functions, allow forced use of -dnl libltdl-supplied implementation (and default to do so -dnl on "known bad" systems). Could use a runtime check, but -dnl (a) detecting malloc issues is notoriously unreliable -dnl (b) only known system that declares argz functions, -dnl provides them, yet they are broken, is cygwin -dnl releases prior to 16-Mar-2007 (1.5.24 and earlier) -dnl So, it's more straightforward simply to special case -dnl this for known bad systems. -AS_IF([test -z "$LT_ARGZ_H"], - [AC_CACHE_CHECK( - [if argz actually works], - [lt_cv_sys_argz_works], - [[case $host_os in #( - *cygwin*) - lt_cv_sys_argz_works=no - if test no != "$cross_compiling"; then - lt_cv_sys_argz_works="guessing no" - else - lt_sed_extract_leading_digits='s/^\([0-9\.]*\).*/\1/' - save_IFS=$IFS - IFS=-. - set x `uname -r | $SED -e "$lt_sed_extract_leading_digits"` - IFS=$save_IFS - lt_os_major=${2-0} - lt_os_minor=${3-0} - lt_os_micro=${4-0} - if test 1 -lt "$lt_os_major" \ - || { test 1 -eq "$lt_os_major" \ - && { test 5 -lt "$lt_os_minor" \ - || { test 5 -eq "$lt_os_minor" \ - && test 24 -lt "$lt_os_micro"; }; }; }; then - lt_cv_sys_argz_works=yes - fi - fi - ;; #( - *) lt_cv_sys_argz_works=yes ;; - esac]]) - AS_IF([test yes = "$lt_cv_sys_argz_works"], - [AC_DEFINE([HAVE_WORKING_ARGZ], 1, - [This value is set to 1 to indicate that the system argz facility works])], - [LT_ARGZ_H=lt__argz.h - AC_LIBOBJ([lt__argz])])]) - -AC_SUBST([LT_ARGZ_H]) -]) - -# ltdl.m4 - Configure ltdl for the target system. -*-Autoconf-*- -# -# Copyright (C) 1999-2008, 2011-2019, 2021-2024 Free Software -# Foundation, Inc. -# Written by Thomas Tanner, 1999 -# -# This file is free software; the Free Software Foundation gives -# unlimited permission to copy and/or distribute it, with or without -# modifications, as long as this notice is preserved. - -# serial 24 LTDL_INIT - -# LT_CONFIG_LTDL_DIR(DIRECTORY, [LTDL-MODE]) -# ------------------------------------------ -# DIRECTORY contains the libltdl sources. It is okay to call this -# function multiple times, as long as the same DIRECTORY is always given. -AC_DEFUN([LT_CONFIG_LTDL_DIR], -[AC_BEFORE([$0], [LTDL_INIT]) -_$0($*) -])# LT_CONFIG_LTDL_DIR - -# We break this out into a separate macro, so that we can call it safely -# internally without being caught accidentally by the sed scan in libtoolize. -m4_defun([_LT_CONFIG_LTDL_DIR], -[dnl remove trailing slashes -m4_pushdef([_ARG_DIR], m4_bpatsubst([$1], [/*$])) -m4_case(_LTDL_DIR, - [], [dnl only set lt_ltdl_dir if _ARG_DIR is not simply '.' - m4_if(_ARG_DIR, [.], - [], - [m4_define([_LTDL_DIR], _ARG_DIR) - _LT_SHELL_INIT([lt_ltdl_dir=']_ARG_DIR['])])], - [m4_if(_ARG_DIR, _LTDL_DIR, - [], - [m4_fatal([multiple libltdl directories: ']_LTDL_DIR[', ']_ARG_DIR['])])]) -m4_popdef([_ARG_DIR]) -])# _LT_CONFIG_LTDL_DIR - -# Initialise: -m4_define([_LTDL_DIR], []) - - -# _LT_BUILD_PREFIX -# ---------------- -# If Autoconf is new enough, expand to '$(top_build_prefix)', otherwise -# to '$(top_builddir)/'. -m4_define([_LT_BUILD_PREFIX], -[m4_ifdef([AC_AUTOCONF_VERSION], - [m4_if(m4_version_compare(m4_defn([AC_AUTOCONF_VERSION]), [2.62]), - [-1], [m4_ifdef([_AC_HAVE_TOP_BUILD_PREFIX], - [$(top_build_prefix)], - [$(top_builddir)/])], - [$(top_build_prefix)])], - [$(top_builddir)/])[]dnl -]) - - -# LTDL_CONVENIENCE -# ---------------- -# sets LIBLTDL to the link flags for the libltdl convenience library and -# LTDLINCL to the include flags for the libltdl header and adds -# --enable-ltdl-convenience to the configure arguments. Note that -# AC_CONFIG_SUBDIRS is not called here. LIBLTDL will be prefixed with -# '$(top_build_prefix)' if available, otherwise with '$(top_builddir)/', -# and LTDLINCL will be prefixed with '$(top_srcdir)/' (note the single -# quotes!). If your package is not flat and you're not using automake, -# define top_build_prefix, top_builddir, and top_srcdir appropriately -# in your Makefiles. -AC_DEFUN([LTDL_CONVENIENCE], -[AC_BEFORE([$0], [LTDL_INIT])dnl -dnl Although the argument is deprecated and no longer documented, -dnl LTDL_CONVENIENCE used to take a DIRECTORY orgument, if we have one -dnl here make sure it is the same as any other declaration of libltdl's -dnl location! This also ensures lt_ltdl_dir is set when configure.ac is -dnl not yet using an explicit LT_CONFIG_LTDL_DIR. -m4_ifval([$1], [_LT_CONFIG_LTDL_DIR([$1])])dnl -_$0() -])# LTDL_CONVENIENCE - -# AC_LIBLTDL_CONVENIENCE accepted a directory argument in older libtools, -# now we have LT_CONFIG_LTDL_DIR: -AU_DEFUN([AC_LIBLTDL_CONVENIENCE], -[_LT_CONFIG_LTDL_DIR([m4_default([$1], [libltdl])]) -_LTDL_CONVENIENCE]) - -dnl aclocal-1.4 backwards compatibility: -dnl AC_DEFUN([AC_LIBLTDL_CONVENIENCE], []) - - -# _LTDL_CONVENIENCE -# ----------------- -# Code shared by LTDL_CONVENIENCE and LTDL_INIT([convenience]). -m4_defun([_LTDL_CONVENIENCE], -[case $enable_ltdl_convenience in - no) AC_MSG_ERROR([this package needs a convenience libltdl]) ;; - "") enable_ltdl_convenience=yes - ac_configure_args="$ac_configure_args --enable-ltdl-convenience" ;; -esac -LIBLTDL='_LT_BUILD_PREFIX'"${lt_ltdl_dir+$lt_ltdl_dir/}libltdlc.la" -LTDLDEPS=$LIBLTDL -LTDLINCL='-I$(top_srcdir)'"${lt_ltdl_dir+/$lt_ltdl_dir}" - -AC_SUBST([LIBLTDL]) -AC_SUBST([LTDLDEPS]) -AC_SUBST([LTDLINCL]) - -# For backwards non-gettext consistent compatibility... -INCLTDL=$LTDLINCL -AC_SUBST([INCLTDL]) -])# _LTDL_CONVENIENCE - - -# LTDL_INSTALLABLE -# ---------------- -# sets LIBLTDL to the link flags for the libltdl installable library -# and LTDLINCL to the include flags for the libltdl header and adds -# --enable-ltdl-install to the configure arguments. Note that -# AC_CONFIG_SUBDIRS is not called from here. If an installed libltdl -# is not found, LIBLTDL will be prefixed with '$(top_build_prefix)' if -# available, otherwise with '$(top_builddir)/', and LTDLINCL will be -# prefixed with '$(top_srcdir)/' (note the single quotes!). If your -# package is not flat and you're not using automake, define top_build_prefix, -# top_builddir, and top_srcdir appropriately in your Makefiles. -# In the future, this macro may have to be called after LT_INIT. -AC_DEFUN([LTDL_INSTALLABLE], -[AC_BEFORE([$0], [LTDL_INIT])dnl -dnl Although the argument is deprecated and no longer documented, -dnl LTDL_INSTALLABLE used to take a DIRECTORY orgument, if we have one -dnl here make sure it is the same as any other declaration of libltdl's -dnl location! This also ensures lt_ltdl_dir is set when configure.ac is -dnl not yet using an explicit LT_CONFIG_LTDL_DIR. -m4_ifval([$1], [_LT_CONFIG_LTDL_DIR([$1])])dnl -_$0() -])# LTDL_INSTALLABLE - -# AC_LIBLTDL_INSTALLABLE accepted a directory argument in older libtools, -# now we have LT_CONFIG_LTDL_DIR: -AU_DEFUN([AC_LIBLTDL_INSTALLABLE], -[_LT_CONFIG_LTDL_DIR([m4_default([$1], [libltdl])]) -_LTDL_INSTALLABLE]) - -dnl aclocal-1.4 backwards compatibility: -dnl AC_DEFUN([AC_LIBLTDL_INSTALLABLE], []) - - -# _LTDL_INSTALLABLE -# ----------------- -# Code shared by LTDL_INSTALLABLE and LTDL_INIT([installable]). -m4_defun([_LTDL_INSTALLABLE], -[if test -f "$prefix/lib/libltdl.la"; then - lt_save_LDFLAGS=$LDFLAGS - LDFLAGS="-L$prefix/lib $LDFLAGS" - AC_CHECK_LIB([ltdl], [lt_dlinit], [lt_lib_ltdl=yes]) - LDFLAGS=$lt_save_LDFLAGS - if test yes = "${lt_lib_ltdl-no}"; then - if test yes != "$enable_ltdl_install"; then - # Don't overwrite $prefix/lib/libltdl.la without --enable-ltdl-install - AC_MSG_WARN([not overwriting libltdl at $prefix, force with '--enable-ltdl-install']) - enable_ltdl_install=no - fi - elif test no = "$enable_ltdl_install"; then - AC_MSG_WARN([libltdl not installed, but installation disabled]) - fi -fi - -# If configure.ac declared an installable ltdl, and the user didn't override -# with --disable-ltdl-install, we will install the shipped libltdl. -case $enable_ltdl_install in - no) ac_configure_args="$ac_configure_args --enable-ltdl-install=no" - LIBLTDL=-lltdl - LTDLDEPS= - LTDLINCL= - ;; - *) enable_ltdl_install=yes - ac_configure_args="$ac_configure_args --enable-ltdl-install" - LIBLTDL='_LT_BUILD_PREFIX'"${lt_ltdl_dir+$lt_ltdl_dir/}libltdl.la" - LTDLDEPS=$LIBLTDL - LTDLINCL='-I$(top_srcdir)'"${lt_ltdl_dir+/$lt_ltdl_dir}" - ;; -esac - -AC_SUBST([LIBLTDL]) -AC_SUBST([LTDLDEPS]) -AC_SUBST([LTDLINCL]) - -# For backwards non-gettext consistent compatibility... -INCLTDL=$LTDLINCL -AC_SUBST([INCLTDL]) -])# LTDL_INSTALLABLE - - -# _LTDL_MODE_DISPATCH -# ------------------- -m4_define([_LTDL_MODE_DISPATCH], -[dnl If _LTDL_DIR is '.', then we are configuring libltdl itself: -m4_if(_LTDL_DIR, [], - [], - dnl if _LTDL_MODE was not set already, the default value is 'subproject': - [m4_case(m4_default(_LTDL_MODE, [subproject]), - [subproject], [AC_CONFIG_SUBDIRS(_LTDL_DIR) - _LT_SHELL_INIT([lt_dlopen_dir=$lt_ltdl_dir])], - [nonrecursive], [_LT_SHELL_INIT([lt_dlopen_dir=$lt_ltdl_dir; lt_libobj_prefix=$lt_ltdl_dir/])], - [recursive], [], - [m4_fatal([unknown libltdl mode: ]_LTDL_MODE)])])dnl -dnl Be careful not to expand twice: -m4_define([$0], []) -])# _LTDL_MODE_DISPATCH - - -# _LT_LIBOBJ(MODULE_NAME) -# ----------------------- -# Like AC_LIBOBJ, except that MODULE_NAME goes into _LT_LIBOBJS instead -# of into LIBOBJS. -AC_DEFUN([_LT_LIBOBJ], [ - m4_pattern_allow([^_LT_LIBOBJS$]) - _LT_LIBOBJS="$_LT_LIBOBJS $1.$ac_objext" -])# _LT_LIBOBJS - - -# LTDL_INIT([OPTIONS]) -# -------------------- -# Clients of libltdl can use this macro to allow the installer to -# choose between a shipped copy of the ltdl sources or a preinstalled -# version of the library. If the shipped ltdl sources are not in a -# subdirectory named libltdl, the directory name must be given by -# LT_CONFIG_LTDL_DIR. -AC_DEFUN([LTDL_INIT], -[dnl Parse OPTIONS -_LT_SET_OPTIONS([$0], [$1]) - -dnl We need to keep our own list of libobjs separate from our parent project, -dnl and the easiest way to do that is redefine the AC_LIBOBJs macro while -dnl we look for our own LIBOBJs. -m4_pushdef([AC_LIBOBJ], m4_defn([_LT_LIBOBJ])) -m4_pushdef([AC_LIBSOURCES]) - -dnl If not otherwise defined, default to the 1.5.x compatible subproject mode: -m4_if(_LTDL_MODE, [], - [m4_define([_LTDL_MODE], m4_default([$2], [subproject])) - m4_if([-1], [m4_bregexp(_LTDL_MODE, [\(subproject\|\(non\)?recursive\)])], - [m4_fatal([unknown libltdl mode: ]_LTDL_MODE)])]) - -AC_ARG_WITH([included_ltdl], - [AS_HELP_STRING([--with-included-ltdl], - [use the GNU ltdl sources included here])]) - -if test yes != "$with_included_ltdl"; then - # We are not being forced to use the included libltdl sources, so - # decide whether there is a useful installed version we can use. - AC_CHECK_HEADER([ltdl.h], - [AC_CHECK_DECL([lt_dlinterface_register], - [AC_CHECK_LIB([ltdl], [lt_dladvise_preload], - [with_included_ltdl=no], - [with_included_ltdl=yes])], - [with_included_ltdl=yes], - [AC_INCLUDES_DEFAULT - #include ])], - [with_included_ltdl=yes], - [AC_INCLUDES_DEFAULT] - ) -fi - -dnl If neither LT_CONFIG_LTDL_DIR, LTDL_CONVENIENCE nor LTDL_INSTALLABLE -dnl was called yet, then for old times' sake, we assume libltdl is in an -dnl eponymous directory: -AC_PROVIDE_IFELSE([LT_CONFIG_LTDL_DIR], [], [_LT_CONFIG_LTDL_DIR([libltdl])]) - -AC_ARG_WITH([ltdl_include], - [AS_HELP_STRING([--with-ltdl-include=DIR], - [use the ltdl headers installed in DIR])]) - -if test -n "$with_ltdl_include"; then - if test -f "$with_ltdl_include/ltdl.h"; then : - else - AC_MSG_ERROR([invalid ltdl include directory: '$with_ltdl_include']) - fi -else - with_ltdl_include=no -fi - -AC_ARG_WITH([ltdl_lib], - [AS_HELP_STRING([--with-ltdl-lib=DIR], - [use the libltdl.la installed in DIR])]) - -if test -n "$with_ltdl_lib"; then - if test -f "$with_ltdl_lib/libltdl.la"; then : - else - AC_MSG_ERROR([invalid ltdl library directory: '$with_ltdl_lib']) - fi -else - with_ltdl_lib=no -fi - -case ,$with_included_ltdl,$with_ltdl_include,$with_ltdl_lib, in - ,yes,no,no,) - m4_case(m4_default(_LTDL_TYPE, [convenience]), - [convenience], [_LTDL_CONVENIENCE], - [installable], [_LTDL_INSTALLABLE], - [m4_fatal([unknown libltdl build type: ]_LTDL_TYPE)]) - ;; - ,no,no,no,) - # If the included ltdl is not to be used, then use the - # preinstalled libltdl we found. - AC_DEFINE([HAVE_LTDL], [1], - [Define this if a modern libltdl is already installed]) - LIBLTDL=-lltdl - LTDLDEPS= - LTDLINCL= - ;; - ,no*,no,*) - AC_MSG_ERROR(['--with-ltdl-include' and '--with-ltdl-lib' options must be used together]) - ;; - *) with_included_ltdl=no - LIBLTDL="-L$with_ltdl_lib -lltdl" - LTDLDEPS= - LTDLINCL=-I$with_ltdl_include - ;; -esac -INCLTDL=$LTDLINCL - -# Report our decision... -AC_MSG_CHECKING([where to find libltdl headers]) -AC_MSG_RESULT([$LTDLINCL]) -AC_MSG_CHECKING([where to find libltdl library]) -AC_MSG_RESULT([$LIBLTDL]) - -_LTDL_SETUP - -dnl restore autoconf definition. -m4_popdef([AC_LIBOBJ]) -m4_popdef([AC_LIBSOURCES]) - -AC_CONFIG_COMMANDS_PRE([ - _ltdl_libobjs= - _ltdl_ltlibobjs= - if test -n "$_LT_LIBOBJS"; then - # Remove the extension. - _lt_sed_drop_objext='s/\.o$//;s/\.obj$//' - for i in `for i in $_LT_LIBOBJS; do echo "$i"; done | $SED "$_lt_sed_drop_objext" | sort -u`; do - _ltdl_libobjs="$_ltdl_libobjs $lt_libobj_prefix$i.$ac_objext" - _ltdl_ltlibobjs="$_ltdl_ltlibobjs $lt_libobj_prefix$i.lo" - done - fi - AC_SUBST([ltdl_LIBOBJS], [$_ltdl_libobjs]) - AC_SUBST([ltdl_LTLIBOBJS], [$_ltdl_ltlibobjs]) -]) - -# Only expand once: -m4_define([LTDL_INIT]) -])# LTDL_INIT - -# Old names: -AU_DEFUN([AC_LIB_LTDL], [LTDL_INIT($@)]) -AU_DEFUN([AC_WITH_LTDL], [LTDL_INIT($@)]) -AU_DEFUN([LT_WITH_LTDL], [LTDL_INIT($@)]) -dnl aclocal-1.4 backwards compatibility: -dnl AC_DEFUN([AC_LIB_LTDL], []) -dnl AC_DEFUN([AC_WITH_LTDL], []) -dnl AC_DEFUN([LT_WITH_LTDL], []) - - -# _LTDL_SETUP -# ----------- -# Perform all the checks necessary for compilation of the ltdl objects -# -- including compiler checks and header checks. This is a public -# interface mainly for the benefit of libltdl's own configure.ac, most -# other users should call LTDL_INIT instead. -AC_DEFUN([_LTDL_SETUP], -[AC_REQUIRE([AC_PROG_CC])dnl -AC_REQUIRE([LT_SYS_MODULE_EXT])dnl -AC_REQUIRE([LT_SYS_MODULE_PATH])dnl -AC_REQUIRE([LT_SYS_DLSEARCH_PATH])dnl -AC_REQUIRE([LT_LIB_DLLOAD])dnl -AC_REQUIRE([LT_SYS_SYMBOL_USCORE])dnl -AC_REQUIRE([LT_FUNC_DLSYM_USCORE])dnl -AC_REQUIRE([LT_SYS_DLOPEN_DEPLIBS])dnl -AC_REQUIRE([LT_FUNC_ARGZ])dnl - -m4_require([_LT_CHECK_OBJDIR])dnl -m4_require([_LT_HEADER_DLFCN])dnl -m4_require([_LT_CHECK_DLPREOPEN])dnl -m4_require([_LT_DECL_SED])dnl - -dnl Don't require this, or it will be expanded earlier than the code -dnl that sets the variables it relies on: -_LT_ENABLE_INSTALL - -dnl _LTDL_MODE specific code must be called at least once: -_LTDL_MODE_DISPATCH - -# In order that ltdl.c can compile, find out the first AC_CONFIG_HEADERS -# the user used. This is so that ltdl.h can pick up the parent projects -# config.h file, The first file in AC_CONFIG_HEADERS must contain the -# definitions required by ltdl.c. -# FIXME: Remove use of undocumented AC_LIST_HEADERS (2.59 compatibility). -AC_CONFIG_COMMANDS_PRE([dnl -m4_pattern_allow([^LT_CONFIG_H$])dnl -m4_ifset([AH_HEADER], - [LT_CONFIG_H=AH_HEADER], - [m4_ifset([AC_LIST_HEADERS], - [LT_CONFIG_H=`echo "AC_LIST_HEADERS" | $SED 's|^[[ ]]*||;s|[[ :]].*$||'`], - [])])]) -AC_SUBST([LT_CONFIG_H]) - -AC_CHECK_HEADERS([unistd.h dl.h sys/dl.h dld.h mach-o/dyld.h dirent.h], - [], [], [AC_INCLUDES_DEFAULT]) - -AC_CHECK_FUNCS([closedir opendir readdir], [], [AC_LIBOBJ([lt__dirent])]) -AC_CHECK_FUNCS([strlcat strlcpy], [], [AC_LIBOBJ([lt__strl])]) - -m4_pattern_allow([LT_LIBEXT])dnl -AC_DEFINE_UNQUOTED([LT_LIBEXT],["$libext"],[The archive extension]) - -name= -eval "lt_libprefix=\"$libname_spec\"" -m4_pattern_allow([LT_LIBPREFIX])dnl -AC_DEFINE_UNQUOTED([LT_LIBPREFIX],["$lt_libprefix"],[The archive prefix]) - -name=ltdl -eval "LTDLOPEN=\"$libname_spec\"" -AC_SUBST([LTDLOPEN]) -])# _LTDL_SETUP - - -# _LT_ENABLE_INSTALL -# ------------------ -m4_define([_LT_ENABLE_INSTALL], -[AC_ARG_ENABLE([ltdl-install], - [AS_HELP_STRING([--enable-ltdl-install], [install libltdl])]) - -case ,$enable_ltdl_install,$enable_ltdl_convenience in - *yes*) ;; - *) enable_ltdl_convenience=yes ;; -esac - -m4_ifdef([AM_CONDITIONAL], -[AM_CONDITIONAL(INSTALL_LTDL, test no != "${enable_ltdl_install-no}") - AM_CONDITIONAL(CONVENIENCE_LTDL, test no != "${enable_ltdl_convenience-no}") - AM_CONDITIONAL(LTARGZH_EXISTS, test -n "$LT_ARGZ_H")]) -])# _LT_ENABLE_INSTALL - - -# LT_SYS_DLOPEN_DEPLIBS -# --------------------- -AC_DEFUN([LT_SYS_DLOPEN_DEPLIBS], -[AC_REQUIRE([AC_CANONICAL_HOST])dnl -AC_CACHE_CHECK([whether deplibs are loaded by dlopen], - [lt_cv_sys_dlopen_deplibs], - [# PORTME does your system automatically load deplibs for dlopen? - # or its logical equivalent (e.g. shl_load for HP-UX < 11) - # For now, we just catch OSes we know something about -- in the - # future, we'll try test this programmatically. - lt_cv_sys_dlopen_deplibs=unknown - case $host_os in - aix3*|aix4.1.*|aix4.2.*) - # Unknown whether this is true for these versions of AIX, but - # we want this 'case' here to explicitly catch those versions. - lt_cv_sys_dlopen_deplibs=unknown - ;; - aix[[4-9]]*) - lt_cv_sys_dlopen_deplibs=yes - ;; - amigaos*) - case $host_cpu in - powerpc) - lt_cv_sys_dlopen_deplibs=no - ;; - esac - ;; - darwin*) - # Assuming the user has installed a libdl from somewhere, this is true - # If you are looking for one http://www.opendarwin.org/projects/dlcompat - lt_cv_sys_dlopen_deplibs=yes - ;; - freebsd* | dragonfly* | midnightbsd*) - lt_cv_sys_dlopen_deplibs=yes - ;; - gnu* | linux* | k*bsd*-gnu | kopensolaris*-gnu) - # GNU and its variants, using gnu ld.so (Glibc) - lt_cv_sys_dlopen_deplibs=yes - ;; - hpux10*|hpux11*) - lt_cv_sys_dlopen_deplibs=yes - ;; - interix*) - lt_cv_sys_dlopen_deplibs=yes - ;; - irix[[12345]]*|irix6.[[01]]*) - # Catch all versions of IRIX before 6.2, and indicate that we don't - # know how it worked for any of those versions. - lt_cv_sys_dlopen_deplibs=unknown - ;; - irix*) - # The case above catches anything before 6.2, and it's known that - # at 6.2 and later dlopen does load deplibs. - lt_cv_sys_dlopen_deplibs=yes - ;; - *-mlibc) - lt_cv_sys_dlopen_deplibs=yes - ;; - netbsd* | netbsdelf*-gnu) - lt_cv_sys_dlopen_deplibs=yes - ;; - openbsd*) - lt_cv_sys_dlopen_deplibs=yes - ;; - osf[[1234]]*) - # dlopen did load deplibs (at least at 4.x), but until the 5.x series, - # it did *not* use an RPATH in a shared library to find objects the - # library depends on, so we explicitly say 'no'. - lt_cv_sys_dlopen_deplibs=no - ;; - osf5.0|osf5.0a|osf5.1) - # dlopen *does* load deplibs and with the right loader patch applied - # it even uses RPATH in a shared library to search for shared objects - # that the library depends on, but there's no easy way to know if that - # patch is installed. Since this is the case, all we can really - # say is unknown -- it depends on the patch being installed. If - # it is, this changes to 'yes'. Without it, it would be 'no'. - lt_cv_sys_dlopen_deplibs=unknown - ;; - osf*) - # the two cases above should catch all versions of osf <= 5.1. Read - # the comments above for what we know about them. - # At > 5.1, deplibs are loaded *and* any RPATH in a shared library - # is used to find them so we can finally say 'yes'. - lt_cv_sys_dlopen_deplibs=yes - ;; - qnx*) - lt_cv_sys_dlopen_deplibs=yes - ;; - solaris*) - lt_cv_sys_dlopen_deplibs=yes - ;; - sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) - libltdl_cv_sys_dlopen_deplibs=yes - ;; - esac - ]) -if test yes != "$lt_cv_sys_dlopen_deplibs"; then - AC_DEFINE([LTDL_DLOPEN_DEPLIBS], [1], - [Define if the OS needs help to load dependent libraries for dlopen().]) -fi -])# LT_SYS_DLOPEN_DEPLIBS - -# Old name: -AU_ALIAS([AC_LTDL_SYS_DLOPEN_DEPLIBS], [LT_SYS_DLOPEN_DEPLIBS]) -dnl aclocal-1.4 backwards compatibility: -dnl AC_DEFUN([AC_LTDL_SYS_DLOPEN_DEPLIBS], []) - - -# LT_SYS_MODULE_EXT -# ----------------- -AC_DEFUN([LT_SYS_MODULE_EXT], -[m4_require([_LT_SYS_DYNAMIC_LINKER])dnl -AC_CACHE_CHECK([what extension is used for runtime loadable modules], - [libltdl_cv_shlibext], -[ -module=yes -eval libltdl_cv_shlibext=$shrext_cmds -module=no -eval libltdl_cv_shrext=$shrext_cmds - ]) -if test -n "$libltdl_cv_shlibext"; then - m4_pattern_allow([LT_MODULE_EXT])dnl - AC_DEFINE_UNQUOTED([LT_MODULE_EXT], ["$libltdl_cv_shlibext"], - [Define to the extension used for runtime loadable modules, say, ".so".]) -fi -if test "$libltdl_cv_shrext" != "$libltdl_cv_shlibext"; then - m4_pattern_allow([LT_SHARED_EXT])dnl - AC_DEFINE_UNQUOTED([LT_SHARED_EXT], ["$libltdl_cv_shrext"], - [Define to the shared library suffix, say, ".dylib".]) -fi -if test -n "$shared_archive_member_spec"; then - m4_pattern_allow([LT_SHARED_LIB_MEMBER])dnl - AC_DEFINE_UNQUOTED([LT_SHARED_LIB_MEMBER], ["($shared_archive_member_spec.o)"], - [Define to the shared archive member specification, say "(shr.o)".]) -fi -])# LT_SYS_MODULE_EXT - -# Old name: -AU_ALIAS([AC_LTDL_SHLIBEXT], [LT_SYS_MODULE_EXT]) -dnl aclocal-1.4 backwards compatibility: -dnl AC_DEFUN([AC_LTDL_SHLIBEXT], []) - - -# LT_SYS_MODULE_PATH -# ------------------ -AC_DEFUN([LT_SYS_MODULE_PATH], -[m4_require([_LT_SYS_DYNAMIC_LINKER])dnl -AC_CACHE_CHECK([what variable specifies run-time module search path], - [lt_cv_module_path_var], [lt_cv_module_path_var=$shlibpath_var]) -if test -n "$lt_cv_module_path_var"; then - m4_pattern_allow([LT_MODULE_PATH_VAR])dnl - AC_DEFINE_UNQUOTED([LT_MODULE_PATH_VAR], ["$lt_cv_module_path_var"], - [Define to the name of the environment variable that determines the run-time module search path.]) -fi -])# LT_SYS_MODULE_PATH - -# Old name: -AU_ALIAS([AC_LTDL_SHLIBPATH], [LT_SYS_MODULE_PATH]) -dnl aclocal-1.4 backwards compatibility: -dnl AC_DEFUN([AC_LTDL_SHLIBPATH], []) - - -# LT_SYS_DLSEARCH_PATH -# -------------------- -AC_DEFUN([LT_SYS_DLSEARCH_PATH], -[m4_require([_LT_SYS_DYNAMIC_LINKER])dnl -AC_CACHE_CHECK([for the default library search path], - [lt_cv_sys_dlsearch_path], - [lt_cv_sys_dlsearch_path=$sys_lib_dlsearch_path_spec]) -if test -n "$lt_cv_sys_dlsearch_path"; then - sys_dlsearch_path= - for dir in $lt_cv_sys_dlsearch_path; do - if test -z "$sys_dlsearch_path"; then - sys_dlsearch_path=$dir - else - sys_dlsearch_path=$sys_dlsearch_path$PATH_SEPARATOR$dir - fi - done - m4_pattern_allow([LT_DLSEARCH_PATH])dnl - AC_DEFINE_UNQUOTED([LT_DLSEARCH_PATH], ["$sys_dlsearch_path"], - [Define to the system default library search path.]) -fi -])# LT_SYS_DLSEARCH_PATH - -# Old name: -AU_ALIAS([AC_LTDL_SYSSEARCHPATH], [LT_SYS_DLSEARCH_PATH]) -dnl aclocal-1.4 backwards compatibility: -dnl AC_DEFUN([AC_LTDL_SYSSEARCHPATH], []) - - -# _LT_CHECK_DLPREOPEN -# ------------------- -m4_defun([_LT_CHECK_DLPREOPEN], -[m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl -AC_CACHE_CHECK([whether libtool supports -dlopen/-dlpreopen], - [libltdl_cv_preloaded_symbols], - [if test -n "$lt_cv_sys_global_symbol_pipe"; then - libltdl_cv_preloaded_symbols=yes - else - libltdl_cv_preloaded_symbols=no - fi - ]) -if test yes = "$libltdl_cv_preloaded_symbols"; then - AC_DEFINE([HAVE_PRELOADED_SYMBOLS], [1], - [Define if libtool can extract symbol lists from object files.]) -fi -])# _LT_CHECK_DLPREOPEN - - -# LT_LIB_DLLOAD -# ------------- -AC_DEFUN([LT_LIB_DLLOAD], -[m4_pattern_allow([^LT_DLLOADERS$]) -LT_DLLOADERS= -AC_SUBST([LT_DLLOADERS]) - -AC_LANG_PUSH([C]) -lt_dlload_save_LIBS=$LIBS - -LIBADD_DLOPEN= -AC_SEARCH_LIBS([dlopen], [dl], - [AC_DEFINE([HAVE_LIBDL], [1], - [Define if you have the libdl library or equivalent.]) - if test "$ac_cv_search_dlopen" != "none required"; then - LIBADD_DLOPEN=-ldl - fi - libltdl_cv_lib_dl_dlopen=yes - LT_DLLOADERS="$LT_DLLOADERS ${lt_dlopen_dir+$lt_dlopen_dir/}dlopen.la"], - [AC_LINK_IFELSE([AC_LANG_PROGRAM([[#if HAVE_DLFCN_H -# include -#endif - ]], [[dlopen(0, 0);]])], - [AC_DEFINE([HAVE_LIBDL], [1], - [Define if you have the libdl library or equivalent.]) - libltdl_cv_func_dlopen=yes - LT_DLLOADERS="$LT_DLLOADERS ${lt_dlopen_dir+$lt_dlopen_dir/}dlopen.la"], - [AC_CHECK_LIB([svld], [dlopen], - [AC_DEFINE([HAVE_LIBDL], [1], - [Define if you have the libdl library or equivalent.]) - LIBADD_DLOPEN=-lsvld libltdl_cv_func_dlopen=yes - LT_DLLOADERS="$LT_DLLOADERS ${lt_dlopen_dir+$lt_dlopen_dir/}dlopen.la"])])]) -if test yes = "$libltdl_cv_func_dlopen" || test yes = "$libltdl_cv_lib_dl_dlopen" -then - lt_save_LIBS=$LIBS - LIBS="$LIBS $LIBADD_DLOPEN" - AC_CHECK_FUNCS([dlerror]) - LIBS=$lt_save_LIBS -fi -AC_SUBST([LIBADD_DLOPEN]) - -LIBADD_SHL_LOAD= -AC_CHECK_FUNC([shl_load], - [AC_DEFINE([HAVE_SHL_LOAD], [1], - [Define if you have the shl_load function.]) - LT_DLLOADERS="$LT_DLLOADERS ${lt_dlopen_dir+$lt_dlopen_dir/}shl_load.la"], - [AC_CHECK_LIB([dld], [shl_load], - [AC_DEFINE([HAVE_SHL_LOAD], [1], - [Define if you have the shl_load function.]) - LT_DLLOADERS="$LT_DLLOADERS ${lt_dlopen_dir+$lt_dlopen_dir/}shl_load.la" - LIBADD_SHL_LOAD=-ldld])]) -AC_SUBST([LIBADD_SHL_LOAD]) - -case $host_os in -darwin[[1567]].*) -# We only want this for pre-Mac OS X 10.4. - AC_CHECK_FUNC([_dyld_func_lookup], - [AC_DEFINE([HAVE_DYLD], [1], - [Define if you have the _dyld_func_lookup function.]) - LT_DLLOADERS="$LT_DLLOADERS ${lt_dlopen_dir+$lt_dlopen_dir/}dyld.la"]) - ;; -beos*) - LT_DLLOADERS="$LT_DLLOADERS ${lt_dlopen_dir+$lt_dlopen_dir/}load_add_on.la" - ;; -cygwin* | mingw* | windows* | pw32*) - AC_CHECK_DECLS([cygwin_conv_path], [], [], [[#include ]]) - LT_DLLOADERS="$LT_DLLOADERS ${lt_dlopen_dir+$lt_dlopen_dir/}loadlibrary.la" - ;; -esac - -AC_CHECK_LIB([dld], [dld_link], - [AC_DEFINE([HAVE_DLD], [1], - [Define if you have the GNU dld library.]) - LT_DLLOADERS="$LT_DLLOADERS ${lt_dlopen_dir+$lt_dlopen_dir/}dld_link.la"]) -AC_SUBST([LIBADD_DLD_LINK]) - -m4_pattern_allow([^LT_DLPREOPEN$]) -LT_DLPREOPEN= -if test -n "$LT_DLLOADERS" -then - for lt_loader in $LT_DLLOADERS; do - LT_DLPREOPEN="$LT_DLPREOPEN-dlpreopen $lt_loader " - done - AC_DEFINE([HAVE_LIBDLLOADER], [1], - [Define if libdlloader will be built on this platform]) -fi -AC_SUBST([LT_DLPREOPEN]) - -dnl This isn't used anymore, but set it for backwards compatibility -LIBADD_DL="$LIBADD_DLOPEN $LIBADD_SHL_LOAD" -AC_SUBST([LIBADD_DL]) - -LIBS=$lt_dlload_save_LIBS -AC_LANG_POP -])# LT_LIB_DLLOAD - -# Old name: -AU_ALIAS([AC_LTDL_DLLIB], [LT_LIB_DLLOAD]) -dnl aclocal-1.4 backwards compatibility: -dnl AC_DEFUN([AC_LTDL_DLLIB], []) - - -# LT_SYS_SYMBOL_USCORE -# -------------------- -# does the compiler prefix global symbols with an underscore? -AC_DEFUN([LT_SYS_SYMBOL_USCORE], -[m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl -AC_CACHE_CHECK([for _ prefix in compiled symbols], - [lt_cv_sys_symbol_underscore], - [lt_cv_sys_symbol_underscore=no - cat > conftest.$ac_ext <<_LT_EOF -void nm_test_func(){} -int main(void){nm_test_func;return 0;} -_LT_EOF - if AC_TRY_EVAL(ac_compile); then - # Now try to grab the symbols. - ac_nlist=conftest.nm - if AC_TRY_EVAL(NM conftest.$ac_objext \| $lt_cv_sys_global_symbol_pipe \> $ac_nlist) && test -s "$ac_nlist"; then - # See whether the symbols have a leading underscore. - if grep '^. _nm_test_func' "$ac_nlist" >/dev/null; then - lt_cv_sys_symbol_underscore=yes - else - if grep '^. nm_test_func ' "$ac_nlist" >/dev/null; then - : - else - echo "configure: cannot find nm_test_func in $ac_nlist" >&AS_MESSAGE_LOG_FD - fi - fi - else - echo "configure: cannot run $lt_cv_sys_global_symbol_pipe" >&AS_MESSAGE_LOG_FD - fi - else - echo "configure: failed program was:" >&AS_MESSAGE_LOG_FD - cat conftest.c >&AS_MESSAGE_LOG_FD - fi - rm -rf conftest* - ]) - sys_symbol_underscore=$lt_cv_sys_symbol_underscore - AC_SUBST([sys_symbol_underscore]) -])# LT_SYS_SYMBOL_USCORE - -# Old name: -AU_ALIAS([AC_LTDL_SYMBOL_USCORE], [LT_SYS_SYMBOL_USCORE]) -dnl aclocal-1.4 backwards compatibility: -dnl AC_DEFUN([AC_LTDL_SYMBOL_USCORE], []) - - -# LT_FUNC_DLSYM_USCORE -# -------------------- -AC_DEFUN([LT_FUNC_DLSYM_USCORE], -[AC_REQUIRE([_LT_COMPILER_PIC])dnl for lt_prog_compiler_wl -AC_REQUIRE([LT_SYS_SYMBOL_USCORE])dnl for lt_cv_sys_symbol_underscore -AC_REQUIRE([LT_SYS_MODULE_EXT])dnl for libltdl_cv_shlibext -if test yes = "$lt_cv_sys_symbol_underscore"; then - if test yes = "$libltdl_cv_func_dlopen" || test yes = "$libltdl_cv_lib_dl_dlopen"; then - AC_CACHE_CHECK([whether we have to add an underscore for dlsym], - [libltdl_cv_need_uscore], - [libltdl_cv_need_uscore=unknown - dlsym_uscore_save_LIBS=$LIBS - LIBS="$LIBS $LIBADD_DLOPEN" - libname=conftmod # stay within 8.3 filename limits! - cat >$libname.$ac_ext <<_LT_EOF -[#line $LINENO "configure" -#include "confdefs.h" -/* When -fvisibility=hidden is used, assume the code has been annotated - correspondingly for the symbols needed. */ -#if defined __GNUC__ && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)) -int fnord () __attribute__((visibility("default"))); -#endif -int fnord () { return 42; }] -_LT_EOF - - # ltfn_module_cmds module_cmds - # Execute tilde-delimited MODULE_CMDS with environment primed for - # $module_cmds or $archive_cmds type content. - ltfn_module_cmds () - {( # subshell avoids polluting parent global environment - module_cmds_save_ifs=$IFS; IFS='~' - for cmd in @S|@1; do - IFS=$module_cmds_save_ifs - libobjs=$libname.$ac_objext; lib=$libname$libltdl_cv_shlibext - rpath=/not-exists; soname=$libname$libltdl_cv_shlibext; output_objdir=. - major=; versuffix=; verstring=; deplibs= - ECHO=echo; wl=$lt_prog_compiler_wl; allow_undefined_flag= - eval $cmd - done - IFS=$module_cmds_save_ifs - )} - - # Compile a loadable module using libtool macro expansion results. - $CC $pic_flag -c $libname.$ac_ext - ltfn_module_cmds "${module_cmds:-$archive_cmds}" - - # Try to fetch fnord with dlsym(). - libltdl_dlunknown=0; libltdl_dlnouscore=1; libltdl_dluscore=2 - cat >conftest.$ac_ext <<_LT_EOF -[#line $LINENO "configure" -#include "confdefs.h" -#if HAVE_DLFCN_H -#include -#endif -#include -#ifndef RTLD_GLOBAL -# ifdef DL_GLOBAL -# define RTLD_GLOBAL DL_GLOBAL -# else -# define RTLD_GLOBAL 0 -# endif -#endif -#ifndef RTLD_NOW -# ifdef DL_NOW -# define RTLD_NOW DL_NOW -# else -# define RTLD_NOW 0 -# endif -#endif -int main (void) { - void *handle = dlopen ("`pwd`/$libname$libltdl_cv_shlibext", RTLD_GLOBAL|RTLD_NOW); - int status = $libltdl_dlunknown; - if (handle) { - if (dlsym (handle, "fnord")) - status = $libltdl_dlnouscore; - else { - if (dlsym (handle, "_fnord")) - status = $libltdl_dluscore; - else - puts (dlerror ()); - } - dlclose (handle); - } else - puts (dlerror ()); - return status; -}] -_LT_EOF - if AC_TRY_EVAL(ac_link) && test -s "conftest$ac_exeext" 2>/dev/null; then - (./conftest; exit; ) >&AS_MESSAGE_LOG_FD 2>/dev/null - libltdl_status=$? - case x$libltdl_status in - x$libltdl_dlnouscore) libltdl_cv_need_uscore=no ;; - x$libltdl_dluscore) libltdl_cv_need_uscore=yes ;; - x*) libltdl_cv_need_uscore=unknown ;; - esac - fi - rm -rf conftest* $libname* - LIBS=$dlsym_uscore_save_LIBS - ]) - fi -fi - -if test yes = "$libltdl_cv_need_uscore"; then - AC_DEFINE([NEED_USCORE], [1], - [Define if dlsym() requires a leading underscore in symbol names.]) -fi -])# LT_FUNC_DLSYM_USCORE - -# Old name: -AU_ALIAS([AC_LTDL_DLSYM_USCORE], [LT_FUNC_DLSYM_USCORE]) -dnl aclocal-1.4 backwards compatibility: -dnl AC_DEFUN([AC_LTDL_DLSYM_USCORE], []) - # pkg.m4 - Macros to locate and use pkg-config. -*- Autoconf -*- # serial 12 (pkg-config-0.29.2) @@ -2741,6 +1751,8 @@ m4_include([m4/ax_boost_base.m4]) m4_include([m4/ax_boost_thread.m4]) m4_include([m4/ax_cxx_compile_stdcxx.m4]) m4_include([m4/libtool.m4]) +m4_include([m4/ltargz.m4]) +m4_include([m4/ltdl.m4]) m4_include([m4/ltoptions.m4]) m4_include([m4/ltsugar.m4]) m4_include([m4/ltversion.m4]) diff --git a/doc/cservice.update.sql b/doc/cservice.update.sql index e9d2a60c..3ae697e1 100644 --- a/doc/cservice.update.sql +++ b/doc/cservice.update.sql @@ -116,13 +116,9 @@ CREATE TABLE users_fingerprints ( ); ALTER TABLE users - ADD COLUMN scram_record TEXT; - -ALTER TABLE users + ADD COLUMN scram_record TEXT, ALTER COLUMN flags TYPE INT4; -INSERT INTO translations (language_id, response_id, text, last_updated) VALUES(1, 197, 'Your AUTOHIDE setting is now ON.', 31337); -INSERT INTO translations (language_id, response_id, text, last_updated) VALUES(1, 198, 'Your AUTOHIDE setting is now OFF.', 31337); INSERT INTO translations (language_id, response_id, text, last_updated) VALUES(1, 195, 'Your CERTONLY setting is now ON.', 31337); INSERT INTO translations (language_id, response_id, text, last_updated) VALUES(1, 196, 'Your CERTONLY setting is now OFF.', 31337); INSERT INTO translations (language_id, response_id, text, last_updated) VALUES(1, 197, 'Your AUTOHIDE setting is now ON.', 31337); @@ -139,3 +135,5 @@ INSERT INTO translations (language_id, response_id, text, last_updated) VALUES(1 INSERT INTO translations (language_id, response_id, text, last_updated) VALUES(1, 234, 'That fingerprint was not found on your username.', 31337); INSERT INTO help VALUES ('CERT', '1', E'/msg X cert [fingerprint] [note]\nThis command allows you to add, remove and list TLS fingerprints added to your username.\nBy connecting to Undernet using TLS and a certificate, you may login to X without using a password if the certificate''s fingerprint has been added to your username.\nTo login to X with a fingerprint, use ''/msg X@channels.undernet.org login [TOTP token]''.\nUsing CERT ADD or REM without specifying a fingerprint will add or remove the fingerprint you are currently connected with (if any).\nA specified fingerprint must be in a SHA-256 format (i.e. AB:CD:12:ED:34 ...).\nWhen having a fingerprint added to your account, you may deactivate password login on IRC using ''SET CERTONLY ON/OFF''. You will still be able to login to the website with your password.'); +INSERT INTO help VALUES ('SET CERTONLY', '1', E'/msg X set CERTONLY \nThis command allows you to enable or disable CERTONLY mode on your username.\nWhen CERTONLY is enabled, you will only be able to login to X using a TLS certificate that has a fingerprint added to your username. Password logins will be disabled while this setting is ON.\nYou must have at least one fingerprint added to your username before enabling CERTONLY.'); +INSERT INTO help VALUES ('SET AUTOHIDE', '1', E'/msg X set AUTOHIDE \nThis command allows you to enable or disable AUTOHIDE mode on your username.\nWhen AUTOHIDE is enabled, you will receive usermode +x automatically upon authenticating with X resulting in your real hostmask being hidden to other users.'); diff --git a/libltdl/Makefile.in b/libltdl/Makefile.in index d038af0c..5b34f616 100644 --- a/libltdl/Makefile.in +++ b/libltdl/Makefile.in @@ -100,6 +100,7 @@ host_triplet = @host@ subdir = . ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/../m4/libtool.m4 \ + $(top_srcdir)/../m4/ltargz.m4 $(top_srcdir)/../m4/ltdl.m4 \ $(top_srcdir)/../m4/ltoptions.m4 \ $(top_srcdir)/../m4/ltsugar.m4 \ $(top_srcdir)/../m4/ltversion.m4 \ @@ -111,7 +112,7 @@ DIST_COMMON = $(srcdir)/Makefile.am $(top_srcdir)/configure \ $(am__ltdlinclude_HEADERS_DIST) $(am__DIST_COMMON) am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ configure.lineno config.status.lineno -mkinstalldirs = $(SHELL) $(top_srcdir)/../mkinstalldirs +mkinstalldirs = $(install_sh) -d CONFIG_HEADER = config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = @@ -295,15 +296,18 @@ am__define_uniq_tagged_files = \ done | $(am__uniquify_input)` AM_RECURSIVE_TARGETS = cscope am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/config-h.in \ - $(top_srcdir)/../compile $(top_srcdir)/../config.guess \ - $(top_srcdir)/../config.sub $(top_srcdir)/../depcomp \ - $(top_srcdir)/../install-sh $(top_srcdir)/../ltmain.sh \ - $(top_srcdir)/../missing $(top_srcdir)/../mkinstalldirs \ - ../AUTHORS ../COPYING ../ChangeLog ../INSTALL ../NEWS \ - ../README ../TODO ../ar-lib ../compile ../config.guess \ - ../config.sub ../depcomp ../install-sh ../ltconfig \ - ../ltmain.sh ../missing ../mkinstalldirs COPYING.LIB README \ - lt__argz.c lt__dirent.c lt__strl.c + $(top_srcdir)/../compile \ + $(top_srcdir)/../config.guess \ + $(top_srcdir)/../config.sub \ + $(top_srcdir)/../depcomp \ + $(top_srcdir)/../install-sh \ + $(top_srcdir)/../ltmain.sh \ + $(top_srcdir)/../missing ../compile \ + ../config.guess ../config.sub \ + ../depcomp ../install-sh \ + ../ltmain.sh \ + ../missing COPYING.LIB \ + README lt__argz.c lt__dirent.c lt__strl.c DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) distdir = $(PACKAGE)-$(VERSION) top_distdir = $(distdir) diff --git a/libltdl/aclocal.m4 b/libltdl/aclocal.m4 index 3b421f5c..c6c322f5 100644 --- a/libltdl/aclocal.m4 +++ b/libltdl/aclocal.m4 @@ -20,996 +20,6 @@ You have another version of autoconf. It may work, but is not guaranteed to. If you have problems, you may need to regenerate the build system entirely. To do so, use the procedure documented by the package, typically 'autoreconf'.])]) -# Portability macros for glibc argz. -*- Autoconf -*- -# -# Copyright (C) 2004-2007, 2011-2019, 2021-2024 Free Software -# Foundation, Inc. -# Written by Gary V. Vaughan -# -# This file is free software; the Free Software Foundation gives -# unlimited permission to copy and/or distribute it, with or without -# modifications, as long as this notice is preserved. - -# serial 2 ltargz.m4 - -AC_DEFUN([LT_FUNC_ARGZ], [ -dnl Required for use of '$SED' in Cygwin configuration. -AC_REQUIRE([AC_PROG_SED])dnl -AC_CHECK_HEADERS([argz.h], [], [], [AC_INCLUDES_DEFAULT]) - -AC_CHECK_TYPES([error_t], - [], - [AC_DEFINE([error_t], [int], - [Define to a type to use for 'error_t' if it is not otherwise available.]) - AC_DEFINE([__error_t_defined], [1], [Define so that glibc/gnulib argp.h - does not typedef error_t.])], - [#if defined(HAVE_ARGZ_H) -# include -#endif]) - -LT_ARGZ_H= -AC_CHECK_FUNCS([argz_add argz_append argz_count argz_create_sep argz_insert \ - argz_next argz_stringify], [], [LT_ARGZ_H=lt__argz.h; AC_LIBOBJ([lt__argz])]) - -dnl if have system argz functions, allow forced use of -dnl libltdl-supplied implementation (and default to do so -dnl on "known bad" systems). Could use a runtime check, but -dnl (a) detecting malloc issues is notoriously unreliable -dnl (b) only known system that declares argz functions, -dnl provides them, yet they are broken, is cygwin -dnl releases prior to 16-Mar-2007 (1.5.24 and earlier) -dnl So, it's more straightforward simply to special case -dnl this for known bad systems. -AS_IF([test -z "$LT_ARGZ_H"], - [AC_CACHE_CHECK( - [if argz actually works], - [lt_cv_sys_argz_works], - [[case $host_os in #( - *cygwin*) - lt_cv_sys_argz_works=no - if test no != "$cross_compiling"; then - lt_cv_sys_argz_works="guessing no" - else - lt_sed_extract_leading_digits='s/^\([0-9\.]*\).*/\1/' - save_IFS=$IFS - IFS=-. - set x `uname -r | $SED -e "$lt_sed_extract_leading_digits"` - IFS=$save_IFS - lt_os_major=${2-0} - lt_os_minor=${3-0} - lt_os_micro=${4-0} - if test 1 -lt "$lt_os_major" \ - || { test 1 -eq "$lt_os_major" \ - && { test 5 -lt "$lt_os_minor" \ - || { test 5 -eq "$lt_os_minor" \ - && test 24 -lt "$lt_os_micro"; }; }; }; then - lt_cv_sys_argz_works=yes - fi - fi - ;; #( - *) lt_cv_sys_argz_works=yes ;; - esac]]) - AS_IF([test yes = "$lt_cv_sys_argz_works"], - [AC_DEFINE([HAVE_WORKING_ARGZ], 1, - [This value is set to 1 to indicate that the system argz facility works])], - [LT_ARGZ_H=lt__argz.h - AC_LIBOBJ([lt__argz])])]) - -AC_SUBST([LT_ARGZ_H]) -]) - -# ltdl.m4 - Configure ltdl for the target system. -*-Autoconf-*- -# -# Copyright (C) 1999-2008, 2011-2019, 2021-2024 Free Software -# Foundation, Inc. -# Written by Thomas Tanner, 1999 -# -# This file is free software; the Free Software Foundation gives -# unlimited permission to copy and/or distribute it, with or without -# modifications, as long as this notice is preserved. - -# serial 24 LTDL_INIT - -# LT_CONFIG_LTDL_DIR(DIRECTORY, [LTDL-MODE]) -# ------------------------------------------ -# DIRECTORY contains the libltdl sources. It is okay to call this -# function multiple times, as long as the same DIRECTORY is always given. -AC_DEFUN([LT_CONFIG_LTDL_DIR], -[AC_BEFORE([$0], [LTDL_INIT]) -_$0($*) -])# LT_CONFIG_LTDL_DIR - -# We break this out into a separate macro, so that we can call it safely -# internally without being caught accidentally by the sed scan in libtoolize. -m4_defun([_LT_CONFIG_LTDL_DIR], -[dnl remove trailing slashes -m4_pushdef([_ARG_DIR], m4_bpatsubst([$1], [/*$])) -m4_case(_LTDL_DIR, - [], [dnl only set lt_ltdl_dir if _ARG_DIR is not simply '.' - m4_if(_ARG_DIR, [.], - [], - [m4_define([_LTDL_DIR], _ARG_DIR) - _LT_SHELL_INIT([lt_ltdl_dir=']_ARG_DIR['])])], - [m4_if(_ARG_DIR, _LTDL_DIR, - [], - [m4_fatal([multiple libltdl directories: ']_LTDL_DIR[', ']_ARG_DIR['])])]) -m4_popdef([_ARG_DIR]) -])# _LT_CONFIG_LTDL_DIR - -# Initialise: -m4_define([_LTDL_DIR], []) - - -# _LT_BUILD_PREFIX -# ---------------- -# If Autoconf is new enough, expand to '$(top_build_prefix)', otherwise -# to '$(top_builddir)/'. -m4_define([_LT_BUILD_PREFIX], -[m4_ifdef([AC_AUTOCONF_VERSION], - [m4_if(m4_version_compare(m4_defn([AC_AUTOCONF_VERSION]), [2.62]), - [-1], [m4_ifdef([_AC_HAVE_TOP_BUILD_PREFIX], - [$(top_build_prefix)], - [$(top_builddir)/])], - [$(top_build_prefix)])], - [$(top_builddir)/])[]dnl -]) - - -# LTDL_CONVENIENCE -# ---------------- -# sets LIBLTDL to the link flags for the libltdl convenience library and -# LTDLINCL to the include flags for the libltdl header and adds -# --enable-ltdl-convenience to the configure arguments. Note that -# AC_CONFIG_SUBDIRS is not called here. LIBLTDL will be prefixed with -# '$(top_build_prefix)' if available, otherwise with '$(top_builddir)/', -# and LTDLINCL will be prefixed with '$(top_srcdir)/' (note the single -# quotes!). If your package is not flat and you're not using automake, -# define top_build_prefix, top_builddir, and top_srcdir appropriately -# in your Makefiles. -AC_DEFUN([LTDL_CONVENIENCE], -[AC_BEFORE([$0], [LTDL_INIT])dnl -dnl Although the argument is deprecated and no longer documented, -dnl LTDL_CONVENIENCE used to take a DIRECTORY orgument, if we have one -dnl here make sure it is the same as any other declaration of libltdl's -dnl location! This also ensures lt_ltdl_dir is set when configure.ac is -dnl not yet using an explicit LT_CONFIG_LTDL_DIR. -m4_ifval([$1], [_LT_CONFIG_LTDL_DIR([$1])])dnl -_$0() -])# LTDL_CONVENIENCE - -# AC_LIBLTDL_CONVENIENCE accepted a directory argument in older libtools, -# now we have LT_CONFIG_LTDL_DIR: -AU_DEFUN([AC_LIBLTDL_CONVENIENCE], -[_LT_CONFIG_LTDL_DIR([m4_default([$1], [libltdl])]) -_LTDL_CONVENIENCE]) - -dnl aclocal-1.4 backwards compatibility: -dnl AC_DEFUN([AC_LIBLTDL_CONVENIENCE], []) - - -# _LTDL_CONVENIENCE -# ----------------- -# Code shared by LTDL_CONVENIENCE and LTDL_INIT([convenience]). -m4_defun([_LTDL_CONVENIENCE], -[case $enable_ltdl_convenience in - no) AC_MSG_ERROR([this package needs a convenience libltdl]) ;; - "") enable_ltdl_convenience=yes - ac_configure_args="$ac_configure_args --enable-ltdl-convenience" ;; -esac -LIBLTDL='_LT_BUILD_PREFIX'"${lt_ltdl_dir+$lt_ltdl_dir/}libltdlc.la" -LTDLDEPS=$LIBLTDL -LTDLINCL='-I$(top_srcdir)'"${lt_ltdl_dir+/$lt_ltdl_dir}" - -AC_SUBST([LIBLTDL]) -AC_SUBST([LTDLDEPS]) -AC_SUBST([LTDLINCL]) - -# For backwards non-gettext consistent compatibility... -INCLTDL=$LTDLINCL -AC_SUBST([INCLTDL]) -])# _LTDL_CONVENIENCE - - -# LTDL_INSTALLABLE -# ---------------- -# sets LIBLTDL to the link flags for the libltdl installable library -# and LTDLINCL to the include flags for the libltdl header and adds -# --enable-ltdl-install to the configure arguments. Note that -# AC_CONFIG_SUBDIRS is not called from here. If an installed libltdl -# is not found, LIBLTDL will be prefixed with '$(top_build_prefix)' if -# available, otherwise with '$(top_builddir)/', and LTDLINCL will be -# prefixed with '$(top_srcdir)/' (note the single quotes!). If your -# package is not flat and you're not using automake, define top_build_prefix, -# top_builddir, and top_srcdir appropriately in your Makefiles. -# In the future, this macro may have to be called after LT_INIT. -AC_DEFUN([LTDL_INSTALLABLE], -[AC_BEFORE([$0], [LTDL_INIT])dnl -dnl Although the argument is deprecated and no longer documented, -dnl LTDL_INSTALLABLE used to take a DIRECTORY orgument, if we have one -dnl here make sure it is the same as any other declaration of libltdl's -dnl location! This also ensures lt_ltdl_dir is set when configure.ac is -dnl not yet using an explicit LT_CONFIG_LTDL_DIR. -m4_ifval([$1], [_LT_CONFIG_LTDL_DIR([$1])])dnl -_$0() -])# LTDL_INSTALLABLE - -# AC_LIBLTDL_INSTALLABLE accepted a directory argument in older libtools, -# now we have LT_CONFIG_LTDL_DIR: -AU_DEFUN([AC_LIBLTDL_INSTALLABLE], -[_LT_CONFIG_LTDL_DIR([m4_default([$1], [libltdl])]) -_LTDL_INSTALLABLE]) - -dnl aclocal-1.4 backwards compatibility: -dnl AC_DEFUN([AC_LIBLTDL_INSTALLABLE], []) - - -# _LTDL_INSTALLABLE -# ----------------- -# Code shared by LTDL_INSTALLABLE and LTDL_INIT([installable]). -m4_defun([_LTDL_INSTALLABLE], -[if test -f "$prefix/lib/libltdl.la"; then - lt_save_LDFLAGS=$LDFLAGS - LDFLAGS="-L$prefix/lib $LDFLAGS" - AC_CHECK_LIB([ltdl], [lt_dlinit], [lt_lib_ltdl=yes]) - LDFLAGS=$lt_save_LDFLAGS - if test yes = "${lt_lib_ltdl-no}"; then - if test yes != "$enable_ltdl_install"; then - # Don't overwrite $prefix/lib/libltdl.la without --enable-ltdl-install - AC_MSG_WARN([not overwriting libltdl at $prefix, force with '--enable-ltdl-install']) - enable_ltdl_install=no - fi - elif test no = "$enable_ltdl_install"; then - AC_MSG_WARN([libltdl not installed, but installation disabled]) - fi -fi - -# If configure.ac declared an installable ltdl, and the user didn't override -# with --disable-ltdl-install, we will install the shipped libltdl. -case $enable_ltdl_install in - no) ac_configure_args="$ac_configure_args --enable-ltdl-install=no" - LIBLTDL=-lltdl - LTDLDEPS= - LTDLINCL= - ;; - *) enable_ltdl_install=yes - ac_configure_args="$ac_configure_args --enable-ltdl-install" - LIBLTDL='_LT_BUILD_PREFIX'"${lt_ltdl_dir+$lt_ltdl_dir/}libltdl.la" - LTDLDEPS=$LIBLTDL - LTDLINCL='-I$(top_srcdir)'"${lt_ltdl_dir+/$lt_ltdl_dir}" - ;; -esac - -AC_SUBST([LIBLTDL]) -AC_SUBST([LTDLDEPS]) -AC_SUBST([LTDLINCL]) - -# For backwards non-gettext consistent compatibility... -INCLTDL=$LTDLINCL -AC_SUBST([INCLTDL]) -])# LTDL_INSTALLABLE - - -# _LTDL_MODE_DISPATCH -# ------------------- -m4_define([_LTDL_MODE_DISPATCH], -[dnl If _LTDL_DIR is '.', then we are configuring libltdl itself: -m4_if(_LTDL_DIR, [], - [], - dnl if _LTDL_MODE was not set already, the default value is 'subproject': - [m4_case(m4_default(_LTDL_MODE, [subproject]), - [subproject], [AC_CONFIG_SUBDIRS(_LTDL_DIR) - _LT_SHELL_INIT([lt_dlopen_dir=$lt_ltdl_dir])], - [nonrecursive], [_LT_SHELL_INIT([lt_dlopen_dir=$lt_ltdl_dir; lt_libobj_prefix=$lt_ltdl_dir/])], - [recursive], [], - [m4_fatal([unknown libltdl mode: ]_LTDL_MODE)])])dnl -dnl Be careful not to expand twice: -m4_define([$0], []) -])# _LTDL_MODE_DISPATCH - - -# _LT_LIBOBJ(MODULE_NAME) -# ----------------------- -# Like AC_LIBOBJ, except that MODULE_NAME goes into _LT_LIBOBJS instead -# of into LIBOBJS. -AC_DEFUN([_LT_LIBOBJ], [ - m4_pattern_allow([^_LT_LIBOBJS$]) - _LT_LIBOBJS="$_LT_LIBOBJS $1.$ac_objext" -])# _LT_LIBOBJS - - -# LTDL_INIT([OPTIONS]) -# -------------------- -# Clients of libltdl can use this macro to allow the installer to -# choose between a shipped copy of the ltdl sources or a preinstalled -# version of the library. If the shipped ltdl sources are not in a -# subdirectory named libltdl, the directory name must be given by -# LT_CONFIG_LTDL_DIR. -AC_DEFUN([LTDL_INIT], -[dnl Parse OPTIONS -_LT_SET_OPTIONS([$0], [$1]) - -dnl We need to keep our own list of libobjs separate from our parent project, -dnl and the easiest way to do that is redefine the AC_LIBOBJs macro while -dnl we look for our own LIBOBJs. -m4_pushdef([AC_LIBOBJ], m4_defn([_LT_LIBOBJ])) -m4_pushdef([AC_LIBSOURCES]) - -dnl If not otherwise defined, default to the 1.5.x compatible subproject mode: -m4_if(_LTDL_MODE, [], - [m4_define([_LTDL_MODE], m4_default([$2], [subproject])) - m4_if([-1], [m4_bregexp(_LTDL_MODE, [\(subproject\|\(non\)?recursive\)])], - [m4_fatal([unknown libltdl mode: ]_LTDL_MODE)])]) - -AC_ARG_WITH([included_ltdl], - [AS_HELP_STRING([--with-included-ltdl], - [use the GNU ltdl sources included here])]) - -if test yes != "$with_included_ltdl"; then - # We are not being forced to use the included libltdl sources, so - # decide whether there is a useful installed version we can use. - AC_CHECK_HEADER([ltdl.h], - [AC_CHECK_DECL([lt_dlinterface_register], - [AC_CHECK_LIB([ltdl], [lt_dladvise_preload], - [with_included_ltdl=no], - [with_included_ltdl=yes])], - [with_included_ltdl=yes], - [AC_INCLUDES_DEFAULT - #include ])], - [with_included_ltdl=yes], - [AC_INCLUDES_DEFAULT] - ) -fi - -dnl If neither LT_CONFIG_LTDL_DIR, LTDL_CONVENIENCE nor LTDL_INSTALLABLE -dnl was called yet, then for old times' sake, we assume libltdl is in an -dnl eponymous directory: -AC_PROVIDE_IFELSE([LT_CONFIG_LTDL_DIR], [], [_LT_CONFIG_LTDL_DIR([libltdl])]) - -AC_ARG_WITH([ltdl_include], - [AS_HELP_STRING([--with-ltdl-include=DIR], - [use the ltdl headers installed in DIR])]) - -if test -n "$with_ltdl_include"; then - if test -f "$with_ltdl_include/ltdl.h"; then : - else - AC_MSG_ERROR([invalid ltdl include directory: '$with_ltdl_include']) - fi -else - with_ltdl_include=no -fi - -AC_ARG_WITH([ltdl_lib], - [AS_HELP_STRING([--with-ltdl-lib=DIR], - [use the libltdl.la installed in DIR])]) - -if test -n "$with_ltdl_lib"; then - if test -f "$with_ltdl_lib/libltdl.la"; then : - else - AC_MSG_ERROR([invalid ltdl library directory: '$with_ltdl_lib']) - fi -else - with_ltdl_lib=no -fi - -case ,$with_included_ltdl,$with_ltdl_include,$with_ltdl_lib, in - ,yes,no,no,) - m4_case(m4_default(_LTDL_TYPE, [convenience]), - [convenience], [_LTDL_CONVENIENCE], - [installable], [_LTDL_INSTALLABLE], - [m4_fatal([unknown libltdl build type: ]_LTDL_TYPE)]) - ;; - ,no,no,no,) - # If the included ltdl is not to be used, then use the - # preinstalled libltdl we found. - AC_DEFINE([HAVE_LTDL], [1], - [Define this if a modern libltdl is already installed]) - LIBLTDL=-lltdl - LTDLDEPS= - LTDLINCL= - ;; - ,no*,no,*) - AC_MSG_ERROR(['--with-ltdl-include' and '--with-ltdl-lib' options must be used together]) - ;; - *) with_included_ltdl=no - LIBLTDL="-L$with_ltdl_lib -lltdl" - LTDLDEPS= - LTDLINCL=-I$with_ltdl_include - ;; -esac -INCLTDL=$LTDLINCL - -# Report our decision... -AC_MSG_CHECKING([where to find libltdl headers]) -AC_MSG_RESULT([$LTDLINCL]) -AC_MSG_CHECKING([where to find libltdl library]) -AC_MSG_RESULT([$LIBLTDL]) - -_LTDL_SETUP - -dnl restore autoconf definition. -m4_popdef([AC_LIBOBJ]) -m4_popdef([AC_LIBSOURCES]) - -AC_CONFIG_COMMANDS_PRE([ - _ltdl_libobjs= - _ltdl_ltlibobjs= - if test -n "$_LT_LIBOBJS"; then - # Remove the extension. - _lt_sed_drop_objext='s/\.o$//;s/\.obj$//' - for i in `for i in $_LT_LIBOBJS; do echo "$i"; done | $SED "$_lt_sed_drop_objext" | sort -u`; do - _ltdl_libobjs="$_ltdl_libobjs $lt_libobj_prefix$i.$ac_objext" - _ltdl_ltlibobjs="$_ltdl_ltlibobjs $lt_libobj_prefix$i.lo" - done - fi - AC_SUBST([ltdl_LIBOBJS], [$_ltdl_libobjs]) - AC_SUBST([ltdl_LTLIBOBJS], [$_ltdl_ltlibobjs]) -]) - -# Only expand once: -m4_define([LTDL_INIT]) -])# LTDL_INIT - -# Old names: -AU_DEFUN([AC_LIB_LTDL], [LTDL_INIT($@)]) -AU_DEFUN([AC_WITH_LTDL], [LTDL_INIT($@)]) -AU_DEFUN([LT_WITH_LTDL], [LTDL_INIT($@)]) -dnl aclocal-1.4 backwards compatibility: -dnl AC_DEFUN([AC_LIB_LTDL], []) -dnl AC_DEFUN([AC_WITH_LTDL], []) -dnl AC_DEFUN([LT_WITH_LTDL], []) - - -# _LTDL_SETUP -# ----------- -# Perform all the checks necessary for compilation of the ltdl objects -# -- including compiler checks and header checks. This is a public -# interface mainly for the benefit of libltdl's own configure.ac, most -# other users should call LTDL_INIT instead. -AC_DEFUN([_LTDL_SETUP], -[AC_REQUIRE([AC_PROG_CC])dnl -AC_REQUIRE([LT_SYS_MODULE_EXT])dnl -AC_REQUIRE([LT_SYS_MODULE_PATH])dnl -AC_REQUIRE([LT_SYS_DLSEARCH_PATH])dnl -AC_REQUIRE([LT_LIB_DLLOAD])dnl -AC_REQUIRE([LT_SYS_SYMBOL_USCORE])dnl -AC_REQUIRE([LT_FUNC_DLSYM_USCORE])dnl -AC_REQUIRE([LT_SYS_DLOPEN_DEPLIBS])dnl -AC_REQUIRE([LT_FUNC_ARGZ])dnl - -m4_require([_LT_CHECK_OBJDIR])dnl -m4_require([_LT_HEADER_DLFCN])dnl -m4_require([_LT_CHECK_DLPREOPEN])dnl -m4_require([_LT_DECL_SED])dnl - -dnl Don't require this, or it will be expanded earlier than the code -dnl that sets the variables it relies on: -_LT_ENABLE_INSTALL - -dnl _LTDL_MODE specific code must be called at least once: -_LTDL_MODE_DISPATCH - -# In order that ltdl.c can compile, find out the first AC_CONFIG_HEADERS -# the user used. This is so that ltdl.h can pick up the parent projects -# config.h file, The first file in AC_CONFIG_HEADERS must contain the -# definitions required by ltdl.c. -# FIXME: Remove use of undocumented AC_LIST_HEADERS (2.59 compatibility). -AC_CONFIG_COMMANDS_PRE([dnl -m4_pattern_allow([^LT_CONFIG_H$])dnl -m4_ifset([AH_HEADER], - [LT_CONFIG_H=AH_HEADER], - [m4_ifset([AC_LIST_HEADERS], - [LT_CONFIG_H=`echo "AC_LIST_HEADERS" | $SED 's|^[[ ]]*||;s|[[ :]].*$||'`], - [])])]) -AC_SUBST([LT_CONFIG_H]) - -AC_CHECK_HEADERS([unistd.h dl.h sys/dl.h dld.h mach-o/dyld.h dirent.h], - [], [], [AC_INCLUDES_DEFAULT]) - -AC_CHECK_FUNCS([closedir opendir readdir], [], [AC_LIBOBJ([lt__dirent])]) -AC_CHECK_FUNCS([strlcat strlcpy], [], [AC_LIBOBJ([lt__strl])]) - -m4_pattern_allow([LT_LIBEXT])dnl -AC_DEFINE_UNQUOTED([LT_LIBEXT],["$libext"],[The archive extension]) - -name= -eval "lt_libprefix=\"$libname_spec\"" -m4_pattern_allow([LT_LIBPREFIX])dnl -AC_DEFINE_UNQUOTED([LT_LIBPREFIX],["$lt_libprefix"],[The archive prefix]) - -name=ltdl -eval "LTDLOPEN=\"$libname_spec\"" -AC_SUBST([LTDLOPEN]) -])# _LTDL_SETUP - - -# _LT_ENABLE_INSTALL -# ------------------ -m4_define([_LT_ENABLE_INSTALL], -[AC_ARG_ENABLE([ltdl-install], - [AS_HELP_STRING([--enable-ltdl-install], [install libltdl])]) - -case ,$enable_ltdl_install,$enable_ltdl_convenience in - *yes*) ;; - *) enable_ltdl_convenience=yes ;; -esac - -m4_ifdef([AM_CONDITIONAL], -[AM_CONDITIONAL(INSTALL_LTDL, test no != "${enable_ltdl_install-no}") - AM_CONDITIONAL(CONVENIENCE_LTDL, test no != "${enable_ltdl_convenience-no}") - AM_CONDITIONAL(LTARGZH_EXISTS, test -n "$LT_ARGZ_H")]) -])# _LT_ENABLE_INSTALL - - -# LT_SYS_DLOPEN_DEPLIBS -# --------------------- -AC_DEFUN([LT_SYS_DLOPEN_DEPLIBS], -[AC_REQUIRE([AC_CANONICAL_HOST])dnl -AC_CACHE_CHECK([whether deplibs are loaded by dlopen], - [lt_cv_sys_dlopen_deplibs], - [# PORTME does your system automatically load deplibs for dlopen? - # or its logical equivalent (e.g. shl_load for HP-UX < 11) - # For now, we just catch OSes we know something about -- in the - # future, we'll try test this programmatically. - lt_cv_sys_dlopen_deplibs=unknown - case $host_os in - aix3*|aix4.1.*|aix4.2.*) - # Unknown whether this is true for these versions of AIX, but - # we want this 'case' here to explicitly catch those versions. - lt_cv_sys_dlopen_deplibs=unknown - ;; - aix[[4-9]]*) - lt_cv_sys_dlopen_deplibs=yes - ;; - amigaos*) - case $host_cpu in - powerpc) - lt_cv_sys_dlopen_deplibs=no - ;; - esac - ;; - darwin*) - # Assuming the user has installed a libdl from somewhere, this is true - # If you are looking for one http://www.opendarwin.org/projects/dlcompat - lt_cv_sys_dlopen_deplibs=yes - ;; - freebsd* | dragonfly* | midnightbsd*) - lt_cv_sys_dlopen_deplibs=yes - ;; - gnu* | linux* | k*bsd*-gnu | kopensolaris*-gnu) - # GNU and its variants, using gnu ld.so (Glibc) - lt_cv_sys_dlopen_deplibs=yes - ;; - hpux10*|hpux11*) - lt_cv_sys_dlopen_deplibs=yes - ;; - interix*) - lt_cv_sys_dlopen_deplibs=yes - ;; - irix[[12345]]*|irix6.[[01]]*) - # Catch all versions of IRIX before 6.2, and indicate that we don't - # know how it worked for any of those versions. - lt_cv_sys_dlopen_deplibs=unknown - ;; - irix*) - # The case above catches anything before 6.2, and it's known that - # at 6.2 and later dlopen does load deplibs. - lt_cv_sys_dlopen_deplibs=yes - ;; - *-mlibc) - lt_cv_sys_dlopen_deplibs=yes - ;; - netbsd* | netbsdelf*-gnu) - lt_cv_sys_dlopen_deplibs=yes - ;; - openbsd*) - lt_cv_sys_dlopen_deplibs=yes - ;; - osf[[1234]]*) - # dlopen did load deplibs (at least at 4.x), but until the 5.x series, - # it did *not* use an RPATH in a shared library to find objects the - # library depends on, so we explicitly say 'no'. - lt_cv_sys_dlopen_deplibs=no - ;; - osf5.0|osf5.0a|osf5.1) - # dlopen *does* load deplibs and with the right loader patch applied - # it even uses RPATH in a shared library to search for shared objects - # that the library depends on, but there's no easy way to know if that - # patch is installed. Since this is the case, all we can really - # say is unknown -- it depends on the patch being installed. If - # it is, this changes to 'yes'. Without it, it would be 'no'. - lt_cv_sys_dlopen_deplibs=unknown - ;; - osf*) - # the two cases above should catch all versions of osf <= 5.1. Read - # the comments above for what we know about them. - # At > 5.1, deplibs are loaded *and* any RPATH in a shared library - # is used to find them so we can finally say 'yes'. - lt_cv_sys_dlopen_deplibs=yes - ;; - qnx*) - lt_cv_sys_dlopen_deplibs=yes - ;; - solaris*) - lt_cv_sys_dlopen_deplibs=yes - ;; - sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) - libltdl_cv_sys_dlopen_deplibs=yes - ;; - esac - ]) -if test yes != "$lt_cv_sys_dlopen_deplibs"; then - AC_DEFINE([LTDL_DLOPEN_DEPLIBS], [1], - [Define if the OS needs help to load dependent libraries for dlopen().]) -fi -])# LT_SYS_DLOPEN_DEPLIBS - -# Old name: -AU_ALIAS([AC_LTDL_SYS_DLOPEN_DEPLIBS], [LT_SYS_DLOPEN_DEPLIBS]) -dnl aclocal-1.4 backwards compatibility: -dnl AC_DEFUN([AC_LTDL_SYS_DLOPEN_DEPLIBS], []) - - -# LT_SYS_MODULE_EXT -# ----------------- -AC_DEFUN([LT_SYS_MODULE_EXT], -[m4_require([_LT_SYS_DYNAMIC_LINKER])dnl -AC_CACHE_CHECK([what extension is used for runtime loadable modules], - [libltdl_cv_shlibext], -[ -module=yes -eval libltdl_cv_shlibext=$shrext_cmds -module=no -eval libltdl_cv_shrext=$shrext_cmds - ]) -if test -n "$libltdl_cv_shlibext"; then - m4_pattern_allow([LT_MODULE_EXT])dnl - AC_DEFINE_UNQUOTED([LT_MODULE_EXT], ["$libltdl_cv_shlibext"], - [Define to the extension used for runtime loadable modules, say, ".so".]) -fi -if test "$libltdl_cv_shrext" != "$libltdl_cv_shlibext"; then - m4_pattern_allow([LT_SHARED_EXT])dnl - AC_DEFINE_UNQUOTED([LT_SHARED_EXT], ["$libltdl_cv_shrext"], - [Define to the shared library suffix, say, ".dylib".]) -fi -if test -n "$shared_archive_member_spec"; then - m4_pattern_allow([LT_SHARED_LIB_MEMBER])dnl - AC_DEFINE_UNQUOTED([LT_SHARED_LIB_MEMBER], ["($shared_archive_member_spec.o)"], - [Define to the shared archive member specification, say "(shr.o)".]) -fi -])# LT_SYS_MODULE_EXT - -# Old name: -AU_ALIAS([AC_LTDL_SHLIBEXT], [LT_SYS_MODULE_EXT]) -dnl aclocal-1.4 backwards compatibility: -dnl AC_DEFUN([AC_LTDL_SHLIBEXT], []) - - -# LT_SYS_MODULE_PATH -# ------------------ -AC_DEFUN([LT_SYS_MODULE_PATH], -[m4_require([_LT_SYS_DYNAMIC_LINKER])dnl -AC_CACHE_CHECK([what variable specifies run-time module search path], - [lt_cv_module_path_var], [lt_cv_module_path_var=$shlibpath_var]) -if test -n "$lt_cv_module_path_var"; then - m4_pattern_allow([LT_MODULE_PATH_VAR])dnl - AC_DEFINE_UNQUOTED([LT_MODULE_PATH_VAR], ["$lt_cv_module_path_var"], - [Define to the name of the environment variable that determines the run-time module search path.]) -fi -])# LT_SYS_MODULE_PATH - -# Old name: -AU_ALIAS([AC_LTDL_SHLIBPATH], [LT_SYS_MODULE_PATH]) -dnl aclocal-1.4 backwards compatibility: -dnl AC_DEFUN([AC_LTDL_SHLIBPATH], []) - - -# LT_SYS_DLSEARCH_PATH -# -------------------- -AC_DEFUN([LT_SYS_DLSEARCH_PATH], -[m4_require([_LT_SYS_DYNAMIC_LINKER])dnl -AC_CACHE_CHECK([for the default library search path], - [lt_cv_sys_dlsearch_path], - [lt_cv_sys_dlsearch_path=$sys_lib_dlsearch_path_spec]) -if test -n "$lt_cv_sys_dlsearch_path"; then - sys_dlsearch_path= - for dir in $lt_cv_sys_dlsearch_path; do - if test -z "$sys_dlsearch_path"; then - sys_dlsearch_path=$dir - else - sys_dlsearch_path=$sys_dlsearch_path$PATH_SEPARATOR$dir - fi - done - m4_pattern_allow([LT_DLSEARCH_PATH])dnl - AC_DEFINE_UNQUOTED([LT_DLSEARCH_PATH], ["$sys_dlsearch_path"], - [Define to the system default library search path.]) -fi -])# LT_SYS_DLSEARCH_PATH - -# Old name: -AU_ALIAS([AC_LTDL_SYSSEARCHPATH], [LT_SYS_DLSEARCH_PATH]) -dnl aclocal-1.4 backwards compatibility: -dnl AC_DEFUN([AC_LTDL_SYSSEARCHPATH], []) - - -# _LT_CHECK_DLPREOPEN -# ------------------- -m4_defun([_LT_CHECK_DLPREOPEN], -[m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl -AC_CACHE_CHECK([whether libtool supports -dlopen/-dlpreopen], - [libltdl_cv_preloaded_symbols], - [if test -n "$lt_cv_sys_global_symbol_pipe"; then - libltdl_cv_preloaded_symbols=yes - else - libltdl_cv_preloaded_symbols=no - fi - ]) -if test yes = "$libltdl_cv_preloaded_symbols"; then - AC_DEFINE([HAVE_PRELOADED_SYMBOLS], [1], - [Define if libtool can extract symbol lists from object files.]) -fi -])# _LT_CHECK_DLPREOPEN - - -# LT_LIB_DLLOAD -# ------------- -AC_DEFUN([LT_LIB_DLLOAD], -[m4_pattern_allow([^LT_DLLOADERS$]) -LT_DLLOADERS= -AC_SUBST([LT_DLLOADERS]) - -AC_LANG_PUSH([C]) -lt_dlload_save_LIBS=$LIBS - -LIBADD_DLOPEN= -AC_SEARCH_LIBS([dlopen], [dl], - [AC_DEFINE([HAVE_LIBDL], [1], - [Define if you have the libdl library or equivalent.]) - if test "$ac_cv_search_dlopen" != "none required"; then - LIBADD_DLOPEN=-ldl - fi - libltdl_cv_lib_dl_dlopen=yes - LT_DLLOADERS="$LT_DLLOADERS ${lt_dlopen_dir+$lt_dlopen_dir/}dlopen.la"], - [AC_LINK_IFELSE([AC_LANG_PROGRAM([[#if HAVE_DLFCN_H -# include -#endif - ]], [[dlopen(0, 0);]])], - [AC_DEFINE([HAVE_LIBDL], [1], - [Define if you have the libdl library or equivalent.]) - libltdl_cv_func_dlopen=yes - LT_DLLOADERS="$LT_DLLOADERS ${lt_dlopen_dir+$lt_dlopen_dir/}dlopen.la"], - [AC_CHECK_LIB([svld], [dlopen], - [AC_DEFINE([HAVE_LIBDL], [1], - [Define if you have the libdl library or equivalent.]) - LIBADD_DLOPEN=-lsvld libltdl_cv_func_dlopen=yes - LT_DLLOADERS="$LT_DLLOADERS ${lt_dlopen_dir+$lt_dlopen_dir/}dlopen.la"])])]) -if test yes = "$libltdl_cv_func_dlopen" || test yes = "$libltdl_cv_lib_dl_dlopen" -then - lt_save_LIBS=$LIBS - LIBS="$LIBS $LIBADD_DLOPEN" - AC_CHECK_FUNCS([dlerror]) - LIBS=$lt_save_LIBS -fi -AC_SUBST([LIBADD_DLOPEN]) - -LIBADD_SHL_LOAD= -AC_CHECK_FUNC([shl_load], - [AC_DEFINE([HAVE_SHL_LOAD], [1], - [Define if you have the shl_load function.]) - LT_DLLOADERS="$LT_DLLOADERS ${lt_dlopen_dir+$lt_dlopen_dir/}shl_load.la"], - [AC_CHECK_LIB([dld], [shl_load], - [AC_DEFINE([HAVE_SHL_LOAD], [1], - [Define if you have the shl_load function.]) - LT_DLLOADERS="$LT_DLLOADERS ${lt_dlopen_dir+$lt_dlopen_dir/}shl_load.la" - LIBADD_SHL_LOAD=-ldld])]) -AC_SUBST([LIBADD_SHL_LOAD]) - -case $host_os in -darwin[[1567]].*) -# We only want this for pre-Mac OS X 10.4. - AC_CHECK_FUNC([_dyld_func_lookup], - [AC_DEFINE([HAVE_DYLD], [1], - [Define if you have the _dyld_func_lookup function.]) - LT_DLLOADERS="$LT_DLLOADERS ${lt_dlopen_dir+$lt_dlopen_dir/}dyld.la"]) - ;; -beos*) - LT_DLLOADERS="$LT_DLLOADERS ${lt_dlopen_dir+$lt_dlopen_dir/}load_add_on.la" - ;; -cygwin* | mingw* | windows* | pw32*) - AC_CHECK_DECLS([cygwin_conv_path], [], [], [[#include ]]) - LT_DLLOADERS="$LT_DLLOADERS ${lt_dlopen_dir+$lt_dlopen_dir/}loadlibrary.la" - ;; -esac - -AC_CHECK_LIB([dld], [dld_link], - [AC_DEFINE([HAVE_DLD], [1], - [Define if you have the GNU dld library.]) - LT_DLLOADERS="$LT_DLLOADERS ${lt_dlopen_dir+$lt_dlopen_dir/}dld_link.la"]) -AC_SUBST([LIBADD_DLD_LINK]) - -m4_pattern_allow([^LT_DLPREOPEN$]) -LT_DLPREOPEN= -if test -n "$LT_DLLOADERS" -then - for lt_loader in $LT_DLLOADERS; do - LT_DLPREOPEN="$LT_DLPREOPEN-dlpreopen $lt_loader " - done - AC_DEFINE([HAVE_LIBDLLOADER], [1], - [Define if libdlloader will be built on this platform]) -fi -AC_SUBST([LT_DLPREOPEN]) - -dnl This isn't used anymore, but set it for backwards compatibility -LIBADD_DL="$LIBADD_DLOPEN $LIBADD_SHL_LOAD" -AC_SUBST([LIBADD_DL]) - -LIBS=$lt_dlload_save_LIBS -AC_LANG_POP -])# LT_LIB_DLLOAD - -# Old name: -AU_ALIAS([AC_LTDL_DLLIB], [LT_LIB_DLLOAD]) -dnl aclocal-1.4 backwards compatibility: -dnl AC_DEFUN([AC_LTDL_DLLIB], []) - - -# LT_SYS_SYMBOL_USCORE -# -------------------- -# does the compiler prefix global symbols with an underscore? -AC_DEFUN([LT_SYS_SYMBOL_USCORE], -[m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl -AC_CACHE_CHECK([for _ prefix in compiled symbols], - [lt_cv_sys_symbol_underscore], - [lt_cv_sys_symbol_underscore=no - cat > conftest.$ac_ext <<_LT_EOF -void nm_test_func(){} -int main(void){nm_test_func;return 0;} -_LT_EOF - if AC_TRY_EVAL(ac_compile); then - # Now try to grab the symbols. - ac_nlist=conftest.nm - if AC_TRY_EVAL(NM conftest.$ac_objext \| $lt_cv_sys_global_symbol_pipe \> $ac_nlist) && test -s "$ac_nlist"; then - # See whether the symbols have a leading underscore. - if grep '^. _nm_test_func' "$ac_nlist" >/dev/null; then - lt_cv_sys_symbol_underscore=yes - else - if grep '^. nm_test_func ' "$ac_nlist" >/dev/null; then - : - else - echo "configure: cannot find nm_test_func in $ac_nlist" >&AS_MESSAGE_LOG_FD - fi - fi - else - echo "configure: cannot run $lt_cv_sys_global_symbol_pipe" >&AS_MESSAGE_LOG_FD - fi - else - echo "configure: failed program was:" >&AS_MESSAGE_LOG_FD - cat conftest.c >&AS_MESSAGE_LOG_FD - fi - rm -rf conftest* - ]) - sys_symbol_underscore=$lt_cv_sys_symbol_underscore - AC_SUBST([sys_symbol_underscore]) -])# LT_SYS_SYMBOL_USCORE - -# Old name: -AU_ALIAS([AC_LTDL_SYMBOL_USCORE], [LT_SYS_SYMBOL_USCORE]) -dnl aclocal-1.4 backwards compatibility: -dnl AC_DEFUN([AC_LTDL_SYMBOL_USCORE], []) - - -# LT_FUNC_DLSYM_USCORE -# -------------------- -AC_DEFUN([LT_FUNC_DLSYM_USCORE], -[AC_REQUIRE([_LT_COMPILER_PIC])dnl for lt_prog_compiler_wl -AC_REQUIRE([LT_SYS_SYMBOL_USCORE])dnl for lt_cv_sys_symbol_underscore -AC_REQUIRE([LT_SYS_MODULE_EXT])dnl for libltdl_cv_shlibext -if test yes = "$lt_cv_sys_symbol_underscore"; then - if test yes = "$libltdl_cv_func_dlopen" || test yes = "$libltdl_cv_lib_dl_dlopen"; then - AC_CACHE_CHECK([whether we have to add an underscore for dlsym], - [libltdl_cv_need_uscore], - [libltdl_cv_need_uscore=unknown - dlsym_uscore_save_LIBS=$LIBS - LIBS="$LIBS $LIBADD_DLOPEN" - libname=conftmod # stay within 8.3 filename limits! - cat >$libname.$ac_ext <<_LT_EOF -[#line $LINENO "configure" -#include "confdefs.h" -/* When -fvisibility=hidden is used, assume the code has been annotated - correspondingly for the symbols needed. */ -#if defined __GNUC__ && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)) -int fnord () __attribute__((visibility("default"))); -#endif -int fnord () { return 42; }] -_LT_EOF - - # ltfn_module_cmds module_cmds - # Execute tilde-delimited MODULE_CMDS with environment primed for - # $module_cmds or $archive_cmds type content. - ltfn_module_cmds () - {( # subshell avoids polluting parent global environment - module_cmds_save_ifs=$IFS; IFS='~' - for cmd in @S|@1; do - IFS=$module_cmds_save_ifs - libobjs=$libname.$ac_objext; lib=$libname$libltdl_cv_shlibext - rpath=/not-exists; soname=$libname$libltdl_cv_shlibext; output_objdir=. - major=; versuffix=; verstring=; deplibs= - ECHO=echo; wl=$lt_prog_compiler_wl; allow_undefined_flag= - eval $cmd - done - IFS=$module_cmds_save_ifs - )} - - # Compile a loadable module using libtool macro expansion results. - $CC $pic_flag -c $libname.$ac_ext - ltfn_module_cmds "${module_cmds:-$archive_cmds}" - - # Try to fetch fnord with dlsym(). - libltdl_dlunknown=0; libltdl_dlnouscore=1; libltdl_dluscore=2 - cat >conftest.$ac_ext <<_LT_EOF -[#line $LINENO "configure" -#include "confdefs.h" -#if HAVE_DLFCN_H -#include -#endif -#include -#ifndef RTLD_GLOBAL -# ifdef DL_GLOBAL -# define RTLD_GLOBAL DL_GLOBAL -# else -# define RTLD_GLOBAL 0 -# endif -#endif -#ifndef RTLD_NOW -# ifdef DL_NOW -# define RTLD_NOW DL_NOW -# else -# define RTLD_NOW 0 -# endif -#endif -int main (void) { - void *handle = dlopen ("`pwd`/$libname$libltdl_cv_shlibext", RTLD_GLOBAL|RTLD_NOW); - int status = $libltdl_dlunknown; - if (handle) { - if (dlsym (handle, "fnord")) - status = $libltdl_dlnouscore; - else { - if (dlsym (handle, "_fnord")) - status = $libltdl_dluscore; - else - puts (dlerror ()); - } - dlclose (handle); - } else - puts (dlerror ()); - return status; -}] -_LT_EOF - if AC_TRY_EVAL(ac_link) && test -s "conftest$ac_exeext" 2>/dev/null; then - (./conftest; exit; ) >&AS_MESSAGE_LOG_FD 2>/dev/null - libltdl_status=$? - case x$libltdl_status in - x$libltdl_dlnouscore) libltdl_cv_need_uscore=no ;; - x$libltdl_dluscore) libltdl_cv_need_uscore=yes ;; - x*) libltdl_cv_need_uscore=unknown ;; - esac - fi - rm -rf conftest* $libname* - LIBS=$dlsym_uscore_save_LIBS - ]) - fi -fi - -if test yes = "$libltdl_cv_need_uscore"; then - AC_DEFINE([NEED_USCORE], [1], - [Define if dlsym() requires a leading underscore in symbol names.]) -fi -])# LT_FUNC_DLSYM_USCORE - -# Old name: -AU_ALIAS([AC_LTDL_DLSYM_USCORE], [LT_FUNC_DLSYM_USCORE]) -dnl aclocal-1.4 backwards compatibility: -dnl AC_DEFUN([AC_LTDL_DLSYM_USCORE], []) - # Copyright (C) 2002-2024 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation @@ -2296,6 +1306,8 @@ AC_SUBST(am__xargs_n) ]) m4_include([../m4/libtool.m4]) +m4_include([../m4/ltargz.m4]) +m4_include([../m4/ltdl.m4]) m4_include([../m4/ltoptions.m4]) m4_include([../m4/ltsugar.m4]) m4_include([../m4/ltversion.m4]) diff --git a/libltdl/configure b/libltdl/configure old mode 100755 new mode 100644 diff --git a/mod.cservice/SETCommand.cc b/mod.cservice/SETCommand.cc index 767c2e07..06aa777d 100644 --- a/mod.cservice/SETCommand.cc +++ b/mod.cservice/SETCommand.cc @@ -189,7 +189,7 @@ if( st[1][0] != '#' ) // Didn't find a hash? bot->Notice(theClient, bot->getResponse(theUser, language::no_fingerprints_registered, - string("You currently don't have any fingerprints added to your account. For more information, use '/msg X help fingerprint'"))); + string("You currently don't have any fingerprints added to your account. For more information, use '/msg X help cert'"))); return true; } theUser->setFlag(sqlUser::F_CERTONLY); From db7a21cbd570aa35ade45397a96d6f2c018c6744 Mon Sep 17 00:00:00 2001 From: MrIron Date: Fri, 9 Jan 2026 14:57:08 +0100 Subject: [PATCH 3/3] minor fix --- mod.cservice/CERTCommand.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mod.cservice/CERTCommand.cc b/mod.cservice/CERTCommand.cc index 9e73b808..654c5e1c 100644 --- a/mod.cservice/CERTCommand.cc +++ b/mod.cservice/CERTCommand.cc @@ -27,7 +27,7 @@ namespace gnuworld { -bool CERTCommand::Exec( iClient* [[maybe_unused]] theClient, const string& [[maybe_unused]] Message ) +bool CERTCommand::Exec( [[maybe_unused]] iClient* theClient, [[maybe_unused]] const string& Message ) { #ifdef NEW_IRCU_FEATURES