html/xauth.pl
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
53 use Irssi;
54 use Irssi::Irc;
55
56 use strict;
57
58 use 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
71 my (%CONFIG) = (
72 autostart => '',
73 autojoin => '',
74 hiddenhost => ''
75 );
76
77 Irssi::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
96 my ($usage) = qq!X-Authentication v$VERSION by Toshio Spoor
97
98 Usage:
99 /auth <chatnet>
100
101 Settings:
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
107 Rehashing 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
128 my (%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
137 my ($verbose) = 1;
138
139 # Don't touch these, unless the signature changes.
140 #
141 my ($success) = "AUTHENTICATION SUCCESSFUL";
142 my ($already) = "Sorry, You are already authenticated";
143 my ($failed) = "AUTHENTICATION FAILED";
144 my ($remind) = "Remember: Nobody from CService will ever ask you for your password, do NOT give";
145 my ($nouser) = "I don't know who";
146
147 # Global Vars, don't change these.
148 #
149 my ($x_passfile) = Irssi::get_irssi_dir() ."/x.users";
150 my ($x_chanfile) = Irssi::get_irssi_dir() ."/x.channels";
151
152 my (@users) = ();
153 my (@chans) = ();
154
155 # Core Code
156 #
157 #
158
159 sub putlog() {
160
161 my ($window) = Irssi::active_win();
162 Irssi::print("[$IRSSI{'name'}] @_", MSGLEVEL_CLIENTNOTICE);
163
164 }
165
166 sub haltdef() {
167
168 Irssi::signal_stop();
169
170 }
171
172 sub conn($) {
173
174 my ($server) = @_;
175
176 if (!$server || !$server->{connected}) {
177 return 0;
178 } else {
179 return 1;
180 }
181
182 }
183
184 sub 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
213 sub 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
229 sub 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
284 sub 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
341 sub 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 $/ = "\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
378 sub 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
395 sub 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
414 sub 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 $/ = "\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
453 sub 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
476 sub 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
486 sub 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
494 sub onoff($) {
495
496 my ($value) = @_;
497
498 if ($value) {
499 return "On";
500 } else {
501 return "Off";
502 }
503
504 }
505
506 sub 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
518 sub init() {
519
520 &init_set();
521 &x_rehash();
522
523
524 }
525
526 sub x_help() {
527
528 &putlog("$usage");
529
530 }
531
532
533 # Main
534 #
535 #
536
537 &init();
538
539 Irssi::command_bind("auth", "cmd_auth");
540 Irssi::command_bind("xrehash", "x_rehash");
541 Irssi::command_bind("xhelp", "x_help");
542
543 Irssi::signal_add("event notice", "event_notice");
544 Irssi::signal_add("event connected", "event_connect");
545
546 Irssi::printformat(MSGLEVEL_CLIENTNOTICE, "xauth_load", "$IRSSI{'name'}", $VERSION);