1# Some code taken from `nickserv.pl' for convenience. 2# Credits Sami Haahtinen / ZaNaGa 3# 4 5# Don't forget to create the necessary chatnets in your irssi config file. 6# 7# Example: 8# .... 9# { 10# address = "irc.undernet.org"; 11# chatnet = "Undernet"; 12# port = "6668"; 13# autoconnect = no; 14# } 15# ..... 16# 17# 18# Then connect with the server like this: 19# /server undernet (or set autoconnect to yes) 20 21# Make sure you fill in *all* necessary information without typos. 22# 23# Files you need to edit after first run: 24# x.users -> For your x user/pw information. 25# x.channels -> Channels to join after authing. (optional) 26# 27# Use /xrehash to reload if you edit the files. 28# 29# Var: 30# my (%masks) -> See help there. 31 32# Tested with X versions 33# Undernet P10 Channel Services II Release 1.1pl7 34# 35 36# 37# This program is free software; you can redistribute it and/or modify 38# it under the terms of the GNU General Public License as published by 39# the Free Software Foundation; either version 2, or (at your option) 40# any later version. 41# 42# This program is distributed in the hope that it will be useful, but 43# WITHOUT ANY WARRANTY; without even the implied warranty of 44# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the file 45# COPYING (included with this distribution) or the GNU General Public 46# License for more details. 47# 48# You should have received a copy of the GNU General Public License 49# along with this program; if not, write to the Free Software 50# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 51# 52 53use Irssi; 54use Irssi::Irc; 55 56use strict; 57 58use vars qw($VERSION %IRSSI); 59 60$VERSION = '1.02'; 61 62%IRSSI = ( 63 authors => 'Toshio R. Spoor', 64 contact => 't.spoor@gmail.com', 65 name => 'xauth', 66 description => 'Undernet X Service Authentication Program', 67 license => 'GNU GPLv2 or later', 68 changed => '$Date: 2004/12/17 08:39:47 $' 69); 70 71my (%CONFIG) = ( 72 autostart => '', 73 autojoin => '', 74 hiddenhost => '' 75); 76 77Irssi::theme_register([ 78 xauth_rehash => '{comment $0} %KRehashing configuration files and settings%n', 79 xauth_autostart => '{comment $0} %KAuto-Start :%n $1', 80 xauth_autojoin => '{comment $0} %KAuto-Join :%n $1', 81 xauth_hiddenhost=> '{comment $0} %KHiddenhost :%n $1', 82 xauth_auth => '{comment $0} %KAuthorising%n $1 %Kwith%n $2 %Kon%n $3', 83 xauth_load => '{comment $0} %KScript %nv$1 %Kloaded ...%n', 84 xauth_nocon => '{comment $0} %KNot connected to server%n', 85 xauth_noconn => '{comment $0} %KThere does not exist a connection to $1%n', 86 xauth_success => '{comment $0} %KLogged in successfully on %n$1', 87 xauth_failed => '{comment $0} %KFailed to login on %n$1 ($2)', 88 xauth_already => '{comment $0} %KI am already logged in on%n $1', 89 xauth_nouser => '{comment $0} $1 %Kdoes not know who %n$2 %Kis on %n$3', 90 xauth_nohost => '{comment $0} %KNo hostmask found for %n$1%K, to fix this edit this script, see masks', 91 xauth_noentry => '{comment $0} %KI did not find an entry for %n$1 %Kcheck%n $2', 92 xauth_missing => '{comment $0} %KI am missing username, password or authentication host login information%n', 93 xauth_join => '{comment $0} %KJoined on%n $1%K : %n$2-' 94]); 95 96my ($usage) = qq!X-Authentication v$VERSION by Toshio Spoor 97 98Usage: 99/auth <chatnet> 100 101Settings: 102/set xauth Shows current settings 103/toggle xauth_autostart Toggle Auto Start 104/toggle xauth_autojoin Toggle Auto Join 105/toggle xauth_hiddenhost Toggle Hiddenhost (ircu u2.10.11+) 106 107Rehashing settings and user/channel file: 108/xrehash Run this after any changes 109 made to settings/files 110 111/save Make settings permanent 112!; 113 114# The `masks' hash is very important: 115# Here we fill in the masks we need to authenticate with. 116# 117# <chatnet> = <host> <authhost> 118# 119# You can find this very easily: 120# /msg x login 121# 122# 08:49 -!- Irssi: Starting query in Undernet with x 123# 08:49 <Foo> login 124# 08:49 -X(channels@undernet.org)- To use LOGIN, you must /msg X@services.undernet.org 125# 126# Keep the chatnet lowercase 127 128my (%masks) = ( 129 undernet => [ 'cservice@undernet.org', 'X@channels.undernet.org' ], 130 worldirc => [ 'cservice@worldirc.org','X@channels.worldirc.org' ] 131); 132 133# 0 = None 134# 1 = Normal 135# 2 = More 136 137my ($verbose) = 1; 138 139# Don't touch these, unless the signature changes. 140# 141my ($success) = "AUTHENTICATION SUCCESSFUL"; 142my ($already) = "Sorry, You are already authenticated"; 143my ($failed) = "AUTHENTICATION FAILED"; 144my ($remind) = "Remember: Nobody from CService will ever ask you for your password, do NOT give"; 145my ($nouser) = "I don't know who"; 146 147# Global Vars, don't change these. 148# 149my ($x_passfile) = Irssi::get_irssi_dir() ."/x.users"; 150my ($x_chanfile) = Irssi::get_irssi_dir() ."/x.channels"; 151 152my (@users) = (); 153my (@chans) = (); 154 155# Core Code 156# 157# 158 159sub putlog() { 160 161 my ($window) = Irssi::active_win(); 162 Irssi::print("[$IRSSI{'name'}] @_", MSGLEVEL_CLIENTNOTICE); 163 164} 165 166sub haltdef() { 167 168 Irssi::signal_stop(); 169 170} 171 172sub conn($) { 173 174 my ($server) = @_; 175 176 if (!$server || !$server->{connected}) { 177 return 0; 178 } else { 179 return 1; 180 } 181 182} 183 184sub join_channels($) { 185 186 my ($chatnet) = @_; 187 my (@channels) = (); 188 my ($server) = Irssi::server_find_tag($chatnet); 189 190 if (!$server) { 191 Irssi::printformat(MSGLEVEL_CLIENTNOTICE, "xauth_nocon", "$IRSSI{'name'}"); 192 return; 193 } 194 195 foreach (@chans) { 196 197 my ($channel, $ircnet) = split(/:/); 198 199 if (lc($chatnet) eq lc($ircnet)) { 200 # If we do it like this, the status window stays active. 201 push (@channels, $channel); 202 $server->send_raw("JOIN #$channel"); 203 } 204 } 205 206 if ($verbose) { 207 if (@channels) { 208 Irssi::printformat(MSGLEVEL_CLIENTNOTICE, "xauth_join", "$IRSSI{'name'}", $chatnet, @channels); 209 } 210 } 211} 212 213sub mask_check($) { 214 215 my ($address) = @_; 216 217 foreach my $key (keys %masks) { 218 if (lc($masks{$key}->[0]) eq lc($address)) { 219 return $key; 220 last; 221 } 222 } 223 224 return 0; 225 226} 227 228 229sub event_notice() { 230 231 my ($server, $args, $nick, $nickad) = @_; 232 233 return unless (&mask_check($nickad)); 234 235 my ($cnet) = $server->{'tag'}; 236 my ($version) = $server->{'version'}; 237 238 my ($target, $data) = $args =~ /^(\S*)\s+:(.*)$/; 239 240 $_ = $data; 241 242 if (/^$already/i) { 243 Irssi::printformat(MSGLEVEL_CLIENTNOTICE, "xauth_already", "$IRSSI{'name'}", $cnet); 244 &haltdef(); 245 } 246 247 if (/^$success/i) { 248 Irssi::printformat(MSGLEVEL_CLIENTNOTICE, "xauth_success", "$IRSSI{'name'}", $cnet); 249 250 if (($version) && ($CONFIG{'hiddenhost'})) { 251 252 my($app,$hi,$lo) = $version =~ /^(..).(..).(..)/; 253 $app =~ s/\D//g; 254 255 if (($app >= 2) && ($lo >= 11)) { 256 &putlog("Found ircu $version, setting umode +x") if ($verbose > 1); 257 $server->command("mode $target +x"); 258 } 259 } 260 261 if ($CONFIG{'autojoin'}) { 262 &join_channels($cnet); 263 } 264 &haltdef(); 265 } 266 267 if (/^$failed/i) { 268 if (/\((.*?)\)/) { $args = $1 }; 269 Irssi::printformat(MSGLEVEL_CLIENTNOTICE, "xauth_failed", "$IRSSI{'name'}", $cnet, $args); 270 &haltdef(); 271 } 272 273 if (/^$remind/i) { 274 &haltdef(); 275 } 276 277 if (/^$nouser/i) { 278 if (/who\s(.*?)\s/) { $args = $1 }; 279 Irssi::printformat(MSGLEVEL_CLIENTNOTICE, "xauth_nouser", "$IRSSI{'name'}", "$nick", $args, $cnet); 280 &haltdef(); 281 } 282} 283 284sub cmd_auth() { 285 286 my ($data, $server, $witem) = @_; 287 my ($username, $ircnet, $password, $xlogin, $xmask, $chatnet, $found); 288 289 if ($data) { 290 $chatnet = $data; 291 } else { 292 &putlog("$usage"); 293 return; 294 } 295 296 if (! &conn($server)) { 297 Irssi::printformat(MSGLEVEL_CLIENTNOTICE, "xauth_nocon", "$IRSSI{'name'}"); 298 return; 299 } 300 301 my ($authserver) = Irssi::server_find_tag($chatnet); 302 303 if (! $authserver) { 304 Irssi::printformat(MSGLEVEL_CLIENTNOTICE, "xauth_noconn", "$IRSSI{'name'}", $chatnet); 305 return; 306 } 307 308 foreach (@users) { 309 310 ($username, $ircnet, $password) = split(/:/); 311 312 if (lc($ircnet) eq lc($chatnet)) { 313 $xmask = $masks{lc($ircnet)}->[0]; 314 $xlogin = $masks{lc($ircnet)}->[1]; 315 316 if ((!$xmask) || (!$xlogin)) { 317 Irssi::printformat(MSGLEVEL_CLIENTNOTICE, "xauth_nohost", "$IRSSI{'name'}", $chatnet); 318 return; 319 } 320 321 $found=1; 322 last; 323 } 324 } 325 326 if (! $found ) { 327 Irssi::printformat(MSGLEVEL_CLIENTNOTICE, "xauth_noentry", "$IRSSI{'name'}", $chatnet, qq/"$x_passfile"/); 328 return; 329 } 330 331 if (($username) && ($password) && ($xlogin)) { 332 Irssi::printformat(MSGLEVEL_CLIENTNOTICE, "xauth_auth", "$IRSSI{'name'}", $username, $xlogin, $chatnet); 333 $authserver->send_raw("PRIVMSG $xlogin :login $username $password"); 334 } else { 335 Irssi::printformat(MSGLEVEL_CLIENTNOTICE, "xauth_missing", "$IRSSI{'name'}"); 336 } 337} 338 339# Code taken from nickserv.pl 340 341sub read_users() { 342 my $count = 0; 343 344 # Lets reset @users so we can call this as a function. 345 @users = (); 346 347 if (!(open XUSERS, "<", $x_passfile)) { 348 &create_users; 349 }; 350 &putlog("Running checks on the userfile.") if ($verbose > 1); 351 # first we test the file with mask 066 (we don't actually care if the 352 # file is executable by others.. what could they do with it =) 353 354 # Well, according to my calculations umask 066 should be 54, go figure. 355 356 my $mode = (stat($x_passfile))[2]; 357 if ($mode & 54) { 358 &putlog("your password file should be mode 0600. Go fix it!"); 359 &putlog("use command: chmod 0600 $x_passfile"); 360 } 361 362 # and then we read the userfile. 363 # apparently Irssi resets $/, so we set it here. 364 365 local $/ = "\n"; 366 while( my $line = <XUSERS>) { 367 if( $line !~ /^(#|\s*$)/ ) { 368 my ($nick, $ircnet, $password) = 369 $line =~ /^\s*(\S+)\s+(\S+)\s+(.*?)$/; 370 push @users, "$nick:$ircnet:$password"; 371 $count++; 372 } 373 } 374 &putlog("Found $count accounts") if ($verbose > 1); 375 close XUSERS; 376} 377 378sub create_users() { 379 380 &putlog("Creating basic userfile in $x_passfile. Edit File."); 381 382 if(!(open XUSERS, ">", $x_passfile)) { 383 &putlog("Unable to create file $x_passfile"); 384 } 385 386 print XUSERS "# username and IrcNet Tag are case insensitive\n"; 387 print XUSERS "#\n"; 388 print XUSERS "# username IrcNet Tag Password\n"; 389 print XUSERS "# -------- ---------- --------\n"; 390 391 close XUSERS; 392 chmod 0600, $x_passfile; 393} 394 395sub create_chans() { 396 &putlog("Creating basic channelfile in $x_chanfile. Edit File."); 397 if(!(open NICKCHANS, ">", $x_chanfile)) { 398 &putlog("Unable to create file $x_chanfile"); 399 } 400 401 print NICKCHANS "# This file should contain a list of all channels\n"; 402 print NICKCHANS "# which you don't want to join until after you've\n"; 403 print NICKCHANS "# successfully identified with x. This is\n"; 404 print NICKCHANS "# useful if you have a hidden host (+x).\n"; 405 print NICKCHANS "# Enter Channel without `#'\n"; 406 print NICKCHANS "#\n"; 407 print NICKCHANS "# Channel IrcNet Tag\n"; 408 print NICKCHANS "# -------- ----------\n"; 409 410 close NICKCHANS; 411 chmod 0600, $x_chanfile; 412} 413 414sub read_chans() { 415 my $count = 0; 416 417 # Lets reset @users so we can call this as a function. 418 @chans = (); 419 420 if (!(open NICKCHANS, "<", $x_chanfile)) { 421 create_chans; 422 }; 423 &putlog("Running checks on the channelfile.") if ($verbose > 1); 424 # first we test the file with mask 066 (we don't actually care if the 425 # file is executable by others.. what could they do with it =) 426 427 # Well, according to my calculations umask 066 should be 54, go figure. 428 429 my $mode = (stat($x_chanfile))[2]; 430 if ($mode & 54) { 431 &putlog("your channels file should be mode 0600. Go fix it!"); 432 &putlog("use command: chmod 0600 $x_chanfile"); 433 } 434 435 # and then we read the channelfile. 436 # apparently Irssi resets $/, so we set it here. 437 438 local $/ = "\n"; 439 while( my $line = <NICKCHANS>) { 440 if( $line !~ /^(#|\s*$)/ ) { 441 my ($channel, $ircnet) = 442 $line =~ /\s*(\S+)\s+(\S+)/; 443 push @chans, "$channel:$ircnet"; 444 $count++; 445 } 446 } 447 &putlog("Found $count channels") if ($verbose > 1); 448 close NICKCHANS; 449} 450 451# End code from nickserv.pl 452 453sub event_connect() { 454 455 $CONFIG{'autostart'} = Irssi::settings_get_bool('xauth_autostart'); 456 457 return unless ($CONFIG{'autostart'}); 458 459 my ($server) = @_; 460 my ($cnet) = $server->{'tag'}; 461 my ($found); 462 463 foreach my $key (keys %masks) { 464 if (lc($key) eq lc($cnet)) { 465 $found=1; 466 last; 467 } 468 } 469 470 return unless($found); 471 472 $server->command("auth $cnet"); 473 474} 475 476sub x_rehash() { 477 478 Irssi::printformat(MSGLEVEL_CLIENTNOTICE, "xauth_rehash", "$IRSSI{'name'}") if (($verbose) && (@_)); 479 480 &read_users(); 481 &read_chans(); 482 &get_set(@_); 483 484} 485 486sub init_set() { 487 488 Irssi::settings_add_bool('misc', 'xauth_autostart', '0'); 489 Irssi::settings_add_bool('misc', 'xauth_autojoin', '1'); 490 Irssi::settings_add_bool('misc', 'xauth_hiddenhost','0'); 491 492} 493 494sub onoff($) { 495 496 my ($value) = @_; 497 498 if ($value) { 499 return "On"; 500 } else { 501 return "Off"; 502 } 503 504} 505 506sub get_set() { 507 508 $CONFIG{'autostart'} = Irssi::settings_get_bool('xauth_autostart'); 509 $CONFIG{'autojoin'} = Irssi::settings_get_bool('xauth_autojoin'); 510 $CONFIG{'hiddenhost'} = Irssi::settings_get_bool('xauth_hiddenhost'); 511 512 Irssi::printformat(MSGLEVEL_CLIENTNOTICE, "xauth_autostart", "$IRSSI{'name'}", &onoff("$CONFIG{'autostart'}")) if (($verbose) && (@_)); 513 Irssi::printformat(MSGLEVEL_CLIENTNOTICE, "xauth_autojoin", "$IRSSI{'name'}", &onoff("$CONFIG{'autojoin'}")) if (($verbose) && (@_)); 514 Irssi::printformat(MSGLEVEL_CLIENTNOTICE, "xauth_hiddenhost", "$IRSSI{'name'}", &onoff("$CONFIG{'hiddenhost'}")) if (($verbose) && (@_)); 515 516} 517 518sub init() { 519 520 &init_set(); 521 &x_rehash(); 522 523 524} 525 526sub x_help() { 527 528 &putlog("$usage"); 529 530} 531 532 533# Main 534# 535# 536 537&init(); 538 539Irssi::command_bind("auth", "cmd_auth"); 540Irssi::command_bind("xrehash", "x_rehash"); 541Irssi::command_bind("xhelp", "x_help"); 542 543Irssi::signal_add("event notice", "event_notice"); 544Irssi::signal_add("event connected", "event_connect"); 545 546Irssi::printformat(MSGLEVEL_CLIENTNOTICE, "xauth_load", "$IRSSI{'name'}", $VERSION); 547