[Pkg-shadow-devel] [Git][debian/adduser][wip/fixup_existing] fix EXISTING_HAS_PASSWORD to correctly handle !

Marc Haber (@zugschlus) gitlab at salsa.debian.org
Sat Jan 10 20:49:35 GMT 2026



Marc Haber pushed to branch wip/fixup_existing at Debian / adduser


Commits:
4da77685 by Marc Haber at 2026-01-10T21:49:24+01:00
fix EXISTING_HAS_PASSWORD to correctly handle !

This now also handles !something in the password field

- - - - -


1 changed file:

- AdduserCommon.pm


Changes:

=====================================
AdduserCommon.pm
=====================================
@@ -102,11 +102,8 @@ use constant {
     EXISTING_ID_MISMATCH => 4,
     EXISTING_LOCKED => 8,
     EXISTING_HAS_PASSWORD => 16,
-    EXISTING_DISABLED_PASS => 40,        # 32 | EXISTING_LOCKED
-    EXISTING_INVALID_PASS => 72,    # 64 | EXISTING_LOCKED
-    EXISTING_EXPIRED => 136,         # 128 | EXISTING_LOCKED
-    EXISTING_NOLOGIN => 264,        # 256 | EXISTING_LOCKED
-    EXISTING_PASSWORDLESS => 512,
+    EXISTING_EXPIRED => 32,
+    EXISTING_NOLOGIN => 64,
 };
 
 use constant {
@@ -149,11 +146,8 @@ use constant {
     'EXISTING_ID_MISMATCH',
     'EXISTING_LOCKED',
     'EXISTING_HAS_PASSWORD',
-    'EXISTING_DISABLED_PASS',
-    'EXISTING_INVALID_PASS',
     'EXISTING_EXPIRED',
     'EXISTING_NOLOGIN',
-    'EXISTING_PASSWORDLESS',
     'STDOUTDEFLEVEL',
     'STDERRDEFLEVEL',
     'LOGMSGDEFLEVEL',
@@ -609,48 +603,47 @@ END {
 #   new_name: the name of the user to check
 #   new_uid : the UID of the user
 # return value:
-#   bitwise combination of these constants:
-#       EXISTING_NOT_FOUND => 0
-#       EXISTING_FOUND => 1
-#       EXISTING_SYSTEM => 2
-#       EXISTING_ID_MISMATCH => 4
-#       EXISTING_LOCKED => 8
-#       EXISTING_HAS_PASSWORD => 16
-#       EXISTING_DISABLED_PASS => 32
-#       EXISTING_INVALID_PASS => 64
-#       EXISTING_NOLOGIN => 128
-#       EXISTING_EXPIRED => 256
-#       EXISTING_PASSWORDLESS => 512
+#   bitwise combination of the EXISTING_ constants
 sub existing_user_status {
-    my ($config, $new_name,$new_uid) = @_;
+    my ($config, $user_name,$user_uid) = @_;
     my $ret = EXISTING_NOT_FOUND;
-    log_trace( "existing_user_status called with new_name %s, new_uid %s, first_system_uid %s, last_system_uid %s", $new_name, $new_uid, $config->{"first_system_uid"}, $config->{"last_system_uid"} );
-    if (my (undef,$pw,$uid,undef,undef,$home,$shell) = egetpwnam($new_name)) {
+    log_trace( "existing_user_status called with user_name %s, user_uid %s, first_system_uid %s, last_system_uid %s", $user_name, $user_uid, $config->{"first_system_uid"}, $config->{"last_system_uid"} );
+
+    # collect user data
+    my (
+        $egpwn_name, $egpwn_passwd, $egpwn_uid, $egpwn_gid, $egpwn_quota,
+        $egpwn_comment, $egpwn_gcos, $egpwn_dir, $egpwn_shell, $egpwn_expire,
+        $egpwn_rest
+    ) = egetpwnam($user_name);
+    my $shadow_line = `getent shadow $user_name`;
+    chomp $shadow_line;
+    my @shadow_fields = split /:/, $shadow_line;
+    if (defined $egpwn_uid) {
         # user with the name exists
-        log_trace( "egetpwnam(%s) returns %s, %s, %s, %s", $new_name, $pw, $uid, $home, $shell );
+        log_trace( "egetpwnam(%s) returns %s, %s, %s, %s", $user_name, $egpwn_passwd, $egpwn_uid, $egpwn_dir, $egpwn_shell );
         $ret |= EXISTING_FOUND;
-        $ret |= EXISTING_ID_MISMATCH if (defined($new_uid) && $uid != $new_uid);
+        $ret |= EXISTING_ID_MISMATCH if (defined($user_uid) && $egpwn_uid != $user_uid);
         $ret |= EXISTING_SYSTEM if
-            (($uid >= $config->{"first_system_uid"}) && ($uid <= $config->{"last_system_uid"}));
+            (($egpwn_uid >= $config->{"first_system_uid"}) && ($egpwn_uid <= $config->{"last_system_uid"}));
         $ret |= EXISTING_HAS_PASSWORD if
-            (defined $pw && $pw ne '' && $pw ne '!' && $pw !~ /^\*/);
-        $ret |= EXISTING_LOCKED if (substr($pw,0,1) eq "!");  # TODO: also check expiry?
+            (defined $egpwn_passwd && $egpwn_passwd ne '' && ($egpwn_passwd =~ s/^[!*]+//r ne ''));
+
+        my $password_field = $shadow_fields[1] // '';
+        $ret |= EXISTING_LOCKED if $password_field =~ /^[!*]/;
 
-        # Note: the following conditions will also be true against EXISTING_LOCKED
-        # iow, if $x & EXISTING_INVALID_PASS, then $x & EXISTING_LOCKED
-        $ret |= EXISTING_DISABLED_PASS if (substr($pw,0,1) eq "!");
-        $ret |= EXISTING_INVALID_PASS if (substr($pw,0,1) eq "*");
-        $ret |= EXISTING_PASSWORDLESS if ($pw eq '!');
-        $ret |= EXISTING_NOLOGIN if ($shell =~ /bin\/nologin/);
+        $ret |= EXISTING_NOLOGIN if ($egpwn_shell =~ /bin\/nologin/);
 
-        my $age = `chage -l $new_name`;
-        $ret |= EXISTING_EXPIRED if ($age =~ /password must be changed/);
+        my $acct_exp = $shadow_fields[7] // '';
+        if ($acct_exp && $acct_exp > 0) {
+            my $today_days = int(time / 86400);
+            $ret |= EXISTING_EXPIRED if $acct_exp < $today_days;
+        }
 
-    } elsif (defined($new_uid) && getpwuid($new_uid)) {
+    } elsif (defined($user_uid) && getpwuid($user_uid)) {
         # user with the uid exists
         $ret |= EXISTING_ID_MISMATCH;
     }
-    log_trace( "existing_user_status( %s, %s ) returns %s (%s)", $new_name, $new_uid, $ret, existing_value_desc($ret) );
+    log_trace( "existing_user_status( %s, %s ) returns %s (%s)", $user_name, $user_uid, $ret, existing_value_desc($ret) );
     return $ret;
 }
 



View it on GitLab: https://salsa.debian.org/debian/adduser/-/commit/4da77685fd171e653de087605635c064639b5b1f

-- 
View it on GitLab: https://salsa.debian.org/debian/adduser/-/commit/4da77685fd171e653de087605635c064639b5b1f
You're receiving this email because of your account on salsa.debian.org.


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


More information about the Pkg-shadow-devel mailing list