File Coverage

lib/Rex/User/FreeBSD.pm
Criterion Covered Total %
statement 44 180 24.4
branch 0 54 0.0
condition 0 21 0.0
subroutine 15 24 62.5
pod 0 9 0.0
total 59 288 20.4


line stmt bran cond sub pod time code
1             #
2             # (c) Jan Gehring
3             #
4              
5             package Rex::User::FreeBSD;
6              
7 1     1   14 use v5.12.5;
  1         4  
8 1     1   5 use warnings;
  1         2  
  1         40  
9              
10             our $VERSION = '1.14.3'; # VERSION
11              
12 1     1   6 use Rex::Logger;
  1         2  
  1         6  
13 1     1   20 use Rex::Commands::MD5;
  1         1  
  1         10  
14 1     1   5 use Rex::Helper::Run;
  1         3  
  1         63  
15 1     1   7 use Rex::Helper::Encode;
  1         24  
  1         61  
16 1     1   7 use Rex::Commands::Fs;
  1         4  
  1         16  
17 1     1   11 use Rex::Commands::File;
  1         2  
  1         7  
18 1     1   14 use Rex::Interface::File;
  1         6  
  1         15  
19 1     1   35 use Rex::Interface::Fs;
  1         2  
  1         20  
20 1     1   44 use Rex::Interface::Exec;
  1         2  
  1         9  
21 1     1   27 use Rex::User::Linux;
  1         3  
  1         13  
22 1     1   36 use Rex::Helper::Path;
  1         3  
  1         92  
23 1     1   14 use JSON::MaybeXS;
  1         4  
  1         65  
24              
25 1     1   5 use base qw(Rex::User::Linux);
  1         3  
  1         1863  
26              
27             sub new {
28 0     0 0   my $that = shift;
29 0   0       my $proto = ref($that) || $that;
30 0           my $self = $proto->SUPER::new(@_);
31              
32 0           bless( $self, $proto );
33              
34 0           return $self;
35             }
36              
37             sub create_user {
38 0     0 0   my ( $self, $user, $data ) = @_;
39              
40 0           my $cmd;
41              
42 0           my $uid = $self->get_uid($user);
43 0           my $should_create_home;
44              
45 0           my $old_pw_md5 = md5("/etc/passwd");
46              
47 0 0 0       if ( $data->{'create_home'} || $data->{'create-home'} ) {
    0 0        
    0 0        
      0        
      0        
48 0           $should_create_home = 1;
49             }
50             elsif ( $data->{'no_create_home'} || $data->{'no-create-home'} ) {
51 0           $should_create_home = 0;
52             }
53             elsif ( ( exists $data->{'no_create_home'} && $data->{'no_create_home'} == 0 )
54             || ( exists $data->{'no-create-home'} && $data->{'no-create-home'} == 0 ) )
55             {
56 0           $should_create_home = 1;
57             }
58              
59 0 0         if ( !defined $uid ) {
60 0           Rex::Logger::debug("User $user does not exists. Creating it now.");
61 0           $cmd = "pw useradd ";
62             }
63             else {
64 0           Rex::Logger::debug("User $user already exists. Updating...");
65 0           $cmd = "pw usermod ";
66             }
67              
68 0 0         if ( $data->{"uid"} ) {
69 0           $cmd .= " -u " . $data->{"uid"};
70             }
71              
72 0 0         if ( $data->{"home"} ) {
73 0           $cmd .= " -d " . $data->{"home"};
74             }
75              
76 0 0 0       if ( $should_create_home && !defined $uid ) { #useradd mode
77 0           $cmd .= " -m ";
78             }
79              
80 0 0         if ( exists $data->{shell} ) {
81 0           $cmd .= " -s " . $data->{shell};
82             }
83              
84 0 0         if ( $data->{"comment"} ) {
85 0           $cmd .= " -c \"" . $data->{"comment"} . "\" ";
86             }
87              
88 0 0         if ( $data->{"expire"} ) {
89 0           $cmd .= " -e " . $data->{"expire"};
90             }
91              
92 0 0         if ( $data->{"groups"} ) {
93 0           my @groups = @{ $data->{groups} };
  0            
94 0           $cmd .= " -g " . $groups[0];
95 0           $cmd .= " -G " . join( ",", @groups );
96             }
97              
98 0           my $rnd_file = get_tmp_file;
99 0           my $fh = Rex::Interface::File->create;
100 0           $fh->open( ">", $rnd_file );
101 0           $fh->write("$cmd -n $user\nexit \$?\n");
102 0           $fh->close;
103              
104 0           i_run "/bin/sh $rnd_file", fail_ok => 1;
105 0           my $retval = $?;
106 0           Rex::Interface::Fs->create()->unlink($rnd_file);
107              
108 0 0         if ( $retval == 0 ) {
109 0           Rex::Logger::debug("User $user created/updated.");
110             }
111             else {
112 0           Rex::Logger::info( "Error creating/updating user $user", "warn" );
113 0           die("Error creating/updating user $user");
114             }
115              
116 0 0         if ( exists $data->{password} ) {
117 0           Rex::Logger::debug("Changing password of $user.");
118              
119 0           $rnd_file = get_tmp_file;
120 0           $fh = Rex::Interface::File->create;
121 0           $fh->open( ">", $rnd_file );
122             $fh->write(
123 0           "echo '" . $data->{password} . "' | pw usermod $user -h 0\nexit \$?\n" );
124 0           $fh->close;
125              
126 0           i_run "/bin/sh $rnd_file", fail_ok => 1;
127 0           my $pw_retval = $?;
128 0           Rex::Interface::Fs->create()->unlink($rnd_file);
129              
130 0 0         if ( $pw_retval != 0 ) {
131 0           die("Error setting password for $user");
132             }
133              
134             }
135              
136 0           my $new_pw_md5 = md5("/etc/passwd");
137              
138 0 0         if ( $new_pw_md5 eq $old_pw_md5 ) {
139             return {
140 0           changed => 0,
141             ret => $self->get_uid($user),
142             };
143             }
144             else {
145             return {
146 0           changed => 1,
147             ret => $self->get_uid($user),
148             },
149             ;
150             }
151              
152             }
153              
154             sub rm_user {
155 0     0 0   my ( $self, $user, $data ) = @_;
156              
157 0           Rex::Logger::debug("Removing user $user");
158              
159 0           my $cmd = "pw userdel";
160              
161 0 0         if ( exists $data->{delete_home} ) {
162 0           $cmd .= " -r ";
163             }
164              
165 0           my $output = i_run $cmd . " -n " . $user, fail_ok => 1;
166 0 0         if ( $? == 67 ) {
    0          
167 0           Rex::Logger::info( "Cannot delete user $user (no such user)", "warn" );
168             }
169             elsif ( $? != 0 ) {
170 0           die("Error deleting user $user ($output)");
171             }
172              
173             }
174              
175             sub get_uid {
176 0     0 0   my ( $self, $user ) = @_;
177              
178 0           my %data = $self->get_user($user);
179 0           return $data{uid};
180             }
181              
182             sub get_user {
183 0     0 0   my ( $self, $user ) = @_;
184              
185 0           Rex::Logger::debug("Getting information for $user");
186 0           my $rnd_file = get_tmp_file;
187 0           my $fh = Rex::Interface::File->create;
188 0           my $script = q|
189             unlink $0;
190             print to_json([ getpwnam($ARGV[0]) ]);
191             |;
192 0           $fh->open( ">", $rnd_file );
193 0           $fh->write($script);
194 0           $fh->write( func_to_json() );
195 0           $fh->close;
196              
197 0           my $data_str = i_run "perl $rnd_file $user", fail_ok => 1;
198 0 0         if ( $? != 0 ) {
199 0           die("Error getting user information for $user");
200             }
201              
202 0           Rex::Interface::Fs->create()->unlink($rnd_file);
203              
204 0           my $data = decode_json($data_str);
205              
206             return (
207 0 0         name => $data->[0],
208             password => $data->[1],
209             uid => $data->[2],
210             gid => $data->[3],
211             comment => $data->[5],
212             home => $data->[7],
213             shell => $data->[8],
214             expire => exists $data->[9] ? $data->[9] : 0,
215             );
216             }
217              
218             sub create_group {
219 0     0 0   my ( $self, $group, $data ) = @_;
220              
221 0           my $cmd;
222              
223 0 0         if ( !defined $self->get_gid($group) ) {
224 0           Rex::Logger::debug("Creating new group $group");
225              
226 0           $cmd = "pw groupadd ";
227              
228 0 0         if ( exists $data->{gid} ) {
229 0           $cmd .= " -g " . $data->{gid};
230             }
231              
232 0           i_run $cmd . " -n " . $group, fail_ok => 1;
233 0 0         if ( $? != 0 ) {
234 0           die("Error creating/modifying group $group");
235             }
236             }
237             else {
238 0           Rex::Logger::debug("Group $group already exists. Updating...");
239              
240             # updating with pw groupmod doesn't work good in freebsd 10
241             # so we directly edit the /etc/group file
242             #$cmd = "pw groupmod ";
243              
244 0 0         if ( exists $data->{gid} ) {
245             eval {
246 0           my @content = split( /\n/, cat("/etc/group") );
247 0           my $gid = $data->{gid};
248 0           for (@content) {
249 0           s/^$group:([^:]+):(\d+):/$group:$1:$gid:/;
250             }
251 0           my $fh = file_write("/etc/group");
252 0           $fh->write( join( "\n", @content ) );
253 0           $fh->close;
254 0           1;
255 0 0         } or do {
256 0           die("Error creating/modifying group $group");
257             };
258             }
259             }
260              
261 0           return $self->get_gid($group);
262              
263             }
264              
265             sub get_gid {
266 0     0 0   my ( $self, $group ) = @_;
267              
268 0           my %data = $self->get_group($group);
269 0           return $data{gid};
270             }
271              
272             sub get_group {
273 0     0 0   my ( $self, $group ) = @_;
274              
275 0           Rex::Logger::debug("Getting information for $group");
276 0           my $rnd_file = get_tmp_file;
277 0           my $fh = Rex::Interface::File->create;
278 0           my $script = q|
279             unlink $0;
280             print to_json([ getgrnam($ARGV[0]) ]);
281             |;
282 0           $fh->open( ">", $rnd_file );
283 0           $fh->write($script);
284 0           $fh->write( func_to_json() );
285 0           $fh->close;
286              
287 0           my $data_str = i_run "perl $rnd_file $group", fail_ok => 1;
288 0 0         if ( $? != 0 ) {
289 0           die("Error getting group information");
290             }
291              
292 0           Rex::Interface::Fs->create()->unlink($rnd_file);
293              
294 0           my $data = decode_json($data_str);
295              
296             return (
297 0           name => $data->[0],
298             password => $data->[1],
299             gid => $data->[2],
300             members => $data->[3],
301             );
302              
303             }
304              
305             sub rm_group {
306 0     0 0   my ( $self, $group ) = @_;
307              
308 0           i_run "pw groupdel $group", fail_ok => 1;
309 0 0         if ( $? != 0 ) {
310 0           die("Error deleting group $group");
311             }
312             }
313              
314             1;