2 # Common functions for editing the samba config file
3 # XXX privileges for groups with 'net' command
5 BEGIN { push(@INC, ".."); };
8 %access = &get_module_acl();
9 $has_iconv = &has_command("iconv");
11 # Get the samba version
12 if (open(VERSION, "$module_config_directory/version")) {
13 chop($samba_version = <VERSION>);
17 $has_pdbedit = ( $samba_version >= 3 && &has_command($config{'pdbedit'}) );
18 $has_smbgroupedit = 1 if (&has_command($config{'smbgroupedit'}));
19 $has_net = 1 if ($config{'net'} =~ /^(\S+)/ && &has_command("$1"));
20 $has_groups = ( $samba_version >= 3 && ($has_smbgroupedit || $has_net) );
23 # List all the shares from the samba config file
27 &open_readfile(SAMBA, $config{smb_conf});
29 chop; s/;.*$//g; s/^\s*#.*$//g;
30 if (/^\s*\[([^\]]+)\]/) {
36 # Check for an include directive in the [global] share
38 &get_share("global", \%global);
39 local $inc = &getval("include", \%global);
40 if ($inc && $inc !~ /\%/) {
48 # get_share(share, [array])
49 # Fills the associative array %share with the parameters from the given share
52 local($found, $_, $first, $arr);
53 $arr = (@_==2 ? $_[1] : "share");
55 &open_readfile(SAMBA, $config{smb_conf});
57 chop; s/^\s*;.*$//g; s/^\s*#.*$//g;
58 if (/^\s*\[([^\]]+)\]/) {
59 # Start of share section
66 $$arr{share_name} = $1;
69 elsif ($found && /^\s*([^=]*\S)\s*=\s*(.*)$/) {
70 # Directives inside a section
71 if (lc($1) eq "read only") {
72 # bastard special case.. change to writable
73 $$arr{'writable'} = $2 =~ /yes|true|1/i ? "no" : "yes";
76 $$arr{lc($1)} = &from_utf8("$2");
79 elsif (!$first && /^\s*([^=]*\S)\s*=\s*(.*)$/ && $_[0] eq "global") {
80 # Directives outside a section! Assume to be part of [global]
81 $$arr{share_name} = "global";
82 $$arr{lc($1)} = &from_utf8("$2");
92 # Add an entry to the config file
95 &open_tempfile(CONF, ">> $config{smb_conf}");
96 &print_tempfile(CONF, "\n");
97 &print_tempfile(CONF, "[$_[0]]\n");
98 foreach $k (grep {!/share_name/} (keys %share)) {
99 &print_tempfile(CONF, "\t$k = $share{$k}\n");
101 &close_tempfile(CONF);
105 # modify_share(oldname, newname)
106 # Change a share (and maybe it's name)
109 local($_, @conf, $replacing, $first);
110 &open_readfile(CONF, $config{smb_conf});
113 &open_tempfile(CONF, ">$config{smb_conf}");
114 for($i=0; $i<@conf; $i++) {
115 chop($_ = $conf[$i]); s/;.*$//g; s/#.*$//g;
116 if (/^\s*\[([^\]]+)\]/) {
118 if ($replacing) { $replacing = 0; }
119 elsif ($1 eq $_[0]) {
120 &print_tempfile(CONF, "[$_[1]]\n");
121 foreach $k (grep {!/share_name/} (keys %share)) {
122 &print_tempfile(CONF, "\t$k = ",
123 &to_utf8($share{$k}),"\n");
125 #&print_tempfile(CONF, "\n");
129 elsif (!$first && /^\s*([^=]*\S)\s*=\s*(.*)$/ && $_[0] eq "global") {
130 # found start of directives outside any share - assume [global]
132 &print_tempfile(CONF, "[$_[1]]\n");
133 foreach $k (grep {!/share_name/} (keys %share)) {
134 &print_tempfile(CONF, "\t$k = ",
135 &to_utf8($share{$k}),"\n");
137 &print_tempfile(CONF, "\n");
140 if (!$replacing || $conf[$i] =~ /^\s*[#;]/ || $conf[$i] =~ /^\s*$/) {
141 &print_tempfile(CONF, $conf[$i]);
144 &close_tempfile(CONF);
148 # delete_share(share)
149 # Delete some share from the config file
152 local($_, @conf, $deleting);
153 &open_readfile(CONF, $config{smb_conf});
156 &open_tempfile(CONF, "> $config{smb_conf}");
157 for($i=0; $i<@conf; $i++) {
158 chop($_ = $conf[$i]); s/;.*$//g;
159 if (/^\s*\[([^\]]+)\]/) {
160 if ($deleting) { $deleting = 0; }
161 elsif ($1 eq $_[0]) {
162 &print_tempfile(CONF, "\n");
167 &print_tempfile(CONF, $conf[$i]);
170 &close_tempfile(CONF);
175 # Converts a string to UTF-8 if needed
179 if ($v =~ /^[\000-\177]*$/ || !$has_iconv) {
183 my $temp = &transname();
184 &open_tempfile(TEMP, ">$temp", 0, 1);
185 &print_tempfile(TEMP, $v);
186 &close_tempfile(TEMP);
187 my $out = &backquote_command("iconv -f iso-8859-1 -t UTF-8 <$temp");
189 return $? || $out eq '' ? $v : $out;
194 # Converts a string from UTF-8 if needed
198 if ($v =~ /^[\000-\177]*$/ || !$has_iconv) {
202 my $temp = &transname();
203 &open_tempfile(TEMP, ">$temp", 0, 1);
204 &print_tempfile(TEMP, $v);
205 &close_tempfile(TEMP);
206 my $out = &backquote_command("iconv -f UTF-8 -t iso-8859-1 <$temp");
208 return $? || $out eq '' ? $v : $out;
213 # list_connections([share])
214 # Uses the smbstatus program to return a list of connections a share. Each
215 # element of the returned list is of the form:
216 # share, user, group, pid, hostname, date/time
219 local($l, $started, @rv);
220 if ($samba_version >= 3) {
221 # New samba status format
224 local $ex = &execute_command("$config{samba_status_program} -s $config{smb_conf}", undef, \$out, undef);
226 # -s option not supported
227 &execute_command("$config{samba_status_program}",
228 undef, \$out, undef);
230 foreach $l (split(/\n/ , $out)) {
234 elsif ($started == 1 &&
235 $l =~ /^\s*(\d+)\s+(\S+)\s+(\S+)\s+(\S+)\s+\((\S+)\)/) {
236 # A line with a PID, username, group and hostname
237 $pidmap{$1} = [ $1, $2, $3, $4, $5 ];
239 elsif ($started == 2 &&
240 $l =~ /^\s*(\S+)\s+(\d+)\s+(\S+)\s+(.*)$/) {
241 # A line with a service, PID and machine. This must be
242 # combined data from the first type of line to create
243 # the needed information
244 local $p = $pidmap{$2};
245 if (!$_[0] || $1 eq $_[0] ||
246 $1 eq $p->[1] && $_[0] eq "homes") {
247 push(@rv, [ $1, $p->[1], $p->[2], $2, $3, $4 ]);
253 # Old samba status format
255 &execute_command("$config{samba_status_program} -S",
256 undef, \$out, undef);
257 foreach $l (split(/\n/, $out)) {
258 if ($l =~ /^----/) { $started++; }
259 if ($started && $l =~ /^(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(.*)\s+\(\S+\)\s+(.*)$/ && (!$_[0] || $1 eq $_[0] || $1 eq $2 && $_[0] eq "homes")) {
260 push(@rv, [ $1, $2, $3, $4, $5, $6 ]);
268 # Returns a list of locked files as an array, in the form:
269 # pid, mode, rw, oplock, file, date
272 local($l, $started, @rv);
275 &execute_command("$config{samba_status_program} -L", undef, \$out, undef);
276 &reset_environment();
277 foreach $l (split(/\n/, $out)) {
278 if ($l =~ /^----/) { $started = 1; }
279 if ($started && $l =~ /^(\d+)\s+(\d+)\s+(\S+)\s+(0x\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S.*)\s\s((Mon|Tue|Wed|Thu|Fri|Sat|Sun)\s.*)/i) {
281 push(@rv, [ $1, $3, $5, $6, $7.'/'.$8, $9 ]);
283 elsif ($started && $l =~ /^(\d+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(.*)\s+(\S+\s+\S+\s+\d+\s+\d+:\d+:\d+\s+\d+)/) {
285 push(@rv, [ $1, $2, $3, $4, $5, $6 ]);
293 # Checks if the value of this key (or it's synonyms) in %share is true
296 return &getval($_[0]) =~ /yes|true|1/i;
301 # Checks if the value of this key (or it's synonyms) in %share is false
304 return &getval($_[0]) =~ /no|false|0/i;
308 # getval(name, [&hash])
309 # Given the name of a key in %share, return the value. Also looks for synonyms.
310 # If the value is not found, a default is looked for.. this can come from
311 # a copied section, the [global] configuration section, or from the SAMBA
312 # defaults. This means that getval() always returns something..
315 local $hash = $_[1] || \%share;
318 foreach (split(/,/, $synon{$_[0]})) {
319 if (defined($hash->{$_})) { return $hash->{$_}; }
322 if (defined($hash->{$_[0]})) {
323 return $hash->{$_[0]};
325 elsif ($_[0] ne "copy" && ($copy = $hash->{"copy"})) {
326 # this share is a copy.. get the value from the source
329 return &getval($_[0]);
332 # return the default value...
333 return &default_value($_[0]);
339 # setval(name, value, [default])
340 # Sets some value in %share. Synonyms with the same meaning are removed.
341 # If the value is the same as the share or given default, dont store it
346 # default was given..
349 elsif ($_[0] ne "copy" && ($copy = $share{"copy"})) {
350 # get value from copy source..
353 $def = &getval($_[0]);
356 # get global/samba default
357 $def = &default_value($_[0]);
359 if ($_[1] eq $def || ($def !~ /\S/ && $_[1] !~ /\S/) ||
360 ($def =~ /^(true|yes|1)$/i && $_[1] =~ /^(true|yes|1)$/i) ||
361 ($def =~ /^(false|no|0)$/i && $_[1] =~ /^(false|no|0)$/i)) {
362 # The value is the default.. delete this entry
367 foreach (split(/,/, $synon{$_[0]})) {
371 $share{$_[0]} = $_[1];
377 # Delete a value from %share (and it's synonyms)
382 foreach (split(/,/, $synon{$_[0]})) {
386 else { delete($share{$_[0]}); }
390 # default_value(name)
391 # Returns the default value for a parameter
396 # First look in the [global] section.. (unless this _is_ the global section)
397 if ($share{share_name} ne "global") {
398 &get_share("global", "global");
400 foreach (split(/,/, $synon{$_[0]})) {
401 if (defined($global{$_})) { return $global{$_}; }
404 if (defined($global{$_[0]})) { return $global{$_[0]}; }
407 # Else look in the samba defaults
409 foreach (split(/,/, $synon{$_[0]})) {
410 if (exists($default_values{$_})) {
411 return $default_values{$_};
415 return $default_values{$_[0]};
419 # The list of synonyms used by samba for parameter names
420 @synon = ( "writeable,write ok,writable",
422 "printable,print ok",
423 "allow hosts,hosts allow",
424 "deny hosts,hosts deny",
425 "create mode,create mask",
426 "directory mode,directory mask",
430 "only guest,guest only",
431 "user,username,users",
432 "default,default service",
433 "auto services,preload",
434 "lock directory,lock dir",
435 "max xmit,max packet",
436 "root directory,root dir,root",
437 "case sensitive,case sig names",
438 "idmap uid,winbind uid",
439 "idmap gid,winbind gid",
441 foreach $s (@synon) {
442 foreach $ss (split(/,/ , $s)) {
448 # Default values for samba configuration parameters
449 %default_values = ( "allow hosts",undef,
450 "alternate permissions","no",
456 "directory mode","755",
457 "default case","lower",
458 "case sensitive","no",
460 "preserve case","yes",
461 "short preserve case","yes",
462 "delete readonly","no",
464 "dont descend",undef,
467 "force create mode","000",
468 "force directory mode","000",
469 "guest account","nobody", # depends
471 "hide dot files","yes",
472 "invalid users",undef,
474 "lppause command",undef, # depends
475 "lpq command",undef, # depends
476 "lpresume command",undef, # depends
477 "lprm command",undef, #depends
478 "magic output",undef, # odd..
479 "magic script",undef,
481 "mangled names","yes",
491 "level2 oplocks","no",
492 "load printers","yes",
497 "print command",undef,
498 # "print command","lpr -r -P %p %s",
500 "printer driver",undef,
504 "root preexec",undef,
505 "root postexec",undef,
506 "set directory","no",
508 "socket options","TCP_NODELAY",
509 "strict locking","no",
511 "unix password sync","no",
514 "volume",undef, # depends
519 "winbind cache time",300,
520 "winbind enable local accounts","yes",
521 "winbind trusted domains only","no",
522 "winbind enum users","yes",
523 "winbind enum groups","yes",
525 $default_values{'encrypt passwords'} = 'yes' if ($samba_version >= 3);
528 # Convert a samba unix user list into a more readable form
532 foreach $u (split(/[ \t,]+/ , $_[0])) {
533 if ($u =~ /^\@(.*)$/) {
534 push(@rv, "group <tt>".&html_escape($1)."</tt>");
537 push(@rv, "<tt>".&html_escape($u)."</tt>");
540 return join("," , @rv);
546 ($n = $_[0]) =~ s/ /_/g;
547 return sprintf "<input type=radio name=$n value=yes %s> $text{'yes'}\n".
548 "<input type=radio name=$n value=no %s> $text{'no'}\n",
549 &istrue($_[0]) ? "checked" : "",
550 &isfalse($_[0]) ? "checked" : "";
553 # username_input(name)
554 # Outputs HTML for an username field
557 ($n = $_[0]) =~ s/ /_/g;
559 print "<td><input name=$n size=8 value=\"$v\"> ",
560 &user_chooser_button($n, 0),"</td>\n";
563 # username_input(name, default)
566 ($n = $_[0]) =~ s/ /_/g;
568 print "<td><input name=$n size=8 value=\"$v\"> ",
569 &group_chooser_button($n, 0),"</td>\n";
574 @sock_opts = ("SO_KEEPALIVE", "SO_REUSEADDR", "SO_BROADCAST", "TCP_NODELAY",
575 "IPTOS_LOWDELAY", "IPTOS_THROUGHPUT", "SO_SNDBUF*", "SO_RCVBUF*",
576 "SO_SNDLOWAT*", "SO_RCVLOWAT*");
578 @protocols = ("CORE", "COREPLUS", "LANMAN1", "LANMAN2", "NT1");
582 # Returns an array of all the users from the samba password file
585 local(@rv, @b, $_, $lnum);
587 # Get list of users from the pdbedit command, which uses a configurable
588 # back-end for storage
589 &open_execute_command(PASS, "cd / && $config{'pdbedit'} -L -w -s $config{'smb_conf'}", 1);
592 # Read the password file directly
593 &open_readfile(PASS, $config{'smb_passwd'});
599 local @b = split(/:/, $_);
601 local $u = { 'name' => $b[0], 'uid' => $b[1],
602 'pass1' => $b[2], 'pass2' => $b[3],
603 'oldname' => $b[0] };
604 if ($samba_version >= 2 && $b[4] =~ /^\[/) {
605 $b[4] =~ s/[\[\] ]//g;
606 $u->{'opts'} = [ split(//, $b[4]) ];
607 $u->{'change'} = $b[5];
610 $u->{'real'} = $b[4];
611 $u->{'home'} = $b[5];
612 $u->{'shell'} = $b[6];
614 $u->{'index'} = scalar(@rv);
615 $u->{'line'} = $lnum-1;
622 # smbpasswd_cmd(args)
623 # Returns the full smbpasswd command with extra args
627 return $config{'samba_password_program'}.
628 ($samba_version >= 3 ? " -c " : " -s ").
629 $config{'smb_conf'}." ".$args;
633 # Add a user to the samba password file
637 # Use the pdbedit command
638 local $ws = &indexof("W", @{$_[0]->{'opts'}}) >= 0 ? "-m" : "";
639 local @opts = grep { $_ ne "U" && $_ ne "W" } @{$_[0]->{'opts'}};
640 local $out = &backquote_logged(
641 "cd / && $config{'pdbedit'} -a -s $config{'smb_conf'} -u ".
642 quotemeta($_[0]->{'name'}).
643 ($config{'sync_gid'} ? " -G $config{'sync_gid'}" : "").
644 " -c '[".join("", @opts)."]' $ws");
645 $? && &error("$config{'pdbedit'} failed : <pre>$out</pre>");
648 # Try using smbpasswd -a
649 local $out = &backquote_logged(
650 "cd / && ".&smbpasswd_cmd(
652 (&indexof("D", @{$_[0]->{'opts'}}) >= 0 ? "-d " : "").
653 (&indexof("N", @{$_[0]->{'opts'}}) >= 0 ? "-n " : "").
654 (&indexof("W", @{$_[0]->{'opts'}}) >= 0 ? "-m " : "").
655 quotemeta($_[0]->{'name'})));
657 # Add direct to Samba password file
658 &open_tempfile(PASS, ">>$config{'smb_passwd'}");
659 &print_tempfile(PASS, &user_string($_[0]));
660 &close_tempfile(PASS);
661 chown(0, 0, $config{'smb_passwd'});
662 chmod(0600, $config{'smb_passwd'});
668 # Change an existing samba user
672 # Use the pdbedit command
673 if ($_[0]->{'oldname'} ne "" && $_[0]->{'oldname'} ne $_[0]->{'name'}) {
674 # Username changed! Have to delete and re-create
675 local $out = &backquote_logged(
676 "cd / && $config{'pdbedit'} -x -s $config{'smb_conf'} -u ".
677 quotemeta($_[0]->{'oldname'}));
678 $? && &error("$config{'pdbedit'} failed : <pre>$out</pre>");
683 local @opts = grep { $_ ne "U" } @{$_[0]->{'opts'}};
684 &indexof("W", @{$_[0]->{'opts'}}) >= 0 && &error($text{'saveuser_ews'});
685 $out = &backquote_logged(
686 "cd / && $config{'pdbedit'} -r -s $config{'smb_conf'} -u ".
687 quotemeta($_[0]->{'name'}).
688 " -c '[".join("", @opts)."]' 2>&1");
689 $? && &error("$config{'pdbedit'} failed : <pre>$out</pre>");
693 if (!$_[0]->{'oldname'} || $_[0]->{'oldname'} eq $_[0]->{'name'}) {
694 # Try using smbpasswd command
695 local $out = &backquote_logged(
696 "cd / && ".&smbpasswd_cmd(
697 (&indexof("D", @{$_[0]->{'opts'}}) >= 0 ? "-d "
699 quotemeta($_[0]->{'name'})));
702 # Also directly update the Samba password file
703 &replace_file_line($config{'smb_passwd'}, $_[0]->{'line'},
704 &user_string($_[0]));
709 # Delete a samba user
713 # Use the pdbedit command
714 local $out = &backquote_logged(
715 "cd / && $config{'pdbedit'} -x -s $config{'smb_conf'} -u ".
716 quotemeta($_[0]->{'name'}));
717 $? && &error("$config{'pdbedit'} failed : <pre>$out</pre>");
720 # Try the smbpasswd command
721 local $out = &backquote_logged(
722 "cd / && ".&smbpasswd_cmd("-x ".quotemeta($_[0]->{'name'})));
724 # Just remove from the Samba password file
725 &replace_file_line($config{'smb_passwd'}, $_[0]->{'line'});
732 local @u = ($_[0]->{'name'}, $_[0]->{'uid'},
733 $_[0]->{'pass1'}, $_[0]->{'pass2'});
734 if ($_[0]->{'opts'}) {
735 push(@u, sprintf "[%-11s]", join("", @{$_[0]->{'opts'}}));
736 push(@u, sprintf "LCT-%X", time());
740 push(@u, $_[0]->{'real'}, $_[0]->{'home'}, $_[0]->{'shell'});
742 return join(":", @u)."\n";
745 # set_password(user, password, [&output])
746 # Changes the password of a user in the encrypted password file
749 local $qu = quotemeta($_[0]);
750 local $qp = quotemeta($_[1]);
751 if ($samba_version >= 2) {
752 local $passin = "$_[1]\n$_[1]\n";
753 local $ex = &execute_command(
754 &smbpasswd_cmd("-s $qu"), \$passin, $_[2], $_[2]);
760 &execute_command("$config{'samba_password_program'} $qu $qp",
761 undef, $_[2], $_[2]);
762 return $out =~ /changed/i;
767 # Returns 0 if not, 1 if it is, or 2 if run from (x)inetd
770 local ($found_inet, @smbpids, @nmbpids);
771 if (&foreign_check("inetd")) {
772 &foreign_require("inetd", "inetd-lib.pl");
773 foreach $inet (&foreign_call("inetd", "list_inets")) {
774 $found_inet++ if (($inet->[8] =~ /smbd/ ||
775 $inet->[9] =~ /smbd/) && $inet->[1]);
778 elsif (&foreign_check("xinetd")) {
779 &foreign_require("xinetd", "xinetd-lib.pl");
780 foreach $xi (&foreign_call("xinetd", "get_xinetd_config")) {
781 local $q = $xi->{'quick'};
782 $found_inet++ if ($q->{'disable'}->[0] ne 'yes' &&
783 $q->{'server'}->[0] =~ /smbd/);
786 @smbpids = &find_byname("smbd");
787 @nmbpids = &find_byname("nmbd");
788 return !$found_inet && !@smbpids && !@nmbpids ? 0 :
789 !$found_inet ? 1 : 2;
792 # is_winbind_running()
793 # Returns 0 if not, 1 if it is
794 sub is_winbind_running
797 @wbpids = &find_byname("winbindd");
798 return !@wbpids ? 0 : 1;
801 # can($permissions_string, \%access, [$sname])
802 # check global and per-share permissions:
804 # $permissions_string = any exists permissions except 'c' (creation).
805 # \%access = ref on what get_module_acl() returns.
808 local ($acl, $stype, @perm);
809 local ($perm, $acc, $sname) = @_;
810 @perm = split(//, $perm);
811 $sname = $in{'old_name'} || $in{'share'} unless $sname;
814 &get_share($sname); # use local %share
815 $stype = &istrue('printable') ? 'ps' : 'fs';
818 # check global acl (r,w)
820 next if ($_ ne 'r') && ($_ ne 'w');
821 return 0 unless $acc->{$_ . '_' . $stype};
824 # check per-share acl
825 if ($acc->{'per_' . $stype . '_acls'}) {
826 $acl = $acc->{'ACL' . $stype . '_' . $sname};
828 # next if $_ eq 'c'; # skip creation perms for per-share acls
829 return 0 if index($acl, $_) == -1;
835 # save_samba_acl($permissions_string, \%access, $share_name)
838 local ($p, $a, $s)=@_;
839 %share || &get_share($s); # use global %share
840 local $t=&istrue('printable') ? 'ps' : 'fs';
841 $a->{'ACL'. $t .'_'. $s} = $p;
843 return &save_module_acl($a);
846 # drop_samba_acl(\%access, $share_name)
850 %share || &get_share($s); # use global %share
851 local $t=&istrue('printable') ? 'ps' : 'fs';
852 delete($a->{'ACL'. $t .'_' . $s});
854 return &save_module_acl($a);
858 # Returns an array containing details of Samba groups
861 local (@rv, $group, $cmd);
862 if ($has_smbgroupedit) {
863 $cmd = "$config{'smbgroupedit'} -v -l";
866 $cmd = "$config{'net'} -s $config{'smb_conf'} groupmap list verbose";
868 &open_execute_command(GROUPS, $cmd, 1);
872 $group = { 'name' => $1,
873 'index' => scalar(@rv) };
876 elsif (/^\s+SID\s*:\s+(.*)/i) {
877 $group->{'sid'} = $1;
879 elsif (/^\s+Unix group\s*:\s*(.*)/i) {
880 $group->{'unix'} = $1;
882 elsif (/^\s+Group type\s*:\s*(.*)/i) {
883 $group->{'type'} = lc($1) eq 'domain group' ? 'd' :
884 lc($1) eq 'nt builtin' ? 'b' :
885 lc($1) eq 'unknown type' ? 'u' :
886 lc($1) eq 'local group' ? 'l' : $1;
888 elsif (/^\s+Comment\s*:\s*(.*)/i) {
889 $group->{'desc'} = $1;
891 elsif (/^\s+Privilege\s*:\s*(.*)/i) {
892 $group->{'priv'} = lc($1) eq 'no privilege' ? undef : $1;
899 # delete_group(&group)
900 # Delete an existing Samba group
904 if ($has_smbgroupedit) {
905 $out = &backquote_logged("$config{'smbgroupedit'} -x ".quotemeta($_[0]->{'name'})." 2>&1");
906 $? && &error("$config{'smbgroupedit'} failed : <pre>$out</pre>");
909 $out = &backquote_logged("$config{'net'} -s $config{'smb_conf'} groupmap delete ntgroup=".quotemeta($_[0]->{'name'})." 2>&1");
910 $? && &error("$config{'net'} failed : <pre>$out</pre>");
914 # modify_group(&group)
915 # Update the details of an existing Samba group
919 if ($has_smbgroupedit) {
920 $out = &backquote_logged(
921 $config{'smbgroupedit'}.
922 " -c ".quotemeta($_[0]->{'sid'}).
923 ($_[0]->{'unix'} == -1 ? "" :" -u ".quotemeta($_[0]->{'unix'})).
924 ($_[0]->{'desc'} ? " -d ".quotemeta($_[0]->{'desc'}) :" -d ''").
925 " -t ".$_[0]->{'type'}.
927 $? && &error("$config{'smbgroupedit'} failed : <pre>$out</pre>");
930 $out = &backquote_logged(
931 "$config{'net'} -s $config{'smb_conf'} groupmap modify".
932 " sid=".quotemeta($_[0]->{'sid'}).
933 ($_[0]->{'unix'} == -1 ? "" :
934 " unixgroup=".quotemeta($_[0]->{'unix'})).
935 ($_[0]->{'desc'} ? " comment=".quotemeta($_[0]->{'desc'})
937 " type=".quotemeta($_[0]->{'type'})." 2>&1");
938 $? && &error("$config{'net'} failed : <pre>$out</pre>");
942 # create_group(&group)
943 # Add a Samba new group
947 if ($has_smbgroupedit) {
948 $out = &backquote_logged(
949 $config{'smbgroupedit'}.
950 " -a ".quotemeta($_[0]->{'unix'}).
951 " -n ".quotemeta($_[0]->{'name'}).
952 ($_[0]->{'priv'} ? " -p ".quotemeta($_[0]->{'priv'}) : "").
953 ($_[0]->{'desc'} ? " -d ".quotemeta($_[0]->{'desc'}) :" -d ''").
954 " -t ".$_[0]->{'type'}." 2>&1");
955 $? && &error("$config{'smbgroupedit'} failed : <pre>$out</pre>");
958 $out = &backquote_logged("$config{'net'} -s $config{'smb_conf'} maxrid 2>&1");
959 local $maxrid = $out =~ /rid:\s+(\d+)/ ? $1 + 1 : undef;
960 $maxrid = 1000 if ($maxrid < 1000); # Should be >1000
961 $out = &backquote_logged(
962 "$config{'net'} -s $config{'smb_conf'} groupmap add".
964 " unixgroup=".quotemeta($_[0]->{'unix'}).
965 " ntgroup=".quotemeta($_[0]->{'name'}).
966 " type=".quotemeta($_[0]->{'type'})." 2>&1");
967 $? && &error("<pre>$out</pre>");
968 $out = &backquote_logged(
969 "$config{'net'} groupmap modify".
970 " ntgroup=".quotemeta($_[0]->{'name'}).
971 ($_[0]->{'desc'} ? " comment=".quotemeta($_[0]->{'desc'})
973 " type=".quotemeta($_[0]->{'type'})." 2>&1");
974 $? && &error("$config{'net'} failed : <pre>$out</pre>");
978 # get_samba_version(&out, [keep-original-format])
979 # Returns the Samba version
980 sub get_samba_version
983 foreach $flag ("-V", "-v") {
984 &execute_command("$config{'samba_server'} $flag", undef, $_[0], $_[0]);
985 if (${$_[0]} =~ /(Version|Samba)\s+(CVS\s+)?[^0-9 ]*(\d+)\.(\S+)/i) {
997 sub check_user_enabled
1000 &get_share("global");
1001 if (!&istrue("encrypt passwords")) {
1002 $err = &text('check_user1', $_[0], "conf_pass.cgi");
1004 elsif (!$config{'smb_passwd'} && !$has_pdbedit) {
1005 $err = &text('check_user2', $_[0], "../config.cgi?$module_name");
1008 print "<p>$err<p>\n";
1010 &footer("", $text{'index_sharelist'});
1015 sub check_group_enabled
1017 if ($samba_version < 3) {
1018 $err = &text('check_groups1', $_[0]);
1020 elsif (!$has_groups) {
1021 $err = &text('check_groups2', $_[0], "../config.cgi?$module_name");
1024 print "<p>$err<p>\n";
1026 &footer("", $text{'index_sharelist'});