--- /dev/null
+# Copyright (C) 2000 Ian Jackson
+#
+# This 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 of the License, 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 GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with userv-utils; if not, write to the Free Software
+# Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# $Id: Makefile,v 1.1 2000/05/20 20:04:03 ian Exp $
+
+etcdir= /etc
+var= /var
+varlib= $(var)/lib
+prefix= /usr/local
+bindir= $(prefix)/bin
+sbindir= $(prefix)/sbin
+
+libdir= $(prefix)/lib
+libuserv= $(libdir)/userv
+libfinger= $(libuserv)/finger
+
+varuserv= $(varlib)/userv
+varfinger= $(varuserv)/finger
+
+etcuserv= $(etcdir)/userv
+etcfinger= $(etcuserv)/finger
+uservicesd= $(etcuserv)/services.d
+
+user= daemon
+
+ROOTMKDIRS= $(etcfinger) $(uservicesd) $(libfinger) $(varuserv)
+USERVICES= finger-notmyself finger-finger finger-getprefs finger-setprefs
+FINGERCONFS= config services
+TARGETS= $(FINGERCONFS) $(USERVICES)
+
+SUBSTVARS= user etcfinger varfinger libfinger
+SEDSCRIPT= '$(foreach f, $(SUBSTVARS), s,@$f@,$($f),g; )'
+
+all: $(TARGETS)
+
+%: %.in
+ sed -e $(SEDSCRIPT) <$< >$@.new && mv -f $@.new $@
+
+install: all
+ install -d -m 755 -o root $(ROOTMKDIRS)
+ install -d -m 700 -o $(user) $(varfinger)
+ install -m 755 in.fingerd $(sbindir)
+ install -m 755 setprefs $(libfinger)
+ ./install-confs $(etcfinger) $(FINGERCONFS)
+ ./install-confs $(uservicesd) $(USERVICES)
+
+fresh-install: erase-configs install
+
+erase-configs:
+ cd $(etcfinger); rm -f $(FINGERCONFS)
+ cd $(uservicesd); rm -f $(USERVICES)
--- /dev/null
+# This configuration file controls the userv finger daemon
+# The possible directives in it are:
+# default-pref <logged-on-list-preference> <search-preference>
+# hostname <hostname>
+# prefs-file <per-user-preferences-file>
+# services-file <extended-services-file>
+# Blank lines and #-comments are allowed.
+#
+# The per-user prefs file has a list of
+# <username> <logged-on-list-preference> <search-preference>
+# and may NOT contain blank lines or comments. It is supposed
+# to be edited only by the finger-pref userv service.
+#
+# The logged-on-list preference controls how, if at all, a user
+# appears in the list of logged on users. It may be is either `-', or
+# `+' followed by a possibly-empty list of fields to show. `-' means
+# that the user will not appear, whether they are logged on or not.
+# `+' means that they will appear. It may be followed by one or more
+# of the following letters:
+# i Show the idle time
+# m Show whether the session is accepting messages (`mesg')
+# t Show why tty the session is on
+# l Show when the session started (ie, when the user logged on)
+# f Show where the user is logged on from
+# n Show the user's name (from the passwd file GCOS field)
+#
+# The search-preference controls how, if at all, a user's details will
+# be used and their information returned, in response to a search request.
+# n The user will never be returned for a search request
+# u Only matches against their username will count, and only their
+# username will be displayed.
+# y Matching is performed against username or full name and both
+# are displayed.
+#
+# The extended services file is usually the file `services' in
+# this directory.
+
+default-pref +m y
+services-file @etcfinger@/services
+prefs-file @varfinger@/prefs
--- /dev/null
+#!/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".
+ " <nothing> list of logged on users and available services\r\n".
+ " / this help text\r\n".
+ " <service> separately advertised special finger service\r\n".
+ " <user> user (logged in or otherwise)\r\n".
+ " <user>+<xtra> user-provided extended/special finger service\r\n".
+ " /<substring> 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 (<W>) {
+
+ 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= <STDIN>;
+ $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 (<C>) {
+ 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 (<C>) {
+ 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 (<DL>) {
+ m/^(\w+) ([-+][$list_fields]+) ([$search_opts])$/ or die;
+ $user_pref_list{$1}= $2;
+ $user_pref_search{$1}= $3;
+ }
+ close DL;
+ } elsif ($! != &ENOENT) {
+ die $!;
+ }
+}