chiark / gitweb /
Bugfixes.
[userv-utils.git] / finger / in.fingerd
1 #!/usr/bin/perl --
2
3 use POSIX;
4
5 setup();
6 read_config();
7 read_services();
8 parse_query();
9 process_query();
10
11 sub process_query () {
12     if (exists $services{$query}) {
13
14         exec ($verbose && length $services{$query}->{'verbose'} ?
15                 $services{$query}->{'verbose'} :
16                 $services{$query}->{'command'});
17         die $!;
18
19     }
20
21     if ($query eq '/') {
22
23         print ("userv fingerd on $hostname\r\n".
24                "queries supported:\r\n".
25                "\r\n".
26                "  <nothing>     list of logged on users and available services\r\n".
27                "  /             this help text\r\n".
28                "  <service>     separately advertised special finger service\r\n".
29                "  <user>        user (logged in or otherwise)\r\n".
30                "  <user>+<xtra> user-provided extended/special finger service\r\n".
31                "  /<substring>  search for user matching substring\r\n")
32             or die $!;
33
34         return;
35
36     }
37
38     if (!length $query) {
39
40         read_per_user();
41
42         if ($verbose) {
43             print "Username Idle  Msg,tty   Login at     From\r\n" or die $!;
44         }
45         
46         open W,"who -iw|" or die $!;
47         while (<W>) {
48
49             m/^(\w+) +(\S) +(\S+) +(\w+ +\d+ \d\d\:\d\d) +(\S+) +(.*)$/ or die;
50             ($user, $mesg, $tty, $login, $idle, $from) = ($1,$2,$3,$4,$5,$6);
51             $mesg = $mesg =~ m/[-+]/ ? $& : '?';
52
53             if ($tty =~ m/\./) {
54                 $from =~ s/.$/$& /;
55                 $from.= $tty;
56                 $tty= '';
57             }
58             
59             $pref= exists $user_pref_list{$user}
60                 ? $user_pref_list{$user} : $def_pref_list;
61             next unless $pref =~ m/^\+/;
62
63             $idle= '' unless $pref =~ m/i/;
64             $mesg= ' ' unless $pref =~ m/m/;
65             $tty= '' unless $pref =~ m/t/;
66             $login= '' unless $pref =~ m/l/;
67             $from= '' unless $pref =~ m/t/;
68             
69             if ($verbose) {
70
71                 printf "%-8s %-5s %s%-8s %-12s %s\r\n",
72                     $user, $idle, $mesg, $tty, $login, $from
73                         or die $!;
74             } else {
75                 $users{$user}->{'pref'} = $pref;
76                 $users{$user}->{'mesg'}->{$mesg} = 1;
77                 $users{$user}->{'idle'} = min_idle($users{$user}->{'idle'}, $idle);
78             }
79
80         }
81         $!=0; close W; $? and die "$! $?";
82
83         if (!$verbose) {
84             print "Username Idle  Msg  Name\r\n" or die $!;
85
86             for $user (sort keys %users) {
87                 $pref= $users{$user}->{'pref'};
88                 $name= $pref =~ m/n/ ? (getpwnam($user))[6] : '';
89                 $name =~ s/,.*//;
90                 $mesg= join('', sort keys %{ $users{$user}->{'mesg'} });
91                 $mesg= '+' if $mesg =~ m,\+,;
92                 printf "%-8s %-5s %s    %s\r\n",
93                     $user, $users{$user}->{'idle'}, $mesg, $name
94                         or die $!;
95             }
96         }
97
98         foreach $service (sort keys %services) {
99             $desc= $services{$service}->{'desc'};
100             next unless length $desc;
101
102             if (!$anyservice) {
103                 print "\r\nService      Description\r\n" or die $!;
104                 $anyservice= 1;
105             }
106             
107             printf "%-12s %s\r\n", $service, $desc or die $!;
108         }
109         
110         print "\r\nFor help, finger /\@$hostname\r\n";
111         return;
112         
113     }
114
115     if ($query =~ s,^/,,) {
116         $query =~ s/\W/\\$&/g;
117         read_per_user();
118
119         while (($user,$passwd,$uid,$gid,$quota,$comment,$name) = getpwent) {
120             $name =~ s/,.*//;
121
122             $pref= exists $user_pref_search{$user}
123                 ? $user_pref_search{$user}
124                 : $def_pref_search;
125             next unless $pref =~ m/[uy]/;
126             $name= '' unless $pref =~ m/y/;
127             next unless query_match($user) || query_match($name);
128
129             if (!$found) {
130                 print "Username  Name\r\n" or die $!;
131                 $found= 1;
132             }
133             printf "%-9s %s\r\n", $user,$name or die $!;
134
135         }
136
137         if (!$found) {
138             print "No matches.  finger /\@$hostname for help.\r\n" or die $!;
139         }
140
141         return;
142     }
143
144     if ($query =~ s/\+.*$//) { $qsuffix= $&; }
145
146     if (!(($user)= getpwnam($query))) {
147         print "No user named \`$query'.  finger /\@$hostname for help.\r\n" or die $!;
148         return;
149     }
150
151     @servcmd= length $qsuffix
152         ? ('finger-finger')
153         : ('finger-extended',$qsuffix);
154     exec 'userv','-t',300,$user,@list;
155     die $!;
156
157 }
158
159 sub query_match ($) {
160     my ($data) = @_;
161     return $data =~ m/\b$query\b/io;
162 }
163
164 sub setup () {
165     $progname= $0; $progname =~ s,.*/,,;
166     alarm(300);
167
168     $config= '/etc/finger-userv/config';
169
170     if (@ARGV) { @ARGV == 1 or die; $config= $ARGV[1]; }
171     $services= '/etc/userv/finger/services';
172     $peruser= '/var/lib/userv/finger/prefs';
173     $def_pref_list= '+m';  $list_fields= 'imtlfn';
174     $def_pref_search= 'y';  $search_opts= 'nuy';
175 }
176
177 sub parse_query () {
178     $query= <STDIN>;
179     $query =~ s/\r?\n$// or die "$0: no query\n";
180
181     $verbose = $query =~ s,^/[wW],,;
182     $query =~ s/^ *//;
183 }
184
185 sub min_idle ($$) {
186     my ($a,$b) = @_;
187     return '.' if $a eq '.' || $b eq '.';
188     return $b if $a eq 'old' || $a eq '';
189     return $a if $b eq 'old' || $b eq '';;
190     return $a le $b ? $a : $b;
191 }
192
193 sub read_config () {
194     if (open C, "$config") {
195         while (<C>) {
196             chomp; s/\s+$//; s/^\s+//;
197             if (m/^default\-pref\s+([-+][$list_fields]+)\s+([$search_opts])$/) {
198                 $def_pref_list= $1;
199                 $def_pref_search= $2;
200             } elsif (m/^hostname\s+(\S+)$/) {
201                 $hostname= $1;
202             } elsif (m/^prefs\-file\s+(\S.*)$/) {
203                 $peruser= $1;
204             } elsif (m/^services\-file\s+(\S.*)$/) {
205                 $services= $1;
206             } elsif (m/\S/ && !m/^\#/) {
207                 die;
208             }
209         }
210         close C or die $!;
211     } elsif ($! != &ENOENT) {
212         die $!;
213     }
214
215     if (!defined $hostname) {
216         chomp($hostname= `hostname -f`);
217         length $hostname or die $?;
218     }
219 }
220
221 sub read_services () {
222     if (open C, "$services") {
223         while (<C>) {
224             chomp; s/\s+$//; s/^\s+//;
225             next if m/^\#/ || !m/\S/;
226             if (m/^service\s+(\S.*)$/) {
227                 $sname= $1;
228                 die if exists $services{$sname};
229             } elsif (m/^(desc|command|verbose)\s+(\S.*)$/) {
230                 die if exists $services{$sname}->{$1};
231                 $services{$sname}->{$1}= $2;
232             } else {
233                 die;
234             }
235         }
236         close C;
237         foreach $sname (keys %services) {
238             die unless exists $services{$sname}->{'command'};
239         }
240     } elsif ($! != &ENOENT) {
241         die $!;
242     }
243 }
244
245 sub read_per_user () {
246     if (open DL, "$peruser") {
247         while (<DL>) {
248             m/^(\w+) ([-+][$list_fields]+) ([$search_opts])$/ or die;
249             $user_pref_list{$1}= $2;
250             $user_pref_search{$1}= $3;
251         }
252         close DL;
253     } elsif ($! != &ENOENT) {
254         die $!;
255     }
256 }