$OpenBSD: patch-lib_Rex_User_OpenBSD_pm,v 1.1.1.1 2019/02/21 04:54:50 afresh1 Exp $

Index: lib/Rex/User/OpenBSD.pm
--- lib/Rex/User/OpenBSD.pm.orig
+++ lib/Rex/User/OpenBSD.pm
@@ -14,14 +14,16 @@ our $VERSION = '1.6.0'; # VERSION
 use Rex::Logger;
 use Rex::Commands::MD5;
 use Rex::Helper::Run;
+use Rex::Helper::Encode;
 use Rex::Commands::Fs;
-use Rex::User::NetBSD;
 use Rex::Interface::File;
 use Rex::Interface::Fs;
 use Rex::Interface::Exec;
+use Rex::User::Linux;
 use Rex::Helper::Path;
+use JSON::MaybeXS;
 
-use base qw(Rex::User::NetBSD);
+use base qw(Rex::User::Linux);
 
 sub new {
   my $that  = shift;
@@ -40,7 +42,8 @@ sub create_user {
 
   my $old_pw_md5 = md5("/etc/passwd");
 
-  my $uid = $self->get_uid($user);
+  my $uid       = $self->get_uid($user);
+  my %user_info = $self->get_user($user);
   my $should_create_home;
 
   if ( $data->{'create_home'} || $data->{'create-home'} ) {
@@ -70,7 +73,11 @@ sub create_user {
   }
 
   if ( exists $data->{uid} ) {
-    $cmd .= " -u " . $data->{uid};
+
+    # On OpenBSD, "usermod -u n login" fails when the user login
+    # has already n as userid. So skip it from the command arg
+    # when the uid is already correct.
+    $cmd .= " -u " . $data->{uid} unless $data->{uid} == $user_info{uid};
   }
 
   if ( exists $data->{home} ) {
@@ -93,6 +100,10 @@ sub create_user {
     $cmd .= " -e '" . $data->{expire} . "'";
   }
 
+  if ( exists $data->{login_class} ) {
+    $cmd .= " -L '" . $data->{login_class} . "'";
+  }
+
   if ( exists $data->{groups} ) {
     my @groups    = @{ $data->{groups} };
     my $pri_group = shift @groups;
@@ -170,6 +181,127 @@ sub create_user {
       ret     => $self->get_uid($user),
       },
       ;
+  }
+
+}
+
+sub get_user {
+  my ( $self, $user ) = @_;
+
+  Rex::Logger::debug("Getting information for $user");
+  my $rnd_file = get_tmp_file;
+  my $fh       = Rex::Interface::File->create;
+  my $script   = q|
+    unlink $0;
+    print to_json([ getpwnam($ARGV[0]) ]);
+  |;
+  $fh->open( ">", $rnd_file );
+  $fh->write($script);
+  $fh->write( func_to_json() );
+  $fh->close;
+
+  my $data_str = i_run "perl $rnd_file $user", fail_ok => 1;
+  if ( $? != 0 ) {
+    die("Error getting user information for $user");
+  }
+
+  my $data = decode_json($data_str);
+
+  return (
+    name     => $data->[0],
+    password => $data->[1],
+    uid      => $data->[2],
+    gid      => $data->[3],
+    pwchange => $data->[4],
+    class    => $data->[5],
+    comment  => $data->[6],
+    home     => $data->[7],
+    shell    => $data->[8],
+    expire   => $data->[9],
+  );
+}
+
+sub lock_password {
+  my ( $self, $user ) = @_;
+
+  # Is the password already locked?
+  my $result = i_run "getent passwd $user", fail_ok => 1;
+
+  if ( $result !~ /^$user.*$/ ) {
+    die "Unexpected result from getent: $result";
+  }
+  elsif ( $result =~ /^$user.*-$/ ) {
+
+    # Already locked
+    return { changed => 0 };
+  }
+  else {
+    my $ret = i_run "usermod -Z $user", fail_ok => 1;
+    if ( $? != 0 ) {
+      die("Error locking account $user: $ret");
+    }
+    return {
+      changed => 1,
+      ret     => $ret,
+    };
+  }
+}
+
+sub unlock_password {
+  my ( $self, $user ) = @_;
+
+  # Is the password already unlocked?
+  my $result = i_run "getent passwd $user", fail_ok => 1;
+
+  if ( $result !~ /^$user.*$/ ) {
+    die "Unexpected result from getent: $result";
+  }
+  elsif ( $result !~ /^$user.*-$/ ) {
+
+    # Already unlocked
+    return { changed => 0 };
+  }
+  else {
+    my $ret = i_run "usermod -U $user", sub { @_ }, fail_ok => 1;
+    if ( $? != 0 ) {
+      die("Error unlocking account $user: $ret");
+    }
+    return {
+      changed => 1,
+      ret     => $ret,
+    };
+  }
+}
+
+sub rm_user {
+  my ( $self, $user, $data ) = @_;
+
+  Rex::Logger::debug("Removing user $user");
+
+  my %user_info = $self->get_user($user);
+
+  my $cmd = "userdel";
+
+  if ( exists $data->{delete_home} ) {
+    $cmd .= " -r";
+  }
+
+  my $output = i_run $cmd . " " . $user, fail_ok => 1;
+  if ( $? == 67 ) {
+    Rex::Logger::info( "Cannot delete user $user (no such user)", "warn" );
+  }
+  elsif ( $? != 0 ) {
+    die("Error deleting user $user ($output)");
+  }
+
+  if ( exists $data->{delete_home} && is_dir( $user_info{home} ) ) {
+    Rex::Logger::debug(
+      "userdel doesn't delete home directory. removing it now by hand...");
+    rmdir $user_info{home};
+  }
+
+  if ( $? != 0 ) {
+    die( "Error removing " . $user_info{home} );
   }
 
 }
