Fix path apparently gone wrong by cherrypick.
[samba.git] / lib / nss_wrapper / nss_wrapper.pl
1 #!/usr/bin/perl
2 #
3
4 use strict;
5
6 use Getopt::Long;
7 use Cwd qw(abs_path);
8
9 my $opt_help = 0;
10 my $opt_path = undef;
11 my $opt_action = undef;
12 my $opt_type = undef;
13 my $opt_name = undef;
14
15 my $passwdfn = undef;
16 my $groupfn = undef;
17 my $actionfn = undef;
18
19 sub passwd_add($$);
20 sub passwd_delete($$);
21 sub group_add($$);
22 sub group_delete($$);
23
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
30 );
31
32 sub usage($;$)
33 {
34         my ($ret, $msg) = @_;
35
36         print $msg."\n\n" if defined($msg);
37
38         print "usage:
39
40         --help|-h|-?            Show this help.
41
42         --path <path>           Path of the 'passwd' or 'group' file.
43
44         --type <type>           Only 'passwd' is supported yet,
45                                 but 'group' and maybe 'member' will be added
46                                 in future.
47
48         --action <action>       'add' or 'delete'.
49
50         --name <name>           The name of the object.
51 ";
52         exit($ret);
53 }
54
55 usage(1) if (not $result);
56
57 usage(0) if ($opt_help);
58
59 if (not defined($opt_path)) {
60         usage(1, "missing: --path <path>");
61 }
62 if ($opt_path eq "" or $opt_path eq "/") {
63         usage(1, "invalid: --path <path>: '$opt_path'");
64 }
65 my $opt_fullpath = abs_path($opt_path);
66 if (not defined($opt_fullpath)) {
67         usage(1, "invalid: --path <path>: '$opt_path'");
68 }
69
70
71 if (not defined($opt_action)) {
72         usage(1, "missing: --action [add|delete]");
73 }
74 if ($opt_action eq "add") {
75         $passwdfn = \&passwd_add;
76         $groupfn = \&group_add;
77 } elsif ($opt_action eq "delete") {
78         $passwdfn = \&passwd_delete;
79         $groupfn = \&group_delete;
80 } else {
81         usage(1, "invalid: --action [add|delete]: '$opt_action'");
82 }
83
84 if (not defined($opt_type)) {
85         usage(1, "missing: --type [passwd|group]");
86 }
87 if ($opt_type eq "passwd") {
88         $actionfn = $passwdfn;
89 } elsif ($opt_type eq "group") {
90         $actionfn = $groupfn;
91 } else {
92         usage(1, "invalid: --type [passwd|group]: '$opt_type'")
93 }
94
95 if (not defined($opt_name)) {
96         usage(1, "missing: --name <name>");
97 }
98 if ($opt_name eq "") {
99         usage(1, "invalid: --name <name>");
100 }
101
102 exit $actionfn->($opt_fullpath, $opt_name);
103
104 sub passwd_add_entry($$);
105
106 sub passwd_load($)
107 {
108         my ($path) = @_;
109         my @lines;
110         my $passwd = undef;
111
112         open(PWD, "<$path") or die("Unable to open '$path' for read");
113         @lines = <PWD>;
114         close(PWD);
115
116         $passwd->{array} = ();
117         $passwd->{name} = {};
118         $passwd->{uid} = {};
119         $passwd->{path} = $path;
120
121         foreach my $line (@lines) {
122                 passwd_add_entry($passwd, $line);
123         }
124
125         return $passwd;
126 }
127
128 sub passwd_lookup_name($$)
129 {
130         my ($passwd, $name) = @_;
131
132         return undef unless defined($passwd->{name}{$name});
133
134         return $passwd->{name}{$name};
135 }
136
137 sub passwd_lookup_uid($$)
138 {
139         my ($passwd, $uid) = @_;
140
141         return undef unless defined($passwd->{uid}{$uid});
142
143         return $passwd->{uid}{$uid};
144 }
145
146 sub passwd_get_free_uid($)
147 {
148         my ($passwd) = @_;
149         my $uid = 1000;
150
151         while (passwd_lookup_uid($passwd, $uid)) {
152                 $uid++;
153         }
154
155         return $uid;
156 }
157
158 sub passwd_add_entry($$)
159 {
160         my ($passwd, $str) = @_;
161
162         chomp $str;
163         my @e = split(':', $str);
164
165         push(@{$passwd->{array}}, \@e);
166         $passwd->{name}{$e[0]} = \@e;
167         $passwd->{uid}{$e[2]} = \@e;
168 }
169
170 sub passwd_remove_entry($$)
171 {
172         my ($passwd, $eref) = @_;
173
174         for(my $i; defined($passwd->{array}[$i]); $i++) {
175                 if ($eref == $passwd->{array}[$i]) {
176                         $passwd->{array}[$i] = undef;
177                 }
178         }
179
180         delete $passwd->{name}{${$eref}[0]};
181         delete $passwd->{uid}{${$eref}[2]};
182 }
183
184 sub passwd_save($)
185 {
186         my ($passwd) = @_;
187         my @lines = ();
188         my $path = $passwd->{path};
189         my $tmppath = $path.$$;
190
191         foreach my $eref (@{$passwd->{array}}) {
192                 next unless defined($eref);
193
194                 my $line = join(':', @{$eref});
195                 push(@lines, $line);
196         }
197
198         open(PWD, ">$tmppath") or die("Unable to open '$tmppath' for write");
199         print PWD join("\n", @lines)."\n";
200         close(PWD);
201         rename($tmppath, $path) or die("Unable to rename $tmppath => $path");
202 }
203
204 sub passwd_add($$)
205 {
206         my ($path, $name) = @_;
207
208         #print "passwd_add: '$name' in '$path'\n";
209
210         my $passwd = passwd_load($path);
211
212         my $e = passwd_lookup_name($passwd, $name);
213         die("account[$name] already exists in '$path'") if defined($e);
214
215         my $uid = passwd_get_free_uid($passwd);
216         my $gid = 65534;# nogroup gid
217
218         my $pwent = $name.":x:".$uid.":".$gid.":".$name." gecos:/nodir:/bin/false";
219
220         passwd_add_entry($passwd, $pwent);
221
222         passwd_save($passwd);
223
224         return 0;
225 }
226
227 sub passwd_delete($$)
228 {
229         my ($path, $name) = @_;
230
231         #print "passwd_delete: '$name' in '$path'\n";
232
233         my $passwd = passwd_load($path);
234
235         my $e = passwd_lookup_name($passwd, $name);
236         die("account[$name] does not exists in '$path'") unless defined($e);
237
238         passwd_remove_entry($passwd, $e);
239
240         passwd_save($passwd);
241
242         return 0;
243 }
244
245 sub group_add($$)
246 {
247         my ($path, $name) = @_;
248
249         #print "group_add: '$name' in '$path'\n";
250
251         die("group_add: not implemented yet!");
252
253         return 0;
254 }
255
256 sub group_delete($$)
257 {
258         my ($path, $name) = @_;
259
260         #print "group_delete: '$name' in '$path'\n";
261
262         die("group_delete: not implemented yet!");
263
264         return 0;
265 }