Your IP : 216.73.216.48
if (word(2 $loadinfo()) != [pf]) {
load -pf $word(1 $loadinfo());
return;
};
package sasl_auth;
## SASL authentication script for EPIC5.
## Written by zlonix@efnet, public domain.
##
## Version: 1.0 (January, 2014)
## - Initial roll-out
##
## Version: 1.1 (March, 2014)
## - Perl is not required anymore
##
## Version: 1.2 (April, 2014)
## - Fixed bug with '\' in password (rb skered)
##
## Version: 1.3 (September, 2014)
## - Fixed bug with reconnection (rb skered)
## This script implements SASL authentication, primarily used on
## Freenode network. Currently only PLAIN method is supported.
##
## !!! WARNING !!! WARNING !!! WARNING !!! WARNING !!! WARNING !!!
## Never forget that your password may be intercepted, which
## is also very easy with the only currently implemented
## method. Because of that consider using SSL connection, and
## do not use same password for IRC and anything important,
## it can be easily read by root user on your server.
##
## DUE TO UNKNOWN REASONS THIS SCRIPT DOESN'T WORK WITH
## 'FLOODPROT' SCRIPT FROM DEFAULT EPIC DISTRIBUTION.
## !!! WARNING !!! WARNING !!! WARNING !!! WARNING !!! WARNING !!!
##
## All rules are controlled with 'sasl_auth' alias, which take three or
## four arguments: server (you may use asterisks like a pattern, best
## match wins if there is a tie), method of the authentication
## (currently unchecked on input and always resolved to 'PLAIN'), user
## name and optional password. If you do not provide the password it
## will be prompted upon connection. Prompted password is not saved in
## any variable.
##
## Be aware that there is some difference between 'server' definition
## across hooks and EPIC itself (server to which you issue /server
## command may be different to which you're actually connecting). You
## may define your server as 'irc.freenode.net' but by DNS round-robin
## mechanism be connected to 'hobana.freenode.net', for example, and
## hooks won't be thrown. If in any doubt - use wildcards, or define
## your preferred servers in ircII.servers file under your $IRCLIB to
## escape from DNS round-robin, if desired.
##
## Examples:
## sasl_auth *.freenode.net plain MyNick MyPassowrd
## sasl_auth *.other.net garbage TestNick
##
## Put those into your ~/.ircrc (or such) file after loading
## sasl_auth.
##
## Take special considiration if your credentials contain special chars
## like '\' or '$', because, if, for example, you're using PF loader to
## load your .ircrc (or whatever script you use with sasl_auth) - those
## will be evaluated, and password "\test$var" may end up just as
## "test".
##
## If you specify server under /sasl_auth command, but upon connect it
## won't ACK our request (essentialy meaning it doesn't support
## capabilities) or NAK it script will disconnect your from this server.
##
## Limitation and bugs:
## - only one and insecure method (freenode disabled blowfish support,
## so, this may never be implemented);
## - in case of a long base64 string for authentication it may
## not fit to the maximum message length and authentication
## will be failed, it can happen if you have very long
## password;
alias sasl_auth (server, method, user, password, void) {
if (@server && @method && @user) {
if (findw($server $sasl_auth.servers) == -1) {
@ push(sasl_auth.servers $server);
@ push(sasl_auth.methods $method);
@ push(sasl_auth.users $user);
if (@password) {
@ push(sasl_auth.passwords $password);
@ push(sasl_auth.interactive 0);
} else {
@ push(sasl_auth.passwords INTERACTIVE);
@ push(sasl_auth.interactive 1);
};
};
};
};
alias sasl_auth.plain (nick, password, void) {
# echo nick - $nick;
# echo pass - $password;
# echo xform - $xform("-CTCP +B64" $^\nick\\0$^\nick\\0$^\password);
# echo xform - $xform("-b64 +ctcp" $xform("-CTCP +B64" $^\nick\\0$^\nick\\0$^\password));
return $xform("-CTCP +B64" $^\nick\\0$^\nick\\0$^\password);
};
alias sasl_auth.setstate (server, state, void) {
if (state != [null]) {
assign sasl_auth.status.$server $state;
} else {
assign -sasl_auth.status.$server;
};
};
on #-server_established 100 '\\\\[$$sasl_auth.servers\\\\] %' {
@ :server = servername();
@ :state = sasl_auth.status.$server;
if (state == []) {
sasl_auth.setstate $server req_sent;
quote CAP REQ :sasl;
} else {
xecho -b sasl_auth: server_established: server $server is in a wrong state [$state] (should be <empty>);
sasl_auth.setstate $server null;
};
};
on ^odd_server_stuff '\\\\[$$sasl_auth.servers\\\\] CAP % ACK :*sasl*' {
@ :server = servername();
@ :state = sasl_auth.status.$server;
if (state == [req_sent]) {
sasl_auth.setstate $server meth_sent;
@ :idx = rmatch($server $sasl_auth.servers)-1;
quote AUTHENTICATE $toupper($word($idx $sasl_auth.methods));
} else {
xecho -b sasl_auth: odd_server_stuff: CAP ACK: server $server \(real: $0\) is in a wrong state [$state] (should be "req_sent");
sasl_auth.setstate $server null;
};
};
alias sasl_auth.sendauth (auth, void) {
quote AUTHENTICATE $auth;
};
on ^odd_server_stuff '\* AUTHENTICATE \+' {
@ :server = servername();
@ :state = sasl_auth.status.$server;
if (state == [meth_sent]) {
sasl_auth.setstate $server auth_sent;
@ :idx = rmatch($server $sasl_auth.servers)-1;
@ :method = word($idx $sasl_auth.methods);
@ :nick = word($idx $sasl_auth.users);
@ :pass = word($idx $sasl_auth.passwords);
@ :interactive = word($idx $sasl_auth.interactive);
if (interactive == 1) {
input -noecho "SASL password: " {
## local variables of the hook are not accessible here
@ :pass = *0;
@ :idx = rmatch($server $sasl_auth.servers)-1;
@ :nick = word($idx $sasl_auth.users);
@ :auth = sasl_auth.plain($nick $pass);
sasl_auth.sendauth $auth;
};
} else {
@ :auth = sasl_auth.plain($nick $pass);
sasl_auth.sendauth $auth;
};
} else {
xecho -b sasl_auth: odd_server_stuff: AUTHENTICATE: server $server \(real: $0\) is in a wrong state [$state] (should be "meth_sent");
sasl_auth.setstate $server null;
};
};
on -901 '\\\\[$$sasl_auth.servers\\\\] *' {
@ :server = servername();
@ :state = sasl_auth.status.$server;
if (state == [auth_sent]) {
sasl_auth.setstate $server null;
disconnect;
} else {
xecho -b sasl_auth: 901: server $server \(real: $0\) is in a wrong state [$state] (should be "auth_sent");
sasl_auth.setstate $server null;
};
};
on -903 '\\\\[$$sasl_auth.servers\\\\] *' {
@ :server = servername();
@ :state = sasl_auth.status.$server;
if (state == [auth_sent]) {
sasl_auth.setstate $server null;
quote CAP END;
} else {
xecho -b sasl_auth: 903: server $server \(real: $0\) is in a wrong state [$state] (should be "auth_sent");
sasl_auth.setstate $server null;
};
};
on #-001 100 '\\\\[$$sasl_auth.servers\\\\] *' {
@ :server = servername();
@ :state = sasl_auth.status.$server;
if (state != []) {
xecho -b sasl_auth: 001: server $server \(real: $0\) in a state [$state] and do not support capabilities (001 received without ACK/NAK);
xecho -b sasl_auth: odd_server_stuff: CAP NAK: disconnecting from $server \(real: $0\);
disconnect;
};
sasl_auth.setstate $server null;
};
on ^odd_server_stuff '\\\\[$$sasl_auth.servers\\\\] CAP * NAK :sasl' {
@ :server = servername();
@ :state = sasl_auth.status.$server;
xecho -b sasl_auth: odd_server_stuff: CAP NAK: server $server \(real: $0\) in a state [$state] and do not support proposed SASL capability (:sasl), NAK received;
xecho -b sasl_auth: odd_server_stuff: CAP NAK: disconnecting from $server \(real: $0\);
sasl_auth.setstate $server null;
disconnect;
};
on #-server_lost 100 '% \\\\[$$sasl_auth.servers\\\\] *' {
@ :server = servername();
@ :state = sasl_auth.status.$server;
if (state != []) {
xecho -b sasl_auth: server_lost: server $server \(real: $1\) in a wrong state [$state] (should be <empty>);
};
sasl_auth.setstate $server null;
};