11 my $opt_action = undef;
20 sub passwd_delete($$);
24 my $result = GetOptions(
25 'help|h|?' => \$opt_help,
26 'path=s' => \$opt_path,
27 'action=s' => \$opt_action,
28 'type=s' => \$opt_type,
29 'name=s' => \$opt_name
36 print $msg."\n\n" if defined($msg);
40 --help|-h|-? Show this help.
42 --path <path> Path of the 'passwd' or 'group' file.
44 --type <type> Only 'passwd' and 'group' are supported yet,
45 maybe 'member' will be added in future.
47 --action <action> 'add' or 'delete'.
49 --name <name> The name of the object.
54 usage(1) if (not $result);
56 usage(0) if ($opt_help);
58 if (not defined($opt_path)) {
59 usage(1, "missing: --path <path>");
61 if ($opt_path eq "" or $opt_path eq "/") {
62 usage(1, "invalid: --path <path>: '$opt_path'");
64 my $opt_fullpath = abs_path($opt_path);
65 if (not defined($opt_fullpath)) {
66 usage(1, "invalid: --path <path>: '$opt_path'");
70 if (not defined($opt_action)) {
71 usage(1, "missing: --action [add|delete]");
73 if ($opt_action eq "add") {
74 $passwdfn = \&passwd_add;
75 $groupfn = \&group_add;
76 } elsif ($opt_action eq "delete") {
77 $passwdfn = \&passwd_delete;
78 $groupfn = \&group_delete;
80 usage(1, "invalid: --action [add|delete]: '$opt_action'");
83 if (not defined($opt_type)) {
84 usage(1, "missing: --type [passwd|group]");
86 if ($opt_type eq "passwd") {
87 $actionfn = $passwdfn;
88 } elsif ($opt_type eq "group") {
91 usage(1, "invalid: --type [passwd|group]: '$opt_type'")
94 if (not defined($opt_name)) {
95 usage(1, "missing: --name <name>");
97 if ($opt_name eq "") {
98 usage(1, "invalid: --name <name>");
101 exit $actionfn->($opt_fullpath, $opt_name);
103 sub passwd_add_entry($$);
111 open(PWD, "<$path") or die("Unable to open '$path' for read");
115 $passwd->{array} = ();
116 $passwd->{name} = {};
118 $passwd->{path} = $path;
120 foreach my $line (@lines) {
121 passwd_add_entry($passwd, $line);
127 sub group_add_entry($$);
135 open(GROUP, "<$path") or die("Unable to open '$path' for read");
139 $group->{array} = ();
142 $group->{path} = $path;
144 foreach my $line (@lines) {
145 group_add_entry($group, $line);
151 sub passwd_lookup_name($$)
153 my ($passwd, $name) = @_;
155 return undef unless defined($passwd->{name}{$name});
157 return $passwd->{name}{$name};
160 sub group_lookup_name($$)
162 my ($group, $name) = @_;
164 return undef unless defined($group->{name}{$name});
166 return $group->{name}{$name};
169 sub passwd_lookup_uid($$)
171 my ($passwd, $uid) = @_;
173 return undef unless defined($passwd->{uid}{$uid});
175 return $passwd->{uid}{$uid};
178 sub group_lookup_gid($$)
180 my ($group, $gid) = @_;
182 return undef unless defined($group->{gid}{$gid});
184 return $group->{gid}{$gid};
187 sub passwd_get_free_uid($)
192 while (passwd_lookup_uid($passwd, $uid)) {
199 sub group_get_free_gid($)
204 while (group_lookup_gid($group, $gid)) {
211 sub passwd_add_entry($$)
213 my ($passwd, $str) = @_;
216 my @e = split(':', $str);
218 push(@{$passwd->{array}}, \@e);
219 $passwd->{name}{$e[0]} = \@e;
220 $passwd->{uid}{$e[2]} = \@e;
223 sub group_add_entry($$)
225 my ($group, $str) = @_;
228 my @e = split(':', $str);
230 push(@{$group->{array}}, \@e);
231 $group->{name}{$e[0]} = \@e;
232 $group->{gid}{$e[2]} = \@e;
235 sub passwd_remove_entry($$)
237 my ($passwd, $eref) = @_;
239 for (my $i = 0; defined($passwd->{array}[$i]); $i++) {
240 if ($eref == $passwd->{array}[$i]) {
241 $passwd->{array}[$i] = undef;
245 delete $passwd->{name}{${$eref}[0]};
246 delete $passwd->{uid}{${$eref}[2]};
253 my $path = $passwd->{path};
254 my $tmppath = $path.$$;
256 foreach my $eref (@{$passwd->{array}}) {
257 next unless defined($eref);
259 my $line = join(':', @{$eref});
263 open(PWD, ">$tmppath") or die("Unable to open '$tmppath' for write");
264 print PWD join("\n", @lines)."\n";
266 rename($tmppath, $path) or die("Unable to rename $tmppath => $path");
273 my $path = $group->{path};
274 my $tmppath = $path.$$;
276 foreach my $eref (@{$group->{array}}) {
277 next unless defined($eref);
279 my $line = join(':', @{$eref});
280 if (scalar(@{$eref}) == 3) {
286 open(GROUP, ">$tmppath") or die("Unable to open '$tmppath' for write");
287 print GROUP join("\n", @lines)."\n";
289 rename($tmppath, $path) or die("Unable to rename $tmppath => $path");
294 my ($path, $name) = @_;
296 #print "passwd_add: '$name' in '$path'\n";
298 my $passwd = passwd_load($path);
300 my $e = passwd_lookup_name($passwd, $name);
301 die("account[$name] already exists in '$path'") if defined($e);
303 my $uid = passwd_get_free_uid($passwd);
304 my $gid = 65534;# nogroup gid
306 my $pwent = $name.":x:".$uid.":".$gid.":".$name." gecos:/nodir:/bin/false";
308 passwd_add_entry($passwd, $pwent);
310 passwd_save($passwd);
315 sub passwd_delete($$)
317 my ($path, $name) = @_;
319 #print "passwd_delete: '$name' in '$path'\n";
321 my $passwd = passwd_load($path);
323 my $e = passwd_lookup_name($passwd, $name);
324 die("account[$name] does not exists in '$path'") unless defined($e);
326 passwd_remove_entry($passwd, $e);
328 passwd_save($passwd);
335 my ($path, $name) = @_;
337 #print "group_add: '$name' in '$path'\n";
339 my $group = group_load($path);
341 my $e = group_lookup_name($group, $name);
342 die("group[$name] already exists in '$path'") if defined($e);
344 my $gid = group_get_free_gid($group);
346 my $gwent = $name.":x:".$gid.":".""; #no members yet
348 group_add_entry($group, $gwent);
352 #printf("%d\n", $gid);
359 my ($path, $name) = @_;
361 #print "group_delete: '$name' in '$path'\n";
363 die("group_delete: not implemented yet!");