Ticket #50421: patch-rename-server-wallet-backend.diff
File patch-rename-server-wallet-backend.diff, 51.8 KB (added by akkornel (A. Karl Kornel), 8 years ago) |
---|
-
deleted file server/wallet-backend
+ - 1 #!/usr/bin/perl2 #3 # Wallet server for storing and retrieving secure data.4 5 use 5.008;6 use strict;7 use warnings;8 9 use Getopt::Long qw(GetOptions);10 use Sys::Syslog qw(openlog syslog);11 use Wallet::Server;12 13 # Set to zero to suppress syslog logging, which is used for testing and for14 # the -q option. Set to a reference to a string to append messages to that15 # string instead.16 our $SYSLOG;17 $SYSLOG = 1 unless defined $SYSLOG;18 19 ##############################################################################20 # Logging21 ##############################################################################22 23 # Initialize logging.24 sub log_init {25 if (ref $SYSLOG) {26 $$SYSLOG = '';27 } elsif ($SYSLOG) {28 openlog ('wallet-backend', 'pid', 'auth');29 }30 }31 32 # Get an identity string for the user suitable for including in log messages.33 sub identity {34 my $identity = '';35 if ($ENV{REMOTE_USER}) {36 $identity = $ENV{REMOTE_USER};37 my $host = $ENV{REMOTE_HOST} || $ENV{REMOTE_ADDR};38 $identity .= " ($host)" if $host;39 }40 return $identity;41 }42 43 # Log an error message to both syslog and to stderr and exit with a non-zero44 # status.45 sub error {46 my $message = join ('', @_);47 if ($SYSLOG) {48 my $identity = identity;49 my $log;50 if ($identity) {51 $log = "error for $identity: $message";52 } else {53 $log = "error: $message";54 }55 $log =~ s/[^\x20-\x7e]/_/g;56 if (ref $SYSLOG) {57 $$SYSLOG .= "$log\n";58 } else {59 syslog ('err', "%s", $log);60 }61 }62 die "$message\n";63 }64 65 # Log a wallet failure message for a given command to both syslog and to66 # stderr and exit with a non-zero status. Takes the message and the command67 # that was being run.68 sub failure {69 my ($message, @command) = @_;70 if ($SYSLOG) {71 my $log = "command @command from " . identity . " failed: $message";72 $log =~ s/[^\x20-\x7e]/_/g;73 if (ref $SYSLOG) {74 $$SYSLOG .= "$log\n";75 } else {76 syslog ('err', "%s", $log);77 }78 }79 die "$message\n";80 }81 82 # Log a wallet success message for a given command.83 sub success {84 my (@command) = @_;85 if ($SYSLOG) {86 my $log = "command @command from " . identity . " succeeded";87 $log =~ s/[^\x20-\x7e]/_/g;88 if (ref $SYSLOG) {89 $$SYSLOG .= "$log\n";90 } else {91 syslog ('info', "%s", $log);92 }93 }94 }95 96 ##############################################################################97 # Parameter checking98 ##############################################################################99 100 # Check all arguments against a very restricted set of allowed characters and101 # to ensure the right number of arguments are taken. The arguments are the102 # number of arguments expected (minimum and maximum), a reference to an array103 # of which argument numbers shouldn't be checked, and then the arguments.104 #105 # This function is probably temporary and will be replaced with something that106 # knows more about the syntax of each command and can check more things.107 sub check_args {108 my ($min, $max, $exclude, @args) = @_;109 if (@args < $min) {110 error "insufficient arguments";111 } elsif (@args > $max and $max != -1) {112 error "too many arguments";113 }114 my %exclude = map { $_ => 1 } @$exclude;115 for (my $i = 1; $i <= @args; $i++) {116 next if $exclude{$i};117 unless ($args[$i - 1] =~ m,^[\w_/\@.-]*\z,) {118 error "invalid characters in argument: $args[$i - 1]";119 }120 }121 }122 123 ##############################################################################124 # Implementation125 ##############################################################################126 127 # Parse and execute a command. We wrap this in a subroutine call for easier128 # testing.129 sub command {130 log_init;131 my $user = $ENV{REMOTE_USER} or error "REMOTE_USER not set";132 my $host = $ENV{REMOTE_HOST} || $ENV{REMOTE_ADDR}133 or error "neither REMOTE_HOST nor REMOTE_ADDR set";134 135 # Instantiate the server object.136 my $server = Wallet::Server->new ($user, $host);137 138 # Parse command-line options and dispatch to the appropriate calls.139 my ($command, @args) = @_;140 if ($command eq 'acl') {141 my $action = shift @args;142 if ($action eq 'add') {143 check_args (3, 3, [3], @args);144 $server->acl_add (@args) or failure ($server->error, @_);145 } elsif ($action eq 'check') {146 check_args (1, 1, [], @args);147 my $status = $server->acl_check (@args);148 if (!defined ($status)) {149 failure ($server->error, @_);150 } else {151 print $status ? "yes\n" : "no\n";152 }153 } elsif ($action eq 'create') {154 check_args (1, 1, [], @args);155 $server->acl_create (@args) or failure ($server->error, @_);156 } elsif ($action eq 'destroy') {157 check_args (1, 1, [], @args);158 $server->acl_destroy (@args) or failure ($server->error, @_);159 } elsif ($action eq 'history') {160 check_args (1, 1, [], @args);161 my $output = $server->acl_history (@args);162 if (defined $output) {163 print $output;164 } else {165 failure ($server->error, @_);166 }167 } elsif ($action eq 'remove') {168 check_args (3, 3, [3], @args);169 $server->acl_remove (@args) or failure ($server->error, @_);170 } elsif ($action eq 'rename') {171 check_args (2, 2, [], @args);172 $server->acl_rename (@args) or failure ($server->error, @_);173 } elsif ($action eq 'replace') {174 check_args (2, 2, [], @args);175 $server->acl_replace (@args) or failure ($server->error, @_);176 } elsif ($action eq 'show') {177 check_args (1, 1, [], @args);178 my $output = $server->acl_show (@args);179 if (defined $output) {180 print $output;181 } else {182 failure ($server->error, @_);183 }184 } else {185 error "unknown command acl $action";186 }187 } elsif ($command eq 'autocreate') {188 check_args (2, 2, [], @args);189 $server->autocreate (@args) or failure ($server->error, @_);190 } elsif ($command eq 'check') {191 check_args (2, 2, [], @args);192 my $status = $server->check (@args);193 if (!defined ($status)) {194 failure ($server->error, @_);195 } else {196 print $status ? "yes\n" : "no\n";197 }198 } elsif ($command eq 'comment') {199 check_args (2, 3, [3], @args);200 if (@args > 2) {201 $server->comment (@args) or failure ($server->error, @_);202 } else {203 my $output = $server->comment (@args);204 if (defined $output) {205 print $output, "\n";206 } elsif (not $server->error) {207 print "No comment set\n";208 } else {209 failure ($server->error, @_);210 }211 }212 } elsif ($command eq 'create') {213 check_args (2, 2, [], @args);214 $server->create (@args) or failure ($server->error, @_);215 } elsif ($command eq 'destroy') {216 check_args (2, 2, [], @args);217 $server->destroy (@args) or failure ($server->error, @_);218 } elsif ($command eq 'expires') {219 check_args (2, 3, [], @args);220 if (@args > 2) {221 $server->expires (@args) or failure ($server->error, @_);222 } else {223 my $output = $server->expires (@args);224 if (defined $output) {225 print $output, "\n";226 } elsif (not $server->error) {227 print "No expiration set\n";228 } else {229 failure ($server->error, @_);230 }231 }232 } elsif ($command eq 'flag') {233 my $action = shift @args;234 check_args (3, 3, [], @args);235 if ($action eq 'clear') {236 $server->flag_clear (@args) or failure ($server->error, @_);237 } elsif ($action eq 'set') {238 $server->flag_set (@args) or failure ($server->error, @_);239 } else {240 error "unknown command flag $action";241 }242 } elsif ($command eq 'get') {243 check_args (2, 2, [], @args);244 my $output = $server->get (@args);245 if (defined $output) {246 print $output;247 } else {248 failure ($server->error, @_);249 }250 } elsif ($command eq 'getacl') {251 check_args (3, 3, [], @args);252 my $output = $server->acl (@args);253 if (defined $output) {254 print $output, "\n";255 } elsif (not $server->error) {256 print "No ACL set\n";257 } else {258 failure ($server->error, @_);259 }260 } elsif ($command eq 'getattr') {261 check_args (3, 3, [], @args);262 my @result = $server->attr (@args);263 if (not @result and $server->error) {264 failure ($server->error, @_);265 } elsif (@result) {266 print join ("\n", @result, '');267 }268 } elsif ($command eq 'history') {269 check_args (2, 2, [], @args);270 my $output = $server->history (@args);271 if (defined $output) {272 print $output;273 } else {274 failure ($server->error, @_);275 }276 } elsif ($command eq 'owner') {277 check_args (2, 3, [], @args);278 if (@args > 2) {279 $server->owner (@args) or failure ($server->error, @_);280 } else {281 my $output = $server->owner (@args);282 if (defined $output) {283 print $output, "\n";284 } elsif (not $server->error) {285 print "No owner set\n";286 } else {287 failure ($server->error, @_);288 }289 }290 } elsif ($command eq 'rename') {291 check_args (3, 3, [], @args);292 $server->rename (@args) or failure ($server->error, @_);293 } elsif ($command eq 'setacl') {294 check_args (4, 4, [], @args);295 $server->acl (@args) or failure ($server->error, @_);296 } elsif ($command eq 'setattr') {297 check_args (4, -1, [], @args);298 $server->attr (@args) or failure ($server->error, @_);299 } elsif ($command eq 'show') {300 check_args (2, 2, [], @args);301 my $output = $server->show (@args);302 if (defined $output) {303 print $output;304 } else {305 failure ($server->error, @_);306 }307 } elsif ($command eq 'store') {308 check_args (2, 3, [3], @args);309 if (@args == 2) {310 local $/;311 $args[2] = <STDIN>;312 }313 splice (@_, 3);314 $server->store (@args) or failure ($server->error, @_);315 } elsif ($command eq 'update') {316 check_args (2, 2, [], @args);317 my $output = $server->update (@args);318 if (defined $output) {319 print $output;320 } else {321 failure ($server->error, @_);322 }323 } else {324 error "unknown command $command";325 }326 success (@_);327 }328 329 # Parse command-line options.330 my ($quiet);331 Getopt::Long::config ('require_order');332 GetOptions ('q|quiet' => \$quiet) or exit 1;333 $SYSLOG = 0 if $quiet;334 335 # Run the command.336 command (@ARGV);337 338 __END__339 340 ##############################################################################341 # Documentation342 ##############################################################################343 344 # The commands section of this document is duplicated from the documentation345 # for wallet and should be kept in sync.346 347 =for stopwords348 wallet-backend backend backend-specific remctld ACL acl timestamp getacl349 setacl metadata keytab keytabs enctypes enctype ktadd KDC Allbery350 autocreate MERCHANTABILITY NONINFRINGEMENT sublicense351 352 =head1 NAME353 354 wallet-backend - Wallet server for storing and retrieving secure data355 356 =head1 SYNOPSIS357 358 B<wallet-backend> [B<-q>] I<command> [I<args> ...]359 360 =head1 DESCRIPTION361 362 B<wallet-backend> implements the interface between B<remctld> and the363 wallet system. It is written to run under B<remctld> and expects the364 authenticated identity of the remote user in the REMOTE_USER environment365 variable. It uses REMOTE_HOST or REMOTE_ADDR if REMOTE_HOST isn't set for366 additional trace information. It accepts the command from B<remctld> on367 the command line, creates a Wallet::Server object, and calls the368 appropriate methods.369 370 This program is a fairly thin wrapper around Wallet::Server that371 translates command strings into method calls and returns the results. It372 does check all arguments except for the <data> argument to the store373 command and rejects any argument not matching C<^[\w_/.-]+\z>; in other374 words, only alphanumerics, underscore (C<_>), slash (C</>), period (C<.>),375 and hyphen (C<->) are permitted in arguments. This provides some376 additional security over and above the checking already done by the rest377 of the wallet code.378 379 =head1 OPTIONS380 381 =over 4382 383 =item B<--quiet>, B<-q>384 385 If this option is given, B<wallet-backend> will not log its actions to386 syslog.387 388 =back389 390 =head1 COMMANDS391 392 Most commands are only available to wallet administrators (users on the393 C<ADMIN> ACL). The exceptions are C<acl check>, C<check>, C<get>,394 C<store>, C<show>, C<destroy>, C<flag clear>, C<flag set>, C<getattr>,395 C<setattr>, and C<history>. C<acl check> and C<check> can be run by396 anyone. All of the rest of those commands have their own ACLs except397 C<getattr> and C<history>, which use the C<show> ACL, C<setattr>, which398 uses the C<store> ACL, and C<comment>, which uses the owner or C<show> ACL399 depending on whether one is setting or retrieving the comment. If the400 appropriate ACL is set, it alone is checked to see if the user has access.401 Otherwise, C<destroy>, C<get>, C<store>, C<show>, C<getattr>, C<setattr>,402 C<history>, and C<comment> access is permitted if the user is authorized403 by the owner ACL of the object.404 405 Administrators can run any command on any object or ACL except for C<get>406 and C<store>. For C<get> and C<store>, they must still be authorized by407 either the appropriate specific ACL or the owner ACL.408 409 If the locked flag is set on an object, no commands can be run on that410 object that change data except the C<flags> commands, nor can the C<get>411 command be used on that object. C<show>, C<history>, C<getacl>,412 C<getattr>, and C<owner>, C<comment>, or C<expires> without an argument413 can still be used on that object.414 415 For more information on attributes, see L<ATTRIBUTES>.416 417 =over 4418 419 =item acl add <id> <scheme> <identifier>420 421 Add an entry with <scheme> and <identifier> to the ACL <id>. <id> may be422 either the name of an ACL or its numeric identifier.423 424 =item acl check <id>425 426 Check whether an ACL with the ID <id> already exists. If it does, prints427 C<yes>; if not, prints C<no>.428 429 =item acl create <name>430 431 Create a new, empty ACL with name <name>. When setting an ACL on an432 object with a set of entries that don't match an existing ACL, first433 create a new ACL with C<acl create>, add the appropriate entries to it434 with C<acl add>, and then set the ACL on an object with the C<owner> or435 C<setacl> commands.436 437 =item acl destroy <id>438 439 Destroy the ACL <id>. This ACL must no longer be referenced by any object440 or the ACL destruction will fail. The special ACL named C<ADMIN> cannot441 be destroyed.442 443 =item acl history <id>444 445 Display the history of the ACL <id>. Each change to the ACL (not446 including changes to the name of the ACL) will be represented by two447 lines. The first line will have a timestamp of the change followed by a448 description of the change, and the second line will give the user who made449 the change and the host from which the change was made.450 451 =item acl remove <id> <scheme> <identifier>452 453 Remove the entry with <scheme> and <identifier> from the ACL <id>. <id>454 may be either the name of an ACL or its numeric identifier. The last455 entry in the special ACL C<ADMIN> cannot be removed to protect against456 accidental lockout, but administrators can remove themselves from the457 C<ADMIN> ACL and can leave only a non-functioning entry on the ACL. Use458 caution when removing entries from the C<ADMIN> ACL.459 460 =item acl rename <id> <name>461 462 Renames the ACL identified by <id> to <name>. This changes the463 human-readable name, not the underlying numeric ID, so the ACL's464 associations with objects will be unchanged. The C<ADMIN> ACL may not be465 renamed. <id> may be either the current name or the numeric ID. <name>466 must not be all-numeric. To rename an ACL, the current user must be467 authorized by the C<ADMIN> ACL.468 469 =item acl replace <id> <new-id>470 471 Find any objects owned by <id>, and then change their ownership to472 <new_id> instead. <new-id> should already exist, and may already have473 some objects owned by it. <id> is not deleted afterwards, though in474 most cases that is probably your next step. The C<ADMIN> ACL may not be475 replaced from. <id> and <new-id> may be either the current name or the476 numeric ID. To replace an ACL, the current user must be authorized by477 the C<ADMIN> ACL.478 479 =item acl show <id>480 481 Display the name, numeric ID, and entries of the ACL <id>.482 483 =item autocreate <type> <name>484 485 Create a new object of type <type> with name <name>. The user must be486 listed in the default ACL for an object with that type and name, and the487 object will be created with that default ACL set as the object owner.488 489 =item check <type> <name>490 491 Check whether an object of type <type> and name <name> already exists. If492 it does, prints C<yes>; if not, prints C<no>.493 494 =item comment <type> <name> [<comment>]495 496 If <comment> is not given, displays the current comment for the object497 identified by <type> and <name>, or C<No comment set> if none is set.498 499 If <comment> is given, sets the comment on the object identified by500 <type> and <name> to <comment>. If <comment> is the empty string, clears501 the comment.502 503 =item create <type> <name>504 505 Create a new object of type <type> with name <name>. With some backends,506 this will trigger creation of an entry in an external system as well.507 The new object will have no ACLs and no owner set, so usually the508 administrator will want to then set an owner with C<owner> so that the509 object will be usable.510 511 =item destroy <type> <name>512 513 Destroy the object identified by <type> and <name>. With some backends,514 this will trigger destruction of an object in an external system as well.515 516 =item expires <type> <name> [<date> [<time>]]517 518 If <date> is not given, displays the current expiration of the object519 identified by <type> and <name>, or C<No expiration set> if none is set.520 The expiration will be displayed in seconds since epoch.521 522 If <date> is given, sets the expiration on the object identified by <type>523 and <name> to <date> and (if given) <time>. <date> and <time> must be in524 some format that can be parsed by the Perl Date::Parse module. Most525 common formats are supported; if in doubt, use C<YYYY-MM-DD HH:MM:SS>. If526 <date> is the empty string, clears the expiration of the object.527 528 Currently, the expiration of an object is not used.529 530 =item flag clear <type> <name> <flag>531 532 Clears the flag <flag> on the object identified by <type> and <name>.533 534 =item flag set <type> <name> <flag>535 536 Sets the flag <flag> on the object identified by <type> and <name>.537 Recognized flags are C<locked>, which prevents all further actions on that538 object until the flag is cleared, and C<unchanging>, which tells the539 object backend to not generate new data on get but instead return the same540 data as previously returned. The C<unchanging> flag is not meaningful for541 objects that do not generate new data on the fly.542 543 =item get <type> <name>544 545 Prints to standard output the data associated with the object identified546 by <type> and <name>. This may trigger generation of new data and547 invalidate old data for that object depending on the object type.548 549 =item getacl <type> <name> <acl>550 551 Prints the ACL <acl>, which must be one of C<get>, C<store>, C<show>,552 C<destroy>, or C<flags>, for the object identified by <type> and <name>.553 Prints C<No ACL set> if that ACL isn't set on that object. Remember that554 if the C<get>, C<store>, or C<show> ACLs aren't set, authorization falls555 back to checking the owner ACL. See the C<owner> command for displaying556 or setting it.557 558 =item getattr <type> <name> <attr>559 560 Prints the object attribute <attr> for the object identified by <type> and561 <name>. Attributes are used to store backend-specific information for a562 particular object type, and <attr> must be an attribute type known to the563 underlying object implementation. The attribute values, if any, are564 printed one per line. If the attribute is not set on this object, nothing565 is printed.566 567 =item history <type> <name>568 569 Displays the history for the object identified by <type> and <name>. This570 human-readable output will have two lines for each action that changes the571 object, plus for any get action. The first line has the timestamp of the572 action and the action, and the second line gives the user who performed573 the action and the host from which they performed it.574 575 =item owner <type> <name> [<owner>]576 577 If <owner> is not given, displays the current owner ACL of the object578 identified by <type> and <name>, or C<No owner set> if none is set. The579 result will be the name of an ACL.580 581 If <owner> is given, sets the owner of the object identified by <type> and582 <name> to <owner>. If <owner> is the empty string, clears the owner of583 the object.584 585 =item rename <type> <name> <new-name>586 587 Renames an existing object. This currently only supports file objects,588 where it renames the object itself, then the name and location of the589 object in the file store.590 591 =item setacl <type> <name> <acl> <id>592 593 Sets the ACL <acl>, which must be one of C<get>, C<store>, C<show>,594 C<destroy>, or C<flags>, to <id> on the object identified by <type> and595 <name>. If <id> is the empty string, clears that ACL on the object.596 597 =item setattr <type> <name> <attr> <value> [<value> ...]598 599 Sets the object attribute <attr> for the object identified by <type> and600 <name>. Attributes are used to store backend-specific information for a601 particular object type, and <attr> must be an attribute type known to the602 underlying object implementation. To clear the attribute for this object,603 pass in a <value> of the empty string (C<''>).604 605 =item show <type> <name>606 607 Displays the current object metadata for the object identified by <type>608 and <name>. This human-readable output will show the object type and609 name, the owner, any specific ACLs set on the object, the expiration if610 any, and the user, remote host, and time when the object was created, last611 stored, and last downloaded.612 613 =item store <type> <name> [<data>]614 615 Stores <data> for the object identified by <type> and <name> for later616 retrieval with C<get>. Not all object types support this. If <data> is617 not given as an argument, it will be read from standard input.618 619 =item update <type> <name>620 621 Prints to standard output the data associated with the object identified622 by <type> and <name>. If the object is one that can have changing623 information, such as a keytab or password, then we generate new data for624 that object regardless of whether there is current data or the unchanging625 flag is set.626 627 =back628 629 =head1 ATTRIBUTES630 631 Object attributes store additional properties and configuration632 information for objects stored in the wallet. They are displayed as part633 of the object data with C<show>, retrieved with C<getattr>, and set with634 C<setattr>.635 636 =head2 Keytab Attributes637 638 Keytab objects support the following attributes:639 640 =over 4641 642 =item enctypes643 644 Restricts the generated keytab to a specific set of encryption types. The645 values of this attribute must be enctype strings recognized by Kerberos646 (strings like C<aes256-cts-hmac-sha1-96> or C<des-cbc-crc>). Note that647 the salt should not be included; since the salt is irrelevant for keytab648 keys, it will always be set to C<normal> by the wallet.649 650 If this attribute is set, the specified enctype list will be passed to651 ktadd when get() is called for that keytab. If it is not set, the default652 set in the KDC will be used.653 654 This attribute is ignored if the C<unchanging> flag is set on a keytab.655 Keytabs retrieved with C<unchanging> set will contain all keys present in656 the KDC for that Kerberos principal and therefore may contain different657 enctypes than those requested by this attribute.658 659 =back660 661 =head1 AUTHOR662 663 Russ Allbery <eagle@eyrie.org>664 665 =head1 COPYRIGHT AND LICENSE666 667 Copyright 2007, 2008, 2010, 2011, 2012, 2013 The Board of Trustees of the668 Leland Stanford Junior University669 670 Permission is hereby granted, free of charge, to any person obtaining a671 copy of this software and associated documentation files (the "Software"),672 to deal in the Software without restriction, including without limitation673 the rights to use, copy, modify, merge, publish, distribute, sublicense,674 and/or sell copies of the Software, and to permit persons to whom the675 Software is furnished to do so, subject to the following conditions:676 677 The above copyright notice and this permission notice shall be included in678 all copies or substantial portions of the Software.679 680 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR681 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,682 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL683 THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER684 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING685 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER686 DEALINGS IN THE SOFTWARE.687 688 =head1 SEE ALSO689 690 Wallet::Server(3), remctld(8)691 692 This program is part of the wallet system. The current version is693 available from L<http://www.eyrie.org/~eagle/software/wallet/>.694 695 =cut -
new file server/wallet-backend.in
- + 1 #!@PERL@ 2 # 3 # Wallet server for storing and retrieving secure data. 4 5 use 5.008; 6 use strict; 7 use warnings; 8 9 use Getopt::Long qw(GetOptions); 10 use Sys::Syslog qw(openlog syslog); 11 use Wallet::Server; 12 13 # Set to zero to suppress syslog logging, which is used for testing and for 14 # the -q option. Set to a reference to a string to append messages to that 15 # string instead. 16 our $SYSLOG; 17 $SYSLOG = 1 unless defined $SYSLOG; 18 19 ############################################################################## 20 # Logging 21 ############################################################################## 22 23 # Initialize logging. 24 sub log_init { 25 if (ref $SYSLOG) { 26 $$SYSLOG = ''; 27 } elsif ($SYSLOG) { 28 openlog ('wallet-backend', 'pid', 'auth'); 29 } 30 } 31 32 # Get an identity string for the user suitable for including in log messages. 33 sub identity { 34 my $identity = ''; 35 if ($ENV{REMOTE_USER}) { 36 $identity = $ENV{REMOTE_USER}; 37 my $host = $ENV{REMOTE_HOST} || $ENV{REMOTE_ADDR}; 38 $identity .= " ($host)" if $host; 39 } 40 return $identity; 41 } 42 43 # Log an error message to both syslog and to stderr and exit with a non-zero 44 # status. 45 sub error { 46 my $message = join ('', @_); 47 if ($SYSLOG) { 48 my $identity = identity; 49 my $log; 50 if ($identity) { 51 $log = "error for $identity: $message"; 52 } else { 53 $log = "error: $message"; 54 } 55 $log =~ s/[^\x20-\x7e]/_/g; 56 if (ref $SYSLOG) { 57 $$SYSLOG .= "$log\n"; 58 } else { 59 syslog ('err', "%s", $log); 60 } 61 } 62 die "$message\n"; 63 } 64 65 # Log a wallet failure message for a given command to both syslog and to 66 # stderr and exit with a non-zero status. Takes the message and the command 67 # that was being run. 68 sub failure { 69 my ($message, @command) = @_; 70 if ($SYSLOG) { 71 my $log = "command @command from " . identity . " failed: $message"; 72 $log =~ s/[^\x20-\x7e]/_/g; 73 if (ref $SYSLOG) { 74 $$SYSLOG .= "$log\n"; 75 } else { 76 syslog ('err', "%s", $log); 77 } 78 } 79 die "$message\n"; 80 } 81 82 # Log a wallet success message for a given command. 83 sub success { 84 my (@command) = @_; 85 if ($SYSLOG) { 86 my $log = "command @command from " . identity . " succeeded"; 87 $log =~ s/[^\x20-\x7e]/_/g; 88 if (ref $SYSLOG) { 89 $$SYSLOG .= "$log\n"; 90 } else { 91 syslog ('info', "%s", $log); 92 } 93 } 94 } 95 96 ############################################################################## 97 # Parameter checking 98 ############################################################################## 99 100 # Check all arguments against a very restricted set of allowed characters and 101 # to ensure the right number of arguments are taken. The arguments are the 102 # number of arguments expected (minimum and maximum), a reference to an array 103 # of which argument numbers shouldn't be checked, and then the arguments. 104 # 105 # This function is probably temporary and will be replaced with something that 106 # knows more about the syntax of each command and can check more things. 107 sub check_args { 108 my ($min, $max, $exclude, @args) = @_; 109 if (@args < $min) { 110 error "insufficient arguments"; 111 } elsif (@args > $max and $max != -1) { 112 error "too many arguments"; 113 } 114 my %exclude = map { $_ => 1 } @$exclude; 115 for (my $i = 1; $i <= @args; $i++) { 116 next if $exclude{$i}; 117 unless ($args[$i - 1] =~ m,^[\w_/\@.-]*\z,) { 118 error "invalid characters in argument: $args[$i - 1]"; 119 } 120 } 121 } 122 123 ############################################################################## 124 # Implementation 125 ############################################################################## 126 127 # Parse and execute a command. We wrap this in a subroutine call for easier 128 # testing. 129 sub command { 130 log_init; 131 my $user = $ENV{REMOTE_USER} or error "REMOTE_USER not set"; 132 my $host = $ENV{REMOTE_HOST} || $ENV{REMOTE_ADDR} 133 or error "neither REMOTE_HOST nor REMOTE_ADDR set"; 134 135 # Instantiate the server object. 136 my $server = Wallet::Server->new ($user, $host); 137 138 # Parse command-line options and dispatch to the appropriate calls. 139 my ($command, @args) = @_; 140 if ($command eq 'acl') { 141 my $action = shift @args; 142 if ($action eq 'add') { 143 check_args (3, 3, [3], @args); 144 $server->acl_add (@args) or failure ($server->error, @_); 145 } elsif ($action eq 'check') { 146 check_args (1, 1, [], @args); 147 my $status = $server->acl_check (@args); 148 if (!defined ($status)) { 149 failure ($server->error, @_); 150 } else { 151 print $status ? "yes\n" : "no\n"; 152 } 153 } elsif ($action eq 'create') { 154 check_args (1, 1, [], @args); 155 $server->acl_create (@args) or failure ($server->error, @_); 156 } elsif ($action eq 'destroy') { 157 check_args (1, 1, [], @args); 158 $server->acl_destroy (@args) or failure ($server->error, @_); 159 } elsif ($action eq 'history') { 160 check_args (1, 1, [], @args); 161 my $output = $server->acl_history (@args); 162 if (defined $output) { 163 print $output; 164 } else { 165 failure ($server->error, @_); 166 } 167 } elsif ($action eq 'remove') { 168 check_args (3, 3, [3], @args); 169 $server->acl_remove (@args) or failure ($server->error, @_); 170 } elsif ($action eq 'rename') { 171 check_args (2, 2, [], @args); 172 $server->acl_rename (@args) or failure ($server->error, @_); 173 } elsif ($action eq 'replace') { 174 check_args (2, 2, [], @args); 175 $server->acl_replace (@args) or failure ($server->error, @_); 176 } elsif ($action eq 'show') { 177 check_args (1, 1, [], @args); 178 my $output = $server->acl_show (@args); 179 if (defined $output) { 180 print $output; 181 } else { 182 failure ($server->error, @_); 183 } 184 } else { 185 error "unknown command acl $action"; 186 } 187 } elsif ($command eq 'autocreate') { 188 check_args (2, 2, [], @args); 189 $server->autocreate (@args) or failure ($server->error, @_); 190 } elsif ($command eq 'check') { 191 check_args (2, 2, [], @args); 192 my $status = $server->check (@args); 193 if (!defined ($status)) { 194 failure ($server->error, @_); 195 } else { 196 print $status ? "yes\n" : "no\n"; 197 } 198 } elsif ($command eq 'comment') { 199 check_args (2, 3, [3], @args); 200 if (@args > 2) { 201 $server->comment (@args) or failure ($server->error, @_); 202 } else { 203 my $output = $server->comment (@args); 204 if (defined $output) { 205 print $output, "\n"; 206 } elsif (not $server->error) { 207 print "No comment set\n"; 208 } else { 209 failure ($server->error, @_); 210 } 211 } 212 } elsif ($command eq 'create') { 213 check_args (2, 2, [], @args); 214 $server->create (@args) or failure ($server->error, @_); 215 } elsif ($command eq 'destroy') { 216 check_args (2, 2, [], @args); 217 $server->destroy (@args) or failure ($server->error, @_); 218 } elsif ($command eq 'expires') { 219 check_args (2, 3, [], @args); 220 if (@args > 2) { 221 $server->expires (@args) or failure ($server->error, @_); 222 } else { 223 my $output = $server->expires (@args); 224 if (defined $output) { 225 print $output, "\n"; 226 } elsif (not $server->error) { 227 print "No expiration set\n"; 228 } else { 229 failure ($server->error, @_); 230 } 231 } 232 } elsif ($command eq 'flag') { 233 my $action = shift @args; 234 check_args (3, 3, [], @args); 235 if ($action eq 'clear') { 236 $server->flag_clear (@args) or failure ($server->error, @_); 237 } elsif ($action eq 'set') { 238 $server->flag_set (@args) or failure ($server->error, @_); 239 } else { 240 error "unknown command flag $action"; 241 } 242 } elsif ($command eq 'get') { 243 check_args (2, 2, [], @args); 244 my $output = $server->get (@args); 245 if (defined $output) { 246 print $output; 247 } else { 248 failure ($server->error, @_); 249 } 250 } elsif ($command eq 'getacl') { 251 check_args (3, 3, [], @args); 252 my $output = $server->acl (@args); 253 if (defined $output) { 254 print $output, "\n"; 255 } elsif (not $server->error) { 256 print "No ACL set\n"; 257 } else { 258 failure ($server->error, @_); 259 } 260 } elsif ($command eq 'getattr') { 261 check_args (3, 3, [], @args); 262 my @result = $server->attr (@args); 263 if (not @result and $server->error) { 264 failure ($server->error, @_); 265 } elsif (@result) { 266 print join ("\n", @result, ''); 267 } 268 } elsif ($command eq 'history') { 269 check_args (2, 2, [], @args); 270 my $output = $server->history (@args); 271 if (defined $output) { 272 print $output; 273 } else { 274 failure ($server->error, @_); 275 } 276 } elsif ($command eq 'owner') { 277 check_args (2, 3, [], @args); 278 if (@args > 2) { 279 $server->owner (@args) or failure ($server->error, @_); 280 } else { 281 my $output = $server->owner (@args); 282 if (defined $output) { 283 print $output, "\n"; 284 } elsif (not $server->error) { 285 print "No owner set\n"; 286 } else { 287 failure ($server->error, @_); 288 } 289 } 290 } elsif ($command eq 'rename') { 291 check_args (3, 3, [], @args); 292 $server->rename (@args) or failure ($server->error, @_); 293 } elsif ($command eq 'setacl') { 294 check_args (4, 4, [], @args); 295 $server->acl (@args) or failure ($server->error, @_); 296 } elsif ($command eq 'setattr') { 297 check_args (4, -1, [], @args); 298 $server->attr (@args) or failure ($server->error, @_); 299 } elsif ($command eq 'show') { 300 check_args (2, 2, [], @args); 301 my $output = $server->show (@args); 302 if (defined $output) { 303 print $output; 304 } else { 305 failure ($server->error, @_); 306 } 307 } elsif ($command eq 'store') { 308 check_args (2, 3, [3], @args); 309 if (@args == 2) { 310 local $/; 311 $args[2] = <STDIN>; 312 } 313 splice (@_, 3); 314 $server->store (@args) or failure ($server->error, @_); 315 } elsif ($command eq 'update') { 316 check_args (2, 2, [], @args); 317 my $output = $server->update (@args); 318 if (defined $output) { 319 print $output; 320 } else { 321 failure ($server->error, @_); 322 } 323 } else { 324 error "unknown command $command"; 325 } 326 success (@_); 327 } 328 329 # Parse command-line options. 330 my ($quiet); 331 Getopt::Long::config ('require_order'); 332 GetOptions ('q|quiet' => \$quiet) or exit 1; 333 $SYSLOG = 0 if $quiet; 334 335 # Run the command. 336 command (@ARGV); 337 338 __END__ 339 340 ############################################################################## 341 # Documentation 342 ############################################################################## 343 344 # The commands section of this document is duplicated from the documentation 345 # for wallet and should be kept in sync. 346 347 =for stopwords 348 wallet-backend backend backend-specific remctld ACL acl timestamp getacl 349 setacl metadata keytab keytabs enctypes enctype ktadd KDC Allbery 350 autocreate MERCHANTABILITY NONINFRINGEMENT sublicense 351 352 =head1 NAME 353 354 wallet-backend - Wallet server for storing and retrieving secure data 355 356 =head1 SYNOPSIS 357 358 B<wallet-backend> [B<-q>] I<command> [I<args> ...] 359 360 =head1 DESCRIPTION 361 362 B<wallet-backend> implements the interface between B<remctld> and the 363 wallet system. It is written to run under B<remctld> and expects the 364 authenticated identity of the remote user in the REMOTE_USER environment 365 variable. It uses REMOTE_HOST or REMOTE_ADDR if REMOTE_HOST isn't set for 366 additional trace information. It accepts the command from B<remctld> on 367 the command line, creates a Wallet::Server object, and calls the 368 appropriate methods. 369 370 This program is a fairly thin wrapper around Wallet::Server that 371 translates command strings into method calls and returns the results. It 372 does check all arguments except for the <data> argument to the store 373 command and rejects any argument not matching C<^[\w_/.-]+\z>; in other 374 words, only alphanumerics, underscore (C<_>), slash (C</>), period (C<.>), 375 and hyphen (C<->) are permitted in arguments. This provides some 376 additional security over and above the checking already done by the rest 377 of the wallet code. 378 379 =head1 OPTIONS 380 381 =over 4 382 383 =item B<--quiet>, B<-q> 384 385 If this option is given, B<wallet-backend> will not log its actions to 386 syslog. 387 388 =back 389 390 =head1 COMMANDS 391 392 Most commands are only available to wallet administrators (users on the 393 C<ADMIN> ACL). The exceptions are C<acl check>, C<check>, C<get>, 394 C<store>, C<show>, C<destroy>, C<flag clear>, C<flag set>, C<getattr>, 395 C<setattr>, and C<history>. C<acl check> and C<check> can be run by 396 anyone. All of the rest of those commands have their own ACLs except 397 C<getattr> and C<history>, which use the C<show> ACL, C<setattr>, which 398 uses the C<store> ACL, and C<comment>, which uses the owner or C<show> ACL 399 depending on whether one is setting or retrieving the comment. If the 400 appropriate ACL is set, it alone is checked to see if the user has access. 401 Otherwise, C<destroy>, C<get>, C<store>, C<show>, C<getattr>, C<setattr>, 402 C<history>, and C<comment> access is permitted if the user is authorized 403 by the owner ACL of the object. 404 405 Administrators can run any command on any object or ACL except for C<get> 406 and C<store>. For C<get> and C<store>, they must still be authorized by 407 either the appropriate specific ACL or the owner ACL. 408 409 If the locked flag is set on an object, no commands can be run on that 410 object that change data except the C<flags> commands, nor can the C<get> 411 command be used on that object. C<show>, C<history>, C<getacl>, 412 C<getattr>, and C<owner>, C<comment>, or C<expires> without an argument 413 can still be used on that object. 414 415 For more information on attributes, see L<ATTRIBUTES>. 416 417 =over 4 418 419 =item acl add <id> <scheme> <identifier> 420 421 Add an entry with <scheme> and <identifier> to the ACL <id>. <id> may be 422 either the name of an ACL or its numeric identifier. 423 424 =item acl check <id> 425 426 Check whether an ACL with the ID <id> already exists. If it does, prints 427 C<yes>; if not, prints C<no>. 428 429 =item acl create <name> 430 431 Create a new, empty ACL with name <name>. When setting an ACL on an 432 object with a set of entries that don't match an existing ACL, first 433 create a new ACL with C<acl create>, add the appropriate entries to it 434 with C<acl add>, and then set the ACL on an object with the C<owner> or 435 C<setacl> commands. 436 437 =item acl destroy <id> 438 439 Destroy the ACL <id>. This ACL must no longer be referenced by any object 440 or the ACL destruction will fail. The special ACL named C<ADMIN> cannot 441 be destroyed. 442 443 =item acl history <id> 444 445 Display the history of the ACL <id>. Each change to the ACL (not 446 including changes to the name of the ACL) will be represented by two 447 lines. The first line will have a timestamp of the change followed by a 448 description of the change, and the second line will give the user who made 449 the change and the host from which the change was made. 450 451 =item acl remove <id> <scheme> <identifier> 452 453 Remove the entry with <scheme> and <identifier> from the ACL <id>. <id> 454 may be either the name of an ACL or its numeric identifier. The last 455 entry in the special ACL C<ADMIN> cannot be removed to protect against 456 accidental lockout, but administrators can remove themselves from the 457 C<ADMIN> ACL and can leave only a non-functioning entry on the ACL. Use 458 caution when removing entries from the C<ADMIN> ACL. 459 460 =item acl rename <id> <name> 461 462 Renames the ACL identified by <id> to <name>. This changes the 463 human-readable name, not the underlying numeric ID, so the ACL's 464 associations with objects will be unchanged. The C<ADMIN> ACL may not be 465 renamed. <id> may be either the current name or the numeric ID. <name> 466 must not be all-numeric. To rename an ACL, the current user must be 467 authorized by the C<ADMIN> ACL. 468 469 =item acl replace <id> <new-id> 470 471 Find any objects owned by <id>, and then change their ownership to 472 <new_id> instead. <new-id> should already exist, and may already have 473 some objects owned by it. <id> is not deleted afterwards, though in 474 most cases that is probably your next step. The C<ADMIN> ACL may not be 475 replaced from. <id> and <new-id> may be either the current name or the 476 numeric ID. To replace an ACL, the current user must be authorized by 477 the C<ADMIN> ACL. 478 479 =item acl show <id> 480 481 Display the name, numeric ID, and entries of the ACL <id>. 482 483 =item autocreate <type> <name> 484 485 Create a new object of type <type> with name <name>. The user must be 486 listed in the default ACL for an object with that type and name, and the 487 object will be created with that default ACL set as the object owner. 488 489 =item check <type> <name> 490 491 Check whether an object of type <type> and name <name> already exists. If 492 it does, prints C<yes>; if not, prints C<no>. 493 494 =item comment <type> <name> [<comment>] 495 496 If <comment> is not given, displays the current comment for the object 497 identified by <type> and <name>, or C<No comment set> if none is set. 498 499 If <comment> is given, sets the comment on the object identified by 500 <type> and <name> to <comment>. If <comment> is the empty string, clears 501 the comment. 502 503 =item create <type> <name> 504 505 Create a new object of type <type> with name <name>. With some backends, 506 this will trigger creation of an entry in an external system as well. 507 The new object will have no ACLs and no owner set, so usually the 508 administrator will want to then set an owner with C<owner> so that the 509 object will be usable. 510 511 =item destroy <type> <name> 512 513 Destroy the object identified by <type> and <name>. With some backends, 514 this will trigger destruction of an object in an external system as well. 515 516 =item expires <type> <name> [<date> [<time>]] 517 518 If <date> is not given, displays the current expiration of the object 519 identified by <type> and <name>, or C<No expiration set> if none is set. 520 The expiration will be displayed in seconds since epoch. 521 522 If <date> is given, sets the expiration on the object identified by <type> 523 and <name> to <date> and (if given) <time>. <date> and <time> must be in 524 some format that can be parsed by the Perl Date::Parse module. Most 525 common formats are supported; if in doubt, use C<YYYY-MM-DD HH:MM:SS>. If 526 <date> is the empty string, clears the expiration of the object. 527 528 Currently, the expiration of an object is not used. 529 530 =item flag clear <type> <name> <flag> 531 532 Clears the flag <flag> on the object identified by <type> and <name>. 533 534 =item flag set <type> <name> <flag> 535 536 Sets the flag <flag> on the object identified by <type> and <name>. 537 Recognized flags are C<locked>, which prevents all further actions on that 538 object until the flag is cleared, and C<unchanging>, which tells the 539 object backend to not generate new data on get but instead return the same 540 data as previously returned. The C<unchanging> flag is not meaningful for 541 objects that do not generate new data on the fly. 542 543 =item get <type> <name> 544 545 Prints to standard output the data associated with the object identified 546 by <type> and <name>. This may trigger generation of new data and 547 invalidate old data for that object depending on the object type. 548 549 =item getacl <type> <name> <acl> 550 551 Prints the ACL <acl>, which must be one of C<get>, C<store>, C<show>, 552 C<destroy>, or C<flags>, for the object identified by <type> and <name>. 553 Prints C<No ACL set> if that ACL isn't set on that object. Remember that 554 if the C<get>, C<store>, or C<show> ACLs aren't set, authorization falls 555 back to checking the owner ACL. See the C<owner> command for displaying 556 or setting it. 557 558 =item getattr <type> <name> <attr> 559 560 Prints the object attribute <attr> for the object identified by <type> and 561 <name>. Attributes are used to store backend-specific information for a 562 particular object type, and <attr> must be an attribute type known to the 563 underlying object implementation. The attribute values, if any, are 564 printed one per line. If the attribute is not set on this object, nothing 565 is printed. 566 567 =item history <type> <name> 568 569 Displays the history for the object identified by <type> and <name>. This 570 human-readable output will have two lines for each action that changes the 571 object, plus for any get action. The first line has the timestamp of the 572 action and the action, and the second line gives the user who performed 573 the action and the host from which they performed it. 574 575 =item owner <type> <name> [<owner>] 576 577 If <owner> is not given, displays the current owner ACL of the object 578 identified by <type> and <name>, or C<No owner set> if none is set. The 579 result will be the name of an ACL. 580 581 If <owner> is given, sets the owner of the object identified by <type> and 582 <name> to <owner>. If <owner> is the empty string, clears the owner of 583 the object. 584 585 =item rename <type> <name> <new-name> 586 587 Renames an existing object. This currently only supports file objects, 588 where it renames the object itself, then the name and location of the 589 object in the file store. 590 591 =item setacl <type> <name> <acl> <id> 592 593 Sets the ACL <acl>, which must be one of C<get>, C<store>, C<show>, 594 C<destroy>, or C<flags>, to <id> on the object identified by <type> and 595 <name>. If <id> is the empty string, clears that ACL on the object. 596 597 =item setattr <type> <name> <attr> <value> [<value> ...] 598 599 Sets the object attribute <attr> for the object identified by <type> and 600 <name>. Attributes are used to store backend-specific information for a 601 particular object type, and <attr> must be an attribute type known to the 602 underlying object implementation. To clear the attribute for this object, 603 pass in a <value> of the empty string (C<''>). 604 605 =item show <type> <name> 606 607 Displays the current object metadata for the object identified by <type> 608 and <name>. This human-readable output will show the object type and 609 name, the owner, any specific ACLs set on the object, the expiration if 610 any, and the user, remote host, and time when the object was created, last 611 stored, and last downloaded. 612 613 =item store <type> <name> [<data>] 614 615 Stores <data> for the object identified by <type> and <name> for later 616 retrieval with C<get>. Not all object types support this. If <data> is 617 not given as an argument, it will be read from standard input. 618 619 =item update <type> <name> 620 621 Prints to standard output the data associated with the object identified 622 by <type> and <name>. If the object is one that can have changing 623 information, such as a keytab or password, then we generate new data for 624 that object regardless of whether there is current data or the unchanging 625 flag is set. 626 627 =back 628 629 =head1 ATTRIBUTES 630 631 Object attributes store additional properties and configuration 632 information for objects stored in the wallet. They are displayed as part 633 of the object data with C<show>, retrieved with C<getattr>, and set with 634 C<setattr>. 635 636 =head2 Keytab Attributes 637 638 Keytab objects support the following attributes: 639 640 =over 4 641 642 =item enctypes 643 644 Restricts the generated keytab to a specific set of encryption types. The 645 values of this attribute must be enctype strings recognized by Kerberos 646 (strings like C<aes256-cts-hmac-sha1-96> or C<des-cbc-crc>). Note that 647 the salt should not be included; since the salt is irrelevant for keytab 648 keys, it will always be set to C<normal> by the wallet. 649 650 If this attribute is set, the specified enctype list will be passed to 651 ktadd when get() is called for that keytab. If it is not set, the default 652 set in the KDC will be used. 653 654 This attribute is ignored if the C<unchanging> flag is set on a keytab. 655 Keytabs retrieved with C<unchanging> set will contain all keys present in 656 the KDC for that Kerberos principal and therefore may contain different 657 enctypes than those requested by this attribute. 658 659 =back 660 661 =head1 AUTHOR 662 663 Russ Allbery <eagle@eyrie.org> 664 665 =head1 COPYRIGHT AND LICENSE 666 667 Copyright 2007, 2008, 2010, 2011, 2012, 2013 The Board of Trustees of the 668 Leland Stanford Junior University 669 670 Permission is hereby granted, free of charge, to any person obtaining a 671 copy of this software and associated documentation files (the "Software"), 672 to deal in the Software without restriction, including without limitation 673 the rights to use, copy, modify, merge, publish, distribute, sublicense, 674 and/or sell copies of the Software, and to permit persons to whom the 675 Software is furnished to do so, subject to the following conditions: 676 677 The above copyright notice and this permission notice shall be included in 678 all copies or substantial portions of the Software. 679 680 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 681 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 682 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 683 THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 684 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 685 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 686 DEALINGS IN THE SOFTWARE. 687 688 =head1 SEE ALSO 689 690 Wallet::Server(3), remctld(8) 691 692 This program is part of the wallet system. The current version is 693 available from L<http://www.eyrie.org/~eagle/software/wallet/>. 694 695 =cut