# Some code taken from `nickserv.pl' for convenience.
# Credits Sami Haahtinen / ZaNaGa
#
# Don't forget to create the necessary chatnets in your irssi config file.
#
# Example:
# ....
# {
# address = "irc.undernet.org";
# chatnet = "Undernet";
# port = "6668";
# autoconnect = no;
# }
# .....
#
#
# Then connect with the server like this:
# /server undernet (or set autoconnect to yes)
# Make sure you fill in *all* necessary information without typos.
#
# Files you need to edit after first run:
# x.users -> For your x user/pw information.
# x.channels -> Channels to join after authing. (optional)
#
# Use /xrehash to reload if you edit the files.
#
# Var:
# my (%masks) -> See help there.
# Tested with X versions
# Undernet P10 Channel Services II Release 1.1pl7
#
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the file
# COPYING (included with this distribution) or the GNU General Public
# License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
use Irssi;
use Irssi::Irc;
use strict;
use vars qw($VERSION %IRSSI);
$VERSION = '1.02';
%IRSSI = (
authors => 'Toshio R. Spoor',
contact => '[email protected]',
name => 'xauth',
description => 'Undernet X Service Authentication Program',
license => 'GNU GPLv2 or later',
changed => '$Date: 2004/12/17 08:39:47 $'
);
my (%CONFIG) = (
autostart => '',
autojoin => '',
hiddenhost => ''
);
Irssi::theme_register([
xauth_rehash => '{comment $0} %KRehashing configuration files and settings%n',
xauth_autostart => '{comment $0} %KAuto-Start :%n $1',
xauth_autojoin => '{comment $0} %KAuto-Join :%n $1',
xauth_hiddenhost=> '{comment $0} %KHiddenhost :%n $1',
xauth_auth => '{comment $0} %KAuthorising%n $1 %Kwith%n $2 %Kon%n $3',
xauth_load => '{comment $0} %KScript %nv$1 %Kloaded ...%n',
xauth_nocon => '{comment $0} %KNot connected to server%n',
xauth_noconn => '{comment $0} %KThere does not exist a connection to $1%n',
xauth_success => '{comment $0} %KLogged in successfully on %n$1',
xauth_failed => '{comment $0} %KFailed to login on %n$1 ($2)',
xauth_already => '{comment $0} %KI am already logged in on%n $1',
xauth_nouser => '{comment $0} $1 %Kdoes not know who %n$2 %Kis on %n$3',
xauth_nohost => '{comment $0} %KNo hostmask found for %n$1%K, to fix this edit this script, see masks',
xauth_noentry => '{comment $0} %KI did not find an entry for %n$1 %Kcheck%n $2',
xauth_missing => '{comment $0} %KI am missing username, password or authentication host login information%n',
xauth_join => '{comment $0} %KJoined on%n $1%K : %n$2-'
]);
my ($usage) = qq!X-Authentication v$VERSION by Toshio Spoor
Usage:
/auth
Settings:
/set xauth Shows current settings
/toggle xauth_autostart Toggle Auto Start
/toggle xauth_autojoin Toggle Auto Join
/toggle xauth_hiddenhost Toggle Hiddenhost (ircu u2.10.11+)
Rehashing settings and user/channel file:
/xrehash Run this after any changes
made to settings/files
/save Make settings permanent
!;
# The `masks' hash is very important:
# Here we fill in the masks we need to authenticate with.
#
# =
#
# You can find this very easily:
# /msg x login
#
# 08:49 -!- Irssi: Starting query in Undernet with x
# 08:49 login
# 08:49 -X([email protected])- To use LOGIN, you must /msg [email protected]
#
# Keep the chatnet lowercase
my (%masks) = (
undernet => [ '[email protected]', '[email protected]' ],
worldirc => [ '[email protected]','[email protected]' ]
);
# 0 = None
# 1 = Normal
# 2 = More
my ($verbose) = 1;
# Don't touch these, unless the signature changes.
#
my ($success) = "AUTHENTICATION SUCCESSFUL";
my ($already) = "Sorry, You are already authenticated";
my ($failed) = "AUTHENTICATION FAILED";
my ($remind) = "Remember: Nobody from CService will ever ask you for your password, do NOT give";
my ($nouser) = "I don't know who";
# Global Vars, don't change these.
#
my ($x_passfile) = Irssi::get_irssi_dir() ."/x.users";
my ($x_chanfile) = Irssi::get_irssi_dir() ."/x.channels";
my (@users) = ();
my (@chans) = ();
# Core Code
#
#
sub putlog() {
my ($window) = Irssi::active_win();
Irssi::print("[$IRSSI{'name'}] @_", MSGLEVEL_CLIENTNOTICE);
}
sub haltdef() {
Irssi::signal_stop();
}
sub conn($) {
my ($server) = @_;
if (!$server || !$server->{connected}) {
return 0;
} else {
return 1;
}
}
sub join_channels($) {
my ($chatnet) = @_;
my (@channels) = ();
my ($server) = Irssi::server_find_tag($chatnet);
if (!$server) {
Irssi::printformat(MSGLEVEL_CLIENTNOTICE, "xauth_nocon", "$IRSSI{'name'}");
return;
}
foreach (@chans) {
my ($channel, $ircnet) = split(/:/);
if (lc($chatnet) eq lc($ircnet)) {
# If we do it like this, the status window stays active.
push (@channels, $channel);
$server->send_raw("JOIN #$channel");
}
}
if ($verbose) {
if (@channels) {
Irssi::printformat(MSGLEVEL_CLIENTNOTICE, "xauth_join", "$IRSSI{'name'}", $chatnet, @channels);
}
}
}
sub mask_check($) {
my ($address) = @_;
foreach my $key (keys %masks) {
if (lc($masks{$key}->[0]) eq lc($address)) {
return $key;
last;
}
}
return 0;
}
sub event_notice() {
my ($server, $args, $nick, $nickad) = @_;
return unless (&mask_check($nickad));
my ($cnet) = $server->{'tag'};
my ($version) = $server->{'version'};
my ($target, $data) = $args =~ /^(\S*)\s+:(.*)$/;
$_ = $data;
if (/^$already/i) {
Irssi::printformat(MSGLEVEL_CLIENTNOTICE, "xauth_already", "$IRSSI{'name'}", $cnet);
&haltdef();
}
if (/^$success/i) {
Irssi::printformat(MSGLEVEL_CLIENTNOTICE, "xauth_success", "$IRSSI{'name'}", $cnet);
if (($version) && ($CONFIG{'hiddenhost'})) {
my($app,$hi,$lo) = $version =~ /^(..).(..).(..)/;
$app =~ s/\D//g;
if (($app >= 2) && ($lo >= 11)) {
&putlog("Found ircu $version, setting umode +x") if ($verbose > 1);
$server->command("mode $target +x");
}
}
if ($CONFIG{'autojoin'}) {
&join_channels($cnet);
}
&haltdef();
}
if (/^$failed/i) {
if (/\((.*?)\)/) { $args = $1 };
Irssi::printformat(MSGLEVEL_CLIENTNOTICE, "xauth_failed", "$IRSSI{'name'}", $cnet, $args);
&haltdef();
}
if (/^$remind/i) {
&haltdef();
}
if (/^$nouser/i) {
if (/who\s(.*?)\s/) { $args = $1 };
Irssi::printformat(MSGLEVEL_CLIENTNOTICE, "xauth_nouser", "$IRSSI{'name'}", "$nick", $args, $cnet);
&haltdef();
}
}
sub cmd_auth() {
my ($data, $server, $witem) = @_;
my ($username, $ircnet, $password, $xlogin, $xmask, $chatnet, $found);
if ($data) {
$chatnet = $data;
} else {
&putlog("$usage");
return;
}
if (! &conn($server)) {
Irssi::printformat(MSGLEVEL_CLIENTNOTICE, "xauth_nocon", "$IRSSI{'name'}");
return;
}
my ($authserver) = Irssi::server_find_tag($chatnet);
if (! $authserver) {
Irssi::printformat(MSGLEVEL_CLIENTNOTICE, "xauth_noconn", "$IRSSI{'name'}", $chatnet);
return;
}
foreach (@users) {
($username, $ircnet, $password) = split(/:/);
if (lc($ircnet) eq lc($chatnet)) {
$xmask = $masks{lc($ircnet)}->[0];
$xlogin = $masks{lc($ircnet)}->[1];
if ((!$xmask) || (!$xlogin)) {
Irssi::printformat(MSGLEVEL_CLIENTNOTICE, "xauth_nohost", "$IRSSI{'name'}", $chatnet);
return;
}
$found=1;
last;
}
}
if (! $found ) {
Irssi::printformat(MSGLEVEL_CLIENTNOTICE, "xauth_noentry", "$IRSSI{'name'}", $chatnet, qq/"$x_passfile"/);
return;
}
if (($username) && ($password) && ($xlogin)) {
Irssi::printformat(MSGLEVEL_CLIENTNOTICE, "xauth_auth", "$IRSSI{'name'}", $username, $xlogin, $chatnet);
$authserver->send_raw("PRIVMSG $xlogin :login $username $password");
} else {
Irssi::printformat(MSGLEVEL_CLIENTNOTICE, "xauth_missing", "$IRSSI{'name'}");
}
}
# Code taken from nickserv.pl
sub read_users() {
my $count = 0;
# Lets reset @users so we can call this as a function.
@users = ();
if (!(open XUSERS, "<", $x_passfile)) {
&create_users;
};
&putlog("Running checks on the userfile.") if ($verbose > 1);
# first we test the file with mask 066 (we don't actually care if the
# file is executable by others.. what could they do with it =)
# Well, according to my calculations umask 066 should be 54, go figure.
my $mode = (stat($x_passfile))[2];
if ($mode & 54) {
&putlog("your password file should be mode 0600. Go fix it!");
&putlog("use command: chmod 0600 $x_passfile");
}
# and then we read the userfile.
# apparently Irssi resets $/, so we set it here.
local $/ = "\n";
while( my $line = ) {
if( $line !~ /^(#|\s*$)/ ) {
my ($nick, $ircnet, $password) =
$line =~ /^\s*(\S+)\s+(\S+)\s+(.*?)$/;
push @users, "$nick:$ircnet:$password";
$count++;
}
}
&putlog("Found $count accounts") if ($verbose > 1);
close XUSERS;
}
sub create_users() {
&putlog("Creating basic userfile in $x_passfile. Edit File.");
if(!(open XUSERS, ">", $x_passfile)) {
&putlog("Unable to create file $x_passfile");
}
print XUSERS "# username and IrcNet Tag are case insensitive\n";
print XUSERS "#\n";
print XUSERS "# username IrcNet Tag Password\n";
print XUSERS "# -------- ---------- --------\n";
close XUSERS;
chmod 0600, $x_passfile;
}
sub create_chans() {
&putlog("Creating basic channelfile in $x_chanfile. Edit File.");
if(!(open NICKCHANS, ">", $x_chanfile)) {
&putlog("Unable to create file $x_chanfile");
}
print NICKCHANS "# This file should contain a list of all channels\n";
print NICKCHANS "# which you don't want to join until after you've\n";
print NICKCHANS "# successfully identified with x. This is\n";
print NICKCHANS "# useful if you have a hidden host (+x).\n";
print NICKCHANS "# Enter Channel without `#'\n";
print NICKCHANS "#\n";
print NICKCHANS "# Channel IrcNet Tag\n";
print NICKCHANS "# -------- ----------\n";
close NICKCHANS;
chmod 0600, $x_chanfile;
}
sub read_chans() {
my $count = 0;
# Lets reset @users so we can call this as a function.
@chans = ();
if (!(open NICKCHANS, "<", $x_chanfile)) {
create_chans;
};
&putlog("Running checks on the channelfile.") if ($verbose > 1);
# first we test the file with mask 066 (we don't actually care if the
# file is executable by others.. what could they do with it =)
# Well, according to my calculations umask 066 should be 54, go figure.
my $mode = (stat($x_chanfile))[2];
if ($mode & 54) {
&putlog("your channels file should be mode 0600. Go fix it!");
&putlog("use command: chmod 0600 $x_chanfile");
}
# and then we read the channelfile.
# apparently Irssi resets $/, so we set it here.
local $/ = "\n";
while( my $line = ) {
if( $line !~ /^(#|\s*$)/ ) {
my ($channel, $ircnet) =
$line =~ /\s*(\S+)\s+(\S+)/;
push @chans, "$channel:$ircnet";
$count++;
}
}
&putlog("Found $count channels") if ($verbose > 1);
close NICKCHANS;
}
# End code from nickserv.pl
sub event_connect() {
$CONFIG{'autostart'} = Irssi::settings_get_bool('xauth_autostart');
return unless ($CONFIG{'autostart'});
my ($server) = @_;
my ($cnet) = $server->{'tag'};
my ($found);
foreach my $key (keys %masks) {
if (lc($key) eq lc($cnet)) {
$found=1;
last;
}
}
return unless($found);
$server->command("auth $cnet");
}
sub x_rehash() {
Irssi::printformat(MSGLEVEL_CLIENTNOTICE, "xauth_rehash", "$IRSSI{'name'}") if (($verbose) && (@_));
&read_users();
&read_chans();
&get_set(@_);
}
sub init_set() {
Irssi::settings_add_bool('misc', 'xauth_autostart', '0');
Irssi::settings_add_bool('misc', 'xauth_autojoin', '1');
Irssi::settings_add_bool('misc', 'xauth_hiddenhost','0');
}
sub onoff($) {
my ($value) = @_;
if ($value) {
return "On";
} else {
return "Off";
}
}
sub get_set() {
$CONFIG{'autostart'} = Irssi::settings_get_bool('xauth_autostart');
$CONFIG{'autojoin'} = Irssi::settings_get_bool('xauth_autojoin');
$CONFIG{'hiddenhost'} = Irssi::settings_get_bool('xauth_hiddenhost');
Irssi::printformat(MSGLEVEL_CLIENTNOTICE, "xauth_autostart", "$IRSSI{'name'}", &onoff("$CONFIG{'autostart'}")) if (($verbose) && (@_));
Irssi::printformat(MSGLEVEL_CLIENTNOTICE, "xauth_autojoin", "$IRSSI{'name'}", &onoff("$CONFIG{'autojoin'}")) if (($verbose) && (@_));
Irssi::printformat(MSGLEVEL_CLIENTNOTICE, "xauth_hiddenhost", "$IRSSI{'name'}", &onoff("$CONFIG{'hiddenhost'}")) if (($verbose) && (@_));
}
sub init() {
&init_set();
&x_rehash();
}
sub x_help() {
&putlog("$usage");
}
# Main
#
#
&init();
Irssi::command_bind("auth", "cmd_auth");
Irssi::command_bind("xrehash", "x_rehash");
Irssi::command_bind("xhelp", "x_help");
Irssi::signal_add("event notice", "event_notice");
Irssi::signal_add("event connected", "event_connect");
Irssi::printformat(MSGLEVEL_CLIENTNOTICE, "xauth_load", "$IRSSI{'name'}", $VERSION);