From b2658a0fd461562b83a84040eca0babc16069380 Mon Sep 17 00:00:00 2001 From: Bill MacAllister Date: Mon, 30 Sep 2019 21:15:44 +0000 Subject: [PATCH 01/47] Add password charset, add checksum, allow quilt * Allow the specification of valid characters to be used when generating passwords. * Add the command checksum to return the checksum of file objects. * Patches to allow the use of quilt. --- debian/changelog | 15 +++ debian/control | 2 + debian/patches/0001-allow-quilt.patch | 25 +++++ debian/patches/0002-password-charset.patch | 40 ++++++++ debian/patches/0003-checksum.patch | 102 +++++++++++++++++++++ debian/patches/0004-news.patch | 24 +++++ debian/patches/series | 4 + 7 files changed, 212 insertions(+) create mode 100644 debian/patches/0001-allow-quilt.patch create mode 100644 debian/patches/0002-password-charset.patch create mode 100644 debian/patches/0003-checksum.patch create mode 100644 debian/patches/0004-news.patch create mode 100644 debian/patches/series diff --git a/debian/changelog b/debian/changelog index f9e71a2c..80d70603 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,18 @@ +wallet (1.4-3) unstable; urgency=medium + + * Allow the specification of valid characters to be used when + generating passwords. + * Add the command checksum to return the checksum of file objects. + * Patches to allow the use of quilt. + + -- Bill MacAllister Mon, 30 Sep 2019 18:39:21 +0000 + +wallet (1.4-2) unstable; urgency=medium + + * Dropbox only release + + -- Bill MacAllister Sun, 06 Jan 2019 19:49:07 +0000 + wallet (1.4-1) unstable; urgency=medium * New upstream release. diff --git a/debian/control b/debian/control index 84b3c8a2..e70f542f 100644 --- a/debian/control +++ b/debian/control @@ -12,6 +12,7 @@ Build-Depends: libdbd-sqlite3-perl, libdbi-perl, libdbix-class-perl, + libfile-slurp-perl, libheimdal-kadm5-perl, libipc-run-perl, libjson-perl, @@ -82,6 +83,7 @@ Depends: libdbd-sqlite3-perl | libdbd-mysql-perl | libdbd-pg-perl, libdbi-perl, libdbix-class-perl, + libfile-slurp-perl, libsql-translator-perl, libtimedate-perl, remctl-server, diff --git a/debian/patches/0001-allow-quilt.patch b/debian/patches/0001-allow-quilt.patch new file mode 100644 index 00000000..1edd0f4c --- /dev/null +++ b/debian/patches/0001-allow-quilt.patch @@ -0,0 +1,25 @@ +diff --git a/tests/docs/spdx-license-t b/tests/docs/spdx-license-t +index 91072bf..a55b054 100755 +--- a/tests/docs/spdx-license-t ++++ b/tests/docs/spdx-license-t +@@ -72,6 +72,7 @@ my @IGNORE_PATHS = ( + qr{ \A php/ltmain [.] sh \z }xms, # Created by phpize + qr{ \A php/run-tests [.] php \z }xms, # Created by phpize + qr{ [.] l?a \z }xms, # Created by libtool ++ qr{ [.] pc/ }xms, # Created by quilt + ); + ## use critic + +diff --git a/tests/tap/perl/Test/RRA/Automake.pm b/tests/tap/perl/Test/RRA/Automake.pm +index 69fff6a..1a785ff 100644 +--- a/tests/tap/perl/Test/RRA/Automake.pm ++++ b/tests/tap/perl/Test/RRA/Automake.pm +@@ -74,7 +74,7 @@ BEGIN { + # Directories to skip globally when looking for all files, or for directories + # that could contain Perl files. + my @GLOBAL_SKIP = qw( +- .git _build autom4te.cache build-aux perl/_build perl/blib ++ .git _build autom4te.cache build-aux perl/_build perl/blib debian .pc + ); + + # Additional paths to skip when building a list of all files in the diff --git a/debian/patches/0002-password-charset.patch b/debian/patches/0002-password-charset.patch new file mode 100644 index 00000000..00badcb3 --- /dev/null +++ b/debian/patches/0002-password-charset.patch @@ -0,0 +1,40 @@ +diff --git a/perl/lib/Wallet/Config.pm b/perl/lib/Wallet/Config.pm +index 60f0e10..66d433f 100644 +--- a/perl/lib/Wallet/Config.pm ++++ b/perl/lib/Wallet/Config.pm +@@ -298,6 +298,15 @@ is run before data is stored. + + our $PWD_LENGTH_MAX = 21; + ++=item PWD_CHARACTERS ++ ++A string that contains valid characters to be used in generating ++passwords. The default is to allow any printable character. ++ ++=cut ++ ++our $PWD_CHARACTERS = ''; ++ + =back + + =head1 KEYTAB OBJECT CONFIGURATION +diff --git a/perl/lib/Wallet/Object/Password.pm b/perl/lib/Wallet/Object/Password.pm +index 336aa9d..f581c18 100644 +--- a/perl/lib/Wallet/Object/Password.pm ++++ b/perl/lib/Wallet/Object/Password.pm +@@ -81,6 +81,15 @@ sub retrieve { + } + my $pass = chars ($Wallet::Config::PWD_LENGTH_MIN, + $Wallet::Config::PWD_LENGTH_MAX); ++ if ($Wallet::Config::PWD_CHARACTERS) { ++ my @pw_chars = (); ++ for (my $i=0; $ilog_action ('store', $user, $host, $time); + unless (close FILE) { diff --git a/debian/patches/0003-checksum.patch b/debian/patches/0003-checksum.patch new file mode 100644 index 00000000..4051957f --- /dev/null +++ b/debian/patches/0003-checksum.patch @@ -0,0 +1,102 @@ +diff --git a/perl/lib/Wallet/Config.pm b/perl/lib/Wallet/Config.pm +index 60f0e10..9efa2cb 100644 +--- a/perl/lib/Wallet/Config.pm ++++ b/perl/lib/Wallet/Config.pm +@@ -1029,6 +1029,25 @@ Obvious improvements could be made, such as checking that the part after + the slash for a C ACL looked like a host name and the part after a + slash for a C 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 +diff --git a/perl/lib/Wallet/Object/File.pm b/perl/lib/Wallet/Object/File.pm +index bef8981..4fc424f 100644 +--- 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 history information. PRINCIPAL + 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 +diff --git a/server/wallet-backend.in b/server/wallet-backend.in +index 8e38460..5e6889c 100644 +--- 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) { diff --git a/debian/patches/0004-news.patch b/debian/patches/0004-news.patch new file mode 100644 index 00000000..2c11c188 --- /dev/null +++ b/debian/patches/0004-news.patch @@ -0,0 +1,24 @@ +diff --git a/NEWS b/NEWS +index be636b4..a5f310b 100644 +--- a/NEWS ++++ b/NEWS +@@ -1,5 +1,19 @@ + User-Visible wallet Changes + ++wallet 1.4-3 (2019-09-30) ++ ++ Two new features have been added to wallet with this release. ++ ++ A valid set of characters to be used when generating a password ++ can be specified. This allows for a variety of password policies ++ include use of only lower case characters, excluding the use of ++ upper case O, etc. ++ ++ The checksum command had been added that returns the checksum of ++ a file object. This makes it simpler to integrate the use of ++ wallet with configuration management systems such as puppet and ++ chef. ++ + wallet 1.4 (2018-06-03) + + Substantial improvements to Active Directory support: Add a diff --git a/debian/patches/series b/debian/patches/series new file mode 100644 index 00000000..72c2420d --- /dev/null +++ b/debian/patches/series @@ -0,0 +1,4 @@ +0001-allow-quilt.patch +0002-password-charset.patch +0003-checksum.patch +0004-news.patch From 89861441ce4817f3e781e812846541c137eda67c Mon Sep 17 00:00:00 2001 From: Bill MacAllister Date: Thu, 10 Oct 2019 22:40:06 +0000 Subject: [PATCH 02/47] Correct the checksum patch --- debian/patches/0003-checksum.patch | 38 +++++++++++++++++++++++------- 1 file changed, 30 insertions(+), 8 deletions(-) diff --git a/debian/patches/0003-checksum.patch b/debian/patches/0003-checksum.patch index 4051957f..514d93a1 100644 --- a/debian/patches/0003-checksum.patch +++ b/debian/patches/0003-checksum.patch @@ -1,8 +1,6 @@ -diff --git a/perl/lib/Wallet/Config.pm b/perl/lib/Wallet/Config.pm -index 60f0e10..9efa2cb 100644 --- a/perl/lib/Wallet/Config.pm +++ b/perl/lib/Wallet/Config.pm -@@ -1029,6 +1029,25 @@ Obvious improvements could be made, such as checking that the part after +@@ -1038,6 +1038,25 @@ Obvious improvements could be made, such the slash for a C ACL looked like a host name and the part after a slash for a C ACL look like a user name. @@ -28,8 +26,6 @@ index 60f0e10..9efa2cb 100644 =head1 ENVIRONMENT =over 4 -diff --git a/perl/lib/Wallet/Object/File.pm b/perl/lib/Wallet/Object/File.pm -index bef8981..4fc424f 100644 --- a/perl/lib/Wallet/Object/File.pm +++ b/perl/lib/Wallet/Object/File.pm @@ -19,6 +19,7 @@ use warnings; @@ -67,7 +63,7 @@ index bef8981..4fc424f 100644 # 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 history information. PRINCIPAL +@@ -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. @@ -81,8 +77,6 @@ index bef8981..4fc424f 100644 =item store(DATA, PRINCIPAL, HOSTNAME [, DATETIME]) Store DATA as the current contents of the file object. Any existing data -diff --git a/server/wallet-backend.in b/server/wallet-backend.in -index 8e38460..5e6889c 100644 --- a/server/wallet-backend.in +++ b/server/wallet-backend.in @@ -196,6 +196,14 @@ sub command { @@ -100,3 +94,31 @@ index 8e38460..5e6889c 100644 } 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 From c330886a95188f9ecfa0f6eeb50e41100a2dd998 Mon Sep 17 00:00:00 2001 From: Bill MacAllister Date: Fri, 11 Oct 2019 00:09:54 +0000 Subject: [PATCH 03/47] Add documentation for checksub command --- debian/patches/0005-checksum-doc.patch | 17 +++++++++++++++++ debian/patches/series | 1 + 2 files changed, 18 insertions(+) create mode 100644 debian/patches/0005-checksum-doc.patch diff --git a/debian/patches/0005-checksum-doc.patch b/debian/patches/0005-checksum-doc.patch new file mode 100644 index 00000000..25cef844 --- /dev/null +++ b/debian/patches/0005-checksum-doc.patch @@ -0,0 +1,17 @@ +--- a/server/wallet-backend.in ++++ b/server/wallet-backend.in +@@ -500,6 +500,14 @@ + Check whether an object of type and name already exists. If + it does, prints C; if not, prints C. + ++=item checksum file|password ++ ++Return the checksum for a file or password object. 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 in ++the wallet configuration file. See perldoc Wallet::Config for ++complete details. ++ + =item comment [] + + If is not given, displays the current comment for the object diff --git a/debian/patches/series b/debian/patches/series index 72c2420d..c0413156 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -2,3 +2,4 @@ 0002-password-charset.patch 0003-checksum.patch 0004-news.patch +0005-checksum-doc.patch From 7a709081131ce8047ed975dbc43b7e46a9efe7f0 Mon Sep 17 00:00:00 2001 From: Bill MacAllister Date: Wed, 8 Jan 2020 19:26:26 +0000 Subject: [PATCH 04/47] Update changelog for encryption support --- debian/changelog | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/debian/changelog b/debian/changelog index 80d70603..fb07186d 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +wallet (1.4-4) unstable; urgency=medium + + * Add support for encrypting file objects. + + -- Bill MacAllister Wed, 08 Jan 2020 19:26:09 +0000 + wallet (1.4-3) unstable; urgency=medium * Allow the specification of valid characters to be used when From 52ebabd8890bd5534879a1418a916eaa639b9bb6 Mon Sep 17 00:00:00 2001 From: Bill MacAllister Date: Wed, 8 Jan 2020 19:30:33 +0000 Subject: [PATCH 05/47] Update debian control with encryption packages --- debian/control | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/debian/control b/debian/control index e70f542f..4b161650 100644 --- a/debian/control +++ b/debian/control @@ -6,6 +6,8 @@ Bugs: mailto:rra@debian.org Build-Depends: debhelper (>= 11), libauthen-sasl-perl, + libcrypt-blowfish-perl, + libcrypt-cbc-perl, libcrypt-generatepassword-perl, libdatetime-format-sqlite-perl, libdatetime-perl, @@ -94,6 +96,8 @@ Recommends: remctl-server (>= 2.14), Suggests: libauthen-sasl-perl, + libcrypt-blowfish-perl, + libcrypt-cbc-perl, libcrypt-generatepassword-perl, libipc-run-perl, libjson-perl, From 1f1c134bb927a9d2379160b90613da6fd93d28c2 Mon Sep 17 00:00:00 2001 From: Bill MacAllister Date: Thu, 9 Jan 2020 01:50:45 +0000 Subject: [PATCH 06/47] Add support for encrypted file objects --- debian/patches/0006-file-crypt.patch | 239 +++++++++++++++++++++++++++ debian/patches/series | 1 + 2 files changed, 240 insertions(+) create mode 100644 debian/patches/0006-file-crypt.patch diff --git a/debian/patches/0006-file-crypt.patch b/debian/patches/0006-file-crypt.patch new file mode 100644 index 00000000..532b3edd --- /dev/null +++ b/debian/patches/0006-file-crypt.patch @@ -0,0 +1,239 @@ +--- a/perl/lib/Wallet/Config.pm ++++ b/perl/lib/Wallet/Config.pm +@@ -765,11 +765,42 @@ with this ACL type. This variable must + + =cut + ++our $LDAP_SECRET; ++ ++=item LDAP_SECRET ++ ++Specifies an LDAP URL that is used to retrieve the secret to use when ++encrypting and decrypting file objects. The url must not include the ++hostname. LDAP_HOST will be used as the hostname to bind to. The ++Kerberos ticket cache specified in LDAP_CACHE is used when connecting ++to the LDAP server. GSS-API authentication is always used; there is ++currently no support for any other type of bind. The ticket cache ++must be for a principal with access to retrieve the secret. This ++variable and LDAP_CACHE must be set to use file object encryption. ++ ++=cut ++ ++our $LDAP_SECRET_PREFIX; ++ ++=item LDAP_SECRET_PREFIX ++ ++Specifies the prefix to be used when generating storing an encrypted ++file object. The prefix is used to determine whether or not a file ++object has been stored encrypted. This allows the gradual transition ++from unencrypted file objects to encrypted file objects. When file ++object encryption is enable any "get" of an unencyrpted file object ++will result in the replacement of the unencrypted object with an ++encrypted object. ++ ++=cut ++ + our $LDAP_CACHE; + + =back + +-Finally, depending on the structure of the LDAP directory being queried, ++=head2 LDAP Principal Mapping ++ ++Depending on the structure of the LDAP directory being queried, + there may not be any attribute in the directory whose value exactly + matches the Kerberos principal. The attribute designated by + LDAP_FILTER_ATTR may instead hold a transformation of the principal name +@@ -794,6 +825,27 @@ Note that this example only removes the + Any principal from some other realm will be left fully qualified, and then + presumably will not be found in the directory. + ++=head2 File Object Encryption ++ ++The default encryption method use is based on the twofish cypher. If ++another encryption method is desired then the perl function file_crypt ++should be defined. The function must accept three parameters: the ++action to preform, the encryption secret, and the string to encrypt or ++decrypt. For example: ++ ++ sub file_crypt { ++ use Crypt::RC4; ++ my ($action, $secret, $string) = @_; ++ ++ my $return_string; ++ if ($action eq 'encrypt') { ++ $return_string = RC4($secret, $string); ++ } elsif ($action eq 'decrypt') { ++ $return_string = RC4($secret, $string); ++ } ++ return $return_string; ++ } ++ + =head1 NETDB ACL CONFIGURATION + + These configuration variables are only needed if you intend to use the +--- a/perl/lib/Wallet/Object/File.pm ++++ b/perl/lib/Wallet/Object/File.pm +@@ -20,6 +20,7 @@ use warnings; + use Digest::MD5 qw(md5_hex); + use File::Copy qw(move); + use File::Slurp; ++use Wallet::ACL::LDAP::Attribute; + use Wallet::Config; + use Wallet::Object::Base; + +@@ -107,6 +108,114 @@ sub rename { + } + + ############################################################################## ++# Encyption and decryption ++############################################################################## ++ ++sub _get_crypt_key { ++ my ($self) = @_; ++ ++ # ldap:///basedn?attr?scope?filter ++ my $url = $Wallet::Config::LDAP_SECRET; ++ $url =~ s{^ldap:///}{}xmsi; ++ if ($url eq $Wallet::Config::LDAP_SECRET) { ++ self->error("ERROR: Invalid LDAP URL $url"); ++ exit 1; ++ } ++ my @parts = split /\?/, $url; ++ my $base = $parts[0]; ++ my $attr = $parts[1]; ++ my $scope = $parts[2]; ++ my $filter = $parts[3]; ++ ++ # Search for the secret in the LDAP directory ++ my $ldap_obj = Wallet::ACL::LDAP::Attribute->new; ++ my $ldap = $ldap_obj->{ldap}; ++ my $entry; ++ eval { ++ my @options = (base => $base, ++ filter => $filter, ++ scope => $scope, ++ attrs => [ $attr ] ++ ); ++ my $search = $ldap->search (@options); ++ if ($search->count == 1) { ++ $entry = $search->pop_entry; ++ } elsif ($search->count > 1) { ++ die 'ERROR: ' . $search->count . " LDAP entries found for $filter"; ++ } else { ++ die "ERROR: No entry found for $url"; ++ } ++ }; ++ if ($@ || !$entry) { ++ die "ERROR: LDAP search failed for $url"; ++ } ++ ++ my $return_val; ++ my $cnt = 0; ++ foreach my $return_attr ($entry->attributes) { ++ if (lc($return_attr) eq lc($attr)) { ++ $return_val = $entry->get_value($return_val); ++ $cnt++; ++ } ++ } ++ if (!$return_val) { ++ die "ERROR: LDAP search failed for $url"; ++ } ++ if ($cnt !=1) { ++ die "ERROR: LDAP search return too many values ($url)"; ++ } ++ return $return_val; ++} ++ ++sub _file_crypt { ++ my ($self, $action, $string) = @_; ++ ++ use Crypt::CBC; ++ use MIME::Base64; ++ ++ my $return_string; ++ my $pre = $Wallet::Config::LDAP_SECRET_PREFIX; ++ my $key = $self->_get_crypt_key(); ++ ++ my $cipher = Crypt::CBC->new( ++ -key => $key, ++ -cipher => 'Twofish', ++ -padding => 'space', ++ -add_header => 1 ++ ); ++ if ($action eq 'encrypt') { ++ $return_string = $pre . encode_base64($cipher->encrypt($string)); ++ } elsif ($action eq 'decrypt') { ++ if ($string =~ s/^$pre//xms) { ++ $return_string = $cipher->decrypt(decode_base64($string)); ++ } else { ++ $return_string = $string; ++ } ++ } else { ++ my $msg = "ERROR: invalid action ($action)\n "; ++ $msg .= "INFO: action must be 'encrypt' or 'decrypt'\n"; ++ $self->error($msg); ++ return; ++ } ++ return $return_string; ++} ++ ++sub _file_decrypt { ++ my ($self, $data, $user, $host, $time) = @_; ++ my $undata = $self->_file_crypt('decrypt', $data); ++ if ($undata eq $data) { ++ $self->store($data, $user, $host, $time) = @_; ++ } ++ return $undata; ++} ++ ++sub _file_encrypt { ++ my ($self, $data) = @_; ++ my $endata = $self->_file_crypt('encrypt', $data); ++ return $endata; ++} ++ ++############################################################################## + # Core methods + ############################################################################## + +@@ -143,6 +253,9 @@ sub get { + $self->error ("cannot get $id: $!"); + return; + } ++ if ($Wallet::LDAP::SECRET) { ++ $data = self->_file_decrypt($user, $host, $time, $data); ++ } + $self->log_action ('get', $user, $host, $time); + return $data; + } +@@ -158,10 +271,17 @@ sub checksum { + } + my $path = $self->file_path; + my $this_checksum; ++ my $this_data; ++ my $this_endata = read_file($path); ++ if ($Wallet::Config::LDAP_SECRET) { ++ $this_data = $self->_file_decrypt($this_endata, $user, $host, $time) ++ } else { ++ $this_data = $this_endata; ++ } + if (defined (&Wallet::Config::file_checksum)) { +- $this_checksum = Wallet::Config::file_checksum($path); ++ $this_checksum = Wallet::Config::file_checksum($this_data); + } else { +- $this_checksum = md5_hex(read_file($path)); ++ $this_checksum = md5_hex($this_data); + } + $self->log_action ('checksum', $user, $host, $time); + return $this_checksum; +@@ -189,6 +309,9 @@ sub store { + $self->error ("cannot store $id: $!"); + return; + } ++ if ($Wallet::Config::LDAP_SECRET) { ++ $data = $self->_file_encrypt($data); ++ } + unless (print FILE ($data) and close FILE) { + $self->error ("cannot store $id: $!"); + close FILE; diff --git a/debian/patches/series b/debian/patches/series index c0413156..634db0cf 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -3,3 +3,4 @@ 0003-checksum.patch 0004-news.patch 0005-checksum-doc.patch +0006-file-crypt.patch From 64db9de40c6212824df4daa26fbfb7fcd77de72c Mon Sep 17 00:00:00 2001 From: Bill MacAllister Date: Tue, 21 Apr 2020 19:27:26 +0000 Subject: [PATCH 07/47] Better class error reporting Patch to make errors invoking a class more descriptive. The errors only happen when there is a reference to a module that does not exist or has not been installed. --- debian/patches/0007-class-error.patch | 30 +++++++++++++++++++++++++++ debian/patches/series | 1 + 2 files changed, 31 insertions(+) create mode 100644 debian/patches/0007-class-error.patch diff --git a/debian/patches/0007-class-error.patch b/debian/patches/0007-class-error.patch new file mode 100644 index 00000000..b62009c1 --- /dev/null +++ b/debian/patches/0007-class-error.patch @@ -0,0 +1,30 @@ +Patch to make errors invoking a class more descriptive. The errors +only happen when there is a reference to a module that does not exist +or has not been installed. + +diff --git a/perl/lib/Wallet/Server.pm b/perl/lib/Wallet/Server.pm +index b0c955c..f4f9f81 100644 +--- a/perl/lib/Wallet/Server.pm ++++ b/perl/lib/Wallet/Server.pm +@@ -103,7 +103,7 @@ sub type_mapping { + if (defined $class) { + eval "require $class"; + if ($@) { +- $self->error ($@); ++ print ($self->error ($@)); + return; + } + } +@@ -508,10 +508,10 @@ sub checksum { + } + my $object = $self->retrieve ($type, $name); + if (!defined $object) { +- return; ++ return; + } + if (!$self->acl_verify ($object, 'get')) { +- return; ++ return; + } + my $result = $object->checksum($self->{user}, $self->{host}); + $self->error ($object->error) unless defined $result; diff --git a/debian/patches/series b/debian/patches/series index 634db0cf..f032677b 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -4,3 +4,4 @@ 0004-news.patch 0005-checksum-doc.patch 0006-file-crypt.patch +0007-class-error.patch From 20ed25b2fca7b45e5f606ae9b92e901aab3e619d Mon Sep 17 00:00:00 2001 From: Bill MacAllister Date: Tue, 21 Apr 2020 23:38:47 +0000 Subject: [PATCH 08/47] Die on invalid LDAP url Make sure that an invalid url error generates output as well as stopping processing. --- debian/patches/0008-invalid-ldap-url.patch | 17 +++++++++++++++++ debian/patches/series | 1 + 2 files changed, 18 insertions(+) create mode 100644 debian/patches/0008-invalid-ldap-url.patch diff --git a/debian/patches/0008-invalid-ldap-url.patch b/debian/patches/0008-invalid-ldap-url.patch new file mode 100644 index 00000000..9ed5ca11 --- /dev/null +++ b/debian/patches/0008-invalid-ldap-url.patch @@ -0,0 +1,17 @@ +Make sure that an invalid url error generates output as well as +stopping processing. + +diff --git a/perl/lib/Wallet/Object/File.pm b/perl/lib/Wallet/Object/File.pm +index e892589..e676759 100644 +--- a/perl/lib/Wallet/Object/File.pm ++++ b/perl/lib/Wallet/Object/File.pm +@@ -118,8 +118,7 @@ sub _get_crypt_key { + my $url = $Wallet::Config::LDAP_SECRET; + $url =~ s{^ldap:///}{}xmsi; + if ($url eq $Wallet::Config::LDAP_SECRET) { +- self->error("ERROR: Invalid LDAP URL $url"); +- exit 1; ++ die("ERROR: Invalid LDAP URL $url"); + } + my @parts = split /\?/, $url; + my $base = $parts[0]; diff --git a/debian/patches/series b/debian/patches/series index f032677b..eb1d75a5 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -5,3 +5,4 @@ 0005-checksum-doc.patch 0006-file-crypt.patch 0007-class-error.patch +0008-invalid-ldap-url.patch From cc1b9532e1b332e6682464bb6f6067d37ab6a132 Mon Sep 17 00:00:00 2001 From: Bill MacAllister Date: Thu, 23 Apr 2020 22:28:22 +0000 Subject: [PATCH 09/47] Require GSSAPI is present when using LDAP * Request the presence of the GSSAPI module is either LDAP ACL support or encrypted object support is enabled. --- debian/changelog | 6 +++++- debian/control | 2 ++ debian/patches/0009-require-perl-gssapi.patch | 17 +++++++++++++++++ debian/patches/series | 1 + 4 files changed, 25 insertions(+), 1 deletion(-) create mode 100644 debian/patches/0009-require-perl-gssapi.patch diff --git a/debian/changelog b/debian/changelog index fb07186d..9cff2e69 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,8 +1,12 @@ wallet (1.4-4) unstable; urgency=medium * Add support for encrypting file objects. + * Update object class error reporting to make it more obvious when + an object is not defined correctly in the wallet database. + * Request the presence of the GSSAPI module is either LDAP ACL + support or encrypted object support is enabled. - -- Bill MacAllister Wed, 08 Jan 2020 19:26:09 +0000 + -- Bill MacAllister Thu, 23 Apr 2020 22:25:13 +0000 wallet (1.4-3) unstable; urgency=medium diff --git a/debian/control b/debian/control index 4b161650..28576347 100644 --- a/debian/control +++ b/debian/control @@ -15,6 +15,7 @@ Build-Depends: libdbi-perl, libdbix-class-perl, libfile-slurp-perl, + libgssapi-perl, libheimdal-kadm5-perl, libipc-run-perl, libjson-perl, @@ -99,6 +100,7 @@ Suggests: libcrypt-blowfish-perl, libcrypt-cbc-perl, libcrypt-generatepassword-perl, + libgssapi-perl, libipc-run-perl, libjson-perl, libnet-duo-perl, diff --git a/debian/patches/0009-require-perl-gssapi.patch b/debian/patches/0009-require-perl-gssapi.patch new file mode 100644 index 00000000..64ff5758 --- /dev/null +++ b/debian/patches/0009-require-perl-gssapi.patch @@ -0,0 +1,17 @@ +If the GSSAPI module is not present on the wallet server LDAP searches +will silently perform anonymous binds to the server. This change means +that when GSSAPI is not present the wallet server will fail when LDAP +lookups are attempted. + +diff --git a/perl/lib/Wallet/ACL/LDAP/Attribute.pm b/perl/lib/Wallet/ACL/LDAP/Attribute.pm +index 65e0208..02948e2 100644 +--- a/perl/lib/Wallet/ACL/LDAP/Attribute.pm ++++ b/perl/lib/Wallet/ACL/LDAP/Attribute.pm +@@ -18,6 +18,7 @@ use strict; + use warnings; + + use Authen::SASL; ++use GSSAPI; + use Net::LDAP qw(LDAP_COMPARE_TRUE); + use Wallet::ACL::Base; + use Wallet::Config; diff --git a/debian/patches/series b/debian/patches/series index eb1d75a5..20bf4691 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -6,3 +6,4 @@ 0006-file-crypt.patch 0007-class-error.patch 0008-invalid-ldap-url.patch +0009-require-perl-gssapi.patch \ No newline at end of file From ab7d7bb5806adf15939d538ba9080ce4e6c835de Mon Sep 17 00:00:00 2001 From: Bill MacAllister Date: Fri, 24 Apr 2020 07:14:58 +0000 Subject: [PATCH 10/47] Armor encrypt store, syntax fixes * Encypt the data before attempting any of the actual storage of file objects. * Die immediately on any errors retrieving the encryption secret. * Correct reference to LDAP_SECRET. * Correct arguments passed to _file_decrypt. --- debian/patches/0010-empty-store.patch | 110 ++++++++++++++++++++++++++ debian/patches/series | 3 +- 2 files changed, 112 insertions(+), 1 deletion(-) create mode 100644 debian/patches/0010-empty-store.patch diff --git a/debian/patches/0010-empty-store.patch b/debian/patches/0010-empty-store.patch new file mode 100644 index 00000000..181dfd5c --- /dev/null +++ b/debian/patches/0010-empty-store.patch @@ -0,0 +1,110 @@ +Armor encrypt store, syntax fixes + +* Encypt the data before attempting any of the actual storage of + file objects. +* Die immediately on any errors retrieving the encryption secret. +* Correct reference to LDAP_SECRET. +* Correct arguments passed to _file_decrypt. + +diff --git a/perl/lib/Wallet/Object/File.pm b/perl/lib/Wallet/Object/File.pm +index e676759..d49eef8 100644 +--- a/perl/lib/Wallet/Object/File.pm ++++ b/perl/lib/Wallet/Object/File.pm +@@ -145,23 +145,29 @@ sub _get_crypt_key { + die "ERROR: No entry found for $url"; + } + }; +- if ($@ || !$entry) { +- die "ERROR: LDAP search failed for $url"; ++ if ($@) { ++ die "INFO: LDAP search failed using $url\n" ++ . "ERROR: $@"; ++ } ++ if (!$entry) { ++ die "ERROR: No entry returned for LDAP search using $url"; + } + + my $return_val; + my $cnt = 0; + foreach my $return_attr ($entry->attributes) { +- if (lc($return_attr) eq lc($attr)) { +- $return_val = $entry->get_value($return_val); ++ if ($return_attr =~ /^$attr$/xmsi) { ++ $return_val = $entry->get_value($attr); ++ last; + $cnt++; + } + } + if (!$return_val) { +- die "ERROR: LDAP search failed for $url"; ++ die "ERROR: Attribute not found $url"; + } +- if ($cnt !=1) { +- die "ERROR: LDAP search return too many values ($url)"; ++ if ($cnt > 0) { ++ my $obj_cnt = $cnt + 1; ++ die "ERROR: LDAP search return too many values ($obj_cnt) for $url"; + } + return $return_val; + } +@@ -185,7 +191,9 @@ sub _file_crypt { + if ($action eq 'encrypt') { + $return_string = $pre . encode_base64($cipher->encrypt($string)); + } elsif ($action eq 'decrypt') { +- if ($string =~ s/^$pre//xms) { ++ my $pre_regex = $pre; ++ $pre_regex =~ s/(\W)/\\$1/g; ++ if ($string =~ s/^$pre_regex//xms) { + $return_string = $cipher->decrypt(decode_base64($string)); + } else { + $return_string = $string; +@@ -193,8 +201,7 @@ sub _file_crypt { + } else { + my $msg = "ERROR: invalid action ($action)\n "; + $msg .= "INFO: action must be 'encrypt' or 'decrypt'\n"; +- $self->error($msg); +- return; ++ die $msg; + } + return $return_string; + } +@@ -203,7 +210,7 @@ sub _file_decrypt { + my ($self, $data, $user, $host, $time) = @_; + my $undata = $self->_file_crypt('decrypt', $data); + if ($undata eq $data) { +- $self->store($data, $user, $host, $time) = @_; ++ $self->store($data, $user, $host, $time); + } + return $undata; + } +@@ -251,8 +258,8 @@ sub get { + $self->error ("cannot get $id: $!"); + return; + } +- if ($Wallet::LDAP::SECRET) { +- $data = self->_file_decrypt($user, $host, $time, $data); ++ if ($Wallet::Config::LDAP_SECRET) { ++ $data = $self->_file_decrypt($data, $user, $host, $time); + } + $self->log_action ('get', $user, $host, $time); + return $data; +@@ -301,15 +308,16 @@ sub store { + return; + } + } ++ if ($Wallet::Config::LDAP_SECRET) { ++ $data = $self->_file_encrypt($data); ++ } ++ + my $path = $self->file_path; + return unless $path; + unless (open (FILE, '>', $path)) { + $self->error ("cannot store $id: $!"); + return; + } +- if ($Wallet::Config::LDAP_SECRET) { +- $data = $self->_file_encrypt($data); +- } + unless (print FILE ($data) and close FILE) { + $self->error ("cannot store $id: $!"); + close FILE; diff --git a/debian/patches/series b/debian/patches/series index 20bf4691..f974812d 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -6,4 +6,5 @@ 0006-file-crypt.patch 0007-class-error.patch 0008-invalid-ldap-url.patch -0009-require-perl-gssapi.patch \ No newline at end of file +0009-require-perl-gssapi.patch +0010-empty-store.patch From d11539d43a4f85a9ffc5264caf422303de1eb3d4 Mon Sep 17 00:00:00 2001 From: Bill MacAllister Date: Fri, 24 Apr 2020 21:45:41 +0000 Subject: [PATCH 11/47] Mark source as UNRELEASED --- debian/changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/changelog b/debian/changelog index 9cff2e69..24ec6b2f 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,4 +1,4 @@ -wallet (1.4-4) unstable; urgency=medium +wallet (1.4-4) UNRELEASED; urgency=medium * Add support for encrypting file objects. * Update object class error reporting to make it more obvious when From 4afad0a9a2faadc8cd03667184188cbddbc935a2 Mon Sep 17 00:00:00 2001 From: Bill MacAllister Date: Sat, 25 Apr 2020 23:42:45 +0000 Subject: [PATCH 12/47] Minor changes to the documentation Wallet client man page * Add the checksum command * Add acl add examples --- debian/patches/0011-doc.patch | 168 ++++++++++++++++++++++++++++++++++ debian/patches/series | 1 + 2 files changed, 169 insertions(+) create mode 100644 debian/patches/0011-doc.patch diff --git a/debian/patches/0011-doc.patch b/debian/patches/0011-doc.patch new file mode 100644 index 00000000..3f4e41fa --- /dev/null +++ b/debian/patches/0011-doc.patch @@ -0,0 +1,168 @@ +Minor changes to the documentation + +Wallet client man page +* Add the checksum command +* Add acl add examples + +Update documentation for Object encryption in Config.pm +--- a/client/wallet.pod ++++ b/client/wallet.pod +@@ -181,7 +181,13 @@ For more information on attributes, see + =item acl add + + Add an entry with and to the ACL . may be +-either the name of an ACL or its numeric identifier. ++either the name of an ACL or its numeric identifier. Three schemes are ++supported: krb5, netdb, and ldap-attr. The netdb and ldap-attr must ++be configured before they can be used. Examples: ++ ++ wallet acl add config/db krb5 mac@CA-ZEPHYR.ORG ++ wallet acl add config/db netdb host/keddie.ca-zephyr.org ++ wallet acl add config/db ldap-attr czPrivilegeGroup=admin + + =item acl check + +@@ -257,6 +263,10 @@ already exist. + Check whether an object of type and name already exists. If + it does, prints C; if not, prints C. + ++=item checksum ++ ++Returns the checksum for file objects. ++ + =item comment [] + + If is not given, displays the current comment for the object +@@ -390,7 +400,7 @@ will attempt to automatically create it + + Prints to standard output the data associated with the object identified + by and , or stores it in a file if the B<-f> option was +-given. This will generate new data in the object, and only works for ++given. This will generate new data in the object, and only works for + objects that support generating new data automatically, such as keytabs or + passwords. Types that do not support generating new data will fail and + direct you to use get instead. +--- a/perl/lib/Wallet/Config.pm ++++ b/perl/lib/Wallet/Config.pm +@@ -723,6 +723,9 @@ specify the LDAP server and additional c + information required for the wallet to check for the existence of + attributes. + ++The format for specifying an LDAP ACL is "acl-attr "" ++where a simple filter is of the form "attribute=value". ++ + =over 4 + + =item LDAP_HOST +@@ -765,35 +768,6 @@ with this ACL type. This variable must + + =cut + +-our $LDAP_SECRET; +- +-=item LDAP_SECRET +- +-Specifies an LDAP URL that is used to retrieve the secret to use when +-encrypting and decrypting file objects. The url must not include the +-hostname. LDAP_HOST will be used as the hostname to bind to. The +-Kerberos ticket cache specified in LDAP_CACHE is used when connecting +-to the LDAP server. GSS-API authentication is always used; there is +-currently no support for any other type of bind. The ticket cache +-must be for a principal with access to retrieve the secret. This +-variable and LDAP_CACHE must be set to use file object encryption. +- +-=cut +- +-our $LDAP_SECRET_PREFIX; +- +-=item LDAP_SECRET_PREFIX +- +-Specifies the prefix to be used when generating storing an encrypted +-file object. The prefix is used to determine whether or not a file +-object has been stored encrypted. This allows the gradual transition +-from unencrypted file objects to encrypted file objects. When file +-object encryption is enable any "get" of an unencyrpted file object +-will result in the replacement of the unencrypted object with an +-encrypted object. +- +-=cut +- + our $LDAP_CACHE; + + =back +@@ -825,13 +799,48 @@ Note that this example only removes the + Any principal from some other realm will be left fully qualified, and then + presumably will not be found in the directory. + +-=head2 File Object Encryption ++=head1 FILE OBJECT ENCRYPTION ++ ++=over 4 ++ ++=item LDAP_SECRET ++ ++Specifies an LDAP URL that is used to retrieve the secret to use when ++encrypting and decrypting file objects. The url must not include the ++hostname. LDAP_HOST will be used as the hostname to bind to. The ++Kerberos ticket cache specified in LDAP_CACHE is used when connecting ++to the LDAP server. GSS-API authentication is always used; there is ++currently no support for any other type of bind. The ticket cache ++must be for a principal with access to retrieve the secret. This ++variable and LDAP_CACHE must be set to use file object encryption. ++ ++=cut ++ ++our $LDAP_SECRET; ++ ++=item LDAP_SECRET_PREFIX + +-The default encryption method use is based on the twofish cypher. If ++Specifies the prefix to be used when generating storing an encrypted ++file object. The prefix is used to determine whether or not a file ++object has been stored encrypted. This allows the gradual transition ++from unencrypted file objects to encrypted file objects. When file ++object encryption is enable any "get" of an unencyrpted file object ++will result in the replacement of the unencrypted object with an ++encrypted object. ++ ++=cut ++ ++our $LDAP_SECRET_PREFIX; ++ ++=item file_crypt; ++ ++This functionality has not been implmented yet. ++ ++The default encryption method is based on the twofish cypher. If + another encryption method is desired then the perl function file_crypt +-should be defined. The function must accept three parameters: the +-action to preform, the encryption secret, and the string to encrypt or +-decrypt. For example: ++should be defined in the configuration file. The function must accept ++three parameters: the action to preform, the encryption secret, and ++the string to encrypt or decrypt. For example: + + sub file_crypt { + use Crypt::RC4; +@@ -846,6 +855,21 @@ decrypt. For example: + return $return_string; + } + ++=item file_crypt_secret ++ ++This functionality has not been implmented yet. ++ ++The default method use is based on the twofish cypher. If another ++method of retrieving a secret is desired then the perl function ++file_crypt_secret should be defined. The function accepts no ++parameters and returns the secret to be used. For example: ++ ++ sub file_crypt_secret { ++ return "thisIsABadIdea"; ++ } ++ ++=back ++ + =head1 NETDB ACL CONFIGURATION + + These configuration variables are only needed if you intend to use the diff --git a/debian/patches/series b/debian/patches/series index f974812d..f0f594c0 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -8,3 +8,4 @@ 0008-invalid-ldap-url.patch 0009-require-perl-gssapi.patch 0010-empty-store.patch +0011-doc.patch From b30d10a43093ab98e572c1adef286bca56c8a585 Mon Sep 17 00:00:00 2001 From: Bill MacAllister Date: Sun, 26 Apr 2020 00:36:12 +0000 Subject: [PATCH 13/47] Update changelog for package release --- debian/changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/changelog b/debian/changelog index 24ec6b2f..9cff2e69 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,4 +1,4 @@ -wallet (1.4-4) UNRELEASED; urgency=medium +wallet (1.4-4) unstable; urgency=medium * Add support for encrypting file objects. * Update object class error reporting to make it more obvious when From dd8dc4cda960f1eeb282488318a716037ea5e88f Mon Sep 17 00:00:00 2001 From: Bill MacAllister Date: Tue, 19 May 2020 00:56:18 +0000 Subject: [PATCH 14/47] Add password generation options Add password generation options supporting generation of password using selected Crypt::HSXKPasswd presets or a custom routine. --- debian/changelog | 7 ++ debian/patches/0012-pwd-options.patch | 127 ++++++++++++++++++++++++++ debian/patches/series | 1 + 3 files changed, 135 insertions(+) create mode 100644 debian/patches/0012-pwd-options.patch diff --git a/debian/changelog b/debian/changelog index 9cff2e69..3fcbc0a8 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,10 @@ +wallet (1.4-5) unstable; urgency=medium + + * Add password generation options supporting generation of password + using selected Crypt::HSXKPasswd presets or a custom routine. + + -- Bill MacAllister Tue, 19 May 2020 00:55:32 +0000 + wallet (1.4-4) unstable; urgency=medium * Add support for encrypting file objects. diff --git a/debian/patches/0012-pwd-options.patch b/debian/patches/0012-pwd-options.patch new file mode 100644 index 00000000..67f362c6 --- /dev/null +++ b/debian/patches/0012-pwd-options.patch @@ -0,0 +1,127 @@ +--- a/perl/lib/Wallet/Config.pm ++++ b/perl/lib/Wallet/Config.pm +@@ -266,6 +266,27 @@ that is inherited. + + =over 4 + ++=item PWD_TYPE ++ ++Specifies the algorithm to use when generating a password. The default is ++to select a random set of printable ASCII characters. The pool of characters ++can be restricted by specifying PWD_CHARACTERS. This form of password ++generation can be explicitly requested by specifying RANDOM. ++ ++The PWD_TYPE can be used to specify the generation of passwords using ++the XKCD inspired perl module Crypt::HSXKPasswd. Three values are ++supported that use preset configuration values: XKCD-DEFAULT, ++XKCD-APPLIED, and XKCD. See the module documentation for the details ++of these presents. ++ ++A PWD_TYPE of CUSTOM is supported. If defined then the configuration ++file must contain a Perl function generate_password that returns a ++generated password. ++ ++=cut ++ ++our $PWD_TYPE; ++ + =item PWD_FILE_BUCKET + + The directory into which to store password objects. Password objects will +@@ -274,7 +295,7 @@ L for the full + directory must be writable by the wallet server and the wallet server must + be able to create subdirectories of it. + +-PWD_FILE_BUCKET must be set to use file objects. ++PWD_FILE_BUCKET must be set to use password objects. + + =cut + +--- a/perl/lib/Wallet/Object/Password.pm ++++ b/perl/lib/Wallet/Object/Password.pm +@@ -52,6 +52,38 @@ sub file_path { + return "$Wallet::Config::PWD_FILE_BUCKET/$hash/$name"; + } + ++# Returns a password of random characters. ++sub _pwd_random { ++ my ($self) = @_; ++ my $pass = chars ($Wallet::Config::PWD_LENGTH_MIN, ++ $Wallet::Config::PWD_LENGTH_MAX); ++ if ($Wallet::Config::PWD_CHARACTERS) { ++ my @pw_chars = (); ++ for (my $i=0; $inew(preset => $preset); ++ my $pass = $hsxkpasswd_instance->password(); ++ return $pass; ++} ++ + ############################################################################## + # Shared methods + ############################################################################## +@@ -75,20 +107,34 @@ sub retrieve { + ob_name => $self->{name}); + my $object = $schema->resultset('Object')->find (\%search); + if (!$object->ob_stored_on || $operation eq 'update') { +- unless (open (FILE, '>', $path)) { +- $self->error ("cannot store initial settings for $id: $!\n"); +- return; ++ my $pass; ++ if (not $Wallet::Config::PWD_TYPE ++ || $Wallet::Config::PWD_TYPE eq 'RANDOM') ++ { ++ $pass = $self->_pwd_random(); + } +- my $pass = chars ($Wallet::Config::PWD_LENGTH_MIN, +- $Wallet::Config::PWD_LENGTH_MAX); +- if ($Wallet::Config::PWD_CHARACTERS) { +- my @pw_chars = (); +- for (my $i=0; $i_pwd_xkcd($1); ++ } ++ elsif ($Wallet::Config::PWD_TYPE eq 'CUSTOM') ++ { ++ if (defined(&Wallet::Config::generate_password)) { ++ $pass = Wallet::Config::generate_password(); ++ } else { ++ $self->error ("function generate_password() not found\n"); ++ return; + } +- $pass = chars ($Wallet::Config::PWD_LENGTH_MIN, +- $Wallet::Config::PWD_LENGTH_MAX, +- \@pw_chars); ++ } ++ else ++ { ++ $self->error ("Unknown PWD_TYPE ($Wallet::Config::PWD_TYPE )\n"); ++ return; ++ } ++ unless (open (FILE, '>', $path)) { ++ $self->error ("cannot open $path $!\n"); ++ return; + } + print FILE $pass; + $self->log_action ('store', $user, $host, $time); diff --git a/debian/patches/series b/debian/patches/series index f0f594c0..23724c22 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -9,3 +9,4 @@ 0009-require-perl-gssapi.patch 0010-empty-store.patch 0011-doc.patch +0012-pwd-options.patch From a961f24946b790c11d891867d56f3255ff76c5d3 Mon Sep 17 00:00:00 2001 From: Bill MacAllister Date: Fri, 22 May 2020 21:47:22 +0000 Subject: [PATCH 15/47] Update handling of PWD_TYPE Explicitly set PWD_TYPE in the configuation file to prevent "unassigned variable warnings". --- debian/patches/0012-pwd-options.patch | 41 ++++++++++++++------------- 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/debian/patches/0012-pwd-options.patch b/debian/patches/0012-pwd-options.patch index 67f362c6..71045274 100644 --- a/debian/patches/0012-pwd-options.patch +++ b/debian/patches/0012-pwd-options.patch @@ -6,10 +6,10 @@ +=item PWD_TYPE + -+Specifies the algorithm to use when generating a password. The default is -+to select a random set of printable ASCII characters. The pool of characters -+can be restricted by specifying PWD_CHARACTERS. This form of password -+generation can be explicitly requested by specifying RANDOM. ++Specifies the algorithm to use when generating a password. The ++default is RANDOM which specified that random set of printable ASCII ++characters will be used to create a password. The pool of characters ++can be restricted by specifying PWD_CHARACTERS. + +The PWD_TYPE can be used to specify the generation of passwords using +the XKCD inspired perl module Crypt::HSXKPasswd. Three values are @@ -23,7 +23,7 @@ + +=cut + -+our $PWD_TYPE; ++our $PWD_TYPE = 'RANDOM'; + =item PWD_FILE_BUCKET @@ -78,7 +78,7 @@ ############################################################################## # Shared methods ############################################################################## -@@ -75,20 +107,34 @@ sub retrieve { +@@ -75,20 +107,37 @@ sub retrieve { ob_name => $self->{name}); my $object = $schema->resultset('Object')->find (\%search); if (!$object->ob_stored_on || $operation eq 'update') { @@ -86,17 +86,10 @@ - $self->error ("cannot store initial settings for $id: $!\n"); - return; + my $pass; -+ if (not $Wallet::Config::PWD_TYPE -+ || $Wallet::Config::PWD_TYPE eq 'RANDOM') ++ if ($Wallet::Config::PWD_TYPE eq 'RANDOM') + { + $pass = $self->_pwd_random(); - } -- my $pass = chars ($Wallet::Config::PWD_LENGTH_MIN, -- $Wallet::Config::PWD_LENGTH_MAX); -- if ($Wallet::Config::PWD_CHARACTERS) { -- my @pw_chars = (); -- for (my $i=0; $ierror ("function generate_password() not found\n"); + return; ++ } + } +- my $pass = chars ($Wallet::Config::PWD_LENGTH_MIN, +- $Wallet::Config::PWD_LENGTH_MAX); +- if ($Wallet::Config::PWD_CHARACTERS) { +- my @pw_chars = (); +- for (my $i=0; $ierror ("Unknown PWD_TYPE ($Wallet::Config::PWD_TYPE)\n"); ++ } else { ++ $self->error ("PWD_TYPE not set\n"); } - $pass = chars ($Wallet::Config::PWD_LENGTH_MIN, - $Wallet::Config::PWD_LENGTH_MAX, - \@pw_chars); -+ } -+ else -+ { -+ $self->error ("Unknown PWD_TYPE ($Wallet::Config::PWD_TYPE )\n"); + return; + } + unless (open (FILE, '>', $path)) { From bb937246b12166835ca03ec095ece7f51606e655 Mon Sep 17 00:00:00 2001 From: Bill MacAllister Date: Fri, 22 May 2020 23:21:39 +0000 Subject: [PATCH 16/47] Correct parsing of PWD_TYPE --- debian/patches/0012-pwd-options.patch | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/patches/0012-pwd-options.patch b/debian/patches/0012-pwd-options.patch index 71045274..659112be 100644 --- a/debian/patches/0012-pwd-options.patch +++ b/debian/patches/0012-pwd-options.patch @@ -91,7 +91,7 @@ + $pass = $self->_pwd_random(); + } + elsif ($Wallet::Config::PWD_TYPE -+ =~ /^XKCD(\-APPLIED|\-DEFAULT{0,1})/xms) ++ =~ /^XKCD(\-APPLIED|\-DEFAULT){0,1}/xms) + { + $pass = $self->_pwd_xkcd($1); + } From 50b1f204e5efc70aaa6b4a60ff73863336389cd9 Mon Sep 17 00:00:00 2001 From: Bill MacAllister Date: Sat, 23 May 2020 00:20:00 +0000 Subject: [PATCH 17/47] Add encryption to password objects --- debian/patches/0013-crypt-fixup.patch | 117 ++++++++++++++++++++++++++ debian/patches/series | 1 + 2 files changed, 118 insertions(+) create mode 100644 debian/patches/0013-crypt-fixup.patch diff --git a/debian/patches/0013-crypt-fixup.patch b/debian/patches/0013-crypt-fixup.patch new file mode 100644 index 00000000..8d0ed99c --- /dev/null +++ b/debian/patches/0013-crypt-fixup.patch @@ -0,0 +1,117 @@ +--- a/perl/lib/Wallet/Object/File.pm ++++ b/perl/lib/Wallet/Object/File.pm +@@ -175,8 +175,8 @@ sub _get_crypt_key { + sub _file_crypt { + my ($self, $action, $string) = @_; + +- use Crypt::CBC; +- use MIME::Base64; ++ require Crypt::CBC; ++ require MIME::Base64; + + my $return_string; + my $pre = $Wallet::Config::LDAP_SECRET_PREFIX; +@@ -189,12 +189,14 @@ sub _file_crypt { + -add_header => 1 + ); + if ($action eq 'encrypt') { +- $return_string = $pre . encode_base64($cipher->encrypt($string)); ++ $return_string ++ = $pre . MIME::Base64::encode_base64($cipher->encrypt($string)); + } elsif ($action eq 'decrypt') { + my $pre_regex = $pre; + $pre_regex =~ s/(\W)/\\$1/g; + if ($string =~ s/^$pre_regex//xms) { +- $return_string = $cipher->decrypt(decode_base64($string)); ++ $return_string ++ = $cipher->decrypt(MIME::Base64::decode_base64($string)); + } else { + $return_string = $string; + } +@@ -206,7 +208,7 @@ sub _file_crypt { + return $return_string; + } + +-sub _file_decrypt { ++sub file_decrypt { + my ($self, $data, $user, $host, $time) = @_; + my $undata = $self->_file_crypt('decrypt', $data); + if ($undata eq $data) { +@@ -215,7 +217,7 @@ sub _file_decrypt { + return $undata; + } + +-sub _file_encrypt { ++sub file_encrypt { + my ($self, $data) = @_; + my $endata = $self->_file_crypt('encrypt', $data); + return $endata; +@@ -259,7 +261,7 @@ sub get { + return; + } + if ($Wallet::Config::LDAP_SECRET) { +- $data = $self->_file_decrypt($data, $user, $host, $time); ++ $data = $self->file_decrypt($data, $user, $host, $time); + } + $self->log_action ('get', $user, $host, $time); + return $data; +@@ -279,7 +281,7 @@ sub checksum { + my $this_data; + my $this_endata = read_file($path); + if ($Wallet::Config::LDAP_SECRET) { +- $this_data = $self->_file_decrypt($this_endata, $user, $host, $time) ++ $this_data = $self->file_decrypt($this_endata, $user, $host, $time) + } else { + $this_data = $this_endata; + } +@@ -309,7 +311,7 @@ sub store { + } + } + if ($Wallet::Config::LDAP_SECRET) { +- $data = $self->_file_encrypt($data); ++ $data = $self->file_encrypt($data); + } + + my $path = $self->file_path; +--- a/perl/lib/Wallet/Object/Password.pm ++++ b/perl/lib/Wallet/Object/Password.pm +@@ -122,16 +122,16 @@ sub retrieve { + if (defined(&Wallet::Config::generate_password)) { + $pass = Wallet::Config::generate_password(); + } else { +- $self->error ("function generate_password() not found\n"); ++ $self->error("function generate_password() not found\n"); + return; + } + } + else + { + if (defined($Wallet::Config::PWD_TYPE)) { +- $self->error ("Unknown PWD_TYPE ($Wallet::Config::PWD_TYPE)\n"); ++ $self->error("Unknown PWD_TYPE ($Wallet::Config::PWD_TYPE)\n"); + } else { +- $self->error ("PWD_TYPE not set\n"); ++ $self->error("PWD_TYPE not set\n"); + } + return; + } +@@ -139,6 +139,9 @@ sub retrieve { + $self->error ("cannot open $path $!\n"); + return; + } ++ if ($Wallet::Config::LDAP_SECRET) { ++ $pass = Wallet::Object::File->file_encrypt($pass); ++ } + print FILE $pass; + $self->log_action ('store', $user, $host, $time); + unless (close FILE) { +@@ -158,6 +161,9 @@ sub retrieve { + return; + } + $self->log_action ($operation, $user, $host, $time); ++ if ($Wallet::Config::LDAP_SECRET) { ++ $data = Wallet::Object::File->file_decrypt($data); ++ } + return $data; + } + diff --git a/debian/patches/series b/debian/patches/series index 23724c22..807f0545 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -10,3 +10,4 @@ 0010-empty-store.patch 0011-doc.patch 0012-pwd-options.patch +0013-crypt-fixup.patch From 5cf33a72bb0b24ec7daaaabbb7f0ea4ca9f3f485 Mon Sep 17 00:00:00 2001 From: Bill MacAllister Date: Sat, 23 May 2020 01:13:44 +0000 Subject: [PATCH 18/47] Update config documentation for custom encryption --- debian/patches/series | 1 + 1 file changed, 1 insertion(+) diff --git a/debian/patches/series b/debian/patches/series index 807f0545..ce977f4f 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -11,3 +11,4 @@ 0011-doc.patch 0012-pwd-options.patch 0013-crypt-fixup.patch +0014-crypt-custom.patch From 6964ef7c4886fe7299f6cca26149e87e188ee84d Mon Sep 17 00:00:00 2001 From: Bill MacAllister Date: Sat, 23 May 2020 01:16:13 +0000 Subject: [PATCH 19/47] Update the change log with the current work --- debian/changelog | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/debian/changelog b/debian/changelog index 3fcbc0a8..7dfecb67 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,9 +1,11 @@ -wallet (1.4-5) unstable; urgency=medium +wallet (1.4-5) UNRELEASED; urgency=medium * Add password generation options supporting generation of password using selected Crypt::HSXKPasswd presets or a custom routine. + * Add encryption of password objects. + * Add support for custom encryption methods. - -- Bill MacAllister Tue, 19 May 2020 00:55:32 +0000 + -- Bill MacAllister Sat, 23 May 2020 01:15:25 +0000 wallet (1.4-4) unstable; urgency=medium From cc770a089851adefd2590bce7c1d41be5c771ca3 Mon Sep 17 00:00:00 2001 From: Bill MacAllister Date: Sat, 23 May 2020 01:17:09 +0000 Subject: [PATCH 20/47] Add the custom encryption patch --- debian/patches/0014-crypt-custom.patch | 83 ++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) create mode 100644 debian/patches/0014-crypt-custom.patch diff --git a/debian/patches/0014-crypt-custom.patch b/debian/patches/0014-crypt-custom.patch new file mode 100644 index 00000000..74f98efd --- /dev/null +++ b/debian/patches/0014-crypt-custom.patch @@ -0,0 +1,83 @@ +--- a/perl/lib/Wallet/Config.pm ++++ b/perl/lib/Wallet/Config.pm +@@ -853,42 +853,6 @@ encrypted object. + + our $LDAP_SECRET_PREFIX; + +-=item file_crypt; +- +-This functionality has not been implmented yet. +- +-The default encryption method is based on the twofish cypher. If +-another encryption method is desired then the perl function file_crypt +-should be defined in the configuration file. The function must accept +-three parameters: the action to preform, the encryption secret, and +-the string to encrypt or decrypt. For example: +- +- sub file_crypt { +- use Crypt::RC4; +- my ($action, $secret, $string) = @_; +- +- my $return_string; +- if ($action eq 'encrypt') { +- $return_string = RC4($secret, $string); +- } elsif ($action eq 'decrypt') { +- $return_string = RC4($secret, $string); +- } +- return $return_string; +- } +- +-=item file_crypt_secret +- +-This functionality has not been implmented yet. +- +-The default method use is based on the twofish cypher. If another +-method of retrieving a secret is desired then the perl function +-file_crypt_secret should be defined. The function accepts no +-parameters and returns the secret to be used. For example: +- +- sub file_crypt_secret { +- return "thisIsABadIdea"; +- } +- + =back + + =head1 NETDB ACL CONFIGURATION +@@ -1154,6 +1118,37 @@ as a base64 string. + return $cs; + } + ++=head1 ENCRYPTION METHODS ++ ++The default encryption method is based on the twofish cypher. If ++another encryption method is desired then the perl function file_crypt ++should be defined in the configuration file. The function must accept ++three parameters: the action to preform, the encryption secret, and ++the string to encrypt or decrypt. For example: ++ ++ sub file_crypt { ++ use Crypt::RC4; ++ my ($action, $secret, $string) = @_; ++ ++ my $return_string; ++ if ($action eq 'encrypt') { ++ $return_string = RC4($secret, $string); ++ } elsif ($action eq 'decrypt') { ++ $return_string = RC4($secret, $string); ++ } ++ return $return_string; ++ } ++ ++The default method for retrieving the secret used to encryption ++operations is retrieved from an LDAP server. If another method of ++retrieving a secret is desired then the perl function ++file_crypt_secret should be defined. The function accepts no ++parameters and returns the secret to be used. For example: ++ ++ sub file_crypt_secret { ++ return "thisIsABadIdea"; ++ } ++ + =head1 ENVIRONMENT + + =over 4 From 96af9e54d712343a6c0cb9099e6188543e8d7b8d Mon Sep 17 00:00:00 2001 From: Bill MacAllister Date: Sat, 23 May 2020 23:14:53 +0000 Subject: [PATCH 21/47] Implement custom file_crypt and file_crypt_key support Makes changes to allow encryption to overridden by sepcifying routines in the configuration file. Update Config.pm with a working example of an alternate configuration method. --- debian/patches/0014-crypt-custom.patch | 151 +++++++++++++++++++++++-- 1 file changed, 139 insertions(+), 12 deletions(-) diff --git a/debian/patches/0014-crypt-custom.patch b/debian/patches/0014-crypt-custom.patch index 74f98efd..e900ed8a 100644 --- a/debian/patches/0014-crypt-custom.patch +++ b/debian/patches/0014-crypt-custom.patch @@ -1,6 +1,46 @@ --- a/perl/lib/Wallet/Config.pm +++ b/perl/lib/Wallet/Config.pm -@@ -853,42 +853,6 @@ encrypted object. +@@ -791,39 +791,6 @@ with this ACL type. This variable must + + our $LDAP_CACHE; + +-=back +- +-=head2 LDAP Principal Mapping +- +-Depending on the structure of the LDAP directory being queried, +-there may not be any attribute in the directory whose value exactly +-matches the Kerberos principal. The attribute designated by +-LDAP_FILTER_ATTR may instead hold a transformation of the principal name +-(such as the principal with the local realm stripped off, or rewritten +-into an LDAP DN form). If this is the case, define a Perl function named +-ldap_map_principal. This function will be called whenever an LDAP +-attribute ACL is being verified. It will take one argument, the +-principal, and is expected to return the value to search for in the LDAP +-directory server. +- +-For example, if the principal name without the local realm is stored in +-the C attribute in the directory, set LDAP_FILTER_ATTR to C and +-then define ldap_map_attribute as follows: +- +- sub ldap_map_principal { +- my ($principal) = @_; +- $principal =~ s/\@EXAMPLE\.COM$//; +- return $principal; +- } +- +-Note that this example only removes the local realm (here, EXAMPLE.COM). +-Any principal from some other realm will be left fully qualified, and then +-presumably will not be found in the directory. +- +-=head1 FILE OBJECT ENCRYPTION +- +-=over 4 +- + =item LDAP_SECRET + + Specifies an LDAP URL that is used to retrieve the secret to use when +@@ -853,43 +820,34 @@ encrypted object. our $LDAP_SECRET_PREFIX; @@ -26,24 +66,47 @@ - } - return $return_string; - } -- ++=back + -=item file_crypt_secret -- ++=head2 LDAP Principal Mapping + -This functionality has not been implmented yet. -- ++Depending on the structure of the LDAP directory being queried, ++there may not be any attribute in the directory whose value exactly ++matches the Kerberos principal. The attribute designated by ++LDAP_FILTER_ATTR may instead hold a transformation of the principal name ++(such as the principal with the local realm stripped off, or rewritten ++into an LDAP DN form). If this is the case, define a Perl function named ++ldap_map_principal. This function will be called whenever an LDAP ++attribute ACL is being verified. It will take one argument, the ++principal, and is expected to return the value to search for in the LDAP ++directory server. + -The default method use is based on the twofish cypher. If another -method of retrieving a secret is desired then the perl function -file_crypt_secret should be defined. The function accepts no -parameters and returns the secret to be used. For example: -- ++For example, if the principal name without the local realm is stored in ++the C attribute in the directory, set LDAP_FILTER_ATTR to C and ++then define ldap_map_attribute as follows: + - sub file_crypt_secret { - return "thisIsABadIdea"; -- } -- - =back ++ sub ldap_map_principal { ++ my ($principal) = @_; ++ $principal =~ s/\@EXAMPLE\.COM$//; ++ return $principal; + } + +-=back ++Note that this example only removes the local realm (here, EXAMPLE.COM). ++Any principal from some other realm will be left fully qualified, and then ++presumably will not be found in the directory. =head1 NETDB ACL CONFIGURATION -@@ -1154,6 +1118,37 @@ as a base64 string. + +@@ -1154,6 +1112,41 @@ as a base64 string. return $cs; } @@ -56,14 +119,18 @@ +the string to encrypt or decrypt. For example: + + sub file_crypt { -+ use Crypt::RC4; + my ($action, $secret, $string) = @_; + ++ my $cipher = Crypt::CBC->new(-key => $secret, ++ -cipher => 'Blowfish'); ++ + my $return_string; + if ($action eq 'encrypt') { -+ $return_string = RC4($secret, $string); ++ $return_string = $cipher->encrypt($string); + } elsif ($action eq 'decrypt') { -+ $return_string = RC4($secret, $string); ++ $return_string = $cipher->decrypt($string); ++ } else { ++ print("Unknown encryption action ($action)\n"); + } + return $return_string; + } @@ -81,3 +148,63 @@ =head1 ENVIRONMENT =over 4 +--- a/perl/lib/Wallet/Object/File.pm ++++ b/perl/lib/Wallet/Object/File.pm +@@ -114,6 +114,11 @@ sub rename { + sub _get_crypt_key { + my ($self) = @_; + ++ if (defined (&Wallet::Config::file_crypt_secret)) { ++ my $return_val = Wallet::Config::file_crypt_secret(); ++ return $return_val; ++ } ++ + # ldap:///basedn?attr?scope?filter + my $url = $Wallet::Config::LDAP_SECRET; + $url =~ s{^ldap:///}{}xmsi; +@@ -173,14 +178,13 @@ sub _get_crypt_key { + } + + sub _file_crypt { +- my ($self, $action, $string) = @_; ++ my ($self, $action, $key, $string) = @_; + + require Crypt::CBC; + require MIME::Base64; + + my $return_string; + my $pre = $Wallet::Config::LDAP_SECRET_PREFIX; +- my $key = $self->_get_crypt_key(); + + my $cipher = Crypt::CBC->new( + -key => $key, +@@ -210,7 +214,13 @@ sub _file_crypt { + + sub file_decrypt { + my ($self, $data, $user, $host, $time) = @_; +- my $undata = $self->_file_crypt('decrypt', $data); ++ my $key = $self->_get_crypt_key(); ++ my $undata; ++ if (defined (&Wallet::Config::file_crypt)) { ++ $undata = Wallet::Config::file_crypt('decrypt', $key, $data); ++ } else { ++ $undata = $self->_file_crypt('decrypt', $key, $data); ++ } + if ($undata eq $data) { + $self->store($data, $user, $host, $time); + } +@@ -219,7 +229,13 @@ sub file_decrypt { + + sub file_encrypt { + my ($self, $data) = @_; +- my $endata = $self->_file_crypt('encrypt', $data); ++ my $key = $self->_get_crypt_key(); ++ my $endata; ++ if (defined (&Wallet::Config::file_crypt)) { ++ $endata = Wallet::Config::file_crypt('encrypt', $key, $data); ++ } else { ++ $endata = $self->_file_crypt('encrypt', $key, $data); ++ } + return $endata; + } + From e466bbb1db5d16144c8ee083b7933dc11136e813 Mon Sep 17 00:00:00 2001 From: Bill MacAllister Date: Tue, 26 May 2020 06:43:29 +0000 Subject: [PATCH 22/47] Update changelog for package release --- debian/changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/changelog b/debian/changelog index 7dfecb67..7eac5282 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,4 +1,4 @@ -wallet (1.4-5) UNRELEASED; urgency=medium +wallet (1.4-5) unstable; urgency=medium * Add password generation options supporting generation of password using selected Crypt::HSXKPasswd presets or a custom routine. From 9d13821b32671f03574bd639206e87469ae81b20 Mon Sep 17 00:00:00 2001 From: Bill MacAllister Date: Wed, 10 Jun 2020 23:23:10 +0000 Subject: [PATCH 23/47] Updates to encryption configuration and error traps * Rename the configuratiion variable LDAP_SECRET_PREFIX to ENCRYPTION_PREFIX. * Improve error messaging when attempting to retrieve the encryption secret from LDAP. * Trap the case when ENCRYPTION_PREFIX is specified and the required LDAP variables are not. --- debian/changelog | 11 + debian/patches/0015-encryption-fixes.patch | 221 +++++++++++++++++++++ debian/patches/series | 1 + 3 files changed, 233 insertions(+) create mode 100644 debian/patches/0015-encryption-fixes.patch diff --git a/debian/changelog b/debian/changelog index 7eac5282..f5f7f66c 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,14 @@ +wallet (1.4-6) unstable; urgency=medium + + * Rename the configuratiion variable LDAP_SECRET_PREFIX to + ENCRYPTION_PREFIX. + * Improve error messaging when attempting to retrieve the encryption + secret from LDAP. + * Trap the case when ENCRYPTION_PREFIX is specified and the required + LDAP variables are not. + + -- Bill MacAllister Wed, 10 Jun 2020 23:16:34 +0000 + wallet (1.4-5) unstable; urgency=medium * Add password generation options supporting generation of password diff --git a/debian/patches/0015-encryption-fixes.patch b/debian/patches/0015-encryption-fixes.patch new file mode 100644 index 00000000..fd63a58a --- /dev/null +++ b/debian/patches/0015-encryption-fixes.patch @@ -0,0 +1,221 @@ +--- a/perl/lib/Wallet/Object/File.pm ++++ b/perl/lib/Wallet/Object/File.pm +@@ -123,13 +123,39 @@ sub _get_crypt_key { + my $url = $Wallet::Config::LDAP_SECRET; + $url =~ s{^ldap:///}{}xmsi; + if ($url eq $Wallet::Config::LDAP_SECRET) { +- die("ERROR: Invalid LDAP URL $url"); ++ my $msg = "\n" ++ $msg .= "INFO: LDAP_SECRET contains a hostname\n"; ++ $msg .= "ERROR: Invalid LDAP_SECRET URL $url\n"; ++ die $msg; + } + my @parts = split /\?/, $url; + my $base = $parts[0]; ++ if (!$base) { ++ $msg .= "INFO: LDAP_SECRET does not contain a base dn\n"; ++ $msg .= "ERROR: Invalid LDAP_SECRET URL $url\n"; ++ die $msg; ++ } + my $attr = $parts[1]; ++ if (!$attr) { ++ $msg .= "INFO: LDAP_SECRET does not contain an attribute\n"; ++ $msg .= "ERROR: Invalid LDAP_SECRET URL $url\n"; ++ die $msg; ++ } + my $scope = $parts[2]; ++ if (!$scope) { ++ $scope = 'subtree'; ++ } + my $filter = $parts[3]; ++ if (!$filter) { ++ $filter = 'objectClass=*'; ++ } ++ ++ # Search details just in case they have to be displayed ++ my $msg = "\n"; ++ $msg .= "INFO: base = $base\n"; ++ $msg .= "INFO: filter = $filter\n"; ++ $msg .= "INFO: scope = $scope\n"; ++ $msg .= "INFO: attribute = $attr\n"; + + # Search for the secret in the LDAP directory + my $ldap_obj = Wallet::ACL::LDAP::Attribute->new; +@@ -145,17 +171,23 @@ sub _get_crypt_key { + if ($search->count == 1) { + $entry = $search->pop_entry; + } elsif ($search->count > 1) { +- die 'ERROR: ' . $search->count . " LDAP entries found for $filter"; ++ $msg .= 'ERROR: ' . $search->count . ' LDAP entries found for ' ++ . "$filter\n"; ++ die $msg; + } else { +- die "ERROR: No entry found for $url"; ++ my $msg = $search_details; ++ $msg .= "ERROR: No entry found for $url\n"; ++ die $msg; + } + }; + if ($@) { +- die "INFO: LDAP search failed using $url\n" +- . "ERROR: $@"; ++ $msg .= "ERROR: LDAP search failed using $url\n"; ++ $msg .= "ERROR: $@" . "\n"; ++ die $msg; + } + if (!$entry) { +- die "ERROR: No entry returned for LDAP search using $url"; ++ $msg .= "ERROR: No entry returned for LDAP search using $url"; ++ die $msg; + } + + my $return_val; +@@ -168,11 +200,15 @@ sub _get_crypt_key { + } + } + if (!$return_val) { +- die "ERROR: Attribute not found $url"; ++ $msg .= $search_details; ++ $msg .= "ERROR: Attribute not found $url\n"; ++ die $msg; + } + if ($cnt > 0) { + my $obj_cnt = $cnt + 1; +- die "ERROR: LDAP search return too many values ($obj_cnt) for $url"; ++ $msg .= $search_details; ++ $msg .= "ERROR: LDAP returned too many values ($obj_cnt) for $url"; ++ die $msg; + } + return $return_val; + } +@@ -184,7 +220,7 @@ sub _file_crypt { + require MIME::Base64; + + my $return_string; +- my $pre = $Wallet::Config::LDAP_SECRET_PREFIX; ++ my $pre = $Wallet::Config::ENCRYPTION_PREFIX; + + my $cipher = Crypt::CBC->new( + -key => $key, +@@ -219,6 +255,12 @@ sub file_decrypt { + if (defined (&Wallet::Config::file_crypt)) { + $undata = Wallet::Config::file_crypt('decrypt', $key, $data); + } else { ++ if (!$Wallet::Config::LDAP_SECRET) { ++ my $msg = "\n"; ++ $msg .= "ERROR: ENCYPTION_PREFIX specified and LDAP_SECRET is " ++ . "missing\n"; ++ die $msg; ++ } + $undata = $self->_file_crypt('decrypt', $key, $data); + } + if ($undata eq $data) { +@@ -234,6 +276,12 @@ sub file_encrypt { + if (defined (&Wallet::Config::file_crypt)) { + $endata = Wallet::Config::file_crypt('encrypt', $key, $data); + } else { ++ if (!$Wallet::Config::LDAP_SECRET) { ++ my $msg = "\n"; ++ $msg .= "ERROR: ENCYPTION_PREFIX specified and LDAP_SECRET is " ++ . "missing\n"; ++ die $msg; ++ } + $endata = $self->_file_crypt('encrypt', $key, $data); + } + return $endata; +@@ -276,7 +324,7 @@ sub get { + $self->error ("cannot get $id: $!"); + return; + } +- if ($Wallet::Config::LDAP_SECRET) { ++ if ($Wallet::Config::ENCRYPTION_PREFIX) { + $data = $self->file_decrypt($data, $user, $host, $time); + } + $self->log_action ('get', $user, $host, $time); +@@ -296,7 +344,7 @@ sub checksum { + my $this_checksum; + my $this_data; + my $this_endata = read_file($path); +- if ($Wallet::Config::LDAP_SECRET) { ++ if ($Wallet::Config::ENCRYPTION_PREFIX) { + $this_data = $self->file_decrypt($this_endata, $user, $host, $time) + } else { + $this_data = $this_endata; +@@ -326,7 +374,7 @@ sub store { + return; + } + } +- if ($Wallet::Config::LDAP_SECRET) { ++ if ($Wallet::Config::ENCRYPTION_PREFIX) { + $data = $self->file_encrypt($data); + } + +--- a/perl/lib/Wallet/Config.pm ++++ b/perl/lib/Wallet/Config.pm +@@ -795,31 +795,19 @@ our $LDAP_CACHE; + + Specifies an LDAP URL that is used to retrieve the secret to use when + encrypting and decrypting file objects. The url must not include the +-hostname. LDAP_HOST will be used as the hostname to bind to. The +-Kerberos ticket cache specified in LDAP_CACHE is used when connecting +-to the LDAP server. GSS-API authentication is always used; there is +-currently no support for any other type of bind. The ticket cache +-must be for a principal with access to retrieve the secret. This +-variable and LDAP_CACHE must be set to use file object encryption. ++hostname. LDAP_HOST will be used as the hostname for the server to ++bind to. The Kerberos ticket cache specified in LDAP_CACHE is used ++when connecting to the LDAP server. GSS-API authentication is always ++used; there is currently no support for any other type of bind. The ++ticket cache must be for a principal with access to retrieve the ++secret. The variables LDAP_HOST, LDAP_CACHE, LDAP_SECRET, and ++ENCRYPTION_PREFIX must be set to use the default encryption ++processing. + + =cut + + our $LDAP_SECRET; + +-=item LDAP_SECRET_PREFIX +- +-Specifies the prefix to be used when generating storing an encrypted +-file object. The prefix is used to determine whether or not a file +-object has been stored encrypted. This allows the gradual transition +-from unencrypted file objects to encrypted file objects. When file +-object encryption is enable any "get" of an unencyrpted file object +-will result in the replacement of the unencrypted object with an +-encrypted object. +- +-=cut +- +-our $LDAP_SECRET_PREFIX; +- + =back + + =head2 LDAP Principal Mapping +@@ -1112,7 +1100,25 @@ as a base64 string. + return $cs; + } + +-=head1 ENCRYPTION METHODS ++=head1 ENCRYPTION CONFIGURATION AND METHODS ++ ++=over4 ++=item ENCRYPTION_PREFIX ++ ++Specifies the prefix to be used when generating storing an encrypted ++file object. The prefix is used to determine whether or not a file ++object has been stored encrypted. This allows the gradual transition ++from unencrypted file objects to encrypted file objects. When file ++object encryption is enable any "get" of an unencyrpted file object ++will result in the replacement of the unencrypted object with an ++encrypted object. This variable must be set to use file and password ++encyrption. ++ ++=cut ++ ++our $ENCRYPTION_PREFIX; ++ ++=back + + The default encryption method is based on the twofish cypher. If + another encryption method is desired then the perl function file_crypt diff --git a/debian/patches/series b/debian/patches/series index ce977f4f..472ea18f 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -12,3 +12,4 @@ 0012-pwd-options.patch 0013-crypt-fixup.patch 0014-crypt-custom.patch +0015-encryption-fixes.patch From 0f4c625784959c38ff3dbeeb8aa6989460384305 Mon Sep 17 00:00:00 2001 From: Bill MacAllister Date: Thu, 11 Jun 2020 01:06:57 +0000 Subject: [PATCH 24/47] Add the checkfile command The checkfile command compares the checksum of a wallet object with the checksum of a file and if they differ a wallet get is performed. --- debian/patches/0016-update-command.patch | 174 +++++++++++++++++++++++ debian/patches/series | 1 + 2 files changed, 175 insertions(+) create mode 100644 debian/patches/0016-update-command.patch diff --git a/debian/patches/0016-update-command.patch b/debian/patches/0016-update-command.patch new file mode 100644 index 00000000..b5c9edc4 --- /dev/null +++ b/debian/patches/0016-update-command.patch @@ -0,0 +1,174 @@ +--- /dev/null ++++ b/client/checkfile.c +@@ -0,0 +1,136 @@ ++/* ++ * Test file object checksum against a file on the system ++ * ++ * Written by Bill MacAllister ++ * Copyright 2020 Dropbox, Inc. ++ * ++ * SPDX-License-Identifier: MIT ++ */ ++ ++#include ++#include ++ ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++/* Given a string and its length return a checksum for the string. ++ */ ++char *checkfile_str2md5(const char *str, int length) { ++ int n; ++ MD5_CTX c; ++ unsigned char digest[16]; ++ char *out = (char*)malloc(33); ++ ++ MD5_Init(&c); ++ ++ while (length > 0) { ++ if (length > 512) { ++ MD5_Update(&c, str, 512); ++ } else { ++ MD5_Update(&c, str, length); ++ } ++ length -= 512; ++ str += 512; ++ } ++ ++ MD5_Final(digest, &c); ++ ++ for (n = 0; n < 16; ++n) { ++ snprintf(&(out[n*2]), 16*2, "%02x", (unsigned int)digest[n]); ++ } ++ ++ return out; ++} ++ ++/* ++ * Read all of a file into memory and return the contents in newly allocated ++ * memory. Returns the size of the file contents in the second argument if ++ * it's not NULL. Dies on any failure. ++ */ ++void * ++checkfile_read_file(const char *name, size_t *length) ++{ ++ char *contents; ++ size_t size, offset; ++ int fd; ++ struct stat st; ++ ssize_t status; ++ ++ fd = open(name, O_RDONLY); ++ if (fd < 0) ++ return NULL; ++ if (fstat(fd, &st) < 0) ++ return NULL; ++ size = st.st_size; ++ contents = xmalloc(size); ++ ++ offset = 0; ++ do { ++ if (offset >= size - 1) { ++ size += BUFSIZ; ++ contents = xrealloc(contents, size); ++ } ++ do { ++ status = read(fd, contents + offset, size - offset - 1); ++ } while (status == -1 && errno == EINTR); ++ if (status < 0) ++ sysdie("cannot read from file"); ++ offset += status; ++ } while (status > 0); ++ close(fd); ++ if (length != NULL) ++ *length = offset; ++ return contents; ++} ++ ++/* ++ * Given a remctl object, the command prefix, object type, and object name, ++ * and a file calculate the checksum of the file, get the checksum of ++ * the wallet object, and compare them. Returns 0 if the checksums ++ * match and an exit status on if the don't match. ++ */ ++int ++checkfile(struct remctl *r, const char *prefix, const char *type, ++ const char *name, const char *file) ++{ ++ const char *command[5]; ++ char *file_data = NULL; ++ char *file_checksum = NULL; ++ char *wallet_checksum = NULL; ++ size_t wallet_length = 0; ++ int status; ++ ++ /* Check to see if the file exists. It not return mismatch status */ ++ file_data = checkfile_read_file(file, 1); ++ if (file_data == NULL) ++ return 1; ++ ++ command[0] = prefix; ++ command[1] = "checksum"; ++ command[2] = type; ++ command[3] = name; ++ command[4] = NULL; ++ status = run_command(r, command, &wallet_checksum, &wallet_length); ++ if (status != 0) ++ return status; ++ ++ /* If the wallet object is empty or NULL return mismatch and let the ++ * subsequent call to file handle the error condition of an empty ++ * file object. ++ */ ++ if ((wallet_length == 0) || (wallet_checksum == NULL)) ++ return 1; ++ ++ file_checksum = str2md5(file_data, strlen(file_data)); ++ ++ return strcmp(file_checksum, wallet_checksum); ++} +--- a/client/wallet.c ++++ b/client/wallet.c +@@ -172,6 +172,14 @@ main(int argc, char *argv[]) + if (argc > 2) + die("too many arguments"); + status = rekey_keytab(r, ctx, options.type, argv[1]); ++ } else if (strcmp(argv[0], "checkfile") == 0) { ++ if (argc > 3) ++ die("too many arguments"); ++ if (strcmp(argv[1], "keytab") == 0) ++ die("checkfile command is not valid for keytabs"); ++ status = checkfile(r, options.type, argv[1], argv[2], file); ++ if (status > 0) ++ status = get_file(r, options.type, argv[1], argv[2], file); + } else { + count = argc + 1; + if (strcmp(argv[0], "store") == 0) { +--- a/client/wallet.pod ++++ b/client/wallet.pod +@@ -263,7 +263,14 @@ already exist. + Check whether an object of type and name already exists. If + it does, prints C; if not, prints C. + +-=item checksum ++=item checkfile ++ ++Preforms a get command only if the wallet object checksum differs from ++the checksum of the file specified. The -f switch must be specified. ++This command is not valid for keytabs and the wallet object must have ++been stored. ++ ++=item checksum + + Returns the checksum for file objects. + diff --git a/debian/patches/series b/debian/patches/series index 472ea18f..e7b6348a 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -13,3 +13,4 @@ 0013-crypt-fixup.patch 0014-crypt-custom.patch 0015-encryption-fixes.patch +0016-update-command.patch From e03fdec0f320f8d3547d582f9b0e71205e9d7c80 Mon Sep 17 00:00:00 2001 From: Bill MacAllister Date: Tue, 16 Jun 2020 20:08:00 +0000 Subject: [PATCH 25/47] Debugging checkfile - Add checkfile to internal.h - Update Makefile.am to include checkfile.c - Add libssl-dev to build-depends - Correct call to checkfile_read_file - Correct call to str2md5 --- debian/control | 1 + debian/gbp.conf | 2 +- debian/patches/0016-update-command.patch | 37 ++++++++++++++++++++++-- 3 files changed, 36 insertions(+), 4 deletions(-) diff --git a/debian/control b/debian/control index 28576347..d26f8352 100644 --- a/debian/control +++ b/debian/control @@ -27,6 +27,7 @@ Build-Depends: libnet-remctl-perl, libperl6-slurp-perl, libremctl-dev, + libssl-dev, libsql-translator-perl, libtest-minimumversion-perl, libtest-pod-perl, diff --git a/debian/gbp.conf b/debian/gbp.conf index 224e7974..0488dcd2 100644 --- a/debian/gbp.conf +++ b/debian/gbp.conf @@ -2,7 +2,7 @@ # upstream development using the DEP-14 layout. [DEFAULT] -debian-branch = debian/master +debian-branch = ubuntu/master upstream-branch = upstream/latest pristine-tar = True diff --git a/debian/patches/0016-update-command.patch b/debian/patches/0016-update-command.patch index b5c9edc4..12c2278d 100644 --- a/debian/patches/0016-update-command.patch +++ b/debian/patches/0016-update-command.patch @@ -1,6 +1,6 @@ --- /dev/null +++ b/client/checkfile.c -@@ -0,0 +1,136 @@ +@@ -0,0 +1,137 @@ +/* + * Test file object checksum against a file on the system + * @@ -108,12 +108,13 @@ + const char *command[5]; + char *file_data = NULL; + char *file_checksum = NULL; ++ size_t count, length; + char *wallet_checksum = NULL; + size_t wallet_length = 0; + int status; + + /* Check to see if the file exists. It not return mismatch status */ -+ file_data = checkfile_read_file(file, 1); ++ file_data = checkfile_read_file(file, &length); + if (file_data == NULL) + return 1; + @@ -133,7 +134,7 @@ + if ((wallet_length == 0) || (wallet_checksum == NULL)) + return 1; + -+ file_checksum = str2md5(file_data, strlen(file_data)); ++ file_checksum = checkfile_str2md5(file_data, strlen(file_data)); + + return strcmp(file_checksum, wallet_checksum); +} @@ -172,3 +173,33 @@ Returns the checksum for file objects. +--- a/client/internal.h ++++ b/client/internal.h +@@ -97,6 +97,15 @@ int get_file(struct remctl *, const char + const char *name, const char *file); + + /* ++ * Given a remctl object, the command prefix, object type, and object name, ++ * and a file calculate the checksum of the file, get the checksum of ++ * the wallet object, and compare them. Returns 0 if the checksums ++ * match and an exit status on if the don't match. ++ */ ++int checkfile(struct remctl *r, const char *prefix, const char *type, ++ const char *name, const char *file); ++ ++/* + * Given a remctl object, the Kerberos context, the type for the wallet + * interface, the name of a keytab object, and a file name, call the correct + * wallet commands to download a keytab and write it to that file. If srvtab +--- a/Makefile.am ++++ b/Makefile.am +@@ -150,7 +150,8 @@ util_libutil_a_CPPFLAGS = $(KRB5_CPPFLAG + # The private library used by both wallet and wallet-rekey. + noinst_LIBRARIES += client/libwallet.a + client_libwallet_a_SOURCES = client/file.c client/internal.h client/keytab.c \ +- client/krb5.c client/options.c client/remctl.c client/srvtab.c ++ client/krb5.c client/options.c client/remctl.c client/srvtab.c \ ++ client/checkfile.c + client_libwallet_a_CPPFLAGS = $(REMCTL_CPPFLAGS) $(KRB5_CPPFLAGS) + + # The client and server programs. From 6754bd93f4d595af787ed9fb4e44f119f7c4d23b Mon Sep 17 00:00:00 2001 From: Bill MacAllister Date: Tue, 16 Jun 2020 20:08:00 +0000 Subject: [PATCH 26/47] Debugging checkfile - Add checkfile to internal.h - Update Makefile.am to include checkfile.c - Add libssl-dev to build-depends - Correct call to checkfile_read_file - Correct call to str2md5 --- debian/control | 1 + debian/gbp.conf | 2 +- debian/patches/0016-update-command.patch | 37 ++++++++++++++++++++++-- 3 files changed, 36 insertions(+), 4 deletions(-) diff --git a/debian/control b/debian/control index 28576347..d26f8352 100644 --- a/debian/control +++ b/debian/control @@ -27,6 +27,7 @@ Build-Depends: libnet-remctl-perl, libperl6-slurp-perl, libremctl-dev, + libssl-dev, libsql-translator-perl, libtest-minimumversion-perl, libtest-pod-perl, diff --git a/debian/gbp.conf b/debian/gbp.conf index 224e7974..0488dcd2 100644 --- a/debian/gbp.conf +++ b/debian/gbp.conf @@ -2,7 +2,7 @@ # upstream development using the DEP-14 layout. [DEFAULT] -debian-branch = debian/master +debian-branch = ubuntu/master upstream-branch = upstream/latest pristine-tar = True diff --git a/debian/patches/0016-update-command.patch b/debian/patches/0016-update-command.patch index b5c9edc4..12c2278d 100644 --- a/debian/patches/0016-update-command.patch +++ b/debian/patches/0016-update-command.patch @@ -1,6 +1,6 @@ --- /dev/null +++ b/client/checkfile.c -@@ -0,0 +1,136 @@ +@@ -0,0 +1,137 @@ +/* + * Test file object checksum against a file on the system + * @@ -108,12 +108,13 @@ + const char *command[5]; + char *file_data = NULL; + char *file_checksum = NULL; ++ size_t count, length; + char *wallet_checksum = NULL; + size_t wallet_length = 0; + int status; + + /* Check to see if the file exists. It not return mismatch status */ -+ file_data = checkfile_read_file(file, 1); ++ file_data = checkfile_read_file(file, &length); + if (file_data == NULL) + return 1; + @@ -133,7 +134,7 @@ + if ((wallet_length == 0) || (wallet_checksum == NULL)) + return 1; + -+ file_checksum = str2md5(file_data, strlen(file_data)); ++ file_checksum = checkfile_str2md5(file_data, strlen(file_data)); + + return strcmp(file_checksum, wallet_checksum); +} @@ -172,3 +173,33 @@ Returns the checksum for file objects. +--- a/client/internal.h ++++ b/client/internal.h +@@ -97,6 +97,15 @@ int get_file(struct remctl *, const char + const char *name, const char *file); + + /* ++ * Given a remctl object, the command prefix, object type, and object name, ++ * and a file calculate the checksum of the file, get the checksum of ++ * the wallet object, and compare them. Returns 0 if the checksums ++ * match and an exit status on if the don't match. ++ */ ++int checkfile(struct remctl *r, const char *prefix, const char *type, ++ const char *name, const char *file); ++ ++/* + * Given a remctl object, the Kerberos context, the type for the wallet + * interface, the name of a keytab object, and a file name, call the correct + * wallet commands to download a keytab and write it to that file. If srvtab +--- a/Makefile.am ++++ b/Makefile.am +@@ -150,7 +150,8 @@ util_libutil_a_CPPFLAGS = $(KRB5_CPPFLAG + # The private library used by both wallet and wallet-rekey. + noinst_LIBRARIES += client/libwallet.a + client_libwallet_a_SOURCES = client/file.c client/internal.h client/keytab.c \ +- client/krb5.c client/options.c client/remctl.c client/srvtab.c ++ client/krb5.c client/options.c client/remctl.c client/srvtab.c \ ++ client/checkfile.c + client_libwallet_a_CPPFLAGS = $(REMCTL_CPPFLAGS) $(KRB5_CPPFLAGS) + + # The client and server programs. From 926bc5155dc4d03b27c72c2d3e3439de3487340e Mon Sep 17 00:00:00 2001 From: Bill MacAllister Date: Thu, 2 Jul 2020 16:35:01 +0000 Subject: [PATCH 27/47] Update gbp.conf for debian builds --- debian/gbp.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/gbp.conf b/debian/gbp.conf index 0488dcd2..224e7974 100644 --- a/debian/gbp.conf +++ b/debian/gbp.conf @@ -2,7 +2,7 @@ # upstream development using the DEP-14 layout. [DEFAULT] -debian-branch = ubuntu/master +debian-branch = debian/master upstream-branch = upstream/latest pristine-tar = True From 5b2c72f76afedf502ff77b0cc06cca0ebdff953e Mon Sep 17 00:00:00 2001 From: Bill MacAllister Date: Mon, 6 Jul 2020 23:49:49 +0000 Subject: [PATCH 28/47] Update filecheck patch adding OpenSSL library support --- debian/patches/0016-update-command.patch | 613 ++++++++++++++++++++++- 1 file changed, 612 insertions(+), 1 deletion(-) diff --git a/debian/patches/0016-update-command.patch b/debian/patches/0016-update-command.patch index 12c2278d..3df54469 100644 --- a/debian/patches/0016-update-command.patch +++ b/debian/patches/0016-update-command.patch @@ -193,7 +193,229 @@ * wallet commands to download a keytab and write it to that file. If srvtab --- a/Makefile.am +++ b/Makefile.am -@@ -150,7 +150,8 @@ util_libutil_a_CPPFLAGS = $(KRB5_CPPFLAG +@@ -20,119 +20,119 @@ WALLET_PERL_FLAGS ?= + # added to EXTRA_DIST and so that they can be copied over properly for + # builddir != srcdir builds. + PERL_FILES = perl/Build.PL perl/MANIFEST perl/MANIFEST.SKIP perl/create-ddl \ +- perl/lib/Wallet/ACL.pm perl/lib/Wallet/ACL/Base.pm \ +- perl/lib/Wallet/ACL/External.pm perl/lib/Wallet/ACL/Krb5.pm \ +- perl/lib/Wallet/ACL/Krb5/Regex.pm \ +- perl/lib/Wallet/ACL/LDAP/Attribute.pm \ +- perl/lib/Wallet/ACL/LDAP/Attribute/Root.pm \ +- perl/lib/Wallet/ACL/NetDB.pm perl/lib/Wallet/ACL/Nested.pm \ +- perl/lib/Wallet/ACL/NetDB/Root.pm perl/lib/Wallet/Admin.pm \ +- perl/lib/Wallet/Config.pm perl/lib/Wallet/Database.pm \ +- perl/lib/Wallet/Kadmin.pm perl/lib/Wallet/Kadmin/AD.pm \ +- perl/lib/Wallet/Kadmin/Heimdal.pm perl/lib/Wallet/Kadmin/MIT.pm \ +- perl/lib/Wallet/Object/Base.pm perl/lib/Wallet/Object/Duo.pm \ +- perl/lib/Wallet/Object/File.pm perl/lib/Wallet/Object/Keytab.pm \ +- perl/lib/Wallet/Object/Password.pm \ +- perl/lib/Wallet/Object/WAKeyring.pm \ +- perl/lib/Wallet/Policy/Stanford.pm perl/lib/Wallet/Report.pm \ +- perl/lib/Wallet/Schema.pm perl/lib/Wallet/Server.pm \ +- perl/lib/Wallet/Schema/Result/Acl.pm \ +- perl/lib/Wallet/Schema/Result/AclEntry.pm \ +- perl/lib/Wallet/Schema/Result/AclHistory.pm \ +- perl/lib/Wallet/Schema/Result/AclScheme.pm \ +- perl/lib/Wallet/Schema/Result/Duo.pm \ +- perl/lib/Wallet/Schema/Result/Enctype.pm \ +- perl/lib/Wallet/Schema/Result/Flag.pm \ +- perl/lib/Wallet/Schema/Result/KeytabEnctype.pm \ +- perl/lib/Wallet/Schema/Result/KeytabSync.pm \ +- perl/lib/Wallet/Schema/Result/Object.pm \ +- perl/lib/Wallet/Schema/Result/ObjectHistory.pm \ +- perl/lib/Wallet/Schema/Result/SyncTarget.pm \ +- perl/lib/Wallet/Schema/Result/Type.pm \ +- perl/sql/Wallet-Schema-0.07-0.08-MySQL.sql \ +- perl/sql/Wallet-Schema-0.07-0.08-SQLite.sql \ +- perl/sql/Wallet-Schema-0.07-MySQL.sql \ +- perl/sql/Wallet-Schema-0.07-SQLite.sql \ +- perl/sql/Wallet-Schema-0.08-0.09-MySQL.sql \ +- perl/sql/Wallet-Schema-0.08-0.09-PostgreSQL.sql \ +- perl/sql/Wallet-Schema-0.08-0.09-SQLite.sql \ +- perl/sql/Wallet-Schema-0.08-MySQL.sql \ +- perl/sql/Wallet-Schema-0.08-PostgreSQL.sql \ +- perl/sql/Wallet-Schema-0.08-SQLite.sql \ +- perl/sql/Wallet-Schema-0.09-MySQL.sql \ +- perl/sql/Wallet-Schema-0.09-PostgreSQL.sql \ +- perl/sql/Wallet-Schema-0.09-SQLite.sql \ +- perl/sql/Wallet-Schema-0.09-0.10-MySQL.sql \ +- perl/sql/Wallet-Schema-0.09-0.10-PostgreSQL.sql \ +- perl/sql/Wallet-Schema-0.09-0.10-SQLite.sql \ +- perl/sql/Wallet-Schema-0.10-MySQL.sql \ +- perl/sql/Wallet-Schema-0.10-PostgreSQL.sql \ +- perl/sql/Wallet-Schema-0.10-SQLite.sql \ +- perl/sql/wallet-1.3-update-duo.sql perl/t/data/README \ +- perl/t/data/acl-command perl/t/data/duo/integration.json \ +- perl/t/data/duo/integration-ldap.json \ +- perl/t/data/duo/integration-radius.json \ +- perl/t/data/duo/integration-rdp.json perl/t/data/duo/keys.json \ +- perl/t/data/keytab-fake perl/t/data/keytab.conf \ ++ perl/lib/Wallet/ACL.pm perl/lib/Wallet/ACL/Base.pm \ ++ perl/lib/Wallet/ACL/External.pm perl/lib/Wallet/ACL/Krb5.pm \ ++ perl/lib/Wallet/ACL/Krb5/Regex.pm \ ++ perl/lib/Wallet/ACL/LDAP/Attribute.pm \ ++ perl/lib/Wallet/ACL/LDAP/Attribute/Root.pm \ ++ perl/lib/Wallet/ACL/NetDB.pm perl/lib/Wallet/ACL/Nested.pm \ ++ perl/lib/Wallet/ACL/NetDB/Root.pm perl/lib/Wallet/Admin.pm \ ++ perl/lib/Wallet/Config.pm perl/lib/Wallet/Database.pm \ ++ perl/lib/Wallet/Kadmin.pm perl/lib/Wallet/Kadmin/AD.pm \ ++ perl/lib/Wallet/Kadmin/Heimdal.pm perl/lib/Wallet/Kadmin/MIT.pm \ ++ perl/lib/Wallet/Object/Base.pm perl/lib/Wallet/Object/Duo.pm \ ++ perl/lib/Wallet/Object/File.pm perl/lib/Wallet/Object/Keytab.pm \ ++ perl/lib/Wallet/Object/Password.pm \ ++ perl/lib/Wallet/Object/WAKeyring.pm \ ++ perl/lib/Wallet/Policy/Stanford.pm perl/lib/Wallet/Report.pm \ ++ perl/lib/Wallet/Schema.pm perl/lib/Wallet/Server.pm \ ++ perl/lib/Wallet/Schema/Result/Acl.pm \ ++ perl/lib/Wallet/Schema/Result/AclEntry.pm \ ++ perl/lib/Wallet/Schema/Result/AclHistory.pm \ ++ perl/lib/Wallet/Schema/Result/AclScheme.pm \ ++ perl/lib/Wallet/Schema/Result/Duo.pm \ ++ perl/lib/Wallet/Schema/Result/Enctype.pm \ ++ perl/lib/Wallet/Schema/Result/Flag.pm \ ++ perl/lib/Wallet/Schema/Result/KeytabEnctype.pm \ ++ perl/lib/Wallet/Schema/Result/KeytabSync.pm \ ++ perl/lib/Wallet/Schema/Result/Object.pm \ ++ perl/lib/Wallet/Schema/Result/ObjectHistory.pm \ ++ perl/lib/Wallet/Schema/Result/SyncTarget.pm \ ++ perl/lib/Wallet/Schema/Result/Type.pm \ ++ perl/sql/Wallet-Schema-0.07-0.08-MySQL.sql \ ++ perl/sql/Wallet-Schema-0.07-0.08-SQLite.sql \ ++ perl/sql/Wallet-Schema-0.07-MySQL.sql \ ++ perl/sql/Wallet-Schema-0.07-SQLite.sql \ ++ perl/sql/Wallet-Schema-0.08-0.09-MySQL.sql \ ++ perl/sql/Wallet-Schema-0.08-0.09-PostgreSQL.sql \ ++ perl/sql/Wallet-Schema-0.08-0.09-SQLite.sql \ ++ perl/sql/Wallet-Schema-0.08-MySQL.sql \ ++ perl/sql/Wallet-Schema-0.08-PostgreSQL.sql \ ++ perl/sql/Wallet-Schema-0.08-SQLite.sql \ ++ perl/sql/Wallet-Schema-0.09-MySQL.sql \ ++ perl/sql/Wallet-Schema-0.09-PostgreSQL.sql \ ++ perl/sql/Wallet-Schema-0.09-SQLite.sql \ ++ perl/sql/Wallet-Schema-0.09-0.10-MySQL.sql \ ++ perl/sql/Wallet-Schema-0.09-0.10-PostgreSQL.sql \ ++ perl/sql/Wallet-Schema-0.09-0.10-SQLite.sql \ ++ perl/sql/Wallet-Schema-0.10-MySQL.sql \ ++ perl/sql/Wallet-Schema-0.10-PostgreSQL.sql \ ++ perl/sql/Wallet-Schema-0.10-SQLite.sql \ ++ perl/sql/wallet-1.3-update-duo.sql perl/t/data/README \ ++ perl/t/data/acl-command perl/t/data/duo/integration.json \ ++ perl/t/data/duo/integration-ldap.json \ ++ perl/t/data/duo/integration-radius.json \ ++ perl/t/data/duo/integration-rdp.json perl/t/data/duo/keys.json \ ++ perl/t/data/keytab-fake perl/t/data/keytab.conf \ + perl/t/data/netdb-fake perl/t/data/netdb.conf perl/t/data/perl.conf \ + perl/t/docs/pod-spelling.t perl/t/docs/pod.t perl/t/general/acl.t \ +- perl/t/general/admin.t perl/t/general/config.t \ +- perl/t/general/init.t perl/t/general/report.t \ +- perl/t/general/server.t perl/t/lib/Util.pm perl/t/object/base.t \ +- perl/t/object/duo.t perl/t/object/duo-ldap.t \ +- perl/t/object/duo-pam.t perl/t/object/duo-radius.t \ ++ perl/t/general/admin.t perl/t/general/config.t \ ++ perl/t/general/init.t perl/t/general/report.t \ ++ perl/t/general/server.t perl/t/lib/Util.pm perl/t/object/base.t \ ++ perl/t/object/duo.t perl/t/object/duo-ldap.t \ ++ perl/t/object/duo-pam.t perl/t/object/duo-radius.t \ + perl/t/object/duo-rdp.t perl/t/object/file.t perl/t/object/keytab.t \ +- perl/t/object/password.t perl/t/object/wa-keyring.t \ +- perl/t/policy/stanford.t perl/t/style/minimum-version.t \ ++ perl/t/object/password.t perl/t/object/wa-keyring.t \ ++ perl/t/policy/stanford.t perl/t/style/minimum-version.t \ + perl/t/style/strict.t perl/t/util/kadmin.t perl/t/verifier/basic.t \ +- perl/t/verifier/external.t perl/t/verifier/ldap-attr.t \ ++ perl/t/verifier/external.t perl/t/verifier/ldap-attr.t \ + perl/t/verifier/nested.t perl/t/verifier/netdb.t + + # Directories that have to be created in builddir != srcdir builds before + # copying PERL_FILES over. +-PERL_DIRECTORIES = perl perl/lib perl/lib/Wallet perl/lib/Wallet/ACL \ +- perl/lib/Wallet/ACL/Krb5 perl/lib/Wallet/ACL/LDAP \ +- perl/lib/Wallet/ACL/LDAP/Attribute perl/lib/Wallet/ACL/NetDB \ +- perl/lib/Wallet/Kadmin perl/lib/Wallet/Object \ +- perl/lib/Wallet/Policy perl/lib/Wallet/Schema \ +- perl/lib/Wallet/Schema/Result perl/sql perl/t perl/t/data \ ++PERL_DIRECTORIES = perl perl/lib perl/lib/Wallet perl/lib/Wallet/ACL \ ++ perl/lib/Wallet/ACL/Krb5 perl/lib/Wallet/ACL/LDAP \ ++ perl/lib/Wallet/ACL/LDAP/Attribute perl/lib/Wallet/ACL/NetDB \ ++ perl/lib/Wallet/Kadmin perl/lib/Wallet/Object \ ++ perl/lib/Wallet/Policy perl/lib/Wallet/Schema \ ++ perl/lib/Wallet/Schema/Result perl/sql perl/t perl/t/data \ + perl/t/data/duo perl/t/docs perl/t/general perl/t/lib perl/t/object \ + perl/t/policy perl/t/style perl/t/util perl/t/verifier + + ACLOCAL_AMFLAGS = -I m4 +-EXTRA_DIST = .gitignore .travis.yml LICENSE README.md bootstrap \ +- client/wallet.pod client/wallet-rekey.pod config/allow-extract \ +- config/keytab config/keytab.acl config/wallet \ +- config/wallet-report.acl docs/design contrib/README \ +- contrib/ad-keytab contrib/ad-keytab.8 \ +- contrib/commerzbank/wallet-history contrib/convert-srvtab-db \ +- contrib/used-principals contrib/wallet-contacts \ +- contrib/wallet-rekey-periodic contrib/wallet-rekey-periodic.8 \ +- contrib/wallet-summary contrib/wallet-summary.8 \ +- contrib/wallet-unknown-hosts contrib/wallet-unknown-hosts.8 \ ++EXTRA_DIST = .gitignore .travis.yml LICENSE README.md bootstrap \ ++ client/wallet.pod client/wallet-rekey.pod config/allow-extract \ ++ config/keytab config/keytab.acl config/wallet \ ++ config/wallet-report.acl docs/design contrib/README \ ++ contrib/ad-keytab contrib/ad-keytab.8 \ ++ contrib/commerzbank/wallet-history contrib/convert-srvtab-db \ ++ contrib/used-principals contrib/wallet-contacts \ ++ contrib/wallet-rekey-periodic contrib/wallet-rekey-periodic.8 \ ++ contrib/wallet-summary contrib/wallet-summary.8 \ ++ contrib/wallet-unknown-hosts contrib/wallet-unknown-hosts.8 \ + docs/design-acl docs/design-api docs/metadata docs/netdb-role-api \ + docs/notes docs/objects-and-schemes docs/setup docs/stanford-naming \ +- examples/stanford.conf server/keytab-backend.in \ +- server/wallet-admin.in server/wallet-backend.in \ +- server/wallet-report.in tests/README tests/TESTS \ ++ examples/stanford.conf server/keytab-backend.in \ ++ server/wallet-admin.in server/wallet-backend.in \ ++ server/wallet-report.in tests/README tests/TESTS \ + tests/config/README tests/data/allow-extract tests/data/basic.conf \ + tests/data/cmd-fake tests/data/cmd-wrapper tests/data/cppcheck.supp \ + tests/data/fake-data tests/data/fake-kadmin tests/data/fake-keytab \ +- tests/data/fake-keytab-2 tests/data/fake-keytab-foreign \ +- tests/data/fake-keytab-merge tests/data/fake-keytab-old \ +- tests/data/fake-keytab-partial \ ++ tests/data/fake-keytab-2 tests/data/fake-keytab-foreign \ ++ tests/data/fake-keytab-merge tests/data/fake-keytab-old \ ++ tests/data/fake-keytab-partial \ + tests/data/fake-keytab-partial-result tests/data/fake-keytab-rekey \ +- tests/data/fake-keytab-unknown tests/data/fake-srvtab \ ++ tests/data/fake-keytab-unknown tests/data/fake-srvtab \ + tests/data/full.conf tests/data/perl.conf tests/data/wallet.conf \ +- tests/docs/pod-spelling-t tests/docs/pod-t \ +- tests/docs/spdx-license-t tests/perl/minimum-version-t \ +- tests/perl/module-version-t tests/perl/strict-t \ ++ tests/docs/pod-spelling-t tests/docs/pod-t \ ++ tests/docs/spdx-license-t tests/perl/minimum-version-t \ ++ tests/perl/module-version-t tests/perl/strict-t \ + tests/server/admin-t tests/server/backend-t tests/server/keytab-t \ +- tests/server/report-t tests/style/obsolete-strings-t \ +- tests/tap/kerberos.sh tests/tap/libtap.sh \ +- tests/tap/perl/Test/RRA.pm tests/tap/perl/Test/RRA/Automake.pm \ +- tests/tap/perl/Test/RRA/Config.pm \ +- tests/tap/perl/Test/RRA/ModuleVersion.pm tests/tap/remctl.sh \ ++ tests/server/report-t tests/style/obsolete-strings-t \ ++ tests/tap/kerberos.sh tests/tap/libtap.sh \ ++ tests/tap/perl/Test/RRA.pm tests/tap/perl/Test/RRA/Automake.pm \ ++ tests/tap/perl/Test/RRA/Config.pm \ ++ tests/tap/perl/Test/RRA/ModuleVersion.pm tests/tap/remctl.sh \ + tests/util/xmalloc-t $(PERL_FILES) + + # Supporting convenience libraries used by other targets. +@@ -142,7 +142,7 @@ portable_libportable_a_SOURCES = portabl + portable/uio.h + portable_libportable_a_CPPFLAGS = $(KRB5_CPPFLAGS) + portable_libportable_a_LIBADD = $(LIBOBJS) +-util_libutil_a_SOURCES = util/macros.h util/messages-krb5.c \ ++util_libutil_a_SOURCES = util/macros.h util/messages-krb5.c \ + util/messages-krb5.h util/messages.c util/messages.h util/xmalloc.c \ + util/xmalloc.h + util_libutil_a_CPPFLAGS = $(KRB5_CPPFLAGS) +@@ -150,21 +150,22 @@ util_libutil_a_CPPFLAGS = $(KRB5_CPPFLAG # The private library used by both wallet and wallet-rekey. noinst_LIBRARIES += client/libwallet.a client_libwallet_a_SOURCES = client/file.c client/internal.h client/keytab.c \ @@ -203,3 +425,392 @@ client_libwallet_a_CPPFLAGS = $(REMCTL_CPPFLAGS) $(KRB5_CPPFLAGS) # The client and server programs. + bin_PROGRAMS = client/wallet client/wallet-rekey + sbin_SCRIPTS = server/keytab-backend server/wallet-admin \ + server/wallet-backend server/wallet-report +-client_wallet_CPPFLAGS = $(REMCTL_CPPFLAGS) $(KRB5_CPPFLAGS) +-client_wallet_LDFLAGS = $(REMCTL_LDFLAGS) $(KRB5_LDFLAGS) ++client_wallet_CPPFLAGS = $(REMCTL_CPPFLAGS) $(KRB5_CPPFLAGS) $(CRYPTO_CPPFLAGS) ++client_wallet_LDFLAGS = $(REMCTL_LDFLAGS) $(KRB5_LDFLAGS) $(CRYPTO_LDFLAGS) + client_wallet_LDADD = client/libwallet.a util/libutil.a \ +- portable/libportable.a $(REMCTL_LIBS) $(KRB5_LIBS) +-client_wallet_rekey_CPPFLAGS = $(REMCTL_CPPFLAGS) $(KRB5_CPPFLAGS) +-client_wallet_rekey_LDFLAGS = $(REMCTL_LDFLAGS) $(KRB5_LDFLAGS) ++ portable/libportable.a $(REMCTL_LIBS) $(KRB5_LIBS) $(CRYPTO_LIBS) ++client_wallet_rekey_CPPFLAGS = $(REMCTL_CPPFLAGS) $(KRB5_CPPFLAGS) $(CRYPTO_CPPFLAGS) ++client_wallet_rekey_LDFLAGS = $(REMCTL_LDFLAGS) $(KRB5_LDFLAGS) $(CRYPTO_LDFLAGS) + client_wallet_rekey_LDADD = client/libwallet.a util/libutil.a \ +- portable/libportable.a $(REMCTL_LIBS) $(KRB5_LIBS) ++ portable/libportable.a $(REMCTL_LIBS) $(KRB5_LIBS) $(CRYPTO_LIBS) + + # The manual pages. + dist_man_MANS = client/wallet.1 client/wallet-rekey.1 server/keytab-backend.8 \ +@@ -189,18 +190,18 @@ dist_pkgdata_DATA = perl/sql/Wallet-Sche + # compiler warnings enabled as possible. + warnings: + $(MAKE) V=0 CFLAGS='$(WARNINGS_CFLAGS) $(AM_CFLAGS)' \ +- KRB5_CPPFLAGS='$(KRB5_CPPFLAGS_GCC)' ++ KRB5_CPPFLAGS='$(KRB5_CPPFLAGS_GCC)' + $(MAKE) V=0 CFLAGS='$(WARNINGS_CFLAGS) $(AM_CFLAGS)' \ +- KRB5_CPPFLAGS='$(KRB5_CPPFLAGS_GCC)' $(check_PROGRAMS) ++ KRB5_CPPFLAGS='$(KRB5_CPPFLAGS_GCC)' $(check_PROGRAMS) + + # Remove some additional files. + CLEANFILES = perl/t/lib/Test/RRA.pm perl/t/lib/Test/RRA/Automake.pm \ + perl/t/lib/Test/RRA/Config.pm server/keytab-backend \ + server/wallet-admin server/wallet-backend server/wallet-report +-MAINTAINERCLEANFILES = Makefile.in aclocal.m4 build-aux/compile \ +- build-aux/depcomp build-aux/install-sh build-aux/missing \ +- client/wallet.1 config.h.in config.h.in~ configure \ +- contrib/wallet-report.8 server/keytab-backend.8 \ ++MAINTAINERCLEANFILES = Makefile.in aclocal.m4 build-aux/compile \ ++ build-aux/depcomp build-aux/install-sh build-aux/missing \ ++ client/wallet.1 config.h.in config.h.in~ configure \ ++ contrib/wallet-report.8 server/keytab-backend.8 \ + server/wallet-admin.8 server/wallet-backend.8 server/wallet-report.8 + + # For each of the Perl scripts, we need to fill in the path to the Perl +@@ -226,17 +227,17 @@ all-local: perl/blib/lib/Wallet/Config.p + + perl/blib/lib/Wallet/Config.pm: $(srcdir)/perl/lib/Wallet/Config.pm + set -e; if [ x"$(builddir)" != x"$(srcdir)" ] ; then \ +- for d in $(PERL_DIRECTORIES) ; do \ ++ for d in $(PERL_DIRECTORIES) ; do \ + [ -d "$(builddir)/$$d" ] || mkdir "$(builddir)/$$d" ; \ +- done ; \ +- for f in $(PERL_FILES) ; do \ ++ done ; \ ++ for f in $(PERL_FILES) ; do \ + cp "$(srcdir)/$$f" "$(builddir)/$$f" ; \ +- done ; \ ++ done ; \ + fi + $(MKDIR_P) perl/t/lib/Test/RRA + $(INSTALL_DATA) $(srcdir)/tests/tap/perl/Test/RRA.pm perl/t/lib/Test/ + $(INSTALL_DATA) $(srcdir)/tests/tap/perl/Test/RRA/Config.pm \ +- perl/t/lib/Test/RRA/ ++ perl/t/lib/Test/RRA/ + cd perl && $(PERL) Build.PL $(WALLET_PERL_FLAGS) + cd perl && ./Build + +@@ -251,13 +252,13 @@ perl/blib/lib/Wallet/Config.pm: $(srcdir + install-data-local: + set -e; flags= ; \ + case "$(prefix)" in \ +- */_inst) flags="--install_base $(prefix)" ;; \ ++ */_inst) flags="--install_base $(prefix)" ;; \ + esac ; \ + cd perl && ./Build install $$flags --destdir '$(DESTDIR)' + + clean-local: + set -e; if [ -f "perl/Build" ] ; then \ +- cd perl && ./Build realclean ; \ ++ cd perl && ./Build realclean ; \ + fi + + # Remove the Autoconf cache. Remove the files that we copy over if and only +@@ -265,9 +266,9 @@ clean-local: + distclean-local: + rm -rf autom4te.cache + set -e; if [ x"$(builddir)" != x"$(srcdir)" ] ; then \ +- for f in $(PERL_FILES) ; do \ ++ for f in $(PERL_FILES) ; do \ + rm -f "$(builddir)/$$f" ; \ +- done ; \ ++ done ; \ + fi + + # The bits below are for the test suite, not for the main package. +@@ -313,8 +314,8 @@ check-local: $(check_PROGRAMS) + # Used by maintainers to check the source code with cppcheck. + check-cppcheck: + cd $(abs_top_srcdir) && cppcheck -q --error-exitcode=2 \ +- --suppressions-list=tests/data/cppcheck.supp \ +- --enable=warning,performance,portability,style . ++ --suppressions-list=tests/data/cppcheck.supp \ ++ --enable=warning,performance,portability,style . + + # Alas, we have to disable this check because there's no way to do an + # uninstall from Perl. +--- a/configure.ac ++++ b/configure.ac +@@ -74,6 +74,9 @@ AC_CHECK_FUNCS([krb5_appdefault_string], + AC_LIBOBJ([krb5-extra]) + RRA_LIB_KRB5_RESTORE + ++dnl Probe for optional libraries ++RRA_LIB_OPENSSL_OPTIONAL ++ + dnl Probe for properties of the C library. + AC_HEADER_STDBOOL + AC_CHECK_HEADERS([strings.h sys/bitypes.h sys/uio.h sys/time.h syslog.h]) +--- /dev/null ++++ b/m4/openssl.m4 +@@ -0,0 +1,115 @@ ++dnl Find the compiler and linker flags for OpenSSL. ++dnl ++dnl Finds the compiler and linker flags for linking with both the OpenSSL SSL ++dnl library and its crypto library. Provides the --with-openssl, ++dnl --with-openssl-lib, and --with-openssl-include configure options to ++dnl specify non-standard paths to the OpenSSL libraries. ++dnl ++dnl Provides the macro RRA_LIB_OPENSSL and sets the substitution variables ++dnl OPENSSL_CPPFLAGS, OPENSSL_LDFLAGS, OPENSSL_LIBS, CRYPTO_CPPFLAGS, ++dnl CRYPTO_LDFLAGS, and CRYPTO_LIBS. Also provides RRA_LIB_OPENSSL_SWITCH and ++dnl RRA_LIB_CRYPTO_SWITCH to set CPPFLAGS, LDFLAGS, and LIBS to include the ++dnl SSL or crypto libraries, saving the current values first, and ++dnl RRA_LIB_OPENSSL_RESTORE and RRA_LIB_CRYPTO_RESTORE to restore those ++dnl settings to before the last RRA_LIB_OPENSSL_SWITCH or ++dnl RRA_LIB_CRYPTO_SWITCH. Defines HAVE_OPENSSL and sets rra_use_OPENSSL to ++dnl true if the library is found. ++dnl ++dnl Provides the RRA_LIB_OPENSSL_OPTIONAL macro, which should be used if ++dnl OpenSSL support is optional. This macro will still set the substitution ++dnl variables and shell variables described above, but they'll be empty unless ++dnl OpenSSL libraries are detected. HAVE_OPENSSL will be defined only if the ++dnl library is found. ++dnl ++dnl Depends on RRA_ENABLE_REDUCED_DEPENDS and the lib-helper.m4 framework. ++dnl ++dnl The canonical version of this file is maintained in the rra-c-util ++dnl package, available at . ++dnl ++dnl Written by Russ Allbery ++dnl Copyright 2016, 2018 Russ Allbery ++dnl Copyright 2010, 2013 ++dnl The Board of Trustees of the Leland Stanford Junior University ++dnl ++dnl This file is free software; the authors give unlimited permission to copy ++dnl and/or distribute it, with or without modifications, as long as this ++dnl notice is preserved. ++dnl ++dnl SPDX-License-Identifier: FSFULLR ++ ++dnl Save the current CPPFLAGS, LDFLAGS, and LIBS settings and switch to ++dnl versions that include the SSL or crypto flags. Used as a wrapper, with ++dnl RRA_LIB_OPENSSL_RESTORE or RRA_LIB_CRYPTO_RESTORE, around tests. ++AC_DEFUN([RRA_LIB_OPENSSL_SWITCH], [RRA_LIB_HELPER_SWITCH([OPENSSL])]) ++AC_DEFUN([RRA_LIB_CRYPTO_SWITCH], [RRA_LIB_HELPER_SWITCH([CRYPTO])]) ++ ++dnl Restore CPPFLAGS, LDFLAGS, and LIBS to their previous values (before ++dnl RRA_LIB_OPENSSL_SWITCH or RRA_LIB_CRYPTO_SWITCH were called). ++AC_DEFUN([RRA_LIB_OPENSSL_RESTORE], [RRA_LIB_HELPER_RESTORE([OPENSSL])]) ++AC_DEFUN([RRA_LIB_CRYPTO_RESTORE], [RRA_LIB_HELPER_RESTORE([CRYPTO])]) ++ ++dnl Check for the OpenSSL and crypto libraries and assemble OPENSSL_LIBS and ++dnl CRYPTO_LIBS. Helper function for _RRA_LIB_OPENSSL_INTERNAL. Must be ++dnl called with RRA_LIB_OPENSSL_SWITCH enabled. ++AC_DEFUN([_RRA_LIB_OPENSSL_INTERNAL_LIBS], ++[rra_openssl_extra= ++ LIBS= ++ AS_IF([test x"$rra_reduced_depends" != xtrue], ++ [AC_SEARCH_LIBS([dlopen], [dl])]) ++ rra_openssl_extra="$LIBS" ++ LIBS="$rra_OPENSSL_save_LIBS" ++ AC_CHECK_LIB([crypto], [AES_cbc_encrypt], ++ [CRYPTO_LIBS="-lcrypto $rra_openssl_extra"], ++ [AS_IF([test x"$1" = xtrue], ++ [AC_MSG_ERROR([cannot find usable OpenSSL crypto library])])], ++ [$rra_openssl_extra]) ++ AS_IF([test x"$rra_reduced_depends" = xtrue], ++ [AC_CHECK_LIB([ssl], [SSL_accept], [OPENSSL_LIBS=-lssl], ++ [AS_IF([test x"$1" = xtrue], ++ [AC_MSG_ERROR([cannot find usable OpenSSL library])])])], ++ [AC_CHECK_LIB([ssl], [SSL_accept], ++ [OPENSSL_LIBS="-lssl $CRYPTO_LIBS"], ++ [AS_IF([test x"$1" = xtrue], ++ [AC_MSG_ERROR([cannot find usable OpenSSL library])])], ++ [$CRYPTO_LIBS])])]) ++ ++dnl Checks if the OpenSSL header and OpenSSL and crypto libraries are present. ++dnl The single argument, if "true", says to fail if the OpenSSL SSL library ++dnl could not be found. ++AC_DEFUN([_RRA_LIB_OPENSSL_INTERNAL], ++[AC_REQUIRE([RRA_ENABLE_REDUCED_DEPENDS]) ++ RRA_LIB_HELPER_PATHS([OPENSSL]) ++ CRYPTO_CPPFLAGS="$OPENSSL_CPPFLAGS" ++ CRYPTO_LDFLAGS="$OPENSSL_LDFLAGS" ++ CRYPTO_LIBS= ++ AC_SUBST([CRYPTO_CPPFLAGS]) ++ AC_SUBST([CRYPTO_LDFLAGS]) ++ AC_SUBST([CRYPTO_LIBS]) ++ RRA_LIB_OPENSSL_SWITCH ++ AC_CHECK_HEADER([openssl/ssl.h], ++ [_RRA_LIB_OPENSSL_INTERNAL_LIBS([$1])], ++ [AS_IF([test x"$1" = xtrue], ++ [AC_MSG_ERROR([cannot find usable OpenSSL header])])]) ++ RRA_LIB_OPENSSL_RESTORE]) ++ ++dnl The main macro for packages with mandatory OpenSSL support. ++AC_DEFUN([RRA_LIB_OPENSSL], ++[RRA_LIB_HELPER_VAR_INIT([OPENSSL]) ++ RRA_LIB_HELPER_WITH([openssl], [OpenSSL], [OPENSSL]) ++ _RRA_LIB_OPENSSL_INTERNAL([true]) ++ rra_use_OPENSSL=true ++ AC_DEFINE([HAVE_OPENSSL], 1, [Define if libssl is available.])]) ++ ++dnl The main macro for packages with optional OpenSSL support. ++AC_DEFUN([RRA_LIB_OPENSSL_OPTIONAL], ++[RRA_LIB_HELPER_VAR_INIT([OPENSSL]) ++ RRA_LIB_HELPER_WITH_OPTIONAL([openssl], [OpenSSL], [OPENSSL]) ++ AS_IF([test x"$rra_use_OPENSSL" != xfalse], ++ [AS_IF([test x"$rra_use_OPENSSL" = xtrue], ++ [_RRA_LIB_OPENSSL_INTERNAL([true])], ++ [_RRA_LIB_OPENSSL_INTERNAL([false])])]) ++ AS_IF([test x"$OPENSSL_LIBS" = x], ++ [RRA_LIB_HELPER_VAR_CLEAR([OPENSSL]) ++ RRA_LIB_HELPER_VAR_CLEAR([CRYPTO])], ++ [rra_use_OPENSSL=true ++ AC_DEFINE([HAVE_OPENSSL], 1, [Define if libssl is available.])])]) +--- /dev/null ++++ b/m4/lib-helper.m4 +@@ -0,0 +1,149 @@ ++dnl Helper functions to manage compiler variables. ++dnl ++dnl These are a wide variety of helper macros to make it easier to construct ++dnl standard macros to probe for a library and to set library-specific ++dnl CPPFLAGS, LDFLAGS, and LIBS shell substitution variables. Most of them ++dnl take as one of the arguments the prefix string to use for variables, which ++dnl is usually something like "KRB5" or "GSSAPI". ++dnl ++dnl Depends on RRA_SET_LDFLAGS. ++dnl ++dnl The canonical version of this file is maintained in the rra-c-util ++dnl package, available at . ++dnl ++dnl Written by Russ Allbery ++dnl Copyright 2018 Russ Allbery ++dnl Copyright 2011, 2013 ++dnl The Board of Trustees of the Leland Stanford Junior University ++dnl ++dnl This file is free software; the authors give unlimited permission to copy ++dnl and/or distribute it, with or without modifications, as long as this ++dnl notice is preserved. ++dnl ++dnl SPDX-License-Identifier: FSFULLR ++ ++dnl Add the library flags to the default compiler flags and then remove them. ++dnl ++dnl To use these macros, pass the prefix string used for the variables as the ++dnl only argument. For example, to use these for a library with KRB5 as a ++dnl prefix, one would use: ++dnl ++dnl AC_DEFUN([RRA_LIB_KRB5_SWITCH], [RRA_LIB_HELPER_SWITCH([KRB5])]) ++dnl AC_DEFUN([RRA_LIB_KRB5_RESTORE], [RRA_LIB_HELPER_RESTORE([KRB5])]) ++dnl ++dnl Then, wrap checks for library features with RRA_LIB_KRB5_SWITCH and ++dnl RRA_LIB_KRB5_RESTORE. ++AC_DEFUN([RRA_LIB_HELPER_SWITCH], ++[rra_$1[]_save_CPPFLAGS="$CPPFLAGS" ++ rra_$1[]_save_LDFLAGS="$LDFLAGS" ++ rra_$1[]_save_LIBS="$LIBS" ++ CPPFLAGS="$$1[]_CPPFLAGS $CPPFLAGS" ++ LDFLAGS="$$1[]_LDFLAGS $LDFLAGS" ++ LIBS="$$1[]_LIBS $LIBS"]) ++ ++AC_DEFUN([RRA_LIB_HELPER_RESTORE], ++[CPPFLAGS="$rra_$1[]_save_CPPFLAGS" ++ LDFLAGS="$rra_$1[]_save_LDFLAGS" ++ LIBS="$rra_$1[]_save_LIBS"]) ++ ++dnl Given _root, _libdir, and _includedir variables set for a library (set by ++dnl RRA_LIB_HELPER_WITH*), set the LDFLAGS and CPPFLAGS variables for that ++dnl library accordingly. Takes the variable prefix as the only argument. ++AC_DEFUN([RRA_LIB_HELPER_PATHS], ++[AS_IF([test x"$rra_$1[]_libdir" != x], ++ [$1[]_LDFLAGS="-L$rra_$1[]_libdir"], ++ [AS_IF([test x"$rra_$1[]_root" != x], ++ [RRA_SET_LDFLAGS([$1][_LDFLAGS], [${rra_$1[]_root}])])]) ++ AS_IF([test x"$rra_$1[]_includedir" != x], ++ [$1[]_CPPFLAGS="-I$rra_$1[]_includedir"], ++ [AS_IF([test x"$rra_$1[]_root" != x], ++ [AS_IF([test x"$rra_$1[]_root" != x/usr], ++ [$1[]_CPPFLAGS="-I${rra_$1[]_root}/include"])])])]) ++ ++dnl Check whether a library works. This is used as a sanity check on the ++dnl results of *-config shell scripts. Takes four arguments; the first, if ++dnl "true", says that a working library is mandatory and errors out if it ++dnl doesn't. The second is the variable prefix. The third is a function to ++dnl look for that should be in the libraries. The fourth is the ++dnl human-readable name of the library for error messages. ++AC_DEFUN([RRA_LIB_HELPER_CHECK], ++[RRA_LIB_HELPER_SWITCH([$2]) ++ AC_CHECK_FUNC([$3], [], ++ [AS_IF([test x"$1" = xtrue], ++ [AC_MSG_FAILURE([unable to link with $4 library])]) ++ $2[]_CPPFLAGS= ++ $2[]_LDFLAGS= ++ $2[]_LIBS=]) ++ RRA_LIB_HELPER_RESTORE([$2])]) ++ ++dnl Initialize the variables used by a library probe and set the appropriate ++dnl ones as substitution variables. Takes the library variable prefix as its ++dnl only argument. ++AC_DEFUN([RRA_LIB_HELPER_VAR_INIT], ++[rra_$1[]_root= ++ rra_$1[]_libdir= ++ rra_$1[]_includedir= ++ rra_use_$1= ++ $1[]_CPPFLAGS= ++ $1[]_LDFLAGS= ++ $1[]_LIBS= ++ AC_SUBST([$1][_CPPFLAGS]) ++ AC_SUBST([$1][_LDFLAGS]) ++ AC_SUBST([$1][_LIBS])]) ++ ++dnl Unset all of the variables used by a library probe. Used with the ++dnl _OPTIONAL versions of header probes when a header or library wasn't found ++dnl and therefore the library isn't usable. ++AC_DEFUN([RRA_LIB_HELPER_VAR_CLEAR], ++[$1[]_CPPFLAGS= ++ $1[]_LDFLAGS= ++ $1[]_LIBS=]) ++ ++dnl Handles --with options for a non-optional library. First argument is the ++dnl base for the switch names. Second argument is the short description. ++dnl Third argument is the variable prefix. The variables set are used by ++dnl RRA_LIB_HELPER_PATHS. ++AC_DEFUN([RRA_LIB_HELPER_WITH], ++[AC_ARG_WITH([$1], ++ [AS_HELP_STRING([--with-][$1][=DIR], ++ [Location of $2 headers and libraries])], ++ [AS_IF([test x"$withval" != xyes && test x"$withval" != xno], ++ [rra_$3[]_root="$withval"])]) ++ AC_ARG_WITH([$1][-include], ++ [AS_HELP_STRING([--with-][$1][-include=DIR], ++ [Location of $2 headers])], ++ [AS_IF([test x"$withval" != xyes && test x"$withval" != xno], ++ [rra_$3[]_includedir="$withval"])]) ++ AC_ARG_WITH([$1][-lib], ++ [AS_HELP_STRING([--with-][$1][-lib=DIR], ++ [Location of $2 libraries])], ++ [AS_IF([test x"$withval" != xyes && test x"$withval" != xno], ++ [rra_$3[]_libdir="$withval"])])]) ++ ++dnl Handles --with options for an optional library, so --with- can ++dnl cause the checks to be skipped entirely or become mandatory. Sets an ++dnl rra_use_PREFIX variable to true or false if the library is explicitly ++dnl enabled or disabled. ++dnl ++dnl First argument is the base for the switch names. Second argument is the ++dnl short description. Third argument is the variable prefix. ++dnl ++dnl The variables set are used by RRA_LIB_HELPER_PATHS. ++AC_DEFUN([RRA_LIB_HELPER_WITH_OPTIONAL], ++[AC_ARG_WITH([$1], ++ [AS_HELP_STRING([--with-][$1][@<:@=DIR@:>@], ++ [Location of $2 headers and libraries])], ++ [AS_IF([test x"$withval" = xno], ++ [rra_use_$3=false], ++ [AS_IF([test x"$withval" != xyes], [rra_$3[]_root="$withval"]) ++ rra_use_$3=true])]) ++ AC_ARG_WITH([$1][-include], ++ [AS_HELP_STRING([--with-][$1][-include=DIR], ++ [Location of $2 headers])], ++ [AS_IF([test x"$withval" != xyes && test x"$withval" != xno], ++ [rra_$3[]_includedir="$withval"])]) ++ AC_ARG_WITH([$1][-lib], ++ [AS_HELP_STRING([--with-][$1][-lib=DIR], ++ [Location of $2 libraries])], ++ [AS_IF([test x"$withval" != xyes && test x"$withval" != xno], ++ [rra_$3[]_libdir="$withval"])])]) From 12f40e69292644d5d11cf4eda86357687054808b Mon Sep 17 00:00:00 2001 From: Bill MacAllister Date: Tue, 7 Jul 2020 00:41:35 +0000 Subject: [PATCH 29/47] Correct syntax and POD errors introduced in the 0015 patch --- debian/patches/0015-encryption-fixes.patch | 44 ++++++++++++---------- 1 file changed, 25 insertions(+), 19 deletions(-) diff --git a/debian/patches/0015-encryption-fixes.patch b/debian/patches/0015-encryption-fixes.patch index fd63a58a..3fc7c82e 100644 --- a/debian/patches/0015-encryption-fixes.patch +++ b/debian/patches/0015-encryption-fixes.patch @@ -1,11 +1,16 @@ --- a/perl/lib/Wallet/Object/File.pm +++ b/perl/lib/Wallet/Object/File.pm -@@ -123,13 +123,39 @@ sub _get_crypt_key { +@@ -119,17 +119,44 @@ sub _get_crypt_key { + return $return_val; + } + ++ my $msg = "\n"; ++ + # ldap:///basedn?attr?scope?filter my $url = $Wallet::Config::LDAP_SECRET; $url =~ s{^ldap:///}{}xmsi; if ($url eq $Wallet::Config::LDAP_SECRET) { - die("ERROR: Invalid LDAP URL $url"); -+ my $msg = "\n" + $msg .= "INFO: LDAP_SECRET contains a hostname\n"; + $msg .= "ERROR: Invalid LDAP_SECRET URL $url\n"; + die $msg; @@ -33,15 +38,15 @@ + } + + # Search details just in case they have to be displayed -+ my $msg = "\n"; -+ $msg .= "INFO: base = $base\n"; -+ $msg .= "INFO: filter = $filter\n"; -+ $msg .= "INFO: scope = $scope\n"; -+ $msg .= "INFO: attribute = $attr\n"; ++ my $search_details = "\n"; ++ $search_details .= "INFO: base = $base\n"; ++ $search_details .= "INFO: filter = $filter\n"; ++ $search_details .= "INFO: scope = $scope\n"; ++ $search_details .= "INFO: attribute = $attr\n"; # Search for the secret in the LDAP directory my $ldap_obj = Wallet::ACL::LDAP::Attribute->new; -@@ -145,17 +171,23 @@ sub _get_crypt_key { +@@ -145,17 +172,23 @@ sub _get_crypt_key { if ($search->count == 1) { $entry = $search->pop_entry; } elsif ($search->count > 1) { @@ -51,8 +56,8 @@ + die $msg; } else { - die "ERROR: No entry found for $url"; -+ my $msg = $search_details; -+ $msg .= "ERROR: No entry found for $url\n"; ++ my $msg .= $search_details; ++ $msg .= "ERROR: No entry found for $url\n"; + die $msg; } }; @@ -70,7 +75,7 @@ } my $return_val; -@@ -168,11 +200,15 @@ sub _get_crypt_key { +@@ -168,11 +201,15 @@ sub _get_crypt_key { } } if (!$return_val) { @@ -88,7 +93,7 @@ } return $return_val; } -@@ -184,7 +220,7 @@ sub _file_crypt { +@@ -184,7 +221,7 @@ sub _file_crypt { require MIME::Base64; my $return_string; @@ -97,7 +102,7 @@ my $cipher = Crypt::CBC->new( -key => $key, -@@ -219,6 +255,12 @@ sub file_decrypt { +@@ -219,6 +256,12 @@ sub file_decrypt { if (defined (&Wallet::Config::file_crypt)) { $undata = Wallet::Config::file_crypt('decrypt', $key, $data); } else { @@ -110,7 +115,7 @@ $undata = $self->_file_crypt('decrypt', $key, $data); } if ($undata eq $data) { -@@ -234,6 +276,12 @@ sub file_encrypt { +@@ -234,6 +277,12 @@ sub file_encrypt { if (defined (&Wallet::Config::file_crypt)) { $endata = Wallet::Config::file_crypt('encrypt', $key, $data); } else { @@ -123,7 +128,7 @@ $endata = $self->_file_crypt('encrypt', $key, $data); } return $endata; -@@ -276,7 +324,7 @@ sub get { +@@ -276,7 +325,7 @@ sub get { $self->error ("cannot get $id: $!"); return; } @@ -132,7 +137,7 @@ $data = $self->file_decrypt($data, $user, $host, $time); } $self->log_action ('get', $user, $host, $time); -@@ -296,7 +344,7 @@ sub checksum { +@@ -296,7 +345,7 @@ sub checksum { my $this_checksum; my $this_data; my $this_endata = read_file($path); @@ -141,7 +146,7 @@ $this_data = $self->file_decrypt($this_endata, $user, $host, $time) } else { $this_data = $this_endata; -@@ -326,7 +374,7 @@ sub store { +@@ -326,7 +375,7 @@ sub store { return; } } @@ -192,14 +197,15 @@ =back =head2 LDAP Principal Mapping -@@ -1112,7 +1100,25 @@ as a base64 string. +@@ -1112,7 +1100,26 @@ as a base64 string. return $cs; } -=head1 ENCRYPTION METHODS +=head1 ENCRYPTION CONFIGURATION AND METHODS + -+=over4 ++=over 4 ++ +=item ENCRYPTION_PREFIX + +Specifies the prefix to be used when generating storing an encrypted From 6ed033dc31100b20a881999161aa6da0d15e5e68 Mon Sep 17 00:00:00 2001 From: Bill MacAllister Date: Tue, 7 Jul 2020 06:47:33 +0000 Subject: [PATCH 30/47] Update wallet client checkfile processing * Update command line checking to allow checkfile to specify -f. * Fail if the checkfile command does not include -f. --- debian/patches/0016-update-command.patch | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/debian/patches/0016-update-command.patch b/debian/patches/0016-update-command.patch index 3df54469..245429a1 100644 --- a/debian/patches/0016-update-command.patch +++ b/debian/patches/0016-update-command.patch @@ -140,7 +140,28 @@ +} --- a/client/wallet.c +++ b/client/wallet.c -@@ -172,6 +172,14 @@ main(int argc, char *argv[]) +@@ -124,9 +124,18 @@ main(int argc, char *argv[]) + usage(1); + + /* -f is only supported for get and store and -S with get keytab. */ +- if (file != NULL) +- if (strcmp(argv[0], "get") != 0 && strcmp(argv[0], "store") != 0) ++ if (file != NULL) { ++ if (strcmp(argv[0], "get") != 0 && ++ strcmp(argv[0], "store") != 0 && ++ strcmp(argv[0], "checkfile") != 0) ++ { + die("-f only supported for get and store"); ++ } ++ } else { ++ if (strcmp(argv[0], "checkfile") == 0) ++ die("-f is required by checkfile"); ++ } ++ + if (srvtab != NULL) { + if (strcmp(argv[0], "get") != 0 || strcmp(argv[1], "keytab") != 0) + die("-S only supported for get keytab"); +@@ -172,6 +181,14 @@ main(int argc, char *argv[]) if (argc > 2) die("too many arguments"); status = rekey_keytab(r, ctx, options.type, argv[1]); From 2962c9f9966c7f897cc8145db920d838a7f3d254 Mon Sep 17 00:00:00 2001 From: Bill MacAllister Date: Wed, 15 Jul 2020 17:23:08 +0000 Subject: [PATCH 31/47] checkfile changes * Correct code indent * Correct condition code blocks. Add explicit blocks, i.e. {}. * Restrict the checksum compare to the length of the checksum value. --- debian/gbp.conf | 2 +- debian/patches/0016-update-command.patch | 66 +++++++++++++----------- 2 files changed, 36 insertions(+), 32 deletions(-) diff --git a/debian/gbp.conf b/debian/gbp.conf index 0488dcd2..91fbaee2 100644 --- a/debian/gbp.conf +++ b/debian/gbp.conf @@ -2,7 +2,7 @@ # upstream development using the DEP-14 layout. [DEFAULT] -debian-branch = ubuntu/master +debian-branch = ubuntu/debugging upstream-branch = upstream/latest pristine-tar = True diff --git a/debian/patches/0016-update-command.patch b/debian/patches/0016-update-command.patch index 245429a1..e4aa2702 100644 --- a/debian/patches/0016-update-command.patch +++ b/debian/patches/0016-update-command.patch @@ -1,6 +1,6 @@ --- /dev/null +++ b/client/checkfile.c -@@ -0,0 +1,137 @@ +@@ -0,0 +1,141 @@ +/* + * Test file object checksum against a file on the system + * @@ -36,19 +36,19 @@ + MD5_Init(&c); + + while (length > 0) { -+ if (length > 512) { -+ MD5_Update(&c, str, 512); -+ } else { -+ MD5_Update(&c, str, length); -+ } -+ length -= 512; -+ str += 512; ++ if (length > 512) { ++ MD5_Update(&c, str, 512); ++ } else { ++ MD5_Update(&c, str, length); ++ } ++ length -= 512; ++ str += 512; + } + + MD5_Final(digest, &c); + + for (n = 0; n < 16; ++n) { -+ snprintf(&(out[n*2]), 16*2, "%02x", (unsigned int)digest[n]); ++ snprintf(&(out[n*2]), 16*2, "%02x", (unsigned int)digest[n]); + } + + return out; @@ -70,28 +70,28 @@ + + fd = open(name, O_RDONLY); + if (fd < 0) -+ return NULL; ++ return NULL; + if (fstat(fd, &st) < 0) -+ return NULL; ++ return NULL; + size = st.st_size; + contents = xmalloc(size); + + offset = 0; + do { -+ if (offset >= size - 1) { -+ size += BUFSIZ; -+ contents = xrealloc(contents, size); -+ } -+ do { -+ status = read(fd, contents + offset, size - offset - 1); -+ } while (status == -1 && errno == EINTR); -+ if (status < 0) -+ sysdie("cannot read from file"); -+ offset += status; ++ if (offset >= size - 1) { ++ size += BUFSIZ; ++ contents = xrealloc(contents, size); ++ } ++ do { ++ status = read(fd, contents + offset, size - offset - 1); ++ } while (status == -1 && errno == EINTR); ++ if (status < 0) ++ sysdie("cannot read from file"); ++ offset += status; + } while (status > 0); + close(fd); + if (length != NULL) -+ *length = offset; ++ *length = offset; + return contents; +} + @@ -115,8 +115,9 @@ + + /* Check to see if the file exists. It not return mismatch status */ + file_data = checkfile_read_file(file, &length); -+ if (file_data == NULL) -+ return 1; ++ if (file_data == NULL) { ++ return 1; ++ } + + command[0] = prefix; + command[1] = "checksum"; @@ -124,19 +125,22 @@ + command[3] = name; + command[4] = NULL; + status = run_command(r, command, &wallet_checksum, &wallet_length); -+ if (status != 0) -+ return status; ++ if (status != 0) { ++ return status; ++ } + + /* If the wallet object is empty or NULL return mismatch and let the + * subsequent call to file handle the error condition of an empty + * file object. + */ -+ if ((wallet_length == 0) || (wallet_checksum == NULL)) -+ return 1; ++ if ((wallet_length == 0) || (wallet_checksum == NULL)) { ++ return 1; ++ } + -+ file_checksum = checkfile_str2md5(file_data, strlen(file_data)); ++ file_checksum = checkfile_str2md5(file_data, length); ++ status = strncmp(file_checksum, wallet_checksum, wallet_length); + -+ return strcmp(file_checksum, wallet_checksum); ++ return status; +} --- a/client/wallet.c +++ b/client/wallet.c @@ -171,7 +175,7 @@ + if (strcmp(argv[1], "keytab") == 0) + die("checkfile command is not valid for keytabs"); + status = checkfile(r, options.type, argv[1], argv[2], file); -+ if (status > 0) ++ if (status != 0) + status = get_file(r, options.type, argv[1], argv[2], file); } else { count = argc + 1; From 40e15baad3a7930884394dcfa2ee0d33a6717631 Mon Sep 17 00:00:00 2001 From: Bill MacAllister Date: Thu, 16 Jul 2020 16:15:26 +0000 Subject: [PATCH 32/47] Merge in updated checkfile patch from the debugging branch --- debian/gbp.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/gbp.conf b/debian/gbp.conf index 91fbaee2..0488dcd2 100644 --- a/debian/gbp.conf +++ b/debian/gbp.conf @@ -2,7 +2,7 @@ # upstream development using the DEP-14 layout. [DEFAULT] -debian-branch = ubuntu/debugging +debian-branch = ubuntu/master upstream-branch = upstream/latest pristine-tar = True From d6a268304f90c5367c218599641fae7a86dfc10d Mon Sep 17 00:00:00 2001 From: Bill MacAllister Date: Thu, 16 Jul 2020 16:18:16 +0000 Subject: [PATCH 33/47] Rename the patch that implements checkfile --- .../patches/{0016-update-command.patch => 0016-checkfile.patch} | 0 debian/patches/series | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename debian/patches/{0016-update-command.patch => 0016-checkfile.patch} (100%) diff --git a/debian/patches/0016-update-command.patch b/debian/patches/0016-checkfile.patch similarity index 100% rename from debian/patches/0016-update-command.patch rename to debian/patches/0016-checkfile.patch diff --git a/debian/patches/series b/debian/patches/series index e7b6348a..c3289a4a 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -13,4 +13,4 @@ 0013-crypt-fixup.patch 0014-crypt-custom.patch 0015-encryption-fixes.patch -0016-update-command.patch +0016-checkfile.patch From d9ede46e750a6a19fff5250d9ab97bbe6608f63d Mon Sep 17 00:00:00 2001 From: Bill MacAllister Date: Thu, 16 Jul 2020 16:56:09 +0000 Subject: [PATCH 34/47] Update Debian version for package release --- debian/changelog | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/debian/changelog b/debian/changelog index f5f7f66c..69ac2e3b 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,11 @@ +wallet (1.4-7) unstable; urgency=medium + + * Add the checkfile command to the wallet client. checkfile uses + md5 checksums to determine if a file/password object has changed + and performs a get only if the object has changed. + + -- Bill MacAllister Thu, 16 Jul 2020 16:55:34 +0000 + wallet (1.4-6) unstable; urgency=medium * Rename the configuratiion variable LDAP_SECRET_PREFIX to From d93cc373dc2ffb9a38d0ea96c3f5deecece6abdd Mon Sep 17 00:00:00 2001 From: Bill MacAllister Date: Thu, 16 Jul 2020 17:03:38 +0000 Subject: [PATCH 35/47] Update the gbp configuration for debian/master --- debian/gbp.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/gbp.conf b/debian/gbp.conf index 0488dcd2..224e7974 100644 --- a/debian/gbp.conf +++ b/debian/gbp.conf @@ -2,7 +2,7 @@ # upstream development using the DEP-14 layout. [DEFAULT] -debian-branch = ubuntu/master +debian-branch = debian/master upstream-branch = upstream/latest pristine-tar = True From 704407e1796645f9e1afc072e5c4d6a7b1abbd25 Mon Sep 17 00:00:00 2001 From: Bill MacAllister Date: Mon, 14 Dec 2020 19:37:25 +0000 Subject: [PATCH 36/47] Update client man page, suppress spurious check file warning * The POD was updated with the original checkfile changes, but a new man page was not generated. This change updates the man page for the client. * When issuing a checkfile command against an password object that exists but has not been stored yet a warning message was being generated. This warning is confusing since the command succeeds since the password is generated and downloaded. --- debian/patches/0017-checkfile.patch | 77 +++++++++++++++++++++++++++++ debian/patches/series | 1 + 2 files changed, 78 insertions(+) create mode 100644 debian/patches/0017-checkfile.patch diff --git a/debian/patches/0017-checkfile.patch b/debian/patches/0017-checkfile.patch new file mode 100644 index 00000000..166c7b94 --- /dev/null +++ b/debian/patches/0017-checkfile.patch @@ -0,0 +1,77 @@ +Update client man page, suppress spurious check file warning + +* The POD was updated with the original checkfile changes, but a + new man page was not generated. This change updates the man page + for the client. + +* When issuing a checkfile command against an password object that + exists but has not been stored yet a warning message was being + generated. This warning is confusing since the command succeeds + since the password is generated and downloaded. +--- a/client/wallet.1 ++++ b/client/wallet.1 +@@ -129,7 +129,7 @@ + .\" ======================================================================== + .\" + .IX Title "WALLET 1" +-.TH WALLET 1 "2018-06-04" "1.4" "wallet" ++.TH WALLET 1 "2020-12-14" "perl v5.26.1" "User Contributed Perl Documentation" + .\" For nroff, turn off justification. Always turn off hyphenation; it makes + .\" way too many mistakes in technical documents. + .if n .ad l +@@ -291,7 +291,15 @@ For more information on attributes, see + .IP "acl add " 4 + .IX Item "acl add " + Add an entry with and to the \s-1ACL\s0 . may be +-either the name of an \s-1ACL\s0 or its numeric identifier. ++either the name of an \s-1ACL\s0 or its numeric identifier. Three schemes are ++supported: krb5, netdb, and ldap-attr. The netdb and ldap-attr must ++be configured before they can be used. Examples: ++.Sp ++.Vb 3 ++\& wallet acl add config/db krb5 mac@CA\-ZEPHYR.ORG ++\& wallet acl add config/db netdb host/keddie.ca\-zephyr.org ++\& wallet acl add config/db ldap\-attr czPrivilegeGroup=admin ++.Ve + .IP "acl check " 4 + .IX Item "acl check " + Check whether an \s-1ACL\s0 with the \s-1ID\s0 already exists. If it does, prints +@@ -356,6 +364,15 @@ already exist. + .IX Item "check " + Check whether an object of type and name already exists. If + it does, prints \f(CW\*(C`yes\*(C'\fR; if not, prints \f(CW\*(C`no\*(C'\fR. ++.IP "checkfile " 4 ++.IX Item "checkfile " ++Preforms a get command only if the wallet object checksum differs from ++the checksum of the file specified. The \-f switch must be specified. ++This command is not valid for keytabs and the wallet object must have ++been stored. ++.IP "checksum " 4 ++.IX Item "checksum " ++Returns the checksum for file objects. + .IP "comment []" 4 + .IX Item "comment []" + If is not given, displays the current comment for the object +@@ -474,7 +491,7 @@ will attempt to automatically create it + .IX Item "update " + Prints to standard output the data associated with the object identified + by and , or stores it in a file if the \fB\-f\fR option was +-given. This will generate new data in the object, and only works for ++given. This will generate new data in the object, and only works for + objects that support generating new data automatically, such as keytabs or + passwords. Types that do not support generating new data will fail and + direct you to use get instead. +--- a/perl/lib/Wallet/Object/File.pm ++++ b/perl/lib/Wallet/Object/File.pm +@@ -344,7 +344,10 @@ sub checksum { + my $path = $self->file_path; + my $this_checksum; + my $this_data; +- my $this_endata = read_file($path); ++ my $this_endata; ++ if (-e $path) { ++ $this_endata = read_file($path); ++ } + if ($Wallet::Config::ENCRYPTION_PREFIX) { + $this_data = $self->file_decrypt($this_endata, $user, $host, $time) + } else { diff --git a/debian/patches/series b/debian/patches/series index c3289a4a..41ac9c7b 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -14,3 +14,4 @@ 0014-crypt-custom.patch 0015-encryption-fixes.patch 0016-checkfile.patch +0017-checkfile.patch From e94aaf3170b0d9dc4f5bc3c7063c121a40da928e Mon Sep 17 00:00:00 2001 From: Bill MacAllister Date: Mon, 14 Dec 2020 19:39:48 +0000 Subject: [PATCH 37/47] Update changelog with checkfile fixes * The POD was updated with the original checkfile changes, but a new man page was not generated. This change updates the man page for the client. * When issuing a checkfile command against an password object that exists but has not been stored yet a warning message was being generated. This warning is confusing since the command succeeds since the password is generated and downloaded. --- debian/changelog | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/debian/changelog b/debian/changelog index 69ac2e3b..ca817ace 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,16 @@ +wallet (1.4-8) unstable; urgency=medium + + * Updates to checkfile support. + - The POD was updated with the original checkfile changes, but a + new man page was not generated. This change updates the man page + for the client. + - When issuing a checkfile command against an password object that + exists but has not been stored yet a warning message was being + generated. This warning is confusing since the command succeeds + since the password is generated and downloaded. + + -- Bill MacAllister Mon, 14 Dec 2020 19:39:40 +0000 + wallet (1.4-7) unstable; urgency=medium * Add the checkfile command to the wallet client. checkfile uses From 48c4ee46e6f5b80210ff778fa4b03dc3fb55e748 Mon Sep 17 00:00:00 2001 From: Bill MacAllister Date: Mon, 16 Aug 2021 18:17:51 +0000 Subject: [PATCH 38/47] Correct an AD default * Correct the default value used for the maximum of a "computer name" used when creating AD keytabs. --- debian/changelog | 7 + debian/patches/0018-ad-length.patch | 36 ++ debian/patches/series | 1 + perl/lib/Wallet/Kadmin/AD.pm | 554 ---------------------------- 4 files changed, 44 insertions(+), 554 deletions(-) create mode 100644 debian/patches/0018-ad-length.patch delete mode 100644 perl/lib/Wallet/Kadmin/AD.pm diff --git a/debian/changelog b/debian/changelog index ca817ace..49794776 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,10 @@ +wallet (1.4-9) unstable; urgency=medium + + * Correct the default value used for the maximum of a "computer + name" used when creating AD keytabs. + + -- Bill MacAllister Mon, 16 Aug 2021 18:17:30 +0000 + wallet (1.4-8) unstable; urgency=medium * Updates to checkfile support. diff --git a/debian/patches/0018-ad-length.patch b/debian/patches/0018-ad-length.patch new file mode 100644 index 00000000..fe5c0d0a --- /dev/null +++ b/debian/patches/0018-ad-length.patch @@ -0,0 +1,36 @@ +--- a/contrib/ad-keytab ++++ b/contrib/ad-keytab +@@ -3,7 +3,7 @@ + # Create, update, delete, and display keytabs stored in Active Directory. + # + # Written by Bill MacAllister +-# Copyright 2016 Dropbox, Inc. ++# Copyright 2016-21 Dropbox, Inc. + # + # SPDX-License-Identifier: MIT + +@@ -227,7 +227,7 @@ sub kerberos_attrs { + $attr{cn} =~ s/.*?=//xms; + } + } else { +- if (length($attr{cn})>20) { ++ if (length($attr{cn})>19) { + my $cnt = 0; + my $this_dn; + my $this_prefix = substr($attr{cn}, 0, 18); +--- a/perl/lib/Wallet/Config.pm ++++ b/perl/lib/Wallet/Config.pm +@@ -508,11 +508,11 @@ The maximum length of a unique identifie + Directory keytab objects. If the identifier exceeds this length then it will + be truncated and an integer will be appended to the end of the identifier. + This parameter is here in hopes that at some point in the future Microsoft +-will remove the limitation. ++will remove the limitation. The default value is 19. + + =cut + +-our $AD_SERVICE_LENGTH = '20'; ++our $AD_SERVICE_LENGTH = '19'; + + =item AD_SERVICE_LIMIT + diff --git a/debian/patches/series b/debian/patches/series index 41ac9c7b..5bb9a9f2 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -15,3 +15,4 @@ 0015-encryption-fixes.patch 0016-checkfile.patch 0017-checkfile.patch +0018-ad-length.patch diff --git a/perl/lib/Wallet/Kadmin/AD.pm b/perl/lib/Wallet/Kadmin/AD.pm deleted file mode 100644 index f2f86b9b..00000000 --- a/perl/lib/Wallet/Kadmin/AD.pm +++ /dev/null @@ -1,554 +0,0 @@ -# Wallet::Kadmin::AD -- Wallet Kerberos administration API for AD -# -# Written by Bill MacAllister -# Copyright 2016, 2018 Russ Allbery -# Copyright 2015-2016 Dropbox, Inc. -# Copyright 2007-2010, 2014 -# The Board of Trustees of the Leland Stanford Junior University -# -# SPDX-License-Identifier: MIT - -############################################################################## -# Modules and declarations -############################################################################## - -package Wallet::Kadmin::AD; - -use 5.008; -use strict; -use warnings; - -use Authen::SASL; -use Net::LDAP; -use IPC::Run qw(run timeout); -use Sys::Syslog qw(:standard :macros); -use Wallet::Config; -use Wallet::Kadmin; - -our @ISA = qw(Wallet::Kadmin); -our $VERSION = '1.04'; - -my $LDAP; - -############################################################################## -# kadmin Interaction -############################################################################## - -# Send debugging output to syslog. - -sub ad_syslog { - my ($self, $l, $m) = @_; - if (!$self->{SYSLOG}) { - openlog('wallet-server', 'ndelay,nofatal', 'local3'); - $self->{SYSLOG} = 1; - } - if ($l !~ /^(debug|info|err|warning)$/xms) { - $l = 'err'; - } - syslog($l, $m); - return; -} - -# Return a string given an array whose elements are command line arguments -# passws to IPC::Run. Quote any strings that have embedded spaces. Replace -# null elements with the string #NULL#. - -sub ad_cmd_string { - my ($self, $cmd_ref) = @_; - my $z = ''; - my $ws = ' '; - for my $e (@{ $cmd_ref }) { - if (!$e) { - $z .= $ws . '#NULL#'; - } elsif ($e =~ /\s/xms) { - $z .= $ws . '"' . $e . '"'; - } else { - $z .= $ws . $e; - } - $ws = ' '; - } - return $z; -} - -# Make sure that principals are well-formed and don't contain -# characters that will cause us problems when talking to kadmin. -# Takes a principal and returns true if it's okay, false otherwise. -# Note that we do not permit realm information here. -sub valid_principal { - my ($self, $principal) = @_; - return scalar ($principal =~ m,^[\w-]+(/[\w_.-]+)?\z,); -} - -# Connect to the Active Directory server using LDAP. The connection is -# used to retrieve information about existing keytabs since msktutil -# does not have this functionality. -sub ldap_connect { - my ($self) = @_; - - if (!$LDAP) { - eval { - local $ENV{KRB5CCNAME} = $Wallet::Config::AD_CACHE; - my $sasl = Authen::SASL->new(mechanism => 'GSSAPI'); - $LDAP = Net::LDAP->new($Wallet::Config::KEYTAB_HOST, - onerror => 'die'); - my $mesg = eval { $LDAP->bind(undef, sasl => $sasl) }; - }; - if ($@) { - my $error = $@; - chomp $error; - 1 while ($error =~ s/ at \S+ line \d+\.?\z//); - die "LDAP bind to AD failed: $error\n"; - } - } - return $LDAP; -} - -# Construct a base filter for searching Active Directory. - -sub ldap_base_filter { - my ($self, $principal) = @_; - - my $base; - my $filter; - my $this_type; - my $this_id; - - if ($principal =~ m,^(.*?)/(\S+),xms) { - $this_type = $1; - $this_id = $2; - } else { - $this_id = $principal; - } - - # Create a filter to find the objects we create - if ($this_id =~ s/@(.*)//xms) { - $filter = "(userPrincipalName=${principal})"; - } elsif ($Wallet::Config::KEYTAB_REALM) { - $filter = '(userPrincipalName=' . $principal - . '@' . $Wallet::Config::KEYTAB_REALM . ')'; - } else { - $filter = "(userPrincipalName=${principal}\@*)"; - } - - # Set the base distinguished name - if ($this_type && $this_type eq 'host') { - $base = $Wallet::Config::AD_COMPUTER_RDN; - } else { - $base = $Wallet::Config::AD_USER_RDN; - } - $base .= ',' . $Wallet::Config::AD_BASE_DN; - - return ($base, $filter); -} - -# Take in a base and a filter and return the assoicated DN or return -# null if there is no matching entry. -sub ldap_get_dn { - my ($self, $base, $filter) = @_; - my $dn; - - if ($Wallet::Config::AD_DEBUG) { - $self->ad_syslog('debug', "base:$base filter:$filter scope:subtree\n"); - } - - $self->ldap_connect(); - my @attrs = ('objectclass'); - my $result; - eval { - $result = $LDAP->search( - base => $base, - scope => 'subtree', - filter => $filter, - attrs => \@attrs - ); - }; - if ($@) { - my $error = $@; - die "LDAP search error: $error\n"; - } - if ($result->code) { - $self->ad_syslog('info', "base:$base filter:$filter scope:subtree\n"); - die $result->error; - } - if ($Wallet::Config::AD_DEBUG) { - $self->ad_syslog('debug', 'returned: ' . $result->count); - } - - if ($result->count == 1) { - for my $entry ($result->entries) { - $dn = $entry->dn; - } - } elsif ($result->count > 1) { - $self->ad_syslog('err', 'too many AD entries for this keytab'); - for my $entry ($result->entries) { - $self->ad_syslog('info', 'dn found: ' . $entry->dn . "\n"); - } - die("INFO: use show to examine the problem\n"); - } - - return $dn; -} - -# TODO: Get a keytab from the keytab bucket. -sub get_ad_keytab { - my ($self, $principal) = @_; - return; -} - -# Run a msktutil command and capture the output. Returns the output, -# either as a list of lines or, in scalar context, as one string. -# Depending on the exit status of msktutil or on the eval trap to know -# when the msktutil command fails. The error string returned from the -# call to run frequently contains information about a success rather -# that error output. -sub msktutil { - my ($self, $args_ref) = @_; - unless (defined($Wallet::Config::KEYTAB_HOST) - and defined($Wallet::Config::KEYTAB_PRINCIPAL) - and defined($Wallet::Config::KEYTAB_FILE) - and defined($Wallet::Config::KEYTAB_REALM)) - { - die "keytab object implementation not configured\n"; - } - unless (-e $Wallet::Config::AD_MSKTUTIL - and defined($Wallet::Config::AD_BASE_DN) - and defined($Wallet::Config::AD_COMPUTER_RDN) - and defined($Wallet::Config::AD_USER_RDN)) - { - die "Active Directory support not configured\n"; - } - my @args = @{$args_ref}; - my @cmd = ($Wallet::Config::AD_MSKTUTIL); - push @cmd, @args; - if ($Wallet::Config::AD_DEBUG) { - $self->ad_syslog('debug', $self->ad_cmd_string(\@cmd)); - } - - my $in; - my $out; - my $err; - my $err_msg; - my $err_no; - eval { - local $ENV{KRB5CCNAME} = $Wallet::Config::AD_CACHE; - run \@cmd, \$in, \$out, \$err, timeout(120); - if ($?) { - $err_no = $?; - } - }; - if ($@) { - $err_msg .= "ERROR ($err_no): $@\n"; - } - if ($err_no || $err_msg) { - if ($err) { - $err_msg .= "ERROR: $err\n"; - $err_msg .= 'Problem command: ' . join(' ', @cmd) . "\n"; - } - $self->ad_syslog('err', $err_msg); - die $err_msg; - } else { - if ($err) { - $out .= "\n" . $err; - } - } - if ($Wallet::Config::AD_DEBUG) { - $self->ad_syslog('debug', $out); - } - return $out; -} - -# The unique identifier that Active Directory used to store keytabs -# has a maximum length of 20 characters. This routine takes a -# principal name an generates a unique ID based on the principal name. -sub get_account_id { - my ($self, $this_princ) = @_; - - my $this_id; - my ($this_base, $this_filter) = $self->ldap_base_filter($this_princ); - my $real_dn = $self->ldap_get_dn($this_base, $this_filter); - if ($real_dn) { - $this_id = $real_dn; - $this_id =~ s/,.*//xms; - $this_id =~ s/.*?=//xms; - } else { - my ($this_type, $this_cn) = split '/', $this_princ, 2; - my $max_len; - if ($this_type eq 'host') { - $max_len = $Wallet::Config::AD_SERVICE_LENGTH - 1; - } else { - $max_len = $Wallet::Config::AD_SERVICE_LENGTH; - if ($Wallet::Config::AD_SERVICE_PREFIX) { - $this_cn = $Wallet::Config::AD_SERVICE_PREFIX . $this_cn; - } - } - my $loop_limit = $Wallet::Config::AD_SERVICE_LIMIT; - if (length($this_cn)>$max_len) { - my $cnt = 0; - my $this_dn; - my $suffix_size = length("$loop_limit"); - my $this_prefix = substr($this_cn, 0, $max_len - $suffix_size); - my $this_format = "%0${suffix_size}i"; - while ($cnt<$loop_limit) { - $this_cn = $this_prefix . sprintf($this_format, $cnt); - $this_dn = $self->ldap_get_dn($this_base, "cn=$this_cn"); - if (!$this_dn) { - $this_id = $this_cn; - last; - } - $cnt++; - } - } else { - $this_id = $this_cn; - } - } - return $this_id; -} - -# Either create or update a keytab for the principal. Return the -# name of the keytab file created. -sub ad_create_update { - my ($self, $principal, $action) = @_; - return unless $self->valid_principal($principal); - my $keytab = $Wallet::Config::KEYTAB_TMP . "/keytab.$$"; - if (-e $keytab) { - unlink $keytab or die "Problem deleting $keytab\n"; - } - my @cmd = ('--' . $action); - push @cmd, '--server', $Wallet::Config::AD_SERVER; - push @cmd, '--enctypes', '0x1C'; - push @cmd, '--keytab', $keytab; - push @cmd, '--realm', $Wallet::Config::KEYTAB_REALM; - push @cmd, '--upn', $principal; - - my $this_type; - my $this_id; - if ($principal =~ m,^(.*?)/(\S+),xms) { - $this_type = $1; - $this_id = $2; - my $account_id = $self->get_account_id($principal); - if ($this_type eq 'host') { - my $host = $this_id; - $host =~ s/[.].*//xms; - push @cmd, '--base', $Wallet::Config::AD_COMPUTER_RDN; - push @cmd, '--dont-expire-password'; - push @cmd, '--computer-name', $account_id; - push @cmd, '--hostname', $this_id; - } else { - push @cmd, '--base', $Wallet::Config::AD_USER_RDN; - push @cmd, '--use-service-account'; - push @cmd, '--service', $principal; - push @cmd, '--account-name', $account_id; - push @cmd, '--no-pac'; - } - my $out = $self->msktutil(\@cmd); - if ($out =~ /Error:\s+\S+\s+failed/xms - || !$self->exists($principal)) - { - $self->ad_delete($principal); - my $m = "ERROR: problem creating keytab for $principal"; - $self->ad_syslog('err', $m); - $self->ad_syslog('err', - 'Problem command:' . ad_cmd_string(\@cmd)); - die "$m\n"; - } - } else { - die "ERROR: Invalid principal format ($principal)\n"; - } - - return $keytab; -} - -############################################################################## -# Public interfaces -############################################################################## - -# Set a callback to be called for forked kadmin processes. -sub fork_callback { - my ($self, $callback) = @_; - $self->{fork_callback} = $callback; -} - -# Check whether a given principal already exists. Returns true if so, -# false otherwise. The best way to do this with AD is to perform an -# ldap query. -sub exists { - my ($self, $principal) = @_; - return unless $self->valid_principal($principal); - - my ($base, $filter) = $self->ldap_base_filter($principal); - - return $self->ldap_get_dn($base, $filter); -} - -# Call msktutil to Create a principal in Kerberos. Sets the error and -# returns undef on failure, and returns 1 on either success or if the -# principal already exists. Note, this creates a keytab that is never -# used because it is not returned to the user. -sub create { - my ($self, $principal) = @_; - unless ($self->valid_principal($principal)) { - die "ERROR: invalid principal name $principal\n"; - return; - } - if ($self->exists($principal)) { - if ($Wallet::Config::AD_DEBUG) { - $self->ad_syslog('debug', "$principal exists"); - } - return 1; - } - my $file = $self->ad_create_update($principal, 'create'); - if (-e $file) { - unlink $file or die "Problem deleting $file\n"; - } - return 1; -} - -# TODO: Return a keytab. Need to create a local keytab cache when -# a keytab is marked unchanging and return that. -sub keytab { - my ($self, $principal) = @_; - unless ($self->valid_principal($principal)) { - die "ERROR: invalid principal name $principal\n"; - return; - } - my $file = 'call to route to get the file name of local keytab file'; - if (!-e $file) { - die "ERROR: keytab file $file does not exist.\n"; - } - return $self->read_keytab($file); -} - -# Update a keytab for a principal. This action changes the AD -# password for the principal and increments the kvno. The enctypes -# passed in are ignored. -sub keytab_rekey { - my ($self, $principal, @enctypes) = @_; - unless ($self->valid_principal($principal)) { - die "ERROR: invalid principal name: $principal\n"; - return; - } - if (!$self->exists($principal)) { - die "ERROR: $principal does not exist\n"; - } - unless ($self->valid_principal($principal)) { - die "ERROR: invalid principal name $principal\n"; - return; - } - my $file = $self->ad_create_update($principal, 'update'); - return $self->read_keytab($file); -} - -# Delete a principal from Kerberos. Return true if successful, false -# otherwise. If the deletion fails, sets the error. If the principal -# doesn't exist, return success; we're bringing reality in line with -# our expectations. For AD this means just delete the object using -# LDAP. -sub destroy { - my ($self, $principal) = @_; - unless ($self->valid_principal($principal)) { - $self->error("invalid principal name: $principal"); - } - my $exists = $self->exists($principal); - if (!defined $exists) { - return 1; - } elsif (not $exists) { - return 1; - } - - return $self->ad_delete($principal); -} - -# Delete an entry from AD using LDAP. - -sub ad_delete { - my ($self, $principal) = @_; - - my ($base, $filter) = $self->ldap_base_filter($principal); - my $dn = $self->ldap_get_dn($base, $filter); - - $self->ldap_connect(); - my $msgid = $LDAP->delete($dn); - if ($msgid->code) { - my $m; - $m .= "ERROR: Problem deleting $dn\n"; - $m .= $msgid->error; - $self->ad_syslog('err', $m); - die $m; - } - return 1; -} - -# Create a new AD kadmin object. Very empty for the moment, but later it -# will probably fill out if we go to using a module rather than calling -# kadmin directly. -sub new { - my ($class) = @_; - unless (defined($Wallet::Config::KEYTAB_TMP)) { - die "KEYTAB_TMP configuration variable not set\n"; - } - my $self = {}; - $self->{SYSLOG} = undef; - bless($self, $class); - return $self; -} - -1; -__END__ - -############################################################################## -# Documentation -############################################################################## - -=for stopwords -rekeying rekeys remctl backend keytabs keytab kadmin KDC API Allbery -unlinked MacAllister msktutil - -=head1 NAME - -Wallet::Kadmin::AD - Wallet Kerberos administration API for Active Directory - -=head1 SYNOPSIS - - my $kadmin = Wallet::Kadmin::AD->new; - $kadmin->create ('host/foo.example.com'); - my $data = $kadmin->keytab_rekey ('host/foo.example.com'); - $data = $kadmin->keytab ('host/foo.example.com'); - my $exists = $kadmin->exists ('host/oldshell.example.com'); - $kadmin->destroy ('host/oldshell.example.com') if $exists; - -=head1 DESCRIPTION - -Wallet::Kadmin::AD implements the Wallet::Kadmin API for Active -Directory Kerberos, providing an interface to create and delete -principals and create keytabs. It provides the API documented in -L for an Active Directory Kerberos KDC. - -AD Kerberos does not provide any method via msktutil to retrieve a -keytab for a principal without rekeying it, so the keytab() method (as -opposed to keytab_rekey(), which rekeys the principal) is implemented -using a local keytab cache. - -To use this class, several configuration parameters must be set. See -L for details. - -=head1 LIMITATIONS - -Currently, this implementation calls an external B program rather -than using a native Perl module and therefore requires B be -installed and parses its output. - -=head1 SEE ALSO - -msktutil, Wallet::Config(3), Wallet::Kadmin(3), -Wallet::Object::Keytab(3), wallet-backend(8) - -This module is part of the wallet system. The current version is -available from L. - -=head1 AUTHORS - -Bill MacAllister -and Russ Allbery -and Jon Robertson . - -=cut From ae0541f4366854c690ff9f9da0665c310ec0c579 Mon Sep 17 00:00:00 2001 From: Bill MacAllister Date: Sun, 12 Jun 2022 18:28:58 +0000 Subject: [PATCH 39/47] Update changelog for new release --- debian/changelog | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/debian/changelog b/debian/changelog index 49794776..62a4dd52 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,10 @@ +wallet (1.4-10) unstable; urgency=medium + + * Correct problem with transition of unencrypted file and password + objects to encrypted objected. + + -- Bill MacAllister Sun, 12 Jun 2022 18:28:16 +0000 + wallet (1.4-9) unstable; urgency=medium * Correct the default value used for the maximum of a "computer From aaaf4b02e1bbb2d2c9ae3a9408eb15bfe486b714 Mon Sep 17 00:00:00 2001 From: Bill MacAllister Date: Mon, 13 Jun 2022 05:02:19 +0000 Subject: [PATCH 40/47] Correct handling of transition of plain password to encryption --- debian/patches/0019-password-encrypt.patch | 122 +++++++++++++++++++++ debian/patches/series | 1 + 2 files changed, 123 insertions(+) create mode 100644 debian/patches/0019-password-encrypt.patch diff --git a/debian/patches/0019-password-encrypt.patch b/debian/patches/0019-password-encrypt.patch new file mode 100644 index 00000000..36d2366a --- /dev/null +++ b/debian/patches/0019-password-encrypt.patch @@ -0,0 +1,122 @@ +--- a/perl/lib/Wallet/Object/File.pm ++++ b/perl/lib/Wallet/Object/File.pm +@@ -249,8 +249,9 @@ sub _file_crypt { + return $return_string; + } + +-sub file_decrypt { +- my ($self, $data, $user, $host, $time) = @_; ++# Given a string decrypt it. ++sub string_decrypt { ++ my ($self, $data) = @_; + my $key = $self->_get_crypt_key(); + my $undata; + if (defined (&Wallet::Config::file_crypt)) { +@@ -264,6 +265,15 @@ sub file_decrypt { + } + $undata = $self->_file_crypt('decrypt', $key, $data); + } ++ return $undata; ++} ++ ++# Given a string decrypt it. If the string is not encrypted then the ++# input string string will match the decrypted string and the string ++# will be encrypted and stored to disk. ++sub file_decrypt { ++ my ($self, $data, $user, $host, $time) = @_; ++ my $undata = $self->string_decrypt($data); + if ($undata eq $data) { + $self->store($data, $user, $host, $time); + } +--- a/perl/lib/Wallet/Object/Password.pm ++++ b/perl/lib/Wallet/Object/Password.pm +@@ -84,6 +84,44 @@ sub _pwd_xkcd { + return $pass; + } + ++# Read the password file to disk. ++sub _read_pw_file { ++ my ($self, $path) = @_; ++ my $id = $self->{type} . ':' . $self->{name}; ++ ++ unless (open (FILE, '<', $path)) { ++ $self->error ("cannot get $id: object has not been stored"); ++ return; ++ } ++ local $/; ++ my $data = ; ++ unless (close FILE) { ++ $self->error ("cannot get $id: $!"); ++ return; ++ } ++ return $data; ++} ++ ++# Write the password file to disk. ++sub _write_pw_file { ++ my ($self, $path, $data) = @_; ++ my $id = $self->{type} . ':' . $self->{name}; ++ ++ unless (open (FILE, '>', $path)) { ++ $self->error ("cannot open $path $!\n"); ++ return 1; ++ } ++ if ($Wallet::Config::LDAP_SECRET) { ++ $data = Wallet::Object::File->file_encrypt($data); ++ } ++ print FILE $data; ++ unless (close FILE) { ++ $self->error ("cannot store $id: $!"); ++ return 1; ++ } ++ return 0; ++} ++ + ############################################################################## + # Shared methods + ############################################################################## +@@ -135,34 +173,25 @@ sub retrieve { + } + return; + } +- unless (open (FILE, '>', $path)) { +- $self->error ("cannot open $path $!\n"); ++ if ($self->_write_pw_file($path, $pass)) { + return; + } +- if ($Wallet::Config::LDAP_SECRET) { +- $pass = Wallet::Object::File->file_encrypt($pass); +- } +- print FILE $pass; + $self->log_action ('store', $user, $host, $time); +- unless (close FILE) { +- $self->error ("cannot get $id: $!"); +- return; +- } + } + +- unless (open (FILE, '<', $path)) { +- $self->error ("cannot get $id: object has not been stored"); +- return; +- } +- local $/; +- my $data = ; +- unless (close FILE) { +- $self->error ("cannot get $id: $!"); ++ my $data = $self->_read_pw_file($path); ++ if (!$data) { + return; + } + $self->log_action ($operation, $user, $host, $time); + if ($Wallet::Config::LDAP_SECRET) { +- $data = Wallet::Object::File->file_decrypt($data); ++ my $undata = Wallet::Object::File->string_decrypt($data); ++ if ($undata eq $data) { ++ my $endata = Wallet::Object::File->file_encrypt($data); ++ $self->_write_pw_file($path, $endata); ++ $self->log_action ($operation, $user, $host, $time); ++ } ++ $data = $undata; + } + return $data; + } diff --git a/debian/patches/series b/debian/patches/series index 5bb9a9f2..0e1e4833 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -16,3 +16,4 @@ 0016-checkfile.patch 0017-checkfile.patch 0018-ad-length.patch +0019-password-encrypt.patch From 661dff0f094d925900f61c132d099f44b674af64 Mon Sep 17 00:00:00 2001 From: Bill MacAllister Date: Sat, 18 Jun 2022 01:52:57 +0000 Subject: [PATCH 41/47] Patch to remove support for WebAuth keyrings WebAuth is no longer supported by Debian. --- debian/patches/0020-retire-webauth.patch | 1359 ++++++++++++++++++++++ debian/patches/series | 1 + 2 files changed, 1360 insertions(+) create mode 100644 debian/patches/0020-retire-webauth.patch diff --git a/debian/patches/0020-retire-webauth.patch b/debian/patches/0020-retire-webauth.patch new file mode 100644 index 00000000..0ccf159a --- /dev/null +++ b/debian/patches/0020-retire-webauth.patch @@ -0,0 +1,1359 @@ +Index: wallet/perl/lib/Wallet/Object/WAKeyring.pm +=================================================================== +--- wallet.orig/perl/lib/Wallet/Object/WAKeyring.pm 2022-06-18 01:53:50.800081794 +0000 ++++ /dev/null 1970-01-01 00:00:00.000000000 +0000 +@@ -1,367 +0,0 @@ +-# Wallet::Object::WAKeyring -- WebAuth keyring object implementation +-# +-# Written by Russ Allbery +-# Copyright 2016 Russ Allbery +-# Copyright 2012-2014 +-# The Board of Trustees of the Leland Stanford Junior University +-# +-# SPDX-License-Identifier: MIT +- +-############################################################################## +-# Modules and declarations +-############################################################################## +- +-package Wallet::Object::WAKeyring; +- +-use 5.008; +-use strict; +-use warnings; +- +-use Digest::MD5 qw(md5_hex); +-use Fcntl qw(LOCK_EX); +-use Wallet::Config; +-use Wallet::Object::Base; +-use WebAuth 3.06 qw(WA_KEY_AES WA_AES_128); +- +-our @ISA = qw(Wallet::Object::Base); +-our $VERSION = '1.04'; +- +-############################################################################## +-# File naming +-############################################################################## +- +-# Returns the path into which that keyring object will be stored or undef on +-# error. On error, sets the internal error. +-sub file_path { +- my ($self) = @_; +- my $name = $self->{name}; +- unless ($Wallet::Config::WAKEYRING_BUCKET) { +- $self->error ('WebAuth keyring support not configured'); +- return; +- } +- unless ($name) { +- $self->error ('WebAuth keyring objects may not have empty names'); +- return; +- } +- my $hash = substr (md5_hex ($name), 0, 2); +- $name =~ s/([^\w-])/sprintf ('%%%02X', ord ($1))/ge; +- my $parent = "$Wallet::Config::WAKEYRING_BUCKET/$hash"; +- unless (-d $parent || mkdir ($parent, 0700)) { +- $self->error ("cannot create keyring bucket $hash: $!"); +- return; +- } +- return "$Wallet::Config::WAKEYRING_BUCKET/$hash/$name"; +-} +- +-############################################################################## +-# Core methods +-############################################################################## +- +-# Override destroy to delete the file as well. +-sub destroy { +- my ($self, $user, $host, $time) = @_; +- my $id = $self->{type} . ':' . $self->{name}; +- my $path = $self->file_path; +- if (defined ($path) && -f $path && !unlink ($path)) { +- $self->error ("cannot delete $id: $!"); +- return; +- } +- return $self->SUPER::destroy ($user, $host, $time); +-} +- +-# Update the keyring if needed, and then return the contents of the current +-# keyring. +-sub get { +- 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; +- return unless defined $path; +- +- # Create a WebAuth context and ensure we can load the relevant modules. +- my $wa = eval { WebAuth->new }; +- if ($@) { +- $self->error ("cannot initialize WebAuth: $@"); +- return; +- } +- +- # Check if the keyring already exists. If not, create a new one with a +- # single key that's immediately valid and two more that will become valid +- # in the future. +- # +- # If the keyring does already exist, get a lock on the file. At the end +- # of this process, we'll do an atomic update and then drop our lock. +- # +- # FIXME: There are probably better ways to do this. There are some race +- # conditions here, particularly with new keyrings. +- unless (open (FILE, '+<', $path)) { +- my $data; +- eval { +- my $key = $wa->key_create (WA_KEY_AES, WA_AES_128); +- my $ring = $wa->keyring_new ($key); +- $key = $wa->key_create (WA_KEY_AES, WA_AES_128); +- my $valid = time + $Wallet::Config::WAKEYRING_REKEY_INTERVAL; +- $ring->add (time, $valid, $key); +- $key = $wa->key_create (WA_KEY_AES, WA_AES_128); +- $valid += $Wallet::Config::WAKEYRING_REKEY_INTERVAL; +- $ring->add (time, $valid, $key); +- $data = $ring->encode; +- $ring->write ($path); +- }; +- if ($@) { +- $self->error ("cannot create new keyring"); +- return; +- }; +- $self->log_action ('get', $user, $host, $time); +- return $data; +- } +- unless (flock (FILE, LOCK_EX)) { +- $self->error ("cannot get lock on keyring: $!"); +- return; +- } +- +- # Read the keyring. +- my $ring = eval { WebAuth::Keyring->read ($wa, $path) }; +- if ($@) { +- $self->error ("cannot read keyring: $@"); +- return; +- } +- +- # If the most recent key has a valid-after older than now + +- # WAKEYRING_REKEY_INTERVAL, we generate a new key with a valid_after of +- # now + 2 * WAKEYRING_REKEY_INTERVAL. +- my ($count, $newest) = (0, 0); +- for my $entry ($ring->entries) { +- $count++; +- if ($entry->valid_after > $newest) { +- $newest = $entry->valid_after; +- } +- } +- eval { +- if ($newest <= time + $Wallet::Config::WAKEYRING_REKEY_INTERVAL) { +- my $valid = time + 2 * $Wallet::Config::WAKEYRING_REKEY_INTERVAL; +- my $key = $wa->key_create (WA_KEY_AES, WA_AES_128); +- $ring->add (time, $valid, $key); +- } +- }; +- if ($@) { +- $self->error ("cannot add new key: $@"); +- return; +- } +- +- # If there are any keys older than the purge interval, remove them, but +- # only do so if we have more than three keys (the one that's currently +- # active, the one that's going to come active in the rekey interval, and +- # the one that's going to come active after that. +- # +- # FIXME: Be sure that we don't remove the last currently-valid key. +- my $cutoff = time - $Wallet::Config::WAKEYRING_PURGE_INTERVAL; +- my $i = 0; +- my @purge; +- if ($count > 3) { +- for my $entry ($ring->entries) { +- if ($entry->creation < $cutoff) { +- push (@purge, $i); +- } +- $i++; +- } +- } +- if (@purge && $count - @purge >= 3) { +- eval { +- for my $key (reverse @purge) { +- $ring->remove ($key); +- } +- }; +- if ($@) { +- $self->error ("cannot remove old keys: $@"); +- return; +- } +- } +- +- # Encode the key. +- my $data = eval { $ring->encode }; +- if ($@) { +- $self->error ("cannot encode keyring: $@"); +- return; +- } +- +- # Write the new keyring to the path. +- eval { $ring->write ($path) }; +- if ($@) { +- $self->error ("cannot store new keyring: $@"); +- return; +- } +- close FILE; +- $self->log_action ('get', $user, $host, $time); +- return $data; +-} +- +-# Store the file on the wallet server. +-# +-# FIXME: Check the provided keyring for validity. +-sub store { +- my ($self, $data, $user, $host, $time) = @_; +- $time ||= time; +- my $id = $self->{type} . ':' . $self->{name}; +- if ($self->flag_check ('locked')) { +- $self->error ("cannot store $id: object is locked"); +- return; +- } +- if ($Wallet::Config::FILE_MAX_SIZE) { +- my $max = $Wallet::Config::FILE_MAX_SIZE; +- if (length ($data) > $max) { +- $self->error ("data exceeds maximum of $max bytes"); +- return; +- } +- } +- my $path = $self->file_path; +- return unless $path; +- unless (open (FILE, '>', $path)) { +- $self->error ("cannot store $id: $!"); +- return; +- } +- unless (print FILE ($data) and close FILE) { +- $self->error ("cannot store $id: $!"); +- close FILE; +- return; +- } +- $self->log_action ('store', $user, $host, $time); +- return 1; +-} +- +-1; +-__END__ +- +-############################################################################## +-# Documentation +-############################################################################## +- +-=for stopwords +-WebAuth keyring keyrings API HOSTNAME DATETIME keytab AES rekey Allbery +- +-=head1 NAME +- +-Wallet::Object::WAKeyring - WebAuth keyring object implementation for wallet +- +-=head1 SYNOPSIS +- +- my ($user, $host, $time); +- my @name = qw(wa-keyring www.stanford.edu); +- my @trace = ($user, $host, $time); +- my $object = Wallet::Object::WAKeyring->create (@name, $schema, $trace); +- my $keyring = $object->get (@trace); +- unless ($object->store ($keyring)) { +- die $object->error, "\n"; +- } +- $object->destroy (@trace); +- +-=head1 DESCRIPTION +- +-Wallet::Object::WAKeyring is a representation of a WebAuth keyring in the +-wallet. It implements the wallet object API and provides the necessary +-glue to store a keyring on the wallet server, retrieve it, update the +-keyring with new keys automatically as needed, purge old keys +-automatically, and delete the keyring when the object is deleted. +- +-WebAuth keyrings hold one or more keys. Each key has a creation time and +-a validity time. The key cannot be used until its validity time has been +-reached. This permits safe key rotation: a new key is added with a +-validity time in the future, and then the keyring is updated everywhere it +-needs to be before that validity time is reached. This wallet object +-automatically handles key rotation by adding keys with validity dates in +-the future and removing keys with creation dates substantially in the +-past. +- +-To use this object, various configuration options specifying where to +-store the keyrings and how to handle key rotation must be set. See +-Wallet::Config for details on these configuration parameters and +-information about how to set wallet configuration. +- +-=head1 METHODS +- +-This object mostly inherits from Wallet::Object::Base. See the +-documentation for that class for all generic methods. Below are only +-those methods that are overridden or behave specially for this +-implementation. +- +-=over 4 +- +-=item destroy(PRINCIPAL, HOSTNAME [, DATETIME]) +- +-Destroys a WebAuth keyring object by removing it from the database and +-deleting the corresponding file on the wallet server. Returns true on +-success and false on failure. The caller should call error() to get the +-error message after a failure. PRINCIPAL, HOSTNAME, and DATETIME are +-stored as history information. PRINCIPAL should be the user who is +-destroying the object. If DATETIME isn't given, the current time is used. +- +-=item get(PRINCIPAL, HOSTNAME [, DATETIME]) +- +-Either creates a new WebAuth keyring (if this object has not bee stored or +-retrieved before) or does any necessary periodic maintenance on the +-keyring and then returns its data. The caller should call error() to get +-the error message if get() returns undef. 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. +- +-If this object has never been stored or retrieved before, a new keyring +-will be created with three 128-bit AES keys: one that is immediately +-valid, one that will become valid after the rekey interval, and one that +-will become valid after twice the rekey interval. +- +-If keyring data for this object already exists, the creation and validity +-dates for each key in the keyring will be examined. If the key with the +-validity date the farthest into the future has a date that's less than or +-equal to the current time plus the rekey interval, a new 128-bit AES key +-will be added to the keyring with a validity time of twice the rekey +-interval in the future. Finally, all keys with a creation date older than +-the configured purge interval will be removed provided that the keyring +-has at least three keys +- +-=item store(DATA, PRINCIPAL, HOSTNAME [, DATETIME]) +- +-Store DATA as the current contents of the WebAuth keyring object. Note +-that this is not checked for validity, just assumed to be a valid keyring. +-Any existing data will be overwritten. Returns true on success and false +-on failure. The caller should call error() to get the error message after +-a failure. PRINCIPAL, HOSTNAME, and DATETIME are stored as history +-information. PRINCIPAL should be the user who is destroying the object. +-If DATETIME isn't given, the current time is used. +- +-If FILE_MAX_SIZE is set in the wallet configuration, a store() of DATA +-larger than that configuration setting will be rejected. +- +-=back +- +-=head1 FILES +- +-=over 4 +- +-=item WAKEYRING_BUCKET// +- +-WebAuth keyrings are stored on the wallet server under the directory +-WAKEYRING_BUCKET as set in the wallet configuration. is the first +-two characters of the hex-encoded MD5 hash of the wallet file object name, +-used to not put too many files in the same directory. is the name +-of the file object with all characters other than alphanumerics, +-underscores, and dashes replaced by "%" and the hex code of the character. +- +-=back +- +-=head1 SEE ALSO +- +-Wallet::Config(3), Wallet::Object::Base(3), wallet-backend(8), WebAuth(3) +- +-This module is part of the wallet system. The current version is available +-from L. +- +-=head1 AUTHOR +- +-Russ Allbery +- +-=cut +Index: wallet/NEWS +=================================================================== +--- wallet.orig/NEWS 2022-06-18 01:53:50.800081794 +0000 ++++ wallet/NEWS 2022-06-18 01:53:50.780080738 +0000 +@@ -1,5 +1,13 @@ + User-Visible wallet Changes + ++wallet 1.4-10 (2022-06-17) ++ ++ The support for WebAuth keyrings has been removed since it is not ++ supported by Debian. ++ ++ There is a critical fix for transition from unencrypted password ++ and file objects to encrypted. ++ + wallet 1.4-3 (2019-09-30) + + Two new features have been added to wallet with this release. +Index: wallet/README +=================================================================== +--- wallet.orig/README 2022-06-18 01:53:50.800081794 +0000 ++++ wallet/README 2022-06-18 01:53:50.780080738 +0000 +@@ -42,16 +42,16 @@ + regexes matching Kerberos principal names, and LDAP attribute checks. + + Currently, the object types supported are simple files, passwords, +- Kerberos keytabs, WebAuth keyrings, and Duo integrations. By default, +- whenever a Kerberos keytab object is retrieved from the wallet, the key +- is changed in the Kerberos KDC and the wallet returns a keytab for the +- new key. However, a keytab object can also be configured to preserve +- the existing keys when retrieved. Included in the wallet distribution +- is a script that can be run via remctl on an MIT Kerberos KDC to extract +- the existing key for a principal, and the wallet system will use that +- interface to retrieve the current key if the unchanging flag is set on a +- Kerberos keytab object for MIT Kerberos. (Heimdal doesn't require any +- special support.) ++ Kerberos keytabs, and Duo integrations. By default, whenever a ++ Kerberos keytab object is retrieved from the wallet, the key is ++ changed in the Kerberos KDC and the wallet returns a keytab for the ++ new key. However, a keytab object can also be configured to ++ preserve the existing keys when retrieved. Included in the wallet ++ distribution is a script that can be run via remctl on an MIT ++ Kerberos KDC to extract the existing key for a principal, and the ++ wallet system will use that interface to retrieve the current key if ++ the unchanging flag is set on a Kerberos keytab object for MIT ++ Kerberos. (Heimdal doesn't require any special support.) + + REQUIREMENTS + +@@ -98,9 +98,6 @@ + binary that supports the -norandkey option to ktadd. This option is + included in MIT Kerberos 1.7 and later. + +- The WebAuth keyring object support in the wallet server requires the +- WebAuth Perl module from WebAuth 4.4.0 or later. +- + The Duo integration object support in the wallet server requires the + Net::Duo, JSON, and Perl6::Slurp Perl modules. + +Index: wallet/README.md +=================================================================== +--- wallet.orig/README.md 2022-06-18 01:53:50.800081794 +0000 ++++ wallet/README.md 2022-06-18 01:53:50.780080738 +0000 +@@ -43,16 +43,16 @@ + regexes matching Kerberos principal names, and LDAP attribute checks. + + Currently, the object types supported are simple files, passwords, +-Kerberos keytabs, WebAuth keyrings, and Duo integrations. By default, +-whenever a Kerberos keytab object is retrieved from the wallet, the key is +-changed in the Kerberos KDC and the wallet returns a keytab for the new +-key. However, a keytab object can also be configured to preserve the +-existing keys when retrieved. Included in the wallet distribution is a +-script that can be run via remctl on an MIT Kerberos KDC to extract the +-existing key for a principal, and the wallet system will use that +-interface to retrieve the current key if the unchanging flag is set on a +-Kerberos keytab object for MIT Kerberos. (Heimdal doesn't require any +-special support.) ++Kerberos keytabs, and Duo integrations. By default, whenever a ++Kerberos keytab object is retrieved from the wallet, the key is ++changed in the Kerberos KDC and the wallet returns a keytab for the ++new key. However, a keytab object can also be configured to preserve ++the existing keys when retrieved. Included in the wallet distribution ++is a script that can be run via remctl on an MIT Kerberos KDC to ++extract the existing key for a principal, and the wallet system will ++use that interface to retrieve the current key if the unchanging flag ++is set on a Kerberos keytab object for MIT Kerberos. (Heimdal doesn't ++require any special support.) + + ## Requirements + +@@ -98,9 +98,6 @@ + supports the `-norandkey` option to `ktadd`. This option is included in + MIT Kerberos 1.7 and later. + +-The WebAuth keyring object support in the wallet server requires the +-WebAuth Perl module from WebAuth 4.4.0 or later. +- + The Duo integration object support in the wallet server requires the + Net::Duo, JSON, and Perl6::Slurp Perl modules. + +Index: wallet/contrib/wallet-rekey-periodic +=================================================================== +--- wallet.orig/contrib/wallet-rekey-periodic 2022-06-18 01:53:50.800081794 +0000 ++++ /dev/null 1970-01-01 00:00:00.000000000 +0000 +@@ -1,268 +0,0 @@ +-#!/bin/sh +-# +-# Rekey all principals on a system at a random but constrained interval. +-# +-# This script is a wrapper around wallet-rekey that adds some additional +-# functionality: rekeying of all keytabs at known locations on the system, +-# skipping keytabs that are marked unchanging, rekeying any keytabs with DES +-# keys immediately but otherwise only rekeying once a month based on a random +-# interval based on the hostname, and cleaning up old keys. +-# +-# It's primarily meant to be run daily from cron, but can also be run manually +-# from the command line to rekey specific keytab files. +-# +-# This script assumes Linux, and the test for Heimdal assumes that the +-# Kerberos clients are installed in /usr/bin. At sites other than Stanford, +-# change the principal setting near the top of the script to use your local +-# realm. +- +-set -e +- +-# Red Hat puts its Kerberos binaries in an odd place. Make sure that we +-# prefer the system binaries everwhere. +-PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/kerberos/bin; export PATH +- +-# The rekeying interval. Rekeying will be done, on average, every this number +-# of days. +-INTERVAL=30 +- +-# Under normal circumstances, we don't want to rekey every host at the same +-# time. We therefore run this script daily, but we only do the rekeying if +-# it's our day to do so. +-# +-# For the decision whether we should go on this day, we want to do something +-# relatively random, but zero-intervention and with no state. We therefore +-# hash the hostname with MD5 and mod it with $INTERVAL, which gives us a +-# number between 0 and $INTERVAL - 1. Then, take the mod of the day of the +-# year. If the result matches the number we got, we rekey. +-# +-# We do the check later, since we always want to rekey if we see DES keys. +-hostnum=$(hostname | md5sum | awk '{print $1}') +-DAY=$(awk "END { print 0x$hostnum % $INTERVAL }" /dev/null ; then +- return 0 +- else +- return 1 +- fi +-} +- +-# Returns whether the installed Kerberos implementation on the local system is +-# Heimdal. +-is_heimdal () { +- if [ -x '/usr/bin/kgetcred' ] ; then +- return 0 +- else +- return 1 +- fi +-} +- +-# Print the list of principals in a keytab. +-principals () { +- if is_heimdal ; then +- ktutil -k "$1" list | awk '{ +- if (FNR > 3) { +- princ = $3 +- sub(/@.*/, "", princ) +- print princ +- } +- }' | sort -u +- else +- klist -k "$1" | awk '{ +- if (FNR > 3) { +- princ = $2 +- sub(/@.*/, "", princ) +- print princ +- } +- }' | sort -u +- fi +-} +- +-# Run a command under k5start using the host/* principal for the current +-# hostname as the authentication credentials. +-run_k5start () { +- k5start -qf /etc/krb5.keytab "$principal" -- "$@" +-} +- +-# Check all of the principals in a keytab and see if any of them are +-# unchanging. If any are, we skip rekeying this keytab, since otherwise we're +-# going to accumulate multiple copies of the same key and the cleanup +-# functions won't remove the excess keys. +-is_unchanging () { +- princs=$(principals "$1") +- for princ in $princs ; do +- if run_k5start wallet show keytab "$princ" 2>&1 \ +- | grep -q 'Flags: unchanging' ; then +- return 0 +- fi +- done +- return 1 +-} +- +-# Check whether any of the principals in this keytab have DES keys. This is a +-# bit complicated, since we don't want to trigger this if there are DES keys +-# but ones with old kvnos. +-# +-# We get a list of all the unique kvnos in the file, and then a list of all +-# the unique kvnos of DES keys in the file. If those lists match, we consider +-# this a DES keytab; if not, there's at least one kvno with non-DES keys, so +-# we consider this a non-DES keytab. +-is_des () { +- if is_heimdal ; then +- all=$(ktutil -k "$1" list | sed '1,3d' | awk '{print $1}' | sort -nu) +- des=$(ktutil -k "$1" list | grep des-cbc-crc | awk '{print $1}' \ +- | sort -nu) +- else +- all=$(klist -k "$1" | sed '1,3d' | awk '{print $1}' | sort -nu) +- des=$(klist -ke "$1" | egrep '\(DES cbc|des-cbc-crc' \ +- | awk '{print $1}' | sort -nu) +- fi +- if [ "$all" = "$des" ] ; then +- return 0 +- else +- return 1 +- fi +-} +- +-# Rekey the given keytab file if it exists, this is either the active day or +-# the keytab contains DES keys, and it isn't unchanging. On Heimdal, we'll +-# also purge old keys. We can't do this on MIT because the kadmin routine +-# that purges old keys requires admin authentication. +-rekey () { +- if [ -f "$1" ] ; then +- if is_des "$1" || is_active_day ; then +- if ! is_unchanging "$1" ; then +- if is_heimdal ; then +- ktutil -k "$1" purge +- fi +- run_k5start wallet-rekey "$1" +- fi +- fi +- fi +-} +- +-# The default action is to rekey the host keytab, the WebAuth keytab, and any +-# keytabs found in /etc/keytabs/*. But if we're given keytabs on the command +-# line, we'll rekey those instead. (This won't generally be used since we're +-# installed as a cron job.) +-if [ -z "$1" ] ; then +- for file in /etc/webauth/keytab /etc/keytabs/* /etc/krb5.keytab ; do +- rekey "$file" +- done +-else +- for file in "$@" ; do +- rekey "$file" +- done +-fi +- +-# Documentation. Use a hack to hide this from the shell. Because of the +-# above exit line, this should never be executed. +-DOCS=<<__END_OF_DOCS__ +- +-=for stopwords +-Allbery DES Heimdal hostname keytab keytabs ktutil rekey rekeyable +-rekeying wallet-rekey wallet-rekey-periodic SPDX-License-Identifier MIT +- +-=head1 NAME +- +-wallet-rekey-periodic - Periodically rekey all system keytabs +- +-=head1 SYNOPSIS +- +-B [I ...] +- +-=head1 DESCRIPTION +- +-B is a wrapper around wallet-rekey that adds some +-additional functionality: rekeying of all keytabs at known locations on +-the system, skipping keytabs that are marked unchanging, rekeying any +-keytabs with DES keys immediately but otherwise only rekeying once a month +-based on a random interval based on the hostname, and cleaning up old +-keys. +- +-It's primarily meant to be run daily from cron, but can also be run +-manually from the command line to rekey specific keytab files. +- +-B will, for each keytab, find a list of all +-principals in that keytab and see if any of them still have DES keys. If +-so, it will always attempt to rekey that keytab. If not, it will only do +-so, for a given system, once every 30 days (based on a hash of the +-hostname). It will also always skip keytabs that contain any principals +-that wallet says are unchanging, since otherwise the current wallet-rekey +-implementation will duplicate the existing keys. +- +-On Heimdal systems, this command will remove keys older than a week before +-rekeying the keytab. This relies on B functionality that's +-available only in Heimdal, so MIT Kerberos keytabs will slowly grow unless +-they're manually pruned. This will be fixed in a later release of +-B. +- +-If no keytabs are given on the command line, B will +-rekey a set of system keytabs described below under L. Otherwise, +-it will rekey the keytabs given. +- +-=head1 FILES +- +-=over 4 +- +-=item F +- +-=item F +- +-=item F +- +-The default list of locations checked for rekeyable keytabs. If run with +-no command-line arguments, B will try to rekey +-every principal in each keytab found at any of these paths. +- +-=back +- +-=head1 AUTHOR +- +-Russ Allbery +- +-=head1 COPYRIGHT AND LICENSE +- +-Copyright 2013-2014 The Board of Trustees of the Leland Stanford Junior +-University +- +-Permission is hereby granted, free of charge, to any person obtaining a +-copy of this software and associated documentation files (the "Software"), +-to deal in the Software without restriction, including without limitation +-the rights to use, copy, modify, merge, publish, distribute, sublicense, +-and/or sell copies of the Software, and to permit persons to whom the +-Software is furnished to do so, subject to the following conditions: +- +-The above copyright notice and this permission notice shall be included in +-all copies or substantial portions of the Software. +- +-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +-THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +-FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +-DEALINGS IN THE SOFTWARE. +- +-SPDX-License-Identifier: MIT +- +-=head1 SEE ALSO +- +-ktutil(8), wallet(1), wallet-rekey(1) +- +-=cut +- +-__END_OF_DOCS__ +- +-# Local Variables: +-# copyright-at-end-flag: t +-# End: +Index: wallet/perl/lib/Wallet/Config.pm +=================================================================== +--- wallet.orig/perl/lib/Wallet/Config.pm 2022-06-18 01:53:50.800081794 +0000 ++++ wallet/perl/lib/Wallet/Config.pm 2022-06-18 01:53:50.784080949 +0000 +@@ -26,7 +26,7 @@ + DBI DSN SQLite subdirectories KEYTAB keytab kadmind KDC add-ons kadmin DNS + SRV kadmin keytabs remctl backend lowercased NETDB ACL NetDB unscoped + usernames rekey hostnames Allbery wallet-backend keytab-backend Heimdal +-rekeys WebAuth WEBAUTH keyring LDAP DN GSS-API integrations msktutil CN DIT ++rekeys LDAP DN GSS-API integrations msktutil CN DIT + + =head1 SYNOPSIS + +@@ -645,67 +645,6 @@ + + =back + +-=head1 WEBAUTH KEYRING OBJECT CONFIGURATION +- +-These configuration variables only need to be set if you intend to use the +-C object type (the Wallet::Object::WAKeyring class). +- +-=over 4 +- +-=item WAKEYRING_BUCKET +- +-The directory into which to store WebAuth keyring objects. WebAuth +-keyring objects will be stored in subdirectories of this directory. See +-L for the full details of the naming scheme. +-This directory must be writable by the wallet server and the wallet server +-must be able to create subdirectories of it. +- +-WAKEYRING_BUCKET must be set to use WebAuth keyring objects. +- +-=cut +- +-our $WAKEYRING_BUCKET; +- +-=item WAKEYRING_REKEY_INTERVAL +- +-The interval, in seconds, at which new keys are generated in a keyring. +-The object implementation will try to arrange for there to be keys added +-to the keyring separated by this interval. +- +-It's useful to provide some interval to install the keyring everywhere +-that it's used before the key becomes inactive. Every keyring will +-therefore normally have at least three keys: one that's currently active, +-one that becomes valid in the future but less than +-WAKEYRING_REKEY_INTERVAL from now, and one that becomes valid between one +-and two of those intervals into the future. This means that one has twice +-this interval to distribute the keyring everywhere it is used. +- +-Internally, this is implemented by adding a new key that becomes valid in +-twice this interval from the current time if the newest key becomes valid +-at or less than this interval in the future. +- +-The default value is 60 * 60 * 24 (one day). +- +-=cut +- +-our $WAKEYRING_REKEY_INTERVAL = 60 * 60 * 24; +- +-=item WAKEYRING_PURGE_INTERVAL +- +-The interval, in seconds, from the key creation date after which keys are +-removed from the keyring. This is used to clean up old keys and finish +-key rotation. Keys won't be removed unless there are more than three keys +-in the keyring to try to keep a misconfiguration from removing all valid +-keys. +- +-The default value is 60 * 60 * 24 * 90 (90 days). +- +-=cut +- +-our $WAKEYRING_PURGE_INTERVAL = 60 * 60 * 24 * 90; +- +-=back +- + =head1 EXTERNAL ACL CONFIGURATION + + This configuration variable is only needed if you intend to use the +@@ -940,7 +879,7 @@ + sub default_owner { + my ($type, $name) = @_; + my %allowed = map { $_ => 1 } +- qw(HTTP cifs host imap ldap nfs pop sieve smtp webauth); ++ qw(HTTP cifs host imap ldap nfs pop sieve smtp); + my $realm = 'example.com'; + return unless $type eq 'keytab'; + return unless $name =~ m%/%; +@@ -997,7 +936,7 @@ + sub verify_name { + my ($type, $name, $user) = @_; + my %host_based = map { $_ => 1 } +- qw(HTTP cifs host imap ldap nfs pop sieve smtp webauth); ++ qw(HTTP cifs host imap ldap nfs pop sieve smtp); + return unless $type eq 'keytab'; + return unless $name =~ m%/%; + my ($service, $instance) = split ('/', $name, 2); +@@ -1029,7 +968,7 @@ + sub is_for_host { + my ($type, $name, $hostname) = @_; + my %host_based = map { $_ => 1 } +- qw(HTTP cifs host imap ldap nfs pop sieve smtp webauth); ++ qw(HTTP cifs host imap ldap nfs pop sieve smtp); + return 0 unless $type eq 'keytab'; + return 0 unless $name =~ m%/%; + my ($service, $instance) = split ('/', $name, 2); +Index: wallet/perl/t/object/wa-keyring.t +=================================================================== +--- wallet.orig/perl/t/object/wa-keyring.t 2022-06-18 01:53:50.800081794 +0000 ++++ /dev/null 1970-01-01 00:00:00.000000000 +0000 +@@ -1,183 +0,0 @@ +-#!/usr/bin/perl +-# +-# Tests for the WebAuth keyring object implementation. +-# +-# Written by Russ Allbery +-# Copyright 2013-2014 +-# The Board of Trustees of the Leland Stanford Junior University +-# +-# SPDX-License-Identifier: MIT +- +-use strict; +-use warnings; +- +-use Test::More; +- +-BEGIN { +- eval 'use WebAuth 3.06 qw(WA_KEY_AES WA_AES_128)'; +- plan skip_all => 'WebAuth 3.06 required for testing wa-keyring' +- if $@; +-} +- +-use WebAuth::Key 1.01 (); +-use WebAuth::Keyring 1.02 (); +- +-BEGIN { +- plan tests => 68; +- use_ok('Wallet::Admin'); +- use_ok('Wallet::Config'); +- use_ok('Wallet::Object::WAKeyring'); +-} +- +-use lib 't/lib'; +-use Util; +- +-# Some global defaults to use. +-my $user = 'admin@EXAMPLE.COM'; +-my $host = 'localhost'; +-my @trace = ($user, $host, time); +- +-# Flush all output immediately. +-$| = 1; +- +-# Use Wallet::Admin to set up the database. +-system ('rm -rf test-keyrings') == 0 or die "cannot remove test-keyrings\n"; +-db_setup; +-my $admin = eval { Wallet::Admin->new }; +-is ($@, '', 'Database connection succeeded'); +-is ($admin->reinitialize ($user), 1, 'Database initialization succeeded'); +-my $schema = $admin->schema; +- +-# Create a WebAuth context to use. +-my $wa = WebAuth->new; +- +-# Test error handling in the absence of configuration. +-my $object = eval { +- Wallet::Object::WAKeyring->create ('wa-keyring', 'test', $schema, @trace) +- }; +-ok (defined ($object), 'Creating a basic WebAuth keyring object succeeds'); +-ok ($object->isa ('Wallet::Object::WAKeyring'), ' and is the right class'); +-is ($object->get (@trace), undef, ' and get fails'); +-is ($object->error, 'WebAuth keyring support not configured', +- ' with the right error'); +-is ($object->store (@trace), undef, ' and store fails'); +-is ($object->error, 'WebAuth keyring support not configured', +- ' with the right error'); +-is ($object->destroy (@trace), 1, ' but destroy succeeds'); +- +-# Set up our configuration. +-mkdir 'test-keyrings' or die "cannot create test-keyrings: $!\n"; +-$Wallet::Config::WAKEYRING_BUCKET = 'test-keyrings'; +- +-# Okay, now we can test. First, the basic object without store. +-$object = eval { +- Wallet::Object::WAKeyring->create ('wa-keyring', 'test', $schema, @trace) +- }; +-ok (defined ($object), 'Creating a basic WebAuth keyring object succeeds'); +-ok ($object->isa ('Wallet::Object::WAKeyring'), ' and is the right class'); +-my $data = $object->get (@trace); +-ok ($data, ' and get succeeds'); +-my $keyring = WebAuth::Keyring->decode ($wa, $data); +-ok ($keyring->isa ('WebAuth::Keyring'), ' and resulting keyring decodes'); +-my @entries = $keyring->entries; +-is (scalar (@entries), 3, ' and has three entries'); +-is ($entries[0]->creation, 0, 'First has good creation'); +-is ($entries[0]->key->type, WA_KEY_AES, ' and key type'); +-is ($entries[0]->key->length, WA_AES_128, ' and key length'); +-is ($entries[0]->valid_after, 0, ' and validity'); +-ok ((time - $entries[1]->creation) < 2, 'Second has good creation'); +-is ($entries[1]->key->type, WA_KEY_AES, ' and key type'); +-is ($entries[1]->key->length, WA_AES_128, ' and key length'); +-ok (($entries[1]->valid_after - time) <= 60 * 60 * 24, +- ' and validity (upper)'); +-ok (($entries[1]->valid_after - time) > 60 * 60 * 24 - 2, +- ' and validity (lower)'); +-ok ((time - $entries[2]->creation) < 2, 'Third has good creation'); +-is ($entries[2]->key->type, WA_KEY_AES, ' and key type'); +-is ($entries[2]->key->length, WA_AES_128, ' and key length'); +-ok (($entries[2]->valid_after - time) <= 2 * 60 * 60 * 24, +- ' and validity (upper)'); +-ok (($entries[2]->valid_after - time) > 2 * 60 * 60 * 24 - 2, +- ' and validity (lower)'); +-my $data2 = $object->get (@trace); +-is ($data2, $data, 'Getting the object again returns the same data'); +-is ($object->error, undef, ' with no error'); +-is ($object->destroy (@trace), 1, 'Destroying the object succeeds'); +- +-# Now store something and be sure that we get something reasonable. +-$object = eval { +- Wallet::Object::WAKeyring->create ('wa-keyring', 'test', $schema, @trace) +- }; +-ok (defined ($object), 'Recreating the object succeeds'); +-my $key = WebAuth::Key->new ($wa, WA_KEY_AES, WA_AES_128); +-$keyring = WebAuth::Keyring->new ($wa, $key); +-$data = $keyring->encode; +-is ($object->store ($data, @trace), 1, ' and storing data in it succeeds'); +-ok (-d 'test-keyrings/09', ' and the hash bucket was created'); +-ok (-f 'test-keyrings/09/test', ' and the file exists'); +-is (contents ('test-keyrings/09/test'), $data, ' with the right contents'); +-$data = $object->get (@trace); +-$keyring = WebAuth::Keyring->decode ($wa, $data); +-ok ($keyring->isa ('WebAuth::Keyring'), ' and get returns a valid keyring'); +-@entries = $keyring->entries; +-is (scalar (@entries), 2, ' and has three entries'); +-is ($entries[0]->creation, 0, 'First has good creation'); +-is ($entries[0]->key->type, WA_KEY_AES, ' and key type'); +-is ($entries[0]->key->length, WA_AES_128, ' and key length'); +-is ($entries[0]->valid_after, 0, ' and validity'); +-is ($entries[0]->key->data, $key->data, ' and matches the original key'); +-ok ((time - $entries[1]->creation) < 2, 'Second has good creation'); +-is ($entries[1]->key->type, WA_KEY_AES, ' and key type'); +-is ($entries[1]->key->length, WA_AES_128, ' and key length'); +-ok (($entries[1]->valid_after - time) <= 2 * 60 * 60 * 24, +- ' and validity (upper)'); +-ok (($entries[1]->valid_after - time) > 2 * 60 * 60 * 24 - 2, +- ' and validity (lower)'); +- +-# Test pruning. Add another old key and a couple of more current keys to the +-# current keyring. +-$key = WebAuth::Key->new ($wa, WA_KEY_AES, WA_AES_128); +-$keyring->add (0, 0, $key); +-$key = WebAuth::Key->new ($wa, WA_KEY_AES, WA_AES_128); +-$keyring->add (time - 24 * 60 * 60, time - 24 * 60 * 60, $key); +-$key = WebAuth::Key->new ($wa, WA_KEY_AES, WA_AES_128); +-$keyring->add (time, time, $key); +-$data = $keyring->encode; +-is ($object->store ($data, @trace), 1, 'Storing modified keyring succeeds'); +-$data = $object->get (@trace); +-$keyring = WebAuth::Keyring->decode ($wa, $data); +-ok ($keyring->isa ('WebAuth::Keyring'), ' and get returns a valid keyring'); +-@entries = $keyring->entries; +-is (scalar (@entries), 3, ' and has three entries'); +-ok ((time - $entries[0]->creation) < 2, 'First has good creation'); +-ok (($entries[0]->valid_after - time) <= 2 * 60 * 60 * 24, +- ' and validity (upper)'); +-ok (($entries[0]->valid_after - time) > 2 * 60 * 60 * 24 - 2, +- ' and validity (lower)'); +-ok ((time - $entries[1]->creation) < 24 * 60 * 60 + 2, +- 'Second has good creation'); +-ok ((time - $entries[1]->valid_after) <= 60 * 60 * 24 + 2, +- ' and validity'); +-ok ((time - $entries[2]->creation) < 2, 'Third has good creation'); +-ok ((time - $entries[2]->valid_after) < 2, ' and validity'); +-is ($object->destroy (@trace), 1, 'Destroying the object succeeds'); +- +-# Test error handling in the file store. +-system ('rm -r test-keyrings') == 0 or die "cannot remove test-keyrings\n"; +-$object = eval { +- Wallet::Object::WAKeyring->create ('wa-keyring', 'test', $schema, @trace) +- }; +-ok (defined ($object), 'Recreating the object succeeds'); +-is ($object->get (@trace), undef, ' but retrieving it fails'); +-like ($object->error, qr/^cannot create keyring bucket 09: /, +- ' with the right error'); +-is ($object->store ("foo\n", @trace), undef, ' and store fails'); +-like ($object->error, qr/^cannot create keyring bucket 09: /, +- ' with the right error'); +-is ($object->destroy (@trace), 1, ' but destroying the object succeeds'); +- +-# Clean up. +-$admin->destroy; +-END { +- unlink ('wallet-db'); +-} +Index: wallet/contrib/wallet-rekey-periodic.8 +=================================================================== +--- wallet.orig/contrib/wallet-rekey-periodic.8 2022-06-18 01:53:50.800081794 +0000 ++++ /dev/null 1970-01-01 00:00:00.000000000 +0000 +@@ -1,213 +0,0 @@ +-.\" Automatically generated by Pod::Man 4.09 (Pod::Simple 3.35) +-.\" +-.\" Standard preamble: +-.\" ======================================================================== +-.de Sp \" Vertical space (when we can't use .PP) +-.if t .sp .5v +-.if n .sp +-.. +-.de Vb \" Begin verbatim text +-.ft CW +-.nf +-.ne \\$1 +-.. +-.de Ve \" End verbatim text +-.ft R +-.fi +-.. +-.\" Set up some character translations and predefined strings. \*(-- will +-.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left +-.\" double quote, and \*(R" will give a right double quote. \*(C+ will +-.\" give a nicer C++. Capital omega is used to do unbreakable dashes and +-.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, +-.\" nothing in troff, for use with C<>. +-.tr \(*W- +-.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' +-.ie n \{\ +-. ds -- \(*W- +-. ds PI pi +-. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch +-. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch +-. ds L" "" +-. ds R" "" +-. ds C` "" +-. ds C' "" +-'br\} +-.el\{\ +-. ds -- \|\(em\| +-. ds PI \(*p +-. ds L" `` +-. ds R" '' +-. ds C` +-. ds C' +-'br\} +-.\" +-.\" Escape single quotes in literal strings from groff's Unicode transform. +-.ie \n(.g .ds Aq \(aq +-.el .ds Aq ' +-.\" +-.\" If the F register is >0, we'll generate index entries on stderr for +-.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index +-.\" entries marked with X<> in POD. Of course, you'll have to process the +-.\" output yourself in some meaningful fashion. +-.\" +-.\" Avoid warning from groff about undefined register 'F'. +-.de IX +-.. +-.if !\nF .nr F 0 +-.if \nF>0 \{\ +-. de IX +-. tm Index:\\$1\t\\n%\t"\\$2" +-.. +-. if !\nF==2 \{\ +-. nr % 0 +-. nr F 2 +-. \} +-.\} +-.\" +-.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). +-.\" Fear. Run. Save yourself. No user-serviceable parts. +-. \" fudge factors for nroff and troff +-.if n \{\ +-. ds #H 0 +-. ds #V .8m +-. ds #F .3m +-. ds #[ \f1 +-. ds #] \fP +-.\} +-.if t \{\ +-. ds #H ((1u-(\\\\n(.fu%2u))*.13m) +-. ds #V .6m +-. ds #F 0 +-. ds #[ \& +-. ds #] \& +-.\} +-. \" simple accents for nroff and troff +-.if n \{\ +-. ds ' \& +-. ds ` \& +-. ds ^ \& +-. ds , \& +-. ds ~ ~ +-. ds / +-.\} +-.if t \{\ +-. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" +-. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' +-. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' +-. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' +-. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' +-. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' +-.\} +-. \" troff and (daisy-wheel) nroff accents +-.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' +-.ds 8 \h'\*(#H'\(*b\h'-\*(#H' +-.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] +-.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' +-.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' +-.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] +-.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] +-.ds ae a\h'-(\w'a'u*4/10)'e +-.ds Ae A\h'-(\w'A'u*4/10)'E +-. \" corrections for vroff +-.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' +-.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' +-. \" for low resolution devices (crt and lpr) +-.if \n(.H>23 .if \n(.V>19 \ +-\{\ +-. ds : e +-. ds 8 ss +-. ds o a +-. ds d- d\h'-1'\(ga +-. ds D- D\h'-1'\(hy +-. ds th \o'bp' +-. ds Th \o'LP' +-. ds ae ae +-. ds Ae AE +-.\} +-.rm #[ #] #H #V #F C +-.\" ======================================================================== +-.\" +-.IX Title "WALLET-REKEY-PERIODIC 8" +-.TH WALLET-REKEY-PERIODIC 8 "2018-06-04" "1.4" "wallet" +-.\" For nroff, turn off justification. Always turn off hyphenation; it makes +-.\" way too many mistakes in technical documents. +-.if n .ad l +-.nh +-.SH "NAME" +-wallet\-rekey\-periodic \- Periodically rekey all system keytabs +-.SH "SYNOPSIS" +-.IX Header "SYNOPSIS" +-\&\fBwallet-rekey-periodic\fR [\fIkeytab\fR ...] +-.SH "DESCRIPTION" +-.IX Header "DESCRIPTION" +-\&\fBwallet-rekey-periodic\fR is a wrapper around wallet-rekey that adds some +-additional functionality: rekeying of all keytabs at known locations on +-the system, skipping keytabs that are marked unchanging, rekeying any +-keytabs with \s-1DES\s0 keys immediately but otherwise only rekeying once a month +-based on a random interval based on the hostname, and cleaning up old +-keys. +-.PP +-It's primarily meant to be run daily from cron, but can also be run +-manually from the command line to rekey specific keytab files. +-.PP +-\&\fBwallet-rekey-periodic\fR will, for each keytab, find a list of all +-principals in that keytab and see if any of them still have \s-1DES\s0 keys. If +-so, it will always attempt to rekey that keytab. If not, it will only do +-so, for a given system, once every 30 days (based on a hash of the +-hostname). It will also always skip keytabs that contain any principals +-that wallet says are unchanging, since otherwise the current wallet-rekey +-implementation will duplicate the existing keys. +-.PP +-On Heimdal systems, this command will remove keys older than a week before +-rekeying the keytab. This relies on \fBktutil\fR functionality that's +-available only in Heimdal, so \s-1MIT\s0 Kerberos keytabs will slowly grow unless +-they're manually pruned. This will be fixed in a later release of +-\&\fBwallet-rekey\fR. +-.PP +-If no keytabs are given on the command line, \fBwallet-rekey-periodic\fR will +-rekey a set of system keytabs described below under \*(L"\s-1FILES\*(R"\s0. Otherwise, +-it will rekey the keytabs given. +-.SH "FILES" +-.IX Header "FILES" +-.IP "\fI/etc/keytabs/*\fR" 4 +-.IX Item "/etc/keytabs/*" +-.PD 0 +-.IP "\fI/etc/krb5.keytab\fR" 4 +-.IX Item "/etc/krb5.keytab" +-.IP "\fI/etc/webauth/keytab\fR" 4 +-.IX Item "/etc/webauth/keytab" +-.PD +-The default list of locations checked for rekeyable keytabs. If run with +-no command-line arguments, \fBwallet-rekey-periodic\fR will try to rekey +-every principal in each keytab found at any of these paths. +-.SH "AUTHOR" +-.IX Header "AUTHOR" +-Russ Allbery +-.SH "COPYRIGHT AND LICENSE" +-.IX Header "COPYRIGHT AND LICENSE" +-Copyright 2013\-2014 The Board of Trustees of the Leland Stanford Junior +-University +-.PP +-Permission is hereby granted, free of charge, to any person obtaining a +-copy of this software and associated documentation files (the \*(L"Software\*(R"), +-to deal in the Software without restriction, including without limitation +-the rights to use, copy, modify, merge, publish, distribute, sublicense, +-and/or sell copies of the Software, and to permit persons to whom the +-Software is furnished to do so, subject to the following conditions: +-.PP +-The above copyright notice and this permission notice shall be included in +-all copies or substantial portions of the Software. +-.PP +-\&\s-1THE SOFTWARE IS PROVIDED \*(L"AS IS\*(R", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\s0 \s-1IN NO EVENT SHALL +-THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +-FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +-DEALINGS IN THE SOFTWARE.\s0 +-.PP +-SPDX-License-Identifier: \s-1MIT\s0 +-.SH "SEE ALSO" +-.IX Header "SEE ALSO" +-\&\fIktutil\fR\|(8), \fIwallet\fR\|(1), \fIwallet\-rekey\fR\|(1) +Index: wallet/contrib/wallet-summary +=================================================================== +--- wallet.orig/contrib/wallet-summary 2022-06-18 01:53:50.800081794 +0000 ++++ wallet/contrib/wallet-summary 2022-06-18 01:53:50.784080949 +0000 +@@ -41,7 +41,6 @@ + [qr(^pop/), 'pop/*', 'Kerberized POP'], + [qr(^sieve/), 'sieve/*', 'Sieve mail sorting'], + [qr(^smtp/), 'smtp/*', 'SMTP'], +- [qr(^webauth/), 'webauth/*', 'WebAuth v3'], + [qr(^service/), 'service/*', 'Service principals']); + + ############################################################################## +Index: wallet/contrib/used-principals +=================================================================== +--- wallet.orig/contrib/used-principals 2022-06-18 01:53:50.800081794 +0000 ++++ wallet/contrib/used-principals 2022-06-18 01:53:50.784080949 +0000 +@@ -18,7 +18,7 @@ + # appended. + our %HOST_BASED = map { $_ => 1 } + qw(HTTP afpserver cifs ftp host ident imap ldap nfs pop sieve smtp +- uniengd webauth); ++ uniengd); + + # Parse command-line options. + my ($count, $help, $k4, $principals); +Index: wallet/perl/t/policy/stanford.t +=================================================================== +--- wallet.orig/perl/t/policy/stanford.t 2022-06-18 01:53:50.800081794 +0000 ++++ wallet/perl/t/policy/stanford.t 2022-06-18 01:53:50.784080949 +0000 +@@ -211,15 +211,6 @@ + ], + '...and when netdb ACL already exists' + ); +- is_deeply( +- [default_owner('keytab', 'webauth/foo.stanford.edu')], +- [ +- 'host/foo.stanford.edu', +- ['netdb-root', 'foo.stanford.edu'], +- ['krb5', 'host/foo.stanford.edu@stanford.edu'] +- ], +- '...and when netdb-root ACL already exists' +- ); + + # Now with a root instance. + local $ENV{REMOTE_USER} = 'admin/root@stanford.edu'; +@@ -241,15 +232,6 @@ + ], + '...and when netdb ACL already exists' + ); +- is_deeply( +- [default_owner('keytab', 'webauth/foo.stanford.edu')], +- [ +- 'host/foo.stanford.edu', +- ['netdb-root', 'foo.stanford.edu'], +- ['krb5', 'host/foo.stanford.edu@stanford.edu'] +- ], +- '...and when netdb-root ACL already exists' +- ); + + # Check for a type that isn't host-based. + is( +Index: wallet/perl/Build.PL +=================================================================== +--- wallet.orig/perl/Build.PL 2022-06-18 01:53:50.800081794 +0000 ++++ wallet/perl/Build.PL 2022-06-18 01:53:50.784080949 +0000 +@@ -46,7 +46,6 @@ + 'Net::Duo' => 0, + 'Net::LDAP' => 0, + 'Net::Remctl' => 0, +- WebAuth => 0, + }, + test_requires => { + 'Crypt::GeneratePassword' => 0, +Index: wallet/docs/metadata/description +=================================================================== +--- wallet.orig/docs/metadata/description 2022-06-18 01:53:44.683758725 +0000 ++++ wallet/docs/metadata/description 2022-06-18 01:54:27.806036564 +0000 +@@ -19,7 +19,7 @@ + regexes matching Kerberos principal names, and LDAP attribute checks. + + Currently, the object types supported are simple files, passwords, +-Kerberos keytabs, WebAuth keyrings, and Duo integrations. By default, ++Kerberos keytabs, and Duo integrations. By default, + whenever a Kerberos keytab object is retrieved from the wallet, the key is + changed in the Kerberos KDC and the wallet returns a keytab for the new + key. However, a keytab object can also be configured to preserve the +Index: wallet/docs/metadata/requirements +=================================================================== +--- wallet.orig/docs/metadata/requirements 2022-06-18 01:20:49.283265080 +0000 ++++ wallet/docs/metadata/requirements 2022-06-18 01:56:13.399614445 +0000 +@@ -40,9 +40,6 @@ + supports the `-norandkey` option to `ktadd`. This option is included in + MIT Kerberos 1.7 and later. + +-The WebAuth keyring object support in the wallet server requires the +-WebAuth Perl module from WebAuth 4.4.0 or later. +- + The Duo integration object support in the wallet server requires the + Net::Duo, JSON, and Perl6::Slurp Perl modules. + diff --git a/debian/patches/series b/debian/patches/series index 0e1e4833..a57325fa 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -17,3 +17,4 @@ 0017-checkfile.patch 0018-ad-length.patch 0019-password-encrypt.patch +0020-retire-webauth.patch From 50603a74fd98421da74b6b71e539f117c7490f10 Mon Sep 17 00:00:00 2001 From: Bill MacAllister Date: Sat, 18 Jun 2022 02:18:14 +0000 Subject: [PATCH 42/47] Remove webauth support from control file --- debian/control | 2 -- 1 file changed, 2 deletions(-) diff --git a/debian/control b/debian/control index d26f8352..c77239dd 100644 --- a/debian/control +++ b/debian/control @@ -33,7 +33,6 @@ Build-Depends: libtest-pod-perl, libtest-strict-perl, libtimedate-perl, - libwebauth-perl, perl, sqlite3, Rules-Requires-Root: no @@ -108,7 +107,6 @@ Suggests: libnet-ldap-perl, libnet-remctl-perl, libperl6-slurp-perl, - libwebauth-perl (>= 4.4.0), Description: Kerberos-authenticated secure data management server The wallet is a system for managing secure data, authorization rules to retrieve or change that data, and audit rules for documenting actions From 7bd94054322d3500654bba64b2a040ef2d08b7e1 Mon Sep 17 00:00:00 2001 From: Bill MacAllister Date: Sat, 18 Jun 2022 02:32:28 +0000 Subject: [PATCH 43/47] Add a patch to work around some build cruft It looks like the build process is creating a configure~ file which causes the license test to fail. --- debian/patches/0021-spx-test.patch | 12 ++++++++++++ debian/patches/series | 1 + 2 files changed, 13 insertions(+) create mode 100644 debian/patches/0021-spx-test.patch diff --git a/debian/patches/0021-spx-test.patch b/debian/patches/0021-spx-test.patch new file mode 100644 index 00000000..82aa5d3d --- /dev/null +++ b/debian/patches/0021-spx-test.patch @@ -0,0 +1,12 @@ +Index: wallet/tests/docs/spdx-license-t +=================================================================== +--- wallet.orig/tests/docs/spdx-license-t 2022-06-05 23:25:17.526523890 +0000 ++++ wallet/tests/docs/spdx-license-t 2022-06-05 23:26:57.183817283 +0000 +@@ -53,6 +53,7 @@ + qr{ [.] output \z }xms, # Test data + ); + my @IGNORE_PATHS = ( ++ qr{ \A configure~ }xms, # Build artifact + qr{ \A debian/ }xms, # Found in debian/* branches + qr{ \A docs/metadata/ }xms, # Package license should be fine + qr{ \A docs/protocol[.](html|txt) \z }xms, # Generated by xml2rfc diff --git a/debian/patches/series b/debian/patches/series index a57325fa..a3dd19a8 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -18,3 +18,4 @@ 0018-ad-length.patch 0019-password-encrypt.patch 0020-retire-webauth.patch +0021-spx-test.patch \ No newline at end of file From 07ffea4238aa2e6c7506b0cda3ae23bfbc5c3610 Mon Sep 17 00:00:00 2001 From: Bill MacAllister Date: Sat, 18 Jun 2022 02:42:26 +0000 Subject: [PATCH 44/47] Update changelog with webauth change --- debian/changelog | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/debian/changelog b/debian/changelog index 62a4dd52..1f65a6f7 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +wallet (1.4-11) unstable; urgency=medium + + * Remove support for WebAuth keyrings. + + -- Bill MacAllister Sat, 18 Jun 2022 02:42:15 +0000 + wallet (1.4-10) unstable; urgency=medium * Correct problem with transition of unencrypted file and password From 0281e06202d5d3a19ad5d9a98806678dd3e30343 Mon Sep 17 00:00:00 2001 From: Bill MacAllister Date: Thu, 23 Jun 2022 06:33:27 +0000 Subject: [PATCH 45/47] Correct password encryption Correct double encryption problem when transitioning to encrypted password storage. --- debian/changelog | 7 +++++++ debian/patches/0022-password-double-encryption.patch | 12 ++++++++++++ debian/patches/series | 3 ++- 3 files changed, 21 insertions(+), 1 deletion(-) create mode 100644 debian/patches/0022-password-double-encryption.patch diff --git a/debian/changelog b/debian/changelog index 1f65a6f7..c8e7bd9a 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,10 @@ +wallet (1.4-12) unstable; urgency=medium + + * Correct double encryption problem when transitioning to encrypted + password storage. + + -- Bill MacAllister Thu, 23 Jun 2022 06:33:15 +0000 + wallet (1.4-11) unstable; urgency=medium * Remove support for WebAuth keyrings. diff --git a/debian/patches/0022-password-double-encryption.patch b/debian/patches/0022-password-double-encryption.patch new file mode 100644 index 00000000..e1839647 --- /dev/null +++ b/debian/patches/0022-password-double-encryption.patch @@ -0,0 +1,12 @@ +--- a/perl/lib/Wallet/Object/Password.pm ++++ b/perl/lib/Wallet/Object/Password.pm +@@ -187,8 +187,7 @@ sub retrieve { + if ($Wallet::Config::LDAP_SECRET) { + my $undata = Wallet::Object::File->string_decrypt($data); + if ($undata eq $data) { +- my $endata = Wallet::Object::File->file_encrypt($data); +- $self->_write_pw_file($path, $endata); ++ $self->_write_pw_file($path, $data); + $self->log_action ($operation, $user, $host, $time); + } + $data = $undata; diff --git a/debian/patches/series b/debian/patches/series index a3dd19a8..e31f900a 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -18,4 +18,5 @@ 0018-ad-length.patch 0019-password-encrypt.patch 0020-retire-webauth.patch -0021-spx-test.patch \ No newline at end of file +0021-spx-test.patch +0022-password-double-encryption.patch From d81c418482b5ec40f90a009f09b117b988b7984e Mon Sep 17 00:00:00 2001 From: Bill MacAllister Date: Fri, 18 Nov 2022 08:06:16 +0000 Subject: [PATCH 46/47] Functionality and performance changes to ldap-attr ACLs Expand the allow ldap-attr ACL specification to include a full ldap filter. At the same time remove the compare search and perform the access test in a single LDAP search. --- debian/changelog | 8 + debian/patches/0023-ldap-attr-filter.patch | 183 +++++++++++++++++++++ debian/patches/series | 1 + 3 files changed, 192 insertions(+) create mode 100644 debian/patches/0023-ldap-attr-filter.patch diff --git a/debian/changelog b/debian/changelog index c8e7bd9a..4c31c0c1 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,11 @@ +wallet (1.4-13) unstable; urgency=medium + + * Expand the allow ldap-attr ACL specification to include a full + ldap filter. At the same time remove the compare search and + perform the access test in a single LDAP search. + + -- Bill MacAllister Fri, 18 Nov 2022 08:05:41 +0000 + wallet (1.4-12) unstable; urgency=medium * Correct double encryption problem when transitioning to encrypted diff --git a/debian/patches/0023-ldap-attr-filter.patch b/debian/patches/0023-ldap-attr-filter.patch new file mode 100644 index 00000000..b204d367 --- /dev/null +++ b/debian/patches/0023-ldap-attr-filter.patch @@ -0,0 +1,183 @@ +Index: wallet/perl/lib/Wallet/ACL/LDAP/Attribute.pm +=================================================================== +--- wallet.orig/perl/lib/Wallet/ACL/LDAP/Attribute.pm 2022-11-18 08:01:14.615451075 +0000 ++++ wallet/perl/lib/Wallet/ACL/LDAP/Attribute.pm 2022-11-18 08:03:02.096649951 +0000 +@@ -62,10 +62,9 @@ + return $self; + } + +-# Check whether a given principal has the required LDAP attribute. We first +-# map the principal to a DN by doing a search for that principal (and bailing +-# if we get more than one entry). Then, we do a compare to see if that DN has +-# the desired attribute and value. ++# Check whether a given principal has access to the wallet object ++# using an LDAP search using a filter consisting of the principal ++# and the ldap-attr filter. + # + # If the ldap_map_principal sub is defined in Wallet::Config, call it on the + # principal first to map it to the value for which we'll search. +@@ -75,18 +74,29 @@ + sub check { + my ($self, $principal, $acl) = @_; + undef $self->{error}; +- unless ($principal) { ++ if (!$principal) { + $self->error ('no principal specified'); + return; + } +- my ($attr, $value); +- if ($acl) { +- ($attr, $value) = split ('=', $acl, 2); ++ ++ if (!$acl) { ++ $self->error ('no ACL specified'); ++ return; ++ } ++ if ($acl !~ /=/xms) { ++ $self->error ('Malformed LDAP filter, no equal sign present'); ++ return; + } +- unless (defined ($attr) and defined ($value)) { +- $self->error ('malformed ldap-attr ACL'); ++ my $lcnt = $acl =~ tr/\(//; ++ my $rcnt = $acl =~ tr/\)//; ++ if ($lcnt != $rcnt) { ++ $self->error ('Malformed LDAP filter, parenthesis mismatch'); + return; + } ++ my $attr_filter = $acl; ++ if ($attr_filter !~ /^\(/xms) { ++ $attr_filter = "($attr_filter)"; ++ } + my $ldap = $self->{ldap}; + + # Map the principal name to an attribute value for our search if we're +@@ -99,38 +109,29 @@ + } + } + +- # Now, map the user to a DN by doing a search. +- my $entry; ++ # Now search for one, and only one, matching entry ++ my $found; ++ my $fattr = $Wallet::Config::LDAP_FILTER_ATTR || 'krb5PrincipalName'; ++ my $filter = "(&($fattr=$principal)$attr_filter)"; ++ my $base = $Wallet::Config::LDAP_BASE; ++ my @options = (base => $base, filter => $filter, attrs => [ 'dn' ]); + eval { +- my $fattr = $Wallet::Config::LDAP_FILTER_ATTR || 'krb5PrincipalName'; +- my $filter = "($fattr=$principal)"; +- my $base = $Wallet::Config::LDAP_BASE; +- my @options = (base => $base, filter => $filter, attrs => [ 'dn' ]); + my $search = $ldap->search (@options); + if ($search->count == 1) { +- $entry = $search->pop_entry; ++ $found = 1; + } elsif ($search->count > 1) { + die $search->count . " LDAP entries found for $principal"; + } + }; + if ($@) { +- $self->error ("cannot search for $principal in LDAP: $@"); ++ $self->error ("search for $attr_filter failed in LDAP: $@"); + return; + } +- return 0 unless $entry; +- +- # We have a user entry. We can now check whether that user has the +- # desired attribute and value. +- my $result; +- eval { +- my $mesg = $ldap->compare ($entry, attr => $attr, value => $value); +- $result = $mesg->code; +- }; +- if ($@) { +- $self->error ("cannot check LDAP attribute $attr for $principal: $@"); +- return; ++ if ($found) { ++ return 1; + } +- return ($result == LDAP_COMPARE_TRUE) ? 1 : 0; ++ ++ return; + } + + 1; +@@ -160,12 +161,13 @@ + + =head1 DESCRIPTION + +-Wallet::ACL::LDAP::Attribute checks whether the LDAP record for the entry +-corresponding to a principal contains an attribute with a particular +-value. It is used to verify ACL lines of type C. The value of +-such an ACL is an attribute followed by an equal sign and a value, and the +-ACL grants access to a given principal if and only if the LDAP entry for +-that principal has that attribute set to that value. ++Wallet::ACL::LDAP::Attribute checks whether the LDAP record for the ++entry corresponding to a principal contains an attribute with a ++particular value. It is used to verify ACL lines of type ++C. The value of such an ACL is a valid LDAP filter, and ++the ACL grants access to a given principal if and only if an LDAP ++search using a filter constructed of the principal filter AND ++the ACL filter returns a single entry. + + To use this object, several configuration parameters must be set. See + L for details on those configuration parameters and +@@ -183,10 +185,9 @@ + =item check(PRINCIPAL, ACL) + + Returns true if PRINCIPAL is granted access according to ACL, false if +-not, and undef on an error (see L<"DIAGNOSTICS"> below). ACL must be an +-attribute name and a value, separated by an equal sign (with no +-whitespace). PRINCIPAL will be granted access if its LDAP entry contains +-that attribute with that value. ++not, and undef on an error (see L<"DIAGNOSTICS"> below). ACL must be ++a valid LDAP filter. The filter formed using the PRINCIPAL and the ++ACL filter must return a single entry for access to be granted. + + =item error() + +@@ -216,31 +217,29 @@ + + =over 4 + +-=item cannot check LDAP attribute %s for %s: %s ++=item search for %s failed in LDAP: %s + +-The LDAP compare to check for the required attribute failed. The +-attribute may have been misspelled, or there may be LDAP directory +-permission issues. This error indicates that PRINCIPAL's entry was +-located in LDAP, but the check failed during the compare to verify the +-attribute value. ++The search for an ldap entry failed because of a configuration error ++in Wallet or the LDAP server. For example the Wallet configuration ++includes an invalid root DN. + +-=item cannot search for %s in LDAP: %s ++=item malformed ldap-attr LDAP filter, no equal sign present + +-Searching for PRINCIPAL (possibly after ldap_map_principal() mapping) +-failed. This is often due to LDAP directory permissions issues. This +-indicates a failure during the mapping of PRINCIPAL to an LDAP DN. ++The ACL filter stored as ldap-attr is not a valid LDAP filter. + +-=item malformed ldap-attr ACL ++=item malformed ldap-attr LDAP filter, parenthesis mismatch + +-The ACL parameter to check() was malformed. Usually this means that +-either the attribute or the value were empty or the required C<=> sign +-separating them was missing. ++The ACL filter stored as ldap-attr is not a valid LDAP filter. + + =item mapping principal to LDAP failed: %s + + There was an ldap_map_principal() function defined in the wallet + configuration, but calling it for the PRINCIPAL argument failed. + ++=item no ACL specified ++ ++The ACL parameter to check() was undefined or the empty string. ++ + =item no principal specified + + The PRINCIPAL parameter to check() was undefined or the empty string. diff --git a/debian/patches/series b/debian/patches/series index e31f900a..c91db4ac 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -20,3 +20,4 @@ 0020-retire-webauth.patch 0021-spx-test.patch 0022-password-double-encryption.patch +0023-ldap-attr-filter.patch From 85f90eeafcd2f7eea3e9d9e506e4896691713fe8 Mon Sep 17 00:00:00 2001 From: Bill MacAllister Date: Mon, 28 Aug 2023 23:36:03 -0700 Subject: [PATCH 47/47] Disable depreciation warning for opensslv1. This is an emergency patch to support the opensslv1 warning for the default encryption message. This warning is affecting production systems negatively. To resolve this problem a method will be implemented that allows the transition to any encryption method supported by Crypt::CBC. --- debian/changelog | 10 +++++++ .../patches/0024-crypt-suppress-warning.patch | 27 +++++++++++++++++++ debian/patches/series | 1 + 3 files changed, 38 insertions(+) create mode 100644 debian/patches/0024-crypt-suppress-warning.patch diff --git a/debian/changelog b/debian/changelog index 4c31c0c1..55bb5c7f 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,13 @@ +wallet (1.4-14) unstable; urgency=medium + + * Disable depreciation warning for opensslv1. This is an emergency + patch to support the opensslv1 warning for the default encryption + message. This warning is affecting production systems negatively. + To resolve this problem a method will be implemented that allows + the transition to any encryption method supported by Crypt::CBC. + + -- Bill MacAllister Mon, 28 Aug 2023 23:35:39 -0700 + wallet (1.4-13) unstable; urgency=medium * Expand the allow ldap-attr ACL specification to include a full diff --git a/debian/patches/0024-crypt-suppress-warning.patch b/debian/patches/0024-crypt-suppress-warning.patch new file mode 100644 index 00000000..e2318a35 --- /dev/null +++ b/debian/patches/0024-crypt-suppress-warning.patch @@ -0,0 +1,27 @@ +Description: Disable depreciation warning for opensslv1 + This is an emergency patch to support the opensslv1 warning for the + default encryption message. This warning is affecting production + systems negatively. To resolve this problem a method will be implemented + that allows the transition to any encryption method supported by + Crypt::CBC. +Author: Bill MacAllister +--- +This patch header follows DEP-3: http://dep.debian.net/deps/dep3/ +--- a/perl/lib/Wallet/Object/File.pm ++++ b/perl/lib/Wallet/Object/File.pm +@@ -224,10 +224,11 @@ sub _file_crypt { + my $pre = $Wallet::Config::ENCRYPTION_PREFIX; + + my $cipher = Crypt::CBC->new( +- -key => $key, +- -cipher => 'Twofish', +- -padding => 'space', +- -add_header => 1 ++ -key => $key, ++ -cipher => 'Twofish', ++ -padding => 'space', ++ -add_header => 1, ++ -nodeprecate => 1 + ); + if ($action eq 'encrypt') { + $return_string diff --git a/debian/patches/series b/debian/patches/series index c91db4ac..522fb4b0 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -21,3 +21,4 @@ 0021-spx-test.patch 0022-password-double-encryption.patch 0023-ldap-attr-filter.patch +0024-crypt-suppress-warning.patch