diff options
-rwxr-xr-x | contrib/wallet-contacts | 193 |
1 files changed, 193 insertions, 0 deletions
diff --git a/contrib/wallet-contacts b/contrib/wallet-contacts new file mode 100755 index 0000000..a7bccf3 --- /dev/null +++ b/contrib/wallet-contacts @@ -0,0 +1,193 @@ +#!/usr/bin/perl -w +# +# wallet-contacts -- Report contact addresses for matching wallet objects. +# +# Written by Russ Allbery <rra@stanford.edu> +# Copyright 2009 Board of Trustees, Leland Stanford Jr. University +# +# See LICENSE for licensing terms. + +############################################################################## +# Modules and declarations +############################################################################## + +require 5.006; + +use strict; + +use Getopt::Long qw(GetOptions); +use Wallet::Admin (); + +# Used to cache lookups of e-mail addresses by identifiers. +our %EMAIL; + +############################################################################## +# whois lookups +############################################################################## + +# Given the directory handle of a user, look up their e-mail address. This +# assumes the Stanford-specific swhois program. +sub person_email { + my ($identifier) = @_; + return $EMAIL{$identifier} if exists $EMAIL{$identifier}; + my @output = `swhois '$identifier'`; + for my $line (@output) { + if ($line =~ /^\s*Email:\s*(\S+)/i) { + $EMAIL{$identifier} = $1; + return $1; + } elsif ($line =~ /^\s*SUNet IDs:\s*(\S+)/) { + my $email = $1 . '@stanford.edu'; + $EMAIL{$identifier} = $email; + return $email; + } + } + warn "$0: unable to find email address for identifier $identifier\n"; + $EMAIL{$identifier} = undef; + return; +} + +# Look up a system in whois and return the e-mail address or addresses of the +# administrator. +sub whois_lookup { + my ($system) = @_; + my @output = `swhois '$system'`; + my ($inadmin, @users, @admins); + for (@output) { + if (/^\s*administrator:\s*(?:\S+\s+)+\((d\S+)\)\s*$/i) { + push (@admins, person_email ($1)); + $inadmin = 1; + } elsif (/^\s*administrator:/i) { + $inadmin = 1; + } elsif (/^\s*group:/i) { + $inadmin = 0; + } elsif ($inadmin and /^\s*e-?mail: (\S+)/i) { + push (@admins, $1); + } elsif ($inadmin and /^\s*(?:\S+\s+)+\((d\S+)\)\s*$/i) { + push (@admins, person_email ($1)); + } elsif (/^\s*user:\s*(?:\S+\s+)+\((d\S+)\)\s*$/i) { + push (@users, person_email ($1)); + } + } + @admins = @users if !@admins; + warn "$0: unable to find administrator for $system\n" unless @admins; + return @admins; +} + +############################################################################## +# Main routine +############################################################################## + +# Read in command-line options. +my ($help); +Getopt::Long::config ('no_ignore_case', 'bundling'); +GetOptions ('help|h' => \$help) or exit 1; +if ($help) { + print "Feeding myself to perldoc, please wait....\n"; + exec ('perldoc', '-t', $0); +} +my ($type, $name) = @ARGV; +if (@ARGV > 2 or not defined $name) { + die "Usage: wallet-contacts <type> <name>\n"; +} + +# Clean up $0 for error reporting. +$0 =~ s%.*/%%; + +# Gather the list of ACL lines. +my $admin = Wallet::Admin->new; +my @lines = $admin->report_owners ($type, $name); +if (!@lines and $admin->error) { + die $admin->error, "\n"; +} + +# Now, for each line, turn it into an e-mail address. krb5 ACLs go as-is if +# they are regular user principals. If they're other principals, ignore them +# unless they're of the form host/*, in which case extract the host and treat +# it the same as a netdb ACL. netdb and netdb-root ACLs result in a whois +# lookup on that host, extracting the e-mail address of the administrator +# group. If there is no e-mail address, extract the user and look up their +# e-mail address. +my @email; +for (@lines) { + my ($scheme, $identifier) = @$_; + my $machine; + if ($scheme eq 'krb5') { + if ($identifier =~ m,^[^/]+\@,) { + push (@email, $identifier); + } elsif ($identifier =~ m,^host/([^/]+)\@,) { + $machine = $1; + } + } elsif ($scheme eq 'netdb' or $scheme eq 'netdb-root') { + $machine = $identifier; + } + if ($machine) { + push (@email, whois_lookup ($machine)); + } +} + +# We now have a list of e-mail addresses. De-duplicate and then print them +# out. +my %seen; +@email = grep { !$seen{$_}++ } sort @email; +print join ("\n", @email, ''); + +############################################################################## +# Documentation +############################################################################## + +=head1 NAME + +wallet-contacts - Report contact addresses for matching wallet objects + +=head1 SYNOPSIS + +B<wallet-contacts> [B<-h>] I<type-pattern> I<name-pattern> + +=head1 DESCRIPTION + +B<wallet-contacts> returns a list of e-mail addresses corresponding to +members of owner ACLs for all objects in the wallet database matching +I<type-pattern> and I<name-pattern>. The patterns can be wallet object +types or names, or they can be SQL patterns using C<%> as a wildcard. + +C<krb5> ACL schemes will return the corresponding identifier as an e-mail +address unless it contains a C</>. If it contains C</>, it will be +ignored except for principals of the form C<host/I<hostname>>, which will +have I<hostname> treated as if it were the identifier in a C<netdb> ACL. + +C<netdb> and C<netdb-root> ACL schemes will return the e-mail address from +a whois lookup of the corresponding NetDB object. B<wallet-contacts> will +run B<whois> on the system name and search the output for users and +administrators. E-mail addresses for admin groups will be returned as-is. +Administrators will result in a second lookup via B<swhois> for their +directory handle, returning the corresponding e-mail address if found in +their whois record. If there are no administrators or admin teams with +e-mail addresses, the value of the user key, if any, will be looked up +similar to an administrator. + +If B<wallet-contacts> is unable to find any contact for a host or any +e-mail address for an administrator or user, it will warn but continue. + +=head1 OPTIONS + +=over 4 + +=item B<-h>, B<--help> + +Print out this documentation (which is done simply by feeding the script +to C<perldoc -t>). + +=back + +=head1 CAVEATS + +Many of the assumptions made by this script are Stanford-specific, such as +the ability to use Kerberos principals as-is as e-mail addresses, the +B<swhois> program for looking up people, and the parsing of the B<whois> +output format. + +=head1 AUTHOR + +Russ Allbery <rra@stanford.edu> + +=cut |