1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
|
--- a/perl/lib/Wallet/Config.pm
+++ b/perl/lib/Wallet/Config.pm
@@ -1038,6 +1038,25 @@ Obvious improvements could be made, such
the slash for a C<host/> ACL looked like a host name and the part after a
slash for a C<user/> ACL look like a user name.
+=head1 FILE CHECKSUMS
+
+By default a file objects checksum some will be calculated using the
+perl function md5_hex of the Digest::MD5 module. This behavior can be
+overriden by defining a perl function in the configuration file named
+file_checksum that returns a checksum for the file.
+
+For example, the following file_checksub function returns the MD5 hash
+as a base64 string.
+
+ sub file_checksum {
+ my ($path) = @_;
+ open(my $fh, '<', $path) or die "ERROR: reading $filename";
+ binmode($fh);
+ my $cs = Digest::MD5->new->addfile($fh)->b64digest, "\n";
+ close $fh;
+ return $cs;
+ }
+
=head1 ENVIRONMENT
=over 4
--- a/perl/lib/Wallet/Object/File.pm
+++ b/perl/lib/Wallet/Object/File.pm
@@ -19,6 +19,7 @@ use warnings;
use Digest::MD5 qw(md5_hex);
use File::Copy qw(move);
+use File::Slurp;
use Wallet::Config;
use Wallet::Object::Base;
@@ -146,6 +147,26 @@ sub get {
return $data;
}
+# Return an check sum of a file
+sub checksum {
+ my ($self, $user, $host, $time) = @_;
+ $time ||= time;
+ my $id = $self->{type} . ':' . $self->{name};
+ if ($self->flag_check ('locked')) {
+ $self->error ("cannot get $id: object is locked");
+ return;
+ }
+ my $path = $self->file_path;
+ my $this_checksum;
+ if (defined (&Wallet::Config::file_checksum)) {
+ $this_checksum = Wallet::Config::file_checksum($path);
+ } else {
+ $this_checksum = md5_hex(read_file($path));
+ }
+ $self->log_action ('checksum', $user, $host, $time);
+ return $this_checksum;
+}
+
# Store the file on the wallet server.
sub store {
my ($self, $data, $user, $host, $time) = @_;
@@ -242,6 +263,13 @@ HOSTNAME, and DATETIME are stored as his
should be the user who is downloading the keytab. If DATETIME isn't
given, the current time is used.
+=item checksum(PRINCIPAL, HOSTNAME [, DATETIME])
+
+Retrieves the checksum for contents of the file object or undef on
+error. PRINCIPAL, HOSTNAME, and DATETIME are stored as history
+information. PRINCIPAL should be the user who is downloading the
+keytab. If DATETIME isn't given, the current time is used.
+
=item store(DATA, PRINCIPAL, HOSTNAME [, DATETIME])
Store DATA as the current contents of the file object. Any existing data
--- a/server/wallet-backend.in
+++ b/server/wallet-backend.in
@@ -196,6 +196,14 @@ sub command {
} else {
print $status ? "yes\n" : "no\n";
}
+ } elsif ($command eq 'checksum') {
+ check_args (2, 2, [], @args);
+ my $output = $server->checksum (@args);
+ if (defined $output) {
+ print $output;
+ } else {
+ failure ($server->error, @_);
+ }
} elsif ($command eq 'comment') {
check_args (2, 3, [3], @args);
if (@args > 2) {
--- a/perl/lib/Wallet/Server.pm
+++ b/perl/lib/Wallet/Server.pm
@@ -499,6 +499,25 @@ sub check {
return 1;
}
+# Returns the checksum for a file or password object.
+sub checksum {
+ my ($self, $type, $name) = @_;
+ if ($type ne 'file' && $type ne 'password') {
+ $self->error ("Invalid type ${type}");
+ return;
+ }
+ my $object = $self->retrieve ($type, $name);
+ if (!defined $object) {
+ return;
+ }
+ if (!$self->acl_verify ($object, 'get')) {
+ return;
+ }
+ my $result = $object->checksum($self->{user}, $self->{host});
+ $self->error ($object->error) unless defined $result;
+ return $result;
+}
+
# 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
|