[Pkg-shadow-devel] [Git][debian/adduser][adduser-encrypt-home] 16 commits: remove unused get_dir_mode

Marc Haber (@zugschlus) gitlab at salsa.debian.org
Fri Jun 5 06:01:28 BST 2026



Marc Haber pushed to branch adduser-encrypt-home at Debian / adduser


Commits:
b139f106 by Marc Haber at 2026-06-01T08:13:55+02:00
remove unused get_dir_mode

Git-Dch: ignore

- - - - -
9b7314cd by Marc Haber at 2026-06-01T08:14:03+02:00
add empty 00test to verify that the lib is okay

Git-Dch: ignore

- - - - -
039bbc7e by Marc Haber at 2026-06-01T08:14:03+02:00
make AdduserTestsCommon a proper module

Git-Dch: ignore

- - - - -
0a355dc1 by Marc Haber at 2026-06-01T08:14:03+02:00
improve existing test helper functions

This also adds cleanup_user and cleanup_tree

Git-Dch: ignore

- - - - -
af354ad5 by Marc Haber at 2026-06-01T08:14:03+02:00
add cleanup class to help cleaning up after tests

Git-Dch: ignore

- - - - -
0c82dcc4 by Marc Haber at 2026-06-01T08:14:03+02:00
add code to do better home directory tests

this pulls part of the skel.t to the library so that other tests
can work with strange files in /etc/skel, this might help debugging
code that handles the home directory contents

Git-Dch: ignore

- - - - -
c3cbc5f6 by Marc Haber at 2026-06-01T08:14:03+02:00
make skel.t use the new Common functions

Git-Dch: ignore

- - - - -
8f305535 by Marc Haber at 2026-06-01T08:14:03+02:00
adapt three tests to use the new cleanup class

Git-Dch: ignore

- - - - -
aab7a62b by Marc Haber at 2026-06-05T07:00:52+02:00
sanitize log output

Some UTF-8 chars break log output in testing

- - - - -
cb129e24 by Marc Haber at 2026-06-05T07:00:53+02:00
have which return undef if the program is not found

This should not change anything since this code path was
previously unused.

- - - - -
dd7446de by Marc Haber at 2026-06-05T07:00:53+02:00
change logic and return values

0 means okay, != 0 means something wrong (meaningful return value)
Improve error message.
That also means that the callers must turn their logic around.

- - - - -
20ebad6a by Dustin Kirkland at 2026-06-05T07:01:12+02:00
Add support for encrypting home directories

* adduser: Add --encrypt-home option, which calls ecryptfs-setup-private
  for the hard work.
* doc/adduser.8: document the --encrypt-home option
* debian/control: suggest ecryptfs-utils >= 67-1
* deluser: remove all of /var/lib/ecryptfs/$user with --remove-home

- - - - -
2c7b5724 by Mateus Rodrigues de Morais at 2026-06-05T07:01:12+02:00
Add encrypted home tests with isolation-machine restriction

- - - - -
f76989b9 by Marc Haber at 2026-06-05T07:01:12+02:00
also execute ecryptfs test without ecryptfs-utils installed

Git-Dch: ignore

- - - - -
525133a5 by Marc Haber at 2026-06-05T07:01:12+02:00
hike up module version number to 3.157

Git-Dch: ignore

- - - - -
76106035 by Marc Haber at 2026-06-05T07:01:12+02:00
add encrypt_home_no_package

We test whether adduser --encrypt-home fails correctly when
the ecryptfs package is not installed.

- - - - -


18 changed files:

- AdduserCommon.pm
- AdduserCreateHomedir.pm
- AdduserLogging.pm
- AdduserRetvalues.pm
- AdduserStatefile.pm
- adduser
- debian/control
- debian/tests/control
- + debian/tests/ecryptfs-no-package/encrypt_home_no_package.t
- + debian/tests/ecryptfs/encrypt_home.t
- + debian/tests/f/00test.t
- debian/tests/f/addusertogroup_underscore.t
- debian/tests/f/deluser_quiet.t
- debian/tests/f/skel.t
- debian/tests/f/uidgidpool.t
- debian/tests/lib/AdduserTestsCommon.pm
- deluser
- doc/adduser.8


Changes:

=====================================
AdduserCommon.pm
=====================================
@@ -1,4 +1,4 @@
-package Debian::AdduserCommon 3.139;
+package Debian::AdduserCommon 3.157;
 use 5.36.0;
 use utf8;
 
@@ -29,12 +29,12 @@ use parent qw(Exporter);
 use Fcntl qw(:flock SEEK_END);
 my $codeset;
 
-use Debian::AdduserLogging 3.139;
-use Debian::AdduserRetvalues 3.139;
-use Debian::AdduserStatefile 3.139;
+use Debian::AdduserLogging 3.157;
+use Debian::AdduserRetvalues 3.157;
+use Debian::AdduserStatefile 3.157;
 BEGIN {
-    if ( Debian::AdduserLogging->VERSION != version->declare('3.139') ||
-         Debian::AdduserRetvalues->VERSION != version->declare('3.139') ) {
+    if ( Debian::AdduserLogging->VERSION != version->declare('3.157') ||
+         Debian::AdduserRetvalues->VERSION != version->declare('3.157') ) {
            die "wrong module version in adduser, check your packaging or path";
     }
     local $ENV{PERL_DL_NONLAZY}=1;
@@ -482,7 +482,7 @@ sub which {
         log_fatal( mtx("Could not find program named `%s' in \$PATH."), $progname );
         exit( RET_EXEC_NOT_FOUND );
     }
-    return 0;
+    return undef;
 }
 
 


=====================================
AdduserCreateHomedir.pm
=====================================
@@ -1,10 +1,12 @@
-package Debian::AdduserCreateHomedir 3.139;
+package Debian::AdduserCreateHomedir 3.157;
 use 5.36.0;
 use utf8;
 
 use strict;
 use warnings;
-use Debian::AdduserLogging 3.139;
+use Debian::AdduserLogging 3.157;
+use Debian::AdduserCommon 3.157;
+use Debian::AdduserRetvalues 3.157;
 
 # Adduser module to create home dir and to copy skel
 #
@@ -22,24 +24,35 @@ use vars qw(@EXPORT $VAR1);
 
 sub create_homedir {
     my %params = @_;
+    my $new_name = $params{new_name};
     my $home_dir = $params{home_dir};
     my $new_uid = $params{uid};
     my $primary_gid = $params{gid};
     my $copy_skeleton = $params{copy_skeleton};
     my $system_user = $params{system_user};
     my $no_create_home = $params{no_create_home};
+    my $encrypt_home = $params{encrypt_home};
     my $config = $params{config};
 
     log_trace("create_homedir(home_dir=%s, new_uid=%s, primary_gid=%s, copy_skeleton=%s, system_user=%s, no_create_home=%s", $home_dir, $new_uid, $primary_gid, $copy_skeleton, $system_user, $no_create_home);
 
+    my $ecryptfs_setup_private;
+    if (defined($encrypt_home)) {
+        $ecryptfs_setup_private = &which('ecryptfs-setup-private', 1);
+        unless (defined $ecryptfs_setup_private) {
+            log_fatal("encrypt_home set but ecryptfs-setup-private not found. Package missing?");
+            return( RET_EXEC_NOT_FOUND );
+        }
+    }
+
     if ($home_dir =~ /^\/+nonexistent(\/|$)/) {
         log_info(mtx("Not creating `%s'."), $home_dir);
-        return 1;
+        return 0;
     }
 
     if ($no_create_home) {
         log_info(mtx("Not creating home directory `%s' as requested."), $home_dir);
-        return 1;
+        return 0;
     }
 
     if (-e $home_dir) {
@@ -50,19 +63,19 @@ sub create_homedir {
                 log_warn(mtx("Warning: The home directory `%s' does not belong to the user you are currently creating."), $home_dir);
             }
         }
-        return 1;
+        return 0;
     }
 
     log_info(mtx("Creating home directory `%s' ..."), $home_dir);
 
     mktree($home_dir) or do {
         log_err(gtx("Couldn't create home directory `%s': %s."), $home_dir, $!);
-        return 0;
+        return RET_INVALID_HOME_DIRECTORY;
     };
 
     chown($new_uid, $primary_gid, $home_dir) or do {
         log_err("chown %s:%s %s: %s", $new_uid, $primary_gid, $home_dir, $!);
-        return 0;
+        return RET_WRONG_OBJECT_PROPERTIES;
     };
 
     # Determine if setgid bit should be applied
@@ -81,9 +94,14 @@ sub create_homedir {
 
     chmod($dir_mode, $home_dir) or do {
         log_err("chmod %s %s: %s", $dir_mode, $home_dir, $!);
-        return 0;
+        return RET_WRONG_OBJECT_PROPERTIES;
     };
 
+    if (defined($encrypt_home)) {
+        log_info( mtx("Setting up encryption ...\n"));
+        &systemcall($ecryptfs_setup_private, '-b', '-u', $new_name);
+    }
+
     if ($config->{skel} && $copy_skeleton) {
         log_info(mtx("Copying files from `%s' ..."), $config->{skel});
         copy_skel(
@@ -93,10 +111,14 @@ sub create_homedir {
             $primary_gid,
             $setgid,
             $config->{skel_ignore_regex}
-        ) or return 0;
+        ) and return RET_FILE_ERROR;
     }
 
-    return 1;
+    if (defined($encrypt_home)) {
+        &systemcall("/bin/umount", $home_dir);
+    }
+
+    return RET_OK;
 }
 
 sub mktree {
@@ -145,14 +167,14 @@ sub recurse_copy {
     # Untaint source path (allow any bytes except / or null)
     $src =~ m{^(/[^/\0]+(?:/[^/\0]+)*)$} or do {
         log_err("Invalid source path: %s", $src);
-        return 0;
+        return RET_INVALID_HOME_DIRECTORY;
     };
     $src = $1;
     log_trace("Processing directory: %s", $src);
 
     opendir(my $dh, $src) or do {
         log_err("opendir %s: %s", $src, $!);
-        return 0;
+        return RET_SYSTEMCALL_ERROR;
     };
 
     my @entries = grep { $_ ne '.' && $_ ne '..' && (!$ignore_re || !/$ignore_re/) } readdir($dh);
@@ -175,7 +197,7 @@ sub recurse_copy {
         # Untaint destination path
         $dst_path =~ m{^(/[^/\0]+(?:/[^/\0]+)*)$} or do {
             log_err("Invalid destination path: %s", $dst_path);
-            return 0;
+            return RET_INVALID_HOME_DIRECTORY;
         };
         $dst_path = $1;
         log_trace("src_path=%s dst_path=%s", $src_path, $dst_path);
@@ -184,11 +206,11 @@ sub recurse_copy {
             # Symlink
             my $target = readlink($src_path) or do {
                 log_err("readlink %s: %s", $src_path, $!);
-                return 0;
+                return RET_SYSTEMCALL_ERROR
             };
             $target =~ m{^([^/\0]+(?:/[^/\0]+)*)$} or do {
                 log_err("Unsafe symlink: %s", $target);
-                return 0;
+                return RET_WRONG_OBJECT_PROPERTIES;
             };
             my ($cu, $cg) = ($>, $));
             ($>, $)) = ($uid, $gid);
@@ -196,8 +218,8 @@ sub recurse_copy {
             my $err = $!;
             ($>, $)) = ($cu, $cg);
             if (!$ok) {
-                log_err("symlink %s: %s", $dst_path, $err);
-                return 0;
+                log_err("error creating symlink %s: %s", $dst_path, $err);
+                return RET_SYSTEMCALL_ERROR;
             }
             log_trace("Created symlink: %s -> %s", $dst_path, $target);
 
@@ -205,32 +227,32 @@ sub recurse_copy {
             # Directory
             if (!-d $dst_path) {
                 mkdir($dst_path, 0700) or do {
-                    log_err("mkdir %s: %s", $dst_path, $!);
-                    return 0;
+                    log_err("error in mkdir %s: %s", $dst_path, $!);
+                    return RET_INVALID_HOME_DIRECTORY;
                 };
                 log_trace("Created directory: %s", $dst_path);
             }
             set_perms($src_path, $dst_path, $uid, $gid, $sgid) or return 0;
-            recurse_copy($src_base, $dst_base, $rel ? "$rel/$entry" : $entry, $uid, $gid, $sgid, $ignore_re) or return 0;
+            recurse_copy($src_base, $dst_base, $rel ? "$rel/$entry" : $entry, $uid, $gid, $sgid, $ignore_re) and return 0;
 
         } elsif (-f $src_path) {
             # Regular file
             open(my $in, '<', $src_path) or do {
-                log_err("open %s: %s", $src_path, $!);
-                return 0;
+                log_err("error read-opening %s: %s", $src_path, $!);
+                return RET_FILE_ERROR;
             };
             open(my $out, '>', $dst_path) or do {
                 close($in);
-                log_err("open %s: %s", $dst_path, $!);
-                return 0;
+                log_err("error write-opening %s: %s", $dst_path, $!);
+                return RET_FILE_ERROR;
             };
             binmode($in);
             binmode($out);
             print $out $_ while <$in>;
             close($in);
             close($out) or do {
-                log_err("close %s: %s", $dst_path, $!);
-                return 0;
+                log_err("error closing %s: %s", $dst_path, $!);
+                return RET_FILE_ERROR;
             };
             set_perms($src_path, $dst_path, $uid, $gid, 0) or return 0;
             log_trace("Copied file: %s", $dst_path);
@@ -238,7 +260,7 @@ sub recurse_copy {
     }
 
     log_trace("Finished processing directory: %s", $src);
-    return 1;
+    return RET_OK;
 }
 
 


=====================================
AdduserLogging.pm
=====================================
@@ -1,4 +1,4 @@
-package Debian::AdduserLogging 3.139;
+package Debian::AdduserLogging 3.157;
 use 5.36.0;
 use utf8;
 
@@ -200,6 +200,12 @@ sub logf {
         $outstring = sprintf( $fmt, @dta );
         $loutstring = sprintf( gettext($fmt), @dta );
     }
+    # sanitize string and indicate when sanitized.
+    # some utf-8 chars interfere with test output
+    my $changed = ($outstring =~ s/[^ -~]/_/g);
+    $outstring = "[sanitized] $outstring" if $changed;
+    $changed = ($loutstring =~ s/[^ -~]/_/g);
+    $loutstring = "[sanitized] $loutstring" if $changed;
     logtrace("outstring %s", $outstring);
     logtrace("loutstring %s", $loutstring);
     logtrace("msglevel %s (%d), stdoutmsglevel %s (%d), stderrmsglevel %s (%d), logmsglevel %s (%d)", $msglevel, numeric_msglevel($msglevel), $stdoutmsglevel, numeric_msglevel($stdoutmsglevel), $stderrmsglevel, numeric_msglevel($stderrmsglevel), $logmsglevel, numeric_msglevel($logmsglevel));


=====================================
AdduserRetvalues.pm
=====================================
@@ -1,4 +1,4 @@
-package Debian::AdduserRetvalues 3.139;
+package Debian::AdduserRetvalues 3.157;
 use 5.36.0;
 use utf8;
 


=====================================
AdduserStatefile.pm
=====================================
@@ -1,4 +1,4 @@
-package Debian::AdduserStatefile 3.139;
+package Debian::AdduserStatefile 3.157;
 use 5.36.0;
 use utf8;
 


=====================================
adduser
=====================================
@@ -31,15 +31,15 @@ use utf8;
 
 use Getopt::Long;
 
-use Debian::AdduserCommon 3.139;
-use Debian::AdduserLogging 3.139;
-use Debian::AdduserRetvalues 3.139;
-use Debian::AdduserStatefile 3.139;
-use Debian::AdduserCreateHomedir 3.139;
+use Debian::AdduserCommon 3.157;
+use Debian::AdduserLogging 3.157;
+use Debian::AdduserRetvalues 3.157;
+use Debian::AdduserStatefile 3.157;
+use Debian::AdduserCreateHomedir 3.157;
 BEGIN {
-    if ( Debian::AdduserCommon->VERSION != version->declare('3.139') ||
-         Debian::AdduserLogging->VERSION != version->declare('3.139') ||
-         Debian::AdduserRetvalues->VERSION != version->declare('3.139') ) {
+    if ( Debian::AdduserCommon->VERSION != version->declare('3.157') ||
+         Debian::AdduserLogging->VERSION != version->declare('3.157') ||
+         Debian::AdduserRetvalues->VERSION != version->declare('3.157') ) {
            die "wrong module version in adduser, check your packaging or path";
     }
 }
@@ -113,6 +113,8 @@ my $ask_passwd = 1;		# ask for a passwd?
 my $disabled_login = 0;		# leave the new account disabled?
 
 our @configfiles;
+our @defaults = undef;
+our $encrypt_home = undef;
 our $found_group_opt = undef;
 our $found_sys_opt = undef;
 our $found_unlock_opt = undef;
@@ -146,7 +148,6 @@ my $first_uid = undef;
 my $last_uid = undef;
 my $first_gid = undef;
 my $last_gid = undef;
-my $dir_mode = undef;
 my $perm = undef;
 my %uid_pool;
 my %gid_pool;
@@ -171,6 +172,7 @@ GetOptions(
     'logmsglevel=s' => \$logmsglevel,
     'disabled-login' => sub { $disabled_login = 1; $ask_passwd = 0 },
     'disabled-password' => sub { $ask_passwd = 0 },
+    'encrypt-home' => \$encrypt_home,
     'firstgid=i' => \$new_firstgid,
     'firstuid=i' => \$new_firstuid,
     'force-badname' => sub { $name_check_level = 1 unless $name_check_level },
@@ -719,16 +721,18 @@ if ($action eq "addsysuser") {
     }
 
     $primary_gid = $gid_option;
+    $undohome = $home_dir;
     create_homedir(
         home_dir => $home_dir,
+        new_name => $new_name,
         uid => $new_uid,
         gid => $gid_option,
         copy_skeleton => 0,
         system_user => 1,
         no_create_home => $no_create_home,
-        dir_mode => $dir_mode,
+        encrypt_home => $encrypt_home,
         config => \%config,
-    ) or cleanup();
+    ) and cleanup();
 
     exit( $returnvalue );
 }
@@ -969,14 +973,15 @@ if ($action eq "adduser") {
 
     create_homedir(
         home_dir => $home_dir,
+        new_name => $new_name,
         uid => $new_uid,
         gid => $primary_gid,
         copy_skeleton => $no_copy_skel ? 0 : 1,
         system_user => 0,
         no_create_home => $no_create_home,
-        dir_mode => $dir_mode,
+        encrypt_home => $encrypt_home,
         config => \%config,
-    ) or cleanup();
+    ) and cleanup();
 
     # useradd without -p has left the account disabled (password string is '!')
     if ($ask_passwd) {
@@ -1508,24 +1513,6 @@ sub usage_error {
     exit( RET_INVALID_CALL );
 }
 
-# get_dir_mode: return the appropriate permissions mode for a home directory
-# parameters:
-#   none
-# return value:
-#   a valid octal mode
-sub get_dir_mode
-  {
-    my $mode = $found_sys_opt
-      ? $config{"sys_dir_mode"}
-      : $config{"dir_mode"};
-
-    if(!defined($mode) || ! ($mode =~ /[0-7]{3}/ || $mode =~ /[0-7]{4}/)) {
-        $mode = ($found_sys_opt) ? "755" : "0700";
-    }
-
-    return oct($mode);
-  }
-
 # Local Variables:
 # mode:cperl
 # cperl-indent-level:4


=====================================
debian/control
=====================================
@@ -14,7 +14,7 @@ Architecture: all
 Multi-Arch: foreign
 Pre-Depends: ${misc:Pre-Depends}
 Depends: passwd (>= 1:4.19.0-4), ${misc:Depends}
-Suggests: liblocale-gettext-perl, perl, cron, quota
+Suggests: liblocale-gettext-perl, perl, cron, quota, ecryptfs-utils (>= 67-1)
 Description: add and remove users and groups
  This package includes the 'adduser' and 'deluser' commands for creating
  and removing users.


=====================================
debian/tests/control
=====================================
@@ -3,6 +3,16 @@ Depends: adduser, cron, perl, login
 Restrictions: needs-root
 Features: test-name=package-test-suite
 
+Test-Command: /usr/bin/prove -p -v debian/tests/ecryptfs
+Depends: cron, ecryptfs-utils, kmod, perl
+Restrictions: allow-stderr isolation-machine needs-root
+Features: test-name=ecryptfs-with-pkg
+
+Test-Command: /usr/bin/prove -p -v debian/tests/ecryptfs-no-package
+Depends: cron, kmod, perl
+Restrictions: allow-stderr isolation-machine needs-root
+Features: test-name=ecryptfs-without-pkg
+
 Test-Command: cd testsuite/ && ./runsuite.sh
 Depends: adduser, cron, perl, login
 Restrictions: allow-stderr breaks-testbed needs-root


=====================================
debian/tests/ecryptfs-no-package/encrypt_home_no_package.t
=====================================
@@ -0,0 +1,23 @@
+#! /usr/bin/perl -Idebian/tests/lib
+
+use diagnostics;
+use strict;
+use warnings;
+
+use AdduserTestsCommon;
+
+# enable ecryptfs kernel module
+system('/sbin/modprobe', 'ecryptfs');
+
+my $test_user="foocrypt";
+
+assert_user_does_not_exist($test_user);
+
+assert_command_failure('/usr/sbin/adduser', '--encrypt-home', $test_user);
+
+system("getent passwd $test_user");
+system("ls -l /home /home/$test_user");
+
+assert_user_does_not_exist($test_user);
+
+assert_path_does_not_exist("/home/$test_user");


=====================================
debian/tests/ecryptfs/encrypt_home.t
=====================================
@@ -0,0 +1,31 @@
+#! /usr/bin/perl -Idebian/tests/lib
+
+use diagnostics;
+use strict;
+use warnings;
+
+use AdduserTestsCommon;
+
+# enable ecryptfs kernel module
+system('/sbin/modprobe', 'ecryptfs');
+
+my $test_user="foocrypt";
+
+assert_user_does_not_exist($test_user);
+
+assert_command_success('/usr/sbin/adduser', '--encrypt-home', $test_user);
+
+assert_user_exists($test_user);
+assert_group_exists($test_user);
+assert_group_membership_exists($test_user, $test_user);
+
+# test for ecryptfs files stored in $HOME
+assert_path_exists("/home/$test_user/.ecryptfs");
+assert_path_exists("/home/$test_user/.Private");
+# and not stored in $HOME
+assert_path_exists("/home/.ecryptfs/$test_user");
+
+assert_command_success('/usr/sbin/deluser', '--remove-home', $test_user);
+assert_user_does_not_exist($test_user);
+assert_path_does_not_exist("/home/$test_user");
+assert_path_does_not_exist("/home/.ecryptfs/$test_user");
\ No newline at end of file


=====================================
debian/tests/f/00test.t
=====================================
@@ -0,0 +1,11 @@
+#! /usr/bin/perl -Idebian/tests/lib
+
+use diagnostics;
+use strict;
+use warnings;
+
+use AdduserTestsCommon;
+
+assert_path_exists("/");
+
+# vim: tabstop=4 shiftwidth=4 expandtab


=====================================
debian/tests/f/addusertogroup_underscore.t
=====================================
@@ -9,12 +9,17 @@ use warnings;
 
 use AdduserTestsCommon;
 
+my $cl_user = AdduserTestsCommon::AdduserTestCleanup->new(
+    \&cleanup_user
+);
+
 # create user and group
 my $test_user="u1099397";
 my $test_sysuser="_u1099397";
 my $test_group="g1099397";
 my $test_sysgroup="_g1099397";
 my $nonexistent="/nonexistent";
+$cl_user->add(qw($test_user $test_sysuser $test_group $test_sysgroup));
 assert_user_does_not_exist($test_user);
 assert_user_does_not_exist($test_sysuser);
 assert_group_does_not_exist($test_group);
@@ -113,6 +118,7 @@ assert_command_success('/usr/sbin/deluser',
     $test_sysuser);
 assert_user_does_not_exist($test_sysuser);
 
+$cl_user->finalize();
 
 # end of test
 # vim: tabstop=4 shiftwidth=4 expandtab


=====================================
debian/tests/f/deluser_quiet.t
=====================================
@@ -9,13 +9,12 @@ my $name='duq';
 
 use AdduserTestsCommon;
 
-
-END {
-    remove_tree("/home/$name");
-    remove_tree("/var/mail/$name");
-}
+my $cl_user = AdduserTestsCommon::AdduserTestCleanup->new(
+    \&cleanup_user
+);
 
 assert_user_does_not_exist($name);
+$cl_user->add($name);
 assert_command_success(
     '/usr/sbin/adduser',
     '--stdoutmsglevel=error', '--stderrmsglevel=error',
@@ -28,5 +27,6 @@ my $output = `/usr/sbin/deluser --stdoutmsglevel=error --stderrmsglevel=error $n
 is($output, '', 'option "--stdoutmsglevel=error" silences deluser output under normal use');
 
 assert_user_does_not_exist($name);
+$cl_user->finalize();
 
 # vim: tabstop=4 shiftwidth=4 expandtab


=====================================
debian/tests/f/skel.t
=====================================
@@ -10,24 +10,10 @@ use AdduserTestsCommon;
 my $name="ausskel";
 
 END {
-    remove_tree("/var/mail/$name");
-    unlink("/etc/skel/test\ file");
-    unlink("/etc/skel/Tüst");
-    unlink("/etc/skel/ŞĞÇaŞ-tst");
-    unlink("/etc/skel/Masaüstü/ŞĞÇaŞ-tst");
-    rmdir("/etc/skel/Masaüstü");
+    cleanup_home_directory_tests();
+    cleanup_user($name);
 }
-
-system("cp /etc/skel/.bashrc /etc/skel/test\\ file");
-assert_path_is_a_file("/etc/skel/test file");
-system("cp /etc/skel/.bashrc /etc/skel/Tüst");
-assert_path_is_a_file("/etc/skel/Tüst");
-system("cp /etc/skel/.bashrc /etc/skel/ŞĞÇaŞ-tst");
-assert_path_is_a_file("/etc/skel/ŞĞÇaŞ-tst");
-system("mkdir -p /etc/skel/Masaüstü");
-assert_path_is_a_directory("/etc/skel/Masaüstü");
-system("cp /etc/skel/.bashrc /etc/skel/Masaüstü/ŞĞÇaŞ-tst");
-assert_path_is_a_file("/etc/skel/Masaüstü/ŞĞÇaŞ-tst");
+my $homedir_contents = initialize_home_directory_tests();
 
 assert_user_does_not_exist($name);
 assert_command_success(
@@ -40,15 +26,6 @@ assert_command_success(
 assert_user_exists($name);
 assert_user_has_home_directory($name,"/home/$name");
 assert_path_is_a_directory("/home/$name");
-
-my $skel_list = `find /etc/skel/ -mindepth 1 -printf "%f %l %m %s\n" | sort`;
-my $home_list = `find /home/$name/ -mindepth 1 -printf "%f %l %m %s\n" | sort`;
-ok($? == 0, "find /home/$name  successful");
-if( !ok($home_list eq $skel_list, 'files copied to home directory correct') ) {
-    print("skel_list: $skel_list\n");
-    print("home_list $home_list\n");
-    system("ls -al /etc/skel");
-    system("ls -al /home/$name");
-}
+assert_user_home_directory_content($name, "/home/$name", $homedir_contents);
 
 # vim: tabstop=4 shiftwidth=4 expandtab


=====================================
debian/tests/f/uidgidpool.t
=====================================
@@ -10,6 +10,14 @@ use AdduserTestsCommon;
 
 my @quiet=("--stdoutmsglevel=error", '--stderrmsglevel=error');
 
+my $cl_user = AdduserTestsCommon::AdduserTestCleanup->new(
+    \&cleanup_user
+);
+my $cl_tree = AdduserTestsCommon::AdduserTestCleanup->new(
+    \&cleanup_tree
+);
+
+
 # single pool file
 my $uidpoolfile="/etc/adduser-uidpool.conf";
 my $gidpoolfile="/etc/adduser-gidpool.conf";
@@ -17,6 +25,8 @@ my $poolbasedir="/etc/adduser-pool.d";
 my $uidpooldir="$poolbasedir/uid";
 my $gidpooldir="$poolbasedir/gid";
 my %confhash;
+$cl_tree->add(qw(/etc/adduser-uidpool.conf /etc/adduser-gidpool.conf));
+$cl_tree->add(qw(/etc/adduser-pool.d));
 
 my $auid=40123;
 my $agid=40234;
@@ -40,6 +50,8 @@ my @uidlist = (
     'shell' => '/bin/sh',
    }
 );
+$cl_tree->add(qw(/home/pool101 /home/pool202));
+$cl_user->add(qw(pooluid101 pooluid202));
 my $firstuid = (sort map {$_->{id}} @uidlist)[0];
 
 my @uidreserved = (
@@ -52,6 +64,8 @@ my @uidreserved = (
     'shell' => '/bin/sh',
    }
 );
+$cl_tree->add(qw(/home/uidreserved1 /home/auidreserved1));
+$cl_user->add(qw(uidreserved1));
 
 my @gidlist = (
     {
@@ -69,6 +83,7 @@ my @gidreserved = (
     id => $firstgid,
    }
 );
+$cl_user->add(qw(poolgid101 poolgid202 gidreserved1));
 
 # test creating user/group without uidpool set
 
@@ -414,7 +429,7 @@ foreach my $user( @uidlist ) {
     cleanup();
 }
 
-# remove test pool directories
-assert_command_success('rm', '-rf', $uidpooldir, $gidpooldir, $poolbasedir);
+$cl_user->finalize();
+$cl_tree->finalize();
 
 # vim: tabstop=4 shiftwidth=4 expandtab


=====================================
debian/tests/lib/AdduserTestsCommon.pm
=====================================
@@ -1,12 +1,97 @@
+package AdduserTestsCommon;
+
+use utf8;
+use Exporter 'import';
 use diagnostics;
 use strict;
 use warnings;
 use Encode;
-use utf8;
 use I18N::Langinfo qw(langinfo CODESET);
 use File::Path qw(remove_tree);
 use Test::More qw(no_plan);
 
+our @EXPORT = qw(
+    egetgrnam
+    egetpwnam
+    in_range
+    find_unused_uid
+    find_unused_name
+    find_unused_gid
+    assert_command_success
+    assert_command_failure
+    assert_command_result_silent
+    assert_command_failure_silent
+    assert_command_success_silent
+    assert_command_match_output
+    initialize_home_directory_tests
+    cleanup_home_directory_tests
+    assert_user_has_home_directory
+    assert_user_home_directory_empty
+    assert_user_home_directory_content
+    assert_group_does_not_exist
+    assert_group_is_system
+    assert_group_is_non_system
+    assert_user_is_system
+    assert_user_is_non_system
+    assert_gid_does_not_exist
+    assert_group_exists
+    assert_gid_exists
+    assert_group_gid_exists
+    group_gid_exists
+    assert_group_membership_does_not_exist
+    assert_group_membership_exists
+    group_membership_exists
+    assert_primary_group_membership_exists
+    primary_group_membership_exists
+    assert_supplementary_group_membership_exists
+    assert_supplementary_group_membership_does_not_exist
+    supplementary_group_membership_exists
+    assert_path_does_not_exist
+    assert_path_exists
+    assert_path_has_mode
+    assert_path_has_ownership
+    assert_path_is_a_file
+    assert_path_is_a_directory
+    assert_path_is_an_empty_directory
+    assert_user_does_not_exist
+    assert_user_exists
+    assert_uid_does_not_exist
+    assert_uid_exists
+    assert_user_uid_exists
+    user_uid_exists
+    assert_user_has_disabled_password
+    assert_user_has_comment
+    assert_dir_group_owner
+    assert_user_has_login_shell
+    assert_user_has_uid
+    assert_group_has_gid
+    which
+    apply_config
+    apply_config_hash
+    assert_user_status
+    existing_user_status
+    existing_group_status
+    cleanup_tree
+    cleanup_user
+    EXISTING_NOT_FOUND
+    EXISTING_FOUND
+    EXISTING_SYSTEM
+    EXISTING_ID_MISMATCH
+    EXISTING_LOCKED
+    EXISTING_HAS_PASSWORD
+    EXISTING_EXPIRED
+    EXISTING_NOLOGIN
+    SYS_MIN
+    SYS_MAX
+    USER_MIN
+    USER_MAX
+    remove_tree
+    is
+    ok
+    like
+);
+
+
 BEGIN {
     if (! -f '/var/cache/adduser/tests/state.tar') {
         my @conffiles = (
@@ -49,6 +134,13 @@ my $charset = langinfo(CODESET);
 binmode(STDOUT, ":encoding($charset)");
 binmode(STDERR, ":encoding($charset)");
 
+our @skelfiles = (
+    "test file",
+    "Tüst",
+    "ŞĞÇaŞ-tst",
+    "Masaüstü/ŞĞÇaŞ-tst",
+);
+
 sub egetgrnam {
     my ($name) = @_;
     $name = encode($charset, $name);
@@ -182,6 +274,49 @@ sub assert_command_match_output {
     isnt($? >> 8, 0, "command failure (expected): @_");
 }
 
+sub initialize_home_directory_tests {
+    # initialize /etc/skel with some weird files
+    ok(1, "initialize /etc/skel with test files");
+    system("mkdir", "-p", "/etc/skel/Masaüstü");
+    assert_path_is_a_directory("/etc/skel/Masaüstü");
+    foreach my $file (@skelfiles) {
+        system("cp", "/etc/skel/.bashrc", "/etc/skel/$file");
+        assert_path_is_a_file("/etc/skel/$file");
+    }
+
+    my $skel_contents = `find /etc/skel/ -mindepth 1 -printf "%f %l %m %s\n" | sort`;
+    return $skel_contents;
+}
+
+sub assert_user_has_home_directory {
+    my ($user, $home) = @_;
+    is((egetpwnam($user))[7], $home, "user has home directory: ~$user is $home");
+}
+
+sub assert_user_home_directory_empty {
+    my ($user, $home) = @_;
+}
+
+sub assert_user_home_directory_content {
+    my ($user, $home, $expected_content) = @_;
+    my $current_content = `find $home -mindepth 1 -printf "%f %l %m %s\n" | sort`;
+    if( !ok($expected_content eq $current_content, 'files copied to home directory correct') ) {
+        print("expected_content (internal format):\n$expected_content\n");
+        print("current_content (internal format):\n$current_content\n");
+        system("ls", "-al", "$home");
+    }
+}
+
+sub cleanup_home_directory_tests {
+    ok(1, "remove test files from /etc/skel");
+    foreach my $file (@skelfiles) {
+        cleanup_tree("/etc/skel/$file");
+        assert_path_does_not_exist("/etc/skel/$file");
+    }
+    cleanup_tree("/etc/skel/Masaüstü");
+    assert_path_does_not_exist("/etc/skel/Masaüstü");
+}
+
 sub assert_group_does_not_exist {
     my $group = shift;
     is(egetgrnam($group), undef, "group does not exist: $group");
@@ -333,7 +468,7 @@ sub supplementary_group_membership_exists {
 }
 
 sub assert_path_does_not_exist {
-    my $path = shift;
+    my $path = encode('UTF-8', shift);
     ok(! -e $path, "path does not exist: $path");
 }
 
@@ -383,17 +518,17 @@ sub assert_path_has_ownership {
 }
 
 sub assert_path_is_a_file {
-    my $path = shift;
+    my $path = encode('UTF-8', shift);
     ok(-f $path, "path is a file: $path");
 }
 
 sub assert_path_is_a_directory {
-    my $path = shift;
+    my $path = encode('UTF-8', shift);
     ok(-d $path, "path is a directory: $path");
 }
 
 sub assert_path_is_an_empty_directory {
-    my $path = shift;
+    my $path = encode('UTF-8', shift);
     my $name = "path is an empty directory: $path";
 
     my $dh;
@@ -471,11 +606,6 @@ sub assert_user_has_disabled_password {
     fail($name);
 }
 
-sub assert_user_has_home_directory {
-    my ($user, $home) = @_;
-    is((egetpwnam($user))[7], $home, "user has home directory: ~$user is $home");
-}
-
 sub assert_user_has_comment {
     my ($user, $comment) = @_;
     is((egetpwnam($user))[6], $comment, "user has comment: ~$user is $comment");
@@ -626,6 +756,109 @@ sub existing_group_status {
     return $ret;
 }
 
+# those functions can be used as cleanup functions for AdduserTestCleanup
+
+sub cleanup_tree {
+    my ($path) = @_;
+    return unless defined $path && length $path;
+
+    remove_tree($path);
+}
+
+sub cleanup_user {
+    my ($username) = @_;
+    return unless defined $username && length $username;
+
+    my $home_dir;
+
+    # Look up passwd entry
+    if (my @pw = getpwnam($username)) {
+        $home_dir = $pw[7];  # in getpwnam: (name, passwd, uid, gid, quota, comment, gcos, dir, shell)
+    }
+
+    open(my $null, '>', '/dev/null') or die;
+    open(STDOUT, '>&', $null);
+    open(STDERR, '>&', $null);
+    system('userdel', '-r', $username);
+    system('groupdel', $username);
+    close($null);
+
+    remove_tree($home_dir) if $home_dir;
+    remove_tree("/var/mail/$username");
+    remove_tree("/var/spool/cron/crontabs/$username");
+}
+
+
+package AdduserTestsCommon::AdduserTestCleanup;
+
+sub new {
+    my ($class, $callback) = @_;
+    bless {
+        list     => [],
+        callback => $callback,
+        done     => 0,
+    }, $class;
+}
+
+sub add {
+    my ($self, @items) = @_;
+    push @{ $self->{list} }, @items;
+}
+
+sub finalize {
+    my ($self) = @_;
+    return if $self->{done}++;
+
+    my $cb = $self->{callback} or return;
+    for my $item (@{ $self->{list} }) {
+        eval { $cb->($item) };
+        warn "cleanup failed for [$item]: $@" if $@;
+    }
+}
+
+sub DESTROY {
+    my ($self) = @_;
+
+    # Safe fallback only
+    return if ${^GLOBAL_PHASE} eq 'DESTRUCT';
+
+    $self->finalize;
+}
+
+
+# example usage
+# 
+# use AdduserTestsCommon::AdduserTestCleanup;
+# 
+# sub cleanup_file {
+#     my ($path) = @_;
+#     unlink $path or warn "unlink $path failed: $!";
+# }
+# 
+# my $cleanup = AdduserTestsCommon::AdduserTestCleanup->new(
+#     sub {
+#         my ($item) = @_;
+#         cleanup_file($item);
+#     }
+# );
+# 
+# $cleanup->add(qw(
+#     /tmp/adduser-test-1
+#     /tmp/adduser-test-2
+# ));
+# 
+# $cleanup->add(qw(
+#     /tmp/adduser-test-3
+# ));
+#
+# # later, at a convenient point
+# $cleanup->finalize;
+# 
+# 
+# # Leaving the block destroys $cleanup, triggering cleanup callbacks
+# 
+# done_testing;
+
 1;
 
 # vim: tabstop=4 shiftwidth=4 expandtab


=====================================
deluser
=====================================
@@ -25,14 +25,14 @@ use utf8;
 
 use Getopt::Long;
 
-use Debian::AdduserCommon 3.139;
-use Debian::AdduserLogging 3.139;
-use Debian::AdduserRetvalues 3.139;
-use Debian::AdduserStatefile 3.139;
+use Debian::AdduserCommon 3.157;
+use Debian::AdduserLogging 3.157;
+use Debian::AdduserRetvalues 3.157;
+use Debian::AdduserStatefile 3.157;
 BEGIN {
-    if ( Debian::AdduserCommon->VERSION != version->declare('3.139') ||
-         Debian::AdduserLogging->VERSION != version->declare('3.139') ||
-         Debian::AdduserRetvalues->VERSION != version->declare('3.139') ) {
+    if ( Debian::AdduserCommon->VERSION != version->declare('3.157') ||
+         Debian::AdduserLogging->VERSION != version->declare('3.157') ||
+         Debian::AdduserRetvalues->VERSION != version->declare('3.157') ) {
            die "wrong module version in adduser, check your packaging or path";
     }
 }
@@ -387,8 +387,28 @@ if($action eq "deluser") {
                     if(-d $name);
             } # sub home_match
 
+            # collect ecryptfs config files not stored in $HOME
+            sub ecryptfs_match {
+                # untaint the name without changing it
+                $File::Find::name =~ /(.*)/s;  # captures the full string
+                $name = $1;
+                if ( $name !~ m[^/var/lib/ecryptfs/\Q$user] &&  $name !~ m[^/home/\.ecryptfs/\Q$user]) {
+                    $File::Find::prune=1;
+                    return;
+                }
+                push(@files, $name)
+                    if(-f $name || -l $name);
+                push(@dirs, $name)
+                    if(-d $name);
+            } # sub ecryptfs_match
+
             File::Find::find({wanted => \&home_match, untaint => 1, no_chdir => 1}, $pw_homedir)
                 if(-d "$pw_homedir");
+            if(-d "/var/lib/ecryptfs/$user") {
+                File::Find::find({wanted => \&ecryptfs_match, untaint => 1, no_chdir => 1}, "/var/lib/ecryptfs/$user");
+            } elsif (-d "/home/.ecryptfs/$user") {
+                File::Find::find({wanted => \&ecryptfs_match, untaint => 1, no_chdir => 1}, "/home/.ecryptfs/$user");
+            }
             push(@files, "/var/mail/$user")
                 if(-e "/var/mail/$user");
         }


=====================================
doc/adduser.8
=====================================
@@ -26,6 +26,7 @@ adduser, addgroup \- add or manipulate users or groups
 .OP \-\-debug
 .OP \-\-disabled\-login
 .OP \-\-disabled\-password
+.OP \-\-encrypt\-home
 .OP \-\-firstgid id
 .OP \-\-firstuid id
 .OP \-\-gid id
@@ -226,6 +227,11 @@ might be pre-determined with the \fBUID_POOL\fP and \fBGID_POOL\fP option,
 documented in
 .BR adduser.conf (5).
 
+To set up an encrypted home directory for the new user, add the
+.B \-\-encrypt\-home
+option.  For more information, refer to the \-b option of
+.B ecryptfs-setup-private(1).
+
 .SS "Add a system user"
 If called with one non-option argument and the \fB\-\-system\fP option,
 \fBadduser\fP will add a



View it on GitLab: https://salsa.debian.org/debian/adduser/-/compare/cf1bbcd9d0f5739f0c49d296f2a400cd8f3b31f4...76106035c910f315f9bca2f9f304e3d1e2f9c101

-- 
View it on GitLab: https://salsa.debian.org/debian/adduser/-/compare/cf1bbcd9d0f5739f0c49d296f2a400cd8f3b31f4...76106035c910f315f9bca2f9f304e3d1e2f9c101
You're receiving this email because of your account on salsa.debian.org. Manage all notifications: https://salsa.debian.org/-/profile/notifications | Help: https://salsa.debian.org/help


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://alioth-lists.debian.net/pipermail/pkg-shadow-devel/attachments/20260605/92441446/attachment-0001.htm>


More information about the Pkg-shadow-devel mailing list