diff --git a/net/znc/Makefile b/net/znc/Makefile new file mode 100644 index 0000000000..349cffbe9f --- /dev/null +++ b/net/znc/Makefile @@ -0,0 +1,289 @@ +# +# Copyright (C) 2009-2010 OpenWrt.org +# +# This is free software, licensed under the GNU General Public License v2. +# See /LICENSE for more information. +# + +include $(TOPDIR)/rules.mk + +PKG_NAME:=znc +PKG_VERSION:=1.2 +PKG_RELEASE:=1 + +PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz +PKG_SOURCE_URL:=http://znc.in/releases \ + http://znc.in/releases/archive +PKG_MD5SUM:=ef18e5402a82cc3fcab5c2ac5c2e6f3b + +PKG_MAINTAINER:=Jonas Gorski +PKG_LICENSE:=Apache-2.0 +PKG_LICENSE_FILES:=LICENSE + +PKG_BUILD_PARALLEL:=1 + + +define Package/znc/default + SUBMENU:=Instant Messaging + SECTION:=net + CATEGORY:=Network + TITLE:=ZNC + URL:=http://en.znc.in/ +endef + +define Package/znc + $(Package/znc/default) + DEPENDS:=+libopenssl +libpthread $(CXX_DEPENDS) + MENU:=1 +endef + +define Package/znc/description + ZNC is an IRC bouncer with many advanced features like detaching, + multiple users, per channel playback buffer, SSL, IPv6, transparent DCC + bouncing, and c++ module support to name a few. +endef + +define Package/znc/conffiles +/etc/config/znc +endef + + +define Package/znc/install + $(INSTALL_DIR) $(1)/usr/bin + $(INSTALL_BIN) $(PKG_BUILD_DIR)/znc $(1)/usr/bin/ + $(INSTALL_DIR) $(1)/etc/init.d + $(INSTALL_BIN) ./files/znc.init $(1)/etc/init.d/znc + $(INSTALL_DIR) $(1)/etc/config + $(INSTALL_DATA) ./files/znc.conf $(1)/etc/config/znc + $(INSTALL_DIR) $(1)/usr/lib/znc/ + $(INSTALL_BIN) $(PKG_BUILD_DIR)/modules/droproot.so $(1)/usr/lib/znc/ +endef + + +ZNC_MODULES := +ZNC_MODULE_TARGETS := droproot.so + +define module + define Package/znc-mod-$(strip $(1)) + $(Package/znc/default) + TITLE+= ($(strip $(1)) plugin) + DEPENDS:=znc + endef + + define Package/znc-mod-$(strip $(1))/description + $(strip $(2)) + endef + + define Package/znc-mod-$(strip $(1))/install + $(INSTALL_DIR) $$(1)/usr/lib/znc/ + $(INSTALL_BIN) $$(PKG_BUILD_DIR)/modules/$(subst -,_,$(strip $(1))).so $$(1)/usr/lib/znc/ + # include webadmin page templates if existing + if [ -d $$(PKG_BUILD_DIR)/modules/data/$(subst -,_,$(strip $(1))) ]; then \ + $(INSTALL_DIR) $$(1)/usr/share/znc/modules ;\ + $(CP) -r $$(PKG_BUILD_DIR)/modules/data/$(subst -,_,$(strip $(1))) $$(1)/usr/share/znc/modules ;\ + fi + endef + + ZNC_MODULES += znc-mod-$(strip $(1)) + $(if $(CONFIG_PACKAGE_znc-mod-$(strip $(1))),ZNC_MODULE_TARGETS += $(subst -,_,$(strip $(1))).so) +endef + +define webadmin + define Package/znc-mod-webadmin + $(Package/znc/default) + TITLE+= (webadmin plugin) + DEPENDS:=znc + endef + + define Package/znc-mod-webadmin/description + Allows you to add/remove/edit users and settings on the fly via a web browser. + endef + + define Package/znc-mod-webadmin/install + $(INSTALL_DIR) $$(1)/usr/lib/znc/ + $(INSTALL_BIN) $$(PKG_BUILD_DIR)/modules/webadmin.so $$(1)/usr/lib/znc/ + $(INSTALL_DIR) $$(1)/usr/share/znc/modules + $(CP) -r $$(PKG_BUILD_DIR)/modules/data/webadmin $$(1)/usr/share/znc/modules + $(INSTALL_DIR) $$(1)/usr/share/znc/webskins/ + $(CP) -r $$(PKG_BUILD_DIR)/webskins/_default_ $$(1)/usr/share/znc/webskins/ + endef + + ZNC_MODULES += znc-mod-webadmin + $(if $(CONFIG_PACKAGE_znc-mod-webadmin),ZNC_MODULE_TARGETS += webadmin.so) +endef + +define webskin + define Package/znc-webskin-$(strip $(1)) + $(Package/znc/default) + TITLE+= ($(strip $(1)) webskin) + DEPENDS:=znc-mod-webadmin + endef + + define Package/znc-webskin-$(strip $(1))/description + $(strip $(1)) webskin for webadmin + endef + + define Package/znc-webskin-$(strip $(1))/install + $(INSTALL_DIR) $$(1)/usr/share/znc/webskins/ + $(CP) -r $$(PKG_BUILD_DIR)/webskins/$(strip $(1)) $$(1)/usr/share/znc/webskins/ + endef + ZNC_MODULES += znc-webskin-$(strip $(1)) +endef + +, := , + +$(eval $(call module,adminlog,Log user connects and disconnects and failed \ + logins to file or syslog.)) + +$(eval $(call module,autoattach,Reattaches you to channels on activity.)) + +$(eval $(call module,autocycle,Cycles a channel when you are the only one in \ + there and you don't have op.)) + +$(eval $(call module,autoop,Auto op the good guys.)) + +$(eval $(call module,autoreply,Gives a automatic reply if someone messages you \ + if you are away.)) + +$(eval $(call module,autovoice,Autovoices everyone who joins some channel.)) + +$(eval $(call module,awaynick,Change your nick while you are away.)) + +$(eval $(call module,awaystore,Stores messages while away$(,) also auto away.)) + +$(eval $(call module,block-motd,This module blocks the server's Message of the \ + Day.)) + +$(eval $(call module,blockuser,Blocks certain users from using ZNC saying \ + their account was disabled.)) + +$(eval $(call module,bouncedcc,Bounces dcc transfers through the znc server \ + instead of sending them directly to the user.)) + +$(eval $(call module,buffextras,Add nick changes$(,) joins$(,) parts$(,) topic \ + changes etc. to your playback buffer.)) + +$(eval $(call module,cert,Use a SSL certificate for connecting to a server.)) + +$(eval $(call module,certauth,This module allows users to log in to ZNC via \ + SSL client keys.)) + +$(eval $(call module,chansaver,Keeping config up to date when user joins and \ + parts.)) + +$(eval $(call module,clearbufferonmsg,This module keeps the buffer until the \ + next message from the client.)) + +$(eval $(call module,clientnotify,Notify about new incoming connections to \ + your user.)) + +$(eval $(call module,controlpanel,Allows you to add/remove/edit users and \ + settings on the fly via IRC messages.)) + +$(eval $(call module,crypt,Encryption for channel/private messages.)) + +$(eval $(call module,ctcpflood,This module tries to block ctcp floods.)) + +$(eval $(call module,dcc,Allows you to transfer files to and from ZNC.)) + +$(eval $(call module,disconkick,This module will kick your client from all \ + channels where you are$(,) in case if ZNC disconnects from server.)) + +$(eval $(call module,fail2ban,Block IPs for some time after a failed login.)) + +$(eval $(call module,flooddetach,This module detaches you from channels which \ + are flooded.)) + +$(eval $(call module,identfile,Places the ident of a user to a file when they \ + are trying to connect.)) + +$(eval $(call module,keepnick,Tries to get you your primary nick.)) + +$(eval $(call module,kickrejoin,Implements auto-rejoin-on-kick.)) + +$(eval $(call module,lastseen,Logs when a user last logged in to ZNC.)) + +$(eval $(call module,listsockets,This module displays a list of all open \ + sockets in ZNC.)) + +$(eval $(call module,log,Log conversations to file.)) + +$(eval $(call module,modules_online,This module fakes the online status of \ + ZNC-*users.)) + +$(eval $(call module,nickserv,Auths you with NickServ.)) + +$(eval $(call module,notes,This modules stores and displays short notes using \ + a key/note pairs and shows them to you on connect.)) + +$(eval $(call module,notify-connect,Sends a notice to all admins when a user \ + logs in or out.)) + +$(eval $(call module,partyline,Allows ZNC users to join internal channels and \ + query other ZNC users on the same ZNC.)) + +$(eval $(call module,perform,Performs commands on connect.)) + +$(eval $(call module,q,Auths you with Q (and a little more).)) + +$(eval $(call module,raw,View all of the raw traffic.)) + +$(eval $(call module,route-replies,Routes back answers to the right client \ + when connected with multiple clients.)) + +$(eval $(call module,sasl,The SASL module allows you to authenticate to an \ + IRC network via SASL.)) + +$(eval $(call module,savebuff,Saves your channel buffers into an encrypted \ + file so they can survive restarts and reboots.)) + +$(eval $(call module,schat,SSL (encrypted) DCC chats.)) + +$(eval $(call module,send-raw,Allows you to send raw traffic to IRC from \ + other users.)) + +$(eval $(call module,simple-away,This module will automatically set you away \ + on IRC while you are disconnected from the bouncer.)) + +$(eval $(call module,shell,Have your unix shell in a query window right inside \ + of your IRC client.)) + +$(eval $(call module,stickychan,Keeps you sticked to specific channels.)) + +$(eval $(call module,watch,Monitor activity for specific text patterns from \ + specific users and have the text sent to a special query window.)) + +$(eval $(call webadmin)) + +$(eval $(call webskin,dark-clouds)) +$(eval $(call webskin,forest)) +$(eval $(call webskin,ice)) + +PKG_CONFIG_DEPENDS := $(patsubst %,CONFIG_PACKAGE_%,$(ZNC_MODULES)) + +include $(INCLUDE_DIR)/uclibc++.mk +include $(INCLUDE_DIR)/package.mk + +CONFIGURE_VARS += \ + CXXFLAGS="$(TARGET_CFLAGS) -fno-builtin -fno-rtti -nostdinc++" \ + CPPFLAGS="-I$(STAGING_DIR)/usr/include -I$(STAGING_DIR)/include" \ + LDFLAGS="-nodefaultlibs -lc -L$(STAGING_DIR)/usr/lib -L$(STAGING_DIR)/lib" \ + LIBS="-luClibc++ -lm -lssl -lcrypto $(LIBGCC_S) -lc" + +CONFIGURE_ARGS += \ + --disable-c-ares \ + --disable-perl + +define Build/Configure + $(call Build/Configure/Default,) + $(call libtool_disable_rpath) +endef + +define Build/Compile + $(call Build/Compile/Default,znc) + +$(MAKE_VARS) $(MAKE) $(PKG_JOBS) -C $(PKG_BUILD_DIR)/modules \ + $(MAKE_FLAGS) $(ZNC_MODULE_TARGETS) +endef + +$(eval $(call BuildPackage,znc)) +$(foreach m,$(ZNC_MODULES),$(eval $(call BuildPackage,$(m)))) diff --git a/net/znc/files/znc.conf b/net/znc/files/znc.conf new file mode 100644 index 0000000000..1b0d842a53 --- /dev/null +++ b/net/znc/files/znc.conf @@ -0,0 +1,29 @@ +config znc + # where to listen for connections + list listener '192.168.1.1 1234' + # If using SSL sockets, use the following certifcate: + # option znc_ssl_cert '/etc/znc.cert' + + # load global modules (You need to install them first): + # list module 'fail2ban' + + # remove this to enable the service + option disabled 1 + +config user 'sampleUser' + # Use either a plain text password or use the full sha256#... line. + # You can generate one with 'znc -s'. + option password 'changeme' + option nick 'sampleUser' + option altnick 'userSample' + option ident 'openwrt' + option realname 'John Doe' + + # This adds support for channels in znc configuration: + # list channel '#chan optional_password' + + # list of allowed servers: + # list server 'chat.freenode.net 6667' + + # load user modules (' [params...]'): + # list module 'simple_away -timer 10 disconnected' diff --git a/net/znc/files/znc.init b/net/znc/files/znc.init new file mode 100644 index 0000000000..7cc7fa70fd --- /dev/null +++ b/net/znc/files/znc.init @@ -0,0 +1,194 @@ +#!/bin/sh /etc/rc.common +# Copyright (C) 2010 Openwrt.org + +START=60 + +ZNC_CONFIG_PATH=/tmp/etc/znc +PID_FILE=${ZNC_CONFIG_PATH}/znc.pid +ZNC_CONFIG=${ZNC_CONFIG_PATH}/configs/znc.conf + +EXTERNAL_CONFIG=0 +DISABLED= + +RUNAS_USER= +RUNAS_GROUP= + +add_param() { + echo "$1 = $2" >> $ZNC_CONFIG +} + +add_chan() { + chan=${1% *} + pass=${1#* } + echo " " >> $ZNC_CONFIG + [ "$chan" != "$pass" ] && echo " Key = $pass" >> $ZNC_CONFIG + echo " " >> $ZNC_CONFIG +} + +add_network() { + local current_user="$1" + local network="$2" + local user + local name + + config_get user "$network" user + + [ "$user" = "$current_user" ] || return 0 + + config_get name "$network" name + echo " " >> $ZNC_CONFIG + config_list_foreach "$network" server "add_param \" Server\"" + config_list_foreach "$network" channel "add_chan" +} + +znc_global() { + local znc="$1" + local anoniplimit + local maxbuffersize + local connectdelay + local serverthrottle + local znc_config_path + local znc_pem_file + + config_get_bool DISABLED "$znc" disabled 0 + + [ "$DISABLED" -eq 0 ] || return 0 + + config_get znc_config_path "$znc" znc_config_path + + config_get RUNAS_USER "$znc" runas_user + config_get RUNAS_GROUP "$znc" runas_group + + if [ "${znc_config_path}" ] + then + ZNC_CONFIG_PATH=$znc_config_path + EXTERNAL_CONFIG=1 + else + mkdir -p $ZNC_CONFIG_PATH/configs/ + [ ! -f "$ZNC_CONFIG" ] || rm "$ZNC_CONFIG" + + add_param "Version" "1.0" + + config_get anoniplimit "$znc" anoniplimit + config_get maxbuffersize "$znc" maxbuffersize + config_get connectdelay "$znc" connectdelay + config_get serverthrottle "$znc" serverthrottle + config_get znc_pem_file "$znc" znc_ssl_cert + + [ -z "$znc_pem_file" ] || ln -sf "$znc_pem_file" $ZNC_CONFIG_PATH/znc.pem + + [ -z $anoniplimit ] || echo "AnonIPLimit = $anoniplimit" >> $ZNC_CONFIG + [ -z $maxbuffersize ] || echo "MaxBufferSize = $maxbuffersize" >> $ZNC_CONFIG + [ -z $connectdelay ] || echo "ConnectDelay = $connectdelay" >> $ZNC_CONFIG + [ -z $serverthrottle ] || echo "ServerThrottle = $anoniplimit" >> $ZNC_CONFIG + + echo "PidFile = $PID_FILE" >> $ZNC_CONFIG + + config_list_foreach "$znc" listener "add_param Listener" + config_list_foreach "$znc" module "add_param LoadModule" + + add_param LoadModule "droproot ${RUNAS_USER:-nobody} ${RUNAS_GROUP:-nogroup}" + fi +} + +add_user() { + local user="$1" + local password + local nick + local altnick + local ident + local realname + local buffer + local quitmsg + local chanmodes + local vhost + local server + + config_get password "$user" password + config_get nick "$user" nick + config_get altnick "$user" altnick + config_get ident "$user" ident + config_get realname "$user" realname + config_get buffer "$user" buffer + config_get quitmsg "$user" quitmsg + config_get chanmodes "$user" chanmodes + config_get vhost "$user" vhost + config_get server "$user" server + + echo "" >> $ZNC_CONFIG + + case "$password" in + "md5#"* | "sha256#"* | "plain#"*) + add_param " Pass" "$password" + ;; + *) + add_param " Pass" "plain#$password" + ;; + esac + + add_param " Nick" "$nick" + add_param " AltNick" "${altnick:-$nick"_"}" + add_param " Ident" "${ident:-$nick}" + add_param " RealName" "${realname:-$nick}" + [ -z "$vhost" ] || add_param " VHost" "$vhost" + add_param " Buffer" "${buffer:-50}" + add_param " KeepBuffer" "false" + add_param " ChanModes" "${chanmodes:-"+stn"}" + [ -z "$quitmsg" ] || add_param " QuitMsg" "$quitmsg" + + config_list_foreach "$user" module "add_param \" LoadModule\"" + + # add legacy network + if [ "$server" ]; then + echo " " >> $ZNC_CONFIG + config_list_foreach "$user" server "add_param \" Server\"" + config_list_foreach "$user" channel "add_chan" + echo " " >> $ZNC_CONFIG + fi + + config_foreach "add_network \"$user\"" network + + echo "" >> $ZNC_CONFIG +} + + +start() { + config_load znc + config_foreach znc_global znc + + if [ "$DISABLED" -eq 1 ]; then + return 0 + fi + + if [ "$EXTERNAL_CONFIG" -eq 0 ] + then + config_foreach add_listener listener + config_foreach add_user user + + chown -hR ${RUNAS_USER:-nobody}:${RUNAS_GROUP:-nogroup} /tmp/etc/znc + fi + + if [ "$EXTERNAL_CONFIG" -eq 1 -a "$RUNAS_USER" ] + then + local SU=$(which su) + if [ "$SU" ] + then + $SU -c "/usr/bin/znc -d$ZNC_CONFIG_PATH >/dev/null &" $RUNAS_USER + else + logger -s -t ZNC -p daemon.err "Could not run ZNC as user $RUNAS_USER: su not found." + exit 1 + fi + else + /usr/bin/znc -d$ZNC_CONFIG_PATH >/dev/null & + fi +} + +stop() { + if [ -f "$PID_FILE" ] + then + kill $(cat "$PID_FILE") + else + killall znc + fi +} + diff --git a/net/znc/patches/001-move_rootcheck_after_config.patch b/net/znc/patches/001-move_rootcheck_after_config.patch new file mode 100644 index 0000000000..8b3e3e7037 --- /dev/null +++ b/net/znc/patches/001-move_rootcheck_after_config.patch @@ -0,0 +1,52 @@ +From 5f655f9a25a377c01cb15517859eb514628a43d4 Mon Sep 17 00:00:00 2001 +From: Jonas Gorski +Date: Wed, 6 Apr 2011 04:10:23 +0200 +Subject: [PATCH] Move the root check to after config parsing + +--- + src/main.cpp | 27 ++++++++++++++------------- + 1 files changed, 14 insertions(+), 13 deletions(-) + +--- a/src/main.cpp ++++ b/src/main.cpp +@@ -243,19 +243,6 @@ int main(int argc, char** argv) { + CUtils::PrintStatus(true, ""); + } + +- if (isRoot()) { +- CUtils::PrintError("You are running ZNC as root! Don't do that! There are not many valid"); +- CUtils::PrintError("reasons for this and it can, in theory, cause great damage!"); +- if (!bAllowRoot) { +- delete pZNC; +- return 1; +- } +- CUtils::PrintError("You have been warned."); +- CUtils::PrintError("Hit CTRL+C now if you don't want to run ZNC as root."); +- CUtils::PrintError("ZNC will start in 30 seconds."); +- sleep(30); +- } +- + if (bMakeConf) { + if (!pZNC->WriteNewConfig(sConfig)) { + delete pZNC; +@@ -276,6 +263,20 @@ int main(int argc, char** argv) { + return 1; + } + ++ if (isRoot()) { ++ CUtils::PrintError("You are running ZNC as root! Don't do that! There are not many valid"); ++ CUtils::PrintError("reasons for this and it can, in theory, cause great damage!"); ++ if (!bAllowRoot) { ++ delete pZNC; ++ return 1; ++ } ++ CUtils::PrintError("You have been warned."); ++ CUtils::PrintError("Hit CTRL+C now if you don't want to run ZNC as root."); ++ CUtils::PrintError("ZNC will start in 30 seconds."); ++ sleep(30); ++ } ++ ++ + if (bForeground) { + int iPid = getpid(); + CUtils::PrintMessage("Staying open for debugging [pid: " + CString(iPid) + "]"); diff --git a/net/znc/patches/002-Uclibcpp_build_fix.patch b/net/znc/patches/002-Uclibcpp_build_fix.patch new file mode 100644 index 0000000000..df27c80cc0 --- /dev/null +++ b/net/znc/patches/002-Uclibcpp_build_fix.patch @@ -0,0 +1,28 @@ +From fa14938321eda39f16bee6068296e6abc9df7b85 Mon Sep 17 00:00:00 2001 +From: Jonas Gorski +Date: Wed, 6 Apr 2011 04:11:48 +0200 +Subject: [PATCH] Add a uClibc++ build workaround + +--- + modules/webadmin.cpp | 4 +++- + 1 files changed, 3 insertions(+), 1 deletions(-) + +--- a/modules/webadmin.cpp ++++ b/modules/webadmin.cpp +@@ -20,6 +20,7 @@ + #include + #include + ++using std::string; + using std::stringstream; + using std::make_pair; + using std::set; +@@ -75,7 +76,7 @@ class CWebAdminMod : public CModule { + public: + MODCONSTRUCTOR(CWebAdminMod) { + VPair vParams; +- vParams.push_back(make_pair("user", "")); ++ vParams.push_back(make_pair((string)"user", (string)"")); + AddSubPage(new CWebSubPage("settings", "Global Settings", CWebSubPage::F_ADMIN)); + AddSubPage(new CWebSubPage("edituser", "Your Settings", vParams)); + AddSubPage(new CWebSubPage("traffic", "Traffic Info", CWebSubPage::F_ADMIN)); diff --git a/net/znc/patches/003-Reduce_rebuild_time.patch b/net/znc/patches/003-Reduce_rebuild_time.patch new file mode 100644 index 0000000000..25c08e5b3b --- /dev/null +++ b/net/znc/patches/003-Reduce_rebuild_time.patch @@ -0,0 +1,38 @@ +From 94aff4c3389111fc85054eb06b40bea26a216d0c Mon Sep 17 00:00:00 2001 +From: Jonas Gorski +Date: Sat, 16 Apr 2011 05:51:04 +0200 +Subject: [PATCH] Don't rebuild everything when the Makefile's timestamp changed + +--- + Makefile.in | 2 +- + modules/Makefile.in | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +--- a/Makefile.in ++++ b/Makefile.in +@@ -104,7 +104,7 @@ clean: + distclean: clean + rm -rf $(DISTCLEAN) + +-src/%.o: src/%.cpp Makefile ++src/%.o: src/%.cpp + @mkdir -p .depend src + $(E) Building core object $*... + $(Q)$(CXX) $(CXXFLAGS) -c -o $@ $< -MD -MF .depend/$*.dep -MT $@ +--- a/modules/Makefile.in ++++ b/modules/Makefile.in +@@ -117,12 +117,12 @@ install_datadir: + clean: + rm -rf $(CLEAN) + +-%.o: %.cpp Makefile ++%.o: %.cpp + @mkdir -p .depend + $(E) Building module $(notdir $(basename $@))... + $(Q)$(CXX) $(MODFLAGS) -c -o $@ $< $($(notdir $(basename $@))CXXFLAGS) -MD -MF .depend/$(notdir $@).dep + +-%.so: %.o Makefile ++%.so: %.o + $(E) "Linking module" $(notdir $(basename $@))... + $(Q)$(CXX) $(MODFLAGS) $(LDFLAGS) $(MODLINK) -o $@ $< $($(notdir $(basename $@))LDFLAGS) $(LIBS) + diff --git a/net/znc/patches/004-restore_droproot.patch b/net/znc/patches/004-restore_droproot.patch new file mode 100644 index 0000000000..2c7cefe5d4 --- /dev/null +++ b/net/znc/patches/004-restore_droproot.patch @@ -0,0 +1,147 @@ +--- /dev/null ++++ b/modules/droproot.cpp +@@ -0,0 +1,144 @@ ++/* ++ * droproot.cpp ++ * ++ * Copyright (c) 2009 Vadtec (vadtec@vadtec.net) ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 as published ++ * by the Free Software Foundation. ++ * ++ * Copyright (C) 2004-2012 See the AUTHORS file for details. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 as published ++ * by the Free Software Foundation. ++ */ ++ ++#include ++#include ++#include ++#include ++ ++class CDroproot : public CModule { ++ ++public: ++ MODCONSTRUCTOR(CDroproot) { ++ } ++ ++ virtual ~CDroproot() { ++ } ++ ++ uid_t GetUser(const CString& sUser, CString& sMessage) { ++ uid_t ret = sUser.ToUInt(); ++ ++ if (ret != 0) ++ return ret; ++ ++ struct passwd *pUser = getpwnam(sUser.c_str()); ++ ++ if (!pUser) { ++ sMessage = "User [" + sUser + "] not found!"; ++ return 0; ++ } ++ ++ return pUser->pw_uid; ++ } ++ ++ gid_t GetGroup(const CString& sGroup, CString& sMessage) { ++ gid_t ret = sGroup.ToUInt(); ++ ++ if (ret != 0) ++ return ret; ++ ++ struct group *pGroup = getgrnam(sGroup.c_str()); ++ ++ if (!pGroup) { ++ sMessage = "Group [" + sGroup + "] not found!"; ++ return 0; ++ } ++ ++ return pGroup->gr_gid; ++ } ++ ++ virtual bool OnLoad(const CString& sArgs, CString& sMessage) { ++ CString sUser = sArgs.Token(0); ++ CString sGroup = sArgs.Token(1, true); ++ ++ if (sUser.empty() || sGroup.empty()) { ++ sMessage = "Usage: LoadModule = Droproot "; ++ return false; ++ } ++ ++ m_user = GetUser(sUser, sMessage); ++ ++ if (m_user == 0) { ++ sMessage ++ = "Error: Cannot run as root, check your config file | Useage: LoadModule = Droproot "; ++ return false; ++ } ++ ++ m_group = GetGroup(sGroup, sMessage); ++ ++ if (m_group == 0) { ++ sMessage ++ = "Error: Cannot run as root, check your config file | Useage: LoadModule = Droproot "; ++ return false; ++ } ++ ++ return true; ++ } ++ ++ virtual bool OnBoot() { ++ int u, eu, g, eg, sg; ++ ++ if ((geteuid() == 0) || (getuid() == 0) || (getegid() == 0) || (getgid() ++ == 0)) { ++ ++ CUtils::PrintAction("Dropping root permissions"); ++ ++ // Clear all the supplementary groups ++ sg = setgroups(0, NULL); ++ ++ if (sg < 0) { ++ CUtils::PrintStatus(false, ++ "Could not remove supplementary groups! [" ++ + CString(strerror(errno)) + "]"); ++ ++ return false; ++ } ++ ++ // Set the group (if we are root, this sets all three group IDs) ++ g = setgid(m_group); ++ eg = setegid(m_group); ++ ++ if ((g < 0) || (eg < 0)) { ++ CUtils::PrintStatus(false, "Could not switch group id! [" ++ + CString(strerror(errno)) + "]"); ++ ++ return false; ++ } ++ ++ // and set the user (if we are root, this sets all three user IDs) ++ u = setuid(m_user); ++ eu = seteuid(m_user); ++ ++ if ((u < 0) || (eu < 0)) { ++ CUtils::PrintStatus(false, "Could not switch user id! [" ++ + CString(strerror(errno)) + "]"); ++ ++ return false; ++ } ++ ++ CUtils::PrintStatus(true); ++ ++ return true; ++ } ++ ++ return true; ++ } ++ ++protected: ++ uid_t m_user; ++ gid_t m_group; ++}; ++ ++GLOBALMODULEDEFS(CDroproot, "Allows ZNC to drop root privileges and run as an un-privileged user.")