--- server/wallet-backend 2016-01-17 19:13:02.000000000 -0800 +++ /dev/null 2016-01-23 14:00:27.000000000 -0800 @@ -1,695 +0,0 @@ -#!/usr/bin/perl -# -# Wallet server for storing and retrieving secure data. - -use 5.008; -use strict; -use warnings; - -use Getopt::Long qw(GetOptions); -use Sys::Syslog qw(openlog syslog); -use Wallet::Server; - -# Set to zero to suppress syslog logging, which is used for testing and for -# the -q option. Set to a reference to a string to append messages to that -# string instead. -our $SYSLOG; -$SYSLOG = 1 unless defined $SYSLOG; - -############################################################################## -# Logging -############################################################################## - -# Initialize logging. -sub log_init { - if (ref $SYSLOG) { - $$SYSLOG = ''; - } elsif ($SYSLOG) { - openlog ('wallet-backend', 'pid', 'auth'); - } -} - -# Get an identity string for the user suitable for including in log messages. -sub identity { - my $identity = ''; - if ($ENV{REMOTE_USER}) { - $identity = $ENV{REMOTE_USER}; - my $host = $ENV{REMOTE_HOST} || $ENV{REMOTE_ADDR}; - $identity .= " ($host)" if $host; - } - return $identity; -} - -# Log an error message to both syslog and to stderr and exit with a non-zero -# status. -sub error { - my $message = join ('', @_); - if ($SYSLOG) { - my $identity = identity; - my $log; - if ($identity) { - $log = "error for $identity: $message"; - } else { - $log = "error: $message"; - } - $log =~ s/[^\x20-\x7e]/_/g; - if (ref $SYSLOG) { - $$SYSLOG .= "$log\n"; - } else { - syslog ('err', "%s", $log); - } - } - die "$message\n"; -} - -# Log a wallet failure message for a given command to both syslog and to -# stderr and exit with a non-zero status. Takes the message and the command -# that was being run. -sub failure { - my ($message, @command) = @_; - if ($SYSLOG) { - my $log = "command @command from " . identity . " failed: $message"; - $log =~ s/[^\x20-\x7e]/_/g; - if (ref $SYSLOG) { - $$SYSLOG .= "$log\n"; - } else { - syslog ('err', "%s", $log); - } - } - die "$message\n"; -} - -# Log a wallet success message for a given command. -sub success { - my (@command) = @_; - if ($SYSLOG) { - my $log = "command @command from " . identity . " succeeded"; - $log =~ s/[^\x20-\x7e]/_/g; - if (ref $SYSLOG) { - $$SYSLOG .= "$log\n"; - } else { - syslog ('info', "%s", $log); - } - } -} - -############################################################################## -# Parameter checking -############################################################################## - -# Check all arguments against a very restricted set of allowed characters and -# to ensure the right number of arguments are taken. The arguments are the -# number of arguments expected (minimum and maximum), a reference to an array -# of which argument numbers shouldn't be checked, and then the arguments. -# -# This function is probably temporary and will be replaced with something that -# knows more about the syntax of each command and can check more things. -sub check_args { - my ($min, $max, $exclude, @args) = @_; - if (@args < $min) { - error "insufficient arguments"; - } elsif (@args > $max and $max != -1) { - error "too many arguments"; - } - my %exclude = map { $_ => 1 } @$exclude; - for (my $i = 1; $i <= @args; $i++) { - next if $exclude{$i}; - unless ($args[$i - 1] =~ m,^[\w_/\@.-]*\z,) { - error "invalid characters in argument: $args[$i - 1]"; - } - } -} - -############################################################################## -# Implementation -############################################################################## - -# Parse and execute a command. We wrap this in a subroutine call for easier -# testing. -sub command { - log_init; - my $user = $ENV{REMOTE_USER} or error "REMOTE_USER not set"; - my $host = $ENV{REMOTE_HOST} || $ENV{REMOTE_ADDR} - or error "neither REMOTE_HOST nor REMOTE_ADDR set"; - - # Instantiate the server object. - my $server = Wallet::Server->new ($user, $host); - - # Parse command-line options and dispatch to the appropriate calls. - my ($command, @args) = @_; - if ($command eq 'acl') { - my $action = shift @args; - if ($action eq 'add') { - check_args (3, 3, [3], @args); - $server->acl_add (@args) or failure ($server->error, @_); - } elsif ($action eq 'check') { - check_args (1, 1, [], @args); - my $status = $server->acl_check (@args); - if (!defined ($status)) { - failure ($server->error, @_); - } else { - print $status ? "yes\n" : "no\n"; - } - } elsif ($action eq 'create') { - check_args (1, 1, [], @args); - $server->acl_create (@args) or failure ($server->error, @_); - } elsif ($action eq 'destroy') { - check_args (1, 1, [], @args); - $server->acl_destroy (@args) or failure ($server->error, @_); - } elsif ($action eq 'history') { - check_args (1, 1, [], @args); - my $output = $server->acl_history (@args); - if (defined $output) { - print $output; - } else { - failure ($server->error, @_); - } - } elsif ($action eq 'remove') { - check_args (3, 3, [3], @args); - $server->acl_remove (@args) or failure ($server->error, @_); - } elsif ($action eq 'rename') { - check_args (2, 2, [], @args); - $server->acl_rename (@args) or failure ($server->error, @_); - } elsif ($action eq 'replace') { - check_args (2, 2, [], @args); - $server->acl_replace (@args) or failure ($server->error, @_); - } elsif ($action eq 'show') { - check_args (1, 1, [], @args); - my $output = $server->acl_show (@args); - if (defined $output) { - print $output; - } else { - failure ($server->error, @_); - } - } else { - error "unknown command acl $action"; - } - } elsif ($command eq 'autocreate') { - check_args (2, 2, [], @args); - $server->autocreate (@args) or failure ($server->error, @_); - } elsif ($command eq 'check') { - check_args (2, 2, [], @args); - my $status = $server->check (@args); - if (!defined ($status)) { - failure ($server->error, @_); - } else { - print $status ? "yes\n" : "no\n"; - } - } elsif ($command eq 'comment') { - check_args (2, 3, [3], @args); - if (@args > 2) { - $server->comment (@args) or failure ($server->error, @_); - } else { - my $output = $server->comment (@args); - if (defined $output) { - print $output, "\n"; - } elsif (not $server->error) { - print "No comment set\n"; - } else { - failure ($server->error, @_); - } - } - } elsif ($command eq 'create') { - check_args (2, 2, [], @args); - $server->create (@args) or failure ($server->error, @_); - } elsif ($command eq 'destroy') { - check_args (2, 2, [], @args); - $server->destroy (@args) or failure ($server->error, @_); - } elsif ($command eq 'expires') { - check_args (2, 3, [], @args); - if (@args > 2) { - $server->expires (@args) or failure ($server->error, @_); - } else { - my $output = $server->expires (@args); - if (defined $output) { - print $output, "\n"; - } elsif (not $server->error) { - print "No expiration set\n"; - } else { - failure ($server->error, @_); - } - } - } elsif ($command eq 'flag') { - my $action = shift @args; - check_args (3, 3, [], @args); - if ($action eq 'clear') { - $server->flag_clear (@args) or failure ($server->error, @_); - } elsif ($action eq 'set') { - $server->flag_set (@args) or failure ($server->error, @_); - } else { - error "unknown command flag $action"; - } - } elsif ($command eq 'get') { - check_args (2, 2, [], @args); - my $output = $server->get (@args); - if (defined $output) { - print $output; - } else { - failure ($server->error, @_); - } - } elsif ($command eq 'getacl') { - check_args (3, 3, [], @args); - my $output = $server->acl (@args); - if (defined $output) { - print $output, "\n"; - } elsif (not $server->error) { - print "No ACL set\n"; - } else { - failure ($server->error, @_); - } - } elsif ($command eq 'getattr') { - check_args (3, 3, [], @args); - my @result = $server->attr (@args); - if (not @result and $server->error) { - failure ($server->error, @_); - } elsif (@result) { - print join ("\n", @result, ''); - } - } elsif ($command eq 'history') { - check_args (2, 2, [], @args); - my $output = $server->history (@args); - if (defined $output) { - print $output; - } else { - failure ($server->error, @_); - } - } elsif ($command eq 'owner') { - check_args (2, 3, [], @args); - if (@args > 2) { - $server->owner (@args) or failure ($server->error, @_); - } else { - my $output = $server->owner (@args); - if (defined $output) { - print $output, "\n"; - } elsif (not $server->error) { - print "No owner set\n"; - } else { - failure ($server->error, @_); - } - } - } elsif ($command eq 'rename') { - check_args (3, 3, [], @args); - $server->rename (@args) or failure ($server->error, @_); - } elsif ($command eq 'setacl') { - check_args (4, 4, [], @args); - $server->acl (@args) or failure ($server->error, @_); - } elsif ($command eq 'setattr') { - check_args (4, -1, [], @args); - $server->attr (@args) or failure ($server->error, @_); - } elsif ($command eq 'show') { - check_args (2, 2, [], @args); - my $output = $server->show (@args); - if (defined $output) { - print $output; - } else { - failure ($server->error, @_); - } - } elsif ($command eq 'store') { - check_args (2, 3, [3], @args); - if (@args == 2) { - local $/; - $args[2] = ; - } - splice (@_, 3); - $server->store (@args) or failure ($server->error, @_); - } elsif ($command eq 'update') { - check_args (2, 2, [], @args); - my $output = $server->update (@args); - if (defined $output) { - print $output; - } else { - failure ($server->error, @_); - } - } else { - error "unknown command $command"; - } - success (@_); -} - -# Parse command-line options. -my ($quiet); -Getopt::Long::config ('require_order'); -GetOptions ('q|quiet' => \$quiet) or exit 1; -$SYSLOG = 0 if $quiet; - -# Run the command. -command (@ARGV); - -__END__ - -############################################################################## -# Documentation -############################################################################## - -# The commands section of this document is duplicated from the documentation -# for wallet and should be kept in sync. - -=for stopwords -wallet-backend backend backend-specific remctld ACL acl timestamp getacl -setacl metadata keytab keytabs enctypes enctype ktadd KDC Allbery -autocreate MERCHANTABILITY NONINFRINGEMENT sublicense - -=head1 NAME - -wallet-backend - Wallet server for storing and retrieving secure data - -=head1 SYNOPSIS - -B [B<-q>] I [I ...] - -=head1 DESCRIPTION - -B implements the interface between B and the -wallet system. It is written to run under B and expects the -authenticated identity of the remote user in the REMOTE_USER environment -variable. It uses REMOTE_HOST or REMOTE_ADDR if REMOTE_HOST isn't set for -additional trace information. It accepts the command from B on -the command line, creates a Wallet::Server object, and calls the -appropriate methods. - -This program is a fairly thin wrapper around Wallet::Server that -translates command strings into method calls and returns the results. It -does check all arguments except for the argument to the store -command and rejects any argument not matching C<^[\w_/.-]+\z>; in other -words, only alphanumerics, underscore (C<_>), slash (C), period (C<.>), -and hyphen (C<->) are permitted in arguments. This provides some -additional security over and above the checking already done by the rest -of the wallet code. - -=head1 OPTIONS - -=over 4 - -=item B<--quiet>, B<-q> - -If this option is given, B will not log its actions to -syslog. - -=back - -=head1 COMMANDS - -Most commands are only available to wallet administrators (users on the -C ACL). The exceptions are C, C, C, -C, C, C, C, C, C, -C, and C. C and C can be run by -anyone. All of the rest of those commands have their own ACLs except -C and C, which use the C ACL, C, which -uses the C ACL, and C, which uses the owner or C ACL -depending on whether one is setting or retrieving the comment. If the -appropriate ACL is set, it alone is checked to see if the user has access. -Otherwise, C, C, C, C, C, C, -C, and C access is permitted if the user is authorized -by the owner ACL of the object. - -Administrators can run any command on any object or ACL except for C -and C. For C and C, they must still be authorized by -either the appropriate specific ACL or the owner ACL. - -If the locked flag is set on an object, no commands can be run on that -object that change data except the C commands, nor can the C -command be used on that object. C, C, C, -C, and C, C, or C without an argument -can still be used on that object. - -For more information on attributes, see L. - -=over 4 - -=item acl add - -Add an entry with and to the ACL . may be -either the name of an ACL or its numeric identifier. - -=item acl check - -Check whether an ACL with the ID already exists. If it does, prints -C; if not, prints C. - -=item acl create - -Create a new, empty ACL with name . When setting an ACL on an -object with a set of entries that don't match an existing ACL, first -create a new ACL with C, add the appropriate entries to it -with C, and then set the ACL on an object with the C or -C commands. - -=item acl destroy - -Destroy the ACL . This ACL must no longer be referenced by any object -or the ACL destruction will fail. The special ACL named C cannot -be destroyed. - -=item acl history - -Display the history of the ACL . Each change to the ACL (not -including changes to the name of the ACL) will be represented by two -lines. The first line will have a timestamp of the change followed by a -description of the change, and the second line will give the user who made -the change and the host from which the change was made. - -=item acl remove - -Remove the entry with and from the ACL . -may be either the name of an ACL or its numeric identifier. The last -entry in the special ACL C cannot be removed to protect against -accidental lockout, but administrators can remove themselves from the -C ACL and can leave only a non-functioning entry on the ACL. Use -caution when removing entries from the C ACL. - -=item acl rename - -Renames the ACL identified by to . This changes the -human-readable name, not the underlying numeric ID, so the ACL's -associations with objects will be unchanged. The C ACL may not be -renamed. may be either the current name or the numeric ID. -must not be all-numeric. To rename an ACL, the current user must be -authorized by the C ACL. - -=item acl replace - -Find any objects owned by , and then change their ownership to - instead. should already exist, and may already have -some objects owned by it. is not deleted afterwards, though in -most cases that is probably your next step. The C ACL may not be -replaced from. and may be either the current name or the -numeric ID. To replace an ACL, the current user must be authorized by -the C ACL. - -=item acl show - -Display the name, numeric ID, and entries of the ACL . - -=item autocreate - -Create a new object of type with name . The user must be -listed in the default ACL for an object with that type and name, and the -object will be created with that default ACL set as the object owner. - -=item check - -Check whether an object of type and name already exists. If -it does, prints C; if not, prints C. - -=item comment [] - -If is not given, displays the current comment for the object -identified by and , or C if none is set. - -If is given, sets the comment on the object identified by - and to . If is the empty string, clears -the comment. - -=item create - -Create a new object of type with name . With some backends, -this will trigger creation of an entry in an external system as well. -The new object will have no ACLs and no owner set, so usually the -administrator will want to then set an owner with C so that the -object will be usable. - -=item destroy - -Destroy the object identified by and . With some backends, -this will trigger destruction of an object in an external system as well. - -=item expires [ [