nss_wrapper: split out passwd and group paths in nss_wrapper.pl.
[sfrench/samba-autobuild/.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_passwd_path = undef;
11 my $opt_group_path = undef;
12 my $opt_action = undef;
13 my $opt_type = undef;
14 my $opt_name = undef;
15
16 my $passwdfn = undef;
17 my $groupfn = undef;
18 my $actionfn = undef;
19
20 sub passwd_add($$);
21 sub passwd_delete($$);
22 sub group_add($$);
23 sub group_delete($$);
24
25 my $result = GetOptions(
26         'help|h|?'      => \$opt_help,
27         'passwd_path=s' => \$opt_passwd_path,
28         'group_path=s'  => \$opt_group_path,
29         'action=s'      => \$opt_action,
30         'type=s'        => \$opt_type,
31         'name=s'        => \$opt_name
32 );
33
34 sub usage($;$)
35 {
36         my ($ret, $msg) = @_;
37
38         print $msg."\n\n" if defined($msg);
39
40         print "usage:
41
42         --help|-h|-?            Show this help.
43
44         --passwd_path <path>    Path of the 'passwd' file.
45         --group_path <path>     Path of the 'group' file.
46
47         --type <type>           Only 'passwd' and 'group' are supported yet,
48                                 maybe 'member' will be added in future.
49
50         --action <action>       'add' or 'delete'.
51
52         --name <name>           The name of the object.
53 ";
54         exit($ret);
55 }
56
57 usage(1) if (not $result);
58
59 usage(0) if ($opt_help);
60
61 if (not defined($opt_action)) {
62         usage(1, "missing: --action [add|delete]");
63 }
64 if ($opt_action eq "add") {
65         $passwdfn = \&passwd_add;
66         $groupfn = \&group_add;
67 } elsif ($opt_action eq "delete") {
68         $passwdfn = \&passwd_delete;
69         $groupfn = \&group_delete;
70 } else {
71         usage(1, "invalid: --action [add|delete]: '$opt_action'");
72 }
73
74 if (not defined($opt_type)) {
75         usage(1, "missing: --type [passwd|group]");
76 }
77 my $opt_fullpath;
78 if ($opt_type eq "passwd") {
79         $actionfn = $passwdfn;
80         $opt_fullpath = check_path($opt_passwd_path, $opt_type);
81 } elsif ($opt_type eq "group") {
82         $actionfn = $groupfn;
83         $opt_fullpath = check_path($opt_group_path, $opt_type);
84 } else {
85         usage(1, "invalid: --type [passwd|group]: '$opt_type'")
86 }
87
88 if (not defined($opt_name)) {
89         usage(1, "missing: --name <name>");
90 }
91 if ($opt_name eq "") {
92         usage(1, "invalid: --name <name>");
93 }
94
95 exit $actionfn->($opt_fullpath, $opt_name);
96
97 sub check_path($$)
98 {
99         my ($path,$type) = @_;
100
101         if (not defined($path)) {
102                 usage(1, "missing: --$type\_path <path>");
103         }
104         if ($path eq "" or $path eq "/") {
105                 usage(1, "invalid: --$type\_path <path>: '$path'");
106         }
107         my $fullpath = abs_path($path);
108         if (not defined($fullpath)) {
109                 usage(1, "invalid: --$type\_path <path>: '$path'");
110         }
111         return $fullpath;
112 }
113
114 sub passwd_add_entry($$);
115
116 sub passwd_load($)
117 {
118         my ($path) = @_;
119         my @lines;
120         my $passwd = undef;
121
122         open(PWD, "<$path") or die("Unable to open '$path' for read");
123         @lines = <PWD>;
124         close(PWD);
125
126         $passwd->{array} = ();
127         $passwd->{name} = {};
128         $passwd->{uid} = {};
129         $passwd->{path} = $path;
130
131         foreach my $line (@lines) {
132                 passwd_add_entry($passwd, $line);
133         }
134
135         return $passwd;
136 }
137
138 sub group_add_entry($$);
139
140 sub group_load($)
141 {
142         my ($path) = @_;
143         my @lines;
144         my $group = undef;
145
146         open(GROUP, "<$path") or die("Unable to open '$path' for read");
147         @lines = <GROUP>;
148         close(GROUP);
149
150         $group->{array} = ();
151         $group->{name} = {};
152         $group->{gid} = {};
153         $group->{path} = $path;
154
155         foreach my $line (@lines) {
156                 group_add_entry($group, $line);
157         }
158
159         return $group;
160 }
161
162 sub passwd_lookup_name($$)
163 {
164         my ($passwd, $name) = @_;
165
166         return undef unless defined($passwd->{name}{$name});
167
168         return $passwd->{name}{$name};
169 }
170
171 sub group_lookup_name($$)
172 {
173         my ($group, $name) = @_;
174
175         return undef unless defined($group->{name}{$name});
176
177         return $group->{name}{$name};
178 }
179
180 sub passwd_lookup_uid($$)
181 {
182         my ($passwd, $uid) = @_;
183
184         return undef unless defined($passwd->{uid}{$uid});
185
186         return $passwd->{uid}{$uid};
187 }
188
189 sub group_lookup_gid($$)
190 {
191         my ($group, $gid) = @_;
192
193         return undef unless defined($group->{gid}{$gid});
194
195         return $group->{gid}{$gid};
196 }
197
198 sub passwd_get_free_uid($)
199 {
200         my ($passwd) = @_;
201         my $uid = 1000;
202
203         while (passwd_lookup_uid($passwd, $uid)) {
204                 $uid++;
205         }
206
207         return $uid;
208 }
209
210 sub group_get_free_gid($)
211 {
212         my ($group) = @_;
213         my $gid = 1000;
214
215         while (group_lookup_gid($group, $gid)) {
216                 $gid++;
217         }
218
219         return $gid;
220 }
221
222 sub passwd_add_entry($$)
223 {
224         my ($passwd, $str) = @_;
225
226         chomp $str;
227         my @e = split(':', $str);
228
229         push(@{$passwd->{array}}, \@e);
230         $passwd->{name}{$e[0]} = \@e;
231         $passwd->{uid}{$e[2]} = \@e;
232 }
233
234 sub group_add_entry($$)
235 {
236         my ($group, $str) = @_;
237
238         chomp $str;
239         my @e = split(':', $str);
240
241         push(@{$group->{array}}, \@e);
242         $group->{name}{$e[0]} = \@e;
243         $group->{gid}{$e[2]} = \@e;
244 }
245
246 sub passwd_remove_entry($$)
247 {
248         my ($passwd, $eref) = @_;
249
250         for (my $i = 0; defined($passwd->{array}[$i]); $i++) {
251                 if ($eref == $passwd->{array}[$i]) {
252                         $passwd->{array}[$i] = undef;
253                 }
254         }
255
256         delete $passwd->{name}{${$eref}[0]};
257         delete $passwd->{uid}{${$eref}[2]};
258 }
259
260 sub group_remove_entry($$)
261 {
262         my ($group, $eref) = @_;
263
264         for (my $i = 0; defined($group->{array}[$i]); $i++) {
265                 if ($eref == $group->{array}[$i]) {
266                         $group->{array}[$i] = undef;
267                 }
268         }
269
270         delete $group->{name}{${$eref}[0]};
271         delete $group->{gid}{${$eref}[2]};
272 }
273
274 sub passwd_save($)
275 {
276         my ($passwd) = @_;
277         my @lines = ();
278         my $path = $passwd->{path};
279         my $tmppath = $path.$$;
280
281         foreach my $eref (@{$passwd->{array}}) {
282                 next unless defined($eref);
283
284                 my $line = join(':', @{$eref});
285                 push(@lines, $line);
286         }
287
288         open(PWD, ">$tmppath") or die("Unable to open '$tmppath' for write");
289         print PWD join("\n", @lines)."\n";
290         close(PWD);
291         rename($tmppath, $path) or die("Unable to rename $tmppath => $path");
292 }
293
294 sub group_save($)
295 {
296         my ($group) = @_;
297         my @lines = ();
298         my $path = $group->{path};
299         my $tmppath = $path.$$;
300
301         foreach my $eref (@{$group->{array}}) {
302                 next unless defined($eref);
303
304                 my $line = join(':', @{$eref});
305                 if (scalar(@{$eref}) == 3) {
306                         $line .= ":";
307                 }
308                 push(@lines, $line);
309         }
310
311         open(GROUP, ">$tmppath") or die("Unable to open '$tmppath' for write");
312         print GROUP join("\n", @lines)."\n";
313         close(GROUP);
314         rename($tmppath, $path) or die("Unable to rename $tmppath => $path");
315 }
316
317 sub passwd_add($$)
318 {
319         my ($path, $name) = @_;
320
321         #print "passwd_add: '$name' in '$path'\n";
322
323         my $passwd = passwd_load($path);
324
325         my $e = passwd_lookup_name($passwd, $name);
326         die("account[$name] already exists in '$path'") if defined($e);
327
328         my $uid = passwd_get_free_uid($passwd);
329         my $gid = 65534;# nogroup gid
330
331         my $pwent = $name.":x:".$uid.":".$gid.":".$name." gecos:/nodir:/bin/false";
332
333         passwd_add_entry($passwd, $pwent);
334
335         passwd_save($passwd);
336
337         return 0;
338 }
339
340 sub passwd_delete($$)
341 {
342         my ($path, $name) = @_;
343
344         #print "passwd_delete: '$name' in '$path'\n";
345
346         my $passwd = passwd_load($path);
347
348         my $e = passwd_lookup_name($passwd, $name);
349         die("account[$name] does not exists in '$path'") unless defined($e);
350
351         passwd_remove_entry($passwd, $e);
352
353         passwd_save($passwd);
354
355         return 0;
356 }
357
358 sub group_add($$)
359 {
360         my ($path, $name) = @_;
361
362         #print "group_add: '$name' in '$path'\n";
363
364         my $group = group_load($path);
365
366         my $e = group_lookup_name($group, $name);
367         die("group[$name] already exists in '$path'") if defined($e);
368
369         my $gid = group_get_free_gid($group);
370
371         my $gwent = $name.":x:".$gid.":".""; #no members yet
372
373         group_add_entry($group, $gwent);
374
375         group_save($group);
376
377         #printf("%d\n", $gid);
378
379         return 0;
380 }
381
382 sub group_delete($$)
383 {
384         my ($path, $name) = @_;
385
386         #print "group_delete: '$name' in '$path'\n";
387
388         my $group = group_load($path);
389
390         my $e = group_lookup_name($group, $name);
391         die("group[$name] does not exists in '$path'") unless defined($e);
392
393         group_remove_entry($group, $e);
394
395         group_save($group);
396
397         return 0;
398 }