diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-05 17:47:29 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-05 17:47:29 +0000 |
commit | 4f5791ebd03eaec1c7da0865a383175b05102712 (patch) | |
tree | 8ce7b00f7a76baa386372422adebbe64510812d4 /third_party/nss_wrapper/nss_wrapper.pl | |
parent | Initial commit. (diff) | |
download | samba-4f5791ebd03eaec1c7da0865a383175b05102712.tar.xz samba-4f5791ebd03eaec1c7da0865a383175b05102712.zip |
Adding upstream version 2:4.17.12+dfsg.upstream/2%4.17.12+dfsgupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/nss_wrapper/nss_wrapper.pl')
-rwxr-xr-x | third_party/nss_wrapper/nss_wrapper.pl | 521 |
1 files changed, 521 insertions, 0 deletions
diff --git a/third_party/nss_wrapper/nss_wrapper.pl b/third_party/nss_wrapper/nss_wrapper.pl new file mode 100755 index 0000000..48fa2c5 --- /dev/null +++ b/third_party/nss_wrapper/nss_wrapper.pl @@ -0,0 +1,521 @@ +#!/usr/bin/perl +# + +use strict; + +use Getopt::Long; +use Cwd qw(abs_path); + +my $opt_help = 0; +my $opt_passwd_path = undef; +my $opt_group_path = undef; +my $opt_action = undef; +my $opt_type = undef; +my $opt_name = undef; +my $opt_member = undef; +my $opt_gid = 65534;# nogroup gid + +my $passwdfn = undef; +my $groupfn = undef; +my $memberfn = undef; +my $actionfn = undef; + +sub passwd_add($$$$$); +sub passwd_delete($$$$$); +sub group_add($$$$$); +sub group_delete($$$$$); +sub member_add($$$$$); +sub member_delete($$$$$); + +sub check_path($$); + +my $result = GetOptions( + 'help|h|?' => \$opt_help, + 'passwd_path=s' => \$opt_passwd_path, + 'group_path=s' => \$opt_group_path, + 'action=s' => \$opt_action, + 'type=s' => \$opt_type, + 'name=s' => \$opt_name, + 'member=s' => \$opt_member, + 'gid=i' => \$opt_gid +); + +sub usage($;$) +{ + my ($ret, $msg) = @_; + + print $msg."\n\n" if defined($msg); + + print "usage: + + --help|-h|-? Show this help. + + --passwd_path <path> Path of the 'passwd' file. + --group_path <path> Path of the 'group' file. + + --type <type> 'passwd', 'group' and 'member' are supported. + + --action <action> 'add' or 'delete'. + + --name <name> The name of the object. + + --member <member> The name of the member. + + --gid <gid> Primary Group ID for new users. +"; + exit($ret); +} + +usage(1) if (not $result); + +usage(0) if ($opt_help); + +if (not defined($opt_action)) { + usage(1, "missing: --action [add|delete]"); +} +if ($opt_action eq "add") { + $passwdfn = \&passwd_add; + $groupfn = \&group_add; + $memberfn = \&member_add; +} elsif ($opt_action eq "delete") { + $passwdfn = \&passwd_delete; + $groupfn = \&group_delete; + $memberfn = \&member_delete; +} else { + usage(1, "invalid: --action [add|delete]: '$opt_action'"); +} + +if (not defined($opt_type)) { + usage(1, "missing: --type [passwd|group|member]"); +} +if ($opt_type eq "member" and not defined($opt_member)) { + usage(1, "missing: --member <member>"); +} +my $opt_fullpath_passwd; +my $opt_fullpath_group; +if ($opt_type eq "passwd") { + $actionfn = $passwdfn; + $opt_fullpath_passwd = check_path($opt_passwd_path, $opt_type); +} elsif ($opt_type eq "group") { + $actionfn = $groupfn; + $opt_fullpath_group = check_path($opt_group_path, $opt_type); +} elsif ($opt_type eq "member") { + $actionfn = $memberfn; + $opt_fullpath_passwd = check_path($opt_passwd_path, "passwd"); + $opt_fullpath_group = check_path($opt_group_path, "group"); +} else { + usage(1, "invalid: --type [passwd|group]: '$opt_type'") +} + +if (not defined($opt_name)) { + usage(1, "missing: --name <name>"); +} +if ($opt_name eq "") { + usage(1, "invalid: --name <name>"); +} + +exit $actionfn->($opt_fullpath_passwd, $opt_member, $opt_fullpath_group, $opt_name, $opt_gid); + +sub check_path($$) +{ + my ($path,$type) = @_; + + if (not defined($path)) { + usage(1, "missing: --$type\_path <path>"); + } + if ($path eq "" or $path eq "/") { + usage(1, "invalid: --$type\_path <path>: '$path'"); + } + my $fullpath = abs_path($path); + if (not defined($fullpath)) { + usage(1, "invalid: --$type\_path <path>: '$path'"); + } + return $fullpath; +} + +sub passwd_add_entry($$); + +sub passwd_load($) +{ + my ($path) = @_; + my @lines; + my $passwd = undef; + + open(PWD, "<$path") or die("Unable to open '$path' for read"); + @lines = <PWD>; + close(PWD); + + $passwd->{array} = (); + $passwd->{name} = {}; + $passwd->{uid} = {}; + $passwd->{path} = $path; + + foreach my $line (@lines) { + passwd_add_entry($passwd, $line); + } + + return $passwd; +} + +sub group_add_entry($$); + +sub group_load($) +{ + my ($path) = @_; + my @lines; + my $group = undef; + + open(GROUP, "<$path") or die("Unable to open '$path' for read"); + @lines = <GROUP>; + close(GROUP); + + $group->{array} = (); + $group->{name} = {}; + $group->{gid} = {}; + $group->{path} = $path; + + foreach my $line (@lines) { + group_add_entry($group, $line); + } + + return $group; +} + +sub passwd_lookup_name($$) +{ + my ($passwd, $name) = @_; + + return undef unless defined($passwd->{name}{$name}); + + return $passwd->{name}{$name}; +} + +sub group_lookup_name($$) +{ + my ($group, $name) = @_; + + return undef unless defined($group->{name}{$name}); + + return $group->{name}{$name}; +} + +sub passwd_lookup_uid($$) +{ + my ($passwd, $uid) = @_; + + return undef unless defined($passwd->{uid}{$uid}); + + return $passwd->{uid}{$uid}; +} + +sub group_lookup_gid($$) +{ + my ($group, $gid) = @_; + + return undef unless defined($group->{gid}{$gid}); + + return $group->{gid}{$gid}; +} + +sub passwd_get_free_uid($) +{ + my ($passwd) = @_; + my $uid = 1000; + + while (passwd_lookup_uid($passwd, $uid)) { + $uid++; + } + + return $uid; +} + +sub group_get_free_gid($) +{ + my ($group) = @_; + my $gid = 1000; + + while (group_lookup_gid($group, $gid)) { + $gid++; + } + + return $gid; +} + +sub passwd_add_entry($$) +{ + my ($passwd, $str) = @_; + + chomp $str; + my @e = split(':', $str); + + push(@{$passwd->{array}}, \@e); + $passwd->{name}{$e[0]} = \@e; + $passwd->{uid}{$e[2]} = \@e; +} + +sub group_add_entry($$) +{ + my ($group, $str) = @_; + + chomp $str; + my @e = split(':', $str); + + push(@{$group->{array}}, \@e); + $group->{name}{$e[0]} = \@e; + $group->{gid}{$e[2]} = \@e; +} + +sub passwd_remove_entry($$) +{ + my ($passwd, $eref) = @_; + + for (my $i = 0; defined($passwd->{array}[$i]); $i++) { + if ($eref == $passwd->{array}[$i]) { + $passwd->{array}[$i] = undef; + } + } + + delete $passwd->{name}{${$eref}[0]}; + delete $passwd->{uid}{${$eref}[2]}; +} + +sub group_remove_entry($$) +{ + my ($group, $eref) = @_; + + for (my $i = 0; defined($group->{array}[$i]); $i++) { + if ($eref == $group->{array}[$i]) { + $group->{array}[$i] = undef; + } + } + + delete $group->{name}{${$eref}[0]}; + delete $group->{gid}{${$eref}[2]}; +} + +sub group_add_member($$$) +{ + my ($group, $eref, $username) = @_; + + my @members; + my $str = @$eref[3] || undef; + if ($str) { + @members = split(",", $str); + } + + foreach my $member (@members) { + if ($member and $member eq $username) { + die("account[$username] is already member of '@$eref[0]'"); + } + } + + push(@members, $username); + + my $gwent = @$eref[0].":x:".@$eref[2].":".join(",", @members); + + group_remove_entry($group, $eref); + + group_add_entry($group, $gwent); +} + +sub group_delete_member($$$) +{ + my ($group, $eref, $username) = @_; + + my @members = undef; + my $str = @$eref[3] || undef; + if ($str) { + @members = split(",", $str); + } + my @new_members; + my $removed = 0; + + foreach my $member (@members) { + if ($member and $member ne $username) { + push(@new_members, $member); + } else { + $removed = 1; + } + } + + if ($removed != 1) { + die("account[$username] is not member of '@$eref[0]'"); + } + + my $gwent = @$eref[0].":x:".@$eref[2].":".join(",", @new_members); + + group_remove_entry($group, $eref); + + group_add_entry($group, $gwent); +} + +sub passwd_save($) +{ + my ($passwd) = @_; + my @lines = (); + my $path = $passwd->{path}; + my $tmppath = $path.$$; + + foreach my $eref (@{$passwd->{array}}) { + next unless defined($eref); + + my $line = join(':', @{$eref}); + push(@lines, $line); + } + + open(PWD, ">$tmppath") or die("Unable to open '$tmppath' for write"); + print PWD join("\n", @lines)."\n"; + close(PWD); + rename($tmppath, $path) or die("Unable to rename $tmppath => $path"); +} + +sub group_save($) +{ + my ($group) = @_; + my @lines = (); + my $path = $group->{path}; + my $tmppath = $path.$$; + + foreach my $eref (@{$group->{array}}) { + next unless defined($eref); + + my $line = join(':', @{$eref}); + if (scalar(@{$eref}) == 3) { + $line .= ":"; + } + push(@lines, $line); + } + + open(GROUP, ">$tmppath") or die("Unable to open '$tmppath' for write"); + print GROUP join("\n", @lines)."\n"; + close(GROUP); + rename($tmppath, $path) or die("Unable to rename $tmppath => $path"); +} + +sub passwd_add($$$$$) +{ + my ($path, $dummy, $dummy2, $name, $gid) = @_; + + #print "passwd_add: '$name' in '$path'\n"; + + my $passwd = passwd_load($path); + + my $e = passwd_lookup_name($passwd, $name); + die("account[$name] already exists in '$path'") if defined($e); + + my $uid = passwd_get_free_uid($passwd); + + my $pwent = $name.":x:".$uid.":".$gid.":".$name." gecos:/nodir:/bin/false"; + + passwd_add_entry($passwd, $pwent); + + passwd_save($passwd); + + return 0; +} + +sub passwd_delete($$$$$) +{ + my ($path, $dummy, $dummy2, $name, $dummy3) = @_; + + #print "passwd_delete: '$name' in '$path'\n"; + + my $passwd = passwd_load($path); + + my $e = passwd_lookup_name($passwd, $name); + die("account[$name] does not exists in '$path'") unless defined($e); + + passwd_remove_entry($passwd, $e); + + passwd_save($passwd); + + return 0; +} + +sub group_add($$$$$) +{ + my ($dummy, $dummy2, $path, $name, $dummy3) = @_; + + #print "group_add: '$name' in '$path'\n"; + + my $group = group_load($path); + + my $e = group_lookup_name($group, $name); + die("group[$name] already exists in '$path'") if defined($e); + + my $gid = group_get_free_gid($group); + + my $gwent = $name.":x:".$gid.":".""; + + group_add_entry($group, $gwent); + + group_save($group); + + #printf("%d\n", $gid); + + return 0; +} + +sub group_delete($$$$$) +{ + my ($dummy, $dummy2, $path, $name, $dummy3) = @_; + + #print "group_delete: '$name' in '$path'\n"; + + my $group = group_load($path); + + my $e = group_lookup_name($group, $name); + die("group[$name] does not exists in '$path'") unless defined($e); + + group_remove_entry($group, $e); + + group_save($group); + + return 0; +} + +sub member_add($$$$$) +{ + my ($passwd_path, $username, $group_path, $groupname, $dummy) = @_; + + #print "member_add: adding '$username' in '$passwd_path' to '$groupname' in '$group_path'\n"; + + my $group = group_load($group_path); + + my $g = group_lookup_name($group, $groupname); + die("group[$groupname] does not exists in '$group_path'") unless defined($g); + + my $passwd = passwd_load($passwd_path); + + my $u = passwd_lookup_name($passwd, $username); + die("account[$username] does not exists in '$passwd_path'") unless defined($u); + + group_add_member($group, $g, $username); + + group_save($group); + + return 0; +} + +sub member_delete($$$$$) +{ + my ($passwd_path, $username, $group_path, $groupname, $dummy) = @_; + + #print "member_delete: removing '$username' in '$passwd_path' from '$groupname' in '$group_path'\n"; + + my $group = group_load($group_path); + + my $g = group_lookup_name($group, $groupname); + die("group[$groupname] does not exists in '$group_path'") unless defined($g); + + my $passwd = passwd_load($passwd_path); + + my $u = passwd_lookup_name($passwd, $username); + die("account[$username] does not exists in '$passwd_path'") unless defined($u); + + group_delete_member($group, $g, $username); + + group_save($group); + + return 0; +} |