diff options
author | michael <michael@82007160-df01-0410-b94d-b575c5fd34c7> | 2012-10-27 21:02:32 +0000 |
---|---|---|
committer | michael <michael@82007160-df01-0410-b94d-b575c5fd34c7> | 2012-10-27 21:02:32 +0000 |
commit | 70f1558a2eca8295e30bb1e381d948056333634d (patch) | |
tree | 3051cb6afbc7d5ebae4381e54c70d9cbe54005a4 /src | |
parent | 4f1edcf052857117fd51e878c362f878961c4dc9 (diff) |
- Second time's the charm? Moving svnroot/ircd-hybrid-8 to
svnroot/ircd-hybrid/trunk
git-svn-id: svn://svn.ircd-hybrid.org/svnroot/ircd-hybrid/trunk@1592 82007160-df01-0410-b94d-b575c5fd34c7
Diffstat (limited to 'src')
-rw-r--r-- | src/Makefile.am | 62 | ||||
-rw-r--r-- | src/Makefile.in | 728 | ||||
-rw-r--r-- | src/balloc.c | 503 | ||||
-rw-r--r-- | src/channel.c | 864 | ||||
-rw-r--r-- | src/channel_mode.c | 1797 | ||||
-rw-r--r-- | src/client.c | 1205 | ||||
-rw-r--r-- | src/conf.c | 3622 | ||||
-rw-r--r-- | src/conf_lexer.c | 4278 | ||||
-rw-r--r-- | src/conf_lexer.l | 489 | ||||
-rw-r--r-- | src/conf_parser.c | 7071 | ||||
-rw-r--r-- | src/conf_parser.h | 513 | ||||
-rw-r--r-- | src/conf_parser.y | 3072 | ||||
-rw-r--r-- | src/csvlib.c | 671 | ||||
-rw-r--r-- | src/dbuf.c | 112 | ||||
-rw-r--r-- | src/event.c | 292 | ||||
-rw-r--r-- | src/fdlist.c | 243 | ||||
-rw-r--r-- | src/getopt.c | 127 | ||||
-rw-r--r-- | src/hash.c | 907 | ||||
-rw-r--r-- | src/hook.c | 216 | ||||
-rw-r--r-- | src/hostmask.c | 820 | ||||
-rw-r--r-- | src/irc_res.c | 836 | ||||
-rw-r--r-- | src/irc_reslib.c | 1168 | ||||
-rw-r--r-- | src/irc_string.c | 263 | ||||
-rw-r--r-- | src/ircd.c | 658 | ||||
-rw-r--r-- | src/ircd_signal.c | 135 | ||||
-rw-r--r-- | src/list.c | 277 | ||||
-rw-r--r-- | src/listener.c | 429 | ||||
-rw-r--r-- | src/log.c | 123 | ||||
-rw-r--r-- | src/match.c | 616 | ||||
-rw-r--r-- | src/memory.c | 114 | ||||
-rw-r--r-- | src/messages.tab | 1029 | ||||
-rw-r--r-- | src/modules.c | 401 | ||||
-rw-r--r-- | src/motd.c | 283 | ||||
-rw-r--r-- | src/numeric.c | 226 | ||||
-rw-r--r-- | src/packet.c | 414 | ||||
-rw-r--r-- | src/parse.c | 815 | ||||
-rw-r--r-- | src/restart.c | 94 | ||||
-rw-r--r-- | src/resv.c | 230 | ||||
-rw-r--r-- | src/rng_mt.c | 167 | ||||
-rw-r--r-- | src/rsa.c | 120 | ||||
-rw-r--r-- | src/s_auth.c | 598 | ||||
-rw-r--r-- | src/s_bsd.c | 757 | ||||
-rw-r--r-- | src/s_bsd_devpoll.c | 186 | ||||
-rw-r--r-- | src/s_bsd_epoll.c | 221 | ||||
-rw-r--r-- | src/s_bsd_kqueue.c | 199 | ||||
-rw-r--r-- | src/s_bsd_poll.c | 224 | ||||
-rw-r--r-- | src/s_bsd_select.c | 204 | ||||
-rw-r--r-- | src/s_bsd_sigio.c | 318 | ||||
-rw-r--r-- | src/s_gline.c | 114 | ||||
-rw-r--r-- | src/s_misc.c | 131 | ||||
-rw-r--r-- | src/s_serv.c | 1503 | ||||
-rw-r--r-- | src/s_user.c | 1484 | ||||
-rw-r--r-- | src/send.c | 1111 | ||||
-rw-r--r-- | src/sprintf_irc.c | 472 | ||||
-rw-r--r-- | src/version.c | 105 | ||||
-rw-r--r-- | src/watch.c | 235 | ||||
-rw-r--r-- | src/whowas.c | 142 |
57 files changed, 43994 insertions, 0 deletions
diff --git a/src/Makefile.am b/src/Makefile.am new file mode 100644 index 0000000..2f51356 --- /dev/null +++ b/src/Makefile.am @@ -0,0 +1,62 @@ +AUTOMAKE_OPTIONS = foreign + +sbin_PROGRAMS = ircd + +AM_YFLAGS = -d + +AM_CPPFLAGS = $(LTDLINCL) -I$(top_srcdir)/include +ircd_LDFLAGS = -export-dynamic +ircd_LDADD = $(LIBLTDL) +ircd_DEPENDENCIES = $(LTDLDEPS) + +ircd_SOURCES = balloc.c \ + channel.c \ + channel_mode.c \ + client.c \ + conf.c \ + conf_parser.y \ + conf_lexer.l \ + csvlib.c \ + dbuf.c \ + event.c \ + fdlist.c \ + getopt.c \ + hash.c \ + hook.c \ + hostmask.c \ + irc_res.c \ + irc_reslib.c \ + irc_string.c \ + ircd.c \ + ircd_signal.c \ + list.c \ + listener.c \ + log.c \ + match.c \ + memory.c \ + modules.c \ + motd.c \ + rng_mt.c \ + numeric.c \ + packet.c \ + parse.c \ + s_bsd_epoll.c \ + s_bsd_poll.c \ + s_bsd_sigio.c \ + s_bsd_devpoll.c \ + s_bsd_kqueue.c \ + s_bsd_select.c \ + restart.c \ + resv.c \ + rsa.c \ + s_auth.c \ + s_bsd.c \ + s_gline.c \ + s_misc.c \ + s_serv.c \ + s_user.c \ + send.c \ + sprintf_irc.c \ + version.c \ + watch.c \ + whowas.c diff --git a/src/Makefile.in b/src/Makefile.in new file mode 100644 index 0000000..a8102c7 --- /dev/null +++ b/src/Makefile.in @@ -0,0 +1,728 @@ +# Makefile.in generated by automake 1.12.4 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2012 Free Software Foundation, Inc. + +# This Makefile.in 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. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +am__make_dryrun = \ + { \ + am__dry=no; \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + echo 'am--echo: ; @echo "AM" OK' | $(MAKE) -f - 2>/dev/null \ + | grep '^AM OK$$' >/dev/null || am__dry=yes;; \ + *) \ + for am__flg in $$MAKEFLAGS; do \ + case $$am__flg in \ + *=*|--*) ;; \ + *n*) am__dry=yes; break;; \ + esac; \ + done;; \ + esac; \ + test $$am__dry = yes; \ + } +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +sbin_PROGRAMS = ircd$(EXEEXT) +subdir = src +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in \ + $(top_srcdir)/depcomp $(top_srcdir)/ylwrap conf_lexer.c \ + conf_parser.c conf_parser.h +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +am__installdirs = "$(DESTDIR)$(sbindir)" +PROGRAMS = $(sbin_PROGRAMS) +am_ircd_OBJECTS = balloc.$(OBJEXT) channel.$(OBJEXT) \ + channel_mode.$(OBJEXT) client.$(OBJEXT) conf.$(OBJEXT) \ + conf_parser.$(OBJEXT) conf_lexer.$(OBJEXT) csvlib.$(OBJEXT) \ + dbuf.$(OBJEXT) event.$(OBJEXT) fdlist.$(OBJEXT) \ + getopt.$(OBJEXT) hash.$(OBJEXT) hook.$(OBJEXT) \ + hostmask.$(OBJEXT) irc_res.$(OBJEXT) irc_reslib.$(OBJEXT) \ + irc_string.$(OBJEXT) ircd.$(OBJEXT) ircd_signal.$(OBJEXT) \ + list.$(OBJEXT) listener.$(OBJEXT) log.$(OBJEXT) \ + match.$(OBJEXT) memory.$(OBJEXT) modules.$(OBJEXT) \ + motd.$(OBJEXT) rng_mt.$(OBJEXT) numeric.$(OBJEXT) \ + packet.$(OBJEXT) parse.$(OBJEXT) s_bsd_epoll.$(OBJEXT) \ + s_bsd_poll.$(OBJEXT) s_bsd_sigio.$(OBJEXT) \ + s_bsd_devpoll.$(OBJEXT) s_bsd_kqueue.$(OBJEXT) \ + s_bsd_select.$(OBJEXT) restart.$(OBJEXT) resv.$(OBJEXT) \ + rsa.$(OBJEXT) s_auth.$(OBJEXT) s_bsd.$(OBJEXT) \ + s_gline.$(OBJEXT) s_misc.$(OBJEXT) s_serv.$(OBJEXT) \ + s_user.$(OBJEXT) send.$(OBJEXT) sprintf_irc.$(OBJEXT) \ + version.$(OBJEXT) watch.$(OBJEXT) whowas.$(OBJEXT) +ircd_OBJECTS = $(am_ircd_OBJECTS) +am__DEPENDENCIES_1 = +ircd_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(ircd_LDFLAGS) \ + $(LDFLAGS) -o $@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +@MAINTAINER_MODE_FALSE@am__skiplex = test -f $@ || +LEXCOMPILE = $(LEX) $(AM_LFLAGS) $(LFLAGS) +LTLEXCOMPILE = $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(LEX) $(AM_LFLAGS) $(LFLAGS) +YLWRAP = $(top_srcdir)/ylwrap +@MAINTAINER_MODE_FALSE@am__skipyacc = test -f $@ || +am__yacc_c2h = sed -e s/cc$$/hh/ -e s/cpp$$/hpp/ -e s/cxx$$/hxx/ \ + -e s/c++$$/h++/ -e s/c$$/h/ +YACCCOMPILE = $(YACC) $(AM_YFLAGS) $(YFLAGS) +LTYACCCOMPILE = $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(YACC) $(AM_YFLAGS) $(YFLAGS) +SOURCES = $(ircd_SOURCES) +DIST_SOURCES = $(ircd_SOURCES) +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AR = @AR@ +ARGZ_H = @ARGZ_H@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DATADIR = @DATADIR@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GREP = @GREP@ +INCLTDL = @INCLTDL@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBADD_DL = @LIBADD_DL@ +LIBADD_DLD_LINK = @LIBADD_DLD_LINK@ +LIBADD_DLOPEN = @LIBADD_DLOPEN@ +LIBADD_SHL_LOAD = @LIBADD_SHL_LOAD@ +LIBDIR = @LIBDIR@ +LIBLTDL = @LIBLTDL@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LOCALSTATEDIR = @LOCALSTATEDIR@ +LTDLDEPS = @LTDLDEPS@ +LTDLINCL = @LTDLINCL@ +LTDLOPEN = @LTDLOPEN@ +LTLIBOBJS = @LTLIBOBJS@ +LT_CONFIG_H = @LT_CONFIG_H@ +LT_DLLOADERS = @LT_DLLOADERS@ +LT_DLPREOPEN = @LT_DLPREOPEN@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PREFIX = @PREFIX@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +SYSCONFDIR = @SYSCONFDIR@ +VERSION = @VERSION@ +YACC = @YACC@ +YFLAGS = @YFLAGS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +ltdl_LIBOBJS = @ltdl_LIBOBJS@ +ltdl_LTLIBOBJS = @ltdl_LTLIBOBJS@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sys_symbol_underscore = @sys_symbol_underscore@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +AUTOMAKE_OPTIONS = foreign +AM_YFLAGS = -d +AM_CPPFLAGS = $(LTDLINCL) -I$(top_srcdir)/include +ircd_LDFLAGS = -export-dynamic +ircd_LDADD = $(LIBLTDL) +ircd_DEPENDENCIES = $(LTDLDEPS) +ircd_SOURCES = balloc.c \ + channel.c \ + channel_mode.c \ + client.c \ + conf.c \ + conf_parser.y \ + conf_lexer.l \ + csvlib.c \ + dbuf.c \ + event.c \ + fdlist.c \ + getopt.c \ + hash.c \ + hook.c \ + hostmask.c \ + irc_res.c \ + irc_reslib.c \ + irc_string.c \ + ircd.c \ + ircd_signal.c \ + list.c \ + listener.c \ + log.c \ + match.c \ + memory.c \ + modules.c \ + motd.c \ + rng_mt.c \ + numeric.c \ + packet.c \ + parse.c \ + s_bsd_epoll.c \ + s_bsd_poll.c \ + s_bsd_sigio.c \ + s_bsd_devpoll.c \ + s_bsd_kqueue.c \ + s_bsd_select.c \ + restart.c \ + resv.c \ + rsa.c \ + s_auth.c \ + s_bsd.c \ + s_gline.c \ + s_misc.c \ + s_serv.c \ + s_user.c \ + send.c \ + sprintf_irc.c \ + version.c \ + watch.c \ + whowas.c + +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .l .lo .o .obj .y +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign src/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): +install-sbinPROGRAMS: $(sbin_PROGRAMS) + @$(NORMAL_INSTALL) + @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(sbindir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(sbindir)" || exit 1; \ + fi; \ + for p in $$list; do echo "$$p $$p"; done | \ + sed 's/$(EXEEXT)$$//' | \ + while read p p1; do if test -f $$p || test -f $$p1; \ + then echo "$$p"; echo "$$p"; else :; fi; \ + done | \ + sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \ + -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ + sed 'N;N;N;s,\n, ,g' | \ + $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ + { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ + if ($$2 == $$4) files[d] = files[d] " " $$1; \ + else { print "f", $$3 "/" $$4, $$1; } } \ + END { for (d in files) print "f", d, files[d] }' | \ + while read type dir files; do \ + if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ + test -z "$$files" || { \ + echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(sbindir)$$dir'"; \ + $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(sbindir)$$dir" || exit $$?; \ + } \ + ; done + +uninstall-sbinPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \ + files=`for p in $$list; do echo "$$p"; done | \ + sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ + -e 's/$$/$(EXEEXT)/' `; \ + test -n "$$list" || exit 0; \ + echo " ( cd '$(DESTDIR)$(sbindir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(sbindir)" && rm -f $$files + +clean-sbinPROGRAMS: + @list='$(sbin_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list +conf_parser.h: conf_parser.c + @if test ! -f $@; then rm -f conf_parser.c; else :; fi + @if test ! -f $@; then $(MAKE) $(AM_MAKEFLAGS) conf_parser.c; else :; fi +ircd$(EXEEXT): $(ircd_OBJECTS) $(ircd_DEPENDENCIES) $(EXTRA_ircd_DEPENDENCIES) + @rm -f ircd$(EXEEXT) + $(ircd_LINK) $(ircd_OBJECTS) $(ircd_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/balloc.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/channel.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/channel_mode.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/client.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/conf.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/conf_lexer.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/conf_parser.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/csvlib.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbuf.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/event.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fdlist.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/getopt.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hash.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hook.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hostmask.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/irc_res.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/irc_reslib.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/irc_string.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ircd.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ircd_signal.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/list.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/listener.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/log.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/match.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/memory.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/modules.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/motd.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/numeric.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/packet.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/parse.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/restart.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/resv.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rng_mt.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rsa.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/s_auth.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/s_bsd.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/s_bsd_devpoll.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/s_bsd_epoll.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/s_bsd_kqueue.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/s_bsd_poll.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/s_bsd_select.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/s_bsd_sigio.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/s_gline.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/s_misc.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/s_serv.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/s_user.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/send.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sprintf_irc.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/version.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/watch.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/whowas.Po@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +.l.c: + $(am__skiplex) $(SHELL) $(YLWRAP) $< $(LEX_OUTPUT_ROOT).c $@ -- $(LEXCOMPILE) + +.y.c: + $(am__skipyacc) $(SHELL) $(YLWRAP) $< y.tab.c $@ y.tab.h `echo $@ | $(am__yacc_c2h)` y.output $*.output -- $(YACCCOMPILE) + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +cscopelist: $(HEADERS) $(SOURCES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(PROGRAMS) +installdirs: + for dir in "$(DESTDIR)$(sbindir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." + -rm -f conf_lexer.c + -rm -f conf_parser.c + -rm -f conf_parser.h +clean: clean-am + +clean-am: clean-generic clean-libtool clean-sbinPROGRAMS \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: install-sbinPROGRAMS + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-sbinPROGRAMS + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libtool clean-sbinPROGRAMS cscopelist ctags distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-sbinPROGRAMS install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags uninstall uninstall-am uninstall-sbinPROGRAMS + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/balloc.c b/src/balloc.c new file mode 100644 index 0000000..c2c0733 --- /dev/null +++ b/src/balloc.c @@ -0,0 +1,503 @@ +/* + * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd). + * + * Copyright (C) 2002 by the past and present ircd coders, and others. + * Original credit lines follow: + * + * File: balloc.c + * Owner: Wohali (Joan Touzet) + * + * Modified 2001/11/29 for mmap() support by Aaron Sethman <androsyn@ratbox.org> + * + * 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 + */ + +/*! \file balloc.c + * \brief A block allocator + * \version $Id$ + * + * About the block allocator + * + * Basically we have three ways of getting memory off of the operating + * system. Below are this list of methods and the order of preference. + * + * 1. mmap() anonymous pages with the MMAP_ANON flag.\n + * 2. mmap() via the /dev/zero trick.\n + * 3. malloc()\n + * + * The advantages of 1 and 2 are this. We can munmap() the pages which will + * return the pages back to the operating system, thus reducing the size + * of the process as the memory is unused. malloc() on many systems just keeps + * a heap of memory to itself, which never gets given back to the OS, except on + * exit. This of course is bad, if say we have an event that causes us to allocate + * say, 200MB of memory, while our normal memory consumption would be 15MB. In the + * malloc() case, the amount of memory allocated to our process never goes down, as + * malloc() has it locked up in its heap. With the mmap() method, we can munmap() + * the block and return it back to the OS, thus causing our memory consumption to go + * down after we no longer need it. + */ + + +#include "stdinc.h" +#ifdef HAVE_MMAP /* We've got mmap() that is good */ +#include <sys/mman.h> + +/* HP-UX sucks */ +#ifdef MAP_ANONYMOUS +#ifndef MAP_ANON +#define MAP_ANON MAP_ANONYMOUS +#endif +#endif /* MAP_ANONYMOUS */ +#endif + +#include "list.h" +#include "balloc.h" +#include "memory.h" +#include "irc_string.h" +#include "client.h" +#include "send.h" +#include "numeric.h" +#include "fdlist.h" +#include "event.h" + + +static BlockHeap *heap_list = NULL; + +static int BlockHeapGarbageCollect(BlockHeap *); +static void heap_garbage_collection(void *); + +/*! \brief Returns memory for the block back to either the malloc heap + * in case of !HAVE_MMAP, or back to the OS otherwise. + * \param ptr Pointer to memory to be freed + * \param size The size of the memory space + */ +static void +free_block(void *ptr, size_t size) +{ +#ifdef HAVE_MMAP + munmap(ptr, size); +#else + free(ptr); +#endif +} + +#ifdef HAVE_MMAP +#ifndef MAP_ANON /* But we cannot mmap() anonymous pages */ + /* So we mmap() /dev/zero, which is just as good */ +static fde_t dpfd; +#endif +#endif + +/*! \brief Opens /dev/zero and saves the file handle for + * future allocations. + */ +void +initBlockHeap(void) +{ +#ifdef HAVE_MMAP +#ifndef MAP_ANON + int zero_fd = open("/dev/zero", O_RDWR); + + if (zero_fd < 0) + outofmemory(); + fd_open(&dpfd, zero_fd, 0, "Anonymous mmap()"); +#endif + eventAdd("heap_garbage_collection", &heap_garbage_collection, NULL, 119); +#endif +} + +/*! + * \param size Size of block to allocate + * \return Address pointer to allocated data space + */ +static void * +get_block(size_t size) +{ +#ifdef HAVE_MMAP + void *ptr = NULL; + +#ifndef MAP_ANON + ptr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE, dpfd.fd, 0); +#else + ptr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); +#endif + return ptr == MAP_FAILED ? NULL : ptr; +#else + return malloc(size); +#endif +} + +static void +heap_garbage_collection(void *arg) +{ + BlockHeap *bh; + + for (bh = heap_list; bh != NULL; bh = bh->next) + BlockHeapGarbageCollect(bh); +} + +/*! \brief Allocates a new block for addition to a blockheap + * \param bh Pointer to parent blockheap + * \return 0 if successful, 1 if not + */ +static int +newblock(BlockHeap *bh) +{ + MemBlock *newblk = NULL; + Block *b = NULL; + int i = 0; + void *offset = NULL; + + /* Setup the initial data structure. */ + if ((b = calloc(1, sizeof(Block))) == NULL) + return 1; + + b->freeElems = bh->elemsPerBlock; + b->next = bh->base; + b->alloc_size = bh->elemsPerBlock * (bh->elemSize + sizeof(MemBlock)); + b->elems = get_block(b->alloc_size); + + if (b->elems == NULL) + return 1; + + offset = b->elems; + + /* Setup our blocks now */ + for (; i < bh->elemsPerBlock; ++i) + { + void *data; + + newblk = offset; + newblk->block = b; + data = (void *)((size_t)offset + sizeof(MemBlock)); + + dlinkAdd(data, &newblk->self, &b->free_list); + offset = (void *)((size_t)offset + bh->elemSize + sizeof(MemBlock)); + } + + ++bh->blocksAllocated; + bh->freeElems += bh->elemsPerBlock; + bh->base = b; + + return 0; +} + +/*! \brief Creates a new blockheap + * + * Creates a new blockheap from which smaller blocks can be allocated. + * Intended to be used instead of multiple calls to malloc() when + * performance is an issue. + * + * \param name Name of the blockheap + * \param elemsize Size of the basic element to be stored + * \param elemsperblock Number of elements to be stored in a single block of + * memory. When the blockheap runs out of free memory, + * it will allocate elemsize * elemsperblock more. + * \return Pointer to new BlockHeap, or NULL if unsuccessful + */ +BlockHeap * +BlockHeapCreate(const char *const name, size_t elemsize, int elemsperblock) +{ + BlockHeap *bh = NULL; + assert(elemsize > 0 && elemsperblock > 0); + + /* Catch idiotic requests up front */ + if ((elemsize <= 0) || (elemsperblock <= 0)) + outofmemory(); /* die.. out of memory */ + + /* Allocate our new BlockHeap */ + if ((bh = calloc(1, sizeof(BlockHeap))) == NULL) + outofmemory(); /* die.. out of memory */ + + if ((elemsize % sizeof(void *)) != 0) + { + /* Pad to even pointer boundary */ + elemsize += sizeof(void *); + elemsize &= ~(sizeof(void *) - 1); + } + + bh->name = name; + bh->elemSize = elemsize; + bh->elemsPerBlock = elemsperblock; + + /* Be sure our malloc was successful */ + if (newblock(bh)) + { + if (bh != NULL) + free(bh); + + outofmemory(); /* die.. out of memory */ + } + + bh->next = heap_list; + heap_list = bh; + + return bh; +} + +/*! \brief Returns a pointer to a struct within our BlockHeap that's free for + * the taking. + * \param bh Pointer to the Blockheap + * \return Address pointer to allocated data space, or NULL if unsuccessful + */ +void * +BlockHeapAlloc(BlockHeap *bh) +{ + Block *walker = NULL; + dlink_node *new_node = NULL; + + assert(bh != NULL); + + if (bh->freeElems == 0) + { + /* Allocate new block and assign */ + /* newblock returns 1 if unsuccessful, 0 if not */ + if (newblock(bh)) + { + /* That didn't work..try to garbage collect */ + BlockHeapGarbageCollect(bh); + + if (newblock(bh)) + outofmemory(); /* Well that didn't work either...bail */ + } + } + + for (walker = bh->base; walker != NULL; walker = walker->next) + { + if (walker->freeElems > 0) + { + --bh->freeElems; + --walker->freeElems; + new_node = walker->free_list.head; + + dlinkDelete(new_node, &walker->free_list); + assert(new_node->data != NULL); + + memset(new_node->data, 0, bh->elemSize); + return new_node->data; + } + } + + assert(0 == 1); + outofmemory(); + return NULL; +} + +/*! \brief Returns an element to the free pool, does not free() + * \param bh Pointer to BlockHeap containing element + * \param ptr Pointer to element to be "freed" + * \return 0 if successful, 1 if element not contained within BlockHeap + */ +int +BlockHeapFree(BlockHeap *bh, void *ptr) +{ + Block *block = NULL; + struct MemBlock *memblock = NULL; + + assert(bh != NULL); + assert(ptr != NULL); + + memblock = (void *)((size_t)ptr - sizeof(MemBlock)); + assert(memblock->block != NULL); + + if (memblock->block == NULL) + outofmemory(); + + block = memblock->block; + ++bh->freeElems; + ++block->freeElems; + mem_frob(ptr, bh->elemSize); + + dlinkAdd(ptr, &memblock->self, &block->free_list); + return 0; +} + +/*! \brief Performs garbage collection on the block heap. + * + * Performs garbage collection on the block heap. Any blocks that are + * completely unallocated are removed from the heap. Garbage collection + * will \b never remove the root node of the heap. + * + * \param bh Pointer to the BlockHeap to be cleaned up + * \return 0 if successful, 1 if bh == NULL + */ +static int +BlockHeapGarbageCollect(BlockHeap *bh) +{ + Block *walker = NULL, *last = NULL; + + assert(bh != NULL); + + if (bh->freeElems < bh->elemsPerBlock || bh->blocksAllocated == 1) + { + /* There couldn't possibly be an entire free block. Return. */ + return 0; + } + + walker = bh->base; + + while (walker != NULL) + { + if (walker->freeElems == bh->elemsPerBlock) + { + free_block(walker->elems, walker->alloc_size); + + if (last != NULL) + { + last->next = walker->next; + + if (walker != NULL) + free(walker); + walker = last->next; + } + else + { + bh->base = walker->next; + + if (walker != NULL) + free(walker); + walker = bh->base; + } + + --bh->blocksAllocated; + bh->freeElems -= bh->elemsPerBlock; + } + else + { + last = walker; + walker = walker->next; + } + } + + return 0; +} + +/*! \brief Completely free()s a BlockHeap. Use for cleanup. + * \param bh Pointer to the BlockHeap to be destroyed + * \return 0 if successful, 1 if bh == NULL + */ +int +BlockHeapDestroy(BlockHeap *bh) +{ + Block *walker = NULL, *next = NULL; + + if (bh == NULL) + return 1; + + for (walker = bh->base; walker != NULL; walker = next) + { + next = walker->next; + free_block(walker->elems, walker->alloc_size); + + if (walker != NULL) + free(walker); + } + + if (heap_list == bh) + heap_list = bh->next; + else { + BlockHeap *prev; + + for (prev = heap_list; prev->next != bh; prev = prev->next) + /* nothing */ ; + prev->next = bh->next; + } + + free(bh); + return 0; +} + +/*! \brief Returns the number of bytes being used + * \param bh Pointer to a BlockHeap + * \return Number of bytes being used + */ +static size_t +block_heap_get_used_mem(const BlockHeap *const bh) +{ + return(((bh->blocksAllocated * + bh->elemsPerBlock)-bh->freeElems) * + (bh->elemSize + sizeof(MemBlock))); +} + +/*! \brief Returns the number of bytes being free for further allocations + * \param bh Pointer to a BlockHeap + * \return Number of bytes being free for further allocations + */ +static size_t +block_heap_get_free_mem(const BlockHeap *const bh) +{ + return(bh->freeElems * (bh->elemSize + sizeof(MemBlock))); +} + +/*! \brief Returns the total number of bytes of memory belonging to a heap + * \param bh Pointer to a BlockHeap + * \return Total number of bytes of memory belonging to a heap + */ +static size_t +block_heap_get_size_mem(const BlockHeap *const bh) +{ + return(((bh->blocksAllocated * + bh->elemsPerBlock)) * + (bh->elemSize + sizeof(MemBlock))); +} + +/*! \brief Returns the number of elements being used. + * \param bh Pointer to a BlockHeap + * \return Number of elements being free for further allocations + */ +static unsigned int +block_heap_get_used_elm(const BlockHeap *const bh) +{ + return((bh->blocksAllocated * + bh->elemsPerBlock)-bh->freeElems); +} + +/*! \brief Returns the number of elements being free for further allocations. + * \param bh Pointer to a BlockHeap + * \return Number of elements being free for further allocations + */ +static unsigned int +block_heap_get_free_elm(const BlockHeap *const bh) +{ + return(bh->freeElems); +} + +/*! \brief Returns the number of total elements belonging to a heap. + * Includes \b free and \b used elements. + * \param bh Pointer to a BlockHeap + * \return Number of total elements belonging to a heap + */ +static unsigned int +block_heap_get_size_elm(const BlockHeap *const bh) +{ + return(bh->blocksAllocated * bh->elemsPerBlock); +} + +void +block_heap_report_stats(struct Client *client_p) +{ + const BlockHeap *bh = NULL; + + for (bh = heap_list; bh != NULL; bh = bh->next) + sendto_one(client_p, ":%s %d %s z :%s mempool: used %u/%u free %u/%u (size %u/%u)", + me.name, RPL_STATSDEBUG, client_p->name, bh->name, + block_heap_get_used_elm(bh), + block_heap_get_used_mem(bh), + block_heap_get_free_elm(bh), + block_heap_get_free_mem(bh), + block_heap_get_size_elm(bh), + block_heap_get_size_mem(bh)); +} diff --git a/src/channel.c b/src/channel.c new file mode 100644 index 0000000..14e6a14 --- /dev/null +++ b/src/channel.c @@ -0,0 +1,864 @@ +/* + * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd). + * + * Copyright (C) 2002 by the past and present ircd coders, and others. + * + * 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 + */ + +/*! \file channel.c + * \brief Responsible for managing channels, members, bans and topics + * \version $Id$ + */ + +#include "stdinc.h" +#include "list.h" +#include "channel.h" +#include "channel_mode.h" +#include "client.h" +#include "hash.h" +#include "hostmask.h" +#include "irc_string.h" +#include "sprintf_irc.h" +#include "ircd.h" +#include "numeric.h" +#include "s_serv.h" /* captab */ +#include "s_user.h" +#include "send.h" +#include "conf.h" /* ConfigFileEntry, ConfigChannel */ +#include "event.h" +#include "memory.h" +#include "balloc.h" + +struct config_channel_entry ConfigChannel; +dlink_list global_channel_list = { NULL, NULL, 0 }; +BlockHeap *ban_heap; /*! \todo ban_heap shouldn't be a global var */ + +static BlockHeap *member_heap = NULL; +static BlockHeap *channel_heap = NULL; + +static char buf[IRCD_BUFSIZE]; +static char modebuf[MODEBUFLEN]; +static char parabuf[MODEBUFLEN]; + + +/*! \brief Initializes the channel blockheap, adds known channel CAPAB + */ +void +init_channels(void) +{ + add_capability("EX", CAP_EX, 1); + add_capability("IE", CAP_IE, 1); + add_capability("CHW", CAP_CHW, 1); + + channel_heap = BlockHeapCreate("channel", sizeof(struct Channel), CHANNEL_HEAP_SIZE); + ban_heap = BlockHeapCreate("ban", sizeof(struct Ban), BAN_HEAP_SIZE); + member_heap = BlockHeapCreate("member", sizeof(struct Membership), CHANNEL_HEAP_SIZE*2); +} + +/*! \brief adds a user to a channel by adding another link to the + * channels member chain. + * \param chptr pointer to channel to add client to + * \param who pointer to client (who) to add + * \param flags flags for chanops etc + * \param flood_ctrl whether to count this join in flood calculations + */ +void +add_user_to_channel(struct Channel *chptr, struct Client *who, + unsigned int flags, int flood_ctrl) +{ + struct Membership *ms = NULL; + + if (GlobalSetOptions.joinfloodtime > 0) + { + if (flood_ctrl) + chptr->number_joined++; + + chptr->number_joined -= (CurrentTime - chptr->last_join_time) * + (((float)GlobalSetOptions.joinfloodcount) / + (float)GlobalSetOptions.joinfloodtime); + + if (chptr->number_joined <= 0) + { + chptr->number_joined = 0; + ClearJoinFloodNoticed(chptr); + } + else if (chptr->number_joined >= GlobalSetOptions.joinfloodcount) + { + chptr->number_joined = GlobalSetOptions.joinfloodcount; + + if (!IsSetJoinFloodNoticed(chptr)) + { + SetJoinFloodNoticed(chptr); + sendto_realops_flags(UMODE_BOTS, L_ALL, + "Possible Join Flooder %s on %s target: %s", + get_client_name(who, HIDE_IP), + who->servptr->name, chptr->chname); + } + } + + chptr->last_join_time = CurrentTime; + } + + ms = BlockHeapAlloc(member_heap); + ms->client_p = who; + ms->chptr = chptr; + ms->flags = flags; + + dlinkAdd(ms, &ms->channode, &chptr->members); + dlinkAdd(ms, &ms->usernode, &who->channel); +} + +/*! \brief deletes an user from a channel by removing a link in the + * channels member chain. + * \param member pointer to Membership struct + */ +void +remove_user_from_channel(struct Membership *member) +{ + struct Client *client_p = member->client_p; + struct Channel *chptr = member->chptr; + + dlinkDelete(&member->channode, &chptr->members); + dlinkDelete(&member->usernode, &client_p->channel); + + BlockHeapFree(member_heap, member); + + if (chptr->members.head == NULL) + destroy_channel(chptr); +} + +/* send_members() + * + * inputs - + * output - NONE + * side effects - + */ +static void +send_members(struct Client *client_p, struct Channel *chptr, + char *lmodebuf, char *lparabuf) +{ + struct Membership *ms; + dlink_node *ptr; + int tlen; /* length of text to append */ + char *t, *start; /* temp char pointer */ + + start = t = buf + ircsprintf(buf, ":%s SJOIN %lu %s %s %s:", + ID_or_name(&me, client_p), + (unsigned long)chptr->channelts, + chptr->chname, lmodebuf, lparabuf); + + DLINK_FOREACH(ptr, chptr->members.head) + { + ms = ptr->data; + + tlen = strlen(IsCapable(client_p, CAP_TS6) ? + ID(ms->client_p) : ms->client_p->name) + 1; /* nick + space */ + + if (ms->flags & CHFL_CHANOP) + tlen++; +#ifdef HALFOPS + else if (ms->flags & CHFL_HALFOP) + tlen++; +#endif + if (ms->flags & CHFL_VOICE) + tlen++; + + /* space will be converted into CR, but we also need space for LF.. + * That's why we use '- 1' here + * -adx */ + if (t + tlen - buf > IRCD_BUFSIZE - 1) + { + *(t - 1) = '\0'; /* kill the space and terminate the string */ + sendto_one(client_p, "%s", buf); + t = start; + } + + if ((ms->flags & (CHFL_CHANOP | CHFL_HALFOP))) + *t++ = (!(ms->flags & CHFL_CHANOP) && IsCapable(client_p, CAP_HOPS)) ? + '%' : '@'; + if ((ms->flags & CHFL_VOICE)) + *t++ = '+'; + + if (IsCapable(client_p, CAP_TS6)) + strcpy(t, ID(ms->client_p)); + else + strcpy(t, ms->client_p->name); + t += strlen(t); + *t++ = ' '; + } + + /* should always be non-NULL unless we have a kind of persistent channels */ + if (chptr->members.head != NULL) + t--; /* take the space out */ + *t = '\0'; + sendto_one(client_p, "%s", buf); +} + +/*! \brief sends +b/+e/+I + * \param client_p client pointer to server + * \param chptr pointer to channel + * \param top pointer to top of mode link list to send + * \param flag char flag flagging type of mode. Currently this can be 'b', e' or 'I' + */ +static void +send_mode_list(struct Client *client_p, struct Channel *chptr, + dlink_list *top, char flag) +{ + int ts5 = !IsCapable(client_p, CAP_TS6); + dlink_node *lp; + struct Ban *banptr; + char pbuf[IRCD_BUFSIZE]; + int tlen, mlen, cur_len, count = 0; + char *mp = NULL, *pp = pbuf; + + if (top == NULL || top->length == 0) + return; + + if (ts5) + mlen = ircsprintf(buf, ":%s MODE %s +", me.name, chptr->chname); + else + mlen = ircsprintf(buf, ":%s BMASK %lu %s %c :", me.id, + (unsigned long)chptr->channelts, chptr->chname, flag); + + /* MODE needs additional one byte for space between buf and pbuf */ + cur_len = mlen + ts5; + mp = buf + mlen; + + DLINK_FOREACH(lp, top->head) + { + banptr = lp->data; + + /* must add another b/e/I letter if we use MODE */ + tlen = banptr->len + 3 + ts5; + + /* + * send buffer and start over if we cannot fit another ban, + * or if the target is non-ts6 and we have too many modes in + * in this line. + */ + if (cur_len + (tlen - 1) > IRCD_BUFSIZE - 2 || + (!IsCapable(client_p, CAP_TS6) && + (count >= MAXMODEPARAMS || pp - pbuf >= MODEBUFLEN))) + { + *(pp - 1) = '\0'; /* get rid of trailing space on buffer */ + sendto_one(client_p, "%s%s%s", buf, ts5 ? " " : "", pbuf); + + cur_len = mlen + ts5; + mp = buf + mlen; + pp = pbuf; + count = 0; + } + + count++; + if (ts5) + { + *mp++ = flag; + *mp = '\0'; + } + + pp += ircsprintf(pp, "%s!%s@%s ", banptr->name, banptr->username, + banptr->host); + cur_len += tlen; + } + + *(pp - 1) = '\0'; /* get rid of trailing space on buffer */ + sendto_one(client_p, "%s%s%s", buf, ts5 ? " " : "", pbuf); +} + +/*! \brief send "client_p" a full list of the modes for channel chptr + * \param client_p pointer to client client_p + * \param chptr pointer to channel pointer + */ +void +send_channel_modes(struct Client *client_p, struct Channel *chptr) +{ + *modebuf = *parabuf = '\0'; + channel_modes(chptr, client_p, modebuf, parabuf); + send_members(client_p, chptr, modebuf, parabuf); + + send_mode_list(client_p, chptr, &chptr->banlist, 'b'); + + if (IsCapable(client_p, CAP_EX)) + send_mode_list(client_p, chptr, &chptr->exceptlist, 'e'); + if (IsCapable(client_p, CAP_IE)) + send_mode_list(client_p, chptr, &chptr->invexlist, 'I'); +} + +/*! \brief check channel name for invalid characters + * \param name pointer to channel name string + * \param local indicates whether it's a local or remote creation + * \return 0 if invalid, 1 otherwise + */ +int +check_channel_name(const char *name, int local) +{ + const char *p = name; + const int max_length = local ? LOCAL_CHANNELLEN : CHANNELLEN; + assert(name != NULL); + + if (!IsChanPrefix(*p)) + return 0; + + if (!local || !ConfigChannel.disable_fake_channels) + { + while (*++p) + if (!IsChanChar(*p)) + return 0; + } + else + { + while (*++p) + if (!IsVisibleChanChar(*p)) + return 0; + } + + return p - name <= max_length; +} + +void +remove_ban(struct Ban *bptr, dlink_list *list) +{ + dlinkDelete(&bptr->node, list); + + MyFree(bptr->name); + MyFree(bptr->username); + MyFree(bptr->host); + MyFree(bptr->who); + + BlockHeapFree(ban_heap, bptr); +} + +/* free_channel_list() + * + * inputs - pointer to dlink_list + * output - NONE + * side effects - + */ +void +free_channel_list(dlink_list *list) +{ + dlink_node *ptr = NULL, *next_ptr = NULL; + + DLINK_FOREACH_SAFE(ptr, next_ptr, list->head) + remove_ban(ptr->data, list); + + assert(list->tail == NULL && list->head == NULL); +} + +/*! \brief Get Channel block for chname (and allocate a new channel + * block, if it didn't exist before) + * \param chname channel name + * \return channel block + */ +struct Channel * +make_channel(const char *chname) +{ + struct Channel *chptr = NULL; + + assert(!EmptyString(chname)); + + chptr = BlockHeapAlloc(channel_heap); + + /* doesn't hurt to set it here */ + chptr->channelts = CurrentTime; + chptr->last_join_time = CurrentTime; + + strlcpy(chptr->chname, chname, sizeof(chptr->chname)); + dlinkAdd(chptr, &chptr->node, &global_channel_list); + + hash_add_channel(chptr); + + return chptr; +} + +/*! \brief walk through this channel, and destroy it. + * \param chptr channel pointer + */ +void +destroy_channel(struct Channel *chptr) +{ + dlink_node *ptr = NULL, *ptr_next = NULL; + + DLINK_FOREACH_SAFE(ptr, ptr_next, chptr->invites.head) + del_invite(chptr, ptr->data); + + /* free ban/exception/invex lists */ + free_channel_list(&chptr->banlist); + free_channel_list(&chptr->exceptlist); + free_channel_list(&chptr->invexlist); + + dlinkDelete(&chptr->node, &global_channel_list); + hash_del_channel(chptr); + + BlockHeapFree(channel_heap, chptr); +} + +/*! + * \param chptr pointer to channel + * \return string pointer "=" if public, "@" if secret else "*" + */ +static const char * +channel_pub_or_secret(const struct Channel *chptr) +{ + if (SecretChannel(chptr)) + return "@"; + if (PrivateChannel(chptr)) + return "*"; + return "="; +} + +/*! \brief lists all names on given channel + * \param source_p pointer to client struct requesting names + * \param chptr pointer to channel block + * \param show_eon show ENDOFNAMES numeric or not + * (don't want it with /names with no params) + */ +void +channel_member_names(struct Client *source_p, struct Channel *chptr, + int show_eon) +{ + struct Client *target_p = NULL; + struct Membership *ms = NULL; + dlink_node *ptr = NULL; + char lbuf[IRCD_BUFSIZE + 1]; + char *t = NULL, *start = NULL; + int tlen = 0; + int is_member = IsMember(source_p, chptr); + int multi_prefix = HasCap(source_p, CAP_MULTI_PREFIX) != 0; + + if (PubChannel(chptr) || is_member) + { + t = lbuf + ircsprintf(lbuf, form_str(RPL_NAMREPLY), + me.name, source_p->name, + channel_pub_or_secret(chptr), + chptr->chname); + start = t; + + DLINK_FOREACH(ptr, chptr->members.head) + { + ms = ptr->data; + target_p = ms->client_p; + + if (HasUMode(target_p, UMODE_INVISIBLE) && !is_member) + continue; + + tlen = strlen(target_p->name) + 1; /* nick + space */ + + if (!multi_prefix) + { + if (ms->flags & (CHFL_CHANOP | CHFL_HALFOP | CHFL_VOICE)) + ++tlen; + } + else + { + if (ms->flags & CHFL_CHANOP) + ++tlen; + if (ms->flags & CHFL_HALFOP) + ++tlen; + if (ms->flags & CHFL_VOICE) + ++tlen; + } + + if (t + tlen - lbuf > IRCD_BUFSIZE - 2) + { + *(t - 1) = '\0'; + sendto_one(source_p, "%s", lbuf); + t = start; + } + + t += ircsprintf(t, "%s%s ", get_member_status(ms, multi_prefix), + target_p->name); + } + + if (tlen != 0) + { + *(t - 1) = '\0'; + sendto_one(source_p, "%s", lbuf); + } + } + + if (show_eon) + sendto_one(source_p, form_str(RPL_ENDOFNAMES), + me.name, source_p->name, chptr->chname); +} + +/*! \brief adds client to invite list + * \param chptr pointer to channel block + * \param who pointer to client to add invite to + */ +void +add_invite(struct Channel *chptr, struct Client *who) +{ + del_invite(chptr, who); + + /* + * delete last link in chain if the list is max length + */ + if (dlink_list_length(&who->localClient->invited) >= + ConfigChannel.max_chans_per_user) + del_invite(who->localClient->invited.tail->data, who); + + /* add client to channel invite list */ + dlinkAdd(who, make_dlink_node(), &chptr->invites); + + /* add channel to the end of the client invite list */ + dlinkAdd(chptr, make_dlink_node(), &who->localClient->invited); +} + +/*! \brief Delete Invite block from channel invite list + * and client invite list + * \param chptr pointer to Channel struct + * \param who pointer to client to remove invites from + */ +void +del_invite(struct Channel *chptr, struct Client *who) +{ + dlink_node *ptr = NULL; + + if ((ptr = dlinkFindDelete(&who->localClient->invited, chptr))) + free_dlink_node(ptr); + + if ((ptr = dlinkFindDelete(&chptr->invites, who))) + free_dlink_node(ptr); +} + +/* get_member_status() + * + * inputs - pointer to struct Membership + * - YES if we can combine different flags + * output - string either @, +, % or "" depending on whether + * chanop, voiced or user + * side effects - + * + * NOTE: Returned string is usually a static buffer + * (like in get_client_name) + */ +const char * +get_member_status(const struct Membership *ms, int combine) +{ + static char buffer[4]; + char *p = NULL; + + if (ms == NULL) + return ""; + p = buffer; + + if (ms->flags & CHFL_CHANOP) + { + if (!combine) + return "@"; + *p++ = '@'; + } + +#ifdef HALFOPS + if (ms->flags & CHFL_HALFOP) + { + if (!combine) + return "%"; + *p++ = '%'; + } +#endif + + if (ms->flags & CHFL_VOICE) + *p++ = '+'; + *p = '\0'; + + return buffer; +} + +/*! + * \param who pointer to Client to check + * \param list pointer to ban list to search + * \return 1 if ban found for given n!u\@h mask, 0 otherwise + * + */ +static int +find_bmask(const struct Client *who, const dlink_list *const list) +{ + const dlink_node *ptr = NULL; + + DLINK_FOREACH(ptr, list->head) + { + const struct Ban *bp = ptr->data; + + if (match(bp->name, who->name) && match(bp->username, who->username)) + { + switch (bp->type) + { + case HM_HOST: + if (match(bp->host, who->host) || match(bp->host, who->sockhost)) + return 1; + break; + case HM_IPV4: + if (who->localClient->aftype == AF_INET) + if (match_ipv4(&who->localClient->ip, &bp->addr, bp->bits)) + return 1; + break; +#ifdef IPV6 + case HM_IPV6: + if (who->localClient->aftype == AF_INET6) + if (match_ipv6(&who->localClient->ip, &bp->addr, bp->bits)) + return 1; + break; +#endif + default: + assert(0); + } + } + } + + return 0; +} + +/*! + * \param chptr pointer to channel block + * \param who pointer to client to check access fo + * \return 0 if not banned, 1 otherwise + */ +int +is_banned(const struct Channel *chptr, const struct Client *who) +{ + if (find_bmask(who, &chptr->banlist)) + if (!find_bmask(who, &chptr->exceptlist)) + return 1; + + return 0; +} + +/*! + * \param source_p pointer to client attempting to join + * \param chptr pointer to channel + * \param key key sent by client attempting to join if present + * \return ERR_BANNEDFROMCHAN, ERR_INVITEONLYCHAN, ERR_CHANNELISFULL + * or 0 if allowed to join. + */ +int +can_join(struct Client *source_p, struct Channel *chptr, const char *key) +{ + if (is_banned(chptr, source_p)) + return ERR_BANNEDFROMCHAN; + +#ifdef HAVE_LIBCRYPTO + if ((chptr->mode.mode & MODE_SSLONLY) && !source_p->localClient->fd.ssl) + return ERR_SSLONLYCHAN; +#endif + + if ((chptr->mode.mode & MODE_REGONLY) && !HasUMode(source_p, UMODE_REGISTERED)) + return ERR_NEEDREGGEDNICK; + + if ((chptr->mode.mode & MODE_OPERONLY) && !HasUMode(source_p, UMODE_OPER)) + return ERR_OPERONLYCHAN; + + if (chptr->mode.mode & MODE_INVITEONLY) + if (!dlinkFind(&source_p->localClient->invited, chptr)) + if (!find_bmask(source_p, &chptr->invexlist)) + return ERR_INVITEONLYCHAN; + + if (chptr->mode.key[0] && (!key || strcmp(chptr->mode.key, key))) + return ERR_BADCHANNELKEY; + + if (chptr->mode.limit && dlink_list_length(&chptr->members) >= + chptr->mode.limit) + return ERR_CHANNELISFULL; + + return 0; +} + +int +has_member_flags(struct Membership *ms, unsigned int flags) +{ + if (ms != NULL) + return ms->flags & flags; + return 0; +} + +struct Membership * +find_channel_link(struct Client *client_p, struct Channel *chptr) +{ + dlink_node *ptr = NULL; + + if (!IsClient(client_p)) + return NULL; + + DLINK_FOREACH(ptr, client_p->channel.head) + if (((struct Membership *)ptr->data)->chptr == chptr) + return ptr->data; + + return NULL; +} + +/*! + * \param chptr pointer to Channel struct + * \param source_p pointer to Client struct + * \param ms pointer to Membership struct (can be NULL) + * \return CAN_SEND_OPV if op or voiced on channel\n + * CAN_SEND_NONOP if can send to channel but is not an op\n + * ERR_CANNOTSENDTOCHAN or ERR_NEEDREGGEDNICK if they cannot send to channel\n + */ +int +can_send(struct Channel *chptr, struct Client *source_p, struct Membership *ms) +{ + if (IsServer(source_p) || HasFlag(source_p, FLAGS_SERVICE)) + return CAN_SEND_OPV; + + if (MyClient(source_p) && !IsExemptResv(source_p)) + if (!(HasUMode(source_p, UMODE_OPER) && ConfigFileEntry.oper_pass_resv)) + if (!hash_find_resv(chptr->chname) == ConfigChannel.restrict_channels) + return ERR_CANNOTSENDTOCHAN; + + if (ms != NULL || (ms = find_channel_link(source_p, chptr))) + { + if (ms->flags & (CHFL_CHANOP|CHFL_HALFOP|CHFL_VOICE)) + return CAN_SEND_OPV; + + /* cache can send if quiet_on_ban and banned */ + if (ConfigChannel.quiet_on_ban && MyClient(source_p)) + { + if (ms->flags & CHFL_BAN_SILENCED) + return ERR_CANNOTSENDTOCHAN; + + if (!(ms->flags & CHFL_BAN_CHECKED)) + { + if (is_banned(chptr, source_p)) + { + ms->flags |= (CHFL_BAN_CHECKED|CHFL_BAN_SILENCED); + return ERR_CANNOTSENDTOCHAN; + } + + ms->flags |= CHFL_BAN_CHECKED; + } + } + } + else if (chptr->mode.mode & MODE_NOPRIVMSGS) + return ERR_CANNOTSENDTOCHAN; + + if (chptr->mode.mode & MODE_MODERATED) + return ERR_CANNOTSENDTOCHAN; + + return CAN_SEND_NONOP; +} + +/*! \brief Updates the client's oper_warn_count_down, warns the + * IRC operators if necessary, and updates + * join_leave_countdown as needed. + * \param source_p pointer to struct Client to check + * \param name channel name or NULL if this is a part. + */ +void +check_spambot_warning(struct Client *source_p, const char *name) +{ + int t_delta = 0; + int decrement_count = 0; + + if ((GlobalSetOptions.spam_num && + (source_p->localClient->join_leave_count >= + GlobalSetOptions.spam_num))) + { + if (source_p->localClient->oper_warn_count_down > 0) + source_p->localClient->oper_warn_count_down--; + else + source_p->localClient->oper_warn_count_down = 0; + + if (source_p->localClient->oper_warn_count_down == 0) + { + /* Its already known as a possible spambot */ + if (name != NULL) + sendto_realops_flags(UMODE_BOTS, L_ALL, + "User %s (%s@%s) trying to join %s is a possible spambot", + source_p->name, source_p->username, + source_p->host, name); + else + sendto_realops_flags(UMODE_BOTS, L_ALL, + "User %s (%s@%s) is a possible spambot", + source_p->name, source_p->username, + source_p->host); + source_p->localClient->oper_warn_count_down = OPER_SPAM_COUNTDOWN; + } + } + else + { + if ((t_delta = (CurrentTime - source_p->localClient->last_leave_time)) > + JOIN_LEAVE_COUNT_EXPIRE_TIME) + { + decrement_count = (t_delta / JOIN_LEAVE_COUNT_EXPIRE_TIME); + if (decrement_count > source_p->localClient->join_leave_count) + source_p->localClient->join_leave_count = 0; + else + source_p->localClient->join_leave_count -= decrement_count; + } + else + { + if ((CurrentTime - (source_p->localClient->last_join_time)) < + GlobalSetOptions.spam_time) + { + /* oh, its a possible spambot */ + source_p->localClient->join_leave_count++; + } + } + + if (name != NULL) + source_p->localClient->last_join_time = CurrentTime; + else + source_p->localClient->last_leave_time = CurrentTime; + } +} + +/*! \brief compares usercount and servercount against their split + * values and adjusts splitmode accordingly + * \param unused Unused address pointer + */ +void +check_splitmode(void *unused) +{ + if (splitchecking && (ConfigChannel.no_join_on_split || + ConfigChannel.no_create_on_split)) + { + const unsigned int server = dlink_list_length(&global_serv_list); + + if (!splitmode && ((server < split_servers) || (Count.total < split_users))) + { + splitmode = 1; + + sendto_realops_flags(UMODE_ALL,L_ALL, + "Network split, activating splitmode"); + eventAddIsh("check_splitmode", check_splitmode, NULL, 10); + } + else if (splitmode && (server > split_servers) && (Count.total > split_users)) + { + splitmode = 0; + + sendto_realops_flags(UMODE_ALL, L_ALL, + "Network rejoined, deactivating splitmode"); + eventDelete(check_splitmode, NULL); + } + } +} + +/*! \brief Sets the channel topic for chptr + * \param chptr Pointer to struct Channel + * \param topic The topic string + * \param topic_info n!u\@h formatted string of the topic setter + * \param topicts timestamp on the topic + */ +void +set_channel_topic(struct Channel *chptr, const char *topic, + const char *topic_info, time_t topicts) +{ + strlcpy(chptr->topic, topic, sizeof(chptr->topic)); + strlcpy(chptr->topic_info, topic_info, sizeof(chptr->topic_info)); + chptr->topic_time = topicts; +} diff --git a/src/channel_mode.c b/src/channel_mode.c new file mode 100644 index 0000000..4751ec4 --- /dev/null +++ b/src/channel_mode.c @@ -0,0 +1,1797 @@ +/* + * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd). + * channel_mode.c: Controls modes on channels. + * + * Copyright (C) 2005 by the past and present ircd coders, and others. + * + * 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 + * + * $Id$ + */ + +#include "stdinc.h" +#include "list.h" +#include "channel.h" +#include "channel_mode.h" +#include "client.h" +#include "hash.h" +#include "hostmask.h" +#include "irc_string.h" +#include "sprintf_irc.h" +#include "ircd.h" +#include "numeric.h" +#include "s_serv.h" /* captab */ +#include "s_user.h" +#include "send.h" +#include "whowas.h" +#include "conf.h" /* ConfigFileEntry, ConfigChannel */ +#include "event.h" +#include "memory.h" +#include "balloc.h" +#include "log.h" +#include "parse.h" + +/* some small utility functions */ +static char *check_string(char *); +static char *fix_key(char *); +static char *fix_key_old(char *); +static void chm_nosuch(struct Client *, struct Client *, + struct Channel *, int, int *, char **, int *, int, + int, char, void *, const char *); +static void chm_simple(struct Client *, struct Client *, struct Channel *, + int, int *, char **, int *, int, int, char, void *, + const char *); +static void chm_registered(struct Client *, struct Client *, struct Channel *, + int, int *, char **, int *, int, int, char, void *, + const char *); +static void chm_limit(struct Client *, struct Client *, struct Channel *, + int, int *, char **, int *, int, int, char, void *, + const char *); +static void chm_key(struct Client *, struct Client *, struct Channel *, + int, int *, char **, int *, int, int, char, void *, + const char *); +static void chm_op(struct Client *, struct Client *, struct Channel *, int, + int *, char **, int *, int, int, char, void *, + const char *); +#ifdef HALFOPS +static void chm_hop(struct Client *, struct Client *, struct Channel *, int, + int *, char **, int *, int, int, char, void *, + const char *); +#endif +static void chm_voice(struct Client *, struct Client *, struct Channel *, + int, int *, char **, int *, int, int, char, void *, + const char *); +static void chm_ban(struct Client *, struct Client *, struct Channel *, int, + int *, char **, int *, int, int, char, void *, + const char *); +static void chm_except(struct Client *, struct Client *, struct Channel *, + int, int *, char **, int *, int, int, char, void *, + const char *); +static void chm_invex(struct Client *, struct Client *, struct Channel *, + int, int *, char **, int *, int, int, char, void *, + const char *); +static void send_cap_mode_changes(struct Client *, struct Client *, + struct Channel *, unsigned int, unsigned int); +static void send_mode_changes(struct Client *, struct Client *, + struct Channel *, char *); + +/* 10 is a magic number in hybrid 6 NFI where it comes from -db */ +#define BAN_FUDGE 10 +#define NCHCAPS (sizeof(channel_capabs)/sizeof(int)) +#define NCHCAP_COMBOS (1 << NCHCAPS) + +static char nuh_mask[MAXPARA][IRCD_BUFSIZE]; +/* some buffers for rebuilding channel/nick lists with ,'s */ +static char modebuf[IRCD_BUFSIZE]; +static char parabuf[MODEBUFLEN]; +static struct ChModeChange mode_changes[IRCD_BUFSIZE]; +static int mode_count; +static int mode_limit; /* number of modes set other than simple */ +static int simple_modes_mask; /* bit mask of simple modes already set */ +#ifdef HALFOPS +static int channel_capabs[] = { CAP_EX, CAP_IE, CAP_TS6, CAP_HOPS }; +#else +static int channel_capabs[] = { CAP_EX, CAP_IE, CAP_TS6 }; +#endif +static struct ChCapCombo chcap_combos[NCHCAP_COMBOS]; +extern BlockHeap *ban_heap; + + +/* XXX check_string is propably not longer required in add_id and del_id */ +/* check_string() + * + * inputs - string to check + * output - pointer to modified string + * side effects - Fixes a string so that the first white space found + * becomes an end of string marker (`\0`). + * returns the 'fixed' string or "*" if the string + * was NULL length or a NULL pointer. + */ +static char * +check_string(char *s) +{ + char *str = s; + static char star[] = "*"; + + if (EmptyString(s)) + return star; + + for (; *s; ++s) + { + if (IsSpace(*s)) + { + *s = '\0'; + break; + } + } + + return str; +} + +/* + * Ban functions to work with mode +b/e/d/I + */ +/* add the specified ID to the channel.. + * -is 8/9/00 + */ + +int +add_id(struct Client *client_p, struct Channel *chptr, char *banid, int type) +{ + dlink_list *list = NULL; + dlink_node *ban = NULL; + size_t len = 0; + struct Ban *ban_p = NULL; + unsigned int num_mask; + char name[NICKLEN + 1]; + char user[USERLEN + 1]; + char host[HOSTLEN + 1]; + struct split_nuh_item nuh; + + /* dont let local clients overflow the b/e/I lists */ + if (MyClient(client_p)) + { + num_mask = dlink_list_length(&chptr->banlist) + + dlink_list_length(&chptr->exceptlist) + + dlink_list_length(&chptr->invexlist); + + if (num_mask >= ConfigChannel.max_bans) + { + sendto_one(client_p, form_str(ERR_BANLISTFULL), + me.name, client_p->name, chptr->chname, banid); + return 0; + } + + collapse(banid); + } + + nuh.nuhmask = check_string(banid); + nuh.nickptr = name; + nuh.userptr = user; + nuh.hostptr = host; + + nuh.nicksize = sizeof(name); + nuh.usersize = sizeof(user); + nuh.hostsize = sizeof(host); + + split_nuh(&nuh); + + /* + * Re-assemble a new n!u@h and print it back to banid for sending + * the mode to the channel. + */ + len = ircsprintf(banid, "%s!%s@%s", name, user, host); + + switch (type) + { + case CHFL_BAN: + list = &chptr->banlist; + clear_ban_cache(chptr); + break; + case CHFL_EXCEPTION: + list = &chptr->exceptlist; + clear_ban_cache(chptr); + break; + case CHFL_INVEX: + list = &chptr->invexlist; + break; + default: + assert(0); + return 0; + } + + DLINK_FOREACH(ban, list->head) + { + ban_p = ban->data; + if (!irccmp(ban_p->name, name) && + !irccmp(ban_p->username, user) && + !irccmp(ban_p->host, host)) + { + return 0; + } + } + + ban_p = BlockHeapAlloc(ban_heap); + + DupString(ban_p->name, name); + DupString(ban_p->username, user); + DupString(ban_p->host, host); + + ban_p->when = CurrentTime; + ban_p->len = len - 2; /* -2 for @ and ! */ + ban_p->type = parse_netmask(host, &ban_p->addr, &ban_p->bits); + + if (IsClient(client_p)) + { + ban_p->who = MyMalloc(strlen(client_p->name) + + strlen(client_p->username) + + strlen(client_p->host) + 3); + ircsprintf(ban_p->who, "%s!%s@%s", client_p->name, + client_p->username, client_p->host); + } + else + DupString(ban_p->who, client_p->name); + + dlinkAdd(ban_p, &ban_p->node, list); + + return 1; +} + +/* + * inputs - pointer to channel + * - pointer to ban id + * - type of ban, i.e. ban, exception, invex + * output - 0 for failure, 1 for success + * side effects - + */ +static int +del_id(struct Channel *chptr, char *banid, int type) +{ + dlink_list *list; + dlink_node *ban; + struct Ban *banptr; + char name[NICKLEN + 1]; + char user[USERLEN + 1]; + char host[HOSTLEN + 1]; + struct split_nuh_item nuh; + + if (banid == NULL) + return 0; + + nuh.nuhmask = check_string(banid); + nuh.nickptr = name; + nuh.userptr = user; + nuh.hostptr = host; + + nuh.nicksize = sizeof(name); + nuh.usersize = sizeof(user); + nuh.hostsize = sizeof(host); + + split_nuh(&nuh); + + /* + * Re-assemble a new n!u@h and print it back to banid for sending + * the mode to the channel. + */ + ircsprintf(banid, "%s!%s@%s", name, user, host); + + switch (type) + { + case CHFL_BAN: + list = &chptr->banlist; + clear_ban_cache(chptr); + break; + case CHFL_EXCEPTION: + list = &chptr->exceptlist; + clear_ban_cache(chptr); + break; + case CHFL_INVEX: + list = &chptr->invexlist; + break; + default: + sendto_realops_flags(UMODE_ALL, L_ALL, + "del_id() called with unknown ban type %d!", type); + return 0; + } + + DLINK_FOREACH(ban, list->head) + { + banptr = ban->data; + + if (!irccmp(name, banptr->name) && + !irccmp(user, banptr->username) && + !irccmp(host, banptr->host)) + { + remove_ban(banptr, list); + return 1; + } + } + + return 0; +} + +const struct mode_letter chan_modes[] = { + { MODE_INVITEONLY, 'i' }, + { MODE_MODERATED, 'm' }, + { MODE_NOPRIVMSGS, 'n' }, + { MODE_PRIVATE, 'p' }, + { MODE_REGISTERED, 'r' }, + { MODE_SECRET, 's' }, + { MODE_TOPICLIMIT, 't' }, + { MODE_OPERONLY, 'O' }, + { MODE_REGONLY, 'R' }, + { MODE_SSLONLY, 'S' }, + { 0, '\0' } +}; + +/* channel_modes() + * + * inputs - pointer to channel + * - pointer to client + * - pointer to mode buf + * - pointer to parameter buf + * output - NONE + * side effects - write the "simple" list of channel modes for channel + * chptr onto buffer mbuf with the parameters in pbuf. + */ +void +channel_modes(struct Channel *chptr, struct Client *client_p, + char *mbuf, char *pbuf) +{ + const struct mode_letter *tab = chan_modes; + + *mbuf++ = '+'; + *pbuf = '\0'; + + for (; tab->mode; ++tab) + if (chptr->mode.mode & tab->mode) + *mbuf++ = tab->letter; + + if (chptr->mode.limit) + { + *mbuf++ = 'l'; + + if (IsServer(client_p) || HasFlag(client_p, FLAGS_SERVICE) || IsMember(client_p, chptr)) + pbuf += ircsprintf(pbuf, "%d ", chptr->mode.limit); + } + + if (chptr->mode.key[0]) + { + *mbuf++ = 'k'; + + if (IsServer(client_p) || HasFlag(client_p, FLAGS_SERVICE) || IsMember(client_p, chptr)) + ircsprintf(pbuf, "%s ", chptr->mode.key); + } + + *mbuf = '\0'; +} + +/* fix_key() + * + * inputs - pointer to key to clean up + * output - pointer to cleaned up key + * side effects - input string is modified + * + * stolen from Undernet's ircd -orabidoo + */ +static char * +fix_key(char *arg) +{ + unsigned char *s, *t, c; + + for (s = t = (unsigned char *)arg; (c = *s); s++) + { + c &= 0x7f; + if (c != ':' && c > ' ' && c != ',') + *t++ = c; + } + + *t = '\0'; + return(arg); +} + +/* fix_key_old() + * + * inputs - pointer to key to clean up + * output - pointer to cleaned up key + * side effects - input string is modifed + * + * Here we attempt to be compatible with older non-hybrid servers. + * We can't back down from the ':' issue however. --Rodder + */ +static char * +fix_key_old(char *arg) +{ + unsigned char *s, *t, c; + + for (s = t = (unsigned char *)arg; (c = *s); s++) + { + c &= 0x7f; + if ((c != 0x0a) && (c != ':') && (c != 0x0d) && (c != ',')) + *t++ = c; + } + + *t = '\0'; + return(arg); +} + +/* bitmasks for various error returns that set_channel_mode should only return + * once per call -orabidoo + */ + +#define SM_ERR_NOTS 0x00000001 /* No TS on channel */ +#define SM_ERR_NOOPS 0x00000002 /* No chan ops */ +#define SM_ERR_UNKNOWN 0x00000004 +#define SM_ERR_RPL_B 0x00000008 +#define SM_ERR_RPL_E 0x00000010 +#define SM_ERR_NOTONCHANNEL 0x00000020 /* Not on channel */ +#define SM_ERR_RPL_I 0x00000040 +#define SM_ERR_NOTOPER 0x00000080 +#define SM_ERR_ONLYSERVER 0x00000100 + +/* Now lets do some stuff to keep track of what combinations of + * servers exist... + * Note that the number of combinations doubles each time you add + * something to this list. Each one is only quick if no servers use that + * combination, but if the numbers get too high here MODE will get too + * slow. I suggest if you get more than 7 here, you consider getting rid + * of some and merging or something. If it wasn't for irc+cs we would + * probably not even need to bother about most of these, but unfortunately + * we do. -A1kmm + */ + +/* void init_chcap_usage_counts(void) + * + * Inputs - none + * Output - none + * Side-effects - Initialises the usage counts to zero. Fills in the + * chcap_yes and chcap_no combination tables. + */ +void +init_chcap_usage_counts(void) +{ + unsigned long m, c, y, n; + + memset(chcap_combos, 0, sizeof(chcap_combos)); + + /* For every possible combination */ + for (m = 0; m < NCHCAP_COMBOS; m++) + { + /* Check each capab */ + for (c = y = n = 0; c < NCHCAPS; c++) + { + if ((m & (1 << c)) == 0) + n |= channel_capabs[c]; + else + y |= channel_capabs[c]; + } + chcap_combos[m].cap_yes = y; + chcap_combos[m].cap_no = n; + } +} + +/* void set_chcap_usage_counts(struct Client *serv_p) + * Input: serv_p; The client whose capabs to register. + * Output: none + * Side-effects: Increments the usage counts for the correct capab + * combination. + */ +void +set_chcap_usage_counts(struct Client *serv_p) +{ + int n; + + for (n = 0; n < NCHCAP_COMBOS; n++) + { + if (((serv_p->localClient->caps & chcap_combos[n].cap_yes) == + chcap_combos[n].cap_yes) && + ((serv_p->localClient->caps & chcap_combos[n].cap_no) == 0)) + { + chcap_combos[n].count++; + return; + } + } + + /* This should be impossible -A1kmm. */ + assert(0); +} + +/* void set_chcap_usage_counts(struct Client *serv_p) + * + * Inputs - serv_p; The client whose capabs to register. + * Output - none + * Side-effects - Decrements the usage counts for the correct capab + * combination. + */ +void +unset_chcap_usage_counts(struct Client *serv_p) +{ + int n; + + for (n = 0; n < NCHCAP_COMBOS; n++) + { + if ((serv_p->localClient->caps & chcap_combos[n].cap_yes) == + chcap_combos[n].cap_yes && + (serv_p->localClient->caps & chcap_combos[n].cap_no) == 0) + { + /* Hopefully capabs can't change dynamically or anything... */ + assert(chcap_combos[n].count > 0); + chcap_combos[n].count--; + return; + } + } + + /* This should be impossible -A1kmm. */ + assert(0); +} + +/* Mode functions handle mode changes for a particular mode... */ +static void +chm_nosuch(struct Client *client_p, struct Client *source_p, + struct Channel *chptr, int parc, int *parn, + char **parv, int *errors, int alev, int dir, char c, void *d, + const char *chname) +{ + if (*errors & SM_ERR_UNKNOWN) + return; + + *errors |= SM_ERR_UNKNOWN; + sendto_one(source_p, form_str(ERR_UNKNOWNMODE), me.name, + source_p->name, c); +} + +static void +chm_simple(struct Client *client_p, struct Client *source_p, struct Channel *chptr, + int parc, int *parn, char **parv, int *errors, int alev, int dir, + char c, void *d, const char *chname) +{ + long mode_type; + + mode_type = (long)d; + + if ((alev < CHACCESS_HALFOP) || + ((mode_type == MODE_PRIVATE) && (alev < CHACCESS_CHANOP))) + { + if (!(*errors & SM_ERR_NOOPS)) + sendto_one(source_p, form_str(alev == CHACCESS_NOTONCHAN ? + ERR_NOTONCHANNEL : ERR_CHANOPRIVSNEEDED), + me.name, source_p->name, chname); + *errors |= SM_ERR_NOOPS; + return; + } + + /* If have already dealt with this simple mode, ignore it */ + if (simple_modes_mask & mode_type) + return; + + simple_modes_mask |= mode_type; + + /* setting + */ + /* Apparently, (though no one has ever told the hybrid group directly) + * admins don't like redundant mode checking. ok. It would have been nice + * if you had have told us directly. I've left the original code snippets + * in place. + * + * -Dianora + */ + if ((dir == MODE_ADD)) /* && !(chptr->mode.mode & mode_type)) */ + { + chptr->mode.mode |= mode_type; + + mode_changes[mode_count].letter = c; + mode_changes[mode_count].dir = MODE_ADD; + mode_changes[mode_count].caps = 0; + mode_changes[mode_count].nocaps = 0; + mode_changes[mode_count].id = NULL; + mode_changes[mode_count].mems = ALL_MEMBERS; + mode_changes[mode_count++].arg = NULL; + } + else if ((dir == MODE_DEL)) /* && (chptr->mode.mode & mode_type)) */ + { + /* setting - */ + + chptr->mode.mode &= ~mode_type; + + mode_changes[mode_count].letter = c; + mode_changes[mode_count].dir = MODE_DEL; + mode_changes[mode_count].caps = 0; + mode_changes[mode_count].nocaps = 0; + mode_changes[mode_count].mems = ALL_MEMBERS; + mode_changes[mode_count].id = NULL; + mode_changes[mode_count++].arg = NULL; + } +} + +static void +chm_registered(struct Client *client_p, struct Client *source_p, struct Channel *chptr, + int parc, int *parn, char **parv, int *errors, int alev, int dir, + char c, void *d, const char *chname) +{ + long mode_type; + + mode_type = (long)d; + + + if (!IsServer(source_p) && !HasFlag(source_p, FLAGS_SERVICE)) + { + if (!(*errors & SM_ERR_ONLYSERVER)) + sendto_one(source_p, form_str(alev == CHACCESS_NOTONCHAN ? + ERR_NOTONCHANNEL : ERR_ONLYSERVERSCANCHANGE), + me.name, source_p->name, chname); + *errors |= SM_ERR_ONLYSERVER; + return; + } + + /* If have already dealt with this simple mode, ignore it */ + if (simple_modes_mask & mode_type) + return; + + simple_modes_mask |= mode_type; + + /* setting + */ + /* Apparently, (though no one has ever told the hybrid group directly) + * admins don't like redundant mode checking. ok. It would have been nice + * if you had have told us directly. I've left the original code snippets + * in place. + * + * -Dianora + */ + if ((dir == MODE_ADD)) /* && !(chptr->mode.mode & mode_type)) */ + { + chptr->mode.mode |= mode_type; + + mode_changes[mode_count].letter = c; + mode_changes[mode_count].dir = MODE_ADD; + mode_changes[mode_count].caps = 0; + mode_changes[mode_count].nocaps = 0; + mode_changes[mode_count].id = NULL; + mode_changes[mode_count].mems = ALL_MEMBERS; + mode_changes[mode_count++].arg = NULL; + } + else if ((dir == MODE_DEL)) /* && (chptr->mode.mode & mode_type)) */ + { + /* setting - */ + + chptr->mode.mode &= ~mode_type; + + mode_changes[mode_count].letter = c; + mode_changes[mode_count].dir = MODE_DEL; + mode_changes[mode_count].caps = 0; + mode_changes[mode_count].nocaps = 0; + mode_changes[mode_count].mems = ALL_MEMBERS; + mode_changes[mode_count].id = NULL; + mode_changes[mode_count++].arg = NULL; + } +} + +static void +chm_operonly(struct Client *client_p, struct Client *source_p, struct Channel *chptr, + int parc, int *parn, char **parv, int *errors, int alev, int dir, + char c, void *d, const char *chname) +{ + long mode_type; + + mode_type = (long)d; + + if ((alev < CHACCESS_HALFOP) || + ((mode_type == MODE_PRIVATE) && (alev < CHACCESS_CHANOP))) + { + if (!(*errors & SM_ERR_NOOPS)) + sendto_one(source_p, form_str(alev == CHACCESS_NOTONCHAN ? + ERR_NOTONCHANNEL : ERR_CHANOPRIVSNEEDED), + me.name, source_p->name, chname); + *errors |= SM_ERR_NOOPS; + return; + } + else if (MyClient(source_p) && !HasUMode(source_p, UMODE_OPER)) + { + if (!(*errors & SM_ERR_NOTOPER)) + { + if (alev == CHACCESS_NOTONCHAN) + sendto_one(source_p, form_str(ERR_NOTONCHANNEL), + me.name, source_p->name, chname); + else + sendto_one(source_p, form_str(ERR_NOPRIVILEGES), + me.name, source_p->name); + } + + *errors |= SM_ERR_NOTOPER; + return; + } + + /* If have already dealt with this simple mode, ignore it */ + if (simple_modes_mask & mode_type) + return; + + simple_modes_mask |= mode_type; + + if ((dir == MODE_ADD)) /* && !(chptr->mode.mode & mode_type)) */ + { + chptr->mode.mode |= mode_type; + + mode_changes[mode_count].letter = c; + mode_changes[mode_count].dir = MODE_ADD; + mode_changes[mode_count].caps = 0; + mode_changes[mode_count].nocaps = 0; + mode_changes[mode_count].id = NULL; + mode_changes[mode_count].mems = ALL_MEMBERS; + mode_changes[mode_count].mems = ALL_MEMBERS; + mode_changes[mode_count++].arg = NULL; + } + else if ((dir == MODE_DEL)) /* && (chptr->mode.mode & mode_type)) */ + { + /* setting - */ + + chptr->mode.mode &= ~mode_type; + + mode_changes[mode_count].letter = c; + mode_changes[mode_count].dir = MODE_DEL; + mode_changes[mode_count].caps = 0; + mode_changes[mode_count].nocaps = 0; + mode_changes[mode_count].mems = ALL_MEMBERS; + mode_changes[mode_count].id = NULL; + mode_changes[mode_count++].arg = NULL; + } +} + +static void +chm_ban(struct Client *client_p, struct Client *source_p, + struct Channel *chptr, int parc, int *parn, + char **parv, int *errors, int alev, int dir, char c, void *d, + const char *chname) +{ + char *mask = NULL; + + if (dir == MODE_QUERY || parc <= *parn) + { + dlink_node *ptr = NULL; + + if (*errors & SM_ERR_RPL_B) + return; + + *errors |= SM_ERR_RPL_B; + + DLINK_FOREACH(ptr, chptr->banlist.head) + { + const struct Ban *banptr = ptr->data; + sendto_one(client_p, form_str(RPL_BANLIST), + me.name, client_p->name, chname, + banptr->name, banptr->username, banptr->host, + banptr->who, banptr->when); + } + + sendto_one(source_p, form_str(RPL_ENDOFBANLIST), me.name, + source_p->name, chname); + return; + } + + if (alev < CHACCESS_HALFOP) + { + if (!(*errors & SM_ERR_NOOPS)) + sendto_one(source_p, form_str(alev == CHACCESS_NOTONCHAN ? + ERR_NOTONCHANNEL : ERR_CHANOPRIVSNEEDED), + me.name, source_p->name, chname); + *errors |= SM_ERR_NOOPS; + return; + } + + if (MyClient(source_p) && (++mode_limit > MAXMODEPARAMS)) + return; + + mask = nuh_mask[*parn]; + memcpy(mask, parv[*parn], sizeof(nuh_mask[*parn])); + ++*parn; + + if (IsServer(client_p)) + if (strchr(mask, ' ')) + return; + + switch (dir) + { + case MODE_ADD: + if (!add_id(source_p, chptr, mask, CHFL_BAN)) + return; + break; + case MODE_DEL: + if (!del_id(chptr, mask, CHFL_BAN)) + return; + break; + default: + assert(0); + } + + mode_changes[mode_count].letter = c; + mode_changes[mode_count].dir = dir; + mode_changes[mode_count].caps = 0; + mode_changes[mode_count].nocaps = 0; + mode_changes[mode_count].mems = ALL_MEMBERS; + mode_changes[mode_count].id = NULL; + mode_changes[mode_count++].arg = mask; +} + +static void +chm_except(struct Client *client_p, struct Client *source_p, + struct Channel *chptr, int parc, int *parn, + char **parv, int *errors, int alev, int dir, char c, void *d, + const char *chname) +{ + char *mask = NULL; + + if (alev < CHACCESS_HALFOP) + { + if (!(*errors & SM_ERR_NOOPS)) + sendto_one(source_p, form_str(alev == CHACCESS_NOTONCHAN ? + ERR_NOTONCHANNEL : ERR_CHANOPRIVSNEEDED), + me.name, source_p->name, chname); + *errors |= SM_ERR_NOOPS; + return; + } + + if (dir == MODE_QUERY || parc <= *parn) + { + dlink_node *ptr = NULL; + + if (*errors & SM_ERR_RPL_E) + return; + + *errors |= SM_ERR_RPL_E; + + DLINK_FOREACH(ptr, chptr->exceptlist.head) + { + const struct Ban *banptr = ptr->data; + sendto_one(client_p, form_str(RPL_EXCEPTLIST), + me.name, client_p->name, chname, + banptr->name, banptr->username, banptr->host, + banptr->who, banptr->when); + } + + sendto_one(source_p, form_str(RPL_ENDOFEXCEPTLIST), me.name, + source_p->name, chname); + return; + } + + if (MyClient(source_p) && (++mode_limit > MAXMODEPARAMS)) + return; + + mask = nuh_mask[*parn]; + memcpy(mask, parv[*parn], sizeof(nuh_mask[*parn])); + ++*parn; + + if (IsServer(client_p)) + if (strchr(mask, ' ')) + return; + + switch (dir) + { + case MODE_ADD: + if (!add_id(source_p, chptr, mask, CHFL_EXCEPTION)) + return; + break; + case MODE_DEL: + if (!del_id(chptr, mask, CHFL_EXCEPTION)) + return; + break; + default: + assert(0); + } + + mode_changes[mode_count].letter = c; + mode_changes[mode_count].dir = dir; + mode_changes[mode_count].caps = CAP_EX; + mode_changes[mode_count].nocaps = 0; + mode_changes[mode_count].mems = ONLY_CHANOPS; + mode_changes[mode_count].id = NULL; + mode_changes[mode_count++].arg = mask; +} + +static void +chm_invex(struct Client *client_p, struct Client *source_p, + struct Channel *chptr, int parc, int *parn, + char **parv, int *errors, int alev, int dir, char c, void *d, + const char *chname) +{ + char *mask = NULL; + + if (alev < CHACCESS_HALFOP) + { + if (!(*errors & SM_ERR_NOOPS)) + sendto_one(source_p, form_str(alev == CHACCESS_NOTONCHAN ? + ERR_NOTONCHANNEL : ERR_CHANOPRIVSNEEDED), + me.name, source_p->name, chname); + *errors |= SM_ERR_NOOPS; + return; + } + + if (dir == MODE_QUERY || parc <= *parn) + { + dlink_node *ptr = NULL; + + if (*errors & SM_ERR_RPL_I) + return; + + *errors |= SM_ERR_RPL_I; + + DLINK_FOREACH(ptr, chptr->invexlist.head) + { + const struct Ban *banptr = ptr->data; + sendto_one(client_p, form_str(RPL_INVITELIST), me.name, + client_p->name, chname, + banptr->name, banptr->username, banptr->host, + banptr->who, banptr->when); + } + + sendto_one(source_p, form_str(RPL_ENDOFINVITELIST), me.name, + source_p->name, chname); + return; + } + + if (MyClient(source_p) && (++mode_limit > MAXMODEPARAMS)) + return; + + mask = nuh_mask[*parn]; + memcpy(mask, parv[*parn], sizeof(nuh_mask[*parn])); + ++*parn; + + if (IsServer(client_p)) + if (strchr(mask, ' ')) + return; + + switch (dir) + { + case MODE_ADD: + if (!add_id(source_p, chptr, mask, CHFL_INVEX)) + return; + break; + case MODE_DEL: + if (!del_id(chptr, mask, CHFL_INVEX)) + return; + break; + default: + assert(0); + } + + mode_changes[mode_count].letter = c; + mode_changes[mode_count].dir = dir; + mode_changes[mode_count].caps = CAP_IE; + mode_changes[mode_count].nocaps = 0; + mode_changes[mode_count].mems = ONLY_CHANOPS; + mode_changes[mode_count].id = NULL; + mode_changes[mode_count++].arg = mask; +} + +/* + * inputs - pointer to channel + * output - none + * side effects - clear ban cache + */ +void +clear_ban_cache(struct Channel *chptr) +{ + dlink_node *ptr = NULL; + + DLINK_FOREACH(ptr, chptr->members.head) + { + struct Membership *ms = ptr->data; + + if (MyConnect(ms->client_p)) + ms->flags &= ~(CHFL_BAN_SILENCED|CHFL_BAN_CHECKED); + } +} + +void +clear_ban_cache_client(struct Client *client_p) +{ + dlink_node *ptr = NULL; + + DLINK_FOREACH(ptr, client_p->channel.head) + { + struct Membership *ms = ptr->data; + ms->flags &= ~(CHFL_BAN_SILENCED|CHFL_BAN_CHECKED); + } +} + +static void +chm_op(struct Client *client_p, struct Client *source_p, + struct Channel *chptr, int parc, int *parn, + char **parv, int *errors, int alev, int dir, char c, void *d, + const char *chname) +{ + char *opnick; + struct Client *targ_p; + struct Membership *member; + int caps = 0; + + if (alev < CHACCESS_CHANOP) + { + if (!(*errors & SM_ERR_NOOPS)) + sendto_one(source_p, form_str(alev == CHACCESS_NOTONCHAN ? + ERR_NOTONCHANNEL : ERR_CHANOPRIVSNEEDED), + me.name, source_p->name, chname); + *errors |= SM_ERR_NOOPS; + return; + } + + if ((dir == MODE_QUERY) || (parc <= *parn)) + return; + + opnick = parv[(*parn)++]; + + if ((targ_p = find_chasing(client_p, source_p, opnick, NULL)) == NULL) + return; + if (!IsClient(targ_p)) + return; + + if ((member = find_channel_link(targ_p, chptr)) == NULL) + { + if (!(*errors & SM_ERR_NOTONCHANNEL)) + sendto_one(source_p, form_str(ERR_USERNOTINCHANNEL), + me.name, source_p->name, opnick, chname); + *errors |= SM_ERR_NOTONCHANNEL; + return; + } + + if (MyClient(source_p) && (++mode_limit > MAXMODEPARAMS)) + return; + + /* no redundant mode changes */ + if (dir == MODE_ADD && has_member_flags(member, CHFL_CHANOP)) + return; + if (dir == MODE_DEL && !has_member_flags(member, CHFL_CHANOP)) + { +#ifdef HALFOPS + if (has_member_flags(member, CHFL_HALFOP)) + { + --*parn; + chm_hop(client_p, source_p, chptr, parc, parn, parv, errors, alev, + dir, c, d, chname); + } +#endif + return; + } + +#ifdef HALFOPS + if (dir == MODE_ADD && has_member_flags(member, CHFL_HALFOP)) + { + /* promoting from % to @ is visible only to CAP_HOPS servers */ + mode_changes[mode_count].letter = 'h'; + mode_changes[mode_count].dir = MODE_DEL; + mode_changes[mode_count].caps = caps = CAP_HOPS; + mode_changes[mode_count].nocaps = 0; + mode_changes[mode_count].mems = ALL_MEMBERS; + mode_changes[mode_count].id = NULL; + mode_changes[mode_count].arg = targ_p->name; + mode_changes[mode_count++].client = targ_p; + } +#endif + + mode_changes[mode_count].letter = 'o'; + mode_changes[mode_count].dir = dir; + mode_changes[mode_count].caps = caps; + mode_changes[mode_count].nocaps = 0; + mode_changes[mode_count].mems = ALL_MEMBERS; + mode_changes[mode_count].id = targ_p->id; + mode_changes[mode_count].arg = targ_p->name; + mode_changes[mode_count++].client = targ_p; + + if (dir == MODE_ADD) + { + AddMemberFlag(member, CHFL_CHANOP); + DelMemberFlag(member, CHFL_DEOPPED | CHFL_HALFOP); + } + else + DelMemberFlag(member, CHFL_CHANOP); +} + +#ifdef HALFOPS +static void +chm_hop(struct Client *client_p, struct Client *source_p, + struct Channel *chptr, int parc, int *parn, + char **parv, int *errors, int alev, int dir, char c, void *d, + const char *chname) +{ + char *opnick; + struct Client *targ_p; + struct Membership *member; + + /* *sigh* - dont allow halfops to set +/-h, they could fully control a + * channel if there were no ops - it doesnt solve anything.. MODE_PRIVATE + * when used with MODE_SECRET is paranoid - cant use +p + * + * it needs to be optional per channel - but not via +p, that or remove + * paranoid.. -- fl_ + * + * +p means paranoid, it is useless for anything else on modern IRC, as + * list isn't really usable. If you want to have a private channel these + * days, you set it +s. Halfops can no longer remove simple modes when + * +p is set (although they can set +p) so it is safe to use this to + * control whether they can (de)halfop... + */ + if (alev < + ((chptr->mode.mode & MODE_PRIVATE) ? CHACCESS_CHANOP : CHACCESS_HALFOP)) + { + if (!(*errors & SM_ERR_NOOPS)) + sendto_one(source_p, form_str(alev == CHACCESS_NOTONCHAN ? + ERR_NOTONCHANNEL : ERR_CHANOPRIVSNEEDED), + me.name, source_p->name, chname); + *errors |= SM_ERR_NOOPS; + return; + } + + if ((dir == MODE_QUERY) || (parc <= *parn)) + return; + + opnick = parv[(*parn)++]; + + if ((targ_p = find_chasing(client_p, source_p, opnick, NULL)) == NULL) + return; + if (!IsClient(targ_p)) + return; + + if ((member = find_channel_link(targ_p, chptr)) == NULL) + { + if (!(*errors & SM_ERR_NOTONCHANNEL)) + sendto_one(source_p, form_str(ERR_USERNOTINCHANNEL), + me.name, source_p->name, opnick, chname); + *errors |= SM_ERR_NOTONCHANNEL; + return; + } + + if (MyClient(source_p) && (++mode_limit > MAXMODEPARAMS)) + return; + + /* no redundant mode changes */ + if (dir == MODE_ADD && has_member_flags(member, CHFL_HALFOP | CHFL_CHANOP)) + return; + if (dir == MODE_DEL && !has_member_flags(member, CHFL_HALFOP)) + return; + + mode_changes[mode_count].letter = 'h'; + mode_changes[mode_count].dir = dir; + mode_changes[mode_count].caps = CAP_HOPS; + mode_changes[mode_count].nocaps = 0; + mode_changes[mode_count].mems = ALL_MEMBERS; + mode_changes[mode_count].id = targ_p->id; + mode_changes[mode_count].arg = targ_p->name; + mode_changes[mode_count++].client = targ_p; + + mode_changes[mode_count].letter = 'o'; + mode_changes[mode_count].dir = dir; + mode_changes[mode_count].caps = 0; + mode_changes[mode_count].nocaps = CAP_HOPS; + mode_changes[mode_count].mems = ONLY_SERVERS; + mode_changes[mode_count].id = targ_p->id; + mode_changes[mode_count].arg = targ_p->name; + mode_changes[mode_count++].client = targ_p; + + if (dir == MODE_ADD) + { + AddMemberFlag(member, CHFL_HALFOP); + DelMemberFlag(member, CHFL_DEOPPED); + } + else + DelMemberFlag(member, CHFL_HALFOP); +} +#endif + +static void +chm_voice(struct Client *client_p, struct Client *source_p, + struct Channel *chptr, int parc, int *parn, + char **parv, int *errors, int alev, int dir, char c, void *d, + const char *chname) +{ + char *opnick; + struct Client *targ_p; + struct Membership *member; + + if (alev < CHACCESS_HALFOP) + { + if (!(*errors & SM_ERR_NOOPS)) + sendto_one(source_p, form_str(alev == CHACCESS_NOTONCHAN ? + ERR_NOTONCHANNEL : ERR_CHANOPRIVSNEEDED), + me.name, source_p->name, chname); + *errors |= SM_ERR_NOOPS; + return; + } + + if ((dir == MODE_QUERY) || parc <= *parn) + return; + + opnick = parv[(*parn)++]; + + if ((targ_p = find_chasing(client_p, source_p, opnick, NULL)) == NULL) + return; + if (!IsClient(targ_p)) + return; + + if ((member = find_channel_link(targ_p, chptr)) == NULL) + { + if (!(*errors & SM_ERR_NOTONCHANNEL)) + sendto_one(source_p, form_str(ERR_USERNOTINCHANNEL), + me.name, source_p->name, opnick, chname); + *errors |= SM_ERR_NOTONCHANNEL; + return; + } + + if (MyClient(source_p) && (++mode_limit > MAXMODEPARAMS)) + return; + + /* no redundant mode changes */ + if (dir == MODE_ADD && has_member_flags(member, CHFL_VOICE)) + return; + if (dir == MODE_DEL && !has_member_flags(member, CHFL_VOICE)) + return; + + mode_changes[mode_count].letter = 'v'; + mode_changes[mode_count].dir = dir; + mode_changes[mode_count].caps = 0; + mode_changes[mode_count].nocaps = 0; + mode_changes[mode_count].mems = ALL_MEMBERS; + mode_changes[mode_count].id = targ_p->id; + mode_changes[mode_count].arg = targ_p->name; + mode_changes[mode_count++].client = targ_p; + + if (dir == MODE_ADD) + AddMemberFlag(member, CHFL_VOICE); + else + DelMemberFlag(member, CHFL_VOICE); +} + +static void +chm_limit(struct Client *client_p, struct Client *source_p, + struct Channel *chptr, int parc, int *parn, + char **parv, int *errors, int alev, int dir, char c, void *d, + const char *chname) +{ + int i, limit; + char *lstr; + + if (alev < CHACCESS_HALFOP) + { + if (!(*errors & SM_ERR_NOOPS)) + sendto_one(source_p, form_str(alev == CHACCESS_NOTONCHAN ? + ERR_NOTONCHANNEL : ERR_CHANOPRIVSNEEDED), + me.name, source_p->name, chname); + *errors |= SM_ERR_NOOPS; + return; + } + + if (dir == MODE_QUERY) + return; + + if ((dir == MODE_ADD) && parc > *parn) + { + lstr = parv[(*parn)++]; + + if ((limit = atoi(lstr)) <= 0) + return; + + ircsprintf(lstr, "%d", limit); + + /* if somebody sets MODE #channel +ll 1 2, accept latter --fl */ + for (i = 0; i < mode_count; i++) + { + if (mode_changes[i].letter == c && mode_changes[i].dir == MODE_ADD) + mode_changes[i].letter = 0; + } + + mode_changes[mode_count].letter = c; + mode_changes[mode_count].dir = MODE_ADD; + mode_changes[mode_count].caps = 0; + mode_changes[mode_count].nocaps = 0; + mode_changes[mode_count].mems = ALL_MEMBERS; + mode_changes[mode_count].id = NULL; + mode_changes[mode_count++].arg = lstr; + + chptr->mode.limit = limit; + } + else if (dir == MODE_DEL) + { + if (!chptr->mode.limit) + return; + + chptr->mode.limit = 0; + + mode_changes[mode_count].letter = c; + mode_changes[mode_count].dir = MODE_DEL; + mode_changes[mode_count].caps = 0; + mode_changes[mode_count].nocaps = 0; + mode_changes[mode_count].mems = ALL_MEMBERS; + mode_changes[mode_count].id = NULL; + mode_changes[mode_count++].arg = NULL; + } +} + +static void +chm_key(struct Client *client_p, struct Client *source_p, + struct Channel *chptr, int parc, int *parn, + char **parv, int *errors, int alev, int dir, char c, void *d, + const char *chname) +{ + int i; + char *key; + + if (alev < CHACCESS_HALFOP) + { + if (!(*errors & SM_ERR_NOOPS)) + sendto_one(source_p, form_str(alev == CHACCESS_NOTONCHAN ? + ERR_NOTONCHANNEL : ERR_CHANOPRIVSNEEDED), + me.name, source_p->name, chname); + *errors |= SM_ERR_NOOPS; + return; + } + + if (dir == MODE_QUERY) + return; + + if ((dir == MODE_ADD) && parc > *parn) + { + key = parv[(*parn)++]; + + if (MyClient(source_p)) + fix_key(key); + else + fix_key_old(key); + + if (*key == '\0') + return; + + assert(key[0] != ' '); + strlcpy(chptr->mode.key, key, sizeof(chptr->mode.key)); + + /* if somebody does MODE #channel +kk a b, accept latter --fl */ + for (i = 0; i < mode_count; i++) + { + if (mode_changes[i].letter == c && mode_changes[i].dir == MODE_ADD) + mode_changes[i].letter = 0; + } + + mode_changes[mode_count].letter = c; + mode_changes[mode_count].dir = MODE_ADD; + mode_changes[mode_count].caps = 0; + mode_changes[mode_count].nocaps = 0; + mode_changes[mode_count].mems = ALL_MEMBERS; + mode_changes[mode_count].id = NULL; + mode_changes[mode_count++].arg = chptr->mode.key; + } + else if (dir == MODE_DEL) + { + if (parc > *parn) + (*parn)++; + + if (chptr->mode.key[0] == '\0') + return; + + chptr->mode.key[0] = '\0'; + + mode_changes[mode_count].letter = c; + mode_changes[mode_count].dir = MODE_DEL; + mode_changes[mode_count].caps = 0; + mode_changes[mode_count].nocaps = 0; + mode_changes[mode_count].mems = ALL_MEMBERS; + mode_changes[mode_count].id = NULL; + mode_changes[mode_count++].arg = "*"; + } +} + +struct ChannelMode +{ + void (*func) (struct Client *client_p, struct Client *source_p, + struct Channel *chptr, int parc, int *parn, char **parv, + int *errors, int alev, int dir, char c, void *d, + const char *chname); + void *d; +}; + +static struct ChannelMode ModeTable[255] = +{ + {chm_nosuch, NULL}, + {chm_nosuch, NULL}, /* A */ + {chm_nosuch, NULL}, /* B */ + {chm_nosuch, NULL}, /* C */ + {chm_nosuch, NULL}, /* D */ + {chm_nosuch, NULL}, /* E */ + {chm_nosuch, NULL}, /* F */ + {chm_nosuch, NULL}, /* G */ + {chm_nosuch, NULL}, /* H */ + {chm_invex, NULL}, /* I */ + {chm_nosuch, NULL}, /* J */ + {chm_nosuch, NULL}, /* K */ + {chm_nosuch, NULL}, /* L */ + {chm_nosuch, NULL}, /* M */ + {chm_nosuch, NULL}, /* N */ + {chm_operonly, (void *) MODE_OPERONLY}, /* O */ + {chm_nosuch, NULL}, /* P */ + {chm_nosuch, NULL}, /* Q */ + {chm_simple, (void *) MODE_REGONLY}, /* R */ + {chm_simple, (void *) MODE_SSLONLY}, /* S */ + {chm_nosuch, NULL}, /* T */ + {chm_nosuch, NULL}, /* U */ + {chm_nosuch, NULL}, /* V */ + {chm_nosuch, NULL}, /* W */ + {chm_nosuch, NULL}, /* X */ + {chm_nosuch, NULL}, /* Y */ + {chm_nosuch, NULL}, /* Z */ + {chm_nosuch, NULL}, + {chm_nosuch, NULL}, + {chm_nosuch, NULL}, + {chm_nosuch, NULL}, + {chm_nosuch, NULL}, + {chm_nosuch, NULL}, + {chm_nosuch, NULL}, /* a */ + {chm_ban, NULL}, /* b */ + {chm_nosuch, NULL}, /* c */ + {chm_nosuch, NULL}, /* d */ + {chm_except, NULL}, /* e */ + {chm_nosuch, NULL}, /* f */ + {chm_nosuch, NULL}, /* g */ +#ifdef HALFOPS + {chm_hop, NULL}, /* h */ +#else + {chm_nosuch, NULL}, /* h */ +#endif + {chm_simple, (void *) MODE_INVITEONLY}, /* i */ + {chm_nosuch, NULL}, /* j */ + {chm_key, NULL}, /* k */ + {chm_limit, NULL}, /* l */ + {chm_simple, (void *) MODE_MODERATED}, /* m */ + {chm_simple, (void *) MODE_NOPRIVMSGS}, /* n */ + {chm_op, NULL}, /* o */ + {chm_simple, (void *) MODE_PRIVATE}, /* p */ + {chm_nosuch, NULL}, /* q */ + {chm_registered, (void *) MODE_REGISTERED}, /* r */ + {chm_simple, (void *) MODE_SECRET}, /* s */ + {chm_simple, (void *) MODE_TOPICLIMIT}, /* t */ + {chm_nosuch, NULL}, /* u */ + {chm_voice, NULL}, /* v */ + {chm_nosuch, NULL}, /* w */ + {chm_nosuch, NULL}, /* x */ + {chm_nosuch, NULL}, /* y */ + {chm_nosuch, NULL}, /* z */ +}; + +/* get_channel_access() + * + * inputs - pointer to Client struct + * - pointer to Membership struct + * output - CHACCESS_CHANOP if we should let them have + * chanop level access, 0 for peon level access. + * side effects - NONE + */ +static int +get_channel_access(struct Client *source_p, struct Membership *member) +{ + /* Let hacked servers in for now... */ + if (!MyClient(source_p)) + return CHACCESS_CHANOP; + + if (member == NULL) + return CHACCESS_NOTONCHAN; + + /* just to be sure.. */ + assert(source_p == member->client_p); + + if (has_member_flags(member, CHFL_CHANOP)) + return CHACCESS_CHANOP; + +#ifdef HALFOPS + if (has_member_flags(member, CHFL_HALFOP)) + return CHACCESS_HALFOP; +#endif + + return CHACCESS_PEON; +} + +/* void send_cap_mode_changes(struct Client *client_p, + * struct Client *source_p, + * struct Channel *chptr, int cap, int nocap) + * Input: The client sending(client_p), the source client(source_p), + * the channel to send mode changes for(chptr) + * Output: None. + * Side-effects: Sends the appropriate mode changes to capable servers. + * + * send_cap_mode_changes() will loop the server list itself, because + * at this point in time we have 4 capabs for channels, CAP_IE, CAP_EX, + * and a server could support any number of these.. + * so we make the modebufs per server, tailoring them to each servers + * specific demand. Its not very pretty, but its one of the few realistic + * ways to handle having this many capabs for channel modes.. --fl_ + * + * Reverted back to my original design, except that we now keep a count + * of the number of servers which each combination as an optimisation, so + * the capabs combinations which are not needed are not worked out. -A1kmm + */ +/* rewritten to ensure parabuf < MODEBUFLEN -db */ + +static void +send_cap_mode_changes(struct Client *client_p, struct Client *source_p, + struct Channel *chptr, unsigned int cap, unsigned int nocap) +{ + int i, mbl, pbl, arglen, nc, mc; + int len; + const char *arg = NULL; + char *parptr; + int dir = MODE_QUERY; + + mc = 0; + nc = 0; + pbl = 0; + + parabuf[0] = '\0'; + parptr = parabuf; + + if ((cap & CAP_TS6) && source_p->id[0] != '\0') + mbl = ircsprintf(modebuf, ":%s TMODE %lu %s ", source_p->id, + (unsigned long)chptr->channelts, chptr->chname); + else + mbl = ircsprintf(modebuf, ":%s MODE %s ", source_p->name, + chptr->chname); + + /* loop the list of - modes we have */ + for (i = 0; i < mode_count; i++) + { + /* if they dont support the cap we need, or they do support a cap they + * cant have, then dont add it to the modebuf.. that way they wont see + * the mode + */ + if ((mode_changes[i].letter == 0) || + ((cap & mode_changes[i].caps) != mode_changes[i].caps) + || ((nocap & mode_changes[i].nocaps) != mode_changes[i].nocaps)) + continue; + + arg = ""; + + if ((cap & CAP_TS6) && mode_changes[i].id) + arg = mode_changes[i].id; + if (*arg == '\0') + arg = mode_changes[i].arg; + + /* if we're creeping past the buf size, we need to send it and make + * another line for the other modes + * XXX - this could give away server topology with uids being + * different lengths, but not much we can do, except possibly break + * them as if they were the longest of the nick or uid at all times, + * which even then won't work as we don't always know the uid -A1kmm. + */ + if (arg != NULL) + arglen = strlen(arg); + else + arglen = 0; + + if ((mc == MAXMODEPARAMS) || + ((arglen + mbl + pbl + 2) > IRCD_BUFSIZE) || + (pbl + arglen + BAN_FUDGE) >= MODEBUFLEN) + { + if (nc != 0) + sendto_server(client_p, cap, nocap, + "%s %s", + modebuf, parabuf); + nc = 0; + mc = 0; + + if ((cap & CAP_TS6) && source_p->id[0] != '\0') + mbl = ircsprintf(modebuf, ":%s MODE %s ", source_p->id, + chptr->chname); + else + mbl = ircsprintf(modebuf, ":%s MODE %s ", source_p->name, + chptr->chname); + + pbl = 0; + parabuf[0] = '\0'; + parptr = parabuf; + dir = MODE_QUERY; + } + + if (dir != mode_changes[i].dir) + { + modebuf[mbl++] = (mode_changes[i].dir == MODE_ADD) ? '+' : '-'; + dir = mode_changes[i].dir; + } + + modebuf[mbl++] = mode_changes[i].letter; + modebuf[mbl] = '\0'; + nc++; + + if (arg != NULL) + { + len = ircsprintf(parptr, "%s ", arg); + pbl += len; + parptr += len; + mc++; + } + } + + if (pbl && parabuf[pbl - 1] == ' ') + parabuf[pbl - 1] = 0; + + if (nc != 0) + sendto_server(client_p, cap, nocap, + "%s %s", modebuf, parabuf); +} + +/* void send_mode_changes(struct Client *client_p, + * struct Client *source_p, + * struct Channel *chptr) + * Input: The client sending(client_p), the source client(source_p), + * the channel to send mode changes for(chptr), + * mode change globals. + * Output: None. + * Side-effects: Sends the appropriate mode changes to other clients + * and propagates to servers. + */ +/* ensure parabuf < MODEBUFLEN -db */ +static void +send_mode_changes(struct Client *client_p, struct Client *source_p, + struct Channel *chptr, char *chname) +{ + int i, mbl, pbl, arglen, nc, mc; + int len; + const char *arg = NULL; + char *parptr; + int dir = MODE_QUERY; + + /* bail out if we have nothing to do... */ + if (!mode_count) + return; + + if (IsServer(source_p)) + mbl = ircsprintf(modebuf, ":%s MODE %s ", (IsHidden(source_p) || + ConfigServerHide.hide_servers) ? + me.name : source_p->name, chname); + else + mbl = ircsprintf(modebuf, ":%s!%s@%s MODE %s ", source_p->name, + source_p->username, source_p->host, chname); + + mc = 0; + nc = 0; + pbl = 0; + + parabuf[0] = '\0'; + parptr = parabuf; + + for (i = 0; i < mode_count; i++) + { + if (mode_changes[i].letter == 0 || + mode_changes[i].mems == NON_CHANOPS || + mode_changes[i].mems == ONLY_SERVERS) + continue; + + arg = mode_changes[i].arg; + if (arg != NULL) + arglen = strlen(arg); + else + arglen = 0; + + if ((mc == MAXMODEPARAMS) || + ((arglen + mbl + pbl + 2) > IRCD_BUFSIZE) || + ((arglen + pbl + BAN_FUDGE) >= MODEBUFLEN)) + { + if (mbl && modebuf[mbl - 1] == '-') + modebuf[mbl - 1] = '\0'; + + if (nc != 0) + sendto_channel_local(ALL_MEMBERS, 0, chptr, "%s %s", modebuf, parabuf); + + nc = 0; + mc = 0; + + if (IsServer(source_p)) + mbl = ircsprintf(modebuf, ":%s MODE %s ", me.name, chname); + else + mbl = ircsprintf(modebuf, ":%s!%s@%s MODE %s ", source_p->name, + source_p->username, source_p->host, chname); + + pbl = 0; + parabuf[0] = '\0'; + parptr = parabuf; + dir = MODE_QUERY; + } + + if (dir != mode_changes[i].dir) + { + modebuf[mbl++] = (mode_changes[i].dir == MODE_ADD) ? '+' : '-'; + dir = mode_changes[i].dir; + } + + modebuf[mbl++] = mode_changes[i].letter; + modebuf[mbl] = '\0'; + nc++; + + if (arg != NULL) + { + len = ircsprintf(parptr, "%s ", arg); + pbl += len; + parptr += len; + mc++; + } + } + + if (pbl && parabuf[pbl - 1] == ' ') + parabuf[pbl - 1] = 0; + + if (nc != 0) + sendto_channel_local(ALL_MEMBERS, 0, chptr, "%s %s", modebuf, parabuf); + + nc = 0; + mc = 0; + + /* Now send to servers... */ + for (i = 0; i < NCHCAP_COMBOS; i++) + if (chcap_combos[i].count != 0) + send_cap_mode_changes(client_p, source_p, chptr, + chcap_combos[i].cap_yes, + chcap_combos[i].cap_no); +} + +/* void set_channel_mode(struct Client *client_p, struct Client *source_p, + * struct Channel *chptr, int parc, char **parv, + * char *chname) + * Input: The client we received this from, the client this originated + * from, the channel, the parameter count starting at the modes, + * the parameters, the channel name. + * Output: None. + * Side-effects: Changes the channel membership and modes appropriately, + * sends the appropriate MODE messages to the appropriate + * clients. + */ +void +set_channel_mode(struct Client *client_p, struct Client *source_p, struct Channel *chptr, + struct Membership *member, int parc, char *parv[], char *chname) +{ + int dir = MODE_ADD; + int parn = 1; + int alevel, errors = 0; + char *ml = parv[0], c; + int table_position; + + mode_count = 0; + mode_limit = 0; + simple_modes_mask = 0; + + alevel = get_channel_access(source_p, member); + + for (; (c = *ml) != '\0'; ml++) + { +#if 0 + if(mode_count > 20) + break; +#endif + switch (c) + { + case '+': + dir = MODE_ADD; + break; + case '-': + dir = MODE_DEL; + break; + case '=': + dir = MODE_QUERY; + break; + default: + if (c < 'A' || c > 'z') + table_position = 0; + else + table_position = c - 'A' + 1; + ModeTable[table_position].func(client_p, source_p, chptr, + parc, &parn, + parv, &errors, alevel, dir, c, + ModeTable[table_position].d, + chname); + break; + } + } + + send_mode_changes(client_p, source_p, chptr, chname); +} diff --git a/src/client.c b/src/client.c new file mode 100644 index 0000000..4341716 --- /dev/null +++ b/src/client.c @@ -0,0 +1,1205 @@ +/* + * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd). + * client.c: Controls clients. + * + * Copyright (C) 2002 by the past and present ircd coders, and others. + * + * 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 + * + * $Id$ + */ + +#include "stdinc.h" +#include "list.h" +#include "client.h" +#include "channel_mode.h" +#include "event.h" +#include "fdlist.h" +#include "hash.h" +#include "irc_string.h" +#include "ircd.h" +#include "s_gline.h" +#include "numeric.h" +#include "packet.h" +#include "s_auth.h" +#include "s_bsd.h" +#include "conf.h" +#include "log.h" +#include "s_misc.h" +#include "s_serv.h" +#include "send.h" +#include "whowas.h" +#include "s_user.h" +#include "dbuf.h" +#include "memory.h" +#include "hostmask.h" +#include "balloc.h" +#include "listener.h" +#include "irc_res.h" +#include "userhost.h" +#include "watch.h" + +dlink_list listing_client_list = { NULL, NULL, 0 }; +/* Pointer to beginning of Client list */ +dlink_list global_client_list = {NULL, NULL, 0}; +/* unknown/client pointer lists */ +dlink_list unknown_list = {NULL, NULL, 0}; +dlink_list local_client_list = {NULL, NULL, 0}; +dlink_list serv_list = {NULL, NULL, 0}; +dlink_list global_serv_list = {NULL, NULL, 0}; +dlink_list oper_list = {NULL, NULL, 0}; + +static EVH check_pings; + +static BlockHeap *client_heap = NULL; +static BlockHeap *lclient_heap = NULL; + +static dlink_list dead_list = { NULL, NULL, 0}; +static dlink_list abort_list = { NULL, NULL, 0}; + +static dlink_node *eac_next; /* next aborted client to exit */ + +static void check_pings_list(dlink_list *); +static void check_unknowns_list(void); +static void ban_them(struct Client *, struct ConfItem *); + + +/* init_client() + * + * inputs - NONE + * output - NONE + * side effects - initialize client free memory + */ +void +init_client(void) +{ + /* start off the check ping event .. -- adrian + * Every 30 seconds is plenty -- db + */ + client_heap = BlockHeapCreate("client", sizeof(struct Client), CLIENT_HEAP_SIZE); + lclient_heap = BlockHeapCreate("local client", sizeof(struct LocalUser), LCLIENT_HEAP_SIZE); + eventAdd("check_pings", check_pings, NULL, 5); +} + +/* + * make_client - create a new Client struct and set it to initial state. + * + * from == NULL, create local client (a client connected + * to a socket). + * WARNING: This leaves the client in a dangerous + * state where fd == -1, dead flag is not set and + * the client is on the unknown_list; therefore, + * the first thing to do after calling make_client(NULL) + * is setting fd to something reasonable. -adx + * + * from, create remote client (behind a socket + * associated with the client defined by + * 'from'). ('from' is a local client!!). + */ +struct Client * +make_client(struct Client *from) +{ + struct Client *client_p = BlockHeapAlloc(client_heap); + + if (from == NULL) + { + client_p->from = client_p; /* 'from' of local client is self! */ + client_p->localClient = BlockHeapAlloc(lclient_heap); + client_p->localClient->since = CurrentTime; + client_p->localClient->lasttime = CurrentTime; + client_p->localClient->firsttime = CurrentTime; + client_p->localClient->registration = REG_INIT; + + /* as good a place as any... */ + dlinkAdd(client_p, &client_p->localClient->lclient_node, &unknown_list); + } + else + client_p->from = from; /* 'from' of local client is self! */ + + client_p->idhnext = client_p; + client_p->hnext = client_p; + client_p->status = STAT_UNKNOWN; + strcpy(client_p->username, "unknown"); + strcpy(client_p->svid, "0"); + + return client_p; +} + +/* + * free_client + * + * inputs - pointer to client + * output - NONE + * side effects - client pointed to has its memory freed + */ +static void +free_client(struct Client *client_p) +{ + assert(client_p != NULL); + assert(client_p != &me); + assert(client_p->hnext == client_p); + assert(client_p->idhnext == client_p); + assert(client_p->channel.head == NULL); + assert(dlink_list_length(&client_p->channel) == 0); + assert(dlink_list_length(&client_p->whowas) == 0); + assert(!IsServer(client_p) || IsServer(client_p) && client_p->serv); + + MyFree(client_p->serv); + + if (MyConnect(client_p)) + { + assert(client_p->localClient->invited.head == NULL); + assert(dlink_list_length(&client_p->localClient->invited) == 0); + assert(dlink_list_length(&client_p->localClient->watches) == 0); + assert(IsClosing(client_p) && IsDead(client_p)); + + MyFree(client_p->localClient->response); + MyFree(client_p->localClient->auth_oper); + + /* + * clean up extra sockets from P-lines which have been discarded. + */ + if (client_p->localClient->listener) + { + assert(0 < client_p->localClient->listener->ref_count); + if (0 == --client_p->localClient->listener->ref_count && + !client_p->localClient->listener->active) + free_listener(client_p->localClient->listener); + } + + dbuf_clear(&client_p->localClient->buf_recvq); + dbuf_clear(&client_p->localClient->buf_sendq); + + BlockHeapFree(lclient_heap, client_p->localClient); + } + + BlockHeapFree(client_heap, client_p); +} + +/* + * check_pings - go through the local client list and check activity + * kill off stuff that should die + * + * inputs - NOT USED (from event) + * output - next time_t when check_pings() should be called again + * side effects - + * + * + * A PING can be sent to clients as necessary. + * + * Client/Server ping outs are handled. + */ + +/* + * Addon from adrian. We used to call this after nextping seconds, + * however I've changed it to run once a second. This is only for + * PING timeouts, not K/etc-line checks (thanks dianora!). Having it + * run once a second makes life a lot easier - when a new client connects + * and they need a ping in 4 seconds, if nextping was set to 20 seconds + * we end up waiting 20 seconds. This is stupid. :-) + * I will optimise (hah!) check_pings() once I've finished working on + * tidying up other network IO evilnesses. + * -- adrian + */ + +static void +check_pings(void *notused) +{ + check_pings_list(&local_client_list); + check_pings_list(&serv_list); + check_unknowns_list(); +} + +/* check_pings_list() + * + * inputs - pointer to list to check + * output - NONE + * side effects - + */ +static void +check_pings_list(dlink_list *list) +{ + char scratch[32]; /* way too generous but... */ + struct Client *client_p; /* current local client_p being examined */ + int ping, pingwarn; /* ping time value from client */ + dlink_node *ptr, *next_ptr; + + DLINK_FOREACH_SAFE(ptr, next_ptr, list->head) + { + client_p = ptr->data; + + /* + ** Note: No need to notify opers here. It's + ** already done when "FLAGS_DEADSOCKET" is set. + */ + if (IsDead(client_p)) + { + /* Ignore it, its been exited already */ + continue; + } + + if (!IsRegistered(client_p)) + ping = CONNECTTIMEOUT, pingwarn = 0; + else + ping = get_client_ping(client_p, &pingwarn); + + if (ping < CurrentTime - client_p->localClient->lasttime) + { + if (!IsPingSent(client_p)) + { + /* + * if we havent PINGed the connection and we havent + * heard from it in a while, PING it to make sure + * it is still alive. + */ + SetPingSent(client_p); + ClearPingWarning(client_p); + client_p->localClient->lasttime = CurrentTime - ping; + sendto_one(client_p, "PING :%s", ID_or_name(&me, client_p)); + } + else + { + if (CurrentTime - client_p->localClient->lasttime >= 2 * ping) + { + /* + * If the client/server hasn't talked to us in 2*ping seconds + * and it has a ping time, then close its connection. + */ + if (IsServer(client_p) || IsHandshake(client_p)) + { + sendto_realops_flags(UMODE_ALL, L_ADMIN, + "No response from %s, closing link", + get_client_name(client_p, HIDE_IP)); + sendto_realops_flags(UMODE_ALL, L_OPER, + "No response from %s, closing link", + get_client_name(client_p, MASK_IP)); + ilog(LOG_TYPE_IRCD, "No response from %s, closing link", + get_client_name(client_p, HIDE_IP)); + } + + snprintf(scratch, sizeof(scratch), "Ping timeout: %d seconds", + (int)(CurrentTime - client_p->localClient->lasttime)); + exit_client(client_p, &me, scratch); + } + else if (!IsPingWarning(client_p) && pingwarn > 0 && + (IsServer(client_p) || IsHandshake(client_p)) && + CurrentTime - client_p->localClient->lasttime >= ping + pingwarn) + { + /* + * If the server hasn't replied in pingwarn seconds after sending + * the PING, notify the opers so that they are aware of the problem. + */ + SetPingWarning(client_p); + sendto_realops_flags(UMODE_ALL, L_ADMIN, + "Warning, no response from %s in %d seconds", + get_client_name(client_p, HIDE_IP), pingwarn); + sendto_realops_flags(UMODE_ALL, L_OPER, + "Warning, no response from %s in %d seconds", + get_client_name(client_p, MASK_IP), pingwarn); + ilog(LOG_TYPE_IRCD, "No response from %s in %d seconds", + get_client_name(client_p, HIDE_IP), pingwarn); + } + } + } + } +} + +/* check_unknowns_list() + * + * inputs - pointer to list of unknown clients + * output - NONE + * side effects - unknown clients get marked for termination after n seconds + */ +static void +check_unknowns_list(void) +{ + dlink_node *ptr, *next_ptr; + + DLINK_FOREACH_SAFE(ptr, next_ptr, unknown_list.head) + { + struct Client *client_p = ptr->data; + + /* + * Check UNKNOWN connections - if they have been in this state + * for > 30s, close them. + */ + if (IsAuthFinished(client_p) && (CurrentTime - client_p->localClient->firsttime) > 30) + exit_client(client_p, &me, "Registration timed out"); + } +} + +/* check_conf_klines() + * + * inputs - NONE + * output - NONE + * side effects - Check all connections for a pending kline against the + * client, exit the client if a kline matches. + */ +void +check_conf_klines(void) +{ + struct Client *client_p = NULL; /* current local client_p being examined */ + struct AccessItem *aconf = NULL; + struct ConfItem *conf = NULL; + dlink_node *ptr, *next_ptr; + + DLINK_FOREACH_SAFE(ptr, next_ptr, local_client_list.head) + { + client_p = ptr->data; + + /* If a client is already being exited + */ + if (IsDead(client_p) || !IsClient(client_p)) + continue; + + /* if there is a returned struct ConfItem then kill it */ + if ((aconf = find_dline_conf(&client_p->localClient->ip, + client_p->localClient->aftype)) != NULL) + { + if (aconf->status & CONF_EXEMPTDLINE) + continue; + + conf = unmap_conf_item(aconf); + ban_them(client_p, conf); + continue; /* and go examine next fd/client_p */ + } + + if (ConfigFileEntry.glines && (aconf = find_gline(client_p))) + { + if (IsExemptKline(client_p) || + IsExemptGline(client_p)) + { + sendto_realops_flags(UMODE_ALL, L_ALL, + "GLINE over-ruled for %s, client is %sline_exempt", + get_client_name(client_p, HIDE_IP), IsExemptKline(client_p) ? "k" : "g"); + continue; + } + + conf = unmap_conf_item(aconf); + ban_them(client_p, conf); + /* and go examine next fd/client_p */ + continue; + } + + if ((aconf = find_kill(client_p)) != NULL) + { + + /* if there is a returned struct AccessItem.. then kill it */ + if (IsExemptKline(client_p)) + { + sendto_realops_flags(UMODE_ALL, L_ALL, + "KLINE over-ruled for %s, client is kline_exempt", + get_client_name(client_p, HIDE_IP)); + continue; + } + + conf = unmap_conf_item(aconf); + ban_them(client_p, conf); + continue; + } + + /* if there is a returned struct MatchItem then kill it */ + if ((conf = find_matching_name_conf(XLINE_TYPE, client_p->info, + NULL, NULL, 0)) != NULL || + (conf = find_matching_name_conf(RXLINE_TYPE, client_p->info, + NULL, NULL, 0)) != NULL) + { + ban_them(client_p, conf); + continue; + } + } + + /* also check the unknowns list for new dlines */ + DLINK_FOREACH_SAFE(ptr, next_ptr, unknown_list.head) + { + client_p = ptr->data; + + if ((aconf = find_dline_conf(&client_p->localClient->ip, + client_p->localClient->aftype))) + { + if (aconf->status & CONF_EXEMPTDLINE) + continue; + + exit_client(client_p, &me, "D-lined"); + } + } +} + +/* + * ban_them + * + * inputs - pointer to client to ban + * - pointer to ConfItem + * output - NONE + * side effects - given client_p is banned + */ +static void +ban_them(struct Client *client_p, struct ConfItem *conf) +{ + const char *user_reason = NULL; /* What is sent to user */ + struct AccessItem *aconf = NULL; + struct MatchItem *xconf = NULL; + const char *type_string = NULL; + const char dline_string[] = "D-line"; + const char kline_string[] = "K-line"; + const char gline_string[] = "G-line"; + const char xline_string[] = "X-line"; + + switch (conf->type) + { + case RKLINE_TYPE: + case KLINE_TYPE: + type_string = kline_string; + aconf = map_to_conf(conf); + break; + case DLINE_TYPE: + type_string = dline_string; + aconf = map_to_conf(conf); + break; + case GLINE_TYPE: + type_string = gline_string; + aconf = map_to_conf(conf); + break; + case RXLINE_TYPE: + case XLINE_TYPE: + type_string = xline_string; + xconf = map_to_conf(conf); + ++xconf->count; + break; + default: + assert(0); + break; + } + + if (aconf != NULL) + user_reason = aconf->reason ? aconf->reason : type_string; + if (xconf != NULL) + user_reason = xconf->reason ? xconf->reason : type_string; + + sendto_realops_flags(UMODE_ALL, L_ALL, "%s active for %s", + type_string, get_client_name(client_p, HIDE_IP)); + + if (IsClient(client_p)) + sendto_one(client_p, form_str(ERR_YOUREBANNEDCREEP), + me.name, client_p->name, user_reason); + + exit_client(client_p, &me, user_reason); +} + +/* update_client_exit_stats() + * + * input - pointer to client + * output - NONE + * side effects - + */ +static void +update_client_exit_stats(struct Client *client_p) +{ + if (IsClient(client_p)) + { + assert(Count.total > 0); + --Count.total; + if (HasUMode(client_p, UMODE_OPER)) + --Count.oper; + if (HasUMode(client_p, UMODE_INVISIBLE)) + --Count.invisi; + } + else if (IsServer(client_p)) + sendto_realops_flags(UMODE_EXTERNAL, L_ALL, "Server %s split from %s", + client_p->name, client_p->servptr->name); + + if (splitchecking && !splitmode) + check_splitmode(NULL); +} + +/* find_person() + * + * inputs - pointer to name + * output - return client pointer + * side effects - find person by (nick)name + */ +struct Client * +find_person(const struct Client *client_p, const char *name) +{ + struct Client *c2ptr = NULL; + + if (IsDigit(*name)) + { + if ((c2ptr = hash_find_id(name)) != NULL) + { + /* invisible users shall not be found by UID guessing */ + if (HasUMode(c2ptr, UMODE_INVISIBLE)) + if (!IsServer(client_p) && !HasFlag(client_p, FLAGS_SERVICE)) + c2ptr = NULL; + } + } + else + c2ptr = hash_find_client(name); + + return ((c2ptr != NULL && IsClient(c2ptr)) ? c2ptr : NULL); +} + +/* + * find_chasing - find the client structure for a nick name (user) + * using history mechanism if necessary. If the client is not found, + * an error message (NO SUCH NICK) is generated. If the client was found + * through the history, chasing will be 1 and otherwise 0. + */ +struct Client * +find_chasing(struct Client *client_p, struct Client *source_p, const char *user, int *chasing) +{ + struct Client *who = find_person(client_p, user); + + if (chasing) + *chasing = 0; + + if (who) + return who; + + if (IsDigit(*user)) + return NULL; + + if ((who = get_history(user, + (time_t)ConfigFileEntry.kill_chase_time_limit)) + == NULL) + { + sendto_one(source_p, form_str(ERR_NOSUCHNICK), + me.name, source_p->name, user); + return NULL; + } + + if (chasing) + *chasing = 1; + + return who; +} + +/* + * get_client_name - Return the name of the client + * for various tracking and + * admin purposes. The main purpose of this function is to + * return the "socket host" name of the client, if that + * differs from the advertised name (other than case). + * But, this can be used to any client structure. + * + * NOTE 1: + * Watch out the allocation of "nbuf", if either source_p->name + * or source_p->sockhost gets changed into pointers instead of + * directly allocated within the structure... + * + * NOTE 2: + * Function return either a pointer to the structure (source_p) or + * to internal buffer (nbuf). *NEVER* use the returned pointer + * to modify what it points!!! + */ +const char * +get_client_name(const struct Client *client, enum addr_mask_type type) +{ + static char nbuf[HOSTLEN * 2 + USERLEN + 5]; + + assert(client != NULL); + + if (!MyConnect(client)) + return client->name; + + if (IsServer(client) || IsConnecting(client) || IsHandshake(client)) + { + if (!irccmp(client->name, client->host)) + return client->name; + else if (ConfigServerHide.hide_server_ips) + type = MASK_IP; + } + + if (ConfigFileEntry.hide_spoof_ips) + if (type == SHOW_IP && IsIPSpoof(client)) + type = MASK_IP; + + /* And finally, let's get the host information, ip or name */ + switch (type) + { + case SHOW_IP: + snprintf(nbuf, sizeof(nbuf), "%s[%s@%s]", + client->name, + client->username, client->sockhost); + break; + case MASK_IP: + if (client->localClient->aftype == AF_INET) + snprintf(nbuf, sizeof(nbuf), "%s[%s@255.255.255.255]", + client->name, client->username); + else + snprintf(nbuf, sizeof(nbuf), "%s[%s@ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff]", + client->name, client->username); + break; + default: + snprintf(nbuf, sizeof(nbuf), "%s[%s@%s]", + client->name, + client->username, client->host); + } + + return nbuf; +} + +void +free_exited_clients(void) +{ + dlink_node *ptr = NULL, *next = NULL; + + DLINK_FOREACH_SAFE(ptr, next, dead_list.head) + { + free_client(ptr->data); + dlinkDelete(ptr, &dead_list); + free_dlink_node(ptr); + } +} + +/* + * Exit one client, local or remote. Assuming all dependents have + * been already removed, and socket closed for local client. + * + * The only messages generated are QUITs on channels. + */ +static void +exit_one_client(struct Client *source_p, const char *quitmsg) +{ + dlink_node *lp = NULL, *next_lp = NULL; + + assert(!IsMe(source_p)); + + if (IsClient(source_p)) + { + if (source_p->servptr->serv != NULL) + dlinkDelete(&source_p->lnode, &source_p->servptr->serv->client_list); + + /* + * If a person is on a channel, send a QUIT notice + * to every client (person) on the same channel (so + * that the client can show the "**signoff" message). + * (Note: The notice is to the local clients *only*) + */ + sendto_common_channels_local(source_p, 0, ":%s!%s@%s QUIT :%s", + source_p->name, source_p->username, + source_p->host, quitmsg); + DLINK_FOREACH_SAFE(lp, next_lp, source_p->channel.head) + remove_user_from_channel(lp->data); + + add_history(source_p, 0); + off_history(source_p); + + watch_check_hash(source_p, RPL_LOGOFF); + + if (MyConnect(source_p)) + { + /* Clean up invitefield */ + DLINK_FOREACH_SAFE(lp, next_lp, source_p->localClient->invited.head) + del_invite(lp->data, source_p); + + del_all_accepts(source_p); + } + } + else if (IsServer(source_p)) + { + dlinkDelete(&source_p->lnode, &source_p->servptr->serv->server_list); + + if ((lp = dlinkFindDelete(&global_serv_list, source_p)) != NULL) + free_dlink_node(lp); + } + + /* Remove source_p from the client lists */ + if (HasID(source_p)) + hash_del_id(source_p); + if (source_p->name[0]) + hash_del_client(source_p); + + if (IsUserHostIp(source_p)) + delete_user_host(source_p->username, source_p->host, !MyConnect(source_p)); + + /* remove from global client list + * NOTE: source_p->node.next cannot be NULL if the client is added + * to global_client_list (there is always &me at its end) + */ + if (source_p != NULL && source_p->node.next != NULL) + dlinkDelete(&source_p->node, &global_client_list); + + update_client_exit_stats(source_p); + + /* Check to see if the client isn't already on the dead list */ + assert(dlinkFind(&dead_list, source_p) == NULL); + + /* add to dead client dlist */ + SetDead(source_p); + dlinkAdd(source_p, make_dlink_node(), &dead_list); +} + +/* Recursively send QUITs and SQUITs for source_p and all its dependent clients + * and servers to those servers that need them. A server needs the client + * QUITs if it can't figure them out from the SQUIT (ie pre-TS4) or if it + * isn't getting the SQUIT because of @#(*&@)# hostmasking. With TS4, once + * a link gets a SQUIT, it doesn't need any QUIT/SQUITs for clients depending + * on that one -orabidoo + * + * This is now called on each local server -adx + */ +static void +recurse_send_quits(struct Client *original_source_p, struct Client *source_p, + struct Client *from, struct Client *to, const char *comment, + const char *splitstr) +{ + dlink_node *ptr, *next; + struct Client *target_p; + + assert(to != source_p); /* should be already removed from serv_list */ + + /* If this server can handle quit storm (QS) removal + * of dependents, just send the SQUIT + */ + if (!IsCapable(to, CAP_QS)) + DLINK_FOREACH_SAFE(ptr, next, source_p->serv->client_list.head) + { + target_p = ptr->data; + sendto_one(to, ":%s QUIT :%s", target_p->name, splitstr); + } + + DLINK_FOREACH_SAFE(ptr, next, source_p->serv->server_list.head) + recurse_send_quits(original_source_p, ptr->data, from, to, + comment, splitstr); + + if ((source_p == original_source_p && to != from) || + !IsCapable(to, CAP_QS)) + { + /* don't use a prefix here - we have to be 100% sure the message + * will be accepted without Unknown prefix etc.. */ + sendto_one(to, "SQUIT %s :%s", ID_or_name(source_p, to), comment); + } +} + +/* + * Remove all clients that depend on source_p; assumes all (S)QUITs have + * already been sent. we make sure to exit a server's dependent clients + * and servers before the server itself; exit_one_client takes care of + * actually removing things off llists. tweaked from +CSr31 -orabidoo + */ +static void +recurse_remove_clients(struct Client *source_p, const char *quitmsg) +{ + dlink_node *ptr, *next; + + DLINK_FOREACH_SAFE(ptr, next, source_p->serv->client_list.head) + exit_one_client(ptr->data, quitmsg); + + DLINK_FOREACH_SAFE(ptr, next, source_p->serv->server_list.head) + { + recurse_remove_clients(ptr->data, quitmsg); + exit_one_client(ptr->data, quitmsg); + } +} + +/* +** Remove *everything* that depends on source_p, from all lists, and sending +** all necessary QUITs and SQUITs. source_p itself is still on the lists, +** and its SQUITs have been sent except for the upstream one -orabidoo +*/ +static void +remove_dependents(struct Client *source_p, struct Client *from, + const char *comment, const char *splitstr) +{ + dlink_node *ptr = NULL; + + DLINK_FOREACH(ptr, serv_list.head) + recurse_send_quits(source_p, source_p, from, ptr->data, + comment, splitstr); + + recurse_remove_clients(source_p, splitstr); +} + +/* + * exit_client - exit a client of any type. Generally, you can use + * this on any struct Client, regardless of its state. + * + * Note, you shouldn't exit remote _users_ without first doing + * AddFlag(x, FLAGS_KILLED) and propagating a kill or similar message. + * However, it is perfectly correct to call exit_client to force a _server_ + * quit (either local or remote one). + * + * inputs: - a client pointer that is going to be exited + * - for servers, the second argument is a pointer to who + * is firing the server. This side won't get any generated + * messages. NEVER NULL! + * output: none + * side effects: the client is delinked from all lists, disconnected, + * and the rest of IRC network is notified of the exit. + * Client memory is scheduled to be freed + */ +void +exit_client(struct Client *source_p, struct Client *from, const char *comment) +{ + dlink_node *m = NULL; + + if (MyConnect(source_p)) + { + /* DO NOT REMOVE. exit_client can be called twice after a failed + * read/write. + */ + if (IsClosing(source_p)) + return; + + SetClosing(source_p); + + if (IsIpHash(source_p)) + remove_one_ip(&source_p->localClient->ip); + + if (source_p->localClient->auth) + { + delete_auth(source_p->localClient->auth); + source_p->localClient->auth = NULL; + } + + /* + * This source_p could have status of one of STAT_UNKNOWN, STAT_CONNECTING + * STAT_HANDSHAKE or STAT_UNKNOWN + * all of which are lumped together into unknown_list + * + * In all above cases IsRegistered() will not be true. + */ + if (!IsRegistered(source_p)) + { + assert(dlinkFind(&unknown_list, source_p)); + + dlinkDelete(&source_p->localClient->lclient_node, &unknown_list); + } + else if (IsClient(source_p)) + { + time_t on_for = CurrentTime - source_p->localClient->firsttime; + assert(Count.local > 0); + Count.local--; + + if (HasUMode(source_p, UMODE_OPER)) + if ((m = dlinkFindDelete(&oper_list, source_p)) != NULL) + free_dlink_node(m); + + assert(dlinkFind(&local_client_list, source_p)); + dlinkDelete(&source_p->localClient->lclient_node, &local_client_list); + + if (source_p->localClient->list_task != NULL) + free_list_task(source_p->localClient->list_task, source_p); + + watch_del_watch_list(source_p); + sendto_realops_flags(UMODE_CCONN, L_ALL, "Client exiting: %s (%s@%s) [%s] [%s]", + source_p->name, source_p->username, source_p->host, comment, + ConfigFileEntry.hide_spoof_ips && IsIPSpoof(source_p) ? + "255.255.255.255" : source_p->sockhost); + sendto_realops_flags(UMODE_CCONN_FULL, L_ALL, "CLIEXIT: %s %s %s %s 0 %s", + source_p->name, + source_p->username, + source_p->host, + ConfigFileEntry.hide_spoof_ips && IsIPSpoof(source_p) ? + "255.255.255.255" : source_p->sockhost, + comment); + ilog(LOG_TYPE_USER, "%s (%3u:%02u:%02u): %s!%s@%s %llu/%llu", + myctime(source_p->localClient->firsttime), (unsigned int)(on_for / 3600), + (unsigned int)((on_for % 3600)/60), (unsigned int)(on_for % 60), + source_p->name, source_p->username, source_p->host, + source_p->localClient->send.bytes>>10, + source_p->localClient->recv.bytes>>10); + } + else if (IsServer(source_p)) + { + assert(Count.myserver > 0); + --Count.myserver; + + assert(dlinkFind(&serv_list, source_p)); + dlinkDelete(&source_p->localClient->lclient_node, &serv_list); + unset_chcap_usage_counts(source_p); + } + + if (!IsDead(source_p)) + { + if (IsServer(source_p)) + { + /* for them, we are exiting the network */ + sendto_one(source_p, ":%s SQUIT %s :%s", + ID_or_name(from, source_p), me.name, comment); + } + + sendto_one(source_p, "ERROR :Closing Link: %s (%s)", + source_p->host, comment); + } + + /* + ** Currently only server connections can have + ** depending remote clients here, but it does no + ** harm to check for all local clients. In + ** future some other clients than servers might + ** have remotes too... + ** + ** Close the Client connection first and mark it + ** so that no messages are attempted to send to it. + ** Remember it makes source_p->from == NULL. + */ + close_connection(source_p); + } + + if (IsServer(source_p)) + { + char splitstr[HOSTLEN + HOSTLEN + 2]; + + /* This shouldn't ever happen */ + assert(source_p->serv != NULL && source_p->servptr != NULL); + + if (ConfigServerHide.hide_servers) + /* + * Set netsplit message to "*.net *.split" to still show + * that its a split, but hide the servers splitting + */ + strcpy(splitstr, "*.net *.split"); + else + snprintf(splitstr, sizeof(splitstr), "%s %s", + source_p->servptr->name, source_p->name); + + remove_dependents(source_p, from->from, comment, splitstr); + + if (source_p->servptr == &me) + { + sendto_realops_flags(UMODE_ALL, L_ALL, + "%s was connected for %d seconds. %llu/%llu sendK/recvK.", + source_p->name, (int)(CurrentTime - source_p->localClient->firsttime), + source_p->localClient->send.bytes >> 10, + source_p->localClient->recv.bytes >> 10); + ilog(LOG_TYPE_IRCD, "%s was connected for %d seconds. %llu/%llu sendK/recvK.", + source_p->name, (int)(CurrentTime - source_p->localClient->firsttime), + source_p->localClient->send.bytes >> 10, + source_p->localClient->recv.bytes >> 10); + } + } + else if (IsClient(source_p) && !HasFlag(source_p, FLAGS_KILLED)) + { + sendto_server(from->from, CAP_TS6, NOCAPS, + ":%s QUIT :%s", ID(source_p), comment); + sendto_server(from->from, NOCAPS, CAP_TS6, + ":%s QUIT :%s", source_p->name, comment); + } + + /* The client *better* be off all of the lists */ + assert(dlinkFind(&unknown_list, source_p) == NULL); + assert(dlinkFind(&local_client_list, source_p) == NULL); + assert(dlinkFind(&serv_list, source_p) == NULL); + assert(dlinkFind(&oper_list, source_p) == NULL); + + exit_one_client(source_p, comment); +} + +/* + * dead_link_on_write - report a write error if not already dead, + * mark it as dead then exit it + */ +void +dead_link_on_write(struct Client *client_p, int ierrno) +{ + dlink_node *ptr; + + if (IsDefunct(client_p)) + return; + + dbuf_clear(&client_p->localClient->buf_recvq); + dbuf_clear(&client_p->localClient->buf_sendq); + + assert(dlinkFind(&abort_list, client_p) == NULL); + ptr = make_dlink_node(); + /* don't let exit_aborted_clients() finish yet */ + dlinkAddTail(client_p, ptr, &abort_list); + + if (eac_next == NULL) + eac_next = ptr; + + SetDead(client_p); /* You are dead my friend */ +} + +/* + * dead_link_on_read - report a read error if not already dead, + * mark it as dead then exit it + */ +void +dead_link_on_read(struct Client *client_p, int error) +{ + char errmsg[255]; + int current_error; + + if (IsDefunct(client_p)) + return; + + dbuf_clear(&client_p->localClient->buf_recvq); + dbuf_clear(&client_p->localClient->buf_sendq); + + current_error = get_sockerr(client_p->localClient->fd.fd); + + if (IsServer(client_p) || IsHandshake(client_p)) + { + int connected = CurrentTime - client_p->localClient->firsttime; + + if (error == 0) + { + /* Admins get the real IP */ + sendto_realops_flags(UMODE_ALL, L_ADMIN, + "Server %s closed the connection", + get_client_name(client_p, SHOW_IP)); + + /* Opers get a masked IP */ + sendto_realops_flags(UMODE_ALL, L_OPER, + "Server %s closed the connection", + get_client_name(client_p, MASK_IP)); + + ilog(LOG_TYPE_IRCD, "Server %s closed the connection", + get_client_name(client_p, SHOW_IP)); + } + else + { + report_error(L_ADMIN, "Lost connection to %s: %s", + get_client_name(client_p, SHOW_IP), current_error); + report_error(L_OPER, "Lost connection to %s: %s", + get_client_name(client_p, MASK_IP), current_error); + } + + sendto_realops_flags(UMODE_ALL, L_ALL, + "%s had been connected for %d day%s, %2d:%02d:%02d", + client_p->name, connected/86400, + (connected/86400 == 1) ? "" : "s", + (connected % 86400) / 3600, (connected % 3600) / 60, + connected % 60); + } + + if (error == 0) + strlcpy(errmsg, "Remote host closed the connection", + sizeof(errmsg)); + else + snprintf(errmsg, sizeof(errmsg), "Read error: %s", + strerror(current_error)); + + exit_client(client_p, &me, errmsg); +} + +void +exit_aborted_clients(void) +{ + dlink_node *ptr; + struct Client *target_p; + const char *notice; + + DLINK_FOREACH_SAFE(ptr, eac_next, abort_list.head) + { + target_p = ptr->data; + eac_next = ptr->next; + + if (target_p == NULL) + { + sendto_realops_flags(UMODE_ALL, L_ALL, + "Warning: null client on abort_list!"); + dlinkDelete(ptr, &abort_list); + free_dlink_node(ptr); + continue; + } + + dlinkDelete(ptr, &abort_list); + + if (IsSendQExceeded(target_p)) + notice = "Max SendQ exceeded"; + else + notice = "Write error: connection closed"; + + exit_client(target_p, &me, notice); + free_dlink_node(ptr); + } +} + +/* + * accept processing, this adds a form of "caller ID" to ircd + * + * If a client puts themselves into "caller ID only" mode, + * only clients that match a client pointer they have put on + * the accept list will be allowed to message them. + * + * Diane Bruce, "Dianora" db@db.net + */ + +void +del_accept(struct split_nuh_item *accept_p, struct Client *client_p) +{ + dlinkDelete(&accept_p->node, &client_p->localClient->acceptlist); + + MyFree(accept_p->nickptr); + MyFree(accept_p->userptr); + MyFree(accept_p->hostptr); + MyFree(accept_p); +} + +struct split_nuh_item * +find_accept(const char *nick, const char *user, + const char *host, struct Client *client_p, int do_match) +{ + dlink_node *ptr = NULL; + /* XXX We wouldn't need that if match() would return 0 on match */ + int (*cmpfunc)(const char *, const char *) = do_match ? match : irccmp; + + DLINK_FOREACH(ptr, client_p->localClient->acceptlist.head) + { + struct split_nuh_item *accept_p = ptr->data; + + if (cmpfunc(accept_p->nickptr, nick) == do_match && + cmpfunc(accept_p->userptr, user) == do_match && + cmpfunc(accept_p->hostptr, host) == do_match) + return accept_p; + } + + return NULL; +} + +/* accept_message() + * + * inputs - pointer to source client + * - pointer to target client + * output - 1 if accept this message 0 if not + * side effects - See if source is on target's allow list + */ +int +accept_message(struct Client *source, + struct Client *target) +{ + dlink_node *ptr = NULL; + + if (source == target || find_accept(source->name, source->username, + source->host, target, 1)) + return 1; + + if (HasUMode(target, UMODE_SOFTCALLERID)) + DLINK_FOREACH(ptr, target->channel.head) + if (IsMember(source, ((struct Membership *)ptr->data)->chptr)) + return 1; + + return 0; +} + +/* del_all_accepts() + * + * inputs - pointer to exiting client + * output - NONE + * side effects - Walk through given clients acceptlist and remove all entries + */ +void +del_all_accepts(struct Client *client_p) +{ + dlink_node *ptr = NULL, *next_ptr = NULL; + + DLINK_FOREACH_SAFE(ptr, next_ptr, client_p->localClient->acceptlist.head) + del_accept(ptr->data, client_p); +} diff --git a/src/conf.c b/src/conf.c new file mode 100644 index 0000000..b5adf94 --- /dev/null +++ b/src/conf.c @@ -0,0 +1,3622 @@ +/* + * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd). + * conf.c: Configuration file functions. + * + * Copyright (C) 2002 by the past and present ircd coders, and others. + * + * 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 + * + * $Id$ + */ + +#include "stdinc.h" +#include "list.h" +#include "ircd_defs.h" +#include "balloc.h" +#include "conf.h" +#include "s_serv.h" +#include "resv.h" +#include "channel.h" +#include "client.h" +#include "event.h" +#include "hook.h" +#include "irc_string.h" +#include "s_bsd.h" +#include "ircd.h" +#include "listener.h" +#include "hostmask.h" +#include "modules.h" +#include "numeric.h" +#include "fdlist.h" +#include "log.h" +#include "send.h" +#include "s_gline.h" +#include "memory.h" +#include "irc_res.h" +#include "userhost.h" +#include "s_user.h" +#include "channel_mode.h" +#include "parse.h" +#include "s_misc.h" + +struct Callback *client_check_cb = NULL; +struct config_server_hide ConfigServerHide; + +/* general conf items link list root, other than k lines etc. */ +dlink_list service_items = { NULL, NULL, 0 }; +dlink_list server_items = { NULL, NULL, 0 }; +dlink_list cluster_items = { NULL, NULL, 0 }; +dlink_list oconf_items = { NULL, NULL, 0 }; +dlink_list uconf_items = { NULL, NULL, 0 }; +dlink_list xconf_items = { NULL, NULL, 0 }; +dlink_list rxconf_items = { NULL, NULL, 0 }; +dlink_list rkconf_items = { NULL, NULL, 0 }; +dlink_list nresv_items = { NULL, NULL, 0 }; +dlink_list class_items = { NULL, NULL, 0 }; + +dlink_list temporary_xlines = { NULL, NULL, 0 }; +dlink_list temporary_resv = { NULL, NULL, 0 }; + +extern unsigned int lineno; +extern char linebuf[]; +extern char conffilebuf[IRCD_BUFSIZE]; +extern int yyparse(); /* defined in y.tab.c */ + +struct conf_parser_context conf_parser_ctx = { 0, 0, NULL }; + +/* internally defined functions */ +static void read_conf(FILE *); +static void clear_out_old_conf(void); +static void flush_deleted_I_P(void); +static void expire_tklines(dlink_list *); +static void garbage_collect_ip_entries(void); +static int hash_ip(struct irc_ssaddr *); +static int verify_access(struct Client *, const char *); +static int attach_iline(struct Client *, struct ConfItem *); +static struct ip_entry *find_or_add_ip(struct irc_ssaddr *); +static void parse_conf_file(int, int); +static dlink_list *map_to_list(ConfType); +static struct AccessItem *find_regexp_kline(const char *[]); +static int find_user_host(struct Client *, char *, char *, char *, unsigned int); + +/* + * bit_len + */ +static int cidr_limit_reached(int, struct irc_ssaddr *, struct ClassItem *); +static void remove_from_cidr_check(struct irc_ssaddr *, struct ClassItem *); +static void destroy_cidr_class(struct ClassItem *); + +static void flags_to_ascii(unsigned int, const unsigned int[], char *, int); + +/* address of default class conf */ +static struct ConfItem *class_default; + +/* usually, with hash tables, you use a prime number... + * but in this case I am dealing with ip addresses, + * not ascii strings. + */ +#define IP_HASH_SIZE 0x1000 + +struct ip_entry +{ + struct irc_ssaddr ip; + int count; + time_t last_attempt; + struct ip_entry *next; +}; + +static struct ip_entry *ip_hash_table[IP_HASH_SIZE]; +static BlockHeap *ip_entry_heap = NULL; +static int ip_entries_count = 0; + + +void * +map_to_conf(struct ConfItem *aconf) +{ + void *conf; + conf = (void *)((uintptr_t)aconf + + (uintptr_t)sizeof(struct ConfItem)); + return(conf); +} + +struct ConfItem * +unmap_conf_item(void *aconf) +{ + struct ConfItem *conf; + + conf = (struct ConfItem *)((uintptr_t)aconf - + (uintptr_t)sizeof(struct ConfItem)); + return(conf); +} + +/* conf_dns_callback() + * + * inputs - pointer to struct AccessItem + * - pointer to DNSReply reply + * output - none + * side effects - called when resolver query finishes + * if the query resulted in a successful search, hp will contain + * a non-null pointer, otherwise hp will be null. + * if successful save hp in the conf item it was called with + */ +static void +conf_dns_callback(void *vptr, const struct irc_ssaddr *addr, const char *name) +{ + struct AccessItem *aconf = vptr; + + aconf->dns_pending = 0; + + if (addr != NULL) + memcpy(&aconf->addr, addr, sizeof(aconf->addr)); + else + aconf->dns_failed = 1; +} + +/* conf_dns_lookup() + * + * do a nameserver lookup of the conf host + * if the conf entry is currently doing a ns lookup do nothing, otherwise + * allocate a dns_query and start ns lookup. + */ +static void +conf_dns_lookup(struct AccessItem *aconf) +{ + if (!aconf->dns_pending) + { + aconf->dns_pending = 1; + gethost_byname(conf_dns_callback, aconf, aconf->host); + } +} + +/* make_conf_item() + * + * inputs - type of item + * output - pointer to new conf entry + * side effects - none + */ +struct ConfItem * +make_conf_item(ConfType type) +{ + struct ConfItem *conf = NULL; + struct AccessItem *aconf = NULL; + struct ClassItem *aclass = NULL; + int status = 0; + + switch (type) + { + case DLINE_TYPE: + case EXEMPTDLINE_TYPE: + case GLINE_TYPE: + case KLINE_TYPE: + case CLIENT_TYPE: + case OPER_TYPE: + case SERVER_TYPE: + conf = MyMalloc(sizeof(struct ConfItem) + + sizeof(struct AccessItem)); + aconf = map_to_conf(conf); + aconf->aftype = AF_INET; + + /* Yes, sigh. switch on type again */ + switch (type) + { + case EXEMPTDLINE_TYPE: + status = CONF_EXEMPTDLINE; + break; + + case DLINE_TYPE: + status = CONF_DLINE; + break; + + case KLINE_TYPE: + status = CONF_KLINE; + break; + + case GLINE_TYPE: + status = CONF_GLINE; + break; + + case CLIENT_TYPE: + status = CONF_CLIENT; + break; + + case OPER_TYPE: + status = CONF_OPERATOR; + dlinkAdd(conf, &conf->node, &oconf_items); + break; + + case SERVER_TYPE: + status = CONF_SERVER; + dlinkAdd(conf, &conf->node, &server_items); + break; + + default: + break; + } + aconf->status = status; + break; + + case ULINE_TYPE: + conf = (struct ConfItem *)MyMalloc(sizeof(struct ConfItem) + + sizeof(struct MatchItem)); + dlinkAdd(conf, &conf->node, &uconf_items); + break; + + case XLINE_TYPE: + conf = (struct ConfItem *)MyMalloc(sizeof(struct ConfItem) + + sizeof(struct MatchItem)); + dlinkAdd(conf, &conf->node, &xconf_items); + break; +#ifdef HAVE_LIBPCRE + case RXLINE_TYPE: + conf = (struct ConfItem *)MyMalloc(sizeof(struct ConfItem) + + sizeof(struct MatchItem)); + dlinkAdd(conf, &conf->node, &rxconf_items); + break; + + case RKLINE_TYPE: + conf = (struct ConfItem *)MyMalloc(sizeof(struct ConfItem) + + sizeof(struct AccessItem)); + aconf = map_to_conf(conf); + aconf->status = CONF_KLINE; + dlinkAdd(conf, &conf->node, &rkconf_items); + break; +#endif + case CLUSTER_TYPE: + conf = (struct ConfItem *)MyMalloc(sizeof(struct ConfItem)); + dlinkAdd(conf, &conf->node, &cluster_items); + break; + + case CRESV_TYPE: + conf = (struct ConfItem *)MyMalloc(sizeof(struct ConfItem) + + sizeof(struct ResvChannel)); + break; + + case NRESV_TYPE: + conf = (struct ConfItem *)MyMalloc(sizeof(struct ConfItem) + + sizeof(struct MatchItem)); + dlinkAdd(conf, &conf->node, &nresv_items); + break; + + case SERVICE_TYPE: + status = CONF_SERVICE; + conf = MyMalloc(sizeof(struct ConfItem)); + dlinkAdd(conf, &conf->node, &service_items); + break; + + case CLASS_TYPE: + conf = MyMalloc(sizeof(struct ConfItem) + + sizeof(struct ClassItem)); + dlinkAdd(conf, &conf->node, &class_items); + + aclass = map_to_conf(conf); + aclass->active = 1; + aclass->con_freq = DEFAULT_CONNECTFREQUENCY; + aclass->ping_freq = DEFAULT_PINGFREQUENCY; + aclass->max_total = MAXIMUM_LINKS_DEFAULT; + aclass->max_sendq = DEFAULT_SENDQ; + aclass->max_recvq = DEFAULT_RECVQ; + + break; + + default: + conf = NULL; + break; + } + + /* XXX Yes, this will core if default is hit. I want it to for now - db */ + conf->type = type; + + return conf; +} + +void +delete_conf_item(struct ConfItem *conf) +{ + dlink_node *m = NULL, *m_next = NULL; + struct MatchItem *match_item; + struct AccessItem *aconf; + ConfType type = conf->type; + + MyFree(conf->name); + conf->name = NULL; + + switch(type) + { + case DLINE_TYPE: + case EXEMPTDLINE_TYPE: + case GLINE_TYPE: + case KLINE_TYPE: + case CLIENT_TYPE: + case OPER_TYPE: + case SERVER_TYPE: + aconf = map_to_conf(conf); + + if (aconf->dns_pending) + delete_resolver_queries(aconf); + if (aconf->passwd != NULL) + memset(aconf->passwd, 0, strlen(aconf->passwd)); + if (aconf->spasswd != NULL) + memset(aconf->spasswd, 0, strlen(aconf->spasswd)); + aconf->class_ptr = NULL; + + MyFree(aconf->passwd); + MyFree(aconf->spasswd); + MyFree(aconf->reason); + MyFree(aconf->oper_reason); + MyFree(aconf->user); + MyFree(aconf->host); +#ifdef HAVE_LIBCRYPTO + MyFree(aconf->cipher_list); + + if (aconf->rsa_public_key) + RSA_free(aconf->rsa_public_key); + MyFree(aconf->rsa_public_key_file); +#endif + + /* Yes, sigh. switch on type again */ + switch(type) + { + case EXEMPTDLINE_TYPE: + case DLINE_TYPE: + case GLINE_TYPE: + case KLINE_TYPE: + case CLIENT_TYPE: + MyFree(conf); + break; + + case OPER_TYPE: + aconf = map_to_conf(conf); + if (!IsConfIllegal(aconf)) + dlinkDelete(&conf->node, &oconf_items); + MyFree(conf); + break; + + case SERVER_TYPE: + aconf = map_to_conf(conf); + + DLINK_FOREACH_SAFE(m, m_next, aconf->hub_list.head) + { + MyFree(m->data); + free_dlink_node(m); + } + + DLINK_FOREACH_SAFE(m, m_next, aconf->leaf_list.head) + { + MyFree(m->data); + free_dlink_node(m); + } + + if (!IsConfIllegal(aconf)) + dlinkDelete(&conf->node, &server_items); + MyFree(conf); + break; + + default: + break; + } + break; + + case ULINE_TYPE: + match_item = map_to_conf(conf); + MyFree(match_item->user); + MyFree(match_item->host); + MyFree(match_item->reason); + MyFree(match_item->oper_reason); + dlinkDelete(&conf->node, &uconf_items); + MyFree(conf); + break; + + case XLINE_TYPE: + match_item = map_to_conf(conf); + MyFree(match_item->user); + MyFree(match_item->host); + MyFree(match_item->reason); + MyFree(match_item->oper_reason); + dlinkDelete(&conf->node, &xconf_items); + MyFree(conf); + break; +#ifdef HAVE_LIBPCRE + case RKLINE_TYPE: + aconf = map_to_conf(conf); + MyFree(aconf->regexuser); + MyFree(aconf->regexhost); + MyFree(aconf->user); + MyFree(aconf->host); + MyFree(aconf->reason); + MyFree(aconf->oper_reason); + dlinkDelete(&conf->node, &rkconf_items); + MyFree(conf); + break; + + case RXLINE_TYPE: + MyFree(conf->regexpname); + match_item = map_to_conf(conf); + MyFree(match_item->user); + MyFree(match_item->host); + MyFree(match_item->reason); + MyFree(match_item->oper_reason); + dlinkDelete(&conf->node, &rxconf_items); + MyFree(conf); + break; +#endif + case NRESV_TYPE: + match_item = map_to_conf(conf); + MyFree(match_item->user); + MyFree(match_item->host); + MyFree(match_item->reason); + MyFree(match_item->oper_reason); + dlinkDelete(&conf->node, &nresv_items); + + if (conf->flags & CONF_FLAGS_TEMPORARY) + if ((m = dlinkFindDelete(&temporary_resv, conf)) != NULL) + free_dlink_node(m); + + MyFree(conf); + break; + + case CLUSTER_TYPE: + dlinkDelete(&conf->node, &cluster_items); + MyFree(conf); + break; + + case CRESV_TYPE: + if (conf->flags & CONF_FLAGS_TEMPORARY) + if ((m = dlinkFindDelete(&temporary_resv, conf)) != NULL) + free_dlink_node(m); + + MyFree(conf); + break; + + case CLASS_TYPE: + dlinkDelete(&conf->node, &class_items); + MyFree(conf); + break; + + case SERVICE_TYPE: + dlinkDelete(&conf->node, &service_items); + MyFree(conf); + break; + + default: + break; + } +} + +/* free_access_item() + * + * inputs - pointer to conf to free + * output - none + * side effects - crucial password fields are zeroed, conf is freed + */ +void +free_access_item(struct AccessItem *aconf) +{ + struct ConfItem *conf; + + if (aconf == NULL) + return; + conf = unmap_conf_item(aconf); + delete_conf_item(conf); +} + +static const unsigned int shared_bit_table[] = + { 'K', 'k', 'U', 'X', 'x', 'Y', 'Q', 'q', 'R', 'L', 0}; + +/* report_confitem_types() + * + * inputs - pointer to client requesting confitem report + * - ConfType to report + * output - none + * side effects - + */ +void +report_confitem_types(struct Client *source_p, ConfType type) +{ + dlink_node *ptr = NULL, *dptr = NULL; + struct ConfItem *conf = NULL; + struct AccessItem *aconf = NULL; + struct MatchItem *matchitem = NULL; + struct ClassItem *classitem = NULL; + char buf[12]; + char *p = NULL; + + switch (type) + { + case XLINE_TYPE: + DLINK_FOREACH(ptr, xconf_items.head) + { + conf = ptr->data; + matchitem = map_to_conf(conf); + + sendto_one(source_p, form_str(RPL_STATSXLINE), + me.name, source_p->name, + matchitem->hold ? "x": "X", matchitem->count, + conf->name, matchitem->reason); + } + break; + +#ifdef HAVE_LIBPCRE + case RXLINE_TYPE: + DLINK_FOREACH(ptr, rxconf_items.head) + { + conf = ptr->data; + matchitem = map_to_conf(conf); + + sendto_one(source_p, form_str(RPL_STATSXLINE), + me.name, source_p->name, + "XR", matchitem->count, + conf->name, matchitem->reason); + } + break; + + case RKLINE_TYPE: + DLINK_FOREACH(ptr, rkconf_items.head) + { + aconf = map_to_conf((conf = ptr->data)); + + sendto_one(source_p, form_str(RPL_STATSKLINE), me.name, + source_p->name, "KR", aconf->host, aconf->user, + aconf->reason, aconf->oper_reason ? aconf->oper_reason : ""); + } + break; +#endif + + case ULINE_TYPE: + DLINK_FOREACH(ptr, uconf_items.head) + { + conf = ptr->data; + matchitem = map_to_conf(conf); + + p = buf; + + /* some of these are redundant for the sake of + * consistency with cluster{} flags + */ + *p++ = 'c'; + flags_to_ascii(matchitem->action, shared_bit_table, p, 0); + + sendto_one(source_p, form_str(RPL_STATSULINE), + me.name, source_p->name, conf->name, + matchitem->user?matchitem->user: "*", + matchitem->host?matchitem->host: "*", buf); + } + + DLINK_FOREACH(ptr, cluster_items.head) + { + conf = ptr->data; + + p = buf; + + *p++ = 'C'; + flags_to_ascii(conf->flags, shared_bit_table, p, 0); + + sendto_one(source_p, form_str(RPL_STATSULINE), + me.name, source_p->name, conf->name, + "*", "*", buf); + } + + break; + + case OPER_TYPE: + DLINK_FOREACH(ptr, oconf_items.head) + { + conf = ptr->data; + aconf = map_to_conf(conf); + + /* Don't allow non opers to see oper privs */ + if (HasUMode(source_p, UMODE_OPER)) + sendto_one(source_p, form_str(RPL_STATSOLINE), + me.name, source_p->name, 'O', aconf->user, aconf->host, + conf->name, oper_privs_as_string(aconf->port), + aconf->class_ptr ? aconf->class_ptr->name : "<default>"); + else + sendto_one(source_p, form_str(RPL_STATSOLINE), + me.name, source_p->name, 'O', aconf->user, aconf->host, + conf->name, "0", + aconf->class_ptr ? aconf->class_ptr->name : "<default>"); + } + break; + + case CLASS_TYPE: + DLINK_FOREACH(ptr, class_items.head) + { + conf = ptr->data; + classitem = map_to_conf(conf); + sendto_one(source_p, form_str(RPL_STATSYLINE), + me.name, source_p->name, 'Y', + conf->name, classitem->ping_freq, + classitem->con_freq, + classitem->max_total, classitem->max_sendq, + classitem->max_recvq, + classitem->curr_user_count, + classitem->number_per_cidr, classitem->cidr_bitlen_ipv4, + classitem->number_per_cidr, classitem->cidr_bitlen_ipv6, + classitem->active ? "active" : "disabled"); + } + break; + + case CONF_TYPE: + case CLIENT_TYPE: + break; + + case SERVICE_TYPE: + DLINK_FOREACH(ptr, service_items.head) + { + conf = ptr->data; + sendto_one(source_p, form_str(RPL_STATSSERVICE), + me.name, source_p->name, 'S', "*", conf->name, 0, 0); + } + break; + + case SERVER_TYPE: + DLINK_FOREACH(ptr, server_items.head) + { + p = buf; + + conf = ptr->data; + aconf = map_to_conf(conf); + + buf[0] = '\0'; + + if (IsConfAllowAutoConn(aconf)) + *p++ = 'A'; + if (IsConfSSL(aconf)) + *p++ = 'S'; + if (buf[0] == '\0') + *p++ = '*'; + + *p = '\0'; + + /* + * Allow admins to see actual ips unless hide_server_ips is enabled + */ + if (!ConfigServerHide.hide_server_ips && HasUMode(source_p, UMODE_ADMIN)) + sendto_one(source_p, form_str(RPL_STATSCLINE), + me.name, source_p->name, 'C', aconf->host, + buf, conf->name, aconf->port, + aconf->class_ptr ? aconf->class_ptr->name : "<default>"); + else + sendto_one(source_p, form_str(RPL_STATSCLINE), + me.name, source_p->name, 'C', + "*@127.0.0.1", buf, conf->name, aconf->port, + aconf->class_ptr ? aconf->class_ptr->name : "<default>"); + } + break; + + case HUB_TYPE: + DLINK_FOREACH(ptr, server_items.head) + { + conf = ptr->data; + aconf = map_to_conf(conf); + + DLINK_FOREACH(dptr, aconf->hub_list.head) + sendto_one(source_p, form_str(RPL_STATSHLINE), me.name, + source_p->name, 'H', dptr->data, conf->name, 0, "*"); + } + break; + + case LEAF_TYPE: + DLINK_FOREACH(ptr, server_items.head) + { + conf = ptr->data; + aconf = map_to_conf(conf); + + DLINK_FOREACH(dptr, aconf->leaf_list.head) + sendto_one(source_p, form_str(RPL_STATSLLINE), me.name, + source_p->name, 'L', dptr->data, conf->name, 0, "*"); + } + break; + + case GLINE_TYPE: + case KLINE_TYPE: + case DLINE_TYPE: + case EXEMPTDLINE_TYPE: + case CRESV_TYPE: + case NRESV_TYPE: + case CLUSTER_TYPE: + default: + break; + } +} + +/* check_client() + * + * inputs - pointer to client + * output - 0 = Success + * NOT_AUTHORIZED (-1) = Access denied (no I line match) + * IRCD_SOCKET_ERROR (-2) = Bad socket. + * I_LINE_FULL (-3) = I-line is full + * TOO_MANY (-4) = Too many connections from hostname + * BANNED_CLIENT (-5) = K-lined + * side effects - Ordinary client access check. + * Look for conf lines which have the same + * status as the flags passed. + */ +static void * +check_client(va_list args) +{ + struct Client *source_p = va_arg(args, struct Client *); + const char *username = va_arg(args, const char *); + int i; + + /* I'm already in big trouble if source_p->localClient is NULL -db */ + if ((i = verify_access(source_p, username))) + ilog(LOG_TYPE_IRCD, "Access denied: %s[%s]", + source_p->name, source_p->sockhost); + + switch (i) + { + case TOO_MANY: + sendto_realops_flags(UMODE_FULL, L_ALL, + "Too many on IP for %s (%s).", + get_client_name(source_p, SHOW_IP), + source_p->sockhost); + ilog(LOG_TYPE_IRCD, "Too many connections on IP from %s.", + get_client_name(source_p, SHOW_IP)); + ++ServerStats.is_ref; + exit_client(source_p, &me, "No more connections allowed on that IP"); + break; + + case I_LINE_FULL: + sendto_realops_flags(UMODE_FULL, L_ALL, + "I-line is full for %s (%s).", + get_client_name(source_p, SHOW_IP), + source_p->sockhost); + ilog(LOG_TYPE_IRCD, "Too many connections from %s.", + get_client_name(source_p, SHOW_IP)); + ++ServerStats.is_ref; + exit_client(source_p, &me, + "No more connections allowed in your connection class"); + break; + + case NOT_AUTHORIZED: + ++ServerStats.is_ref; + /* jdc - lists server name & port connections are on */ + /* a purely cosmetical change */ + sendto_realops_flags(UMODE_UNAUTH, L_ALL, + "Unauthorized client connection from %s [%s] on [%s/%u].", + get_client_name(source_p, SHOW_IP), + source_p->sockhost, + source_p->localClient->listener->name, + source_p->localClient->listener->port); + ilog(LOG_TYPE_IRCD, + "Unauthorized client connection from %s on [%s/%u].", + get_client_name(source_p, SHOW_IP), + source_p->localClient->listener->name, + source_p->localClient->listener->port); + + exit_client(source_p, &me, "You are not authorized to use this server"); + break; + + case BANNED_CLIENT: + exit_client(source_p, &me, "Banned"); + ++ServerStats.is_ref; + break; + + case 0: + default: + break; + } + + return (i < 0 ? NULL : source_p); +} + +/* verify_access() + * + * inputs - pointer to client to verify + * - pointer to proposed username + * output - 0 if success -'ve if not + * side effect - find the first (best) I line to attach. + */ +static int +verify_access(struct Client *client_p, const char *username) +{ + struct AccessItem *aconf = NULL, *rkconf = NULL; + struct ConfItem *conf = NULL; + char non_ident[USERLEN + 1] = { '~', '\0' }; + const char *uhi[3]; + + if (IsGotId(client_p)) + { + aconf = find_address_conf(client_p->host, client_p->username, + &client_p->localClient->ip, + client_p->localClient->aftype, + client_p->localClient->passwd); + } + else + { + strlcpy(non_ident+1, username, sizeof(non_ident)-1); + aconf = find_address_conf(client_p->host,non_ident, + &client_p->localClient->ip, + client_p->localClient->aftype, + client_p->localClient->passwd); + } + + uhi[0] = IsGotId(client_p) ? client_p->username : non_ident; + uhi[1] = client_p->host; + uhi[2] = client_p->sockhost; + + rkconf = find_regexp_kline(uhi); + + if (aconf != NULL) + { + if (IsConfClient(aconf) && !rkconf) + { + conf = unmap_conf_item(aconf); + + if (IsConfRedir(aconf)) + { + sendto_one(client_p, form_str(RPL_REDIR), + me.name, client_p->name, + conf->name ? conf->name : "", + aconf->port); + return(NOT_AUTHORIZED); + } + + if (IsConfDoIdentd(aconf)) + SetNeedId(client_p); + + /* Thanks for spoof idea amm */ + if (IsConfDoSpoofIp(aconf)) + { + conf = unmap_conf_item(aconf); + + if (!ConfigFileEntry.hide_spoof_ips && IsConfSpoofNotice(aconf)) + sendto_realops_flags(UMODE_ALL, L_ADMIN, "%s spoofing: %s as %s", + client_p->name, client_p->host, conf->name); + strlcpy(client_p->host, conf->name, sizeof(client_p->host)); + SetIPSpoof(client_p); + } + + return(attach_iline(client_p, conf)); + } + else if (rkconf || IsConfKill(aconf) || (ConfigFileEntry.glines && IsConfGline(aconf))) + { + /* XXX */ + aconf = rkconf ? rkconf : aconf; + if (IsConfGline(aconf)) + sendto_one(client_p, ":%s NOTICE %s :*** G-lined", me.name, + client_p->name); + sendto_one(client_p, ":%s NOTICE %s :*** Banned: %s", + me.name, client_p->name, aconf->reason); + return(BANNED_CLIENT); + } + } + + return(NOT_AUTHORIZED); +} + +/* attach_iline() + * + * inputs - client pointer + * - conf pointer + * output - + * side effects - do actual attach + */ +static int +attach_iline(struct Client *client_p, struct ConfItem *conf) +{ + struct AccessItem *aconf; + struct ClassItem *aclass; + struct ip_entry *ip_found; + int a_limit_reached = 0; + int local = 0, global = 0, ident = 0; + + ip_found = find_or_add_ip(&client_p->localClient->ip); + ip_found->count++; + SetIpHash(client_p); + + aconf = map_to_conf(conf); + if (aconf->class_ptr == NULL) + return NOT_AUTHORIZED; /* If class is missing, this is best */ + + aclass = map_to_conf(aconf->class_ptr); + + count_user_host(client_p->username, client_p->host, + &global, &local, &ident); + + /* XXX blah. go down checking the various silly limits + * setting a_limit_reached if any limit is reached. + * - Dianora + */ + if (aclass->max_total != 0 && aclass->curr_user_count >= aclass->max_total) + a_limit_reached = 1; + else if (aclass->max_perip != 0 && ip_found->count > aclass->max_perip) + a_limit_reached = 1; + else if (aclass->max_local != 0 && local >= aclass->max_local) + a_limit_reached = 1; + else if (aclass->max_global != 0 && global >= aclass->max_global) + a_limit_reached = 1; + else if (aclass->max_ident != 0 && ident >= aclass->max_ident && + client_p->username[0] != '~') + a_limit_reached = 1; + + if (a_limit_reached) + { + if (!IsConfExemptLimits(aconf)) + return TOO_MANY; /* Already at maximum allowed */ + + sendto_one(client_p, + ":%s NOTICE %s :*** Your connection class is full, " + "but you have exceed_limit = yes;", me.name, client_p->name); + } + + return attach_conf(client_p, conf); +} + +/* init_ip_hash_table() + * + * inputs - NONE + * output - NONE + * side effects - allocate memory for ip_entry(s) + * - clear the ip hash table + */ +void +init_ip_hash_table(void) +{ + ip_entry_heap = BlockHeapCreate("ip", sizeof(struct ip_entry), + 2 * hard_fdlimit); + memset(ip_hash_table, 0, sizeof(ip_hash_table)); +} + +/* find_or_add_ip() + * + * inputs - pointer to struct irc_ssaddr + * output - pointer to a struct ip_entry + * side effects - + * + * If the ip # was not found, a new struct ip_entry is created, and the ip + * count set to 0. + */ +static struct ip_entry * +find_or_add_ip(struct irc_ssaddr *ip_in) +{ + struct ip_entry *ptr, *newptr; + int hash_index = hash_ip(ip_in), res; + struct sockaddr_in *v4 = (struct sockaddr_in *)ip_in, *ptr_v4; +#ifdef IPV6 + struct sockaddr_in6 *v6 = (struct sockaddr_in6 *)ip_in, *ptr_v6; +#endif + + for (ptr = ip_hash_table[hash_index]; ptr; ptr = ptr->next) + { +#ifdef IPV6 + if (ptr->ip.ss.ss_family != ip_in->ss.ss_family) + continue; + if (ip_in->ss.ss_family == AF_INET6) + { + ptr_v6 = (struct sockaddr_in6 *)&ptr->ip; + res = memcmp(&v6->sin6_addr, &ptr_v6->sin6_addr, sizeof(struct in6_addr)); + } + else +#endif + { + ptr_v4 = (struct sockaddr_in *)&ptr->ip; + res = memcmp(&v4->sin_addr, &ptr_v4->sin_addr, sizeof(struct in_addr)); + } + if (res == 0) + { + /* Found entry already in hash, return it. */ + return ptr; + } + } + + if (ip_entries_count >= 2 * hard_fdlimit) + garbage_collect_ip_entries(); + + newptr = BlockHeapAlloc(ip_entry_heap); + ip_entries_count++; + memcpy(&newptr->ip, ip_in, sizeof(struct irc_ssaddr)); + + newptr->next = ip_hash_table[hash_index]; + ip_hash_table[hash_index] = newptr; + + return newptr; +} + +/* remove_one_ip() + * + * inputs - unsigned long IP address value + * output - NONE + * side effects - The ip address given, is looked up in ip hash table + * and number of ip#'s for that ip decremented. + * If ip # count reaches 0 and has expired, + * the struct ip_entry is returned to the ip_entry_heap + */ +void +remove_one_ip(struct irc_ssaddr *ip_in) +{ + struct ip_entry *ptr; + struct ip_entry *last_ptr = NULL; + int hash_index = hash_ip(ip_in), res; + struct sockaddr_in *v4 = (struct sockaddr_in *)ip_in, *ptr_v4; +#ifdef IPV6 + struct sockaddr_in6 *v6 = (struct sockaddr_in6 *)ip_in, *ptr_v6; +#endif + + for (ptr = ip_hash_table[hash_index]; ptr; ptr = ptr->next) + { +#ifdef IPV6 + if (ptr->ip.ss.ss_family != ip_in->ss.ss_family) + continue; + if (ip_in->ss.ss_family == AF_INET6) + { + ptr_v6 = (struct sockaddr_in6 *)&ptr->ip; + res = memcmp(&v6->sin6_addr, &ptr_v6->sin6_addr, sizeof(struct in6_addr)); + } + else +#endif + { + ptr_v4 = (struct sockaddr_in *)&ptr->ip; + res = memcmp(&v4->sin_addr, &ptr_v4->sin_addr, sizeof(struct in_addr)); + } + if (res) + continue; + if (ptr->count > 0) + ptr->count--; + if (ptr->count == 0 && + (CurrentTime-ptr->last_attempt) >= ConfigFileEntry.throttle_time) + { + if (last_ptr != NULL) + last_ptr->next = ptr->next; + else + ip_hash_table[hash_index] = ptr->next; + + BlockHeapFree(ip_entry_heap, ptr); + ip_entries_count--; + return; + } + last_ptr = ptr; + } +} + +/* hash_ip() + * + * input - pointer to an irc_inaddr + * output - integer value used as index into hash table + * side effects - hopefully, none + */ +static int +hash_ip(struct irc_ssaddr *addr) +{ + if (addr->ss.ss_family == AF_INET) + { + struct sockaddr_in *v4 = (struct sockaddr_in *)addr; + int hash; + uint32_t ip; + + ip = ntohl(v4->sin_addr.s_addr); + hash = ((ip >> 12) + ip) & (IP_HASH_SIZE-1); + return hash; + } +#ifdef IPV6 + else + { + int hash; + struct sockaddr_in6 *v6 = (struct sockaddr_in6 *)addr; + uint32_t *ip = (uint32_t *)&v6->sin6_addr.s6_addr; + + hash = ip[0] ^ ip[3]; + hash ^= hash >> 16; + hash ^= hash >> 8; + hash = hash & (IP_HASH_SIZE - 1); + return hash; + } +#else + return 0; +#endif +} + +/* count_ip_hash() + * + * inputs - pointer to counter of number of ips hashed + * - pointer to memory used for ip hash + * output - returned via pointers input + * side effects - NONE + * + * number of hashed ip #'s is counted up, plus the amount of memory + * used in the hash. + */ +void +count_ip_hash(unsigned int *number_ips_stored, uint64_t *mem_ips_stored) +{ + struct ip_entry *ptr; + int i; + + *number_ips_stored = 0; + *mem_ips_stored = 0; + + for (i = 0; i < IP_HASH_SIZE; i++) + { + for (ptr = ip_hash_table[i]; ptr; ptr = ptr->next) + { + *number_ips_stored += 1; + *mem_ips_stored += sizeof(struct ip_entry); + } + } +} + +/* garbage_collect_ip_entries() + * + * input - NONE + * output - NONE + * side effects - free up all ip entries with no connections + */ +static void +garbage_collect_ip_entries(void) +{ + struct ip_entry *ptr; + struct ip_entry *last_ptr; + struct ip_entry *next_ptr; + int i; + + for (i = 0; i < IP_HASH_SIZE; i++) + { + last_ptr = NULL; + + for (ptr = ip_hash_table[i]; ptr; ptr = next_ptr) + { + next_ptr = ptr->next; + + if (ptr->count == 0 && + (CurrentTime - ptr->last_attempt) >= ConfigFileEntry.throttle_time) + { + if (last_ptr != NULL) + last_ptr->next = ptr->next; + else + ip_hash_table[i] = ptr->next; + BlockHeapFree(ip_entry_heap, ptr); + ip_entries_count--; + } + else + last_ptr = ptr; + } + } +} + +/* detach_conf() + * + * inputs - pointer to client to detach + * - type of conf to detach + * output - 0 for success, -1 for failure + * side effects - Disassociate configuration from the client. + * Also removes a class from the list if marked for deleting. + */ +int +detach_conf(struct Client *client_p, ConfType type) +{ + dlink_node *ptr, *next_ptr; + struct ConfItem *conf; + struct ClassItem *aclass; + struct AccessItem *aconf; + struct ConfItem *aclass_conf; + + DLINK_FOREACH_SAFE(ptr, next_ptr, client_p->localClient->confs.head) + { + conf = ptr->data; + + if (type == CONF_TYPE || conf->type == type) + { + dlinkDelete(ptr, &client_p->localClient->confs); + free_dlink_node(ptr); + + switch (conf->type) + { + case CLIENT_TYPE: + case OPER_TYPE: + case SERVER_TYPE: + aconf = map_to_conf(conf); + + assert(aconf->clients > 0); + + if ((aclass_conf = aconf->class_ptr) != NULL) + { + aclass = map_to_conf(aclass_conf); + + assert(aclass->curr_user_count > 0); + + if (conf->type == CLIENT_TYPE) + remove_from_cidr_check(&client_p->localClient->ip, aclass); + if (--aclass->curr_user_count == 0 && aclass->active == 0) + delete_conf_item(aclass_conf); + } + + if (--aconf->clients == 0 && IsConfIllegal(aconf)) + delete_conf_item(conf); + + break; + default: + break; + } + + if (type != CONF_TYPE) + return 0; + } + } + + return -1; +} + +/* attach_conf() + * + * inputs - client pointer + * - conf pointer + * output - + * side effects - Associate a specific configuration entry to a *local* + * client (this is the one which used in accepting the + * connection). Note, that this automatically changes the + * attachment if there was an old one... + */ +int +attach_conf(struct Client *client_p, struct ConfItem *conf) +{ + struct AccessItem *aconf = map_to_conf(conf); + struct ClassItem *aclass = map_to_conf(aconf->class_ptr); + + if (dlinkFind(&client_p->localClient->confs, conf) != NULL) + return 1; + + if (IsConfIllegal(aconf)) /* TBV: can't happen */ + return NOT_AUTHORIZED; + + if (conf->type == CLIENT_TYPE) + if (cidr_limit_reached(IsConfExemptLimits(aconf), + &client_p->localClient->ip, aclass)) + return TOO_MANY; /* Already at maximum allowed */ + + aclass->curr_user_count++; + aconf->clients++; + + dlinkAdd(conf, make_dlink_node(), &client_p->localClient->confs); + + return 0; +} + +/* attach_connect_block() + * + * inputs - pointer to server to attach + * - name of server + * - hostname of server + * output - true (1) if both are found, otherwise return false (0) + * side effects - find connect block and attach them to connecting client + */ +int +attach_connect_block(struct Client *client_p, const char *name, + const char *host) +{ + dlink_node *ptr; + struct ConfItem *conf; + struct AccessItem *aconf; + + assert(client_p != NULL); + assert(host != NULL); + + if (client_p == NULL || host == NULL) + return 0; + + DLINK_FOREACH(ptr, server_items.head) + { + conf = ptr->data; + aconf = map_to_conf(conf); + + if (match(conf->name, name) == 0 || match(aconf->host, host) == 0) + continue; + + attach_conf(client_p, conf); + return -1; + } + + return 0; +} + +/* find_conf_exact() + * + * inputs - type of ConfItem + * - pointer to name to find + * - pointer to username to find + * - pointer to host to find + * output - NULL or pointer to conf found + * side effects - find a conf entry which matches the hostname + * and has the same name. + */ +struct ConfItem * +find_conf_exact(ConfType type, const char *name, const char *user, + const char *host) +{ + dlink_node *ptr; + dlink_list *list_p; + struct ConfItem *conf = NULL; + struct AccessItem *aconf; + + /* Only valid for OPER_TYPE and ...? */ + list_p = map_to_list(type); + + DLINK_FOREACH(ptr, (*list_p).head) + { + conf = ptr->data; + + if (conf->name == NULL) + continue; + aconf = map_to_conf(conf); + if (aconf->host == NULL) + continue; + if (irccmp(conf->name, name) != 0) + continue; + + /* + ** Accept if the *real* hostname (usually sockethost) + ** socket host) matches *either* host or name field + ** of the configuration. + */ + if (!match(aconf->host, host) || !match(aconf->user, user)) + continue; + if (type == OPER_TYPE) + { + struct ClassItem *aclass = map_to_conf(aconf->class_ptr); + + if (aconf->clients >= aclass->max_total) + continue; + } + + return conf; + } + + return NULL; +} + +/* find_conf_name() + * + * inputs - pointer to conf link list to search + * - pointer to name to find + * - int mask of type of conf to find + * output - NULL or pointer to conf found + * side effects - find a conf entry which matches the name + * and has the given mask. + */ +struct ConfItem * +find_conf_name(dlink_list *list, const char *name, ConfType type) +{ + dlink_node *ptr; + struct ConfItem* conf; + + DLINK_FOREACH(ptr, list->head) + { + conf = ptr->data; + + if (conf->type == type) + { + if (conf->name && (irccmp(conf->name, name) == 0 || + match(conf->name, name))) + return conf; + } + } + + return NULL; +} + +/* map_to_list() + * + * inputs - ConfType conf + * output - pointer to dlink_list to use + * side effects - none + */ +static dlink_list * +map_to_list(ConfType type) +{ + switch(type) + { + case RXLINE_TYPE: + return(&rxconf_items); + break; + case XLINE_TYPE: + return(&xconf_items); + break; + case ULINE_TYPE: + return(&uconf_items); + break; + case NRESV_TYPE: + return(&nresv_items); + break; + case OPER_TYPE: + return(&oconf_items); + break; + case CLASS_TYPE: + return(&class_items); + break; + case SERVER_TYPE: + return(&server_items); + break; + case SERVICE_TYPE: + return(&service_items); + break; + case CLUSTER_TYPE: + return(&cluster_items); + break; + case CONF_TYPE: + case GLINE_TYPE: + case KLINE_TYPE: + case DLINE_TYPE: + case CRESV_TYPE: + default: + return NULL; + } +} + +/* find_matching_name_conf() + * + * inputs - type of link list to look in + * - pointer to name string to find + * - pointer to user + * - pointer to host + * - optional action to match on as well + * output - NULL or pointer to found struct MatchItem + * side effects - looks for a match on name field + */ +struct ConfItem * +find_matching_name_conf(ConfType type, const char *name, const char *user, + const char *host, int action) +{ + dlink_node *ptr=NULL; + struct ConfItem *conf=NULL; + struct AccessItem *aconf=NULL; + struct MatchItem *match_item=NULL; + dlink_list *list_p = map_to_list(type); + + switch (type) + { +#ifdef HAVE_LIBPCRE + case RXLINE_TYPE: + DLINK_FOREACH(ptr, list_p->head) + { + conf = ptr->data; + assert(conf->regexpname); + + if (!ircd_pcre_exec(conf->regexpname, name)) + return conf; + } + break; +#endif + case SERVICE_TYPE: + DLINK_FOREACH(ptr, list_p->head) + { + conf = ptr->data; + + if (EmptyString(conf->name)) + continue; + if ((name != NULL) && !irccmp(name, conf->name)) + return conf; + } + break; + + case XLINE_TYPE: + case ULINE_TYPE: + case NRESV_TYPE: + DLINK_FOREACH(ptr, list_p->head) + { + conf = ptr->data; + + match_item = map_to_conf(conf); + if (EmptyString(conf->name)) + continue; + if ((name != NULL) && match_esc(conf->name, name)) + { + if ((user == NULL && (host == NULL))) + return conf; + if ((match_item->action & action) != action) + continue; + if (EmptyString(match_item->user) || EmptyString(match_item->host)) + return conf; + if (match(match_item->user, user) && match(match_item->host, host)) + return conf; + } + } + break; + + case SERVER_TYPE: + DLINK_FOREACH(ptr, list_p->head) + { + conf = ptr->data; + aconf = map_to_conf(conf); + + if ((name != NULL) && match_esc(name, conf->name)) + return conf; + else if ((host != NULL) && match_esc(host, aconf->host)) + return conf; + } + break; + + default: + break; + } + return NULL; +} + +/* find_exact_name_conf() + * + * inputs - type of link list to look in + * - pointer to name string to find + * - pointer to user + * - pointer to host + * output - NULL or pointer to found struct MatchItem + * side effects - looks for an exact match on name field + */ +struct ConfItem * +find_exact_name_conf(ConfType type, const struct Client *who, const char *name, + const char *user, const char *host) +{ + dlink_node *ptr = NULL; + struct AccessItem *aconf; + struct ConfItem *conf; + struct MatchItem *match_item; + dlink_list *list_p; + + list_p = map_to_list(type); + + switch(type) + { + case RXLINE_TYPE: + case XLINE_TYPE: + case ULINE_TYPE: + case NRESV_TYPE: + + DLINK_FOREACH(ptr, list_p->head) + { + conf = ptr->data; + match_item = (struct MatchItem *)map_to_conf(conf); + if (EmptyString(conf->name)) + continue; + + if (irccmp(conf->name, name) == 0) + { + if ((user == NULL && (host == NULL))) + return (conf); + if (EmptyString(match_item->user) || EmptyString(match_item->host)) + return (conf); + if (match(match_item->user, user) && match(match_item->host, host)) + return (conf); + } + } + break; + + case OPER_TYPE: + DLINK_FOREACH(ptr, list_p->head) + { + conf = ptr->data; + aconf = map_to_conf(conf); + + if (EmptyString(conf->name)) + continue; + + if (!irccmp(conf->name, name)) + { + if (!who) + return conf; + if (EmptyString(aconf->user) || EmptyString(aconf->host)) + return conf; + if (match(aconf->user, who->username)) + { + switch (aconf->type) + { + case HM_HOST: + if (match(aconf->host, who->host) || match(aconf->host, who->sockhost)) + return conf; + break; + case HM_IPV4: + if (who->localClient->aftype == AF_INET) + if (match_ipv4(&who->localClient->ip, &aconf->addr, aconf->bits)) + return conf; + break; +#ifdef IPV6 + case HM_IPV6: + if (who->localClient->aftype == AF_INET6) + if (match_ipv6(&who->localClient->ip, &aconf->addr, aconf->bits)) + return conf; + break; +#endif + default: + assert(0); + } + } + } + } + + break; + + case SERVER_TYPE: + DLINK_FOREACH(ptr, list_p->head) + { + conf = ptr->data; + aconf = (struct AccessItem *)map_to_conf(conf); + if (EmptyString(conf->name)) + continue; + + if (name == NULL) + { + if (EmptyString(aconf->host)) + continue; + if (irccmp(aconf->host, host) == 0) + return(conf); + } + else if (irccmp(conf->name, name) == 0) + { + return (conf); + } + } + break; + + case CLASS_TYPE: + DLINK_FOREACH(ptr, list_p->head) + { + conf = ptr->data; + if (EmptyString(conf->name)) + continue; + + if (irccmp(conf->name, name) == 0) + return (conf); + } + break; + + default: + break; + } + return(NULL); +} + +/* rehash() + * + * Actual REHASH service routine. Called with sig == 0 if it has been called + * as a result of an operator issuing this command, else assume it has been + * called as a result of the server receiving a HUP signal. + */ +int +rehash(int sig) +{ + if (sig != 0) + sendto_realops_flags(UMODE_ALL, L_ALL, + "Got signal SIGHUP, reloading ircd.conf file"); + + restart_resolver(); + + /* don't close listeners until we know we can go ahead with the rehash */ + + /* Check to see if we magically got(or lost) IPv6 support */ + check_can_use_v6(); + + read_conf_files(0); + + if (ServerInfo.description != NULL) + strlcpy(me.info, ServerInfo.description, sizeof(me.info)); + + load_conf_modules(); + + flush_deleted_I_P(); + + rehashed_klines = 1; +/* XXX */ + if (ConfigLoggingEntry.use_logging) + log_close_all(); + + return(0); +} + +/* set_default_conf() + * + * inputs - NONE + * output - NONE + * side effects - Set default values here. + * This is called **PRIOR** to parsing the + * configuration file. If you want to do some validation + * of values later, put them in validate_conf(). + */ +static void +set_default_conf(void) +{ + /* verify init_class() ran, this should be an unnecessary check + * but its not much work. + */ + assert(class_default == (struct ConfItem *) class_items.tail->data); + +#ifdef HAVE_LIBCRYPTO + ServerInfo.rsa_private_key = NULL; + ServerInfo.rsa_private_key_file = NULL; +#endif + + /* ServerInfo.name is not rehashable */ + /* ServerInfo.name = ServerInfo.name; */ + ServerInfo.description = NULL; + DupString(ServerInfo.network_name, NETWORK_NAME_DEFAULT); + DupString(ServerInfo.network_desc, NETWORK_DESC_DEFAULT); + + memset(&ServerInfo.ip, 0, sizeof(ServerInfo.ip)); + ServerInfo.specific_ipv4_vhost = 0; + memset(&ServerInfo.ip6, 0, sizeof(ServerInfo.ip6)); + ServerInfo.specific_ipv6_vhost = 0; + + ServerInfo.max_clients = MAXCLIENTS_MAX; + + ServerInfo.hub = 0; + ServerInfo.dns_host.sin_addr.s_addr = 0; + ServerInfo.dns_host.sin_port = 0; + AdminInfo.name = NULL; + AdminInfo.email = NULL; + AdminInfo.description = NULL; + + log_close_all(); + + ConfigLoggingEntry.use_logging = 1; + + ConfigChannel.disable_fake_channels = 0; + ConfigChannel.restrict_channels = 0; + ConfigChannel.knock_delay = 300; + ConfigChannel.knock_delay_channel = 60; + ConfigChannel.max_chans_per_user = 25; + ConfigChannel.max_chans_per_oper = 50; + ConfigChannel.quiet_on_ban = 1; + ConfigChannel.max_bans = 25; + ConfigChannel.default_split_user_count = 0; + ConfigChannel.default_split_server_count = 0; + ConfigChannel.no_join_on_split = 0; + ConfigChannel.no_create_on_split = 0; + + ConfigServerHide.flatten_links = 0; + ConfigServerHide.links_delay = 300; + ConfigServerHide.hidden = 0; + ConfigServerHide.hide_servers = 0; + DupString(ConfigServerHide.hidden_name, NETWORK_NAME_DEFAULT); + ConfigServerHide.hide_server_ips = 0; + + + DupString(ConfigFileEntry.service_name, SERVICE_NAME_DEFAULT); + ConfigFileEntry.max_watch = WATCHSIZE_DEFAULT; + ConfigFileEntry.glines = 0; + ConfigFileEntry.gline_time = 12 * 3600; + ConfigFileEntry.gline_request_time = GLINE_REQUEST_EXPIRE_DEFAULT; + ConfigFileEntry.gline_min_cidr = 16; + ConfigFileEntry.gline_min_cidr6 = 48; + ConfigFileEntry.invisible_on_connect = 1; + ConfigFileEntry.tkline_expire_notices = 1; + ConfigFileEntry.hide_spoof_ips = 1; + ConfigFileEntry.ignore_bogus_ts = 0; + ConfigFileEntry.disable_auth = 0; + ConfigFileEntry.disable_remote = 0; + ConfigFileEntry.kill_chase_time_limit = 90; + ConfigFileEntry.default_floodcount = 8; + ConfigFileEntry.failed_oper_notice = 1; + ConfigFileEntry.dots_in_ident = 0; + ConfigFileEntry.min_nonwildcard = 4; + ConfigFileEntry.min_nonwildcard_simple = 3; + ConfigFileEntry.max_accept = 20; + ConfigFileEntry.anti_nick_flood = 0; + ConfigFileEntry.max_nick_time = 20; + ConfigFileEntry.max_nick_changes = 5; + ConfigFileEntry.anti_spam_exit_message_time = 0; + ConfigFileEntry.ts_warn_delta = TS_WARN_DELTA_DEFAULT; + ConfigFileEntry.ts_max_delta = TS_MAX_DELTA_DEFAULT; + ConfigFileEntry.warn_no_nline = 1; + ConfigFileEntry.stats_o_oper_only = 0; + ConfigFileEntry.stats_k_oper_only = 1; /* masked */ + ConfigFileEntry.stats_i_oper_only = 1; /* masked */ + ConfigFileEntry.stats_P_oper_only = 0; + ConfigFileEntry.caller_id_wait = 60; + ConfigFileEntry.opers_bypass_callerid = 0; + ConfigFileEntry.pace_wait = 10; + ConfigFileEntry.pace_wait_simple = 1; + ConfigFileEntry.short_motd = 0; + ConfigFileEntry.ping_cookie = 0; + ConfigFileEntry.no_oper_flood = 0; + ConfigFileEntry.true_no_oper_flood = 0; + ConfigFileEntry.oper_pass_resv = 1; + ConfigFileEntry.max_targets = MAX_TARGETS_DEFAULT; + ConfigFileEntry.oper_only_umodes = UMODE_DEBUG; + ConfigFileEntry.oper_umodes = UMODE_BOTS | UMODE_LOCOPS | UMODE_SERVNOTICE | + UMODE_OPERWALL | UMODE_WALLOP; + ConfigFileEntry.use_egd = 0; + ConfigFileEntry.egdpool_path = NULL; + ConfigFileEntry.throttle_time = 10; +} + +static void +validate_conf(void) +{ + if (ConfigFileEntry.ts_warn_delta < TS_WARN_DELTA_MIN) + ConfigFileEntry.ts_warn_delta = TS_WARN_DELTA_DEFAULT; + + if (ConfigFileEntry.ts_max_delta < TS_MAX_DELTA_MIN) + ConfigFileEntry.ts_max_delta = TS_MAX_DELTA_DEFAULT; + + if (ServerInfo.network_name == NULL) + DupString(ServerInfo.network_name,NETWORK_NAME_DEFAULT); + + if (ServerInfo.network_desc == NULL) + DupString(ServerInfo.network_desc,NETWORK_DESC_DEFAULT); + + if (ConfigFileEntry.service_name == NULL) + DupString(ConfigFileEntry.service_name, SERVICE_NAME_DEFAULT); + + ConfigFileEntry.max_watch = IRCD_MAX(ConfigFileEntry.max_watch, WATCHSIZE_MIN); +} + +/* read_conf() + * + * inputs - file descriptor pointing to config file to use + * output - None + * side effects - Read configuration file. + */ +static void +read_conf(FILE *file) +{ + lineno = 0; + + set_default_conf(); /* Set default values prior to conf parsing */ + conf_parser_ctx.pass = 1; + yyparse(); /* pick up the classes first */ + + rewind(file); + + conf_parser_ctx.pass = 2; + yyparse(); /* Load the values from the conf */ + validate_conf(); /* Check to make sure some values are still okay. */ + /* Some global values are also loaded here. */ + check_class(); /* Make sure classes are valid */ +} + +/* lookup_confhost() + * + * start DNS lookups of all hostnames in the conf + * line and convert an IP addresses in a.b.c.d number for to IP#s. + */ +static void +lookup_confhost(struct ConfItem *conf) +{ + struct AccessItem *aconf; + struct addrinfo hints, *res; + + aconf = map_to_conf(conf); + + if (has_wildcards(aconf->host)) + { + ilog(LOG_TYPE_IRCD, "Host/server name error: (%s) (%s)", + aconf->host, conf->name); + return; + } + + /* Do name lookup now on hostnames given and store the + * ip numbers in conf structure. + */ + memset(&hints, 0, sizeof(hints)); + + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + + /* Get us ready for a bind() and don't bother doing dns lookup */ + hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST; + + if (getaddrinfo(aconf->host, NULL, &hints, &res)) + { + conf_dns_lookup(aconf); + return; + } + + assert(res != NULL); + + memcpy(&aconf->addr, res->ai_addr, res->ai_addrlen); + aconf->addr.ss_len = res->ai_addrlen; + aconf->addr.ss.ss_family = res->ai_family; + freeaddrinfo(res); +} + +/* conf_connect_allowed() + * + * inputs - pointer to inaddr + * - int type ipv4 or ipv6 + * output - BANNED or accepted + * side effects - none + */ +int +conf_connect_allowed(struct irc_ssaddr *addr, int aftype) +{ + struct ip_entry *ip_found; + struct AccessItem *aconf = find_dline_conf(addr, aftype); + + /* DLINE exempt also gets you out of static limits/pacing... */ + if (aconf && (aconf->status & CONF_EXEMPTDLINE)) + return 0; + + if (aconf != NULL) + return BANNED_CLIENT; + + ip_found = find_or_add_ip(addr); + + if ((CurrentTime - ip_found->last_attempt) < + ConfigFileEntry.throttle_time) + { + ip_found->last_attempt = CurrentTime; + return TOO_FAST; + } + + ip_found->last_attempt = CurrentTime; + return 0; +} + +static struct AccessItem * +find_regexp_kline(const char *uhi[]) +{ +#ifdef HAVE_LIBPCRE + const dlink_node *ptr = NULL; + + DLINK_FOREACH(ptr, rkconf_items.head) + { + struct AccessItem *aptr = map_to_conf(ptr->data); + + assert(aptr->regexuser); + assert(aptr->regexhost); + + if (!ircd_pcre_exec(aptr->regexuser, uhi[0]) && + (!ircd_pcre_exec(aptr->regexhost, uhi[1]) || + !ircd_pcre_exec(aptr->regexhost, uhi[2]))) + return aptr; + } +#endif + return NULL; +} + +/* find_kill() + * + * inputs - pointer to client structure + * output - pointer to struct AccessItem if found + * side effects - See if this user is klined already, + * and if so, return struct AccessItem pointer + */ +struct AccessItem * +find_kill(struct Client *client_p) +{ + struct AccessItem *aconf = NULL; + const char *uhi[3]; + + uhi[0] = client_p->username; + uhi[1] = client_p->host; + uhi[2] = client_p->sockhost; + + assert(client_p != NULL); + + aconf = find_conf_by_address(client_p->host, &client_p->localClient->ip, + CONF_KLINE, client_p->localClient->aftype, + client_p->username, NULL, 1); + if (aconf == NULL) + aconf = find_regexp_kline(uhi); + + return aconf; +} + +struct AccessItem * +find_gline(struct Client *client_p) +{ + struct AccessItem *aconf; + + assert(client_p != NULL); + + aconf = find_conf_by_address(client_p->host, &client_p->localClient->ip, + CONF_GLINE, client_p->localClient->aftype, + client_p->username, NULL, 1); + return aconf; +} + +/* add_temp_line() + * + * inputs - pointer to struct ConfItem + * output - none + * Side effects - links in given struct ConfItem into + * temporary *line link list + */ +void +add_temp_line(struct ConfItem *conf) +{ + if (conf->type == XLINE_TYPE) + { + conf->flags |= CONF_FLAGS_TEMPORARY; + dlinkAdd(conf, make_dlink_node(), &temporary_xlines); + } + else if ((conf->type == NRESV_TYPE) || (conf->type == CRESV_TYPE)) + { + conf->flags |= CONF_FLAGS_TEMPORARY; + dlinkAdd(conf, make_dlink_node(), &temporary_resv); + } +} + +/* cleanup_tklines() + * + * inputs - NONE + * output - NONE + * side effects - call function to expire temporary k/d lines + * This is an event started off in ircd.c + */ +void +cleanup_tklines(void *notused) +{ + hostmask_expire_temporary(); + expire_tklines(&temporary_xlines); + expire_tklines(&temporary_resv); +} + +/* expire_tklines() + * + * inputs - tkline list pointer + * output - NONE + * side effects - expire tklines + */ +static void +expire_tklines(dlink_list *tklist) +{ + dlink_node *ptr; + dlink_node *next_ptr; + struct ConfItem *conf; + struct MatchItem *xconf; + struct MatchItem *nconf; + struct ResvChannel *cconf; + + DLINK_FOREACH_SAFE(ptr, next_ptr, tklist->head) + { + conf = ptr->data; + + if (conf->type == XLINE_TYPE) + { + xconf = (struct MatchItem *)map_to_conf(conf); + if (xconf->hold <= CurrentTime) + { + if (ConfigFileEntry.tkline_expire_notices) + sendto_realops_flags(UMODE_ALL, L_ALL, + "Temporary X-line for [%s] sexpired", conf->name); + dlinkDelete(ptr, tklist); + free_dlink_node(ptr); + delete_conf_item(conf); + } + } + else if (conf->type == NRESV_TYPE) + { + nconf = (struct MatchItem *)map_to_conf(conf); + if (nconf->hold <= CurrentTime) + { + if (ConfigFileEntry.tkline_expire_notices) + sendto_realops_flags(UMODE_ALL, L_ALL, + "Temporary RESV for [%s] expired", conf->name); + dlinkDelete(ptr, tklist); + free_dlink_node(ptr); + delete_conf_item(conf); + } + } + else if (conf->type == CRESV_TYPE) + { + cconf = (struct ResvChannel *)map_to_conf(conf); + if (cconf->hold <= CurrentTime) + { + if (ConfigFileEntry.tkline_expire_notices) + sendto_realops_flags(UMODE_ALL, L_ALL, + "Temporary RESV for [%s] expired", cconf->name); + delete_channel_resv(cconf); + } + } + } +} + +/* oper_privs_as_string() + * + * inputs - pointer to client_p + * output - pointer to static string showing oper privs + * side effects - return as string, the oper privs as derived from port + */ +static const struct oper_privs +{ + const unsigned int oprivs; + const unsigned char c; +} flag_list[] = { + { OPER_FLAG_ADMIN, 'A' }, + { OPER_FLAG_REMOTEBAN, 'B' }, + { OPER_FLAG_DIE, 'D' }, + { OPER_FLAG_GLINE, 'G' }, + { OPER_FLAG_REHASH, 'H' }, + { OPER_FLAG_K, 'K' }, + { OPER_FLAG_OPERWALL, 'L' }, + { OPER_FLAG_N, 'N' }, + { OPER_FLAG_GLOBAL_KILL, 'O' }, + { OPER_FLAG_REMOTE, 'R' }, + { OPER_FLAG_OPER_SPY, 'S' }, + { OPER_FLAG_UNKLINE, 'U' }, + { OPER_FLAG_X, 'X' }, + { 0, '\0' } +}; + +char * +oper_privs_as_string(const unsigned int port) +{ + static char privs_out[16]; + char *privs_ptr = privs_out; + unsigned int i = 0; + + for (; flag_list[i].oprivs; ++i) + { + if (port & flag_list[i].oprivs) + *privs_ptr++ = flag_list[i].c; + else + *privs_ptr++ = ToLowerTab[flag_list[i].c]; + } + + *privs_ptr = '\0'; + + return privs_out; +} + +/* + * Input: A client to find the active oper{} name for. + * Output: The nick!user@host{oper} of the oper. + * "oper" is server name for remote opers + * Side effects: None. + */ +const char * +get_oper_name(const struct Client *client_p) +{ + dlink_node *cnode = NULL; + /* +5 for !,@,{,} and null */ + static char buffer[NICKLEN + USERLEN + HOSTLEN + HOSTLEN + 5]; + + if (MyConnect(client_p)) + { + if ((cnode = client_p->localClient->confs.head)) + { + struct ConfItem *conf = cnode->data; + const struct AccessItem *aconf = map_to_conf(conf); + + if (IsConfOperator(aconf)) + { + snprintf(buffer, sizeof(buffer), "%s!%s@%s{%s}", client_p->name, + client_p->username, client_p->host, conf->name); + return buffer; + } + } + + /* Probably should assert here for now. If there is an oper out there + * with no oper{} conf attached, it would be good for us to know... + */ + assert(0); /* Oper without oper conf! */ + } + + snprintf(buffer, sizeof(buffer), "%s!%s@%s{%s}", client_p->name, + client_p->username, client_p->host, client_p->servptr->name); + return buffer; +} + +/* read_conf_files() + * + * inputs - cold start YES or NO + * output - none + * side effects - read all conf files needed, ircd.conf kline.conf etc. + */ +void +read_conf_files(int cold) +{ + const char *filename; + char chanmodes[32]; + char chanlimit[32]; + + conf_parser_ctx.boot = cold; + filename = get_conf_name(CONF_TYPE); + + /* We need to know the initial filename for the yyerror() to report + FIXME: The full path is in conffilenamebuf first time since we + dont know anything else + + - Gozem 2002-07-21 + */ + strlcpy(conffilebuf, filename, sizeof(conffilebuf)); + + if ((conf_parser_ctx.conf_file = fopen(filename, "r")) == NULL) + { + if (cold) + { + ilog(LOG_TYPE_IRCD, "Unable to read configuration file '%s': %s", + filename, strerror(errno)); + exit(-1); + } + else + { + sendto_realops_flags(UMODE_ALL, L_ALL, + "Unable to read configuration file '%s': %s", + filename, strerror(errno)); + return; + } + } + + if (!cold) + clear_out_old_conf(); + + read_conf(conf_parser_ctx.conf_file); + fclose(conf_parser_ctx.conf_file); + + add_isupport("NETWORK", ServerInfo.network_name, -1); + snprintf(chanmodes, sizeof(chanmodes), "beI:%d", + ConfigChannel.max_bans); + add_isupport("MAXLIST", chanmodes, -1); + add_isupport("MAXTARGETS", NULL, ConfigFileEntry.max_targets); + + add_isupport("CHANTYPES", "#", -1); + + snprintf(chanlimit, sizeof(chanlimit), "#:%d", + ConfigChannel.max_chans_per_user); + add_isupport("CHANLIMIT", chanlimit, -1); + snprintf(chanmodes, sizeof(chanmodes), "%s", + "beI,k,l,imnprstORS"); + add_isupport("CHANNELLEN", NULL, LOCAL_CHANNELLEN); + + add_isupport("EXCEPTS", "e", -1); + add_isupport("INVEX", "I", -1); + add_isupport("CHANMODES", chanmodes, -1); + + /* + * message_locale may have changed. rebuild isupport since it relies + * on strlen(form_str(RPL_ISUPPORT)) + */ + rebuild_isupport_message_line(); + + parse_conf_file(KLINE_TYPE, cold); + parse_conf_file(DLINE_TYPE, cold); + parse_conf_file(XLINE_TYPE, cold); + parse_conf_file(NRESV_TYPE, cold); + parse_conf_file(CRESV_TYPE, cold); +} + +/* parse_conf_file() + * + * inputs - type of conf file to parse + * output - none + * side effects - conf file for givenconf type is opened and read then parsed + */ +static void +parse_conf_file(int type, int cold) +{ + FILE *file = NULL; + const char *filename = get_conf_name(type); + + if ((file = fopen(filename, "r")) == NULL) + { + if (cold) + ilog(LOG_TYPE_IRCD, "Unable to read configuration file '%s': %s", + filename, strerror(errno)); + else + sendto_realops_flags(UMODE_ALL, L_ALL, + "Unable to read configuration file '%s': %s", + filename, strerror(errno)); + } + else + { + parse_csv_file(file, type); + fclose(file); + } +} + +/* clear_out_old_conf() + * + * inputs - none + * output - none + * side effects - Clear out the old configuration + */ +static void +clear_out_old_conf(void) +{ + dlink_node *ptr = NULL, *next_ptr = NULL; + struct ConfItem *conf; + struct AccessItem *aconf; + struct ClassItem *cltmp; + dlink_list *free_items [] = { + &server_items, &oconf_items, + &uconf_items, &xconf_items, &rxconf_items, &rkconf_items, + &nresv_items, &cluster_items, &service_items, NULL + }; + + dlink_list ** iterator = free_items; /* C is dumb */ + + /* We only need to free anything allocated by yyparse() here. + * Resetting structs, etc, is taken care of by set_default_conf(). + */ + + for (; *iterator != NULL; iterator++) + { + DLINK_FOREACH_SAFE(ptr, next_ptr, (*iterator)->head) + { + conf = ptr->data; + /* XXX This is less than pretty */ + if (conf->type == SERVER_TYPE) + { + aconf = map_to_conf(conf); + + if (aconf->clients != 0) + { + SetConfIllegal(aconf); + dlinkDelete(&conf->node, &server_items); + } + else + { + delete_conf_item(conf); + } + } + else if (conf->type == OPER_TYPE) + { + aconf = map_to_conf(conf); + + if (aconf->clients != 0) + { + SetConfIllegal(aconf); + dlinkDelete(&conf->node, &oconf_items); + } + else + { + delete_conf_item(conf); + } + } + else if (conf->type == XLINE_TYPE || + conf->type == RXLINE_TYPE || + conf->type == RKLINE_TYPE) + { + /* temporary (r)xlines are also on + * the (r)xconf items list */ + if (conf->flags & CONF_FLAGS_TEMPORARY) + continue; + + delete_conf_item(conf); + } + else + { + delete_conf_item(conf); + } + } + } + + /* + * don't delete the class table, rather mark all entries + * for deletion. The table is cleaned up by check_class. - avalon + */ + DLINK_FOREACH(ptr, class_items.head) + { + cltmp = map_to_conf(ptr->data); + + if (ptr != class_items.tail) /* never mark the "default" class */ + cltmp->active = 0; + } + + clear_out_address_conf(); + + /* clean out module paths */ + mod_clear_paths(); + + /* clean out ServerInfo */ + MyFree(ServerInfo.description); + ServerInfo.description = NULL; + MyFree(ServerInfo.network_name); + ServerInfo.network_name = NULL; + MyFree(ServerInfo.network_desc); + ServerInfo.network_desc = NULL; + MyFree(ConfigFileEntry.egdpool_path); + ConfigFileEntry.egdpool_path = NULL; +#ifdef HAVE_LIBCRYPTO + if (ServerInfo.rsa_private_key != NULL) + { + RSA_free(ServerInfo.rsa_private_key); + ServerInfo.rsa_private_key = NULL; + } + + MyFree(ServerInfo.rsa_private_key_file); + ServerInfo.rsa_private_key_file = NULL; + + if (ServerInfo.server_ctx) + SSL_CTX_set_options(ServerInfo.server_ctx, SSL_OP_NO_SSLv2| + SSL_OP_NO_SSLv3| + SSL_OP_NO_TLSv1); + if (ServerInfo.client_ctx) + SSL_CTX_set_options(ServerInfo.client_ctx, SSL_OP_NO_SSLv2| + SSL_OP_NO_SSLv3| + SSL_OP_NO_TLSv1); +#endif + + /* clean out old resvs from the conf */ + clear_conf_resv(); + + /* clean out AdminInfo */ + MyFree(AdminInfo.name); + AdminInfo.name = NULL; + MyFree(AdminInfo.email); + AdminInfo.email = NULL; + MyFree(AdminInfo.description); + AdminInfo.description = NULL; + + /* operator{} and class{} blocks are freed above */ + /* clean out listeners */ + close_listeners(); + + /* auth{}, quarantine{}, shared{}, connect{}, kill{}, deny{}, + * exempt{} and gecos{} blocks are freed above too + */ + + /* clean out general */ + MyFree(ConfigFileEntry.service_name); + ConfigFileEntry.service_name = NULL; + + delete_isupport("INVEX"); + delete_isupport("EXCEPTS"); +} + +/* flush_deleted_I_P() + * + * inputs - none + * output - none + * side effects - This function removes I/P conf items + */ +static void +flush_deleted_I_P(void) +{ + dlink_node *ptr; + dlink_node *next_ptr; + struct ConfItem *conf; + struct AccessItem *aconf; + dlink_list * free_items [] = { + &server_items, &oconf_items, NULL + }; + dlink_list ** iterator = free_items; /* C is dumb */ + + /* flush out deleted I and P lines + * although still in use. + */ + for (; *iterator != NULL; iterator++) + { + DLINK_FOREACH_SAFE(ptr, next_ptr, (*iterator)->head) + { + conf = ptr->data; + aconf = (struct AccessItem *)map_to_conf(conf); + + if (IsConfIllegal(aconf)) + { + dlinkDelete(ptr, *iterator); + + if (aconf->clients == 0) + delete_conf_item(conf); + } + } + } +} + +/* get_conf_name() + * + * inputs - type of conf file to return name of file for + * output - pointer to filename for type of conf + * side effects - none + */ +const char * +get_conf_name(ConfType type) +{ + switch (type) + { + case CONF_TYPE: + return ConfigFileEntry.configfile; + break; + case KLINE_TYPE: + return ConfigFileEntry.klinefile; + break; + case DLINE_TYPE: + return ConfigFileEntry.dlinefile; + break; + case XLINE_TYPE: + return ConfigFileEntry.xlinefile; + break; + case CRESV_TYPE: + return ConfigFileEntry.cresvfile; + break; + case NRESV_TYPE: + return ConfigFileEntry.nresvfile; + break; + default: + return NULL; /* This should NEVER HAPPEN since we call this function + only with the above values, this will cause us to core + at some point if this happens so we know where it was */ + } +} + +#define BAD_PING (-1) + +/* get_conf_ping() + * + * inputs - pointer to struct AccessItem + * - pointer to a variable that receives ping warning time + * output - ping frequency + * side effects - NONE + */ +static int +get_conf_ping(struct ConfItem *conf, int *pingwarn) +{ + struct ClassItem *aclass; + struct AccessItem *aconf; + + if (conf != NULL) + { + aconf = (struct AccessItem *)map_to_conf(conf); + if (aconf->class_ptr != NULL) + { + aclass = (struct ClassItem *)map_to_conf(aconf->class_ptr); + *pingwarn = aclass->ping_warning; + return aclass->ping_freq; + } + } + + return BAD_PING; +} + +/* get_client_class() + * + * inputs - pointer to client struct + * output - pointer to name of class + * side effects - NONE + */ +const char * +get_client_class(struct Client *target_p) +{ + dlink_node *cnode = NULL; + struct AccessItem *aconf = NULL; + + assert(!IsMe(target_p)); + + if ((cnode = target_p->localClient->confs.head)) + { + struct ConfItem *conf = cnode->data; + + assert((conf->type == CLIENT_TYPE) || (conf->type == SERVER_TYPE) || + (conf->type == OPER_TYPE)); + + aconf = map_to_conf(conf); + if (aconf->class_ptr != NULL) + return aconf->class_ptr->name; + } + + return "default"; +} + +/* get_client_ping() + * + * inputs - pointer to client struct + * - pointer to a variable that receives ping warning time + * output - ping frequency + * side effects - NONE + */ +int +get_client_ping(struct Client *target_p, int *pingwarn) +{ + int ping = 0; + dlink_node *cnode = NULL; + + if ((cnode = target_p->localClient->confs.head)) + { + struct ConfItem *conf = cnode->data; + + assert((conf->type == CLIENT_TYPE) || (conf->type == SERVER_TYPE) || + (conf->type == OPER_TYPE)); + + ping = get_conf_ping(conf, pingwarn); + if (ping > 0) + return ping; + } + + *pingwarn = 0; + return DEFAULT_PINGFREQUENCY; +} + +/* find_class() + * + * inputs - string name of class + * output - corresponding Class pointer + * side effects - NONE + */ +struct ConfItem * +find_class(const char *classname) +{ + struct ConfItem *conf; + + if ((conf = find_exact_name_conf(CLASS_TYPE, NULL, classname, NULL, NULL)) != NULL) + return conf; + + return class_default; +} + +/* check_class() + * + * inputs - NONE + * output - NONE + * side effects - + */ +void +check_class(void) +{ + dlink_node *ptr = NULL, *next_ptr = NULL; + + DLINK_FOREACH_SAFE(ptr, next_ptr, class_items.head) + { + struct ClassItem *aclass = map_to_conf(ptr->data); + + if (!aclass->active && !aclass->curr_user_count) + { + destroy_cidr_class(aclass); + delete_conf_item(ptr->data); + } + } +} + +/* init_class() + * + * inputs - NONE + * output - NONE + * side effects - + */ +void +init_class(void) +{ + struct ClassItem *aclass; + + class_default = make_conf_item(CLASS_TYPE); + + aclass = map_to_conf(class_default); + aclass->active = 1; + DupString(class_default->name, "default"); + aclass->con_freq = DEFAULT_CONNECTFREQUENCY; + aclass->ping_freq = DEFAULT_PINGFREQUENCY; + aclass->max_total = MAXIMUM_LINKS_DEFAULT; + aclass->max_sendq = DEFAULT_SENDQ; + aclass->max_recvq = DEFAULT_RECVQ; + + client_check_cb = register_callback("check_client", check_client); +} + +/* get_sendq() + * + * inputs - pointer to client + * output - sendq for this client as found from its class + * side effects - NONE + */ +unsigned int +get_sendq(struct Client *client_p) +{ + unsigned int sendq = DEFAULT_SENDQ; + dlink_node *cnode; + struct ConfItem *class_conf; + struct ClassItem *aclass; + struct AccessItem *aconf; + + assert(!IsMe(client_p)); + + if ((cnode = client_p->localClient->confs.head)) + { + struct ConfItem *conf = cnode->data; + + assert((conf->type == CLIENT_TYPE) || (conf->type == SERVER_TYPE) || + (conf->type == OPER_TYPE)); + + aconf = map_to_conf(conf); + + if ((class_conf = aconf->class_ptr) == NULL) + return DEFAULT_SENDQ; /* TBV: shouldn't be possible at all */ + + aclass = map_to_conf(class_conf); + sendq = aclass->max_sendq; + return sendq; + } + + /* XXX return a default? + * if here, then there wasn't an attached conf with a sendq + * that is very bad -Dianora + */ + return DEFAULT_SENDQ; +} + +unsigned int +get_recvq(struct Client *client_p) +{ + unsigned int recvq = DEFAULT_RECVQ; + dlink_node *cnode; + struct ConfItem *class_conf; + struct ClassItem *aclass; + struct AccessItem *aconf; + + assert(!IsMe(client_p)); + + if ((cnode = client_p->localClient->confs.head)) + { + struct ConfItem *conf = cnode->data; + + assert((conf->type == CLIENT_TYPE) || (conf->type == SERVER_TYPE) || + (conf->type == OPER_TYPE)); + + aconf = map_to_conf(conf); + + if ((class_conf = aconf->class_ptr) == NULL) + return DEFAULT_RECVQ; /* TBV: shouldn't be possible at all */ + + aclass = map_to_conf(class_conf); + recvq = aclass->max_recvq; + return recvq; + } + + /* XXX return a default? + * if here, then there wasn't an attached conf with a recvq + * that is very bad -Dianora + */ + return DEFAULT_RECVQ; +} + +/* conf_add_class_to_conf() + * + * inputs - pointer to config item + * output - NONE + * side effects - Add a class pointer to a conf + */ +void +conf_add_class_to_conf(struct ConfItem *conf, const char *class_name) +{ + struct AccessItem *aconf = map_to_conf(conf); + struct ClassItem *class = NULL; + + if (class_name == NULL) + { + aconf->class_ptr = class_default; + + if (conf->type == CLIENT_TYPE) + sendto_realops_flags(UMODE_ALL, L_ALL, + "Warning *** Defaulting to default class for %s@%s", + aconf->user, aconf->host); + else + sendto_realops_flags(UMODE_ALL, L_ALL, + "Warning *** Defaulting to default class for %s", + conf->name); + } + else + aconf->class_ptr = find_class(class_name); + + if (aconf->class_ptr) + class = map_to_conf(aconf->class_ptr); + + if (aconf->class_ptr == NULL || !class->active) + { + if (conf->type == CLIENT_TYPE) + sendto_realops_flags(UMODE_ALL, L_ALL, + "Warning *** Defaulting to default class for %s@%s", + aconf->user, aconf->host); + else + sendto_realops_flags(UMODE_ALL, L_ALL, + "Warning *** Defaulting to default class for %s", + conf->name); + aconf->class_ptr = class_default; + } +} + +/* conf_add_server() + * + * inputs - pointer to config item + * - pointer to link count already on this conf + * output - NONE + * side effects - Add a connect block + */ +int +conf_add_server(struct ConfItem *conf, const char *class_name) +{ + struct AccessItem *aconf = map_to_conf(conf); + + conf_add_class_to_conf(conf, class_name); + + if (!aconf->host || !conf->name) + { + sendto_realops_flags(UMODE_ALL, L_ALL, "Bad connect block"); + ilog(LOG_TYPE_IRCD, "Bad connect block"); + return -1; + } + + if (EmptyString(aconf->passwd)) + { + sendto_realops_flags(UMODE_ALL, L_ALL, "Bad connect block, name %s", + conf->name); + ilog(LOG_TYPE_IRCD, "Bad connect block, host %s", conf->name); + return -1; + } + + lookup_confhost(conf); + + return 0; +} + +/* yyerror() + * + * inputs - message from parser + * output - NONE + * side effects - message to opers and log file entry is made + */ +void +yyerror(const char *msg) +{ + char newlinebuf[IRCD_BUFSIZE]; + + if (conf_parser_ctx.pass != 1) + return; + + strip_tabs(newlinebuf, linebuf, sizeof(newlinebuf)); + sendto_realops_flags(UMODE_ALL, L_ALL, "\"%s\", line %u: %s: %s", + conffilebuf, lineno + 1, msg, newlinebuf); + ilog(LOG_TYPE_IRCD, "\"%s\", line %u: %s: %s", + conffilebuf, lineno + 1, msg, newlinebuf); +} + +/* + * valid_tkline() + * + * inputs - pointer to ascii string to check + * - whether the specified time is in seconds or minutes + * output - -1 not enough parameters + * - 0 if not an integer number, else the number + * side effects - none + * Originally written by Dianora (Diane, db@db.net) + */ +time_t +valid_tkline(const char *p, int minutes) +{ + time_t result = 0; + + for (; *p; ++p) + { + if (!IsDigit(*p)) + return 0; + + result *= 10; + result += ((*p) & 0xF); + } + + /* + * In the degenerate case where oper does a /quote kline 0 user@host :reason + * i.e. they specifically use 0, I am going to return 1 instead + * as a return value of non-zero is used to flag it as a temporary kline + */ + if (result == 0) + result = 1; + + /* + * If the incoming time is in seconds convert it to minutes for the purpose + * of this calculation + */ + if (!minutes) + result = result / (time_t)60; + + if (result > MAX_TDKLINE_TIME) + result = MAX_TDKLINE_TIME; + + result = result * (time_t)60; /* turn it into seconds */ + + return result; +} + +/* valid_wild_card() + * + * input - pointer to client + * - int flag, 0 for no warning oper 1 for warning oper + * - count of following varargs to check + * output - 0 if not valid, 1 if valid + * side effects - NOTICE is given to source_p if warn is 1 + */ +int +valid_wild_card(struct Client *source_p, int warn, int count, ...) +{ + char *p; + char tmpch; + int nonwild = 0; + va_list args; + + /* + * Now we must check the user and host to make sure there + * are at least NONWILDCHARS non-wildcard characters in + * them, otherwise assume they are attempting to kline + * *@* or some variant of that. This code will also catch + * people attempting to kline *@*.tld, as long as NONWILDCHARS + * is greater than 3. In that case, there are only 3 non-wild + * characters (tld), so if NONWILDCHARS is 4, the kline will + * be disallowed. + * -wnder + */ + + va_start(args, count); + + while (count--) + { + p = va_arg(args, char *); + if (p == NULL) + continue; + + while ((tmpch = *p++)) + { + if (!IsKWildChar(tmpch)) + { + /* + * If we find enough non-wild characters, we can + * break - no point in searching further. + */ + if (++nonwild >= ConfigFileEntry.min_nonwildcard) + return 1; + } + } + } + + if (warn) + sendto_one(source_p, ":%s NOTICE %s :Please include at least %d non-wildcard characters with the mask", + me.name, source_p->name, ConfigFileEntry.min_nonwildcard); + return 0; +} + +/* XXX should this go into a separate file ? -Dianora */ +/* parse_aline + * + * input - pointer to cmd name being used + * - pointer to client using cmd + * - parc parameter count + * - parv[] list of parameters to parse + * - parse_flags bit map of things to test + * - pointer to user or string to parse into + * - pointer to host or NULL to parse into if non NULL + * - pointer to optional tkline time or NULL + * - pointer to target_server to parse into if non NULL + * - pointer to reason to parse into + * + * output - 1 if valid, -1 if not valid + * side effects - A generalised k/d/x etc. line parser, + * "ALINE [time] user@host|string [ON] target :reason" + * will parse returning a parsed user, host if + * h_p pointer is non NULL, string otherwise. + * if tkline_time pointer is non NULL a tk line will be set + * to non zero if found. + * if tkline_time pointer is NULL and tk line is found, + * error is reported. + * if target_server is NULL and an "ON" is found error + * is reported. + * if reason pointer is NULL ignore pointer, + * this allows use of parse_a_line in unkline etc. + * + * - Dianora + */ +int +parse_aline(const char *cmd, struct Client *source_p, + int parc, char **parv, + int parse_flags, char **up_p, char **h_p, time_t *tkline_time, + char **target_server, char **reason) +{ + int found_tkline_time=0; + static char def_reason[] = "No Reason"; + static char user[USERLEN*4+1]; + static char host[HOSTLEN*4+1]; + + parv++; + parc--; + + found_tkline_time = valid_tkline(*parv, TK_MINUTES); + + if (found_tkline_time != 0) + { + parv++; + parc--; + + if (tkline_time != NULL) + *tkline_time = found_tkline_time; + else + { + sendto_one(source_p, ":%s NOTICE %s :temp_line not supported by %s", + me.name, source_p->name, cmd); + return -1; + } + } + + if (parc == 0) + { + sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS), + me.name, source_p->name, cmd); + return -1; + } + + if (h_p == NULL) + *up_p = *parv; + else + { + if (find_user_host(source_p, *parv, user, host, parse_flags) == 0) + return -1; + + *up_p = user; + *h_p = host; + } + + parc--; + parv++; + + if (parc != 0) + { + if (irccmp(*parv, "ON") == 0) + { + parc--; + parv++; + + if (target_server == NULL) + { + sendto_one(source_p, ":%s NOTICE %s :ON server not supported by %s", + me.name, source_p->name, cmd); + return -1; + } + + if (!HasOFlag(source_p, OPER_FLAG_REMOTEBAN)) + { + sendto_one(source_p, form_str(ERR_NOPRIVS), + me.name, source_p->name, "remoteban"); + return -1; + } + + if (parc == 0 || EmptyString(*parv)) + { + sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS), + me.name, source_p->name, cmd); + return -1; + } + + *target_server = *parv; + parc--; + parv++; + } + else + { + /* Make sure target_server *is* NULL if no ON server found + * caller probably NULL'd it first, but no harm to do it again -db + */ + if (target_server != NULL) + *target_server = NULL; + } + } + + if (h_p != NULL) + { + if (strchr(user, '!') != NULL) + { + sendto_one(source_p, ":%s NOTICE %s :Invalid character '!' in kline", + me.name, source_p->name); + return -1; + } + + if ((parse_flags & AWILD) && !valid_wild_card(source_p, 1, 2, *up_p, *h_p)) + return -1; + } + else + if ((parse_flags & AWILD) && !valid_wild_card(source_p, 1, 1, *up_p)) + return -1; + + if (reason != NULL) + { + if (parc != 0 && !EmptyString(*parv)) + { + *reason = *parv; + if (!valid_comment(source_p, *reason, 1)) + return -1; + } + else + *reason = def_reason; + } + + return 1; +} + +/* find_user_host() + * + * inputs - pointer to client placing kline + * - pointer to user_host_or_nick + * - pointer to user buffer + * - pointer to host buffer + * output - 0 if not ok to kline, 1 to kline i.e. if valid user host + * side effects - + */ +static int +find_user_host(struct Client *source_p, char *user_host_or_nick, + char *luser, char *lhost, unsigned int flags) +{ + struct Client *target_p = NULL; + char *hostp = NULL; + + if (lhost == NULL) + { + strlcpy(luser, user_host_or_nick, USERLEN*4 + 1); + return 1; + } + + if ((hostp = strchr(user_host_or_nick, '@')) || *user_host_or_nick == '*') + { + /* Explicit user@host mask given */ + + if (hostp != NULL) /* I'm a little user@host */ + { + *(hostp++) = '\0'; /* short and squat */ + if (*user_host_or_nick) + strlcpy(luser, user_host_or_nick, USERLEN*4 + 1); /* here is my user */ + else + strcpy(luser, "*"); + if (*hostp) + strlcpy(lhost, hostp, HOSTLEN + 1); /* here is my host */ + else + strcpy(lhost, "*"); + } + else + { + luser[0] = '*'; /* no @ found, assume its *@somehost */ + luser[1] = '\0'; + strlcpy(lhost, user_host_or_nick, HOSTLEN*4 + 1); + } + + return 1; + } + else + { + /* Try to find user@host mask from nick */ + /* Okay to use source_p as the first param, because source_p == client_p */ + if ((target_p = + find_chasing(source_p, source_p, user_host_or_nick, NULL)) == NULL) + return 0; + + if (IsExemptKline(target_p)) + { + if (!IsServer(source_p)) + sendto_one(source_p, + ":%s NOTICE %s :%s is E-lined", + me.name, source_p->name, target_p->name); + return 0; + } + + /* + * turn the "user" bit into "*user", blow away '~' + * if found in original user name (non-idented) + */ + strlcpy(luser, target_p->username, USERLEN*4 + 1); + + if (target_p->username[0] == '~') + luser[0] = '*'; + + if (target_p->sockhost[0] == '\0' || + (target_p->sockhost[0] == '0' && target_p->sockhost[1] == '\0')) + strlcpy(lhost, target_p->host, HOSTLEN*4 + 1); + else + strlcpy(lhost, target_p->sockhost, HOSTLEN*4 + 1); + return 1; + } + + return 0; +} + +/* valid_comment() + * + * inputs - pointer to client + * - pointer to comment + * output - 0 if no valid comment, + * - 1 if valid + * side effects - truncates reason where necessary + */ +int +valid_comment(struct Client *source_p, char *comment, int warn) +{ + if (strchr(comment, '"')) + { + if (warn) + sendto_one(source_p, ":%s NOTICE %s :Invalid character '\"' in comment", + me.name, source_p->name); + return 0; + } + + if (strlen(comment) > REASONLEN) + comment[REASONLEN-1] = '\0'; + + return 1; +} + +/* match_conf_password() + * + * inputs - pointer to given password + * - pointer to Conf + * output - 1 or 0 if match + * side effects - none + */ +int +match_conf_password(const char *password, const struct AccessItem *aconf) +{ + const char *encr = NULL; + + if (EmptyString(password) || EmptyString(aconf->passwd)) + return 0; + + if (aconf->flags & CONF_FLAGS_ENCRYPTED) + encr = crypt(password, aconf->passwd); + else + encr = password; + + return !strcmp(encr, aconf->passwd); +} + +/* + * cluster_a_line + * + * inputs - client sending the cluster + * - command name "KLINE" "XLINE" etc. + * - capab -- CAP_KLN etc. from s_serv.h + * - cluster type -- CLUSTER_KLINE etc. from conf.h + * - pattern and args to send along + * output - none + * side effects - Take source_p send the pattern with args given + * along to all servers that match capab and cluster type +*/ +void +cluster_a_line(struct Client *source_p, const char *command, + int capab, int cluster_type, const char *pattern, ...) +{ + va_list args; + char buffer[IRCD_BUFSIZE]; + const dlink_node *ptr = NULL; + + va_start(args, pattern); + vsnprintf(buffer, sizeof(buffer), pattern, args); + va_end(args); + + DLINK_FOREACH(ptr, cluster_items.head) + { + const struct ConfItem *conf = ptr->data; + + if (conf->flags & cluster_type) + sendto_match_servs(source_p, conf->name, CAP_CLUSTER|capab, + "%s %s %s", command, conf->name, buffer); + } +} + +/* + * split_nuh + * + * inputs - pointer to original mask (modified in place) + * - pointer to pointer where nick should go + * - pointer to pointer where user should go + * - pointer to pointer where host should go + * output - NONE + * side effects - mask is modified in place + * If nick pointer is NULL, ignore writing to it + * this allows us to use this function elsewhere. + * + * mask nick user host + * ---------------------- ------- ------- ------ + * Dianora!db@db.net Dianora db db.net + * Dianora Dianora * * + * db.net * * db.net + * OR if nick pointer is NULL + * Dianora - * Dianora + * Dianora! Dianora * * + * Dianora!@ Dianora * * + * Dianora!db Dianora db * + * Dianora!@db.net Dianora * db.net + * db@db.net * db db.net + * !@ * * * + * @ * * * + * ! * * * + */ +void +split_nuh(struct split_nuh_item *const iptr) +{ + char *p = NULL, *q = NULL; + + if (iptr->nickptr) + strlcpy(iptr->nickptr, "*", iptr->nicksize); + if (iptr->userptr) + strlcpy(iptr->userptr, "*", iptr->usersize); + if (iptr->hostptr) + strlcpy(iptr->hostptr, "*", iptr->hostsize); + + if ((p = strchr(iptr->nuhmask, '!'))) + { + *p = '\0'; + + if (iptr->nickptr && *iptr->nuhmask != '\0') + strlcpy(iptr->nickptr, iptr->nuhmask, iptr->nicksize); + + if ((q = strchr(++p, '@'))) { + *q++ = '\0'; + + if (*p != '\0') + strlcpy(iptr->userptr, p, iptr->usersize); + + if (*q != '\0') + strlcpy(iptr->hostptr, q, iptr->hostsize); + } + else + { + if (*p != '\0') + strlcpy(iptr->userptr, p, iptr->usersize); + } + } + else + { + /* No ! found so lets look for a user@host */ + if ((p = strchr(iptr->nuhmask, '@'))) + { + /* if found a @ */ + *p++ = '\0'; + + if (*iptr->nuhmask != '\0') + strlcpy(iptr->userptr, iptr->nuhmask, iptr->usersize); + + if (*p != '\0') + strlcpy(iptr->hostptr, p, iptr->hostsize); + } + else + { + /* no @ found */ + if (!iptr->nickptr || strpbrk(iptr->nuhmask, ".:")) + strlcpy(iptr->hostptr, iptr->nuhmask, iptr->hostsize); + else + strlcpy(iptr->nickptr, iptr->nuhmask, iptr->nicksize); + } + } +} + +/* + * flags_to_ascii + * + * inputs - flags is a bitmask + * - pointer to table of ascii letters corresponding + * to each bit + * - flag 1 for convert ToLower if bit missing + * 0 if ignore. + * output - none + * side effects - string pointed to by p has bitmap chars written to it + */ +static void +flags_to_ascii(unsigned int flags, const unsigned int bit_table[], char *p, + int lowerit) +{ + unsigned int mask = 1; + int i = 0; + + for (mask = 1; (mask != 0) && (bit_table[i] != 0); mask <<= 1, i++) + { + if (flags & mask) + *p++ = bit_table[i]; + else if (lowerit) + *p++ = ToLower(bit_table[i]); + } + *p = '\0'; +} + +/* + * cidr_limit_reached + * + * inputs - int flag allowing over_rule of limits + * - pointer to the ip to be added + * - pointer to the class + * output - non zero if limit reached + * 0 if limit not reached + * side effects - + */ +static int +cidr_limit_reached(int over_rule, + struct irc_ssaddr *ip, struct ClassItem *aclass) +{ + dlink_node *ptr = NULL; + struct CidrItem *cidr; + + if (aclass->number_per_cidr <= 0) + return 0; + + if (ip->ss.ss_family == AF_INET) + { + if (aclass->cidr_bitlen_ipv4 <= 0) + return 0; + + DLINK_FOREACH(ptr, aclass->list_ipv4.head) + { + cidr = ptr->data; + if (match_ipv4(ip, &cidr->mask, aclass->cidr_bitlen_ipv4)) + { + if (!over_rule && (cidr->number_on_this_cidr >= aclass->number_per_cidr)) + return -1; + cidr->number_on_this_cidr++; + return 0; + } + } + cidr = MyMalloc(sizeof(struct CidrItem)); + cidr->number_on_this_cidr = 1; + cidr->mask = *ip; + mask_addr(&cidr->mask, aclass->cidr_bitlen_ipv4); + dlinkAdd(cidr, &cidr->node, &aclass->list_ipv4); + } +#ifdef IPV6 + else if (aclass->cidr_bitlen_ipv6 > 0) + { + DLINK_FOREACH(ptr, aclass->list_ipv6.head) + { + cidr = ptr->data; + if (match_ipv6(ip, &cidr->mask, aclass->cidr_bitlen_ipv6)) + { + if (!over_rule && (cidr->number_on_this_cidr >= aclass->number_per_cidr)) + return -1; + cidr->number_on_this_cidr++; + return 0; + } + } + cidr = MyMalloc(sizeof(struct CidrItem)); + cidr->number_on_this_cidr = 1; + cidr->mask = *ip; + mask_addr(&cidr->mask, aclass->cidr_bitlen_ipv6); + dlinkAdd(cidr, &cidr->node, &aclass->list_ipv6); + } +#endif + return 0; +} + +/* + * remove_from_cidr_check + * + * inputs - pointer to the ip to be removed + * - pointer to the class + * output - NONE + * side effects - + */ +static void +remove_from_cidr_check(struct irc_ssaddr *ip, struct ClassItem *aclass) +{ + dlink_node *ptr = NULL; + dlink_node *next_ptr = NULL; + struct CidrItem *cidr; + + if (aclass->number_per_cidr == 0) + return; + + if (ip->ss.ss_family == AF_INET) + { + if (aclass->cidr_bitlen_ipv4 <= 0) + return; + + DLINK_FOREACH_SAFE(ptr, next_ptr, aclass->list_ipv4.head) + { + cidr = ptr->data; + if (match_ipv4(ip, &cidr->mask, aclass->cidr_bitlen_ipv4)) + { + cidr->number_on_this_cidr--; + if (cidr->number_on_this_cidr == 0) + { + dlinkDelete(ptr, &aclass->list_ipv4); + MyFree(cidr); + return; + } + } + } + } +#ifdef IPV6 + else if (aclass->cidr_bitlen_ipv6 > 0) + { + DLINK_FOREACH_SAFE(ptr, next_ptr, aclass->list_ipv6.head) + { + cidr = ptr->data; + if (match_ipv6(ip, &cidr->mask, aclass->cidr_bitlen_ipv6)) + { + cidr->number_on_this_cidr--; + if (cidr->number_on_this_cidr == 0) + { + dlinkDelete(ptr, &aclass->list_ipv6); + MyFree(cidr); + return; + } + } + } + } +#endif +} + +static void +rebuild_cidr_list(int aftype, struct ConfItem *oldcl, struct ClassItem *newcl, + dlink_list *old_list, dlink_list *new_list, int changed) +{ + dlink_node *ptr; + struct Client *client_p; + struct ConfItem *conf; + struct AccessItem *aconf; + + if (!changed) + { + *new_list = *old_list; + old_list->head = old_list->tail = NULL; + old_list->length = 0; + return; + } + + DLINK_FOREACH(ptr, local_client_list.head) + { + client_p = ptr->data; + if (client_p->localClient->aftype != aftype) + continue; + if (dlink_list_length(&client_p->localClient->confs) == 0) + continue; + + conf = client_p->localClient->confs.tail->data; + if (conf->type == CLIENT_TYPE) + { + aconf = map_to_conf(conf); + if (aconf->class_ptr == oldcl) + cidr_limit_reached(1, &client_p->localClient->ip, newcl); + } + } +} + +/* + * rebuild_cidr_class + * + * inputs - pointer to old conf + * - pointer to new_class + * output - none + * side effects - rebuilds the class link list of cidr blocks + */ +void +rebuild_cidr_class(struct ConfItem *conf, struct ClassItem *new_class) +{ + struct ClassItem *old_class = map_to_conf(conf); + + if (old_class->number_per_cidr > 0 && new_class->number_per_cidr > 0) + { + if (old_class->cidr_bitlen_ipv4 > 0 && new_class->cidr_bitlen_ipv4 > 0) + rebuild_cidr_list(AF_INET, conf, new_class, + &old_class->list_ipv4, &new_class->list_ipv4, + old_class->cidr_bitlen_ipv4 != new_class->cidr_bitlen_ipv4); + +#ifdef IPV6 + if (old_class->cidr_bitlen_ipv6 > 0 && new_class->cidr_bitlen_ipv6 > 0) + rebuild_cidr_list(AF_INET6, conf, new_class, + &old_class->list_ipv6, &new_class->list_ipv6, + old_class->cidr_bitlen_ipv6 != new_class->cidr_bitlen_ipv6); +#endif + } + + destroy_cidr_class(old_class); +} + +/* + * destroy_cidr_list + * + * inputs - pointer to class dlink list of cidr blocks + * output - none + * side effects - completely destroys the class link list of cidr blocks + */ +static void +destroy_cidr_list(dlink_list *list) +{ + dlink_node *ptr = NULL, *next_ptr = NULL; + + DLINK_FOREACH_SAFE(ptr, next_ptr, list->head) + { + dlinkDelete(ptr, list); + MyFree(ptr->data); + } +} + +/* + * destroy_cidr_class + * + * inputs - pointer to class + * output - none + * side effects - completely destroys the class link list of cidr blocks + */ +static void +destroy_cidr_class(struct ClassItem *aclass) +{ + destroy_cidr_list(&aclass->list_ipv4); + destroy_cidr_list(&aclass->list_ipv6); +} diff --git a/src/conf_lexer.c b/src/conf_lexer.c new file mode 100644 index 0000000..e9d42bb --- /dev/null +++ b/src/conf_lexer.c @@ -0,0 +1,4278 @@ + +#line 3 "conf_lexer.c" + +#define YY_INT_ALIGNED short int + +/* A lexical scanner generated by flex */ + +#define FLEX_SCANNER +#define YY_FLEX_MAJOR_VERSION 2 +#define YY_FLEX_MINOR_VERSION 5 +#define YY_FLEX_SUBMINOR_VERSION 37 +#if YY_FLEX_SUBMINOR_VERSION > 0 +#define FLEX_BETA +#endif + +/* First, we deal with platform-specific or compiler-specific issues. */ + +/* begin standard C headers. */ +#include <stdio.h> +#include <string.h> +#include <errno.h> +#include <stdlib.h> + +/* end standard C headers. */ + +/* flex integer type definitions */ + +#ifndef FLEXINT_H +#define FLEXINT_H + +/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */ + +#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L + +/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h, + * if you want the limit (max/min) macros for int types. + */ +#ifndef __STDC_LIMIT_MACROS +#define __STDC_LIMIT_MACROS 1 +#endif + +#include <inttypes.h> +typedef int8_t flex_int8_t; +typedef uint8_t flex_uint8_t; +typedef int16_t flex_int16_t; +typedef uint16_t flex_uint16_t; +typedef int32_t flex_int32_t; +typedef uint32_t flex_uint32_t; +#else +typedef signed char flex_int8_t; +typedef short int flex_int16_t; +typedef int flex_int32_t; +typedef unsigned char flex_uint8_t; +typedef unsigned short int flex_uint16_t; +typedef unsigned int flex_uint32_t; + +/* Limits of integral types. */ +#ifndef INT8_MIN +#define INT8_MIN (-128) +#endif +#ifndef INT16_MIN +#define INT16_MIN (-32767-1) +#endif +#ifndef INT32_MIN +#define INT32_MIN (-2147483647-1) +#endif +#ifndef INT8_MAX +#define INT8_MAX (127) +#endif +#ifndef INT16_MAX +#define INT16_MAX (32767) +#endif +#ifndef INT32_MAX +#define INT32_MAX (2147483647) +#endif +#ifndef UINT8_MAX +#define UINT8_MAX (255U) +#endif +#ifndef UINT16_MAX +#define UINT16_MAX (65535U) +#endif +#ifndef UINT32_MAX +#define UINT32_MAX (4294967295U) +#endif + +#endif /* ! C99 */ + +#endif /* ! FLEXINT_H */ + +#ifdef __cplusplus + +/* The "const" storage-class-modifier is valid. */ +#define YY_USE_CONST + +#else /* ! __cplusplus */ + +/* C99 requires __STDC__ to be defined as 1. */ +#if defined (__STDC__) + +#define YY_USE_CONST + +#endif /* defined (__STDC__) */ +#endif /* ! __cplusplus */ + +#ifdef YY_USE_CONST +#define yyconst const +#else +#define yyconst +#endif + +/* Returned upon end-of-file. */ +#define YY_NULL 0 + +/* Promotes a possibly negative, possibly signed char to an unsigned + * integer for use as an array index. If the signed char is negative, + * we want to instead treat it as an 8-bit unsigned char, hence the + * double cast. + */ +#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c) + +/* Enter a start condition. This macro really ought to take a parameter, + * but we do it the disgusting crufty way forced on us by the ()-less + * definition of BEGIN. + */ +#define BEGIN (yy_start) = 1 + 2 * + +/* Translate the current start state into a value that can be later handed + * to BEGIN to return to the state. The YYSTATE alias is for lex + * compatibility. + */ +#define YY_START (((yy_start) - 1) / 2) +#define YYSTATE YY_START + +/* Action number for EOF rule of a given start state. */ +#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1) + +/* Special action meaning "start processing a new file". */ +#define YY_NEW_FILE yyrestart(yyin ) + +#define YY_END_OF_BUFFER_CHAR 0 + +/* Size of default input buffer. */ +#ifndef YY_BUF_SIZE +#define YY_BUF_SIZE 16384 +#endif + +/* The state buf must be large enough to hold one state per character in the main buffer. + */ +#define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type)) + +#ifndef YY_TYPEDEF_YY_BUFFER_STATE +#define YY_TYPEDEF_YY_BUFFER_STATE +typedef struct yy_buffer_state *YY_BUFFER_STATE; +#endif + +#ifndef YY_TYPEDEF_YY_SIZE_T +#define YY_TYPEDEF_YY_SIZE_T +typedef size_t yy_size_t; +#endif + +extern yy_size_t yyleng; + +extern FILE *yyin, *yyout; + +#define EOB_ACT_CONTINUE_SCAN 0 +#define EOB_ACT_END_OF_FILE 1 +#define EOB_ACT_LAST_MATCH 2 + + #define YY_LESS_LINENO(n) + +/* Return all but the first "n" matched characters back to the input stream. */ +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up yytext. */ \ + int yyless_macro_arg = (n); \ + YY_LESS_LINENO(yyless_macro_arg);\ + *yy_cp = (yy_hold_char); \ + YY_RESTORE_YY_MORE_OFFSET \ + (yy_c_buf_p) = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \ + YY_DO_BEFORE_ACTION; /* set up yytext again */ \ + } \ + while ( 0 ) + +#define unput(c) yyunput( c, (yytext_ptr) ) + +#ifndef YY_STRUCT_YY_BUFFER_STATE +#define YY_STRUCT_YY_BUFFER_STATE +struct yy_buffer_state + { + FILE *yy_input_file; + + char *yy_ch_buf; /* input buffer */ + char *yy_buf_pos; /* current position in input buffer */ + + /* Size of input buffer in bytes, not including room for EOB + * characters. + */ + yy_size_t yy_buf_size; + + /* Number of characters read into yy_ch_buf, not including EOB + * characters. + */ + yy_size_t yy_n_chars; + + /* Whether we "own" the buffer - i.e., we know we created it, + * and can realloc() it to grow it, and should free() it to + * delete it. + */ + int yy_is_our_buffer; + + /* Whether this is an "interactive" input source; if so, and + * if we're using stdio for input, then we want to use getc() + * instead of fread(), to make sure we stop fetching input after + * each newline. + */ + int yy_is_interactive; + + /* Whether we're considered to be at the beginning of a line. + * If so, '^' rules will be active on the next match, otherwise + * not. + */ + int yy_at_bol; + + int yy_bs_lineno; /**< The line count. */ + int yy_bs_column; /**< The column count. */ + + /* Whether to try to fill the input buffer when we reach the + * end of it. + */ + int yy_fill_buffer; + + int yy_buffer_status; + +#define YY_BUFFER_NEW 0 +#define YY_BUFFER_NORMAL 1 + /* When an EOF's been seen but there's still some text to process + * then we mark the buffer as YY_EOF_PENDING, to indicate that we + * shouldn't try reading from the input source any more. We might + * still have a bunch of tokens to match, though, because of + * possible backing-up. + * + * When we actually see the EOF, we change the status to "new" + * (via yyrestart()), so that the user can continue scanning by + * just pointing yyin at a new input file. + */ +#define YY_BUFFER_EOF_PENDING 2 + + }; +#endif /* !YY_STRUCT_YY_BUFFER_STATE */ + +/* Stack of input buffers. */ +static size_t yy_buffer_stack_top = 0; /**< index of top of stack. */ +static size_t yy_buffer_stack_max = 0; /**< capacity of stack. */ +static YY_BUFFER_STATE * yy_buffer_stack = 0; /**< Stack as an array. */ + +/* We provide macros for accessing buffer states in case in the + * future we want to put the buffer states in a more general + * "scanner state". + * + * Returns the top of the stack, or NULL. + */ +#define YY_CURRENT_BUFFER ( (yy_buffer_stack) \ + ? (yy_buffer_stack)[(yy_buffer_stack_top)] \ + : NULL) + +/* Same as previous macro, but useful when we know that the buffer stack is not + * NULL or when we need an lvalue. For internal use only. + */ +#define YY_CURRENT_BUFFER_LVALUE (yy_buffer_stack)[(yy_buffer_stack_top)] + +/* yy_hold_char holds the character lost when yytext is formed. */ +static char yy_hold_char; +static yy_size_t yy_n_chars; /* number of characters read into yy_ch_buf */ +yy_size_t yyleng; + +/* Points to current character in buffer. */ +static char *yy_c_buf_p = (char *) 0; +static int yy_init = 0; /* whether we need to initialize */ +static int yy_start = 0; /* start state number */ + +/* Flag which is used to allow yywrap()'s to do buffer switches + * instead of setting up a fresh yyin. A bit of a hack ... + */ +static int yy_did_buffer_switch_on_eof; + +void yyrestart (FILE *input_file ); +void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer ); +YY_BUFFER_STATE yy_create_buffer (FILE *file,int size ); +void yy_delete_buffer (YY_BUFFER_STATE b ); +void yy_flush_buffer (YY_BUFFER_STATE b ); +void yypush_buffer_state (YY_BUFFER_STATE new_buffer ); +void yypop_buffer_state (void ); + +static void yyensure_buffer_stack (void ); +static void yy_load_buffer_state (void ); +static void yy_init_buffer (YY_BUFFER_STATE b,FILE *file ); + +#define YY_FLUSH_BUFFER yy_flush_buffer(YY_CURRENT_BUFFER ) + +YY_BUFFER_STATE yy_scan_buffer (char *base,yy_size_t size ); +YY_BUFFER_STATE yy_scan_string (yyconst char *yy_str ); +YY_BUFFER_STATE yy_scan_bytes (yyconst char *bytes,yy_size_t len ); + +void *yyalloc (yy_size_t ); +void *yyrealloc (void *,yy_size_t ); +void yyfree (void * ); + +#define yy_new_buffer yy_create_buffer + +#define yy_set_interactive(is_interactive) \ + { \ + if ( ! YY_CURRENT_BUFFER ){ \ + yyensure_buffer_stack (); \ + YY_CURRENT_BUFFER_LVALUE = \ + yy_create_buffer(yyin,YY_BUF_SIZE ); \ + } \ + YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \ + } + +#define yy_set_bol(at_bol) \ + { \ + if ( ! YY_CURRENT_BUFFER ){\ + yyensure_buffer_stack (); \ + YY_CURRENT_BUFFER_LVALUE = \ + yy_create_buffer(yyin,YY_BUF_SIZE ); \ + } \ + YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \ + } + +#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol) + +/* Begin user sect3 */ + +#define yywrap() 1 +#define YY_SKIP_YYWRAP + +typedef unsigned char YY_CHAR; + +FILE *yyin = (FILE *) 0, *yyout = (FILE *) 0; + +typedef int yy_state_type; + +extern int yylineno; + +int yylineno = 1; + +extern char *yytext; +#define yytext_ptr yytext + +static yy_state_type yy_get_previous_state (void ); +static yy_state_type yy_try_NUL_trans (yy_state_type current_state ); +static int yy_get_next_buffer (void ); +static void yy_fatal_error (yyconst char msg[] ); + +/* Done after the current pattern has been matched and before the + * corresponding action - sets up yytext. + */ +#define YY_DO_BEFORE_ACTION \ + (yytext_ptr) = yy_bp; \ + (yytext_ptr) -= (yy_more_len); \ + yyleng = (size_t) (yy_cp - (yytext_ptr)); \ + (yy_hold_char) = *yy_cp; \ + *yy_cp = '\0'; \ + (yy_c_buf_p) = yy_cp; + +#define YY_NUM_RULES 238 +#define YY_END_OF_BUFFER 239 +/* This struct is not used in this scanner, + but its presence is necessary. */ +struct yy_trans_info + { + flex_int32_t yy_verify; + flex_int32_t yy_nxt; + }; +static yyconst flex_int16_t yy_accept[1546] = + { 0, + 4, 4, 239, 237, 4, 3, 237, 5, 237, 237, + 6, 237, 237, 237, 237, 237, 237, 237, 237, 237, + 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, + 237, 237, 237, 237, 237, 237, 4, 3, 0, 7, + 5, 236, 0, 2, 5, 6, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 68, 0, 230, 0, 0, 0, 0, 0, 0, + 0, 235, 0, 0, 0, 0, 0, 0, 0, 96, + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 12, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 217, 0, 0, + 0, 0, 0, 30, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 79, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 203, 0, 0, 0, + 0, 0, 0, 143, 0, 0, 146, 0, 0, 0, + 0, 205, 128, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 164, 0, 0, 0, 0, 0, 13, + 0, 195, 225, 0, 0, 0, 0, 0, 0, 0, + 0, 216, 198, 0, 0, 28, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 41, 0, 0, + 200, 0, 0, 0, 0, 0, 0, 0, 63, 219, + + 0, 0, 0, 69, 70, 0, 0, 73, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 90, 0, 0, 0, 94, 0, 0, + 0, 0, 0, 103, 0, 0, 189, 0, 111, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 124, 0, + 0, 0, 0, 0, 0, 147, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 151, 0, + 0, 0, 0, 0, 0, 0, 160, 0, 0, 0, + 0, 215, 0, 0, 0, 9, 0, 0, 0, 224, + 0, 0, 196, 0, 0, 21, 0, 0, 199, 0, + + 0, 0, 34, 0, 0, 37, 0, 0, 0, 0, + 0, 42, 0, 44, 0, 46, 0, 0, 0, 0, + 0, 0, 218, 0, 0, 0, 0, 229, 0, 0, + 75, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 234, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 115, 0, 118, 0, 0, 0, 0, 0, 0, + 0, 137, 0, 0, 0, 0, 0, 0, 201, 0, + 148, 134, 0, 0, 0, 0, 0, 0, 135, 0, + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 161, 0, 0, 214, 163, 0, 0, 0, 11, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 40, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 58, 0, 0, + 0, 0, 0, 228, 0, 0, 0, 0, 0, 0, + 78, 213, 80, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 233, 0, 0, 221, 0, 188, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 106, 0, 0, + + 0, 0, 0, 0, 114, 0, 0, 119, 120, 0, + 0, 0, 0, 0, 223, 0, 138, 0, 0, 144, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 153, 204, 0, 0, 0, 192, + 0, 0, 0, 162, 210, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 18, 0, 22, 23, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 45, 0, 0, 0, 0, 0, 53, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, 220, 0, 187, 202, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 122, 0, 0, 0, 0, 222, + 0, 0, 0, 141, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 155, 154, 0, 191, 157, 0, 0, + 0, 0, 0, 0, 0, 14, 211, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 206, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + + 0, 0, 0, 65, 0, 0, 0, 0, 227, 0, + 0, 0, 0, 0, 186, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 232, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 100, 0, 105, 0, 207, 0, + 0, 0, 0, 107, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, + + 0, 0, 38, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 209, 0, + 0, 226, 0, 0, 77, 0, 0, 0, 0, 0, + 82, 83, 0, 0, 0, 86, 231, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 182, 0, 109, 0, 0, 0, 116, 117, + 121, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 156, 0, + 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, + + 197, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 55, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 166, 0, 0, 84, 0, 0, 85, 0, + 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 112, 0, + 0, 0, 0, 0, 0, 139, 140, 0, 208, 145, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 24, 0, 0, 29, 0, + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 54, 0, 59, 0, 0, 0, 0, 0, + 0, 0, 184, 175, 0, 81, 0, 0, 190, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 194, 0, 108, 0, 0, 0, 125, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 158, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 31, 0, 0, 0, 36, 39, 0, 0, 0, 47, + 48, 0, 0, 0, 61, 0, 0, 0, 0, 0, + + 0, 0, 76, 0, 0, 0, 0, 0, 0, 0, + 92, 93, 95, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 110, 113, 0, 0, 0, 0, 0, 212, + 149, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 173, 0, 0, 0, 10, 0, + 0, 0, 0, 0, 0, 0, 0, 35, 0, 43, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 170, 0, 0, 91, 0, 0, + 99, 0, 102, 0, 0, 0, 0, 0, 0, 0, + 136, 142, 0, 0, 0, 0, 0, 0, 0, 0, + + 0, 0, 159, 0, 0, 174, 176, 0, 0, 0, + 16, 0, 0, 0, 0, 0, 0, 49, 51, 0, + 0, 0, 62, 0, 0, 0, 0, 0, 0, 0, + 0, 87, 0, 0, 0, 0, 0, 0, 104, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 8, 171, 0, 0, 0, + 0, 0, 0, 0, 0, 52, 0, 0, 60, 66, + 0, 0, 72, 0, 0, 0, 0, 0, 88, 0, + 0, 101, 0, 0, 0, 0, 0, 0, 0, 133, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + + 0, 19, 20, 0, 0, 0, 0, 0, 0, 0, + 57, 0, 71, 0, 0, 0, 0, 167, 0, 0, + 98, 0, 193, 183, 0, 0, 0, 0, 0, 0, + 0, 177, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 123, 0, 0, 0, 130, 132, + 131, 180, 179, 178, 181, 0, 0, 0, 25, 0, + 0, 0, 0, 165, 0, 0, 0, 0, 168, 169, + 0, 97, 0, 0, 0, 0, 0, 152, 0, 0, + 0, 0, 0, 0, 0, 0, 185, 0, 0, 0, + + 127, 0, 0, 0, 0, 0, 0, 0, 0, 67, + 0, 0, 0, 126, 129, 0, 0, 0, 0, 32, + 0, 0, 74, 0, 17, 150, 0, 0, 0, 0, + 50, 89, 0, 0, 0, 33, 0, 0, 27, 0, + 0, 0, 26, 172, 0 + } ; + +static yyconst flex_int32_t yy_ec[256] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 2, 1, 4, 5, 1, 1, 1, 1, 1, + 1, 6, 1, 1, 1, 7, 8, 9, 10, 9, + 11, 12, 9, 13, 9, 9, 9, 1, 1, 14, + 1, 15, 1, 1, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, + 1, 1, 1, 1, 42, 1, 43, 44, 45, 46, + + 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, + 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, + 67, 68, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1 + } ; + +static yyconst flex_int32_t yy_meta[69] = + { 0, + 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1 + } ; + +static yyconst flex_int16_t yy_base[1551] = + { 0, + 0, 0, 2962, 2963, 2959, 0, 66, 0, 64, 66, + 66, 98, 43, 146, 75, 58, 85, 76, 117, 109, + 51, 154, 155, 197, 239, 53, 177, 57, 125, 283, + 323, 190, 127, 168, 128, 143, 2958, 0, 86, 2963, + 0, 2963, 166, 2963, 0, 220, 181, 181, 181, 196, + 190, 200, 202, 203, 220, 209, 237, 237, 242, 231, + 221, 326, 247, 244, 235, 252, 256, 255, 292, 253, + 262, 276, 266, 303, 301, 264, 292, 290, 318, 332, + 327, 328, 342, 327, 341, 347, 342, 359, 351, 378, + 347, 338, 367, 350, 378, 375, 381, 390, 391, 2917, + + 383, 394, 399, 386, 385, 405, 446, 403, 422, 433, + 413, 396, 405, 443, 412, 427, 417, 431, 438, 439, + 2916, 448, 456, 498, 468, 463, 476, 474, 481, 474, + 493, 492, 492, 478, 2963, 495, 499, 489, 506, 500, + 2915, 499, 504, 501, 506, 508, 518, 514, 536, 523, + 546, 523, 547, 2963, 550, 539, 536, 540, 548, 540, + 556, 549, 558, 552, 560, 559, 555, 553, 565, 558, + 571, 571, 582, 561, 578, 2914, 583, 592, 144, 588, + 584, 595, 591, 606, 605, 601, 595, 601, 2963, 606, + 2913, 598, 618, 601, 600, 601, 619, 625, 626, 610, + + 624, 649, 638, 623, 645, 635, 647, 649, 638, 643, + 658, 646, 644, 661, 666, 671, 2963, 658, 654, 2912, + 660, 674, 658, 2963, 666, 669, 2963, 684, 682, 675, + 689, 2963, 686, 686, 694, 701, 690, 710, 704, 713, + 715, 699, 711, 712, 716, 721, 716, 711, 711, 720, + 720, 729, 727, 2963, 731, 732, 735, 742, 2911, 2963, + 757, 2963, 743, 758, 758, 751, 752, 2910, 750, 751, + 767, 2963, 2963, 766, 753, 2963, 759, 776, 774, 2909, + 765, 769, 757, 778, 768, 768, 783, 2963, 775, 775, + 2963, 778, 784, 798, 811, 800, 811, 2908, 2963, 798, + + 805, 801, 801, 2963, 2963, 2907, 818, 2906, 823, 823, + 820, 2905, 813, 828, 818, 830, 862, 835, 846, 850, + 834, 842, 845, 2963, 852, 2904, 853, 2903, 852, 857, + 857, 868, 874, 888, 2902, 863, 2963, 2901, 2963, 886, + 874, 887, 888, 890, 886, 898, 898, 918, 2900, 904, + 908, 906, 934, 919, 905, 2963, 914, 924, 922, 2930, + 937, 911, 911, 928, 2930, 2897, 958, 959, 2963, 956, + 942, 955, 956, 958, 953, 964, 2963, 969, 956, 962, + 2896, 959, 974, 959, 962, 975, 980, 976, 978, 2963, + 976, 984, 2895, 992, 1000, 2963, 1005, 1010, 2963, 1002, + + 1006, 1004, 2963, 1009, 1004, 2963, 1009, 1022, 1007, 1014, + 1026, 2963, 1026, 2963, 1031, 2894, 1021, 1018, 1015, 1027, + 1024, 1020, 2963, 1043, 1042, 1039, 1043, 1031, 1048, 1031, + 2893, 2892, 1051, 2891, 1053, 1049, 1065, 1067, 1071, 1072, + 1061, 1075, 1066, 1077, 1081, 1084, 1068, 1063, 1082, 1085, + 1077, 1088, 1094, 1094, 1084, 1101, 1100, 1109, 1116, 1110, + 1105, 1104, 2890, 1125, 1118, 1104, 1131, 1135, 1122, 2889, + 1126, 2963, 1125, 2963, 1134, 1138, 1129, 1143, 1151, 1154, + 1153, 2963, 1143, 1146, 1173, 1162, 1174, 2888, 2963, 1179, + 2887, 2963, 1183, 1173, 1182, 2886, 1169, 1185, 2963, 1179, + + 1170, 1178, 1178, 1190, 1186, 1187, 1197, 1187, 1196, 1204, + 1197, 2914, 1197, 1204, 2963, 2963, 1222, 2884, 1210, 2963, + 1221, 1215, 1218, 1225, 1220, 1235, 1230, 1234, 1226, 1226, + 1227, 1232, 1244, 1236, 1239, 1234, 2883, 2963, 1254, 2882, + 1246, 1251, 1275, 2881, 1245, 2880, 1261, 2879, 1267, 1248, + 2878, 1282, 1273, 2963, 1278, 1269, 1290, 1292, 1296, 1294, + 2963, 2963, 2963, 1297, 1287, 1301, 1294, 1289, 1300, 1305, + 1306, 1301, 1299, 1298, 2963, 1299, 1316, 1307, 1319, 1315, + 1332, 1334, 1338, 1329, 1334, 1342, 1333, 1331, 1346, 2877, + 1336, 1350, 1342, 1341, 1355, 1344, 1357, 2963, 1341, 1347, + + 1354, 1367, 1351, 1357, 2963, 1358, 1370, 2963, 1378, 1367, + 1385, 1367, 1383, 1391, 1375, 1395, 1395, 1392, 1381, 2963, + 1392, 1394, 1394, 1391, 1394, 1402, 2876, 1394, 1435, 1404, + 2875, 1407, 2874, 1411, 2963, 2963, 1421, 1422, 1409, 2963, + 1429, 1437, 1435, 2963, 2963, 1430, 1442, 1432, 1435, 1454, + 1457, 1445, 1456, 1453, 1448, 1443, 2963, 1445, 2963, 1460, + 2873, 1450, 2872, 2871, 2870, 1471, 1467, 1468, 1466, 2869, + 2963, 1462, 1474, 1485, 1490, 1485, 2963, 1481, 1495, 1487, + 1484, 1489, 1494, 1507, 1499, 1497, 1512, 1509, 1492, 1512, + 1499, 1514, 1515, 1505, 1516, 1528, 1532, 1521, 1536, 1531, + + 1546, 1542, 1547, 1547, 2868, 2963, 1530, 2963, 2963, 1549, + 1536, 2867, 1555, 1538, 2866, 2865, 1554, 1547, 1547, 1541, + 1555, 1556, 1551, 1556, 1563, 1569, 1559, 1565, 1566, 1578, + 1574, 1571, 1573, 1595, 2963, 1582, 1598, 1582, 1594, 2963, + 1588, 1599, 1595, 1591, 1603, 1598, 1605, 1604, 1600, 1613, + 1617, 1608, 1603, 2864, 2863, 2862, 2861, 2860, 1621, 1622, + 2859, 1624, 2858, 2963, 2963, 1627, 2963, 2963, 1631, 2857, + 90, 1640, 1624, 1632, 1632, 2963, 2963, 1646, 1652, 1645, + 1646, 1642, 1655, 1653, 1672, 1655, 1650, 1663, 1662, 2963, + 1659, 1664, 1661, 1679, 1676, 1668, 1669, 1683, 1690, 1682, + + 1696, 1677, 1689, 2963, 1695, 1706, 1697, 1695, 1696, 1711, + 1706, 1709, 1709, 1709, 2963, 1708, 1714, 1728, 1710, 1720, + 2856, 1728, 1729, 1727, 1717, 1728, 1735, 1732, 1730, 1754, + 1736, 1746, 1738, 1758, 2963, 1760, 2963, 1750, 2963, 1744, + 1751, 1768, 1754, 2963, 1764, 1774, 1767, 1768, 2855, 1763, + 1762, 1772, 2854, 1774, 1787, 1780, 1771, 1790, 1792, 2853, + 1797, 1783, 1799, 1785, 1798, 1807, 1804, 1818, 1815, 1818, + 1808, 1809, 1811, 1813, 2852, 1805, 1818, 1830, 1832, 1833, + 1829, 1826, 190, 2889, 2877, 1822, 1841, 2849, 2848, 2847, + 2963, 1831, 1839, 1843, 1840, 1838, 1842, 1837, 1858, 1856, + + 1862, 1871, 2963, 1860, 1869, 1867, 1876, 1876, 1867, 2846, + 1861, 1871, 1886, 1869, 1877, 1886, 1886, 1887, 2845, 1891, + 1891, 2963, 1884, 1897, 2963, 1901, 1886, 2844, 1888, 1899, + 2963, 2963, 1910, 1894, 1895, 2963, 2963, 1905, 1914, 1907, + 1905, 1926, 1931, 1927, 2843, 1922, 1925, 1923, 1942, 2842, + 2841, 1939, 2840, 1936, 2963, 1937, 1943, 1947, 2963, 2963, + 2963, 1947, 1935, 1932, 1953, 1937, 1957, 1950, 1952, 1962, + 1965, 1956, 1971, 1975, 1964, 1964, 1967, 1968, 1979, 1974, + 1975, 1979, 1981, 1978, 1983, 1984, 1990, 1998, 2963, 1990, + 1993, 2877, 2876, 2864, 2863, 1987, 1990, 2008, 2011, 1996, + + 2963, 2006, 2004, 2008, 2016, 2020, 2015, 2025, 2025, 2034, + 2020, 2033, 2026, 2031, 2029, 2039, 2036, 2050, 2049, 2044, + 2053, 2963, 2053, 2041, 2832, 2039, 2049, 2828, 2827, 2052, + 2045, 2048, 2963, 2058, 2056, 2963, 2069, 2073, 2963, 2069, + 2086, 2086, 2963, 2077, 2074, 2081, 2091, 2083, 2825, 2084, + 2823, 2084, 2084, 2088, 2088, 2089, 2105, 2097, 2963, 2111, + 2105, 2094, 2113, 2822, 2107, 2963, 2963, 2123, 2963, 2963, + 2118, 2125, 2120, 2821, 2819, 2130, 2818, 2117, 2137, 2138, + 2139, 2141, 2138, 2139, 2145, 2132, 2141, 2150, 2150, 2137, + 2146, 2150, 2140, 2164, 2817, 2963, 2151, 2158, 2963, 2160, + + 2167, 2161, 2164, 2173, 2162, 2811, 2172, 2176, 2185, 2176, + 2188, 2179, 2963, 2808, 2963, 2187, 2191, 2182, 2188, 2201, + 2187, 2191, 1636, 2963, 2208, 2963, 2214, 2203, 2963, 2217, + 2216, 2202, 2219, 2221, 2211, 2218, 2216, 2221, 2241, 2218, + 2226, 2236, 2963, 2242, 2963, 2245, 2240, 2254, 2963, 1390, + 2245, 2240, 2247, 2257, 2260, 2264, 2257, 2257, 2259, 2260, + 2273, 2257, 2258, 2262, 2266, 2273, 2271, 2272, 2290, 2273, + 2963, 2281, 2283, 2286, 2290, 2297, 2299, 2300, 2306, 2292, + 2963, 1386, 2294, 2295, 2963, 2963, 2305, 2302, 2308, 2963, + 2963, 2320, 2306, 2324, 2963, 2319, 2313, 1239, 861, 2315, + + 2325, 2329, 2963, 2337, 2325, 2330, 2340, 2335, 2348, 2348, + 2963, 2963, 2963, 853, 2342, 2355, 2351, 2346, 822, 2348, + 2345, 2353, 2963, 2963, 2354, 2358, 2368, 2371, 2372, 2963, + 2963, 2377, 2371, 2376, 815, 2377, 2381, 811, 810, 809, + 462, 2379, 2383, 455, 2963, 2391, 2389, 2379, 2963, 2383, + 2379, 2381, 2387, 2403, 445, 2409, 2408, 2963, 2399, 2963, + 2402, 2399, 393, 2403, 2404, 2403, 2403, 2424, 2408, 2418, + 2419, 2426, 380, 2428, 2963, 2431, 2419, 2963, 2419, 2430, + 2963, 2442, 2963, 2445, 2447, 2430, 2437, 2441, 2452, 2435, + 2963, 2963, 2446, 2448, 2448, 2464, 2451, 2460, 2459, 2461, + + 2462, 2466, 2963, 287, 2477, 2963, 2963, 2481, 2482, 273, + 2963, 2466, 2474, 2471, 2483, 249, 2476, 2963, 266, 2496, + 2488, 2486, 2963, 2487, 2492, 2495, 2506, 2509, 2519, 2507, + 2516, 2963, 2520, 2509, 2517, 2512, 2530, 2530, 2963, 2525, + 2534, 2515, 200, 2537, 2523, 2536, 2536, 2538, 2545, 2540, + 2542, 2545, 2546, 2547, 2551, 2963, 2963, 2552, 310, 2547, + 2569, 2556, 2575, 2575, 2570, 2963, 2559, 2576, 2963, 2963, + 2570, 2565, 2963, 145, 2575, 2575, 2574, 2575, 124, 2584, + 2577, 2963, 2586, 2580, 2595, 2592, 109, 2602, 107, 2963, + 2595, 2601, 2599, 2611, 2605, 2607, 2610, 2616, 2614, 2615, + + 2627, 2963, 2963, 2619, 2616, 2631, 2624, 2624, 2640, 2627, + 2963, 2633, 2963, 2636, 2636, 2646, 2647, 2963, 2634, 2645, + 2963, 2646, 2963, 2963, 2643, 2658, 2658, 2662, 2665, 2666, + 2669, 2963, 2651, 2657, 2658, 2659, 2666, 2672, 2669, 2670, + 2670, 2675, 2683, 2686, 2696, 2701, 2699, 2696, 2701, 2689, + 2690, 2703, 2696, 2713, 2963, 2712, 2710, 2714, 2963, 2963, + 2963, 2963, 2963, 2963, 2963, 2716, 2723, 2711, 2963, 2731, + 100, 2732, 2725, 2963, 2720, 2738, 2729, 2732, 2963, 2963, + 2733, 2963, 2729, 2739, 2748, 2743, 2753, 2963, 2757, 2741, + 2757, 2749, 2761, 2757, 2750, 2763, 2963, 2759, 2767, 2772, + + 2963, 2774, 2776, 2777, 95, 2775, 2772, 2778, 2779, 2963, + 2775, 2784, 2794, 2963, 2963, 2781, 2796, 2802, 2786, 2963, + 2805, 2796, 2963, 2807, 2963, 2963, 93, 2798, 2800, 2796, + 2963, 2963, 2796, 2799, 2804, 2963, 2817, 2815, 2963, 2817, + 2811, 2828, 2963, 2963, 2963, 105, 2875, 97, 84, 81 + } ; + +static yyconst flex_int16_t yy_def[1551] = + { 0, + 1545, 1, 1545, 1545, 1545, 1546, 1547, 1548, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1546, 1547, 1545, + 1548, 1545, 1545, 1545, 1548, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1549, 1550, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1549, 1549, 1550, 1550, 1545, 1545, 1545, 1545, 1545, + + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 0, 1545, 1545, 1545, 1545, 1545 + } ; + +static yyconst flex_int16_t yy_nxt[3032] = + { 0, + 4, 5, 6, 7, 8, 4, 9, 10, 11, 11, + 11, 11, 11, 4, 4, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, + 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, + 4, 4, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 31, 32, 33, 34, 35, 36, 4, 40, 40, + 42, 44, 53, 45, 46, 46, 46, 46, 46, 66, + 83, 994, 54, 102, 992, 67, 68, 43, 40, 40, + 61, 883, 106, 884, 62, 74, 69, 41, 63, 53, + + 70, 64, 75, 885, 65, 38, 66, 83, 71, 54, + 102, 72, 67, 68, 43, 47, 48, 61, 49, 106, + 73, 62, 74, 69, 50, 63, 51, 70, 64, 75, + 80, 65, 76, 52, 1533, 71, 1518, 81, 72, 82, + 77, 1491, 47, 48, 107, 49, 78, 73, 1428, 126, + 1426, 50, 79, 51, 129, 304, 305, 80, 108, 76, + 52, 55, 130, 56, 81, 1419, 82, 77, 57, 58, + 84, 107, 59, 78, 88, 60, 126, 85, 89, 79, + 86, 129, 87, 127, 90, 108, 1414, 128, 55, 130, + 56, 883, 103, 884, 131, 57, 58, 84, 132, 59, + + 104, 88, 60, 885, 85, 89, 105, 86, 133, 87, + 127, 90, 91, 92, 128, 134, 93, 123, 124, 103, + 94, 131, 135, 125, 136, 132, 95, 104, 46, 46, + 46, 46, 46, 105, 137, 133, 138, 139, 142, 91, + 92, 1388, 134, 93, 123, 124, 140, 94, 141, 135, + 125, 136, 143, 95, 96, 144, 97, 145, 98, 147, + 148, 137, 99, 138, 139, 142, 154, 156, 100, 157, + 158, 159, 160, 140, 101, 141, 164, 146, 1366, 143, + 155, 96, 144, 97, 145, 98, 147, 148, 165, 99, + 1364, 166, 167, 154, 156, 100, 157, 158, 159, 160, + + 172, 101, 109, 164, 146, 110, 111, 155, 112, 161, + 173, 162, 113, 114, 1358, 165, 115, 116, 166, 167, + 168, 1402, 1403, 174, 170, 175, 163, 172, 1354, 109, + 171, 169, 110, 111, 176, 112, 161, 173, 162, 113, + 114, 149, 150, 115, 116, 117, 151, 168, 118, 119, + 174, 170, 175, 163, 152, 120, 121, 171, 169, 153, + 177, 176, 122, 178, 179, 180, 181, 182, 149, 150, + 183, 184, 117, 151, 185, 118, 119, 192, 195, 186, + 190, 152, 120, 121, 187, 191, 153, 177, 193, 122, + 178, 179, 180, 181, 182, 188, 196, 183, 184, 189, + + 194, 185, 197, 198, 192, 195, 186, 190, 201, 199, + 203, 187, 191, 204, 208, 193, 205, 209, 220, 229, + 210, 1330, 188, 196, 200, 230, 189, 194, 211, 197, + 198, 227, 206, 207, 1320, 201, 199, 203, 233, 221, + 204, 208, 234, 205, 209, 220, 229, 210, 225, 235, + 222, 200, 230, 228, 223, 211, 224, 236, 227, 206, + 207, 212, 226, 213, 214, 233, 221, 215, 216, 234, + 217, 237, 231, 218, 238, 225, 235, 222, 240, 219, + 228, 223, 232, 224, 236, 241, 1314, 248, 212, 226, + 213, 214, 249, 252, 215, 216, 1305, 217, 237, 231, + + 218, 238, 250, 1302, 253, 240, 219, 254, 251, 232, + 255, 256, 241, 242, 248, 257, 243, 258, 259, 249, + 252, 260, 262, 244, 245, 263, 264, 266, 261, 250, + 246, 253, 267, 268, 254, 251, 247, 255, 256, 269, + 242, 270, 257, 243, 258, 259, 271, 272, 260, 262, + 244, 245, 263, 264, 266, 261, 273, 246, 274, 267, + 268, 275, 276, 247, 277, 278, 269, 279, 270, 280, + 281, 282, 283, 271, 272, 284, 285, 286, 287, 288, + 289, 291, 292, 273, 293, 274, 294, 295, 275, 276, + 296, 277, 278, 290, 279, 299, 280, 281, 282, 283, + + 297, 298, 284, 285, 286, 287, 288, 289, 291, 292, + 300, 293, 302, 294, 295, 303, 306, 296, 307, 310, + 290, 308, 299, 311, 309, 312, 313, 297, 298, 314, + 315, 316, 318, 319, 320, 321, 323, 300, 324, 302, + 325, 322, 303, 306, 326, 307, 310, 327, 308, 328, + 311, 309, 312, 313, 333, 334, 314, 315, 316, 318, + 319, 320, 321, 323, 335, 324, 329, 325, 336, 337, + 338, 326, 339, 330, 327, 340, 328, 341, 331, 342, + 343, 333, 334, 332, 344, 345, 346, 347, 348, 351, + 349, 335, 352, 329, 353, 336, 337, 338, 354, 339, + + 330, 355, 340, 356, 341, 331, 342, 343, 357, 358, + 332, 344, 345, 346, 347, 348, 351, 349, 359, 352, + 362, 353, 360, 363, 364, 354, 365, 361, 355, 366, + 356, 367, 369, 370, 371, 357, 358, 372, 373, 374, + 375, 368, 376, 377, 379, 359, 380, 362, 381, 360, + 363, 364, 378, 365, 382, 383, 366, 384, 367, 369, + 370, 371, 385, 386, 372, 373, 374, 375, 368, 376, + 377, 379, 387, 380, 389, 381, 390, 391, 392, 393, + 394, 382, 383, 396, 384, 397, 398, 399, 400, 385, + 386, 401, 402, 403, 405, 406, 407, 408, 409, 387, + + 410, 389, 411, 390, 391, 392, 393, 394, 412, 413, + 396, 414, 397, 398, 399, 400, 415, 416, 401, 402, + 403, 405, 406, 407, 408, 409, 417, 410, 419, 411, + 421, 423, 424, 425, 426, 412, 413, 428, 414, 430, + 418, 420, 431, 415, 416, 432, 434, 435, 436, 437, + 1301, 1300, 1299, 417, 447, 419, 1296, 421, 423, 424, + 425, 426, 448, 1284, 428, 449, 430, 418, 450, 431, + 451, 452, 432, 434, 435, 436, 437, 438, 439, 440, + 453, 447, 455, 441, 457, 442, 458, 459, 443, 448, + 444, 460, 449, 461, 1279, 450, 445, 451, 452, 446, + + 467, 469, 1268, 462, 438, 439, 440, 453, 470, 455, + 441, 457, 442, 458, 459, 443, 471, 444, 460, 472, + 461, 463, 473, 445, 474, 464, 446, 467, 469, 465, + 462, 475, 476, 477, 480, 470, 481, 482, 487, 488, + 489, 490, 491, 471, 496, 497, 472, 483, 463, 473, + 478, 474, 464, 484, 493, 494, 498, 485, 475, 476, + 477, 480, 486, 481, 482, 487, 488, 489, 490, 491, + 495, 496, 497, 501, 502, 503, 504, 478, 505, 506, + 484, 493, 494, 498, 485, 507, 508, 509, 510, 486, + 512, 513, 515, 516, 517, 511, 518, 495, 519, 520, + + 501, 502, 503, 504, 521, 505, 506, 523, 524, 522, + 525, 527, 507, 508, 509, 510, 528, 512, 513, 515, + 516, 517, 511, 518, 529, 519, 520, 530, 531, 532, + 533, 521, 534, 535, 523, 524, 522, 525, 527, 536, + 537, 538, 539, 528, 540, 541, 542, 544, 545, 546, + 547, 529, 548, 549, 530, 531, 532, 533, 550, 534, + 535, 551, 552, 553, 554, 555, 536, 537, 538, 539, + 556, 540, 541, 542, 544, 545, 546, 547, 559, 548, + 549, 561, 562, 563, 564, 550, 565, 568, 551, 552, + 553, 554, 555, 569, 566, 570, 573, 556, 567, 574, + + 571, 575, 576, 577, 578, 559, 579, 580, 561, 562, + 563, 564, 572, 565, 568, 581, 584, 582, 585, 586, + 569, 566, 570, 573, 583, 567, 574, 571, 575, 576, + 577, 578, 587, 579, 580, 588, 589, 590, 591, 572, + 593, 597, 581, 584, 582, 585, 586, 594, 595, 598, + 603, 583, 600, 596, 605, 606, 608, 609, 607, 587, + 599, 610, 588, 589, 590, 591, 611, 593, 597, 601, + 612, 615, 602, 616, 594, 595, 598, 603, 617, 600, + 596, 605, 606, 608, 609, 607, 613, 599, 610, 614, + 618, 619, 620, 611, 622, 627, 601, 612, 615, 602, + + 616, 628, 624, 630, 631, 617, 625, 632, 633, 626, + 634, 635, 636, 613, 637, 638, 614, 618, 619, 620, + 639, 622, 627, 640, 641, 642, 643, 645, 628, 624, + 630, 631, 646, 625, 632, 633, 626, 634, 635, 636, + 647, 637, 638, 649, 650, 651, 652, 639, 653, 655, + 640, 641, 642, 643, 645, 656, 657, 658, 659, 646, + 660, 661, 662, 663, 664, 665, 654, 647, 666, 668, + 649, 650, 651, 652, 670, 653, 655, 671, 677, 679, + 1267, 683, 656, 657, 658, 659, 681, 660, 661, 662, + 663, 664, 665, 672, 673, 666, 668, 682, 685, 686, + + 687, 670, 674, 688, 671, 677, 679, 675, 683, 689, + 690, 691, 692, 681, 693, 694, 695, 696, 697, 698, + 672, 673, 699, 700, 682, 685, 686, 687, 701, 674, + 688, 702, 703, 704, 675, 705, 689, 690, 691, 692, + 706, 693, 694, 695, 696, 697, 698, 707, 708, 699, + 700, 709, 710, 711, 712, 701, 713, 714, 702, 703, + 704, 715, 705, 716, 717, 719, 720, 706, 721, 722, + 723, 724, 725, 726, 707, 708, 727, 728, 709, 710, + 711, 712, 729, 713, 714, 730, 731, 732, 715, 733, + 716, 717, 719, 720, 734, 721, 722, 723, 724, 725, + + 726, 735, 736, 727, 728, 737, 738, 739, 740, 729, + 741, 744, 730, 731, 732, 745, 733, 742, 743, 746, + 747, 734, 748, 749, 750, 751, 753, 1256, 735, 736, + 759, 1226, 737, 738, 739, 740, 761, 741, 744, 763, + 764, 765, 745, 766, 742, 743, 746, 747, 767, 748, + 749, 750, 751, 753, 754, 768, 769, 759, 755, 770, + 756, 771, 772, 761, 757, 758, 763, 764, 765, 773, + 766, 774, 775, 776, 777, 767, 778, 779, 780, 781, + 782, 754, 768, 769, 784, 755, 770, 756, 771, 772, + 788, 757, 758, 789, 790, 791, 773, 793, 774, 775, + + 776, 777, 794, 778, 779, 780, 781, 782, 796, 797, + 798, 784, 795, 799, 800, 801, 802, 788, 803, 804, + 789, 790, 791, 805, 793, 806, 807, 808, 809, 794, + 810, 811, 812, 813, 814, 796, 797, 798, 815, 795, + 799, 800, 801, 802, 816, 803, 804, 817, 818, 819, + 805, 820, 806, 807, 808, 809, 821, 810, 811, 812, + 813, 814, 822, 823, 824, 815, 825, 827, 828, 829, + 831, 816, 832, 835, 817, 818, 819, 836, 820, 837, + 838, 839, 840, 821, 841, 842, 843, 844, 845, 822, + 823, 824, 846, 825, 827, 828, 829, 831, 847, 832, + + 835, 848, 849, 850, 836, 851, 837, 838, 839, 840, + 852, 841, 842, 843, 844, 845, 853, 854, 855, 846, + 856, 857, 858, 859, 860, 847, 861, 862, 848, 849, + 850, 863, 851, 864, 865, 866, 867, 852, 868, 869, + 875, 876, 878, 853, 854, 855, 880, 856, 857, 858, + 859, 860, 881, 861, 862, 886, 887, 888, 863, 889, + 864, 865, 866, 867, 890, 868, 869, 875, 876, 878, + 891, 892, 893, 880, 894, 895, 897, 1204, 901, 881, + 902, 903, 886, 887, 888, 904, 889, 898, 896, 905, + 906, 890, 899, 907, 908, 909, 910, 891, 892, 893, + + 911, 894, 895, 897, 900, 901, 912, 902, 903, 913, + 914, 915, 904, 916, 898, 896, 905, 906, 917, 899, + 907, 908, 909, 910, 918, 919, 920, 911, 921, 922, + 923, 900, 924, 912, 925, 926, 913, 914, 915, 927, + 916, 928, 929, 930, 931, 917, 932, 934, 935, 936, + 937, 918, 919, 920, 938, 921, 922, 923, 939, 924, + 940, 925, 926, 941, 944, 945, 927, 946, 928, 929, + 930, 931, 942, 932, 934, 935, 936, 937, 947, 948, + 949, 938, 943, 950, 951, 939, 952, 940, 953, 954, + 941, 944, 945, 955, 946, 956, 957, 959, 960, 942, + + 961, 963, 964, 965, 966, 947, 948, 949, 967, 943, + 950, 951, 968, 952, 970, 953, 954, 971, 972, 973, + 955, 974, 956, 957, 959, 960, 975, 961, 963, 964, + 965, 966, 976, 977, 978, 967, 979, 980, 981, 968, + 982, 970, 983, 985, 971, 972, 973, 986, 974, 987, + 988, 989, 990, 975, 991, 996, 997, 1001, 1002, 976, + 977, 978, 1003, 979, 980, 981, 1004, 982, 1005, 983, + 985, 1006, 1007, 1008, 986, 1009, 987, 988, 989, 990, + 1010, 991, 996, 997, 1001, 1002, 1011, 1012, 1013, 1003, + 1014, 1015, 1016, 1004, 1017, 1005, 1019, 1020, 1006, 1007, + + 1008, 1021, 1009, 1022, 1023, 1024, 1025, 1010, 1026, 1028, + 1029, 1030, 1031, 1011, 1012, 1013, 1032, 1014, 1015, 1016, + 1033, 1017, 1035, 1019, 1020, 1036, 1039, 1037, 1021, 1040, + 1022, 1023, 1024, 1025, 1041, 1026, 1028, 1029, 1030, 1031, + 1042, 1043, 1044, 1032, 1038, 1045, 1046, 1033, 1047, 1035, + 1049, 1050, 1036, 1039, 1037, 1051, 1040, 1052, 1055, 1057, + 1058, 1041, 1059, 1060, 1061, 1062, 1063, 1042, 1043, 1044, + 1064, 1038, 1045, 1046, 1065, 1047, 1066, 1049, 1050, 1067, + 1068, 1069, 1051, 1070, 1052, 1055, 1057, 1058, 1071, 1059, + 1060, 1061, 1062, 1063, 1072, 1073, 1074, 1064, 1075, 1076, + + 1077, 1065, 1078, 1066, 1079, 1080, 1067, 1068, 1069, 1081, + 1070, 1082, 1083, 1084, 1085, 1071, 1086, 1087, 1088, 1089, + 1090, 1072, 1073, 1074, 1091, 1075, 1076, 1077, 1092, 1078, + 1093, 1079, 1080, 1094, 1095, 1096, 1081, 1097, 1082, 1083, + 1084, 1085, 1098, 1086, 1087, 1088, 1089, 1090, 1099, 1100, + 1101, 1091, 1102, 1103, 1104, 1092, 1105, 1093, 1106, 1107, + 1094, 1095, 1096, 1108, 1097, 1109, 1110, 1111, 1112, 1098, + 1113, 1114, 1115, 1116, 1118, 1099, 1100, 1101, 1119, 1102, + 1103, 1104, 1122, 1105, 1123, 1106, 1107, 1124, 1125, 1126, + 1108, 1127, 1109, 1110, 1111, 1112, 1128, 1113, 1114, 1115, + + 1116, 1118, 1129, 1130, 1131, 1119, 1132, 1133, 1134, 1122, + 1135, 1123, 1136, 1138, 1124, 1125, 1126, 1140, 1127, 1141, + 1142, 1143, 1144, 1128, 1145, 1146, 1147, 1148, 1149, 1129, + 1130, 1131, 1150, 1132, 1133, 1134, 1152, 1135, 1153, 1136, + 1138, 1154, 1155, 1156, 1140, 1159, 1141, 1142, 1143, 1144, + 1161, 1145, 1146, 1147, 1148, 1149, 1162, 1163, 1164, 1150, + 1165, 1166, 1167, 1152, 1168, 1153, 1169, 1170, 1154, 1155, + 1156, 1171, 1159, 1172, 1173, 1174, 1175, 1161, 1176, 1177, + 1179, 1180, 1181, 1162, 1163, 1164, 1182, 1165, 1166, 1167, + 1183, 1168, 1184, 1169, 1170, 1185, 1186, 1188, 1171, 1189, + + 1172, 1173, 1174, 1175, 1190, 1176, 1177, 1179, 1180, 1181, + 1191, 1192, 1193, 1182, 1197, 1198, 1199, 1183, 1200, 1184, + 1195, 1202, 1185, 1186, 1188, 1203, 1189, 1205, 1196, 1206, + 1207, 1190, 1208, 1209, 1210, 1201, 1211, 1191, 1192, 1193, + 1212, 1197, 1198, 1199, 1213, 1200, 1214, 1195, 1202, 1215, + 1216, 1219, 1203, 1220, 1205, 1221, 1206, 1207, 1217, 1208, + 1209, 1210, 1201, 1211, 1218, 1222, 1223, 1212, 1224, 1225, + 1227, 1213, 1228, 1214, 1229, 1230, 1215, 1216, 1219, 1231, + 1220, 1232, 1221, 1233, 1234, 1217, 1235, 1236, 1237, 1238, + 1239, 1218, 1222, 1223, 1240, 1224, 1225, 1227, 1241, 1228, + + 1242, 1229, 1230, 1243, 1244, 1245, 1231, 1246, 1232, 1247, + 1233, 1234, 1248, 1235, 1236, 1237, 1238, 1239, 1249, 1250, + 1251, 1240, 1252, 1253, 1254, 1241, 1255, 1242, 1257, 1258, + 1243, 1244, 1245, 1259, 1246, 1260, 1247, 1261, 1262, 1248, + 1263, 1264, 1265, 1266, 1269, 1249, 1250, 1251, 1270, 1252, + 1253, 1254, 1271, 1255, 1272, 1257, 1258, 1273, 1274, 1275, + 1259, 1276, 1260, 1277, 1261, 1262, 1278, 1263, 1264, 1265, + 1266, 1269, 1280, 1281, 1282, 1270, 1283, 1285, 1286, 1271, + 1287, 1272, 1288, 1289, 1273, 1274, 1275, 1290, 1276, 1291, + 1277, 1292, 1293, 1278, 1294, 1295, 1297, 1298, 1303, 1280, + + 1281, 1282, 1304, 1283, 1285, 1286, 1306, 1287, 1307, 1288, + 1289, 1308, 1309, 1310, 1290, 1311, 1291, 1312, 1292, 1293, + 1313, 1294, 1295, 1297, 1298, 1303, 1315, 1316, 1317, 1304, + 1318, 1319, 1321, 1306, 1322, 1307, 1323, 1324, 1308, 1309, + 1310, 1325, 1311, 1326, 1312, 1327, 1328, 1313, 1329, 1331, + 1332, 1333, 1334, 1315, 1316, 1317, 1335, 1318, 1319, 1321, + 1336, 1322, 1337, 1323, 1324, 1338, 1339, 1340, 1325, 1341, + 1326, 1342, 1327, 1328, 1343, 1329, 1331, 1332, 1333, 1334, + 1344, 1345, 1346, 1335, 1347, 1348, 1349, 1336, 1350, 1337, + 1351, 1352, 1338, 1339, 1340, 1353, 1341, 1355, 1342, 1356, + + 1357, 1343, 1359, 1360, 1361, 1363, 1362, 1344, 1345, 1346, + 1365, 1347, 1348, 1349, 1367, 1350, 1368, 1351, 1352, 1369, + 1370, 1371, 1353, 1372, 1355, 1373, 1356, 1357, 1374, 1359, + 1360, 1361, 1363, 1362, 1375, 1378, 1376, 1365, 1379, 1380, + 1381, 1367, 1377, 1368, 1382, 1383, 1369, 1370, 1371, 1384, + 1372, 1385, 1373, 1386, 1387, 1374, 1389, 1390, 1391, 1392, + 1393, 1375, 1378, 1376, 1394, 1379, 1380, 1381, 1395, 1377, + 1396, 1382, 1383, 1397, 1398, 1399, 1384, 1400, 1385, 1401, + 1386, 1387, 1404, 1389, 1390, 1391, 1392, 1393, 1405, 1406, + 1407, 1394, 1408, 1409, 1410, 1395, 1411, 1396, 1412, 1413, + + 1397, 1398, 1399, 1415, 1400, 1416, 1401, 1417, 1418, 1404, + 1420, 1421, 1422, 1423, 1424, 1405, 1406, 1407, 1425, 1408, + 1409, 1410, 1427, 1411, 1429, 1412, 1413, 1430, 1431, 1432, + 1415, 1433, 1416, 1434, 1417, 1418, 1435, 1420, 1421, 1422, + 1423, 1424, 1436, 1437, 1438, 1425, 1439, 1440, 1441, 1427, + 1442, 1429, 1443, 1444, 1430, 1431, 1432, 1445, 1433, 1446, + 1434, 1447, 1448, 1435, 1449, 1450, 1451, 1452, 1453, 1436, + 1437, 1438, 1454, 1439, 1440, 1441, 1455, 1442, 1456, 1443, + 1444, 1457, 1458, 1459, 1445, 1460, 1446, 1461, 1447, 1448, + 1462, 1449, 1450, 1451, 1452, 1453, 1463, 1464, 1465, 1454, + + 1466, 1467, 1468, 1455, 1469, 1456, 1470, 1471, 1457, 1458, + 1459, 1472, 1460, 1473, 1461, 1474, 1475, 1462, 1476, 1477, + 1478, 1479, 1480, 1463, 1464, 1465, 1481, 1466, 1467, 1468, + 1482, 1469, 1483, 1470, 1471, 1484, 1485, 1486, 1472, 1487, + 1473, 1488, 1474, 1475, 1489, 1476, 1477, 1478, 1479, 1480, + 1490, 1492, 1493, 1481, 1494, 1495, 1496, 1482, 1497, 1483, + 1498, 1499, 1484, 1485, 1486, 1500, 1487, 1501, 1488, 1502, + 1503, 1489, 1504, 1505, 1506, 1507, 1508, 1490, 1492, 1493, + 1509, 1494, 1495, 1496, 1510, 1497, 1511, 1498, 1499, 1512, + 1513, 1514, 1500, 1515, 1501, 1516, 1502, 1503, 1517, 1504, + + 1505, 1506, 1507, 1508, 1519, 1520, 1521, 1509, 1522, 1523, + 1524, 1510, 1525, 1511, 1526, 1527, 1512, 1513, 1514, 1528, + 1515, 1529, 1516, 1530, 1531, 1517, 1532, 1534, 1535, 1536, + 1537, 1519, 1520, 1521, 1538, 1522, 1523, 1524, 1539, 1525, + 1540, 1526, 1527, 1541, 1542, 1543, 1528, 1544, 1529, 1194, + 1530, 1531, 1187, 1532, 1534, 1535, 1536, 1537, 1178, 1160, + 1158, 1538, 1157, 1151, 1139, 1539, 1137, 1540, 1121, 1120, + 1541, 1542, 1543, 1117, 1544, 39, 39, 995, 995, 993, + 993, 1056, 1054, 1053, 1048, 1034, 1027, 1018, 1000, 999, + 998, 995, 993, 984, 969, 962, 958, 933, 882, 879, + + 877, 874, 873, 872, 871, 870, 834, 833, 830, 826, + 792, 787, 786, 785, 783, 762, 760, 752, 718, 684, + 680, 678, 676, 669, 667, 648, 644, 629, 623, 621, + 604, 592, 560, 558, 557, 543, 526, 514, 500, 499, + 492, 479, 468, 466, 456, 454, 433, 429, 427, 422, + 404, 395, 388, 350, 317, 301, 265, 239, 202, 37, + 37, 1545, 3, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545 + } ; + +static yyconst flex_int16_t yy_chk[3032] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 7, 7, + 9, 10, 13, 10, 11, 11, 11, 11, 11, 16, + 21, 1550, 13, 26, 1549, 16, 16, 9, 39, 39, + 15, 771, 28, 771, 15, 18, 16, 1548, 15, 13, + + 17, 15, 18, 771, 15, 1546, 16, 21, 17, 13, + 26, 17, 16, 16, 9, 12, 12, 15, 12, 28, + 17, 15, 18, 16, 12, 15, 12, 17, 15, 18, + 20, 15, 19, 12, 1527, 17, 1505, 20, 17, 20, + 19, 1471, 12, 12, 29, 12, 19, 17, 1389, 33, + 1387, 12, 19, 12, 35, 179, 179, 20, 29, 19, + 12, 14, 36, 14, 20, 1379, 20, 19, 14, 14, + 22, 29, 14, 19, 23, 14, 33, 22, 23, 19, + 22, 35, 22, 34, 23, 29, 1374, 34, 14, 36, + 14, 883, 27, 883, 43, 14, 14, 22, 47, 14, + + 27, 23, 14, 883, 22, 23, 27, 22, 48, 22, + 34, 23, 24, 24, 34, 49, 24, 32, 32, 27, + 24, 43, 50, 32, 51, 47, 24, 27, 46, 46, + 46, 46, 46, 27, 52, 48, 53, 54, 56, 24, + 24, 1343, 49, 24, 32, 32, 55, 24, 55, 50, + 32, 51, 57, 24, 25, 58, 25, 59, 25, 60, + 61, 52, 25, 53, 54, 56, 63, 64, 25, 65, + 66, 67, 68, 55, 25, 55, 70, 59, 1319, 57, + 63, 25, 58, 25, 59, 25, 60, 61, 71, 25, + 1316, 72, 73, 63, 64, 25, 65, 66, 67, 68, + + 76, 25, 30, 70, 59, 30, 30, 63, 30, 69, + 77, 69, 30, 30, 1310, 71, 30, 30, 72, 73, + 74, 1359, 1359, 78, 75, 78, 69, 76, 1304, 30, + 75, 74, 30, 30, 79, 30, 69, 77, 69, 30, + 30, 62, 62, 30, 30, 31, 62, 74, 31, 31, + 78, 75, 78, 69, 62, 31, 31, 75, 74, 62, + 80, 79, 31, 81, 82, 83, 84, 85, 62, 62, + 86, 87, 31, 62, 88, 31, 31, 92, 94, 89, + 91, 62, 31, 31, 89, 91, 62, 80, 93, 31, + 81, 82, 83, 84, 85, 90, 95, 86, 87, 90, + + 93, 88, 96, 97, 92, 94, 89, 91, 99, 98, + 101, 89, 91, 102, 104, 93, 103, 105, 108, 112, + 106, 1273, 90, 95, 98, 113, 90, 93, 106, 96, + 97, 111, 103, 103, 1263, 99, 98, 101, 115, 109, + 102, 104, 116, 103, 105, 108, 112, 106, 110, 117, + 109, 98, 113, 111, 109, 106, 109, 118, 111, 103, + 103, 107, 110, 107, 107, 115, 109, 107, 107, 116, + 107, 119, 114, 107, 120, 110, 117, 109, 122, 107, + 111, 109, 114, 109, 118, 123, 1255, 125, 107, 110, + 107, 107, 126, 128, 107, 107, 1244, 107, 119, 114, + + 107, 120, 127, 1241, 129, 122, 107, 130, 127, 114, + 131, 132, 123, 124, 125, 133, 124, 134, 136, 126, + 128, 137, 138, 124, 124, 139, 140, 142, 137, 127, + 124, 129, 143, 144, 130, 127, 124, 131, 132, 145, + 124, 146, 133, 124, 134, 136, 147, 148, 137, 138, + 124, 124, 139, 140, 142, 137, 149, 124, 150, 143, + 144, 151, 152, 124, 153, 155, 145, 156, 146, 157, + 158, 159, 160, 147, 148, 161, 162, 163, 164, 165, + 166, 167, 168, 149, 169, 150, 170, 171, 151, 152, + 172, 153, 155, 166, 156, 174, 157, 158, 159, 160, + + 173, 173, 161, 162, 163, 164, 165, 166, 167, 168, + 175, 169, 177, 170, 171, 178, 180, 172, 181, 183, + 166, 182, 174, 184, 182, 185, 186, 173, 173, 187, + 188, 190, 192, 193, 194, 195, 196, 175, 197, 177, + 198, 195, 178, 180, 199, 181, 183, 200, 182, 201, + 184, 182, 185, 186, 203, 204, 187, 188, 190, 192, + 193, 194, 195, 196, 205, 197, 202, 198, 206, 207, + 208, 199, 209, 202, 200, 210, 201, 211, 202, 212, + 213, 203, 204, 202, 214, 215, 216, 218, 219, 221, + 219, 205, 222, 202, 223, 206, 207, 208, 225, 209, + + 202, 226, 210, 228, 211, 202, 212, 213, 229, 230, + 202, 214, 215, 216, 218, 219, 221, 219, 231, 222, + 234, 223, 233, 235, 236, 225, 237, 233, 226, 238, + 228, 239, 240, 241, 242, 229, 230, 243, 244, 245, + 246, 239, 247, 248, 249, 231, 250, 234, 251, 233, + 235, 236, 248, 237, 252, 253, 238, 255, 239, 240, + 241, 242, 256, 257, 243, 244, 245, 246, 239, 247, + 248, 249, 258, 250, 261, 251, 263, 264, 265, 266, + 267, 252, 253, 269, 255, 270, 271, 274, 275, 256, + 257, 277, 278, 279, 281, 282, 283, 284, 285, 258, + + 286, 261, 287, 263, 264, 265, 266, 267, 289, 290, + 269, 292, 270, 271, 274, 275, 293, 294, 277, 278, + 279, 281, 282, 283, 284, 285, 295, 286, 296, 287, + 297, 300, 301, 302, 303, 289, 290, 307, 292, 309, + 295, 296, 310, 293, 294, 311, 313, 314, 315, 316, + 1240, 1239, 1238, 295, 318, 296, 1235, 297, 300, 301, + 302, 303, 319, 1219, 307, 320, 309, 295, 321, 310, + 322, 323, 311, 313, 314, 315, 316, 317, 317, 317, + 325, 318, 327, 317, 329, 317, 330, 331, 317, 319, + 317, 332, 320, 333, 1214, 321, 317, 322, 323, 317, + + 336, 340, 1199, 334, 317, 317, 317, 325, 341, 327, + 317, 329, 317, 330, 331, 317, 342, 317, 332, 343, + 333, 334, 344, 317, 345, 334, 317, 336, 340, 334, + 334, 346, 347, 348, 350, 341, 351, 352, 354, 355, + 357, 358, 359, 342, 362, 363, 343, 352, 334, 344, + 348, 345, 334, 353, 361, 361, 364, 353, 346, 347, + 348, 350, 353, 351, 352, 354, 355, 357, 358, 359, + 361, 362, 363, 367, 368, 370, 371, 348, 372, 373, + 353, 361, 361, 364, 353, 374, 375, 376, 378, 353, + 379, 380, 382, 383, 384, 378, 385, 361, 386, 387, + + 367, 368, 370, 371, 388, 372, 373, 389, 391, 388, + 392, 394, 374, 375, 376, 378, 395, 379, 380, 382, + 383, 384, 378, 385, 397, 386, 387, 398, 400, 401, + 402, 388, 404, 405, 389, 391, 388, 392, 394, 407, + 408, 409, 410, 395, 411, 413, 415, 417, 418, 419, + 420, 397, 421, 422, 398, 400, 401, 402, 424, 404, + 405, 425, 426, 427, 428, 429, 407, 408, 409, 410, + 430, 411, 413, 415, 417, 418, 419, 420, 433, 421, + 422, 435, 436, 437, 438, 424, 439, 441, 425, 426, + 427, 428, 429, 442, 440, 443, 445, 430, 440, 446, + + 444, 447, 448, 449, 450, 433, 451, 452, 435, 436, + 437, 438, 444, 439, 441, 453, 455, 454, 456, 457, + 442, 440, 443, 445, 454, 440, 446, 444, 447, 448, + 449, 450, 458, 451, 452, 459, 460, 461, 462, 444, + 464, 466, 453, 455, 454, 456, 457, 465, 465, 467, + 469, 454, 468, 465, 471, 473, 475, 476, 473, 458, + 467, 477, 459, 460, 461, 462, 478, 464, 466, 468, + 479, 481, 468, 483, 465, 465, 467, 469, 484, 468, + 465, 471, 473, 475, 476, 473, 480, 467, 477, 480, + 485, 486, 487, 478, 490, 494, 468, 479, 481, 468, + + 483, 495, 493, 497, 498, 484, 493, 500, 501, 493, + 502, 503, 504, 480, 505, 506, 480, 485, 486, 487, + 507, 490, 494, 508, 509, 510, 511, 513, 495, 493, + 497, 498, 514, 493, 500, 501, 493, 502, 503, 504, + 517, 505, 506, 519, 521, 522, 523, 507, 524, 525, + 508, 509, 510, 511, 513, 526, 527, 528, 529, 514, + 530, 531, 532, 533, 534, 535, 524, 517, 536, 539, + 519, 521, 522, 523, 541, 524, 525, 542, 545, 547, + 1198, 550, 526, 527, 528, 529, 549, 530, 531, 532, + 533, 534, 535, 543, 543, 536, 539, 549, 552, 553, + + 555, 541, 543, 556, 542, 545, 547, 543, 550, 557, + 558, 559, 560, 549, 564, 565, 566, 567, 568, 569, + 543, 543, 570, 571, 549, 552, 553, 555, 572, 543, + 556, 573, 574, 576, 543, 577, 557, 558, 559, 560, + 578, 564, 565, 566, 567, 568, 569, 579, 580, 570, + 571, 581, 582, 583, 584, 572, 585, 586, 573, 574, + 576, 587, 577, 588, 589, 591, 592, 578, 593, 594, + 595, 596, 597, 599, 579, 580, 600, 601, 581, 582, + 583, 584, 602, 585, 586, 603, 604, 606, 587, 607, + 588, 589, 591, 592, 609, 593, 594, 595, 596, 597, + + 599, 610, 611, 600, 601, 612, 613, 614, 615, 602, + 616, 618, 603, 604, 606, 619, 607, 617, 617, 621, + 622, 609, 623, 624, 625, 626, 628, 1182, 610, 611, + 630, 1150, 612, 613, 614, 615, 632, 616, 618, 634, + 637, 638, 619, 639, 617, 617, 621, 622, 641, 623, + 624, 625, 626, 628, 629, 642, 643, 630, 629, 646, + 629, 647, 648, 632, 629, 629, 634, 637, 638, 649, + 639, 650, 651, 652, 653, 641, 654, 655, 656, 658, + 660, 629, 642, 643, 662, 629, 646, 629, 647, 648, + 666, 629, 629, 667, 668, 669, 649, 672, 650, 651, + + 652, 653, 673, 654, 655, 656, 658, 660, 674, 675, + 676, 662, 673, 678, 679, 680, 681, 666, 682, 683, + 667, 668, 669, 684, 672, 685, 686, 687, 688, 673, + 689, 690, 691, 692, 693, 674, 675, 676, 694, 673, + 678, 679, 680, 681, 695, 682, 683, 696, 697, 698, + 684, 699, 685, 686, 687, 688, 700, 689, 690, 691, + 692, 693, 701, 702, 703, 694, 704, 707, 710, 711, + 713, 695, 714, 717, 696, 697, 698, 718, 699, 719, + 720, 721, 722, 700, 723, 724, 725, 726, 727, 701, + 702, 703, 728, 704, 707, 710, 711, 713, 729, 714, + + 717, 730, 731, 732, 718, 733, 719, 720, 721, 722, + 734, 723, 724, 725, 726, 727, 736, 737, 738, 728, + 739, 741, 742, 743, 744, 729, 745, 746, 730, 731, + 732, 747, 733, 748, 749, 750, 751, 734, 752, 753, + 759, 760, 762, 736, 737, 738, 766, 739, 741, 742, + 743, 744, 769, 745, 746, 772, 773, 774, 747, 775, + 748, 749, 750, 751, 778, 752, 753, 759, 760, 762, + 779, 780, 781, 766, 782, 783, 784, 1123, 786, 769, + 787, 788, 772, 773, 774, 789, 775, 785, 783, 791, + 792, 778, 785, 793, 794, 795, 796, 779, 780, 781, + + 797, 782, 783, 784, 785, 786, 798, 787, 788, 799, + 800, 801, 789, 802, 785, 783, 791, 792, 803, 785, + 793, 794, 795, 796, 805, 806, 807, 797, 808, 809, + 810, 785, 811, 798, 812, 813, 799, 800, 801, 814, + 802, 816, 817, 818, 819, 803, 820, 822, 823, 824, + 825, 805, 806, 807, 826, 808, 809, 810, 827, 811, + 828, 812, 813, 829, 831, 832, 814, 833, 816, 817, + 818, 819, 830, 820, 822, 823, 824, 825, 834, 836, + 838, 826, 830, 840, 841, 827, 842, 828, 843, 845, + 829, 831, 832, 846, 833, 847, 848, 850, 851, 830, + + 852, 854, 855, 856, 857, 834, 836, 838, 858, 830, + 840, 841, 859, 842, 861, 843, 845, 862, 863, 864, + 846, 865, 847, 848, 850, 851, 866, 852, 854, 855, + 856, 857, 867, 868, 869, 858, 870, 871, 872, 859, + 873, 861, 874, 876, 862, 863, 864, 877, 865, 878, + 879, 880, 881, 866, 882, 886, 887, 892, 893, 867, + 868, 869, 894, 870, 871, 872, 895, 873, 896, 874, + 876, 897, 898, 899, 877, 900, 878, 879, 880, 881, + 901, 882, 886, 887, 892, 893, 902, 904, 905, 894, + 906, 907, 908, 895, 909, 896, 911, 912, 897, 898, + + 899, 913, 900, 914, 915, 916, 917, 901, 918, 920, + 921, 923, 924, 902, 904, 905, 926, 906, 907, 908, + 927, 909, 929, 911, 912, 930, 934, 933, 913, 935, + 914, 915, 916, 917, 938, 918, 920, 921, 923, 924, + 939, 940, 941, 926, 933, 942, 943, 927, 944, 929, + 946, 947, 930, 934, 933, 948, 935, 949, 952, 954, + 956, 938, 957, 958, 962, 963, 964, 939, 940, 941, + 965, 933, 942, 943, 966, 944, 967, 946, 947, 968, + 969, 970, 948, 971, 949, 952, 954, 956, 972, 957, + 958, 962, 963, 964, 973, 974, 975, 965, 976, 977, + + 978, 966, 979, 967, 980, 981, 968, 969, 970, 982, + 971, 983, 984, 985, 986, 972, 987, 988, 990, 991, + 996, 973, 974, 975, 997, 976, 977, 978, 998, 979, + 999, 980, 981, 1000, 1002, 1003, 982, 1004, 983, 984, + 985, 986, 1005, 987, 988, 990, 991, 996, 1006, 1007, + 1008, 997, 1009, 1010, 1011, 998, 1012, 999, 1013, 1014, + 1000, 1002, 1003, 1015, 1004, 1016, 1017, 1018, 1019, 1005, + 1020, 1021, 1023, 1024, 1026, 1006, 1007, 1008, 1027, 1009, + 1010, 1011, 1030, 1012, 1031, 1013, 1014, 1032, 1034, 1035, + 1015, 1037, 1016, 1017, 1018, 1019, 1038, 1020, 1021, 1023, + + 1024, 1026, 1040, 1041, 1042, 1027, 1044, 1045, 1046, 1030, + 1047, 1031, 1048, 1050, 1032, 1034, 1035, 1052, 1037, 1053, + 1054, 1055, 1056, 1038, 1057, 1058, 1060, 1061, 1062, 1040, + 1041, 1042, 1063, 1044, 1045, 1046, 1065, 1047, 1068, 1048, + 1050, 1071, 1072, 1073, 1052, 1076, 1053, 1054, 1055, 1056, + 1078, 1057, 1058, 1060, 1061, 1062, 1079, 1080, 1081, 1063, + 1082, 1083, 1084, 1065, 1085, 1068, 1086, 1087, 1071, 1072, + 1073, 1088, 1076, 1089, 1090, 1091, 1092, 1078, 1093, 1094, + 1097, 1098, 1100, 1079, 1080, 1081, 1101, 1082, 1083, 1084, + 1102, 1085, 1103, 1086, 1087, 1104, 1105, 1107, 1088, 1108, + + 1089, 1090, 1091, 1092, 1109, 1093, 1094, 1097, 1098, 1100, + 1110, 1111, 1112, 1101, 1117, 1118, 1119, 1102, 1120, 1103, + 1116, 1121, 1104, 1105, 1107, 1122, 1108, 1125, 1116, 1127, + 1128, 1109, 1130, 1131, 1132, 1120, 1133, 1110, 1111, 1112, + 1134, 1117, 1118, 1119, 1135, 1120, 1136, 1116, 1121, 1137, + 1138, 1140, 1122, 1141, 1125, 1142, 1127, 1128, 1139, 1130, + 1131, 1132, 1120, 1133, 1139, 1144, 1146, 1134, 1147, 1148, + 1151, 1135, 1152, 1136, 1153, 1154, 1137, 1138, 1140, 1155, + 1141, 1156, 1142, 1157, 1158, 1139, 1159, 1160, 1161, 1162, + 1163, 1139, 1144, 1146, 1164, 1147, 1148, 1151, 1165, 1152, + + 1166, 1153, 1154, 1167, 1168, 1169, 1155, 1170, 1156, 1172, + 1157, 1158, 1173, 1159, 1160, 1161, 1162, 1163, 1174, 1175, + 1176, 1164, 1177, 1178, 1179, 1165, 1180, 1166, 1183, 1184, + 1167, 1168, 1169, 1187, 1170, 1188, 1172, 1189, 1192, 1173, + 1193, 1194, 1196, 1197, 1200, 1174, 1175, 1176, 1201, 1177, + 1178, 1179, 1202, 1180, 1204, 1183, 1184, 1205, 1206, 1207, + 1187, 1208, 1188, 1209, 1189, 1192, 1210, 1193, 1194, 1196, + 1197, 1200, 1215, 1216, 1217, 1201, 1218, 1220, 1221, 1202, + 1222, 1204, 1225, 1226, 1205, 1206, 1207, 1227, 1208, 1228, + 1209, 1229, 1232, 1210, 1233, 1234, 1236, 1237, 1242, 1215, + + 1216, 1217, 1243, 1218, 1220, 1221, 1246, 1222, 1247, 1225, + 1226, 1248, 1250, 1251, 1227, 1252, 1228, 1253, 1229, 1232, + 1254, 1233, 1234, 1236, 1237, 1242, 1256, 1257, 1259, 1243, + 1261, 1262, 1264, 1246, 1265, 1247, 1266, 1267, 1248, 1250, + 1251, 1268, 1252, 1269, 1253, 1270, 1271, 1254, 1272, 1274, + 1276, 1277, 1279, 1256, 1257, 1259, 1280, 1261, 1262, 1264, + 1282, 1265, 1284, 1266, 1267, 1285, 1286, 1287, 1268, 1288, + 1269, 1289, 1270, 1271, 1290, 1272, 1274, 1276, 1277, 1279, + 1293, 1294, 1295, 1280, 1296, 1297, 1298, 1282, 1299, 1284, + 1300, 1301, 1285, 1286, 1287, 1302, 1288, 1305, 1289, 1308, + + 1309, 1290, 1312, 1313, 1314, 1315, 1314, 1293, 1294, 1295, + 1317, 1296, 1297, 1298, 1320, 1299, 1321, 1300, 1301, 1322, + 1324, 1325, 1302, 1326, 1305, 1327, 1308, 1309, 1328, 1312, + 1313, 1314, 1315, 1314, 1329, 1331, 1330, 1317, 1333, 1334, + 1335, 1320, 1330, 1321, 1336, 1337, 1322, 1324, 1325, 1338, + 1326, 1340, 1327, 1341, 1342, 1328, 1344, 1345, 1346, 1347, + 1348, 1329, 1331, 1330, 1349, 1333, 1334, 1335, 1350, 1330, + 1351, 1336, 1337, 1352, 1353, 1354, 1338, 1355, 1340, 1358, + 1341, 1342, 1360, 1344, 1345, 1346, 1347, 1348, 1361, 1362, + 1363, 1349, 1364, 1365, 1367, 1350, 1368, 1351, 1371, 1372, + + 1352, 1353, 1354, 1375, 1355, 1376, 1358, 1377, 1378, 1360, + 1380, 1381, 1383, 1384, 1385, 1361, 1362, 1363, 1386, 1364, + 1365, 1367, 1388, 1368, 1391, 1371, 1372, 1392, 1393, 1394, + 1375, 1395, 1376, 1396, 1377, 1378, 1397, 1380, 1381, 1383, + 1384, 1385, 1398, 1399, 1400, 1386, 1401, 1404, 1405, 1388, + 1406, 1391, 1407, 1408, 1392, 1393, 1394, 1409, 1395, 1410, + 1396, 1412, 1414, 1397, 1415, 1416, 1417, 1419, 1420, 1398, + 1399, 1400, 1422, 1401, 1404, 1405, 1425, 1406, 1426, 1407, + 1408, 1427, 1428, 1429, 1409, 1430, 1410, 1431, 1412, 1414, + 1433, 1415, 1416, 1417, 1419, 1420, 1434, 1435, 1436, 1422, + + 1437, 1438, 1439, 1425, 1440, 1426, 1441, 1442, 1427, 1428, + 1429, 1443, 1430, 1444, 1431, 1445, 1446, 1433, 1447, 1448, + 1449, 1450, 1451, 1434, 1435, 1436, 1452, 1437, 1438, 1439, + 1453, 1440, 1454, 1441, 1442, 1456, 1457, 1458, 1443, 1466, + 1444, 1467, 1445, 1446, 1468, 1447, 1448, 1449, 1450, 1451, + 1470, 1472, 1473, 1452, 1475, 1476, 1477, 1453, 1478, 1454, + 1481, 1483, 1456, 1457, 1458, 1484, 1466, 1485, 1467, 1486, + 1487, 1468, 1489, 1490, 1491, 1492, 1493, 1470, 1472, 1473, + 1494, 1475, 1476, 1477, 1495, 1478, 1496, 1481, 1483, 1498, + 1499, 1500, 1484, 1502, 1485, 1503, 1486, 1487, 1504, 1489, + + 1490, 1491, 1492, 1493, 1506, 1507, 1508, 1494, 1509, 1511, + 1512, 1495, 1513, 1496, 1516, 1517, 1498, 1499, 1500, 1518, + 1502, 1519, 1503, 1521, 1522, 1504, 1524, 1528, 1529, 1530, + 1533, 1506, 1507, 1508, 1534, 1509, 1511, 1512, 1535, 1513, + 1537, 1516, 1517, 1538, 1540, 1541, 1518, 1542, 1519, 1114, + 1521, 1522, 1106, 1524, 1528, 1529, 1530, 1533, 1095, 1077, + 1075, 1534, 1074, 1064, 1051, 1535, 1049, 1537, 1029, 1028, + 1538, 1540, 1541, 1025, 1542, 1547, 1547, 995, 994, 993, + 992, 953, 951, 950, 945, 928, 919, 910, 890, 889, + 888, 885, 884, 875, 860, 853, 849, 821, 770, 763, + + 761, 758, 757, 756, 755, 754, 716, 715, 712, 705, + 670, 665, 664, 663, 661, 633, 631, 627, 590, 551, + 548, 546, 544, 540, 537, 518, 512, 496, 491, 488, + 470, 463, 434, 432, 431, 416, 393, 381, 366, 365, + 360, 349, 338, 335, 328, 326, 312, 308, 306, 298, + 280, 268, 259, 220, 191, 176, 141, 121, 100, 37, + 5, 3, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, + 1545 + } ; + +static yy_state_type yy_last_accepting_state; +static char *yy_last_accepting_cpos; + +extern int yy_flex_debug; +int yy_flex_debug = 0; + +/* The intent behind this definition is that it'll catch + * any uses of REJECT which flex missed. + */ +#define REJECT reject_used_but_not_detected +static int yy_more_flag = 0; +static int yy_more_len = 0; +#define yymore() ((yy_more_flag) = 1) +#define YY_MORE_ADJ (yy_more_len) +#define YY_RESTORE_YY_MORE_OFFSET +char *yytext; +#line 1 "conf_lexer.l" +/* + * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd). + * conf_lexer.l: Scans the ircd configuration file for tokens. + * + * Copyright (C) 2002 by the past and present ircd coders, and others. + * + * 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 + * + * $Id: conf_lexer.l 1547 2012-09-30 17:50:03Z michael $ + */ +#line 31 "conf_lexer.l" +#include "stdinc.h" +#include "irc_string.h" +#include "conf.h" +#include "conf_parser.h" /* autogenerated header file */ +#include "memory.h" +#include "hostmask.h" +#include "log.h" + +#undef YY_INPUT +#define YY_FATAL_ERROR(msg) conf_yy_fatal_error(msg) +#define YY_INPUT(buf,result,max_size) \ + if (!(result = conf_yy_input(buf, max_size))) \ + YY_FATAL_ERROR("input in flex scanner failed"); +#define MAX_INCLUDE_DEPTH 10 + + +unsigned int lineno = 1; +char linebuf[IRCD_BUFSIZE]; +char conffilebuf[IRCD_BUFSIZE]; + +static int include_stack_ptr = 0; +static YY_BUFFER_STATE include_stack[MAX_INCLUDE_DEPTH]; +static unsigned int lineno_stack[MAX_INCLUDE_DEPTH]; +static FILE *inc_fbfile_in[MAX_INCLUDE_DEPTH]; +static char conffile_stack[MAX_INCLUDE_DEPTH][IRCD_BUFSIZE]; +static void ccomment(void); +static void cinclude(void); +static int ieof(void); + +static int +conf_yy_input(char *lbuf, unsigned int max_size) +{ + return !fgets(lbuf, max_size, conf_parser_ctx.conf_file) ? 0 : strlen(lbuf); +} + +static int +conf_yy_fatal_error(const char *msg) +{ + return 0; +} + +#line 1700 "conf_lexer.c" + +#define INITIAL 0 + +#ifndef YY_NO_UNISTD_H +/* Special case for "unistd.h", since it is non-ANSI. We include it way + * down here because we want the user's section 1 to have been scanned first. + * The user has a chance to override it with an option. + */ +#include <unistd.h> +#endif + +#ifndef YY_EXTRA_TYPE +#define YY_EXTRA_TYPE void * +#endif + +static int yy_init_globals (void ); + +/* Accessor methods to globals. + These are made visible to non-reentrant scanners for convenience. */ + +int yylex_destroy (void ); + +int yyget_debug (void ); + +void yyset_debug (int debug_flag ); + +YY_EXTRA_TYPE yyget_extra (void ); + +void yyset_extra (YY_EXTRA_TYPE user_defined ); + +FILE *yyget_in (void ); + +void yyset_in (FILE * in_str ); + +FILE *yyget_out (void ); + +void yyset_out (FILE * out_str ); + +yy_size_t yyget_leng (void ); + +char *yyget_text (void ); + +int yyget_lineno (void ); + +void yyset_lineno (int line_number ); + +/* Macros after this point can all be overridden by user definitions in + * section 1. + */ + +#ifndef YY_SKIP_YYWRAP +#ifdef __cplusplus +extern "C" int yywrap (void ); +#else +extern int yywrap (void ); +#endif +#endif + +#ifndef yytext_ptr +static void yy_flex_strncpy (char *,yyconst char *,int ); +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen (yyconst char * ); +#endif + +#ifndef YY_NO_INPUT + +#ifdef __cplusplus +static int yyinput (void ); +#else +static int input (void ); +#endif + +#endif + +/* Amount of stuff to slurp up with each read. */ +#ifndef YY_READ_BUF_SIZE +#define YY_READ_BUF_SIZE 8192 +#endif + +/* Copy whatever the last rule matched to the standard output. */ +#ifndef ECHO +/* This used to be an fputs(), but since the string might contain NUL's, + * we now use fwrite(). + */ +#define ECHO do { if (fwrite( yytext, yyleng, 1, yyout )) {} } while (0) +#endif + +/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL, + * is returned in "result". + */ +#ifndef YY_INPUT +#define YY_INPUT(buf,result,max_size) \ + if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \ + { \ + int c = '*'; \ + size_t n; \ + for ( n = 0; n < max_size && \ + (c = getc( yyin )) != EOF && c != '\n'; ++n ) \ + buf[n] = (char) c; \ + if ( c == '\n' ) \ + buf[n++] = (char) c; \ + if ( c == EOF && ferror( yyin ) ) \ + YY_FATAL_ERROR( "input in flex scanner failed" ); \ + result = n; \ + } \ + else \ + { \ + errno=0; \ + while ( (result = fread(buf, 1, max_size, yyin))==0 && ferror(yyin)) \ + { \ + if( errno != EINTR) \ + { \ + YY_FATAL_ERROR( "input in flex scanner failed" ); \ + break; \ + } \ + errno=0; \ + clearerr(yyin); \ + } \ + }\ +\ + +#endif + +/* No semi-colon after return; correct usage is to write "yyterminate();" - + * we don't want an extra ';' after the "return" because that will cause + * some compilers to complain about unreachable statements. + */ +#ifndef yyterminate +#define yyterminate() return YY_NULL +#endif + +/* Number of entries by which start-condition stack grows. */ +#ifndef YY_START_STACK_INCR +#define YY_START_STACK_INCR 25 +#endif + +/* Report a fatal error. */ +#ifndef YY_FATAL_ERROR +#define YY_FATAL_ERROR(msg) yy_fatal_error( msg ) +#endif + +/* end tables serialization structures and prototypes */ + +/* Default declaration of generated scanner - a define so the user can + * easily add parameters. + */ +#ifndef YY_DECL +#define YY_DECL_IS_OURS 1 + +extern int yylex (void); + +#define YY_DECL int yylex (void) +#endif /* !YY_DECL */ + +/* Code executed at the beginning of each rule, after yytext and yyleng + * have been set up. + */ +#ifndef YY_USER_ACTION +#define YY_USER_ACTION +#endif + +/* Code executed at the end of each rule. */ +#ifndef YY_BREAK +#define YY_BREAK break; +#endif + +#define YY_RULE_SETUP \ + YY_USER_ACTION + +/** The main scanner function which does all the work. + */ +YY_DECL +{ + register yy_state_type yy_current_state; + register char *yy_cp, *yy_bp; + register int yy_act; + +#line 80 "conf_lexer.l" + +#line 1882 "conf_lexer.c" + + if ( !(yy_init) ) + { + (yy_init) = 1; + +#ifdef YY_USER_INIT + YY_USER_INIT; +#endif + + if ( ! (yy_start) ) + (yy_start) = 1; /* first start state */ + + if ( ! yyin ) + yyin = stdin; + + if ( ! yyout ) + yyout = stdout; + + if ( ! YY_CURRENT_BUFFER ) { + yyensure_buffer_stack (); + YY_CURRENT_BUFFER_LVALUE = + yy_create_buffer(yyin,YY_BUF_SIZE ); + } + + yy_load_buffer_state( ); + } + + while ( 1 ) /* loops until end-of-file is reached */ + { + (yy_more_len) = 0; + if ( (yy_more_flag) ) + { + (yy_more_len) = (yy_c_buf_p) - (yytext_ptr); + (yy_more_flag) = 0; + } + yy_cp = (yy_c_buf_p); + + /* Support of yytext. */ + *yy_cp = (yy_hold_char); + + /* yy_bp points to the position in yy_ch_buf of the start of + * the current run. + */ + yy_bp = yy_cp; + + yy_current_state = (yy_start); +yy_match: + do + { + register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)]; + if ( yy_accept[yy_current_state] ) + { + (yy_last_accepting_state) = yy_current_state; + (yy_last_accepting_cpos) = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 1546 ) + yy_c = yy_meta[(unsigned int) yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + ++yy_cp; + } + while ( yy_current_state != 1545 ); + yy_cp = (yy_last_accepting_cpos); + yy_current_state = (yy_last_accepting_state); + +yy_find_action: + yy_act = yy_accept[yy_current_state]; + + YY_DO_BEFORE_ACTION; + +do_action: /* This label is used only to access EOF actions. */ + + switch ( yy_act ) + { /* beginning of action switch */ + case 0: /* must back up */ + /* undo the effects of YY_DO_BEFORE_ACTION */ + *yy_cp = (yy_hold_char); + yy_cp = (yy_last_accepting_cpos); + yy_current_state = (yy_last_accepting_state); + goto yy_find_action; + +case 1: +YY_RULE_SETUP +#line 81 "conf_lexer.l" +{ cinclude(); } + YY_BREAK +case 2: +YY_RULE_SETUP +#line 82 "conf_lexer.l" +{ ccomment(); } + YY_BREAK +case 3: +/* rule 3 can match eol */ +YY_RULE_SETUP +#line 84 "conf_lexer.l" +{ strlcpy(linebuf, yytext+1, sizeof(linebuf)); ++lineno; yyless(1); } + YY_BREAK +case 4: +YY_RULE_SETUP +#line 86 "conf_lexer.l" +; + YY_BREAK +case 5: +YY_RULE_SETUP +#line 87 "conf_lexer.l" +; + YY_BREAK +case 6: +YY_RULE_SETUP +#line 89 "conf_lexer.l" +{ yylval.number = atoi(yytext); return NUMBER; } + YY_BREAK +case 7: +/* rule 7 can match eol */ +YY_RULE_SETUP +#line 91 "conf_lexer.l" +{ if (yytext[yyleng-2] == '\\') + { + yyless(yyleng-1); /* return last quote */ + yymore(); /* append next string */ + } + else + { + yylval.string = yytext+1; + if(yylval.string[yyleng-2] != '"') + ilog(LOG_TYPE_IRCD, "Unterminated character string"); + else + { + int i,j; + + yylval.string[yyleng-2] = '\0'; /* remove close + * quote + */ + + for (j=i=0 ;yylval.string[i] != '\0'; i++,j++) + { + if (yylval.string[i] != '\\') + { + yylval.string[j] = yylval.string[i]; + } + else + { + i++; + if (yylval.string[i] == '\0') /* XXX + * should not + * happen + */ + { + ilog(LOG_TYPE_IRCD, + "Unterminated character string"); + break; + } + yylval.string[j] = yylval.string[i]; + } + } + yylval.string[j] = '\0'; + return QSTRING; + } + } + } + YY_BREAK +case 8: +YY_RULE_SETUP +#line 136 "conf_lexer.l" +{ return ACCEPT_PASSWORD; } + YY_BREAK +case 9: +YY_RULE_SETUP +#line 137 "conf_lexer.l" +{ return ADMIN; } + YY_BREAK +case 10: +YY_RULE_SETUP +#line 138 "conf_lexer.l" +{ return ADMIN; } + YY_BREAK +case 11: +YY_RULE_SETUP +#line 139 "conf_lexer.l" +{ return AFTYPE; } + YY_BREAK +case 12: +YY_RULE_SETUP +#line 140 "conf_lexer.l" +{ return T_ALL; } + YY_BREAK +case 13: +YY_RULE_SETUP +#line 141 "conf_lexer.l" +{ return IRCD_AUTH; } + YY_BREAK +case 14: +YY_RULE_SETUP +#line 142 "conf_lexer.l" +{ return AUTOCONN; } + YY_BREAK +case 15: +YY_RULE_SETUP +#line 143 "conf_lexer.l" +{ return CAN_FLOOD; } + YY_BREAK +case 16: +YY_RULE_SETUP +#line 144 "conf_lexer.l" +{ return CALLER_ID_WAIT; } + YY_BREAK +case 17: +YY_RULE_SETUP +#line 145 "conf_lexer.l" +{ return OPERS_BYPASS_CALLERID; } + YY_BREAK +case 18: +YY_RULE_SETUP +#line 146 "conf_lexer.l" +{ return CHANNEL; } + YY_BREAK +case 19: +YY_RULE_SETUP +#line 147 "conf_lexer.l" +{ return CIDR_BITLEN_IPV4; } + YY_BREAK +case 20: +YY_RULE_SETUP +#line 148 "conf_lexer.l" +{ return CIDR_BITLEN_IPV6; } + YY_BREAK +case 21: +YY_RULE_SETUP +#line 149 "conf_lexer.l" +{ return CLASS; } + YY_BREAK +case 22: +YY_RULE_SETUP +#line 150 "conf_lexer.l" +{ return T_CLUSTER; } + YY_BREAK +case 23: +YY_RULE_SETUP +#line 151 "conf_lexer.l" +{ return CONNECT; } + YY_BREAK +case 24: +YY_RULE_SETUP +#line 152 "conf_lexer.l" +{ return CONNECTFREQ; } + YY_BREAK +case 25: +YY_RULE_SETUP +#line 153 "conf_lexer.l" +{ return DEFAULT_FLOODCOUNT; } + YY_BREAK +case 26: +YY_RULE_SETUP +#line 154 "conf_lexer.l" +{ return DEFAULT_SPLIT_SERVER_COUNT; } + YY_BREAK +case 27: +YY_RULE_SETUP +#line 155 "conf_lexer.l" +{ return DEFAULT_SPLIT_USER_COUNT; } + YY_BREAK +case 28: +YY_RULE_SETUP +#line 156 "conf_lexer.l" +{ return DENY; } + YY_BREAK +case 29: +YY_RULE_SETUP +#line 157 "conf_lexer.l" +{ return DESCRIPTION; } + YY_BREAK +case 30: +YY_RULE_SETUP +#line 158 "conf_lexer.l" +{ return DIE; } + YY_BREAK +case 31: +YY_RULE_SETUP +#line 159 "conf_lexer.l" +{ return DISABLE_AUTH; } + YY_BREAK +case 32: +YY_RULE_SETUP +#line 160 "conf_lexer.l" +{ return DISABLE_FAKE_CHANNELS; } + YY_BREAK +case 33: +YY_RULE_SETUP +#line 161 "conf_lexer.l" +{ return DISABLE_REMOTE_COMMANDS; } + YY_BREAK +case 34: +YY_RULE_SETUP +#line 162 "conf_lexer.l" +{ return T_DLINE; } + YY_BREAK +case 35: +YY_RULE_SETUP +#line 163 "conf_lexer.l" +{ return DOTS_IN_IDENT; } + YY_BREAK +case 36: +YY_RULE_SETUP +#line 164 "conf_lexer.l" +{ return EGDPOOL_PATH; } + YY_BREAK +case 37: +YY_RULE_SETUP +#line 165 "conf_lexer.l" +{ return EMAIL; } + YY_BREAK +case 38: +YY_RULE_SETUP +#line 166 "conf_lexer.l" +{ return ENCRYPTED; } + YY_BREAK +case 39: +YY_RULE_SETUP +#line 167 "conf_lexer.l" +{ return EXCEED_LIMIT; } + YY_BREAK +case 40: +YY_RULE_SETUP +#line 168 "conf_lexer.l" +{ return EXEMPT; } + YY_BREAK +case 41: +YY_RULE_SETUP +#line 169 "conf_lexer.l" +{ return T_FILE; } + YY_BREAK +case 42: +YY_RULE_SETUP +#line 170 "conf_lexer.l" +{ return IRCD_FLAGS; } + YY_BREAK +case 43: +YY_RULE_SETUP +#line 171 "conf_lexer.l" +{ return FLATTEN_LINKS; } + YY_BREAK +case 44: +YY_RULE_SETUP +#line 172 "conf_lexer.l" +{ return GECOS; } + YY_BREAK +case 45: +YY_RULE_SETUP +#line 173 "conf_lexer.l" +{ return GENERAL; } + YY_BREAK +case 46: +YY_RULE_SETUP +#line 174 "conf_lexer.l" +{ return GLINE; } + YY_BREAK +case 47: +YY_RULE_SETUP +#line 175 "conf_lexer.l" +{ return GLINE_ENABLE; } + YY_BREAK +case 48: +YY_RULE_SETUP +#line 176 "conf_lexer.l" +{ return GLINE_EXEMPT; } + YY_BREAK +case 49: +YY_RULE_SETUP +#line 177 "conf_lexer.l" +{ return GLINE_DURATION; } + YY_BREAK +case 50: +YY_RULE_SETUP +#line 178 "conf_lexer.l" +{ return GLINE_REQUEST_DURATION; } + YY_BREAK +case 51: +YY_RULE_SETUP +#line 179 "conf_lexer.l" +{ return GLINE_MIN_CIDR; } + YY_BREAK +case 52: +YY_RULE_SETUP +#line 180 "conf_lexer.l" +{ return GLINE_MIN_CIDR6; } + YY_BREAK +case 53: +YY_RULE_SETUP +#line 181 "conf_lexer.l" +{ return T_GLOBOPS; } + YY_BREAK +case 54: +YY_RULE_SETUP +#line 182 "conf_lexer.l" +{ return GLOBAL_KILL; } + YY_BREAK +case 55: +YY_RULE_SETUP +#line 183 "conf_lexer.l" +{ return NEED_IDENT; } + YY_BREAK +case 56: +YY_RULE_SETUP +#line 184 "conf_lexer.l" +{ return NEED_IDENT; } + YY_BREAK +case 57: +YY_RULE_SETUP +#line 185 "conf_lexer.l" +{ return HAVENT_READ_CONF; } + YY_BREAK +case 58: +YY_RULE_SETUP +#line 186 "conf_lexer.l" +{ return HIDDEN; } + YY_BREAK +case 59: +YY_RULE_SETUP +#line 187 "conf_lexer.l" +{ return HIDDEN_NAME; } + YY_BREAK +case 60: +YY_RULE_SETUP +#line 188 "conf_lexer.l" +{ return HIDE_SERVER_IPS; } + YY_BREAK +case 61: +YY_RULE_SETUP +#line 189 "conf_lexer.l" +{ return HIDE_SERVERS; } + YY_BREAK +case 62: +YY_RULE_SETUP +#line 190 "conf_lexer.l" +{ return HIDE_SPOOF_IPS; } + YY_BREAK +case 63: +YY_RULE_SETUP +#line 191 "conf_lexer.l" +{ return HOST; } + YY_BREAK +case 64: +YY_RULE_SETUP +#line 192 "conf_lexer.l" +{ return HUB; } + YY_BREAK +case 65: +YY_RULE_SETUP +#line 193 "conf_lexer.l" +{ return HUB_MASK; } + YY_BREAK +case 66: +YY_RULE_SETUP +#line 194 "conf_lexer.l" +{ return IGNORE_BOGUS_TS; } + YY_BREAK +case 67: +YY_RULE_SETUP +#line 195 "conf_lexer.l" +{ return INVISIBLE_ON_CONNECT; } + YY_BREAK +case 68: +YY_RULE_SETUP +#line 196 "conf_lexer.l" +{ return IP; } + YY_BREAK +case 69: +YY_RULE_SETUP +#line 197 "conf_lexer.l" +{ return T_IPV4; } + YY_BREAK +case 70: +YY_RULE_SETUP +#line 198 "conf_lexer.l" +{ return T_IPV6; } + YY_BREAK +case 71: +YY_RULE_SETUP +#line 199 "conf_lexer.l" +{ return JOIN_FLOOD_COUNT; } + YY_BREAK +case 72: +YY_RULE_SETUP +#line 200 "conf_lexer.l" +{ return JOIN_FLOOD_TIME; } + YY_BREAK +case 73: +YY_RULE_SETUP +#line 201 "conf_lexer.l" +{ return KILL; } + YY_BREAK +case 74: +YY_RULE_SETUP +#line 202 "conf_lexer.l" +{ return KILL_CHASE_TIME_LIMIT; } + YY_BREAK +case 75: +YY_RULE_SETUP +#line 203 "conf_lexer.l" +{ return KLINE; } + YY_BREAK +case 76: +YY_RULE_SETUP +#line 204 "conf_lexer.l" +{ return KLINE_EXEMPT; } + YY_BREAK +case 77: +YY_RULE_SETUP +#line 205 "conf_lexer.l" +{ return LEAF_MASK; } + YY_BREAK +case 78: +YY_RULE_SETUP +#line 206 "conf_lexer.l" +{ return LISTEN; } + YY_BREAK +case 79: +YY_RULE_SETUP +#line 207 "conf_lexer.l" +{ return T_LOG; } + YY_BREAK +case 80: +YY_RULE_SETUP +#line 208 "conf_lexer.l" +{ return TMASKED; } + YY_BREAK +case 81: +YY_RULE_SETUP +#line 209 "conf_lexer.l" +{ return T_MAX_CLIENTS; } + YY_BREAK +case 82: +YY_RULE_SETUP +#line 210 "conf_lexer.l" +{ return MAX_IDENT; } + YY_BREAK +case 83: +YY_RULE_SETUP +#line 211 "conf_lexer.l" +{ return MAX_LOCAL; } + YY_BREAK +case 84: +YY_RULE_SETUP +#line 212 "conf_lexer.l" +{ return MAX_GLOBAL; } + YY_BREAK +case 85: +YY_RULE_SETUP +#line 213 "conf_lexer.l" +{ return MAX_NUMBER; } + YY_BREAK +case 86: +YY_RULE_SETUP +#line 214 "conf_lexer.l" +{ return MAX_WATCH; } + YY_BREAK +case 87: +YY_RULE_SETUP +#line 215 "conf_lexer.l" +{ return MESSAGE_LOCALE; } + YY_BREAK +case 88: +YY_RULE_SETUP +#line 216 "conf_lexer.l" +{ return MIN_NONWILDCARD; } + YY_BREAK +case 89: +YY_RULE_SETUP +#line 217 "conf_lexer.l" +{ return MIN_NONWILDCARD_SIMPLE; } + YY_BREAK +case 90: +YY_RULE_SETUP +#line 218 "conf_lexer.l" +{ return NAME; } + YY_BREAK +case 91: +YY_RULE_SETUP +#line 219 "conf_lexer.l" +{ return NEED_PASSWORD; } + YY_BREAK +case 92: +YY_RULE_SETUP +#line 220 "conf_lexer.l" +{ return NETWORK_DESC; } + YY_BREAK +case 93: +YY_RULE_SETUP +#line 221 "conf_lexer.l" +{ return NETWORK_NAME; } + YY_BREAK +case 94: +YY_RULE_SETUP +#line 222 "conf_lexer.l" +{ return NICK; } + YY_BREAK +case 95: +YY_RULE_SETUP +#line 223 "conf_lexer.l" +{ return NICK_CHANGES; } + YY_BREAK +case 96: +YY_RULE_SETUP +#line 224 "conf_lexer.l" +{ yylval.number = 0; return TBOOL; } + YY_BREAK +case 97: +YY_RULE_SETUP +#line 225 "conf_lexer.l" +{ return NO_CREATE_ON_SPLIT; } + YY_BREAK +case 98: +YY_RULE_SETUP +#line 226 "conf_lexer.l" +{ return NO_JOIN_ON_SPLIT; } + YY_BREAK +case 99: +YY_RULE_SETUP +#line 227 "conf_lexer.l" +{ return NO_OPER_FLOOD; } + YY_BREAK +case 100: +YY_RULE_SETUP +#line 228 "conf_lexer.l" +{ return NO_TILDE; } + YY_BREAK +case 101: +YY_RULE_SETUP +#line 229 "conf_lexer.l" +{ return NUMBER_PER_CIDR; } + YY_BREAK +case 102: +YY_RULE_SETUP +#line 230 "conf_lexer.l" +{ return NUMBER_PER_IP; } + YY_BREAK +case 103: +YY_RULE_SETUP +#line 231 "conf_lexer.l" +{ return OPERATOR; } + YY_BREAK +case 104: +YY_RULE_SETUP +#line 232 "conf_lexer.l" +{ return OPER_PASS_RESV; } + YY_BREAK +case 105: +YY_RULE_SETUP +#line 233 "conf_lexer.l" +{ return OPERATOR; } + YY_BREAK +case 106: +YY_RULE_SETUP +#line 234 "conf_lexer.l" +{ return PASSWORD; } + YY_BREAK +case 107: +YY_RULE_SETUP +#line 235 "conf_lexer.l" +{ return PASSWORD; } + YY_BREAK +case 108: +YY_RULE_SETUP +#line 236 "conf_lexer.l" +{ return PING_COOKIE; } + YY_BREAK +case 109: +YY_RULE_SETUP +#line 237 "conf_lexer.l" +{ return PING_TIME; } + YY_BREAK +case 110: +YY_RULE_SETUP +#line 238 "conf_lexer.l" +{ return PING_WARNING; } + YY_BREAK +case 111: +YY_RULE_SETUP +#line 239 "conf_lexer.l" +{ return PORT; } + YY_BREAK +case 112: +YY_RULE_SETUP +#line 240 "conf_lexer.l" +{ return RESV; } + YY_BREAK +case 113: +YY_RULE_SETUP +#line 241 "conf_lexer.l" +{ return QUIET_ON_BAN; } + YY_BREAK +case 114: +YY_RULE_SETUP +#line 242 "conf_lexer.l" +{ return REASON; } + YY_BREAK +case 115: +YY_RULE_SETUP +#line 243 "conf_lexer.l" +{ return T_RECVQ; } + YY_BREAK +case 116: +YY_RULE_SETUP +#line 244 "conf_lexer.l" +{ return REDIRPORT; } + YY_BREAK +case 117: +YY_RULE_SETUP +#line 245 "conf_lexer.l" +{ return REDIRSERV; } + YY_BREAK +case 118: +YY_RULE_SETUP +#line 246 "conf_lexer.l" +{ return REGEX_T; } + YY_BREAK +case 119: +YY_RULE_SETUP +#line 247 "conf_lexer.l" +{ return REHASH; } + YY_BREAK +case 120: +YY_RULE_SETUP +#line 248 "conf_lexer.l" +{ return REMOTE; } + YY_BREAK +case 121: +YY_RULE_SETUP +#line 249 "conf_lexer.l" +{ return REMOTEBAN; } + YY_BREAK +case 122: +YY_RULE_SETUP +#line 250 "conf_lexer.l" +{ return T_RESTART; } + YY_BREAK +case 123: +YY_RULE_SETUP +#line 251 "conf_lexer.l" +{ return RESTRICT_CHANNELS; } + YY_BREAK +case 124: +YY_RULE_SETUP +#line 252 "conf_lexer.l" +{ return RESV; } + YY_BREAK +case 125: +YY_RULE_SETUP +#line 253 "conf_lexer.l" +{ return RESV_EXEMPT; } + YY_BREAK +case 126: +YY_RULE_SETUP +#line 254 "conf_lexer.l" +{ return RSA_PRIVATE_KEY_FILE; } + YY_BREAK +case 127: +YY_RULE_SETUP +#line 255 "conf_lexer.l" +{ return RSA_PUBLIC_KEY_FILE; } + YY_BREAK +case 128: +YY_RULE_SETUP +#line 256 "conf_lexer.l" +{ return T_SSL; } + YY_BREAK +case 129: +YY_RULE_SETUP +#line 257 "conf_lexer.l" +{ return SSL_CERTIFICATE_FILE; } + YY_BREAK +case 130: +YY_RULE_SETUP +#line 258 "conf_lexer.l" +{ return T_SSL_CLIENT_METHOD; } + YY_BREAK +case 131: +YY_RULE_SETUP +#line 259 "conf_lexer.l" +{ return T_SSL_SERVER_METHOD; } + YY_BREAK +case 132: +YY_RULE_SETUP +#line 260 "conf_lexer.l" +{ return SSL_DH_PARAM_FILE; } + YY_BREAK +case 133: +YY_RULE_SETUP +#line 261 "conf_lexer.l" +{ return T_SSL_CIPHER_LIST; } + YY_BREAK +case 134: +YY_RULE_SETUP +#line 262 "conf_lexer.l" +{ return T_SSLV3; } + YY_BREAK +case 135: +YY_RULE_SETUP +#line 263 "conf_lexer.l" +{ return T_TLSV1; } + YY_BREAK +case 136: +YY_RULE_SETUP +#line 264 "conf_lexer.l" +{ return SEND_PASSWORD; } + YY_BREAK +case 137: +YY_RULE_SETUP +#line 265 "conf_lexer.l" +{ return SENDQ; } + YY_BREAK +case 138: +YY_RULE_SETUP +#line 266 "conf_lexer.l" +{ return T_SERVER; } + YY_BREAK +case 139: +YY_RULE_SETUP +#line 267 "conf_lexer.l" +{ return SERVERHIDE; } + YY_BREAK +case 140: +YY_RULE_SETUP +#line 268 "conf_lexer.l" +{ return SERVERINFO; } + YY_BREAK +case 141: +YY_RULE_SETUP +#line 269 "conf_lexer.l" +{ return T_SERVICE; } + YY_BREAK +case 142: +YY_RULE_SETUP +#line 270 "conf_lexer.l" +{ return T_SERVICES_NAME; } + YY_BREAK +case 143: +YY_RULE_SETUP +#line 271 "conf_lexer.l" +{ return T_SET; } + YY_BREAK +case 144: +YY_RULE_SETUP +#line 272 "conf_lexer.l" +{ return T_SHARED; } + YY_BREAK +case 145: +YY_RULE_SETUP +#line 273 "conf_lexer.l" +{ return SHORT_MOTD; } + YY_BREAK +case 146: +YY_RULE_SETUP +#line 274 "conf_lexer.l" +{ return IRCD_SID; } + YY_BREAK +case 147: +YY_RULE_SETUP +#line 275 "conf_lexer.l" +{ return T_SIZE; } + YY_BREAK +case 148: +YY_RULE_SETUP +#line 276 "conf_lexer.l" +{ return SPOOF; } + YY_BREAK +case 149: +YY_RULE_SETUP +#line 277 "conf_lexer.l" +{ return SPOOF_NOTICE; } + YY_BREAK +case 150: +YY_RULE_SETUP +#line 278 "conf_lexer.l" +{ return TKLINE_EXPIRE_NOTICES; } + YY_BREAK +case 151: +YY_RULE_SETUP +#line 279 "conf_lexer.l" +{ return TYPE; } + YY_BREAK +case 152: +YY_RULE_SETUP +#line 280 "conf_lexer.l" +{ return TRUE_NO_OPER_FLOOD; } + YY_BREAK +case 153: +YY_RULE_SETUP +#line 281 "conf_lexer.l" +{ return T_UMODES; } + YY_BREAK +case 154: +YY_RULE_SETUP +#line 282 "conf_lexer.l" +{ return UNKLINE; } + YY_BREAK +case 155: +YY_RULE_SETUP +#line 283 "conf_lexer.l" +{ return T_UNDLINE; } + YY_BREAK +case 156: +YY_RULE_SETUP +#line 284 "conf_lexer.l" +{ return T_UNLIMITED; } + YY_BREAK +case 157: +YY_RULE_SETUP +#line 285 "conf_lexer.l" +{ return USE_EGD; } + YY_BREAK +case 158: +YY_RULE_SETUP +#line 286 "conf_lexer.l" +{ return USE_LOGGING; } + YY_BREAK +case 159: +YY_RULE_SETUP +#line 287 "conf_lexer.l" +{ return THROTTLE_TIME; } + YY_BREAK +case 160: +YY_RULE_SETUP +#line 288 "conf_lexer.l" +{ return USER; } + YY_BREAK +case 161: +YY_RULE_SETUP +#line 289 "conf_lexer.l" +{ return VHOST; } + YY_BREAK +case 162: +YY_RULE_SETUP +#line 290 "conf_lexer.l" +{ return VHOST6; } + YY_BREAK +case 163: +YY_RULE_SETUP +#line 291 "conf_lexer.l" +{ return XLINE; } + YY_BREAK +case 164: +YY_RULE_SETUP +#line 292 "conf_lexer.l" +{ yylval.number = 1; return TBOOL; } + YY_BREAK +case 165: +YY_RULE_SETUP +#line 294 "conf_lexer.l" +{ return FAILED_OPER_NOTICE; } + YY_BREAK +case 166: +YY_RULE_SETUP +#line 295 "conf_lexer.l" +{ return MAX_ACCEPT; } + YY_BREAK +case 167: +YY_RULE_SETUP +#line 296 "conf_lexer.l" +{ return MAX_NICK_CHANGES; } + YY_BREAK +case 168: +YY_RULE_SETUP +#line 297 "conf_lexer.l" +{ return MAX_CHANS_PER_OPER; } + YY_BREAK +case 169: +YY_RULE_SETUP +#line 298 "conf_lexer.l" +{ return MAX_CHANS_PER_USER; } + YY_BREAK +case 170: +YY_RULE_SETUP +#line 299 "conf_lexer.l" +{ return MAX_NICK_TIME; } + YY_BREAK +case 171: +YY_RULE_SETUP +#line 300 "conf_lexer.l" +{ return ANTI_NICK_FLOOD; } + YY_BREAK +case 172: +YY_RULE_SETUP +#line 301 "conf_lexer.l" +{ return ANTI_SPAM_EXIT_MESSAGE_TIME; } + YY_BREAK +case 173: +YY_RULE_SETUP +#line 302 "conf_lexer.l" +{ return TS_MAX_DELTA; } + YY_BREAK +case 174: +YY_RULE_SETUP +#line 303 "conf_lexer.l" +{ return TS_WARN_DELTA; } + YY_BREAK +case 175: +YY_RULE_SETUP +#line 304 "conf_lexer.l" +{ return LINKS_DELAY; } + YY_BREAK +case 176: +YY_RULE_SETUP +#line 305 "conf_lexer.l" +{ return WARN_NO_NLINE; } + YY_BREAK +case 177: +YY_RULE_SETUP +#line 307 "conf_lexer.l" +{ return STATS_E_DISABLED; } + YY_BREAK +case 178: +YY_RULE_SETUP +#line 308 "conf_lexer.l" +{ return STATS_O_OPER_ONLY; } + YY_BREAK +case 179: +YY_RULE_SETUP +#line 309 "conf_lexer.l" +{ return STATS_K_OPER_ONLY; } + YY_BREAK +case 180: +YY_RULE_SETUP +#line 310 "conf_lexer.l" +{ return STATS_I_OPER_ONLY; } + YY_BREAK +case 181: +YY_RULE_SETUP +#line 311 "conf_lexer.l" +{ return STATS_P_OPER_ONLY; } + YY_BREAK +case 182: +YY_RULE_SETUP +#line 312 "conf_lexer.l" +{ return PACE_WAIT; } + YY_BREAK +case 183: +YY_RULE_SETUP +#line 313 "conf_lexer.l" +{ return PACE_WAIT_SIMPLE; } + YY_BREAK +case 184: +YY_RULE_SETUP +#line 314 "conf_lexer.l" +{ return KNOCK_DELAY; } + YY_BREAK +case 185: +YY_RULE_SETUP +#line 315 "conf_lexer.l" +{ return KNOCK_DELAY_CHANNEL; } + YY_BREAK +case 186: +YY_RULE_SETUP +#line 316 "conf_lexer.l" +{ return MAX_BANS; } + YY_BREAK +case 187: +YY_RULE_SETUP +#line 317 "conf_lexer.l" +{ return MODULES; } + YY_BREAK +case 188: +YY_RULE_SETUP +#line 318 "conf_lexer.l" +{ return MODULE; } + YY_BREAK +case 189: +YY_RULE_SETUP +#line 319 "conf_lexer.l" +{ return PATH; } + YY_BREAK +case 190: +YY_RULE_SETUP +#line 320 "conf_lexer.l" +{ return MAX_TARGETS; } + YY_BREAK +case 191: +YY_RULE_SETUP +#line 322 "conf_lexer.l" +{ return T_UNXLINE; } + YY_BREAK +case 192: +YY_RULE_SETUP +#line 323 "conf_lexer.l" +{ return T_UNRESV; } + YY_BREAK +case 193: +YY_RULE_SETUP +#line 325 "conf_lexer.l" +{ return OPER_ONLY_UMODES; } + YY_BREAK +case 194: +YY_RULE_SETUP +#line 326 "conf_lexer.l" +{ return OPER_UMODES; } + YY_BREAK +case 195: +YY_RULE_SETUP +#line 327 "conf_lexer.l" +{ return T_BOTS; } + YY_BREAK +case 196: +YY_RULE_SETUP +#line 328 "conf_lexer.l" +{ return T_CCONN; } + YY_BREAK +case 197: +YY_RULE_SETUP +#line 329 "conf_lexer.l" +{ return T_CCONN_FULL; } + YY_BREAK +case 198: +YY_RULE_SETUP +#line 330 "conf_lexer.l" +{ return T_DEAF; } + YY_BREAK +case 199: +YY_RULE_SETUP +#line 331 "conf_lexer.l" +{ return T_DEBUG; } + YY_BREAK +case 200: +YY_RULE_SETUP +#line 332 "conf_lexer.l" +{ return T_FULL; } + YY_BREAK +case 201: +YY_RULE_SETUP +#line 333 "conf_lexer.l" +{ return T_SKILL; } + YY_BREAK +case 202: +YY_RULE_SETUP +#line 334 "conf_lexer.l" +{ return T_NCHANGE; } + YY_BREAK +case 203: +YY_RULE_SETUP +#line 335 "conf_lexer.l" +{ return T_REJ; } + YY_BREAK +case 204: +YY_RULE_SETUP +#line 336 "conf_lexer.l" +{ return T_UNAUTH; } + YY_BREAK +case 205: +YY_RULE_SETUP +#line 337 "conf_lexer.l" +{ return T_SPY; } + YY_BREAK +case 206: +YY_RULE_SETUP +#line 338 "conf_lexer.l" +{ return T_EXTERNAL; } + YY_BREAK +case 207: +YY_RULE_SETUP +#line 339 "conf_lexer.l" +{ return T_OPERWALL; } + YY_BREAK +case 208: +YY_RULE_SETUP +#line 340 "conf_lexer.l" +{ return T_SERVNOTICE; } + YY_BREAK +case 209: +YY_RULE_SETUP +#line 341 "conf_lexer.l" +{ return T_INVISIBLE; } + YY_BREAK +case 210: +YY_RULE_SETUP +#line 342 "conf_lexer.l" +{ return T_WALLOP; } + YY_BREAK +case 211: +YY_RULE_SETUP +#line 343 "conf_lexer.l" +{ return T_CALLERID; } + YY_BREAK +case 212: +YY_RULE_SETUP +#line 344 "conf_lexer.l" +{ return T_SOFTCALLERID; } + YY_BREAK +case 213: +YY_RULE_SETUP +#line 345 "conf_lexer.l" +{ return T_LOCOPS; } + YY_BREAK +case 214: +YY_RULE_SETUP +#line 347 "conf_lexer.l" +{ return WEEKS; } + YY_BREAK +case 215: +YY_RULE_SETUP +#line 348 "conf_lexer.l" +{ return WEEKS; } + YY_BREAK +case 216: +YY_RULE_SETUP +#line 349 "conf_lexer.l" +{ return DAYS; } + YY_BREAK +case 217: +YY_RULE_SETUP +#line 350 "conf_lexer.l" +{ return DAYS; } + YY_BREAK +case 218: +YY_RULE_SETUP +#line 351 "conf_lexer.l" +{ return HOURS; } + YY_BREAK +case 219: +YY_RULE_SETUP +#line 352 "conf_lexer.l" +{ return HOURS; } + YY_BREAK +case 220: +YY_RULE_SETUP +#line 353 "conf_lexer.l" +{ return MINUTES; } + YY_BREAK +case 221: +YY_RULE_SETUP +#line 354 "conf_lexer.l" +{ return MINUTES; } + YY_BREAK +case 222: +YY_RULE_SETUP +#line 355 "conf_lexer.l" +{ return SECONDS; } + YY_BREAK +case 223: +YY_RULE_SETUP +#line 356 "conf_lexer.l" +{ return SECONDS; } + YY_BREAK +case 224: +YY_RULE_SETUP +#line 358 "conf_lexer.l" +{ return BYTES; } + YY_BREAK +case 225: +YY_RULE_SETUP +#line 359 "conf_lexer.l" +{ return BYTES; } + YY_BREAK +case 226: +YY_RULE_SETUP +#line 360 "conf_lexer.l" +{ return KBYTES; } + YY_BREAK +case 227: +YY_RULE_SETUP +#line 361 "conf_lexer.l" +{ return KBYTES; } + YY_BREAK +case 228: +YY_RULE_SETUP +#line 362 "conf_lexer.l" +{ return KBYTES; } + YY_BREAK +case 229: +YY_RULE_SETUP +#line 363 "conf_lexer.l" +{ return KBYTES; } + YY_BREAK +case 230: +YY_RULE_SETUP +#line 364 "conf_lexer.l" +{ return KBYTES; } + YY_BREAK +case 231: +YY_RULE_SETUP +#line 365 "conf_lexer.l" +{ return MBYTES; } + YY_BREAK +case 232: +YY_RULE_SETUP +#line 366 "conf_lexer.l" +{ return MBYTES; } + YY_BREAK +case 233: +YY_RULE_SETUP +#line 367 "conf_lexer.l" +{ return MBYTES; } + YY_BREAK +case 234: +YY_RULE_SETUP +#line 368 "conf_lexer.l" +{ return MBYTES; } + YY_BREAK +case 235: +YY_RULE_SETUP +#line 369 "conf_lexer.l" +{ return MBYTES; } + YY_BREAK +case 236: +YY_RULE_SETUP +#line 370 "conf_lexer.l" +{ return TWODOTS; } + YY_BREAK +case 237: +YY_RULE_SETUP +#line 372 "conf_lexer.l" +{ return yytext[0]; } + YY_BREAK +case YY_STATE_EOF(INITIAL): +#line 373 "conf_lexer.l" +{ if (ieof()) yyterminate(); } + YY_BREAK +case 238: +YY_RULE_SETUP +#line 375 "conf_lexer.l" +ECHO; + YY_BREAK +#line 3206 "conf_lexer.c" + + case YY_END_OF_BUFFER: + { + /* Amount of text matched not including the EOB char. */ + int yy_amount_of_matched_text = (int) (yy_cp - (yytext_ptr)) - 1; + + /* Undo the effects of YY_DO_BEFORE_ACTION. */ + *yy_cp = (yy_hold_char); + YY_RESTORE_YY_MORE_OFFSET + + if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW ) + { + /* We're scanning a new file or input source. It's + * possible that this happened because the user + * just pointed yyin at a new source and called + * yylex(). If so, then we have to assure + * consistency between YY_CURRENT_BUFFER and our + * globals. Here is the right place to do so, because + * this is the first action (other than possibly a + * back-up) that will match for the new input source. + */ + (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; + YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin; + YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL; + } + + /* Note that here we test for yy_c_buf_p "<=" to the position + * of the first EOB in the buffer, since yy_c_buf_p will + * already have been incremented past the NUL character + * (since all states make transitions on EOB to the + * end-of-buffer state). Contrast this with the test + * in input(). + */ + if ( (yy_c_buf_p) <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] ) + { /* This was really a NUL. */ + yy_state_type yy_next_state; + + (yy_c_buf_p) = (yytext_ptr) + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state( ); + + /* Okay, we're now positioned to make the NUL + * transition. We couldn't have + * yy_get_previous_state() go ahead and do it + * for us because it doesn't know how to deal + * with the possibility of jamming (and we don't + * want to build jamming into it because then it + * will run more slowly). + */ + + yy_next_state = yy_try_NUL_trans( yy_current_state ); + + yy_bp = (yytext_ptr) + YY_MORE_ADJ; + + if ( yy_next_state ) + { + /* Consume the NUL. */ + yy_cp = ++(yy_c_buf_p); + yy_current_state = yy_next_state; + goto yy_match; + } + + else + { + yy_cp = (yy_last_accepting_cpos); + yy_current_state = (yy_last_accepting_state); + goto yy_find_action; + } + } + + else switch ( yy_get_next_buffer( ) ) + { + case EOB_ACT_END_OF_FILE: + { + (yy_did_buffer_switch_on_eof) = 0; + + if ( yywrap( ) ) + { + /* Note: because we've taken care in + * yy_get_next_buffer() to have set up + * yytext, we can now set up + * yy_c_buf_p so that if some total + * hoser (like flex itself) wants to + * call the scanner after we return the + * YY_NULL, it'll still work - another + * YY_NULL will get returned. + */ + (yy_c_buf_p) = (yytext_ptr) + YY_MORE_ADJ; + + yy_act = YY_STATE_EOF(YY_START); + goto do_action; + } + + else + { + if ( ! (yy_did_buffer_switch_on_eof) ) + YY_NEW_FILE; + } + break; + } + + case EOB_ACT_CONTINUE_SCAN: + (yy_c_buf_p) = + (yytext_ptr) + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state( ); + + yy_cp = (yy_c_buf_p); + yy_bp = (yytext_ptr) + YY_MORE_ADJ; + goto yy_match; + + case EOB_ACT_LAST_MATCH: + (yy_c_buf_p) = + &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)]; + + yy_current_state = yy_get_previous_state( ); + + yy_cp = (yy_c_buf_p); + yy_bp = (yytext_ptr) + YY_MORE_ADJ; + goto yy_find_action; + } + break; + } + + default: + YY_FATAL_ERROR( + "fatal flex scanner internal error--no action found" ); + } /* end of action switch */ + } /* end of scanning one token */ +} /* end of yylex */ + +/* yy_get_next_buffer - try to read in a new buffer + * + * Returns a code representing an action: + * EOB_ACT_LAST_MATCH - + * EOB_ACT_CONTINUE_SCAN - continue scanning from current position + * EOB_ACT_END_OF_FILE - end of file + */ +static int yy_get_next_buffer (void) +{ + register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf; + register char *source = (yytext_ptr); + register int number_to_move, i; + int ret_val; + + if ( (yy_c_buf_p) > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] ) + YY_FATAL_ERROR( + "fatal flex scanner internal error--end of buffer missed" ); + + if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 ) + { /* Don't try to fill the buffer, so this is an EOF. */ + if ( (yy_c_buf_p) - (yytext_ptr) - YY_MORE_ADJ == 1 ) + { + /* We matched a single character, the EOB, so + * treat this as a final EOF. + */ + return EOB_ACT_END_OF_FILE; + } + + else + { + /* We matched some text prior to the EOB, first + * process it. + */ + return EOB_ACT_LAST_MATCH; + } + } + + /* Try to read more data. */ + + /* First move last chars to start of buffer. */ + number_to_move = (int) ((yy_c_buf_p) - (yytext_ptr)) - 1; + + for ( i = 0; i < number_to_move; ++i ) + *(dest++) = *(source++); + + if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING ) + /* don't do the read, it's not guaranteed to return an EOF, + * just force an EOF + */ + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars) = 0; + + else + { + yy_size_t num_to_read = + YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; + + while ( num_to_read <= 0 ) + { /* Not enough room in the buffer - grow it. */ + + /* just a shorter name for the current buffer */ + YY_BUFFER_STATE b = YY_CURRENT_BUFFER_LVALUE; + + int yy_c_buf_p_offset = + (int) ((yy_c_buf_p) - b->yy_ch_buf); + + if ( b->yy_is_our_buffer ) + { + yy_size_t new_size = b->yy_buf_size * 2; + + if ( new_size <= 0 ) + b->yy_buf_size += b->yy_buf_size / 8; + else + b->yy_buf_size *= 2; + + b->yy_ch_buf = (char *) + /* Include room in for 2 EOB chars. */ + yyrealloc((void *) b->yy_ch_buf,b->yy_buf_size + 2 ); + } + else + /* Can't grow it, we don't own it. */ + b->yy_ch_buf = 0; + + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( + "fatal error - scanner input buffer overflow" ); + + (yy_c_buf_p) = &b->yy_ch_buf[yy_c_buf_p_offset]; + + num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size - + number_to_move - 1; + + } + + if ( num_to_read > YY_READ_BUF_SIZE ) + num_to_read = YY_READ_BUF_SIZE; + + /* Read in more data. */ + YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]), + (yy_n_chars), num_to_read ); + + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); + } + + if ( (yy_n_chars) == 0 ) + { + if ( number_to_move == YY_MORE_ADJ ) + { + ret_val = EOB_ACT_END_OF_FILE; + yyrestart(yyin ); + } + + else + { + ret_val = EOB_ACT_LAST_MATCH; + YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = + YY_BUFFER_EOF_PENDING; + } + } + + else + ret_val = EOB_ACT_CONTINUE_SCAN; + + if ((yy_size_t) ((yy_n_chars) + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) { + /* Extend the array by 50%, plus the number we really need. */ + yy_size_t new_size = (yy_n_chars) + number_to_move + ((yy_n_chars) >> 1); + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) yyrealloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size ); + if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" ); + } + + (yy_n_chars) += number_to_move; + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] = YY_END_OF_BUFFER_CHAR; + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] = YY_END_OF_BUFFER_CHAR; + + (yytext_ptr) = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0]; + + return ret_val; +} + +/* yy_get_previous_state - get the state just before the EOB char was reached */ + + static yy_state_type yy_get_previous_state (void) +{ + register yy_state_type yy_current_state; + register char *yy_cp; + + yy_current_state = (yy_start); + + for ( yy_cp = (yytext_ptr) + YY_MORE_ADJ; yy_cp < (yy_c_buf_p); ++yy_cp ) + { + register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1); + if ( yy_accept[yy_current_state] ) + { + (yy_last_accepting_state) = yy_current_state; + (yy_last_accepting_cpos) = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 1546 ) + yy_c = yy_meta[(unsigned int) yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + } + + return yy_current_state; +} + +/* yy_try_NUL_trans - try to make a transition on the NUL character + * + * synopsis + * next_state = yy_try_NUL_trans( current_state ); + */ + static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state ) +{ + register int yy_is_jam; + register char *yy_cp = (yy_c_buf_p); + + register YY_CHAR yy_c = 1; + if ( yy_accept[yy_current_state] ) + { + (yy_last_accepting_state) = yy_current_state; + (yy_last_accepting_cpos) = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 1546 ) + yy_c = yy_meta[(unsigned int) yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + yy_is_jam = (yy_current_state == 1545); + + return yy_is_jam ? 0 : yy_current_state; +} + +#ifndef YY_NO_INPUT +#ifdef __cplusplus + static int yyinput (void) +#else + static int input (void) +#endif + +{ + int c; + + *(yy_c_buf_p) = (yy_hold_char); + + if ( *(yy_c_buf_p) == YY_END_OF_BUFFER_CHAR ) + { + /* yy_c_buf_p now points to the character we want to return. + * If this occurs *before* the EOB characters, then it's a + * valid NUL; if not, then we've hit the end of the buffer. + */ + if ( (yy_c_buf_p) < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] ) + /* This was really a NUL. */ + *(yy_c_buf_p) = '\0'; + + else + { /* need more input */ + yy_size_t offset = (yy_c_buf_p) - (yytext_ptr); + ++(yy_c_buf_p); + + switch ( yy_get_next_buffer( ) ) + { + case EOB_ACT_LAST_MATCH: + /* This happens because yy_g_n_b() + * sees that we've accumulated a + * token and flags that we need to + * try matching the token before + * proceeding. But for input(), + * there's no matching to consider. + * So convert the EOB_ACT_LAST_MATCH + * to EOB_ACT_END_OF_FILE. + */ + + /* Reset buffer status. */ + yyrestart(yyin ); + + /*FALLTHROUGH*/ + + case EOB_ACT_END_OF_FILE: + { + if ( yywrap( ) ) + return EOF; + + if ( ! (yy_did_buffer_switch_on_eof) ) + YY_NEW_FILE; +#ifdef __cplusplus + return yyinput(); +#else + return input(); +#endif + } + + case EOB_ACT_CONTINUE_SCAN: + (yy_c_buf_p) = (yytext_ptr) + offset; + break; + } + } + } + + c = *(unsigned char *) (yy_c_buf_p); /* cast for 8-bit char's */ + *(yy_c_buf_p) = '\0'; /* preserve yytext */ + (yy_hold_char) = *++(yy_c_buf_p); + + return c; +} +#endif /* ifndef YY_NO_INPUT */ + +/** Immediately switch to a different input stream. + * @param input_file A readable stream. + * + * @note This function does not reset the start condition to @c INITIAL . + */ + void yyrestart (FILE * input_file ) +{ + + if ( ! YY_CURRENT_BUFFER ){ + yyensure_buffer_stack (); + YY_CURRENT_BUFFER_LVALUE = + yy_create_buffer(yyin,YY_BUF_SIZE ); + } + + yy_init_buffer(YY_CURRENT_BUFFER,input_file ); + yy_load_buffer_state( ); +} + +/** Switch to a different input buffer. + * @param new_buffer The new input buffer. + * + */ + void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer ) +{ + + /* TODO. We should be able to replace this entire function body + * with + * yypop_buffer_state(); + * yypush_buffer_state(new_buffer); + */ + yyensure_buffer_stack (); + if ( YY_CURRENT_BUFFER == new_buffer ) + return; + + if ( YY_CURRENT_BUFFER ) + { + /* Flush out information for old buffer. */ + *(yy_c_buf_p) = (yy_hold_char); + YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p); + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); + } + + YY_CURRENT_BUFFER_LVALUE = new_buffer; + yy_load_buffer_state( ); + + /* We don't actually know whether we did this switch during + * EOF (yywrap()) processing, but the only time this flag + * is looked at is after yywrap() is called, so it's safe + * to go ahead and always set it. + */ + (yy_did_buffer_switch_on_eof) = 1; +} + +static void yy_load_buffer_state (void) +{ + (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; + (yytext_ptr) = (yy_c_buf_p) = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos; + yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file; + (yy_hold_char) = *(yy_c_buf_p); +} + +/** Allocate and initialize an input buffer state. + * @param file A readable stream. + * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE. + * + * @return the allocated buffer state. + */ + YY_BUFFER_STATE yy_create_buffer (FILE * file, int size ) +{ + YY_BUFFER_STATE b; + + b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state ) ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); + + b->yy_buf_size = size; + + /* yy_ch_buf has to be 2 characters longer than the size given because + * we need to put in 2 end-of-buffer characters. + */ + b->yy_ch_buf = (char *) yyalloc(b->yy_buf_size + 2 ); + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); + + b->yy_is_our_buffer = 1; + + yy_init_buffer(b,file ); + + return b; +} + +/** Destroy the buffer. + * @param b a buffer created with yy_create_buffer() + * + */ + void yy_delete_buffer (YY_BUFFER_STATE b ) +{ + + if ( ! b ) + return; + + if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */ + YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0; + + if ( b->yy_is_our_buffer ) + yyfree((void *) b->yy_ch_buf ); + + yyfree((void *) b ); +} + +/* Initializes or reinitializes a buffer. + * This function is sometimes called more than once on the same buffer, + * such as during a yyrestart() or at EOF. + */ + static void yy_init_buffer (YY_BUFFER_STATE b, FILE * file ) + +{ + int oerrno = errno; + + yy_flush_buffer(b ); + + b->yy_input_file = file; + b->yy_fill_buffer = 1; + + /* If b is the current buffer, then yy_init_buffer was _probably_ + * called from yyrestart() or through yy_get_next_buffer. + * In that case, we don't want to reset the lineno or column. + */ + if (b != YY_CURRENT_BUFFER){ + b->yy_bs_lineno = 1; + b->yy_bs_column = 0; + } + + b->yy_is_interactive = 0; + + errno = oerrno; +} + +/** Discard all buffered characters. On the next scan, YY_INPUT will be called. + * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER. + * + */ + void yy_flush_buffer (YY_BUFFER_STATE b ) +{ + if ( ! b ) + return; + + b->yy_n_chars = 0; + + /* We always need two end-of-buffer characters. The first causes + * a transition to the end-of-buffer state. The second causes + * a jam in that state. + */ + b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR; + b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR; + + b->yy_buf_pos = &b->yy_ch_buf[0]; + + b->yy_at_bol = 1; + b->yy_buffer_status = YY_BUFFER_NEW; + + if ( b == YY_CURRENT_BUFFER ) + yy_load_buffer_state( ); +} + +/** Pushes the new state onto the stack. The new state becomes + * the current state. This function will allocate the stack + * if necessary. + * @param new_buffer The new state. + * + */ +void yypush_buffer_state (YY_BUFFER_STATE new_buffer ) +{ + if (new_buffer == NULL) + return; + + yyensure_buffer_stack(); + + /* This block is copied from yy_switch_to_buffer. */ + if ( YY_CURRENT_BUFFER ) + { + /* Flush out information for old buffer. */ + *(yy_c_buf_p) = (yy_hold_char); + YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p); + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); + } + + /* Only push if top exists. Otherwise, replace top. */ + if (YY_CURRENT_BUFFER) + (yy_buffer_stack_top)++; + YY_CURRENT_BUFFER_LVALUE = new_buffer; + + /* copied from yy_switch_to_buffer. */ + yy_load_buffer_state( ); + (yy_did_buffer_switch_on_eof) = 1; +} + +/** Removes and deletes the top of the stack, if present. + * The next element becomes the new top. + * + */ +void yypop_buffer_state (void) +{ + if (!YY_CURRENT_BUFFER) + return; + + yy_delete_buffer(YY_CURRENT_BUFFER ); + YY_CURRENT_BUFFER_LVALUE = NULL; + if ((yy_buffer_stack_top) > 0) + --(yy_buffer_stack_top); + + if (YY_CURRENT_BUFFER) { + yy_load_buffer_state( ); + (yy_did_buffer_switch_on_eof) = 1; + } +} + +/* Allocates the stack if it does not exist. + * Guarantees space for at least one push. + */ +static void yyensure_buffer_stack (void) +{ + yy_size_t num_to_alloc; + + if (!(yy_buffer_stack)) { + + /* First allocation is just for 2 elements, since we don't know if this + * scanner will even need a stack. We use 2 instead of 1 to avoid an + * immediate realloc on the next call. + */ + num_to_alloc = 1; + (yy_buffer_stack) = (struct yy_buffer_state**)yyalloc + (num_to_alloc * sizeof(struct yy_buffer_state*) + ); + if ( ! (yy_buffer_stack) ) + YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" ); + + memset((yy_buffer_stack), 0, num_to_alloc * sizeof(struct yy_buffer_state*)); + + (yy_buffer_stack_max) = num_to_alloc; + (yy_buffer_stack_top) = 0; + return; + } + + if ((yy_buffer_stack_top) >= ((yy_buffer_stack_max)) - 1){ + + /* Increase the buffer to prepare for a possible push. */ + int grow_size = 8 /* arbitrary grow size */; + + num_to_alloc = (yy_buffer_stack_max) + grow_size; + (yy_buffer_stack) = (struct yy_buffer_state**)yyrealloc + ((yy_buffer_stack), + num_to_alloc * sizeof(struct yy_buffer_state*) + ); + if ( ! (yy_buffer_stack) ) + YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" ); + + /* zero only the new slots.*/ + memset((yy_buffer_stack) + (yy_buffer_stack_max), 0, grow_size * sizeof(struct yy_buffer_state*)); + (yy_buffer_stack_max) = num_to_alloc; + } +} + +/** Setup the input buffer state to scan directly from a user-specified character buffer. + * @param base the character buffer + * @param size the size in bytes of the character buffer + * + * @return the newly allocated buffer state object. + */ +YY_BUFFER_STATE yy_scan_buffer (char * base, yy_size_t size ) +{ + YY_BUFFER_STATE b; + + if ( size < 2 || + base[size-2] != YY_END_OF_BUFFER_CHAR || + base[size-1] != YY_END_OF_BUFFER_CHAR ) + /* They forgot to leave room for the EOB's. */ + return 0; + + b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state ) ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" ); + + b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */ + b->yy_buf_pos = b->yy_ch_buf = base; + b->yy_is_our_buffer = 0; + b->yy_input_file = 0; + b->yy_n_chars = b->yy_buf_size; + b->yy_is_interactive = 0; + b->yy_at_bol = 1; + b->yy_fill_buffer = 0; + b->yy_buffer_status = YY_BUFFER_NEW; + + yy_switch_to_buffer(b ); + + return b; +} + +/** Setup the input buffer state to scan a string. The next call to yylex() will + * scan from a @e copy of @a str. + * @param yystr a NUL-terminated string to scan + * + * @return the newly allocated buffer state object. + * @note If you want to scan bytes that may contain NUL values, then use + * yy_scan_bytes() instead. + */ +YY_BUFFER_STATE yy_scan_string (yyconst char * yystr ) +{ + + return yy_scan_bytes(yystr,strlen(yystr) ); +} + +/** Setup the input buffer state to scan the given bytes. The next call to yylex() will + * scan from a @e copy of @a bytes. + * @param yybytes the byte buffer to scan + * @param _yybytes_len the number of bytes in the buffer pointed to by @a bytes. + * + * @return the newly allocated buffer state object. + */ +YY_BUFFER_STATE yy_scan_bytes (yyconst char * yybytes, yy_size_t _yybytes_len ) +{ + YY_BUFFER_STATE b; + char *buf; + yy_size_t n; + int i; + + /* Get memory for full buffer, including space for trailing EOB's. */ + n = _yybytes_len + 2; + buf = (char *) yyalloc(n ); + if ( ! buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" ); + + for ( i = 0; i < _yybytes_len; ++i ) + buf[i] = yybytes[i]; + + buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR; + + b = yy_scan_buffer(buf,n ); + if ( ! b ) + YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" ); + + /* It's okay to grow etc. this buffer, and we should throw it + * away when we're done. + */ + b->yy_is_our_buffer = 1; + + return b; +} + +#ifndef YY_EXIT_FAILURE +#define YY_EXIT_FAILURE 2 +#endif + +static void yy_fatal_error (yyconst char* msg ) +{ + (void) fprintf( stderr, "%s\n", msg ); + exit( YY_EXIT_FAILURE ); +} + +/* Redefine yyless() so it works in section 3 code. */ + +#undef yyless +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up yytext. */ \ + int yyless_macro_arg = (n); \ + YY_LESS_LINENO(yyless_macro_arg);\ + yytext[yyleng] = (yy_hold_char); \ + (yy_c_buf_p) = yytext + yyless_macro_arg; \ + (yy_hold_char) = *(yy_c_buf_p); \ + *(yy_c_buf_p) = '\0'; \ + yyleng = yyless_macro_arg; \ + } \ + while ( 0 ) + +/* Accessor methods (get/set functions) to struct members. */ + +/** Get the current line number. + * + */ +int yyget_lineno (void) +{ + + return yylineno; +} + +/** Get the input stream. + * + */ +FILE *yyget_in (void) +{ + return yyin; +} + +/** Get the output stream. + * + */ +FILE *yyget_out (void) +{ + return yyout; +} + +/** Get the length of the current token. + * + */ +yy_size_t yyget_leng (void) +{ + return yyleng; +} + +/** Get the current token. + * + */ + +char *yyget_text (void) +{ + return yytext; +} + +/** Set the current line number. + * @param line_number + * + */ +void yyset_lineno (int line_number ) +{ + + yylineno = line_number; +} + +/** Set the input stream. This does not discard the current + * input buffer. + * @param in_str A readable stream. + * + * @see yy_switch_to_buffer + */ +void yyset_in (FILE * in_str ) +{ + yyin = in_str ; +} + +void yyset_out (FILE * out_str ) +{ + yyout = out_str ; +} + +int yyget_debug (void) +{ + return yy_flex_debug; +} + +void yyset_debug (int bdebug ) +{ + yy_flex_debug = bdebug ; +} + +static int yy_init_globals (void) +{ + /* Initialization is the same as for the non-reentrant scanner. + * This function is called from yylex_destroy(), so don't allocate here. + */ + + (yy_buffer_stack) = 0; + (yy_buffer_stack_top) = 0; + (yy_buffer_stack_max) = 0; + (yy_c_buf_p) = (char *) 0; + (yy_init) = 0; + (yy_start) = 0; + +/* Defined in main.c */ +#ifdef YY_STDINIT + yyin = stdin; + yyout = stdout; +#else + yyin = (FILE *) 0; + yyout = (FILE *) 0; +#endif + + /* For future reference: Set errno on error, since we are called by + * yylex_init() + */ + return 0; +} + +/* yylex_destroy is for both reentrant and non-reentrant scanners. */ +int yylex_destroy (void) +{ + + /* Pop the buffer stack, destroying each element. */ + while(YY_CURRENT_BUFFER){ + yy_delete_buffer(YY_CURRENT_BUFFER ); + YY_CURRENT_BUFFER_LVALUE = NULL; + yypop_buffer_state(); + } + + /* Destroy the stack itself. */ + yyfree((yy_buffer_stack) ); + (yy_buffer_stack) = NULL; + + /* Reset the globals. This is important in a non-reentrant scanner so the next time + * yylex() is called, initialization will occur. */ + yy_init_globals( ); + + return 0; +} + +/* + * Internal utility routines. + */ + +#ifndef yytext_ptr +static void yy_flex_strncpy (char* s1, yyconst char * s2, int n ) +{ + register int i; + for ( i = 0; i < n; ++i ) + s1[i] = s2[i]; +} +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen (yyconst char * s ) +{ + register int n; + for ( n = 0; s[n]; ++n ) + ; + + return n; +} +#endif + +void *yyalloc (yy_size_t size ) +{ + return (void *) malloc( size ); +} + +void *yyrealloc (void * ptr, yy_size_t size ) +{ + /* The cast to (char *) in the following accommodates both + * implementations that use char* generic pointers, and those + * that use void* generic pointers. It works with the latter + * because both ANSI C and C++ allow castless assignment from + * any pointer type to void*, and deal with argument conversions + * as though doing an assignment. + */ + return (void *) realloc( (char *) ptr, size ); +} + +void yyfree (void * ptr ) +{ + free( (char *) ptr ); /* see yyrealloc() for (char *) cast */ +} + +#define YYTABLES_NAME "yytables" + +#line 375 "conf_lexer.l" + + + +/* C-comment ignoring routine -kre*/ +static void +ccomment(void) +{ + int c = 0; + + /* log(L_NOTICE, "got comment"); */ + while (1) + { + while ((c = input()) != '*' && c != EOF) + if (c == '\n') + ++lineno; + + if (c == '*') + { + while ((c = input()) == '*') + /* Nothing */ ; + if (c == '/') + break; + else if (c == '\n') + ++lineno; + } + + if (c == EOF) + { + YY_FATAL_ERROR("EOF in comment"); + /* XXX hack alert this disables + * the stupid unused function warning + * gcc generates + */ + if (1 == 0) + yy_fatal_error("EOF in comment"); + break; + } + } +} + +/* C-style .includes. This function will properly swap input conf buffers, + * and lineno -kre */ +static void +cinclude(void) +{ + char *p = NULL; + + if ((p = strchr(yytext, '<')) == NULL) + *strchr(p = strchr(yytext, '"') + 1, '"') = '\0'; + else + *strchr(++p, '>') = '\0'; + + /* log(L_NOTICE, "got include %s!", c); */ + + /* do stacking and co. */ + if (include_stack_ptr >= MAX_INCLUDE_DEPTH) + ilog(LOG_TYPE_IRCD, "Includes nested too deep in %s", p); + else + { + FILE *tmp_fbfile_in = NULL; + char filenamebuf[IRCD_BUFSIZE]; + + if (*p == '/') /* if it is an absolute path */ + snprintf(filenamebuf, sizeof(filenamebuf), "%s", p); + else + snprintf(filenamebuf, sizeof(filenamebuf), "%s/%s", ETCPATH, p); + + tmp_fbfile_in = fopen(filenamebuf, "r"); + + if (tmp_fbfile_in == NULL) + { + ilog(LOG_TYPE_IRCD, "Unable to read configuration file '%s': %s", + filenamebuf, strerror(errno)); + return; + } + + lineno_stack[include_stack_ptr] = lineno; + lineno = 1; + inc_fbfile_in[include_stack_ptr] = conf_parser_ctx.conf_file; + strlcpy(conffile_stack[include_stack_ptr], conffilebuf, IRCD_BUFSIZE); + include_stack[include_stack_ptr++] = YY_CURRENT_BUFFER; + conf_parser_ctx.conf_file = tmp_fbfile_in; + snprintf(conffilebuf, sizeof(conffilebuf), "%s", filenamebuf); + yy_switch_to_buffer(yy_create_buffer(yyin,YY_BUF_SIZE)); + } +} + +/* This is function that will be called on EOF in conf file. It will + * apropriately close conf if it not main conf and swap input buffers -kre + * */ +static int +ieof(void) +{ + /* log(L_NOTICE, "return from include stack!"); */ + if (include_stack_ptr) + fclose(conf_parser_ctx.conf_file); + if (--include_stack_ptr < 0) + { + /* log(L_NOTICE, "terminating lexer"); */ + /* We will now exit the lexer - restore init values if we get /rehash + * later and reenter lexer -kre */ + include_stack_ptr = 0; + lineno = 1; + return 1; + } + + /* switch buffer */ + /* log(L_NOTICE, "deleting include_stack_ptr=%d", include_stack_ptr); */ + yy_delete_buffer(YY_CURRENT_BUFFER); + lineno = lineno_stack[include_stack_ptr]; + conf_parser_ctx.conf_file = inc_fbfile_in[include_stack_ptr]; + strlcpy(conffilebuf, conffile_stack[include_stack_ptr], sizeof(conffilebuf)); + yy_switch_to_buffer(include_stack[include_stack_ptr]); + + return 0; +} + diff --git a/src/conf_lexer.l b/src/conf_lexer.l new file mode 100644 index 0000000..d089a57 --- /dev/null +++ b/src/conf_lexer.l @@ -0,0 +1,489 @@ +/* + * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd). + * conf_lexer.l: Scans the ircd configuration file for tokens. + * + * Copyright (C) 2002 by the past and present ircd coders, and others. + * + * 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 + * + * $Id$ + */ + +%option case-insensitive +%option noyywrap +%option nounput +%option never-interactive + +%{ +#include "stdinc.h" +#include "irc_string.h" +#include "conf.h" +#include "conf_parser.h" /* autogenerated header file */ +#include "memory.h" +#include "hostmask.h" +#include "log.h" + +#undef YY_INPUT +#define YY_FATAL_ERROR(msg) conf_yy_fatal_error(msg) +#define YY_INPUT(buf,result,max_size) \ + if (!(result = conf_yy_input(buf, max_size))) \ + YY_FATAL_ERROR("input in flex scanner failed"); +#define MAX_INCLUDE_DEPTH 10 + + +unsigned int lineno = 1; +char linebuf[IRCD_BUFSIZE]; +char conffilebuf[IRCD_BUFSIZE]; + +static int include_stack_ptr = 0; +static YY_BUFFER_STATE include_stack[MAX_INCLUDE_DEPTH]; +static unsigned int lineno_stack[MAX_INCLUDE_DEPTH]; +static FILE *inc_fbfile_in[MAX_INCLUDE_DEPTH]; +static char conffile_stack[MAX_INCLUDE_DEPTH][IRCD_BUFSIZE]; +static void ccomment(void); +static void cinclude(void); +static int ieof(void); + +static int +conf_yy_input(char *lbuf, unsigned int max_size) +{ + return !fgets(lbuf, max_size, conf_parser_ctx.conf_file) ? 0 : strlen(lbuf); +} + +static int +conf_yy_fatal_error(const char *msg) +{ + return 0; +} + +%} + +WS [[:blank:]]* +DIGIT [[:digit:]]+ +COMMENT ("//"|"#").* +qstring \"[^\"\n]*[\"\n] +include \.include{WS}(\<.*\>|\".*\") + +%% +{include} { cinclude(); } +"/*" { ccomment(); } + +\n.* { strlcpy(linebuf, yytext+1, sizeof(linebuf)); ++lineno; yyless(1); } + +{WS} ; +{COMMENT} ; + +{DIGIT} { yylval.number = atoi(yytext); return NUMBER; } + +{qstring} { if (yytext[yyleng-2] == '\\') + { + yyless(yyleng-1); /* return last quote */ + yymore(); /* append next string */ + } + else + { + yylval.string = yytext+1; + if(yylval.string[yyleng-2] != '"') + ilog(LOG_TYPE_IRCD, "Unterminated character string"); + else + { + int i,j; + + yylval.string[yyleng-2] = '\0'; /* remove close + * quote + */ + + for (j=i=0 ;yylval.string[i] != '\0'; i++,j++) + { + if (yylval.string[i] != '\\') + { + yylval.string[j] = yylval.string[i]; + } + else + { + i++; + if (yylval.string[i] == '\0') /* XXX + * should not + * happen + */ + { + ilog(LOG_TYPE_IRCD, + "Unterminated character string"); + break; + } + yylval.string[j] = yylval.string[i]; + } + } + yylval.string[j] = '\0'; + return QSTRING; + } + } + } + +accept_password { return ACCEPT_PASSWORD; } +admin { return ADMIN; } +administrator { return ADMIN; } +aftype { return AFTYPE; } +all { return T_ALL; } +auth { return IRCD_AUTH; } +autoconn { return AUTOCONN; } +can_flood { return CAN_FLOOD; } +caller_id_wait { return CALLER_ID_WAIT; } +opers_bypass_callerid { return OPERS_BYPASS_CALLERID; } +channel { return CHANNEL; } +cidr_bitlen_ipv4 { return CIDR_BITLEN_IPV4; } +cidr_bitlen_ipv6 { return CIDR_BITLEN_IPV6; } +class { return CLASS; } +cluster { return T_CLUSTER; } +connect { return CONNECT; } +connectfreq { return CONNECTFREQ; } +default_floodcount { return DEFAULT_FLOODCOUNT; } +default_split_server_count { return DEFAULT_SPLIT_SERVER_COUNT; } +default_split_user_count { return DEFAULT_SPLIT_USER_COUNT; } +deny { return DENY; } +description { return DESCRIPTION; } +die { return DIE; } +disable_auth { return DISABLE_AUTH; } +disable_fake_channels { return DISABLE_FAKE_CHANNELS; } +disable_remote_commands { return DISABLE_REMOTE_COMMANDS; } +dline { return T_DLINE; } +dots_in_ident { return DOTS_IN_IDENT; } +egdpool_path { return EGDPOOL_PATH; } +email { return EMAIL; } +encrypted { return ENCRYPTED; } +exceed_limit { return EXCEED_LIMIT; } +exempt { return EXEMPT; } +file { return T_FILE; } +flags { return IRCD_FLAGS; } +flatten_links { return FLATTEN_LINKS; } +gecos { return GECOS; } +general { return GENERAL; } +gline { return GLINE; } +gline_enable { return GLINE_ENABLE; } +gline_exempt { return GLINE_EXEMPT; } +gline_duration { return GLINE_DURATION; } +gline_request_duration { return GLINE_REQUEST_DURATION; } +gline_min_cidr { return GLINE_MIN_CIDR; } +gline_min_cidr6 { return GLINE_MIN_CIDR6; } +globops { return T_GLOBOPS; } +global_kill { return GLOBAL_KILL; } +have_ident { return NEED_IDENT; } +need_ident { return NEED_IDENT; } +havent_read_conf { return HAVENT_READ_CONF; } +hidden { return HIDDEN; } +hidden_name { return HIDDEN_NAME; } +hide_server_ips { return HIDE_SERVER_IPS; } +hide_servers { return HIDE_SERVERS; } +hide_spoof_ips { return HIDE_SPOOF_IPS; } +host { return HOST; } +hub { return HUB; } +hub_mask { return HUB_MASK; } +ignore_bogus_ts { return IGNORE_BOGUS_TS; } +invisible_on_connect { return INVISIBLE_ON_CONNECT; } +ip { return IP; } +ipv4 { return T_IPV4; } +ipv6 { return T_IPV6; } +join_flood_count { return JOIN_FLOOD_COUNT; } +join_flood_time { return JOIN_FLOOD_TIME; } +kill { return KILL; } +kill_chase_time_limit { return KILL_CHASE_TIME_LIMIT; } +kline { return KLINE; } +kline_exempt { return KLINE_EXEMPT; } +leaf_mask { return LEAF_MASK; } +listen { return LISTEN; } +log { return T_LOG; } +masked { return TMASKED; } +max_clients { return T_MAX_CLIENTS; } +max_ident { return MAX_IDENT; } +max_local { return MAX_LOCAL; } +max_global { return MAX_GLOBAL; } +max_number { return MAX_NUMBER; } +max_watch { return MAX_WATCH; } +message_locale { return MESSAGE_LOCALE; } +min_nonwildcard { return MIN_NONWILDCARD; } +min_nonwildcard_simple { return MIN_NONWILDCARD_SIMPLE; } +name { return NAME; } +need_password { return NEED_PASSWORD; } +network_desc { return NETWORK_DESC; } +network_name { return NETWORK_NAME; } +nick { return NICK; } +nick_changes { return NICK_CHANGES; } +no { yylval.number = 0; return TBOOL; } +no_create_on_split { return NO_CREATE_ON_SPLIT; } +no_join_on_split { return NO_JOIN_ON_SPLIT; } +no_oper_flood { return NO_OPER_FLOOD; } +no_tilde { return NO_TILDE; } +number_per_cidr { return NUMBER_PER_CIDR; } +number_per_ip { return NUMBER_PER_IP; } +oper { return OPERATOR; } +oper_pass_resv { return OPER_PASS_RESV; } +operator { return OPERATOR; } +passwd { return PASSWORD; } +password { return PASSWORD; } +ping_cookie { return PING_COOKIE; } +ping_time { return PING_TIME; } +ping_warning { return PING_WARNING; } +port { return PORT; } +quarantine { return RESV; } +quiet_on_ban { return QUIET_ON_BAN; } +reason { return REASON; } +recvq { return T_RECVQ; } +redirport { return REDIRPORT; } +redirserv { return REDIRSERV; } +regex { return REGEX_T; } +rehash { return REHASH; } +remote { return REMOTE; } +remoteban { return REMOTEBAN; } +restart { return T_RESTART; } +restrict_channels { return RESTRICT_CHANNELS; } +resv { return RESV; } +resv_exempt { return RESV_EXEMPT; } +rsa_private_key_file { return RSA_PRIVATE_KEY_FILE; } +rsa_public_key_file { return RSA_PUBLIC_KEY_FILE; } +ssl { return T_SSL; } +ssl_certificate_file { return SSL_CERTIFICATE_FILE; } +ssl_client_method { return T_SSL_CLIENT_METHOD; } +ssl_server_method { return T_SSL_SERVER_METHOD; } +ssl_dh_param_file { return SSL_DH_PARAM_FILE; } +ssl_cipher_list { return T_SSL_CIPHER_LIST; } +sslv3 { return T_SSLV3; } +tlsv1 { return T_TLSV1; } +send_password { return SEND_PASSWORD; } +sendq { return SENDQ; } +server { return T_SERVER; } +serverhide { return SERVERHIDE; } +serverinfo { return SERVERINFO; } +service { return T_SERVICE; } +services_name { return T_SERVICES_NAME; } +set { return T_SET; } +shared { return T_SHARED; } +short_motd { return SHORT_MOTD; } +sid { return IRCD_SID; } +size { return T_SIZE; } +spoof { return SPOOF; } +spoof_notice { return SPOOF_NOTICE; } +tkline_expire_notices { return TKLINE_EXPIRE_NOTICES; } +type { return TYPE; } +true_no_oper_flood { return TRUE_NO_OPER_FLOOD; } +umodes { return T_UMODES; } +unkline { return UNKLINE; } +undline { return T_UNDLINE; } +unlimited { return T_UNLIMITED; } +use_egd { return USE_EGD; } +use_logging { return USE_LOGGING; } +throttle_time { return THROTTLE_TIME; } +user { return USER; } +vhost { return VHOST; } +vhost6 { return VHOST6; } +xline { return XLINE; } +yes { yylval.number = 1; return TBOOL; } + +failed_oper_notice { return FAILED_OPER_NOTICE; } +max_accept { return MAX_ACCEPT; } +max_nick_changes { return MAX_NICK_CHANGES; } +max_chans_per_oper { return MAX_CHANS_PER_OPER; } +max_chans_per_user { return MAX_CHANS_PER_USER; } +max_nick_time { return MAX_NICK_TIME; } +anti_nick_flood { return ANTI_NICK_FLOOD; } +anti_spam_exit_message_time { return ANTI_SPAM_EXIT_MESSAGE_TIME; } +ts_max_delta { return TS_MAX_DELTA; } +ts_warn_delta { return TS_WARN_DELTA; } +links_delay { return LINKS_DELAY; } +warn_no_nline { return WARN_NO_NLINE; } + +stats_e_disabled { return STATS_E_DISABLED; } +stats_o_oper_only { return STATS_O_OPER_ONLY; } +stats_k_oper_only { return STATS_K_OPER_ONLY; } +stats_i_oper_only { return STATS_I_OPER_ONLY; } +stats_P_oper_only { return STATS_P_OPER_ONLY; } +pace_wait { return PACE_WAIT; } +pace_wait_simple { return PACE_WAIT_SIMPLE; } +knock_delay { return KNOCK_DELAY; } +knock_delay_channel { return KNOCK_DELAY_CHANNEL; } +max_bans { return MAX_BANS; } +modules { return MODULES; } +module { return MODULE; } +path { return PATH; } +max_targets { return MAX_TARGETS; } + +unxline { return T_UNXLINE; } +unresv { return T_UNRESV; } + +oper_only_umodes { return OPER_ONLY_UMODES; } +oper_umodes { return OPER_UMODES; } +bots { return T_BOTS; } +cconn { return T_CCONN; } +cconn_full { return T_CCONN_FULL; } +deaf { return T_DEAF; } +debug { return T_DEBUG; } +full { return T_FULL; } +skill { return T_SKILL; } +nchange { return T_NCHANGE; } +rej { return T_REJ; } +unauth { return T_UNAUTH; } +spy { return T_SPY; } +external { return T_EXTERNAL; } +operwall { return T_OPERWALL; } +servnotice { return T_SERVNOTICE; } +invisible { return T_INVISIBLE; } +wallop { return T_WALLOP; } +callerid { return T_CALLERID; } +softcallerid { return T_SOFTCALLERID; } +locops { return T_LOCOPS; } + +weeks { return WEEKS; } +week { return WEEKS; } +days { return DAYS; } +day { return DAYS; } +hours { return HOURS; } +hour { return HOURS; } +minutes { return MINUTES; } +minute { return MINUTES; } +seconds { return SECONDS; } +second { return SECONDS; } + +bytes { return BYTES; } +byte { return BYTES; } +kilobytes { return KBYTES; } +kilobyte { return KBYTES; } +kbytes { return KBYTES; } +kbyte { return KBYTES; } +kb { return KBYTES; } +megabytes { return MBYTES; } +megabyte { return MBYTES; } +mbytes { return MBYTES; } +mbyte { return MBYTES; } +mb { return MBYTES; } +\.\. { return TWODOTS; } + +. { return yytext[0]; } +<<EOF>> { if (ieof()) yyterminate(); } + +%% + +/* C-comment ignoring routine -kre*/ +static void +ccomment(void) +{ + int c = 0; + + /* log(L_NOTICE, "got comment"); */ + while (1) + { + while ((c = input()) != '*' && c != EOF) + if (c == '\n') + ++lineno; + + if (c == '*') + { + while ((c = input()) == '*') + /* Nothing */ ; + if (c == '/') + break; + else if (c == '\n') + ++lineno; + } + + if (c == EOF) + { + YY_FATAL_ERROR("EOF in comment"); + /* XXX hack alert this disables + * the stupid unused function warning + * gcc generates + */ + if (1 == 0) + yy_fatal_error("EOF in comment"); + break; + } + } +} + +/* C-style .includes. This function will properly swap input conf buffers, + * and lineno -kre */ +static void +cinclude(void) +{ + char *p = NULL; + + if ((p = strchr(yytext, '<')) == NULL) + *strchr(p = strchr(yytext, '"') + 1, '"') = '\0'; + else + *strchr(++p, '>') = '\0'; + + /* log(L_NOTICE, "got include %s!", c); */ + + /* do stacking and co. */ + if (include_stack_ptr >= MAX_INCLUDE_DEPTH) + ilog(LOG_TYPE_IRCD, "Includes nested too deep in %s", p); + else + { + FILE *tmp_fbfile_in = NULL; + char filenamebuf[IRCD_BUFSIZE]; + + if (*p == '/') /* if it is an absolute path */ + snprintf(filenamebuf, sizeof(filenamebuf), "%s", p); + else + snprintf(filenamebuf, sizeof(filenamebuf), "%s/%s", ETCPATH, p); + + tmp_fbfile_in = fopen(filenamebuf, "r"); + + if (tmp_fbfile_in == NULL) + { + ilog(LOG_TYPE_IRCD, "Unable to read configuration file '%s': %s", + filenamebuf, strerror(errno)); + return; + } + + lineno_stack[include_stack_ptr] = lineno; + lineno = 1; + inc_fbfile_in[include_stack_ptr] = conf_parser_ctx.conf_file; + strlcpy(conffile_stack[include_stack_ptr], conffilebuf, IRCD_BUFSIZE); + include_stack[include_stack_ptr++] = YY_CURRENT_BUFFER; + conf_parser_ctx.conf_file = tmp_fbfile_in; + snprintf(conffilebuf, sizeof(conffilebuf), "%s", filenamebuf); + yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE)); + } +} + +/* This is function that will be called on EOF in conf file. It will + * apropriately close conf if it not main conf and swap input buffers -kre + * */ +static int +ieof(void) +{ + /* log(L_NOTICE, "return from include stack!"); */ + if (include_stack_ptr) + fclose(conf_parser_ctx.conf_file); + if (--include_stack_ptr < 0) + { + /* log(L_NOTICE, "terminating lexer"); */ + /* We will now exit the lexer - restore init values if we get /rehash + * later and reenter lexer -kre */ + include_stack_ptr = 0; + lineno = 1; + return 1; + } + + /* switch buffer */ + /* log(L_NOTICE, "deleting include_stack_ptr=%d", include_stack_ptr); */ + yy_delete_buffer(YY_CURRENT_BUFFER); + lineno = lineno_stack[include_stack_ptr]; + conf_parser_ctx.conf_file = inc_fbfile_in[include_stack_ptr]; + strlcpy(conffilebuf, conffile_stack[include_stack_ptr], sizeof(conffilebuf)); + yy_switch_to_buffer(include_stack[include_stack_ptr]); + + return 0; +} diff --git a/src/conf_parser.c b/src/conf_parser.c new file mode 100644 index 0000000..294935c --- /dev/null +++ b/src/conf_parser.c @@ -0,0 +1,7071 @@ +/* A Bison parser, made by GNU Bison 2.6.2. */ + +/* Bison implementation for Yacc-like parsers in C + + Copyright (C) 1984, 1989-1990, 2000-2012 Free Software Foundation, Inc. + + 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 3 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, see <http://www.gnu.org/licenses/>. */ + +/* As a special exception, you may create a larger work that contains + part or all of the Bison parser skeleton and distribute that work + under terms of your choice, so long as that work isn't itself a + parser generator using the skeleton or a modified version thereof + as a parser skeleton. Alternatively, if you modify or redistribute + the parser skeleton itself, you may (at your option) remove this + special exception, which will cause the skeleton and the resulting + Bison output files to be licensed under the GNU General Public + License without this special exception. + + This special exception was added by the Free Software Foundation in + version 2.2 of Bison. */ + +/* C LALR(1) parser skeleton written by Richard Stallman, by + simplifying the original so-called "semantic" parser. */ + +/* All symbols defined below should begin with yy or YY, to avoid + infringing on user name space. This should be done even for local + variables, as they might otherwise be expanded by user macros. + There are some unavoidable exceptions within include files to + define necessary library symbols; they are noted "INFRINGES ON + USER NAME SPACE" below. */ + +/* Identify Bison output. */ +#define YYBISON 1 + +/* Bison version. */ +#define YYBISON_VERSION "2.6.2" + +/* Skeleton name. */ +#define YYSKELETON_NAME "yacc.c" + +/* Pure parsers. */ +#define YYPURE 0 + +/* Push parsers. */ +#define YYPUSH 0 + +/* Pull parsers. */ +#define YYPULL 1 + + + + +/* Copy the first part of user declarations. */ +/* Line 336 of yacc.c */ +#line 25 "conf_parser.y" + + +#define YY_NO_UNPUT +#include <sys/types.h> +#include <string.h> + +#include "config.h" +#include "stdinc.h" +#include "ircd.h" +#include "list.h" +#include "conf.h" +#include "event.h" +#include "log.h" +#include "client.h" /* for UMODE_ALL only */ +#include "irc_string.h" +#include "sprintf_irc.h" +#include "memory.h" +#include "modules.h" +#include "s_serv.h" +#include "hostmask.h" +#include "send.h" +#include "listener.h" +#include "resv.h" +#include "numeric.h" +#include "s_user.h" + +#ifdef HAVE_LIBCRYPTO +#include <openssl/rsa.h> +#include <openssl/bio.h> +#include <openssl/pem.h> +#include <openssl/dh.h> +#endif + +int yylex(void); + +static char *class_name = NULL; +static struct ConfItem *yy_conf = NULL; +static struct AccessItem *yy_aconf = NULL; +static struct MatchItem *yy_match_item = NULL; +static struct ClassItem *yy_class = NULL; +static char *yy_class_name = NULL; + +static dlink_list col_conf_list = { NULL, NULL, 0 }; +static unsigned int listener_flags = 0; +static unsigned int regex_ban = 0; +static char userbuf[IRCD_BUFSIZE]; +static char hostbuf[IRCD_BUFSIZE]; +static char reasonbuf[REASONLEN + 1]; +static char gecos_name[REALLEN * 4]; +static char lfile[IRCD_BUFSIZE]; +static unsigned int ltype = 0; +static unsigned int lsize = 0; +static char *resv_reason = NULL; +static char *listener_address = NULL; + +struct CollectItem +{ + dlink_node node; + char *name; + char *user; + char *host; + char *passwd; + int port; + int flags; +#ifdef HAVE_LIBCRYPTO + char *rsa_public_key_file; + RSA *rsa_public_key; +#endif +}; + +static void +free_collect_item(struct CollectItem *item) +{ + MyFree(item->name); + MyFree(item->user); + MyFree(item->host); + MyFree(item->passwd); +#ifdef HAVE_LIBCRYPTO + MyFree(item->rsa_public_key_file); +#endif + MyFree(item); +} + + +/* Line 336 of yacc.c */ +#line 153 "conf_parser.c" + +# ifndef YY_NULL +# if defined __cplusplus && 201103L <= __cplusplus +# define YY_NULL nullptr +# else +# define YY_NULL 0 +# endif +# endif + +/* Enabling verbose error messages. */ +#ifdef YYERROR_VERBOSE +# undef YYERROR_VERBOSE +# define YYERROR_VERBOSE 1 +#else +# define YYERROR_VERBOSE 0 +#endif + +/* In a future release of Bison, this section will be replaced + by #include "y.tab.h". */ +#ifndef YY_Y_TAB_H +# define YY_Y_TAB_H +/* Enabling traces. */ +#ifndef YYDEBUG +# define YYDEBUG 0 +#endif +#if YYDEBUG +extern int yydebug; +#endif + +/* Tokens. */ +#ifndef YYTOKENTYPE +# define YYTOKENTYPE + /* Put the tokens into the symbol table, so that GDB and other debuggers + know about them. */ + enum yytokentype { + ACCEPT_PASSWORD = 258, + ADMIN = 259, + AFTYPE = 260, + ANTI_NICK_FLOOD = 261, + ANTI_SPAM_EXIT_MESSAGE_TIME = 262, + AUTOCONN = 263, + BYTES = 264, + KBYTES = 265, + MBYTES = 266, + CALLER_ID_WAIT = 267, + CAN_FLOOD = 268, + CHANNEL = 269, + CIDR_BITLEN_IPV4 = 270, + CIDR_BITLEN_IPV6 = 271, + CLASS = 272, + CONNECT = 273, + CONNECTFREQ = 274, + DEFAULT_FLOODCOUNT = 275, + DEFAULT_SPLIT_SERVER_COUNT = 276, + DEFAULT_SPLIT_USER_COUNT = 277, + DENY = 278, + DESCRIPTION = 279, + DIE = 280, + DISABLE_AUTH = 281, + DISABLE_FAKE_CHANNELS = 282, + DISABLE_REMOTE_COMMANDS = 283, + DOTS_IN_IDENT = 284, + EGDPOOL_PATH = 285, + EMAIL = 286, + ENCRYPTED = 287, + EXCEED_LIMIT = 288, + EXEMPT = 289, + FAILED_OPER_NOTICE = 290, + IRCD_FLAGS = 291, + FLATTEN_LINKS = 292, + GECOS = 293, + GENERAL = 294, + GLINE = 295, + GLINE_DURATION = 296, + GLINE_ENABLE = 297, + GLINE_EXEMPT = 298, + GLINE_REQUEST_DURATION = 299, + GLINE_MIN_CIDR = 300, + GLINE_MIN_CIDR6 = 301, + GLOBAL_KILL = 302, + IRCD_AUTH = 303, + NEED_IDENT = 304, + HAVENT_READ_CONF = 305, + HIDDEN = 306, + HIDDEN_NAME = 307, + HIDE_SERVER_IPS = 308, + HIDE_SERVERS = 309, + HIDE_SPOOF_IPS = 310, + HOST = 311, + HUB = 312, + HUB_MASK = 313, + IGNORE_BOGUS_TS = 314, + INVISIBLE_ON_CONNECT = 315, + IP = 316, + KILL = 317, + KILL_CHASE_TIME_LIMIT = 318, + KLINE = 319, + KLINE_EXEMPT = 320, + KNOCK_DELAY = 321, + KNOCK_DELAY_CHANNEL = 322, + LEAF_MASK = 323, + LINKS_DELAY = 324, + LISTEN = 325, + T_LOG = 326, + MAX_ACCEPT = 327, + MAX_BANS = 328, + MAX_CHANS_PER_OPER = 329, + MAX_CHANS_PER_USER = 330, + MAX_GLOBAL = 331, + MAX_IDENT = 332, + MAX_LOCAL = 333, + MAX_NICK_CHANGES = 334, + MAX_NICK_TIME = 335, + MAX_NUMBER = 336, + MAX_TARGETS = 337, + MAX_WATCH = 338, + MESSAGE_LOCALE = 339, + MIN_NONWILDCARD = 340, + MIN_NONWILDCARD_SIMPLE = 341, + MODULE = 342, + MODULES = 343, + NAME = 344, + NEED_PASSWORD = 345, + NETWORK_DESC = 346, + NETWORK_NAME = 347, + NICK = 348, + NICK_CHANGES = 349, + NO_CREATE_ON_SPLIT = 350, + NO_JOIN_ON_SPLIT = 351, + NO_OPER_FLOOD = 352, + NO_TILDE = 353, + NUMBER = 354, + NUMBER_PER_CIDR = 355, + NUMBER_PER_IP = 356, + OPERATOR = 357, + OPERS_BYPASS_CALLERID = 358, + OPER_ONLY_UMODES = 359, + OPER_PASS_RESV = 360, + OPER_SPY_T = 361, + OPER_UMODES = 362, + JOIN_FLOOD_COUNT = 363, + JOIN_FLOOD_TIME = 364, + PACE_WAIT = 365, + PACE_WAIT_SIMPLE = 366, + PASSWORD = 367, + PATH = 368, + PING_COOKIE = 369, + PING_TIME = 370, + PING_WARNING = 371, + PORT = 372, + QSTRING = 373, + QUIET_ON_BAN = 374, + REASON = 375, + REDIRPORT = 376, + REDIRSERV = 377, + REGEX_T = 378, + REHASH = 379, + REMOTE = 380, + REMOTEBAN = 381, + RESTRICT_CHANNELS = 382, + RSA_PRIVATE_KEY_FILE = 383, + RSA_PUBLIC_KEY_FILE = 384, + SSL_CERTIFICATE_FILE = 385, + SSL_DH_PARAM_FILE = 386, + T_SSL_CLIENT_METHOD = 387, + T_SSL_SERVER_METHOD = 388, + T_SSLV3 = 389, + T_TLSV1 = 390, + RESV = 391, + RESV_EXEMPT = 392, + SECONDS = 393, + MINUTES = 394, + HOURS = 395, + DAYS = 396, + WEEKS = 397, + SENDQ = 398, + SEND_PASSWORD = 399, + SERVERHIDE = 400, + SERVERINFO = 401, + IRCD_SID = 402, + TKLINE_EXPIRE_NOTICES = 403, + T_SHARED = 404, + T_CLUSTER = 405, + TYPE = 406, + SHORT_MOTD = 407, + SPOOF = 408, + SPOOF_NOTICE = 409, + STATS_E_DISABLED = 410, + STATS_I_OPER_ONLY = 411, + STATS_K_OPER_ONLY = 412, + STATS_O_OPER_ONLY = 413, + STATS_P_OPER_ONLY = 414, + TBOOL = 415, + TMASKED = 416, + TS_MAX_DELTA = 417, + TS_WARN_DELTA = 418, + TWODOTS = 419, + T_ALL = 420, + T_BOTS = 421, + T_SOFTCALLERID = 422, + T_CALLERID = 423, + T_CCONN = 424, + T_CCONN_FULL = 425, + T_SSL_CIPHER_LIST = 426, + T_DEAF = 427, + T_DEBUG = 428, + T_DLINE = 429, + T_EXTERNAL = 430, + T_FULL = 431, + T_INVISIBLE = 432, + T_IPV4 = 433, + T_IPV6 = 434, + T_LOCOPS = 435, + T_MAX_CLIENTS = 436, + T_NCHANGE = 437, + T_OPERWALL = 438, + T_RECVQ = 439, + T_REJ = 440, + T_SERVER = 441, + T_SERVNOTICE = 442, + T_SET = 443, + T_SKILL = 444, + T_SPY = 445, + T_SSL = 446, + T_UMODES = 447, + T_UNAUTH = 448, + T_UNDLINE = 449, + T_UNLIMITED = 450, + T_UNRESV = 451, + T_UNXLINE = 452, + T_GLOBOPS = 453, + T_WALLOP = 454, + T_RESTART = 455, + T_SERVICE = 456, + T_SERVICES_NAME = 457, + THROTTLE_TIME = 458, + TRUE_NO_OPER_FLOOD = 459, + UNKLINE = 460, + USER = 461, + USE_EGD = 462, + USE_LOGGING = 463, + VHOST = 464, + VHOST6 = 465, + XLINE = 466, + WARN_NO_NLINE = 467, + T_SIZE = 468, + T_FILE = 469 + }; +#endif +/* Tokens. */ +#define ACCEPT_PASSWORD 258 +#define ADMIN 259 +#define AFTYPE 260 +#define ANTI_NICK_FLOOD 261 +#define ANTI_SPAM_EXIT_MESSAGE_TIME 262 +#define AUTOCONN 263 +#define BYTES 264 +#define KBYTES 265 +#define MBYTES 266 +#define CALLER_ID_WAIT 267 +#define CAN_FLOOD 268 +#define CHANNEL 269 +#define CIDR_BITLEN_IPV4 270 +#define CIDR_BITLEN_IPV6 271 +#define CLASS 272 +#define CONNECT 273 +#define CONNECTFREQ 274 +#define DEFAULT_FLOODCOUNT 275 +#define DEFAULT_SPLIT_SERVER_COUNT 276 +#define DEFAULT_SPLIT_USER_COUNT 277 +#define DENY 278 +#define DESCRIPTION 279 +#define DIE 280 +#define DISABLE_AUTH 281 +#define DISABLE_FAKE_CHANNELS 282 +#define DISABLE_REMOTE_COMMANDS 283 +#define DOTS_IN_IDENT 284 +#define EGDPOOL_PATH 285 +#define EMAIL 286 +#define ENCRYPTED 287 +#define EXCEED_LIMIT 288 +#define EXEMPT 289 +#define FAILED_OPER_NOTICE 290 +#define IRCD_FLAGS 291 +#define FLATTEN_LINKS 292 +#define GECOS 293 +#define GENERAL 294 +#define GLINE 295 +#define GLINE_DURATION 296 +#define GLINE_ENABLE 297 +#define GLINE_EXEMPT 298 +#define GLINE_REQUEST_DURATION 299 +#define GLINE_MIN_CIDR 300 +#define GLINE_MIN_CIDR6 301 +#define GLOBAL_KILL 302 +#define IRCD_AUTH 303 +#define NEED_IDENT 304 +#define HAVENT_READ_CONF 305 +#define HIDDEN 306 +#define HIDDEN_NAME 307 +#define HIDE_SERVER_IPS 308 +#define HIDE_SERVERS 309 +#define HIDE_SPOOF_IPS 310 +#define HOST 311 +#define HUB 312 +#define HUB_MASK 313 +#define IGNORE_BOGUS_TS 314 +#define INVISIBLE_ON_CONNECT 315 +#define IP 316 +#define KILL 317 +#define KILL_CHASE_TIME_LIMIT 318 +#define KLINE 319 +#define KLINE_EXEMPT 320 +#define KNOCK_DELAY 321 +#define KNOCK_DELAY_CHANNEL 322 +#define LEAF_MASK 323 +#define LINKS_DELAY 324 +#define LISTEN 325 +#define T_LOG 326 +#define MAX_ACCEPT 327 +#define MAX_BANS 328 +#define MAX_CHANS_PER_OPER 329 +#define MAX_CHANS_PER_USER 330 +#define MAX_GLOBAL 331 +#define MAX_IDENT 332 +#define MAX_LOCAL 333 +#define MAX_NICK_CHANGES 334 +#define MAX_NICK_TIME 335 +#define MAX_NUMBER 336 +#define MAX_TARGETS 337 +#define MAX_WATCH 338 +#define MESSAGE_LOCALE 339 +#define MIN_NONWILDCARD 340 +#define MIN_NONWILDCARD_SIMPLE 341 +#define MODULE 342 +#define MODULES 343 +#define NAME 344 +#define NEED_PASSWORD 345 +#define NETWORK_DESC 346 +#define NETWORK_NAME 347 +#define NICK 348 +#define NICK_CHANGES 349 +#define NO_CREATE_ON_SPLIT 350 +#define NO_JOIN_ON_SPLIT 351 +#define NO_OPER_FLOOD 352 +#define NO_TILDE 353 +#define NUMBER 354 +#define NUMBER_PER_CIDR 355 +#define NUMBER_PER_IP 356 +#define OPERATOR 357 +#define OPERS_BYPASS_CALLERID 358 +#define OPER_ONLY_UMODES 359 +#define OPER_PASS_RESV 360 +#define OPER_SPY_T 361 +#define OPER_UMODES 362 +#define JOIN_FLOOD_COUNT 363 +#define JOIN_FLOOD_TIME 364 +#define PACE_WAIT 365 +#define PACE_WAIT_SIMPLE 366 +#define PASSWORD 367 +#define PATH 368 +#define PING_COOKIE 369 +#define PING_TIME 370 +#define PING_WARNING 371 +#define PORT 372 +#define QSTRING 373 +#define QUIET_ON_BAN 374 +#define REASON 375 +#define REDIRPORT 376 +#define REDIRSERV 377 +#define REGEX_T 378 +#define REHASH 379 +#define REMOTE 380 +#define REMOTEBAN 381 +#define RESTRICT_CHANNELS 382 +#define RSA_PRIVATE_KEY_FILE 383 +#define RSA_PUBLIC_KEY_FILE 384 +#define SSL_CERTIFICATE_FILE 385 +#define SSL_DH_PARAM_FILE 386 +#define T_SSL_CLIENT_METHOD 387 +#define T_SSL_SERVER_METHOD 388 +#define T_SSLV3 389 +#define T_TLSV1 390 +#define RESV 391 +#define RESV_EXEMPT 392 +#define SECONDS 393 +#define MINUTES 394 +#define HOURS 395 +#define DAYS 396 +#define WEEKS 397 +#define SENDQ 398 +#define SEND_PASSWORD 399 +#define SERVERHIDE 400 +#define SERVERINFO 401 +#define IRCD_SID 402 +#define TKLINE_EXPIRE_NOTICES 403 +#define T_SHARED 404 +#define T_CLUSTER 405 +#define TYPE 406 +#define SHORT_MOTD 407 +#define SPOOF 408 +#define SPOOF_NOTICE 409 +#define STATS_E_DISABLED 410 +#define STATS_I_OPER_ONLY 411 +#define STATS_K_OPER_ONLY 412 +#define STATS_O_OPER_ONLY 413 +#define STATS_P_OPER_ONLY 414 +#define TBOOL 415 +#define TMASKED 416 +#define TS_MAX_DELTA 417 +#define TS_WARN_DELTA 418 +#define TWODOTS 419 +#define T_ALL 420 +#define T_BOTS 421 +#define T_SOFTCALLERID 422 +#define T_CALLERID 423 +#define T_CCONN 424 +#define T_CCONN_FULL 425 +#define T_SSL_CIPHER_LIST 426 +#define T_DEAF 427 +#define T_DEBUG 428 +#define T_DLINE 429 +#define T_EXTERNAL 430 +#define T_FULL 431 +#define T_INVISIBLE 432 +#define T_IPV4 433 +#define T_IPV6 434 +#define T_LOCOPS 435 +#define T_MAX_CLIENTS 436 +#define T_NCHANGE 437 +#define T_OPERWALL 438 +#define T_RECVQ 439 +#define T_REJ 440 +#define T_SERVER 441 +#define T_SERVNOTICE 442 +#define T_SET 443 +#define T_SKILL 444 +#define T_SPY 445 +#define T_SSL 446 +#define T_UMODES 447 +#define T_UNAUTH 448 +#define T_UNDLINE 449 +#define T_UNLIMITED 450 +#define T_UNRESV 451 +#define T_UNXLINE 452 +#define T_GLOBOPS 453 +#define T_WALLOP 454 +#define T_RESTART 455 +#define T_SERVICE 456 +#define T_SERVICES_NAME 457 +#define THROTTLE_TIME 458 +#define TRUE_NO_OPER_FLOOD 459 +#define UNKLINE 460 +#define USER 461 +#define USE_EGD 462 +#define USE_LOGGING 463 +#define VHOST 464 +#define VHOST6 465 +#define XLINE 466 +#define WARN_NO_NLINE 467 +#define T_SIZE 468 +#define T_FILE 469 + + + +#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED +typedef union YYSTYPE +{ +/* Line 350 of yacc.c */ +#line 110 "conf_parser.y" + + int number; + char *string; + + +/* Line 350 of yacc.c */ +#line 630 "conf_parser.c" +} YYSTYPE; +# define YYSTYPE_IS_TRIVIAL 1 +# define yystype YYSTYPE /* obsolescent; will be withdrawn */ +# define YYSTYPE_IS_DECLARED 1 +#endif + +extern YYSTYPE yylval; + +#ifdef YYPARSE_PARAM +#if defined __STDC__ || defined __cplusplus +int yyparse (void *YYPARSE_PARAM); +#else +int yyparse (); +#endif +#else /* ! YYPARSE_PARAM */ +#if defined __STDC__ || defined __cplusplus +int yyparse (void); +#else +int yyparse (); +#endif +#endif /* ! YYPARSE_PARAM */ + +#endif /* !YY_Y_TAB_H */ + +/* Copy the second part of user declarations. */ + +/* Line 353 of yacc.c */ +#line 658 "conf_parser.c" + +#ifdef short +# undef short +#endif + +#ifdef YYTYPE_UINT8 +typedef YYTYPE_UINT8 yytype_uint8; +#else +typedef unsigned char yytype_uint8; +#endif + +#ifdef YYTYPE_INT8 +typedef YYTYPE_INT8 yytype_int8; +#elif (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +typedef signed char yytype_int8; +#else +typedef short int yytype_int8; +#endif + +#ifdef YYTYPE_UINT16 +typedef YYTYPE_UINT16 yytype_uint16; +#else +typedef unsigned short int yytype_uint16; +#endif + +#ifdef YYTYPE_INT16 +typedef YYTYPE_INT16 yytype_int16; +#else +typedef short int yytype_int16; +#endif + +#ifndef YYSIZE_T +# ifdef __SIZE_TYPE__ +# define YYSIZE_T __SIZE_TYPE__ +# elif defined size_t +# define YYSIZE_T size_t +# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +# include <stddef.h> /* INFRINGES ON USER NAME SPACE */ +# define YYSIZE_T size_t +# else +# define YYSIZE_T unsigned int +# endif +#endif + +#define YYSIZE_MAXIMUM ((YYSIZE_T) -1) + +#ifndef YY_ +# if defined YYENABLE_NLS && YYENABLE_NLS +# if ENABLE_NLS +# include <libintl.h> /* INFRINGES ON USER NAME SPACE */ +# define YY_(msgid) dgettext ("bison-runtime", msgid) +# endif +# endif +# ifndef YY_ +# define YY_(msgid) msgid +# endif +#endif + +/* Suppress unused-variable warnings by "using" E. */ +#if ! defined lint || defined __GNUC__ +# define YYUSE(e) ((void) (e)) +#else +# define YYUSE(e) /* empty */ +#endif + +/* Identity function, used to suppress warnings about constant conditions. */ +#ifndef lint +# define YYID(n) (n) +#else +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static int +YYID (int yyi) +#else +static int +YYID (yyi) + int yyi; +#endif +{ + return yyi; +} +#endif + +#if ! defined yyoverflow || YYERROR_VERBOSE + +/* The parser invokes alloca or malloc; define the necessary symbols. */ + +# ifdef YYSTACK_USE_ALLOCA +# if YYSTACK_USE_ALLOCA +# ifdef __GNUC__ +# define YYSTACK_ALLOC __builtin_alloca +# elif defined __BUILTIN_VA_ARG_INCR +# include <alloca.h> /* INFRINGES ON USER NAME SPACE */ +# elif defined _AIX +# define YYSTACK_ALLOC __alloca +# elif defined _MSC_VER +# include <malloc.h> /* INFRINGES ON USER NAME SPACE */ +# define alloca _alloca +# else +# define YYSTACK_ALLOC alloca +# if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */ + /* Use EXIT_SUCCESS as a witness for stdlib.h. */ +# ifndef EXIT_SUCCESS +# define EXIT_SUCCESS 0 +# endif +# endif +# endif +# endif +# endif + +# ifdef YYSTACK_ALLOC + /* Pacify GCC's `empty if-body' warning. */ +# define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0)) +# ifndef YYSTACK_ALLOC_MAXIMUM + /* The OS might guarantee only one guard page at the bottom of the stack, + and a page size can be as small as 4096 bytes. So we cannot safely + invoke alloca (N) if N exceeds 4096. Use a slightly smaller number + to allow for a few compiler-allocated temporary stack slots. */ +# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */ +# endif +# else +# define YYSTACK_ALLOC YYMALLOC +# define YYSTACK_FREE YYFREE +# ifndef YYSTACK_ALLOC_MAXIMUM +# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM +# endif +# if (defined __cplusplus && ! defined EXIT_SUCCESS \ + && ! ((defined YYMALLOC || defined malloc) \ + && (defined YYFREE || defined free))) +# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */ +# ifndef EXIT_SUCCESS +# define EXIT_SUCCESS 0 +# endif +# endif +# ifndef YYMALLOC +# define YYMALLOC malloc +# if ! defined malloc && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */ +# endif +# endif +# ifndef YYFREE +# define YYFREE free +# if ! defined free && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +void free (void *); /* INFRINGES ON USER NAME SPACE */ +# endif +# endif +# endif +#endif /* ! defined yyoverflow || YYERROR_VERBOSE */ + + +#if (! defined yyoverflow \ + && (! defined __cplusplus \ + || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) + +/* A type that is properly aligned for any stack member. */ +union yyalloc +{ + yytype_int16 yyss_alloc; + YYSTYPE yyvs_alloc; +}; + +/* The size of the maximum gap between one aligned stack and the next. */ +# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1) + +/* The size of an array large to enough to hold all stacks, each with + N elements. */ +# define YYSTACK_BYTES(N) \ + ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \ + + YYSTACK_GAP_MAXIMUM) + +# define YYCOPY_NEEDED 1 + +/* Relocate STACK from its old location to the new one. The + local variables YYSIZE and YYSTACKSIZE give the old and new number of + elements in the stack, and YYPTR gives the new location of the + stack. Advance YYPTR to a properly aligned location for the next + stack. */ +# define YYSTACK_RELOCATE(Stack_alloc, Stack) \ + do \ + { \ + YYSIZE_T yynewbytes; \ + YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \ + Stack = &yyptr->Stack_alloc; \ + yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \ + yyptr += yynewbytes / sizeof (*yyptr); \ + } \ + while (YYID (0)) + +#endif + +#if defined YYCOPY_NEEDED && YYCOPY_NEEDED +/* Copy COUNT objects from SRC to DST. The source and destination do + not overlap. */ +# ifndef YYCOPY +# if defined __GNUC__ && 1 < __GNUC__ +# define YYCOPY(Dst, Src, Count) \ + __builtin_memcpy (Dst, Src, (Count) * sizeof (*(Src))) +# else +# define YYCOPY(Dst, Src, Count) \ + do \ + { \ + YYSIZE_T yyi; \ + for (yyi = 0; yyi < (Count); yyi++) \ + (Dst)[yyi] = (Src)[yyi]; \ + } \ + while (YYID (0)) +# endif +# endif +#endif /* !YYCOPY_NEEDED */ + +/* YYFINAL -- State number of the termination state. */ +#define YYFINAL 2 +/* YYLAST -- Last index in YYTABLE. */ +#define YYLAST 1206 + +/* YYNTOKENS -- Number of terminals. */ +#define YYNTOKENS 220 +/* YYNNTS -- Number of nonterminals. */ +#define YYNNTS 283 +/* YYNRULES -- Number of rules. */ +#define YYNRULES 627 +/* YYNRULES -- Number of states. */ +#define YYNSTATES 1228 + +/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */ +#define YYUNDEFTOK 2 +#define YYMAXUTOK 469 + +#define YYTRANSLATE(YYX) \ + ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) + +/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */ +static const yytype_uint8 yytranslate[] = +{ + 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 219, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 215, + 2, 218, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 217, 2, 216, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, + 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, + 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, + 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, + 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, + 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, + 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, + 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, + 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, + 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, + 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, + 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, + 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, + 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, + 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, + 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, + 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, + 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, + 205, 206, 207, 208, 209, 210, 211, 212, 213, 214 +}; + +#if YYDEBUG +/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in + YYRHS. */ +static const yytype_uint16 yyprhs[] = +{ + 0, 0, 3, 4, 7, 9, 11, 13, 15, 17, + 19, 21, 23, 25, 27, 29, 31, 33, 35, 37, + 39, 41, 43, 45, 47, 50, 53, 54, 56, 59, + 63, 67, 71, 75, 79, 80, 82, 85, 89, 93, + 97, 103, 106, 108, 110, 112, 115, 120, 125, 131, + 134, 136, 138, 140, 142, 144, 146, 148, 150, 152, + 154, 156, 158, 160, 162, 164, 166, 169, 174, 179, + 183, 185, 187, 189, 193, 195, 197, 199, 204, 209, + 214, 219, 224, 229, 234, 239, 244, 249, 254, 259, + 264, 270, 273, 275, 277, 279, 281, 284, 289, 294, + 299, 305, 308, 310, 312, 314, 317, 322, 323, 330, + 333, 335, 337, 339, 341, 344, 349, 354, 359, 360, + 366, 370, 372, 374, 376, 378, 380, 382, 384, 386, + 387, 394, 397, 399, 401, 403, 405, 407, 409, 411, + 413, 415, 418, 423, 428, 433, 438, 443, 448, 449, + 455, 459, 461, 463, 465, 467, 469, 471, 473, 475, + 477, 479, 481, 483, 485, 487, 489, 491, 493, 495, + 497, 499, 501, 502, 508, 512, 514, 516, 518, 520, + 522, 524, 526, 528, 530, 532, 534, 536, 538, 540, + 542, 544, 546, 548, 550, 552, 553, 560, 563, 565, + 567, 569, 571, 573, 575, 577, 579, 581, 583, 585, + 587, 589, 591, 593, 596, 601, 606, 611, 616, 621, + 626, 631, 636, 641, 646, 651, 656, 661, 666, 667, + 674, 675, 681, 685, 687, 689, 691, 693, 696, 698, + 700, 702, 704, 706, 709, 710, 716, 720, 722, 724, + 728, 733, 738, 739, 746, 749, 751, 753, 755, 757, + 759, 761, 763, 765, 767, 770, 775, 780, 785, 790, + 791, 797, 801, 803, 805, 807, 809, 811, 813, 815, + 817, 819, 821, 826, 831, 836, 837, 844, 847, 849, + 851, 853, 855, 858, 863, 868, 873, 879, 882, 884, + 886, 888, 893, 894, 901, 904, 906, 908, 910, 912, + 915, 920, 925, 926, 932, 936, 938, 940, 942, 944, + 946, 948, 950, 952, 954, 956, 958, 959, 966, 969, + 971, 973, 975, 978, 983, 984, 990, 994, 996, 998, + 1000, 1002, 1004, 1006, 1008, 1010, 1012, 1014, 1016, 1017, + 1024, 1027, 1029, 1031, 1033, 1035, 1037, 1039, 1041, 1043, + 1045, 1047, 1049, 1051, 1053, 1055, 1058, 1063, 1068, 1073, + 1078, 1083, 1088, 1093, 1098, 1099, 1105, 1109, 1111, 1113, + 1115, 1120, 1125, 1130, 1135, 1140, 1141, 1148, 1149, 1155, + 1159, 1161, 1163, 1166, 1168, 1170, 1172, 1174, 1176, 1181, + 1186, 1187, 1194, 1197, 1199, 1201, 1203, 1205, 1210, 1215, + 1221, 1224, 1226, 1228, 1230, 1235, 1236, 1243, 1244, 1250, + 1254, 1256, 1258, 1261, 1263, 1265, 1267, 1269, 1271, 1276, + 1281, 1287, 1290, 1292, 1294, 1296, 1298, 1300, 1302, 1304, + 1306, 1308, 1310, 1312, 1314, 1316, 1318, 1320, 1322, 1324, + 1326, 1328, 1330, 1332, 1334, 1336, 1338, 1340, 1342, 1344, + 1346, 1348, 1350, 1352, 1354, 1356, 1358, 1360, 1362, 1364, + 1366, 1368, 1370, 1372, 1374, 1376, 1378, 1380, 1382, 1384, + 1386, 1388, 1390, 1392, 1397, 1402, 1407, 1412, 1417, 1422, + 1427, 1432, 1437, 1442, 1447, 1452, 1457, 1462, 1467, 1472, + 1477, 1482, 1487, 1492, 1497, 1502, 1507, 1512, 1517, 1522, + 1527, 1532, 1537, 1542, 1547, 1552, 1557, 1562, 1567, 1572, + 1577, 1582, 1587, 1592, 1597, 1602, 1607, 1612, 1617, 1622, + 1623, 1629, 1633, 1635, 1637, 1639, 1641, 1643, 1645, 1647, + 1649, 1651, 1653, 1655, 1657, 1659, 1661, 1663, 1665, 1667, + 1669, 1671, 1673, 1675, 1676, 1682, 1686, 1688, 1690, 1692, + 1694, 1696, 1698, 1700, 1702, 1704, 1706, 1708, 1710, 1712, + 1714, 1716, 1718, 1720, 1722, 1724, 1726, 1728, 1733, 1738, + 1743, 1749, 1752, 1754, 1756, 1758, 1760, 1762, 1764, 1766, + 1768, 1770, 1772, 1774, 1776, 1778, 1780, 1782, 1784, 1789, + 1794, 1799, 1804, 1809, 1814, 1819, 1824, 1829, 1834, 1839, + 1844, 1849, 1854, 1860, 1863, 1865, 1867, 1869, 1871, 1873, + 1875, 1877, 1879, 1884, 1889, 1894, 1899, 1904 +}; + +/* YYRHS -- A `-1'-separated list of the rules' RHS. */ +static const yytype_int16 yyrhs[] = +{ + 221, 0, -1, -1, 221, 222, -1, 254, -1, 260, + -1, 274, -1, 477, -1, 292, -1, 310, -1, 324, + -1, 232, -1, 494, -1, 339, -1, 346, -1, 350, + -1, 360, -1, 369, -1, 389, -1, 399, -1, 405, + -1, 419, -1, 409, -1, 227, -1, 1, 215, -1, + 1, 216, -1, -1, 224, -1, 99, 223, -1, 99, + 138, 223, -1, 99, 139, 223, -1, 99, 140, 223, + -1, 99, 141, 223, -1, 99, 142, 223, -1, -1, + 226, -1, 99, 225, -1, 99, 9, 225, -1, 99, + 10, 225, -1, 99, 11, 225, -1, 88, 217, 228, + 216, 215, -1, 228, 229, -1, 229, -1, 230, -1, + 231, -1, 1, 215, -1, 87, 218, 118, 215, -1, + 113, 218, 118, 215, -1, 146, 217, 233, 216, 215, + -1, 233, 234, -1, 234, -1, 245, -1, 250, -1, + 253, -1, 247, -1, 248, -1, 249, -1, 252, -1, + 243, -1, 242, -1, 251, -1, 246, -1, 241, -1, + 235, -1, 236, -1, 244, -1, 1, 215, -1, 132, + 218, 237, 215, -1, 133, 218, 239, 215, -1, 237, + 219, 238, -1, 238, -1, 134, -1, 135, -1, 239, + 219, 240, -1, 240, -1, 134, -1, 135, -1, 130, + 218, 118, 215, -1, 128, 218, 118, 215, -1, 131, + 218, 118, 215, -1, 171, 218, 118, 215, -1, 89, + 218, 118, 215, -1, 147, 218, 118, 215, -1, 24, + 218, 118, 215, -1, 92, 218, 118, 215, -1, 91, + 218, 118, 215, -1, 209, 218, 118, 215, -1, 210, + 218, 118, 215, -1, 181, 218, 99, 215, -1, 57, + 218, 160, 215, -1, 4, 217, 255, 216, 215, -1, + 255, 256, -1, 256, -1, 257, -1, 259, -1, 258, + -1, 1, 215, -1, 89, 218, 118, 215, -1, 31, + 218, 118, 215, -1, 24, 218, 118, 215, -1, 71, + 217, 261, 216, 215, -1, 261, 262, -1, 262, -1, + 263, -1, 264, -1, 1, 215, -1, 208, 218, 160, + 215, -1, -1, 265, 214, 217, 266, 216, 215, -1, + 266, 267, -1, 267, -1, 268, -1, 270, -1, 269, + -1, 1, 215, -1, 89, 218, 118, 215, -1, 213, + 218, 226, 215, -1, 213, 218, 195, 215, -1, -1, + 151, 271, 218, 272, 215, -1, 272, 219, 273, -1, + 273, -1, 206, -1, 102, -1, 40, -1, 174, -1, + 64, -1, 62, -1, 173, -1, -1, 102, 275, 217, + 276, 216, 215, -1, 276, 277, -1, 277, -1, 278, + -1, 279, -1, 280, -1, 284, -1, 283, -1, 281, + -1, 282, -1, 288, -1, 1, 215, -1, 89, 218, + 118, 215, -1, 206, 218, 118, 215, -1, 112, 218, + 118, 215, -1, 32, 218, 160, 215, -1, 129, 218, + 118, 215, -1, 17, 218, 118, 215, -1, -1, 192, + 285, 218, 286, 215, -1, 286, 219, 287, -1, 287, + -1, 166, -1, 169, -1, 170, -1, 172, -1, 173, + -1, 176, -1, 51, -1, 189, -1, 182, -1, 185, + -1, 193, -1, 190, -1, 175, -1, 183, -1, 187, + -1, 177, -1, 199, -1, 167, -1, 168, -1, 180, + -1, -1, 36, 289, 218, 290, 215, -1, 290, 219, + 291, -1, 291, -1, 47, -1, 125, -1, 64, -1, + 205, -1, 174, -1, 194, -1, 211, -1, 40, -1, + 25, -1, 200, -1, 124, -1, 4, -1, 94, -1, + 183, -1, 198, -1, 106, -1, 126, -1, 188, -1, + 87, -1, -1, 17, 293, 217, 294, 216, 215, -1, + 294, 295, -1, 295, -1, 296, -1, 307, -1, 308, + -1, 297, -1, 298, -1, 309, -1, 299, -1, 300, + -1, 301, -1, 302, -1, 303, -1, 304, -1, 305, + -1, 306, -1, 1, 215, -1, 89, 218, 118, 215, + -1, 115, 218, 224, 215, -1, 116, 218, 224, 215, + -1, 101, 218, 99, 215, -1, 19, 218, 224, 215, + -1, 81, 218, 99, 215, -1, 76, 218, 99, 215, + -1, 78, 218, 99, 215, -1, 77, 218, 99, 215, + -1, 143, 218, 226, 215, -1, 184, 218, 226, 215, + -1, 15, 218, 99, 215, -1, 16, 218, 99, 215, + -1, 100, 218, 99, 215, -1, -1, 70, 311, 217, + 316, 216, 215, -1, -1, 36, 313, 218, 314, 215, + -1, 314, 219, 315, -1, 315, -1, 191, -1, 51, + -1, 186, -1, 316, 317, -1, 317, -1, 318, -1, + 312, -1, 322, -1, 323, -1, 1, 215, -1, -1, + 117, 218, 320, 319, 215, -1, 320, 219, 321, -1, + 321, -1, 99, -1, 99, 164, 99, -1, 61, 218, + 118, 215, -1, 56, 218, 118, 215, -1, -1, 48, + 325, 217, 326, 216, 215, -1, 326, 327, -1, 327, + -1, 328, -1, 329, -1, 330, -1, 332, -1, 336, + -1, 337, -1, 338, -1, 331, -1, 1, 215, -1, + 206, 218, 118, 215, -1, 112, 218, 118, 215, -1, + 17, 218, 118, 215, -1, 32, 218, 160, 215, -1, + -1, 36, 333, 218, 334, 215, -1, 334, 219, 335, + -1, 335, -1, 154, -1, 33, -1, 65, -1, 49, + -1, 13, -1, 98, -1, 43, -1, 137, -1, 90, + -1, 153, 218, 118, 215, -1, 122, 218, 118, 215, + -1, 121, 218, 99, 215, -1, -1, 136, 340, 217, + 341, 216, 215, -1, 341, 342, -1, 342, -1, 343, + -1, 344, -1, 345, -1, 1, 215, -1, 120, 218, + 118, 215, -1, 14, 218, 118, 215, -1, 93, 218, + 118, 215, -1, 201, 217, 347, 216, 215, -1, 347, + 348, -1, 348, -1, 349, -1, 1, -1, 89, 218, + 118, 215, -1, -1, 149, 351, 217, 352, 216, 215, + -1, 352, 353, -1, 353, -1, 354, -1, 355, -1, + 356, -1, 1, 215, -1, 89, 218, 118, 215, -1, + 206, 218, 118, 215, -1, -1, 151, 357, 218, 358, + 215, -1, 358, 219, 359, -1, 359, -1, 64, -1, + 205, -1, 174, -1, 194, -1, 211, -1, 197, -1, + 136, -1, 196, -1, 180, -1, 165, -1, -1, 150, + 361, 217, 362, 216, 215, -1, 362, 363, -1, 363, + -1, 364, -1, 365, -1, 1, 215, -1, 89, 218, + 118, 215, -1, -1, 151, 366, 218, 367, 215, -1, + 367, 219, 368, -1, 368, -1, 64, -1, 205, -1, + 174, -1, 194, -1, 211, -1, 197, -1, 136, -1, + 196, -1, 180, -1, 165, -1, -1, 18, 370, 217, + 371, 216, 215, -1, 371, 372, -1, 372, -1, 373, + -1, 374, -1, 375, -1, 376, -1, 377, -1, 379, + -1, 378, -1, 388, -1, 380, -1, 385, -1, 386, + -1, 387, -1, 384, -1, 1, 215, -1, 89, 218, + 118, 215, -1, 56, 218, 118, 215, -1, 209, 218, + 118, 215, -1, 144, 218, 118, 215, -1, 3, 218, + 118, 215, -1, 117, 218, 99, 215, -1, 5, 218, + 178, 215, -1, 5, 218, 179, 215, -1, -1, 36, + 381, 218, 382, 215, -1, 382, 219, 383, -1, 383, + -1, 8, -1, 191, -1, 32, 218, 160, 215, -1, + 58, 218, 118, 215, -1, 68, 218, 118, 215, -1, + 17, 218, 118, 215, -1, 171, 218, 118, 215, -1, + -1, 62, 390, 217, 395, 216, 215, -1, -1, 151, + 392, 218, 393, 215, -1, 393, 219, 394, -1, 394, + -1, 123, -1, 395, 396, -1, 396, -1, 397, -1, + 398, -1, 391, -1, 1, -1, 206, 218, 118, 215, + -1, 120, 218, 118, 215, -1, -1, 23, 400, 217, + 401, 216, 215, -1, 401, 402, -1, 402, -1, 403, + -1, 404, -1, 1, -1, 61, 218, 118, 215, -1, + 120, 218, 118, 215, -1, 34, 217, 406, 216, 215, + -1, 406, 407, -1, 407, -1, 408, -1, 1, -1, + 61, 218, 118, 215, -1, -1, 38, 410, 217, 415, + 216, 215, -1, -1, 151, 412, 218, 413, 215, -1, + 413, 219, 414, -1, 414, -1, 123, -1, 415, 416, + -1, 416, -1, 417, -1, 418, -1, 411, -1, 1, + -1, 89, 218, 118, 215, -1, 120, 218, 118, 215, + -1, 39, 217, 420, 216, 215, -1, 420, 421, -1, + 421, -1, 430, -1, 431, -1, 433, -1, 434, -1, + 435, -1, 436, -1, 437, -1, 438, -1, 439, -1, + 440, -1, 429, -1, 442, -1, 443, -1, 458, -1, + 445, -1, 447, -1, 449, -1, 448, -1, 452, -1, + 446, -1, 453, -1, 454, -1, 455, -1, 456, -1, + 457, -1, 470, -1, 459, -1, 460, -1, 461, -1, + 466, -1, 450, -1, 451, -1, 476, -1, 474, -1, + 475, -1, 432, -1, 465, -1, 441, -1, 463, -1, + 464, -1, 428, -1, 423, -1, 424, -1, 425, -1, + 426, -1, 427, -1, 444, -1, 422, -1, 462, -1, + 1, -1, 83, 218, 99, 215, -1, 42, 218, 160, + 215, -1, 41, 218, 224, 215, -1, 44, 218, 224, + 215, -1, 45, 218, 99, 215, -1, 46, 218, 99, + 215, -1, 148, 218, 160, 215, -1, 63, 218, 224, + 215, -1, 55, 218, 160, 215, -1, 59, 218, 160, + 215, -1, 28, 218, 160, 215, -1, 35, 218, 160, + 215, -1, 6, 218, 160, 215, -1, 80, 218, 224, + 215, -1, 79, 218, 99, 215, -1, 72, 218, 99, + 215, -1, 7, 218, 224, 215, -1, 163, 218, 224, + 215, -1, 162, 218, 224, 215, -1, 50, 218, 99, + 215, -1, 60, 218, 160, 215, -1, 212, 218, 160, + 215, -1, 155, 218, 160, 215, -1, 158, 218, 160, + 215, -1, 159, 218, 160, 215, -1, 157, 218, 160, + 215, -1, 157, 218, 161, 215, -1, 156, 218, 160, + 215, -1, 156, 218, 161, 215, -1, 110, 218, 224, + 215, -1, 12, 218, 224, 215, -1, 103, 218, 160, + 215, -1, 111, 218, 224, 215, -1, 152, 218, 160, + 215, -1, 97, 218, 160, 215, -1, 204, 218, 160, + 215, -1, 105, 218, 160, 215, -1, 84, 218, 118, + 215, -1, 29, 218, 99, 215, -1, 82, 218, 99, + 215, -1, 207, 218, 160, 215, -1, 30, 218, 118, + 215, -1, 202, 218, 118, 215, -1, 114, 218, 160, + 215, -1, 26, 218, 160, 215, -1, 203, 218, 224, + 215, -1, -1, 107, 467, 218, 468, 215, -1, 468, + 219, 469, -1, 469, -1, 166, -1, 169, -1, 170, + -1, 172, -1, 173, -1, 176, -1, 51, -1, 189, + -1, 182, -1, 185, -1, 193, -1, 190, -1, 175, + -1, 183, -1, 187, -1, 177, -1, 199, -1, 167, + -1, 168, -1, 180, -1, -1, 104, 471, 218, 472, + 215, -1, 472, 219, 473, -1, 473, -1, 166, -1, + 169, -1, 170, -1, 172, -1, 173, -1, 176, -1, + 189, -1, 51, -1, 182, -1, 185, -1, 193, -1, + 190, -1, 175, -1, 183, -1, 187, -1, 177, -1, + 199, -1, 167, -1, 168, -1, 180, -1, 85, 218, + 99, 215, -1, 86, 218, 99, 215, -1, 20, 218, + 99, 215, -1, 14, 217, 478, 216, 215, -1, 478, + 479, -1, 479, -1, 487, -1, 482, -1, 483, -1, + 484, -1, 485, -1, 486, -1, 488, -1, 489, -1, + 490, -1, 481, -1, 491, -1, 492, -1, 493, -1, + 480, -1, 1, -1, 27, 218, 160, 215, -1, 127, + 218, 160, 215, -1, 66, 218, 224, 215, -1, 67, + 218, 224, 215, -1, 75, 218, 99, 215, -1, 74, + 218, 99, 215, -1, 119, 218, 160, 215, -1, 73, + 218, 99, 215, -1, 22, 218, 99, 215, -1, 21, + 218, 99, 215, -1, 95, 218, 160, 215, -1, 96, + 218, 160, 215, -1, 108, 218, 99, 215, -1, 109, + 218, 224, 215, -1, 145, 217, 495, 216, 215, -1, + 495, 496, -1, 496, -1, 497, -1, 498, -1, 500, + -1, 501, -1, 499, -1, 502, -1, 1, -1, 37, + 218, 160, 215, -1, 54, 218, 160, 215, -1, 52, + 218, 118, 215, -1, 69, 218, 224, 215, -1, 51, + 218, 160, 215, -1, 53, 218, 160, 215, -1 +}; + +/* YYRLINE[YYN] -- source line where rule number YYN was defined. */ +static const yytype_uint16 yyrline[] = +{ + 0, 330, 330, 331, 334, 335, 336, 337, 338, 339, + 340, 341, 342, 343, 344, 345, 346, 347, 348, 349, + 350, 351, 352, 353, 354, 355, 359, 359, 360, 364, + 368, 372, 376, 380, 386, 386, 387, 388, 389, 390, + 397, 400, 400, 401, 401, 401, 403, 409, 416, 418, + 418, 419, 419, 420, 420, 421, 421, 422, 422, 423, + 423, 424, 424, 425, 425, 426, 427, 430, 431, 433, + 433, 434, 440, 448, 448, 449, 455, 463, 502, 561, + 589, 597, 612, 627, 636, 650, 659, 687, 717, 740, + 749, 751, 751, 752, 752, 753, 753, 755, 764, 773, + 785, 786, 786, 788, 788, 789, 791, 798, 798, 808, + 809, 811, 811, 812, 812, 814, 819, 822, 828, 827, + 833, 833, 834, 838, 842, 846, 850, 854, 858, 869, + 868, 966, 966, 967, 967, 967, 968, 968, 968, 969, + 969, 969, 971, 980, 1017, 1029, 1040, 1082, 1092, 1091, + 1097, 1097, 1098, 1102, 1106, 1110, 1114, 1118, 1122, 1126, + 1130, 1134, 1138, 1142, 1146, 1150, 1154, 1158, 1162, 1166, + 1170, 1174, 1181, 1180, 1186, 1186, 1187, 1191, 1195, 1199, + 1203, 1207, 1211, 1215, 1219, 1223, 1227, 1231, 1235, 1239, + 1243, 1247, 1251, 1255, 1259, 1270, 1269, 1319, 1319, 1320, + 1321, 1321, 1322, 1323, 1324, 1325, 1326, 1327, 1328, 1329, + 1330, 1331, 1331, 1332, 1334, 1343, 1349, 1355, 1361, 1367, + 1373, 1379, 1385, 1391, 1397, 1404, 1410, 1416, 1426, 1425, + 1442, 1441, 1446, 1446, 1447, 1451, 1455, 1463, 1463, 1464, + 1464, 1464, 1464, 1464, 1466, 1466, 1468, 1468, 1470, 1484, + 1504, 1513, 1526, 1525, 1594, 1594, 1595, 1595, 1595, 1595, + 1596, 1596, 1596, 1597, 1597, 1599, 1634, 1647, 1656, 1668, + 1667, 1671, 1671, 1672, 1676, 1680, 1684, 1688, 1692, 1696, + 1700, 1704, 1710, 1729, 1739, 1753, 1752, 1768, 1768, 1769, + 1769, 1769, 1769, 1771, 1780, 1795, 1808, 1810, 1810, 1811, + 1811, 1813, 1829, 1828, 1844, 1844, 1845, 1845, 1845, 1845, + 1847, 1856, 1879, 1878, 1884, 1884, 1885, 1889, 1893, 1897, + 1901, 1905, 1909, 1913, 1917, 1921, 1931, 1930, 1947, 1947, + 1948, 1948, 1948, 1950, 1957, 1956, 1962, 1962, 1963, 1967, + 1971, 1975, 1979, 1983, 1987, 1991, 1995, 1999, 2009, 2008, + 2059, 2059, 2060, 2060, 2060, 2061, 2061, 2062, 2062, 2062, + 2063, 2063, 2063, 2064, 2064, 2065, 2067, 2076, 2085, 2111, + 2129, 2147, 2153, 2157, 2166, 2165, 2169, 2169, 2170, 2174, + 2180, 2191, 2202, 2213, 2222, 2241, 2240, 2306, 2305, 2309, + 2309, 2310, 2316, 2316, 2317, 2317, 2317, 2317, 2319, 2338, + 2348, 2347, 2372, 2372, 2373, 2373, 2373, 2375, 2381, 2390, + 2392, 2392, 2393, 2393, 2395, 2414, 2413, 2461, 2460, 2464, + 2464, 2465, 2471, 2471, 2472, 2472, 2472, 2472, 2474, 2480, + 2489, 2492, 2492, 2493, 2493, 2494, 2494, 2495, 2495, 2496, + 2496, 2497, 2497, 2498, 2499, 2500, 2500, 2501, 2501, 2502, + 2502, 2503, 2503, 2504, 2504, 2505, 2505, 2506, 2507, 2507, + 2508, 2508, 2509, 2509, 2510, 2510, 2511, 2511, 2512, 2513, + 2513, 2514, 2515, 2516, 2516, 2517, 2517, 2518, 2519, 2520, + 2521, 2521, 2522, 2525, 2530, 2536, 2542, 2548, 2553, 2558, + 2563, 2568, 2573, 2578, 2583, 2588, 2593, 2598, 2603, 2608, + 2613, 2618, 2624, 2635, 2640, 2645, 2650, 2655, 2660, 2663, + 2668, 2671, 2676, 2681, 2686, 2691, 2696, 2701, 2706, 2711, + 2716, 2727, 2732, 2737, 2742, 2751, 2760, 2765, 2770, 2776, + 2775, 2780, 2780, 2781, 2784, 2787, 2790, 2793, 2796, 2799, + 2802, 2805, 2808, 2811, 2814, 2817, 2820, 2823, 2826, 2829, + 2832, 2835, 2838, 2844, 2843, 2848, 2848, 2849, 2852, 2855, + 2858, 2861, 2864, 2867, 2870, 2873, 2876, 2879, 2882, 2885, + 2888, 2891, 2894, 2897, 2900, 2903, 2906, 2911, 2916, 2921, + 2930, 2933, 2933, 2934, 2935, 2935, 2936, 2936, 2937, 2937, + 2938, 2939, 2939, 2940, 2941, 2941, 2942, 2942, 2944, 2949, + 2954, 2959, 2964, 2969, 2974, 2979, 2984, 2989, 2994, 2999, + 3004, 3009, 3017, 3020, 3020, 3021, 3021, 3022, 3023, 3023, + 3024, 3025, 3027, 3033, 3039, 3048, 3062, 3068 +}; +#endif + +#if YYDEBUG || YYERROR_VERBOSE || 0 +/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. + First, the terminals, then, starting at YYNTOKENS, nonterminals. */ +static const char *const yytname[] = +{ + "$end", "error", "$undefined", "ACCEPT_PASSWORD", "ADMIN", "AFTYPE", + "ANTI_NICK_FLOOD", "ANTI_SPAM_EXIT_MESSAGE_TIME", "AUTOCONN", "BYTES", + "KBYTES", "MBYTES", "CALLER_ID_WAIT", "CAN_FLOOD", "CHANNEL", + "CIDR_BITLEN_IPV4", "CIDR_BITLEN_IPV6", "CLASS", "CONNECT", + "CONNECTFREQ", "DEFAULT_FLOODCOUNT", "DEFAULT_SPLIT_SERVER_COUNT", + "DEFAULT_SPLIT_USER_COUNT", "DENY", "DESCRIPTION", "DIE", "DISABLE_AUTH", + "DISABLE_FAKE_CHANNELS", "DISABLE_REMOTE_COMMANDS", "DOTS_IN_IDENT", + "EGDPOOL_PATH", "EMAIL", "ENCRYPTED", "EXCEED_LIMIT", "EXEMPT", + "FAILED_OPER_NOTICE", "IRCD_FLAGS", "FLATTEN_LINKS", "GECOS", "GENERAL", + "GLINE", "GLINE_DURATION", "GLINE_ENABLE", "GLINE_EXEMPT", + "GLINE_REQUEST_DURATION", "GLINE_MIN_CIDR", "GLINE_MIN_CIDR6", + "GLOBAL_KILL", "IRCD_AUTH", "NEED_IDENT", "HAVENT_READ_CONF", "HIDDEN", + "HIDDEN_NAME", "HIDE_SERVER_IPS", "HIDE_SERVERS", "HIDE_SPOOF_IPS", + "HOST", "HUB", "HUB_MASK", "IGNORE_BOGUS_TS", "INVISIBLE_ON_CONNECT", + "IP", "KILL", "KILL_CHASE_TIME_LIMIT", "KLINE", "KLINE_EXEMPT", + "KNOCK_DELAY", "KNOCK_DELAY_CHANNEL", "LEAF_MASK", "LINKS_DELAY", + "LISTEN", "T_LOG", "MAX_ACCEPT", "MAX_BANS", "MAX_CHANS_PER_OPER", + "MAX_CHANS_PER_USER", "MAX_GLOBAL", "MAX_IDENT", "MAX_LOCAL", + "MAX_NICK_CHANGES", "MAX_NICK_TIME", "MAX_NUMBER", "MAX_TARGETS", + "MAX_WATCH", "MESSAGE_LOCALE", "MIN_NONWILDCARD", + "MIN_NONWILDCARD_SIMPLE", "MODULE", "MODULES", "NAME", "NEED_PASSWORD", + "NETWORK_DESC", "NETWORK_NAME", "NICK", "NICK_CHANGES", + "NO_CREATE_ON_SPLIT", "NO_JOIN_ON_SPLIT", "NO_OPER_FLOOD", "NO_TILDE", + "NUMBER", "NUMBER_PER_CIDR", "NUMBER_PER_IP", "OPERATOR", + "OPERS_BYPASS_CALLERID", "OPER_ONLY_UMODES", "OPER_PASS_RESV", + "OPER_SPY_T", "OPER_UMODES", "JOIN_FLOOD_COUNT", "JOIN_FLOOD_TIME", + "PACE_WAIT", "PACE_WAIT_SIMPLE", "PASSWORD", "PATH", "PING_COOKIE", + "PING_TIME", "PING_WARNING", "PORT", "QSTRING", "QUIET_ON_BAN", "REASON", + "REDIRPORT", "REDIRSERV", "REGEX_T", "REHASH", "REMOTE", "REMOTEBAN", + "RESTRICT_CHANNELS", "RSA_PRIVATE_KEY_FILE", "RSA_PUBLIC_KEY_FILE", + "SSL_CERTIFICATE_FILE", "SSL_DH_PARAM_FILE", "T_SSL_CLIENT_METHOD", + "T_SSL_SERVER_METHOD", "T_SSLV3", "T_TLSV1", "RESV", "RESV_EXEMPT", + "SECONDS", "MINUTES", "HOURS", "DAYS", "WEEKS", "SENDQ", "SEND_PASSWORD", + "SERVERHIDE", "SERVERINFO", "IRCD_SID", "TKLINE_EXPIRE_NOTICES", + "T_SHARED", "T_CLUSTER", "TYPE", "SHORT_MOTD", "SPOOF", "SPOOF_NOTICE", + "STATS_E_DISABLED", "STATS_I_OPER_ONLY", "STATS_K_OPER_ONLY", + "STATS_O_OPER_ONLY", "STATS_P_OPER_ONLY", "TBOOL", "TMASKED", + "TS_MAX_DELTA", "TS_WARN_DELTA", "TWODOTS", "T_ALL", "T_BOTS", + "T_SOFTCALLERID", "T_CALLERID", "T_CCONN", "T_CCONN_FULL", + "T_SSL_CIPHER_LIST", "T_DEAF", "T_DEBUG", "T_DLINE", "T_EXTERNAL", + "T_FULL", "T_INVISIBLE", "T_IPV4", "T_IPV6", "T_LOCOPS", "T_MAX_CLIENTS", + "T_NCHANGE", "T_OPERWALL", "T_RECVQ", "T_REJ", "T_SERVER", + "T_SERVNOTICE", "T_SET", "T_SKILL", "T_SPY", "T_SSL", "T_UMODES", + "T_UNAUTH", "T_UNDLINE", "T_UNLIMITED", "T_UNRESV", "T_UNXLINE", + "T_GLOBOPS", "T_WALLOP", "T_RESTART", "T_SERVICE", "T_SERVICES_NAME", + "THROTTLE_TIME", "TRUE_NO_OPER_FLOOD", "UNKLINE", "USER", "USE_EGD", + "USE_LOGGING", "VHOST", "VHOST6", "XLINE", "WARN_NO_NLINE", "T_SIZE", + "T_FILE", "';'", "'}'", "'{'", "'='", "','", "$accept", "conf", + "conf_item", "timespec_", "timespec", "sizespec_", "sizespec", + "modules_entry", "modules_items", "modules_item", "modules_module", + "modules_path", "serverinfo_entry", "serverinfo_items", + "serverinfo_item", "serverinfo_ssl_client_method", + "serverinfo_ssl_server_method", "client_method_types", + "client_method_type_item", "server_method_types", + "server_method_type_item", "serverinfo_ssl_certificate_file", + "serverinfo_rsa_private_key_file", "serverinfo_ssl_dh_param_file", + "serverinfo_ssl_cipher_list", "serverinfo_name", "serverinfo_sid", + "serverinfo_description", "serverinfo_network_name", + "serverinfo_network_desc", "serverinfo_vhost", "serverinfo_vhost6", + "serverinfo_max_clients", "serverinfo_hub", "admin_entry", "admin_items", + "admin_item", "admin_name", "admin_email", "admin_description", + "logging_entry", "logging_items", "logging_item", "logging_use_logging", + "logging_file_entry", "$@1", "logging_file_items", "logging_file_item", + "logging_file_name", "logging_file_size", "logging_file_type", "$@2", + "logging_file_type_items", "logging_file_type_item", "oper_entry", "$@3", + "oper_items", "oper_item", "oper_name", "oper_user", "oper_password", + "oper_encrypted", "oper_rsa_public_key_file", "oper_class", + "oper_umodes", "$@4", "oper_umodes_items", "oper_umodes_item", + "oper_flags", "$@5", "oper_flags_items", "oper_flags_item", + "class_entry", "$@6", "class_items", "class_item", "class_name", + "class_ping_time", "class_ping_warning", "class_number_per_ip", + "class_connectfreq", "class_max_number", "class_max_global", + "class_max_local", "class_max_ident", "class_sendq", "class_recvq", + "class_cidr_bitlen_ipv4", "class_cidr_bitlen_ipv6", + "class_number_per_cidr", "listen_entry", "$@7", "listen_flags", "$@8", + "listen_flags_items", "listen_flags_item", "listen_items", "listen_item", + "listen_port", "$@9", "port_items", "port_item", "listen_address", + "listen_host", "auth_entry", "$@10", "auth_items", "auth_item", + "auth_user", "auth_passwd", "auth_class", "auth_encrypted", "auth_flags", + "$@11", "auth_flags_items", "auth_flags_item", "auth_spoof", + "auth_redir_serv", "auth_redir_port", "resv_entry", "$@12", "resv_items", + "resv_item", "resv_creason", "resv_channel", "resv_nick", + "service_entry", "service_items", "service_item", "service_name", + "shared_entry", "$@13", "shared_items", "shared_item", "shared_name", + "shared_user", "shared_type", "$@14", "shared_types", "shared_type_item", + "cluster_entry", "$@15", "cluster_items", "cluster_item", "cluster_name", + "cluster_type", "$@16", "cluster_types", "cluster_type_item", + "connect_entry", "$@17", "connect_items", "connect_item", "connect_name", + "connect_host", "connect_vhost", "connect_send_password", + "connect_accept_password", "connect_port", "connect_aftype", + "connect_flags", "$@18", "connect_flags_items", "connect_flags_item", + "connect_encrypted", "connect_hub_mask", "connect_leaf_mask", + "connect_class", "connect_ssl_cipher_list", "kill_entry", "$@19", + "kill_type", "$@20", "kill_type_items", "kill_type_item", "kill_items", + "kill_item", "kill_user", "kill_reason", "deny_entry", "$@21", + "deny_items", "deny_item", "deny_ip", "deny_reason", "exempt_entry", + "exempt_items", "exempt_item", "exempt_ip", "gecos_entry", "$@22", + "gecos_flags", "$@23", "gecos_flags_items", "gecos_flags_item", + "gecos_items", "gecos_item", "gecos_name", "gecos_reason", + "general_entry", "general_items", "general_item", "general_max_watch", + "general_gline_enable", "general_gline_duration", + "general_gline_request_duration", "general_gline_min_cidr", + "general_gline_min_cidr6", "general_tkline_expire_notices", + "general_kill_chase_time_limit", "general_hide_spoof_ips", + "general_ignore_bogus_ts", "general_disable_remote_commands", + "general_failed_oper_notice", "general_anti_nick_flood", + "general_max_nick_time", "general_max_nick_changes", + "general_max_accept", "general_anti_spam_exit_message_time", + "general_ts_warn_delta", "general_ts_max_delta", + "general_havent_read_conf", "general_invisible_on_connect", + "general_warn_no_nline", "general_stats_e_disabled", + "general_stats_o_oper_only", "general_stats_P_oper_only", + "general_stats_k_oper_only", "general_stats_i_oper_only", + "general_pace_wait", "general_caller_id_wait", + "general_opers_bypass_callerid", "general_pace_wait_simple", + "general_short_motd", "general_no_oper_flood", + "general_true_no_oper_flood", "general_oper_pass_resv", + "general_message_locale", "general_dots_in_ident", "general_max_targets", + "general_use_egd", "general_egdpool_path", "general_services_name", + "general_ping_cookie", "general_disable_auth", "general_throttle_time", + "general_oper_umodes", "$@24", "umode_oitems", "umode_oitem", + "general_oper_only_umodes", "$@25", "umode_items", "umode_item", + "general_min_nonwildcard", "general_min_nonwildcard_simple", + "general_default_floodcount", "channel_entry", "channel_items", + "channel_item", "channel_disable_fake_channels", + "channel_restrict_channels", "channel_knock_delay", + "channel_knock_delay_channel", "channel_max_chans_per_user", + "channel_max_chans_per_oper", "channel_quiet_on_ban", "channel_max_bans", + "channel_default_split_user_count", "channel_default_split_server_count", + "channel_no_create_on_split", "channel_no_join_on_split", + "channel_jflood_count", "channel_jflood_time", "serverhide_entry", + "serverhide_items", "serverhide_item", "serverhide_flatten_links", + "serverhide_hide_servers", "serverhide_hidden_name", + "serverhide_links_delay", "serverhide_hidden", + "serverhide_hide_server_ips", YY_NULL +}; +#endif + +# ifdef YYPRINT +/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to + token YYLEX-NUM. */ +static const yytype_uint16 yytoknum[] = +{ + 0, 256, 257, 258, 259, 260, 261, 262, 263, 264, + 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, + 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, + 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, + 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, + 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, + 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, + 325, 326, 327, 328, 329, 330, 331, 332, 333, 334, + 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, + 345, 346, 347, 348, 349, 350, 351, 352, 353, 354, + 355, 356, 357, 358, 359, 360, 361, 362, 363, 364, + 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, + 375, 376, 377, 378, 379, 380, 381, 382, 383, 384, + 385, 386, 387, 388, 389, 390, 391, 392, 393, 394, + 395, 396, 397, 398, 399, 400, 401, 402, 403, 404, + 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, + 415, 416, 417, 418, 419, 420, 421, 422, 423, 424, + 425, 426, 427, 428, 429, 430, 431, 432, 433, 434, + 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, + 445, 446, 447, 448, 449, 450, 451, 452, 453, 454, + 455, 456, 457, 458, 459, 460, 461, 462, 463, 464, + 465, 466, 467, 468, 469, 59, 125, 123, 61, 44 +}; +# endif + +/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ +static const yytype_uint16 yyr1[] = +{ + 0, 220, 221, 221, 222, 222, 222, 222, 222, 222, + 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, + 222, 222, 222, 222, 222, 222, 223, 223, 224, 224, + 224, 224, 224, 224, 225, 225, 226, 226, 226, 226, + 227, 228, 228, 229, 229, 229, 230, 231, 232, 233, + 233, 234, 234, 234, 234, 234, 234, 234, 234, 234, + 234, 234, 234, 234, 234, 234, 234, 235, 236, 237, + 237, 238, 238, 239, 239, 240, 240, 241, 242, 243, + 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, + 254, 255, 255, 256, 256, 256, 256, 257, 258, 259, + 260, 261, 261, 262, 262, 262, 263, 265, 264, 266, + 266, 267, 267, 267, 267, 268, 269, 269, 271, 270, + 272, 272, 273, 273, 273, 273, 273, 273, 273, 275, + 274, 276, 276, 277, 277, 277, 277, 277, 277, 277, + 277, 277, 278, 279, 280, 281, 282, 283, 285, 284, + 286, 286, 287, 287, 287, 287, 287, 287, 287, 287, + 287, 287, 287, 287, 287, 287, 287, 287, 287, 287, + 287, 287, 289, 288, 290, 290, 291, 291, 291, 291, + 291, 291, 291, 291, 291, 291, 291, 291, 291, 291, + 291, 291, 291, 291, 291, 293, 292, 294, 294, 295, + 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, + 295, 295, 295, 295, 296, 297, 298, 299, 300, 301, + 302, 303, 304, 305, 306, 307, 308, 309, 311, 310, + 313, 312, 314, 314, 315, 315, 315, 316, 316, 317, + 317, 317, 317, 317, 319, 318, 320, 320, 321, 321, + 322, 323, 325, 324, 326, 326, 327, 327, 327, 327, + 327, 327, 327, 327, 327, 328, 329, 330, 331, 333, + 332, 334, 334, 335, 335, 335, 335, 335, 335, 335, + 335, 335, 336, 337, 338, 340, 339, 341, 341, 342, + 342, 342, 342, 343, 344, 345, 346, 347, 347, 348, + 348, 349, 351, 350, 352, 352, 353, 353, 353, 353, + 354, 355, 357, 356, 358, 358, 359, 359, 359, 359, + 359, 359, 359, 359, 359, 359, 361, 360, 362, 362, + 363, 363, 363, 364, 366, 365, 367, 367, 368, 368, + 368, 368, 368, 368, 368, 368, 368, 368, 370, 369, + 371, 371, 372, 372, 372, 372, 372, 372, 372, 372, + 372, 372, 372, 372, 372, 372, 373, 374, 375, 376, + 377, 378, 379, 379, 381, 380, 382, 382, 383, 383, + 384, 385, 386, 387, 388, 390, 389, 392, 391, 393, + 393, 394, 395, 395, 396, 396, 396, 396, 397, 398, + 400, 399, 401, 401, 402, 402, 402, 403, 404, 405, + 406, 406, 407, 407, 408, 410, 409, 412, 411, 413, + 413, 414, 415, 415, 416, 416, 416, 416, 417, 418, + 419, 420, 420, 421, 421, 421, 421, 421, 421, 421, + 421, 421, 421, 421, 421, 421, 421, 421, 421, 421, + 421, 421, 421, 421, 421, 421, 421, 421, 421, 421, + 421, 421, 421, 421, 421, 421, 421, 421, 421, 421, + 421, 421, 421, 421, 421, 421, 421, 421, 421, 421, + 421, 421, 421, 422, 423, 424, 425, 426, 427, 428, + 429, 430, 431, 432, 433, 434, 435, 436, 437, 438, + 439, 440, 441, 442, 443, 444, 445, 446, 447, 447, + 448, 448, 449, 450, 451, 452, 453, 454, 455, 456, + 457, 458, 459, 460, 461, 462, 463, 464, 465, 467, + 466, 468, 468, 469, 469, 469, 469, 469, 469, 469, + 469, 469, 469, 469, 469, 469, 469, 469, 469, 469, + 469, 469, 469, 471, 470, 472, 472, 473, 473, 473, + 473, 473, 473, 473, 473, 473, 473, 473, 473, 473, + 473, 473, 473, 473, 473, 473, 473, 474, 475, 476, + 477, 478, 478, 479, 479, 479, 479, 479, 479, 479, + 479, 479, 479, 479, 479, 479, 479, 479, 480, 481, + 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, + 492, 493, 494, 495, 495, 496, 496, 496, 496, 496, + 496, 496, 497, 498, 499, 500, 501, 502 +}; + +/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */ +static const yytype_uint8 yyr2[] = +{ + 0, 2, 0, 2, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 2, 2, 0, 1, 2, 3, + 3, 3, 3, 3, 0, 1, 2, 3, 3, 3, + 5, 2, 1, 1, 1, 2, 4, 4, 5, 2, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 2, 4, 4, 3, + 1, 1, 1, 3, 1, 1, 1, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 5, 2, 1, 1, 1, 1, 2, 4, 4, 4, + 5, 2, 1, 1, 1, 2, 4, 0, 6, 2, + 1, 1, 1, 1, 2, 4, 4, 4, 0, 5, + 3, 1, 1, 1, 1, 1, 1, 1, 1, 0, + 6, 2, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 2, 4, 4, 4, 4, 4, 4, 0, 5, + 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 0, 5, 3, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 0, 6, 2, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 2, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 0, 6, + 0, 5, 3, 1, 1, 1, 1, 2, 1, 1, + 1, 1, 1, 2, 0, 5, 3, 1, 1, 3, + 4, 4, 0, 6, 2, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 2, 4, 4, 4, 4, 0, + 5, 3, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 4, 4, 4, 0, 6, 2, 1, 1, + 1, 1, 2, 4, 4, 4, 5, 2, 1, 1, + 1, 4, 0, 6, 2, 1, 1, 1, 1, 2, + 4, 4, 0, 5, 3, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 0, 6, 2, 1, + 1, 1, 2, 4, 0, 5, 3, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 0, 6, + 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 2, 4, 4, 4, 4, + 4, 4, 4, 4, 0, 5, 3, 1, 1, 1, + 4, 4, 4, 4, 4, 0, 6, 0, 5, 3, + 1, 1, 2, 1, 1, 1, 1, 1, 4, 4, + 0, 6, 2, 1, 1, 1, 1, 4, 4, 5, + 2, 1, 1, 1, 4, 0, 6, 0, 5, 3, + 1, 1, 2, 1, 1, 1, 1, 1, 4, 4, + 5, 2, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, + 5, 3, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 0, 5, 3, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 4, 4, 4, + 5, 2, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 5, 2, 1, 1, 1, 1, 1, 1, + 1, 1, 4, 4, 4, 4, 4, 4 +}; + +/* YYDEFACT[STATE-NAME] -- Default reduction number in state STATE-NUM. + Performed when YYTABLE doesn't specify something else to do. Zero + means the default is an error. */ +static const yytype_uint16 yydefact[] = +{ + 2, 0, 1, 0, 0, 0, 195, 348, 400, 0, + 415, 0, 252, 385, 228, 0, 0, 129, 285, 0, + 0, 302, 326, 0, 3, 23, 11, 4, 5, 6, + 8, 9, 10, 13, 14, 15, 16, 17, 18, 19, + 20, 22, 21, 7, 12, 24, 25, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 92, 93, 95, 94, 597, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 582, 596, 592, 584, 585, 586, 587, 588, + 583, 589, 590, 591, 593, 594, 595, 0, 0, 0, + 413, 0, 0, 411, 412, 0, 482, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 553, 0, 529, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 432, 480, 474, + 475, 476, 477, 478, 473, 443, 433, 434, 468, 435, + 436, 437, 438, 439, 440, 441, 442, 470, 444, 445, + 479, 447, 452, 448, 450, 449, 463, 464, 451, 453, + 454, 455, 456, 457, 446, 459, 460, 461, 481, 471, + 472, 469, 462, 458, 466, 467, 465, 0, 0, 0, + 0, 0, 0, 102, 103, 104, 0, 0, 0, 0, + 0, 42, 43, 44, 0, 0, 621, 0, 0, 0, + 0, 0, 0, 0, 614, 615, 616, 619, 617, 618, + 620, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 50, 63, + 64, 62, 59, 58, 65, 51, 61, 54, 55, 56, + 52, 60, 57, 53, 0, 0, 300, 0, 0, 298, + 299, 96, 0, 0, 0, 0, 91, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 581, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 198, + 199, 202, 203, 205, 206, 207, 208, 209, 210, 211, + 212, 200, 201, 204, 0, 0, 0, 0, 0, 374, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 351, + 352, 353, 354, 355, 356, 358, 357, 360, 364, 361, + 362, 363, 359, 406, 0, 0, 0, 403, 404, 405, + 0, 0, 410, 427, 0, 0, 417, 426, 0, 423, + 424, 425, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 431, 0, 0, 0, 269, 0, 0, 0, + 0, 0, 0, 255, 256, 257, 258, 263, 259, 260, + 261, 262, 397, 0, 387, 0, 396, 0, 393, 394, + 395, 0, 230, 0, 0, 0, 240, 0, 238, 239, + 241, 242, 105, 0, 0, 101, 0, 45, 0, 0, + 0, 41, 0, 0, 0, 172, 0, 0, 0, 148, + 0, 0, 132, 133, 134, 135, 138, 139, 137, 136, + 140, 0, 0, 0, 0, 0, 288, 289, 290, 291, + 0, 0, 0, 0, 0, 0, 0, 613, 66, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 49, 0, 0, 312, 0, + 0, 305, 306, 307, 308, 0, 0, 334, 0, 329, + 330, 331, 0, 0, 297, 0, 0, 0, 90, 0, + 0, 0, 26, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 580, 213, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 197, 365, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 350, 0, 0, + 0, 402, 0, 409, 0, 0, 0, 0, 422, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 430, 264, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 254, 0, 0, 0, 0, 392, 243, 0, 0, + 0, 0, 0, 237, 0, 100, 0, 0, 0, 40, + 141, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 131, 292, 0, 0, 0, 0, 287, 0, 0, 0, + 0, 0, 0, 612, 0, 0, 0, 0, 0, 0, + 0, 0, 71, 72, 0, 70, 75, 76, 0, 74, + 0, 0, 0, 0, 0, 48, 309, 0, 0, 0, + 0, 304, 332, 0, 0, 0, 328, 0, 296, 99, + 98, 97, 607, 606, 598, 26, 26, 26, 26, 26, + 28, 27, 600, 601, 605, 603, 602, 608, 609, 610, + 611, 604, 599, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 34, 0, 0, 196, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 349, 0, 0, 401, 414, 0, 0, + 0, 416, 495, 499, 513, 579, 527, 493, 521, 524, + 494, 485, 484, 486, 487, 488, 502, 491, 492, 503, + 490, 498, 497, 496, 522, 483, 520, 577, 578, 517, + 514, 564, 557, 574, 575, 558, 559, 560, 561, 569, + 562, 572, 576, 565, 570, 566, 571, 563, 568, 567, + 573, 0, 556, 519, 539, 533, 550, 551, 534, 535, + 536, 537, 545, 538, 548, 552, 541, 546, 542, 547, + 540, 544, 543, 549, 0, 532, 512, 515, 526, 489, + 516, 505, 510, 511, 508, 509, 506, 507, 501, 500, + 525, 528, 518, 523, 504, 0, 0, 0, 0, 0, + 0, 0, 0, 253, 0, 0, 0, 386, 0, 0, + 0, 248, 244, 247, 229, 106, 0, 0, 118, 0, + 0, 110, 111, 113, 112, 46, 47, 0, 0, 0, + 0, 0, 0, 0, 0, 130, 0, 0, 0, 286, + 622, 626, 624, 627, 623, 625, 83, 89, 81, 85, + 84, 78, 77, 79, 67, 0, 68, 0, 82, 80, + 88, 86, 87, 0, 0, 0, 303, 0, 0, 327, + 301, 29, 30, 31, 32, 33, 225, 226, 218, 220, + 222, 221, 219, 214, 227, 217, 215, 216, 34, 34, + 34, 36, 35, 223, 224, 370, 372, 373, 383, 380, + 378, 379, 0, 377, 367, 381, 382, 366, 371, 369, + 384, 368, 407, 408, 428, 429, 421, 0, 420, 554, + 0, 530, 0, 267, 268, 277, 274, 279, 276, 275, + 281, 278, 280, 273, 0, 272, 266, 284, 283, 282, + 265, 399, 391, 0, 390, 398, 235, 236, 234, 0, + 233, 251, 250, 0, 0, 0, 114, 0, 0, 0, + 0, 109, 147, 145, 187, 184, 183, 176, 178, 194, + 188, 191, 186, 177, 192, 180, 189, 193, 181, 190, + 185, 179, 182, 0, 175, 142, 144, 146, 158, 152, + 169, 170, 153, 154, 155, 156, 164, 157, 167, 171, + 160, 165, 161, 166, 159, 163, 162, 168, 0, 151, + 143, 294, 295, 293, 69, 73, 310, 316, 322, 325, + 318, 324, 319, 323, 321, 317, 320, 0, 315, 311, + 333, 338, 344, 347, 340, 346, 341, 345, 343, 339, + 342, 0, 337, 37, 38, 39, 375, 0, 418, 0, + 555, 531, 270, 0, 388, 0, 231, 0, 249, 246, + 245, 0, 0, 0, 0, 108, 173, 0, 149, 0, + 313, 0, 335, 0, 376, 419, 271, 389, 232, 115, + 124, 127, 126, 123, 128, 125, 122, 0, 121, 117, + 116, 174, 150, 314, 336, 119, 0, 120 +}; + +/* YYDEFGOTO[NTERM-NUM]. */ +static const yytype_int16 yydefgoto[] = +{ + -1, 1, 24, 780, 781, 1021, 1022, 25, 230, 231, + 232, 233, 26, 267, 268, 269, 270, 744, 745, 748, + 749, 271, 272, 273, 274, 275, 276, 277, 278, 279, + 280, 281, 282, 283, 27, 71, 72, 73, 74, 75, + 28, 222, 223, 224, 225, 226, 950, 951, 952, 953, + 954, 1088, 1217, 1218, 29, 60, 501, 502, 503, 504, + 505, 506, 507, 508, 509, 717, 1138, 1139, 510, 713, + 1113, 1114, 30, 49, 328, 329, 330, 331, 332, 333, + 334, 335, 336, 337, 338, 339, 340, 341, 342, 343, + 31, 57, 476, 698, 1079, 1080, 477, 478, 479, 1085, + 942, 943, 480, 481, 32, 55, 452, 453, 454, 455, + 456, 457, 458, 684, 1064, 1065, 459, 460, 461, 33, + 61, 515, 516, 517, 518, 519, 34, 288, 289, 290, + 35, 64, 550, 551, 552, 553, 554, 758, 1157, 1158, + 36, 65, 558, 559, 560, 561, 764, 1171, 1172, 37, + 50, 358, 359, 360, 361, 362, 363, 364, 365, 366, + 367, 607, 1032, 1033, 368, 369, 370, 371, 372, 38, + 56, 466, 693, 1073, 1074, 467, 468, 469, 470, 39, + 51, 376, 377, 378, 379, 40, 112, 113, 114, 41, + 53, 387, 626, 1047, 1048, 388, 389, 390, 391, 42, + 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, + 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, + 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, + 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, + 206, 207, 208, 209, 210, 211, 212, 423, 904, 905, + 213, 421, 881, 882, 214, 215, 216, 43, 91, 92, + 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, + 103, 104, 105, 106, 44, 243, 244, 245, 246, 247, + 248, 249, 250 +}; + +/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing + STATE-NUM. */ +#define YYPACT_NINF -744 +static const yytype_int16 yypact[] = +{ + -744, 610, -744, -209, -187, -179, -744, -744, -744, -176, + -744, -171, -744, -744, -744, -166, -164, -744, -744, -139, + -136, -744, -744, -131, -744, -744, -744, -744, -744, -744, + -744, -744, -744, -744, -744, -744, -744, -744, -744, -744, + -744, -744, -744, -744, -744, -744, -744, 61, 807, -126, + -104, -84, 16, -79, 382, -77, -63, -60, 7, 21, + -49, -40, 638, 381, -26, 52, 25, -152, 62, 85, + 86, 18, -744, -744, -744, -744, -744, 88, 89, 93, + 94, 96, 101, 108, 112, 118, 119, 125, 127, 132, + 133, 162, -744, -744, -744, -744, -744, -744, -744, -744, + -744, -744, -744, -744, -744, -744, -744, 531, 499, 266, + -744, 135, 28, -744, -744, 11, -744, 142, 143, 145, + 147, 148, 150, 153, 163, 166, 167, 169, 173, 174, + 175, 177, 178, 180, 182, 183, 185, 191, 197, 200, + 201, 202, 204, 211, 212, 215, -744, 216, -744, 217, + 218, 221, 222, 225, 226, 229, 234, 235, 237, 238, + 239, 242, 253, 256, 257, 262, 38, -744, -744, -744, + -744, -744, -744, -744, -744, -744, -744, -744, -744, -744, + -744, -744, -744, -744, -744, -744, -744, -744, -744, -744, + -744, -744, -744, -744, -744, -744, -744, -744, -744, -744, + -744, -744, -744, -744, -744, -744, -744, -744, -744, -744, + -744, -744, -744, -744, -744, -744, -744, 337, 24, 259, + 73, 263, 4, -744, -744, -744, 126, 131, 264, 270, + 59, -744, -744, -744, 389, 209, -744, 276, 279, 280, + 281, 285, 287, 3, -744, -744, -744, -744, -744, -744, + -744, 149, 288, 289, 290, 292, 299, 301, 302, 303, + 304, 305, 307, 308, 315, 324, 330, 75, -744, -744, + -744, -744, -744, -744, -744, -744, -744, -744, -744, -744, + -744, -744, -744, -744, 208, 30, -744, 331, 15, -744, + -744, -744, 107, 254, 359, 165, -744, 385, 396, 367, + 454, 454, 455, 457, 461, 399, 401, 464, 454, 404, + 405, 351, -744, 358, 356, 360, 361, 362, 364, 365, + 369, 374, 375, 379, 383, 386, 388, 395, 232, -744, + -744, -744, -744, -744, -744, -744, -744, -744, -744, -744, + -744, -744, -744, -744, 384, 397, 400, 403, 408, -744, + 411, 412, 420, 423, 424, 427, 433, 434, 260, -744, + -744, -744, -744, -744, -744, -744, -744, -744, -744, -744, + -744, -744, -744, -744, 435, 437, 8, -744, -744, -744, + 458, 407, -744, -744, 441, 442, -744, -744, 36, -744, + -744, -744, 417, 454, 454, 501, 443, 459, 524, 543, + 502, 454, 503, 454, 565, 567, 568, 508, 509, 513, + 454, 577, 578, 454, 580, 583, 566, 584, 587, 527, + 528, 475, 535, 478, 454, 454, 537, 540, 541, 542, + -146, -133, 544, 546, 454, 454, 585, 454, 550, 553, + 554, 510, -744, 515, 514, 517, -744, 519, 521, 525, + 529, 530, 58, -744, -744, -744, -744, -744, -744, -744, + -744, -744, -744, 533, -744, 534, -744, 10, -744, -744, + -744, 538, -744, 536, 539, 545, -744, 115, -744, -744, + -744, -744, -744, 582, 547, -744, 532, -744, 640, 643, + 549, -744, 555, 559, 560, -744, 562, 569, 572, -744, + 573, 70, -744, -744, -744, -744, -744, -744, -744, -744, + -744, 558, 588, 595, 597, 146, -744, -744, -744, -744, + 623, 625, 687, 658, 659, 454, 606, -744, -744, 704, + 663, 706, 707, 709, 713, 714, 715, 79, 159, 717, + 718, 646, 719, 720, 626, -744, 628, 622, -744, 624, + 128, -744, -744, -744, -744, 629, 630, -744, 22, -744, + -744, -744, 728, 632, -744, 634, 635, 636, -744, 637, + 639, 641, 430, 642, 645, 648, 649, 650, 651, 652, + 653, 654, 656, 657, -744, -744, 754, 756, 454, 759, + 776, 778, 779, 761, 784, 785, 454, 454, 786, 786, + 671, -744, -744, 769, 122, 770, 729, 672, 773, 774, + 775, 777, 795, 780, 781, 782, 681, -744, 783, 787, + 682, -744, 689, -744, 788, 789, 690, 694, -744, 695, + 696, 697, 698, 699, 702, 703, 705, 708, 710, 712, + 716, 721, 722, 723, 724, 725, 726, 727, 730, 731, + 732, 733, 734, 735, 736, 737, 738, 739, 551, 740, + 599, 741, 742, 743, 744, 745, 746, 747, 748, 749, + 750, 751, 752, 753, 755, 757, 758, 760, 762, 763, + -744, -744, 801, 764, 711, 803, 823, 810, 812, 814, + 765, -744, 815, 766, 817, 767, -744, -744, 768, 825, + 826, 870, 772, -744, 790, -744, 184, 791, 792, -744, + -744, 853, 816, 771, 856, 861, 863, 793, 865, 794, + -744, -744, 867, 872, 873, 797, -744, 798, 799, 800, + 802, 804, 805, -744, 806, 808, 809, 811, 813, 818, + 819, 820, -744, -744, -195, -744, -744, -744, -172, -744, + 821, 822, 824, 827, 828, -744, -744, 874, 829, 875, + 830, -744, -744, 876, 831, 833, -744, 835, -744, -744, + -744, -744, -744, -744, -744, 454, 454, 454, 454, 454, + -744, -744, -744, -744, -744, -744, -744, -744, -744, -744, + -744, -744, -744, 836, 837, 838, 839, 840, 841, 842, + 843, 844, 845, 846, 847, 314, 848, 849, -744, 850, + 851, 852, 854, 855, 13, 857, 858, 859, 860, 862, + 864, 866, 868, -744, 869, 871, -744, -744, 877, 878, + 879, -744, -744, -744, -744, -744, -744, -744, -744, -744, + -744, -744, -744, -744, -744, -744, -744, -744, -744, -744, + -744, -744, -744, -744, -744, -744, -744, -744, -744, -744, + -744, -744, -744, -744, -744, -744, -744, -744, -744, -744, + -744, -744, -744, -744, -744, -744, -744, -744, -744, -744, + -744, -167, -744, -744, -744, -744, -744, -744, -744, -744, + -744, -744, -744, -744, -744, -744, -744, -744, -744, -744, + -744, -744, -744, -744, -154, -744, -744, -744, -744, -744, + -744, -744, -744, -744, -744, -744, -744, -744, -744, -744, + -744, -744, -744, -744, -744, 880, 881, 309, 882, 883, + 884, 885, 886, -744, 887, 893, 888, -744, -33, 889, + 890, 832, 891, -744, -744, -744, 892, 894, -744, 895, + 154, -744, -744, -744, -744, -744, -744, 896, 899, 511, + 900, 901, 902, 627, 903, -744, 904, 905, 906, -744, + -744, -744, -744, -744, -744, -744, -744, -744, -744, -744, + -744, -744, -744, -744, -744, 79, -744, 159, -744, -744, + -744, -744, -744, 907, 460, 908, -744, 909, 665, -744, + -744, -744, -744, -744, -744, -744, -744, -744, -744, -744, + -744, -744, -744, -744, -744, -744, -744, -744, 786, 786, + 786, -744, -744, -744, -744, -744, -744, -744, -744, -744, + -744, -744, -145, -744, -744, -744, -744, -744, -744, -744, + -744, -744, -744, -744, -744, -744, -744, -50, -744, -744, + 551, -744, 599, -744, -744, -744, -744, -744, -744, -744, + -744, -744, -744, -744, -41, -744, -744, -744, -744, -744, + -744, -744, -744, -27, -744, -744, -744, -744, -744, -17, + -744, -744, -744, 898, 870, 910, -744, 911, 912, -86, + 913, -744, -744, -744, -744, -744, -744, -744, -744, -744, + -744, -744, -744, -744, -744, -744, -744, -744, -744, -744, + -744, -744, -744, 34, -744, -744, -744, -744, -744, -744, + -744, -744, -744, -744, -744, -744, -744, -744, -744, -744, + -744, -744, -744, -744, -744, -744, -744, -744, 40, -744, + -744, -744, -744, -744, -744, -744, -744, -744, -744, -744, + -744, -744, -744, -744, -744, -744, -744, 53, -744, -744, + -744, -744, -744, -744, -744, -744, -744, -744, -744, -744, + -744, 63, -744, -744, -744, -744, -744, 13, -744, 879, + -744, -744, -744, 309, -744, 893, -744, -33, -744, -744, + -744, 914, 277, 916, 917, -744, -744, 511, -744, 627, + -744, 460, -744, 665, -744, -744, -744, -744, -744, -744, + -744, -744, -744, -744, -744, -744, -744, 68, -744, -744, + -744, -744, -744, -744, -744, -744, 277, -744 +}; + +/* YYPGOTO[NTERM-NUM]. */ +static const yytype_int16 yypgoto[] = +{ + -744, -744, -744, -743, -298, -663, -598, -744, -744, 897, + -744, -744, -744, -744, 915, -744, -744, -744, 14, -744, + 1, -744, -744, -744, -744, -744, -744, -744, -744, -744, + -744, -744, -744, -744, -744, -744, 924, -744, -744, -744, + -744, -744, 796, -744, -744, -744, -744, 48, -744, -744, + -744, -744, -744, -226, -744, -744, -744, 500, -744, -744, + -744, -744, -744, -744, -744, -744, -744, -196, -744, -744, + -744, -193, -744, -744, -744, 680, -744, -744, -744, -744, + -744, -744, -744, -744, -744, -744, -744, -744, -744, -744, + -744, -744, -744, -744, -744, -177, -744, 548, -744, -744, + -744, -62, -744, -744, -744, -744, -744, 575, -744, -744, + -744, -744, -744, -744, -744, -153, -744, -744, -744, -744, + -744, -744, 516, -744, -744, -744, -744, -744, 918, -744, + -744, -744, -744, 482, -744, -744, -744, -744, -744, -163, + -744, -744, -744, 483, -744, -744, -744, -744, -159, -744, + -744, -744, 688, -744, -744, -744, -744, -744, -744, -744, + -744, -744, -744, -137, -744, -744, -744, -744, -744, -744, + -744, -744, -744, -744, -117, -744, 604, -744, -744, -744, + -744, -744, 700, -744, -744, -744, -744, 966, -744, -744, + -744, -744, -744, -744, -99, -744, 701, -744, -744, -744, + -744, 919, -744, -744, -744, -744, -744, -744, -744, -744, + -744, -744, -744, -744, -744, -744, -744, -744, -744, -744, + -744, -744, -744, -744, -744, -744, -744, -744, -744, -744, + -744, -744, -744, -744, -744, -744, -744, -744, -744, -744, + -744, -744, -744, -744, -744, -744, -744, -744, -744, 35, + -744, -744, -744, 32, -744, -744, -744, -744, -744, 997, + -744, -744, -744, -744, -744, -744, -744, -744, -744, -744, + -744, -744, -744, -744, -744, -744, 920, -744, -744, -744, + -744, -744, -744 +}; + +/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If + positive, shift that token. If negative, reduce the rule which + number is the opposite. If YYTABLE_NINF, syntax error. */ +#define YYTABLE_NINF -108 +static const yytype_int16 yytable[] = +{ + 806, 807, 573, 574, 236, 220, 45, 46, 220, 373, + 581, 462, 383, 805, 667, 668, 286, 110, 1076, 67, + 984, 1030, 227, 555, 985, 462, 286, 669, 670, 110, + 47, 555, 1001, 1002, 1003, 1004, 1005, 383, 48, 116, + 237, 52, 68, 986, 117, 118, 54, 987, 1049, 69, + 119, 58, 1050, 59, 238, 239, 240, 241, 120, 443, + 227, 1051, 67, 291, 121, 1052, 122, 123, 124, 374, + 1176, 492, 242, 125, 1177, 444, 251, 111, 62, 126, + 127, 63, 128, 129, 130, 68, 66, 493, 131, 111, + 445, 107, 69, 132, 446, 630, 631, 133, 134, 252, + 384, 135, 494, 638, 287, 640, 495, 70, 228, 1193, + 136, 556, 647, 108, 287, 650, 471, 137, 138, 556, + 139, 140, 141, 142, 143, 384, 661, 662, 375, 546, + 463, 385, 253, 109, 229, 144, 673, 674, 115, 676, + 217, 145, 146, 147, 463, 148, 228, 511, 149, 150, + 70, 472, 151, 1077, 218, 946, 385, 219, 1078, 496, + 512, 464, 386, 76, 254, 1178, 255, 256, 234, 1179, + 447, 473, 229, 557, 1182, 464, 474, 235, 1183, 448, + 449, 557, 497, 77, 78, 946, 152, 386, 1184, 79, + 153, 284, 1185, 154, 155, 156, 157, 158, 1186, 498, + 159, 160, 1187, 257, 1031, 258, 259, 260, 261, 546, + 511, 450, 221, 742, 743, 221, 465, 547, -107, 526, + 484, -107, 262, 512, 620, 565, 695, 732, 80, 81, + 465, 563, 475, 313, 295, 82, 83, 84, 765, 513, + 161, 162, 163, 947, 381, 164, 263, 314, 315, 1196, + 165, 316, 627, 1197, 441, 1198, 264, 85, 86, 1199, + 471, 344, 499, 345, 451, 346, 514, 373, 1200, 285, + 87, 88, 1201, 947, 690, 490, 500, 347, 1202, 548, + 292, 89, 1203, 1225, 265, 266, 719, 1226, 482, 90, + 795, 544, 348, 746, 747, 472, 349, 547, 803, 804, + 810, 811, 513, 293, 294, 948, 297, 298, 317, 318, + 319, 299, 300, 320, 301, 473, 350, 1210, 351, 302, + 474, 321, 1055, 1018, 1019, 1020, 303, 374, 352, 514, + 304, 702, 322, 323, 549, 948, 305, 306, 443, 1211, + 486, 1212, 1056, 307, 760, 308, 487, 324, 325, 353, + 309, 310, 1057, 380, 444, 1173, 1174, 1175, 1058, 548, + 392, 393, 725, 394, 528, 395, 396, 949, 397, 445, + 1090, 398, 566, 446, 1059, 326, 475, 354, 311, 1213, + 568, 399, 251, 116, 400, 401, 375, 402, 117, 118, + 492, 403, 404, 405, 119, 406, 407, 949, 408, 1060, + 409, 410, 120, 411, 355, 252, 493, 1061, 121, 412, + 122, 123, 124, 805, 549, 413, 327, 125, 414, 415, + 416, 494, 417, 126, 127, 495, 128, 129, 130, 418, + 419, 356, 131, 420, 422, 424, 425, 132, 253, 426, + 427, 133, 134, 428, 429, 135, 1062, 430, 600, 447, + 1214, 1215, 431, 432, 136, 433, 434, 435, 448, 449, + 436, 137, 138, 1063, 139, 140, 141, 142, 143, 357, + 254, 437, 255, 256, 438, 439, 616, 567, 496, 144, + 440, 483, 488, 1216, 569, 145, 146, 147, 489, 148, + 450, 1194, 149, 150, 520, 570, 151, 521, 522, 523, + 344, 497, 345, 524, 346, 525, 529, 530, 531, 257, + 532, 258, 259, 260, 261, 1094, 347, 533, 498, 534, + 535, 536, 537, 538, 1147, 539, 540, 571, 262, 572, + 152, 348, 313, 541, 153, 349, 1095, 154, 155, 156, + 157, 158, 542, 451, 159, 160, 314, 315, 543, 562, + 316, 1096, 263, 572, 575, 350, 576, 351, 1097, 578, + 577, 579, 264, 580, 582, 583, 584, 352, 775, 776, + 777, 778, 779, 585, 586, 1098, 622, 629, 587, 588, + 589, 499, 590, 591, 161, 162, 163, 592, 353, 164, + 265, 266, 593, 594, 165, 500, 1148, 595, 1099, 602, + 632, 596, 861, 633, 597, 1100, 598, 317, 318, 319, + 2, 3, 320, 599, 4, 603, 354, 1101, 604, 634, + 321, 605, 623, 635, 5, 1149, 606, 6, 7, 608, + 609, 322, 323, 8, 1150, 1102, 1103, 1104, 610, 236, + 1151, 611, 612, 355, 9, 613, 324, 325, 10, 11, + 884, 614, 615, 618, 1152, 619, 1153, 1154, 12, 624, + 625, 636, 637, 639, 641, 1155, 642, 643, 644, 645, + 356, 1156, 13, 646, 326, 237, 648, 649, 1118, 651, + 14, 15, 652, 654, 653, 1105, 655, 656, 657, 238, + 239, 240, 241, 658, 1106, 659, 660, 663, 16, 1107, + 664, 665, 666, 675, 671, 1108, 672, 242, 357, 1109, + 677, 1110, 17, 678, 679, 327, 1111, 862, 863, 864, + 865, 866, 1112, 867, 868, 680, 869, 870, 871, 1161, + 681, 872, 682, 873, 874, 683, 875, 685, 876, 686, + 877, 878, 704, 687, 879, 752, 18, 688, 689, 706, + 880, 692, 694, 697, 699, 19, 20, 700, 707, 21, + 22, 708, 705, 701, 709, 885, 886, 887, 888, 889, + 710, 890, 891, 721, 892, 893, 894, 711, 712, 895, + 714, 896, 897, 727, 898, 728, 899, 715, 900, 901, + 716, 718, 902, 1119, 1120, 1121, 1122, 1123, 903, 1124, + 1125, 1162, 1126, 1127, 1128, 729, 722, 1129, 76, 1130, + 1131, 23, 1132, 723, 1133, 724, 1134, 1135, 730, 731, + 1136, 733, 734, 735, 736, 737, 1137, 738, 77, 78, + 1163, 739, 740, 741, 79, 750, 751, 753, 754, 1164, + 757, 755, 759, 756, 762, 1165, 767, 768, 763, 769, + 770, 771, 772, 793, 773, 794, 774, 782, 796, 1166, + 783, 1167, 1168, 784, 785, 786, 787, 788, 789, 790, + 1169, 791, 792, 80, 81, 797, 1170, 798, 799, 800, + 82, 83, 84, 801, 802, 805, 808, 809, 812, 813, + 814, 815, 816, 817, 819, 818, 823, 826, 820, 821, + 822, 824, 85, 86, 827, 825, 828, 829, 830, 831, + 832, 833, 834, 835, 836, 87, 88, 837, 838, 925, + 839, 928, 929, 840, 926, 841, 89, 842, 930, 927, + 931, 843, 932, 934, 90, 936, 844, 845, 846, 847, + 848, 849, 850, 939, 940, 851, 852, 853, 854, 855, + 856, 857, 858, 859, 860, 883, 906, 907, 908, 909, + 910, 911, 912, 913, 914, 915, 916, 917, 918, 941, + 919, 957, 920, 921, 960, 922, 958, 923, 924, 961, + 933, 962, 937, 964, 935, 966, 938, 944, 1145, 959, + 967, 968, 993, 995, 997, 296, 1083, 1188, 1091, 1144, + 1227, 720, 1046, 1222, 1221, 945, 955, 956, 601, 965, + 1208, 963, 969, 970, 971, 972, 1072, 973, 485, 974, + 975, 976, 1189, 977, 978, 703, 979, 691, 980, 1191, + 1206, 726, 761, 981, 982, 983, 988, 989, 1223, 990, + 1204, 766, 991, 992, 1224, 996, 617, 994, 999, 998, + 1000, 1006, 1007, 1008, 1009, 1010, 1011, 1012, 1013, 1014, + 1015, 1016, 1017, 1023, 1024, 1025, 1026, 1027, 1207, 1028, + 1029, 696, 1034, 1035, 1036, 1037, 621, 1038, 382, 1039, + 1205, 1040, 1180, 1041, 1042, 442, 1043, 1181, 312, 628, + 0, 0, 1044, 1045, 0, 1053, 1054, 1066, 1067, 1068, + 1069, 1070, 1071, 1075, 1081, 1082, 0, 1086, 0, 0, + 1084, 1092, 1087, 1089, 1093, 1115, 1116, 1117, 1140, 1141, + 1142, 1143, 1146, 1159, 1160, 1190, 0, 491, 1195, 1209, + 1192, 1219, 1220, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 527, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 545, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 564 +}; + +#define yypact_value_is_default(yystate) \ + ((yystate) == (-744)) + +#define yytable_value_is_error(yytable_value) \ + YYID (0) + +static const yytype_int16 yycheck[] = +{ + 598, 599, 300, 301, 1, 1, 215, 216, 1, 1, + 308, 1, 1, 99, 160, 161, 1, 1, 51, 1, + 215, 8, 1, 1, 219, 1, 1, 160, 161, 1, + 217, 1, 775, 776, 777, 778, 779, 1, 217, 1, + 37, 217, 24, 215, 6, 7, 217, 219, 215, 31, + 12, 217, 219, 217, 51, 52, 53, 54, 20, 1, + 1, 215, 1, 215, 26, 219, 28, 29, 30, 61, + 215, 1, 69, 35, 219, 17, 1, 61, 217, 41, + 42, 217, 44, 45, 46, 24, 217, 17, 50, 61, + 32, 217, 31, 55, 36, 393, 394, 59, 60, 24, + 89, 63, 32, 401, 89, 403, 36, 89, 87, 195, + 72, 89, 410, 217, 89, 413, 1, 79, 80, 89, + 82, 83, 84, 85, 86, 89, 424, 425, 120, 1, + 120, 120, 57, 217, 113, 97, 434, 435, 217, 437, + 217, 103, 104, 105, 120, 107, 87, 1, 110, 111, + 89, 36, 114, 186, 217, 1, 120, 217, 191, 89, + 14, 151, 151, 1, 89, 215, 91, 92, 217, 219, + 112, 56, 113, 151, 215, 151, 61, 217, 219, 121, + 122, 151, 112, 21, 22, 1, 148, 151, 215, 27, + 152, 217, 219, 155, 156, 157, 158, 159, 215, 129, + 162, 163, 219, 128, 191, 130, 131, 132, 133, 1, + 1, 153, 208, 134, 135, 208, 206, 89, 214, 216, + 216, 214, 147, 14, 216, 118, 216, 525, 66, 67, + 206, 216, 117, 1, 216, 73, 74, 75, 216, 93, + 202, 203, 204, 89, 216, 207, 171, 15, 16, 215, + 212, 19, 216, 219, 216, 215, 181, 95, 96, 219, + 1, 1, 192, 3, 206, 5, 120, 1, 215, 217, + 108, 109, 219, 89, 216, 216, 206, 17, 215, 151, + 218, 119, 219, 215, 209, 210, 216, 219, 215, 127, + 588, 216, 32, 134, 135, 36, 36, 89, 596, 597, + 178, 179, 93, 218, 218, 151, 218, 218, 76, 77, + 78, 218, 218, 81, 218, 56, 56, 40, 58, 218, + 61, 89, 13, 9, 10, 11, 218, 61, 68, 120, + 218, 216, 100, 101, 206, 151, 218, 218, 1, 62, + 214, 64, 33, 218, 216, 218, 215, 115, 116, 89, + 218, 218, 43, 218, 17, 1018, 1019, 1020, 49, 151, + 218, 218, 216, 218, 215, 218, 218, 213, 218, 32, + 216, 218, 118, 36, 65, 143, 117, 117, 216, 102, + 215, 218, 1, 1, 218, 218, 120, 218, 6, 7, + 1, 218, 218, 218, 12, 218, 218, 213, 218, 90, + 218, 218, 20, 218, 144, 24, 17, 98, 26, 218, + 28, 29, 30, 99, 206, 218, 184, 35, 218, 218, + 218, 32, 218, 41, 42, 36, 44, 45, 46, 218, + 218, 171, 50, 218, 218, 218, 218, 55, 57, 218, + 218, 59, 60, 218, 218, 63, 137, 218, 216, 112, + 173, 174, 218, 218, 72, 218, 218, 218, 121, 122, + 218, 79, 80, 154, 82, 83, 84, 85, 86, 209, + 89, 218, 91, 92, 218, 218, 216, 118, 89, 97, + 218, 218, 218, 206, 99, 103, 104, 105, 218, 107, + 153, 1089, 110, 111, 218, 99, 114, 218, 218, 218, + 1, 112, 3, 218, 5, 218, 218, 218, 218, 128, + 218, 130, 131, 132, 133, 4, 17, 218, 129, 218, + 218, 218, 218, 218, 64, 218, 218, 160, 147, 99, + 148, 32, 1, 218, 152, 36, 25, 155, 156, 157, + 158, 159, 218, 206, 162, 163, 15, 16, 218, 218, + 19, 40, 171, 99, 99, 56, 99, 58, 47, 160, + 99, 160, 181, 99, 160, 160, 215, 68, 138, 139, + 140, 141, 142, 215, 218, 64, 118, 160, 218, 218, + 218, 192, 218, 218, 202, 203, 204, 218, 89, 207, + 209, 210, 218, 218, 212, 206, 136, 218, 87, 215, + 99, 218, 51, 160, 218, 94, 218, 76, 77, 78, + 0, 1, 81, 218, 4, 218, 117, 106, 218, 160, + 89, 218, 215, 99, 14, 165, 218, 17, 18, 218, + 218, 100, 101, 23, 174, 124, 125, 126, 218, 1, + 180, 218, 218, 144, 34, 218, 115, 116, 38, 39, + 51, 218, 218, 218, 194, 218, 196, 197, 48, 218, + 218, 118, 160, 160, 99, 205, 99, 99, 160, 160, + 171, 211, 62, 160, 143, 37, 99, 99, 51, 99, + 70, 71, 99, 99, 118, 174, 99, 160, 160, 51, + 52, 53, 54, 218, 183, 160, 218, 160, 88, 188, + 160, 160, 160, 118, 160, 194, 160, 69, 209, 198, + 160, 200, 102, 160, 160, 184, 205, 166, 167, 168, + 169, 170, 211, 172, 173, 215, 175, 176, 177, 64, + 215, 180, 218, 182, 183, 218, 185, 218, 187, 218, + 189, 190, 160, 218, 193, 99, 136, 218, 218, 217, + 199, 218, 218, 215, 218, 145, 146, 218, 118, 149, + 150, 118, 215, 218, 215, 166, 167, 168, 169, 170, + 215, 172, 173, 215, 175, 176, 177, 218, 218, 180, + 218, 182, 183, 160, 185, 160, 187, 218, 189, 190, + 218, 218, 193, 166, 167, 168, 169, 170, 199, 172, + 173, 136, 175, 176, 177, 118, 218, 180, 1, 182, + 183, 201, 185, 218, 187, 218, 189, 190, 160, 160, + 193, 215, 118, 160, 118, 118, 199, 118, 21, 22, + 165, 118, 118, 118, 27, 118, 118, 118, 118, 174, + 218, 215, 218, 215, 215, 180, 118, 215, 218, 215, + 215, 215, 215, 99, 215, 99, 215, 215, 99, 194, + 215, 196, 197, 215, 215, 215, 215, 215, 215, 215, + 205, 215, 215, 66, 67, 99, 211, 99, 99, 118, + 73, 74, 75, 99, 99, 99, 215, 118, 118, 160, + 218, 118, 118, 118, 99, 118, 215, 215, 118, 118, + 118, 118, 95, 96, 215, 118, 118, 118, 218, 215, + 215, 215, 215, 215, 215, 108, 109, 215, 215, 118, + 215, 118, 99, 215, 160, 215, 119, 215, 118, 218, + 118, 215, 118, 118, 127, 118, 215, 215, 215, 215, + 215, 215, 215, 118, 118, 215, 215, 215, 215, 215, + 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, + 215, 215, 215, 215, 215, 215, 215, 215, 215, 99, + 215, 118, 215, 215, 118, 215, 160, 215, 215, 118, + 215, 118, 215, 118, 218, 118, 218, 215, 987, 218, + 118, 118, 118, 118, 118, 71, 164, 99, 950, 985, + 1226, 501, 123, 1199, 1197, 215, 215, 215, 328, 215, + 1187, 218, 215, 215, 215, 215, 123, 215, 222, 215, + 215, 215, 1084, 215, 215, 477, 215, 452, 215, 118, + 1183, 515, 550, 215, 215, 215, 215, 215, 1201, 215, + 1177, 558, 215, 215, 1203, 215, 358, 218, 215, 218, + 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, + 215, 215, 215, 215, 215, 215, 215, 215, 1185, 215, + 215, 467, 215, 215, 215, 215, 376, 215, 112, 215, + 1179, 215, 1050, 215, 215, 166, 215, 1052, 91, 388, + -1, -1, 215, 215, -1, 215, 215, 215, 215, 215, + 215, 215, 215, 215, 215, 215, -1, 215, -1, -1, + 219, 215, 218, 218, 215, 215, 215, 215, 215, 215, + 215, 215, 215, 215, 215, 215, -1, 230, 215, 215, + 218, 215, 215, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 243, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 267, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 288 +}; + +/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing + symbol of state STATE-NUM. */ +static const yytype_uint16 yystos[] = +{ + 0, 221, 0, 1, 4, 14, 17, 18, 23, 34, + 38, 39, 48, 62, 70, 71, 88, 102, 136, 145, + 146, 149, 150, 201, 222, 227, 232, 254, 260, 274, + 292, 310, 324, 339, 346, 350, 360, 369, 389, 399, + 405, 409, 419, 477, 494, 215, 216, 217, 217, 293, + 370, 400, 217, 410, 217, 325, 390, 311, 217, 217, + 275, 340, 217, 217, 351, 361, 217, 1, 24, 31, + 89, 255, 256, 257, 258, 259, 1, 21, 22, 27, + 66, 67, 73, 74, 75, 95, 96, 108, 109, 119, + 127, 478, 479, 480, 481, 482, 483, 484, 485, 486, + 487, 488, 489, 490, 491, 492, 493, 217, 217, 217, + 1, 61, 406, 407, 408, 217, 1, 6, 7, 12, + 20, 26, 28, 29, 30, 35, 41, 42, 44, 45, + 46, 50, 55, 59, 60, 63, 72, 79, 80, 82, + 83, 84, 85, 86, 97, 103, 104, 105, 107, 110, + 111, 114, 148, 152, 155, 156, 157, 158, 159, 162, + 163, 202, 203, 204, 207, 212, 420, 421, 422, 423, + 424, 425, 426, 427, 428, 429, 430, 431, 432, 433, + 434, 435, 436, 437, 438, 439, 440, 441, 442, 443, + 444, 445, 446, 447, 448, 449, 450, 451, 452, 453, + 454, 455, 456, 457, 458, 459, 460, 461, 462, 463, + 464, 465, 466, 470, 474, 475, 476, 217, 217, 217, + 1, 208, 261, 262, 263, 264, 265, 1, 87, 113, + 228, 229, 230, 231, 217, 217, 1, 37, 51, 52, + 53, 54, 69, 495, 496, 497, 498, 499, 500, 501, + 502, 1, 24, 57, 89, 91, 92, 128, 130, 131, + 132, 133, 147, 171, 181, 209, 210, 233, 234, 235, + 236, 241, 242, 243, 244, 245, 246, 247, 248, 249, + 250, 251, 252, 253, 217, 217, 1, 89, 347, 348, + 349, 215, 218, 218, 218, 216, 256, 218, 218, 218, + 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, + 218, 216, 479, 1, 15, 16, 19, 76, 77, 78, + 81, 89, 100, 101, 115, 116, 143, 184, 294, 295, + 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, + 306, 307, 308, 309, 1, 3, 5, 17, 32, 36, + 56, 58, 68, 89, 117, 144, 171, 209, 371, 372, + 373, 374, 375, 376, 377, 378, 379, 380, 384, 385, + 386, 387, 388, 1, 61, 120, 401, 402, 403, 404, + 218, 216, 407, 1, 89, 120, 151, 411, 415, 416, + 417, 418, 218, 218, 218, 218, 218, 218, 218, 218, + 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, + 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, + 218, 471, 218, 467, 218, 218, 218, 218, 218, 218, + 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, + 218, 216, 421, 1, 17, 32, 36, 112, 121, 122, + 153, 206, 326, 327, 328, 329, 330, 331, 332, 336, + 337, 338, 1, 120, 151, 206, 391, 395, 396, 397, + 398, 1, 36, 56, 61, 117, 312, 316, 317, 318, + 322, 323, 215, 218, 216, 262, 214, 215, 218, 218, + 216, 229, 1, 17, 32, 36, 89, 112, 129, 192, + 206, 276, 277, 278, 279, 280, 281, 282, 283, 284, + 288, 1, 14, 93, 120, 341, 342, 343, 344, 345, + 218, 218, 218, 218, 218, 218, 216, 496, 215, 218, + 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, + 218, 218, 218, 218, 216, 234, 1, 89, 151, 206, + 352, 353, 354, 355, 356, 1, 89, 151, 362, 363, + 364, 365, 218, 216, 348, 118, 118, 118, 215, 99, + 99, 160, 99, 224, 224, 99, 99, 99, 160, 160, + 99, 224, 160, 160, 215, 215, 218, 218, 218, 218, + 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, + 216, 295, 215, 218, 218, 218, 218, 381, 218, 218, + 218, 218, 218, 218, 218, 218, 216, 372, 218, 218, + 216, 402, 118, 215, 218, 218, 412, 216, 416, 160, + 224, 224, 99, 160, 160, 99, 118, 160, 224, 160, + 224, 99, 99, 99, 160, 160, 160, 224, 99, 99, + 224, 99, 99, 118, 99, 99, 160, 160, 218, 160, + 218, 224, 224, 160, 160, 160, 160, 160, 161, 160, + 161, 160, 160, 224, 224, 118, 224, 160, 160, 160, + 215, 215, 218, 218, 333, 218, 218, 218, 218, 218, + 216, 327, 218, 392, 218, 216, 396, 215, 313, 218, + 218, 218, 216, 317, 160, 215, 217, 118, 118, 215, + 215, 218, 218, 289, 218, 218, 218, 285, 218, 216, + 277, 215, 218, 218, 218, 216, 342, 160, 160, 118, + 160, 160, 224, 215, 118, 160, 118, 118, 118, 118, + 118, 118, 134, 135, 237, 238, 134, 135, 239, 240, + 118, 118, 99, 118, 118, 215, 215, 218, 357, 218, + 216, 353, 215, 218, 366, 216, 363, 118, 215, 215, + 215, 215, 215, 215, 215, 138, 139, 140, 141, 142, + 223, 224, 215, 215, 215, 215, 215, 215, 215, 215, + 215, 215, 215, 99, 99, 224, 99, 99, 99, 99, + 118, 99, 99, 224, 224, 99, 226, 226, 215, 118, + 178, 179, 118, 160, 218, 118, 118, 118, 118, 99, + 118, 118, 118, 215, 118, 118, 215, 215, 118, 118, + 218, 215, 215, 215, 215, 215, 215, 215, 215, 215, + 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, + 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, + 215, 51, 166, 167, 168, 169, 170, 172, 173, 175, + 176, 177, 180, 182, 183, 185, 187, 189, 190, 193, + 199, 472, 473, 215, 51, 166, 167, 168, 169, 170, + 172, 173, 175, 176, 177, 180, 182, 183, 185, 187, + 189, 190, 193, 199, 468, 469, 215, 215, 215, 215, + 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, + 215, 215, 215, 215, 215, 118, 160, 218, 118, 99, + 118, 118, 118, 215, 118, 218, 118, 215, 218, 118, + 118, 99, 320, 321, 215, 215, 1, 89, 151, 213, + 266, 267, 268, 269, 270, 215, 215, 118, 160, 218, + 118, 118, 118, 218, 118, 215, 118, 118, 118, 215, + 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, + 215, 215, 215, 215, 215, 219, 215, 219, 215, 215, + 215, 215, 215, 118, 218, 118, 215, 118, 218, 215, + 215, 223, 223, 223, 223, 223, 215, 215, 215, 215, + 215, 215, 215, 215, 215, 215, 215, 215, 9, 10, + 11, 225, 226, 215, 215, 215, 215, 215, 215, 215, + 8, 191, 382, 383, 215, 215, 215, 215, 215, 215, + 215, 215, 215, 215, 215, 215, 123, 413, 414, 215, + 219, 215, 219, 215, 215, 13, 33, 43, 49, 65, + 90, 98, 137, 154, 334, 335, 215, 215, 215, 215, + 215, 215, 123, 393, 394, 215, 51, 186, 191, 314, + 315, 215, 215, 164, 219, 319, 215, 218, 271, 218, + 216, 267, 215, 215, 4, 25, 40, 47, 64, 87, + 94, 106, 124, 125, 126, 174, 183, 188, 194, 198, + 200, 205, 211, 290, 291, 215, 215, 215, 51, 166, + 167, 168, 169, 170, 172, 173, 175, 176, 177, 180, + 182, 183, 185, 187, 189, 190, 193, 199, 286, 287, + 215, 215, 215, 215, 238, 240, 215, 64, 136, 165, + 174, 180, 194, 196, 197, 205, 211, 358, 359, 215, + 215, 64, 136, 165, 174, 180, 194, 196, 197, 205, + 211, 367, 368, 225, 225, 225, 215, 219, 215, 219, + 473, 469, 215, 219, 215, 219, 215, 219, 99, 321, + 215, 118, 218, 195, 226, 215, 215, 219, 215, 219, + 215, 219, 215, 219, 383, 414, 335, 394, 315, 215, + 40, 62, 64, 102, 173, 174, 206, 272, 273, 215, + 215, 291, 287, 359, 368, 215, 219, 273 +}; + +#define yyerrok (yyerrstatus = 0) +#define yyclearin (yychar = YYEMPTY) +#define YYEMPTY (-2) +#define YYEOF 0 + +#define YYACCEPT goto yyacceptlab +#define YYABORT goto yyabortlab +#define YYERROR goto yyerrorlab + + +/* Like YYERROR except do call yyerror. This remains here temporarily + to ease the transition to the new meaning of YYERROR, for GCC. + Once GCC version 2 has supplanted version 1, this can go. However, + YYFAIL appears to be in use. Nevertheless, it is formally deprecated + in Bison 2.4.2's NEWS entry, where a plan to phase it out is + discussed. */ + +#define YYFAIL goto yyerrlab +#if defined YYFAIL + /* This is here to suppress warnings from the GCC cpp's + -Wunused-macros. Normally we don't worry about that warning, but + some users do, and we want to make it easy for users to remove + YYFAIL uses, which will produce warnings from Bison 2.5. */ +#endif + +#define YYRECOVERING() (!!yyerrstatus) + +#define YYBACKUP(Token, Value) \ +do \ + if (yychar == YYEMPTY) \ + { \ + yychar = (Token); \ + yylval = (Value); \ + YYPOPSTACK (yylen); \ + yystate = *yyssp; \ + goto yybackup; \ + } \ + else \ + { \ + yyerror (YY_("syntax error: cannot back up")); \ + YYERROR; \ + } \ +while (YYID (0)) + + +#define YYTERROR 1 +#define YYERRCODE 256 + +/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N]. + If N is 0, then set CURRENT to the empty location which ends + the previous symbol: RHS[0] (always defined). */ + +#ifndef YYLLOC_DEFAULT +# define YYLLOC_DEFAULT(Current, Rhs, N) \ + do \ + if (YYID (N)) \ + { \ + (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \ + (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \ + (Current).last_line = YYRHSLOC (Rhs, N).last_line; \ + (Current).last_column = YYRHSLOC (Rhs, N).last_column; \ + } \ + else \ + { \ + (Current).first_line = (Current).last_line = \ + YYRHSLOC (Rhs, 0).last_line; \ + (Current).first_column = (Current).last_column = \ + YYRHSLOC (Rhs, 0).last_column; \ + } \ + while (YYID (0)) +#endif + +#define YYRHSLOC(Rhs, K) ((Rhs)[K]) + + + +/* This macro is provided for backward compatibility. */ + +#ifndef YY_LOCATION_PRINT +# define YY_LOCATION_PRINT(File, Loc) ((void) 0) +#endif + + +/* YYLEX -- calling `yylex' with the right arguments. */ + +#ifdef YYLEX_PARAM +# define YYLEX yylex (YYLEX_PARAM) +#else +# define YYLEX yylex () +#endif + +/* Enable debugging if requested. */ +#if YYDEBUG + +# ifndef YYFPRINTF +# include <stdio.h> /* INFRINGES ON USER NAME SPACE */ +# define YYFPRINTF fprintf +# endif + +# define YYDPRINTF(Args) \ +do { \ + if (yydebug) \ + YYFPRINTF Args; \ +} while (YYID (0)) + +# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \ +do { \ + if (yydebug) \ + { \ + YYFPRINTF (stderr, "%s ", Title); \ + yy_symbol_print (stderr, \ + Type, Value); \ + YYFPRINTF (stderr, "\n"); \ + } \ +} while (YYID (0)) + + +/*--------------------------------. +| Print this symbol on YYOUTPUT. | +`--------------------------------*/ + +/*ARGSUSED*/ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep) +#else +static void +yy_symbol_value_print (yyoutput, yytype, yyvaluep) + FILE *yyoutput; + int yytype; + YYSTYPE const * const yyvaluep; +#endif +{ + FILE *yyo = yyoutput; + YYUSE (yyo); + if (!yyvaluep) + return; +# ifdef YYPRINT + if (yytype < YYNTOKENS) + YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep); +# else + YYUSE (yyoutput); +# endif + switch (yytype) + { + default: + break; + } +} + + +/*--------------------------------. +| Print this symbol on YYOUTPUT. | +`--------------------------------*/ + +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep) +#else +static void +yy_symbol_print (yyoutput, yytype, yyvaluep) + FILE *yyoutput; + int yytype; + YYSTYPE const * const yyvaluep; +#endif +{ + if (yytype < YYNTOKENS) + YYFPRINTF (yyoutput, "token %s (", yytname[yytype]); + else + YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]); + + yy_symbol_value_print (yyoutput, yytype, yyvaluep); + YYFPRINTF (yyoutput, ")"); +} + +/*------------------------------------------------------------------. +| yy_stack_print -- Print the state stack from its BOTTOM up to its | +| TOP (included). | +`------------------------------------------------------------------*/ + +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop) +#else +static void +yy_stack_print (yybottom, yytop) + yytype_int16 *yybottom; + yytype_int16 *yytop; +#endif +{ + YYFPRINTF (stderr, "Stack now"); + for (; yybottom <= yytop; yybottom++) + { + int yybot = *yybottom; + YYFPRINTF (stderr, " %d", yybot); + } + YYFPRINTF (stderr, "\n"); +} + +# define YY_STACK_PRINT(Bottom, Top) \ +do { \ + if (yydebug) \ + yy_stack_print ((Bottom), (Top)); \ +} while (YYID (0)) + + +/*------------------------------------------------. +| Report that the YYRULE is going to be reduced. | +`------------------------------------------------*/ + +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_reduce_print (YYSTYPE *yyvsp, int yyrule) +#else +static void +yy_reduce_print (yyvsp, yyrule) + YYSTYPE *yyvsp; + int yyrule; +#endif +{ + int yynrhs = yyr2[yyrule]; + int yyi; + unsigned long int yylno = yyrline[yyrule]; + YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n", + yyrule - 1, yylno); + /* The symbols being reduced. */ + for (yyi = 0; yyi < yynrhs; yyi++) + { + YYFPRINTF (stderr, " $%d = ", yyi + 1); + yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi], + &(yyvsp[(yyi + 1) - (yynrhs)]) + ); + YYFPRINTF (stderr, "\n"); + } +} + +# define YY_REDUCE_PRINT(Rule) \ +do { \ + if (yydebug) \ + yy_reduce_print (yyvsp, Rule); \ +} while (YYID (0)) + +/* Nonzero means print parse trace. It is left uninitialized so that + multiple parsers can coexist. */ +int yydebug; +#else /* !YYDEBUG */ +# define YYDPRINTF(Args) +# define YY_SYMBOL_PRINT(Title, Type, Value, Location) +# define YY_STACK_PRINT(Bottom, Top) +# define YY_REDUCE_PRINT(Rule) +#endif /* !YYDEBUG */ + + +/* YYINITDEPTH -- initial size of the parser's stacks. */ +#ifndef YYINITDEPTH +# define YYINITDEPTH 200 +#endif + +/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only + if the built-in stack extension method is used). + + Do not make this value too large; the results are undefined if + YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH) + evaluated with infinite-precision integer arithmetic. */ + +#ifndef YYMAXDEPTH +# define YYMAXDEPTH 10000 +#endif + + +#if YYERROR_VERBOSE + +# ifndef yystrlen +# if defined __GLIBC__ && defined _STRING_H +# define yystrlen strlen +# else +/* Return the length of YYSTR. */ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static YYSIZE_T +yystrlen (const char *yystr) +#else +static YYSIZE_T +yystrlen (yystr) + const char *yystr; +#endif +{ + YYSIZE_T yylen; + for (yylen = 0; yystr[yylen]; yylen++) + continue; + return yylen; +} +# endif +# endif + +# ifndef yystpcpy +# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE +# define yystpcpy stpcpy +# else +/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in + YYDEST. */ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static char * +yystpcpy (char *yydest, const char *yysrc) +#else +static char * +yystpcpy (yydest, yysrc) + char *yydest; + const char *yysrc; +#endif +{ + char *yyd = yydest; + const char *yys = yysrc; + + while ((*yyd++ = *yys++) != '\0') + continue; + + return yyd - 1; +} +# endif +# endif + +# ifndef yytnamerr +/* Copy to YYRES the contents of YYSTR after stripping away unnecessary + quotes and backslashes, so that it's suitable for yyerror. The + heuristic is that double-quoting is unnecessary unless the string + contains an apostrophe, a comma, or backslash (other than + backslash-backslash). YYSTR is taken from yytname. If YYRES is + null, do not copy; instead, return the length of what the result + would have been. */ +static YYSIZE_T +yytnamerr (char *yyres, const char *yystr) +{ + if (*yystr == '"') + { + YYSIZE_T yyn = 0; + char const *yyp = yystr; + + for (;;) + switch (*++yyp) + { + case '\'': + case ',': + goto do_not_strip_quotes; + + case '\\': + if (*++yyp != '\\') + goto do_not_strip_quotes; + /* Fall through. */ + default: + if (yyres) + yyres[yyn] = *yyp; + yyn++; + break; + + case '"': + if (yyres) + yyres[yyn] = '\0'; + return yyn; + } + do_not_strip_quotes: ; + } + + if (! yyres) + return yystrlen (yystr); + + return yystpcpy (yyres, yystr) - yyres; +} +# endif + +/* Copy into *YYMSG, which is of size *YYMSG_ALLOC, an error message + about the unexpected token YYTOKEN for the state stack whose top is + YYSSP. + + Return 0 if *YYMSG was successfully written. Return 1 if *YYMSG is + not large enough to hold the message. In that case, also set + *YYMSG_ALLOC to the required number of bytes. Return 2 if the + required number of bytes is too large to store. */ +static int +yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg, + yytype_int16 *yyssp, int yytoken) +{ + YYSIZE_T yysize0 = yytnamerr (YY_NULL, yytname[yytoken]); + YYSIZE_T yysize = yysize0; + YYSIZE_T yysize1; + enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 }; + /* Internationalized format string. */ + const char *yyformat = YY_NULL; + /* Arguments of yyformat. */ + char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM]; + /* Number of reported tokens (one for the "unexpected", one per + "expected"). */ + int yycount = 0; + + /* There are many possibilities here to consider: + - Assume YYFAIL is not used. It's too flawed to consider. See + <http://lists.gnu.org/archive/html/bison-patches/2009-12/msg00024.html> + for details. YYERROR is fine as it does not invoke this + function. + - If this state is a consistent state with a default action, then + the only way this function was invoked is if the default action + is an error action. In that case, don't check for expected + tokens because there are none. + - The only way there can be no lookahead present (in yychar) is if + this state is a consistent state with a default action. Thus, + detecting the absence of a lookahead is sufficient to determine + that there is no unexpected or expected token to report. In that + case, just report a simple "syntax error". + - Don't assume there isn't a lookahead just because this state is a + consistent state with a default action. There might have been a + previous inconsistent state, consistent state with a non-default + action, or user semantic action that manipulated yychar. + - Of course, the expected token list depends on states to have + correct lookahead information, and it depends on the parser not + to perform extra reductions after fetching a lookahead from the + scanner and before detecting a syntax error. Thus, state merging + (from LALR or IELR) and default reductions corrupt the expected + token list. However, the list is correct for canonical LR with + one exception: it will still contain any token that will not be + accepted due to an error action in a later state. + */ + if (yytoken != YYEMPTY) + { + int yyn = yypact[*yyssp]; + yyarg[yycount++] = yytname[yytoken]; + if (!yypact_value_is_default (yyn)) + { + /* Start YYX at -YYN if negative to avoid negative indexes in + YYCHECK. In other words, skip the first -YYN actions for + this state because they are default actions. */ + int yyxbegin = yyn < 0 ? -yyn : 0; + /* Stay within bounds of both yycheck and yytname. */ + int yychecklim = YYLAST - yyn + 1; + int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS; + int yyx; + + for (yyx = yyxbegin; yyx < yyxend; ++yyx) + if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR + && !yytable_value_is_error (yytable[yyx + yyn])) + { + if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM) + { + yycount = 1; + yysize = yysize0; + break; + } + yyarg[yycount++] = yytname[yyx]; + yysize1 = yysize + yytnamerr (YY_NULL, yytname[yyx]); + if (! (yysize <= yysize1 + && yysize1 <= YYSTACK_ALLOC_MAXIMUM)) + return 2; + yysize = yysize1; + } + } + } + + switch (yycount) + { +# define YYCASE_(N, S) \ + case N: \ + yyformat = S; \ + break + YYCASE_(0, YY_("syntax error")); + YYCASE_(1, YY_("syntax error, unexpected %s")); + YYCASE_(2, YY_("syntax error, unexpected %s, expecting %s")); + YYCASE_(3, YY_("syntax error, unexpected %s, expecting %s or %s")); + YYCASE_(4, YY_("syntax error, unexpected %s, expecting %s or %s or %s")); + YYCASE_(5, YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s")); +# undef YYCASE_ + } + + yysize1 = yysize + yystrlen (yyformat); + if (! (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM)) + return 2; + yysize = yysize1; + + if (*yymsg_alloc < yysize) + { + *yymsg_alloc = 2 * yysize; + if (! (yysize <= *yymsg_alloc + && *yymsg_alloc <= YYSTACK_ALLOC_MAXIMUM)) + *yymsg_alloc = YYSTACK_ALLOC_MAXIMUM; + return 1; + } + + /* Avoid sprintf, as that infringes on the user's name space. + Don't have undefined behavior even if the translation + produced a string with the wrong number of "%s"s. */ + { + char *yyp = *yymsg; + int yyi = 0; + while ((*yyp = *yyformat) != '\0') + if (*yyp == '%' && yyformat[1] == 's' && yyi < yycount) + { + yyp += yytnamerr (yyp, yyarg[yyi++]); + yyformat += 2; + } + else + { + yyp++; + yyformat++; + } + } + return 0; +} +#endif /* YYERROR_VERBOSE */ + +/*-----------------------------------------------. +| Release the memory associated to this symbol. | +`-----------------------------------------------*/ + +/*ARGSUSED*/ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep) +#else +static void +yydestruct (yymsg, yytype, yyvaluep) + const char *yymsg; + int yytype; + YYSTYPE *yyvaluep; +#endif +{ + YYUSE (yyvaluep); + + if (!yymsg) + yymsg = "Deleting"; + YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp); + + switch (yytype) + { + + default: + break; + } +} + + + + +/* The lookahead symbol. */ +int yychar; + +/* The semantic value of the lookahead symbol. */ +YYSTYPE yylval; + +/* Number of syntax errors so far. */ +int yynerrs; + + +/*----------. +| yyparse. | +`----------*/ + +#ifdef YYPARSE_PARAM +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +int +yyparse (void *YYPARSE_PARAM) +#else +int +yyparse (YYPARSE_PARAM) + void *YYPARSE_PARAM; +#endif +#else /* ! YYPARSE_PARAM */ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +int +yyparse (void) +#else +int +yyparse () + +#endif +#endif +{ + int yystate; + /* Number of tokens to shift before error messages enabled. */ + int yyerrstatus; + + /* The stacks and their tools: + `yyss': related to states. + `yyvs': related to semantic values. + + Refer to the stacks through separate pointers, to allow yyoverflow + to reallocate them elsewhere. */ + + /* The state stack. */ + yytype_int16 yyssa[YYINITDEPTH]; + yytype_int16 *yyss; + yytype_int16 *yyssp; + + /* The semantic value stack. */ + YYSTYPE yyvsa[YYINITDEPTH]; + YYSTYPE *yyvs; + YYSTYPE *yyvsp; + + YYSIZE_T yystacksize; + + int yyn; + int yyresult; + /* Lookahead token as an internal (translated) token number. */ + int yytoken; + /* The variables used to return semantic value and location from the + action routines. */ + YYSTYPE yyval; + +#if YYERROR_VERBOSE + /* Buffer for error messages, and its allocated size. */ + char yymsgbuf[128]; + char *yymsg = yymsgbuf; + YYSIZE_T yymsg_alloc = sizeof yymsgbuf; +#endif + +#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N)) + + /* The number of symbols on the RHS of the reduced rule. + Keep to zero when no symbol should be popped. */ + int yylen = 0; + + yytoken = 0; + yyss = yyssa; + yyvs = yyvsa; + yystacksize = YYINITDEPTH; + + YYDPRINTF ((stderr, "Starting parse\n")); + + yystate = 0; + yyerrstatus = 0; + yynerrs = 0; + yychar = YYEMPTY; /* Cause a token to be read. */ + + /* Initialize stack pointers. + Waste one element of value and location stack + so that they stay on the same level as the state stack. + The wasted elements are never initialized. */ + yyssp = yyss; + yyvsp = yyvs; + goto yysetstate; + +/*------------------------------------------------------------. +| yynewstate -- Push a new state, which is found in yystate. | +`------------------------------------------------------------*/ + yynewstate: + /* In all cases, when you get here, the value and location stacks + have just been pushed. So pushing a state here evens the stacks. */ + yyssp++; + + yysetstate: + *yyssp = yystate; + + if (yyss + yystacksize - 1 <= yyssp) + { + /* Get the current used size of the three stacks, in elements. */ + YYSIZE_T yysize = yyssp - yyss + 1; + +#ifdef yyoverflow + { + /* Give user a chance to reallocate the stack. Use copies of + these so that the &'s don't force the real ones into + memory. */ + YYSTYPE *yyvs1 = yyvs; + yytype_int16 *yyss1 = yyss; + + /* Each stack pointer address is followed by the size of the + data in use in that stack, in bytes. This used to be a + conditional around just the two extra args, but that might + be undefined if yyoverflow is a macro. */ + yyoverflow (YY_("memory exhausted"), + &yyss1, yysize * sizeof (*yyssp), + &yyvs1, yysize * sizeof (*yyvsp), + &yystacksize); + + yyss = yyss1; + yyvs = yyvs1; + } +#else /* no yyoverflow */ +# ifndef YYSTACK_RELOCATE + goto yyexhaustedlab; +# else + /* Extend the stack our own way. */ + if (YYMAXDEPTH <= yystacksize) + goto yyexhaustedlab; + yystacksize *= 2; + if (YYMAXDEPTH < yystacksize) + yystacksize = YYMAXDEPTH; + + { + yytype_int16 *yyss1 = yyss; + union yyalloc *yyptr = + (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)); + if (! yyptr) + goto yyexhaustedlab; + YYSTACK_RELOCATE (yyss_alloc, yyss); + YYSTACK_RELOCATE (yyvs_alloc, yyvs); +# undef YYSTACK_RELOCATE + if (yyss1 != yyssa) + YYSTACK_FREE (yyss1); + } +# endif +#endif /* no yyoverflow */ + + yyssp = yyss + yysize - 1; + yyvsp = yyvs + yysize - 1; + + YYDPRINTF ((stderr, "Stack size increased to %lu\n", + (unsigned long int) yystacksize)); + + if (yyss + yystacksize - 1 <= yyssp) + YYABORT; + } + + YYDPRINTF ((stderr, "Entering state %d\n", yystate)); + + if (yystate == YYFINAL) + YYACCEPT; + + goto yybackup; + +/*-----------. +| yybackup. | +`-----------*/ +yybackup: + + /* Do appropriate processing given the current state. Read a + lookahead token if we need one and don't already have one. */ + + /* First try to decide what to do without reference to lookahead token. */ + yyn = yypact[yystate]; + if (yypact_value_is_default (yyn)) + goto yydefault; + + /* Not known => get a lookahead token if don't already have one. */ + + /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */ + if (yychar == YYEMPTY) + { + YYDPRINTF ((stderr, "Reading a token: ")); + yychar = YYLEX; + } + + if (yychar <= YYEOF) + { + yychar = yytoken = YYEOF; + YYDPRINTF ((stderr, "Now at end of input.\n")); + } + else + { + yytoken = YYTRANSLATE (yychar); + YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc); + } + + /* If the proper action on seeing token YYTOKEN is to reduce or to + detect an error, take that action. */ + yyn += yytoken; + if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken) + goto yydefault; + yyn = yytable[yyn]; + if (yyn <= 0) + { + if (yytable_value_is_error (yyn)) + goto yyerrlab; + yyn = -yyn; + goto yyreduce; + } + + /* Count tokens shifted since error; after three, turn off error + status. */ + if (yyerrstatus) + yyerrstatus--; + + /* Shift the lookahead token. */ + YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc); + + /* Discard the shifted token. */ + yychar = YYEMPTY; + + yystate = yyn; + *++yyvsp = yylval; + + goto yynewstate; + + +/*-----------------------------------------------------------. +| yydefault -- do the default action for the current state. | +`-----------------------------------------------------------*/ +yydefault: + yyn = yydefact[yystate]; + if (yyn == 0) + goto yyerrlab; + goto yyreduce; + + +/*-----------------------------. +| yyreduce -- Do a reduction. | +`-----------------------------*/ +yyreduce: + /* yyn is the number of a rule to reduce with. */ + yylen = yyr2[yyn]; + + /* If YYLEN is nonzero, implement the default value of the action: + `$$ = $1'. + + Otherwise, the following line sets YYVAL to garbage. + This behavior is undocumented and Bison + users should not rely upon it. Assigning to YYVAL + unconditionally makes the parser a bit smaller, and it avoids a + GCC warning that YYVAL may be used uninitialized. */ + yyval = yyvsp[1-yylen]; + + + YY_REDUCE_PRINT (yyn); + switch (yyn) + { + case 26: +/* Line 1787 of yacc.c */ +#line 359 "conf_parser.y" + { (yyval.number) = 0; } + break; + + case 28: +/* Line 1787 of yacc.c */ +#line 361 "conf_parser.y" + { + (yyval.number) = (yyvsp[(1) - (2)].number) + (yyvsp[(2) - (2)].number); + } + break; + + case 29: +/* Line 1787 of yacc.c */ +#line 365 "conf_parser.y" + { + (yyval.number) = (yyvsp[(1) - (3)].number) + (yyvsp[(3) - (3)].number); + } + break; + + case 30: +/* Line 1787 of yacc.c */ +#line 369 "conf_parser.y" + { + (yyval.number) = (yyvsp[(1) - (3)].number) * 60 + (yyvsp[(3) - (3)].number); + } + break; + + case 31: +/* Line 1787 of yacc.c */ +#line 373 "conf_parser.y" + { + (yyval.number) = (yyvsp[(1) - (3)].number) * 60 * 60 + (yyvsp[(3) - (3)].number); + } + break; + + case 32: +/* Line 1787 of yacc.c */ +#line 377 "conf_parser.y" + { + (yyval.number) = (yyvsp[(1) - (3)].number) * 60 * 60 * 24 + (yyvsp[(3) - (3)].number); + } + break; + + case 33: +/* Line 1787 of yacc.c */ +#line 381 "conf_parser.y" + { + (yyval.number) = (yyvsp[(1) - (3)].number) * 60 * 60 * 24 * 7 + (yyvsp[(3) - (3)].number); + } + break; + + case 34: +/* Line 1787 of yacc.c */ +#line 386 "conf_parser.y" + { (yyval.number) = 0; } + break; + + case 36: +/* Line 1787 of yacc.c */ +#line 387 "conf_parser.y" + { (yyval.number) = (yyvsp[(1) - (2)].number) + (yyvsp[(2) - (2)].number); } + break; + + case 37: +/* Line 1787 of yacc.c */ +#line 388 "conf_parser.y" + { (yyval.number) = (yyvsp[(1) - (3)].number) + (yyvsp[(3) - (3)].number); } + break; + + case 38: +/* Line 1787 of yacc.c */ +#line 389 "conf_parser.y" + { (yyval.number) = (yyvsp[(1) - (3)].number) * 1024 + (yyvsp[(3) - (3)].number); } + break; + + case 39: +/* Line 1787 of yacc.c */ +#line 390 "conf_parser.y" + { (yyval.number) = (yyvsp[(1) - (3)].number) * 1024 * 1024 + (yyvsp[(3) - (3)].number); } + break; + + case 46: +/* Line 1787 of yacc.c */ +#line 404 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + add_conf_module(libio_basename(yylval.string)); +} + break; + + case 47: +/* Line 1787 of yacc.c */ +#line 410 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + mod_add_path(yylval.string); +} + break; + + case 71: +/* Line 1787 of yacc.c */ +#line 435 "conf_parser.y" + { +#ifdef HAVE_LIBCRYPTO + if (conf_parser_ctx.pass == 2 && ServerInfo.client_ctx) + SSL_CTX_clear_options(ServerInfo.client_ctx, SSL_OP_NO_SSLv3); +#endif +} + break; + + case 72: +/* Line 1787 of yacc.c */ +#line 441 "conf_parser.y" + { +#ifdef HAVE_LIBCRYPTO + if (conf_parser_ctx.pass == 2 && ServerInfo.client_ctx) + SSL_CTX_clear_options(ServerInfo.client_ctx, SSL_OP_NO_TLSv1); +#endif +} + break; + + case 75: +/* Line 1787 of yacc.c */ +#line 450 "conf_parser.y" + { +#ifdef HAVE_LIBCRYPTO + if (conf_parser_ctx.pass == 2 && ServerInfo.server_ctx) + SSL_CTX_clear_options(ServerInfo.server_ctx, SSL_OP_NO_SSLv3); +#endif +} + break; + + case 76: +/* Line 1787 of yacc.c */ +#line 456 "conf_parser.y" + { +#ifdef HAVE_LIBCRYPTO + if (conf_parser_ctx.pass == 2 && ServerInfo.server_ctx) + SSL_CTX_clear_options(ServerInfo.server_ctx, SSL_OP_NO_TLSv1); +#endif +} + break; + + case 77: +/* Line 1787 of yacc.c */ +#line 464 "conf_parser.y" + { +#ifdef HAVE_LIBCRYPTO + if (conf_parser_ctx.pass == 2 && ServerInfo.server_ctx) + { + if (!ServerInfo.rsa_private_key_file) + { + yyerror("No rsa_private_key_file specified, SSL disabled"); + break; + } + + if (SSL_CTX_use_certificate_file(ServerInfo.server_ctx, yylval.string, + SSL_FILETYPE_PEM) <= 0 || + SSL_CTX_use_certificate_file(ServerInfo.client_ctx, yylval.string, + SSL_FILETYPE_PEM) <= 0) + { + yyerror(ERR_lib_error_string(ERR_get_error())); + break; + } + + if (SSL_CTX_use_PrivateKey_file(ServerInfo.server_ctx, ServerInfo.rsa_private_key_file, + SSL_FILETYPE_PEM) <= 0 || + SSL_CTX_use_PrivateKey_file(ServerInfo.client_ctx, ServerInfo.rsa_private_key_file, + SSL_FILETYPE_PEM) <= 0) + { + yyerror(ERR_lib_error_string(ERR_get_error())); + break; + } + + if (!SSL_CTX_check_private_key(ServerInfo.server_ctx) || + !SSL_CTX_check_private_key(ServerInfo.client_ctx)) + { + yyerror(ERR_lib_error_string(ERR_get_error())); + break; + } + } +#endif +} + break; + + case 78: +/* Line 1787 of yacc.c */ +#line 503 "conf_parser.y" + { +#ifdef HAVE_LIBCRYPTO + if (conf_parser_ctx.pass == 1) + { + BIO *file; + + if (ServerInfo.rsa_private_key) + { + RSA_free(ServerInfo.rsa_private_key); + ServerInfo.rsa_private_key = NULL; + } + + if (ServerInfo.rsa_private_key_file) + { + MyFree(ServerInfo.rsa_private_key_file); + ServerInfo.rsa_private_key_file = NULL; + } + + DupString(ServerInfo.rsa_private_key_file, yylval.string); + + if ((file = BIO_new_file(yylval.string, "r")) == NULL) + { + yyerror("File open failed, ignoring"); + break; + } + + ServerInfo.rsa_private_key = PEM_read_bio_RSAPrivateKey(file, NULL, 0, NULL); + + BIO_set_close(file, BIO_CLOSE); + BIO_free(file); + + if (ServerInfo.rsa_private_key == NULL) + { + yyerror("Couldn't extract key, ignoring"); + break; + } + + if (!RSA_check_key(ServerInfo.rsa_private_key)) + { + RSA_free(ServerInfo.rsa_private_key); + ServerInfo.rsa_private_key = NULL; + + yyerror("Invalid key, ignoring"); + break; + } + + /* require 2048 bit (256 byte) key */ + if (RSA_size(ServerInfo.rsa_private_key) != 256) + { + RSA_free(ServerInfo.rsa_private_key); + ServerInfo.rsa_private_key = NULL; + + yyerror("Not a 2048 bit key, ignoring"); + } + } +#endif +} + break; + + case 79: +/* Line 1787 of yacc.c */ +#line 562 "conf_parser.y" + { +/* TBD - XXX: error reporting */ +#ifdef HAVE_LIBCRYPTO + if (conf_parser_ctx.pass == 2 && ServerInfo.server_ctx) + { + BIO *file = BIO_new_file(yylval.string, "r"); + + if (file) + { + DH *dh = PEM_read_bio_DHparams(file, NULL, NULL, NULL); + + BIO_free(file); + + if (dh) + { + if (DH_size(dh) < 128) + ilog(LOG_TYPE_IRCD, "Ignoring serverinfo::ssl_dh_param_file -- need at least a 1024 bit DH prime size"); + else + SSL_CTX_set_tmp_dh(ServerInfo.server_ctx, dh); + + DH_free(dh); + } + } + } +#endif +} + break; + + case 80: +/* Line 1787 of yacc.c */ +#line 590 "conf_parser.y" + { +#ifdef HAVE_LIBCRYPTO + if (conf_parser_ctx.pass == 2 && ServerInfo.server_ctx) + SSL_CTX_set_cipher_list(ServerInfo.server_ctx, yylval.string); +#endif +} + break; + + case 81: +/* Line 1787 of yacc.c */ +#line 598 "conf_parser.y" + { + /* this isn't rehashable */ + if (conf_parser_ctx.pass == 2 && !ServerInfo.name) + { + if (valid_servname(yylval.string)) + DupString(ServerInfo.name, yylval.string); + else + { + ilog(LOG_TYPE_IRCD, "Ignoring serverinfo::name -- invalid name. Aborting."); + exit(0); + } + } +} + break; + + case 82: +/* Line 1787 of yacc.c */ +#line 613 "conf_parser.y" + { + /* this isn't rehashable */ + if (conf_parser_ctx.pass == 2 && !ServerInfo.sid) + { + if (valid_sid(yylval.string)) + DupString(ServerInfo.sid, yylval.string); + else + { + ilog(LOG_TYPE_IRCD, "Ignoring serverinfo::sid -- invalid SID. Aborting."); + exit(0); + } + } +} + break; + + case 83: +/* Line 1787 of yacc.c */ +#line 628 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + { + MyFree(ServerInfo.description); + DupString(ServerInfo.description,yylval.string); + } +} + break; + + case 84: +/* Line 1787 of yacc.c */ +#line 637 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + { + char *p; + + if ((p = strchr(yylval.string, ' ')) != NULL) + p = '\0'; + + MyFree(ServerInfo.network_name); + DupString(ServerInfo.network_name, yylval.string); + } +} + break; + + case 85: +/* Line 1787 of yacc.c */ +#line 651 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + { + MyFree(ServerInfo.network_desc); + DupString(ServerInfo.network_desc, yylval.string); + } +} + break; + + case 86: +/* Line 1787 of yacc.c */ +#line 660 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2 && *yylval.string != '*') + { + struct addrinfo hints, *res; + + memset(&hints, 0, sizeof(hints)); + + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST; + + if (getaddrinfo(yylval.string, NULL, &hints, &res)) + ilog(LOG_TYPE_IRCD, "Invalid netmask for server vhost(%s)", yylval.string); + else + { + assert(res != NULL); + + memcpy(&ServerInfo.ip, res->ai_addr, res->ai_addrlen); + ServerInfo.ip.ss.ss_family = res->ai_family; + ServerInfo.ip.ss_len = res->ai_addrlen; + freeaddrinfo(res); + + ServerInfo.specific_ipv4_vhost = 1; + } + } +} + break; + + case 87: +/* Line 1787 of yacc.c */ +#line 688 "conf_parser.y" + { +#ifdef IPV6 + if (conf_parser_ctx.pass == 2 && *yylval.string != '*') + { + struct addrinfo hints, *res; + + memset(&hints, 0, sizeof(hints)); + + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST; + + if (getaddrinfo(yylval.string, NULL, &hints, &res)) + ilog(LOG_TYPE_IRCD, "Invalid netmask for server vhost6(%s)", yylval.string); + else + { + assert(res != NULL); + + memcpy(&ServerInfo.ip6, res->ai_addr, res->ai_addrlen); + ServerInfo.ip6.ss.ss_family = res->ai_family; + ServerInfo.ip6.ss_len = res->ai_addrlen; + freeaddrinfo(res); + + ServerInfo.specific_ipv6_vhost = 1; + } + } +#endif +} + break; + + case 88: +/* Line 1787 of yacc.c */ +#line 718 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + { + recalc_fdlimit(NULL); + + if ((yyvsp[(3) - (4)].number) < MAXCLIENTS_MIN) + { + char buf[IRCD_BUFSIZE]; + ircsprintf(buf, "MAXCLIENTS too low, setting to %d", MAXCLIENTS_MIN); + yyerror(buf); + } + else if ((yyvsp[(3) - (4)].number) > MAXCLIENTS_MAX) + { + char buf[IRCD_BUFSIZE]; + ircsprintf(buf, "MAXCLIENTS too high, setting to %d", MAXCLIENTS_MAX); + yyerror(buf); + } + else + ServerInfo.max_clients = (yyvsp[(3) - (4)].number); + } +} + break; + + case 89: +/* Line 1787 of yacc.c */ +#line 741 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + ServerInfo.hub = yylval.number; +} + break; + + case 97: +/* Line 1787 of yacc.c */ +#line 756 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + { + MyFree(AdminInfo.name); + DupString(AdminInfo.name, yylval.string); + } +} + break; + + case 98: +/* Line 1787 of yacc.c */ +#line 765 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + { + MyFree(AdminInfo.email); + DupString(AdminInfo.email, yylval.string); + } +} + break; + + case 99: +/* Line 1787 of yacc.c */ +#line 774 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + { + MyFree(AdminInfo.description); + DupString(AdminInfo.description, yylval.string); + } +} + break; + + case 106: +/* Line 1787 of yacc.c */ +#line 792 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + ConfigLoggingEntry.use_logging = yylval.number; +} + break; + + case 107: +/* Line 1787 of yacc.c */ +#line 798 "conf_parser.y" + { + lfile[0] = '\0'; + ltype = 0; + lsize = 0; +} + break; + + case 108: +/* Line 1787 of yacc.c */ +#line 803 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2 && ltype > 0) + log_add_file(ltype, lsize, lfile); +} + break; + + case 115: +/* Line 1787 of yacc.c */ +#line 815 "conf_parser.y" + { + strlcpy(lfile, yylval.string, sizeof(lfile)); +} + break; + + case 116: +/* Line 1787 of yacc.c */ +#line 820 "conf_parser.y" + { + lsize = (yyvsp[(3) - (4)].number); +} + break; + + case 117: +/* Line 1787 of yacc.c */ +#line 823 "conf_parser.y" + { + lsize = 0; +} + break; + + case 118: +/* Line 1787 of yacc.c */ +#line 828 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + ltype = 0; +} + break; + + case 122: +/* Line 1787 of yacc.c */ +#line 835 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + ltype = LOG_TYPE_USER; +} + break; + + case 123: +/* Line 1787 of yacc.c */ +#line 839 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + ltype = LOG_TYPE_OPER; +} + break; + + case 124: +/* Line 1787 of yacc.c */ +#line 843 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + ltype = LOG_TYPE_GLINE; +} + break; + + case 125: +/* Line 1787 of yacc.c */ +#line 847 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + ltype = LOG_TYPE_DLINE; +} + break; + + case 126: +/* Line 1787 of yacc.c */ +#line 851 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + ltype = LOG_TYPE_KLINE; +} + break; + + case 127: +/* Line 1787 of yacc.c */ +#line 855 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + ltype = LOG_TYPE_KILL; +} + break; + + case 128: +/* Line 1787 of yacc.c */ +#line 859 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + ltype = LOG_TYPE_DEBUG; +} + break; + + case 129: +/* Line 1787 of yacc.c */ +#line 869 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + { + yy_conf = make_conf_item(OPER_TYPE); + yy_aconf = map_to_conf(yy_conf); + SetConfEncrypted(yy_aconf); /* Yes, the default is encrypted */ + } + else + { + MyFree(class_name); + class_name = NULL; + } +} + break; + + case 130: +/* Line 1787 of yacc.c */ +#line 882 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + { + struct CollectItem *yy_tmp; + dlink_node *ptr; + dlink_node *next_ptr; + + conf_add_class_to_conf(yy_conf, class_name); + + /* Now, make sure there is a copy of the "base" given oper + * block in each of the collected copies + */ + + DLINK_FOREACH_SAFE(ptr, next_ptr, col_conf_list.head) + { + struct AccessItem *new_aconf; + struct ConfItem *new_conf; + yy_tmp = ptr->data; + + new_conf = make_conf_item(OPER_TYPE); + new_aconf = (struct AccessItem *)map_to_conf(new_conf); + + new_aconf->flags = yy_aconf->flags; + + if (yy_conf->name != NULL) + DupString(new_conf->name, yy_conf->name); + if (yy_tmp->user != NULL) + DupString(new_aconf->user, yy_tmp->user); + else + DupString(new_aconf->user, "*"); + if (yy_tmp->host != NULL) + DupString(new_aconf->host, yy_tmp->host); + else + DupString(new_aconf->host, "*"); + + new_aconf->type = parse_netmask(new_aconf->host, &new_aconf->addr, + &new_aconf->bits); + + conf_add_class_to_conf(new_conf, class_name); + if (yy_aconf->passwd != NULL) + DupString(new_aconf->passwd, yy_aconf->passwd); + + new_aconf->port = yy_aconf->port; +#ifdef HAVE_LIBCRYPTO + if (yy_aconf->rsa_public_key_file != NULL) + { + BIO *file; + + DupString(new_aconf->rsa_public_key_file, + yy_aconf->rsa_public_key_file); + + file = BIO_new_file(yy_aconf->rsa_public_key_file, "r"); + new_aconf->rsa_public_key = PEM_read_bio_RSA_PUBKEY(file, + NULL, 0, NULL); + BIO_set_close(file, BIO_CLOSE); + BIO_free(file); + } +#endif + +#ifdef HAVE_LIBCRYPTO + if (yy_tmp->name && (yy_tmp->passwd || yy_aconf->rsa_public_key) + && yy_tmp->host) +#else + if (yy_tmp->name && yy_tmp->passwd && yy_tmp->host) +#endif + { + conf_add_class_to_conf(new_conf, class_name); + if (yy_tmp->name != NULL) + DupString(new_conf->name, yy_tmp->name); + } + + dlinkDelete(&yy_tmp->node, &col_conf_list); + free_collect_item(yy_tmp); + } + + yy_conf = NULL; + yy_aconf = NULL; + + + MyFree(class_name); + class_name = NULL; + } +} + break; + + case 142: +/* Line 1787 of yacc.c */ +#line 972 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + { + MyFree(yy_conf->name); + DupString(yy_conf->name, yylval.string); + } +} + break; + + case 143: +/* Line 1787 of yacc.c */ +#line 981 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + { + struct split_nuh_item nuh; + + nuh.nuhmask = yylval.string; + nuh.nickptr = NULL; + nuh.userptr = userbuf; + nuh.hostptr = hostbuf; + + nuh.nicksize = 0; + nuh.usersize = sizeof(userbuf); + nuh.hostsize = sizeof(hostbuf); + + split_nuh(&nuh); + + if (yy_aconf->user == NULL) + { + DupString(yy_aconf->user, userbuf); + DupString(yy_aconf->host, hostbuf); + + yy_aconf->type = parse_netmask(yy_aconf->host, &yy_aconf->addr, + &yy_aconf->bits); + } + else + { + struct CollectItem *yy_tmp = MyMalloc(sizeof(struct CollectItem)); + + DupString(yy_tmp->user, userbuf); + DupString(yy_tmp->host, hostbuf); + + dlinkAdd(yy_tmp, &yy_tmp->node, &col_conf_list); + } + } +} + break; + + case 144: +/* Line 1787 of yacc.c */ +#line 1018 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + { + if (yy_aconf->passwd != NULL) + memset(yy_aconf->passwd, 0, strlen(yy_aconf->passwd)); + + MyFree(yy_aconf->passwd); + DupString(yy_aconf->passwd, yylval.string); + } +} + break; + + case 145: +/* Line 1787 of yacc.c */ +#line 1030 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + { + if (yylval.number) + SetConfEncrypted(yy_aconf); + else + ClearConfEncrypted(yy_aconf); + } +} + break; + + case 146: +/* Line 1787 of yacc.c */ +#line 1041 "conf_parser.y" + { +#ifdef HAVE_LIBCRYPTO + if (conf_parser_ctx.pass == 2) + { + BIO *file; + + if (yy_aconf->rsa_public_key != NULL) + { + RSA_free(yy_aconf->rsa_public_key); + yy_aconf->rsa_public_key = NULL; + } + + if (yy_aconf->rsa_public_key_file != NULL) + { + MyFree(yy_aconf->rsa_public_key_file); + yy_aconf->rsa_public_key_file = NULL; + } + + DupString(yy_aconf->rsa_public_key_file, yylval.string); + file = BIO_new_file(yylval.string, "r"); + + if (file == NULL) + { + yyerror("Ignoring rsa_public_key_file -- file doesn't exist"); + break; + } + + yy_aconf->rsa_public_key = PEM_read_bio_RSA_PUBKEY(file, NULL, 0, NULL); + + if (yy_aconf->rsa_public_key == NULL) + { + yyerror("Ignoring rsa_public_key_file -- Key invalid; check key syntax."); + break; + } + + BIO_set_close(file, BIO_CLOSE); + BIO_free(file); + } +#endif /* HAVE_LIBCRYPTO */ +} + break; + + case 147: +/* Line 1787 of yacc.c */ +#line 1083 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + { + MyFree(class_name); + DupString(class_name, yylval.string); + } +} + break; + + case 148: +/* Line 1787 of yacc.c */ +#line 1092 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + yy_aconf->modes = 0; +} + break; + + case 152: +/* Line 1787 of yacc.c */ +#line 1099 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + yy_aconf->modes |= UMODE_BOTS; +} + break; + + case 153: +/* Line 1787 of yacc.c */ +#line 1103 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + yy_aconf->modes |= UMODE_CCONN; +} + break; + + case 154: +/* Line 1787 of yacc.c */ +#line 1107 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + yy_aconf->modes |= UMODE_CCONN_FULL; +} + break; + + case 155: +/* Line 1787 of yacc.c */ +#line 1111 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + yy_aconf->modes |= UMODE_DEAF; +} + break; + + case 156: +/* Line 1787 of yacc.c */ +#line 1115 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + yy_aconf->modes |= UMODE_DEBUG; +} + break; + + case 157: +/* Line 1787 of yacc.c */ +#line 1119 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + yy_aconf->modes |= UMODE_FULL; +} + break; + + case 158: +/* Line 1787 of yacc.c */ +#line 1123 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + yy_aconf->modes |= UMODE_HIDDEN; +} + break; + + case 159: +/* Line 1787 of yacc.c */ +#line 1127 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + yy_aconf->modes |= UMODE_SKILL; +} + break; + + case 160: +/* Line 1787 of yacc.c */ +#line 1131 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + yy_aconf->modes |= UMODE_NCHANGE; +} + break; + + case 161: +/* Line 1787 of yacc.c */ +#line 1135 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + yy_aconf->modes |= UMODE_REJ; +} + break; + + case 162: +/* Line 1787 of yacc.c */ +#line 1139 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + yy_aconf->modes |= UMODE_UNAUTH; +} + break; + + case 163: +/* Line 1787 of yacc.c */ +#line 1143 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + yy_aconf->modes |= UMODE_SPY; +} + break; + + case 164: +/* Line 1787 of yacc.c */ +#line 1147 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + yy_aconf->modes |= UMODE_EXTERNAL; +} + break; + + case 165: +/* Line 1787 of yacc.c */ +#line 1151 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + yy_aconf->modes |= UMODE_OPERWALL; +} + break; + + case 166: +/* Line 1787 of yacc.c */ +#line 1155 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + yy_aconf->modes |= UMODE_SERVNOTICE; +} + break; + + case 167: +/* Line 1787 of yacc.c */ +#line 1159 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + yy_aconf->modes |= UMODE_INVISIBLE; +} + break; + + case 168: +/* Line 1787 of yacc.c */ +#line 1163 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + yy_aconf->modes |= UMODE_WALLOP; +} + break; + + case 169: +/* Line 1787 of yacc.c */ +#line 1167 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + yy_aconf->modes |= UMODE_SOFTCALLERID; +} + break; + + case 170: +/* Line 1787 of yacc.c */ +#line 1171 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + yy_aconf->modes |= UMODE_CALLERID; +} + break; + + case 171: +/* Line 1787 of yacc.c */ +#line 1175 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + yy_aconf->modes |= UMODE_LOCOPS; +} + break; + + case 172: +/* Line 1787 of yacc.c */ +#line 1181 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + yy_aconf->port = 0; +} + break; + + case 176: +/* Line 1787 of yacc.c */ +#line 1188 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + yy_aconf->port |= OPER_FLAG_GLOBAL_KILL; +} + break; + + case 177: +/* Line 1787 of yacc.c */ +#line 1192 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + yy_aconf->port |= OPER_FLAG_REMOTE; +} + break; + + case 178: +/* Line 1787 of yacc.c */ +#line 1196 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + yy_aconf->port |= OPER_FLAG_K; +} + break; + + case 179: +/* Line 1787 of yacc.c */ +#line 1200 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + yy_aconf->port |= OPER_FLAG_UNKLINE; +} + break; + + case 180: +/* Line 1787 of yacc.c */ +#line 1204 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + yy_aconf->port |= OPER_FLAG_DLINE; +} + break; + + case 181: +/* Line 1787 of yacc.c */ +#line 1208 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + yy_aconf->port |= OPER_FLAG_UNDLINE; +} + break; + + case 182: +/* Line 1787 of yacc.c */ +#line 1212 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + yy_aconf->port |= OPER_FLAG_X; +} + break; + + case 183: +/* Line 1787 of yacc.c */ +#line 1216 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + yy_aconf->port |= OPER_FLAG_GLINE; +} + break; + + case 184: +/* Line 1787 of yacc.c */ +#line 1220 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + yy_aconf->port |= OPER_FLAG_DIE; +} + break; + + case 185: +/* Line 1787 of yacc.c */ +#line 1224 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + yy_aconf->port |= OPER_FLAG_RESTART; +} + break; + + case 186: +/* Line 1787 of yacc.c */ +#line 1228 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + yy_aconf->port |= OPER_FLAG_REHASH; +} + break; + + case 187: +/* Line 1787 of yacc.c */ +#line 1232 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + yy_aconf->port |= OPER_FLAG_ADMIN; +} + break; + + case 188: +/* Line 1787 of yacc.c */ +#line 1236 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + yy_aconf->port |= OPER_FLAG_N; +} + break; + + case 189: +/* Line 1787 of yacc.c */ +#line 1240 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + yy_aconf->port |= OPER_FLAG_OPERWALL; +} + break; + + case 190: +/* Line 1787 of yacc.c */ +#line 1244 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + yy_aconf->port |= OPER_FLAG_GLOBOPS; +} + break; + + case 191: +/* Line 1787 of yacc.c */ +#line 1248 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + yy_aconf->port |= OPER_FLAG_OPER_SPY; +} + break; + + case 192: +/* Line 1787 of yacc.c */ +#line 1252 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + yy_aconf->port |= OPER_FLAG_REMOTEBAN; +} + break; + + case 193: +/* Line 1787 of yacc.c */ +#line 1256 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + yy_aconf->port |= OPER_FLAG_SET; +} + break; + + case 194: +/* Line 1787 of yacc.c */ +#line 1260 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + yy_aconf->port |= OPER_FLAG_MODULE; +} + break; + + case 195: +/* Line 1787 of yacc.c */ +#line 1270 "conf_parser.y" + { + if (conf_parser_ctx.pass == 1) + { + yy_conf = make_conf_item(CLASS_TYPE); + yy_class = map_to_conf(yy_conf); + } +} + break; + + case 196: +/* Line 1787 of yacc.c */ +#line 1277 "conf_parser.y" + { + if (conf_parser_ctx.pass == 1) + { + struct ConfItem *cconf = NULL; + struct ClassItem *class = NULL; + + if (yy_class_name == NULL) + delete_conf_item(yy_conf); + else + { + cconf = find_exact_name_conf(CLASS_TYPE, NULL, yy_class_name, NULL, NULL); + + if (cconf != NULL) /* The class existed already */ + { + int user_count = 0; + + rebuild_cidr_class(cconf, yy_class); + + class = map_to_conf(cconf); + + user_count = class->curr_user_count; + memcpy(class, yy_class, sizeof(*class)); + class->curr_user_count = user_count; + class->active = 1; + + delete_conf_item(yy_conf); + + MyFree(cconf->name); /* Allows case change of class name */ + cconf->name = yy_class_name; + } + else /* Brand new class */ + { + MyFree(yy_conf->name); /* just in case it was allocated */ + yy_conf->name = yy_class_name; + yy_class->active = 1; + } + } + + yy_class_name = NULL; + } +} + break; + + case 214: +/* Line 1787 of yacc.c */ +#line 1335 "conf_parser.y" + { + if (conf_parser_ctx.pass == 1) + { + MyFree(yy_class_name); + DupString(yy_class_name, yylval.string); + } +} + break; + + case 215: +/* Line 1787 of yacc.c */ +#line 1344 "conf_parser.y" + { + if (conf_parser_ctx.pass == 1) + yy_class->ping_freq = (yyvsp[(3) - (4)].number); +} + break; + + case 216: +/* Line 1787 of yacc.c */ +#line 1350 "conf_parser.y" + { + if (conf_parser_ctx.pass == 1) + yy_class->ping_warning = (yyvsp[(3) - (4)].number); +} + break; + + case 217: +/* Line 1787 of yacc.c */ +#line 1356 "conf_parser.y" + { + if (conf_parser_ctx.pass == 1) + yy_class->max_perip = (yyvsp[(3) - (4)].number); +} + break; + + case 218: +/* Line 1787 of yacc.c */ +#line 1362 "conf_parser.y" + { + if (conf_parser_ctx.pass == 1) + yy_class->con_freq = (yyvsp[(3) - (4)].number); +} + break; + + case 219: +/* Line 1787 of yacc.c */ +#line 1368 "conf_parser.y" + { + if (conf_parser_ctx.pass == 1) + yy_class->max_total = (yyvsp[(3) - (4)].number); +} + break; + + case 220: +/* Line 1787 of yacc.c */ +#line 1374 "conf_parser.y" + { + if (conf_parser_ctx.pass == 1) + yy_class->max_global = (yyvsp[(3) - (4)].number); +} + break; + + case 221: +/* Line 1787 of yacc.c */ +#line 1380 "conf_parser.y" + { + if (conf_parser_ctx.pass == 1) + yy_class->max_local = (yyvsp[(3) - (4)].number); +} + break; + + case 222: +/* Line 1787 of yacc.c */ +#line 1386 "conf_parser.y" + { + if (conf_parser_ctx.pass == 1) + yy_class->max_ident = (yyvsp[(3) - (4)].number); +} + break; + + case 223: +/* Line 1787 of yacc.c */ +#line 1392 "conf_parser.y" + { + if (conf_parser_ctx.pass == 1) + yy_class->max_sendq = (yyvsp[(3) - (4)].number); +} + break; + + case 224: +/* Line 1787 of yacc.c */ +#line 1398 "conf_parser.y" + { + if (conf_parser_ctx.pass == 1) + if ((yyvsp[(3) - (4)].number) >= CLIENT_FLOOD_MIN && (yyvsp[(3) - (4)].number) <= CLIENT_FLOOD_MAX) + yy_class->max_recvq = (yyvsp[(3) - (4)].number); +} + break; + + case 225: +/* Line 1787 of yacc.c */ +#line 1405 "conf_parser.y" + { + if (conf_parser_ctx.pass == 1) + yy_class->cidr_bitlen_ipv4 = (yyvsp[(3) - (4)].number) > 32 ? 32 : (yyvsp[(3) - (4)].number); +} + break; + + case 226: +/* Line 1787 of yacc.c */ +#line 1411 "conf_parser.y" + { + if (conf_parser_ctx.pass == 1) + yy_class->cidr_bitlen_ipv6 = (yyvsp[(3) - (4)].number) > 128 ? 128 : (yyvsp[(3) - (4)].number); +} + break; + + case 227: +/* Line 1787 of yacc.c */ +#line 1417 "conf_parser.y" + { + if (conf_parser_ctx.pass == 1) + yy_class->number_per_cidr = (yyvsp[(3) - (4)].number); +} + break; + + case 228: +/* Line 1787 of yacc.c */ +#line 1426 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + { + listener_address = NULL; + listener_flags = 0; + } +} + break; + + case 229: +/* Line 1787 of yacc.c */ +#line 1433 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + { + MyFree(listener_address); + listener_address = NULL; + } +} + break; + + case 230: +/* Line 1787 of yacc.c */ +#line 1442 "conf_parser.y" + { + listener_flags = 0; +} + break; + + case 234: +/* Line 1787 of yacc.c */ +#line 1448 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + listener_flags |= LISTENER_SSL; +} + break; + + case 235: +/* Line 1787 of yacc.c */ +#line 1452 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + listener_flags |= LISTENER_HIDDEN; +} + break; + + case 236: +/* Line 1787 of yacc.c */ +#line 1456 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + listener_flags |= LISTENER_SERVER; +} + break; + + case 244: +/* Line 1787 of yacc.c */ +#line 1466 "conf_parser.y" + { listener_flags = 0; } + break; + + case 248: +/* Line 1787 of yacc.c */ +#line 1471 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + { + if ((listener_flags & LISTENER_SSL)) +#ifdef HAVE_LIBCRYPTO + if (!ServerInfo.server_ctx) +#endif + { + yyerror("SSL not available - port closed"); + break; + } + add_listener((yyvsp[(1) - (1)].number), listener_address, listener_flags); + } +} + break; + + case 249: +/* Line 1787 of yacc.c */ +#line 1485 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + { + int i; + + if ((listener_flags & LISTENER_SSL)) +#ifdef HAVE_LIBCRYPTO + if (!ServerInfo.server_ctx) +#endif + { + yyerror("SSL not available - port closed"); + break; + } + + for (i = (yyvsp[(1) - (3)].number); i <= (yyvsp[(3) - (3)].number); ++i) + add_listener(i, listener_address, listener_flags); + } +} + break; + + case 250: +/* Line 1787 of yacc.c */ +#line 1505 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + { + MyFree(listener_address); + DupString(listener_address, yylval.string); + } +} + break; + + case 251: +/* Line 1787 of yacc.c */ +#line 1514 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + { + MyFree(listener_address); + DupString(listener_address, yylval.string); + } +} + break; + + case 252: +/* Line 1787 of yacc.c */ +#line 1526 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + { + yy_conf = make_conf_item(CLIENT_TYPE); + yy_aconf = map_to_conf(yy_conf); + } + else + { + MyFree(class_name); + class_name = NULL; + } +} + break; + + case 253: +/* Line 1787 of yacc.c */ +#line 1538 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + { + struct CollectItem *yy_tmp = NULL; + dlink_node *ptr = NULL, *next_ptr = NULL; + + if (yy_aconf->user && yy_aconf->host) + { + conf_add_class_to_conf(yy_conf, class_name); + add_conf_by_address(CONF_CLIENT, yy_aconf); + } + else + delete_conf_item(yy_conf); + + /* copy over settings from first struct */ + DLINK_FOREACH_SAFE(ptr, next_ptr, col_conf_list.head) + { + struct AccessItem *new_aconf; + struct ConfItem *new_conf; + + new_conf = make_conf_item(CLIENT_TYPE); + new_aconf = map_to_conf(new_conf); + + yy_tmp = ptr->data; + + assert(yy_tmp->user && yy_tmp->host); + + if (yy_aconf->passwd != NULL) + DupString(new_aconf->passwd, yy_aconf->passwd); + if (yy_conf->name != NULL) + DupString(new_conf->name, yy_conf->name); + if (yy_aconf->passwd != NULL) + DupString(new_aconf->passwd, yy_aconf->passwd); + + new_aconf->flags = yy_aconf->flags; + new_aconf->port = yy_aconf->port; + + DupString(new_aconf->user, yy_tmp->user); + collapse(new_aconf->user); + + DupString(new_aconf->host, yy_tmp->host); + collapse(new_aconf->host); + + conf_add_class_to_conf(new_conf, class_name); + add_conf_by_address(CONF_CLIENT, new_aconf); + dlinkDelete(&yy_tmp->node, &col_conf_list); + free_collect_item(yy_tmp); + } + + MyFree(class_name); + class_name = NULL; + yy_conf = NULL; + yy_aconf = NULL; + } +} + break; + + case 265: +/* Line 1787 of yacc.c */ +#line 1600 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + { + struct CollectItem *yy_tmp = NULL; + struct split_nuh_item nuh; + + nuh.nuhmask = yylval.string; + nuh.nickptr = NULL; + nuh.userptr = userbuf; + nuh.hostptr = hostbuf; + + nuh.nicksize = 0; + nuh.usersize = sizeof(userbuf); + nuh.hostsize = sizeof(hostbuf); + + split_nuh(&nuh); + + if (yy_aconf->user == NULL) + { + DupString(yy_aconf->user, userbuf); + DupString(yy_aconf->host, hostbuf); + } + else + { + yy_tmp = MyMalloc(sizeof(struct CollectItem)); + + DupString(yy_tmp->user, userbuf); + DupString(yy_tmp->host, hostbuf); + + dlinkAdd(yy_tmp, &yy_tmp->node, &col_conf_list); + } + } +} + break; + + case 266: +/* Line 1787 of yacc.c */ +#line 1635 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + { + /* be paranoid */ + if (yy_aconf->passwd != NULL) + memset(yy_aconf->passwd, 0, strlen(yy_aconf->passwd)); + + MyFree(yy_aconf->passwd); + DupString(yy_aconf->passwd, yylval.string); + } +} + break; + + case 267: +/* Line 1787 of yacc.c */ +#line 1648 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + { + MyFree(class_name); + DupString(class_name, yylval.string); + } +} + break; + + case 268: +/* Line 1787 of yacc.c */ +#line 1657 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + { + if (yylval.number) + SetConfEncrypted(yy_aconf); + else + ClearConfEncrypted(yy_aconf); + } +} + break; + + case 269: +/* Line 1787 of yacc.c */ +#line 1668 "conf_parser.y" + { +} + break; + + case 273: +/* Line 1787 of yacc.c */ +#line 1673 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + yy_aconf->flags |= CONF_FLAGS_SPOOF_NOTICE; +} + break; + + case 274: +/* Line 1787 of yacc.c */ +#line 1677 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + yy_aconf->flags |= CONF_FLAGS_NOLIMIT; +} + break; + + case 275: +/* Line 1787 of yacc.c */ +#line 1681 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + yy_aconf->flags |= CONF_FLAGS_EXEMPTKLINE; +} + break; + + case 276: +/* Line 1787 of yacc.c */ +#line 1685 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + yy_aconf->flags |= CONF_FLAGS_NEED_IDENTD; +} + break; + + case 277: +/* Line 1787 of yacc.c */ +#line 1689 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + yy_aconf->flags |= CONF_FLAGS_CAN_FLOOD; +} + break; + + case 278: +/* Line 1787 of yacc.c */ +#line 1693 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + yy_aconf->flags |= CONF_FLAGS_NO_TILDE; +} + break; + + case 279: +/* Line 1787 of yacc.c */ +#line 1697 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + yy_aconf->flags |= CONF_FLAGS_EXEMPTGLINE; +} + break; + + case 280: +/* Line 1787 of yacc.c */ +#line 1701 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + yy_aconf->flags |= CONF_FLAGS_EXEMPTRESV; +} + break; + + case 281: +/* Line 1787 of yacc.c */ +#line 1705 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + yy_aconf->flags |= CONF_FLAGS_NEED_PASSWORD; +} + break; + + case 282: +/* Line 1787 of yacc.c */ +#line 1711 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + { + MyFree(yy_conf->name); + + if (strlen(yylval.string) <= HOSTLEN && valid_hostname(yylval.string)) + { + DupString(yy_conf->name, yylval.string); + yy_aconf->flags |= CONF_FLAGS_SPOOF_IP; + } + else + { + ilog(LOG_TYPE_IRCD, "Spoof either is too long or contains invalid characters. Ignoring it."); + yy_conf->name = NULL; + } + } +} + break; + + case 283: +/* Line 1787 of yacc.c */ +#line 1730 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + { + yy_aconf->flags |= CONF_FLAGS_REDIR; + MyFree(yy_conf->name); + DupString(yy_conf->name, yylval.string); + } +} + break; + + case 284: +/* Line 1787 of yacc.c */ +#line 1740 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + { + yy_aconf->flags |= CONF_FLAGS_REDIR; + yy_aconf->port = (yyvsp[(3) - (4)].number); + } +} + break; + + case 285: +/* Line 1787 of yacc.c */ +#line 1753 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + { + MyFree(resv_reason); + resv_reason = NULL; + } +} + break; + + case 286: +/* Line 1787 of yacc.c */ +#line 1760 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + { + MyFree(resv_reason); + resv_reason = NULL; + } +} + break; + + case 293: +/* Line 1787 of yacc.c */ +#line 1772 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + { + MyFree(resv_reason); + DupString(resv_reason, yylval.string); + } +} + break; + + case 294: +/* Line 1787 of yacc.c */ +#line 1781 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + { + if (IsChanPrefix(*yylval.string)) + { + char def_reason[] = "No reason"; + + create_channel_resv(yylval.string, resv_reason != NULL ? resv_reason : def_reason, 1); + } + } + /* ignore it for now.. but we really should make a warning if + * its an erroneous name --fl_ */ +} + break; + + case 295: +/* Line 1787 of yacc.c */ +#line 1796 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + { + char def_reason[] = "No reason"; + + create_nick_resv(yylval.string, resv_reason != NULL ? resv_reason : def_reason, 1); + } +} + break; + + case 301: +/* Line 1787 of yacc.c */ +#line 1814 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + { + if (valid_servname(yylval.string)) + { + yy_conf = make_conf_item(SERVICE_TYPE); + DupString(yy_conf->name, yylval.string); + } + } +} + break; + + case 302: +/* Line 1787 of yacc.c */ +#line 1829 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + { + yy_conf = make_conf_item(ULINE_TYPE); + yy_match_item = map_to_conf(yy_conf); + yy_match_item->action = SHARED_ALL; + } +} + break; + + case 303: +/* Line 1787 of yacc.c */ +#line 1837 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + { + yy_conf = NULL; + } +} + break; + + case 310: +/* Line 1787 of yacc.c */ +#line 1848 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + { + MyFree(yy_conf->name); + DupString(yy_conf->name, yylval.string); + } +} + break; + + case 311: +/* Line 1787 of yacc.c */ +#line 1857 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + { + struct split_nuh_item nuh; + + nuh.nuhmask = yylval.string; + nuh.nickptr = NULL; + nuh.userptr = userbuf; + nuh.hostptr = hostbuf; + + nuh.nicksize = 0; + nuh.usersize = sizeof(userbuf); + nuh.hostsize = sizeof(hostbuf); + + split_nuh(&nuh); + + DupString(yy_match_item->user, userbuf); + DupString(yy_match_item->host, hostbuf); + } +} + break; + + case 312: +/* Line 1787 of yacc.c */ +#line 1879 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + yy_match_item->action = 0; +} + break; + + case 316: +/* Line 1787 of yacc.c */ +#line 1886 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + yy_match_item->action |= SHARED_KLINE; +} + break; + + case 317: +/* Line 1787 of yacc.c */ +#line 1890 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + yy_match_item->action |= SHARED_UNKLINE; +} + break; + + case 318: +/* Line 1787 of yacc.c */ +#line 1894 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + yy_match_item->action |= SHARED_DLINE; +} + break; + + case 319: +/* Line 1787 of yacc.c */ +#line 1898 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + yy_match_item->action |= SHARED_UNDLINE; +} + break; + + case 320: +/* Line 1787 of yacc.c */ +#line 1902 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + yy_match_item->action |= SHARED_XLINE; +} + break; + + case 321: +/* Line 1787 of yacc.c */ +#line 1906 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + yy_match_item->action |= SHARED_UNXLINE; +} + break; + + case 322: +/* Line 1787 of yacc.c */ +#line 1910 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + yy_match_item->action |= SHARED_RESV; +} + break; + + case 323: +/* Line 1787 of yacc.c */ +#line 1914 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + yy_match_item->action |= SHARED_UNRESV; +} + break; + + case 324: +/* Line 1787 of yacc.c */ +#line 1918 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + yy_match_item->action |= SHARED_LOCOPS; +} + break; + + case 325: +/* Line 1787 of yacc.c */ +#line 1922 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + yy_match_item->action = SHARED_ALL; +} + break; + + case 326: +/* Line 1787 of yacc.c */ +#line 1931 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + { + yy_conf = make_conf_item(CLUSTER_TYPE); + yy_conf->flags = SHARED_ALL; + } +} + break; + + case 327: +/* Line 1787 of yacc.c */ +#line 1938 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + { + if (yy_conf->name == NULL) + DupString(yy_conf->name, "*"); + yy_conf = NULL; + } +} + break; + + case 333: +/* Line 1787 of yacc.c */ +#line 1951 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + DupString(yy_conf->name, yylval.string); +} + break; + + case 334: +/* Line 1787 of yacc.c */ +#line 1957 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + yy_conf->flags = 0; +} + break; + + case 338: +/* Line 1787 of yacc.c */ +#line 1964 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + yy_conf->flags |= SHARED_KLINE; +} + break; + + case 339: +/* Line 1787 of yacc.c */ +#line 1968 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + yy_conf->flags |= SHARED_UNKLINE; +} + break; + + case 340: +/* Line 1787 of yacc.c */ +#line 1972 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + yy_conf->flags |= SHARED_DLINE; +} + break; + + case 341: +/* Line 1787 of yacc.c */ +#line 1976 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + yy_conf->flags |= SHARED_UNDLINE; +} + break; + + case 342: +/* Line 1787 of yacc.c */ +#line 1980 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + yy_conf->flags |= SHARED_XLINE; +} + break; + + case 343: +/* Line 1787 of yacc.c */ +#line 1984 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + yy_conf->flags |= SHARED_UNXLINE; +} + break; + + case 344: +/* Line 1787 of yacc.c */ +#line 1988 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + yy_conf->flags |= SHARED_RESV; +} + break; + + case 345: +/* Line 1787 of yacc.c */ +#line 1992 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + yy_conf->flags |= SHARED_UNRESV; +} + break; + + case 346: +/* Line 1787 of yacc.c */ +#line 1996 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + yy_conf->flags |= SHARED_LOCOPS; +} + break; + + case 347: +/* Line 1787 of yacc.c */ +#line 2000 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + yy_conf->flags = SHARED_ALL; +} + break; + + case 348: +/* Line 1787 of yacc.c */ +#line 2009 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + { + yy_conf = make_conf_item(SERVER_TYPE); + yy_aconf = map_to_conf(yy_conf); + + /* defaults */ + yy_aconf->port = PORTNUM; + } + else + { + MyFree(class_name); + class_name = NULL; + } +} + break; + + case 349: +/* Line 1787 of yacc.c */ +#line 2024 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + { + if (yy_aconf->host && yy_aconf->passwd && yy_aconf->spasswd) + { + if (conf_add_server(yy_conf, class_name) == -1) + delete_conf_item(yy_conf); + } + else + { + if (yy_conf->name != NULL) + { + if (yy_aconf->host == NULL) + yyerror("Ignoring connect block -- missing host"); + else if (!yy_aconf->passwd || !yy_aconf->spasswd) + yyerror("Ignoring connect block -- missing password"); + } + + /* XXX + * This fixes a try_connections() core (caused by invalid class_ptr + * pointers) reported by metalrock. That's an ugly fix, but there + * is currently no better way. The entire config subsystem needs an + * rewrite ASAP. make_conf_item() shouldn't really add things onto + * a doubly linked list immediately without any sanity checks! -Michael + */ + delete_conf_item(yy_conf); + } + + MyFree(class_name); + class_name = NULL; + yy_conf = NULL; + yy_aconf = NULL; + } +} + break; + + case 366: +/* Line 1787 of yacc.c */ +#line 2068 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + { + MyFree(yy_conf->name); + DupString(yy_conf->name, yylval.string); + } +} + break; + + case 367: +/* Line 1787 of yacc.c */ +#line 2077 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + { + MyFree(yy_aconf->host); + DupString(yy_aconf->host, yylval.string); + } +} + break; + + case 368: +/* Line 1787 of yacc.c */ +#line 2086 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + { + struct addrinfo hints, *res; + + memset(&hints, 0, sizeof(hints)); + + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST; + + if (getaddrinfo(yylval.string, NULL, &hints, &res)) + ilog(LOG_TYPE_IRCD, "Invalid netmask for server vhost(%s)", yylval.string); + else + { + assert(res != NULL); + + memcpy(&yy_aconf->bind, res->ai_addr, res->ai_addrlen); + yy_aconf->bind.ss.ss_family = res->ai_family; + yy_aconf->bind.ss_len = res->ai_addrlen; + freeaddrinfo(res); + } + } +} + break; + + case 369: +/* Line 1787 of yacc.c */ +#line 2112 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + { + if ((yyvsp[(3) - (4)].string)[0] == ':') + yyerror("Server passwords cannot begin with a colon"); + else if (strchr((yyvsp[(3) - (4)].string), ' ') != NULL) + yyerror("Server passwords cannot contain spaces"); + else { + if (yy_aconf->spasswd != NULL) + memset(yy_aconf->spasswd, 0, strlen(yy_aconf->spasswd)); + + MyFree(yy_aconf->spasswd); + DupString(yy_aconf->spasswd, yylval.string); + } + } +} + break; + + case 370: +/* Line 1787 of yacc.c */ +#line 2130 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + { + if ((yyvsp[(3) - (4)].string)[0] == ':') + yyerror("Server passwords cannot begin with a colon"); + else if (strchr((yyvsp[(3) - (4)].string), ' ') != NULL) + yyerror("Server passwords cannot contain spaces"); + else { + if (yy_aconf->passwd != NULL) + memset(yy_aconf->passwd, 0, strlen(yy_aconf->passwd)); + + MyFree(yy_aconf->passwd); + DupString(yy_aconf->passwd, yylval.string); + } + } +} + break; + + case 371: +/* Line 1787 of yacc.c */ +#line 2148 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + yy_aconf->port = (yyvsp[(3) - (4)].number); +} + break; + + case 372: +/* Line 1787 of yacc.c */ +#line 2154 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + yy_aconf->aftype = AF_INET; +} + break; + + case 373: +/* Line 1787 of yacc.c */ +#line 2158 "conf_parser.y" + { +#ifdef IPV6 + if (conf_parser_ctx.pass == 2) + yy_aconf->aftype = AF_INET6; +#endif +} + break; + + case 374: +/* Line 1787 of yacc.c */ +#line 2166 "conf_parser.y" + { +} + break; + + case 378: +/* Line 1787 of yacc.c */ +#line 2171 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + SetConfAllowAutoConn(yy_aconf); +} + break; + + case 379: +/* Line 1787 of yacc.c */ +#line 2175 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + SetConfSSL(yy_aconf); +} + break; + + case 380: +/* Line 1787 of yacc.c */ +#line 2181 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + { + if (yylval.number) + yy_aconf->flags |= CONF_FLAGS_ENCRYPTED; + else + yy_aconf->flags &= ~CONF_FLAGS_ENCRYPTED; + } +} + break; + + case 381: +/* Line 1787 of yacc.c */ +#line 2192 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + { + char *mask; + + DupString(mask, yylval.string); + dlinkAdd(mask, make_dlink_node(), &yy_aconf->hub_list); + } +} + break; + + case 382: +/* Line 1787 of yacc.c */ +#line 2203 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + { + char *mask; + + DupString(mask, yylval.string); + dlinkAdd(mask, make_dlink_node(), &yy_aconf->leaf_list); + } +} + break; + + case 383: +/* Line 1787 of yacc.c */ +#line 2214 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + { + MyFree(class_name); + DupString(class_name, yylval.string); + } +} + break; + + case 384: +/* Line 1787 of yacc.c */ +#line 2223 "conf_parser.y" + { +#ifdef HAVE_LIBCRYPTO + if (conf_parser_ctx.pass == 2) + { + MyFree(yy_aconf->cipher_list); + DupString(yy_aconf->cipher_list, yylval.string); + } +#else + if (conf_parser_ctx.pass == 2) + yyerror("Ignoring connect::ciphers -- no OpenSSL support"); +#endif +} + break; + + case 385: +/* Line 1787 of yacc.c */ +#line 2241 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + { + userbuf[0] = hostbuf[0] = reasonbuf[0] = '\0'; + regex_ban = 0; + } +} + break; + + case 386: +/* Line 1787 of yacc.c */ +#line 2248 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + { + if (userbuf[0] && hostbuf[0]) + { + if (regex_ban) + { +#ifdef HAVE_LIBPCRE + void *exp_user = NULL; + void *exp_host = NULL; + const char *errptr = NULL; + + if (!(exp_user = ircd_pcre_compile(userbuf, &errptr)) || + !(exp_host = ircd_pcre_compile(hostbuf, &errptr))) + { + ilog(LOG_TYPE_IRCD, "Failed to add regular expression based K-Line: %s", + errptr); + break; + } + + yy_aconf = map_to_conf(make_conf_item(RKLINE_TYPE)); + yy_aconf->regexuser = exp_user; + yy_aconf->regexhost = exp_host; + + DupString(yy_aconf->user, userbuf); + DupString(yy_aconf->host, hostbuf); + + if (reasonbuf[0]) + DupString(yy_aconf->reason, reasonbuf); + else + DupString(yy_aconf->reason, "No reason"); +#else + ilog(LOG_TYPE_IRCD, "Failed to add regular expression based K-Line: no PCRE support"); + break; +#endif + } + else + { + find_and_delete_temporary(userbuf, hostbuf, CONF_KLINE); + + yy_aconf = map_to_conf(make_conf_item(KLINE_TYPE)); + + DupString(yy_aconf->user, userbuf); + DupString(yy_aconf->host, hostbuf); + + if (reasonbuf[0]) + DupString(yy_aconf->reason, reasonbuf); + else + DupString(yy_aconf->reason, "No reason"); + add_conf_by_address(CONF_KLINE, yy_aconf); + } + } + + yy_aconf = NULL; + } +} + break; + + case 387: +/* Line 1787 of yacc.c */ +#line 2306 "conf_parser.y" + { +} + break; + + case 391: +/* Line 1787 of yacc.c */ +#line 2311 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + regex_ban = 1; +} + break; + + case 398: +/* Line 1787 of yacc.c */ +#line 2320 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + { + struct split_nuh_item nuh; + + nuh.nuhmask = yylval.string; + nuh.nickptr = NULL; + nuh.userptr = userbuf; + nuh.hostptr = hostbuf; + + nuh.nicksize = 0; + nuh.usersize = sizeof(userbuf); + nuh.hostsize = sizeof(hostbuf); + + split_nuh(&nuh); + } +} + break; + + case 399: +/* Line 1787 of yacc.c */ +#line 2339 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + strlcpy(reasonbuf, yylval.string, sizeof(reasonbuf)); +} + break; + + case 400: +/* Line 1787 of yacc.c */ +#line 2348 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + hostbuf[0] = reasonbuf[0] = '\0'; +} + break; + + case 401: +/* Line 1787 of yacc.c */ +#line 2352 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + { + if (hostbuf[0] && parse_netmask(hostbuf, NULL, NULL) != HM_HOST) + { + find_and_delete_temporary(NULL, hostbuf, CONF_DLINE); + + yy_aconf = map_to_conf(make_conf_item(DLINE_TYPE)); + DupString(yy_aconf->host, hostbuf); + + if (reasonbuf[0]) + DupString(yy_aconf->reason, reasonbuf); + else + DupString(yy_aconf->reason, "No reason"); + add_conf_by_address(CONF_DLINE, yy_aconf); + yy_aconf = NULL; + } + } +} + break; + + case 407: +/* Line 1787 of yacc.c */ +#line 2376 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + strlcpy(hostbuf, yylval.string, sizeof(hostbuf)); +} + break; + + case 408: +/* Line 1787 of yacc.c */ +#line 2382 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + strlcpy(reasonbuf, yylval.string, sizeof(reasonbuf)); +} + break; + + case 414: +/* Line 1787 of yacc.c */ +#line 2396 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + { + if (yylval.string[0] && parse_netmask(yylval.string, NULL, NULL) != HM_HOST) + { + yy_aconf = map_to_conf(make_conf_item(EXEMPTDLINE_TYPE)); + DupString(yy_aconf->host, yylval.string); + + add_conf_by_address(CONF_EXEMPTDLINE, yy_aconf); + yy_aconf = NULL; + } + } +} + break; + + case 415: +/* Line 1787 of yacc.c */ +#line 2414 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + { + regex_ban = 0; + reasonbuf[0] = gecos_name[0] = '\0'; + } +} + break; + + case 416: +/* Line 1787 of yacc.c */ +#line 2421 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + { + if (gecos_name[0]) + { + if (regex_ban) + { +#ifdef HAVE_LIBPCRE + void *exp_p = NULL; + const char *errptr = NULL; + + if (!(exp_p = ircd_pcre_compile(gecos_name, &errptr))) + { + ilog(LOG_TYPE_IRCD, "Failed to add regular expression based X-Line: %s", + errptr); + break; + } + + yy_conf = make_conf_item(RXLINE_TYPE); + yy_conf->regexpname = exp_p; +#else + ilog(LOG_TYPE_IRCD, "Failed to add regular expression based X-Line: no PCRE support"); + break; +#endif + } + else + yy_conf = make_conf_item(XLINE_TYPE); + + yy_match_item = map_to_conf(yy_conf); + DupString(yy_conf->name, gecos_name); + + if (reasonbuf[0]) + DupString(yy_match_item->reason, reasonbuf); + else + DupString(yy_match_item->reason, "No reason"); + } + } +} + break; + + case 417: +/* Line 1787 of yacc.c */ +#line 2461 "conf_parser.y" + { +} + break; + + case 421: +/* Line 1787 of yacc.c */ +#line 2466 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + regex_ban = 1; +} + break; + + case 428: +/* Line 1787 of yacc.c */ +#line 2475 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + strlcpy(gecos_name, yylval.string, sizeof(gecos_name)); +} + break; + + case 429: +/* Line 1787 of yacc.c */ +#line 2481 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + strlcpy(reasonbuf, yylval.string, sizeof(reasonbuf)); +} + break; + + case 483: +/* Line 1787 of yacc.c */ +#line 2526 "conf_parser.y" + { + ConfigFileEntry.max_watch = (yyvsp[(3) - (4)].number); +} + break; + + case 484: +/* Line 1787 of yacc.c */ +#line 2531 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + ConfigFileEntry.glines = yylval.number; +} + break; + + case 485: +/* Line 1787 of yacc.c */ +#line 2537 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + ConfigFileEntry.gline_time = (yyvsp[(3) - (4)].number); +} + break; + + case 486: +/* Line 1787 of yacc.c */ +#line 2543 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + ConfigFileEntry.gline_request_time = (yyvsp[(3) - (4)].number); +} + break; + + case 487: +/* Line 1787 of yacc.c */ +#line 2549 "conf_parser.y" + { + ConfigFileEntry.gline_min_cidr = (yyvsp[(3) - (4)].number); +} + break; + + case 488: +/* Line 1787 of yacc.c */ +#line 2554 "conf_parser.y" + { + ConfigFileEntry.gline_min_cidr6 = (yyvsp[(3) - (4)].number); +} + break; + + case 489: +/* Line 1787 of yacc.c */ +#line 2559 "conf_parser.y" + { + ConfigFileEntry.tkline_expire_notices = yylval.number; +} + break; + + case 490: +/* Line 1787 of yacc.c */ +#line 2564 "conf_parser.y" + { + ConfigFileEntry.kill_chase_time_limit = (yyvsp[(3) - (4)].number); +} + break; + + case 491: +/* Line 1787 of yacc.c */ +#line 2569 "conf_parser.y" + { + ConfigFileEntry.hide_spoof_ips = yylval.number; +} + break; + + case 492: +/* Line 1787 of yacc.c */ +#line 2574 "conf_parser.y" + { + ConfigFileEntry.ignore_bogus_ts = yylval.number; +} + break; + + case 493: +/* Line 1787 of yacc.c */ +#line 2579 "conf_parser.y" + { + ConfigFileEntry.disable_remote = yylval.number; +} + break; + + case 494: +/* Line 1787 of yacc.c */ +#line 2584 "conf_parser.y" + { + ConfigFileEntry.failed_oper_notice = yylval.number; +} + break; + + case 495: +/* Line 1787 of yacc.c */ +#line 2589 "conf_parser.y" + { + ConfigFileEntry.anti_nick_flood = yylval.number; +} + break; + + case 496: +/* Line 1787 of yacc.c */ +#line 2594 "conf_parser.y" + { + ConfigFileEntry.max_nick_time = (yyvsp[(3) - (4)].number); +} + break; + + case 497: +/* Line 1787 of yacc.c */ +#line 2599 "conf_parser.y" + { + ConfigFileEntry.max_nick_changes = (yyvsp[(3) - (4)].number); +} + break; + + case 498: +/* Line 1787 of yacc.c */ +#line 2604 "conf_parser.y" + { + ConfigFileEntry.max_accept = (yyvsp[(3) - (4)].number); +} + break; + + case 499: +/* Line 1787 of yacc.c */ +#line 2609 "conf_parser.y" + { + ConfigFileEntry.anti_spam_exit_message_time = (yyvsp[(3) - (4)].number); +} + break; + + case 500: +/* Line 1787 of yacc.c */ +#line 2614 "conf_parser.y" + { + ConfigFileEntry.ts_warn_delta = (yyvsp[(3) - (4)].number); +} + break; + + case 501: +/* Line 1787 of yacc.c */ +#line 2619 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + ConfigFileEntry.ts_max_delta = (yyvsp[(3) - (4)].number); +} + break; + + case 502: +/* Line 1787 of yacc.c */ +#line 2625 "conf_parser.y" + { + if (((yyvsp[(3) - (4)].number) > 0) && conf_parser_ctx.pass == 1) + { + ilog(LOG_TYPE_IRCD, "You haven't read your config file properly."); + ilog(LOG_TYPE_IRCD, "There is a line in the example conf that will kill your server if not removed."); + ilog(LOG_TYPE_IRCD, "Consider actually reading/editing the conf file, and removing this line."); + exit(0); + } +} + break; + + case 503: +/* Line 1787 of yacc.c */ +#line 2636 "conf_parser.y" + { + ConfigFileEntry.invisible_on_connect = yylval.number; +} + break; + + case 504: +/* Line 1787 of yacc.c */ +#line 2641 "conf_parser.y" + { + ConfigFileEntry.warn_no_nline = yylval.number; +} + break; + + case 505: +/* Line 1787 of yacc.c */ +#line 2646 "conf_parser.y" + { + ConfigFileEntry.stats_e_disabled = yylval.number; +} + break; + + case 506: +/* Line 1787 of yacc.c */ +#line 2651 "conf_parser.y" + { + ConfigFileEntry.stats_o_oper_only = yylval.number; +} + break; + + case 507: +/* Line 1787 of yacc.c */ +#line 2656 "conf_parser.y" + { + ConfigFileEntry.stats_P_oper_only = yylval.number; +} + break; + + case 508: +/* Line 1787 of yacc.c */ +#line 2661 "conf_parser.y" + { + ConfigFileEntry.stats_k_oper_only = 2 * yylval.number; +} + break; + + case 509: +/* Line 1787 of yacc.c */ +#line 2664 "conf_parser.y" + { + ConfigFileEntry.stats_k_oper_only = 1; +} + break; + + case 510: +/* Line 1787 of yacc.c */ +#line 2669 "conf_parser.y" + { + ConfigFileEntry.stats_i_oper_only = 2 * yylval.number; +} + break; + + case 511: +/* Line 1787 of yacc.c */ +#line 2672 "conf_parser.y" + { + ConfigFileEntry.stats_i_oper_only = 1; +} + break; + + case 512: +/* Line 1787 of yacc.c */ +#line 2677 "conf_parser.y" + { + ConfigFileEntry.pace_wait = (yyvsp[(3) - (4)].number); +} + break; + + case 513: +/* Line 1787 of yacc.c */ +#line 2682 "conf_parser.y" + { + ConfigFileEntry.caller_id_wait = (yyvsp[(3) - (4)].number); +} + break; + + case 514: +/* Line 1787 of yacc.c */ +#line 2687 "conf_parser.y" + { + ConfigFileEntry.opers_bypass_callerid = yylval.number; +} + break; + + case 515: +/* Line 1787 of yacc.c */ +#line 2692 "conf_parser.y" + { + ConfigFileEntry.pace_wait_simple = (yyvsp[(3) - (4)].number); +} + break; + + case 516: +/* Line 1787 of yacc.c */ +#line 2697 "conf_parser.y" + { + ConfigFileEntry.short_motd = yylval.number; +} + break; + + case 517: +/* Line 1787 of yacc.c */ +#line 2702 "conf_parser.y" + { + ConfigFileEntry.no_oper_flood = yylval.number; +} + break; + + case 518: +/* Line 1787 of yacc.c */ +#line 2707 "conf_parser.y" + { + ConfigFileEntry.true_no_oper_flood = yylval.number; +} + break; + + case 519: +/* Line 1787 of yacc.c */ +#line 2712 "conf_parser.y" + { + ConfigFileEntry.oper_pass_resv = yylval.number; +} + break; + + case 520: +/* Line 1787 of yacc.c */ +#line 2717 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + { + if (strlen(yylval.string) > LOCALE_LENGTH-2) + yylval.string[LOCALE_LENGTH-1] = '\0'; + + set_locale(yylval.string); + } +} + break; + + case 521: +/* Line 1787 of yacc.c */ +#line 2728 "conf_parser.y" + { + ConfigFileEntry.dots_in_ident = (yyvsp[(3) - (4)].number); +} + break; + + case 522: +/* Line 1787 of yacc.c */ +#line 2733 "conf_parser.y" + { + ConfigFileEntry.max_targets = (yyvsp[(3) - (4)].number); +} + break; + + case 523: +/* Line 1787 of yacc.c */ +#line 2738 "conf_parser.y" + { + ConfigFileEntry.use_egd = yylval.number; +} + break; + + case 524: +/* Line 1787 of yacc.c */ +#line 2743 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + { + MyFree(ConfigFileEntry.egdpool_path); + DupString(ConfigFileEntry.egdpool_path, yylval.string); + } +} + break; + + case 525: +/* Line 1787 of yacc.c */ +#line 2752 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2 && valid_servname(yylval.string)) + { + MyFree(ConfigFileEntry.service_name); + DupString(ConfigFileEntry.service_name, yylval.string); + } +} + break; + + case 526: +/* Line 1787 of yacc.c */ +#line 2761 "conf_parser.y" + { + ConfigFileEntry.ping_cookie = yylval.number; +} + break; + + case 527: +/* Line 1787 of yacc.c */ +#line 2766 "conf_parser.y" + { + ConfigFileEntry.disable_auth = yylval.number; +} + break; + + case 528: +/* Line 1787 of yacc.c */ +#line 2771 "conf_parser.y" + { + ConfigFileEntry.throttle_time = yylval.number; +} + break; + + case 529: +/* Line 1787 of yacc.c */ +#line 2776 "conf_parser.y" + { + ConfigFileEntry.oper_umodes = 0; +} + break; + + case 533: +/* Line 1787 of yacc.c */ +#line 2782 "conf_parser.y" + { + ConfigFileEntry.oper_umodes |= UMODE_BOTS; +} + break; + + case 534: +/* Line 1787 of yacc.c */ +#line 2785 "conf_parser.y" + { + ConfigFileEntry.oper_umodes |= UMODE_CCONN; +} + break; + + case 535: +/* Line 1787 of yacc.c */ +#line 2788 "conf_parser.y" + { + ConfigFileEntry.oper_umodes |= UMODE_CCONN_FULL; +} + break; + + case 536: +/* Line 1787 of yacc.c */ +#line 2791 "conf_parser.y" + { + ConfigFileEntry.oper_umodes |= UMODE_DEAF; +} + break; + + case 537: +/* Line 1787 of yacc.c */ +#line 2794 "conf_parser.y" + { + ConfigFileEntry.oper_umodes |= UMODE_DEBUG; +} + break; + + case 538: +/* Line 1787 of yacc.c */ +#line 2797 "conf_parser.y" + { + ConfigFileEntry.oper_umodes |= UMODE_FULL; +} + break; + + case 539: +/* Line 1787 of yacc.c */ +#line 2800 "conf_parser.y" + { + ConfigFileEntry.oper_umodes |= UMODE_HIDDEN; +} + break; + + case 540: +/* Line 1787 of yacc.c */ +#line 2803 "conf_parser.y" + { + ConfigFileEntry.oper_umodes |= UMODE_SKILL; +} + break; + + case 541: +/* Line 1787 of yacc.c */ +#line 2806 "conf_parser.y" + { + ConfigFileEntry.oper_umodes |= UMODE_NCHANGE; +} + break; + + case 542: +/* Line 1787 of yacc.c */ +#line 2809 "conf_parser.y" + { + ConfigFileEntry.oper_umodes |= UMODE_REJ; +} + break; + + case 543: +/* Line 1787 of yacc.c */ +#line 2812 "conf_parser.y" + { + ConfigFileEntry.oper_umodes |= UMODE_UNAUTH; +} + break; + + case 544: +/* Line 1787 of yacc.c */ +#line 2815 "conf_parser.y" + { + ConfigFileEntry.oper_umodes |= UMODE_SPY; +} + break; + + case 545: +/* Line 1787 of yacc.c */ +#line 2818 "conf_parser.y" + { + ConfigFileEntry.oper_umodes |= UMODE_EXTERNAL; +} + break; + + case 546: +/* Line 1787 of yacc.c */ +#line 2821 "conf_parser.y" + { + ConfigFileEntry.oper_umodes |= UMODE_OPERWALL; +} + break; + + case 547: +/* Line 1787 of yacc.c */ +#line 2824 "conf_parser.y" + { + ConfigFileEntry.oper_umodes |= UMODE_SERVNOTICE; +} + break; + + case 548: +/* Line 1787 of yacc.c */ +#line 2827 "conf_parser.y" + { + ConfigFileEntry.oper_umodes |= UMODE_INVISIBLE; +} + break; + + case 549: +/* Line 1787 of yacc.c */ +#line 2830 "conf_parser.y" + { + ConfigFileEntry.oper_umodes |= UMODE_WALLOP; +} + break; + + case 550: +/* Line 1787 of yacc.c */ +#line 2833 "conf_parser.y" + { + ConfigFileEntry.oper_umodes |= UMODE_SOFTCALLERID; +} + break; + + case 551: +/* Line 1787 of yacc.c */ +#line 2836 "conf_parser.y" + { + ConfigFileEntry.oper_umodes |= UMODE_CALLERID; +} + break; + + case 552: +/* Line 1787 of yacc.c */ +#line 2839 "conf_parser.y" + { + ConfigFileEntry.oper_umodes |= UMODE_LOCOPS; +} + break; + + case 553: +/* Line 1787 of yacc.c */ +#line 2844 "conf_parser.y" + { + ConfigFileEntry.oper_only_umodes = 0; +} + break; + + case 557: +/* Line 1787 of yacc.c */ +#line 2850 "conf_parser.y" + { + ConfigFileEntry.oper_only_umodes |= UMODE_BOTS; +} + break; + + case 558: +/* Line 1787 of yacc.c */ +#line 2853 "conf_parser.y" + { + ConfigFileEntry.oper_only_umodes |= UMODE_CCONN; +} + break; + + case 559: +/* Line 1787 of yacc.c */ +#line 2856 "conf_parser.y" + { + ConfigFileEntry.oper_only_umodes |= UMODE_CCONN_FULL; +} + break; + + case 560: +/* Line 1787 of yacc.c */ +#line 2859 "conf_parser.y" + { + ConfigFileEntry.oper_only_umodes |= UMODE_DEAF; +} + break; + + case 561: +/* Line 1787 of yacc.c */ +#line 2862 "conf_parser.y" + { + ConfigFileEntry.oper_only_umodes |= UMODE_DEBUG; +} + break; + + case 562: +/* Line 1787 of yacc.c */ +#line 2865 "conf_parser.y" + { + ConfigFileEntry.oper_only_umodes |= UMODE_FULL; +} + break; + + case 563: +/* Line 1787 of yacc.c */ +#line 2868 "conf_parser.y" + { + ConfigFileEntry.oper_only_umodes |= UMODE_SKILL; +} + break; + + case 564: +/* Line 1787 of yacc.c */ +#line 2871 "conf_parser.y" + { + ConfigFileEntry.oper_only_umodes |= UMODE_HIDDEN; +} + break; + + case 565: +/* Line 1787 of yacc.c */ +#line 2874 "conf_parser.y" + { + ConfigFileEntry.oper_only_umodes |= UMODE_NCHANGE; +} + break; + + case 566: +/* Line 1787 of yacc.c */ +#line 2877 "conf_parser.y" + { + ConfigFileEntry.oper_only_umodes |= UMODE_REJ; +} + break; + + case 567: +/* Line 1787 of yacc.c */ +#line 2880 "conf_parser.y" + { + ConfigFileEntry.oper_only_umodes |= UMODE_UNAUTH; +} + break; + + case 568: +/* Line 1787 of yacc.c */ +#line 2883 "conf_parser.y" + { + ConfigFileEntry.oper_only_umodes |= UMODE_SPY; +} + break; + + case 569: +/* Line 1787 of yacc.c */ +#line 2886 "conf_parser.y" + { + ConfigFileEntry.oper_only_umodes |= UMODE_EXTERNAL; +} + break; + + case 570: +/* Line 1787 of yacc.c */ +#line 2889 "conf_parser.y" + { + ConfigFileEntry.oper_only_umodes |= UMODE_OPERWALL; +} + break; + + case 571: +/* Line 1787 of yacc.c */ +#line 2892 "conf_parser.y" + { + ConfigFileEntry.oper_only_umodes |= UMODE_SERVNOTICE; +} + break; + + case 572: +/* Line 1787 of yacc.c */ +#line 2895 "conf_parser.y" + { + ConfigFileEntry.oper_only_umodes |= UMODE_INVISIBLE; +} + break; + + case 573: +/* Line 1787 of yacc.c */ +#line 2898 "conf_parser.y" + { + ConfigFileEntry.oper_only_umodes |= UMODE_WALLOP; +} + break; + + case 574: +/* Line 1787 of yacc.c */ +#line 2901 "conf_parser.y" + { + ConfigFileEntry.oper_only_umodes |= UMODE_SOFTCALLERID; +} + break; + + case 575: +/* Line 1787 of yacc.c */ +#line 2904 "conf_parser.y" + { + ConfigFileEntry.oper_only_umodes |= UMODE_CALLERID; +} + break; + + case 576: +/* Line 1787 of yacc.c */ +#line 2907 "conf_parser.y" + { + ConfigFileEntry.oper_only_umodes |= UMODE_LOCOPS; +} + break; + + case 577: +/* Line 1787 of yacc.c */ +#line 2912 "conf_parser.y" + { + ConfigFileEntry.min_nonwildcard = (yyvsp[(3) - (4)].number); +} + break; + + case 578: +/* Line 1787 of yacc.c */ +#line 2917 "conf_parser.y" + { + ConfigFileEntry.min_nonwildcard_simple = (yyvsp[(3) - (4)].number); +} + break; + + case 579: +/* Line 1787 of yacc.c */ +#line 2922 "conf_parser.y" + { + ConfigFileEntry.default_floodcount = (yyvsp[(3) - (4)].number); +} + break; + + case 598: +/* Line 1787 of yacc.c */ +#line 2945 "conf_parser.y" + { + ConfigChannel.disable_fake_channels = yylval.number; +} + break; + + case 599: +/* Line 1787 of yacc.c */ +#line 2950 "conf_parser.y" + { + ConfigChannel.restrict_channels = yylval.number; +} + break; + + case 600: +/* Line 1787 of yacc.c */ +#line 2955 "conf_parser.y" + { + ConfigChannel.knock_delay = (yyvsp[(3) - (4)].number); +} + break; + + case 601: +/* Line 1787 of yacc.c */ +#line 2960 "conf_parser.y" + { + ConfigChannel.knock_delay_channel = (yyvsp[(3) - (4)].number); +} + break; + + case 602: +/* Line 1787 of yacc.c */ +#line 2965 "conf_parser.y" + { + ConfigChannel.max_chans_per_user = (yyvsp[(3) - (4)].number); +} + break; + + case 603: +/* Line 1787 of yacc.c */ +#line 2970 "conf_parser.y" + { + ConfigChannel.max_chans_per_oper = (yyvsp[(3) - (4)].number); +} + break; + + case 604: +/* Line 1787 of yacc.c */ +#line 2975 "conf_parser.y" + { + ConfigChannel.quiet_on_ban = yylval.number; +} + break; + + case 605: +/* Line 1787 of yacc.c */ +#line 2980 "conf_parser.y" + { + ConfigChannel.max_bans = (yyvsp[(3) - (4)].number); +} + break; + + case 606: +/* Line 1787 of yacc.c */ +#line 2985 "conf_parser.y" + { + ConfigChannel.default_split_user_count = (yyvsp[(3) - (4)].number); +} + break; + + case 607: +/* Line 1787 of yacc.c */ +#line 2990 "conf_parser.y" + { + ConfigChannel.default_split_server_count = (yyvsp[(3) - (4)].number); +} + break; + + case 608: +/* Line 1787 of yacc.c */ +#line 2995 "conf_parser.y" + { + ConfigChannel.no_create_on_split = yylval.number; +} + break; + + case 609: +/* Line 1787 of yacc.c */ +#line 3000 "conf_parser.y" + { + ConfigChannel.no_join_on_split = yylval.number; +} + break; + + case 610: +/* Line 1787 of yacc.c */ +#line 3005 "conf_parser.y" + { + GlobalSetOptions.joinfloodcount = yylval.number; +} + break; + + case 611: +/* Line 1787 of yacc.c */ +#line 3010 "conf_parser.y" + { + GlobalSetOptions.joinfloodtime = yylval.number; +} + break; + + case 622: +/* Line 1787 of yacc.c */ +#line 3028 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + ConfigServerHide.flatten_links = yylval.number; +} + break; + + case 623: +/* Line 1787 of yacc.c */ +#line 3034 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + ConfigServerHide.hide_servers = yylval.number; +} + break; + + case 624: +/* Line 1787 of yacc.c */ +#line 3040 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + { + MyFree(ConfigServerHide.hidden_name); + DupString(ConfigServerHide.hidden_name, yylval.string); + } +} + break; + + case 625: +/* Line 1787 of yacc.c */ +#line 3049 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + { + if (((yyvsp[(3) - (4)].number) > 0) && ConfigServerHide.links_disabled == 1) + { + eventAddIsh("write_links_file", write_links_file, NULL, (yyvsp[(3) - (4)].number)); + ConfigServerHide.links_disabled = 0; + } + + ConfigServerHide.links_delay = (yyvsp[(3) - (4)].number); + } +} + break; + + case 626: +/* Line 1787 of yacc.c */ +#line 3063 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + ConfigServerHide.hidden = yylval.number; +} + break; + + case 627: +/* Line 1787 of yacc.c */ +#line 3069 "conf_parser.y" + { + if (conf_parser_ctx.pass == 2) + ConfigServerHide.hide_server_ips = yylval.number; +} + break; + + +/* Line 1787 of yacc.c */ +#line 6844 "conf_parser.c" + default: break; + } + /* User semantic actions sometimes alter yychar, and that requires + that yytoken be updated with the new translation. We take the + approach of translating immediately before every use of yytoken. + One alternative is translating here after every semantic action, + but that translation would be missed if the semantic action invokes + YYABORT, YYACCEPT, or YYERROR immediately after altering yychar or + if it invokes YYBACKUP. In the case of YYABORT or YYACCEPT, an + incorrect destructor might then be invoked immediately. In the + case of YYERROR or YYBACKUP, subsequent parser actions might lead + to an incorrect destructor call or verbose syntax error message + before the lookahead is translated. */ + YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc); + + YYPOPSTACK (yylen); + yylen = 0; + YY_STACK_PRINT (yyss, yyssp); + + *++yyvsp = yyval; + + /* Now `shift' the result of the reduction. Determine what state + that goes to, based on the state we popped back to and the rule + number reduced by. */ + + yyn = yyr1[yyn]; + + yystate = yypgoto[yyn - YYNTOKENS] + *yyssp; + if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp) + yystate = yytable[yystate]; + else + yystate = yydefgoto[yyn - YYNTOKENS]; + + goto yynewstate; + + +/*------------------------------------. +| yyerrlab -- here on detecting error | +`------------------------------------*/ +yyerrlab: + /* Make sure we have latest lookahead translation. See comments at + user semantic actions for why this is necessary. */ + yytoken = yychar == YYEMPTY ? YYEMPTY : YYTRANSLATE (yychar); + + /* If not already recovering from an error, report this error. */ + if (!yyerrstatus) + { + ++yynerrs; +#if ! YYERROR_VERBOSE + yyerror (YY_("syntax error")); +#else +# define YYSYNTAX_ERROR yysyntax_error (&yymsg_alloc, &yymsg, \ + yyssp, yytoken) + { + char const *yymsgp = YY_("syntax error"); + int yysyntax_error_status; + yysyntax_error_status = YYSYNTAX_ERROR; + if (yysyntax_error_status == 0) + yymsgp = yymsg; + else if (yysyntax_error_status == 1) + { + if (yymsg != yymsgbuf) + YYSTACK_FREE (yymsg); + yymsg = (char *) YYSTACK_ALLOC (yymsg_alloc); + if (!yymsg) + { + yymsg = yymsgbuf; + yymsg_alloc = sizeof yymsgbuf; + yysyntax_error_status = 2; + } + else + { + yysyntax_error_status = YYSYNTAX_ERROR; + yymsgp = yymsg; + } + } + yyerror (yymsgp); + if (yysyntax_error_status == 2) + goto yyexhaustedlab; + } +# undef YYSYNTAX_ERROR +#endif + } + + + + if (yyerrstatus == 3) + { + /* If just tried and failed to reuse lookahead token after an + error, discard it. */ + + if (yychar <= YYEOF) + { + /* Return failure if at end of input. */ + if (yychar == YYEOF) + YYABORT; + } + else + { + yydestruct ("Error: discarding", + yytoken, &yylval); + yychar = YYEMPTY; + } + } + + /* Else will try to reuse lookahead token after shifting the error + token. */ + goto yyerrlab1; + + +/*---------------------------------------------------. +| yyerrorlab -- error raised explicitly by YYERROR. | +`---------------------------------------------------*/ +yyerrorlab: + + /* Pacify compilers like GCC when the user code never invokes + YYERROR and the label yyerrorlab therefore never appears in user + code. */ + if (/*CONSTCOND*/ 0) + goto yyerrorlab; + + /* Do not reclaim the symbols of the rule which action triggered + this YYERROR. */ + YYPOPSTACK (yylen); + yylen = 0; + YY_STACK_PRINT (yyss, yyssp); + yystate = *yyssp; + goto yyerrlab1; + + +/*-------------------------------------------------------------. +| yyerrlab1 -- common code for both syntax error and YYERROR. | +`-------------------------------------------------------------*/ +yyerrlab1: + yyerrstatus = 3; /* Each real token shifted decrements this. */ + + for (;;) + { + yyn = yypact[yystate]; + if (!yypact_value_is_default (yyn)) + { + yyn += YYTERROR; + if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR) + { + yyn = yytable[yyn]; + if (0 < yyn) + break; + } + } + + /* Pop the current state because it cannot handle the error token. */ + if (yyssp == yyss) + YYABORT; + + + yydestruct ("Error: popping", + yystos[yystate], yyvsp); + YYPOPSTACK (1); + yystate = *yyssp; + YY_STACK_PRINT (yyss, yyssp); + } + + *++yyvsp = yylval; + + + /* Shift the error token. */ + YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp); + + yystate = yyn; + goto yynewstate; + + +/*-------------------------------------. +| yyacceptlab -- YYACCEPT comes here. | +`-------------------------------------*/ +yyacceptlab: + yyresult = 0; + goto yyreturn; + +/*-----------------------------------. +| yyabortlab -- YYABORT comes here. | +`-----------------------------------*/ +yyabortlab: + yyresult = 1; + goto yyreturn; + +#if !defined yyoverflow || YYERROR_VERBOSE +/*-------------------------------------------------. +| yyexhaustedlab -- memory exhaustion comes here. | +`-------------------------------------------------*/ +yyexhaustedlab: + yyerror (YY_("memory exhausted")); + yyresult = 2; + /* Fall through. */ +#endif + +yyreturn: + if (yychar != YYEMPTY) + { + /* Make sure we have latest lookahead translation. See comments at + user semantic actions for why this is necessary. */ + yytoken = YYTRANSLATE (yychar); + yydestruct ("Cleanup: discarding lookahead", + yytoken, &yylval); + } + /* Do not reclaim the symbols of the rule which action triggered + this YYABORT or YYACCEPT. */ + YYPOPSTACK (yylen); + YY_STACK_PRINT (yyss, yyssp); + while (yyssp != yyss) + { + yydestruct ("Cleanup: popping", + yystos[*yyssp], yyvsp); + YYPOPSTACK (1); + } +#ifndef yyoverflow + if (yyss != yyssa) + YYSTACK_FREE (yyss); +#endif +#if YYERROR_VERBOSE + if (yymsg != yymsgbuf) + YYSTACK_FREE (yymsg); +#endif + /* Make sure YYID is used. */ + return YYID (yyresult); +} + + diff --git a/src/conf_parser.h b/src/conf_parser.h new file mode 100644 index 0000000..89bb943 --- /dev/null +++ b/src/conf_parser.h @@ -0,0 +1,513 @@ +/* A Bison parser, made by GNU Bison 2.6.2. */ + +/* Bison interface for Yacc-like parsers in C + + Copyright (C) 1984, 1989-1990, 2000-2012 Free Software Foundation, Inc. + + 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 3 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, see <http://www.gnu.org/licenses/>. */ + +/* As a special exception, you may create a larger work that contains + part or all of the Bison parser skeleton and distribute that work + under terms of your choice, so long as that work isn't itself a + parser generator using the skeleton or a modified version thereof + as a parser skeleton. Alternatively, if you modify or redistribute + the parser skeleton itself, you may (at your option) remove this + special exception, which will cause the skeleton and the resulting + Bison output files to be licensed under the GNU General Public + License without this special exception. + + This special exception was added by the Free Software Foundation in + version 2.2 of Bison. */ + +#ifndef YY_Y_TAB_H +# define YY_Y_TAB_H +/* Enabling traces. */ +#ifndef YYDEBUG +# define YYDEBUG 0 +#endif +#if YYDEBUG +extern int yydebug; +#endif + +/* Tokens. */ +#ifndef YYTOKENTYPE +# define YYTOKENTYPE + /* Put the tokens into the symbol table, so that GDB and other debuggers + know about them. */ + enum yytokentype { + ACCEPT_PASSWORD = 258, + ADMIN = 259, + AFTYPE = 260, + ANTI_NICK_FLOOD = 261, + ANTI_SPAM_EXIT_MESSAGE_TIME = 262, + AUTOCONN = 263, + BYTES = 264, + KBYTES = 265, + MBYTES = 266, + CALLER_ID_WAIT = 267, + CAN_FLOOD = 268, + CHANNEL = 269, + CIDR_BITLEN_IPV4 = 270, + CIDR_BITLEN_IPV6 = 271, + CLASS = 272, + CONNECT = 273, + CONNECTFREQ = 274, + DEFAULT_FLOODCOUNT = 275, + DEFAULT_SPLIT_SERVER_COUNT = 276, + DEFAULT_SPLIT_USER_COUNT = 277, + DENY = 278, + DESCRIPTION = 279, + DIE = 280, + DISABLE_AUTH = 281, + DISABLE_FAKE_CHANNELS = 282, + DISABLE_REMOTE_COMMANDS = 283, + DOTS_IN_IDENT = 284, + EGDPOOL_PATH = 285, + EMAIL = 286, + ENCRYPTED = 287, + EXCEED_LIMIT = 288, + EXEMPT = 289, + FAILED_OPER_NOTICE = 290, + IRCD_FLAGS = 291, + FLATTEN_LINKS = 292, + GECOS = 293, + GENERAL = 294, + GLINE = 295, + GLINE_DURATION = 296, + GLINE_ENABLE = 297, + GLINE_EXEMPT = 298, + GLINE_REQUEST_DURATION = 299, + GLINE_MIN_CIDR = 300, + GLINE_MIN_CIDR6 = 301, + GLOBAL_KILL = 302, + IRCD_AUTH = 303, + NEED_IDENT = 304, + HAVENT_READ_CONF = 305, + HIDDEN = 306, + HIDDEN_NAME = 307, + HIDE_SERVER_IPS = 308, + HIDE_SERVERS = 309, + HIDE_SPOOF_IPS = 310, + HOST = 311, + HUB = 312, + HUB_MASK = 313, + IGNORE_BOGUS_TS = 314, + INVISIBLE_ON_CONNECT = 315, + IP = 316, + KILL = 317, + KILL_CHASE_TIME_LIMIT = 318, + KLINE = 319, + KLINE_EXEMPT = 320, + KNOCK_DELAY = 321, + KNOCK_DELAY_CHANNEL = 322, + LEAF_MASK = 323, + LINKS_DELAY = 324, + LISTEN = 325, + T_LOG = 326, + MAX_ACCEPT = 327, + MAX_BANS = 328, + MAX_CHANS_PER_OPER = 329, + MAX_CHANS_PER_USER = 330, + MAX_GLOBAL = 331, + MAX_IDENT = 332, + MAX_LOCAL = 333, + MAX_NICK_CHANGES = 334, + MAX_NICK_TIME = 335, + MAX_NUMBER = 336, + MAX_TARGETS = 337, + MAX_WATCH = 338, + MESSAGE_LOCALE = 339, + MIN_NONWILDCARD = 340, + MIN_NONWILDCARD_SIMPLE = 341, + MODULE = 342, + MODULES = 343, + NAME = 344, + NEED_PASSWORD = 345, + NETWORK_DESC = 346, + NETWORK_NAME = 347, + NICK = 348, + NICK_CHANGES = 349, + NO_CREATE_ON_SPLIT = 350, + NO_JOIN_ON_SPLIT = 351, + NO_OPER_FLOOD = 352, + NO_TILDE = 353, + NUMBER = 354, + NUMBER_PER_CIDR = 355, + NUMBER_PER_IP = 356, + OPERATOR = 357, + OPERS_BYPASS_CALLERID = 358, + OPER_ONLY_UMODES = 359, + OPER_PASS_RESV = 360, + OPER_SPY_T = 361, + OPER_UMODES = 362, + JOIN_FLOOD_COUNT = 363, + JOIN_FLOOD_TIME = 364, + PACE_WAIT = 365, + PACE_WAIT_SIMPLE = 366, + PASSWORD = 367, + PATH = 368, + PING_COOKIE = 369, + PING_TIME = 370, + PING_WARNING = 371, + PORT = 372, + QSTRING = 373, + QUIET_ON_BAN = 374, + REASON = 375, + REDIRPORT = 376, + REDIRSERV = 377, + REGEX_T = 378, + REHASH = 379, + REMOTE = 380, + REMOTEBAN = 381, + RESTRICT_CHANNELS = 382, + RSA_PRIVATE_KEY_FILE = 383, + RSA_PUBLIC_KEY_FILE = 384, + SSL_CERTIFICATE_FILE = 385, + SSL_DH_PARAM_FILE = 386, + T_SSL_CLIENT_METHOD = 387, + T_SSL_SERVER_METHOD = 388, + T_SSLV3 = 389, + T_TLSV1 = 390, + RESV = 391, + RESV_EXEMPT = 392, + SECONDS = 393, + MINUTES = 394, + HOURS = 395, + DAYS = 396, + WEEKS = 397, + SENDQ = 398, + SEND_PASSWORD = 399, + SERVERHIDE = 400, + SERVERINFO = 401, + IRCD_SID = 402, + TKLINE_EXPIRE_NOTICES = 403, + T_SHARED = 404, + T_CLUSTER = 405, + TYPE = 406, + SHORT_MOTD = 407, + SPOOF = 408, + SPOOF_NOTICE = 409, + STATS_E_DISABLED = 410, + STATS_I_OPER_ONLY = 411, + STATS_K_OPER_ONLY = 412, + STATS_O_OPER_ONLY = 413, + STATS_P_OPER_ONLY = 414, + TBOOL = 415, + TMASKED = 416, + TS_MAX_DELTA = 417, + TS_WARN_DELTA = 418, + TWODOTS = 419, + T_ALL = 420, + T_BOTS = 421, + T_SOFTCALLERID = 422, + T_CALLERID = 423, + T_CCONN = 424, + T_CCONN_FULL = 425, + T_SSL_CIPHER_LIST = 426, + T_DEAF = 427, + T_DEBUG = 428, + T_DLINE = 429, + T_EXTERNAL = 430, + T_FULL = 431, + T_INVISIBLE = 432, + T_IPV4 = 433, + T_IPV6 = 434, + T_LOCOPS = 435, + T_MAX_CLIENTS = 436, + T_NCHANGE = 437, + T_OPERWALL = 438, + T_RECVQ = 439, + T_REJ = 440, + T_SERVER = 441, + T_SERVNOTICE = 442, + T_SET = 443, + T_SKILL = 444, + T_SPY = 445, + T_SSL = 446, + T_UMODES = 447, + T_UNAUTH = 448, + T_UNDLINE = 449, + T_UNLIMITED = 450, + T_UNRESV = 451, + T_UNXLINE = 452, + T_GLOBOPS = 453, + T_WALLOP = 454, + T_RESTART = 455, + T_SERVICE = 456, + T_SERVICES_NAME = 457, + THROTTLE_TIME = 458, + TRUE_NO_OPER_FLOOD = 459, + UNKLINE = 460, + USER = 461, + USE_EGD = 462, + USE_LOGGING = 463, + VHOST = 464, + VHOST6 = 465, + XLINE = 466, + WARN_NO_NLINE = 467, + T_SIZE = 468, + T_FILE = 469 + }; +#endif +/* Tokens. */ +#define ACCEPT_PASSWORD 258 +#define ADMIN 259 +#define AFTYPE 260 +#define ANTI_NICK_FLOOD 261 +#define ANTI_SPAM_EXIT_MESSAGE_TIME 262 +#define AUTOCONN 263 +#define BYTES 264 +#define KBYTES 265 +#define MBYTES 266 +#define CALLER_ID_WAIT 267 +#define CAN_FLOOD 268 +#define CHANNEL 269 +#define CIDR_BITLEN_IPV4 270 +#define CIDR_BITLEN_IPV6 271 +#define CLASS 272 +#define CONNECT 273 +#define CONNECTFREQ 274 +#define DEFAULT_FLOODCOUNT 275 +#define DEFAULT_SPLIT_SERVER_COUNT 276 +#define DEFAULT_SPLIT_USER_COUNT 277 +#define DENY 278 +#define DESCRIPTION 279 +#define DIE 280 +#define DISABLE_AUTH 281 +#define DISABLE_FAKE_CHANNELS 282 +#define DISABLE_REMOTE_COMMANDS 283 +#define DOTS_IN_IDENT 284 +#define EGDPOOL_PATH 285 +#define EMAIL 286 +#define ENCRYPTED 287 +#define EXCEED_LIMIT 288 +#define EXEMPT 289 +#define FAILED_OPER_NOTICE 290 +#define IRCD_FLAGS 291 +#define FLATTEN_LINKS 292 +#define GECOS 293 +#define GENERAL 294 +#define GLINE 295 +#define GLINE_DURATION 296 +#define GLINE_ENABLE 297 +#define GLINE_EXEMPT 298 +#define GLINE_REQUEST_DURATION 299 +#define GLINE_MIN_CIDR 300 +#define GLINE_MIN_CIDR6 301 +#define GLOBAL_KILL 302 +#define IRCD_AUTH 303 +#define NEED_IDENT 304 +#define HAVENT_READ_CONF 305 +#define HIDDEN 306 +#define HIDDEN_NAME 307 +#define HIDE_SERVER_IPS 308 +#define HIDE_SERVERS 309 +#define HIDE_SPOOF_IPS 310 +#define HOST 311 +#define HUB 312 +#define HUB_MASK 313 +#define IGNORE_BOGUS_TS 314 +#define INVISIBLE_ON_CONNECT 315 +#define IP 316 +#define KILL 317 +#define KILL_CHASE_TIME_LIMIT 318 +#define KLINE 319 +#define KLINE_EXEMPT 320 +#define KNOCK_DELAY 321 +#define KNOCK_DELAY_CHANNEL 322 +#define LEAF_MASK 323 +#define LINKS_DELAY 324 +#define LISTEN 325 +#define T_LOG 326 +#define MAX_ACCEPT 327 +#define MAX_BANS 328 +#define MAX_CHANS_PER_OPER 329 +#define MAX_CHANS_PER_USER 330 +#define MAX_GLOBAL 331 +#define MAX_IDENT 332 +#define MAX_LOCAL 333 +#define MAX_NICK_CHANGES 334 +#define MAX_NICK_TIME 335 +#define MAX_NUMBER 336 +#define MAX_TARGETS 337 +#define MAX_WATCH 338 +#define MESSAGE_LOCALE 339 +#define MIN_NONWILDCARD 340 +#define MIN_NONWILDCARD_SIMPLE 341 +#define MODULE 342 +#define MODULES 343 +#define NAME 344 +#define NEED_PASSWORD 345 +#define NETWORK_DESC 346 +#define NETWORK_NAME 347 +#define NICK 348 +#define NICK_CHANGES 349 +#define NO_CREATE_ON_SPLIT 350 +#define NO_JOIN_ON_SPLIT 351 +#define NO_OPER_FLOOD 352 +#define NO_TILDE 353 +#define NUMBER 354 +#define NUMBER_PER_CIDR 355 +#define NUMBER_PER_IP 356 +#define OPERATOR 357 +#define OPERS_BYPASS_CALLERID 358 +#define OPER_ONLY_UMODES 359 +#define OPER_PASS_RESV 360 +#define OPER_SPY_T 361 +#define OPER_UMODES 362 +#define JOIN_FLOOD_COUNT 363 +#define JOIN_FLOOD_TIME 364 +#define PACE_WAIT 365 +#define PACE_WAIT_SIMPLE 366 +#define PASSWORD 367 +#define PATH 368 +#define PING_COOKIE 369 +#define PING_TIME 370 +#define PING_WARNING 371 +#define PORT 372 +#define QSTRING 373 +#define QUIET_ON_BAN 374 +#define REASON 375 +#define REDIRPORT 376 +#define REDIRSERV 377 +#define REGEX_T 378 +#define REHASH 379 +#define REMOTE 380 +#define REMOTEBAN 381 +#define RESTRICT_CHANNELS 382 +#define RSA_PRIVATE_KEY_FILE 383 +#define RSA_PUBLIC_KEY_FILE 384 +#define SSL_CERTIFICATE_FILE 385 +#define SSL_DH_PARAM_FILE 386 +#define T_SSL_CLIENT_METHOD 387 +#define T_SSL_SERVER_METHOD 388 +#define T_SSLV3 389 +#define T_TLSV1 390 +#define RESV 391 +#define RESV_EXEMPT 392 +#define SECONDS 393 +#define MINUTES 394 +#define HOURS 395 +#define DAYS 396 +#define WEEKS 397 +#define SENDQ 398 +#define SEND_PASSWORD 399 +#define SERVERHIDE 400 +#define SERVERINFO 401 +#define IRCD_SID 402 +#define TKLINE_EXPIRE_NOTICES 403 +#define T_SHARED 404 +#define T_CLUSTER 405 +#define TYPE 406 +#define SHORT_MOTD 407 +#define SPOOF 408 +#define SPOOF_NOTICE 409 +#define STATS_E_DISABLED 410 +#define STATS_I_OPER_ONLY 411 +#define STATS_K_OPER_ONLY 412 +#define STATS_O_OPER_ONLY 413 +#define STATS_P_OPER_ONLY 414 +#define TBOOL 415 +#define TMASKED 416 +#define TS_MAX_DELTA 417 +#define TS_WARN_DELTA 418 +#define TWODOTS 419 +#define T_ALL 420 +#define T_BOTS 421 +#define T_SOFTCALLERID 422 +#define T_CALLERID 423 +#define T_CCONN 424 +#define T_CCONN_FULL 425 +#define T_SSL_CIPHER_LIST 426 +#define T_DEAF 427 +#define T_DEBUG 428 +#define T_DLINE 429 +#define T_EXTERNAL 430 +#define T_FULL 431 +#define T_INVISIBLE 432 +#define T_IPV4 433 +#define T_IPV6 434 +#define T_LOCOPS 435 +#define T_MAX_CLIENTS 436 +#define T_NCHANGE 437 +#define T_OPERWALL 438 +#define T_RECVQ 439 +#define T_REJ 440 +#define T_SERVER 441 +#define T_SERVNOTICE 442 +#define T_SET 443 +#define T_SKILL 444 +#define T_SPY 445 +#define T_SSL 446 +#define T_UMODES 447 +#define T_UNAUTH 448 +#define T_UNDLINE 449 +#define T_UNLIMITED 450 +#define T_UNRESV 451 +#define T_UNXLINE 452 +#define T_GLOBOPS 453 +#define T_WALLOP 454 +#define T_RESTART 455 +#define T_SERVICE 456 +#define T_SERVICES_NAME 457 +#define THROTTLE_TIME 458 +#define TRUE_NO_OPER_FLOOD 459 +#define UNKLINE 460 +#define USER 461 +#define USE_EGD 462 +#define USE_LOGGING 463 +#define VHOST 464 +#define VHOST6 465 +#define XLINE 466 +#define WARN_NO_NLINE 467 +#define T_SIZE 468 +#define T_FILE 469 + + + +#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED +typedef union YYSTYPE +{ +/* Line 2049 of yacc.c */ +#line 110 "conf_parser.y" + + int number; + char *string; + + +/* Line 2049 of yacc.c */ +#line 491 "conf_parser.h" +} YYSTYPE; +# define YYSTYPE_IS_TRIVIAL 1 +# define yystype YYSTYPE /* obsolescent; will be withdrawn */ +# define YYSTYPE_IS_DECLARED 1 +#endif + +extern YYSTYPE yylval; + +#ifdef YYPARSE_PARAM +#if defined __STDC__ || defined __cplusplus +int yyparse (void *YYPARSE_PARAM); +#else +int yyparse (); +#endif +#else /* ! YYPARSE_PARAM */ +#if defined __STDC__ || defined __cplusplus +int yyparse (void); +#else +int yyparse (); +#endif +#endif /* ! YYPARSE_PARAM */ + +#endif /* !YY_Y_TAB_H */ diff --git a/src/conf_parser.y b/src/conf_parser.y new file mode 100644 index 0000000..1e5096b --- /dev/null +++ b/src/conf_parser.y @@ -0,0 +1,3072 @@ +/* + * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd). + * conf_parser.y: Parses the ircd configuration file. + * + * Copyright (C) 2005 by the past and present ircd coders, and others. + * + * 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 + * + * $Id$ + */ + +%{ + +#define YY_NO_UNPUT +#include <sys/types.h> +#include <string.h> + +#include "config.h" +#include "stdinc.h" +#include "ircd.h" +#include "list.h" +#include "conf.h" +#include "event.h" +#include "log.h" +#include "client.h" /* for UMODE_ALL only */ +#include "irc_string.h" +#include "sprintf_irc.h" +#include "memory.h" +#include "modules.h" +#include "s_serv.h" +#include "hostmask.h" +#include "send.h" +#include "listener.h" +#include "resv.h" +#include "numeric.h" +#include "s_user.h" + +#ifdef HAVE_LIBCRYPTO +#include <openssl/rsa.h> +#include <openssl/bio.h> +#include <openssl/pem.h> +#include <openssl/dh.h> +#endif + +int yylex(void); + +static char *class_name = NULL; +static struct ConfItem *yy_conf = NULL; +static struct AccessItem *yy_aconf = NULL; +static struct MatchItem *yy_match_item = NULL; +static struct ClassItem *yy_class = NULL; +static char *yy_class_name = NULL; + +static dlink_list col_conf_list = { NULL, NULL, 0 }; +static unsigned int listener_flags = 0; +static unsigned int regex_ban = 0; +static char userbuf[IRCD_BUFSIZE]; +static char hostbuf[IRCD_BUFSIZE]; +static char reasonbuf[REASONLEN + 1]; +static char gecos_name[REALLEN * 4]; +static char lfile[IRCD_BUFSIZE]; +static unsigned int ltype = 0; +static unsigned int lsize = 0; +static char *resv_reason = NULL; +static char *listener_address = NULL; + +struct CollectItem +{ + dlink_node node; + char *name; + char *user; + char *host; + char *passwd; + int port; + int flags; +#ifdef HAVE_LIBCRYPTO + char *rsa_public_key_file; + RSA *rsa_public_key; +#endif +}; + +static void +free_collect_item(struct CollectItem *item) +{ + MyFree(item->name); + MyFree(item->user); + MyFree(item->host); + MyFree(item->passwd); +#ifdef HAVE_LIBCRYPTO + MyFree(item->rsa_public_key_file); +#endif + MyFree(item); +} + +%} + +%union { + int number; + char *string; +} + +%token ACCEPT_PASSWORD +%token ADMIN +%token AFTYPE +%token ANTI_NICK_FLOOD +%token ANTI_SPAM_EXIT_MESSAGE_TIME +%token AUTOCONN +%token BYTES KBYTES MBYTES +%token CALLER_ID_WAIT +%token CAN_FLOOD +%token CHANNEL +%token CIDR_BITLEN_IPV4 +%token CIDR_BITLEN_IPV6 +%token CLASS +%token CONNECT +%token CONNECTFREQ +%token DEFAULT_FLOODCOUNT +%token DEFAULT_SPLIT_SERVER_COUNT +%token DEFAULT_SPLIT_USER_COUNT +%token DENY +%token DESCRIPTION +%token DIE +%token DISABLE_AUTH +%token DISABLE_FAKE_CHANNELS +%token DISABLE_REMOTE_COMMANDS +%token DOTS_IN_IDENT +%token EGDPOOL_PATH +%token EMAIL +%token ENCRYPTED +%token EXCEED_LIMIT +%token EXEMPT +%token FAILED_OPER_NOTICE +%token IRCD_FLAGS +%token FLATTEN_LINKS +%token GECOS +%token GENERAL +%token GLINE +%token GLINE_DURATION +%token GLINE_ENABLE +%token GLINE_EXEMPT +%token GLINE_REQUEST_DURATION +%token GLINE_MIN_CIDR +%token GLINE_MIN_CIDR6 +%token GLOBAL_KILL +%token IRCD_AUTH +%token NEED_IDENT +%token HAVENT_READ_CONF +%token HIDDEN +%token HIDDEN_NAME +%token HIDE_SERVER_IPS +%token HIDE_SERVERS +%token HIDE_SPOOF_IPS +%token HOST +%token HUB +%token HUB_MASK +%token IGNORE_BOGUS_TS +%token INVISIBLE_ON_CONNECT +%token IP +%token KILL +%token KILL_CHASE_TIME_LIMIT +%token KLINE +%token KLINE_EXEMPT +%token KNOCK_DELAY +%token KNOCK_DELAY_CHANNEL +%token LEAF_MASK +%token LINKS_DELAY +%token LISTEN +%token T_LOG +%token MAX_ACCEPT +%token MAX_BANS +%token MAX_CHANS_PER_OPER +%token MAX_CHANS_PER_USER +%token MAX_GLOBAL +%token MAX_IDENT +%token MAX_LOCAL +%token MAX_NICK_CHANGES +%token MAX_NICK_TIME +%token MAX_NUMBER +%token MAX_TARGETS +%token MAX_WATCH +%token MESSAGE_LOCALE +%token MIN_NONWILDCARD +%token MIN_NONWILDCARD_SIMPLE +%token MODULE +%token MODULES +%token NAME +%token NEED_PASSWORD +%token NETWORK_DESC +%token NETWORK_NAME +%token NICK +%token NICK_CHANGES +%token NO_CREATE_ON_SPLIT +%token NO_JOIN_ON_SPLIT +%token NO_OPER_FLOOD +%token NO_TILDE +%token NUMBER +%token NUMBER_PER_CIDR +%token NUMBER_PER_IP +%token OPERATOR +%token OPERS_BYPASS_CALLERID +%token OPER_ONLY_UMODES +%token OPER_PASS_RESV +%token OPER_SPY_T +%token OPER_UMODES +%token JOIN_FLOOD_COUNT +%token JOIN_FLOOD_TIME +%token PACE_WAIT +%token PACE_WAIT_SIMPLE +%token PASSWORD +%token PATH +%token PING_COOKIE +%token PING_TIME +%token PING_WARNING +%token PORT +%token QSTRING +%token QUIET_ON_BAN +%token REASON +%token REDIRPORT +%token REDIRSERV +%token REGEX_T +%token REHASH +%token REMOTE +%token REMOTEBAN +%token RESTRICT_CHANNELS +%token RSA_PRIVATE_KEY_FILE +%token RSA_PUBLIC_KEY_FILE +%token SSL_CERTIFICATE_FILE +%token SSL_DH_PARAM_FILE +%token T_SSL_CLIENT_METHOD +%token T_SSL_SERVER_METHOD +%token T_SSLV3 +%token T_TLSV1 +%token RESV +%token RESV_EXEMPT +%token SECONDS MINUTES HOURS DAYS WEEKS +%token SENDQ +%token SEND_PASSWORD +%token SERVERHIDE +%token SERVERINFO +%token IRCD_SID +%token TKLINE_EXPIRE_NOTICES +%token T_SHARED +%token T_CLUSTER +%token TYPE +%token SHORT_MOTD +%token SPOOF +%token SPOOF_NOTICE +%token STATS_E_DISABLED +%token STATS_I_OPER_ONLY +%token STATS_K_OPER_ONLY +%token STATS_O_OPER_ONLY +%token STATS_P_OPER_ONLY +%token TBOOL +%token TMASKED +%token TS_MAX_DELTA +%token TS_WARN_DELTA +%token TWODOTS +%token T_ALL +%token T_BOTS +%token T_SOFTCALLERID +%token T_CALLERID +%token T_CCONN +%token T_CCONN_FULL +%token T_SSL_CIPHER_LIST +%token T_DEAF +%token T_DEBUG +%token T_DLINE +%token T_EXTERNAL +%token T_FULL +%token T_INVISIBLE +%token T_IPV4 +%token T_IPV6 +%token T_LOCOPS +%token T_MAX_CLIENTS +%token T_NCHANGE +%token T_OPERWALL +%token T_RECVQ +%token T_REJ +%token T_SERVER +%token T_SERVNOTICE +%token T_SET +%token T_SKILL +%token T_SPY +%token T_SSL +%token T_UMODES +%token T_UNAUTH +%token T_UNDLINE +%token T_UNLIMITED +%token T_UNRESV +%token T_UNXLINE +%token T_GLOBOPS +%token T_WALLOP +%token T_RESTART +%token T_SERVICE +%token T_SERVICES_NAME +%token THROTTLE_TIME +%token TRUE_NO_OPER_FLOOD +%token UNKLINE +%token USER +%token USE_EGD +%token USE_LOGGING +%token VHOST +%token VHOST6 +%token XLINE +%token WARN_NO_NLINE +%token T_SIZE +%token T_FILE + +%type <string> QSTRING +%type <number> NUMBER +%type <number> timespec +%type <number> timespec_ +%type <number> sizespec +%type <number> sizespec_ + +%% +conf: + | conf conf_item + ; + +conf_item: admin_entry + | logging_entry + | oper_entry + | channel_entry + | class_entry + | listen_entry + | auth_entry + | serverinfo_entry + | serverhide_entry + | resv_entry + | service_entry + | shared_entry + | cluster_entry + | connect_entry + | kill_entry + | deny_entry + | exempt_entry + | general_entry + | gecos_entry + | modules_entry + | error ';' + | error '}' + ; + + +timespec_: { $$ = 0; } | timespec; +timespec: NUMBER timespec_ + { + $$ = $1 + $2; + } + | NUMBER SECONDS timespec_ + { + $$ = $1 + $3; + } + | NUMBER MINUTES timespec_ + { + $$ = $1 * 60 + $3; + } + | NUMBER HOURS timespec_ + { + $$ = $1 * 60 * 60 + $3; + } + | NUMBER DAYS timespec_ + { + $$ = $1 * 60 * 60 * 24 + $3; + } + | NUMBER WEEKS timespec_ + { + $$ = $1 * 60 * 60 * 24 * 7 + $3; + } + ; + +sizespec_: { $$ = 0; } | sizespec; +sizespec: NUMBER sizespec_ { $$ = $1 + $2; } + | NUMBER BYTES sizespec_ { $$ = $1 + $3; } + | NUMBER KBYTES sizespec_ { $$ = $1 * 1024 + $3; } + | NUMBER MBYTES sizespec_ { $$ = $1 * 1024 * 1024 + $3; } + ; + + +/*************************************************************************** + * section modules + ***************************************************************************/ +modules_entry: MODULES + '{' modules_items '}' ';'; + +modules_items: modules_items modules_item | modules_item; +modules_item: modules_module | modules_path | error ';' ; + +modules_module: MODULE '=' QSTRING ';' +{ + if (conf_parser_ctx.pass == 2) + add_conf_module(libio_basename(yylval.string)); +}; + +modules_path: PATH '=' QSTRING ';' +{ + if (conf_parser_ctx.pass == 2) + mod_add_path(yylval.string); +}; + + +serverinfo_entry: SERVERINFO '{' serverinfo_items '}' ';'; + +serverinfo_items: serverinfo_items serverinfo_item | serverinfo_item ; +serverinfo_item: serverinfo_name | serverinfo_vhost | + serverinfo_hub | serverinfo_description | + serverinfo_network_name | serverinfo_network_desc | + serverinfo_max_clients | serverinfo_ssl_dh_param_file | + serverinfo_rsa_private_key_file | serverinfo_vhost6 | + serverinfo_sid | serverinfo_ssl_certificate_file | + serverinfo_ssl_client_method | serverinfo_ssl_server_method | + serverinfo_ssl_cipher_list | + error ';' ; + + +serverinfo_ssl_client_method: T_SSL_CLIENT_METHOD '=' client_method_types ';' ; +serverinfo_ssl_server_method: T_SSL_SERVER_METHOD '=' server_method_types ';' ; + +client_method_types: client_method_types ',' client_method_type_item | client_method_type_item; +client_method_type_item: T_SSLV3 +{ +#ifdef HAVE_LIBCRYPTO + if (conf_parser_ctx.pass == 2 && ServerInfo.client_ctx) + SSL_CTX_clear_options(ServerInfo.client_ctx, SSL_OP_NO_SSLv3); +#endif +} | T_TLSV1 +{ +#ifdef HAVE_LIBCRYPTO + if (conf_parser_ctx.pass == 2 && ServerInfo.client_ctx) + SSL_CTX_clear_options(ServerInfo.client_ctx, SSL_OP_NO_TLSv1); +#endif +}; + +server_method_types: server_method_types ',' server_method_type_item | server_method_type_item; +server_method_type_item: T_SSLV3 +{ +#ifdef HAVE_LIBCRYPTO + if (conf_parser_ctx.pass == 2 && ServerInfo.server_ctx) + SSL_CTX_clear_options(ServerInfo.server_ctx, SSL_OP_NO_SSLv3); +#endif +} | T_TLSV1 +{ +#ifdef HAVE_LIBCRYPTO + if (conf_parser_ctx.pass == 2 && ServerInfo.server_ctx) + SSL_CTX_clear_options(ServerInfo.server_ctx, SSL_OP_NO_TLSv1); +#endif +}; + +serverinfo_ssl_certificate_file: SSL_CERTIFICATE_FILE '=' QSTRING ';' +{ +#ifdef HAVE_LIBCRYPTO + if (conf_parser_ctx.pass == 2 && ServerInfo.server_ctx) + { + if (!ServerInfo.rsa_private_key_file) + { + yyerror("No rsa_private_key_file specified, SSL disabled"); + break; + } + + if (SSL_CTX_use_certificate_file(ServerInfo.server_ctx, yylval.string, + SSL_FILETYPE_PEM) <= 0 || + SSL_CTX_use_certificate_file(ServerInfo.client_ctx, yylval.string, + SSL_FILETYPE_PEM) <= 0) + { + yyerror(ERR_lib_error_string(ERR_get_error())); + break; + } + + if (SSL_CTX_use_PrivateKey_file(ServerInfo.server_ctx, ServerInfo.rsa_private_key_file, + SSL_FILETYPE_PEM) <= 0 || + SSL_CTX_use_PrivateKey_file(ServerInfo.client_ctx, ServerInfo.rsa_private_key_file, + SSL_FILETYPE_PEM) <= 0) + { + yyerror(ERR_lib_error_string(ERR_get_error())); + break; + } + + if (!SSL_CTX_check_private_key(ServerInfo.server_ctx) || + !SSL_CTX_check_private_key(ServerInfo.client_ctx)) + { + yyerror(ERR_lib_error_string(ERR_get_error())); + break; + } + } +#endif +}; + +serverinfo_rsa_private_key_file: RSA_PRIVATE_KEY_FILE '=' QSTRING ';' +{ +#ifdef HAVE_LIBCRYPTO + if (conf_parser_ctx.pass == 1) + { + BIO *file; + + if (ServerInfo.rsa_private_key) + { + RSA_free(ServerInfo.rsa_private_key); + ServerInfo.rsa_private_key = NULL; + } + + if (ServerInfo.rsa_private_key_file) + { + MyFree(ServerInfo.rsa_private_key_file); + ServerInfo.rsa_private_key_file = NULL; + } + + DupString(ServerInfo.rsa_private_key_file, yylval.string); + + if ((file = BIO_new_file(yylval.string, "r")) == NULL) + { + yyerror("File open failed, ignoring"); + break; + } + + ServerInfo.rsa_private_key = PEM_read_bio_RSAPrivateKey(file, NULL, 0, NULL); + + BIO_set_close(file, BIO_CLOSE); + BIO_free(file); + + if (ServerInfo.rsa_private_key == NULL) + { + yyerror("Couldn't extract key, ignoring"); + break; + } + + if (!RSA_check_key(ServerInfo.rsa_private_key)) + { + RSA_free(ServerInfo.rsa_private_key); + ServerInfo.rsa_private_key = NULL; + + yyerror("Invalid key, ignoring"); + break; + } + + /* require 2048 bit (256 byte) key */ + if (RSA_size(ServerInfo.rsa_private_key) != 256) + { + RSA_free(ServerInfo.rsa_private_key); + ServerInfo.rsa_private_key = NULL; + + yyerror("Not a 2048 bit key, ignoring"); + } + } +#endif +}; + +serverinfo_ssl_dh_param_file: SSL_DH_PARAM_FILE '=' QSTRING ';' +{ +/* TBD - XXX: error reporting */ +#ifdef HAVE_LIBCRYPTO + if (conf_parser_ctx.pass == 2 && ServerInfo.server_ctx) + { + BIO *file = BIO_new_file(yylval.string, "r"); + + if (file) + { + DH *dh = PEM_read_bio_DHparams(file, NULL, NULL, NULL); + + BIO_free(file); + + if (dh) + { + if (DH_size(dh) < 128) + ilog(LOG_TYPE_IRCD, "Ignoring serverinfo::ssl_dh_param_file -- need at least a 1024 bit DH prime size"); + else + SSL_CTX_set_tmp_dh(ServerInfo.server_ctx, dh); + + DH_free(dh); + } + } + } +#endif +}; + +serverinfo_ssl_cipher_list: T_SSL_CIPHER_LIST '=' QSTRING ';' +{ +#ifdef HAVE_LIBCRYPTO + if (conf_parser_ctx.pass == 2 && ServerInfo.server_ctx) + SSL_CTX_set_cipher_list(ServerInfo.server_ctx, yylval.string); +#endif +}; + +serverinfo_name: NAME '=' QSTRING ';' +{ + /* this isn't rehashable */ + if (conf_parser_ctx.pass == 2 && !ServerInfo.name) + { + if (valid_servname(yylval.string)) + DupString(ServerInfo.name, yylval.string); + else + { + ilog(LOG_TYPE_IRCD, "Ignoring serverinfo::name -- invalid name. Aborting."); + exit(0); + } + } +}; + +serverinfo_sid: IRCD_SID '=' QSTRING ';' +{ + /* this isn't rehashable */ + if (conf_parser_ctx.pass == 2 && !ServerInfo.sid) + { + if (valid_sid(yylval.string)) + DupString(ServerInfo.sid, yylval.string); + else + { + ilog(LOG_TYPE_IRCD, "Ignoring serverinfo::sid -- invalid SID. Aborting."); + exit(0); + } + } +}; + +serverinfo_description: DESCRIPTION '=' QSTRING ';' +{ + if (conf_parser_ctx.pass == 2) + { + MyFree(ServerInfo.description); + DupString(ServerInfo.description,yylval.string); + } +}; + +serverinfo_network_name: NETWORK_NAME '=' QSTRING ';' +{ + if (conf_parser_ctx.pass == 2) + { + char *p; + + if ((p = strchr(yylval.string, ' ')) != NULL) + p = '\0'; + + MyFree(ServerInfo.network_name); + DupString(ServerInfo.network_name, yylval.string); + } +}; + +serverinfo_network_desc: NETWORK_DESC '=' QSTRING ';' +{ + if (conf_parser_ctx.pass == 2) + { + MyFree(ServerInfo.network_desc); + DupString(ServerInfo.network_desc, yylval.string); + } +}; + +serverinfo_vhost: VHOST '=' QSTRING ';' +{ + if (conf_parser_ctx.pass == 2 && *yylval.string != '*') + { + struct addrinfo hints, *res; + + memset(&hints, 0, sizeof(hints)); + + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST; + + if (getaddrinfo(yylval.string, NULL, &hints, &res)) + ilog(LOG_TYPE_IRCD, "Invalid netmask for server vhost(%s)", yylval.string); + else + { + assert(res != NULL); + + memcpy(&ServerInfo.ip, res->ai_addr, res->ai_addrlen); + ServerInfo.ip.ss.ss_family = res->ai_family; + ServerInfo.ip.ss_len = res->ai_addrlen; + freeaddrinfo(res); + + ServerInfo.specific_ipv4_vhost = 1; + } + } +}; + +serverinfo_vhost6: VHOST6 '=' QSTRING ';' +{ +#ifdef IPV6 + if (conf_parser_ctx.pass == 2 && *yylval.string != '*') + { + struct addrinfo hints, *res; + + memset(&hints, 0, sizeof(hints)); + + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST; + + if (getaddrinfo(yylval.string, NULL, &hints, &res)) + ilog(LOG_TYPE_IRCD, "Invalid netmask for server vhost6(%s)", yylval.string); + else + { + assert(res != NULL); + + memcpy(&ServerInfo.ip6, res->ai_addr, res->ai_addrlen); + ServerInfo.ip6.ss.ss_family = res->ai_family; + ServerInfo.ip6.ss_len = res->ai_addrlen; + freeaddrinfo(res); + + ServerInfo.specific_ipv6_vhost = 1; + } + } +#endif +}; + +serverinfo_max_clients: T_MAX_CLIENTS '=' NUMBER ';' +{ + if (conf_parser_ctx.pass == 2) + { + recalc_fdlimit(NULL); + + if ($3 < MAXCLIENTS_MIN) + { + char buf[IRCD_BUFSIZE]; + ircsprintf(buf, "MAXCLIENTS too low, setting to %d", MAXCLIENTS_MIN); + yyerror(buf); + } + else if ($3 > MAXCLIENTS_MAX) + { + char buf[IRCD_BUFSIZE]; + ircsprintf(buf, "MAXCLIENTS too high, setting to %d", MAXCLIENTS_MAX); + yyerror(buf); + } + else + ServerInfo.max_clients = $3; + } +}; + +serverinfo_hub: HUB '=' TBOOL ';' +{ + if (conf_parser_ctx.pass == 2) + ServerInfo.hub = yylval.number; +}; + +/*************************************************************************** + * admin section + ***************************************************************************/ +admin_entry: ADMIN '{' admin_items '}' ';' ; + +admin_items: admin_items admin_item | admin_item; +admin_item: admin_name | admin_description | + admin_email | error ';' ; + +admin_name: NAME '=' QSTRING ';' +{ + if (conf_parser_ctx.pass == 2) + { + MyFree(AdminInfo.name); + DupString(AdminInfo.name, yylval.string); + } +}; + +admin_email: EMAIL '=' QSTRING ';' +{ + if (conf_parser_ctx.pass == 2) + { + MyFree(AdminInfo.email); + DupString(AdminInfo.email, yylval.string); + } +}; + +admin_description: DESCRIPTION '=' QSTRING ';' +{ + if (conf_parser_ctx.pass == 2) + { + MyFree(AdminInfo.description); + DupString(AdminInfo.description, yylval.string); + } +}; + +/*************************************************************************** + * section logging + ***************************************************************************/ +logging_entry: T_LOG '{' logging_items '}' ';' ; +logging_items: logging_items logging_item | logging_item ; + +logging_item: logging_use_logging | logging_file_entry | + error ';' ; + +logging_use_logging: USE_LOGGING '=' TBOOL ';' +{ + if (conf_parser_ctx.pass == 2) + ConfigLoggingEntry.use_logging = yylval.number; +}; + +logging_file_entry: +{ + lfile[0] = '\0'; + ltype = 0; + lsize = 0; +} T_FILE '{' logging_file_items '}' ';' +{ + if (conf_parser_ctx.pass == 2 && ltype > 0) + log_add_file(ltype, lsize, lfile); +}; + +logging_file_items: logging_file_items logging_file_item | + logging_file_item ; + +logging_file_item: logging_file_name | logging_file_type | + logging_file_size | error ';' ; + +logging_file_name: NAME '=' QSTRING ';' +{ + strlcpy(lfile, yylval.string, sizeof(lfile)); +} + +logging_file_size: T_SIZE '=' sizespec ';' +{ + lsize = $3; +} | T_SIZE '=' T_UNLIMITED ';' +{ + lsize = 0; +}; + +logging_file_type: TYPE +{ + if (conf_parser_ctx.pass == 2) + ltype = 0; +} '=' logging_file_type_items ';' ; + +logging_file_type_items: logging_file_type_items ',' logging_file_type_item | logging_file_type_item; +logging_file_type_item: USER +{ + if (conf_parser_ctx.pass == 2) + ltype = LOG_TYPE_USER; +} | OPERATOR +{ + if (conf_parser_ctx.pass == 2) + ltype = LOG_TYPE_OPER; +} | GLINE +{ + if (conf_parser_ctx.pass == 2) + ltype = LOG_TYPE_GLINE; +} | T_DLINE +{ + if (conf_parser_ctx.pass == 2) + ltype = LOG_TYPE_DLINE; +} | KLINE +{ + if (conf_parser_ctx.pass == 2) + ltype = LOG_TYPE_KLINE; +} | KILL +{ + if (conf_parser_ctx.pass == 2) + ltype = LOG_TYPE_KILL; +} | T_DEBUG +{ + if (conf_parser_ctx.pass == 2) + ltype = LOG_TYPE_DEBUG; +}; + + +/*************************************************************************** + * section oper + ***************************************************************************/ +oper_entry: OPERATOR +{ + if (conf_parser_ctx.pass == 2) + { + yy_conf = make_conf_item(OPER_TYPE); + yy_aconf = map_to_conf(yy_conf); + SetConfEncrypted(yy_aconf); /* Yes, the default is encrypted */ + } + else + { + MyFree(class_name); + class_name = NULL; + } +} '{' oper_items '}' ';' +{ + if (conf_parser_ctx.pass == 2) + { + struct CollectItem *yy_tmp; + dlink_node *ptr; + dlink_node *next_ptr; + + conf_add_class_to_conf(yy_conf, class_name); + + /* Now, make sure there is a copy of the "base" given oper + * block in each of the collected copies + */ + + DLINK_FOREACH_SAFE(ptr, next_ptr, col_conf_list.head) + { + struct AccessItem *new_aconf; + struct ConfItem *new_conf; + yy_tmp = ptr->data; + + new_conf = make_conf_item(OPER_TYPE); + new_aconf = (struct AccessItem *)map_to_conf(new_conf); + + new_aconf->flags = yy_aconf->flags; + + if (yy_conf->name != NULL) + DupString(new_conf->name, yy_conf->name); + if (yy_tmp->user != NULL) + DupString(new_aconf->user, yy_tmp->user); + else + DupString(new_aconf->user, "*"); + if (yy_tmp->host != NULL) + DupString(new_aconf->host, yy_tmp->host); + else + DupString(new_aconf->host, "*"); + + new_aconf->type = parse_netmask(new_aconf->host, &new_aconf->addr, + &new_aconf->bits); + + conf_add_class_to_conf(new_conf, class_name); + if (yy_aconf->passwd != NULL) + DupString(new_aconf->passwd, yy_aconf->passwd); + + new_aconf->port = yy_aconf->port; +#ifdef HAVE_LIBCRYPTO + if (yy_aconf->rsa_public_key_file != NULL) + { + BIO *file; + + DupString(new_aconf->rsa_public_key_file, + yy_aconf->rsa_public_key_file); + + file = BIO_new_file(yy_aconf->rsa_public_key_file, "r"); + new_aconf->rsa_public_key = PEM_read_bio_RSA_PUBKEY(file, + NULL, 0, NULL); + BIO_set_close(file, BIO_CLOSE); + BIO_free(file); + } +#endif + +#ifdef HAVE_LIBCRYPTO + if (yy_tmp->name && (yy_tmp->passwd || yy_aconf->rsa_public_key) + && yy_tmp->host) +#else + if (yy_tmp->name && yy_tmp->passwd && yy_tmp->host) +#endif + { + conf_add_class_to_conf(new_conf, class_name); + if (yy_tmp->name != NULL) + DupString(new_conf->name, yy_tmp->name); + } + + dlinkDelete(&yy_tmp->node, &col_conf_list); + free_collect_item(yy_tmp); + } + + yy_conf = NULL; + yy_aconf = NULL; + + + MyFree(class_name); + class_name = NULL; + } +}; + +oper_items: oper_items oper_item | oper_item; +oper_item: oper_name | oper_user | oper_password | + oper_umodes | oper_class | oper_encrypted | + oper_rsa_public_key_file | oper_flags | error ';' ; + +oper_name: NAME '=' QSTRING ';' +{ + if (conf_parser_ctx.pass == 2) + { + MyFree(yy_conf->name); + DupString(yy_conf->name, yylval.string); + } +}; + +oper_user: USER '=' QSTRING ';' +{ + if (conf_parser_ctx.pass == 2) + { + struct split_nuh_item nuh; + + nuh.nuhmask = yylval.string; + nuh.nickptr = NULL; + nuh.userptr = userbuf; + nuh.hostptr = hostbuf; + + nuh.nicksize = 0; + nuh.usersize = sizeof(userbuf); + nuh.hostsize = sizeof(hostbuf); + + split_nuh(&nuh); + + if (yy_aconf->user == NULL) + { + DupString(yy_aconf->user, userbuf); + DupString(yy_aconf->host, hostbuf); + + yy_aconf->type = parse_netmask(yy_aconf->host, &yy_aconf->addr, + &yy_aconf->bits); + } + else + { + struct CollectItem *yy_tmp = MyMalloc(sizeof(struct CollectItem)); + + DupString(yy_tmp->user, userbuf); + DupString(yy_tmp->host, hostbuf); + + dlinkAdd(yy_tmp, &yy_tmp->node, &col_conf_list); + } + } +}; + +oper_password: PASSWORD '=' QSTRING ';' +{ + if (conf_parser_ctx.pass == 2) + { + if (yy_aconf->passwd != NULL) + memset(yy_aconf->passwd, 0, strlen(yy_aconf->passwd)); + + MyFree(yy_aconf->passwd); + DupString(yy_aconf->passwd, yylval.string); + } +}; + +oper_encrypted: ENCRYPTED '=' TBOOL ';' +{ + if (conf_parser_ctx.pass == 2) + { + if (yylval.number) + SetConfEncrypted(yy_aconf); + else + ClearConfEncrypted(yy_aconf); + } +}; + +oper_rsa_public_key_file: RSA_PUBLIC_KEY_FILE '=' QSTRING ';' +{ +#ifdef HAVE_LIBCRYPTO + if (conf_parser_ctx.pass == 2) + { + BIO *file; + + if (yy_aconf->rsa_public_key != NULL) + { + RSA_free(yy_aconf->rsa_public_key); + yy_aconf->rsa_public_key = NULL; + } + + if (yy_aconf->rsa_public_key_file != NULL) + { + MyFree(yy_aconf->rsa_public_key_file); + yy_aconf->rsa_public_key_file = NULL; + } + + DupString(yy_aconf->rsa_public_key_file, yylval.string); + file = BIO_new_file(yylval.string, "r"); + + if (file == NULL) + { + yyerror("Ignoring rsa_public_key_file -- file doesn't exist"); + break; + } + + yy_aconf->rsa_public_key = PEM_read_bio_RSA_PUBKEY(file, NULL, 0, NULL); + + if (yy_aconf->rsa_public_key == NULL) + { + yyerror("Ignoring rsa_public_key_file -- Key invalid; check key syntax."); + break; + } + + BIO_set_close(file, BIO_CLOSE); + BIO_free(file); + } +#endif /* HAVE_LIBCRYPTO */ +}; + +oper_class: CLASS '=' QSTRING ';' +{ + if (conf_parser_ctx.pass == 2) + { + MyFree(class_name); + DupString(class_name, yylval.string); + } +}; + +oper_umodes: T_UMODES +{ + if (conf_parser_ctx.pass == 2) + yy_aconf->modes = 0; +} '=' oper_umodes_items ';' ; + +oper_umodes_items: oper_umodes_items ',' oper_umodes_item | oper_umodes_item; +oper_umodes_item: T_BOTS +{ + if (conf_parser_ctx.pass == 2) + yy_aconf->modes |= UMODE_BOTS; +} | T_CCONN +{ + if (conf_parser_ctx.pass == 2) + yy_aconf->modes |= UMODE_CCONN; +} | T_CCONN_FULL +{ + if (conf_parser_ctx.pass == 2) + yy_aconf->modes |= UMODE_CCONN_FULL; +} | T_DEAF +{ + if (conf_parser_ctx.pass == 2) + yy_aconf->modes |= UMODE_DEAF; +} | T_DEBUG +{ + if (conf_parser_ctx.pass == 2) + yy_aconf->modes |= UMODE_DEBUG; +} | T_FULL +{ + if (conf_parser_ctx.pass == 2) + yy_aconf->modes |= UMODE_FULL; +} | HIDDEN +{ + if (conf_parser_ctx.pass == 2) + yy_aconf->modes |= UMODE_HIDDEN; +} | T_SKILL +{ + if (conf_parser_ctx.pass == 2) + yy_aconf->modes |= UMODE_SKILL; +} | T_NCHANGE +{ + if (conf_parser_ctx.pass == 2) + yy_aconf->modes |= UMODE_NCHANGE; +} | T_REJ +{ + if (conf_parser_ctx.pass == 2) + yy_aconf->modes |= UMODE_REJ; +} | T_UNAUTH +{ + if (conf_parser_ctx.pass == 2) + yy_aconf->modes |= UMODE_UNAUTH; +} | T_SPY +{ + if (conf_parser_ctx.pass == 2) + yy_aconf->modes |= UMODE_SPY; +} | T_EXTERNAL +{ + if (conf_parser_ctx.pass == 2) + yy_aconf->modes |= UMODE_EXTERNAL; +} | T_OPERWALL +{ + if (conf_parser_ctx.pass == 2) + yy_aconf->modes |= UMODE_OPERWALL; +} | T_SERVNOTICE +{ + if (conf_parser_ctx.pass == 2) + yy_aconf->modes |= UMODE_SERVNOTICE; +} | T_INVISIBLE +{ + if (conf_parser_ctx.pass == 2) + yy_aconf->modes |= UMODE_INVISIBLE; +} | T_WALLOP +{ + if (conf_parser_ctx.pass == 2) + yy_aconf->modes |= UMODE_WALLOP; +} | T_SOFTCALLERID +{ + if (conf_parser_ctx.pass == 2) + yy_aconf->modes |= UMODE_SOFTCALLERID; +} | T_CALLERID +{ + if (conf_parser_ctx.pass == 2) + yy_aconf->modes |= UMODE_CALLERID; +} | T_LOCOPS +{ + if (conf_parser_ctx.pass == 2) + yy_aconf->modes |= UMODE_LOCOPS; +}; + +oper_flags: IRCD_FLAGS +{ + if (conf_parser_ctx.pass == 2) + yy_aconf->port = 0; +} '=' oper_flags_items ';'; + +oper_flags_items: oper_flags_items ',' oper_flags_item | oper_flags_item; +oper_flags_item: GLOBAL_KILL +{ + if (conf_parser_ctx.pass == 2) + yy_aconf->port |= OPER_FLAG_GLOBAL_KILL; +} | REMOTE +{ + if (conf_parser_ctx.pass == 2) + yy_aconf->port |= OPER_FLAG_REMOTE; +} | KLINE +{ + if (conf_parser_ctx.pass == 2) + yy_aconf->port |= OPER_FLAG_K; +} | UNKLINE +{ + if (conf_parser_ctx.pass == 2) + yy_aconf->port |= OPER_FLAG_UNKLINE; +} | T_DLINE +{ + if (conf_parser_ctx.pass == 2) + yy_aconf->port |= OPER_FLAG_DLINE; +} | T_UNDLINE +{ + if (conf_parser_ctx.pass == 2) + yy_aconf->port |= OPER_FLAG_UNDLINE; +} | XLINE +{ + if (conf_parser_ctx.pass == 2) + yy_aconf->port |= OPER_FLAG_X; +} | GLINE +{ + if (conf_parser_ctx.pass == 2) + yy_aconf->port |= OPER_FLAG_GLINE; +} | DIE +{ + if (conf_parser_ctx.pass == 2) + yy_aconf->port |= OPER_FLAG_DIE; +} | T_RESTART +{ + if (conf_parser_ctx.pass == 2) + yy_aconf->port |= OPER_FLAG_RESTART; +} | REHASH +{ + if (conf_parser_ctx.pass == 2) + yy_aconf->port |= OPER_FLAG_REHASH; +} | ADMIN +{ + if (conf_parser_ctx.pass == 2) + yy_aconf->port |= OPER_FLAG_ADMIN; +} | NICK_CHANGES +{ + if (conf_parser_ctx.pass == 2) + yy_aconf->port |= OPER_FLAG_N; +} | T_OPERWALL +{ + if (conf_parser_ctx.pass == 2) + yy_aconf->port |= OPER_FLAG_OPERWALL; +} | T_GLOBOPS +{ + if (conf_parser_ctx.pass == 2) + yy_aconf->port |= OPER_FLAG_GLOBOPS; +} | OPER_SPY_T +{ + if (conf_parser_ctx.pass == 2) + yy_aconf->port |= OPER_FLAG_OPER_SPY; +} | REMOTEBAN +{ + if (conf_parser_ctx.pass == 2) + yy_aconf->port |= OPER_FLAG_REMOTEBAN; +} | T_SET +{ + if (conf_parser_ctx.pass == 2) + yy_aconf->port |= OPER_FLAG_SET; +} | MODULE +{ + if (conf_parser_ctx.pass == 2) + yy_aconf->port |= OPER_FLAG_MODULE; +}; + + +/*************************************************************************** + * section class + ***************************************************************************/ +class_entry: CLASS +{ + if (conf_parser_ctx.pass == 1) + { + yy_conf = make_conf_item(CLASS_TYPE); + yy_class = map_to_conf(yy_conf); + } +} '{' class_items '}' ';' +{ + if (conf_parser_ctx.pass == 1) + { + struct ConfItem *cconf = NULL; + struct ClassItem *class = NULL; + + if (yy_class_name == NULL) + delete_conf_item(yy_conf); + else + { + cconf = find_exact_name_conf(CLASS_TYPE, NULL, yy_class_name, NULL, NULL); + + if (cconf != NULL) /* The class existed already */ + { + int user_count = 0; + + rebuild_cidr_class(cconf, yy_class); + + class = map_to_conf(cconf); + + user_count = class->curr_user_count; + memcpy(class, yy_class, sizeof(*class)); + class->curr_user_count = user_count; + class->active = 1; + + delete_conf_item(yy_conf); + + MyFree(cconf->name); /* Allows case change of class name */ + cconf->name = yy_class_name; + } + else /* Brand new class */ + { + MyFree(yy_conf->name); /* just in case it was allocated */ + yy_conf->name = yy_class_name; + yy_class->active = 1; + } + } + + yy_class_name = NULL; + } +}; + +class_items: class_items class_item | class_item; +class_item: class_name | + class_cidr_bitlen_ipv4 | class_cidr_bitlen_ipv6 | + class_ping_time | + class_ping_warning | + class_number_per_cidr | + class_number_per_ip | + class_connectfreq | + class_max_number | + class_max_global | + class_max_local | + class_max_ident | + class_sendq | class_recvq | + error ';' ; + +class_name: NAME '=' QSTRING ';' +{ + if (conf_parser_ctx.pass == 1) + { + MyFree(yy_class_name); + DupString(yy_class_name, yylval.string); + } +}; + +class_ping_time: PING_TIME '=' timespec ';' +{ + if (conf_parser_ctx.pass == 1) + yy_class->ping_freq = $3; +}; + +class_ping_warning: PING_WARNING '=' timespec ';' +{ + if (conf_parser_ctx.pass == 1) + yy_class->ping_warning = $3; +}; + +class_number_per_ip: NUMBER_PER_IP '=' NUMBER ';' +{ + if (conf_parser_ctx.pass == 1) + yy_class->max_perip = $3; +}; + +class_connectfreq: CONNECTFREQ '=' timespec ';' +{ + if (conf_parser_ctx.pass == 1) + yy_class->con_freq = $3; +}; + +class_max_number: MAX_NUMBER '=' NUMBER ';' +{ + if (conf_parser_ctx.pass == 1) + yy_class->max_total = $3; +}; + +class_max_global: MAX_GLOBAL '=' NUMBER ';' +{ + if (conf_parser_ctx.pass == 1) + yy_class->max_global = $3; +}; + +class_max_local: MAX_LOCAL '=' NUMBER ';' +{ + if (conf_parser_ctx.pass == 1) + yy_class->max_local = $3; +}; + +class_max_ident: MAX_IDENT '=' NUMBER ';' +{ + if (conf_parser_ctx.pass == 1) + yy_class->max_ident = $3; +}; + +class_sendq: SENDQ '=' sizespec ';' +{ + if (conf_parser_ctx.pass == 1) + yy_class->max_sendq = $3; +}; + +class_recvq: T_RECVQ '=' sizespec ';' +{ + if (conf_parser_ctx.pass == 1) + if ($3 >= CLIENT_FLOOD_MIN && $3 <= CLIENT_FLOOD_MAX) + yy_class->max_recvq = $3; +}; + +class_cidr_bitlen_ipv4: CIDR_BITLEN_IPV4 '=' NUMBER ';' +{ + if (conf_parser_ctx.pass == 1) + yy_class->cidr_bitlen_ipv4 = $3 > 32 ? 32 : $3; +}; + +class_cidr_bitlen_ipv6: CIDR_BITLEN_IPV6 '=' NUMBER ';' +{ + if (conf_parser_ctx.pass == 1) + yy_class->cidr_bitlen_ipv6 = $3 > 128 ? 128 : $3; +}; + +class_number_per_cidr: NUMBER_PER_CIDR '=' NUMBER ';' +{ + if (conf_parser_ctx.pass == 1) + yy_class->number_per_cidr = $3; +}; + +/*************************************************************************** + * section listen + ***************************************************************************/ +listen_entry: LISTEN +{ + if (conf_parser_ctx.pass == 2) + { + listener_address = NULL; + listener_flags = 0; + } +} '{' listen_items '}' ';' +{ + if (conf_parser_ctx.pass == 2) + { + MyFree(listener_address); + listener_address = NULL; + } +}; + +listen_flags: IRCD_FLAGS +{ + listener_flags = 0; +} '=' listen_flags_items ';'; + +listen_flags_items: listen_flags_items ',' listen_flags_item | listen_flags_item; +listen_flags_item: T_SSL +{ + if (conf_parser_ctx.pass == 2) + listener_flags |= LISTENER_SSL; +} | HIDDEN +{ + if (conf_parser_ctx.pass == 2) + listener_flags |= LISTENER_HIDDEN; +} | T_SERVER +{ + if (conf_parser_ctx.pass == 2) + listener_flags |= LISTENER_SERVER; +}; + + + +listen_items: listen_items listen_item | listen_item; +listen_item: listen_port | listen_flags | listen_address | listen_host | error ';'; + +listen_port: PORT '=' port_items { listener_flags = 0; } ';'; + +port_items: port_items ',' port_item | port_item; + +port_item: NUMBER +{ + if (conf_parser_ctx.pass == 2) + { + if ((listener_flags & LISTENER_SSL)) +#ifdef HAVE_LIBCRYPTO + if (!ServerInfo.server_ctx) +#endif + { + yyerror("SSL not available - port closed"); + break; + } + add_listener($1, listener_address, listener_flags); + } +} | NUMBER TWODOTS NUMBER +{ + if (conf_parser_ctx.pass == 2) + { + int i; + + if ((listener_flags & LISTENER_SSL)) +#ifdef HAVE_LIBCRYPTO + if (!ServerInfo.server_ctx) +#endif + { + yyerror("SSL not available - port closed"); + break; + } + + for (i = $1; i <= $3; ++i) + add_listener(i, listener_address, listener_flags); + } +}; + +listen_address: IP '=' QSTRING ';' +{ + if (conf_parser_ctx.pass == 2) + { + MyFree(listener_address); + DupString(listener_address, yylval.string); + } +}; + +listen_host: HOST '=' QSTRING ';' +{ + if (conf_parser_ctx.pass == 2) + { + MyFree(listener_address); + DupString(listener_address, yylval.string); + } +}; + +/*************************************************************************** + * section auth + ***************************************************************************/ +auth_entry: IRCD_AUTH +{ + if (conf_parser_ctx.pass == 2) + { + yy_conf = make_conf_item(CLIENT_TYPE); + yy_aconf = map_to_conf(yy_conf); + } + else + { + MyFree(class_name); + class_name = NULL; + } +} '{' auth_items '}' ';' +{ + if (conf_parser_ctx.pass == 2) + { + struct CollectItem *yy_tmp = NULL; + dlink_node *ptr = NULL, *next_ptr = NULL; + + if (yy_aconf->user && yy_aconf->host) + { + conf_add_class_to_conf(yy_conf, class_name); + add_conf_by_address(CONF_CLIENT, yy_aconf); + } + else + delete_conf_item(yy_conf); + + /* copy over settings from first struct */ + DLINK_FOREACH_SAFE(ptr, next_ptr, col_conf_list.head) + { + struct AccessItem *new_aconf; + struct ConfItem *new_conf; + + new_conf = make_conf_item(CLIENT_TYPE); + new_aconf = map_to_conf(new_conf); + + yy_tmp = ptr->data; + + assert(yy_tmp->user && yy_tmp->host); + + if (yy_aconf->passwd != NULL) + DupString(new_aconf->passwd, yy_aconf->passwd); + if (yy_conf->name != NULL) + DupString(new_conf->name, yy_conf->name); + if (yy_aconf->passwd != NULL) + DupString(new_aconf->passwd, yy_aconf->passwd); + + new_aconf->flags = yy_aconf->flags; + new_aconf->port = yy_aconf->port; + + DupString(new_aconf->user, yy_tmp->user); + collapse(new_aconf->user); + + DupString(new_aconf->host, yy_tmp->host); + collapse(new_aconf->host); + + conf_add_class_to_conf(new_conf, class_name); + add_conf_by_address(CONF_CLIENT, new_aconf); + dlinkDelete(&yy_tmp->node, &col_conf_list); + free_collect_item(yy_tmp); + } + + MyFree(class_name); + class_name = NULL; + yy_conf = NULL; + yy_aconf = NULL; + } +}; + +auth_items: auth_items auth_item | auth_item; +auth_item: auth_user | auth_passwd | auth_class | auth_flags | + auth_spoof | auth_redir_serv | auth_redir_port | + auth_encrypted | error ';' ; + +auth_user: USER '=' QSTRING ';' +{ + if (conf_parser_ctx.pass == 2) + { + struct CollectItem *yy_tmp = NULL; + struct split_nuh_item nuh; + + nuh.nuhmask = yylval.string; + nuh.nickptr = NULL; + nuh.userptr = userbuf; + nuh.hostptr = hostbuf; + + nuh.nicksize = 0; + nuh.usersize = sizeof(userbuf); + nuh.hostsize = sizeof(hostbuf); + + split_nuh(&nuh); + + if (yy_aconf->user == NULL) + { + DupString(yy_aconf->user, userbuf); + DupString(yy_aconf->host, hostbuf); + } + else + { + yy_tmp = MyMalloc(sizeof(struct CollectItem)); + + DupString(yy_tmp->user, userbuf); + DupString(yy_tmp->host, hostbuf); + + dlinkAdd(yy_tmp, &yy_tmp->node, &col_conf_list); + } + } +}; + +auth_passwd: PASSWORD '=' QSTRING ';' +{ + if (conf_parser_ctx.pass == 2) + { + /* be paranoid */ + if (yy_aconf->passwd != NULL) + memset(yy_aconf->passwd, 0, strlen(yy_aconf->passwd)); + + MyFree(yy_aconf->passwd); + DupString(yy_aconf->passwd, yylval.string); + } +}; + +auth_class: CLASS '=' QSTRING ';' +{ + if (conf_parser_ctx.pass == 2) + { + MyFree(class_name); + DupString(class_name, yylval.string); + } +}; + +auth_encrypted: ENCRYPTED '=' TBOOL ';' +{ + if (conf_parser_ctx.pass == 2) + { + if (yylval.number) + SetConfEncrypted(yy_aconf); + else + ClearConfEncrypted(yy_aconf); + } +}; + +auth_flags: IRCD_FLAGS +{ +} '=' auth_flags_items ';'; + +auth_flags_items: auth_flags_items ',' auth_flags_item | auth_flags_item; +auth_flags_item: SPOOF_NOTICE +{ + if (conf_parser_ctx.pass == 2) + yy_aconf->flags |= CONF_FLAGS_SPOOF_NOTICE; +} | EXCEED_LIMIT +{ + if (conf_parser_ctx.pass == 2) + yy_aconf->flags |= CONF_FLAGS_NOLIMIT; +} | KLINE_EXEMPT +{ + if (conf_parser_ctx.pass == 2) + yy_aconf->flags |= CONF_FLAGS_EXEMPTKLINE; +} | NEED_IDENT +{ + if (conf_parser_ctx.pass == 2) + yy_aconf->flags |= CONF_FLAGS_NEED_IDENTD; +} | CAN_FLOOD +{ + if (conf_parser_ctx.pass == 2) + yy_aconf->flags |= CONF_FLAGS_CAN_FLOOD; +} | NO_TILDE +{ + if (conf_parser_ctx.pass == 2) + yy_aconf->flags |= CONF_FLAGS_NO_TILDE; +} | GLINE_EXEMPT +{ + if (conf_parser_ctx.pass == 2) + yy_aconf->flags |= CONF_FLAGS_EXEMPTGLINE; +} | RESV_EXEMPT +{ + if (conf_parser_ctx.pass == 2) + yy_aconf->flags |= CONF_FLAGS_EXEMPTRESV; +} | NEED_PASSWORD +{ + if (conf_parser_ctx.pass == 2) + yy_aconf->flags |= CONF_FLAGS_NEED_PASSWORD; +}; + +auth_spoof: SPOOF '=' QSTRING ';' +{ + if (conf_parser_ctx.pass == 2) + { + MyFree(yy_conf->name); + + if (strlen(yylval.string) <= HOSTLEN && valid_hostname(yylval.string)) + { + DupString(yy_conf->name, yylval.string); + yy_aconf->flags |= CONF_FLAGS_SPOOF_IP; + } + else + { + ilog(LOG_TYPE_IRCD, "Spoof either is too long or contains invalid characters. Ignoring it."); + yy_conf->name = NULL; + } + } +}; + +auth_redir_serv: REDIRSERV '=' QSTRING ';' +{ + if (conf_parser_ctx.pass == 2) + { + yy_aconf->flags |= CONF_FLAGS_REDIR; + MyFree(yy_conf->name); + DupString(yy_conf->name, yylval.string); + } +}; + +auth_redir_port: REDIRPORT '=' NUMBER ';' +{ + if (conf_parser_ctx.pass == 2) + { + yy_aconf->flags |= CONF_FLAGS_REDIR; + yy_aconf->port = $3; + } +}; + + +/*************************************************************************** + * section resv + ***************************************************************************/ +resv_entry: RESV +{ + if (conf_parser_ctx.pass == 2) + { + MyFree(resv_reason); + resv_reason = NULL; + } +} '{' resv_items '}' ';' +{ + if (conf_parser_ctx.pass == 2) + { + MyFree(resv_reason); + resv_reason = NULL; + } +}; + +resv_items: resv_items resv_item | resv_item; +resv_item: resv_creason | resv_channel | resv_nick | error ';' ; + +resv_creason: REASON '=' QSTRING ';' +{ + if (conf_parser_ctx.pass == 2) + { + MyFree(resv_reason); + DupString(resv_reason, yylval.string); + } +}; + +resv_channel: CHANNEL '=' QSTRING ';' +{ + if (conf_parser_ctx.pass == 2) + { + if (IsChanPrefix(*yylval.string)) + { + char def_reason[] = "No reason"; + + create_channel_resv(yylval.string, resv_reason != NULL ? resv_reason : def_reason, 1); + } + } + /* ignore it for now.. but we really should make a warning if + * its an erroneous name --fl_ */ +}; + +resv_nick: NICK '=' QSTRING ';' +{ + if (conf_parser_ctx.pass == 2) + { + char def_reason[] = "No reason"; + + create_nick_resv(yylval.string, resv_reason != NULL ? resv_reason : def_reason, 1); + } +}; + +/*************************************************************************** + * section service + ***************************************************************************/ +service_entry: T_SERVICE '{' service_items '}' ';'; + +service_items: service_items service_item | service_item; +service_item: service_name | error; + +service_name: NAME '=' QSTRING ';' +{ + if (conf_parser_ctx.pass == 2) + { + if (valid_servname(yylval.string)) + { + yy_conf = make_conf_item(SERVICE_TYPE); + DupString(yy_conf->name, yylval.string); + } + } +}; + +/*************************************************************************** + * section shared, for sharing remote klines etc. + ***************************************************************************/ +shared_entry: T_SHARED +{ + if (conf_parser_ctx.pass == 2) + { + yy_conf = make_conf_item(ULINE_TYPE); + yy_match_item = map_to_conf(yy_conf); + yy_match_item->action = SHARED_ALL; + } +} '{' shared_items '}' ';' +{ + if (conf_parser_ctx.pass == 2) + { + yy_conf = NULL; + } +}; + +shared_items: shared_items shared_item | shared_item; +shared_item: shared_name | shared_user | shared_type | error ';' ; + +shared_name: NAME '=' QSTRING ';' +{ + if (conf_parser_ctx.pass == 2) + { + MyFree(yy_conf->name); + DupString(yy_conf->name, yylval.string); + } +}; + +shared_user: USER '=' QSTRING ';' +{ + if (conf_parser_ctx.pass == 2) + { + struct split_nuh_item nuh; + + nuh.nuhmask = yylval.string; + nuh.nickptr = NULL; + nuh.userptr = userbuf; + nuh.hostptr = hostbuf; + + nuh.nicksize = 0; + nuh.usersize = sizeof(userbuf); + nuh.hostsize = sizeof(hostbuf); + + split_nuh(&nuh); + + DupString(yy_match_item->user, userbuf); + DupString(yy_match_item->host, hostbuf); + } +}; + +shared_type: TYPE +{ + if (conf_parser_ctx.pass == 2) + yy_match_item->action = 0; +} '=' shared_types ';' ; + +shared_types: shared_types ',' shared_type_item | shared_type_item; +shared_type_item: KLINE +{ + if (conf_parser_ctx.pass == 2) + yy_match_item->action |= SHARED_KLINE; +} | UNKLINE +{ + if (conf_parser_ctx.pass == 2) + yy_match_item->action |= SHARED_UNKLINE; +} | T_DLINE +{ + if (conf_parser_ctx.pass == 2) + yy_match_item->action |= SHARED_DLINE; +} | T_UNDLINE +{ + if (conf_parser_ctx.pass == 2) + yy_match_item->action |= SHARED_UNDLINE; +} | XLINE +{ + if (conf_parser_ctx.pass == 2) + yy_match_item->action |= SHARED_XLINE; +} | T_UNXLINE +{ + if (conf_parser_ctx.pass == 2) + yy_match_item->action |= SHARED_UNXLINE; +} | RESV +{ + if (conf_parser_ctx.pass == 2) + yy_match_item->action |= SHARED_RESV; +} | T_UNRESV +{ + if (conf_parser_ctx.pass == 2) + yy_match_item->action |= SHARED_UNRESV; +} | T_LOCOPS +{ + if (conf_parser_ctx.pass == 2) + yy_match_item->action |= SHARED_LOCOPS; +} | T_ALL +{ + if (conf_parser_ctx.pass == 2) + yy_match_item->action = SHARED_ALL; +}; + +/*************************************************************************** + * section cluster + ***************************************************************************/ +cluster_entry: T_CLUSTER +{ + if (conf_parser_ctx.pass == 2) + { + yy_conf = make_conf_item(CLUSTER_TYPE); + yy_conf->flags = SHARED_ALL; + } +} '{' cluster_items '}' ';' +{ + if (conf_parser_ctx.pass == 2) + { + if (yy_conf->name == NULL) + DupString(yy_conf->name, "*"); + yy_conf = NULL; + } +}; + +cluster_items: cluster_items cluster_item | cluster_item; +cluster_item: cluster_name | cluster_type | error ';' ; + +cluster_name: NAME '=' QSTRING ';' +{ + if (conf_parser_ctx.pass == 2) + DupString(yy_conf->name, yylval.string); +}; + +cluster_type: TYPE +{ + if (conf_parser_ctx.pass == 2) + yy_conf->flags = 0; +} '=' cluster_types ';' ; + +cluster_types: cluster_types ',' cluster_type_item | cluster_type_item; +cluster_type_item: KLINE +{ + if (conf_parser_ctx.pass == 2) + yy_conf->flags |= SHARED_KLINE; +} | UNKLINE +{ + if (conf_parser_ctx.pass == 2) + yy_conf->flags |= SHARED_UNKLINE; +} | T_DLINE +{ + if (conf_parser_ctx.pass == 2) + yy_conf->flags |= SHARED_DLINE; +} | T_UNDLINE +{ + if (conf_parser_ctx.pass == 2) + yy_conf->flags |= SHARED_UNDLINE; +} | XLINE +{ + if (conf_parser_ctx.pass == 2) + yy_conf->flags |= SHARED_XLINE; +} | T_UNXLINE +{ + if (conf_parser_ctx.pass == 2) + yy_conf->flags |= SHARED_UNXLINE; +} | RESV +{ + if (conf_parser_ctx.pass == 2) + yy_conf->flags |= SHARED_RESV; +} | T_UNRESV +{ + if (conf_parser_ctx.pass == 2) + yy_conf->flags |= SHARED_UNRESV; +} | T_LOCOPS +{ + if (conf_parser_ctx.pass == 2) + yy_conf->flags |= SHARED_LOCOPS; +} | T_ALL +{ + if (conf_parser_ctx.pass == 2) + yy_conf->flags = SHARED_ALL; +}; + +/*************************************************************************** + * section connect + ***************************************************************************/ +connect_entry: CONNECT +{ + if (conf_parser_ctx.pass == 2) + { + yy_conf = make_conf_item(SERVER_TYPE); + yy_aconf = map_to_conf(yy_conf); + + /* defaults */ + yy_aconf->port = PORTNUM; + } + else + { + MyFree(class_name); + class_name = NULL; + } +} '{' connect_items '}' ';' +{ + if (conf_parser_ctx.pass == 2) + { + if (yy_aconf->host && yy_aconf->passwd && yy_aconf->spasswd) + { + if (conf_add_server(yy_conf, class_name) == -1) + delete_conf_item(yy_conf); + } + else + { + if (yy_conf->name != NULL) + { + if (yy_aconf->host == NULL) + yyerror("Ignoring connect block -- missing host"); + else if (!yy_aconf->passwd || !yy_aconf->spasswd) + yyerror("Ignoring connect block -- missing password"); + } + + /* XXX + * This fixes a try_connections() core (caused by invalid class_ptr + * pointers) reported by metalrock. That's an ugly fix, but there + * is currently no better way. The entire config subsystem needs an + * rewrite ASAP. make_conf_item() shouldn't really add things onto + * a doubly linked list immediately without any sanity checks! -Michael + */ + delete_conf_item(yy_conf); + } + + MyFree(class_name); + class_name = NULL; + yy_conf = NULL; + yy_aconf = NULL; + } +}; + +connect_items: connect_items connect_item | connect_item; +connect_item: connect_name | connect_host | connect_vhost | + connect_send_password | connect_accept_password | + connect_aftype | connect_port | connect_ssl_cipher_list | + connect_flags | connect_hub_mask | connect_leaf_mask | + connect_class | connect_encrypted | + error ';' ; + +connect_name: NAME '=' QSTRING ';' +{ + if (conf_parser_ctx.pass == 2) + { + MyFree(yy_conf->name); + DupString(yy_conf->name, yylval.string); + } +}; + +connect_host: HOST '=' QSTRING ';' +{ + if (conf_parser_ctx.pass == 2) + { + MyFree(yy_aconf->host); + DupString(yy_aconf->host, yylval.string); + } +}; + +connect_vhost: VHOST '=' QSTRING ';' +{ + if (conf_parser_ctx.pass == 2) + { + struct addrinfo hints, *res; + + memset(&hints, 0, sizeof(hints)); + + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST; + + if (getaddrinfo(yylval.string, NULL, &hints, &res)) + ilog(LOG_TYPE_IRCD, "Invalid netmask for server vhost(%s)", yylval.string); + else + { + assert(res != NULL); + + memcpy(&yy_aconf->bind, res->ai_addr, res->ai_addrlen); + yy_aconf->bind.ss.ss_family = res->ai_family; + yy_aconf->bind.ss_len = res->ai_addrlen; + freeaddrinfo(res); + } + } +}; + +connect_send_password: SEND_PASSWORD '=' QSTRING ';' +{ + if (conf_parser_ctx.pass == 2) + { + if ($3[0] == ':') + yyerror("Server passwords cannot begin with a colon"); + else if (strchr($3, ' ') != NULL) + yyerror("Server passwords cannot contain spaces"); + else { + if (yy_aconf->spasswd != NULL) + memset(yy_aconf->spasswd, 0, strlen(yy_aconf->spasswd)); + + MyFree(yy_aconf->spasswd); + DupString(yy_aconf->spasswd, yylval.string); + } + } +}; + +connect_accept_password: ACCEPT_PASSWORD '=' QSTRING ';' +{ + if (conf_parser_ctx.pass == 2) + { + if ($3[0] == ':') + yyerror("Server passwords cannot begin with a colon"); + else if (strchr($3, ' ') != NULL) + yyerror("Server passwords cannot contain spaces"); + else { + if (yy_aconf->passwd != NULL) + memset(yy_aconf->passwd, 0, strlen(yy_aconf->passwd)); + + MyFree(yy_aconf->passwd); + DupString(yy_aconf->passwd, yylval.string); + } + } +}; + +connect_port: PORT '=' NUMBER ';' +{ + if (conf_parser_ctx.pass == 2) + yy_aconf->port = $3; +}; + +connect_aftype: AFTYPE '=' T_IPV4 ';' +{ + if (conf_parser_ctx.pass == 2) + yy_aconf->aftype = AF_INET; +} | AFTYPE '=' T_IPV6 ';' +{ +#ifdef IPV6 + if (conf_parser_ctx.pass == 2) + yy_aconf->aftype = AF_INET6; +#endif +}; + +connect_flags: IRCD_FLAGS +{ +} '=' connect_flags_items ';'; + +connect_flags_items: connect_flags_items ',' connect_flags_item | connect_flags_item; +connect_flags_item: AUTOCONN +{ + if (conf_parser_ctx.pass == 2) + SetConfAllowAutoConn(yy_aconf); +} | T_SSL +{ + if (conf_parser_ctx.pass == 2) + SetConfSSL(yy_aconf); +}; + +connect_encrypted: ENCRYPTED '=' TBOOL ';' +{ + if (conf_parser_ctx.pass == 2) + { + if (yylval.number) + yy_aconf->flags |= CONF_FLAGS_ENCRYPTED; + else + yy_aconf->flags &= ~CONF_FLAGS_ENCRYPTED; + } +}; + +connect_hub_mask: HUB_MASK '=' QSTRING ';' +{ + if (conf_parser_ctx.pass == 2) + { + char *mask; + + DupString(mask, yylval.string); + dlinkAdd(mask, make_dlink_node(), &yy_aconf->hub_list); + } +}; + +connect_leaf_mask: LEAF_MASK '=' QSTRING ';' +{ + if (conf_parser_ctx.pass == 2) + { + char *mask; + + DupString(mask, yylval.string); + dlinkAdd(mask, make_dlink_node(), &yy_aconf->leaf_list); + } +}; + +connect_class: CLASS '=' QSTRING ';' +{ + if (conf_parser_ctx.pass == 2) + { + MyFree(class_name); + DupString(class_name, yylval.string); + } +}; + +connect_ssl_cipher_list: T_SSL_CIPHER_LIST '=' QSTRING ';' +{ +#ifdef HAVE_LIBCRYPTO + if (conf_parser_ctx.pass == 2) + { + MyFree(yy_aconf->cipher_list); + DupString(yy_aconf->cipher_list, yylval.string); + } +#else + if (conf_parser_ctx.pass == 2) + yyerror("Ignoring connect::ciphers -- no OpenSSL support"); +#endif +}; + + +/*************************************************************************** + * section kill + ***************************************************************************/ +kill_entry: KILL +{ + if (conf_parser_ctx.pass == 2) + { + userbuf[0] = hostbuf[0] = reasonbuf[0] = '\0'; + regex_ban = 0; + } +} '{' kill_items '}' ';' +{ + if (conf_parser_ctx.pass == 2) + { + if (userbuf[0] && hostbuf[0]) + { + if (regex_ban) + { +#ifdef HAVE_LIBPCRE + void *exp_user = NULL; + void *exp_host = NULL; + const char *errptr = NULL; + + if (!(exp_user = ircd_pcre_compile(userbuf, &errptr)) || + !(exp_host = ircd_pcre_compile(hostbuf, &errptr))) + { + ilog(LOG_TYPE_IRCD, "Failed to add regular expression based K-Line: %s", + errptr); + break; + } + + yy_aconf = map_to_conf(make_conf_item(RKLINE_TYPE)); + yy_aconf->regexuser = exp_user; + yy_aconf->regexhost = exp_host; + + DupString(yy_aconf->user, userbuf); + DupString(yy_aconf->host, hostbuf); + + if (reasonbuf[0]) + DupString(yy_aconf->reason, reasonbuf); + else + DupString(yy_aconf->reason, "No reason"); +#else + ilog(LOG_TYPE_IRCD, "Failed to add regular expression based K-Line: no PCRE support"); + break; +#endif + } + else + { + find_and_delete_temporary(userbuf, hostbuf, CONF_KLINE); + + yy_aconf = map_to_conf(make_conf_item(KLINE_TYPE)); + + DupString(yy_aconf->user, userbuf); + DupString(yy_aconf->host, hostbuf); + + if (reasonbuf[0]) + DupString(yy_aconf->reason, reasonbuf); + else + DupString(yy_aconf->reason, "No reason"); + add_conf_by_address(CONF_KLINE, yy_aconf); + } + } + + yy_aconf = NULL; + } +}; + +kill_type: TYPE +{ +} '=' kill_type_items ';'; + +kill_type_items: kill_type_items ',' kill_type_item | kill_type_item; +kill_type_item: REGEX_T +{ + if (conf_parser_ctx.pass == 2) + regex_ban = 1; +}; + +kill_items: kill_items kill_item | kill_item; +kill_item: kill_user | kill_reason | kill_type | error; + +kill_user: USER '=' QSTRING ';' +{ + if (conf_parser_ctx.pass == 2) + { + struct split_nuh_item nuh; + + nuh.nuhmask = yylval.string; + nuh.nickptr = NULL; + nuh.userptr = userbuf; + nuh.hostptr = hostbuf; + + nuh.nicksize = 0; + nuh.usersize = sizeof(userbuf); + nuh.hostsize = sizeof(hostbuf); + + split_nuh(&nuh); + } +}; + +kill_reason: REASON '=' QSTRING ';' +{ + if (conf_parser_ctx.pass == 2) + strlcpy(reasonbuf, yylval.string, sizeof(reasonbuf)); +}; + +/*************************************************************************** + * section deny + ***************************************************************************/ +deny_entry: DENY +{ + if (conf_parser_ctx.pass == 2) + hostbuf[0] = reasonbuf[0] = '\0'; +} '{' deny_items '}' ';' +{ + if (conf_parser_ctx.pass == 2) + { + if (hostbuf[0] && parse_netmask(hostbuf, NULL, NULL) != HM_HOST) + { + find_and_delete_temporary(NULL, hostbuf, CONF_DLINE); + + yy_aconf = map_to_conf(make_conf_item(DLINE_TYPE)); + DupString(yy_aconf->host, hostbuf); + + if (reasonbuf[0]) + DupString(yy_aconf->reason, reasonbuf); + else + DupString(yy_aconf->reason, "No reason"); + add_conf_by_address(CONF_DLINE, yy_aconf); + yy_aconf = NULL; + } + } +}; + +deny_items: deny_items deny_item | deny_item; +deny_item: deny_ip | deny_reason | error; + +deny_ip: IP '=' QSTRING ';' +{ + if (conf_parser_ctx.pass == 2) + strlcpy(hostbuf, yylval.string, sizeof(hostbuf)); +}; + +deny_reason: REASON '=' QSTRING ';' +{ + if (conf_parser_ctx.pass == 2) + strlcpy(reasonbuf, yylval.string, sizeof(reasonbuf)); +}; + +/*************************************************************************** + * section exempt + ***************************************************************************/ +exempt_entry: EXEMPT '{' exempt_items '}' ';'; + +exempt_items: exempt_items exempt_item | exempt_item; +exempt_item: exempt_ip | error; + +exempt_ip: IP '=' QSTRING ';' +{ + if (conf_parser_ctx.pass == 2) + { + if (yylval.string[0] && parse_netmask(yylval.string, NULL, NULL) != HM_HOST) + { + yy_aconf = map_to_conf(make_conf_item(EXEMPTDLINE_TYPE)); + DupString(yy_aconf->host, yylval.string); + + add_conf_by_address(CONF_EXEMPTDLINE, yy_aconf); + yy_aconf = NULL; + } + } +}; + +/*************************************************************************** + * section gecos + ***************************************************************************/ +gecos_entry: GECOS +{ + if (conf_parser_ctx.pass == 2) + { + regex_ban = 0; + reasonbuf[0] = gecos_name[0] = '\0'; + } +} '{' gecos_items '}' ';' +{ + if (conf_parser_ctx.pass == 2) + { + if (gecos_name[0]) + { + if (regex_ban) + { +#ifdef HAVE_LIBPCRE + void *exp_p = NULL; + const char *errptr = NULL; + + if (!(exp_p = ircd_pcre_compile(gecos_name, &errptr))) + { + ilog(LOG_TYPE_IRCD, "Failed to add regular expression based X-Line: %s", + errptr); + break; + } + + yy_conf = make_conf_item(RXLINE_TYPE); + yy_conf->regexpname = exp_p; +#else + ilog(LOG_TYPE_IRCD, "Failed to add regular expression based X-Line: no PCRE support"); + break; +#endif + } + else + yy_conf = make_conf_item(XLINE_TYPE); + + yy_match_item = map_to_conf(yy_conf); + DupString(yy_conf->name, gecos_name); + + if (reasonbuf[0]) + DupString(yy_match_item->reason, reasonbuf); + else + DupString(yy_match_item->reason, "No reason"); + } + } +}; + +gecos_flags: TYPE +{ +} '=' gecos_flags_items ';'; + +gecos_flags_items: gecos_flags_items ',' gecos_flags_item | gecos_flags_item; +gecos_flags_item: REGEX_T +{ + if (conf_parser_ctx.pass == 2) + regex_ban = 1; +}; + +gecos_items: gecos_items gecos_item | gecos_item; +gecos_item: gecos_name | gecos_reason | gecos_flags | error; + +gecos_name: NAME '=' QSTRING ';' +{ + if (conf_parser_ctx.pass == 2) + strlcpy(gecos_name, yylval.string, sizeof(gecos_name)); +}; + +gecos_reason: REASON '=' QSTRING ';' +{ + if (conf_parser_ctx.pass == 2) + strlcpy(reasonbuf, yylval.string, sizeof(reasonbuf)); +}; + +/*************************************************************************** + * section general + ***************************************************************************/ +general_entry: GENERAL + '{' general_items '}' ';'; + +general_items: general_items general_item | general_item; +general_item: general_hide_spoof_ips | general_ignore_bogus_ts | + general_failed_oper_notice | general_anti_nick_flood | + general_max_nick_time | general_max_nick_changes | + general_max_accept | general_anti_spam_exit_message_time | + general_ts_warn_delta | general_ts_max_delta | + general_kill_chase_time_limit | + general_invisible_on_connect | + general_warn_no_nline | general_dots_in_ident | + general_stats_o_oper_only | general_stats_k_oper_only | + general_pace_wait | general_stats_i_oper_only | + general_pace_wait_simple | general_stats_P_oper_only | + general_short_motd | general_no_oper_flood | + general_true_no_oper_flood | general_oper_pass_resv | + general_message_locale | + general_oper_only_umodes | general_max_targets | + general_use_egd | general_egdpool_path | + general_oper_umodes | general_caller_id_wait | + general_opers_bypass_callerid | general_default_floodcount | + general_min_nonwildcard | general_min_nonwildcard_simple | + general_disable_remote_commands | + general_throttle_time | general_havent_read_conf | + general_ping_cookie | + general_disable_auth | + general_tkline_expire_notices | general_gline_enable | + general_gline_duration | general_gline_request_duration | + general_gline_min_cidr | + general_gline_min_cidr6 | + general_stats_e_disabled | + general_max_watch | general_services_name | + error; + + +general_max_watch: MAX_WATCH '=' NUMBER ';' +{ + ConfigFileEntry.max_watch = $3; +}; + +general_gline_enable: GLINE_ENABLE '=' TBOOL ';' +{ + if (conf_parser_ctx.pass == 2) + ConfigFileEntry.glines = yylval.number; +}; + +general_gline_duration: GLINE_DURATION '=' timespec ';' +{ + if (conf_parser_ctx.pass == 2) + ConfigFileEntry.gline_time = $3; +}; + +general_gline_request_duration: GLINE_REQUEST_DURATION '=' timespec ';' +{ + if (conf_parser_ctx.pass == 2) + ConfigFileEntry.gline_request_time = $3; +}; + +general_gline_min_cidr: GLINE_MIN_CIDR '=' NUMBER ';' +{ + ConfigFileEntry.gline_min_cidr = $3; +}; + +general_gline_min_cidr6: GLINE_MIN_CIDR6 '=' NUMBER ';' +{ + ConfigFileEntry.gline_min_cidr6 = $3; +}; + +general_tkline_expire_notices: TKLINE_EXPIRE_NOTICES '=' TBOOL ';' +{ + ConfigFileEntry.tkline_expire_notices = yylval.number; +}; + +general_kill_chase_time_limit: KILL_CHASE_TIME_LIMIT '=' timespec ';' +{ + ConfigFileEntry.kill_chase_time_limit = $3; +}; + +general_hide_spoof_ips: HIDE_SPOOF_IPS '=' TBOOL ';' +{ + ConfigFileEntry.hide_spoof_ips = yylval.number; +}; + +general_ignore_bogus_ts: IGNORE_BOGUS_TS '=' TBOOL ';' +{ + ConfigFileEntry.ignore_bogus_ts = yylval.number; +}; + +general_disable_remote_commands: DISABLE_REMOTE_COMMANDS '=' TBOOL ';' +{ + ConfigFileEntry.disable_remote = yylval.number; +}; + +general_failed_oper_notice: FAILED_OPER_NOTICE '=' TBOOL ';' +{ + ConfigFileEntry.failed_oper_notice = yylval.number; +}; + +general_anti_nick_flood: ANTI_NICK_FLOOD '=' TBOOL ';' +{ + ConfigFileEntry.anti_nick_flood = yylval.number; +}; + +general_max_nick_time: MAX_NICK_TIME '=' timespec ';' +{ + ConfigFileEntry.max_nick_time = $3; +}; + +general_max_nick_changes: MAX_NICK_CHANGES '=' NUMBER ';' +{ + ConfigFileEntry.max_nick_changes = $3; +}; + +general_max_accept: MAX_ACCEPT '=' NUMBER ';' +{ + ConfigFileEntry.max_accept = $3; +}; + +general_anti_spam_exit_message_time: ANTI_SPAM_EXIT_MESSAGE_TIME '=' timespec ';' +{ + ConfigFileEntry.anti_spam_exit_message_time = $3; +}; + +general_ts_warn_delta: TS_WARN_DELTA '=' timespec ';' +{ + ConfigFileEntry.ts_warn_delta = $3; +}; + +general_ts_max_delta: TS_MAX_DELTA '=' timespec ';' +{ + if (conf_parser_ctx.pass == 2) + ConfigFileEntry.ts_max_delta = $3; +}; + +general_havent_read_conf: HAVENT_READ_CONF '=' NUMBER ';' +{ + if (($3 > 0) && conf_parser_ctx.pass == 1) + { + ilog(LOG_TYPE_IRCD, "You haven't read your config file properly."); + ilog(LOG_TYPE_IRCD, "There is a line in the example conf that will kill your server if not removed."); + ilog(LOG_TYPE_IRCD, "Consider actually reading/editing the conf file, and removing this line."); + exit(0); + } +}; + +general_invisible_on_connect: INVISIBLE_ON_CONNECT '=' TBOOL ';' +{ + ConfigFileEntry.invisible_on_connect = yylval.number; +}; + +general_warn_no_nline: WARN_NO_NLINE '=' TBOOL ';' +{ + ConfigFileEntry.warn_no_nline = yylval.number; +}; + +general_stats_e_disabled: STATS_E_DISABLED '=' TBOOL ';' +{ + ConfigFileEntry.stats_e_disabled = yylval.number; +}; + +general_stats_o_oper_only: STATS_O_OPER_ONLY '=' TBOOL ';' +{ + ConfigFileEntry.stats_o_oper_only = yylval.number; +}; + +general_stats_P_oper_only: STATS_P_OPER_ONLY '=' TBOOL ';' +{ + ConfigFileEntry.stats_P_oper_only = yylval.number; +}; + +general_stats_k_oper_only: STATS_K_OPER_ONLY '=' TBOOL ';' +{ + ConfigFileEntry.stats_k_oper_only = 2 * yylval.number; +} | STATS_K_OPER_ONLY '=' TMASKED ';' +{ + ConfigFileEntry.stats_k_oper_only = 1; +}; + +general_stats_i_oper_only: STATS_I_OPER_ONLY '=' TBOOL ';' +{ + ConfigFileEntry.stats_i_oper_only = 2 * yylval.number; +} | STATS_I_OPER_ONLY '=' TMASKED ';' +{ + ConfigFileEntry.stats_i_oper_only = 1; +}; + +general_pace_wait: PACE_WAIT '=' timespec ';' +{ + ConfigFileEntry.pace_wait = $3; +}; + +general_caller_id_wait: CALLER_ID_WAIT '=' timespec ';' +{ + ConfigFileEntry.caller_id_wait = $3; +}; + +general_opers_bypass_callerid: OPERS_BYPASS_CALLERID '=' TBOOL ';' +{ + ConfigFileEntry.opers_bypass_callerid = yylval.number; +}; + +general_pace_wait_simple: PACE_WAIT_SIMPLE '=' timespec ';' +{ + ConfigFileEntry.pace_wait_simple = $3; +}; + +general_short_motd: SHORT_MOTD '=' TBOOL ';' +{ + ConfigFileEntry.short_motd = yylval.number; +}; + +general_no_oper_flood: NO_OPER_FLOOD '=' TBOOL ';' +{ + ConfigFileEntry.no_oper_flood = yylval.number; +}; + +general_true_no_oper_flood: TRUE_NO_OPER_FLOOD '=' TBOOL ';' +{ + ConfigFileEntry.true_no_oper_flood = yylval.number; +}; + +general_oper_pass_resv: OPER_PASS_RESV '=' TBOOL ';' +{ + ConfigFileEntry.oper_pass_resv = yylval.number; +}; + +general_message_locale: MESSAGE_LOCALE '=' QSTRING ';' +{ + if (conf_parser_ctx.pass == 2) + { + if (strlen(yylval.string) > LOCALE_LENGTH-2) + yylval.string[LOCALE_LENGTH-1] = '\0'; + + set_locale(yylval.string); + } +}; + +general_dots_in_ident: DOTS_IN_IDENT '=' NUMBER ';' +{ + ConfigFileEntry.dots_in_ident = $3; +}; + +general_max_targets: MAX_TARGETS '=' NUMBER ';' +{ + ConfigFileEntry.max_targets = $3; +}; + +general_use_egd: USE_EGD '=' TBOOL ';' +{ + ConfigFileEntry.use_egd = yylval.number; +}; + +general_egdpool_path: EGDPOOL_PATH '=' QSTRING ';' +{ + if (conf_parser_ctx.pass == 2) + { + MyFree(ConfigFileEntry.egdpool_path); + DupString(ConfigFileEntry.egdpool_path, yylval.string); + } +}; + +general_services_name: T_SERVICES_NAME '=' QSTRING ';' +{ + if (conf_parser_ctx.pass == 2 && valid_servname(yylval.string)) + { + MyFree(ConfigFileEntry.service_name); + DupString(ConfigFileEntry.service_name, yylval.string); + } +}; + +general_ping_cookie: PING_COOKIE '=' TBOOL ';' +{ + ConfigFileEntry.ping_cookie = yylval.number; +}; + +general_disable_auth: DISABLE_AUTH '=' TBOOL ';' +{ + ConfigFileEntry.disable_auth = yylval.number; +}; + +general_throttle_time: THROTTLE_TIME '=' timespec ';' +{ + ConfigFileEntry.throttle_time = yylval.number; +}; + +general_oper_umodes: OPER_UMODES +{ + ConfigFileEntry.oper_umodes = 0; +} '=' umode_oitems ';' ; + +umode_oitems: umode_oitems ',' umode_oitem | umode_oitem; +umode_oitem: T_BOTS +{ + ConfigFileEntry.oper_umodes |= UMODE_BOTS; +} | T_CCONN +{ + ConfigFileEntry.oper_umodes |= UMODE_CCONN; +} | T_CCONN_FULL +{ + ConfigFileEntry.oper_umodes |= UMODE_CCONN_FULL; +} | T_DEAF +{ + ConfigFileEntry.oper_umodes |= UMODE_DEAF; +} | T_DEBUG +{ + ConfigFileEntry.oper_umodes |= UMODE_DEBUG; +} | T_FULL +{ + ConfigFileEntry.oper_umodes |= UMODE_FULL; +} | HIDDEN +{ + ConfigFileEntry.oper_umodes |= UMODE_HIDDEN; +} | T_SKILL +{ + ConfigFileEntry.oper_umodes |= UMODE_SKILL; +} | T_NCHANGE +{ + ConfigFileEntry.oper_umodes |= UMODE_NCHANGE; +} | T_REJ +{ + ConfigFileEntry.oper_umodes |= UMODE_REJ; +} | T_UNAUTH +{ + ConfigFileEntry.oper_umodes |= UMODE_UNAUTH; +} | T_SPY +{ + ConfigFileEntry.oper_umodes |= UMODE_SPY; +} | T_EXTERNAL +{ + ConfigFileEntry.oper_umodes |= UMODE_EXTERNAL; +} | T_OPERWALL +{ + ConfigFileEntry.oper_umodes |= UMODE_OPERWALL; +} | T_SERVNOTICE +{ + ConfigFileEntry.oper_umodes |= UMODE_SERVNOTICE; +} | T_INVISIBLE +{ + ConfigFileEntry.oper_umodes |= UMODE_INVISIBLE; +} | T_WALLOP +{ + ConfigFileEntry.oper_umodes |= UMODE_WALLOP; +} | T_SOFTCALLERID +{ + ConfigFileEntry.oper_umodes |= UMODE_SOFTCALLERID; +} | T_CALLERID +{ + ConfigFileEntry.oper_umodes |= UMODE_CALLERID; +} | T_LOCOPS +{ + ConfigFileEntry.oper_umodes |= UMODE_LOCOPS; +}; + +general_oper_only_umodes: OPER_ONLY_UMODES +{ + ConfigFileEntry.oper_only_umodes = 0; +} '=' umode_items ';' ; + +umode_items: umode_items ',' umode_item | umode_item; +umode_item: T_BOTS +{ + ConfigFileEntry.oper_only_umodes |= UMODE_BOTS; +} | T_CCONN +{ + ConfigFileEntry.oper_only_umodes |= UMODE_CCONN; +} | T_CCONN_FULL +{ + ConfigFileEntry.oper_only_umodes |= UMODE_CCONN_FULL; +} | T_DEAF +{ + ConfigFileEntry.oper_only_umodes |= UMODE_DEAF; +} | T_DEBUG +{ + ConfigFileEntry.oper_only_umodes |= UMODE_DEBUG; +} | T_FULL +{ + ConfigFileEntry.oper_only_umodes |= UMODE_FULL; +} | T_SKILL +{ + ConfigFileEntry.oper_only_umodes |= UMODE_SKILL; +} | HIDDEN +{ + ConfigFileEntry.oper_only_umodes |= UMODE_HIDDEN; +} | T_NCHANGE +{ + ConfigFileEntry.oper_only_umodes |= UMODE_NCHANGE; +} | T_REJ +{ + ConfigFileEntry.oper_only_umodes |= UMODE_REJ; +} | T_UNAUTH +{ + ConfigFileEntry.oper_only_umodes |= UMODE_UNAUTH; +} | T_SPY +{ + ConfigFileEntry.oper_only_umodes |= UMODE_SPY; +} | T_EXTERNAL +{ + ConfigFileEntry.oper_only_umodes |= UMODE_EXTERNAL; +} | T_OPERWALL +{ + ConfigFileEntry.oper_only_umodes |= UMODE_OPERWALL; +} | T_SERVNOTICE +{ + ConfigFileEntry.oper_only_umodes |= UMODE_SERVNOTICE; +} | T_INVISIBLE +{ + ConfigFileEntry.oper_only_umodes |= UMODE_INVISIBLE; +} | T_WALLOP +{ + ConfigFileEntry.oper_only_umodes |= UMODE_WALLOP; +} | T_SOFTCALLERID +{ + ConfigFileEntry.oper_only_umodes |= UMODE_SOFTCALLERID; +} | T_CALLERID +{ + ConfigFileEntry.oper_only_umodes |= UMODE_CALLERID; +} | T_LOCOPS +{ + ConfigFileEntry.oper_only_umodes |= UMODE_LOCOPS; +}; + +general_min_nonwildcard: MIN_NONWILDCARD '=' NUMBER ';' +{ + ConfigFileEntry.min_nonwildcard = $3; +}; + +general_min_nonwildcard_simple: MIN_NONWILDCARD_SIMPLE '=' NUMBER ';' +{ + ConfigFileEntry.min_nonwildcard_simple = $3; +}; + +general_default_floodcount: DEFAULT_FLOODCOUNT '=' NUMBER ';' +{ + ConfigFileEntry.default_floodcount = $3; +}; + + +/*************************************************************************** + * section channel + ***************************************************************************/ +channel_entry: CHANNEL + '{' channel_items '}' ';'; + +channel_items: channel_items channel_item | channel_item; +channel_item: channel_max_bans | + channel_knock_delay | channel_knock_delay_channel | + channel_max_chans_per_user | channel_max_chans_per_oper | + channel_quiet_on_ban | channel_default_split_user_count | + channel_default_split_server_count | + channel_no_create_on_split | channel_restrict_channels | + channel_no_join_on_split | + channel_jflood_count | channel_jflood_time | + channel_disable_fake_channels | error; + +channel_disable_fake_channels: DISABLE_FAKE_CHANNELS '=' TBOOL ';' +{ + ConfigChannel.disable_fake_channels = yylval.number; +}; + +channel_restrict_channels: RESTRICT_CHANNELS '=' TBOOL ';' +{ + ConfigChannel.restrict_channels = yylval.number; +}; + +channel_knock_delay: KNOCK_DELAY '=' timespec ';' +{ + ConfigChannel.knock_delay = $3; +}; + +channel_knock_delay_channel: KNOCK_DELAY_CHANNEL '=' timespec ';' +{ + ConfigChannel.knock_delay_channel = $3; +}; + +channel_max_chans_per_user: MAX_CHANS_PER_USER '=' NUMBER ';' +{ + ConfigChannel.max_chans_per_user = $3; +}; + +channel_max_chans_per_oper: MAX_CHANS_PER_OPER '=' NUMBER ';' +{ + ConfigChannel.max_chans_per_oper = $3; +}; + +channel_quiet_on_ban: QUIET_ON_BAN '=' TBOOL ';' +{ + ConfigChannel.quiet_on_ban = yylval.number; +}; + +channel_max_bans: MAX_BANS '=' NUMBER ';' +{ + ConfigChannel.max_bans = $3; +}; + +channel_default_split_user_count: DEFAULT_SPLIT_USER_COUNT '=' NUMBER ';' +{ + ConfigChannel.default_split_user_count = $3; +}; + +channel_default_split_server_count: DEFAULT_SPLIT_SERVER_COUNT '=' NUMBER ';' +{ + ConfigChannel.default_split_server_count = $3; +}; + +channel_no_create_on_split: NO_CREATE_ON_SPLIT '=' TBOOL ';' +{ + ConfigChannel.no_create_on_split = yylval.number; +}; + +channel_no_join_on_split: NO_JOIN_ON_SPLIT '=' TBOOL ';' +{ + ConfigChannel.no_join_on_split = yylval.number; +}; + +channel_jflood_count: JOIN_FLOOD_COUNT '=' NUMBER ';' +{ + GlobalSetOptions.joinfloodcount = yylval.number; +}; + +channel_jflood_time: JOIN_FLOOD_TIME '=' timespec ';' +{ + GlobalSetOptions.joinfloodtime = yylval.number; +}; + +/*************************************************************************** + * section serverhide + ***************************************************************************/ +serverhide_entry: SERVERHIDE + '{' serverhide_items '}' ';'; + +serverhide_items: serverhide_items serverhide_item | serverhide_item; +serverhide_item: serverhide_flatten_links | serverhide_hide_servers | + serverhide_links_delay | + serverhide_hidden | serverhide_hidden_name | + serverhide_hide_server_ips | + error; + +serverhide_flatten_links: FLATTEN_LINKS '=' TBOOL ';' +{ + if (conf_parser_ctx.pass == 2) + ConfigServerHide.flatten_links = yylval.number; +}; + +serverhide_hide_servers: HIDE_SERVERS '=' TBOOL ';' +{ + if (conf_parser_ctx.pass == 2) + ConfigServerHide.hide_servers = yylval.number; +}; + +serverhide_hidden_name: HIDDEN_NAME '=' QSTRING ';' +{ + if (conf_parser_ctx.pass == 2) + { + MyFree(ConfigServerHide.hidden_name); + DupString(ConfigServerHide.hidden_name, yylval.string); + } +}; + +serverhide_links_delay: LINKS_DELAY '=' timespec ';' +{ + if (conf_parser_ctx.pass == 2) + { + if (($3 > 0) && ConfigServerHide.links_disabled == 1) + { + eventAddIsh("write_links_file", write_links_file, NULL, $3); + ConfigServerHide.links_disabled = 0; + } + + ConfigServerHide.links_delay = $3; + } +}; + +serverhide_hidden: HIDDEN '=' TBOOL ';' +{ + if (conf_parser_ctx.pass == 2) + ConfigServerHide.hidden = yylval.number; +}; + +serverhide_hide_server_ips: HIDE_SERVER_IPS '=' TBOOL ';' +{ + if (conf_parser_ctx.pass == 2) + ConfigServerHide.hide_server_ips = yylval.number; +}; diff --git a/src/csvlib.c b/src/csvlib.c new file mode 100644 index 0000000..0b6034d --- /dev/null +++ b/src/csvlib.c @@ -0,0 +1,671 @@ +/* + * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd). + * csvlib.c - set of functions to deal with csv type of conf files + * + * Copyright (C) 2003 by Diane Bruce, Stuart Walsh + * Use it anywhere you like, if you like it buy us a beer. + * If it's broken, don't bother us with the lawyers. + * + * $Id$ + */ + +#include "config.h" +#include "stdinc.h" +#include "list.h" +#include "log.h" +#include "conf.h" +#include "hostmask.h" +#include "client.h" +#include "irc_string.h" +#include "sprintf_irc.h" +#include "memory.h" +#include "send.h" +#include "resv.h" +#include "s_serv.h" + +/* Fix "statement not reached" warnings on Sun WorkShop C */ +#ifdef __SUNPRO_C +# pragma error_messages(off, E_STATEMENT_NOT_REACHED) +#endif + + +static void parse_csv_line(char *, ...); +static int write_csv_line(FILE *, const char *, ...); +static int flush_write(struct Client *, FILE *, FILE *, + const char *, const char *); +static char *getfield(char *); + +int +find_and_delete_temporary(const char *user, const char *host, int type) +{ + struct irc_ssaddr iphost, *piphost; + struct AccessItem *aconf; + int t; + + if ((t = parse_netmask(host, &iphost, NULL)) != HM_HOST) + { +#ifdef IPV6 + if (t == HM_IPV6) + t = AF_INET6; + else +#endif + t = AF_INET; + piphost = &iphost; + } + else + { + t = 0; + piphost = NULL; + } + + if ((aconf = find_conf_by_address(host, piphost, type, t, user, NULL, 0))) + { + if (IsConfTemporary(aconf)) + { + delete_one_address_conf(host, aconf); + return 1; + } + } + + return 0; +} + +/* parse_csv_file() + * + * inputs - FILE pointer + * - type of conf to parse + * output - none + * side effects - + */ +void +parse_csv_file(FILE *file, ConfType conf_type) +{ + struct ConfItem *conf; + struct AccessItem *aconf; + struct MatchItem *match_item; + char *name_field=NULL; + char *user_field=NULL; + char *reason_field=NULL; + char *oper_reason=NULL; + char *host_field=NULL; + char line[IRCD_BUFSIZE]; + char *p; + + while (fgets(line, sizeof(line), file) != NULL) + { + if ((p = strchr(line, '\n')) != NULL) + *p = '\0'; + + if ((line[0] == '\0') || (line[0] == '#')) + continue; + + switch(conf_type) + { + case KLINE_TYPE: + parse_csv_line(line, &user_field, &host_field, &reason_field, NULL); + + find_and_delete_temporary(user_field, host_field, CONF_KLINE); + + conf = make_conf_item(KLINE_TYPE); + aconf = map_to_conf(conf); + + if (host_field != NULL) + DupString(aconf->host, host_field); + if (reason_field != NULL) + DupString(aconf->reason, reason_field); + if (user_field != NULL) + DupString(aconf->user, user_field); + if (aconf->host != NULL) + add_conf_by_address(CONF_KLINE, aconf); + break; + case DLINE_TYPE: + parse_csv_line(line, &host_field, &reason_field, NULL); + + if (host_field && parse_netmask(host_field, NULL, NULL) != HM_HOST) + { + find_and_delete_temporary(NULL, host_field, CONF_DLINE); + + aconf = map_to_conf(make_conf_item(DLINE_TYPE)); + DupString(aconf->host, host_field); + + if (reason_field != NULL) + DupString(aconf->reason, reason_field); + else + DupString(aconf->reason, "No reason"); + add_conf_by_address(CONF_DLINE, aconf); + } + + break; + + case XLINE_TYPE: + parse_csv_line(line, &name_field, &reason_field, &oper_reason, NULL); + conf = make_conf_item(XLINE_TYPE); + match_item = (struct MatchItem *)map_to_conf(conf); + if (name_field != NULL) + DupString(conf->name, name_field); + if (reason_field != NULL) + DupString(match_item->reason, reason_field); + break; + case CRESV_TYPE: + parse_csv_line(line, &name_field, &reason_field, NULL); + (void)create_channel_resv(name_field, reason_field, 0); + break; + + case NRESV_TYPE: + parse_csv_line(line, &name_field, &reason_field, NULL); + (void)create_nick_resv(name_field, reason_field, 0); + break; + + case GLINE_TYPE: + case CONF_TYPE: + case OPER_TYPE: + case CLIENT_TYPE: + case SERVER_TYPE: + case CLUSTER_TYPE: + case HUB_TYPE: + case LEAF_TYPE: + case ULINE_TYPE: + case EXEMPTDLINE_TYPE: + case CLASS_TYPE: + default: + break; + } + } +} + +/* + * parse_csv_line() + * + * inputs - pointer to line to parse + * output - + * side effects - + */ + +static void +parse_csv_line(char *line, ...) +{ + va_list args; + char **dest; + char *field = NULL; + + va_start(args, line); + + for (; ;) + { + dest = va_arg(args, char **); + if ((dest == NULL) || ((field = getfield(field ? NULL : line)) == NULL)) + { + va_end(args); + return; + } + *dest = field; + } +} + +/* write_conf_line() + * + * inputs - pointer to struct AccessItem + * - string current_date (small date) + * - time_t cur_time + * output - NONE + * side effects - This function takes care of + * finding right conf file, writing + * the right lines to this file, + * notifying the oper that their kline/dline etc. is in place + * notifying the opers on the server about the k/d etc. line + * + * - Dianora + */ +void +write_conf_line(struct Client *source_p, struct ConfItem *conf, + const char *current_date, time_t cur_time) +{ + FILE *out; + const char *filename, *from, *to; + struct AccessItem *aconf; + struct MatchItem *xconf; + struct ResvChannel *cresv_p=NULL; + struct MatchItem *nresv_p=NULL; + ConfType type; + + type = conf->type; + filename = get_conf_name(type); + + if (!MyConnect(source_p) && IsCapable(source_p->from, CAP_TS6) && HasID(source_p)) + { + from = me.id; + to = source_p->id; + } + else + { + from = me.name; + to = source_p->name; + } + + if ((out = fopen(filename, "a")) == NULL) + { + sendto_realops_flags(UMODE_ALL, L_ALL, + "*** Problem opening %s ", filename); + return; + } + + switch(type) + { + case KLINE_TYPE: + aconf = (struct AccessItem *)map_to_conf(conf); + sendto_realops_flags(UMODE_ALL, L_ALL, + "%s added K-Line for [%s@%s] [%s]", + get_oper_name(source_p), + aconf->user, aconf->host, aconf->reason); + sendto_one(source_p, ":%s NOTICE %s :Added K-Line [%s@%s]", + from, to, aconf->user, aconf->host); + ilog(LOG_TYPE_KLINE, "%s added K-Line for [%s@%s] [%s]", + source_p->name, aconf->user, aconf->host, aconf->reason); + write_csv_line(out, "%s%s%s%s%s%s%d", + aconf->user, aconf->host, + aconf->reason, aconf->oper_reason, current_date, + get_oper_name(source_p), cur_time); + break; + case DLINE_TYPE: + aconf = (struct AccessItem *)map_to_conf(conf); + sendto_realops_flags(UMODE_ALL, L_ALL, + "%s added D-Line for [%s] [%s]", + get_oper_name(source_p), aconf->host, aconf->reason); + sendto_one(source_p, ":%s NOTICE %s :Added D-Line [%s] to %s", + from, to, aconf->host, filename); + ilog(LOG_TYPE_DLINE, "%s added D-Line for [%s] [%s]", + get_oper_name(source_p), aconf->host, aconf->reason); + write_csv_line(out, "%s%s%s%s%s%d", + aconf->host, aconf->reason, aconf->oper_reason, + current_date, + get_oper_name(source_p), cur_time); + break; + + case XLINE_TYPE: + xconf = (struct MatchItem *)map_to_conf(conf); + sendto_realops_flags(UMODE_ALL, L_ALL, + "%s added X-Line for [%s] [%s]", + get_oper_name(source_p), conf->name, + xconf->reason); + sendto_one(source_p, + ":%s NOTICE %s :Added X-Line [%s] [%d] [%s] to %s", + from, to, conf->name, + xconf->action, xconf->reason, filename); + ilog(LOG_TYPE_IRCD, "%s added X-Line for [%s] [%s]", + get_oper_name(source_p), conf->name, xconf->reason); + write_csv_line(out, "%s%s%s%s%s%d", + conf->name, xconf->reason, xconf->oper_reason, + current_date, get_oper_name(source_p), cur_time); + break; + case CRESV_TYPE: + cresv_p = (struct ResvChannel *)map_to_conf(conf); + + write_csv_line(out, "%s%s", + cresv_p->name, cresv_p->reason); + break; + + case NRESV_TYPE: + nresv_p = (struct MatchItem *)map_to_conf(conf); + + write_csv_line(out, "%s%s", + conf->name, nresv_p->reason); + break; + + default: + fclose(out); + return; + } + + fclose(out); +} + +/* + * write_csv_line() + * + * inputs - pointer to FILE * + * - formatted string + * output - + * side effects - single line is written to csv conf file + */ +static int +write_csv_line(FILE *out, const char *format, ...) +{ + char c; + size_t bytes = 0; + va_list args; + char tmp[1024]; + char *str = tmp; + const char *null_string = ""; + + if (out == NULL) + return(0); + + va_start(args, format); + + while ((c = *format++)) + { + if (c == '%') + { + c = *format++; + if (c == 's') + { + const char *p1 = va_arg(args, const char *); + if (p1 == NULL) + p1 = null_string; + *str++ = '\"'; + ++bytes; + while (*p1 != '\0') + { + *str++ = *p1++; + ++bytes; + } + *str++ = '\"'; + *str++ = ','; + + bytes += 2; + continue; + } + if (c == 'c') + { + *str++ = '\"'; + ++bytes; + *str++ = (char) va_arg(args, int); + ++bytes; + *str++ = '\"'; + *str++ = ','; + + bytes += 2; + continue; + } + + if (c == 'd') + { + int v = va_arg(args, int); + char t[40]; + char *p=t; + + while (v > 10) + { + *p++ = (v % 10) + '0'; + v = v/10; + } + *p++ = (v % 10) + '0'; + + *str++ = '\"'; + ++bytes; + while (p != t) + { + *str++ = *--p; + ++bytes; + } + + *str++ = '\"'; + *str++ = ','; + bytes += 2; + continue; + } + if (c != '%') + { + int ret; + + format -= 2; + ret = vsprintf(str, format, args); + str += ret; + bytes += ret; + *str++ = ','; + + ++bytes; + break; + } + } + *str++ = c; + ++bytes; + } + + if (*(str-1) == ',') + { + *(str-1) = '\n'; + *str = '\0'; + } + else + { + *str++ = '\n'; + ++bytes; + *str = '\0'; + } + + va_end(args); + str = tmp; + fputs(str, out); + + return(bytes); +} + +/* + * getfield + * + * inputs - input buffer + * output - next field + * side effects - field breakup for ircd.conf file. + */ +static char * +getfield(char *newline) +{ + static char *line = NULL; + char *end, *field; + + if (newline != NULL) + line = newline; + + if (line == NULL) + return(NULL); + + field = line; + + /* skip everything that's not a starting quote */ + for(;;) + { + if (*field == '\0') + return(NULL); + else if (*field == '"') + break; + ++field; + } + + /* skip over the beginning " */ + end = ++field; + + for (;;) + { + /* At end of string, mark it as end and return */ + if ((*end == '\0') || (*end == '\n')) + { + line = NULL; + return(NULL); + } + else if (*end == '\\') /* found escape character ? */ + { + end++; + } + else if (*end == '"') /* found terminating " */ + { + *end++ = '\0'; + line = end; + return(field); + } + + end++; + } + + return (NULL); +} + +/* remove_conf_line() + * + * inputs - type of kline to remove + * - pointer to oper removing + * - pat1 pat2 patterns to match + * output - -1 if unsuccessful 0 if no change 1 if change + * side effects - + */ +int +remove_conf_line(ConfType type, struct Client *source_p, const char *pat1, const char *pat2) +{ + const char *filename; + FILE *in, *out; + int pairme=0; + char buf[IRCD_BUFSIZE], buff[IRCD_BUFSIZE], temppath[IRCD_BUFSIZE]; + char *found1; + char *found2; + int oldumask; + + filename = get_conf_name(type); + + if ((in = fopen(filename, "r")) == NULL) + { + sendto_one(source_p, ":%s NOTICE %s :Cannot open %s", me.name, + source_p->name, filename); + return -1; + } + + ircsprintf(temppath, "%s.tmp", filename); + oldumask = umask(0); + + if ((out = fopen(temppath, "w")) == NULL) + { + sendto_one(source_p, ":%s NOTICE %s :Cannot open %s", me.name, + source_p->name, temppath); + fclose(in); + umask(oldumask); + return -1; + } + + umask(oldumask); + oldumask = umask(0); + + while (fgets(buf, sizeof(buf), in) != NULL) + { + if ((*buf == '\0') || (*buf == '#')) + { + if (flush_write(source_p, in, out, buf, temppath) < 0) + return -1; + } + + /* Keep copy of original line, getfield trashes line as it goes */ + strlcpy(buff, buf, sizeof(buff)); + + if ((found1 = getfield(buff)) == NULL) + { + if (flush_write(source_p, in, out, buf, temppath) < 0) + return -1; + continue; + } + + if (pat2 != NULL) + { + if ((found2 = getfield(NULL)) == NULL) + { + if (flush_write(source_p, in, out, buf, temppath) < 0) + return -1; + continue; + } + + if (!irccmp(pat1, found1) && !irccmp(pat2, found2)) + { + pairme = 1; + continue; + } + else + { + if(flush_write(source_p, in, out, buf, temppath) < 0) + return -1; + continue; + } + } + else + { + if (!irccmp(pat1, found1)) + { + pairme = 1; + continue; + } + else + { + if(flush_write(source_p, in, out, buf, temppath) < 0) + return -1; + continue; + } + } + } + + fclose(in); + fclose(out); + +/* The result of the rename should be checked too... oh well */ +/* If there was an error on a write above, then its been reported + * and I am not going to trash the original kline /conf file + */ + + if (pairme == 0) + { + if(temppath != NULL) + (void)unlink(temppath); + return 0; + } + else + { + (void)rename(temppath, filename); + + /* XXX + * This is a very inefficient way of removing a kline/xline etc. + * This next function call forces a complete re-read of all conf + * files, instead of a re-read of the kline/dline etc. files modified + * But, consider how often an /quote unkline etc. is done compared + * to how often a /quote kline is done. Its not a biggie in + * the grand scheme of things. If it does become a biggie, + * we will rewrite it - Dianora + */ + + rehash(0); + return 1; + } +} + +/* + * flush_write() + * + * inputs - pointer to client structure of oper requesting unkline + * - in is the input file descriptor + * - out is the output file descriptor + * - buf is the buffer to write + * - ntowrite is the expected number of character to be written + * - temppath is the temporary file name to be written + * output - -1 for error on write + * - 0 for ok + * side effects - if successful, the buf is written to output file + * if a write failure happesn, and the file pointed to + * by temppath, if its non NULL, is removed. + * + * The idea here is, to be as robust as possible when writing to the + * kline file. + * + * -Dianora + */ +static int +flush_write(struct Client *source_p, FILE *in, FILE* out, + const char *buf, const char *temppath) +{ + int error_on_write = fputs(buf, out) < 0 ? (-1) : (0); + + if (error_on_write) + { + sendto_one(source_p,":%s NOTICE %s :Unable to write to %s aborting", + me.name, source_p->name, temppath); + if(temppath != NULL) + (void)unlink(temppath); + fclose(in); + fclose(out); + } + + return (error_on_write); +} diff --git a/src/dbuf.c b/src/dbuf.c new file mode 100644 index 0000000..1271b86 --- /dev/null +++ b/src/dbuf.c @@ -0,0 +1,112 @@ +/* + * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd). + * dbuf.c: Supports dynamic data buffers. + * + * Copyright (C) 2002 by the past and present ircd coders, and others. + * + * 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 + * + * $Id$ + */ + +#include "stdinc.h" +#include "list.h" +#include "balloc.h" +#include "dbuf.h" +#include "memory.h" + +static BlockHeap *dbuf_heap; + +void +dbuf_init(void) +{ + dbuf_heap = BlockHeapCreate("dbuf", sizeof(struct dbuf_block), DBUF_HEAP_SIZE); +} + +static struct dbuf_block * +dbuf_alloc(struct dbuf_queue *qptr) +{ + struct dbuf_block *block = BlockHeapAlloc(dbuf_heap); + + dlinkAddTail(block, make_dlink_node(), &qptr->blocks); + return block; +} + +void +dbuf_put(struct dbuf_queue *qptr, char *data, size_t count) +{ + struct dbuf_block *last; + size_t amount; + + assert(count > 0); + if (qptr->blocks.tail == NULL) + dbuf_alloc(qptr); + + do { + last = qptr->blocks.tail->data; + + amount = DBUF_BLOCK_SIZE - last->size; + if (!amount) + { + last = dbuf_alloc(qptr); + amount = DBUF_BLOCK_SIZE; + } + if (amount > count) + amount = count; + + memcpy((void *) &last->data[last->size], data, amount); + count -= amount; + last->size += amount; + qptr->total_size += amount; + + data += amount; + + } while (count > 0); +} + +void +dbuf_delete(struct dbuf_queue *qptr, size_t count) +{ + dlink_node *ptr; + struct dbuf_block *first; + + assert(qptr->total_size >= count); + if (count == 0) + return; + + /* free whole blocks first.. */ + while (1) + { + if (!count) + return; + ptr = qptr->blocks.head; + first = ptr->data; + if (count < first->size) + break; + + qptr->total_size -= first->size; + count -= first->size; + dlinkDelete(ptr, &qptr->blocks); + free_dlink_node(ptr); + BlockHeapFree(dbuf_heap, first); + } + + /* ..then remove data from the beginning of the queue */ + first->size -= count; + qptr->total_size -= count; + memmove((void *) &first->data, (void *) &first->data[count], first->size); +} + diff --git a/src/event.c b/src/event.c new file mode 100644 index 0000000..2ddc75d --- /dev/null +++ b/src/event.c @@ -0,0 +1,292 @@ +/* + * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd). + * event.c: Event functions. + * + * Copyright (C) 1998-2000 Regents of the University of California + * Copyright (C) 2001-2002 Hybrid Development Team + * + * Code borrowed from the squid web cache by Adrian Chadd. + * Original header: + * + * DEBUG: section 41 Event Processing + * AUTHOR: Henrik Nordstrom + * + * SQUID Internet Object Cache http://squid.nlanr.net/Squid/ + * ---------------------------------------------------------- + * + * Squid is the result of efforts by numerous individuals from the + * Internet community. Development is led by Duane Wessels of the + * National Laboratory for Applied Network Research and funded by the + * National Science Foundation. Squid is Copyrighted (C) 1998 by + * the Regents of the University of California. Please see the + * COPYRIGHT file for full details. Squid incorporates software + * developed and/or copyrighted by other sources. Please see the + * CREDITS file for full details. + * + * 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 + * + * $Id$ + */ + +/* + * How it's used: + * + * Should be pretty self-explanatory. Events are added to the static + * array event_table with a frequency time telling eventRun how often + * to execute it. + */ + +#include "stdinc.h" +#include "list.h" +#include "ircd.h" +#include "event.h" +#include "client.h" +#include "send.h" +#include "memory.h" +#include "log.h" +#include "numeric.h" + +static const char *last_event_ran = NULL; +static struct ev_entry event_table[MAX_EVENTS]; +static time_t event_time_min = -1; +static int eventFind(EVH *func, void *arg); + +/* + * void eventAdd(const char *name, EVH *func, void *arg, time_t when) + * + * Input: Name of event, function to call, arguments to pass, and frequency + * of the event. + * Output: None + * Side Effects: Adds the event to the event list. + */ +void +eventAdd(const char *name, EVH *func, void *arg, time_t when) +{ + int i; + + /* find first inactive index, or use next index */ + for (i = 0; i < MAX_EVENTS; i++) + { + if (event_table[i].active == 0) + { + event_table[i].func = func; + event_table[i].name = name; + event_table[i].arg = arg; + event_table[i].when = CurrentTime + when; + event_table[i].frequency = when; + event_table[i].active = 1; + + if ((event_table[i].when < event_time_min) || (event_time_min == -1)) + event_time_min = event_table[i].when; + + return; + } + } + /* XXX if reach here, its an error */ + ilog(LOG_TYPE_IRCD, "Event table is full! (%d)", i); +} + +/* + * void eventDelete(EVH *func, void *arg) + * + * Input: Function handler, argument that was passed. + * Output: None + * Side Effects: Removes the event from the event list + */ +void +eventDelete(EVH *func, void *arg) +{ + int i = eventFind(func, arg); + + if (i == -1) + return; + + event_table[i].name = NULL; + event_table[i].func = NULL; + event_table[i].arg = NULL; + event_table[i].active = 0; +} + +/* + * void eventAddIsh(const char *name, EVH *func, void *arg, time_t delta_isa) + * + * Input: Name of event, function to call, arguments to pass, and frequency + * of the event. + * Output: None + * Side Effects: Adds the event to the event list within +- 1/3 of the + * specified frequency. + */ +void +eventAddIsh(const char *name, EVH *func, void *arg, time_t delta_ish) +{ + if (delta_ish >= 3.0) + { + const time_t two_third = (2 * delta_ish) / 3; + delta_ish = two_third + ((rand() % 1000) * two_third) / 1000; + /* + * XXX I hate the above magic, I don't even know if its right. + * Grr. -- adrian + */ + } + + eventAdd(name, func, arg, delta_ish); +} + +/* + * void eventRun(void) + * + * Input: None + * Output: None + * Side Effects: Runs pending events in the event list + */ +void +eventRun(void) +{ + int i; + + for (i = 0; i < MAX_EVENTS; i++) + { + if (event_table[i].active && (event_table[i].when <= CurrentTime)) + { + last_event_ran = event_table[i].name; + event_table[i].func(event_table[i].arg); + event_table[i].when = CurrentTime + event_table[i].frequency; + event_time_min = -1; + } + } +} + +/* + * time_t eventNextTime(void) + * + * Input: None + * Output: Specifies the next time eventRun() should be run + * Side Effects: None + */ +time_t +eventNextTime(void) +{ + int i; + + if (event_time_min == -1) + { + for (i = 0; i < MAX_EVENTS; i++) + { + if (event_table[i].active && ((event_table[i].when < event_time_min) || (event_time_min == -1))) + event_time_min = event_table[i].when; + } + } + + return(event_time_min); +} + +/* + * void eventInit(void) + * + * Input: None + * Output: None + * Side Effects: Initializes the event system. + */ +void +eventInit(void) +{ + last_event_ran = NULL; + memset(event_table, 0, sizeof(event_table)); +} + +/* + * int eventFind(EVH *func, void *arg) + * + * Input: Event function and the argument passed to it + * Output: Index to the slow in the event_table + * Side Effects: None + */ +static int +eventFind(EVH *func, void *arg) +{ + int i; + + for (i = 0; i < MAX_EVENTS; i++) + { + if ((event_table[i].func == func) && + (event_table[i].arg == arg) && + event_table[i].active) + return(i); + } + + return(-1); +} + +/* + * void show_events(struct Client *source_p) + * + * Input: Client requesting the event + * Output: List of events + * Side Effects: None + */ +void +show_events(struct Client *source_p) +{ + int i; + + if (last_event_ran) + { + sendto_one(source_p, ":%s %d %s :Last event to run: %s", + me.name, RPL_STATSDEBUG, source_p->name, last_event_ran); + sendto_one(source_p, ":%s %d %s : ", + me.name, RPL_STATSDEBUG, source_p->name); + } + + sendto_one(source_p, + ":%s %d %s : Operation Next Execution", + me.name, RPL_STATSDEBUG, source_p->name); + sendto_one(source_p, + ":%s %d %s : -------------------------------------------", + me.name, RPL_STATSDEBUG, source_p->name); + + for (i = 0; i < MAX_EVENTS; i++) + if (event_table[i].active) + { + sendto_one(source_p, ":%s %d %s : %-28s %-4d seconds", + me.name, RPL_STATSDEBUG, source_p->name, + event_table[i].name, + (int)(event_table[i].when - CurrentTime)); + } + + sendto_one(source_p, ":%s %d %s : ", + me.name, RPL_STATSDEBUG, source_p->name); +} + +/* + * void set_back_events(time_t by) + * Input: Time to set back events by. + * Output: None. + * Side-effects: Sets back all events by "by" seconds. + */ +void +set_back_events(time_t by) +{ + int i; + + for (i = 0; i < MAX_EVENTS; i++) + { + if (event_table[i].when > by) + event_table[i].when -= by; + else + event_table[i].when = 0; + } +} + diff --git a/src/fdlist.c b/src/fdlist.c new file mode 100644 index 0000000..5400ad3 --- /dev/null +++ b/src/fdlist.c @@ -0,0 +1,243 @@ +/* + * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd). + * fdlist.c: Maintains a list of file descriptors. + * + * Copyright (C) 2002 by the past and present ircd coders, and others. + * + * 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 + * + * $Id$ + */ + +#include "stdinc.h" +#include "fdlist.h" +#include "client.h" /* struct Client */ +#include "event.h" +#include "ircd.h" /* GlobalSetOptions */ +#include "irc_string.h" +#include "s_bsd.h" /* comm_setselect */ +#include "conf.h" /* ServerInfo */ +#include "send.h" +#include "memory.h" +#include "numeric.h" +#include "s_misc.h" +#include "irc_res.h" + +fde_t *fd_hash[FD_HASH_SIZE]; +fde_t *fd_next_in_loop = NULL; +int number_fd = LEAKED_FDS; +int hard_fdlimit = 0; +struct Callback *fdlimit_cb = NULL; + +static void * +changing_fdlimit(va_list args) +{ + int old_fdlimit = hard_fdlimit; + + hard_fdlimit = va_arg(args, int); + + if (ServerInfo.max_clients > (unsigned int)MAXCLIENTS_MAX) + { + if (old_fdlimit != 0) + sendto_realops_flags(UMODE_ALL, L_ALL, + "HARD_FDLIMIT changed to %d, adjusting MAXCLIENTS to %d", + hard_fdlimit, MAXCLIENTS_MAX); + + ServerInfo.max_clients = MAXCLIENTS_MAX; + } + + return NULL; +} + +void +fdlist_init(void) +{ + memset(&fd_hash, 0, sizeof(fd_hash)); + + fdlimit_cb = register_callback("changing_fdlimit", changing_fdlimit); + eventAddIsh("recalc_fdlimit", recalc_fdlimit, NULL, 58); + recalc_fdlimit(NULL); +} + +void +recalc_fdlimit(void *unused) +{ + int fdmax; + struct rlimit limit; + + if (!getrlimit(RLIMIT_NOFILE, &limit)) + { + limit.rlim_cur = limit.rlim_max; + setrlimit(RLIMIT_NOFILE, &limit); + } + + fdmax = getdtablesize(); + + /* allow MAXCLIENTS_MIN clients even at the cost of MAX_BUFFER and + * some not really LEAKED_FDS */ + fdmax = IRCD_MAX(fdmax, LEAKED_FDS + MAX_BUFFER + MAXCLIENTS_MIN); + + /* under no condition shall this raise over 65536 + * for example user ip heap is sized 2*hard_fdlimit */ + fdmax = IRCD_MIN(fdmax, 65536); + + if (fdmax != hard_fdlimit) + execute_callback(fdlimit_cb, fdmax); +} + +static inline unsigned int +hash_fd(int fd) +{ + return (((unsigned) fd) % FD_HASH_SIZE); +} + +fde_t * +lookup_fd(int fd) +{ + fde_t *F = fd_hash[hash_fd(fd)]; + + while (F) + { + if (F->fd == fd) + return (F); + F = F->hnext; + } + + return (NULL); +} + +/* Called to open a given filedescriptor */ +void +fd_open(fde_t *F, int fd, int is_socket, const char *desc) +{ + unsigned int hashv = hash_fd(fd); + assert(fd >= 0); + + F->fd = fd; + F->comm_index = -1; + if (desc) + strlcpy(F->desc, desc, sizeof(F->desc)); + /* Note: normally we'd have to clear the other flags, + * but currently F is always cleared before calling us.. */ + F->flags.open = 1; + F->flags.is_socket = is_socket; + F->hnext = fd_hash[hashv]; + fd_hash[hashv] = F; + + number_fd++; +} + +/* Called to close a given filedescriptor */ +void +fd_close(fde_t *F) +{ + unsigned int hashv = hash_fd(F->fd); + + if (F == fd_next_in_loop) + fd_next_in_loop = F->hnext; + + if (F->flags.is_socket) + comm_setselect(F, COMM_SELECT_WRITE | COMM_SELECT_READ, NULL, NULL, 0); + + delete_resolver_queries(F); + +#ifdef HAVE_LIBCRYPTO + if (F->ssl) + SSL_free(F->ssl); +#endif + + if (fd_hash[hashv] == F) + fd_hash[hashv] = F->hnext; + else { + fde_t *prev; + + /* let it core if not found */ + for (prev = fd_hash[hashv]; prev->hnext != F; prev = prev->hnext) + ; + prev->hnext = F->hnext; + } + + /* Unlike squid, we're actually closing the FD here! -- adrian */ + close(F->fd); + number_fd--; + + memset(F, 0, sizeof(fde_t)); +} + +/* + * fd_dump() - dump the list of active filedescriptors + */ +void +fd_dump(struct Client *source_p) +{ + int i; + fde_t *F; + + for (i = 0; i < FD_HASH_SIZE; i++) + for (F = fd_hash[i]; F != NULL; F = F->hnext) + sendto_one(source_p, ":%s %d %s :fd %-5d desc '%s'", + me.name, RPL_STATSDEBUG, source_p->name, + F->fd, F->desc); +} + +/* + * fd_note() - set the fd note + * + * Note: must be careful not to overflow fd_table[fd].desc when + * calling. + */ +void +fd_note(fde_t *F, const char *format, ...) +{ + va_list args; + + if (format != NULL) + { + va_start(args, format); + vsnprintf(F->desc, sizeof(F->desc), format, args); + va_end(args); + } + else + F->desc[0] = '\0'; +} + +/* Make sure stdio descriptors (0-2) and profiler descriptor (3) + * always go somewhere harmless. Use -foreground for profiling + * or executing from gdb */ +void +close_standard_fds(void) +{ + int i; + + for (i = 0; i < LOWEST_SAFE_FD; i++) + { + close(i); + if (open("/dev/null", O_RDWR) < 0) + exit(-1); /* we're hosed if we can't even open /dev/null */ + } +} + +void +close_fds(fde_t *one) +{ + int i; + fde_t *F; + + for (i = 0; i < FD_HASH_SIZE; i++) + for (F = fd_hash[i]; F != NULL; F = F->hnext) + if (F != one) + close(F->fd); +} diff --git a/src/getopt.c b/src/getopt.c new file mode 100644 index 0000000..5b863d3 --- /dev/null +++ b/src/getopt.c @@ -0,0 +1,127 @@ +/* + * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd). + * getopt.c: Uses getopt to fetch the command line options. + * + * Copyright (C) 2002 by the past and present ircd coders, and others. + * + * 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 + * + * $Id$ + */ + +#include "stdinc.h" +#include "ircd_getopt.h" + +#define OPTCHAR '-' + + +static void +usage(const char *name, const struct lgetopt *opts) +{ + unsigned int i; + + fprintf(stderr, "Usage: %s [options]\n", name); + fprintf(stderr, "Where valid options are:\n"); + + for (i = 0; opts[i].opt; ++i) + fprintf(stderr, "\t%c%-10s %-20s%s\n", OPTCHAR, opts[i].opt, + (opts[i].argtype == YESNO || opts[i].argtype == USAGE) ? "" : + opts[i].argtype == INTEGER ? "<number>" : "<string>", + opts[i].desc); + + exit(EXIT_FAILURE); +} + +void +parseargs(int *argc, char ***argv, struct lgetopt *opts) +{ + unsigned int i; + const char *progname = (*argv)[0]; + + /* loop through each argument */ + while (1) + { + int found = 0; + + (*argc)--; + (*argv)++; + + if (*argc < 1 || (*argv)[0][0] != OPTCHAR) + return; + + (*argv)[0]++; + + /* search through our argument list, and see if it matches */ + for (i = 0; opts[i].opt; i++) + { + if (!strcmp(opts[i].opt, (*argv)[0])) + { + /* found our argument */ + found = 1; + + switch (opts[i].argtype) + { + case YESNO: + *((int *)opts[i].argloc) = 1; + break; + + case INTEGER: + if (*argc < 2) + { + fprintf(stderr, "Error: option '%c%s' requires an argument\n", + OPTCHAR, opts[i].opt); + usage((*argv)[0], opts); + } + + *((int *)opts[i].argloc) = atoi((*argv)[1]); + (*argc)--; + (*argv)++; + break; + + case STRING: + if (*argc < 2) + { + fprintf(stderr, "error: option '%c%s' requires an argument\n", + OPTCHAR, opts[i].opt); + usage(progname, opts); + } + + *((char**)opts[i].argloc) = malloc(strlen((*argv)[1]) + 1); + strcpy(*((char**)opts[i].argloc), (*argv)[1]); + (*argc)--; + (*argv)++; + break; + + case USAGE: + usage(progname, opts); + /* NOTREACHED */ + + default: + fprintf(stderr, "Error: internal error in parseargs() at %s:%d\n", + __FILE__, __LINE__); + exit(EXIT_FAILURE); + } + } + } + + if (!found) + { + fprintf(stderr, "error: unknown argument '%c%s'\n", + OPTCHAR, (*argv)[0]); + usage(progname, opts); + } + } +} diff --git a/src/hash.c b/src/hash.c new file mode 100644 index 0000000..d0b0a55 --- /dev/null +++ b/src/hash.c @@ -0,0 +1,907 @@ +/* + * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd). + * hash.c: Maintains hashtables. + * + * Copyright (C) 2002 by the past and present ircd coders, and others. + * + * 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 + * + * $Id$ + */ + +#include "stdinc.h" +#include "list.h" +#include "balloc.h" +#include "conf.h" +#include "channel.h" +#include "channel_mode.h" +#include "client.h" +#include "modules.h" +#include "hash.h" +#include "resv.h" +#include "rng_mt.h" +#include "userhost.h" +#include "irc_string.h" +#include "ircd.h" +#include "numeric.h" +#include "send.h" +#include "memory.h" +#include "dbuf.h" +#include "s_user.h" + + +static BlockHeap *userhost_heap = NULL; +static BlockHeap *namehost_heap = NULL; + +static unsigned int hashf_xor_key = 0; + +/* The actual hash tables, They MUST be of the same HASHSIZE, variable + * size tables could be supported but the rehash routine should also + * rebuild the transformation maps, I kept the tables of equal size + * so that I can use one hash function. + */ +static struct Client *idTable[HASHSIZE]; +static struct Client *clientTable[HASHSIZE]; +static struct Channel *channelTable[HASHSIZE]; +static struct UserHost *userhostTable[HASHSIZE]; +static struct ResvChannel *resvchannelTable[HASHSIZE]; + + +/* init_hash() + * + * inputs - NONE + * output - NONE + * side effects - Initialize the maps used by hash + * functions and clear the tables + */ +void +init_hash(void) +{ + /* Default the userhost/namehost sizes to CLIENT_HEAP_SIZE for now, + * should be a good close approximation anyway + * - Dianora + */ + userhost_heap = BlockHeapCreate("userhost", sizeof(struct UserHost), CLIENT_HEAP_SIZE); + namehost_heap = BlockHeapCreate("namehost", sizeof(struct NameHost), CLIENT_HEAP_SIZE); + + hashf_xor_key = genrand_int32() % 256; /* better than nothing --adx */ +} + +/* + * New hash function based on the Fowler/Noll/Vo (FNV) algorithm from + * http://www.isthe.com/chongo/tech/comp/fnv/ + * + * Here, we use the FNV-1 method, which gives slightly better results + * than FNV-1a. -Michael + */ +unsigned int +strhash(const char *name) +{ + const unsigned char *p = (const unsigned char *)name; + unsigned int hval = FNV1_32_INIT; + + if (*p == '\0') + return 0; + for (; *p != '\0'; ++p) + { + hval += (hval << 1) + (hval << 4) + (hval << 7) + + (hval << 8) + (hval << 24); + hval ^= (ToLower(*p) ^ hashf_xor_key); + } + + return (hval >> FNV1_32_BITS) ^ (hval & ((1 << FNV1_32_BITS) - 1)); +} + +/************************** Externally visible functions ********************/ + +/* Optimization note: in these functions I supposed that the CSE optimization + * (Common Subexpression Elimination) does its work decently, this means that + * I avoided introducing new variables to do the work myself and I did let + * the optimizer play with more free registers, actual tests proved this + * solution to be faster than doing things like tmp2=tmp->hnext... and then + * use tmp2 myself which would have given less freedom to the optimizer. + */ + +/* hash_add_client() + * + * inputs - pointer to client + * output - NONE + * side effects - Adds a client's name in the proper hash linked + * list, can't fail, client_p must have a non-null + * name or expect a coredump, the name is infact + * taken from client_p->name + */ +void +hash_add_client(struct Client *client_p) +{ + unsigned int hashv = strhash(client_p->name); + + client_p->hnext = clientTable[hashv]; + clientTable[hashv] = client_p; +} + +/* hash_add_channel() + * + * inputs - pointer to channel + * output - NONE + * side effects - Adds a channel's name in the proper hash linked + * list, can't fail. chptr must have a non-null name + * or expect a coredump. As before the name is taken + * from chptr->name, we do hash its entire lenght + * since this proved to be statistically faster + */ +void +hash_add_channel(struct Channel *chptr) +{ + unsigned int hashv = strhash(chptr->chname); + + chptr->hnextch = channelTable[hashv]; + channelTable[hashv] = chptr; +} + +void +hash_add_resv(struct ResvChannel *chptr) +{ + unsigned int hashv = strhash(chptr->name); + + chptr->hnext = resvchannelTable[hashv]; + resvchannelTable[hashv] = chptr; +} + +void +hash_add_userhost(struct UserHost *userhost) +{ + unsigned int hashv = strhash(userhost->host); + + userhost->next = userhostTable[hashv]; + userhostTable[hashv] = userhost; +} + +void +hash_add_id(struct Client *client_p) +{ + unsigned int hashv = strhash(client_p->id); + + client_p->idhnext = idTable[hashv]; + idTable[hashv] = client_p; +} + +/* hash_del_id() + * + * inputs - pointer to client + * output - NONE + * side effects - Removes an ID from the hash linked list + */ +void +hash_del_id(struct Client *client_p) +{ + unsigned int hashv = strhash(client_p->id); + struct Client *tmp = idTable[hashv]; + + if (tmp != NULL) + { + if (tmp == client_p) + { + idTable[hashv] = client_p->idhnext; + client_p->idhnext = client_p; + } + else + { + while (tmp->idhnext != client_p) + if ((tmp = tmp->idhnext) == NULL) + return; + + tmp->idhnext = tmp->idhnext->idhnext; + client_p->idhnext = client_p; + } + } +} + +/* hash_del_client() + * + * inputs - pointer to client + * output - NONE + * side effects - Removes a Client's name from the hash linked list + */ +void +hash_del_client(struct Client *client_p) +{ + unsigned int hashv = strhash(client_p->name); + struct Client *tmp = clientTable[hashv]; + + if (tmp != NULL) + { + if (tmp == client_p) + { + clientTable[hashv] = client_p->hnext; + client_p->hnext = client_p; + } + else + { + while (tmp->hnext != client_p) + if ((tmp = tmp->hnext) == NULL) + return; + + tmp->hnext = tmp->hnext->hnext; + client_p->hnext = client_p; + } + } +} + +/* hash_del_userhost() + * + * inputs - pointer to userhost + * output - NONE + * side effects - Removes a userhost from the hash linked list + */ +void +hash_del_userhost(struct UserHost *userhost) +{ + unsigned int hashv = strhash(userhost->host); + struct UserHost *tmp = userhostTable[hashv]; + + if (tmp != NULL) + { + if (tmp == userhost) + { + userhostTable[hashv] = userhost->next; + userhost->next = userhost; + } + else + { + while (tmp->next != userhost) + if ((tmp = tmp->next) == NULL) + return; + + tmp->next = tmp->next->next; + userhost->next = userhost; + } + } +} + +/* hash_del_channel() + * + * inputs - pointer to client + * output - NONE + * side effects - Removes the channel's name from the corresponding + * hash linked list + */ +void +hash_del_channel(struct Channel *chptr) +{ + unsigned int hashv = strhash(chptr->chname); + struct Channel *tmp = channelTable[hashv]; + + if (tmp != NULL) + { + if (tmp == chptr) + { + channelTable[hashv] = chptr->hnextch; + chptr->hnextch = chptr; + } + else + { + while (tmp->hnextch != chptr) + if ((tmp = tmp->hnextch) == NULL) + return; + + tmp->hnextch = tmp->hnextch->hnextch; + chptr->hnextch = chptr; + } + } +} + +void +hash_del_resv(struct ResvChannel *chptr) +{ + unsigned int hashv = strhash(chptr->name); + struct ResvChannel *tmp = resvchannelTable[hashv]; + + if (tmp != NULL) + { + if (tmp == chptr) + { + resvchannelTable[hashv] = chptr->hnext; + chptr->hnext = chptr; + } + else + { + while (tmp->hnext != chptr) + if ((tmp = tmp->hnext) == NULL) + return; + + tmp->hnext = tmp->hnext->hnext; + chptr->hnext = chptr; + } + } +} + +/* hash_find_client() + * + * inputs - pointer to name + * output - NONE + * side effects - New semantics: finds a client whose name is 'name' + * if can't find one returns NULL. If it finds one moves + * it to the top of the list and returns it. + */ +struct Client * +hash_find_client(const char *name) +{ + unsigned int hashv = strhash(name); + struct Client *client_p; + + if ((client_p = clientTable[hashv]) != NULL) + { + if (irccmp(name, client_p->name)) + { + struct Client *prev; + + while (prev = client_p, (client_p = client_p->hnext) != NULL) + { + if (!irccmp(name, client_p->name)) + { + prev->hnext = client_p->hnext; + client_p->hnext = clientTable[hashv]; + clientTable[hashv] = client_p; + break; + } + } + } + } + + return client_p; +} + +struct Client * +hash_find_id(const char *name) +{ + unsigned int hashv = strhash(name); + struct Client *client_p; + + if ((client_p = idTable[hashv]) != NULL) + { + if (strcmp(name, client_p->id)) + { + struct Client *prev; + + while (prev = client_p, (client_p = client_p->idhnext) != NULL) + { + if (!strcmp(name, client_p->id)) + { + prev->idhnext = client_p->idhnext; + client_p->idhnext = idTable[hashv]; + idTable[hashv] = client_p; + break; + } + } + } + } + + return client_p; +} + +struct Client * +hash_find_server(const char *name) +{ + unsigned int hashv = strhash(name); + struct Client *client_p = NULL; + + if (IsDigit(*name) && strlen(name) == IRC_MAXSID) + return hash_find_id(name); + + if ((client_p = clientTable[hashv]) != NULL) + { + if ((!IsServer(client_p) && !IsMe(client_p)) || + irccmp(name, client_p->name)) + { + struct Client *prev; + + while (prev = client_p, (client_p = client_p->hnext) != NULL) + { + if ((IsServer(client_p) || IsMe(client_p)) && + !irccmp(name, client_p->name)) + { + prev->hnext = client_p->hnext; + client_p->hnext = clientTable[hashv]; + clientTable[hashv] = client_p; + break; + } + } + } + } + + return client_p; +} + +/* hash_find_channel() + * + * inputs - pointer to name + * output - NONE + * side effects - New semantics: finds a channel whose name is 'name', + * if can't find one returns NULL, if can find it moves + * it to the top of the list and returns it. + */ +struct Channel * +hash_find_channel(const char *name) +{ + unsigned int hashv = strhash(name); + struct Channel *chptr = NULL; + + if ((chptr = channelTable[hashv]) != NULL) + { + if (irccmp(name, chptr->chname)) + { + struct Channel *prev; + + while (prev = chptr, (chptr = chptr->hnextch) != NULL) + { + if (!irccmp(name, chptr->chname)) + { + prev->hnextch = chptr->hnextch; + chptr->hnextch = channelTable[hashv]; + channelTable[hashv] = chptr; + break; + } + } + } + } + + return chptr; +} + +/* hash_get_bucket(int type, unsigned int hashv) + * + * inputs - hash value (must be between 0 and HASHSIZE - 1) + * output - NONE + * returns - pointer to first channel in channelTable[hashv] + * if that exists; + * NULL if there is no channel in that place; + * NULL if hashv is an invalid number. + * side effects - NONE + */ +void * +hash_get_bucket(int type, unsigned int hashv) +{ + assert(hashv < HASHSIZE); + if (hashv >= HASHSIZE) + return NULL; + + switch (type) + { + case HASH_TYPE_ID: + return idTable[hashv]; + break; + case HASH_TYPE_CHANNEL: + return channelTable[hashv]; + break; + case HASH_TYPE_CLIENT: + return clientTable[hashv]; + break; + case HASH_TYPE_USERHOST: + return userhostTable[hashv]; + break; + case HASH_TYPE_RESERVED: + return resvchannelTable[hashv]; + break; + default: + assert(0); + } + + return NULL; +} + +/* hash_find_resv() + * + * inputs - pointer to name + * output - NONE + * side effects - New semantics: finds a reserved channel whose name is 'name', + * if can't find one returns NULL, if can find it moves + * it to the top of the list and returns it. + */ +struct ResvChannel * +hash_find_resv(const char *name) +{ + unsigned int hashv = strhash(name); + struct ResvChannel *chptr; + + if ((chptr = resvchannelTable[hashv]) != NULL) + { + if (irccmp(name, chptr->name)) + { + struct ResvChannel *prev; + + while (prev = chptr, (chptr = chptr->hnext) != NULL) + { + if (!irccmp(name, chptr->name)) + { + prev->hnext = chptr->hnext; + chptr->hnext = resvchannelTable[hashv]; + resvchannelTable[hashv] = chptr; + break; + } + } + } + } + + return chptr; +} + +struct UserHost * +hash_find_userhost(const char *host) +{ + unsigned int hashv = strhash(host); + struct UserHost *userhost; + + if ((userhost = userhostTable[hashv])) + { + if (irccmp(host, userhost->host)) + { + struct UserHost *prev; + + while (prev = userhost, (userhost = userhost->next) != NULL) + { + if (!irccmp(host, userhost->host)) + { + prev->next = userhost->next; + userhost->next = userhostTable[hashv]; + userhostTable[hashv] = userhost; + break; + } + } + } + } + + return userhost; +} + +/* count_user_host() + * + * inputs - user name + * - hostname + * - int flag 1 if global, 0 if local + * - pointer to where global count should go + * - pointer to where local count should go + * - pointer to where identd count should go (local clients only) + * output - none + * side effects - + */ +void +count_user_host(const char *user, const char *host, int *global_p, + int *local_p, int *icount_p) +{ + dlink_node *ptr; + struct UserHost *found_userhost; + struct NameHost *nameh; + + if ((found_userhost = hash_find_userhost(host)) == NULL) + return; + + DLINK_FOREACH(ptr, found_userhost->list.head) + { + nameh = ptr->data; + + if (!irccmp(user, nameh->name)) + { + if (global_p != NULL) + *global_p = nameh->gcount; + if (local_p != NULL) + *local_p = nameh->lcount; + if (icount_p != NULL) + *icount_p = nameh->icount; + return; + } + } +} + +/* find_or_add_userhost() + * + * inputs - host name + * output - none + * side effects - find UserHost * for given host name + */ +static struct UserHost * +find_or_add_userhost(const char *host) +{ + struct UserHost *userhost; + + if ((userhost = hash_find_userhost(host)) != NULL) + return userhost; + + userhost = BlockHeapAlloc(userhost_heap); + strlcpy(userhost->host, host, sizeof(userhost->host)); + hash_add_userhost(userhost); + + return userhost; +} + +/* add_user_host() + * + * inputs - user name + * - hostname + * - int flag 1 if global, 0 if local + * output - none + * side effects - add given user@host to hash tables + */ +void +add_user_host(const char *user, const char *host, int global) +{ + dlink_node *ptr; + struct UserHost *found_userhost; + struct NameHost *nameh; + int hasident = 1; + + if (*user == '~') + { + hasident = 0; + ++user; + } + + if ((found_userhost = find_or_add_userhost(host)) == NULL) + return; + + DLINK_FOREACH(ptr, found_userhost->list.head) + { + nameh = ptr->data; + + if (!irccmp(user, nameh->name)) + { + nameh->gcount++; + + if (!global) + { + if (hasident) + nameh->icount++; + nameh->lcount++; + } + + return; + } + } + + nameh = BlockHeapAlloc(namehost_heap); + strlcpy(nameh->name, user, sizeof(nameh->name)); + + nameh->gcount = 1; + + if (!global) + { + if (hasident) + nameh->icount = 1; + nameh->lcount = 1; + } + + dlinkAdd(nameh, &nameh->node, &found_userhost->list); +} + +/* delete_user_host() + * + * inputs - user name + * - hostname + * - int flag 1 if global, 0 if local + * output - none + * side effects - delete given user@host to hash tables + */ +void +delete_user_host(const char *user, const char *host, int global) +{ + dlink_node *ptr = NULL, *next_ptr = NULL; + struct UserHost *found_userhost; + struct NameHost *nameh; + int hasident = 1; + + if (*user == '~') + { + hasident = 0; + ++user; + } + + if ((found_userhost = hash_find_userhost(host)) == NULL) + return; + + DLINK_FOREACH_SAFE(ptr, next_ptr, found_userhost->list.head) + { + nameh = ptr->data; + + if (!irccmp(user, nameh->name)) + { + if (nameh->gcount > 0) + nameh->gcount--; + if (!global) + { + if (nameh->lcount > 0) + nameh->lcount--; + if (hasident && nameh->icount > 0) + nameh->icount--; + } + + if (nameh->gcount == 0 && nameh->lcount == 0) + { + dlinkDelete(&nameh->node, &found_userhost->list); + BlockHeapFree(namehost_heap, nameh); + } + + if (dlink_list_length(&found_userhost->list) == 0) + { + hash_del_userhost(found_userhost); + BlockHeapFree(userhost_heap, found_userhost); + } + + return; + } + } +} + +/* + * Safe list code. + * + * The idea is really quite simple. As the link lists pointed to in + * each "bucket" of the channel hash table are traversed atomically + * there is no locking needed. Overall, yes, inconsistent reported + * state can still happen, but normally this isn't a big deal. + * I don't like sticking the code into hash.c but oh well. Moreover, + * if a hash isn't used in future, oops. + * + * - Dianora + */ + +/* exceeding_sendq() + * + * inputs - pointer to client to check + * output - 1 if client is in danger of blowing its sendq + * 0 if it is not. + * side effects - + * + * Sendq limit is fairly conservative at 1/2 (In original anyway) + */ +static int +exceeding_sendq(struct Client *to) +{ + if (dbuf_length(&to->localClient->buf_sendq) > (get_sendq(to) / 2)) + return 1; + else + return 0; +} + +void +free_list_task(struct ListTask *lt, struct Client *source_p) +{ + dlink_node *dl, *dln; + + if ((dl = dlinkFindDelete(&listing_client_list, source_p)) != NULL) + free_dlink_node(dl); + + DLINK_FOREACH_SAFE(dl, dln, lt->show_mask.head) + { + MyFree(dl->data); + free_dlink_node(dl); + } + + DLINK_FOREACH_SAFE(dl, dln, lt->hide_mask.head) + { + MyFree(dl->data); + free_dlink_node(dl); + } + + MyFree(lt); + + if (MyConnect(source_p)) + source_p->localClient->list_task = NULL; +} + +/* list_allow_channel() + * + * inputs - channel name + * - pointer to a list task + * output - 1 if the channel is to be displayed + * 0 otherwise + * side effects - + */ +static int +list_allow_channel(const char *chname, struct ListTask *lt) +{ + dlink_node *dl = NULL; + + DLINK_FOREACH(dl, lt->show_mask.head) + if (!match_chan(dl->data, chname)) + return 0; + + DLINK_FOREACH(dl, lt->hide_mask.head) + if (match_chan(dl->data, chname)) + return 0; + + return 1; +} + +/* list_one_channel() + * + * inputs - client pointer to return result to + * - pointer to channel to list + * - pointer to ListTask structure + * output - none + * side effects - + */ +static void +list_one_channel(struct Client *source_p, struct Channel *chptr, + struct ListTask *list_task) +{ + if (SecretChannel(chptr) && !IsMember(source_p, chptr)) + return; + if (dlink_list_length(&chptr->members) < list_task->users_min || + dlink_list_length(&chptr->members) > list_task->users_max || + (chptr->channelts != 0 && + ((unsigned int)chptr->channelts < list_task->created_min || + (unsigned int)chptr->channelts > list_task->created_max)) || + (unsigned int)chptr->topic_time < list_task->topicts_min || + (chptr->topic_time ? (unsigned int)chptr->topic_time : UINT_MAX) > + list_task->topicts_max) + return; + + if (!list_allow_channel(chptr->chname, list_task)) + return; + sendto_one(source_p, form_str(RPL_LIST), me.name, source_p->name, + chptr->chname, dlink_list_length(&chptr->members), + chptr->topic); +} + +/* safe_list_channels() + * + * inputs - pointer to client requesting list + * output - 0/1 + * side effects - safely list all channels to source_p + * + * Walk the channel buckets, ensure all pointers in a bucket are + * traversed before blocking on a sendq. This means, no locking is needed. + * + * N.B. This code is "remote" safe, but is not currently used for + * remote clients. + * + * - Dianora + */ +void +safe_list_channels(struct Client *source_p, struct ListTask *list_task, + int only_unmasked_channels) +{ + struct Channel *chptr = NULL; + + if (!only_unmasked_channels) + { + unsigned int i; + + for (i = list_task->hash_index; i < HASHSIZE; ++i) + { + if (exceeding_sendq(source_p->from)) + { + list_task->hash_index = i; + return; /* still more to do */ + } + + for (chptr = channelTable[i]; chptr; chptr = chptr->hnextch) + list_one_channel(source_p, chptr, list_task); + } + } + else + { + dlink_node *dl; + + DLINK_FOREACH(dl, list_task->show_mask.head) + if ((chptr = hash_find_channel(dl->data)) != NULL) + list_one_channel(source_p, chptr, list_task); + } + + free_list_task(list_task, source_p); + sendto_one(source_p, form_str(RPL_LISTEND), + me.name, source_p->name); +} diff --git a/src/hook.c b/src/hook.c new file mode 100644 index 0000000..9b4b1c5 --- /dev/null +++ b/src/hook.c @@ -0,0 +1,216 @@ +/* + * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd). + * + * Copyright (C) 2003 Piotr Nizynski, Advanced IRC Services Project Team + * Copyright (C) 2005 Hybrid Development Team + * + * 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 + * + * $Id$ + */ + +/*! \file hook.c + * \brief Provides a generic event hooking interface. + * \version $Id$ + */ + +#include "stdinc.h" +#include "list.h" +#include "hook.h" +#include "ircd.h" +#include "memory.h" +#include "numeric.h" +#include "irc_string.h" +#include "send.h" +#include "client.h" + +static dlink_list callback_list = { NULL, NULL, 0} ; + +/*! \brief Creates a new callback. + * \param name name used to identify the callback + * (can be NULL for anonymous callbacks) + * \param func initial function attached to the chain + * (can be NULL to create an empty chain) + * \return pointer to Callback structure or NULL if already exists + * \note Once registered, a callback should never be freed! + * That's because there may be modules which depend on it + * (even if no functions are attached). That's also why + * we dynamically allocate the struct here -- we don't want + * to allow anyone to place it in module data, which can be + * unloaded at any time. + */ +struct Callback * +register_callback(const char *name, CBFUNC *func) +{ + struct Callback *cb = NULL; + + if (name != NULL) + { + if ((cb = find_callback(name)) != NULL) + { + if (func != NULL) + dlinkAddTail(func, MyMalloc(sizeof(dlink_node)), &cb->chain); + + return cb; + } + } + + cb = MyMalloc(sizeof(struct Callback)); + if (func != NULL) + dlinkAdd(func, MyMalloc(sizeof(dlink_node)), &cb->chain); + + if (name != NULL) + { + DupString(cb->name, name); + dlinkAdd(cb, &cb->node, &callback_list); + } + + return cb; +} + +/*! \brief Passes control down the callback hook chain. + * \param cb pointer to Callback structure + * \param ... argument to pass + * \return function return value + */ +void * +execute_callback(struct Callback *cb, ...) +{ + void *res; + va_list args; + + cb->called++; + cb->last = CurrentTime; + + if (!is_callback_present(cb)) + return NULL; + + va_start(args, cb); + res = ((CBFUNC *) cb->chain.head->data)(args); + va_end(args); + + return res; +} + +/*! \brief Called by a hook function to pass code flow further + * in the hook chain. + * \param this_hook pointer to dlink_node of the current hook function + * \param ... (original or modified) arguments to be passed + * \return callback return value + */ +void * +pass_callback(dlink_node *this_hook, ...) +{ + void *res; + va_list args; + + if (this_hook->next == NULL) + return NULL; /* reached the last one */ + + va_start(args, this_hook); + res = ((CBFUNC *) this_hook->next->data)(args); + va_end(args); + + return res; +} + +/*! \brief Finds a named callback. + * \param name name of the callback + * \return pointer to Callback structure or NULL if not found + */ +struct Callback * +find_callback(const char *name) +{ + dlink_node *ptr; + + DLINK_FOREACH(ptr, callback_list.head) + { + struct Callback *cb = ptr->data; + + if (!irccmp(cb->name, name)) + return cb; + } + + return NULL; +} + +/*! \brief Installs a hook for the given callback. + * + * The new hook is installed at the beginning of the chain, + * so it has full control over functions installed earlier. + * + * \param cb pointer to Callback structure + * \param hook address of hook function + * \return pointer to dlink_node of the hook (used when passing + * control to the next hook in the chain); + * valid till uninstall_hook() is called + */ +dlink_node * +install_hook(struct Callback *cb, CBFUNC *hook) +{ + dlink_node *node = MyMalloc(sizeof(dlink_node)); + + dlinkAdd(hook, node, &cb->chain); + return node; +} + +/*! \brief Removes a specific hook for the given callback. + * \param cb pointer to Callback structure + * \param hook address of hook function + */ +void +uninstall_hook(struct Callback *cb, CBFUNC *hook) +{ + /* let it core if not found */ + dlink_node *ptr = dlinkFind(&cb->chain, hook); + + dlinkDelete(ptr, &cb->chain); + MyFree(ptr); +} + +/*! \brief Displays registered callbacks and lengths of their hook chains. + * (This is the handler of /stats h) + * \param source_p pointer to struct Client + */ +void +stats_hooks(struct Client *source_p) +{ + dlink_node *ptr; + char lastused[32]; + + sendto_one(source_p, ":%s %d %s : %-20s %-20s Used Hooks", me.name, + RPL_STATSDEBUG, source_p->name, "Callback", "Last Execution"); + sendto_one(source_p, ":%s %d %s : ------------------------------------" + "--------------------", me.name, RPL_STATSDEBUG, source_p->name); + + DLINK_FOREACH(ptr, callback_list.head) + { + struct Callback *cb = ptr->data; + + if (cb->last != 0) + snprintf(lastused, sizeof(lastused), "%d seconds ago", + (int) (CurrentTime - cb->last)); + else + strcpy(lastused, "NEVER"); + + sendto_one(source_p, ":%s %d %s : %-20s %-20s %-8u %d", me.name, + RPL_STATSDEBUG, source_p->name, cb->name, lastused, cb->called, + dlink_list_length(&cb->chain)); + } + + sendto_one(source_p, ":%s %d %s : ", me.name, RPL_STATSDEBUG, + source_p->name); +} diff --git a/src/hostmask.c b/src/hostmask.c new file mode 100644 index 0000000..f7cca41 --- /dev/null +++ b/src/hostmask.c @@ -0,0 +1,820 @@ +/* + * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd). + * hostmask.c: Code to efficiently find IP & hostmask based configs. + * + * Copyright (C) 2005 by the past and present ircd coders, and others. + * + * 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 + * + * $Id$ + */ + +#include "stdinc.h" +#include "memory.h" +#include "ircd_defs.h" +#include "list.h" +#include "conf.h" +#include "hostmask.h" +#include "send.h" +#include "irc_string.h" +#include "ircd.h" + + +#define DigitParse(ch) do { \ + if (ch >= '0' && ch <= '9') \ + ch = ch - '0'; \ + else if (ch >= 'A' && ch <= 'F') \ + ch = ch - 'A' + 10; \ + else if (ch >= 'a' && ch <= 'f') \ + ch = ch - 'a' + 10; \ + } while (0); + +/* The mask parser/type determination code... */ + +/* int try_parse_v6_netmask(const char *, struct irc_ssaddr *, int *); + * Input: A possible IPV6 address as a string. + * Output: An integer describing whether it is an IPV6 or hostmask, + * an address(if it is IPV6), a bitlength(if it is IPV6). + * Side effects: None + * Comments: Called from parse_netmask + */ +/* Fixed so ::/0 (any IPv6 address) is valid + Also a bug in DigitParse above. + -Gozem 2002-07-19 gozem@linux.nu +*/ +#ifdef IPV6 +static int +try_parse_v6_netmask(const char *text, struct irc_ssaddr *addr, int *b) +{ + const char *p; + char c; + int d[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; + int dp = 0; + int nyble = 4; + int finsert = -1; + int bits = 128; + int deficit = 0; + short dc[8]; + struct sockaddr_in6 *v6 = (struct sockaddr_in6 *)addr; + + for (p = text; (c = *p); p++) + if (IsXDigit(c)) + { + if (nyble == 0) + return HM_HOST; + DigitParse(c); + d[dp] |= c << (4 * --nyble); + } + else if (c == ':') + { + if (p > text && *(p - 1) == ':') + { + if (finsert >= 0) + return HM_HOST; + finsert = dp; + } + else + { + /* If there were less than 4 hex digits, e.g. :ABC: shift right + * so we don't interpret it as ABC0 -A1kmm */ + d[dp] = d[dp] >> 4 * nyble; + nyble = 4; + if (++dp >= 8) + return HM_HOST; + } + } + else if (c == '*') + { + /* * must be last, and * is ambiguous if there is a ::... -A1kmm */ + if (finsert >= 0 || *(p + 1) || dp == 0 || *(p - 1) != ':') + return HM_HOST; + bits = dp * 16; + } + else if (c == '/') + { + char *after; + + d[dp] = d[dp] >> 4 * nyble; + dp++; + bits = strtoul(p + 1, &after, 10); + + if (bits < 0 || *after) + return HM_HOST; + if (bits > dp * 4 && !(finsert >= 0 && bits <= 128)) + return HM_HOST; + break; + } + else + return HM_HOST; + + d[dp] = d[dp] >> 4 * nyble; + + if (c == 0) + dp++; + if (finsert < 0 && bits == 0) + bits = dp * 16; + + /* How many words are missing? -A1kmm */ + deficit = bits / 16 + ((bits % 16) ? 1 : 0) - dp; + + /* Now fill in the gaps(from ::) in the copied table... -A1kmm */ + for (dp = 0, nyble = 0; dp < 8; dp++) + { + if (nyble == finsert && deficit) + { + dc[dp] = 0; + deficit--; + } + else + dc[dp] = d[nyble++]; + } + + /* Set unused bits to 0... -A1kmm */ + if (bits < 128 && (bits % 16 != 0)) + dc[bits / 16] &= ~((1 << (15 - bits % 16)) - 1); + for (dp = bits / 16 + (bits % 16 ? 1 : 0); dp < 8; dp++) + dc[dp] = 0; + + /* And assign... -A1kmm */ + if (addr) + for (dp = 0; dp < 8; dp++) + /* The cast is a kludge to make netbsd work. */ + ((unsigned short *)&v6->sin6_addr)[dp] = htons(dc[dp]); + + if (b != NULL) + *b = bits; + return HM_IPV6; +} +#endif + +/* int try_parse_v4_netmask(const char *, struct irc_ssaddr *, int *); + * Input: A possible IPV4 address as a string. + * Output: An integer describing whether it is an IPV4 or hostmask, + * an address(if it is IPV4), a bitlength(if it is IPV4). + * Side effects: None + * Comments: Called from parse_netmask + */ +static int +try_parse_v4_netmask(const char *text, struct irc_ssaddr *addr, int *b) +{ + const char *p; + const char *digits[4]; + unsigned char addb[4]; + int n = 0, bits = 0; + char c; + struct sockaddr_in *v4 = (struct sockaddr_in *)addr; + + digits[n++] = text; + + for (p = text; (c = *p); p++) + if (c >= '0' && c <= '9') /* empty */ + ; + else if (c == '.') + { + if (n >= 4) + return HM_HOST; + + digits[n++] = p + 1; + } + else if (c == '*') + { + if (*(p + 1) || n == 0 || *(p - 1) != '.') + return HM_HOST; + + bits = (n - 1) * 8; + break; + } + else if (c == '/') + { + char *after; + bits = strtoul(p + 1, &after, 10); + + if (!bits || *after) + return HM_HOST; + if (bits > n * 8) + return HM_HOST; + + break; + } + else + return HM_HOST; + + if (n < 4 && bits == 0) + bits = n * 8; + if (bits) + while (n < 4) + digits[n++] = "0"; + + for (n = 0; n < 4; n++) + addb[n] = strtoul(digits[n], NULL, 10); + + if (bits == 0) + bits = 32; + + /* Set unused bits to 0... -A1kmm */ + if (bits < 32 && bits % 8) + addb[bits / 8] &= ~((1 << (8 - bits % 8)) - 1); + for (n = bits / 8 + (bits % 8 ? 1 : 0); n < 4; n++) + addb[n] = 0; + if (addr) + v4->sin_addr.s_addr = + htonl(addb[0] << 24 | addb[1] << 16 | addb[2] << 8 | addb[3]); + if (b != NULL) + *b = bits; + return HM_IPV4; +} + +/* int parse_netmask(const char *, struct irc_ssaddr *, int *); + * Input: A hostmask, or an IPV4/6 address. + * Output: An integer describing whether it is an IPV4, IPV6 address or a + * hostmask, an address(if it is an IP mask), + * a bitlength(if it is IP mask). + * Side effects: None + */ +int +parse_netmask(const char *text, struct irc_ssaddr *addr, int *b) +{ +#ifdef IPV6 + if (strchr(text, ':')) + return try_parse_v6_netmask(text, addr, b); +#endif + if (strchr(text, '.')) + return try_parse_v4_netmask(text, addr, b); + return HM_HOST; +} + +/* The address matching stuff... */ +/* int match_ipv6(struct irc_ssaddr *, struct irc_ssaddr *, int) + * Input: An IP address, an IP mask, the number of bits in the mask. + * Output: if match, -1 else 0 + * Side effects: None + */ +#ifdef IPV6 +int +match_ipv6(const struct irc_ssaddr *addr, const struct irc_ssaddr *mask, int bits) +{ + int i, m, n = bits / 8; + const struct sockaddr_in6 *v6 = (const struct sockaddr_in6 *)addr; + const struct sockaddr_in6 *v6mask = (const struct sockaddr_in6 *)mask; + + for (i = 0; i < n; i++) + if (v6->sin6_addr.s6_addr[i] != v6mask->sin6_addr.s6_addr[i]) + return 0; + if ((m = bits % 8) == 0) + return -1; + if ((v6->sin6_addr.s6_addr[n] & ~((1 << (8 - m)) - 1)) == + v6mask->sin6_addr.s6_addr[n]) + return -1; + return 0; +} +#endif + +/* int match_ipv4(struct irc_ssaddr *, struct irc_ssaddr *, int) + * Input: An IP address, an IP mask, the number of bits in the mask. + * Output: if match, -1 else 0 + * Side Effects: None + */ +int +match_ipv4(const struct irc_ssaddr *addr, const struct irc_ssaddr *mask, int bits) +{ + const struct sockaddr_in *v4 = (const struct sockaddr_in *)addr; + const struct sockaddr_in *v4mask = (const struct sockaddr_in *)mask; + + if ((ntohl(v4->sin_addr.s_addr) & ~((1 << (32 - bits)) - 1)) != + ntohl(v4mask->sin_addr.s_addr)) + return 0; + return -1; +} + +/* + * mask_addr + * + * inputs - pointer to the ip to mask + * - bitlen + * output - NONE + * side effects - + */ +void +mask_addr(struct irc_ssaddr *ip, int bits) +{ + int mask; +#ifdef IPV6 + struct sockaddr_in6 *v6_base_ip; + int i, m, n; +#endif + struct sockaddr_in *v4_base_ip; + +#ifdef IPV6 + if (ip->ss.ss_family != AF_INET6) +#endif + { + v4_base_ip = (struct sockaddr_in *)ip; + + mask = ~((1 << (32 - bits)) - 1); + v4_base_ip->sin_addr.s_addr = htonl(ntohl(v4_base_ip->sin_addr.s_addr) & mask); + } +#ifdef IPV6 + else + { + n = bits / 8; + m = bits % 8; + v6_base_ip = (struct sockaddr_in6 *)ip; + + mask = ~((1 << (8 - m)) -1 ); + v6_base_ip->sin6_addr.s6_addr[n] = v6_base_ip->sin6_addr.s6_addr[n] & mask; + + for (i = n + 1; i < 16; i++) + v6_base_ip->sin6_addr.s6_addr[i] = 0; + } +#endif +} + +/* Hashtable stuff...now external as its used in m_stats.c */ +dlink_list atable[ATABLE_SIZE]; + +void +init_host_hash(void) +{ + memset(&atable, 0, sizeof(atable)); +} + +/* unsigned long hash_ipv4(struct irc_ssaddr*) + * Input: An IP address. + * Output: A hash value of the IP address. + * Side effects: None + */ +static uint32_t +hash_ipv4(struct irc_ssaddr *addr, int bits) +{ + if (bits != 0) + { + struct sockaddr_in *v4 = (struct sockaddr_in *)addr; + uint32_t av = ntohl(v4->sin_addr.s_addr) & ~((1 << (32 - bits)) - 1); + + return (av ^ (av >> 12) ^ (av >> 24)) & (ATABLE_SIZE - 1); + } + + return 0; +} + +/* unsigned long hash_ipv6(struct irc_ssaddr*) + * Input: An IP address. + * Output: A hash value of the IP address. + * Side effects: None + */ +#ifdef IPV6 +static uint32_t +hash_ipv6(struct irc_ssaddr *addr, int bits) +{ + uint32_t v = 0, n; + struct sockaddr_in6 *v6 = (struct sockaddr_in6 *)addr; + + for (n = 0; n < 16; n++) + { + if (bits >= 8) + { + v ^= v6->sin6_addr.s6_addr[n]; + bits -= 8; + } + else if (bits) + { + v ^= v6->sin6_addr.s6_addr[n] & ~((1 << (8 - bits)) - 1); + return v & (ATABLE_SIZE - 1); + } + else + return v & (ATABLE_SIZE - 1); + } + return v & (ATABLE_SIZE - 1); +} +#endif + +/* int hash_text(const char *start) + * Input: The start of the text to hash. + * Output: The hash of the string between 1 and (TH_MAX-1) + * Side-effects: None. + */ +static uint32_t +hash_text(const char *start) +{ + const char *p = start; + uint32_t h = 0; + + for (; *p; ++p) + h = (h << 4) - (h + (unsigned char)ToLower(*p)); + + return h & (ATABLE_SIZE - 1); +} + +/* unsigned long get_hash_mask(const char *) + * Input: The text to hash. + * Output: The hash of the string right of the first '.' past the last + * wildcard in the string. + * Side-effects: None. + */ +static uint32_t +get_mask_hash(const char *text) +{ + const char *hp = "", *p; + + for (p = text + strlen(text) - 1; p >= text; p--) + if (IsMWildChar(*p)) + return hash_text(hp); + else if (*p == '.') + hp = p + 1; + return hash_text(text); +} + +/* struct AccessItem *find_conf_by_address(const char *, struct irc_ssaddr *, + * int type, int fam, const char *username) + * Input: The hostname, the address, the type of mask to find, the address + * family, the username. + * Output: The matching value with the highest precedence. + * Side-effects: None + * Note: Setting bit 0 of the type means that the username is ignored. + * Warning: IsNeedPassword for everything that is not an auth{} entry + * should always be true (i.e. aconf->flags & CONF_FLAGS_NEED_PASSWORD == 0) + */ +struct AccessItem * +find_conf_by_address(const char *name, struct irc_ssaddr *addr, unsigned int type, + int fam, const char *username, const char *password, int do_match) +{ + unsigned int hprecv = 0; + dlink_node *ptr = NULL; + struct AccessItem *hprec = NULL; + struct AddressRec *arec; + int b; + int (*cmpfunc)(const char *, const char *) = do_match ? match : irccmp; + + if (username == NULL) + username = ""; + if (password == NULL) + password = ""; + + if (addr) + { + /* Check for IPV6 matches... */ +#ifdef IPV6 + if (fam == AF_INET6) + { + for (b = 128; b >= 0; b -= 16) + { + DLINK_FOREACH(ptr, atable[hash_ipv6(addr, b)].head) + { + arec = ptr->data; + + if (arec->type == (type & ~0x1) && + arec->precedence > hprecv && + arec->masktype == HM_IPV6 && + match_ipv6(addr, &arec->Mask.ipa.addr, + arec->Mask.ipa.bits) && + (type & 0x1 || cmpfunc(arec->username, username) == do_match) && + (IsNeedPassword(arec->aconf) || arec->aconf->passwd == NULL || + match_conf_password(password, arec->aconf))) + { + hprecv = arec->precedence; + hprec = arec->aconf; + } + } + } + } + else +#endif + if (fam == AF_INET) + { + for (b = 32; b >= 0; b -= 8) + { + DLINK_FOREACH(ptr, atable[hash_ipv4(addr, b)].head) + { + arec = ptr->data; + + if (arec->type == (type & ~0x1) && + arec->precedence > hprecv && + arec->masktype == HM_IPV4 && + match_ipv4(addr, &arec->Mask.ipa.addr, + arec->Mask.ipa.bits) && + (type & 0x1 || cmpfunc(arec->username, username) == do_match) && + (IsNeedPassword(arec->aconf) || arec->aconf->passwd == NULL || + match_conf_password(password, arec->aconf))) + { + hprecv = arec->precedence; + hprec = arec->aconf; + } + } + } + } + } + + if (name != NULL) + { + const char *p = name; + + while (1) + { + DLINK_FOREACH(ptr, atable[hash_text(p)].head) + { + arec = ptr->data; + if ((arec->type == (type & ~0x1)) && + arec->precedence > hprecv && + (arec->masktype == HM_HOST) && + cmpfunc(arec->Mask.hostname, name) == do_match && + (type & 0x1 || cmpfunc(arec->username, username) == do_match) && + (IsNeedPassword(arec->aconf) || arec->aconf->passwd == NULL || + match_conf_password(password, arec->aconf))) + { + hprecv = arec->precedence; + hprec = arec->aconf; + } + } + p = strchr(p, '.'); + if (p == NULL) + break; + p++; + } + + DLINK_FOREACH(ptr, atable[0].head) + { + arec = ptr->data; + + if (arec->type == (type & ~0x1) && + arec->precedence > hprecv && + arec->masktype == HM_HOST && + cmpfunc(arec->Mask.hostname, name) == do_match && + (type & 0x1 || cmpfunc(arec->username, username) == do_match) && + (IsNeedPassword(arec->aconf) || arec->aconf->passwd == NULL || + match_conf_password(password, arec->aconf))) + { + hprecv = arec->precedence; + hprec = arec->aconf; + } + } + } + + return hprec; +} + +/* struct AccessItem* find_address_conf(const char*, const char*, + * struct irc_ssaddr*, int, char *); + * Input: The hostname, username, address, address family. + * Output: The applicable AccessItem. + * Side-effects: None + */ +struct AccessItem * +find_address_conf(const char *host, const char *user, + struct irc_ssaddr *ip, int aftype, char *password) +{ + struct AccessItem *iconf, *kconf; + + /* Find the best auth{} block... If none, return NULL -A1kmm */ + if ((iconf = find_conf_by_address(host, ip, CONF_CLIENT, aftype, user, + password, 1)) == NULL) + return NULL; + + /* If they are exempt from K-lines, return the best auth{} block. -A1kmm */ + if (IsConfExemptKline(iconf)) + return iconf; + + /* Find the best K-line... -A1kmm */ + kconf = find_conf_by_address(host, ip, CONF_KLINE, aftype, user, NULL, 1); + + /* + * If they are K-lined, return the K-line. Otherwise, return the + * auth{} block. -A1kmm + */ + if (kconf != NULL) + return kconf; + + kconf = find_conf_by_address(host, ip, CONF_GLINE, aftype, user, NULL, 1); + if (kconf != NULL && !IsConfExemptGline(iconf)) + return kconf; + + return iconf; +} + +/* struct AccessItem* find_dline_conf(struct irc_ssaddr*, int) + * + * Input: An address, an address family. + * Output: The best matching D-line or exempt line. + * Side effects: None. + */ +struct AccessItem * +find_dline_conf(struct irc_ssaddr *addr, int aftype) +{ + struct AccessItem *eline; + + eline = find_conf_by_address(NULL, addr, CONF_EXEMPTDLINE | 1, aftype, + NULL, NULL, 1); + if (eline != NULL) + return eline; + + return find_conf_by_address(NULL, addr, CONF_DLINE | 1, aftype, NULL, NULL, 1); +} + +/* void add_conf_by_address(int, struct AccessItem *aconf) + * Input: + * Output: None + * Side-effects: Adds this entry to the hash table. + */ +void +add_conf_by_address(const unsigned int type, struct AccessItem *aconf) +{ + const char *address; + const char *username; + static unsigned int prec_value = 0xFFFFFFFF; + int bits = 0; + struct AddressRec *arec; + + address = aconf->host; + username = aconf->user; + + assert(type != 0); + assert(aconf != NULL); + + if (EmptyString(address)) + address = "/NOMATCH!/"; + + arec = MyMalloc(sizeof(struct AddressRec)); + arec->masktype = parse_netmask(address, &arec->Mask.ipa.addr, &bits); + arec->Mask.ipa.bits = bits; + arec->username = username; + arec->aconf = aconf; + arec->precedence = prec_value--; + arec->type = type; + + switch (arec->masktype) + { + case HM_IPV4: + /* We have to do this, since we do not re-hash for every bit -A1kmm. */ + bits -= bits % 8; + dlinkAdd(arec, &arec->node, &atable[hash_ipv4(&arec->Mask.ipa.addr, bits)]); + break; +#ifdef IPV6 + case HM_IPV6: + /* We have to do this, since we do not re-hash for every bit -A1kmm. */ + bits -= bits % 16; + dlinkAdd(arec, &arec->node, &atable[hash_ipv6(&arec->Mask.ipa.addr, bits)]); + break; +#endif + default: /* HM_HOST */ + arec->Mask.hostname = address; + dlinkAdd(arec, &arec->node, &atable[get_mask_hash(address)]); + break; + } +} + +/* void delete_one_address(const char*, struct AccessItem*) + * Input: An address string, the associated AccessItem. + * Output: None + * Side effects: Deletes an address record. Frees the AccessItem if there + * is nothing referencing it, sets it as illegal otherwise. + */ +void +delete_one_address_conf(const char *address, struct AccessItem *aconf) +{ + int bits = 0; + uint32_t hv = 0; + dlink_node *ptr = NULL, *ptr_next = NULL; + struct irc_ssaddr addr; + + switch (parse_netmask(address, &addr, &bits)) + { + case HM_IPV4: + /* We have to do this, since we do not re-hash for every bit -A1kmm. */ + bits -= bits % 8; + hv = hash_ipv4(&addr, bits); + break; +#ifdef IPV6 + case HM_IPV6: + /* We have to do this, since we do not re-hash for every bit -A1kmm. */ + bits -= bits % 16; + hv = hash_ipv6(&addr, bits); + break; +#endif + default: /* HM_HOST */ + hv = get_mask_hash(address); + break; + } + + DLINK_FOREACH_SAFE(ptr, ptr_next, atable[hv].head) + { + struct AddressRec *arec = ptr->data; + + if (arec->aconf == aconf) + { + dlinkDelete(&arec->node, &atable[hv]); + aconf->status |= CONF_ILLEGAL; + + if (!aconf->clients) + free_access_item(aconf); + + MyFree(arec); + return; + } + } +} + +/* void clear_out_address_conf(void) + * Input: None + * Output: None + * Side effects: Clears out all address records in the hash table, + * frees them, and frees the AccessItems if nothing references + * them, otherwise sets them as illegal. + */ +void +clear_out_address_conf(void) +{ + unsigned int i = 0; + dlink_node *ptr = NULL, *ptr_next = NULL; + + for (i = 0; i < ATABLE_SIZE; ++i) + { + DLINK_FOREACH_SAFE(ptr, ptr_next, atable[i].head) + { + struct AddressRec *arec = ptr->data; + + /* We keep the temporary K-lines and destroy the + * permanent ones, just to be confusing :) -A1kmm + */ + if (!(arec->aconf->flags & CONF_FLAGS_TEMPORARY)) + { + dlinkDelete(&arec->node, &atable[i]); + /* unlink it from link list - Dianora */ + arec->aconf->status |= CONF_ILLEGAL; + + if (!arec->aconf->clients) + free_access_item(arec->aconf); + MyFree(arec); + } + } + } +} + +static void +hostmask_send_expiration(struct AddressRec *arec) +{ + char ban_type = '\0'; + + if (!ConfigFileEntry.tkline_expire_notices) + return; + + switch (arec->type) + { + case CONF_KLINE: + ban_type = 'K'; + break; + case CONF_DLINE: + ban_type = 'D'; + break; + case CONF_GLINE: + ban_type = 'G'; + break; + } + + sendto_realops_flags(UMODE_ALL, L_ALL, + "Temporary %c-line for [%s@%s] expired", ban_type, + (arec->aconf->user) ? arec->aconf->user : "*", + (arec->aconf->host) ? arec->aconf->host : "*"); +} + +void +hostmask_expire_temporary(void) +{ + unsigned int i = 0; + dlink_node *ptr = NULL, *ptr_next = NULL; + + for (i = 0; i < ATABLE_SIZE; ++i) + { + DLINK_FOREACH_SAFE(ptr, ptr_next, atable[i].head) + { + struct AddressRec *arec = ptr->data; + + if (!IsConfTemporary(arec->aconf) || arec->aconf->hold > CurrentTime) + continue; + + switch (arec->type) + { + case CONF_KLINE: + case CONF_DLINE: + case CONF_GLINE: + hostmask_send_expiration(arec); + + dlinkDelete(&arec->node, &atable[i]); + free_access_item(arec->aconf); + MyFree(arec); + break; + } + } + } +} diff --git a/src/irc_res.c b/src/irc_res.c new file mode 100644 index 0000000..200b68d --- /dev/null +++ b/src/irc_res.c @@ -0,0 +1,836 @@ +/* + * A rewrite of Darren Reeds original res.c As there is nothing + * left of Darrens original code, this is now licensed by the hybrid group. + * (Well, some of the function names are the same, and bits of the structs..) + * You can use it where it is useful, free even. Buy us a beer and stuff. + * + * The authors takes no responsibility for any damage or loss + * of property which results from the use of this software. + * + * $Id$ + * + * July 1999 - Rewrote a bunch of stuff here. Change hostent builder code, + * added callbacks and reference counting of returned hostents. + * --Bleep (Thomas Helvey <tomh@inxpress.net>) + * + * This was all needlessly complicated for irc. Simplified. No more hostent + * All we really care about is the IP -> hostname mappings. Thats all. + * + * Apr 28, 2003 --cryogen and Dianora + */ + +#include "stdinc.h" +#include "list.h" +#include "balloc.h" +#include "client.h" +#include "event.h" +#include "irc_string.h" +#include "sprintf_irc.h" +#include "ircd.h" +#include "numeric.h" +#include "rng_mt.h" +#include "fdlist.h" +#include "s_bsd.h" +#include "log.h" +#include "s_misc.h" +#include "send.h" +#include "memory.h" +#include "irc_res.h" +#include "irc_reslib.h" + +#if (CHAR_BIT != 8) +#error this code needs to be able to address individual octets +#endif + +static PF res_readreply; + +#define MAXPACKET 1024 /* rfc sez 512 but we expand names so ... */ +#define RES_MAXALIASES 35 /* maximum aliases allowed */ +#define RES_MAXADDRS 35 /* maximum addresses allowed */ +#define AR_TTL 600 /* TTL in seconds for dns cache entries */ + +/* RFC 1104/1105 wasn't very helpful about what these fields + * should be named, so for now, we'll just name them this way. + * we probably should look at what named calls them or something. + */ +#define TYPE_SIZE (size_t)2 +#define CLASS_SIZE (size_t)2 +#define TTL_SIZE (size_t)4 +#define RDLENGTH_SIZE (size_t)2 +#define ANSWER_FIXED_SIZE (TYPE_SIZE + CLASS_SIZE + TTL_SIZE + RDLENGTH_SIZE) + +typedef enum +{ + REQ_IDLE, /* We're doing not much at all */ + REQ_PTR, /* Looking up a PTR */ + REQ_A, /* Looking up an A, possibly because AAAA failed */ +#ifdef IPV6 + REQ_AAAA, /* Looking up an AAAA */ +#endif + REQ_CNAME /* We got a CNAME in response, we better get a real answer next */ +} request_state; + +struct reslist +{ + dlink_node node; + int id; + int sent; /* number of requests sent */ + request_state state; /* State the resolver machine is in */ + time_t ttl; + char type; + char retries; /* retry counter */ + char sends; /* number of sends (>1 means resent) */ + char resend; /* send flag. 0 == dont resend */ + time_t sentat; + time_t timeout; + struct irc_ssaddr addr; + char *name; + dns_callback_fnc callback; + void *callback_ctx; +}; + +static fde_t ResolverFileDescriptor; +static dlink_list request_list = { NULL, NULL, 0 }; +static BlockHeap *dns_heap = NULL; + +static void rem_request(struct reslist *); +static struct reslist *make_request(dns_callback_fnc, void *); +static void do_query_name(dns_callback_fnc, void *, + const char *, struct reslist *, int); +static void do_query_number(dns_callback_fnc, void *, + const struct irc_ssaddr *, + struct reslist *); +static void query_name(const char *, int, int, struct reslist *); +static int send_res_msg(const char *, int, int); +static void resend_query(struct reslist *); +static int proc_answer(struct reslist *, HEADER *, char *, char *); +static struct reslist *find_id(int); + + +/* + * int + * res_ourserver(inp) + * looks up "inp" in irc_nsaddr_list[] + * returns: + * 0 : not found + * >0 : found + * author: + * paul vixie, 29may94 + * revised for ircd, cryogen(stu) may03 + */ +static int +res_ourserver(const struct irc_ssaddr *inp) +{ +#ifdef IPV6 + const struct sockaddr_in6 *v6; + const struct sockaddr_in6 *v6in = (const struct sockaddr_in6 *)inp; +#endif + const struct sockaddr_in *v4; + const struct sockaddr_in *v4in = (const struct sockaddr_in *)inp; + int ns; + + for (ns = 0; ns < irc_nscount; ++ns) + { + const struct irc_ssaddr *srv = &irc_nsaddr_list[ns]; +#ifdef IPV6 + v6 = (const struct sockaddr_in6 *)srv; +#endif + v4 = (const struct sockaddr_in *)srv; + + /* could probably just memcmp(srv, inp, srv.ss_len) here + * but we'll air on the side of caution - stu + * + */ + switch (srv->ss.ss_family) + { +#ifdef IPV6 + case AF_INET6: + if (srv->ss.ss_family == inp->ss.ss_family) + if (v6->sin6_port == v6in->sin6_port) + if (!memcmp(&v6->sin6_addr.s6_addr, &v6in->sin6_addr.s6_addr, + sizeof(struct in6_addr))) + return 1; + break; +#endif + case AF_INET: + if (srv->ss.ss_family == inp->ss.ss_family) + if (v4->sin_port == v4in->sin_port) + if (v4->sin_addr.s_addr == v4in->sin_addr.s_addr) + return 1; + break; + default: + break; + } + } + + return 0; +} + +/* + * timeout_query_list - Remove queries from the list which have been + * there too long without being resolved. + */ +static time_t +timeout_query_list(time_t now) +{ + dlink_node *ptr; + dlink_node *next_ptr; + struct reslist *request; + time_t next_time = 0; + time_t timeout = 0; + + DLINK_FOREACH_SAFE(ptr, next_ptr, request_list.head) + { + request = ptr->data; + timeout = request->sentat + request->timeout; + + if (now >= timeout) + { + if (--request->retries <= 0) + { + (*request->callback)(request->callback_ctx, NULL, NULL); + rem_request(request); + continue; + } + else + { + request->sentat = now; + request->timeout += request->timeout; + resend_query(request); + } + } + + if ((next_time == 0) || timeout < next_time) + next_time = timeout; + } + + return (next_time > now) ? next_time : (now + AR_TTL); +} + +/* + * timeout_resolver - check request list + */ +static void +timeout_resolver(void *notused) +{ + timeout_query_list(CurrentTime); +} + +/* + * start_resolver - do everything we need to read the resolv.conf file + * and initialize the resolver file descriptor if needed + */ +static void +start_resolver(void) +{ + irc_res_init(); + + if (!ResolverFileDescriptor.flags.open) + { + if (comm_open(&ResolverFileDescriptor, irc_nsaddr_list[0].ss.ss_family, + SOCK_DGRAM, 0, "Resolver socket") == -1) + return; + + /* At the moment, the resolver FD data is global .. */ + comm_setselect(&ResolverFileDescriptor, COMM_SELECT_READ, + res_readreply, NULL, 0); + eventAdd("timeout_resolver", timeout_resolver, NULL, 1); + } +} + +/* + * init_resolver - initialize resolver and resolver library + */ +void +init_resolver(void) +{ + dns_heap = BlockHeapCreate("dns", sizeof(struct reslist), DNS_HEAP_SIZE); + memset(&ResolverFileDescriptor, 0, sizeof(fde_t)); + start_resolver(); +} + +/* + * restart_resolver - reread resolv.conf, reopen socket + */ +void +restart_resolver(void) +{ + fd_close(&ResolverFileDescriptor); + eventDelete(timeout_resolver, NULL); /* -ddosen */ + start_resolver(); +} + +/* + * rem_request - remove a request from the list. + * This must also free any memory that has been allocated for + * temporary storage of DNS results. + */ +static void +rem_request(struct reslist *request) +{ + dlinkDelete(&request->node, &request_list); + + MyFree(request->name); + BlockHeapFree(dns_heap, request); +} + +/* + * make_request - Create a DNS request record for the server. + */ +static struct reslist * +make_request(dns_callback_fnc callback, void *ctx) +{ + struct reslist *request = BlockHeapAlloc(dns_heap); + + request->sentat = CurrentTime; + request->retries = 3; + request->resend = 1; + request->timeout = 4; /* start at 4 and exponential inc. */ + request->state = REQ_IDLE; + request->callback = callback; + request->callback_ctx = ctx; + + dlinkAdd(request, &request->node, &request_list); + return request; +} + +/* + * delete_resolver_queries - cleanup outstanding queries + * for which there no longer exist clients or conf lines. + */ +void +delete_resolver_queries(const void *vptr) +{ + dlink_node *ptr = NULL, *next_ptr = NULL; + + DLINK_FOREACH_SAFE(ptr, next_ptr, request_list.head) + { + struct reslist *request = ptr->data; + + if (request->callback_ctx == vptr) + rem_request(request); + } +} + +/* + * send_res_msg - sends msg to all nameservers found in the "_res" structure. + * This should reflect /etc/resolv.conf. We will get responses + * which arent needed but is easier than checking to see if nameserver + * isnt present. Returns number of messages successfully sent to + * nameservers or -1 if no successful sends. + */ +static int +send_res_msg(const char *msg, int len, int rcount) +{ + int i; + int sent = 0; + int max_queries = IRCD_MIN(irc_nscount, rcount); + + /* RES_PRIMARY option is not implemented + * if (res.options & RES_PRIMARY || 0 == max_queries) + */ + if (max_queries == 0) + max_queries = 1; + + for (i = 0; i < max_queries; i++) + { + if (sendto(ResolverFileDescriptor.fd, msg, len, 0, + (struct sockaddr*)&(irc_nsaddr_list[i]), + irc_nsaddr_list[i].ss_len) == len) + ++sent; + } + + return sent; +} + +/* + * find_id - find a dns request id (id is determined by dn_mkquery) + */ +static struct reslist * +find_id(int id) +{ + dlink_node *ptr = NULL; + + DLINK_FOREACH(ptr, request_list.head) + { + struct reslist *request = ptr->data; + + if (request->id == id) + return request; + } + + return NULL; +} + +/* + * gethost_byname_type - get host address from name + * + */ +void +gethost_byname_type(dns_callback_fnc callback, void *ctx, const char *name, int type) +{ + assert(name != NULL); + do_query_name(callback, ctx, name, NULL, type); +} + +/* + * gethost_byname - wrapper for _type - send T_AAAA first if IPV6 supported + */ +void +gethost_byname(dns_callback_fnc callback, void *ctx, const char *name) +{ +#ifdef IPV6 + gethost_byname_type(callback, ctx, name, T_AAAA); +#else + gethost_byname_type(callback, ctx, name, T_A); +#endif +} + +/* + * gethost_byaddr - get host name from address + */ +void +gethost_byaddr(dns_callback_fnc callback, void *ctx, const struct irc_ssaddr *addr) +{ + do_query_number(callback, ctx, addr, NULL); +} + +/* + * do_query_name - nameserver lookup name + */ +static void +do_query_name(dns_callback_fnc callback, void *ctx, const char *name, + struct reslist *request, int type) +{ + char host_name[HOSTLEN + 1]; + + strlcpy(host_name, name, sizeof(host_name)); + + if (request == NULL) + { + request = make_request(callback, ctx); + request->name = MyMalloc(strlen(host_name) + 1); + request->type = type; + strcpy(request->name, host_name); +#ifdef IPV6 + if (type != T_A) + request->state = REQ_AAAA; + else +#endif + request->state = REQ_A; + } + + request->type = type; + query_name(host_name, C_IN, type, request); +} + +/* + * do_query_number - Use this to do reverse IP# lookups. + */ +static void +do_query_number(dns_callback_fnc callback, void *ctx, + const struct irc_ssaddr *addr, + struct reslist *request) +{ + char ipbuf[128]; + const unsigned char *cp; + + if (addr->ss.ss_family == AF_INET) + { + const struct sockaddr_in *v4 = (const struct sockaddr_in *)addr; + cp = (const unsigned char *)&v4->sin_addr.s_addr; + + snprintf(ipbuf, sizeof(ipbuf), "%u.%u.%u.%u.in-addr.arpa.", + (unsigned int)(cp[3]), (unsigned int)(cp[2]), + (unsigned int)(cp[1]), (unsigned int)(cp[0])); + } +#ifdef IPV6 + else if (addr->ss.ss_family == AF_INET6) + { + const struct sockaddr_in6 *v6 = (const struct sockaddr_in6 *)addr; + cp = (const unsigned char *)&v6->sin6_addr.s6_addr; + + snprintf(ipbuf, sizeof(ipbuf), + "%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x." + "%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.ip6.arpa.", + (unsigned int)(cp[15] & 0xf), (unsigned int)(cp[15] >> 4), + (unsigned int)(cp[14] & 0xf), (unsigned int)(cp[14] >> 4), + (unsigned int)(cp[13] & 0xf), (unsigned int)(cp[13] >> 4), + (unsigned int)(cp[12] & 0xf), (unsigned int)(cp[12] >> 4), + (unsigned int)(cp[11] & 0xf), (unsigned int)(cp[11] >> 4), + (unsigned int)(cp[10] & 0xf), (unsigned int)(cp[10] >> 4), + (unsigned int)(cp[9] & 0xf), (unsigned int)(cp[9] >> 4), + (unsigned int)(cp[8] & 0xf), (unsigned int)(cp[8] >> 4), + (unsigned int)(cp[7] & 0xf), (unsigned int)(cp[7] >> 4), + (unsigned int)(cp[6] & 0xf), (unsigned int)(cp[6] >> 4), + (unsigned int)(cp[5] & 0xf), (unsigned int)(cp[5] >> 4), + (unsigned int)(cp[4] & 0xf), (unsigned int)(cp[4] >> 4), + (unsigned int)(cp[3] & 0xf), (unsigned int)(cp[3] >> 4), + (unsigned int)(cp[2] & 0xf), (unsigned int)(cp[2] >> 4), + (unsigned int)(cp[1] & 0xf), (unsigned int)(cp[1] >> 4), + (unsigned int)(cp[0] & 0xf), (unsigned int)(cp[0] >> 4)); + } +#endif + if (request == NULL) + { + request = make_request(callback, ctx); + request->type = T_PTR; + memcpy(&request->addr, addr, sizeof(struct irc_ssaddr)); + request->name = MyMalloc(HOSTLEN + 1); + } + + query_name(ipbuf, C_IN, T_PTR, request); +} + +/* + * query_name - generate a query based on class, type and name. + */ +static void +query_name(const char *name, int query_class, int type, + struct reslist *request) +{ + char buf[MAXPACKET]; + int request_len = 0; + + memset(buf, 0, sizeof(buf)); + + if ((request_len = irc_res_mkquery(name, query_class, type, + (unsigned char *)buf, sizeof(buf))) > 0) + { + HEADER *header = (HEADER *)buf; + + /* + * generate an unique id + * NOTE: we don't have to worry about converting this to and from + * network byte order, the nameserver does not interpret this value + * and returns it unchanged + */ + do + header->id = (header->id + genrand_int32()) & 0xffff; + while (find_id(header->id)); + + request->id = header->id; + ++request->sends; + + request->sent += send_res_msg(buf, request_len, request->sends); + } +} + +static void +resend_query(struct reslist *request) +{ + if (request->resend == 0) + return; + + switch (request->type) + { + case T_PTR: + do_query_number(NULL, NULL, &request->addr, request); + break; + case T_A: + do_query_name(NULL, NULL, request->name, request, request->type); + break; +#ifdef IPV6 + case T_AAAA: + /* didnt work, try A */ + if (request->state == REQ_AAAA) + do_query_name(NULL, NULL, request->name, request, T_A); +#endif + default: + break; + } +} + +/* + * proc_answer - process name server reply + */ +static int +proc_answer(struct reslist *request, HEADER *header, char *buf, char *eob) +{ + char hostbuf[HOSTLEN + 100]; /* working buffer */ + unsigned char *current; /* current position in buf */ + int query_class; /* answer class */ + int type; /* answer type */ + int n; /* temp count */ + int rd_length; + struct sockaddr_in *v4; /* conversion */ +#ifdef IPV6 + struct sockaddr_in6 *v6; +#endif + current = (unsigned char *)buf + sizeof(HEADER); + + for (; header->qdcount > 0; --header->qdcount) + { + if ((n = irc_dn_skipname(current, (unsigned char *)eob)) < 0) + break; + + current += (size_t)n + QFIXEDSZ; + } + + /* + * process each answer sent to us blech. + */ + while (header->ancount > 0 && (char *)current < eob) + { + header->ancount--; + + n = irc_dn_expand((unsigned char *)buf, (unsigned char *)eob, current, + hostbuf, sizeof(hostbuf)); + + if (n < 0 /* broken message */ || n == 0 /* no more answers left */) + return 0; + + hostbuf[HOSTLEN] = '\0'; + + /* With Address arithmetic you have to be very anal + * this code was not working on alpha due to that + * (spotted by rodder/jailbird/dianora) + */ + current += (size_t) n; + + if (!(((char *)current + ANSWER_FIXED_SIZE) < eob)) + break; + + type = irc_ns_get16(current); + current += TYPE_SIZE; + + query_class = irc_ns_get16(current); + current += CLASS_SIZE; + + request->ttl = irc_ns_get32(current); + current += TTL_SIZE; + + rd_length = irc_ns_get16(current); + current += RDLENGTH_SIZE; + + /* + * Wait to set request->type until we verify this structure + */ + switch (type) + { + case T_A: + if (request->type != T_A) + return 0; + + /* + * check for invalid rd_length or too many addresses + */ + if (rd_length != sizeof(struct in_addr)) + return 0; + + v4 = (struct sockaddr_in *)&request->addr; + request->addr.ss_len = sizeof(struct sockaddr_in); + v4->sin_family = AF_INET; + memcpy(&v4->sin_addr, current, sizeof(struct in_addr)); + return 1; + break; +#ifdef IPV6 + case T_AAAA: + if (request->type != T_AAAA) + return 0; + + if (rd_length != sizeof(struct in6_addr)) + return 0; + + request->addr.ss_len = sizeof(struct sockaddr_in6); + v6 = (struct sockaddr_in6 *)&request->addr; + v6->sin6_family = AF_INET6; + memcpy(&v6->sin6_addr, current, sizeof(struct in6_addr)); + return 1; + break; +#endif + case T_PTR: + if (request->type != T_PTR) + return 0; + + n = irc_dn_expand((unsigned char *)buf, (unsigned char *)eob, + current, hostbuf, sizeof(hostbuf)); + if (n < 0 /* broken message */ || n == 0 /* no more answers left */) + return 0; + + strlcpy(request->name, hostbuf, HOSTLEN + 1); + return 1; + break; + case T_CNAME: /* first check we already havent started looking + into a cname */ + if (request->type != T_PTR) + return 0; + + if (request->state == REQ_CNAME) + { + n = irc_dn_expand((unsigned char *)buf, (unsigned char *)eob, + current, hostbuf, sizeof(hostbuf)); + + if (n < 0) + return 0; + return 1; + } + + request->state = REQ_CNAME; + current += rd_length; + break; + + default: + /* XXX I'd rather just throw away the entire bogus thing + * but its possible its just a broken nameserver with still + * valid answers. But lets do some rudimentary logging for now... + */ + ilog(LOG_TYPE_IRCD, "irc_res.c bogus type %d", type); + break; + } + } + + return 1; +} + +/* + * res_readreply - read a dns reply from the nameserver and process it. + */ +static void +res_readreply(fde_t *fd, void *data) +{ + char buf[sizeof(HEADER) + MAXPACKET] + /* Sparc and alpha need 16bit-alignment for accessing header->id + * (which is uint16_t). Because of the header = (HEADER*) buf; + * lateron, this is neeeded. --FaUl + */ +#if defined(__sparc__) || defined(__alpha__) + __attribute__((aligned (16))) +#endif + ; + HEADER *header; + struct reslist *request = NULL; + int rc; + socklen_t len = sizeof(struct irc_ssaddr); + struct irc_ssaddr lsin; + + rc = recvfrom(fd->fd, buf, sizeof(buf), 0, (struct sockaddr *)&lsin, &len); + + /* Re-schedule a read *after* recvfrom, or we'll be registering + * interest where it'll instantly be ready for read :-) -- adrian + */ + comm_setselect(fd, COMM_SELECT_READ, res_readreply, NULL, 0); + + /* Better to cast the sizeof instead of rc */ + if (rc <= (int)(sizeof(HEADER))) + return; + + /* + * convert DNS reply reader from Network byte order to CPU byte order. + */ + header = (HEADER *)buf; + header->ancount = ntohs(header->ancount); + header->qdcount = ntohs(header->qdcount); + header->nscount = ntohs(header->nscount); + header->arcount = ntohs(header->arcount); + + /* + * check against possibly fake replies + */ + if (!res_ourserver(&lsin)) + return; + + /* + * response for an id which we have already received an answer for + * just ignore this response. + */ + if (!(request = find_id(header->id))) + return; + + if ((header->rcode != NO_ERRORS) || (header->ancount == 0)) + { + if (header->rcode == SERVFAIL || header->rcode == NXDOMAIN) + { + /* + * If a bad error was returned, stop here and don't + * send any more (no retries granted). + */ + (*request->callback)(request->callback_ctx, NULL, NULL); + rem_request(request); + } +#ifdef IPV6 + else + { + /* + * If we havent already tried this, and we're looking up AAAA, try A + * now + */ + if (request->state == REQ_AAAA && request->type == T_AAAA) + { + request->timeout += 4; + resend_query(request); + } + } +#endif + + return; + } + + /* + * If this fails there was an error decoding the received packet, + * try it again and hope it works the next time. + */ + if (proc_answer(request, header, buf, buf + rc)) + { + if (request->type == T_PTR) + { + if (request->name == NULL) + { + /* + * got a PTR response with no name, something bogus is happening + * don't bother trying again, the client address doesn't resolve + */ + (*request->callback)(request->callback_ctx, NULL, NULL); + rem_request(request); + return; + } + + /* + * Lookup the 'authoritative' name that we were given for the + * ip#. + * + */ +#ifdef IPV6 + if (request->addr.ss.ss_family == AF_INET6) + gethost_byname_type(request->callback, request->callback_ctx, request->name, T_AAAA); + else +#endif + gethost_byname_type(request->callback, request->callback_ctx, request->name, T_A); + rem_request(request); + } + else + { + /* + * got a name and address response, client resolved + */ + (*request->callback)(request->callback_ctx, &request->addr, request->name); + rem_request(request); + } + } + else if (!request->sent) + { + /* XXX - we got a response for a query we didn't send with a valid id? + * this should never happen, bail here and leave the client unresolved + */ + assert(0); + + /* XXX don't leak it */ + rem_request(request); + } +} + +void +report_dns_servers(struct Client *source_p) +{ + int i; + char ipaddr[HOSTIPLEN + 1]; + + for (i = 0; i < irc_nscount; i++) + { + getnameinfo((struct sockaddr *)&(irc_nsaddr_list[i]), + irc_nsaddr_list[i].ss_len, ipaddr, + sizeof(ipaddr), NULL, 0, NI_NUMERICHOST); + sendto_one(source_p, form_str(RPL_STATSALINE), + me.name, source_p->name, ipaddr); + } +} diff --git a/src/irc_reslib.c b/src/irc_reslib.c new file mode 100644 index 0000000..42bf2c2 --- /dev/null +++ b/src/irc_reslib.c @@ -0,0 +1,1168 @@ +/* + * Copyright (c) 1985, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Portions Copyright (c) 1993 by Digital Equipment Corporation. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies, and that + * the name of Digital Equipment Corporation not be used in advertising or + * publicity pertaining to distribution of the document or software without + * specific, written prior permission. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT + * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + +/* + * Portions Copyright (c) 1996-1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS + * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE + * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + +/* Original copyright ISC as above. + * Code modified specifically for ircd use from the following orginal files + * in bind ... + * + * res_comp.c + * ns_name.c + * ns_netint.c + * res_init.c + * + * - Dianora + */ + +#include "stdinc.h" +#include "ircd_defs.h" +#include "irc_res.h" +#include "irc_reslib.h" +#include "irc_string.h" + +#define NS_TYPE_ELT 0x40 /* EDNS0 extended label type */ +#define DNS_LABELTYPE_BITSTRING 0x41 +#define MAXLINE 128 + +/* $Id$ */ + +struct irc_ssaddr irc_nsaddr_list[IRCD_MAXNS]; +int irc_nscount = 0; + +static const char digits[] = "0123456789"; +static const char digitvalue[256] = { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*16*/ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*32*/ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*48*/ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, /*64*/ + -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*80*/ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*96*/ + -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*112*/ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*128*/ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*256*/ +}; + +static int labellen(const unsigned char *lp); +static int special(int ch); +static int printable(int ch); +static int irc_decode_bitstring(const unsigned char **cpp, char *dn, const char *eom); +static int irc_ns_name_compress(const char *src, unsigned char *dst, size_t dstsiz, + const unsigned char **dnptrs, const unsigned char **lastdnptr); +static int irc_dn_find(const unsigned char *, const unsigned char *, const unsigned char * const *, + const unsigned char * const *); +static int irc_encode_bitsring(const char **, const char *, unsigned char **, unsigned char **, + const unsigned char *); +static int irc_ns_name_uncompress(const unsigned char *, const unsigned char *, + const unsigned char *, char *, size_t); +static int irc_ns_name_unpack(const unsigned char *, const unsigned char *, + const unsigned char *, unsigned char *, + size_t); +static int irc_ns_name_ntop(const unsigned char *, char *, size_t); +static int irc_ns_name_skip(const unsigned char **, const unsigned char *); +static int mklower(int ch); + + +/* add_nameserver() + * + * input - either an IPV4 address in dotted quad + * or an IPV6 address in : format + * output - NONE + * side effects - entry in irc_nsaddr_list is filled in as needed + */ +static void +add_nameserver(const char *arg) +{ + struct addrinfo hints, *res; + + /* Done max number of nameservers? */ + if (irc_nscount >= IRCD_MAXNS) + return; + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_DGRAM; + hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST; + + if (getaddrinfo(arg, "domain", &hints, &res)) + return; + + if (res == NULL) + return; + + memcpy(&irc_nsaddr_list[irc_nscount].ss, res->ai_addr, res->ai_addrlen); + irc_nsaddr_list[irc_nscount++].ss_len = res->ai_addrlen; + freeaddrinfo(res); +} + +/* parse_resvconf() + * + * inputs - NONE + * output - -1 if failure 0 if success + * side effects - fills in irc_nsaddr_list + */ +static void +parse_resvconf(void) +{ + char *p; + char *opt; + char *arg; + char input[MAXLINE]; + FILE *file; + + /* XXX "/etc/resolv.conf" should be from a define in config.h perhaps + * for cygwin support etc. this hardcodes it to unix for now -db + */ + if ((file = fopen("/etc/resolv.conf", "r")) == NULL) + return; + + while (fgets(input, sizeof(input), file) != NULL) + { + /* blow away any newline */ + if ((p = strpbrk(input, "\r\n")) != NULL) + *p = '\0'; + + p = input; + + /* skip until something thats not a space is seen */ + while (IsSpace(*p)) + ++p; + + /* if at this point, have a '\0' then continue */ + if (*p == '\0') + continue; + + /* Ignore comment lines immediately */ + if (*p == ';' || *p == '#') + continue; + + /* skip until a space is found */ + opt = p; + while (!IsSpace(*p) && *p) + ++p; + + if (*p == '\0') + continue; /* no arguments?.. ignore this line */ + + /* blow away the space character */ + *p++ = '\0'; + + /* skip these spaces that are before the argument */ + while (IsSpace(*p)) + ++p; + + /* Now arg should be right where p is pointing */ + arg = p; + + if ((p = strpbrk(arg, " \t")) != NULL) + *p = '\0'; /* take the first word */ + + if (!irccmp(opt, "nameserver")) + add_nameserver(arg); + } + + fclose(file); +} + +void +irc_res_init(void) +{ + irc_nscount = 0; + memset(irc_nsaddr_list, 0, sizeof(irc_nsaddr_list)); + + parse_resvconf(); + + if (!irc_nscount) + add_nameserver("127.0.0.1"); +} + +/* + * Expand compressed domain name 'comp_dn' to full domain name. + * 'msg' is a pointer to the begining of the message, + * 'eomorig' points to the first location after the message, + * 'exp_dn' is a pointer to a buffer of size 'length' for the result. + * Return size of compressed name or -1 if there was an error. + */ +int +irc_dn_expand(const unsigned char *msg, const unsigned char *eom, + const unsigned char *src, char *dst, int dstsiz) +{ + int n = irc_ns_name_uncompress(msg, eom, src, dst, (size_t)dstsiz); + + if (n > 0 && dst[0] == '.') + dst[0] = '\0'; + return(n); +} /*2*/ + +/* + * irc_ns_name_uncompress(msg, eom, src, dst, dstsiz) + * Expand compressed domain name to presentation format. + * return: + * Number of bytes read out of `src', or -1 (with errno set). + * note: + * Root domain returns as "." not "". + */ +static int +irc_ns_name_uncompress(const unsigned char *msg, const unsigned char *eom, + const unsigned char *src, char *dst, size_t dstsiz) +{ + unsigned char tmp[NS_MAXCDNAME]; + int n; + + if ((n = irc_ns_name_unpack(msg, eom, src, tmp, sizeof tmp)) == -1) + return(-1); + if (irc_ns_name_ntop(tmp, dst, dstsiz) == -1) + return(-1); + return(n); +} /*2*/ + +/* + * irc_ns_name_unpack(msg, eom, src, dst, dstsiz) + * Unpack a domain name from a message, source may be compressed. + * return: + * -1 if it fails, or consumed octets if it succeeds. + */ +static int +irc_ns_name_unpack(const unsigned char *msg, const unsigned char *eom, + const unsigned char *src, unsigned char *dst, + size_t dstsiz) +{ + const unsigned char *srcp, *dstlim; + unsigned char *dstp; + int n, len, checked, l; + + len = -1; + checked = 0; + dstp = dst; + srcp = src; + dstlim = dst + dstsiz; + if (srcp < msg || srcp >= eom) { + errno = EMSGSIZE; + return (-1); + } + /* Fetch next label in domain name. */ + while ((n = *srcp++) != 0) { + /* Check for indirection. */ + switch (n & NS_CMPRSFLGS) { + case 0: + case NS_TYPE_ELT: + /* Limit checks. */ + if ((l = labellen(srcp - 1)) < 0) { + errno = EMSGSIZE; + return(-1); + } + if (dstp + l + 1 >= dstlim || srcp + l >= eom) { + errno = EMSGSIZE; + return (-1); + } + checked += l + 1; + *dstp++ = n; + memcpy(dstp, srcp, l); + dstp += l; + srcp += l; + break; + + case NS_CMPRSFLGS: + if (srcp >= eom) { + errno = EMSGSIZE; + return (-1); + } + if (len < 0) + len = srcp - src + 1; + srcp = msg + (((n & 0x3f) << 8) | (*srcp & 0xff)); + if (srcp < msg || srcp >= eom) { /* Out of range. */ + errno = EMSGSIZE; + return (-1); + } + checked += 2; + /* + * Check for loops in the compressed name; + * if we've looked at the whole message, + * there must be a loop. + */ + if (checked >= eom - msg) { + errno = EMSGSIZE; + return (-1); + } + break; + + default: + errno = EMSGSIZE; + return (-1); /* flag error */ + } + } + *dstp = '\0'; + if (len < 0) + len = srcp - src; + return (len); +} /*2*/ + +/* + * irc_ns_name_ntop(src, dst, dstsiz) + * Convert an encoded domain name to printable ascii as per RFC1035. + * return: + * Number of bytes written to buffer, or -1 (with errno set) + * notes: + * The root is returned as "." + * All other domains are returned in non absolute form + */ +static int +irc_ns_name_ntop(const unsigned char *src, char *dst, size_t dstsiz) +{ + const unsigned char *cp; + char *dn, *eom; + unsigned char c; + unsigned int n; + int l; + + cp = src; + dn = dst; + eom = dst + dstsiz; + + while ((n = *cp++) != 0) { + if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) { + /* Some kind of compression pointer. */ + errno = EMSGSIZE; + return (-1); + } + if (dn != dst) { + if (dn >= eom) { + errno = EMSGSIZE; + return (-1); + } + *dn++ = '.'; + } + if ((l = labellen((cp - 1))) < 0) { + errno = EMSGSIZE; /* XXX */ + return(-1); + } + if (dn + l >= eom) { + errno = EMSGSIZE; + return (-1); + } + if ((n & NS_CMPRSFLGS) == NS_TYPE_ELT) { + int m; + + if (n != DNS_LABELTYPE_BITSTRING) { + /* XXX: labellen should reject this case */ + errno = EINVAL; + return(-1); + } + if ((m = irc_decode_bitstring(&cp, dn, eom)) < 0) + { + errno = EMSGSIZE; + return(-1); + } + dn += m; + continue; + } + for ((void)NULL; l > 0; l--) { + c = *cp++; + if (special(c)) { + if (dn + 1 >= eom) { + errno = EMSGSIZE; + return (-1); + } + *dn++ = '\\'; + *dn++ = (char)c; + } else if (!printable(c)) { + if (dn + 3 >= eom) { + errno = EMSGSIZE; + return (-1); + } + *dn++ = '\\'; + *dn++ = digits[c / 100]; + *dn++ = digits[(c % 100) / 10]; + *dn++ = digits[c % 10]; + } else { + if (dn >= eom) { + errno = EMSGSIZE; + return (-1); + } + *dn++ = (char)c; + } + } + } + if (dn == dst) { + if (dn >= eom) { + errno = EMSGSIZE; + return (-1); + } + *dn++ = '.'; + } + if (dn >= eom) { + errno = EMSGSIZE; + return (-1); + } + *dn++ = '\0'; + return (dn - dst); +} /*2*/ + +/* + * Skip over a compressed domain name. Return the size or -1. + */ +int +irc_dn_skipname(const unsigned char *ptr, const unsigned char *eom) { + const unsigned char *saveptr = ptr; + + if (irc_ns_name_skip(&ptr, eom) == -1) + return(-1); + return(ptr - saveptr); +} /*2*/ + +/* + * ns_name_skip(ptrptr, eom) + * Advance *ptrptr to skip over the compressed name it points at. + * return: + * 0 on success, -1 (with errno set) on failure. + */ +static int +irc_ns_name_skip(const unsigned char **ptrptr, const unsigned char *eom) +{ + const unsigned char *cp; + unsigned int n; + int l; + + cp = *ptrptr; + + while (cp < eom && (n = *cp++) != 0) + { + /* Check for indirection. */ + switch (n & NS_CMPRSFLGS) + { + case 0: /* normal case, n == len */ + cp += n; + continue; + case NS_TYPE_ELT: /* EDNS0 extended label */ + if ((l = labellen(cp - 1)) < 0) + { + errno = EMSGSIZE; /* XXX */ + return(-1); + } + + cp += l; + continue; + case NS_CMPRSFLGS: /* indirection */ + cp++; + break; + default: /* illegal type */ + errno = EMSGSIZE; + return(-1); + } + + break; + } + + if (cp > eom) + { + errno = EMSGSIZE; + return (-1); + } + + *ptrptr = cp; + return(0); +} /*2*/ + +unsigned int +irc_ns_get16(const unsigned char *src) +{ + unsigned int dst; + + IRC_NS_GET16(dst, src); + return(dst); +} + +unsigned long +irc_ns_get32(const unsigned char *src) +{ + unsigned long dst; + + IRC_NS_GET32(dst, src); + return(dst); +} + +void +irc_ns_put16(unsigned int src, unsigned char *dst) +{ + IRC_NS_PUT16(src, dst); +} + +void +irc_ns_put32(unsigned long src, unsigned char *dst) +{ + IRC_NS_PUT32(src, dst); +} + +/* From ns_name.c */ + +/* + * special(ch) + * Thinking in noninternationalized USASCII (per the DNS spec), + * is this characted special ("in need of quoting") ? + * return: + * boolean. + */ +static int +special(int ch) +{ + switch (ch) + { + case 0x22: /* '"' */ + case 0x2E: /* '.' */ + case 0x3B: /* ';' */ + case 0x5C: /* '\\' */ + case 0x28: /* '(' */ + case 0x29: /* ')' */ + /* Special modifiers in zone files. */ + case 0x40: /* '@' */ + case 0x24: /* '$' */ + return(1); + default: + return(0); + } +} /*2*/ + +static int +labellen(const unsigned char *lp) +{ + int bitlen; + unsigned char l = *lp; + + if ((l & NS_CMPRSFLGS) == NS_CMPRSFLGS) + { + /* should be avoided by the caller */ + return(-1); + } + + if ((l & NS_CMPRSFLGS) == NS_TYPE_ELT) + { + if (l == DNS_LABELTYPE_BITSTRING) + { + if ((bitlen = *(lp + 1)) == 0) + bitlen = 256; + return((bitlen + 7 ) / 8 + 1); + } + + return(-1); /* unknwon ELT */ + } + + return(l); +} /*2*/ + + +/* + * printable(ch) + * Thinking in noninternationalized USASCII (per the DNS spec), + * is this character visible and not a space when printed ? + * return: + * boolean. + */ +static int +printable(int ch) +{ + return(ch > 0x20 && ch < 0x7f); +} /*2*/ + +static int +irc_decode_bitstring(const unsigned char **cpp, char *dn, const char *eom) +{ + const unsigned char *cp = *cpp; + char *beg = dn, tc; + int b, blen, plen; + + if ((blen = (*cp & 0xff)) == 0) + blen = 256; + plen = (blen + 3) / 4; + plen += sizeof("\\[x/]") + (blen > 99 ? 3 : (blen > 9) ? 2 : 1); + if (dn + plen >= eom) + return(-1); + + cp++; + dn += sprintf(dn, "\\[x"); + for (b = blen; b > 7; b -= 8, cp++) + dn += sprintf(dn, "%02x", *cp & 0xff); + if (b > 4) { + tc = *cp++; + dn += sprintf(dn, "%02x", tc & (0xff << (8 - b))); + } else if (b > 0) { + tc = *cp++; + dn += sprintf(dn, "%1x", + ((tc >> 4) & 0x0f) & (0x0f << (4 - b))); + } + dn += sprintf(dn, "/%d]", blen); + + *cpp = cp; + return(dn - beg); +} /*2*/ + +/* + * irc_ns_name_pton(src, dst, dstsiz) + * Convert a ascii string into an encoded domain name as per RFC1035. + * return: + * -1 if it fails + * 1 if string was fully qualified + * 0 is string was not fully qualified + * notes: + * Enforces label and domain length limits. + */ +static int +irc_ns_name_pton(const char *src, unsigned char *dst, size_t dstsiz) +{ + unsigned char *label, *bp, *eom; + char *cp; + int c, n, escaped, e = 0; + + escaped = 0; + bp = dst; + eom = dst + dstsiz; + label = bp++; + + + while ((c = *src++) != 0) { + if (escaped) { + if (c == '[') { /* start a bit string label */ + if ((cp = strchr(src, ']')) == NULL) { + errno = EINVAL; /* ??? */ + return(-1); + } + if ((e = irc_encode_bitsring(&src, + cp + 2, + &label, + &bp, + eom)) + != 0) { + errno = e; + return(-1); + } + escaped = 0; + label = bp++; + if ((c = *src++) == 0) + goto done; + else if (c != '.') { + errno = EINVAL; + return(-1); + } + continue; + } + else if ((cp = strchr(digits, c)) != NULL) { + n = (cp - digits) * 100; + if ((c = *src++) == 0 || + (cp = strchr(digits, c)) == NULL) { + errno = EMSGSIZE; + return (-1); + } + n += (cp - digits) * 10; + if ((c = *src++) == 0 || + (cp = strchr(digits, c)) == NULL) { + errno = EMSGSIZE; + return (-1); + } + n += (cp - digits); + if (n > 255) { + errno = EMSGSIZE; + return (-1); + } + c = n; + } + escaped = 0; + } else if (c == '\\') { + escaped = 1; + continue; + } else if (c == '.') { + c = (bp - label - 1); + if ((c & NS_CMPRSFLGS) != 0) { /* Label too big. */ + errno = EMSGSIZE; + return (-1); + } + if (label >= eom) { + errno = EMSGSIZE; + return (-1); + } + *label = c; + /* Fully qualified ? */ + if (*src == '\0') { + if (c != 0) { + if (bp >= eom) { + errno = EMSGSIZE; + return (-1); + } + *bp++ = '\0'; + } + if ((bp - dst) > NS_MAXCDNAME) { + errno = EMSGSIZE; + return (-1); + } + return (1); + } + if (c == 0 || *src == '.') { + errno = EMSGSIZE; + return (-1); + } + label = bp++; + continue; + } + if (bp >= eom) { + errno = EMSGSIZE; + return (-1); + } + *bp++ = (unsigned char)c; + } + c = (bp - label - 1); + if ((c & NS_CMPRSFLGS) != 0) { /* Label too big. */ + errno = EMSGSIZE; + return (-1); + } + done: + if (label >= eom) { + errno = EMSGSIZE; + return (-1); + } + *label = c; + if (c != 0) { + if (bp >= eom) { + errno = EMSGSIZE; + return (-1); + } + *bp++ = 0; + } + + if ((bp - dst) > NS_MAXCDNAME) + { /* src too big */ + errno = EMSGSIZE; + return (-1); + } + + return (0); +} /*2*/ + +/* + * irc_ns_name_pack(src, dst, dstsiz, dnptrs, lastdnptr) + * Pack domain name 'domain' into 'comp_dn'. + * return: + * Size of the compressed name, or -1. + * notes: + * 'dnptrs' is an array of pointers to previous compressed names. + * dnptrs[0] is a pointer to the beginning of the message. The array + * ends with NULL. + * 'lastdnptr' is a pointer to the end of the array pointed to + * by 'dnptrs'. + * Side effects: + * The list of pointers in dnptrs is updated for labels inserted into + * the message as we compress the name. If 'dnptr' is NULL, we don't + * try to compress names. If 'lastdnptr' is NULL, we don't update the + * list. + */ +static int +irc_ns_name_pack(const unsigned char *src, unsigned char *dst, int dstsiz, + const unsigned char **dnptrs, const unsigned char **lastdnptr) +{ + unsigned char *dstp; + const unsigned char **cpp, **lpp, *eob, *msg; + const unsigned char *srcp; + int n, l, first = 1; + + srcp = src; + dstp = dst; + eob = dstp + dstsiz; + lpp = cpp = NULL; + if (dnptrs != NULL) { + if ((msg = *dnptrs++) != NULL) { + for (cpp = dnptrs; *cpp != NULL; cpp++) + (void)NULL; + lpp = cpp; /* end of list to search */ + } + } else + msg = NULL; + + /* make sure the domain we are about to add is legal */ + l = 0; + do { + int l0; + + n = *srcp; + if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) { + errno = EMSGSIZE; + return (-1); + } + if ((l0 = labellen(srcp)) < 0) { + errno = EINVAL; + return(-1); + } + l += l0 + 1; + if (l > NS_MAXCDNAME) { + errno = EMSGSIZE; + return (-1); + } + srcp += l0 + 1; + } while (n != 0); + + /* from here on we need to reset compression pointer array on error */ + srcp = src; + do { + /* Look to see if we can use pointers. */ + n = *srcp; + if (n != 0 && msg != NULL) { + l = irc_dn_find(srcp, msg, (const unsigned char * const *)dnptrs, + (const unsigned char * const *)lpp); + if (l >= 0) { + if (dstp + 1 >= eob) { + goto cleanup; + } + *dstp++ = (l >> 8) | NS_CMPRSFLGS; + *dstp++ = l % 256; + return (dstp - dst); + } + /* Not found, save it. */ + if (lastdnptr != NULL && cpp < lastdnptr - 1 && + (dstp - msg) < 0x4000 && first) { + *cpp++ = dstp; + *cpp = NULL; + first = 0; + } + } + /* copy label to buffer */ + if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) { + /* Should not happen. */ + goto cleanup; + } + n = labellen(srcp); + if (dstp + 1 + n >= eob) { + goto cleanup; + } + memcpy(dstp, srcp, n + 1); + srcp += n + 1; + dstp += n + 1; + } while (n != 0); + + if (dstp > eob) { +cleanup: + if (msg != NULL) + *lpp = NULL; + errno = EMSGSIZE; + return (-1); + } + return(dstp - dst); +} /*2*/ + +static int +irc_ns_name_compress(const char *src, unsigned char *dst, size_t dstsiz, + const unsigned char **dnptrs, const unsigned char **lastdnptr) +{ + unsigned char tmp[NS_MAXCDNAME]; + + if (irc_ns_name_pton(src, tmp, sizeof tmp) == -1) + return(-1); + return(irc_ns_name_pack(tmp, dst, dstsiz, dnptrs, lastdnptr)); +} + +static int +irc_encode_bitsring(const char **bp, const char *end, unsigned char **labelp, + unsigned char **dst, const unsigned char *eom) +{ + int afterslash = 0; + const char *cp = *bp; + unsigned char *tp; + char c; + const char *beg_blen; + char *end_blen = NULL; + int value = 0, count = 0, tbcount = 0, blen = 0; + + beg_blen = end_blen = NULL; + + /* a bitstring must contain at least 2 characters */ + if (end - cp < 2) + return(EINVAL); + + /* XXX: currently, only hex strings are supported */ + if (*cp++ != 'x') + return(EINVAL); + if (!isxdigit((*cp) & 0xff)) /* reject '\[x/BLEN]' */ + return(EINVAL); + + for (tp = *dst + 1; cp < end && tp < eom; cp++) { + switch((c = *cp)) { + case ']': /* end of the bitstring */ + if (afterslash) { + if (beg_blen == NULL) + return(EINVAL); + blen = (int)strtol(beg_blen, &end_blen, 10); + if (*end_blen != ']') + return(EINVAL); + } + if (count) + *tp++ = ((value << 4) & 0xff); + cp++; /* skip ']' */ + goto done; + case '/': + afterslash = 1; + break; + default: + if (afterslash) { + if (!isdigit(c&0xff)) + return(EINVAL); + if (beg_blen == NULL) { + + if (c == '0') { + /* blen never begings with 0 */ + return(EINVAL); + } + beg_blen = cp; + } + } else { + if (!isxdigit(c&0xff)) + return(EINVAL); + value <<= 4; + value += digitvalue[(int)c]; + count += 4; + tbcount += 4; + if (tbcount > 256) + return(EINVAL); + if (count == 8) { + *tp++ = value; + count = 0; + } + } + break; + } + } + done: + if (cp >= end || tp >= eom) + return(EMSGSIZE); + + /* + * bit length validation: + * If a <length> is present, the number of digits in the <bit-data> + * MUST be just sufficient to contain the number of bits specified + * by the <length>. If there are insignificant bits in a final + * hexadecimal or octal digit, they MUST be zero. + * RFC 2673, Section 3.2. + */ + if (blen > 0) { + int traillen; + + if (((blen + 3) & ~3) != tbcount) + return(EINVAL); + traillen = tbcount - blen; /* between 0 and 3 */ + if (((value << (8 - traillen)) & 0xff) != 0) + return(EINVAL); + } + else + blen = tbcount; + if (blen == 256) + blen = 0; + + /* encode the type and the significant bit fields */ + **labelp = DNS_LABELTYPE_BITSTRING; + **dst = blen; + + *bp = cp; + *dst = tp; + + return(0); +} /*2*/ + +/* + * dn_find(domain, msg, dnptrs, lastdnptr) + * Search for the counted-label name in an array of compressed names. + * return: + * offset from msg if found, or -1. + * notes: + * dnptrs is the pointer to the first name on the list, + * not the pointer to the start of the message. + */ +static int +irc_dn_find(const unsigned char *domain, const unsigned char *msg, + const unsigned char * const *dnptrs, + const unsigned char * const *lastdnptr) +{ + const unsigned char *dn, *cp, *sp; + const unsigned char * const *cpp; + unsigned int n; + + for (cpp = dnptrs; cpp < lastdnptr; cpp++) + { + sp = *cpp; + /* + * terminate search on: + * root label + * compression pointer + * unusable offset + */ + while (*sp != 0 && (*sp & NS_CMPRSFLGS) == 0 && + (sp - msg) < 0x4000) { + dn = domain; + cp = sp; + while ((n = *cp++) != 0) { + /* + * check for indirection + */ + switch (n & NS_CMPRSFLGS) { + case 0: /* normal case, n == len */ + n = labellen(cp - 1); /* XXX */ + + if (n != *dn++) + goto next; + + for ((void)NULL; n > 0; n--) + if (mklower(*dn++) != + mklower(*cp++)) + goto next; + /* Is next root for both ? */ + if (*dn == '\0' && *cp == '\0') + return (sp - msg); + if (*dn) + continue; + goto next; + case NS_CMPRSFLGS: /* indirection */ + cp = msg + (((n & 0x3f) << 8) | *cp); + break; + + default: /* illegal type */ + errno = EMSGSIZE; + return (-1); + } + } + next: ; + sp += *sp + 1; + } + } + errno = ENOENT; + return (-1); +} /*2*/ + +/* + * * Thinking in noninternationalized USASCII (per the DNS spec), + * * convert this character to lower case if it's upper case. + * */ +static int +mklower(int ch) +{ + if (ch >= 0x41 && ch <= 0x5A) + return(ch + 0x20); + + return(ch); +} /*2*/ + +/* From resolv/mkquery.c */ + +/* + * Form all types of queries. + * Returns the size of the result or -1. + */ +int +irc_res_mkquery( + const char *dname, /* domain name */ + int class, int type, /* class and type of query */ + unsigned char *buf, /* buffer to put query */ + int buflen) /* size of buffer */ +{ + HEADER *hp; + unsigned char *cp; + int n; + const unsigned char *dnptrs[20], **dpp, **lastdnptr; + + /* + * Initialize header fields. + */ + if ((buf == NULL) || (buflen < HFIXEDSZ)) + return (-1); + memset(buf, 0, HFIXEDSZ); + hp = (HEADER *) buf; + + hp->id = 0; + hp->opcode = QUERY; + hp->rd = 1; /* recurse */ + hp->rcode = NO_ERRORS; + cp = buf + HFIXEDSZ; + buflen -= HFIXEDSZ; + dpp = dnptrs; + *dpp++ = buf; + *dpp++ = NULL; + lastdnptr = dnptrs + sizeof dnptrs / sizeof dnptrs[0]; + + if ((buflen -= QFIXEDSZ) < 0) + return (-1); + if ((n = irc_ns_name_compress(dname, cp, buflen, dnptrs, + lastdnptr)) < 0) + return (-1); + + cp += n; + buflen -= n; + IRC_NS_PUT16(type, cp); + IRC_NS_PUT16(class, cp); + hp->qdcount = htons(1); + + return (cp - buf); +} diff --git a/src/irc_string.c b/src/irc_string.c new file mode 100644 index 0000000..08b4321 --- /dev/null +++ b/src/irc_string.c @@ -0,0 +1,263 @@ +/* + * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd). + * irc_string.c: IRC string functions. + * + * Copyright (C) 2002 by the past and present ircd coders, and others. + * + * 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 + * + * $Id$ + */ + +#include "config.h" +#ifdef HAVE_LIBPCRE +#include <pcre.h> +#endif + +#include "stdinc.h" +#include "irc_string.h" +#include "sprintf_irc.h" + + +int +has_wildcards(const char *s) +{ + char c; + + while ((c = *s++)) + if (IsMWildChar(c)) + return 1; + + return 0; +} + +/* + * myctime - This is like standard ctime()-function, but it zaps away + * the newline from the end of that string. Also, it takes + * the time value as parameter, instead of pointer to it. + * Note that it is necessary to copy the string to alternate + * buffer (who knows how ctime() implements it, maybe it statically + * has newline there and never 'refreshes' it -- zapping that + * might break things in other places...) + * + * + * Thu Nov 24 18:22:48 1986 + */ +const char * +myctime(time_t value) +{ + static char buf[32]; + char *p; + + strcpy(buf, ctime(&value)); + + if ((p = strchr(buf, '\n')) != NULL) + *p = '\0'; + return buf; +} + +/* + * strip_tabs(dst, src, length) + * + * Copies src to dst, while converting all \t (tabs) into spaces. + */ +void +strip_tabs(char *dest, const char *src, size_t len) +{ + char *d = dest; + + /* Sanity check; we don't want anything nasty... */ + assert(dest != NULL); + assert(src != NULL); + assert(len > 0); + + for (; --len && *src; ++src) + *d++ = *src == '\t' ? ' ' : *src; + + *d = '\0'; /* NUL terminate, thanks and goodbye */ +} + +/* + * strtoken - walk through a string of tokens, using a set of separators + * argv 9/90 + * + */ +#ifndef HAVE_STRTOK_R + +char * +strtoken(char** save, char* str, const char* fs) +{ + char* pos = *save; /* keep last position across calls */ + char* tmp; + + if (str) + pos = str; /* new string scan */ + + while (pos && *pos && strchr(fs, *pos) != NULL) + ++pos; /* skip leading separators */ + + if (!pos || !*pos) + return (pos = *save = NULL); /* string contains only sep's */ + + tmp = pos; /* now, keep position of the token */ + + while (*pos && strchr(fs, *pos) == NULL) + ++pos; /* skip content of the token */ + + if (*pos) + *pos++ = '\0'; /* remove first sep after the token */ + else + pos = NULL; /* end of string */ + + *save = pos; + return tmp; +} +#endif /* !HAVE_STRTOK_R */ + +/* libio_basename() + * + * input - i.e. "/usr/local/ircd/modules/m_whois.so" + * output - i.e. "m_whois.so" + * side effects - this will be overwritten on subsequent calls + */ +const char * +libio_basename(const char *path) +{ + const char *s; + + if ((s = strrchr(path, '/')) == NULL) + s = path; + else + s++; + + return s; +} + +/* + * strlcat and strlcpy were ripped from openssh 2.5.1p2 + * They had the following Copyright info: + * + * + * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED `AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef HAVE_STRLCAT +size_t +strlcat(char *dst, const char *src, size_t siz) +{ + char *d = dst; + const char *s = src; + size_t n = siz, dlen; + + while (n-- != 0 && *d != '\0') + d++; + + dlen = d - dst; + n = siz - dlen; + + if (n == 0) + return dlen + strlen(s); + + while (*s != '\0') + { + if (n != 1) + { + *d++ = *s; + n--; + } + + s++; + } + + *d = '\0'; + return dlen + (s - src); /* count does not include NUL */ +} +#endif + +#ifndef HAVE_STRLCPY +size_t +strlcpy(char *dst, const char *src, size_t siz) +{ + char *d = dst; + const char *s = src; + size_t n = siz; + + /* Copy as many bytes as will fit */ + if (n != 0 && --n != 0) + { + do + { + if ((*d++ = *s++) == 0) + break; + } while (--n != 0); + } + + /* Not enough room in dst, add NUL and traverse rest of src */ + if (n == 0) + { + if (siz != 0) + *d = '\0'; /* NUL-terminate dst */ + while (*s++) + ; + } + + return s - src - 1; /* count does not include NUL */ +} +#endif + +#ifdef HAVE_LIBPCRE +void * +ircd_pcre_compile(const char *pattern, const char **errptr) +{ + int erroroffset = 0; + int options = PCRE_EXTRA; + + assert(pattern); + + return pcre_compile(pattern, options, errptr, &erroroffset, NULL); +} + +int +ircd_pcre_exec(const void *code, const char *subject) +{ + assert(code && subject); + + return pcre_exec(code, NULL, subject, strlen(subject), 0, 0, NULL, 0) < 0; +} +#endif diff --git a/src/ircd.c b/src/ircd.c new file mode 100644 index 0000000..ee02bcd --- /dev/null +++ b/src/ircd.c @@ -0,0 +1,658 @@ +/* + * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd). + * ircd.c: Starts up and runs the ircd. + * + * Copyright (C) 2002 by the past and present ircd coders, and others. + * + * 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 + * + * $Id$ + */ + +#include "stdinc.h" +#include "s_user.h" +#include "list.h" +#include "ircd.h" +#include "channel.h" +#include "channel_mode.h" +#include "client.h" +#include "event.h" +#include "fdlist.h" +#include "hash.h" +#include "irc_string.h" +#include "ircd_signal.h" +#include "s_gline.h" +#include "motd.h" +#include "hostmask.h" +#include "numeric.h" +#include "packet.h" +#include "parse.h" +#include "irc_res.h" +#include "restart.h" +#include "rng_mt.h" +#include "s_auth.h" +#include "s_bsd.h" +#include "conf.h" +#include "log.h" +#include "s_misc.h" +#include "s_serv.h" /* try_connections */ +#include "send.h" +#include "whowas.h" +#include "modules.h" +#include "memory.h" +#include "hook.h" +#include "ircd_getopt.h" +#include "balloc.h" +#include "motd.h" +#include "supported.h" +#include "watch.h" + + +/* /quote set variables */ +struct SetOptions GlobalSetOptions; + +/* configuration set from ircd.conf */ +struct config_file_entry ConfigFileEntry; +/* server info set from ircd.conf */ +struct server_info ServerInfo; +/* admin info set from ircd.conf */ +struct admin_info AdminInfo = { NULL, NULL, NULL }; +struct Counter Count = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; +struct ServerState_t server_state = { 0 }; +struct logging_entry ConfigLoggingEntry = { .use_logging = 1 }; +struct ServerStatistics ServerStats; +struct timeval SystemTime; +struct Client me; /* That's me */ +struct LocalUser meLocalUser; /* That's also part of me */ + +const char *logFileName = LPATH; +const char *pidFileName = PPATH; + +char **myargv; + +int dorehash = 0; +int doremotd = 0; + +/* Set to zero because it should be initialized later using + * initialize_server_capabs + */ +int default_server_capabs = 0; +unsigned int splitmode; +unsigned int splitchecking; +unsigned int split_users; +unsigned int split_servers; + +/* Do klines the same way hybrid-6 did them, i.e. at the + * top of the next io_loop instead of in the same loop as + * the klines are being applied. + * + * This should fix strange CPU starvation as very indirectly reported. + * (Why do you people not email bug reports? WHY? WHY?) + * + * - Dianora + */ + +int rehashed_klines = 0; + + +/* + * print_startup - print startup information + */ +static void +print_startup(int pid) +{ + printf("ircd: version %s\n", ircd_version); + printf("ircd: pid %d\n", pid); + printf("ircd: running in %s mode from %s\n", !server_state.foreground ? "background" + : "foreground", ConfigFileEntry.dpath); +} + +static void +make_daemon(void) +{ + int pid; + + if ((pid = fork()) < 0) + { + perror("fork"); + exit(EXIT_FAILURE); + } + else if (pid > 0) + { + print_startup(pid); + exit(EXIT_SUCCESS); + } + + setsid(); +} + +static int printVersion = 0; + +static struct lgetopt myopts[] = { + {"dlinefile", &ConfigFileEntry.dlinefile, + STRING, "File to use for dline.conf"}, + {"configfile", &ConfigFileEntry.configfile, + STRING, "File to use for ircd.conf"}, + {"klinefile", &ConfigFileEntry.klinefile, + STRING, "File to use for kline.conf"}, + {"xlinefile", &ConfigFileEntry.xlinefile, + STRING, "File to use for xline.conf"}, + {"logfile", &logFileName, + STRING, "File to use for ircd.log"}, + {"pidfile", &pidFileName, + STRING, "File to use for process ID"}, + {"foreground", &server_state.foreground, + YESNO, "Run in foreground (don't detach)"}, + {"version", &printVersion, + YESNO, "Print version and exit"}, + {"help", NULL, USAGE, "Print this text"}, + {NULL, NULL, STRING, NULL}, +}; + +void +set_time(void) +{ + static char to_send[200]; + struct timeval newtime; + newtime.tv_sec = 0; + newtime.tv_usec = 0; + + if (gettimeofday(&newtime, NULL) == -1) + { + ilog(LOG_TYPE_IRCD, "Clock Failure (%s), TS can be corrupted", + strerror(errno)); + sendto_realops_flags(UMODE_ALL, L_ALL, + "Clock Failure (%s), TS can be corrupted", + strerror(errno)); + restart("Clock Failure"); + } + + if (newtime.tv_sec < CurrentTime) + { + snprintf(to_send, sizeof(to_send), + "System clock is running backwards - (%lu < %lu)", + (unsigned long)newtime.tv_sec, (unsigned long)CurrentTime); + report_error(L_ALL, to_send, me.name, 0); + set_back_events(CurrentTime - newtime.tv_sec); + } + + SystemTime.tv_sec = newtime.tv_sec; + SystemTime.tv_usec = newtime.tv_usec; +} + +static void +io_loop(void) +{ + while (1 == 1) + { + /* + * Maybe we want a flags word? + * ie. if (REHASHED_KLINES(global_flags)) + * SET_REHASHED_KLINES(global_flags) + * CLEAR_REHASHED_KLINES(global_flags) + * + * - Dianora + */ + if (rehashed_klines) + { + check_conf_klines(); + rehashed_klines = 0; + } + + if (listing_client_list.head) + { + dlink_node *ptr = NULL, *ptr_next = NULL; + DLINK_FOREACH_SAFE(ptr, ptr_next, listing_client_list.head) + { + struct Client *client_p = ptr->data; + assert(client_p->localClient->list_task); + safe_list_channels(client_p, client_p->localClient->list_task, 0); + } + } + + /* Run pending events, then get the number of seconds to the next + * event + */ + while (eventNextTime() <= CurrentTime) + eventRun(); + + comm_select(); + exit_aborted_clients(); + free_exited_clients(); + send_queued_all(); + + /* Check to see whether we have to rehash the configuration .. */ + if (dorehash) + { + rehash(1); + dorehash = 0; + } + if (doremotd) + { + read_message_file(&ConfigFileEntry.motd); + sendto_realops_flags(UMODE_ALL, L_ALL, + "Got signal SIGUSR1, reloading ircd motd file"); + doremotd = 0; + } + } +} + +/* initalialize_global_set_options() + * + * inputs - none + * output - none + * side effects - This sets all global set options needed + */ +static void +initialize_global_set_options(void) +{ + memset(&GlobalSetOptions, 0, sizeof(GlobalSetOptions)); + + GlobalSetOptions.autoconn = 1; + GlobalSetOptions.spam_time = MIN_JOIN_LEAVE_TIME; + GlobalSetOptions.spam_num = MAX_JOIN_LEAVE_COUNT; + + if (ConfigFileEntry.default_floodcount) + GlobalSetOptions.floodcount = ConfigFileEntry.default_floodcount; + else + GlobalSetOptions.floodcount = 10; + + /* XXX I have no idea what to try here - Dianora */ + GlobalSetOptions.joinfloodcount = 16; + GlobalSetOptions.joinfloodtime = 8; + + split_servers = ConfigChannel.default_split_server_count; + split_users = ConfigChannel.default_split_user_count; + + if (split_users && split_servers && (ConfigChannel.no_create_on_split || + ConfigChannel.no_join_on_split)) + { + splitmode = 1; + splitchecking = 1; + } + + GlobalSetOptions.ident_timeout = IDENT_TIMEOUT; + /* End of global set options */ +} + +/* initialize_message_files() + * + * inputs - none + * output - none + * side effects - Set up all message files needed, motd etc. + */ +static void +initialize_message_files(void) +{ + init_message_file(USER_MOTD, MPATH, &ConfigFileEntry.motd); + init_message_file(USER_LINKS, LIPATH, &ConfigFileEntry.linksfile); + + read_message_file(&ConfigFileEntry.motd); + read_message_file(&ConfigFileEntry.linksfile); + + init_isupport(); +} + +/* initialize_server_capabs() + * + * inputs - none + * output - none + */ +static void +initialize_server_capabs(void) +{ + add_capability("QS", CAP_QS, 1); + add_capability("EOB", CAP_EOB, 1); + add_capability("TS6", CAP_TS6, 0); + add_capability("CLUSTER", CAP_CLUSTER, 1); + add_capability("SVS", CAP_SVS, 1); +#ifdef HALFOPS + add_capability("HOPS", CAP_HOPS, 1); +#endif +} + +/* write_pidfile() + * + * inputs - filename+path of pid file + * output - NONE + * side effects - write the pid of the ircd to filename + */ +static void +write_pidfile(const char *filename) +{ + FILE *fb; + + if ((fb = fopen(filename, "w"))) + { + char buff[32]; + unsigned int pid = (unsigned int)getpid(); + + snprintf(buff, sizeof(buff), "%u\n", pid); + + if ((fputs(buff, fb) == -1)) + ilog(LOG_TYPE_IRCD, "Error writing %u to pid file %s (%s)", + pid, filename, strerror(errno)); + + fclose(fb); + } + else + { + ilog(LOG_TYPE_IRCD, "Error opening pid file %s", filename); + } +} + +/* check_pidfile() + * + * inputs - filename+path of pid file + * output - none + * side effects - reads pid from pidfile and checks if ircd is in process + * list. if it is, gracefully exits + * -kre + */ +static void +check_pidfile(const char *filename) +{ + FILE *fb; + char buff[32]; + pid_t pidfromfile; + + /* Don't do logging here, since we don't have log() initialised */ + if ((fb = fopen(filename, "r"))) + { + if (fgets(buff, 20, fb) == NULL) + { + /* log(L_ERROR, "Error reading from pid file %s (%s)", filename, + * strerror(errno)); + */ + } + else + { + pidfromfile = atoi(buff); + + if (!kill(pidfromfile, 0)) + { + /* log(L_ERROR, "Server is already running"); */ + printf("ircd: daemon is already running\n"); + exit(-1); + } + } + + fclose(fb); + } + else if (errno != ENOENT) + { + /* log(L_ERROR, "Error opening pid file %s", filename); */ + } +} + +/* setup_corefile() + * + * inputs - nothing + * output - nothing + * side effects - setups corefile to system limits. + * -kre + */ +static void +setup_corefile(void) +{ +#ifdef HAVE_SYS_RESOURCE_H + struct rlimit rlim; /* resource limits */ + + /* Set corefilesize to maximum */ + if (!getrlimit(RLIMIT_CORE, &rlim)) + { + rlim.rlim_cur = rlim.rlim_max; + setrlimit(RLIMIT_CORE, &rlim); + } +#endif +} + +/* init_ssl() + * + * inputs - nothing + * output - nothing + * side effects - setups SSL context. + */ +static void +init_ssl(void) +{ +#ifdef HAVE_LIBCRYPTO + SSL_load_error_strings(); + SSLeay_add_ssl_algorithms(); + + if ((ServerInfo.server_ctx = SSL_CTX_new(SSLv23_server_method())) == NULL) + { + const char *s; + + fprintf(stderr, "ERROR: Could not initialize the SSL Server context -- %s\n", + s = ERR_lib_error_string(ERR_get_error())); + ilog(LOG_TYPE_IRCD, "ERROR: Could not initialize the SSL Server context -- %s\n", s); + } + + SSL_CTX_set_options(ServerInfo.server_ctx, SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3|SSL_OP_NO_TLSv1); + SSL_CTX_set_options(ServerInfo.server_ctx, SSL_OP_TLS_ROLLBACK_BUG|SSL_OP_ALL); + SSL_CTX_set_verify(ServerInfo.server_ctx, SSL_VERIFY_NONE, NULL); + + if ((ServerInfo.client_ctx = SSL_CTX_new(SSLv23_client_method())) == NULL) + { + const char *s; + + fprintf(stderr, "ERROR: Could not initialize the SSL Client context -- %s\n", + s = ERR_lib_error_string(ERR_get_error())); + ilog(LOG_TYPE_IRCD, "ERROR: Could not initialize the SSL Client context -- %s\n", s); + } + + SSL_CTX_set_options(ServerInfo.client_ctx, SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3|SSL_OP_NO_TLSv1); + SSL_CTX_set_options(ServerInfo.client_ctx, SSL_OP_TLS_ROLLBACK_BUG|SSL_OP_ALL); + SSL_CTX_set_verify(ServerInfo.client_ctx, SSL_VERIFY_NONE, NULL); +#endif /* HAVE_LIBCRYPTO */ +} + +/* init_callbacks() + * + * inputs - nothing + * output - nothing + * side effects - setups standard hook points + */ +static void +init_callbacks(void) +{ + iorecv_cb = register_callback("iorecv", iorecv_default); + iosend_cb = register_callback("iosend", iosend_default); +} + +int +main(int argc, char *argv[]) +{ + /* Check to see if the user is running + * us as root, which is a nono + */ + if (geteuid() == 0) + { + fprintf(stderr, "Don't run ircd as root!!!\n"); + return -1; + } + + /* Setup corefile size immediately after boot -kre */ + setup_corefile(); + + /* save server boot time right away, so getrusage works correctly */ + set_time(); + + /* It ain't random, but it ought to be a little harder to guess */ + init_genrand(SystemTime.tv_sec ^ (SystemTime.tv_usec | (getpid() << 20))); + + me.localClient = &meLocalUser; + dlinkAdd(&me, &me.node, &global_client_list); /* Pointer to beginning + of Client list */ + /* Initialise the channel capability usage counts... */ + init_chcap_usage_counts(); + + ConfigFileEntry.dpath = DPATH; + ConfigFileEntry.configfile = CPATH; /* Server configuration file */ + ConfigFileEntry.klinefile = KPATH; /* Server kline file */ + ConfigFileEntry.xlinefile = XPATH; /* Server xline file */ + ConfigFileEntry.dlinefile = DLPATH; /* dline file */ + ConfigFileEntry.cresvfile = CRESVPATH; /* channel resv file */ + ConfigFileEntry.nresvfile = NRESVPATH; /* nick resv file */ + myargv = argv; + umask(077); /* better safe than sorry --SRB */ + + parseargs(&argc, &argv, myopts); + + if (printVersion) + { + printf("ircd: version %s\n", ircd_version); + exit(EXIT_SUCCESS); + } + + if (chdir(ConfigFileEntry.dpath)) + { + perror("chdir"); + exit(EXIT_FAILURE); + } + + init_ssl(); + + if (!server_state.foreground) + { + make_daemon(); + close_standard_fds(); /* this needs to be before init_netio()! */ + } + else + print_startup(getpid()); + + setup_signals(); + + /* Init the event subsystem */ + eventInit(); + /* We need this to initialise the fd array before anything else */ + fdlist_init(); + log_add_file(LOG_TYPE_IRCD, 0, logFileName); + check_can_use_v6(); + init_comm(); /* This needs to be setup early ! -- adrian */ + /* Check if there is pidfile and daemon already running */ + check_pidfile(pidFileName); + + initBlockHeap(); + init_dlink_nodes(); + init_callbacks(); + initialize_message_files(); + dbuf_init(); + init_hash(); + init_ip_hash_table(); /* client host ip hash table */ + init_host_hash(); /* Host-hashtable. */ + init_client(); + init_class(); + whowas_init(); + watch_init(); + init_auth(); /* Initialise the auth code */ + init_resolver(); /* Needs to be setup before the io loop */ + modules_init(); + read_conf_files(1); /* cold start init conf files */ + init_uid(); + initialize_server_capabs(); /* Set up default_server_capabs */ + initialize_global_set_options(); + init_channels(); + + if (EmptyString(ServerInfo.sid)) + { + ilog(LOG_TYPE_IRCD, "ERROR: No server id specified in serverinfo block."); + exit(EXIT_FAILURE); + } + + strlcpy(me.id, ServerInfo.sid, sizeof(me.id)); + + if (EmptyString(ServerInfo.name)) + { + ilog(LOG_TYPE_IRCD, "ERROR: No server name specified in serverinfo block."); + exit(EXIT_FAILURE); + } + + strlcpy(me.name, ServerInfo.name, sizeof(me.name)); + + /* serverinfo{} description must exist. If not, error out.*/ + if (EmptyString(ServerInfo.description)) + { + ilog(LOG_TYPE_IRCD, "ERROR: No server description specified in serverinfo block."); + exit(EXIT_FAILURE); + } + + strlcpy(me.info, ServerInfo.description, sizeof(me.info)); + + me.from = &me; + me.servptr = &me; + me.localClient->lasttime = CurrentTime; + me.localClient->since = CurrentTime; + me.localClient->firsttime = CurrentTime; + + SetMe(&me); + make_server(&me); + + hash_add_id(&me); + hash_add_client(&me); + + /* add ourselves to global_serv_list */ + dlinkAdd(&me, make_dlink_node(), &global_serv_list); + + if (chdir(MODPATH)) + { + ilog(LOG_TYPE_IRCD, "Could not load core modules. Terminating!"); + exit(EXIT_FAILURE); + } + + load_all_modules(1); + load_conf_modules(); + load_core_modules(1); + + /* Go back to DPATH after checking to see if we can chdir to MODPATH */ + if (chdir(ConfigFileEntry.dpath)) + { + perror("chdir"); + exit(EXIT_FAILURE); + } + + /* + * assemble_umode_buffer() has to be called after + * reading conf/loading modules. + */ + assemble_umode_buffer(); + + write_pidfile(pidFileName); + + ilog(LOG_TYPE_IRCD, "Server Ready"); + + eventAddIsh("cleanup_glines", cleanup_glines, NULL, CLEANUP_GLINES_TIME); + eventAddIsh("cleanup_tklines", cleanup_tklines, NULL, CLEANUP_TKLINES_TIME); + + /* We want try_connections to be called as soon as possible now! -- adrian */ + /* No, 'cause after a restart it would cause all sorts of nick collides */ + eventAddIsh("try_connections", try_connections, NULL, STARTUP_CONNECTIONS_TIME); + + /* Setup the timeout check. I'll shift it later :) -- adrian */ + eventAddIsh("comm_checktimeouts", comm_checktimeouts, NULL, 1); + + if (ConfigServerHide.links_delay > 0) + eventAddIsh("write_links_file", write_links_file, NULL, ConfigServerHide.links_delay); + else + ConfigServerHide.links_disabled = 1; + + if (splitmode) + eventAddIsh("check_splitmode", check_splitmode, NULL, 60); + + io_loop(); + return 0; +} diff --git a/src/ircd_signal.c b/src/ircd_signal.c new file mode 100644 index 0000000..b76e542 --- /dev/null +++ b/src/ircd_signal.c @@ -0,0 +1,135 @@ +/* + * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd). + * ircd_signal.c: responsible for ircd's signal handling + * + * Copyright (C) 2002 by the past and present ircd coders, and others. + * + * 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 + * + * $Id$ + */ + +#include "stdinc.h" +#include "list.h" +#include "ircd_signal.h" +#include "ircd.h" /* dorehash */ +#include "restart.h" /* server_die */ +#include "memory.h" +#include "s_bsd.h" + +/* + * sigterm_handler - exit the server + */ +static void +sigterm_handler(int sig) +{ + server_die("received signal SIGTERM", 0); +} + +/* + * sighup_handler - reread the server configuration + */ +static void +sighup_handler(int sig) +{ + dorehash = 1; +} + +/* + * sigusr1_handler - reread the motd file + */ +static void +sigusr1_handler(int sig) +{ + doremotd = 1; +} + +/* + * + * inputs - nothing + * output - nothing + * side effects - Reaps zombies periodically + * -AndroSyn + */ +static void +sigchld_handler(int sig) +{ + int status; + waitpid(-1, &status, WNOHANG); +} + +/* + * sigint_handler - restart the server + */ +static void +sigint_handler(int sig) +{ + server_die("SIGINT received", !server_state.foreground); +} + +/* + * setup_signals - initialize signal handlers for server + */ +void +setup_signals(void) +{ + struct sigaction act; + + act.sa_flags = 0; + act.sa_handler = SIG_IGN; + + sigemptyset(&act.sa_mask); + sigaddset(&act.sa_mask, SIGPIPE); + sigaddset(&act.sa_mask, SIGALRM); + sigaction(SIGALRM, &act, 0); +#ifdef SIGTRAP + sigaddset(&act.sa_mask, SIGTRAP); +#endif +#ifdef SIGXFSZ + sigaddset(&act.sa_mask, SIGXFSZ); + sigaction(SIGXFSZ, &act, 0); +#endif + +#ifdef SIGWINCH + sigaddset(&act.sa_mask, SIGWINCH); + sigaction(SIGWINCH, &act, 0); +#endif + sigaction(SIGPIPE, &act, 0); +#ifdef SIGTRAP + sigaction(SIGTRAP, &act, 0); +#endif + + act.sa_handler = sighup_handler; + sigemptyset(&act.sa_mask); + sigaddset(&act.sa_mask, SIGHUP); + sigaction(SIGHUP, &act, 0); + + act.sa_handler = sigint_handler; + sigaddset(&act.sa_mask, SIGINT); + sigaction(SIGINT, &act, 0); + + act.sa_handler = sigterm_handler; + sigaddset(&act.sa_mask, SIGTERM); + sigaction(SIGTERM, &act, 0); + + act.sa_handler = sigusr1_handler; + sigaddset(&act.sa_mask, SIGUSR1); + sigaction(SIGUSR1, &act, 0); + + act.sa_handler = sigchld_handler; + sigaddset(&act.sa_mask, SIGCHLD); + sigaction(SIGCHLD, &act, 0); +} diff --git a/src/list.c b/src/list.c new file mode 100644 index 0000000..2850d46 --- /dev/null +++ b/src/list.c @@ -0,0 +1,277 @@ +/* + * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd). + * list.c: Various assorted functions for various structures. + * + * Copyright (C) 2002 by the past and present ircd coders, and others. + * + * 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 + * + * $Id$ + */ + +#include "stdinc.h" +#include "list.h" +#include "balloc.h" + +static BlockHeap *dnode_heap; + + +/* init_dlink_nodes() + * + * inputs - NONE + * output - NONE + * side effects - initializes the dnode BlockHeap + */ +void +init_dlink_nodes(void) +{ + dnode_heap = BlockHeapCreate("dlink node", sizeof(dlink_node), DNODE_HEAP_SIZE); +} + +/* make_dlink_node() + * + * inputs - NONE + * output - pointer to new dlink_node + * side effects - NONE + */ +dlink_node * +make_dlink_node(void) +{ + dlink_node *lp = BlockHeapAlloc(dnode_heap); + + return lp; +} + +/* free_dlink_node() + * + * inputs - pointer to dlink_node + * output - NONE + * side effects - free given dlink_node + */ +void +free_dlink_node(dlink_node *ptr) +{ + BlockHeapFree(dnode_heap, ptr); +} + +/* + * dlink_ routines are stolen from squid, except for dlinkAddBefore, + * which is mine. + * -- adrian + */ +void +dlinkAdd(void *data, dlink_node *m, dlink_list *list) +{ + m->data = data; + m->prev = NULL; + m->next = list->head; + + /* Assumption: If list->tail != NULL, list->head != NULL */ + if (list->head != NULL) + list->head->prev = m; + else if (list->tail == NULL) + list->tail = m; + + list->head = m; + list->length++; +} + +void +dlinkAddBefore(dlink_node *b, void *data, dlink_node *m, dlink_list *list) +{ + /* Shortcut - if its the first one, call dlinkAdd only */ + if (b == list->head) + dlinkAdd(data, m, list); + else + { + m->data = data; + b->prev->next = m; + m->prev = b->prev; + b->prev = m; + m->next = b; + list->length++; + } +} + +void +dlinkAddTail(void *data, dlink_node *m, dlink_list *list) +{ + m->data = data; + m->next = NULL; + m->prev = list->tail; + + /* Assumption: If list->tail != NULL, list->head != NULL */ + if (list->tail != NULL) + list->tail->next = m; + else if (list->head == NULL) + list->head = m; + + list->tail = m; + list->length++; +} + +/* Execution profiles show that this function is called the most + * often of all non-spontaneous functions. So it had better be + * efficient. */ +void +dlinkDelete(dlink_node *m, dlink_list *list) +{ + /* Assumption: If m->next == NULL, then list->tail == m + * and: If m->prev == NULL, then list->head == m + */ + if (m->next) + m->next->prev = m->prev; + else + { + assert(list->tail == m); + list->tail = m->prev; + } + + if (m->prev) + m->prev->next = m->next; + else + { + assert(list->head == m); + list->head = m->next; + } + + /* Set this to NULL does matter */ + m->next = m->prev = NULL; + list->length--; +} + +/* + * dlinkFind + * inputs - list to search + * - data + * output - pointer to link or NULL if not found + * side effects - Look for ptr in the linked listed pointed to by link. + */ +dlink_node * +dlinkFind(dlink_list *list, void *data) +{ + dlink_node *ptr; + + DLINK_FOREACH(ptr, list->head) + if (ptr->data == data) + return ptr; + + return NULL; +} + +void +dlinkMoveList(dlink_list *from, dlink_list *to) +{ + /* There are three cases */ + /* case one, nothing in from list */ + if (from->head == NULL) + return; + + /* case two, nothing in to list */ + /* actually if to->head is NULL and to->tail isn't, thats a bug */ + if (to->head == NULL) + { + to->head = from->head; + to->tail = from->tail; + from->head = from->tail = NULL; + to->length = from->length; + from->length = 0; + return; + } + + /* third case play with the links */ + from->tail->next = to->head; + from->head->prev = to->head->prev; + to->head->prev = from->tail; + to->head = from->head; + from->head = from->tail = NULL; + to->length += from->length; + from->length = 0; + /* I think I got that right */ +} + +void +dlink_move_node(dlink_node *m, dlink_list *list_del, dlink_list *list_add) +{ + /* Assumption: If m->next == NULL, then list_del->tail == m + * and: If m->prev == NULL, then list_del->head == m + */ + if (m->next) + m->next->prev = m->prev; + else + { + assert(list->tail == m); + list_del->tail = m->prev; + } + + if (m->prev) + m->prev->next = m->next; + else + { + assert(list->head == m); + list_del->head = m->next; + } + + /* Set this to NULL does matter */ + m->prev = NULL; + m->next = list_add->head; + + /* Assumption: If list_add->tail != NULL, list_add->head != NULL */ + if (list_add->head != NULL) + list_add->head->prev = m; + else if (list_add->tail == NULL) + list_add->tail = m; + + list_add->head = m; + list_add->length++; + list_del->length--; +} + +dlink_node * +dlinkFindDelete(dlink_list *list, void *data) +{ + dlink_node *m; + + DLINK_FOREACH(m, list->head) + { + if (m->data == data) + { + if (m->next) + m->next->prev = m->prev; + else + { + assert(list->tail == m); + list->tail = m->prev; + } + if (m->prev) + m->prev->next = m->next; + else + { + assert(list->head == m); + list->head = m->next; + } + /* Set this to NULL does matter */ + m->next = m->prev = NULL; + list->length--; + + return m; + } + } + + return NULL; +} + + diff --git a/src/listener.c b/src/listener.c new file mode 100644 index 0000000..3572570 --- /dev/null +++ b/src/listener.c @@ -0,0 +1,429 @@ +/* + * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd). + * listener.c: Listens on a port. + * + * Copyright (C) 2002 by the past and present ircd coders, and others. + * + * 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 + * + * $Id$ + */ + +#include "stdinc.h" +#include "list.h" +#include "listener.h" +#include "client.h" +#include "fdlist.h" +#include "irc_string.h" +#include "sprintf_irc.h" +#include "ircd.h" +#include "ircd_defs.h" +#include "s_bsd.h" +#include "numeric.h" +#include "conf.h" +#include "send.h" +#include "memory.h" + +static PF accept_connection; + +static dlink_list ListenerPollList = { NULL, NULL, 0 }; +static void close_listener(struct Listener *listener); + +static struct Listener * +make_listener(int port, struct irc_ssaddr *addr) +{ + struct Listener *listener = MyMalloc(sizeof(struct Listener)); + + listener->port = port; + memcpy(&listener->addr, addr, sizeof(struct irc_ssaddr)); + + return listener; +} + +void +free_listener(struct Listener *listener) +{ + assert(listener != NULL); + + dlinkDelete(&listener->listener_node, &ListenerPollList); + MyFree(listener); +} + +/* + * get_listener_name - return displayable listener name and port + * returns "host.foo.org/6667" for a given listener + */ +const char * +get_listener_name(const struct Listener *const listener) +{ + static char buf[HOSTLEN + HOSTLEN + PORTNAMELEN + 4]; + + snprintf(buf, sizeof(buf), "%s[%s/%u]", me.name, + listener->name, listener->port); + return buf; +} + +/* show_ports() + * + * inputs - pointer to client to show ports to + * output - none + * side effects - send port listing to a client + */ +void +show_ports(struct Client *source_p) +{ + char buf[6]; + char *p = NULL; + dlink_node *ptr; + + DLINK_FOREACH(ptr, ListenerPollList.head) + { + const struct Listener *listener = ptr->data; + p = buf; + + if (listener->flags & LISTENER_HIDDEN) { + if (!HasUMode(source_p, UMODE_ADMIN)) + continue; + *p++ = 'H'; + } + + if (listener->flags & LISTENER_SERVER) + *p++ = 'S'; + if (listener->flags & LISTENER_SSL) + *p++ = 's'; + *p = '\0'; + sendto_one(source_p, form_str(RPL_STATSPLINE), + me.name, source_p->name, 'P', listener->port, + HasUMode(source_p, UMODE_ADMIN) ? listener->name : me.name, + listener->ref_count, buf, + listener->active ? "active" : "disabled"); + } +} + +/* + * inetport - create a listener socket in the AF_INET or AF_INET6 domain, + * bind it to the port given in 'port' and listen to it + * returns true (1) if successful false (0) on error. + * + * If the operating system has a define for SOMAXCONN, use it, otherwise + * use HYBRID_SOMAXCONN + */ +#ifdef SOMAXCONN +#undef HYBRID_SOMAXCONN +#define HYBRID_SOMAXCONN SOMAXCONN +#endif + +static int +inetport(struct Listener *listener) +{ + struct irc_ssaddr lsin; + socklen_t opt = 1; + + memset(&lsin, 0, sizeof(lsin)); + memcpy(&lsin, &listener->addr, sizeof(lsin)); + + getnameinfo((struct sockaddr *)&lsin, lsin.ss_len, listener->name, + sizeof(listener->name), NULL, 0, NI_NUMERICHOST); + + /* + * At first, open a new socket + */ + if (comm_open(&listener->fd, listener->addr.ss.ss_family, SOCK_STREAM, 0, + "Listener socket") == -1) + { + report_error(L_ALL, "opening listener socket %s:%s", + get_listener_name(listener), errno); + return 0; + } + + if (setsockopt(listener->fd.fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt))) + { + report_error(L_ALL, "setting SO_REUSEADDR for listener %s:%s", + get_listener_name(listener), errno); + fd_close(&listener->fd); + return 0; + } + + /* + * Bind a port to listen for new connections if port is non-null, + * else assume it is already open and try get something from it. + */ + lsin.ss_port = htons(listener->port); + + if (bind(listener->fd.fd, (struct sockaddr *)&lsin, lsin.ss_len)) + { + report_error(L_ALL, "binding listener socket %s:%s", + get_listener_name(listener), errno); + fd_close(&listener->fd); + return 0; + } + + if (listen(listener->fd.fd, HYBRID_SOMAXCONN)) + { + report_error(L_ALL, "listen failed for %s:%s", + get_listener_name(listener), errno); + fd_close(&listener->fd); + return 0; + } + + /* Listen completion events are READ events .. */ + + accept_connection(&listener->fd, listener); + return 1; +} + +static struct Listener * +find_listener(int port, struct irc_ssaddr *addr) +{ + dlink_node *ptr; + struct Listener *listener = NULL; + struct Listener *last_closed = NULL; + + DLINK_FOREACH(ptr, ListenerPollList.head) + { + listener = ptr->data; + + if ((port == listener->port) && + (!memcmp(addr, &listener->addr, sizeof(struct irc_ssaddr)))) + { + /* Try to return an open listener, otherwise reuse a closed one */ + if (!listener->fd.flags.open) + last_closed = listener; + else + return (listener); + } + } + + return (last_closed); +} + +/* + * add_listener- create a new listener + * port - the port number to listen on + * vhost_ip - if non-null must contain a valid IP address string in + * the format "255.255.255.255" + */ +void +add_listener(int port, const char *vhost_ip, unsigned int flags) +{ + struct Listener *listener; + struct irc_ssaddr vaddr; + struct addrinfo hints, *res; + char portname[PORTNAMELEN + 1]; +#ifdef IPV6 + static short int pass = 0; /* if ipv6 and no address specified we need to + have two listeners; one for each protocol. */ +#endif + + /* + * if no or invalid port in conf line, don't bother + */ + if (!(port > 0 && port <= 0xFFFF)) + return; + + memset(&vaddr, 0, sizeof(vaddr)); + + /* Set up the hints structure */ + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + /* Get us ready for a bind() and don't bother doing dns lookup */ + hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST; + +#ifdef IPV6 + if (ServerInfo.can_use_v6) + { + snprintf(portname, sizeof(portname), "%d", port); + getaddrinfo("::", portname, &hints, &res); + vaddr.ss.ss_family = AF_INET6; + assert(res != NULL); + + memcpy((struct sockaddr*)&vaddr, res->ai_addr, res->ai_addrlen); + vaddr.ss_port = port; + vaddr.ss_len = res->ai_addrlen; + freeaddrinfo(res); + } + else +#endif + { + struct sockaddr_in *v4 = (struct sockaddr_in*) &vaddr; + v4->sin_addr.s_addr = INADDR_ANY; + vaddr.ss.ss_family = AF_INET; + vaddr.ss_len = sizeof(struct sockaddr_in); + v4->sin_port = htons(port); + } + + snprintf(portname, PORTNAMELEN, "%d", port); + + if (vhost_ip) + { + if (getaddrinfo(vhost_ip, portname, &hints, &res)) + return; + + assert(res != NULL); + + memcpy((struct sockaddr*)&vaddr, res->ai_addr, res->ai_addrlen); + vaddr.ss_port = port; + vaddr.ss_len = res->ai_addrlen; + freeaddrinfo(res); + } +#ifdef IPV6 + else if (pass == 0 && ServerInfo.can_use_v6) + { + /* add the ipv4 listener if we havent already */ + pass = 1; + add_listener(port, "0.0.0.0", flags); + } + pass = 0; +#endif + + if ((listener = find_listener(port, &vaddr))) + { + listener->flags = flags; + if (listener->fd.flags.open) + return; + } + else + { + listener = make_listener(port, &vaddr); + dlinkAdd(listener, &listener->listener_node, &ListenerPollList); + listener->flags = flags; + } + + if (inetport(listener)) + listener->active = 1; + else + close_listener(listener); +} + +/* + * close_listener - close a single listener + */ +static void +close_listener(struct Listener *listener) +{ + assert(listener != NULL); + + if (listener == NULL) + return; + + if (listener->fd.flags.open) + fd_close(&listener->fd); + + listener->active = 0; + + if (listener->ref_count) + return; + + free_listener(listener); +} + +/* + * close_listeners - close and free all listeners that are not being used + */ +void +close_listeners(void) +{ + dlink_node *ptr = NULL, *next_ptr = NULL; + + /* close all 'extra' listening ports we have */ + DLINK_FOREACH_SAFE(ptr, next_ptr, ListenerPollList.head) + close_listener(ptr->data); +} + +#define TOOFAST_WARNING "ERROR :Trying to reconnect too fast.\r\n" +#define DLINE_WARNING "ERROR :You have been D-lined.\r\n" + +static void +accept_connection(fde_t *pfd, void *data) +{ + static time_t last_oper_notice = 0; + struct irc_ssaddr addr; + int fd; + int pe; + struct Listener *listener = data; + + memset(&addr, 0, sizeof(addr)); + + assert(listener != NULL); + + /* There may be many reasons for error return, but + * in otherwise correctly working environment the + * probable cause is running out of file descriptors + * (EMFILE, ENFILE or others?). The man pages for + * accept don't seem to list these as possible, + * although it's obvious that it may happen here. + * Thus no specific errors are tested at this + * point, just assume that connections cannot + * be accepted until some old is closed first. + */ + while ((fd = comm_accept(listener, &addr)) != -1) + { + /* + * check for connection limit + */ + if (number_fd > hard_fdlimit - 10) + { + ++ServerStats.is_ref; + + /* + * slow down the whining to opers bit + */ + if ((last_oper_notice + 20) <= CurrentTime) + { + sendto_realops_flags(UMODE_ALL, L_ALL, "All connections in use. (%s)", + get_listener_name(listener)); + last_oper_notice = CurrentTime; + } + + if (!(listener->flags & LISTENER_SSL)) + send(fd, "ERROR :All connections in use\r\n", 32, 0); + + close(fd); + break; /* jump out and re-register a new io request */ + } + + /* + * Do an initial check we aren't connecting too fast or with too many + * from this IP... + */ + if ((pe = conf_connect_allowed(&addr, addr.ss.ss_family)) != 0) + { + ++ServerStats.is_ref; + + if (!(listener->flags & LISTENER_SSL)) + switch (pe) + { + case BANNED_CLIENT: + send(fd, DLINE_WARNING, sizeof(DLINE_WARNING)-1, 0); + break; + case TOO_FAST: + send(fd, TOOFAST_WARNING, sizeof(TOOFAST_WARNING)-1, 0); + break; + } + + close(fd); + continue; /* drop the one and keep on clearing the queue */ + } + + ++ServerStats.is_ac; + add_connection(listener, &addr, fd); + } + + /* Re-register a new IO request for the next accept .. */ + comm_setselect(&listener->fd, COMM_SELECT_READ, accept_connection, + listener, 0); +} diff --git a/src/log.c b/src/log.c new file mode 100644 index 0000000..e81257b --- /dev/null +++ b/src/log.c @@ -0,0 +1,123 @@ +/* + * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd). + * log.c: Logger functions. + * + * Copyright (C) 2002 by the past and present ircd coders, and others. + * + * 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 + * + * $Id$ + */ + +#include "stdinc.h" + +#include "log.h" +#include "irc_string.h" +#include "ircd.h" +#include "conf.h" +#include "s_misc.h" + + +static struct { + char path[PATH_MAX + 1]; + size_t size; + FILE *file; +} log_type_table[LOG_TYPE_LAST]; + + +int +log_add_file(enum log_type type, size_t size, const char *path) +{ + if (log_type_table[type].file) + fclose(log_type_table[type].file); + + strlcpy(log_type_table[type].path, path, sizeof(log_type_table[type].path)); + log_type_table[type].size = size; + + return (log_type_table[type].file = fopen(path, "a")) != NULL; +} + +void +log_close_all(void) +{ + unsigned int type = 0; + + while (++type < LOG_TYPE_LAST) + { + if (log_type_table[type].file == NULL) + continue; + + fclose(log_type_table[type].file); + log_type_table[type].file = NULL; + } +} + +static int +log_exceed_size(unsigned int type) +{ + struct stat sb; + + if (!log_type_table[type].size) + return 0; + + if (stat(log_type_table[type].path, &sb) < 0) + return -1; + + return (size_t)sb.st_size > log_type_table[type].size; +} + +static void +log_write(enum log_type type, const char *message) +{ + char buf[IRCD_BUFSIZE]; + + strftime(buf, sizeof(buf), "[%FT%H:%M:%S%z]", localtime(&CurrentTime)); + + fprintf(log_type_table[type].file, "%s %s\n", buf, message); + fflush(log_type_table[type].file); +} + +void +ilog(enum log_type type, const char *fmt, ...) +{ + char buf[LOG_BUFSIZE]; + va_list args; + + if (!log_type_table[type].file || !ConfigLoggingEntry.use_logging) + return; + + va_start(args, fmt); + vsnprintf(buf, sizeof(buf), fmt, args); + va_end(args); + + log_write(type, buf); + + if (log_exceed_size(type) <= 0) + return; + + snprintf(buf, sizeof(buf), "Rotating logfile %s", + log_type_table[type].path); + log_write(type, buf); + + fclose(log_type_table[type].file); + log_type_table[type].file = NULL; + + snprintf(buf, sizeof(buf), "%s.old", log_type_table[type].path); + unlink(buf); + rename(log_type_table[type].path, buf); + + log_add_file(type, log_type_table[type].size, log_type_table[type].path); +} diff --git a/src/match.c b/src/match.c new file mode 100644 index 0000000..4c4513e --- /dev/null +++ b/src/match.c @@ -0,0 +1,616 @@ +/************************************************************************ + * IRC - Internet Relay Chat, src/match.c + * Copyright (C) 1990 Jarkko Oikarinen + * + * 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 1, 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Id$ + * + */ + +#include "stdinc.h" +#include "irc_string.h" +#include "client.h" +#include "ircd.h" + +/* Fix "statement not reached" warnings on Sun WorkShop C */ +#ifdef __SUNPRO_C +# pragma error_messages(off, E_STATEMENT_NOT_REACHED) +#endif + +/* match() + * + * Compare if a given string (name) matches the given + * mask (which can contain wild cards: '*' - match any + * number of chars, '?' - match any single character. + * + * return 1, if match + * 0, if no match + * + * Originally by Douglas A Lewis (dalewis@acsu.buffalo.edu) + */ +int +match(const char *mask, const char *name) +{ + const unsigned char *m = (const unsigned char *)mask; + const unsigned char *n = (const unsigned char *)name; + const unsigned char *ma = NULL; + const unsigned char *na = (const unsigned char *)name; + + assert(mask != NULL); + assert(name != NULL); + + while (1) + { + if (*m == '*') + { + while (*m == '*') + m++; + ma = m; + na = n; + } + + if (!*m) + { + if (!*n) + return 1; + if (!ma) + return 0; + for (m--; (m > (const unsigned char *)mask) && (*m == '?'); m--) + ; + if (*m == '*') + return 1; + m = ma; + n = ++na; + } + else if (!*n) + { + while (*m == '*') + m++; + return *m == 0; + } + + if (ToLower(*m) != ToLower(*n) && *m != '?' && (*m != '#' || !IsDigit(*n))) + { + if (!ma) + return 0; + m = ma; + n = ++na; + } + else + m++, n++; + } + + return 0; +} + +/* match_esc() + * + * The match() function with support for escaping characters such + * as '*' and '?' + */ +int +match_esc(const char *mask, const char *name) +{ + const unsigned char *m = (const unsigned char *)mask; + const unsigned char *n = (const unsigned char *)name; + const unsigned char *ma = NULL; + const unsigned char *na = (const unsigned char *)name; + + assert(mask != NULL); + assert(name != NULL); + + while (1) + { + if (*m == '*') + { + while (*m == '*') + m++; + ma = m; + na = n; + } + + if (!*m) + { + if (!*n) + return 1; + if (!ma) + return 0; + for (m--; (m > (const unsigned char *)mask) && (*m == '?'); m--) + ; + if (*m == '*') + return 1; + m = ma; + n = ++na; + } + else if (!*n) + { + while (*m == '*') + m++; + return *m == 0; + } + + if (*m != '?' && (*m != '#' || IsDigit(*n))) + { + if (*m == '\\') + if (!*++m) + return 0; + if (ToLower(*m) != ToLower(*n)) + { + if (!ma) + return 0; + m = ma; + n = ++na; + } + else + m++, n++; + } + else + m++, n++; + } + + return 0; +} + +/* match_chan() + * + * The match_esc() function doing channel prefix auto-escape, + * ie. mask: #blah*blah is seen like \#blah*blah + */ +int +match_chan(const char *mask, const char *name) +{ + if (*mask == '#') + { + if (*name != '#') + return 0; + ++name, ++mask; + } + + return match_esc(mask, name); +} + +/* collapse() + * + * collapses a string containing multiple *'s. + */ +char * +collapse(char *pattern) +{ + char *p = pattern, *po = pattern; + char c; + + if (p == NULL) + return NULL; + + while ((c = *p++)) + { + if (c != '*') + *po++ = c; + else if (*p != '*') + *po++ = '*'; + } + + *po = 0; + + return pattern; +} + +/* collapse_esc() + * + * The collapse() function with support for escaping characters + */ +char * +collapse_esc(char *pattern) +{ + char *p = pattern, *po = pattern; + char c; + + if (p == NULL) + return NULL; + + while ((c = *p++)) + { + if (c != '*') + { + *po++ = c; + if (c == '\\' && *p) + *po++ = *p++; + } + else if (*p != '*') + *po++ = '*'; + } + + *po = 0; + + return pattern; +} + +/* + * irccmp - case insensitive comparison of two 0 terminated strings. + * + * returns 0, if s1 equal to s2 + * 1, if not + */ +int +irccmp(const char *s1, const char *s2) +{ + const unsigned char *str1 = (const unsigned char *)s1; + const unsigned char *str2 = (const unsigned char *)s2; + + assert(s1 != NULL); + assert(s2 != NULL); + + for (; ToUpper(*str1) == ToUpper(*str2); ++str1, ++str2) + if (*str1 == '\0') + return 0; + + return 1; +} + +int +ircncmp(const char *s1, const char *s2, size_t n) +{ + const unsigned char *str1 = (const unsigned char *)s1; + const unsigned char *str2 = (const unsigned char *)s2; + + assert(s1 != NULL); + assert(s2 != NULL); + assert(n > 0); + + if (n == 0) + return 0; + + for (; ToUpper(*str1) == ToUpper(*str2); ++str1, ++str2) + if (--n == 0 || *str1 == '\0') + return 0; + + return 1; +} + +const unsigned char ToLowerTab[] = { + 0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, + 0xb, 0xc, 0xd, 0xe, 0xf, 0x10, 0x11, 0x12, 0x13, 0x14, + 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, + 0x1e, 0x1f, + ' ', '!', '"', '#', '$', '%', '&', 0x27, '(', ')', + '*', '+', ',', '-', '.', '/', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + ':', ';', '<', '=', '>', '?', + '@', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', + 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', + 't', 'u', 'v', 'w', 'x', 'y', 'z', '{', '|', '}', '~', + '_', + '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', + 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', + 't', 'u', 'v', 'w', 'x', 'y', 'z', '{', '|', '}', '~', + 0x7f, + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, + 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, + 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, + 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, + 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, + 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, + 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, + 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, + 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, + 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, + 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, + 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, + 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, + 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, + 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, + 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff +}; + +const unsigned char ToUpperTab[] = { + 0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, + 0xb, 0xc, 0xd, 0xe, 0xf, 0x10, 0x11, 0x12, 0x13, 0x14, + 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, + 0x1e, 0x1f, + ' ', '!', '"', '#', '$', '%', '&', 0x27, '(', ')', + '*', '+', ',', '-', '.', '/', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + ':', ';', '<', '=', '>', '?', + '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', + 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', + 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '[', '\\', ']', '^', + 0x5f, + '`', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', + 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', + 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '[', '\\', ']', '^', + 0x7f, + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, + 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, + 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, + 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, + 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, + 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, + 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, + 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, + 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, + 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, + 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, + 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, + 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, + 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, + 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, + 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff +}; + +/* + * CharAttrs table + * + * NOTE: RFC 1459 sez: anything but a ^G, comma, or space is allowed + * for channel names + */ +const unsigned int CharAttrs[] = { +/* 0 */ CNTRL_C, +/* 1 */ CNTRL_C|CHAN_C|VCHAN_C|NONEOS_C, +/* 2 */ CNTRL_C|CHAN_C|NONEOS_C, +/* 3 */ CNTRL_C|CHAN_C|NONEOS_C, +/* 4 */ CNTRL_C|CHAN_C|VCHAN_C|NONEOS_C, +/* 5 */ CNTRL_C|CHAN_C|VCHAN_C|NONEOS_C, +/* 6 */ CNTRL_C|CHAN_C|VCHAN_C|NONEOS_C, +/* 7 BEL */ CNTRL_C|NONEOS_C, +/* 8 \b */ CNTRL_C|CHAN_C|VCHAN_C|NONEOS_C, +/* 9 \t */ CNTRL_C|SPACE_C|CHAN_C|VCHAN_C|NONEOS_C, +/* 10 \n */ CNTRL_C|SPACE_C|CHAN_C|VCHAN_C|NONEOS_C|EOL_C, +/* 11 \v */ CNTRL_C|SPACE_C|CHAN_C|VCHAN_C|NONEOS_C, +/* 12 \f */ CNTRL_C|SPACE_C|CHAN_C|VCHAN_C|NONEOS_C, +/* 13 \r */ CNTRL_C|SPACE_C|CHAN_C|VCHAN_C|NONEOS_C|EOL_C, +/* 14 */ CNTRL_C|CHAN_C|VCHAN_C|NONEOS_C, +/* 15 */ CNTRL_C|CHAN_C|NONEOS_C, +/* 16 */ CNTRL_C|CHAN_C|VCHAN_C|NONEOS_C, +/* 17 */ CNTRL_C|CHAN_C|VCHAN_C|NONEOS_C, +/* 18 */ CNTRL_C|CHAN_C|VCHAN_C|NONEOS_C, +/* 19 */ CNTRL_C|CHAN_C|VCHAN_C|NONEOS_C, +/* 20 */ CNTRL_C|CHAN_C|VCHAN_C|NONEOS_C, +/* 21 */ CNTRL_C|CHAN_C|VCHAN_C|NONEOS_C, +/* 22 */ CNTRL_C|CHAN_C|NONEOS_C, +/* 23 */ CNTRL_C|CHAN_C|VCHAN_C|NONEOS_C, +/* 24 */ CNTRL_C|CHAN_C|VCHAN_C|NONEOS_C, +/* 25 */ CNTRL_C|CHAN_C|VCHAN_C|NONEOS_C, +/* 26 */ CNTRL_C|CHAN_C|VCHAN_C|NONEOS_C, +/* 27 */ CNTRL_C|CHAN_C|VCHAN_C|NONEOS_C, +/* 28 */ CNTRL_C|CHAN_C|VCHAN_C|NONEOS_C, +/* 29 */ CNTRL_C|CHAN_C|NONEOS_C, +/* 30 */ CNTRL_C|CHAN_C|VCHAN_C|NONEOS_C, +/* 31 */ CNTRL_C|CHAN_C|NONEOS_C, +/* SP */ PRINT_C|SPACE_C, +/* ! */ PRINT_C|KWILD_C|CHAN_C|VCHAN_C|NONEOS_C, +/* " */ PRINT_C|CHAN_C|VCHAN_C|NONEOS_C, +/* # */ PRINT_C|KWILD_C|MWILD_C|CHANPFX_C|CHAN_C|VCHAN_C|NONEOS_C, +/* $ */ PRINT_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C, +/* % */ PRINT_C|CHAN_C|VCHAN_C|NONEOS_C, +/* & */ PRINT_C|CHAN_C|VCHAN_C|NONEOS_C, +/* ' */ PRINT_C|CHAN_C|VCHAN_C|NONEOS_C, +/* ( */ PRINT_C|CHAN_C|VCHAN_C|NONEOS_C, +/* ) */ PRINT_C|CHAN_C|VCHAN_C|NONEOS_C, +/* * */ PRINT_C|KWILD_C|MWILD_C|CHAN_C|VCHAN_C|NONEOS_C|SERV_C, +/* + */ PRINT_C|CHAN_C|VCHAN_C|NONEOS_C, +/* , */ PRINT_C|NONEOS_C, +/* - */ PRINT_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C|HOST_C, +/* . */ PRINT_C|KWILD_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C|HOST_C|SERV_C, +/* / */ PRINT_C|CHAN_C|VCHAN_C|NONEOS_C, +/* 0 */ PRINT_C|DIGIT_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C|HOST_C, +/* 1 */ PRINT_C|DIGIT_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C|HOST_C, +/* 2 */ PRINT_C|DIGIT_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C|HOST_C, +/* 3 */ PRINT_C|DIGIT_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C|HOST_C, +/* 4 */ PRINT_C|DIGIT_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C|HOST_C, +/* 5 */ PRINT_C|DIGIT_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C|HOST_C, +/* 6 */ PRINT_C|DIGIT_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C|HOST_C, +/* 7 */ PRINT_C|DIGIT_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C|HOST_C, +/* 8 */ PRINT_C|DIGIT_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C|HOST_C, +/* 9 */ PRINT_C|DIGIT_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C|HOST_C, +/* : */ PRINT_C|KWILD_C|CHAN_C|VCHAN_C|NONEOS_C|HOST_C, +/* ; */ PRINT_C|CHAN_C|VCHAN_C|NONEOS_C, +/* < */ PRINT_C|CHAN_C|VCHAN_C|NONEOS_C, +/* = */ PRINT_C|CHAN_C|VCHAN_C|NONEOS_C, +/* > */ PRINT_C|CHAN_C|VCHAN_C|NONEOS_C, +/* ? */ PRINT_C|KWILD_C|MWILD_C|CHAN_C|VCHAN_C|NONEOS_C, +/* @ */ PRINT_C|KWILD_C|CHAN_C|VCHAN_C|NONEOS_C, +/* A */ PRINT_C|ALPHA_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C|HOST_C, +/* B */ PRINT_C|ALPHA_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C|HOST_C, +/* C */ PRINT_C|ALPHA_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C|HOST_C, +/* D */ PRINT_C|ALPHA_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C|HOST_C, +/* E */ PRINT_C|ALPHA_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C|HOST_C, +/* F */ PRINT_C|ALPHA_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C|HOST_C, +/* G */ PRINT_C|ALPHA_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C|HOST_C, +/* H */ PRINT_C|ALPHA_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C|HOST_C, +/* I */ PRINT_C|ALPHA_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C|HOST_C, +/* J */ PRINT_C|ALPHA_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C|HOST_C, +/* K */ PRINT_C|ALPHA_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C|HOST_C, +/* L */ PRINT_C|ALPHA_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C|HOST_C, +/* M */ PRINT_C|ALPHA_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C|HOST_C, +/* N */ PRINT_C|ALPHA_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C|HOST_C, +/* O */ PRINT_C|ALPHA_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C|HOST_C, +/* P */ PRINT_C|ALPHA_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C|HOST_C, +/* Q */ PRINT_C|ALPHA_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C|HOST_C, +/* R */ PRINT_C|ALPHA_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C|HOST_C, +/* S */ PRINT_C|ALPHA_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C|HOST_C, +/* T */ PRINT_C|ALPHA_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C|HOST_C, +/* U */ PRINT_C|ALPHA_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C|HOST_C, +/* V */ PRINT_C|ALPHA_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C|HOST_C, +/* W */ PRINT_C|ALPHA_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C|HOST_C, +/* X */ PRINT_C|ALPHA_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C|HOST_C, +/* Y */ PRINT_C|ALPHA_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C|HOST_C, +/* Z */ PRINT_C|ALPHA_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C|HOST_C, +/* [ */ PRINT_C|ALPHA_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C, +/* \ */ PRINT_C|ALPHA_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C, +/* ] */ PRINT_C|ALPHA_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C, +/* ^ */ PRINT_C|ALPHA_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C, +/* _ */ PRINT_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C, +/* ` */ PRINT_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C, +/* a */ PRINT_C|ALPHA_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C|HOST_C, +/* b */ PRINT_C|ALPHA_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C|HOST_C, +/* c */ PRINT_C|ALPHA_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C|HOST_C, +/* d */ PRINT_C|ALPHA_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C|HOST_C, +/* e */ PRINT_C|ALPHA_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C|HOST_C, +/* f */ PRINT_C|ALPHA_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C|HOST_C, +/* g */ PRINT_C|ALPHA_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C|HOST_C, +/* h */ PRINT_C|ALPHA_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C|HOST_C, +/* i */ PRINT_C|ALPHA_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C|HOST_C, +/* j */ PRINT_C|ALPHA_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C|HOST_C, +/* k */ PRINT_C|ALPHA_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C|HOST_C, +/* l */ PRINT_C|ALPHA_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C|HOST_C, +/* m */ PRINT_C|ALPHA_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C|HOST_C, +/* n */ PRINT_C|ALPHA_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C|HOST_C, +/* o */ PRINT_C|ALPHA_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C|HOST_C, +/* p */ PRINT_C|ALPHA_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C|HOST_C, +/* q */ PRINT_C|ALPHA_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C|HOST_C, +/* r */ PRINT_C|ALPHA_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C|HOST_C, +/* s */ PRINT_C|ALPHA_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C|HOST_C, +/* t */ PRINT_C|ALPHA_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C|HOST_C, +/* u */ PRINT_C|ALPHA_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C|HOST_C, +/* v */ PRINT_C|ALPHA_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C|HOST_C, +/* w */ PRINT_C|ALPHA_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C|HOST_C, +/* x */ PRINT_C|ALPHA_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C|HOST_C, +/* y */ PRINT_C|ALPHA_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C|HOST_C, +/* z */ PRINT_C|ALPHA_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C|HOST_C, +/* { */ PRINT_C|ALPHA_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C, +/* | */ PRINT_C|ALPHA_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C, +/* } */ PRINT_C|ALPHA_C|NICK_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C, +/* ~ */ PRINT_C|ALPHA_C|CHAN_C|VCHAN_C|NONEOS_C|USER_C, +/* del */ CHAN_C|VCHAN_C|NONEOS_C, +/* 0x80 */ CHAN_C|VCHAN_C|NONEOS_C, +/* 0x81 */ CHAN_C|VCHAN_C|NONEOS_C, +/* 0x82 */ CHAN_C|VCHAN_C|NONEOS_C, +/* 0x83 */ CHAN_C|VCHAN_C|NONEOS_C, +/* 0x84 */ CHAN_C|VCHAN_C|NONEOS_C, +/* 0x85 */ CHAN_C|VCHAN_C|NONEOS_C, +/* 0x86 */ CHAN_C|VCHAN_C|NONEOS_C, +/* 0x87 */ CHAN_C|VCHAN_C|NONEOS_C, +/* 0x88 */ CHAN_C|VCHAN_C|NONEOS_C, +/* 0x89 */ CHAN_C|VCHAN_C|NONEOS_C, +/* 0x8A */ CHAN_C|VCHAN_C|NONEOS_C, +/* 0x8B */ CHAN_C|VCHAN_C|NONEOS_C, +/* 0x8C */ CHAN_C|VCHAN_C|NONEOS_C, +/* 0x8D */ CHAN_C|VCHAN_C|NONEOS_C, +/* 0x8E */ CHAN_C|VCHAN_C|NONEOS_C, +/* 0x8F */ CHAN_C|VCHAN_C|NONEOS_C, +/* 0x90 */ CHAN_C|VCHAN_C|NONEOS_C, +/* 0x91 */ CHAN_C|VCHAN_C|NONEOS_C, +/* 0x92 */ CHAN_C|VCHAN_C|NONEOS_C, +/* 0x93 */ CHAN_C|VCHAN_C|NONEOS_C, +/* 0x94 */ CHAN_C|VCHAN_C|NONEOS_C, +/* 0x95 */ CHAN_C|VCHAN_C|NONEOS_C, +/* 0x96 */ CHAN_C|VCHAN_C|NONEOS_C, +/* 0x97 */ CHAN_C|VCHAN_C|NONEOS_C, +/* 0x98 */ CHAN_C|VCHAN_C|NONEOS_C, +/* 0x99 */ CHAN_C|VCHAN_C|NONEOS_C, +/* 0x9A */ CHAN_C|VCHAN_C|NONEOS_C, +/* 0x9B */ CHAN_C|VCHAN_C|NONEOS_C, +/* 0x9C */ CHAN_C|VCHAN_C|NONEOS_C, +/* 0x9D */ CHAN_C|VCHAN_C|NONEOS_C, +/* 0x9E */ CHAN_C|VCHAN_C|NONEOS_C, +/* 0x9F */ CHAN_C|VCHAN_C|NONEOS_C, +/* 0xA0 */ CHAN_C|NONEOS_C, +/* 0xA1 */ CHAN_C|VCHAN_C|NONEOS_C, +/* 0xA2 */ CHAN_C|VCHAN_C|NONEOS_C, +/* 0xA3 */ CHAN_C|VCHAN_C|NONEOS_C, +/* 0xA4 */ CHAN_C|VCHAN_C|NONEOS_C, +/* 0xA5 */ CHAN_C|VCHAN_C|NONEOS_C, +/* 0xA6 */ CHAN_C|VCHAN_C|NONEOS_C, +/* 0xA7 */ CHAN_C|VCHAN_C|NONEOS_C, +/* 0xA8 */ CHAN_C|VCHAN_C|NONEOS_C, +/* 0xA9 */ CHAN_C|VCHAN_C|NONEOS_C, +/* 0xAA */ CHAN_C|VCHAN_C|NONEOS_C, +/* 0xAB */ CHAN_C|VCHAN_C|NONEOS_C, +/* 0xAC */ CHAN_C|VCHAN_C|NONEOS_C, +/* 0xAD */ CHAN_C|VCHAN_C|NONEOS_C, +/* 0xAE */ CHAN_C|VCHAN_C|NONEOS_C, +/* 0xAF */ CHAN_C|VCHAN_C|NONEOS_C, +/* 0xB0 */ CHAN_C|VCHAN_C|NONEOS_C, +/* 0xB1 */ CHAN_C|VCHAN_C|NONEOS_C, +/* 0xB2 */ CHAN_C|VCHAN_C|NONEOS_C, +/* 0xB3 */ CHAN_C|VCHAN_C|NONEOS_C, +/* 0xB4 */ CHAN_C|VCHAN_C|NONEOS_C, +/* 0xB5 */ CHAN_C|VCHAN_C|NONEOS_C, +/* 0xB6 */ CHAN_C|VCHAN_C|NONEOS_C, +/* 0xB7 */ CHAN_C|VCHAN_C|NONEOS_C, +/* 0xB8 */ CHAN_C|VCHAN_C|NONEOS_C, +/* 0xB9 */ CHAN_C|VCHAN_C|NONEOS_C, +/* 0xBA */ CHAN_C|VCHAN_C|NONEOS_C, +/* 0xBB */ CHAN_C|VCHAN_C|NONEOS_C, +/* 0xBC */ CHAN_C|VCHAN_C|NONEOS_C, +/* 0xBD */ CHAN_C|VCHAN_C|NONEOS_C, +/* 0xBE */ CHAN_C|VCHAN_C|NONEOS_C, +/* 0xBF */ CHAN_C|VCHAN_C|NONEOS_C, +/* 0xC0 */ CHAN_C|VCHAN_C|NONEOS_C, +/* 0xC1 */ CHAN_C|VCHAN_C|NONEOS_C, +/* 0xC2 */ CHAN_C|VCHAN_C|NONEOS_C, +/* 0xC3 */ CHAN_C|VCHAN_C|NONEOS_C, +/* 0xC4 */ CHAN_C|VCHAN_C|NONEOS_C, +/* 0xC5 */ CHAN_C|VCHAN_C|NONEOS_C, +/* 0xC6 */ CHAN_C|VCHAN_C|NONEOS_C, +/* 0xC7 */ CHAN_C|VCHAN_C|NONEOS_C, +/* 0xC8 */ CHAN_C|VCHAN_C|NONEOS_C, +/* 0xC9 */ CHAN_C|VCHAN_C|NONEOS_C, +/* 0xCA */ CHAN_C|VCHAN_C|NONEOS_C, +/* 0xCB */ CHAN_C|VCHAN_C|NONEOS_C, +/* 0xCC */ CHAN_C|VCHAN_C|NONEOS_C, +/* 0xCD */ CHAN_C|VCHAN_C|NONEOS_C, +/* 0xCE */ CHAN_C|VCHAN_C|NONEOS_C, +/* 0xCF */ CHAN_C|VCHAN_C|NONEOS_C, +/* 0xD0 */ CHAN_C|VCHAN_C|NONEOS_C, +/* 0xD1 */ CHAN_C|VCHAN_C|NONEOS_C, +/* 0xD2 */ CHAN_C|VCHAN_C|NONEOS_C, +/* 0xD3 */ CHAN_C|VCHAN_C|NONEOS_C, +/* 0xD4 */ CHAN_C|VCHAN_C|NONEOS_C, +/* 0xD5 */ CHAN_C|VCHAN_C|NONEOS_C, +/* 0xD6 */ CHAN_C|VCHAN_C|NONEOS_C, +/* 0xD7 */ CHAN_C|VCHAN_C|NONEOS_C, +/* 0xD8 */ CHAN_C|VCHAN_C|NONEOS_C, +/* 0xD9 */ CHAN_C|VCHAN_C|NONEOS_C, +/* 0xDA */ CHAN_C|VCHAN_C|NONEOS_C, +/* 0xDB */ CHAN_C|VCHAN_C|NONEOS_C, +/* 0xDC */ CHAN_C|VCHAN_C|NONEOS_C, +/* 0xDD */ CHAN_C|VCHAN_C|NONEOS_C, +/* 0xDE */ CHAN_C|VCHAN_C|NONEOS_C, +/* 0xDF */ CHAN_C|VCHAN_C|NONEOS_C, +/* 0xE0 */ CHAN_C|VCHAN_C|NONEOS_C, +/* 0xE1 */ CHAN_C|VCHAN_C|NONEOS_C, +/* 0xE2 */ CHAN_C|VCHAN_C|NONEOS_C, +/* 0xE3 */ CHAN_C|VCHAN_C|NONEOS_C, +/* 0xE4 */ CHAN_C|VCHAN_C|NONEOS_C, +/* 0xE5 */ CHAN_C|VCHAN_C|NONEOS_C, +/* 0xE6 */ CHAN_C|VCHAN_C|NONEOS_C, +/* 0xE7 */ CHAN_C|VCHAN_C|NONEOS_C, +/* 0xE8 */ CHAN_C|VCHAN_C|NONEOS_C, +/* 0xE9 */ CHAN_C|VCHAN_C|NONEOS_C, +/* 0xEA */ CHAN_C|VCHAN_C|NONEOS_C, +/* 0xEB */ CHAN_C|VCHAN_C|NONEOS_C, +/* 0xEC */ CHAN_C|VCHAN_C|NONEOS_C, +/* 0xED */ CHAN_C|VCHAN_C|NONEOS_C, +/* 0xEE */ CHAN_C|VCHAN_C|NONEOS_C, +/* 0xEF */ CHAN_C|VCHAN_C|NONEOS_C, +/* 0xF0 */ CHAN_C|VCHAN_C|NONEOS_C, +/* 0xF1 */ CHAN_C|VCHAN_C|NONEOS_C, +/* 0xF2 */ CHAN_C|VCHAN_C|NONEOS_C, +/* 0xF3 */ CHAN_C|VCHAN_C|NONEOS_C, +/* 0xF4 */ CHAN_C|VCHAN_C|NONEOS_C, +/* 0xF5 */ CHAN_C|VCHAN_C|NONEOS_C, +/* 0xF6 */ CHAN_C|VCHAN_C|NONEOS_C, +/* 0xF7 */ CHAN_C|VCHAN_C|NONEOS_C, +/* 0xF8 */ CHAN_C|VCHAN_C|NONEOS_C, +/* 0xF9 */ CHAN_C|VCHAN_C|NONEOS_C, +/* 0xFA */ CHAN_C|VCHAN_C|NONEOS_C, +/* 0xFB */ CHAN_C|VCHAN_C|NONEOS_C, +/* 0xFC */ CHAN_C|VCHAN_C|NONEOS_C, +/* 0xFD */ CHAN_C|VCHAN_C|NONEOS_C, +/* 0xFE */ CHAN_C|VCHAN_C|NONEOS_C, +/* 0xFF */ CHAN_C|VCHAN_C|NONEOS_C +}; diff --git a/src/memory.c b/src/memory.c new file mode 100644 index 0000000..037807a --- /dev/null +++ b/src/memory.c @@ -0,0 +1,114 @@ +/* + * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd). + * memory.c: Memory utilities. + * + * Copyright (C) 2002 by the past and present ircd coders, and others. + * + * 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 + * + * $Id$ + */ + + +#include "stdinc.h" +#include "ircd_defs.h" +#include "irc_string.h" +#include "memory.h" +#include "log.h" +#include "restart.h" + + +/* + * MyMalloc - allocate memory, call outofmemory on failure + */ +void * +MyMalloc(size_t size) +{ + void *ret = calloc(1, size); + + if (ret == NULL) + outofmemory(); + + return ret; +} + +/* + * MyRealloc - reallocate memory, call outofmemory on failure + */ +void * +MyRealloc(void *x, size_t y) +{ + void *ret = realloc(x, y); + + if (ret == NULL) + outofmemory(); + + return ret; +} + +void +MyFree(void *x) +{ + if (x) + free(x); +} + +void +_DupString(char **x, const char *y) +{ + (*x) = malloc(strlen(y) + 1); + strcpy((*x), y); +} + +/* outofmemory() + * + * input - NONE + * output - NONE + * side effects - simply try to report there is a problem. + * Abort if it was called more than once + */ +void +outofmemory(void) +{ + static int was_here = 0; + + if (was_here++) + abort(); + + ilog(LOG_TYPE_IRCD, "Out of memory: restarting server..."); + restart("Out of Memory"); +} + +#ifndef NDEBUG +/* + * frob some memory. debugging time. + * -- adrian + */ +void +mem_frob(void *data, int len) +{ + /* correct for Intel only! little endian */ + unsigned char b[4] = { 0xef, 0xbe, 0xad, 0xde }; + int i; + char *cdata = data; + + for (i = 0; i < len; i++) + { + *cdata = b[i % 4]; + cdata++; + } +} +#endif diff --git a/src/messages.tab b/src/messages.tab new file mode 100644 index 0000000..12e22c6 --- /dev/null +++ b/src/messages.tab @@ -0,0 +1,1029 @@ +/************************************************************************ + * IRC - Internet Relay Chat, src/messages.tab + * Copyright (C) 1992 Darren Reed + * + * 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 1, 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Id$ + */ + +static struct NumericInfo replies[] = { +/* 000 */ {NULL, NULL, NULL}, +/* 001 */ {"RPL_WELCOME", ":%s 001 %s :Welcome to the %s Internet Relay Chat Network %s", NULL}, +/* 002 */ {"RPL_YOURHOST", ":%s 002 %s :Your host is %s, running version %s", NULL}, +/* 003 */ {"RPL_CREATED", ":%s 003 %s :This server was created %s", NULL}, +#ifdef HALFOPS +/* 004 */ {"RPL_MYINFO", ":%s 004 %s %s %s %s biklmnoprstveIhORS bkloveIh", NULL}, +#else +/* 004 */ {"RPL_MYINFO", ":%s 004 %s %s %s %s biklmnoprstveIORS bkloveI", NULL}, +#endif +/* 005 */ {"RPL_ISUPPORT", ":%s 005 %s %s :are supported by this server", NULL}, +/* 006 */ {NULL, NULL, NULL}, +/* 007 */ {NULL, NULL, NULL}, +/* 008 */ {NULL, NULL, NULL}, +/* 009 */ {NULL, NULL, NULL}, +/* 010 */ {"RPL_REDIR", ":%s 010 %s %s %d :Please use this Server/Port instead", NULL}, +/* 011 */ {NULL, NULL, NULL}, +/* 012 */ {NULL, NULL, NULL}, +/* 013 */ {NULL, NULL, NULL}, +/* 014 */ {NULL, NULL, NULL}, +/* 015 */ {"RPL_MAP", ":%s 015 %s :%s", NULL}, +/* 016 */ {NULL, NULL, NULL}, +/* 017 */ {"RPL_MAPEND", ":%s 017 %s :End of /MAP", NULL}, +/* 018 */ {NULL, NULL, NULL}, +/* 019 */ {NULL, NULL, NULL}, +/* 020 */ {NULL, NULL, NULL}, +/* 021 */ {NULL, NULL, NULL}, +/* 022 */ {NULL, NULL, NULL}, +/* 023 */ {NULL, NULL, NULL}, +/* 024 */ {NULL, NULL, NULL}, +/* 025 */ {NULL, NULL, NULL}, +/* 026 */ {NULL, NULL, NULL}, +/* 027 */ {NULL, NULL, NULL}, +/* 028 */ {NULL, NULL, NULL}, +/* 029 */ {NULL, NULL, NULL}, +/* 030 */ {NULL, NULL, NULL}, +/* 031 */ {NULL, NULL, NULL}, +/* 032 */ {NULL, NULL, NULL}, +/* 033 */ {NULL, NULL, NULL}, +/* 034 */ {NULL, NULL, NULL}, +/* 035 */ {NULL, NULL, NULL}, +/* 036 */ {NULL, NULL, NULL}, +/* 037 */ {NULL, NULL, NULL}, +/* 038 */ {NULL, NULL, NULL}, +/* 039 */ {NULL, NULL, NULL}, +/* 040 */ {NULL, NULL, NULL}, +/* 041 */ {NULL, NULL, NULL}, +/* 042 */ {"RPL_YOURID", ":%s 042 %s %s :your unique ID", NULL}, +/* 043 */ {NULL, NULL, NULL}, +/* 044 */ {NULL, NULL, NULL}, +/* 045 */ {NULL, NULL, NULL}, +/* 046 */ {NULL, NULL, NULL}, +/* 047 */ {NULL, NULL, NULL}, +/* 048 */ {NULL, NULL, NULL}, +/* 049 */ {NULL, NULL, NULL}, +/* 050 */ {NULL, NULL, NULL}, +/* 051 */ {NULL, NULL, NULL}, +/* 052 */ {NULL, NULL, NULL}, +/* 053 */ {NULL, NULL, NULL}, +/* 054 */ {NULL, NULL, NULL}, +/* 055 */ {NULL, NULL, NULL}, +/* 056 */ {NULL, NULL, NULL}, +/* 057 */ {NULL, NULL, NULL}, +/* 058 */ {NULL, NULL, NULL}, +/* 059 */ {NULL, NULL, NULL}, +/* 060 */ {NULL, NULL, NULL}, +/* 061 */ {NULL, NULL, NULL}, +/* 062 */ {NULL, NULL, NULL}, +/* 063 */ {NULL, NULL, NULL}, +/* 064 */ {NULL, NULL, NULL}, +/* 065 */ {NULL, NULL, NULL}, +/* 066 */ {NULL, NULL, NULL}, +/* 067 */ {NULL, NULL, NULL}, +/* 068 */ {NULL, NULL, NULL}, +/* 069 */ {NULL, NULL, NULL}, +/* 070 */ {NULL, NULL, NULL}, +/* 071 */ {NULL, NULL, NULL}, +/* 072 */ {NULL, NULL, NULL}, +/* 073 */ {NULL, NULL, NULL}, +/* 074 */ {NULL, NULL, NULL}, +/* 075 */ {NULL, NULL, NULL}, +/* 076 */ {NULL, NULL, NULL}, +/* 077 */ {NULL, NULL, NULL}, +/* 078 */ {NULL, NULL, NULL}, +/* 079 */ {NULL, NULL, NULL}, +/* 080 */ {NULL, NULL, NULL}, +/* 081 */ {NULL, NULL, NULL}, +/* 082 */ {NULL, NULL, NULL}, +/* 083 */ {NULL, NULL, NULL}, +/* 084 */ {NULL, NULL, NULL}, +/* 085 */ {NULL, NULL, NULL}, +/* 086 */ {NULL, NULL, NULL}, +/* 087 */ {NULL, NULL, NULL}, +/* 088 */ {NULL, NULL, NULL}, +/* 089 */ {NULL, NULL, NULL}, +/* 090 */ {NULL, NULL, NULL}, +/* 091 */ {NULL, NULL, NULL}, +/* 092 */ {NULL, NULL, NULL}, +/* 093 */ {NULL, NULL, NULL}, +/* 094 */ {NULL, NULL, NULL}, +/* 095 */ {NULL, NULL, NULL}, +/* 096 */ {NULL, NULL, NULL}, +/* 097 */ {NULL, NULL, NULL}, +/* 098 */ {NULL, NULL, NULL}, +/* 099 */ {NULL, NULL, NULL}, +/* 100 */ {NULL, NULL, NULL}, +/* 101 */ {NULL, NULL, NULL}, +/* 102 */ {NULL, NULL, NULL}, +/* 103 */ {NULL, NULL, NULL}, +/* 104 */ {NULL, NULL, NULL}, +/* 105 */ {NULL, NULL, NULL}, +/* 106 */ {NULL, NULL, NULL}, +/* 107 */ {NULL, NULL, NULL}, +/* 108 */ {NULL, NULL, NULL}, +/* 109 */ {NULL, NULL, NULL}, +/* 110 */ {NULL, NULL, NULL}, +/* 111 */ {NULL, NULL, NULL}, +/* 112 */ {NULL, NULL, NULL}, +/* 113 */ {NULL, NULL, NULL}, +/* 114 */ {NULL, NULL, NULL}, +/* 115 */ {NULL, NULL, NULL}, +/* 116 */ {NULL, NULL, NULL}, +/* 117 */ {NULL, NULL, NULL}, +/* 118 */ {NULL, NULL, NULL}, +/* 119 */ {NULL, NULL, NULL}, +/* 120 */ {NULL, NULL, NULL}, +/* 121 */ {NULL, NULL, NULL}, +/* 122 */ {NULL, NULL, NULL}, +/* 123 */ {NULL, NULL, NULL}, +/* 124 */ {NULL, NULL, NULL}, +/* 125 */ {NULL, NULL, NULL}, +/* 126 */ {NULL, NULL, NULL}, +/* 127 */ {NULL, NULL, NULL}, +/* 128 */ {NULL, NULL, NULL}, +/* 129 */ {NULL, NULL, NULL}, +/* 130 */ {NULL, NULL, NULL}, +/* 131 */ {NULL, NULL, NULL}, +/* 132 */ {NULL, NULL, NULL}, +/* 133 */ {NULL, NULL, NULL}, +/* 134 */ {NULL, NULL, NULL}, +/* 135 */ {NULL, NULL, NULL}, +/* 136 */ {NULL, NULL, NULL}, +/* 137 */ {NULL, NULL, NULL}, +/* 138 */ {NULL, NULL, NULL}, +/* 139 */ {NULL, NULL, NULL}, +/* 140 */ {NULL, NULL, NULL}, +/* 141 */ {NULL, NULL, NULL}, +/* 142 */ {NULL, NULL, NULL}, +/* 143 */ {NULL, NULL, NULL}, +/* 144 */ {NULL, NULL, NULL}, +/* 145 */ {NULL, NULL, NULL}, +/* 146 */ {NULL, NULL, NULL}, +/* 147 */ {NULL, NULL, NULL}, +/* 148 */ {NULL, NULL, NULL}, +/* 149 */ {NULL, NULL, NULL}, +/* 150 */ {NULL, NULL, NULL}, +/* 151 */ {NULL, NULL, NULL}, +/* 152 */ {NULL, NULL, NULL}, +/* 153 */ {NULL, NULL, NULL}, +/* 154 */ {NULL, NULL, NULL}, +/* 155 */ {NULL, NULL, NULL}, +/* 156 */ {NULL, NULL, NULL}, +/* 157 */ {NULL, NULL, NULL}, +/* 158 */ {NULL, NULL, NULL}, +/* 159 */ {NULL, NULL, NULL}, +/* 160 */ {NULL, NULL, NULL}, +/* 161 */ {NULL, NULL, NULL}, +/* 162 */ {NULL, NULL, NULL}, +/* 163 */ {NULL, NULL, NULL}, +/* 164 */ {NULL, NULL, NULL}, +/* 165 */ {NULL, NULL, NULL}, +/* 166 */ {NULL, NULL, NULL}, +/* 167 */ {NULL, NULL, NULL}, +/* 168 */ {NULL, NULL, NULL}, +/* 169 */ {NULL, NULL, NULL}, +/* 170 */ {NULL, NULL, NULL}, +/* 171 */ {NULL, NULL, NULL}, +/* 172 */ {NULL, NULL, NULL}, +/* 173 */ {NULL, NULL, NULL}, +/* 174 */ {NULL, NULL, NULL}, +/* 175 */ {NULL, NULL, NULL}, +/* 176 */ {NULL, NULL, NULL}, +/* 177 */ {NULL, NULL, NULL}, +/* 178 */ {NULL, NULL, NULL}, +/* 179 */ {NULL, NULL, NULL}, +/* 180 */ {NULL, NULL, NULL}, +/* 181 */ {NULL, NULL, NULL}, +/* 182 */ {NULL, NULL, NULL}, +/* 183 */ {NULL, NULL, NULL}, +/* 184 */ {NULL, NULL, NULL}, +/* 185 */ {NULL, NULL, NULL}, +/* 186 */ {NULL, NULL, NULL}, +/* 187 */ {NULL, NULL, NULL}, +/* 188 */ {NULL, NULL, NULL}, +/* 189 */ {NULL, NULL, NULL}, +/* 190 */ {NULL, NULL, NULL}, +/* 191 */ {NULL, NULL, NULL}, +/* 192 */ {NULL, NULL, NULL}, +/* 193 */ {NULL, NULL, NULL}, +/* 194 */ {NULL, NULL, NULL}, +/* 195 */ {NULL, NULL, NULL}, +/* 196 */ {NULL, NULL, NULL}, +/* 197 */ {NULL, NULL, NULL}, +/* 198 */ {NULL, NULL, NULL}, +/* 199 */ {NULL, NULL, NULL}, +/* 200 */ {"RPL_TRACELINK", ":%s 200 %s Link %s %s %s", NULL}, +/* 201 */ {"RPL_TRACECONNECTING", ":%s 201 %s Try. %s %s", NULL}, +/* 202 */ {"RPL_TRACEHANDSHAKE", ":%s 202 %s H.S. %s %s", NULL}, +/* 203 */ {"RPL_TRACEUNKNOWN", ":%s 203 %s ???? %s %s (%s) %d", NULL}, +/* 204 */ {"RPL_TRACEOPERATOR", ":%s 204 %s Oper %s %s (%s) %lu %lu", NULL}, +/* 205 */ {"RPL_TRACEUSER", ":%s 205 %s User %s %s (%s) %lu %lu", NULL}, +/* 206 */ {"RPL_TRACESERVER", ":%s 206 %s Serv %s %dS %dC %s %s!%s@%s %lu", NULL}, +/* 207 */ {NULL, NULL, NULL}, +/* 208 */ {"RPL_TRACENEWTYPE", ":%s 208 %s <newtype> 0 %s", NULL}, +/* 209 */ {"RPL_TRACECLASS", ":%s 209 %s Class %s %d", NULL}, +/* 210 */ {NULL, NULL, NULL}, +/* 211 */ {"RPL_STATSLINKINFO", ":%s 211 %s %s %u %u %llu %u %llu :%u %u %s", NULL}, +/* 212 */ {"RPL_STATSCOMMANDS", ":%s 212 %s %s %u %llu :%u", NULL}, +/* 213 */ {"RPL_STATSCLINE", ":%s 213 %s %c %s %s %s %d %s", NULL}, +/* 214 */ {"RPL_STATSNLINE", ":%s 214 %s %c %s * %s %d %s", NULL}, +/* 215 */ {"RPL_STATSILINE", ":%s 215 %s %c %s * %s@%s %d %s", NULL}, +/* 216 */ {"RPL_STATSKLINE", ":%s 216 %s %s %s * %s :%s | %s", NULL}, +/* 217 */ {"RPL_STATSQLINE", ":%s 217 %s %c %s :%s", NULL}, +/* 218 */ {"RPL_STATSYLINE", ":%s 218 %s %c %s %d %d %d %lu %lu %d %d/%d %d/%d %s", NULL}, +/* 219 */ {"RPL_ENDOFSTATS", ":%s 219 %s %c :End of /STATS report", NULL}, +/* 220 */ {"RPL_STATSPLINE", ":%s 220 %s %c %d %s %d %s :%s", NULL}, +/* 221 */ {"RPL_UMODEIS", ":%s 221 %s %s", NULL}, +/* 222 */ {NULL, NULL, NULL}, +/* 223 */ {NULL, NULL, NULL}, +/* 224 */ {NULL, NULL, NULL}, +/* 225 */ {"RPL_STATSDLINE", ":%s 225 %s %c %s :%s | %s", NULL}, +/* 226 */ {"RPL_STATSALINE", ":%s 226 %s %s", NULL}, +/* 227 */ {NULL, NULL, NULL}, +/* 228 */ {NULL, NULL, NULL}, +/* 229 */ {NULL, NULL, NULL}, +/* 230 */ {NULL, NULL, NULL}, +/* 231 */ {NULL, NULL, NULL}, +/* 232 */ {NULL, NULL, NULL}, +/* 233 */ {NULL, NULL, NULL}, +/* 234 */ {NULL, NULL, NULL}, +/* 235 */ {NULL, NULL, NULL}, +/* 236 */ {NULL, NULL, NULL}, +/* 237 */ {NULL, NULL, NULL}, +/* 238 */ {NULL, NULL, NULL}, +/* 239 */ {NULL, NULL, NULL}, +/* 240 */ {NULL, NULL, NULL}, +/* 241 */ {"RPL_STATSLLINE", ":%s 241 %s %c %s * %s %d %s", NULL}, +/* 242 */ {"RPL_STATSUPTIME", ":%s 242 %s :Server Up %d days, %d:%02d:%02d", NULL}, +/* 243 */ {"RPL_STATSOLINE", ":%s 243 %s %c %s@%s * %s %s %s", NULL}, +/* 244 */ {"RPL_STATSHLINE", ":%s 244 %s %c %s * %s %d %s", NULL}, +/* 245 */ {"RPL_STATSSLINE", NULL, NULL}, +/* 246 */ {"RPL_STATSSERVICE", ":%s 246 %s %c %s * %s %d %d", NULL}, +/* 247 */ {"RPL_STATSXLINE", ":%s 247 %s %s %d %s :%s", NULL}, +/* 248 */ {"RPL_STATSULINE", ":%s 248 %s U %s %s@%s %s", NULL}, +/* 249 */ {NULL, NULL, NULL}, +/* 250 */ {"RPL_STATSCONN", ":%s 250 %s :Highest connection count: %d (%d clients) (%llu connections received)", NULL}, +/* 251 */ {"RPL_LUSERCLIENT", ":%s 251 %s :There are %d users and %d invisible on %d servers", NULL}, +/* 252 */ {"RPL_LUSEROP", ":%s 252 %s %d :IRC Operators online", NULL}, +/* 253 */ {"RPL_LUSERUNKNOWN", ":%s 253 %s %d :unknown connection(s)", NULL}, +/* 254 */ {"RPL_LUSERCHANNELS", ":%s 254 %s %d :channels formed", NULL}, +/* 255 */ {"RPL_LUSERME", ":%s 255 %s :I have %d clients and %d servers", NULL}, +/* 256 */ {"RPL_ADMINME", ":%s 256 %s :Administrative info about %s", NULL}, +/* 257 */ {"RPL_ADMINLOC1", ":%s 257 %s :%s", NULL}, +/* 258 */ {"RPL_ADMINLOC2", ":%s 258 %s :%s", NULL}, +/* 259 */ {"RPL_ADMINEMAIL", ":%s 259 %s :%s", NULL}, +/* 260 */ {NULL, NULL, NULL}, +/* 261 */ {NULL, NULL, NULL}, +/* 262 */ {"RPL_ENDOFTRACE", ":%s 262 %s %s :End of TRACE", NULL}, +/* 263 */ {"RPL_LOAD2HI", ":%s 263 %s :Server load is temporarily too heavy. Please wait a while and try again.", NULL}, +/* 264 */ {NULL, NULL, NULL}, +/* 265 */ {"RPL_LOCALUSERS", ":%s 265 %s :Current local users: %d Max: %d", NULL}, +/* 266 */ {"RPL_GLOBALUSERS", ":%s 266 %s :Current global users: %d Max: %d", NULL}, +/* 267 */ {NULL, NULL, NULL}, +/* 268 */ {NULL, NULL, NULL}, +/* 269 */ {NULL, NULL, NULL}, +/* 270 */ {NULL, NULL, NULL}, +/* 271 */ {NULL, NULL, NULL}, +/* 272 */ {NULL, NULL, NULL}, +/* 273 */ {NULL, NULL, NULL}, +/* 274 */ {NULL, NULL, NULL}, +/* 275 */ {NULL, NULL, NULL}, +/* 276 */ {NULL, NULL, NULL}, +/* 277 */ {NULL, NULL, NULL}, +/* 278 */ {NULL, NULL, NULL}, +/* 279 */ {NULL, NULL, NULL}, +/* 280 */ {NULL, NULL, NULL}, +/* 281 */ {"RPL_ACCEPTLIST", ":%s 281 %s :%s", NULL}, +/* 282 */ {"RPL_ENDOFACCEPT", ":%s 282 %s :End of /ACCEPT list.", NULL}, +/* 283 */ {NULL, NULL, NULL}, +/* 284 */ {NULL, NULL, NULL}, +/* 285 */ {NULL, NULL, NULL}, +/* 286 */ {NULL, NULL, NULL}, +/* 287 */ {NULL, NULL, NULL}, +/* 288 */ {NULL, NULL, NULL}, +/* 289 */ {NULL, NULL, NULL}, +/* 290 */ {NULL, NULL, NULL}, +/* 291 */ {NULL, NULL, NULL}, +/* 292 */ {NULL, NULL, NULL}, +/* 293 */ {NULL, NULL, NULL}, +/* 294 */ {NULL, NULL, NULL}, +/* 295 */ {NULL, NULL, NULL}, +/* 296 */ {NULL, NULL, NULL}, +/* 297 */ {NULL, NULL, NULL}, +/* 298 */ {NULL, NULL, NULL}, +/* 299 */ {NULL, NULL, NULL}, +/* 300 */ {NULL, NULL, NULL}, +/* 301 */ {"RPL_AWAY", ":%s 301 %s %s :%s", NULL}, +/* 302 */ {"RPL_USERHOST", ":%s 302 %s :%s", NULL}, +/* 303 */ {"RPL_ISON", ":%s 303 %s :", NULL}, +/* 304 */ {"RPL_TEXT", NULL, NULL}, +/* 305 */ {"RPL_UNAWAY", ":%s 305 %s :You are no longer marked as being away", NULL}, +/* 306 */ {"RPL_NOWAWAY", ":%s 306 %s :You have been marked as being away", NULL}, +/* 307 */ {"RPL_WHOISREGNICK", ":%s 307 %s %s :has identified for this nick", NULL}, +/* 308 */ {"RPL_WHOISADMIN", ":%s 313 %s %s :is a Server Administrator", NULL}, +/* 309 */ {NULL, NULL, NULL}, +/* 310 */ {NULL, NULL, NULL}, +/* 311 */ {"RPL_WHOISUSER", ":%s 311 %s %s %s %s * :%s", NULL}, +/* 312 */ {"RPL_WHOISSERVER", ":%s 312 %s %s %s :%s", NULL}, +/* 313 */ {"RPL_WHOISOPERATOR", ":%s 313 %s %s :is an IRC Operator", NULL}, +/* 314 */ {"RPL_WHOWASUSER", ":%s 314 %s %s %s %s * :%s", NULL}, +/* 315 */ {"RPL_ENDOFWHO", ":%s 315 %s %s :End of /WHO list.", NULL}, +/* 316 */ {"RPL_WHOISCHANOP", NULL, NULL}, +/* 317 */ {"RPL_WHOISIDLE", ":%s 317 %s %s %d %d :seconds idle, signon time", NULL}, +/* 318 */ {"RPL_ENDOFWHOIS", ":%s 318 %s %s :End of /WHOIS list.", NULL}, +/* 319 */ {"RPL_WHOISCHANNELS", ":%s 319 %s %s :%s", NULL}, +/* 320 */ {NULL, NULL, NULL}, +/* 321 */ {"RPL_LISTSTART", ":%s 321 %s Channel :Users Name", NULL}, +/* 322 */ {"RPL_LIST", ":%s 322 %s %s %d :%s", NULL}, +/* 323 */ {"RPL_LISTEND", ":%s 323 %s :End of /LIST", NULL}, +/* 324 */ {"RPL_CHANNELMODEIS", ":%s 324 %s %s %s %s", NULL}, +/* 325 */ {NULL, NULL, NULL}, +/* 326 */ {NULL, NULL, NULL}, +/* 327 */ {NULL, NULL, NULL}, +/* 328 */ {NULL, NULL, NULL}, +/* 329 */ {"RPL_CREATIONTIME", ":%s 329 %s %s %lu", NULL}, +/* 330 */ {NULL, NULL, NULL}, +/* 331 */ {"RPL_NOTOPIC", ":%s 331 %s %s :No topic is set.", NULL}, +/* 332 */ {"RPL_TOPIC", ":%s 332 %s %s :%s", NULL}, +/* 333 */ {"RPL_TOPICWHOTIME", ":%s 333 %s %s %s %lu", NULL}, +/* 334 */ {NULL, NULL, NULL}, +/* 335 */ {NULL, NULL, NULL}, +/* 336 */ {NULL, NULL, NULL}, +/* 337 */ {NULL, NULL, NULL}, +/* 338 */ {"RPL_WHOISACTUALLY", ":%s 338 %s %s %s :actually using host", NULL}, +/* 339 */ {NULL, NULL, NULL}, +/* 340 */ {NULL, NULL, NULL}, +/* 341 */ {"RPL_INVITING", ":%s 341 %s %s %s", NULL}, +/* 342 */ {NULL, NULL, NULL}, +/* 343 */ {NULL, NULL, NULL}, +/* 344 */ {NULL, NULL, NULL}, +/* 345 */ {NULL, NULL, NULL}, +/* 346 */ {"RPL_INVEXLIST", ":%s 346 %s %s %s!%s@%s %s %lu", NULL}, +/* 347 */ {"RPL_ENDOFINVEXLIST", ":%s 347 %s %s :End of Channel Invite List", NULL}, +/* 348 */ {"RPL_EXCEPTLIST", ":%s 348 %s %s %s!%s@%s %s %lu", NULL}, +/* 349 */ {"RPL_ENDOFEXCEPTLIST", ":%s 349 %s %s :End of Channel Exception List", NULL}, +/* 350 */ {NULL, NULL, NULL}, +/* 351 */ {"RPL_VERSION", ":%s 351 %s %s(%s). %s :%s%s", NULL}, +/* 352 */ {"RPL_WHOREPLY", ":%s 352 %s %s %s %s %s %s %s :%d %s", NULL}, +/* 353 */ {"RPL_NAMREPLY", ":%s 353 %s %s %s :", NULL}, +/* 354 */ {NULL, NULL, NULL}, +/* 355 */ {NULL, NULL, NULL}, +/* 356 */ {NULL, NULL, NULL}, +/* 357 */ {NULL, NULL, NULL}, +/* 358 */ {NULL, NULL, NULL}, +/* 359 */ {NULL, NULL, NULL}, +/* 360 */ {NULL, NULL, NULL}, +/* 361 */ {NULL, NULL, NULL}, +/* 362 */ {"RPL_CLOSING", ":%s 362 %s %s :Closed. Status = %d", NULL}, +/* 363 */ {"RPL_CLOSEEND", ":%s 363 %s %d: Connections Closed", NULL}, +/* 364 */ {"RPL_LINKS", ":%s 364 %s %s %s :%d %s", NULL}, +/* 365 */ {"RPL_ENDOFLINKS", ":%s 365 %s %s :End of /LINKS list.", NULL}, +/* 366 */ {"RPL_ENDOFNAMES", ":%s 366 %s %s :End of /NAMES list.", NULL}, +/* 367 */ {"RPL_BANLIST", ":%s 367 %s %s %s!%s@%s %s %lu", NULL}, +/* 368 */ {"RPL_ENDOFBANLIST", ":%s 368 %s %s :End of Channel Ban List", NULL}, +/* 369 */ {"RPL_ENDOFWHOWAS", ":%s 369 %s %s :End of WHOWAS", NULL}, +/* 370 */ {NULL, NULL, NULL}, +/* 371 */ {"RPL_INFO", ":%s 371 %s :%s", NULL}, +/* 372 */ {"RPL_MOTD", ":%s 372 %s :- %s", NULL}, +/* 373 */ {"RPL_INFOSTART", ":%s 373 %s :Server INFO", NULL}, +/* 374 */ {"RPL_ENDOFINFO", ":%s 374 %s :End of /INFO list.", NULL}, +/* 375 */ {"RPL_MOTDSTART", ":%s 375 %s :- %s Message of the Day - ", NULL}, +/* 376 */ {"RPL_ENDOFMOTD", ":%s 376 %s :End of /MOTD command.", NULL}, +/* 377 */ {NULL, NULL, NULL}, +/* 378 */ {NULL, NULL, NULL}, +/* 379 */ {NULL, NULL, NULL}, +/* 380 */ {NULL, NULL, NULL}, +/* 381 */ {"RPL_YOUREOPER", ":%s 381 %s :You have entered... the Twilight Zone!", NULL}, +/* 382 */ {"RPL_REHASHING", ":%s 382 %s %s :Rehashing", NULL}, +/* 383 */ {NULL, NULL, NULL}, +/* 384 */ {NULL, NULL, NULL}, +/* 385 */ {NULL, NULL, NULL}, +/* 386 */ {NULL, ":%s 386 %s :%s", NULL}, +/* 387 */ {NULL, NULL, NULL}, +/* 388 */ {NULL, NULL, NULL}, +/* 389 */ {NULL, NULL, NULL}, +/* 390 */ {NULL, NULL, NULL}, +/* 391 */ {"RPL_TIME", ":%s 391 %s %s :%s", NULL}, +/* 392 */ {NULL, NULL, NULL}, +/* 393 */ {NULL, NULL, NULL}, +/* 394 */ {NULL, NULL, NULL}, +/* 395 */ {NULL, NULL, NULL}, +/* 396 */ {"RPL_HOSTHIDDEN", ":%s 396 %s %s :is now your hidden host", NULL}, +/* 397 */ {NULL, NULL, NULL}, +/* 398 */ {NULL, NULL, NULL}, +/* 399 */ {NULL, NULL, NULL}, +/* 400 */ {NULL, NULL, NULL}, +/* 401 */ {"ERR_NOSUCHNICK", ":%s 401 %s %s :No such nick/channel", NULL}, +/* 402 */ {"ERR_NOSUCHSERVER", ":%s 402 %s %s :No such server", NULL}, +/* 403 */ {"ERR_NOSUCHCHANNEL", ":%s 403 %s %s :No such channel", NULL}, +/* 404 */ {"ERR_CANNOTSENDTOCHAN", ":%s 404 %s %s :Cannot send to channel", NULL}, +/* 405 */ {"ERR_TOOMANYCHANNELS", ":%s 405 %s %s :You have joined too many channels", NULL}, +/* 406 */ {"ERR_WASNOSUCHNICK", ":%s 406 %s %s :There was no such nickname", NULL}, +/* 407 */ {"ERR_TOOMANYTARGETS", ":%s 407 %s %s :Too many recipients. Only %d processed", NULL}, +/* 408 */ {NULL, NULL, NULL}, +/* 409 */ {"ERR_NOORIGIN", ":%s 409 %s :No origin specified", NULL}, +/* 410 */ {"ERR_INVALIDCAPCMD", ":%s 410 %s %s :Invalid CAP subcommand", NULL}, +/* 411 */ {"ERR_NORECIPIENT", ":%s 411 %s :No recipient given (%s)", NULL}, +/* 412 */ {"ERR_NOTEXTTOSEND", ":%s 412 %s :No text to send", NULL}, +/* 413 */ {"ERR_NOTOPLEVEL", ":%s 413 %s %s :No toplevel domain specified", NULL}, +/* 414 */ {"ERR_WILDTOPLEVEL", ":%s 414 %s %s :Wildcard in toplevel Domain", NULL}, +/* 415 */ {NULL, NULL, NULL}, +/* 416 */ {NULL, NULL, NULL}, +/* 417 */ {NULL, NULL, NULL}, +/* 418 */ {NULL, NULL, NULL}, +/* 419 */ {NULL, NULL, NULL}, +/* 420 */ {NULL, NULL, NULL}, +/* 421 */ {"ERR_UNKNOWNCOMMAND", ":%s 421 %s %s :Unknown command", NULL}, +/* 422 */ {"ERR_NOMOTD", ":%s 422 %s :MOTD File is missing", NULL}, +/* 423 */ {"ERR_NOADMININFO", ":%s 423 %s %s :No administrative info available", NULL}, +/* 424 */ {NULL, NULL, NULL}, +/* 425 */ {NULL, NULL, NULL}, +/* 426 */ {NULL, NULL, NULL}, +/* 427 */ {NULL, NULL, NULL}, +/* 428 */ {NULL, NULL, NULL}, +/* 429 */ {NULL, NULL, NULL}, +/* 430 */ {NULL, NULL, NULL}, +/* 431 */ {"ERR_NONICKNAMEGIVEN", ":%s 431 %s :No nickname given", NULL}, +/* 432 */ {"ERR_ERRONEUSNICKNAME", ":%s 432 %s %s :Erroneous Nickname", NULL}, +/* 433 */ {"ERR_NICKNAMEINUSE", ":%s 433 %s %s :Nickname is already in use.", NULL}, +/* 434 */ {NULL, NULL, NULL}, +/* 435 */ {NULL, NULL, NULL}, +/* 436 */ {"ERR_NICKCOLLISION", ":%s 436 %s %s :Nickname collision KILL", NULL}, +/* 437 */ {"ERR_UNAVAILRESOURCE", ":%s 437 %s %s :Nick/channel is temporarily unavailable", NULL}, +/* 438 */ {"ERR_NICKTOOFAST", ":%s 438 %s %s %s :Nick change too fast. Please wait %d seconds.", NULL}, +/* 439 */ {NULL, NULL, NULL}, +/* 440 */ {"ERR_SERVICESDOWN", ":%s 440 %s %s :Services is currently down.", NULL}, +/* 441 */ {"ERR_USERNOTINCHANNEL", ":%s 441 %s %s %s :They aren't on that channel", NULL}, +/* 442 */ {"ERR_NOTONCHANNEL", ":%s 442 %s %s :You're not on that channel", NULL}, +/* 443 */ {"ERR_USERONCHANNEL", ":%s 443 %s %s %s :is already on channel", NULL}, +/* 444 */ {NULL, NULL, NULL}, +/* 445 */ {NULL, NULL, NULL}, +/* 446 */ {NULL, NULL, NULL}, +/* 447 */ {NULL, NULL, NULL}, +/* 448 */ {NULL, NULL, NULL}, +/* 449 */ {NULL, NULL, NULL}, +/* 450 */ {NULL, NULL, NULL}, +/* 451 */ {"ERR_NOTREGISTERED", ":%s 451 %s :You have not registered", NULL}, +/* 452 */ {NULL, NULL, NULL}, +/* 453 */ {NULL, NULL, NULL}, +/* 454 */ {NULL, NULL, NULL}, +/* 455 */ {NULL, NULL, NULL}, +/* 456 */ {"ERR_ACCEPTFULL", ":%s 456 %s :Accept list is full", NULL}, +/* 457 */ {"ERR_ACCEPTEXIST", ":%s 457 %s %s!%s@%s :is already on your accept list", NULL}, +/* 458 */ {"ERR_ACCEPTNOT", ":%s 458 %s %s!%s@%s :is not on your accept list", NULL}, +/* 459 */ {NULL, NULL, NULL}, +/* 460 */ {NULL, NULL, NULL}, +/* 461 */ {"ERR_NEEDMOREPARAMS", ":%s 461 %s %s :Not enough parameters", NULL}, +/* 462 */ {"ERR_ALREADYREGISTRED", ":%s 462 %s :You may not reregister", NULL}, +/* 463 */ {NULL, NULL, NULL}, +/* 464 */ {"ERR_PASSWDMISMATCH", ":%s 464 %s :Password Incorrect", NULL}, +/* 465 */ {"ERR_YOUREBANNEDCREEP", ":%s 465 %s :You are banned from this server- %s", NULL}, +/* 466 */ {NULL, NULL, NULL}, +/* 467 */ {NULL, NULL, NULL}, +/* 468 */ {"ERR_ONLYSERVERSCANCHANGE", ":%s 468 %s %s :Only servers can change that mode", NULL}, +/* 469 */ {NULL, NULL, NULL}, +/* 470 */ {"ERR_OPERONLYCHAN", ":%s 470 %s %s :Cannot join channel (+O)", NULL}, +/* 471 */ {"ERR_CHANNELISFULL", ":%s 471 %s %s :Cannot join channel (+l)", NULL}, +/* 472 */ {"ERR_UNKNOWNMODE", ":%s 472 %s %c :is unknown mode char to me", NULL}, +/* 473 */ {"ERR_INVITEONLYCHAN", ":%s 473 %s %s :Cannot join channel (+i)", NULL}, +/* 474 */ {"ERR_BANNEDFROMCHAN", ":%s 474 %s %s :Cannot join channel (+b)", NULL}, +/* 475 */ {"ERR_BADCHANNELKEY", ":%s 475 %s %s :Cannot join channel (+k)", NULL}, +/* 476 */ {NULL, NULL, NULL}, +/* 477 */ {"ERR_NEEDREGGEDNICK", ":%s 477 %s %s :You need to identify to a registered nick to join or speak in that " + "channel.", NULL}, +/* 478 */ {"ERR_BANLISTFULL", ":%s 478 %s %s %s :Channel ban list is full", NULL}, +/* 479 */ {"ERR_BADCHANNAME", ":%s 479 %s %s :Illegal channel name", NULL}, +/* 480 */ {"ERR_SSLONLYCHAN", ":%s 480 %s %s :Cannot join channel (+S)", NULL}, +/* 481 */ {"ERR_NOPRIVILEGES", ":%s 481 %s :Permission Denied - You're not an IRC operator", NULL}, +/* 482 */ {"ERR_CHANOPRIVSNEEDED", ":%s 482 %s %s :You're not channel operator", NULL}, +/* 483 */ {"ERR_CANTKILLSERVER", ":%s 483 %s :You can't kill a server!", NULL}, +/* 484 */ {"ERR_RESTRICTED", ":%s 484 %s :You are restricted", NULL}, +/* 485 */ {NULL, NULL, NULL}, +/* 486 */ {"ERR_NONONREG", ":%s 486 %s %s :You must identify to a registered " + "nick to private message that person", NULL}, +/* 487 */ {NULL, NULL, NULL}, +/* 488 */ {NULL, NULL, NULL}, +/* 489 */ {NULL, NULL, NULL}, +/* 490 */ {NULL, NULL, NULL}, +/* 491 */ {"ERR_NOOPERHOST", ":%s 491 %s :Only few of mere mortals may try to enter the twilight zone", NULL}, +/* 492 */ {NULL, NULL, NULL}, +/* 493 */ {NULL, NULL, NULL}, +/* 494 */ {NULL, NULL, NULL}, +/* 495 */ {NULL, NULL, NULL}, +/* 496 */ {NULL, NULL, NULL}, +/* 497 */ {NULL, NULL, NULL}, +/* 498 */ {NULL, NULL, NULL}, +/* 499 */ {NULL, NULL, NULL}, +/* 500 */ {NULL, NULL, NULL}, +/* 501 */ {"ERR_UMODEUNKNOWNFLAG", ":%s 501 %s :Unknown MODE flag", NULL}, +/* 502 */ {"ERR_USERSDONTMATCH", ":%s 502 %s :Can't change mode for other users", NULL}, +/* 503 */ {"ERR_GHOSTEDCLIENT", ":%s 503 %s :Message could not be delivered to %s", NULL}, +/* 504 */ {"ERR_USERNOTONSERV", ":%s 504 %s %s :User is not on this server", NULL}, +/* 505 */ {NULL, NULL, NULL}, +/* 506 */ {NULL, NULL, NULL}, +/* 507 */ {NULL, NULL, NULL}, +/* 508 */ {NULL, NULL, NULL}, +/* 509 */ {NULL, NULL, NULL}, +/* 510 */ {NULL, NULL, NULL}, +/* 511 */ {NULL, NULL, NULL}, +/* 512 */ {"ERR_TOOMANYWATCH", ":%s 512 %s %s :Maximum size for WATCH-list is %d entries", NULL}, +/* 513 */ {"ERR_WRONGPONG", ":%s 513 %s :To connect type /QUOTE PONG %lu", NULL}, +/* 514 */ {NULL, NULL, NULL}, +/* 515 */ {NULL, NULL, NULL}, +/* 516 */ {NULL, NULL, NULL}, +/* 517 */ {NULL, NULL, NULL}, +/* 518 */ {NULL, NULL, NULL}, +/* 519 */ {NULL, NULL, NULL}, +/* 520 */ {NULL, NULL, NULL}, +/* 521 */ {"ERR_LISTSYNTAX", ":%s 521 %s :Bad list syntax, type /QUOTE HELP LIST", NULL}, +/* 522 */ {NULL, NULL, NULL}, +/* 523 */ {NULL, NULL, NULL}, +/* 524 */ {"ERR_HELPNOTFOUND", ":%s 524 %s %s :Help not found", NULL}, +/* 525 */ {NULL, NULL, NULL}, +/* 526 */ {NULL, NULL, NULL}, +/* 527 */ {NULL, NULL, NULL}, +/* 528 */ {NULL, NULL, NULL}, +/* 529 */ {NULL, NULL, NULL}, +/* 530 */ {NULL, NULL, NULL}, +/* 531 */ {NULL, NULL, NULL}, +/* 532 */ {NULL, NULL, NULL}, +/* 533 */ {NULL, NULL, NULL}, +/* 534 */ {NULL, NULL, NULL}, +/* 535 */ {NULL, NULL, NULL}, +/* 536 */ {NULL, NULL, NULL}, +/* 537 */ {NULL, NULL, NULL}, +/* 538 */ {NULL, NULL, NULL}, +/* 539 */ {NULL, NULL, NULL}, +/* 540 */ {NULL, NULL, NULL}, +/* 541 */ {NULL, NULL, NULL}, +/* 542 */ {NULL, NULL, NULL}, +/* 543 */ {NULL, NULL, NULL}, +/* 544 */ {NULL, NULL, NULL}, +/* 545 */ {NULL, NULL, NULL}, +/* 546 */ {NULL, NULL, NULL}, +/* 547 */ {NULL, NULL, NULL}, +/* 548 */ {NULL, NULL, NULL}, +/* 549 */ {NULL, NULL, NULL}, +/* 550 */ {NULL, NULL, NULL}, +/* 551 */ {NULL, NULL, NULL}, +/* 552 */ {NULL, NULL, NULL}, +/* 553 */ {NULL, NULL, NULL}, +/* 554 */ {NULL, NULL, NULL}, +/* 555 */ {NULL, NULL, NULL}, +/* 556 */ {NULL, NULL, NULL}, +/* 557 */ {NULL, NULL, NULL}, +/* 558 */ {NULL, NULL, NULL}, +/* 559 */ {NULL, NULL, NULL}, +/* 560 */ {NULL, NULL, NULL}, +/* 561 */ {NULL, NULL, NULL}, +/* 562 */ {NULL, NULL, NULL}, +/* 563 */ {NULL, NULL, NULL}, +/* 564 */ {NULL, NULL, NULL}, +/* 565 */ {NULL, NULL, NULL}, +/* 566 */ {NULL, NULL, NULL}, +/* 567 */ {NULL, NULL, NULL}, +/* 568 */ {NULL, NULL, NULL}, +/* 569 */ {NULL, NULL, NULL}, +/* 570 */ {NULL, NULL, NULL}, +/* 571 */ {NULL, NULL, NULL}, +/* 572 */ {NULL, NULL, NULL}, +/* 573 */ {NULL, NULL, NULL}, +/* 574 */ {NULL, NULL, NULL}, +/* 575 */ {NULL, NULL, NULL}, +/* 576 */ {NULL, NULL, NULL}, +/* 577 */ {NULL, NULL, NULL}, +/* 578 */ {NULL, NULL, NULL}, +/* 579 */ {NULL, NULL, NULL}, +/* 580 */ {NULL, NULL, NULL}, +/* 581 */ {NULL, NULL, NULL}, +/* 582 */ {NULL, NULL, NULL}, +/* 583 */ {NULL, NULL, NULL}, +/* 584 */ {NULL, NULL, NULL}, +/* 585 */ {NULL, NULL, NULL}, +/* 586 */ {NULL, NULL, NULL}, +/* 587 */ {NULL, NULL, NULL}, +/* 588 */ {NULL, NULL, NULL}, +/* 589 */ {NULL, NULL, NULL}, +/* 590 */ {NULL, NULL, NULL}, +/* 591 */ {NULL, NULL, NULL}, +/* 592 */ {NULL, NULL, NULL}, +/* 593 */ {NULL, NULL, NULL}, +/* 594 */ {NULL, NULL, NULL}, +/* 595 */ {NULL, NULL, NULL}, +/* 596 */ {NULL, NULL, NULL}, +/* 597 */ {NULL, NULL, NULL}, +/* 598 */ {NULL, NULL, NULL}, +/* 599 */ {NULL, NULL, NULL}, +/* 600 */ {"RPL_LOGON", ":%s 600 %s %s %s %s %d :logged online", NULL}, +/* 601 */ {"RPL_LOGOFF", ":%s 601 %s %s %s %s %d :logged offline", NULL}, +/* 602 */ {"RPL_WATCHOFF", ":%s 602 %s %s %s %s %d :stopped watching", NULL}, +/* 603 */ {"RPL_WATCHSTAT", ":%s 603 %s :You have %u and are on %u WATCH entries", NULL}, +/* 604 */ {"RPL_NOWON", ":%s 604 %s %s %s %s %d :is online", NULL}, +/* 605 */ {"RPL_NOWOFF", ":%s 605 %s %s %s %s %d :is offline", NULL}, +/* 606 */ {"RPL_WATCHLIST", ":%s 606 %s :%s", NULL}, +/* 607 */ {"RPL_ENDOFWATCHLIST", ":%s 607 %s :End of WATCH %c", NULL}, +/* 608 */ {NULL, NULL, NULL}, +/* 609 */ {NULL, NULL, NULL}, +/* 610 */ {NULL, NULL, NULL}, +/* 611 */ {NULL, NULL, NULL}, +/* 612 */ {NULL, NULL, NULL}, +/* 613 */ {NULL, NULL, NULL}, +/* 614 */ {NULL, NULL, NULL}, +/* 615 */ {NULL, NULL, NULL}, +/* 616 */ {NULL, NULL, NULL}, +/* 617 */ {NULL, NULL, NULL}, +/* 618 */ {NULL, NULL, NULL}, +/* 619 */ {NULL, NULL, NULL}, +/* 620 */ {NULL, NULL, NULL}, +/* 621 */ {NULL, NULL, NULL}, +/* 622 */ {NULL, NULL, NULL}, +/* 623 */ {NULL, NULL, NULL}, +/* 624 */ {NULL, NULL, NULL}, +/* 625 */ {NULL, NULL, NULL}, +/* 626 */ {NULL, NULL, NULL}, +/* 627 */ {NULL, NULL, NULL}, +/* 628 */ {NULL, NULL, NULL}, +/* 629 */ {NULL, NULL, NULL}, +/* 630 */ {NULL, NULL, NULL}, +/* 631 */ {NULL, NULL, NULL}, +/* 632 */ {NULL, NULL, NULL}, +/* 633 */ {NULL, NULL, NULL}, +/* 634 */ {NULL, NULL, NULL}, +/* 635 */ {NULL, NULL, NULL}, +/* 636 */ {NULL, NULL, NULL}, +/* 637 */ {NULL, NULL, NULL}, +/* 638 */ {NULL, NULL, NULL}, +/* 639 */ {NULL, NULL, NULL}, +/* 640 */ {NULL, NULL, NULL}, +/* 641 */ {NULL, NULL, NULL}, +/* 642 */ {NULL, NULL, NULL}, +/* 643 */ {NULL, NULL, NULL}, +/* 644 */ {NULL, NULL, NULL}, +/* 645 */ {NULL, NULL, NULL}, +/* 646 */ {NULL, NULL, NULL}, +/* 647 */ {NULL, NULL, NULL}, +/* 648 */ {NULL, NULL, NULL}, +/* 649 */ {NULL, NULL, NULL}, +/* 650 */ {NULL, NULL, NULL}, +/* 651 */ {NULL, NULL, NULL}, +/* 652 */ {NULL, NULL, NULL}, +/* 653 */ {NULL, NULL, NULL}, +/* 654 */ {NULL, NULL, NULL}, +/* 655 */ {NULL, NULL, NULL}, +/* 656 */ {NULL, NULL, NULL}, +/* 657 */ {NULL, NULL, NULL}, +/* 658 */ {NULL, NULL, NULL}, +/* 659 */ {NULL, NULL, NULL}, +/* 660 */ {NULL, NULL, NULL}, +/* 661 */ {NULL, NULL, NULL}, +/* 662 */ {NULL, NULL, NULL}, +/* 663 */ {NULL, NULL, NULL}, +/* 664 */ {NULL, NULL, NULL}, +/* 665 */ {NULL, NULL, NULL}, +/* 666 */ {NULL, NULL, NULL}, +/* 667 */ {NULL, NULL, NULL}, +/* 668 */ {NULL, NULL, NULL}, +/* 669 */ {NULL, NULL, NULL}, +/* 670 */ {NULL, NULL, NULL}, +/* 671 */ {"RPL_WHOISSECURE", ":%s 671 %s %s :is connected via SSL (secure link)", NULL}, +/* 672 */ {NULL, NULL, NULL}, +/* 673 */ {NULL, NULL, NULL}, +/* 674 */ {NULL, NULL, NULL}, +/* 675 */ {NULL, NULL, NULL}, +/* 676 */ {NULL, NULL, NULL}, +/* 677 */ {NULL, NULL, NULL}, +/* 678 */ {NULL, NULL, NULL}, +/* 679 */ {NULL, NULL, NULL}, +/* 680 */ {NULL, NULL, NULL}, +/* 681 */ {NULL, NULL, NULL}, +/* 682 */ {NULL, NULL, NULL}, +/* 683 */ {NULL, NULL, NULL}, +/* 684 */ {NULL, NULL, NULL}, +/* 685 */ {NULL, NULL, NULL}, +/* 686 */ {NULL, NULL, NULL}, +/* 687 */ {NULL, NULL, NULL}, +/* 688 */ {NULL, NULL, NULL}, +/* 689 */ {NULL, NULL, NULL}, +/* 690 */ {NULL, NULL, NULL}, +/* 691 */ {NULL, NULL, NULL}, +/* 692 */ {NULL, NULL, NULL}, +/* 693 */ {NULL, NULL, NULL}, +/* 694 */ {NULL, NULL, NULL}, +/* 695 */ {NULL, NULL, NULL}, +/* 696 */ {NULL, NULL, NULL}, +/* 697 */ {NULL, NULL, NULL}, +/* 698 */ {NULL, NULL, NULL}, +/* 699 */ {NULL, NULL, NULL}, +/* 700 */ {NULL, NULL, NULL}, +/* 701 */ {NULL, NULL, NULL}, +/* 702 */ {"RPL_MODLIST", ":%s 702 %s %s %p %s %s", NULL}, +/* 703 */ {"RPL_ENDOFMODLIST", ":%s 703 %s :End of /MODLIST.", NULL}, +/* 704 */ {"RPL_HELPSTART", ":%s 704 %s %s :%s", NULL}, +/* 705 */ {"RPL_HELPTXT", ":%s 705 %s %s :%s", NULL}, +/* 706 */ {"RPL_ENDOFHELP", ":%s 706 %s %s :End of /HELP.", NULL}, +/* 707 */ {NULL, NULL, NULL}, +/* 708 */ {"RPL_ETRACE_FULL", ":%s 708 %s %s %s %s %s %s %s %s %s :%s", NULL}, +/* 709 */ {"RPL_ETRACE", ":%s 709 %s %s %s %s %s %s %s :%s", NULL}, +/* 710 */ {"RPL_KNOCK", ":%s 710 %s %s %s!%s@%s :has asked for an invite.", NULL}, +/* 711 */ {"RPL_KNOCKDLVR", ":%s 711 %s %s :Your KNOCK has been delivered.", NULL}, +/* 712 */ {"ERR_TOOMANYKNOCK", ":%s 712 %s %s :Too many KNOCKs (%s).", NULL}, +/* 713 */ {"ERR_CHANOPEN", ":%s 713 %s %s :Channel is open.", NULL}, +/* 714 */ {"ERR_KNOCKONCHAN", ":%s 714 %s %s :You are already on that channel.", NULL}, +/* 715 */ {NULL, NULL, NULL}, +/* 716 */ {"RPL_TARGUMODEG", ":%s 716 %s %s :is in +g mode (server side ignore)", NULL}, +/* 717 */ {"RPL_TARGNOTIFY", ":%s 717 %s %s :has been informed that you messaged them.", NULL}, +/* 718 */ {"RPL_UMODEGMSG", ":%s 718 %s %s :is messaging you, and you are umode +g.", NULL}, +/* 719 */ {NULL, NULL, NULL}, +/* 720 */ {NULL, NULL, NULL}, +/* 721 */ {NULL, NULL, NULL}, +/* 722 */ {NULL, NULL, NULL}, +/* 723 */ {"ERR_NOPRIVS", ":%s 723 %s %s :Insufficient oper privs.", NULL }, +/* 724 */ {"RPL_TESTMASK", ":%s 724 %s %s!%s@%s %u %u :Local/remote clients match.", NULL }, +/* 725 */ {"RPL_TESTLINE", ":%s 725 %s %c %ld %s :%s | %s", NULL }, +/* 726 */ {"RPL_NOTESTLINE", ":%s 726 %s %s :No matches", NULL }, +/* 727 */ {NULL, NULL, NULL}, +/* 728 */ {NULL, NULL, NULL}, +/* 729 */ {NULL, NULL, NULL}, +/* 730 */ {NULL, NULL, NULL}, +/* 731 */ {NULL, NULL, NULL}, +/* 732 */ {NULL, NULL, NULL}, +/* 733 */ {NULL, NULL, NULL}, +/* 734 */ {NULL, NULL, NULL}, +/* 735 */ {NULL, NULL, NULL}, +/* 736 */ {NULL, NULL, NULL}, +/* 737 */ {NULL, NULL, NULL}, +/* 738 */ {NULL, NULL, NULL}, +/* 739 */ {NULL, NULL, NULL}, +/* 740 */ {NULL, NULL, NULL}, +/* 741 */ {NULL, NULL, NULL}, +/* 742 */ {NULL, NULL, NULL}, +/* 743 */ {NULL, NULL, NULL}, +/* 744 */ {NULL, NULL, NULL}, +/* 745 */ {NULL, NULL, NULL}, +/* 746 */ {NULL, NULL, NULL}, +/* 747 */ {NULL, NULL, NULL}, +/* 748 */ {NULL, NULL, NULL}, +/* 749 */ {NULL, NULL, NULL}, +/* 750 */ {NULL, NULL, NULL}, +/* 751 */ {NULL, NULL, NULL}, +/* 752 */ {NULL, NULL, NULL}, +/* 753 */ {NULL, NULL, NULL}, +/* 754 */ {NULL, NULL, NULL}, +/* 755 */ {NULL, NULL, NULL}, +/* 756 */ {NULL, NULL, NULL}, +/* 757 */ {NULL, NULL, NULL}, +/* 758 */ {NULL, NULL, NULL}, +/* 759 */ {NULL, NULL, NULL}, +/* 760 */ {NULL, NULL, NULL}, +/* 761 */ {NULL, NULL, NULL}, +/* 762 */ {NULL, NULL, NULL}, +/* 763 */ {NULL, NULL, NULL}, +/* 764 */ {NULL, NULL, NULL}, +/* 765 */ {NULL, NULL, NULL}, +/* 766 */ {NULL, NULL, NULL}, +/* 767 */ {NULL, NULL, NULL}, +/* 768 */ {NULL, NULL, NULL}, +/* 769 */ {NULL, NULL, NULL}, +/* 770 */ {NULL, NULL, NULL}, +/* 771 */ {NULL, NULL, NULL}, +/* 772 */ {NULL, NULL, NULL}, +/* 773 */ {NULL, NULL, NULL}, +/* 774 */ {NULL, NULL, NULL}, +/* 775 */ {NULL, NULL, NULL}, +/* 776 */ {NULL, NULL, NULL}, +/* 777 */ {NULL, NULL, NULL}, +/* 778 */ {NULL, NULL, NULL}, +/* 779 */ {NULL, NULL, NULL}, +/* 780 */ {NULL, NULL, NULL}, +/* 781 */ {NULL, NULL, NULL}, +/* 782 */ {NULL, NULL, NULL}, +/* 783 */ {NULL, NULL, NULL}, +/* 784 */ {NULL, NULL, NULL}, +/* 785 */ {NULL, NULL, NULL}, +/* 786 */ {NULL, NULL, NULL}, +/* 787 */ {NULL, NULL, NULL}, +/* 788 */ {NULL, NULL, NULL}, +/* 789 */ {NULL, NULL, NULL}, +/* 790 */ {NULL, NULL, NULL}, +/* 791 */ {NULL, NULL, NULL}, +/* 792 */ {NULL, NULL, NULL}, +/* 793 */ {NULL, NULL, NULL}, +/* 794 */ {NULL, NULL, NULL}, +/* 795 */ {NULL, NULL, NULL}, +/* 796 */ {NULL, NULL, NULL}, +/* 797 */ {NULL, NULL, NULL}, +/* 798 */ {NULL, NULL, NULL}, +/* 799 */ {NULL, NULL, NULL}, +/* 800 */ {NULL, NULL, NULL}, +/* 801 */ {NULL, NULL, NULL}, +/* 802 */ {NULL, NULL, NULL}, +/* 803 */ {NULL, NULL, NULL}, +/* 804 */ {NULL, NULL, NULL}, +/* 805 */ {NULL, NULL, NULL}, +/* 806 */ {NULL, NULL, NULL}, +/* 807 */ {NULL, NULL, NULL}, +/* 808 */ {NULL, NULL, NULL}, +/* 809 */ {NULL, NULL, NULL}, +/* 810 */ {NULL, NULL, NULL}, +/* 811 */ {NULL, NULL, NULL}, +/* 812 */ {NULL, NULL, NULL}, +/* 813 */ {NULL, NULL, NULL}, +/* 814 */ {NULL, NULL, NULL}, +/* 815 */ {NULL, NULL, NULL}, +/* 816 */ {NULL, NULL, NULL}, +/* 817 */ {NULL, NULL, NULL}, +/* 818 */ {NULL, NULL, NULL}, +/* 819 */ {NULL, NULL, NULL}, +/* 820 */ {NULL, NULL, NULL}, +/* 821 */ {NULL, NULL, NULL}, +/* 822 */ {NULL, NULL, NULL}, +/* 823 */ {NULL, NULL, NULL}, +/* 824 */ {NULL, NULL, NULL}, +/* 825 */ {NULL, NULL, NULL}, +/* 826 */ {NULL, NULL, NULL}, +/* 827 */ {NULL, NULL, NULL}, +/* 828 */ {NULL, NULL, NULL}, +/* 829 */ {NULL, NULL, NULL}, +/* 830 */ {NULL, NULL, NULL}, +/* 831 */ {NULL, NULL, NULL}, +/* 832 */ {NULL, NULL, NULL}, +/* 833 */ {NULL, NULL, NULL}, +/* 834 */ {NULL, NULL, NULL}, +/* 835 */ {NULL, NULL, NULL}, +/* 836 */ {NULL, NULL, NULL}, +/* 837 */ {NULL, NULL, NULL}, +/* 838 */ {NULL, NULL, NULL}, +/* 839 */ {NULL, NULL, NULL}, +/* 840 */ {NULL, NULL, NULL}, +/* 841 */ {NULL, NULL, NULL}, +/* 842 */ {NULL, NULL, NULL}, +/* 843 */ {NULL, NULL, NULL}, +/* 844 */ {NULL, NULL, NULL}, +/* 845 */ {NULL, NULL, NULL}, +/* 846 */ {NULL, NULL, NULL}, +/* 847 */ {NULL, NULL, NULL}, +/* 848 */ {NULL, NULL, NULL}, +/* 849 */ {NULL, NULL, NULL}, +/* 850 */ {NULL, NULL, NULL}, +/* 851 */ {NULL, NULL, NULL}, +/* 852 */ {NULL, NULL, NULL}, +/* 853 */ {NULL, NULL, NULL}, +/* 854 */ {NULL, NULL, NULL}, +/* 855 */ {NULL, NULL, NULL}, +/* 856 */ {NULL, NULL, NULL}, +/* 857 */ {NULL, NULL, NULL}, +/* 858 */ {NULL, NULL, NULL}, +/* 859 */ {NULL, NULL, NULL}, +/* 860 */ {NULL, NULL, NULL}, +/* 861 */ {NULL, NULL, NULL}, +/* 862 */ {NULL, NULL, NULL}, +/* 863 */ {NULL, NULL, NULL}, +/* 864 */ {NULL, NULL, NULL}, +/* 865 */ {NULL, NULL, NULL}, +/* 866 */ {NULL, NULL, NULL}, +/* 867 */ {NULL, NULL, NULL}, +/* 868 */ {NULL, NULL, NULL}, +/* 869 */ {NULL, NULL, NULL}, +/* 870 */ {NULL, NULL, NULL}, +/* 871 */ {NULL, NULL, NULL}, +/* 872 */ {NULL, NULL, NULL}, +/* 873 */ {NULL, NULL, NULL}, +/* 874 */ {NULL, NULL, NULL}, +/* 875 */ {NULL, NULL, NULL}, +/* 876 */ {NULL, NULL, NULL}, +/* 877 */ {NULL, NULL, NULL}, +/* 878 */ {NULL, NULL, NULL}, +/* 879 */ {NULL, NULL, NULL}, +/* 880 */ {NULL, NULL, NULL}, +/* 881 */ {NULL, NULL, NULL}, +/* 882 */ {NULL, NULL, NULL}, +/* 883 */ {NULL, NULL, NULL}, +/* 884 */ {NULL, NULL, NULL}, +/* 885 */ {NULL, NULL, NULL}, +/* 886 */ {NULL, NULL, NULL}, +/* 887 */ {NULL, NULL, NULL}, +/* 888 */ {NULL, NULL, NULL}, +/* 889 */ {NULL, NULL, NULL}, +/* 890 */ {NULL, NULL, NULL}, +/* 891 */ {NULL, NULL, NULL}, +/* 892 */ {NULL, NULL, NULL}, +/* 893 */ {NULL, NULL, NULL}, +/* 894 */ {NULL, NULL, NULL}, +/* 895 */ {NULL, NULL, NULL}, +/* 896 */ {NULL, NULL, NULL}, +/* 897 */ {NULL, NULL, NULL}, +/* 898 */ {NULL, NULL, NULL}, +/* 899 */ {NULL, NULL, NULL}, +/* 900 */ {NULL, NULL, NULL}, +/* 901 */ {NULL, NULL, NULL}, +/* 902 */ {NULL, NULL, NULL}, +/* 903 */ {NULL, NULL, NULL}, +/* 904 */ {NULL, NULL, NULL}, +/* 905 */ {NULL, NULL, NULL}, +/* 906 */ {NULL, NULL, NULL}, +/* 907 */ {NULL, NULL, NULL}, +/* 908 */ {NULL, NULL, NULL}, +/* 909 */ {NULL, NULL, NULL}, +/* 910 */ {NULL, NULL, NULL}, +/* 911 */ {NULL, NULL, NULL}, +/* 912 */ {NULL, NULL, NULL}, +/* 913 */ {NULL, NULL, NULL}, +/* 914 */ {NULL, NULL, NULL}, +/* 915 */ {NULL, NULL, NULL}, +/* 916 */ {NULL, NULL, NULL}, +/* 917 */ {NULL, NULL, NULL}, +/* 918 */ {NULL, NULL, NULL}, +/* 919 */ {NULL, NULL, NULL}, +/* 920 */ {NULL, NULL, NULL}, +/* 921 */ {NULL, NULL, NULL}, +/* 922 */ {NULL, NULL, NULL}, +/* 923 */ {NULL, NULL, NULL}, +/* 924 */ {NULL, NULL, NULL}, +/* 925 */ {NULL, NULL, NULL}, +/* 926 */ {NULL, NULL, NULL}, +/* 927 */ {NULL, NULL, NULL}, +/* 928 */ {NULL, NULL, NULL}, +/* 929 */ {NULL, NULL, NULL}, +/* 930 */ {NULL, NULL, NULL}, +/* 931 */ {NULL, NULL, NULL}, +/* 932 */ {NULL, NULL, NULL}, +/* 933 */ {NULL, NULL, NULL}, +/* 934 */ {NULL, NULL, NULL}, +/* 935 */ {NULL, NULL, NULL}, +/* 936 */ {NULL, NULL, NULL}, +/* 937 */ {NULL, NULL, NULL}, +/* 938 */ {NULL, NULL, NULL}, +/* 939 */ {NULL, NULL, NULL}, +/* 940 */ {NULL, NULL, NULL}, +/* 941 */ {NULL, NULL, NULL}, +/* 942 */ {NULL, NULL, NULL}, +/* 943 */ {NULL, NULL, NULL}, +/* 944 */ {NULL, NULL, NULL}, +/* 945 */ {NULL, NULL, NULL}, +/* 946 */ {NULL, NULL, NULL}, +/* 947 */ {NULL, NULL, NULL}, +/* 948 */ {NULL, NULL, NULL}, +/* 949 */ {NULL, NULL, NULL}, +/* 950 */ {NULL, NULL, NULL}, +/* 951 */ {NULL, NULL, NULL}, +/* 952 */ {NULL, NULL, NULL}, +/* 953 */ {NULL, NULL, NULL}, +/* 954 */ {NULL, NULL, NULL}, +/* 955 */ {NULL, NULL, NULL}, +/* 956 */ {NULL, NULL, NULL}, +/* 957 */ {NULL, NULL, NULL}, +/* 958 */ {NULL, NULL, NULL}, +/* 959 */ {NULL, NULL, NULL}, +/* 960 */ {NULL, NULL, NULL}, +/* 961 */ {NULL, NULL, NULL}, +/* 962 */ {NULL, NULL, NULL}, +/* 963 */ {NULL, NULL, NULL}, +/* 964 */ {NULL, NULL, NULL}, +/* 965 */ {NULL, NULL, NULL}, +/* 966 */ {NULL, NULL, NULL}, +/* 967 */ {NULL, NULL, NULL}, +/* 968 */ {NULL, NULL, NULL}, +/* 969 */ {NULL, NULL, NULL}, +/* 970 */ {NULL, NULL, NULL}, +/* 971 */ {NULL, NULL, NULL}, +/* 972 */ {NULL, NULL, NULL}, +/* 973 */ {NULL, NULL, NULL}, +/* 974 */ {NULL, NULL, NULL}, +/* 975 */ {NULL, NULL, NULL}, +/* 976 */ {NULL, NULL, NULL}, +/* 977 */ {NULL, NULL, NULL}, +/* 978 */ {NULL, NULL, NULL}, +/* 979 */ {NULL, NULL, NULL}, +/* 980 */ {NULL, NULL, NULL}, +/* 981 */ {NULL, NULL, NULL}, +/* 982 */ {NULL, NULL, NULL}, +/* 983 */ {NULL, NULL, NULL}, +/* 984 */ {NULL, NULL, NULL}, +/* 985 */ {NULL, NULL, NULL}, +/* 986 */ {NULL, NULL, NULL}, +/* 987 */ {NULL, NULL, NULL}, +/* 988 */ {NULL, NULL, NULL}, +/* 989 */ {NULL, NULL, NULL}, +/* 990 */ {NULL, NULL, NULL}, +/* 991 */ {NULL, NULL, NULL}, +/* 992 */ {NULL, NULL, NULL}, +/* 993 */ {NULL, NULL, NULL}, +/* 994 */ {NULL, NULL, NULL}, +/* 995 */ {NULL, NULL, NULL}, +/* 996 */ {NULL, NULL, NULL}, +/* 997 */ {NULL, NULL, NULL}, +/* 998 */ {NULL, NULL, NULL}, +/* 999 */ {NULL, NULL, NULL} +}; diff --git a/src/modules.c b/src/modules.c new file mode 100644 index 0000000..8a5ab1b --- /dev/null +++ b/src/modules.c @@ -0,0 +1,401 @@ +/* + * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd). + * modules.c: A module loader. + * + * Copyright (C) 2002 by the past and present ircd coders, and others. + * + * 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 + * + * $Id$ + */ + +#include "ltdl.h" + +#include "stdinc.h" +#include "list.h" +#include "modules.h" +#include "log.h" +#include "ircd.h" +#include "client.h" +#include "send.h" +#include "conf.h" +#include "numeric.h" +#include "parse.h" +#include "ircd_defs.h" +#include "irc_string.h" +#include "memory.h" + + +dlink_list modules_list = { NULL, NULL, 0 }; + +static const char *unknown_ver = "<unknown>"; + +static const char *core_module_table[] = +{ + "m_die.la", + "m_error.la", + "m_join.la", + "m_kick.la", + "m_kill.la", + "m_message.la", + "m_mode.la", + "m_nick.la", + "m_part.la", + "m_quit.la", + "m_server.la", + "m_sjoin.la", + "m_squit.la", + NULL +}; + +static dlink_list mod_paths = { NULL, NULL, 0 }; +static dlink_list conf_modules = { NULL, NULL, 0 }; + +int +modules_valid_suffix(const char *name) +{ + return ((name = strrchr(name, '.'))) && !strcmp(name, ".la"); +} + +/* unload_one_module() + * + * inputs - name of module to unload + * - 1 to say modules unloaded, 0 to not + * output - 0 if successful, -1 if error + * side effects - module is unloaded + */ +int +unload_one_module(const char *name, int warn) +{ + struct module *modp = NULL; + + if ((modp = findmodule_byname(name)) == NULL) + return -1; + + if (modp->modexit) + modp->modexit(); + + assert(dlink_list_length(&modules_list) > 0); + dlinkDelete(&modp->node, &modules_list); + MyFree(modp->name); + + lt_dlclose(modp->handle); + + if (warn == 1) + { + ilog(LOG_TYPE_IRCD, "Module %s unloaded", name); + sendto_realops_flags(UMODE_ALL, L_ALL, "Module %s unloaded", name); + } + + return 0; +} + +/* load_a_module() + * + * inputs - path name of module, int to notice, int of core + * output - -1 if error 0 if success + * side effects - loads a module if successful + */ +int +load_a_module(const char *path, int warn) +{ + lt_dlhandle tmpptr = NULL; + const char *mod_basename = NULL; + struct module *modp = NULL; + + if (findmodule_byname((mod_basename = libio_basename(path)))) + return 1; + + if (!(tmpptr = lt_dlopen(path))) { + const char *err = ((err = lt_dlerror())) ? err : "<unknown>"; + + sendto_realops_flags(UMODE_ALL, L_ALL, "Error loading module %s: %s", + mod_basename, err); + ilog(LOG_TYPE_IRCD, "Error loading module %s: %s", mod_basename, err); + return -1; + } + + if ((modp = lt_dlsym(tmpptr, "module_entry")) == NULL) + { + const char *err = ((err = lt_dlerror())) ? err : "<unknown>"; + + sendto_realops_flags(UMODE_ALL, L_ALL, "Error loading module %s: %s", + mod_basename, err); + ilog(LOG_TYPE_IRCD, "Error loading module %s: %s", mod_basename, err); + lt_dlclose(tmpptr); + return -1; + } + + modp->handle = tmpptr; + + if (EmptyString(modp->version)) + modp->version = unknown_ver; + + DupString(modp->name, mod_basename); + dlinkAdd(modp, &modp->node, &modules_list); + + if (modp->modinit) + modp->modinit(); + + if (warn == 1) + { + sendto_realops_flags(UMODE_ALL, L_ALL, + "Module %s [version: %s handle: %p] loaded.", + modp->name, modp->version, tmpptr); + ilog(LOG_TYPE_IRCD, "Module %s [version: %s handle: %p] loaded.", + modp->name, modp->version, tmpptr); + } + + return 0; +} + +/* + * modules_init + * + * input - NONE + * output - NONE + * side effects - The basic module manipulation modules are loaded + */ +void +modules_init(void) +{ + if (lt_dlinit()) + { + ilog(LOG_TYPE_IRCD, "Couldn't initialize the libltdl run time dynamic" + " link library. Exiting."); + exit(0); + } +} + +/* mod_find_path() + * + * input - path + * output - none + * side effects - returns a module path from path + */ +static struct module_path * +mod_find_path(const char *path) +{ + dlink_node *ptr; + + DLINK_FOREACH(ptr, mod_paths.head) + { + struct module_path *mpath = ptr->data; + + if (!strcmp(path, mpath->path)) + return mpath; + } + + return NULL; +} + +/* mod_add_path() + * + * input - path + * output - NONE + * side effects - adds path to list + */ +void +mod_add_path(const char *path) +{ + struct module_path *pathst; + + if (mod_find_path(path)) + return; + + pathst = MyMalloc(sizeof(struct module_path)); + + strlcpy(pathst->path, path, sizeof(pathst->path)); + dlinkAdd(pathst, &pathst->node, &mod_paths); +} + +/* add_conf_module + * + * input - module name + * output - NONE + * side effects - adds module to conf_mod + */ +void +add_conf_module(const char *name) +{ + struct module_path *pathst; + + pathst = MyMalloc(sizeof(struct module_path)); + + strlcpy(pathst->path, name, sizeof(pathst->path)); + dlinkAdd(pathst, &pathst->node, &conf_modules); +} + +/* mod_clear_paths() + * + * input - NONE + * output - NONE + * side effects - clear the lists of paths and conf modules + */ +void +mod_clear_paths(void) +{ + dlink_node *ptr = NULL, *next_ptr = NULL; + + DLINK_FOREACH_SAFE(ptr, next_ptr, mod_paths.head) + { + dlinkDelete(ptr, &mod_paths); + MyFree(ptr->data); + } + + DLINK_FOREACH_SAFE(ptr, next_ptr, conf_modules.head) + { + dlinkDelete(ptr, &conf_modules); + MyFree(ptr->data); + } +} + +/* findmodule_byname + * + * input - name of module + * output - NULL if not found or pointer to module + * side effects - NONE + */ +struct module * +findmodule_byname(const char *name) +{ + dlink_node *ptr = NULL; + + DLINK_FOREACH(ptr, modules_list.head) + { + struct module *modp = ptr->data; + + if (strcmp(modp->name, name) == 0) + return modp; + } + + return NULL; +} + +/* load_all_modules() + * + * input - int flag warn + * output - NONE + * side effects - load all modules found in autoload directory + */ +void +load_all_modules(int warn) +{ + DIR *system_module_dir = NULL; + struct dirent *ldirent = NULL; + char module_fq_name[PATH_MAX + 1]; + + if ((system_module_dir = opendir(AUTOMODPATH)) == NULL) + { + ilog(LOG_TYPE_IRCD, "Could not load modules from %s: %s", + AUTOMODPATH, strerror(errno)); + return; + } + + while ((ldirent = readdir(system_module_dir)) != NULL) + { + if (modules_valid_suffix(ldirent->d_name)) + { + snprintf(module_fq_name, sizeof(module_fq_name), "%s/%s", + AUTOMODPATH, ldirent->d_name); + load_a_module(module_fq_name, warn); + } + } + + closedir(system_module_dir); +} + +/* load_conf_modules() + * + * input - NONE + * output - NONE + * side effects - load modules given in ircd.conf + */ +void +load_conf_modules(void) +{ + dlink_node *ptr = NULL; + + DLINK_FOREACH(ptr, conf_modules.head) + { + struct module_path *mpath = ptr->data; + + if (findmodule_byname(mpath->path) == NULL) + load_one_module(mpath->path); + } +} + +/* load_core_modules() + * + * input - int flag warn + * output - NONE + * side effects - core modules are loaded, if any fail, kill ircd + */ +void +load_core_modules(int warn) +{ + char module_name[PATH_MAX + 1]; + int i = 0; + + for (; core_module_table[i]; ++i) + { + snprintf(module_name, sizeof(module_name), "%s%s", + MODPATH, core_module_table[i]); + + if (load_a_module(module_name, warn) == -1) + { + ilog(LOG_TYPE_IRCD, "Error loading core module %s: terminating ircd", + core_module_table[i]); + exit(EXIT_FAILURE); + } + } +} + +/* load_one_module() + * + * input - pointer to path + * - flagged as core module or not + * output - -1 if error + * side effects - module is loaded if found. + */ +int +load_one_module(const char *path) +{ + dlink_node *ptr = NULL; + char modpath[PATH_MAX + 1]; + struct stat statbuf; + + DLINK_FOREACH(ptr, mod_paths.head) + { + const struct module_path *mpath = ptr->data; + + snprintf(modpath, sizeof(modpath), "%s/%s", mpath->path, path); + + if (!modules_valid_suffix(path)) + continue; + + if (strstr(modpath, "../") == NULL && + strstr(modpath, "/..") == NULL) + if (!stat(modpath, &statbuf)) + if (S_ISREG(statbuf.st_mode)) /* Regular files only please */ + return load_a_module(modpath, 1); + } + + sendto_realops_flags(UMODE_ALL, L_ALL, + "Cannot locate module %s", path); + ilog(LOG_TYPE_IRCD, "Cannot locate module %s", path); + return -1; +} diff --git a/src/motd.c b/src/motd.c new file mode 100644 index 0000000..a4c2612 --- /dev/null +++ b/src/motd.c @@ -0,0 +1,283 @@ +/* + * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd). + * motd.c: Message of the day functions. + * + * Copyright (C) 2002 by the past and present ircd coders, and others. + * + * 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 + * + * $Id$ + */ + +#include "stdinc.h" +#include "list.h" +#include "motd.h" +#include "ircd.h" +#include "fdlist.h" +#include "s_bsd.h" +#include "conf.h" +#include "send.h" +#include "numeric.h" +#include "client.h" +#include "irc_string.h" +#include "sprintf_irc.h" +#include "memory.h" +#include "s_serv.h" + +/* +** init_message_file +** +*/ +void +init_message_file(MotdType motdType, const char *fileName, MessageFile *motd) +{ + strlcpy(motd->fileName, fileName, sizeof(motd->fileName)); + motd->motdType = motdType; + motd->contentsOfFile = NULL; + motd->lastChangedDate[0] = '\0'; +} + +/* +** send_message_file +** +** This function split off so a server notice could be generated on a +** user requested motd, but not on each connecting client. +*/ +int +send_message_file(struct Client *source_p, MessageFile *motdToPrint) +{ + MessageFileLine *linePointer; + MotdType motdType; + const char *from, *to; + + if (motdToPrint == NULL) + return(-1); + + motdType = motdToPrint->motdType; + + from = ID_or_name(&me, source_p->from); + to = ID_or_name(source_p, source_p->from); + + switch (motdType) + { + case USER_MOTD: + if (motdToPrint->contentsOfFile == NULL) + sendto_one(source_p, form_str(ERR_NOMOTD), from, to); + else + { + sendto_one(source_p, form_str(RPL_MOTDSTART), + from, to, me.name); + + for (linePointer = motdToPrint->contentsOfFile; linePointer; + linePointer = linePointer->next) + { + sendto_one(source_p, form_str(RPL_MOTD), + from, to, linePointer->line); + } + + sendto_one(source_p, form_str(RPL_ENDOFMOTD), from, to); + } + break; + + case USER_LINKS: + if (motdToPrint->contentsOfFile != NULL) + { + for (linePointer = motdToPrint->contentsOfFile; linePointer; + linePointer = linePointer->next) + { + sendto_one(source_p, ":%s 364 %s %s", /* XXX */ + from, to, linePointer->line); + } + } + break; + + case ISSUPPORT: + if (motdToPrint->contentsOfFile != NULL) + { + for (linePointer = motdToPrint->contentsOfFile; linePointer; + linePointer = linePointer->next) + { + sendto_one(source_p, form_str(RPL_ISUPPORT), + me.name, source_p->name, linePointer->line); + } + } + break; + + default: + break; + } + + return(0); +} + +/* + * read_message_file() - original From CoMSTuD, added Aug 29, 1996 + * + * inputs - pointer to MessageFileptr + * output - + * side effects - + */ +int +read_message_file(MessageFile *MessageFileptr) +{ + struct stat sb; + struct tm *local_tm; + + /* used to clear out old MessageFile entries */ + MessageFileLine *mptr = 0; + MessageFileLine *next_mptr = 0; + + /* used to add new MessageFile entries */ + MessageFileLine *newMessageLine = 0; + MessageFileLine *currentMessageLine = 0; + + char buffer[MESSAGELINELEN]; + char *p; + FILE *file; + + for (mptr = MessageFileptr->contentsOfFile; mptr; mptr = next_mptr) + { + next_mptr = mptr->next; + MyFree(mptr); + } + + MessageFileptr->contentsOfFile = NULL; + + if (stat(MessageFileptr->fileName, &sb) < 0) + return(-1); + + local_tm = localtime(&sb.st_mtime); + + if (local_tm) + ircsprintf(MessageFileptr->lastChangedDate, + "%d/%d/%d %d:%02d", + local_tm->tm_mday, + local_tm->tm_mon + 1, + 1900 + local_tm->tm_year, + local_tm->tm_hour, + local_tm->tm_min); + + if ((file = fopen(MessageFileptr->fileName, "r")) == NULL) + return(-1); + + while (fgets(buffer, sizeof(buffer), file)) + { + if ((p = strchr(buffer, '\n')) != NULL) + *p = '\0'; + + newMessageLine = (MessageFileLine *)MyMalloc(sizeof(MessageFileLine)); + strlcpy(newMessageLine->line, buffer, sizeof(newMessageLine->line)); + newMessageLine->next = NULL; + + if (MessageFileptr->contentsOfFile != NULL) + { + if (currentMessageLine) + currentMessageLine->next = newMessageLine; + + currentMessageLine = newMessageLine; + } + else + { + MessageFileptr->contentsOfFile = newMessageLine; + currentMessageLine = newMessageLine; + } + } + + fclose(file); + return(0); +} + +/* + * init_MessageLine + * + * inputs - NONE + * output - pointer to new MessageFile + * side effects - Use this when an internal Message File is wanted + * without reading an actual file. The MessageFile + * is init'ed, but must have content added to it through + * addto_MessageLine() + */ + +MessageFile * +init_MessageLine(void) +{ + MessageFile *mf; + MessageFileLine *mptr = NULL; + + mf = MyMalloc(sizeof(MessageFile)); + mf->motdType = ISSUPPORT; /* XXX maybe pass it alone in args? */ + mptr = MyMalloc(sizeof(MessageFileLine)); + mf->contentsOfFile = mptr; + return(mf); +} + +/* + * addto_MessageLine + * + * inputs - Pointer to existing MessageFile + * - New string to add to this MessageFile + * output - NONE + * side effects - Use this when an internal MessageFile is wanted + * without reading an actual file. Content is added + * to this MessageFile through this function. + */ + +void +addto_MessageLine(MessageFile *mf, const char *str) +{ + MessageFileLine *mptr = mf->contentsOfFile; + MessageFileLine *nmptr = NULL; + + if (mptr == NULL) + { + mptr = MyMalloc(sizeof(MessageFileLine)); + strcpy(mptr->line, str); + mf->contentsOfFile = mptr; + } + else + { + while (mptr->next != NULL) + mptr = mptr->next; + nmptr = MyMalloc(sizeof(MessageFileLine)); + strcpy(nmptr->line, str); + mptr->next = nmptr; + } +} + +/* + * destroy_MessageLine(MessageFile *mf) + * + * inputs - pointer to the MessageFile to destroy + * output - NONE + * side effects - All the MessageLines attached to the given mf + * Are freed then one MessageLine is recreated + */ +void +destroy_MessageLine(MessageFile *mf) +{ + MessageFileLine *mptr = mf->contentsOfFile; + MessageFileLine *nmptr = NULL; + + if (mptr == NULL) + return; + + for (mptr = mf->contentsOfFile; mptr != NULL; mptr = nmptr) + { + nmptr = mptr->next; + MyFree(mptr); + } + mf->contentsOfFile = NULL; +} diff --git a/src/numeric.c b/src/numeric.c new file mode 100644 index 0000000..2a1042d --- /dev/null +++ b/src/numeric.c @@ -0,0 +1,226 @@ +/* + * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd). + * numeric.c: Numeric handling functions. + * + * Copyright (C) 2002 by the past and present ircd coders, and others. + * + * 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 + * + * $Id$ + */ + +#include "stdinc.h" + +#include "numeric.h" +#include "irc_string.h" +#include "memory.h" +#include "log.h" +#include "send.h" +#include "client.h" +#include "messages.tab" + +static char used_locale[LOCALE_LENGTH] = "standard"; + +/* + * form_str + * + * inputs - numeric + * output - corresponding string + * side effects - NONE + */ +const char* form_str(int numeric) +{ + assert(-1 < numeric); + assert(numeric < ERR_LAST_ERR_MSG); + + if (numeric > ERR_LAST_ERR_MSG) + numeric = ERR_LAST_ERR_MSG; + if (numeric < 0) + numeric = ERR_LAST_ERR_MSG; + + assert(replies[numeric].standard != NULL); + + return (replies[numeric].translated != NULL ? replies[numeric].translated : + replies[numeric].standard); +} + +/* Attempts to change a numeric with index "reply" to "new_reply". + * Returns 1 if ok, 0 otherwise. + */ +static int +change_reply(const char *locale, int linecnt, int reply, char *new_reply) +{ + int found; + char *new = new_reply; + const char *old = replies[reply].standard; + + for (; *new; new++) + { + if (*new == '%') + { + if (!*++new) break; + if (*new != '%') + { + /* We've just found a format symbol. Check if it is the next format + * symbol in the original reply. + */ + for (; *new >= '0' && *new <= '9'; new++); /* skip size prefix */ + found = 0; + for (; *old; old++) + { + if (*old == '%') + { + if (!*++old) break; /* shouldn't happen */ + if (*old != '%') + { + for (; *old >= '0' && *old <= '9'; old++); /* skip size prefix */ + if (*new != *old++) + { + ilog(LOG_TYPE_IRCD, "Incompatible format symbols (%s.lang, %d)", + locale, linecnt); + return 0; + } + found = 1; + break; + } + } + } + if (!found) + { + ilog(LOG_TYPE_IRCD, "Too many format symbols (%s.lang, %d)", locale, linecnt); + return(0); + } + } + } + } + + MyFree(replies[reply].translated); + DupString(replies[reply].translated, new_reply); + return(1); +} + +/* Loads a language file. Errors are logged into the log file. */ +void +set_locale(const char *locale) +{ + int i, res = 1, linecnt = 0; + char buffer[IRCD_BUFSIZE + 1]; + char *ident, *reply; + FILE *f; + + /* Restore standard replies */ + for (i = 0; i <= ERR_LAST_ERR_MSG; i++) /* 0 isn't a magic number! ;> */ + { + if (replies[i].translated != NULL) + { + MyFree(replies[i].translated); + replies[i].translated = NULL; + } + } + + if (strchr(locale, '/') != NULL) + { + strlcpy(used_locale, "standard", sizeof(used_locale)); /* XXX paranoid */ + return; + } + + /* yes, I know - the slash isn't necessary. But I have to be sure + * that it'll work even if some lame admin won't put "/" at the end + * of MSGPATH. + */ + snprintf(buffer, sizeof(buffer), "%s/%s.lang", MSGPATH, locale); + if ((f = fopen(buffer, "r")) == NULL) + { + strlcpy(used_locale, "standard", sizeof(used_locale)); /* XXX */ + return; + } + + /* Process the language file */ + while (fgets(buffer, sizeof(buffer), f)) + { + ++linecnt; + if (buffer[0] == ';') + continue; /* that's a comment */ + + if ((ident = strpbrk(buffer, "\r\n")) != NULL) + *ident = '\0'; + + /* skip spaces if there are any */ + for (ident = buffer; *ident == ' ' || *ident == '\t'; ident++)/* null */; + if (*ident == '\0') + continue; /* empty line */ + + /* skip after the reply identificator */ + for (reply = ident; *reply != ' ' && *reply != '\t' && *reply != ':'; + reply++) + if (*reply == '\0') goto error; + + if (*reply == ' ' || *reply == '\t') + { + for (*reply++ = '\0'; *reply == ' ' || *reply == '\t'; reply++); + if (*reply != ':') + { + error: + ilog(LOG_TYPE_IRCD, "Invalid line in language file (%s.lang, %d)", + locale, linecnt); + res = 0; + continue; + } + } + else + *reply++ = '\0'; + if (*ident == '\0') + goto error; + + /* skip to the beginning of reply */ + while (*reply == ' ' || *reply == '\t') reply++; + if (*reply == '\0') + goto error; + + for (i = 0; i <= ERR_LAST_ERR_MSG; i++) + { + if (replies[i].name != NULL) + { + if (irccmp(replies[i].name, ident) == 0) + { + if (!change_reply(locale, linecnt, i, reply)) res = 0; + i = -1; + break; + } + } + } + if (i != -1) + { + ilog(LOG_TYPE_IRCD, + "Unknown numeric %s (%s.lang, %d)", ident, locale, linecnt); + res = 0; + } + } + fclose(f); + + strlcpy(used_locale, locale, sizeof(used_locale)); + if (!res) + sendto_realops_flags(UMODE_ALL, L_ADMIN, "Language file [%s] contains " + "errors, check server log file for more details", + used_locale); +} + +/* Returns the name of current locale. */ +const char * +get_locale(void) +{ + return used_locale; +} diff --git a/src/packet.c b/src/packet.c new file mode 100644 index 0000000..aeb4ac6 --- /dev/null +++ b/src/packet.c @@ -0,0 +1,414 @@ +/* + * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd). + * packet.c: Packet handlers. + * + * Copyright (C) 2002 by the past and present ircd coders, and others. + * + * 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 + * + * $Id$ + */ +#include "stdinc.h" +#include "list.h" +#include "s_bsd.h" +#include "conf.h" +#include "s_serv.h" +#include "client.h" +#include "ircd.h" +#include "parse.h" +#include "fdlist.h" +#include "packet.h" +#include "irc_string.h" +#include "memory.h" +#include "hook.h" +#include "send.h" +#include "s_misc.h" + +#define READBUF_SIZE 16384 + +struct Callback *iorecv_cb = NULL; + +static char readBuf[READBUF_SIZE]; +static void client_dopacket(struct Client *, char *, size_t); + +/* extract_one_line() + * + * inputs - pointer to a dbuf queue + * - pointer to buffer to copy data to + * output - length of <buffer> + * side effects - one line is copied and removed from the dbuf + */ +static int +extract_one_line(struct dbuf_queue *qptr, char *buffer) +{ + struct dbuf_block *block; + int line_bytes = 0, empty_bytes = 0, phase = 0; + unsigned int idx; + + char c; + dlink_node *ptr; + + /* + * Phase 0: "empty" characters before the line + * Phase 1: copying the line + * Phase 2: "empty" characters after the line + * (delete them as well and free some space in the dbuf) + * + * Empty characters are CR, LF and space (but, of course, not + * in the middle of a line). We try to remove as much of them as we can, + * since they simply eat server memory. + * + * --adx + */ + DLINK_FOREACH(ptr, qptr->blocks.head) + { + block = ptr->data; + + for (idx = 0; idx < block->size; idx++) + { + c = block->data[idx]; + if (IsEol(c) || (c == ' ' && phase != 1)) + { + empty_bytes++; + if (phase == 1) + phase = 2; + } + else switch (phase) + { + case 0: phase = 1; + case 1: if (line_bytes++ < IRCD_BUFSIZE - 2) + *buffer++ = c; + break; + case 2: *buffer = '\0'; + dbuf_delete(qptr, line_bytes + empty_bytes); + return IRCD_MIN(line_bytes, IRCD_BUFSIZE - 2); + } + } + } + + /* + * Now, if we haven't reached phase 2, ignore all line bytes + * that we have read, since this is a partial line case. + */ + if (phase != 2) + line_bytes = 0; + else + *buffer = '\0'; + + /* Remove what is now unnecessary */ + dbuf_delete(qptr, line_bytes + empty_bytes); + return IRCD_MIN(line_bytes, IRCD_BUFSIZE - 2); +} + +/* + * parse_client_queued - parse client queued messages + */ +static void +parse_client_queued(struct Client *client_p) +{ + int dolen = 0; + int checkflood = 1; + struct LocalUser *lclient_p = client_p->localClient; + + if (IsUnknown(client_p)) + { + int i = 0; + + for(;;) + { + if (IsDefunct(client_p)) + return; + + /* rate unknown clients at MAX_FLOOD per loop */ + if (i >= MAX_FLOOD) + break; + + dolen = extract_one_line(&lclient_p->buf_recvq, readBuf); + if (dolen == 0) + break; + + client_dopacket(client_p, readBuf, dolen); + i++; + + /* if they've dropped out of the unknown state, break and move + * to the parsing for their appropriate status. --fl + */ + if(!IsUnknown(client_p)) + break; + } + } + + if (IsServer(client_p) || IsConnecting(client_p) || IsHandshake(client_p)) + { + while (1) + { + if (IsDefunct(client_p)) + return; + if ((dolen = extract_one_line(&lclient_p->buf_recvq, + readBuf)) == 0) + break; + client_dopacket(client_p, readBuf, dolen); + } + } + else if (IsClient(client_p)) + { + if (ConfigFileEntry.no_oper_flood && (HasUMode(client_p, UMODE_OPER) || IsCanFlood(client_p))) + { + if (ConfigFileEntry.true_no_oper_flood) + checkflood = -1; + else + checkflood = 0; + } + + /* + * Handle flood protection here - if we exceed our flood limit on + * messages in this loop, we simply drop out of the loop prematurely. + * -- adrian + */ + for (;;) + { + if (IsDefunct(client_p)) + break; + + /* This flood protection works as follows: + * + * A client is given allow_read lines to send to the server. Every + * time a line is parsed, sent_parsed is increased. sent_parsed + * is decreased by 1 every time flood_recalc is called. + * + * Thus a client can 'burst' allow_read lines to the server, any + * excess lines will be parsed one per flood_recalc() call. + * + * Therefore a client will be penalised more if they keep flooding, + * as sent_parsed will always hover around the allow_read limit + * and no 'bursts' will be permitted. + */ + if (checkflood > 0) + { + if(lclient_p->sent_parsed >= lclient_p->allow_read) + break; + } + + /* allow opers 4 times the amount of messages as users. why 4? + * why not. :) --fl_ + */ + else if (lclient_p->sent_parsed >= (4 * lclient_p->allow_read) && + checkflood != -1) + break; + + dolen = extract_one_line(&lclient_p->buf_recvq, readBuf); + if (dolen == 0) + break; + + client_dopacket(client_p, readBuf, dolen); + lclient_p->sent_parsed++; + } + } +} + +/* flood_endgrace() + * + * marks the end of the clients grace period + */ +void +flood_endgrace(struct Client *client_p) +{ + SetFloodDone(client_p); + + /* Drop their flood limit back down */ + client_p->localClient->allow_read = MAX_FLOOD; + + /* sent_parsed could be way over MAX_FLOOD but under MAX_FLOOD_BURST, + * so reset it. + */ + client_p->localClient->sent_parsed = 0; +} + +/* + * flood_recalc + * + * recalculate the number of allowed flood lines. this should be called + * once a second on any given client. We then attempt to flush some data. + */ +void +flood_recalc(fde_t *fd, void *data) +{ + struct Client *client_p = data; + struct LocalUser *lclient_p = client_p->localClient; + + /* allow a bursting client their allocation per second, allow + * a client whos flooding an extra 2 per second + */ + if (IsFloodDone(client_p)) + lclient_p->sent_parsed -= 2; + else + lclient_p->sent_parsed = 0; + + if (lclient_p->sent_parsed < 0) + lclient_p->sent_parsed = 0; + + parse_client_queued(client_p); + + /* And now, try flushing .. */ + if (!IsDead(client_p)) + { + /* and finally, reset the flood check */ + comm_setflush(fd, 1000, flood_recalc, client_p); + } +} + +/* + * iorecv_default - append a packet to the recvq dbuf + */ +void * +iorecv_default(va_list args) +{ + struct Client *client_p = va_arg(args, struct Client *); + int length = va_arg(args, int); + char *buf = va_arg(args, char *); + + dbuf_put(&client_p->localClient->buf_recvq, buf, length); + return NULL; +} + +/* + * read_packet - Read a 'packet' of data from a connection and process it. + */ +void +read_packet(fde_t *fd, void *data) +{ + struct Client *client_p = data; + int length = 0; + + if (IsDefunct(client_p)) + return; + + /* + * Read some data. We *used to* do anti-flood protection here, but + * I personally think it makes the code too hairy to make sane. + * -- adrian + */ + do { +#ifdef HAVE_LIBCRYPTO + if (fd->ssl) + { + length = SSL_read(fd->ssl, readBuf, READBUF_SIZE); + + /* translate openssl error codes, sigh */ + if (length < 0) + switch (SSL_get_error(fd->ssl, length)) + { + case SSL_ERROR_WANT_WRITE: + fd->flags.pending_read = 1; + SetSendqBlocked(client_p); + comm_setselect(fd, COMM_SELECT_WRITE, (PF *) sendq_unblocked, + client_p, 0); + return; + case SSL_ERROR_WANT_READ: + errno = EWOULDBLOCK; + case SSL_ERROR_SYSCALL: + break; + case SSL_ERROR_SSL: + if (errno == EAGAIN) + break; + default: + length = errno = 0; + } + } + else +#endif + { + length = recv(fd->fd, readBuf, READBUF_SIZE, 0); + } + + if (length <= 0) + { + /* + * If true, then we can recover from this error. Just jump out of + * the loop and re-register a new io-request. + */ + if (length < 0 && ignoreErrno(errno)) + break; + + dead_link_on_read(client_p, length); + return; + } + + execute_callback(iorecv_cb, client_p, length, readBuf); + + if (client_p->localClient->lasttime < CurrentTime) + client_p->localClient->lasttime = CurrentTime; + if (client_p->localClient->lasttime > client_p->localClient->since) + client_p->localClient->since = CurrentTime; + ClearPingSent(client_p); + + /* Attempt to parse what we have */ + parse_client_queued(client_p); + + if (IsDefunct(client_p)) + return; + + /* Check to make sure we're not flooding */ + if (!(IsServer(client_p) || IsHandshake(client_p) || IsConnecting(client_p)) + && (dbuf_length(&client_p->localClient->buf_recvq) > + get_recvq(client_p))) + { + if (!(ConfigFileEntry.no_oper_flood && HasUMode(client_p, UMODE_OPER))) + { + exit_client(client_p, client_p, "Excess Flood"); + return; + } + } + } +#ifdef HAVE_LIBCRYPTO + while (length == sizeof(readBuf) || fd->ssl); +#else + while (length == sizeof(readBuf)); +#endif + + /* If we get here, we need to register for another COMM_SELECT_READ */ + comm_setselect(fd, COMM_SELECT_READ, read_packet, client_p, 0); +} + +/* + * client_dopacket - copy packet to client buf and parse it + * client_p - pointer to client structure for which the buffer data + * applies. + * buffer - pointr to the buffer containing the newly read data + * length - number of valid bytes of data in the buffer + * + * Note: + * It is implicitly assumed that dopacket is called only + * with client_p of "local" variation, which contains all the + * necessary fields (buffer etc..) + */ +static void +client_dopacket(struct Client *client_p, char *buffer, size_t length) +{ + /* + * Update messages received + */ + ++me.localClient->recv.messages; + ++client_p->localClient->recv.messages; + + /* + * Update bytes received + */ + client_p->localClient->recv.bytes += length; + me.localClient->recv.bytes += length; + + parse(client_p, buffer, buffer + length); +} diff --git a/src/parse.c b/src/parse.c new file mode 100644 index 0000000..f326d74 --- /dev/null +++ b/src/parse.c @@ -0,0 +1,815 @@ +/* + * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd). + * parse.c: The message parser. + * + * Copyright (C) 2002 by the past and present ircd coders, and others. + * + * 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 + * + * $Id$ + */ + +#include "stdinc.h" +#include "client.h" +#include "parse.h" +#include "channel.h" +#include "hash.h" +#include "irc_string.h" +#include "sprintf_irc.h" +#include "ircd.h" +#include "numeric.h" +#include "log.h" +#include "send.h" +#include "conf.h" +#include "memory.h" +#include "s_user.h" +#include "s_serv.h" + +/* + * (based on orabidoo's parser code) + * + * This has always just been a trie. Look at volume III of Knuth ACP + * + * + * ok, you start out with an array of pointers, each one corresponds + * to a letter at the current position in the command being examined. + * + * so roughly you have this for matching 'trie' or 'tie' + * + * 't' points -> [MessageTree *] 'r' -> [MessageTree *] -> 'i' + * -> [MessageTree *] -> [MessageTree *] -> 'e' and matches + * + * 'i' -> [MessageTree *] -> 'e' and matches + * + * BUGS (Limitations!) + * + * I designed this trie to parse ircd commands. Hence it currently + * casefolds. This is trivial to fix by increasing MAXPTRLEN. + * This trie also "folds" '{' etc. down. This means, the input to this + * trie must be alpha tokens only. This again, is a limitation that + * can be overcome by increasing MAXPTRLEN to include upper/lower case + * at the expense of more memory. At the extreme end, you could make + * MAXPTRLEN 128. + * + * This is also not a patricia trie. On short ircd tokens, this is + * not likely going to matter. + * + * Diane Bruce (Dianora), June 6 2003 + */ + +#define MAXPTRLEN 32 + /* Must be a power of 2, and + * larger than 26 [a-z]|[A-Z] + * its used to allocate the set + * of pointers at each node of the tree + * There are MAXPTRLEN pointers at each node. + * Obviously, there have to be more pointers + * Than ASCII letters. 32 is a nice number + * since there is then no need to shift + * 'A'/'a' to base 0 index, at the expense + * of a few never used pointers. For a small + * parser like this, this is a good compromise + * and does make it somewhat faster. + * + * - Dianora + */ + +struct MessageTree +{ + int links; /* Count of all pointers (including msg) at this node + * used as reference count for deletion of _this_ node. + */ + struct Message *msg; + struct MessageTree *pointers[MAXPTRLEN]; +}; + +static struct MessageTree msg_tree; + +/* + * NOTE: parse() should not be called recursively by other functions! + */ +static char *sender; +static char *para[MAXPARA + 2]; /* <prefix> + <params> + NULL */ +static char buffer[1024]; + +static int cancel_clients(struct Client *, struct Client *, char *); +static void remove_unknown(struct Client *, char *, char *); +static void handle_numeric(char[], struct Client *, struct Client *, int, char *[]); +static void handle_command(struct Message *, struct Client *, struct Client *, unsigned int, char *[]); + + +/* + * parse a buffer. + * + * NOTE: parse() should not be called recusively by any other functions! + */ +void +parse(struct Client *client_p, char *pbuffer, char *bufend) +{ + struct Client *from = client_p; + struct Message *msg_ptr = NULL; + char *ch = NULL; + char *s = NULL; + char *numeric = NULL; + unsigned int parc = 0; + unsigned int paramcount; + + if (IsDefunct(client_p)) + return; + + assert(client_p->localClient->fd.flags.open); + assert((bufend - pbuffer) < 512); + + for (ch = pbuffer; *ch == ' '; ++ch) /* skip spaces */ + /* null statement */ ; + + if (*ch == ':') + { + /* + * Copy the prefix to 'sender' assuming it terminates + * with SPACE (or NULL, which is an error, though). + */ + sender = ++ch; + + if ((s = strchr(ch, ' ')) != NULL) + { + *s = '\0'; + ch = ++s; + } + + if (*sender && IsServer(client_p)) + { + if ((from = find_person(client_p, sender)) == NULL) + from = hash_find_server(sender); + + /* Hmm! If the client corresponding to the + * prefix is not found--what is the correct + * action??? Now, I will ignore the message + * (old IRC just let it through as if the + * prefix just wasn't there...) --msa + */ + if (from == NULL) + { + ++ServerStats.is_unpf; + remove_unknown(client_p, sender, pbuffer); + return; + } + + if (from->from != client_p) + { + ++ServerStats.is_wrdi; + cancel_clients(client_p, from, pbuffer); + return; + } + } + + while (*ch == ' ') + ++ch; + } + + if (*ch == '\0') + { + ++ServerStats.is_empt; + return; + } + + /* Extract the command code from the packet. Point s to the end + * of the command code and calculate the length using pointer + * arithmetic. Note: only need length for numerics and *all* + * numerics must have parameters and thus a space after the command + * code. -avalon + */ + + /* EOB is 3 chars long but is not a numeric */ + if (*(ch + 3) == ' ' && /* ok, lets see if its a possible numeric.. */ + IsDigit(*ch) && IsDigit(*(ch + 1)) && IsDigit(*(ch + 2))) + { + numeric = ch; + paramcount = MAXPARA; + ++ServerStats.is_num; + s = ch + 3; /* I know this is ' ' from above if */ + *s++ = '\0'; /* blow away the ' ', and point s to next part */ + } + else + { + unsigned int ii = 0; + + if ((s = strchr(ch, ' ')) != NULL) + *s++ = '\0'; + + if ((msg_ptr = find_command(ch)) == NULL) + { + /* Note: Give error message *only* to recognized + * persons. It's a nightmare situation to have + * two programs sending "Unknown command"'s or + * equivalent to each other at full blast.... + * If it has got to person state, it at least + * seems to be well behaving. Perhaps this message + * should never be generated, though... --msa + * Hm, when is the buffer empty -- if a command + * code has been found ?? -Armin + */ + if (*pbuffer != '\0') + { + if (IsClient(from)) + sendto_one(from, form_str(ERR_UNKNOWNCOMMAND), + me.name, from->name, ch); + } + + ++ServerStats.is_unco; + return; + } + + assert(msg_ptr->cmd != NULL); + + paramcount = msg_ptr->args_max; + ii = bufend - ((s) ? s : ch); + msg_ptr->bytes += ii; + } + + /* + * Must the following loop really be so devious? On surface it + * splits the message to parameters from blank spaces. But, if + * paramcount has been reached, the rest of the message goes into + * this last parameter (about same effect as ":" has...) --msa + */ + + /* Note initially true: s==NULL || *(s-1) == '\0' !! */ + + para[parc] = from->name; + + if (s) + { + if (paramcount > MAXPARA) + paramcount = MAXPARA; + + while (1) + { + while (*s == ' ') + *s++ = '\0'; + + if (*s == '\0') + break; + + if (*s == ':') + { + /* The rest is a single parameter */ + para[++parc] = s + 1; + break; + } + + para[++parc] = s; + + if (parc >= paramcount) + break; + + while (*s && *s != ' ') + ++s; + } + } + + para[++parc] = NULL; + + if (msg_ptr != NULL) + handle_command(msg_ptr, client_p, from, parc, para); + else + handle_numeric(numeric, client_p, from, parc, para); +} + +/* handle_command() + * + * inputs - pointer to message block + * - pointer to client + * - pointer to client message is from + * - count of number of args + * - pointer to argv[] array + * output - -1 if error from server + * side effects - + */ +static void +handle_command(struct Message *mptr, struct Client *client_p, + struct Client *from, unsigned int i, char *hpara[]) +{ + MessageHandler handler = 0; + + if (IsServer(client_p)) + mptr->rcount++; + + mptr->count++; + + handler = mptr->handlers[client_p->handler]; + + /* check right amount of params is passed... --is */ + if (i < mptr->args_min) + { + if (!IsServer(client_p)) + { + sendto_one(client_p, form_str(ERR_NEEDMOREPARAMS), me.name, + EmptyString(hpara[0]) ? "*" : hpara[0], mptr->cmd); + } + else + { + sendto_realops_flags(UMODE_ALL, L_ALL, + "Dropping server %s due to (invalid) command '%s' " + "with only %d arguments (expecting %d).", + client_p->name, mptr->cmd, i, mptr->args_min); + ilog(LOG_TYPE_IRCD, "Insufficient parameters (%d) for command '%s' from %s.", + i, mptr->cmd, client_p->name); + exit_client(client_p, client_p, + "Not enough arguments to server command."); + } + } + else + (*handler)(client_p, from, i, hpara); +} + +/* add_msg_element() + * + * inputs - pointer to MessageTree + * - pointer to Message to add for given command + * - pointer to current portion of command being added + * output - NONE + * side effects - recursively build the Message Tree ;-) + */ +/* + * How this works. + * + * The code first checks to see if its reached the end of the command + * If so, that struct MessageTree has a msg pointer updated and the links + * count incremented, since a msg pointer is a reference. + * Then the code descends recursively, building the trie. + * If a pointer index inside the struct MessageTree is NULL a new + * child struct MessageTree has to be allocated. + * The links (reference count) is incremented as they are created + * in the parent. + */ +static void +add_msg_element(struct MessageTree *mtree_p, struct Message *msg_p, + const char *cmd) +{ + struct MessageTree *ntree_p; + + if (*cmd == '\0') + { + mtree_p->msg = msg_p; + mtree_p->links++; /* Have msg pointer, so up ref count */ + } + else + { + /* *cmd & (MAXPTRLEN-1) + * convert the char pointed to at *cmd from ASCII to an integer + * between 0 and MAXPTRLEN. + * Thus 'A' -> 0x1 'B' -> 0x2 'c' -> 0x3 etc. + */ + + if ((ntree_p = mtree_p->pointers[*cmd & (MAXPTRLEN - 1)]) == NULL) + { + ntree_p = MyMalloc(sizeof(struct MessageTree)); + mtree_p->pointers[*cmd & (MAXPTRLEN - 1)] = ntree_p; + + mtree_p->links++; /* Have new pointer, so up ref count */ + } + + add_msg_element(ntree_p, msg_p, cmd + 1); + } +} + +/* del_msg_element() + * + * inputs - Pointer to MessageTree to delete from + * - pointer to command name to delete + * output - NONE + * side effects - recursively deletes a token from the Message Tree ;-) + */ +/* + * How this works. + * + * Well, first off, the code recursively descends into the trie + * until it finds the terminating letter of the command being removed. + * Once it has done that, it marks the msg pointer as NULL then + * reduces the reference count on that allocated struct MessageTree + * since a command counts as a reference. + * + * Then it pops up the recurse stack. As it comes back up the recurse + * The code checks to see if the child now has no pointers or msg + * i.e. the links count has gone to zero. If its no longer used, the + * child struct MessageTree can be deleted. The parent reference + * to this child is then removed and the parents link count goes down. + * Thus, we continue to go back up removing all unused MessageTree(s) + */ +static void +del_msg_element(struct MessageTree *mtree_p, const char *cmd) +{ + struct MessageTree *ntree_p; + + /* + * In case this is called for a nonexistent command + * check that there is a msg pointer here, else links-- goes -ve + * -db + */ + if ((*cmd == '\0') && (mtree_p->msg != NULL)) + { + mtree_p->msg = NULL; + mtree_p->links--; + } + else + { + if ((ntree_p = mtree_p->pointers[*cmd & (MAXPTRLEN - 1)]) != NULL) + { + del_msg_element(ntree_p, cmd + 1); + + if (ntree_p->links == 0) + { + mtree_p->pointers[*cmd & (MAXPTRLEN - 1)] = NULL; + mtree_p->links--; + MyFree(ntree_p); + } + } + } +} + +/* msg_tree_parse() + * + * inputs - Pointer to command to find + * - Pointer to MessageTree root + * output - Find given command returning Message * if found NULL if not + * side effects - none + */ +static struct Message * +msg_tree_parse(const char *cmd) +{ + struct MessageTree *mtree = &msg_tree; + assert(cmd && *cmd); + + while (IsAlpha(*cmd) && (mtree = mtree->pointers[*cmd & (MAXPTRLEN - 1)])) + if (*++cmd == '\0') + return mtree->msg; + + return NULL; +} + +/* mod_add_cmd() + * + * inputs - pointer to struct Message + * output - none + * side effects - load this one command name + * msg->count msg->bytes is modified in place, in + * modules address space. Might not want to do that... + */ +void +mod_add_cmd(struct Message *msg) +{ + assert(msg && msg->cmd); + + /* command already added? */ + if (msg_tree_parse(msg->cmd)) + return; + + add_msg_element(&msg_tree, msg, msg->cmd); + msg->count = msg->rcount = msg->bytes = 0; +} + +/* mod_del_cmd() + * + * inputs - pointer to struct Message + * output - none + * side effects - unload this one command name + */ +void +mod_del_cmd(struct Message *msg) +{ + assert(msg && msg->cmd); + + del_msg_element(&msg_tree, msg->cmd); +} + +/* find_command() + * + * inputs - command name + * output - pointer to struct Message + * side effects - none + */ +struct Message * +find_command(const char *cmd) +{ + return msg_tree_parse(cmd); +} + +static void +recurse_report_messages(struct Client *source_p, const struct MessageTree *mtree) +{ + unsigned int i; + + if (mtree->msg != NULL) + sendto_one(source_p, form_str(RPL_STATSCOMMANDS), + me.name, source_p->name, mtree->msg->cmd, + mtree->msg->count, mtree->msg->bytes, + mtree->msg->rcount); + + for (i = 0; i < MAXPTRLEN; ++i) + if (mtree->pointers[i] != NULL) + recurse_report_messages(source_p, mtree->pointers[i]); +} + +/* report_messages() + * + * inputs - pointer to client to report to + * output - NONE + * side effects - client is shown list of commands + */ +void +report_messages(struct Client *source_p) +{ + const struct MessageTree *mtree = &msg_tree; + unsigned int i; + + for (i = 0; i < MAXPTRLEN; ++i) + if (mtree->pointers[i] != NULL) + recurse_report_messages(source_p, mtree->pointers[i]); +} + +/* cancel_clients() + * + * inputs - + * output - + * side effects - + */ +static int +cancel_clients(struct Client *client_p, struct Client *source_p, char *cmd) +{ + /* kill all possible points that are causing confusion here, + * I'm not sure I've got this all right... + * - avalon + * + * knowing avalon, probably not. + */ + + /* with TS, fake prefixes are a common thing, during the + * connect burst when there's a nick collision, and they + * must be ignored rather than killed because one of the + * two is surviving.. so we don't bother sending them to + * all ops everytime, as this could send 'private' stuff + * from lagged clients. we do send the ones that cause + * servers to be dropped though, as well as the ones from + * non-TS servers -orabidoo + */ + /* Incorrect prefix for a server from some connection. If it is a + * client trying to be annoying, just QUIT them, if it is a server + * then the same deal. + */ + if (IsServer(source_p) || IsMe(source_p)) + { + sendto_realops_flags(UMODE_DEBUG, L_ADMIN, "Message for %s[%s] from %s", + source_p->name, source_p->from->name, + get_client_name(client_p, SHOW_IP)); + sendto_realops_flags(UMODE_DEBUG, L_OPER, "Message for %s[%s] from %s", + source_p->name, source_p->from->name, + get_client_name(client_p, MASK_IP)); + sendto_realops_flags(UMODE_DEBUG, L_ALL, + "Not dropping server %s (%s) for Fake Direction", + client_p->name, source_p->name); + return -1; + /* return exit_client(client_p, client_p, &me, "Fake Direction");*/ + } + + /* Ok, someone is trying to impose as a client and things are + * confused. If we got the wrong prefix from a server, send out a + * kill, else just exit the lame client. + */ + /* If the fake prefix is coming from a TS server, discard it + * silently -orabidoo + * + * all servers must be TS these days --is + */ + sendto_realops_flags(UMODE_DEBUG, L_ADMIN, + "Message for %s[%s@%s!%s] from %s (TS, ignored)", + source_p->name, source_p->username, source_p->host, + source_p->from->name, get_client_name(client_p, SHOW_IP)); + sendto_realops_flags(UMODE_DEBUG, L_OPER, + "Message for %s[%s@%s!%s] from %s (TS, ignored)", + source_p->name, source_p->username, source_p->host, + source_p->from->name, get_client_name(client_p, MASK_IP)); + + return 0; +} + +/* remove_unknown() + * + * inputs - + * output - + * side effects - + */ +static void +remove_unknown(struct Client *client_p, char *lsender, char *lbuffer) +{ + /* Do kill if it came from a server because it means there is a ghost + * user on the other server which needs to be removed. -avalon + * Tell opers about this. -Taner + */ + /* '[0-9]something' is an ID (KILL/SQUIT depending on its length) + * 'nodots' is a nickname (KILL) + * 'no.dot.at.start' is a server (SQUIT) + */ + if ((IsDigit(*lsender) && strlen(lsender) <= IRC_MAXSID) || + strchr(lsender, '.') != NULL) + { + sendto_realops_flags(UMODE_DEBUG, L_ADMIN, + "Unknown prefix (%s) from %s, Squitting %s", + lbuffer, get_client_name(client_p, SHOW_IP), lsender); + sendto_realops_flags(UMODE_DEBUG, L_OPER, + "Unknown prefix (%s) from %s, Squitting %s", + lbuffer, client_p->name, lsender); + sendto_one(client_p, ":%s SQUIT %s :(Unknown prefix (%s) from %s)", + me.name, lsender, lbuffer, client_p->name); + } + else + sendto_one(client_p, ":%s KILL %s :%s (Unknown Client)", + me.name, lsender, me.name); +} + +/* + * + * parc number of arguments ('sender' counted as one!) + * parv[0] pointer to 'sender' (may point to empty string) (not used) + * parv[1]..parv[parc-1] + * pointers to additional parameters, this is a NULL + * terminated list (parv[parc] == NULL). + * + * *WARNING* + * Numerics are mostly error reports. If there is something + * wrong with the message, just *DROP* it! Don't even think of + * sending back a neat error message -- big danger of creating + * a ping pong error message... + */ +static void +handle_numeric(char numeric[], struct Client *client_p, struct Client *source_p, + int parc, char *parv[]) +{ + struct Client *target_p; + struct Channel *chptr; + char *t; /* current position within the buffer */ + int i, tl; /* current length of presently being built string in t */ + + if (parc < 2 || !IsServer(source_p)) + return; + + /* Remap low number numerics. */ + if (numeric[0] == '0') + numeric[0] = '1'; + + /* Prepare the parameter portion of the message into 'buffer'. + * (Because the buffer is twice as large as the message buffer + * for the socket, no overflow can occur here... ...on current + * assumptions--bets are off, if these are changed --msa) + */ + t = buffer; + for (i = 2; i < (parc - 1); i++) + { + tl = ircsprintf(t, " %s", parv[i]); + t += tl; + } + + ircsprintf(t, " :%s", parv[parc-1]); + + if (((target_p = find_person(client_p, parv[1])) != NULL) || + ((target_p = hash_find_server(parv[1])) != NULL)) + { + if (IsMe(target_p)) + { + int num; + + /* + * We shouldn't get numerics sent to us, + * any numerics we do get indicate a bug somewhere.. + */ + /* ugh. this is here because of nick collisions. when two servers + * relink, they burst each other their nicks, then perform collides. + * if there is a nick collision, BOTH servers will kill their own + * nicks, and BOTH will kill the other servers nick, which wont exist, + * because it will have been already killed by the local server. + * + * unfortunately, as we cant guarantee other servers will do the + * "right thing" on a nick collision, we have to keep both kills. + * ergo we need to ignore ERR_NOSUCHNICK. --fl_ + */ + /* quick comment. This _was_ tried. i.e. assume the other servers + * will do the "right thing" and kill a nick that is colliding. + * unfortunately, it did not work. --Dianora + */ + + /* Yes, a good compiler would have optimised this, but + * this is probably easier to read. -db + */ + num = atoi(numeric); + + if ((num != ERR_NOSUCHNICK)) + sendto_realops_flags(UMODE_ALL, L_ADMIN, + "*** %s(via %s) sent a %s numeric to me: %s", + source_p->name, client_p->name, numeric, buffer); + return; + } + else if (target_p->from == client_p) + { + /* This message changed direction (nick collision?) + * ignore it. + */ + return; + } + + /* csircd will send out unknown umode flag for +a (admin), drop it here. */ + if ((atoi(numeric) == ERR_UMODEUNKNOWNFLAG) && MyClient(target_p)) + return; + + /* Fake it for server hiding, if its our client */ + if (ConfigServerHide.hide_servers && + MyClient(target_p) && !HasUMode(target_p, UMODE_OPER)) + sendto_one(target_p, ":%s %s %s%s", me.name, numeric, target_p->name, buffer); + else + sendto_one(target_p, ":%s %s %s%s", ID_or_name(source_p, target_p->from), + numeric, ID_or_name(target_p, target_p->from), buffer); + return; + } + else if ((chptr = hash_find_channel(parv[1])) != NULL) + sendto_channel_local(ALL_MEMBERS, 0, chptr, ":%s %s %s %s", + source_p->name, + numeric, chptr->chname, buffer); +} + +/* m_not_oper() + * inputs - + * output - + * side effects - just returns a nastyogram to given user + */ +void +m_not_oper(struct Client *client_p, struct Client *source_p, + int parc, char *parv[]) +{ + sendto_one(source_p, form_str(ERR_NOPRIVILEGES), + me.name, source_p->name); +} + +void +m_unregistered(struct Client *client_p, struct Client *source_p, + int parc, char *parv[]) +{ + sendto_one(source_p, form_str(ERR_NOTREGISTERED), me.name, + source_p->name[0] ? source_p->name : "*"); +} + +void +m_registered(struct Client *client_p, struct Client *source_p, + int parc, char *parv[]) +{ + sendto_one(source_p, form_str(ERR_ALREADYREGISTRED), + me.name, source_p->name); +} + +void +m_ignore(struct Client *client_p, struct Client *source_p, + int parc, char *parv[]) +{ + return; +} + +void +rfc1459_command_send_error(struct Client *client_p, struct Client *source_p, + int parc, char *parv[]) +{ + const char *in_para; + + in_para = (parc > 1 && *parv[1] != '\0') ? parv[1] : "<>"; + + ilog(LOG_TYPE_IRCD, "Received ERROR message from %s: %s", + source_p->name, in_para); + + if (client_p == source_p) + { + sendto_realops_flags(UMODE_ALL, L_ADMIN, "ERROR :from %s -- %s", + get_client_name(client_p, HIDE_IP), in_para); + sendto_realops_flags(UMODE_ALL, L_OPER, "ERROR :from %s -- %s", + get_client_name(client_p, MASK_IP), in_para); + } + else + { + sendto_realops_flags(UMODE_ALL, L_OPER, "ERROR :from %s via %s -- %s", + source_p->name, get_client_name(client_p, MASK_IP), in_para); + sendto_realops_flags(UMODE_ALL, L_ADMIN, "ERROR :from %s via %s -- %s", + source_p->name, get_client_name(client_p, HIDE_IP), in_para); + } + + if (MyClient(source_p)) + exit_client(source_p, source_p, "ERROR"); +} diff --git a/src/restart.c b/src/restart.c new file mode 100644 index 0000000..01966a6 --- /dev/null +++ b/src/restart.c @@ -0,0 +1,94 @@ +/* + * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd). + * restart.c: Functions to allow the ircd to restart. + * + * Copyright (C) 2002 by the past and present ircd coders, and others. + * + * 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 + * + * $Id$ + */ + +#include "stdinc.h" +#include "list.h" +#include "restart.h" +#include "fdlist.h" +#include "ircd.h" +#include "irc_string.h" +#include "send.h" +#include "log.h" +#include "client.h" /* for UMODE_ALL */ +#include "memory.h" + +void +restart(const char *mesg) +{ + static int was_here = 0; /* redundant due to restarting flag below */ + + if (was_here++) + abort(); + + server_die(mesg, 1); +} + +void +server_die(const char *mesg, int rboot) +{ + char buffer[IRCD_BUFSIZE]; + dlink_node *ptr = NULL; + struct Client *target_p = NULL; + static int was_here = 0; + + if (rboot && was_here++) + abort(); + + if (EmptyString(mesg)) + snprintf(buffer, sizeof(buffer), "Server %s", + rboot ? "Restarting" : "Terminating"); + else + snprintf(buffer, sizeof(buffer), "Server %s: %s", + rboot ? "Restarting" : "Terminating", mesg); + + DLINK_FOREACH(ptr, local_client_list.head) + { + target_p = ptr->data; + + sendto_one(target_p, ":%s NOTICE %s :%s", + me.name, target_p->name, buffer); + } + + DLINK_FOREACH(ptr, serv_list.head) + { + target_p = ptr->data; + + sendto_one(target_p, ":%s ERROR :%s", me.name, buffer); + } + + ilog(LOG_TYPE_IRCD, "%s", buffer); + + send_queued_all(); + close_fds(NULL); + + unlink(pidFileName); + + if (rboot) + { + execv(SPATH, myargv); + exit(1); + } + else + exit(0); +} diff --git a/src/resv.c b/src/resv.c new file mode 100644 index 0000000..6f4ec14 --- /dev/null +++ b/src/resv.c @@ -0,0 +1,230 @@ +/* + * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd). + * resv.c: Functions to reserve(jupe) a nick/channel. + * + * Copyright (C) 2001-2002 Hybrid Development Team + * + * 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 + * + * $Id$ + */ + +#include "stdinc.h" +#include "list.h" +#include "ircd.h" +#include "send.h" +#include "client.h" +#include "memory.h" +#include "numeric.h" +#include "resv.h" +#include "hash.h" +#include "irc_string.h" +#include "ircd_defs.h" +#include "conf.h" + +dlink_list resv_channel_list = { NULL, NULL, 0 }; + + +/* create_channel_resv() + * + * inputs - name of channel to create resv for + * - reason for resv + * - flag, 1 for from ircd.conf 0 from elsehwere + * output - pointer to struct ResvChannel + * side effects - + */ +struct ConfItem * +create_channel_resv(char *name, char *reason, int in_conf) +{ + struct ConfItem *conf = NULL; + struct ResvChannel *resv_p = NULL; + + if (name == NULL || reason == NULL) + return NULL; + + if (hash_find_resv(name)) + return NULL; + + if (strlen(reason) > REASONLEN) + reason[REASONLEN] = '\0'; + + conf = make_conf_item(CRESV_TYPE); + resv_p = map_to_conf(conf); + + strlcpy(resv_p->name, name, sizeof(resv_p->name)); + DupString(conf->name, name); + DupString(resv_p->reason, reason); + resv_p->conf = in_conf; + + dlinkAdd(resv_p, &resv_p->node, &resv_channel_list); + hash_add_resv(resv_p); + + return conf; +} + +/* create_nick_resv() + * + * inputs - name of nick to create resv for + * - reason for resv + * - 1 if from ircd.conf, 0 if from elsewhere + * output - pointer to struct ResvNick + * side effects - + */ +struct ConfItem * +create_nick_resv(char *name, char *reason, int in_conf) +{ + struct ConfItem *conf = NULL; + struct MatchItem *resv_p = NULL; + + if (name == NULL || reason == NULL) + return NULL; + + if (find_matching_name_conf(NRESV_TYPE, name, NULL, NULL, 0)) + return NULL; + + if (strlen(reason) > REASONLEN) + reason[REASONLEN] = '\0'; + + conf = make_conf_item(NRESV_TYPE); + resv_p = map_to_conf(conf); + + DupString(conf->name, name); + DupString(resv_p->reason, reason); + resv_p->action = in_conf; + + return conf; +} + +/* clear_conf_resv() + * + * inputs - none + * output - none + * side effects - All resvs are cleared out + */ +void +clear_conf_resv(void) +{ + dlink_node *ptr = NULL, *next_ptr = NULL; + + DLINK_FOREACH_SAFE(ptr, next_ptr, resv_channel_list.head) + delete_channel_resv(ptr->data); +} + +/* delete_channel_resv() + * + * inputs - pointer to channel resv to delete + * output - none + * side effects - given struct ResvChannel * is removed + */ +int +delete_channel_resv(struct ResvChannel *resv_p) +{ + struct ConfItem *conf = NULL; + assert(resv_p != NULL); + + hash_del_resv(resv_p); + dlinkDelete(&resv_p->node, &resv_channel_list); + MyFree(resv_p->reason); + conf = unmap_conf_item(resv_p); + delete_conf_item(conf); + + return 1; +} + +/* match_find_resv() + * + * inputs - pointer to name + * output - pointer to a struct ResvChannel + * side effects - Finds a reserved channel whose name matches 'name', + * if can't find one returns NULL. + */ +struct ResvChannel * +match_find_resv(const char *name) +{ + dlink_node *ptr = NULL; + + if (EmptyString(name)) + return NULL; + + DLINK_FOREACH(ptr, resv_channel_list.head) + { + struct ResvChannel *chptr = ptr->data; + + if (match_chan(name, chptr->name)) + return chptr; + } + + return NULL; +} + +/* report_resv() + * + * inputs - pointer to client pointer to report to. + * output - NONE + * side effects - report all resvs to client. + */ +void +report_resv(struct Client *source_p) +{ + dlink_node *ptr; + struct ConfItem *conf; + struct ResvChannel *resv_cp; + struct MatchItem *resv_np; + + DLINK_FOREACH(ptr, resv_channel_list.head) + { + resv_cp = ptr->data; + sendto_one(source_p, form_str(RPL_STATSQLINE), + me.name, source_p->name, + resv_cp->conf ? 'Q' : 'q', + resv_cp->name, resv_cp->reason); + } + + DLINK_FOREACH(ptr, nresv_items.head) + { + conf = ptr->data; + resv_np = map_to_conf(conf); + + sendto_one(source_p, form_str(RPL_STATSQLINE), + me.name, source_p->name, + resv_np->action ? 'Q' : 'q', + conf->name, resv_np->reason); + } +} + +/* valid_wild_card_simple() + * + * inputs - data to check for sufficient non-wildcard characters + * outputs - 1 if valid, else 0 + * side effects - none + */ +int +valid_wild_card_simple(const char *data) +{ + const unsigned char *p = (const unsigned char *)data; + int nonwild = 0; + + while (*p != '\0') + { + if ((*p == '\\' && *++p) || (*p && !IsMWildChar(*p))) + if (++nonwild == ConfigFileEntry.min_nonwildcard_simple) + return 1; + if (*p != '\0') + ++p; + } + + return 0; +} diff --git a/src/rng_mt.c b/src/rng_mt.c new file mode 100644 index 0000000..dacc11f --- /dev/null +++ b/src/rng_mt.c @@ -0,0 +1,167 @@ +/* + A C-program for MT19937, with initialization improved 2002/1/26. + Coded by Takuji Nishimura and Makoto Matsumoto. + + Before using, initialize the state by using init_genrand(seed) + or init_by_array(init_key, key_length). + + Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura, + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + 3. The names of its contributors may not be used to endorse or promote + products derived from this software without specific prior written + permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + + Any feedback is very welcome. + http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html + email: m-mat @ math.sci.hiroshima-u.ac.jp (remove space) + + $Id$ +*/ + +#include "stdinc.h" +#include "rng_mt.h" + +/* Period parameters */ +#define N 624 +#define M 397 +#define MATRIX_A 0x9908b0dfU /* constant vector a */ +#define UPPER_MASK 0x80000000U /* most significant w-r bits */ +#define LOWER_MASK 0x7fffffffU /* least significant r bits */ + +static uint32_t mt[N]; /* the array for the state vector */ +static int mti = N + 1; /* mti==N+1 means mt[N] is not initialized */ + +/* initializes mt[N] with a seed */ +void +init_genrand(uint32_t s) +{ + mt[0] = s & 0xffffffffU; + + for (mti = 1; mti < N; mti++) + { + mt[mti] = (1812433253U * (mt[mti - 1] ^ (mt[mti - 1] >> 30)) + mti); + /* See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier. */ + /* In the previous versions, MSBs of the seed affect */ + /* only MSBs of the array mt[]. */ + /* 2002/01/09 modified by Makoto Matsumoto */ + mt[mti] &= 0xffffffffU; + /* for >32 bit machines */ + } +} + +/* initialize by an array with array-length */ +/* init_key is the array for initializing keys */ +/* key_length is its length */ +/* slight change for C++, 2004/2/26 */ +void +init_by_array(uint32_t init_key[], int key_length) +{ + int i, j, k; + + init_genrand(19650218U); + + i = 1; j = 0; + k = (N > key_length ? N : key_length); + + for (; k; k--) + { + mt[i] = (mt[i] ^ ((mt[i - 1] ^ (mt[i - 1] >> 30)) * 1664525U)) + + init_key[j] + j; /* non linear */ + mt[i] &= 0xffffffffU; /* for WORDSIZE > 32 machines */ + i++; j++; + + if (i >= N) + { + mt[0] = mt[N - 1]; + i = 1; + } + + if (j >= key_length) + j = 0; + } + + for (k = N - 1; k; k--) + { + mt[i] = (mt[i] ^ ((mt[i - 1] ^ (mt[i - 1] >> 30)) * 1566083941U)) + - i; /* non linear */ + mt[i] &= 0xffffffffU; /* for WORDSIZE > 32 machines */ + i++; + + if (i >= N) + { + mt[0] = mt[N - 1]; + i = 1; + } + } + + mt[0] = 0x80000000U; /* MSB is 1; assuring non-zero initial array */ +} + +/* generates a random number on [0,0xffffffff]-interval */ +uint32_t +genrand_int32(void) +{ + uint32_t y; + static uint32_t mag01[2]={ 0x0U, MATRIX_A }; + /* mag01[x] = x * MATRIX_A for x=0,1 */ + + if (mti >= N) + { /* generate N words at one time */ + int kk; + + if (mti == N + 1) /* if init_genrand() has not been called, */ + init_genrand(5489U); /* a default initial seed is used */ + + for (kk = 0; kk < N - M; kk++) + { + y = (mt[kk] & UPPER_MASK) | (mt[kk + 1] & LOWER_MASK); + mt[kk] = mt[kk + M] ^ (y >> 1) ^ mag01[y & 0x1U]; + } + + for (; kk < N - 1; kk++) + { + y = (mt[kk] & UPPER_MASK) | (mt[kk + 1] & LOWER_MASK); + mt[kk] = mt[kk + (M - N)] ^ (y >> 1) ^ mag01[y & 0x1U]; + } + + y = (mt[N - 1] & UPPER_MASK) | (mt[0] & LOWER_MASK); + mt[N - 1] = mt[M - 1] ^ (y >> 1) ^ mag01[y & 0x1U]; + + mti = 0; + } + + y = mt[mti++]; + + /* Tempering */ + y ^= (y >> 11); + y ^= (y << 7) & 0x9d2c5680U; + y ^= (y << 15) & 0xefc60000U; + y ^= (y >> 18); + + return y; +} diff --git a/src/rsa.c b/src/rsa.c new file mode 100644 index 0000000..8623ae0 --- /dev/null +++ b/src/rsa.c @@ -0,0 +1,120 @@ +/* + * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd). + * rsa.c: Functions for use with RSA public key cryptography. + * + * Copyright (C) 2002 by the past and present ircd coders, and others. + * + * 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 + * + * $Id$ + */ + +#include "stdinc.h" +#ifdef HAVE_LIBCRYPTO +#include <openssl/pem.h> +#include <openssl/rand.h> +#include <openssl/rsa.h> +#include <openssl/bn.h> +#include <openssl/evp.h> +#include <openssl/err.h> +#include <openssl/opensslv.h> + +#include "memory.h" +#include "rsa.h" +#include "conf.h" +#include "log.h" + + +/* + * report_crypto_errors - Dump crypto error list to log + */ +void +report_crypto_errors(void) +{ + unsigned long e = 0; + unsigned long cnt = 0; + + while ((cnt < 100) && (e = ERR_get_error())) + { + ilog(LOG_TYPE_IRCD, "SSL error: %s", ERR_error_string(e, 0)); + cnt++; + } +} + +static void +binary_to_hex(unsigned char *bin, char *hex, int length) +{ + static const char trans[] = "0123456789ABCDEF"; + int i; + + for (i = 0; i < length; i++) + { + hex[i << 1] = trans[bin[i] >> 4]; + hex[(i << 1) + 1] = trans[bin[i] & 0xf]; + } + + hex[i << 1] = '\0'; +} + +int +get_randomness(unsigned char *buf, int length) +{ + /* Seed OpenSSL PRNG with EGD enthropy pool -kre */ + if (ConfigFileEntry.use_egd && + (ConfigFileEntry.egdpool_path != NULL)) + { + if (RAND_egd(ConfigFileEntry.egdpool_path) == -1) + return -1; + } + + if (RAND_status()) + return (RAND_bytes(buf, length)); + else /* XXX - abort? */ + return (RAND_pseudo_bytes(buf, length)); +} + +int +generate_challenge(char **r_challenge, char **r_response, RSA *rsa) +{ + unsigned char secret[32], *tmp; + unsigned long length; + int ret = -1; + + if (!rsa) + return -1; + + get_randomness(secret, 32); + *r_response = MyMalloc(65); + binary_to_hex(secret, *r_response, 32); + + length = RSA_size(rsa); + tmp = MyMalloc(length); + ret = RSA_public_encrypt(32, secret, tmp, rsa, RSA_PKCS1_PADDING); + + *r_challenge = MyMalloc((length << 1) + 1); + binary_to_hex( tmp, *r_challenge, length); + (*r_challenge)[length<<1] = 0; + MyFree(tmp); + + if (ret < 0) + { + report_crypto_errors(); + return -1; + } + + return 0; +} +#endif diff --git a/src/s_auth.c b/src/s_auth.c new file mode 100644 index 0000000..c14cb22 --- /dev/null +++ b/src/s_auth.c @@ -0,0 +1,598 @@ +/* + * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd). + * s_auth.c: Functions for querying a users ident. + * + * Copyright (C) 2002 by the past and present ircd coders, and others. + * + * 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 + * + * $Id$ + */ + +/* + * Changes: + * July 6, 1999 - Rewrote most of the code here. When a client connects + * to the server and passes initial socket validation checks, it + * is owned by this module (auth) which returns it to the rest of the + * server when dns and auth queries are finished. Until the client is + * released, the server does not know it exists and does not process + * any messages from it. + * --Bleep Thomas Helvey <tomh@inxpress.net> + */ + +#include "stdinc.h" +#include "list.h" +#include "ircd_defs.h" +#include "fdlist.h" +#include "s_auth.h" +#include "conf.h" +#include "balloc.h" +#include "client.h" +#include "event.h" +#include "hook.h" +#include "irc_string.h" +#include "ircd.h" +#include "packet.h" +#include "irc_res.h" +#include "s_bsd.h" +#include "log.h" +#include "send.h" + + +static const char *HeaderMessages[] = { + ":%s NOTICE AUTH :*** Looking up your hostname...", + ":%s NOTICE AUTH :*** Found your hostname", + ":%s NOTICE AUTH :*** Couldn't look up your hostname", + ":%s NOTICE AUTH :*** Checking Ident", + ":%s NOTICE AUTH :*** Got Ident response", + ":%s NOTICE AUTH :*** No Ident response", + ":%s NOTICE AUTH :*** Your forward and reverse DNS do not match, ignoring hostname.", + ":%s NOTICE AUTH :*** Your hostname is too long, ignoring hostname" +}; + +enum { + REPORT_DO_DNS, + REPORT_FIN_DNS, + REPORT_FAIL_DNS, + REPORT_DO_ID, + REPORT_FIN_ID, + REPORT_FAIL_ID, + REPORT_IP_MISMATCH, + REPORT_HOST_TOOLONG +}; + +#define sendheader(c, i) sendto_one((c), HeaderMessages[(i)], me.name) + +static BlockHeap *auth_heap = NULL; +static dlink_list auth_doing_list = { NULL, NULL, 0 }; + +static EVH timeout_auth_queries_event; + +static PF read_auth_reply; +static CNCB auth_connect_callback; +static CBFUNC start_auth; + +struct Callback *auth_cb = NULL; + +/* init_auth() + * + * Initialise the auth code + */ +void +init_auth(void) +{ + auth_heap = BlockHeapCreate("auth", sizeof(struct AuthRequest), AUTH_HEAP_SIZE); + auth_cb = register_callback("start_auth", start_auth); + eventAddIsh("timeout_auth_queries_event", timeout_auth_queries_event, NULL, 1); +} + +/* + * make_auth_request - allocate a new auth request + */ +static struct AuthRequest * +make_auth_request(struct Client *client) +{ + struct AuthRequest *request = BlockHeapAlloc(auth_heap); + + client->localClient->auth = request; + request->client = client; + request->timeout = CurrentTime + CONNECTTIMEOUT; + + return request; +} + +/* + * release_auth_client - release auth client from auth system + * this adds the client into the local client lists so it can be read by + * the main io processing loop + */ +void +release_auth_client(struct AuthRequest *auth) +{ + struct Client *client = auth->client; + + if (IsDoingAuth(auth) || IsDNSPending(auth)) + return; + + client->localClient->auth = NULL; + dlinkDelete(&auth->node, &auth_doing_list); + BlockHeapFree(auth_heap, auth); + + /* + * When a client has auth'ed, we want to start reading what it sends + * us. This is what read_packet() does. + * -- adrian + */ + client->localClient->allow_read = MAX_FLOOD; + comm_setflush(&client->localClient->fd, 1000, flood_recalc, client); + + dlinkAdd(client, &client->node, &global_client_list); + + client->localClient->since = CurrentTime; + client->localClient->lasttime = CurrentTime; + client->localClient->firsttime = CurrentTime; + client->flags |= FLAGS_FINISHED_AUTH; + + read_packet(&client->localClient->fd, client); +} + +/* + * auth_dns_callback - called when resolver query finishes + * if the query resulted in a successful search, name will contain + * a non-NULL pointer, otherwise name will be NULL. + * set the client on it's way to a connection completion, regardless + * of success of failure + */ +static void +auth_dns_callback(void *vptr, const struct irc_ssaddr *addr, const char *name) +{ + struct AuthRequest *auth = vptr; + + ClearDNSPending(auth); + + if (name != NULL) + { + const struct sockaddr_in *v4, *v4dns; +#ifdef IPV6 + const struct sockaddr_in6 *v6, *v6dns; +#endif + int good = 1; + +#ifdef IPV6 + if (auth->client->localClient->ip.ss.ss_family == AF_INET6) + { + v6 = (const struct sockaddr_in6 *)&auth->client->localClient->ip; + v6dns = (const struct sockaddr_in6 *)addr; + if (memcmp(&v6->sin6_addr, &v6dns->sin6_addr, sizeof(struct in6_addr)) != 0) + { + sendheader(auth->client, REPORT_IP_MISMATCH); + good = 0; + } + } + else +#endif + { + v4 = (const struct sockaddr_in *)&auth->client->localClient->ip; + v4dns = (const struct sockaddr_in *)addr; + if(v4->sin_addr.s_addr != v4dns->sin_addr.s_addr) + { + sendheader(auth->client, REPORT_IP_MISMATCH); + good = 0; + } + } + if (good && strlen(name) <= HOSTLEN) + { + strlcpy(auth->client->host, name, + sizeof(auth->client->host)); + sendheader(auth->client, REPORT_FIN_DNS); + } + else if (strlen(name) > HOSTLEN) + sendheader(auth->client, REPORT_HOST_TOOLONG); + } + else + sendheader(auth->client, REPORT_FAIL_DNS); + + release_auth_client(auth); +} + +/* + * authsenderr - handle auth send errors + */ +static void +auth_error(struct AuthRequest *auth) +{ + ++ServerStats.is_abad; + + fd_close(&auth->fd); + + ClearAuth(auth); + + sendheader(auth->client, REPORT_FAIL_ID); + + release_auth_client(auth); +} + +/* + * start_auth_query - Flag the client to show that an attempt to + * contact the ident server on + * the client's host. The connect and subsequently the socket are all put + * into 'non-blocking' mode. Should the connect or any later phase of the + * identifing process fail, it is aborted and the user is given a username + * of "unknown". + */ +static int +start_auth_query(struct AuthRequest *auth) +{ + struct irc_ssaddr localaddr; + socklen_t locallen = sizeof(struct irc_ssaddr); +#ifdef IPV6 + struct sockaddr_in6 *v6; +#else + struct sockaddr_in *v4; +#endif + + /* open a socket of the same type as the client socket */ + if (comm_open(&auth->fd, auth->client->localClient->ip.ss.ss_family, + SOCK_STREAM, 0, "ident") == -1) + { + report_error(L_ALL, "creating auth stream socket %s:%s", + get_client_name(auth->client, SHOW_IP), errno); + ilog(LOG_TYPE_IRCD, "Unable to create auth socket for %s", + get_client_name(auth->client, SHOW_IP)); + ++ServerStats.is_abad; + return 0; + } + + sendheader(auth->client, REPORT_DO_ID); + + /* + * get the local address of the client and bind to that to + * make the auth request. This used to be done only for + * ifdef VIRTUAL_HOST, but needs to be done for all clients + * since the ident request must originate from that same address-- + * and machines with multiple IP addresses are common now + */ + memset(&localaddr, 0, locallen); + getsockname(auth->client->localClient->fd.fd, (struct sockaddr*)&localaddr, + &locallen); + +#ifdef IPV6 + remove_ipv6_mapping(&localaddr); + v6 = (struct sockaddr_in6 *)&localaddr; + v6->sin6_port = htons(0); +#else + localaddr.ss_len = locallen; + v4 = (struct sockaddr_in *)&localaddr; + v4->sin_port = htons(0); +#endif + localaddr.ss_port = htons(0); + + comm_connect_tcp(&auth->fd, auth->client->sockhost, 113, + (struct sockaddr *)&localaddr, localaddr.ss_len, auth_connect_callback, + auth, auth->client->localClient->ip.ss.ss_family, + GlobalSetOptions.ident_timeout); + return 1; /* We suceed here for now */ +} + +/* + * GetValidIdent - parse ident query reply from identd server + * + * Inputs - pointer to ident buf + * Output - NULL if no valid ident found, otherwise pointer to name + * Side effects - + */ +/* + * A few questions have been asked about this mess, obviously + * it should have been commented better the first time. + * The original idea was to remove all references to libc from ircd-hybrid. + * Instead of having to write a replacement for sscanf(), I did a + * rather gruseome parser here so we could remove this function call. + * Note, that I had also removed a few floating point printfs as well (though + * now we are still stuck with a few...) + * Remember, we have a replacement ircd sprintf, we have bleeps fputs lib + * it would have been nice to remove some unneeded code. + * Oh well. If we don't remove libc stuff totally, then it would be + * far cleaner to use sscanf() + * + * - Dianora + */ +static char * +GetValidIdent(char *buf) +{ + int remp = 0; + int locp = 0; + char* colon1Ptr; + char* colon2Ptr; + char* colon3Ptr; + char* commaPtr; + char* remotePortString; + + /* All this to get rid of a sscanf() fun. */ + remotePortString = buf; + + if ((colon1Ptr = strchr(remotePortString,':')) == NULL) + return 0; + *colon1Ptr = '\0'; + colon1Ptr++; + + if ((colon2Ptr = strchr(colon1Ptr,':')) == NULL) + return 0; + *colon2Ptr = '\0'; + colon2Ptr++; + + if ((commaPtr = strchr(remotePortString, ',')) == NULL) + return 0; + *commaPtr = '\0'; + commaPtr++; + + if ((remp = atoi(remotePortString)) == 0) + return 0; + + if ((locp = atoi(commaPtr)) == 0) + return 0; + + /* look for USERID bordered by first pair of colons */ + if (strstr(colon1Ptr, "USERID") == NULL) + return 0; + + if ((colon3Ptr = strchr(colon2Ptr,':')) == NULL) + return 0; + *colon3Ptr = '\0'; + colon3Ptr++; + return (colon3Ptr); +} + +/* + * start_auth + * + * inputs - pointer to client to auth + * output - NONE + * side effects - starts auth (identd) and dns queries for a client + */ +static void * +start_auth(va_list args) +{ + struct Client *client = va_arg(args, struct Client *); + struct AuthRequest *auth = NULL; + + assert(client != NULL); + + auth = make_auth_request(client); + dlinkAdd(auth, &auth->node, &auth_doing_list); + + sendheader(client, REPORT_DO_DNS); + + SetDNSPending(auth); + + if (ConfigFileEntry.disable_auth == 0) + { + SetDoingAuth(auth); + start_auth_query(auth); + } + + gethost_byaddr(auth_dns_callback, auth, &client->localClient->ip); + + return NULL; +} + +/* + * timeout_auth_queries - timeout resolver and identd requests + * allow clients through if requests failed + */ +static void +timeout_auth_queries_event(void *notused) +{ + dlink_node *ptr = NULL, *next_ptr = NULL; + + DLINK_FOREACH_SAFE(ptr, next_ptr, auth_doing_list.head) + { + struct AuthRequest *auth = ptr->data; + + if (auth->timeout > CurrentTime) + continue; + + if (IsDoingAuth(auth)) + { + ++ServerStats.is_abad; + fd_close(&auth->fd); + ClearAuth(auth); + sendheader(auth->client, REPORT_FAIL_ID); + } + + if (IsDNSPending(auth)) + { + delete_resolver_queries(auth); + ClearDNSPending(auth); + sendheader(auth->client, REPORT_FAIL_DNS); + } + + ilog(LOG_TYPE_IRCD, "DNS/AUTH timeout %s", + get_client_name(auth->client, SHOW_IP)); + release_auth_client(auth); + } +} + +/* + * auth_connect_callback() - deal with the result of comm_connect_tcp() + * + * If the connection failed, we simply close the auth fd and report + * a failure. If the connection suceeded send the ident server a query + * giving "theirport , ourport". The write is only attempted *once* so + * it is deemed to be a fail if the entire write doesn't write all the + * data given. This shouldnt be a problem since the socket should have + * a write buffer far greater than this message to store it in should + * problems arise. -avalon + */ +static void +auth_connect_callback(fde_t *fd, int error, void *data) +{ + struct AuthRequest *auth = data; + struct irc_ssaddr us; + struct irc_ssaddr them; + char authbuf[32]; + socklen_t ulen = sizeof(struct irc_ssaddr); + socklen_t tlen = sizeof(struct irc_ssaddr); + uint16_t uport, tport; +#ifdef IPV6 + struct sockaddr_in6 *v6; +#else + struct sockaddr_in *v4; +#endif + + if (error != COMM_OK) + { + auth_error(auth); + return; + } + + if (getsockname(auth->client->localClient->fd.fd, (struct sockaddr *)&us, + &ulen) || + getpeername(auth->client->localClient->fd.fd, (struct sockaddr *)&them, + &tlen)) + { + ilog(LOG_TYPE_IRCD, "auth get{sock,peer}name error for %s", + get_client_name(auth->client, SHOW_IP)); + auth_error(auth); + return; + } + +#ifdef IPV6 + v6 = (struct sockaddr_in6 *)&us; + uport = ntohs(v6->sin6_port); + v6 = (struct sockaddr_in6 *)&them; + tport = ntohs(v6->sin6_port); + remove_ipv6_mapping(&us); + remove_ipv6_mapping(&them); +#else + v4 = (struct sockaddr_in *)&us; + uport = ntohs(v4->sin_port); + v4 = (struct sockaddr_in *)&them; + tport = ntohs(v4->sin_port); + us.ss_len = ulen; + them.ss_len = tlen; +#endif + + snprintf(authbuf, sizeof(authbuf), "%u , %u\r\n", tport, uport); + + if (send(fd->fd, authbuf, strlen(authbuf), 0) == -1) + { + auth_error(auth); + return; + } + + read_auth_reply(&auth->fd, auth); +} + +/* + * read_auth_reply - read the reply (if any) from the ident server + * we connected to. + * We only give it one shot, if the reply isn't good the first time + * fail the authentication entirely. --Bleep + */ +#define AUTH_BUFSIZ 128 + +static void +read_auth_reply(fde_t *fd, void *data) +{ + struct AuthRequest *auth = data; + char *s = NULL; + char *t = NULL; + int len; + int count; + char buf[AUTH_BUFSIZ + 1]; /* buffer to read auth reply into */ + + /* Why? + * Well, recv() on many POSIX systems is a per-packet operation, + * and we do not necessarily want this, because on lowspec machines, + * the ident response may come back fragmented, thus resulting in an + * invalid ident response, even if the ident response was really OK. + * + * So PLEASE do not change this code to recv without being aware of the + * consequences. + * + * --nenolod + */ + len = read(fd->fd, buf, AUTH_BUFSIZ); + + if (len < 0) + { + if (ignoreErrno(errno)) + comm_setselect(fd, COMM_SELECT_READ, read_auth_reply, auth, 0); + else + auth_error(auth); + return; + } + + if (len > 0) + { + buf[len] = '\0'; + + if ((s = GetValidIdent(buf))) + { + t = auth->client->username; + + while (*s == '~' || *s == '^') + s++; + + for (count = USERLEN; *s && count; s++) + { + if (*s == '@') + break; + if (!IsSpace(*s) && *s != ':' && *s != '[') + { + *t++ = *s; + count--; + } + } + + *t = '\0'; + } + } + + fd_close(fd); + + ClearAuth(auth); + + if (s == NULL) + { + sendheader(auth->client, REPORT_FAIL_ID); + ++ServerStats.is_abad; + } + else + { + sendheader(auth->client, REPORT_FIN_ID); + ++ServerStats.is_asuc; + SetGotId(auth->client); + } + + release_auth_client(auth); +} + +/* + * delete_auth() + */ +void +delete_auth(struct AuthRequest *auth) +{ + if (IsDNSPending(auth)) + delete_resolver_queries(auth); + + if (IsDoingAuth(auth)) + fd_close(&auth->fd); + + dlinkDelete(&auth->node, &auth_doing_list); + BlockHeapFree(auth_heap, auth); +} diff --git a/src/s_bsd.c b/src/s_bsd.c new file mode 100644 index 0000000..316d3f4 --- /dev/null +++ b/src/s_bsd.c @@ -0,0 +1,757 @@ +/* + * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd). + * s_bsd.c: Network functions. + * + * Copyright (C) 2002 by the past and present ircd coders, and others. + * + * 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 + * + * $Id$ + */ + +#include "stdinc.h" +#include <netinet/in_systm.h> +#include <netinet/ip.h> +#include <netinet/tcp.h> +#include "list.h" +#include "fdlist.h" +#include "s_bsd.h" +#include "client.h" +#include "dbuf.h" +#include "event.h" +#include "irc_string.h" +#include "ircd.h" +#include "listener.h" +#include "numeric.h" +#include "packet.h" +#include "irc_res.h" +#include "restart.h" +#include "s_auth.h" +#include "conf.h" +#include "log.h" +#include "s_serv.h" +#include "send.h" +#include "memory.h" +#include "s_user.h" +#include "hook.h" + +static const char *comm_err_str[] = { "Comm OK", "Error during bind()", + "Error during DNS lookup", "connect timeout", "Error during connect()", + "Comm Error" }; + +struct Callback *setup_socket_cb = NULL; + +static void comm_connect_callback(fde_t *, int); +static PF comm_connect_timeout; +static void comm_connect_dns_callback(void *, const struct irc_ssaddr *, const char *); +static PF comm_connect_tryconnect; + + +/* check_can_use_v6() + * Check if the system can open AF_INET6 sockets + */ +void +check_can_use_v6(void) +{ +#ifdef IPV6 + int v6; + + if ((v6 = socket(AF_INET6, SOCK_STREAM, 0)) < 0) + ServerInfo.can_use_v6 = 0; + else + { + ServerInfo.can_use_v6 = 1; + close(v6); + } +#else + ServerInfo.can_use_v6 = 0; +#endif +} + +/* get_sockerr - get the error value from the socket or the current errno + * + * Get the *real* error from the socket (well try to anyway..). + * This may only work when SO_DEBUG is enabled but its worth the + * gamble anyway. + */ +int +get_sockerr(int fd) +{ + int errtmp = errno; +#ifdef SO_ERROR + int err = 0; + socklen_t len = sizeof(err); + + if (-1 < fd && !getsockopt(fd, SOL_SOCKET, SO_ERROR, &err, &len)) + { + if (err) + errtmp = err; + } + errno = errtmp; +#endif + return errtmp; +} + +/* + * report_error - report an error from an errno. + * Record error to log and also send a copy to all *LOCAL* opers online. + * + * text is a *format* string for outputing error. It must + * contain only two '%s', the first will be replaced + * by the sockhost from the client_p, and the latter will + * be taken from sys_errlist[errno]. + * + * client_p if not NULL, is the *LOCAL* client associated with + * the error. + * + * Cannot use perror() within daemon. stderr is closed in + * ircd and cannot be used. And, worse yet, it might have + * been reassigned to a normal connection... + * + * Actually stderr is still there IFF ircd was run with -s --Rodder + */ + +void +report_error(int level, const char* text, const char* who, int error) +{ + who = (who) ? who : ""; + + sendto_realops_flags(UMODE_DEBUG, level, text, who, strerror(error)); + ilog(LOG_TYPE_IRCD, text, who, strerror(error)); +} + +/* + * setup_socket() + * + * Set the socket non-blocking, and other wonderful bits. + */ +static void * +setup_socket(va_list args) +{ + int fd = va_arg(args, int); + int opt = 1; + + setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt)); + +#ifdef IPTOS_LOWDELAY + opt = IPTOS_LOWDELAY; + setsockopt(fd, IPPROTO_IP, IP_TOS, &opt, sizeof(opt)); +#endif + + fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK); + + return NULL; +} + +/* + * init_comm() + * + * Initializes comm subsystem. + */ +void +init_comm(void) +{ + setup_socket_cb = register_callback("setup_socket", setup_socket); + init_netio(); +} + +/* + * close_connection + * Close the physical connection. This function must make + * MyConnect(client_p) == FALSE, and set client_p->from == NULL. + */ +void +close_connection(struct Client *client_p) +{ + struct AccessItem *aconf; + struct ClassItem *aclass; + dlink_node *ptr = NULL; + + assert(client_p); + + if (!IsDead(client_p)) + { + /* attempt to flush any pending dbufs. Evil, but .. -- adrian */ + /* there is still a chance that we might send data to this socket + * even if it is marked as blocked (COMM_SELECT_READ handler is called + * before COMM_SELECT_WRITE). Let's try, nothing to lose.. -adx + */ + ClearSendqBlocked(client_p); + send_queued_write(client_p); + } + + if (IsClient(client_p)) + { + ++ServerStats.is_cl; + ServerStats.is_cbs += client_p->localClient->send.bytes; + ServerStats.is_cbr += client_p->localClient->recv.bytes; + ServerStats.is_cti += CurrentTime - client_p->localClient->firsttime; + } + else if (IsServer(client_p)) + { + ++ServerStats.is_sv; + ServerStats.is_sbs += client_p->localClient->send.bytes; + ServerStats.is_sbr += client_p->localClient->recv.bytes; + ServerStats.is_sti += CurrentTime - client_p->localClient->firsttime; + + DLINK_FOREACH(ptr, server_items.head) + { + struct ConfItem *conf = ptr->data; + + if (irccmp(conf->name, client_p->name)) + continue; + + /* + * Reset next-connect cycle of all connect{} blocks that match + * this servername. + */ + aconf = map_to_conf(conf); + aclass = map_to_conf(aconf->class_ptr); + aconf->hold = CurrentTime + aclass->con_freq; + } + } + else + ++ServerStats.is_ni; + +#ifdef HAVE_LIBCRYPTO + if (client_p->localClient->fd.ssl) + { + SSL_set_shutdown(client_p->localClient->fd.ssl, SSL_RECEIVED_SHUTDOWN); + + if (!SSL_shutdown(client_p->localClient->fd.ssl)) + SSL_shutdown(client_p->localClient->fd.ssl); + } +#endif + if (client_p->localClient->fd.flags.open) + fd_close(&client_p->localClient->fd); + + dbuf_clear(&client_p->localClient->buf_sendq); + dbuf_clear(&client_p->localClient->buf_recvq); + + MyFree(client_p->localClient->passwd); + detach_conf(client_p, CONF_TYPE); + client_p->from = NULL; /* ...this should catch them! >:) --msa */ +} + +#ifdef HAVE_LIBCRYPTO +/* + * ssl_handshake - let OpenSSL initialize the protocol. Register for + * read/write events if necessary. + */ +static void +ssl_handshake(int fd, struct Client *client_p) +{ + int ret = SSL_accept(client_p->localClient->fd.ssl); + + if (ret <= 0) + switch (SSL_get_error(client_p->localClient->fd.ssl, ret)) + { + case SSL_ERROR_WANT_WRITE: + comm_setselect(&client_p->localClient->fd, COMM_SELECT_WRITE, + (PF *) ssl_handshake, client_p, 0); + return; + + case SSL_ERROR_WANT_READ: + comm_setselect(&client_p->localClient->fd, COMM_SELECT_READ, + (PF *) ssl_handshake, client_p, 0); + return; + + default: + exit_client(client_p, client_p, "Error during SSL handshake"); + return; + } + + execute_callback(auth_cb, client_p); +} +#endif + +/* + * add_connection - creates a client which has just connected to us on + * the given fd. The sockhost field is initialized with the ip# of the host. + * An unique id is calculated now, in case it is needed for auth. + * The client is sent to the auth module for verification, and not put in + * any client list yet. + */ +void +add_connection(struct Listener *listener, struct irc_ssaddr *irn, int fd) +{ + struct Client *new_client = make_client(NULL); + + fd_open(&new_client->localClient->fd, fd, 1, + (listener->flags & LISTENER_SSL) ? + "Incoming SSL connection" : "Incoming connection"); + + /* + * copy address to 'sockhost' as a string, copy it to host too + * so we have something valid to put into error messages... + */ + memcpy(&new_client->localClient->ip, irn, sizeof(struct irc_ssaddr)); + + getnameinfo((struct sockaddr *)&new_client->localClient->ip, + new_client->localClient->ip.ss_len, new_client->sockhost, + sizeof(new_client->sockhost), NULL, 0, NI_NUMERICHOST); + new_client->localClient->aftype = new_client->localClient->ip.ss.ss_family; + + if (new_client->sockhost[0] == ':' && new_client->sockhost[1] == ':') + { + strlcpy(new_client->host, "0", sizeof(new_client->host)); + strlcpy(new_client->host+1, new_client->sockhost, sizeof(new_client->host)-1); + memmove(new_client->sockhost+1, new_client->sockhost, sizeof(new_client->sockhost)-1); + new_client->sockhost[0] = '0'; + } + else + strlcpy(new_client->host, new_client->sockhost, sizeof(new_client->host)); + + new_client->localClient->listener = listener; + ++listener->ref_count; + +#ifdef HAVE_LIBCRYPTO + if (listener->flags & LISTENER_SSL) + { + if ((new_client->localClient->fd.ssl = SSL_new(ServerInfo.server_ctx)) == NULL) + { + ilog(LOG_TYPE_IRCD, "SSL_new() ERROR! -- %s", + ERR_error_string(ERR_get_error(), NULL)); + + SetDead(new_client); + exit_client(new_client, new_client, "SSL_new failed"); + return; + } + + SSL_set_fd(new_client->localClient->fd.ssl, fd); + ssl_handshake(0, new_client); + } + else +#endif + execute_callback(auth_cb, new_client); +} + +/* + * stolen from squid - its a neat (but overused! :) routine which we + * can use to see whether we can ignore this errno or not. It is + * generally useful for non-blocking network IO related errnos. + * -- adrian + */ +int +ignoreErrno(int ierrno) +{ + switch (ierrno) + { + case EINPROGRESS: + case EWOULDBLOCK: +#if EAGAIN != EWOULDBLOCK + case EAGAIN: +#endif + case EALREADY: + case EINTR: +#ifdef ERESTART + case ERESTART: +#endif + return 1; + default: + return 0; + } +} + +/* + * comm_settimeout() - set the socket timeout + * + * Set the timeout for the fd + */ +void +comm_settimeout(fde_t *fd, time_t timeout, PF *callback, void *cbdata) +{ + assert(fd->flags.open); + + fd->timeout = CurrentTime + (timeout / 1000); + fd->timeout_handler = callback; + fd->timeout_data = cbdata; +} + +/* + * comm_setflush() - set a flush function + * + * A flush function is simply a function called if found during + * comm_timeouts(). Its basically a second timeout, except in this case + * I'm too lazy to implement multiple timeout functions! :-) + * its kinda nice to have it separate, since this is designed for + * flush functions, and when comm_close() is implemented correctly + * with close functions, we _actually_ don't call comm_close() here .. + * -- originally Adrian's notes + * comm_close() is replaced with fd_close() in fdlist.c + */ +void +comm_setflush(fde_t *fd, time_t timeout, PF *callback, void *cbdata) +{ + assert(fd->flags.open); + + fd->flush_timeout = CurrentTime + (timeout / 1000); + fd->flush_handler = callback; + fd->flush_data = cbdata; +} + +/* + * comm_checktimeouts() - check the socket timeouts + * + * All this routine does is call the given callback/cbdata, without closing + * down the file descriptor. When close handlers have been implemented, + * this will happen. + */ +void +comm_checktimeouts(void *notused) +{ + int i; + fde_t *F; + PF *hdl; + void *data; + + for (i = 0; i < FD_HASH_SIZE; i++) + for (F = fd_hash[i]; F != NULL; F = fd_next_in_loop) + { + assert(F->flags.open); + fd_next_in_loop = F->hnext; + + /* check flush functions */ + if (F->flush_handler && F->flush_timeout > 0 && + F->flush_timeout < CurrentTime) + { + hdl = F->flush_handler; + data = F->flush_data; + comm_setflush(F, 0, NULL, NULL); + hdl(F, data); + } + + /* check timeouts */ + if (F->timeout_handler && F->timeout > 0 && + F->timeout < CurrentTime) + { + /* Call timeout handler */ + hdl = F->timeout_handler; + data = F->timeout_data; + comm_settimeout(F, 0, NULL, NULL); + hdl(F, data); + } + } +} + +/* + * void comm_connect_tcp(int fd, const char *host, unsigned short port, + * struct sockaddr *clocal, int socklen, + * CNCB *callback, void *data, int aftype, int timeout) + * Input: An fd to connect with, a host and port to connect to, + * a local sockaddr to connect from + length(or NULL to use the + * default), a callback, the data to pass into the callback, the + * address family. + * Output: None. + * Side-effects: A non-blocking connection to the host is started, and + * if necessary, set up for selection. The callback given + * may be called now, or it may be called later. + */ +void +comm_connect_tcp(fde_t *fd, const char *host, unsigned short port, + struct sockaddr *clocal, int socklen, CNCB *callback, + void *data, int aftype, int timeout) +{ + struct addrinfo hints, *res; + char portname[PORTNAMELEN + 1]; + + assert(callback); + fd->connect.callback = callback; + fd->connect.data = data; + + fd->connect.hostaddr.ss.ss_family = aftype; + fd->connect.hostaddr.ss_port = htons(port); + + /* Note that we're using a passed sockaddr here. This is because + * generally you'll be bind()ing to a sockaddr grabbed from + * getsockname(), so this makes things easier. + * XXX If NULL is passed as local, we should later on bind() to the + * virtual host IP, for completeness. + * -- adrian + */ + if ((clocal != NULL) && (bind(fd->fd, clocal, socklen) < 0)) + { + /* Failure, call the callback with COMM_ERR_BIND */ + comm_connect_callback(fd, COMM_ERR_BIND); + /* ... and quit */ + return; + } + + /* Next, if we have been given an IP, get the addr and skip the + * DNS check (and head direct to comm_connect_tryconnect(). + */ + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST; + + snprintf(portname, sizeof(portname), "%d", port); + + if (getaddrinfo(host, portname, &hints, &res)) + { + /* Send the DNS request, for the next level */ + if (aftype == AF_INET6) + gethost_byname_type(comm_connect_dns_callback, fd, host, T_AAAA); + else + gethost_byname_type(comm_connect_dns_callback, fd, host, T_A); + } + else + { + /* We have a valid IP, so we just call tryconnect */ + /* Make sure we actually set the timeout here .. */ + assert(res != NULL); + memcpy(&fd->connect.hostaddr, res->ai_addr, res->ai_addrlen); + fd->connect.hostaddr.ss_len = res->ai_addrlen; + fd->connect.hostaddr.ss.ss_family = res->ai_family; + freeaddrinfo(res); + comm_settimeout(fd, timeout*1000, comm_connect_timeout, NULL); + comm_connect_tryconnect(fd, NULL); + } +} + +/* + * comm_connect_callback() - call the callback, and continue with life + */ +static void +comm_connect_callback(fde_t *fd, int status) +{ + CNCB *hdl; + + /* This check is gross..but probably necessary */ + if (fd->connect.callback == NULL) + return; + + /* Clear the connect flag + handler */ + hdl = fd->connect.callback; + fd->connect.callback = NULL; + + /* Clear the timeout handler */ + comm_settimeout(fd, 0, NULL, NULL); + + /* Call the handler */ + hdl(fd, status, fd->connect.data); +} + +/* + * comm_connect_timeout() - this gets called when the socket connection + * times out. This *only* can be called once connect() is initially + * called .. + */ +static void +comm_connect_timeout(fde_t *fd, void *notused) +{ + /* error! */ + comm_connect_callback(fd, COMM_ERR_TIMEOUT); +} + +/* + * comm_connect_dns_callback() - called at the completion of the DNS request + * + * The DNS request has completed, so if we've got an error, return it, + * otherwise we initiate the connect() + */ +static void +comm_connect_dns_callback(void *vptr, const struct irc_ssaddr *addr, const char *name) +{ + fde_t *F = vptr; + + if (name == NULL) + { + comm_connect_callback(F, COMM_ERR_DNS); + return; + } + + /* No error, set a 10 second timeout */ + comm_settimeout(F, 30*1000, comm_connect_timeout, NULL); + + /* Copy over the DNS reply info so we can use it in the connect() */ + /* + * Note we don't fudge the refcount here, because we aren't keeping + * the DNS record around, and the DNS cache is gone anyway.. + * -- adrian + */ + memcpy(&F->connect.hostaddr, addr, addr->ss_len); + /* The cast is hacky, but safe - port offset is same on v4 and v6 */ + ((struct sockaddr_in *) &F->connect.hostaddr)->sin_port = + F->connect.hostaddr.ss_port; + F->connect.hostaddr.ss_len = addr->ss_len; + + /* Now, call the tryconnect() routine to try a connect() */ + comm_connect_tryconnect(F, NULL); +} + +/* static void comm_connect_tryconnect(int fd, void *notused) + * Input: The fd, the handler data(unused). + * Output: None. + * Side-effects: Try and connect with pending connect data for the FD. If + * we succeed or get a fatal error, call the callback. + * Otherwise, it is still blocking or something, so register + * to select for a write event on this FD. + */ +static void +comm_connect_tryconnect(fde_t *fd, void *notused) +{ + int retval; + + /* This check is needed or re-entrant s_bsd_* like sigio break it. */ + if (fd->connect.callback == NULL) + return; + + /* Try the connect() */ + retval = connect(fd->fd, (struct sockaddr *) &fd->connect.hostaddr, + fd->connect.hostaddr.ss_len); + + /* Error? */ + if (retval < 0) + { + /* + * If we get EISCONN, then we've already connect()ed the socket, + * which is a good thing. + * -- adrian + */ + if (errno == EISCONN) + comm_connect_callback(fd, COMM_OK); + else if (ignoreErrno(errno)) + /* Ignore error? Reschedule */ + comm_setselect(fd, COMM_SELECT_WRITE, comm_connect_tryconnect, + NULL, 0); + else + /* Error? Fail with COMM_ERR_CONNECT */ + comm_connect_callback(fd, COMM_ERR_CONNECT); + return; + } + + /* If we get here, we've suceeded, so call with COMM_OK */ + comm_connect_callback(fd, COMM_OK); +} + +/* + * comm_errorstr() - return an error string for the given error condition + */ +const char * +comm_errstr(int error) +{ + if (error < 0 || error >= COMM_ERR_MAX) + return "Invalid error number!"; + return comm_err_str[error]; +} + +/* + * comm_open() - open a socket + * + * This is a highly highly cut down version of squid's comm_open() which + * for the most part emulates socket(), *EXCEPT* it fails if we're about + * to run out of file descriptors. + */ +int +comm_open(fde_t *F, int family, int sock_type, int proto, const char *note) +{ + int fd; + + /* First, make sure we aren't going to run out of file descriptors */ + if (number_fd >= hard_fdlimit) + { + errno = ENFILE; + return -1; + } + + /* + * Next, we try to open the socket. We *should* drop the reserved FD + * limit if/when we get an error, but we can deal with that later. + * XXX !!! -- adrian + */ + fd = socket(family, sock_type, proto); + if (fd < 0) + return -1; /* errno will be passed through, yay.. */ + + execute_callback(setup_socket_cb, fd); + + /* update things in our fd tracking */ + fd_open(F, fd, 1, note); + return 0; +} + +/* + * comm_accept() - accept an incoming connection + * + * This is a simple wrapper for accept() which enforces FD limits like + * comm_open() does. Returned fd must be either closed or tagged with + * fd_open (this function no longer does it). + */ +int +comm_accept(struct Listener *lptr, struct irc_ssaddr *pn) +{ + int newfd; + socklen_t addrlen = sizeof(struct irc_ssaddr); + + if (number_fd >= hard_fdlimit) + { + errno = ENFILE; + return -1; + } + + /* + * Next, do the accept(). if we get an error, we should drop the + * reserved fd limit, but we can deal with that when comm_open() + * also does it. XXX -- adrian + */ + newfd = accept(lptr->fd.fd, (struct sockaddr *)pn, &addrlen); + if (newfd < 0) + return -1; + +#ifdef IPV6 + remove_ipv6_mapping(pn); +#else + pn->ss_len = addrlen; +#endif + + execute_callback(setup_socket_cb, newfd); + + /* .. and return */ + return newfd; +} + +/* + * remove_ipv6_mapping() - Removes IPv4-In-IPv6 mapping from an address + * OSes with IPv6 mapping listening on both + * AF_INET and AF_INET6 map AF_INET connections inside AF_INET6 structures + * + */ +#ifdef IPV6 +void +remove_ipv6_mapping(struct irc_ssaddr *addr) +{ + if (addr->ss.ss_family == AF_INET6) + { + if (IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)addr)->sin6_addr)) + { + struct sockaddr_in6 v6; + struct sockaddr_in *v4 = (struct sockaddr_in *)addr; + + memcpy(&v6, addr, sizeof(v6)); + memset(v4, 0, sizeof(struct sockaddr_in)); + memcpy(&v4->sin_addr, &v6.sin6_addr.s6_addr[12], sizeof(v4->sin_addr)); + + addr->ss.ss_family = AF_INET; + addr->ss_len = sizeof(struct sockaddr_in); + } + else + addr->ss_len = sizeof(struct sockaddr_in6); + } + else + addr->ss_len = sizeof(struct sockaddr_in); +} +#endif diff --git a/src/s_bsd_devpoll.c b/src/s_bsd_devpoll.c new file mode 100644 index 0000000..49d4eee --- /dev/null +++ b/src/s_bsd_devpoll.c @@ -0,0 +1,186 @@ +/* + * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd). + * s_bsd_devpoll.c: /dev/poll compatible network routines. + * + * Originally by Adrian Chadd <adrian@creative.net.au> + * Copyright (C) 2002 Hybrid Development Team + * + * 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 + * + * $Id$ + */ + +#include "stdinc.h" +#if USE_IOPOLL_MECHANISM == __IOPOLL_MECHANISM_DEVPOLL +#include <sys/ioctl.h> +/* HPUX uses devpoll.h and not sys/devpoll.h */ +#ifdef HAVE_DEVPOLL_H +# include <devpoll.h> +#else +# ifdef HAVE_SYS_DEVPOLL_H +# include <sys/devpoll.h> +# else +# error "No devpoll.h found! Try ./configuring and letting the script choose for you." +# endif +#endif +#include "fdlist.h" +#include "ircd.h" +#include "s_bsd.h" +#include "log.h" + +static fde_t dpfd; + +/* + * init_netio + * + * This is a needed exported function which will be called to initialise + * the network loop code. + */ +void +init_netio(void) +{ + int fd; + + if ((fd = open("/dev/poll", O_RDWR)) < 0) + { + ilog(LOG_TYPE_IRCD, "init_netio: Couldn't open /dev/poll - %d: %s", + errno, strerror(errno)); + exit(115); /* Whee! */ + } + + fd_open(&dpfd, fd, 0, "/dev/poll file descriptor"); +} + +/* + * Write an update to the devpoll filter. + * See, we end up having to do a seperate (?) remove before we do an + * add of a new polltype, so we have to have this function seperate from + * the others. + */ +static void +devpoll_write_update(int fd, int events) +{ + struct pollfd pfd; + + /* Build the pollfd entry */ + pfd.revents = 0; + pfd.fd = fd; + pfd.events = events; + + /* Write the thing to our poll fd */ + if (write(dpfd.fd, &pfd, sizeof(pfd)) != sizeof(pfd)) + ilog(LOG_TYPE_IRCD, "devpoll_write_update: dpfd write failed %d: %s", + errno, strerror(errno)); +} + +/* + * comm_setselect + * + * This is a needed exported function which will be called to register + * and deregister interest in a pending IO state for a given FD. + */ +void +comm_setselect(fde_t *F, unsigned int type, PF *handler, + void *client_data, time_t timeout) +{ + int new_events; + + if ((type & COMM_SELECT_READ)) + { + F->read_handler = handler; + F->read_data = client_data; + } + + if ((type & COMM_SELECT_WRITE)) + { + F->write_handler = handler; + F->write_data = client_data; + } + + new_events = (F->read_handler ? POLLIN : 0) | + (F->write_handler ? POLLOUT : 0); + + if (timeout != 0) + F->timeout = CurrentTime + (timeout / 1000); + + if (new_events != F->evcache) + { + devpoll_write_update(F->fd, POLLREMOVE); + if ((F->evcache = new_events)) + devpoll_write_update(F->fd, new_events); + } +} + +/* + * comm_select + * + * Called to do the new-style IO, courtesy of squid (like most of this + * new IO code). This routine handles the stuff we've hidden in + * comm_setselect and fd_table[] and calls callbacks for IO ready + * events. + */ +void +comm_select(void) +{ + int num, i; + struct pollfd pollfds[128]; + struct dvpoll dopoll; + PF *hdl; + fde_t *F; + + dopoll.dp_timeout = SELECT_DELAY; + dopoll.dp_nfds = 128; + dopoll.dp_fds = &pollfds[0]; + num = ioctl(dpfd.fd, DP_POLL, &dopoll); + + set_time(); + + if (num < 0) + { +#ifdef HAVE_USLEEP + usleep(50000); /* avoid 99% CPU in comm_select */ +#endif + return; + } + + for (i = 0; i < num; i++) + { + F = lookup_fd(dopoll.dp_fds[i].fd); + if (F == NULL || !F->flags.open) + continue; + + if ((dopoll.dp_fds[i].revents & POLLIN)) + if ((hdl = F->read_handler) != NULL) + { + F->read_handler = NULL; + hdl(F, F->read_data); + if (!F->flags.open) + continue; + } + + if ((dopoll.dp_fds[i].revents & POLLOUT)) + if ((hdl = F->write_handler) != NULL) + { + F->write_handler = NULL; + hdl(F, F->write_data); + if (!F->flags.open) + continue; + } + + comm_setselect(F, 0, NULL, NULL, 0); + } +} +#endif diff --git a/src/s_bsd_epoll.c b/src/s_bsd_epoll.c new file mode 100644 index 0000000..8e8de83 --- /dev/null +++ b/src/s_bsd_epoll.c @@ -0,0 +1,221 @@ +/* + * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd). + * s_bsd_epoll.c: Linux epoll() compatible network routines. + * + * Copyright (C) 2002-2005 Hybrid Development Team + * Based also on work of Adrian Chadd, Aaron Sethman and others. + * + * 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 + * + * $Id$ + */ + +#include "stdinc.h" +#if USE_IOPOLL_MECHANISM == __IOPOLL_MECHANISM_EPOLL +#include "fdlist.h" +#include "ircd.h" +#include "memory.h" +#include "s_bsd.h" +#include "log.h" +#include <sys/epoll.h> +#include <sys/syscall.h> + +static fde_t efd; + +/* Thanks to ircu for the following ifdefs. */ + +/* The GNU C library may have a valid header but stub implementations + * of the epoll system calls. If so, provide our own. */ +#if defined(__stub_epoll_create) || defined(__stub___epoll_create) || defined(EPOLL_NEED_BODY) + +/* Oh, did we mention that some glibc releases do not even define the + * syscall numbers? */ +#if !defined(__NR_epoll_create) +#if defined(__ia64__) +#define __NR_epoll_create 1243 +#define __NR_epoll_ctl 1244 +#define __NR_epoll_wait 1245 +#elif defined(__x86_64__) +#define __NR_epoll_create 214 +#define __NR_epoll_ctl 233 +#define __NR_epoll_wait 232 +#elif defined(__sparc64__) || defined(__sparc__) +#define __NR_epoll_create 193 +#define __NR_epoll_ctl 194 +#define __NR_epoll_wait 195 +#elif defined(__s390__) || defined(__m68k__) +#define __NR_epoll_create 249 +#define __NR_epoll_ctl 250 +#define __NR_epoll_wait 251 +#elif defined(__ppc64__) || defined(__ppc__) +#define __NR_epoll_create 236 +#define __NR_epoll_ctl 237 +#define __NR_epoll_wait 238 +#elif defined(__parisc__) || defined(__arm26__) || defined(__arm__) +#define __NR_epoll_create 224 +#define __NR_epoll_ctl 225 +#define __NR_epoll_wait 226 +#elif defined(__alpha__) +#define __NR_epoll_create 407 +#define __NR_epoll_ctl 408 +#define __NR_epoll_wait 409 +#elif defined(__sh64__) +#define __NR_epoll_create 282 +#define __NR_epoll_ctl 283 +#define __NR_epoll_wait 284 +#elif defined(__i386__) || defined(__sh__) || defined(__m32r__) || defined(__h8300__) || defined(__frv__) +#define __NR_epoll_create 254 +#define __NR_epoll_ctl 255 +#define __NR_epoll_wait 256 +#else /* cpu types */ +#error No system call numbers defined for epoll family. +#endif /* cpu types */ +#endif /* !defined(__NR_epoll_create) */ + +_syscall1(int, epoll_create, int, size) +_syscall4(int, epoll_ctl, int, epfd, int, op, int, fd, struct epoll_event *, event) +_syscall4(int, epoll_wait, int, epfd, struct epoll_event *, pevents, int, maxevents, int, timeout) + +#endif /* epoll_create defined as stub */ + +/* + * init_netio + * + * This is a needed exported function which will be called to initialise + * the network loop code. + */ +void +init_netio(void) +{ + int fd; + + if ((fd = epoll_create(hard_fdlimit)) < 0) + { + ilog(LOG_TYPE_IRCD, "init_netio: Couldn't open epoll fd - %d: %s", + errno, strerror(errno)); + exit(115); /* Whee! */ + } + + fd_open(&efd, fd, 0, "epoll file descriptor"); +} + +/* + * comm_setselect + * + * This is a needed exported function which will be called to register + * and deregister interest in a pending IO state for a given FD. + */ +void +comm_setselect(fde_t *F, unsigned int type, PF *handler, + void *client_data, time_t timeout) +{ + int new_events, op; + struct epoll_event ep_event = { 0, { 0 } }; + + if ((type & COMM_SELECT_READ)) + { + F->read_handler = handler; + F->read_data = client_data; + } + + if ((type & COMM_SELECT_WRITE)) + { + F->write_handler = handler; + F->write_data = client_data; + } + + new_events = (F->read_handler ? EPOLLIN : 0) | + (F->write_handler ? EPOLLOUT : 0); + + if (timeout != 0) + F->timeout = CurrentTime + (timeout / 1000); + + if (new_events != F->evcache) + { + if (new_events == 0) + op = EPOLL_CTL_DEL; + else if (F->evcache == 0) + op = EPOLL_CTL_ADD; + else + op = EPOLL_CTL_MOD; + + ep_event.events = F->evcache = new_events; + ep_event.data.fd = F->fd; + + if (epoll_ctl(efd.fd, op, F->fd, &ep_event) != 0) + { + ilog(LOG_TYPE_IRCD, "comm_setselect: epoll_ctl() failed: %s", strerror(errno)); + abort(); + } + } +} + +/* + * comm_select() + * + * Called to do the new-style IO, courtesy of of squid (like most of this + * new IO code). This routine handles the stuff we've hidden in + * comm_setselect and fd_table[] and calls callbacks for IO ready + * events. + */ +void +comm_select(void) +{ + struct epoll_event ep_fdlist[128]; + int num, i; + PF *hdl; + fde_t *F; + + num = epoll_wait(efd.fd, ep_fdlist, 128, SELECT_DELAY); + + set_time(); + + if (num < 0) + { +#ifdef HAVE_USLEEP + usleep(50000); /* avoid 99% CPU in comm_select */ +#endif + return; + } + + for (i = 0; i < num; i++) + { + F = lookup_fd(ep_fdlist[i].data.fd); + if (F == NULL || !F->flags.open) + continue; + + if ((ep_fdlist[i].events & (EPOLLIN | EPOLLHUP | EPOLLERR))) + if ((hdl = F->read_handler) != NULL) + { + F->read_handler = NULL; + hdl(F, F->read_data); + if (!F->flags.open) + continue; + } + + if ((ep_fdlist[i].events & (EPOLLOUT | EPOLLHUP | EPOLLERR))) + if ((hdl = F->write_handler) != NULL) + { + F->write_handler = NULL; + hdl(F, F->write_data); + if (!F->flags.open) + continue; + } + + comm_setselect(F, 0, NULL, NULL, 0); + } +} +#endif diff --git a/src/s_bsd_kqueue.c b/src/s_bsd_kqueue.c new file mode 100644 index 0000000..6571878 --- /dev/null +++ b/src/s_bsd_kqueue.c @@ -0,0 +1,199 @@ +/* + * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd). + * s_bsd_kqueue.c: FreeBSD kqueue compatible network routines. + * + * Originally by Adrian Chadd <adrian@creative.net.au> + * Copyright (C) 2005 Hybrid Development Team + * + * 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 + * + * $Id$ + */ + +#include "stdinc.h" +#if USE_IOPOLL_MECHANISM == __IOPOLL_MECHANISM_KQUEUE +#include <sys/event.h> +#include "fdlist.h" +#include "ircd.h" +#include "memory.h" +#include "s_bsd.h" +#include "log.h" + +#define KE_LENGTH 128 + +/* jlemon goofed up and didn't add EV_SET until fbsd 4.3 */ + +#ifndef EV_SET +#define EV_SET(kevp, a, b, c, d, e, f) do { \ + (kevp)->ident = (a); \ + (kevp)->filter = (b); \ + (kevp)->flags = (c); \ + (kevp)->fflags = (d); \ + (kevp)->data = (e); \ + (kevp)->udata = (f); \ +} while(0) +#endif + +static fde_t kqfd; +static struct kevent kq_fdlist[KE_LENGTH]; /* kevent buffer */ +static int kqoff; /* offset into the buffer */ +void init_netio(void); + +/* + * init_netio + * + * This is a needed exported function which will be called to initialise + * the network loop code. + */ +void +init_netio(void) +{ + int fd; + + if ((fd = kqueue()) < 0) + { + ilog(LOG_TYPE_IRCD, "init_netio: Couldn't open kqueue fd!"); + exit(115); /* Whee! */ + } + + fd_open(&kqfd, fd, 0, "kqueue() file descriptor"); +} + +/* + * Write a single update to the kqueue list. + */ +static void +kq_update_events(int fd, int filter, int what) +{ + static struct timespec zero_timespec = {0, 0}; + struct kevent *kep = kq_fdlist + kqoff; + + EV_SET(kep, (uintptr_t) fd, (short) filter, what, 0, 0, NULL); + + if (++kqoff == KE_LENGTH) + { + kevent(kqfd.fd, kq_fdlist, kqoff, NULL, 0, &zero_timespec); + kqoff = 0; + } +} + +/* + * comm_setselect + * + * This is a needed exported function which will be called to register + * and deregister interest in a pending IO state for a given FD. + */ +void +comm_setselect(fde_t *F, unsigned int type, PF *handler, + void *client_data, time_t timeout) +{ + int new_events, diff; + + if ((type & COMM_SELECT_READ)) + { + F->read_handler = handler; + F->read_data = client_data; + } + + if ((type & COMM_SELECT_WRITE)) + { + F->write_handler = handler; + F->write_data = client_data; + } + + new_events = (F->read_handler ? COMM_SELECT_READ : 0) | + (F->write_handler ? COMM_SELECT_WRITE : 0); + + if (timeout != 0) + F->timeout = CurrentTime + (timeout / 1000); + + diff = new_events ^ F->evcache; + + if ((diff & COMM_SELECT_READ)) + kq_update_events(F->fd, EVFILT_READ, + (new_events & COMM_SELECT_READ) ? EV_ADD : EV_DELETE); + if ((diff & COMM_SELECT_WRITE)) + kq_update_events(F->fd, EVFILT_WRITE, + (new_events & COMM_SELECT_WRITE) ? EV_ADD : EV_DELETE); + + F->evcache = new_events; +} + +/* + * comm_select + * + * Called to do the new-style IO, courtesy of squid (like most of this + * new IO code). This routine handles the stuff we've hidden in + * comm_setselect and fd_table[] and calls callbacks for IO ready + * events. + */ +void +comm_select(void) +{ + int num, i; + static struct kevent ke[KE_LENGTH]; + struct timespec poll_time; + PF *hdl; + fde_t *F; + + /* + * remember we are doing NANOseconds here, not micro/milli. God knows + * why jlemon used a timespec, but hey, he wrote the interface, not I + * -- Adrian + */ + poll_time.tv_sec = 0; + poll_time.tv_nsec = SELECT_DELAY * 1000000; + num = kevent(kqfd.fd, kq_fdlist, kqoff, ke, KE_LENGTH, &poll_time); + kqoff = 0; + + set_time(); + + if (num < 0) + { +#ifdef HAVE_USLEEP + usleep(50000); /* avoid 99% CPU in comm_select */ +#endif + return; + } + + for (i = 0; i < num; i++) + { + F = lookup_fd(ke[i].ident); + if (F == NULL || !F->flags.open || (ke[i].flags & EV_ERROR)) + continue; + + if (ke[i].filter == EVFILT_READ) + if ((hdl = F->read_handler) != NULL) + { + F->read_handler = NULL; + hdl(F, F->read_data); + if (!F->flags.open) + continue; + } + + if (ke[i].filter == EVFILT_WRITE) + if ((hdl = F->write_handler) != NULL) + { + F->write_handler = NULL; + hdl(F, F->write_data); + if (!F->flags.open) + continue; + } + + comm_setselect(F, 0, NULL, NULL, 0); + } +} +#endif diff --git a/src/s_bsd_poll.c b/src/s_bsd_poll.c new file mode 100644 index 0000000..2692da5 --- /dev/null +++ b/src/s_bsd_poll.c @@ -0,0 +1,224 @@ +/* + * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd). + * s_bsd_poll.c: POSIX poll() compatible network routines. + * + * Originally by Adrian Chadd <adrian@creative.net.au> + * Copyright (C) 2002 Hybrid Development Team + * + * 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 + * + * $Id$ + */ + +#include "stdinc.h" +#if USE_IOPOLL_MECHANISM == __IOPOLL_MECHANISM_POLL +#include <sys/poll.h> +#include "fdlist.h" +#include "list.h" +#include "hook.h" +#include "ircd.h" +#include "s_bsd.h" +#include "log.h" + +/* I hate linux -- adrian */ +#ifndef POLLRDNORM +#define POLLRDNORM POLLIN +#endif +#ifndef POLLWRNORM +#define POLLWRNORM POLLOUT +#endif + +static struct pollfd *pollfds; +static int pollmax = -1; /* highest FD number */ +static dlink_node *hookptr; + +/* + * changing_fdlimit + * + * Resize pollfds array if necessary. + */ +static void * +changing_fdlimit(va_list args) +{ + int old_fdlimit = hard_fdlimit; + + pass_callback(hookptr, va_arg(args, int)); + + if (hard_fdlimit != old_fdlimit) + pollfds = MyRealloc(pollfds, sizeof(struct pollfd) * hard_fdlimit); + + return NULL; +} + +/* + * init_netio + * + * This is a needed exported function which will be called to initialise + * the network loop code. + */ +void +init_netio(void) +{ + int fd; + + pollfds = MyMalloc(sizeof(struct pollfd) * hard_fdlimit); + + for (fd = 0; fd < hard_fdlimit; fd++) + pollfds[fd].fd = -1; + + hookptr = install_hook(fdlimit_cb, changing_fdlimit); +} + +/* + * find a spare slot in the fd list. We can optimise this out later! + * -- adrian + */ +static inline int +poll_findslot(void) +{ + int i; + + for (i = 0; i < hard_fdlimit; i++) + if (pollfds[i].fd == -1) + { + /* MATCH!!#$*&$ */ + return i; + } + + assert(1 == 0); + /* NOTREACHED */ + return -1; +} + +/* + * comm_setselect + * + * This is a needed exported function which will be called to register + * and deregister interest in a pending IO state for a given FD. + */ +void +comm_setselect(fde_t *F, unsigned int type, PF *handler, + void *client_data, time_t timeout) +{ + int new_events; + + if ((type & COMM_SELECT_READ)) + { + F->read_handler = handler; + F->read_data = client_data; + } + + if ((type & COMM_SELECT_WRITE)) + { + F->write_handler = handler; + F->write_data = client_data; + } + + new_events = (F->read_handler ? POLLRDNORM : 0) | + (F->write_handler ? POLLWRNORM : 0); + + if (timeout != 0) + F->timeout = CurrentTime + (timeout / 1000); + + if (new_events != F->evcache) + { + if (new_events == 0) + { + pollfds[F->comm_index].fd = -1; + pollfds[F->comm_index].revents = 0; + + if (pollmax == F->comm_index) + while (pollmax >= 0 && pollfds[pollmax].fd == -1) + pollmax--; + } + else + { + if (F->evcache == 0) + { + F->comm_index = poll_findslot(); + if (F->comm_index > pollmax) + pollmax = F->comm_index; + + pollfds[F->comm_index].fd = F->fd; + } + pollfds[F->comm_index].events = new_events; + pollfds[F->comm_index].revents = 0; + } + + F->evcache = new_events; + } +} + +/* + * comm_select + * + * Called to do the new-style IO, courtesy of of squid (like most of this + * new IO code). This routine handles the stuff we've hidden in + * comm_setselect and fd_table[] and calls callbacks for IO ready + * events. + */ +void +comm_select(void) +{ + int num, ci, revents; + PF *hdl; + fde_t *F; + + /* XXX kill that +1 later ! -- adrian */ + num = poll(pollfds, pollmax + 1, SELECT_DELAY); + + set_time(); + + if (num < 0) + { +#ifdef HAVE_USLEEP + usleep(50000); /* avoid 99% CPU in comm_select */ +#endif + return; + } + + for (ci = 0; ci <= pollmax && num > 0; ci++) + { + if ((revents = pollfds[ci].revents) == 0 || pollfds[ci].fd == -1) + continue; + num--; + + F = lookup_fd(pollfds[ci].fd); + if (F == NULL || !F->flags.open) + continue; + + if (revents & (POLLRDNORM | POLLIN | POLLHUP | POLLERR)) + if ((hdl = F->read_handler) != NULL) + { + F->read_handler = NULL; + hdl(F, F->read_data); + if (!F->flags.open) + continue; + } + + if (revents & (POLLWRNORM | POLLOUT | POLLHUP | POLLERR)) + if ((hdl = F->write_handler) != NULL) + { + F->write_handler = NULL; + hdl(F, F->write_data); + if (!F->flags.open) + continue; + } + + comm_setselect(F, 0, NULL, NULL, 0); + } +} +#endif diff --git a/src/s_bsd_select.c b/src/s_bsd_select.c new file mode 100644 index 0000000..c0b327c --- /dev/null +++ b/src/s_bsd_select.c @@ -0,0 +1,204 @@ +/* + * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd). + * s_bsd_select.c: select() compatible network routines. + * + * Originally by Adrian Chadd <adrian@creative.net.au> + * Copyright (C) 2002 Hybrid Development Team + * + * 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 + * + * $Id$ + */ + +#include "stdinc.h" +#if USE_IOPOLL_MECHANISM == __IOPOLL_MECHANISM_SELECT +#include "list.h" +#include "fdlist.h" +#include "hook.h" +#include "ircd.h" +#include "s_bsd.h" +#include "log.h" + +/* + * Note that this is only a single list - multiple lists is kinda pointless + * under select because the list size is a function of the highest FD :-) + * -- adrian + */ + +static fd_set select_readfds, tmpreadfds; +static fd_set select_writefds, tmpwritefds; +static int highest_fd = -1; +static dlink_node *hookptr; + +/* + * changing_fdlimit + * + * Make sure hard_fdlimit doesn't go too big. + */ +static void * +changing_fdlimit(va_list args) +{ + int fdmax = va_arg(args, int); + + if (fdmax > FD_SETSIZE) + fdmax = FD_SETSIZE; + + return pass_callback(hookptr, fdmax); +} + +/* + * init_netio + * + * This is a needed exported function which will be called to initialise + * the network loop code. + */ +void +init_netio(void) +{ + FD_ZERO(&select_readfds); + FD_ZERO(&select_writefds); + + hookptr = install_hook(fdlimit_cb, changing_fdlimit); +} + +/* + * comm_setselect + * + * This is a needed exported function which will be called to register + * and deregister interest in a pending IO state for a given FD. + */ +void +comm_setselect(fde_t *F, unsigned int type, PF *handler, + void *client_data, time_t timeout) +{ + int new_events; + + if ((type & COMM_SELECT_READ)) + { + F->read_handler = handler; + F->read_data = client_data; + } + + if ((type & COMM_SELECT_WRITE)) + { + F->write_handler = handler; + F->write_data = client_data; + } + + new_events = (F->read_handler ? COMM_SELECT_READ : 0) | + (F->write_handler ? COMM_SELECT_WRITE : 0); + + if (timeout != 0) + F->timeout = CurrentTime + (timeout / 1000); + + if (new_events != F->evcache) + { + if ((new_events & COMM_SELECT_READ)) + FD_SET(F->fd, &select_readfds); + else + { + FD_CLR(F->fd, &select_readfds); + FD_CLR(F->fd, &tmpreadfds); + } + + if ((new_events & COMM_SELECT_WRITE)) + FD_SET(F->fd, &select_writefds); + else + { + FD_CLR(F->fd, &select_writefds); + FD_CLR(F->fd, &tmpwritefds); + } + + if (new_events == 0) + { + if (highest_fd == F->fd) + while (highest_fd >= 0 && (FD_ISSET(highest_fd, &select_readfds) || + FD_ISSET(highest_fd, &select_writefds))) + highest_fd--; + } + else if (F->evcache == 0) + if (F->fd > highest_fd) + highest_fd = F->fd; + + F->evcache = new_events; + } +} + +/* + * comm_select + * + * Called to do the new-style IO, courtesy of squid (like most of this + * new IO code). This routine handles the stuff we've hidden in + * comm_setselect and fd_table[] and calls callbacks for IO ready + * events. + */ +void +comm_select(void) +{ + struct timeval to; + int num, fd; + fde_t *F; + PF *hdl; + + /* Copy over the read/write sets so we don't have to rebuild em */ + memcpy(&tmpreadfds, &select_readfds, sizeof(fd_set)); + memcpy(&tmpwritefds, &select_writefds, sizeof(fd_set)); + + to.tv_sec = 0; + to.tv_usec = SELECT_DELAY * 1000; + num = select(highest_fd + 1, &tmpreadfds, &tmpwritefds, NULL, &to); + + set_time(); + + if (num < 0) + { +#ifdef HAVE_USLEEP + usleep(50000); +#endif + return; + } + + for (fd = 0; fd <= highest_fd && num > 0; fd++) + if (FD_ISSET(fd, &tmpreadfds) || FD_ISSET(fd, &tmpwritefds)) + { + num--; + + F = lookup_fd(fd); + if (F == NULL || !F->flags.open) + continue; + + if (FD_ISSET(fd, &tmpreadfds)) + if ((hdl = F->read_handler) != NULL) + { + F->read_handler = NULL; + hdl(F, F->read_data); + if (!F->flags.open) + continue; + } + + if (FD_ISSET(fd, &tmpwritefds)) + if ((hdl = F->write_handler) != NULL) + { + F->write_handler = NULL; + hdl(F, F->write_data); + if (!F->flags.open) + continue; + } + + comm_setselect(F, 0, NULL, NULL, 0); + } +} +#endif diff --git a/src/s_bsd_sigio.c b/src/s_bsd_sigio.c new file mode 100644 index 0000000..6480393 --- /dev/null +++ b/src/s_bsd_sigio.c @@ -0,0 +1,318 @@ +/* + * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd). + * s_bsd_sigio.c: Linux Realtime SIGIO compatible network routines. + * + * Originally by Aaron Sethman <androsyn@ratbox.org> + * based upon: s_bsd_poll.c by Adrian Chadd <adrian@creative.net.au> + * Copyright (C) 2001-2002 Hybrid Development Team + * + * 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 + * + * $Id$ + */ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE 1 /* Needed for F_SETSIG */ +#endif + +#include "stdinc.h" +#if USE_IOPOLL_MECHANISM == __IOPOLL_MECHANISM_RTSIGIO +#include <sys/poll.h> +#include "list.h" +#include "fdlist.h" +#include "hook.h" +#include "ircd.h" +#include "s_bsd.h" +#include "log.h" + +#define SIGIO_SIGNAL SIGRTMIN + +static pid_t my_pid; +static sigset_t our_sigset; +static struct pollfd *pollfds; +static int pollmax = -1; /* highest FD number */ +static dlink_node *fdlim_hook, *setupfd_hook; + +/* + * static void mask_our_signal(int s) + * + * Input: None + * Output: None + * Side Effects: Block our signal + */ +static void +mask_our_signal() +{ + sigemptyset(&our_sigset); + sigaddset(&our_sigset, SIGIO_SIGNAL); + sigaddset(&our_sigset, SIGIO); + sigprocmask(SIG_BLOCK, &our_sigset, NULL); +} + +/* + * void setup_sigio_fd(int fd) + * + * Input: File descriptor + * Output: None + * Side Effect: Sets the FD up for SIGIO + */ +static void * +setup_sigio_fd(va_list args) +{ + int fd = va_arg(args, int); + + fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_ASYNC); + fcntl(fd, F_SETSIG, SIGIO_SIGNAL); + fcntl(fd, F_SETOWN, my_pid); + + return pass_callback(setupfd_hook, fd); +} + +/* + * changing_fdlimit + * + * Resize pollfds array if necessary. + */ +static void * +changing_fdlimit(va_list args) +{ + int old_fdlimit = hard_fdlimit; + + pass_callback(fdlim_hook, va_arg(args, int)); + + if (hard_fdlimit != old_fdlimit) + pollfds = MyRealloc(pollfds, sizeof(struct pollfd) * hard_fdlimit); + + return NULL; +} + +/* + * void init_netio(void) + * + * Input: None + * Output: None + * Side Effects: This is a needed exported function which will + * be called to initialise the network loop code. + */ +void +init_netio(void) +{ + int fd; + + pollfds = MyMalloc(sizeof(struct pollfd) * hard_fdlimit); + + for (fd = 0; fd < hard_fdlimit; fd++) + pollfds[fd].fd = -1; + + setupfd_hook = install_hook(setup_socket_cb, setup_sigio_fd); + fdlim_hook = install_hook(fdlimit_cb, changing_fdlimit); + + my_pid = getpid(); + mask_our_signal(SIGIO_SIGNAL); +} + +/* + * find a spare slot in the fd list. We can optimise this out later! + * -- adrian + */ +static inline int +poll_findslot(void) +{ + int i; + + for (i = 0; i < hard_fdlimit; i++) + { + if (pollfds[i].fd == -1) + { + /* MATCH!!#$*&$ */ + return i; + } + } + + assert(1 == 0); + /* NOTREACHED */ + return -1; +} + +/* + * comm_setselect + * + * This is a needed exported function which will be called to register + * and deregister interest in a pending IO state for a given FD. + */ +void +comm_setselect(fde_t *F, unsigned int type, PF *handler, + void *client_data, time_t timeout) +{ + int new_events; + + if ((type & COMM_SELECT_READ)) + { + F->read_handler = handler; + F->read_data = client_data; + } + + if ((type & COMM_SELECT_WRITE)) + { + F->write_handler = handler; + F->write_data = client_data; + } + + new_events = (F->read_handler ? POLLRDNORM : 0) | + (F->write_handler ? POLLWRNORM : 0); + + if (timeout != 0) + F->timeout = CurrentTime + (timeout / 1000); + + if (new_events != F->evcache) + { + if (new_events == 0) + { + pollfds[F->comm_index].fd = -1; + pollfds[F->comm_index].revents = 0; + + if (pollmax == F->comm_index) + while (pollmax >= 0 && pollfds[pollmax].fd == -1) + pollmax--; + } + else + { + if (F->evcache == 0) + { + F->comm_index = poll_findslot(); + if (F->comm_index > pollmax) + pollmax = F->comm_index; + + pollfds[F->comm_index].fd = F->fd; + } + pollfds[F->comm_index].events = new_events; + pollfds[F->comm_index].revents = 0; + } + + F->evcache = new_events; + } +} + +/* + * comm_select + * + * Called to do the new-style IO, courtesy of squid (like most of this + * new IO code). This routine handles the stuff we've hidden in + * comm_setselect and fd_table[] and calls callbacks for IO ready + * events. + */ +void +comm_select(void) +{ + static time_t last_rtsigqo_warning = 0; + struct timespec timeout; + struct siginfo si; + int i, revents, num; + fde_t *F; + PF *hdl; + + timeout.tv_sec = 0; + timeout.tv_nsec = 1000000 * SELECT_DELAY; + i = sigtimedwait(&our_sigset, &si, &timeout); + + set_time(); + + if (i != SIGIO) + { + if (i > 0) + { + F = lookup_fd(si.si_fd); + if (F == NULL || !F->flags.open) + return; + + if (si.si_band & (POLLRDNORM | POLLIN | POLLHUP | POLLERR)) + if ((hdl = F->read_handler) != NULL) + { + F->read_handler = NULL; + hdl(F, F->read_data); + if (!F->flags.open) + return; + } + + if (si.si_band & (POLLWRNORM | POLLOUT | POLLHUP | POLLERR)) + if ((hdl = F->write_handler) != NULL) + { + F->write_handler = NULL; + hdl(F, F->write_data); + if (!F->flags.open) + return; + } + + comm_setselect(F, 0, NULL, NULL, 0); + } + + return; + } + + /* RT signal queue overflowed.. */ + + if (CurrentTime - last_rtsigqo_warning >= 30) + { + ilog(LOG_TYPE_IRCD, "Kernel RT Signal queue overflowed. " + "Is /proc/sys/kernel/rtsig-max too small?"); + last_rtsigqo_warning = CurrentTime; + } + + signal(SIGIO_SIGNAL, SIG_IGN); + signal(SIGIO_SIGNAL, SIG_DFL); + + /* ..try polling instead */ + + while ((num = poll(pollfds, pollmax + 1, 0)) < 0 && ignoreErrno(errno)) + ; + + /* update current time again, eww.. */ + set_time(); + + for (i = 0; i <= pollmax && num > 0; i++) + { + if ((revents = pollfds[i].revents) == 0 || pollfds[i].fd == -1) + continue; + num--; + + F = lookup_fd(pollfds[i].fd); + if (F == NULL || !F->flags.open) + continue; + + if (revents & (POLLRDNORM | POLLIN | POLLHUP | POLLERR)) + if ((hdl = F->read_handler) != NULL) + { + F->read_handler = NULL; + hdl(F, F->read_data); + if (!F->flags.open) + continue; + } + + if (revents & (POLLWRNORM | POLLOUT | POLLHUP | POLLERR)) + if ((hdl = F->write_handler) != NULL) + { + F->write_handler = NULL; + hdl(F, F->write_data); + if (!F->flags.open) + continue; + } + + comm_setselect(F, 0, NULL, NULL, 0); + } + + mask_our_signal(SIGIO_SIGNAL); +} +#endif diff --git a/src/s_gline.c b/src/s_gline.c new file mode 100644 index 0000000..aff7a05 --- /dev/null +++ b/src/s_gline.c @@ -0,0 +1,114 @@ +/* + * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd). + * s_gline.c: GLine global ban functions. + * + * Copyright (C) 2002 by the past and present ircd coders, and others. + * + * 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 + * + * $Id$ + */ + +#include "stdinc.h" +#include "list.h" +#include "client.h" +#include "irc_string.h" +#include "ircd.h" +#include "hostmask.h" +#include "conf.h" +#include "s_misc.h" +#include "send.h" +#include "s_serv.h" +#include "s_gline.h" +#include "event.h" +#include "memory.h" + +dlink_list pending_glines[GLINE_PENDING_ADD_TYPE + 1] = { { NULL, NULL, 0 }, + { NULL, NULL, 0 } }; + +static void expire_pending_glines(struct gline_pending *); + + +struct AccessItem * +find_is_glined(const char *host, const char *user) +{ + struct irc_ssaddr iphost, *piphost; + struct AccessItem *aconf; + int t; + + if ((t = parse_netmask(host, &iphost, &t)) != HM_HOST) + { +#ifdef IPV6 + if (t == HM_IPV6) + t = AF_INET6; + else +#endif + t = AF_INET; + piphost = &iphost; + } + else + { + t = 0; + piphost = NULL; + } + + aconf = find_conf_by_address(host, piphost, CONF_GLINE, t, user, NULL, 0); + return aconf; +} + +/* cleanup_glines() + * + * inputs - NONE + * output - NONE + * side effects - expire gline lists + * This is an event started off in ircd.c + */ +void +cleanup_glines(void *unused) +{ + expire_pending_glines(unused); +} + +/* expire_pending_glines() + * + * inputs - NONE + * output - NONE + * side effects - + * + * Go through the pending gline list, expire any that haven't had + * enough "votes" in the time period allowed + */ +static void +expire_pending_glines(struct gline_pending *in) +{ + dlink_node *ptr = NULL, *next_ptr = NULL; + unsigned int idx = 0; + + for (; idx < GLINE_PENDING_ADD_TYPE + 1; ++idx) + { + DLINK_FOREACH_SAFE(ptr, next_ptr, pending_glines[idx].head) + { + struct gline_pending *glp_ptr = ptr->data; + + if ((glp_ptr->last_gline_time + ConfigFileEntry.gline_request_time) <= CurrentTime || + glp_ptr == in) + { + dlinkDelete(&glp_ptr->node, &pending_glines[idx]); + MyFree(glp_ptr); + } + } + } +} diff --git a/src/s_misc.c b/src/s_misc.c new file mode 100644 index 0000000..1b6166b --- /dev/null +++ b/src/s_misc.c @@ -0,0 +1,131 @@ +/* + * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd). + * s_misc.c: Yet another miscellaneous functions file. + * + * Copyright (C) 2002 by the past and present ircd coders, and others. + * + * 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 + * + * $Id$ + */ + +#include "stdinc.h" +#include "s_misc.h" +#include "client.h" +#include "irc_string.h" +#include "sprintf_irc.h" +#include "ircd.h" +#include "numeric.h" +#include "irc_res.h" +#include "fdlist.h" +#include "s_bsd.h" +#include "conf.h" +#include "s_serv.h" +#include "send.h" +#include "memory.h" + + +static const char *months[] = +{ + "January", "February", "March", "April", + "May", "June", "July", "August", + "September", "October", "November","December" +}; + +static const char *weekdays[] = +{ + "Sunday", "Monday", "Tuesday", "Wednesday", + "Thursday", "Friday", "Saturday" +}; + +char * +date(time_t lclock) +{ + static char buf[80], plus; + struct tm *lt, *gm; + struct tm gmbuf; + int minswest; + + if (!lclock) + lclock = CurrentTime; + gm = gmtime(&lclock); + memcpy(&gmbuf, gm, sizeof(gmbuf)); + gm = &gmbuf; + lt = localtime(&lclock); + + /* + * There is unfortunately no clean portable way to extract time zone + * offset information, so do ugly things. + */ + minswest = (gm->tm_hour - lt->tm_hour) * 60 + (gm->tm_min - lt->tm_min); + + if (lt->tm_yday != gm->tm_yday) + { + if ((lt->tm_yday > gm->tm_yday && lt->tm_year == gm->tm_year) || + (lt->tm_yday < gm->tm_yday && lt->tm_year != gm->tm_year)) + minswest -= 24 * 60; + else + minswest += 24 * 60; + } + + plus = (minswest > 0) ? '-' : '+'; + if (minswest < 0) + minswest = -minswest; + + snprintf(buf, sizeof(buf), "%s %s %d %d -- %02u:%02u:%02u %c%02u:%02u", + weekdays[lt->tm_wday], months[lt->tm_mon],lt->tm_mday, + lt->tm_year + 1900, lt->tm_hour, lt->tm_min, lt->tm_sec, + plus, minswest/60, minswest%60); + return buf; +} + +const char * +smalldate(time_t lclock) +{ + static char buf[MAX_DATE_STRING]; + struct tm *lt, *gm; + struct tm gmbuf; + + if (!lclock) + lclock = CurrentTime; + + gm = gmtime(&lclock); + memcpy(&gmbuf, gm, sizeof(gmbuf)); + gm = &gmbuf; + lt = localtime(&lclock); + + snprintf(buf, sizeof(buf), "%d/%d/%d %02d.%02d", + lt->tm_year + 1900, lt->tm_mon + 1, lt->tm_mday, + lt->tm_hour, lt->tm_min); + + return buf; +} + +#ifdef HAVE_LIBCRYPTO +char * +ssl_get_cipher(const SSL *ssl) +{ + static char buffer[IRCD_BUFSIZE / 4]; + int bits = 0; + + SSL_CIPHER_get_bits(SSL_get_current_cipher(ssl), &bits); + + snprintf(buffer, sizeof(buffer), "%s %s-%d", SSL_get_version(ssl), + SSL_get_cipher(ssl), bits); + + return buffer; +} +#endif diff --git a/src/s_serv.c b/src/s_serv.c new file mode 100644 index 0000000..4d7dcd6 --- /dev/null +++ b/src/s_serv.c @@ -0,0 +1,1503 @@ +/* + * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd). + * s_serv.c: Server related functions. + * + * Copyright (C) 2005 by the past and present ircd coders, and others. + * + * 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 + * + * $Id$ + */ + +#include "stdinc.h" +#ifdef HAVE_LIBCRYPTO +#include <openssl/rsa.h> +#include "rsa.h" +#endif +#include "list.h" +#include "channel.h" +#include "channel_mode.h" +#include "client.h" +#include "dbuf.h" +#include "event.h" +#include "fdlist.h" +#include "hash.h" +#include "irc_string.h" +#include "sprintf_irc.h" +#include "ircd.h" +#include "ircd_defs.h" +#include "s_bsd.h" +#include "numeric.h" +#include "packet.h" +#include "irc_res.h" +#include "conf.h" +#include "s_serv.h" +#include "log.h" +#include "s_misc.h" +#include "s_user.h" +#include "send.h" +#include "memory.h" +#include "channel.h" /* chcap_usage_counts stuff...*/ +#include "parse.h" + +#define MIN_CONN_FREQ 300 + +static dlink_list cap_list = { NULL, NULL, 0 }; +static void server_burst(struct Client *); +static void burst_all(struct Client *); +static void send_tb(struct Client *client_p, struct Channel *chptr); + +static CNCB serv_connect_callback; + +static void burst_members(struct Client *, struct Channel *); + +/* + * write_links_file + * + * inputs - void pointer which is not used + * output - NONE + * side effects - called from an event, write out list of linked servers + * but in no particular order. + */ +void +write_links_file(void* notused) +{ + MessageFileLine *next_mptr = NULL; + MessageFileLine *mptr = NULL; + MessageFileLine *currentMessageLine = NULL; + MessageFileLine *newMessageLine = NULL; + MessageFile *MessageFileptr = &ConfigFileEntry.linksfile; + FILE *file; + char buff[512]; + dlink_node *ptr; + + if ((file = fopen(MessageFileptr->fileName, "w")) == NULL) + return; + + for (mptr = MessageFileptr->contentsOfFile; mptr; mptr = next_mptr) + { + next_mptr = mptr->next; + MyFree(mptr); + } + + MessageFileptr->contentsOfFile = NULL; + + DLINK_FOREACH(ptr, global_serv_list.head) + { + const struct Client *target_p = ptr->data; + + /* skip ourselves, we send ourselves in /links */ + if (IsMe(target_p)) + continue; + + /* skip hidden servers */ + if (IsHidden(target_p)) + continue; + + newMessageLine = MyMalloc(sizeof(MessageFileLine)); + + /* + * Attempt to format the file in such a way it follows the usual links output + * ie "servername uplink :hops info" + * Mostly for aesthetic reasons - makes it look pretty in mIRC ;) + * - madmax + */ + snprintf(newMessageLine->line, sizeof(newMessageLine->line), "%s %s :1 %s", + target_p->name, me.name, target_p->info); + + if (MessageFileptr->contentsOfFile) + { + if (currentMessageLine) + currentMessageLine->next = newMessageLine; + currentMessageLine = newMessageLine; + } + else + { + MessageFileptr->contentsOfFile = newMessageLine; + currentMessageLine = newMessageLine; + } + + snprintf(buff, sizeof(buff), "%s %s :1 %s\n", + target_p->name, me.name, target_p->info); + fputs(buff, file); + } + + fclose(file); +} + +/* hunt_server() + * Do the basic thing in delivering the message (command) + * across the relays to the specific server (server) for + * actions. + * + * Note: The command is a format string and *MUST* be + * of prefixed style (e.g. ":%s COMMAND %s ..."). + * Command can have only max 8 parameters. + * + * server parv[server] is the parameter identifying the + * target server. + * + * *WARNING* + * parv[server] is replaced with the pointer to the + * real servername from the matched client (I'm lazy + * now --msa). + * + * returns: (see #defines) + */ +int +hunt_server(struct Client *client_p, struct Client *source_p, const char *command, + int server, int parc, char *parv[]) +{ + struct Client *target_p = NULL; + struct Client *target_tmp = NULL; + dlink_node *ptr; + int wilds; + + /* Assume it's me, if no server */ + if (parc <= server || EmptyString(parv[server])) + return HUNTED_ISME; + + if (!strcmp(parv[server], me.id) || match(parv[server], me.name)) + return HUNTED_ISME; + + /* These are to pickup matches that would cause the following + * message to go in the wrong direction while doing quick fast + * non-matching lookups. + */ + if (MyClient(source_p)) + target_p = hash_find_client(parv[server]); + else + target_p = find_person(client_p, parv[server]); + + if (target_p) + if (target_p->from == source_p->from && !MyConnect(target_p)) + target_p = NULL; + + if (target_p == NULL && (target_p = hash_find_server(parv[server]))) + if (target_p->from == source_p->from && !MyConnect(target_p)) + target_p = NULL; + + collapse(parv[server]); + wilds = has_wildcards(parv[server]); + + /* Again, if there are no wild cards involved in the server + * name, use the hash lookup + */ + if (target_p == NULL) + { + if (!wilds) + { + if (!(target_p = hash_find_server(parv[server]))) + { + sendto_one(source_p, form_str(ERR_NOSUCHSERVER), + me.name, source_p->name, parv[server]); + return(HUNTED_NOSUCH); + } + } + else + { + DLINK_FOREACH(ptr, global_client_list.head) + { + target_tmp = ptr->data; + + if (match(parv[server], target_tmp->name)) + { + if (target_tmp->from == source_p->from && !MyConnect(target_tmp)) + continue; + target_p = ptr->data; + + if (IsRegistered(target_p) && (target_p != client_p)) + break; + } + } + } + } + + if (target_p != NULL) + { + if(!IsRegistered(target_p)) + { + sendto_one(source_p, form_str(ERR_NOSUCHSERVER), + me.name, source_p->name, parv[server]); + return HUNTED_NOSUCH; + } + + if (IsMe(target_p) || MyClient(target_p)) + return HUNTED_ISME; + + if (!match(target_p->name, parv[server])) + parv[server] = target_p->name; + + /* This is a little kludgy but should work... */ + if (IsClient(source_p) && + ((MyConnect(target_p) && IsCapable(target_p, CAP_TS6)) || + (!MyConnect(target_p) && IsCapable(target_p->from, CAP_TS6)))) + parv[0] = ID(source_p); + + sendto_one(target_p, command, parv[0], + parv[1], parv[2], parv[3], parv[4], + parv[5], parv[6], parv[7], parv[8]); + return(HUNTED_PASS); + } + + sendto_one(source_p, form_str(ERR_NOSUCHSERVER), + me.name, source_p->name, parv[server]); + return(HUNTED_NOSUCH); +} + +/* try_connections() + * + * inputs - void pointer which is not used + * output - NONE + * side effects - + * scan through configuration and try new connections. + * Returns the calendar time when the next call to this + * function should be made latest. (No harm done if this + * is called earlier or later...) + */ +void +try_connections(void *unused) +{ + dlink_node *ptr; + struct ConfItem *conf; + struct AccessItem *aconf; + struct ClassItem *cltmp; + int confrq; + + /* TODO: change this to set active flag to 0 when added to event! --Habeeb */ + if (GlobalSetOptions.autoconn == 0) + return; + + DLINK_FOREACH(ptr, server_items.head) + { + conf = ptr->data; + aconf = map_to_conf(conf); + + /* Also when already connecting! (update holdtimes) --SRB + */ + if (!(aconf->status & CONF_SERVER) || !aconf->port || + !(IsConfAllowAutoConn(aconf))) + continue; + + cltmp = map_to_conf(aconf->class_ptr); + + /* Skip this entry if the use of it is still on hold until + * future. Otherwise handle this entry (and set it on hold + * until next time). Will reset only hold times, if already + * made one successfull connection... [this algorithm is + * a bit fuzzy... -- msa >;) ] + */ + if (aconf->hold > CurrentTime) + continue; + + if (cltmp == NULL) + confrq = DEFAULT_CONNECTFREQUENCY; + else + { + confrq = cltmp->con_freq; + if (confrq < MIN_CONN_FREQ) + confrq = MIN_CONN_FREQ; + } + + aconf->hold = CurrentTime + confrq; + + /* Found a CONNECT config with port specified, scan clients + * and see if this server is already connected? + */ + if (hash_find_server(conf->name) != NULL) + continue; + + if (cltmp->curr_user_count < cltmp->max_total) + { + /* Go to the end of the list, if not already last */ + if (ptr->next != NULL) + { + dlinkDelete(ptr, &server_items); + dlinkAddTail(conf, &conf->node, &server_items); + } + + if (find_servconn_in_progress(conf->name)) + return; + + /* We used to only print this if serv_connect() actually + * succeeded, but since comm_tcp_connect() can call the callback + * immediately if there is an error, we were getting error messages + * in the wrong order. SO, we just print out the activated line, + * and let serv_connect() / serv_connect_callback() print an + * error afterwards if it fails. + * -- adrian + */ + if (ConfigServerHide.hide_server_ips) + sendto_realops_flags(UMODE_ALL, L_ALL, "Connection to %s activated.", + conf->name); + else + sendto_realops_flags(UMODE_ALL, L_ALL, "Connection to %s[%s] activated.", + conf->name, aconf->host); + + serv_connect(aconf, NULL); + /* We connect only one at time... */ + return; + } + } +} + +int +valid_servname(const char *name) +{ + unsigned int length = 0; + unsigned int dots = 0; + const char *p = name; + + for (; *p; ++p) + { + if (!IsServChar(*p)) + return 0; + + ++length; + + if (*p == '.') + ++dots; + } + + return dots != 0 && length <= HOSTLEN; +} + +int +check_server(const char *name, struct Client *client_p) +{ + dlink_node *ptr; + struct ConfItem *conf = NULL; + struct ConfItem *server_conf = NULL; + struct AccessItem *server_aconf = NULL; + struct AccessItem *aconf = NULL; + int error = -1; + + assert(client_p != NULL); + + /* loop through looking for all possible connect items that might work */ + DLINK_FOREACH(ptr, server_items.head) + { + conf = ptr->data; + aconf = map_to_conf(conf); + + if (!match(name, conf->name)) + continue; + + error = -3; + + /* XXX: Fix me for IPv6 */ + /* XXX sockhost is the IPv4 ip as a string */ + if (match(aconf->host, client_p->host) || + match(aconf->host, client_p->sockhost)) + { + error = -2; + + if (!match_conf_password(client_p->localClient->passwd, aconf)) + return -2; + + server_conf = conf; + } + } + + if (server_conf == NULL) + return(error); + + attach_conf(client_p, server_conf); + + server_aconf = map_to_conf(server_conf); + + if (aconf != NULL) + { + struct sockaddr_in *v4; +#ifdef IPV6 + struct sockaddr_in6 *v6; +#endif + switch (aconf->aftype) + { +#ifdef IPV6 + case AF_INET6: + v6 = (struct sockaddr_in6 *)&aconf->addr; + + if (IN6_IS_ADDR_UNSPECIFIED(&v6->sin6_addr)) + memcpy(&aconf->addr, &client_p->localClient->ip, sizeof(struct irc_ssaddr)); + break; +#endif + case AF_INET: + v4 = (struct sockaddr_in *)&aconf->addr; + + if (v4->sin_addr.s_addr == INADDR_NONE) + memcpy(&aconf->addr, &client_p->localClient->ip, sizeof(struct irc_ssaddr)); + break; + } + } + + return(0); +} + +/* add_capability() + * + * inputs - string name of CAPAB + * - int flag of capability + * output - NONE + * side effects - Adds given capability name and bit mask to + * current supported capabilities. This allows + * modules to dynamically add or subtract their capability. + */ +void +add_capability(const char *capab_name, int cap_flag, int add_to_default) +{ + struct Capability *cap = MyMalloc(sizeof(*cap)); + + DupString(cap->name, capab_name); + cap->cap = cap_flag; + dlinkAdd(cap, &cap->node, &cap_list); + + if (add_to_default) + default_server_capabs |= cap_flag; +} + +/* delete_capability() + * + * inputs - string name of CAPAB + * output - NONE + * side effects - delete given capability from ones known. + */ +int +delete_capability(const char *capab_name) +{ + dlink_node *ptr; + dlink_node *next_ptr; + struct Capability *cap; + + DLINK_FOREACH_SAFE(ptr, next_ptr, cap_list.head) + { + cap = ptr->data; + + if (cap->cap != 0) + { + if (irccmp(cap->name, capab_name) == 0) + { + default_server_capabs &= ~(cap->cap); + dlinkDelete(ptr, &cap_list); + MyFree(cap->name); + cap->name = NULL; + MyFree(cap); + } + } + } + + return 0; +} + +/* + * find_capability() + * + * inputs - string name of capab to find + * output - 0 if not found CAPAB otherwise + * side effects - none + */ +int +find_capability(const char *capab) +{ + const dlink_node *ptr = NULL; + + DLINK_FOREACH(ptr, cap_list.head) + { + const struct Capability *cap = ptr->data; + + if (cap->cap && !irccmp(cap->name, capab)) + return cap->cap; + } + + return 0; +} + +/* send_capabilities() + * + * inputs - Client pointer to send to + * - Pointer to AccessItem (for crypt) + * - int flag of capabilities that this server can send + * output - NONE + * side effects - send the CAPAB line to a server -orabidoo + * + */ +void +send_capabilities(struct Client *client_p, struct AccessItem *aconf, + int cap_can_send) +{ + struct Capability *cap=NULL; + char msgbuf[IRCD_BUFSIZE]; + char *t; + int tl; + dlink_node *ptr; + + t = msgbuf; + + DLINK_FOREACH(ptr, cap_list.head) + { + cap = ptr->data; + + if (cap->cap & (cap_can_send|default_server_capabs)) + { + tl = ircsprintf(t, "%s ", cap->name); + t += tl; + } + } + + *(t - 1) = '\0'; + sendto_one(client_p, "CAPAB :%s", msgbuf); +} + +/* sendnick_TS() + * + * inputs - client (server) to send nick towards + * - client to send nick for + * output - NONE + * side effects - NICK message is sent towards given client_p + */ +void +sendnick_TS(struct Client *client_p, struct Client *target_p) +{ + static char ubuf[12]; + + if (!IsClient(target_p)) + return; + + send_umode(NULL, target_p, 0, SEND_UMODES, ubuf); + + if (ubuf[0] == '\0') + { + ubuf[0] = '+'; + ubuf[1] = '\0'; + } + + if (IsCapable(client_p, CAP_SVS)) + { + if (HasID(target_p) && IsCapable(client_p, CAP_TS6)) + sendto_one(client_p, ":%s UID %s %d %lu %s %s %s %s %s %s :%s", + target_p->servptr->id, + target_p->name, target_p->hopcount + 1, + (unsigned long) target_p->tsinfo, + ubuf, target_p->username, target_p->host, + (MyClient(target_p) && IsIPSpoof(target_p)) ? + "0" : target_p->sockhost, target_p->id, + target_p->svid, target_p->info); + else + sendto_one(client_p, "NICK %s %d %lu %s %s %s %s %s :%s", + target_p->name, target_p->hopcount + 1, + (unsigned long) target_p->tsinfo, + ubuf, target_p->username, target_p->host, + target_p->servptr->name, target_p->svid, + target_p->info); + } + else + { + if (HasID(target_p) && IsCapable(client_p, CAP_TS6)) + sendto_one(client_p, ":%s UID %s %d %lu %s %s %s %s %s :%s", + target_p->servptr->id, + target_p->name, target_p->hopcount + 1, + (unsigned long) target_p->tsinfo, + ubuf, target_p->username, target_p->host, + (MyClient(target_p) && IsIPSpoof(target_p)) ? + "0" : target_p->sockhost, target_p->id, target_p->info); + else + sendto_one(client_p, "NICK %s %d %lu %s %s %s %s :%s", + target_p->name, target_p->hopcount + 1, + (unsigned long) target_p->tsinfo, + ubuf, target_p->username, target_p->host, + target_p->servptr->name, target_p->info); + } + + if (target_p->away[0]) + sendto_one(client_p, ":%s AWAY :%s", ID_or_name(target_p, client_p), + target_p->away); + +} + +/* + * show_capabilities - show current server capabilities + * + * inputs - pointer to a struct Client + * output - pointer to static string + * side effects - build up string representing capabilities of server listed + */ +const char * +show_capabilities(struct Client *target_p) +{ + static char msgbuf[IRCD_BUFSIZE]; + char *t = msgbuf; + dlink_node *ptr; + + t += ircsprintf(msgbuf, "TS "); + + DLINK_FOREACH(ptr, cap_list.head) + { + const struct Capability *cap = ptr->data; + + if (IsCapable(target_p, cap->cap)) + t += ircsprintf(t, "%s ", cap->name); + } + + *(t - 1) = '\0'; + return msgbuf; +} + +/* make_server() + * + * inputs - pointer to client struct + * output - pointer to struct Server + * side effects - add's an Server information block to a client + * if it was not previously allocated. + */ +struct Server * +make_server(struct Client *client_p) +{ + if (client_p->serv == NULL) + client_p->serv = MyMalloc(sizeof(struct Server)); + + return client_p->serv; +} + +/* server_estab() + * + * inputs - pointer to a struct Client + * output - + * side effects - + */ +void +server_estab(struct Client *client_p) +{ + struct Client *target_p; + struct ConfItem *conf; + struct AccessItem *aconf=NULL; + char *host; + const char *inpath; + static char inpath_ip[HOSTLEN * 2 + USERLEN + 6]; + dlink_node *ptr; +#ifdef HAVE_LIBCRYPTO + const COMP_METHOD *compression = NULL, *expansion = NULL; +#endif + + assert(client_p != NULL); + + strlcpy(inpath_ip, get_client_name(client_p, SHOW_IP), sizeof(inpath_ip)); + + inpath = get_client_name(client_p, MASK_IP); /* "refresh" inpath with host */ + host = client_p->name; + + if ((conf = find_conf_name(&client_p->localClient->confs, host, SERVER_TYPE)) + == NULL) + { + /* This shouldn't happen, better tell the ops... -A1kmm */ + sendto_realops_flags(UMODE_ALL, L_ALL, "Warning: Lost connect{} block " + "for server %s(this shouldn't happen)!", host); + exit_client(client_p, &me, "Lost connect{} block!"); + return; + } + + MyFree(client_p->localClient->passwd); + client_p->localClient->passwd = NULL; + + /* Its got identd, since its a server */ + SetGotId(client_p); + + /* If there is something in the serv_list, it might be this + * connecting server.. + */ + if (!ServerInfo.hub && serv_list.head) + { + if (client_p != serv_list.head->data || serv_list.head->next) + { + ++ServerStats.is_ref; + sendto_one(client_p, "ERROR :I'm a leaf not a hub"); + exit_client(client_p, &me, "I'm a leaf"); + return; + } + } + + aconf = map_to_conf(conf); + + if (IsUnknown(client_p)) + { + /* jdc -- 1. Use EmptyString(), not [0] index reference. + * 2. Check aconf->spasswd, not aconf->passwd. + */ + if (!EmptyString(aconf->spasswd)) + sendto_one(client_p, "PASS %s TS %d %s", + aconf->spasswd, TS_CURRENT, me.id); + + /* Pass my info to the new server + * + * Pass on ZIP if supported + * Pass on TB if supported. + * - Dianora + */ + + send_capabilities(client_p, aconf, 0); + + sendto_one(client_p, "SERVER %s 1 :%s%s", + me.name, ConfigServerHide.hidden ? "(H) " : "", me.info); + } + + sendto_one(client_p, "SVINFO %d %d 0 :%lu", TS_CURRENT, TS_MIN, + (unsigned long)CurrentTime); + + /* assumption here is if they passed the correct TS version, they also passed an SID */ + if (IsCapable(client_p, CAP_TS6)) + hash_add_id(client_p); + + /* XXX Does this ever happen? I don't think so -db */ + detach_conf(client_p, OPER_TYPE); + + /* *WARNING* + ** In the following code in place of plain server's + ** name we send what is returned by get_client_name + ** which may add the "sockhost" after the name. It's + ** *very* *important* that there is a SPACE between + ** the name and sockhost (if present). The receiving + ** server will start the information field from this + ** first blank and thus puts the sockhost into info. + ** ...a bit tricky, but you have been warned, besides + ** code is more neat this way... --msa + */ + client_p->servptr = &me; + + if (IsClosing(client_p)) + return; + + SetServer(client_p); + + /* Update the capability combination usage counts. -A1kmm */ + set_chcap_usage_counts(client_p); + + /* Some day, all these lists will be consolidated *sigh* */ + dlinkAdd(client_p, &client_p->lnode, &me.serv->server_list); + + assert(dlinkFind(&unknown_list, client_p)); + + dlink_move_node(&client_p->localClient->lclient_node, + &unknown_list, &serv_list); + + Count.myserver++; + + dlinkAdd(client_p, make_dlink_node(), &global_serv_list); + hash_add_client(client_p); + + /* doesnt duplicate client_p->serv if allocated this struct already */ + make_server(client_p); + + /* fixing eob timings.. -gnp */ + client_p->localClient->firsttime = CurrentTime; + + if (find_matching_name_conf(SERVICE_TYPE, client_p->name, NULL, NULL, 0)) + AddFlag(client_p, FLAGS_SERVICE); + + /* Show the real host/IP to admins */ +#ifdef HAVE_LIBCRYPTO + if (client_p->localClient->fd.ssl) + { + compression = SSL_get_current_compression(client_p->localClient->fd.ssl); + expansion = SSL_get_current_expansion(client_p->localClient->fd.ssl); + + sendto_realops_flags(UMODE_ALL, L_ADMIN, + "Link with %s established: [SSL: %s, Compression/Expansion method: %s/%s] (Capabilities: %s)", + inpath_ip, ssl_get_cipher(client_p->localClient->fd.ssl), + compression ? SSL_COMP_get_name(compression) : "NONE", + expansion ? SSL_COMP_get_name(expansion) : "NONE", + show_capabilities(client_p)); + /* Now show the masked hostname/IP to opers */ + sendto_realops_flags(UMODE_ALL, L_OPER, + "Link with %s established: [SSL: %s, Compression/Expansion method: %s/%s] (Capabilities: %s)", + inpath, ssl_get_cipher(client_p->localClient->fd.ssl), + compression ? SSL_COMP_get_name(compression) : "NONE", + expansion ? SSL_COMP_get_name(expansion) : "NONE", + show_capabilities(client_p)); + ilog(LOG_TYPE_IRCD, "Link with %s established: [SSL: %s, Compression/Expansion method: %s/%s] (Capabilities: %s)", + inpath_ip, ssl_get_cipher(client_p->localClient->fd.ssl), + compression ? SSL_COMP_get_name(compression) : "NONE", + expansion ? SSL_COMP_get_name(expansion) : "NONE", + show_capabilities(client_p)); + } + else +#endif + { + sendto_realops_flags(UMODE_ALL, L_ADMIN, + "Link with %s established: (Capabilities: %s)", + inpath_ip,show_capabilities(client_p)); + /* Now show the masked hostname/IP to opers */ + sendto_realops_flags(UMODE_ALL, L_OPER, + "Link with %s established: (Capabilities: %s)", + inpath,show_capabilities(client_p)); + ilog(LOG_TYPE_IRCD, "Link with %s established: (Capabilities: %s)", + inpath_ip, show_capabilities(client_p)); + } + + fd_note(&client_p->localClient->fd, "Server: %s", client_p->name); + + /* Old sendto_serv_but_one() call removed because we now + ** need to send different names to different servers + ** (domain name matching) Send new server to other servers. + */ + DLINK_FOREACH(ptr, serv_list.head) + { + target_p = ptr->data; + + if (target_p == client_p) + continue; + + if (IsCapable(target_p, CAP_TS6) && HasID(client_p)) + sendto_one(target_p, ":%s SID %s 2 %s :%s%s", + me.id, client_p->name, client_p->id, + IsHidden(client_p) ? "(H) " : "", + client_p->info); + else + sendto_one(target_p,":%s SERVER %s 2 :%s%s", + me.name, client_p->name, + IsHidden(client_p) ? "(H) " : "", + client_p->info); + } + + /* Pass on my client information to the new server + ** + ** First, pass only servers (idea is that if the link gets + ** cancelled beacause the server was already there, + ** there are no NICK's to be cancelled...). Of course, + ** if cancellation occurs, all this info is sent anyway, + ** and I guess the link dies when a read is attempted...? --msa + ** + ** Note: Link cancellation to occur at this point means + ** that at least two servers from my fragment are building + ** up connection this other fragment at the same time, it's + ** a race condition, not the normal way of operation... + ** + ** ALSO NOTE: using the get_client_name for server names-- + ** see previous *WARNING*!!! (Also, original inpath + ** is destroyed...) + */ + + DLINK_FOREACH_PREV(ptr, global_serv_list.tail) + { + target_p = ptr->data; + + /* target_p->from == target_p for target_p == client_p */ + if (IsMe(target_p) || target_p->from == client_p) + continue; + + if (IsCapable(client_p, CAP_TS6)) + { + if (HasID(target_p)) + sendto_one(client_p, ":%s SID %s %d %s :%s%s", + ID(target_p->servptr), target_p->name, target_p->hopcount+1, + target_p->id, IsHidden(target_p) ? "(H) " : "", + target_p->info); + else /* introducing non-ts6 server */ + sendto_one(client_p, ":%s SERVER %s %d :%s%s", + ID(target_p->servptr), target_p->name, target_p->hopcount+1, + IsHidden(target_p) ? "(H) " : "", target_p->info); + } + else + sendto_one(client_p, ":%s SERVER %s %d :%s%s", + target_p->servptr->name, target_p->name, target_p->hopcount+1, + IsHidden(target_p) ? "(H) " : "", target_p->info); + } + + server_burst(client_p); +} + +/* server_burst() + * + * inputs - struct Client pointer server + * - + * output - none + * side effects - send a server burst + * bugs - still too long + */ +static void +server_burst(struct Client *client_p) +{ + /* Send it in the shortened format with the TS, if + ** it's a TS server; walk the list of channels, sending + ** all the nicks that haven't been sent yet for each + ** channel, then send the channel itself -- it's less + ** obvious than sending all nicks first, but on the + ** receiving side memory will be allocated more nicely + ** saving a few seconds in the handling of a split + ** -orabidoo + */ + + burst_all(client_p); + + /* EOB stuff is now in burst_all */ + /* Always send a PING after connect burst is done */ + sendto_one(client_p, "PING :%s", ID_or_name(&me, client_p)); +} + +/* burst_all() + * + * inputs - pointer to server to send burst to + * output - NONE + * side effects - complete burst of channels/nicks is sent to client_p + */ +static void +burst_all(struct Client *client_p) +{ + dlink_node *ptr = NULL; + + DLINK_FOREACH(ptr, global_channel_list.head) + { + struct Channel *chptr = ptr->data; + + if (dlink_list_length(&chptr->members) != 0) + { + burst_members(client_p, chptr); + send_channel_modes(client_p, chptr); + + if (IsCapable(client_p, CAP_TBURST)) + send_tb(client_p, chptr); + } + } + + /* also send out those that are not on any channel + */ + DLINK_FOREACH(ptr, global_client_list.head) + { + struct Client *target_p = ptr->data; + + if (!HasFlag(target_p, FLAGS_BURSTED) && target_p->from != client_p) + sendnick_TS(client_p, target_p); + + DelFlag(target_p, FLAGS_BURSTED); + } + + /* We send the time we started the burst, and let the remote host determine an EOB time, + ** as otherwise we end up sending a EOB of 0 Sending here means it gets sent last -- fl + */ + /* Its simpler to just send EOB and use the time its been connected.. --fl_ */ + if (IsCapable(client_p, CAP_EOB)) + sendto_one(client_p, ":%s EOB", ID_or_name(&me, client_p)); +} + +/* + * send_tb + * + * inputs - pointer to Client + * - pointer to channel + * output - NONE + * side effects - Called on a server burst when + * server is CAP_TBURST capable + */ +static void +send_tb(struct Client *client_p, struct Channel *chptr) +{ + /* + * We may also send an empty topic here, but only if topic_time isn't 0, + * i.e. if we had a topic that got unset. This is required for syncing + * topics properly. + * + * Imagine the following scenario: Our downlink introduces a channel + * to us with a TS that is equal to ours, but the channel topic on + * their side got unset while the servers were in splitmode, which means + * their 'topic' is newer. They simply wanted to unset it, so we have to + * deal with it in a more sophisticated fashion instead of just resetting + * it to their old topic they had before. Read m_tburst.c:ms_tburst + * for further information -Michael + */ + if (chptr->topic_time != 0) + sendto_one(client_p, ":%s TBURST %lu %s %lu %s :%s", + ID_or_name(&me, client_p), + (unsigned long)chptr->channelts, chptr->chname, + (unsigned long)chptr->topic_time, + chptr->topic_info, + chptr->topic); +} + +/* burst_members() + * + * inputs - pointer to server to send members to + * - dlink_list pointer to membership list to send + * output - NONE + * side effects - + */ +static void +burst_members(struct Client *client_p, struct Channel *chptr) +{ + struct Client *target_p; + struct Membership *ms; + dlink_node *ptr; + + DLINK_FOREACH(ptr, chptr->members.head) + { + ms = ptr->data; + target_p = ms->client_p; + + if (!HasFlag(target_p, FLAGS_BURSTED)) + { + AddFlag(target_p, FLAGS_BURSTED); + + if (target_p->from != client_p) + sendnick_TS(client_p, target_p); + } + } +} + +/* New server connection code + * Based upon the stuff floating about in s_bsd.c + * -- adrian + */ + +/* serv_connect() - initiate a server connection + * + * inputs - pointer to conf + * - pointer to client doing the connect + * output - + * side effects - + * + * This code initiates a connection to a server. It first checks to make + * sure the given server exists. If this is the case, it creates a socket, + * creates a client, saves the socket information in the client, and + * initiates a connection to the server through comm_connect_tcp(). The + * completion of this goes through serv_completed_connection(). + * + * We return 1 if the connection is attempted, since we don't know whether + * it suceeded or not, and 0 if it fails in here somewhere. + */ +int +serv_connect(struct AccessItem *aconf, struct Client *by) +{ + struct ConfItem *conf; + struct Client *client_p; + char buf[HOSTIPLEN + 1]; + + /* conversion structs */ + struct sockaddr_in *v4; + /* Make sure aconf is useful */ + assert(aconf != NULL); + + /* XXX should be passing struct ConfItem in the first place */ + conf = unmap_conf_item(aconf); + + /* log */ + getnameinfo((struct sockaddr *)&aconf->addr, aconf->addr.ss_len, + buf, sizeof(buf), NULL, 0, NI_NUMERICHOST); + ilog(LOG_TYPE_IRCD, "Connect to %s[%s] @%s", conf->name, aconf->host, + buf); + + /* Still processing a DNS lookup? -> exit */ + if (aconf->dns_pending) + { + sendto_realops_flags(UMODE_ALL, L_ALL, + "Error connecting to %s: DNS lookup for connect{} in progress.", + conf->name); + return (0); + } + + if (aconf->dns_failed) + { + sendto_realops_flags(UMODE_ALL, L_ALL, + "Error connecting to %s: DNS lookup for connect{} failed.", + conf->name); + return (0); + } + + /* Make sure this server isn't already connected + * Note: aconf should ALWAYS be a valid C: line + */ + if ((client_p = hash_find_server(conf->name)) != NULL) + { + sendto_realops_flags(UMODE_ALL, L_ADMIN, + "Server %s already present from %s", + conf->name, get_client_name(client_p, SHOW_IP)); + sendto_realops_flags(UMODE_ALL, L_OPER, + "Server %s already present from %s", + conf->name, get_client_name(client_p, MASK_IP)); + if (by && IsClient(by) && !MyClient(by)) + sendto_one(by, ":%s NOTICE %s :Server %s already present from %s", + me.name, by->name, conf->name, + get_client_name(client_p, MASK_IP)); + return (0); + } + + /* Create a local client */ + client_p = make_client(NULL); + + /* Copy in the server, hostname, fd */ + strlcpy(client_p->name, conf->name, sizeof(client_p->name)); + strlcpy(client_p->host, aconf->host, sizeof(client_p->host)); + + /* We already converted the ip once, so lets use it - stu */ + strlcpy(client_p->sockhost, buf, sizeof(client_p->sockhost)); + + /* create a socket for the server connection */ + if (comm_open(&client_p->localClient->fd, aconf->addr.ss.ss_family, + SOCK_STREAM, 0, NULL) < 0) + { + /* Eek, failure to create the socket */ + report_error(L_ALL, + "opening stream socket to %s: %s", conf->name, errno); + SetDead(client_p); + exit_client(client_p, &me, "Connection failed"); + return (0); + } + + /* servernames are always guaranteed under HOSTLEN chars */ + fd_note(&client_p->localClient->fd, "Server: %s", conf->name); + + /* Attach config entries to client here rather than in + * serv_connect_callback(). This to avoid null pointer references. + */ + if (!attach_connect_block(client_p, conf->name, aconf->host)) + { + sendto_realops_flags(UMODE_ALL, L_ALL, + "Host %s is not enabled for connecting:no C/N-line", + conf->name); + if (by && IsClient(by) && !MyClient(by)) + sendto_one(by, ":%s NOTICE %s :Connect to host %s failed.", + me.name, by->name, client_p->name); + SetDead(client_p); + exit_client(client_p, client_p, "Connection failed"); + return (0); + } + + /* at this point we have a connection in progress and C/N lines + * attached to the client, the socket info should be saved in the + * client and it should either be resolved or have a valid address. + * + * The socket has been connected or connect is in progress. + */ + make_server(client_p); + + if (by && IsClient(by)) + strlcpy(client_p->serv->by, by->name, sizeof(client_p->serv->by)); + else + strlcpy(client_p->serv->by, "AutoConn.", sizeof(client_p->serv->by)); + + SetConnecting(client_p); + dlinkAdd(client_p, &client_p->node, &global_client_list); + /* from def_fam */ + client_p->localClient->aftype = aconf->aftype; + + /* Now, initiate the connection */ + /* XXX assume that a non 0 type means a specific bind address + * for this connect. + */ + switch (aconf->aftype) + { + case AF_INET: + v4 = (struct sockaddr_in*)&aconf->bind; + if (v4->sin_addr.s_addr != 0) + { + struct irc_ssaddr ipn; + memset(&ipn, 0, sizeof(struct irc_ssaddr)); + ipn.ss.ss_family = AF_INET; + ipn.ss_port = 0; + memcpy(&ipn, &aconf->bind, sizeof(struct irc_ssaddr)); + comm_connect_tcp(&client_p->localClient->fd, aconf->host, aconf->port, + (struct sockaddr *)&ipn, ipn.ss_len, + serv_connect_callback, client_p, aconf->aftype, + CONNECTTIMEOUT); + } + else if (ServerInfo.specific_ipv4_vhost) + { + struct irc_ssaddr ipn; + memset(&ipn, 0, sizeof(struct irc_ssaddr)); + ipn.ss.ss_family = AF_INET; + ipn.ss_port = 0; + memcpy(&ipn, &ServerInfo.ip, sizeof(struct irc_ssaddr)); + comm_connect_tcp(&client_p->localClient->fd, aconf->host, aconf->port, + (struct sockaddr *)&ipn, ipn.ss_len, + serv_connect_callback, client_p, aconf->aftype, + CONNECTTIMEOUT); + } + else + comm_connect_tcp(&client_p->localClient->fd, aconf->host, aconf->port, + NULL, 0, serv_connect_callback, client_p, aconf->aftype, + CONNECTTIMEOUT); + break; +#ifdef IPV6 + case AF_INET6: + { + struct irc_ssaddr ipn; + struct sockaddr_in6 *v6; + struct sockaddr_in6 *v6conf; + + memset(&ipn, 0, sizeof(struct irc_ssaddr)); + v6conf = (struct sockaddr_in6 *)&aconf->bind; + v6 = (struct sockaddr_in6 *)&ipn; + + if (memcmp(&v6conf->sin6_addr, &v6->sin6_addr, + sizeof(struct in6_addr)) != 0) + { + memcpy(&ipn, &aconf->bind, sizeof(struct irc_ssaddr)); + ipn.ss.ss_family = AF_INET6; + ipn.ss_port = 0; + comm_connect_tcp(&client_p->localClient->fd, + aconf->host, aconf->port, + (struct sockaddr *)&ipn, ipn.ss_len, + serv_connect_callback, client_p, + aconf->aftype, CONNECTTIMEOUT); + } + else if (ServerInfo.specific_ipv6_vhost) + { + memcpy(&ipn, &ServerInfo.ip6, sizeof(struct irc_ssaddr)); + ipn.ss.ss_family = AF_INET6; + ipn.ss_port = 0; + comm_connect_tcp(&client_p->localClient->fd, + aconf->host, aconf->port, + (struct sockaddr *)&ipn, ipn.ss_len, + serv_connect_callback, client_p, + aconf->aftype, CONNECTTIMEOUT); + } + else + comm_connect_tcp(&client_p->localClient->fd, + aconf->host, aconf->port, + NULL, 0, serv_connect_callback, client_p, + aconf->aftype, CONNECTTIMEOUT); + } +#endif + } + return (1); +} + +#ifdef HAVE_LIBCRYPTO +static void +finish_ssl_server_handshake(struct Client *client_p) +{ + struct ConfItem *conf=NULL; + struct AccessItem *aconf=NULL; + + conf = find_conf_name(&client_p->localClient->confs, + client_p->name, SERVER_TYPE); + if (conf == NULL) + { + sendto_realops_flags(UMODE_ALL, L_ADMIN, + "Lost connect{} block for %s", get_client_name(client_p, HIDE_IP)); + sendto_realops_flags(UMODE_ALL, L_OPER, + "Lost connect{} block for %s", get_client_name(client_p, MASK_IP)); + + exit_client(client_p, &me, "Lost connect{} block"); + return; + } + + aconf = map_to_conf(conf); + + /* jdc -- Check and send spasswd, not passwd. */ + if (!EmptyString(aconf->spasswd)) + sendto_one(client_p, "PASS %s TS %d %s", + aconf->spasswd, TS_CURRENT, me.id); + + send_capabilities(client_p, aconf, 0); + + sendto_one(client_p, "SERVER %s 1 :%s%s", + me.name, ConfigServerHide.hidden ? "(H) " : "", + me.info); + + /* If we've been marked dead because a send failed, just exit + * here now and save everyone the trouble of us ever existing. + */ + if (IsDead(client_p)) + { + sendto_realops_flags(UMODE_ALL, L_ADMIN, + "%s[%s] went dead during handshake", + client_p->name, + client_p->host); + sendto_realops_flags(UMODE_ALL, L_OPER, + "%s went dead during handshake", client_p->name); + return; + } + + /* don't move to serv_list yet -- we haven't sent a burst! */ + /* If we get here, we're ok, so lets start reading some data */ + comm_setselect(&client_p->localClient->fd, COMM_SELECT_READ, read_packet, client_p, 0); +} + +static void +ssl_server_handshake(fde_t *fd, struct Client *client_p) +{ + int ret; + int err; + + ret = SSL_connect(client_p->localClient->fd.ssl); + + if (ret <= 0) + { + switch ((err = SSL_get_error(client_p->localClient->fd.ssl, ret))) + { + case SSL_ERROR_WANT_WRITE: + comm_setselect(&client_p->localClient->fd, COMM_SELECT_WRITE, + (PF *)ssl_server_handshake, client_p, 0); + return; + case SSL_ERROR_WANT_READ: + comm_setselect(&client_p->localClient->fd, COMM_SELECT_READ, + (PF *)ssl_server_handshake, client_p, 0); + return; + default: + { + const char *sslerr = ERR_error_string(ERR_get_error(), NULL); + sendto_realops_flags(UMODE_ALL, L_ALL, + "Error connecting to %s: %s", client_p->name, + sslerr ? sslerr : "unknown SSL error"); + exit_client(client_p, client_p, "Error during SSL handshake"); + return; + } + } + } + + finish_ssl_server_handshake(client_p); +} + +static void +ssl_connect_init(struct Client *client_p, struct AccessItem *aconf, fde_t *fd) +{ + if ((client_p->localClient->fd.ssl = SSL_new(ServerInfo.client_ctx)) == NULL) + { + ilog(LOG_TYPE_IRCD, "SSL_new() ERROR! -- %s", + ERR_error_string(ERR_get_error(), NULL)); + SetDead(client_p); + exit_client(client_p, client_p, "SSL_new failed"); + return; + } + + SSL_set_fd(fd->ssl, fd->fd); + + if (!EmptyString(aconf->cipher_list)) + SSL_set_cipher_list(client_p->localClient->fd.ssl, aconf->cipher_list); + + ssl_server_handshake(NULL, client_p); +} +#endif + +/* serv_connect_callback() - complete a server connection. + * + * This routine is called after the server connection attempt has + * completed. If unsucessful, an error is sent to ops and the client + * is closed. If sucessful, it goes through the initialisation/check + * procedures, the capabilities are sent, and the socket is then + * marked for reading. + */ +static void +serv_connect_callback(fde_t *fd, int status, void *data) +{ + struct Client *client_p = data; + struct ConfItem *conf=NULL; + struct AccessItem *aconf=NULL; + + /* First, make sure its a real client! */ + assert(client_p != NULL); + assert(&client_p->localClient->fd == fd); + + /* Next, for backward purposes, record the ip of the server */ + memcpy(&client_p->localClient->ip, &fd->connect.hostaddr, + sizeof(struct irc_ssaddr)); + /* Check the status */ + if (status != COMM_OK) + { + /* We have an error, so report it and quit + * Admins get to see any IP, mere opers don't *sigh* + */ + if (ConfigServerHide.hide_server_ips) + sendto_realops_flags(UMODE_ALL, L_ADMIN, + "Error connecting to %s: %s", + client_p->name, comm_errstr(status)); + else + sendto_realops_flags(UMODE_ALL, L_ADMIN, + "Error connecting to %s[%s]: %s", client_p->name, + client_p->host, comm_errstr(status)); + + sendto_realops_flags(UMODE_ALL, L_OPER, + "Error connecting to %s: %s", + client_p->name, comm_errstr(status)); + + /* If a fd goes bad, call dead_link() the socket is no + * longer valid for reading or writing. + */ + dead_link_on_write(client_p, 0); + return; + } + + /* COMM_OK, so continue the connection procedure */ + /* Get the C/N lines */ + conf = find_conf_name(&client_p->localClient->confs, + client_p->name, SERVER_TYPE); + if (conf == NULL) + { + sendto_realops_flags(UMODE_ALL, L_ADMIN, + "Lost connect{} block for %s", get_client_name(client_p, HIDE_IP)); + sendto_realops_flags(UMODE_ALL, L_OPER, + "Lost connect{} block for %s", get_client_name(client_p, MASK_IP)); + + exit_client(client_p, &me, "Lost connect{} block"); + return; + } + + aconf = map_to_conf(conf); + /* Next, send the initial handshake */ + SetHandshake(client_p); + +#ifdef HAVE_LIBCRYPTO + if (IsConfSSL(aconf)) + { + ssl_connect_init(client_p, aconf, fd); + return; + } +#endif + + /* jdc -- Check and send spasswd, not passwd. */ + if (!EmptyString(aconf->spasswd)) + sendto_one(client_p, "PASS %s TS %d %s", + aconf->spasswd, TS_CURRENT, me.id); + + send_capabilities(client_p, aconf, 0); + + sendto_one(client_p, "SERVER %s 1 :%s%s", + me.name, ConfigServerHide.hidden ? "(H) " : "", + me.info); + + /* If we've been marked dead because a send failed, just exit + * here now and save everyone the trouble of us ever existing. + */ + if (IsDead(client_p)) + { + sendto_realops_flags(UMODE_ALL, L_ADMIN, + "%s[%s] went dead during handshake", + client_p->name, + client_p->host); + sendto_realops_flags(UMODE_ALL, L_OPER, + "%s went dead during handshake", client_p->name); + return; + } + + /* don't move to serv_list yet -- we haven't sent a burst! */ + /* If we get here, we're ok, so lets start reading some data */ + comm_setselect(fd, COMM_SELECT_READ, read_packet, client_p, 0); +} + +struct Client * +find_servconn_in_progress(const char *name) +{ + dlink_node *ptr; + struct Client *cptr; + + DLINK_FOREACH(ptr, unknown_list.head) + { + cptr = ptr->data; + + if (cptr && cptr->name[0]) + if (match(name, cptr->name)) + return cptr; + } + + return NULL; +} diff --git a/src/s_user.c b/src/s_user.c new file mode 100644 index 0000000..1973bfa --- /dev/null +++ b/src/s_user.c @@ -0,0 +1,1484 @@ +/* + * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd). + * s_user.c: User related functions. + * + * Copyright (C) 2002 by the past and present ircd coders, and others. + * + * 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 + * + * $Id$ + */ + +#include "stdinc.h" +#include "list.h" +#include "s_user.h" +#include "s_misc.h" +#include "channel.h" +#include "channel_mode.h" +#include "client.h" +#include "fdlist.h" +#include "hash.h" +#include "irc_string.h" +#include "sprintf_irc.h" +#include "s_bsd.h" +#include "ircd.h" +#include "listener.h" +#include "motd.h" +#include "numeric.h" +#include "conf.h" +#include "log.h" +#include "s_serv.h" +#include "send.h" +#include "supported.h" +#include "whowas.h" +#include "memory.h" +#include "packet.h" +#include "rng_mt.h" +#include "userhost.h" +#include "hook.h" +#include "s_misc.h" +#include "parse.h" +#include "watch.h" + + +struct Callback *entering_umode_cb = NULL; +struct Callback *umode_cb = NULL; + +static char umode_buffer[IRCD_BUFSIZE]; + +static void user_welcome(struct Client *); +static void report_and_set_user_flags(struct Client *, const struct AccessItem *); +static int check_xline(struct Client *); +static void introduce_client(struct Client *); +static const char *uid_get(void); + +/* Used for building up the isupport string, + * used with init_isupport, add_isupport, delete_isupport + */ + +struct Isupport +{ + dlink_node node; + char *name; + char *options; + int number; +}; + +static dlink_list support_list = { NULL, NULL, 0 }; +MessageFile *isupportFile; + +/* memory is cheap. map 0-255 to equivalent mode */ +unsigned int user_modes[256] = +{ + /* 0x00 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x0F */ + /* 0x10 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x1F */ + /* 0x20 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x2F */ + /* 0x30 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x3F */ + 0, /* @ */ + 0, /* A */ + 0, /* B */ + UMODE_CCONN_FULL, /* C */ + UMODE_DEAF, /* D */ + 0, /* E */ + 0, /* F */ + UMODE_SOFTCALLERID, /* G */ + UMODE_HIDDEN, /* H */ + 0, /* I */ + 0, /* J */ + 0, /* K */ + 0, /* L */ + 0, /* M */ + 0, /* N */ + 0, /* O */ + 0, /* P */ + 0, /* Q */ + UMODE_REGONLY, /* R */ + 0, /* S */ + 0, /* T */ + 0, /* U */ + 0, /* V */ + 0, /* W */ + 0, /* X */ + 0, /* Y */ + 0, /* Z 0x5A */ + 0, 0, 0, 0, 0, /* 0x5F */ + 0, /* 0x60 */ + UMODE_ADMIN, /* a */ + UMODE_BOTS, /* b */ + UMODE_CCONN, /* c */ + UMODE_DEBUG, /* d */ + 0, /* e */ + UMODE_FULL, /* f */ + UMODE_CALLERID, /* g */ + 0, /* h */ + UMODE_INVISIBLE, /* i */ + UMODE_REJ, /* j */ + UMODE_SKILL, /* k */ + UMODE_LOCOPS, /* l */ + 0, /* m */ + UMODE_NCHANGE, /* n */ + UMODE_OPER, /* o */ + 0, /* p */ + 0, /* q */ + UMODE_REGISTERED, /* r */ + UMODE_SERVNOTICE, /* s */ + 0, /* t */ + UMODE_UNAUTH, /* u */ + 0, /* v */ + UMODE_WALLOP, /* w */ + UMODE_EXTERNAL, /* x */ + UMODE_SPY, /* y */ + UMODE_OPERWALL, /* z 0x7A */ + 0,0,0,0,0, /* 0x7B - 0x7F */ + + /* 0x80 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x8F */ + /* 0x90 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x9F */ + /* 0xA0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xAF */ + /* 0xB0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xBF */ + /* 0xC0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xCF */ + /* 0xD0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xDF */ + /* 0xE0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xEF */ + /* 0xF0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 /* 0xFF */ +}; + +void +assemble_umode_buffer(void) +{ + unsigned int idx = 0; + char *umode_buffer_ptr = umode_buffer; + + for (; idx < (sizeof(user_modes) / sizeof(user_modes[0])); ++idx) + if (user_modes[idx]) + *umode_buffer_ptr++ = idx; + + *umode_buffer_ptr = '\0'; +} + +/* show_lusers() + * + * inputs - pointer to client + * output - NONE + * side effects - display to client user counts etc. + */ +void +show_lusers(struct Client *source_p) +{ + const char *from, *to; + + if (!MyConnect(source_p) && IsCapable(source_p->from, CAP_TS6) && HasID(source_p)) + { + from = me.id; + to = source_p->id; + } + else + { + from = me.name; + to = source_p->name; + } + + if (!ConfigServerHide.hide_servers || HasUMode(source_p, UMODE_OPER)) + sendto_one(source_p, form_str(RPL_LUSERCLIENT), + from, to, (Count.total-Count.invisi), + Count.invisi, dlink_list_length(&global_serv_list)); + else + sendto_one(source_p, form_str(RPL_LUSERCLIENT), from, to, + (Count.total-Count.invisi), Count.invisi, 1); + + if (Count.oper > 0) + sendto_one(source_p, form_str(RPL_LUSEROP), + from, to, Count.oper); + + if (dlink_list_length(&unknown_list) > 0) + sendto_one(source_p, form_str(RPL_LUSERUNKNOWN), + from, to, dlink_list_length(&unknown_list)); + + if (dlink_list_length(&global_channel_list) > 0) + sendto_one(source_p, form_str(RPL_LUSERCHANNELS), + from, to, dlink_list_length(&global_channel_list)); + + if (!ConfigServerHide.hide_servers || HasUMode(source_p, UMODE_OPER)) + { + sendto_one(source_p, form_str(RPL_LUSERME), + from, to, Count.local, Count.myserver); + sendto_one(source_p, form_str(RPL_LOCALUSERS), + from, to, Count.local, Count.max_loc, + Count.local, Count.max_loc); + } + else + { + sendto_one(source_p, form_str(RPL_LUSERME), + from, to, Count.total, 0); + sendto_one(source_p, form_str(RPL_LOCALUSERS), + from, to, Count.total, Count.max_tot, + Count.total, Count.max_tot); + } + + sendto_one(source_p, form_str(RPL_GLOBALUSERS), + from, to, Count.total, Count.max_tot, + Count.total, Count.max_tot); + + if (!ConfigServerHide.hide_servers || HasUMode(source_p, UMODE_OPER)) + sendto_one(source_p, form_str(RPL_STATSCONN), from, to, + Count.max_loc_con, Count.max_loc_cli, Count.totalrestartcount); + + if (Count.local > Count.max_loc_cli) + Count.max_loc_cli = Count.local; + + if ((Count.local + Count.myserver) > Count.max_loc_con) + Count.max_loc_con = Count.local + Count.myserver; +} + +/* show_isupport() + * + * inputs - pointer to client + * output - NONE + * side effects - display to client what we support (for them) + */ +void +show_isupport(struct Client *source_p) +{ + send_message_file(source_p, isupportFile); +} + +/* +** register_local_user +** This function is called when both NICK and USER messages +** have been accepted for the client, in whatever order. Only +** after this, is the USER message propagated. +** +** NICK's must be propagated at once when received, although +** it would be better to delay them too until full info is +** available. Doing it is not so simple though, would have +** to implement the following: +** +** (actually it has been implemented already for a while) -orabidoo +** +** 1) user telnets in and gives only "NICK foobar" and waits +** 2) another user far away logs in normally with the nick +** "foobar" (quite legal, as this server didn't propagate +** it). +** 3) now this server gets nick "foobar" from outside, but +** has alread the same defined locally. Current server +** would just issue "KILL foobar" to clean out dups. But, +** this is not fair. It should actually request another +** nick from local user or kill him/her... +*/ +void +register_local_user(struct Client *source_p) +{ + const char *id = NULL; + const struct AccessItem *aconf = NULL; + dlink_node *ptr = NULL; + + assert(source_p != NULL); + assert(source_p == source_p->from); + assert(MyConnect(source_p)); + assert(!source_p->localClient->registration); + + ClearCap(source_p, CAP_TS6); + + if (ConfigFileEntry.ping_cookie) + { + if (!IsPingSent(source_p) && source_p->localClient->random_ping == 0) + { + do + source_p->localClient->random_ping = genrand_int32(); + while (!source_p->localClient->random_ping); + + sendto_one(source_p, "PING :%u", + source_p->localClient->random_ping); + SetPingSent(source_p); + return; + } + + if (!HasPingCookie(source_p)) + return; + } + + source_p->localClient->last_privmsg = CurrentTime; + /* Straight up the maximum rate of flooding... */ + source_p->localClient->allow_read = MAX_FLOOD_BURST; + + if (!execute_callback(client_check_cb, source_p, source_p->username)) + return; + + if (valid_hostname(source_p->host) == 0) + { + sendto_one(source_p, ":%s NOTICE %s :*** Notice -- You have an illegal " + "character in your hostname", me.name, source_p->name); + strlcpy(source_p->host, source_p->sockhost, + sizeof(source_p->host)); + } + + ptr = source_p->localClient->confs.head; + aconf = map_to_conf(ptr->data); + + if (!IsGotId(source_p)) + { + char username[USERLEN + 1]; + const char *p = username; + unsigned int i = 0; + + if (IsNeedIdentd(aconf)) + { + ++ServerStats.is_ref; + sendto_one(source_p, ":%s NOTICE %s :*** Notice -- You need to install " + "identd to use this server", me.name, source_p->name); + exit_client(source_p, &me, "Install identd"); + return; + } + + strlcpy(username, source_p->username, sizeof(username)); + + if (!IsNoTilde(aconf)) + source_p->username[i++] = '~'; + + for (; *p && i < USERLEN; ++p) + if (*p != '[') + source_p->username[i++] = *p; + + source_p->username[i] = '\0'; + } + + /* password check */ + if (!EmptyString(aconf->passwd)) + { + const char *pass = source_p->localClient->passwd; + + if (!match_conf_password(pass, aconf)) + { + ++ServerStats.is_ref; + sendto_one(source_p, form_str(ERR_PASSWDMISMATCH), + me.name, source_p->name); + exit_client(source_p, &me, "Bad Password"); + return; + } + } + + /* don't free source_p->localClient->passwd here - it can be required + * by masked /stats I if there are auth{} blocks with need_password = no; + * --adx + */ + + /* report if user has &^>= etc. and set flags as needed in source_p */ + report_and_set_user_flags(source_p, aconf); + + if (IsDead(source_p)) + return; + + /* Limit clients - + * We want to be able to have servers and F-line clients + * connect, so save room for "buffer" connections. + * Smaller servers may want to decrease this, and it should + * probably be just a percentage of the MAXCLIENTS... + * -Taner + */ + /* Except "F:" clients */ + if ((Count.local >= ServerInfo.max_clients + MAX_BUFFER) || + (Count.local >= ServerInfo.max_clients && !IsExemptLimits(source_p))) + { + sendto_realops_flags(UMODE_FULL, L_ALL, + "Too many clients, rejecting %s[%s].", + source_p->name, source_p->host); + ++ServerStats.is_ref; + exit_client(source_p, &me, "Sorry, server is full - try later"); + return; + } + + /* valid user name check */ + if (valid_username(source_p->username) == 0) + { + char tmpstr2[IRCD_BUFSIZE]; + + sendto_realops_flags(UMODE_REJ, L_ALL, "Invalid username: %s (%s@%s)", + source_p->name, source_p->username, source_p->host); + ++ServerStats.is_ref; + snprintf(tmpstr2, sizeof(tmpstr2), "Invalid username [%s]", + source_p->username); + exit_client(source_p, &me, tmpstr2); + return; + } + + if (check_xline(source_p)) + return; + + while (hash_find_id((id = uid_get())) != NULL) + ; + + strlcpy(source_p->id, id, sizeof(source_p->id)); + hash_add_id(source_p); + + sendto_realops_flags(UMODE_CCONN, L_ALL, + "Client connecting: %s (%s@%s) [%s] {%s} [%s] <%s>", + source_p->name, source_p->username, source_p->host, + ConfigFileEntry.hide_spoof_ips && IsIPSpoof(source_p) ? + "255.255.255.255" : source_p->sockhost, + get_client_class(source_p), + source_p->info, source_p->id); + + sendto_realops_flags(UMODE_CCONN_FULL, L_ALL, + "CLICONN %s %s %s %s %s %s %s 0 %s", + source_p->name, source_p->username, source_p->host, + ConfigFileEntry.hide_spoof_ips && IsIPSpoof(source_p) ? + "255.255.255.255" : source_p->sockhost, + get_client_class(source_p), + ConfigFileEntry.hide_spoof_ips && IsIPSpoof(source_p) ? + "<hidden>" : source_p->localClient->client_host, + ConfigFileEntry.hide_spoof_ips && IsIPSpoof(source_p) ? + "<hidden>" : source_p->localClient->client_server, + source_p->info); + + + if (ConfigFileEntry.invisible_on_connect) + { + AddUMode(source_p, UMODE_INVISIBLE); + ++Count.invisi; + } + + if ((++Count.local) > Count.max_loc) + { + Count.max_loc = Count.local; + + if (!(Count.max_loc % 10)) + sendto_realops_flags(UMODE_ALL, L_ALL, "New Max Local Clients: %d", + Count.max_loc); + } + + /* Increment our total user count here */ + if (++Count.total > Count.max_tot) + Count.max_tot = Count.total; + ++Count.totalrestartcount; + + assert(source_p->servptr == &me); + SetClient(source_p); + dlinkAdd(source_p, &source_p->lnode, &source_p->servptr->serv->client_list); + + source_p->localClient->allow_read = MAX_FLOOD_BURST; + + assert(dlinkFind(&unknown_list, source_p)); + + dlink_move_node(&source_p->localClient->lclient_node, + &unknown_list, &local_client_list); + + user_welcome(source_p); + add_user_host(source_p->username, source_p->host, 0); + SetUserHost(source_p); + + introduce_client(source_p); +} + +/* register_remote_user() + * + * inputs - source_p remote or directly connected client + * - username to register as + * - host name to register as + * - server name + * - realname (gecos) + * output - NONE + * side effects - This function is called when a remote client + * is introduced by a server. + */ +void +register_remote_user(struct Client *source_p, + const char *username, const char *host, const char *server, + const char *realname) +{ + struct Client *target_p = NULL; + + assert(source_p != NULL); + assert(source_p->username != username); + + strlcpy(source_p->host, host, sizeof(source_p->host)); + strlcpy(source_p->username, username, sizeof(source_p->username)); + + /* + * coming from another server, take the servers word for it + */ + source_p->servptr = hash_find_server(server); + + /* Super GhostDetect: + * If we can't find the server the user is supposed to be on, + * then simply blow the user away. -Taner + */ + if (source_p->servptr == NULL) + { + sendto_realops_flags(UMODE_ALL, L_ALL, + "No server %s for user %s[%s@%s] from %s", + server, source_p->name, source_p->username, + source_p->host, source_p->from->name); + kill_client(source_p->from, source_p, "%s (Server doesn't exist)", me.name); + + AddFlag(source_p, FLAGS_KILLED); + exit_client(source_p, &me, "Ghosted Client"); + return; + } + + if ((target_p = source_p->servptr) && target_p->from != source_p->from) + { + sendto_realops_flags(UMODE_DEBUG, L_ALL, + "Bad User [%s] :%s USER %s@%s %s, != %s[%s]", + source_p->from->name, source_p->name, source_p->username, + source_p->host, source_p->servptr->name, + target_p->name, target_p->from->name); + kill_client(source_p->from, source_p, + "%s (NICK from wrong direction (%s != %s))", + me.name, source_p->servptr->name, target_p->from->name); + AddFlag(source_p, FLAGS_KILLED); + exit_client(source_p, &me, "USER server wrong direction"); + return; + } + + /* + * If the nick has been introduced by a services server, + * make it a service as well. + */ + if (HasFlag(source_p->servptr, FLAGS_SERVICE)) + AddFlag(source_p, FLAGS_SERVICE); + + /* Increment our total user count here */ + if (++Count.total > Count.max_tot) + Count.max_tot = Count.total; + + SetClient(source_p); + dlinkAdd(source_p, &source_p->lnode, &source_p->servptr->serv->client_list); + add_user_host(source_p->username, source_p->host, 1); + SetUserHost(source_p); + + introduce_client(source_p); +} + +/* introduce_client() + * + * inputs - source_p + * output - NONE + * side effects - This common function introduces a client to the rest + * of the net, either from a local client connect or + * from a remote connect. + */ +static void +introduce_client(struct Client *source_p) +{ + dlink_node *server_node = NULL; + static char ubuf[12]; + + if (MyClient(source_p)) + send_umode(source_p, source_p, 0, SEND_UMODES, ubuf); + else + send_umode(NULL, source_p, 0, SEND_UMODES, ubuf); + + watch_check_hash(source_p, RPL_LOGON); + + if (*ubuf == '\0') + { + ubuf[0] = '+'; + ubuf[1] = '\0'; + } + + DLINK_FOREACH(server_node, serv_list.head) + { + struct Client *server = server_node->data; + + if (server == source_p->from) + continue; + + if (IsCapable(server, CAP_SVS)) + { + if (IsCapable(server, CAP_TS6) && HasID(source_p)) + sendto_one(server, ":%s UID %s %d %lu %s %s %s %s %s %s :%s", + source_p->servptr->id, + source_p->name, source_p->hopcount+1, + (unsigned long)source_p->tsinfo, + ubuf, source_p->username, source_p->host, + (MyClient(source_p) && IsIPSpoof(source_p)) ? + "0" : source_p->sockhost, source_p->id, + source_p->svid, + source_p->info); + else + sendto_one(server, "NICK %s %d %lu %s %s %s %s %s :%s", + source_p->name, source_p->hopcount+1, + (unsigned long)source_p->tsinfo, + ubuf, source_p->username, source_p->host, + source_p->servptr->name, source_p->svid, + source_p->info); + + } + else + { + if (IsCapable(server, CAP_TS6) && HasID(source_p)) + sendto_one(server, ":%s UID %s %d %lu %s %s %s %s %s :%s", + source_p->servptr->id, + source_p->name, source_p->hopcount+1, + (unsigned long)source_p->tsinfo, + ubuf, source_p->username, source_p->host, + (MyClient(source_p) && IsIPSpoof(source_p)) ? + "0" : source_p->sockhost, source_p->id, source_p->info); + else + sendto_one(server, "NICK %s %d %lu %s %s %s %s :%s", + source_p->name, source_p->hopcount+1, + (unsigned long)source_p->tsinfo, + ubuf, source_p->username, source_p->host, + source_p->servptr->name, source_p->info); + } + } +} + +/* valid_hostname() + * + * Inputs - pointer to hostname + * Output - 1 if valid, 0 if not + * Side effects - check hostname for validity + * + * NOTE: this doesn't allow a hostname to begin with a dot and + * will not allow more dots than chars. + */ +int +valid_hostname(const char *hostname) +{ + const char *p = hostname; + + assert(p != NULL); + + if (*p == '.' || *p == ':') + return 0; + + for (; *p; ++p) + if (!IsHostChar(*p)) + return 0; + + return 1; +} + +/* valid_username() + * + * Inputs - pointer to user + * Output - 1 if valid, 0 if not + * Side effects - check username for validity + * + * Absolutely always reject any '*' '!' '?' '@' in an user name + * reject any odd control characters names. + * Allow '.' in username to allow for "first.last" + * style of username + */ +int +valid_username(const char *username) +{ + int dots = 0; + const char *p = username; + + assert(p != NULL); + + if (*p == '~') + ++p; + + /* reject usernames that don't start with an alphanum + * i.e. reject jokers who have '-@somehost' or '.@somehost' + * or "-hi-@somehost", "h-----@somehost" would still be accepted. + */ + if (!IsAlNum(*p)) + return 0; + + while (*++p) + { + if ((*p == '.') && ConfigFileEntry.dots_in_ident) + { + if (++dots > ConfigFileEntry.dots_in_ident) + return 0; + if (!IsUserChar(*(p + 1))) + return 0; + } + else if (!IsUserChar(*p)) + return 0; + } + + return 1; +} + +/* clean_nick_name() + * + * input - nickname + * - whether it's a local nick (1) or remote (0) + * output - none + * side effects - walks through the nickname, returning 0 if erroneous + */ +int +valid_nickname(const char *nickname, const int local) +{ + const char *p = nickname; + assert(nickname && *nickname); + + /* nicks can't start with a digit or - or be 0 length */ + /* This closer duplicates behaviour of hybrid-6 */ + if (*p == '-' || (IsDigit(*p) && local) || *p == '\0') + return 0; + + for (; *p; ++p) + if (!IsNickChar(*p)) + return 0; + + return p - nickname <= NICKLEN; +} + +/* report_and_set_user_flags() + * + * inputs - pointer to source_p + * - pointer to aconf for this user + * output - NONE + * side effects - Report to user any special flags + * they are getting, and set them. + */ +static void +report_and_set_user_flags(struct Client *source_p, const struct AccessItem *aconf) +{ + /* If this user is being spoofed, tell them so */ + if (IsConfDoSpoofIp(aconf)) + { + sendto_one(source_p, + ":%s NOTICE %s :*** Spoofing your IP. congrats.", + me.name, source_p->name); + } + + /* If this user is in the exception class, Set it "E lined" */ + if (IsConfExemptKline(aconf)) + { + SetExemptKline(source_p); + sendto_one(source_p, + ":%s NOTICE %s :*** You are exempt from K/D/G lines. congrats.", + me.name, source_p->name); + } + + /* The else here is to make sure that G line exempt users + * do not get noticed twice. + */ + else if (IsConfExemptGline(aconf)) + { + SetExemptGline(source_p); + sendto_one(source_p, ":%s NOTICE %s :*** You are exempt from G lines.", + me.name, source_p->name); + } + + if (IsConfExemptResv(aconf)) + { + SetExemptResv(source_p); + sendto_one(source_p, ":%s NOTICE %s :*** You are exempt from resvs.", + me.name, source_p->name); + } + + /* If this user is exempt from user limits set it "F lined" */ + if (IsConfExemptLimits(aconf)) + { + SetExemptLimits(source_p); + sendto_one(source_p, + ":%s NOTICE %s :*** You are exempt from user limits. congrats.", + me.name,source_p->name); + } + + if (IsConfCanFlood(aconf)) + { + SetCanFlood(source_p); + sendto_one(source_p, ":%s NOTICE %s :*** You are exempt from flood " + "protection, aren't you fearsome.", + me.name, source_p->name); + } +} + +/* change_simple_umode() + * + * this callback can be hooked to allow special handling of + * certain usermodes + */ +static void * +change_simple_umode(va_list args) +{ + struct Client *client_p; + struct Client *source_p; + int what; + unsigned int flag; + + client_p = va_arg(args, struct Client *); + source_p = va_arg(args, struct Client *); + what = va_arg(args, int); + flag = va_arg(args, unsigned int); + + if (what == MODE_ADD) + AddUMode(source_p, flag); + else + DelUMode(source_p, flag); + + return NULL; +} + +/* set_user_mode() + * + * added 15/10/91 By Darren Reed. + * parv[0] - sender + * parv[1] - username to change mode for + * parv[2] - modes to change + */ +void +set_user_mode(struct Client *client_p, struct Client *source_p, + int parc, char *parv[]) +{ + unsigned int flag, setflags; + char **p, *m, buf[IRCD_BUFSIZE]; + struct Client *target_p; + int what = MODE_ADD, badflag = 0, i; + + assert(!(parc < 2)); + + if ((target_p = find_person(client_p, parv[1])) == NULL) + { + if (MyConnect(source_p)) + sendto_one(source_p, form_str(ERR_NOSUCHCHANNEL), + me.name, source_p->name, parv[1]); + return; + } + + if (IsServer(source_p)) + { + sendto_realops_flags(UMODE_ALL, L_ADMIN, "*** Mode for User %s from %s", + parv[1], source_p->name); + return; + } + + if (source_p != target_p) + { + sendto_one(source_p, form_str(ERR_USERSDONTMATCH), + me.name, source_p->name); + return; + } + + if (parc < 3) + { + m = buf; + *m++ = '+'; + + for (i = 0; i < 128; i++) + if (HasUMode(source_p, user_modes[i])) + *m++ = (char)i; + *m = '\0'; + + sendto_one(source_p, form_str(RPL_UMODEIS), + me.name, source_p->name, buf); + return; + } + + execute_callback(entering_umode_cb, client_p, source_p); + + /* find flags already set for user */ + setflags = source_p->umodes; + + /* parse mode change string(s) */ + for (p = &parv[2]; p && *p; p++) + { + for (m = *p; *m; m++) + { + switch (*m) + { + case '+': + what = MODE_ADD; + break; + case '-': + what = MODE_DEL; + break; + case 'o': + if (what == MODE_ADD) + { + if (IsServer(client_p) && !HasUMode(source_p, UMODE_OPER)) + { + ++Count.oper; + SetOper(source_p); + } + } + else + { + /* Only decrement the oper counts if an oper to begin with + * found by Pat Szuta, Perly , perly@xnet.com + */ + if (!HasUMode(source_p, UMODE_OPER)) + break; + + ClearOper(source_p); + Count.oper--; + + if (MyConnect(source_p)) + { + dlink_node *dm; + + detach_conf(source_p, OPER_TYPE); + ClrOFlag(source_p); + DelUMode(source_p, ConfigFileEntry.oper_only_umodes); + + if ((dm = dlinkFindDelete(&oper_list, source_p)) != NULL) + free_dlink_node(dm); + } + } + + break; + + /* we may not get these, + * but they shouldnt be in default + */ + case 'r': + case ' ' : + case '\n': + case '\r': + case '\t': + break; + + default: + if ((flag = user_modes[(unsigned char)*m])) + { + if (MyConnect(source_p) && !HasUMode(source_p, UMODE_OPER) && + (ConfigFileEntry.oper_only_umodes & flag)) + { + badflag = 1; + } + else + execute_callback(umode_cb, client_p, source_p, what, flag); + } + else + { + if (MyConnect(source_p)) + badflag = 1; + } + + break; + } + } + } + + if (badflag) + sendto_one(source_p, form_str(ERR_UMODEUNKNOWNFLAG), + me.name, source_p->name); + + if (HasUMode(source_p, UMODE_NCHANGE) && !HasOFlag(source_p, OPER_FLAG_N)) + { + sendto_one(source_p, ":%s NOTICE %s :*** You have no nchange flag;", + me.name, source_p->name); + DelUMode(source_p, UMODE_NCHANGE); + } + + if (MyConnect(source_p) && HasUMode(source_p, UMODE_ADMIN) && + !HasOFlag(source_p, OPER_FLAG_ADMIN)) + { + sendto_one(source_p, ":%s NOTICE %s :*** You have no admin flag;", + me.name, source_p->name); + DelUMode(source_p, UMODE_ADMIN); + } + + if (!(setflags & UMODE_INVISIBLE) && HasUMode(source_p, UMODE_INVISIBLE)) + ++Count.invisi; + if ((setflags & UMODE_INVISIBLE) && !HasUMode(source_p, UMODE_INVISIBLE)) + --Count.invisi; + + /* + * compare new flags with old flags and send string which + * will cause servers to update correctly. + */ + send_umode_out(client_p, source_p, setflags); +} + +/* send_umode() + * send the MODE string for user (user) to connection client_p + * -avalon + * + * inputs - client_p + * - source_p + * - int old + * - sendmask mask of modes to send + * - suplied umode_buf + * output - NONE + */ +void +send_umode(struct Client *client_p, struct Client *source_p, + unsigned int old, unsigned int sendmask, char *umode_buf) +{ + char *m = umode_buf; + int what = 0; + unsigned int i; + unsigned int flag; + + /* + * build a string in umode_buf to represent the change in the user's + * mode between the new (source_p->umodes) and 'old'. + */ + for (i = 0; i < 128; i++) + { + flag = user_modes[i]; + if (!flag) + continue; + + if (MyClient(source_p) && !(flag & sendmask)) + continue; + + if ((flag & old) && !HasUMode(source_p, flag)) + { + if (what == MODE_DEL) + *m++ = (char)i; + else + { + what = MODE_DEL; + *m++ = '-'; + *m++ = (char)i; + } + } + else if (!(flag & old) && HasUMode(source_p, flag)) + { + if (what == MODE_ADD) + *m++ = (char)i; + else + { + what = MODE_ADD; + *m++ = '+'; + *m++ = (char)i; + } + } + } + + *m = '\0'; + + if (*umode_buf && client_p) + sendto_one(client_p, ":%s!%s@%s MODE %s :%s", + source_p->name, source_p->username, + source_p->host, source_p->name, umode_buf); +} + +/* send_umode_out() + * + * inputs - + * output - NONE + * side effects - Only send ubuf out to servers that know about this client + */ +void +send_umode_out(struct Client *client_p, struct Client *source_p, + unsigned int old) +{ + char buf[IRCD_BUFSIZE] = { '\0' }; + dlink_node *ptr = NULL; + + send_umode(NULL, source_p, old, SEND_UMODES, buf); + + if (buf[0]) + { + DLINK_FOREACH(ptr, serv_list.head) + { + struct Client *target_p = ptr->data; + + if ((target_p != client_p) && (target_p != source_p)) + sendto_one(target_p, ":%s MODE %s :%s", + ID_or_name(source_p, target_p), + ID_or_name(source_p, target_p), buf); + } + } + + if (client_p && MyClient(client_p)) + send_umode(client_p, source_p, old, 0xffffffff, buf); +} + +/* user_welcome() + * + * inputs - client pointer to client to welcome + * output - NONE + * side effects - + */ +static void +user_welcome(struct Client *source_p) +{ +#if defined(__TIME__) && defined(__DATE__) + static const char built_date[] = __DATE__ " at " __TIME__; +#else + static const char built_date[] = "unknown"; +#endif + +#ifdef HAVE_LIBCRYPTO + if (source_p->localClient->fd.ssl != NULL) + sendto_one(source_p, ":%s NOTICE %s :*** Connected securely via %s", + me.name, source_p->name, + ssl_get_cipher(source_p->localClient->fd.ssl)); +#endif + + sendto_one(source_p, form_str(RPL_WELCOME), me.name, source_p->name, + ServerInfo.network_name, source_p->name); + sendto_one(source_p, form_str(RPL_YOURHOST), me.name, source_p->name, + get_listener_name(source_p->localClient->listener), ircd_version); + sendto_one(source_p, form_str(RPL_CREATED), + me.name, source_p->name, built_date); + sendto_one(source_p, form_str(RPL_MYINFO), + me.name, source_p->name, me.name, ircd_version, umode_buffer); + show_isupport(source_p); + + if (source_p->id[0] != '\0') + sendto_one(source_p, form_str(RPL_YOURID), me.name, + source_p->name, source_p->id); + + show_lusers(source_p); + + if (ConfigFileEntry.short_motd) + { + sendto_one(source_p, ":%s NOTICE %s :*** Notice -- motd was last changed at %s", + me.name, source_p->name, ConfigFileEntry.motd.lastChangedDate); + sendto_one(source_p, + ":%s NOTICE %s :*** Notice -- Please read the motd if you haven't " + "read it", me.name, source_p->name); + sendto_one(source_p, form_str(RPL_MOTDSTART), + me.name, source_p->name, me.name); + sendto_one(source_p, form_str(RPL_MOTD), + me.name, source_p->name, + "*** This is the short motd ***"); + sendto_one(source_p, form_str(RPL_ENDOFMOTD), + me.name, source_p->name); + } + else + send_message_file(source_p, &ConfigFileEntry.motd); +} + +/* check_xline() + * + * inputs - pointer to client to test + * outupt - 1 if exiting 0 if ok + * side effects - + */ +static int +check_xline(struct Client *source_p) +{ + struct ConfItem *conf = NULL; + const char *reason = NULL; + + if ((conf = find_matching_name_conf(XLINE_TYPE, source_p->info, NULL, NULL, 0)) || + (conf = find_matching_name_conf(RXLINE_TYPE, source_p->info, NULL, NULL, 0))) + { + struct MatchItem *reg = map_to_conf(conf); + + ++reg->count; + + if (reg->reason != NULL) + reason = reg->reason; + else + reason = "No Reason"; + + sendto_realops_flags(UMODE_REJ, L_ALL, + "X-line Rejecting [%s] [%s], user %s [%s]", + source_p->info, reason, + get_client_name(source_p, HIDE_IP), + source_p->sockhost); + + ++ServerStats.is_ref; + exit_client(source_p, &me, "Bad user info"); + return 1; + } + + return 0; +} + +/* oper_up() + * + * inputs - pointer to given client to oper + * output - NONE + * side effects - Blindly opers up given source_p, using aconf info + * all checks on passwords have already been done. + * This could also be used by rsa oper routines. + */ +void +oper_up(struct Client *source_p) +{ + const unsigned int old = source_p->umodes; + const struct AccessItem *oconf = NULL; + + assert(source_p->localClient->confs.head); + oconf = map_to_conf((source_p->localClient->confs.head)->data); + + ++Count.oper; + SetOper(source_p); + + if (oconf->modes) + AddUMode(source_p, oconf->modes); + else if (ConfigFileEntry.oper_umodes) + AddUMode(source_p, ConfigFileEntry.oper_umodes); + + if (!(old & UMODE_INVISIBLE) && HasUMode(source_p, UMODE_INVISIBLE)) + ++Count.invisi; + if ((old & UMODE_INVISIBLE) && !HasUMode(source_p, UMODE_INVISIBLE)) + --Count.invisi; + + assert(dlinkFind(&oper_list, source_p) == NULL); + dlinkAdd(source_p, make_dlink_node(), &oper_list); + + AddOFlag(source_p, oconf->port); + + if (HasOFlag(source_p, OPER_FLAG_ADMIN)) + AddUMode(source_p, UMODE_ADMIN); + if (!HasOFlag(source_p, OPER_FLAG_N)) + DelUMode(source_p, UMODE_NCHANGE); + + sendto_realops_flags(UMODE_ALL, L_ALL, "%s is now an operator", + get_oper_name(source_p)); + send_umode_out(source_p, source_p, old); + sendto_one(source_p, form_str(RPL_YOUREOPER), me.name, source_p->name); +} + +static char new_uid[TOTALSIDUID + 1]; /* allow for \0 */ + +int +valid_sid(const char *sid) +{ + if (strlen(sid) == IRC_MAXSID) + if (IsDigit(*sid)) + if (IsAlNum(*(sid + 1)) && IsAlNum(*(sid + 2))) + return 1; + + return 0; +} + +/* + * init_uid() + * + * inputs - NONE + * output - NONE + * side effects - new_uid is filled in with server id portion (sid) + * (first 3 bytes) or defaulted to 'A'. + * Rest is filled in with 'A' + */ +void +init_uid(void) +{ + int i; + + memset(new_uid, 0, sizeof(new_uid)); + + if (!EmptyString(ServerInfo.sid)) + strlcpy(new_uid, ServerInfo.sid, sizeof(new_uid)); + + for (i = 0; i < IRC_MAXSID; ++i) + if (new_uid[i] == '\0') + new_uid[i] = 'A'; + + /* NOTE: if IRC_MAXUID != 6, this will have to be rewritten */ + /* Yes nenolod, I have known it was off by one ever since I wrote it + * But *JUST* for you, though, it really doesn't look as *pretty* + * -Dianora + */ + memcpy(new_uid + IRC_MAXSID, "AAAAA@", IRC_MAXUID); + + entering_umode_cb = register_callback("entering_umode", NULL); + umode_cb = register_callback("changing_umode", change_simple_umode); +} + +/* + * add_one_to_uid + * + * inputs - index number into new_uid + * output - NONE + * side effects - new_uid is incremented by one + * note this is a recursive function + */ +static void +add_one_to_uid(int i) +{ + if (i != IRC_MAXSID) /* Not reached server SID portion yet? */ + { + if (new_uid[i] == 'Z') + new_uid[i] = '0'; + else if (new_uid[i] == '9') + { + new_uid[i] = 'A'; + add_one_to_uid(i-1); + } + else + ++new_uid[i]; + } + else + { + /* NOTE: if IRC_MAXUID != 6, this will have to be rewritten */ + if (new_uid[i] == 'Z') + memcpy(new_uid + IRC_MAXSID, "AAAAAA", IRC_MAXUID); + else + ++new_uid[i]; + } +} + +/* + * uid_get + * + * inputs - struct Client * + * output - new UID is returned to caller + * side effects - new_uid is incremented by one. + */ +static const char * +uid_get(void) +{ + add_one_to_uid(TOTALSIDUID - 1); /* index from 0 */ + return new_uid; +} + +/* + * init_isupport() + * + * input - NONE + * output - NONE + * side effects - Must be called before isupport is enabled + */ +void +init_isupport(void) +{ + isupportFile = init_MessageLine(); + + add_isupport("CALLERID", NULL, -1); + add_isupport("CASEMAPPING", CASEMAP, -1); + add_isupport("DEAF", "D", -1); + add_isupport("KICKLEN", NULL, KICKLEN); + add_isupport("MODES", NULL, MAXMODEPARAMS); + add_isupport("NICKLEN", NULL, NICKLEN); +#ifdef HALFOPS + add_isupport("PREFIX", "(ohv)@%+", -1); + add_isupport("STATUSMSG", "@%+", -1); +#else + add_isupport("PREFIX", "(ov)@+", -1); + add_isupport("STATUSMSG", "@+", -1); +#endif + add_isupport("TOPICLEN", NULL, TOPICLEN); +} + +/* + * add_isupport() + * + * input - name of supported function + * - options if any + * - number if any + * output - NONE + * side effects - Each supported item must call this when activated + */ +void +add_isupport(const char *name, const char *options, int n) +{ + dlink_node *ptr; + struct Isupport *support; + + DLINK_FOREACH(ptr, support_list.head) + { + support = ptr->data; + if (irccmp(support->name, name) == 0) + { + MyFree(support->name); + MyFree(support->options); + break; + } + } + + if (ptr == NULL) + { + support = MyMalloc(sizeof(*support)); + dlinkAddTail(support, &support->node, &support_list); + } + + DupString(support->name, name); + if (options != NULL) + DupString(support->options, options); + support->number = n; + + rebuild_isupport_message_line(); +} + +/* + * delete_isupport() + * + * input - name of supported function + * output - NONE + * side effects - Each supported item must call this when deactivated + */ +void +delete_isupport(const char *name) +{ + dlink_node *ptr; + struct Isupport *support; + + DLINK_FOREACH(ptr, support_list.head) + { + support = ptr->data; + if (irccmp(support->name, name) == 0) + { + dlinkDelete(ptr, &support_list); + MyFree(support->name); + MyFree(support->options); + MyFree(support); + break; + } + } + + rebuild_isupport_message_line(); +} + +/* + * rebuild_isupport_message_line + * + * input - NONE + * output - NONE + * side effects - Destroy the isupport MessageFile lines, and rebuild. + */ +void +rebuild_isupport_message_line(void) +{ + char isupportbuffer[IRCD_BUFSIZE]; + char *p = isupportbuffer; + dlink_node *ptr = NULL; + int n = 0; + int tokens = 0; + size_t len = 0; + size_t reserve = strlen(me.name) + HOSTLEN + strlen(form_str(RPL_ISUPPORT)); + + destroy_MessageLine(isupportFile); + + DLINK_FOREACH(ptr, support_list.head) + { + struct Isupport *support = ptr->data; + + p += (n = ircsprintf(p, "%s", support->name)); + len += n; + + if (support->options != NULL) + { + p += (n = ircsprintf(p, "=%s", support->options)); + len += n; + } + + if (support->number > 0) + { + p += (n = ircsprintf(p, "=%d", support->number)); + len += n; + } + + *p++ = ' '; + len++; + *p = '\0'; + + if (++tokens == (MAXPARA-2) || len >= (sizeof(isupportbuffer)-reserve)) + { /* arbritrary for now */ + if (*--p == ' ') + *p = '\0'; + + addto_MessageLine(isupportFile, isupportbuffer); + p = isupportbuffer; + len = 0; + n = tokens = 0; + } + } + + if (len != 0) + { + if (*--p == ' ') + *p = '\0'; + addto_MessageLine(isupportFile, isupportbuffer); + } +} diff --git a/src/send.c b/src/send.c new file mode 100644 index 0000000..afa684e --- /dev/null +++ b/src/send.c @@ -0,0 +1,1111 @@ +/* + * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd). + * send.c: Functions for sending messages. + * + * Copyright (C) 2002 by the past and present ircd coders, and others. + * + * 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 + * + * $Id$ + */ + +#include "stdinc.h" +#include "list.h" +#include "send.h" +#include "channel.h" +#include "client.h" +#include "dbuf.h" +#include "irc_string.h" +#include "ircd.h" +#include "numeric.h" +#include "fdlist.h" +#include "s_bsd.h" +#include "s_serv.h" +#include "sprintf_irc.h" +#include "conf.h" +#include "log.h" +#include "memory.h" +#include "hook.h" +#include "packet.h" + + +struct Callback *iosend_cb = NULL; +static unsigned int current_serial = 0; + + +/* send_format() + * + * inputs - buffer to format into + * - size of the buffer + * - format pattern to use + * - var args + * output - number of bytes formatted output + * side effects - modifies sendbuf + */ +static inline int +send_format(char *lsendbuf, int bufsize, const char *pattern, va_list args) +{ + int len; + + /* + * from rfc1459 + * + * IRC messages are always lines of characters terminated with a CR-LF + * (Carriage Return - Line Feed) pair, and these messages shall not + * exceed 512 characters in length, counting all characters + * including the trailing CR-LF. + * Thus, there are 510 characters maximum allowed + * for the command and its parameters. There is no provision for + * continuation message lines. See section 7 for more details about + * current implementations. + */ + len = vsnprintf(lsendbuf, bufsize - 1, pattern, args); + if (len > bufsize - 2) + len = bufsize - 2; /* required by some versions of vsnprintf */ + + lsendbuf[len++] = '\r'; + lsendbuf[len++] = '\n'; + return len; +} + +/* + * iosend_default - append a packet to the client's sendq. + */ +void * +iosend_default(va_list args) +{ + struct Client *to = va_arg(args, struct Client *); + int length = va_arg(args, int); + char *buf = va_arg(args, char *); + + dbuf_put(&to->localClient->buf_sendq, buf, length); + return NULL; +} + +/* + ** send_message + ** Internal utility which appends given buffer to the sockets + ** sendq. + */ +static void +send_message(struct Client *to, char *buf, int len) +{ + assert(!IsMe(to)); + assert(to != &me); + + if (dbuf_length(&to->localClient->buf_sendq) + len > get_sendq(to)) + { + if (IsServer(to)) + sendto_realops_flags(UMODE_ALL, L_ALL, + "Max SendQ limit exceeded for %s: %lu > %lu", + get_client_name(to, HIDE_IP), + (unsigned long)(dbuf_length(&to->localClient->buf_sendq) + len), + get_sendq(to)); + if (IsClient(to)) + SetSendQExceeded(to); + dead_link_on_write(to, 0); + return; + } + + execute_callback(iosend_cb, to, len, buf); + + /* + ** Update statistics. The following is slightly incorrect + ** because it counts messages even if queued, but bytes + ** only really sent. Queued bytes get updated in SendQueued. + */ + ++to->localClient->send.messages; + ++me.localClient->send.messages; + + if (dbuf_length(&to->localClient->buf_sendq) > + (IsServer(to) ? (unsigned int) 1024 : (unsigned int) 4096)) + send_queued_write(to); +} + +/* send_message_remote() + * + * inputs - pointer to client from message is being sent + * - pointer to client to send to + * - pointer to preformatted buffer + * - length of input buffer + * output - none + * side effects - Despite the function name, this only sends to directly + * connected clients. + * + */ +static void +send_message_remote(struct Client *to, struct Client *from, + char *buf, int len) +{ + if (!MyConnect(to)) + { + sendto_realops_flags(UMODE_ALL, L_ALL, + "server send message to %s [%s] dropped from %s(Not local server)", + to->name, to->from->name, from->name); + return; + } + + /* Optimize by checking if (from && to) before everything */ + /* we set to->from up there.. */ + + if (!MyClient(from) && IsClient(to) && (to == from->from)) + { + if (IsServer(from)) + { + sendto_realops_flags(UMODE_ALL, L_ALL, + "Send message to %s [%s] dropped from %s(Fake Dir)", + to->name, to->from->name, from->name); + return; + } + + sendto_realops_flags(UMODE_ALL, L_ALL, + "Ghosted: %s[%s@%s] from %s[%s@%s] (%s)", + to->name, to->username, to->host, + from->name, from->username, from->host, + to->from->name); + + sendto_server(NULL, CAP_TS6, NOCAPS, + ":%s KILL %s :%s (%s[%s@%s] Ghosted %s)", + me.id, to->name, me.name, to->name, + to->username, to->host, to->from->name); + sendto_server(NULL, NOCAPS, CAP_TS6, + ":%s KILL %s :%s (%s[%s@%s] Ghosted %s)", + me.name, to->name, me.name, to->name, + to->username, to->host, to->from->name); + + AddFlag(to, FLAGS_KILLED); + + if (IsClient(from)) + sendto_one(from, form_str(ERR_GHOSTEDCLIENT), + me.name, from->name, to->name, to->username, + to->host, to->from); + + exit_client(to, &me, "Ghosted client"); + + return; + } + + send_message(to, buf, len); +} + +/* + ** sendq_unblocked + ** Called when a socket is ready for writing. + */ +void +sendq_unblocked(fde_t *fd, struct Client *client_p) +{ + ClearSendqBlocked(client_p); + /* let send_queued_write be executed by send_queued_all */ + +#ifdef HAVE_LIBCRYPTO + if (fd->flags.pending_read) + { + fd->flags.pending_read = 0; + read_packet(fd, client_p); + } +#endif +} + +/* + ** send_queued_write + ** This is called when there is a chance that some output would + ** be possible. This attempts to empty the send queue as far as + ** possible, and then if any data is left, a write is rescheduled. + */ +void +send_queued_write(struct Client *to) +{ + int retlen; + struct dbuf_block *first; + + /* + ** Once socket is marked dead, we cannot start writing to it, + ** even if the error is removed... + */ + if (IsDead(to) || IsSendqBlocked(to)) + return; /* no use calling send() now */ + + /* Next, lets try to write some data */ + + if (dbuf_length(&to->localClient->buf_sendq)) + { + do { + first = to->localClient->buf_sendq.blocks.head->data; + +#ifdef HAVE_LIBCRYPTO + if (to->localClient->fd.ssl) + { + retlen = SSL_write(to->localClient->fd.ssl, first->data, first->size); + + /* translate openssl error codes, sigh */ + if (retlen < 0) + switch (SSL_get_error(to->localClient->fd.ssl, retlen)) + { + case SSL_ERROR_WANT_READ: + return; /* retry later, don't register for write events */ + + case SSL_ERROR_WANT_WRITE: + errno = EWOULDBLOCK; + case SSL_ERROR_SYSCALL: + break; + case SSL_ERROR_SSL: + if (errno == EAGAIN) + break; + default: + retlen = errno = 0; /* either an SSL-specific error or EOF */ + } + } + else +#endif + retlen = send(to->localClient->fd.fd, first->data, first->size, 0); + + if (retlen <= 0) + break; + + dbuf_delete(&to->localClient->buf_sendq, retlen); + + /* We have some data written .. update counters */ + to->localClient->send.bytes += retlen; + me.localClient->send.bytes += retlen; + } while (dbuf_length(&to->localClient->buf_sendq)); + + if ((retlen < 0) && (ignoreErrno(errno))) + { + /* we have a non-fatal error, reschedule a write */ + SetSendqBlocked(to); + comm_setselect(&to->localClient->fd, COMM_SELECT_WRITE, + (PF *)sendq_unblocked, (void *)to, 0); + } + else if (retlen <= 0) + { + dead_link_on_write(to, errno); + return; + } + } +} + +/* send_queued_all() + * + * input - NONE + * output - NONE + * side effects - try to flush sendq of each client + */ +void +send_queued_all(void) +{ + dlink_node *ptr; + + /* Servers are processed first, mainly because this can generate + * a notice to opers, which is to be delivered by this function. + */ + DLINK_FOREACH(ptr, serv_list.head) + send_queued_write((struct Client *) ptr->data); + + DLINK_FOREACH(ptr, unknown_list.head) + send_queued_write((struct Client *) ptr->data); + + DLINK_FOREACH(ptr, local_client_list.head) + send_queued_write((struct Client *) ptr->data); + + /* NOTE: This can still put clients on aborted_list; unfortunately, + * exit_aborted_clients takes precedence over send_queued_all, + * because exiting clients can generate server/oper traffic. + * The easiest approach is dealing with aborted clients in the next I/O lap. + * -adx + */ +} + +/* sendto_one() + * + * inputs - pointer to destination client + * - var args message + * output - NONE + * side effects - send message to single client + */ +void +sendto_one(struct Client *to, const char *pattern, ...) +{ + va_list args; + char buffer[IRCD_BUFSIZE]; + int len; + + if (to->from != NULL) + to = to->from; + if (IsDead(to)) + return; /* This socket has already been marked as dead */ + + va_start(args, pattern); + len = send_format(buffer, IRCD_BUFSIZE, pattern, args); + va_end(args); + + send_message(to, buffer, len); +} + +/* sendto_channel_butone() + * + * inputs - pointer to client(server) to NOT send message to + * - pointer to client that is sending this message + * - pointer to channel being sent to + * - vargs message + * output - NONE + * side effects - message as given is sent to given channel members. + * + * WARNING - +D clients are ignored + */ +void +sendto_channel_butone(struct Client *one, struct Client *from, + struct Channel *chptr, unsigned int type, + const char *pattern, ...) +{ + va_list alocal, aremote, auid; + char local_buf[IRCD_BUFSIZE]; + char remote_buf[IRCD_BUFSIZE]; + char uid_buf[IRCD_BUFSIZE]; + int local_len, remote_len, uid_len; + dlink_node *ptr = NULL, *ptr_next = NULL; + + if (IsServer(from)) + local_len = ircsprintf(local_buf, ":%s ", + from->name); + else + local_len = ircsprintf(local_buf, ":%s!%s@%s ", + from->name, from->username, from->host); + remote_len = ircsprintf(remote_buf, ":%s ", + from->name); + uid_len = ircsprintf(uid_buf, ":%s ", + ID(from)); + + va_start(alocal, pattern); + va_start(aremote, pattern); + va_start(auid, pattern); + local_len += send_format(&local_buf[local_len], IRCD_BUFSIZE - local_len, + pattern, alocal); + remote_len += send_format(&remote_buf[remote_len], IRCD_BUFSIZE - remote_len, + pattern, aremote); + uid_len += send_format(&uid_buf[uid_len], IRCD_BUFSIZE - uid_len, pattern, + auid); + va_end(auid); + va_end(aremote); + va_end(alocal); + + ++current_serial; + + DLINK_FOREACH_SAFE(ptr, ptr_next, chptr->members.head) + { + struct Membership *ms = ptr->data; + struct Client *target_p = ms->client_p; + + assert(IsClient(target_p)); + + if (IsDefunct(target_p) || HasUMode(target_p, UMODE_DEAF) || target_p->from == one) + continue; + + if (type != 0 && (ms->flags & type) == 0) + continue; + + if (MyConnect(target_p)) + { + if (target_p->localClient->serial != current_serial) + { + send_message(target_p, local_buf, local_len); + target_p->localClient->serial = current_serial; + } + } + else + { + /* Now check whether a message has been sent to this + * remote link already + */ + if (target_p->from->localClient->serial != current_serial) + { + if (IsCapable(target_p->from, CAP_TS6)) + send_message_remote(target_p->from, from, uid_buf, uid_len); + else + send_message_remote(target_p->from, from, remote_buf, remote_len); + target_p->from->localClient->serial = current_serial; + } + } + } +} + +/* sendto_server() + * + * inputs - pointer to client to NOT send to + * - pointer to channel + * - caps or'd together which must ALL be present + * - caps or'd together which must ALL NOT be present + * - printf style format string + * - args to format string + * output - NONE + * side effects - Send a message to all connected servers, except the + * client 'one' (if non-NULL), as long as the servers + * support ALL capabs in 'caps', and NO capabs in 'nocaps'. + * + * This function was written in an attempt to merge together the other + * billion sendto_*serv*() functions, which sprung up with capabs, + * lazylinks, uids, etc. + * -davidt + */ +void +sendto_server(struct Client *one, + const unsigned int caps, + const unsigned int nocaps, + const char *format, ...) +{ + va_list args; + dlink_node *ptr = NULL; + char buffer[IRCD_BUFSIZE]; + int len = 0; + + va_start(args, format); + len = send_format(buffer, IRCD_BUFSIZE, format, args); + va_end(args); + + DLINK_FOREACH(ptr, serv_list.head) + { + struct Client *client_p = ptr->data; + + /* If dead already skip */ + if (IsDead(client_p)) + continue; + /* check against 'one' */ + if (one != NULL && (client_p == one->from)) + continue; + /* check we have required capabs */ + if ((client_p->localClient->caps & caps) != caps) + continue; + /* check we don't have any forbidden capabs */ + if ((client_p->localClient->caps & nocaps) != 0) + continue; + + send_message(client_p, buffer, len); + } +} + +/* sendto_common_channels_local() + * + * inputs - pointer to client + * - pattern to send + * output - NONE + * side effects - Sends a message to all people on local server who are + * in same channel with user. + * used by m_nick.c and exit_one_client. + */ +void +sendto_common_channels_local(struct Client *user, int touser, + const char *pattern, ...) +{ + va_list args; + dlink_node *uptr; + dlink_node *cptr; + struct Channel *chptr; + struct Membership *ms; + struct Client *target_p; + char buffer[IRCD_BUFSIZE]; + int len; + + va_start(args, pattern); + len = send_format(buffer, IRCD_BUFSIZE, pattern, args); + va_end(args); + + ++current_serial; + + DLINK_FOREACH(cptr, user->channel.head) + { + chptr = ((struct Membership *) cptr->data)->chptr; + assert(chptr != NULL); + + DLINK_FOREACH(uptr, chptr->members.head) + { + ms = uptr->data; + target_p = ms->client_p; + assert(target_p != NULL); + + if (!MyConnect(target_p) || target_p == user || IsDefunct(target_p) || + target_p->localClient->serial == current_serial) + continue; + + target_p->localClient->serial = current_serial; + send_message(target_p, buffer, len); + } + } + + if (touser && MyConnect(user) && !IsDead(user) && + user->localClient->serial != current_serial) + send_message(user, buffer, len); +} + +/* sendto_channel_local() + * + * inputs - member status mask, e.g. CHFL_CHANOP | CHFL_VOICE + * - whether to ignore +D clients (YES/NO) + * - pointer to channel to send to + * - var args pattern + * output - NONE + * side effects - Send a message to all members of a channel that are + * locally connected to this server. + */ +void +sendto_channel_local(int type, int nodeaf, struct Channel *chptr, + const char *pattern, ...) +{ + va_list args; + char buffer[IRCD_BUFSIZE]; + int len; + dlink_node *ptr; + struct Membership *ms; + struct Client *target_p; + + va_start(args, pattern); + len = send_format(buffer, IRCD_BUFSIZE, pattern, args); + va_end(args); + + DLINK_FOREACH(ptr, chptr->members.head) + { + ms = ptr->data; + target_p = ms->client_p; + + if (type != 0 && (ms->flags & type) == 0) + continue; + + if (!MyConnect(target_p) || IsDefunct(target_p) || + (nodeaf && HasUMode(target_p, UMODE_DEAF))) + continue; + + send_message(target_p, buffer, len); + } +} + +/* sendto_channel_local_butone() + * + * inputs - pointer to client to NOT send message to + * - member status mask, e.g. CHFL_CHANOP | CHFL_VOICE + * - pointer to channel to send to + * - var args pattern + * output - NONE + * side effects - Send a message to all members of a channel that are + * locally connected to this server except one. + * + * WARNING - +D clients are omitted + */ +void +sendto_channel_local_butone(struct Client *one, int type, + struct Channel *chptr, const char *pattern, ...) +{ + va_list args; + char buffer[IRCD_BUFSIZE]; + int len; + struct Client *target_p; + struct Membership *ms; + dlink_node *ptr; + + va_start(args, pattern); + len = send_format(buffer, IRCD_BUFSIZE, pattern, args); + va_end(args); + + DLINK_FOREACH(ptr, chptr->members.head) + { + ms = ptr->data; + target_p = ms->client_p; + + if (type != 0 && (ms->flags & type) == 0) + continue; + + if (!MyConnect(target_p) || target_p == one || + IsDefunct(target_p) || HasUMode(target_p, UMODE_DEAF)) + continue; + send_message(target_p, buffer, len); + } +} + + +/* sendto_channel_remote() + * + * inputs - Client not to send towards + * - Client from whom message is from + * - member status mask, e.g. CHFL_CHANOP | CHFL_VOICE + * - pointer to channel to send to + * - var args pattern + * output - NONE + * side effects - Send a message to all members of a channel that are + * remote to this server. + */ +void +sendto_channel_remote(struct Client *one, struct Client *from, int type, + const unsigned int caps, const unsigned int nocaps, + struct Channel *chptr, const char *pattern, ...) +{ + va_list args; + char buffer[IRCD_BUFSIZE]; + int len; + dlink_node *ptr; + struct Client *target_p; + struct Membership *ms; + + va_start(args, pattern); + len = send_format(buffer, IRCD_BUFSIZE, pattern, args); + va_end(args); + + ++current_serial; + + DLINK_FOREACH(ptr, chptr->members.head) + { + ms = ptr->data; + target_p = ms->client_p; + + if (type != 0 && (ms->flags & type) == 0) + continue; + + if (MyConnect(target_p)) + continue; + target_p = target_p->from; + + if (target_p == one->from || + ((target_p->from->localClient->caps & caps) != caps) || + ((target_p->from->localClient->caps & nocaps) != 0)) + continue; + if (target_p->from->localClient->serial != current_serial) + { + send_message(target_p, buffer, len); + target_p->from->localClient->serial = current_serial; + } + } +} + +/* + ** match_it() and sendto_match_butone() ARE only used + ** to send a msg to all ppl on servers/hosts that match a specified mask + ** (used for enhanced PRIVMSGs) for opers + ** + ** addition -- Armin, 8jun90 (gruner@informatik.tu-muenchen.de) + ** + */ + +/* match_it() + * + * inputs - client pointer to match on + * - actual mask to match + * - what to match on, HOST or SERVER + * output - 1 or 0 if match or not + * side effects - NONE + */ +static int +match_it(const struct Client *one, const char *mask, int what) +{ + if (what == MATCH_HOST) + return match(mask, one->host); + + return match(mask, one->servptr->name); +} + +/* sendto_match_butone() + * + * Send to all clients which match the mask in a way defined on 'what'; + * either by user hostname or user servername. + * + * ugh. ONLY used by m_message.c to send an "oper magic" message. ugh. + */ +void +sendto_match_butone(struct Client *one, struct Client *from, char *mask, + int what, const char *pattern, ...) +{ + va_list alocal, aremote; + struct Client *client_p; + dlink_node *ptr, *ptr_next; + char local_buf[IRCD_BUFSIZE], remote_buf[IRCD_BUFSIZE]; + int local_len = ircsprintf(local_buf, ":%s!%s@%s ", from->name, + from->username, from->host); + int remote_len = ircsprintf(remote_buf, ":%s ", from->name); + + va_start(alocal, pattern); + va_start(aremote, pattern); + local_len += send_format(&local_buf[local_len], IRCD_BUFSIZE - local_len, + pattern, alocal); + remote_len += send_format(&remote_buf[remote_len], IRCD_BUFSIZE - remote_len, + pattern, aremote); + va_end(aremote); + va_end(alocal); + + /* scan the local clients */ + DLINK_FOREACH(ptr, local_client_list.head) + { + client_p = ptr->data; + + if (client_p != one && !IsDefunct(client_p) && + match_it(client_p, mask, what)) + send_message(client_p, local_buf, local_len); + } + + /* Now scan servers */ + DLINK_FOREACH_SAFE(ptr, ptr_next, serv_list.head) + { + client_p = ptr->data; + + /* + * The old code looped through every client on the + * network for each server to check if the + * server (client_p) has at least 1 client matching + * the mask, using something like: + * + * for (target_p = GlobalClientList; target_p; target_p = target_p->next) + * if (IsRegisteredUser(target_p) && + * match_it(target_p, mask, what) && + * (target_p->from == client_p)) + * vsendto_prefix_one(client_p, from, pattern, args); + * + * That way, we wouldn't send the message to + * a server who didn't have a matching client. + * However, on a network such as EFNet, that + * code would have looped through about 50 + * servers, and in each loop, loop through + * about 50k clients as well, calling match() + * in each nested loop. That is a very bad + * thing cpu wise - just send the message + * to every connected server and let that + * server deal with it. + * -wnder + */ + if (client_p != one && !IsDefunct(client_p)) + send_message_remote(client_p, from, remote_buf, remote_len); + } +} + +/* sendto_match_servs() + * + * inputs - source client + * - mask to send to + * - capab needed + * - data + * outputs - none + * side effects - data sent to servers matching with capab + */ +void +sendto_match_servs(struct Client *source_p, const char *mask, int cap, + const char *pattern, ...) +{ + va_list args; + struct Client *target_p; + dlink_node *ptr; + char buffer[IRCD_BUFSIZE]; + int found = 0; + + va_start(args, pattern); + vsnprintf(buffer, sizeof(buffer), pattern, args); + va_end(args); + + ++current_serial; + + DLINK_FOREACH(ptr, global_serv_list.head) + { + target_p = ptr->data; + + /* Do not attempt to send to ourselves, or the source */ + if (IsMe(target_p) || target_p->from == source_p->from) + continue; + + if (target_p->from->localClient->serial == current_serial) + continue; + + if (match(mask, target_p->name)) + { + /* + * if we set the serial here, then we'll never do a + * match() again, if !IsCapable() + */ + target_p->from->localClient->serial = current_serial; + found++; + + if (!IsCapable(target_p->from, cap)) + continue; + + sendto_anywhere(target_p, source_p, "%s", buffer); + } + } +} + +/* sendto_anywhere() + * + * inputs - pointer to dest client + * - pointer to from client + * - varags + * output - NONE + * side effects - less efficient than sendto_remote and sendto_one + * but useful when one does not know where target "lives" + */ +void +sendto_anywhere(struct Client *to, struct Client *from, + const char *pattern, ...) +{ + va_list args; + char buffer[IRCD_BUFSIZE]; + int len; + struct Client *send_to = (to->from != NULL ? to->from : to); + + if (IsDead(send_to)) + return; + + if (MyClient(to)) + { + if (IsServer(from)) + { + if (IsCapable(to, CAP_TS6) && HasID(from)) + len = ircsprintf(buffer, ":%s ", from->id); + else + len = ircsprintf(buffer, ":%s ", from->name); + } + else + len = ircsprintf(buffer, ":%s!%s@%s ", + from->name, from->username, from->host); + } + else len = ircsprintf(buffer, ":%s ", ID_or_name(from, send_to)); + + va_start(args, pattern); + len += send_format(&buffer[len], IRCD_BUFSIZE - len, pattern, args); + va_end(args); + + if(MyClient(to)) + send_message(send_to, buffer, len); + else + send_message_remote(send_to, from, buffer, len); +} + +/* sendto_realops_flags() + * + * inputs - flag types of messages to show to real opers + * - flag indicating opers/admins + * - var args input message + * output - NONE + * side effects - Send to *local* ops only but NOT +s nonopers. + */ +void +sendto_realops_flags(unsigned int flags, int level, const char *pattern, ...) +{ + dlink_node *ptr = NULL; + char nbuf[IRCD_BUFSIZE]; + va_list args; + + va_start(args, pattern); + vsnprintf(nbuf, IRCD_BUFSIZE, pattern, args); + va_end(args); + + DLINK_FOREACH(ptr, oper_list.head) + { + struct Client *client_p = ptr->data; + assert(HasUMode(client_p, UMODE_OPER)); + + /* If we're sending it to opers and theyre an admin, skip. + * If we're sending it to admins, and theyre not, skip. + */ + if (((level == L_ADMIN) && !HasUMode(client_p, UMODE_ADMIN)) || + ((level == L_OPER) && HasUMode(client_p, UMODE_ADMIN))) + continue; + + if (HasUMode(client_p, flags)) + sendto_one(client_p, ":%s NOTICE %s :*** Notice -- %s", + me.name, client_p->name, nbuf); + } +} + +void +sendto_globops_flags(unsigned int flags, int level, const char *pattern, ...) +{ + dlink_node *ptr = NULL; + char nbuf[IRCD_BUFSIZE]; + va_list args; + + va_start(args, pattern); + vsnprintf(nbuf, IRCD_BUFSIZE, pattern, args); + va_end(args); + + DLINK_FOREACH(ptr, oper_list.head) + { + struct Client *client_p = ptr->data; + assert(client_p->umodes & UMODE_OPER); + + /* If we're sending it to opers and theyre an admin, skip. + * If we're sending it to admins, and theyre not, skip. + */ + if (((level == L_ADMIN) && !HasUMode(client_p, UMODE_ADMIN)) || + ((level == L_OPER) && HasUMode(client_p, UMODE_ADMIN))) + continue; + + if (HasUMode(client_p, flags)) + sendto_one(client_p, ":%s NOTICE %s :*** Global -- %s", + me.name, client_p->name, nbuf); + } +} + +/* sendto_wallops_flags() + * + * inputs - flag types of messages to show to real opers + * - client sending request + * - var args input message + * output - NONE + * side effects - Send a wallops to local opers + */ +void +sendto_wallops_flags(unsigned int flags, struct Client *source_p, + const char *pattern, ...) +{ + dlink_node *ptr = NULL; + va_list args; + char buffer[IRCD_BUFSIZE]; + int len; + + if (IsClient(source_p)) + len = ircsprintf(buffer, ":%s!%s@%s WALLOPS :", + source_p->name, source_p->username, source_p->host); + else + len = ircsprintf(buffer, ":%s WALLOPS :", source_p->name); + + va_start(args, pattern); + len += send_format(&buffer[len], IRCD_BUFSIZE - len, pattern, args); + va_end(args); + + DLINK_FOREACH(ptr, oper_list.head) + { + struct Client *client_p = ptr->data; + assert(client_p->umodes & UMODE_OPER); + + if (HasUMode(client_p, flags) && !IsDefunct(client_p)) + send_message(client_p, buffer, len); + } +} + +/* ts_warn() + * + * inputs - var args message + * output - NONE + * side effects - Call sendto_realops_flags, with some flood checking + * (at most 5 warnings every 5 seconds) + */ +void +ts_warn(const char *pattern, ...) +{ + va_list args; + char buffer[IRCD_BUFSIZE]; + static time_t last = 0; + static int warnings = 0; + + /* + ** if we're running with TS_WARNINGS enabled and someone does + ** something silly like (remotely) connecting a nonTS server, + ** we'll get a ton of warnings, so we make sure we don't send + ** more than 5 every 5 seconds. -orabidoo + */ + + if (CurrentTime - last < 5) + { + if (++warnings > 5) + return; + } + else + { + last = CurrentTime; + warnings = 0; + } + + va_start(args, pattern); + vsnprintf(buffer, sizeof(buffer), pattern, args); + va_end(args); + + sendto_realops_flags(UMODE_ALL, L_ALL, "%s", buffer); + ilog(LOG_TYPE_IRCD, "%s", buffer); +} + +/* kill_client() + * + * inputs - client to send kill towards + * - pointer to client to kill + * - reason for kill + * output - NONE + * side effects - NONE + */ +void +kill_client(struct Client *client_p, struct Client *diedie, + const char *pattern, ...) +{ + va_list args; + char buffer[IRCD_BUFSIZE]; + int len; + + if (client_p->from != NULL) + client_p = client_p->from; + if (IsDead(client_p)) + return; + + len = ircsprintf(buffer, ":%s KILL %s :", ID_or_name(&me, client_p->from), + ID_or_name(diedie, client_p)); + + va_start(args, pattern); + len += send_format(&buffer[len], IRCD_BUFSIZE - len, pattern, args); + va_end(args); + + send_message(client_p, buffer, len); +} + +/* kill_client_ll_serv_butone() + * + * inputs - pointer to client to not send to + * - pointer to client to kill + * output - NONE + * side effects - Send a KILL for the given client + * message to all connected servers + * except the client 'one'. Also deal with + * client being unknown to leaf, as in lazylink... + */ +void +kill_client_ll_serv_butone(struct Client *one, struct Client *source_p, + const char *pattern, ...) +{ + va_list args; + int have_uid = 0; + dlink_node *ptr = NULL; + char buf_uid[IRCD_BUFSIZE], buf_nick[IRCD_BUFSIZE]; + int len_uid = 0, len_nick = 0; + + if (HasID(source_p)) + { + have_uid = 1; + va_start(args, pattern); + len_uid = ircsprintf(buf_uid, ":%s KILL %s :", me.id, ID(source_p)); + len_uid += send_format(&buf_uid[len_uid], IRCD_BUFSIZE - len_uid, pattern, + args); + va_end(args); + } + + va_start(args, pattern); + len_nick = ircsprintf(buf_nick, ":%s KILL %s :", me.name, source_p->name); + len_nick += send_format(&buf_nick[len_nick], IRCD_BUFSIZE - len_nick, pattern, + args); + va_end(args); + + DLINK_FOREACH(ptr, serv_list.head) + { + struct Client *client_p = ptr->data; + + if (one != NULL && (client_p == one->from)) + continue; + if (IsDefunct(client_p)) + continue; + + if (have_uid && IsCapable(client_p, CAP_TS6)) + send_message(client_p, buf_uid, len_uid); + else + send_message(client_p, buf_nick, len_nick); + } +} diff --git a/src/sprintf_irc.c b/src/sprintf_irc.c new file mode 100644 index 0000000..8a3ea56 --- /dev/null +++ b/src/sprintf_irc.c @@ -0,0 +1,472 @@ +/* + * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd). + * sprintf_irc.c: Functions for printing to a string. + * + * Copyright (C) 2002 by the past and present ircd coders, and others. + * + * 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 + * + * $Id$ + */ + +#include "stdinc.h" +#include "sprintf_irc.h" +#include "irc_string.h" + + +static const char atoi_tab[4000] = { + '0','0','0',0, '0','0','1',0, '0','0','2',0, '0','0','3',0, '0','0','4',0, + '0','0','5',0, '0','0','6',0, '0','0','7',0, '0','0','8',0, '0','0','9',0, + '0','1','0',0, '0','1','1',0, '0','1','2',0, '0','1','3',0, '0','1','4',0, + '0','1','5',0, '0','1','6',0, '0','1','7',0, '0','1','8',0, '0','1','9',0, + '0','2','0',0, '0','2','1',0, '0','2','2',0, '0','2','3',0, '0','2','4',0, + '0','2','5',0, '0','2','6',0, '0','2','7',0, '0','2','8',0, '0','2','9',0, + '0','3','0',0, '0','3','1',0, '0','3','2',0, '0','3','3',0, '0','3','4',0, + '0','3','5',0, '0','3','6',0, '0','3','7',0, '0','3','8',0, '0','3','9',0, + '0','4','0',0, '0','4','1',0, '0','4','2',0, '0','4','3',0, '0','4','4',0, + '0','4','5',0, '0','4','6',0, '0','4','7',0, '0','4','8',0, '0','4','9',0, + '0','5','0',0, '0','5','1',0, '0','5','2',0, '0','5','3',0, '0','5','4',0, + '0','5','5',0, '0','5','6',0, '0','5','7',0, '0','5','8',0, '0','5','9',0, + '0','6','0',0, '0','6','1',0, '0','6','2',0, '0','6','3',0, '0','6','4',0, + '0','6','5',0, '0','6','6',0, '0','6','7',0, '0','6','8',0, '0','6','9',0, + '0','7','0',0, '0','7','1',0, '0','7','2',0, '0','7','3',0, '0','7','4',0, + '0','7','5',0, '0','7','6',0, '0','7','7',0, '0','7','8',0, '0','7','9',0, + '0','8','0',0, '0','8','1',0, '0','8','2',0, '0','8','3',0, '0','8','4',0, + '0','8','5',0, '0','8','6',0, '0','8','7',0, '0','8','8',0, '0','8','9',0, + '0','9','0',0, '0','9','1',0, '0','9','2',0, '0','9','3',0, '0','9','4',0, + '0','9','5',0, '0','9','6',0, '0','9','7',0, '0','9','8',0, '0','9','9',0, + '1','0','0',0, '1','0','1',0, '1','0','2',0, '1','0','3',0, '1','0','4',0, + '1','0','5',0, '1','0','6',0, '1','0','7',0, '1','0','8',0, '1','0','9',0, + '1','1','0',0, '1','1','1',0, '1','1','2',0, '1','1','3',0, '1','1','4',0, + '1','1','5',0, '1','1','6',0, '1','1','7',0, '1','1','8',0, '1','1','9',0, + '1','2','0',0, '1','2','1',0, '1','2','2',0, '1','2','3',0, '1','2','4',0, + '1','2','5',0, '1','2','6',0, '1','2','7',0, '1','2','8',0, '1','2','9',0, + '1','3','0',0, '1','3','1',0, '1','3','2',0, '1','3','3',0, '1','3','4',0, + '1','3','5',0, '1','3','6',0, '1','3','7',0, '1','3','8',0, '1','3','9',0, + '1','4','0',0, '1','4','1',0, '1','4','2',0, '1','4','3',0, '1','4','4',0, + '1','4','5',0, '1','4','6',0, '1','4','7',0, '1','4','8',0, '1','4','9',0, + '1','5','0',0, '1','5','1',0, '1','5','2',0, '1','5','3',0, '1','5','4',0, + '1','5','5',0, '1','5','6',0, '1','5','7',0, '1','5','8',0, '1','5','9',0, + '1','6','0',0, '1','6','1',0, '1','6','2',0, '1','6','3',0, '1','6','4',0, + '1','6','5',0, '1','6','6',0, '1','6','7',0, '1','6','8',0, '1','6','9',0, + '1','7','0',0, '1','7','1',0, '1','7','2',0, '1','7','3',0, '1','7','4',0, + '1','7','5',0, '1','7','6',0, '1','7','7',0, '1','7','8',0, '1','7','9',0, + '1','8','0',0, '1','8','1',0, '1','8','2',0, '1','8','3',0, '1','8','4',0, + '1','8','5',0, '1','8','6',0, '1','8','7',0, '1','8','8',0, '1','8','9',0, + '1','9','0',0, '1','9','1',0, '1','9','2',0, '1','9','3',0, '1','9','4',0, + '1','9','5',0, '1','9','6',0, '1','9','7',0, '1','9','8',0, '1','9','9',0, + '2','0','0',0, '2','0','1',0, '2','0','2',0, '2','0','3',0, '2','0','4',0, + '2','0','5',0, '2','0','6',0, '2','0','7',0, '2','0','8',0, '2','0','9',0, + '2','1','0',0, '2','1','1',0, '2','1','2',0, '2','1','3',0, '2','1','4',0, + '2','1','5',0, '2','1','6',0, '2','1','7',0, '2','1','8',0, '2','1','9',0, + '2','2','0',0, '2','2','1',0, '2','2','2',0, '2','2','3',0, '2','2','4',0, + '2','2','5',0, '2','2','6',0, '2','2','7',0, '2','2','8',0, '2','2','9',0, + '2','3','0',0, '2','3','1',0, '2','3','2',0, '2','3','3',0, '2','3','4',0, + '2','3','5',0, '2','3','6',0, '2','3','7',0, '2','3','8',0, '2','3','9',0, + '2','4','0',0, '2','4','1',0, '2','4','2',0, '2','4','3',0, '2','4','4',0, + '2','4','5',0, '2','4','6',0, '2','4','7',0, '2','4','8',0, '2','4','9',0, + '2','5','0',0, '2','5','1',0, '2','5','2',0, '2','5','3',0, '2','5','4',0, + '2','5','5',0, '2','5','6',0, '2','5','7',0, '2','5','8',0, '2','5','9',0, + '2','6','0',0, '2','6','1',0, '2','6','2',0, '2','6','3',0, '2','6','4',0, + '2','6','5',0, '2','6','6',0, '2','6','7',0, '2','6','8',0, '2','6','9',0, + '2','7','0',0, '2','7','1',0, '2','7','2',0, '2','7','3',0, '2','7','4',0, + '2','7','5',0, '2','7','6',0, '2','7','7',0, '2','7','8',0, '2','7','9',0, + '2','8','0',0, '2','8','1',0, '2','8','2',0, '2','8','3',0, '2','8','4',0, + '2','8','5',0, '2','8','6',0, '2','8','7',0, '2','8','8',0, '2','8','9',0, + '2','9','0',0, '2','9','1',0, '2','9','2',0, '2','9','3',0, '2','9','4',0, + '2','9','5',0, '2','9','6',0, '2','9','7',0, '2','9','8',0, '2','9','9',0, + '3','0','0',0, '3','0','1',0, '3','0','2',0, '3','0','3',0, '3','0','4',0, + '3','0','5',0, '3','0','6',0, '3','0','7',0, '3','0','8',0, '3','0','9',0, + '3','1','0',0, '3','1','1',0, '3','1','2',0, '3','1','3',0, '3','1','4',0, + '3','1','5',0, '3','1','6',0, '3','1','7',0, '3','1','8',0, '3','1','9',0, + '3','2','0',0, '3','2','1',0, '3','2','2',0, '3','2','3',0, '3','2','4',0, + '3','2','5',0, '3','2','6',0, '3','2','7',0, '3','2','8',0, '3','2','9',0, + '3','3','0',0, '3','3','1',0, '3','3','2',0, '3','3','3',0, '3','3','4',0, + '3','3','5',0, '3','3','6',0, '3','3','7',0, '3','3','8',0, '3','3','9',0, + '3','4','0',0, '3','4','1',0, '3','4','2',0, '3','4','3',0, '3','4','4',0, + '3','4','5',0, '3','4','6',0, '3','4','7',0, '3','4','8',0, '3','4','9',0, + '3','5','0',0, '3','5','1',0, '3','5','2',0, '3','5','3',0, '3','5','4',0, + '3','5','5',0, '3','5','6',0, '3','5','7',0, '3','5','8',0, '3','5','9',0, + '3','6','0',0, '3','6','1',0, '3','6','2',0, '3','6','3',0, '3','6','4',0, + '3','6','5',0, '3','6','6',0, '3','6','7',0, '3','6','8',0, '3','6','9',0, + '3','7','0',0, '3','7','1',0, '3','7','2',0, '3','7','3',0, '3','7','4',0, + '3','7','5',0, '3','7','6',0, '3','7','7',0, '3','7','8',0, '3','7','9',0, + '3','8','0',0, '3','8','1',0, '3','8','2',0, '3','8','3',0, '3','8','4',0, + '3','8','5',0, '3','8','6',0, '3','8','7',0, '3','8','8',0, '3','8','9',0, + '3','9','0',0, '3','9','1',0, '3','9','2',0, '3','9','3',0, '3','9','4',0, + '3','9','5',0, '3','9','6',0, '3','9','7',0, '3','9','8',0, '3','9','9',0, + '4','0','0',0, '4','0','1',0, '4','0','2',0, '4','0','3',0, '4','0','4',0, + '4','0','5',0, '4','0','6',0, '4','0','7',0, '4','0','8',0, '4','0','9',0, + '4','1','0',0, '4','1','1',0, '4','1','2',0, '4','1','3',0, '4','1','4',0, + '4','1','5',0, '4','1','6',0, '4','1','7',0, '4','1','8',0, '4','1','9',0, + '4','2','0',0, '4','2','1',0, '4','2','2',0, '4','2','3',0, '4','2','4',0, + '4','2','5',0, '4','2','6',0, '4','2','7',0, '4','2','8',0, '4','2','9',0, + '4','3','0',0, '4','3','1',0, '4','3','2',0, '4','3','3',0, '4','3','4',0, + '4','3','5',0, '4','3','6',0, '4','3','7',0, '4','3','8',0, '4','3','9',0, + '4','4','0',0, '4','4','1',0, '4','4','2',0, '4','4','3',0, '4','4','4',0, + '4','4','5',0, '4','4','6',0, '4','4','7',0, '4','4','8',0, '4','4','9',0, + '4','5','0',0, '4','5','1',0, '4','5','2',0, '4','5','3',0, '4','5','4',0, + '4','5','5',0, '4','5','6',0, '4','5','7',0, '4','5','8',0, '4','5','9',0, + '4','6','0',0, '4','6','1',0, '4','6','2',0, '4','6','3',0, '4','6','4',0, + '4','6','5',0, '4','6','6',0, '4','6','7',0, '4','6','8',0, '4','6','9',0, + '4','7','0',0, '4','7','1',0, '4','7','2',0, '4','7','3',0, '4','7','4',0, + '4','7','5',0, '4','7','6',0, '4','7','7',0, '4','7','8',0, '4','7','9',0, + '4','8','0',0, '4','8','1',0, '4','8','2',0, '4','8','3',0, '4','8','4',0, + '4','8','5',0, '4','8','6',0, '4','8','7',0, '4','8','8',0, '4','8','9',0, + '4','9','0',0, '4','9','1',0, '4','9','2',0, '4','9','3',0, '4','9','4',0, + '4','9','5',0, '4','9','6',0, '4','9','7',0, '4','9','8',0, '4','9','9',0, + '5','0','0',0, '5','0','1',0, '5','0','2',0, '5','0','3',0, '5','0','4',0, + '5','0','5',0, '5','0','6',0, '5','0','7',0, '5','0','8',0, '5','0','9',0, + '5','1','0',0, '5','1','1',0, '5','1','2',0, '5','1','3',0, '5','1','4',0, + '5','1','5',0, '5','1','6',0, '5','1','7',0, '5','1','8',0, '5','1','9',0, + '5','2','0',0, '5','2','1',0, '5','2','2',0, '5','2','3',0, '5','2','4',0, + '5','2','5',0, '5','2','6',0, '5','2','7',0, '5','2','8',0, '5','2','9',0, + '5','3','0',0, '5','3','1',0, '5','3','2',0, '5','3','3',0, '5','3','4',0, + '5','3','5',0, '5','3','6',0, '5','3','7',0, '5','3','8',0, '5','3','9',0, + '5','4','0',0, '5','4','1',0, '5','4','2',0, '5','4','3',0, '5','4','4',0, + '5','4','5',0, '5','4','6',0, '5','4','7',0, '5','4','8',0, '5','4','9',0, + '5','5','0',0, '5','5','1',0, '5','5','2',0, '5','5','3',0, '5','5','4',0, + '5','5','5',0, '5','5','6',0, '5','5','7',0, '5','5','8',0, '5','5','9',0, + '5','6','0',0, '5','6','1',0, '5','6','2',0, '5','6','3',0, '5','6','4',0, + '5','6','5',0, '5','6','6',0, '5','6','7',0, '5','6','8',0, '5','6','9',0, + '5','7','0',0, '5','7','1',0, '5','7','2',0, '5','7','3',0, '5','7','4',0, + '5','7','5',0, '5','7','6',0, '5','7','7',0, '5','7','8',0, '5','7','9',0, + '5','8','0',0, '5','8','1',0, '5','8','2',0, '5','8','3',0, '5','8','4',0, + '5','8','5',0, '5','8','6',0, '5','8','7',0, '5','8','8',0, '5','8','9',0, + '5','9','0',0, '5','9','1',0, '5','9','2',0, '5','9','3',0, '5','9','4',0, + '5','9','5',0, '5','9','6',0, '5','9','7',0, '5','9','8',0, '5','9','9',0, + '6','0','0',0, '6','0','1',0, '6','0','2',0, '6','0','3',0, '6','0','4',0, + '6','0','5',0, '6','0','6',0, '6','0','7',0, '6','0','8',0, '6','0','9',0, + '6','1','0',0, '6','1','1',0, '6','1','2',0, '6','1','3',0, '6','1','4',0, + '6','1','5',0, '6','1','6',0, '6','1','7',0, '6','1','8',0, '6','1','9',0, + '6','2','0',0, '6','2','1',0, '6','2','2',0, '6','2','3',0, '6','2','4',0, + '6','2','5',0, '6','2','6',0, '6','2','7',0, '6','2','8',0, '6','2','9',0, + '6','3','0',0, '6','3','1',0, '6','3','2',0, '6','3','3',0, '6','3','4',0, + '6','3','5',0, '6','3','6',0, '6','3','7',0, '6','3','8',0, '6','3','9',0, + '6','4','0',0, '6','4','1',0, '6','4','2',0, '6','4','3',0, '6','4','4',0, + '6','4','5',0, '6','4','6',0, '6','4','7',0, '6','4','8',0, '6','4','9',0, + '6','5','0',0, '6','5','1',0, '6','5','2',0, '6','5','3',0, '6','5','4',0, + '6','5','5',0, '6','5','6',0, '6','5','7',0, '6','5','8',0, '6','5','9',0, + '6','6','0',0, '6','6','1',0, '6','6','2',0, '6','6','3',0, '6','6','4',0, + '6','6','5',0, '6','6','6',0, '6','6','7',0, '6','6','8',0, '6','6','9',0, + '6','7','0',0, '6','7','1',0, '6','7','2',0, '6','7','3',0, '6','7','4',0, + '6','7','5',0, '6','7','6',0, '6','7','7',0, '6','7','8',0, '6','7','9',0, + '6','8','0',0, '6','8','1',0, '6','8','2',0, '6','8','3',0, '6','8','4',0, + '6','8','5',0, '6','8','6',0, '6','8','7',0, '6','8','8',0, '6','8','9',0, + '6','9','0',0, '6','9','1',0, '6','9','2',0, '6','9','3',0, '6','9','4',0, + '6','9','5',0, '6','9','6',0, '6','9','7',0, '6','9','8',0, '6','9','9',0, + '7','0','0',0, '7','0','1',0, '7','0','2',0, '7','0','3',0, '7','0','4',0, + '7','0','5',0, '7','0','6',0, '7','0','7',0, '7','0','8',0, '7','0','9',0, + '7','1','0',0, '7','1','1',0, '7','1','2',0, '7','1','3',0, '7','1','4',0, + '7','1','5',0, '7','1','6',0, '7','1','7',0, '7','1','8',0, '7','1','9',0, + '7','2','0',0, '7','2','1',0, '7','2','2',0, '7','2','3',0, '7','2','4',0, + '7','2','5',0, '7','2','6',0, '7','2','7',0, '7','2','8',0, '7','2','9',0, + '7','3','0',0, '7','3','1',0, '7','3','2',0, '7','3','3',0, '7','3','4',0, + '7','3','5',0, '7','3','6',0, '7','3','7',0, '7','3','8',0, '7','3','9',0, + '7','4','0',0, '7','4','1',0, '7','4','2',0, '7','4','3',0, '7','4','4',0, + '7','4','5',0, '7','4','6',0, '7','4','7',0, '7','4','8',0, '7','4','9',0, + '7','5','0',0, '7','5','1',0, '7','5','2',0, '7','5','3',0, '7','5','4',0, + '7','5','5',0, '7','5','6',0, '7','5','7',0, '7','5','8',0, '7','5','9',0, + '7','6','0',0, '7','6','1',0, '7','6','2',0, '7','6','3',0, '7','6','4',0, + '7','6','5',0, '7','6','6',0, '7','6','7',0, '7','6','8',0, '7','6','9',0, + '7','7','0',0, '7','7','1',0, '7','7','2',0, '7','7','3',0, '7','7','4',0, + '7','7','5',0, '7','7','6',0, '7','7','7',0, '7','7','8',0, '7','7','9',0, + '7','8','0',0, '7','8','1',0, '7','8','2',0, '7','8','3',0, '7','8','4',0, + '7','8','5',0, '7','8','6',0, '7','8','7',0, '7','8','8',0, '7','8','9',0, + '7','9','0',0, '7','9','1',0, '7','9','2',0, '7','9','3',0, '7','9','4',0, + '7','9','5',0, '7','9','6',0, '7','9','7',0, '7','9','8',0, '7','9','9',0, + '8','0','0',0, '8','0','1',0, '8','0','2',0, '8','0','3',0, '8','0','4',0, + '8','0','5',0, '8','0','6',0, '8','0','7',0, '8','0','8',0, '8','0','9',0, + '8','1','0',0, '8','1','1',0, '8','1','2',0, '8','1','3',0, '8','1','4',0, + '8','1','5',0, '8','1','6',0, '8','1','7',0, '8','1','8',0, '8','1','9',0, + '8','2','0',0, '8','2','1',0, '8','2','2',0, '8','2','3',0, '8','2','4',0, + '8','2','5',0, '8','2','6',0, '8','2','7',0, '8','2','8',0, '8','2','9',0, + '8','3','0',0, '8','3','1',0, '8','3','2',0, '8','3','3',0, '8','3','4',0, + '8','3','5',0, '8','3','6',0, '8','3','7',0, '8','3','8',0, '8','3','9',0, + '8','4','0',0, '8','4','1',0, '8','4','2',0, '8','4','3',0, '8','4','4',0, + '8','4','5',0, '8','4','6',0, '8','4','7',0, '8','4','8',0, '8','4','9',0, + '8','5','0',0, '8','5','1',0, '8','5','2',0, '8','5','3',0, '8','5','4',0, + '8','5','5',0, '8','5','6',0, '8','5','7',0, '8','5','8',0, '8','5','9',0, + '8','6','0',0, '8','6','1',0, '8','6','2',0, '8','6','3',0, '8','6','4',0, + '8','6','5',0, '8','6','6',0, '8','6','7',0, '8','6','8',0, '8','6','9',0, + '8','7','0',0, '8','7','1',0, '8','7','2',0, '8','7','3',0, '8','7','4',0, + '8','7','5',0, '8','7','6',0, '8','7','7',0, '8','7','8',0, '8','7','9',0, + '8','8','0',0, '8','8','1',0, '8','8','2',0, '8','8','3',0, '8','8','4',0, + '8','8','5',0, '8','8','6',0, '8','8','7',0, '8','8','8',0, '8','8','9',0, + '8','9','0',0, '8','9','1',0, '8','9','2',0, '8','9','3',0, '8','9','4',0, + '8','9','5',0, '8','9','6',0, '8','9','7',0, '8','9','8',0, '8','9','9',0, + '9','0','0',0, '9','0','1',0, '9','0','2',0, '9','0','3',0, '9','0','4',0, + '9','0','5',0, '9','0','6',0, '9','0','7',0, '9','0','8',0, '9','0','9',0, + '9','1','0',0, '9','1','1',0, '9','1','2',0, '9','1','3',0, '9','1','4',0, + '9','1','5',0, '9','1','6',0, '9','1','7',0, '9','1','8',0, '9','1','9',0, + '9','2','0',0, '9','2','1',0, '9','2','2',0, '9','2','3',0, '9','2','4',0, + '9','2','5',0, '9','2','6',0, '9','2','7',0, '9','2','8',0, '9','2','9',0, + '9','3','0',0, '9','3','1',0, '9','3','2',0, '9','3','3',0, '9','3','4',0, + '9','3','5',0, '9','3','6',0, '9','3','7',0, '9','3','8',0, '9','3','9',0, + '9','4','0',0, '9','4','1',0, '9','4','2',0, '9','4','3',0, '9','4','4',0, + '9','4','5',0, '9','4','6',0, '9','4','7',0, '9','4','8',0, '9','4','9',0, + '9','5','0',0, '9','5','1',0, '9','5','2',0, '9','5','3',0, '9','5','4',0, + '9','5','5',0, '9','5','6',0, '9','5','7',0, '9','5','8',0, '9','5','9',0, + '9','6','0',0, '9','6','1',0, '9','6','2',0, '9','6','3',0, '9','6','4',0, + '9','6','5',0, '9','6','6',0, '9','6','7',0, '9','6','8',0, '9','6','9',0, + '9','7','0',0, '9','7','1',0, '9','7','2',0, '9','7','3',0, '9','7','4',0, + '9','7','5',0, '9','7','6',0, '9','7','7',0, '9','7','8',0, '9','7','9',0, + '9','8','0',0, '9','8','1',0, '9','8','2',0, '9','8','3',0, '9','8','4',0, + '9','8','5',0, '9','8','6',0, '9','8','7',0, '9','8','8',0, '9','8','9',0, + '9','9','0',0, '9','9','1',0, '9','9','2',0, '9','9','3',0, '9','9','4',0, + '9','9','5',0, '9','9','6',0, '9','9','7',0, '9','9','8',0, '9','9','9',0 +}; + +static char scratch_buffer[32]; + +/* + * sprintf_irc + * + * sprintf_irc is optimized for the formats: %c, %s, %lu, %d and %u. + * Where %lu actually equals %l09u (for printing time_t timestamps). + * + * sprintf_irc is NOT optimized for any other format and resorts to using + * the normal sprintf when it encounters a format it doesn't understand + * (including padding, width, precision etc). + * + * The following benchmark was measured on a PPro200 with linux 2.0.30, + * libc 5.4.28, compiled with gcc-2.7.2.1 with -O3. + * + * Format sprintf sprintf_irc Speed up factor + * + * "12345678901234567890" 3.385 us 0.859 us 3.94 + * "%s", buffer (20 chars) 3.780 us 0.547 us 6.91 + * "%c%c%c", c1, c2, c3 3.640 us 0.376 us 9.68 + * "%lu", (time_t)t 5.851 us 0.842 us 6.95 + * + * Less important: + * "%d", 31337 4.487 us 0.852 us 5.27 + * "%u.%u.%u.%u", 9.069 us 2.431 us 3.73 + * + * Not used: + * "%03d", 401 4.348 us + * "%N" 0.216 us 20.13 + * + * --Run + */ + +int +vsprintf_irc(char *str, const char *format, va_list args) +{ + char c; + int bytes = 0; + + while ((c = *format++)) + { + if (c == '%') + { + c = *format++; /* May never be '\0' ! */ + + if (c == 's') + { + const char *p1 = va_arg(args, const char *); + if ((*str = *p1)) + { + ++bytes; + while ((*++str = *++p1)) + ++bytes; + } + + continue; + } + + if (c == 'c') + { + *str++ = (char) va_arg(args, int); + ++bytes; + + continue; + } + + /* + * Prints time_t value in interval + * [ 100000000 , 4294967295 ] + * Actually prints like "%09lu" + */ + if (c == 'l' && *format == 'u') + { + unsigned long v1, v2; + const char *ap; + + ++format; + v1 = va_arg(args, unsigned long); + if (v1 == 0) + { + *str++ = '0'; + ++bytes; + continue; + } + if (v1 > 999999999L) + { + v2 = v1 / 1000000000; + v1 -= v2 * 1000000000; + *str++ = '0' + v2; + ++bytes; + } + + v2 = v1 / 1000000; + v1 -= v2 * 1000000; + ap = atoi_tab + (v2 << 2); + *str++ = *ap++; + *str++ = *ap++; + *str++ = *ap; + v2 = v1 / 1000; + v1 -= v2 * 1000; + ap = atoi_tab + (v2 << 2); + *str++ = *ap++; + *str++ = *ap++; + *str++ = *ap; + ap = atoi_tab + (v1 << 2); + *str++ = *ap++; + *str++ = *ap++; + *str++ = *ap; + + bytes += 9; + + continue; + } + if (c == 't') + { + unsigned int v1; + + v1 = va_arg(args,int); + + *str++ = (v1/10) + '0'; + *str++ = v1%10 + '0'; + + bytes += 2; + + continue; + } + + if (c == 'd') + { + unsigned int v1, v2; + const char *ap; + char *s = &scratch_buffer[sizeof(scratch_buffer) - 2]; + + v1 = va_arg(args, int); + if ((int)v1 <= 0) + { + if (v1 == 0) + { + *str++ = '0'; + ++bytes; + continue; + } + *str++ = '-'; + ++bytes; + v1 = -v1; + } + + do + { + v2 = v1 / 1000; + ap = atoi_tab + 2 + ((v1 - 1000 * v2) << 2); + *s-- = *ap--; + *s-- = *ap--; + *s-- = *ap; + } + while ((v1 = v2) > 0); + + while ('0' == *++s); + + *str = *s; + ++bytes; + + while ((*++str = *++s)) + ++bytes; + + continue; + } + + if (c == 'u') + { + unsigned int v1, v2; + const char *ap; + char *s = &scratch_buffer[sizeof(scratch_buffer) - 2]; + + v1 = va_arg(args, unsigned int); + if (v1 == 0) + { + *str++ = '0'; + ++bytes; + continue; + } + + do + { + v2 = v1 / 1000; + ap = atoi_tab + 2 + ((v1 - 1000 * v2) << 2); + *s-- = *ap--; + *s-- = *ap--; + *s-- = *ap; + } + while ((v1 = v2) > 0); + + while ('0' == *++s); + + *str = *s; + ++bytes; + + while ((*++str = *++s)) + ++bytes; + + continue; + } + + if (c != '%') + { + int ret; + + format -= 2; + ret = vsprintf(str, format, args); + str += ret; + bytes += ret; + + break; + } + } + + *str++ = c; + ++bytes; + } + + *str = '\0'; + + return(bytes); +} /* vsprintf_irc() */ + +int +ircsprintf(char *str, const char *format, ...) +{ + va_list args; + int bytes; + + va_start(args, format); + + bytes = vsprintf_irc(str, format, args); + + va_end(args); + + return(bytes); +} /* ircsprintf() */ + diff --git a/src/version.c b/src/version.c new file mode 100644 index 0000000..f80cca5 --- /dev/null +++ b/src/version.c @@ -0,0 +1,105 @@ +/* + * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd). + * + * Copyright (C) 2002 by the past and present ircd coders, and others. + * + * 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 + * + * $Id$ + */ + +#include "patchlevel.h" +#include "serno.h" +#include "ircd.h" + +const char *ircd_version = PATCHLEVEL; +const char *serno = SERIALNUM; + +const char *infotext[] = +{ + "IRC --", + "Based on the original code written by Jarkko Oikarinen", + "Copyright 1988, 1989, 1990, 1991 University of Oulu, Computing Center", + "Copyright (c) 1997-2012 Hybrid Development Team", + "", + "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, or", + "(at your option) any later version.", + "", + "", + "The hybrid team is a group of ircd coders who were frustrated", + "with the instability and all-out dirtiness of the EFnet ircd's", + "available. hybrid is the name for the collective efforts of a group", + "of people, all of us.", + "", + "Anyone is welcome to contribute to this effort. You are encouraged", + "to participate in the Hybrid mailing list. To subscribe to the", + "Hybrid List, use this link:", + " https://lists.ircd-hybrid.org/mailman/listinfo/hybrid", + "", + "The core team as, of this major release:", + "", + "billy-jon, William Bierman III <bill@mu.org>", + "cryogen, Stuart Walsh <stu@ipng.org.uk>", + "Dianora, Diane Bruce <db@db.net>", + "metalrock, Jack Low <jclow@csupomona.edu>", + "Michael, Michael Wobst <michael@wobst.at>", + "Rodder, Jon Lusky <lusky@blown.net>", + "Wohali, Joan Touzet <joant@ieee.org>", + "", + "The following people have contributed blood, sweat, and/or code to", + "recent releases of Hybrid, in nick alphabetical order:", + "", + "A1kmm, Andrew Miller <a1kmm@mware.virtualave.net>", + "adx, Piotr Nizynski <nizynski@sysplex.pl>", + "AndroSyn, Aaron Sethman <androsyn@ratbox.org>", + "bane, Dragan Dosen <bane@idolnet.org>", + "bysin, Ben Kittridge <bkittridge@cfl.rr.com>", + "cosine, Patrick Alken <wnder@uwns.underworld.net>", + "David-T, David Taylor <davidt@yadt.co.uk>", + "fgeek, Henri Salo <henri@nerv.fi>", + "fl, Lee Hardy <lee@leeh.co.uk>", + "Garion, Joost Vunderink <garion@efnet.nl>", + "Habeeb, David Supuran <habeeb@cfl.rr.com>", + "Hwy101, W. Campbell <wcampbel@botbay.net>", + "jmallett, Juli Mallett <jmallett@FreeBSD.org>", + "joshk, Joshua Kwan <joshk@triplehelix.org>", + "jv, Jakub Vlasek <jv@pilsedu.cz>", + "k9, Jeremy Chadwick <ircd@jdc.parodius.com>", + "kire, Erik Small <smalle@hawaii.edu>", + "knight, Alan LeVee <alan.levee@prometheus-designs.net>", + "kre, Dinko Korunic <kreator@fly.srk.fer.hr>", + "madmax, Paul Lomax <madmax@efnet.org>", + "nenolod, William Pitcock <nenolod@nenolod.net>", + "Riedel, Dennis Vink, <riedel@chaotic.nl>", + "scuzzy, David Todd <scuzzy@aniverse.net>", + "spookey, David Colburn <spookey@spookey.org>", + "TimeMr14C, Yusuf Iskenderoglu <uhc0@stud.uni-karlsruhe.de>", + "toot, Toby Verrall <to7@antipope.fsnet.co.uk>", + "vx0, Mark Miller <mark@oc768.net>", + "wiz, Jason Dambrosio <jason@wiz.cx>", + "Xride, Søren Straarup <xride@x12.dk>", + "zb^3, Alfred Perlstein <alfred@freebsd.org>", + "", + "Others are welcome. Always. And if we left anyone off the above list,", + "be sure to let us know that too. Many others have contributed to", + "previous versions of this ircd and its ancestors, too many to list", + "here.", + "", + "Send bug fixes/complaints/rotten tomatoes to bugs@ircd-hybrid.org.", + "", 0 +}; diff --git a/src/watch.c b/src/watch.c new file mode 100644 index 0000000..ba7db13 --- /dev/null +++ b/src/watch.c @@ -0,0 +1,235 @@ +/* + * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd). + * + * Copyright (C) 1997 Jukka Santala (Donwulff) + * Copyright (C) 2005 by the Hybrid Development Team. + * + * 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 + */ + +/*! \file watch.c + * \brief File including functions for WATCH support + * \version $Id$ + */ + +#include "stdinc.h" +#include "list.h" +#include "balloc.h" +#include "s_user.h" +#include "s_misc.h" +#include "client.h" +#include "hash.h" +#include "irc_string.h" +#include "sprintf_irc.h" +#include "ircd.h" +#include "numeric.h" +#include "conf.h" +#include "s_serv.h" +#include "send.h" +#include "supported.h" +#include "whowas.h" +#include "memory.h" +#include "packet.h" +#include "watch.h" + +#define WATCH_HEAP_SIZE 32 + +static dlink_list watchTable[HASHSIZE]; + +static BlockHeap *watch_heap = NULL; + +/*! \brief Initializes the watch table + */ +void +watch_init(void) +{ + watch_heap = BlockHeapCreate("watch", sizeof(struct Watch), WATCH_HEAP_SIZE); +} + +/* + * Rough figure of the datastructures for watch: + * + * NOTIFY HASH client_p1 + * | |- nick1 + * nick1-|- client_p1 |- nick2 + * | |- client_p2 client_p3 + * | |- client_p3 client_p2 |- nick1 + * | |- nick1 + * nick2-|- client_p2 |- nick2 + * |- client_p1 + */ + +/*! \brief Counts up memory used by watch list headers + */ +void +watch_count_memory(unsigned int *const count, uint64_t *const memory) +{ + unsigned int idx; + + for (idx = 0; idx < HASHSIZE; ++idx) + *count += dlink_list_length(&watchTable[idx]); + + *memory = *count * sizeof(struct Watch); +} + +/*! \brief Notifies all clients that have client_p's nick name on + * their watch list. + * \param client_p pointer to Client struct + * \param reply numeric to send. Either RPL_LOGON or RPL_LOGOFF + */ +void +watch_check_hash(struct Client *client_p, int reply) +{ + struct Watch *anptr = NULL; + dlink_node *ptr = NULL; + assert(IsClient(client_p)); + if ((anptr = watch_find_hash(client_p->name)) == NULL) + return; /* This nick isn't on watch */ + + /* Update the time of last change to item */ + anptr->lasttime = CurrentTime; + + /* Send notifies out to everybody on the list in header */ + DLINK_FOREACH(ptr, anptr->watched_by.head) + { + struct Client *target_p = ptr->data; + + sendto_one(target_p, form_str(reply), + me.name, target_p->name, client_p->name, + client_p->username, client_p->host, + anptr->lasttime, client_p->info); + } +} + +/*! \brief Looks up the watch table for a given nick + * \param name nick name to look up + */ +struct Watch * +watch_find_hash(const char *name) +{ + dlink_node *ptr = NULL; + + DLINK_FOREACH(ptr, watchTable[strhash(name)].head) + { + struct Watch *anptr = ptr->data; + + if (!irccmp(anptr->nick, name)) + return anptr; + } + + return NULL; +} + +/*! \brief Adds a watch entry to client_p's watch list + * \param nick nick name to add + * \param client_p Pointer to Client struct + */ +void +watch_add_to_hash_table(const char *nick, struct Client *client_p) +{ + struct Watch *anptr = NULL; + dlink_node *ptr = NULL; + + /* If found NULL (no header for this nick), make one... */ + if ((anptr = watch_find_hash(nick)) == NULL) + { + anptr = BlockHeapAlloc(watch_heap); + anptr->lasttime = CurrentTime; + strlcpy(anptr->nick, nick, sizeof(anptr->nick)); + + dlinkAdd(anptr, &anptr->node, &watchTable[strhash(nick)]); + } + else + { + /* Is this client already on the watch-list? */ + ptr = dlinkFind(&anptr->watched_by, client_p); + } + + if (ptr == NULL) + { + /* No it isn't, so add it in the bucket and client addint it */ + dlinkAdd(client_p, make_dlink_node(), &anptr->watched_by); + dlinkAdd(anptr, make_dlink_node(), &client_p->localClient->watches); + } +} + +/*! \brief Removes a single entry from client_p's watch list + * \param nick nick name to remove + * \param client_p Pointer to Client struct + */ +void +watch_del_from_hash_table(const char *nick, struct Client *client_p) +{ + struct Watch *anptr = NULL; + dlink_node *ptr = NULL; + + if ((anptr = watch_find_hash(nick)) == NULL) + return; /* No header found for that nick. i.e. it's not being watched */ + + if ((ptr = dlinkFind(&anptr->watched_by, client_p)) == NULL) + return; /* This nick isn't being watched by client_p */ + + dlinkDelete(ptr, &anptr->watched_by); + free_dlink_node(ptr); + + if ((ptr = dlinkFindDelete(&client_p->localClient->watches, anptr))) + free_dlink_node(ptr); + + /* In case this header is now empty of notices, remove it */ + if (anptr->watched_by.head == NULL) + { + assert(dlinkFind(&watchTable[strhash(nick)], anptr) != NULL); + dlinkDelete(&anptr->node, &watchTable[strhash(nick)]); + BlockHeapFree(watch_heap, anptr); + } +} + +/*! \brief Removes all entries from client_p's watch list + * and deletes headers that are no longer being watched. + * \param client_p Pointer to Client struct + */ +void +watch_del_watch_list(struct Client *client_p) +{ + dlink_node *ptr = NULL, *ptr_next = NULL; + dlink_node *tmp = NULL; + + DLINK_FOREACH_SAFE(ptr, ptr_next, client_p->localClient->watches.head) + { + struct Watch *anptr = ptr->data; + + assert(anptr); + + assert(dlinkFind(&anptr->watched_by, client_p) != NULL); + if ((tmp = dlinkFindDelete(&anptr->watched_by, client_p))) + free_dlink_node(tmp); + + /* If this leaves a header without notifies, remove it. */ + if (anptr->watched_by.head == NULL) + { + assert(dlinkFind(&watchTable[strhash(anptr->nick)], anptr) != NULL); + dlinkDelete(&anptr->node, &watchTable[strhash(anptr->nick)]); + + BlockHeapFree(watch_heap, anptr); + } + + dlinkDelete(ptr, &client_p->localClient->watches); + free_dlink_node(ptr); + } + + assert(client_p->localClient->watches.head == NULL); + assert(client_p->localClient->watches.tail == NULL); +} diff --git a/src/whowas.c b/src/whowas.c new file mode 100644 index 0000000..7d0e087 --- /dev/null +++ b/src/whowas.c @@ -0,0 +1,142 @@ +/* + * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd). + * whowas.c: WHOWAS user cache. + * + * Copyright (C) 2005 by the past and present ircd coders, and others. + * + * 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 + * + * $Id$ + */ + +#include "stdinc.h" +#include "list.h" +#include "whowas.h" +#include "client.h" +#include "hash.h" +#include "irc_string.h" +#include "ircd.h" + + +static struct Whowas WHOWAS[NICKNAMEHISTORYLENGTH]; +dlink_list WHOWASHASH[HASHSIZE]; + + +void +add_history(struct Client *client_p, int online) +{ + static unsigned int whowas_next = 0; + struct Whowas *who = &WHOWAS[whowas_next]; + + assert(client_p && client_p->servptr); + + if (++whowas_next == NICKNAMEHISTORYLENGTH) + whowas_next = 0; + + if (who->hashv != -1) + { + if (who->online) + dlinkDelete(&who->cnode, &who->online->whowas); + + dlinkDelete(&who->tnode, &WHOWASHASH[who->hashv]); + } + + who->hashv = strhash(client_p->name); + who->logoff = CurrentTime; + + strlcpy(who->name, client_p->name, sizeof(who->name)); + strlcpy(who->username, client_p->username, sizeof(who->username)); + strlcpy(who->hostname, client_p->host, sizeof(who->hostname)); + strlcpy(who->realname, client_p->info, sizeof(who->realname)); + strlcpy(who->servername, client_p->servptr->name, sizeof(who->servername)); + + if (online) + { + who->online = client_p; + dlinkAdd(who, &who->cnode, &client_p->whowas); + } + else + who->online = NULL; + + dlinkAdd(who, &who->tnode, &WHOWASHASH[who->hashv]); +} + +void +off_history(struct Client *client_p) +{ + dlink_node *ptr = NULL, *ptr_next = NULL; + + DLINK_FOREACH_SAFE(ptr, ptr_next, client_p->whowas.head) + { + struct Whowas *temp = ptr->data; + + temp->online = NULL; + dlinkDelete(&temp->cnode, &client_p->whowas); + } +} + +struct Client * +get_history(const char *nick, time_t timelimit) +{ + dlink_node *ptr = NULL; + + timelimit = CurrentTime - timelimit; + + DLINK_FOREACH(ptr, WHOWASHASH[strhash(nick)].head) + { + struct Whowas *temp = ptr->data; + + if (temp->logoff < timelimit) + continue; + if (irccmp(nick, temp->name)) + continue; + return temp->online; + } + + return NULL; +} + +void +count_whowas_memory(unsigned int *wwu, uint64_t *wwum) +{ + const struct Whowas *tmp; + int i; + unsigned int u = 0; + uint64_t um = 0; + + /* count the number of used whowas structs in 'u' */ + /* count up the memory used of whowas structs in um */ + for (i = 0, tmp = &WHOWAS[0]; i < NICKNAMEHISTORYLENGTH; ++i, ++tmp) + { + if (tmp->hashv != -1) + { + ++u; + um += sizeof(struct Whowas); + } + } + + *wwu = u; + *wwum = um; +} + +void +whowas_init(void) +{ + unsigned int idx; + + for (idx = 0; idx < NICKNAMEHISTORYLENGTH; ++idx) + WHOWAS[idx].hashv = -1; +} |