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)

Submit with the substitution being used upstream

  • deleted file server/wallet-backend

    + -  
    1 #!/usr/bin/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
  • new file server/wallet-backend.in

    - +  
     1#!@PERL@
     2#
     3# Wallet server for storing and retrieving secure data.
     4
     5use 5.008;
     6use strict;
     7use warnings;
     8
     9use Getopt::Long qw(GetOptions);
     10use Sys::Syslog qw(openlog syslog);
     11use 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.
     16our $SYSLOG;
     17$SYSLOG = 1 unless defined $SYSLOG;
     18
     19##############################################################################
     20# Logging
     21##############################################################################
     22
     23# Initialize logging.
     24sub 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.
     33sub 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.
     45sub 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.
     68sub 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.
     83sub 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.
     107sub 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.
     129sub 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.
     330my ($quiet);
     331Getopt::Long::config ('require_order');
     332GetOptions ('q|quiet' => \$quiet) or exit 1;
     333$SYSLOG = 0 if $quiet;
     334
     335# Run the command.
     336command (@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
     348wallet-backend backend backend-specific remctld ACL acl timestamp getacl
     349setacl metadata keytab keytabs enctypes enctype ktadd KDC Allbery
     350autocreate MERCHANTABILITY NONINFRINGEMENT sublicense
     351
     352=head1 NAME
     353
     354wallet-backend - Wallet server for storing and retrieving secure data
     355
     356=head1 SYNOPSIS
     357
     358B<wallet-backend> [B<-q>] I<command> [I<args> ...]
     359
     360=head1 DESCRIPTION
     361
     362B<wallet-backend> implements the interface between B<remctld> and the
     363wallet system.  It is written to run under B<remctld> and expects the
     364authenticated identity of the remote user in the REMOTE_USER environment
     365variable.  It uses REMOTE_HOST or REMOTE_ADDR if REMOTE_HOST isn't set for
     366additional trace information.  It accepts the command from B<remctld> on
     367the command line, creates a Wallet::Server object, and calls the
     368appropriate methods.
     369
     370This program is a fairly thin wrapper around Wallet::Server that
     371translates command strings into method calls and returns the results.  It
     372does check all arguments except for the <data> argument to the store
     373command and rejects any argument not matching C<^[\w_/.-]+\z>; in other
     374words, only alphanumerics, underscore (C<_>), slash (C</>), period (C<.>),
     375and hyphen (C<->) are permitted in arguments.  This provides some
     376additional security over and above the checking already done by the rest
     377of the wallet code.
     378
     379=head1 OPTIONS
     380
     381=over 4
     382
     383=item B<--quiet>, B<-q>
     384
     385If this option is given, B<wallet-backend> will not log its actions to
     386syslog.
     387
     388=back
     389
     390=head1 COMMANDS
     391
     392Most commands are only available to wallet administrators (users on the
     393C<ADMIN> ACL).  The exceptions are C<acl check>, C<check>, C<get>,
     394C<store>, C<show>, C<destroy>, C<flag clear>, C<flag set>, C<getattr>,
     395C<setattr>, and C<history>.  C<acl check> and C<check> can be run by
     396anyone.  All of the rest of those commands have their own ACLs except
     397C<getattr> and C<history>, which use the C<show> ACL, C<setattr>, which
     398uses the C<store> ACL, and C<comment>, which uses the owner or C<show> ACL
     399depending on whether one is setting or retrieving the comment.  If the
     400appropriate ACL is set, it alone is checked to see if the user has access.
     401Otherwise, C<destroy>, C<get>, C<store>, C<show>, C<getattr>, C<setattr>,
     402C<history>, and C<comment> access is permitted if the user is authorized
     403by the owner ACL of the object.
     404
     405Administrators can run any command on any object or ACL except for C<get>
     406and C<store>.  For C<get> and C<store>, they must still be authorized by
     407either the appropriate specific ACL or the owner ACL.
     408
     409If the locked flag is set on an object, no commands can be run on that
     410object that change data except the C<flags> commands, nor can the C<get>
     411command be used on that object.  C<show>, C<history>, C<getacl>,
     412C<getattr>, and C<owner>, C<comment>, or C<expires> without an argument
     413can still be used on that object.
     414
     415For more information on attributes, see L<ATTRIBUTES>.
     416
     417=over 4
     418
     419=item acl add <id> <scheme> <identifier>
     420
     421Add an entry with <scheme> and <identifier> to the ACL <id>.  <id> may be
     422either the name of an ACL or its numeric identifier.
     423
     424=item acl check <id>
     425
     426Check whether an ACL with the ID <id> already exists.  If it does, prints
     427C<yes>; if not, prints C<no>.
     428
     429=item acl create <name>
     430
     431Create a new, empty ACL with name <name>.  When setting an ACL on an
     432object with a set of entries that don't match an existing ACL, first
     433create a new ACL with C<acl create>, add the appropriate entries to it
     434with C<acl add>, and then set the ACL on an object with the C<owner> or
     435C<setacl> commands.
     436
     437=item acl destroy <id>
     438
     439Destroy the ACL <id>.  This ACL must no longer be referenced by any object
     440or the ACL destruction will fail.  The special ACL named C<ADMIN> cannot
     441be destroyed.
     442
     443=item acl history <id>
     444
     445Display the history of the ACL <id>.  Each change to the ACL (not
     446including changes to the name of the ACL) will be represented by two
     447lines.  The first line will have a timestamp of the change followed by a
     448description of the change, and the second line will give the user who made
     449the change and the host from which the change was made.
     450
     451=item acl remove <id> <scheme> <identifier>
     452
     453Remove the entry with <scheme> and <identifier> from the ACL <id>.  <id>
     454may be either the name of an ACL or its numeric identifier.  The last
     455entry in the special ACL C<ADMIN> cannot be removed to protect against
     456accidental lockout, but administrators can remove themselves from the
     457C<ADMIN> ACL and can leave only a non-functioning entry on the ACL.  Use
     458caution when removing entries from the C<ADMIN> ACL.
     459
     460=item acl rename <id> <name>
     461
     462Renames the ACL identified by <id> to <name>.  This changes the
     463human-readable name, not the underlying numeric ID, so the ACL's
     464associations with objects will be unchanged.  The C<ADMIN> ACL may not be
     465renamed.  <id> may be either the current name or the numeric ID.  <name>
     466must not be all-numeric.  To rename an ACL, the current user must be
     467authorized by the C<ADMIN> ACL.
     468
     469=item acl replace <id> <new-id>
     470
     471Find any objects owned by <id>, and then change their ownership to
     472<new_id> instead.  <new-id> should already exist, and may already have
     473some objects owned by it.  <id> is not deleted afterwards, though in
     474most cases that is probably your next step.  The C<ADMIN> ACL may not be
     475replaced from.  <id> and <new-id> may be either the current name or the
     476numeric ID.  To replace an ACL, the current user must be authorized by
     477the C<ADMIN> ACL.
     478
     479=item acl show <id>
     480
     481Display the name, numeric ID, and entries of the ACL <id>.
     482
     483=item autocreate <type> <name>
     484
     485Create a new object of type <type> with name <name>.  The user must be
     486listed in the default ACL for an object with that type and name, and the
     487object will be created with that default ACL set as the object owner.
     488
     489=item check <type> <name>
     490
     491Check whether an object of type <type> and name <name> already exists.  If
     492it does, prints C<yes>; if not, prints C<no>.
     493
     494=item comment <type> <name> [<comment>]
     495
     496If <comment> is not given, displays the current comment for the object
     497identified by <type> and <name>, or C<No comment set> if none is set.
     498
     499If <comment> is given, sets the comment on the object identified by
     500<type> and <name> to <comment>.  If <comment> is the empty string, clears
     501the comment.
     502
     503=item create <type> <name>
     504
     505Create a new object of type <type> with name <name>.  With some backends,
     506this will trigger creation of an entry in an external system as well.
     507The new object will have no ACLs and no owner set, so usually the
     508administrator will want to then set an owner with C<owner> so that the
     509object will be usable.
     510
     511=item destroy <type> <name>
     512
     513Destroy the object identified by <type> and <name>.  With some backends,
     514this will trigger destruction of an object in an external system as well.
     515
     516=item expires <type> <name> [<date> [<time>]]
     517
     518If <date> is not given, displays the current expiration of the object
     519identified by <type> and <name>, or C<No expiration set> if none is set.
     520The expiration will be displayed in seconds since epoch.
     521
     522If <date> is given, sets the expiration on the object identified by <type>
     523and <name> to <date> and (if given) <time>.  <date> and <time> must be in
     524some format that can be parsed by the Perl Date::Parse module.  Most
     525common 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
     528Currently, the expiration of an object is not used.
     529
     530=item flag clear <type> <name> <flag>
     531
     532Clears the flag <flag> on the object identified by <type> and <name>.
     533
     534=item flag set <type> <name> <flag>
     535
     536Sets the flag <flag> on the object identified by <type> and <name>.
     537Recognized flags are C<locked>, which prevents all further actions on that
     538object until the flag is cleared, and C<unchanging>, which tells the
     539object backend to not generate new data on get but instead return the same
     540data as previously returned.  The C<unchanging> flag is not meaningful for
     541objects that do not generate new data on the fly.
     542
     543=item get <type> <name>
     544
     545Prints to standard output the data associated with the object identified
     546by <type> and <name>.  This may trigger generation of new data and
     547invalidate old data for that object depending on the object type.
     548
     549=item getacl <type> <name> <acl>
     550
     551Prints the ACL <acl>, which must be one of C<get>, C<store>, C<show>,
     552C<destroy>, or C<flags>, for the object identified by <type> and <name>.
     553Prints C<No ACL set> if that ACL isn't set on that object.  Remember that
     554if the C<get>, C<store>, or C<show> ACLs aren't set, authorization falls
     555back to checking the owner ACL.  See the C<owner> command for displaying
     556or setting it.
     557
     558=item getattr <type> <name> <attr>
     559
     560Prints the object attribute <attr> for the object identified by <type> and
     561<name>.  Attributes are used to store backend-specific information for a
     562particular object type, and <attr> must be an attribute type known to the
     563underlying object implementation.  The attribute values, if any, are
     564printed one per line.  If the attribute is not set on this object, nothing
     565is printed.
     566
     567=item history <type> <name>
     568
     569Displays the history for the object identified by <type> and <name>.  This
     570human-readable output will have two lines for each action that changes the
     571object, plus for any get action.  The first line has the timestamp of the
     572action and the action, and the second line gives the user who performed
     573the action and the host from which they performed it.
     574
     575=item owner <type> <name> [<owner>]
     576
     577If <owner> is not given, displays the current owner ACL of the object
     578identified by <type> and <name>, or C<No owner set> if none is set.  The
     579result will be the name of an ACL.
     580
     581If <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
     583the object.
     584
     585=item rename <type> <name> <new-name>
     586
     587Renames an existing object.  This currently only supports file objects,
     588where it renames the object itself, then the name and location of the
     589object in the file store.
     590
     591=item setacl <type> <name> <acl> <id>
     592
     593Sets the ACL <acl>, which must be one of C<get>, C<store>, C<show>,
     594C<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
     599Sets the object attribute <attr> for the object identified by <type> and
     600<name>.  Attributes are used to store backend-specific information for a
     601particular object type, and <attr> must be an attribute type known to the
     602underlying object implementation.  To clear the attribute for this object,
     603pass in a <value> of the empty string (C<''>).
     604
     605=item show <type> <name>
     606
     607Displays the current object metadata for the object identified by <type>
     608and <name>.  This human-readable output will show the object type and
     609name, the owner, any specific ACLs set on the object, the expiration if
     610any, and the user, remote host, and time when the object was created, last
     611stored, and last downloaded.
     612
     613=item store <type> <name> [<data>]
     614
     615Stores <data> for the object identified by <type> and <name> for later
     616retrieval with C<get>.  Not all object types support this.  If <data> is
     617not given as an argument, it will be read from standard input.
     618
     619=item update <type> <name>
     620
     621Prints to standard output the data associated with the object identified
     622by <type> and <name>.  If the object is one that can have changing
     623information, such as a keytab or password, then we generate new data for
     624that object regardless of whether there is current data or the unchanging
     625flag is set.
     626
     627=back
     628
     629=head1 ATTRIBUTES
     630
     631Object attributes store additional properties and configuration
     632information for objects stored in the wallet.  They are displayed as part
     633of the object data with C<show>, retrieved with C<getattr>, and set with
     634C<setattr>.
     635
     636=head2 Keytab Attributes
     637
     638Keytab objects support the following attributes:
     639
     640=over 4
     641
     642=item enctypes
     643
     644Restricts the generated keytab to a specific set of encryption types.  The
     645values 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
     647the salt should not be included; since the salt is irrelevant for keytab
     648keys, it will always be set to C<normal> by the wallet.
     649
     650If this attribute is set, the specified enctype list will be passed to
     651ktadd when get() is called for that keytab.  If it is not set, the default
     652set in the KDC will be used.
     653
     654This attribute is ignored if the C<unchanging> flag is set on a keytab.
     655Keytabs retrieved with C<unchanging> set will contain all keys present in
     656the KDC for that Kerberos principal and therefore may contain different
     657enctypes than those requested by this attribute.
     658
     659=back
     660
     661=head1 AUTHOR
     662
     663Russ Allbery <eagle@eyrie.org>
     664
     665=head1 COPYRIGHT AND LICENSE
     666
     667Copyright 2007, 2008, 2010, 2011, 2012, 2013 The Board of Trustees of the
     668Leland Stanford Junior University
     669
     670Permission is hereby granted, free of charge, to any person obtaining a
     671copy of this software and associated documentation files (the "Software"),
     672to deal in the Software without restriction, including without limitation
     673the rights to use, copy, modify, merge, publish, distribute, sublicense,
     674and/or sell copies of the Software, and to permit persons to whom the
     675Software is furnished to do so, subject to the following conditions:
     676
     677The above copyright notice and this permission notice shall be included in
     678all copies or substantial portions of the Software.
     679
     680THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     681IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     682FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     683THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     684LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
     685FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
     686DEALINGS IN THE SOFTWARE.
     687
     688=head1 SEE ALSO
     689
     690Wallet::Server(3), remctld(8)
     691
     692This program is part of the wallet system.  The current version is
     693available from L<http://www.eyrie.org/~eagle/software/wallet/>.
     694
     695=cut