summaryrefslogtreecommitdiff
path: root/lib/nss_wrapper/nss_wrapper.pl
diff options
context:
space:
mode:
Diffstat (limited to 'lib/nss_wrapper/nss_wrapper.pl')
-rw-r--r--lib/nss_wrapper/nss_wrapper.pl265
1 files changed, 265 insertions, 0 deletions
diff --git a/lib/nss_wrapper/nss_wrapper.pl b/lib/nss_wrapper/nss_wrapper.pl
new file mode 100644
index 0000000000..b1c9be5365
--- /dev/null
+++ b/lib/nss_wrapper/nss_wrapper.pl
@@ -0,0 +1,265 @@
+#!/usr/bin/perl
+#
+
+use strict;
+
+use Getopt::Long;
+use Cwd qw(abs_path);
+
+my $opt_help = 0;
+my $opt_path = undef;
+my $opt_action = undef;
+my $opt_type = undef;
+my $opt_name = undef;
+
+my $passwdfn = undef;
+my $groupfn = undef;
+my $actionfn = undef;
+
+sub passwd_add($$);
+sub passwd_delete($$);
+sub group_add($$);
+sub group_delete($$);
+
+my $result = GetOptions(
+ 'help|h|?' => \$opt_help,
+ 'path=s' => \$opt_path,
+ 'action=s' => \$opt_action,
+ 'type=s' => \$opt_type,
+ 'name=s' => \$opt_name
+);
+
+sub usage($;$)
+{
+ my ($ret, $msg) = @_;
+
+ print $msg."\n\n" if defined($msg);
+
+ print "usage:
+
+ --help|-h|-? Show this help.
+
+ --path <path> Path of the 'passwd' or 'group' file.
+
+ --type <type> Only 'passwd' is supported yet,
+ but 'group' and maybe 'member' will be added
+ in future.
+
+ --action <action> 'add' or 'delete'.
+
+ --name <name> The name of the object.
+";
+ exit($ret);
+}
+
+usage(1) if (not $result);
+
+usage(0) if ($opt_help);
+
+if (not defined($opt_path)) {
+ usage(1, "missing: --path <path>");
+}
+if ($opt_path eq "" or $opt_path eq "/") {
+ usage(1, "invalid: --path <path>: '$opt_path'");
+}
+my $opt_fullpath = abs_path($opt_path);
+if (not defined($opt_fullpath)) {
+ usage(1, "invalid: --path <path>: '$opt_path'");
+}
+
+
+if (not defined($opt_action)) {
+ usage(1, "missing: --action [add|delete]");
+}
+if ($opt_action eq "add") {
+ $passwdfn = \&passwd_add;
+ $groupfn = \&group_add;
+} elsif ($opt_action eq "delete") {
+ $passwdfn = \&passwd_delete;
+ $groupfn = \&group_delete;
+} else {
+ usage(1, "invalid: --action [add|delete]: '$opt_action'");
+}
+
+if (not defined($opt_type)) {
+ usage(1, "missing: --type [passwd|group]");
+}
+if ($opt_type eq "passwd") {
+ $actionfn = $passwdfn;
+} elsif ($opt_type eq "group") {
+ $actionfn = $groupfn;
+} 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, $opt_name);
+
+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 passwd_lookup_name($$)
+{
+ my ($passwd, $name) = @_;
+
+ return undef unless defined($passwd->{name}{$name});
+
+ return $passwd->{name}{$name};
+}
+
+sub passwd_lookup_uid($$)
+{
+ my ($passwd, $uid) = @_;
+
+ return undef unless defined($passwd->{uid}{$uid});
+
+ return $passwd->{uid}{$uid};
+}
+
+sub passwd_get_free_uid($)
+{
+ my ($passwd) = @_;
+ my $uid = 1000;
+
+ while (passwd_lookup_uid($passwd, $uid)) {
+ $uid++;
+ }
+
+ return $uid;
+}
+
+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 passwd_remove_entry($$)
+{
+ my ($passwd, $eref) = @_;
+
+ for(my $i; 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 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 passwd_add($$)
+{
+ my ($path, $name) = @_;
+
+ #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 $gid = 65534;# nogroup gid
+
+ 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, $name) = @_;
+
+ #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 ($path, $name) = @_;
+
+ #print "group_add: '$name' in '$path'\n";
+
+ die("group_add: not implemented yet!");
+
+ return 0;
+}
+
+sub group_delete($$)
+{
+ my ($path, $name) = @_;
+
+ #print "group_delete: '$name' in '$path'\n";
+
+ die("group_delete: not implemented yet!");
+
+ return 0;
+}