summaryrefslogtreecommitdiff
path: root/perl/Wallet/Server.pm
diff options
context:
space:
mode:
Diffstat (limited to 'perl/Wallet/Server.pm')
-rw-r--r--perl/Wallet/Server.pm1095
1 files changed, 0 insertions, 1095 deletions
diff --git a/perl/Wallet/Server.pm b/perl/Wallet/Server.pm
deleted file mode 100644
index 3266928..0000000
--- a/perl/Wallet/Server.pm
+++ /dev/null
@@ -1,1095 +0,0 @@
-# Wallet::Server -- Wallet system server implementation.
-#
-# Written by Russ Allbery <eagle@eyrie.org>
-# Copyright 2007, 2008, 2010, 2011, 2013
-# The Board of Trustees of the Leland Stanford Junior University
-#
-# See LICENSE for licensing terms.
-
-##############################################################################
-# Modules and declarations
-##############################################################################
-
-package Wallet::Server;
-require 5.006;
-
-use strict;
-use vars qw(%MAPPING $VERSION);
-
-use Wallet::ACL;
-use Wallet::Config;
-use Wallet::Schema;
-
-# This version should be increased on any code change to this module. Always
-# use two digits for the minor version with a leading zero if necessary so
-# that it will sort properly.
-$VERSION = '0.11';
-
-##############################################################################
-# Utility methods
-##############################################################################
-
-# Create a new wallet server object. A new server should be created for each
-# user who is making changes to the wallet. Takes the principal and host who
-# are sending wallet requests. Opens a connection to the database that will
-# be used for all of the wallet metadata based on the wallet configuration
-# information. We also instantiate the administrative ACL, which we'll use
-# for various things. Throw an exception if anything goes wrong.
-sub new {
- my ($class, $user, $host) = @_;
- my $schema = Wallet::Schema->connect;
- my $acl = Wallet::ACL->new ('ADMIN', $schema);
- my $self = {
- schema => $schema,
- user => $user,
- host => $host,
- admin => $acl,
- };
- bless ($self, $class);
- return $self;
-}
-
-# Returns the database handle (used mostly for testing).
-sub dbh {
- my ($self) = @_;
- return $self->{schema}->storage->dbh;
-}
-
-# Returns the DBIx::Class-based database schema object.
-sub schema {
- my ($self) = @_;
- return $self->{schema};
-}
-
-# Set or return the error stashed in the object.
-sub error {
- my ($self, @error) = @_;
- if (@error) {
- my $error = join ('', @error);
- chomp $error;
- 1 while ($error =~ s/ at \S+ line \d+\.?\z//);
- $self->{error} = $error;
- }
- return $self->{error};
-}
-
-# Disconnect the database handle on object destruction to avoid warnings.
-sub DESTROY {
- my ($self) = @_;
-
- if ($self->{schema}) {
- $self->{schema}->storage->dbh->disconnect;
- }
-}
-
-##############################################################################
-# Object methods
-##############################################################################
-
-# Given an object type, return the mapping to a class by querying the
-# database, or undef if no mapping exists. Also load the relevant module.
-sub type_mapping {
- my ($self, $type) = @_;
- my $class;
- eval {
- my $guard = $self->{schema}->txn_scope_guard;
- my %search = (ty_name => $type);
- my $type_rec = $self->{schema}->resultset('Type')->find (\%search);
- $class = $type_rec->ty_class;
- $guard->commit;
- };
- if ($@) {
- $self->error ($@);
- return;
- }
- if (defined $class) {
- eval "require $class";
- if ($@) {
- $self->error ($@);
- return;
- }
- }
- return $class;
-}
-
-# Given an object which doesn't currently exist, check whether a default_owner
-# function is defined and, if so, if it returns an ACL for that object. If
-# so, create the ACL and check if the current user is authorized by that ACL.
-# Returns true if so, false if not, setting the internal error as appropriate.
-#
-# This leaves those new ACLs in the database, which may not be the best
-# behavior, but it's the simplest given the current Wallet::ACL API. This
-# should probably be revisited later.
-sub create_check {
- my ($self, $type, $name) = @_;
- my $user = $self->{user};
- my $host = $self->{host};
- my $schema = $self->{schema};
- unless (defined (&Wallet::Config::default_owner)) {
- $self->error ("$user not authorized to create ${type}:${name}");
- return;
- }
- my ($aname, @acl) = Wallet::Config::default_owner ($type, $name);
- unless (defined $aname) {
- $self->error ("$user not authorized to create ${type}:${name}");
- return;
- }
- my $acl = eval { Wallet::ACL->new ($aname, $schema) };
- if ($@) {
- $acl = eval { Wallet::ACL->create ($aname, $schema, $user, $host) };
- if ($@) {
- $self->error ($@);
- return;
- }
- for my $entry (@acl) {
- unless ($acl->add ($entry->[0], $entry->[1], $user, $host)) {
- $self->error ($acl->error);
- return;
- }
- }
- } else {
- my @entries = $acl->list;
- if (not @entries and $acl->error) {
- $self->error ($acl->error);
- return;
- }
- @entries = sort { $$a[0] cmp $$b[0] && $$a[1] cmp $$b[1] } @entries;
- @acl = sort { $$a[0] cmp $$b[0] && $$a[1] cmp $$b[1] } @acl;
- my $okay = 1;
- if (@entries != @acl) {
- $okay = 0;
- } else {
- for my $i (0 .. $#entries) {
- $okay = 0 unless ($entries[$i][0] eq $acl[$i][0]);
- $okay = 0 unless ($entries[$i][1] eq $acl[$i][1]);
- }
- }
- unless ($okay) {
- $self->error ("ACL $aname exists and doesn't match default");
- return;
- }
- }
- if ($acl->check ($user)) {
- return $aname;
- } else {
- $self->error ("$user not authorized to create ${type}:${name}");
- return;
- }
-}
-
-# Create an object and returns it. This function is called by both create and
-# autocreate and assumes that permissions and names have already been checked.
-# On error, returns undef and sets the internal error.
-sub create_object {
- my ($self, $type, $name) = @_;
- my $class = $self->type_mapping ($type);
- unless ($class) {
- $self->error ("unknown object type $type");
- return;
- }
- my $schema = $self->{schema};
- my $user = $self->{user};
- my $host = $self->{host};
- my $object = eval { $class->create ($type, $name, $schema, $user, $host) };
- if ($@) {
- $self->error ($@);
- return;
- }
- return $object;
-}
-
-# Create a new object and returns that object. This method can only be called
-# by wallet administrators. autocreate should be used by regular users who
-# may benefit from default ACLs. On error, returns undef and sets the
-# internal error.
-sub create {
- my ($self, $type, $name) = @_;
- unless ($self->{admin}->check ($self->{user})) {
- my $id = $type . ':' . $name;
- $self->error ("$self->{user} not authorized to create $id");
- return;
- }
- if (defined (&Wallet::Config::verify_name)) {
- my $error = Wallet::Config::verify_name ($type, $name, $self->{user});
- if ($error) {
- $self->error ("${type}:${name} rejected: $error");
- return;
- }
- }
- return unless $self->create_object ($type, $name);
- return 1;
-}
-
-# Attempt to auto-create an object based on default ACLs. This method is
-# called by the wallet client when trying to get an object that doesn't
-# already exist. On error, returns undef and sets the internal error.
-sub autocreate {
- my ($self, $type, $name) = @_;
- if (defined (&Wallet::Config::verify_name)) {
- my $error = Wallet::Config::verify_name ($type, $name, $self->{user});
- if ($error) {
- $self->error ("${type}:${name} rejected: $error");
- return;
- }
- }
- my $acl = $self->create_check ($type, $name);
- return unless $acl;
- my $object = $self->create_object ($type, $name);
- return unless $object;
- unless ($object->owner ($acl, $self->{user}, $self->{host})) {
- $self->error ($object->error);
- return;
- }
- return 1;
-}
-
-# Given the name and type of an object, returns a Perl object representing it
-# or returns undef and sets the internal error.
-sub retrieve {
- my ($self, $type, $name) = @_;
- my $class = $self->type_mapping ($type);
- unless ($class) {
- $self->error ("unknown object type $type");
- return;
- }
- my $object = eval { $class->new ($type, $name, $self->{schema}) };
- if ($@) {
- $self->error ($@);
- return;
- } else {
- return $object;
- }
-}
-
-# Sets the internal error variable to the correct message for permission
-# denied on an object.
-sub object_error {
- my ($self, $object, $action) = @_;
- my $user = $self->{user};
- my $id = $object->type . ':' . $object->name;
- if ($action eq 'getattr') {
- $action = "get attributes for";
- } elsif ($action eq 'setattr') {
- $action = "set attributes for";
- } elsif ($action !~ /^(create|get|store|show|destroy)\z/) {
- $action = "set $action for";
- }
- $self->error ("$self->{user} not authorized to $action $id");
-}
-
-# Given an object and an action, checks if the current user has access to
-# perform that object. If so, returns true. If not, returns undef and sets
-# the internal error message. Note that we do not allow any special access to
-# admins for get and store; if they want to do that with objects, they need to
-# set the ACL accordingly.
-sub acl_verify {
- my ($self, $object, $action) = @_;
- my %actions = map { $_ => 1 }
- qw(get store show destroy flags setattr getattr comment);
- unless ($actions{$action}) {
- $self->error ("unknown action $action");
- return;
- }
- if ($action ne 'get' and $action ne 'store') {
- return 1 if $self->{admin}->check ($self->{user});
- }
- my $id;
- if ($action eq 'getattr') {
- $id = $object->acl ('show');
- } elsif ($action eq 'setattr') {
- $id = $object->acl ('store');
- } elsif ($action ne 'comment') {
- $id = $object->acl ($action);
- }
- if (! defined ($id) and $action ne 'flags') {
- $id = $object->owner;
- }
- unless (defined $id) {
- $self->object_error ($object, $action);
- return;
- }
- my $acl = eval { Wallet::ACL->new ($id, $self->{schema}) };
- if ($@) {
- $self->error ($@);
- return;
- }
- my $status = $acl->check ($self->{user});
- if ($status == 1) {
- return 1;
- } elsif (not defined $status) {
- $self->error ($acl->error);
- return;
- } else {
- $self->object_error ($object, $action);
- return;
- }
-}
-
-# Retrieves or sets an ACL on an object.
-sub acl {
- my ($self, $type, $name, $acl, $id) = @_;
- undef $self->{error};
- my $object = $self->retrieve ($type, $name);
- return unless defined $object;
- unless ($self->{admin}->check ($self->{user})) {
- $self->object_error ($object, 'ACL');
- return;
- }
- my $result;
- if (defined $id) {
- $result = $object->acl ($acl, $id, $self->{user}, $self->{host});
- } else {
- $result = $object->acl ($acl);
- }
- if (not defined ($result) and $object->error) {
- $self->error ($object->error);
- }
- return $result;
-}
-
-# Retrieves or sets an attribute on an object.
-sub attr {
- my ($self, $type, $name, $attr, @values) = @_;
- undef $self->{error};
- my $object = $self->retrieve ($type, $name);
- return unless defined $object;
- my $user = $self->{user};
- my $host = $self->{host};
- if (@values) {
- return unless $self->acl_verify ($object, 'setattr');
- if (@values == 1 and $values[0] eq '') {
- @values = ();
- }
- my $result = $object->attr ($attr, [ @values ], $user, $host);
- $self->error ($object->error) unless $result;
- return $result;
- } else {
- return unless $self->acl_verify ($object, 'getattr');
- my @result = $object->attr ($attr);
- if (not @result and $object->error) {
- $self->error ($object->error);
- return;
- } else {
- return @result;
- }
- }
-}
-
-# Retrieves or sets the comment of an object.
-sub comment {
- my ($self, $type, $name, $comment) = @_;
- undef $self->{error};
- my $object = $self->retrieve ($type, $name);
- return unless defined $object;
- my $result;
- if (defined $comment) {
- return unless $self->acl_verify ($object, 'comment');
- $result = $object->comment ($comment, $self->{user}, $self->{host});
- } else {
- return unless $self->acl_verify ($object, 'show');
- $result = $object->comment;
- }
- if (not defined ($result) and $object->error) {
- $self->error ($object->error);
- }
- return $result;
-}
-
-# Retrieves or sets the expiration of an object.
-sub expires {
- my ($self, $type, $name, $expires) = @_;
- undef $self->{error};
- my $object = $self->retrieve ($type, $name);
- return unless defined $object;
- unless ($self->{admin}->check ($self->{user})) {
- $self->object_error ($object, 'expires');
- return;
- }
- my $result;
- if (defined $expires) {
- $result = $object->expires ($expires, $self->{user}, $self->{host});
- } else {
- $result = $object->expires;
- }
- if (not defined ($result) and $object->error) {
- $self->error ($object->error);
- }
- return $result;
-}
-
-# Retrieves or sets the owner of an object.
-sub owner {
- my ($self, $type, $name, $owner) = @_;
- undef $self->{error};
- my $object = $self->retrieve ($type, $name);
- return unless defined $object;
- unless ($self->{admin}->check ($self->{user})) {
- $self->object_error ($object, 'owner');
- return;
- }
- my $result;
- if (defined $owner) {
- $result = $object->owner ($owner, $self->{user}, $self->{host});
- } else {
- $result = $object->owner;
- }
- if (not defined ($result) and $object->error) {
- $self->error ($object->error);
- }
- return $result;
-}
-
-# Checks for the existence of an object. Returns 1 if it does, 0 if it
-# doesn't, and undef if there was an error in checking the existence of the
-# object.
-sub check {
- my ($self, $type, $name) = @_;
- my $object = $self->retrieve ($type, $name);
- if (not defined $object) {
- if ($self->error =~ /^cannot find/) {
- return 0;
- } else {
- return;
- }
- }
- return 1;
-}
-
-# Retrieve the information associated with an object, or returns undef and
-# sets the internal error if the retrieval fails or if the user isn't
-# authorized. If the object doesn't exist, attempts dynamic creation of the
-# object using the default ACL mappings (if any).
-sub get {
- my ($self, $type, $name) = @_;
- my $object = $self->retrieve ($type, $name);
- return unless defined $object;
- return unless $self->acl_verify ($object, 'get');
- my $result = $object->get ($self->{user}, $self->{host});
- $self->error ($object->error) unless defined $result;
- return $result;
-}
-
-# Store new data in an object, or returns undef and sets the internal error if
-# the object can't be found or if the user isn't authorized. Also don't
-# permit storing undef, although storing the empty string is fine. If the
-# object doesn't exist, attempts dynamic creation of the object using the
-# default ACL mappings (if any).
-sub store {
- my ($self, $type, $name, $data) = @_;
- my $object = $self->retrieve ($type, $name);
- return unless defined $object;
- return unless $self->acl_verify ($object, 'store');
- if (not defined ($data)) {
- $self->{error} = "no data supplied to store";
- return;
- }
- my $result = $object->store ($data, $self->{user}, $self->{host});
- $self->error ($object->error) unless defined $result;
- return $result;
-}
-
-# Return a human-readable description of the object's metadata, or returns
-# undef and sets the internal error if the object can't be found or if the
-# user isn't authorized.
-sub show {
- my ($self, $type, $name) = @_;
- my $object = $self->retrieve ($type, $name);
- return unless defined $object;
- return unless $self->acl_verify ($object, 'show');
- my $result = $object->show;
- $self->error ($object->error) unless defined $result;
- return $result;
-}
-
-# Return a human-readable description of the object history, or returns undef
-# and sets the internal error if the object can't be found or if the user
-# isn't authorized.
-sub history {
- my ($self, $type, $name) = @_;
- my $object = $self->retrieve ($type, $name);
- return unless defined $object;
- return unless $self->acl_verify ($object, 'show');
- my $result = $object->history;
- $self->error ($object->error) unless defined $result;
- return $result;
-}
-
-# Destroys the object, or returns undef and sets the internal error if the
-# object can't be found or if the user isn't authorized.
-sub destroy {
- my ($self, $type, $name) = @_;
- my $object = $self->retrieve ($type, $name);
- return unless defined $object;
- return unless $self->acl_verify ($object, 'destroy');
- my $result = $object->destroy ($self->{user}, $self->{host});
- $self->error ($object->error) unless defined $result;
- return $result;
-}
-
-##############################################################################
-# Object flag methods
-##############################################################################
-
-# Clear a flag on an object. Takes the object and the flag. Returns true on
-# success or undef and sets the internal error on failure.
-sub flag_clear {
- my ($self, $type, $name, $flag) = @_;
- my $object = $self->retrieve ($type, $name);
- return unless defined $object;
- return unless $self->acl_verify ($object, 'flags');
- my $result = $object->flag_clear ($flag, $self->{user}, $self->{host});
- $self->error ($object->error) unless defined $result;
- return $result;
-}
-
-# Set a flag on an object. Takes the object and the flag. Returns true on
-# success or undef and sets the internal error on failure.
-sub flag_set {
- my ($self, $type, $name, $flag) = @_;
- my $object = $self->retrieve ($type, $name);
- return unless defined $object;
- return unless $self->acl_verify ($object, 'flags');
- my $result = $object->flag_set ($flag, $self->{user}, $self->{host});
- $self->error ($object->error) unless defined $result;
- return $result;
-}
-
-##############################################################################
-# ACL methods
-##############################################################################
-
-# Checks for the existence of an ACL. Returns 1 if it does, 0 if it doesn't,
-# and undef if there was an error in checking the existence of the object.
-sub acl_check {
- my ($self, $id) = @_;
- my $acl = eval { Wallet::ACL->new ($id, $self->{schema}) };
- if ($@) {
- if ($@ =~ /^ACL .* not found/) {
- return 0;
- } else {
- $self->error ($@);
- return;
- }
- }
- return 1;
-}
-
-# Create a new empty ACL in the database. Returns true on success and undef
-# on failure, setting the internal error.
-sub acl_create {
- my ($self, $name) = @_;
- unless ($self->{admin}->check ($self->{user})) {
- $self->error ("$self->{user} not authorized to create ACL");
- return;
- }
- my $user = $self->{user};
- my $host = $self->{host};
- if (defined (&Wallet::Config::verify_acl_name)) {
- my $error = Wallet::Config::verify_acl_name ($name, $user);
- if ($error) {
- $self->error ("$name rejected: $error");
- return;
- }
- }
- my $schema = $self->{schema};
- my $acl = eval { Wallet::ACL->create ($name, $schema, $user, $host) };
- if ($@) {
- $self->error ($@);
- return;
- } else {
- return 1;
- }
-}
-
-# Sets the internal error variable to the correct message for permission
-# denied on an ACL.
-sub acl_error {
- my ($self, $acl, $action) = @_;
- my $user = $self->{user};
- if ($action eq 'add') {
- $action = 'add to';
- } elsif ($action eq 'remove') {
- $action = 'remove from';
- } elsif ($action eq 'history') {
- $action = 'see history of';
- }
- $self->error ("$self->{user} not authorized to $action ACL $acl");
-}
-
-# Display the history of an ACL or return undef and set the internal error.
-sub acl_history {
- my ($self, $id) = @_;
- unless ($self->{admin}->check ($self->{user})) {
- $self->acl_error ($id, 'history');
- return;
- }
- my $acl = eval { Wallet::ACL->new ($id, $self->{schema}) };
- if ($@) {
- $self->error ($@);
- return;
- }
- my $result = $acl->history;
- if (not defined $result) {
- $self->error ($acl->error);
- return;
- }
- return $result;
-}
-
-# Display the membership of an ACL or return undef and set the internal error.
-sub acl_show {
- my ($self, $id) = @_;
- unless ($self->{admin}->check ($self->{user})) {
- $self->acl_error ($id, 'show');
- return;
- }
- my $acl = eval { Wallet::ACL->new ($id, $self->{schema}) };
- if ($@) {
- $self->error ($@);
- return;
- }
- my $result = $acl->show;
- if (not defined $result) {
- $self->error ($acl->error);
- return;
- }
- return $result;
-}
-
-# Change the human-readable name of an ACL or return undef and set the
-# internal error.
-sub acl_rename {
- my ($self, $id, $name) = @_;
- unless ($self->{admin}->check ($self->{user})) {
- $self->acl_error ($id, 'rename');
- return;
- }
- my $acl = eval { Wallet::ACL->new ($id, $self->{schema}) };
- if ($@) {
- $self->error ($@);
- return;
- }
- if ($acl->name eq 'ADMIN') {
- $self->error ('cannot rename the ADMIN ACL');
- return;
- }
- if (defined (&Wallet::Config::verify_acl_name)) {
- my $error = Wallet::Config::verify_acl_name ($name, $self->{user});
- if ($error) {
- $self->error ("$name rejected: $error");
- return;
- }
- }
- unless ($acl->rename ($name)) {
- $self->error ($acl->error);
- return;
- }
- return 1;
-}
-
-# Destroy an ACL, deleting it out of the database. Returns true on success.
-# On failure, returns undef, setting the internal error.
-sub acl_destroy {
- my ($self, $id) = @_;
- unless ($self->{admin}->check ($self->{user})) {
- $self->acl_error ($id, 'destroy');
- return;
- }
- my $acl = eval { Wallet::ACL->new ($id, $self->{schema}) };
- if ($@) {
- $self->error ($@);
- return;
- }
- if ($acl->name eq 'ADMIN') {
- $self->error ('cannot destroy the ADMIN ACL');
- return;
- }
- unless ($acl->destroy ($self->{user}, $self->{host})) {
- $self->error ($acl->error);
- return;
- }
- return 1;
-}
-
-# Add an ACL entry to an ACL. Returns true on success. On failure, returns
-# undef, setting the internal error.
-sub acl_add {
- my ($self, $id, $scheme, $identifier) = @_;
- unless ($self->{admin}->check ($self->{user})) {
- $self->acl_error ($id, 'add');
- return;
- }
- my $acl = eval { Wallet::ACL->new ($id, $self->{schema}) };
- if ($@) {
- $self->error ($@);
- return;
- }
- unless ($acl->add ($scheme, $identifier, $self->{user}, $self->{host})) {
- $self->error ($acl->error);
- return;
- }
- return 1;
-}
-
-# Remove an ACL entry to an ACL. Returns true on success. On failure,
-# returns undef, setting the internal error.
-sub acl_remove {
- my ($self, $id, $scheme, $identifier) = @_;
- unless ($self->{admin}->check ($self->{user})) {
- $self->acl_error ($id, 'remove');
- return;
- }
- my $acl = eval { Wallet::ACL->new ($id, $self->{schema}) };
- if ($@) {
- $self->error ($@);
- return;
- }
- if ($acl->name eq 'ADMIN') {
- my @e = $acl->list;
- if (not @e and $acl->error) {
- $self->error ($acl->error);
- return;
- } elsif (@e == 1 && $e[0][0] eq $scheme && $e[0][1] eq $identifier) {
- $self->error ('cannot remove last ADMIN ACL entry');
- return;
- }
- }
- my $user = $self->{user};
- my $host = $self->{host};
- unless ($acl->remove ($scheme, $identifier, $user, $host)) {
- $self->error ($acl->error);
- return;
- }
- return 1;
-}
-
-1;
-__END__
-
-##############################################################################
-# Documentation
-##############################################################################
-
-=head1 NAME
-
-Wallet::Server - Wallet system server implementation
-
-=for stopwords
-keytabs metadata backend HOSTNAME ACL timestamp ACL's nul Allbery
-backend-specific wallet-backend verifier
-
-=head1 SYNOPSIS
-
- use Wallet::Server;
- my $server = Wallet::Server->new ($user, $host);
- $server->create ('keytab', 'host/example.com@EXAMPLE.COM');
-
-=head1 DESCRIPTION
-
-Wallet::Server is the top-level class that implements the wallet server.
-The wallet is a system for storing, generating, and retrieving secure
-information such as Kerberos keytabs. The server maintains metadata about
-the objects, checks access against ACLs, and dispatches requests for
-objects to backend implementations for that object type.
-
-Wallet::Server is normally instantiated and used by B<wallet-backend>, a
-thin wrapper around this object that determines the authenticated remote
-user and gets user input and then calls the appropriate method of this
-object.
-
-To use this object, several configuration variables must be set (at least
-the database configuration). For information on those variables and how
-to set them, see L<Wallet::Config>.
-
-=head1 CLASS METHODS
-
-=over 4
-
-=item new(PRINCIPAL, HOSTNAME)
-
-Creates a new wallet server object for actions from the user PRINCIPAL
-connecting from HOSTNAME. PRINCIPAL and HOSTNAME will be used for logging
-history information for all subsequent operations. new() opens the
-database, using the database configuration as set by Wallet::Config and
-ensures that the C<ADMIN> ACL exists. That ACL will be used to authorize
-privileged operations.
-
-On any error, this method throws an exception.
-
-=back
-
-=head1 INSTANCE METHODS
-
-For all methods that can fail, the caller should call error() after a
-failure to get the error message.
-
-=over 4
-
-=item acl(TYPE, NAME, ACL [, ID])
-
-Gets or sets the ACL type ACL to ID for the object identified by TYPE and
-NAME. ACL should be one of C<get>, C<store>, C<show>, C<destroy>, or
-C<flags>. If ID is not given, returns the current setting of that ACL as
-a numeric ACL ID or undef if that ACL isn't set or on failure. To
-distinguish between an ACL that isn't set and a failure to retrieve the
-ACL, the caller should call error() after an undef return. If error()
-also returns undef, that ACL wasn't set; otherwise, error() will return
-the error message.
-
-If ID is given, sets the specified ACL to ID, which can be either the name
-of an ACL or a numeric ACL ID. To clear the ACL, pass in an empty string
-as the ID. To set or clear an ACL, the current user must be authorized by
-the ADMIN ACL. Returns true for success and false for failure.
-
-ACL settings are checked before the owner and override the owner setting.
-
-=item acl_add(ID, SCHEME, IDENTIFIER)
-
-Adds an ACL entry with scheme SCHEME and identifier IDENTIFIER to the ACL
-identified by ID. ID may be either the ACL name or the numeric ACL ID.
-SCHEME must be a valid ACL scheme for which the wallet system has an ACL
-verifier implementation. To add an entry to an ACL, the current user must
-be authorized by the ADMIN ACL. Returns true for success and false for
-failure.
-
-=item acl_create(NAME)
-
-Create a new ACL with the specified NAME, which must not be all-numeric.
-The newly created ACL will be empty. To create an ACL, the current user
-must be authorized by the ADMIN ACL. Returns true on success and false on
-failure.
-
-=item acl_destroy(ID)
-
-Destroys the ACL identified by ID, which may be either the ACL name or its
-numeric ID. This call will fail if the ACL is still referenced by any
-object. The ADMIN ACL may not be destroyed. To destroy an ACL, the
-current user must be authorized by the ADMIN ACL. Returns true on success
-and false on failure.
-
-=item acl_history(ID)
-
-Returns the history of the ACL identified by ID, which may be either the
-ACL name or its numeric ID. To see the history of an ACL, the current
-user must be authorized by the ADMIN ACL. Each change that modifies the
-ACL (not counting changes in the name of the ACL) will be represented by
-two lines. The first line will have a timestamp of the change followed by
-a description of the change, and the second line will give the user who
-made the change and the host from which the change was made. Returns
-undef on failure.
-
-=item acl_remove(ID, SCHEME, IDENTIFIER)
-
-Removes from the ACL identified by ID the entry matching SCHEME and
-IDENTIFIER. ID may be either the name of the ACL or its numeric ID. The
-last entry in the ADMIN ACL cannot be removed. To remove an entry from an
-ACL, the current user must be authorized by the ADMIN ACL. Returns true
-on success and false on failure.
-
-=item acl_rename(OLD, NEW)
-
-Renames the ACL identified by OLD to NEW. This changes the human-readable
-name, not the underlying numeric ID, so the ACL's associations with
-objects will be unchanged. The ADMIN ACL may not be renamed. OLD may be
-either the current name or the numeric ID. NEW must not be all-numeric.
-To rename an ACL, the current user must be authorized by the ADMIN ACL.
-Returns true on success and false on failure.
-
-=item acl_show(ID)
-
-Returns a human-readable description, including membership, of the ACL
-identified by ID, which may be either the ACL name or its numeric ID. To
-show an ACL, the current user must be authorized by the ADMIN ACL
-(although be aware that anyone with show access to an object can see the
-membership of ACLs associated with that object through the show() method).
-Returns the human-readable description on success and undef on failure.
-
-=item attr(TYPE, NAME, ATTRIBUTE [, VALUE ...])
-
-Sets or retrieves a given object attribute. Attributes are used to store
-backend-specific information for a particular object type and ATTRIBUTE
-must be an attribute type known to the underlying object implementation.
-
-If VALUE is not given, returns the values of that attribute, if any, as a
-list. On error, returns the empty list. To distinguish between an error
-and an empty return, call error() afterward. It is guaranteed to return
-undef unless there was an error. To retrieve an attribute setting, the
-user must be authorized by the ADMIN ACL, the show ACL if set, or the
-owner ACL if the show ACL is not set.
-
-If VALUE is given, sets the given ATTRIBUTE values to VALUE, which is one
-or more attribute values. Pass the empty string as the only VALUE to
-clear the attribute values. Returns true on success and false on failure.
-To set an attribute value, the user must be authorized by the ADMIN ACL,
-the store ACL if set, or the owner ACL if the store ACL is not set.
-
-=item autocreate(TYPE, NAME)
-
-Creates a new object of type TYPE and name NAME. TYPE must be a
-recognized type for which the wallet system has a backend implementation.
-Returns true on success and false on failure.
-
-To create an object using this method, the current user must be authorized
-by the default owner as determined by the wallet configuration. For more
-information on how to map new objects to default owners, see
-Wallet::Config(3). Wallet administrators should use the create() method
-to create objects.
-
-=item check(TYPE, NAME)
-
-Check whether an object of type TYPE and name NAME exists. Returns 1 if
-it does, 0 if it doesn't, and undef if some error occurred while checking
-for the existence of the object.
-
-=item comment(TYPE, NAME, [COMMENT])
-
-Gets or sets the comment for the object identified by TYPE and NAME. If
-COMMENT is not given, returns the current comment or undef if no comment
-is set or on an error. To distinguish between an expiration that isn't
-set and a failure to retrieve the expiration, the caller should call
-error() after an undef return. If error() also returns undef, no comment
-was set; otherwise, error() will return the error message.
-
-If COMMENT is given, sets the comment to COMMENT. Pass in the empty
-string for COMMENT to clear the comment. To set a comment, the current
-user must be the object owner or be on the ADMIN ACL. Returns true for
-success and false for failure.
-
-=item create(TYPE, NAME)
-
-Creates a new object of type TYPE and name NAME. TYPE must be a
-recognized type for which the wallet system has a backend implementation.
-Returns true on success and false on failure.
-
-To create an object using this method, the current user must be authorized
-by the ADMIN ACL. Use autocreate() to create objects based on the default
-owner as determined by the wallet configuration.
-
-=item destroy(TYPE, NAME)
-
-Destroys the object identified by TYPE and NAME. This destroys any data
-that the wallet had saved about the object, may remove the underlying
-object from other external systems, and destroys the wallet database entry
-for the object. To destroy an object, the current user must be a member
-of the ADMIN ACL, authorized by the destroy ACL, or authorized by the
-owner ACL; however, if the destroy ACL is set, the owner ACL will not be
-checked. Returns true on success and false on failure.
-
-=item dbh()
-
-Returns the database handle of a Wallet::Server object. This is used
-mostly for testing; normally, clients should perform all actions through
-the Wallet::Server object to ensure that authorization and history logging
-is done properly.
-
-=item error()
-
-Returns the error of the last failing operation or undef if no operations
-have failed. Callers should call this function to get the error message
-after an undef return from any other instance method.
-
-=item expires(TYPE, NAME [, EXPIRES])
-
-Gets or sets the expiration for the object identified by TYPE and NAME.
-If EXPIRES is not given, returns the current expiration or undef if no
-expiration is set or on an error. To distinguish between an expiration
-that isn't set and a failure to retrieve the expiration, the caller should
-call error() after an undef return. If error() also returns undef, the
-expiration wasn't set; otherwise, error() will return the error message.
-
-If EXPIRES is given, sets the expiration to EXPIRES. EXPIRES must be in
-the format C<YYYY-MM-DD +HH:MM:SS>, although the time portion may be
-omitted. Pass in the empty string for EXPIRES to clear the expiration
-date. To set an expiration, the current user must be authorized by the
-ADMIN ACL. Returns true for success and false for failure.
-
-=item flag_clear(TYPE, NAME, FLAG)
-
-Clears the flag FLAG on the object identified by TYPE and NAME. To clear
-a flag, the current user must be authorized by the ADMIN ACL or the flags
-ACL on the object.
-
-=item flag_set(TYPE, NAME, FLAG)
-
-Sets the flag FLAG on the object identified by TYPE and NAME. To set a
-flag, the current user must be authorized by the ADMIN ACL or the flags
-ACL on the object.
-
-=item get(TYPE, NAME)
-
-Returns the data associated with the object identified by TYPE and NAME.
-Depending on the object TYPE, this may generate new data and invalidate
-any existing data or it may return data previously stored or generated.
-Note that this data may be binary and may contain nul characters. To get
-an object, the current user must either be authorized by the owner ACL or
-authorized by the get ACL; however, if the get ACL is set, the owner ACL
-will not be checked. Being a member of the ADMIN ACL does not provide any
-special privileges to get objects.
-
-Returns undef on failure. The caller should be careful to distinguish
-between undef and the empty string, which is valid object data.
-
-=item history(TYPE, NAME)
-
-Returns (as a string) the human-readable history of the object identified
-by TYPE and NAME, or undef on error. To see the object history, the
-current user must be a member of the ADMIN ACL, authorized by the show
-ACL, or authorized by the owner ACL; however, if the show ACL is set, the
-owner ACL will not be checked.
-
-=item owner(TYPE, NAME [, OWNER])
-
-Gets or sets the owner for the object identified by TYPE and NAME. If
-OWNER is not given, returns the current owner as a numeric ACL ID or undef
-if no owner is set or on an error. To distinguish between an owner that
-isn't set and a failure to retrieve the owner, the caller should call
-error() after an undef return. If error() also returns undef, that ACL
-wasn't set; otherwise, error() will return the error message.
-
-If OWNER is given, sets the owner to OWNER, which may be either the name
-of an ACL or a numeric ACL ID. To set an owner, the current user must be
-authorized by the ADMIN ACL. Returns true for success and false for
-failure.
-
-The owner of an object is permitted to get, store, and show that object,
-but cannot destroy or set flags on that object without being listed on
-those ACLs as well.
-
-=item schema()
-
-Returns the DBIx::Class schema object.
-
-=item show(TYPE, NAME)
-
-Returns (as a string) a human-readable representation of the metadata
-stored for the object identified by TYPE and NAME, or undef on error.
-Included is the metadata and entries of any ACLs associated with the
-object. To show an object, the current user must be a member of the ADMIN
-ACL, authorized by the show ACL, or authorized by the owner ACL; however,
-if the show ACL is set, the owner ACL will not be checked.
-
-=item store(TYPE, NAME, DATA)
-
-Stores DATA for the object identified with TYPE and NAME for later
-retrieval with get. Not all object types support this. Note that DATA
-may be binary and may contain nul characters. To store an object, the
-current user must either be authorized by the owner ACL or authorized by
-the store ACL; however, if the store ACL is set, the owner ACL is not
-checked. Being a member of the ADMIN ACL does not provide any special
-privileges to store objects. Returns true on success and false on
-failure.
-
-=back
-
-=head1 SEE ALSO
-
-wallet-backend(8)
-
-This module is part of the wallet system. The current version is
-available from L<http://www.eyrie.org/~eagle/software/wallet/>.
-
-=head1 AUTHOR
-
-Russ Allbery <eagle@eyrie.org>
-
-=cut