#!/usr/bin/perl -- use POSIX; setup(); read_config(); read_services(); parse_query(); process_query(); sub process_query () { if (exists $services{$query}) { exec ($verbose && length $services{$query}->{'verbose'} ? $services{$query}->{'verbose'} : $services{$query}->{'command'}); die $!; } if ($query eq '/') { print ("userv fingerd on $hostname\r\n". "queries supported:\r\n". "\r\n". " list of logged on users and available services\r\n". " / this help text\r\n". " separately advertised special finger service\r\n". " user (logged in or otherwise)\r\n". " + user-provided extended/special finger service\r\n". " / search for user matching substring\r\n") or die $!; return; } if (!length $query) { read_per_user(); if ($verbose) { print "Username Idle Msg,tty Login at From\r\n" or die $!; } open W,"who -iw|" or die $!; while () { m/^(\w+) +(\S) +(\S+) +(\w+ +\d+ \d\d\:\d\d) +(\S+) +(.*)$/ or die; ($user, $mesg, $tty, $login, $idle, $from) = ($1,$2,$3,$4,$5,$6); $mesg = $mesg =~ m/[-+]/ ? $& : '?'; if ($tty =~ m/\./) { $from =~ s/.$/$& /; $from.= $tty; $tty= ''; } $pref= exists $user_pref_list{$user} ? $user_pref_list{$user} : $def_pref_list; next unless $pref =~ m/^\+/; $idle= '' unless $pref =~ m/i/; $mesg= ' ' unless $pref =~ m/m/; $tty= '' unless $pref =~ m/t/; $login= '' unless $pref =~ m/l/; $from= '' unless $pref =~ m/t/; if ($verbose) { printf "%-8s %-5s %s%-8s %-12s %s\r\n", $user, $idle, $mesg, $tty, $login, $from or die $!; } else { $users{$user}->{'pref'} = $pref; $users{$user}->{'mesg'}->{$mesg} = 1; $users{$user}->{'idle'} = min_idle($users{$user}->{'idle'}, $idle); } } $!=0; close W; $? and die "$! $?"; if (!$verbose) { print "Username Idle Msg Name\r\n" or die $!; for $user (sort keys %users) { $pref= $users{$user}->{'pref'}; $name= $pref =~ m/n/ ? (getpwnam($user))[6] : ''; $name =~ s/,.*//; $mesg= join('', sort keys %{ $users{$user}->{'mesg'} }); $mesg= '+' if $mesg =~ m,\+,; printf "%-8s %-5s %s %s\r\n", $user, $users{$user}->{'idle'}, $mesg, $name or die $!; } } foreach $service (sort keys %services) { $desc= $services{$service}->{'desc'}; next unless length $desc; if (!$anyservice) { print "\r\nService Description\r\n" or die $!; $anyservice= 1; } printf "%-12s %s\r\n", $service, $desc or die $!; } print "\r\nFor help, finger /\@$hostname\r\n"; return; } if ($query =~ s,^/,,) { $query =~ s/\W/\\$&/g; read_per_user(); while (($user,$passwd,$uid,$gid,$quota,$comment,$name) = getpwent) { $name =~ s/,.*//; $pref= exists $user_pref_search{$user} ? $user_pref_search{$user} : $def_pref_search; next unless $pref =~ m/[uy]/; $name= '' unless $pref =~ m/y/; next unless query_match($user) || query_match($name); if (!$found) { print "Username Name\r\n" or die $!; $found= 1; } printf "%-9s %s\r\n", $user,$name or die $!; } if (!$found) { print "No matches. finger /\@$hostname for help.\r\n" or die $!; } return; } if ($query =~ s/\+.*$//) { $qsuffix= $&; } if (!(($user)= getpwnam($query))) { print "No user named \`$query'. finger /\@$hostname for help.\r\n" or die $!; return; } @servcmd= length $qsuffix ? ('finger-finger') : ('finger-extended',$qsuffix); exec 'userv','-t',300,$user,@list; die $!; } sub query_match ($) { my ($data) = @_; return $data =~ m/\b$query\b/io; } sub setup () { $progname= $0; $progname =~ s,.*/,,; alarm(300); $config= '/etc/finger-userv/config'; if (@ARGV) { @ARGV == 1 or die; $config= $ARGV[1]; } $services= '/etc/userv/finger/services'; $peruser= '/var/lib/userv/finger/prefs'; $def_pref_list= '+m'; $list_fields= 'imtlfn'; $def_pref_search= 'y'; $search_opts= 'nuy'; } sub parse_query () { $query= ; $query =~ s/\r?\n$// or die "$0: no query\n"; $verbose = $query =~ s,^/[wW],,; $query =~ s/^ *//; } sub min_idle ($$) { my ($a,$b) = @_; return '.' if $a eq '.' || $b eq '.'; return $b if $a eq 'old' || $a eq ''; return $a if $b eq 'old' || $b eq '';; return $a le $b ? $a : $b; } sub read_config () { if (open C, "$config") { while () { chomp; s/\s+$//; s/^\s+//; if (m/^default\-pref\s+([-+][$list_fields]+)\s+([$search_opts])$/) { $def_pref_list= $1; $def_pref_search= $2; } elsif (m/^hostname\s+(\S+)$/) { $hostname= $1; } elsif (m/^prefs\-file\s+(\S.*)$/) { $peruser= $1; } elsif (m/^services\-file\s+(\S.*)$/) { $services= $1; } elsif (m/\S/ && !m/^\#/) { die; } } close C or die $!; } elsif ($! != &ENOENT) { die $!; } if (!defined $hostname) { chomp($hostname= `hostname -f`); length $hostname or die $?; } } sub read_services () { if (open C, "$services") { while () { chomp; s/\s+$//; s/^\s+//; next if m/^\#/ || !m/\S/; if (m/^service\s+(\S.*)$/) { $sname= $1; die if exists $services{$sname}; } elsif (m/^(desc|command|verbose)\s+(\S.*)$/) { die if exists $services{$sname}->{$1}; $services{$sname}->{$1}= $2; } else { die; } } close C; foreach $sname (keys %services) { die unless exists $services{$sname}->{'command'}; } } elsif ($! != &ENOENT) { die $!; } } sub read_per_user () { if (open DL, "$peruser") { while (
) { m/^(\w+) ([-+][$list_fields]+) ([$search_opts])$/ or die; $user_pref_list{$1}= $2; $user_pref_search{$1}= $3; } close DL; } elsif ($! != &ENOENT) { die $!; } }