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 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248
|
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;
load capctl;
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) {
@ :enc = encode($server);
if (state != [null]) {
assign sasl_auth.status.$enc $state;
} else {
assign -sasl_auth.status.$enc;
};
};
alias sasl_auth.getstate (server, void) {
@ :enc = encode($server);
return $sasl_auth.status[$enc];
};
on #-server_established 100 '\\\\[$$sasl_auth.servers\\\\] %' {
@ :server = servername();
@ :server_enc = encode($server);
@ :state = sasl_auth.getstate($server);
@ ::sasl_in_progress[$server_enc] = 1;
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.getstate($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.getstate($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($servername() $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.getstate($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.getstate($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.getstate($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.getstate($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.getstate($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;
};
|