Pastebin launched a little side project called VERYVIRAL.com, check it out ;-) Want more features on Pastebin? Sign Up, it's FREE!
Guest

Untitled

By: a guest on Feb 7th, 2010  |  syntax: None  |  size: 7.79 KB  |  views: 963  |  expires: Never
download  |  raw  |  embed  |  report abuse  |  print
Text below is selected. Please press Ctrl+C to copy to your clipboard. (⌘+C on Mac)
  1. use strict;
  2. use Irssi;
  3. use vars qw($VERSION %IRSSI);
  4. # $Id: cap_sasl.pl 5330 2006-05-31 02:25:21Z gxti $
  5.  
  6. use MIME::Base64;
  7.  
  8. $VERSION = "1.2";
  9.  
  10. %IRSSI = (
  11.     authors     => 'Michael Tharp, Jilles Tjoelker, Lee T. Starnes',
  12.     contact     => 'lstarnes1024+irc@gmail.com', 'gxti@partiallystapled.com',
  13.     name        => 'cap_sasl.pl',
  14.     description => 'Implements PLAIN SASL authentication mechanism for use with charybdis ircds, and enables CAP MULTI-PREFIX',
  15.     license     => 'GNU General Public License',
  16.     url         => 'http://sasl.charybdis.be/',
  17.     changed     => 'Sun Feb  7 21:27:35 EST 2010'
  18. );
  19.  
  20. my %sasl_auth = ();
  21. my %mech = ();
  22.  
  23. sub timeout;
  24.  
  25. sub server_connected {
  26.         my $server = shift;
  27.         $server->send_raw_now("CAP LS");
  28. }
  29.  
  30. sub event_cap {
  31.         my ($server, $args, $nick, $address) = @_;
  32.         my ($subcmd, $caps, $tosend);
  33.        
  34.         my $timeout = Irssi::settings_get_int('sasl_timeout') * 1000;
  35.         $tosend = '';
  36.         if ($args =~ /^\S+ (\S+) :(.*)$/) {
  37.                 $subcmd = uc $1;
  38.                 $caps = ' '.$2.' ';
  39.                 if ($subcmd eq 'LS') {
  40.                         $tosend .= ' multi-prefix' if $caps =~ / multi-prefix /i;
  41.                         $tosend .= ' sasl' if $caps =~ / sasl /i && defined($sasl_auth{$server->{tag}});
  42.                         $tosend =~ s/^ //;
  43.                         $server->print('', "CLICAP: supported by server:$caps");
  44.                         if (!$server->{connected}) {
  45.                                 if ($tosend eq '') {
  46.                                         $server->send_raw_now("CAP END");
  47.                                 } else {
  48.                                         $server->print('', "CLICAP: requesting: $tosend");
  49.                                         $server->send_raw_now("CAP REQ :$tosend");
  50.                                 }
  51.                         }
  52.                         Irssi::signal_stop();
  53.                 } elsif ($subcmd eq 'ACK') {
  54.                         $server->print('', "CLICAP: now enabled:$caps");
  55.                         if ($caps =~ / sasl /i) {
  56.                                 $sasl_auth{$server->{tag}}{buffer} = '';
  57.                                 if($mech{$sasl_auth{$server->{tag}}{mech}}) {
  58.                                         $server->send_raw_now("AUTHENTICATE " . $sasl_auth{$server->{tag}}{mech});
  59.                                         Irssi::timeout_add_once($timeout, \&timeout, $server->{tag});
  60.                                 }else{
  61.                                         $server->print('', 'SASL: attempted to start unknown mechanism "' . $sasl_auth{$server->{tag}}{mech} . '"');
  62.                                 }
  63.                         }
  64.                         elsif (!$server->{connected}) {
  65.                                 $server->send_raw_now("CAP END");
  66.                         }
  67.                         Irssi::signal_stop();
  68.                 } elsif ($subcmd eq 'NAK') {
  69.                         $server->print('', "CLICAP: refused:$caps");
  70.                         if (!$server->{connected}) {
  71.                                 $server->send_raw_now("CAP END");
  72.                         }
  73.                         Irssi::signal_stop();
  74.                 } elsif ($subcmd eq 'LIST') {
  75.                         $server->print('', "CLICAP: currently enabled:$caps");
  76.                         Irssi::signal_stop();
  77.                 }
  78.         }
  79. }
  80.  
  81. sub event_authenticate {
  82.         my ($server, $args, $nick, $address) = @_;
  83.         my $sasl = $sasl_auth{$server->{tag}};
  84.         return unless $sasl && $mech{$sasl->{mech}};
  85.  
  86.         $sasl->{buffer} .= $args;
  87.         return if length($args) == 400;
  88.  
  89.         my $data = $sasl->{buffer} eq '+' ? '' : decode_base64($sasl->{buffer});
  90.         my $out = $mech{$sasl->{mech}}($sasl, $data);
  91.         $out = '' unless defined $out;
  92.         $out = $out eq '' ? '+' : encode_base64($out, '');
  93.  
  94.         while(length $out >= 400) {
  95.                 my $subout = substr($out, 0, 400, '');
  96.                 $server->send_raw_now("AUTHENTICATE $subout");
  97.         }
  98.         if(length $out) {
  99.                 $server->send_raw_now("AUTHENTICATE $out");
  100.         }else{ # Last piece was exactly 400 bytes, we have to send some padding to indicate we're done
  101.                 $server->send_raw_now("AUTHENTICATE +");
  102.         }
  103.  
  104.         $sasl->{buffer} = '';
  105.         Irssi::signal_stop();
  106. }
  107.  
  108. sub event_saslend {
  109.         my ($server, $args, $nick, $address) = @_;
  110.  
  111.         my $data = $args;
  112.         $data =~ s/^\S+ :?//;
  113.         # need this to see it, ?? -- jilles
  114.         $server->print('', $data);
  115.         if (!$server->{connected}) {
  116.                 $server->send_raw_now("CAP END");
  117.         }
  118. }
  119.  
  120. sub timeout {
  121.         my $tag = shift;
  122.         my $server = Irssi::server_find_tag($tag);
  123.         if(!$server->{connected}) {
  124.                 $server->print('', "SASL: authentication timed out");
  125.                 $server->send_raw_now("CAP END");
  126.         }
  127. }
  128.  
  129. sub cmd_sasl {
  130.         my ($data, $server, $item) = @_;
  131.  
  132.         if ($data ne '') {
  133.                 Irssi::command_runsub ('sasl', $data, $server, $item);
  134.         } else {
  135.                 cmd_sasl_show(@_);
  136.         }
  137. }
  138.  
  139. sub cmd_sasl_set {
  140.         my ($data, $server, $item) = @_;
  141.  
  142.         if (my($net, $u, $p, $m) = $data =~ /^(\S+) (\S+) (\S+) (\S+)$/) {
  143.                 if($mech{uc $m}) {
  144.                         $sasl_auth{$net}{user} = $u;
  145.                         $sasl_auth{$net}{password} = $p;
  146.                         $sasl_auth{$net}{mech} = uc $m;
  147.                         Irssi::print("SASL: added $net: [$m] $sasl_auth{$net}{user} *");
  148.                 }else{
  149.                         Irssi::print("SASL: unknown mechanism $m");
  150.                 }
  151.         } elsif ($data =~ /^(\S+)$/) {
  152.                 $net = $1;
  153.                 if (defined($sasl_auth{$net})) {
  154.                         delete $sasl_auth{$net};
  155.                         Irssi::print("SASL: deleted $net");
  156.                 } else {
  157.                         Irssi::print("SASL: no entry for $net");
  158.                 }
  159.         } else {
  160.                 Irssi::print("SASL: usage: /sasl set <net> <user> <password or keyfile> <mechanism>");
  161.         }
  162. }
  163.  
  164. sub cmd_sasl_show {
  165.         #my ($data, $server, $item) = @_;
  166.         my $net;
  167.         my $count = 0;
  168.  
  169.         foreach $net (keys %sasl_auth) {
  170.                 Irssi::print("SASL: $net: [$sasl_auth{$net}{mech}] $sasl_auth{$net}{user} *");
  171.                 $count++;
  172.         }
  173.         Irssi::print("SASL: no networks defined") if !$count;
  174. }
  175.  
  176. sub cmd_sasl_save {
  177.         #my ($data, $server, $item) = @_;
  178.         my $file = Irssi::get_irssi_dir()."/sasl.auth";
  179.         open FILE, "> $file" or return;
  180.         foreach my $net (keys %sasl_auth) {
  181.                 printf FILE ("%s\t%s\t%s\t%s\n", $net, $sasl_auth{$net}{user}, $sasl_auth{$net}{password}, $sasl_auth{$net}{mech});
  182.         }
  183.         close FILE;
  184.         Irssi::print("SASL: auth saved to $file");
  185. }
  186.  
  187. sub cmd_sasl_load {
  188.         #my ($data, $server, $item) = @_;
  189.         my $file = Irssi::get_irssi_dir()."/sasl.auth";
  190.  
  191.         open FILE, "< $file" or return;
  192.         %sasl_auth = ();
  193.         while (<FILE>) {
  194.                 chomp;
  195.                 my ($net, $u, $p, $m) = split (/\t/, $_, 4);
  196.                 $m ||= "PLAIN";
  197.                 if($mech{uc $m}) {
  198.                         $sasl_auth{$net}{user} = $u;
  199.                         $sasl_auth{$net}{password} = $p;
  200.                         $sasl_auth{$net}{mech} = uc $m;
  201.                 }else{
  202.                         Irssi::print("SASL: unknown mechanism $m");
  203.                 }
  204.         }
  205.         close FILE;
  206.         Irssi::print("SASL: auth loaded from $file");
  207. }
  208.  
  209. sub cmd_sasl_mechanisms {
  210.         Irssi::print("SASL: mechanisms supported: " . join(" ", keys %mech));
  211. }
  212.  
  213. Irssi::signal_add_first('server connected', \&server_connected);
  214. Irssi::signal_add('event cap', \&event_cap);
  215. Irssi::signal_add('event authenticate', \&event_authenticate);
  216. Irssi::signal_add('event 903', 'event_saslend');
  217. Irssi::signal_add('event 904', 'event_saslend');
  218. Irssi::signal_add('event 905', 'event_saslend');
  219. Irssi::signal_add('event 906', 'event_saslend');
  220. Irssi::signal_add('event 907', 'event_saslend');
  221.  
  222. Irssi::command_bind('sasl', \&cmd_sasl);
  223. Irssi::command_bind('sasl load', \&cmd_sasl_load);
  224. Irssi::command_bind('sasl save', \&cmd_sasl_save);
  225. Irssi::command_bind('sasl set', \&cmd_sasl_set);
  226. Irssi::command_bind('sasl show', \&cmd_sasl_show);
  227. Irssi::command_bind('sasl mechanisms', \&cmd_sasl_mechanisms);
  228.  
  229. Irssi::settings_add_int('misc', 'sasl_timeout', 5);
  230.  
  231. $mech{PLAIN} = sub {
  232.         my($sasl, $data) = @_;
  233.         my $u = $sasl->{user};
  234.         my $p = $sasl->{password};
  235.  
  236.         join("\0", $u, $u, $p);
  237. };
  238.  
  239. eval {
  240.         use Crypt::OpenSSL::Bignum;
  241.         use Crypt::DH;
  242.         use Crypt::Blowfish;
  243.         use Math::BigInt;
  244.         sub bin2bi { return Crypt::OpenSSL::Bignum->new_from_bin(shift)->to_decimal } # binary to BigInt
  245.         sub bi2bin { return Crypt::OpenSSL::Bignum->new_from_decimal((shift)->bstr)->to_bin } # BigInt to binary
  246.         $mech{'DH-BLOWFISH'} = sub {
  247.                 my($sasl, $data) = @_;
  248.                 my $u = $sasl->{user};
  249.                 my $pass = $sasl->{password};
  250.  
  251.                 # Generate private key and compute secret key
  252.                 my($p, $g, $y) = unpack("(n/a*)3", $data);
  253.                 my $dh = Crypt::DH->new(p => bin2bi($p), g => bin2bi($g));
  254.                 $dh->generate_keys;
  255.  
  256.                 my $secret = bi2bin($dh->compute_secret(bin2bi($y)));
  257.                 my $pubkey = bi2bin($dh->pub_key);
  258.  
  259.                 # Pad the password to the nearest multiple of blocksize and encrypt
  260.                 $pass .= "\0";
  261.                 $pass .= chr(rand(256)) while length($pass) % 8;
  262.  
  263.                 my $cipher = Crypt::Blowfish->new($secret);
  264.                 my $crypted = '';
  265.                 while(length $pass) {
  266.                         my $clear = substr($pass, 0, 8, '');
  267.                         $crypted .= $cipher->encrypt($clear);
  268.                 }
  269.  
  270.                 pack("n/a*Z*a*", $pubkey, $u, $crypted);
  271.         };
  272. };
  273.  
  274. cmd_sasl_load();
  275.  
  276. # vim: ts=4
clone this paste RAW Paste Data