2 # Common functions for editing the samba config file
7 # Get the samba version
8 if (open(VERSION, "$module_config_directory/version")) {
9 chop($samba_version = <VERSION>);
14 # List all the shares from the samba config file
18 open(SAMBA, $config{smb_conf});
20 chop; s/;.*$//g; s/^\s*#.*$//g;
21 if (/^\s*\[([^\]]+)\]/) {
30 # get_share(share, [array])
31 # Fills the associative array %share with the parameters from the given share
34 local($found, $_, $first, $arr);
35 $arr = (@_==2 ? $_[1] : "share");
37 open(SAMBA, $config{smb_conf});
39 chop; s/^\s*;.*$//g; s/^\s*#.*$//g;
40 if (/^\s*\[([^\]]+)\]/) {
41 # Start of share section
44 elsif ($1 eq $_[0]) { $found = 1; $$arr{share_name} = $1; }
46 elsif ($found && /^\s*([^=]*\S)\s*=\s*(.*)$/) {
47 # Directives inside a section
48 if (lc($1) eq "read only") {
49 # bastard special case.. change to writable
50 $$arr{'writable'} = $2 =~ /yes|true|1/i ? "no" : "yes";
52 else { $$arr{lc($1)} = $2; }
54 elsif (!$first && /^\s*([^=]*\S)\s*=\s*(.*)$/ && $_[0] eq "global") {
55 # Directives outside a section! Assume to be part of [global]
56 $$arr{share_name} = "global";
67 # Add an entry to the config file
70 open(CONF, ">> $config{smb_conf}");
72 print CONF "[$_[0]]\n";
73 foreach $k (grep {!/share_name/} (keys %share)) {
74 print CONF "\t$k = $share{$k}\n";
80 # modify_share(oldname, newname)
81 # Change a share (and maybe it's name)
84 local($_, @conf, $replacing, $first);
85 open(CONF, $config{smb_conf});
88 open(CONF, "> $config{smb_conf}");
89 for($i=0; $i<@conf; $i++) {
90 chop($_ = $conf[$i]); s/;.*$//g; s/#.*$//g;
91 if (/^\s*\[([^\]]+)\]/) {
93 if ($replacing) { $replacing = 0; }
95 print CONF "[$_[1]]\n";
96 foreach $k (grep {!/share_name/} (keys %share)) {
97 print CONF "\t$k = $share{$k}\n";
103 elsif (!$first && /^\s*([^=]*\S)\s*=\s*(.*)$/ && $_[0] eq "global") {
104 # found start of directives outside any share - assume [global]
106 print CONF "[$_[1]]\n";
107 foreach $k (grep {!/share_name/} (keys %share)) {
108 print CONF "\t$k = $share{$k}\n";
113 if (!$replacing) { print CONF $conf[$i]; }
119 # delete_share(share)
120 # Delete some share from the config file
123 local($_, @conf, $deleting);
124 open(CONF, $config{smb_conf});
127 open(CONF, "> $config{smb_conf}");
128 for($i=0; $i<@conf; $i++) {
129 chop($_ = $conf[$i]); s/;.*$//g;
130 if (/^\s*\[([^\]]+)\]/) {
131 if ($deleting) { $deleting = 0; }
132 elsif ($1 eq $_[0]) {
137 if (!$deleting) { print CONF $conf[$i]; }
143 # list_connections([share])
144 # Uses the smbstatus program to return a list of connections a share. Each
145 # element of the returned list is of the form:
146 # share, user, group, pid, hostname, date/time
149 local($l, $started, @rv);
150 foreach $l (split(/\n/ , `$config{samba_status_program} -S`)) {
151 if ($l =~ /^----/) { $started = 1; }
152 if ($started && $l =~ /^(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(.*)\s+\(\S+\)\s+(.*)$/ && (!$_[0] || $1 eq $_[0] || $1 eq $2 && $_[0] eq "homes")) {
153 push(@rv, [ $1, $2, $3, $4, $5, $6 ]);
160 # Returns a list of locked files as an array, in the form:
161 # pid, mode, rw, oplock, file, date
164 local($l, $started, @rv);
165 foreach $l (split(/\n/ , `$config{samba_status_program} -L`)) {
166 if ($l =~ /^----/) { $started = 1; }
167 if ($started && $l =~ /^(\d+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(.*)\s+(\S+\s+\S+\s+\d+\s+\d+:\d+:\d+\s+\d+)/) {
168 push(@rv, [ $1, $2, $3, $4, $5, $6 ]);
176 # Checks if the value of this key (or it's synonyms) in %share is true
179 return &getval($_[0]) =~ /yes|true|1/i;
184 # Checks if the value of this key (or it's synonyms) in %share is false
187 return &getval($_[0]) =~ /no|false|0/i;
192 # Given the name of a key in %share, return the value. Also looks for synonyms.
193 # If the value is not found, a default is looked for.. this can come from
194 # a copied section, the [global] configuration section, or from the SAMBA
195 # defaults. This means that getval() always returns something..
200 foreach (split(/,/, $synon{$_[0]})) {
201 if (defined($share{$_})) { return $share{$_}; }
204 if (defined($share{$_[0]})) {
205 return $share{$_[0]};
207 elsif ($_[0] ne "copy" && ($copy = $share{"copy"})) {
208 # this share is a copy.. get the value from the source
211 return &getval($_[0]);
214 # return the default value...
215 return &default_value($_[0]);
221 # setval(name, value, [default])
222 # Sets some value in %share. Synonyms with the same meaning are removed.
223 # If the value is the same as the share or given default, dont store it
228 # default was given..
231 elsif ($_[0] ne "copy" && ($copy = $share{"copy"})) {
232 # get value from copy source..
235 $def = &getval($_[0]);
238 # get global/samba default
239 $def = &default_value($_[0]);
241 if ($_[1] eq $def || ($def !~ /\S/ && $_[1] !~ /\S/) ||
242 ($def =~ /^(true|yes|1)$/i && $_[1] =~ /^(true|yes|1)$/i) ||
243 ($def =~ /^(false|no|0)$/i && $_[1] =~ /^(false|no|0)$/i)) {
244 # The value is the default.. delete this entry
249 foreach (split(/,/, $synon{$_[0]})) {
253 $share{$_[0]} = $_[1];
259 # Delete a value from %share (and it's synonyms)
264 foreach (split(/,/, $synon{$_[0]})) {
268 else { delete($share{$_[0]}); }
272 # default_value(name)
273 # Returns the default value for a parameter
278 # First look in the [global] section.. (unless this _is_ the global section)
279 if ($share{share_name} ne "global") {
280 &get_share("global", "global");
282 foreach (split(/,/, $synon{$_[0]})) {
283 if (defined($global{$_})) { return $global{$_}; }
286 if (defined($global{$_[0]})) { return $global{$_[0]}; }
289 # Else look in the samba defaults
291 foreach (split(/,/, $synon{$_[0]})) {
292 if (exists($default_values{$_})) {
293 return $default_values{$_};
297 return $default_values{$_[0]};
301 # The list of synonyms used by samba for parameter names
302 @synon = ( "writable,write ok,writeable",
304 "printable,print ok",
305 "allow hosts,hosts allow",
306 "deny hosts,hosts deny",
307 "create mode,create mask",
308 "directory mode,directory mask",
312 "only guest,guest only",
313 "user,username,users",
314 "default,default service",
315 "auto services,preload",
316 "lock directory,lock dir",
317 "max xmit,max packet",
318 "root directory,root dir,root",
319 "case sensitive,case sig names"
321 foreach $s (@synon) {
322 foreach $ss (split(/,/ , $s)) {
328 # Default values for samba configuration parameters
329 %default_values = ( "allow hosts",undef,
330 "alternate permissions","no",
335 "directory mode","755",
336 "default case","lower",
337 "case sensitive","no",
339 "preserve case","no",
340 "short preserve case","no",
341 "delete readonly","no",
343 "dont descend",undef,
346 "force create mode","000",
347 "force directory mode","000",
348 "guest account","nobody", # depends
350 "hide dot files","yes",
351 "invalid users",undef,
353 "lppause command",undef, # depends
354 "lpq command",undef, # depends
355 "lpresume command",undef, # depends
356 "lprm command",undef, #depends
357 "magic output",undef, # odd..
358 "magic script",undef,
360 "mangled names","yes",
372 "print command",undef,
373 # "print command","lpr -r -P %p %s",
375 "printer driver",undef,
379 "root preexec",undef,
380 "root postexec",undef,
381 "set directory","no",
383 "strict locking","no",
387 "volume",undef, # depends
391 "write list",undef );
394 # Convert a samba unix user list into a more readable form
398 foreach $u (split(/[ \t,]+/ , $_[0])) {
399 if ($u =~ /^\@(.*)$/) {
400 push(@rv, "group <tt>".&html_escape($1)."</tt>");
403 push(@rv, "<tt>".&html_escape($u)."</tt>");
406 return join("," , @rv);
411 # Returns HTML for a true/false option
414 ($n = $_[0]) =~ s/ /_/g;
415 return sprintf "<input type=radio name=$n value=yes %s> $text{'yes'}\n".
416 "<input type=radio name=$n value=no %s> $text{'no'}\n",
417 &istrue($_[0]) ? "checked" : "",
418 &isfalse($_[0]) ? "checked" : "";
421 # username_input(name)
422 # Outputs HTML for an username field
425 ($n = $_[0]) =~ s/ /_/g;
427 print "<td><input name=$n size=8 value=\"$v\"> ",
428 &user_chooser_button($n, 0),"</td>\n";
431 # username_input(name, default)
434 ($n = $_[0]) =~ s/ /_/g;
436 print "<td><input name=$n size=8 value=\"$v\"> ",
437 &group_chooser_button($n, 0),"</td>\n";
442 @sock_opts = ("SO_KEEPALIVE", "SO_REUSEADDR", "SO_BROADCAST", "TCP_NODELAY",
443 "IPTOS_LOWDELAY", "IPTOS_THROUGHPUT", "SO_SNDBUF*", "SO_RCVBUF*",
444 "SO_SNDLOWAT*", "SO_RCVLOWAT*");
446 @protocols = ("CORE", "COREPLUS", "LANMAN1", "LANMAN2", "NT1");
450 # Returns an array of all the users from the samba password file
453 local(@rv, @b, $_, $lnum);
454 open(PASS, $config{'smb_passwd'});
459 local @b = split(/:/, $_);
461 local $u = { 'name' => $b[0], 'uid' => $b[1],
462 'pass1' => $b[2], 'pass2' => $b[3] };
463 if ($samba_version >= 2 && $b[4] =~ /^\[/) {
464 $b[4] =~ s/[\[\] ]//g;
465 $u->{'opts'} = [ split(//, $b[4]) ];
466 $u->{'change'} = $b[5];
469 $u->{'real'} = $b[4];
470 $u->{'home'} = $b[5];
471 $u->{'shell'} = $b[6];
473 $u->{'index'} = scalar(@rv);
474 $u->{'line'} = $lnum-1;
482 # Add a user to the samba password file
485 open(PASS, ">>$config{'smb_passwd'}");
486 print PASS &user_string($_[0]);
488 chown(0, 0, $config{'smb_passwd'});
489 chmod(0600, $config{'smb_passwd'});
493 # Change an existing samba user
496 &replace_file_line($config{'smb_passwd'}, $_[0]->{'line'}, &user_string($_[0]));
500 # Delete a samba user
503 &replace_file_line($config{'smb_passwd'}, $_[0]->{'line'});
508 local @u = ($_[0]->{'name'}, $_[0]->{'uid'},
509 $_[0]->{'pass1'}, $_[0]->{'pass2'});
510 if ($_[0]->{'opts'}) {
511 push(@u, sprintf "[%-11s]", join("", @{$_[0]->{'opts'}}));
512 push(@u, sprintf "LCT-%X", time());
515 push(@u, $_[0]->{'real'}, $_[0]->{'home'}, $_[0]->{'shell'});
517 return join(":", @u).":\n";
520 # set_password(user, password)
521 # Changes the password of a user in the encrypted password file
525 $out = `$config{'samba_password_program'} "$_[0]" "$_[1]" 2>&1 </dev/null`;
526 return $out =~ /changed/;
530 # Returns 0 if not, 1 if it is, or 2 if run from (x)inetd
533 local ($found_inet, @smbpids, @nmbpids);
534 if (&foreign_check("inetd")) {
535 &foreign_require("inetd", "inetd-lib.pl");
536 foreach $inet (&foreign_call("inetd", "list_inets")) {
537 $found_inet++ if (($inet->[8] =~ /smbd/ ||
538 $inet->[9] =~ /smbd/) && $inet->[1]);
541 elsif (&foreign_check("xinetd")) {
542 &foreign_require("xinetd", "xinetd-lib.pl");
543 foreach $xi (&foreign_call("xinetd", "get_xinetd_config")) {
544 local $q = $xi->{'quick'};
545 $found_inet++ if ($q->{'disable'}->[0] ne 'yes' &&
546 $q->{'server'}->[0] =~ /smbd/);
549 @smbpids = &find_byname("smbd");
550 @nmbpids = &find_byname("nmbd");
551 return !$found_inet && !@smbpids && !@nmbpids ? 0 :
552 !$found_inet ? 1 : 2;
555 # can($permissions_string, \%access, [$sname])
556 # check global and per-share permissions:
558 # $permissions_string = any exists permissions except 'c' (creation).
559 # \%access = ref on what get_module_acl() returns.
562 local ($acl, $stype, @perm);
563 local ($perm, $acc, $sname) = @_;
564 @perm = split(//, $perm);
565 $sname = $in{'old_name'} || $in{'share'} unless $sname;
568 &get_share($sname); # use local %share
569 $stype = &istrue('printable') ? 'ps' : 'fs';
572 # check global acl (r,w)
574 next if ($_ ne 'r') && ($_ ne 'w');
575 return 0 unless $acc->{$_ . '_' . $stype};
578 # check per-share acl
579 if ($acc->{'per_' . $stype . '_acls'}) {
580 $acl = $acc->{'ACL' . $stype . '_' . $sname};
582 # next if $_ eq 'c'; # skip creation perms for per-share acls
583 return 0 if index($acl, $_) == -1;
589 # save_samba_acl($permissions_string, \%access, $share_name)
592 local ($p, $a, $s)=@_;
593 defined(%share) || &get_share($s); # use global %share
594 local $t=&istrue('printable') ? 'ps' : 'fs';
595 $a->{'ACL'. $t .'_'. $s} = $p;
597 return &save_module_acl($a);
600 # drop_samba_acl(\%access, $share_name)
604 defined(%share) || &get_share($s); # use global %share
605 local $t=&istrue('printable') ? 'ps' : 'fs';
606 delete($a->{'ACL'. $t .'_' . $s});
608 return &save_module_acl($a);