diff --git a/modules/modperl/codegen.pl b/modules/modperl/codegen.pl index 1fa60a61..2c6a2652 100755 --- a/modules/modperl/codegen.pl +++ b/modules/modperl/codegen.pl @@ -98,6 +98,7 @@ while (<$in>) { say $out "\t\tPUSH_PTR($sub*, *i);"; say $out "\t}"; } + when (/SCString/) { my $b=$a->{base}; $b=~s/^const//; say $out "\tPUSH_PTR($b*, &$a->{var});" } when (/CString/) { say $out "\tPUSH_STR($a->{var});" } when (/\*$/) { my $t=$a->{type}; $t=~s/^const//; say $out "\tPUSH_PTR($t, $a->{var});" } when (/&$/) { my $b=$a->{base}; $b=~s/^const//; say $out "\tPUSH_PTR($b*, &$a->{var});" } diff --git a/modules/modperl/functions.in b/modules/modperl/functions.in index 87d4c867..105acb61 100644 --- a/modules/modperl/functions.in +++ b/modules/modperl/functions.in @@ -103,3 +103,8 @@ EModRet OnChanNoticeMessage(CNoticeMessage& Message) EModRet OnTopicMessage(CTopicMessage& Message) EModRet OnSendToClientMessage(CMessage& Message) EModRet OnSendToIRCMessage(CMessage& Message) + +void OnClientGetSASLMechanisms(SCString& ssMechanisms) +EModRet OnClientSASLServerInitialChallenge(const CString& sMechanism, CString& sResponse) +EModRet OnClientSASLAuthenticate(const CString& sMechanism, const CString& sMessage) +void OnClientSASLAborted() diff --git a/modules/modperl/modperl.i b/modules/modperl/modperl.i index 55ecff9a..25f04d39 100644 --- a/modules/modperl/modperl.i +++ b/modules/modperl/modperl.i @@ -49,6 +49,7 @@ #include "znc/Buffer.h" #include "modperl/module.h" #define stat struct stat +#include "modperl/pstring.h" %} %apply long { off_t }; @@ -66,11 +67,32 @@ %include namespace std { - template class set { - public: - set(); - set(const set&); - }; + template class set { + public: + set(); + set(const set&); + unsigned int size() const; + bool empty() const; + void clear(); + void insert(const K& key); + void erase(const K& key); + %extend { + bool has_key(const K& key) { + auto i = self->find(key); + return i != self->end(); + } + SV* keys_() { + AV* av = newAV_alloc_x(self->size()); + // assume SCString + int i = 0; + for (const auto& a : *self) { + av_store(av, i++, PString(a).GetSV(false)); + } + SV* result = newRV_noinc((SV*)av); + return sv_2mortal(result); + } + } + }; } %include "modperl/CString.i" @@ -98,9 +120,9 @@ namespace std { %template(VCString) std::vector; typedef std::vector VCString; /*%template(MNicks) std::map;*/ -/*%template(SModInfo) std::set; +/*%template(SModInfo) std::set;*/ %template(SCString) std::set; -typedef std::set SCString;*/ +typedef std::set SCString; %template(PerlMCString) std::map; class MCString : public std::map {}; /*%template(PerlModulesVector) std::vector;*/ @@ -294,6 +316,13 @@ typedef std::vector > VPair; return %$result; } *GetNicks = *_GetNicks_; + + package ZNC::SCString; + sub keys { + my $self = shift; + my $keys = $self->keys_; + return @$keys; + } %} /* vim: set filetype=cpp: */ diff --git a/modules/modperl/module.h b/modules/modperl/module.h index 3dbff660..61caa74b 100644 --- a/modules/modperl/module.h +++ b/modules/modperl/module.h @@ -160,6 +160,13 @@ class ZNC_EXPORT_LIB_EXPORT CPerlModule : public CModule { EModRet OnTopicMessage(CTopicMessage& Message) override; EModRet OnSendToClientMessage(CMessage& Message) override; EModRet OnSendToIRCMessage(CMessage& Message) override; + + void OnClientGetSASLMechanisms(SCString& ssMechanisms) override; + EModRet OnClientSASLServerInitialChallenge(const CString& sMechanism, + CString& sResponse) override; + EModRet OnClientSASLAuthenticate(const CString& sMechanism, + const CString& sMessage) override; + void OnClientSASLAborted() override; }; static inline CPerlModule* AsPerlModule(CModule* p) { diff --git a/test/integration/tests/scripting.cpp b/test/integration/tests/scripting.cpp index 516cd9c4..2bccaa53 100644 --- a/test/integration/tests/scripting.cpp +++ b/test/integration/tests/scripting.cpp @@ -404,5 +404,62 @@ TEST_F(ZNCTest, ModpythonSaslAuth) { "as user"); } +TEST_F(ZNCTest, ModperlSaslAuth) { +#ifndef WANT_PERL + GTEST_SKIP() << "Modperl is disabled"; +#endif + auto znc = Run(); + znc->CanLeak(); + + InstallModule("sasltest.pm", R"( + package sasltest; + use base 'ZNC::Module'; + sub module_types { $ZNC::CModInfo::GlobalModule } + + sub OnClientGetSASLMechanisms { + my $self = shift; + my $mechs = shift; + $mechs->insert('FOO'); + } + + sub OnClientSASLServerInitialChallenge { + if ($_[1] eq "FOO") { + $_[2] = "Welcome"; + } + return $ZNC::CONTINUE; + } + + sub OnClientSASLAuthenticate { + my $self = $_[0]; + if ($_[1] eq "FOO") { + my $user = ZNC::CZNC::Get()->FindUser("user"); + $self->GetClient->AcceptSASLLogin($user); + return $ZNC::HALT; + } + return $ZNC::CONTINUE; + } + + 1; +)"); + + auto ircd = ConnectIRCd(); + auto client = LoginClient(); + client.Write("znc loadmod modperl"); + client.Write("znc loadmod sasltest"); + client.ReadUntil("Loaded"); + + auto client2 = ConnectClient(); + client2.Write("CAP LS 302"); + client2.Write("NICK nick"); + client2.ReadUntil(" sasl=FOO,PLAIN "); + client2.Write("CAP REQ :sasl"); + client2.Write("AUTHENTICATE FOO"); + client2.ReadUntil("AUTHENTICATE " + QByteArrayLiteral("Welcome").toBase64()); + client2.Write("AUTHENTICATE +"); + client2.ReadUntil( + ":irc.znc.in 900 nick nick!user@127.0.0.1 user :You are now logged in " + "as user"); +} + } // namespace } // namespace znc_inttest